From 0f5a8cf378360e0c19e2b649617cee18dffb63a4 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 9 Oct 2023 15:36:02 -0700 Subject: [PATCH 01/98] image decoder header file and constructor --- fairseq2n/src/fairseq2n/CMakeLists.txt | 1 + .../src/fairseq2n/data/image/image_decoder.cc | 39 +++++++++ .../src/fairseq2n/data/image/image_decoder.h | 87 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 fairseq2n/src/fairseq2n/data/image/image_decoder.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/image_decoder.h diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index b642d5d0a..756ed4b2a 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources(fairseq2n data/audio/detail/sndfile.cc data/detail/file.cc data/detail/file_system.cc + data/image/image_decoder.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc new file mode 100644 index 000000000..3542ba3c3 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -0,0 +1,39 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/image_decoder.h" + +#include +#include +#include + +#include +#include + +#include "fairseq2n/exception.h" +#include "fairseq2n/float.h" +#include "fairseq2n/fmt.h" +#include "fairseq2n/memory.h" +#include "fairseq2n/span.h" +#include "fairseq2n/data/audio/detail/sndfile.h" +#include "fairseq2n/data/detail/tensor_helpers.h" +#include "fairseq2n/detail/exception.h" + +using namespace fairseq2n::detail; + +namespace fairseq2n { + +image_decoder::image_decoder(image_decoder_options opts) + : opts_{opts} +{ + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); + if (dtype != at::kFloat && dtype != at::kByte) + throw_( + "`image_decoder` supports only `torch.float32` and `torch.uint8` data types."); +} + + +}; \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h new file mode 100644 index 000000000..144dde1a8 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -0,0 +1,87 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include + +#include "fairseq2n/api.h" +#include "fairseq2n/data/data.h" + +#include +#include + +namespace fairseq2n { + +class image_decoder_options { +public: + image_decoder_options + maybe_dtype(std::optional value) noexcept + { + auto tmp = *this; + + tmp.maybe_dtype_ = value; + + return tmp; + } + + std::optional + maybe_dtype() const noexcept + { + return maybe_dtype_; + } + + image_decoder_options + maybe_device(std::optional value) noexcept + { + auto tmp = *this; + + tmp.maybe_device_ = value; + + return tmp; + } + + std::optional + maybe_device() const noexcept + { + return maybe_device_; + } + + image_decoder_options + pin_memory(bool value) noexcept + { + auto tmp = *this; + + tmp.pin_memory_ = value; + + return tmp; + } + + bool + pin_memory() const noexcept + { + return pin_memory_; + } + +private: + std::optional maybe_dtype_{}; + std::optional maybe_device_{}; + bool pin_memory_ = false; +}; + +class FAIRSEQ2_API image_decoder { +public: + explicit + image_decoder(image_decoder_options opts = {}); + + data + operator()(data &&d) const; + +private: + image_decoder_options opts_; +}; + +} // \ No newline at end of file From 8bc7f6393cdcf0f6682d903e5f63a796a7ee0499 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 10 Oct 2023 08:10:54 -0700 Subject: [PATCH 02/98] png.cc and png.h --- fairseq2n/src/fairseq2n/CMakeLists.txt | 5 ++ .../src/fairseq2n/data/image/detail/png.cc | 37 ++++++++++++++ .../src/fairseq2n/data/image/detail/png.h | 51 +++++++++++++++++++ .../src/fairseq2n/data/image/image_decoder.cc | 14 +++++ 4 files changed, 107 insertions(+) create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.h diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 756ed4b2a..2a348efa2 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -102,6 +102,9 @@ target_include_directories(fairseq2n ${system} $ ) +find_package(PNG REQUIRED) +find_package(JPEG REQUIRED) + target_link_libraries(fairseq2n PRIVATE ${CMAKE_DL_LIBS} @@ -114,6 +117,8 @@ target_link_libraries(fairseq2n Threads::Threads sentencepiece-static SndFile::sndfile + PNG::PNG + JPEG::JPEG PUBLIC torch ) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.cc b/fairseq2n/src/fairseq2n/data/image/detail/png.cc new file mode 100644 index 000000000..ad1cf9310 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png.cc @@ -0,0 +1,37 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/detail/png.h" + +#include +#include +#include + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n::detail { + +::png_size_t vio_file::read(void *ptr, ::png_size_t size) { + if (current_pos_ >= block_.size()) { + return 0; + } + + ::png_size_t bytes_to_read = std::min(size, block_.size() - current_pos_); + std::memcpy(ptr, block_.data() + current_pos_, bytes_to_read); + current_pos_ += bytes_to_read; + + return bytes_to_read; +} + +::png_size_t vio_file::write(const void *ptr, ::png_size_t size) { + // We only support decoding image files. + return -1; +} + +} + + // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.h b/fairseq2n/src/fairseq2n/data/image/detail/png.h new file mode 100644 index 000000000..3c888f971 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png.h @@ -0,0 +1,51 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include +#include + +#include + + +#include "fairseq2n/memory.h" +#include "fairseq2n/span.h" +#include "fairseq2n/utils/cast.h" + +namespace fairseq2n::detail { + +// Wraps `memory_block` as a "virtual" file to use with libpng. +class vio_file { +public: + explicit + vio_file(memory_block &&block) noexcept + : block_{std::move(block)} + {} + + ::png_voidp get_io_ptr() { + return static_cast<::png_voidp>(&io_ptr_); + } + + ::png_size_t read(void *ptr, ::png_size_t size); + + ::png_size_t write(const void *ptr, ::png_size_t size); + +private: + static std::size_t + as_size(::png_size_t value) noexcept + { + return conditional_cast(value); + } + +private: + memory_block block_; + ::png_size_t current_pos_{}; + char io_ptr_; +}; + +} // namespace fairseq2n::detail \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 3542ba3c3..7e0d2d07a 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -35,5 +35,19 @@ image_decoder::image_decoder(image_decoder_options opts) "`image_decoder` supports only `torch.float32` and `torch.uint8` data types."); } +data +image_decoder::operator()(data &&d) const +{ + if (!d.is_memory_block()) + throw_( + "The input data must be of type `memory_block`, but is of type `{}` instead.", d.type()); + + const memory_block &block = d.as_memory_block(); + if (block.empty()) + throw_( + "The input memory block has zero length and cannot be decoded as audio."); + + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); +} }; \ No newline at end of file From a499b18237a08d629b5905e70d0289a58c1f7141 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 06:44:59 -0700 Subject: [PATCH 03/98] remove png files and import libpng methods --- .../src/fairseq2n/data/image/detail/png.cc | 37 ------------ .../src/fairseq2n/data/image/detail/png.h | 51 ----------------- .../src/fairseq2n/data/image/image_decoder.cc | 57 +++++++++++++++++++ 3 files changed, 57 insertions(+), 88 deletions(-) delete mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.cc delete mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.h diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.cc b/fairseq2n/src/fairseq2n/data/image/detail/png.cc deleted file mode 100644 index ad1cf9310..000000000 --- a/fairseq2n/src/fairseq2n/data/image/detail/png.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Meta Platforms, Inc. and affiliates. -// All rights reserved. -// -// This source code is licensed under the BSD-style license found in the -// LICENSE file in the root directory of this source tree. - -#include "fairseq2n/data/image/detail/png.h" - -#include -#include -#include - -#include "fairseq2n/exception.h" -#include "fairseq2n/detail/exception.h" - -namespace fairseq2n::detail { - -::png_size_t vio_file::read(void *ptr, ::png_size_t size) { - if (current_pos_ >= block_.size()) { - return 0; - } - - ::png_size_t bytes_to_read = std::min(size, block_.size() - current_pos_); - std::memcpy(ptr, block_.data() + current_pos_, bytes_to_read); - current_pos_ += bytes_to_read; - - return bytes_to_read; -} - -::png_size_t vio_file::write(const void *ptr, ::png_size_t size) { - // We only support decoding image files. - return -1; -} - -} - - // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.h b/fairseq2n/src/fairseq2n/data/image/detail/png.h deleted file mode 100644 index 3c888f971..000000000 --- a/fairseq2n/src/fairseq2n/data/image/detail/png.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Meta Platforms, Inc. and affiliates. -// All rights reserved. -// -// This source code is licensed under the BSD-style license found in the -// LICENSE file in the root directory of this source tree. - -#pragma once - -#include -#include -#include - -#include - - -#include "fairseq2n/memory.h" -#include "fairseq2n/span.h" -#include "fairseq2n/utils/cast.h" - -namespace fairseq2n::detail { - -// Wraps `memory_block` as a "virtual" file to use with libpng. -class vio_file { -public: - explicit - vio_file(memory_block &&block) noexcept - : block_{std::move(block)} - {} - - ::png_voidp get_io_ptr() { - return static_cast<::png_voidp>(&io_ptr_); - } - - ::png_size_t read(void *ptr, ::png_size_t size); - - ::png_size_t write(const void *ptr, ::png_size_t size); - -private: - static std::size_t - as_size(::png_size_t value) noexcept - { - return conditional_cast(value); - } - -private: - memory_block block_; - ::png_size_t current_pos_{}; - char io_ptr_; -}; - -} // namespace fairseq2n::detail \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 7e0d2d07a..d453d8502 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,63 @@ image_decoder::operator()(data &&d) const throw_( "The input memory block has zero length and cannot be decoded as audio."); + png_bytep buffer = reinterpret_cast(const_cast(static_cast(block.data()))); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + // Handle error + } + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + // Handle error + } + + png_rw_ptr read_fn = [](png_structp png_ptr, png_bytep data, png_size_t length) { + png_bytep& buffer = *reinterpret_cast(png_get_io_ptr(png_ptr)); + memcpy(data, buffer, length); + buffer += length; + }; + png_set_read_fn(png_ptr, &buffer, read_fn); + + png_read_info(png_ptr, info_ptr); + png_uint_32 width = png_get_image_width(png_ptr, info_ptr); + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + int color_type = png_get_color_type(png_ptr, info_ptr); + + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); + + at::Tensor rgb = at::empty({width, height}, + at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + + writable_memory_span rgb_bits = get_raw_mutable_storage(rgb); + + switch (dtype) { + case at::kFloat: { + span waveform_data = cast(rgb_bits); + + buffer.decode_into(waveform_data); + + break; + } + case at::kByte: { + span waveform_data = cast(rgb_bits); + + file.decode_into(waveform_data); + + break; + } + default: + throw_( + "`audio_decoder` uses an unsupported data type. Please file a bug report."); + }; + + at::Device device = opts_.maybe_device().value_or(at::kCPU); + if (device != at::kCPU) + waveform = waveform.to(device); + } }; \ No newline at end of file From 794c34a6d0523c4e1ff266b4482cbee9f0d19845 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 06:45:21 -0700 Subject: [PATCH 04/98] image decoder --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index d453d8502..f90a6cecd 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -86,25 +86,25 @@ image_decoder::operator()(data &&d) const case at::kFloat: { span waveform_data = cast(rgb_bits); - buffer.decode_into(waveform_data); + // todo break; } case at::kByte: { span waveform_data = cast(rgb_bits); - file.decode_into(waveform_data); + // todo break; } default: throw_( - "`audio_decoder` uses an unsupported data type. Please file a bug report."); + "`image_decoder` uses an unsupported data type. Please file a bug report."); }; at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) - waveform = waveform.to(device); + // todo } }; \ No newline at end of file From f751cc833531ce54d95f9700ed55b3412a956e8f Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 08:30:28 -0700 Subject: [PATCH 05/98] python binding --- src/fairseq2/data/png.py | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/fairseq2/data/png.py diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py new file mode 100644 index 000000000..fbb722153 --- /dev/null +++ b/src/fairseq2/data/png.py @@ -0,0 +1,42 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import TYPE_CHECKING, Optional, TypedDict, Union + +from torch import Tensor +from typing_extensions import NotRequired + +from fairseq2 import _DOC_MODE +from fairseq2.memory import MemoryBlock +from fairseq2.typing import DataType, Device + +if TYPE_CHECKING or _DOC_MODE: + + class ImageDecoder: + def __init__( + self, + dtype: Optional[DataType] = None, + device: Optional[Device] = None, + pin_memory: bool = False, + ) -> None: + ... + + def __call__(self, memory_block: MemoryBlock) -> "ImageDecoderOutput": + ... + +else: + from fairseq2n.bindings.data.png import ImageDecoder as ImageDecoder + + def _set_module_name() -> None: + for t in [ImageDecoder]: + t.__module__ = __name__ + + _set_module_name() + +class ImageDecoderOutput(TypedDict): + waveform: Tensor + sample_rate: float + format: int From 1a7b52addce53f8ff469f92ef7a4a7a146fec320 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 15:09:32 -0700 Subject: [PATCH 06/98] png decoder progress and py binding --- fairseq2n/src/fairseq2n/CMakeLists.txt | 2 +- .../{image_decoder.cc => png_decoder.cc} | 70 ++++++++++++++----- .../image/{image_decoder.h => png_decoder.h} | 14 ++-- src/fairseq2/data/png.py | 2 - 4 files changed, 59 insertions(+), 29 deletions(-) rename fairseq2n/src/fairseq2n/data/image/{image_decoder.cc => png_decoder.cc} (62%) rename fairseq2n/src/fairseq2n/data/image/{image_decoder.h => png_decoder.h} (85%) diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 2a348efa2..c3e68d1bb 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -54,7 +54,7 @@ target_sources(fairseq2n data/audio/detail/sndfile.cc data/detail/file.cc data/detail/file_system.cc - data/image/image_decoder.cc + data/image/png_decoder.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc similarity index 62% rename from fairseq2n/src/fairseq2n/data/image/image_decoder.cc rename to fairseq2n/src/fairseq2n/data/image/png_decoder.cc index f90a6cecd..3d9f036aa 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -4,12 +4,13 @@ // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. -#include "fairseq2n/data/image/image_decoder.h" +#include "fairseq2n/data/image/png_decoder.h" #include #include #include #include +#include #include #include @@ -27,17 +28,17 @@ using namespace fairseq2n::detail; namespace fairseq2n { -image_decoder::image_decoder(image_decoder_options opts) +png_decoder::png_decoder(png_decoder_options opts) : opts_{opts} { at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); if (dtype != at::kFloat && dtype != at::kByte) throw_( - "`image_decoder` supports only `torch.float32` and `torch.uint8` data types."); + "`png_decoder` supports only `torch.float32` and `torch.uint8` data types."); } data -image_decoder::operator()(data &&d) const +png_decoder::operator()(data &&d) const { if (!d.is_memory_block()) throw_( @@ -46,41 +47,67 @@ image_decoder::operator()(data &&d) const const memory_block &block = d.as_memory_block(); if (block.empty()) throw_( - "The input memory block has zero length and cannot be decoded as audio."); - - png_bytep buffer = reinterpret_cast(const_cast(static_cast(block.data()))); + "The input memory block has zero length and cannot be decoded as png."); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { - // Handle error + throw_("Failed to create PNG read struct."); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); - // Handle error + throw_("Failed to create PNG info struct."); + } + + // Set up error handling. + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw std::runtime_error("Error reading PNG image from memory"); } - - png_rw_ptr read_fn = [](png_structp png_ptr, png_bytep data, png_size_t length) { - png_bytep& buffer = *reinterpret_cast(png_get_io_ptr(png_ptr)); - memcpy(data, buffer, length); - buffer += length; - }; - png_set_read_fn(png_ptr, &buffer, read_fn); + auto datap = block.data(); + auto datap_len = block.size(); + + struct Reader { + png_const_bytep ptr; + png_size_t count; + } reader; + + reader.ptr = png_const_bytep(datap) + 8; + reader.count = datap_len - 8; + + auto read_callback = [](png_structp png_ptr, + png_bytep output, + png_size_t bytes) { + auto reader = static_cast(png_get_io_ptr(png_ptr)); + TORCH_CHECK( + reader->count >= bytes, + "Out of bound read in png_decoder. Probably, the input image is corrupted"); + std::copy(reader->ptr, reader->ptr + bytes, output); + reader->ptr += bytes; + reader->count -= bytes; + }; + png_set_sig_bytes(png_ptr, 8); + png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); + png_uint_32 width = png_get_image_width(png_ptr, info_ptr); png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); - - + + // temporary check to confirm image is being read + std::cout << "img width:" << width << std::endl; + + /* at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); at::Tensor rgb = at::empty({width, height}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); writable_memory_span rgb_bits = get_raw_mutable_storage(rgb); + switch (dtype) { case at::kFloat: { @@ -104,7 +131,12 @@ image_decoder::operator()(data &&d) const at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) - // todo + {// todo + } + + */ + + } }; \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/png_decoder.h similarity index 85% rename from fairseq2n/src/fairseq2n/data/image/image_decoder.h rename to fairseq2n/src/fairseq2n/data/image/png_decoder.h index 144dde1a8..0e4e993a7 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.h @@ -16,9 +16,9 @@ namespace fairseq2n { -class image_decoder_options { +class png_decoder_options { public: - image_decoder_options + png_decoder_options maybe_dtype(std::optional value) noexcept { auto tmp = *this; @@ -34,7 +34,7 @@ class image_decoder_options { return maybe_dtype_; } - image_decoder_options + png_decoder_options maybe_device(std::optional value) noexcept { auto tmp = *this; @@ -50,7 +50,7 @@ class image_decoder_options { return maybe_device_; } - image_decoder_options + png_decoder_options pin_memory(bool value) noexcept { auto tmp = *this; @@ -72,16 +72,16 @@ class image_decoder_options { bool pin_memory_ = false; }; -class FAIRSEQ2_API image_decoder { +class FAIRSEQ2_API png_decoder { public: explicit - image_decoder(image_decoder_options opts = {}); + png_decoder(png_decoder_options opts = {}); data operator()(data &&d) const; private: - image_decoder_options opts_; + png_decoder_options opts_; }; } // \ No newline at end of file diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index fbb722153..9e8279d83 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -37,6 +37,4 @@ def _set_module_name() -> None: _set_module_name() class ImageDecoderOutput(TypedDict): - waveform: Tensor - sample_rate: float format: int From 87b02c77253fa77baf632d93c48d22001a5f39d8 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 15:26:23 -0700 Subject: [PATCH 07/98] build py binding --- .../src/fairseq2n/bindings/CMakeLists.txt | 1 + .../python/src/fairseq2n/bindings/data/png.cc | 47 +++++++++++++++++++ .../python/src/fairseq2n/bindings/module.h | 3 ++ src/fairseq2/data/png.py | 10 ++-- 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 fairseq2n/python/src/fairseq2n/bindings/data/png.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt index 5215c8130..f0f6c70a3 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt +++ b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(py_bindings init.cc memory.cc data/audio.cc + data/png.cc data/data_pipeline.cc data/init.cc data/string.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc new file mode 100644 index 000000000..f7a44af32 --- /dev/null +++ b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc @@ -0,0 +1,47 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/bindings/module.h" + +#include +#include + +#include +#include + +#include +#include + +namespace py = pybind11; + +namespace fairseq2n { + +void +def_png(py::module_ &data_module) +{ + py::module_ m = data_module.def_submodule("png"); + + // PNGDecoder + py::class_>(m, "PNGDecoder") + .def( + py::init([]( + std::optional maybe_dtype, + std::optional maybe_device, + bool pin_memory) + { + auto opts = png_decoder_options() + .maybe_dtype(maybe_dtype).maybe_device(maybe_device).pin_memory(pin_memory); + + return std::make_shared(opts); + }), + py::arg("dtype") = std::nullopt, + py::arg("device") = std::nullopt, + py::arg("pin_memory") = false) + .def("__call__", &png_decoder::operator(), py::call_guard{}); + + map_functors().register_(); +} +} // namespace fairseq2n diff --git a/fairseq2n/python/src/fairseq2n/bindings/module.h b/fairseq2n/python/src/fairseq2n/bindings/module.h index 2a79e9fdd..01e454f4b 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/module.h +++ b/fairseq2n/python/src/fairseq2n/bindings/module.h @@ -22,6 +22,9 @@ namespace fairseq2n { void def_audio(pybind11::module_ &data_module); +void +def_png(py::module_ &data_module); + void def_data(pybind11::module_ &base_module); diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index 9e8279d83..bb11c9314 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -15,7 +15,7 @@ if TYPE_CHECKING or _DOC_MODE: - class ImageDecoder: + class PNGDecoder: def __init__( self, dtype: Optional[DataType] = None, @@ -24,17 +24,17 @@ def __init__( ) -> None: ... - def __call__(self, memory_block: MemoryBlock) -> "ImageDecoderOutput": + def __call__(self, memory_block: MemoryBlock) -> "PNGDecoderOutput": ... else: - from fairseq2n.bindings.data.png import ImageDecoder as ImageDecoder + from fairseq2n.bindings.data.png import PNGDecoder as PNGDecoder def _set_module_name() -> None: - for t in [ImageDecoder]: + for t in [PNGDecoder]: t.__module__ = __name__ _set_module_name() -class ImageDecoderOutput(TypedDict): +class PNGDecoderOutput(TypedDict): format: int From 10bcc14a67dae7812835aaf09185b51bc3d956ce Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 15:42:02 -0700 Subject: [PATCH 08/98] update init --- fairseq2n/python/src/fairseq2n/bindings/data/init.cc | 2 ++ fairseq2n/python/src/fairseq2n/bindings/module.h | 2 +- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc index acceffc5b..ec9364254 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc @@ -40,6 +40,8 @@ def_data(py::module_ &base) def_audio(m); + def_png(m); + def_data_pipeline(m); def_string(m); diff --git a/fairseq2n/python/src/fairseq2n/bindings/module.h b/fairseq2n/python/src/fairseq2n/bindings/module.h index 01e454f4b..2db246694 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/module.h +++ b/fairseq2n/python/src/fairseq2n/bindings/module.h @@ -23,7 +23,7 @@ void def_audio(pybind11::module_ &data_module); void -def_png(py::module_ &data_module); +def_png(pybind11::module_ &data_module); void def_data(pybind11::module_ &base_module); diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 3d9f036aa..fe538efc0 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -20,7 +20,6 @@ #include "fairseq2n/fmt.h" #include "fairseq2n/memory.h" #include "fairseq2n/span.h" -#include "fairseq2n/data/audio/detail/sndfile.h" #include "fairseq2n/data/detail/tensor_helpers.h" #include "fairseq2n/detail/exception.h" From 5e363866bc86651b14b4e8b89d9fb1fbfcb7848a Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 08:56:52 -0700 Subject: [PATCH 09/98] png decoder progress --- .../src/fairseq2n/data/image/png_decoder.cc | 63 ++++++------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index fe538efc0..b5ac51c58 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -47,7 +47,7 @@ png_decoder::operator()(data &&d) const if (block.empty()) throw_( "The input memory block has zero length and cannot be decoded as png."); - + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { throw_("Failed to create PNG read struct."); @@ -58,30 +58,24 @@ png_decoder::operator()(data &&d) const throw_("Failed to create PNG info struct."); } - // Set up error handling. - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - throw std::runtime_error("Error reading PNG image from memory"); - } - - auto datap = block.data(); - auto datap_len = block.size(); + auto data_ptr = block.data(); + auto data_len = block.size(); struct Reader { png_const_bytep ptr; png_size_t count; } reader; - reader.ptr = png_const_bytep(datap) + 8; - reader.count = datap_len - 8; + reader.ptr = png_const_bytep(data_ptr) + 8; + reader.count = data_len - 8; auto read_callback = [](png_structp png_ptr, png_bytep output, png_size_t bytes) { auto reader = static_cast(png_get_io_ptr(png_ptr)); - TORCH_CHECK( - reader->count >= bytes, - "Out of bound read in png_decoder. Probably, the input image is corrupted"); + if (reader->count > bytes) { + throw std::runtime_error("Out of bound read in png_decoder. Probably, the input image is corrupted"); + } std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; @@ -94,48 +88,29 @@ png_decoder::operator()(data &&d) const png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); - + int channels = png_get_channels(png_ptr, info_ptr); // temporary check to confirm image is being read std::cout << "img width:" << width << std::endl; - /* at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - at::Tensor rgb = at::empty({width, height}, + at::Tensor image = at::empty({width, height, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); - writable_memory_span rgb_bits = get_raw_mutable_storage(rgb); - - - switch (dtype) { - case at::kFloat: { - span waveform_data = cast(rgb_bits); - - // todo - - break; - } - case at::kByte: { - span waveform_data = cast(rgb_bits); - - // todo - - break; - } - default: - throw_( - "`image_decoder` uses an unsupported data type. Please file a bug report."); - }; - at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) - {// todo - } + image = image.to(device); - */ + // Pack png data and format as output. + data_dict output{ + {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, + {"channels", static_cast(channels)}, {"height", static_cast(height)}, + {"width", static_cast(width)}}; + output.emplace("image", std::move(image)); - + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + return output; } }; \ No newline at end of file From 3f4dc22a414a1af3bbe028456be709fe36db55fd Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 13:44:44 -0700 Subject: [PATCH 10/98] png decoder progress --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index b5ac51c58..10399e97e 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -60,7 +60,7 @@ png_decoder::operator()(data &&d) const auto data_ptr = block.data(); auto data_len = block.size(); - + std::cout << "len " << data_len << std::endl; struct Reader { png_const_bytep ptr; png_size_t count; @@ -73,13 +73,12 @@ png_decoder::operator()(data &&d) const png_bytep output, png_size_t bytes) { auto reader = static_cast(png_get_io_ptr(png_ptr)); - if (reader->count > bytes) { - throw std::runtime_error("Out of bound read in png_decoder. Probably, the input image is corrupted"); - } + std::cout << "reader->count: " << reader->count << " bytes " << bytes << std::endl; std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; }; + png_set_sig_bytes(png_ptr, 8); png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); @@ -90,12 +89,9 @@ png_decoder::operator()(data &&d) const int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); - // temporary check to confirm image is being read - std::cout << "img width:" << width << std::endl; - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - at::Tensor image = at::empty({width, height, channels}, + at::Tensor image = at::empty({width, height}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); at::Device device = opts_.maybe_device().value_or(at::kCPU); From 59f679961ab54584daf37f3c2b7e6559b4363eca Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 13:45:30 -0700 Subject: [PATCH 11/98] remove print statements --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 10399e97e..28dc458c4 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -60,7 +60,7 @@ png_decoder::operator()(data &&d) const auto data_ptr = block.data(); auto data_len = block.size(); - std::cout << "len " << data_len << std::endl; + struct Reader { png_const_bytep ptr; png_size_t count; @@ -73,7 +73,6 @@ png_decoder::operator()(data &&d) const png_bytep output, png_size_t bytes) { auto reader = static_cast(png_get_io_ptr(png_ptr)); - std::cout << "reader->count: " << reader->count << " bytes " << bytes << std::endl; std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; From 9ab69a3f83173b97184f506242ee4bb4378fb1a4 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 15:12:05 -0700 Subject: [PATCH 12/98] populate tensor object with png data --- .../src/fairseq2n/data/image/png_decoder.cc | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 28dc458c4..f7a9cd5f5 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -68,7 +68,8 @@ png_decoder::operator()(data &&d) const reader.ptr = png_const_bytep(data_ptr) + 8; reader.count = data_len - 8; - + + // Define custom read function auto read_callback = [](png_structp png_ptr, png_bytep output, png_size_t bytes) { @@ -87,12 +88,39 @@ png_decoder::operator()(data &&d) const int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); - + + // Allocate memory for image data + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); + for (int y = 0; y < height; y++) { + row_pointers[y] = (png_byte*) malloc(rowbytes); + } + + // Read image data row by row + png_read_image(png_ptr, row_pointers); + + // Specify tensor data type at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - at::Tensor image = at::empty({width, height}, - at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + // Copy image data into tensor object + at::Tensor image = at::empty({height, width, 3}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + for (int y = 0; y < height; y++) { + png_bytep row = row_pointers[y]; + for (int x = 0; x < width; x++) { + png_bytep px = &(row[x * 3]); + image[y][x][0] = px[0]; + image[y][x][1] = px[1]; + image[y][x][2] = px[2]; + } + } + // Free memory for image data + for (int y = 0; y < height; y++) { + free(row_pointers[y]); + } + free(row_pointers); + + // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); From 2cfeca3e5c60bcbdf1a7d4aba71d185c7b4ed48d Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 15:13:30 -0700 Subject: [PATCH 13/98] remove unnecessary include --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index f7a9cd5f5..3a148b4e9 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include From 740366a412aea649d795d090844554567070dfbe Mon Sep 17 00:00:00 2001 From: Alisha Date: Fri, 20 Oct 2023 15:48:24 -0700 Subject: [PATCH 14/98] more efficient use of memory for populating tensor --- .../src/fairseq2n/data/image/png_decoder.cc | 44 ++++++------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 3a148b4e9..99a6ba2b8 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -69,10 +70,10 @@ png_decoder::operator()(data &&d) const reader.count = data_len - 8; // Define custom read function - auto read_callback = [](png_structp png_ptr, + auto read_callback = [](png_structp png_ptr2, png_bytep output, png_size_t bytes) { - auto reader = static_cast(png_get_io_ptr(png_ptr)); + auto reader = static_cast(png_get_io_ptr(png_ptr2)); std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; @@ -88,37 +89,18 @@ png_decoder::operator()(data &&d) const int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); - // Allocate memory for image data - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); - png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); - for (int y = 0; y < height; y++) { - row_pointers[y] = (png_byte*) malloc(rowbytes); - } - - // Read image data row by row - png_read_image(png_ptr, row_pointers); - - // Specify tensor data type - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kByte); + at::Tensor image = at::empty({height, width, 4}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + auto t_ptr = image.accessor().data(); + // Copy image data into tensor object - at::Tensor image = at::empty({height, width, 3}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); - for (int y = 0; y < height; y++) { - png_bytep row = row_pointers[y]; - for (int x = 0; x < width; x++) { - png_bytep px = &(row[x * 3]); - image[y][x][0] = px[0]; - image[y][x][1] = px[1]; - image[y][x][2] = px[2]; - } - } - - // Free memory for image data - for (int y = 0; y < height; y++) { - free(row_pointers[y]); + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, t_ptr, nullptr); + t_ptr += rowbytes; } - free(row_pointers); - + t_ptr = image.accessor().data(); + // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) From 1fc8e4584429b4a04685682427e2e2e58a9e6bd1 Mon Sep 17 00:00:00 2001 From: Alisha Date: Fri, 20 Oct 2023 16:35:15 -0700 Subject: [PATCH 15/98] use get_raw_mutable_storage instead --- .../src/fairseq2n/data/image/png_decoder.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 99a6ba2b8..b716d2439 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -90,22 +90,24 @@ png_decoder::operator()(data &&d) const int channels = png_get_channels(png_ptr, info_ptr); at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kByte); - at::Tensor image = at::empty({height, width, 4}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - auto t_ptr = image.accessor().data(); - - // Copy image data into tensor object + writable_memory_span image_bits = get_raw_mutable_storage(image); + png_bytep image_data = reinterpret_cast(image_bits.data()); + + // Read image data into tensor for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, t_ptr, nullptr); - t_ptr += rowbytes; + png_read_row(png_ptr, image_data, nullptr); + image_data += rowbytes; } - t_ptr = image.accessor().data(); - + // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); + // Pack png data and format as output. data_dict output{ {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, From 18f3c8e99376f3ac2a0b9b81980fe73800588cf2 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sat, 21 Oct 2023 17:08:22 -0700 Subject: [PATCH 16/98] add png to build configs, support float32 tensor --- .github/workflows/_build_doc.yaml | 3 + .github/workflows/_build_wheel-linux.yaml | 6 ++ .github/workflows/_build_wheel-macos.yaml | 2 + .github/workflows/_lint_cc.yaml | 3 + .github/workflows/_lint_py.yaml | 3 + .github/workflows/_lint_sh.yaml | 3 + .github/workflows/_test_py_devel.yaml | 3 + .../python/src/fairseq2n/bindings/data/png.cc | 4 +- fairseq2n/src/fairseq2n/CMakeLists.txt | 2 - .../src/fairseq2n/data/image/png_decoder.cc | 68 ++++++++++++++----- .../src/fairseq2n/data/image/png_decoder.h | 23 ++----- src/fairseq2/data/png.py | 7 +- 12 files changed, 80 insertions(+), 47 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index d4b5802a0..04a262077 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -33,6 +33,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 5707b05b4..d876c1510 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -56,6 +56,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -159,6 +162,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index 60a5f7414..8ce85138d 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -38,6 +38,7 @@ jobs: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | brew install libsndfile python@${{ inputs.py }} || true + brew install libpng || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv @@ -101,6 +102,7 @@ jobs: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | brew install libsndfile python@${{ inputs.py }} || true + brew install libpng || true - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index b17b289bb..844f91108 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -33,6 +33,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 62a4e19a8..9d56f860c 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -30,6 +30,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index e2b974e9b..3f3ba65f6 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -27,6 +27,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_test_py_devel.yaml b/.github/workflows/_test_py_devel.yaml index 7b5e47a58..a154cfbc9 100644 --- a/.github/workflows/_test_py_devel.yaml +++ b/.github/workflows/_test_py_devel.yaml @@ -38,6 +38,9 @@ jobs: - name: Install libsndfile run: | yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc index f7a44af32..a3c45c2ab 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc @@ -28,16 +28,14 @@ def_png(py::module_ &data_module) py::class_>(m, "PNGDecoder") .def( py::init([]( - std::optional maybe_dtype, std::optional maybe_device, bool pin_memory) { auto opts = png_decoder_options() - .maybe_dtype(maybe_dtype).maybe_device(maybe_device).pin_memory(pin_memory); + .maybe_device(maybe_device).pin_memory(pin_memory); return std::make_shared(opts); }), - py::arg("dtype") = std::nullopt, py::arg("device") = std::nullopt, py::arg("pin_memory") = false) .def("__call__", &png_decoder::operator(), py::call_guard{}); diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 19dd4a873..a0018dc8a 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -104,7 +104,6 @@ target_include_directories(fairseq2n ${system} ) find_package(PNG REQUIRED) -find_package(JPEG REQUIRED) target_link_libraries(fairseq2n PRIVATE @@ -119,7 +118,6 @@ target_link_libraries(fairseq2n sentencepiece-static SndFile::sndfile PNG::PNG - JPEG::JPEG PUBLIC torch ) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index b716d2439..e295e5465 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -29,11 +29,12 @@ namespace fairseq2n { png_decoder::png_decoder(png_decoder_options opts) : opts_{opts} -{ - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - if (dtype != at::kFloat && dtype != at::kByte) - throw_( - "`png_decoder` supports only `torch.float32` and `torch.uint8` data types."); +{} + +bool +png_decoder::is_little_endian() const { + uint32_t x = 1; + return *(uint8_t*)&x; } data @@ -58,18 +59,23 @@ png_decoder::operator()(data &&d) const throw_("Failed to create PNG info struct."); } - auto data_ptr = block.data(); + auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); + /* + if(png_sig_cmp(data_ptr, 0, 8) == 0) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw_("The input data is not a valid PNG image."); + }; + */ struct Reader { png_const_bytep ptr; png_size_t count; } reader; - reader.ptr = png_const_bytep(data_ptr) + 8; + reader.ptr = data_ptr + 8; reader.count = data_len - 8; - // Define custom read function auto read_callback = [](png_structp png_ptr2, png_bytep output, png_size_t bytes) { @@ -83,13 +89,31 @@ png_decoder::operator()(data &&d) const png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); - png_uint_32 width = png_get_image_width(png_ptr, info_ptr); - png_uint_32 height = png_get_image_height(png_ptr, info_ptr); - int bit_depth = png_get_bit_depth(png_ptr, info_ptr); - int color_type = png_get_color_type(png_ptr, info_ptr); + png_uint_32 width, height; + int bit_depth, color_type; + int interlace_type; + auto retval = png_get_IHDR( + png_ptr, + info_ptr, + &width, + &height, + &bit_depth, + &color_type, + &interlace_type, + nullptr, + nullptr); + + if (retval != 1) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw_("Could not read image metadata from content."); + } + + if (is_little_endian()) { + png_set_swap(png_ptr); + } int channels = png_get_channels(png_ptr, info_ptr); - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kByte); + at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kFloat; at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); @@ -97,17 +121,25 @@ png_decoder::operator()(data &&d) const png_bytep image_data = reinterpret_cast(image_bits.data()); // Read image data into tensor - for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, image_data, nullptr); - image_data += rowbytes; + if (dtype == at::kByte) { + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, image_data, nullptr); + image_data += rowbytes; + } + } else { // image is 16 bit + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, (uint8_t*)image_data, nullptr); + for (size_t j = 0; j < rowbytes; ++j) { + image_data[j] = (int32_t)image_data[j]; + } + image_data += rowbytes; + } } - // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); - // Pack png data and format as output. data_dict output{ {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.h b/fairseq2n/src/fairseq2n/data/image/png_decoder.h index 0e4e993a7..3267e9727 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.h @@ -18,22 +18,6 @@ namespace fairseq2n { class png_decoder_options { public: - png_decoder_options - maybe_dtype(std::optional value) noexcept - { - auto tmp = *this; - - tmp.maybe_dtype_ = value; - - return tmp; - } - - std::optional - maybe_dtype() const noexcept - { - return maybe_dtype_; - } - png_decoder_options maybe_device(std::optional value) noexcept { @@ -67,7 +51,6 @@ class png_decoder_options { } private: - std::optional maybe_dtype_{}; std::optional maybe_device_{}; bool pin_memory_ = false; }; @@ -82,6 +65,8 @@ class FAIRSEQ2_API png_decoder { private: png_decoder_options opts_; -}; -} // \ No newline at end of file + bool + is_little_endian() const; +}; +} // namespace fairseq2n diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index bb11c9314..ee0c61cfe 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -4,10 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -from typing import TYPE_CHECKING, Optional, TypedDict, Union - -from torch import Tensor -from typing_extensions import NotRequired +from typing import TYPE_CHECKING, Optional, TypedDict from fairseq2 import _DOC_MODE from fairseq2.memory import MemoryBlock @@ -18,7 +15,6 @@ class PNGDecoder: def __init__( self, - dtype: Optional[DataType] = None, device: Optional[Device] = None, pin_memory: bool = False, ) -> None: @@ -36,5 +32,6 @@ def _set_module_name() -> None: _set_module_name() + class PNGDecoderOutput(TypedDict): format: int From 4b59f2d8a4b52ab3f16dbd39b47f6574cced26f0 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sat, 21 Oct 2023 17:16:53 -0700 Subject: [PATCH 17/98] fix lint --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 2 +- src/fairseq2/data/png.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index e295e5465..817a08877 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -128,7 +128,7 @@ png_decoder::operator()(data &&d) const } } else { // image is 16 bit for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, (uint8_t*)image_data, nullptr); + png_read_row(png_ptr, image_data, nullptr); for (size_t j = 0; j < rowbytes; ++j) { image_data[j] = (int32_t)image_data[j]; } diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index ee0c61cfe..40da2e974 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -8,7 +8,7 @@ from fairseq2 import _DOC_MODE from fairseq2.memory import MemoryBlock -from fairseq2.typing import DataType, Device +from fairseq2.typing import Device if TYPE_CHECKING or _DOC_MODE: From c6cdb4bcb654d5bb384fed245d69b51d19f5cf59 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sat, 21 Oct 2023 17:33:55 -0700 Subject: [PATCH 18/98] fix lint --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 817a08877..273009699 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -130,7 +130,7 @@ png_decoder::operator()(data &&d) const for (png_uint_32 i = 0; i < height; ++i) { png_read_row(png_ptr, image_data, nullptr); for (size_t j = 0; j < rowbytes; ++j) { - image_data[j] = (int32_t)image_data[j]; + image_data[j] = static_cast(image_data[j]); } image_data += rowbytes; } @@ -151,4 +151,4 @@ png_decoder::operator()(data &&d) const png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return output; } -}; \ No newline at end of file +}; From 749b23c579d86116f2c251360ff8065fcaffe030 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sun, 22 Oct 2023 17:32:50 -0700 Subject: [PATCH 19/98] fix lint --- .../src/fairseq2n/data/image/png_decoder.cc | 42 +++++++++---------- .../src/fairseq2n/data/image/png_decoder.h | 4 +- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 273009699..6edb52a7d 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -32,9 +32,9 @@ png_decoder::png_decoder(png_decoder_options opts) {} bool -png_decoder::is_little_endian() const { +png_decoder::is_little_endian() { uint32_t x = 1; - return *(uint8_t*)&x; + return (*reinterpret_cast(&x) == 1); } data @@ -49,32 +49,25 @@ png_decoder::operator()(data &&d) const throw_( "The input memory block has zero length and cannot be decoded as png."); - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { throw_("Failed to create PNG read struct."); } png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); + if (info_ptr == nullptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); throw_("Failed to create PNG info struct."); } auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); - /* - if(png_sig_cmp(data_ptr, 0, 8) == 0) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - throw_("The input data is not a valid PNG image."); - }; - */ struct Reader { png_const_bytep ptr; png_size_t count; - } reader; - - reader.ptr = data_ptr + 8; - reader.count = data_len - 8; + Reader(png_const_bytep p, png_size_t c) : ptr(p), count(c) {} + }; + Reader reader(data_ptr + 8, data_len - 8); auto read_callback = [](png_structp png_ptr2, png_bytep output, @@ -89,9 +82,9 @@ png_decoder::operator()(data &&d) const png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); - png_uint_32 width, height; - int bit_depth, color_type; - int interlace_type; + png_uint_32 width=0, height=0; + int bit_depth=0, color_type=0; + int interlace_type=0; auto retval = png_get_IHDR( png_ptr, info_ptr, @@ -118,7 +111,7 @@ png_decoder::operator()(data &&d) const size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); writable_memory_span image_bits = get_raw_mutable_storage(image); - png_bytep image_data = reinterpret_cast(image_bits.data()); + auto image_data = reinterpret_cast(image_bits.data()); // Read image data into tensor if (dtype == at::kByte) { @@ -126,11 +119,14 @@ png_decoder::operator()(data &&d) const png_read_row(png_ptr, image_data, nullptr); image_data += rowbytes; } - } else { // image is 16 bit + } else { + // Image is 16 bit. Pytorch does not support uint16 tensors, so we + // read into a uint16 vector and then cast into a float32 tensor. + std::vector> row_pointers(height, std::vector(rowbytes / sizeof(uint16_t))); for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, image_data, nullptr); + png_read_row(png_ptr, reinterpret_cast(row_pointers[i].data()), nullptr); for (size_t j = 0; j < rowbytes; ++j) { - image_data[j] = static_cast(image_data[j]); + image_data[j] = static_cast(row_pointers[i][j]); } image_data += rowbytes; } diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.h b/fairseq2n/src/fairseq2n/data/image/png_decoder.h index 3267e9727..f30313ad8 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.h @@ -66,7 +66,7 @@ class FAIRSEQ2_API png_decoder { private: png_decoder_options opts_; - bool - is_little_endian() const; + static bool + is_little_endian(); }; } // namespace fairseq2n From a365cc62f6c28fabd35ed37d10e1509f690ea2b5 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 06:44:17 -0700 Subject: [PATCH 20/98] remove type casting --- .../src/fairseq2n/data/image/png_decoder.cc | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 6edb52a7d..5365e5278 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -106,7 +106,7 @@ png_decoder::operator()(data &&d) const } int channels = png_get_channels(png_ptr, info_ptr); - at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kFloat; + at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); @@ -114,22 +114,9 @@ png_decoder::operator()(data &&d) const auto image_data = reinterpret_cast(image_bits.data()); // Read image data into tensor - if (dtype == at::kByte) { - for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, image_data, nullptr); - image_data += rowbytes; - } - } else { - // Image is 16 bit. Pytorch does not support uint16 tensors, so we - // read into a uint16 vector and then cast into a float32 tensor. - std::vector> row_pointers(height, std::vector(rowbytes / sizeof(uint16_t))); - for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, reinterpret_cast(row_pointers[i].data()), nullptr); - for (size_t j = 0; j < rowbytes; ++j) { - image_data[j] = static_cast(row_pointers[i][j]); - } - image_data += rowbytes; - } + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, image_data, nullptr); + image_data += rowbytes; } at::Device device = opts_.maybe_device().value_or(at::kCPU); From 38ca2645c767d827824c8320d252cedefb0a27cd Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 08:19:54 -0700 Subject: [PATCH 21/98] combine png and jpeg decoders into one class --- .../src/fairseq2n/bindings/CMakeLists.txt | 2 +- .../bindings/data/{png.cc => image.cc} | 18 ++++---- .../src/fairseq2n/bindings/data/init.cc | 2 +- .../python/src/fairseq2n/bindings/module.h | 2 +- fairseq2n/src/fairseq2n/CMakeLists.txt | 4 +- .../{png_decoder.cc => image_decoder.cc} | 43 +++++++++++++++---- .../image/{png_decoder.h => image_decoder.h} | 19 +++++--- src/fairseq2/data/{png.py => image.py} | 10 ++--- 8 files changed, 67 insertions(+), 33 deletions(-) rename fairseq2n/python/src/fairseq2n/bindings/data/{png.cc => image.cc} (61%) rename fairseq2n/src/fairseq2n/data/image/{png_decoder.cc => image_decoder.cc} (80%) rename fairseq2n/src/fairseq2n/data/image/{png_decoder.h => image_decoder.h} (77%) rename src/fairseq2/data/{png.py => image.py} (73%) diff --git a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt index f0f6c70a3..9ad9c92b7 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt +++ b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt @@ -17,7 +17,7 @@ target_sources(py_bindings init.cc memory.cc data/audio.cc - data/png.cc + data/image.cc data/data_pipeline.cc data/init.cc data/string.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc b/fairseq2n/python/src/fairseq2n/bindings/data/image.cc similarity index 61% rename from fairseq2n/python/src/fairseq2n/bindings/data/png.cc rename to fairseq2n/python/src/fairseq2n/bindings/data/image.cc index a3c45c2ab..7263a9b3d 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/image.cc @@ -13,33 +13,33 @@ #include #include -#include +#include namespace py = pybind11; namespace fairseq2n { void -def_png(py::module_ &data_module) +def_image(py::module_ &data_module) { - py::module_ m = data_module.def_submodule("png"); + py::module_ m = data_module.def_submodule("image"); - // PNGDecoder - py::class_>(m, "PNGDecoder") + // ImageDecoder + py::class_>(m, "ImageDecoder") .def( py::init([]( std::optional maybe_device, bool pin_memory) { - auto opts = png_decoder_options() + auto opts = image_decoder_options() .maybe_device(maybe_device).pin_memory(pin_memory); - return std::make_shared(opts); + return std::make_shared(opts); }), py::arg("device") = std::nullopt, py::arg("pin_memory") = false) - .def("__call__", &png_decoder::operator(), py::call_guard{}); + .def("__call__", &image_decoder::operator(), py::call_guard{}); - map_functors().register_(); + map_functors().register_(); } } // namespace fairseq2n diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc index ec9364254..f0408b262 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc @@ -40,7 +40,7 @@ def_data(py::module_ &base) def_audio(m); - def_png(m); + def_image(m); def_data_pipeline(m); diff --git a/fairseq2n/python/src/fairseq2n/bindings/module.h b/fairseq2n/python/src/fairseq2n/bindings/module.h index 2db246694..3cf686773 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/module.h +++ b/fairseq2n/python/src/fairseq2n/bindings/module.h @@ -23,7 +23,7 @@ void def_audio(pybind11::module_ &data_module); void -def_png(pybind11::module_ &data_module); +def_image(pybind11::module_ &data_module); void def_data(pybind11::module_ &base_module); diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index a0018dc8a..30378f731 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -55,7 +55,7 @@ target_sources(fairseq2n data/audio/detail/sndfile.cc data/detail/file.cc data/detail/file_system.cc - data/image/png_decoder.cc + data/image/image_decoder.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc @@ -104,6 +104,7 @@ target_include_directories(fairseq2n ${system} ) find_package(PNG REQUIRED) +find_package(JPEG REQUIRED) target_link_libraries(fairseq2n PRIVATE @@ -118,6 +119,7 @@ target_link_libraries(fairseq2n sentencepiece-static SndFile::sndfile PNG::PNG + JPEG::JPEG PUBLIC torch ) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc similarity index 80% rename from fairseq2n/src/fairseq2n/data/image/png_decoder.cc rename to fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 5365e5278..dc307d031 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -4,12 +4,11 @@ // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. -#include "fairseq2n/data/image/png_decoder.h" +#include "fairseq2n/data/image/image_decoder.h" #include #include #include -#include #include #include @@ -27,28 +26,48 @@ using namespace fairseq2n::detail; namespace fairseq2n { -png_decoder::png_decoder(png_decoder_options opts) +image_decoder::image_decoder(image_decoder_options opts) : opts_{opts} {} bool -png_decoder::is_little_endian() { +image_decoder::is_little_endian() { uint32_t x = 1; return (*reinterpret_cast(&x) == 1); } data -png_decoder::operator()(data &&d) const +image_decoder::operator()(data &&d) const { if (!d.is_memory_block()) throw_( "The input data must be of type `memory_block`, but is of type `{}` instead.", d.type()); - + const memory_block &block = d.as_memory_block(); if (block.empty()) throw_( - "The input memory block has zero length and cannot be decoded as png."); - + "The input memory block has zero length and cannot be decoded."); + + auto data_ptr = block.data(); + data output; + + const uint8_t jpeg_signature[3] = {255, 216, 255}; + const uint8_t png_signature[4] = {137, 80, 78, 71}; + + if(memcmp(jpeg_signature, data_ptr, 3) == 0) { + output = decode_jpeg(const_cast(block)); + } else if(memcmp(png_signature, data_ptr, 4) == 0) { + output = decode_png(const_cast(block)); + } else { + throw_( + "Unsupported image file. Only jpeg and png are currently supported."); + } + return output; +} + +data +image_decoder::decode_png(memory_block &block) const +{ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { throw_("Failed to create PNG read struct."); @@ -134,4 +153,10 @@ png_decoder::operator()(data &&d) const png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return output; } -}; + +data +image_decoder::decode_jpeg(memory_block &block) const { + data output; + return output; +} +}; // namespace fairseq2n diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h similarity index 77% rename from fairseq2n/src/fairseq2n/data/image/png_decoder.h rename to fairseq2n/src/fairseq2n/data/image/image_decoder.h index f30313ad8..f8a9f6d9e 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -13,12 +13,13 @@ #include #include +#include namespace fairseq2n { -class png_decoder_options { +class image_decoder_options { public: - png_decoder_options + image_decoder_options maybe_device(std::optional value) noexcept { auto tmp = *this; @@ -34,7 +35,7 @@ class png_decoder_options { return maybe_device_; } - png_decoder_options + image_decoder_options pin_memory(bool value) noexcept { auto tmp = *this; @@ -55,18 +56,24 @@ class png_decoder_options { bool pin_memory_ = false; }; -class FAIRSEQ2_API png_decoder { +class FAIRSEQ2_API image_decoder { public: explicit - png_decoder(png_decoder_options opts = {}); + image_decoder(image_decoder_options opts = {}); data operator()(data &&d) const; private: - png_decoder_options opts_; + image_decoder_options opts_; static bool is_little_endian(); + + data + decode_png(memory_block &block) const; + + data + decode_jpeg(memory_block &block) const; }; } // namespace fairseq2n diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/image.py similarity index 73% rename from src/fairseq2/data/png.py rename to src/fairseq2/data/image.py index 40da2e974..4a5fcd512 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/image.py @@ -12,7 +12,7 @@ if TYPE_CHECKING or _DOC_MODE: - class PNGDecoder: + class ImageDecoder: def __init__( self, device: Optional[Device] = None, @@ -20,18 +20,18 @@ def __init__( ) -> None: ... - def __call__(self, memory_block: MemoryBlock) -> "PNGDecoderOutput": + def __call__(self, memory_block: MemoryBlock) -> "ImageDecoderOutput": ... else: - from fairseq2n.bindings.data.png import PNGDecoder as PNGDecoder + from fairseq2n.bindings.data.image import ImageDecoder as ImageDecoder def _set_module_name() -> None: - for t in [PNGDecoder]: + for t in [ImageDecoder]: t.__module__ = __name__ _set_module_name() -class PNGDecoderOutput(TypedDict): +class ImageDecoderOutput(TypedDict): format: int From 0587a6b71f9e5b44d5b66d39761400f22a72f1a5 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 15:53:02 -0700 Subject: [PATCH 22/98] jpeg decoder --- .github/workflows/_build_doc.yaml | 3 + .github/workflows/_build_wheel-linux.yaml | 6 ++ .github/workflows/_build_wheel-macos.yaml | 2 + .github/workflows/_lint_cc.yaml | 3 + .github/workflows/_lint_py.yaml | 3 + .github/workflows/_lint_sh.yaml | 3 + .../src/fairseq2n/data/image/image_decoder.cc | 64 +++++++++++++++---- .../src/fairseq2n/data/image/image_decoder.h | 5 +- 8 files changed, 76 insertions(+), 13 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 04a262077..8909b2628 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -36,6 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index d876c1510..ec0a93051 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -59,6 +59,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -165,6 +168,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index 8ce85138d..51efaef76 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,6 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true + brew install libjpeg || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv @@ -103,6 +104,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true + brew install libjpeg || true - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 844f91108..5eb9838e9 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -36,6 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 9d56f860c..c712a157e 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -33,6 +33,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 3f3ba65f6..fd4d4f1a5 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -30,6 +30,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index dc307d031..667aff63d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -50,14 +50,14 @@ image_decoder::operator()(data &&d) const auto data_ptr = block.data(); data output; - - const uint8_t jpeg_signature[3] = {255, 216, 255}; - const uint8_t png_signature[4] = {137, 80, 78, 71}; - - if(memcmp(jpeg_signature, data_ptr, 3) == 0) { - output = decode_jpeg(const_cast(block)); - } else if(memcmp(png_signature, data_ptr, 4) == 0) { - output = decode_png(const_cast(block)); + + const std::array jpeg_signature = {255, 216, 255}; + const std::array png_signature = {137, 80, 78, 71}; + + if(memcmp(jpeg_signature.data(), data_ptr, 3) == 0) { + output = decode_jpeg(block); + } else if(memcmp(png_signature.data(), data_ptr, 4) == 0) { + output = decode_png(block); } else { throw_( "Unsupported image file. Only jpeg and png are currently supported."); @@ -66,7 +66,7 @@ image_decoder::operator()(data &&d) const } data -image_decoder::decode_png(memory_block &block) const +image_decoder::decode_png(const memory_block &block) const { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { @@ -155,8 +155,50 @@ image_decoder::decode_png(memory_block &block) const } data -image_decoder::decode_jpeg(memory_block &block) const { - data output; +image_decoder::decode_jpeg(const memory_block &block) const +{ + auto data_ptr = block.data(); + auto data_len = block.size(); + + // Set up decompression process + struct jpeg_decompress_struct cinfo = {}; + struct jpeg_error_mgr jerr = {}; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + auto width = cinfo.output_width; + auto height = cinfo.output_height; + auto channels = cinfo.output_components; + auto row_size = static_cast(width) * static_cast(channels); + int bit_depth = cinfo.data_precision; + + at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; + at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + writable_memory_span image_bits = get_raw_mutable_storage(image); + auto image_data = reinterpret_cast(image_bits.data()); + + // Read image into tensor + while (cinfo.output_scanline < cinfo.output_height) { + jpeg_read_scanlines(&cinfo, &image_data, 1); + image_data += row_size; + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + at::Device device = opts_.maybe_device().value_or(at::kCPU); + if (device != at::kCPU) + image = image.to(device); + + // Pack jpeg data and format as output. + data_dict output{ + {{"channels", static_cast(channels)}, {"height", static_cast(height)}, + {"width", static_cast(width)}, {"bit_depth", static_cast(bit_depth)}}}; + + output.emplace("image", std::move(image)); + return output; } }; // namespace fairseq2n diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h index f8a9f6d9e..c4c0b297a 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace fairseq2n { @@ -71,9 +72,9 @@ class FAIRSEQ2_API image_decoder { is_little_endian(); data - decode_png(memory_block &block) const; + decode_png(const memory_block &block) const; data - decode_jpeg(memory_block &block) const; + decode_jpeg(const memory_block &block) const; }; } // namespace fairseq2n From c58cf8d41a0e218256b98cc898984911c1d25efb Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 16:00:59 -0700 Subject: [PATCH 23/98] fix lint --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 667aff63d..7efd39eb9 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -172,7 +172,7 @@ image_decoder::decode_jpeg(const memory_block &block) const auto width = cinfo.output_width; auto height = cinfo.output_height; auto channels = cinfo.output_components; - auto row_size = static_cast(width) * static_cast(channels); + auto row_size = width * static_cast(channels); int bit_depth = cinfo.data_precision; at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; From 4ca5acfdd164c38376fef6eed75fd0bed46191d1 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 16:20:06 -0700 Subject: [PATCH 24/98] fix lint --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 7efd39eb9..2c7803f7e 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,13 +159,14 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); + std::vector data_copy(data_ptr, data_ptr + data_len); // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, data_copy.data(), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From 2fc74daa5146082dfd9e077ba7a1411cea61ca71 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 16:46:58 -0700 Subject: [PATCH 25/98] change type cast --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 2c7803f7e..114f057ac 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,14 +159,13 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); - std::vector data_copy(data_ptr, data_ptr + data_len); // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, data_copy.data(), data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From ca9b0044e1e825e8801bccfa24902887fd1e7939 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 14:49:34 -0700 Subject: [PATCH 26/98] unit test --- tests/unit/data/image/test.jpg | Bin 0 -> 27453 bytes tests/unit/data/image/test.png | Bin 0 -> 73036 bytes tests/unit/data/image/test_image_decoder.py | 115 ++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 tests/unit/data/image/test.jpg create mode 100644 tests/unit/data/image/test.png create mode 100644 tests/unit/data/image/test_image_decoder.py diff --git a/tests/unit/data/image/test.jpg b/tests/unit/data/image/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..552e2ada387fa59a0598e60536eda1def05c1e05 GIT binary patch literal 27453 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 literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test.png b/tests/unit/data/image/test.png new file mode 100644 index 0000000000000000000000000000000000000000..75472cbb5ff78acc8716ad9121ed421f17f96c9a GIT binary patch literal 73036 zcmeFYgFxi9Z{ z95<8illeFjQH2HKsfoAJNl?~*p1iZq@E<&WUm!Cs>W8i?jLP|EctxrUwW8t|O8@9h z+Q|X0@cJPmzJtEd<-PjY`f-j9N|eTr33nwMmd;?5w#7Ol$u}rLZ}Pd*Qt7@YU~8gT zNP!UX)$7rAZoAzx4racJ?g9^SxG>%_V@=K01C=N28IdDd?ljtXFfU-6AiSRO0lJd^6;Nlv^s+*Vb)Er4ya3myh=QkSFLES$go`ncRo}`Rvi8VhRF-#&+z{xz$Av%nfFfML zFQ%8Ul@28;7@(c5T50NS9WT7YTl-C|1vpD{a|M~lN@E5&NpY>0Z z*$~t~L2jJCdvDXiF$03W(#W4Vw0w9^V#M|1P^xN;`jK_&OKgoXQP4BZP(00cM9}{mI3$C)Vc`bofCRN%6dR5SMX1^cmKb zan5Q}Tb;qyI{A^BWlvsE1@5MvDXVLigC{W+N=Y8og?CAW88*BzT-o_|tBn_6axQlHM@5a3K>rvzy$2YrjCNZ=58 zz8yp+`lw3!UXX9$v4?XPx;@1<#dY`VI#j#1p0+QjbrfOyk73J>ad>98CGmkRy%Aqy zi={8<=5Kq2hvbHwXF{8lmZv}UF?!c&6|baHoEmtm3%&7@xHS)9ZpSw&nZem3g9lBa z)4GsZwXqmUY`D4E@T(1mXPDbR7MvZ8Jj!!RZcjKVlq9zzYa|yUxbWw{3*)~sGL(HW z5{u1&={|^3r+u0TCUl+rl3SHUv>>+O+3H~B-l4F!gS~dkz4+-dieRR{zkjZ6!w-2B zGImVA@he%gMN~-DE5E9uI(EqxrQiVyjK7hY`076eKYaIu;0^Wy$Fu!I5FqmL2PzIF zrp$L|;x=~%)QNU*Im&bYXXVd|F<%&P%sg`OZ~lXlk0tvD<0CqY-@qS|I`l26mu{#Y z?R=w=l-M{KZ=F6|a5ZPv473{d)YBQ7Qa3 zf=on?ax2PZo%jT0M_i9OP2ovS=3G9Z<+liNfl(ArG+AM~jKpouY82fd7Kwo|1}6fo z;8bDO^yyK#Gt9YQRGAmX2Du67oBkE$ub5s8w7r|rDSpM+QCO~3Oz5-2s6hu0^zID# zNN%=@Z`bmDCFJAFwC^Kbkd+sIS(@;LzUjA9{AvEHjuvk4rJT-xu0DULPPdDB{~J4g=EWD(p^OveIZkN zQ}ClYwK~`-c~WGT%3DEEl}*uJ4M$N@m9XG>VQj&k8c*(c#)(Q!TCqsYJI`Onz5FLK zCy!5D9H_6J)rT&~k7a8pd(q>>GWDZL@#MriBsoA%#8p+NWTupzlM5A`TP*8$eWt1k z2~>oXVEHa8#LiTz;<|E+lGeFPnJpP(=4zb2S`5sQHOXqSe3FgwH|gT)q&eMcYXw8f zMJh$g2nEjqIkj390)@0z`?9|dHzN8}^T4ynML_OXN_#RB`!Yv0AwXmuwfIm9{C z9TPWgh8&Yds=sKdX|-$dmxyW2SIb!nWEwj;@`euQux8ulrRBO>5Wz}dvvZnrG;^M? z`D#z+YNzh)cRPcl1(Q656Mb#3)SiH-gDV2;{p?eYC8xh|3q#5pRch60MK7C|umyYt zTJ$QG1e>iq(#{gE+plM@i_Q?|hp+!Ua(T4&B$pJ-{?U4rWr%wF4YG?~wseFZ*^df1WqtQ%`?efFO2Yuruqa`atBSI6l`ONOs z8k*Vh4kd&7;mWC#<~W#Y<&;s8N0Axa0}e)@AxIF7AWl*ts0BzBq;4Hj^QLCDhSZvM zKEtKd1+7u4QTigk8QMJRljVK$<@cA7UzxvDsckl&9hpqS{ql~OU_HY18)9m0V9EU_vG_;ZjU^MPr)a*+Z&s4 zTh46=TU)F{@ZsXpNVitxM&zR4#jnUjf*!LX`8?JM?jhGuK&Ay0J!Soe8Ljm~Bfi1+ z6Dae3#eM>)tmx$EH2%Tp%T-Mpjv7NE8VcqL_6pkNYIa6;Vn@iQRZ)XcNl{A*)1#Uh zLxw@+Kgv}Nxo5<|ER9Kvqz7*V>26gpxTpj(sa6fMb+g}9vONxe9H~X_%st1h^<0+% z-Drlb$oQa3t4A&rX-sCXvsc$|FTa|+YT5(qo>KS?M`?iZxEMYuKN=jC0@z)&pTeshHIJ!i-bi}evf_)z2VUk<4 zq%y;aUQR!+pAW|dS_D-dtz5nLi=Dikt zo%4Ex-J4zA%mw!r!zAF%TWO8AUU4ttVLS+L7nzIUJ^$qOWbb;0dW(9A&sv$_v4Vnb zWiuJ;m-C^aohcJdxg{xZ#*nDJD5`PE@$dZBZoMt^Rlkr_o>7NT{lt4ikMXlW4oSegd6;i8TZev|*_*)zK`G4!7lAyejy1z#o4F&_iDrVfV@;)38KwGGNE*H^NcK&KVqeQ@V^iFoefT8&l*-b1PGFp-MEi-&AwTQU&sWya(?b-64 z7vH9}v_5zl=~{nyz5LR5^u8RC)zbr)?@LR)kiVC?*17AtkY1bqQRa%}fc2=83`fHL zd7FVK2Rn*eGZBi`W0bRjquUQ6?%c}QnN9KxPyfnmxce&qAVq;4(FlF7NfKGXB zlY*`Y`P(VdSy(!(6|!Hm3`^;&xEa6odiBc97z3q%(2q6R-~TQg9bLahw6Ye(JTaLY-;EboTAMf-Qo31#Z5(;s1gQS;4PIdV@HQ(Izr$BkUZv0C|Jn}xCqQNH=ifi+G;y=|uRGZ|{_9x40a+hDVP#|a!1|xp2Db7)yvwU#;bsEX_-tWq zV&e$hLy(P)gPs2$8~*L1|GMRW+p78Bx3Yu&`_}*V(Z9CxvpyW*za8nH{QAec0K)_y z^RxaZ^93L48;O4gKR7S$0IPALo=#Q1+6 z{2%*|{_i0FCz1c5U;n3C|JxM*&qn^wYyD5x`F}R@|2G?Cxjy|96@w6`AVf4Jr!iEU@5xMpXE6E(j#7)d4v z$0^bcA$r&7E;H_jb2k*HP~1emDH7+R-PBVG%%kxk3AkuB4-6oZqT zv_b6Ul3({}CMpl2Uu$}XR6k07TO6xO=_d>ZpoWpMD%f1$@$GF5b_=Q}e*Fl;YfZD51;5<8WUhDi+^tX*L`o&@q-eaL3*6+uu9ZZWsINwu^_+!>uW@t@g1 zb*`fClnM;{wk5>%1w^fxx%PU(bXjsCNZvAn2@bgQWgbkNMs+e%)oWzly?!OGsVU!3 zwnQorel8_CQ5k>7R}p{bM$SQ>dVby5s11XOl{_!HZ}45n6d@tH9+?~<(a=LW=)LjE zlid`*RZJKoHY>uHA1Ga8ue?*T&`MXmSJ-?(nBRcnFFV!eE`rhja%LCJT3*j=143$I z5;}&1RGSvl^(kD$x@ayGW4OBFQ1T5+Z6(cHz;9>~%eAaJ&5l(K&e>SE=KOZlv~Xmp zcX$1x=J>LSDL2*_E6?P1G&YPPI^JGXiM{+K(%Pf2#uX;rgIBh(alw7^tyETkS%1Ih z1|hLbLbBv#c3#YslcA&2pQ@Z>qD77*^6gls-GBTNGPmQ-S3>&7n`BhyTuDyvZ#C%t zV5Sw>Xkk~ipAdE?7iB$i&Ezlajq`M7Qr)|%mJPsmA)4PXXLR@&FC%*x?kjF0_epVe zAEALi8Kr(QP=*$UNgGVWMIirZs*flga)Oj!F=iH-?4Gyu2%5(Xq>j97aO-UU6D>eu z@*~2V2=d8*2$H1b##bUXv_qoQdLd>Vkc3%lZfE-|aJs+W)Y+-hN(9}8I_fJb8uZ;X z%MGz7u$WOdjO06-(AM6lm!I>{Db2&YNR9e+SfaR`H-ioK;FZdB=O6Z$E$FqJ8)^%H z;z8u3Yg#-^;@NxEc@+x3_1=3Hos8s^m3;h73a{K0YV0hEd+RS7g!TDzQB8aGh&wwS zw?!xi#WJ~7*p~sr<=%dJ@~w~n6tq4<%5q6L-AX!~=fJ`sCw_1IrQ@8*$qVKTuj9}) zg7{}Y6-uAY1pVG_iq6IWb&*p{NYj)^YcAh^d_DnNI3zJdJk8hfYs+;Ih5HGAMZ*C7 z8uO@FML6#fSgDb#T}?-XS0>}DXqSC!%LQ?zRk!8l&*+<(^6Zh~Rqj;w+1eOS;H6#I z$)#TR_PC&Tk?h=^B*>CHX3lER|J^Eq4ZbakIjGr&PxE!}ScZ?y8$(`jd=o)fM;Sdv z!|v4fYolE{?}5_+1kldD@LJz5$+#1qlQ)~WuEB58{MS7vfqP!b?o*kV6=S_~@>|X0 z%Dx)9*D|qjo3;N{$^aqG)2&xm-pl2sEidR_Q5*}M!R9ivylg9SDz5)X43*tYkgXgq z3z?*iIPU>bD*(KGFJ%|v7Yv;BjhfUKD5q>s$c%KO=!Pg+m7V5(tq*+on55_JyW!uK z*x=ujOuo931YjAX^qQKhu?D=#WA;8v>(kC)>k~datE9Cn&uY7<(vKf$d?!Sv*VKR$ zm$5;S!-C7JI(x|DtrC))$a^CE?!-iE2}&hExxTn-@}R{53a_%cby{T$7r~VuW5G6r zIC7S2HppR-y(`DLF=w##K7Ts%oTeDsPT;IC@-9|l`S4W?wcH|qgF{*|dg&oW2kJBq zxS>$i_u%G|h^PLx%Pp8oY)JKc&PEV3$uq7J5Buf1&*^Ufm$#b{Kif0&_~}e%&92A7 zQPu%CuE%+9p?siLeW2H;h;|JtrwGqKyh!8Yz_hY~v5{xQNN>AU&yB#vXrr~mLUYM8 z6Accdir6RPJKtYg$@Cd{xU`n(&1v2x*Dxf{Gq6jP4UP>Ymh7L5JsE4)nWy;@*db&) zOKBArrawT32DKCP&D0q9HnO?iWR^)_b#2k{f%M(qf%<3LGp@6jurmRN+f6)Y0rb?+ zmjhIPVo?0U?I)7K5U9d2h1>&a_1QJXezb!A2Et%Ff zFz&yvwG?lGY4M9f={V^HuS?+yLcUB<4~{>KJUN~%P>Eff^@i8y32ggtjlisCAea~B zb!bYKZVpg#zyOV z37D}Dc~vkQG4`{W8TW3LupS7XLq{=KkoWs?3wZFnfWB-j&AHRLt<_MAM@P$Mn12tJ!Ai3K(x6fy;GyIb`A67c3-CH`4n@AXr<=(lmuVWO5ATz60ezf zU*n0{D+y*eF4F5CXtu5W23lG?bP|V!J5f46*s}y+#)8gW@$d}csJ6{Nu*%9jACdIG zj7Qq!>!%r)nKy~KqxSm5?5QtVd{xaNta0$tcu6-m8OfweYi{7! zv2N$nrism_-8eNk9<%DgqwNcx<(w+>on^808lzP{cd+@~OzKnPqgFFTVQl~2Fl@ju zqa8FbALjJ>^*CL&(>Ur8jCGEyuJ5IwD7Pjp(fmjQrT@^Q<){oK5**c&$r0joO->oHJ%?Y)rC(&V3AEN(RrN6OGg<3N^3($${V9-+!e$lV3AXjd!!`fg1;f6gRq+^~ot-=9Rx%!+xAjEmH7y^G^xZUd%eBb#r}i&CI2`N{m^)CLMPAfy>C;5N*R{^@amxg zWX4hCwdFcR>fJQy%DLC6>P@qN;-2GvC>EQ4W$nFcReuF*IcW)e0EY~CS<}pot!E%-ragxmjl~JStYG&I(wcoq{I**kWkUyW zC)+DAKpUzKI_RYHe5AFj{Vz{X^!M=2g&KtGZCXbLh-UsO@CC<_#EVx z`1`aKE9Sh@k!X_!%51Df-@-qoKd7UoM8MFQ-9odC{u2mkLi92M(th7KXFd0rZ`$|x zO*q%<=bZ0h;s(lkvfVu8?+;c)d2ga%KDg{08usL^OLZb3-I{Bmxu0driyL{or$d73 z_1-?ur(e{H#D&h22TP+t=cbjQrU@XcInOy726G;*!TD67|=} zT!ErE-chZy!KlZIJN7$CfG$Z`U&}i{ytJCC*I0N~2k_DEoZIEX*H>^$&5HL$%cCNq zy8Rid+wzB%0`}VRZMjV((w_{BJ+Fnx^>;s$>-X=I^Dg&Jzt1g$Tln7}*Lk|;!<_mL zh-$;OVrNgSx|XdlK(I2X=aOa2+My#~h*HB8DdKDfj#d)iWg5k+Aextm>Pn4oY&SIy znHF!u0+>c&>2EEZP6~u!8v`S^TIax|{KbsTk9Rh_j=|!ZdU@E*N3+SvmtooyTmJ;d zmNzEs-&MJ6V{pKmicBX`N@%3>eMS0kyEV2RZi~E#@NCaB>}$=3j*ruKg)LV~z7^HiO~Wdc{W2cBKJYT>i;{t{vY)TMZ)bgtDWlX>gXd>^zMl~N zVQWY;tF65a7pJ6IAg=-zOWtQXz+0qP^H}+4nQ8K_y43o{NKYfQU-nWGkvzW)zVuWK zkjA(LaMN*>-V6iAV}PVSo~L(CzC{acQ~OMpZ`L>*dgo4kIlZ-eDy|H2wQKV`ric0? zj1wC;dVhU3P)^l~2Kcs?CkT$AKE%EdwHX+*xcW9sye3^QX%@`O)wZW_f8+&c)c0bX z#YclmoiX^@&=|LZIT@H+=O@!H>n&s^>@H9Q3QnhVTuH57xE;Td9q%dAbyy}$^%wqx zi4A_HRk5eW4xpWA#Yhllo;Oe0#$VE-*pgPk)6Ukk-o6dqtZ?aLXB|9`1nGoZacv_6hpeUbO7!(Z3; zGC_QDS~&=3&#$GkJz4#}vtcr_wXv5M;JmZGE{F3@o$$ZvX!I`tpgHy9@SJkuJO1R| zF+}$EnxOTikabLlt-Z82nE1#0Ip#v&7+-xB?=nR+=!qqLi2o4s&}ooFHMMOT!mHX7 zo|L{OaitJYy*F>Q5k^+Nc^mI7xF_+f*1s*+1?JJ`=+1MwW6<7BJoobe@&=a4s9LQC ziYWvCQmgH5`lc%LDn44dc4s?4w?VFy+D~{NV3egk78n(65rBhE(nLjAcP9pNHr^d2 zCW9`FU)S>xzDS9f@Un`_7egoCjAP7lH}PERp3cN>#do%KYjy0~YdWS|w0L{8k{1{| z@#h#j*TrUm`ujJtcEop#h`(y0K`AX)__t6}RCo3*Y!*X9%e;~vRWf=$>m{x&I6J}E z_wj}pUs`##q>R@KYvbeThsE&aqyir8-;C4ARj-vuZu~%DVzC=Hehp+5bsn$vmkFuw z%>R?rN#`-7a`>6W)f%yroGV)uU}OD6(nf&qc=OeT#&hYe$jk(Y%@}V$i-+0~LNfAm zg(7Mc6-Q=3GD*V^nAQ=KF8u8K@MGs6_)KrInYcgD+>g&rc(JfZyoWL*5PUGo;bSKcS@cb8Vh?h zOODQktBU9!2M%&KTR8p08#P~ze3b49fUbTd);V@wV;>%9=ly#G<*mxL(o|c%G~2mJ z12RS*AdmQ~N&&`0(+4u=D-sDN+vHqkBO50$;ptG$#0gZk!G@5?31y9%d$3<^!1)(S zmlBMZR2DEvM}VY%xlUXOS#Xuf#7R+jqtAUj9m%lLg=WQ~ScFA*%Nds^cgPTlXownM z30lhs@ViAT?e*rJ14D6&Ap_PaA_|vJU6;?!IA$*pUgUOO+4%f&K=a2J;L>dYZViV2 zH(*6f6*5I`eVt;*O77V0oHUf$9raQ1CVzQnM#9^BU(dPNr7AO)6(|O!s*X}%am(05 z(?nj}|JC3E(U1D-X4=cJ|0}x2ZE4hPMJBJtkNw`48q3Q7q z3PuAE?RS=F@gw<9?V-1~pjrwqxOZPJrrzZ1gBzzuP~$^;?K0=G2AvW7ivr|f??)9~ zL(&I;SD5_>WNQHlK!;iRTOH?U`@_m-^|WW|YG^)c_iSs3_w1&BW&|8-iLJU->-l-p z?M4R5`|qWDVf!Rs7oz@#?VmC3^CA;mGF+IUOfm6Ut$i;s)w$y(D5U@erFYikMtcER zsS38nTHgKsShCK|&v}$~t4Nsv9Br2Cf#?*0D%Kljo1%FAojq14+l}&EH{b3b=d`lWT^nrnclyFFbiaFwrCk zkG_sA=9`?FQ~f}mMRpp!<-B{6x6n~=#~TzLo&ote*7Ast#Els37${MM$m>?*IMV}1 zTb8PQUq`1u%ak@^KOgLX#dW)XueFhJxiFk+U2ME|TLZ1IU#O`RjHfMsUzQp}GNbXK z;gsgUxQ(d<-8FTsuPp`30ym=|A~3SM03qQnk)I|_IHOXlSDcgROysbi3D&;COR+d6 zV1rs5yQeVk(xIA#UiVytvzvYhk#&w#(8KdT01UICc7+hbk_AwpQwHoNRFPbGb(sX@ zV3t16=4s6~L{0fLnqIV=T)p-ObXIg&pG# zC!kOp8ue80hBWe%S-z)|S)t>5_^0h?fsY*r|KZ`<(@tyTY<>OY94WHN(o2#qe$F~g zm&~ELP7f?-uO^MOTbY=Q#J%dF?XCFj`1Hpoz;qs~!b60=0D<$Z2;6|{-ix13y?GsO zW^o%8o7|%7u52l1WdmuhZWLd#_xrhQxqKE5i{#BQ12iEu92^2@n#hO(t7Uxc$>$F3 z-E1tajT-JnG*Zv=!TTpkNW7OIhvaTT>@A*fsg*big zZSG{WXZVYlt#t-AvnCuS#eIT?OXr7Au-_>H)P=zM1!=^AMXIXB>wX_zqAogK>Tl9K zc0SgI&56-GcGBR{?#h?sg0s9 z^#3M7PERg-7KUHV{Rsi##to5(X;uSegG}$Ak+fXpi6@`*hCRmjktVdudd$=}CA&Rs zKa2T=lcfM$fJW?ysH+bH9^S08KQls;ZX zj>P~Y=D)F&elzW`my1_$w5yaOliZ+SZRQgqs3TbB7`cgv;> zw&7rL)%E>M{;)5pEtf7Mq9^9nj8~4b$NVcr8*+THq-v3$&S~aH`G);*teYEybPL*# zHTUP9x0-E-u}PmXwr=RVOW-{i>*1@v8utQA^7p#MjYYF(o zx`cQv*ynznhwE|{UuAp;J;!*O-wdRE`v^Z~;dE_)LK}-F?>|B$sXBWfd()7V4d#(2 zromcvJ%Mtn*F8g|UsGt-JmGdC!SpsnGqHI|oo$;E+_k;ZY4vGwf?x7FQnpu|>hgr5 zV-Whzh+Ivr8+2&3=VUzK!=7fy7D&?oWjuy4N6!No@6!A-S&wIxdU?f?&5T4|ovSBL zS-hZX;1-nA&xIMWdl|TP?umv8G)^93^|8bgkK9v(-O7;}}O$yISJC(gVBmDA@~0beiGC2r!D z^dAE6a~&^QC2fS(;~tod)Orh1d*5;J)c?_}9SJGD@F2zWwDt<6Jy|Ms>u-r{%LNzy ze0hr$C~>&wE2UPlc-cc!9h!yTM84&)1r#>iT0NDl*6cMAR6vDhQV(Fsg>xG*UIBB@}m zzdHw?d!84x+88=h*Y1}4RD zl^-|HaBj5LHFF)IbmAT?n-1h|7?9VRl}B`l*#kJx{p2-x>24TVl|>-< zW8q2FiLWOo-E_+;oZaA94}|_5Kfl+ugrz9FEmu1J+kwm{gVWYw8}x$|THcSv^FhvO zKSb;0gy@DxM?%YghFe!%1{Lq|3Q{-s`3{)Ul)r}-W@45=*H|DREUlg~Qtn<_5~=R` zYJ_|8J`moL=dY4~v(Opduj#mg`Ow4w;xaKH*lqyUSToFVs*)6Wbb-jBJ18C9fpxsX zUEPVCTgMh~Jka`w=gH9)g@7?Yx|K{$W((-h;3aD!(lx5>>S+XPT)Z*&X{)oWMb~WX z20W8~&}fnGQb#h7l>BqbpIkG*v80Co)>vIj+^HASeA4TKvi_a=`IUntzIG>w_Tzv(ZG9miu$6A%72 zI|0p(6H#*E*h-*~H1wNRcadnit$T^%r2sT0G;IJ2-|CSCBh2@3k{;a%G%P9yeTH0( zP;*yn{PIngsczQTOU(s765n#1YCs20Dl3U>+q5G4wdf|>Q+nkeVMvs%lVM!fx!=4v z<#TsiqgHVcRl3m#WIk!C*kGN9AXN@Tf#1X?-q=A8V2#Q&sHl=d-R02$jI7>JtwxKb ziB*(NV3eV@dFLVr{N*rKr^zg9l+ki!j=EfPCcDUU6^IEyYu8N9A`T+xD1^}AEWZqM z{-(u9tDEt2UbiW^s5vuYDqbwo`_Dz9qL+_61g>g{CBWC(=n_Zr`xQ5?JthvgM*D4+ zp@!SNDO0r~;R0KxEkmqYwg~rr2*Lb1ghZ}^7%FlckBnxM9zQ&UYgSg%WLQ-g??=IS zGS+sxPq2fS0n%&e5u%iz0d087My)dy`|`vA9%EztX$I0haK5M8ntPNPjdhMYdw3R_ zXmwSD&s6se9haq3+@R{IB*eAzeR*PzZ6vAw(7?C3%5GEH!t8e|Jz=nFo~w4XdgH>I z$a;r;l4^-Q;w%n!i;b`_lBY{sy7gs;2nP`~QvFL4#d+sK{BD7a?^St=NHyr~ir}U1 zOJ=(!7YBAUC=q9J3uBw7msQI1l^>7k#55)=+KsU(6;dCHt8z@=gk>=TFhDLKM`@%3 z8KiO{JyyewaLZu^2*f8_HfFoiuYSb~*}jl-&Ck@W!k4VrG8tl@wm1Lz?)Hd@B*7xIW;&a$Fjf|iXXGB@kjmuo!rpS&}fF4$}r zh3U$o<0=A;?=mRRp8LyU|1c?D^}sWi_w7W=3Mn-5=?SvE_8)pru(586+;e2MCrcY} zrqF!j{}FHkof+{n-3>2*hD9fy)z2DsO@7lgp;!{%Ol8vpQiJ|Miqe=kT_?NY@=&}~ zk9$5Fvw>jN_-I^Lv+@v3L_nLV$gfh{n^!Z{+qN<4g0?YRLN=^n6DQd&p?03?PR(U5 zhn6I8vR3!NGbs&uf4=3x&>;}_L^Io`ON~YTO86IC8+ObA8)C`ZMGVkXfe~reu8@2q z7Kr+6xeNE%$)Qn{=DQLXwKqx86Ez!+BF+&idYJ!~18m!)myTDB-%nOeuyhSG>u2j@ z1n<85T^@?u<^_Q9eueel`3t~}MOTAJ%d}8%GVYcKeY)J#i zxiD5A>VvJk#-WHWK(YR?|4wH_T)w4JjI4@qRzI)5`T#}o1(dMk{K-``Qt4z__sU33 ziw*;nL$at}7TjiPma@NXkiwk9)=+DG*~aDZwZ;n4!2k*1R$-ux0pk3O7?>l> z2e_6?)zX{h)oERFa@J#GED$zM+r1^e(D~7PAk7;#HR5`<2g(6z`MFKhZwvgxhs@7n z&a2qdL!M4VVBp%6PTGH9s;k%;%VGg}rVn}iwMNQVN*N5$qCxW`(<9F36J%;zR^H5j z(+}^LZIi;cQOnIiqcOQozmKx*` zEGK@HhY~}0Hqp(cz8@D>FchN@xhIMQ7&U3TShdCW6iD}KqXSYac>kHVUQ@hLuEy=q zRN+OBt)8_2`Rk15BDCuqzSwHR z?mu*!6=H=w2_(b0po1m`G!vl07Tcu~^DScB-Uzp`N^`tk>YL9f4Prnt! zEGH6M+nwT-Wa;}>iCn)+UqSbmb&fbS<|?lT;C&S`A?)^R^H&TI!S)?R7Jg|C`3d7U0QPW3*ax|WMk~l@^$wQEEhSPcHjkW(E-{bV5L)ZZJroLX z^7ZAp{_me~p$?J$b(kQ~o1fn}K;q%D)Qf3smi;BWVk~BgLmh`TFHGY-RwlLsNN>V; zZB8G(ZqaCh&SBtyyDb^Zad;^mlly_`Bcm$3slwai7PYHo?E_|T4OvROJ~-CztHKJi zg20N;C2=hhWU0Ak+Oiq*MMs1 zylgb#%)*I>o}5oFl5ZetSgl>)_31}6?0?qjSgj<|sr-Q^@h@}5$mLkw^bkYE=g{uM= z`x&`LU?7P4Xgtr_!T%BW15R?+9EQ&VV_4t`dd4R|M_OHTZo~|f3kes`mAUfkB++rF zjTR5@(&;p#6-vE%SbaSQ0e|yJTRf$fl-VZ6?nybpF;ElHNgZ+9Bf+cd3Z0yyu6y+Ft!yt1y#GdH@<*awqr5`@W-_Zryz| zQ=CiJdROTTK%exOr=w!L$;MGIN`;4RcuoL6g+DeRW~xrSx?MgP>)#O6>i})#3z)cC zg}dz5oo)d~9sk}8NpGr$f2t~}Vuw8znwosRJdmD7asWO5-Z@PR?7#7K+q21DY_(1M z+IH^|&zwJf8ct@dvu#=SQPf_zMUEvm6_(upW*B(#rO#p>B(vTD+sZUcy=$gb<14eT=aeT@=2hQ;QS%vwmOfb_5i;a=x&wb z-8@ip7si6icvS2-(!t%OnE@t6oTU2?;ql&l8LjvlAg8RoKn+E9nfhm_=%?#eksvZ1 z4wQKkm&k?@WrZbg!C~d!U#Y(Lm;LCxJfSu0K}Dy0*7?m!QV9|5c-HK)b9(TI=zGq( z%D&4N5fuNq2ZskwQND_cb|>@{gU#zb;%iKjFSsn{zE<20fr3* z5BQX=>>yD)lo2E*RT+3$Rx0jsWbI0z`6b`f;eqfuU79d#FA2Oq_>p6r05b^5RCJ3^ zZp|FN*~d1xng4QSo@J%EU*vjiC^o7l4rln=$s9Ar4E_~26o~Bxlug&%F)Q590ieC6 zj$F=C4t!Il90V7wFyv=l%2ND(7P94+YB)&<5c3oE7~GOD!Lr;~BWC)@OM0BEu<1J7 zqaaVna>6FJ({#ILe~IcE!zns$ zL9n&nJ-sl(S<(Lx# zr~Qva9B`rI;Nr1qiygSWMN7z9$8kzewp9Mq;Yw&{a?=$fVa_YYWZdD5+rn_oB&Sl* znFi1g^{JuZZdpJ-(nze}G0GR1o~1V-yuL2K?WNUT$HOfg5tjob08g-Fn1R0kZ)#iH zxV-8(@u*MJ`IMGp{5{{_w#f9%mRDFaypI0+1Fy33{NxU62m>@mCV^Xeu1M~5KkZu2 z-C;E;y4~#!_$4w|`J#oJh#Rx@nrp%9#FjLAAd7gYKh0gA?qV}30rL{S_*K1+P?436 zVLm$rc}C>8EVEULkIo}Hu6B>CzPIJ_PXIF~6oclFz%tuk^#{y%xO{ar5fgT3Yn-v_ zv#J`qwEGQ)x*r3+gF-K#U5%8=8W|>!0CRo3u+!*anTss#0OY*2e>f($J!@-26_)}6 z=B?h>>#9aq9^#3tLLNWNMfj3eV&OcLW%C^5N7;xEl6HN*_ooS9*U$ueQ#10FCHUDE zqq?L4#8d;s)WoT8GkpMhYX$+t4dR$_p_}gTsr}gCfMC$gHo?%L$DL?Q8*P%YSv#zS z8wjRF#=4mAw+_bXv#xvYgSz~uVZGWD3)G_&WzabCZunN~y-37MpdF_I*o|Uer5?s7 z05ag9vIVJD?>Mq7=;sBT%D?=rWHo~0023^1_c@vgk(O+f@-hF zjV$`c&gea;Z$s&(k_c8P%$h8t%2&6%ahc;5Xu52fCzV$H+GnHDFmMczdtn54YZd>emcpaMyfc(J-ZU3TG&5DXO1ToQqpK2F5ACx6myP zaiFxi^`$a0ket;fJ|0DvHfHp9c68hBAUTQ2mB{&}t*>*043PSq0JrV0HIl?Ad}x0- zpRnj3y-P7%sX^gja;mRdc;n6+A4={o3yYxq)hZZG zbd&7BycV3jezw1gBv_6EQuV=}Mf8zh-pUSlHpfe@)7Pf%7+!$79K%d!STIxoe0dSv zUclR2EX#pVdc4*mb5`}dvUCK`xWZm-5@IKNG4q7pGITHK7{U470v+xq#~5ezVQaq zBs$#(0MlFKch}?#vsU#RSmSfVh|f2d&|PJT<>d$E|K#-qh@ljot+GDOkei#@x@kbD zQh)8QQmnMrk*{q~7sRv1Pa0*Bx1&IxYRTS&qnEtcSo^^fEzoB@>U901OFDtTTlAfF z_>-iWSY6q=Y^-w`yg~S*3V=PyR*}~7O~Ass=_uR@WOXS77prJv*{h|L7no z2|{$>YWv1#Qe1P^%L(b_4*;G+y6*FCv^OFOY*xPR=uL1Hs$|tn2Rg~0yFYn` z2Hho>2f4QmLpY_a{2~KB-Zz?+1i3a(Hj9-^4N7Wr_3l#NlHC`0NZ^+R`B4DU^O;1~ z_7{c#E8R+!jbRsLX4S(SN0&}5gp~UujT!jxQrNqydaOMa!X-U?oDCf@D_XQHXvzV) z*^VbX<%#eG7Od^q7JVKUE2aY;-K?L_V69DSLru3ksI}?t3B%8wf8}wA0iNkHfmbE3 z#z!@;&V?BiABS0M&s64Js_e1+yx3%H%5!S@GrE1TaZSA-&?Vc=N}U}@ctAX*t6l4g1?B7j1XK&qVg7rLizi{3|zib!RL0~VjO zpdC5(?I()Tz+;O|RK>M;AyRk>aF>O0!?;umEr7tT)C^f)JDGmF-+kFgbB>#OxFNp3 z>zw3r<-pu}Wg6(^n0ReY3l#d7##TIm*^*;Y@_|i5@(Eh=3@a6d`lHm#3-viIDXeH0 zW_4N1SRdItZ(5?6I`~(U0sXwH?v#wG9?bX3PVk;C&nwp_=hdttSY%6|@56<(?o0A0 z{r*j6pMCPUl9trX-d(Af(b~Ts*li0k+d=tePp>~{G0mdSyjl}Xb$%um@lYk;!3U}Y z>`raY%tni-fzN^1s)&2Z1I%_!Yu*60Z>Upz+9Lu|0pQ01o?d6wH4s7T7>dPbd+3xA zbPRjT7a_dV*$5`cX0Km|0J$uGgs}4iV-Q0{Z~wdlU|{Eqx!<+3{+=~}*lEiqT z+Vx_`v8*|WBh0>2j@PbOx*~l)sTr!1sssZjb_&IH-7?hn@nF!1Mflzlqm+v#8@14_ zxYwO^ExC`Umc$qG&sQVYJhk6_mVlyr8v!uCC$#HdBAgD4KSEhFsaj8$<=59wUM{vy zrPPaNF$vKN4&~-GMM0`koouOm!sKEaGvpx9Gk`ulydEGYGe0roWr_R$*n6v}D7*G? zSVuqvQ5tC!0cjN&Iur$Iq&uVp29WL;5mAwn5{B;XZc$3QySqDw_%`}H?<@Y^)9>tm z!n#>&?tAYm_to21hM=&MgCSL8t^=vBRI%zDqK=86K_<=CR2&a22i7KU>($v}iH^nT zmAEdRol)|G;-K;7j+s-Xw&wN%HQS5x9nPS`u| z{VqCkhKBb{iPs<^|ErMc#BW2R=iWxg8{}Qi(vs++ zi2||dLjt*gJD%Wp--F*SOgXL)TtaErT#f}h;qtM&y=CNn*HcwS{ixIqJ6(FPz-!nEwU21rP8x;x-%4Q zCQQWuWHeP@l@)RqA#5C1F8rXbL2VV?j$QPw9e?h3 zA4uWSlfnUlVP=zTO&r);1!n+TizVCi5FkU#26j z(9y$uZfnvpR`~4{^eIUr`Xq}VGSuGTw_G3Atf2m=EE3BD_S9!NuZWEf#1!uXb7#gSon7KA~>Ojsqn>KRKTkj80hIf{)g_TEi}Z zdeIrO!9jt@lyjaN=5ka3CI9~O^uCvw zcgK@S5RkO0J2n4i*kyOHMSOHN+{}MfepH49=R*R}ab%{xX4w}d)60r`&pYO3Yh)_U zUn5UJP0P2`Lwn5Q7EkW7J*;Bv-vXO~J&Fip|1W|AX&D5{pA& zuj(y73Q2+k>Xn)$%+3|?lR{4P?XqvK5!$~DJ#Ulk0^35o@$VZ&%@$`1ZVi?fdDrh2 z_jfYM0NuQ0M}dRha(%)qXku*5?S#l{5ttI_=i788g-ts#<+f_1gNdH;GQHtQzOz#? z9lW!=>HLO~U6gt;r}%p>mNI-zI{Me`Jduai9-42~La(?p-ObHaq4?H1qZF*&Xm z{M%$G)As=F!XjSrt^ij(nWygzE3wry+C=e+O7>^Uzs+F1p0CHLH87Ao&)b`LzJ#4xV|}9-+7B zhGT}5Urh)9ixI=4&nGU|YCQEpgn$AL9rtNV-d%!~Jj^ZaTVVlKI_JU6#QA{je&P2* z0yUPw?4}w!SnwR-LQsZEiN?K21W>yc9CiCtvS8oxZ*ivjT5LqT3TzEg2S6QYe*VxR z3VY7d=+?}-aftJT<@q&S22mD|F|c6h{k?o@X=aW;)f85cL%Pjah2zi_!Z zRG1?({5S-O{88*o9<{XP&oe^}@?s|!zEX+#;A50`0G-$2zW$q^{DLOsNZ4a?*JWLC zclqfSJ-o!oGXsD720V~Q1 zh5_$ZSQe>%(Nr_Ag(pwW}lynx5TOemA z;v8@1V`ZkqFL|Az@{RquJ5?D4aFpjh(g3%YUtk%e`A>uoLJglYmx~b4ywy}w4$)r8 zl$AkCy@qKlJ(2yS0c-30`UALB?hN&+k>;tK*4dWBW`Lb77H_7hf;^Vf^R9wY)!q0WA zW4*o4Ur%0Gb=}RSmti!9w}GM%)80Mi_8IOF6Y^?vB|EZ}framd^L9%UU$>nq=`l^u zV)gn*DPv8Oj~aDXBc?5ZVFgU`q_%9E57iSB5%c2_8Kram=`BwYSF6$ovR9;|>X7>6 z>}4D}YIf#c!PSnXFU^OZt%rItZRnn0M;Uzi;OG9+BeR+Q+)0deHbb#`Yl3v^VYc97dLs zT_=_C2toJb+)simE!TOTfdwp2%fPx(9$gkl2(!in{ChDARcnZk`eSc$KE+Ez3t0G#SPmKn;mH z;9f)6oyu})d>^IKOU3VVSs^JpFJj(a-}RH>CG|9=j+!%1Az;fF_q~3T)6{gyA^X+| zMPZRgIAtPy>lv2cj2x(`PEQjz`dCm!9NW`OS)%IsnUX{*jL#Hqx9yo_)!6INX2R1P z20HEC*E=6zZ8=sP+UDkRpeulYO!CjkN-_uw;0hMC^%kuRqpowpNv7l5{mnnkXTBh% z7Jk|GS3F&ZiE0VZp1a$1RV91!djeyj>_4;CW`52VL5*jhl92fvdT}R@O)NimE zu%bT4#&7&m%(y!T&DnG%B#Pta+64YMa*5tG=j32XBi0=uanPuS9#d?_*Wk!7W}Zzg z+W~gIr-59pH~3-mP3-h3msoCgJgH(veAQGNqxeyAsRxrh`9@ zd%dl<1N{VXl^mu0u?E=ApjUR}?s9z8HrElqr8RO+y8-0Y|`pCp5^sHuLZX?*!rT)Zzw!8f6-zuifN{d;!%pdI~EiQQs)PdnE}mQkeUOay_gM|I6oaGn^; zhH1&ijn@Y^23`s7!)|_53-Pp>Y|5?f?Khzm*S1$&OSj5D!``d9&z+mcf-cyp1Pvim z7O?Tn-*SLyP=q}$E%{)3PR2WUCO7QF!t4qm^D{f1Igla`o3ED{v8l|3I__2#*Y-SM zEj{(Ltt7!T4P7L9URXGp;pNN=dPUa>73|HNvmyhp_3sLLRL^p+MW-;U)-m)inz~{M zajHY*xuivx^M*?h?zHNA%qDEg!?g$+we^LEK}-M4fkPhS+Sp*y)Vz~`_Nj?qv3t^Jo};|3U#-w;G4a%i8W`7 zg)Ee(Hlu#kJV=ECx5)O_#$m+A*LqltOy-f_KJUMsAUp6Mt}|s>cE9HQF*4s)udl+A z*#x0ML7i*al|G)|UpoJ_LVfO=y{61UaE&iis2G)#x^OPamu~Old-i^wT_5ggzGSVk z93HiE&EmX+W3NG}jL`u@ZctYW#!w|c7L4{4O1$9Vt+Q#r{<_cf**QAQFEVMwx_$OS zYF>1(mxrFKb5KvHWkHQz-hgSCGDgk?Q4D_V4)p${oQkm=cq`($r&x?w5foiXFe@AO$12trOXL-#t|aqB#weWRPGTBfOfTQ=#p9`o^in^|YhZ5e$=WeKqIF+OG49P4>Fd%@`%E|O8xMcfsmg2Hw_)zofmmQV;a~B z>1{}RADJ%4DdwJw;;DZSdIJpINjp9~c+^nk4iBuUQ%G~T&i428)PC79H5uhY{3{-{8pD`LIiqYeC#W=_)($z zM|tN(ZQFCBll@@CglSmx`*f7sQ0C2S5KCl<#zMhpf(rMsLSX?(MG_`oFyK;^COhTI z+pp*zX;jE5JF}W8rB~U!dS|inF-S6h{Bd9M>>lE$QAjj7^2{3mg3psBO_cn-GGXnRK{kIe}P0&W1Ax{#Fg} zH$}42ZYS6li9;>R+Rs;NaLGlM6GqV9p-#moiN&*+_3bnF1wnJ_+gh1BJvh z(#~AUTc1rs%$^@~P$aUYoW4px%iGEanX&*fK)2am8s{%U;9-+-uY_mkyYNOCC`y(x zQc-bKId#2(F^oD}%TWMo{1)8xN?_hW)BcT z_76g&E7q)+vdRvN8TB#7Vqn8Fi2xFZ{>-SR()qc{$P_mEc00iXydi1UtODie%n5n4 zeerc?+Q)oKpFI`;{i2nz5y}(bVXD6di|RGAh#FZ%{D^9X!~yJ!0=e65CzbD66R(@* z)EbOA-?J6xn3p_&kPfI}7#%s?gbBoqv0T>}xW_g&L9)}CF~pI67{5Pclx3FfM9(T; zvz-ysJ2_52WUC=!*BdJ8nt|+kIh(dj1D8@P6Lx=uyjePXR5_Zgr`EPbRl1b35#B-z z6)Qe#XY|r4$;1YubI@Tf892q);kW=_xSz4J$Nwp9)K=m3YX;@aeaiN!_exG{NA$$4 zb=793UFS5^if!Zkj@U9k$$tdxAM$Kdtn&VFU;6PAP>$cVjuR4WV(YtXLMjLvYW!bQ zAwNhXPc!|L`Y5T1BQOgKG0>uc>o#|lKJRDpZ;g~)*^l`{r82}4tjc?ZCy2=_kS!- z^x||r^h5K$0nx-PTt*t&Nej!kb__bFXj+F0@SI83H1t;HA+(V3nr?3rq_+rT$?~2k z6>C+OUpu=#C>ae*?puHfZ>cbS`WMz;Lm;2gZ)Rnv&wdYI&w{~5OAG8w5<{edL%x^e zq~-&^KjfPuIJEv4z!=L5|LqgKwvN1FKx(GDV{K+E4C)#5fr`4HKrw{*=g&dWTSiO? z$a12t5E@jtj~Zg-kIS{*3GonyYYGX0X^`lDe*4N*f0SQ?iO?d=Oag8lx(?gP^dvBll6i-|LC-sYG*tKw4el zG@JUcL8vsVfCQ^xOb?5N=?k_5{l&;Bo|Rs&ij~Tli$0TZfaSJDN8L+M#hSu35O${J zj}BF!nmK)I<1PEJ;3rkYn2l1tNjT`g`dK9UL9xUiaJ{45Y#>_O7LIzvpsd=FT03Ih zN{f|0)!oWPa3_H7o@^Xg$jgI|{NF)azli!leDce}w$*yil#Q>|Sc4d&!E9}j4T|1H z4+ZFZPNrS0eDLQYRGkGLSVAW|BWhqQQlY;>NDBk#mji~cqMM@Dt*a=X0FOPt!GiM# z$6NtbU$8fm+N0z5a$K~=s$W9odqG2~Sg6)Z3JL<4+=U6!E6iNr{|78o*rxDs9?u{z zXwGsew2#SsqWWdSEyKwvlZYKPbbN3sf5O$ccWH*^}W;BQ2*Hg2VDXr zl9|N%|Dzp#NsNNnWYyA|)%*;%Iv8Sr4<*>EBsiF{DE%{H4 z=Vb<=>P$XOgau45wK)xSTN?LR6I~;zSPj9N@=`$s^=}vBLWr3eMJ{dpmwdhjB{?Y8 zGpc`5=r{8J85WiQ>Jt0@`U2Hgz;F*aqrEO|;j3ROk06l)@I0wD85Z%8E4_$)i>} zIfnG=!_piFc(M}-D-&idotc=AYy8gdkCkPPStu`PhH8~Gic@shXvw6Q zX_EUV*qf|&fO;&$++C7Ev69Nft_RJ z%GRZsvP%AOmYwVs*J8;=>s>kJS0$M4#g&>H8p(Rxu9Z7(nB4P%Ifs$^PhZQqR5KS$ z?)f2k`g_J^ypVfkYvufQuHOVl&_*WePNyE{7vsW@zWKcnu~1pmb0=K3(bzzD`Q)#< zsW*TbR;)2)C!SyIvS7V>JYbQ6;ZLyMGw0)PAQ3&H)6x6^p9Ql+##Unh2|JoT#X5dl ztg$6fQS&W2g>)n}thf!F;uk9Z=f$WGnWtb%C-!VB=Ik<1xP03Nl*t_e7Pj8cy<5R4Zn#FxM69q=qbM)74 z^5}1vDwoi$dESy$XqC#~kz+cL@OnnmR%AB^@+*~Um9CbKeO)WfN!#JxcL*9ENG(}& zVs)rru#OItNp5i$yF5}*-K?%N)0D9cud~`$i#kxvxCPEqs!0YNU8zT%OG#G)P`Rrx zuF5RzeHkI#-7T(puW)ylezbqZ3klTuSdCb*6 zJk^o&`ZPy_EktDpAv^=uR*8B>2{;))k*34~lSY?g(D=v?+T2G&3+9LzPm=T>sb}v9 zJ?c_v}MUIxtP(P6Q9o=m_Im`(hJ@>Ts~c#dFjjyz(ca=((?dw&!QC zAUKZmwbk9lEmkh4dX*Ev9PsSw%45T+_E)|n(=Kb>by0pgDHaQQc0(m%i7}cclRaAl zkCI>Fnhnwci%teO6~~$O`y^LUmNjb2_wfO-U$V1@>wOb9ZM4NyoL6JSugKXPaCBc- zd%77vzzYfKZsf@x*|FLChn3P9bh50OHtFASlT72+MShV@ahDfA9$9N|sWVfTwiw}h za`D4jPEZUnVe)S6V$ixc3P#)qG1#J`rtk&O_@s#eXPi%*cNTrgO2(e@9WE z_xgIwQTFHS+Zm}mRu{&>l;(LF>L-+h9Wi(sb@dY}o!7&pH`)ufn1DGC$U=6menG-C+11kA__sg(2I$8V zAtQCx!qz;G#=6M*q7XkXZqMCgDl8kcJ+bD=x;?)q5i_|mFlu1yfbI&ssz*5h4R>!0 zmNF7%;(y0C{q{;%Tr^g$Qb17QXn2O^s)Q)Ea4oJ}Q7*}E3CBi%S(_}!`ks?;9zW;y zI`!jco>9{=%ol>H53(5dE8K>7!3YW+X4OoZpR1vMg!Eo5?E&>_B`OZD?n>UZp)WHp z@$n~ORbQf1*g4j}_FGecq851dFii&bI8*Xnzv6b{@~`iCNfvKL5iQ%;)NkvV4q~%JMvMa@^@_!9yNWycD#~{+g!CWlY!5Y) zp#34%oA-Ntf>?I%jZ=Fphb%|x$kAl7-KsV}{ZmPY-*Ok58crA$I;57RQu_G3yDqf- zVbadF>68z%#S@7IYuNtX2K|pOlM4RhgnJ}-V7-HlWi$OCj*FAtvMAM}93tMvUgV0; z=Yrh5C<6V^oQ{nyT$^mkg2G4=*~)Z73FDhYoR@?VXFMw9%1yOQj+>g^b*VS{;s4r) zy(J!P8s^}ewZvV@^Qb%$`x4E#r)Hb_^VR7a)bFbNK_fJ+iEh8PGQ`pB%PZZM)~61S z1s&*%t?1DnlKa~idxR5J+VIKH(Zv7Prl6Xv60%scDthO|sd=JmpMme_cVOFuc6?Fj zZhx9$&dCFv8ryq#{@z5+T9Dp+i5K6Gon;QRsyUm&m`3y${^5e>jUO57N)j zs5XUvEz$rj8S{ys7tc+%$UzgMM#8(G76_e;0)w`*pWDyJ>p{PX!Fw;}s5ps6SEmX# zSh&_rJst~nQ=+wyXP57Bz<>~&+3JmD0Kel)m(Pf{n#jstpc5sQ71xU|OhP(Av%^_B z6R^$Ex9U1<^q5zq@4>~2T^A}GV78d_l zLbsC3j~ribyu-~uoF~KwT>j~oGVo$6t%G}5YRT%Dge%gCVLiO+l`2hgueZ91f8eXv z4bCxPY5uF!{^9&ll=sY`UkK2aVu~Ax*|;=I&3l66u|I%}x71COOvOe6`ge@O!}WEc z#Pv$7Q6*UwFO{c!Y+3U|AOE9+|3P7FG%6bVM>J0IDPK)L^3g|4mi&m^jWZzb3VD8+ z8M2QY=pgV%F+;5`>wJ=R1pKW$xsoi#QzhSXv0^62P+P&d-0(nQ?RF&fwr% zatw$r0RJ8Ha9OqJxJ6LH#;f$C4-Tr#f5J;O>E$8CYR>#di8%U;BF7Knl(AHj$67EF zQXFe=Jbqx<1R18;O?A*GG;L7yhh%}0$S??&ao`rou!=`P!;3ZX=N>Z#{PnsC;HT+H z2gxNZ_BnmV(U-}61!BwCnV4lp`?>|eA+i{Q#-)drbpJU~dO1IZhFxTB!}Av1AobKXX|)_ttIHE!`Wfb7N+-kH^xE; zF2^dw@N?JY35Qi23bN0byZo!=#WEMH4nEcK7O44Q}PFR!!GR$HQcKAHw(Q<{w9EN;rs2AuGs^}@pWFL>~B>^r>@`c*H9Ro&AH zGt)eYdTbev`lNO6bji=RK?TC}_hNKyxFYp$x%rPSMhN9(zULe^SVpuM&XPJAYotBPSP2rkY;Gw18D2q(YZ&TI@n;h(RO-r+;S2e|Gj* zc?YK&lJR$JAyzo{&N%E5kNnrid`-Xj&nD7e30Amm&I>EGcJH76FplA#u7<#gle88?AoP(Lj+and~)Gnw> zzW-wEA7Xh_2-S!Lw%KMP)*AKo%j%hb#vNWnJ9K^dK*!?AtP%u){!#U>4GMWd7;i~8 zw=){*%SX{x2GZ9t_TJoB0yzU!mcrzcl%kfa14T?Wg7*K1BM`M$$WsT^MpxOP)WSpw zeNtH~-nF!KB!{o0D^_hm@7Vt#k`R?X{Iem)iof`;Ir0&Hj>2gdRjlvUvv?8?_K7$} z4>A6tE3lXsQ5tTEHz$S^fXUa!Vm*trJc}&-k~%%8;$Q98Ku=7oZhY!PF;$|=h!+Y$ z6>TfYh{Ag*O9xtPV_h_eDxu}V*V3^vCK*|3v1Pbj!uGvN+G#icdODt8F zdazGd`gRxrXKNrY`a~>TKylV1wv5Z+HSE-Q4=K#*1@WOeE>0BAu39`W$ArfsOLTmk zLB_Qgx&c-GgHM0S$BR!w?wIB_pGiq$OYNcb&U1}!7mM6(9P42?s22X8i^K`JuQ3#L zfN3W2-=so6COu8NaWOfiLc95QE1OOEgZ~;||G;&FDEHgP18r(X1QUXgHY7bWA83}H zm93%Q<8kP6mvBCz{fGtcV6sXjB_(2MYeZ}anEaxU-MS#J4b|*_Y{Y*NfIH|^R!EjPmUztBC1vumPh6+qK@>Ix;#jeQ%*Is$-Sic~rB%Rt z_l0$ISOY0@MyN=a?{EfZ1Mjum?#9}9hha&}EaMH>(`yFL|9a;m&Y+8pnp>%~(s9?Y zVH^()u!h< zp9qg!ZfWz@u^VXq!i5`#N|TOu{``58c((m$Ojjf6E^ERKFU{e6J8h*H(=abVDRPVh z`|KQt^AiI(FQJ4(p8fLT&t4Su3nQ+CvG^1PD?1d7s>N)4;b3^50c^FURrBHW3r{D8(f3S4qpCQ6| z3tIBgS)>$XonA(G_`Jo!ME}4{qW6gg4Qrn;p?LxqS5I=4#k`kz}9cpfAE+fRR5r$ z^FAhjsPwpWP4t)0q#d^qI^I%);$)P0T!-Ct z&#h$k5yPQPjg8ce9SDNV1UXJwIAa=?Qqu)4f5CnoAOyvu!F-ng5Ns$PDX;reAs~P0 zbm>6)I!h41mP&rCftZot5?JgDD#KFs4LU3mg@oHfg(u6DSVEV(Tdty)83)ci27Ki5gFjpn`iLz{w=tb!e;NeXXkec73UG}7qw z>(B<{-0^b8K)=Wf`0D4$G$EQ-h^aJe8s|zWx;xpR$f?IF~G zqQvCOby^xY$jU4}8Z4y~B%E}@~{okme6FtV$fBzu+2ds!jzs(_-^m1n+>zXrTE<)7!`* z`I4cT)w4CW=n8)RcIj&cI8?HcLeQ1ttR)ONQT_)=ZU4Oq6exG^A!C?tJ+gyfa8@Ym z2E+?9k<4KGWH^alLlsJ#FNw-LbUO4zg0NhYpOd^+(wn{@rlVgz4~I&~1Kc%OkEy@1 zr~j?3H>Uj*fD6W`97z8#TjC$ONy+B$DJPtwSB45%b=sh(W;q(YcOJ-;+pK#MZQbT@ zQg7c~QUOey?i>1H&~aK+ni1&^t!6?t_0TbylAr>W{E^i%m`Ka+DON`cw&8YF&o@as z!HUW}U$E*gfTah>n%_qC9f%wUJ&oKovfV$7-sKvT7Ld*vi-_)E888PeHfN9_v6ndx z`i#;;HREx%wYqG!t2KT}Zg@&*C6|PSf-frc$zSnDp1~vN7yB$!a5p55#E`2U_il zouKgNf>J`Ue2}5HO*LY=(opJ!WE#%Ly?HnVGIS#k2J}IXL1GRW{Tee~E#g7a4Fjc$FiYZ!VVWHel!`e+%4<9e~ z#x?koUYES!N3fnsrjXrmAG7g$X}YE|OPyVh}Y+Q!lrwg=1)-y*gSAXYPSZ(0x!9Fs1#R zo3#0O`5z7h6Dn@Pd3&atRNt@>PwL-ow+RU1uWrG>W=kAp7N3?p` zoZD=C|8&Yd%inb4Va-D@Cl8_e#jv~WrW*7eLr;N5{u_huD?tU?$uibh`EW->Tfe1k1_nVsnxy#EH1GYE$RCGwn zLFI`@6a%9I1k0I}89RZz#rIJ6CD>r&&UG*J |_B5G+Z$Ry z&yL-PR0FJ~Ff8-0q~Oi!$F--rLlyH9lU8;too_WD{H4xQGdF2-o6{WJ4^Hh|PCpqw zZyJi1iPE7#%zZ&+3M$Z)Lk~h_99j))9#QqD%h3te$~i+RjzkMHyx_av4AJ|Hir01d z7=Kv9al}C*{B2~0IpPDOlFW~E=cp{%AlwC~J2@`DG(>q1m{G`$6;>lyLw@dNyaz#q z$4L-o>$7P=-?17eOVGUwuZ-H_!qm$re*9bO{)mNDk?SgLOIIL>$c6<$ZFa(#V`JWweyBMuX+%&8kpY`VvT#T^ zn>rX?b((Bcs~;!1u(xX6M>b4K>hSCz&IS+(RiX4Jom09gMtltN;tWd?44dGgP)?F< zq*vTaw=NOgshzvFwUy%g%nmgz-3%t6h@0(nkJ+5Y0ztm2`P43Q0#MupD&X7 z)d&WAUti(D|E-Yz)fA<*5$u?BnC2`eQpeUk4iSNDIA#kknaT2JV;r2yU-dF}hk)`% z(AOzPfBLV^{KZ#r4U~Mg`%o0FnsAGwmpTZR(iNoR(hU`F4;xdBpZ5leYhbDB$hSR89{7)Z zUOdPK)JCn)PN#56NxtVK8huE?nPqvV@FYn^p}<0*n4ocuyD+t5{s>ro(Zj>{E-gBI zL&Lf8*~#L-jHT9b5VPUxZkkn?LkZxL<`n@Y_#P`8ZdSmcklu0lcxnxuov*)?64kpsSs z2i-9%8#c=ds-Mbcpg2YX)?zoqxC%grl0o4jxKrQ{0DILYBW#v?4|2%;3v!5k7|rp< z@ikWmGGX;%$PmsvoI!m4r-d??mh#0bWoawsMlRb!WNC%)EDKzv;I(rYNk_uurb;ccyDG)$8!`!=>^bM?{9wQcOL`IGwT?cW(a@j(@2 z%%v~A5^;%kS0Uj-(2jW{PT$6XoI5@n$?_@v$*7;rP6@b9u6k~*)7?HO34Fe;sZ;QR zi}DgKuR>07o3f#{(rPR7rohhXu(158P!m~j>b4ymIOvMpjv}JTT{7xhL;M&27s#=p z4~TlaH>d4a&)H)vZz@tT8t!j#Z*$}}>8CKh_@d^W=YpU+s2no<*FJZ!o1_DeYw(9p z8d)3eVOqkfa0VTRgk1JjsUOMai$NiX@!kQg|7ynzb`~;+5RGzCXqW0Uwb$snSgj#O zNwSTF-4XqH+)P!!XSW<*S-|;-jOaebidLk-NljsTiHL z(95`(WzJoW{&+ZAuea4_W1F_8=UAe(wl84U{bIEso-Yt|G!D;*ZQS^e#{Z>YXdy$N z5i+NRHTW0(UGoIepROAYTTOm15MJt-{GFjqty(f)=E#mB03ZNH1bs7EA@f5G1? zH(Ab0H_bmm>FZEnh|vCs^l=!a&cgETbP0%vTojH#rx~4 z&(RBexL>BY8n|lMIu{TYI<`L%wp_-^y4S>M(sL8x%fEv zAKYGW(CW!N3RGs;^x?S8=h}wOztjziIMXJ4XLxH)n`0sPf$3nd!^35gKX87r_CuOC z%kG>j-Qyj6IuE3If5v}r5d7;WvU2c|e(4|9=Vq>A&I2*#r|aK@x9Yy5Ku^1hl>gcm zsKPy$PI>D3FbcOXaV<%-aJu9c3ByT%CQbS#?&6;W2a7*Qsm-V^7GTljc-h{*m!|CQ zB*_?E8djSuQ)wr0i93MGrM@^D0<*Mx3fC;~1vBqmxk8I0_Uws53?G>{zfSJvcj))z z|FJ|&ZAA?yiIFC^R<++=nP?23!F{_4x7dy>nCk)H8B)i~ryVwM;o3}Tr%|=lDAx?5 zun1HocjgvYKL$>Bd;t9(31>mpxtB?%vjX|Y{>{s($ury-G`LXcL)1xJ3~(v>pRstC ze;!K)QBEl`)r#oPHXd)5#qkFJj7Rl@(sgjxhcLk|{4$P$pG`_l-0`KH82nL63q07H z^~Rz_;xECRg#Ynr2e^eM2jRwvdBve0ey`_%U^)Tas{C72Soant41)wE0z{eq{Ja5f zDX-=?$U75ili1LYI$*RLO%vN8685D|`w zsp0GH2fUOv6>l5B}PXCyKynfnB8Il!~XH!;Uvkq*Vm$G=gTXRH#>< z4i$>X2{HQXjVx4_QcJ$^FNOnO)$v{y@0sSq>2lNd+}&>Z{fWhkUW+&1HSxB7=4AWx z_9RuB;jjYCcW}i%>oJvki2@a&y)00#18Vt~UdiU14Ih^t`xScln#oPZ#Bkv9TJXv; zfLXq2KjYZ`Vj6eI(7o>#$oq|00t+s(_mt zZ}pqB=kJXeYBqD@4#zxOthqO&K~RbOM#*2FZ-8ivKWP&M6TC)LCWBHw|5zUhTd_&a z^oAgOS7vc8Z$CAv_8^QcPG-Xx7oF zb?7rY^#)+=G^8)$U4CT|oWV9j>jQ4CuA_O`E#!T>Gjyx`_&M%2Vm%T1EV*e*wbm+^ zVD8j_lWs(R7;txGH!q{pY#b?8h2M^TNOpaluXJeO=Vs#nI*2=|;S-6u^S0-_B%C=o z{jJZPI;F2|!Bax5^QNR@Q2z&Fry;5@g4#06#8e9E#j8&(zgxCa%tdJi*=p$&)Z;n@ zUgjeOVI4)D(ox4tY#nO2)N>uC zk+?;BR!)EELZF{HN{n>dj#a9PBTpICbEJ9m2|D<4A;wZ~*}f;k5=7lEvt2D8ikt1q zv&uQd%8Z}wjzdAo50;TzKLq(*@4wFo96*PCR=s>)$a27A#@Q(>ko~Vmd$QF!d{#C{ zDaSsgtZD`p(mo2;l^<2ObC?{OZd&X{KoX&=u$EqjzJJ_F=PKS10Pbt+1&g6 zWVE@UF(pnNH{rr|#Geny1o>vdO-2a@6%wSK#4af@EP^|T4-ONzhqv|^-*I4)Lxh*` zQ~hK3aBq*rJzaPzMVVM@7}vM&b{YPFpj!R}oD_E>_V$`@VzNGW-IdDU9Z;r7I4WD> zfpQs>pxMwpy*?W7|$Ea?(?bgRnkgf-21iUEy>##ya&y-&2tpqs} z%Vvg^KAV=9D2zSMC52Rzj;wGwa4jD%iA(fld18{A3@h<#9I5FmF5SF$YUl=2)xJL!HIRNB#FewY^0 z88=6q?&YeNlk_%9Q+zaA2^rv`NvBKr4zf9alCf3^g+=;q+tP$_W0rBCuDS(^nsHgg zK@`wgtL%da^3d0;hJ(SWcgmk$;>$h!!*14wY07pBQFW!B9!QMSGsb9ZS=auo@Q>90 zLqjaa)ehVJaCU!4GEqKEFUzkVHQM*{I#$C{W8Vz!I0A$SVAA#0mvku@ECx5-`1+xz zgTgnXCo8K2a(mdEO2B3M1rz1cnp;aDCtNB#J&yI#OR|{of^M1$K?g0~d}3(vI0mfe z(_yE)==5FQL{ykbSqwU43r%;nIdWwXdcK?G12_AZPD= zmwDlHa{wusiWLAsVBxP{BE%KA*NsuO2x&Nv1$(t+NQMxzq`B_KIAfObPBos$tD((0 z0p&S+;0kE)yIwNL;dLl(jw=q8JG^V9Q|8L>Wg{HBVM8hbo9Q>Jg_(DOU_C;Go{}l< zUp9}5@S3K>-76fJ1ondL3Jo}1vo`VzHKd>ghB-)1#>{3}RH!Stnw|6|vfJXSxNbZ< zX*(F+njwvX^lg;iO8Pv%JM(@f^?LvLCs{-R{{JAPPH1h}fPbTNwIE4J4r1@Ew=0gr zT2~gAx5d z4#ep6?907~K3cfgFa3dZ>-3}45R?XY>72@|>~PjaaL={nh6goZ0(8HQ2K{@E9QHrJ z^8+<7s>lX4V&u#|o7n$$G$)Du;klyMO^9w={}3uvopT%XxuUa+fVre!<#=Vmb1-<8 zkC0_PU}rdt>06Ad01_nJw? zu_|qcn(BX=N^YN(GxbezF~D!s?BV#?;gm{ux@-#OdU|d0B;@tQ0bzg(-bf=k26_^1 zh>i}6c)4)T&#I3fZ|lr@#Bw~REuFs3-4M~ZDsadBY;fu|R=Z38X%>K~n0D6o0#7dh zo?>6|f?3Mw!OsAmzC7(sCB<7(sXorgYmqt*ph3ZD**LBE%(QuND5 zC!XHZ&%IT1lM$~#DNxtWh3VBR3HDp?mWK>HD+qyS_`Q%ypBfboiVdj(lk9SSUgDoh zg+j%WZ7q~TpXB!`8Or}Z_TDlq%I=FBRRk#|Bn4qmloCWmP-z2Ekx;rpq*Lj3q%1&1 z!l9)>V3ZVw5Cjw*QMzG3I!C(Cy7B)!kNRHMd(M~h&2Mul``&x6_^q{9?0q!c-q1*O zWuN#C7&ET~dzVn~M8eqU71+k`$ano{Dg*(>)25a~73!*zF^b*~-OLV~p0byA0cfrs zuPU2mX`es;O&ScE3ImisDN>CcM}8lK-vJNRU*^PlZn$|Z2Td*G+48LFZ$u1L)BE1; zb~u20giX~HrEj0V+USD}*aZXjJ{+Y(exHEfHB=f7uJ($NZPa8CwB^A*^1nw2;+LVyeKJ6N2l=hK5zPlsiE&oXa4 zS3=*(n0}e{`u3V<>XYGE{#PCR0f=>?u<@9%vE&j-C~9BM-RMYS97fsb#7I>$a~ zD!*TA;0QMC9iLCrBaD1&zfOAqe1J&@L4~vn9Uj8q(UfIKK?Et`4M=)@gi;+i5h~iS z2UCT%rI5a8W~NOi%=Nhx!^bsIuTp1vscrk8Zv^t>?iRJUi9bI!yy1h!<1%oF$S<%! zA6P|g$P+}E5%JGHG&I_<)W{}^QnYUAj%j`MI$VKE_r|j6cGA1V#%S@)@B!d_;kX?ja#*F43e145zuA(0B^!~*ugWF%S(t9TtFn^k$A%eo$%JQ6)l~#VF}AJ zHeGjkwAGW(pzIA(b;PTWWtT~!yFZG8-9rC>wb$#iOCfbR`mlEA?8)xB7SJ6QVUBIx zf!!9~q1u!3@su#0nMGRmhN@Zs^k;vxjzqwQ5vYyjD}kIJyo3vv=os{C2f4lr9vfF4 zn@_WzaawH>#N3d=^<91+FXM8CrVl?*CC3a;$S0QDW??V zHivnzyu31Xrfy6*MR*yhfstq&s45jIGEn?hv#*^|f9Dj!w~MgreM}cLVb@>j;5%j1 zvHBZhbCJneGWw^OC-gQl=4*UDbNUf$O#-<~y^6Bk;E#x+Uy%_1|KNO-0!$toH}vG& zXEc=gc-^^9V4rqbRqe=%0q13)T9?=zq@A03tpIMR_#Z&t0~(RB$RY;ZA^}$HBUf=y zKW;4vc097t*%F_r(!&vPX}!ZFa1cwbm78j_0AsTcts+ zlbhG!*v`k5wv2*(PVggneM}NXvg3#Oa&s#8X?+^ zM`KreADrRFr>_i$4<5|SP}++s*^phYaH4AF9Bb9^0V1zhCkG*86=5uULE!dS#NuWr zKG9EIqmB$w%u#o=FV*q3_ppzD(`JOT8gdZ4{c*Z}4-^}lUQJ1Y!J`#G+^t$2#N&sT z1Ry!%`F!OYa?st+l0SGUa_pGn3$d}TMyKJXqnsTN2bXSBHS?S~;tMH&A0%U(z}Fuj zo8L3Cg@9yqA3(2$P~?%>ardE>)aqDCM@oFXVRo=*RP5?}YaLD91s4aZ=Gv1jZilfM zmtyCi0jb`CUfwZoMMMNjPw3h|SMqiA*u-L#H*X1Up4Q)4FD`oI=oiV7x$k4D32)>A zZChYMwLCiy1QN<&@M@J+8qCdwCEJO{Gdoa00X(Q;Kf`DLohbe!8 zd&{>m0ToYiGArW4p=AiQ9B}?hjfm-apxXa38f-_9*3h>V&MjK&CKz?cIW|YDdi578 z3uap!`K)N8Ypfk~7-2s(PcUGyqYeU+OyiaNz=@8)#WMQfZf{TQpl+I6&|r9zSk!Z1USor<^201{uFUjjzHn1DSYM_)f*BNbGur?Yqt4zMq!^!#Z!?z2r zz9*(1S&Hf=4!@;EJ!CmxWlX49Rws&(L-b8gS(Ff&iH<(-!R*+|zaK`7xvz5K1!-gpf;3!yt;nH`5#q!(R% z%X=SLPF;aglA{_lb%oWBR`MIvv_Sxd#>XT;2t5R0ccJH|wqvb@0$kV*f$N5S{WF{8 zKU@mtrXnxmR!0eLpE=E1oXE5ZwA3~NdXoBxE165SZZT1izJUlqWh-ccF2nfD#OCx& z?##`l&Cwq6!2!6YP!S!A-l39>d3;X)PBTO-l^p z%~~WKB(5vgy`S<1Qm+YiBbIIuNMgNCw*%ooH;DDyF#G0&inY@NAEw?lYP?sVv9IAL zk5Ug~_aI~6*RF=OC_!wy4<&3(SbGf##Gv28WR4%d&*3W8=5EJz)Ejra!pIj5?EHk! zd@(k#nF^CBDoP@-UrPnU+8ZStU~h~(pv8}U-WdBXjf_+%V${R3)g6EMn6-RQGnk5i z+k123dlBQ7M&gsd@Vx2EHgg4na&nX4&noW$vvlbqPj8>XXn_t= zvXeJiU~we&A)z^d1`orliBVF!N8EzaC_gL98i~m8&LD8W4Fjz&zTh|vOTCKVS>XW~ zmAysjNn4{3YE$#$Y43DfFNU8BYiZWQAqsybcJymL%69W9w!^p|ZgZnzp4HcL*vZ!F z)l{onQD3TCa&gHz)UJkLdE1yBZ2@pT2S z%ZlvwWyfk%bmE4!$!Th+X>4nrId#~=CI~ zsli1C5yo2_dD^1Yua~GEQ7tvLluv`Z*=2(&dd#x8+Q}k2*%l3Vz{r$o-*iZ7}>M30vAb=S{?bhL!G^b-@uKLIUgK;nlD0OA6@u5WD4HB8Eue4Rq>;1=KG%ag8&h1F4sf*)8w*ureDh z);nBXDv3{azpkUUY`Lbb<|b{>+av=ryJa)=0@fMM@N=C*f$2017XGl#OV8h)BJap2 z7K$$OPMu{<1G~Q_EShCztzj_ppSvJy`jaTCFA_77NZF16Bd!k}TQ@>xBUYmq)T*;0JF*as5AG^5<6)EM+<&8NucahiF-O7%5+6%Si&lCZdR1=zr(7ay`4< z`E66YSxK=WCv4H(Dv=jNjZg3AzyR8_kp4Fk0g9gX8^|c9JY|bBeS!oHl@!k5xly;S zD)#M;;8=pgbrZuS3FMe8^}kJq-k#v2XjX(Ndjxc*2Q3@jJ}LQn^g=?q+fV02%ybvU zbC4I+MXE6raPSVJMPq2;V|Amj!Tv^gvUv{lNzz`xeiALKTHE!yl(zQMo2K|e=T%kO zz+nBKK&&HzD8)TlRiAuktAjrS(FxaJsh`w>SC>+z2dCaGu}A5p4SygP-^kcZdg~+4 zhs`il{A%@sM+42%lUx4vfHRp41{c5bcW~ChJ!~vI9^w# z8Z0=Sf<=yAO$d?cEF?XI?RXZ_2INH);`$G~O_9=|?aW$QQ#?qFpX=>aRS|i|jSwAp zyA30L2vAv2CqYT3bJ&jy`y%w&61Yu8AZ@ss=pF-(+O9=~Lk3P-N0qu=`F3B+v|PNK z)A0?=orX#f0`7LCyeWN30h7^Rv!Zf}aiuq6~2Avp7ce&MhR zBHkNTx7 z!BxP;aZOcu6}>1Q*>ECXV;+ zSJ^|0cRm%zt0D}`E*l@SK>UJmS#=Nu=O-f4g4h>m!m*tsDf9r!5F2~RZHlt*ki?`x zrcqeji%-L5a6awQo~z_<&jDhgt2lttbbM=}g$A0Jjhd{luW`#JumEd46D?44Onh^0 z5{Ka=71|^&y7r2$`EyZRujcO)zwm{LjU2tSj6}#Er%}@JsR6|j*MqHbj|Xk<#A4)= zovk=;#$sysUM9yq1&55Ah89_}4f^D!#e}&W6lgRT*n?0W?JsqEeMh>86@4rd)BJNqY_Ar zz$cwGj!$%ZXWW``LV)r!8~{EyJH!Kc?PcMs4lR^a08d6$R~KoNsdObmv@Vy0L@u<5 z+m-#XD%iU?39YnLmWBLK4}?SN%JPUr<&Zwy{MM>I!a_8LC&9mZ`NL@fU~^jH^=>l? zM$ukQIBp>t5aRI!*!#R%pX7h>MI;K1XXYE1*S$Ut@11`yfUCzMNWEC>uhdzWF@NyH zO<_+B1OychWUSHDBwP_KJC?T5@=N^7iTlY?XrbL|=c5KH8xLR#$RvV-xpGtX3MB5q zMNbp&o2S+I$1lxl2(tIy2*q6jumebX>abm$lA`5yyx}B;&5!0*W`Gu^4-=@bb5qI{ zeIupCeO0=>z7=)4Vh@IkrN{?sf{JcN+A3yr+!4iHH8KH9Sj))?{%OKDl8w!88e)1| zm-%$%=HZduYn86AZ$C+sm8t78E=?s1K%`@uFa2X)YG-CB91*1poDL(Zuagij(^)dD zhjM|)(ymPXeOzA)Kq+!4r;H%o$7>D&d5Ey>OL0%$dp)hiH=t*(xz9 z`*RdY^hr(mK8jPos@sm%hVP#)-N8*2E54_0yjN8>V{(pg$SMQ>yDrWD09}%JI!I0? zcJ`+A!yRaM;8fh{@Y9PR+Jm;*M+eSA3FOFu=7&ed%AtLv7yMz5K?@}FlO7-|?31rf z2?y2`tFfc#VbDT5rR+}*$vuyY67x^tAB_Fz_Jy*KNo=#YsA+ndbh83TX0C@g8%U

K{gllYe6>awV1pQ$%0^ABH#p_PO<&>Ya5S!b3lM9lgByZkKaX+U zNQIj0=Y^!~9C)s@M5FaKeR?6R*Qzbosw`frHzL_#_yzcZbDX^oZG*C0POT~=7=T^( zXleR}Bpi;SJ3y#9waEbMGGw1RJ(b-BL_UojCF8tfjx&uMmG+5udN6$<@MfLq7jFUV zVGPf&WF7@?_aQtwz#r}sLz;;=B03A15c0S)T;eu)VfUb1P{F{tW8d@_?u`5XjQpin zBLaDvWb^6Q;J5}PI(ixbNRXI01|(xWnOF4~vtsGag7yMeeZ|8X=`TuQo(=WC5h)Lb zz~VmaE|9U)7={`hCD}sl*s--$VE#?ypNC>5d&pxBn|t%Fn>S8h)iFKz#Ggca-^WAT zCQp?MU!Oa?hTR)tejr3-#DT{AfZ^IkyL6C9F72KJVn%-NzVkix`?!ySawz6{YmQ4w zPwe!ICHImvS94c$^E9(evvK$FuEpZgtazVs_wudO_SLsl?KWPdv;b=`-#7__$wEGb>uHz z{Kd|{cI2-?{OcV2b(H=(jei~JzlVvx2dlp)#J{KIzmbE#QIx+CrN7a&zmdkjA=Cdq z!pEa=vc6*ex!uPZq&?ha)@$ZcOUR!PA5R^=r6+lTS2lqaqSiOBS{{O^wHA`5l=CWw z7ahIOx76#>bl|GOG zSUb{)q-99W2EUye>6K)V-WQs>vKlO6Y!+He5-laGv)QV2{uA{rH^>;BhhRE`sTfqz zP)uqvgv!5qn>EjGdeftVk?$C2Bs&~!-Lsrg()!va(^9Yt(d?pZ*gXYL`RjnAH zV5;&Z9X#oR>Pj}D>Mb8VR9N?vi=V_m2uOnbp7PqL_BH6qr(;8~FYvaNkspVtOcIXj{%f2^!VQ_7N zN-<1EAQO{9CW8vwyo-Ezisy&1Qu-H{F`NDQX_+kaIpdK15-2R3nmYU{yP^Qej8L{S zuW>*)XS;Gu$+I^9Z2gv%(nHEptPQ_M=HE7L!QNl z9DZ;;ff54vMa6R2{A{de)3xRPl#N+@wE6j6=2Aied|2)0Y0jw5D;D}!_T1lrrlD$Q zcEygSB9(7sFp@e!>tX^adToII)QBFFvggBdctzp|Oo0c5P3u+Y<0=TlN}ldR%DiG> zMrW(>N5H%lsH^&s9s86)OQk;$pXc{vSoOrKx55TlX4xo`=z<*Cf`zUt>BA{Vtrvz4 zD`ac-=X)Qa)42>4Xw`Loa&hM5x zd69(lAq!UMSowP%q>SeX$VqNEPF% z07IVnEMJn`u$(%^t+!VmDyFTob-S);O;Bke_egZNcG+*Yiv^O9uvd_h2(h&H(h@{8 zm#WuHR2+L!^=@MH(@CQBna|?(wSQMRVscnE!3i|5@u-at5Jn3FcwwoeL$BqGmY9y- ziwbE=U1?|9z`Czx=9U*SQQ24}>4k?(9)3lY7Y?FgbREWStKAOt7l;6egEr#j`Wq$8 zcFQ+;5ldctZJ4=>DT^W#^L(1`fsXaph^*@eS-uYfDoVZA%@JNfaFr_gxG$9oJquY5?j90q6b>{S z*^M({(~HlmFl#zKy3^rGx<+|7-nDF$$NIM{6e5?J2_81m#XWgw3hNw28oWG3PY;SR zUT#ZspQ+iHMYToV_Qs^BP}xMhY>pFi+1IH`&3#Zdp%fO`lU?=#l**_ac2^$QM#@G9 zqgHZ zCr;yOa+K%Bvet|}%uvDN#ac#Tn%|}le^(byIwG5J4LE*s!b$^{m=0CK83L(NXerWT zIAIp(vu@NP_dmEa*ALe(pdwcRL-0X41}%+1C%LO+JS-SIfFZh z#a5PenO6rLo1i_$gR@+#vK7>amWMp7f^H;$leOvNN6_RCSm>J3IgHd(dqZXUqU|69 z2_a-HkY(Sd8&1l#M6pQT8LF0?^9t4j!9X+@*@3j|f$28(0TKe1!W-x`6oOn&rk9@| zJG}nFtu8H2p;?eCe_oCxIz_i2F(uYtOzj;j@Vo?g-sZb=7@D=wiSTxP8WhF#hDBl6`hE>W{K>#-vdF%^4_xPfiXtb#U`fWP;52b> z{$9*lEX!h*x~s%YMn+!%looWDtrmoReVk>0)LP1ciGLVT2>jy%3$JQti?>0Ml)2I2 z&2z_sd>_d-cVo3x@@P{#nW2E~{}m^CzR?mUkFNPyH+L7RtK{iaP@wTvSK9J8B`6op zj0eE-j)Ivscn~*(6e=75YM(7Q73NLReVU_6UU(*G$)KCs)xJxf`w=@-$)38@b-B)E zADeLtKM+R%_@_D0i1a4c00kZjWk0a(m1dWAxFX{<`o^c&l{~Zn0Qpt;`j1v?USoH= za-=X&9QZfU+{^+W_yG+x-*qLp`@kgI<`MdYr-Nwg5{5T>rP;J`Rv=31Njau+F8i#E znA(>$xDDnPrdq7e#w;A*zjZof<+6!dCi7S z3{tda2K0>1GO?ki^0NPAq{?$h;)MG z&MgfK9jz^x6ZHOL!5xkROW7yV-Ocw{eR*(B(NHA}FI*{8^@hL2C;__9wjqX&?_6aC z)7A8sXJJZz08mPG?^b~)O5SXwqQqui`R3-Ur2?@l^6i<&+u-#xMce1%+pUgAsFsVW z_9dQz57 zZb2iGDqdk?H>sF?{9Z(B0bGKnHg;Kx@>(NO=aISWsnUKvhyvw9vb>0yTOu;1e7_n6)uLhQB2UoVm%IMX0afes7njmq41sTlvXY; zohAc({fE>Y(252NCv{+|=UhP2BWm9cKtc^Fyqo+prK9LA<#FNg<fGi!gJr|H_GkI7z2Y3w zeY#dQW?vs&O`J)bpMu6B9(aw$Vx$LA7DH>;N;|V0LQNH^KNgOkPROA9;`@qPXUXp%`42T%a<2l%&ywcSB1O2Rl;MK5(ADZ)iorSN|qhoEvkH{D2-Xe!a49T zR-41z8hE<{tq*(CXEuQH%b$+!B|`2DxShBm-Ll!SEc1Kmsk1jVqk01$(8aL`bFDvf z>ue$t?^SX3FoR%~Zki!JPXRPPz6vODhT?WVXeSI3$aZ+V5%tAu_L*DsG_{BE#5|S6 z+`>)L5NUX1@_6sFHL}nc3idW85g`U`@R!U2?v`)g#Ssn$FZ`nyKtTxTHI?xEN?$bP zmZ9VZe-Bx`pX|Of3+b<6{#$Of4+f2^c8dBidcxl=?jUYoFv$j;tEZG~$Ve$}A=WM5 zVU2xJs%yZuq+u$cL2pp3XDx5MYJ@-PEcfnH!cxwMB*!lo4NafNM@q<}@pp#2kb4qH zBaVV} zp2vuwr0HoMCkB)Md#*v`v>Do;G8Ase0IDJ_VF@pnYPc%iW7e;@`R5ND>UZhIr$$%YTZQ{XG8%3uBQ^(n3ii<$lYdAy!4u@hZ@WRk{7#ZAfF5nKTUp@ND*z#On?^r~{CNOebTcMQZS2`?bH9K}a(a|F`$JyY zKTXshFZT;2-3K^rH2oORFR~O{Z;4E+HgzpYcle~B zJ~4ZVWuMYHd{T(hL4wY0=fZRl?(3YW?IPn{K)~H9&R2fk+z}CRfmRFN5nEjImp&wK$ZK0xc)x}H6$z)42xhp;VgGo_B#Ax4tEsO z&l-ks#K@edagcROe)>uL-k}e>YO53m1N;qV?>}%b+G8t8@u~nel6}-@1IX~tDH?8Q ziU7gX#;6WvH*zFw4#=cd*MwwRc9-ludS>&<>sb@fjRw!ri&0JwFk;W&vkn78e5kg? zsuLz}VJ?D$;T>>g@)K^v7r#VpHoPsvX1CpY$9g`Agco&|d2`N$r+TcePD1+ZT*h_l zSYe3yaCq@0LoD&jKUyZxi!^O$dE!~fi zAWSRlp&;k(0t44q4cJ`^bHm91-NG|undgSpXI3j&n{lJxAIvtY z@>V5Ikcnm)>^N%kuSS9O0ffSn@G*lS;zF$T>VDkJGat84?qy%YT239tt@hZ(P!Vd< zuK7pCoZK&#qr0)7%Z+Y9EKlGY=WV3$f-iXO%|-SEjSzXCUPfpxEuCMUa4WS-lWnQ$ zc&J39jkb5j=LSRLD9CeBx@$Z4??nG!Jj|z) za1;tE@+oDBAyuc(A;YKDURZuAujH>O>2l~m`8k!Qd(T)&5F?539kFy2lW;cAqm7bc zS-N>XY?@?YEK5$*von8V6?PFTt{D(*PFlDDjQd9B}n^B@y`hmPkC`JOMO?mX*6melHvY0?7PL>D2Sc7h3EWPn~& z`K*#kQ%*hW-hY>e{1AlZtGv6NBROM173+6|=VQnU?kbfsbL8C?T%TW3d~e-yjg(iW zAWQ7hwwe5Qorr)<8ZQw(trAe>gu)(AZ2t6=@x+DYj5@_YmiJvw%Hrv%&I>2Feq{lj z)(a5bxIPKt$sk|xzOyQGmvxrzY+R%emNGrGz6@B7R?TLQ+X=e%D;0IXEI2;inx8Uo z8*yDLNElD{K|9gm=TKtwK0I-oPR(c~pG-ro(0><){P@ZP8v3eMCa#NmrtG3tQz~kB z{k7y+J8{-9?)ZLAHetcZ?TfYk8&tyeb)|9`Ro+33!l`LB)uKEh%pxp(`=lg+l_kT{ z#QX7s-$;&O7gsbx1%Hys`=8f)e(vZF z^Qeu{T&){h^IFXAmdw8ClDE`UTjnf`cIx_j0)P9whG9Y&8ZT2Pac;vJ$NgO1lQhnK zU{+j|wtMsmW>Kx?@_(X@D0w!iI7>ScopqZl>Mrrj_HppcS-LJC5@6`lc*|}6TaId8 zTJX|;yG2N(k5(cRLsfubU9_&kh^=?iK5ENYS!v>_elaF4YRmfM#J}3J{R1@8i3hua zxQNQ-$2nH>gc@i1Rd{ZS&%F%et;*t**-wKR=eo;}sQrI?K_8)TI)r^YTKHmCMp}x) zrPv0)&u1TA^h(jlW;m~MAOo%QHATmI4~VP%GH4&^Ls}cVPD%F7t`3Q+;i)6fk2ai@ z98GvVI}V32^O$~dQFo26=?K96JIttn>>-Vfn0=@*o;S5xaY>xks=!yv(p&XJy!%QL zZ1H!@dsQL}x5kPpzt}@7{eDb2E5ttF zH`+ZZlYNcGZ*6)Ad(Gcr$=04S9DPdeKdYdOp=uES2m@^Gy?+~^5+eH)jjy|@GUs{% zOVpA=zw3$T6s7lBT?46~-pu!yZG{utFS;p5#mLgG=TUcUdBHKYI$tDFV~Tw319xqe zukWgwo154Fu?dZ1Dr!by$4;()LPgUQ**ZTZgm0Z%?5hrRJ4kT4h*wa0K{5CSv*Bm? zhulZ-sa!J(JA`TTb`kg5;0bCKe7$(oYVo^CU3IRM^GQjEq+~O>Cy-wLb#M-*12=y+qPMF4jc+(o^x{H3y+nF-KQKz^bP~-iCtE z7AMA}B-5K+GEvxqG^YQe4_cSG)+&b;M;59o3=gQXhh8F$Tl(sxhF5DZ&UrfR3=#j| z{vJa3&=X9Y5+PK?OL6F#xuNTG9KJmze;m*zZF^F3>Rm{t_Q4b|z5j_C81s6Pj@@Eq zQH|@3@~-|9F;wbrN7vS>@|4+Vx27^eGCShK8h(?`yRxdth?!+2VcZ5u+WD51>N98J z7N6h4nAcSP3FmZL5@^9)(Yl470}YpFL$DVNRJ(*nDC-^v^@)3*Jm8!lA=?s|$^F}| zxvCl2F_gDh+G9NDt}XX8 zT+7|Bb>*n^*w@#yG7V8wyc|54{24jJzu$hkLVb&={qvVVP{c%n_4ET_NsYs^_vEkn z8~XgXby>dM?N^mVC_T0Bg8=sITD{NmMDAkek*E#}F{Oan3FUYy8HbnD)aDxE)yQ=y z|FQ&4LwSp#J-N$mYo6TIzpGHZ#O!TFgK8)nbp?wu+N1xR5?UuG5f0$L4QiqL0N6BZ zx>BGcZEtAxqsOs;vPA-s6AZ82c8w#7oZ=$)Yl_3sm-XS>|tDnvo z-EpI8&Qp5UtX9zU$IZ8|!eyD!c;4Lcpo-OpN!FR0mzD0jqF1ZUl>+Afv?UbZxxcPf z@^GlmJwo-;=k$CZ#R$k`i72tsR;+BO9^^0{{6h&Tz8`@B!_lW3{QK5EI~inJpXqcG z!~>?%`~0{a_U^W*wH8IzZx9K&6FLiTqd9VTEzq#+gu(k-lL`{{fp4cOI6^bsFG-gC zA2RhpGob~IpCU5%=00X&pO#>^s;Iy^WlhVtFRHnX5<;>%gd?^i$^Q{HVTdG~#-?{O z*1)ZfY$JjpXJb}L`i|iGm}6>{F}uI0wc%dw-}nHlVzF>GniD~F)7zD_5kwz_ugnkD zRnJJ72)uH=O{j_T`uzf0(l`4oY>gbpI7A4d@eZ#EH9m^M9?ch*TX?}OmcW{w;EDf( z)03n+?Cm&0blL2tLM%-|u3>XStk`}7V$=g~Z=19KiqX#>PhQJf?~0E1*a~s5hMQ{Z zrb)&&m2=(4Z-Ki=W$hA4{NvvF=iFcGD~B(i{fvcj9Zno+UXRFa6)--R<_2fCFEz@;f>!M>~7rH!3)9mg~9R5VwDn^W8I9=A2sazix# z?}`Rh3;D;eZ)d^IPK*@Cx@H=b=q}mUS+`0qCFW@7B^%~l`ePD0WRjV;>8Rdyp|;#B z6}g7)KW@1ZKUQJRZ|0e?{r=ZRA4#&QZ8p~xnh1_jan+3KfV5;#9{tiNcPxdXyyAq zV3*NC-DobH-K+}bQy%Sl|0+E`UeZ$lVBM~7O6J8MOP?Tt8(5(@K?X~xNULvZWRl0%%bACZHZ)CkIhK6GSjydB7 zMsq9;(NxN3YBN;UR-fu@M>YRjLJ1G@;UyUfj&h%-YiU-q&4aboTXQiPO85?>dg`|i z*O0*@U+cBJY1L#!F1!c{eN-ix#*?eNnXHKM8Op!^y=)OF{5fuTP@*cu^@~d?Nl4Dv zwG2h1JnFysDb)5M#2OEsq|oeZiiM@bo!B3@@#Mi(vZg=SK*tC7tK|iXN^dL^XXP6( zR7&@Cst;*xN6`OUs70b|7D=>WaN0%v-bB@xjWdKgrC5rsp$B0?>z3OomtVyJtASA8 zz;iLg;oDTt*&|kJ^C;i>i^~DL6trS6y9GvX8)|o9m7p ze1*tEF~i`!(#D+O{4Qp#vHR#Bvj$TE9^&m{KIIXqzs{2TW`c!JU)tK;BtA;XktKDw;^(NUj@M;yE4pP~jJlGIj4hHU45F5UP$%f)Hv5Uk$8MY!%85w) z!@MQR9^Dnqe!3wre&Z{RXr^}m>|SDebdchns%R5hmu5vg4g$QtQLTV7|0MQG-r5Rl zyB^AqJ#>}qhT2>^c}UQRjFV){?U&X)&BCvc+YNu&7WO2%b+_2oopZvtDG9rovNu1b zx4I^H&YzKr6Ij5xeaD9lWT-OG;5uY5NM7w1)lm=grNB!}?ts!=&knJ)1|j?NQJ;Jz=WsH7ssxw7l;rV%1`y+?uiNtJgJHXm7*`-S|&Pl`qfse zNe2HPFm0g(4v(TRr{0|EOdtI;uJ6Hh{03>}f>-4&3gwWtlCvBBM1WYHs#@ok^4ve5 ziwomsTt!}?-FO94+i?uN_ETGYm`xFKydGu)yh%j zOJh6UaC4aEN!d7?sZIFamFGBKD1tjX6-9LDSDOg3x%&rA!%4DfZJu@NLT+znHAmO0 z=m$%F=(&_6d!@5hg7A0`C2{7t+u;!1z?og2ZvMf^AjB^np2`D-X6_4l(~;z{zf9`5 z!P@X`q6UEv~%zTrIMT+ z{x_y4FruLZj&$>_^(vuZtC}O}>IzXvEYyigy<{4nggVZw6f8dwbLaUZR^j2H-(Te7 zQ{c*~?)y}rBcu@Bt&C23&p;6%U~XSNBX%=ACnv|i#W zt>igTHc{o{HnE}r7t+dT!vX-^?eN#FolV6PdfwRnxXtOocnkBYPt~uaiuatuKfF-$G2J%?cHJ@Cx<=F ztA%S+lcrr0@N8TDKXkptEd}(qh6(a}LMz=z``rcM{MVH6BP*5u*CT1dHMGsHXtfY! zgBDuf1*QjzFJ$m7@#-Z!O5y?I#>9w$YC3bt7>7}Wm-6u~(FQ*9r`l zmzg%y59ehbqr6t@XUBO!IpeBpx;X#tv%DN)oSgd%Q4G1^BExrMj%_f0-cBO^gAQ2& zPrQvpIPx%Uab?_kK9Lh0uf~Pb29N5>&{sVmjz$~9gKrV&F9w@4!#}LTwPFA9 ztmKHwMWe8*F77y!X8V{tZW~7zwIZK)FFv~*;&cf+<`kopD=xj6GV;!Fj|)v-e^ku1 zdW)$4hC@VO6n&E<`tV`_yLlDL+ebXP%g2-MgIs@t+asdW1X2Iom*swMDz`@S-*Fy{ z_e+v!HEGw7@!rtl@B2|~GkW3oqMfd`oN#Oy+jxDV|EyCPx8v2EG9-iWkDz?DMGwHJ zFSL4%v|A&3MQhWG%BAZaX-W3G35t6hI2naqVm2FlvKr@h4aQp!Ki^_M{;Q8&&%_6K zKeW2^XpNvaLTOvSF^1{5Nis;RPNF$LcGj46_`MM?*;!gi3!B-F;$2S6-1Er&H~;X7 zv{fyky^<%R{B)q$7GJ)06DlgaNR>;U^emY;KklrD39Dopw_`}iOw$|k_Z7~>5Y6BB zj1?o1BNuxxkJOy@`IfQh1-aS!7`0;3WW|>u`(sSkojf}{$~v7qLcS+%@W-;(t#!xe zN^uLKR==#FQ&`0d7&eQ*LT-5@b(6@H@O}DyALO_=QXJp!( zu5pwIl~c(5nI?|h+8ZXnpT}4!AfS0AuWS)c6D18wK{K|__n!C3pv5SYlbmV#jx&ec zmmfZ`KlJMr`RQaX^O1?SLqRoSA?=o`LywW_#sAS1Zj%*fYCrs5vCFI)4hs-rgXtZp%!n)n8&CMxsa*_i(cT zE&|Vv1foM&4nv#|G<$`hL}gF&h~>Ic!x&>W{s$$OF71`r*BPuK+#d`9yZ)^m| zJ{jGa){)qavZyovd}IeYl}wzY{cyLFezeTmfK#zcm})X+^YvJ~tR)HiO`|Xn@@6F} zXPO7{lLz+2(;A#!in$l-O!W3pim$8iOT9-e7`b@iIO-n~!F_fVPSV&bsbdt;P7j;w zavahXcU7E#OV*An8%dV;vhIp?qS6q*G1AXEx+iYrUR*HIeb!x1dh4u^>%|7i%fEOM zj8GQ$LbE@&_c#NjbDIcpwsXwL%TeeEifd5b%u$win{oJafW+9wImb^;^pbu{#Ir&Y z7CBSrR85RyRf~0QT&ey~7qPyO6y&@#cI?JjiP#o>HRSvtV|@4tNqm4`>}$wwyEPh8 zx$JH@G1}qSfwt^ORxP=@su=a}+pw~pkQ!b~$Ft-{Q|4|3CfP2&Gl6CR4yMbljpAH^ zV&thtyd3WsF2wC>oG7-rK;_L-H?T$+@f&$tSZ!L`8Pa(z)$#qWhvIf5HOcZZhiu6% ze(#o>flQ2JxOLa$4I)y*y+D~<>X@>FFF<C^mcCi_i4AvaU{KM5(XvE}$;2p!pZusb$?#aNljcep}1K3CbcX%5$>N-X&AS+nh`JO#C> z8ih`;*+!q`$nAQbeHF>un8PUauJ?im8ZW{9c2ZRU2`kP+rpHnUqDpnT7%sE`H4>-|MSS&Xf^{giL(T;M&3US#F-H zP$}`v$m@QgBNg7Beq}|u6Ut=*y*$l+P(=^r^!{w3rMw2um$Umq(yr)t(B769`5B>W zy~bsB)-h4ZD`X7M_5Fdda*3DJ{SF+}HjKMonBfIeAFhH_ucF>i4 z%EWNYeX}n;_uZS=sY|vl1@V2yT=H~LMBB@sZbTEzO&l9u_jH>lIj1(LdWN1Py@7qQ z>3qg5BzL4jd2P6QD6do~bZyB`zH>#nFLu9FXgMlgHJZ>j+3()Gwb_~G;`iiWIjfh< zf>fKPPMkq#9QgzXF5X&V)eAi{Imunlx^RMZOV2ln%Vbu2-G@rWr7TW&#%N`|tvZ1_ z*yQ-|+Yv^O_jXdPvi)+Q7>cb0ev)YMF%DzZG_w_NN*fKW!8yA)O8XTTVLkWAEw+Ed z`Di8TWG>!-GfA`NbOZ0VM8LwY&AVT9-L34{;AeXKV}I$D*vBG_|TOxEcZBWphNIPdZf0yl63c6CDy~M8-j{^6VxxSU z5l645=kLv5?o$wUm8NB;kwJ-dFuhC;^eaqSbew6@yy2S>8g+0_{0L}j^ilZ@nShUl(3l7Muies_=DIvf%ln=}qGZ0QIv$QvB z%b^uxF+)p7uoH4bby&PgtROBX=*#GDz%uJLBU3SlVi z5LK#c_ZkX(F*`l8Sarnp%s}cnEB#;mRF%B#^!MiX4&adXKf5yvxAJ-ipd`hzP<`4C z)8T#&r>;}b^4q!dO=Vap2d(d>9+X)Z%ORbDq;>M1NQ(WCrOUg$5Y1RJY^04ZDM1x3 zMe9fQ{(20->Ywss`9XEr88X&08-g z72Dsk{6@mOD$T@g4m>sErp3p*?S4H*-r{wbN1G4~4Piu{0}K`YG^1b?W*pqae`BOZ zHRXoG+z>=wH_G<#8h`kAjZl%K17VGWxRId=c8;Xdi=y>ebDsf+U$8iM${5V>1d16J z|3B?r`#;nBACDr`i z;mXupX%Ko44!fdI+VJgh3ByyYQ^jNjJ^r6nKnHNre!9! zB!21B#}ay|BPw@D5CCU}xwii9(piZ|hHuS4UDtC>x4+f-G34F;i4su|=~z+|+iTz} zbGiM|DbBj0Q`QHnHvoX7_1)uk*wlE8wR<47K+qS5R>Qj}Jn$2(?Fntc7mdS;G9DWG zJ}phapUCC=T?N=BnA39~t%u&0QmilCwiB;)hxFC)*x@zpRi`Wt6^bOoLtl&ftrJUOxHoRxI)K0N z<=iIHpfQsLStZjO;$M&;W?znqaazaKpLSARQD>_ zoQnfK^Pk2vBqN63ja1Mp$0LuxGS6M+yGvl~tdHFhJ)gWm@LVxpS{A+2vskB6q6#3U zmo?nR17zBmRc~au#4Fu;ebPG`y#9(9-FrxHU(43u!aWh9=K*|IFsX3^g3vJVI2al> z+N%g!PG)D{JAC{y_B=Ge8K+sVeZNv`@yx7gJ<*i#df)aL9FX>g zrP4NYx7q{S7QJc7i0Sme zGdqGg9HpKkMpA)3l(tYt6yP|<49?K6EzM~*NKezZYEiHn|9SX+Y`;pm&A$Cx1}i|b z5VmtEEf~I8MYh~3G^-q>gZ>~7mt+hDmmjcai5U?#h$bEaneJ;rQ2v%xWPV)X_D7UGh~m-QarVAE+{(ZusV7+hH|T<(NULju z#S<)9JY?gqQrRuJet*=`g41GhUE(jLgEQfn49&m;aBkk>AkHd+^HGPGV*54B*8K>u zlGol2SbDa^qtd*W1GXO14i*2qS~PYS^qgN@gkim7|MRE5!();M?h4VM^E&|eeGbAt zCWS22fA=N&?^E{A9Op&F>tfOukS3CvtO{F7u{q?UrT?@Qp%(rF@dISK3zYJIO^|2m zw4Y<}SNV>?h6tdC9PK#DMANa@th{IF?0AE;DpjDRMotn>A4&h>cO~LY*R%UR0dE(} zA^E#|_9vuC6^2j0w=Q=bso?!mx-mf(4U#gEEb>%193GD^;u^KNOkX)R$#pT$|u+W~oPN+POTM)D2<8f-b(MGyU529v0;#)zaUa67ZlOwX+^G5a0Msu7{{lBb#@HGlp}D&a zEb@BA0TNFF)(iuHV))zgY2I1vF?&eJ@ry|Xg;+qR({mjf9hk`(G%sq&sZ(CakUhnS zn2hb}gjpzn?`~^6^j<2>`(f~y4WRrbch|4Ve^6r!4dGp>rIWY3u(JG+?TC@<`=guc zJzme{bg5-NDO>)!b4_FC*JzGNholpxaTC3mRlb}_G2qCreY7wIZ3tRBbXJ|vP4qjJ zQAdV#cd6}4hY6r8*@QmjDvhcT!~A@kv-8HwtZ_v~;78mUdz33ljmMjk3W|%TKH+k8+Pm2=^eNlsC-oaR z_MlQ&>A)Ir+kpdJA}zC@PN;XqQKUgPzqWP|vs#5@X%OuUIljq&JfqW; zrmS9C?9CehOXL6vedUDK9_TJ(+^{r=^sk#Q zwK9O`5G(Pj*;xCfatxZ%&h9iGZ@7st&P_x_n`C*jXFNX-43DU$jK2EpIUgLE<*p#1 zaXQnW?Pgke9B4tmbe%5N#7VqTE45h1n9&woSw-(Ls;V-LMh(fhNA}lF;qmHqk0+i5 zwK_nq%@hT5Q*Y9r(AGJ;u&Q{pqd)lKILixGXIJo z>G99}Ck-n$>W1cxy}sUgQMh&CUPMhzX!0Z%ldkswjTV+X3-F z=879_iU9if9lQk`{9=^iGgk*Skk0lzDK}ED8RmR5=}SmeCi)d-!UT`>EgqgZB2}X4 z;fMk)@_55+GC!8pF@yIt-1-rNA|MD2a~cDYQ%b<5UY^ASKB;~1UdZ8nzSKF50r~1 zc*SJ_t>W1VfF%n!<*H_NT{>_He5!S=@I0# z--Wjc=4D2;ln`DHMFA+fj z#0nHZ7!k&Wb}tnrSFb#~@@!1)i-C$PMhlj+Y1EXn72o#NlC=Vc>b+e~8jI1&{0DHK z2WW44oFlA-e)FAUEGSvX?7=UF_X{6RgS@Hr^1V&p{v0r!)PPw;!A8Fa;>q0wx9PZO z<`gV=-cNgsRy!2ll|F--9 literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py new file mode 100644 index 000000000..2fade5774 --- /dev/null +++ b/tests/unit/data/image/test_image_decoder.py @@ -0,0 +1,115 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from pathlib import Path +from typing import Any, Final + +import pytest +import torch + +from fairseq2.data.image import ImageDecoder +from fairseq2.memory import MemoryBlock +from fairseq2.typing import DataType +from tests.common import assert_close, device + +TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") +TEST_JPG_PATH: Final = Path(__file__).parent.joinpath("test.jpg") + + +class TestImageDecoder: + def test_init(self) -> None: + decoder = ImageDecoder() + assert isinstance(decoder, ImageDecoder) + + def test_call_works_on_png(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_PNG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + output = decoder(block) + + assert output["bit_depth"] == 8.0 + + assert output["color_type"] == 6.0 + + assert output["channels"] == 4.0 + + assert output["height"] == 1126.0 + + assert output["width"] == 1132.0 + + image = output["image"] + + assert image.shape == torch.Size([1126, 1132, 4]) + + assert image.dtype == torch.uint8 + + assert image.device == device + + assert_close(image.sum(), torch.tensor(1227963170, device=device)) + + def test_call_works_on_jpg(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_JPG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + output = decoder(block) + + assert output["bit_depth"] == 8.0 + + assert output["channels"] == 3.0 + + assert output["height"] == 1126.0 + + assert output["width"] == 1132.0 + + image = output["image"] + + assert image.shape == torch.Size([1126, 1132, 3]) + + assert image.dtype == torch.uint8 + + assert image.device == device + + assert_close(image.sum(), torch.tensor(902747049, device=device)) + + @pytest.mark.parametrize( + "value,type_name", [(None, "pyobj"), (123, "int"), ("s", "string")] + ) + def test_call_raises_error_when_input_is_not_memory_block( + self, value: Any, type_name: str + ) -> None: + decoder = ImageDecoder() + + with pytest.raises( + ValueError, + match=rf"^The input data must be of type `memory_block`, but is of type `{type_name}` instead\.$", + ): + decoder(value) + + def test_call_raises_error_when_input_is_empty(self) -> None: + decoder = ImageDecoder() + + empty_block = MemoryBlock() + + with pytest.raises( + ValueError, + match=r"^The input memory block has zero length and cannot be decoded\.$", + ): + decoder(empty_block) + + def test_call_raises_error_when_input_is_invalid(self) -> None: + decoder = ImageDecoder() + + block = MemoryBlock(b"foo") + + with pytest.raises( + ValueError, + match=r"^Unsupported image file. Only jpeg and png are currently supported\.$", + ): + decoder(block) From ef5757b120da52802d47e4adf03dcd3f858471b1 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 16:36:07 -0700 Subject: [PATCH 27/98] add output keys --- src/fairseq2/data/image.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/fairseq2/data/image.py b/src/fairseq2/data/image.py index 4a5fcd512..2b54032f9 100644 --- a/src/fairseq2/data/image.py +++ b/src/fairseq2/data/image.py @@ -6,6 +6,8 @@ from typing import TYPE_CHECKING, Optional, TypedDict +from torch import Tensor + from fairseq2 import _DOC_MODE from fairseq2.memory import MemoryBlock from fairseq2.typing import Device @@ -34,4 +36,9 @@ def _set_module_name() -> None: class ImageDecoderOutput(TypedDict): - format: int + bit_depth: float + color_type: float + channels: float + height: float + width: float + image: Tensor From d67300a95cb93b506a3b9784f677417143cebe4b Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 17:09:44 -0700 Subject: [PATCH 28/98] fix lint --- tests/unit/data/image/test_image_decoder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index 2fade5774..a9cb3cf02 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -12,7 +12,6 @@ from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock -from fairseq2.typing import DataType from tests.common import assert_close, device TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") From cd6cf80b7b29ce9eda1d70110c853e8069d1aad6 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 17:30:59 -0700 Subject: [PATCH 29/98] change uint8 to unsigned char --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 114f057ac..f7b1ebd7d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -165,7 +165,7 @@ image_decoder::decode_jpeg(const memory_block &block) const struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From 260c58077f8c1acc7f8959deb60815e7225a2122 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 19:02:56 -0700 Subject: [PATCH 30/98] update workflow configs to install libjpeg v8 --- .github/workflows/_build_doc.yaml | 4 ++-- .github/workflows/_build_wheel-linux.yaml | 4 ++-- .github/workflows/_build_wheel-macos.yaml | 2 +- .github/workflows/_lint_cc.yaml | 4 ++-- .github/workflows/_lint_py.yaml | 4 ++-- .github/workflows/_lint_sh.yaml | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 8909b2628..a55e89fd7 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -36,9 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-dev + - name: Install libjpeg8-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg8-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index ec0a93051..3e4b2803e 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -59,9 +59,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-dev + - name: Install libjpeg8-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg8-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index 51efaef76..e6476d2df 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,7 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true - brew install libjpeg || true + brew install libjpeg8 || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 5eb9838e9..3e6cbf92a 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -36,9 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-dev + - name: Install libjpeg8-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg8-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index c712a157e..890b80059 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -33,9 +33,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-dev + - - name: Install libjpeg8-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg8-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index fd4d4f1a5..527aab47e 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -30,9 +30,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-dev + - name: Install libjpeg8-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg8-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From e0dcbd2423d69578ed472bb0ed32eed661806382 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 07:01:46 -0700 Subject: [PATCH 31/98] change package name --- .github/workflows/_build_doc.yaml | 4 ++-- .github/workflows/_build_wheel-linux.yaml | 8 ++++---- .github/workflows/_build_wheel-macos.yaml | 2 +- .github/workflows/_lint_cc.yaml | 4 ++-- .github/workflows/_lint_py.yaml | 4 ++-- .github/workflows/_lint_sh.yaml | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index a55e89fd7..ecff51a40 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -36,9 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg8-dev + - name: Install libjpeg-turbo run: | - yum --assumeyes install libjpeg8-devel + yum --assumeyes install libjpeg-turbo - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 3e4b2803e..9b056e664 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -59,9 +59,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg8-dev + - name: Install libjpeg-turbo run: | - yum --assumeyes install libjpeg8-devel + yum --assumeyes install libjpeg-turbo - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -168,9 +168,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-dev + - name: Install libjpeg-turbo run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-turbo - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index e6476d2df..d137b12e1 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,7 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true - brew install libjpeg8 || true + brew install jpeg-turbo || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 3e6cbf92a..88adcd72f 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -36,9 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg8-dev + - name: Install libjpeg-turbo run: | - yum --assumeyes install libjpeg8-devel + yum --assumeyes install libjpeg-turbo - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 890b80059..3198b915d 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -33,9 +33,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - - name: Install libjpeg8-dev + - name: Install libjpeg-turbo run: | - yum --assumeyes install libjpeg8-devel + yum --assumeyes install libjpeg-turbo - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 527aab47e..fb09813f0 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -30,9 +30,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg8-dev + - name: Install libjpeg-turbo run: | - yum --assumeyes install libjpeg8-devel + yum --assumeyes install libjpeg-turbo - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From e3fc72da68a9a7745b7d14b00da30d5edf134102 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 10:08:33 -0700 Subject: [PATCH 32/98] pass non const ptr to libjpeg --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index f7b1ebd7d..c5a05be02 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,13 +159,15 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); + auto non_const_ptr = const_cast(reinterpret_cast(data_ptr)); + // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, non_const_ptr, data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From b31b48e58f730e992e68f7f21f66ac272d5687fe Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 10:16:00 -0700 Subject: [PATCH 33/98] change package name --- .github/workflows/_build_doc.yaml | 4 ++-- .github/workflows/_build_wheel-linux.yaml | 8 ++++---- .github/workflows/_build_wheel-macos.yaml | 2 +- .github/workflows/_lint_cc.yaml | 4 ++-- .github/workflows/_lint_py.yaml | 4 ++-- .github/workflows/_lint_sh.yaml | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index ecff51a40..fccfc1f12 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -36,9 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo + - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-turbo + yum --assumeyes install libjpeg-dev - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 9b056e664..29165456d 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -59,9 +59,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo + - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-turbo + yum --assumeyes install libjpeg-dev - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -168,9 +168,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo + - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-turbo + yum --assumeyes install libjpeg-dev - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index d137b12e1..51efaef76 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,7 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true - brew install jpeg-turbo || true + brew install libjpeg || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 88adcd72f..59cd03a5c 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -36,9 +36,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo + - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-turbo + yum --assumeyes install libjpeg-dev - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 3198b915d..bb8c081a2 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -33,9 +33,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo + - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-turbo + yum --assumeyes install libjpeg-dev - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index fb09813f0..93402ab6f 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -30,9 +30,9 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo + - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-turbo + yum --assumeyes install libjpeg-dev - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From 9be595fe46f5f552fd64689a2855a33cc0eb27e2 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 10:26:04 -0700 Subject: [PATCH 34/98] fix typo --- .github/workflows/_build_doc.yaml | 2 +- .github/workflows/_build_wheel-linux.yaml | 4 ++-- .github/workflows/_lint_cc.yaml | 2 +- .github/workflows/_lint_py.yaml | 2 +- .github/workflows/_lint_sh.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index fccfc1f12..8909b2628 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -38,7 +38,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-dev + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 29165456d..ec0a93051 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -61,7 +61,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-dev + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -170,7 +170,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-dev + yum --assumeyes install libjpeg-devel - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 59cd03a5c..5eb9838e9 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -38,7 +38,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-dev + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index bb8c081a2..c712a157e 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -35,7 +35,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-dev + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 93402ab6f..fd4d4f1a5 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -32,7 +32,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-dev + yum --assumeyes install libjpeg-devel - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From 9caad8ccf6bd7fbd2c4edbaacca7707921ad1f3b Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 13:47:12 -0700 Subject: [PATCH 35/98] download libjpeg 1.5 and use const data_ptr --- .github/workflows/_build_doc.yaml | 2 +- .github/workflows/_build_wheel-linux.yaml | 4 ++-- .github/workflows/_lint_cc.yaml | 2 +- .github/workflows/_lint_py.yaml | 2 +- .github/workflows/_lint_sh.yaml | 2 +- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 4 +--- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 8909b2628..5ad7d53df 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -38,7 +38,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-devel-2.1.2 - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index ec0a93051..607b4f5d4 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -61,7 +61,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-devel-2.1.2 - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -170,7 +170,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-devel-2.1.2 - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 5eb9838e9..563c74ea1 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -38,7 +38,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-devel-2.1.2 - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index c712a157e..29a5f44c7 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -35,7 +35,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-devel-2.1.2 - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index fd4d4f1a5..661b288d2 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -32,7 +32,7 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel + yum --assumeyes install libjpeg-devel-2.1.2 - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index c5a05be02..f7b1ebd7d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,15 +159,13 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); - auto non_const_ptr = const_cast(reinterpret_cast(data_ptr)); - // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, non_const_ptr, data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From a06b73b16f4eaf0c0a5cc0903d607557ceb8dd4b Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 13:51:11 -0700 Subject: [PATCH 36/98] libjpeg 1.5 --- .github/workflows/_build_doc.yaml | 3 ++- .github/workflows/_build_wheel-linux.yaml | 8 +++++--- .github/workflows/_lint_cc.yaml | 3 ++- .github/workflows/_lint_py.yaml | 3 ++- .github/workflows/_lint_sh.yaml | 3 ++- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 5ad7d53df..bb32cd5d7 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -38,7 +38,8 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel-2.1.2 + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 607b4f5d4..a0d64ccb7 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -61,7 +61,8 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel-2.1.2 + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -164,13 +165,14 @@ jobs: steps: - name: Install libsndfile run: | - yum --assumeyes install libsndfile-devel + yum --assumeyes install libsndfile-develPyTorchjpeg - name: Install libpng-dev run: | yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel-2.1.2 + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 563c74ea1..435923aab 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -38,7 +38,8 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel-2.1.2 + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 29a5f44c7..8f19992dc 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -35,7 +35,8 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel-2.1.2 + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 661b288d2..a015fccca 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -32,7 +32,8 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | - yum --assumeyes install libjpeg-devel-2.1.2 + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From c137b875eebf5700fedee30a70994b4dbcb8e0e9 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 14:07:01 -0700 Subject: [PATCH 37/98] fix typo --- .github/workflows/_build_wheel-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index a0d64ccb7..0092181b6 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -165,7 +165,7 @@ jobs: steps: - name: Install libsndfile run: | - yum --assumeyes install libsndfile-develPyTorchjpeg + yum --assumeyes install libsndfile-devel - name: Install libpng-dev run: | yum --assumeyes install libpng-devel From 7554f6af0d5c4db3cadf680bf65d5de14d4db61a Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 16:18:28 -0700 Subject: [PATCH 38/98] add init --- tests/unit/data/image/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/unit/data/image/__init__.py diff --git a/tests/unit/data/image/__init__.py b/tests/unit/data/image/__init__.py new file mode 100644 index 000000000..e69de29bb From 34b00925bd4f946f88f84fe7108c82494a28c3e8 Mon Sep 17 00:00:00 2001 From: Alisha Date: Thu, 26 Oct 2023 15:57:09 -0700 Subject: [PATCH 39/98] use setjmp/longjmp for error handling --- .../src/fairseq2n/data/image/image_decoder.cc | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index f7b1ebd7d..b945d33c8 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -13,6 +13,7 @@ #include #include +#include #include "fairseq2n/exception.h" #include "fairseq2n/float.h" @@ -54,15 +55,13 @@ image_decoder::operator()(data &&d) const const std::array jpeg_signature = {255, 216, 255}; const std::array png_signature = {137, 80, 78, 71}; - if(memcmp(jpeg_signature.data(), data_ptr, 3) == 0) { - output = decode_jpeg(block); - } else if(memcmp(png_signature.data(), data_ptr, 4) == 0) { - output = decode_png(block); - } else { - throw_( - "Unsupported image file. Only jpeg and png are currently supported."); - } - return output; + if(std::memcmp(jpeg_signature.data(), data_ptr, jpeg_signature.size()) == 0) { + return decode_jpeg(block); + } else if(std::memcmp(png_signature.data(), data_ptr, 4) == 0) { + return decode_png(block); + } + throw_( + "Unsupported image file. Only jpeg and png are currently supported."); } data @@ -80,6 +79,12 @@ image_decoder::decode_png(const memory_block &block) const auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); + // If an error occurs, libpng will longjmp back to setjmp + if (setjmp(png_jmpbuf(png_ptr))) { + // If we get here, libpng has signaled an error + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw_("Internal error."); + } struct Reader { png_const_bytep ptr; @@ -142,7 +147,7 @@ image_decoder::decode_png(const memory_block &block) const if (device != at::kCPU) image = image.to(device); - // Pack png data and format as output. + // Pack png data and format as output data_dict output{ {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, {"channels", static_cast(channels)}, {"height", static_cast(height)}, @@ -157,13 +162,33 @@ image_decoder::decode_png(const memory_block &block) const data image_decoder::decode_jpeg(const memory_block &block) const { + struct custom_error_mgr { + struct jpeg_error_mgr pub; // Public fields + jmp_buf setjmp_buffer; // Return to caller + }; + typedef struct custom_error_mgr * error_ptr; + auto data_ptr = block.data(); auto data_len = block.size(); // Set up decompression process struct jpeg_decompress_struct cinfo = {}; - struct jpeg_error_mgr jerr = {}; - cinfo.err = jpeg_std_error(&jerr); + struct custom_error_mgr jerr = {}; + cinfo.err = jpeg_std_error(&jerr.pub); + // error_exit is called by libjpeg when fatal error occurs + jerr.pub.error_exit = [](j_common_ptr cinfo) { + // cinfo->err really points to a custom_error_mgr struct, so coerce pointer + error_ptr myerr = (error_ptr) cinfo->err; + (*cinfo->err->output_message) (cinfo); + // Return control to the setjmp point + longjmp(myerr->setjmp_buffer, 1); + }; + // If an error occurs, error_exit will longjmp back to setjmp + if (setjmp(jerr.setjmp_buffer)) { + // If we get here, libjpeg has signaled an error + jpeg_destroy_decompress(&cinfo); + throw std::runtime_error("JPEG decompression failed"); + } jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); From 949ec83f26070bdccc0d08f88b9f423a17118a66 Mon Sep 17 00:00:00 2001 From: Alisha Date: Thu, 26 Oct 2023 20:43:17 -0700 Subject: [PATCH 40/98] new classes for resource management --- .../image/detail/jpeg_decompress_struct.cc | 26 ++++++++++++ .../image/detail/jpeg_decompress_struct.h | 27 ++++++++++++ .../data/image/detail/png_read_struct.cc | 40 ++++++++++++++++++ .../data/image/detail/png_read_struct.h | 28 +++++++++++++ .../src/fairseq2n/data/image/image_decoder.cc | 42 ++++++++----------- 5 files changed, 139 insertions(+), 24 deletions(-) create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc new file mode 100644 index 000000000..7ca080a41 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc @@ -0,0 +1,26 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates.error_ptr +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/detail/jpeg_decompress_struct.h" + +#include + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n::detail { + +jpeg_decompress::jpeg_decompress() {} + +jpeg_decompress::~jpeg_decompress() { + jpeg_destroy_decompress(&cinfo); +} + +jpeg_decompress_struct& jpeg_decompress::get() { + return cinfo; +} + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h new file mode 100644 index 000000000..03686a7c2 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -0,0 +1,27 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include "fairseq2n/exception.h" + +namespace fairseq2n::detail { + +class jpeg_decompress { +public: + jpeg_decompress(); + ~jpeg_decompress(); + + jpeg_decompress_struct& get(); + +private: + jpeg_decompress_struct cinfo; + jpeg_decompress(const jpeg_decompress&); + jpeg_decompress& operator=(const jpeg_decompress&); +}; + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc new file mode 100644 index 000000000..1f2727a14 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc @@ -0,0 +1,40 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/detail/png_read_struct.h" + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n::detail { + +png_read::png_read() : png_ptr(nullptr), info_ptr(nullptr) { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { + throw internal_error("Failed to create PNG read struct."); + } + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == nullptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + throw internal_error("Failed to create PNG info struct."); + } +} + +png_read::~png_read() { + if (png_ptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + } +} + +png_structp png_read::getPngPtr() const { + return png_ptr; +} + +png_infop png_read::getInfoPtr() const { + return info_ptr; +} + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h new file mode 100644 index 000000000..5c7a5f64f --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -0,0 +1,28 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include + +namespace fairseq2n::detail { + +class png_read{ +public: + png_read(); + ~png_read(); + + png_structp getPngPtr() const; + png_infop getInfoPtr() const; + +private: + png_structp png_ptr; + png_infop info_ptr; + png_read(const png_read&); + png_read& operator=(const png_read&); +}; + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index b945d33c8..8d1d6f232 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -9,17 +9,17 @@ #include #include #include -#include #include #include -#include +#include #include "fairseq2n/exception.h" #include "fairseq2n/float.h" #include "fairseq2n/fmt.h" #include "fairseq2n/memory.h" -#include "fairseq2n/span.h" +#include "fairseq2n/data/image/detail/png_read_struct.h" +#include "fairseq2n/data/image/detail/jpeg_decompress_struct.h" #include "fairseq2n/data/detail/tensor_helpers.h" #include "fairseq2n/detail/exception.h" @@ -67,15 +67,9 @@ image_decoder::operator()(data &&d) const data image_decoder::decode_png(const memory_block &block) const { - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (png_ptr == nullptr) { - throw_("Failed to create PNG read struct."); - } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == nullptr) { - png_destroy_read_struct(&png_ptr, nullptr, nullptr); - throw_("Failed to create PNG info struct."); - } + png_read pngReadStruct; + png_structp png_ptr = pngReadStruct.getPngPtr(); + png_infop info_ptr = pngReadStruct.getInfoPtr(); auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); @@ -162,25 +156,25 @@ image_decoder::decode_png(const memory_block &block) const data image_decoder::decode_jpeg(const memory_block &block) const { + jpeg_decompress jpegDecompressStruct; + jpeg_decompress_struct cinfo = jpegDecompressStruct.get(); + + auto data_ptr = block.data(); + auto data_len = block.size(); + struct custom_error_mgr { struct jpeg_error_mgr pub; // Public fields jmp_buf setjmp_buffer; // Return to caller }; - typedef struct custom_error_mgr * error_ptr; - - auto data_ptr = block.data(); - auto data_len = block.size(); - - // Set up decompression process - struct jpeg_decompress_struct cinfo = {}; struct custom_error_mgr jerr = {}; + typedef struct custom_error_mgr * error_ptr; cinfo.err = jpeg_std_error(&jerr.pub); - // error_exit is called by libjpeg when fatal error occurs + // error_exit is called by libjpeg when a fatal error occurs jerr.pub.error_exit = [](j_common_ptr cinfo) { - // cinfo->err really points to a custom_error_mgr struct, so coerce pointer - error_ptr myerr = (error_ptr) cinfo->err; - (*cinfo->err->output_message) (cinfo); - // Return control to the setjmp point + // Coerce pointer to custom_error_mgr struct + auto myerr = reinterpret_cast(cinfo->err); + (*cinfo->err->output_message)(cinfo); + // Return control to the setjmp point longjmp(myerr->setjmp_buffer, 1); }; // If an error occurs, error_exit will longjmp back to setjmp From 830c0bc45188becf4716c877ece42b15bfa9e77d Mon Sep 17 00:00:00 2001 From: Alisha Date: Fri, 27 Oct 2023 06:40:19 -0700 Subject: [PATCH 41/98] include new classes in cmakelists --- fairseq2n/src/fairseq2n/CMakeLists.txt | 2 ++ .../fairseq2n/data/image/detail/jpeg_decompress_struct.cc | 5 ----- .../src/fairseq2n/data/image/detail/jpeg_decompress_struct.h | 3 +++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 30378f731..2b00cc157 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -56,6 +56,8 @@ target_sources(fairseq2n data/detail/file.cc data/detail/file_system.cc data/image/image_decoder.cc + data/image/detail/jpeg_decompress_struct.cc + data/image/detail/png_read_struct.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc index 7ca080a41..7922a466e 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc @@ -6,11 +6,6 @@ #include "fairseq2n/data/image/detail/jpeg_decompress_struct.h" -#include - -#include "fairseq2n/exception.h" -#include "fairseq2n/detail/exception.h" - namespace fairseq2n::detail { jpeg_decompress::jpeg_decompress() {} diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index 03686a7c2..c28f4eee8 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -6,8 +6,11 @@ #pragma once +#include #include + #include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" namespace fairseq2n::detail { From a3213e03a2488c89c76b7bd8a20d0168bbae94a5 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 30 Oct 2023 15:34:26 -0700 Subject: [PATCH 42/98] fix include order --- .../src/fairseq2n/data/image/detail/jpeg_decompress_struct.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index c28f4eee8..4f53edf21 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -7,6 +7,8 @@ #pragma once #include +// Forward declaration +typedef struct _IO_FILE FILE; #include #include "fairseq2n/exception.h" From b85a7df13c3e60a58c91b342a72fa70e37edbf5d Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 30 Oct 2023 18:29:42 -0700 Subject: [PATCH 43/98] fix double free and seg fault --- .../data/image/detail/jpeg_decompress_struct.cc | 8 ++++++-- .../data/image/detail/jpeg_decompress_struct.h | 7 +++---- .../data/image/detail/png_read_struct.cc | 2 +- .../fairseq2n/data/image/detail/png_read_struct.h | 5 ++--- .../src/fairseq2n/data/image/image_decoder.cc | 15 +++++++-------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc index 7922a466e..5d56112b9 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc @@ -8,10 +8,14 @@ namespace fairseq2n::detail { -jpeg_decompress::jpeg_decompress() {} +jpeg_decompress::jpeg_decompress() : cinfo() { + jpeg_create_decompress(&cinfo); +} jpeg_decompress::~jpeg_decompress() { - jpeg_destroy_decompress(&cinfo); + if(cinfo.err != nullptr) { + jpeg_destroy_decompress(&cinfo); + } } jpeg_decompress_struct& jpeg_decompress::get() { diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index 4f53edf21..3b433e3a1 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -8,7 +8,7 @@ #include // Forward declaration -typedef struct _IO_FILE FILE; +using FILE = struct _IO_FILE; #include #include "fairseq2n/exception.h" @@ -20,13 +20,12 @@ class jpeg_decompress { public: jpeg_decompress(); ~jpeg_decompress(); - jpeg_decompress_struct& get(); + jpeg_decompress(const jpeg_decompress&) = delete; + jpeg_decompress& operator=(const jpeg_decompress&) = delete; private: jpeg_decompress_struct cinfo; - jpeg_decompress(const jpeg_decompress&); - jpeg_decompress& operator=(const jpeg_decompress&); }; } // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc index 1f2727a14..204249deb 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc @@ -24,7 +24,7 @@ png_read::png_read() : png_ptr(nullptr), info_ptr(nullptr) { } png_read::~png_read() { - if (png_ptr) { + if (png_ptr != nullptr) { png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); } } diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h index 5c7a5f64f..ddfb07f98 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -14,15 +14,14 @@ class png_read{ public: png_read(); ~png_read(); - png_structp getPngPtr() const; png_infop getInfoPtr() const; + png_read(const png_read&) = delete; + png_read& operator=(const png_read&) = delete; private: png_structp png_ptr; png_infop info_ptr; - png_read(const png_read&); - png_read& operator=(const png_read&); }; } // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 8d1d6f232..2706365ec 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -149,7 +149,6 @@ image_decoder::decode_png(const memory_block &block) const output.emplace("image", std::move(image)); - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return output; } @@ -167,7 +166,7 @@ image_decoder::decode_jpeg(const memory_block &block) const jmp_buf setjmp_buffer; // Return to caller }; struct custom_error_mgr jerr = {}; - typedef struct custom_error_mgr * error_ptr; + using error_ptr = struct custom_error_mgr *; cinfo.err = jpeg_std_error(&jerr.pub); // error_exit is called by libjpeg when a fatal error occurs jerr.pub.error_exit = [](j_common_ptr cinfo) { @@ -183,11 +182,12 @@ image_decoder::decode_jpeg(const memory_block &block) const jpeg_destroy_decompress(&cinfo); throw std::runtime_error("JPEG decompression failed"); } - jpeg_create_decompress(&cinfo); + + //jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); - + auto width = cinfo.output_width; auto height = cinfo.output_height; auto channels = cinfo.output_components; @@ -205,19 +205,18 @@ image_decoder::decode_jpeg(const memory_block &block) const image_data += row_size; } jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); - + // Pack jpeg data and format as output. data_dict output{ {{"channels", static_cast(channels)}, {"height", static_cast(height)}, {"width", static_cast(width)}, {"bit_depth", static_cast(bit_depth)}}}; - + output.emplace("image", std::move(image)); - + return output; } }; // namespace fairseq2n From 5644622af820e4212aecd2bc44d9ee5b7d6b2148 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 31 Oct 2023 15:45:02 -0700 Subject: [PATCH 44/98] unit test for corrupted images --- .../src/fairseq2n/data/image/image_decoder.cc | 9 ++---- tests/unit/data/image/test_corrupt.jpg | Bin 0 -> 87571 bytes tests/unit/data/image/test_corrupt.png | Bin 0 -> 73036 bytes tests/unit/data/image/test_image_decoder.py | 28 +++++++++++++++++- 4 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 tests/unit/data/image/test_corrupt.jpg create mode 100644 tests/unit/data/image/test_corrupt.png diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 2706365ec..31052da57 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -75,9 +75,7 @@ image_decoder::decode_png(const memory_block &block) const auto data_len = block.size(); // If an error occurs, libpng will longjmp back to setjmp if (setjmp(png_jmpbuf(png_ptr))) { - // If we get here, libpng has signaled an error - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - throw_("Internal error."); + throw_("libpng internal error."); } struct Reader { @@ -115,7 +113,6 @@ image_decoder::decode_png(const memory_block &block) const nullptr); if (retval != 1) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); throw_("Could not read image metadata from content."); } @@ -178,9 +175,7 @@ image_decoder::decode_jpeg(const memory_block &block) const }; // If an error occurs, error_exit will longjmp back to setjmp if (setjmp(jerr.setjmp_buffer)) { - // If we get here, libjpeg has signaled an error - jpeg_destroy_decompress(&cinfo); - throw std::runtime_error("JPEG decompression failed"); + throw_("JPEG decompression failed."); } //jpeg_create_decompress(&cinfo); diff --git a/tests/unit/data/image/test_corrupt.jpg b/tests/unit/data/image/test_corrupt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2970c55dc97837211811cef5c0e37ecf6d687281 GIT binary patch literal 87571 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 Q%YFeQmL=`{9e)h`7k+)A0{{R3 literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test_corrupt.png b/tests/unit/data/image/test_corrupt.png new file mode 100644 index 0000000000000000000000000000000000000000..5350683e9c8e8f96c443e19a169b04f8aa5a19ce GIT binary patch literal 73036 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 GrT+qv7<%&n literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index a9cb3cf02..8f8100cd9 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -9,6 +9,7 @@ import pytest import torch +import warnings from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock @@ -16,7 +17,8 @@ TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") TEST_JPG_PATH: Final = Path(__file__).parent.joinpath("test.jpg") - +TEST_CORRUPT_JPG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.jpg") +TEST_CORRUPT_PNG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.png") class TestImageDecoder: def test_init(self) -> None: @@ -77,6 +79,30 @@ def test_call_works_on_jpg(self) -> None: assert_close(image.sum(), torch.tensor(902747049, device=device)) + def test_corrupted_png(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_CORRUPT_PNG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + with pytest.raises( + RuntimeError, + match="libpng internal error.", + ): + decoder(block) + + def test_corrupted_jpg(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_CORRUPT_JPG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + with pytest.raises( + RuntimeError, + match="JPEG decompression failed.", + ): + decoder(block) + @pytest.mark.parametrize( "value,type_name", [(None, "pyobj"), (123, "int"), ("s", "string")] ) From 1d31fdf504441ef13f75dc102c499d2e8d87b86e Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 31 Oct 2023 15:53:15 -0700 Subject: [PATCH 45/98] more descriptive test name --- tests/unit/data/image/test_image_decoder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index 8f8100cd9..e5efed62b 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -79,7 +79,7 @@ def test_call_works_on_jpg(self) -> None: assert_close(image.sum(), torch.tensor(902747049, device=device)) - def test_corrupted_png(self) -> None: + def test_call_raises_error_when_input_is_corrupted_png(self) -> None: decoder = ImageDecoder(device=device) with TEST_CORRUPT_PNG_PATH.open("rb") as fb: @@ -91,7 +91,7 @@ def test_corrupted_png(self) -> None: ): decoder(block) - def test_corrupted_jpg(self) -> None: + def test_call_raises_error_when_input_is_corrupted_jpg(self) -> None: decoder = ImageDecoder(device=device) with TEST_CORRUPT_JPG_PATH.open("rb") as fb: From b6bb9ca67fe08d07189a6a6dfe02d2c332cb6826 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 31 Oct 2023 16:01:36 -0700 Subject: [PATCH 46/98] fix lint --- tests/unit/data/image/test_image_decoder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index e5efed62b..f83f79a20 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -9,7 +9,6 @@ import pytest import torch -import warnings from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock @@ -20,6 +19,7 @@ TEST_CORRUPT_JPG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.jpg") TEST_CORRUPT_PNG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.png") + class TestImageDecoder: def test_init(self) -> None: decoder = ImageDecoder() @@ -79,7 +79,7 @@ def test_call_works_on_jpg(self) -> None: assert_close(image.sum(), torch.tensor(902747049, device=device)) - def test_call_raises_error_when_input_is_corrupted_png(self) -> None: + def test_call_raises_error_when_input_is_corrupted_png(self) -> None: decoder = ImageDecoder(device=device) with TEST_CORRUPT_PNG_PATH.open("rb") as fb: From 7a2c1170bc2be5b083f9d002f1b75ca0d8c6003c Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 13 Nov 2023 10:17:03 -0800 Subject: [PATCH 47/98] fix lint --- .github/workflows/_build_doc.yaml | 7 ------- .github/workflows/_build_wheel-linux.yaml | 14 -------------- .github/workflows/_lint_cc.yaml | 7 ------- .github/workflows/_lint_py.yaml | 7 ------- .github/workflows/_lint_sh.yaml | 7 ------- 5 files changed, 42 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index bbbf88099..3e98a812b 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -30,13 +30,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index ac359b1d5..b5aea3cc8 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -53,13 +53,6 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -163,13 +156,6 @@ jobs: run: shell: bash steps: - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 51695fb93..c5ab1cc63 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -30,13 +30,6 @@ jobs: with: submodules: recursive fetch-depth: 2 - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 8a1ebb5f5..cff9fb69c 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -27,13 +27,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 1c3db54cc..a6b89fabe 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -24,13 +24,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From f37366e5bb3407a75ff57b9e74d8e0f2383e80d2 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 5 Dec 2023 14:43:26 -0800 Subject: [PATCH 48/98] clang tidy --- fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h index ddfb07f98..941b3a13c 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -20,8 +20,8 @@ class png_read{ png_read& operator=(const png_read&) = delete; private: - png_structp png_ptr; - png_infop info_ptr; + png_structp png_ptr{nullptr}; + png_infop info_ptr{nullptr}; }; } // namespace fairseq2n::detail From 7ecea3a71636948fe0c4b953dedfa563214c2c34 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 9 Oct 2023 15:36:02 -0700 Subject: [PATCH 49/98] image decoder header file and constructor --- fairseq2n/src/fairseq2n/CMakeLists.txt | 1 + .../src/fairseq2n/data/image/image_decoder.cc | 39 +++++++++ .../src/fairseq2n/data/image/image_decoder.h | 87 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 fairseq2n/src/fairseq2n/data/image/image_decoder.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/image_decoder.h diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 9f752d58c..84638f1a3 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -55,6 +55,7 @@ target_sources(fairseq2n data/audio/detail/sndfile.cc data/detail/file.cc data/detail/file_system.cc + data/image/image_decoder.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc new file mode 100644 index 000000000..3542ba3c3 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -0,0 +1,39 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/image_decoder.h" + +#include +#include +#include + +#include +#include + +#include "fairseq2n/exception.h" +#include "fairseq2n/float.h" +#include "fairseq2n/fmt.h" +#include "fairseq2n/memory.h" +#include "fairseq2n/span.h" +#include "fairseq2n/data/audio/detail/sndfile.h" +#include "fairseq2n/data/detail/tensor_helpers.h" +#include "fairseq2n/detail/exception.h" + +using namespace fairseq2n::detail; + +namespace fairseq2n { + +image_decoder::image_decoder(image_decoder_options opts) + : opts_{opts} +{ + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); + if (dtype != at::kFloat && dtype != at::kByte) + throw_( + "`image_decoder` supports only `torch.float32` and `torch.uint8` data types."); +} + + +}; \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h new file mode 100644 index 000000000..144dde1a8 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -0,0 +1,87 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include + +#include "fairseq2n/api.h" +#include "fairseq2n/data/data.h" + +#include +#include + +namespace fairseq2n { + +class image_decoder_options { +public: + image_decoder_options + maybe_dtype(std::optional value) noexcept + { + auto tmp = *this; + + tmp.maybe_dtype_ = value; + + return tmp; + } + + std::optional + maybe_dtype() const noexcept + { + return maybe_dtype_; + } + + image_decoder_options + maybe_device(std::optional value) noexcept + { + auto tmp = *this; + + tmp.maybe_device_ = value; + + return tmp; + } + + std::optional + maybe_device() const noexcept + { + return maybe_device_; + } + + image_decoder_options + pin_memory(bool value) noexcept + { + auto tmp = *this; + + tmp.pin_memory_ = value; + + return tmp; + } + + bool + pin_memory() const noexcept + { + return pin_memory_; + } + +private: + std::optional maybe_dtype_{}; + std::optional maybe_device_{}; + bool pin_memory_ = false; +}; + +class FAIRSEQ2_API image_decoder { +public: + explicit + image_decoder(image_decoder_options opts = {}); + + data + operator()(data &&d) const; + +private: + image_decoder_options opts_; +}; + +} // \ No newline at end of file From 528dec255fc659d1557dc60cb3852967d54ebeeb Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 10 Oct 2023 08:10:54 -0700 Subject: [PATCH 50/98] png.cc and png.h --- fairseq2n/src/fairseq2n/CMakeLists.txt | 5 ++ .../src/fairseq2n/data/image/detail/png.cc | 37 ++++++++++++++ .../src/fairseq2n/data/image/detail/png.h | 51 +++++++++++++++++++ .../src/fairseq2n/data/image/image_decoder.cc | 14 +++++ 4 files changed, 107 insertions(+) create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.h diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 84638f1a3..30378f731 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -103,6 +103,9 @@ target_include_directories(fairseq2n ${system} $ ) +find_package(PNG REQUIRED) +find_package(JPEG REQUIRED) + target_link_libraries(fairseq2n PRIVATE ${CMAKE_DL_LIBS} @@ -115,6 +118,8 @@ target_link_libraries(fairseq2n Threads::Threads sentencepiece-static SndFile::sndfile + PNG::PNG + JPEG::JPEG PUBLIC torch ) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.cc b/fairseq2n/src/fairseq2n/data/image/detail/png.cc new file mode 100644 index 000000000..ad1cf9310 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png.cc @@ -0,0 +1,37 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/detail/png.h" + +#include +#include +#include + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n::detail { + +::png_size_t vio_file::read(void *ptr, ::png_size_t size) { + if (current_pos_ >= block_.size()) { + return 0; + } + + ::png_size_t bytes_to_read = std::min(size, block_.size() - current_pos_); + std::memcpy(ptr, block_.data() + current_pos_, bytes_to_read); + current_pos_ += bytes_to_read; + + return bytes_to_read; +} + +::png_size_t vio_file::write(const void *ptr, ::png_size_t size) { + // We only support decoding image files. + return -1; +} + +} + + // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.h b/fairseq2n/src/fairseq2n/data/image/detail/png.h new file mode 100644 index 000000000..3c888f971 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png.h @@ -0,0 +1,51 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include +#include + +#include + + +#include "fairseq2n/memory.h" +#include "fairseq2n/span.h" +#include "fairseq2n/utils/cast.h" + +namespace fairseq2n::detail { + +// Wraps `memory_block` as a "virtual" file to use with libpng. +class vio_file { +public: + explicit + vio_file(memory_block &&block) noexcept + : block_{std::move(block)} + {} + + ::png_voidp get_io_ptr() { + return static_cast<::png_voidp>(&io_ptr_); + } + + ::png_size_t read(void *ptr, ::png_size_t size); + + ::png_size_t write(const void *ptr, ::png_size_t size); + +private: + static std::size_t + as_size(::png_size_t value) noexcept + { + return conditional_cast(value); + } + +private: + memory_block block_; + ::png_size_t current_pos_{}; + char io_ptr_; +}; + +} // namespace fairseq2n::detail \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 3542ba3c3..7e0d2d07a 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -35,5 +35,19 @@ image_decoder::image_decoder(image_decoder_options opts) "`image_decoder` supports only `torch.float32` and `torch.uint8` data types."); } +data +image_decoder::operator()(data &&d) const +{ + if (!d.is_memory_block()) + throw_( + "The input data must be of type `memory_block`, but is of type `{}` instead.", d.type()); + + const memory_block &block = d.as_memory_block(); + if (block.empty()) + throw_( + "The input memory block has zero length and cannot be decoded as audio."); + + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); +} }; \ No newline at end of file From d5fdbc4ab77a3911375f3587409c2f69a214340d Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 06:44:59 -0700 Subject: [PATCH 51/98] remove png files and import libpng methods --- .../src/fairseq2n/data/image/detail/png.cc | 37 ------------ .../src/fairseq2n/data/image/detail/png.h | 51 ----------------- .../src/fairseq2n/data/image/image_decoder.cc | 57 +++++++++++++++++++ 3 files changed, 57 insertions(+), 88 deletions(-) delete mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.cc delete mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png.h diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.cc b/fairseq2n/src/fairseq2n/data/image/detail/png.cc deleted file mode 100644 index ad1cf9310..000000000 --- a/fairseq2n/src/fairseq2n/data/image/detail/png.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Meta Platforms, Inc. and affiliates. -// All rights reserved. -// -// This source code is licensed under the BSD-style license found in the -// LICENSE file in the root directory of this source tree. - -#include "fairseq2n/data/image/detail/png.h" - -#include -#include -#include - -#include "fairseq2n/exception.h" -#include "fairseq2n/detail/exception.h" - -namespace fairseq2n::detail { - -::png_size_t vio_file::read(void *ptr, ::png_size_t size) { - if (current_pos_ >= block_.size()) { - return 0; - } - - ::png_size_t bytes_to_read = std::min(size, block_.size() - current_pos_); - std::memcpy(ptr, block_.data() + current_pos_, bytes_to_read); - current_pos_ += bytes_to_read; - - return bytes_to_read; -} - -::png_size_t vio_file::write(const void *ptr, ::png_size_t size) { - // We only support decoding image files. - return -1; -} - -} - - // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png.h b/fairseq2n/src/fairseq2n/data/image/detail/png.h deleted file mode 100644 index 3c888f971..000000000 --- a/fairseq2n/src/fairseq2n/data/image/detail/png.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Meta Platforms, Inc. and affiliates. -// All rights reserved. -// -// This source code is licensed under the BSD-style license found in the -// LICENSE file in the root directory of this source tree. - -#pragma once - -#include -#include -#include - -#include - - -#include "fairseq2n/memory.h" -#include "fairseq2n/span.h" -#include "fairseq2n/utils/cast.h" - -namespace fairseq2n::detail { - -// Wraps `memory_block` as a "virtual" file to use with libpng. -class vio_file { -public: - explicit - vio_file(memory_block &&block) noexcept - : block_{std::move(block)} - {} - - ::png_voidp get_io_ptr() { - return static_cast<::png_voidp>(&io_ptr_); - } - - ::png_size_t read(void *ptr, ::png_size_t size); - - ::png_size_t write(const void *ptr, ::png_size_t size); - -private: - static std::size_t - as_size(::png_size_t value) noexcept - { - return conditional_cast(value); - } - -private: - memory_block block_; - ::png_size_t current_pos_{}; - char io_ptr_; -}; - -} // namespace fairseq2n::detail \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 7e0d2d07a..d453d8502 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,63 @@ image_decoder::operator()(data &&d) const throw_( "The input memory block has zero length and cannot be decoded as audio."); + png_bytep buffer = reinterpret_cast(const_cast(static_cast(block.data()))); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + // Handle error + } + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + // Handle error + } + + png_rw_ptr read_fn = [](png_structp png_ptr, png_bytep data, png_size_t length) { + png_bytep& buffer = *reinterpret_cast(png_get_io_ptr(png_ptr)); + memcpy(data, buffer, length); + buffer += length; + }; + png_set_read_fn(png_ptr, &buffer, read_fn); + + png_read_info(png_ptr, info_ptr); + png_uint_32 width = png_get_image_width(png_ptr, info_ptr); + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + int color_type = png_get_color_type(png_ptr, info_ptr); + + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); + + at::Tensor rgb = at::empty({width, height}, + at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + + writable_memory_span rgb_bits = get_raw_mutable_storage(rgb); + + switch (dtype) { + case at::kFloat: { + span waveform_data = cast(rgb_bits); + + buffer.decode_into(waveform_data); + + break; + } + case at::kByte: { + span waveform_data = cast(rgb_bits); + + file.decode_into(waveform_data); + + break; + } + default: + throw_( + "`audio_decoder` uses an unsupported data type. Please file a bug report."); + }; + + at::Device device = opts_.maybe_device().value_or(at::kCPU); + if (device != at::kCPU) + waveform = waveform.to(device); + } }; \ No newline at end of file From 70b1c7212f778581097be1f36eee6e8b4ebafd5e Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 06:45:21 -0700 Subject: [PATCH 52/98] image decoder --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index d453d8502..f90a6cecd 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -86,25 +86,25 @@ image_decoder::operator()(data &&d) const case at::kFloat: { span waveform_data = cast(rgb_bits); - buffer.decode_into(waveform_data); + // todo break; } case at::kByte: { span waveform_data = cast(rgb_bits); - file.decode_into(waveform_data); + // todo break; } default: throw_( - "`audio_decoder` uses an unsupported data type. Please file a bug report."); + "`image_decoder` uses an unsupported data type. Please file a bug report."); }; at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) - waveform = waveform.to(device); + // todo } }; \ No newline at end of file From 3613c045e15bdfc83abeaed14a78f77b74c29d22 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 08:30:28 -0700 Subject: [PATCH 53/98] python binding --- src/fairseq2/data/png.py | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/fairseq2/data/png.py diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py new file mode 100644 index 000000000..fbb722153 --- /dev/null +++ b/src/fairseq2/data/png.py @@ -0,0 +1,42 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import TYPE_CHECKING, Optional, TypedDict, Union + +from torch import Tensor +from typing_extensions import NotRequired + +from fairseq2 import _DOC_MODE +from fairseq2.memory import MemoryBlock +from fairseq2.typing import DataType, Device + +if TYPE_CHECKING or _DOC_MODE: + + class ImageDecoder: + def __init__( + self, + dtype: Optional[DataType] = None, + device: Optional[Device] = None, + pin_memory: bool = False, + ) -> None: + ... + + def __call__(self, memory_block: MemoryBlock) -> "ImageDecoderOutput": + ... + +else: + from fairseq2n.bindings.data.png import ImageDecoder as ImageDecoder + + def _set_module_name() -> None: + for t in [ImageDecoder]: + t.__module__ = __name__ + + _set_module_name() + +class ImageDecoderOutput(TypedDict): + waveform: Tensor + sample_rate: float + format: int From 790f0a9a6fd9841684914d76ffe8070c4d6466b2 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 15:09:32 -0700 Subject: [PATCH 54/98] png decoder progress and py binding --- fairseq2n/src/fairseq2n/CMakeLists.txt | 2 +- .../{image_decoder.cc => png_decoder.cc} | 70 ++++++++++++++----- .../image/{image_decoder.h => png_decoder.h} | 14 ++-- src/fairseq2/data/png.py | 2 - 4 files changed, 59 insertions(+), 29 deletions(-) rename fairseq2n/src/fairseq2n/data/image/{image_decoder.cc => png_decoder.cc} (62%) rename fairseq2n/src/fairseq2n/data/image/{image_decoder.h => png_decoder.h} (85%) diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 30378f731..19dd4a873 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -55,7 +55,7 @@ target_sources(fairseq2n data/audio/detail/sndfile.cc data/detail/file.cc data/detail/file_system.cc - data/image/image_decoder.cc + data/image/png_decoder.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc similarity index 62% rename from fairseq2n/src/fairseq2n/data/image/image_decoder.cc rename to fairseq2n/src/fairseq2n/data/image/png_decoder.cc index f90a6cecd..3d9f036aa 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -4,12 +4,13 @@ // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. -#include "fairseq2n/data/image/image_decoder.h" +#include "fairseq2n/data/image/png_decoder.h" #include #include #include #include +#include #include #include @@ -27,17 +28,17 @@ using namespace fairseq2n::detail; namespace fairseq2n { -image_decoder::image_decoder(image_decoder_options opts) +png_decoder::png_decoder(png_decoder_options opts) : opts_{opts} { at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); if (dtype != at::kFloat && dtype != at::kByte) throw_( - "`image_decoder` supports only `torch.float32` and `torch.uint8` data types."); + "`png_decoder` supports only `torch.float32` and `torch.uint8` data types."); } data -image_decoder::operator()(data &&d) const +png_decoder::operator()(data &&d) const { if (!d.is_memory_block()) throw_( @@ -46,41 +47,67 @@ image_decoder::operator()(data &&d) const const memory_block &block = d.as_memory_block(); if (block.empty()) throw_( - "The input memory block has zero length and cannot be decoded as audio."); - - png_bytep buffer = reinterpret_cast(const_cast(static_cast(block.data()))); + "The input memory block has zero length and cannot be decoded as png."); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { - // Handle error + throw_("Failed to create PNG read struct."); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); - // Handle error + throw_("Failed to create PNG info struct."); + } + + // Set up error handling. + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw std::runtime_error("Error reading PNG image from memory"); } - - png_rw_ptr read_fn = [](png_structp png_ptr, png_bytep data, png_size_t length) { - png_bytep& buffer = *reinterpret_cast(png_get_io_ptr(png_ptr)); - memcpy(data, buffer, length); - buffer += length; - }; - png_set_read_fn(png_ptr, &buffer, read_fn); + auto datap = block.data(); + auto datap_len = block.size(); + + struct Reader { + png_const_bytep ptr; + png_size_t count; + } reader; + + reader.ptr = png_const_bytep(datap) + 8; + reader.count = datap_len - 8; + + auto read_callback = [](png_structp png_ptr, + png_bytep output, + png_size_t bytes) { + auto reader = static_cast(png_get_io_ptr(png_ptr)); + TORCH_CHECK( + reader->count >= bytes, + "Out of bound read in png_decoder. Probably, the input image is corrupted"); + std::copy(reader->ptr, reader->ptr + bytes, output); + reader->ptr += bytes; + reader->count -= bytes; + }; + png_set_sig_bytes(png_ptr, 8); + png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); + png_uint_32 width = png_get_image_width(png_ptr, info_ptr); png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); - - + + // temporary check to confirm image is being read + std::cout << "img width:" << width << std::endl; + + /* at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); at::Tensor rgb = at::empty({width, height}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); writable_memory_span rgb_bits = get_raw_mutable_storage(rgb); + switch (dtype) { case at::kFloat: { @@ -104,7 +131,12 @@ image_decoder::operator()(data &&d) const at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) - // todo + {// todo + } + + */ + + } }; \ No newline at end of file diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/png_decoder.h similarity index 85% rename from fairseq2n/src/fairseq2n/data/image/image_decoder.h rename to fairseq2n/src/fairseq2n/data/image/png_decoder.h index 144dde1a8..0e4e993a7 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.h @@ -16,9 +16,9 @@ namespace fairseq2n { -class image_decoder_options { +class png_decoder_options { public: - image_decoder_options + png_decoder_options maybe_dtype(std::optional value) noexcept { auto tmp = *this; @@ -34,7 +34,7 @@ class image_decoder_options { return maybe_dtype_; } - image_decoder_options + png_decoder_options maybe_device(std::optional value) noexcept { auto tmp = *this; @@ -50,7 +50,7 @@ class image_decoder_options { return maybe_device_; } - image_decoder_options + png_decoder_options pin_memory(bool value) noexcept { auto tmp = *this; @@ -72,16 +72,16 @@ class image_decoder_options { bool pin_memory_ = false; }; -class FAIRSEQ2_API image_decoder { +class FAIRSEQ2_API png_decoder { public: explicit - image_decoder(image_decoder_options opts = {}); + png_decoder(png_decoder_options opts = {}); data operator()(data &&d) const; private: - image_decoder_options opts_; + png_decoder_options opts_; }; } // \ No newline at end of file diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index fbb722153..9e8279d83 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -37,6 +37,4 @@ def _set_module_name() -> None: _set_module_name() class ImageDecoderOutput(TypedDict): - waveform: Tensor - sample_rate: float format: int From 143770f650c9e1aa0c7b9d8782a3c3308b8d1c9e Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 15:26:23 -0700 Subject: [PATCH 55/98] build py binding --- .../src/fairseq2n/bindings/CMakeLists.txt | 1 + .../python/src/fairseq2n/bindings/data/png.cc | 47 +++++++++++++++++++ .../python/src/fairseq2n/bindings/module.h | 3 ++ src/fairseq2/data/png.py | 10 ++-- 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 fairseq2n/python/src/fairseq2n/bindings/data/png.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt index 2a7d1e529..8d7be119c 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt +++ b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(py_bindings init.cc memory.cc data/audio.cc + data/png.cc data/data_pipeline.cc data/init.cc data/string.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc new file mode 100644 index 000000000..f7a44af32 --- /dev/null +++ b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc @@ -0,0 +1,47 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/bindings/module.h" + +#include +#include + +#include +#include + +#include +#include + +namespace py = pybind11; + +namespace fairseq2n { + +void +def_png(py::module_ &data_module) +{ + py::module_ m = data_module.def_submodule("png"); + + // PNGDecoder + py::class_>(m, "PNGDecoder") + .def( + py::init([]( + std::optional maybe_dtype, + std::optional maybe_device, + bool pin_memory) + { + auto opts = png_decoder_options() + .maybe_dtype(maybe_dtype).maybe_device(maybe_device).pin_memory(pin_memory); + + return std::make_shared(opts); + }), + py::arg("dtype") = std::nullopt, + py::arg("device") = std::nullopt, + py::arg("pin_memory") = false) + .def("__call__", &png_decoder::operator(), py::call_guard{}); + + map_functors().register_(); +} +} // namespace fairseq2n diff --git a/fairseq2n/python/src/fairseq2n/bindings/module.h b/fairseq2n/python/src/fairseq2n/bindings/module.h index 2a79e9fdd..01e454f4b 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/module.h +++ b/fairseq2n/python/src/fairseq2n/bindings/module.h @@ -22,6 +22,9 @@ namespace fairseq2n { void def_audio(pybind11::module_ &data_module); +void +def_png(py::module_ &data_module); + void def_data(pybind11::module_ &base_module); diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index 9e8279d83..bb11c9314 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -15,7 +15,7 @@ if TYPE_CHECKING or _DOC_MODE: - class ImageDecoder: + class PNGDecoder: def __init__( self, dtype: Optional[DataType] = None, @@ -24,17 +24,17 @@ def __init__( ) -> None: ... - def __call__(self, memory_block: MemoryBlock) -> "ImageDecoderOutput": + def __call__(self, memory_block: MemoryBlock) -> "PNGDecoderOutput": ... else: - from fairseq2n.bindings.data.png import ImageDecoder as ImageDecoder + from fairseq2n.bindings.data.png import PNGDecoder as PNGDecoder def _set_module_name() -> None: - for t in [ImageDecoder]: + for t in [PNGDecoder]: t.__module__ = __name__ _set_module_name() -class ImageDecoderOutput(TypedDict): +class PNGDecoderOutput(TypedDict): format: int From 38fe657ed6786841aeecf54720cf892bbb8807b8 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 16 Oct 2023 15:42:02 -0700 Subject: [PATCH 56/98] update init --- fairseq2n/python/src/fairseq2n/bindings/data/init.cc | 2 ++ fairseq2n/python/src/fairseq2n/bindings/module.h | 2 +- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc index acceffc5b..ec9364254 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc @@ -40,6 +40,8 @@ def_data(py::module_ &base) def_audio(m); + def_png(m); + def_data_pipeline(m); def_string(m); diff --git a/fairseq2n/python/src/fairseq2n/bindings/module.h b/fairseq2n/python/src/fairseq2n/bindings/module.h index 01e454f4b..2db246694 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/module.h +++ b/fairseq2n/python/src/fairseq2n/bindings/module.h @@ -23,7 +23,7 @@ void def_audio(pybind11::module_ &data_module); void -def_png(py::module_ &data_module); +def_png(pybind11::module_ &data_module); void def_data(pybind11::module_ &base_module); diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 3d9f036aa..fe538efc0 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -20,7 +20,6 @@ #include "fairseq2n/fmt.h" #include "fairseq2n/memory.h" #include "fairseq2n/span.h" -#include "fairseq2n/data/audio/detail/sndfile.h" #include "fairseq2n/data/detail/tensor_helpers.h" #include "fairseq2n/detail/exception.h" From 7cb73a00d3eee48995b5b31b4d02dca355e59e77 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 08:56:52 -0700 Subject: [PATCH 57/98] png decoder progress --- .../src/fairseq2n/data/image/png_decoder.cc | 63 ++++++------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index fe538efc0..b5ac51c58 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -47,7 +47,7 @@ png_decoder::operator()(data &&d) const if (block.empty()) throw_( "The input memory block has zero length and cannot be decoded as png."); - + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { throw_("Failed to create PNG read struct."); @@ -58,30 +58,24 @@ png_decoder::operator()(data &&d) const throw_("Failed to create PNG info struct."); } - // Set up error handling. - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - throw std::runtime_error("Error reading PNG image from memory"); - } - - auto datap = block.data(); - auto datap_len = block.size(); + auto data_ptr = block.data(); + auto data_len = block.size(); struct Reader { png_const_bytep ptr; png_size_t count; } reader; - reader.ptr = png_const_bytep(datap) + 8; - reader.count = datap_len - 8; + reader.ptr = png_const_bytep(data_ptr) + 8; + reader.count = data_len - 8; auto read_callback = [](png_structp png_ptr, png_bytep output, png_size_t bytes) { auto reader = static_cast(png_get_io_ptr(png_ptr)); - TORCH_CHECK( - reader->count >= bytes, - "Out of bound read in png_decoder. Probably, the input image is corrupted"); + if (reader->count > bytes) { + throw std::runtime_error("Out of bound read in png_decoder. Probably, the input image is corrupted"); + } std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; @@ -94,48 +88,29 @@ png_decoder::operator()(data &&d) const png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); - + int channels = png_get_channels(png_ptr, info_ptr); // temporary check to confirm image is being read std::cout << "img width:" << width << std::endl; - /* at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - at::Tensor rgb = at::empty({width, height}, + at::Tensor image = at::empty({width, height, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); - writable_memory_span rgb_bits = get_raw_mutable_storage(rgb); - - - switch (dtype) { - case at::kFloat: { - span waveform_data = cast(rgb_bits); - - // todo - - break; - } - case at::kByte: { - span waveform_data = cast(rgb_bits); - - // todo - - break; - } - default: - throw_( - "`image_decoder` uses an unsupported data type. Please file a bug report."); - }; - at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) - {// todo - } + image = image.to(device); - */ + // Pack png data and format as output. + data_dict output{ + {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, + {"channels", static_cast(channels)}, {"height", static_cast(height)}, + {"width", static_cast(width)}}; + output.emplace("image", std::move(image)); - + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + return output; } }; \ No newline at end of file From aa12050bb0e7ce1874d64367b8f7e71f59020c6b Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 13:44:44 -0700 Subject: [PATCH 58/98] png decoder progress --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index b5ac51c58..10399e97e 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -60,7 +60,7 @@ png_decoder::operator()(data &&d) const auto data_ptr = block.data(); auto data_len = block.size(); - + std::cout << "len " << data_len << std::endl; struct Reader { png_const_bytep ptr; png_size_t count; @@ -73,13 +73,12 @@ png_decoder::operator()(data &&d) const png_bytep output, png_size_t bytes) { auto reader = static_cast(png_get_io_ptr(png_ptr)); - if (reader->count > bytes) { - throw std::runtime_error("Out of bound read in png_decoder. Probably, the input image is corrupted"); - } + std::cout << "reader->count: " << reader->count << " bytes " << bytes << std::endl; std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; }; + png_set_sig_bytes(png_ptr, 8); png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); @@ -90,12 +89,9 @@ png_decoder::operator()(data &&d) const int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); - // temporary check to confirm image is being read - std::cout << "img width:" << width << std::endl; - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - at::Tensor image = at::empty({width, height, channels}, + at::Tensor image = at::empty({width, height}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); at::Device device = opts_.maybe_device().value_or(at::kCPU); From c17c3b3ef5cb68f02544b1a4e3924471f19a3bd1 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 13:45:30 -0700 Subject: [PATCH 59/98] remove print statements --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 10399e97e..28dc458c4 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -60,7 +60,7 @@ png_decoder::operator()(data &&d) const auto data_ptr = block.data(); auto data_len = block.size(); - std::cout << "len " << data_len << std::endl; + struct Reader { png_const_bytep ptr; png_size_t count; @@ -73,7 +73,6 @@ png_decoder::operator()(data &&d) const png_bytep output, png_size_t bytes) { auto reader = static_cast(png_get_io_ptr(png_ptr)); - std::cout << "reader->count: " << reader->count << " bytes " << bytes << std::endl; std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; From 0075f0ba59ba903b39013178104f359a4fe6fffc Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 15:12:05 -0700 Subject: [PATCH 60/98] populate tensor object with png data --- .../src/fairseq2n/data/image/png_decoder.cc | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 28dc458c4..f7a9cd5f5 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -68,7 +68,8 @@ png_decoder::operator()(data &&d) const reader.ptr = png_const_bytep(data_ptr) + 8; reader.count = data_len - 8; - + + // Define custom read function auto read_callback = [](png_structp png_ptr, png_bytep output, png_size_t bytes) { @@ -87,12 +88,39 @@ png_decoder::operator()(data &&d) const int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); - + + // Allocate memory for image data + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); + for (int y = 0; y < height; y++) { + row_pointers[y] = (png_byte*) malloc(rowbytes); + } + + // Read image data row by row + png_read_image(png_ptr, row_pointers); + + // Specify tensor data type at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - at::Tensor image = at::empty({width, height}, - at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + // Copy image data into tensor object + at::Tensor image = at::empty({height, width, 3}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + for (int y = 0; y < height; y++) { + png_bytep row = row_pointers[y]; + for (int x = 0; x < width; x++) { + png_bytep px = &(row[x * 3]); + image[y][x][0] = px[0]; + image[y][x][1] = px[1]; + image[y][x][2] = px[2]; + } + } + // Free memory for image data + for (int y = 0; y < height; y++) { + free(row_pointers[y]); + } + free(row_pointers); + + // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); From 3efe070b6d4df7c3667e4a66a3125aa965878ca8 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 17 Oct 2023 15:13:30 -0700 Subject: [PATCH 61/98] remove unnecessary include --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index f7a9cd5f5..3a148b4e9 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include From 21239e836d58083251cc2aaec6150292a8ce8798 Mon Sep 17 00:00:00 2001 From: Alisha Date: Fri, 20 Oct 2023 15:48:24 -0700 Subject: [PATCH 62/98] more efficient use of memory for populating tensor --- .../src/fairseq2n/data/image/png_decoder.cc | 44 ++++++------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 3a148b4e9..99a6ba2b8 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -69,10 +70,10 @@ png_decoder::operator()(data &&d) const reader.count = data_len - 8; // Define custom read function - auto read_callback = [](png_structp png_ptr, + auto read_callback = [](png_structp png_ptr2, png_bytep output, png_size_t bytes) { - auto reader = static_cast(png_get_io_ptr(png_ptr)); + auto reader = static_cast(png_get_io_ptr(png_ptr2)); std::copy(reader->ptr, reader->ptr + bytes, output); reader->ptr += bytes; reader->count -= bytes; @@ -88,37 +89,18 @@ png_decoder::operator()(data &&d) const int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); - // Allocate memory for image data - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); - png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); - for (int y = 0; y < height; y++) { - row_pointers[y] = (png_byte*) malloc(rowbytes); - } - - // Read image data row by row - png_read_image(png_ptr, row_pointers); - - // Specify tensor data type - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - + at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kByte); + at::Tensor image = at::empty({height, width, 4}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + auto t_ptr = image.accessor().data(); + // Copy image data into tensor object - at::Tensor image = at::empty({height, width, 3}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); - for (int y = 0; y < height; y++) { - png_bytep row = row_pointers[y]; - for (int x = 0; x < width; x++) { - png_bytep px = &(row[x * 3]); - image[y][x][0] = px[0]; - image[y][x][1] = px[1]; - image[y][x][2] = px[2]; - } - } - - // Free memory for image data - for (int y = 0; y < height; y++) { - free(row_pointers[y]); + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, t_ptr, nullptr); + t_ptr += rowbytes; } - free(row_pointers); - + t_ptr = image.accessor().data(); + // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) From 77b152ae25d63ce6a8e8bdb64b675981cf18cbcf Mon Sep 17 00:00:00 2001 From: Alisha Date: Fri, 20 Oct 2023 16:35:15 -0700 Subject: [PATCH 63/98] use get_raw_mutable_storage instead --- .../src/fairseq2n/data/image/png_decoder.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 99a6ba2b8..b716d2439 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -90,22 +90,24 @@ png_decoder::operator()(data &&d) const int channels = png_get_channels(png_ptr, info_ptr); at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kByte); - at::Tensor image = at::empty({height, width, 4}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - auto t_ptr = image.accessor().data(); - - // Copy image data into tensor object + writable_memory_span image_bits = get_raw_mutable_storage(image); + png_bytep image_data = reinterpret_cast(image_bits.data()); + + // Read image data into tensor for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, t_ptr, nullptr); - t_ptr += rowbytes; + png_read_row(png_ptr, image_data, nullptr); + image_data += rowbytes; } - t_ptr = image.accessor().data(); - + // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); + // Pack png data and format as output. data_dict output{ {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, From 77fc0900e64c06ee6697f41069c4d5149acb766e Mon Sep 17 00:00:00 2001 From: Alisha Date: Sat, 21 Oct 2023 17:08:22 -0700 Subject: [PATCH 64/98] add png to build configs, support float32 tensor --- .github/workflows/_build_wheel-linux.yaml | 9 +++ .github/workflows/_build_wheel-macos.yaml | 2 + .../python/src/fairseq2n/bindings/data/png.cc | 4 +- fairseq2n/src/fairseq2n/CMakeLists.txt | 2 - .../src/fairseq2n/data/image/png_decoder.cc | 68 ++++++++++++++----- .../src/fairseq2n/data/image/png_decoder.h | 23 ++----- src/fairseq2/data/png.py | 7 +- 7 files changed, 68 insertions(+), 47 deletions(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index b5aea3cc8..b937ee708 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -156,6 +156,15 @@ jobs: run: shell: bash steps: +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel +>>>>>>> 18f3c8e9 (add png to build configs, support float32 tensor) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index 1137d4878..febf74102 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -38,6 +38,7 @@ jobs: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | brew install libsndfile python@${{ inputs.py }} || true + brew install libpng || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv @@ -101,6 +102,7 @@ jobs: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | brew install libsndfile python@${{ inputs.py }} || true + brew install libpng || true - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc index f7a44af32..a3c45c2ab 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/png.cc @@ -28,16 +28,14 @@ def_png(py::module_ &data_module) py::class_>(m, "PNGDecoder") .def( py::init([]( - std::optional maybe_dtype, std::optional maybe_device, bool pin_memory) { auto opts = png_decoder_options() - .maybe_dtype(maybe_dtype).maybe_device(maybe_device).pin_memory(pin_memory); + .maybe_device(maybe_device).pin_memory(pin_memory); return std::make_shared(opts); }), - py::arg("dtype") = std::nullopt, py::arg("device") = std::nullopt, py::arg("pin_memory") = false) .def("__call__", &png_decoder::operator(), py::call_guard{}); diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 19dd4a873..a0018dc8a 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -104,7 +104,6 @@ target_include_directories(fairseq2n ${system} ) find_package(PNG REQUIRED) -find_package(JPEG REQUIRED) target_link_libraries(fairseq2n PRIVATE @@ -119,7 +118,6 @@ target_link_libraries(fairseq2n sentencepiece-static SndFile::sndfile PNG::PNG - JPEG::JPEG PUBLIC torch ) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index b716d2439..e295e5465 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -29,11 +29,12 @@ namespace fairseq2n { png_decoder::png_decoder(png_decoder_options opts) : opts_{opts} -{ - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kFloat); - if (dtype != at::kFloat && dtype != at::kByte) - throw_( - "`png_decoder` supports only `torch.float32` and `torch.uint8` data types."); +{} + +bool +png_decoder::is_little_endian() const { + uint32_t x = 1; + return *(uint8_t*)&x; } data @@ -58,18 +59,23 @@ png_decoder::operator()(data &&d) const throw_("Failed to create PNG info struct."); } - auto data_ptr = block.data(); + auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); + /* + if(png_sig_cmp(data_ptr, 0, 8) == 0) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw_("The input data is not a valid PNG image."); + }; + */ struct Reader { png_const_bytep ptr; png_size_t count; } reader; - reader.ptr = png_const_bytep(data_ptr) + 8; + reader.ptr = data_ptr + 8; reader.count = data_len - 8; - // Define custom read function auto read_callback = [](png_structp png_ptr2, png_bytep output, png_size_t bytes) { @@ -83,13 +89,31 @@ png_decoder::operator()(data &&d) const png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); - png_uint_32 width = png_get_image_width(png_ptr, info_ptr); - png_uint_32 height = png_get_image_height(png_ptr, info_ptr); - int bit_depth = png_get_bit_depth(png_ptr, info_ptr); - int color_type = png_get_color_type(png_ptr, info_ptr); + png_uint_32 width, height; + int bit_depth, color_type; + int interlace_type; + auto retval = png_get_IHDR( + png_ptr, + info_ptr, + &width, + &height, + &bit_depth, + &color_type, + &interlace_type, + nullptr, + nullptr); + + if (retval != 1) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw_("Could not read image metadata from content."); + } + + if (is_little_endian()) { + png_set_swap(png_ptr); + } int channels = png_get_channels(png_ptr, info_ptr); - at::ScalarType dtype = opts_.maybe_dtype().value_or(at::kByte); + at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kFloat; at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); @@ -97,17 +121,25 @@ png_decoder::operator()(data &&d) const png_bytep image_data = reinterpret_cast(image_bits.data()); // Read image data into tensor - for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, image_data, nullptr); - image_data += rowbytes; + if (dtype == at::kByte) { + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, image_data, nullptr); + image_data += rowbytes; + } + } else { // image is 16 bit + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, (uint8_t*)image_data, nullptr); + for (size_t j = 0; j < rowbytes; ++j) { + image_data[j] = (int32_t)image_data[j]; + } + image_data += rowbytes; + } } - // Move tensor to specified device at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); - // Pack png data and format as output. data_dict output{ {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.h b/fairseq2n/src/fairseq2n/data/image/png_decoder.h index 0e4e993a7..3267e9727 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.h @@ -18,22 +18,6 @@ namespace fairseq2n { class png_decoder_options { public: - png_decoder_options - maybe_dtype(std::optional value) noexcept - { - auto tmp = *this; - - tmp.maybe_dtype_ = value; - - return tmp; - } - - std::optional - maybe_dtype() const noexcept - { - return maybe_dtype_; - } - png_decoder_options maybe_device(std::optional value) noexcept { @@ -67,7 +51,6 @@ class png_decoder_options { } private: - std::optional maybe_dtype_{}; std::optional maybe_device_{}; bool pin_memory_ = false; }; @@ -82,6 +65,8 @@ class FAIRSEQ2_API png_decoder { private: png_decoder_options opts_; -}; -} // \ No newline at end of file + bool + is_little_endian() const; +}; +} // namespace fairseq2n diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index bb11c9314..ee0c61cfe 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -4,10 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -from typing import TYPE_CHECKING, Optional, TypedDict, Union - -from torch import Tensor -from typing_extensions import NotRequired +from typing import TYPE_CHECKING, Optional, TypedDict from fairseq2 import _DOC_MODE from fairseq2.memory import MemoryBlock @@ -18,7 +15,6 @@ class PNGDecoder: def __init__( self, - dtype: Optional[DataType] = None, device: Optional[Device] = None, pin_memory: bool = False, ) -> None: @@ -36,5 +32,6 @@ def _set_module_name() -> None: _set_module_name() + class PNGDecoderOutput(TypedDict): format: int From a129e0e448d04d2e64d475e83daff8073c315eb3 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sat, 21 Oct 2023 17:16:53 -0700 Subject: [PATCH 65/98] fix lint --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 2 +- src/fairseq2/data/png.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index e295e5465..817a08877 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -128,7 +128,7 @@ png_decoder::operator()(data &&d) const } } else { // image is 16 bit for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, (uint8_t*)image_data, nullptr); + png_read_row(png_ptr, image_data, nullptr); for (size_t j = 0; j < rowbytes; ++j) { image_data[j] = (int32_t)image_data[j]; } diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/png.py index ee0c61cfe..40da2e974 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/png.py @@ -8,7 +8,7 @@ from fairseq2 import _DOC_MODE from fairseq2.memory import MemoryBlock -from fairseq2.typing import DataType, Device +from fairseq2.typing import Device if TYPE_CHECKING or _DOC_MODE: From 4663ab28c951458d6c3539d98d293594f4293877 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sat, 21 Oct 2023 17:33:55 -0700 Subject: [PATCH 66/98] fix lint --- fairseq2n/src/fairseq2n/data/image/png_decoder.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 817a08877..273009699 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -130,7 +130,7 @@ png_decoder::operator()(data &&d) const for (png_uint_32 i = 0; i < height; ++i) { png_read_row(png_ptr, image_data, nullptr); for (size_t j = 0; j < rowbytes; ++j) { - image_data[j] = (int32_t)image_data[j]; + image_data[j] = static_cast(image_data[j]); } image_data += rowbytes; } @@ -151,4 +151,4 @@ png_decoder::operator()(data &&d) const png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return output; } -}; \ No newline at end of file +}; From fd437d8b982695cfcf3f1f900f44cfa10bc23cb4 Mon Sep 17 00:00:00 2001 From: Alisha Date: Sun, 22 Oct 2023 17:32:50 -0700 Subject: [PATCH 67/98] fix lint --- .../src/fairseq2n/data/image/png_decoder.cc | 42 +++++++++---------- .../src/fairseq2n/data/image/png_decoder.h | 4 +- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 273009699..6edb52a7d 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -32,9 +32,9 @@ png_decoder::png_decoder(png_decoder_options opts) {} bool -png_decoder::is_little_endian() const { +png_decoder::is_little_endian() { uint32_t x = 1; - return *(uint8_t*)&x; + return (*reinterpret_cast(&x) == 1); } data @@ -49,32 +49,25 @@ png_decoder::operator()(data &&d) const throw_( "The input memory block has zero length and cannot be decoded as png."); - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { throw_("Failed to create PNG read struct."); } png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); + if (info_ptr == nullptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); throw_("Failed to create PNG info struct."); } auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); - /* - if(png_sig_cmp(data_ptr, 0, 8) == 0) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - throw_("The input data is not a valid PNG image."); - }; - */ struct Reader { png_const_bytep ptr; png_size_t count; - } reader; - - reader.ptr = data_ptr + 8; - reader.count = data_len - 8; + Reader(png_const_bytep p, png_size_t c) : ptr(p), count(c) {} + }; + Reader reader(data_ptr + 8, data_len - 8); auto read_callback = [](png_structp png_ptr2, png_bytep output, @@ -89,9 +82,9 @@ png_decoder::operator()(data &&d) const png_set_read_fn(png_ptr, &reader, read_callback); png_read_info(png_ptr, info_ptr); - png_uint_32 width, height; - int bit_depth, color_type; - int interlace_type; + png_uint_32 width=0, height=0; + int bit_depth=0, color_type=0; + int interlace_type=0; auto retval = png_get_IHDR( png_ptr, info_ptr, @@ -118,7 +111,7 @@ png_decoder::operator()(data &&d) const size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); writable_memory_span image_bits = get_raw_mutable_storage(image); - png_bytep image_data = reinterpret_cast(image_bits.data()); + auto image_data = reinterpret_cast(image_bits.data()); // Read image data into tensor if (dtype == at::kByte) { @@ -126,11 +119,14 @@ png_decoder::operator()(data &&d) const png_read_row(png_ptr, image_data, nullptr); image_data += rowbytes; } - } else { // image is 16 bit + } else { + // Image is 16 bit. Pytorch does not support uint16 tensors, so we + // read into a uint16 vector and then cast into a float32 tensor. + std::vector> row_pointers(height, std::vector(rowbytes / sizeof(uint16_t))); for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, image_data, nullptr); + png_read_row(png_ptr, reinterpret_cast(row_pointers[i].data()), nullptr); for (size_t j = 0; j < rowbytes; ++j) { - image_data[j] = static_cast(image_data[j]); + image_data[j] = static_cast(row_pointers[i][j]); } image_data += rowbytes; } diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.h b/fairseq2n/src/fairseq2n/data/image/png_decoder.h index 3267e9727..f30313ad8 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.h @@ -66,7 +66,7 @@ class FAIRSEQ2_API png_decoder { private: png_decoder_options opts_; - bool - is_little_endian() const; + static bool + is_little_endian(); }; } // namespace fairseq2n From 9c376a415b84bcb82acddbc7ad47d70e4f65010e Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 06:44:17 -0700 Subject: [PATCH 68/98] remove type casting --- .../src/fairseq2n/data/image/png_decoder.cc | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc index 6edb52a7d..5365e5278 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/png_decoder.cc @@ -106,7 +106,7 @@ png_decoder::operator()(data &&d) const } int channels = png_get_channels(png_ptr, info_ptr); - at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kFloat; + at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); @@ -114,22 +114,9 @@ png_decoder::operator()(data &&d) const auto image_data = reinterpret_cast(image_bits.data()); // Read image data into tensor - if (dtype == at::kByte) { - for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, image_data, nullptr); - image_data += rowbytes; - } - } else { - // Image is 16 bit. Pytorch does not support uint16 tensors, so we - // read into a uint16 vector and then cast into a float32 tensor. - std::vector> row_pointers(height, std::vector(rowbytes / sizeof(uint16_t))); - for (png_uint_32 i = 0; i < height; ++i) { - png_read_row(png_ptr, reinterpret_cast(row_pointers[i].data()), nullptr); - for (size_t j = 0; j < rowbytes; ++j) { - image_data[j] = static_cast(row_pointers[i][j]); - } - image_data += rowbytes; - } + for (png_uint_32 i = 0; i < height; ++i) { + png_read_row(png_ptr, image_data, nullptr); + image_data += rowbytes; } at::Device device = opts_.maybe_device().value_or(at::kCPU); From 3d6835211c8ee51080bdace887547c19511d6309 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 08:19:54 -0700 Subject: [PATCH 69/98] combine png and jpeg decoders into one class --- .../src/fairseq2n/bindings/CMakeLists.txt | 2 +- .../bindings/data/{png.cc => image.cc} | 18 ++++---- .../src/fairseq2n/bindings/data/init.cc | 2 +- .../python/src/fairseq2n/bindings/module.h | 2 +- fairseq2n/src/fairseq2n/CMakeLists.txt | 4 +- .../{png_decoder.cc => image_decoder.cc} | 43 +++++++++++++++---- .../image/{png_decoder.h => image_decoder.h} | 19 +++++--- src/fairseq2/data/{png.py => image.py} | 10 ++--- 8 files changed, 67 insertions(+), 33 deletions(-) rename fairseq2n/python/src/fairseq2n/bindings/data/{png.cc => image.cc} (61%) rename fairseq2n/src/fairseq2n/data/image/{png_decoder.cc => image_decoder.cc} (80%) rename fairseq2n/src/fairseq2n/data/image/{png_decoder.h => image_decoder.h} (77%) rename src/fairseq2/data/{png.py => image.py} (73%) diff --git a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt index 8d7be119c..f9806c7d4 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt +++ b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt @@ -17,7 +17,7 @@ target_sources(py_bindings init.cc memory.cc data/audio.cc - data/png.cc + data/image.cc data/data_pipeline.cc data/init.cc data/string.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc b/fairseq2n/python/src/fairseq2n/bindings/data/image.cc similarity index 61% rename from fairseq2n/python/src/fairseq2n/bindings/data/png.cc rename to fairseq2n/python/src/fairseq2n/bindings/data/image.cc index a3c45c2ab..7263a9b3d 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/png.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/image.cc @@ -13,33 +13,33 @@ #include #include -#include +#include namespace py = pybind11; namespace fairseq2n { void -def_png(py::module_ &data_module) +def_image(py::module_ &data_module) { - py::module_ m = data_module.def_submodule("png"); + py::module_ m = data_module.def_submodule("image"); - // PNGDecoder - py::class_>(m, "PNGDecoder") + // ImageDecoder + py::class_>(m, "ImageDecoder") .def( py::init([]( std::optional maybe_device, bool pin_memory) { - auto opts = png_decoder_options() + auto opts = image_decoder_options() .maybe_device(maybe_device).pin_memory(pin_memory); - return std::make_shared(opts); + return std::make_shared(opts); }), py::arg("device") = std::nullopt, py::arg("pin_memory") = false) - .def("__call__", &png_decoder::operator(), py::call_guard{}); + .def("__call__", &image_decoder::operator(), py::call_guard{}); - map_functors().register_(); + map_functors().register_(); } } // namespace fairseq2n diff --git a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc index ec9364254..f0408b262 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/data/init.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/data/init.cc @@ -40,7 +40,7 @@ def_data(py::module_ &base) def_audio(m); - def_png(m); + def_image(m); def_data_pipeline(m); diff --git a/fairseq2n/python/src/fairseq2n/bindings/module.h b/fairseq2n/python/src/fairseq2n/bindings/module.h index 2db246694..3cf686773 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/module.h +++ b/fairseq2n/python/src/fairseq2n/bindings/module.h @@ -23,7 +23,7 @@ void def_audio(pybind11::module_ &data_module); void -def_png(pybind11::module_ &data_module); +def_image(pybind11::module_ &data_module); void def_data(pybind11::module_ &base_module); diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index a0018dc8a..30378f731 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -55,7 +55,7 @@ target_sources(fairseq2n data/audio/detail/sndfile.cc data/detail/file.cc data/detail/file_system.cc - data/image/png_decoder.cc + data/image/image_decoder.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc @@ -104,6 +104,7 @@ target_include_directories(fairseq2n ${system} ) find_package(PNG REQUIRED) +find_package(JPEG REQUIRED) target_link_libraries(fairseq2n PRIVATE @@ -118,6 +119,7 @@ target_link_libraries(fairseq2n sentencepiece-static SndFile::sndfile PNG::PNG + JPEG::JPEG PUBLIC torch ) diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc similarity index 80% rename from fairseq2n/src/fairseq2n/data/image/png_decoder.cc rename to fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 5365e5278..dc307d031 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -4,12 +4,11 @@ // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. -#include "fairseq2n/data/image/png_decoder.h" +#include "fairseq2n/data/image/image_decoder.h" #include #include #include -#include #include #include @@ -27,28 +26,48 @@ using namespace fairseq2n::detail; namespace fairseq2n { -png_decoder::png_decoder(png_decoder_options opts) +image_decoder::image_decoder(image_decoder_options opts) : opts_{opts} {} bool -png_decoder::is_little_endian() { +image_decoder::is_little_endian() { uint32_t x = 1; return (*reinterpret_cast(&x) == 1); } data -png_decoder::operator()(data &&d) const +image_decoder::operator()(data &&d) const { if (!d.is_memory_block()) throw_( "The input data must be of type `memory_block`, but is of type `{}` instead.", d.type()); - + const memory_block &block = d.as_memory_block(); if (block.empty()) throw_( - "The input memory block has zero length and cannot be decoded as png."); - + "The input memory block has zero length and cannot be decoded."); + + auto data_ptr = block.data(); + data output; + + const uint8_t jpeg_signature[3] = {255, 216, 255}; + const uint8_t png_signature[4] = {137, 80, 78, 71}; + + if(memcmp(jpeg_signature, data_ptr, 3) == 0) { + output = decode_jpeg(const_cast(block)); + } else if(memcmp(png_signature, data_ptr, 4) == 0) { + output = decode_png(const_cast(block)); + } else { + throw_( + "Unsupported image file. Only jpeg and png are currently supported."); + } + return output; +} + +data +image_decoder::decode_png(memory_block &block) const +{ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { throw_("Failed to create PNG read struct."); @@ -134,4 +153,10 @@ png_decoder::operator()(data &&d) const png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return output; } -}; + +data +image_decoder::decode_jpeg(memory_block &block) const { + data output; + return output; +} +}; // namespace fairseq2n diff --git a/fairseq2n/src/fairseq2n/data/image/png_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h similarity index 77% rename from fairseq2n/src/fairseq2n/data/image/png_decoder.h rename to fairseq2n/src/fairseq2n/data/image/image_decoder.h index f30313ad8..f8a9f6d9e 100644 --- a/fairseq2n/src/fairseq2n/data/image/png_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -13,12 +13,13 @@ #include #include +#include namespace fairseq2n { -class png_decoder_options { +class image_decoder_options { public: - png_decoder_options + image_decoder_options maybe_device(std::optional value) noexcept { auto tmp = *this; @@ -34,7 +35,7 @@ class png_decoder_options { return maybe_device_; } - png_decoder_options + image_decoder_options pin_memory(bool value) noexcept { auto tmp = *this; @@ -55,18 +56,24 @@ class png_decoder_options { bool pin_memory_ = false; }; -class FAIRSEQ2_API png_decoder { +class FAIRSEQ2_API image_decoder { public: explicit - png_decoder(png_decoder_options opts = {}); + image_decoder(image_decoder_options opts = {}); data operator()(data &&d) const; private: - png_decoder_options opts_; + image_decoder_options opts_; static bool is_little_endian(); + + data + decode_png(memory_block &block) const; + + data + decode_jpeg(memory_block &block) const; }; } // namespace fairseq2n diff --git a/src/fairseq2/data/png.py b/src/fairseq2/data/image.py similarity index 73% rename from src/fairseq2/data/png.py rename to src/fairseq2/data/image.py index 40da2e974..4a5fcd512 100644 --- a/src/fairseq2/data/png.py +++ b/src/fairseq2/data/image.py @@ -12,7 +12,7 @@ if TYPE_CHECKING or _DOC_MODE: - class PNGDecoder: + class ImageDecoder: def __init__( self, device: Optional[Device] = None, @@ -20,18 +20,18 @@ def __init__( ) -> None: ... - def __call__(self, memory_block: MemoryBlock) -> "PNGDecoderOutput": + def __call__(self, memory_block: MemoryBlock) -> "ImageDecoderOutput": ... else: - from fairseq2n.bindings.data.png import PNGDecoder as PNGDecoder + from fairseq2n.bindings.data.image import ImageDecoder as ImageDecoder def _set_module_name() -> None: - for t in [PNGDecoder]: + for t in [ImageDecoder]: t.__module__ = __name__ _set_module_name() -class PNGDecoderOutput(TypedDict): +class ImageDecoderOutput(TypedDict): format: int From cd7925780a01ed2a50d401e979ebedad431d3bdb Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 15:53:02 -0700 Subject: [PATCH 70/98] jpeg decoder --- .github/workflows/_build_wheel-linux.yaml | 6 ++ .github/workflows/_build_wheel-macos.yaml | 2 + .../src/fairseq2n/data/image/image_decoder.cc | 64 +++++++++++++++---- .../src/fairseq2n/data/image/image_decoder.h | 5 +- 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index b937ee708..d4c666710 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -164,7 +164,13 @@ jobs: - name: Install libpng-dev run: | yum --assumeyes install libpng-devel +<<<<<<< HEAD >>>>>>> 18f3c8e9 (add png to build configs, support float32 tensor) +======= + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel +>>>>>>> 0587a6b7 (jpeg decoder) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index febf74102..ddb5e4da9 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,6 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true + brew install libjpeg || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv @@ -103,6 +104,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true + brew install libjpeg || true - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index dc307d031..667aff63d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -50,14 +50,14 @@ image_decoder::operator()(data &&d) const auto data_ptr = block.data(); data output; - - const uint8_t jpeg_signature[3] = {255, 216, 255}; - const uint8_t png_signature[4] = {137, 80, 78, 71}; - - if(memcmp(jpeg_signature, data_ptr, 3) == 0) { - output = decode_jpeg(const_cast(block)); - } else if(memcmp(png_signature, data_ptr, 4) == 0) { - output = decode_png(const_cast(block)); + + const std::array jpeg_signature = {255, 216, 255}; + const std::array png_signature = {137, 80, 78, 71}; + + if(memcmp(jpeg_signature.data(), data_ptr, 3) == 0) { + output = decode_jpeg(block); + } else if(memcmp(png_signature.data(), data_ptr, 4) == 0) { + output = decode_png(block); } else { throw_( "Unsupported image file. Only jpeg and png are currently supported."); @@ -66,7 +66,7 @@ image_decoder::operator()(data &&d) const } data -image_decoder::decode_png(memory_block &block) const +image_decoder::decode_png(const memory_block &block) const { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { @@ -155,8 +155,50 @@ image_decoder::decode_png(memory_block &block) const } data -image_decoder::decode_jpeg(memory_block &block) const { - data output; +image_decoder::decode_jpeg(const memory_block &block) const +{ + auto data_ptr = block.data(); + auto data_len = block.size(); + + // Set up decompression process + struct jpeg_decompress_struct cinfo = {}; + struct jpeg_error_mgr jerr = {}; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + auto width = cinfo.output_width; + auto height = cinfo.output_height; + auto channels = cinfo.output_components; + auto row_size = static_cast(width) * static_cast(channels); + int bit_depth = cinfo.data_precision; + + at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; + at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); + writable_memory_span image_bits = get_raw_mutable_storage(image); + auto image_data = reinterpret_cast(image_bits.data()); + + // Read image into tensor + while (cinfo.output_scanline < cinfo.output_height) { + jpeg_read_scanlines(&cinfo, &image_data, 1); + image_data += row_size; + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + at::Device device = opts_.maybe_device().value_or(at::kCPU); + if (device != at::kCPU) + image = image.to(device); + + // Pack jpeg data and format as output. + data_dict output{ + {{"channels", static_cast(channels)}, {"height", static_cast(height)}, + {"width", static_cast(width)}, {"bit_depth", static_cast(bit_depth)}}}; + + output.emplace("image", std::move(image)); + return output; } }; // namespace fairseq2n diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h index f8a9f6d9e..c4c0b297a 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace fairseq2n { @@ -71,9 +72,9 @@ class FAIRSEQ2_API image_decoder { is_little_endian(); data - decode_png(memory_block &block) const; + decode_png(const memory_block &block) const; data - decode_jpeg(memory_block &block) const; + decode_jpeg(const memory_block &block) const; }; } // namespace fairseq2n From bb4956fd7a6c0aa20ebfbef0389915612a53bc8a Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 16:00:59 -0700 Subject: [PATCH 71/98] fix lint --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 667aff63d..7efd39eb9 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -172,7 +172,7 @@ image_decoder::decode_jpeg(const memory_block &block) const auto width = cinfo.output_width; auto height = cinfo.output_height; auto channels = cinfo.output_components; - auto row_size = static_cast(width) * static_cast(channels); + auto row_size = width * static_cast(channels); int bit_depth = cinfo.data_precision; at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; From c67c5e1d327bfad769add79acc326ecfa7fd34d6 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 16:20:06 -0700 Subject: [PATCH 72/98] fix lint --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 7efd39eb9..2c7803f7e 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,13 +159,14 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); + std::vector data_copy(data_ptr, data_ptr + data_len); // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, data_copy.data(), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From 03e77dba0d85a9126c84ed5b37476ba827d622ae Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 23 Oct 2023 16:46:58 -0700 Subject: [PATCH 73/98] change type cast --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 2c7803f7e..114f057ac 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,14 +159,13 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); - std::vector data_copy(data_ptr, data_ptr + data_len); // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, data_copy.data(), data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From 8e2f083fb18eea5efe3d63f78806cd027e0fce62 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 14:49:34 -0700 Subject: [PATCH 74/98] unit test --- tests/unit/data/image/test.jpg | Bin 0 -> 27453 bytes tests/unit/data/image/test.png | Bin 0 -> 73036 bytes tests/unit/data/image/test_image_decoder.py | 115 ++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 tests/unit/data/image/test.jpg create mode 100644 tests/unit/data/image/test.png create mode 100644 tests/unit/data/image/test_image_decoder.py diff --git a/tests/unit/data/image/test.jpg b/tests/unit/data/image/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..552e2ada387fa59a0598e60536eda1def05c1e05 GIT binary patch literal 27453 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 literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test.png b/tests/unit/data/image/test.png new file mode 100644 index 0000000000000000000000000000000000000000..75472cbb5ff78acc8716ad9121ed421f17f96c9a GIT binary patch literal 73036 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 |_B5G+Z$Ry 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 literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py new file mode 100644 index 000000000..2fade5774 --- /dev/null +++ b/tests/unit/data/image/test_image_decoder.py @@ -0,0 +1,115 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from pathlib import Path +from typing import Any, Final + +import pytest +import torch + +from fairseq2.data.image import ImageDecoder +from fairseq2.memory import MemoryBlock +from fairseq2.typing import DataType +from tests.common import assert_close, device + +TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") +TEST_JPG_PATH: Final = Path(__file__).parent.joinpath("test.jpg") + + +class TestImageDecoder: + def test_init(self) -> None: + decoder = ImageDecoder() + assert isinstance(decoder, ImageDecoder) + + def test_call_works_on_png(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_PNG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + output = decoder(block) + + assert output["bit_depth"] == 8.0 + + assert output["color_type"] == 6.0 + + assert output["channels"] == 4.0 + + assert output["height"] == 1126.0 + + assert output["width"] == 1132.0 + + image = output["image"] + + assert image.shape == torch.Size([1126, 1132, 4]) + + assert image.dtype == torch.uint8 + + assert image.device == device + + assert_close(image.sum(), torch.tensor(1227963170, device=device)) + + def test_call_works_on_jpg(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_JPG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + output = decoder(block) + + assert output["bit_depth"] == 8.0 + + assert output["channels"] == 3.0 + + assert output["height"] == 1126.0 + + assert output["width"] == 1132.0 + + image = output["image"] + + assert image.shape == torch.Size([1126, 1132, 3]) + + assert image.dtype == torch.uint8 + + assert image.device == device + + assert_close(image.sum(), torch.tensor(902747049, device=device)) + + @pytest.mark.parametrize( + "value,type_name", [(None, "pyobj"), (123, "int"), ("s", "string")] + ) + def test_call_raises_error_when_input_is_not_memory_block( + self, value: Any, type_name: str + ) -> None: + decoder = ImageDecoder() + + with pytest.raises( + ValueError, + match=rf"^The input data must be of type `memory_block`, but is of type `{type_name}` instead\.$", + ): + decoder(value) + + def test_call_raises_error_when_input_is_empty(self) -> None: + decoder = ImageDecoder() + + empty_block = MemoryBlock() + + with pytest.raises( + ValueError, + match=r"^The input memory block has zero length and cannot be decoded\.$", + ): + decoder(empty_block) + + def test_call_raises_error_when_input_is_invalid(self) -> None: + decoder = ImageDecoder() + + block = MemoryBlock(b"foo") + + with pytest.raises( + ValueError, + match=r"^Unsupported image file. Only jpeg and png are currently supported\.$", + ): + decoder(block) From 9ce518238ea3542507b04c1a3666b0c731ed529b Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 16:36:07 -0700 Subject: [PATCH 75/98] add output keys --- src/fairseq2/data/image.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/fairseq2/data/image.py b/src/fairseq2/data/image.py index 4a5fcd512..2b54032f9 100644 --- a/src/fairseq2/data/image.py +++ b/src/fairseq2/data/image.py @@ -6,6 +6,8 @@ from typing import TYPE_CHECKING, Optional, TypedDict +from torch import Tensor + from fairseq2 import _DOC_MODE from fairseq2.memory import MemoryBlock from fairseq2.typing import Device @@ -34,4 +36,9 @@ def _set_module_name() -> None: class ImageDecoderOutput(TypedDict): - format: int + bit_depth: float + color_type: float + channels: float + height: float + width: float + image: Tensor From 29716529b616f3b36ab6869ef5a8556ad4c1a32e Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 17:09:44 -0700 Subject: [PATCH 76/98] fix lint --- tests/unit/data/image/test_image_decoder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index 2fade5774..a9cb3cf02 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -12,7 +12,6 @@ from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock -from fairseq2.typing import DataType from tests.common import assert_close, device TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") From 7b4ab4e841fd92544bf2b23f560bac161b1fc3c7 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 17:30:59 -0700 Subject: [PATCH 77/98] change uint8 to unsigned char --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 114f057ac..f7b1ebd7d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -165,7 +165,7 @@ image_decoder::decode_jpeg(const memory_block &block) const struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From 5c90727783681aca5586a3d1c9a9fbafacf294d0 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 24 Oct 2023 19:02:56 -0700 Subject: [PATCH 78/98] update workflow configs to install libjpeg v8 --- .github/workflows/_build_wheel-macos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index ddb5e4da9..24abc0585 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,7 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true - brew install libjpeg || true + brew install libjpeg8 || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv From 9f14881ea9601c2274a3b1a15371486eda319778 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 07:01:46 -0700 Subject: [PATCH 79/98] change package name --- .github/workflows/_build_wheel-linux.yaml | 6 ++++++ .github/workflows/_build_wheel-macos.yaml | 2 +- .github/workflows/_lint_py.yaml | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index d4c666710..bca641116 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -165,12 +165,18 @@ jobs: run: | yum --assumeyes install libpng-devel <<<<<<< HEAD +<<<<<<< HEAD >>>>>>> 18f3c8e9 (add png to build configs, support float32 tensor) ======= - name: Install libjpeg-dev run: | yum --assumeyes install libjpeg-devel >>>>>>> 0587a6b7 (jpeg decoder) +======= + - name: Install libjpeg-turbo + run: | + yum --assumeyes install libjpeg-turbo +>>>>>>> e0dcbd24 (change package name) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index 24abc0585..bdc15bf1f 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,7 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true - brew install libjpeg8 || true + brew install jpeg-turbo || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index e2ba5e6ce..a6fed46b5 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -27,6 +27,18 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel + - name: Install libjpeg-turbo + run: | + yum --assumeyes install libjpeg-turbo +>>>>>>> e0dcbd24 (change package name) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From ddbde925e905ef6063105b10b57c0a50ce3c65e5 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 10:08:33 -0700 Subject: [PATCH 80/98] pass non const ptr to libjpeg --- fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index f7b1ebd7d..c5a05be02 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,13 +159,15 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); + auto non_const_ptr = const_cast(reinterpret_cast(data_ptr)); + // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, non_const_ptr, data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From cc34f6177e85ccadf622df7f96fa5adcba237d6f Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 10:16:00 -0700 Subject: [PATCH 81/98] change package name --- .github/workflows/_build_wheel-linux.yaml | 6 ++++++ .github/workflows/_build_wheel-macos.yaml | 2 +- .github/workflows/_lint_py.yaml | 12 ------------ 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index bca641116..958a935a7 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -166,6 +166,7 @@ jobs: yum --assumeyes install libpng-devel <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD >>>>>>> 18f3c8e9 (add png to build configs, support float32 tensor) ======= - name: Install libjpeg-dev @@ -177,6 +178,11 @@ jobs: run: | yum --assumeyes install libjpeg-turbo >>>>>>> e0dcbd24 (change package name) +======= + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-dev +>>>>>>> b31b48e5 (change package name) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index bdc15bf1f..ddb5e4da9 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -39,7 +39,7 @@ jobs: run: | brew install libsndfile python@${{ inputs.py }} || true brew install libpng || true - brew install jpeg-turbo || true + brew install libjpeg || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index a6fed46b5..e2ba5e6ce 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -27,18 +27,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-turbo - run: | - yum --assumeyes install libjpeg-turbo ->>>>>>> e0dcbd24 (change package name) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From 8ae6b3abb4a0b68a01c37174260d08a41b67349e Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 10:26:04 -0700 Subject: [PATCH 82/98] fix typo --- .github/workflows/_build_doc.yaml | 12 ++++++++++++ .github/workflows/_build_wheel-linux.yaml | 16 ++++++++++++++++ .github/workflows/_lint_cc.yaml | 12 ++++++++++++ .github/workflows/_lint_py.yaml | 12 ++++++++++++ .github/workflows/_lint_sh.yaml | 12 ++++++++++++ 5 files changed, 64 insertions(+) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 9bb07d27e..78adbee93 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -30,6 +30,18 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel +>>>>>>> 9be595fe (fix typo) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 958a935a7..e7b8664e2 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -53,6 +53,18 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel +>>>>>>> 9be595fe (fix typo) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -181,8 +193,12 @@ jobs: ======= - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-dev >>>>>>> b31b48e5 (change package name) +======= + yum --assumeyes install libjpeg-devel +>>>>>>> 9be595fe (fix typo) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 6d5b9110f..7d0320280 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -30,6 +30,18 @@ jobs: with: submodules: recursive fetch-depth: 2 +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel +>>>>>>> 9be595fe (fix typo) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index e2ba5e6ce..a24d3f053 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -27,6 +27,18 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel +>>>>>>> 9be595fe (fix typo) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index a6b89fabe..a37978fad 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -24,6 +24,18 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 +<<<<<<< HEAD +======= + - name: Install libsndfile + run: | + yum --assumeyes install libsndfile-devel + - name: Install libpng-dev + run: | + yum --assumeyes install libpng-devel + - name: Install libjpeg-dev + run: | + yum --assumeyes install libjpeg-devel +>>>>>>> 9be595fe (fix typo) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From 41ec5ac3160bc352402177cc2fc36213a87d82fe Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 13:47:12 -0700 Subject: [PATCH 83/98] download libjpeg 1.5 and use const data_ptr --- .github/workflows/_build_doc.yaml | 4 ++++ .github/workflows/_build_wheel-linux.yaml | 8 ++++++++ .github/workflows/_lint_cc.yaml | 4 ++++ .github/workflows/_lint_py.yaml | 4 ++++ .github/workflows/_lint_sh.yaml | 4 ++++ fairseq2n/src/fairseq2n/data/image/image_decoder.cc | 4 +--- 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 78adbee93..64acddb77 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -40,8 +40,12 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) +======= + yum --assumeyes install libjpeg-devel-2.1.2 +>>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index e7b8664e2..3838cc249 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -63,8 +63,12 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) +======= + yum --assumeyes install libjpeg-devel-2.1.2 +>>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -183,6 +187,7 @@ jobs: ======= - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 0587a6b7 (jpeg decoder) ======= @@ -199,6 +204,9 @@ jobs: ======= yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) +======= + yum --assumeyes install libjpeg-devel-2.1.2 +>>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 7d0320280..0d0f34ee5 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -40,8 +40,12 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) +======= + yum --assumeyes install libjpeg-devel-2.1.2 +>>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index a24d3f053..212a42b48 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -37,8 +37,12 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) +======= + yum --assumeyes install libjpeg-devel-2.1.2 +>>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index a37978fad..3795830ab 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -34,8 +34,12 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) +======= + yum --assumeyes install libjpeg-devel-2.1.2 +>>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index c5a05be02..f7b1ebd7d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -159,15 +159,13 @@ image_decoder::decode_jpeg(const memory_block &block) const { auto data_ptr = block.data(); auto data_len = block.size(); - auto non_const_ptr = const_cast(reinterpret_cast(data_ptr)); - // Set up decompression process struct jpeg_decompress_struct cinfo = {}; struct jpeg_error_mgr jerr = {}; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, non_const_ptr, data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From 3c2105da27126f5572c5da4bd30ccb7468042557 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 13:51:11 -0700 Subject: [PATCH 84/98] libjpeg 1.5 --- .github/workflows/_build_doc.yaml | 5 +++++ .github/workflows/_build_wheel-linux.yaml | 12 +++++++++++- .github/workflows/_lint_cc.yaml | 5 +++++ .github/workflows/_lint_py.yaml | 5 +++++ .github/workflows/_lint_sh.yaml | 5 +++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 64acddb77..4766b487e 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -40,12 +40,17 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD <<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) ======= yum --assumeyes install libjpeg-devel-2.1.2 >>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) +======= + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm +>>>>>>> a06b73b1 (libjpeg 1.5) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 3838cc249..7d5ce9d1b 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -63,12 +63,17 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD <<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) ======= yum --assumeyes install libjpeg-devel-2.1.2 >>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) +======= + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm +>>>>>>> a06b73b1 (libjpeg 1.5) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -176,7 +181,7 @@ jobs: ======= - name: Install libsndfile run: | - yum --assumeyes install libsndfile-devel + yum --assumeyes install libsndfile-develPyTorchjpeg - name: Install libpng-dev run: | yum --assumeyes install libpng-devel @@ -187,6 +192,7 @@ jobs: ======= - name: Install libjpeg-dev run: | +<<<<<<< HEAD <<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 0587a6b7 (jpeg decoder) @@ -207,6 +213,10 @@ jobs: ======= yum --assumeyes install libjpeg-devel-2.1.2 >>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) +======= + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm +>>>>>>> a06b73b1 (libjpeg 1.5) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 0d0f34ee5..d26bbbf88 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -40,12 +40,17 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD <<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) ======= yum --assumeyes install libjpeg-devel-2.1.2 >>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) +======= + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm +>>>>>>> a06b73b1 (libjpeg 1.5) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 212a42b48..ad8ea8e8b 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -37,12 +37,17 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD <<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) ======= yum --assumeyes install libjpeg-devel-2.1.2 >>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) +======= + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm +>>>>>>> a06b73b1 (libjpeg 1.5) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 3795830ab..2c1d3cdd8 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -34,12 +34,17 @@ jobs: yum --assumeyes install libpng-devel - name: Install libjpeg-dev run: | +<<<<<<< HEAD <<<<<<< HEAD yum --assumeyes install libjpeg-devel >>>>>>> 9be595fe (fix typo) ======= yum --assumeyes install libjpeg-devel-2.1.2 >>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) +======= + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm + yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm +>>>>>>> a06b73b1 (libjpeg 1.5) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From 40faa0f1868fa8c65fd8c3ebd895e7c4c87913ac Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 14:07:01 -0700 Subject: [PATCH 85/98] fix typo --- .github/workflows/_build_wheel-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 7d5ce9d1b..ded664bd5 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -181,7 +181,7 @@ jobs: ======= - name: Install libsndfile run: | - yum --assumeyes install libsndfile-develPyTorchjpeg + yum --assumeyes install libsndfile-devel - name: Install libpng-dev run: | yum --assumeyes install libpng-devel From 781689b9390c719e72adda4bbf26016813dcea81 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 25 Oct 2023 16:18:28 -0700 Subject: [PATCH 86/98] add init --- tests/unit/data/image/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/unit/data/image/__init__.py diff --git a/tests/unit/data/image/__init__.py b/tests/unit/data/image/__init__.py new file mode 100644 index 000000000..e69de29bb From c8c1c637f468c7e7f98461d0474a9f55957a6312 Mon Sep 17 00:00:00 2001 From: Alisha Date: Thu, 26 Oct 2023 15:57:09 -0700 Subject: [PATCH 87/98] use setjmp/longjmp for error handling --- .../src/fairseq2n/data/image/image_decoder.cc | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index f7b1ebd7d..b945d33c8 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -13,6 +13,7 @@ #include #include +#include #include "fairseq2n/exception.h" #include "fairseq2n/float.h" @@ -54,15 +55,13 @@ image_decoder::operator()(data &&d) const const std::array jpeg_signature = {255, 216, 255}; const std::array png_signature = {137, 80, 78, 71}; - if(memcmp(jpeg_signature.data(), data_ptr, 3) == 0) { - output = decode_jpeg(block); - } else if(memcmp(png_signature.data(), data_ptr, 4) == 0) { - output = decode_png(block); - } else { - throw_( - "Unsupported image file. Only jpeg and png are currently supported."); - } - return output; + if(std::memcmp(jpeg_signature.data(), data_ptr, jpeg_signature.size()) == 0) { + return decode_jpeg(block); + } else if(std::memcmp(png_signature.data(), data_ptr, 4) == 0) { + return decode_png(block); + } + throw_( + "Unsupported image file. Only jpeg and png are currently supported."); } data @@ -80,6 +79,12 @@ image_decoder::decode_png(const memory_block &block) const auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); + // If an error occurs, libpng will longjmp back to setjmp + if (setjmp(png_jmpbuf(png_ptr))) { + // If we get here, libpng has signaled an error + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw_("Internal error."); + } struct Reader { png_const_bytep ptr; @@ -142,7 +147,7 @@ image_decoder::decode_png(const memory_block &block) const if (device != at::kCPU) image = image.to(device); - // Pack png data and format as output. + // Pack png data and format as output data_dict output{ {"bit_depth", static_cast(bit_depth)}, {"color_type", static_cast(color_type)}, {"channels", static_cast(channels)}, {"height", static_cast(height)}, @@ -157,13 +162,33 @@ image_decoder::decode_png(const memory_block &block) const data image_decoder::decode_jpeg(const memory_block &block) const { + struct custom_error_mgr { + struct jpeg_error_mgr pub; // Public fields + jmp_buf setjmp_buffer; // Return to caller + }; + typedef struct custom_error_mgr * error_ptr; + auto data_ptr = block.data(); auto data_len = block.size(); // Set up decompression process struct jpeg_decompress_struct cinfo = {}; - struct jpeg_error_mgr jerr = {}; - cinfo.err = jpeg_std_error(&jerr); + struct custom_error_mgr jerr = {}; + cinfo.err = jpeg_std_error(&jerr.pub); + // error_exit is called by libjpeg when fatal error occurs + jerr.pub.error_exit = [](j_common_ptr cinfo) { + // cinfo->err really points to a custom_error_mgr struct, so coerce pointer + error_ptr myerr = (error_ptr) cinfo->err; + (*cinfo->err->output_message) (cinfo); + // Return control to the setjmp point + longjmp(myerr->setjmp_buffer, 1); + }; + // If an error occurs, error_exit will longjmp back to setjmp + if (setjmp(jerr.setjmp_buffer)) { + // If we get here, libjpeg has signaled an error + jpeg_destroy_decompress(&cinfo); + throw std::runtime_error("JPEG decompression failed"); + } jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); From 98f33e331e20d391f474baef2afe56defb4c3d16 Mon Sep 17 00:00:00 2001 From: Alisha Date: Thu, 26 Oct 2023 20:43:17 -0700 Subject: [PATCH 88/98] new classes for resource management --- .../image/detail/jpeg_decompress_struct.cc | 26 ++++++++++++ .../image/detail/jpeg_decompress_struct.h | 27 ++++++++++++ .../data/image/detail/png_read_struct.cc | 40 ++++++++++++++++++ .../data/image/detail/png_read_struct.h | 28 +++++++++++++ .../src/fairseq2n/data/image/image_decoder.cc | 42 ++++++++----------- 5 files changed, 139 insertions(+), 24 deletions(-) create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc create mode 100644 fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc new file mode 100644 index 000000000..7ca080a41 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc @@ -0,0 +1,26 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates.error_ptr +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/detail/jpeg_decompress_struct.h" + +#include + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n::detail { + +jpeg_decompress::jpeg_decompress() {} + +jpeg_decompress::~jpeg_decompress() { + jpeg_destroy_decompress(&cinfo); +} + +jpeg_decompress_struct& jpeg_decompress::get() { + return cinfo; +} + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h new file mode 100644 index 000000000..03686a7c2 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -0,0 +1,27 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include "fairseq2n/exception.h" + +namespace fairseq2n::detail { + +class jpeg_decompress { +public: + jpeg_decompress(); + ~jpeg_decompress(); + + jpeg_decompress_struct& get(); + +private: + jpeg_decompress_struct cinfo; + jpeg_decompress(const jpeg_decompress&); + jpeg_decompress& operator=(const jpeg_decompress&); +}; + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc new file mode 100644 index 000000000..1f2727a14 --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc @@ -0,0 +1,40 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#include "fairseq2n/data/image/detail/png_read_struct.h" + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n::detail { + +png_read::png_read() : png_ptr(nullptr), info_ptr(nullptr) { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { + throw internal_error("Failed to create PNG read struct."); + } + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == nullptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + throw internal_error("Failed to create PNG info struct."); + } +} + +png_read::~png_read() { + if (png_ptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + } +} + +png_structp png_read::getPngPtr() const { + return png_ptr; +} + +png_infop png_read::getInfoPtr() const { + return info_ptr; +} + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h new file mode 100644 index 000000000..5c7a5f64f --- /dev/null +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -0,0 +1,28 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include + +namespace fairseq2n::detail { + +class png_read{ +public: + png_read(); + ~png_read(); + + png_structp getPngPtr() const; + png_infop getInfoPtr() const; + +private: + png_structp png_ptr; + png_infop info_ptr; + png_read(const png_read&); + png_read& operator=(const png_read&); +}; + +} // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index b945d33c8..8d1d6f232 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -9,17 +9,17 @@ #include #include #include -#include #include #include -#include +#include #include "fairseq2n/exception.h" #include "fairseq2n/float.h" #include "fairseq2n/fmt.h" #include "fairseq2n/memory.h" -#include "fairseq2n/span.h" +#include "fairseq2n/data/image/detail/png_read_struct.h" +#include "fairseq2n/data/image/detail/jpeg_decompress_struct.h" #include "fairseq2n/data/detail/tensor_helpers.h" #include "fairseq2n/detail/exception.h" @@ -67,15 +67,9 @@ image_decoder::operator()(data &&d) const data image_decoder::decode_png(const memory_block &block) const { - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (png_ptr == nullptr) { - throw_("Failed to create PNG read struct."); - } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == nullptr) { - png_destroy_read_struct(&png_ptr, nullptr, nullptr); - throw_("Failed to create PNG info struct."); - } + png_read pngReadStruct; + png_structp png_ptr = pngReadStruct.getPngPtr(); + png_infop info_ptr = pngReadStruct.getInfoPtr(); auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); @@ -162,25 +156,25 @@ image_decoder::decode_png(const memory_block &block) const data image_decoder::decode_jpeg(const memory_block &block) const { + jpeg_decompress jpegDecompressStruct; + jpeg_decompress_struct cinfo = jpegDecompressStruct.get(); + + auto data_ptr = block.data(); + auto data_len = block.size(); + struct custom_error_mgr { struct jpeg_error_mgr pub; // Public fields jmp_buf setjmp_buffer; // Return to caller }; - typedef struct custom_error_mgr * error_ptr; - - auto data_ptr = block.data(); - auto data_len = block.size(); - - // Set up decompression process - struct jpeg_decompress_struct cinfo = {}; struct custom_error_mgr jerr = {}; + typedef struct custom_error_mgr * error_ptr; cinfo.err = jpeg_std_error(&jerr.pub); - // error_exit is called by libjpeg when fatal error occurs + // error_exit is called by libjpeg when a fatal error occurs jerr.pub.error_exit = [](j_common_ptr cinfo) { - // cinfo->err really points to a custom_error_mgr struct, so coerce pointer - error_ptr myerr = (error_ptr) cinfo->err; - (*cinfo->err->output_message) (cinfo); - // Return control to the setjmp point + // Coerce pointer to custom_error_mgr struct + auto myerr = reinterpret_cast(cinfo->err); + (*cinfo->err->output_message)(cinfo); + // Return control to the setjmp point longjmp(myerr->setjmp_buffer, 1); }; // If an error occurs, error_exit will longjmp back to setjmp From fa325d0a2d800bfe44d0a8f8b46196d985f5804e Mon Sep 17 00:00:00 2001 From: Alisha Date: Fri, 27 Oct 2023 06:40:19 -0700 Subject: [PATCH 89/98] include new classes in cmakelists --- fairseq2n/src/fairseq2n/CMakeLists.txt | 2 ++ .../fairseq2n/data/image/detail/jpeg_decompress_struct.cc | 5 ----- .../src/fairseq2n/data/image/detail/jpeg_decompress_struct.h | 3 +++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 30378f731..2b00cc157 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -56,6 +56,8 @@ target_sources(fairseq2n data/detail/file.cc data/detail/file_system.cc data/image/image_decoder.cc + data/image/detail/jpeg_decompress_struct.cc + data/image/detail/png_read_struct.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc index 7ca080a41..7922a466e 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc @@ -6,11 +6,6 @@ #include "fairseq2n/data/image/detail/jpeg_decompress_struct.h" -#include - -#include "fairseq2n/exception.h" -#include "fairseq2n/detail/exception.h" - namespace fairseq2n::detail { jpeg_decompress::jpeg_decompress() {} diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index 03686a7c2..c28f4eee8 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -6,8 +6,11 @@ #pragma once +#include #include + #include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" namespace fairseq2n::detail { From df235cb03f893d7b9fe8a8a19b02f0bc30c0c3de Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 30 Oct 2023 15:34:26 -0700 Subject: [PATCH 90/98] fix include order --- .../src/fairseq2n/data/image/detail/jpeg_decompress_struct.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index c28f4eee8..4f53edf21 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -7,6 +7,8 @@ #pragma once #include +// Forward declaration +typedef struct _IO_FILE FILE; #include #include "fairseq2n/exception.h" From 3c011f7bc1acea1916821cb5105fe0c63d38c8e3 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 30 Oct 2023 18:29:42 -0700 Subject: [PATCH 91/98] fix double free and seg fault --- .../data/image/detail/jpeg_decompress_struct.cc | 8 ++++++-- .../data/image/detail/jpeg_decompress_struct.h | 7 +++---- .../data/image/detail/png_read_struct.cc | 2 +- .../fairseq2n/data/image/detail/png_read_struct.h | 5 ++--- .../src/fairseq2n/data/image/image_decoder.cc | 15 +++++++-------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc index 7922a466e..5d56112b9 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.cc @@ -8,10 +8,14 @@ namespace fairseq2n::detail { -jpeg_decompress::jpeg_decompress() {} +jpeg_decompress::jpeg_decompress() : cinfo() { + jpeg_create_decompress(&cinfo); +} jpeg_decompress::~jpeg_decompress() { - jpeg_destroy_decompress(&cinfo); + if(cinfo.err != nullptr) { + jpeg_destroy_decompress(&cinfo); + } } jpeg_decompress_struct& jpeg_decompress::get() { diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index 4f53edf21..3b433e3a1 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -8,7 +8,7 @@ #include // Forward declaration -typedef struct _IO_FILE FILE; +using FILE = struct _IO_FILE; #include #include "fairseq2n/exception.h" @@ -20,13 +20,12 @@ class jpeg_decompress { public: jpeg_decompress(); ~jpeg_decompress(); - jpeg_decompress_struct& get(); + jpeg_decompress(const jpeg_decompress&) = delete; + jpeg_decompress& operator=(const jpeg_decompress&) = delete; private: jpeg_decompress_struct cinfo; - jpeg_decompress(const jpeg_decompress&); - jpeg_decompress& operator=(const jpeg_decompress&); }; } // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc index 1f2727a14..204249deb 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc @@ -24,7 +24,7 @@ png_read::png_read() : png_ptr(nullptr), info_ptr(nullptr) { } png_read::~png_read() { - if (png_ptr) { + if (png_ptr != nullptr) { png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); } } diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h index 5c7a5f64f..ddfb07f98 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -14,15 +14,14 @@ class png_read{ public: png_read(); ~png_read(); - png_structp getPngPtr() const; png_infop getInfoPtr() const; + png_read(const png_read&) = delete; + png_read& operator=(const png_read&) = delete; private: png_structp png_ptr; png_infop info_ptr; - png_read(const png_read&); - png_read& operator=(const png_read&); }; } // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 8d1d6f232..2706365ec 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -149,7 +149,6 @@ image_decoder::decode_png(const memory_block &block) const output.emplace("image", std::move(image)); - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return output; } @@ -167,7 +166,7 @@ image_decoder::decode_jpeg(const memory_block &block) const jmp_buf setjmp_buffer; // Return to caller }; struct custom_error_mgr jerr = {}; - typedef struct custom_error_mgr * error_ptr; + using error_ptr = struct custom_error_mgr *; cinfo.err = jpeg_std_error(&jerr.pub); // error_exit is called by libjpeg when a fatal error occurs jerr.pub.error_exit = [](j_common_ptr cinfo) { @@ -183,11 +182,12 @@ image_decoder::decode_jpeg(const memory_block &block) const jpeg_destroy_decompress(&cinfo); throw std::runtime_error("JPEG decompression failed"); } - jpeg_create_decompress(&cinfo); + + //jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); - + auto width = cinfo.output_width; auto height = cinfo.output_height; auto channels = cinfo.output_components; @@ -205,19 +205,18 @@ image_decoder::decode_jpeg(const memory_block &block) const image_data += row_size; } jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); - + // Pack jpeg data and format as output. data_dict output{ {{"channels", static_cast(channels)}, {"height", static_cast(height)}, {"width", static_cast(width)}, {"bit_depth", static_cast(bit_depth)}}}; - + output.emplace("image", std::move(image)); - + return output; } }; // namespace fairseq2n From 3d88336f9d6617dc22dab53a1253c1eae696f618 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 31 Oct 2023 15:45:02 -0700 Subject: [PATCH 92/98] unit test for corrupted images --- .../src/fairseq2n/data/image/image_decoder.cc | 9 ++---- tests/unit/data/image/test_corrupt.jpg | Bin 0 -> 87571 bytes tests/unit/data/image/test_corrupt.png | Bin 0 -> 73036 bytes tests/unit/data/image/test_image_decoder.py | 28 +++++++++++++++++- 4 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 tests/unit/data/image/test_corrupt.jpg create mode 100644 tests/unit/data/image/test_corrupt.png diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 2706365ec..31052da57 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -75,9 +75,7 @@ image_decoder::decode_png(const memory_block &block) const auto data_len = block.size(); // If an error occurs, libpng will longjmp back to setjmp if (setjmp(png_jmpbuf(png_ptr))) { - // If we get here, libpng has signaled an error - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - throw_("Internal error."); + throw_("libpng internal error."); } struct Reader { @@ -115,7 +113,6 @@ image_decoder::decode_png(const memory_block &block) const nullptr); if (retval != 1) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); throw_("Could not read image metadata from content."); } @@ -178,9 +175,7 @@ image_decoder::decode_jpeg(const memory_block &block) const }; // If an error occurs, error_exit will longjmp back to setjmp if (setjmp(jerr.setjmp_buffer)) { - // If we get here, libjpeg has signaled an error - jpeg_destroy_decompress(&cinfo); - throw std::runtime_error("JPEG decompression failed"); + throw_("JPEG decompression failed."); } //jpeg_create_decompress(&cinfo); diff --git a/tests/unit/data/image/test_corrupt.jpg b/tests/unit/data/image/test_corrupt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2970c55dc97837211811cef5c0e37ecf6d687281 GIT binary patch literal 87571 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 Q%YFeQmL=`{9e)h`7k+)A0{{R3 literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test_corrupt.png b/tests/unit/data/image/test_corrupt.png new file mode 100644 index 0000000000000000000000000000000000000000..5350683e9c8e8f96c443e19a169b04f8aa5a19ce GIT binary patch literal 73036 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 GrT+qv7<%&n literal 0 HcmV?d00001 diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index a9cb3cf02..8f8100cd9 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -9,6 +9,7 @@ import pytest import torch +import warnings from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock @@ -16,7 +17,8 @@ TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") TEST_JPG_PATH: Final = Path(__file__).parent.joinpath("test.jpg") - +TEST_CORRUPT_JPG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.jpg") +TEST_CORRUPT_PNG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.png") class TestImageDecoder: def test_init(self) -> None: @@ -77,6 +79,30 @@ def test_call_works_on_jpg(self) -> None: assert_close(image.sum(), torch.tensor(902747049, device=device)) + def test_corrupted_png(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_CORRUPT_PNG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + with pytest.raises( + RuntimeError, + match="libpng internal error.", + ): + decoder(block) + + def test_corrupted_jpg(self) -> None: + decoder = ImageDecoder(device=device) + + with TEST_CORRUPT_JPG_PATH.open("rb") as fb: + block = MemoryBlock(fb.read()) + + with pytest.raises( + RuntimeError, + match="JPEG decompression failed.", + ): + decoder(block) + @pytest.mark.parametrize( "value,type_name", [(None, "pyobj"), (123, "int"), ("s", "string")] ) From 715a59b1c9a292379df009a1b379e0e2e15e2e8f Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 31 Oct 2023 15:53:15 -0700 Subject: [PATCH 93/98] more descriptive test name --- tests/unit/data/image/test_image_decoder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index 8f8100cd9..e5efed62b 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -79,7 +79,7 @@ def test_call_works_on_jpg(self) -> None: assert_close(image.sum(), torch.tensor(902747049, device=device)) - def test_corrupted_png(self) -> None: + def test_call_raises_error_when_input_is_corrupted_png(self) -> None: decoder = ImageDecoder(device=device) with TEST_CORRUPT_PNG_PATH.open("rb") as fb: @@ -91,7 +91,7 @@ def test_corrupted_png(self) -> None: ): decoder(block) - def test_corrupted_jpg(self) -> None: + def test_call_raises_error_when_input_is_corrupted_jpg(self) -> None: decoder = ImageDecoder(device=device) with TEST_CORRUPT_JPG_PATH.open("rb") as fb: From a435ac6bcd708d46de115e9db0fd3c903af34dd6 Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 31 Oct 2023 16:01:36 -0700 Subject: [PATCH 94/98] fix lint --- tests/unit/data/image/test_image_decoder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index e5efed62b..f83f79a20 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -9,7 +9,6 @@ import pytest import torch -import warnings from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock @@ -20,6 +19,7 @@ TEST_CORRUPT_JPG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.jpg") TEST_CORRUPT_PNG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.png") + class TestImageDecoder: def test_init(self) -> None: decoder = ImageDecoder() @@ -79,7 +79,7 @@ def test_call_works_on_jpg(self) -> None: assert_close(image.sum(), torch.tensor(902747049, device=device)) - def test_call_raises_error_when_input_is_corrupted_png(self) -> None: + def test_call_raises_error_when_input_is_corrupted_png(self) -> None: decoder = ImageDecoder(device=device) with TEST_CORRUPT_PNG_PATH.open("rb") as fb: From d14936da58eb7722e1498974e5bf97609082f179 Mon Sep 17 00:00:00 2001 From: Alisha Date: Mon, 13 Nov 2023 10:17:03 -0800 Subject: [PATCH 95/98] fix lint --- .github/workflows/_build_doc.yaml | 3 +++ .github/workflows/_build_wheel-linux.yaml | 6 ++++++ .github/workflows/_lint_cc.yaml | 3 +++ .github/workflows/_lint_py.yaml | 3 +++ .github/workflows/_lint_sh.yaml | 3 +++ 5 files changed, 18 insertions(+) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 4766b487e..88e5de0b5 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -31,6 +31,7 @@ jobs: - name: Check-out the repository uses: actions/checkout@v3 <<<<<<< HEAD +<<<<<<< HEAD ======= - name: Install libsndfile run: | @@ -51,6 +52,8 @@ jobs: yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm >>>>>>> a06b73b1 (libjpeg 1.5) +======= +>>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index ded664bd5..a74a4bece 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -54,6 +54,7 @@ jobs: with: submodules: recursive <<<<<<< HEAD +<<<<<<< HEAD ======= - name: Install libsndfile run: | @@ -74,6 +75,8 @@ jobs: yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm >>>>>>> a06b73b1 (libjpeg 1.5) +======= +>>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv @@ -178,6 +181,7 @@ jobs: shell: bash steps: <<<<<<< HEAD +<<<<<<< HEAD ======= - name: Install libsndfile run: | @@ -217,6 +221,8 @@ jobs: yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm >>>>>>> a06b73b1 (libjpeg 1.5) +======= +>>>>>>> 7a2c1170 (fix lint) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index d26bbbf88..345eec889 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -31,6 +31,7 @@ jobs: submodules: recursive fetch-depth: 2 <<<<<<< HEAD +<<<<<<< HEAD ======= - name: Install libsndfile run: | @@ -51,6 +52,8 @@ jobs: yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm >>>>>>> a06b73b1 (libjpeg 1.5) +======= +>>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index ad8ea8e8b..1fdd21251 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -28,6 +28,7 @@ jobs: - name: Check-out the repository uses: actions/checkout@v3 <<<<<<< HEAD +<<<<<<< HEAD ======= - name: Install libsndfile run: | @@ -48,6 +49,8 @@ jobs: yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm >>>>>>> a06b73b1 (libjpeg 1.5) +======= +>>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index 2c1d3cdd8..a49c9afdc 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -25,6 +25,7 @@ jobs: - name: Check-out the repository uses: actions/checkout@v3 <<<<<<< HEAD +<<<<<<< HEAD ======= - name: Install libsndfile run: | @@ -45,6 +46,8 @@ jobs: yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm >>>>>>> a06b73b1 (libjpeg 1.5) +======= +>>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv From ca2ac55896d5def8e50d5c40c45e9a65bb53433a Mon Sep 17 00:00:00 2001 From: Alisha Date: Tue, 5 Dec 2023 14:43:26 -0800 Subject: [PATCH 96/98] clang tidy --- .github/workflows/_build_doc.yaml | 24 ------------------- .github/workflows/_build_wheel-linux.yaml | 24 ------------------- .github/workflows/_lint_cc.yaml | 24 ------------------- .github/workflows/_lint_py.yaml | 24 ------------------- .github/workflows/_lint_sh.yaml | 24 ------------------- .../data/image/detail/png_read_struct.h | 4 ++-- 6 files changed, 2 insertions(+), 122 deletions(-) diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index 88e5de0b5..9bb07d27e 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -30,30 +30,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 -<<<<<<< HEAD -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD -<<<<<<< HEAD - yum --assumeyes install libjpeg-devel ->>>>>>> 9be595fe (fix typo) -======= - yum --assumeyes install libjpeg-devel-2.1.2 ->>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) -======= - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm ->>>>>>> a06b73b1 (libjpeg 1.5) -======= ->>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index a74a4bece..3fd2f0e89 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -53,30 +53,6 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive -<<<<<<< HEAD -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD -<<<<<<< HEAD - yum --assumeyes install libjpeg-devel ->>>>>>> 9be595fe (fix typo) -======= - yum --assumeyes install libjpeg-devel-2.1.2 ->>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) -======= - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm ->>>>>>> a06b73b1 (libjpeg 1.5) -======= ->>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_cc.yaml b/.github/workflows/_lint_cc.yaml index 345eec889..6d5b9110f 100644 --- a/.github/workflows/_lint_cc.yaml +++ b/.github/workflows/_lint_cc.yaml @@ -30,30 +30,6 @@ jobs: with: submodules: recursive fetch-depth: 2 -<<<<<<< HEAD -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD -<<<<<<< HEAD - yum --assumeyes install libjpeg-devel ->>>>>>> 9be595fe (fix typo) -======= - yum --assumeyes install libjpeg-devel-2.1.2 ->>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) -======= - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm ->>>>>>> a06b73b1 (libjpeg 1.5) -======= ->>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_py.yaml b/.github/workflows/_lint_py.yaml index 1fdd21251..e2ba5e6ce 100644 --- a/.github/workflows/_lint_py.yaml +++ b/.github/workflows/_lint_py.yaml @@ -27,30 +27,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 -<<<<<<< HEAD -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD -<<<<<<< HEAD - yum --assumeyes install libjpeg-devel ->>>>>>> 9be595fe (fix typo) -======= - yum --assumeyes install libjpeg-devel-2.1.2 ->>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) -======= - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm ->>>>>>> a06b73b1 (libjpeg 1.5) -======= ->>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/.github/workflows/_lint_sh.yaml b/.github/workflows/_lint_sh.yaml index a49c9afdc..a6b89fabe 100644 --- a/.github/workflows/_lint_sh.yaml +++ b/.github/workflows/_lint_sh.yaml @@ -24,30 +24,6 @@ jobs: steps: - name: Check-out the repository uses: actions/checkout@v3 -<<<<<<< HEAD -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD -<<<<<<< HEAD - yum --assumeyes install libjpeg-devel ->>>>>>> 9be595fe (fix typo) -======= - yum --assumeyes install libjpeg-devel-2.1.2 ->>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) -======= - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm ->>>>>>> a06b73b1 (libjpeg 1.5) -======= ->>>>>>> 7a2c1170 (fix lint) - name: Create the Python virtual environment run: | python${{ inputs.py }} -m venv ~/venv diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h index ddfb07f98..941b3a13c 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -20,8 +20,8 @@ class png_read{ png_read& operator=(const png_read&) = delete; private: - png_structp png_ptr; - png_infop info_ptr; + png_structp png_ptr{nullptr}; + png_infop info_ptr{nullptr}; }; } // namespace fairseq2n::detail From 14aa70a279ef36eabce715d5c33101392a3152b6 Mon Sep 17 00:00:00 2001 From: Can Balioglu Date: Wed, 6 Dec 2023 11:26:14 -0800 Subject: [PATCH 97/98] Update CMake --- .github/workflows/_build_wheel-linux.yaml | 43 --------- .github/workflows/_build_wheel-macos.yaml | 8 +- INSTALL_FROM_SOURCE.md | 13 +-- README.md | 20 +++-- fairseq2n/CMakeLists.txt | 13 +++ fairseq2n/cmake/summary.cmake | 5 ++ fairseq2n/python/src/fairseq2n/__init__.py | 7 ++ .../src/fairseq2n/bindings/CMakeLists.txt | 2 +- .../python/src/fairseq2n/bindings/init.cc | 7 ++ fairseq2n/src/fairseq2n/CMakeLists.txt | 40 ++++++--- fairseq2n/src/fairseq2n/config.h.in | 6 +- .../image/detail/jpeg_decompress_struct.h | 3 +- .../data/image/detail/png_read_struct.cc | 2 +- .../data/image/detail/png_read_struct.h | 4 +- .../src/fairseq2n/data/image/image_decoder.cc | 90 +++++++++++++------ .../src/fairseq2n/data/image/image_decoder.h | 5 +- tests/unit/data/image/test_image_decoder.py | 4 + 17 files changed, 159 insertions(+), 113 deletions(-) diff --git a/.github/workflows/_build_wheel-linux.yaml b/.github/workflows/_build_wheel-linux.yaml index 3fd2f0e89..b5aea3cc8 100644 --- a/.github/workflows/_build_wheel-linux.yaml +++ b/.github/workflows/_build_wheel-linux.yaml @@ -156,49 +156,6 @@ jobs: run: shell: bash steps: -<<<<<<< HEAD -<<<<<<< HEAD -======= - - name: Install libsndfile - run: | - yum --assumeyes install libsndfile-devel - - name: Install libpng-dev - run: | - yum --assumeyes install libpng-devel -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD ->>>>>>> 18f3c8e9 (add png to build configs, support float32 tensor) -======= - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD -<<<<<<< HEAD - yum --assumeyes install libjpeg-devel ->>>>>>> 0587a6b7 (jpeg decoder) -======= - - name: Install libjpeg-turbo - run: | - yum --assumeyes install libjpeg-turbo ->>>>>>> e0dcbd24 (change package name) -======= - - name: Install libjpeg-dev - run: | -<<<<<<< HEAD - yum --assumeyes install libjpeg-dev ->>>>>>> b31b48e5 (change package name) -======= - yum --assumeyes install libjpeg-devel ->>>>>>> 9be595fe (fix typo) -======= - yum --assumeyes install libjpeg-devel-2.1.2 ->>>>>>> 9caad8cc (download libjpeg 1.5 and use const data_ptr) -======= - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-1.5.3-12.el8.x86_64.rpm - yum --assumeyes install https://rpmfind.net/linux/centos/8-stream/AppStream/x86_64/os/Packages/libjpeg-turbo-devel-1.5.3-12.el8.x86_64.rpm ->>>>>>> a06b73b1 (libjpeg 1.5) -======= ->>>>>>> 7a2c1170 (fix lint) - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/_build_wheel-macos.yaml b/.github/workflows/_build_wheel-macos.yaml index ddb5e4da9..c79f79a26 100644 --- a/.github/workflows/_build_wheel-macos.yaml +++ b/.github/workflows/_build_wheel-macos.yaml @@ -37,9 +37,7 @@ jobs: HOMEBREW_NO_INSTALL_UPGRADE: 1 HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | - brew install libsndfile python@${{ inputs.py }} || true - brew install libpng || true - brew install libjpeg || true + brew install libjpeg libpng libsndfile python@${{ inputs.py }} || true - name: Create the Python virtual environment run: | /usr/local/bin/python${{ inputs.py }} -m venv ~/venv @@ -102,9 +100,7 @@ jobs: HOMEBREW_NO_INSTALL_UPGRADE: 1 HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | - brew install libsndfile python@${{ inputs.py }} || true - brew install libpng || true - brew install libjpeg || true + brew install libjpeg libpng libsndfile python@${{ inputs.py }} || true - name: Download wheels and native tests from staging uses: actions/download-artifact@v3 with: diff --git a/INSTALL_FROM_SOURCE.md b/INSTALL_FROM_SOURCE.md index 40672b237..887f6f75d 100644 --- a/INSTALL_FROM_SOURCE.md +++ b/INSTALL_FROM_SOURCE.md @@ -53,21 +53,22 @@ reusing an existing one to avoid dependency conflicts. ## 3. Install Dependencies ### 3.1 System Dependencies -fairseq2 has a dependency on -[libsndfile](https://github.com/libsndfile/libsndfile) that can be installed via -the system package manager on most Linux distributions, or via Homebrew on +fairseq2 depends on [libjpeg](https://libjpeg.sourceforge.net), +[libpng](http://www.libpng.org/pub/png/libpng.html), and +[libsndfile](https://github.com/libsndfile/libsndfile), which can be installed +via the system package manager on most Linux distributions, or via Homebrew on macOS. For Ubuntu-based systems, run: ```sh -sudo apt install libsndfile-dev +sudo apt install libjpeg8-dev libpng-dev libsndfile-dev ``` Similarly, on Fedora, run: ```sh -sudo dnf install libsndfile-devel +sudo dnf install libjpeg-devel libpng-devel libsndfile-devel ``` For other Linux distributions, please consult its documentation on how to @@ -76,7 +77,7 @@ install packages. For macOS, you can use Homebrew: ```sh -brew install libsndfile +brew install libjpeb libpng libsndfile ``` ### 3.2 PyTorch diff --git a/README.md b/README.md index 97c982fe7..ee5271b90 100644 --- a/README.md +++ b/README.md @@ -59,19 +59,20 @@ fairseq2 is also used by various external projects such as: ## Installing on Linux ### System Dependencies -fairseq2 has a dependency on -[libsndfile](https://github.com/libsndfile/libsndfile) that can be installed via -the system package manager on most Linux distributions. For Ubuntu-based +fairseq2 depends on [libjpeg](https://libjpeg.sourceforge.net), +[libpng](http://www.libpng.org/pub/png/libpng.html), and +[libsndfile](https://github.com/libsndfile/libsndfile), which can be installed +via the system package manager on most Linux distributions. For Ubuntu-based systems, run: ```sh -sudo apt install libsndfile1 +sudo apt install libjpeg8 libpng16-16 libsndfile1 ``` Similarly, on Fedora, run: ```sh -sudo dnf install libsndfile +sudo dnf install libjpeg libpng libsndfile ``` For other Linux distributions, please consult its documentation on how to @@ -139,12 +140,13 @@ pip install fairseq2\ ## Installing on macOS ### System Dependencies -fairseq2 has a dependency on -[libsndfile](https://github.com/libsndfile/libsndfile) that can be installed via -Homebrew: +fairseq2 depends on [libjpeg](https://libjpeg.sourceforge.net), +[libpng](http://www.libpng.org/pub/png/libpng.html), and +[libsndfile](https://github.com/libsndfile/libsndfile), which can be installed +via Homebrew: ```sh -brew install libsndfile +brew install libjpeg libpng libsndfile ``` ### pip diff --git a/fairseq2n/CMakeLists.txt b/fairseq2n/CMakeLists.txt index b351d11ee..e7e9eef62 100644 --- a/fairseq2n/CMakeLists.txt +++ b/fairseq2n/CMakeLists.txt @@ -87,6 +87,13 @@ option(FAIRSEQ2N_TREAT_WARNINGS_AS_ERRORS OFF ) +option(FAIRSEQ2N_SUPPORT_IMAGE + #DESCRIPTION + "Supports JPEG/PNG decoding." + #VALUE + ON +) + option(FAIRSEQ2N_USE_LIBTORCH #DESCRIPTION "Uses libtorch instead of PyTorch." @@ -160,6 +167,12 @@ find_package(SndFile 1.0.25 REQUIRED) find_package(Threads REQUIRED) +if(FAIRSEQ2N_SUPPORT_IMAGE) + find_package(JPEG REQUIRED) + + find_package(PNG REQUIRED) +endif() + if(FAIRSEQ2N_THREAD_LIB STREQUAL "tbb") find_package(TBB 2021.8 REQUIRED) endif() diff --git a/fairseq2n/cmake/summary.cmake b/fairseq2n/cmake/summary.cmake index 61ea927ff..f394b255d 100644 --- a/fairseq2n/cmake/summary.cmake +++ b/fairseq2n/cmake/summary.cmake @@ -34,6 +34,7 @@ function(fairseq2n_print_project_summary) message(STATUS " FAIRSEQ2N_SANITIZERS : ${FAIRSEQ2N_SANITIZERS}") endif() message(STATUS " FAIRSEQ2N_TREAT_WARNINGS_AS_ERRORS : ${FAIRSEQ2N_TREAT_WARNINGS_AS_ERRORS}") + message(STATUS " FAIRSEQ2N_SUPPORT_IMAGE : ${FAIRSEQ2N_SUPPORT_IMAGE}") message(STATUS " FAIRSEQ2N_USE_LIBTORCH : ${FAIRSEQ2N_USE_LIBTORCH}") message(STATUS " FAIRSEQ2N_USE_CUDA : ${FAIRSEQ2N_USE_CUDA}") if(FAIRSEQ2N_USE_CUDA) @@ -50,6 +51,10 @@ function(fairseq2n_print_project_summary) if(FAIRSEQ2N_THREAD_LIB STREQUAL "tbb") message(STATUS " Intel oneTBB : ${TBB_VERSION}") endif() + if(FAIRSEQ2N_SUPPORT_IMAGE) + message(STATUS " libjpeg : ${JPEG_VERSION}") + message(STATUS " libpng : ${PNG_VERSION_STRING}") + endif() message(STATUS " libsndfile : ${SndFile_VERSION}") message(STATUS "") endfunction() diff --git a/fairseq2n/python/src/fairseq2n/__init__.py b/fairseq2n/python/src/fairseq2n/__init__.py index 820884bdd..26394a664 100644 --- a/fairseq2n/python/src/fairseq2n/__init__.py +++ b/fairseq2n/python/src/fairseq2n/__init__.py @@ -132,6 +132,13 @@ def supports_cuda() -> bool: return _supports_cuda() # type: ignore[no-any-return] +def supports_image() -> bool: + """Return ``True`` if fairseq2n supports JPEG/PNG decoding.""" + from fairseq2n.bindings import _supports_image # type: ignore[attr-defined] + + return _supports_image() # type: ignore[no-any-return] + + def cuda_version() -> Optional[Tuple[int, int]]: """Return the version of CUDA that fairseq2n supports. diff --git a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt index f9806c7d4..5db36c0ff 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt +++ b/fairseq2n/python/src/fairseq2n/bindings/CMakeLists.txt @@ -17,9 +17,9 @@ target_sources(py_bindings init.cc memory.cc data/audio.cc - data/image.cc data/data_pipeline.cc data/init.cc + data/image.cc data/string.cc data/text/converters.cc data/text/init.cc diff --git a/fairseq2n/python/src/fairseq2n/bindings/init.cc b/fairseq2n/python/src/fairseq2n/bindings/init.cc index dea93b382..983a1bbe0 100644 --- a/fairseq2n/python/src/fairseq2n/bindings/init.cc +++ b/fairseq2n/python/src/fairseq2n/bindings/init.cc @@ -24,6 +24,13 @@ PYBIND11_MODULE(bindings, m) return supports_cuda; }); + m.def( + "_supports_image", + [] + { + return supports_image; + }); + // See https://github.com/llvm/llvm-project/issues/57123. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code-return" diff --git a/fairseq2n/src/fairseq2n/CMakeLists.txt b/fairseq2n/src/fairseq2n/CMakeLists.txt index 2b00cc157..5bf84f18d 100644 --- a/fairseq2n/src/fairseq2n/CMakeLists.txt +++ b/fairseq2n/src/fairseq2n/CMakeLists.txt @@ -56,8 +56,6 @@ target_sources(fairseq2n data/detail/file.cc data/detail/file_system.cc data/image/image_decoder.cc - data/image/detail/jpeg_decompress_struct.cc - data/image/detail/png_read_struct.cc data/text/string_splitter.cc data/text/string_to_int_converter.cc data/text/string_to_tensor_converter.cc @@ -72,6 +70,14 @@ target_sources(fairseq2n data/text/sentencepiece/sp_processor.cc ) +if(FAIRSEQ2N_SUPPORT_IMAGE) + target_sources(fairseq2n + PRIVATE + data/image/detail/jpeg_decompress_struct.cc + data/image/detail/png_read_struct.cc + ) +endif() + if(FAIRSEQ2N_USE_CUDA) target_sources(fairseq2n PRIVATE @@ -83,8 +89,8 @@ fairseq2n_set_compile_options(fairseq2n) target_compile_features(fairseq2n PUBLIC cxx_std_17) -if(FAIRSEQ2N_THREAD_LIB STREQUAL "tbb") - target_compile_definitions(fairseq2n PRIVATE FAIRSEQ2N_USE_TBB) +if(FAIRSEQ2N_SUPPORT_IMAGE) + target_compile_definitions(fairseq2n PRIVATE FAIRSEQ2N_SUPPORT_IMAGE) endif() if(FAIRSEQ2N_USE_CUDA) @@ -93,6 +99,10 @@ if(FAIRSEQ2N_USE_CUDA) target_compile_definitions(fairseq2n PRIVATE FAIRSEQ2N_USE_CUDA) endif() +if(FAIRSEQ2N_THREAD_LIB STREQUAL "tbb") + target_compile_definitions(fairseq2n PRIVATE FAIRSEQ2N_USE_TBB) +endif() + if(PROJECT_IS_TOP_LEVEL) set(system) else() @@ -105,9 +115,6 @@ target_include_directories(fairseq2n ${system} $ ) -find_package(PNG REQUIRED) -find_package(JPEG REQUIRED) - target_link_libraries(fairseq2n PRIVATE ${CMAKE_DL_LIBS} @@ -120,20 +127,21 @@ target_link_libraries(fairseq2n Threads::Threads sentencepiece-static SndFile::sndfile - PNG::PNG - JPEG::JPEG PUBLIC torch ) -if(FAIRSEQ2N_THREAD_LIB STREQUAL "tbb") - target_link_libraries(fairseq2n PRIVATE TBB::tbb) +if(FAIRSEQ2N_SUPPORT_IMAGE) + target_link_libraries(fairseq2n PRIVATE JPEG::JPEG PNG::PNG) endif() if(FAIRSEQ2N_USE_CUDA) target_link_libraries(fairseq2n PRIVATE CUDA::cudart) endif() +if(FAIRSEQ2N_THREAD_LIB STREQUAL "tbb") + target_link_libraries(fairseq2n PRIVATE TBB::tbb) +endif() fairseq2n_set_link_options(fairseq2n) @@ -182,10 +190,20 @@ install( # Library Configuration # ------------------------------------------------------------ +if(FAIRSEQ2N_SUPPORT_IMAGE) + set(SUPPORTS_IMAGE "true") +else() + set(SUPPORTS_IMAGE "false") +endif() + if(FAIRSEQ2N_USE_CUDA) + set(USES_CUDA "true") + set(CUDA_VERSION_MAJOR "${CUDAToolkit_VERSION_MAJOR}") set(CUDA_VERSION_MINOR "${CUDAToolkit_VERSION_MINOR}") else() + set(USES_CUDA "false") + set(CUDA_VERSION_MAJOR "std::nullopt") set(CUDA_VERSION_MINOR "std::nullopt") endif() diff --git a/fairseq2n/src/fairseq2n/config.h.in b/fairseq2n/src/fairseq2n/config.h.in index 06fd2cdd3..276bb8901 100644 --- a/fairseq2n/src/fairseq2n/config.h.in +++ b/fairseq2n/src/fairseq2n/config.h.in @@ -15,9 +15,11 @@ constexpr std::int32_t version_major = @PROJECT_VERSION_MAJOR@; constexpr std::int32_t version_minor = @PROJECT_VERSION_MINOR@; constexpr std::int32_t version_patch = @PROJECT_VERSION_PATCH@; +constexpr bool supports_image = @SUPPORTS_IMAGE@; + +constexpr bool supports_cuda = @USES_CUDA@; + constexpr std::optional cuda_version_major = @CUDA_VERSION_MAJOR@; constexpr std::optional cuda_version_minor = @CUDA_VERSION_MINOR@; -constexpr bool supports_cuda = cuda_version_major.has_value(); - } // namespace fairseq2n diff --git a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h index 3b433e3a1..1cdcddeb5 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/jpeg_decompress_struct.h @@ -7,8 +7,9 @@ #pragma once #include +#include // Forward declaration -using FILE = struct _IO_FILE; +//using FILE = struct _IO_FILE; #include #include "fairseq2n/exception.h" diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc index 204249deb..29e40e38e 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.cc @@ -11,7 +11,7 @@ namespace fairseq2n::detail { -png_read::png_read() : png_ptr(nullptr), info_ptr(nullptr) { +png_read::png_read() { png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { throw internal_error("Failed to create PNG read struct."); diff --git a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h index 941b3a13c..3fdf2ad26 100644 --- a/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h +++ b/fairseq2n/src/fairseq2n/data/image/detail/png_read_struct.h @@ -20,8 +20,8 @@ class png_read{ png_read& operator=(const png_read&) = delete; private: - png_structp png_ptr{nullptr}; - png_infop info_ptr{nullptr}; + png_structp png_ptr{}; + png_infop info_ptr{}; }; } // namespace fairseq2n::detail diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc index 31052da57..d2d9dd7cb 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.cc +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.cc @@ -6,6 +6,7 @@ #include "fairseq2n/data/image/image_decoder.h" +#ifdef FAIRSEQ2N_SUPPORT_IMAGE #include #include #include @@ -13,6 +14,8 @@ #include #include #include +#include +#include #include "fairseq2n/exception.h" #include "fairseq2n/float.h" @@ -26,12 +29,12 @@ using namespace fairseq2n::detail; namespace fairseq2n { - + image_decoder::image_decoder(image_decoder_options opts) : opts_{opts} {} -bool +bool image_decoder::is_little_endian() { uint32_t x = 1; return (*reinterpret_cast(&x) == 1); @@ -43,55 +46,59 @@ image_decoder::operator()(data &&d) const if (!d.is_memory_block()) throw_( "The input data must be of type `memory_block`, but is of type `{}` instead.", d.type()); - + const memory_block &block = d.as_memory_block(); if (block.empty()) throw_( "The input memory block has zero length and cannot be decoded."); auto data_ptr = block.data(); - data output; - + + data output{}; + const std::array jpeg_signature = {255, 216, 255}; const std::array png_signature = {137, 80, 78, 71}; - if(std::memcmp(jpeg_signature.data(), data_ptr, jpeg_signature.size()) == 0) { + if(std::memcmp(jpeg_signature.data(), data_ptr, jpeg_signature.size()) == 0) return decode_jpeg(block); - } else if(std::memcmp(png_signature.data(), data_ptr, 4) == 0) { + + if(std::memcmp(png_signature.data(), data_ptr, png_signature.size()) == 0) return decode_png(block); - } + throw_( "Unsupported image file. Only jpeg and png are currently supported."); } data -image_decoder::decode_png(const memory_block &block) const +image_decoder::decode_png(const memory_block &block) const { - png_read pngReadStruct; + png_read pngReadStruct; png_structp png_ptr = pngReadStruct.getPngPtr(); png_infop info_ptr = pngReadStruct.getInfoPtr(); auto data_ptr = png_const_bytep(block.data()); auto data_len = block.size(); // If an error occurs, libpng will longjmp back to setjmp + // NOLINTNEXTLINE(cert-err52-cpp) if (setjmp(png_jmpbuf(png_ptr))) { throw_("libpng internal error."); } struct Reader { - png_const_bytep ptr; - png_size_t count; - Reader(png_const_bytep p, png_size_t c) : ptr(p), count(c) {} + png_const_bytep ptr; + png_size_t count; + Reader(png_const_bytep p, png_size_t c) : ptr(p), count(c) {} }; + Reader reader(data_ptr + 8, data_len - 8); - + auto read_callback = [](png_structp png_ptr2, png_bytep output, png_size_t bytes) { - auto reader = static_cast(png_get_io_ptr(png_ptr2)); - std::copy(reader->ptr, reader->ptr + bytes, output); - reader->ptr += bytes; - reader->count -= bytes; + auto reader = static_cast(png_get_io_ptr(png_ptr2)); + std::copy(reader->ptr, reader->ptr + bytes, output); + reader->ptr += bytes; + reader->count -= bytes; }; png_set_sig_bytes(png_ptr, 8); @@ -123,11 +130,11 @@ image_decoder::decode_png(const memory_block &block) const at::ScalarType dtype = bit_depth <= 8 ? at::kByte : at::kShort; at::Tensor image = at::empty({height, width, channels}, at::dtype(dtype).device(at::kCPU).pinned_memory(opts_.pin_memory())); - + size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); writable_memory_span image_bits = get_raw_mutable_storage(image); auto image_data = reinterpret_cast(image_bits.data()); - + // Read image data into tensor for (png_uint_32 i = 0; i < height; ++i) { png_read_row(png_ptr, image_data, nullptr); @@ -145,7 +152,7 @@ image_decoder::decode_png(const memory_block &block) const {"width", static_cast(width)}}; output.emplace("image", std::move(image)); - + return output; } @@ -157,7 +164,7 @@ image_decoder::decode_jpeg(const memory_block &block) const auto data_ptr = block.data(); auto data_len = block.size(); - + struct custom_error_mgr { struct jpeg_error_mgr pub; // Public fields jmp_buf setjmp_buffer; // Return to caller @@ -171,18 +178,22 @@ image_decoder::decode_jpeg(const memory_block &block) const auto myerr = reinterpret_cast(cinfo->err); (*cinfo->err->output_message)(cinfo); // Return control to the setjmp point + // NOLINTNEXTLINE(cert-err52-cpp) longjmp(myerr->setjmp_buffer, 1); }; // If an error occurs, error_exit will longjmp back to setjmp + // NOLINTNEXTLINE(cert-err52-cpp) if (setjmp(jerr.setjmp_buffer)) { throw_("JPEG decompression failed."); } - + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + auto mutable_data_ptr = const_cast(data_ptr); //jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, reinterpret_cast(data_ptr), data_len); + jpeg_mem_src(&cinfo, reinterpret_cast(mutable_data_ptr), data_len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); - + auto width = cinfo.output_width; auto height = cinfo.output_height; auto channels = cinfo.output_components; @@ -204,14 +215,37 @@ image_decoder::decode_jpeg(const memory_block &block) const at::Device device = opts_.maybe_device().value_or(at::kCPU); if (device != at::kCPU) image = image.to(device); - + // Pack jpeg data and format as output. data_dict output{ {{"channels", static_cast(channels)}, {"height", static_cast(height)}, {"width", static_cast(width)}, {"bit_depth", static_cast(bit_depth)}}}; - + output.emplace("image", std::move(image)); - + return output; } + }; // namespace fairseq2n + +#else + +#include "fairseq2n/exception.h" +#include "fairseq2n/detail/exception.h" + +namespace fairseq2n { + +image_decoder::image_decoder(image_decoder_options opts) + : opts_{opts} +{} + +data +image_decoder::operator()(data &&) const +{ + detail::throw_( + "fairseq2n is not built with JPEG/PNG decoding support."); +} + +}; // namespace fairseq2n + +#endif diff --git a/fairseq2n/src/fairseq2n/data/image/image_decoder.h b/fairseq2n/src/fairseq2n/data/image/image_decoder.h index c4c0b297a..c5864804d 100644 --- a/fairseq2n/src/fairseq2n/data/image/image_decoder.h +++ b/fairseq2n/src/fairseq2n/data/image/image_decoder.h @@ -13,8 +13,6 @@ #include #include -#include -#include namespace fairseq2n { @@ -68,7 +66,7 @@ class FAIRSEQ2_API image_decoder { private: image_decoder_options opts_; - static bool + static bool is_little_endian(); data @@ -77,4 +75,5 @@ class FAIRSEQ2_API image_decoder { data decode_jpeg(const memory_block &block) const; }; + } // namespace fairseq2n diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index f83f79a20..aae6eeced 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -12,6 +12,7 @@ from fairseq2.data.image import ImageDecoder from fairseq2.memory import MemoryBlock +from fairseq2n import supports_image from tests.common import assert_close, device TEST_PNG_PATH: Final = Path(__file__).parent.joinpath("test.png") @@ -20,6 +21,9 @@ TEST_CORRUPT_PNG_PATH: Final = Path(__file__).parent.joinpath("test_corrupt.png") +@pytest.mark.skipif( + not supports_image(), reason="fairseq2n is not built with JPEG/PNG decoding support" +) class TestImageDecoder: def test_init(self) -> None: decoder = ImageDecoder() From c981e866a7bc6094181b772ed2bc630251ce33e6 Mon Sep 17 00:00:00 2001 From: Alisha Date: Wed, 6 Dec 2023 18:45:46 -0800 Subject: [PATCH 98/98] resize test images --- tests/unit/data/image/test.jpg | Bin 27453 -> 5528 bytes tests/unit/data/image/test.png | Bin 73036 -> 5528 bytes tests/unit/data/image/test_corrupt.jpg | Bin 87571 -> 5633 bytes tests/unit/data/image/test_corrupt.png | Bin 73036 -> 5588 bytes tests/unit/data/image/test_image_decoder.py | 16 ++++++++-------- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/data/image/test.jpg b/tests/unit/data/image/test.jpg index 552e2ada387fa59a0598e60536eda1def05c1e05..a3052b7c3f1b0385dea08eb1e10cb444f441ccd8 100644 GIT binary patch literal 5528 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 literal 27453 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 diff --git a/tests/unit/data/image/test.png b/tests/unit/data/image/test.png index 75472cbb5ff78acc8716ad9121ed421f17f96c9a..5717d71d3d91ba365e57d280fe4f9fde36010a14 100644 GIT binary patch literal 5528 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 a{r?ATr|x19G7hu=0000Fxi9Z{ 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 |_B5G+Z$Ry z&yL-PR0FJ~Ff8-0q~Oi!$F--rLlyH9lU8;too_WD{H4xQGdF2-o6{WJ4^Hh|PCpqw zZyJi1iPE7#%zZ&+3M$Z)Lk~h_99j))9#QqD%h3te$~i+RjzkMHyx_av4AJ|Hir01d z7=Kv9al}C*{B2~0IpPDOlFW~E=cp{%AlwC~J2@`DG(>q1m{G`$6;>lyLw@dNyaz#q z$4L-o>$7P=-?17eOVGUwuZ-H_!qm$re*9bO{)mNDk?SgLOIIL>$c6<$ZFa(#V`JWweyBMuX+%&8kpY`VvT#T^ zn>rX?b((Bcs~;!1u(xX6M>b4K>hSCz&IS+(RiX4Jom09gMtltN;tWd?44dGgP)?F< zq*vTaw=NOgshzvFwUy%g%nmgz-3%t6h@0(nkJ+5Y0ztm2`P43Q0#MupD&X7 z)d&WAUti(D|E-Yz)fA<*5$u?BnC2`eQpeUk4iSNDIA#kknaT2JV;r2yU-dF}hk)`% z(AOzPfBLV^{KZ#r4U~Mg`%o0FnsAGwmpTZR(iNoR(hU`F4;xdBpZ5leYhbDB$hSR89{7)Z zUOdPK)JCn)PN#56NxtVK8huE?nPqvV@FYn^p}<0*n4ocuyD+t5{s>ro(Zj>{E-gBI zL&Lf8*~#L-jHT9b5VPUxZkkn?LkZxL<`n@Y_#P`8ZdSmcklu0lcxnxuov*)?64kpsSs z2i-9%8#c=ds-Mbcpg2YX)?zoqxC%grl0o4jxKrQ{0DILYBW#v?4|2%;3v!5k7|rp< z@ikWmGGX;%$PmsvoI!m4r-d??mh#0bWoawsMlRb!WNC%)EDKzv;I(rYNk_uurb;ccyDG)$8!`!=>^bM?{9wQcOL`IGwT?cW(a@j(@2 z%%v~A5^;%kS0Uj-(2jW{PT$6XoI5@n$?_@v$*7;rP6@b9u6k~*)7?HO34Fe;sZ;QR zi}DgKuR>07o3f#{(rPR7rohhXu(158P!m~j>b4ymIOvMpjv}JTT{7xhL;M&27s#=p z4~TlaH>d4a&)H)vZz@tT8t!j#Z*$}}>8CKh_@d^W=YpU+s2no<*FJZ!o1_DeYw(9p z8d)3eVOqkfa0VTRgk1JjsUOMai$NiX@!kQg|7ynzb`~;+5RGzCXqW0Uwb$snSgj#O zNwSTF-4XqH+)P!!XSW<*S-|;-jOaebidLk-NljsTiHL z(95`(WzJoW{&+ZAuea4_W1F_8=UAe(wl84U{bIEso-Yt|G!D;*ZQS^e#{Z>YXdy$N z5i+NRHTW0(UGoIepROAYTTOm15MJt-{GFjqty(f)=E#mB03ZNH1bs7EA@f5G1? zH(Ab0H_bmm>FZEnh|vCs^l=!a&cgETbP0%vTojH#rx~4 z&(RBexL>BY8n|lMIu{TYI<`L%wp_-^y4S>M(sL8x%fEv zAKYGW(CW!N3RGs;^x?S8=h}wOztjziIMXJ4XLxH)n`0sPf$3nd!^35gKX87r_CuOC z%kG>j-Qyj6IuE3If5v}r5d7;WvU2c|e(4|9=Vq>A&I2*#r|aK@x9Yy5Ku^1hl>gcm zsKPy$PI>D3FbcOXaV<%-aJu9c3ByT%CQbS#?&6;W2a7*Qsm-V^7GTljc-h{*m!|CQ zB*_?E8djSuQ)wr0i93MGrM@^D0<*Mx3fC;~1vBqmxk8I0_Uws53?G>{zfSJvcj))z z|FJ|&ZAA?yiIFC^R<++=nP?23!F{_4x7dy>nCk)H8B)i~ryVwM;o3}Tr%|=lDAx?5 zun1HocjgvYKL$>Bd;t9(31>mpxtB?%vjX|Y{>{s($ury-G`LXcL)1xJ3~(v>pRstC ze;!K)QBEl`)r#oPHXd)5#qkFJj7Rl@(sgjxhcLk|{4$P$pG`_l-0`KH82nL63q07H z^~Rz_;xECRg#Ynr2e^eM2jRwvdBve0ey`_%U^)Tas{C72Soant41)wE0z{eq{Ja5f zDX-=?$U75ili1LYI$*RLO%vN8685D|`w zsp0GH2fUOv6>l5B}PXCyKynfnB8Il!~XH!;Uvkq*Vm$G=gTXRH#>< z4i$>X2{HQXjVx4_QcJ$^FNOnO)$v{y@0sSq>2lNd+}&>Z{fWhkUW+&1HSxB7=4AWx z_9RuB;jjYCcW}i%>oJvki2@a&y)00#18Vt~UdiU14Ih^t`xScln#oPZ#Bkv9TJXv; zfLXq2KjYZ`Vj6eI(7o>#$oq|00t+s(_mt zZ}pqB=kJXeYBqD@4#zxOthqO&K~RbOM#*2FZ-8ivKWP&M6TC)LCWBHw|5zUhTd_&a z^oAgOS7vc8Z$CAv_8^QcPG-Xx7oF zb?7rY^#)+=G^8)$U4CT|oWV9j>jQ4CuA_O`E#!T>Gjyx`_&M%2Vm%T1EV*e*wbm+^ zVD8j_lWs(R7;txGH!q{pY#b?8h2M^TNOpaluXJeO=Vs#nI*2=|;S-6u^S0-_B%C=o z{jJZPI;F2|!Bax5^QNR@Q2z&Fry;5@g4#06#8e9E#j8&(zgxCa%tdJi*=p$&)Z;n@ zUgjeOVI4)D(ox4tY#nO2)N>uC zk+?;BR!)EELZF{HN{n>dj#a9PBTpICbEJ9m2|D<4A;wZ~*}f;k5=7lEvt2D8ikt1q zv&uQd%8Z}wjzdAo50;TzKLq(*@4wFo96*PCR=s>)$a27A#@Q(>ko~Vmd$QF!d{#C{ zDaSsgtZD`p(mo2;l^<2ObC?{OZd&X{KoX&=u$EqjzJJ_F=PKS10Pbt+1&g6 zWVE@UF(pnNH{rr|#Geny1o>vdO-2a@6%wSK#4af@EP^|T4-ONzhqv|^-*I4)Lxh*` zQ~hK3aBq*rJzaPzMVVM@7}vM&b{YPFpj!R}oD_E>_V$`@VzNGW-IdDU9Z;r7I4WD> zfpQs>pxMwpy*?W7|$Ea?(?bgRnkgf-21iUEy>##ya&y-&2tpqs} z%Vvg^KAV=9D2zSMC52Rzj;wGwa4jD%iA(fld18{A3@h<#9I5FmF5SF$YUl=2)xJL!HIRNB#FewY^0 z88=6q?&YeNlk_%9Q+zaA2^rv`NvBKr4zf9alCf3^g+=;q+tP$_W0rBCuDS(^nsHgg zK@`wgtL%da^3d0;hJ(SWcgmk$;>$h!!*14wY07pBQFW!B9!QMSGsb9ZS=auo@Q>90 zLqjaa)ehVJaCU!4GEqKEFUzkVHQM*{I#$C{W8Vz!I0A$SVAA#0mvku@ECx5-`1+xz zgTgnXCo8K2a(mdEO2B3M1rz1cnp;aDCtNB#J&yI#OR|{of^M1$K?g0~d}3(vI0mfe z(_yE)==5FQL{ykbSqwU43r%;nIdWwXdcK?G12_AZPD= zmwDlHa{wusiWLAsVBxP{BE%KA*NsuO2x&Nv1$(t+NQMxzq`B_KIAfObPBos$tD((0 z0p&S+;0kE)yIwNL;dLl(jw=q8JG^V9Q|8L>Wg{HBVM8hbo9Q>Jg_(DOU_C;Go{}l< zUp9}5@S3K>-76fJ1ondL3Jo}1vo`VzHKd>ghB-)1#>{3}RH!Stnw|6|vfJXSxNbZ< zX*(F+njwvX^lg;iO8Pv%JM(@f^?LvLCs{-R{{JAPPH1h}fPbTNwIE4J4r1@Ew=0gr zT2~gAx5d z4#ep6?907~K3cfgFa3dZ>-3}45R?XY>72@|>~PjaaL={nh6goZ0(8HQ2K{@E9QHrJ z^8+<7s>lX4V&u#|o7n$$G$)Du;klyMO^9w={}3uvopT%XxuUa+fVre!<#=Vmb1-<8 zkC0_PU}rdt>06Ad01_nJw? zu_|qcn(BX=N^YN(GxbezF~D!s?BV#?;gm{ux@-#OdU|d0B;@tQ0bzg(-bf=k26_^1 zh>i}6c)4)T&#I3fZ|lr@#Bw~REuFs3-4M~ZDsadBY;fu|R=Z38X%>K~n0D6o0#7dh zo?>6|f?3Mw!OsAmzC7(sCB<7(sXorgYmqt*ph3ZD**LBE%(QuND5 zC!XHZ&%IT1lM$~#DNxtWh3VBR3HDp?mWK>HD+qyS_`Q%ypBfboiVdj(lk9SSUgDoh zg+j%WZ7q~TpXB!`8Or}Z_TDlq%I=FBRRk#|Bn4qmloCWmP-z2Ekx;rpq*Lj3q%1&1 z!l9)>V3ZVw5Cjw*QMzG3I!C(Cy7B)!kNRHMd(M~h&2Mul``&x6_^q{9?0q!c-q1*O zWuN#C7&ET~dzVn~M8eqU71+k`$ano{Dg*(>)25a~73!*zF^b*~-OLV~p0byA0cfrs zuPU2mX`es;O&ScE3ImisDN>CcM}8lK-vJNRU*^PlZn$|Z2Td*G+48LFZ$u1L)BE1; zb~u20giX~HrEj0V+USD}*aZXjJ{+Y(exHEfHB=f7uJ($NZPa8CwB^A*^1nw2;+LVyeKJ6N2l=hK5zPlsiE&oXa4 zS3=*(n0}e{`u3V<>XYGE{#PCR0f=>?u<@9%vE&j-C~9BM-RMYS97fsb#7I>$a~ zD!*TA;0QMC9iLCrBaD1&zfOAqe1J&@L4~vn9Uj8q(UfIKK?Et`4M=)@gi;+i5h~iS z2UCT%rI5a8W~NOi%=Nhx!^bsIuTp1vscrk8Zv^t>?iRJUi9bI!yy1h!<1%oF$S<%! zA6P|g$P+}E5%JGHG&I_<)W{}^QnYUAj%j`MI$VKE_r|j6cGA1V#%S@)@B!d_;kX?ja#*F43e145zuA(0B^!~*ugWF%S(t9TtFn^k$A%eo$%JQ6)l~#VF}AJ zHeGjkwAGW(pzIA(b;PTWWtT~!yFZG8-9rC>wb$#iOCfbR`mlEA?8)xB7SJ6QVUBIx zf!!9~q1u!3@su#0nMGRmhN@Zs^k;vxjzqwQ5vYyjD}kIJyo3vv=os{C2f4lr9vfF4 zn@_WzaawH>#N3d=^<91+FXM8CrVl?*CC3a;$S0QDW??V zHivnzyu31Xrfy6*MR*yhfstq&s45jIGEn?hv#*^|f9Dj!w~MgreM}cLVb@>j;5%j1 zvHBZhbCJneGWw^OC-gQl=4*UDbNUf$O#-<~y^6Bk;E#x+Uy%_1|KNO-0!$toH}vG& zXEc=gc-^^9V4rqbRqe=%0q13)T9?=zq@A03tpIMR_#Z&t0~(RB$RY;ZA^}$HBUf=y zKW;4vc097t*%F_r(!&vPX}!ZFa1cwbm78j_0AsTcts+ zlbhG!*v`k5wv2*(PVggneM}NXvg3#Oa&s#8X?+^ zM`KreADrRFr>_i$4<5|SP}++s*^phYaH4AF9Bb9^0V1zhCkG*86=5uULE!dS#NuWr zKG9EIqmB$w%u#o=FV*q3_ppzD(`JOT8gdZ4{c*Z}4-^}lUQJ1Y!J`#G+^t$2#N&sT z1Ry!%`F!OYa?st+l0SGUa_pGn3$d}TMyKJXqnsTN2bXSBHS?S~;tMH&A0%U(z}Fuj zo8L3Cg@9yqA3(2$P~?%>ardE>)aqDCM@oFXVRo=*RP5?}YaLD91s4aZ=Gv1jZilfM zmtyCi0jb`CUfwZoMMMNjPw3h|SMqiA*u-L#H*X1Up4Q)4FD`oI=oiV7x$k4D32)>A zZChYMwLCiy1QN<&@M@J+8qCdwCEJO{Gdoa00X(Q;Kf`DLohbe!8 zd&{>m0ToYiGArW4p=AiQ9B}?hjfm-apxXa38f-_9*3h>V&MjK&CKz?cIW|YDdi578 z3uap!`K)N8Ypfk~7-2s(PcUGyqYeU+OyiaNz=@8)#WMQfZf{TQpl+I6&|r9zSk!Z1USor<^201{uFUjjzHn1DSYM_)f*BNbGur?Yqt4zMq!^!#Z!?z2r zz9*(1S&Hf=4!@;EJ!CmxWlX49Rws&(L-b8gS(Ff&iH<(-!R*+|zaK`7xvz5K1!-gpf;3!yt;nH`5#q!(R% z%X=SLPF;aglA{_lb%oWBR`MIvv_Sxd#>XT;2t5R0ccJH|wqvb@0$kV*f$N5S{WF{8 zKU@mtrXnxmR!0eLpE=E1oXE5ZwA3~NdXoBxE165SZZT1izJUlqWh-ccF2nfD#OCx& z?##`l&Cwq6!2!6YP!S!A-l39>d3;X)PBTO-l^p z%~~WKB(5vgy`S<1Qm+YiBbIIuNMgNCw*%ooH;DDyF#G0&inY@NAEw?lYP?sVv9IAL zk5Ug~_aI~6*RF=OC_!wy4<&3(SbGf##Gv28WR4%d&*3W8=5EJz)Ejra!pIj5?EHk! zd@(k#nF^CBDoP@-UrPnU+8ZStU~h~(pv8}U-WdBXjf_+%V${R3)g6EMn6-RQGnk5i z+k123dlBQ7M&gsd@Vx2EHgg4na&nX4&noW$vvlbqPj8>XXn_t= zvXeJiU~we&A)z^d1`orliBVF!N8EzaC_gL98i~m8&LD8W4Fjz&zTh|vOTCKVS>XW~ zmAysjNn4{3YE$#$Y43DfFNU8BYiZWQAqsybcJymL%69W9w!^p|ZgZnzp4HcL*vZ!F z)l{onQD3TCa&gHz)UJkLdE1yBZ2@pT2S z%ZlvwWyfk%bmE4!$!Th+X>4nrId#~=CI~ zsli1C5yo2_dD^1Yua~GEQ7tvLluv`Z*=2(&dd#x8+Q}k2*%l3Vz{r$o-*iZ7}>M30vAb=S{?bhL!G^b-@uKLIUgK;nlD0OA6@u5WD4HB8Eue4Rq>;1=KG%ag8&h1F4sf*)8w*ureDh z);nBXDv3{azpkUUY`Lbb<|b{>+av=ryJa)=0@fMM@N=C*f$2017XGl#OV8h)BJap2 z7K$$OPMu{<1G~Q_EShCztzj_ppSvJy`jaTCFA_77NZF16Bd!k}TQ@>xBUYmq)T*;0JF*as5AG^5<6)EM+<&8NucahiF-O7%5+6%Si&lCZdR1=zr(7ay`4< z`E66YSxK=WCv4H(Dv=jNjZg3AzyR8_kp4Fk0g9gX8^|c9JY|bBeS!oHl@!k5xly;S zD)#M;;8=pgbrZuS3FMe8^}kJq-k#v2XjX(Ndjxc*2Q3@jJ}LQn^g=?q+fV02%ybvU zbC4I+MXE6raPSVJMPq2;V|Amj!Tv^gvUv{lNzz`xeiALKTHE!yl(zQMo2K|e=T%kO zz+nBKK&&HzD8)TlRiAuktAjrS(FxaJsh`w>SC>+z2dCaGu}A5p4SygP-^kcZdg~+4 zhs`il{A%@sM+42%lUx4vfHRp41{c5bcW~ChJ!~vI9^w# z8Z0=Sf<=yAO$d?cEF?XI?RXZ_2INH);`$G~O_9=|?aW$QQ#?qFpX=>aRS|i|jSwAp zyA30L2vAv2CqYT3bJ&jy`y%w&61Yu8AZ@ss=pF-(+O9=~Lk3P-N0qu=`F3B+v|PNK z)A0?=orX#f0`7LCyeWN30h7^Rv!Zf}aiuq6~2Avp7ce&MhR zBHkNTx7 z!BxP;aZOcu6}>1Q*>ECXV;+ zSJ^|0cRm%zt0D}`E*l@SK>UJmS#=Nu=O-f4g4h>m!m*tsDf9r!5F2~RZHlt*ki?`x zrcqeji%-L5a6awQo~z_<&jDhgt2lttbbM=}g$A0Jjhd{luW`#JumEd46D?44Onh^0 z5{Ka=71|^&y7r2$`EyZRujcO)zwm{LjU2tSj6}#Er%}@JsR6|j*MqHbj|Xk<#A4)= zovk=;#$sysUM9yq1&55Ah89_}4f^D!#e}&W6lgRT*n?0W?JsqEeMh>86@4rd)BJNqY_Ar zz$cwGj!$%ZXWW``LV)r!8~{EyJH!Kc?PcMs4lR^a08d6$R~KoNsdObmv@Vy0L@u<5 z+m-#XD%iU?39YnLmWBLK4}?SN%JPUr<&Zwy{MM>I!a_8LC&9mZ`NL@fU~^jH^=>l? zM$ukQIBp>t5aRI!*!#R%pX7h>MI;K1XXYE1*S$Ut@11`yfUCzMNWEC>uhdzWF@NyH zO<_+B1OychWUSHDBwP_KJC?T5@=N^7iTlY?XrbL|=c5KH8xLR#$RvV-xpGtX3MB5q zMNbp&o2S+I$1lxl2(tIy2*q6jumebX>abm$lA`5yyx}B;&5!0*W`Gu^4-=@bb5qI{ zeIupCeO0=>z7=)4Vh@IkrN{?sf{JcN+A3yr+!4iHH8KH9Sj))?{%OKDl8w!88e)1| zm-%$%=HZduYn86AZ$C+sm8t78E=?s1K%`@uFa2X)YG-CB91*1poDL(Zuagij(^)dD zhjM|)(ymPXeOzA)Kq+!4r;H%o$7>D&d5Ey>OL0%$dp)hiH=t*(xz9 z`*RdY^hr(mK8jPos@sm%hVP#)-N8*2E54_0yjN8>V{(pg$SMQ>yDrWD09}%JI!I0? zcJ`+A!yRaM;8fh{@Y9PR+Jm;*M+eSA3FOFu=7&ed%AtLv7yMz5K?@}FlO7-|?31rf z2?y2`tFfc#VbDT5rR+}*$vuyY67x^tAB_Fz_Jy*KNo=#YsA+ndbh83TX0C@g8%U

K{gllYe6>awV1pQ$%0^ABH#p_PO<&>Ya5S!b3lM9lgByZkKaX+U zNQIj0=Y^!~9C)s@M5FaKeR?6R*Qzbosw`frHzL_#_yzcZbDX^oZG*C0POT~=7=T^( zXleR}Bpi;SJ3y#9waEbMGGw1RJ(b-BL_UojCF8tfjx&uMmG+5udN6$<@MfLq7jFUV zVGPf&WF7@?_aQtwz#r}sLz;;=B03A15c0S)T;eu)VfUb1P{F{tW8d@_?u`5XjQpin zBLaDvWb^6Q;J5}PI(ixbNRXI01|(xWnOF4~vtsGag7yMeeZ|8X=`TuQo(=WC5h)Lb zz~VmaE|9U)7={`hCD}sl*s--$VE#?ypNC>5d&pxBn|t%Fn>S8h)iFKz#Ggca-^WAT zCQp?MU!Oa?hTR)tejr3-#DT{AfZ^IkyL6C9F72KJVn%-NzVkix`?!ySawz6{YmQ4w zPwe!ICHImvS94c$^E9(evvK$FuEpZgtazVs_wudO_SLsl?KWPdv;b=`-#7__$wEGb>uHz z{Kd|{cI2-?{OcV2b(H=(jei~JzlVvx2dlp)#J{KIzmbE#QIx+CrN7a&zmdkjA=Cdq z!pEa=vc6*ex!uPZq&?ha)@$ZcOUR!PA5R^=r6+lTS2lqaqSiOBS{{O^wHA`5l=CWw z7ahIOx76#>bl|GOG zSUb{)q-99W2EUye>6K)V-WQs>vKlO6Y!+He5-laGv)QV2{uA{rH^>;BhhRE`sTfqz zP)uqvgv!5qn>EjGdeftVk?$C2Bs&~!-Lsrg()!va(^9Yt(d?pZ*gXYL`RjnAH zV5;&Z9X#oR>Pj}D>Mb8VR9N?vi=V_m2uOnbp7PqL_BH6qr(;8~FYvaNkspVtOcIXj{%f2^!VQ_7N zN-<1EAQO{9CW8vwyo-Ezisy&1Qu-H{F`NDQX_+kaIpdK15-2R3nmYU{yP^Qej8L{S zuW>*)XS;Gu$+I^9Z2gv%(nHEptPQ_M=HE7L!QNl z9DZ;;ff54vMa6R2{A{de)3xRPl#N+@wE6j6=2Aied|2)0Y0jw5D;D}!_T1lrrlD$Q zcEygSB9(7sFp@e!>tX^adToII)QBFFvggBdctzp|Oo0c5P3u+Y<0=TlN}ldR%DiG> zMrW(>N5H%lsH^&s9s86)OQk;$pXc{vSoOrKx55TlX4xo`=z<*Cf`zUt>BA{Vtrvz4 zD`ac-=X)Qa)42>4Xw`Loa&hM5x zd69(lAq!UMSowP%q>SeX$VqNEPF% z07IVnEMJn`u$(%^t+!VmDyFTob-S);O;Bke_egZNcG+*Yiv^O9uvd_h2(h&H(h@{8 zm#WuHR2+L!^=@MH(@CQBna|?(wSQMRVscnE!3i|5@u-at5Jn3FcwwoeL$BqGmY9y- ziwbE=U1?|9z`Czx=9U*SQQ24}>4k?(9)3lY7Y?FgbREWStKAOt7l;6egEr#j`Wq$8 zcFQ+;5ldctZJ4=>DT^W#^L(1`fsXaph^*@eS-uYfDoVZA%@JNfaFr_gxG$9oJquY5?j90q6b>{S z*^M({(~HlmFl#zKy3^rGx<+|7-nDF$$NIM{6e5?J2_81m#XWgw3hNw28oWG3PY;SR zUT#ZspQ+iHMYToV_Qs^BP}xMhY>pFi+1IH`&3#Zdp%fO`lU?=#l**_ac2^$QM#@G9 zqgHZ zCr;yOa+K%Bvet|}%uvDN#ac#Tn%|}le^(byIwG5J4LE*s!b$^{m=0CK83L(NXerWT zIAIp(vu@NP_dmEa*ALe(pdwcRL-0X41}%+1C%LO+JS-SIfFZh z#a5PenO6rLo1i_$gR@+#vK7>amWMp7f^H;$leOvNN6_RCSm>J3IgHd(dqZXUqU|69 z2_a-HkY(Sd8&1l#M6pQT8LF0?^9t4j!9X+@*@3j|f$28(0TKe1!W-x`6oOn&rk9@| zJG}nFtu8H2p;?eCe_oCxIz_i2F(uYtOzj;j@Vo?g-sZb=7@D=wiSTxP8WhF#hDBl6`hE>W{K>#-vdF%^4_xPfiXtb#U`fWP;52b> z{$9*lEX!h*x~s%YMn+!%looWDtrmoReVk>0)LP1ciGLVT2>jy%3$JQti?>0Ml)2I2 z&2z_sd>_d-cVo3x@@P{#nW2E~{}m^CzR?mUkFNPyH+L7RtK{iaP@wTvSK9J8B`6op zj0eE-j)Ivscn~*(6e=75YM(7Q73NLReVU_6UU(*G$)KCs)xJxf`w=@-$)38@b-B)E zADeLtKM+R%_@_D0i1a4c00kZjWk0a(m1dWAxFX{<`o^c&l{~Zn0Qpt;`j1v?USoH= za-=X&9QZfU+{^+W_yG+x-*qLp`@kgI<`MdYr-Nwg5{5T>rP;J`Rv=31Njau+F8i#E znA(>$xDDnPrdq7e#w;A*zjZof<+6!dCi7S z3{tda2K0>1GO?ki^0NPAq{?$h;)MG z&MgfK9jz^x6ZHOL!5xkROW7yV-Ocw{eR*(B(NHA}FI*{8^@hL2C;__9wjqX&?_6aC z)7A8sXJJZz08mPG?^b~)O5SXwqQqui`R3-Ur2?@l^6i<&+u-#xMce1%+pUgAsFsVW z_9dQz57 zZb2iGDqdk?H>sF?{9Z(B0bGKnHg;Kx@>(NO=aISWsnUKvhyvw9vb>0yTOu;1e7_n6)uLhQB2UoVm%IMX0afes7njmq41sTlvXY; zohAc({fE>Y(252NCv{+|=UhP2BWm9cKtc^Fyqo+prK9LA<#FNg<fGi!gJr|H_GkI7z2Y3w zeY#dQW?vs&O`J)bpMu6B9(aw$Vx$LA7DH>;N;|V0LQNH^KNgOkPROA9;`@qPXUXp%`42T%a<2l%&ywcSB1O2Rl;MK5(ADZ)iorSN|qhoEvkH{D2-Xe!a49T zR-41z8hE<{tq*(CXEuQH%b$+!B|`2DxShBm-Ll!SEc1Kmsk1jVqk01$(8aL`bFDvf z>ue$t?^SX3FoR%~Zki!JPXRPPz6vODhT?WVXeSI3$aZ+V5%tAu_L*DsG_{BE#5|S6 z+`>)L5NUX1@_6sFHL}nc3idW85g`U`@R!U2?v`)g#Ssn$FZ`nyKtTxTHI?xEN?$bP zmZ9VZe-Bx`pX|Of3+b<6{#$Of4+f2^c8dBidcxl=?jUYoFv$j;tEZG~$Ve$}A=WM5 zVU2xJs%yZuq+u$cL2pp3XDx5MYJ@-PEcfnH!cxwMB*!lo4NafNM@q<}@pp#2kb4qH zBaVV} zp2vuwr0HoMCkB)Md#*v`v>Do;G8Ase0IDJ_VF@pnYPc%iW7e;@`R5ND>UZhIr$$%YTZQ{XG8%3uBQ^(n3ii<$lYdAy!4u@hZ@WRk{7#ZAfF5nKTUp@ND*z#On?^r~{CNOebTcMQZS2`?bH9K}a(a|F`$JyY zKTXshFZT;2-3K^rH2oORFR~O{Z;4E+HgzpYcle~B zJ~4ZVWuMYHd{T(hL4wY0=fZRl?(3YW?IPn{K)~H9&R2fk+z}CRfmRFN5nEjImp&wK$ZK0xc)x}H6$z)42xhp;VgGo_B#Ax4tEsO z&l-ks#K@edagcROe)>uL-k}e>YO53m1N;qV?>}%b+G8t8@u~nel6}-@1IX~tDH?8Q ziU7gX#;6WvH*zFw4#=cd*MwwRc9-ludS>&<>sb@fjRw!ri&0JwFk;W&vkn78e5kg? zsuLz}VJ?D$;T>>g@)K^v7r#VpHoPsvX1CpY$9g`Agco&|d2`N$r+TcePD1+ZT*h_l zSYe3yaCq@0LoD&jKUyZxi!^O$dE!~fi zAWSRlp&;k(0t44q4cJ`^bHm91-NG|undgSpXI3j&n{lJxAIvtY z@>V5Ikcnm)>^N%kuSS9O0ffSn@G*lS;zF$T>VDkJGat84?qy%YT239tt@hZ(P!Vd< zuK7pCoZK&#qr0)7%Z+Y9EKlGY=WV3$f-iXO%|-SEjSzXCUPfpxEuCMUa4WS-lWnQ$ zc&J39jkb5j=LSRLD9CeBx@$Z4??nG!Jj|z) za1;tE@+oDBAyuc(A;YKDURZuAujH>O>2l~m`8k!Qd(T)&5F?539kFy2lW;cAqm7bc zS-N>XY?@?YEK5$*von8V6?PFTt{D(*PFlDDjQd9B}n^B@y`hmPkC`JOMO?mX*6melHvY0?7PL>D2Sc7h3EWPn~& z`K*#kQ%*hW-hY>e{1AlZtGv6NBROM173+6|=VQnU?kbfsbL8C?T%TW3d~e-yjg(iW zAWQ7hwwe5Qorr)<8ZQw(trAe>gu)(AZ2t6=@x+DYj5@_YmiJvw%Hrv%&I>2Feq{lj z)(a5bxIPKt$sk|xzOyQGmvxrzY+R%emNGrGz6@B7R?TLQ+X=e%D;0IXEI2;inx8Uo z8*yDLNElD{K|9gm=TKtwK0I-oPR(c~pG-ro(0><){P@ZP8v3eMCa#NmrtG3tQz~kB z{k7y+J8{-9?)ZLAHetcZ?TfYk8&tyeb)|9`Ro+33!l`LB)uKEh%pxp(`=lg+l_kT{ z#QX7s-$;&O7gsbx1%Hys`=8f)e(vZF z^Qeu{T&){h^IFXAmdw8ClDE`UTjnf`cIx_j0)P9whG9Y&8ZT2Pac;vJ$NgO1lQhnK zU{+j|wtMsmW>Kx?@_(X@D0w!iI7>ScopqZl>Mrrj_HppcS-LJC5@6`lc*|}6TaId8 zTJX|;yG2N(k5(cRLsfubU9_&kh^=?iK5ENYS!v>_elaF4YRmfM#J}3J{R1@8i3hua zxQNQ-$2nH>gc@i1Rd{ZS&%F%et;*t**-wKR=eo;}sQrI?K_8)TI)r^YTKHmCMp}x) zrPv0)&u1TA^h(jlW;m~MAOo%QHATmI4~VP%GH4&^Ls}cVPD%F7t`3Q+;i)6fk2ai@ z98GvVI}V32^O$~dQFo26=?K96JIttn>>-Vfn0=@*o;S5xaY>xks=!yv(p&XJy!%QL zZ1H!@dsQL}x5kPpzt}@7{eDb2E5ttF zH`+ZZlYNcGZ*6)Ad(Gcr$=04S9DPdeKdYdOp=uES2m@^Gy?+~^5+eH)jjy|@GUs{% zOVpA=zw3$T6s7lBT?46~-pu!yZG{utFS;p5#mLgG=TUcUdBHKYI$tDFV~Tw319xqe zukWgwo154Fu?dZ1Dr!by$4;()LPgUQ**ZTZgm0Z%?5hrRJ4kT4h*wa0K{5CSv*Bm? zhulZ-sa!J(JA`TTb`kg5;0bCKe7$(oYVo^CU3IRM^GQjEq+~O>Cy-wLb#M-*12=y+qPMF4jc+(o^x{H3y+nF-KQKz^bP~-iCtE z7AMA}B-5K+GEvxqG^YQe4_cSG)+&b;M;59o3=gQXhh8F$Tl(sxhF5DZ&UrfR3=#j| z{vJa3&=X9Y5+PK?OL6F#xuNTG9KJmze;m*zZF^F3>Rm{t_Q4b|z5j_C81s6Pj@@Eq zQH|@3@~-|9F;wbrN7vS>@|4+Vx27^eGCShK8h(?`yRxdth?!+2VcZ5u+WD51>N98J z7N6h4nAcSP3FmZL5@^9)(Yl470}YpFL$DVNRJ(*nDC-^v^@)3*Jm8!lA=?s|$^F}| zxvCl2F_gDh+G9NDt}XX8 zT+7|Bb>*n^*w@#yG7V8wyc|54{24jJzu$hkLVb&={qvVVP{c%n_4ET_NsYs^_vEkn z8~XgXby>dM?N^mVC_T0Bg8=sITD{NmMDAkek*E#}F{Oan3FUYy8HbnD)aDxE)yQ=y z|FQ&4LwSp#J-N$mYo6TIzpGHZ#O!TFgK8)nbp?wu+N1xR5?UuG5f0$L4QiqL0N6BZ zx>BGcZEtAxqsOs;vPA-s6AZ82c8w#7oZ=$)Yl_3sm-XS>|tDnvo z-EpI8&Qp5UtX9zU$IZ8|!eyD!c;4Lcpo-OpN!FR0mzD0jqF1ZUl>+Afv?UbZxxcPf z@^GlmJwo-;=k$CZ#R$k`i72tsR;+BO9^^0{{6h&Tz8`@B!_lW3{QK5EI~inJpXqcG z!~>?%`~0{a_U^W*wH8IzZx9K&6FLiTqd9VTEzq#+gu(k-lL`{{fp4cOI6^bsFG-gC zA2RhpGob~IpCU5%=00X&pO#>^s;Iy^WlhVtFRHnX5<;>%gd?^i$^Q{HVTdG~#-?{O z*1)ZfY$JjpXJb}L`i|iGm}6>{F}uI0wc%dw-}nHlVzF>GniD~F)7zD_5kwz_ugnkD zRnJJ72)uH=O{j_T`uzf0(l`4oY>gbpI7A4d@eZ#EH9m^M9?ch*TX?}OmcW{w;EDf( z)03n+?Cm&0blL2tLM%-|u3>XStk`}7V$=g~Z=19KiqX#>PhQJf?~0E1*a~s5hMQ{Z zrb)&&m2=(4Z-Ki=W$hA4{NvvF=iFcGD~B(i{fvcj9Zno+UXRFa6)--R<_2fCFEz@;f>!M>~7rH!3)9mg~9R5VwDn^W8I9=A2sazix# z?}`Rh3;D;eZ)d^IPK*@Cx@H=b=q}mUS+`0qCFW@7B^%~l`ePD0WRjV;>8Rdyp|;#B z6}g7)KW@1ZKUQJRZ|0e?{r=ZRA4#&QZ8p~xnh1_jan+3KfV5;#9{tiNcPxdXyyAq zV3*NC-DobH-K+}bQy%Sl|0+E`UeZ$lVBM~7O6J8MOP?Tt8(5(@K?X~xNULvZWRl0%%bACZHZ)CkIhK6GSjydB7 zMsq9;(NxN3YBN;UR-fu@M>YRjLJ1G@;UyUfj&h%-YiU-q&4aboTXQiPO85?>dg`|i z*O0*@U+cBJY1L#!F1!c{eN-ix#*?eNnXHKM8Op!^y=)OF{5fuTP@*cu^@~d?Nl4Dv zwG2h1JnFysDb)5M#2OEsq|oeZiiM@bo!B3@@#Mi(vZg=SK*tC7tK|iXN^dL^XXP6( zR7&@Cst;*xN6`OUs70b|7D=>WaN0%v-bB@xjWdKgrC5rsp$B0?>z3OomtVyJtASA8 zz;iLg;oDTt*&|kJ^C;i>i^~DL6trS6y9GvX8)|o9m7p ze1*tEF~i`!(#D+O{4Qp#vHR#Bvj$TE9^&m{KIIXqzs{2TW`c!JU)tK;BtA;XktKDw;^(NUj@M;yE4pP~jJlGIj4hHU45F5UP$%f)Hv5Uk$8MY!%85w) z!@MQR9^Dnqe!3wre&Z{RXr^}m>|SDebdchns%R5hmu5vg4g$QtQLTV7|0MQG-r5Rl zyB^AqJ#>}qhT2>^c}UQRjFV){?U&X)&BCvc+YNu&7WO2%b+_2oopZvtDG9rovNu1b zx4I^H&YzKr6Ij5xeaD9lWT-OG;5uY5NM7w1)lm=grNB!}?ts!=&knJ)1|j?NQJ;Jz=WsH7ssxw7l;rV%1`y+?uiNtJgJHXm7*`-S|&Pl`qfse zNe2HPFm0g(4v(TRr{0|EOdtI;uJ6Hh{03>}f>-4&3gwWtlCvBBM1WYHs#@ok^4ve5 ziwomsTt!}?-FO94+i?uN_ETGYm`xFKydGu)yh%j zOJh6UaC4aEN!d7?sZIFamFGBKD1tjX6-9LDSDOg3x%&rA!%4DfZJu@NLT+znHAmO0 z=m$%F=(&_6d!@5hg7A0`C2{7t+u;!1z?og2ZvMf^AjB^np2`D-X6_4l(~;z{zf9`5 z!P@X`q6UEv~%zTrIMT+ z{x_y4FruLZj&$>_^(vuZtC}O}>IzXvEYyigy<{4nggVZw6f8dwbLaUZR^j2H-(Te7 zQ{c*~?)y}rBcu@Bt&C23&p;6%U~XSNBX%=ACnv|i#W zt>igTHc{o{HnE}r7t+dT!vX-^?eN#FolV6PdfwRnxXtOocnkBYPt~uaiuatuKfF-$G2J%?cHJ@Cx<=F ztA%S+lcrr0@N8TDKXkptEd}(qh6(a}LMz=z``rcM{MVH6BP*5u*CT1dHMGsHXtfY! zgBDuf1*QjzFJ$m7@#-Z!O5y?I#>9w$YC3bt7>7}Wm-6u~(FQ*9r`l zmzg%y59ehbqr6t@XUBO!IpeBpx;X#tv%DN)oSgd%Q4G1^BExrMj%_f0-cBO^gAQ2& zPrQvpIPx%Uab?_kK9Lh0uf~Pb29N5>&{sVmjz$~9gKrV&F9w@4!#}LTwPFA9 ztmKHwMWe8*F77y!X8V{tZW~7zwIZK)FFv~*;&cf+<`kopD=xj6GV;!Fj|)v-e^ku1 zdW)$4hC@VO6n&E<`tV`_yLlDL+ebXP%g2-MgIs@t+asdW1X2Iom*swMDz`@S-*Fy{ z_e+v!HEGw7@!rtl@B2|~GkW3oqMfd`oN#Oy+jxDV|EyCPx8v2EG9-iWkDz?DMGwHJ zFSL4%v|A&3MQhWG%BAZaX-W3G35t6hI2naqVm2FlvKr@h4aQp!Ki^_M{;Q8&&%_6K zKeW2^XpNvaLTOvSF^1{5Nis;RPNF$LcGj46_`MM?*;!gi3!B-F;$2S6-1Er&H~;X7 zv{fyky^<%R{B)q$7GJ)06DlgaNR>;U^emY;KklrD39Dopw_`}iOw$|k_Z7~>5Y6BB zj1?o1BNuxxkJOy@`IfQh1-aS!7`0;3WW|>u`(sSkojf}{$~v7qLcS+%@W-;(t#!xe zN^uLKR==#FQ&`0d7&eQ*LT-5@b(6@H@O}DyALO_=QXJp!( zu5pwIl~c(5nI?|h+8ZXnpT}4!AfS0AuWS)c6D18wK{K|__n!C3pv5SYlbmV#jx&ec zmmfZ`KlJMr`RQaX^O1?SLqRoSA?=o`LywW_#sAS1Zj%*fYCrs5vCFI)4hs-rgXtZp%!n)n8&CMxsa*_i(cT zE&|Vv1foM&4nv#|G<$`hL}gF&h~>Ic!x&>W{s$$OF71`r*BPuK+#d`9yZ)^m| zJ{jGa){)qavZyovd}IeYl}wzY{cyLFezeTmfK#zcm})X+^YvJ~tR)HiO`|Xn@@6F} zXPO7{lLz+2(;A#!in$l-O!W3pim$8iOT9-e7`b@iIO-n~!F_fVPSV&bsbdt;P7j;w zavahXcU7E#OV*An8%dV;vhIp?qS6q*G1AXEx+iYrUR*HIeb!x1dh4u^>%|7i%fEOM zj8GQ$LbE@&_c#NjbDIcpwsXwL%TeeEifd5b%u$win{oJafW+9wImb^;^pbu{#Ir&Y z7CBSrR85RyRf~0QT&ey~7qPyO6y&@#cI?JjiP#o>HRSvtV|@4tNqm4`>}$wwyEPh8 zx$JH@G1}qSfwt^ORxP=@su=a}+pw~pkQ!b~$Ft-{Q|4|3CfP2&Gl6CR4yMbljpAH^ zV&thtyd3WsF2wC>oG7-rK;_L-H?T$+@f&$tSZ!L`8Pa(z)$#qWhvIf5HOcZZhiu6% ze(#o>flQ2JxOLa$4I)y*y+D~<>X@>FFF<C^mcCi_i4AvaU{KM5(XvE}$;2p!pZusb$?#aNljcep}1K3CbcX%5$>N-X&AS+nh`JO#C> z8ih`;*+!q`$nAQbeHF>un8PUauJ?im8ZW{9c2ZRU2`kP+rpHnUqDpnT7%sE`H4>-|MSS&Xf^{giL(T;M&3US#F-H zP$}`v$m@QgBNg7Beq}|u6Ut=*y*$l+P(=^r^!{w3rMw2um$Umq(yr)t(B769`5B>W zy~bsB)-h4ZD`X7M_5Fdda*3DJ{SF+}HjKMonBfIeAFhH_ucF>i4 z%EWNYeX}n;_uZS=sY|vl1@V2yT=H~LMBB@sZbTEzO&l9u_jH>lIj1(LdWN1Py@7qQ z>3qg5BzL4jd2P6QD6do~bZyB`zH>#nFLu9FXgMlgHJZ>j+3()Gwb_~G;`iiWIjfh< zf>fKPPMkq#9QgzXF5X&V)eAi{Imunlx^RMZOV2ln%Vbu2-G@rWr7TW&#%N`|tvZ1_ z*yQ-|+Yv^O_jXdPvi)+Q7>cb0ev)YMF%DzZG_w_NN*fKW!8yA)O8XTTVLkWAEw+Ed z`Di8TWG>!-GfA`NbOZ0VM8LwY&AVT9-L34{;AeXKV}I$D*vBG_|TOxEcZBWphNIPdZf0yl63c6CDy~M8-j{^6VxxSU z5l645=kLv5?o$wUm8NB;kwJ-dFuhC;^eaqSbew6@yy2S>8g+0_{0L}j^ilZ@nShUl(3l7Muies_=DIvf%ln=}qGZ0QIv$QvB z%b^uxF+)p7uoH4bby&PgtROBX=*#GDz%uJLBU3SlVi z5LK#c_ZkX(F*`l8Sarnp%s}cnEB#;mRF%B#^!MiX4&adXKf5yvxAJ-ipd`hzP<`4C z)8T#&r>;}b^4q!dO=Vap2d(d>9+X)Z%ORbDq;>M1NQ(WCrOUg$5Y1RJY^04ZDM1x3 zMe9fQ{(20->Ywss`9XEr88X&08-g z72Dsk{6@mOD$T@g4m>sErp3p*?S4H*-r{wbN1G4~4Piu{0}K`YG^1b?W*pqae`BOZ zHRXoG+z>=wH_G<#8h`kAjZl%K17VGWxRId=c8;Xdi=y>ebDsf+U$8iM${5V>1d16J z|3B?r`#;nBACDr`i z;mXupX%Ko44!fdI+VJgh3ByyYQ^jNjJ^r6nKnHNre!9! zB!21B#}ay|BPw@D5CCU}xwii9(piZ|hHuS4UDtC>x4+f-G34F;i4su|=~z+|+iTz} zbGiM|DbBj0Q`QHnHvoX7_1)uk*wlE8wR<47K+qS5R>Qj}Jn$2(?Fntc7mdS;G9DWG zJ}phapUCC=T?N=BnA39~t%u&0QmilCwiB;)hxFC)*x@zpRi`Wt6^bOoLtl&ftrJUOxHoRxI)K0N z<=iIHpfQsLStZjO;$M&;W?znqaazaKpLSARQD>_ zoQnfK^Pk2vBqN63ja1Mp$0LuxGS6M+yGvl~tdHFhJ)gWm@LVxpS{A+2vskB6q6#3U zmo?nR17zBmRc~au#4Fu;ebPG`y#9(9-FrxHU(43u!aWh9=K*|IFsX3^g3vJVI2al> z+N%g!PG)D{JAC{y_B=Ge8K+sVeZNv`@yx7gJ<*i#df)aL9FX>g zrP4NYx7q{S7QJc7i0Sme zGdqGg9HpKkMpA)3l(tYt6yP|<49?K6EzM~*NKezZYEiHn|9SX+Y`;pm&A$Cx1}i|b z5VmtEEf~I8MYh~3G^-q>gZ>~7mt+hDmmjcai5U?#h$bEaneJ;rQ2v%xWPV)X_D7UGh~m-QarVAE+{(ZusV7+hH|T<(NULju z#S<)9JY?gqQrRuJet*=`g41GhUE(jLgEQfn49&m;aBkk>AkHd+^HGPGV*54B*8K>u zlGol2SbDa^qtd*W1GXO14i*2qS~PYS^qgN@gkim7|MRE5!();M?h4VM^E&|eeGbAt zCWS22fA=N&?^E{A9Op&F>tfOukS3CvtO{F7u{q?UrT?@Qp%(rF@dISK3zYJIO^|2m zw4Y<}SNV>?h6tdC9PK#DMANa@th{IF?0AE;DpjDRMotn>A4&h>cO~LY*R%UR0dE(} zA^E#|_9vuC6^2j0w=Q=bso?!mx-mf(4U#gEEb>%193GD^;u^KNOkX)R$#pT$|u+W~oPN+POTM)D2<8f-b(MGyU529v0;#)zaUa67ZlOwX+^G5a0Msu7{{lBb#@HGlp}D&a zEb@BA0TNFF)(iuHV))zgY2I1vF?&eJ@ry|Xg;+qR({mjf9hk`(G%sq&sZ(CakUhnS zn2hb}gjpzn?`~^6^j<2>`(f~y4WRrbch|4Ve^6r!4dGp>rIWY3u(JG+?TC@<`=guc zJzme{bg5-NDO>)!b4_FC*JzGNholpxaTC3mRlb}_G2qCreY7wIZ3tRBbXJ|vP4qjJ zQAdV#cd6}4hY6r8*@QmjDvhcT!~A@kv-8HwtZ_v~;78mUdz33ljmMjk3W|%TKH+k8+Pm2=^eNlsC-oaR z_MlQ&>A)Ir+kpdJA}zC@PN;XqQKUgPzqWP|vs#5@X%OuUIljq&JfqW; zrmS9C?9CehOXL6vedUDK9_TJ(+^{r=^sk#Q zwK9O`5G(Pj*;xCfatxZ%&h9iGZ@7st&P_x_n`C*jXFNX-43DU$jK2EpIUgLE<*p#1 zaXQnW?Pgke9B4tmbe%5N#7VqTE45h1n9&woSw-(Ls;V-LMh(fhNA}lF;qmHqk0+i5 zwK_nq%@hT5Q*Y9r(AGJ;u&Q{pqd)lKILixGXIJo z>G99}Ck-n$>W1cxy}sUgQMh&CUPMhzX!0Z%ldkswjTV+X3-F z=879_iU9if9lQk`{9=^iGgk*Skk0lzDK}ED8RmR5=}SmeCi)d-!UT`>EgqgZB2}X4 z;fMk)@_55+GC!8pF@yIt-1-rNA|MD2a~cDYQ%b<5UY^ASKB;~1UdZ8nzSKF50r~1 zc*SJ_t>W1VfF%n!<*H_NT{>_He5!S=@I0# z--Wjc=4D2;ln`DHMFA+fj z#0nHZ7!k&Wb}tnrSFb#~@@!1)i-C$PMhlj+Y1EXn72o#NlC=Vc>b+e~8jI1&{0DHK z2WW44oFlA-e)FAUEGSvX?7=UF_X{6RgS@Hr^1V&p{v0r!)PPw;!A8Fa;>q0wx9PZO z<`gV=-cNgsRy!2ll|F--9 diff --git a/tests/unit/data/image/test_corrupt.jpg b/tests/unit/data/image/test_corrupt.jpg index 2970c55dc97837211811cef5c0e37ecf6d687281..420af225190fe4642eff8ab61a0ecb27bd0ddf91 100644 GIT binary patch literal 5633 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 GKKwr|F$6dO literal 87571 zcmeFYXH=6-*DoHsfQpDnQ@EAhl`?elC;|eKNCGTbGy!QrdRee&&#fTRH6$Qi2oOSx z5PDUr)X^kJig*%W-^xOsd2XcW6a^;^q1fp|+`+xF?3&Q`q z%|+J#o&OKjf3E+{;==hEgje0g$<^J)!^7t7Usk?<`S{w~Nx0is|5xGpZ-_eN(#1dN z&-D^LUA}txPr82f>XoYu*BKcZZ`@(MbDNd<_U+q$T3`6nEN?K%U!+Tu3k;)RQs zFI~BEsRT5)2mr7-+7{c<>41r>8A*{t9KtEEw8c3{Eg;&mVW)7tbvvL`=Xz{ z{2c1mA7U|mGwcG-gNrwTp^=AY21QO2N1_P|X}tBqmNYcd8F14X|Ka~X-02f=>Ea*$ z^hzC;f4E=1aQ!-c2-h#t=jcD&AL?IWee%@u>Rq-+(tm$RmqEDEInHd}<9n8&Zbjjj zwSG^#CLo7&M>q66FJ>3gI3I)DxI|~fa)|{3g`5%o{eQ6gf7$=1f&a@iz$ZO%qjy{K z+a1Qm&{S1TAK%%5*GbYpBI#u~S^tilzdmc)AI9q^s@V)&{1*hGF+^E$Ww>nS95S?Y z@hK;+ivERs1||5#82vHi;TNj7Ucwv5Ul%3I*-ifa;*YEs!wUpgbAQ%vJo0FKNuxf` zOkY!GwSCP-=9Q+(GLJaD9Dyo~^CT>!HDiKDYT@K3SKz zqxV0E4)6u795S;CNKjRZr4M*b;RIIPQv{PLQ;!);}cg+5BzZm)7}5U-TCAU(tq3PqUN;D3f7rVj<=q zoJ4!(iA|L(g5QV|*MB$t`tOMu)=zL|`fpXu4%nJR(8<0qADs=NQ|ea%^pf{K3h7$Z zPvx;0K)?Gx)Jj*eWcjld&+GgwUKLdn7u@M;jVS23{63}hZXvZ{Y)YE19JigGb=>hU zjo!~JURCTS-?abwvj#F&Jh{tX{g+gCu2)Sk{pt1(u?zn+NSEEQzxW?=u+s~FMHKXM z&Md~fV!9|J(Ni@6`Ty*x^!};o=C)+!g!7*c&Y%7$`QN4D*E`GAWsQo>{>9Ids7#-A z_CJi&rRhW->PTq|9Yz%Vpx4kBqHRoq*Tp7!CA+TCg}-iJ_$ySn06e#&mqNb(NB{KI zO#cPF{kQYtIwX+yQaZcV`b7cU4)iu#-htc&v>s{C(?#B~7EUG~nz-&0i#UkKt3jJ- zvQJ>^@L1I}^tcpL^8;-wYd@3PC<_rcj_5mtT;{P&wa9Y_7S8Nczu+x(cF4QObZFqZ zvvJbhd=8o7J8N0cc0S_uTwOeew9C6~guE#}hmhp`&LN+Mb$xu2Znse8s{MHv0ue25 zL;`+Bo#~&*aGD(IDpkCmIk33gF!Q}++49>$_WZMZiCsJ(`sGQ#&SDvzA(8nUvMR)W z4he`kV_h#y-k5lh0vA(w4aSvH4lDe}mRCl9xAc;Z-^D z_>T_1wNk2s9CT;zYXl+AA!EK(hO>sHyqA`XT#%icN(g*-EZQ+GTvZ9<&mVnNu`lZR zH?-8W9E~GiUgq}tdZ!eECzP_yqT5-88_nlWJ7pe~MAZAz|6Da>!j=bhU)RWl!FKf> zwJzZVuE#T_yOjs(_5lWdR72J4<6V?_I%2j1VEl+rT zq8Pi<`;~uU3VJ)K4v&F~eLb2o*iCi9BlnJaVmA*&Ns98IlstZI_Dp_FQ+X6>y&RCT znQt%w*c>*0LCa2H_fn)Decebt^tY+}{x2Fan&whizn8{DU)<)G=*x7~;&cnT3Ift*-Dgd? zFElOnd)96+!`Y6=d3%O+rd2GWhQ;-xwLpM&L!2!~zvCPt69kxIXg+v{bBM#X%<6YE zHjAA=<0TE%C#aFnA*W*WQ7n;TZkRK7Cz48uBLiC|k=8})xy_#1{zv}sku3}f8n#l& znY9oAZ~bdqrKOsi`OY3x+s|LKj$(p?LFOQ+6AgaLiZlpoxXm|l)zuseock9bc^xCml6aZ)O%zFy;TLnMn z9S;*C&LMTJr!ltz&LPOj;h)o+RA@)-iNylA5yahMSrm(dkHW1N?w&(1t=BMH@X=LI zi@qv_uNL##tI)f7j4CF~Eec*Ie}vzSEzna|%uD~>*RQ0g8!>}homo4FD4)dGz&}we z^PPf7yHMF<*1h;u<}%MA?$Hg@<3Tr3aOOntcifVm_l+e>>852GQ2KzhG05+nnZN8% zjxr1CI!haF8VkiJ96fRRJss#=HLfU-r#3%Eu{Vg-+fSIQ5aOLNAJ*|w2;k7+X*)(* zFaQNL3I259pSi^ac5I$2l}d4j<9M7J?CwgozKVt2X@T{}4CI(mV7HIVm=euu#n#_p#c-1ivgAsq5HI3=`B@9cZ_Plm@i zraH2RVB>Ez>9UI&5S}jN0i2rgr(=g>wV(Qp`i+}~d?xIln$=e&EgTOL2eMT3Uh5l* z8jzgzltvd*REi1g;$4y!Z=$~86_Km?)m;-HRV><1 z{MA&I#^$h;=nQ~7M~<2YL0@aI?d?Gb+q<&Nbu1ioM{!hk{MdEXlMIkbr)`h>8Lokm zn37$Ed}}qn8|agWK7vt8nJbjXZ z=lc3pQOM8HQ9^}ty~y0qut^QZV7wkA6D@LzSR-hPrA$N#w@P`n@J>`Ne?PGZ>5H~_ zYEk?3auO z(m&+)*NzME?y6nYuohl$*G|y%Lc&&$0sC6CE`_4PBhj^@S%bE~WcW#02YjDC8@Hq> zM6=#EgL+{s5ppwMvIhq%YhyaG{cE|r-w;9Op}h*_*BUHEG!S|^W*dD&Yg5F(H-=gA z6j60A_a+yS3%WV`qG`ZPuama@NT#(jhBF~W?Ohk#ov>{)Q1ZANGmFRq=$ksGC-<@k zhi2x`9de0Mu_hV!3-dc|fVRA3Xn2eD=C0$6=+qzs@CCD;sQJK$-k4j754ty9h zQvqXdIU7+;G_30<_+^T@cHX;}&Gm%9E(bRIV)Z@zE6WqxJJR^3kTZFozz-E~$(UOi z)UH;ERJXouXmcCFb#ThnZ(e}N5EwC5bfYj@V?7?2=tE5p0m%{m%h z`Y|Iavi^%ykv>8wqX=e?9*27 zJMyeN1Y<$=2Np#K_bqrSBZr8_nVh{+_F!=K?o_PVXSQ`V^=cFs#iOVRZp#rQX@HYk8u3&{)Cnl%&a(6Qc9 z_w~SW2l33d*+B^4LWaeL5GCr|gW%}>=Viz5=Z zM z?!siw5-rWRK4xfcpIRJp-O@6i#r(DlwiMjAyuLiJSpi1YMahI<=S8PZrI z2_1X7s;NfhPXY!%Ih7(LPX-eoaVVA0?qXk5+eIDvn1*s0^>hJ>=L9~%LJ$6+>HGMz zkBlMr4Fj9u4C1Q7l`8#tic@G>F^JFlyU|iGkD`DLY)E}DV~J4Ge(LX0x-sdk@tdMB zDRE0Ef^4L4U*&;+*Y@r`Wp2 z+`F#ufp!%&@HoFdYh^<^r#h~B+-&`ihwSM++shUUDyqlnURKov=SAoJhvjyik+gnk zsxFND`JOB{hJVs-V7x(|Q6^9Da7!~kV~)r_3}toB2aU)O*)ji#FIYWmtHOsS*ia`g z=@z)^I;!TE8(DAU-IuxQH%J>rKvE z4H=SuBo*|InB55bk1$JS&S94)*15e0=%P58AUTi4Ip#%x%IK{>=KLKDBHSJ9KHTo< zo!;N(0;8P#9>TDI8a1I@n(F1G>cweab8a0^n&}LGC8`deo9I6V8yZ-q@Z{hlTO|#m zjKSt^;T}!VIn}mK(Xp~0rORw0?Wq3L1A`cvH&~SOeI9*htnmaE>}N^{kbg4J*zG?) zcGA(;nWR^keZ#;ys8!$3bk0>x@}Pv3^OO5yh(0*SPWMaQ< z2p%RWj3qeO)XSKB$j(v5PfA61iN=wNT4x5ft?(jV&%1=ozS_=<2v6(+OZMwo319!B zP^YBl-i_(GM=WVQXdP(OlqJ~D@3YGHUNOpi(4otAkBCSaTO_16E7S(^g?s2`AQwlPwAxO6Mwarp>K7i0Ekh!(+#%@C*V*7+hOk@~>(*rqaVA z(FU{kWCm-7;wd*wAJ7~1xZ@(WIL&Hg+K3`2_T-l=*d;}ql9R?yJ_c5wLz1;U0QAuf zxHXT&C+z(jgvO(BFd5)^Y$SC}QA3B-$ri|LpF_%$bzV<7DkRS{xHox&a_n2RpFi9V z!jww*(FTsy-FG6QJO}5+36s2~SPgQ@^0rG$p_Go}1$mxc`Ga`$tA>8OS-peB`Ux4a zC?sD{*a%>&Aqs7e_>=Sq?nM~(+$jF2dlS2gUJ7;h;z=8yIwEIg^5+&yK%zW6`?p05GD);K5 zs?QT2@hOOibt|olYZQ9kHTor6F!6lC8Iidq_B%eT&^O84NMTS^i&=1{A!Q>kR>5_a z<4_j&-U6@QCvL;&?m%O#TK5Cep^Y;qrj#G}nFMCXY+0YikCky_&mq%!L0^s{(7S30O$u03uXlrNXq^u09{5@B z2DRBZAao&iH+b33G2vk6^kb!*cj5K#TL{=SrG!3rl;Fc<)_1@Lr;$9PYj1e#_SS^w72c{=_T32xi z1-vuE8(KimIB{@Za_|IhM*g+90ydNK&)6MT17BomMsdk5y;2%i6wF#bfyY~V09gFk zIposHwFx?n(ajI*ZFz-(0xE`5$f<(|WAGu{h+u2M*}IhokEjKPZ3gI*_O^U-T3GX5 z{riB^A5RpNJO^mE&B}O}jZ|jOrV_d%4aOp?c*aC@hLr;{PqwJ{7oAV4zF=3oU2ZmM z$u6~PD{7VKuF&nDXVy2`N=MoscP5!dc6-zZn!WH69i7kV->jxRq#9+~D7gnK_vuL? z=Drl!j2~PZ6+n5`61&7TxRCpH3^3HPxo(`ry+dQwb)VNW_WBt7Jsg8MvYIxv6u>)9 z`+Dm>{=Gp~c!c2-mLPV=s=8xd1w3-nn(MQhXV$$ePOTI&-m;H?$g=4j^_SY8QYX_s z4SwXQduSAsfp#STyD#Q2(8iyV8pty%>N!gl0{mIWR`E)&oU*qH{k8S7>UJL(RhnEt?7JCZLi$1#p64$q-?Ma36;YwAh6e zw8hCkPKy0*r~)JJa@_~-0yui}sfeg}6EC&4y>GQsF+C*b1Ko4T{_6f?42fV1*8Ksf zN3Oem@ZOc6c&dy=iRw+Zt!yf(KzS-YUQE#zQ$-%~d{iA=GEefIB{$y<^#bhpshC`q zB*oRN7p*FFYJq)&A`0Z^S#nR;WY-8`ZvAW2F%T95^1B@;Zkw1!@Jd zruv+?5BhxVH!|%&I;!{{;F^XoD7|jcVZ|*HC@Kfr+5yH4g2PgGY*T&RX_i7>9ZiG9 zMca%1%}GwxW!>y075MAOpZ$@6(6ND7pdsf>Jc*t~9eo}nE!gRxk_Qqi*B+G^DN5^X z49vRn+7aIH-O!YNk{973X(U)@W!faQI)k1=Ld2GengQs&> zCOokOOa2T6sMFL`UdvtNgf~|0ZB?wk%GTVjjbypX8aO$2aOAa09_TY#vM8nd^aCQ@ zE3ooMS2Ynxuk~L<^#+|M*3ecA(FT%u{Fb2pKtBalH+Ih+*qhJ(V$O|8M!Z z?P+GLzOS*1=WkERA)lP8@xa_-sa{%v&{KLd}N`Ia;IdWoW1gbPha zNEl+N!ws`f9w!?to70j&jlkuN-J`I@c&U4TrTT2qp7#^lfmY|+q%ZHigi>`?N&|%! zEZ(XT8~rr)Ztj;|+4Si))ilV`NtF*fEjX^pEJ^;py+-WN5J84Y2C*F3;sed|bLloD z#fVG7W^i=!R3dN;@3#+|h{+Wm>*999oOU8iXwsbRpF@JG+mydKmT%}Ug_`}T`BotZW>|GdWBP|@Y=txxusny^48mZg( zDhhlxICjus<702v4N33oy zfeBNXGh?w)vhVMdUW$StqgRe*oggFrPJ;%~S<-ps`CPoVkdsmT6mr>ZH)CsQm^?A< z)PCz;_Q}oU2fEFTRuvU0?QVJ-Z!K{~vQ!Ic_`u#xE$+}wv{+DQSfbv7|H+H$iHNC$ zD^0AR`jOte|Kx{1aVyMQ${Bn1kNe?>_!=!rz#3Wq>Xwvx2Qm`(Df;bjGX;FoQDko_ z87H%k49|*Gw2BZSVtqio(`X(KYYYX|!D}A!(&nZ4owz&F1wYSL*M>w-Gsh6#2nPk>5V76r0Q^rsD>;ZO4!hc(!6;3P*%Zu-6l#oSBc9dBO2RF_P}h z@D!!WKl&O`@`LaD`RecBg|NHg2ChNe6gyp&QA46T?Vfv z6P-O+$BMNi3c%)AW*SQ(eYs~u~P zeksY_I~$I2#HQccww?3w@CUG3j2SLtE`b9C zqp8nplcF&Z7|P9=D3??{?C~AXB#`2zc=GJ_hKSJN*Iw^0A0Lc?NC7QI0_ancn3S0M zF>4!Mf+Vn3UnP@3^`B;D`2OVq*`9;rM{vRchZWVDz_sRBW+CqPg8bNXC^bA*8OY?jx*_ zcn$Gehm_dT)%P3TMox3_(5uFpFc^cpKrT&7Xbc7op1#k`(nRf+agB%)wxEfYZ2b%{ zkq$PU!`*p9Y7;(NcXD-h#U5_k&B2R*8N`oikzQqGy6tf96di56&rTO3-V4+`(@kv~ zoDH&<3;0%`b;kbhzH`VnNj}%4)6L~)ApbDPB@@%$Y74aS&DxC?>vYTn+$dU8Xqc+| z*z7BRePZK)skR};;TTM0wM7@v?&}63aydu9sfQ$&r0JM~v$Y%2R0qjZSoOn8)ra6Q8_d4-h-{k$Kd z4H$um4jnz&WCN1%DUfjqwQ@btz0w$v(b#($Y5&Y~*3q2xqfuRA&>g(ytEk0U-ncZG zJcL}jn1GX=7W}$mfBj%k+6Wl85dzHORhd5P4@Hm|OOZBz$5yJ}S2)$qbP6a<$P=Nsh%Vl%et3j z+FN_~aEqpR;;iqP5esn6F@29tpnXk~c#gS<_7d|eeZaIvrytJm>+`5hxzJqj2I1qx z)Z?V8MG6=2e-B%U54(nSA6Us=tvuk3Adgb@ix1+Fw7;tx*vr>XU{S9#iPlu!c2YF_ z!YbhYps`J<7^KHy$7Z_DA&F}9dNs5~O3c55L<;{(W0}6M=oe9Hr}Fi1K1(VW`Y&W8 zsd;p434gn|2fuN`d^2E>(QM zsHePVJe8jmOONynSjI-P7%Nw@QRWlfkKtJ~P-)+FTz|=Xe8c)fD|Hg}B;eNW30$n% zPJ~imJGdwOvt?HjH1eeuOj)Do#y2cjtE!ek%I;|z*IwGy3c%a?#ws5NN;Avw!rA`B zk##9vyHos(sWXb!Xf=ZLVt~W}Z}In$PXn0c$?-A8id8v7V}RI@VvYZykYei1dNZ0tk9}t`R{5fX zs350BAsmG?B`0=E-IV!pDA$60UGb|up1&?w$;~A}1mAJWAa|=&i7+J|=|yNU$i^6s zjhsXW*7%tqX~yHzL}R~t)?r^ZuwJ0(BSVth-i5x2W52T{kZ^C}&lfmpXiiofN28Qw2sGam@aOCOow$`wZT`d9lEd~OMtzwSi;$nuq)i+yV8x>F$%hLQoO_4K>!pVy2tyYN>j53}sfH{7s89QY~9>|s+q*iL%Iga+XBJ=n& z#*M;8+2Xy9?(;4V7rSO>Ny;z@5bdCQ50Cv;BfpK!K1NMR1|7h^wS*YOwog?I&6924 zAuzQR(Ty7L6@c{ZD)Ui4={!yR_N}dt_SDc^Gs#dY7XG z15A=vEm+bcXAbAS+5)76_$my1=BR&;6Xw}?xpQqkB^G#VsnRE%G(5(0sqA77R3ki0g87kz-^Z* z4TU3T32m^SDqRXbMGIy>7>pEADoVtvb#?2BX?v(_l)Y|4%*JM{bakhQy50+;X12lv##3EjHio8|9MVp!--Zs35GLN_0)#m%eKwk~sei~?Bq zym`E1=BHy+9B>j81gv=<<@DpD>_{pV^Z0hQRs>t0&VL5a%Cwp}^4)_G{&`Vv&nSte_t}@dc zW7LlHP(F3rzm^%g=6p3l(QYXEWKc{UJMGX5?h8H}S`=bQnM4Jbn z^vta3D3y+M4MwrsQ|)IqH?!9%#3i@WD9RK#eiEF=RfxpFCvuI?PN5-m7)tjFaFJ3A zytW7vQy-mjsEx(HFZe(V+aqy)!fUaGq&_@$V;3|$1c=yHG z;NkrujEg7x6Xo5Wkd@s{=+jN32~M-Aq=Bi#)7Uxt&DVPR*cpK?YIJyHaVBMVB$s5` zVrZ6SnCfougfp#C0`N_&bi^6+q{%VaBJnou`%hsZBvH&-fOF)@+A4Ax8xQp4Ried$ ztv49#keaii~E0$wqnut_(Hc;!Kaas@EN?||- ze@74#w9sh1IJ#mqRnVU|?i`2x1w!Uslp2W5I3$e-NYaT=xc zpg@f^BFzCh2AXOuK3eR{4{?>MJn)Cwi4RcU{5IOGsh{AQNIsiOA+%G=Bv0zT7mY`N z{%Q-ig$k&2vZ>v!kNeqL5ONGroUSL}@*X-DD1T-ECmkb_rY^la{i1Ci1zp!ViD~6+ zkJ<}DdGQ=@*?znlCH@?*Q(in&f7dTrzKo1pFiHFN{j6`(S3kn1T?BOO<(&B6%CZnR zc-}YPrnPvGbnCS_pF&?A_2p^c!Qw5KBOBgh1Aj4=HTDrbMvoL2pDdv#$f?qqxW1Cq z1T0R-iSHlI)!(WwkUgCuymY07s_)==kFEDCJ|GesDOpWLOgai$DfJ+I8D+(LJNSWp z`IU@8p=#*EzQ&<~W3J17?0Yxqu%XgYOB0sHJlDvJU_UYloI@VARtU0woUv3WjD4ww)FGqZkf0$wb+Kv*>I{o;527GDgU~Y6U zFMzi+8IbY}Hw1y9XfcRVl&jJbbvM|6B_~BV=9aF_fJ%vZBl=cH5YJ1Zx>ZatehvSk zLqB&-0mknB2;G52YZRzK0PrX@PZ_78I*Xu5t6yQmdXuQ$B0cGhD9MubxP?e-vDO(o zcu_LWvr<+cIE}5+DhefgwQXHDfVwfNZbeWZy?h>n<=skImI%}t@Eto^M=UYb^f z-i&(b0`VWTpiUVlMJd<4+$Uwh3KV+_o>Bvzr74GWOS0COttYPZw`%&b&$DwR0%tm^ zZT}onyGdFgUDoJV`L#xAe*T?ScvuGN6yB#I#PYFuddb@7tqTl) zGhIcN#=E{gD|FRdnw^D9gQ;yOFn8K+VgE;;whAMNyW1-czFoyM9_vw$*E!^rjc#y_4v$-`xDEy*Hywi5SQ0Ek$dU$s@ zWw5S_i?=(`;?zRw_;pYvv^&?q_>ExwO8VKNuaFam!{`>cALztO*tYADq{GG<00GF* z!0lP~u4Yg1-M~!M>zaKk8^tGHe!4$4YaA?vKEB4xkLpddbP;!y(y8vM>FYD|Bsx-y zq1JvVcYrOnHr~XC`+JPE(USj~y+7utujlaEmQ&t2WZmy?=o$T-?<5gl)c}v@RCYRu zCmRH|QJzE)V4@=O3{%@hy~Ti!_DaRH!m!Wy$R`j_mJtwo8(6ca`5>)0`5uq?gO3(x zD8aUaCDx@{6Y_B5u9AM59`kee81I1PrPG_8nqpn1W<-yHcD#s~B>s<=@@x>q(%rX* zs9Ko2q^6`05QS}2%bl?F(LJj!YB>K|y1h`UN{zm0mQPmEOT16csz+@^f#_M=W+Hlc zLZtajXKKlNC~rXZHONRLEev4#N`Kq6tvS3t;M{&YF)XvEn%Y8l>tj`IS=*yE=+Ab) z-$(W8Jyp_PI2l{WNuV`j8EmP8nj2)1Y^_jr_a#{pLIX=n2J%_tyo>t{!sRPim5qH>Lu#gBMew z+=D(?hbc|KuoxqhE73#J<;BDp_##^S@k~?di|B}9^_^!uyce%UcmkCpkFN3KCAG^p z48?ZrDk6_i0XutJ>-Fke#z#Z?abU9+DAs6l-glWj;EAh-i!{dj9(^tq{G-BwpWH7- z^nM%phi`ZXcnLXi(jrt7MyJ~kPp87LQnp&1&ii(&mnU|iyrZk+5eDTY&yym0K=sV! zOsK(iav*A6@psKpBGRSQziW`;chwP>M`X3uW?g7VmLq9Ezw_PC0;8;fEU&Izkt+f| zZN|h){MLf~`cB|(SN>3C1UZoM8YreovCc6wJsabF8)s6FTySb>wGJM1Bh$}J`muU) zc8f9IxS}Hp2QZG$g$l~=KutBW1OSC@LS%{Q53dB#RD&1ABw#xTeeHL;J)h)+^9xUE z7~%y$$G{=kj|Ut@z1A_yI7mZc5%5Wyu9Y)9B8`H>B9ETe1`Yhi4W3D=tiDBeY`b&SS}OJu&7BoCco?QPqZTgkS&T1C@$afo2kp+z(66@~2S z65yH)vgG4lMZ8?>kLm-P(wZ?%DJL)IVK*1o$hERoaHX!h#YL|UF? zDVL!S!nK%H^5Q=>1l>7fstkM1lggDE6D6g0q+8Z8|ceTtJT=U8&G39wyc`f!ljwxvSZ1EUc(p_hJS z1u;HRVj8KpVH0&aR&1PCRCAi4AJFxbWovMot;`%@-E?S;mZrF2JbW-EK~r(6p>(9T zbsA;$wzyk2?St%8v3W~7qWr=P+Tr9Ycpeb5XO7f6miik#H4%Tzq0w?{xjvL?!>MFm zY-h60-7-Py_xJ)nkZ&She;SNkt&=5|%g|g%o<94<2Grw0sdvjXN%jWe?yT2Cq2E2f zbEt8??^4uBflb1EKY6@;xy>i!W=|JYB+?u->`UxrO+IU4^M`;H4%!jq*2L zOI4{4%L8LoU+tgy)JWd@_!3%ceV2xCxv7mLi0Ea(lMM(tQ`n6i?QNAYqSro8)~lTO z!ctY%h2Q?a2j1=VFEO<5l7z+B{XX}BynkP4BZ~NSskvC}%GYA(sQ3D7^cPSzPoU?J zj4+(Vks;J#SCtVibr95(Jk;19^Zq!>`SF_0J({erWh@babE*{8Im7eB-v~b7QT0aG zd6DJ!qW8FD+R$Wa&!qVoZ}%Kz*H5=zI6e4Hl?>6=0BJs7UBhF`jY=}?8vAh#2QLK> z#>dzEG=3*-%EgyZ9c7omsa_3?y9}$sc;KM0m{e9LAo8Z-cp& zN4wJ%j@QIG>h#x;ln>4{O$D4UH6Gk4c=kF{LtMkBr9UMzvt;owxsEw_`h;op#Z1xd zf`~@zT*aS1ZP1Q|tE;clSJ#55Sb-ls4YGDqXfOTF;o{^lgVV`= zq!5Inx-MJIiihJq@|@UM#Z0MiXf$Zasn7{T7LR_d2$W%t zN&na~vydYG{Gk!EPn%%$IuorTW*s)m-DN(U+^;o+ej{3u<=K*8<@V~Ydu z+Oo;~gSI`Sq|hnPIpl|xGK4`=% zta5G23EYWCO8pZu8y6kN<)$kOyaR3l&PL%kSPfmWwOcyYV3iX^^P-f^ut9GGwd1e%2>#nv-W1 zP|k2=v{^Q(YG6E>U=Vu{XI$sP~P97)sjA10W4`PUrib1e%NX-shzY)gCKyjH5@uc@C@e9$r1fFH zw9C?o7VV_Fc>(EfzSEIJZ)aSCniHPRC5CStm~2ZX>Hu7JAdalioYR%%ay9Td6n4y_ zZCM*RjWNZZZKO+p_d!&P`O8v_?txI{K#f5s{wRWuaaz;v_&~FUU1TB%B9!xQtHBX> zfN3h8QM!HIg24tTMQAM9A48F))Bb>%#-M5TCTf?{*k3ALRJz`4N6sJ)@J@L=EzubL zMR8kuQsU6Ar|Bd_{+Z%Wv~~As<{}Z;u4|X&SNg=g@=n;Izjl@G|H#2&2yiI4+-w-k zgL48VlM6<2_pM=uCf%_^ohP-TvWo~gA?|i1Wzvod(=@4(rX#0-XLn>xq(+U`O73V; z!1v_j`=S*#XeZ|y{SE)GcweIuVkUial5ZN@Lg6sfo|K@c9qd^mUY)BYpp>{y4a`v^ zwb;A^S9#u@L*@c6TuW@SJnV<l_I(M|RzwjKg3&llM*S*`Ww{uV*NxjKY zr+brk+in{9)n1a_Ucrvqzg&9a4>!sKzs^2))SSKmtbhE2CHLMnmdxD?RR2Mg=Vpb4 zVqIBLy-u1;WjEjzP`*ax0JGE>5Y+;>CJWyUZ#bIFR?4A_Jr$Y$k@MPIzV=2Qs?2p*Kc&Ql^RJ8LqJ1Tz6aYR_|v2C<|$vchwse=TBt1VT#5#< zOW!-*27Xd{Ui(6&ChO~1@^*woNZbz&j=OH4_jVs?E<$!A{m^vj&G$g>u`WlG1rr!u z0YB&iQA?%2TIhra9Zg37cEnR3?v^*VE5EVl^FVPd#&LW}qh zAa=&q_{hyX47krjADgly2lL5h?QJ#Ww7;bzt3ey}7u~zyDv_%n^U?F*biGgAmY=6X z8lV>r@Xz#Y0^bu$fKu^p@0@5Lf2}dgh7i)~t3Cpx@POH7O#NXVP@YCTdz)fA4Mb zVydpp;K3Kpd33CE+r$?-ATz$HG?0%!vv}VB(B6Jj&Ne_*zzOE$V7WX<2*aXCuIb%R z;zgRbsseAcf-J=zTv(%(*s}srQIy0atv(E0$j;1&rK4psmU}wh5`F5xb4x78u&K1? z`0U7uoRfpiP#3SlOi9sK6(i$z7UDA_7^rmJ*;%Gmnt25lmzC93x8<3c{ayz+5rypE z3o$9GO!Mtq#9Lae%|pBt<-Sw@(7yYB9#S{3t)udj&58jSaqIXi@7 zzAMyRiSt25{_a~}%}syb@CL^~7{Duvh>0oV=0`pm7Cf!;FKxc7#v6@{r`DBsdDt>Z z*sx8HDazIJ*n#8$D#69u-4XvA9)~YX_dIoq;hWd-#%};uG&&EFGJ)eV7rKR2LQH?% z+g)Ra(jFvwytX$Ym{n*-DR~eCD}}SXkM8SuZv1>ggD2(W*Ec!qub)_fZYKY-Woqwn zWW@vaedxf%pI9cYl*@Ik?v{~pCHuEQW1;`W)_XuTm33{v%#4bN!T{3SjDSdJig4-h zDg#I&AfYT+l#KM=VTDD2Q7O_#LXnmXgb+iOUP4joP(ukIy|>Uigb@GB%=doZ`v3K_ zR?gz)-rRcjx%=$>JkK^*Hz=+@s^AJ~b|{6r8;~ogxO{y`aach^uH{COt=Xl4zl$hq zC@BXj+`HHsg7oz4loZc8&}$J;FalmqoW6^aQ~LU(3Gxblmc>c9e<3q|9+8+BTQIG0 zeARq+3`B!ENz8^vt&QfC(5-N9i2G)LtpeP+5kVPx%7A9119IL$hn)q+m9m$u`J2P! zB2aVKc{u-}eevfg8|&1pl{57dnN3)BT<^uU5d=tyE$)KM76Emk+ejZ5_io+}NtRIc z-61$S2%S|okzLV!nlXh6T^eeGy@M2G8=Co{Th(Pni6dad#R=tD^tu_3tRF?E5|xzt z5OWp)GDG0&lAjq7e)_hBWz-Lj7w{gS;i`D~CI&J9?AqvRSU9uf4+e|p0jcwaO5nt< z_@Hrgj%@rs2Y&~S%1QC!%fT6*rT`}A*cIna1B2&KEA)C;zZ}+m_Tdh8v6Z;KKd-~O zopkJl9v>EwYn@R+{dS%!qX#jU+F!rCpK3!S6;hf+H4_tfB;Qbw?tT1;?R~rSNueso zsFVG5#v0_$g;YPTFJoUFq}5PrKuM|4@w_@PH~^e;>1o`f;Qt`J>Ff$vq@K)z;m~P^aKv#o~pB|W|qqgC2)Z7OZOC< zcGL!4lg&QzNIq(-LNPE_L+~Y}WqYIW0=j!jsSN?4uw}7`j8FY_x<*nbdYxq~KpMIl zP18P>LAOMvI9oVp+>hVJ<~5f7J+hQ?g@$1txP`jLX}?I6yD|U!#W^M&yU;y!gkn)L z{91?)--{*f$X9)ncUQS*#~z;*Sx^Q4M4}YQZBOKtcFv+}H*)-q%A3|MWp{+xJydS- zCJpD^(b~sj5QQV9xd1B(&OGRPuLub%Mr&)Ne(Fb{O%{0(mU?hU!*&=RbkBe zHDs0z5$HWuh?l&d($bCTcwPLu!aF~;G^lqy&lDXpgHWh!AMGGWS!X;2%oX4%Kw+lW zox$kjJmOijl=P`|9?)6gH=YiL#%y4>vy*_n4U^^lG_AY2y8y2|-_JFtM7~A&W>=S- zRQsBW=*RfB^$=x9P>8L<$&8AKz`hkFyRjnOY~p^KX_|_Y!CZgu=>(1cogvBXZ$Ox@ z`l6J74VjwNZ3Q%7vLHROAJ&jr9>SsOHVG0{t)G3HAw68(%TvF*jb#O-sdmfGWvqgc zp~ndYXn>?p;Q{iP0yOiXNWRflRr7c|qH0857Q^0b&$}`EiPa8UG~qKfTKdgCjj^)q z&U%`eTh*A z(-%~lb-T|`a-tDhF;nDE2C9$h`cj^lnY5}3e%Mi0%3{@B@=!7YqXQTV1;y77>`N{@ zV+F+NBG^}GQ{Osux20#|9~@643Tq6Ro*6uwPK z0}L1A$o*|+t+$rvzaRYEW}v15uvZmikHb+dSkpSIHVyzFx7tQ%`(FYG{)D(*;S9MJwyb7@v5{}^296mBV;U2HkQ%TTipN7p8att1~dN&7cM(`k}Y_#2?@K$nx zMb?Mz!VD9S8*ZtmC)sKb>|3cIB zq;$nXBm!13-M=3oldI_BuAy>_j$)0MRlfZ)NXPBctM`L3njzAMT7?ZQy5{*yyYqXy z;cH}$%r%8aU9)3Dv0bW&w(9U3ME(9o(6bV6k-!}&nePJJf>RrGSyQJ{G^sA&-Fkhu7Q)$FCX(t4r~rqAC+l+(EciW%=`e-s5)Bk7#g3 z3}L{60AihwTrcuLG+}eQcKPgi?n~u>Rl>ineP1_~@8PW5#(kte7;PSe%qD( z!Db)m36l6n5(dL}AWINiAdrnGd`u5tZ|+;xB{Z7UG_UR2l!|_uE2qTZjQB|R!)12Q(s44#gTc*@yxneDhcG<0ZYF*$@DD&ySjQL zgCpCuUk9Pn*%m{zUO*&TAp}s)bDTYKR#NHIg&HXLJfy>%vv>Of@4mS(yRvAJ z+tb!L%$ry=sFOy9KkO35hhl-sNl~bq^>3(A5C~5^t{tnKLb z^%QpQ`!`LD%nV{3Hsb#R(?K+c$G5~#v#z^{TeysNQ}Qn- znn6le!#1tz!I3RTd#$3x&BYnJn2$J?u}-@j3B_x0#}Z&^ zMo76>?y*L2mH-~2y36uok$|Z_mz2&;li9Ua$uKqzn;FWH#`JvVWLGDd9sb0Sw2|b@ zlQ6@8_^&pK-Nor8);?W0gs}jmOLEFe-*Y_qj$QczMYC#^C-iR^Y&Upimt3staYu)8JJ3^Av%RN(X4lCORBoC}Q#q_+44%ICw&Kjx?mwH4LpRQC*v9(ydb~ zpV=fVOEndr+ZBw_7d>nAA{FSXVo4yBGv}8mOSJYK?e1pIbI?k(R>$a7!=>u z<-4)lJjbj(Sp>n{Taw9WqNM3w%|2+9UkZfO668EPzwWDqbG7ZG)H0MJ^X^FPrAr~s z`6Xors*G8nc*TocT?sdF|NW=UZnky(^X>|8VBfi%EkDi5$Zcxx%Unu3X%c3b*aS^2 z%rQEZ=Y5`NgHFp_lQQjjR5D;^eP!&xJNbIy#7NpSsb1O3NQr9%P&dJ|bt$eKTgY}& z5@8%2#iQkXtH4;6%0?T8(O3mcB_(l%UFv>wBOV281%`1gKiifD-$|J6-`{H1v` z)st?RW$CHrofCiv<&!k7EX{ECkdo45!NuWXTczf@Y;52;5b>(1$tExAYXeAc5ke%h z3COI-`qDw_RPi|cHS9wUyw{NgR95+jH}i`dH^}Q*#_Gv2AHYFo06@z=gigsCvN882 zl=o$Wj%=PR@2Aq^gl>-Gl8Nrc(Wd1ESKCr+wexIeU{o4}NMhq~lcWbF+yGqFX^ej; zcjRTuttQ^Kku{%Q!)Mj=5&^M>y_`n<)Zx;p5w~rZ_xLTT?m1l`IOGGdt>P?|Xk>V# zc6zW9B4CD%s+IMct%mAy}tf+uL`_%CI1R)CnAf=L{uJ<37#Lts&m{<5}9b6MMh=I7$= zh$_1Nj!CFr+&h9kYh+g#x;w#?zzoN~7{wX6d&{4uq@+rC7!;#kURBPE=?OjeqMJB( z_@!o@XY5O-iZ^BlL{6BQ8x~xo=Ea!2!b9&oE=+ac&WHVGVZMpbADSV&CqR>2^$sJR zDIQJ&kd6sUz^H&G#J}hl0W^MqLoId#kBX>SvB%E;E85np9#vmXifed>BGKMpL0(`e@YX$-_T`tU^h)6 zeP57o3*qvsF>q3MDl;b>*Mdsfms#_@|TSNf}R z%I)V9?8PW&wo-xW7pFc`adX4IK3`6uF^Bl}OI3*Ze$4_-&D7W+e9tMJjNml>EKK`6 zSYEfc*r=vhKlqa%T#;yW7}1PU)*q49Gg~Q}eUB3_62BlSCiYU&URY5-DdRA z6fL^jZw?z(r$Y1;k{>m5*F8vZ19|-TM5174k6H8f^q91lLmLnueQ#lgvggjxyFw-P zXjr?$tX!vnsR>(ns3vc+aVJ*ww0%eN%@PuEcYzXCX?}opN9vn?OW+pb=3m02f7nxk zJhC{KxUC1lrCC2}{16YMa-1Y6K9!7^Tk+kpC+rzWNOJf1@2k(qp2jvH#pb)&@8053 zd_AI09q_c3yu)KVOtw`1qu7p3`m;ZI%C@PTnt%lAU!sa%N05%MYe>5I# zC1-pt`jK4V3$;TM0O!(kbo==rXCPsn(yd{6afpE*e3Y^sA(En!}&vF}|qwRg8x zVQ{bg*Q1IOYVJ>?*18cN+|DF6$UHPm=cS8sR6yz#%+DJt zPmS9zgJX%_@`Fz*Y8X!%K}{gdjJo(gCZyxRqWZtXR+t z;^-}FL;rXJ%v>qOrj8_8Zj7#kJEb&b(XgReHRwcg$f~fGi!|uHZ|UW@H_N1`-`giH zc>Io2tHP@~2L)&ucdVNvSI+$O#ynTZ`(f!_UF1lbc`p=b&d`(#sxVV=x%)*%w}^t1 zQe4dFq7NeO#Z=iK-YvZrVuK{zNi&E0VLOfxDK;6g2U+K_00!zVmy&X{UFqj>0Vp1$ zfoXu-i>&lE|C3IJfxPbO_^eNaNOviLP0YgZSxF1~hL;Jlmoq6S+;xm#eLuf~FML%O z1Rsei`aWTN^&ON?vskPpjmsQY7)9f!3>81cl}T5^%UWxL?YNU|&bMkE91-@(E(y~Vmt_b?G9?++KW+K1_PpmA*^^I$`(hvdRCVIaB-S!CJbk!_@Gp@pzW zlnIR-b8&|^ryOXC9wIO0%fDPkxN7Eq=@rruG?u+>F!|a|46RmQa{pJ@jlX7GK%Bi) zZ^=#;M^$`>fkEe24=3@o^xBD5sQ2|F&ORkK6YUR_QnsgCf!(0}iZn?+Gs56j$FK=r z=RUEv)Wh|+)M5wDD43qmV9s}@k0p(kD`x2tx2Mk3s$d#mG61Hqy7Ut5?@i9;FjiPO zQDVnfk8|#6!^@wKT(|#8_D$l^dKx5upPb&NWHai9wNHr${Pa6oSJm4hE`RQbm|J9Y z=P&w~OGxNpyfen6gJ!m0AIRkZCJl>R!TQuj6ZfY%p>xbDtMr=RTj?kq}#Ppa%o;eYxb^9hWw_5J3$`V3b^>}upK~c1`-9BO{eW% zh)*7AcuTXhyMVb*ua-d_-qT`}1u^Tl`@8%y(h0;hvggxaFsQZU)wfvNlw4@m<-02y zNzl-Pq>J9E9ErqBBfiQngrJ@Wze;Lu1a|8##JYah$hB0XHm!&9FI$a;6~DEz9`FW4 z+`W;R64pNnq{Oefr&nxl=iT_!u2}AL;6{l<0(v0}IcwO$*4(5!7&%#pm*N${xw-Fx z*bWO$Ux$q~Pms<64&7+N8&~Y9A{u9DkB+iPb^XV$(n`Y9Q$Sv<4p$6OwJ@7M+7=?@j&<+3yYtC9m(Mhy0w z0Me)z=jUDEG;l7qKI5?Cz>Z+Gz*f~mlN!B3XI-7}qNPnngJS#$?l+i+?p4K7kBr=` zKdgKBmGPU#g8_)K1e|F`ZF^g_m8oSI_N8&2+|X&2Ij z)GS*B6D++Yg-|#EAM%{T#9OY`rmlvrs%;8KnMN=9l4D*iDS0#rx$xunDJfpgDf_`0 z(OrYAtZhi8m$z=cBC5r6sZ-+4%`M8ZTch7!7zsuWEtIu#1Qpo}iAnM~8Q>*Bf=lrJ zM*tZknOSTtmm3t(8nR-+%p6aQOB2YH@Htg~IGO<{driGESaP~e%_w3Jr!+zawBZ9a z-ny10#@RLay@05Wrd;AzDl`bm2lN8s)clL3X=W^#y8CnY2pIz-*}gYE^05dHbS2_Hd@kde(#C zOj;00Ern1Et*sag<{@dlIw#ZAqozQDoV)+b~`+8&^C2p)n|@Qe^~8jRA8Q(-=IXk8W2eRoTF1&vJB5Q zef17{TBqgwLPJDqX|pY7v!>Uy<|u%)N=20mcRW!@!5b-7cFmzMj!XF4lOU7_C=Rh&M;{ z-%v|(X+{Y}?dAq3d140pl=$YL0xUpd%s|foVVe~G>k^J%7iv+pFVnWPm}o5Nb*%Q$ z`$wXgxfG?!j#&%yKuHr9gucqn@mb8PNQX@^zi-{n)o1|o&~IJ~sobwHNg&z!cmtWs zkmNUAM(owwM{9NJYZVxvkmsIS@-)Mku{UozVMLz%&NNI*&&e-pus!m^-dy5ql4n~y zPw)on9KgI=nmZP00*`C5%jTCN@RVRk!u@RO{Q*E-Gie%67g>u|XNCzs8!8Sn9?q?8wg$lmyHanGO)@R?IHLjTI+whc0zU=fQ%9G@4W;_URt+YKpr6HTAuZ?t)i1-=Vk=6CJT{Gwu`2v)!??MtY7 zayYq!+l^u#>PpTADy4TstNG}XKjC8A^#~rSgBs}O4_f`9&pK3Mm`km>1ma4iz6Kcj zdmh$y6!9O|`h@LZtW>4$G*wn0{b_Jps9gLYanX)m^;oN zsm88S@nly4_kK}BdFl>QOVU_iBebo( zdzp}qizj&(0EV@t0hB>x)8V=%;@z*tyg`Fu{L{oZf;kZ?P)u42LwTm1ZJ)YX$-in! zx1hP~KW(3~6Xc_-07NbCUJ!tOxdge?Z!dzUNk*5tJ*; zydxj$))y*h{xHi(s+dX-I!CEvl$pO$f3LVl`7{Om9`LBgs(6bqNjV;ddMxJ7&528Q z8K_i6-L-gN8srcW+Yt0rODgegWlPMH#noYvrShN9KxB=&MPHce$CbkYpsWPMsvbRA zI-dmkB&2PQKSFj(#aDSFbOfp;bnWz?x9}j5b3mrFd7=RP6J3K{+nQfPHyoZ;-Y{Q! zC&&$oPO+fn+&KrLIv!2Vwm@elF@kb+RMW2)D8flnfs;(}65ws*7J`Kn%LdGR7Hjqv z49AT?t%7^y*==1s@{O{X@Q@%Wc#iaQGwN3(E+Yj)Tg8*#-VCJ?o(EC>U{V$73w@?P zCC7c&(Z8!n)a89)tAGBOu#bd(3##T&XW9>||5d)Gm-`nT!4v~($b*~;rCODo{brQzj6uV9qk zeF?s+f_ban`p>F84{$ify;jbuAcuFyG5{8@Lu&836VBooAPD z_6V2&N+cT};O{9ZRI)=ksAGyU)X)*&FOp^0LKxBt7pKUw;O z|LhZmZ2WI=f?U0VNl*W)zh0dIMt&CN5#O1tgf*^<7-)bo@HABwgBQK>(l2Y~w$oH) z#c8Qz_J6Ane6(!qJR+09%|KN!Qw@ziP_kcvDkBqaq4gz9^1sVL&5{gb?1pDiPhf0$ z+p0Y2aopa%6bQ1#IVONY_Be1mVjr61IRRA8lQPK(wJ#Vg_pvTDj{|OmT)A3TM#Z{Sq(If6Q}6t5yb60~7n+`ajp_>FKd@Og=OzSd$*4=6=Yym*Z&bg=lk@}<$qlECC z$wT{0p>Xq=`~25%7kROPA$lD>U#nYd2zgdhKktFm;?aQpG---6N)z2w%v*Ml)BYj( z3xycDWC^W@CPRZNi>AVc>FZ5beal(FyoLJ00gSCA% zISJykQyw$AAksbB2Ai+&;j%KtsT`#vhbjr~-d1zMU=|mDN!{|z0#ztH>{Yt8#-mEZ zFN-}LAPpp8B}u1&_~uEou?$7S@r@&Wg|2Mxz07+gci7mU#{fsQo2GHrm`}i_m-+@L zFtqvF&(14MJ|H~T2yj{LosWNY^;#JC1d0Qo8&~?y>v)d~jZHxWQmZvmHtB|2J;L<0 zYwWMCu_}_Pg)RUm&mUhV3}%Wc^mp_R5j2DDh|9Q4+DT2=KTr$M-Aj5Y!HRe?4Z~>z z)#dqGhbb+QJsRYUSddc^bU@c3SJG;0F6T>|c)Hz#o)&n?vR;$5O4+~AUEc4LJ+CU; z%oh$$0}_1aosopQ%X2;ZW$bTI&n=&}Po<&a=< zTQL9Z-MFnx`_mMBfImP zrsCFJ79#$W^;**3As%XVxOKVbk#iSQL0{>3b;`~fR~*?nvXojhl+&7arOT6x=XGfh zxr#v2x+l9U;HO7Z%xzQ$P`E1!KW(1My~22Z%ywTD4l z<%l{%LvuZV8g9V6HC_5QsP@VZlc%?0H-K=97_uNRhPkRexkf*7xK!ZYcR)@nYmy-F z*iXlP``@yg8srXl76gEyc+CXEJxkm8=1xo-+1{Wju6D0jTfufWJR77%aRS4+-n^Zf zf>_Ex*6hv*gFOHU#6LaE8bY7EHJZASd#o;(f zeMB~sDp1cw(TW&FUhg>yFFX) zn`|18zu%D6<80G!ZnHT;Ouw37=w=4EIw08Z+NcJx-Fi@f*XIT)7Pc>ibFX0g^q1-K z(M#?FQ`}EtYw4Wdnflk4@Bo&n-C}z+o5LdNBE;syaL4a>ecpFpdKIh|L4BuDgF5c94wC@@XNcEO~`o%=S<{7rTMDM`RmYA7AZIG+x#1kSlHlVhPF zpOZ>9S_B0G8(QN4V3pDy+r7NsWIXGuijQgApRjnFDu1aj;x!Kh4{VE8H`y+Ku9xw2 zH_Gv4YxaqnGeu2kv)TsAq0T#@V1R7))Ca7U0%V(zjna!E&J${yxHdniBRWnL9a2*7 zXDHprKEJ@NDl~GtD2q1$Q!<~?2W~>VN;9W&)dKzVrdBj=4=1`I*1xDGOJq}CAU-c0 z`7vaS5A4?GS!Je>qg}7iRFwO7rXO|#$7>Lqj_dD_wiOuFZnnE}XUbvI_trBu!6D|T z?>Nc+@iB&X3x`Q9pOZZZN!$x+D>XNIH@jba<{l{d@jVK`a?+x&By}+vlr@zr8r(+D zOzLK9T@zRBIb~0H4O|G74SROG9lIbZ+rKkeIQ-jUYQ;t^5u$Ip)=z{O1fNR6m07SE zsL+ij?~7!&Z!?(hjGfw#ow`IwUflrhwjOhA=;t8Wjo`HMg%HLd;lqh=uCW*uP}dfZ zcu{pIKcca^tzWo!!oRM5S3gB(_CUlyBn1>Ze+Yg=0#8M$BI`wPt@wriys%HhK4B8xOFi!?WA+ z$09)rVe+O_46vJkpo9&_(=hMZ)iSkGiz_wGW{_lcs@8H>$h_%rxXz*2AeCzqIxP~h zD`T8{BI;+4+9S@lQV>-ATr{18?ZM5Rtm=V-589#zoi!-D}i#@oFOjkU66vWGW#gpAx|aAz+5dmD0$cZ2S` z8mG1ET)P5THCym>wE`P+%VYYrL?0hzWqj7)TgP6;a2z2_&e$Z^S_ps9yU$~filVhXlvk{W zFLi}rP0o0p_R}!QhoXNTHAVvP+V1SjY~HIf+%5`n+K53P-ME;2t|<#RhLn>IwgxEr zF%H?#SE*>!a@GV*B)!kRMs~7q7<}?wBAFRu8WIA&1V}xyXJLba4lw(xU}gM6Fd*Ie z`KZI}3^E2;Ai9_a66^a$4r}Jc#KjcXuvsC?@kLq6OKG=I@>&BT(+_b32AXQi4t4~ufzh6`byEpR~6G1)jiAMvwdI? zEj|^;?ReZcQyflkd!9-;pc0Wh=~z(G@T*g$mMV1tvtbb(4Q|J^u2bf_~j3|GgXvNG@0Mf z{xS7D&d<;01Pn`>1^tk#+UO7et#cLl&B{}zR%OO|Qj51!e5*^LZAqZcLmy2aPuOhI zDBDqTS=a>w4?SHxhOiYwTtil$qkmXVXCLp|PelWRc(qdHhtpMS4XvgTvjrzPq9uYL z>rMZUOHG|Wy2_p6N`aut^?*v7S_6MduiTv+G_YwOX3kR<^vBIxKkoSf^-OOSx_cY% zRveZ^zBPEz=O|PA+aEWtujBSFIU`3}xa*QjOg~(!(KE3O$Umj(xp{wKx*ijGfIgS7 zIA}9ppG@&H&78Cz;P`>8@g${rZUxxBxSo0ysOpiIY@ekix}@1UgVQs=b$~JujlWal zdG>VB?Eb8BOoqH5kE+$TVy-0IJ2&$%BQ2LOCrV#Twz*qtEFIQO4GI;~K5^EAs>x^p z3#Ss}hCruJ!Xlo!RsLq7xoqL&00{~7t^AZGKIKN5ttFFfZbf-&vnQ$@qA@NgawZMn z?mlnUVtL;+GytKtz*b2nfGnF*haaYQqHDC>vEyqO^>JSy;ASrk$MvNcI@j5KXJY5F zy3qL}R}Fg##Nkl~(amB`r8U}Gp*rmc8alV~qR{4I(v#{o)KKO23Jvuei}C0nN$Kj@ z?a&flzE1MwNpheQq-V8vY1gr|>&fGV&)vNVIP(GBZg~n-)xzw8$D+A;1=ee$;oQ27 z`5Aas8*w&>mRIO!BQxgVnUd7Gvz2dAua#6?$dH^dV}qN7-?7 z4Y?klJv3X~SuAg^Zx#}?o$;f4kkkSJgKn&`n2B>}&M$smsv)EzLokw+UUMIRvLDsv z$G7>aefdDi{khHFU1D>MGO|qTaoOh+WFmxHE+rlW>mC_o`#k-GgCAb{5S9WyH|bSB zT0O)-SnCu#tgo{8GnfhHreY zrpYEcn`*j8K2bRMVq&N1N2}4s^OVTu6wC#f96VBDngzpjJGcSErx$S zCG5u?F2vnNZdVkwP?|$|%Lu_0VxCs>P)U3xjsC(UEu)Rb#n-2BZb!QB8Yl+I06sd+ zg%@1Ye0~`aY36YH+>0S{vWOQ)3YiH#SQh4PcmNndz3gE6OL0ZVjynQFpyaCE0I+#9 zq+V8F@aYoZNLRgl`45S4hpN!6?UCkEQ)QjotmnEJXr*WTqU8^(2Xbe;p`UNxxF+9T z2Nzy2S^i@V8gw!dEMO=j6Yqir*Q|qKhuZYKfFVmO9Qiz*?N6pkNziIOU0ch4 ze*F9YtcdkN0IZ*u09sW6lT7UO>ZjoHpG^O^HE39%pz8n2(5{zn&TZT7GW~0=tj(Qs z3ryE%_XpE;k%j;H`oljK`j6o<@qz=?zc%_mhWr2jHCU;SDI46|YCv~?BN%MxCIURN z|66wAXWdv(8MpZx6KnIg0oiX%mhL6T5aMVe+L6Y1Ek5zHSr+3;e9;=G zps9%`XGeUndM*zbF!Vg`U*>=Et8eud{V6(sVo$*|E9{6cX_^swYhvtvI@j&F%H)yu z98#uE!fThY=^Z`s206#cOk5;hzWvkQiLOgbu5xMrQ$n7XhAw1k6husNh|97(etKPp z^4~x4*=?*WRPEUQu(z6PvWK%~<2L|XMfAOyJ^b@^xymY@P_X%CwSAk(YFp-%=?9n3 z;3pIruQBPlSNEQ&)ByT(>f&6S7m(2>GpW!tZJo)s?@a~bNHFUgW9@(&@hCxAxD&q2 zfloLEg)K^}R&!86<6URMouikBrQF+OFVh;RIVQvwVQ17uX6;&hj3hn^eHK@0FwoM5 zzcssevf_A}73nwgJfZkf$CTNHzbnoZg;mP0*brJK+m)uZ4xEJ#uU1f~7VTXgj5VOT zpi;@yG0S5qSbBd(muFUJHkTo4{FBLPMT#jLbQxy2B99(6p`c^9=P0TPFut+W%{iW; z55x#Ym70g1sqP1)0F4U4X=08=Fd~-0Q`gS3bamJKanLWL$sKiis%Ri%sB7^6p)cOw z3$HxK!mlmh&pdVcsAEZSdU>8*R2FyKD??pz4AH+qeksWyAc_3k-?*1{Es^+k1yCNC zDRJP_mwAwneQWXD#1#4zYT$}hn3P<}c$N}w5XdW1dIbDpyXo(5+#~nyTHsJFw(&_< z+9Qo&!u_)sBroc8h3fxq+`!qV?EzQ1v4Typy=8DAF=WdXXmS0P_Cz1T{_4>dZ)AMxzP9>*f2Kd=s(3vB=z&pOlaz2^$Pt@%EO77kjn#~_V}5WJ%+&Zx47XAW07J{B z+W|wRP*bAOD+7Y~NGRvKa6m;!@ZIl=@o8@RHhP>;Ln5VQDgv!^zV?vR)m74*jggiq zE7A)D`np>DnXJllAILqe4HLGE1;^G69G7 zzlh$SpLDGCfy5aNU4IK9RexYjpVJHP_-(PwK)o>L{I`OOo3nd)LZ`oyv(FLFu$S_A zEUaAQ*JS&r-sUcu5V9oz4=Xwv@ z>tMI?3;fRm!)MOfy>+NaAT>aDPQCO8{JgQPOJMSe!)hX7KAc5*p3+*ag84y9k~ewLvIj_*P??pU zAKC?qx#&%^O7rXAj!wi^Bfm4z4%*90!!eqnn6gqQLHHp``B?rgN~$2M!E*63VroDw zq+!aY)ZgV@LAom?zK*g)OV$HsHq=c&jhzBs;h{%E{<8v=ONvXCr{<~=P9L2*HYLvk zu4JO1J{2iA{LtPns~4NvF3ll<8dD6g2R8)MbZ>q7a%7~Zyb zeUi;uA^sa}?Pg)`E!D^sv!4yLZ}=jFI#Gn7@H z?o72K57<*G&NqD1EK=R|yt8r-o45V^q~GZ!L$Xh@kGQ4P3n%m!TIyhD^2biPMcB}A zLXlYtYFY5S(&>5XoZBctl2oNZEw%k>&(wgU?^9$EL?d`Wq~+%+}K9yvTX07`sg6>JE?C0AX%bnXxPgS(<6uSlD&8ci!W%=fyy(*EU)7OtZ&J>x_}Z*0qtU3NdbbvF0-@X1+%M#2b))m>$6WtfO0 zwTBru`M<7cILkiN!tE)qgc(Ycw}$K@>>_FEtS4HBA&2?bv6%pCzr{1ciX>;=EI+eqHt>KJIr;~ckJ3QdLN2Jyx z@HZX3cy0TnK&iuN**62Z&w6nxf>ulk5+)# zgQDOojDY`lCLs{B&$;ktVmWVFGs0-V-D(5i-27<-a?bpnsd`M9z>d1wEuyy`Y21|e zY0hDU8gCCOLBe)mEO(8amwQIt&S}4`hYIhsR#~=sAj#j(swhwH`)Pe$^u2#zWy?0G zNF9dbjAiUx={&0`kSXgA=!HL_J4$#OXwZ9 zTK=nj3(fXki*&7<_(jNo;AF-DQ_h!DgxA$BK6;C|LXP#7>d`O)Gq z^zKMPd3mxu*57_Vd~p2Bcn8$neQdBrx;hOspw763kNpu<_xDv$FL8E}tI{rR)nLNk z!F1AFJ|W|7*YXqJob~4xajAC8Q%TZ^Hj>O8k00l%)ku2i$(s$6)=by^_sYEMMo#HT zisyPif+65HLYRtXx_m>$mx__ak4n~Da8ooPGB2%X{wW$@++q{frQl;MsUx{JV>>~i zJddu&BaFgmE{+bN`Y1akRwKNpqEy@C%Knm3124gorxuG%I?P`V>NOlZIN(8qXp^;N zej}+C>kQbv}H9`uAQ(&R0Z^CQVttyR%yi6|a7H)TY4nb~fc&0QJbw&`Q!-p@`ja$2s zfnk1T6SS=3iu26TgiB?i9(Au{h0v1-X-&}wZdSR;%2{@Gh-z&&&1~Rc7mSzz1jd@= z4p8ZVa7BVSfVp28Yfc^RA)?Rck>tN=T)iF@8tEj|U|@5@sg~LSU6N{VHxnu)jBM5( z);?83AaxnrjXaj$T4$WCcmo;Qf32QtCvW)A*V+xpB1^P?`_A<3?wC+WE@=Ga>Zr5T{Oo_^}>N&H*$jS#p_E6$XPR}*oevE#2cud#&)K5s^y{s*YIJn zNe>QB#u$hZoIs;-}edh#a5O)7pAW}4oonh~jzals>xg;tU4{5UnmT`Lj-n{QYW1BdPV_uJ?9!N)>odkq*Jr)n z6dY_weZ(puVbx$Bd~5%yHfn@X3Y_SG;c?F8zzN`@ibl+L z6diwO^86N4H}7g130b)M_;txm>e57@G7Y$ef77MLcU!*H$#dF0Ip}O#+XHBX?3mY-i3cCs4ewg9HfuDy9c$e1c!?U+W058E*`bQiyYF?f)9K%7>vswy&_nm2km)Srf zvfIkXNc;Rf!cBx+9MQfE_A}l~EH*%L>Aja*pbPy;^zLNLjl;JYyoHyBLHZjTmtkL4 zwu#Hy+x()m|14l7L6Kyz{(9y`+g6}lot}1EeMCvWZHRLpSh-xZdfpjdP!VyeeGwPo zF7mh8?y?61=>~FsF4ndJ1ugy`=H5H1iSAt+j=i9wAXNmVN@&uC4g%7G1gQ%aO?n5Z z3l>e0A`n379T5Tqgh=n8ROv1BCLKbTUj26Pd49j=ocEmbzTY2TnYBX5WM(pZ&o1}A z?(4em0V)9T7>XAiddrAIGhXX-Hs0TmLb24@u|v0k4DW`OkByHxzeh?xXkP0Bb(?fR zgG!Xw@f+sU6>SF`w6D}UL!>^9oPs3w3!NV1A-OQ;Y{h8z#ON5cT zTnl8?dx5@);_RQ?ZqUwz#lE@h>mOqd-GWcrQu&!w#I|96aChtW zu7phQUhZ3CE7Ppz%`F5Es?IJ7BMWs>2hHaqpEbphLZv&7cVc(-@yJT>#Z&p+p*nGx~4(dL~8b$+ixVp@&_T8sikvqap-b`?K zL==r#pOQew$)SYpX@0$$7449N8&|$~x==AlX5907+bXq06x7__a*qFpUutAxhJq)+ zhBR#4v<~hmiVRIYyS9WBYT$NDp}Q%Fi0DSD#3N{{c8o3H*;JobEP_=M2UJ`gXkE}+Xm1< zV`Xdvt{TjZ^G78Tu|q5#$7002AE!$SfU|c$7GVc%Xay&UXOdpICEO@ns9JS^HQt`& zJ%l`5lq9=-Ut3N^wvEt&)7iZ_0!rA;3-}gdnLM=@Bzzr&rlRmSj$&#}S9g~|y4I7F z>0QHaM_0SO3Lx)h)fUkA!9+4C$e=atW8+Txx#qpTJN)u-^AKu$0s>bgFa-LrrWPgi z>mT1?lhHFM$$;wKl~)@lIHT8#j^nY!%;oAHC*8e*-VXwrrYEQ)R`I2y5v~lRfu0h# z6^Uf4@ogksV~MUubO{ur=EKDpsZ3J3Ahc@fwX>Iw;pS{`V6nt|R!u2+2P*rq8j)#h z+K#rzf7eI6GSzlh(oEO%kFJC*KcsX9pgvJOz@)W{14o3SV7SEY3qn`%6@ zBp_t(egT=Gz_p%yi**zffq-(R#?C$upkmFpB_Q(@-HM6Qy2mNDI=rPr63m%-7y+Hg z6NcZg2gg1*(RG7T?}Bdj3SQAFgAb}Py74J`*dHg!F6EWuKG%Q4n$M+L%R(|pcqe&6FIqUK6L$kA25i=!>6iJRo52etW{RsX?4;|Tq?R# zsH7_jvu0eJZhcqKQRn68%{4X`8BgT!MH~_3)mt6K#pi@OPFu+g&She=IW%bJzm(o! zTjDH}>NA^;wb`vE)iFw5- zL*Q5j5m08}VI;WgkgqebLd|ThtCqOgB=XpqE!2I9n)kjSM}@j6=X)!=5rRANFiNcA zn7ST^4#uo8Q){7{jQ4B`O1N(i#NOTfUSY7MTN~TqCD``*hoa`6tA1>ayL{_0v#6VgE-^|`{hH#`sHyx6*VdP>Zeq8-j|`=oWrws z(ur!L66Tg{-Jw58z!dXdV)v=?7_r%7_QDyQeW9w)Tv!heGL>MLRSJ>r<&NO(`e*JM z>^k}^X&){_KW< z3L-pH5*P!!XKvaZ?lKo=cIlo=dd&js`EO;xAHNzYTyeMRrXTARBg2CgQ)A7Se#cv? zrTB%PO1l1Rl+2NxusPN8wl}e0enM&}PG@CffaI-SY7?OpcD}lLd zk~D{#t=8p!OQh7e6>H-A=WE%}B6Ts31p zev|}|0!&bRY-;tUer#>kZZaaRz~Z!2wQK)nuw*~b(DO5iqBxrWeG2V%u(h^A+*iJ* zeYw{{`Q+BHJ3e2U5HJL|M5*7-*_E0ZNp zmj-=_Nu|})r4p1~*1HHiG?b=frSZD(b)Iuao3bnCz6r;L%X%Py5@B=$9?^#bK)HzgL zB&XHFQOUtzZoPDrH)0ZzsA=Gi37e_r3N*xYhdA7%v~onAe!;1U)A{a|V((0A`TOS~ zQ|~sv%JuLHMDL}wq)BDn4mXx~$HcGFlP=lJlemzL>0B}17JN75?Z-(#v(#bRk z$h&zzS1rmuwRx~_3KQ}!GSVyD_f_riQ%|CM{9)6()9`4qx;&&xA6tNfHmi4eE;fe` z#JZp}Qd~Vf#X?Q9vkl(+n7z4WMB-XH*X#CC6N4Qea-AswwH?xI20CL%fz?l;X^Jfl5-L64rS0vN?~ctQGWYmZ(?Rl*@(v%I~fq`G03B)jk!qN znt@)I-{s4M$FZ^Otbss>RpUOxa&KE(m_n1awMB zWD<>z-M;PkAcndox0(s-|HE$q&!!QRIRW981u?C;wVFx^mM^EBo!cq73fZ7_+0OYJ z_D=M6?W%VBk0=uMnE_p;0!CD52dt70Qra5n-2-1aA;QjYfmAb3p(qPY9l>(NQ4@i<%!6@{fdt+xDpg0DumB(u9{Z}{pDO#g;Ax< z7XkhNYI|E8{j88GWkGj)8%PQyL@T4OGUeDinIbed{t$9Bo{Uvj5-2vA>4u8G) zVN|7+AyjxNqG};XC9)SXv75MmL8f(-wN8?8c2Wt7C;xO=E%r(7(bXh(#n^0uUn?Z9 zX>jR-JYYdQ`^(Km7E9loP(b}*w*8~{tq|P|k*W9;VamsoCmmZo@i(GQ2k=rS>dNa_ zRf?HU_g-Ci{|p3HVgxTHlF)0}P#}gCI%Kv6?SfJZ*hdEt_~`3b>x#%Vfa-A5RiU`x~em^W?i@x z?l&wJH%j0zjKCs7K&vs@aD8?W3{T);zqvAU&f>aE*biD0>`&Xe_|FeSUtyOQJYu>5 zO~Z0VM+4%u7--BIWifu@!j5K1#1t1_u(*W)PBa)y+XlGQ9>K_Uh&bNB>c94MCyQVy zYb{ct09s_ygD|{kkiQ#Jn`~q0`B&V$3NCu$f`BlIb_A1mr- zLj6iKD7&lbIq;o@QG2Jlb=@KZHG}srLutgu26CzTa?;u8y99jGLOv}_<&inJwGgs1 zQnK7X^P39_ZA)h|d8M54rHo@FmeDiYG^~C>yEo5ARXzGdDUm>F7MD*NdfY7?&6t-J zB3w;^H595WLnt=R8nac4Q)|p#V-E+Qy7RJTv>ioYqpKZBWRa5AKwjh1Urmru-Gbmk zng7~Qntg=&c!6qVZ|?ns#H0k}L=)4Lj)@4%T1^?dGAOFUR3*!rIyu>%?ICzU--SlP z`B$x6$@ZCE=DN5JE!bYkA`auXnWYC|39zTIM~#laoX&@F&OvH1?TQRNr`(v2vRZd}5dJo`b8b z)+&#j(KGs0ZNg(GC$s?=OmL?>1`hH(!}Ib$c9so>khj3LR5F}2HLdc@%`=z`FQC_XU(x2%@v&dn18b?UZ?8mDu1n%R2EfBL!=75$`m%r>~q z55lN&lypZ_6JACu^dByjz!QEM>Zg zXSTw5tPSDaM3j}kqA*SR-gag+w@eW@5oowfsooV;2<<~!)djm4Reu?sl1??ayC+A% zB1HbZo#;fx^2vO=t-a0OQep_SbTn2Ij!b?r;ZjiDB&--;qLP{RIUdoB(iX>8cs-j!d^#?1+al;O(nr7|6 z5k)+*8E^sHhAkm=YoN!?OwM>*Riq!n;#f~>h zDIMCYKj=H&Afcjj`b*Ix@I}#Zgk#P7%Ok5zDIIU4S7lLyfLsNxQ!aNAGrQ6!=7qE2w3B{kpNYuQ+Jyq7$ zro&hsYma7LQbme4s#y=zouZ<@jPrcoRmPM(frmgF`&_lnQ;{0XD?+luvZI`%Mpik9 zQ9*{cHnA!!B`q#TSAZ@Fd zyLKlRQg79_MYD>A^Ljie@SC3qaUG!=N{HHlM3cXZa*~S4d?|Ud`>4ooW5Nq?oD8Ij zRcASZeMea4&p$qs)wWS5ZosWHt=^{<5E)rGRA*9cJ6y$nq#$y4v&Xh{>giWp%;}5M zB*4EST-HB+avq8goWR%|MGp5HRGqx2`1A8jJ*aL+F&~oPd(TI}O|YFG?KfWE2PY!X zs;IzG7pRyDUIP9HxRN3u{-6qnvpN2zU0q@M$ytq&RgpyPmA0G{sfhG!8H{I zzo6AUqi!<;%{&3N-jLv9`vdy>rsK26LI49f8#EN#ezOJFisSqha*&P>tAJuUwrV@Q z(taKU2N0w7+;sJ-me1PkmnQv#-!+<0k{Y7$uA>VmXh> zS}Z=t)a)6+df4|&?h*b0erwRH&M}_rfA>*X;V=v~q>}jtrf7>_C$*L{x^Q_ShCsEv zzv#VQVJ4)x*G}kglk^} zQrJ@YiWOQkUI9pwG0#ufFtxqv^&gR^>tA}p zFHE;bVQ{JYIlz^IDIlX*lZeIJWKV)uIY$;3~4{VQ*O!zvq2gREjL zC45i1V_Oj$(rz^46h$X&{y&$epH@rUev4L+N@94Mwf^-bN(BD0n0lVlG#FxIV={?V zCUD76IJI59p>H8#?^!9BYbgbfuqPeye>ENH2a(aM)^HaJ*M#r`pA!b{S6f5~D~a7e zMR4YMf_sx3J|3|!_;g$eno{np>No8BQ@J;@Lnrf0zhPQH;F}Txcuas-$hHI(@akQk zuL-{(QG_QNGu3yOAuwnR(Y-M;P4G2FPvQ(r;mW)>NN0ocOc4Yw8oX1 z_cB(KEY&o^HCH|HKIWc8zhUxEF)gwZ{(R{{!oC(H=XK5n)22yxWqiX7? z6l?ZUFCMm|JRSWSJJVLLa8lx;TYMhlM#XjbN6*Du%lQm`!%ziNIUqX}AkEeKWg~$n zGrh084!iFylM_6Akb3(VzDH6Aq%2W#!w{Xna;QT!1-y9Tt0yvK>IF8Yx_DE3%CrE^ zQ|1B)ltu7n;~Zn2oUlV@rK)x=lgZdJTMB58EnT7IGl%Kd!r^lSG(o0F=G+= zxiSBeu;OqSX{xxVqTNBvc0&wAQz5>SVjC_)2LNJY7{KO_}NbWsg0Gsj(K4wi*VafrS0+Y?|adf?R=w} zg9~uJ$Ew?@d?|h!xk3t3QH-Bcnu-vge^_mS5E<8KF#698-CX1imn3Ic$g^A^k8R$U zp;vUso~WQ0wCg?7JKH((r$P!9dpX``srtJh_;YIeZkM+xo|#mX&sw!+uFoEN3e&tW z$qGm^^;nsdIE+r~(_AYXK7P=(`@nH!Xu;9qRr+_35Q0N!GMZ8T1Rk8q7_n-`8iZ_3ft8~IBs*& zeLpb2@?Dhp()6%6os3>{^38i$N@Bm7oAEtjH&iXP@0ma<`ZI^t#JfUT>-WAddoXdC zFTO?Z+k6eVw!U{D!nv-WR3=;)UG9vYNy}PrpJYMhzW=tzs;FqW`y~BlQAFEl$@8;I z*8(*bUHTT~ZVUZf0U0%&CxlBKF&>K*S-=OGP~KK9)a;ZcB+xpN>z1fXOZJq{Ql+ts zbs!?j*m_R(7QdB?xxo$M5%s8kRS40om?9MhDWbk?JXq0FTaFz#;vZAK?X_^EI0TmP zb(o>3jJYxUMEVWa7YUBGc9Lrhz0@~=AfamFjY8ZXd4l%E3ACb4adc_LOLq3S4#FxQ zM*dt@74TUn*4r8j*!egK`z`>oYlCAM^S6sX)G*rLn_mRmse~NFTOht<49eg#9==%T zc`NeKG~YiT-~n%UA091tyOAR>jcx&|bf7c{OjTVPnm6lR zTBiq1>~7eNF3pwfJgt%BB;*JpnB=#4CBLu!WrHLjiH#{){x!2%&&M=gv?16+SD}LQ z)j;FNKUT_Da+8ZT-&olGnEk+LC8k@mr4D~*vGS-ocDNxX$y7FTRttqa2T;{DVK(avK4N)kB+f0j$ z@DD-El3he@`hWaYU>ZT^_i~W{jA>~n;k!z;r%lWobfC3ZtYC2RyyZgNGU z((fe>bCkc==v50P|0_a=C;Uklk9GP%3`^b*v}Q8&5-aPFEc{W;@AG;_LZwCJ02zU` zf{3!KWy0kh+%pzNjMCebO7h#jtehZAdJ%3k0yN%N!AK`bptzU;=OH()MEYAH%63BU z2Em6YmBcX>u98CQw#$theW^o6@JoFl6cyBh+b$2T8$SF-*3CT@9Ab*oM%7-1HnOWG zJ}eUL$Eu!3;u!AcdTUMSIMLn2!gz0|wD6e&pW@c(%`@DwWau6pX-K1o&h?*yIGWchZNQPnzG*JHPcCRsk~9r^G99zM)IFB zETX@)O&1ATl0Ryyb7dm$x%%kqxhU!nPT5mAL2^^CrFlk!7Fv2vs0=lJYHkcgr^siW z(l5~G{H{yU5X((FL?7UOso4|1$qJ}Wa%!#B4b8^r36ZNe>Ostj^@-*s@MZ8LY9#zBLNd&lG&Y_|$no@PSHHl&Y$0>Aa()NH*IMN%8Y&4&lEbsDBvq zu#2>QBdZrKNU1cG3kPp3sU}U|5_yN|?unasxoE2IJ24^ ztU7Mcx4#-w7&9V(4w4yTCHcF;aV7(l>2Z-RBuB{>jGtnAvK|UhGFBC{)sXO~d;OOh;g6)?kLrv76aOTI%5BG9O849~{ueBMtE07QoOvUg=%uVi!ELrB z_EM%SFUq2kcM455)-~E!5+Kibau1&Vu<4(Mkgu+(7bRiEXZE^KWQV)UA&Ww&iqS}G zoY%EGyG2U1L4omzMnm>q#)xt_VGx@mk;33yP&IJ^L5hL(2 zjtbnezdPZ12V2u~IJH2|>1(++wcv<7jUio}FmW`J+cJ}I*%afMrF25UqhqJ6<^%2i33u8*S=*Cy>{Bw%~R|Ytv(K?h}&B z!nM~@j>D<8=~VVdh43qJSu$++8K^9}T+6^8(0ZI-M-BuANH|IfjKw(~g^Og1{r{sh z|GAuaxZbI#v5;Vd%tX>&%^Ih)T0Ul5a*}>&Gn57Dy>`n>C6TBEbv(;&QM^KcavUw!m9L1`(o)H4#j=*P_AY`+~mJ`;blDYy7a0!{o zRWZq+N3a{<7A`#_(vvglu@|17F>(yn9*+j^YlRB^{RqoF9DUBGYAxbp#^C2?pRrnxAk5#EkEBuapDR+A=9(wz&;R+Fl4!*N7 zI+jr><_8Bw8k5X7*t5Tie33miAmhznABbMUAd^1bPDBJWr-bNg&cL@rs08QL_gPAb zoEq#E6n38R5c98$7uyqB7k6`6*%%E=2Gg|h6@Eq6rTAuJgy~hwq#wb+YG<8_4}LUNU*K`GGY=xFjaVFx?j^oaX?uOq8;JJc|U?}$F1|SN%!boOJ}716i%Px7w53oltIu3V`=(G~F2fq(HjFjv9CP-z* ziW*9K5aF4Z3D@Z&L_@FYmJrlh(yi$VY4*A$*%4E*YbZ7y96ZcSE*`JDw-b;`z;4CVA(!h=oG4^FSpf1oZ;S42Q@P``$JG*U-|x=}Kmh(O*_^qh0p+&f1SbFg^dIx>#c+xHGAWJc8EM|QvId_8|Ay6e5>LuWQ&4&2 z9vFBXP*V{yG^W{#`_r(!V6>mH&!b3V1nD11%?niAE&_1x>mSt}j2$cj{)mKOkC*;1 zx{MAMXsAP=UXp?5tC76Y#6tDkwz{pwehZk~))87ScnKrU9@A6*8iNb7Dzx4fSbAk? zSTWymdfP9Hxt2V_g9_JZAWwae&zX)_8Aw_czewqN#^SOIsZV}P#4CfP82-62Wtnr^ zcv6Weh>TE3PpH>(od40e67V1QbRk~6dm6FN3bFRbn42^9x+^mB7EgR^ZgPN^aH}sh zlN2RDUJ7WW2Cbh88Xhj)?VxNfm_Z9K5yGv;5~~|-i95P7-2TSB4S0(y$`a*pl6SEi zn6>4O*5JK&L2{$ieg4A9sMnmu#?fOup>-XZbYZiLYh>^ei|zt9GDxLubusp|YsM`p zBokC|+PAcTZ@qSY8Dn)BTnFBP`RUj5Nr@p%EBO3ugr|@zo78R^#k(XpTXt(MmnzRx zplO2)wjJ-l<>iUovtFsL`5^}!r1Y#KdT!u31bz5lp98^UIo~8ixAO1pMXpLE9Y7Sv zHqEb+uuKgYk4ph*#K(}c_7P5s2kUkRfPOlEM&5#o_l^g^^JSlTEmS=qcqQ_%F$qqTZN zl8zotYB;67t#4cZGKO0c60vT*XOigWen+p*oPB+@*~#VM$jb|t-@q72?|_7vmmBKn z)TwS|a+LYo*1C_RL-9@m1wOq7`y&S_u{WpV*u5#%%&FE`E`Dnk$Gx&r3{lgS_M1+F z66yzLKDYr_nHKI{lZPaf9;$JRtJ3IkNL}^T8D>}~x#c{`_x@N_* zmF)n%IOO*+G;u1}QyPR|?eOV8FY_zHPR+-(<>{_#Cpy8Ee6Pu#%f-6ry zf0CgVHdCI$#J+1#J_3=H=x1=;W7ELD>QKQcjW}&GZ#a^N^hC<@R zM(v$H^Q4{UNH9-PMJUwXOW|NI8O;D!XYC0?SpDd@4$;53^$qqPw+mJmahJppAJIg` zhWkeX3jyM%v5Zb6i=FpmQRXxqs%Wa_)s^E3x~Ka&;>L;RayIym*X>&SZI+J@yJBlp zwuzzi1)&Q44pR^ArK1O)Qwu`(#+N+?{&~jV0=WO-1W`SfFNwPhlNRZ z510}-40{d<>+i~Sh~dNI7Un&;qgPwfmu$Cv;^yR>&>QNW4U^f2VRrwYoIuVK(P#7b zJ#8MJmt5HUSb2eaBkIgpDE?2CtcrtDeEbpA2P)7I+;EEk+XxD4CPpW1pLo*x|57QO zJv*?~hFEWCN9gdMPl|hd$@RcyWVHwyDigT}KQMLAh>9rbTd*+o;9;VO{sobgpFiuH zes*%#n)*{X9bD){lD}+LdR5K2>t9c;Rg4W~V;qeu{>yr3p%+Q!0__NBCOe!QYvP4;P6z+g5aAm-@D0P{(qZVG zuB`T0>HB!KKvwl&4=6}i+<(Ua)GqbQ)WUUp)%;xjW;MBh%>2oKJ?uvp`RukI%^B*Z zCNBvSNF&L4&X-XDB_0TusLbSFU18deM@xpya#sQy`G?ITBMuC&j_%sD`e(h<;G*6Yzven2yK$)1 z2`{f!Tx0O-yu2;BSK*!1J7+O%s!Wtz)rnX`i_$`8-oN_!){FboiaZN9_ZbZN`W!Sh z=SnYE4;@6OhG!QI?>3kGIOq35K&<{&;5=lHd~};nfFnMJ}wHc9;BSC_Rz%l-1-9IO#}lCS4e8lHO=chdV{29UEAp zm6Um7jqr>(3{E8q@U#i5fVeLAk-~{@urF_uh`fIjH!8$oY&uUhmt zDvT6e~F&CfBnCshW|hGrKY7xEK@o=8gQXf7oPXGa_ZmW zOmh+Pyv^kqn=3{Z(~|Nt=!;3Bk`t8jzMW#nUsM^&X%0ag0YL#1{ua^4b7=u13ApWh zOibj<=#;73J9Teu`PtalIn+u$JO%pBF5Eq$r5o9ATG@i0XijrJO>|s^oOJh0j-^5H z+nH9wmDh=~)_l20?J2P`hLMA<1R8y07=>Re!k!0h(Ybwe5WV+~=kIi?io#Me^K#!zyA@5If24dpZ1Mb7)RQ4eO&6+DvyzjnJ7ft5z#)d@l2tBg!OE zkL(3c)pU%n?E%dO9@rgPP(?-u5Z#?w zc2}BmoAcwIZMm$1s~PLvtNG7E{Ir=uMc^(J?xOmnf1KJ@emP1JH*Zt}G@B*E;W=cJhECyQ7a#IrNTCJ3%C_ z;C7Bu=3qdn`$BjNXJ#|Yroo)G_m1MLVsV9eUh5#-{)2>k&n5t9TnI`Z%Dza@Vm`ar zGtYRIooSJ0QW+DXlq<4*D{5C*7b3}h*NWWt?0i8%od0!8nY%X+612L}CX`$(=u*Dx z-HWDTES0SxQ*~&+G~WNq(Nnc78RuGAFzSz>bQ>jg^wG5LO2@E$4vtwZM2LPd`uuTe z$q-{`923Etckj+Us7c~S^k>FzUr``3;5&lOqoQ$~S-b$$icl)+#6!&Plh;mp^uO%r zP#K+l$O^X9(CTf!Kc=Gii+SVq?$s-wU^fUB_T3+iX99D^dSgda+!CROl(A4+6!chm zSk|Hy?L0A=DIkSPu~d2IQT}-aEKeR@Rt+plyU7hP2ElyKF_EClf5vxGWm);le7R&o$0}pwSmb0qA(~&749ud1Y^*NHp>e4`Q&VA*e|zcwVrs zqt_*O5JM$J;%W)7BI=up`hHT85mifS*K~;4pJUYOksLJ-MOeMPufB+j>qO+kg?6+p zD)`HK3L9rO3nQ`uRok}|`EB}!QhQp0-9%+TdU@5CsM4H4dyO4YPi*k_W(O50rgl<* zvG3SRwwhF7e@HLCa5<|Yfl`+N9juLp;?F$0)sEYHX}zONa+_P{>zI3&Aa@BOhB2dz zxqfrr(AHMTB2B37<%_Cr9Ozh|{&UCr4U_SiG7H>b@S!*b`d+UDy6O zS3d86xI{aQ8N-*wC@UxKjutHhT_quaQ5+mkf!_)^3`T1+pgfGFdd8PsIP6;6cJ--8 z9Jc`o&%>a$|Jin??#7ucdeCB<3)n|(AcK>;@;Ja-K0#z^{;@5z84DrEKILt;CrZ?P zLy4x|%qcqY%hRXRtD$Y`j}fhswa{?9x(fTZ%_O;d(HIT^!2^A|kS4?csr<$(K_yWU zq}>{CIx_0^4SmFlKcywTZ>svu)4$;~6O+~FEYv|D$fqJi;piz}S!&nxmXic(+Ig}_2*&h-NZ zKl{o*`__5O?kLB8Hy09c>BKub82ENMB0&)8+zUH5&m`QV=}g8TdU=SU(c@CH;QgmA z@aghW(tDiz0cXw?hNqak=4E6U(^N?VqNtmOtarbNaHo;aQ88nn5b`_*-P-E9G zxha^gi?ghGW;rEkUhvit29qaxN&d3%_ zc~HK&t|YD)Zv$N1Z=4?mK?Z4zij}7~p2rE=3n3SFqhlGsG6gM?g{k@JuWS)KIrj9; zbr=zUj#0kO@2-=_AhXYhJ4Hd_O_`O+b;(1jJ`c3|Fp*}wv-%? zKqxOz$bZoc0m4jTtP-0>(cYPh&KXY)){U%4NG9@hgq#2@qY{!VXY$U{MX=cXZ6i{B z{tbpop}H(Y(>rrJjQ4g7nM2s9EO&Z5wxg81c<^z3GMU+78MKiWNd47?t&CN$3LDIC zd&2I{A0ESXDIx^%YlY^ZF*UR#yzaS;kWe>AF`&FZ_~p1rrBHWm7oK*<;Ig~d#X<#{ z2{*BZ-jq`KD1#nV0VhwEsaf0f$`iGAmbBc!TzF*Lx>2)wv@nKkxK*t#+nD<1c)HWe z=KyPsBz**fox?-KF`sXnhx6xLCIc?8zk4ouLVfYjMv-hc&zzoen%vF)8+7iq#rkiT zPOmFzJ4u$9calB08e(_kH?b>(4gYCBk#{7q&2aert?sYEQ@X>%>fluM5eI8b9V>`1 zl~M&3OVvk7K^{sCMH0TXwK8Xmh+xc3ZnfMo1WyK_E5 z)5RMj| z#17E&Xn(8=tE;NA3-d}!fVgM8(!LF$N9xJ??VITidIvChrUttNn^ry5+WAqe!ej3SCAP!rrvH8YHkFf37BS; zsm$6S15QmYq*FIpGQRqGnrQb=X!Y@p#qe*t`d6s6YFRPb56wWvY-zjE0_OZvc@Ps{ z{>Txc{C3s!2kgS5JcYJokUhKlbD|<%E0BpS0om$gZ=^z;rI`9L=kyaGokAs({l_c~ zr}1gBW%pVPw{#_lft6)>2rJnAFW%eLB#5ArZy zNn*Jr1@J;#@3Eay?Q!U)0jW&u(jd&!_7tJxGH8d3%k=4X1LDi<`xxpWcM%Yynlh&x z?}TC-Xvm&0RrCDOz|Lha@Lo$tZ?4tj^eQK1t2(OSZiC>2sT1V$?blrwue*l=Ai~N? zU0F@7+#S_3GwkevH}fi*xt687u|WvIRecn1vRccGoiR*Qh0+I`X!UtK;>mWaSa@sl z+b|qA<~_!5Z8)0xTm>M^yje##r=CjC=nOqS?R@mUVe7K1RD{Wh{{AJAaa0I|GtsHd zn6L{1(JaDD%Gf^I9T9ex3k`^PeZ*$o>%al`_QuK!7EvK3v|E?I$GO5{kj<&h~Txwm?f!Z{+(7_r| zOkb;&1PX?Dj*c?dl95gfl*1ptQqfyELDLo{mb*A(s$gXc;y227xDIP^!VD|0-Z54b`W$CP4j3scuDJSMEJ8}7);>?(`U(yU3t)`FT#k_ zFAiL!vN3m{POT2Dw$`S=WVysU$!I+|thQ6)GHDxwN`F}DJfjV$=atR1I|`|3z){4S z=|okH_vNa7&ST7CGjMVu%;5kr%s4|A4`y|plt$LjV4XPnH@GR0-jJ+(Ul=yt(Y|1@ zB5ahB)v!>sFS_IB-7&8hOe`E)1b-lpd@3-^{fv&NX{c2rFbPWATRv*J4}JI?%Rw-q z=QF#*_-3BkaCK9IG1HSPC2vE#TpqVU1CcifRRac8sb@LaqVlL^zgVplm3i2Cy{-=b0x`c`w=> z6^ZVcUBQ?@v}U(}0uhKtALRfsV$gRxE1D7-La@xCnDi36(8f>c=ezLz?*_N=IV21VFG9FkFDXrEMN_aF5$nYqe0!W*X_BW<&#NEY)K&^BBT(7|D( zH$obqhP{tbX{sZiusPhX&**|?y0DWUzYjP>uI5gUs)mb0@+DdxTA70n4RMe1M!UFc zYFvcja9&G(@BQWV)A6D(jn*(!Zv7Fb`X+HcUcS5j(~9w;Dz<3%bte+ZZ>p+$xMHjm z=0J_x!Y3WDeTj;J!Uc|al1Tk#(?j;-9Q^fI+?x;v_|O!NAb(F2W4Tdyxf~T+zxtSd z5-N|(KuM#nGi$Q*{g77F^lzB2$Z5rI*r~GQ4IwEW&qRfos&PMDjA{D9+YY|ujlnaK zgGi_X$lDixUI#0{OXL%w-gGPxo|Bolv9^g$eY$ZB-d4G?@w9N9t&TXb+HazS;DmZZ zHW5iMY5ta-!hl--?~e&i_9dPtN=2$Z!KW{#aix)X+srkLfX9d8t5+cKY+gL*ruBY; zu>g?8dy^)7__K&oKPC2v`Je3^*9m=dK2;^~x#NMow|C~gFQ40=cL;tgyJlb;_v|v5 zQ3-1jFdnWr%QN014F8`m1O^G1cFY-#t;PyW${7dAYU;)>oPJVzWi(p0W{h31Gt{)n z9;+|@9M%9*oPfy3c0X(l)Db9j7q@*cWr~?o$?j7D=81S(VqTNEIx!-&oqX4x=&c;S zqlA|YI1KaLsO*5Sif`e9E>#;+#tFl^3%f)Lx*$mjxd+J6^GK_cvdJQ1hwIMK?(-+e ziJ_k2$D&&Y`nlgQMc&+2qYt5prpamiZHA?-;KH6ELSMOHS$JNKzdG{&=Iy_Q6d1ZT zC6*(0%|8#HBcy7GoaRW}wd|)H&;E%e80k$0=t8sJvV19e5Ks7X*5m6x0LxA_G`10_ zPzO62KRmC(_CzpEc>8?{BdmZy&Z_5s-juqUfdGL4$00qB0lcWtW9df0#Sx;Gty&h} zJm^Na3aWrIOkxj`k?oFwA~5f*I)BwFc(L2Q+H`EHl5?)K_da6Uu>N*9AZMNGm4fk$ylzsCD9Q#9CPnk z!kx2(w*akiY(}uGbgOElOMhF%i!9=#vr-Fb7FvsOt}`H7IADG`_c3dAs$l$14yLiZ zo47&Kd+HTj7$=A-(1HYm22>jb)qiRQxvDQxR=9>IyW*;pOoj$8OpCW{@|mx$*;`v2 zzc?7(%PE}6y+@hdk5Exj@zuW}LjhsfUH&ij-UBF#t!o<{P|S#cWCbN>BsE!3BnwEI zk|Ie?f)Wb~2`V{CmMjbiLzFC8NfIOvAXzdDIcLt@4d^-Neb4*V_x*Km{r|mnyBMZ> zcTdOFYp=c5dY&a@z$!oRJSVFH+L7+k5jIa56pJ=;DJWdxI1nv8?s{hTxXH(X$ef{} zfzW=!P=KCr5TRP0qxt&_mWk1;da4F_!@=d(NUk@c91BdKPBcsUW&XME#Y8Gr9GAU@ zpV(Q=@Fv#{x|vmXlPu=8l&i;8q>~;ILg@31h9YhI`$r!Th(G&QS{g~oHzmCaE63@N zXI>h0qwV{7Kb~}_=Zyah?D?GAR{p^$qJZc7wX?nl6*6J(*7Rhy_vPHVU1a%%j;0;N>LR`MThmB(g@HH|(d+D?>QtR&DhQ(kDta2)f>L7{ zs*(Nm`|q}{svBttv5CnWrilWua{Ob6Jnf;-r=scLcs*ft`ZW4#w4I34=dy;hGI=Ls zD#g~=89n)zZ?+;kVp)T^q1d9HHU?GVu<+>vekywoHR5ZcDES;syW%M6KM+lU?Dwit zXMJXdoU2*HH`tI4BHEwc+SE8B6?SjQPB4B_iG(6Y!ZjDN^c>7xMnmV!OJkAlp(O|r z=}+)|!9}8ANEj=e9e*bxq5X|~YZxPoiFQ=7G*a*C9K;=EyjtbRuO*Tn&?Cv7#=vAQ z2Hm$=>?mvo(@3{$i8so3G6&q}ansF=u9P~n*av}( z6WJk7fMg|II;k)`M^r=Ec>ZBrj%wO!R}`ThUwnMTTpksu)js2hV5o>j;P@gC_)sw& ziE5g&K6G83SKc-%AYsMbhf$Ae*$SZmA%IKb@0Jevyh{2*&wHCJwL!u!pLnvQqRvN# zDLe|j(**pte3*a_m%%Ps1%<|)OlZ72ZIZ*@)S-XQ)y6YJq^e#*CMx~~Dk1fe-R7wS z<(HMd{M|JK-zG5SC{0yS7!)ombcL0BVP;;QDb z_J^JXmmOcEj!0c2oY`yI3{bE3-B3?h<8~huV_o5TWa^Lg7aa8`k$oGnERcI9egRjdD3Mhq3rwa@!K(=x87}9XuS2dmBYQO)!j4+E+VOMrpkvd=?KLGG zLSG!dd>hrkKHyTlMksk9vuJxK{46xPY36CrDpO zN&i}8+G@?{>OL_ZVBaYCF@jg1d|L0on~v?TVAp?HK%*M$(-yeag<+KJr6(C%o?(N- z-;>#MC)s{@yz0QKyLa5?8r#B$StE4NPO|cy7#(J-N|0IMC+pJW`o8Z7aDI}8gg)xR z_m}JkM|#Y+7RSDO#?AS^oh=rR9n(*2U(I|!*HT(N@maZ0oyq6Rv(=s~WNNZkZ5@YT zx4*wNi}bd?l@xuL-Xj>$XsGL-W-c|#g_?JP_FZaKUH^m_OKJl&_TOO50`qZwnBd+w!HE!#Q_O9TS81BqbCiy&;a8rfJQe8Dq2A=$ehPQAV*fPdT&2feDb-uKDcx~fJzvthjm z9NZPdo#T+kR>&SzLs&3m_+1=|njS3flA; zv=q}r!=px{-Z6f(CV%7xL_%jya}T)Ydd7!oNWM6k5+-ZCUZpJhEO4<-HI4kBgbM#* z0zVl;J5r(OI=kVod{9VLyN?h<>AcgulIPHCc0hCg)7|qyXK6 zJ=HzMSyb}S`+d=ttomHPaCILep-gG(grj?pq}PH`1fTi`3^0L>0MjF@Ix7_}ZljZPWWY|gNt|F`bPZasOihMIIGC3V;qF=V85l*0tcFWqm zh{h>)mFk<3iQ9n2R1V1zM52Q=821Y}Kw+5{-ih?iao0bjfYWV2;2BV!)t84szE98& z*qYZ>P{noCk@rWF1RL|msgm{jOS_wZ@R7M?Tdcr4;leL|sc$Pc?>mTNd@7&p0aUpv zPs=uY%QmQ{%DKaR&_Ix&ymj|<18?Zl|JHV-)l{_j1!$BRpxe&6reSv-y`W}y@^|9K;Y;Mqjk_AnG23vWH){rccP>GASvpudPb!6G# zsXytVg*%$~^p^UzY%_t73p~#Mm#09XTlfF3_`6{KH*QI~rNWF%#*+D~rY%w<&1l#w z02TQpiUHIkjM)T^8t;)Laa>*iKuncSWj_|2|D4al8|0l%sln2fM&9GeLEdcV~z(CtBqvN z-k*Cd+fYGOz`*mzL><(+%xBNl&zsiU>3B3TYv-N04_SV=uN&En?cw$48}TBXhYrIt zrf&;Wbrj6Fo~(XKhN8JNb`~vGmzR`Rcx_6{(60m0jp^oOG=A9Z=Vf*6#lt_)*)etN z5CPP+wx#Fx{iM94$1~(=Z#8O{#}3fLg{6z+`E9Y1W)NTFc-{)sg@d_3v>s7gMXm|u zQ-2C~YH-4u6U;hpqd@dg0X34?b}oGwuUSZQb{W)blCx?@vhjI_qIrf4FoE57x6>v7 zm4lT+P>D_IvTkZFDWBi6g-HSjoV9G*N=`Z4F0t zKb|R_$2K>4xrTcBzrTGfSQRuo99ow&A+A=mpxVqeShq#zC0tY?bMVx1=FxZ$W~0bl zxv%T+@(ITMLi6}2W$}^ED!{RG?mWX49V`WpUCDVb=}9`U?Qc)Qwu zBj3{J*|_BBng(}q!PsP;T8)4^spImFsepH1+L~J*4VvocgVFB z0^P#$T!xIlyPY8w_+~m{+`u|USlhuoe(&WqC)dOvzkpM{eJ@8w)ZG#vTA`)9&Si)J zMOU3jGNX;fmuuEp^KY`(yiiu=Vbda%EJ#{H@93>?1gk2|#;YV+`!p}~=VqxN6)SBV zfw;v}|2@5>O!FBdC|<-OiE>4p1|6*C4Xtqqh*cV77u}D!l*MuVX8zOcj$_8$YDbNU zHKh9*zq=L-@Zz&>0=_V*=g>{M{FJr#tu?#lW7~o3COiwroTW!7Zo!t7aZuzux0rEpo!3kOTjsZq?Y*U#>$S zgF}uKT=Lm<8J=FHA#T&3ZTe6i=w@U0Vge&Gw@4*fe>4Zy8;H1n0|$8TI#I3n4ZR=p z+;s9-nrp;>#aQ~Ke@hW>=GM|~ueci1+3p}5BmKzdMoSBa*d%oDXiYo#N#NDH|KDx$ z?azyG8wAfH@cmA7hWWKDLyUBecGh-Sk8MkiR^FfjI#{fCPSc`FNm6#AC^!}^!WFC| z?F=aTGC}r?r6wiv(QHzpj%=jdwEL~1VM5M@O$K@*8O9*_#5F*?u(BoQX`#Mz|F9zD z+nm#&csJd`ar&o_P4QLnb?(MAr_g$$O653>dT7b?z#?Jxpu;wCO>b8H=&}D;fcT2| z1}mhB6chF@eduy3&c7ZzUeu#$EpkC`HWENcB$u^6@ZFn>BvE{g-$AdsZTapl6Ay4W zqHH~pN!d}ClO2f&r#bMq z0vm?*HD2^J?|j$W${fpikMw9|cVwb>a-*2S@Kf{c;G=8O zbOm~)Ku$s@xXDgt@+4QIlS8q=cJi~FD$tzq-=&H0|D6){?}G9<3t4cKy}7~Dm7~RT zl)bgVOVkCChB!m<+o5gdw|6m#8f&eJ%_mf|Ar26c-D0qsZ2T|w*>`yF3YbI>*RhYV z>djoikob+0bj^r&a@rfjd0L`1R$_W9Jh@daZhU|~f!1{oD#(+}4a*->(V}dxayjN# z#xyxB46Okbp@IeBYS|wuTBK2I!~?Czw7H3nHmnBuLSu(gId$1EVmN_W`|p>sUJV?7d~)@!(Z4kq?ZnG~{vd{^eu5p4 zRjDcSG6T=~wXA0;B|-&gk(yv=8Bn|(mcQ$%n5qTLQ!gZwjZ782GUSFN!mGWcOj=GE zM9i)P*>1zUvls6ClcyGE?p!BPpp)`E_m=Q6LFbgdcTaQsC)6K` zVe$x|h3|k5!cd%Mo!f1JXY%x$a9br_EW!vv6d}HVt^P8xU3r&T5vm?@Nc-F*&8^H77BFHr3f34 z;UycAx1U%m-U+I*0gwLLrhBSP|B$&u&9ZnP?vS8==Qz_sYAqc#Tu6;M z=(OIw>DGEaT#|lj)klhf;z(gBmdlI_qcWd?CW+JLfBV0Q zGk2ML{7gI~!@UBd7zG0KLVI83CZ=hWM;eHw+Ub6%oa^%u>W+u{IBu2?=Zi!!xp^RD zVgCg9WSpbe1*MDvb~K~UW}b!=1dcDFXhCf0!oMBwFAbnKL&LXI^4ezCa^AyM4J`7k z9}^MGo`Z4J0N&47mh#)vN~`h>bwqo=2J3POAVB^=oCA5mO)7yEPV1oOK`%t0mL1EN z#n-Q2~G$idL?L~5Et(hLp9vdrR=OBm94~S3U%D!%wzr+6C`89&CLhn|- z^-@KMy+!$KP>?M#4uOO;2@fPu)bxi>y-`YH8%L|zBk6(IKqPJ|i{dTY&r+zgA-)kI8+@%oq z2ZH|PJ>6EDL;Ks$N%+Rw_57o0iEWc#B=3?-tD-&ok7E8nv;r}Cm`x&F=&6G->UP;+ zevD$4tA!c{_TSk@OMWWHMP^~%fKSxbHQhrod`K8&>YpBas}jtmupCh`CUwy}n0URD&T;NO~k7C49 z=OM$K5rn!;P^;@LlPQ#kZi!ZvI8XkMCwlUhHDtG9?){QK&sa~R9(f4(-R{L^q)cq+ zDcA`u&hS=HV>jt@Fhqfa0VN@!&eBibpanlSLULJ*cI{fAm%)R@vh_rzU5do47lJd7 zgh-RzbhEQM7jk`EDV3jW5`;qplEzfbsWsPieTdRs_Y=z8ZdF}pP&(Lx?j32Cc`d7p zAs{M~3GQ*B2|By%?v_1{>q^8?v;x9y*?F;@A8U&IZ9xB&chWzhlIz5s#&j?ETsxX{ zb)w{VEwRfwcpiq#c!SKy{$MBsP3H&fJpSD7u=m{HsEfv!qHaK1>cdrue|{0qDOz}! z|GGsuAB&M>S{@+yt5*2fV-qp>4RV-Iotj$8GPx!u+w(Rs`x%Nw-q|=A>epcRRqxik z9K;tTDZueumw({_M3PRj87@WY0UgO&97!PFU50hZ3B>3cFBHrWb*mESkVTu4czu&3 zy5R6?Z$WpIew>;n%S>H0c-P^gjkSu}oo)7K`3(=rsoQ{hS3kT{AfvBtm z@h%vjUV3T(2il8YhA5~rW~$R!b>t8?o*~MIb*wLg@Bko=!EyKuR0s%971A!eJUd$) zkFShu&DBOb$W)^QfULL$Ab>(b3@sC?fl!Q+&6^6-MdFxY@4uTBZ9{;pQNQI zgS|ebsdtd*<6%&7{oI?JYwTGXk^WRDW?_g|qK#6k_WQc#eMd|$X;eX{WiDABd` z53j1%~J<#!8pr~liFPe>FR z_DODp-j5##UE?~lk-)Ju0o^^A{*&!zRi)Dq^#$JIKTo)z3rvN@`xn;6r9o_SkdPMu)SjIVtm{II5J zkUgwr(Nu8C@vm}jFBa}Xu!z8Mb^@>VUv0Y#{sAsYHj9OrQ|k^SquNp-F>i_SdR`6S z4;-?$$y`~GZ;`vLEq?xO&@BJQDWz{p6x8!0+>g}XFQ{a)GY0l3Y1G*by!ud86&c=dn|fj%EzQQIlM6LB z3bU<0DhK>PLh5m0T_wvZX28zuli^Oa7fZ_1B~QPEj5jQRSueOh4$r4iXlXPjntJ?! zczoEQ$U&3b-e~@0YBDm*CD?N22f-5~KZ(<94j8?oPgI_WJQ3ei*hYPbf%UmPU;bD( z1#H*-PlOo0fZNwkZBs#0K=1jbGi#|ZL2t;&<4Vha5RZ!=2qfhBA!jJjn=nM51_Zlj zqg^({NW{N{BqQlkSQ|EF?qZu5ut%~SQXU8dJgQ4MQMvcpmQMxtPrhcSMIkshsjDKGU9iXpzNFzNG16=`Q=Dl)=%VzltcISh(G( zh@O-yqQ}c9A7;!gdviVV>bAvs6Zhq?q|M)TU?$uDK!SNQeSUZO0^JZI_=UYiqNx_e}_U$u{VqH3O!}lzkKlkC&L> z)OF1kA%-;$8b4-WY4pH0QZccmXjzWt75RNsZu#x4&Yo}XvL;+3Cfb(DHx|E(m$&)4 zFc0~B3J|YzJ2gB?`c00mGe{Spyw+e&Q3k~Lg4lNym2Npzs-iT<#U}EKQK^cRqZAEC;gP^+-MdZbV_^^ zr{n3Ib0uGl5XqGy1oD#}z#j{CiGLQ|V5ldMy=Tg%8|wTz`L{YZk^gJWE#^8Vq5Oy%OVVD$CVMYT#dLn4dJEv+xVIIjbUMxIoVvgoh~(E`mXpcBO=fU2WI6pp1W= z&9!bz8R8E0EKw;_WXkucy#c_Cltk#CjPy@QDO2EY7t>(BPOCoGtGa64Ko0dSuOBU{ zc)41yaMdkIRa`OG$$D483We~UVii^)@lU`15T_8$n3lYbRt#xBgxo%x5<1mgGHe1tY^1Y-l zI9IVQ072Li`^35?7Q z76&W1TLMLdUeVN#W74j7>zxx>cRyb({_`bPd{AL>?Z-e}DZ13_g&LVL!5wgqxEyB4 zbPY`whbmYGB%8p!y*lFT)&E{6pdcYa^lgF9yDG5Y?DeBUz)6Ssl^#ybfMoO+^VO1S zuE4SCB$`z|OM!&={dMO7UGN0{{%A->B1YiHVC48@yIFMS^Zi#m#d+pO(aUh^` zcYeQ+fY}_BnfkSOI$-;?^k05oOy(q(U&e=0f?q;P3K>{=%r_T{rb<1(dp?$I+E{%- z)|^}2VOS?Tmx_x~DnuBDs2k9(*8ih=zqL+dD zC{bf|a|{Z$(sr=$Z<*_}Rval&W@sLLw0>)3%3-&kGEMn%7-7(0iBAApqc?MAPkU~S zbXv}?tW~apjo1CMG+%OZ&zJG>hm=%o5;wTGE*GPKn<09?q7BDI&*|MX)mp1A@wQZ_k&sS8Hcg;nsV+80>5Orq2G5a)5> zBMYlq`L82>}b{W{n8`4W@osFUZOql|AxkGFPCsISzhl`M+1wt6m=%D0x@trSL=4;h$(Z14D{31RH!$~l9+zuzAl3sAB64+ z;x|i7jAT|tzF`mh!I!<~LD4e+p5s1HF9noV621AO~ji@HI9 zko=p1RUw-f(Y)x8L%ccL$)C(F^y5cwt<2;BZAlS>MU~{;gwMad*V)rN3lf`GB{nZG z=iHw+K_N^D5; z_*Ztxe`g4TeP+PY0H(_H#5ve(gn;P+fd1i~@6!P_X#Dms->6zk8O-6>AtZ6KQ;!q3 zM{#0hEz&-oqYc(K4rk91$~ze#z<}CNzPxX1ePo^MUnMNTnd?!pIhDci~h3 z-%2vR$bH=lwE`*~kQW-9FA>x^2nCff3{>l0q*a`Kb*NMyzL>;yE`)xgT9=VeBv8Q4 z+$?}Y<+2FpqtxXxr4UzMqGlYjL9e^tpdm@F-y@vj7&CqtP4v497nYts|H`f-(ZWdxFe z#Ui4o-*ouED7^o7qY!y>Tq)ih5W_Zd!??c`kQV*rdTQy*{|Kc1*LPS9uWwRUBAgOZ znxYTb=1)*+qM6L@~j$DeA{i>5M{OMz%Tzp2OUDVT$ z164j>q(q7uerfd(1<}@j-jX$NaB(y}%t7NV|VY zB@ha~LKvKkde^2pDFXMH}qcc zvrHG6zh*QSQE01DtTmUU0%3y&OB$tZ)wU4pb?Yucn{?LTE-}@YA5&(Hf?DDY@gK&@ z$w)RLC!UsLS)`Gh0xY$5fjSDqy@~i{Gi|Kz@lYA<)lB|M!2_+NxWg0-j%LhvciE-716M%O%sSgO!;(hXyG>-&6LGv zS}2m0JRkkgQ;a4Vl!78s>Im=r-h3+^erpw!_HXnQPFbN`Df3i;SDJ6-gWQPi8rR}; zDsm7O)AixJe^HG(?n6%g_dw&;aaTM7qj>R80DA=GsS-H?>FejZAt_=5LMe~HTO)S4 za3H=XLeq@;HDI&=6(_FA_bijT&mm)-?TrUrc)-i7T6uqTGuLsJ?ZLpUE5wnMnJEF& zn*z}{6Ojpw5EP$A-=#zwkxt*mx#NDBW}JT%a_0zL>4v@}Y6q6tLhiNVwU#cMhi}Ky zr*4&9*Dm=lThjiz4ZD3}XxaS(aXR>SK_ROltFfa;;&*oD_bzfuMsoxu{XSXxI} zs~13*|44LkKNn78#xmg6HlHuve#M<*(^RAlyJ&mZSK2FFxqW;taqP>qyCBP9X;;WB zo_N$g_so_fU7Mw=T2{x4pO03;v@2;|w;sP#+k1gx;}lnBJBsUh_Gt@Z&i;EsS)>DM+TXQcG+k%YAK8M%h8bwuAev<*3dyn(jrkSa9JX)9UUm z=dmJpg5buDZ>k{LzXeo(G1W6C%Aky@lMq=%SpvYpMJ zqjTZ%sWZ@689Bb_Gnv?Fqf5AS@$%%4&vGv_?H68VOHuOQ%=2%U{KWSu+ol6X#S~T@h;_EhXGW)D5FWudV z_krHy@9GbP#tH{KB>vurKwNCq{oPhR%n6;YzYyDdW3c2yIF&q`>JK^N`kuIM-hg8U zhRe-^-?1-8Z)HAc(IQl}Ago}_o>anb+Pe9=F<2w9@hpf5Mf|d1g`6*+~ZInN~L_KeRiFYEZT-ODz@Q zf}f%dUTy4qm46_zy&jtS|jR3{89vVwS&&mg-gMvIu%CLt59EmVBwC z+B=G~7z&naPK}!~??gEZFuM3Y3D`<)L64)dXWC1cf}wgD)gF}d$!uHbZ>9R9_&uhAWDz0yIVMqkZ=!thuIbmig3M;CJ8Hbk^7I4h~ZJGtV*07*aK;SL{YV6vL*+ z*mGBas*19euWIT`S-Dzo2X>HXEO7mlsqAp*Y;Xd#YvDDkS^rM$m_SYdFTB1jv0|9KKC6F`5q-sHxi85BK6q0OMg= zowLwbG_NDJHI_E7MDc~y`{yNqQw?#&%xB~S2_GnI(hbOMwS`v$_E$qr6Ij5 zJqBHYc3fVT`Bxu3hQ3!RIk%ZQ-t*R2l~MF-CZLB1DI?bN24xhRm&^~Fw)pskpul(Q zG9Tbo*ZY#bgOuK$y-+MaCES{l1IfBFG7}`VRUI6H+3Qoq zz}oI2jgNA+g9>u8EP~7DpwN%q)tnG1b4HxMkLjGUA!?-`_Ydm(AtYNQCeGY3n2V+4x|l8ryf>DaE3X?gbc zixZO?ICLYmD=*9GJtRhIA6{0}Q+p6U32G1#8|PonvQX@s!8=bMTr9n--OFgjtsdDK+xvD<06P zI;5*rxA2?zdEG2FxOvkRWz&LP%!2OPG1k`hv7h*DB~A}?dVI+UwZbsH7>?B3LD{Q_ zrVaugEL`;HwTTSG*;z5%tP~K@bzts7%GIvtb>_tHef@$Y-;j#bm`& zWY6*>%imUGEgwx@MZy=r488F*pU{`S4oXZWv|0QZ{uIr@B)Hu-wDrVlzQCw_p;Y5w za3)icKIsj8jJV$+G@Co6V{Jta?#12W&-6KkA|Gar4Kz@<6~;5R*Yzvd3bf>OVmHw( z+3P5jJZm72R?K65^6rZAG6(uNTVuN@t1DP#k%BpkDhVq+;H=Pp55{7$ClP^N?*|n@ z3ZJwquiFDB``l#gBANKPxD(2mEBC+N6nk4r{*84P8AldSh;(G3kYU}8iVI7l0>zFL zhr3KQG_qK)_*inbHoN;I`{&+$_%@lf`$?%SC=)5EOjeJiBvll6an29A4G|*+teEJf z*m)E4lD%%xXIgAZUoNXHL_4MdI{ilCz@9Ye9=Z0u?^{@-iAv5$!A6yMd*$%`TNEBBWkT>%x=yQ#cP{49$A zg)RUS&(>Ln$t3_@ukuGe$g@{HanMk;*p)hOow#l^K7az^PfN|!W)w1(SYI_eu!3wv zjzRUkFsz7t5|57jYa{jm$H@Ce<-y(Qi6@JGC-f?aizu8qKn#b9+Hy-3y9`qEsJ+Ll zgODRzWG+5vyvDBrE&)|d2x6#=8-{GE!{PRewj9&o1*sT5@zn6gr+oRH&GWlLJgwsN zt3#MWMnazZ<;-xpqxCMOs6Z93%NLF9h8NH4P>xfaJNj6OJ8`GLA~-kdqA`PU>z6nV zU%;FOQR5hJSMn5Fvzbj=7&<-P-54J|@^6q%DkPf~Yo;o!-C?Ai1 zGdH(QUcIbzb@l#hxE|&S&ho|+P+m*Yx+AU=ECO^Lgk$&)t6p)GS{~e&{ykbX4@4TO zjO;ioSc+P4*l$4PkAC zR5Xq%Q4Qn7;)`ujsfs!(JhGIFv5o26xVh{Ab5Bn>s} z9~xmV=4p5{>`^0&S-?oB(UvR+z}+K$iw~L0yVC_2^7@%R4|@C}hHdv<*<4#JsGSlA zakDUI<+Cv7C<)y1oVO9oXdW1<$J(@5y=?kiQZPVyXc3!4T$iQ0pTNna#Pd~9;Zaw8 zqs`;u&yJd!>ft>Ot>FiY-_z9QH0z!U87uP@4M%#%TE<}^eb4kTffC4|(t~{^hRa z$J{O{=jotmJ3V62{DS3|siUTCaLpfu$|G5JE}bhU51b-Q7k0O5Hvv8N_(7bnzz{BE!iNbf~%5Qv5@^p1%WfeeCSnFo{|s^={B19DmezMKRVPf|q7hu;^+ z*sWdTE&J^N=9}jE0*4^))c=Yr{*FVQMpWU~e5G(^39iRk!~!H?5&22K?cIO335V4oGL#J^0n83>g|Y(Mon-}IAQCC*wfv8>!dpnqEKbOa zjO!e8L-X_CUil)l)O{IVLVpKiL-L~9p3m>en?H$fvsto?V zEQ)*BEmdK{7fAxi>2KadYAsq-tAt7^>I6Z#>-ir*&vG#f&$||ZdlGYfz!v`a9OR36 zQpd!XXZV(-#kN935VOYDQ!X7a-T~-?{IA~&PSuY$|JH{!fIBH`PMX#=I?Vl(|E)2% zzwdn-o)vSrJGU1X;*+)0|76#lX)QM`zA1|J)9|E_NR8jt-R8X{HJjC0XpJ-VKIPJw zj$*J8e(rMtA!qQIr2zs<&1$uOMn`5O&jC{rgM0j3fG_XpBiGSKYu6zz9_%B*$L0^z zKB6vtlWlCi``vqL1HEhx${)M?jvSQe8e>j25(*u*OD;=0rbTAOlH>XvNF=)fN>q(0ehhWdlBjf-EZ4igoGN-s@M{ zvE0Z-#oYb|eh!^&n{c}A+4(_b_!aj}c1H5r%irx<7Vbu?d=H*X!0!;_&=V)3L056! z+7J);W=nJ3&Co_8cxFEfzg?lfQf4=3w$9jX9V;_Zu)&!&+_e1sm#zj?Rv>_$}tKZkD3S=-Z%=z7Mf0M4*0yOSU1l0fzE zQtFJ^4O-g-S!)Ye1qz6L1z=U`pVdat`whCXTR*JL|D`$D2>QRP71&jA)$pNwJdo~1 zA@H4u!*AoH?45dHZl`rsN;P~pTFsE}`7r}V9g6JC?1}91CHz%vl>W^F3e=2_G$7}F za``-Lu)&KGJh;3v-^&BLHaI^b-oYzX;2+@rx$TuVzc+XmK2?=Sga0s%MBeK@mt>%k zr{S$iO7iK&!D;@{rzFbJTmg_CdMh663f#^nacRhFfXek*;IeYipMvVm#FQ!g8(b&??5BNmAnPE(11*A7+H6p&`e$Mr_CZ&& zrb@q_UFpyEkCf#fhWdw>cJCpW`Cp%9UXh#XfJ`Y6 zqSuQXLs8k#bk?7E4`Ron=dh^+P^))-Uj&#T12hT1z%0cd9|@_RWa-`sd~`1&cO|yy z;M4R(+b8+rEuH{>w}SFrw`+m-=`Ia<$zuxIT?3R9;w!6bBq8moBYbV%qfD(hN9QC) zNOd3xDrrkj**agP3DegiaOQx~9?3jnCqdb5tGHn#BtJ5X8Ogb#aS$fAAM2n$Pyv<4 zG-?KpGtkMkLo4@Fh1$Ue-o0CQi>*}33?1lnKx=CTj5&I@b*H3ZTdEMCn*%ohC#LEr z#`=Mq>MS3J{Gnh4ttg$G{4fwzC(unTbpuFy06+G)beg_|00`Nzxbm4T+Ky-8<jpE_<9NQ9uf=yaTXNfEIOt75ZOWrSuDY z>wzP5))S~A{?en7sYX_Gpy5^WIhQZc|9R18hQYsF^k43Z^rPP!BZy%jFMJR0ApSfc z0`AHX^dAu4fmndy&IueuAFlqwVDS(@4~zMNEqQYg5N_Bz1R|7tRPIQ&uzad1i?fYU zcup}dMVLHxHBG6RauPzq}tD&3tf5H%QR8{aT*h&99(5RhKH)rF96%D^iQ$jgSfgFAoiw&*rVfO4W^xOtvxzm47YYLMq5@SAKv=1+ zqM*$nQ=u`~SY^sida`w=icX&vwzVU?1SKnO#`W&je9xz!d!&D>u;(zO(H{`!J$`TbpJq;puDbq)g1F13mzetI zS7s~4wFQv(z@`dnu0^6#?KI&>cQfJ*GL@(pG3c+HoE(xJx7atcq$zB_q4i}_Jt7?v zz&r^WX|Ai|{ob}284XHeUzM5zCm;d%ojv9Cu1^1?@0)9tj*Sm{fqZ8@SfEugPaiv9L5=vBm^m6;i{07^$TytTP? zH^I=v#mBf2&VG+ zi58L}gs$B9cEA(Y61m_SQN(+)WnSGWl?tcVrE46ZnS znpartdY56rfv3|T$5ReDI4|d>vD?Djvu9SRIVlVbu7oTiW&m4wlX3^b7#gqUdQOK# z+FyMn-+MDQtso0>_b3>kDhUiz_3yFG3}RgD#-zVj`#y}hXtSD4=Wn5)_+54U=FqMM zZL#lL)~A`zr_Q18Ush$srb4mnqu<)g;mwP>`_)ngn9N)Um1t z@TdlsQ=l7lC=dvEM1ny0pf>5tlXY#ZZ(7J{)p7(3Wt8hEiNGTho>l_irUge55x#=~ zo$|;?*8Dda^UYH8jAgtweAZ}=Hl_@MC)z=t{~dWFOO*fDG<|%SQYo6(%`PJ#rRqw^*7_4Efexyhl7`753KU&?$ zfdn#xkfX15oJ-fpoC`;0#_GjnVFmCH6V6MR9`I~pM)2TS@7ygl?Er&Im~aUq3T$_Y z$USDlc#keZd1&Br3#zwHwFCobGM7(VcRrt>3Bj*Vul?^5Vojfu%)*xY;H>}b=T|I> zEPB{#MCutqIh|bs=D?ePd)f)#L4Y2s19arPSalqO0l1rkdx;EEQYOC24#0L+=Tker zT9s1Q6?DHZHM4!JN+8Q!jfI14PC-uWGU@)iOLt1-2qWhW@3d~wPH6`>rmPa8gcKie z+L}{5?x#p}9X0CG>XFB&t3K5G3#!Dd2B_ zr2Em%Jn8dcUOx5X_?p_sYJt|q>8cMXJsNhh{8yx&Ot-|SM@dXDc8&6fE6H8k0R(zQ zNu}CUROa8V=PB85$S^r_g^!zhY|T%&SA%SzHddulBju32xHw2kMXUWz z^l{Q|NZpobK?6ofTju(F#t;{W!$v7~prS!ME2p&lzNOYxC`hgcO(jocV~Gt!78XJ_ zPOYd|K5Z^!NC8A&^BimDF6De76@b>bLnC8uTm3(8Q| zH1!J9qSz%AHFHl%&iQFG7aM&T4qRdLf~K>c#HI7o(UF@JU=eYLI7%1lGzNlm>Z2~`4MYk6pzs^1JNzXoq%-U>#U~Uq{ zA0;>J*KGqmOuKm7Kok2wc#fyFWgi#ZmnhR)xeFTBMx5rwDZPvE3*1JAdXzfq=OFJjYQ@bmouYbb*b6P(|*R}dc%O(b{cj_~^CynB=QlVf690R12odSYnc7ujD^ ztiW>a5U5^Nkbw91`z0?N0AN;=3l|0fyD8`cZh+(^qtq1?GjrMJuo7R*=Wja0wJ{v9 zqZyb$=V7&VI$4h2+x%>Of!s-WJ^kVJ_B4z4{y~=QYSwmcIfc(~waOw=r#9|qBQAjs z5*+Q+eTdf!;J(6ck*^=@6DIS;-tSB9a6_ zg6H-u5>D`b_0|3UxOMApQS9_gPtQzm_e{_Gd-{DlaioQ8JpFK_Df}Y{(bRMpb!x9D zQeaK*KWY&!g%1NuR5etpDBu#2MDIH!FH2+&o?vj23_%$sqtgi|*%3-$n;e`BCHP;I z6)&rSc0_axZg09-gr;=r?}L9lW-=CT*^vB*Mj1e7z0~oaC}T~((5rjLby6l{nrGxCB@V4o zc^OBSuw8*I$n+0k_Tr)mPi^NG)7Z@S3R)Z2ags7jTj*u88Ks=gFgc_3s5e-KE(mjZ zFwJ}gJ+kP@>@Edi=*vRCy^Q0^PfWv9mCkS9)jY zJTksf&BSgoN0cnOTpTD@H_lA??Z-J0>}A&rt=Q_`#c?((7pq44o+mg};W)7<^mgdT zj{2|#GbN-eqFHbe1Tpbv&&Ur7lm(Mbfar+W8~($60dY*!MmeD?_VPf3RT;wv&j*HD z^9ueZS{71j{5u*-R+D$XxTs8(FDRe~k1O#>NuhdmvYJ<|%I?}mC=-ikwp=gEg(RSB z$!~=`jAA~#EwQ$9))k|ADH+37ZzHg#kjl=?Y&BBY4+1z)aMUM_yfWL^LJLOUmns#g zU(F~#`w1F)yTbGJ>*h15t6W^R^Jv$PoDKu2$(U3mKK#NB184YlheSRh!UBM+E+|@z zu47Jx<;;Z^rnz_XPlGtbtgg0p86r1$)Ous&?=ID9tm|@8=iG?rZZUo~WrWPn(8gdn zINVz6)y_QjIVqD<-{U{?L8TPp#h8?;_vO1%=^94)XXVZXy6dn;**F_kXc%^(->dpq zpR3i601y_V2=w$+ewUviBsvlH$-r=IBQZktco zm@pbDK}(Jn;x8Q$xOnHQc|*R8K1!o(G#!~I+>1_?|spPj*s37#%00qUZ-N1Vl{my#id5NF}SyTAh9d$}kc zm#mB)eJUjy`kr@Cq$hNx{C%x|f<#VXK*m@dlx*P+94I$<#}&HF>z5ciVH?lRj#@YusOGg%Sm{%jw)` z-q&x72WJLgR6e?EcE#?TI#Hk(gwZPQO%(UnyRH_@(Q2$zX~;}l#I#(R`x~y^!aGk2bR0;4Po6IfP5Y>$JkHTLN0(1<+orv`^DR6brTr}R z)Ki;o@zLPgmd8msx1-~xRb8D5zu1m`&iesz2f2M!RaS5RaplJ7o8z(|T z`MZLJ(6!s)1}NvgvrlX9ed#O<&wT;`*hu-&`aDXG z8)h-Iuw*pM9IUOXhN+Ko@lIW%dk^+Pip90l@dd^W;Qqf**G3By-I(f^~0muPCxu&4GWkG z4uUt6?(w(4T?Kql#4k5qOyyiiS(+n2v_i;dNfCLEa@D1U<#N|A4J_1JubmfJSKJ%i zko}wGBBkM8i$L5s-;{6u=6#V_f1J=4cJ0@;bQAg_Ypm@^FwufaPCz3hD>aXrW`G+q z;YI1AyBR~e86zzCTBl8Uxd#=Tz~7OCGMqq=;>(50{)bOw#fkR`1MGQnVg(`jB)XO2 zG8vJdbTWA*6R_WDoYJ{g(%AI#Q|O;6XD7wKdJSH`dPWi?UYyW`{KGP}$Rr#wFM?HC zlY;eHlOTd-54^Yu2eCp1fSA;g32T>#DmC=y0zFdRE|dBjCOiAF`Vq3q!sh|R$9Lh^=pzGGiN#~$iVTp_Hu2a$Q9S7&}Cot6{Ov}rGb*rh@MVz1Y}Tj$(T=-Dqk##_KI{3f^Sv=>bSn4Y>qRg{) z+#yb{UWT*R?PaG+ufIf{Q~S!^Lsivz<$4cx!>m!ry2{;5!pZxIYf|4UX!B#yS<|4N zV7{xDm4YnhIp}@9_KmGdCe|;H($!yFck)v0$-RIr=Wds~P-*VVXm|J1iWjFC#YrX^ z=7@K1XGEO51fSfx_1WSb*CZW{o^|0Yt#N70IEj{YwogPKDI3ju#Xxxw$JG)~*?-T`0G3 zPI^ASHTlt)F8{hI-s2kQ<#j$CHA?3%=h0`vXYKNuc|D9*qT)e(>F7}#`uhTx79Iwf zD4K1=mghel0bul2s@#@LLZPwng88ub5W8soM7Z zU{hWi|M@$1fyYXHQU!ZY>pf0J!3&|bi>@U$=(sXvF_-i@Uy3bCsGnx{q0#)Vd>;fm zTi2PVByFz`*U&X4?cAMmToIUGQ+m9_YPC(&`Hk{Tc+rE_TiCt#2LzRFryL9RG|Q3r zwvndnlkBlJ?N_Mbe)qQz2$i(3r?`|Nj#)kq`Uu%{5UhCd#|_RktMkjpr*^*RjfCi# zsVa0Ii7|AASLpYCG3!P**pqz6-pZ+(%hUDltSEf_xF)phcp@XZ`Fd#~}+xZ0ibRA?fveKbriG>7L2m zJs6JtPu#%CYX_>nuoDv-A&dslvG#&7^xo?Ri5o0n=BeQ{T1xZCG{NNS>@+K3dn-~9 zdu4APwzh5f;S_0L*(d#5J?yX0w*$i@DwrHZ;2A-1KLE(!&+7f#YU1V*XTDi+UNvW1 zixxjwc&LS7#}`3>f9(W@RQx_6o9Np4`z2UM{`8Qi5hviee)?LBqy?-PD0fo^=I{qaQj*nY?Q$oO($eEqbCW zdX6f`?Oyb<*d@Ii;K-Fb$2w*CiID2D2WY~6eSmL<;TzBHzDM5At>0{E0voQ zeQZ~{TC6?$G`C1J6fHJk=SS8(x<5|e-xs{^-T`sANUnkR-H}joIq}2=qvC7=8w7?y zvlq84GA3D-(eR;8_=KhrxprEau&$x_rb_*$oBIzkmt_gBVpJMt;(Ok)JQ20mB3AMu z>5v|pUzBI9+qHXW^^#hmB&D4(6uV*L-52}5QT_%+z)jpFH`mkb<$TCjQAh0+`*H>P z;)1Pnrsem6{^@+K%Neoj(T|HUzQPgI!wF@!V?N(=@@%4)s^fo-prbom<=S8JM~?;cG~J z$P}1ztJ$noh3!>kW&(R3m~b|g4G$;{0t&`sP!GBms8RR(wDQxQ1}DpgWEtV0FV5W< z;(N<8kqJptrIHtBV%51DqI%NijYk5rHQXE>8Vg};s8mBk%=1lL)vLg~TAQs0e3r1k zT52E%%A`9KbBMaNW#!-oftUc;qyfdgcZ%6cpJRCnUYpum(WWVBxT|K)srQ;d(b=jR zm?NFxjT)kaYsDgCrIbpRma;eAjqpi@t)|db)OW8*Ei+j zo;p7(YQoWn3E&*^6AaoP2#jL%+^|*w$#k|%&?kos(*n2X}VwMB8OYf8{`3+5u)HPtK z$Isjo25~qTwnH82^3E?zy|MsbGD;C{8~n%G%+! zhuAozTz2DqdtBvjXPZx&1vBgb_e2BQk;YbPpSOiHi?@8tN2!Vy#xxC{ubgR*mcRG) zT};P@p;Fs(_jV#rDD_uLvx})$B3gv(@~(* zAmGDm(J{_1jwf~7)n4kp>|Zp|Kx6WIwwZoFBIOK!AT$Pax7H;psvb~?H|V=qQ-4jw zRZB0}Ec}=!)XeFgiLjNrR)D#gb#muqAtomkh?pyW{29{pRaAl>6B z=-QUOuhZ*9+OOqj*SYNV+BUq=^~)aSoDqhJ)5d2g05N0I5mL{m=q|qD38LWjZ17!4 zaATfUcwhFyCFS<)X%UB=w!lh<_b*Fs?{v*e;~vLKUl;G<)%o3;FnPoKTzuK{^0}Sq z-p05y%w80y9XA1f`&`w);~3d)!Y4Kx;m+^?Hv1 z_p!_{5Cn3&hhl@P@A`NEyk=)*9_E4AN^{-T=}fd7hb;m9RMG*!m6c(a+oicqE|&OJ zr8nGq^f6EA6 z{Mzr*-@fQp(d3!nD1@3U1%L2(73b)ZH={88`Ce!T6Al>2%lnNMEH-#X&3irJQiU6x zUFuvYMr)T$#f~02XnFXzd&s7aMbVwHde2~Av6Ul-F8TP?mlD6lGGsD_qKz)JTzDJK z!#r)`J0aZY)b?nmvZ4K@Q+65iq?RjK0dT8#e_ipqp=7fds#;2%T>QSMEF>9XCnkF3 z()YJ6i?cI7*zo^iDBw!{J7onpEs=bnPRCV4SA^ze7JbZnUCx)xD!3>zjzNMi9*?xn zoNs>wn5%Zi%7D>Eg~k4zK7f#&i!BRrJuYz^T5#wVg`tX*Q3P+su%=N$i}|h^9!G)Y;JpZ#Q*8#Rc6?;A1Sj5&x34{2BqcA~ivh(@E8r@Z=Z5+%NBl z#5G5N1N@MOkQp{ybI?!wf@v%D!174mbzvHt|J@_ByC@(Q@=8n-`I0I|3D}`5a66=b zI}j5U1|xF#5bXH7DV0vK_tnvHysD|B*y8-s2W^}`#W^`*55aR}>gPm`Ejhtq%#WFK z->Bvigq+#970Nj)>EHJ2FDN~fhhqwa!GaxJB$r&W_$=TEfp2+DKA?|MkodzsqYu)Q zNqe4vVR9u6-hlzh#tFNawgkD<9x~GFqu@<=mPPhbL2y_M+I>j|Bs;RT``!Vll`n|T zOe>*$PcGCEwFlu(po;}|fci;B14sz}i1t<~q!qG!8MA)E1&HFjZY5yC3L|}g8y@U& z0g-nx>IT{Z#Y*swc&HVyD+X}%AtVw7gTyfMo9^-xT}#11{QJ-f7(avEXlW0yShW#2 z)V-cwGv1&7KFpSaqdnM#cb}2F^yctjhCeB`tTzQ=szbU08|KiTE!EMgAo} z?av4X`_vzw3fum!D*UwL!wxd>{&6qGiv^9%_bW0D3H@~^Fb4r#`+kNby+cSa^sqbv z7MO;Cp}#Dm170wR3Xl20HRks}&gw_XazHAkh07jX3Hj4Qmhq4=M3eweAAk8E{m5na zR{@W?EZs#KB*F)t2g z*Ye}bf_1CD(5K`V(I}I$Epou=1ca!s3phLG?wPfOerk97$2t7QcVhy$S0ji4!U23z z9gda2>wp=6tAMl*eqOjoqUOw#@KGV)?kmE8gkKW^K|imPJGz?uXTJa@B{64mq!X2Fs2hVaE9Q6oiy;Z+Zi+0uYG^f?p;M5W5UMG;@gH zDTwT8Mvg`vnO64kw3NPB-v}Z40X==aBTODXG6yR>CyfYZ(C}b8f(9R65+39$^rBEl z&gRI8d&0HkM-JvF7%kQy@(-?#{MiB8Mq*(GFLS8DcOg~C&yHKtrdfT&1;PM;%{ZNd z?=x^$NCe`%{ru`tmMq09uA#tLC}6u3I)^1L)K0_kIN*B_m|>LOba?8a@X2VJa$A_3 z+4JV7a{Gvr=(eeg2o}G?261!=FG@r>G~wTkE3!U3v~kU(V{)W@r2$-*vTgt|Cy+n1 zrAYCC>LnQ8IeDqr&6Qo6yjGL}>LS5l6|qZ6)&YEZ*Un5lq0fm8uL^dcDG#unH~Z7u#jmM8Wuwy!Ey;Ls8eXy1^G{*d%`T8|n5SgYFMmY% zl!Wf)k!72=vMfsufx7^bN8$|eKDzSf>pY4*|X;r`p(naMN;mp*j#Ow zs8_o6+If6Em;wI}b+=O=2Zv?**D4^%3lM~6LqGw8U3wGXH7Z#utmXCJ)S1We?g2>NFWllfgIx3{Zg*ZiOEa0RsQrScqYT0`a#t^taW& zY(hsi0Hqv)I`tPU%zlDfRC_U{5pNJRKp);~qlcN~cr`5FsE)~!f0hSUFaHEA2bWt@ zR(68bo>on|_r;(xvjO|(Q|OFJ7!#yoaPJ&eR;gKMiGqnI1a1X| z19(&v8Clr>2z38}1#me{ZRwz`09hC&NN5efZ2|mf4DMawW~T6Y;6)uX)t?(~^%VJ0 z6X89ppeXka1l%OV9DA-w2A+F--^^kT*FL~s$DSy3;YgdnBP(zdfuDK6MN1Qc4?Z^V z{{y#`e@GDgbK}xO!Y&#fo+gGBsG7a95JwZoU`yei8ihDG=$(H?k0LQxS_7(-FR8F} zb#UD^tiV=T02Hh!10hg1M3^Q+YQ`WChHS+Tfyr&mUo`2;iUg{v7QS zX$o!Y4KS(Ot3t)vK)zkF>iVMutohuq5+eXo>hV>FZ3{eD1}90zn{UhxD;2U_M)k&#gY7vd}9lW2D5EB0rZ^@{3U!qOcH$#vv5@oGJPc6`w)gIh|_qZHUT@n zI|7sV0N4Vo;qX>qHWQ?)AW<$rk;F-HmnVWpY@I zgOYja6O{MRnO)<|In$AXD}D1mkA(Sg|Ba1J^ZQ#77M?-f!=8J4KQ6yro!hfZN)WRse9dV; Q%YFeQmL=`{9e)h`7k+)A0{{R3 diff --git a/tests/unit/data/image/test_corrupt.png b/tests/unit/data/image/test_corrupt.png index 5350683e9c8e8f96c443e19a169b04f8aa5a19ce..ee6292debef9f33bc5792f79000c5b116882f935 100644 GIT binary patch literal 5588 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 WIEesJ^It;@s48kcZ}>-9MgJd@;CgHT literal 73036 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 GrT+qv7<%&n diff --git a/tests/unit/data/image/test_image_decoder.py b/tests/unit/data/image/test_image_decoder.py index aae6eeced..df613c365 100644 --- a/tests/unit/data/image/test_image_decoder.py +++ b/tests/unit/data/image/test_image_decoder.py @@ -43,19 +43,19 @@ def test_call_works_on_png(self) -> None: assert output["channels"] == 4.0 - assert output["height"] == 1126.0 + assert output["height"] == 70.0 - assert output["width"] == 1132.0 + assert output["width"] == 70.0 image = output["image"] - assert image.shape == torch.Size([1126, 1132, 4]) + assert image.shape == torch.Size([70, 70, 4]) assert image.dtype == torch.uint8 assert image.device == device - assert_close(image.sum(), torch.tensor(1227963170, device=device)) + assert_close(image.sum(), torch.tensor(4656924, device=device)) def test_call_works_on_jpg(self) -> None: decoder = ImageDecoder(device=device) @@ -69,19 +69,19 @@ def test_call_works_on_jpg(self) -> None: assert output["channels"] == 3.0 - assert output["height"] == 1126.0 + assert output["height"] == 50.0 - assert output["width"] == 1132.0 + assert output["width"] == 50.0 image = output["image"] - assert image.shape == torch.Size([1126, 1132, 3]) + assert image.shape == torch.Size([50, 50, 3]) assert image.dtype == torch.uint8 assert image.device == device - assert_close(image.sum(), torch.tensor(902747049, device=device)) + assert_close(image.sum(), torch.tensor(1747686, device=device)) def test_call_raises_error_when_input_is_corrupted_png(self) -> None: decoder = ImageDecoder(device=device)