From 13d6f7550a9c00726ed61960155ea5ca5f5163b5 Mon Sep 17 00:00:00 2001 From: GF Date: Sun, 27 Sep 2026 17:40:39 -0400 Subject: [PATCH] Fix JPEG scaled decoding parity for 0.11.2 --- CHANGELOG.md | 27 + .../baseline_444_restart_67x45.jpg | Bin 0 -> 2333 bytes .../baseline_444_restart_67x45_eighth.rgb | Bin 0 -> 162 bytes .../baseline_444_restart_67x45_half.rgb | Bin 0 -> 2346 bytes .../baseline_444_restart_67x45_quarter.rgb | Bin 0 -> 612 bytes corpus/conformance/generate.sh | 99 +++ corpus/conformance/manifest.json | 39 ++ corpus/conformance/scaled_matrix.py | 183 ++++++ crates/j2k-jpeg-cuda/src/decoder.rs | 30 +- .../tests/host_surface/regions.rs | 18 + crates/j2k-jpeg-metal/src/abi.rs | 21 + .../src/compute/fast_packets/descriptors.rs | 70 +++ .../src/compute/fast_packets/params.rs | 64 +- .../src/compute/pack_dispatch/subsampled.rs | 20 +- .../src/compute/region_scaled_plan.rs | 11 +- .../src/compute/single_decode/subsampled.rs | 9 +- .../src/shaders_decode_fast422_regions.metal | 38 +- .../j2k-jpeg-metal/src/shaders_encode.metal | 74 ++- .../src/shaders_pack_subsampled.metal | 30 + .../j2k-jpeg-metal/src/shaders_shared.metal | 15 + crates/j2k-jpeg-metal/tests/scaled_matrix.rs | 321 ++++++++++ .../src/adapter/fast_packet/family.rs | 12 +- crates/j2k-jpeg/src/color/mod.rs | 1 + crates/j2k-jpeg/src/color/scaled_sampling.rs | 226 +++++++ crates/j2k-jpeg/src/decoder.rs | 7 +- crates/j2k-jpeg/src/decoder/core_traits.rs | 126 +--- .../j2k-jpeg/src/decoder/core_traits/tests.rs | 47 +- crates/j2k-jpeg/src/decoder/extended12.rs | 1 + .../src/decoder/extended12/progressive.rs | 33 + .../j2k-jpeg/src/decoder/extended12/scaled.rs | 470 +++++++++++++++ .../src/decoder/extended12/sequential.rs | 33 + .../src/decoder/extended12/writers.rs | 22 +- .../j2k-jpeg/src/decoder/routing/dispatch.rs | 37 +- crates/j2k-jpeg/src/decoder/scratch.rs | 11 +- crates/j2k-jpeg/src/decoder/sequential.rs | 62 +- crates/j2k-jpeg/src/entropy/block.rs | 187 ------ crates/j2k-jpeg/src/entropy/progressive.rs | 23 +- .../src/entropy/progressive/allocation.rs | 28 +- .../src/entropy/progressive/render.rs | 163 ++--- crates/j2k-jpeg/src/entropy/sequential.rs | 7 +- .../src/entropy/sequential/deposit.rs | 145 +---- .../entropy/sequential/emit/four_component.rs | 49 +- .../src/entropy/sequential/emit/output.rs | 72 +-- .../src/entropy/sequential/emit/rgb.rs | 71 +-- .../src/entropy/sequential/emit/types.rs | 25 +- .../src/entropy/sequential/emit/upsample.rs | 31 +- .../src/entropy/sequential/fast420/mod.rs | 207 +------ .../src/entropy/sequential/fast420/rows.rs | 425 +------------ .../src/entropy/sequential/generic.rs | 7 +- .../src/entropy/sequential/generic/driver.rs | 14 +- .../src/entropy/sequential/generic/row.rs | 121 ++-- .../j2k-jpeg/src/entropy/sequential/layout.rs | 8 + .../j2k-jpeg/src/entropy/sequential/plan.rs | 13 +- .../j2k-jpeg/src/entropy/sequential/rgb444.rs | 1 + .../j2k-jpeg/src/entropy/sequential/stripe.rs | 10 - .../j2k-jpeg/src/entropy/sequential/tests.rs | 50 +- crates/j2k-jpeg/src/idct/downscale.rs | 143 ++++- crates/j2k-jpeg/src/internal/scratch.rs | 13 +- crates/j2k-jpeg/tests/decode_into.rs | 32 +- crates/j2k-jpeg/tests/scaled_matrix.rs | 565 ++++++++++++++++++ crates/j2k-jpeg/tests/wsi_parity.rs | 71 ++- .../baseline_444_restart_67x45.jpg | Bin 0 -> 2333 bytes .../baseline_444_restart_67x45_eighth.rgb | Bin 0 -> 162 bytes .../baseline_444_restart_67x45_half.rgb | Bin 0 -> 2346 bytes .../baseline_444_restart_67x45_quarter.rgb | Bin 0 -> 612 bytes .../fixtures/scaled_matrix/cases.tsv | 210 +++++++ .../fixtures/scaled_matrix/data.bin | Bin 0 -> 874595 bytes crates/j2k-test-support/src/fixtures.rs | 18 + crates/j2k-test-support/src/lib.rs | 4 + crates/j2k-test-support/src/scaled_matrix.rs | 153 +++++ 70 files changed, 3381 insertions(+), 1642 deletions(-) create mode 100644 corpus/conformance/baseline_444_restart_67x45.jpg create mode 100644 corpus/conformance/baseline_444_restart_67x45_eighth.rgb create mode 100644 corpus/conformance/baseline_444_restart_67x45_half.rgb create mode 100644 corpus/conformance/baseline_444_restart_67x45_quarter.rgb create mode 100644 corpus/conformance/scaled_matrix.py create mode 100644 crates/j2k-jpeg-metal/tests/scaled_matrix.rs create mode 100644 crates/j2k-jpeg/src/color/scaled_sampling.rs create mode 100644 crates/j2k-jpeg/src/decoder/extended12/scaled.rs create mode 100644 crates/j2k-jpeg/tests/scaled_matrix.rs create mode 100644 crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45.jpg create mode 100644 crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45_eighth.rgb create mode 100644 crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45_half.rgb create mode 100644 crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45_quarter.rgb create mode 100644 crates/j2k-test-support/fixtures/scaled_matrix/cases.tsv create mode 100644 crates/j2k-test-support/fixtures/scaled_matrix/data.bin create mode 100644 crates/j2k-test-support/src/scaled_matrix.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c644b2e0..23f3ace14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,33 @@ and stale roadmap entries have been removed from the public documentation set. - Improves grouped JPEG Metal decode, pooled output reuse, HT cleanup, and inverse wavelet transform dispatch with regression coverage. +- JPEG DCT-scaled decodes (1/2, 1/4, 1/8) now match libjpeg-turbo, and + therefore OpenSlide's NDPI/VMS levels, bit for bit. Checked against a + committed libjpeg-turbo 3.1.4.1 reference matrix covering every chroma + layout, restart intervals, progressive scans and 12-bit precision: + - Reduced IDCTs round like libjpeg's `DESCALE` instead of truncating. + - Each component gets libjpeg-turbo's IDCT size: 4:2:0 and 4:1:0 chroma is + decoded with a larger reduced IDCT, so 4:2:0 needs no upsampling below + full size. + - Chroma is replicated instead of smoothed at 1/8 scale, and at any scale + (including full size) when 2:1 chroma is at most two samples wide. + - Progressive images apply the reduced IDCT to their coefficients instead + of decimating a full-size decode. + - 12-bit images use 12-bit reduced IDCTs instead of decimating a full-size + decode. 12-bit 4:4:0, 4:1:1, 4:1:0 and 1x4 layouts still return + `NotImplemented`. +- Fixes a panic in 12-bit region decodes when the region excluded image + blocks on its left or right. +- Includes output rows in the 12-bit scratch budget so tall, narrow JPEGs + decode without false memory-cap failures. +- `j2k-jpeg-cuda` CPU-backed scaled and region-scaled surfaces now have the + scaled dimensions; they were sized from the source rectangle. +- JPEG Metal scaled decodes follow the same rules, and 4:2:0/4:2:2 region + decodes keep the neighbouring chroma their smoothing reads when a region + ends inside the image. JPEG images at most four pixels wide with 4:2:0 or + 4:2:2 chroma are no longer Metal or CUDA fast shapes: explicit Metal + requests reject them and automatic routing decodes them on the CPU. + - Upgrades `fearless_simd` to 1.0.0 for the `j2k-jpeg` AArch64 NEON kernels and the optional `j2k-native` `simd` feature. The dependency is private, so public APIs are unchanged. `j2k-jpeg` keeps its private exact-AVX2 token on diff --git a/corpus/conformance/baseline_444_restart_67x45.jpg b/corpus/conformance/baseline_444_restart_67x45.jpg new file mode 100644 index 0000000000000000000000000000000000000000..88a73109e9527a247e1db044feef903e6d8264d0 GIT binary patch literal 2333 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 literal 0 HcmV?d00001 diff --git a/corpus/conformance/baseline_444_restart_67x45_quarter.rgb b/corpus/conformance/baseline_444_restart_67x45_quarter.rgb new file mode 100644 index 0000000000000000000000000000000000000000..4d552de32d61bce1aec0c87932de965ea5a374e7 GIT binary patch literal 612 zcmYj|-A@t$0Kn^S=((4++7fCt@!&isA8i4_g^Tp4m3&3S$7wNxyH#v(gcWc!J|vW> z=#h>ubrA>?A~_Op6Cd21_ufN)1-aT7+wbA`@cZ?87kd9F+^=O-oqM`HCEEFp)w0Ba zjNI?Q!9EY@y<)fh?X3R4@AWRW55n+*bh z;GKxml8f93XGAA-qF~zrxd}c%avf`ucIK+5EFLZnz3qrj8p1D!Hw|nE;<6S+yas&R nfZQ6>fs5!+!vPtH>rimiObs*XEA|=ymZoxt;u3xN)hX*QF61*G literal 0 HcmV?d00001 diff --git a/corpus/conformance/generate.sh b/corpus/conformance/generate.sh index a24a88082..b8f85c68d 100755 --- a/corpus/conformance/generate.sh +++ b/corpus/conformance/generate.sh @@ -54,6 +54,48 @@ sys.stdout.buffer.write(header + body) PY } +# Integer-only texture (no floating point or library RNG) so every host +# produces the same pixels: triangle waves, two flat patches that code as +# DC-only blocks, LCG noise, and a saturated corner. +write_texture_ppm() { + local width="$1" + local height="$2" + python3 - "$width" "$height" <<'PY' +import sys + +width = int(sys.argv[1]) +height = int(sys.argv[2]) +state = 20260927 + + +def noise(): + global state + state = (state * 1103515245 + 12345) & 0x7FFFFFFF + return state % 121 - 60 + + +header = f"P6\n{width} {height}\n255\n".encode() +body = bytearray() +for y in range(height): + for x in range(width): + rgb = [ + 28 + abs((x * 9 + y * 4) % 144 - 72) * 200 // 72, + 40 + x * 180 // max(width - 1, 1), + 200 - y * 150 // max(height - 1, 1) + abs((x + y) * 7 % 64 - 32) - 16, + ] + if y < 16 and 40 <= x < 56: + rgb = [201, 77, 143] + if 24 <= y < 40 and 8 <= x < 24: + rgb = [19, 233, 98] + if y >= 30 and x >= 40: + rgb = [value + noise() for value in rgb] + if y < 10 and x < 12: + rgb = [255, 255, 0] + body.extend(min(max(value, 0), 255) for value in rgb) +sys.stdout.buffer.write(header + bytes(body)) +PY +} + strip_pnm_header() { python3 -c 'import sys data = sys.stdin.buffer.read() @@ -113,6 +155,20 @@ write_gray_pgm 8 8 \ djpeg -grayscale grayscale_8x8.jpg | strip_pnm_header > grayscale_8x8.gray assert_size grayscale_8x8.gray 64 +# DCT-scaled references: the reduced IDCTs behind OpenSlide's NDPI/VMS levels. +write_texture_ppm 67 45 \ + | cjpeg -quality 90 -sample 1x1,1x1,1x1 -baseline -optimize -restart 3B \ + -outfile baseline_444_restart_67x45.jpg +djpeg -rgb -scale 1/2 baseline_444_restart_67x45.jpg \ + | strip_pnm_header > baseline_444_restart_67x45_half.rgb +assert_size baseline_444_restart_67x45_half.rgb 2346 +djpeg -rgb -scale 1/4 baseline_444_restart_67x45.jpg \ + | strip_pnm_header > baseline_444_restart_67x45_quarter.rgb +assert_size baseline_444_restart_67x45_quarter.rgb 612 +djpeg -rgb -scale 1/8 baseline_444_restart_67x45.jpg \ + | strip_pnm_header > baseline_444_restart_67x45_eighth.rgb +assert_size baseline_444_restart_67x45_eighth.rgb 162 + cat > manifest.json < manifest.json < cjpeg -sample argument (luma factors; chroma are 1x1), or None for +# grayscale. +LAYOUTS = [ + ("gray", None), + ("444", "1x1"), + ("422", "2x1"), + ("440", "1x2"), + ("420", "2x2"), + ("411", "4x1"), + ("410", "4x2"), + ("1x4", "1x4"), +] + +# 3 and 4 pixel wide images leave 2:1 chroma at most 2 samples wide at full +# size; 9 does at 1/4; the larger sizes span several MCUs and partial edges. +SIZES_8BIT = [(3, 3), (4, 4), (9, 9), (18, 14), (45, 31), (67, 45)] +# Tall narrow images make the component planes dominate the scratch budget, +# while full-size 2:1 chroma still takes the scaled (replicating) writer. +SIZES_12BIT = [(4, 4), (9, 9), (45, 31), (4, 64)] + +CODINGS_8BIT = [ + ("baseline", ["-baseline", "-optimize"]), + ("restart", ["-baseline", "-optimize", "-restart", "1B"]), + ("progressive", ["-progressive"]), +] +CODINGS_12BIT = [ + ("extended", ["-optimize"]), + ("progressive", ["-progressive"]), +] + +SCALES = [1, 2, 4, 8] + + +def texture(width, height, precision): + """Deterministic integer-only texture with strong chroma detail.""" + state = 20260927 + maxval = (1 << precision) - 1 + shift = precision - 8 + pixels = [] + for y in range(height): + for x in range(width): + rgb = [ + 28 + abs((x * 9 + y * 4) % 144 - 72) * 200 // 72, + 40 + x * 180 // max(width - 1, 1), + 200 - y * 150 // max(height - 1, 1) + abs((x + y) * 7 % 64 - 32) - 16, + ] + if (x + 2 * y) % 5 == 0: + rgb = [rgb[2], rgb[0], rgb[1]] + if y >= height // 2 and x >= width // 2: + state = (state * 1103515245 + 12345) & 0x7FFFFFFF + rgb = [value + state % 121 - 60 for value in rgb] + # Saturated corner, kept off tiny images so they stay textured. + if width >= 9 and y < 3 and x < 3: + rgb = [255, 255, 0] + rgb = [min(max(value, 0), 255) for value in rgb] + if shift: + rgb = [(value << shift) | ((x * 5 + y * 3 + i) % (1 << shift)) for i, value in enumerate(rgb)] + rgb = [min(value, maxval) for value in rgb] + pixels.append(rgb) + return pixels + + +def pnm(width, height, precision, gray): + maxval = (1 << precision) - 1 + magic = "P5" if gray else "P6" + body = bytearray() + for rgb in texture(width, height, precision): + samples = [(rgb[0] * 77 + rgb[1] * 150 + rgb[2] * 29) >> 8] if gray else rgb + for value in samples: + if maxval > 255: + body += value.to_bytes(2, "big") + else: + body.append(value) + return f"{magic}\n{width} {height}\n{maxval}\n".encode() + bytes(body) + + +def strip_pnm_header(data): + index = 0 + for _ in range(3): + index = data.index(b"\n", index) + 1 + return data[index:] + + +def run(args, stdin): + return subprocess.run(args, input=stdin, capture_output=True, check=True).stdout + + +def main(): + probe = subprocess.run(["cjpeg", "-version"], capture_output=True, check=False) + version = (probe.stderr or probe.stdout).decode().strip().splitlines()[0] + if "libjpeg-turbo version 3." not in version: + sys.exit(f"error: need libjpeg-turbo 3.x cjpeg/djpeg, found {version!r}") + + os.makedirs(OUT_DIR, exist_ok=True) + data = bytearray() + lines = [ + f"# Generated by corpus/conformance/scaled_matrix.py with {version}", + "# name\tlayout\tcoding\tprecision\twidth\theight\tjpeg\tscale1\tscale2\tscale4\tscale8", + ] + + def append(blob): + start = len(data) + data.extend(blob) + return f"{start}:{len(blob)}" + + matrix = [(8, SIZES_8BIT, CODINGS_8BIT), (12, SIZES_12BIT, CODINGS_12BIT)] + for precision, sizes, codings in matrix: + for layout, sample in LAYOUTS: + gray = sample is None + for width, height in sizes: + for coding, coding_args in codings: + args = ["cjpeg", "-quality", "90", "-precision", str(precision)] + args += ["-grayscale"] if gray else ["-sample", f"{sample},1x1,1x1"] + jpeg = run(args + coding_args, pnm(width, height, precision, gray)) + refs = [] + for denom in SCALES: + out = ["djpeg", "-dct", "int", "-scale", f"1/{denom}"] + out += ["-grayscale"] if gray else ["-rgb"] + ref = strip_pnm_header(run(out, jpeg)) + channels = 1 if gray else 3 + bytes_per_sample = 2 if precision > 8 else 1 + expected = ( + -(-width // denom) * -(-height // denom) * channels * bytes_per_sample + ) + if len(ref) != expected: + sys.exit(f"error: {layout} {width}x{height} {coding} 1/{denom}: {len(ref)} != {expected}") + refs.append(append(ref)) + name = f"{layout}_{width}x{height}_{coding}_{precision}bit" + lines.append( + "\t".join( + [name, layout, coding, str(precision), str(width), str(height), append(jpeg)] + + refs + ) + ) + + with open(os.path.join(OUT_DIR, "data.bin"), "wb") as handle: + handle.write(data) + with open(os.path.join(OUT_DIR, "cases.tsv"), "w", encoding="utf-8") as handle: + handle.write("\n".join(lines) + "\n") + print(f"wrote {len(lines) - 2} cases, {len(data)} bytes") + + +if __name__ == "__main__": + main() diff --git a/crates/j2k-jpeg-cuda/src/decoder.rs b/crates/j2k-jpeg-cuda/src/decoder.rs index a49dad67b..6fba8e258 100644 --- a/crates/j2k-jpeg-cuda/src/decoder.rs +++ b/crates/j2k-jpeg-cuda/src/decoder.rs @@ -143,16 +143,17 @@ impl<'a> Decoder<'a> { ), )); } - let (bytes, outcome) = self + let (bytes, _) = self .inner .decode_request(DecodeRequest::scaled(fmt, scale))?; - wrap_surface( - bytes, - (outcome.decoded.w, outcome.decoded.h), - fmt, - backend, - session, - ) + // `DecodeOutcome::decoded` is the source rectangle; the surface holds + // the scaled image. + let (width, height) = self.inner.info().dimensions; + let dims = ( + width.div_ceil(scale.denominator()), + height.div_ceil(scale.denominator()), + ); + wrap_surface(bytes, dims, fmt, backend, session) } fn decode_region_scaled_to_surface_impl( @@ -171,16 +172,13 @@ impl<'a> Decoder<'a> { ), )); } - let (bytes, outcome) = + let (bytes, _) = self.inner .decode_request(DecodeRequest::region_scaled(fmt, roi.into(), scale))?; - wrap_surface( - bytes, - (outcome.decoded.w, outcome.decoded.h), - fmt, - backend, - session, - ) + // `DecodeOutcome::decoded` is the source ROI; the surface holds its + // scaled covering rectangle. + let scaled = roi.scaled_covering(scale); + wrap_surface(bytes, (scaled.w, scaled.h), fmt, backend, session) } } diff --git a/crates/j2k-jpeg-cuda/tests/host_surface/regions.rs b/crates/j2k-jpeg-cuda/tests/host_surface/regions.rs index 77be676a7..ed0b3e90b 100644 --- a/crates/j2k-jpeg-cuda/tests/host_surface/regions.rs +++ b/crates/j2k-jpeg-cuda/tests/host_surface/regions.rs @@ -42,6 +42,24 @@ fn auto_region_scaled_surface_matches_host_decode() { assert_eq!(surface.as_host_bytes(), Some(host.as_slice())); } +#[test] +fn auto_scaled_surface_has_scaled_dimensions_and_matches_host_decode() { + let scale = Downscale::Quarter; + let mut decoder = Decoder::new(BASELINE_420).expect("decoder"); + let surface = decoder + .decode_scaled_to_device(PixelFormat::Rgb8, scale, BackendRequest::Auto) + .expect("surface"); + assert_eq!(surface.backend_kind(), j2k_core::BackendKind::Cpu); + // The 16x16 fixture at 1/4 is 4x4, not the source size. + assert_eq!(surface.dimensions(), (4, 4)); + + let (host, _) = j2k_jpeg::Decoder::new(BASELINE_420) + .expect("host decoder") + .decode_request(DecodeRequest::scaled(PixelFormat::Rgb8, scale)) + .expect("host decode"); + assert_eq!(surface.as_host_bytes(), Some(host.as_slice())); +} + #[test] fn tile_batch_region_scaled_auto_surface_matches_host_decode() { let roi = Rect { diff --git a/crates/j2k-jpeg-metal/src/abi.rs b/crates/j2k-jpeg-metal/src/abi.rs index 1a05d4d62..d1cd324f8 100644 --- a/crates/j2k-jpeg-metal/src/abi.rs +++ b/crates/j2k-jpeg-metal/src/abi.rs @@ -128,6 +128,15 @@ pub(crate) struct JpegBaselineEntropyEncodeBatchJob<'a> { pub(crate) entropy_capacity: usize, } +/// Pack-kernel chroma modes (`CHROMA_*` in `shaders_shared.metal`), chosen as +/// libjpeg-turbo chooses its upsampler for the decode scale. +pub(crate) const CHROMA_FANCY: u32 = 0; +/// Each chroma sample repeated: smoothing is off at 1/8 scale and for chroma +/// at most two samples wide. +pub(crate) const CHROMA_REPLICATE: u32 = 1; +/// Chroma planes already at output resolution: 4:2:0 decoded below full size. +pub(crate) const CHROMA_UNSAMPLED: u32 = 2; + #[cfg(target_os = "macos")] #[repr(C)] #[derive(Clone, Copy)] @@ -147,6 +156,8 @@ pub(crate) struct JpegFast420Params { pub(crate) out_format: u32, pub(crate) origin_x: u32, pub(crate) origin_y: u32, + /// Chroma upsampling mode (`CHROMA_*` in the shaders). + pub(crate) chroma_mode: u32, } #[cfg(target_os = "macos")] @@ -216,6 +227,8 @@ pub(crate) struct JpegFast420WindowedPackParams { pub(crate) out_stride: u32, pub(crate) alpha: u32, pub(crate) out_format: u32, + /// Chroma upsampling mode (`CHROMA_*` in the shaders). + pub(crate) chroma_mode: u32, } #[cfg(target_os = "macos")] @@ -312,6 +325,8 @@ pub(crate) struct JpegWindowedPackBatchParams { pub(crate) alpha: u32, pub(crate) mode: u32, pub(crate) out_format: u32, + /// Chroma upsampling mode (`CHROMA_*` in the shaders). + pub(crate) chroma_mode: u32, } #[cfg(target_os = "macos")] @@ -328,6 +343,8 @@ pub(crate) struct JpegWindowedTexturePackBatchParams { pub(crate) height: u32, pub(crate) tile_index: u32, pub(crate) alpha: u32, + /// Chroma upsampling mode (`CHROMA_*` in the shaders). + pub(crate) chroma_mode: u32, } #[cfg(target_os = "macos")] @@ -598,6 +615,7 @@ impl_gpu_readback_abi!( out_format: u32, origin_x: u32, origin_y: u32, + chroma_mode: u32, }, JpegFast420ScaledParams { scaled_width: u32, @@ -651,6 +669,7 @@ impl_gpu_readback_abi!( out_stride: u32, alpha: u32, out_format: u32, + chroma_mode: u32, }, JpegFast420BatchParams { width: u32, @@ -712,6 +731,7 @@ impl_gpu_readback_abi!( alpha: u32, mode: u32, out_format: u32, + chroma_mode: u32, }, JpegWindowedTexturePackBatchParams { src_width: u32, @@ -724,6 +744,7 @@ impl_gpu_readback_abi!( height: u32, tile_index: u32, alpha: u32, + chroma_mode: u32, }, JpegTexturePackBatchParams { width: u32, diff --git a/crates/j2k-jpeg-metal/src/compute/fast_packets/descriptors.rs b/crates/j2k-jpeg-metal/src/compute/fast_packets/descriptors.rs index c5111807d..0496d2753 100644 --- a/crates/j2k-jpeg-metal/src/compute/fast_packets/descriptors.rs +++ b/crates/j2k-jpeg-metal/src/compute/fast_packets/descriptors.rs @@ -6,6 +6,24 @@ use super::super::{ JpegFast422PacketV1, JpegFast444PacketV1, JpegHuffmanTable, MetalRuntime, PixelFormat, PlaneMode, }; +use crate::abi::{CHROMA_FANCY, CHROMA_REPLICATE, CHROMA_UNSAMPLED}; + +/// libjpeg-turbo's chroma geometry for a luma extent at one decode scale: +/// the chroma plane extent the decode kernels write and the pack-kernel chroma +/// mode that maps it onto output pixels. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(in crate::compute) struct ScaledChroma { + pub(in crate::compute) width: u32, + pub(in crate::compute) height: u32, + /// `CHROMA_FANCY`, `CHROMA_REPLICATE` or `CHROMA_UNSAMPLED`. + pub(in crate::compute) mode: u32, +} + +impl ScaledChroma { + pub(in crate::compute) fn plane_len(self) -> usize { + self.width as usize * self.height as usize + } +} /// Chroma geometry for the subsampled families that share the /// `JpegFast420Params` kernel ABI (4:2:0 halves chroma rows, 4:2:2 keeps @@ -19,6 +37,9 @@ pub(in crate::compute) trait FastSubsampledPacket { const MCU_HEIGHT: u32; /// Whether the full-RGB batch path may group restart-interval packets. const FULL_RGB_BATCH_SUPPORTS_RESTART: bool; + /// Whether region windows need a neighbouring pixel on each side for + /// chroma smoothing (the subsampled families). + const REGION_CHROMA_CONTEXT: bool; const ENTROPY_PAYLOAD_CTX: &'static str; const REGION_SCALED_BATCH_OUT_STRIDE_CTX: &'static str; const OUTPUT_STRIDE_CTX: &'static str; @@ -54,6 +75,10 @@ pub(in crate::compute) trait FastSubsampledPacket { fn chroma_width(width: u32) -> u32; fn chroma_height(height: u32) -> u32; + /// Chroma geometry for the luma `extent` of an image `image_width` pixels + /// wide decoded at `scale_shift` (0 full size, 3 = 1/8), following + /// libjpeg-turbo's per-component IDCT size and upsampler choice. + fn scaled_chroma(image_width: u32, extent: (u32, u32), scale_shift: u32) -> ScaledChroma; /// Vertical dispatch extent for the full-frame pack kernels: 4:2:0 packs /// 2x2 pixel quads per thread, 4:2:2 packs 2x1 pairs (full-height rows). fn packed_height_extent(height: u32) -> u32; @@ -134,6 +159,7 @@ macro_rules! impl_fast_subsampled_packet_accessors { impl FastSubsampledPacket for JpegFast420PacketV1 { const FAMILY_NAME: &'static str = "fast420"; + const REGION_CHROMA_CONTEXT: bool = true; const MCU_WIDTH: u32 = 16; const MCU_HEIGHT: u32 = 16; const FULL_RGB_BATCH_SUPPORTS_RESTART: bool = true; @@ -153,6 +179,22 @@ impl FastSubsampledPacket for JpegFast420PacketV1 { fn chroma_height(height: u32) -> u32 { height.div_ceil(2) } + fn scaled_chroma(image_width: u32, extent: (u32, u32), scale_shift: u32) -> ScaledChroma { + if scale_shift > 0 { + // Below full size libjpeg-turbo decodes 4:2:0 chroma with the next + // larger IDCT, at luma resolution. + return ScaledChroma { + width: extent.0, + height: extent.1, + mode: CHROMA_UNSAMPLED, + }; + } + ScaledChroma { + width: Self::chroma_width(extent.0), + height: Self::chroma_height(extent.1), + mode: subsampled_chroma_mode(image_width.div_ceil(2), true), + } + } fn packed_height_extent(height: u32) -> u32 { height.div_ceil(2).max(1) } @@ -160,6 +202,7 @@ impl FastSubsampledPacket for JpegFast420PacketV1 { impl FastSubsampledPacket for JpegFast422PacketV1 { const FAMILY_NAME: &'static str = "fast422"; + const REGION_CHROMA_CONTEXT: bool = true; const MCU_WIDTH: u32 = 16; const MCU_HEIGHT: u32 = 8; const FULL_RGB_BATCH_SUPPORTS_RESTART: bool = false; @@ -179,6 +222,15 @@ impl FastSubsampledPacket for JpegFast422PacketV1 { fn chroma_height(height: u32) -> u32 { height } + fn scaled_chroma(image_width: u32, extent: (u32, u32), scale_shift: u32) -> ScaledChroma { + // `downsampled_width` of 4:2:2 chroma: ceil(width * (8 >> shift) / 16). + let image_chroma_width = image_width.div_ceil(2 << scale_shift); + ScaledChroma { + width: Self::chroma_width(extent.0), + height: Self::chroma_height(extent.1), + mode: subsampled_chroma_mode(image_chroma_width, scale_shift < 3), + } + } fn packed_height_extent(height: u32) -> u32 { height } @@ -186,6 +238,7 @@ impl FastSubsampledPacket for JpegFast422PacketV1 { impl FastSubsampledPacket for JpegFast444PacketV1 { const FAMILY_NAME: &'static str = "fast444"; + const REGION_CHROMA_CONTEXT: bool = false; const MCU_WIDTH: u32 = 8; const MCU_HEIGHT: u32 = 8; const FULL_RGB_BATCH_SUPPORTS_RESTART: bool = false; @@ -205,6 +258,13 @@ impl FastSubsampledPacket for JpegFast444PacketV1 { fn chroma_height(height: u32) -> u32 { height } + fn scaled_chroma(_image_width: u32, extent: (u32, u32), _scale_shift: u32) -> ScaledChroma { + ScaledChroma { + width: extent.0, + height: extent.1, + mode: CHROMA_UNSAMPLED, + } + } fn packed_height_extent(height: u32) -> u32 { height } @@ -213,6 +273,16 @@ impl FastSubsampledPacket for JpegFast444PacketV1 { } } +/// `jdsample.c`: 2:1 chroma is smoothed only above 1/8 scale and when it is +/// more than two samples wide; otherwise each sample is replicated. +fn subsampled_chroma_mode(image_chroma_width: u32, smoothing_scale: bool) -> u32 { + if smoothing_scale && image_chroma_width > 2 { + CHROMA_FANCY + } else { + CHROMA_REPLICATE + } +} + /// Scratch-pool cache keys for one batch driver's buffers; keys stay /// per-family so pooled buffers are never shared across kernel families. #[cfg(target_os = "macos")] diff --git a/crates/j2k-jpeg-metal/src/compute/fast_packets/params.rs b/crates/j2k-jpeg-metal/src/compute/fast_packets/params.rs index 1e92e56dd..1da68dd30 100644 --- a/crates/j2k-jpeg-metal/src/compute/fast_packets/params.rs +++ b/crates/j2k-jpeg-metal/src/compute/fast_packets/params.rs @@ -6,7 +6,7 @@ use super::super::{ JpegFast420WindowedPackParams, JpegFast444PacketV1, JpegFast444Params, JpegFast444ScaledParams, PixelFormat, }; -use super::descriptors::FastSubsampledPacket; +use super::descriptors::{FastSubsampledPacket, ScaledChroma}; use crate::buffers::{checked_copy_bytes_to_buffer_at, new_shared_buffer}; use j2k_core::accelerator::GpuAbi; @@ -21,11 +21,12 @@ pub(in crate::compute) fn fast_subsampled_params( ), })?; let out_stride = packet.dimensions().0 as usize * fmt.bytes_per_pixel(); + let chroma = P::scaled_chroma(packet.dimensions().0, packet.dimensions(), 0); Ok(JpegFast420Params { width: packet.dimensions().0, height: packet.dimensions().1, - chroma_width: P::chroma_width(packet.dimensions().0), - chroma_height: P::chroma_height(packet.dimensions().1), + chroma_width: chroma.width, + chroma_height: chroma.height, mcus_per_row: packet.mcus_per_row(), mcu_rows: packet.mcu_rows(), restart_interval_mcus: packet.restart_interval_mcus(), @@ -41,6 +42,7 @@ pub(in crate::compute) fn fast_subsampled_params( out_format, origin_x: 0, origin_y: 0, + chroma_mode: chroma.mode, }) } @@ -56,11 +58,12 @@ pub(in crate::compute) fn fast_subsampled_region_params ), })?; let out_stride = source_window.w as usize * fmt.bytes_per_pixel(); + let chroma = P::scaled_chroma(packet.dimensions().0, (source_window.w, source_window.h), 0); Ok(JpegFast420Params { width: source_window.w, height: source_window.h, - chroma_width: P::chroma_width(source_window.w), - chroma_height: P::chroma_height(source_window.h), + chroma_width: chroma.width, + chroma_height: chroma.height, mcus_per_row: packet.mcus_per_row(), mcu_rows: packet.mcu_rows(), restart_interval_mcus: packet.restart_interval_mcus(), @@ -76,6 +79,7 @@ pub(in crate::compute) fn fast_subsampled_region_params out_format, origin_x: source_window.x, origin_y: source_window.y, + chroma_mode: chroma.mode, }) } @@ -93,11 +97,16 @@ pub(in crate::compute) fn fast_subsampled_scaled_params let denom = 1u32 << scale_shift; let scaled_width = packet.dimensions().0.div_ceil(denom); let scaled_height = packet.dimensions().1.div_ceil(denom); + let chroma = P::scaled_chroma( + packet.dimensions().0, + (scaled_width, scaled_height), + scale_shift, + ); Some(JpegFast420ScaledParams { scaled_width, scaled_height, - chroma_width: P::chroma_width(scaled_width), - chroma_height: P::chroma_height(scaled_height), + chroma_width: chroma.width, + chroma_height: chroma.height, mcus_per_row: packet.mcus_per_row(), mcu_rows: packet.mcu_rows(), restart_interval_mcus: packet.restart_interval_mcus(), @@ -121,21 +130,49 @@ pub(in crate::compute) fn fast_subsampled_scaled_region_params Option { let full = fast_subsampled_scaled_params(packet, scale)?; + let chroma = P::scaled_chroma( + packet.dimensions().0, + (source_window.w, source_window.h), + full.scale_shift, + ); Some(JpegFast420ScaledParams { scaled_width: source_window.w, scaled_height: source_window.h, - chroma_width: P::chroma_width(source_window.w), - chroma_height: P::chroma_height(source_window.h), + chroma_width: chroma.width, + chroma_height: chroma.height, origin_x: source_window.x, origin_y: source_window.y, ..full }) } +/// `roi` grown by the one pixel of neighbouring chroma the 2:1 smoothing +/// filters read on each side, so a window edge inside the image never stands +/// in for the image edge. 4:4:4 needs no context. +fn roi_with_chroma_context( + dims: (u32, u32), + roi: j2k_jpeg::Rect, +) -> j2k_jpeg::Rect { + if !P::REGION_CHROMA_CONTEXT { + return roi; + } + let x0 = roi.x.saturating_sub(1); + let y0 = roi.y.saturating_sub(1); + let x1 = roi.x.saturating_add(roi.w).saturating_add(1).min(dims.0); + let y1 = roi.y.saturating_add(roi.h).saturating_add(1).min(dims.1); + j2k_jpeg::Rect { + x: x0, + y: y0, + w: x1.saturating_sub(x0), + h: y1.saturating_sub(y0), + } +} + pub(in crate::compute) fn fast_subsampled_full_mcu_window( dims: (u32, u32), roi: j2k_jpeg::Rect, ) -> j2k_jpeg::Rect { + let roi = roi_with_chroma_context::

(dims, roi); let x0 = (roi.x / P::MCU_WIDTH) * P::MCU_WIDTH; let y0 = (roi.y / P::MCU_HEIGHT) * P::MCU_HEIGHT; let x1 = (roi.x + roi.w).div_ceil(P::MCU_WIDTH) * P::MCU_WIDTH; @@ -153,6 +190,7 @@ pub(in crate::compute) fn fast_subsampled_full_mcu_scaled_window j2k_jpeg::Rect { + let roi = roi_with_chroma_context::

(scaled_dims, roi); let mcu_width = P::MCU_WIDTH >> scale_shift; let mcu_height = P::MCU_HEIGHT >> scale_shift; let x0 = (roi.x / mcu_width) * mcu_width; @@ -252,8 +290,11 @@ pub(in crate::compute) fn fast444_scaled_region_params( } #[cfg(target_os = "macos")] +/// Pack parameters for the `roi` of a decoded `dims` window whose chroma +/// planes have the geometry `chroma`. pub(in crate::compute) fn fast_subsampled_windowed_pack_params_for_dims( dims: (u32, u32), + chroma: ScaledChroma, fmt: PixelFormat, roi: j2k_jpeg::Rect, ) -> Result { @@ -267,8 +308,8 @@ pub(in crate::compute) fn fast_subsampled_windowed_pack_params_for_dims( (source_window.w, source_window.h), + chroma, fmt, local_roi, )?; let y_len = source_window.w as usize * source_window.h as usize; - let chroma_len = - source_window.w.div_ceil(2) as usize * P::chroma_height(source_window.h) as usize; + let chroma_len = chroma.plane_len(); let y_plane = if let Some(scratch) = scratch.as_deref_mut() { scratch.private_buffer(&runtime.device, "single_decode_y", y_len)? } else { @@ -291,6 +292,11 @@ pub(in crate::compute) fn encode_fast_subsampled_scaled_batch_item( (source_window.w, source_window.h), + chroma, fmt, local_roi, )?; let y_len = source_window.w as usize * source_window.h as usize; - let chroma_len = - source_window.w.div_ceil(2) as usize * P::chroma_height(source_window.h) as usize; + let chroma_len = chroma.plane_len(); let y_plane = new_decode_plane_buffer(&runtime.device, y_len, false)?; let cb_plane = new_private_buffer(&runtime.device, chroma_len)?; let cr_plane = new_private_buffer(&runtime.device, chroma_len)?; diff --git a/crates/j2k-jpeg-metal/src/compute/region_scaled_plan.rs b/crates/j2k-jpeg-metal/src/compute/region_scaled_plan.rs index 3081a12a3..b853ed2bf 100644 --- a/crates/j2k-jpeg-metal/src/compute/region_scaled_plan.rs +++ b/crates/j2k-jpeg-metal/src/compute/region_scaled_plan.rs @@ -37,6 +37,7 @@ pub(super) fn windowed_texture_pack_params( height: plan.pack_params.height, tile_index: 0, alpha: u32::from(u8::MAX), + chroma_mode: plan.pack_params.chroma_mode, } } @@ -174,8 +175,14 @@ pub(super) fn fast_subsampled_region_scaled_batch_plan( w: scaled_roi.w, h: scaled_roi.h, }; + let chroma = P::scaled_chroma( + packet.dimensions().0, + (source_window.w, source_window.h), + full_params.scale_shift, + ); let pack_params = fast_subsampled_windowed_pack_params_for_dims::

( (source_window.w, source_window.h), + chroma, PixelFormat::Rgb8, local_roi, ) @@ -209,10 +216,10 @@ pub(super) fn fast_subsampled_region_scaled_batch_plan( alpha: u32::from(u8::MAX), mode: plane_mode_to_u32(mode), out_format: OUT_RGB, + chroma_mode: pack_params.chroma_mode, }, y_len: source_window.w as usize * source_window.h as usize, - chroma_len: P::chroma_width(source_window.w) as usize - * P::chroma_height(source_window.h) as usize, + chroma_len: chroma.plane_len(), out_tile_len: out_stride * scaled_roi.h as usize, out_dims: (scaled_roi.w, scaled_roi.h), }) diff --git a/crates/j2k-jpeg-metal/src/compute/single_decode/subsampled.rs b/crates/j2k-jpeg-metal/src/compute/single_decode/subsampled.rs index c716a0f17..40136e31f 100644 --- a/crates/j2k-jpeg-metal/src/compute/single_decode/subsampled.rs +++ b/crates/j2k-jpeg-metal/src/compute/single_decode/subsampled.rs @@ -399,14 +399,19 @@ fn try_decode_fast_subsampled_scaled_region_to_surface( w: scaled_roi.w, h: scaled_roi.h, }; + let chroma = P::scaled_chroma( + packet.dimensions().0, + (source_window.w, source_window.h), + full_params.scale_shift, + ); let pack_params = fast_subsampled_windowed_pack_params_for_dims::

( (source_window.w, source_window.h), + chroma, fmt, local_roi, )?; let y_len = source_window.w as usize * source_window.h as usize; - let chroma_len = - source_window.w.div_ceil(2) as usize * P::chroma_height(source_window.h) as usize; + let chroma_len = chroma.plane_len(); let mut scratch = runtime.batch_scratch()?; let y_plane = scratch.private_buffer(&runtime.device, "single_decode_y", y_len)?; let cb_plane = scratch.private_buffer(&runtime.device, "single_decode_cb", chroma_len)?; diff --git a/crates/j2k-jpeg-metal/src/shaders_decode_fast422_regions.metal b/crates/j2k-jpeg-metal/src/shaders_decode_fast422_regions.metal index f529fcb82..549627cc0 100644 --- a/crates/j2k-jpeg-metal/src/shaders_decode_fast422_regions.metal +++ b/crates/j2k-jpeg-metal/src/shaders_decode_fast422_regions.metal @@ -743,8 +743,12 @@ kernel void jpeg_decode_fast420_scaled( thread short coeffs[64]; const uint y_block_size = 8u >> params.scale_shift; - const uint c_block_size = 8u >> params.scale_shift; const uint y_mcu_size = 16u >> params.scale_shift; + // Below full size libjpeg-turbo decodes 4:2:0 chroma with the next larger + // reduced IDCT, so each chroma block covers its whole MCU and the chroma + // planes are at output resolution (the pack kernels use CHROMA_UNSAMPLED). + const uint c_scale_shift = params.scale_shift == 0u ? 0u : params.scale_shift - 1u; + const uint c_block_size = 8u >> c_scale_shift; uint mx = 0u; uint my = 0u; @@ -766,10 +770,10 @@ kernel void jpeg_decode_fast420_scaled( if (!jpeg_decode_deposit_scaled_block(br, entropy, params.entropy_len, y_dc, y_ac, y_quant, y_prev_dc, thread_status, y_plane, params.scaled_width, params.scaled_width, params.scaled_height, y_x + y_block_size, y_y + y_block_size, params.scale_shift, coeffs)) { return; } - if (!jpeg_decode_deposit_scaled_block(br, entropy, params.entropy_len, cb_dc, cb_ac, cb_quant, cb_prev_dc, thread_status, cb_plane, params.chroma_width, params.chroma_width, params.chroma_height, c_x, c_y, params.scale_shift, coeffs)) { + if (!jpeg_decode_deposit_scaled_block(br, entropy, params.entropy_len, cb_dc, cb_ac, cb_quant, cb_prev_dc, thread_status, cb_plane, params.chroma_width, params.chroma_width, params.chroma_height, c_x, c_y, c_scale_shift, coeffs)) { return; } - if (!jpeg_decode_deposit_scaled_block(br, entropy, params.entropy_len, cr_dc, cr_ac, cr_quant, cr_prev_dc, thread_status, cr_plane, params.chroma_width, params.chroma_width, params.chroma_height, c_x, c_y, params.scale_shift, coeffs)) { + if (!jpeg_decode_deposit_scaled_block(br, entropy, params.entropy_len, cr_dc, cr_ac, cr_quant, cr_prev_dc, thread_status, cr_plane, params.chroma_width, params.chroma_width, params.chroma_height, c_x, c_y, c_scale_shift, coeffs)) { return; } advance_mcu_cursor(mx, my, params.mcus_per_row); @@ -814,10 +818,14 @@ kernel void jpeg_decode_fast420_scaled_region( thread short coeffs[64]; const uint y_block_size = 8u >> params.scale_shift; - const uint c_block_size = 8u >> params.scale_shift; const uint y_mcu_size = 16u >> params.scale_shift; - const uint chroma_origin_x = params.origin_x / 2u; - const uint chroma_origin_y = params.origin_y / 2u; + // Below full size libjpeg-turbo decodes 4:2:0 chroma with the next larger + // reduced IDCT: chroma blocks cover whole MCUs at output resolution. + const bool chroma_unsampled = params.scale_shift != 0u; + const uint c_scale_shift = chroma_unsampled ? params.scale_shift - 1u : 0u; + const uint c_block_size = 8u >> c_scale_shift; + const uint chroma_origin_x = chroma_unsampled ? params.origin_x : params.origin_x / 2u; + const uint chroma_origin_y = chroma_unsampled ? params.origin_y : params.origin_y / 2u; uint mx = 0u; uint my = 0u; @@ -839,10 +847,10 @@ kernel void jpeg_decode_fast420_scaled_region( if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, params.entropy_len, y_dc, y_ac, y_quant, y_prev_dc, thread_status, y_plane, params.scaled_width, params.scaled_width, params.scaled_height, params.origin_x, params.origin_y, y_x + y_block_size, y_y + y_block_size, y_block_size, y_block_size, params.scale_shift, coeffs)) { return; } - if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, params.entropy_len, cb_dc, cb_ac, cb_quant, cb_prev_dc, thread_status, cb_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, params.scale_shift, coeffs)) { + if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, params.entropy_len, cb_dc, cb_ac, cb_quant, cb_prev_dc, thread_status, cb_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, c_scale_shift, coeffs)) { return; } - if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, params.entropy_len, cr_dc, cr_ac, cr_quant, cr_prev_dc, thread_status, cr_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, params.scale_shift, coeffs)) { + if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, params.entropy_len, cr_dc, cr_ac, cr_quant, cr_prev_dc, thread_status, cr_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, c_scale_shift, coeffs)) { return; } advance_mcu_cursor(mx, my, params.mcus_per_row); @@ -895,10 +903,14 @@ kernel void jpeg_decode_fast420_scaled_region_batch( thread short coeffs[64]; const uint y_block_size = 8u >> params.scale_shift; - const uint c_block_size = 8u >> params.scale_shift; const uint y_mcu_size = 16u >> params.scale_shift; - const uint chroma_origin_x = params.origin_x / 2u; - const uint chroma_origin_y = params.origin_y / 2u; + // Below full size libjpeg-turbo decodes 4:2:0 chroma with the next larger + // reduced IDCT: chroma blocks cover whole MCUs at output resolution. + const bool chroma_unsampled = params.scale_shift != 0u; + const uint c_scale_shift = chroma_unsampled ? params.scale_shift - 1u : 0u; + const uint c_block_size = 8u >> c_scale_shift; + const uint chroma_origin_x = chroma_unsampled ? params.origin_x : params.origin_x / 2u; + const uint chroma_origin_y = chroma_unsampled ? params.origin_y : params.origin_y / 2u; uint mx = 0u; uint my = 0u; @@ -920,10 +932,10 @@ kernel void jpeg_decode_fast420_scaled_region_batch( if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, entropy_end, y_dc, y_ac, y_quant, y_prev_dc, thread_status, tile_y_plane, params.scaled_width, params.scaled_width, params.scaled_height, params.origin_x, params.origin_y, y_x + y_block_size, y_y + y_block_size, y_block_size, y_block_size, params.scale_shift, coeffs)) { return; } - if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, entropy_end, cb_dc, cb_ac, cb_quant, cb_prev_dc, thread_status, tile_cb_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, params.scale_shift, coeffs)) { + if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, entropy_end, cb_dc, cb_ac, cb_quant, cb_prev_dc, thread_status, tile_cb_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, c_scale_shift, coeffs)) { return; } - if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, entropy_end, cr_dc, cr_ac, cr_quant, cr_prev_dc, thread_status, tile_cr_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, params.scale_shift, coeffs)) { + if (!jpeg_decode_deposit_scaled_region_block_or_skip(br, entropy, entropy_end, cr_dc, cr_ac, cr_quant, cr_prev_dc, thread_status, tile_cr_plane, params.chroma_width, params.chroma_width, params.chroma_height, chroma_origin_x, chroma_origin_y, c_x, c_y, c_block_size, c_block_size, c_scale_shift, coeffs)) { return; } advance_mcu_cursor(mx, my, params.mcus_per_row); diff --git a/crates/j2k-jpeg-metal/src/shaders_encode.metal b/crates/j2k-jpeg-metal/src/shaders_encode.metal index 807c8b650..d5614edca 100644 --- a/crates/j2k-jpeg-metal/src/shaders_encode.metal +++ b/crates/j2k-jpeg-metal/src/shaders_encode.metal @@ -586,15 +586,24 @@ inline bool block_intersects_rect( return block_x < rect_x1 && rect_x < block_x1 && block_y < rect_y1 && rect_y < block_y1; } -inline int descale(int value, int shift) { - return value >> shift; -} - +// Callers of descale_and_clamp add their own rounding term (the full islow IDCT +// folds it into the DC path). inline uchar descale_and_clamp(int value, int shift) { const int shifted = value >> shift; return clamp_u8(shifted + 128); } +// libjpeg DESCALE: arithmetic right shift that rounds half up. Every stage of +// jidctred.c (and libjpeg-turbo's SIMD ports) rounds; a plain shift biases +// DCT-scaled output low by up to one level per component. +inline int descale_rounded(int value, int shift) { + return (value + (1 << (shift - 1))) >> shift; +} + +inline uchar descale_rounded_and_clamp(int value, int shift) { + return clamp_u8(descale_rounded(value, shift) + 128); +} + // libjpeg islow column pass over four columns at once. There is no per-column // DC shortcut: with all AC terms zero the full expression is exactly p0 << PASS1_BITS, // and i16 inputs cannot overflow it. @@ -951,10 +960,10 @@ inline void idct_4x4_column( + p1 * FIX_2_562915447; const int shift = CONST_BITS - PASS1_BITS + 1; - work[col] = descale(tmp10 + tmp2, shift); - work[24 + col] = descale(tmp10 - tmp2, shift); - work[8 + col] = descale(tmp12 + tmp0, shift); - work[16 + col] = descale(tmp12 - tmp0, shift); + work[col] = descale_rounded(tmp10 + tmp2, shift); + work[24 + col] = descale_rounded(tmp10 - tmp2, shift); + work[8 + col] = descale_rounded(tmp12 + tmp0, shift); + work[16 + col] = descale_rounded(tmp12 - tmp0, shift); } inline void idct_4x4_row( @@ -973,7 +982,7 @@ inline void idct_4x4_row( const uint out = row * 4; if (p1 == 0 && p2 == 0 && p3 == 0 && p5 == 0 && p6 == 0 && p7 == 0) { - const uchar dc = descale_and_clamp(p0, PASS1_BITS + 3); + const uchar dc = descale_rounded_and_clamp(p0, PASS1_BITS + 3); output[out] = dc; output[out + 1] = dc; output[out + 2] = dc; @@ -996,10 +1005,10 @@ inline void idct_4x4_row( + p1 * FIX_2_562915447; const int shift = CONST_BITS + PASS1_BITS + 3 + 1; - output[out] = descale_and_clamp(tmp10 + tmp2, shift); - output[out + 3] = descale_and_clamp(tmp10 - tmp2, shift); - output[out + 1] = descale_and_clamp(tmp12 + tmp0, shift); - output[out + 2] = descale_and_clamp(tmp12 - tmp0, shift); + output[out] = descale_rounded_and_clamp(tmp10 + tmp2, shift); + output[out + 3] = descale_rounded_and_clamp(tmp10 - tmp2, shift); + output[out + 1] = descale_rounded_and_clamp(tmp12 + tmp0, shift); + output[out + 2] = descale_rounded_and_clamp(tmp12 - tmp0, shift); } inline void idct_islow_4x4( @@ -1043,8 +1052,8 @@ inline void idct_2x2_column( + p1 * FIX_3_624509785; const int shift = CONST_BITS - PASS1_BITS + 2; - work[col] = descale(tmp10 + tmp0, shift); - work[8 + col] = descale(tmp10 - tmp0, shift); + work[col] = descale_rounded(tmp10 + tmp0, shift); + work[8 + col] = descale_rounded(tmp10 - tmp0, shift); } inline void idct_2x2_row( @@ -1060,7 +1069,7 @@ inline void idct_2x2_row( const int p7 = work[base + 7]; if (p1 == 0 && p3 == 0 && p5 == 0 && p7 == 0) { - const uchar dc = descale_and_clamp(p0, PASS1_BITS + 3); + const uchar dc = descale_rounded_and_clamp(p0, PASS1_BITS + 3); const uint out = row * 2; output[out] = dc; output[out + 1] = dc; @@ -1075,8 +1084,8 @@ inline void idct_2x2_row( const int shift = CONST_BITS + PASS1_BITS + 5; const uint out = row * 2; - output[out] = descale_and_clamp(tmp10 + tmp0, shift); - output[out + 1] = descale_and_clamp(tmp10 - tmp0, shift); + output[out] = descale_rounded_and_clamp(tmp10 + tmp0, shift); + output[out + 1] = descale_rounded_and_clamp(tmp10 - tmp0, shift); } inline void idct_islow_2x2( @@ -1096,7 +1105,7 @@ inline void idct_islow_2x2( } inline uchar idct_islow_1x1(thread const short input[64]) { - return descale_and_clamp(int(input[0]), 3); + return descale_rounded_and_clamp(int(input[0]), 3); } inline void deposit_block_region( @@ -1238,6 +1247,13 @@ inline void deposit_scaled_block( thread const short coeffs[64], bool dc_only ) { + if (scale_shift == 0u) { + // 4:2:0 chroma at 1/2 scale: libjpeg-turbo's full 8x8 IDCT. + thread uchar pixels8[64]; + idct_block(coeffs, dc_only, pixels8); + deposit_block_region(plane, stride, width, height, 0u, 0u, x, y, pixels8); + return; + } if (scale_shift == 1u) { thread uchar pixels4[16]; if (dc_only) { @@ -1643,12 +1659,25 @@ inline void jpeg_sample_420_chroma( device const uchar *cr_plane, uint chroma_width, uint chroma_height, + uint chroma_mode, uint x, uint y, thread uchar &cb, thread uchar &cr ) { + if (chroma_mode == CHROMA_UNSAMPLED) { + const uint idx = min(y, chroma_height - 1u) * chroma_width + min(x, chroma_width - 1u); + cb = cb_plane[idx]; + cr = cr_plane[idx]; + return; + } const uint chroma_y = min(y / 2u, chroma_height - 1u); + if (chroma_mode == CHROMA_REPLICATE) { + const uint idx = chroma_y * chroma_width + min(x / 2u, chroma_width - 1u); + cb = cb_plane[idx]; + cr = cr_plane[idx]; + return; + } const uint near_y = (y & 1u) == 0u ? (chroma_y == 0u ? 0u : chroma_y - 1u) : min(chroma_y + 1u, chroma_height - 1u); @@ -1666,6 +1695,7 @@ inline void jpeg_sample_422_chroma( device const uchar *cr_plane, uint chroma_width, uint chroma_height, + uint chroma_mode, uint x, uint y, thread uchar &cb, @@ -1674,6 +1704,12 @@ inline void jpeg_sample_422_chroma( const uint chroma_y = min(y, chroma_height - 1u); device const uchar *curr_cb = cb_plane + chroma_y * chroma_width; device const uchar *curr_cr = cr_plane + chroma_y * chroma_width; + if (chroma_mode != CHROMA_FANCY) { + const uint chroma_x = min(chroma_mode == CHROMA_UNSAMPLED ? x : x / 2u, chroma_width - 1u); + cb = curr_cb[chroma_x]; + cr = curr_cr[chroma_x]; + return; + } cb = h2v1_sample(curr_cb, chroma_width, x); cr = h2v1_sample(curr_cr, chroma_width, x); diff --git a/crates/j2k-jpeg-metal/src/shaders_pack_subsampled.metal b/crates/j2k-jpeg-metal/src/shaders_pack_subsampled.metal index 65454505d..1d08e9c02 100644 --- a/crates/j2k-jpeg-metal/src/shaders_pack_subsampled.metal +++ b/crates/j2k-jpeg-metal/src/shaders_pack_subsampled.metal @@ -23,6 +23,8 @@ kernel void jpeg_pack_420( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, gid.x, gid.y, cb, @@ -56,6 +58,8 @@ kernel void jpeg_pack_420_rgb( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, gid.x, gid.y, cb, @@ -157,6 +161,8 @@ kernel void jpeg_pack_420_rgba( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, gid.x, gid.y, cb, @@ -266,6 +272,8 @@ kernel void jpeg_pack_422_rgb( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, gid.x, gid.y, cb, @@ -380,6 +388,8 @@ kernel void jpeg_pack_422_rgba( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, gid.x, gid.y, cb, @@ -421,6 +431,8 @@ kernel void jpeg_pack_422_windowed( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -460,6 +472,8 @@ kernel void jpeg_pack_422_windowed_rgb( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -502,6 +516,8 @@ kernel void jpeg_pack_422_windowed_rgb_batch( tile_cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -545,6 +561,8 @@ kernel void jpeg_pack_422_windowed_rgba_texture( tile_cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -579,6 +597,8 @@ kernel void jpeg_pack_422_windowed_rgba( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -620,6 +640,8 @@ kernel void jpeg_pack_420_windowed( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -659,6 +681,8 @@ kernel void jpeg_pack_420_windowed_rgb( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -701,6 +725,8 @@ kernel void jpeg_pack_420_windowed_rgb_batch( tile_cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -744,6 +770,8 @@ kernel void jpeg_pack_420_windowed_rgba_texture( tile_cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, @@ -797,6 +825,8 @@ kernel void jpeg_pack_420_windowed_rgba( cr_plane, params.chroma_width, params.chroma_height, + + params.chroma_mode, src_x, src_y, cb, diff --git a/crates/j2k-jpeg-metal/src/shaders_shared.metal b/crates/j2k-jpeg-metal/src/shaders_shared.metal index 25b230dd6..c237a1499 100644 --- a/crates/j2k-jpeg-metal/src/shaders_shared.metal +++ b/crates/j2k-jpeg-metal/src/shaders_shared.metal @@ -71,6 +71,7 @@ struct JpegFast420Params { uint out_format; uint origin_x; uint origin_y; + uint chroma_mode; }; struct JpegFast420ScaledParams { @@ -128,6 +129,7 @@ struct JpegFast420WindowedPackParams { uint out_stride; uint alpha; uint out_format; + uint chroma_mode; }; struct JpegFast420BatchParams { @@ -206,6 +208,7 @@ struct JpegWindowedPackBatchParams { uint alpha; uint mode; uint out_format; + uint chroma_mode; }; struct JpegWindowedTexturePackBatchParams { @@ -219,6 +222,7 @@ struct JpegWindowedTexturePackBatchParams { uint height; uint tile_index; uint alpha; + uint chroma_mode; }; struct JpegTexturePackBatchParams { @@ -280,6 +284,17 @@ constant uint MODE_GRAY = 0; constant uint MODE_YCBCR = 1; constant uint MODE_RGB = 2; +// How the pack kernels map subsampled chroma planes onto output pixels, +// following libjpeg-turbo's upsampler choice for the decode scale. +// CHROMA_FANCY: triangle-filter upsampling (h2v1/h2v2_fancy_upsample). +// CHROMA_REPLICATE: each chroma sample repeated (smoothing off at 1/8 scale or +// for chroma at most two samples wide). +// CHROMA_UNSAMPLED: chroma planes already at output resolution (4:2:0 decoded +// below full size with libjpeg-turbo's larger chroma IDCT). +constant uint CHROMA_FANCY = 0; +constant uint CHROMA_REPLICATE = 1; +constant uint CHROMA_UNSAMPLED = 2; + constant uint OUT_GRAY = 0; constant uint OUT_RGB = 1; constant uint OUT_RGBA = 2; diff --git a/crates/j2k-jpeg-metal/tests/scaled_matrix.rs b/crates/j2k-jpeg-metal/tests/scaled_matrix.rs new file mode 100644 index 000000000..82590f7be --- /dev/null +++ b/crates/j2k-jpeg-metal/tests/scaled_matrix.rs @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! Metal DCT-scaled decodes against the libjpeg-turbo reference matrix. +//! +//! The Metal fast families (8-bit baseline 4:4:4, 4:2:2 and 4:2:0) must +//! reproduce libjpeg-turbo's scaled output exactly: 4:2:0 chroma decoded with +//! the larger IDCT below full size, 4:2:2 chroma replicated at 1/8 and when at +//! most two samples wide. Images at most four pixels wide, whose full-size +//! 2:1 chroma libjpeg-turbo replicates, are not Metal fast shapes and must be +//! rejected by explicit Metal requests rather than decoded differently. +#![cfg(target_os = "macos")] + +use j2k_core::{BackendKind, BackendRequest, DeviceSurface, Downscale, PixelFormat, Rect}; +use j2k_jpeg_metal::{Decoder, JpegTileBatch, MetalDecodeRequest}; +use j2k_test_support::{ + crop_interleaved_bytes, scaled_matrix_cases, scaled_rect_covering, PixelRect, ScaledMatrixCase, + SCALED_MATRIX_DENOMINATORS, +}; + +fn should_run_metal_runtime() -> bool { + j2k_test_support::metal_runtime_gate(module_path!()) +} + +fn downscale(denominator: u32) -> Downscale { + match denominator { + 1 => Downscale::None, + 2 => Downscale::Half, + 4 => Downscale::Quarter, + 8 => Downscale::Eighth, + _ => unreachable!("matrix denominators are 1, 2, 4, 8"), + } +} + +/// 8-bit sequential cases in the Metal fast families. +fn metal_family_cases() -> Vec { + scaled_matrix_cases() + .into_iter() + .filter(|case| { + case.precision == 8 + && matches!(case.layout, "444" | "422" | "420") + && matches!(case.coding, "baseline" | "restart") + }) + .collect() +} + +/// Full-size 2:1 chroma at most two samples wide: libjpeg-turbo replicates +/// it, so these images are not Metal fast shapes. +fn is_narrow_subsampled(case: &ScaledMatrixCase) -> bool { + case.layout != "444" && case.width <= 4 +} + +fn expected_rgba(rgb: &[u8]) -> Vec { + rgb.chunks_exact(3) + .flat_map(|px| [px[0], px[1], px[2], u8::MAX]) + .collect() +} + +fn mismatch(expected: &[u8], actual: &[u8]) -> Option { + if expected.len() != actual.len() { + return Some(format!( + "{} bytes, expected {}", + actual.len(), + expected.len() + )); + } + let diffs: Vec = expected + .iter() + .zip(actual) + .map(|(&e, &a)| e.abs_diff(a)) + .filter(|&d| d > 0) + .collect(); + let max = diffs.iter().copied().max()?; + Some(format!( + "{} of {} bytes differ, max {max}", + diffs.len(), + expected.len() + )) +} + +fn assert_no_failures(failures: &[String]) { + assert!( + failures.is_empty(), + "{} Metal scaled decodes differ from libjpeg-turbo:\n{}", + failures.len(), + failures.join("\n") + ); +} + +fn region_for(case: &ScaledMatrixCase) -> Rect { + Rect { + x: case.width / 3, + y: case.height / 4, + w: case.width / 2, + h: case.height / 2, + } +} + +fn expected_region(case: &ScaledMatrixCase, roi: Rect, denominator: u32) -> (PixelRect, Vec) { + let scaled = scaled_rect_covering( + PixelRect { + x: roi.x, + y: roi.y, + w: roi.w, + h: roi.h, + }, + denominator, + ); + let (width, _) = case.scaled_dimensions(denominator); + let crop = crop_interleaved_bytes(case.reference(denominator), width as usize, 3, scaled); + (scaled, crop) +} + +#[test] +fn metal_scaled_decodes_match_libjpeg_turbo() { + if !should_run_metal_runtime() { + return; + } + let mut failures = Vec::new(); + for case in metal_family_cases() + .iter() + .filter(|case| !is_narrow_subsampled(case)) + { + for denominator in SCALED_MATRIX_DENOMINATORS { + for fmt in [PixelFormat::Rgb8, PixelFormat::Rgba8] { + let label = format!("{} {fmt:?} 1/{denominator}", case.name); + let mut decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + let request = + MetalDecodeRequest::scaled(fmt, downscale(denominator), BackendRequest::Metal); + match decoder.decode_request_to_device(request) { + Ok(surface) => { + assert_eq!(surface.backend_kind(), BackendKind::Metal, "{label}"); + let rgb = case.reference(denominator); + let expected = if fmt == PixelFormat::Rgba8 { + expected_rgba(rgb) + } else { + rgb.to_vec() + }; + let bytes = surface.as_bytes().expect("surface bytes"); + if let Some(message) = mismatch(&expected, &bytes) { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: Metal decode failed: {err}")), + } + } + } + } + assert_no_failures(&failures); +} + +#[test] +fn metal_scaled_region_decodes_match_libjpeg_turbo_crops() { + if !should_run_metal_runtime() { + return; + } + let mut failures = Vec::new(); + for case in metal_family_cases().iter().filter(|case| case.width >= 18) { + let roi = region_for(case); + for denominator in SCALED_MATRIX_DENOMINATORS { + let label = format!("{} region 1/{denominator}", case.name); + let mut decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + let request = MetalDecodeRequest::region_scaled( + PixelFormat::Rgb8, + roi, + downscale(denominator), + BackendRequest::Metal, + ); + let (scaled, expected) = expected_region(case, roi, denominator); + match decoder.decode_request_to_device(request) { + Ok(surface) => { + assert_eq!(surface.dimensions(), (scaled.w, scaled.h), "{label}"); + let bytes = surface.as_bytes().expect("surface bytes"); + if let Some(message) = mismatch(&expected, &bytes) { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: Metal decode failed: {err}")), + } + } + } + assert_no_failures(&failures); +} + +/// Batches group same-shape tiles into shared dispatches; every tile in a +/// batch must still match its own reference. +#[test] +fn metal_scaled_tile_batches_match_libjpeg_turbo() { + if !should_run_metal_runtime() { + return; + } + let cases: Vec = metal_family_cases() + .into_iter() + .filter(|case| !is_narrow_subsampled(case)) + .collect(); + let mut failures = Vec::new(); + for denominator in SCALED_MATRIX_DENOMINATORS { + for region in [false, true] { + let mut batch = JpegTileBatch::with_capacity(cases.len() * 2); + let mut expected = Vec::new(); + for case in cases.iter().filter(|case| !region || case.width >= 18) { + // Two copies so compatible tiles share a grouped dispatch. + for _ in 0..2 { + let request = if region { + let roi = region_for(case); + expected.push((case.name, expected_region(case, roi, denominator).1)); + MetalDecodeRequest::region_scaled( + PixelFormat::Rgb8, + roi, + downscale(denominator), + BackendRequest::Metal, + ) + } else { + expected.push((case.name, case.reference(denominator).to_vec())); + MetalDecodeRequest::scaled( + PixelFormat::Rgb8, + downscale(denominator), + BackendRequest::Metal, + ) + }; + batch + .push_tile_request(case.jpeg, request) + .expect("push batch tile"); + } + } + let label = if region { "region batch" } else { "batch" }; + match batch.decode_all() { + Ok(surfaces) => { + for (surface, (name, expected)) in surfaces.iter().zip(&expected) { + let bytes = surface.as_bytes().expect("surface bytes"); + if let Some(message) = mismatch(expected, &bytes) { + failures.push(format!("{name} {label} 1/{denominator}: {message}")); + } + } + } + Err(err) => failures.push(format!("{label} 1/{denominator} failed: {err}")), + } + } + } + assert_no_failures(&failures); +} + +#[test] +fn explicit_metal_rejects_narrow_subsampled_images() { + if !should_run_metal_runtime() { + return; + } + for case in metal_family_cases() + .iter() + .filter(|case| is_narrow_subsampled(case)) + { + for denominator in SCALED_MATRIX_DENOMINATORS { + let mut decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + let request = MetalDecodeRequest::scaled( + PixelFormat::Rgb8, + downscale(denominator), + BackendRequest::Metal, + ); + assert!( + decoder.decode_request_to_device(request).is_err(), + "{} 1/{denominator}: narrow 2:1 chroma must not take the Metal fast path", + case.name + ); + } + } +} + +/// Region edges on and beside MCU boundaries at every scale, where the +/// smoothing filters need chroma from outside the decoded window. +#[test] +fn metal_scaled_region_edge_sweep_matches_libjpeg_turbo_crops() { + if !should_run_metal_runtime() { + return; + } + let xs = [0u32, 7, 8, 9, 15, 16, 17]; + let ys = [0u32, 7, 8, 9, 16, 17]; + let mut failures = Vec::new(); + for case in metal_family_cases().iter().filter(|case| case.width == 45) { + for denominator in SCALED_MATRIX_DENOMINATORS { + for &x0 in &xs { + for &x1 in &xs { + for &y0 in &ys { + for &y1 in &ys { + let (x1, y1) = (x1 + 8, y1 + 8); + if x0 >= x1 || y0 >= y1 || x1 > case.width || y1 > case.height { + continue; + } + let roi = Rect { + x: x0, + y: y0, + w: x1 - x0, + h: y1 - y0, + }; + let label = format!( + "{} roi {},{} {}x{} 1/{denominator}", + case.name, roi.x, roi.y, roi.w, roi.h + ); + let mut decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + let request = MetalDecodeRequest::region_scaled( + PixelFormat::Rgb8, + roi, + downscale(denominator), + BackendRequest::Metal, + ); + let (_, expected) = expected_region(case, roi, denominator); + match decoder.decode_request_to_device(request) { + Ok(surface) => { + let bytes = surface.as_bytes().expect("surface bytes"); + if let Some(message) = mismatch(&expected, &bytes) { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: {err}")), + } + } + } + } + } + } + } + assert_no_failures(&failures); +} diff --git a/crates/j2k-jpeg/src/adapter/fast_packet/family.rs b/crates/j2k-jpeg/src/adapter/fast_packet/family.rs index 7e99c4fe4..a5c606c31 100644 --- a/crates/j2k-jpeg/src/adapter/fast_packet/family.rs +++ b/crates/j2k-jpeg/src/adapter/fast_packet/family.rs @@ -29,9 +29,17 @@ pub(super) fn classify_color_fast_packet_info(info: &Info) -> Option 4; match (info.color_space, info.sampling.components()) { - (ColorSpace::YCbCr, [(2, 2), (1, 1), (1, 1)]) => Some(JpegFastPacketFamily::Fast420), - (ColorSpace::YCbCr, [(2, 1), (1, 1), (1, 1)]) => Some(JpegFastPacketFamily::Fast422), + (ColorSpace::YCbCr, [(2, 2), (1, 1), (1, 1)]) if smoothed_chroma => { + Some(JpegFastPacketFamily::Fast420) + } + (ColorSpace::YCbCr, [(2, 1), (1, 1), (1, 1)]) if smoothed_chroma => { + Some(JpegFastPacketFamily::Fast422) + } (ColorSpace::YCbCr | ColorSpace::Rgb, [(1, 1), (1, 1), (1, 1)]) => { Some(JpegFastPacketFamily::Fast444) } diff --git a/crates/j2k-jpeg/src/color/mod.rs b/crates/j2k-jpeg/src/color/mod.rs index b678f469d..9b8f0b957 100644 --- a/crates/j2k-jpeg/src/color/mod.rs +++ b/crates/j2k-jpeg/src/color/mod.rs @@ -3,5 +3,6 @@ //! Color conversion + chroma upsampling. Scalar-only in M1b. pub(crate) mod cmyk; +pub(crate) mod scaled_sampling; pub(crate) mod upsample; pub(crate) mod ycbcr; diff --git a/crates/j2k-jpeg/src/color/scaled_sampling.rs b/crates/j2k-jpeg/src/color/scaled_sampling.rs new file mode 100644 index 000000000..e17252c2f --- /dev/null +++ b/crates/j2k-jpeg/src/color/scaled_sampling.rs @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! libjpeg-turbo's per-component DCT scaling and upsampler choice. +//! +//! When decoding at a reduced scale, libjpeg-turbo (`jdmaster.c`) gives each +//! component its own reduced IDCT: a subsampled component is decoded with a +//! larger IDCT whenever that replaces upsampling, so 4:2:0 chroma at 1/2 is +//! decoded with a full 8x8 IDCT and needs no upsampling at all. `jdsample.c` +//! then picks each component's upsampler: the smoothing ("fancy") filters +//! apply only above 1/8 scale, and the 2:1 horizontal filters only when the +//! component is more than two samples wide; everything else replicates. +//! +//! Every CPU decode path takes its geometry from [`ScaledSampling`] so all of +//! them reproduce libjpeg-turbo (and therefore `OpenSlide`) bit for bit. + +use crate::info::{DownscaleFactor, SamplingFactors}; + +/// How one component's decoded samples reach the output grid. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Upsample { + /// The component is already at output resolution. + None, + /// `h2v1_fancy_upsample`: 2:1 horizontal triangle filter. + FancyH2V1, + /// `h1v2_fancy_upsample`: 1:2 vertical triangle filter. + FancyH1V2, + /// `h2v2_fancy_upsample`: 2:1 horizontal and vertical triangle filter. + FancyH2V2, + /// `int_upsample` and friends: each sample is repeated `h_ratio` times + /// across and each row `v_ratio` times down. + Replicate, +} + +/// Decode geometry of one component at a DCT scale. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct ScaledComponent { + /// Reduced IDCT output size per block side: 8, 4, 2 or 1. + pub(crate) idct_size: u32, + /// Output pixels per decoded sample, horizontally. + pub(crate) h_ratio: u32, + /// Output pixels per decoded sample, vertically. + pub(crate) v_ratio: u32, + /// Decoded samples across the whole image (`downsampled_width`). + pub(crate) width: u32, + /// Decoded sample rows in the whole image (`downsampled_height`). + pub(crate) height: u32, + /// Upsampler libjpeg-turbo selects for this component. + pub(crate) upsample: Upsample, +} + +/// Per-component geometry for one image at one DCT scale. +#[derive(Clone, Copy, Debug)] +pub(crate) struct ScaledSampling { + components: [ScaledComponent; 4], + /// Sampling factors counted in luma-sized output blocks: each component's + /// factors times its IDCT enlargement. Component planes, MCU strides and + /// upsampling ratios follow these; the entropy decode keeps the coded + /// factors. + pub(crate) effective: SamplingFactors, +} + +impl ScaledSampling { + /// Geometry of an image with `sampling` and full-size `dimensions` + /// decoded at `downscale`. + pub(crate) fn new( + sampling: SamplingFactors, + downscale: DownscaleFactor, + dimensions: (u32, u32), + ) -> Self { + let block_size = downscale.output_block_size(); + let max_h = u32::from(sampling.max_h); + let max_v = u32::from(sampling.max_v); + // jdsample.c: `do_fancy = do_fancy_upsampling && min_DCT_scaled_size > 1`. + let smoothing = block_size > 1; + let mut components = [ScaledComponent { + idct_size: block_size, + h_ratio: 1, + v_ratio: 1, + width: 0, + height: 0, + upsample: Upsample::None, + }; 4]; + let mut effective = [(1u8, 1u8); 4]; + for (index, (h, v)) in sampling.iter().enumerate() { + let (h, v) = (u32::from(h), u32::from(v)); + // jdmaster.c `jpeg_calc_output_dimensions`: grow the IDCT while + // both upsampling ratios stay even. + let mut idct_size = block_size; + while idct_size < 8 + && (max_h * block_size).is_multiple_of(h * idct_size * 2) + && (max_v * block_size).is_multiple_of(v * idct_size * 2) + { + idct_size *= 2; + } + let h_ratio = max_h * block_size / (h * idct_size); + let v_ratio = max_v * block_size / (v * idct_size); + let width = downsampled_extent(dimensions.0, h * idct_size, max_h); + let height = downsampled_extent(dimensions.1, v * idct_size, max_v); + let upsample = match (h_ratio, v_ratio) { + (1, 1) => Upsample::None, + (2, 1) if smoothing && width > 2 => Upsample::FancyH2V1, + (1, 2) if smoothing => Upsample::FancyH1V2, + (2, 2) if smoothing && width > 2 => Upsample::FancyH2V2, + _ => Upsample::Replicate, + }; + components[index] = ScaledComponent { + idct_size, + h_ratio, + v_ratio, + width, + height, + upsample, + }; + effective[index] = ( + effective_factor(h, idct_size, block_size), + effective_factor(v, idct_size, block_size), + ); + } + Self { + components, + effective: SamplingFactors::from_validated_components(&effective[..sampling.len()]), + } + } + + /// Geometry of the component at `index` (declaration and plane order). + pub(crate) fn component(&self, index: usize) -> ScaledComponent { + debug_assert!(index < self.effective.len()); + self.components[index] + } + + /// Whether every component decodes straight to output resolution. + pub(crate) fn is_unsampled(&self) -> bool { + self.components[..self.effective.len()] + .iter() + .all(|component| component.upsample == Upsample::None) + } + + /// Whether this is three-component data whose chroma both use the 4:2:0 + /// smoothing filter against a 2x2 first component, the shape the + /// dedicated 4:2:0 emitters handle. + pub(crate) fn is_fancy_420(&self) -> bool { + self.effective.components() == [(2, 2), (1, 1), (1, 1)] + && self.components[1].upsample == Upsample::FancyH2V2 + && self.components[2].upsample == Upsample::FancyH2V2 + } +} + +/// `jdiv_round_up(image_extent * factor * idct_size, max_factor * DCTSIZE)`. +fn downsampled_extent(image_extent: u32, factor_times_idct: u32, max_factor: u32) -> u32 { + let numerator = u64::from(image_extent) * u64::from(factor_times_idct); + let denominator = u64::from(max_factor) * 8; + u32::try_from(numerator.div_ceil(denominator)).unwrap_or(u32::MAX) +} + +#[expect( + clippy::cast_possible_truncation, + reason = "IDCT enlargement never lifts a factor above the 1..=4 maximum" +)] +fn effective_factor(factor: u32, idct_size: u32, block_size: u32) -> u8 { + (factor * idct_size / block_size) as u8 +} + +#[cfg(test)] +mod tests { + use super::{ScaledSampling, Upsample}; + use crate::info::{DownscaleFactor, SamplingFactors}; + + fn chroma(luma: (u8, u8), downscale: DownscaleFactor, width: u32) -> (u32, u32, u32, Upsample) { + let sampling = SamplingFactors::from_components(&[luma, (1, 1), (1, 1)]).unwrap(); + let chroma = ScaledSampling::new(sampling, downscale, (width, 64)).component(1); + ( + chroma.idct_size, + chroma.h_ratio, + chroma.v_ratio, + chroma.upsample, + ) + } + + #[test] + fn subsampled_chroma_uses_libjpeg_turbo_idct_sizes() { + use DownscaleFactor::{Eighth, Full, Half, Quarter}; + use Upsample::{FancyH1V2, FancyH2V1, FancyH2V2, None, Replicate}; + // 4:2:0 chroma is decoded at twice the luma IDCT size below full. + assert_eq!(chroma((2, 2), Full, 64), (8, 2, 2, FancyH2V2)); + assert_eq!(chroma((2, 2), Half, 64), (8, 1, 1, None)); + assert_eq!(chroma((2, 2), Quarter, 64), (4, 1, 1, None)); + assert_eq!(chroma((2, 2), Eighth, 64), (2, 1, 1, None)); + // 4:2:2 and 4:4:0 keep the luma size; 1/8 replicates. + assert_eq!(chroma((2, 1), Half, 64), (4, 2, 1, FancyH2V1)); + assert_eq!(chroma((2, 1), Eighth, 64), (1, 2, 1, Replicate)); + assert_eq!(chroma((1, 2), Quarter, 64), (2, 1, 2, FancyH1V2)); + assert_eq!(chroma((1, 2), Eighth, 64), (1, 1, 2, Replicate)); + // 4:1:0 chroma grows once, leaving a smoothed 2:1 horizontal step. + assert_eq!(chroma((4, 2), Half, 64), (8, 2, 1, FancyH2V1)); + assert_eq!(chroma((4, 2), Eighth, 64), (2, 2, 1, Replicate)); + // 4:1:1 and 1x4 always replicate. + assert_eq!(chroma((4, 1), Half, 64), (4, 4, 1, Replicate)); + assert_eq!(chroma((1, 4), Full, 64), (8, 1, 4, Replicate)); + } + + #[test] + fn narrow_chroma_replicates_instead_of_smoothing() { + use DownscaleFactor::{Full, Quarter}; + // Four pixels of 4:2:0 or 4:2:2 leave two chroma samples. + assert_eq!(chroma((2, 2), Full, 4).3, Upsample::Replicate); + assert_eq!(chroma((2, 1), Full, 4).3, Upsample::Replicate); + assert_eq!(chroma((2, 2), Full, 5).3, Upsample::FancyH2V2); + // 9 pixels at 1/4 leave ceil(9 * 2 / 16) = 2 chroma samples. + assert_eq!(chroma((2, 1), Quarter, 9).3, Upsample::Replicate); + assert_eq!(chroma((2, 1), Quarter, 17).3, Upsample::FancyH2V1); + // The vertical filter has no width limit. + assert_eq!(chroma((1, 2), Full, 2).3, Upsample::FancyH1V2); + } + + #[test] + fn effective_sampling_counts_luma_sized_blocks() { + let sampling = SamplingFactors::from_components(&[(2, 2), (1, 1), (1, 1)]).unwrap(); + let half = ScaledSampling::new(sampling, DownscaleFactor::Half, (64, 64)); + assert_eq!(half.effective.components(), [(2, 2), (2, 2), (2, 2)]); + assert!(half.is_unsampled()); + assert!(!half.is_fancy_420()); + let full = ScaledSampling::new(sampling, DownscaleFactor::Full, (64, 64)); + assert_eq!(full.effective.components(), [(2, 2), (1, 1), (1, 1)]); + assert!(full.is_fancy_420()); + } +} diff --git a/crates/j2k-jpeg/src/decoder.rs b/crates/j2k-jpeg/src/decoder.rs index 70a4b450c..13217fa45 100644 --- a/crates/j2k-jpeg/src/decoder.rs +++ b/crates/j2k-jpeg/src/decoder.rs @@ -13,9 +13,8 @@ use crate::entropy::progressive::{ }; use crate::entropy::sequential::{ decode_scan_baseline, decode_scan_baseline_rgb, decode_scan_fast_rgb_444, - decode_scan_fast_tile_rgb, decode_scan_fast_tile_rgb_region, - decode_scan_fast_tile_rgb_region_scaled, fast_tile_region_first_decode_mcu, finish_scan, - stripe_region_layout, FastTileRegionScaledRequest, PreparedComponentPlan, PreparedDecodePlan, + decode_scan_fast_tile_rgb, decode_scan_fast_tile_rgb_region, fast_tile_region_first_decode_mcu, + finish_scan, stripe_region_layout, PreparedComponentPlan, PreparedDecodePlan, ResolvedPreparedComponentPlan, }; use crate::entropy::ZIGZAG; @@ -82,7 +81,7 @@ use self::color_convert::{ mod warning_ownership; use self::warning_ownership::{merged_warnings, try_clone_warnings}; mod core_traits; -use self::core_traits::{CroppedWriter, ProgressiveDownscaleWriter}; +use self::core_traits::CroppedWriter; mod lossless_region; use self::lossless_region::{LosslessRegionRequest, LosslessRgbRegionFallback, LosslessRgbaAlpha}; mod scratch; diff --git a/crates/j2k-jpeg/src/decoder/core_traits.rs b/crates/j2k-jpeg/src/decoder/core_traits.rs index 00a487201..2c61f420d 100644 --- a/crates/j2k-jpeg/src/decoder/core_traits.rs +++ b/crates/j2k-jpeg/src/decoder/core_traits.rs @@ -2,14 +2,11 @@ use super::{ ComponentRowWriter, CompressedTransferSyntax, CoreDecodeOutcome, DecodeOutcome, - DecodeRowsError, Decoder, DecoderContext, Downscale, DownscaleFactor, ImageCodec, ImageDecode, - ImageDecodeRows, InterleavedRgbWriter, JpegCodec, JpegError, JpegView, OutputWriter, - PixelFormat, Rect, RowSink, ScratchPool, SofKind, TileBatchDecode, Vec, Warning, -}; -use crate::allocation::{ - checked_add_allocation_bytes, checked_allocation_bytes, checked_allocation_len, - try_reserve_for_len_with_live_budget, try_resize_filled, + DecodeRowsError, Decoder, DecoderContext, Downscale, ImageCodec, ImageDecode, ImageDecodeRows, + InterleavedRgbWriter, JpegCodec, JpegError, JpegView, OutputWriter, PixelFormat, Rect, RowSink, + ScratchPool, SofKind, TileBatchDecode, Vec, Warning, }; +use crate::allocation::{checked_allocation_len, try_reserve_for_len_with_live_budget}; use j2k_core::TileRegionScaledDecodeJob; #[cfg(test)] @@ -260,121 +257,6 @@ pub(super) struct CroppedWriter { pub(super) bottom_row: Vec, } -pub(super) struct ProgressiveDownscaleWriter<'a, W> { - pub(super) inner: &'a mut W, - pub(super) denom: u32, - pub(super) scaled_width: usize, - pub(super) r: Vec, - pub(super) g: Vec, - pub(super) b: Vec, -} - -impl<'a, W> ProgressiveDownscaleWriter<'a, W> { - pub(super) fn new( - inner: &'a mut W, - downscale: DownscaleFactor, - dimensions: (u32, u32), - ) -> Result { - let denom = downscale.denominator(); - let scaled_width = dimensions.0.div_ceil(denom) as usize; - let row_bytes = checked_allocation_len::(scaled_width, 3)?; - let mut live_bytes = 0; - let mut r = Vec::new(); - try_reserve_for_len_with_live_budget(&mut r, scaled_width, &mut live_bytes, row_bytes)?; - r.resize(scaled_width, 0); - let mut g = Vec::new(); - try_reserve_for_len_with_live_budget(&mut g, scaled_width, &mut live_bytes, row_bytes)?; - g.resize(scaled_width, 0); - let mut b = Vec::new(); - try_reserve_for_len_with_live_budget(&mut b, scaled_width, &mut live_bytes, row_bytes)?; - b.resize(scaled_width, 0); - Ok(Self { - inner, - denom, - scaled_width, - r, - g, - b, - }) - } - - pub(super) fn capacity_bytes(&self) -> Result { - let rg = checked_add_allocation_bytes( - checked_allocation_bytes::(self.r.capacity())?, - checked_allocation_bytes::(self.g.capacity())?, - )?; - checked_add_allocation_bytes(rg, checked_allocation_bytes::(self.b.capacity())?) - } - - fn should_emit(&self, y: u32) -> bool { - y.is_multiple_of(self.denom) - } - - #[expect( - clippy::cast_possible_truncation, - reason = "validated JPEG output widths originate as u32 dimensions before slice indexing" - )] - fn sample_row( - src: &[u8], - denom: u32, - width: usize, - dst: &mut Vec, - ) -> Result<(), JpegError> { - try_resize_filled(dst, width, 0)?; - for (x, out) in dst.iter_mut().enumerate() { - let src_x = (x as u32) - .saturating_mul(denom) - .min(src.len().saturating_sub(1) as u32); - *out = src[src_x as usize]; - } - Ok(()) - } -} - -impl OutputWriter for ProgressiveDownscaleWriter<'_, W> { - fn write_rgb_row( - &mut self, - y: u32, - r_row: &[u8], - g_row: &[u8], - b_row: &[u8], - ) -> Result<(), JpegError> { - if !self.should_emit(y) { - return Ok(()); - } - Self::sample_row(r_row, self.denom, self.scaled_width, &mut self.r)?; - Self::sample_row(g_row, self.denom, self.scaled_width, &mut self.g)?; - Self::sample_row(b_row, self.denom, self.scaled_width, &mut self.b)?; - self.inner - .write_rgb_row(y / self.denom, &self.r, &self.g, &self.b) - } - - fn write_ycbcr_row( - &mut self, - y: u32, - y_row: &[u8], - cb_row: &[u8], - cr_row: &[u8], - ) -> Result<(), JpegError> { - if !self.should_emit(y) { - return Ok(()); - } - Self::sample_row(y_row, self.denom, self.scaled_width, &mut self.r)?; - Self::sample_row(cb_row, self.denom, self.scaled_width, &mut self.g)?; - Self::sample_row(cr_row, self.denom, self.scaled_width, &mut self.b)?; - self.inner - .write_ycbcr_row(y / self.denom, &self.r, &self.g, &self.b) - } - - fn write_gray_row(&mut self, y: u32, gray_row: &[u8]) -> Result<(), JpegError> { - if !self.should_emit(y) { - return Ok(()); - } - Self::sample_row(gray_row, self.denom, self.scaled_width, &mut self.r)?; - self.inner.write_gray_row(y / self.denom, &self.r) - } -} - impl OutputWriter for &mut W { fn write_rgb_row( &mut self, diff --git a/crates/j2k-jpeg/src/decoder/core_traits/tests.rs b/crates/j2k-jpeg/src/decoder/core_traits/tests.rs index f453b2785..c5f8363f0 100644 --- a/crates/j2k-jpeg/src/decoder/core_traits/tests.rs +++ b/crates/j2k-jpeg/src/decoder/core_traits/tests.rs @@ -4,9 +4,9 @@ use core::fmt; use j2k_core::{DecodeRowsError, ImageDecode, ImageDecodeRows, TileBatchDecode}; use super::{ - core_outcome, CroppedWriter, Decoder, DecoderContext, Downscale, DownscaleFactor, - InterleavedRgbWriter, JpegCodec, JpegError, OutputWriter, PixelFormat, - ProgressiveDownscaleWriter, Rect, RowSink, ScratchPool, TileRegionScaledDecodeJob, Warning, + core_outcome, CroppedWriter, Decoder, DecoderContext, Downscale, InterleavedRgbWriter, + JpegCodec, JpegError, OutputWriter, PixelFormat, Rect, RowSink, ScratchPool, + TileRegionScaledDecodeJob, Warning, }; const JPEG: &[u8] = j2k_test_support::JPEG_BASELINE_420_16X16; @@ -291,47 +291,6 @@ fn core_row_adapter_preserves_the_original_sink_error_type() { assert!(matches!(error, DecodeRowsError::Sink(SinkStopped))); } -#[test] -fn progressive_downscale_writer_samples_each_output_mode_and_skips_intermediate_rows() { - let mut rows = RecordedRows::default(); - { - let mut writer = ProgressiveDownscaleWriter::new(&mut rows, DownscaleFactor::Half, (5, 4)) - .expect("bounded progressive row scratch"); - assert!(writer.capacity_bytes().expect("row capacity") >= 9); - - writer - .write_rgb_row(1, &[1; 5], &[2; 5], &[3; 5]) - .expect("skipped RGB row"); - writer - .write_rgb_row( - 2, - &[1, 2, 3, 4, 5], - &[6, 7, 8, 9, 10], - &[11, 12, 13, 14, 15], - ) - .expect("sampled RGB row"); - writer - .write_ycbcr_row(0, &[21, 22, 23, 24, 25], &[31; 5], &[41; 5]) - .expect("sampled YCbCr row"); - writer - .write_gray_row(1, &[51; 5]) - .expect("skipped grayscale row"); - writer - .write_gray_row(2, &[51, 52, 53, 54, 55]) - .expect("sampled grayscale row"); - } - - assert_eq!( - rows.rgb, - vec![(1, vec![1, 3, 5], vec![6, 8, 10], vec![11, 13, 15])] - ); - assert_eq!( - rows.ycbcr, - vec![(0, vec![21, 23, 25], vec![31; 3], vec![41; 3])] - ); - assert_eq!(rows.gray, vec![(1, vec![51, 53, 55])]); -} - #[test] fn cropped_interleaved_writer_emits_only_rows_inside_the_source_window() { let inner = RecordedRows { diff --git a/crates/j2k-jpeg/src/decoder/extended12.rs b/crates/j2k-jpeg/src/decoder/extended12.rs index 34e068520..86f15ec0b 100644 --- a/crates/j2k-jpeg/src/decoder/extended12.rs +++ b/crates/j2k-jpeg/src/decoder/extended12.rs @@ -9,6 +9,7 @@ mod planes; mod progressive; mod rgba; mod sampling; +mod scaled; mod sequential; mod state; mod upsample; diff --git a/crates/j2k-jpeg/src/decoder/extended12/progressive.rs b/crates/j2k-jpeg/src/decoder/extended12/progressive.rs index 60a1a9dd0..b429e4530 100644 --- a/crates/j2k-jpeg/src/decoder/extended12/progressive.rs +++ b/crates/j2k-jpeg/src/decoder/extended12/progressive.rs @@ -10,9 +10,11 @@ use super::planes::{dequantize_progressive12_block, ensure_progressive12_coeffic use super::sampling::{ progressive_color_sampling, progressive_four_component_sampling, Extended12ColorSampling, }; +use super::scaled::{needs_scaled_extended12_route, Extended12Color}; use super::writers::{ write_extended12_block_region, Extended12Output, Extended12RgbProjection, Extended12WriteRegion, }; +use crate::color::scaled_sampling::ScaledSampling; mod color444; mod four_component; @@ -82,10 +84,20 @@ impl Decoder<'_> { height: self.info.dimensions.1, }); } + let scaled_route = needs_scaled_extended12_route( + &ScaledSampling::new(plan.sampling, downscale, self.info.dimensions), + downscale, + ); if matches!(output, Extended12Output::Rgb16) { match self.info.color_space { ColorSpace::Rgb => { let sampling = progressive_color_sampling(plan, self.info.sof_kind)?; + if scaled_route { + let color = Extended12Color::Rgb(Extended12RgbProjection::Identity); + return self.decode_extended12_scaled_region_into( + out, stride, roi, downscale, color, + ); + } return match sampling { Extended12ColorSampling::S444 => self .decode_progressive12_color444_region_into( @@ -108,6 +120,12 @@ impl Decoder<'_> { } ColorSpace::YCbCr => { let sampling = progressive_color_sampling(plan, self.info.sof_kind)?; + if scaled_route { + let color = Extended12Color::Rgb(Extended12RgbProjection::YCbCr); + return self.decode_extended12_scaled_region_into( + out, stride, roi, downscale, color, + ); + } return match sampling { Extended12ColorSampling::S444 => self .decode_progressive12_color444_region_into( @@ -130,6 +148,12 @@ impl Decoder<'_> { } ColorSpace::Cmyk | ColorSpace::Ycck => { let sampling = progressive_four_component_sampling(plan, self.info.sof_kind)?; + if scaled_route { + let color = Extended12Color::FourComponent(self.info.color_space); + return self.decode_extended12_scaled_region_into( + out, stride, roi, downscale, color, + ); + } return self.decode_progressive12_four_component_region_into( out, stride, roi, downscale, sampling, ); @@ -142,6 +166,15 @@ impl Decoder<'_> { sof: self.info.sof_kind, }); } + if scaled_route { + return self.decode_extended12_scaled_region_into( + out, + stride, + roi, + downscale, + Extended12Color::Gray(output), + ); + } let output_rect = scaled_rect_covering(roi, downscale)?; let dct_blocks = decode_progressive_dct_blocks(plan, self.bytes, 0)?; diff --git a/crates/j2k-jpeg/src/decoder/extended12/scaled.rs b/crates/j2k-jpeg/src/decoder/extended12/scaled.rs new file mode 100644 index 000000000..4968630b7 --- /dev/null +++ b/crates/j2k-jpeg/src/decoder/extended12/scaled.rs @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! libjpeg-turbo DCT scaling for 12-bit sequential and progressive images. +//! +//! Each component is inverse-transformed with the reduced IDCT libjpeg-turbo +//! picks for it ([`ScaledSampling`]) into a plane at its scaled resolution; +//! output rows then upsample every plane with libjpeg-turbo's upsampler for +//! that component and convert the color. Full-size decodes take this route +//! only when libjpeg-turbo replicates a narrow 2:1 component instead of +//! smoothing it; every other full-size decode keeps the direct writers. + +use alloc::vec::Vec; + +use super::super::{ + checked_scratch_len, decode_block_with_activity, decode_progressive_dct_blocks, finish_scan, + merged_warnings, scaled_rect_covering, try_clone_warnings, Backend, BitReader, BlockActivity, + CoefficientBlock, ColorSpace, DecodeOutcome, Decoder, DownscaleFactor, JpegError, Rect, + SofKind, +}; +use super::planes::{dequantize_progressive12_block, ensure_progressive12_coefficient_capacities}; +use super::state::Extended12RestartTracker; +use super::writers::{Extended12Output, Extended12RgbProjection}; +use crate::allocation::try_reserve_for_len_with_live_budget; +use crate::color::scaled_sampling::{ScaledComponent, ScaledSampling, Upsample}; +use crate::idct::downscale::{idct_islow_12bit_1x1, idct_islow_12bit_2x2, idct_islow_12bit_4x4}; + +/// How 12-bit component samples become output pixels. +#[derive(Clone, Copy, Debug)] +pub(super) enum Extended12Color { + /// One component written as `Gray16`, or as `Rgb16` with equal channels. + Gray(Extended12Output), + /// Three components written as `Rgb16`. + Rgb(Extended12RgbProjection), + /// Inverted CMYK or YCCK written as `Rgb16`. + FourComponent(ColorSpace), +} + +impl Extended12Color { + fn components(self) -> usize { + match self { + Self::Gray(_) => 1, + Self::Rgb(_) => 3, + Self::FourComponent(_) => 4, + } + } +} + +/// Whether a 12-bit decode needs libjpeg-turbo's scaled geometry: any reduced +/// scale, or a full-size 2:1 component that libjpeg-turbo replicates because +/// it is at most two samples wide. +pub(super) fn needs_scaled_extended12_route( + scaled: &ScaledSampling, + downscale: DownscaleFactor, +) -> bool { + downscale != DownscaleFactor::Full + || (0..scaled.effective.len()).any(|index| { + let component = scaled.component(index); + component.upsample == Upsample::Replicate && component.h_ratio == 2 + }) +} + +/// A component plane at its scaled resolution, padded to whole blocks. +struct ScaledPlane { + samples: Vec, + stride: usize, + component: ScaledComponent, +} + +impl ScaledPlane { + fn row(&self, y: usize) -> &[u16] { + let y = y.min(self.component.height.saturating_sub(1) as usize); + let start = y * self.stride; + &self.samples[start..start + self.component.width as usize] + } + + fn deposit(&mut self, x: usize, y: usize, size: usize, block: &[u16]) { + for row in 0..size { + let dst = (y + row) * self.stride + x; + self.samples[dst..dst + size].copy_from_slice(&block[row * size..(row + 1) * size]); + } + } +} + +/// At most four component planes, held inline so only sample storage is +/// charged to the decode budget. +struct ScaledPlanes { + planes: [ScaledPlane; 4], + count: usize, +} + +impl ScaledPlanes { + fn as_slice(&self) -> &[ScaledPlane] { + &self.planes[..self.count] + } + + fn get_mut(&mut self, index: usize) -> Option<&mut ScaledPlane> { + self.planes[..self.count].get_mut(index) + } + + fn sample_bytes(&self) -> Result { + self.as_slice().iter().try_fold(0usize, |total, plane| { + let bytes = checked_scratch_len(&[plane.samples.capacity(), 2])?; + checked_scratch_len(&[1, total]).map(|total| total.saturating_add(bytes)) + }) + } +} + +/// Allocates one plane per component, `blocks[i]` (columns, rows) blocks of +/// the component's IDCT size, charging `cap`. +fn allocate_scaled_planes( + scaled: &ScaledSampling, + blocks: &[(usize, usize)], + initial_live_bytes: usize, + cap: usize, +) -> Result { + let mut live_bytes = initial_live_bytes; + let mut planes: [ScaledPlane; 4] = core::array::from_fn(|index| ScaledPlane { + samples: Vec::new(), + stride: 0, + component: scaled.component(index.min(blocks.len().saturating_sub(1))), + }); + for (index, &(cols, rows)) in blocks.iter().enumerate() { + let component = scaled.component(index); + let size = component.idct_size as usize; + let stride = checked_scratch_len(&[cols, size])?; + let len = checked_scratch_len(&[stride, rows, size])?; + let mut samples = Vec::new(); + try_reserve_for_len_with_live_budget(&mut samples, len, &mut live_bytes, cap)?; + samples.resize(len, 0); + planes[index] = ScaledPlane { + samples, + stride, + component, + }; + } + Ok(ScaledPlanes { + planes, + count: blocks.len(), + }) +} + +/// Reduced IDCT of one dequantized block into `pixels` (`size * size` +/// samples); `dc_only` lets the full-size transform take its DC shortcut. +fn idct_12bit_block( + backend: Backend, + coefficients: &[i16; 64], + dc_only: bool, + size: usize, + pixels: &mut [u16; 64], +) { + match size { + 8 if dc_only => pixels.fill(crate::idct::idct_islow_12bit_dc_only_sample( + coefficients[0], + )), + 8 => backend.idct_12bit(coefficients, pixels), + 4 => { + let mut block = [0u16; 16]; + idct_islow_12bit_4x4(coefficients, &mut block); + pixels[..16].copy_from_slice(&block); + } + 2 => { + let mut block = [0u16; 4]; + idct_islow_12bit_2x2(coefficients, &mut block); + pixels[..4].copy_from_slice(&block); + } + _ => pixels[0] = idct_islow_12bit_1x1(coefficients), + } +} + +impl Decoder<'_> { + /// Decodes `roi` of a 12-bit image at `downscale` with libjpeg-turbo's + /// per-component reduced IDCTs and upsamplers. + pub(super) fn decode_extended12_scaled_region_into( + &self, + out: &mut [u8], + stride: usize, + roi: Rect, + downscale: DownscaleFactor, + color: Extended12Color, + ) -> Result { + let output_rect = scaled_rect_covering(roi, downscale)?; + let (planes, warnings, cap) = if self.info.sof_kind == SofKind::Progressive12 { + let planes = self.render_progressive12_scaled_planes(downscale, color)?; + let cap = self + .progressive_plan + .as_ref() + .map_or(0, |plan| plan.scratch_bytes); + (planes, try_clone_warnings(&self.warnings)?, cap) + } else { + let (planes, scan_warnings) = self.decode_extended12_scaled_planes(downscale, color)?; + let warnings = merged_warnings(&self.warnings, scan_warnings)?; + (planes, warnings, self.plan.scratch_bytes) + }; + let live_bytes = planes.sample_bytes()?; + let write = ScaledWrite { + output_rect, + output_width: self.info.dimensions.0.div_ceil(downscale.denominator()) as usize, + live_bytes, + cap, + }; + write_scaled_planes_region(out, stride, write, planes.as_slice(), color)?; + Ok(DecodeOutcome { + decoded: roi, + warnings, + }) + } + + fn decode_extended12_scaled_planes( + &self, + downscale: DownscaleFactor, + color: Extended12Color, + ) -> Result<(ScaledPlanes, Vec), JpegError> { + let plan = &self.plan; + let sof = self.info.sof_kind; + if plan.components.len() != color.components() { + return Err(JpegError::NotImplemented { sof }); + } + let scaled = ScaledSampling::new(plan.sampling, downscale, plan.dimensions); + let max_h = u32::from(plan.sampling.max_h); + let max_v = u32::from(plan.sampling.max_v); + let mcu_cols = plan.dimensions.0.div_ceil(max_h * 8); + let mcu_rows = plan.dimensions.1.div_ceil(max_v * 8); + let blocks: Vec<(usize, usize)> = plan + .sampling + .iter() + .map(|(h, v)| { + ( + mcu_cols as usize * usize::from(h), + mcu_rows as usize * usize::from(v), + ) + }) + .collect(); + let mut planes = allocate_scaled_planes(&scaled, &blocks, 0, plan.scratch_bytes)?; + + let mut br = BitReader::new(&self.bytes[plan.scan_offset..]); + let mut prev_dc = [0i32; 4]; + let mut coeff = CoefficientBlock::default(); + let mut pixels = [0u16; 64]; + let mut restart_tracker = + Extended12RestartTracker::new(plan.restart_interval, mcu_cols * mcu_rows); + for mcu_y in 0..mcu_rows { + for mcu_x in 0..mcu_cols { + if restart_tracker.begin_mcu(&mut br, mcu_y * mcu_cols + mcu_x)? { + prev_dc.fill(0); + } + for component in &plan.components { + let index = component.output_index; + let resolved = plan.resolve_component(component)?; + let plane = planes + .get_mut(index) + .ok_or(JpegError::NotImplemented { sof })?; + let size = plane.component.idct_size as usize; + let (h, v) = (u32::from(component.h), u32::from(component.v)); + for by in 0..v { + for bx in 0..h { + let activity = decode_block_with_activity( + &mut br, + resolved.dc_table, + resolved.ac_table, + &mut prev_dc[index], + resolved.quant, + &mut coeff, + )?; + idct_12bit_block( + self.backend, + coeff.coefficients(), + activity == BlockActivity::DcOnly, + size, + &mut pixels, + ); + plane.deposit( + (mcu_x * h + bx) as usize * size, + (mcu_y * v + by) as usize * size, + size, + &pixels, + ); + } + } + } + restart_tracker.finish_mcu(); + } + } + let scan_warnings = finish_scan(&mut br, true)?; + Ok((planes, scan_warnings)) + } + + fn render_progressive12_scaled_planes( + &self, + downscale: DownscaleFactor, + color: Extended12Color, + ) -> Result { + let sof = self.info.sof_kind; + let plan = self + .progressive_plan + .as_ref() + .ok_or(JpegError::NotImplemented { sof })?; + if plan.components.len() != color.components() { + return Err(JpegError::NotImplemented { sof }); + } + let scaled = ScaledSampling::new(plan.sampling, downscale, plan.dimensions); + let dct_blocks = decode_progressive_dct_blocks(plan, self.bytes, 0)?; + ensure_progressive12_coefficient_capacities(&dct_blocks, plan.scratch_bytes)?; + let mut blocks = [(0usize, 0usize); 4]; + for component in &plan.components { + let slot = blocks + .get_mut(component.output_index) + .ok_or(JpegError::NotImplemented { sof })?; + *slot = (component.block_cols as usize, component.block_rows as usize); + } + let mut planes = allocate_scaled_planes( + &scaled, + &blocks[..plan.components.len()], + dct_blocks.capacity_bytes()?, + plan.scratch_bytes, + )?; + let mut dequant = [0i16; 64]; + let mut pixels = [0u16; 64]; + for (component, coeffs) in plan.components.iter().zip(&dct_blocks.quantized) { + let plane = planes + .get_mut(component.output_index) + .ok_or(JpegError::NotImplemented { sof })?; + let size = plane.component.idct_size as usize; + let cols = component.block_cols as usize; + for (block_index, block) in coeffs.iter().enumerate() { + dequantize_progressive12_block(block, &component.quant, &mut dequant); + let dc_only = dequant[1..].iter().all(|&coefficient| coefficient == 0); + idct_12bit_block(self.backend, &dequant, dc_only, size, &mut pixels); + plane.deposit( + (block_index % cols) * size, + (block_index / cols) * size, + size, + &pixels, + ); + } + } + Ok(planes) + } +} + +/// One component's output row `y`, upsampled across the full scaled width. +fn upsample_row(plane: &ScaledPlane, y: usize, out: &mut [u16]) { + let ScaledComponent { + h_ratio, + v_ratio, + upsample, + .. + } = plane.component; + match upsample { + Upsample::None => out.copy_from_slice(&plane.row(y)[..out.len()]), + Upsample::FancyH2V1 => { + let row = plane.row(y); + for (x, dst) in out.iter_mut().enumerate() { + *dst = super::upsample::upsample_extended12_h2v1_at(row, x); + } + } + Upsample::FancyH1V2 => { + // h1v2_fancy_upsample: 3/4 nearer row + 1/4 further row, biased + // +1 for the upper output row and +2 for the lower. + let sample_y = y / 2; + let curr = plane.row(sample_y); + let (near, bias) = if y.is_multiple_of(2) { + (plane.row(sample_y.saturating_sub(1)), 1) + } else { + (plane.row(sample_y + 1), 2) + }; + for (x, dst) in out.iter_mut().enumerate() { + let sum = 3 * u32::from(curr[x]) + u32::from(near[x]) + bias; + *dst = u16::try_from(sum >> 2).expect("weighted mean of 12-bit samples fits u16"); + } + } + Upsample::FancyH2V2 => { + let sample_y = y / 2; + let prev = plane.row(sample_y.saturating_sub(1)); + let curr = plane.row(sample_y); + let next = plane.row(sample_y + 1); + for (x, dst) in out.iter_mut().enumerate() { + *dst = super::upsample::upsample_h2v2_u16_rows_at(prev, curr, next, x, y % 2 == 1); + } + } + Upsample::Replicate => { + let row = plane.row(y / v_ratio as usize); + let h_ratio = h_ratio as usize; + for (x, dst) in out.iter_mut().enumerate() { + *dst = row[(x / h_ratio).min(row.len() - 1)]; + } + } + } +} + +/// Output geometry and memory budget for writing scaled planes. +#[derive(Clone, Copy)] +struct ScaledWrite { + output_rect: Rect, + /// Width of the scaled image; every upsampled row spans it. + output_width: usize, + /// Bytes already live (the planes) and the cap they share with the rows. + live_bytes: usize, + cap: usize, +} + +fn write_scaled_planes_region( + out: &mut [u8], + stride: usize, + write: ScaledWrite, + planes: &[ScaledPlane], + color: Extended12Color, +) -> Result<(), JpegError> { + let ScaledWrite { + output_rect, + output_width, + mut live_bytes, + cap, + } = write; + let x0 = output_rect.x as usize; + let x1 = x0 + output_rect.w as usize; + let mut rows: [Vec; 4] = Default::default(); + for row in &mut rows[..planes.len()] { + try_reserve_for_len_with_live_budget(row, output_width, &mut live_bytes, cap)?; + row.resize(output_width, 0u16); + } + for y in output_rect.y..output_rect.y + output_rect.h { + for (plane, row) in planes.iter().zip(rows.iter_mut()) { + upsample_row(plane, y as usize, row); + } + let dst_row = &mut out[(y - output_rect.y) as usize * stride..]; + for (dst_x, x) in (x0..x1).enumerate() { + match color { + Extended12Color::Gray(Extended12Output::Gray16) => { + dst_row[dst_x * 2..dst_x * 2 + 2].copy_from_slice(&rows[0][x].to_le_bytes()); + } + Extended12Color::Gray(Extended12Output::Rgb16) => { + let sample = rows[0][x]; + write_rgb16_le( + &mut dst_row[dst_x * 6..dst_x * 6 + 6], + (sample, sample, sample), + ); + } + Extended12Color::Rgb(projection) => { + let (r, g, b) = match projection { + Extended12RgbProjection::Identity => (rows[0][x], rows[1][x], rows[2][x]), + Extended12RgbProjection::YCbCr => crate::color::ycbcr::ycbcr12_to_rgb16( + rows[0][x], rows[1][x], rows[2][x], + ), + }; + write_rgb16_le(&mut dst_row[dst_x * 6..dst_x * 6 + 6], (r, g, b)); + } + Extended12Color::FourComponent(color_space) => { + let samples = (rows[0][x], rows[1][x], rows[2][x], rows[3][x]); + let rgb = if color_space == ColorSpace::Cmyk { + crate::color::cmyk::inverted_cmyk12_to_rgb16( + samples.0, samples.1, samples.2, samples.3, + ) + } else { + crate::color::cmyk::ycck12_to_rgb16( + samples.0, samples.1, samples.2, samples.3, + ) + }; + write_rgb16_le(&mut dst_row[dst_x * 6..dst_x * 6 + 6], rgb); + } + } + } + } + Ok(()) +} + +fn write_rgb16_le(dst: &mut [u8], (r, g, b): (u16, u16, u16)) { + dst[0..2].copy_from_slice(&r.to_le_bytes()); + dst[2..4].copy_from_slice(&g.to_le_bytes()); + dst[4..6].copy_from_slice(&b.to_le_bytes()); +} diff --git a/crates/j2k-jpeg/src/decoder/extended12/sequential.rs b/crates/j2k-jpeg/src/decoder/extended12/sequential.rs index ddc2e886a..ce64bdea1 100644 --- a/crates/j2k-jpeg/src/decoder/extended12/sequential.rs +++ b/crates/j2k-jpeg/src/decoder/extended12/sequential.rs @@ -9,10 +9,12 @@ use super::super::{ use super::sampling::{ extended12_color_sampling, extended12_four_component_sampling, Extended12ColorSampling, }; +use super::scaled::{needs_scaled_extended12_route, Extended12Color}; use super::state::{decode_extended12_block_pixels, Extended12RestartTracker}; use super::writers::{ write_extended12_block_region, Extended12Output, Extended12RgbProjection, Extended12WriteRegion, }; +use crate::color::scaled_sampling::ScaledSampling; mod color444; mod four_component; @@ -121,10 +123,20 @@ impl Decoder<'_> { height: self.info.dimensions.1, }); } + let scaled_route = needs_scaled_extended12_route( + &ScaledSampling::new(self.plan.sampling, downscale, self.info.dimensions), + downscale, + ); if matches!(output, Extended12Output::Rgb16) { match self.info.color_space { ColorSpace::Rgb => { let sampling = extended12_color_sampling(&self.plan, self.info.sof_kind)?; + if scaled_route { + let color = Extended12Color::Rgb(Extended12RgbProjection::Identity); + return self.decode_extended12_scaled_region_into( + out, stride, roi, downscale, color, + ); + } return match sampling { Extended12ColorSampling::S444 => self .decode_extended12_color444_region_into( @@ -147,6 +159,12 @@ impl Decoder<'_> { } ColorSpace::YCbCr => { let sampling = extended12_color_sampling(&self.plan, self.info.sof_kind)?; + if scaled_route { + let color = Extended12Color::Rgb(Extended12RgbProjection::YCbCr); + return self.decode_extended12_scaled_region_into( + out, stride, roi, downscale, color, + ); + } return match sampling { Extended12ColorSampling::S444 => self .decode_extended12_color444_region_into( @@ -170,6 +188,12 @@ impl Decoder<'_> { ColorSpace::Cmyk | ColorSpace::Ycck => { let sampling = extended12_four_component_sampling(&self.plan, self.info.sof_kind)?; + if scaled_route { + let color = Extended12Color::FourComponent(self.info.color_space); + return self.decode_extended12_scaled_region_into( + out, stride, roi, downscale, color, + ); + } return match sampling { Extended12ColorSampling::S444 => self .decode_extended12_four_component444_region_into( @@ -189,6 +213,15 @@ impl Decoder<'_> { sof: self.info.sof_kind, }); } + if scaled_route { + return self.decode_extended12_scaled_region_into( + out, + stride, + roi, + downscale, + Extended12Color::Gray(output), + ); + } let output_rect = scaled_rect_covering(roi, downscale)?; let scan_bytes = &self.bytes[self.plan.scan_offset..]; diff --git a/crates/j2k-jpeg/src/decoder/extended12/writers.rs b/crates/j2k-jpeg/src/decoder/extended12/writers.rs index 0c6e02819..d1a98b7ed 100644 --- a/crates/j2k-jpeg/src/decoder/extended12/writers.rs +++ b/crates/j2k-jpeg/src/decoder/extended12/writers.rs @@ -464,11 +464,23 @@ fn full_block_rows( let rect = region.output_rect; let rows = block_output_span(rect.y, rect.h, 1, height, y0, (y0 + 8).min(height)); let cols = block_output_span(rect.x, rect.w, 1, width, x0, (x0 + 8).min(width)); - let (src_col, dst_col, len) = ( - (cols.start - x0) as usize, - (cols.start - rect.x) as usize, - cols.len(), - ); + // A block outside the output rectangle has an empty span clamped to the + // rectangle's edge, which may lie before the block: emit nothing rather + // than derive offsets from it. + let rows = if cols.is_empty() { + rows.start..rows.start + } else { + rows + }; + let (src_col, dst_col, len) = if cols.is_empty() { + (0, 0, 0) + } else { + ( + (cols.start - x0) as usize, + (cols.start - rect.x) as usize, + cols.len(), + ) + }; rows.map(move |output_y| { ( (output_y - y0) as usize, diff --git a/crates/j2k-jpeg/src/decoder/routing/dispatch.rs b/crates/j2k-jpeg/src/decoder/routing/dispatch.rs index 616fd0942..c5a36027f 100644 --- a/crates/j2k-jpeg/src/decoder/routing/dispatch.rs +++ b/crates/j2k-jpeg/src/decoder/routing/dispatch.rs @@ -3,10 +3,9 @@ //! Output-format dispatch after routing has validated geometry and scratch. use super::super::{ - decode_scan_fast_tile_rgb_region, decode_scan_fast_tile_rgb_region_scaled, - fast_tile_region_first_decode_mcu, merged_warnings, CroppedWriter, DecodeOutcome, Decoder, - DownscaleFactor, FastTileRegionScaledRequest, Gray8Writer, JpegError, OutputFormat, Rect, - Rgb8Writer, Rgba8Writer, ScratchPool, SofKind, + decode_scan_fast_tile_rgb_region, fast_tile_region_first_decode_mcu, merged_warnings, + CroppedWriter, DecodeOutcome, Decoder, DownscaleFactor, Gray8Writer, JpegError, OutputFormat, + Rect, Rgb8Writer, Rgba8Writer, ScratchPool, SofKind, }; use crate::allocation::checked_add_allocation_bytes; @@ -256,34 +255,8 @@ impl Decoder<'_> { warnings: merged_warnings(&self.warnings, scan_warnings)?, }); } - if matches!(fmt, OutputFormat::Rgb8Scaled { .. }) - && self.progressive_plan.is_none() - && self.plan.matches_fast_tile_shape() - { - let mut writer = Rgb8Writer::new_with_backend(out, stride, output_rect.w, self.backend); - let scan_bytes = &self.bytes[self.plan.scan_offset..]; - let checkpoint = self.checkpoint_for_mcu( - scan_bytes, - fast_tile_region_first_decode_mcu(&self.plan, output_rect, downscale), - checked_add_allocation_bytes(external_live_bytes, pool.retained_bytes())?, - )?; - let scan_warnings = decode_scan_fast_tile_rgb_region_scaled( - &self.plan, - self.backend, - scan_bytes, - pool, - &mut writer, - FastTileRegionScaledRequest { - roi: output_rect, - downscale, - checkpoint: checkpoint.as_ref(), - }, - )?; - return Ok(DecodeOutcome { - decoded: output_rect, - warnings: merged_warnings(&self.warnings, scan_warnings)?, - }); - } + // Scaled 4:2:0 takes the generic route: libjpeg-turbo decodes its + // chroma with a larger reduced IDCT, so no 4:2:0 upsampling remains. let base = Rgb8Writer::new_with_backend(out, stride, output_rect.w, self.backend); let (source_x0, source_width) = self.source_window_for_output_rect(downscale, output_rect); let mut writer = CroppedWriter::new(base, output_rect, source_x0, source_width)?; diff --git a/crates/j2k-jpeg/src/decoder/scratch.rs b/crates/j2k-jpeg/src/decoder/scratch.rs index 5c0c85734..e4c63cb5f 100644 --- a/crates/j2k-jpeg/src/decoder/scratch.rs +++ b/crates/j2k-jpeg/src/decoder/scratch.rs @@ -239,7 +239,16 @@ pub(super) fn compute_extended12_planes_scratch_bytes( ) -> Result { let mcu_cols = width.div_ceil(u32::from(sampling.max_h) * 8) as usize; let mcu_rows = height.div_ceil(u32::from(sampling.max_v) * 8) as usize; - let mut total = 0usize; + // The scaled writer holds one u16 output row per component while the + // planes remain live. Full-resolution widths bound every decode scale. + let mut total = checked_usize_product( + &[ + width as usize, + components.len(), + core::mem::size_of::(), + ], + cap, + )?; for component in components { let stride = checked_usize_product(&[mcu_cols, usize::from(component.h), 8], cap)?; let rows = checked_usize_product(&[mcu_rows, usize::from(component.v), 8], cap)?; diff --git a/crates/j2k-jpeg/src/decoder/sequential.rs b/crates/j2k-jpeg/src/decoder/sequential.rs index a9ed2f27a..95b7c1f8d 100644 --- a/crates/j2k-jpeg/src/decoder/sequential.rs +++ b/crates/j2k-jpeg/src/decoder/sequential.rs @@ -10,7 +10,7 @@ use super::{ decode_scan_fast_rgb_444, decode_scan_fast_tile_rgb, emit_decode_scan_profile, jpeg_profile_stages_enabled, merged_warnings, scaled_dimensions, scaled_rect_covering, stripe_region_layout, DecodeOutcome, Decoder, DeviceCheckpoint, DownscaleFactor, Instant, - InterleavedRgbWriter, JpegError, OutputWriter, ProgressiveDownscaleWriter, Rect, ScratchPool, + InterleavedRgbWriter, JpegError, OutputWriter, Rect, ScratchPool, CPU_ROI_CHECKPOINT_CADENCE_MCUS, CPU_ROI_CHECKPOINT_MIN_TARGET_MCUS, }; @@ -143,26 +143,16 @@ impl Decoder<'_> { if let Some(plan) = &self.progressive_plan { let scan_start = profile_enabled.then(Instant::now); let detached_sink_bytes = pool.detached_sink_bytes(); - let scan_warnings = if downscale == DownscaleFactor::Full { - let external_live_bytes = - checked_live_workspace_bytes(detached_sink_bytes, 0, plan.scratch_bytes)?; - decode_progressive(plan, self.backend, self.bytes, writer, external_live_bytes)? - } else { - let mut scaled = - ProgressiveDownscaleWriter::new(writer, downscale, self.info.dimensions)?; - let external_live_bytes = checked_live_workspace_bytes( - detached_sink_bytes, - scaled.capacity_bytes()?, - plan.scratch_bytes, - )?; - decode_progressive( - plan, - self.backend, - self.bytes, - &mut scaled, - external_live_bytes, - )? - }; + let external_live_bytes = + checked_live_workspace_bytes(detached_sink_bytes, 0, plan.scratch_bytes)?; + let scan_warnings = decode_progressive( + plan, + self.backend, + self.bytes, + writer, + external_live_bytes, + downscale, + )?; if let Some(start) = scan_start { emit_decode_scan_profile( "progressive", @@ -216,26 +206,16 @@ impl Decoder<'_> { if let Some(plan) = &self.progressive_plan { let scan_start = profile_enabled.then(Instant::now); let detached_sink_bytes = pool.detached_sink_bytes(); - let scan_warnings = if downscale == DownscaleFactor::Full { - let external_live_bytes = - checked_live_workspace_bytes(detached_sink_bytes, 0, plan.scratch_bytes)?; - decode_progressive(plan, self.backend, self.bytes, writer, external_live_bytes)? - } else { - let mut scaled = - ProgressiveDownscaleWriter::new(writer, downscale, self.info.dimensions)?; - let external_live_bytes = checked_live_workspace_bytes( - detached_sink_bytes, - scaled.capacity_bytes()?, - plan.scratch_bytes, - )?; - decode_progressive( - plan, - self.backend, - self.bytes, - &mut scaled, - external_live_bytes, - )? - }; + let external_live_bytes = + checked_live_workspace_bytes(detached_sink_bytes, 0, plan.scratch_bytes)?; + let scan_warnings = decode_progressive( + plan, + self.backend, + self.bytes, + writer, + external_live_bytes, + downscale, + )?; if let Some(start) = scan_start { emit_decode_scan_profile( "progressive_rgb", diff --git a/crates/j2k-jpeg/src/entropy/block.rs b/crates/j2k-jpeg/src/entropy/block.rs index ee9de6cbd..890d51d51 100644 --- a/crates/j2k-jpeg/src/entropy/block.rs +++ b/crates/j2k-jpeg/src/entropy/block.rs @@ -32,28 +32,6 @@ pub(crate) enum BlockActivity { General, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum ReducedIdctCoefficients { - Half, - Quarter, -} - -impl ReducedIdctCoefficients { - #[expect( - clippy::inline_always, - reason = "measured entropy-block hot path requires cross-helper inlining" - )] - #[inline(always)] - fn keeps(self, natural_idx: usize) -> bool { - let row = natural_idx >> 3; - let col = natural_idx & 7; - match self { - Self::Half => row != 4 && col != 4, - Self::Quarter => !matches!(row, 2 | 4 | 6) && !matches!(col, 2 | 4 | 6), - } - } -} - #[derive(Debug, Clone)] pub(crate) struct CoefficientBlock { coeffs: [i16; 64], @@ -304,65 +282,6 @@ pub(crate) fn decode_block_with_dc_status( Ok(dc_only) } -#[expect( - clippy::inline_always, - reason = "measured entropy-block hot path requires cross-helper inlining" -)] -#[inline(always)] -pub(crate) fn decode_block_for_reduced_idct( - br: &mut BitReader<'_>, - dc_table: DcHuffmanTable<'_>, - ac_table: AcHuffmanTable<'_>, - prev_dc: &mut i32, - quant: &[u16; 64], - block: &mut CoefficientBlock, - keep: ReducedIdctCoefficients, -) -> Result { - block.clear_touched(); - - let diff = dc_table.decode_fast_dc(br)?; - *prev_dc = prev_dc.wrapping_add(diff); - let dc_dequant = (*prev_dc).wrapping_mul(i32::from(quant[0])); - block.store_dc(clamp_i16(dc_dequant)); - - let mut dc_only_for_reduced_idct = true; - drive_ac_fast::(br, ac_table, |k, ac| { - let natural_idx = ZIGZAG[k] as usize; - if keep.keeps(natural_idx) { - let value = ac_decoded_value(ac); - let dequant = value.wrapping_mul(i32::from(quant[k])); - block.store(natural_idx, clamp_i16(dequant)); - dc_only_for_reduced_idct = false; - } - Ok(()) - })?; - Ok(dc_only_for_reduced_idct) -} - -#[expect( - clippy::inline_always, - reason = "measured entropy-block hot path requires cross-helper inlining" -)] -#[inline(always)] -pub(crate) fn decode_block_for_1x1_idct( - br: &mut BitReader<'_>, - dc_table: DcHuffmanTable<'_>, - ac_table: AcHuffmanTable<'_>, - prev_dc: &mut i32, - quant: &[u16; 64], - block: &mut CoefficientBlock, -) -> Result<(), JpegError> { - block.clear_touched(); - - let diff = dc_table.decode_fast_dc(br)?; - *prev_dc = prev_dc.wrapping_add(diff); - let dc_dequant = (*prev_dc).wrapping_mul(i32::from(quant[0])); - block.store_dc(clamp_i16(dc_dequant)); - - drive_ac_fast::(br, ac_table, |_, _| Ok(()))?; - Ok(()) -} - #[expect( clippy::inline_always, reason = "measured entropy-block hot path requires cross-helper inlining" @@ -633,112 +552,6 @@ mod tests { assert_eq!(dc_status_reader.snapshot(), activity_reader.snapshot()); } - #[test] - fn reduced_idct_decoder_keeps_only_coefficients_read_by_scale() { - let dc = trivial_dc_table(); - let raw = RawHuffmanTable { - bits: [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - values: HuffmanValues::from_slice(&[0x41, 0x00]), - }; - let ac = HuffmanTable::from_raw(&raw, HuffmanTableRole::Ac).unwrap(); - let bytes = [0b0001_0100u8, 0, 0, 0]; - let quant = [1u16; 64]; - let ignored_by_quarter = ZIGZAG[5] as usize; - assert_eq!(ignored_by_quarter, 2); - - let mut full_reader = BitReader::new(&bytes); - let mut quarter_reader = BitReader::new(&bytes); - let mut half_reader = BitReader::new(&bytes); - let mut full_prev_dc = 0i32; - let mut quarter_prev_dc = 0i32; - let mut half_prev_dc = 0i32; - let mut full_block = CoefficientBlock::default(); - let mut quarter_block = CoefficientBlock::default(); - let mut half_block = CoefficientBlock::default(); - - decode_block_with_activity( - &mut full_reader, - dc.dc().unwrap(), - ac.ac().unwrap(), - &mut full_prev_dc, - &quant, - &mut full_block, - ) - .unwrap(); - let quarter_dc_only = decode_block_for_reduced_idct( - &mut quarter_reader, - dc.dc().unwrap(), - ac.ac().unwrap(), - &mut quarter_prev_dc, - &quant, - &mut quarter_block, - ReducedIdctCoefficients::Quarter, - ) - .unwrap(); - let half_dc_only = decode_block_for_reduced_idct( - &mut half_reader, - dc.dc().unwrap(), - ac.ac().unwrap(), - &mut half_prev_dc, - &quant, - &mut half_block, - ReducedIdctCoefficients::Half, - ) - .unwrap(); - - assert_eq!(quarter_prev_dc, full_prev_dc); - assert_eq!(half_prev_dc, full_prev_dc); - assert_eq!(quarter_reader.snapshot(), full_reader.snapshot()); - assert_eq!(half_reader.snapshot(), full_reader.snapshot()); - assert_eq!(full_block.coefficients()[ignored_by_quarter], 1); - assert_eq!(quarter_block.coefficients()[ignored_by_quarter], 0); - assert_eq!(half_block.coefficients()[ignored_by_quarter], 1); - assert!(quarter_dc_only); - assert!(!half_dc_only); - } - - #[test] - fn one_by_one_idct_decoder_keeps_dc_and_skips_ac_values() { - let dc = trivial_dc_table(); - let raw = RawHuffmanTable { - bits: [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - values: HuffmanValues::from_slice(&[0x01, 0x00]), - }; - let ac = HuffmanTable::from_raw(&raw, HuffmanTableRole::Ac).unwrap(); - let bytes = [0b0001_0100u8, 0, 0, 0]; - let quant = [1u16; 64]; - let mut full_reader = BitReader::new(&bytes); - let mut one_by_one_reader = BitReader::new(&bytes); - let mut full_prev_dc = 0i32; - let mut one_by_one_prev_dc = 0i32; - let mut full_block = CoefficientBlock::default(); - let mut one_by_one_block = CoefficientBlock::default(); - - decode_block_with_activity( - &mut full_reader, - dc.dc().unwrap(), - ac.ac().unwrap(), - &mut full_prev_dc, - &quant, - &mut full_block, - ) - .unwrap(); - decode_block_for_1x1_idct( - &mut one_by_one_reader, - dc.dc().unwrap(), - ac.ac().unwrap(), - &mut one_by_one_prev_dc, - &quant, - &mut one_by_one_block, - ) - .unwrap(); - - assert_eq!(one_by_one_prev_dc, full_prev_dc); - assert_eq!(one_by_one_reader.snapshot(), full_reader.snapshot()); - assert_eq!(one_by_one_block.dc_coeff(), full_block.dc_coeff()); - assert!(one_by_one_block.coefficients()[1..].iter().all(|&c| c == 0)); - } - #[test] fn skip_block_consumes_stream_and_updates_dc_like_decode() { let dc_raw = RawHuffmanTable { diff --git a/crates/j2k-jpeg/src/entropy/progressive.rs b/crates/j2k-jpeg/src/entropy/progressive.rs index fa5fd8154..1f51fc32d 100644 --- a/crates/j2k-jpeg/src/entropy/progressive.rs +++ b/crates/j2k-jpeg/src/entropy/progressive.rs @@ -6,7 +6,9 @@ use alloc::vec::Vec; use crate::backend::Backend; +use crate::color::scaled_sampling::ScaledSampling; use crate::error::{JpegError, Warning}; +use crate::info::DownscaleFactor; use crate::output::OutputWriter; mod allocation; @@ -25,13 +27,22 @@ pub(crate) use self::scan::decode_progressive_dct_blocks; use self::allocation::{checked_phase_capacity, component_image_capacity_bytes}; use self::render::{emit_component_images, render_component_images}; +/// Decodes a progressive image at `downscale`, applying libjpeg-turbo's +/// reduced IDCTs to the completed coefficients. pub(crate) fn decode_progressive( plan: &PreparedProgressivePlan, backend: Backend, bytes: &[u8], writer: &mut W, external_live_bytes: usize, + downscale: DownscaleFactor, ) -> Result, JpegError> { + let scaled = ScaledSampling::new(plan.sampling, downscale, plan.dimensions); + let denominator = downscale.denominator(); + let output_dimensions = ( + plan.dimensions.0.div_ceil(denominator), + plan.dimensions.1.div_ceil(denominator), + ); let dct_blocks = decode_progressive_dct_blocks(plan, bytes, external_live_bytes)?; let coefficient_live_bytes = checked_phase_capacity( external_live_bytes, @@ -39,14 +50,22 @@ pub(crate) fn decode_progressive( plan.scratch_bytes, )?; let ProgressiveDctBlocks { quantized: coeffs } = dct_blocks; - let images = render_component_images(plan, backend, &coeffs, coefficient_live_bytes)?; + let images = render_component_images(plan, backend, &scaled, &coeffs, coefficient_live_bytes)?; drop(coeffs); let image_live_bytes = checked_phase_capacity( external_live_bytes, component_image_capacity_bytes(images.capacity(), &images)?, plan.scratch_bytes, )?; - emit_component_images(plan, backend, &images, image_live_bytes, writer)?; + emit_component_images( + plan, + backend, + &scaled, + output_dimensions, + &images, + image_live_bytes, + writer, + )?; Ok(Vec::new()) } diff --git a/crates/j2k-jpeg/src/entropy/progressive/allocation.rs b/crates/j2k-jpeg/src/entropy/progressive/allocation.rs index 234abc037..c67a6364c 100644 --- a/crates/j2k-jpeg/src/entropy/progressive/allocation.rs +++ b/crates/j2k-jpeg/src/entropy/progressive/allocation.rs @@ -8,6 +8,7 @@ use crate::allocation::{ checked_add_allocation_bytes, checked_allocation_bytes, checked_allocation_len, try_reserve_for_len_with_live_budget, }; +use crate::color::scaled_sampling::ScaledSampling; use crate::error::JpegError; use super::model::{PreparedProgressiveComponentPlan, PreparedProgressivePlan}; @@ -129,11 +130,13 @@ pub(super) fn checked_phase_capacity( Ok(requested) } +/// Component images at each component's reduced IDCT size. pub(super) fn allocate_component_images( plan: &PreparedProgressivePlan, + scaled: &ScaledSampling, initial_live_bytes: usize, ) -> Result, JpegError> { - let planned_bytes = validate_component_image_workspace(&plan.components)?; + let planned_bytes = validate_component_image_workspace(&plan.components, scaled)?; checked_phase_capacity(initial_live_bytes, planned_bytes, plan.scratch_bytes)?; let mut live_bytes = initial_live_bytes; @@ -144,9 +147,8 @@ pub(super) fn allocate_component_images( &mut live_bytes, plan.scratch_bytes, )?; - for component in &plan.components { - let stride = checked_allocation_len::(component.block_cols as usize, 8)?; - let rows = checked_allocation_len::(component.block_rows as usize, 8)?; + for (index, component) in plan.components.iter().enumerate() { + let (stride, rows) = component_image_extent(component, scaled, index)?; let plane_len = checked_allocation_len::(stride, rows)?; let mut plane = Vec::new(); try_reserve_for_len_with_live_budget( @@ -161,13 +163,25 @@ pub(super) fn allocate_component_images( Ok(images) } +fn component_image_extent( + component: &PreparedProgressiveComponentPlan, + scaled: &ScaledSampling, + index: usize, +) -> Result<(usize, usize), JpegError> { + let idct_size = scaled.component(index).idct_size as usize; + Ok(( + checked_allocation_len::(component.block_cols as usize, idct_size)?, + checked_allocation_len::(component.block_rows as usize, idct_size)?, + )) +} + fn validate_component_image_workspace( components: &[PreparedProgressiveComponentPlan], + scaled: &ScaledSampling, ) -> Result { let mut total = checked_allocation_bytes::(components.len())?; - for component in components { - let stride = checked_allocation_len::(component.block_cols as usize, 8)?; - let rows = checked_allocation_len::(component.block_rows as usize, 8)?; + for (index, component) in components.iter().enumerate() { + let (stride, rows) = component_image_extent(component, scaled, index)?; let plane_len = checked_allocation_len::(stride, rows)?; total = checked_add_allocation_bytes(total, checked_allocation_bytes::(plane_len)?)?; } diff --git a/crates/j2k-jpeg/src/entropy/progressive/render.rs b/crates/j2k-jpeg/src/entropy/progressive/render.rs index 1b4d0eac7..5d843c2d4 100644 --- a/crates/j2k-jpeg/src/entropy/progressive/render.rs +++ b/crates/j2k-jpeg/src/entropy/progressive/render.rs @@ -6,19 +6,24 @@ use alloc::vec::Vec; use crate::allocation::{checked_allocation_len, try_reserve_for_len_with_live_budget}; use crate::backend::Backend; +use crate::color::scaled_sampling::{ScaledComponent, ScaledSampling, Upsample}; use crate::color::upsample::{upsample_h1v2_fancy_row, upsample_h2v1_fancy_row}; use crate::entropy::block::clamp_i16; use crate::entropy::ZIGZAG; use crate::error::JpegError; +use crate::idct::downscale; use crate::info::ColorSpace; use crate::output::OutputWriter; use super::allocation::{allocate_component_images, checked_phase_capacity, ComponentImage}; -use super::model::{PreparedProgressiveComponentPlan, PreparedProgressivePlan}; +use super::model::PreparedProgressivePlan; +/// IDCTs every block into its component image at the component's reduced +/// size (8, 4, 2 or 1 samples per block side, as libjpeg-turbo chooses). pub(super) fn render_component_images( plan: &PreparedProgressivePlan, backend: Backend, + scaled: &ScaledSampling, coeffs: &[Vec<[i32; 64]>], coefficient_live_bytes: usize, ) -> Result, JpegError> { @@ -27,22 +32,50 @@ pub(super) fn render_component_images( reason: "progressive coefficient/component count mismatch", }); } - let mut images = allocate_component_images(plan, coefficient_live_bytes)?; - for ((component, component_coeffs), image) in plan + let mut images = allocate_component_images(plan, scaled, coefficient_live_bytes)?; + for (((index, component), component_coeffs), image) in plan .components .iter() + .enumerate() .zip(coeffs.iter()) .zip(images.iter_mut()) { + let idct_size = scaled.component(index).idct_size as usize; let mut dequant = [0i16; 64]; let mut pixels = [0u8; 64]; + let mut pixels_4x4 = [0u8; 16]; + let mut pixels_2x2 = [0u8; 4]; let natural_quant = natural_order_quant(&component.quant); for by in 0..component.block_rows as usize { for bx in 0..component.block_cols as usize { let block_index = by * component.block_cols as usize + bx; dequantize_block(&component_coeffs[block_index], &natural_quant, &mut dequant); - backend.idct(&dequant, &mut pixels); - deposit_block(&mut image.plane, image.stride, bx * 8, by * 8, &pixels); + let block: &[u8] = match idct_size { + 8 => { + backend.idct(&dequant, &mut pixels); + &pixels + } + 4 => { + downscale::idct_islow_4x4(&dequant, &mut pixels_4x4); + &pixels_4x4 + } + 2 => { + downscale::idct_islow_2x2(&dequant, &mut pixels_2x2); + &pixels_2x2 + } + _ => { + pixels[0] = downscale::idct_islow_1x1(&dequant); + &pixels[..1] + } + }; + deposit_block( + &mut image.plane, + image.stride, + bx * idct_size, + by * idct_size, + idct_size, + block, + ); } } } @@ -67,22 +100,25 @@ fn dequantize_block(coeffs: &[i32; 64], natural_quant: &[u16; 64], out: &mut [i1 } } -fn deposit_block(plane: &mut [u8], stride: usize, x: usize, y: usize, block: &[u8; 64]) { - for row in 0..8 { +fn deposit_block(plane: &mut [u8], stride: usize, x: usize, y: usize, size: usize, block: &[u8]) { + for row in 0..size { let dst = (y + row) * stride + x; - let src = row * 8; - plane[dst..dst + 8].copy_from_slice(&block[src..src + 8]); + let src = row * size; + plane[dst..dst + size].copy_from_slice(&block[src..src + size]); } } +/// Upsamples the component images to the (scaled) output grid row by row. pub(super) fn emit_component_images( plan: &PreparedProgressivePlan, backend: Backend, + scaled: &ScaledSampling, + output_dimensions: (u32, u32), images: &[ComponentImage], image_live_bytes: usize, writer: &mut W, ) -> Result<(), JpegError> { - let (width, height) = plan.dimensions; + let (width, height) = output_dimensions; let width_usize = width as usize; if plan.components.len() == 1 { checked_phase_capacity(image_live_bytes, width_usize, plan.scratch_bytes)?; @@ -99,7 +135,7 @@ pub(super) fn emit_component_images( )?; gray.resize(width_usize, 0u8); for y in 0..height { - upsample_component_row(plan, backend, 0, image, y, &mut gray); + upsample_component_row(backend, scaled.component(0), image, y, &mut gray); writer.write_gray_row(y, &gray)?; } return Ok(()); @@ -121,9 +157,15 @@ pub(super) fn emit_component_images( try_reserve_for_len_with_live_budget(&mut c, width_usize, &mut live_bytes, plan.scratch_bytes)?; c.resize(width_usize, 0u8); for y in 0..height { - upsample_component_row(plan, backend, first, &images[first], y, &mut a); - upsample_component_row(plan, backend, second, &images[second], y, &mut b); - upsample_component_row(plan, backend, third, &images[third], y, &mut c); + upsample_component_row(backend, scaled.component(first), &images[first], y, &mut a); + upsample_component_row( + backend, + scaled.component(second), + &images[second], + y, + &mut b, + ); + upsample_component_row(backend, scaled.component(third), &images[third], y, &mut c); match plan.color_space { ColorSpace::YCbCr => writer.write_ycbcr_row(y, &a, &b, &c)?, ColorSpace::Rgb => writer.write_rgb_row(y, &a, &b, &c)?, @@ -148,69 +190,52 @@ fn component_slot(plan: &PreparedProgressivePlan, output_index: usize) -> Result }) } +/// Emits output row `y` of one component with libjpeg-turbo's upsampler for +/// it; rows past the component's last sample row replicate that row. fn upsample_component_row( - plan: &PreparedProgressivePlan, backend: Backend, - component_index: usize, + component: ScaledComponent, image: &ComponentImage, y: u32, out: &mut [u8], ) { - let component = &plan.components[component_index]; - let h_ratio = plan.sampling.max_h / component.h; - let v_ratio = plan.sampling.max_v / component.v; - if h_ratio == 1 && v_ratio == 1 { - let sample_y = (y as usize).min(component.sample_height.saturating_sub(1) as usize); - let row = component_row(component, image, sample_y); - out.copy_from_slice(&row[..out.len()]); - } else if h_ratio == 2 && v_ratio == 1 { - let sample_y = (y as usize).min(component.sample_height.saturating_sub(1) as usize); - let row = component_row(component, image, sample_y); - upsample_h2v1_fancy_row(row, out.len(), out); - } else if h_ratio == 2 && v_ratio == 2 { - let sample_y = ((y / 2) as usize).min(component.sample_height.saturating_sub(1) as usize); - let prev_y = sample_y.saturating_sub(1); - let next_y = (sample_y + 1).min(component.sample_height.saturating_sub(1) as usize); - let prev = component_row(component, image, prev_y); - let curr = component_row(component, image, sample_y); - let next = component_row(component, image, next_y); - backend.upsample_h2v2_fancy_row([prev, curr, next], out.len(), y % 2 == 1, out); - } else if h_ratio == 1 && v_ratio == 2 { - let sample_y = ((y / 2) as usize).min(component.sample_height.saturating_sub(1) as usize); - let prev_y = sample_y.saturating_sub(1); - let next_y = (sample_y + 1).min(component.sample_height.saturating_sub(1) as usize); - let prev = component_row(component, image, prev_y); - let curr = component_row(component, image, sample_y); - let next = component_row(component, image, next_y); - upsample_h1v2_fancy_row(prev, curr, next, out.len(), y % 2 == 1, out); - } else { - upsample_nearest(plan, component, image, y, out); + let last_row = component.height.saturating_sub(1) as usize; + let row = |sample_y: usize| component_row(component, image, sample_y.min(last_row)); + let y = y as usize; + match component.upsample { + Upsample::None => out.copy_from_slice(&row(y)[..out.len()]), + Upsample::FancyH2V1 => upsample_h2v1_fancy_row(row(y), out.len(), out), + Upsample::FancyH2V2 => { + let sample_y = y / 2; + let rows = [ + row(sample_y.saturating_sub(1)), + row(sample_y), + row(sample_y + 1), + ]; + backend.upsample_h2v2_fancy_row(rows, out.len(), y % 2 == 1, out); + } + Upsample::FancyH1V2 => { + let sample_y = y / 2; + upsample_h1v2_fancy_row( + row(sample_y.saturating_sub(1)), + row(sample_y), + row(sample_y + 1), + out.len(), + y % 2 == 1, + out, + ); + } + Upsample::Replicate => { + let samples = row(y / component.v_ratio as usize); + let h_ratio = component.h_ratio as usize; + for (x, dst) in out.iter_mut().enumerate() { + *dst = samples[(x / h_ratio).min(samples.len() - 1)]; + } + } } } -fn component_row<'a>( - component: &PreparedProgressiveComponentPlan, - image: &'a ComponentImage, - y: usize, -) -> &'a [u8] { - let width = component.sample_width as usize; +fn component_row(component: ScaledComponent, image: &ComponentImage, y: usize) -> &[u8] { let row_start = y * image.stride; - &image.plane[row_start..row_start + width] -} - -fn upsample_nearest( - plan: &PreparedProgressivePlan, - component: &PreparedProgressiveComponentPlan, - image: &ComponentImage, - y: u32, - out: &mut [u8], -) { - let sample_y = ((y as usize) * usize::from(component.v) / usize::from(plan.sampling.max_v)) - .min(component.sample_height.saturating_sub(1) as usize); - let row = component_row(component, image, sample_y); - for (x, dst) in out.iter_mut().enumerate() { - let sample_x = (x * usize::from(component.h) / usize::from(plan.sampling.max_h)) - .min(row.len().saturating_sub(1)); - *dst = row[sample_x]; - } + &image.plane[row_start..row_start + component.width as usize] } diff --git a/crates/j2k-jpeg/src/entropy/sequential.rs b/crates/j2k-jpeg/src/entropy/sequential.rs index b72fce4b6..f00a33e4f 100644 --- a/crates/j2k-jpeg/src/entropy/sequential.rs +++ b/crates/j2k-jpeg/src/entropy/sequential.rs @@ -21,13 +21,10 @@ pub(crate) use self::dct::{ }; #[cfg(feature = "bench-internals")] pub(crate) use self::fast420::decode_scan_fast_tile_rgb_profiled; -pub(crate) use self::fast420::{ - decode_scan_fast_tile_rgb, decode_scan_fast_tile_rgb_region, - decode_scan_fast_tile_rgb_region_scaled, FastTileRegionScaledRequest, -}; +pub(crate) use self::fast420::{decode_scan_fast_tile_rgb, decode_scan_fast_tile_rgb_region}; pub(crate) use self::generic::{decode_scan_baseline, decode_scan_baseline_rgb}; pub(crate) use self::layout::{fast_tile_region_first_decode_mcu, stripe_region_layout}; -use self::layout::{is_ycbcr_420, scaled_dimensions, Fast420RegionLayout}; +use self::layout::{scaled_dimensions, uses_fancy_420_emit, Fast420RegionLayout}; use self::output_scratch::{OutputScratch, RgbOutputScratch}; pub(crate) use self::plan::{ PreparedComponentPlan, PreparedDecodePlan, ResolvedPreparedComponentPlan, diff --git a/crates/j2k-jpeg/src/entropy/sequential/deposit.rs b/crates/j2k-jpeg/src/entropy/sequential/deposit.rs index 05e6b919b..a6db24c55 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/deposit.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/deposit.rs @@ -2,13 +2,7 @@ use super::{ResolvedPreparedComponentPlan, StripeBuffer}; use crate::backend::Backend; -use crate::entropy::block::{ - decode_block_for_1x1_idct, decode_block_for_reduced_idct, BlockActivity, CoefficientBlock, - ReducedIdctCoefficients, -}; -use crate::error::JpegError; -use crate::idct::downscale; -use crate::info::DownscaleFactor; +use crate::entropy::block::{BlockActivity, CoefficientBlock}; use crate::internal::bit_reader::BitReader; use core::ptr; @@ -132,17 +126,6 @@ pub(super) fn deposit_block_1x1(plane: &mut [u8], stride: usize, x: u32, y: u32, plane[dst] = pixel; } -pub(super) struct EntropyBlockState<'a, 'b> { - pub(super) br: &'a mut BitReader<'b>, - pub(super) prev_dc: &'a mut i32, - pub(super) coeff: &'a mut CoefficientBlock, -} - -pub(super) struct ReducedIdctScratch<'a> { - pub(super) pixels_4x4: &'a mut [u8; 16], - pub(super) pixels_2x2: &'a mut [u8; 4], -} - pub(super) struct PlaneBlockTarget<'a> { pub(super) plane: &'a mut [u8], pub(super) stride: usize, @@ -245,129 +228,3 @@ impl FastTile420Window { mx - self.stripe_mcu_start } } - -#[expect( - clippy::needless_pass_by_value, - reason = "entropy state, scratch, and plane target are compact borrowing descriptors consumed as one hot-path operation" -)] -pub(super) fn decode_scaled_block_to_plane( - comp: ResolvedPreparedComponentPlan<'_>, - downscale: DownscaleFactor, - state: EntropyBlockState<'_, '_>, - scratch: ReducedIdctScratch<'_>, - target: PlaneBlockTarget<'_>, -) -> Result<(), JpegError> { - let keep = match downscale { - DownscaleFactor::Full => unreachable!("scaled block path excludes full-size decode"), - DownscaleFactor::Half => ReducedIdctCoefficients::Half, - DownscaleFactor::Quarter => ReducedIdctCoefficients::Quarter, - DownscaleFactor::Eighth => { - decode_block_for_1x1_idct( - state.br, - comp.dc_table, - comp.ac_table, - state.prev_dc, - comp.quant, - state.coeff, - )?; - let pixel = downscale::idct_islow_1x1(state.coeff.coefficients()); - deposit_block_1x1(target.plane, target.stride, target.x, target.y, pixel); - return Ok(()); - } - }; - let dc_only = decode_block_for_reduced_idct( - state.br, - comp.dc_table, - comp.ac_table, - state.prev_dc, - comp.quant, - state.coeff, - keep, - )?; - match downscale { - DownscaleFactor::Full => unreachable!("scaled block path excludes full-size decode"), - DownscaleFactor::Half => { - if dc_only { - downscale::idct_islow_4x4_dc_only(state.coeff.dc_coeff(), scratch.pixels_4x4); - } else { - downscale::idct_islow_4x4(state.coeff.coefficients(), scratch.pixels_4x4); - } - deposit_block_4x4( - target.plane, - target.stride, - target.x, - target.y, - scratch.pixels_4x4, - ); - } - DownscaleFactor::Quarter => { - if dc_only { - downscale::idct_islow_2x2_dc_only(state.coeff.dc_coeff(), scratch.pixels_2x2); - } else { - downscale::idct_islow_2x2(state.coeff.coefficients(), scratch.pixels_2x2); - } - deposit_block_2x2( - target.plane, - target.stride, - target.x, - target.y, - *scratch.pixels_2x2, - ); - } - DownscaleFactor::Eighth => { - let pixel = downscale::idct_islow_1x1(state.coeff.coefficients()); - deposit_block_1x1(target.plane, target.stride, target.x, target.y, pixel); - } - } - Ok(()) -} - -#[expect( - clippy::needless_pass_by_value, - reason = "entropy state and plane target are compact borrowing descriptors used as one reduced-IDCT operation" -)] -pub(super) fn decode_quarter_block_to_plane( - comp: ResolvedPreparedComponentPlan<'_>, - pixels_2x2: &mut [u8; 4], - state: EntropyBlockState<'_, '_>, - target: PlaneBlockTarget<'_>, -) -> Result<(), JpegError> { - let dc_only = decode_block_for_reduced_idct( - state.br, - comp.dc_table, - comp.ac_table, - state.prev_dc, - comp.quant, - state.coeff, - ReducedIdctCoefficients::Quarter, - )?; - if dc_only { - downscale::idct_islow_2x2_dc_only(state.coeff.dc_coeff(), pixels_2x2); - } else { - downscale::idct_islow_2x2(state.coeff.coefficients(), pixels_2x2); - } - deposit_block_2x2(target.plane, target.stride, target.x, target.y, *pixels_2x2); - Ok(()) -} - -#[expect( - clippy::needless_pass_by_value, - reason = "entropy state and plane target are compact borrowing descriptors used as one reduced-IDCT operation" -)] -pub(super) fn decode_eighth_block_to_plane( - comp: ResolvedPreparedComponentPlan<'_>, - state: EntropyBlockState<'_, '_>, - target: PlaneBlockTarget<'_>, -) -> Result<(), JpegError> { - decode_block_for_1x1_idct( - state.br, - comp.dc_table, - comp.ac_table, - state.prev_dc, - comp.quant, - state.coeff, - )?; - let pixel = downscale::idct_islow_1x1(state.coeff.coefficients()); - deposit_block_1x1(target.plane, target.stride, target.x, target.y, pixel); - Ok(()) -} diff --git a/crates/j2k-jpeg/src/entropy/sequential/emit/four_component.rs b/crates/j2k-jpeg/src/entropy/sequential/emit/four_component.rs index 473af5bc1..0e454d452 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/emit/four_component.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/emit/four_component.rs @@ -9,7 +9,7 @@ use super::{ }; use crate::{ color::cmyk::{inverted_cmyk_to_rgb, ycck_to_rgb}, - error::JpegError, + color::scaled_sampling::ScaledSampling, info::ColorSpace, internal::scratch::RgbGenericRows, }; @@ -25,46 +25,22 @@ pub(super) struct FourComponentRow { pub(super) fn fill_four_component_rgb_row( plan: &PreparedDecodePlan, + scaled: &ScaledSampling, neighbors: StripeNeighbors<'_>, row: FourComponentRow, scratch: &mut RgbGenericRows, -) -> Result<(), JpegError> { +) { let FourComponentRow { local_y, stripe_rows, width, } = row; - let (c0_h, c0_v) = plan - .sampling - .component(0) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 0 })?; - let (c1_h, c1_v) = plan - .sampling - .component(1) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 1 })?; - let (c2_h, c2_v) = plan - .sampling - .component(2) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 2 })?; - let (k_h, k_v) = plan - .sampling - .component(3) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 3 })?; - let max_h = u32::from(plan.sampling.max_h); - let max_v = u32::from(plan.sampling.max_v); upsample_component_row_stripe(StripeComponentUpsample { neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 0, - comp_h: c0_h, - comp_v: c0_v, - max_h, - max_v, + component: scaled.component(0), local_y_out: local_y, stripe_rows, width, @@ -75,10 +51,7 @@ pub(super) fn fill_four_component_rgb_row( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 1, - comp_h: c1_h, - comp_v: c1_v, - max_h, - max_v, + component: scaled.component(1), local_y_out: local_y, stripe_rows, width, @@ -89,10 +62,7 @@ pub(super) fn fill_four_component_rgb_row( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 2, - comp_h: c2_h, - comp_v: c2_v, - max_h, - max_v, + component: scaled.component(2), local_y_out: local_y, stripe_rows, width, @@ -103,10 +73,7 @@ pub(super) fn fill_four_component_rgb_row( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 3, - comp_h: k_h, - comp_v: k_v, - max_h, - max_v, + component: scaled.component(3), local_y_out: local_y, stripe_rows, width, @@ -126,6 +93,4 @@ pub(super) fn fill_four_component_rgb_row( scratch.g[x] = g; scratch.b[x] = b; } - - Ok(()) } diff --git a/crates/j2k-jpeg/src/entropy/sequential/emit/output.rs b/crates/j2k-jpeg/src/entropy/sequential/emit/output.rs index 14191dd21..32b795a4f 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/emit/output.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/emit/output.rs @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use super::{ - super::{is_ycbcr_420, scaled_dimensions, OutputScratch, PreparedDecodePlan}, + super::{scaled_dimensions, uses_fancy_420_emit, OutputScratch, PreparedDecodePlan}, four_component::{fill_four_component_rgb_row, FourComponentRow}, - types::{StripeEmit, StripeNeighbors}, + types::{ensure_color_components, StripeEmit, StripeNeighbors}, upsample::{ upsample_420_pair, upsample_component_row_stripe, Stripe420PairSpec, Stripe420PairUpsample, StripeComponentUpsample, StripeComponentUpsampleSpec, @@ -32,6 +32,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( stripe_index, source_width, downscale, + scaled, } = emit; let max_v = u32::from(plan.sampling.max_v); let mcu_height_px = downscale.output_block_size() * max_v; @@ -43,6 +44,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( if stripe_rows == 0 { return Ok(()); } + ensure_color_components(plan)?; let width = source_width; let neighbors = StripeNeighbors { prev, curr, next }; @@ -54,27 +56,10 @@ pub(in crate::entropy::sequential) fn emit_stripe( } } ColorSpace::YCbCr => { - let (cb_h, cb_v) = plan - .sampling - .component(1) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 1 })?; - let (cr_h, cr_v) = plan - .sampling - .component(2) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 2 })?; - - let max_h = u32::from(plan.sampling.max_h); - let max_v = u32::from(plan.sampling.max_v); - - if is_ycbcr_420(plan) { + if uses_fancy_420_emit(plan, scaled) { let OutputScratch::YCbCr420(scratch) = output_scratch else { unreachable!("4:2:0 YCbCr requires dedicated scratch"); }; - debug_assert!( - max_h == 2 && max_v == 2 && cb_h == 1 && cb_v == 1 && cr_h == 1 && cr_v == 1 - ); let mut local_y = 0usize; while local_y < stripe_rows { @@ -133,10 +118,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 1, - comp_h: cb_h, - comp_v: cb_v, - max_h, - max_v, + component: scaled.component(1), local_y_out: local_y as u32, stripe_rows, width, @@ -147,10 +129,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 2, - comp_h: cr_h, - comp_v: cr_v, - max_h, - max_v, + component: scaled.component(2), local_y_out: local_y as u32, stripe_rows, width, @@ -167,25 +146,6 @@ pub(in crate::entropy::sequential) fn emit_stripe( } } ColorSpace::Rgb => { - let (r_h, r_v) = plan - .sampling - .component(0) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 0 })?; - let (g_h, g_v) = plan - .sampling - .component(1) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 1 })?; - let (b_h, b_v) = plan - .sampling - .component(2) - .map(|(h, v)| (u32::from(h), u32::from(v))) - .ok_or(JpegError::UnsupportedComponentCount { count: 2 })?; - - let max_h = u32::from(plan.sampling.max_h); - let max_v = u32::from(plan.sampling.max_v); - let OutputScratch::RgbGeneric(scratch) = output_scratch else { unreachable!("RGB decode requires reusable row scratch"); }; @@ -195,10 +155,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 0, - comp_h: r_h, - comp_v: r_v, - max_h, - max_v, + component: scaled.component(0), local_y_out: local_y as u32, stripe_rows, width, @@ -209,10 +166,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 1, - comp_h: g_h, - comp_v: g_v, - max_h, - max_v, + component: scaled.component(1), local_y_out: local_y as u32, stripe_rows, width, @@ -223,10 +177,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( neighbors, spec: StripeComponentUpsampleSpec { plane_idx: 2, - comp_h: b_h, - comp_v: b_v, - max_h, - max_v, + component: scaled.component(2), local_y_out: local_y as u32, stripe_rows, width, @@ -248,6 +199,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( for local_y in 0..stripe_rows { fill_four_component_rgb_row( plan, + scaled, neighbors, FourComponentRow { local_y: local_y as u32, @@ -255,7 +207,7 @@ pub(in crate::entropy::sequential) fn emit_stripe( width, }, scratch, - )?; + ); writer.write_rgb_row( y_start + local_y as u32, &scratch.r[..width], diff --git a/crates/j2k-jpeg/src/entropy/sequential/emit/rgb.rs b/crates/j2k-jpeg/src/entropy/sequential/emit/rgb.rs index ae0898315..d465250c6 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/emit/rgb.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/emit/rgb.rs @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use super::{ - super::{is_ycbcr_420, scaled_dimensions, PreparedDecodePlan, RgbOutputScratch}, + super::{scaled_dimensions, uses_fancy_420_emit, PreparedDecodePlan, RgbOutputScratch}, four_component::{fill_four_component_rgb_row, FourComponentRow}, - types::{StripeEmit, StripeNeighbors}, + types::{ensure_color_components, StripeEmit, StripeNeighbors}, upsample::{ component_row_triplet, upsample_component_row_stripe, valid_component_rows, StripeComponentUpsample, StripeComponentUpsampleSpec, @@ -38,6 +38,7 @@ pub(in crate::entropy::sequential) fn emit_stripe_rgb { + ColorSpace::YCbCr if uses_fancy_420_emit(plan, scaled) => { let RgbOutputScratch::YCbCr420 = output_scratch else { unreachable!("4:2:0 YCbCr RGB output requires dedicated scratch"); }; @@ -119,21 +121,10 @@ pub(in crate::entropy::sequential) fn emit_stripe_rgb { pub(in crate::entropy::sequential) stripe_index: u32, pub(in crate::entropy::sequential) source_width: usize, pub(in crate::entropy::sequential) downscale: DownscaleFactor, + pub(in crate::entropy::sequential) scaled: &'a ScaledSampling, } #[derive(Clone, Copy)] @@ -31,3 +34,21 @@ pub(in crate::entropy::sequential) struct StripeNeighbors<'a> { pub(in crate::entropy::sequential) curr: &'a StripeBuffer, pub(in crate::entropy::sequential) next: Option<&'a StripeBuffer>, } + +/// Rejects a plan with fewer components than its color space's emitters read +/// (three for YCbCr and RGB, four for CMYK and YCCK). +pub(in crate::entropy::sequential) fn ensure_color_components( + plan: &PreparedDecodePlan, +) -> Result<(), JpegError> { + let needed = match plan.color_space { + ColorSpace::Grayscale => 1, + ColorSpace::YCbCr | ColorSpace::Rgb => 3, + ColorSpace::Cmyk | ColorSpace::Ycck => 4, + }; + if plan.sampling.len() < needed { + return Err(JpegError::UnsupportedComponentCount { + count: u8::try_from(plan.sampling.len()).unwrap_or(u8::MAX), + }); + } + Ok(()) +} diff --git a/crates/j2k-jpeg/src/entropy/sequential/emit/upsample.rs b/crates/j2k-jpeg/src/entropy/sequential/emit/upsample.rs index ce0b545b0..303d57c84 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/emit/upsample.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/emit/upsample.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use super::{super::StripePlane, types::StripeNeighbors}; +use crate::color::scaled_sampling::{ScaledComponent, Upsample}; use crate::color::upsample::{ upsample_1x1, upsample_h1v2_fancy_row, upsample_h2v1_fancy_row, upsample_h2v2_fancy_row, upsample_h2v2_fancy_rows, @@ -9,10 +10,7 @@ use crate::color::upsample::{ #[derive(Clone, Copy)] pub(super) struct StripeComponentUpsampleSpec { pub(super) plane_idx: usize, - pub(super) comp_h: u32, - pub(super) comp_v: u32, - pub(super) max_h: u32, - pub(super) max_v: u32, + pub(super) component: ScaledComponent, pub(super) local_y_out: u32, pub(super) stripe_rows: usize, pub(super) width: usize, @@ -106,16 +104,17 @@ pub(super) fn upsample_component_row_stripe(request: StripeComponentUpsample<'_, let StripeNeighbors { prev, curr, next } = neighbors; let StripeComponentUpsampleSpec { plane_idx, - comp_h, - comp_v, - max_h, - max_v, + component, local_y_out, stripe_rows, width, } = spec; - let v_ratio = max_v / comp_v; - let h_ratio = max_h / comp_h; + let ScaledComponent { + h_ratio, + v_ratio, + upsample, + .. + } = component; let curr_plane = curr.plane(plane_idx); let chroma_rows = curr_plane.rows as u32; let chroma_y = (local_y_out / v_ratio).min(chroma_rows.saturating_sub(1)); @@ -127,15 +126,15 @@ pub(super) fn upsample_component_row_stripe(request: StripeComponentUpsample<'_, valid_component_rows(stripe_rows, v_ratio as usize), ); - match (h_ratio, v_ratio) { - (1, 1) => { + match upsample { + Upsample::None => { upsample_1x1(&curr_row[..width], out); } - (2, 1) => { + Upsample::FancyH2V1 => { let chroma_cols = width.div_ceil(2); upsample_h2v1_fancy_row(&curr_row[..chroma_cols], width, out); } - (1, 2) => { + Upsample::FancyH1V2 => { upsample_h1v2_fancy_row( &prev_row[..width], &curr_row[..width], @@ -145,7 +144,7 @@ pub(super) fn upsample_component_row_stripe(request: StripeComponentUpsample<'_, out, ); } - (2, 2) => { + Upsample::FancyH2V2 => { let chroma_cols = width.div_ceil(2); upsample_h2v2_fancy_row( &prev_row[..chroma_cols], @@ -156,7 +155,7 @@ pub(super) fn upsample_component_row_stripe(request: StripeComponentUpsample<'_, out, ); } - _ => { + Upsample::Replicate => { for (x, slot) in out.iter_mut().enumerate().take(width) { let cx = ((x as u32) / h_ratio).min(curr_row.len() as u32 - 1); *slot = curr_row[cx as usize]; diff --git a/crates/j2k-jpeg/src/entropy/sequential/fast420/mod.rs b/crates/j2k-jpeg/src/entropy/sequential/fast420/mod.rs index 30a77cee1..c453ad314 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/fast420/mod.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/fast420/mod.rs @@ -1,17 +1,17 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -//! Fast 4:2:0 sequential scan drivers, ROI planning, and scaled routing. +//! Fast 4:2:0 sequential scan drivers and ROI planning (full-size only; scaled +//! 4:2:0 decodes chroma with a larger IDCT on the generic route). use super::deposit::{ FastTile420Components, FastTile420DcState, FastTile420EntropyState, FastTile420Window, - ReducedIdctScratch, }; use super::emit::{ emit_stripe_rgb, emit_stripe_rgb_420_region, Fast420RegionStripe, StripeEmit, StripeNeighbors, }; use super::layout::{ fast420_decode_mcu_row_end, fast420_first_decode_mcu_row, last_mcu_row_for_rect, - mcu_row_intersects_rect, scaled_dimensions, Fast420RegionLayout, + mcu_row_intersects_rect, uses_fancy_420_emit, Fast420RegionLayout, }; use super::profile::{Fast420ScanProfiler, NoopFast420Profiler, NoopFast420ScanProfile}; use super::restart::{finish_scan, reader_from_checkpoint}; @@ -19,6 +19,7 @@ use super::{PreparedDecodePlan, ResolvedPreparedComponentPlan, RgbOutputScratch, use crate::backend::Backend; #[cfg(feature = "bench-internals")] use crate::bench_support::BenchFast420Profile; +use crate::color::scaled_sampling::ScaledSampling; use crate::entropy::block::CoefficientBlock; use crate::error::{JpegError, Warning}; use crate::info::{DownscaleFactor, Rect}; @@ -31,7 +32,7 @@ use alloc::vec::Vec; mod rows; pub(super) use self::rows::decode_mcu_row_fast_tile_420; -use self::rows::{decode_mcu_row_fast_tile_420_scaled, skip_mcu_fast_tile_420}; +use self::rows::skip_mcu_fast_tile_420; fn fast_tile_components( plan: &PreparedDecodePlan, @@ -90,10 +91,13 @@ where pool.prepare_for( plan, + plan.sampling, mcus_per_row, DownscaleFactor::Full.output_block_size(), plan.scratch_bytes, )?; + let scaled = ScaledSampling::new(plan.sampling, DownscaleFactor::Full, plan.dimensions); + debug_assert!(uses_fancy_420_emit(plan, &scaled)); let mut br = BitReader::new(scan_bytes); let mut coeff = CoefficientBlock::default(); @@ -179,6 +183,7 @@ where stripe_index: my - 1, source_width: width as usize, downscale: DownscaleFactor::Full, + scaled: &scaled, }, )?; profile.finish_rgb_emit(emit_timer); @@ -200,6 +205,7 @@ where stripe_index: mcu_rows - 1, source_width: width as usize, downscale: DownscaleFactor::Full, + scaled: &scaled, }, )?; profile.finish_rgb_emit(emit_timer); @@ -256,6 +262,7 @@ pub(crate) fn decode_scan_fast_tile_rgb_region { - pub(crate) roi: Rect, - pub(crate) downscale: DownscaleFactor, - pub(crate) checkpoint: Option<&'a DeviceCheckpoint>, -} - -#[expect( - clippy::too_many_lines, - reason = "the fused scaled-region loop keeps ROI seek, reduced IDCT, restart, and writer state in decode order" -)] -pub(crate) fn decode_scan_fast_tile_rgb_region_scaled( - plan: &PreparedDecodePlan, - backend: Backend, - scan_bytes: &[u8], - pool: &mut ScratchPool, - writer: &mut W, - request: FastTileRegionScaledRequest<'_>, -) -> Result, JpegError> { - let FastTileRegionScaledRequest { - roi, - downscale, - checkpoint, - } = request; - debug_assert!(plan.matches_fast_tile_shape()); - debug_assert!(downscale != DownscaleFactor::Full); - - let (width, height) = scaled_dimensions(plan.dimensions, downscale); - let max_h = u32::from(plan.sampling.max_h); - let max_v = u32::from(plan.sampling.max_v); - let block_size = downscale.output_block_size(); - let mcu_width_px = block_size * max_h; - let mcu_height_px = block_size * max_v; - let mcus_per_row = width.div_ceil(mcu_width_px); - let mcu_rows = height.div_ceil(mcu_height_px); - let first_decode_mcu_row = fast420_first_decode_mcu_row(roi, mcu_height_px); - let decode_mcu_row_end = fast420_decode_mcu_row_end(roi, mcu_height_px, mcu_rows); - let last_output_mcu_row = last_mcu_row_for_rect(roi, mcu_height_px, mcu_rows); - - let region_layout = Fast420RegionLayout::new_for_mcu_width(width as usize, roi, mcu_width_px); - - let mut crop_rows = pool.take_sink_rows( - region_layout.row_width().saturating_mul(3), - plan.scratch_bytes, - )?; - if let Err(error) = pool.prepare_for( - plan, - region_layout.stripe_mcus_per_row, - block_size, - plan.scratch_bytes, - ) { - pool.restore_sink_rows(crop_rows); - return Err(error); - } - let result = (|| { - let mut coeff = CoefficientBlock::default(); - let ScratchPool { - prev_dc, - stripe_a, - stripe_b, - stripe_c, - .. - } = pool; - let mut pixels_4x4 = [0u8; 16]; - let mut pixels_2x2 = [0u8; 4]; - let (y_dc_slice, rest_dc) = prev_dc.split_at_mut(1); - let (cb_dc_slice, cr_dc_slice) = rest_dc.split_at_mut(1); - let y_dc = &mut y_dc_slice[0]; - let cb_dc = &mut cb_dc_slice[0]; - let cr_dc = &mut cr_dc_slice[0]; - let target_mcu = first_decode_mcu_row * mcus_per_row; - let (mut br, checkpoint_dc, start_mcu) = - reader_from_checkpoint(scan_bytes, checkpoint, target_mcu); - *y_dc = checkpoint_dc[0]; - *cb_dc = checkpoint_dc[1]; - *cr_dc = checkpoint_dc[2]; - let (y, cb, cr) = fast_tile_components(plan)?; - let components = FastTile420Components { y, cb, cr }; - let window = FastTile420Window { - mcus_per_row, - stripe_mcu_start: region_layout.stripe_mcu_start, - stripe_mcus_per_row: region_layout.stripe_mcus_per_row, - }; - for _ in start_mcu..target_mcu { - skip_mcu_fast_tile_420( - components.y, - components.cb, - components.cr, - &mut br, - &mut *y_dc, - &mut *cb_dc, - &mut *cr_dc, - )?; - } - - let mut prev_stripe: &mut StripeBuffer = stripe_a; - let mut curr_stripe: &mut StripeBuffer = stripe_b; - let mut next_stripe: &mut StripeBuffer = stripe_c; - - decode_mcu_row_fast_tile_420_scaled( - components, - &mut FastTile420EntropyState { - br: &mut br, - dc: FastTile420DcState { - y: &mut *y_dc, - cb: &mut *cb_dc, - cr: &mut *cr_dc, - }, - coeff: &mut coeff, - }, - downscale, - ReducedIdctScratch { - pixels_4x4: &mut pixels_4x4, - pixels_2x2: &mut pixels_2x2, - }, - window, - curr_stripe, - )?; - - let mut has_prev = false; - for my in first_decode_mcu_row + 1..decode_mcu_row_end { - decode_mcu_row_fast_tile_420_scaled( - components, - &mut FastTile420EntropyState { - br: &mut br, - dc: FastTile420DcState { - y: &mut *y_dc, - cb: &mut *cb_dc, - cr: &mut *cr_dc, - }, - coeff: &mut coeff, - }, - downscale, - ReducedIdctScratch { - pixels_4x4: &mut pixels_4x4, - pixels_2x2: &mut pixels_2x2, - }, - window, - next_stripe, - )?; - if mcu_row_intersects_rect(my - 1, mcu_height_px, roi) { - emit_stripe_rgb_420_region( - plan, - backend, - writer, - Fast420RegionStripe { - neighbors: StripeNeighbors { - prev: has_prev.then_some(&*prev_stripe), - curr: curr_stripe, - next: Some(&*next_stripe), - }, - stripe_index: my - 1, - roi, - region_layout, - crop_rows: &mut crop_rows, - downscale, - }, - )?; - } - core::mem::swap(&mut prev_stripe, &mut curr_stripe); - core::mem::swap(&mut curr_stripe, &mut next_stripe); - has_prev = true; - } - - let curr_mcu_row = decode_mcu_row_end - 1; - if curr_mcu_row <= last_output_mcu_row - && mcu_row_intersects_rect(curr_mcu_row, mcu_height_px, roi) - { - emit_stripe_rgb_420_region( - plan, - backend, - writer, - Fast420RegionStripe { - neighbors: StripeNeighbors { - prev: has_prev.then_some(&*prev_stripe), - curr: curr_stripe, - next: None, - }, - stripe_index: curr_mcu_row, - roi, - region_layout, - crop_rows: &mut crop_rows, - downscale, - }, - )?; - } - finish_scan(&mut br, decode_mcu_row_end == mcu_rows) - })(); - pool.restore_sink_rows(crop_rows); - result -} diff --git a/crates/j2k-jpeg/src/entropy/sequential/fast420/rows.rs b/crates/j2k-jpeg/src/entropy/sequential/fast420/rows.rs index 5a7e5d909..17f5c4c88 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/fast420/rows.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/fast420/rows.rs @@ -3,17 +3,14 @@ //! Entropy and IDCT row kernels for the fast 4:2:0 sequential route. use super::super::deposit::{ - assert_stripe_deposit_capacity, decode_eighth_block_to_plane, decode_quarter_block_to_plane, - decode_scaled_block_to_plane, idct_deposit_fast_tile_block, EntropyBlockState, - FastTile420Components, FastTile420EntropyState, FastTile420Window, PlaneBlockTarget, - ReducedIdctScratch, + assert_stripe_deposit_capacity, idct_deposit_fast_tile_block, FastTile420Components, + FastTile420EntropyState, FastTile420Window, PlaneBlockTarget, }; use super::super::profile::Fast420Profiler; use super::super::{ResolvedPreparedComponentPlan, StripeBuffer}; use crate::backend::Backend; use crate::entropy::block::{decode_block_with_activity, skip_block}; use crate::error::JpegError; -use crate::info::DownscaleFactor; use crate::internal::bit_reader::BitReader; // ROI seeks invoke this leaf once per skipped MCU; forced inlining keeps its six Huffman skips @@ -40,175 +37,6 @@ pub(super) fn skip_mcu_fast_tile_420( Ok(()) } -#[expect( - clippy::too_many_lines, - reason = "the scaled MCU-row kernel keeps six component blocks and shared reduced-IDCT scratch in sampling order" -)] -#[expect( - clippy::needless_pass_by_value, - reason = "scratch and window are compact borrowing descriptors threaded through the fused 4:2:0 MCU-row hot path" -)] -pub(super) fn decode_mcu_row_fast_tile_420_scaled( - components: FastTile420Components<'_>, - state: &mut FastTile420EntropyState<'_, '_>, - downscale: DownscaleFactor, - scratch: ReducedIdctScratch<'_>, - window: FastTile420Window, - stripe: &mut StripeBuffer, -) -> Result<(), JpegError> { - if downscale == DownscaleFactor::Quarter { - return decode_mcu_row_fast_tile_420_quarter( - components, - state, - scratch.pixels_2x2, - window, - stripe, - ); - } - if downscale == DownscaleFactor::Eighth { - return decode_mcu_row_fast_tile_420_eighth(components, state, window, stripe); - } - - let block_size = downscale.output_block_size(); - let y_stride = stripe.plane_strides[0]; - let cb_stride = stripe.plane_strides[1]; - let cr_stride = stripe.plane_strides[2]; - - for mx in 0..window.mcus_per_row { - if !window.contains_mcu(mx) { - skip_mcu_fast_tile_420( - components.y, - components.cb, - components.cr, - &mut *state.br, - &mut *state.dc.y, - &mut *state.dc.cb, - &mut *state.dc.cr, - )?; - continue; - } - - let local_mx = window.local_mcu_x(mx); - let y_x = local_mx * 2 * block_size; - let c_x = local_mx * block_size; - decode_scaled_block_to_plane( - components.y, - downscale, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - ReducedIdctScratch { - pixels_4x4: &mut *scratch.pixels_4x4, - pixels_2x2: &mut *scratch.pixels_2x2, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x, - y: 0, - }, - )?; - decode_scaled_block_to_plane( - components.y, - downscale, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - ReducedIdctScratch { - pixels_4x4: &mut *scratch.pixels_4x4, - pixels_2x2: &mut *scratch.pixels_2x2, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x + block_size, - y: 0, - }, - )?; - decode_scaled_block_to_plane( - components.y, - downscale, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - ReducedIdctScratch { - pixels_4x4: &mut *scratch.pixels_4x4, - pixels_2x2: &mut *scratch.pixels_2x2, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x, - y: block_size, - }, - )?; - decode_scaled_block_to_plane( - components.y, - downscale, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - ReducedIdctScratch { - pixels_4x4: &mut *scratch.pixels_4x4, - pixels_2x2: &mut *scratch.pixels_2x2, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x + block_size, - y: block_size, - }, - )?; - decode_scaled_block_to_plane( - components.cb, - downscale, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.cb, - coeff: &mut *state.coeff, - }, - ReducedIdctScratch { - pixels_4x4: &mut *scratch.pixels_4x4, - pixels_2x2: &mut *scratch.pixels_2x2, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[1], - stride: cb_stride, - x: c_x, - y: 0, - }, - )?; - decode_scaled_block_to_plane( - components.cr, - downscale, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.cr, - coeff: &mut *state.coeff, - }, - ReducedIdctScratch { - pixels_4x4: &mut *scratch.pixels_4x4, - pixels_2x2: &mut *scratch.pixels_2x2, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[2], - stride: cr_stride, - x: c_x, - y: 0, - }, - )?; - } - Ok(()) -} - pub(in crate::entropy::sequential) fn decode_mcu_row_fast_tile_420( components: FastTile420Components<'_>, backend: Backend, @@ -417,252 +245,3 @@ fn decode_mcu_row_fast_tile_420_local( Ok(()) } - -#[expect( - clippy::too_many_lines, - reason = "the eighth-scale MCU kernel keeps six entropy blocks and 1x1 deposits in sampling order" -)] -fn decode_mcu_row_fast_tile_420_eighth( - components: FastTile420Components<'_>, - state: &mut FastTile420EntropyState<'_, '_>, - window: FastTile420Window, - stripe: &mut StripeBuffer, -) -> Result<(), JpegError> { - const BLOCK_SIZE: u32 = 1; - let y_stride = stripe.plane_strides[0]; - let cb_stride = stripe.plane_strides[1]; - let cr_stride = stripe.plane_strides[2]; - - for mx in 0..window.mcus_per_row { - if !window.contains_mcu(mx) { - skip_mcu_fast_tile_420( - components.y, - components.cb, - components.cr, - &mut *state.br, - &mut *state.dc.y, - &mut *state.dc.cb, - &mut *state.dc.cr, - )?; - continue; - } - - let local_mx = window.local_mcu_x(mx); - let y_x = local_mx * 2 * BLOCK_SIZE; - let c_x = local_mx * BLOCK_SIZE; - decode_eighth_block_to_plane( - components.y, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x, - y: 0, - }, - )?; - decode_eighth_block_to_plane( - components.y, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x + BLOCK_SIZE, - y: 0, - }, - )?; - decode_eighth_block_to_plane( - components.y, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x, - y: BLOCK_SIZE, - }, - )?; - decode_eighth_block_to_plane( - components.y, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x + BLOCK_SIZE, - y: BLOCK_SIZE, - }, - )?; - decode_eighth_block_to_plane( - components.cb, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.cb, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[1], - stride: cb_stride, - x: c_x, - y: 0, - }, - )?; - decode_eighth_block_to_plane( - components.cr, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.cr, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[2], - stride: cr_stride, - x: c_x, - y: 0, - }, - )?; - } - - Ok(()) -} - -#[expect( - clippy::too_many_lines, - reason = "the quarter-scale MCU kernel keeps six entropy blocks and 2x2 deposits in sampling order" -)] -fn decode_mcu_row_fast_tile_420_quarter( - components: FastTile420Components<'_>, - state: &mut FastTile420EntropyState<'_, '_>, - pixels_2x2: &mut [u8; 4], - window: FastTile420Window, - stripe: &mut StripeBuffer, -) -> Result<(), JpegError> { - const BLOCK_SIZE: u32 = 2; - let y_stride = stripe.plane_strides[0]; - let cb_stride = stripe.plane_strides[1]; - let cr_stride = stripe.plane_strides[2]; - - for mx in 0..window.mcus_per_row { - if !window.contains_mcu(mx) { - skip_mcu_fast_tile_420( - components.y, - components.cb, - components.cr, - &mut *state.br, - &mut *state.dc.y, - &mut *state.dc.cb, - &mut *state.dc.cr, - )?; - continue; - } - - let local_mx = window.local_mcu_x(mx); - let y_x = local_mx * 2 * BLOCK_SIZE; - let c_x = local_mx * BLOCK_SIZE; - decode_quarter_block_to_plane( - components.y, - pixels_2x2, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x, - y: 0, - }, - )?; - decode_quarter_block_to_plane( - components.y, - pixels_2x2, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x + BLOCK_SIZE, - y: 0, - }, - )?; - decode_quarter_block_to_plane( - components.y, - pixels_2x2, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x, - y: BLOCK_SIZE, - }, - )?; - decode_quarter_block_to_plane( - components.y, - pixels_2x2, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.y, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[0], - stride: y_stride, - x: y_x + BLOCK_SIZE, - y: BLOCK_SIZE, - }, - )?; - decode_quarter_block_to_plane( - components.cb, - pixels_2x2, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.cb, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[1], - stride: cb_stride, - x: c_x, - y: 0, - }, - )?; - decode_quarter_block_to_plane( - components.cr, - pixels_2x2, - EntropyBlockState { - br: &mut *state.br, - prev_dc: &mut *state.dc.cr, - coeff: &mut *state.coeff, - }, - PlaneBlockTarget { - plane: &mut stripe.planes[2], - stride: cr_stride, - x: c_x, - y: 0, - }, - )?; - } - - Ok(()) -} diff --git a/crates/j2k-jpeg/src/entropy/sequential/generic.rs b/crates/j2k-jpeg/src/entropy/sequential/generic.rs index 219760924..d1024b6eb 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/generic.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/generic.rs @@ -7,6 +7,7 @@ mod row; use self::driver::{decode_scan_rows, ScanBuffers, ScanOutputMode, ScanSetup, StripeEmitter}; use super::emit::{emit_stripe, emit_stripe_rgb, StripeEmit}; +use super::layout::uses_fancy_420_emit; use super::{OutputScratch, PreparedDecodePlan, RgbOutputScratch}; use crate::backend::Backend; use crate::error::{JpegError, Warning}; @@ -59,6 +60,7 @@ pub(crate) fn decode_scan_baseline( ) -> Result, JpegError> { let setup = ScanSetup::new(plan, downscale, output_rect, ScanOutputMode::ComponentRows); setup.prepare_pool(plan, pool)?; + let fancy_420 = uses_fancy_420_emit(plan, &setup.scaled); let ScratchPool { prev_dc, stripe_a, @@ -71,7 +73,7 @@ pub(crate) fn decode_scan_baseline( } = pool; let scratch = match plan.color_space { ColorSpace::Grayscale => OutputScratch::Grayscale, - ColorSpace::YCbCr if super::is_ycbcr_420(plan) => OutputScratch::YCbCr420(ycbcr_420_rows), + ColorSpace::YCbCr if fancy_420 => OutputScratch::YCbCr420(ycbcr_420_rows), ColorSpace::YCbCr => OutputScratch::YCbCrGeneric(ycbcr_generic_rows), ColorSpace::Rgb | ColorSpace::Cmyk | ColorSpace::Ycck => { OutputScratch::RgbGeneric(rgb_generic_rows) @@ -109,6 +111,7 @@ pub(crate) fn decode_scan_baseline_rgb( ) -> Result, JpegError> { let setup = ScanSetup::new(plan, downscale, output_rect, ScanOutputMode::InterleavedRgb); setup.prepare_pool(plan, pool)?; + let fancy_420 = uses_fancy_420_emit(plan, &setup.scaled); let ScratchPool { prev_dc, stripe_a, @@ -120,7 +123,7 @@ pub(crate) fn decode_scan_baseline_rgb( } = pool; let scratch = match plan.color_space { ColorSpace::Grayscale => RgbOutputScratch::None, - ColorSpace::YCbCr if super::is_ycbcr_420(plan) => RgbOutputScratch::YCbCr420, + ColorSpace::YCbCr if fancy_420 => RgbOutputScratch::YCbCr420, ColorSpace::YCbCr => RgbOutputScratch::YCbCrGeneric(ycbcr_generic_rows), ColorSpace::Rgb | ColorSpace::Cmyk | ColorSpace::Ycck => { RgbOutputScratch::RgbGeneric(rgb_generic_rows) diff --git a/crates/j2k-jpeg/src/entropy/sequential/generic/driver.rs b/crates/j2k-jpeg/src/entropy/sequential/generic/driver.rs index 9c7517957..00c635b0c 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/generic/driver.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/generic/driver.rs @@ -5,8 +5,8 @@ use super::super::emit::StripeEmit; use super::super::layout::{ decode_mcu_row_end_for_rect, expanded_output_rect, fast420_decode_mcu_row_end, - fast420_first_decode_mcu_row, first_decode_mcu_row_for_rect, is_ycbcr_420, - last_mcu_row_for_rect, mcu_row_intersects_rect, scaled_dimensions, stripe_region_layout, + fast420_first_decode_mcu_row, first_decode_mcu_row_for_rect, last_mcu_row_for_rect, + mcu_row_intersects_rect, scaled_dimensions, stripe_region_layout, uses_fancy_420_emit, StripeRegionLayout, }; use super::super::restart::{ @@ -15,6 +15,7 @@ use super::super::restart::{ use super::super::{PreparedDecodePlan, StripeBuffer}; use super::row::{decode_mcu_row, McuRowContext, McuRowState}; use crate::backend::Backend; +use crate::color::scaled_sampling::ScaledSampling; use crate::entropy::block::CoefficientBlock; use crate::error::{JpegError, Warning}; use crate::info::{DownscaleFactor, Rect}; @@ -30,6 +31,7 @@ pub(super) enum ScanOutputMode { #[derive(Clone, Copy)] pub(super) struct ScanSetup { + pub(super) scaled: ScaledSampling, block_size: u32, mcu_height_px: u32, mcus_per_row: u32, @@ -52,6 +54,7 @@ impl ScanSetup { mode: ScanOutputMode, ) -> Self { let (width, height) = scaled_dimensions(plan.dimensions, downscale); + let scaled = ScaledSampling::new(plan.sampling, downscale, plan.dimensions); let block_size = downscale.output_block_size(); let mcu_width_px = block_size * u32::from(plan.sampling.max_h); let mcu_height_px = block_size * u32::from(plan.sampling.max_v); @@ -61,7 +64,7 @@ impl ScanSetup { let full_output_rect = expanded_rect == Rect::full((width, height)); let use_420_context_window = matches!(mode, ScanOutputMode::InterleavedRgb) && !full_output_rect - && is_ycbcr_420(plan); + && uses_fancy_420_emit(plan, &scaled); let emit_rect = if use_420_context_window { output_rect } else { @@ -79,6 +82,7 @@ impl ScanSetup { }; Self { + scaled, block_size, mcu_height_px, mcus_per_row, @@ -101,6 +105,7 @@ impl ScanSetup { ) -> Result<(), JpegError> { pool.prepare_for( plan, + self.scaled.effective, self.region.stripe_mcus_per_row, self.block_size, plan.scratch_bytes, @@ -172,6 +177,7 @@ pub(super) fn decode_scan_rows( plan, backend, downscale, + scaled: &setup.scaled, output_rect: setup.expanded_rect, full_output_rect: setup.full_output_rect, stripe_mcu_start: setup.region.stripe_mcu_start, @@ -210,6 +216,7 @@ pub(super) fn decode_scan_rows( stripe_index: mcu_row - 1, source_width: setup.region.source_width_usize(), downscale, + scaled: &setup.scaled, })?; } core::mem::swap(&mut prev_stripe, &mut curr_stripe); @@ -227,6 +234,7 @@ pub(super) fn decode_scan_rows( stripe_index: current_mcu_row, source_width: setup.region.source_width_usize(), downscale, + scaled: &setup.scaled, })?; } finish_scan(&mut br, setup.decode_mcu_row_end == setup.mcu_rows) diff --git a/crates/j2k-jpeg/src/entropy/sequential/generic/row.rs b/crates/j2k-jpeg/src/entropy/sequential/generic/row.rs index 7a18ec38c..61928858d 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/generic/row.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/generic/row.rs @@ -10,6 +10,7 @@ use super::super::layout::{component_block_intersects_rect, ComponentBlockPositi use super::super::restart::{consume_restart_marker_if_due, McuPosition}; use super::super::{PreparedDecodePlan, StripeBuffer}; use crate::backend::Backend; +use crate::color::scaled_sampling::ScaledSampling; use crate::entropy::block::{ decode_block_with_activity, skip_block, BlockActivity, CoefficientBlock, }; @@ -22,6 +23,9 @@ pub(super) struct McuRowContext<'a> { pub(super) plan: &'a PreparedDecodePlan, pub(super) backend: Backend, pub(super) downscale: DownscaleFactor, + /// Per-component IDCT sizes; planes are laid out for its effective + /// sampling. + pub(super) scaled: &'a ScaledSampling, pub(super) output_rect: Rect, pub(super) full_output_rect: bool, pub(super) stripe_mcu_start: u32, @@ -89,7 +93,6 @@ fn decode_mcu_row_local( stripe: &mut StripeBuffer, ) -> Result<(), JpegError> { let stripe_mcu_end = context.stripe_mcu_start + context.stripe_mcus_per_row; - let block_size = context.downscale.output_block_size(); for comp in &context.plan.components { assert_stripe_deposit_capacity( stripe, @@ -97,7 +100,7 @@ fn decode_mcu_row_local( u32::from(comp.h), u32::from(comp.v), context.stripe_mcus_per_row, - block_size, + context.scaled.component(comp.output_index).idct_size, ); } let mut pixels_4x4 = [0u8; 16]; @@ -133,6 +136,9 @@ fn decode_mcu_row_local( let dc_table = tables.dc_table; let ac_table = tables.ac_table; let in_region = mx >= context.stripe_mcu_start && mx < stripe_mcu_end; + // libjpeg-turbo may decode a subsampled component with a larger + // reduced IDCT than the scale's own block size. + let block_size = context.scaled.component(plane_idx).idct_size; let local_mcu_x0_px = mx.saturating_sub(context.stripe_mcu_start) * u32::from(comp.h) * block_size; for vy in 0..u32::from(comp.v) { @@ -166,84 +172,51 @@ fn decode_mcu_row_local( )?; let block_x = local_mcu_x0_px + vx * block_size; let block_y = vy * block_size; - match context.downscale { - DownscaleFactor::Full => { - match activity { - BlockActivity::DcOnly => { - crate::idct::idct_islow_dc_only( - state.coeff.dc_coeff(), - state.pixels, - ); - } - BlockActivity::BottomHalfZero => { - context.backend.idct_bottom_half_zero( - state.coeff.coefficients(), - state.pixels, - ); - } - BlockActivity::General => { - context - .backend - .idct(state.coeff.coefficients(), state.pixels); - } - } - deposit_block( - &mut stripe.planes[plane_idx], - stripe.plane_strides[plane_idx], - block_x, - block_y, - state.pixels, - ); + let plane = &mut stripe.planes[plane_idx]; + let stride = stripe.plane_strides[plane_idx]; + match (block_size, activity) { + (8, BlockActivity::DcOnly) => { + crate::idct::idct_islow_dc_only(state.coeff.dc_coeff(), state.pixels); + deposit_block(plane, stride, block_x, block_y, state.pixels); + } + (8, BlockActivity::BottomHalfZero) => { + context + .backend + .idct_bottom_half_zero(state.coeff.coefficients(), state.pixels); + deposit_block(plane, stride, block_x, block_y, state.pixels); + } + (8, BlockActivity::General) => { + context + .backend + .idct(state.coeff.coefficients(), state.pixels); + deposit_block(plane, stride, block_x, block_y, state.pixels); } - DownscaleFactor::Half => { - if activity == BlockActivity::DcOnly { - downscale::idct_islow_4x4_dc_only( - state.coeff.dc_coeff(), - &mut pixels_4x4, - ); - } else { - downscale::idct_islow_4x4( - state.coeff.coefficients(), - &mut pixels_4x4, - ); - } - deposit_block_4x4( - &mut stripe.planes[plane_idx], - stripe.plane_strides[plane_idx], - block_x, - block_y, - &pixels_4x4, + (4, BlockActivity::DcOnly) => { + downscale::idct_islow_4x4_dc_only( + state.coeff.dc_coeff(), + &mut pixels_4x4, ); + deposit_block_4x4(plane, stride, block_x, block_y, &pixels_4x4); } - DownscaleFactor::Quarter => { - if activity == BlockActivity::DcOnly { - downscale::idct_islow_2x2_dc_only( - state.coeff.dc_coeff(), - &mut pixels_2x2, - ); - } else { - downscale::idct_islow_2x2( - state.coeff.coefficients(), - &mut pixels_2x2, - ); - } - deposit_block_2x2( - &mut stripe.planes[plane_idx], - stripe.plane_strides[plane_idx], - block_x, - block_y, - pixels_2x2, + (4, _) => { + downscale::idct_islow_4x4(state.coeff.coefficients(), &mut pixels_4x4); + deposit_block_4x4(plane, stride, block_x, block_y, &pixels_4x4); + } + (2, BlockActivity::DcOnly) => { + downscale::idct_islow_2x2_dc_only( + state.coeff.dc_coeff(), + &mut pixels_2x2, ); + deposit_block_2x2(plane, stride, block_x, block_y, pixels_2x2); + } + (2, _) => { + downscale::idct_islow_2x2(state.coeff.coefficients(), &mut pixels_2x2); + deposit_block_2x2(plane, stride, block_x, block_y, pixels_2x2); } - DownscaleFactor::Eighth => { + _ => { + debug_assert_eq!(block_size, 1, "IDCT sizes are 8, 4, 2 or 1"); let pixel = downscale::idct_islow_1x1(state.coeff.coefficients()); - deposit_block_1x1( - &mut stripe.planes[plane_idx], - stripe.plane_strides[plane_idx], - block_x, - block_y, - pixel, - ); + deposit_block_1x1(plane, stride, block_x, block_y, pixel); } } } diff --git a/crates/j2k-jpeg/src/entropy/sequential/layout.rs b/crates/j2k-jpeg/src/entropy/sequential/layout.rs index 3790a55fd..fced3c9e0 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/layout.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/layout.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use super::{PreparedComponentPlan, PreparedDecodePlan}; +use crate::color::scaled_sampling::ScaledSampling; use crate::info::{ColorSpace, DownscaleFactor, Rect}; #[derive(Clone, Copy)] @@ -209,6 +210,13 @@ impl Fast420RegionLayout { } } +/// Whether the dedicated 4:2:0 smoothing emitters produce this decode: coded +/// 4:2:0 YCbCr at a scale where libjpeg-turbo still upsamples its chroma with +/// `h2v2_fancy_upsample`. +pub(super) fn uses_fancy_420_emit(plan: &PreparedDecodePlan, scaled: &ScaledSampling) -> bool { + is_ycbcr_420(plan) && scaled.is_fancy_420() +} + pub(super) fn is_ycbcr_420(plan: &PreparedDecodePlan) -> bool { plan.color_space == ColorSpace::YCbCr && plan.sampling.max_h == 2 diff --git a/crates/j2k-jpeg/src/entropy/sequential/plan.rs b/crates/j2k-jpeg/src/entropy/sequential/plan.rs index fbd179d8a..11fab9056 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/plan.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/plan.rs @@ -64,8 +64,13 @@ impl PreparedDecodePlan { self.restart_interval.is_none() && self.matches_fast_420_device_shape() } + /// Coded 4:2:0 YCbCr whose full-size chroma libjpeg-turbo smooths with + /// `h2v2_fancy_upsample`, the only upsampler the fused 4:2:0 routes + /// implement. Chroma at most two samples wide (images at most four pixels + /// wide) is replicated instead and takes the generic route. pub(crate) fn matches_fast_420_device_shape(&self) -> bool { - is_ycbcr_420(self) + self.dimensions.0 > 4 + && is_ycbcr_420(self) && self.components.len() == 3 && self.components[0].output_index == 0 && self.components[0].h == 2 @@ -92,8 +97,12 @@ impl PreparedDecodePlan { && self.components[2].v == 1 } + /// Coded 4:2:2 YCbCr whose full-size chroma libjpeg-turbo smooths (more + /// than two chroma samples wide), the shape the device 4:2:2 kernels + /// implement. pub(crate) fn matches_fast_rgb422_shape(&self) -> bool { - self.color_space == ColorSpace::YCbCr + self.dimensions.0 > 4 + && self.color_space == ColorSpace::YCbCr && self.components.len() == 3 && self.components[0].output_index == 0 && self.components[0].h == 2 diff --git a/crates/j2k-jpeg/src/entropy/sequential/rgb444.rs b/crates/j2k-jpeg/src/entropy/sequential/rgb444.rs index e002f1c1c..c934e205d 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/rgb444.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/rgb444.rs @@ -48,6 +48,7 @@ pub(crate) fn decode_scan_fast_rgb_444( pool.prepare_for( plan, + plan.sampling, mcus_per_row, DownscaleFactor::Full.output_block_size(), plan.scratch_bytes, diff --git a/crates/j2k-jpeg/src/entropy/sequential/stripe.rs b/crates/j2k-jpeg/src/entropy/sequential/stripe.rs index da3514117..c82376c41 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/stripe.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/stripe.rs @@ -11,8 +11,6 @@ use crate::allocation::{ use crate::error::JpegError; use crate::info::SamplingFactors; -use super::PreparedDecodePlan; - #[derive(Debug, Default)] pub(crate) struct StripeBuffer { pub(crate) planes: Vec>, @@ -29,14 +27,6 @@ pub(crate) struct StripeLayout { } impl StripeLayout { - pub(crate) fn for_plan( - plan: &PreparedDecodePlan, - mcus_per_row: u32, - block_size: u32, - ) -> Result { - Self::for_sampling(plan.sampling, mcus_per_row, block_size) - } - pub(crate) fn for_sampling( sampling: SamplingFactors, mcus_per_row: u32, diff --git a/crates/j2k-jpeg/src/entropy/sequential/tests.rs b/crates/j2k-jpeg/src/entropy/sequential/tests.rs index 49c2a53fd..0137d483d 100644 --- a/crates/j2k-jpeg/src/entropy/sequential/tests.rs +++ b/crates/j2k-jpeg/src/entropy/sequential/tests.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use super::*; +use crate::color::scaled_sampling::ScaledSampling; use crate::entropy::huffman::{HuffmanTable, PreparedHuffmanTables}; use crate::info::{ColorSpace, SamplingFactors}; use crate::output::Rgb8Writer; @@ -422,13 +423,19 @@ fn emit_final_420_stripe( let block = downscale.output_block_size() as usize; let (scaled_width, scaled_height) = scaled_dimensions((13, height), downscale); let width = scaled_width as usize; - let real_chroma_rows = (scaled_height as usize - 2 * block).div_ceil(2); - let prev = synthetic_420_stripe(block, 5, None); - let curr = synthetic_420_stripe(block, 40, Some((real_chroma_rows, padding))); + let sampling = SamplingFactors::from_validated_components(&[(2, 2), (1, 1), (1, 1)]); + // Below full size the chroma is decoded at luma resolution (libjpeg-turbo + // enlarges its IDCT), so its planes match the luma plane. + let scaled = ScaledSampling::new(sampling, downscale, (13, height)); + let chroma = scaled.component(1); + let chroma_block = chroma.idct_size as usize; + let real_chroma_rows = (scaled_height as usize - 2 * block).div_ceil(chroma.v_ratio as usize); + let prev = synthetic_420_stripe(block, chroma_block, 5, None); + let curr = synthetic_420_stripe(block, chroma_block, 40, Some((real_chroma_rows, padding))); let plan = PreparedDecodePlan { components: vec![], huffman_tables: PreparedHuffmanTables::try_with_capacity(0).expect("empty test arena"), - sampling: SamplingFactors::from_validated_components(&[(2, 2), (1, 1), (1, 1)]), + sampling, color_space, restart_interval: None, dimensions: (13, height), @@ -447,6 +454,11 @@ fn emit_final_420_stripe( cr_top: vec![0; width], cr_bot: vec![0; width], }; + let mut ycbcr_rows = crate::internal::scratch::YCbCrGenericRows { + cb_up: vec![0; width], + cr_up: vec![0; width], + }; + let fancy_420 = scaled.is_fancy_420(); let mut out = vec![0u8; width * scaled_height as usize * 3]; let mut writer = Rgb8Writer::new(&mut out, width * 3, scaled_width); let emit = super::emit::StripeEmit { @@ -456,15 +468,23 @@ fn emit_final_420_stripe( stripe_index: 1, source_width: width, downscale, + scaled: &scaled, }; let result = match (rgb_emitter, color_space) { - (true, ColorSpace::YCbCr) => super::emit::emit_stripe_rgb( + (true, ColorSpace::YCbCr) if fancy_420 => super::emit::emit_stripe_rgb( &plan, Backend::detect(), &mut writer, &mut RgbOutputScratch::YCbCr420, emit, ), + (true, ColorSpace::YCbCr) => super::emit::emit_stripe_rgb( + &plan, + Backend::detect(), + &mut writer, + &mut RgbOutputScratch::YCbCrGeneric(&mut ycbcr_rows), + emit, + ), (true, _) => super::emit::emit_stripe_rgb( &plan, Backend::detect(), @@ -472,12 +492,18 @@ fn emit_final_420_stripe( &mut RgbOutputScratch::RgbGeneric(&mut rgb_rows), emit, ), - (false, ColorSpace::YCbCr) => super::emit::emit_stripe( + (false, ColorSpace::YCbCr) if fancy_420 => super::emit::emit_stripe( &plan, &mut writer, &mut OutputScratch::YCbCr420(&mut ycbcr420_rows), emit, ), + (false, ColorSpace::YCbCr) => super::emit::emit_stripe( + &plan, + &mut writer, + &mut OutputScratch::YCbCrGeneric(&mut ycbcr_rows), + emit, + ), (false, _) => super::emit::emit_stripe( &plan, &mut writer, @@ -489,16 +515,18 @@ fn emit_final_420_stripe( out.split_off(width * 2 * block * 3) } -/// One-MCU-wide 4:2:0 stripe of patterned samples. With -/// `Some((real_rows, padding))`, chroma rows from `real_rows` on hold -/// `padding`, or repeat the last real row when `padding` is `None`. +/// One-MCU-wide 4:2:0 stripe of patterned samples, with chroma decoded at +/// `chroma_block` samples per block. With `Some((real_rows, padding))`, chroma +/// rows from `real_rows` on hold `padding`, or repeat the last real row when +/// `padding` is `None`. fn synthetic_420_stripe( block: usize, + chroma_block: usize, seed: usize, chroma_padding: Option<(usize, Option)>, ) -> StripeBuffer { - let strides = [2 * block, block, block]; - let rows = [2 * block, block, block]; + let strides = [2 * block, chroma_block, chroma_block]; + let rows = [2 * block, chroma_block, chroma_block]; let planes = (0..3) .map(|index| { (0..strides[index] * rows[index]) diff --git a/crates/j2k-jpeg/src/idct/downscale.rs b/crates/j2k-jpeg/src/idct/downscale.rs index 149a7e284..8b8b707cf 100644 --- a/crates/j2k-jpeg/src/idct/downscale.rs +++ b/crates/j2k-jpeg/src/idct/downscale.rs @@ -206,8 +206,106 @@ fn idct_2x2_row(work: &[Wrapping; 16], output: &mut [u8; 4], row: usize) { output[out + 1] = descale_and_clamp(tmp10 - tmp0, shift); } +/// 12-bit `jidctred.c`: `BITS_IN_JSAMPLE == 12` keeps `PASS1_BITS = 1` for +/// headroom and computes in 64-bit `JLONG`. The C code's zero-AC shortcuts give +/// the same results as the full computation and are omitted, as in +/// [`super::scalar::idct_islow_12bit`]. +const PASS1_BITS_12: usize = 1; + +/// Reduced 4x4 IDCT of a 12-bit block (`jpeg_idct_4x4`). +pub(crate) fn idct_islow_12bit_4x4(input: &[i16; 64], output: &mut [u16; 16]) { + let fix = |value: Wrapping| i64::from(value.0); + let odd = |z1: i64, z2: i64, z3: i64, z4: i64| { + ( + z1 * -fix(FIX_0_211164243) + + z2 * fix(FIX_1_451774981) + + z3 * -fix(FIX_2_172734803) + + z4 * fix(FIX_1_061594337), + z1 * -fix(FIX_0_509795579) + + z2 * -fix(FIX_0_601344887) + + z3 * fix(FIX_0_899976223) + + z4 * fix(FIX_2_562915447), + ) + }; + let even = |p0: i64, p2: i64, p6: i64| { + let tmp0 = p0 << (CONST_BITS + 1); + let tmp2 = p2 * fix(FIX_1_847759065) - p6 * fix(FIX_0_765366865); + (tmp0 + tmp2, tmp0 - tmp2) + }; + let mut work = [0i64; 32]; + for col in (0..8).filter(|&col| col != 4) { + let p = |row: usize| i64::from(input[row * 8 + col]); + let (tmp10, tmp12) = even(p(0), p(2), p(6)); + let (tmp0, tmp2) = odd(p(7), p(5), p(3), p(1)); + let shift = CONST_BITS - PASS1_BITS_12 + 1; + work[col] = descale_i64(tmp10 + tmp2, shift); + work[24 + col] = descale_i64(tmp10 - tmp2, shift); + work[8 + col] = descale_i64(tmp12 + tmp0, shift); + work[16 + col] = descale_i64(tmp12 - tmp0, shift); + } + for row in 0..4 { + let w = |col: usize| work[row * 8 + col]; + let (tmp10, tmp12) = even(w(0), w(2), w(6)); + let (tmp0, tmp2) = odd(w(7), w(5), w(3), w(1)); + let shift = CONST_BITS + PASS1_BITS_12 + 3 + 1; + let out = &mut output[row * 4..row * 4 + 4]; + out[0] = level_shift_12bit(descale_i64(tmp10 + tmp2, shift)); + out[3] = level_shift_12bit(descale_i64(tmp10 - tmp2, shift)); + out[1] = level_shift_12bit(descale_i64(tmp12 + tmp0, shift)); + out[2] = level_shift_12bit(descale_i64(tmp12 - tmp0, shift)); + } +} + +/// Reduced 2x2 IDCT of a 12-bit block (`jpeg_idct_2x2`). +pub(crate) fn idct_islow_12bit_2x2(input: &[i16; 64], output: &mut [u16; 4]) { + let fix = |value: Wrapping| i64::from(value.0); + let odd = |p7: i64, p5: i64, p3: i64, p1: i64| { + p7 * -fix(FIX_0_720959822) + + p5 * fix(FIX_0_850430095) + + p3 * -fix(FIX_1_272758580) + + p1 * fix(FIX_3_624509785) + }; + let mut work = [0i64; 16]; + for col in [0, 1, 3, 5, 7] { + let p = |row: usize| i64::from(input[row * 8 + col]); + let tmp10 = p(0) << (CONST_BITS + 2); + let tmp0 = odd(p(7), p(5), p(3), p(1)); + let shift = CONST_BITS - PASS1_BITS_12 + 2; + work[col] = descale_i64(tmp10 + tmp0, shift); + work[8 + col] = descale_i64(tmp10 - tmp0, shift); + } + for row in 0..2 { + let w = |col: usize| work[row * 8 + col]; + let tmp10 = w(0) << (CONST_BITS + 2); + let tmp0 = odd(w(7), w(5), w(3), w(1)); + let shift = CONST_BITS + PASS1_BITS_12 + 3 + 2; + output[row * 2] = level_shift_12bit(descale_i64(tmp10 + tmp0, shift)); + output[row * 2 + 1] = level_shift_12bit(descale_i64(tmp10 - tmp0, shift)); + } +} + +/// Reduced 1x1 IDCT of a 12-bit block (`jpeg_idct_1x1`). +pub(crate) fn idct_islow_12bit_1x1(input: &[i16; 64]) -> u16 { + level_shift_12bit(descale_i64(i64::from(input[0]), 3)) +} + +const fn descale_i64(value: i64, shift: usize) -> i64 { + (value + (1 << (shift - 1))) >> shift +} + +#[expect( + clippy::cast_sign_loss, + reason = "reduced 12-bit IDCT samples are clamped to 0..=4095 before conversion" +)] +fn level_shift_12bit(value: i64) -> u16 { + (value + 2048).clamp(0, 4095) as u16 +} + +/// libjpeg's `DESCALE`: arithmetic right shift that rounds half up. Every +/// stage of `jidctred.c` (and libjpeg-turbo's NEON/SSE2 ports) rounds, so a +/// plain shift biases scaled output low by up to one level per component. fn descale(value: Wrapping, shift: usize) -> Wrapping { - Wrapping(value.0 >> shift) + Wrapping((value + Wrapping(1 << (shift - 1))).0 >> shift) } #[expect( @@ -215,7 +313,7 @@ fn descale(value: Wrapping, shift: usize) -> Wrapping { reason = "reduced IDCT samples are clamped to the u8 output range before conversion" )] fn descale_and_clamp(value: Wrapping, shift: usize) -> u8 { - let shifted = value.0 >> shift; + let shifted = descale(value, shift).0; let level_shifted = shifted.wrapping_add(128); level_shifted.clamp(0, 255) as u8 } @@ -255,4 +353,45 @@ mod tests { assert_eq!(actual2, expected2); } } + + #[test] + fn twelve_bit_reduced_idcts_of_dc_blocks_are_uniform_rounded_samples() { + // DESCALE(dc, 3) + 2048: the DC-only result every reduced size shares. + for (dc, expected) in [ + (4i16, 2049u16), + (-4, 2048), + (12, 2050), + (-5, 2047), + (32767, 4095), + ] { + let mut input = [0i16; 64]; + input[0] = dc; + let mut out4 = [0u16; 16]; + let mut out2 = [0u16; 4]; + idct_islow_12bit_4x4(&input, &mut out4); + idct_islow_12bit_2x2(&input, &mut out2); + assert_eq!(idct_islow_12bit_1x1(&input), expected, "1x1 dc={dc}"); + assert!(out4.iter().all(|&px| px == expected), "4x4 dc={dc}"); + assert!(out2.iter().all(|&px| px == expected), "2x2 dc={dc}"); + } + } + + #[test] + fn reduced_idcts_round_dc_half_up_like_libjpeg_descale() { + // jpeg_idct_1x1 and the DC-only paths of jpeg_idct_{4x4,2x2} compute + // DESCALE(dc, 3) = (dc + 4) >> 3. A plain shift gives 128, 127, 129 for + // the first three inputs. + for (dc, expected) in [(4i16, 129u8), (-4, 128), (12, 130), (-5, 127), (3, 128)] { + let mut input = [0i16; 64]; + input[0] = dc; + let mut out4 = [0u8; 16]; + let mut out2 = [0u8; 4]; + idct_islow_4x4(&input, &mut out4); + idct_islow_2x2(&input, &mut out2); + + assert_eq!(idct_islow_1x1(&input), expected, "1x1 dc={dc}"); + assert!(out4.iter().all(|&px| px == expected), "4x4 dc={dc}"); + assert!(out2.iter().all(|&px| px == expected), "2x2 dc={dc}"); + } + } } diff --git a/crates/j2k-jpeg/src/internal/scratch.rs b/crates/j2k-jpeg/src/internal/scratch.rs index 3d19a17ba..f3ca0fe47 100644 --- a/crates/j2k-jpeg/src/internal/scratch.rs +++ b/crates/j2k-jpeg/src/internal/scratch.rs @@ -19,6 +19,7 @@ use crate::allocation::{ }; use crate::entropy::sequential::{PreparedDecodePlan, StripeBuffer, StripeLayout}; use crate::error::JpegError; +use crate::info::SamplingFactors; use alloc::vec::Vec; use j2k_core::ScratchPool as CoreScratchPool; @@ -79,12 +80,13 @@ struct SequentialScratchLayout { impl SequentialScratchLayout { fn for_plan( plan: &PreparedDecodePlan, + sampling: SamplingFactors, mcus_per_row: u32, block_size: u32, ) -> Result { Ok(Self { - stripe: StripeLayout::for_plan(plan, mcus_per_row, block_size)?, - component_count: plan.sampling.len(), + stripe: StripeLayout::for_sampling(sampling, mcus_per_row, block_size)?, + component_count: sampling.len(), row_width: plan.dimensions.0.div_ceil(8 / block_size.max(1)) as usize, }) } @@ -117,15 +119,18 @@ impl ScratchPool { } /// Grow every internal scratch buffer to the shape required by `plan` - /// and zero the predictor so each decode starts clean. + /// and zero the predictor so each decode starts clean. `sampling` sizes + /// the component planes: the coded factors, or the effective factors of a + /// DCT-scaled decode (see `ScaledSampling`). pub(crate) fn prepare_for( &mut self, plan: &PreparedDecodePlan, + sampling: SamplingFactors, mcus_per_row: u32, block_size: u32, max_bytes: usize, ) -> Result<(), JpegError> { - let layout = SequentialScratchLayout::for_plan(plan, mcus_per_row, block_size)?; + let layout = SequentialScratchLayout::for_plan(plan, sampling, mcus_per_row, block_size)?; let target_bytes = layout.minimum_bytes(self.detached_sink_bytes)?; ensure_request_bytes(target_bytes, max_bytes)?; if self.retained_bytes() > target_bytes diff --git a/crates/j2k-jpeg/tests/decode_into.rs b/crates/j2k-jpeg/tests/decode_into.rs index 46651b8d9..0fdfdaba0 100644 --- a/crates/j2k-jpeg/tests/decode_into.rs +++ b/crates/j2k-jpeg/tests/decode_into.rs @@ -313,8 +313,7 @@ fn assert_rgb16_decode_case(case: &Rgb16DecodeCase) { let scaled_roi = scaled_rect_covering_for_test(case.roi, 2); let scaled_row_bytes = scaled_roi.w as usize * PixelFormat::Rgb16.bytes_per_pixel(); let stride = scaled_row_bytes + 6; - let expected_scaled = - expected_scaled_rgb16_pixels(&case.expected, case.dimensions.0 as usize, case.roi, 2); + let expected_scaled = full_scaled_rgb16_crop(&decoder, case.roi, Downscale::Half); let mut region_scaled = vec![0xaa; stride * scaled_roi.h as usize]; let outcome = decoder .decode_region_scaled_into( @@ -934,7 +933,12 @@ fn decode_region_scaled_into_rgba16_projects_progressive12_color_samples() { let scaled_roi = scaled_rect_covering_for_test(roi, 2); let row_bytes = scaled_roi.w as usize * PixelFormat::Rgba16.bytes_per_pixel(); let stride = row_bytes + 8; - let expected_rgb = expected_scaled_rgb16_pixels(&full, full_width, roi, 2); + assert_eq!( + full.len(), + full_width * dec.info().dimensions.1 as usize * 6, + "{label} reference geometry" + ); + let expected_rgb = full_scaled_rgb16_crop(&dec, roi, Downscale::Half); let expected = rgb16_to_rgba16(&expected_rgb, u16::MAX); let mut buf = vec![0xaau8; stride * scaled_roi.h as usize]; @@ -1566,6 +1570,28 @@ fn jpeg_rect(rect: PixelRect) -> Rect { } } +/// The region of a full-image scaled `Rgb16` decode that a region-scaled +/// decode of `roi` must reproduce. +/// +/// libjpeg-turbo parity of the scaled image itself is covered by +/// `tests/scaled_matrix.rs`; the hand-built 12-bit 4:2:2 and 4:2:0 fixtures +/// here use a Huffman table libjpeg-turbo rejects, so they check that region +/// routes agree with the full-image route. +fn full_scaled_rgb16_crop(decoder: &Decoder<'_>, roi: Rect, scale: Downscale) -> Vec { + let (full, _) = decoder + .decode_request(DecodeRequest::scaled(PixelFormat::Rgb16, scale)) + .expect("full-image scaled Rgb16 decode"); + let width = decoder.info().dimensions.0.div_ceil(scale.denominator()); + crop_rgb16_bytes( + &full, + width as usize, + scaled_rect_covering_for_test(roi, scale.denominator()), + ) +} + +/// Point samples of a full-size decode at the scaled grid. Equal to a DCT +/// scaled decode only for fixtures whose blocks are uniform (DC-only with +/// equal neighbours), which is what the remaining callers use. fn expected_scaled_rgb16_pixels(full: &[u8], full_width: usize, roi: Rect, denom: u32) -> Vec { let scaled = scaled_rect_covering_for_test(roi, denom); let mut expected = Vec::with_capacity(scaled.w as usize * scaled.h as usize * 6); diff --git a/crates/j2k-jpeg/tests/scaled_matrix.rs b/crates/j2k-jpeg/tests/scaled_matrix.rs new file mode 100644 index 000000000..41e762743 --- /dev/null +++ b/crates/j2k-jpeg/tests/scaled_matrix.rs @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! DCT-scaled decodes against the libjpeg-turbo reference matrix. +//! +//! libjpeg-turbo gives each component its own reduced IDCT size (chroma is +//! decoded larger so it needs less upsampling), replicates instead of +//! smoothing at 1/8 and for 2:1 components at most two samples wide, and +//! applies the reduced IDCT to progressive and 12-bit coefficients. `OpenSlide` +//! scale-decodes NDPI/VMS levels with it, so j2k must match it bit for bit. + +use std::panic::{catch_unwind, AssertUnwindSafe}; + +use j2k_jpeg::{ + decode_tiles_region_scaled_into, decode_tiles_scaled_into, DecodeOutcome, DecodeRequest, + Decoder, Downscale, JpegError, PixelFormat, Rect, TileBatchOptions, TileRegionScaledDecodeJob, + TileScaledDecodeJob, +}; +use j2k_test_support::{ + crop_interleaved_bytes, scaled_matrix_cases, scaled_rect_covering, PixelRect, ScaledMatrixCase, + SCALED_MATRIX_DENOMINATORS, +}; + +fn downscale(denominator: u32) -> Downscale { + match denominator { + 1 => Downscale::None, + 2 => Downscale::Half, + 4 => Downscale::Quarter, + 8 => Downscale::Eighth, + _ => unreachable!("matrix denominators are 1, 2, 4, 8"), + } +} + +fn pixel_format(case: &ScaledMatrixCase) -> PixelFormat { + match (case.is_gray(), case.precision > 8) { + (true, false) => PixelFormat::Gray8, + (false, false) => PixelFormat::Rgb8, + (true, true) => PixelFormat::Gray16, + (false, true) => PixelFormat::Rgb16, + } +} + +/// Reference samples as native values (8-bit bytes or 12-bit values). +fn reference_samples(case: &ScaledMatrixCase, denominator: u32) -> Vec { + if case.precision > 8 { + case.reference_u16(denominator) + } else { + case.reference(denominator) + .iter() + .map(|&v| u16::from(v)) + .collect() + } +} + +/// Decoder output bytes as native values (16-bit output is little-endian). +fn output_samples(case: &ScaledMatrixCase, bytes: &[u8]) -> Vec { + if case.precision > 8 { + bytes + .chunks_exact(2) + .map(|pair| u16::from_le_bytes([pair[0], pair[1]])) + .collect() + } else { + bytes.iter().map(|&v| u16::from(v)).collect() + } +} + +/// 12-bit layouts the decoder has never implemented at any scale. Their +/// references stay in the matrix so enabling them is checked the same way. +fn is_unimplemented_12bit_layout(case: &ScaledMatrixCase) -> bool { + case.precision > 8 && matches!(case.layout, "440" | "411" | "410" | "1x4") +} + +/// Decodes `request`, turning a panic into a reported failure so one bad case +/// cannot hide the rest of the matrix. +fn decode(decoder: &Decoder<'_>, request: DecodeRequest) -> Result, String> { + let outcome: Result<(Vec, DecodeOutcome), JpegError> = + match catch_unwind(AssertUnwindSafe(|| decoder.decode_request(request))) { + Ok(outcome) => outcome, + Err(panic) => { + let message = panic + .downcast_ref::() + .map(String::as_str) + .or_else(|| panic.downcast_ref::<&str>().copied()) + .unwrap_or("non-string panic"); + return Err(format!("decode panicked: {message}")); + } + }; + outcome + .map(|(bytes, _)| bytes) + .map_err(|err| format!("decode failed: {err}")) +} + +fn expect_not_implemented( + decoder: &Decoder<'_>, + request: DecodeRequest, + label: &str, + failures: &mut Vec, +) { + match catch_unwind(AssertUnwindSafe(|| decoder.decode_request(request))) { + Ok(Err(JpegError::NotImplemented { .. })) => {} + Ok(Err(err)) => failures.push(format!("{label}: expected NotImplemented, got {err}")), + Ok(Ok(_)) => failures.push(format!( + "{label}: now decodes; remove it from is_unimplemented_12bit_layout" + )), + Err(_) => failures.push(format!("{label}: decode panicked")), + } +} + +fn describe_mismatch(expected: &[u16], actual: &[u16]) -> Option { + if expected.len() != actual.len() { + return Some(format!( + "{} samples, expected {}", + actual.len(), + expected.len() + )); + } + let diffs: Vec = expected + .iter() + .zip(actual) + .map(|(&e, &a)| e.abs_diff(a)) + .filter(|&d| d > 0) + .collect(); + let max = diffs.iter().copied().max()?; + Some(format!( + "{} of {} samples differ, max {max}", + diffs.len(), + expected.len() + )) +} + +fn crop_samples(samples: &[u16], width: u32, channels: usize, rect: PixelRect) -> Vec { + let mut out = Vec::new(); + for y in rect.y..rect.y + rect.h { + let start = (y * width + rect.x) as usize * channels; + out.extend_from_slice(&samples[start..start + rect.w as usize * channels]); + } + out +} + +fn assert_no_failures(failures: &[String]) { + assert!( + failures.is_empty(), + "{} scaled decodes differ from libjpeg-turbo:\n{}", + failures.len(), + failures.join("\n") + ); +} + +#[test] +fn scaled_decodes_match_libjpeg_turbo() { + let mut failures = Vec::new(); + for case in scaled_matrix_cases() { + let decoder = match Decoder::new(case.jpeg) { + Ok(decoder) => decoder, + Err(err) => { + failures.push(format!("{}: parse failed: {err}", case.name)); + continue; + } + }; + for denominator in SCALED_MATRIX_DENOMINATORS { + let request = DecodeRequest::scaled(pixel_format(&case), downscale(denominator)); + let label = format!("{} 1/{denominator}", case.name); + if is_unimplemented_12bit_layout(&case) { + expect_not_implemented(&decoder, request, &label, &mut failures); + continue; + } + match decode(&decoder, request) { + Ok(bytes) => { + let expected = reference_samples(&case, denominator); + if let Some(message) = + describe_mismatch(&expected, &output_samples(&case, &bytes)) + { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: {err}")), + } + } + } + assert_no_failures(&failures); +} + +#[test] +fn scaled_rgba_decodes_match_libjpeg_turbo() { + let mut failures = Vec::new(); + for case in scaled_matrix_cases() + .into_iter() + .filter(|case| !case.is_gray() && case.precision == 8) + { + let decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + for denominator in SCALED_MATRIX_DENOMINATORS { + let request = DecodeRequest::scaled(PixelFormat::Rgba8, downscale(denominator)); + let label = format!("{} rgba 1/{denominator}", case.name); + match decode(&decoder, request) { + Ok(bytes) => { + let rgb: Vec = bytes + .chunks_exact(4) + .flat_map(|px| px[..3].iter().map(|&v| u16::from(v))) + .collect(); + let alpha_ok = bytes.chunks_exact(4).all(|px| px[3] == u8::MAX); + if let Some(message) = + describe_mismatch(&reference_samples(&case, denominator), &rgb) + { + failures.push(format!("{label}: {message}")); + } else if !alpha_ok { + failures.push(format!("{label}: alpha is not opaque")); + } + } + Err(err) => failures.push(format!("{label}: {err}")), + } + } + } + assert_no_failures(&failures); +} + +/// Scaled regions are crops of the scaled image, wherever the region starts. +#[test] +fn scaled_region_decodes_match_libjpeg_turbo_crops() { + let mut failures = Vec::new(); + for case in scaled_matrix_cases() + .into_iter() + .filter(|case| case.width >= 18 || case.height >= 64) + { + let decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + let rois = [ + Rect { + x: 5.min(case.width / 3), + y: 3, + w: case.width - 9.min(case.width / 2), + h: case.height - 6, + }, + Rect { + x: case.width / 2 + 1, + y: case.height / 2 - 1, + w: case.width / 2 - 1, + h: case.height / 2, + }, + ]; + for roi in rois { + for denominator in SCALED_MATRIX_DENOMINATORS { + let request = + DecodeRequest::region_scaled(pixel_format(&case), roi, downscale(denominator)); + let label = format!( + "{} roi {},{} {}x{} 1/{denominator}", + case.name, roi.x, roi.y, roi.w, roi.h + ); + if is_unimplemented_12bit_layout(&case) { + expect_not_implemented(&decoder, request, &label, &mut failures); + continue; + } + let scaled = scaled_rect_covering( + PixelRect { + x: roi.x, + y: roi.y, + w: roi.w, + h: roi.h, + }, + denominator, + ); + let (width, _) = case.scaled_dimensions(denominator); + let expected = crop_samples( + &reference_samples(&case, denominator), + width, + case.channels(), + scaled, + ); + match decode(&decoder, request) { + Ok(bytes) => { + if let Some(message) = + describe_mismatch(&expected, &output_samples(&case, &bytes)) + { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: {err}")), + } + } + } + } + assert_no_failures(&failures); +} + +#[test] +fn crop_helper_matches_interleaved_byte_crop() { + let samples: Vec = (0..60).collect(); + let rect = PixelRect { + x: 1, + y: 1, + w: 2, + h: 2, + }; + let widened: Vec = samples.iter().map(|&v| u16::from(v)).collect(); + let expected: Vec = crop_interleaved_bytes(&samples, 5, 3, rect) + .into_iter() + .map(u16::from) + .collect(); + assert_eq!(crop_samples(&widened, 5, 3, rect), expected); +} + +/// The batch tile API (what `wsi-rs` calls for NDPI/VMS scaled levels) routes +/// through the same scaled geometry as single decodes. +#[test] +fn batch_scaled_tile_decodes_match_libjpeg_turbo() { + let cases: Vec = scaled_matrix_cases() + .into_iter() + .filter(|case| case.precision == 8) + .collect(); + let mut failures = Vec::new(); + for denominator in SCALED_MATRIX_DENOMINATORS { + let mut outputs: Vec> = cases + .iter() + .map(|case| vec![0u8; case.reference(denominator).len() * 3 / case.channels()]) + .collect(); + let mut jobs: Vec> = cases + .iter() + .zip(outputs.iter_mut()) + .map(|(case, out)| TileScaledDecodeJob { + input: case.jpeg, + stride: case.scaled_dimensions(denominator).0 as usize * 3, + out: out.as_mut_slice(), + scale: downscale(denominator), + }) + .collect(); + // Grayscale cases decode to RGB here: replicate their references. + if let Err(err) = + decode_tiles_scaled_into(&mut jobs, PixelFormat::Rgb8, TileBatchOptions::default()) + { + failures.push(format!("1/{denominator} batch failed: {err}")); + } + drop(jobs); + for (case, out) in cases.iter().zip(&outputs) { + let expected = rgb_reference(case, denominator); + let actual: Vec = out.iter().map(|&v| u16::from(v)).collect(); + if let Some(message) = describe_mismatch(&expected, &actual) { + failures.push(format!("{} batch 1/{denominator}: {message}", case.name)); + } + } + } + assert_no_failures(&failures); +} + +#[test] +fn batch_scaled_region_tile_decodes_match_libjpeg_turbo_crops() { + let cases: Vec = scaled_matrix_cases() + .into_iter() + .filter(|case| case.precision == 8 && case.width >= 18) + .collect(); + let mut failures = Vec::new(); + for denominator in SCALED_MATRIX_DENOMINATORS { + let rois: Vec = cases + .iter() + .map(|case| Rect { + x: case.width / 3, + y: case.height / 4, + w: case.width / 2, + h: case.height / 2, + }) + .collect(); + let scaled: Vec = rois + .iter() + .map(|roi| { + scaled_rect_covering( + PixelRect { + x: roi.x, + y: roi.y, + w: roi.w, + h: roi.h, + }, + denominator, + ) + }) + .collect(); + let mut outputs: Vec> = scaled + .iter() + .map(|rect| vec![0u8; rect.w as usize * rect.h as usize * 3]) + .collect(); + let mut jobs: Vec> = cases + .iter() + .zip(&rois) + .zip(&scaled) + .zip(outputs.iter_mut()) + .map(|(((case, &roi), rect), out)| TileRegionScaledDecodeJob { + input: case.jpeg, + out: out.as_mut_slice(), + stride: rect.w as usize * 3, + roi: roi.into(), + scale: downscale(denominator), + }) + .collect(); + if let Err(err) = decode_tiles_region_scaled_into( + &mut jobs, + PixelFormat::Rgb8, + TileBatchOptions::default(), + ) { + failures.push(format!("1/{denominator} batch failed: {err}")); + } + drop(jobs); + for ((case, rect), out) in cases.iter().zip(&scaled).zip(&outputs) { + let (width, _) = case.scaled_dimensions(denominator); + let expected = crop_samples(&rgb_reference(case, denominator), width, 3, *rect); + let actual: Vec = out.iter().map(|&v| u16::from(v)).collect(); + if let Some(message) = describe_mismatch(&expected, &actual) { + failures.push(format!( + "{} batch region 1/{denominator}: {message}", + case.name + )); + } + } + } + assert_no_failures(&failures); +} + +/// 8-bit reference as interleaved RGB (grayscale expanded to R = G = B). +fn rgb_reference(case: &ScaledMatrixCase, denominator: u32) -> Vec { + let samples = reference_samples(case, denominator); + if case.is_gray() { + samples.iter().flat_map(|&v| [v, v, v]).collect() + } else { + samples + } +} + +/// Region edges on and beside MCU boundaries at every scale, where smoothing +/// filters need chroma from outside the decoded window. +fn edge_sweep_rois(width: u32, height: u32) -> Vec { + let xs = [0, 7, 8, 9, 15, 16, 17]; + let ys = [0, 7, 8, 9, 16, 17]; + let mut rois = Vec::new(); + for &x0 in &xs { + for &x1 in &xs { + for &y0 in &ys { + for &y1 in &ys { + let (x1, y1) = (x1 + 8, y1 + 8); + if x0 < x1 && y0 < y1 && x1 <= width && y1 <= height { + rois.push(Rect { + x: x0, + y: y0, + w: x1 - x0, + h: y1 - y0, + }); + } + } + } + } + } + rois +} + +#[test] +fn scaled_region_edge_sweep_matches_libjpeg_turbo_crops() { + let mut failures = Vec::new(); + for case in scaled_matrix_cases() + .into_iter() + .filter(|case| case.width == 45 && !is_unimplemented_12bit_layout(case)) + { + let decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + for denominator in SCALED_MATRIX_DENOMINATORS { + let reference = reference_samples(&case, denominator); + let (width, _) = case.scaled_dimensions(denominator); + for roi in edge_sweep_rois(case.width, case.height) { + let scaled = scaled_rect_covering( + PixelRect { + x: roi.x, + y: roi.y, + w: roi.w, + h: roi.h, + }, + denominator, + ); + let expected = crop_samples(&reference, width, case.channels(), scaled); + let request = + DecodeRequest::region_scaled(pixel_format(&case), roi, downscale(denominator)); + let label = format!( + "{} roi {},{} {}x{} 1/{denominator}", + case.name, roi.x, roi.y, roi.w, roi.h + ); + match decode(&decoder, request) { + Ok(bytes) => { + if let Some(message) = + describe_mismatch(&expected, &output_samples(&case, &bytes)) + { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: {err}")), + } + } + } + } + assert_no_failures(&failures); +} + +/// Grayscale images decoded to RGB or RGBA replicate the gray sample into +/// every channel at every scale, for 8-bit and 12-bit precision. +#[test] +fn scaled_gray_to_color_decodes_match_libjpeg_turbo() { + let mut failures = Vec::new(); + for case in scaled_matrix_cases() + .into_iter() + .filter(ScaledMatrixCase::is_gray) + { + let decoder = Decoder::new(case.jpeg).expect("matrix JPEG parses"); + let formats = if case.precision > 8 { + [(PixelFormat::Rgb16, 3), (PixelFormat::Rgba16, 4)] + } else { + [(PixelFormat::Rgb8, 3), (PixelFormat::Rgba8, 4)] + }; + let full = Rect { + x: 0, + y: 0, + w: case.width, + h: case.height, + }; + let inner = Rect { + x: case.width / 3, + y: case.height / 3, + w: case.width - case.width / 3, + h: case.height - case.height / 3, + }; + for denominator in SCALED_MATRIX_DENOMINATORS { + let gray = reference_samples(&case, denominator); + let (width, _) = case.scaled_dimensions(denominator); + for roi in [full, inner] { + let scaled = scaled_rect_covering( + PixelRect { + x: roi.x, + y: roi.y, + w: roi.w, + h: roi.h, + }, + denominator, + ); + let crop = crop_samples(&gray, width, 1, scaled); + for (fmt, channels) in formats { + let alpha = if case.precision > 8 { u16::MAX } else { 255 }; + let expected: Vec = crop + .iter() + .flat_map(|&v| { + let mut px = vec![v; 3]; + if channels == 4 { + px.push(alpha); + } + px + }) + .collect(); + let request = DecodeRequest::region_scaled(fmt, roi, downscale(denominator)); + let label = format!( + "{} {fmt:?} roi {},{} {}x{} 1/{denominator}", + case.name, roi.x, roi.y, roi.w, roi.h + ); + match decode(&decoder, request) { + Ok(bytes) => { + if let Some(message) = + describe_mismatch(&expected, &output_samples(&case, &bytes)) + { + failures.push(format!("{label}: {message}")); + } + } + Err(err) => failures.push(format!("{label}: {err}")), + } + } + } + } + } + assert_no_failures(&failures); +} diff --git a/crates/j2k-jpeg/tests/wsi_parity.rs b/crates/j2k-jpeg/tests/wsi_parity.rs index 52e93a7d4..689c25cf7 100644 --- a/crates/j2k-jpeg/tests/wsi_parity.rs +++ b/crates/j2k-jpeg/tests/wsi_parity.rs @@ -7,7 +7,9 @@ use j2k_test_support::{ crop_interleaved_bytes, restart_coded_grayscale_jpeg, scaled_rect_covering, PixelRect, JPEG_BASELINE_420_16X16, JPEG_BASELINE_420_16X16_RGB, JPEG_BASELINE_420_RESTART_32X16, JPEG_BASELINE_420_RESTART_32X16_RGB, JPEG_BASELINE_422_16X8, JPEG_BASELINE_422_16X8_RGB, - JPEG_BASELINE_444_8X8, JPEG_BASELINE_444_8X8_RGB, JPEG_GRAYSCALE_8X8, JPEG_GRAYSCALE_8X8_GRAY, + JPEG_BASELINE_444_8X8, JPEG_BASELINE_444_8X8_RGB, JPEG_BASELINE_444_RESTART_67X45, + JPEG_BASELINE_444_RESTART_67X45_EIGHTH_RGB, JPEG_BASELINE_444_RESTART_67X45_HALF_RGB, + JPEG_BASELINE_444_RESTART_67X45_QUARTER_RGB, JPEG_GRAYSCALE_8X8, JPEG_GRAYSCALE_8X8_GRAY, }; const BASELINE_420_JPG: &[u8] = JPEG_BASELINE_420_16X16; @@ -16,6 +18,21 @@ const BASELINE_420_RGB: &[u8] = JPEG_BASELINE_420_16X16_RGB; const GRAYSCALE_8X8_JPG: &[u8] = JPEG_GRAYSCALE_8X8; const GRAYSCALE_8X8_GRAY: &[u8] = JPEG_GRAYSCALE_8X8_GRAY; +/// `djpeg -scale 1/N` references for the NDPI/VMS-shaped 4:4:4 restart fixture. +const BASELINE_444_RESTART_SCALED: [(Downscale, u32, &[u8]); 3] = [ + (Downscale::Half, 2, JPEG_BASELINE_444_RESTART_67X45_HALF_RGB), + ( + Downscale::Quarter, + 4, + JPEG_BASELINE_444_RESTART_67X45_QUARTER_RGB, + ), + ( + Downscale::Eighth, + 8, + JPEG_BASELINE_444_RESTART_67X45_EIGHTH_RGB, + ), +]; + #[test] fn baseline_420_16x16_matches_libjpeg_turbo_bit_exact() { let dec = Decoder::new(BASELINE_420_JPG).expect("fixture must parse"); @@ -122,6 +139,52 @@ fn baseline_422_roi_and_scaled_roi_match_full_route_projections() { } } +#[test] +fn baseline_444_restart_scaled_decode_matches_libjpeg_turbo_reduced_idct() { + let decoder = + Decoder::new(JPEG_BASELINE_444_RESTART_67X45).expect("4:4:4 restart fixture must parse"); + assert_eq!(decoder.info().dimensions, (67, 45)); + + for (factor, denominator, expected) in BASELINE_444_RESTART_SCALED { + let (actual, _) = decoder + .decode_request(DecodeRequest::scaled(PixelFormat::Rgb8, factor)) + .expect("scaled 4:4:4 decode must succeed"); + assert_eq!( + actual, expected, + "1/{denominator} output must match djpeg -scale 1/{denominator}" + ); + } +} + +#[test] +fn baseline_444_restart_scaled_region_matches_libjpeg_turbo_crop() { + let decoder = + Decoder::new(JPEG_BASELINE_444_RESTART_67X45).expect("4:4:4 restart fixture must parse"); + let roi = Rect { + x: 13, + y: 9, + w: 41, + h: 27, + }; + + for (factor, denominator, expected) in BASELINE_444_RESTART_SCALED { + let (region, outcome) = decoder + .decode_request(DecodeRequest::region_scaled(PixelFormat::Rgb8, roi, factor)) + .expect("scaled 4:4:4 ROI decode must succeed"); + let scaled_width = 67u32.div_ceil(denominator) as usize; + assert_eq!( + region, + crop_rgb8( + expected, + scaled_width, + scaled_rect_covering_by(roi, denominator) + ), + "1/{denominator} ROI must match the djpeg -scale 1/{denominator} crop" + ); + assert_eq!(outcome.decoded, roi); + } +} + #[test] fn grayscale_8x8_matches_libjpeg_turbo_bit_exact() { let dec = Decoder::new(GRAYSCALE_8X8_JPG).expect("grayscale fixture must parse"); @@ -174,7 +237,7 @@ fn baseline_420_wsi_shaped_scaled_region_matches_full_decode_crop() { .expect("scaled region decode must succeed") .0; - let scaled_roi = scaled_rect_covering_half(roi); + let scaled_roi = scaled_rect_covering_by(roi, 2); assert_eq!(region, crop_rgb8(&full, 8, scaled_roi)); } @@ -235,8 +298,8 @@ fn crop_gray8(full: &[u8], width: usize, roi: Rect) -> Vec { crop_interleaved_bytes(full, width, 1, pixel_rect(roi)) } -fn scaled_rect_covering_half(roi: Rect) -> Rect { - let scaled = scaled_rect_covering(pixel_rect(roi), 2); +fn scaled_rect_covering_by(roi: Rect, denominator: u32) -> Rect { + let scaled = scaled_rect_covering(pixel_rect(roi), denominator); Rect { x: scaled.x, y: scaled.y, diff --git a/crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45.jpg b/crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45.jpg new file mode 100644 index 0000000000000000000000000000000000000000..88a73109e9527a247e1db044feef903e6d8264d0 GIT binary patch literal 2333 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 literal 0 HcmV?d00001 diff --git a/crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45_quarter.rgb b/crates/j2k-test-support/fixtures/conformance/baseline_444_restart_67x45_quarter.rgb new file mode 100644 index 0000000000000000000000000000000000000000..4d552de32d61bce1aec0c87932de965ea5a374e7 GIT binary patch literal 612 zcmYj|-A@t$0Kn^S=((4++7fCt@!&isA8i4_g^Tp4m3&3S$7wNxyH#v(gcWc!J|vW> z=#h>ubrA>?A~_Op6Cd21_ufN)1-aT7+wbA`@cZ?87kd9F+^=O-oqM`HCEEFp)w0Ba zjNI?Q!9EY@y<)fh?X3R4@AWRW55n+*bh z;GKxml8f93XGAA-qF~zrxd}c%avf`ucIK+5EFLZnz3qrj8p1D!Hw|nE;<6S+yas&R nfZQ6>fs5!+!vPtH>rimiObs*XEA|=ymZoxt;u3xN)hX*QF61*G literal 0 HcmV?d00001 diff --git a/crates/j2k-test-support/fixtures/scaled_matrix/cases.tsv b/crates/j2k-test-support/fixtures/scaled_matrix/cases.tsv new file mode 100644 index 000000000..f8f004427 --- /dev/null +++ b/crates/j2k-test-support/fixtures/scaled_matrix/cases.tsv @@ -0,0 +1,210 @@ +# Generated by corpus/conformance/scaled_matrix.py with libjpeg-turbo version 3.1.4.1 (build 20260327) +# name layout coding precision width height jpeg scale1 scale2 scale4 scale8 +gray_3x3_baseline_8bit gray baseline 8 3 3 15:196 0:9 9:4 13:1 14:1 +gray_3x3_restart_8bit gray restart 8 3 3 226:202 211:9 220:4 224:1 225:1 +gray_3x3_progressive_8bit gray progressive 8 3 3 443:319 428:9 437:4 441:1 442:1 +gray_4x4_baseline_8bit gray baseline 8 4 4 784:198 762:16 778:4 782:1 783:1 +gray_4x4_restart_8bit gray restart 8 4 4 1004:204 982:16 998:4 1002:1 1003:1 +gray_4x4_progressive_8bit gray progressive 8 4 4 1230:321 1208:16 1224:4 1228:1 1229:1 +gray_9x9_baseline_8bit gray baseline 8 9 9 1670:239 1551:81 1632:25 1657:9 1666:4 +gray_9x9_restart_8bit gray restart 8 9 9 2028:251 1909:81 1990:25 2015:9 2024:4 +gray_9x9_progressive_8bit gray progressive 8 9 9 2398:367 2279:81 2360:25 2385:9 2394:4 +gray_18x14_baseline_8bit gray baseline 8 18 14 3106:348 2765:252 3017:63 3080:20 3100:6 +gray_18x14_restart_8bit gray restart 8 18 14 3795:365 3454:252 3706:63 3769:20 3789:6 +gray_18x14_progressive_8bit gray progressive 8 18 14 4501:471 4160:252 4412:63 4475:20 4495:6 +gray_45x31_baseline_8bit gray baseline 8 45 31 6855:911 4972:1395 6367:368 6735:96 6831:24 +gray_45x31_restart_8bit gray restart 8 45 31 9649:977 7766:1395 9161:368 9529:96 9625:24 +gray_45x31_progressive_8bit gray progressive 8 45 31 12509:1014 10626:1395 12021:368 12389:96 12485:24 +gray_67x45_baseline_8bit gray baseline 8 67 45 17578:1784 13523:3015 16538:782 17320:204 17524:54 +gray_67x45_restart_8bit gray restart 8 67 45 23417:1919 19362:3015 22377:782 23159:204 23363:54 +gray_67x45_progressive_8bit gray progressive 8 67 45 29391:1839 25336:3015 28351:782 29133:204 29337:54 +444_3x3_baseline_8bit 444 baseline 8 3 3 31275:380 31230:27 31257:12 31269:3 31272:3 +444_3x3_restart_8bit 444 restart 8 3 3 31700:386 31655:27 31682:12 31694:3 31697:3 +444_3x3_progressive_8bit 444 progressive 8 3 3 32131:625 32086:27 32113:12 32125:3 32128:3 +444_4x4_baseline_8bit 444 baseline 8 4 4 32822:379 32756:48 32804:12 32816:3 32819:3 +444_4x4_restart_8bit 444 restart 8 4 4 33267:385 33201:48 33249:12 33261:3 33264:3 +444_4x4_progressive_8bit 444 progressive 8 4 4 33718:621 33652:48 33700:12 33712:3 33715:3 +444_9x9_baseline_8bit 444 baseline 8 9 9 34696:490 34339:243 34582:75 34657:27 34684:12 +444_9x9_restart_8bit 444 restart 8 9 9 35543:503 35186:243 35429:75 35504:27 35531:12 +444_9x9_progressive_8bit 444 progressive 8 9 9 36403:749 36046:243 36289:75 36364:27 36391:12 +444_18x14_baseline_8bit 444 baseline 8 18 14 38175:764 37152:756 37908:189 38097:60 38157:18 +444_18x14_restart_8bit 444 restart 8 18 14 39962:781 38939:756 39695:189 39884:60 39944:18 +444_18x14_progressive_8bit 444 progressive 8 18 14 41766:1011 40743:756 41499:189 41688:60 41748:18 +444_45x31_baseline_8bit 444 baseline 8 45 31 48426:2207 42777:4185 46962:1104 48066:288 48354:72 +444_45x31_restart_8bit 444 restart 8 45 31 56282:2273 50633:4185 54818:1104 55922:288 56210:72 +444_45x31_progressive_8bit 444 progressive 8 45 31 64204:2439 58555:4185 62740:1104 63844:288 64132:72 +444_67x45_baseline_8bit 444 baseline 8 67 45 78808:4436 66643:9045 75688:2346 78034:612 78646:162 +444_67x45_restart_8bit 444 restart 8 67 45 95409:4577 83244:9045 92289:2346 94635:612 95247:162 +444_67x45_progressive_8bit 444 progressive 8 67 45 112151:4603 99986:9045 109031:2346 111377:612 111989:162 +422_3x3_baseline_8bit 422 baseline 8 3 3 116799:363 116754:27 116781:12 116793:3 116796:3 +422_3x3_restart_8bit 422 restart 8 3 3 117207:369 117162:27 117189:12 117201:3 117204:3 +422_3x3_progressive_8bit 422 progressive 8 3 3 117621:600 117576:27 117603:12 117615:3 117618:3 +422_4x4_baseline_8bit 422 baseline 8 4 4 118287:369 118221:48 118269:12 118281:3 118284:3 +422_4x4_restart_8bit 422 restart 8 4 4 118722:375 118656:48 118704:12 118716:3 118719:3 +422_4x4_progressive_8bit 422 progressive 8 4 4 119163:610 119097:48 119145:12 119157:3 119160:3 +422_9x9_baseline_8bit 422 baseline 8 9 9 120130:457 119773:243 120016:75 120091:27 120118:12 +422_9x9_restart_8bit 422 restart 8 9 9 120944:469 120587:243 120830:75 120905:27 120932:12 +422_9x9_progressive_8bit 422 progressive 8 9 9 121770:710 121413:243 121656:75 121731:27 121758:12 +422_18x14_baseline_8bit 422 baseline 8 18 14 123503:636 122480:756 123236:189 123425:60 123485:18 +422_18x14_restart_8bit 422 restart 8 18 14 125162:648 124139:756 124895:189 125084:60 125144:18 +422_18x14_progressive_8bit 422 progressive 8 18 14 126833:889 125810:756 126566:189 126755:60 126815:18 +422_45x31_baseline_8bit 422 baseline 8 45 31 133371:1572 127722:4185 131907:1104 133011:288 133299:72 +422_45x31_restart_8bit 422 restart 8 45 31 140592:1610 134943:4185 139128:1104 140232:288 140520:72 +422_45x31_progressive_8bit 422 progressive 8 45 31 147851:1812 142202:4185 146387:1104 147491:288 147779:72 +422_67x45_baseline_8bit 422 baseline 8 67 45 161828:3126 149663:9045 158708:2346 161054:612 161666:162 +422_67x45_restart_8bit 422 restart 8 67 45 177119:3208 164954:9045 173999:2346 176345:612 176957:162 +422_67x45_progressive_8bit 422 progressive 8 67 45 192492:3319 180327:9045 189372:2346 191718:612 192330:162 +440_3x3_baseline_8bit 440 baseline 8 3 3 195856:371 195811:27 195838:12 195850:3 195853:3 +440_3x3_restart_8bit 440 restart 8 3 3 196272:377 196227:27 196254:12 196266:3 196269:3 +440_3x3_progressive_8bit 440 progressive 8 3 3 196694:613 196649:27 196676:12 196688:3 196691:3 +440_4x4_baseline_8bit 440 baseline 8 4 4 197373:368 197307:48 197355:12 197367:3 197370:3 +440_4x4_restart_8bit 440 restart 8 4 4 197807:374 197741:48 197789:12 197801:3 197804:3 +440_4x4_progressive_8bit 440 progressive 8 4 4 198247:605 198181:48 198229:12 198241:3 198244:3 +440_9x9_baseline_8bit 440 baseline 8 9 9 199209:448 198852:243 199095:75 199170:27 199197:12 +440_9x9_restart_8bit 440 restart 8 9 9 200014:455 199657:243 199900:75 199975:27 200002:12 +440_9x9_progressive_8bit 440 progressive 8 9 9 200826:707 200469:243 200712:75 200787:27 200814:12 +440_18x14_baseline_8bit 440 baseline 8 18 14 202556:611 201533:756 202289:189 202478:60 202538:18 +440_18x14_restart_8bit 440 restart 8 18 14 204190:622 203167:756 203923:189 204112:60 204172:18 +440_18x14_progressive_8bit 440 progressive 8 18 14 205835:869 204812:756 205568:189 205757:60 205817:18 +440_45x31_baseline_8bit 440 baseline 8 45 31 212353:1583 206704:4185 210889:1104 211993:288 212281:72 +440_45x31_restart_8bit 440 restart 8 45 31 219585:1614 213936:4185 218121:1104 219225:288 219513:72 +440_45x31_progressive_8bit 440 progressive 8 45 31 226848:1819 221199:4185 225384:1104 226488:288 226776:72 +440_67x45_baseline_8bit 440 baseline 8 67 45 240832:3079 228667:9045 237712:2346 240058:612 240670:162 +440_67x45_restart_8bit 440 restart 8 67 45 256076:3148 243911:9045 252956:2346 255302:612 255914:162 +440_67x45_progressive_8bit 440 progressive 8 67 45 271389:3252 259224:9045 268269:2346 270615:612 271227:162 +420_3x3_baseline_8bit 420 baseline 8 3 3 274686:360 274641:27 274668:12 274680:3 274683:3 +420_3x3_restart_8bit 420 restart 8 3 3 275091:366 275046:27 275073:12 275085:3 275088:3 +420_3x3_progressive_8bit 420 progressive 8 3 3 275502:599 275457:27 275484:12 275496:3 275499:3 +420_4x4_baseline_8bit 420 baseline 8 4 4 276167:363 276101:48 276149:12 276161:3 276164:3 +420_4x4_restart_8bit 420 restart 8 4 4 276596:369 276530:48 276578:12 276590:3 276593:3 +420_4x4_progressive_8bit 420 progressive 8 4 4 277031:600 276965:48 277013:12 277025:3 277028:3 +420_9x9_baseline_8bit 420 baseline 8 9 9 277988:421 277631:243 277874:75 277949:27 277976:12 +420_9x9_restart_8bit 420 restart 8 9 9 278766:427 278409:243 278652:75 278727:27 278754:12 +420_9x9_progressive_8bit 420 progressive 8 9 9 279550:669 279193:243 279436:75 279511:27 279538:12 +420_18x14_baseline_8bit 420 baseline 8 18 14 281242:550 280219:756 280975:189 281164:60 281224:18 +420_18x14_restart_8bit 420 restart 8 18 14 282815:559 281792:756 282548:189 282737:60 282797:18 +420_18x14_progressive_8bit 420 progressive 8 18 14 284397:796 283374:756 284130:189 284319:60 284379:18 +420_45x31_baseline_8bit 420 baseline 8 45 31 290842:1281 285193:4185 289378:1104 290482:288 290770:72 +420_45x31_restart_8bit 420 restart 8 45 31 297772:1299 292123:4185 296308:1104 297412:288 297700:72 +420_45x31_progressive_8bit 420 progressive 8 45 31 304720:1491 299071:4185 303256:1104 304360:288 304648:72 +420_67x45_baseline_8bit 420 baseline 8 67 45 318376:2439 306211:9045 315256:2346 317602:612 318214:162 +420_67x45_restart_8bit 420 restart 8 67 45 332980:2482 320815:9045 329860:2346 332206:612 332818:162 +420_67x45_progressive_8bit 420 progressive 8 67 45 347627:2608 335462:9045 344507:2346 346853:612 347465:162 +411_3x3_baseline_8bit 411 baseline 8 3 3 350280:352 350235:27 350262:12 350274:3 350277:3 +411_3x3_restart_8bit 411 restart 8 3 3 350677:358 350632:27 350659:12 350671:3 350674:3 +411_3x3_progressive_8bit 411 progressive 8 3 3 351080:589 351035:27 351062:12 351074:3 351077:3 +411_4x4_baseline_8bit 411 baseline 8 4 4 351735:365 351669:48 351717:12 351729:3 351732:3 +411_4x4_restart_8bit 411 restart 8 4 4 352166:371 352100:48 352148:12 352160:3 352163:3 +411_4x4_progressive_8bit 411 progressive 8 4 4 352603:600 352537:48 352585:12 352597:3 352600:3 +411_9x9_baseline_8bit 411 baseline 8 9 9 353560:462 353203:243 353446:75 353521:27 353548:12 +411_9x9_restart_8bit 411 restart 8 9 9 354379:471 354022:243 354265:75 354340:27 354367:12 +411_9x9_progressive_8bit 411 progressive 8 9 9 355207:715 354850:243 355093:75 355168:27 355195:12 +411_18x14_baseline_8bit 411 baseline 8 18 14 356945:574 355922:756 356678:189 356867:60 356927:18 +411_18x14_restart_8bit 411 restart 8 18 14 358542:582 357519:756 358275:189 358464:60 358524:18 +411_18x14_progressive_8bit 411 progressive 8 18 14 360147:818 359124:756 359880:189 360069:60 360129:18 +411_45x31_baseline_8bit 411 baseline 8 45 31 366614:1373 360965:4185 365150:1104 366254:288 366542:72 +411_45x31_restart_8bit 411 restart 8 45 31 373636:1393 367987:4185 372172:1104 373276:288 373564:72 +411_45x31_progressive_8bit 411 progressive 8 45 31 380678:1596 375029:4185 379214:1104 380318:288 380606:72 +411_67x45_baseline_8bit 411 baseline 8 67 45 394439:2488 382274:9045 391319:2346 393665:612 394277:162 +411_67x45_restart_8bit 411 restart 8 67 45 409092:2535 396927:9045 405972:2346 408318:612 408930:162 +411_67x45_progressive_8bit 411 progressive 8 67 45 423792:2676 411627:9045 420672:2346 423018:612 423630:162 +410_3x3_baseline_8bit 410 baseline 8 3 3 426513:356 426468:27 426495:12 426507:3 426510:3 +410_3x3_restart_8bit 410 restart 8 3 3 426914:362 426869:27 426896:12 426908:3 426911:3 +410_3x3_progressive_8bit 410 progressive 8 3 3 427321:593 427276:27 427303:12 427315:3 427318:3 +410_4x4_baseline_8bit 410 baseline 8 4 4 427980:365 427914:48 427962:12 427974:3 427977:3 +410_4x4_restart_8bit 410 restart 8 4 4 428411:371 428345:48 428393:12 428405:3 428408:3 +410_4x4_progressive_8bit 410 progressive 8 4 4 428848:602 428782:48 428830:12 428842:3 428845:3 +410_9x9_baseline_8bit 410 baseline 8 9 9 429807:422 429450:243 429693:75 429768:27 429795:12 +410_9x9_restart_8bit 410 restart 8 9 9 430586:428 430229:243 430472:75 430547:27 430574:12 +410_9x9_progressive_8bit 410 progressive 8 9 9 431371:671 431014:243 431257:75 431332:27 431359:12 +410_18x14_baseline_8bit 410 baseline 8 18 14 433065:524 432042:756 432798:189 432987:60 433047:18 +410_18x14_restart_8bit 410 restart 8 18 14 434612:530 433589:756 434345:189 434534:60 434594:18 +410_18x14_progressive_8bit 410 progressive 8 18 14 436165:760 435142:756 435898:189 436087:60 436147:18 +410_45x31_baseline_8bit 410 baseline 8 45 31 442574:1208 436925:4185 441110:1104 442214:288 442502:72 +410_45x31_restart_8bit 410 restart 8 45 31 449431:1223 443782:4185 447967:1104 449071:288 449359:72 +410_45x31_progressive_8bit 410 progressive 8 45 31 456303:1426 450654:4185 454839:1104 455943:288 456231:72 +410_67x45_baseline_8bit 410 baseline 8 67 45 469894:2204 457729:9045 466774:2346 469120:612 469732:162 +410_67x45_restart_8bit 410 restart 8 67 45 484263:2223 472098:9045 481143:2346 483489:612 484101:162 +410_67x45_progressive_8bit 410 progressive 8 67 45 498651:2377 486486:9045 495531:2346 497877:612 498489:162 +1x4_3x3_baseline_8bit 1x4 baseline 8 3 3 501073:345 501028:27 501055:12 501067:3 501070:3 +1x4_3x3_restart_8bit 1x4 restart 8 3 3 501463:351 501418:27 501445:12 501457:3 501460:3 +1x4_3x3_progressive_8bit 1x4 progressive 8 3 3 501859:583 501814:27 501841:12 501853:3 501856:3 +1x4_4x4_baseline_8bit 1x4 baseline 8 4 4 502508:346 502442:48 502490:12 502502:3 502505:3 +1x4_4x4_restart_8bit 1x4 restart 8 4 4 502920:352 502854:48 502902:12 502914:3 502917:3 +1x4_4x4_progressive_8bit 1x4 progressive 8 4 4 503338:580 503272:48 503320:12 503332:3 503335:3 +1x4_9x9_baseline_8bit 1x4 baseline 8 9 9 504275:441 503918:243 504161:75 504236:27 504263:12 +1x4_9x9_restart_8bit 1x4 restart 8 9 9 505073:449 504716:243 504959:75 505034:27 505061:12 +1x4_9x9_progressive_8bit 1x4 progressive 8 9 9 505879:689 505522:243 505765:75 505840:27 505867:12 +1x4_18x14_baseline_8bit 1x4 baseline 8 18 14 507591:593 506568:756 507324:189 507513:60 507573:18 +1x4_18x14_restart_8bit 1x4 restart 8 18 14 509207:604 508184:756 508940:189 509129:60 509189:18 +1x4_18x14_progressive_8bit 1x4 progressive 8 18 14 510834:840 509811:756 510567:189 510756:60 510816:18 +1x4_45x31_baseline_8bit 1x4 baseline 8 45 31 517323:1275 511674:4185 515859:1104 516963:288 517251:72 +1x4_45x31_restart_8bit 1x4 restart 8 45 31 524247:1299 518598:4185 522783:1104 523887:288 524175:72 +1x4_45x31_progressive_8bit 1x4 progressive 8 45 31 531195:1490 525546:4185 529731:1104 530835:288 531123:72 +1x4_67x45_baseline_8bit 1x4 baseline 8 67 45 544850:2597 532685:9045 541730:2346 544076:612 544688:162 +1x4_67x45_restart_8bit 1x4 restart 8 67 45 559612:2644 547447:9045 556492:2346 558838:612 559450:162 +1x4_67x45_progressive_8bit 1x4 progressive 8 67 45 574421:2757 562256:9045 571301:2346 573647:612 574259:162 +gray_4x4_extended_12bit gray extended 12 4 4 577222:234 577178:32 577210:8 577218:2 577220:2 +gray_4x4_progressive_12bit gray progressive 12 4 4 577500:357 577456:32 577488:8 577496:2 577498:2 +gray_9x9_extended_12bit gray extended 12 9 9 578095:281 577857:162 578019:50 578069:18 578087:8 +gray_9x9_progressive_12bit gray progressive 12 9 9 578614:410 578376:162 578538:50 578588:18 578606:8 +gray_45x31_extended_12bit gray extended 12 45 31 582790:1709 579024:2790 581814:736 582550:192 582742:48 +gray_45x31_progressive_12bit gray progressive 12 45 31 588265:1811 584499:2790 587289:736 588025:192 588217:48 +gray_4x64_extended_12bit gray extended 12 4 64 590764:706 590076:512 590588:128 590716:32 590748:16 +gray_4x64_progressive_12bit gray progressive 12 4 64 592158:827 591470:512 591982:128 592110:32 592142:16 +444_4x4_extended_12bit 444 extended 12 4 4 593117:483 592985:96 593081:24 593105:6 593111:6 +444_4x4_progressive_12bit 444 progressive 12 4 4 593732:730 593600:96 593696:24 593720:6 593726:6 +444_9x9_extended_12bit 444 extended 12 9 9 595176:615 594462:486 594948:150 595098:54 595152:24 +444_9x9_progressive_12bit 444 progressive 12 9 9 596505:868 595791:486 596277:150 596427:54 596481:24 +444_45x31_extended_12bit 444 extended 12 45 31 608671:4549 597373:8370 605743:2208 607951:576 608527:144 +444_45x31_progressive_12bit 444 progressive 12 45 31 624518:4798 613220:8370 621590:2208 623798:576 624374:144 +444_4x64_extended_12bit 444 extended 12 4 64 631380:1777 629316:1536 630852:384 631236:96 631332:48 +444_4x64_progressive_12bit 444 progressive 12 4 64 635221:2039 633157:1536 634693:384 635077:96 635173:48 +422_4x4_extended_12bit 422 extended 12 4 4 637392:476 637260:96 637356:24 637380:6 637386:6 +422_4x4_progressive_12bit 422 progressive 12 4 4 638000:722 637868:96 637964:24 637988:6 637994:6 +422_9x9_extended_12bit 422 extended 12 9 9 639436:570 638722:486 639208:150 639358:54 639412:24 +422_9x9_progressive_12bit 422 progressive 12 9 9 640720:822 640006:486 640492:150 640642:54 640696:24 +422_45x31_extended_12bit 422 extended 12 45 31 652840:3128 641542:8370 649912:2208 652120:576 652696:144 +422_45x31_progressive_12bit 422 progressive 12 45 31 667266:3374 655968:8370 664338:2208 666546:576 667122:144 +422_4x64_extended_12bit 422 extended 12 4 64 672704:1729 670640:1536 672176:384 672560:96 672656:48 +422_4x64_progressive_12bit 422 progressive 12 4 64 676497:1993 674433:1536 675969:384 676353:96 676449:48 +440_4x4_extended_12bit 440 extended 12 4 4 678622:478 678490:96 678586:24 678610:6 678616:6 +440_4x4_progressive_12bit 440 progressive 12 4 4 679232:719 679100:96 679196:24 679220:6 679226:6 +440_9x9_extended_12bit 440 extended 12 9 9 680665:566 679951:486 680437:150 680587:54 680641:24 +440_9x9_progressive_12bit 440 progressive 12 9 9 681945:820 681231:486 681717:150 681867:54 681921:24 +440_45x31_extended_12bit 440 extended 12 45 31 694063:3143 682765:8370 691135:2208 693343:576 693919:144 +440_45x31_progressive_12bit 440 progressive 12 45 31 708504:3392 697206:8370 705576:2208 707784:576 708360:144 +440_4x64_extended_12bit 440 extended 12 4 64 713960:1278 711896:1536 713432:384 713816:96 713912:48 +440_4x64_progressive_12bit 440 progressive 12 4 64 717302:1532 715238:1536 716774:384 717158:96 717254:48 +420_4x4_extended_12bit 420 extended 12 4 4 718966:460 718834:96 718930:24 718954:6 718960:6 +420_4x4_progressive_12bit 420 progressive 12 4 4 719558:698 719426:96 719522:24 719546:6 719552:6 +420_9x9_extended_12bit 420 extended 12 9 9 720970:527 720256:486 720742:150 720892:54 720946:24 +420_9x9_progressive_12bit 420 progressive 12 9 9 722211:780 721497:486 721983:150 722133:54 722187:24 +420_45x31_extended_12bit 420 extended 12 45 31 734289:2466 722991:8370 731361:2208 733569:576 734145:144 +420_45x31_progressive_12bit 420 progressive 12 45 31 748053:2706 736755:8370 745125:2208 747333:576 747909:144 +420_4x64_extended_12bit 420 extended 12 4 64 752823:1258 750759:1536 752295:384 752679:96 752775:48 +420_4x64_progressive_12bit 420 progressive 12 4 64 756145:1515 754081:1536 755617:384 756001:96 756097:48 +411_4x4_extended_12bit 411 extended 12 4 4 757792:471 757660:96 757756:24 757780:6 757786:6 +411_4x4_progressive_12bit 411 progressive 12 4 4 758395:708 758263:96 758359:24 758383:6 758389:6 +411_9x9_extended_12bit 411 extended 12 9 9 759817:575 759103:486 759589:150 759739:54 759793:24 +411_9x9_progressive_12bit 411 progressive 12 9 9 761106:826 760392:486 760878:150 761028:54 761082:24 +411_45x31_extended_12bit 411 extended 12 45 31 773230:2687 761932:8370 770302:2208 772510:576 773086:144 +411_45x31_progressive_12bit 411 progressive 12 45 31 787215:2923 775917:8370 784287:2208 786495:576 787071:144 +411_4x64_extended_12bit 411 extended 12 4 64 792202:1701 790138:1536 791674:384 792058:96 792154:48 +411_4x64_progressive_12bit 411 progressive 12 4 64 795967:1954 793903:1536 795439:384 795823:96 795919:48 +410_4x4_extended_12bit 410 extended 12 4 4 798053:463 797921:96 798017:24 798041:6 798047:6 +410_4x4_progressive_12bit 410 progressive 12 4 4 798648:697 798516:96 798612:24 798636:6 798642:6 +410_9x9_extended_12bit 410 extended 12 9 9 800059:531 799345:486 799831:150 799981:54 800035:24 +410_9x9_progressive_12bit 410 progressive 12 9 9 801304:781 800590:486 801076:150 801226:54 801280:24 +410_45x31_extended_12bit 410 extended 12 45 31 813383:2261 802085:8370 810455:2208 812663:576 813239:144 +410_45x31_progressive_12bit 410 progressive 12 45 31 826942:2502 815644:8370 824014:2208 826222:576 826798:144 +410_4x64_extended_12bit 410 extended 12 4 64 831508:1254 829444:1536 830980:384 831364:96 831460:48 +410_4x64_progressive_12bit 410 progressive 12 4 64 834826:1501 832762:1536 834298:384 834682:96 834778:48 +1x4_4x4_extended_12bit 1x4 extended 12 4 4 836459:394 836327:96 836423:24 836447:6 836453:6 +1x4_4x4_progressive_12bit 1x4 progressive 12 4 4 836985:625 836853:96 836949:24 836973:6 836979:6 +1x4_9x9_extended_12bit 1x4 extended 12 9 9 838324:560 837610:486 838096:150 838246:54 838300:24 +1x4_9x9_progressive_12bit 1x4 progressive 12 9 9 839598:808 838884:486 839370:150 839520:54 839574:24 +1x4_45x31_extended_12bit 1x4 extended 12 45 31 851704:2445 840406:8370 848776:2208 850984:576 851560:144 +1x4_45x31_progressive_12bit 1x4 progressive 12 45 31 865447:2690 854149:8370 862519:2208 864727:576 865303:144 +1x4_4x64_extended_12bit 1x4 extended 12 4 64 870201:1035 868137:1536 869673:384 870057:96 870153:48 +1x4_4x64_progressive_12bit 1x4 progressive 12 4 64 873300:1295 871236:1536 872772:384 873156:96 873252:48 diff --git a/crates/j2k-test-support/fixtures/scaled_matrix/data.bin b/crates/j2k-test-support/fixtures/scaled_matrix/data.bin new file mode 100644 index 0000000000000000000000000000000000000000..05a9f51dda6c88462181c8c799c09230ddcb4722 GIT binary patch literal 874595 zcmeFa1yq~a+BO`VLIn!c4X78|(o!hJ-JK9DgainXK#U;4lK_DPNFZ1U?(Qzdt)&#J zQZMz+)LrsFFw>dNdCz;^dB63awZ8K$0&8`xviHuj_r7gk&%N(!s&d>X?-|4?J^u=X zot??M%DV%SFf%eW0`c*IKzzUth_?vR2MO@=FaH7`LEu+NR7glrP)JNfL|AmK*xI$? zV&dZK)^C(pw_b9+xVXe72}vnw85xF3Y+AEWU5 zpAf$is*$(6=i4Pfe1ZZ$wE|=S*j`yB-QU{^YxAc(=v!*t)c~~K0t^aB!%rVRS#jy zY_|S|MN&rCrW`foyGp^d@fR-tk#qY8RrtSchAS%ZuXgVzl`virM8MSjB)fnu6%Z2q zQz!ClE3|)834T7IpWE^A%Yr23l<oJpyLW1PgXJ95h#RhdQqGO1mR#31B(r_@^kdC_S_vjVPawLBuR^HXt>uF z&yFii3a6I%1O#KV99`Yri_E|loQCH3bhvM>O<+SzHoW2AtaWQZYkt?dO@Leb>$ZsU zEjylr5+IPEAiwyZJMp{TZ4{Q1l#-E^SM?^Qwa)!mS8Y&d{#mWcz=thsIAzaor%Ept zRUVr0k2>m_5m&v%3?+%4Gs|Nbh=tOO5# zt|bU0!uP*e9{nr1 z76A$WkX8_1tMJr{2i_(D0)n`oHwGjG_!p^Dzc&S(^<=cl<|mTxn81F?0sfj_V9ig> z`2nLQC@CQ&t8|i3+)xp0OT?ojuad#>&q#ij~vQ-`&&JZB4SXvNW|u25}m3^r70;>V6w@b5jj- z7j!rR*OOGV!+{_e#&#r4NF;z81(X#WCi&Ru? z{KME;?D#sL$hK(@NPKID5rkfnuHsHh%MauZS)^tEn{D%Y(8k|w^A->g4gMr7ARz1! z7F`2~!G1t&`Bsh|KmNRIoh4%iI2t9BokY>yA^H+>!<53~o9R2i_}g zLWx(Ut6IIs`9Gh+-V)tE{Om@SkFdS5{tj!U=iUhx@}AeHVy~V`@wYnmZ5we{<&ErH zhaJ*RW<=Ze(gugnN}=DYI?k3saFWs=3wK?cIBPxeWvuR^>96{zVuoM2y^JAozgPC& zfG2BELaHHY+gW#%I$t}BrLD!cCrpm_ys%ZrG)|gYuEU=)6?w4xa>Ei3r7{);V5`e}F;VR5PyhJED5<@ttauO{qd_vC^2l=Xb7M%f8(! zVM)8vrOli1!g(tbl}6s|8gq&rQqioPu%tRY9J$8>%{K66Yd1JxEU+?%O}C!wue_yy z=k6)qT;4wu-hSTvu_u}n0S>kS%I6T3^|4cI!Q?(!MV<0rU+WWg2&?Wgm$lPPQMtlf z@GxDK;Qx0_?n>D3uS~9>un-`_ze6n`zT{xyl;hpsPbvT~^KY7>O8s=uKa85o z;TtWyRU`2!cs^~~2LItP4A2MpW%JE1_){Rj$1e$z71$_;mylAjg%|yZ27o{UG9tR| z#AAtr)_(NniQ6$lt|t?@F0RKGKgwJXa?q;0Fn?+J9JFIOvf%&ufW-%R1Ks7Z{tPUX zEI6!;>pf#;W!3h*Sv374pXlbggDg5zrm>~xZTu9tEE0KN`;WOwhyw#}UqLbekm`q{ z0WA*l=TC!P z&^zpF@^YUAI@D>uGff)^Lhs)3hKAT%8o31_0!gvGoXiwzCOMdZ35ZV4=XSL8bu>0q z))eH!3(H%^Zauq4cLtl8yE!6!2>EfWtfXc}6p@4=L@?NS<+UyC{q2oaMI?4cQ3Jc@ z-rWbb5Ia9Just+Bn8IM6O`!)y5(0cl;neip>gtOeB01&QF7zHKOt<4<`Wd#}jDd~kx83Px&5DP~edvg;Af)Nyxme4^ZMMR*{Xku7m zDm%aBTuWnNaXgEeo*Pr!Gce}t=!`Nl)Um|DP(g9MNi=F?v>ytEM^oZ6N}8Hm>nn4z z*jWrOPF;OR{j4+D%uG+y&fdirR}+`Qh+>8X5HPm55Go@(zoD(Fp)jAD>cLJcu4ea* zpSQ8GG_ck*2Sd|>qvB~55u`wWq$fHsB#N0?T{qZNRFF+dW~F6E)He-|OhQaubx!G9 zV!aVqN^g94I3Wy&@<5^^=^1$~E%gN@NvVwFc=zJ+%CqIOmxGK9)YP4kg!1(HZ4#*%YG0?}v}S0p|# zj+tFq*I1UvPDeB2;&LJ@n%gf-%Vi@&W^G9i8ESC+D;BoSYU2sNCYVc=jY*MhxU(1$}emv%VKjF$qA5{^!ze* zd;i?II$b3VU41(!9TQBA%EV#4T`VC8LMS~sn^Rm-n$Al1iHl*f@fB@@6KAJ~OpdAR znFf0xF)?LCQh>KN)YZ+?KP;;a&M9YdYnVv)ESOz2vx=GXr0VX#spIOdrfyJlNmy8j zf4HwJ#K8_p3@a}g=t^>Fgw-P8Hg=Vvy-CCGieA%M#|^a2ZCqn;!K9#cG~6Ak>+V4e zO{j6|i;5^>p)k>gmL>GOq`M1O?xj7rb?np`Gps8LA5(%sd3icG+dFz=!m0Gc^HEb7 z;pjBoEQAs_msND($v;<~Ns2imla-Xd;eOXH`YbQ%fH>rK>Ya({3K*Ozi~o$n1haPDDmW)D)dNdPdXIF%^vq@CkCacd=9l zy9E%UX=#ye-NDq#(6DH)=n0>Z=3lQRbI+yDXsTLZU48v=@!l>@4yML-PH+T)OwYJ8 z7#T{jWa3lwVbaQqE+ZsDqdJ#h6ic{PC9Np}^kmx^78&j41h&)GF>`T8g+wPZG6Ks|)8TH$X(fk{-Ge>X)1H#D&ICASnOVDe zBzr>Lz^3LV`qq|6JU*cyIn5?VAEIv%p;F{jNSnCYF=F^9P0iP6*q z7CEk_!pAO%)gRTLPm4_8lw>jXCwsZT@7KaD!M@QM8R--}fnLzu-Bgj5QZZN*;cDfI zjpTAD!2#jSvd)%@ELvtqHyUPT9XBDppmhS_sAuUFok61zyz%k5 z%?*VaaY^Of(>CV15KLHld@$NOh*8>F1~kZO>YujPFm?*2(;~1iuZXm&Y7U*8np1yn zUjMYUcQ`#P$j8+$mRrkBO(rplyDs#d(FUV~XyHCi?nDlwuz(hdW0nn%4XKzoV5rdn zFniB%b{&}#ZA;G@T(V>@FYRzbM|fjPYqAuumP2qgiQ z$}J%Up~E7$dF_^wn7pJBCuDGJRs+I@Ml1{cHy=`WgB1Tbr2Zo!AuJ%Wa!6HJiE@O1 zw_`s}u`7pEkPv{}i^wTSN$bkUpCIem?zQ_7qX4h6He7LULgv{oNMCX;CE^ywtqxxD zl?$D{zkYfxmSVP1Pvu%T-@~_a*n+{*rvAV2r&(f!I zTX(}^#r5@zk*9v?NHd=kOOE2;Q?P{Fel(o)pddrBBD<+_0NnG{7rrp-f`kTzEKu(u*Y?68?w_taO)v3Pfsd_hwsqVU`*e7aJbNwt1 zVqSVZ%dRqUm*KiLu;XaIyEXI68^-$`b2}=`kF{lNQ(-Ll*~VD*3l_Xn+3|5uQ4PE+ zBwzi7^B!pJAam_j@k8GI@l0HAta#xbPqU@wa_jW@stVN5osD;nM9b`Xt@FUyHASs| zT5WJnANf35%lbC;i5ELC;!5q$SUZ!u_Vpy71ujmi zY=O*OH#u=mA8dbQ-mY3o<8knWyxbJHH~zZ+2JV}&jqf(7Ri;@yEJs_7T!SAcg*jE?TziL)YemsBDvV@-#QZVuoPQAbHHv7g^0%NP3;Sliku z^0UGAa`P=l5BD3eo35VTLy^pV^;#r%-CTE|>VgYf&EfpUOt-U6vC{8?UK}fPsl6b& zwsf<&%EY-eK4;UL!|cM=`r_jGZYzuCv?e33w25~?Ys~1O&bp4Ro~`WNM@XUyb$c2k zY-K(r3x`8rpiX(6v~QJERIor58Bj)x4}QPpymuFOtf%byhoqZ^zXCwqYNWdw>8?h) ztC8+%q`MmFu1325nUU_+<<~KP;$Q$ECL|&#EGht?WdEB`_a9*Hl6O~XohuyP37vBE z+qvVE(mef?i)g-b=x|H?^(komPNz+WPk)VI^Jd6%{*88aWnOiUYxNWLon!^06tVY4 zT_)CCAJ2{E%_i2q6M%rf5WnayV$1v5Uz>c|%V?`NZQP~AoAZ2Iq2OZXosj{Sz^LAl z`i8%#!MqK0nn$7)4fjD^=IkfiP1mJg<$*keulG#}1oZE5?mEp|nEj?Txz_n`DW4~p zPw&L9VnWXg4~dC!8#dn&2YO$czV4+}xL~<|CUxv)(=Wg1M{~JON{hi->$Q28@3c*( z`8^)W%P;2Nn%JY5VB7gYGT^aZocpCWOx~3WKO)!eDOgf|qNu&P`fA6s$yYp36rMMO z)X&jRf8zbVxx{ETEcx*9H63@@-^+&!w(w@PD-M@TzZs8wwpY9@Tj?%U)?1`+@RPzw3>if}LWwM@=+XYL1TgQ?S4{&YKY#2ON|4XM_yz4&+vT z?AokZ?X26ew8$RQ<}EDdfLIWfBQ ze$nW+8R!Lne&R-*?8vw1U7PxH%`gsTrvJv?l|y*bu0{%-5z!L?88 zU#&T;bF;ORAgQyf5xMUs1$coy>*U3JtC6}8*`08C8p7Tj#8hd%Hn3;U%O%)u-kgrz zKZ%inwb=KsqvUAbLcPT5qWMvnf}U7d_lK;xI!9!zu$_1u*UQ@!R9pJ% z-AUdhydTuiu!5M&@!p3>n%tNA^y$V7>6guvI^S`>{aTK%C7fM!JwEa-%fPZ{eA;fk zFLBgArLMbiZe*-l+C;%cj`_=jG~Fk?=x%63=!FIMN2{^&Dk{8+3a_HVtEliQD!hsc z|Hq)hEAP?&6)G&mznly5$9wd3rY=74N1B2)pSHnN%bP8=lbEH+g)=KjdAkANSl};t zc>;ob{6dl&K~l2vdw;yo7UI8o^=Qdf`Dc(VFZ_$%)g)Qg&>fo6M9Y$g`0~q_JW0gd6SDOY!|&g9+}xqkKgG7MdNGb6fqO4lk2yEeaa%$1w?8_fnguo>Mx`FUIMTWa^;4}Hs z&-k}rm9AJR-{5THfkNUg8L_<^_ab?%gH+;h&QfLhA6q3heqLP2oqv+;3?L zwq!W|$J+%UQ(>Q=2x6wuaP4<9LP@;v0a~fpJZS+op>BW4T*hf9&Sj_D=7*RkUv3|q zG2C596tG-VkzxTd5sJ|Pj}9~lQlATdaTY3@A9#=<*{JKXZ}9DDg+NgB&c5igZ}<_O zOAQOE^ZX^$$hr1Ge%=VS#E3Y=-a~J5u)fOvK4mp^~3=wy&+M98vB<$jZ3TRN} zK0%-K=e>$NETTx4Q`KDm@x-&NI}(yB25N<925Z1ePjrlEripin>- z=wlD(P_T)%b+9v%7~GXWqlU3@-X2g-LP!jwF}EZ?qbija6Xh00OXb$qw+?o+w&WM( z2QstsYq>qcGq)yY?mWAh0=6|Y_OgR`24saX=y4@M1RqaV7d$bzkdc;O+>x8Yip2*7 zM<=nl6|J4aopq&^Ob(Dg5n10ncwupFX7bL1n+{+LZ(~C{M;eAmi5-ay!(#mruE+pN zOnhSTa6x8TGA%qRFd{TLyQJo9Ur%*aZc$c7Dyq1&wXJ{p{LFNXHw+31w$RZv3w1-_ z!p_p7B7$i??(Q%QDmX5&mRrEdDqzHsf*mQ;w7iPC&d%1x+LF8sbV_DkLvi=`!nL9C zUU%0tV-pJlS93deY;goDDmELBLwG=4&^Qu@o>`FJk(xva_acxetc<+!mbRXn^0NHM zR7QGELT&x%x$`sQ-Glj#7LFER9TTuil21@!ca#=%frgm!>5!?#-W)$2#AxdJJv6_ zke16~lu{x{1P}ixT6}UrWpia$eL)TjnGna!NvW?Np6DMR?rfr#n;EMa0xyVN(gQ+b zh~;>HPj|SjgNG+QDlsj)l|he=2lqon#xc3AWwqs5$r<$cNCYrmRYBMJ!GY42>WVzq z(vzn&5VlUv=<1+gj90vyjg=V$io%B##bq&K)1!$vKVxh_OiFfcRdrEuURr9RI~7Qj zO04M`80qb4t1H9iW#^r?JZ)*=nC2HmB5?d5U?($k2+}7pjKWMRrW1ohyijm#Tx4=a zaams}H$4rX7!wyu%rCEL8JzBJtq-fr%i|Cg)eVdTJv|6PwP>V=i?gY*tsBudno8?T ziKS8^P;d{dM?@mMxW2NmFe@pUP7Q-HIJtGDBcolNIn~X%1rCMPC)7P`om>%hAp{=; z+R5I?90v2nhGa34=#-QYw7-uLDk6qnlwDq*k(Zj8OtXuLXJw@q_YI8JbTpLbp|ZF+ zwPsodW)LPZn1En-f~_q~>>Svv^EjB#Fg_T}dUEMj<-9#@h%+7`s=e3>jv~+buwc-8TUD38CW_DnAKQyV5Nh3!@ z`T3w+Z7_*-wv;S(X>)b3cP{)?CLu1EG?RI&zq@m>CFO9hS3eD=sc-I<>yJfyk|EZ1 z=6V(`P-J{GHJ+XoK|rC6+)+fTWjVextMP(=J3%W)KM!YHT}3On86Mf2%OUr)R%Ox_ zwT)w3kOVJ|hcm>|!Nkzk0p~}Iqcui{2jN`2p`QM}MdX-{^y%W5B&vRni>*gWB)j)= zQ{S^O!t`aokbNyPmG`{NT|IrOiLNeAo>m41W?*+OJgJNx7ZdJ-@pE?v`-k{)`f36g zmFTgdG9(;TOA3ff9BfVXD(RVl9m7U8g=dwST03WY`+0Z@Qbeqp6& z2QD>H$9sYULy_oIN^r}Nl{44R8|FYVwb#-xFn4hEObaI`ghmDgc*1nu{IEfBo|T2| zBQ=dRX=Z1r6o}bK=QOu9ZsB}UM6651#Vitg@^-8}!V6A=+L`NW>gid#MG%7GDJcXZ z+S|^>(F5fhMRmqTA_=7h6uPTL5yb)7HPvuG^IA9_?P<+A(G#1MOt@<2fh=@)cC>U- z)7CdaxcFcKE5ky9Fun+Ph>I0EI4XhF>sN+tf>rtY5p@H*LMlTZl5=qEsiN^i?VQ>v zQst}j4%q=vcPFfwu9mvCjfrDd`ZMQi zSh2L^{PZ|kG92P%g9p+@7u~!OZd5x1ecco4)>ckoXiN+x4UhD4HFtJ&MdO3%37k&1 z61U1^4wjjx40fAJxW~E3@J?s=)5iDBMwAuAPtQZWIUe?=R%U0^H7pTOWI%8U$q(<3 zfZJKSSoudpC6)SN&}ORT2IYoP+113j!mF1uiHUi1XD^4O?#eFP!Rmev7wKl_=%%Nl za>mlm$-^r-EI0~F@^S^+=y-VJNU;nizBAm}(Af2OW_V?9m&edd#biQaQI`^?nL$-X zrN%!YKlF2fkgRkKG*9Ron>a;a2xM$B+7ITUX=er_1cfCqGYf0_N+Ydv9h?|ZVU>OJ zMY&nztmM3;;^6}q6Xx#JotuB?l?X94*3nizX{7Jz>E=tyi@^AJ+S}V$xx4y>kQv#T ze!Ug&0I0olD2_c==RMePH(R@#!h-H9uO*V3raFqNDK5^|Rt{QcRJAOuT*0X9&>%dD z0CsdT(MF&GBVuUT$)#nf9F0>tX6ohkrIhOx4UE|Fb6s&5hx|6eb839{&08HVw!S8s znx~YtjICUP{X)ZoV|?JQc50R`9=?Q#_#{>a*0m)O?HtB2H()2tW*3sn%9{;)?OGy| zFt=|p%W9w9Eg@SO8K`S0pVqQ)hWh!3X9GgzY;JFD>*^K|5*}B`WQ4Yuvm8!^*o1X+ zlU%D}Lp)JU#B|!;L3qrZ|10j&1f|{D!q`e%<@gx`OJ_H)v@kr{8v%7RHZ_EKV}i-_ zbOse~pQY%b>uVh8Lu|N#yq16j=Q89WRu!cDjNysiI@&#gHB3)W<=6>rBMWdOF*FcE z^nzI0oUw&K{V*X3>GULOhJ~kH_L-QdnB2-H&P)SsIB6f!l^FqzAT*|2D!#|MqiSfU zu6jyIMav8UgX4${A75t&3p*VfDAW%hotP6(4>yjokJHJ7;;XV6eQ6ho3!3F)t(Hep z=7Mue(sN@6o5w1&b&SzHm7B(HuQd-yO}K_G?^9`0{09`DX7R{kOEVRTl?zs zn3;La7w4vmNzUeuK7ni|$=4knom$CBi@`=^RQ9x#<cEZzee5y2`fBL|@|tdhQ( zrpN+Lo+UCY&=qWI2`4aU;^XN>MdJ=Qf`@~Sp=%H=I>^rniVvQ4yV(R-Tpv($ui@ z#!-ndD?9J7l;oBO9~iZ)t|cNn9ys%j^t3zK>#G_#_>x2X9L*pB(ahvjf}IPos6M-@ zC@MOyBlljti;4OvW7oiFKX+?$7=g-;3UdQ{CFOAm)BuOnqVDdxEL*LUYBt`)Af&Ca zqh}B+F~q|k9bb~tltshg6SB*iyRim(M|G{ecR|@sF#{CUg56S$aNUZjh)HA}XUeky6#2n`uErS$ZZ!!$~=rA=KtNX1+Vl z(Hu)hBN+MQu;eZdwH4`Q42}wM_oH!xiOm({uE;5pjue`P|kX zOA;a_v^1qF*ToY@ic85Z%|lv8c(X~Bj3Gyee*lG%mC~>6;}D6+j?Pc|H>Y?ig7kk+ z@!Yn2t?MsuzJc;1f}(5q0pR5rfYtHy2?9U-Lcf(M0g^l=f%+sHWkDiRa!Mz3ZKan{ zD0w}7${^wg{-+Hxc=zn`I>;r>!Q_l;nv@wrCz2ow)P&^PiJxZxc!|lVvqo1z0svf*=bao=7!7D=VeOS$b zd*{QgZs%*dSYm!<;`XGaO?L~><;FTrT4(la=ista->7)l=iAW> zpY-4Mm@);{!Q$lhy=o}>V)L#4%~ZgfhIV(`G2IuYvLzBbYPUB*L85CF6E=z5ULL)4 zaMZ2Kx@%A^@GFC;z7yhcs7xm0uA+H}9_Nihck?}y?VU-f^zTGn&2JyRe7aEAxBc0d z#L_!eJN!?NLGIDA+-ffgYXnR_p=Ft#lrmg=CD``CMn=Kz?#VP|O(6*u+vI2uLK|B@A;`RH`x<`q(dB&^iy|8~Mz|XsG0(P5 zr&`4BwJ1px3On%XOaCeTxn!B;eA7pQ(Fartqf`tFC@1%v`lPz|F)UtF?*{Y8!5-*M7Tw=mw(WG1v8>kBot(t_{o^4YJZ8%TXSFuJ6CemGGB*o7j43Xs7ed(|Ek9U^Nz>$%9H)y-n zT3?Qym|}>@+JD-rS*G02+K4w&0qxJGpogQF2!yq?v!Yz7N!^|k5=CGcPUYLeJrKtu zK{`@ip~FvwyY^dexf|Cq=bP_zcMKL`x~<3)6(8f(CalMYNMGaKJ zbK%+};jcFm1^E?%J;?m>oA%K`dX%xmLNkdX$UUvE@17u2kg49pr74n9(--GWVLPFb z+?^YCslLCv#irHdZcgXx=Aw(gnts{^le+!Xa)V|VxMb^ox5P7~ElPVKZx6idF2ufn z^=v_NwAwc;id%W-S54j2NB$Z~2bHp9B~s8^%FquJ_js?1tc{rXSb6M;0u_&2*f()* z@RHIyq4O6a)ZF*%z9kIKlpl3EWEEQr#T*yR9q%0McRsn@c4GcMWBu;CdiSEm9$!$H zDn5QLdCYXE#j}Rc=94aiM(6}Eni_rPiO*jp3UA^{pPn7h(8_MH+9w&F>UlhQXk<9k z>@=7l|9(x{x3k;D_b)O0CCiYOop-V%9rw{U4IbIyu^}MfMw9GmiuEou?Oy{h8thRMt5q zX`{X1czBFK$PeSTD=A;N(%jyA?DWXZt)KLK`z~*JHPk#TK%sDM&dZ9sQM7C*a+~!k zp5!-ZIIXMH8%au{o~$=ij@3d7e=0OX;K2-#0?QX?X8G=<`Vq@ppELJs^>iLDre0@W zAG{EMnjy+M`O0_8>p;v%Q#(?-p{U2>70zCTvsdBl zRXBSU&R&JHSK;hcIQze=wEb5&`>#cj0XSO}C{pmhhqM3TF4x}#wSmiA?r%HHw}e)4 zk0fl8eU*LOCQ09c2W*u&yd4_zj!}rRy_3xfD6WlL?y}p{l{Y|Ui z@aB}BU@|*9pD5|bI1Z?&z4Z(GwEfee>dlT3y!l^mtCL$!K%{n=A6+Q#Z^Rtofm~mF zELRepw+j+5gXhEg|vyfX8xGV1oHN4!g=*u2Q**C{79gqg0}67#_0CjBu;2kx)a zsP&b1c{VEZi7A!dMJNcQ5FUNn^f>rT{eZpM;TIQqSLVAje~ml&&^gF^gr$n#DlhZ( zF(v%Viw|#jGt*zfRIhxHG99!#eHEY7FuLJrmvi;n&_(wA25sK#=KToYo~S*UXP@$y zB`!TNIQ+Wa;>e9eijXV#`6u37wy#Fpw}{Sm%1Qkvx;)T;Z?qN<6s-;1R4Y&4<&e_v|2n8^*q)WYmK z+c)2aO@w$p_#V~EyX-Xs1~BqD6Ow|Z!@)R}HK#t(HFj*;*Mp%I0Mk0*mApaMVDH{J z@%pRG#b?cY^6#Z1cr#_@UGEaTg9nF43O1*T%{`R%-ZL+|M(W@_UH8PVQNV)CCWqM; z*BG(Qdhalo9xiMcn`n7ynoEDE$Jof^6N>-Xo|lnZkXT;wfmek!~q>bh&+`$-K0#O3}^0?j6$ zz}JdClX#b&|0^Usns?dzoj74f#KZYv>GLNP4#rt8dA(1c`>ta;y5%Y;2eGC>n|Gx! zOfxZ2!`7>no+{TGGocsf;D{`liy=du>MnsSQy=kW8b6ckP1$3o;r?%P4rHFjXWiat zROxiRsBo*IE-S{VjNci{n=SWvY?_)>r*gEPb2u}(`S_mcw5?)ky;MEQ3Cob-nx;oU z%{@QDI&o|*Io3+oFvFx&mW(;(aJqjp{~qhD8_okOaItCX^ZUC_CGJWk!G~j1-}--# zy~KXRTev@0YT4Bx!@j?Fa`tmuvDWvAuQO!*qHAw>m$>8VX!SUoje6W~4gIfuc_3ZO zN4(2~MYWHi+|aQTrSol0#i_66_iyziPe>V`a|X31dpZW~pyYU0+eh=RY_CKGs65PH zdqH)xgQfgBNe`;Tu~&8@0oxasc3JJ2{IxepPZ+dkUtT|NrY+zX?F~MDTSB|G)xJKT zpxvGcgJgibK8Up$c5;`6f7E5ed>RCX z90$bdlIiWmSh(J-d_3y@xpOq_t^-S?2!jm^3`Leio#2 z`>RH=q45hXHBR`%lAPoPPwBdd*}ZFv8rqng-7>p*GwOd2 zH}B%jM&7RFBv&r^y&9!$cv*zkjw2#7k+xgBjqdNg>)dpy%cbRXF^0exQ5h-TSM*^FTJy9e`zcc(w7UaKfh}i?8-T!0)1$ zqyX*6da-V37!N@0bmAb^ZEm9|H_nTOmb?&^q$>ubh2iiLtx>XA>dWD}46y3*I zmaMn18I=yj84m3j^)IX)q~P|^gx0R{7Wig}sP*kQ#+!Td6mxZCUe*2F^_RW(rHDQc z))aqm@*EdCzjnQtm`{jBtRg}5lb&b-bOUd`^0QCP#Z3Yzi6(jZJyXw8EoC?444(Df zn4Jqo42bXDwqs*IZ$bMhGT4#Z_fEkgG6V-V6lvStM&+)>Z<5^Ob8kjz>EX>pPyeZC z7*LCEHA#FmNqjX)d^JgYHA#FmNqjX)d^JgYHA#FmNqjX)d^JgYHA#FmNqjX)d^Jh@ zzwlSCRDAd=s{Yp`aUcmCs07USBj+2$r-wPL;Bfk}>BGfRRbNah)B+W_C3|2vTfB~S zv#2lcZ1y#cyU#AVXAWq_oy(jIs8BI@XNCnpdD-P0^X2jeKkoK}R_Z})1OcR)^0IP2 zRfM>R6i@fuqQBkBI_8NGUV~yuYMi5J&KEb#0@>Vp)0Xt+--ND z6c%K@pED}*isf?_LA`Qf?Hg%DpFPtZ!|^- z*(oJG)jp)RxB82wk%H#==YCrXKd1?d@!j)T!t+446G}{Xw20$Aq{)cBae9BXa*T{; zJ|5z)tzx^Bptm^FyJs(obuieyPJZ8{Z@l0-?b=JMc+a|~@>-fgkTa3gn9#j2g^JJ*ChK^#Zn1Zrpo^9xq^9Hb; zr`zFN$41y8nUJSpg?B(}`7b_v@wD@(w55jqO*xVdOS{9V-F#%1kF`n^5A?|?8KW&R zut$Fv==|(5JI3A>b_{@T@DHxL->XBwU;b7gqv@vt8HxM(h0TvQKgVdE*e73lZ`VcS zmTh?1qwmMR_T82C)d~-KiV(gJyQ^&eKajoyLtSP(F+nk`qt>$TiH@oCUxNe z#l<72mXM~i63aB02dZiJ>wUfEkv~Phgx2vTRvw=&^X@6c$BmP2VDc~-tNUei0Q6Ev z?0u!t2|jO1rBzBR9ev`i-K~X7QM)3+krZm9u%#^T9wY>A?-d7{sF-W@9?iIe!z zZw@l4CK(<3^^aEAe+go#OW$XR3$DviUn4c=w$)*aS9`Uve0tuLtj&&lRUQbLwR5w* zjBaM{#yB|nqnT8p(@VuXBT2;vxPvq6JG7@rImF{PFiQK3K8aOaJN0;swN*5`b_6Qb zLfvqp_XR=h8Hz$W;nJIS+1?B4{C#W39lD+qv_kqBs5F%8RGx@;VN z+)w$jvnw0h^m`wm^v60Gfq+62@Y=|9f%7qf`5P36q4%q#lKdtiCRJYdMAHSVYRBr+ zHbF8EPFfFtS@(sM7IMF2K{Gm+NHoaVZW^=au-ML5o?pZ;OFfi(5&j}= zRC<2if-;Z8?Z0n_FBdgQRwh|o(l6wJs2lP=44c+YCq&WI#RD_*W0)}9$MR2S9=TgF zx?TooKdYD9Vv|r=`($g?<@I8|=BIXbFG#;N&cahHwiKnGhGjg$)y|Oi1uA^p_)>kp z(4ichu}RH(38QuPhq>V;TQ(izn^O?qEdV~_GCVF4_z-V)hF+#z!e=A+_zJ2**DR(< z{B-n=gA&x3!wxZRYLs>7=r#OBI#rt(daS|YV$OX5rv*heB@En+Kj@en>>#IuwTw`x zxwu*G9bEkv^`R~3K~(YCdLBq2DsiYWzb#f$=b)XW?UsNiHxjoE#2gv12v4sBc%q;{E{<#ttLm#Byr%<#0)gu zQ=^ctq%^IsI0lZgMuMBbm&?9AfSRvQ(9@E?2Q?r3$|@aA`>+(PR&#j`yXGrnaC^Lj ztYxG0rz1m>EiwF$SvJahLw9p*V_HXl5tX=lOwc4@`;Icu;iQu@H4D@#$L4B{H@s`J zkN3_d+^wG*c__;mV$tq@FX&f1x`yfyJRmZc5I6X=(ZfkUqECcd45K%w|NAar0R+>0 z0sx=1pwJp2p*7O$#MepxuRj36wB!oGv;a^Hh+mRVKysOK^8bKldITi%hu!?a0wlCd z>$OJ`pu-mYnLiP@`y~X>0|^Rm)Uzc6y0;e4N`6Uzuv!~LdZ^WK9k$F-o&8@ps_hF{ zw~s=PBz^vdnv&hfCk5J-I^)UrcH6pbcdk^m9ld!Go9xnb9AtEA-wuiO332mXJ&Q9sfcR=4YKXc=$l@9C8gpdtTNaRfzvsD*?8K(WggMmPqv`=9v2 zU4G*W-zf<&jQzwK2K46_1PMrP)FuB`D;)U;;z$0Qw00h%r}W z2CyuEK@gH%R!~ts{^c$cS_B3qCuBgfUJU5+w`j?i{x&Un(C*)9$ydZ{g&|O4nLuqT zU_Sl~>6agk4th3ycCx@hO-NX3g^&9u+hRPvqvXFQYflQ+f?t2BdP{q2EPRJZy{Is#vlRsLn9V00 z!iV4dr4qdRsM277u$J(KVU@)O-nG@u`^^(9vv&V`Ht(Ofht)0o8=m5iCcn9i|5^Y3 z8<(-nTfL$_zqt$}h5i-u_Q#RuxBXu>^MWhZ5Qxfz`15QlmaX8n>qZP5AQ^b{W#w!U^@YH0el5eb@KNoSow#K zUlt@Or-c9gQ2@wdLRj@0GW(ZkpgF)_4bVmXrMV<%#Xg7ve*nr;vV=;Nw@tVFnDKAk zVx=l5;4W4^e|83rdP*Sp%J;0e3o`D(K<(N)@R!%G+y=gD^Gb(5n*;s@ut)x-Hkx{CyIDFA9}%w8I&Kul4h;@xJnX<$=EPgc#WFsF=P% zWRYcM-|4B|Z8tA||1SIic-r@%W_EBSwak&zVqDj?Yhrx-;7uNH?YEDjyl(rk6nCr@=7LWACTcR*Xwh;s=)OVtJvAN=G~I6zORhiD)sH7%zMXAWp6G+1WSQodsopF|fjD3= zIM-;VW@5C?w0o?MwWl*gmTI=2Y((s;h(4)l<#FZ^%ocWD4H)WDmzGObwS7Z(sFSNI z)yH*&f;3e($S?x_6hcQqy7R$Uo#k)5%DV%SFf%eW0xfR~ARHhN4>%Wr1b_nv@Vml( z4G6NRkPvWC5)%QKvDb>NT`MjoF1~L4Mu~OnCD)6KOKkcl>A?U09j*Yn`M-G7O~9l6 zMT9`2{L5zf;0kZNp!lD%2)Ig+0FZXPQBG1yMpj-GOiXQ^Tb9{>BvS*}(pD&x6@icq zB*-tc?vF9}mi1T?D73LjR*s;gd`ef(&Yqp#)I2v22<=baw#PD>*|5I%a*_SvK-Iek zw@)mrnedNr>r8r;gK$nrECdJccerKK!){Dc-Fx@Vp@W>McF*H9*{hgJw4hi|b!mQG z{0lTlRm&9OJ5uDK!^r|Hus&8!|pBjpr4~v*e@h4 z73_z~-!4R_Z^xYE5|0j!H&08v`W{~}e(b)ALf4x-ZHf23zDCiB>Cvm|w5m?hzhM>s zvpR|JFXIk>U!ArrtJ7aJa;0(&FvkB%pZ-Yz^zYUxW8RG3)tXsF2n~j>aDH|4n>N?< zL&B!aLwD`NP}=8!q|#%Z(*ZL*BD>C?wiy4sEqX_P($x(GYV)r)Aep?m8Oh1iZOm2O zTGcJ---6G-p<8^*uIj%!Am9Y|512(w{LHCD6@BDv!PIh0w{7|L++SikkkB#@`l%nm zlMw%8w94iulJA!Bi2ag4H7P;ypOlhMKxsL~6qJxXscQ$+iek^st@K<8PMKQIV+(bc zf-H0$9hILrn?F17pyWzPf7|jG1498gfzX;iT;dAI24H}l62Lha^fN}oC#egPkX3@; z{XyyuM7dZ!**a6_pu6GjnqMB3{P5Sm1-r@Gz%bjFkJEoyR3LVhP_ixhGj5l#$QETA z%TijU)ax5Vir;Jix^4L_M*ed_mP1|%-9Oeq0=FO=7b~K3))Og${seURuY0!~^-AD> zOcMxvXXx)gJqO7tmkkrnKLaevXVFieKs=sss(D|ebIUj!Y>1vxB~0y%o!^}}f6bQa zl{XPqao(9A^3rTOu}d&6INf}g$u9Ys_18~q#`ogjJRYWVG_j>FV(tAs{$ zN_#0ao!XXGUR!*jr)ze;erWuB?bX()y?K@YAA4^Z)z;pw{Zc4(cQ3TG6nA%b*Wm8% zF2OB?U`eoqBqV_lC4_|F?k+`Y)Vo$)R+SUh+UwbCKkq(gyyu)R`yGRP143r<&z$of z|Lb?(*Ck#DlCDlMK-RkgRGsOUeF=(j1NzArsBKP2WlaW>Bi}TR(ul0#!L5OgffY7p zok_V_gHp+@FVYB6McCUwmHiRtf-7nyg3VLvU9$4?i{MoVD6ED&PQu;oZ=4*c?di^i zp&uo+^5v=Jhsgm$OpEj!F>t{Efgqe>bdEhR(;J*zmyDR3riFf`luP(&*MK<55X&gffcS_iL}drP$~7^lCCmLa72Mt$MHvk( zZhc$yBDq93G(tSqNhMB8H`zzP{Yj&}qg(I-4J(k$FFDb)W#E0~_EIf)60URx<| zH7@A&GN)Q*3r7VgMtPc+!0zoo|@E^=d5k0prE5= zW)>XkP+I6ihS}knKH z3=U4&%TWn9PdIhsw3ODFn^vAtJNL(Cp9`1dd|NOfWaimWk4h7>q zC8f3R^o?^jt)x9Ofn}Uxv{M59u{8rlk>tW^QH!#bH4v*lYcMAn?!vu0n<{tvKKOa3 zz15Qcl{z;1R^#$Q%5{sBZmn8mw9Qj#+P<|j1$GC}p*|5v_#-#I!{K-EX0}g+CS`#K zH|9c@wfFdZ_i_|KLJ|fTS%F(fkRUYMH{bN8_u6FkU8fO&(?!4Zk*%-XT24*z{1B*t zXqMuOB_31P9Tstl`+5(YGC9GWk&j`V0P@!+S4=obISoX zrMDs;Bz0S(6qD!h@`vXu>DKxgsuEPK-n)bQ_Q9VX28xWUg3OX;kXjSW)b8vo4B}D7 zK;OchSsA|!ejwHH9&iY9B(k0E{7l4OW*GX!w(XRr@aaXqvezo*QD|V(&Tkd9iQS*hl(70gR?In^wgsmGz6br%isZV`MV8el zcscvk_TE8!++LCPSaxxUs(YMjh@)2U%tMvwOjgjOW$tk+bw zpOfwxDYg|Wo|g4=a`@*1VCawUkde$k?$tc_mi*-Xktc`Y4N{d*`B}6vPVZ*$&731E zr`~aevKujSHWgUO`2&K{dJMn;-tylIJRrG7TbyBK--uAv7^%SzCyFTtvqO>r;2IIf z$H2(+(Ye^J;3Y2rB0al2%JAeTshlW4Xv<66D?A>158le(qp54XUYK!KE1;Vrv=A)* zy#|8h@#Rg%cK-I~ZhBCDbM2$hdo|+tV`G(**IeEw{d&h4c>m)UhS802h&XxXkH*rF z$L{wZr@ce?%bj;&;s&9=)T^$#x4g^pv!mVpY#_6rHW|;Q+owS|@a+2bg5(Re$xz$K z-(|9--Ig19drC$iqqbo061uf|RC}~)Ajr-{OMn}xrhV|*7E^)W zZuR!D-~4THLV>x|<6%$TCy7?b{cT*&iJ+mi!w1|rU}DkJXr$(imEk%;!pQ7wq@2x)xpEu^8_DI>Qvf{;>y8bo%vI9`;){A2U%C`pngG?{sh58Hjm#)@X z>UI`ioTyX3*Y`tiRy=lZI|h)fRS~7vzLHa>USo zb{Xt|d@asPWg`DmsN_GXYdUKDyX%i(V@$J+xzPZ!^4s7o!~^M*R*%^GonPzt2|Lx( zB6r%z|J;KArM4E`{_1lL&jtgnKyC3O0euUNo37Cp z0wVSbBe-62?UR{&@%yVU#jd4c&mwLWy*{0?|2o1aVt-7T${Ahai)Y6JVe|z9Y)`{U9=sD>1Ay-?$<;cAYry@VjZ^4gm6`k~d z_4HbJ&B}#i^Jn)u+BlI{-+lOYDKpE+rpLl`a+{Q z6`v#Fa>UplTo}peXf1YIfT)eytbobnHT@nn%a=noMv;c&sh&enul9B?7Hh)yN$ALU z_%tJE9v(h1o0;dEF=diQlPK)Fo;^CNP@r3M*SmTl7jd@?Hafj;dSS)^jUIsF1E- zFzX0gNPrDa=hkCU)ILP#!&Zn`vz{0wds$u{b&2x zVNX+5$2ijTuOA1uf1b$^st8dSvQ}dcX&VaajR;%Ksu_2=oA$J1m_hA3Xs&Imfd2Ks z(c#IMzQDDr3{qGa(Lb9=vjVCobzI7!$%AP!kjWmevW%)B6l4t7%owhvHowAe;-^Sd zMjc@QL>?RWV7s(4Bqr!rN7&Mn{S2e&u%*G`g@NL&j%h(!ok(4-JSADJpYADbraE>_ zg?!p@Qp=Fl=u0Jx97{%*H|od;Ggwg8Pa?NQBfZ{}ilVEKNMMUp!}Y zM5PQ+vYG_x&V#qqRJAts!p2eU51X2MF>P>m_fY;sGP~Qom!#ECyggY@yV9dI-eEn@ z3|;6--W(jRdDL+SM&xfLfMkOty3Aw=YO2G+s*?i}7FOzQetN`cGkB>>Lo3>S!GZLf zU)QqhFeR+Izag=}4-piO*GeZ!Wl}qDrSlb$O!E7@^64Q}=#I*AN^Q$<9crqDu!3N8 z(b!m0e-WwEvx{s`t8diqxza}#9->){p?wzz+0h%7>-g4ZghrxtjwCf)2o)jUZJ<6u z7nTw-Y8TRPwlS`A1Jq*jyx{;m!+L%+aOl2u2YJ@FHjGr^O9w{L+_G^@g8-T20fEdJ zg~Dc|0unQ<8Vo{Jm*5E1O><}_YrSb2)k7k(Ay`5jgVg3dsnm&*V{zgoI^<_)Wc#_W zQ8sX85IIlpp2anamgI{OI439FT1ZKWCaBRVsf5rrgw%Sd#u!7&%v%UHs2-Pg+N{^K zFP7~`sflO;1yn;Ly-dTg%5m&VDNM1nF0x*Ub!A;_VNGcTuDJo*)Cpg%XWm1SDFiaQ zxw)l;7C@=8ZG&m`Hj2@)t&$yT11#^E-taj@*;EUZd~alf1{GVNDcUWEIgT zw3-`5P3??J{q-ru#*Ij$)()!Qq;u<2cjQn&U7JHaqQomE0UHufW0G1glh(n!9Ho+j zvj8@P7r^rit14i1r0VL`TJ%<9(=fCP*VY6GRYF>m>af{VG&9s)r zva+Vi(6;2^VB}>O^ucDX7|KTkQD!2os0h9x zQ>vf}wN``Hd+HS$B677USR;IgH@yCV(~L(s)frsvhs|+^!UMwru^5dg+QmeaP-aPq zWnFMSIJ+1GuPSM(CK5X9U%{|bn7URdwh>cbl-=q_OtWY%5Mei5WH;1{cbJbiMGw@6 zPnP3mTNB$y=QpZfE~4s!C0&J}`YIXXvJhd_v?@(4cNI>$1Ex~13E`OEFle)3Q?uw) zz;aD#4$3Y9c}7RU-2xjFqM^b`l{L3BH4}lZsreBFAYcKk0+rocPJUE|*s8<~)PpjK zc{zl#1ay%T6=p`M#)whxOh7bxVJ3s6(L)X3>{Zfi0d2W{W2t20er=3ck(CrgT(COh zx}>B^s=OvLQV$ZNOf4_9?lJ|9=|G=bXUyB@=TW_CJj-%?3;hGCY=T-Vm9nozmWrnW zt+JAWW8-sxha+Fc}lt=jr#u$E++ z=Roe*XsKI?3D;GOq>D{tb3>FWf!g4LI&q>|#D;F@ zl51iw094il0J~*pd8K-KI4aCcVnVo}Ota83-n zf>2vr*a%6-0^M7)O7xq=XrMF9colYvMORv^S7&xlGGe@_Z?dp|sXTvmVtTU}{~$SC ziSM{{mY`CJg;aruOm;?!8b~J%ua!2c5>EJZxEqW|M_>0~a_{gaE)%o=!Re$v2}y zM5B^q<0A^3)02{FTS_Wt2+d_y7AC_X>*b+HNFWZ8Od=H3rm^I6!mnhwsg6}1C~*vs zMMW&8coD*L24nLYywfqP*PoGeO3?Bj`7P_Ax5YEBibiUSq^6ncy2+*#YsAA;La9ap z(Njk27C}>{*#xg-s8u8|gOjfav~u?l3wGlR$c)hlwhGG#PlyG^=F%I{+1=UODD>B+ z6ndsb1V9-}>(PyL%IqfyW;!1)@JPMG;L6pAoKDq+Th*`Rrx$h*mW#K)Gx{6MKK{bm zG_*#x+KCB7Cy6N-NF@3wMEPolfYrmC>P<#^y=aF zcaYf$-|n^O^|xh3<e6vvgP};A;`VmVho9Jj;UCF8*6??TNKrvG1z%rj z*K|RPVkHMZve~48-(7=*1>HofVE_PWl564_W^Zcdl@_ z8IegzvFwR;dW}tG#puWsn3m>P`$hv2F#+zi-V!IH_XNsH)C1gll3`&yf|kbiLsiETZpOu8x&)Vn{kK7=*2>M!EMH6P!JZ zEUgo5P5hipt@W)%9b7L5L}`RaTZXt=1bOGA2hxIFIufj(WqB$M`=RVrpG-GGDwCY@ zT;dC<5pyxzLDz+db`i_yz|dyMRz18cuncd|M)tc*sCoG?sH}{?uG45{8>4McvhBCB zx?%6;DiNY;TP+FNr4Odaq!5LK-uW zwwPm2XH)>M&}v182VHY>C977peOeW4rY(ZDfi`0LzJjLNQWj7dXFrDen3~4}Rl9K= zt7cVc&+iP8n7%Wg|sEu{NZ-EpNDtgxAnS*ZI-xGh{v((3vav18QmvJ5} zqskuza<_XtZyM(b+nYl~nx!m96r9%7?I-k&jN1+B%}n!*75uDioGe_OR6VW(obUL% z83wBR`sygACsqdQ;A0GjlN|3QyVY(lzU;_B$LXb}*@i*&)htqN={`KUx?Hi6fm0=! zS=0Ij!jT|>&R)~Cd2h29tWQq^nKRzWBxB0^sK|;Rg5+B_*tZSh`QtCURmga>sk)D- z+UT$A4C|O+O%)pTG?Oh%t$i&V984rVY|prxD0vzf7=-!-%4WwXl}EW#Vs+f+Le|sm zpWp)FKDXVy4hzI4DhHp^$WRvmD_^d$RM{UK*5eJp>qAEz#|=2m`t8NI!g@!M7s zp5=1WDyMYH&1KHwa_gl-jVD8I7!}K!F=ZSr7|Jv9lA9W;y~=txO*xGslPEJifT6j# zt%Hc872uYghNq@|sDe+3R7IqX5;|-m!G0^rcQqNX&Q397l(Jj=EJMz^K-7F{ z>uO{$jk&SB)p=`kC3^)M9|a#TC8M;sW?%Kr zIE(&h>$NaVwaLP2KY<~04_eZQ6lqX z>Tw||xsi&dSkKi2{gr6Nv1BP);su_lU^3BL*6om1q9UK4r0As#|G9AcCb_zYK@oYp zjvewemsa&t?)M*TU<)u@!)H4%;=+dYGpK8dve7zq_XuO7Rm(J}! z6+k@7B~oKFEWW384;O;#0P-MbwqSv%nr2v~ratbhNda17AmNz7Wc*CHv%jhvYqR& zF3jl+EF0Jcj>AMoqQo=U-pQS%1tb)PI?_gDk$T{`p{S-do0G_>pGA>Lt zsPt5*vD9dAGQyU5LwdsSiwRg?Cb=Af=&EZTr&4i5R&FB;P=gm8 zqQ#QBYP)+W>n*h!xp68bLTY4ZwX6(_Jd8hdED6@hJq$6` zgzd&ss!%O%Z8ZjU%`ON=TxUCSj5xAUlPHXLR?5+lPxCTKFLErS+cXWQ6d@CG^8!o# z{2K(55kB#ikX#4>fu3q3QAS|m3Hr1eE6QQd&4As`q3R8?=FQ$$*34!EVNd=Qt_1k2B=DKR5d z8GtJM>dR7?;HL5Vy9?FGi7p)pA2W$~e}e=tAZ*GgqBS9=JS-!^BiYy~Su8dxDmK3f zQU)&wrPn2+Pz51X#d_c($&zGWTtRVXJbSjGW2GGTAXZs8z)3MUUNxo$;N2AxNDhq8 z@{F?d30HOw0rd$D z>^yzFoa53hQ6Tp=Pp#_O=!i-$i+q3O{3w4$L?I&$*Bwk|c~|zN22a`BLh6DP3`@<- z3EtKSZ{0FuU1vud2|IgLS6i=0yd6YA^ z7??l~)Fu0zrksn`Gic$r%~j`YI(wm?1Nr=tZ7LgnKT`Kq0}> zqAbo7=IK+aIWb~N9gG0=yE-(OoJ|orIxJEnqC~WnsPdP|x72Vp)0MQ5k#f-V@X$?7 zGHU@D4yTI8uDZTD^=UQsKpZL5CUuu{_ zrmmKyiJYLOnz8dOK(skASbZf@CZNFt(P$9|F1b}Eo;c~0-d5Gvc*mpBsfi#E%Ra{+ z=gHNypBJ%zv02|$2N!ORp+ymB2^}7Bq@XNzJBCgt_Ifq<1~U4fQwzm9#b&CtIRNNL z1S%&MZX4Q^1!^3|w&vrB##mAzo7uI2@|MYS(9CUdEhWZg`vpL4<4T*$YsgJ-A6T6o z0fm`tm{=$3Nk%4_#54S2OZ>8Q{E|}Bizu*kP)(suRdFn-fISDpEWwPWf*{sjRNrt< z&tNm3sH(h}*2-wF>Qp^Q6u3QSXtNA75A#T0fU`BkeM;VxnXFY`Af~<#F~6w7yuLlZvK^ zikYW6AyFG#rl%BV976IaZ?&%M(vigJO4K`LJLlDSqmyHr;ZSl?a|dL!(@iB67m(#1 zQHZH2bwO3q7aG!ZT@&2BlN0>o!4WB~am8b~)t2gJ_Ih=B=2jrP8m5B;UibfmR>13A zV*l0(_@@Z}4_>q5QFV}`or~9ZVH3#2vY z$(R3<^8b?-?2Kt~B9M7@##5wr+9GzE3c2_0`%CTL=?CQGA@7yqJ$-`{h`dkx%uUb8 z{bw_gl(#ZokiUV%Up^V9SIo&z>ueU!ECJ9l5sM?{ca{QfB+P9co4y<@71t5#;fULM z_t`|_?S~h~YCbAhB&jLYBGaBdm8LidpAtVLgse=GGekcuRasRkMty`M8Mu7ogrZ(K29^&Pmm;QX0lPvwrIJmXCwe(4@M0QMft z66MQ`Di@$j238RsxD|$eo)a%?qle>YT#xo#glO8)&pK{~A3DgRTn-4@M{NEU^IdB_ zJT$ERv*A~PB6@+q>T$=pg|&B^ap3(j)BE@B$8pUTo_i3D|FT%KRs+wilZosbJ+cRC z@8Jb?et2b3KGWvFM$r5VeW$jH2@&CDzK!r+!9TX@6R+QAi+xH%tmppDKl1&y;nJc^W>PiV!f3@`=QMS-L#e;dey*l>g0*Q{xw(!etg%1EI!s<6cYq}lXKIRY;rGt#2FJgb ztYS6onujv4Ogn1U7@ii*P;@fpeVIb{&Fb2O+~s;Vt@{)8+9u*X#Ey(|;tehrSeVOE zQOQ5xcl)dv|gGkHgBlB0VCZzfClFJ4gfmRu2J$oCz%3s;$ zf;N=&Z932st}p)T__;@8HoEEOC%d(ft@5#(qxs(Z{RM*#H*Mb86Otp$&64^JVcF}jUg_IMQVBYGl4gWx96a~ln`FcjBd+4U zBM0})_~MJEokwt? z;MQnzt#+<-lK~8J(*i|nYieE`uy`T${oLb|SCXfVwra257+XRaVO(cN9zT7lF0MCI zSY;XdRsQj(yw{XPcnkO_?R!J|Pf2@?PtML;_HKC;KHR?J?Z-#=5G-yVT8@{-2cMeO zeId_Ud~=g+)#2wIy27V&Im#sQ#InuInEZv21C9oaQS<=Mev@>Y@HJ#k z@-%<3q$;nsJmTn995?sKe$#IbnA`L27!yNaW6r@UR#;ypU)&m?@GPtU%z$K|Yi+I- z)A;tjPiZJm?kWI66k-x})=whvyfr_!Ku$TL>wEw~gu&hrT`BwZfNJqJat!)fe2o=AQZMi=|=G5!HsE<>1sY^HHzw5B_ z!MytI`j_s2n_WFl0M;G{=PM5^eW5o*ezhgtgm$4m)*8YX#SvV~GGkXBC*H(;k3HF1 zOS&x~p3>?|%h1$%G1{#r5(fI*Rq$e)OL6dfdDubk(S35CWa8R4#p^u8vF-~pXZMFa zd~l@eqY3KLYor@Q676&KIHoz|yH$R9b_qM<(clmF`>6C+_b$SF9zH)5I1%|q^?T%K zmWJw8J>?u7)@HfmIMGOO>vaYfbpOeVy;oitK8F{4J=s$9Aqv(J2reIpS>2f$BUG!#DjJif)z}Fs^+R~bEE#8rCsZF&TXNRoqf)RkDOv2uQKQ-_vN_oAh7pzB(Dzm;IU^y zcF84XJp0Z)m3{P%hR{v(*n@bC3vTtYD4euyTHYUZ;8w=cNvNOg#U~N1xFztE`K)dm zMGBvD>hQUI)K68ap-T9r*VV!IWMa=V{aP$M6W2e%XN)n@x;GBxI6b<0yiPa>IiP$< zE8CX8wk%)44sQ_8^mIZxr=8pSeldpohOX&m`3<>UUcJk!cX{Rn#F%d2;J^)9d8<<+~q`hSq4=)d#oi#yge|G>;U z)-`+g9pL$Y3#>W*HJk~ye-0|{0PFvcy!yWx@h2VT7*C$&&0=X9W6 zHerC4yEf@cyy|#PSn)?HWafwJH=U-RM;Gpun)}~zXMQav*o|iw0Sg0s-Ac5~f^6U0 zM4aI9cMS?SHeWkne!N`wFxxi6xKv6M7b0zOX?r$nKBdiS9^=z`*D&wYYqIu%kIO#^ zc7%*NLgK(PyL(?&k*AI%fPJ%1h+F$qH64{+sy#es*1eYY;VZ(ToHlJ<6xJnoQn9J(avyA7D$2Utqnp#_7kj>ligH^^IT68dmr?E;utAw zZybvq`F}vy!JH)X7?hZkv2SIi-H9-T2d95T&Zw5YxpzUi$1-#v4!rfV{7Uo_nCh$g z(l%S{=4q}Y4Yv<*V%>WW>hXKru|A<)m%hE=A1tPK%hze%W~|-FtYUSWi*Mgrw<%9( z4Vke!ykjWdhH2`A80N%( z&tFv^JCZ1j-s5GrM_c;!A>Q8*LWd63kj_6iTpRc@)vf9t!S?*=w;t0nU`HSy(8H&9 z@s;<&IoA0N?%zzSP92tdGNI@n{6LjXo}5KoP2XOcx#Xjsjw`O=Hn^OCbUShX>C@#S zahs*6LjA2cq1m%R6b}QLsuQ>8_fGH~I|s>3Y7mpuy7zi4BqQP3jkLKhLLG@l!mC!K z?d3=GF-YL^{<^xsy)vicoKK)4-``lD%{kO9^5zn+-~F(oBSS_|?mb{5#=K0ZrVH%} z-Qxd-V{fnE0%K~dU+SGijW(~_*(HXhm-?@K|B%}?{f41GG&0lkW^~IQt_JO zdvx#oB+KMqI4R)0dQi}m6O&Lm5(MSf=gz-nYmtBOz)_7`8RlnPI3v?bN9WfJqsH}{ z@s%&|RtM`7)?A>Mle%!ip-h=%{3ZM$!;^n4^4o1uG* ztIBxw4xJW@*~}8w{Jo8KMkF>{DA!}YQ|SmQs>1Yk?0=89(Zr%Q`>V^hxyJhVHMver z9e#i|%s7NCZ}QY`>={jN#uT;X;K&Ad+9hP@ygKe*U^u3r`X;Z z`+BzL93O+CRLd4qS^3M;4&~>o)$OTwd-?c2K6XE_#4t#98~nJj*%vnt>1%OLKh60i`BdDXQNR8@%}B2_i8pgS zpWg6X`ghFj|MKjyS8- zT$k3KR@(W?T_0P#qrAPygOPn2j-%g>IxT7pi2CYv!e(iO-POG07oh3O*8ynPw*?;> zH-CMllE*US`DX-e%}MeolIL{8URIU=hbzj*qw&k1wz)2Mx1&wJPiTcCKRUXq#D^=2 z-Cl}(;i_YRjj4rkCPj+JZk4@!c?x#sEfv@ru+4SKG^O=19~H)%_2?|~-c2b|N20yJ zIj)*~;VT)2@k+)m8$kgVBpFi3@XN}34W4pcI%b^9S{C?&Fk~F+5zhy7Jet0}eExqE zcth>5WcKghru;G1up1|NwOb>PN?9?P`y?dhbb2P)_I{&ZWQk z&K@W@DHCU!zp_ibcZv5d@!logyTp5!c<&PLUE;kB2~~c!{DzluT z)AqD>{dOzRt&nJc(XLP&c~Iy6U$f(!NcX)wya)dFiT%^AmtSh{DJ`oTo^N?iM`j{9 zljz!BWpfW@`riHdMs~bu_l%q=jj2nSQ9eqF5V~MwdR2$S)yrc)uVNh4BqALA>Vd`h zj1IikUMj1CJ34J5(1whGSAiDm?w$Jd5;=3=miVGI?KV)r6F4x5zaQOMed~=qUbggU zjT@VBwmWw&Uu}{A|AfgcJoc2OldSvuI*Ds*kQGz#@)Y`Gx-CxfTFh_jY4P;KC&2){ zr7Nc(drUq}OG=Ba)Euf3gZGt~#?`(}unBFyY+WmN%}xpk{&IX`1;2y6A_nsmV8!v1&lBL5Nrw&$O#@*4)!*xxS`!k7DmO(KOZ}ghW*FM#ypd(R(tQv2-PDfCg#6{5`)7pQ z54E?2;h75+HjtSXC~&Ao4DEq*(yok5Xs#nLzTRIq&9 z#m}KZ)7pb8lB=KI~_&R2b7Cvlp4=kc#Aij#0BWu?VQ8k~Du_8*tfpV`wu-F-*JirfsMw{D<6M}Bz$ zVk<60`2>HNzR1Uu;Aeh(QvP+i(iw2jt$KQEWOeIl-K|f{Z>58jQtB0E{E(jjd zj5h+lyADgeeL6mdzgO)y>Q`~YBtW7}Y;JRH#3qyZ`~8wn_f$8;9vW@jvQ&0{%T$#= z&)r!&24Y5M!!0wn46s=5cKc$p)3vG@j!FK1-wgjWfj*&``*8AU=kLT1oRzq;V?q7b z<3Ic_{_?oyobCU*jhwjEMo7>>obhXV`C)TxKVOaQozmVr;gz?%5&L>2ypfc^C3e~9qS$x%-E7~2UTVqnStjTsjo!XH;qZRu-E*TEhC@D|_lN7V ziZd81>pw2?_39l4n)Hev`r3_fIQo)nup(!Fq4E1W*A9B6akX4O=(n!}!Q~hvv}f^4 z?DS+$wNUtQ#Bu%O^JLGejjdxbDTOVKq-PJf`^FS_x*wd>D&lh2es<=1bWz%BTR zxPr%c$rCSS&!d5l?x>nJ^fzpoLLm3x7U`S?yUAIwog%Pj@81RKUkjFrd|O8Ok8|fw z=k8dCjx(mbjXnqX+dcQX1 z@MndA0}WyOs$|F+Z8HZ1NRqz~9%}Ztj=Z3h%E|V~)aZR|$oI`-njdI8qUBIUdiVX0 zz7>%-(=e#q9!k=Y!~}ot$~YmJvq#4h79A^&WSz(cgRGCA{`LJr7qPJY$YWPleEf2| z{&#HUw+qdGASTF8+gxei`8>SeJA692&81fU@Eosk)FEJn>RYWdE3>gjd#8F*S1kj+TC;dG9{ds3 z7`PA4I>C53Fg_E~cQQt3KO=fW|24<*^yq8*}gX!>i7Mmr2u zSu<&-boQ9tBm057R!g1slVI27g>+{x?iRG> za5!b+bt-)}ql=h6G6T=gDjN4HnldU{lC2tG3KpwXc3ME0?(oG#+~9I`b9?>lSj)_l zmbuZEzIG}e*2#)(Wx00`T6EvtkRf01TvY0xG#%{so~E{CPs66!^zoVT#mT347sh+H zderCY7_4U+APn&kkT5N7u zF10()k0Jd^oyVe`$NXH$=6+=6jX*xXVe^n_tC;zSpvm>(^ybL!_V~sJNu3+O4*F11 zGpH{&XD+4qu5-b1mtneiagRV5OA+4Z1nZxVsDi_W8c?(Brm5u?HgmaloK7WTXY+~7 zxQ^*pb^}W6S^oCr>mws(tiDd$zSP0)%&|_w_&jxEc4PJK%F?6WjUnuM+qdugx3~9x z`@xkY+U6%cZ=f_dqNXCGJS(i)udTP}X-How`F(5yPBwMT3gG5?3I)WeAXm7V-%XWJQ$p5 zk=G#)8xSZRkOmJ7nNd6n#{nU*G)^Q z&fC%*=hPPr)rVO2^5J@ve8Y|^LpsKqJvePNX}8d0KZUU-fB`*iX@0(Tt@_p-cfwn5 z`;Fd}jkEEc@QYpmM+{*@ndsiw>ExcxB-%hKvlcYaTTuYaT5v5LQ~|ZC7LrLf3MCt8 zrr@qH*mN#xVx%6xQQjDvKM&T2X}V z)}DumHry1NhUrE&4X4s4eHlaDHWaZgnk11W-rsE5+uZNjoiNDA?`1U4&h;+PSqrlx z8+6KgYu#8!@^cb_cm*WHh`c!zCDWlUztS%#CnPtfsET#aqxcyT+JV+^gU)uH{t5Ge z_l8sCF`EW!D%c4JG9_Djp{aU4a&9C1-UHfxR6E~6dQezlD5@?TK@Ve%WeoMKMb1Wz zQqqS@Q%TABY+69BYH6!v0Y$oGP^O}7)TS^1HdkEHiLV;yXrMRDmM-JTv!r$sh6ruz z9Z78QZo#=RC$0~$1?Wv=`5~*px{#ic{L#6FiRpg&%-SexeT6l$(AqXbq#&nLmU`gA zYfCh{yDw!i4mXif%g9)4$YwB#BEqxio*A{K zd8EsEbP~s`uz1$Fygj9y4aAdCMDRo{;VBZm(%4Qz{+nS`EXD#MY&P;REzi!|S% z)$0zCe0%$VJ^g(J9OuMQ&V6lTjxsaXi0|mB-(Zx?b%bxW*WVuMijnXTZL<*{laT8< zEz^jTQE^nM_SGN)waK-bJ%d#JaZT1^D|WjTgJD$zt2a+J$459dns`yA9BG4>A~ZZZ zbRto~p-lxI1S--Q7u_-vO?eT|o=X@dw`5kuvy!riZbdkYd{l!{j!b@^WI4^Oaww=~ zn2-#{R8t6;hMBthw^eMyB%MOQm$$N0aZEP`4Q1FRPlw)M;#9im)@(98crbZn1U5`+ zoo3EWRM&1U^)9uy&lB?2nR#=B!I1e}VOpHP96*Gsb&H6RkPuRB)Rsd6l##K@ozxOF zq-o!@cI%pU=ZbzyW0!5CX=S!GKEkol6+otHItjUqNO%(@gPOzL5%r<&kl<=`44EB{ z8B1U>SCa;#JJ9LP;52Ap2Dr{0WROi3E24;$G^-RdSWd7Ea9ciYR# zX^kmzXv77$+1j>qyi_lEG~f0{!_1~467eFbdm@h1mVvE|+u zyS1FeM^vT}^ag2OJ;N!Z-K4@bW?ysf9OmIf?f7(gbK4X65;k?SBY2UnyVAmpKI0@n z))Q{MA`KOj1tGOn-4);=8cmhTolqTC6HDWqj(3%RU}KO6B;Bu$Nc8LQZP^H=K8d3DhSiqg3v#odnQ`?_z*@yzc!wDHVgW@H z#CC%>29;LBGBIRmRd0Rm%j%YKC=xe}Ad;}T&CLak4S<%42DL^h0_`f9q0GRzbYiIS zjNE=i(Rj_=P{YPhY172|#55eG*2*4us&7K)5(;aeQMS#~swVSTe8eb^%!~r&hBVUF%wyR9#by1Tnyv zi3&Vry=D!KZo@T~!|;Vz6g-llL;-1#8ZNaXg?sRw`kj$XVt7we^%$DW1QkvUJ)f$d z9ETC+aPUPoEu9m4OSfEsh~F=B5N`sjiQEvayCsD+l*PCyQtN_b;0lB~?Y<5T(71MC z`KED~dNtXw4s6<)WJ>IC^H;Gf7jmq>ZckQmEkWA_ga=dreHyESI+6$^pIC%7gxTIaw8vPc3zG+VLQ3XF`&Dak3XfK@`OS+Kh`;3S}!5a1)l!Tut9>Yf8ZMK-l z8Lxw?q#v8#$Wj)Bh)Gt9$d=Y=3wp`b7bsD4G+|hU0_3>f8Uh*wor}tZ9ZWo6w%)ZVKK0d}t=JZ~-tguJ!HqMKMdXx7aBW;(EG7g9vr5Cr z<)UhCrfLAo)he*wnKfx;MKBnQTGlvTL0E*fZdBDbk}$OhNOEIID!RX%xI=D~g|$a33<+6%dY_lf~RNKqkR z)eR*rsd`g+OsE_pOS7)A!icI~{zxNZRu$f9QrU#pEH-T{F|Btu1sPj47RkC_1LVlL zB)S1$9{%<40yjiR^SDpdSjhjy-hBt9)&2jXC%yM(nlWnZ#@-tiET~9PR4kxkL%;?W zEFg%AiU^9LDE8iaj~aWLT@y9c^!lVfPnyT?`OWX1Irsd&_spF8*S#bB$)2@m4{NVA zd+qgky@f9Wa|G8Jg<Ez1eBu3YCM%H)J))7W$@C&V$w6%#q6??O#W

&czyewCgLoQ<#V5+UFxW`uLt*M#`dLG4Hxu{WEb9?TDzS+ zKHc0rQ<67SRup^7>qfHqYKF#q^r`y=Y~AyxRjXuFS&oWj9*V66G##2jMy&zunn}j8 z0lj7x*=r`uwJxJL3xn+PH&sJJNV>RF>{ZtcLrg)wyML5dMZSAQ4K`~mh?%fLTOg!1 z$1p2`xp^dhiBF0vt;RfFBoW8ClE%(7VqjS8i0srPRzXdUpmaR{PIl?CD0f_#Ey~}_ zA<4tl=0U3XI(4GU)p>l~URZ<3wKFxQm&xyEvZ{thh6T%$MGK>)9iwG=WfN()a{LxE z9q%RSFL8<`Z(Y6Leo4OIk_y*IroO~hov0~D(c%bHlRJP(v^l#c`pJ`)1=oy98Q@$I z6Xfl{v4AjiAT)93M3%8R64@B&UP|*V$OtT~YI2?MPk#^@a~GS{O3V^wM^U3n+~NdQ z(FMwJ*(nl{Dw)Z)@sWh&?99x9VgY~CPMyuqoypJa%jTrCB^8yV#T8`)Ri@fkM4e#=O;OYA7c}l>U%1Cq zTPabO6Yw-HnOsRlYvp?CGC3+KDOD!@ddZ9C^d}~QabQ_Vl~uN#AjFJ;v}M{Ox$G-0 z(vCc!v(U@CG}?uo!^VpI0q;MLt${N!-z0C`~HTP~L zFSTZl4`e6gO^~OVVav%D^U<11`Ne0JF0JR;Kgql*nW?Fk!g7|5(o9a$PZa3H4qavN z@0c%}=Z>3mYK<}zZR6>9RUccX36ib}icz%B=9&5WxMW8;vD48>Rj!QaR)wfUdlAc4zi6V$Mykig$;D)=Q)BDZXUtOX8}nuj^P4o%sD)M; zmdrp)qO%!O1p5lIX;a&S4a**AJBl==W0dOIM3+e<9PW~JhJ!I6p3 z@Fb#6jASH5kC6^%rV!(J*<^mUAhnAYJ(x**#UX{xWHwi&V8CBl3thKzCE*?`Db5rCna8 zr#XEMnhMgs!h|VN7_yY8Wbsm6#1&m)2PBzOWZC<|utiHxMMxKP(<6DCD5mT-ZdWEz*k zgi?HyGjkc7n)t|}^a#p2cQG?~f=>~q()c1)Nm#X0G2N_$p;;U&Sx<~K9`q`W@^6n% zZi~q4D$4C>Tdt!#9Lc`ZOKlwrk51~1yGcdfNU$5@$t=XBUcPU;=5ISg4SN!ABSWEj zT_$Ko2{mIXWur!Q7zrq+x`vsRd z&|2N2qi4O|`_S%UlIj9;i*Zq*X?{2y2@xD-LM2K@l2YZU4ipBNS6tB9;SRMx=lPGM zgna2>rrNbqo89H%sFgi6RNdSg{8!A)N{a`{!0U)ZOMg)eLj?VV<^d3RUKzK@`b9YTx*2W@-Zb-?{E1b=ubVrs@ z|B~tUb$eH7{JqBJSrmu4f#|R--^g)S2oF&R2^C1yDUwIj*H@rf5e$>l6xthuOOj36bu((2!bZ^0*J}K01;;KB%?M1YtxF~WdlR<91?52SpPTU`F z4@iM=bXpx7;yf~<*}}-~ajxj|qsI-{wPDIX--|m|Q?Mbud2ide7jcC{8ftgGmQz$*bXJ{EMwnfpf}Oa1OiG_HqDi@ zOw_cGh&Dq9x!@BK;dvOpO7BR=5y4vF0aDQs!KMk$ zBsw;M>O=Ib6vU*iw5{jSs$4-m(b3mR@_dMXJ-72KRw}V0d9qAIjCIrb4CjdHG)JD7 z8x0)65-|CG(-RR7+mU6t=E~8TIhzk-ckB4y8&75^+8%D(*ML0L4-R`sS8K3kv!6xW zc8QRsGZg7fQW<`usuLQabJ`xQ+HPgQi10)s5-2>tie_gVbJ{KnuWkyq^Ko%?OL4@c z+vADlkUli;E{3t@9opv?7*HCJ?&nJihI@pDSmMbMl5|Bf%`P|`Lx~JdbBihx4Q0g- zX8R9^z)QSbI=}U{a*1?$K>3(}K9MAO%2%l{kaV*S+RaFq?n$C{B#5x-%>n!j;I}b9 z)v~CLO2VB_wSmQcsPbS8eB?qk$m^#N(4ZjM1B!5+&VQeWXs~a6mlY!&MiEJlD};_{ z`9D_0u4|xtTjdJ$gUA+1t|op)U;;_QNyaWz(as40a(99SASm|Lt`WV?;Ws_wm%PG5 zr`!g-NkwibS}4kk5EK9;DNzVAVKmL~DCg(^7%7TD#g@gnikN=Wc?8Bv*4x&C>v;^6 zi;AtcE(Xs#hLZ^&%ibGpdoC*^Ct?cBb}_>%PtNd53!rwl1~=9?V?Dlqy=rY7qk8%^ z`d=fEexyk^I~aaUMQg4mZB#Sgq~Lm;qpo{#Z~m2ZmC`1MzIMfPUWMqftleycD$~QI z>V-#|;Uk^xAg1`!)`1sou$$&S+0i}{85HLo+6E`rxCKxa;rCr42i)8nd;`*na8Df0 zJ0#RNlq?$_E*nYmvA(eUU~!g197W0Ey+>fw&|!RjVn z=dC?38gM%sPj4_T$jOCgOOC5?zkvu|hof%<1@@qwodn)AJPc0=MFzR6g~o)PXXp_y z&`4igq#K>&O5~*^xftKiPPmsweq6^&U+-ycrgnBPd4sX>^*m?QGyqmbrzPH67^+Q^ zH?a)qT1^}qM88|04f4&S?+!6Dj7Hz5)~*-$-wdDz%xQHw0r)!STKy>-!W7PThkUKD zPNU(cA$R|Y@UPHry#iX4!z`=X-PY7`uQSduh)B>TV)X-zjC_0)j5MtvSHUhY2RPXw zAS@Nxh$J>*9Pjw~KSZIS-Co7sHmSjm6dy9$H$2J!D@_Vg#Ce;Lovh>iP@(=A@g8|` z0g2W?fw!e`nMbCFTz0U0LxT^uK7kV7h$xA?NORm9qUAZvPYa(=#7TQZXg1x9e?Ck1 zS#I5UT+)<{UV4>JOg95Z_8MhhI+CRfNZW5PiZef!6Z z5qiy1qF^7aZKI^o?lf+MAZeH6mnoh<{rBB627?paZU#yEHP*1(@tj4CJ9 zTf*=JqIufzuuZ68)Oe~2$LlmFgzYi1FGviO0jgMHhOm?g*9XfY#Wx=F1!-1AA`f#G zKd24b@iNVOCYb!U&}wI?{dczBES5Bz*7$*COPeVghJD(IUtfmxT!z{%NUs>$j?4Pj z>V)vrV=;88K+OP%zLOLPB5UI2qy_e{^v1){u`u6Ks2_3=wE%HiLxG3goEtq{eX`wI z=twl)$0*QU7l*c%4AR1(oM;H*X4+X~5Uw<)Bbl(#TK+H{vy>B({AhHvJ2Af)OTR{s zS>&Wzb{&khvuN~*yc1Ho!U-;&U0hGN*5=cg3aLrZGb-bk=K)y*rco_Wc%8}d({%L# z6hI`qElueX$H2g<&a&uIbcK9Io65%TQqIPQDH*3_dCw6Q^q5RQM80;St~*xC0AUC< z*K>p@>t3?3H?#5ewF*o!^M_}+bVE>+Ht+{1(440O?3!1(H=Kb+_+bOVKK^L4FttGF z)liT{q#>GQ<3ho6!!V68n4TE;eFi4rWfsx|x11B<%;J1fZnjSK-}fg4klA%^TBf#R;>pm=H?D0C=Ss|!uVc|06|yJNML)C5 zYA$3>ShI!|jLSOaURo`_#NC!Rdn;{&8si#dX5ZUw zJ9Eb>r$rLHVzjL4*{c*#B=5`9g+cJD?%E(NZLq4k%@uPucN=qGb8I9S%|KX{TUwZ3 zhb_bHmu->PeLX7O9lTO8VeV)TPly)YP6=ybs}^D&f&i1C5oBi`$=$LddLr8QUW`?n zo8psJKfMw>%2z@aA+LzkKg%!&o=HIWlB`S3Xp`8MTgjY>*LeKNxe4aR3~M}3Gv)I` zW{z%fg?!SOJNtgT;i>F1m4+@aIFh$*%{vTs8Rj8U0kKU=38nk~e2dmBEqnEM!dpem zm@KMC4q;a;OVxt7XxVre=;@k(>?90yti3^2h(Jv^&CsAJ{?5K6mY=f`jOY=YejWYbTP*U<^OtuBcVFNhY{cGGa&+oYF3`0|mp3A* z8>6(%%q*0o^dOfFT`de@Hl`5!I8%7SgTfAook{1duj|bj}HoJ5`_O)V@AMmPtVGu|7#?<}@Misx^)TyxS3sfMnSI$F z_xvN*+(E+Q{-wu*Z+)G3Ww$V3+tPlecuGaFXl_!<{Fe+=SkR!*0OcYdvfPNM{%W=Zvy~`fC`4=$!U8L@5No z1MU1n5cCLWelXgiB6yHy`ytkRE)qB`2#)P(7YI-Zjf4|!$95ym+sl-l2|0eoeMd=W zs7b(uh|Zzh6s?T~#zMK)Y@H>%zJZ=2+xjfF=&vZ!i`2}(2m4!002#+Ur_E{4Jq;-% za~m-+6+4*u=j&@OY{sO${opNl1ngA?HprUD<|@Xj8lhD5Y;-{C8Zc`)MN55%t3Egw zsGVx3qh6-hZ3BE}Z@mPwyY2+tyw6!)Rxz75tc!`2r;LTNk9YvcDA2_!98MtGIWP$Y zk!D>~^_#JJk4c6WWAx-;*&vis-6$ih#KYaEO*ZDNLW8}>kncs}5jpDwPAQZv)PJ`W zJ&~uNe7C+R<6LzkFmDW;Hsh;mT9f!D3cx-9eNWZsmiJEnV3u=Xd?RG_V`6HBrp3hS zLXX1xjqueU(U}vMEt{_9$!pOS4e%y9)Vq+v^aC3BJmsUYQ}EQ5{ZGod@iL`Z~V$^slN2#i+A5kdv(!t z;xp?iCE0W>MTUZsy|W2O%RyJ$PEy^@QddRS!64jNDIH{93e*_X(XpSztlHZRx$3q- z^@LzG_I6mV%4s@cC-LUDqhM7OsBL06 z%Iy-n)@2V2ppc|tsv=b4s$K9sff1Pak=3;`xuZRnKOYC=djY;a!I@VHJ;-OQ@Q1>B z+#p@3ch)!cOGc3j;X=sAE%c9Zfy8kiMHjbYH89; zLgh`Ij4ia(_2jgSbrj7(CK|40szDY~G?11-4SWV{`T}M?3%0tB&{Zgc<|A~7E;7y# zSyPlgNZDU05NzXRgmr%w04_G(X? zm{lw4xnFlK7xT|NTy_(}FF6$UW239}+><|U!TpC9evttt1wu(#nz32X6)T{MnTeLB zw2qXTz79fD4{v-`jj5k!rPpqzGYHjOfa@!cx^&yAa6M(|Ff}Mv*2vCB-P8VQiDoT~R)N5G*>P%=!;e9m47U4TaU8~aLn>TT z^h>Wf6qOr~4QTJn2_H;6`fkZDnI^XIBz3oA0P_|y=}Qd$C4Te2I3_1>?>4CV#e@sR za+>sP$M1@2#Rls3d74Q2s;Ibw%z&XDp63X@nr!^} zTAY;fVEjXZ&U!R_lB|*&Z>W$)6P4(na5!rmp=d5L-VK26^W28z!GPGE5h;?YogEYG zqZ@a_{+R%;3^_!uJS-e>kG*D|e=j8Zh4)SX4ZsHMF{L)WF4hAPtyfqBDuoYfLn+%JvbC;;ZMKW@>`k6a8y^ zoXVY0^&X)!Rnfgutnx)}ZC!eINZK4KuEUAa5}DCmR&;%=>gKKPp3>$%j%ds)@0Qx& z6s4|T)H^=9FgrKD+_*NhnvE&)VTJ+=Z1pNUKov}cpu%owhFH^0D$DV%-F&+$?|;qT zvx`e?El#eu#jo#Tj1?zd3rcK&k()dit>FcettG=t4K0K9jiRz)c=xn@!2qVXkJU5K zJaS`kcCvfnT3PR8g-v>_h0sU63Z`A;0&LAeW{sjN=7TF5{EEpg)oyMjaK|blu7V$# z*B{w?hgV;h*367=agQuj%<7I#>MQ4THaFGXY-z5l9blAoyOs6X=eCoo+fv6zuTPFn zF7-EzbyHV*ii~&^U7mtghpSE+1C&waUU(~5H0;pA_2UM46(Sw#UERxqakV9}!r7FH zVODcKy?k>;)`3*x5!DpKX)UNIUn{8ZX===^?%!Owv*%VD_17iUkJR?|PRz9R-)iA3 zb>@^$krn!Uv{_(P78aDoL2$c3o#P={mALd&H=aMNK*p;j0G*SC7ql^p?qt@~QL5r; zxhP7BEvY&vp_-Xn(zcms*jm?8+?HI>V9{1=$Eyn|?9XT)Zk}kkcdNAeMo;qCDD-|C z$uJqBkO0x41{l?pIc3fGq+a(<$;BjlAzJMad9LuJ$iVbsO4e;+^FRtOD=9xJTnGy- z)l996N)eQ072c>R9jq(QuB;{sMYh=$4h79IbqzTq`ID37J-1tn2l^tqT1?h*-LFQ= zspSXiCTCiwR$)?xaWU=IqD1$63^K*kE*;~Mn&4a97$>}w%&DcbQ=)hfT8T|i9xgJU znaQgciIxiL>dQ;w%Xk5q1z>hHq^BaauDq$I2^F@XR| z%SOcAFk5&^ec*gsx=bE>ppuqI?ch^WnzykBXm6phxPMQNm0IFcuP zV){{OEay0cL#nBDte0bYTwr=>6n!~}QO`(Dh|UZkA5)Rz1?z=p+2C3|NaNTTp#?A0 zF&yL&ZUSQjdoZ#*GTJH8y(!6g6go95!ze1=m>7kRWV5-v&LZwycAT&?yoI)uj6B3P$@uo{ce_DoZYY(|6)VgvIW{mAzIKyZu&C?)_Jl7I_o zh$Sp}GxK8OgGodzzu< z8cgI~ueZrb)VR;|=}C{TuOaDR3c-GT9)voS*Jijl1`=QniZX`~ah|whw~*nO@cM+P z)SwVA0^w>zI5dbBONq(Nk82PF-7L&Z&Y|LkEOQ1KlpO7n<iELQh)R+w*~cc44oSrDyD0a1{p$u2M6)?T4OG3X5amIXYk5p+SJ;i` zgi>p(9%s8^m?KS}XlL$X1az>0A>!NuJDj{a;@q<%on!s|oY6SB5bS2yHZ{sOHO{S& zhAbqTC6+~d6f)EzgCVIz|4g&m&ZwcubYV3mqMB^e@1&lELse1(dLlE1f}TA`)j+Lp zT=ir_&}c9SsAsDSbjDj_S!hff9@<25WD}5nJ~&e}+Qs!N$tMQ3K4d3c;Nw(Kz4#q*`8`-8(JssBZsiDgWT!e6nGPi-6 z*eDo6;a1LJPB3nuLo?aF(-j^cfP?xYR9&FffsS#ZK6y#L)p3>rCfF1%XB1;+lt>CG zC#Cn$(u%ylj6`JAxD(qj)*NT!oDk4W7uN!3a=CTWB))GE)n)IH3I+yhTACOc8|WgS z4)!z@Xv_iB906qoBLh6)rbq{Qg0*W9niGW-W;vE|EblbO1|<_sXh`{ZN3VRJvNn8s zM`-gHE-b^G(iEfB3j;MW+{--TM*Z4WsAIRlska;Z<;+5C^dTmOnp$8RGjO!IX&T0; zJs46Jh=}!rAw6}JQI@uDE`gCqHUqj$F%@!=sls5FL?8J88wIMQAKkU29@o+5TTtPc zGv*XFoT6WeGpuwA8whHcgYcRmxBu`tOX^Gq1RAiM&61pnc|INW=K1-$_16i^I&Zg1pDR_D^>Q4% zD?BM3Zh`^3o+&y0T7(iem?mprVxuObuBvORLO0gvurN;N0Gr_Qo@f)Wo1UVFjx7vC z50t_4VQXP#&C%Lk*{)Z8PfEie8d0)tq$89P%%3~x+UdN^5&N{Ke%rw2;6YWLWK2oB z^vvW%|J#XKuOZ6KCl_k1F^1Klpz?O_`Zm9I47v{I*V~m+-^J?nqV)u%cK25dwl?)* zODB9=279KaI%g(0z$|<1(j@zWDW8fI?;;oHs>JZ(iKNCfW}SUp1Dn@6R@cZb>$NLw zN$VUKneNFR@AFs7Lg{lFo$^}z)BT-_T+lfU5u(^Jt84t!q6XKKF`O!RKDu_e#&!)BZr{)f_E!(*P16gcK zY$wczV2v}k3FLU;+bE%UT#z{-Iy;@*mLG%XMBDJ$|Wt(^IG z9#-b=o=}fEyiYCxZR3Z>gnAV)uw|ks`?N543bu0~I=7o)Q$|3vgtyKHwt-jiSlAYO zTJVW5u$wgm=U7H}s1*9x#=2W2+1IxR@tYi-+d>>00)><4x|NV{V_jVxqac`W6V`&{ zsi*B`6Hc_K$gmENv(~0sMdvuy)Yt?RIw^3?h#gK1lL+FVD_TeAs)n=>kWh|g%5_Jh8^TJ6u`j#5QIkga39*3?GM%TyETSdao z*owY_p`oJ5>)yKQb#58nD1IGP;1gd^S5oX#Tv0z-3%OpGXc|FBons3bZ)i5Zuh zN~=nz_VK+3@{4UTNE@GGLLf2-U&;+fW{^ue;^6hs4fp5?W?(!7LidN`!(14to?%4+ z^hO`AM$g)nNQi+BAEgiR0P^EZEhB+>m5%UI+teNhM34Ue7t(5#0p|ZxTJ3qjW);t7 zb>IJptNoYSyLaEV?VCjxS2qh3w{P3I`Q5Pz`TpyW&HUM8nC==nYEIpC)77HYeT(G zN`)o-1?TcgTK1gM(De4n8lL^nYNP+iuC@63Vd)TJ(P)^>ueD+wwu@Rn@%&Ja=Eo>q#ZHQNkq|vAZ~Z?{8)Fj~>hF z1<}{Ep&5vU2&tSqas%Ouyao%-&OJLSPM(sAc}8%huhUBq-irhdF=Y&nwD5M>oeD=3oP1oZCkJ1_kgCrI9EdPD4$43YDDr+zrIHM1^qqvX5_b9-2GScFMgYRF|1)3`Xi0b z;}-aJ3p(Pityg8=D}8#aaI`^mHeF&#`=4c@irl)y_loSP{3j%E!n+(~P-Z!jzd8b8FJmARYa z4Si6&;1|YKD@EnJV`@BiCHszM>V%$^JoWn}J?7`1*mWyHPo14UwEvRoi+?Z)8LEas zd{p1-_c-W^mXo0>D)G{D3Cy~4P3wmFy;39%#n>9)5sWyel>^((rZhHiZc(CjRy$JHEt!U==(XD{H?XRpLE;(BdjrQylf@n!B6n*xkj)5VEmAb>6WorJV$q%25`yIL)`|JlR3yR+S)+_XBX9P!HtJZ@9rBqFK(q6Qm z3TeESDP3WC2r=H6^{jGjweDDpVwzXn*Wbwz#^?`khH9XTO(E*kpFfHb@dMBHq- zN6Xyzd0p+hwz5%`*v_-E*1h|+d%Dlr9MNLc_FlH9+sAXQ81&ID!puhyZrvZKv$hs1 z!o=p?5CH6KmW;rW!a?_tD81tn2@j}IHv?2LF(rd%hG}?7EGt2sFpSQuA zl6!!nw{m|Bck_)X;~jR@zm8mbytC<}*3I-+;~$r+@C1{ykFiIN$37ZPpB%aH+UM$v zr7Qf^Jtt1bdRi#j3Sij`yF_WbGS)7N?3X`(lodPm)||*bA0ejVVyCO?iAV3j?(7WO z_4>T1Ao6NtM{R}q&Q;525;XIq8dtFg&7Yj&?jAe0umJ#TItI)IIu{)KRj`uq1D|HH z(+?Q*RY&?II%fbK{}p%iQ27Sn*w4XF`W5CI0Af)UVjUeuI>b6n^I6~X6tE;?ciza3 z+0L83lTKmwc)CinE@S&x$Lyf=sn)j|1LrSG$f$r(epE*oISRH!9}?NB0pV9~~3PwW2`QToe#{ z*{oJkvnZP$h>*~Q|Ga>K=@ z{Bn&;7~JJ#(RMZ^ceIE67gOBl-OX9^_k6@_N%!fGcqMy%@K&#ltFN zLn$Z5%|Cr+qaJp?KXlI9nJ4jmuY~(Pp6iu;wL|VS=JMLXnznn{Qfu23LM0fxYSQ_n zYk6At939Kc5i**|7p9xupGwtQKd0key@P5w{V2aR79PYNH~^h8j+VA!hy!<@+$QDn z{MjnCzk@yG|J?e~ikjpR!=&r~EG~n&+VAfl96T!n5x!nZ`T0}oYsvOx^R`Fe#oM?) z`A->ts2RI~7`pt_wg#^vmip&E6OIrT0N%=}th4$f!U}S$w){lL^ir(MBgpU^p?!7ZYWPJ+X zBefP|Dty%qoZf|HL%treuUwlq&8vL!npN&qs&v#l^iQozpXIlI_GG1~$23VDO`z>n zF3jFv7HGayI}>|$UD9jtRlvVgcuqvi>szb$A7KqI9D77REcVxpr7nzg-C3`?_YdYj zY7@E1X~uPiyl1v2>wDvUXm_qXvG#c!ejF>Ah|w8sx_sRd+64P9%y_)bVYkHDgb*13 zk}p#xzI3rSMEUO95AN;~mZ}y*K0L8gUYL=~yQa?xZW^w3h3>w^Fi|EQj^6eRncy^2 zKU!`nb_EpnBbDfjYdS}MWkcuGJZSMhc?{kit)lXDEW`4PVI63!-H{tTZB z(~P}4UEW?-O@QUGylF>^TS^0tC(1ef%^B2uAgW+9o;v{S=ynGW(jK+=O|82vFRYH( zxZx!o^Y#PI2$am^FzbA3YkJQ%rmm|1FdaM8WKI{fFo zf5g!z9zM+%hkqH{Yid~Z-0IG5RoO2IcLw9Eu7N6E6<>A)ifL~%YUbM8>rt>*Mr#{3 zujv{;VB98G5|VFu*yaLt*hIKJnc7v@+xZ3R>Lb!ye{L8qfQCfRdM3A0J}BjOeY4Q~ z1WvC7%naL}0*>0~Q@$Pv#pTNsRle3W;6UX*cZyq{6uX(3Vx`3nMEz50ebyWubV=P< zLH>t_cEneOaK^v-1W5=yv|=j~^YOe^_7E`G7jl<2A0i1j6xy-9d+)7dPCGnuW~nyV z^Jz&XS1pl;YdE5w=q9G(=#HO5H(E!d>UPP`@Y5Q`0a=3Y`edW8GdG6;a<`f%52(dh z_h#+f%R3`$LAg4MJJDT@vB;4=?-;E#Q#OC>(E;cEq>(|epLQ9yYU1<-lR4(-AO38< zt6=ZQPNF*Gl<=Y(zs|6;{=m7iS2sE)s{aA~xuiInSDF6hxycj9ukw#}G!7zy2d)Gq z0w?!8v2k0oVZ`@r-9731$8Fx;JM*hZ`%uey+)l&=pI`m47US*20T-Fa)d}|?K(XzBZn@0| zvz>Ai0K3??%mBt7=(ZdPl35?diej$TjSmxnwdEqlfN@P{gn1-Q)5Bwx$EC?{M2j3wSzW!7>@ej7tE|-MeJbZb+DFzdV&8R+_ed zZ@0OiA^Vg-6|%GWQAvVQG4&}@VLUDDOdmz~`~AaU=my}H#pmw^mz9MDYjsfDU5AXC zN%K`>hjLy-^}l=ZRhsFXX~*P8R?bwU<{jL-@Oj~O6RYz50KemL^tjB+=^H0NA5|BH`{Maw|yTJRUoe$;IM)2a~`dr71HwuDwEc`kHq}&?~^`Q z2j~=LNBY}btMq#oxcU%2HnAMJ`y@05_R~eLdE%JY@!j#tJH#P`yE)poCO*H&H?s15 zm4NW(`)sQ<^8S`CcSWI8h&*W~M^n`*eEhSO%qLIi)wnm-ktA!gjq4oIi0Bj$3C>vQvaEJ;57o_&qh$R=N7J&G5}Auo#i?1 z>Nw?cKY0JX9r_!yP7n3pyzspcFwuJP&B`TlBT?;C#}#IaOx>FsO^^>T*Og~G?(2DN z$Iy&ko_bea+f{QX?Kfzkrl%S%bPvJOhWt(m#41m}L|!FquRPVgyfLToikQ>g{YnjZ z3OS^$_j~T^Cy8I#iwEkA4ajk?*3?Q50>Y00Ca;vOG!tqMS|`!BCP|0((*?l>ya zXv$!B;J}No&vTUSojLLSbace2y~yc<<41!w7Rx^rMz?;-P(MO(wHKp3!`x3j36N0j zlyJEeuk+=ZM~4B&MD~aDDC_BX=AW{MYSoAIbI#Hp4a4^)9X8imcsL&>SLcYs-@hS? z-dLIyDS?8xV%s-YYy z^v2Az0Yzu+JgfXs%fxx|S=iW-t39r@2cuTA=8q@}*^^a3r`l%;$4JkZr38$Or{L7~ z8Iaq|_vm@`qzCVBukD!7+xfffJtFKo58TY$f!>%sE8`u|7cY@>?e+Ew*3(xO3ZJC1 z_J5beBp?@Kj8*G8zxC};I%Ol+zAe+WftO0`Y|UrG%Qc1;sT9kbK`(zlJfSz7W)+}o zWi}=fOYxv?%n4o^cKnX*?xbq~zZ7o(W;9I(se{=K3MMj~zc8S4_X? zvQO=}<>1D`nUb)j@7qjp_4+0re*&mdgOfi#E{A$V2&wjZCd)s<^%3RgV+OvO-r#LJ zOW!NK$EdiDN&b>>ML`uO(%M*TcE}Ni6YDKU8 zZ0O(rEZtwdI^nk+C_9}#v39rpTLI=Mwvf89^r|5)F{tB3FYO?TNMF0IC>x|(^?#{!Xe~!D^gHN3nY?d+F_$_bt z890`G#MDAsdhS5u-HabEBY?6$_nUBbTygMhX+S8L?3no5RPmR6*t-6ne)6l;^A6)t zt~*AHbX9%SRVVZ}W-4uazOsBHhDXPW&T#k7JwNFyF@JgA3Arbxo~+*{gUtQ!G9piT zxcow7S|#nORXm@l?HHbL?$`W+j*;$r_YXl%;G}(>>>H+l#N zs{c|#7~Gi4`|)ovg!GHb=FGj9omm+VFg`7WoJzvMQ8y*hv#(eGai_@bg-XZ)_^`?S z&BgP_CB2WjPoOvEkzdNJj@83YAKP|MkpBc9NsTyi0=%y@R(46}yZwGM(~qAyQn#7{ zuX+Q=^C+iBJ3WY!Hex19!0ii80WmfT2`R@{HWtpl-o3upOB(n z9T0fAp!GPDE+5tvL*AIJdi2tUo8F*(budpMhux|waff$yKd+x*Mpw6w9H|@B9fUnp zJhiHP1?mv=WB-l#XOd-S-UV)7mj;B6m-G=TpBGBB2f|@lhrlca8|nImBT%L^^Xgc` z_IRz0xx!arhYkeSCnQ1$J8MCg4;~1ml#Kn|eQbNwWW1+Oo!htj!)12hPZr{jcOFPk zx0No@aygKBw6{yWa@r5d3E5dQNGP^v7F2{ycUm^HeK~ zP@w62!T;G;Cp%Kvy*krzFzW@+B1-KkzzcX>t10Z=-~-h7BaP3}Ap|k*9+A0M?3;~+ zr*q}@eO=}%<2G59KRQZ{|4jZ40G7&%9Y2GrjlG9h3%aElmk>Q zb6G63lBmqXWv`II4;rF>4C4gnD|~E4r)$!%z%=WAv{>RnfGPf+!09|#yaUO2G=28O zX3V#(IY`yMKBhyz{`SCw-R8r?;(H|?a}G8HMQjJR=_I@}IpOz8EUN8w+tgLZ z7Vyog=eh^qyq8WgKBFdMCTF=L7X0agw6Dm>>H*OpahIVO&2QI`U>nLYKRw1J;?2=6 zpSFR}kOZ;e6WcPZF-}az!NfC$K^wD1N}q}MN6)Jt{M9j|_jC^*waeM8?KoE~Jy1&X zZqKfYgKN;tr|6?Bmxfc=J>7t^UKi8-ZQ^A~XJ$g}5VmyNixyo6R|g(ZFZ{BeeDUCh zRgL}iT{Z`l$QyG@28y-|{wsfuK*%m<0Es9Ti&H7U8p+(KG+b zNggh2ImRbJEh4@phMbdp9I9hK?hpRy$##8NW4_}nV*QfT&tIQKaM{$yV&=+TXx+z4@dsYLcDZYe{cGo>^w7}c;RC1fA}#n2VN{?ZArYK) z8MyuPt`v~c>2IB_4?ZBiv(=h57Fho^oFM4^pW%e*nN9~}HRIs81wEE_ZuI?Sm#P}R zn~l;({f$N2hkc2d>$6fxxJIO--tV`+I4Z0UpX`sE*7r`75IKC7da*<7#1G&LyA1&B z12>Qou-ED6?n5*Oyfgv<@yy#7s!$icd1*^_U+OH??Rt)r=2XM1*Z=JMb@!yf?|#qM ztFxxQ8Bs4df{%B+Oov~fFCM{uec-AR{5B=F#Lh||ENSZCcBVb8Mit1q97ZacjYxwQj+t+lZjo3ioAP6d3pfB&H==1{min+l z<2-C~em(8*rB`N8sNk2km2U0yqU)TM-G4iy;l`rK4Y`YL+Z)yp`q~&qO}_C_Ca}y% zkMlR*2pk1?<@}oPy}ThL1k92LFw{_ke1mYuiRcN3qaUR1`r} zqz91RdkwuqfP@-K2%!@oq1RAC3898iL+`y;0coNl7A)9B#ojpsPkDWw_c{N0zyCjH zt?xUFSy_vI~@uDuCOX{|EoE*Zbe=bvU9 zyH5{od`a}tUc+%taczUdc-X*{$na*PF;hC=w>!n@Y5YxqsVB239#n8+`&y}wZobhi z^pgpgZi;qARGH0DdY%c+?<_A<-v$lU-@u|Je?*s1`%d+mxULQ(El2X?9eQy^^0sDCw#hAVUajkwK@69tfJ*Sjlhx+N((*y|R6??;SbAoz6TZ(POhy}5xvy%5@#%zxb{KoQ*6JaIx@**gK^#C0M?@YR z9YZ<8-NwHdNH-+Mb8$%2pVx)xcb{56Y9dPjY))YP2TD1w{Ij!yo}-Tc9qra@K8!RJ z!a;U^z@RFY3kL$SA36LS`JtZ?`H-Ri1gDLO)+qOcPg(s)jQ_brh6DTD=(a(8Eml(Y zIq={QGT-hD-X(8?h{;c01*_Z3$n{v2_^ zmC`fq;rQ9Bv{e&=lXMp06PsKn`j%SK^#XCGAZNt6zV#LTS7*=zkL47{!TM{Pm(~)VyKY?{?vt)ka7|g+oU1hTu6m~c^qrR#L&XNN^Dk8Y`sZ-eQ+QZjAHsv{?-|T@s+7E*s zuELPZ-O5i214R$FaUdQ2BUcLpX>FzE1ys^vl|49lxTnE$CLKkw^6Q7~=9I&_1P)R! zK80Qwz!^988>3m+a~aXWEf2JRuR%dwxIycU+?y?sMK_h)%wle<7(C&i?RtFAi&_s#!Q(mRk6+0V$aNv9zUEEIiyNc=gedCzxl`?O^ddjH?o^P{m9T*;!0t_)Uw7DCH>Eik!{<<&Y`}Z* z)N)GT;~?`3qKm48a~-pvAaU|x)5o&qU@nqRz>V+k%4+PB&|MuH{w{dvQAw8Mx8z$Y z$ZM0PKaX2?y-27Pe!^@kSuML>tOhs4gZ0=QJo>{IuY%JI&-*-Cf2FgMJttnT-%?*D z(~gq6p_X4odZPOBQ66_LnydM;ptX6Ii`~%ytdAk;_`UN_hoc-X&WK)<3I{zFme9YV zQ4HS7Y_MHbL>+(sNbClWnCfI)GtD|zi~jyEDIXR?q#k|b(%~o#JhrZ*Y*(osP_McCK#azU29kqZY_B~^ab>FkdA4;uF3h2C{Lm<%YL~VH@>8*@D~sgzixw^F(x@A1&^as zLhpJ%zh+m>^^id7i&1y!4T2ZhpiSU`Opq60UL&u5jQK%&c^P zg3Z09+MeCLqg@-=KYESdPW;o6?1w|qU%6UU51l=xkmR{uGFIOBM0V_!$k!+Lz-bQO zmWy8tjNwGYxN2`)XA^~G-#`2=nQ&1{U#ux2P` zw#ct9g3|;(t=K!=P@l?C;J)|ZLd^20>Pt`h5blYW5u^E&1?mAme_~S6+>@qG2M@>$ z@On1{roWc0(aW#D7$mx7z3)iP>-mK51Bd)AJPe17)^Q&f0 zg|5ZMS~g=B8vd#^`y=RfVw%R*Hps)M$9wtm1JE72XF*479x;#WRg+Y$s6xTdva!vb z>MFp~CC&<>p#$1`Sj~l=gU|F0id8~At7T;AERH;S|H1EQz^Fp& z-J+op>-m(;&9>e9$xSnn)?D3><^}SC>7TSwUP=`grw_8OFHGAr7)QGzDxP);ksCw+ zGl~a?Z21zP_p@D5Wdh?5;%d3qb=&eU= zGTx0uZ;`?gbWFlVrFzZt=B?x7Fb@slN$ctxPkZ9$-G!XYpMo1UqJkG3bX>3_#zyi* z1IA*X_2NUF!a>0m2;!r4!QvZZM9-BrDO@HlGx*64T~o8= zO12L$l=xKprFZ&NO8E4(Jm!-O3i~)#x+Q8PF8f*>(7C8cj46|wa3m*LNE&Fr6?mY$ z<+gu}?q$-*qHyTZc?xsh+inM&Q+K|@=U1MNnT~=lXn)yXy>#g_T=zhnp%qLt`Q}Js z0VJf4Ca6PAu|Nr`=Y6qNw0;|u;M2{QnRm?Z*4h&w1P;&vtU}|H(&I;2Jt-E^!@3*>EA}6ZiJ1a*}aeQAup})k}_Ibs01zu64bfKPF>B!H@6L%?m}fH zo-R**oX?^>p>Q}W?BiROMyh8{NSykS?CP`-vwbaWYWKOQg!>QZQ$IakxNkSdR`((! zde-up^WQ8Uo{n7OsCDVbScFxu1#FDEE_eIV)?R>cF!_Lo3|lAJ#N8~6}brk=VXM# zU(6UAYIs&Fq;x)KA}GRt#H-xX`Knj|9cr9{G~YC|Gp2>gma=g>+!L%kt-POCl6?e0 ze}U6Uk>$xy&eegq^Oa(PveDLaKU7}deT|8mA%R2%Tz+UIKio>z7h9Ac4JN}Q1(}e&#;boP3b!ZG8~_%^40Q zNbbq9nxje1Z;8sPm@Q92<8bUXZn=ABUNX`%gFv(g?%6-}Y^tWG6&+PgzJNQoMZbJ|y>tMTMOOOdqFM3#I$^;Y7pP@H|S^Yo#BOhayYGqUt&eZZ<_-O36} zOuKBRT8W)ZNMX5@eKauxTz=>#YYQFJ!uDaAvt0JUqw-vh2e>8aBi4(p&(uD>psWT| zFNand+h)&yADWqQY)jYZf+~HrwKirlj>vcx2d+QmuXX>tEt|8QYW+`#qoyZm4|2!1 zvhty%pF~8wBl9rD5=LU}Chw=k+vtg%s*N79@Ao2YgVysK!rzVXXv}tp`B~7;yuGgW z^u0c@IC_p>^MR0q_H@DV3u;+>Mbx`|rI!}%gbp01 zt;hE$wf*?8Uaojvbe$SDl6LID$$K|F>~9oYe@B;yd8y4cEqz@4_%Sjb=Bav|!fOs@ z>miH=|9qU=VSbP1u|>@h24*?c9t-9k@dLL~WF%HRrC6=g{JnYb{RVRUXym6SvF%X_ zy!dZI{x9O*Ta;9-8>(~3!W9o*N15iBtbj63;qxQwa-B_tbn^9R&anHO$rKMO5nvY5 zmrgBqH)h>{ou;qEHaWAFIX?j&BVN|s{PoMs7f52i;T0-tgxvCbH9(`ndXAIHm+VaC z`kq5O8$)Y+*!HZW?3;4*TRFj%lsrgx%sJ52+mnfUEJCvc*XsM*AdTq!G$IueJB^7h zat#_MozzujJ;HG4^P7)9#Jvb=Y9jYq?cmA}L_d9-uThN;_sX>MJ4AmQ0g)<;OS-C) zbH#%D@MrOF>m}@tUgC*Q(ZHCte>@Pr?(!8`?SNT)+E=Q5bsOY}Qk@~Dq|9fLikd-yCXZhqV)L#pqqbk&wn zVa{e@Osu86-PpVirnE)ixnRz68iNKq#gAIdAjFVlI~IChRreGqt(JC0){ya;mL<-l z40SYBJ#$2SzwLnUJ=W8CXXz5S$abiki^((tm$uxXoNrF&aSUGV=S}EWrV4F^e1m`I zh;vc$X6D11RPYUw5B6;6UZs@!|md1gvQor96&4CsWsp3s^A<4K!WGo6CHD??49 zvi0)3%wKrUt@NLoJ$Jz;e@N#Y_FNe;EV}oN#{D>Ea~}rf-1~y1!!&`q0w>rNY3FKi zcCepu%s!`M_%#peTvXjpIq(7Y;mmW(dTK`4_RWvOSyzkw+LwDXEL|s3NjJ7TLk&!T zPh>w!ZAsLF8(p^U`|~I|sSS|W4$C z5zd{H(9i+L&@=1uUASq^gkm$&WV9i9l_P3UNN|HTs>+3o5dRLbsOMj(<-u>vh= z{wT3`b^`x<^C?^8P@>~PXNR( zz=-~`(a?hE=@@u-Tkf(dZO!ckcPu~eD+QXL1m@86e{Bu|q8kX&-}?Yem+>0|8||l? zfYw|$_%{&V={;+R zU1QsC?f(7+Y=BqUpM7U_yr-&5i}fx5+8*1vbAL%a0O|eP4cVE5vO1o~W0z0q?O5Nw z`E;PLGu11#k6d-Ve^7%kXG$ig&Q{>((~ZERG446D{+*lIxyomoY?QP^K>-yPY7v|pWe;qzYh9unVD%PH3Rqc9}+qfu$y;>%VYQ@ zpYNpi9TZ^WJu6{~!u>Jmzh!jFL%iu7uZNEU&M8tWnL?_x^#@ptxZA>4X!YQq8ZI3o z4ZM(8C=_8mlX74BmZNeSOE**+@y-Y@o}f1#@m6JT$o`D59SHvaYRLW}+3yY9|3fwP z8w&gfvG#w10*rqI%5Nx8o^Wh8m;Eh00?Z}@{chR=av1|{v1#>A8a)Xl_rJmbklcYP zQq6R?=`IdT%Ng`ikWE&TUT~R1d7tilN561tpHc=%J3P%T1`&xfB&3Vi zmWvEGtK4X=6miT|_KXWku?UVfE6hf>b{Sa3^2nIN=Slh5cAilA07r*#7{<#MD{tqf zI~uQaH&9?iBUTa;t73(*a*9P%$!b*cp8x=wxXoo&j*#4k6Jf-22AK_av>78(8 zndC%CgF7X~sh5{&U#*RHfCVG`9I-JmFP=04EA zzd+_uU<&kWya2|Kv^xn{04S4y=?lxBSs4fudJr8j1!Cu8<2b^5R>m?gt9==0`S0jS zzk{9^0Q97zWuOIk_usdjVx55(M9;_$<~({<>JloTW%Q3Y`3*z+jG{A|4)tFrn+u|4 z?hBlpUfDP8gK_9i+akeilak9U(dRAhnhvejEs0nsI{C{h!#lkS!X3e0tE%Lm`@A&^nv_of&@Xg zbLl~%=k%M6w-@todq_WZjLmQ>@?}179qLt@xM?%|9BCDO`$tjqUgYfI4Cim<;@>0Z z-*JYCX6Ld0cl4n9TfNvzQz-43>IAesv9tQ=uQe0{fKeQm{wR4EXfH=gAA833VP`1@ zFnt3`#ot$9?8fR&>BvCO#v!E^fXiy#J!rRptd|<|@nNkFpoB9O_Q_kkL-GKJ^RWTM z1kJC91As`+M#peO(hQIVM|Pm=w}Onu!|bK6Q5{?Wg4U@ikvcjrDE)E@IK$Z;2&Mf6 zL3jE?!$!}_&cO?o3@C5C|9iiI67v{$A6+idfM($uMSp|1>KL;_KAhT7ph5ovP=JSI zQv_0MZ&9l0b>uvo+Qa@e~%cBdBo_pt%WTV7Vw zAJ+(!ql+mYzq|zTNmY&o%)Z!36%60D&TPL9&hU^-hdHDM6qq2okTNoxP}!0g=e+Ldc-liQy`+uu%XztS#Em-Dd=ad+xBgbtfH4!E0^VSJmt z(?QGEcbRIn^@-Rg!EY8 z#<4Mdgv7d{%Cee<{H6ZtJ2QPlvqPPWQ!Nq&Fy77%yzTlT@^Zq@0Z_5{pVuc1N1|UxI{)K~tn1qfEWy zpdNtfdLlj}kyw;k*GuW2tLYibXqigPS&B^0Ec8xgLldj}}Iahe z(B3|=NGDJ8C|~=P*1Y;8!@fq(>iKkJuc!ZlEu=>*5)4DhI6)1ZRCJBNW_t3Dwk9xt zD9kq^+$|;4WVt$=l4v<{uQGQEJ9Zb>Fc2_%b2>Jw$k##FOjQ~pr>-Kdp`~Z3pl4_f zw?bo_QlhNlFc2rC`siFfJ{){+In^iGRz2Q0Vhtl&B;+FFWDGW!lZWt0%F99YbZm6p zJWPXwEn@HvH8qHA-;0mNqYJBCQ<`97Z_})cg)+C(_2%u>#Uz!br6g1?iKu|J4V9rz z#_kBy2sET5LIdZ`*LyA0CX#dHvR!5Yzi%#A%(VN3M3=LfDV7pPHKdO4DV?}rASS1; z4z)E8a@I(SG78Lv1f)q`>oq0%&|$q;I>%6^c-^Q6F$(>>$e)_qTZ$9C+DPAUJC|BV zZ)$jI52?DhXMFO?+Tt?7zdYF2%`wgbTHq2;7K5*;t)q_5_VliFrCCNtm_|cQ;>~Sh zyf7)r1$p(2Wh3KFb)z-W+9+>rl(qp%&nYAbhs(~zcDJRr4<_d?rn$)@ZIwN=bZzb3 zVG(F(c_FH{C!8{wkkFZCsbQ)jrKoM7<$<)pr$S3h;f3|?LDeRRd8o9)1z80FOEZ-~ ze}kA9`GPWytXjRWW?h|jl|CvF>E;j~l~UI;KCpTjVG-kG;+vEhTQ^ueCQFAv?0=ao z9S4>I{3VluKuipb%=>`+cVUM|*b%w@YP5Ni#<={8IihdmY&K$0(bLzS znOzO{xY`@JR6%%u&m~);D;EU4!D2U#%DXkn)-d2P?0{Ficcn4tZQ{jiR<{qKuboU~ zhga&Im9zeEavH;ZKK)2YV}jU$Ct&#^MiuwrNBz&X6kkt$>jHQGtn3=BwDxD?{9K;l zv*EP95w+ETT8<#D)jVAD%9${A+*fdZ-^p-wJDd@Q+;fQTWX8G7+A~upy${y}eLz@L z>dx{@dI>ZTI7^)wv$TET)zoehWiiPlGdyW#hI;&M#Z3AI%d)wagOQoq2anCV zFAU=#*vH|ea+M(K#B=h2t3)yN^v$*Jc+8_u!H>VZE>`1b{>k>!cMp2@pl1(y_Mqp# z^-_huL(ji64WwY@g!S;b{ArJzR*<}J{7IK& zUppRv9-oH=$sUNhQttK#0&Oo9fBpvyqCTwn1nw}MYQK6hrM#Cz!jN71eOw1E>5E1H zH>1pH170&Vy!1-Qzhe-emDLIAg1u2>dFq8fPnlHjr^cZH$dwLgD{p?{bGG14>aQsDnSu>r`rzpVgj2JC)6LWp|m+&T^bT z*FEpDbPPKaCl1grOM(OuW_dInTqU)#5uI&jhD6Gf<{@ChbY^FL2IH^uF@T^0(XoNm z-k`F`BfDJHF2Cnbd*=i^goh>P`kOu@CuP6Ye1Z@@ZilrxwIX+xF%F?rlw)5O}yxAO%%{2;)q{!7=`EIijV&;KL{OHve_q(<{`IB<=&)@BJRYiB9gG=vRJrhci?Inf@lF?`qefi^~b8 zYG|LU^X<25Jtd*tEw>hPr#t7J&5E?!aJhTB(d)j*FyLI=e=cVJLv7jZ6!1m{d3RiQ z*E?Mh^S=`;T)wbeHo_~=dZ_%-7ui}fr0&+dR?BMd9kHm=uo0NEnf`|rzN)wk+KI6R* z?a)fd;Joi#6KaZt8mLPejR~u<#8jI{G`YJsySug7#*ez?&!v_w73K|&HIL8LbgnlI zU9avLtZA=l9!Tn#LyxSQ3@+GoE~~p0##UZ+9h-1lol1JR_TwvPdzZIqn8rpkei z>Z-f5<8z(e-HkoOrlG8++32J;40%?kZ$`CkGQ4ux1yhTiz7cifTE^{_wo9!=f>n5l zmIS4m9LF+el{iVsN=3PPm|9YnOJRg*VZ3!qq2q9!XU9fWUte@`V_-#1KvjWnLS7sR z9$l>z(I|v#R*UZTac#;98cIkTP9(MyipagKO_Mb>i}l^T)dL;%m&v6aIZdO8&T+@4 z3BR%lNzWv^fnLWe9q8reyrltZ(Ee~AK6#7%s6%NDEq)n`fdi8s-5uT~6Pf+-p5+L?2E*`1gWx&~s|-)CQoFcDr?duKYE?O@ zshV8ZUeS1^wqt_Y*4)>X*Vl&aYQ@&|C1sD91eD6QHD8=+R-Es1Tb}c-YOJ}u*mZkm zI3o(9W#cCvA1+M^kxW1;q#GzwHFmfOOY(J(+U@|%T77*XnwaiW zndDy|?_V1P%Yggj%0*L@6RF-2r75u$>3C{hdQDeG>te;w&57}z*7}C#j*`-LO3`FM zS~aAlSaL8|a-zg?xY;Ydu%d3FV0MVK($}&)P;`-+Eli42jK^A)sK`}=6fwb(1!eZ6vS943`qp8;qJB?GnLjDXH#5OM-_<=&3*D&bR|oYjbwlL%#aD(T zmlCr}T8c}@sFd-#>dCs^o~r(u%HAY$rDqGlv@27$zf!NNQO~O=zHlyPcmOxvS~NCX z+(jK-Z^~6RZE_|5wPme*WVI|>s1hYnZKhDIA(iDK7i}is zX{MY2HB9j{MYcs(R$5gLT6EvAY?y@;hf4BeF+M5&sYx!x7-*3zlqBh2B!Vqbi^;La z;lr_bViJLZCk#|lhH4A13^ca4)D%~jW>k|B$|>-u0++%zxt@BZo)$ED%qxbRINF$c zIj`Ybe&e;;;yZU@E{+877lrFanqG305DiyTh=-}VWjG|p7*-@|P%8~fy4I}>30%%Sr*e}(7j0#=M4Vp_VzFC;vo^^Sxdu6>k**)A^#sMM|sUaGv z1@?g%#oMW41B|khj0wfIY1a$L-9Eun&guO&_-gM&QY0Z5ooR#2Qby)$d6UfbV||_R z@bDx=T53dQDw$X~mQ!&puX?Gpyss>uSe_DJpYC6q98^Jy&ur9pi-ojTsSlDIdPosN zRVZ?9!{ye=EBQCC6YkzAcE6P9Bpzyd*1}j6t}Gd&C7os61)Q=)37PUsRh(z(&e10h4Sj24pLD) zFha>0h53m&)dr#IDs9xWZABt&B-@?_mxPSs`r4AQjIx=O?z>&x*Lr5|40ws?ptS;J zFT{!o=PD{?nkYr*Ip9kSf@*XE>g`aZP^YA6v*eO=VKNXCO zGxQ2`M@B`)W~9ewlM}PMhjqC#^TsUN>(|g&^tNOsU}^oHAl3WC{Ha>Lx)F~ z7h!r+<1gd$=c_2w#bZ}itTpDD0fND4~h-;33T$o7&~Lkts`|!0!@SBEhC~(F_?6GLPI67fsimq%9tZ( zRgx28a>8Rul7cB2_EkwX5etzAWCx{CNEbjBH}m}Zr)ce;U94x2J@dUux^JZk0E2r9dfF}9)6f8>-As$ zSVX-UCMXgveBND8%mQWT3zhZ4XkoHc{40!o=Cc#4e4LvdL+V|y36Aij@Gxf&q&D0e z?BM}+_0+QVhPy=tp>d&@h>{jUb$#63Zo<<#d`|={%uKDWqh8z3EorD;)!$zqo+@n{ z#Dg+GEGDQH8|B<2g%^a6PEfbM4A)e7ZTz^3EJ64+8=D=og^8d|g+g5}VZ)@*$(keZQ;kzgMjV1u@YdRRfdRTUlWZLy~CFt@On!0=#vV#r{1QaD8D zeO*#D$|x)mp3t0xtq8Ubv~mi?IO0?35E3*PVdw(RwAL3>pA$ulzWusu;bGP6qrv63 zBeAvG3){&Z+X?3d&=Mm4DqwdzRmVhk$3$JVRxQ_l1CM53yV;!RGHXPx87jgafq){+ zEZ{m&9}zcqQ7;b@U$iGOBsMIZ7!lGO;aw9ApI@p9PlYaAsUjD~qr*aM!%@zSQ6TRN z2IDy1M9ahKl1UZB#M-zB3No%2+r3fn_!wW&^;NwID^PD*jjX(`hbodR^&NE^G9aco6b#*JF+a<)F+!z&vxJC{;d zYVh+1`T2G$aiP+;H#6@Y1tx6bEC}%eTft=XT}@S+;sQsETyN^4ri~C3BO4;d)fujB z1GTeq@U*n@lu$C4w)Ztbg?k}fgZ*ri(|xj&VNFq1_Zng{6U@Dk8u4*RH?&<)CEBUb zgISvUjE#zNjt9IOPrg1WVl0gZYnZc@huJ(W`h(4Qh61`IHm6;iq-MKo6`2 zQ4t`Z9q?+V)zU5t+Tr~Wua-<-T(BO_(hO?^^)q)c)-_Q!wpO-tH1GwqKYJ@ro49E2 z!Z52UoOLBRAV1d+<6*cl*Ibb6<`-@0mzNqk(g^Yvk*IQunrqijLKUo+B~Kue>men5 z9_EnMJ2b3D;TpY>={nV=O4FmRerb@3M-=lmEvqXAf#0L7 z1P$CSKvIQlb7joB;t@os+>nW0myuC|qh4&FV}PZOt1-mL4yI}jlaV*FvVxksnmUJC zxM9rVV{ALZZ5E?pod~libII26Y{z5>I@dP8D*=}5W1bPLM#k_a+d#^o6%Qze5yt&1 zWy6DBAHS51zNq!7bjEc;nx2Jvb{N+`nh=%D^5hpo$*UwHU=ap-t?G9DMpij)GUbV8 zY1TS8J$-*;eFqa0H3MrYh`o%nojk%$1?}K~w$1j2bouJeVl+n6Odf4?_RN(;CF?{+ z8{y)@lx&Ucn*up;;!FYjsLN@drC6I#Q*?@W?W9Bf!}#L)fIFMm;W>wxMwP~w`5sM) zawHGoHl-j7dskr@(j~1b9fL$?wcfmdIy3bqZS?|O&1i@o6l$U4WTt2bkucF#wzpO_ z({%Gx!Ud}41{sntR?QVr)p>}udQ`e6*xXr4-Cs@I=lrDv8Qx4y;Y=t9ESgY7_9eNb zPlnY#ugV>ddh#UW^Yi2fkK@bwJublbFbj$BS(|e;r)ev>{P-0@RkYFeD)m@+r>f$L zn%=0qe3_<9xUYdeOj*rJLj_`>t!E>pprPfcW$UFL09Q;8HcE&wFG+KqNb>1V@EaJf zj4Agg_qZ7%Im~kOPr{@PBBL-(RGVT~|A8QjVx$mEAf7D#@*Q$(Gaxlj+#*S-;4Z%A z8A?5#TROoBqhFN@rbBX;4#)7^&;zF5zRX=xuCZZEPo_t}A3H zCv7cn2G?+O)$j>4jtw$t3A1U9upr>AiYpyr0#5eT8xu>kQ!3zEC>seBl+{z(p$!w> zSHPlj$T0du)2zkyX{V(TpZTY?*czv2+sOgBJVDLDbPoJ{6cG@SMr2(r<)V0@u;hS* zOrw@WNv?&v-?;=6LAsBH#utJMGLB6%Z>)w7 z#VgLlN=93OsHG;dCZ}b5lsRB$*jz;oa}o|1$zX=T;3=e)n!ix)$*EZa%^5+tQdHF3IlXTCmzOKpl$DJJsau13~IYPwch zLUyvp4Ta9DiCaS<&JJ?^e#(9k8iWMn`AFUCXvLu@Wn#3Ft|NbXFHQ`~r5&g(Y6YcN zR6x#z8`g^zZ9uIuPQ-Ql=1_g^3?QD*h7r5NJZfwzUb*3J$QEt;z-H`^2N_0f^t--^ z&+?H;*W>F`0=LNtCt03P^ijf^D+g*R!E~eyv?VVnN{SdNDOt!EImwxMD58V3^Zn&| z(3htDFZSaur4$=@5mfMb8ug9HoR&h(2zOreC3TX9dxv4sdW?N8tahoG(q$EwFNz>( zhE?em)SavDJ(D`X4X28Obhvanl32)RL1Y?G<-zTDGE;5pNXt+wIf}C?CBnS6*sHcT zvU?z8panCU5ZdXCq*?@b1f-9a7WNO+jR32LYFox*+Giar2dpSv$bqS(wUw(GaTKpm zKfN?tr5uDFG0~PxfmKZ4`n%)WQ$wqq!s;Pts!v#BT1sm@xplaGu)TGdNF7F24w)CW zz#7`pXBJAw7V?epv08YzY_^?3fs1ZI3cRX2plT|rzAB^+honG}#TNcVWDF%UyRMDg zGTu5^)!ZLh(_~OlX4Y2k*WR8rKGe86oUTC%Qph%tOg2-&hnZ$lJc=hnsm;Cx89_uJ zzZ?rV$q7Y?NGK{QC?BqC?yRp%qn7*ERGJg39mvhm-7TdvjYD^;y`>6Zk{PDrAwF73 znHD696R{UdEDuS-dS|~om*+%BZ;rDKhC4U}?RX(^OQf)td(8>{ithm0zBj+l1(BjJww`qab)+n6!$b|c!C}@%n_*f z5|XJz{6KXr<@q~>y`<5Q|;!WDnY6iWd^V&8&8UtTa>evgO#1O zk-3Gd3jz(xiFa)(2*^ow4T*O_RYsqJD?3-=BHCh7YM_l1L8&dCNmHR-%ii9?22lz| zHICLz2s^xksh^dZu9dB_m6d~s6)x1iF4;8;rAsREMQ6L4B)MrOLIazEQoGR=LjmPO z-f2@_p~E5O!~~SIVwy3e#?7)6W)f|#?{03aYHX-u1Mx!`rH7j}<+_fvM0o^i>ji2n zr&=qdm?Fwu3I7{_zEUy2}kj%u!2=A;&F zC2wt_tfnWgVImEMsl58ba@d86pg0q^BskDiKtdx>~ww;Whk7BjIOlP!WI$k}Y9`0U>P>j~cjzq`x z`ovJpB8tT_y97hKgignEv*w60l(3GMl_7QQA|Y|)(Eh^Mp%7nkG^V>-6qx6G-f6NHdY~iSaH;69CUoXxN`!;Hm%c2P zVDE?1i3_TL(Bk#3_5yVb};broePMO zkAqVJa7TJ`R-GS41}w+6{*V@adzFXd2Bi6MvH1$;HQS0n|CK3-z%@_4(4~im=1+Qq zgS&&AZE7BFebmPj9+l&Bh0giSXv*dX#jxsBb#1~LTo!CyD7HnYe@MMf*fHrt%$ z<0_mN|6ntHoaeeRx|^p1%|0=6rM`nRH`iOw`25Xt(&q5**prAa;s-mwnMj6VCQ z3%_i6hK0RmKU==PiI^LWu8GB+&>@h+J^Q|u_7*FbXFs<=VxNxB!Hm;BQV*S*K)hh@ zf0vDJkHvMC%Tt*@rrmyemG|8bP1jX+*;^C)-z02cwVc`+e09E-mXCUVDwR6Do)=q{)D0*W9WoG<^5sEQYST!6XOG@k zMgMdb1*01)~8Su0oV9oNk&C+ zSK-RMpCqNxx2&RAT)GfJzd+d>QdL~Xf;C95{#eVD%_KN;8+GNUKhuf6{m+coJeOq% z$viXr=2zLZ7h}N={9@1VSkhE%c0W3Kj|j?>mEA8Dzcqg-%k}wE#d70Q_*--k&oRCy z69xj(-wOl6M}328@9Kn7{O2ZbHL3?Z&Pf-{mm-U+n`gC z5*Rfng4YNt-AQ9e@29 zSE-%c(0`#mUm-hCgLt~0P5gM7r}=S`nN+Y=SsUJ5B);7UVmtrgqB&cBgpN`J15+OX<@$j{KZ}9HAI`#8Hr2>;ag_~bs5|)gdEZh z4q?CMJ&wc5wQtHPt-aKBLXA6tj^Q;ZmWO#2A)o4bN~p&3{VM`N zxT4;)fWKAAQQe%czh71FM$Cn@*y-^PSq5Fo?CkG_2P{`Js^bLjK&yQoC!r0Vp~ z)`;TaA9ch$QS0rcYHty(b8dFa=9fG5jB-}DL1!4(1`X+ahtAmc$dUuU@q;(0nGDGm z49v6L0>@gh6#{~O{Z3d>6e=V2{;DJ1|92g6eS1Z%T97jTt}F5d zzfcPid_R`gO}Oj*(yL>cxIp>?UJfLS%Wp|RQkymov<|*19lDB{a#mIk@yK^6gO`Gj zESI(~RUj|0tK@JLH}j{H8P(oo4%G!&FcLZ+<{)F7X>IP^6IebrwS6t+ed-0P^z*qP z8a#x;n$JDQlm%_ox;AbRu5)-dK;9}$oJ??+z7s&#(#7AEbK-N1x6Y)c zf~`KD^lDaqy})I#BK){qPm)wn3;a0RN-Og{l9unS3UY3K(`=4L(py*SS1r(r}%% z>UgaF%MFS28B_6XkVTM~F{!3blK4ylS)cBa@!|N>m4qPc(74<)erpbL%w>n(xSzWd zlUTD5J$_J7%E93H=O96AqtgOVEp&bBG1USs2uzBbp7k6Sm_W3 zQp50Cq0X2WL5S|3|rCGTc#nKQvd~l(s2We55*iD$sCFX$zNDY{^ni%kCz{2 zbu#6y&wC@`iJwq5_NldC*NNLf4Oa$;OY)dQ+}YBZgUfT?Z`ZWke|EL^b7(}2wMehS z97D=hk14+RVz=&%@A~+i_-8J=6U#au9qiNX5IlTciv{ifl-y~%Azx44j2!57vx|1W zxVO^$M_^xU0O{>-GzIrOir*StCgx{DSW~~HI`-XM8>_r=)&%Oy*EXlQZ13M|14GU~ zp&kC{>Ja_(#LC;U>c?k}NA5r9atQ5`{ZF*`Pqg??wD?c7_)oO>Pqg??wD?c7_)oO> zPqg??wD?c7_)oO>Pqg??wD?c7_)oO>Pqg??wD?c7_)oO>Pqg^|jcD=TWXS)QXz~Bn zN8It>ZlwQb#n9={-148g;NMcf*Aw zZ+mC|fdJ@1^6cixx+j03ADwzgrwHc%%q-lt-C22bf)@82IrJYu;Et_#Z=W~sKk_+b z-?s$Q({@?X*M|4D4&SZ$Q+4B0HN58-WMJQHb8O$XpPvN&qRBW=^m3lwf=PM%Dy*k` zOXuWQ$MSNeUFrM5((|TW5%-c9snH!?=2ZZjpAOmXX}bItcMH+kE4FD-EdcKfNO zfymv}_wk=!Zf{!I{joa!rEGSmmAL`9{*MFNFct273n=Yev^8Oc1OwXAU`AdGfusu^hab7#K?~(mf zM?p_GEfV(D7xn+5z0P1gj;D=QDi|!Fg!8&;=f)?{a<3=91ipY-Jx$foz~@(|zunr9 zR&e^;)6XB>bsw-b^0(kb$6t0|XGitlcDU{TgWhyPC|}=wXq&U1iU3fyA2EHm$32{< znEemp(uvC~=#AJWz^@!$>&M?sv%Ua6=X3gIT2F+kprh@I`&ccf%RX8FEP7$9eM$XI zbWg87n>DcgiBC1}tDY*F2Sls=6JIEJEFc%`4nBl?2>s?uv$&;3GEjE;V!>I``MQco zuMKVay`kUC6}Ns-<`)P3{Po7^VP;SER)sd3)LMtX)#6<5!+-gJowUsV^$`7~xp4!8 zIh8h_C-Rf0H@|bw_bW5_Y+z01Er+(b_|07fZ?pfrOnmO#llZi|Y}Xy& ze?i~B>bvvI=qJCQ`u^I1Q;-ePy`MVDXML>bQr)Fjj(E?;-@*R|U2^;Gv$a+GJq>mR zTYoqKe?f8X%H0o_(|Ds_->-gpFYwN}kK^tfOZCtGZZy#Qt*ztw)tXV7upyQANsQHs z8cLTX?a>EvGg!F)jMBe(p{~0IPI3P-5x?(5ef~B6{(beo37vnTK3$x}V1;uC{Lilc z+VS1MZ!diRy~qo$`+9|E`)34kBLY^LG4kK6uxKsE@ibRwPxByIEh@PH%g@ za{Cmz|3O7K9i)F{Ah3?K|gfLyDd?^<`T(e{xzJ3U@Fh*laSxeo!VZ*Sdy9{K#Muijez3c8rE&`4e@oxFp{@-Y~=)8cITFUQV)-7CGyO0ZR7es0g9uJ** zwd~5hpH>g8q!RZXFF5{1TdK0Gmwa|t{&DWHJp$(%Izg|0FaPr~`k(idXZo9<`fupz zo7QzZ>vl--`*g0yQXlb_ZVb{C_diI<|CQo_OX`{@Xz~>U+r3 zm!G)=)qT8oM?CcfetqC~VQ<{pEPi=reVTnc75@uxY+J~Kp9@>^o@*F;ZTO4%wGG1T z>qV!YAEw=j{^sDT?l14Gz$w`08Xx*^e=*cLnBNOOu_t_PXXHKKJI`CcUf>^OUVPy9 zX#ZQEe*4ZJjMcmh-!j1Kqdx>}yxTns2Gh@vJbNgt1qO+tA=aqll+J6OY zy^=N6lXJNtXSSz&l!dHMMc4uGUTlJv2s9%}>oC$4PT^%!>B4&R_(DbF2jamiyrEH! zwO_x)R4jv(7X#GuiLwb;TAi5Ehn7v|>84fs(INBvh~eUztr=e}2)pUubn2#B_acpSW zb!IkoWEL&5nYuRXrWRVRtWMs%diCxHS3cTYy|p&7vH0x!SDyXg_w0T#InEywD$nt> zIti4yXR8v=_d!C&^W!BZib)M=>IU^M#!uYJ9Q)NU-<>a3qwO59U6R{ILv;GW#!loe zMq{tRV6zRx9xJx3l{jmmjSSZ{-yffxtm*3%&ZsNaW&G9JvVKa5Ber%iP&h@P_cJM0 zX3ZeCXSe6F*`c2(~O@pe2;ljb?*wIzL$xHE_m%w=jo$)erbdtZm z)G%{#WOnoV#YE4-T9yY3YkHCWMo@r_>tX`QOp?#%I>rcn6AeR`8_gqKGc!|{7p~phxO(rZ z?Z!y+z3JL(6V`M6y7SuU;x?=oA=$et!F@LUSR*aGJ??@W8DlF6wJPI{SEPMCFzIFN z;#B(J7+$_Cuu0QeX;~vl=)UM&8$715Ajz7In9d=LmeZTsWOgING|nGh7fvh-N7rp@ zT8T{}?%Si$wOZ7Dq{WYW0n$cC;6*dtJ4o7vC`*4*_ZZc_jH~M?o0%5Q4fbv<&TlL(ZqBUTo}Ing*Scns-*YV0aM%&q z#0&Kd_wM3TRV9A9*t3>U@BY-dURa8@m91?`E1HUFyaH%jDX9FcVZe}XtVtno==CCda9ai;sG7ATUXY>VOu~Vi%(^n zhrBmh)vLYtWJu#B_cNVmK;eI6J9|4pZTg z1}3SmvY^w->~N0mS)qE0(=jO+YUf#+s%=FT28gIRx~e0bVFF~-l$G=qiYJRT6Vf(^ z)oNL8w%)c3t=J}qnny=kryGnzMFW#K`)G-DBpOy3X0gW24x?sgg_BE4bNkH18p?pj!GPmi>BL>rIvuV>|U!EQ?_uFdv zx`b_g%7*E5Mniae_nCo?pozikp;4;R>gb;D7@Hhen;g70JbZI#^5$sgwXy13Gm524 zP5ec{=`q^r;q-IevB%W~{<7@TC5i5;^k5}5o-o90vN>JPF_YJ0y4L{pn;K&Uvakx! zBu!}JrickyHG!E{clb~!vIB~16_V7Ng4#|>Yk#qROj`Nz$WXh$V&HX4xXlcvnp~vI zEi?K^Og@!nXt|YEYUjy&>+0GE8Z1Lv?d64${y~SeyU*sBw(1wyl{R8`XSiMM(a{vs z)gD_cleNtX`o zk8=WDD_}uzExJk=Y|w;^c7zNJfDHFL>@D;HQ%;p3T`PqO`6PX6hCL{~&jVzROxG4d z6?~|ow!o&K>T9{Bw+8w?6!u@G42`jdv{Z8~ua(L(B=QaMWhNwE4~46s6>ZL8D^S|C zsy17zW!!GL)!BW`BpjR3))evpF zEptp^O4q>p;mBHDGSSXzpg@e-={=#~)_71OEP_i(t}Mhgp)gfUij$JmHk8+Ng)(xT zH8w=kcj}ZPNof&RPAxVRW6Zgky4d381{*#np@LUtwBXyQI)NUoH`8tW?P>nLFI_;u1~g>CpSn6OsVlKAF#v&BuN4b$yhB5 z(IAC4Td|G-s_{;TV?@TA;LAJdb?RazzqA2fs*4x59j!3Cmzncn8U@M3;#ZezYby)VeawUb|5LTzr{x~!RiS4p*r5XMIa;lMb493@0VZB; z>Re5%*o;t)f(_c#+E#LX38V~?EY1X~GNQ_Wk&HBGO$MTYiSCf)naAo)18n|kiF&SB zWnqh&<<&w?8J#PEmeyqyH$^A$Fhm2IXF~DoohUn_S~I9rFX{AaM$>GovBzOhw`e&A zHNUA%Dj!J7lY6V%f<^{YChYh=6H~6VJ1qTUx`FBX$I?AgcwQMbSve{yqFT+bZZ76c zN|e6b+AN`xz?D?UmAbmRt_JhGC0lZ@HxU4#Q&4vylL>@=Foh=LV zuY?2?wC1Vmy^4E$gwr9?u|)O*t6q-E)g)G{V-4JBE;F|}FqMBQN$itWp8`=aG0Ff zI|e2U#(ArL$gFH^5V3Uvf?bzj)q8gsz4gXWqO4TaLv3qd4>nYfH!C|7^V2QYR&0wG zt=-F3@jz4MN@wY+s&uwVU>kQWD2=(+a_*Sa>jWq6Y++GqH8NPp2(D7O^E;!sx9gkD z@VsFV-;vDbfsu7(GIXjaIY#Q0EcB0Oqns})Nkq+&GKiIYI(=NH9V1oTplg>4Yx>Al ztrBfnc{Qe_9#*KrAQfTJXsTbGln;KL-b=5aC4Og{lyFuDumnm#j<;~JU zlOChCM53$F(yr7d6|`H+=rq#mdB#E6)U;}I+<0xaeR#&~xMY{FnPdxgSyxXKj}y9K zK5$cc{Gk?f7>f61Cmk%sx@)LsYXrWfb7ewH3UDpHbUmq}14393>Se%MVwfx=zA`(t z5)w$u2q^)k)FV-PGJ@I4uC*cr6PU`&6v0$+*>HopR#H_&63|KVQc8U~O5k5!b(+PC z=1GV(Dms_%B;R+5TZS~&W^3)}Qsbbl+@a@48mmk6hBS^er^VrAH@dYpWg5C-OF66& ziD;aoAFFSlF*!eSXFlrcUsl?uwVLtXq*@;IYGdf8G+?6+J~3Jhoj!QD*6Un7(5({Y zQCNd1u1|svc#_tl%DZ#W_cYCx1YToAwIEhXNMu97#DFB!At38QHXo8p;Sxlwtg0rw zaS$&XC6`|7a+2Q*8<}M~YPG6Z&!%frDSRI)%dLo&SXP+{WAN!U(h60jRAjPMOmxex zH7hPw*9_LxH!5_TIz3r$$u#N#N^K6?5QQ(xwFoeSEcO^jIU;H6*DcMqUs-LPna~YS z_wia~~+mESgR4T10PlT{tQXKgVLG(%Al)dXK_Jf1DsAcEeOZ1rp9h z)mg%%RWW=ziUZ6jj02X0gi%t$s92yFl_4+8s+Piq8Vq^3hS|f$Pm={xRJp#0t*WS| zGpe%5qG+Zdn#uD{g60r8SiU^JO375ojV+o{Dfa_S)uu`8s4r`@>lr2$p-qlg)szX0 zp&4X9qv%3sdHRsNu&a*KSZ(hxO^p~=r(0K-yW0As_BD}wnO3?=E12L1@wl1&1HRW9 zPG93@e^N_#Mdu%Zk&hQs-1BJ3(Zk%5=|sUsq-G|jrYVf-U{zAHG0?<9NE8DS%#05z zjsS3DfSkg#3T}2;lc=Pz2(?7zuMj!iEW%`yQc4rEsr6)<5>5~XgP{@l!Z5BVQCy1= zN;rIpQC`V{Tq?XHow^>Sm#)bv<|kcjyQ@>aYI4F0U8{m zF_<>uBfjXVSc;S`*3=78x#C1TI|#{&%gswd2L$JNN3){S#2Fdo{6dx_7pKW6Xu%db zdEr<4>xY=4_I#O&AmdUckUU~iIqL+w$d$#0l0;Zod1;wKUZH5=F}v$Z$7VH+?PV4# zv$2}$P^iQL1zM$yZj!mTl>0Z82Nt5}^-^A&P~0u68)-8Qn5Kp*Z?9C(%yQai!~`9a zwb%+?m4avL36_y_SPFct5_lCw`meljAGhL6OpzB-?aj3u6Apw39<(+zB2(-!g@%B9 zPJAj0l?RBYdq)aRq*nSsDl(G`i-BZr4xf)?2$}FXi+F{>zKG+Ep~WqDp16z!ckX%= z0+`B5%PEOTBIZ!VWpYhtw<9YxvYJEfRq&@PXcyJO`F^vtrwPMG#S{YyMx<_K(0#!% z#rk&t%F;BWER)Bi38~lb_UIe4zW=O#X@O;5Yf@jf_dT6cuGlzA(@Q?V_0Sq zln1nvWApUz!$jgyn&23_-k-5pC2q=0oQ_40L}9A{DGen>MR6EJ7&SRT7!koq^vcT$ zC1!(YFettd3AAv@{V4J>lD~wIj8kNtikdQZ0l5U7PsWll#IQ(6Ac5=4k|qkI#9Dbg zFs8pnF2l#(=&vy~GWrMVZ(bfIP_mm=I#WfIV{tJId)p3V5^BPh#x9M4X4MZi7)E8n z$^=_);lkq%q!VRdlQ6KL(za+AZEDwEO43t9!V^94!v=JBV?kq8|M%lr=TTVCEE|!g z4vwD=Ag)F;wMoEfsZf>z;YMMKB1(|~EJO@FHXQ4kkmr|0Ov=tJE1<|h#NITu5A<%JOQsncWMr>Sod>YeUm& zxr#y3C`1LalDBh05tHh7iqbFO@Igc(yp5l(MzSrG-c{Y^$HRjYl8t4~Z%+p1FAl)? zgqF{HYyRkcu?6tHjq2j-Rlhjf@?Bri8fENRS1l02bxp8dpgUbWqMWQ%gKEM_Dt1Fl zBjMBpI3_#Ye+(fKYT!9z8q1F_+keDVWjAY&_~1p`G3v0-HpUmQ zq6=B)`G}(RrZgokiw!H6me*C$ug_L2kJ072d_Yk=cf3mWz@qrM`yelIXLMA!nD1f5 zVm{V|H1hMhHQc#U_6cg4C$=~_Zb4K&?+d%`kvHU-)fAU0q2R#TDF6s2J^}-DN2mGZ z$0Sg|=|!vz3LgYB@)<3(g5`Y9LIFoxf~lz?P>VBgRCErx1c2d&gcCDzxoJc~PC2na zLaA=!bq{M2gqxr1X&ur+nsF82V;r=mQ zWQjF^Fyo!S=?|Zd26u9aBuG+O6p7+S%=3XlLZKe9s55bh=)@doY8DF#S7Qo#vRPxe zQd=2fvZ=^SgDMd@Rd`YnqBtcbFA-PfP9}L56TnO=l7waPND6*IXE}OFUo<^aK6g0>*pfrcux$&~-~5ePtS(%6s&<-9D#H zVNnWung<|to{aI*>8?5_0xHk&4pf2WTg{i_& z3ZHy-B!mn`M@Qq&2jS0$og{ksL%P7Ouu2CWg0a@8`B-gO)GhykG zp%6%97Ai5f0F+gPOdhN#o6e+cWYU%jk;cL#5ib`x77IK@v&LW+(a$ai;;6S+h_b% z^~7BMquWA@A;Yn(%dg8@{+Dg!BNKN}6Rjh84}rI;jvVe!7XLa-?$W_4NaYUbfzd%ZsY!4|PI@h)zyQMy zWuk5)bLaBY^>Qq!1XMvn2;upp9A->f-gz?iFa;D+49H|;BMXsYc9D*aD}Z?BmBg2c zGDNvyT3p;fTe05CE|dv#HSz;o;ERNa;+~E?d6ggHY*xv+@g?TQ2lb}us%uYX>sk=k zKkbD}N@6QWe)5n*vcoRCcjLyG+rz?jYs)#7bixpXY$3q~2{*qMb)1g2g+d(Sj^$7s&8qIr2t&+^XTklRxEeoX8OCWwh)oKL ziSY^x_6v;)j>?WtElP$~#bMOxI7ba#O-i1|rcdMowFSvFY*Y~u1<%h5!{vlv5hnw} zfmzT3T228Sl*iAmc9vkprGJdrKdM1qZo*8ht4%8k=VZ2_OY9h!0u+`VA_J0aB+e4Q z^>%~6R(APb?|2`nsXnf}>aE%_k-h{ucDzesihuMpAQg20Yp?*dM-RX4HcGy3dJSHQWKMza0DGCEk<^h zA}5)U83m?qL7GBz>$Vl)pnmE;J<41KnU#hMteuxT&|X9*o~_M4F3a;s zO+9}!^n`dw{Z6hIZL$6>WB^Jg6q*(F(+p^}4@sM&>YzWmsru!<%C3%Qasu*A`MAk) zCp7&G$32Nc@k5{zd-5sYaWMC?nU9DEsmJXfR1Zu!E)eI2HwOdMZYd?v z2}E#OYG6#DXT%BLaM!Seltc(BCY>9T!3P5I*ifS!I)U=L1P)n+a+|Bg?9 z$j}0lqXaWT)pe`kvK~f0eDxyv@jZ^ioG|}TpJ&LxnG?j*%$DV$9g%MPjcI_d`GHe_ z_>Rn16E38dK-l&eYKzy!XR}Cc*7axg-=2moo{p16daJ1E#0ZaEZ}0Sg#01aO;A2r> z|7=K51}HQEo)uX~&v2xLtNlgIC>Hln~~=f@nm5=qT>AEQQqjFNOB^K znayM7sVIncI%rUqZq%pQ9EiDg#+8Zc=5BI<9O?xFQ+v#NO8npE1Rz_v=xQRd65!}3 zug{m>{jjdKpIAGRuWAh`ue?y}#M`$}^X3V$<7o-Eam??VU4qYz-dUg<{bwID=Ke6( zFOe2M#^3k?@!(Hp2_neG$*T;DD!&j;b&r601;>PXpZD`P?H}(Go)H-p&p_pfQiFAo zu9Hb2qtM8K=KM-tk^+$=g@6bMSbQ$n3mbO^9p(lLPb5G<@bp4_mWTnAiBq_GfX0$F zCQH^sPu?9B^;^nwu*n%5vaD zSJOj#A9h4|y)>yWK72ZJzckjx&9{7HwEQY7Kz}CI0+wA9EPk3lw;D3oZ!D(i( zdgyPb9e*P#{9Rzwd-(_Vz+I{qFd?`@&NMLD6QXjRdxg2Ui-SlL}|cx}wZXKIG|-73vHjqRaxKevqiq1S(u((mS1@9oLPBqYXp zr@03~F2qNkiS;`h8W9|s6ycAFc4vZpq}1fv+|bpml;sRSBOYAGL6_vk5>cUWsDEmD zpnHgKL>e#^o(9f`fElm?R<@QIH^q#+K@VNxMmCx<5#<4J`1$b>9Zw-lW}!|M`$RV< z;l?pXaYs*qLPZ8%bwlWtM@&&~PVFF4QFpSd)30SVv2K;}HZq8Ne{#F%4C)hMxS0sC z=0~dDpMF+){i(3h94Q$k)?Z|N@T~sIv!dFi)1t~0Xu=VSw>$NWAL4vSl54n+XOyo` zREmE@PE-gw+n=7{*_ssClMz`*iyY9Qt=WF9X};o&Kx}4o2rxA;2NIAI6oLqj%!4E# zQ(2VMdQx}?$+uS&sqa8kG(nnVAbC;BXumle6wGMNbE6)99^w+OPCSPS!&VXpRuy#} z_@Wj>QsMhE-BDJ_>k{!RS+qCfxann=EPgG~fH8bxi^?VZH2(?jM4b!7@?PIJvSdN# zy=T`<9iE>*VUB&MLFqH9?&WAb&PaUD;(bq};-jK`!~MKtj(PgIh6aVl2W7?j3*tir zDL(m_^X*#r7%Xxb6y6TdyG>{O3CI<6JF%?CTU$H$-#3A$iA6J7k-{>K5{DGcag#5?H?DRJy{93MP8l=bW`r5dyC z+xt>-Q-(h$(3^6A-9x16D_neDdsF=4E|ClMS}f4uUOK_zbl?`RLsvh@v0N*WT`I`y z+&A+K9@XNK7w68(j)VBQrG6%!DI3h={4cw}U|%GtnCNbo&S%(aAo zfz04iMr;NxG!yQbmgE6WiVp|~h|Y;hLIlGRenq4h0wYDlN*rbTEJ}kL>XK@;5RE9t zss$%z?@VBN9Vtjd4j5j^*q^C~KUj5|2-k~oeiP6TO>HW^$en}sD*^c- z(jy~MgFRu92h-g>@_eI-PVH8hQ~D$?@NDJ<$aFDU3%E@j-64pm<#@)Xy^5{HoFarJ z+j3t*9H2R>VhKPvFWxeOGns??XCO&}V`NkGhj&UUOV3{WaP(Bl$+C5vlT{=a3)elvhrqzn|YZ zH*dcq=Uv^x-Q#23$PuoU{^#1Fg4;5}+O_G`W!^@(dwrS*J~tpW*FPQM69sYe$O`hw zh>D5}fTsr$ap%a)3)sqFi8if|AG#@won!_zu|iR$A;ld9ZvtNQD-KDnE^|4s{pHM8 za~u5QVJ>u$C)1QyX@EcbsPyR~Yv%MU`jnbKXdc?!bjI8uPxuG6}Mm*g;7Dl8dUZ#^v^A?-ncflxo(;o)g{-7!s^i;hD`TnRES!Z(K3v&tWo;y*v@jW36^O} zOK+s%taU}5J)Ewkx+$A%kjrlem9~O-?M0FyjcRPvJ~TTpZt9%mwT@w$2U9h6eAiIT z;@rsk!s5*()5T%!<>A_JBi&b*a7GUH(UiujEIH%yKt-YnWZ`#p6*)h~$9U&XKqSdCH_P&a)5$pKG^wsI1 z%OjT6NpW90#kDohRhM>-PYA75C0g2m#wnV?nkN_KsIfpze3}-DYObW}dPQx^^5M2} zGpF1LXEp$fba_tMuhPYN`KZL``-+RP}kB~@w6Z|SWa8thscoxL_{Tkk5p+=sm~ zm={_LIL%ITuPO|Yo6>7%^3;Pkg*I272hxC3>#_iqW$1cKk!g_K(pP2B2(?stV+KhF zDbtavj5@7xqO)hDqo=XOMrtsE75W@?N2z_tIBpwT@9y6mP%d}kW-ZyP9Wh>#m=k3r zFR466-kvKP$**q)*VjNAvB28II6f+?j)T*5u^VQpnydnau(SrsYKSA&=9MUGq`Drx zVbalNwzY_wnlW-CP}YF!u(JA%mMP=Zx>J?hRX5*H=;%nOZ%jJJ1fMG^j^L|O#qBBF zNwiX*TU`XIh)d+erSND7v6fOZB2)~ERSKqxPS>VWYEwv+6hW;*sUEVnj&)kqjrBCO zJk8J$t5MR-nudPE=#p)GqeDI4N}e!;4b(+lbi|)vAUw*MzQrv-(KM#28(G26sDLGK zQ^Hwjkcf{LwJ@Y3CDH-5vVu{Ap;SfU%b{g80&$&1qZxBFSj;t|W;I5oim$GNXzR-z zwdQHf)Mb0;qM19SM|L+tCc1*!jiJY=n4mIw9HlRtJ%f^~63R$vB`FEy_~fE|xJZUB z?<$cDSIX6;d}@g#jlfO9G4ohLxkA#_Qa{*SZ_?J4sWqU=il`cPzC&5tspy+FjVu`T z6LqY4RcgO5yiW+bZiAl5Ee{|&;yC@OoHiI+oK8c>lahk-vXYDFNVbkd8>w*q(WgpG z<>gXK!*S$H8kZ%IHP;A7TjcG{60ug4UN4GMRc6ZBEThCQs2x}}T2|zO;R5B9cVn ziOM)kV-2&nN!Z#^PmnQy6(tdDN(zUrZh9h)pHt9EE$-tobVUSu0VxAXh=F6ERH9Twvg?=*J;T^kPN|>)%bf?U zBAl&)(Nt7xCig6G#y(IZn~1=c(&SDaW>#J_Ei^uCX>d#F2jn|4oNBKeR01M0AU!b@ zln+8E^Ya}{QX2(TM?~l23KMeB30OovGmlrCJ=!YXTy`k*WsFv~KP@#uTnOeOTYBkJ z^IXRi&$6z?b#wew$fzCypc5{dM9+REvBX66L2`{L$kNc9l(3A@;I#DkbWRS^fXE$T zl5`YI5djg8hlgUIkUVH93oB)3s|4AVWk99A1gGWu(qZWmcwSY8Wr#DrRwwUb71?Py zT?F6yG*EjHd9bK%8h-gp_DlrW7M>~vg3&RFQ9iNpeu?0v%7FrKXl6X+}=%NV&Krd;OY3)0$J#ksqN11n42z{j4{Kb?aT}b34}m^Bf$v~u(&K@3ZIkSQk~mY1)3e? z5hd_wcDgq!0nvcb57N3uNWJqEf-XU%=wOQ2-1m_&t1$>Ba zkvCKt)zpRS8zI%dLdE%ae+&Q zOLiwBPV6oj%Cv1D12Xm|Cir^mS_`3|l$R z(b{#TX>g;ov4>;rwQXGQx^}57x($C$ERWN4kOl=vdpo;8;#9y+dpDr$qmbIaD3Wx+A%VOZ`9MTqLNez<7V^nG#?VSp}7A3DP>1wmC z4=Cqs;Lc{`Xt>!Yh2q!O>jJGsha?tza zxdV;m7jg{Q6{1WwG6Y(hj&I^r3CqMt1dh!r)*9-CMg>e%NL5f9=M5DLO}Xtn;zV^r z7_>QqUJ#GV49k?E3XEJqegQcfgRYa6G`ENewI#V#h1|x%wu@TQfH<|KNP0zQPRLd! z!7_qU5h>Y?RI;3e&4yL$u4dT^pDIjb$Z?IVF85rB4e#|QaTVsnHv zSS~04iwu!eq3ca_7$Yi|9bP|K!W+ydw`b#R!0JmB)7=tSRAlOflO+kB>Ov465eWdg z(hEcC>!3J(0+<##D~J_O_De7U4k({v7U`u^^*bW)Y(lOm_f@N=JIX2##xS~M>oA@ zSXrQWGW4((GK8lWbW&Iny=8!+S2nFo#Vxk8qlzk$+2wg<6%=8qR3LP|zYb}|um&@s z6Q>i%Az(3sL59O6dM;Ujlgvm8S_*n@bLg=NPE{;}knTLw6}ja)EWIB~u;*AmDuMbO z6~PjrnP){j5Qui6%7M)_1hXfhsbhive-P!JbBXxBi1OZbaTa#|xAx&Ie?0fR%Z}|k zcWv3~Y+ampHp#Yb+3q}T+wSbMIG4ZLQqF?f?n5sBmgTtvcyAym3jXYo@CfJq_y4D) z@pp;DdAZ}c=eO_t>!CdVs)udg?lk6Y+wu3Ue;f1MTz2dZI}AWj_PFz&3s*S1SKk4V zvu_-YQ1NMT>Uxf)i*tkQMNAlYrVF^V?NJ+=5k}rE4uYD?e_Oi&aHhq+3+JBa=iY!E$`h! zk*6ZxLbmKXH7|8N^)@i_pvCcL)^6lyj$Nsj0S)lF$Eg3l?zlljtD% zx4D}?KmO`zdXoL@If)l6*Y%HcS8u&_;P}a{j@!>Ihm7S;MZT|WFcsr2+gI+rm%9PJ z^W?zUcQ&`W9NmdHXGwueVKe??C?a zx&KSB>*V>XsF``lnfR(=SZMjl^7~Ieu2cNJ%Vo#Q;*ak$0u|fZbN8#?54}>h=Hd~t4XU<`BNBg6 zLo+EyU%nF^E8?&Y8l2v~<`Wh3^$ozSb>|;c^?iBs;U5*j=^aalr5~@@^SoZzDGht) zwZ(Q8sx16qcZ&A|7GFI-n(26n`BB}qSKp&zk5>&p+*R<6@pOhExjwx6 zu%Bx;_4v*=iIDzJD~RtbWF1rmce{-S^zbr z`aa;;9MAK;tUsr6vcvWpS*e`=di(wR)AyGSh)`ouY{r-)RM`1tvj=fbB z=;K`j-u><&w)ot=;ecD^#~`r_T^Zrpy9uA_T~X_H#~)*$ z%_|asg&!@i<3e}5lXK_gqvD2z8_?I+koGh*n&6SoYUL}J-yfc`%j(-3869toL?0IAFH(Ng2vgGFG zQUCMB$DbWJR#?1c$I-1%T^zmum)o|j43}$fH-8>2t$sV{^b>waU1MrUk^=WYw(@d$ z+oPrzzyIX=xwY?CkH&tiTi?4kXs+N>@xDR-(J0X{?niC4fd&k z!dlY$fFZ$JT-5c^%j^3OUq9^?y1l#}|IkYsK6fy{V^2;}&9~poKFkaAOi|x67P^Xh zKY8zi6P2>8Ti+PzaqpiV_Y8S&@5rCQaM0P4{>{S|8Gv&ayuqiGz%RZ|e~&Bt^`$ zz^-rC1FAQVYxxE9kbTjY3R0VY`{gqKk592Hb*ovQf+zn-{;ah#j7xtHQ8gXY>xPq_ zRV#o;)8+ejraGjT7T70uZfk#Y%(DH1ZF2{nxpc)T_xd6TKQx?B`?^8y?~b-*d}uQ6 zKNlwFW{b9F5(bwZKiOkXyaD)hlbs(i{-)gRoOfbPeDNuX{d`1myCQ2V6g|Gx@%E(y zyWHJWZHu>_90Oh%ir&8eYQ!NRM2=65j_dllnDOYz#AliEb34O!-9CA7$CiH4ZexjP zw{?>8&I?(@*RIw_@Ljg>L|Z=UYPF|q08W1v*X7lpAjfC3(JvjQ;g11N?SyAn-FW4~ z;!Ne9rHJppd&RFAcIV6+1xucVi>c53S=~JAh5lJ6!?|I1IG%@n_NVdg%>-8ahrq1| z<4>>{|4LTx+$E zWtcc?es9!~PuddQm$%7}*VgxKA-=uT@rB?A__+ z`^*J=7HTdn6Ra-m54xqO44v7&_wwS(B5JRD^)_V*``54I-+W!d!LMG~3J&P~g7uU4 z3!YmB0*=~$8y@&Qsj(IDaKo{2bQHLF=6tjEfk*d?hvlU^sq#m#J!qt@lagI|{gqI_MG&Y5 zcfQE-aChs)(&(a=?GA6$%8QVm4|0*&3I4Gk1gR`vczj*9tJ#~tP-Ue{2@@k9yy%8J zDUbcOEyR|VIqtDiIr?Lk$bMSb7j`}}lFQ;Al0ScN*EZeM+al#M$g^I)@N(^~ckkaX zRr(%$9o4^cZbvlsnA9blza%lnzh;6w4F3JsANph6SNg`N*g*a5KRT*{Ug?@zukH2% zyz^_xjtjJ~A0OQfK03NItNo(!ve1XoT=_Mz>!#DFxL{@c5At_Zwh-V1W( z^t*rlSRSKU`01D9V#BXs^Zw&G692q?en%f7G+RPJywm50k-c5K0451OGz%%a@vlpMevhArmjPpN*0B0GoDYjNO6n z@~b5;EV>?j_ZJmx^yyh2>T0nv?TqeqKfO@p`zFK6>hUxJ&^-8_Ncp!{b=9^_}hBJ6Vdr}-P_+P5y*ht4n0u3Q`V>apaxy-jcUURhQJYx|Rr zy-uroQ&_n7_`7|8xpu|-J&BsHzdITITHlQ`Pp@jg^Ur{pYYDDb`;XrtCselYUVIU*s&RdOXy}^^xjyW~SNzazrob(G zs&=_xAHM(fjrYYreiwcvf&AT{4c@Ow-i|#N2INJ3YkBj_g--C7xy8$;2Y+8Jei^nO zUHGrU!n?|(D@P6M3eM`|8@-32KE#dYHzkKpy{-6_2hVto^G4ct7y2%&Kkq5|c&+7a zLU89V-z{xugx#*%%vX&WgA&cm47IHQK;OBomBtA8VLI}`~f8mhIKd(b7d6a&7sfrrn!P)xmNHCqYQ5!-3`kU`6 zichX#uDq1F(jWcw2pz2=Q9U;`E=`G<(kIu~yCrSkOsWPyE?GMMUmI(CqP}%qt~sXO z_wE~ST>eIPGV9Un-wR)VZS3WcB(IWBW{BZ?kD}50o2aK+4?W578r$A>;?0bnt*g(8 zx3_rgT+3dk+rJw5h2_kDl&zV}`0-v3Hg*J`1&CwtHA=XqwH?|f!Bjz956*j8P5CjpHO4|3OI z>E-QBu3$$U;ymqhcUAh{gBzKi0n72~=6m%$`Re?ah!W39;!2PwH3EVMj~8&|{|d6= z?CfUE%pgoYtk$5RyEJr{hVIhPT^hPeLw9NDE)CtKp}RD6mxk`r&|Mn3OG9^Q=q?T2 zrJ=htbeD$i($HNRx=TZMY3MEu-KC+sG<27S?$Xd*8oEnEcWLM@4c(=oyEJr{hVIhP zT^hPeLw9NDE)CtKp}RD6mxk`r&|Mn3OG9^Q=)j*(>i;M1`2#+Q)eJS;_8T~ii9s>&B~a!z}b>(9k-M}dwaD>9Dr>XU3+;PLjlcx zrhr6d50kb{B96fC`#})Rj}FWn*!ec%qr^L&53<;dJNZ8Ng4xuGpoNMRe!WfWYA=m> zmScI=gviA)%DUH!s>rU_xiSZ$988ZS+;_Wy;Q^hN>N{=E8z=Sk?0O-~K{QGIA>&x^ zyF-t{l-tIwz~V2axly_!N$z=bU%njXN)qlap0){jSEKdKcH&Z*CbO@bKjre}ZQQd| z*#{1xu<3jS)KUI}Umqn!fBqIz9j^0NoR^{1AzSa@6xMPb&cn%*B+r*+`*x19aY^OB z2K4Se-B!rx(Grh!@kEEayUkR7hoX(ZHpKgFrwz(&pQ~>So)_XzP_Hpgji+3(f27*` zHD;hMNmlbMfdX2U(-?~%%X4^LqPeqs^1$KZz(=TiqVe;|FHs?9A4PQk3)DMP*^x3) zT5(?Jm+-Amz3D@uEB4KltIex}{?Q5eUfYwrZ4{842KLsy*oe1yN%;pi>~k`qPJ3Up zKUL{`O##Kb*kANKz;%LWQ(^AJQ6KgrZ{YATM6sNlhqa#@woY)Da!q&@(tB}y-7vDn z)Mkw>fXn|aM)kxYpzXHh^h_|BRqXU(G81GngLy`idw{u=vS#`TQd6s6 z2p+keckjW*fy-VF9|U9=TpI^Pw7(3z+lwCQGU8J74%SP}3o8G}bxU|3z&wc`GCja` zR=R8%ddvNj-u2PXSNklREU*OAzXQI!l=VYzYYjMCEDv$gZIzba4G519JHQRzQxnto zjscY-nRn#Z1yx;-t7D-IU4|cRwum2IC+&Xtm}t>KcoKI@@`i42W>=$0L5Ur_<1M4e z8pAz2e4e=iZ|LN?xh{!Q3c5I}>55Z#3$;?ON2Lz#myhE4D%USU zn+Gib_i)AM_9G)~cB}l^u`+R7PM6f_m4c&e1tZDYNiwG4Q_W){)hsg0iN4ybW)u4M zqWdaEiy4+hi`9O~2J`f6^N~c;89@vTYz+O*Mwa;M8k^-pXguYr^JDbBy~vit6th6a zCOtm(y{IVS%!dI^`iS{B7rHswUp}XLxgLju~mVar0f_S(-<_{I*gWLI$Ea;)PTZ@gDr&uNQCVKEGt z@T=i$1i@5=&#v)L*C-(RiWNW6>k!W>vdY&{hSrPbe)htQq>Btt%hqdV-<}xf3c;^X zR%LgT(@qKBl+JFHduA(I7Zb9OW`7&axb_;SDOqcOrOM!ReHpxH`-R2EcHl+1qveRR zNCWE zU!M?!*)OT?^rM)UlQkqm_D9m)w@tKJZJDmq7dU2kQU0u!pN;~Lpwi*#lx&-WZD&x& z66e{J;20eH{gt8-ZR>oOwJOm>@to4v^jDtB+m+(hR|+&J>sM9I7;pG&f8bUR*nA=0 z)5^0IiRwD!F%3D5y=4+_QQsZrQ@RZOEUCRwtnF~Rgr8qiO_O7uA)hgE`4$VGSLc;| zLW0r^p6});mkp5@7EW-mc5bD()7Q#!&4Bo{Jat!vSS^}g@y3PyGx{sSdh7DMSakV; ze&NTjgjP;HP_BPN+_z&YDtasdR1nk0s&)R(hV>H-%EsPX!zpf)YXWKTHd||@uTQ_^ zoy&aj+Vp_Z+h%VKbt$yr?zcT(HhEOOj>!L+{k6n@d#_}o=qJcVr~M`M$Z>0W z4ko&Fx;e^~&!5r7%q!zPc<5Wf zyu#sq+R*HllUBTH=r^uxb{Q=16N_OPuWZ?@h-VHvWz&gBKW8?d=O&<{~zUdYwaV{ryv4}{1%EB>6xpu|! zx&5zG`_9M&&M^*PIwdUn_So-&qWux~Gxtn$#mx(Xl)0B7|A+vy>gEU@A~b5&ykEz> zyKCF@u3dSTvbtFQ&1)#FJ-bUGxL*OWApEGn+-g0FaB9EI%i;&zd->jS0r5i_ZJhwbTLUjrsw{hSpMZ<=9-mM# z$YP!i=h4&T>-k0L9rUGBp5C0?oLZ@uRO4wdFbxK#!N4>am<9vWU|<>yOoM@GFfa`U zroq587?=hF(_mm43`~Q8X)rJi2ByKlG#Ho$1Jht&8VpQ>foU)>4F;ycz%&?`1_RSz zU>XcegMn!am<9vWU|<>yOoM@GFfa`Uroq587?=hF(_mm44E%o!3_JIljO#zJJiWz{$HHMivHEx_>^Fmywx)<##-ngMkA$*_R>m;YX==Di!Rc z*B+(KGRW${NYAJ}PdpOU!1f}I#`Z-XucM2i6OW^D`uAp>1;lK8P~C2FQO&DIvtpf# z`rl<@*4=O)$DTL4g_%Hh3W~HVNslZ(sgi#oZZn4!^jUZ!D?-j5=;lT`2gPnygwQ+4t%z!5C#(DL@Sd2LUbg71Ojf>i zz;RhUvR`yxlh`8{kqe3DZ6oHvd%23CDX$lIn>@;Jn})i@F5djo9&gTd)_Ej9K(q4* zOke7pqk!W0b0n0!58ZhoC@y`q^I0b(w_{-Ltvj8q^+GeGH%DSdCcNVYmAK{vfvCqD zGcf*qDBy(Sm%xMZ2}o-}60z>Y2_`NSzs%YzS#-ho2Lw7ygAQkL-lE?0)K~gX9VU`5 zdBsyNv`AO{(&0^vwiiAz9QTp;my8^(RO8dS=XLZHHY00pR=%t6C=~ABxp+QBbq(nv zVOZahUcULJ3uIDe^ny2LD&gTl=HvV4cZv(ooeAUsIbN-hGEd_j9f76)u~(H zo%ygCz{Sru-M+tYx%ko?)OB0|XeucVz*6ZMndn%UelvDD5IxXP4ANTejNJT?mnaSy zZEWYnnm{6P^3L7g42fBT-oH~vC)xKAC(NP8|KXOUWLL4_uU2Ks;yLg2QGRN5V)Oer zZe5ypVlt2Sg4aFjKSOMlyg>ooEzH-AuuwuY9@;|UtKox@%AOzdn)X-tgo5n&H3RQO z-f$jxp=3S&`oQ8M`qriXPzIsFU-b+Q@GzKaCXxrAv8LbYKU}n&9D7&(nnTfSrKNF( zMm+`OkQ4muqqF<-d!a5n_c;~(+e-Z zx#m@A7h9{mu?0DR#-*Ns{`(2(bew!3>I<2Oop^~NcCP(+4*^f5!Ivq_ zz-%nl^%S9TlneXp@|~AcrizvKU*>&`o)le;{_vukhc__3Bg(B_RN6Co?q+yGRC>|Z zR(BKc@hrL%qNB0!&*PaEjoU$HHw}}rD?h*OxNCVX^W)=%h;;Uk3h!^R;r8zA*1w3P z_rE&B{;ia|3+woHO3QR*=vSUEU7n!DH(#B*P45}0^Y*r+#q2+Yzs`3&o6vskUi<#n z-qx8X)>T@xE32Czs2Zw?V5ou)F4dQGrn`r)7t?k{(Ek{A+| zbjEnSW*FMX;+4>vY>|T?%Uz!%4V{c}0)A;TR;^88`9gJ~AB(vSad}FNnFk4F>u$FU zdzsD(;oDUfO4peXiep!_9FAlU?)3oF{^X4>o+}%VrXZ8jBKjZM z8rIH#@HAvkF|qYHo4GZSUS<|POc&a#rCO%uV&pH@b+&~9N(&g^&&M4`>})>-On@EO zB?E9MK$zhu5@mw$vF~~FTX`(flLa`bolGt9f-lSstg0Zi$4 zXU!qcW%=Up+0WV-TSc(nUJdl8dm>)odsRmM+vbl1OKS1#eX$nt*NuW0HI;m4+)#4) zGY!`` zRg?AT?#}*uzuJD7igk@{mpUPHkxSS~*Q+@%I-oG&=4)QpxPgO=E{6})Ppx`Yy?KD>Cv~J=$!4w&; z*m*LMPE$}3()ml}Qu%9jbKKiM{QQcc zZwF({qw5~+O28`-)syTba++0%Ng|XbDCBbgMAz$;V8`tmtI3)DuDlOmQa13|3pZ0g zU0lVq4rss&r8?HxITJFZ`E>@$T!ye`td+jq8o23nuv#?q)yv?pgGEBlBX2Me{o+$i zX%j{sBzt}bxQLE)%_8VEJ%gLYjnSON)mJ^J*Ikb!hTpyKH0~r-U4Q-FZMjo;h@s9e zIz!;F=+!1)9=f+C(Xp&o>3KU}%;q1D6L|r@Uu7ncJ-qw)a*_}y+5X<4^1a73YveN? zf2kSN6o10F$>t95`Ef%{ zj)P45KfL_)tCU}%mX_r0E=N!GyJz2jULk9yM)~DCBK9+0hnvX}QZgtCjToKc#Kr5MZ#w!F&ic6~}WWH5~| zrW(Sm?Fl%<_N zA;so!A@DZGDVzX9+7Y57YHKxQL)`JtkHy%QGy=RmxAki z1?(9k(7Jm0^ah$%Oqxn>y;fLj>zbjavWuW&%0_3lMVXJ=KVR$A8cw}&@#AzMhN8!~ROy$=iH;uMQdk2{ zB?;>8GZ52ct7U)Z@$U2!o0g`$NPs;aOu3xbN7yauF%xYmZdjt!Pn;Ez2y#g16`RB+ z&%8>CF;+`%*DS4vWOhkWHYvA39AJGTeGt`_0kZ~yC_5k>5Ch;vfj_{95%|Nz%EZLT z$i&9N!pzFf#?HQ%ZSUTF`?)yw?dROTcQ3~w4o+^Kg9i_?A2@vE5YG`Vo`XEpO6VAX zYZ#gKFfr}n*|&Ee&wu(u8K=&X0MlTg;{rxUbPSx-Y0$y%w@RIC{QhAEetnVyC`tEo zG)4U{I(i095F-;ai#zqIzs#zr|II|*6N#4^H9*Wihx$LR0xsgzLNRmk|BN|5Ha;48 z!)y2K+}ej-GZTk57Jh*}zRxfNOR{_tafOBT^{&E~9z41t(bh~lk|Mw7bc{jb_|P&* z(n;m%i{5K2dIbywkRnK$)<4vy|MB^6=%0Vso{H8>f3q{n_e{gTVMR>;XeNv-KdsiTp4Zcubus<9M{QRe}<^k%3fS>sD9&J=# z$%*=LA@wOZ2JAH5=n_CdAnE|=FtzlbzT|u9KOTYOgeLj4%u#AVYBT;e0sK*(juZ5w zAaydr;d~6orHmQsy#@FUGJYnsqq(uEdhPir1l;J8Q(2J~+(B$pk#EgN>K;aue$8)` zIh*VcarN8d(8a$Tl~6pCR&VW?+7wok?-pO9`@g~2GXlAnf5X|I`tI!i-0#4P!U$qw z;bi9G1KRZ;ygdu>>r>SC3;2RRy5_g{i&+{A`Pu0|oPF(XF64&a?tQe7Y7>biyj~xC zVXx_l?x+oVBhUA(=Q)?|qYu3gJfX0^Ntv#6pFbfEp8Vjo@V`7?>D; zI#wq7DoBF{Q0y3W>i9D|`27U|QiP05kRKDB@A2T`!nyk6QP+UNM*(yFYo&AyAbLjB z_gcTlf@{s%+y43-%0578AQAw<O??jqejN0i`;pYI_=ljuCrx!U z!1kWhpdrHzVrw~NO|A2v0>O_uzXyT{Zd=PBJ)5mDz^zaiK2kv6D4?v!%+TcN?8I6t za_gDZ#hl7#l(zzukEg!8I$2jx6P+*=n^EUh(;+Z7t{qlSxeKS|}%VNQjMY@ojXuBYPq)$FB zw`Phf#-3H%-snzDe@sM{u2-O&U4Va(T!g=plaJw8NqkqUVy|P4v^vtn5ar}+Z{x-d z(^9Pu6ON8BXtOaW4=OpU7U^ySGj)W*-1t464&anQNfBLY?G@0%If~ zJnsF&Hh?GyVgP1FT>PBe2l)gPY(lU->p;mve}A(lMkc`~ zSlId|L}FkiaCMmF)RN*EiS=!RGuc~ECcXW=kPeB(o5*I6YI3J@=NT83u$;4gut5H5 z!Zi$P?4n+s*fC>|cHLf=ld)58d0rihF0In~xGV7d#fzCIC*o;FLNgMcAK8Py8_6Lc zd+=8yVWFpvPyWBy2n*Bq8vaci`G-Nv@V{dz77nP&9b(viH5{rK=NBkYJR8tPUz6@g z-aG_DDqKl8rM20%S=@edSieNBs}E~#;Xk8z>p{&rPab7ed$V~>(k|TF~a?DhDgo?YCpVmHfb!^bCJQDC(7f#LCCSdC1+PfcR&vIiTMQJPUIJxrmi9k3@7H z|I{Dq3e+G#jg$0$3X@c|iH?(z1Ne4nS#(X;o!@R57)c&JG0ae0YD{85j1 zJ5a$%s?Z1m^vT~pbevis4nAr3J1>7etp*=bo3GW#A@okPi`wUhwLfF#kMU(8Pz#VW z0UGSjP72TjARuYftM7GuA7lE8bvQAtH~zxT8uj%1CBPT|rIG1?mV~%tiQg~zKG+mJ zBSn09BzLyl%q#=AXGernIqU2&q&1h}kNY6<7m5Hg{jfth}>y($LD6d2*ufi62nWj*Dh!g&}f0tf#Q)pNnI=>Q;B>6eR5r}^ zDAKex%Q@H3j_eG^sD^i|B$7hB)8V+X(tL6^o;)^GKQT3Wbzxxs%3$-=$yjS)qBf!~ z9tqVibu%yavLGor6q#FO7{@dqB6A`N%PXsjiIt@@-S`{BgTu4E9W$7$esXVIWQk&w zzlJ@`tia5s!bTgb*~XR$W{5~1_vo;+=(Iu%mXJB!l|47xaA_#9eLlTpzA58+UXfr# zxmy}SIl|4rOUX7&%skA<(AOv=Fe)&tl$hP!Q-=<=F3a|qoh@kX_HSK4XO5R;-K|JJ z6A>g0_f~e%Hh`U1Hy5`>f!%%VBYmS|0=!|6!~nbXzO=NWppgz}!%9w02RM7w4~owT zll2ZzK*9`NRP;SG!6pih2(T~I$=4Pg4@--1y3ktKldO4ht8uj7yJNQ$KO5NhIuT0F z4z;nhRdCQzGf+|bL>X<9Jxa&d@)(Jr-*hD>-D5?8X9v-0r*T!seN)%jkJyPb~ zB~zVGk$Ig(rR0q zxanqGjSGB_pgc0V)Pjz5BO3Vj+9Jsbm^LD*ZF*v0WoL1fAX6O;%yCNeJsX^ZYm#&7 zo0^)I=KF^)4_DZkMBBhEtqS#_S@5VLOlfI%OWE8sv1$>YspIQoh|)BPGj$FNOGqlf z#SeAm^j^SV*NTuz&X&3^il%P%J{}=q?hR!DJ>Aiy+4#_Dl&6Y~f`X2!nVApLJ}1kg zt<1iG>=;~c7qAdyd{*|1x-!_-FgVCOF3F&w)PPi@f@=5BZ+BX&O>*=g1SOOW_1E>@ z>W{V4HnWLOz-0Fgl@tNnFl%W-oSdf zyIW>$WR5Kj^BoHM-!LWG590cNnG!Lvuu=zWBGhC7Ro?nN(tMxL@Bt}AK= zxTArBN2uZFcXv+x2R#t$s6kK!h&K$t4}bhOPz5IwABd5QUz%A9f&#p6Cw1k{_f+za zDbWhL{XC+wc0;bXq5v{snJ>xDcI2k$4VA5lH{PCcFSX>q#V(klz8WKA!ELws#a`*1 z+L|95oBz72r*CtPB!ht$jRy)o>Bw1SEbSTpI#Yb4!Xakkl#*@QO;!!(G3lp%d?JTR zm@m)ioG_PWUE(O!pX)8#)76`6D028q4%1_`s4O+0F1shthp#_`&sln#^qMd&YHh))mfJi}AY5#SW0xWX?veLgzK7I(b7fody zwaG3C`F+N~CDes8On*s*Gf}5N+@L=#;}M5j;^=yhR5vO{_jOyEl-54%pk~?xzh~N5 z|1>S4r+W!v?$`<2T%X#a1MZ<}v_H&%4t3vfYaiAcZ zuipL4+%YiF|0(kZKs#I@20nfi2e&lDo%l2T24wEQ&o#wr2~vcwRn2=)V|0FsmQ$lr zPx5v?9K6VB=u%%|ZUfxfsqe_ZUv3RR2DE^x5{Z9g$oM#QP3FPRoWIP1NljK}MpMM% zPt!t#+cKPxyCW=4&vm@T9jm)h_@DjoTaJ&~h9{{)_+OWz0O>a^h&1ZAoZa^{U&u+$ zH@u!*+9W&fm=dGPEy+|}0-fwxF`$AIR2BL!`uO*i!@zR)&hL%?J?AI<=&gum%hG`@ z>~!Y+9jW$_^oREKO;V=1PYJw)1Ic)5J>OSy0n5XFpXB~rf&3$P_+5S$ITv&zOrqw} zI$?rOv}=FO{f~-`mPo@_D|(%qLpRRF;UgzJ+$_QGHu&pP^5|zCjHM>QN`rwI`(+>H zD~R$Lgfq8`RqOAtuCmbSKc}|>lL|2~yHR0Z1vi;5u^q__O&D~Yy4hO!(C7A4*a$hg zrZVV4Us_8*+`L&_OOj`&U|N5qbCW^Nl6(0~Q^9Ow{?J@k>q2wmZp+woXLrTm;9$cA z#Mt$q$?fWbdn$9&&NfYQYon%XgH2u6((hlRybz;&mZiKC9z>PIsMN-t$C@eCNa`&5 z>6cpQkEfWFgjo0EEPK21o4b9wreZKxe8&5c1Isn56(PNu{#8Ec9@F$*Yg>X^LVqNB z%)4+IRk=VaoN6KrPS!Thw=`}xjLeNpHVjX9v`)qjUU3;+c8%@U>6(fxTQ{4YhF+PB zEo;N9u2AlxC_7PuGeZEy|reouFNhH+z9A;yxeeqVgvoKCmE6GwKNo5%8LbO)7 zpevQCtlXkzG*#eMg|ey1hNjfG5qiD4?=)Q4_UY{lORqz>rUo?@CO5&uMxn@ZjqnaJ z%tQc;?3p!Rp4w4}9Vo}Ow+yzg5H2iqc23m}kb9;p2^R|6=kn@%%m@1==EySM#pY8( z*w&52nU%!rgXGTf0&}@?nXK-pte~@frt$=s4EBs>FUq)7N3SbLuLNx!RbodR&BKqn z4(_1Zr%_ow{0g%gmGJptZD zYSC>d_a?o>UhCxcoTR#(oc5Zm!j^K}M(yC%?AUbU&~Q^1uC_a&s~d&svTd$Ml#Xi* z4(ZHy!&9n4rl%UlH;Om=2QJswNTy{ed&VlZ=0b34N@O{8f}vcbtwv5Vv=C*4&#^AU z`5`7<8t##MHav;F0mSN%?2N$dBy@>+P=z771?omHMYVhT;9YVWLo zhg8YO44If^nnra-1yp%w6Jv7gDsklfM)1c#> zuQu2gT{7l8xfrn28ed7MzKrj^Jh-@lPZw@R$``>E!!;FC-IbEW&*wQPrv)0KVzmp} zlgm3S8U~;h9U&oe-q^W{0+Lr=YH(JZUxo{^!QTZVitf~mD02&{^^PhCNGmSLtj6aT zx3<=<5D1(7ZKEw@LVbCDZDU9~7Mfh7(p|3I)$L83f_61R(;LwjTd=d`wHy6|>t*9t z+LEM8T_tMK#wjX_nI=NMx=N|GswG)2nW?5lndYztv;1Y-rY9{`vtEVyA->hV84*6% zXf)On(c&WJ&w*zYCS{kBv+y0oyO-r~(|aA=?kv z3~nX}^wp{O=DClx=Cw^mO*Rp)m0^2|Chy``Zj4kr#@k9%TFB-YN}^R{^jN8jlHqsRiV}8EvtnS ztHs^-TCZ>Q1u5CuOJynu<`|s|Qa>N&Chz47E<$RTw1%gX?DMPLQHvh2D-Ow%n8IAY ztR&y$2-h-mREe8ahKx@h)GNb2Cc`EnGAT8;JU6#BD|@W6{9$QTcRyjUqOh$4T||~na7$!Hn@RADrDs!^-=LR&b8bPABPP)!#osx>+$~1U0wEd{sELdZ zM5l&DnW1BJGqCv9OFx!=Ms~L#>U+eF$o{ zJg3(dkro`D>=GO75a;a{W9pt}42@7h_$dX41o_5B$6#v;^XJ=IGwgM%Dnc$5$7Ar` z)pbd=?PXDAnc6W4%0X^U-TixWAg8^Z5KC=gm3e8SSPb4Vw<+q`tFg+Vn5!>(iMK-J z#F3i3_Ue++K_+MqdB0@c;4o|OfPv>!3Fd}La2GVR5r$58M5RTCdwNA!L;b8R!_RpI znAmt32L~g=5`tsXh6wo9hMZ@edG}i}#aU=CcZt@%T1&WN;#{$TU#eiDrMz9z{&-36 zwH$LyM)i7KNLl*)Jmwu`q_ipN356I^feh>fiwZ|sDZuq)&~Qa3e=Uc6btEAa)(vs1 z@q|v>`}AAHUP#GGcM9|Iva)kQ7W=WM^nZoIA}VYQm3p9m~SEW3R4ED%?TU@n4O_zr>n?+$Apa^$3+`|rH4U_jl z2>Jwq?Sst&;t&W#dPHbR96Td0urt>F(ne8xko%39)~d=3?<7CB&*HMa9P>)KpagT3MYXoN>WT10ESad*7_^iXqRbir&eUx1&AqQHH0x3u_ z!}-pa`USSvR$T8AwwB5+v&zJq#EhYzJV^D+HCnnC6WeAv@Mtw`H%&)e%~(nYEohHJ zxfZKJ)66s$%w4W(`S;}n)%~*|?vXsFsTzBwornP1!cxO!|$xes-Z2x(k$9pCmf<1 z;OAvzZ=>emY;J>8b@ni~^Kc8cNkH2Nr#iQW+mw?6S7Pi6;PM-*t=?WDV1JXaQnQd| zw2+07c1xUu0~CyR@#%|==&EepjL#s4l_YbK@LJ@hOk|Nj-R+UU1|6?S_re>i*1+kU zipt>%=B2W(lL_8!rq)G1n*A19jbKYmFeKa(Y;JF7vI;3&4~2FpgOxwVnMT@n-AW)& zr&B)UzuyiEu5rxl0u%3!`**nJP!bsI^^9cY5%LaMey&7$i*8+0jK5lsr9n%wc^%j! z&P2<>(a^-+R@(?FWN)SJY_IL@=;LAH8sw4@qEr%Xl~V?}9E*5)tLNchYFe^IXuMZo zsiByczHL|V@d%@%ZWdv4IRVv?;B?V|T&aS^`1Oro{8G%jJ8|tB9;oJsmZ#O8UCE-Y zk^;TpaBD{|F@s1$XRFzP7XJ3YH`0Bi@Y!pmj+k#fS$7T0;~F-JRj#NndT@`Yywi?cOQ=nDuL(E z1})t~mQRH~e3HEMsp-yrZ0(f#X|FTc3o)KkDMCaIP~!oAAvGVcYKw|#Ym(iybE=aj z+Tk7wI3tA^xFyoe2x4NXVQQ*mX(FixR(IEN^D=hx*TRIjrX`yVCs<#~u&65t*cuPQ zmHRYzdpmkcIAGvBzT$d`q3&}ii&|IMFd-PHEdmqHAjrIUp0x6=4qGhZm}J_wZQJ-5 zsUBk|QgIrj$-~;ZCqo2W9B56HS1qs+Ue;H>q^Omf04X$5cX!h9ur{`a*vsi^Nq{wV zO%3&Z41Ha-QE0=I5X*`b$F?}Lt0)yB!8bLCucj*`qs9SS$fVOBS`L4yN zbY<(=d5Ggl<|1}NdT^1G4zfa45dCTo9utw&Q8)Eaj_Ap_!~*e=`;7x70?&WR%^mWu z=+X}xO4PuD%sRB9?+hMoli-bXLn}#jNUJua8s3(ZOZ5{iG?OH0X@vS3`s(SJ+Gr|S z7z*i03TvoX`Ux3(8p9FBSh!9~p6OPo4L;itpR3*;E@A2@)YNS&>?&a#1Ucnk^2%b184hVC%l0njEnbftZ&OFtTF>3GidxDfy(74+Y444;ai;jjY>t`c zOAnos@6i#uEGAZGAY`2-RI6^{Z>Z~Hpkb_cUR+6C%u-mzvfsoU|pVj3ZEjT zd?CDnbfTtD4>Nkoq2mll!P#g=mK`q%D(7LVhGvfvD*NXf+n2hh8oH)~N0uDwCv9tnkmG~Zm#(f?snsCd zQ9AX8T8*CI`cy}Jtw+sDeA{$ve{L8#5Zz)J+Tjt?n~*oqitoGF(L2_90oOd@)iMmm z_jopqreB(_o|~w%f~FWGSgF>TX_a{yR1~`72GDiu5zS5Egvel`6QUl1X!1>IF3N8h zs%~2B>~Cx7k813+scJUu8Vczc&Yv9^y3$pum4Q|*(m9W_*2s;pz}5TUW}^s0enrK> zI5?sT>{|&%*M_GP>x&4B4b4MM&84-C0pt$TiU#B6rlh_u{9^muW^=f7x|33xp==yX zzaYmxyWO#HJ}SR4I43p$=K(L%LE_va3$rrH`YQ1YE%o)}sw8}sT{%IWK=f>D%AaX& zzEnH6*@jfg(LEPsr4)hCOD8&~Ou=!3h~&bcv;cU4xkt8sU^X&7yDGPEf>1V6Usgyg zf|nJVmXt#}n$Rs(h2v%8TQv)}yX>XWiV`6%8c}JG=x*1g1iI>Y3nx zOi4@5ZYay1tIMygNQtY=cd9GX!sgnOunGM+^^4_8n*{P|fxd*Fj$9~0H>}t$sM`)P zhzhCjOY--KHE<5m^ovG@C)E}fR;42c%Hs%iIsPSSS_PSknGt@ZtekDU zexkBTr@iBpt7|?K;^SlvwszLEc5?J_PK>LA`}er~}$}0>?p+aqpD2p9E4 zl3R95aG^Im&l#OV!j-j<@m}TSuH-7xQvKNNZc|A_lyPLIPePV&oP}FdRAPEtSw>C; z#;hPUxGleXqk??78Y1OdYyoTXL&04AEj|5l=^>=j2;ZV;qkIImFJbt0dG1;zOaVfM zx@1EgjjU~b{oSh5T{3fFMyc+how4{qWX5Qa!$4TNoHLHTXAWrJoaMB`H}>WPk6 zqGv%!BoSYV4{2+!nyvRxLDzW~d;1p>%ZZ*<)y*3{sk(*;m|JSNbwCL`t;IcJBQf9H z%HAAYobClpcPt!4XjdEmZ&*ae3zGcHBC_wBvi&JP4gxW=0DB^USoZ+w^E1?iWWXvg zfOh+B#V%Dv;RL`KE zf7HVXtX}2<_ORiXfw*&{u!+Q%%;?Up3910`r$uFZerd1|Hfwys25(tcR)l*t@W6XG zRefKj`|Rs29fm4*NLZsjd=_%9*LnCUW1&M3)sH!NXWutOpxa#F<|oC0@s6h=Z;Sbm zY%ob71G&T#tBg&8CUhtPn>~SG!-lqyyZg(-bOlh?V~1UTStk@uJ*@laTT22jICWw7 z3*B%_;e6cs*}mCzfZcN0WM> z2>Ihq5K_(U{Z?g6LUQ{q_ojAN?T`aP-@j?8ej~`!awg*)jsSns-eBHyvhUZczaYKx z3Jizs3rrKf;Y8GUV8QP6R@*e(AH27q`%5XX6$^$uU8*No<1d$ z4Q_qvLg-5}te7~R+{yC%Kqr%qvSRexT1iJRthm^Q1EFx6`wQxlYTk>R!pU;!V(Y)W z?W)yZdw3^360|(@@Ej&Eu) zoV8GV(6wP{YttÐ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 z z<*rz%$6Y4_P0#Rcf(?ZGoybik15nEF*Dp|VA4x#cCD_|*kAYU`KIsQ?J!#~3|Sb@ z3KdTkLpKjf{D!$$G)jb-ul%Dr$Di`tw`uBi*34uG&Nf;Ddfi%L=OLZGBMg%LlcD z+O5fB%g8LZ@UfB?vLrFYA%eVf*WF)@z{s$xzc_9k#q=Z|6=%h27?s5I2t-&$eq!4G zw7g>nqxON*OA`|)VHsFt%uq#nJ0^XjDA`|KM^8`wpWb0aFZjo8_P86*tFCSzl;`+!; zC8bf2KQ)ZrTxopkj>0|&w+>h7da?^GS(<@%$N;rsu_=BLfjy~Wf7>0D8|3&_UGE5) z`^>)i54HP5?%ZA0!k3a$_qyIX2;ZV(8Zu+b;}bCnhX9bA*rc7YX)#9=_Y@?-<6>JN zBmyR}JuO*Xo_VGu^^CeIK+SB%7s`-16k>WYGB2jQ0Lb2tLZ)Oep|G+dcnzeEhcPrj zk8?qOYwmCxjz>Ru>Uh(rw-Q20%avo&s&jTS6LyPt=jt(;ZFw?V!?{zPbK^J``M`-y z*4Q%b;)i|Re(+29=bZEQVlN3iRR63tBq;fD*cA!yf;iQ1tjfICdZuCe1HsT)h;A-d ze-d8N9d&vK$QBz~mw1$roJ!A)gC0pu3y;|ypOF}ub_`R9O-rp$g_M`Z+9Aag3i>%% zri+~A!^A1Dc^w1@3K0b9OO}(q+m-MXfQ)9ENjQFsSu-Ic+ z31O)8WA%lR^1P&pj02vsI1eR$Q-y4zMwuY#NO}hFwoWfO8jZ=?S%JtYjZLQ%l%nE9 zRf)spF(&Sj-qz$<8^YO)i{UU`CJB27!V!?{_80AHf>4Jm0n#wLf+J zo_C?=m6P}610OV$x)LQf`1OfVm8l164u{c_&^h4=hhx$rLf(jo56?@DF3Si5KxClA zk>tH+Wq1Ijmv~H03OAIb0w7p)WC=vfHcAqn8Am!;U&qz;roxpM~1!`lN_C&76X8=a*ukLB$byFN&N>2I%F4$i0*Wvz3xt&kV-@i(dHkR*+uNE6C<1^OI&0EldqC`@ zz03&cN!0e-sG?3rMJtn}CR+PS2gl1?>x4je?1gvPm&OtSkg3Zu)NmOvGCkPv!mFal z)LC(?v*ds<9O2jrQza@cGOGrIXTNA#_3l}_r(g|c&fK#-hzhEVIK;{frR@(X+?$$y zIQoslF~HG^PKqkZjAxhS3c#_gB^iqa$Ncz|89`xZ={^bmNNaXNG^&(X3qO{h3l;FPSJrxNnNuy>G`4ujtO5%vgQXpl=D)_!x%j%vHUMG>9*7n z+q7o;y<5mH*Ky}o(CoM0^)5g;D>3bND8dinK|zY3)`$Pv`hey;a-Qw=UChAjr9<+j zM?N`yWNr0N;m6-{oR9PVP|CZJ6gK$Wy-UOA%)`|5;hc!xvKV7yhH(JWy-xPdkOwU_ z6CCPHF>(-wa5a#6{Po`B&A#J?WutDfTD4Fh37~5|!ZzPv*U(Ad)bi|V=g6r_|Cu7! z9NIU}9~kVN4xG7oeE#;?fvea5ANJk@D9UGB^c|Ql&wwOB1wj-P1yoQ31j#w)oO6(z zk(_hRIVZ_kKoBIWs6DOMeZJzUJ>$0g2Gc2+(tkW=PbaLrV^Kb7AYrU4$*&W{* z9dXe#pk6bw+dF9>rMUl6!@#w+%dHKaNfrGz<-dFS<9j8P#>E<>mWUR9AGAT^TFAx^Sszz9)2c%xGo6?Oe7p zUxJZ96y8dccIKpG_JDnQv01K@L5`w9zLr5!m|ae7K+cumyupORoY)el3&mRA6^6kT z!SVT(xw+Ts>xVDa=hfBPmDeieRqK|Pg*CO*_t#F%)C^tk%$UCDKG>x>*I~vNC3hs+ zMl2;#BcsEpVB9{lQ7*fKlPF~2#i_*!gbM_777P=;MVzOrkfNoaLc zdU;b>*>p`!cV%gEagk|WiCk8>ZA)upOMBx${q$^Y_jptKRFhpt!y}=p$CF&; za^v;#>NV2FY|~qeq7qf24dtVywKA<8i&K57J7X#*!i#IYqoaJ1Ox@E|-HL5uFUIH8 zbk*0-)YjJLWJF}7n-`QR=2lrYHYN35>Y41qTWK1o2ni9Nea5Cs zE#QhnM4f#`fLXexZj_u-fU~|=o>f4bFJ9|5wk$ErHzG|hFiX}s#3?u|Dd9p}Ues89 zPGLiCP)(^$S&3R&l2t)yN^N{^U-Ib9lB(HykC6iPOO={eOZ4hPT8q05>5li7L0#lGXEie1GLoyh^S6`K4(0TMo?S|Pof!QCdl znOYZYl`cridTZ!J`rCw+J4Xyh$6mS+m*5j(>k%q#AFkz}=o^=mn;kb;mDW=fpI8uU zn-;H>lckxN>Ry*z+FLMoHNR^#EeQ{Td(tGDvJ?k%f^SqCoR086=Ur_Ob=54sUfnTP z&cj5~TUOCu*Dx;BIkwq9wKE{7%_}6r)z`qr6K};bw!kwgE+;FtyEuNRGA%IP*C;wf zC^B3+Ivj5$uPt+QEU&&Ns&KSSxzOA2>P7X@BIlv3h*P?a3PxAVoT^PdeAS%{w7q1N ztqqh6qx4PiRKw*^uez9EKR+LR&j5KBZ$mfh$PkCtOrOpi&#tD#;L>ob%4DfnPn}o? zw?wPLO8fDd_~QPE@Uc|il?Jv%9ra4Lh+(guwb*0{i*|L(RuzL{T}M9+XLThfaTya6 zHPZxBt2TF+p%Bk}KUWVAH#J9h30qflAIGFvkIvkHo_wF0;$Y_#cez*(mGoe*8a$il zRZw9!FcLbjQf^-1s?Zp$&=ul3k{o{76K^F>)VN#QwolhGQ`y{2!CG3}Oj6$5&cHs` z$*tSRqs7fS!`;r=*-_5YLB`R;F4#RJzzfMvoo=&7-70{mOJob%R4} zm5Y6Yk3f#SeCGwb{+O6CzwtLY1BxnzDwo$SN^kycL()XcpA$ERwH# zy2RP&vK!t?P>opQb-Vi2;L9rN*>cMEB9d}vWrfbEm@62B8)=tYX>|E&4Y)~$ImwzjD4ekn7co?Hus!J$ za_*A9WPgTAaDuK)rs|16bwM{_1D})er8+$|A_a}6w(;EBjnZdQ%o!s0*|dA-3@Ti{ zB~`ZUm$0B`G^rdWEv|b;Oz@Pj(7BVIa-tO)QaPSy+HHj{*h^^`i=HqPlCjo4?|ddO zQf4AbwJl!SCsIw(|D;5`nR1LqP@Zl{r(=EIv9>GTi7l!ItqNx|tWTDU7}q-|cb;n) z!d@L_kTnDd*6%3gqt_Klx4yjzy5ld9f=#v?^aV}}h zy5O;$NZrxtf-5!>1#wadJ$B_ee*JcqmC-hty@_>s1*0}m4KY#qy%#%j2dC}ox?}1q zdgcc6AKVJl@HaZ0mZ6e0=u#VHTW4linC@OWklGX*-)(*lSYKl-1KZ zuy7^r#)z}1wV6m(g-KPHO{teouBAyyX~@OS*eY+|Qj4&fin6Y*hE}iq8uRj&^0C2= z*}mY>E^~f;H|6R&tA+~ABwM+7H>akC_}+5wbO)zQm!$TlhRfwSMGh&2Zf%$AXRlTb zHdr?lojRSVoM>(kcwXJI%EP@NF~jOYjFX!~P0oe9=6tKtG#C63Qdd;LtxAi_ z+0H!y{--S4415!f0yPw!1B_f+f`gJSL}@sC2ZZ=F7DgnNCut;yoX_!Yxtx-G70>3x zd0h@qRPb)r_41duSCe;)u@7jy5bWpRhCh;+7T;VF?U(GYofht27ScVQ9oQbJP_w#3=V$=J%kD>x=G3U9?Z+(k7ZsQ7ASRcEACfwNXyY}(zD zVtqqXO>JZ0Giin*g#o7K-j?d-qWS)^Ir$dGX*Q1e=7p7d#UqZojW&t}s(uwhWgA{; zN-9d?64sIug*LL89=eKV%0^Cd)lr%yz-jE zXQfV`aaU8VbWy!vd`{Xx*3MU}DG|?^$jAn&xfWYjHk$bt$p|IO+4nkEUbhY$QuRH4 z5`V-;TMK{0TkEuxzKnaANlmnt^Z8T9ZH3KKb!X>et0vufBhTvB8JA3%1q`aB>BMDQ zW<=U1;=i|!h|9{Usg7tY&Yo^cU25|_<5FOk>uV5_pHS`-6kFKX;8T)TaHGwmFEd;= zAX+mb$}TC=J25;qGdepfw5}k!zsR#cD_JwzL+pI2N3NTNUut%_M|fCTU!!wbM9%$Q z7Y)@&<&!QxMp15OT=T4Bi!{CZEPNUjlixb%i3nwxNb8tNWrZrJ_(^3qm>ZWX#0(f2 zUK0HOLK!Z8g6zMQ;bJBH0V@6l+W1q43!nxO6o)R3<4hDa6;2W1mk9m`JA)VEq6hxe z;UfH1h)YmAlF8aDGivmZj4b|n)<5?T{##8i5W=q?Bv4V~|9Kj($3>)qsF8mb$2Wa{{UI&iSz_Xg52l#%QU)6=SEX=n-mji z)dC;W7*ZceWk31mXMY!qD~@*T-p`S~dP@B=>pPn9c~7IqsRJnu8}a#O%}bED+sw=O z6pI|EhTApsZ6b%ZMSF;!R++<)>k%uj+?8*Q>^Xf2itSsL8ar|(O8;O+9N2$ZYvZRG z5-Dycd17DjgM7c)sJkz!io6{=GfFnNVxEyvF2<|YZcOHW4`?%AMQQi#%BN@R-XXXO z2AkHVi0fU?9VgMfvRb5%JIUR;N>7KHJT9`6&jX&{Cx z+n;>G_a%zs7@SN^FtYvrA?cEk<9-+KCoF!@Qc`y7X?ZSc>sHRyddO-s0A` ztv8$K!Z_(;ldj?;!vlFZlvu~Up@>S^!a zjczzgpVln>l6%l?ZD4PhpjxT$QVadpFN&{aK-zf6>878G@_qjIRW85ha;uGEy}aIHo5uIEaAUkfUCA>%G&Q|*Q>~RHt*RNV)TOF1#~M&h_1`NGf1D1# zQuiS-z<4F_t!KHWWgkh)D_F?pEQE}=9I?Flb%$VZ@qKA%m!Kgt-1%0;^&8DZ_~TH# z>et4D*lVWufnQDSFMb7VSN=@fAsl)=c|ygvX0nj}<+I1{`sKfUk&m8yku@8bZF^tG z>13~YSA+G2+v7d6*&0hWNs3cy1@>w10dqB#7!@n>5rGGX%wC|FMo@vu};+E`}9YUM1CZ1GsZ&ny@<&XWk z@@4;>?eLK{`cRqs@vP^%Hz&or4vr;gm1kz()m8l-k)0$k04&g{2WB?7xSe@cM7|-+ zqNjd{hTbZgG5xd7#9iUOY4H;2?6sghF=T@D`L}Xn&Cf4;_iK(&y>@XwVQ}3c8?Z6> z8BW;##c%TP>__{jYuewy9V?zwSgUMZ+qUH>+Ap277~ zk~kYPHy$UIKCHe|&^5uVs?^B9t3<}D$;ms|NaO%iOG#@wQRgEcTRd3UI^&)hpDb}v zJnN|{Q}aNWZN%L0hLY{N4};yo7%SoNHqJ2xqgNsF@@>A0%1?hee>?+!zfeEbEMazJ z^@)EbmmKXGt51U}YHa$mIX_Ame%)L&t-SMUkV>8B;)t+v*6DK~T}HOj@j)B0*OjY; z@;5xc#T6fZe^SV48^?T8xhlvudUxm+mrHDF(>|)K#k~mFuf?7B-23L4xA&#H4&1zE zPAroO(y!3>wqN{-fg)-fQ zb~Q3S?wEZj{Pn?;Gz2huGj=jkyD-rvg07;Y%83D=pKs|Sbf16D_|aJIwR3;&?!K0# zew(Z8MrQcT=H|x%dWAwA1)tB+>uz5+SSMz@3=$3PPhI;KT`?V`AZ7ex{>Fi82WMZ- z6nyZp{nE+z>FmIdGZI7R?_?e??tOkUX*`oDRq2;hJ0BvMbo3j`D$Dx%M$6N{OFB_1 zA5MMgGG(T@H(0fX&iKA+&MwS3osY{@xA{-tD@8{u=OI+_l%FDf(0nnUFw;(s1N?_=9o3} z`l4q5dxiG%^WrHy0{NVDX|DU`dp^o#2*wRBOW1|zsRYEWTlcpMbZ&&y78{I@rJ#id zj9f>!&1l~z^RVGn244zTK$?l`>t7m}l7}QWfHW^{o}1Hi+68Qay?S4^ynog#=}|{C zux%!6SZP>LFF#baV@-~$Jg#6s+n8QC1#3qT4=ioZ6O|O=L)u;%=)u=e2GjfNJX>@TP|McdTMb`>#x#0PpjH25D z4Mj-`ayO|&=e&cAVq(1n3S4%*_C{M`-Mh=VJ?lY}hhN;BWt4w^aw?5G zZx0(2)7-m49+M~ZA7bd~2H^NCp=NFWI z8mB0;%kg}hv-l7fn%uGJefq7KxQ%pdy*%w{ucw-Id<%(kW*ZaMtg(sld^w&?PZZxU za{mZnJ$HKPc{)`OVw9Pg;ovu2ml1!%YWW32L5aT26%yAzHiq-a5x}g2TNVI*5-kJdl z<0rCfxZTM+bA9UL`ud}@hOuhI&U4{s)PgPy%KO#ua(YlmO$w<=AvGzaCWX|bkeU=y zlR|1zNKFc!2vQj!2v zQuBXvQWGzLg_D~9SzikxzyOF)6aObj&3*Vc{X6vuLNI{{Apet~<{AMYQ2jfuiN1c= zysy6LLNqI{UOEF?!PexyRzP!~xb^C`m&5Vp{btO^&PsB0`ux|pX2NBj+uGI2wHBU= zAADTkmz{h+=?kga7Vl?Qh8>uHvXA+pF%c=bi|QrG>|x&cEStRLc@Wsj_&Ma_5p2G4 zjO1FC!xqI9z$w>NPoi9`X8n{w=bhZr6*Q#d zlWmOFQUJp8+J2c;>$zyMoJ$w|?{LjW9$J08*SInd#W|ifGWv?PW%7TpT5S7JX?JVW z%tvCR-+*T&#c3_6g60>iWR%Oy*2R`3p9i9U07))dshOvaeJmFZ&Ru1)F&yD2aTPP& zxy?K5w=y>?ay#8lY^7U5{K7f?Y!_9Mjk@7V+$VOE-@|66(t9g{wZdQQ<9ImoaQy!% zuQ_QlLVw$Bt&gGY!VIgk12JGAOg-Rr%-eT9_c%*vp@%#3??U#g>@UR z5^Joh_~>lBem5BnDty_7vl9d_v>l?0j6nEHdttwludRmY*GK2hb5FclO_{e!QF)mD zh(oe=WM^qUU~XtNNO3QGnXfKI%Ddft0wd7vF{R_%HA3sebNAUJXD;#O!%Z(@&!9rz z<=JUT3~PO|bMJ4zQ8V61=C098++737FdeJv65vpwCcK(($FHW4+WNmqZkjc2?Pk8b zpnW9&bN%&I;ZI*R(~UyGHe*SUlpxMX9D21~xi}=u^2IidhbHR~9ERuq8jf@^A2F z_pgZ;%kTFS0hPWVo2=PW76v;jpT5)%TB~j6nHzg?(cD*1iVY7wQ1*L=P%gL{Ako3s zdPk(7YvTi_iP>06%|1KMgZ6AnytgImzkYlV%c!N;J9qf~oYCuc%Z!A4Gp6-&pX_6z z&vG5!Z@%4ezU72=x$7gf?JnD)rulAN`=^uB#>w<@QHr4gzhsJTtnTx8-I;l%DMIn| zuaDbz)tBDa?|-2avq|94IWlFNJF;_YT=>61IH_K5XT91tEI7S3cYke=tGG(}T=7Ai zV}APd(W`$loDP}^9xU7wCfw#ZH&1NPMsq&hOXab1d;BurJh_vvwWKip$Qeo3gEwU_ zwsqOQo+xJEUhu!ay=9bjFtd@Pff^+}L|C%8v8`tlJy)O+?> zkW`KN`VN7P%O@#OAxyzL<;r?)PT7OwmN`XD5n8*6W%O)n=(Q`RJ4^2`b7#08-xqUf zuhH2$iQuQthMC&vcD*MayGFm!%v3L9aJ+91wTA6|@MDK zntM^ax0$r><}bCo--_H{ubNu0l-RhZ{H#1}@sS+3VQd{aDy{bJWmasfGzX6~J*hG% zh{x5a>TUBTRU)Y_vzuQ?S#0{sL1b~7E1~eA2k&x2O^bs7R}fwGW6=w4 z+gs{=w1)Geknz-uzwSv@qsF{L}@SmA1nK;H<)*>{i@3KVz1HT2b)!y_@fL&uCU*| zcgaS^3n=eI3AFL0p=vi~7y5>4lha$@k$EbV0*RO0>)>-MOn-ju z+D&ntp<`D2Ghc6aJ3oE*cK32dbL z0(MfsP72sb0Xr#RCk5=JfSnYulLB^9z)lL-NdY@4U?&Caq=20iu#*CIQov3M*hv99 zDPSiB?4*F56tI&5c2dAj3fM^jJ1Jl%1?;4NofNQ>0(MfsP72sb0XzS90XxSC^a$a9 zEWyb}z`@SHDrXY@eu0EPWizR$|InB?sY(5>&?kWafYe0jKWR%kA{~K11)ol$@m2OG zTU<17u?V47?U%VF(Y~mYpcH_dJ-S@_tc6bN9lLMvxyZcjJKtEIZMycoZ&4}wdh_PZBss6hq-BR$h0&VyVy z@`>Pmrvj;OI*@W~nfZ@xeeLBlS$h2byirw7;15&$9fik!kMG!c%=b$?FZMmYtBcXY z+%xn}u`jjp={X+BlxPV@CJwe~f$Lg5CDCUe?lQS95!A;+({%KO#gWUAnyo{cJ|u=* zvzQOFkDF`?^X@3gCpJij;S3&*uhjjQ3vMr_gu#WmOI{d zXs5OJPkpkcGSHj3sNIvwHz63%zJ`y9m!3dPMWm)i!GFjb{}%zE=RC-?2{JHBXO7;U z-#R29SlRK{=y2gnQms3@ofBdE_)%>@=ga}S721{eLGy*aHRq*fo|hM`-}AcsT*ZF= zb`SAzzyHW9@t0}?`orTiu3eWM-W0tg#rbE&`LgH4@ViA_`7x<@d`Stw?{LlA?=3Rd?{P@89Q*z(X^t{=OWfb?*rel$% z-7eogf9|8T7Qph>@$R0a!^^)?;~j>80Sou=%^-0*6k3CQ+?iU zn_Ito;%9O1DZQ|3Yk@0&@u*K!+>=_FhF9%dd&g}YWeZph>sMY}ik)-dwbXqf(DEeA z|E8Iub;PKq`q`4pnpZy>dDNUDLlKYT58K@6wPbnAGUHtq7-8zfWaLzQwrZ=O6Km1k zx30I*6Sb{$@uuz?KE+nd;fCdYqn=gH8)YvU=YhyygA<)*qg!W#yYPCaPi=(yf65Xf z$$`WZ^0=_M=y2iwDc$=|&p}1cNf40MwvNmk-Sn#LxV`lc%a!CzJWPaCPjm)y&c z`F3G_^QyW?$dtvH9KtynS&aW10HHRz7RBSxM zp)NnJBx*I@_0)Kv6qQo)<5T;F&WXhBmotI!JKRDg(#CrdO}*6wzcy|UOz%$$o?gmBSV1wAaj{>pL2$-RkF0o9ydbJVbi%wcLGP5R z!UvuWi7k8VD)CLi=qTe5uv&GA&su|cE zPh1_1FVqMar1I;L7B4(!q3n9J^LX_j`Ar<1<9Y3o}#yRZy8OmT`nm zgI>2bdc{58jaI{+$r!e6D7y&^L!H*rf^|7(u__%Aw;q{)6ibNT4! zqaWYzE!D}BD0leY5h&tBu+y`l$NWVrx zSS@^(tYiYIwv|8DEq=E18y&Ts=i6PD0+6RsZjUO9y$^q633B^&y5)&lL*A>qy4*UN$eR4|>k$4&MV9hD7!gO2n#!;#hZ`pJ9XrGuM zM|vubyq!SJ7!KJ#G`pqAlsS-nr(XxklxL?~x*DZ=OVoRAQJQerdY^`oUcx1-EJjXm zzCk19%DZb!SIh6>{pO_m>t2Sx?o;@WuK&~4yfR1sUPSPz!aL0byH#2>?fIEQeJzSw zbC>ZUbCJy|pAVwP7L)Qc`lGlB3->4El}WtUvhC_|#8fssKc%2aBYHX{yu{9Lyogmv zif%VZ`)%{fuanN%($f5oI!$aPHjaP&G1nj!8|<86;!X?PchNXq5tFc>m~%sqZP&Mx zKOUAbm^+`0f8o>K%hvsc9Q@GwyGOlQ$gLNHhIs60Sw7FbG_LrRd%f$0>gZfSlJ4n8X_*FWT#-U*O>XZ}r8)xnnA-V5 zqV><3T%A)4DevHUbu4E-1(ao|c5f;LdBFtZtAXoMO8W^Zjns=GYS2r0{Yb3}FXm*K zjM0;r@nyG1bnJPDh;e%=O}tibB~o1$+OoG`+GNjT99|gWj2n_@;@t}PVf&LY#`>Hq zaxg-x=HPH8&7~(w%K+7oyhguDUZXa_nO3^N-`iR^)l@vLGUJL*a~ zsfKm~^8T$i8{OX;%>?J}`dx)%<~eTotqwPfd?N@+lHMX7Q+tm-F3eOOHC2v~2Y+VW zCmk{Z0=?zrGpH4%bU`W6Pj+)ibg{|KFf)0 zb8s&X?Z3u-QT?ih`i``2DG>S*1uxj#Wo6iSc={Gl}2koqq`;bpq8(9~sL2NNvR1eyN?!}U5w821_3(P=T zP=2fs`iRD%bja%ex|;K&1QHp))dQfy-3qSeOoV^h<=^&+;qP+%S=Il=WC;Y22;q?{ zfS@Es`oGs0ymq@%sL$ofp*p4eRL`UDh)jy#J$khEfOVaLOZXdT3JQ`?+H2EoE}ts0 zGt^Y!k za$H>YV72@yhMtCYPH$eYkn8c&b3e9k;@`(Y_wV<+;9raTrGGRm$vI;QRd0pnYV7)F zf9ZDq%ri6o+&{bU*I)kiF*>A?so``J&tu7*RoVlzJhaD=Q%DTrg36%H7z^!T+GDi5 zC>z3$BqKYh4m3!6l=cKICmaAjL1ds{lm%0O*dcFd3_b!Mh2J5TD1u3X(+~ppLC+Bz zbQOe%g;)`y4~|2^P&uRy@}Qv@E20CkgCXDxa1}U!B!Sb&L3jk1g~Gvd@F_?OVbpu! zEOH(Y3%mtIz&I*yBo&b$!Pqz2!z35HZ<>fRb{2UA-$EoXStuAu1 z9}odS001!c^AtbW~Mz1OuLzO{_-sU zof?q9fAKAYBXM_b{AIALxZ|Mu=T`PF#X+ed7-13php~gyGxh6cC$GJ(JABBZn*-OS zBe*Vs)YPQ^RI@)@M+k%&cM}jgd}}Z4pWVCo_w%^dN!D!D`SP9Pth2H$dzD@41Fgqx zq@oW3rDs`MlgIZ}$<4&A$-``enMzdpSF3^-zSVNL=N)N(Jv>Fb`j;#EbKBIvzNqLA z{EI81?lel|aa=qmc<<{!l$Y>dIir7lkgmD)Bs2Snu}Vh}e*Xe32Q4q{QRp~03y*_m zfHy!hXbRgxkuWn{hlr9E&=gb=#gJCi9)1hg!e^juXaG@0exi98E6JIpMw%lPk&LiO zYzhm)*wG$nFZvEkCrOe%;!cf=_5|_^%mEca0`4r{gDwyPHNmGaMkEM5f|{fIup5Xe z{1a}5Wg!3-hF6hDbT9f1lf*Vi4x}2=Q_^AVHWrB;hl5c&G!kRPZlD2Vc3N&)AzBWw z1T+R2Apsx}B!QU_4^jbZATZL2>XQ#4bBG(l01v$bosi-!319QaQlJAht zlLWB0SUK_>y@Lj$+-N&Ij{PEakxd{shz9HjyV@sWrqLGCCvq8D4d#LRAR{mdHUX-@HP9ZSLh@ll1i)jS zT_kNp3w{At!FtdnGy_e*`uGAOi-Kqgrh&aCHQFk^bjsYq{w@aS;Px>qaE-jd;q!+WkV04S!5Sdh#o_i zNsc65k~sDfi$Pt{yQn962zd=jp)asx(jHPXwnSb8gAhUBEszd~5I=)f;2v-aa)TMM z0>m7-i-h5e2NN6upT^s(1?^x0-XcHJgEnC-SQjo~B6bZsi@rc3Q4vTQxsLi`OjsLg zK$<3-&>)}&NCN6`Iot+_KpkiRZXpk0UHB~$g=Axa@B*9xYrqiX3VA|tFgHAmOJftQ zz?88!WNEAiQ%66d6|f14AlH!ZXeGRfjp4F?O^zX-2loTL&}rgtVhJDytmE?}0GLt&UrsVH5>VPkBj5tMnN8ABgK~?Yv zvJIbrdk`~(1zo~*O%eJCmEp7e6f%b1!)1sF@&%W&Ft$uG!49K~XgrGBJ2Hhh;g%8z zS7G@i3DOohihPM?A0PqB6BCF@z!~5*>;fHz24Fe(772yt;Y`>Prh*wDbMQO(2nvC6 z;AJEl6+$OTX;>L1iLRl=_zctHHX4gKK;mdAb_kmy1!14bvouG@L&UelQlctx790TS z!G1^qTEs&c2-mX~*b%XWZs2oA4>kg;&>*hkWMmR!L0@Chm?64}%A@Wm2XY&!1`i{7 zC>K5!15}-Kk*q^QATMDH#Ac!mKtNhG!l4m(9xWgVL&s2E>^yo15C7gHt56^K2rYzo zK?EB>USWJFKUz(D1@oolC!ZyX6ZaA)!E3-9FdSlmDlk6Wn)6``m@JZ_^j zPzP*=0GJ8JPnIBwB3Hn#ByR8nHVYkt7=dlj7aN9^$Yf-V%&^NFW8HNGX+ZsmdjLh^ zJHP|n1y&($cz72BH^Gi58M*>lgTKIw01sFQX+kgHWW)p;0DDMnh$38siK3#AI4ljX z1DU`e`Uy!vdr@|pZkk@2WLhCqmlmdJrhZ0@0zjZ1`VL-$TwykN9#ex)Knsu`!~&Xt zPT((Bg%LBcL1j>w&X)@t# z@^y5M{F>BCR3xqdo-mBtbpXr>o1%$OBP4;(TpvECtRNqF1JZ@s;0w6FzJ$)<+HjZL zjI6^+$S~Fgu)*CVN%$1$6BdDXVu^?VjV{86mC){j=+JXS2T&Vm!F~S@E{iCb4H|&V z!0!+%9`y4AA8{E8;4SWga}h;!8kvI4$Rm&~cn|)GHUeCT4ln{gLD$g*(k8|VHzAv( z4TO>GgM08UvJ){Gx9dN$_=)SqVQ3EWhef~}U?#q5Q4yy=PlyPW!-o+R2}SwfpWpzg z7CwitVuQG+%|VzUWq6*P2@Q}{Nylif(TpKw=uL7zdVuB>agsO=_`zb}B;*1;$8SJv zhS=``7g zWJ0q-TEbWRIrJpF23LV;Ks~4jzJVe!I;aqm1-Ed|HUn}4%Rm{p2iSzvp_h2?ehLtt?F{Rs&3sNazOi5;6uPfn_ifS%9*j z4oDj!Ku^JFPyl!dWD)&A1#l6HfcGIY$O@PcA`ZVt;!z{)491MqQr93IkSMMPpJ)$b>(D;nD`*7a@eLl8=%ONs1dPH0 zNI&`=k5-3BAQpo1AVn*1U8DvxAt_;|s0~tpoI%}jpSDB(3?3yu0D{3J*a>Ms(%~Dpg)u=Y@G@$E`Cy&s zFwzD8LRryz>=(I)<`f`{uiif(TX+!ZhRg7n{{ol~O(Ux42sVn3nGRXRy+RXqh*V78 zBFz#!ANmD~L5WZalmadQBY+B6 z4Lw8bQ3bRH83NbgF}NGf!S%`nb3>>=HTVng6}R%|c2`qu$gCW32*cM%cR$)c7nsgJs1qVYI zqyRXBz6dXp0RF-wv|-%ViePoD_}9!5MkdifFup(M{VR!!|MCS-IR3{j9rpqd z6*Y{Ycw&i>i9o-b`5?>QL)@qSu|1b0><;q{KY5cUOlL04@2XRfaD7@9u#R&P+ORP<-3r<~xhLI_1H` zbr;#8+BkAIv&*+%7`LI!#G+Z^SnD)T?uj2S^dG-jXKEE)cMxSBO|34t!W80Ek$P}` z&(nHv3h2B1IrWgbafH7((nq-eTkT-#9gEK0l;1pdlxA=em8|FUk2+=@5JCWYI=DVzZV*> zb`Q7Flc!cCJCz)a9tfN$n;I+nN%j;u@KxA5XpDD|A82sUsI|O%^RP>Zn!%{kqFM)E z+u&+08=vao$&)2bYB_ctg}eoc1YWUp>pH6Y8zHj~A_;7p#Lu<~-J zbZ$$ki8J}T-QEipeAWBrY3TOo%Ey$w$K`xl%j0oVTl97X$xlVci&{!4?8iP^^10#MlQt6u0?3WTpi~0nFsF2 z(w*3HTHIazEHyUQ?k>BK{L+3tz8f~5KV9^=^=0X8t=QZS!N$v|b+65JPLZGQJDn?b z2%i(Wd|xf~aLi)znn8fa&(})jDr~QdzyEOVt%Gk9y3k@$U11oJkFLHL+R>B*f)-Q(Z+WKQCP!g0r_p6BQL?%L;`pD1o*$(X4rDC|1Q6_W7Pdo;p( zehWFY`9wK^?!&pPXgq&XV>xu z%iGVjd(oP$Y#*kb^m=PN=`j6fk|jajvsPgs^D(uysD1&=t#!@HYo?@FDJfP;ij|ULrKDIXDOO5~m6Bqmq*y5_R!WMMl47N#SScyi z|6it9|2neu-=$bl5=I80e`HMwRJ--k1GIMtx|J5bCdlr=mt4;3bL{!NM-K`9Qb-7{ z(RwO1bm-5aQ8xTc7k+O4U$V6@f}i$7i3IAuzYISb`Yzo%X}_wZx3AmtjO(ImyM`a? z&T4mul=;nA*T3#5`GI_20rSF-#xHYR^`hgseDU`2y=PPk%GC}V8k)-ywY!C#5pkX; zR$<}^yHtgbO?vQmc1Nq_%UtjK!g$H5$*j@xwD~cr@2_O$cL>siJWJho0X90x_j3h{nFa6kZc<% zIAVF@t(TmK_uZ>c!p>Z7R&H?}TAAo<1_;`mUm5crSGsjyUvc?$&+=W{)YrfVw>R$U z5`IQ=X7ZsIZg`B0@~RZyi@K1i&3f<46ep=MSv^r;2KW`jZsxJv{D9xPn~y!!MWe13D}?aI;R#=ww0YqR6>0b4^Zv?f(nR;f{NXN ziGhms9C+>PzOVi6{qFrd<9+vsXN=nq4hFFn%yZ6T9{KxcrFuP$DgQq5(4kMa#(i4v z)9+*Cl-QyxvKE$_aj|cqfG#0@*~*S5mR%kl_`|_i+Ti1Jw*Nq-*4OX0Sy8OVs=goB z%}6g=q*;hlF=I7sNDB2&b|}VoX6+X_Q)OCrt6@WPX?|3Wy;rL z>+sx3w{kzUn%m4YJ3V*t{Xrk9E!=i)t=q;QTla_qcW2wWM|j;W`$ztZ9oD?s5aALv zzp7XMtMy&IqdFh!6`ix^`rdw1R!4U1y=r9btxikF4DFTNdfx4__OpZDA39Mp=kTb< zjcZ-$k}x56QMgymr~YB>J$D~)nDMoNjk8y~Ju>{*~gVoO_L%yTl`+ z+2Nw|KYFH;Ljk?3rsb=CEV<(1Nd04l_&Xc$-X;^qV2WN`43rBysZ8gf><(CS*X$h3E~dL8-n(8R{8>pJ(FoHYFHaA()(1=dkZLvWkj zuiOuwXmE0#_p}jhKDgmeT?^Syn`cwWRIta7x+T`9SKYXG;xxO?r&B{;-#i`pW@+|z zmv`nX%^n;<1<*D7LLWlYl9t)I#Z`Z`Ev~P0y>qP-oB9uPY~vLZ0?Sb3-7R^!qYmwHxDacruxONZXM+o8$q9kqFza!qQE z*_0Z8bmk@xKI-kZt(`Anhi0=5ZXMv#cEyfUw<|2_x4L>pd8acSiWXb>uz5hEmENn)%JCr_Wn;V%pD(yOZD*U)_OC>Zg-eRZ{@50luaHyYZK=o0m0anU;<@HRyT?zwCpaIN z;kmVMTbJ>7l4sWlFa7Y9e_kS2KLGtmk$QXRPTnsEN>_S9W=mUjg-+&qU5`6yE%rjp zQIo`Tc2vw$(2mbm3x7V2gz{`rMcyPMSX2H&E+K8`D>f23EK1NVytkBiKOMsDpyOZ! zZObx57OqU5vvBEz-jO|Iz8p*zlDX`a+=Z5q!Mrv*i+Ynqyt~XoF60Rxsq9f-YGEyu z3n@j*@$+gpilERzAey5zdJ#HOZlfF;BL?Zkaeewp)Yf~^6jn(*(Sz}E)>{@)Uih_e zkPY<=;=tnM06iBf_b+6EQG##eX1Uj}k`=s?e5``WJ~>_2EzihXzJqm>%c&Djhc38K zIhXI06O4WI0Pm?PF<&}bWV2RASz40aWYc8>@{Fw#<3t+2!F+fhzMk}k?&98}1}V?x z(53oV{1y5R?&%s%r7P%D-Iso(eT3kfU_I<`VR{Q!BAsv#RTW)_9-my+8HEsc+=>R{ zTBIwNG zssz-MT<5EJIOzvC3sng^TcxqpY7sl2>hVP? zj@=Q*=pE6NRp5PTF_BBFih3}T9EO*YB;1KDL9@jP?92w?iqJu`ML3c6ydBx77Z(@# zAvTldLQmFV9xHl?6h4eSr)QuSqYe#b*JW8gNtk84Y|c+HCm!`bTqSSvk13}DP$mDT z9mxAg2`~{3P$37m=5O-LFo{8#1|2w3>2?K71^+TCuBNWu8+Pny8MNWarY<{<4+$C; zlQG6~wPVZdk!g>HmYpA!*6u)p|DdBgmeeh0bN{EiTkM{Qy}aZO%luty&TI>N6h7)+ z>4r0p{!Bg5@nvk}^~jfzx&A(N+H`v~s?v zt;^jjthL{e$ecU%bzB_qef%#|t?2$K-=mK0Uw1RMMa-BwyU(l&9d%>Uo*@q1W(>Sg z@X7w6RqL0Xsg3NKQ_%VL@={CO+vGMXzhrR58JUk)^$czwHu_S`_ahU|E$H0P-^lnH z?ti4pr~C_AMr0J}R=k>Vq))f?9a|h|veFzd$H8{|uvGhzMeOo7uRYRxWrvle$`9|i ze96g4T?Rd|-FmCx1mAUEZOQ(E{8P&9I%m?l^(tvQ#_rbK{{83qwx@ok(?jA8gsmQN zv{%d3W9FV{AJC#~{y)aJdN2HCn%LMJ_-si=*&j=S#%5Y4ew$qKcuMbeufoG$eu^EM zP|WXA0qe*IVRJVp_B}s0pX=6((?{FIKl$>@6z3|MKi5vY`mW99 zZ^JTK_?jK7Vk1Kywj5roz=!K8_ok}xFw7uL;pg~5Kkt7(n>+c$-kxP@x;C%f?R|le#VYDR%OA~ab}G$U)Iw#7 zKHRX$EtAwJ*l10wK0Ds8>2bba9LsK%5L>=xiR8Nfvbg`Uxc{=af17jquPmGtgXs8OHK2SB+@hx4kXCCTg=|oym4*8Obs-O7&|hUJ@geZ`Ns-oJ;a%H|pP-zNSq^Pkra1+NX^ zE4MS1aVY&4>I9y%IQ1m-tuLyTsyqFm3#dA)xw90bZgXO`15^k3(Lg%kGy2eKXP;H zU@4n*oA5K#$F}aRptH~SPuiHXy3{;lrtO=cxuv({PT1oRkX*f@V~zW$`>_0*FVA}E zJ@iZ&hb4P9cwBki^7^EcjWZ9_Ef=5tZQ{VlecO#oTgJ88boqGW*)5))deOqSMaN+$ ztd-M)9k+amS(*6Q+OFrIPj|lDtu>=Won?JvdKb6d7{eFbn2|jJeOp!qZks9ZpT)P@ z*u10n?9ArN6M}uJ2Q+nSQX#P1h62lKG%wrlc>38hmr~~kZJqNXZ~W}H$Nld{!u||A z{(6kArK3vBOTN;)N)fGp$7HlQAnaa&%g0*#nTOrywRgJ(P8&MvMVD$b&*zx&iu5m$ zvbIy4chkczXSZFReC18EP7%&GS_}>uQ|ndNe{3Y1vGBHqemnYq+dVMSZ2LDie^A_t z%g-Hiiwg4I(QfyJrS7GUx+h<(^=y92dKI-NqwM@D1V^Q8d3WkmW!>w_9fx6s&j_2F zFPtN5OnWl6V5gCGeRp`}IoHN?OABqRzMr-*3cz?4)lZ2qBUUeM%+O{?O?{)S#RM5B z4N(D_TQiK)`c-Wq?M=p4MEpUU$%zYS-lk>aO)8>*+d^BGc3@(+&M4 z>jVvwxpJ3!FZ;p($rNs=z9>O<;%AvFuPZei{6FU~!K@>k3>basvi2e7Y38Gz?_^ z?TdNfB;e&hS7W~Xurq$cHEfY>-gtWKs2_Rb>33bfp3ccvJ-E(-)`MCW9<*}Zrf=p0 zaT~pt)6Rh!Y4*pJZr<_!ZG(m9 z(f8|;Y<8QDed_q2%aJA@M7uVv_O7bG>93s)Y@dH_ddRsF+uvK;?$4L~jeC0Kx~59T zyE?g5;vR+X4%y*3BH!+p&D)OHd89^E)~TK#(lL7aCUgJ8pN2EpG@H@_FJpzYsI z?(e@8jP*a3%%*>bdD%7d-y5+D-sb=PTYs}+GC%Jx*!J0DJ_NqC09*n8T(-QA%zsfT z0MKHSuVUvx-TEyl^()hwZGC6TXZ>Z(F`29%t-nlCtfoqs@*DIV>&_kI3UXL1Q5IZ5epAb})i6`^ zK<}hx5Lq{2(_xZpwL!|qz9d;4Qnn_=77Bh%d|8-%8H{*HjchzfvC7xk51~__%eLV=*AYKy6QYOWI=5!PR|yhSz`zr_<<^3fBqC$IBRlje}x6 zZY9gZY}azgL$wkk@i3To9f778i7?$#g0vu~n3<;1%Orz66s~9|-^w0gs=pzhc`cZY zISUhP2goU{EO*91nhUq$Va!)8mW$a3n1+0UQz$`8wC&^tsZVnC18Cu&zm-v2%|%bi zE-^~(BCX^nb(n>cDI@`n<<;qQvPXB}&1r8OhK}L3!VCBQ^QYKkzMCE*6V*EL1EzyM zW8=@y|KH#W0QTVDxdQ*685m%D@{%?G?x^RbYQO|I+XAx2OwGnWzL=NG;Xu(~LXIg= zuxP#do%~j>i9U4g`d=5opH4#T#khUbz67b4d#?4o^Bbpe@BfL@`0^)CqoeKM2*7Dn z`WsGT)}J_y9s3LI8*pgZ&0#|~hv{dxPpBG_a_4^4;g>RJjaa_**7o-!I<>8H@s2}> zCS``DUC34EGCMCG*k-ewXm>MXg*-_rBVHs*$&8RJ?GI#+2Bk4#r;jY z{7%M(7x-LuVJ?n|@7Cq!hO$dT-rXr*xOu<0=Ji`!q5{h|4BwuTH2iaj{iVdr9kE@v z{fJz5YFoxG>*PTnQi^u?Hf&48rODots)nbwjh^~-<>FnNH)U+zTy=WLz2`YWeH&j- zK5(_sms?d_T-RQUa{u--deq%=gK}yNsW~AtcUX;xssA#V|1y~WGMN7z;^qIB*y*=Z z``;VPJX*|uW(D(Ry8g0je>%1&V%>oxGdR1$unH3ri=1+8wE}+de~T(J7pOAFUxxR0 zaQTxelV@20Z}ktu3Q!zOOyHLay8_&%Ox;dFs}KIkC;IL7o*$Lzzr4k%W1R=zruE-l zOh4`ON2+g0JJ+T~od5(&!@%qa&(BdJlTD`uOk?-F}%aUM=x+ zVDebUjq@AdgWuLM@12oG{^@Gxy)%S*W?`}^Ql?(Vpj9y$zn#b5j&bH&+w8;rl)2r_ z<5kPod1HS0IY=Z_8uR{ruP%N34=-ysJ>T61jn(45@t3^sE~{MGh?wuyWZAsNUZa{{ zi~O8a+3)4ZO)e$;Tt2s*JlQ)L-u{0ar{ns6g41Du)2ReFotpM}IGw-w)eG}{^8dtH zwzdDgGw9o~H4%zj^s?+HnxihL1Ueq2 zY}Pd?bJTKsD7Mw zx46+&`XoJurs$tkZC26<5L=n2(LhfCOvWmJ3Eb4%LaD8``iR;?sc)@0iSO5SeG2Nr zv+zSvM!yHNvVle)E=7dVQY?WY<3+tUj5Sx$kI9khr=_Xfs>bRtfUJJ0TB?RVNPh^< z{REEHA;W`?RzD1XoTWF>UqN^+KUoB8wWebv~uF_&E!5Be%=~ayBbftbkWz#!GQ9VnJVx{;s)>fa-TC#QO z3%S7Vs-4)5+d~O7LEFgNYk_>bUIrjmxAkzcQdBn-D=!A?AN1w?xY#8di+g$@^+Z-u zM~oqIsB$o7%57?kZVzyWZ!$A&^L-|?AlfATlgP==Vzrs4$Tc2B>nM}MKa#v1t2b!nm5ED8L zu%Py6BO1uyh171z zyY+p5|Ea}ph~at-C|hn(F-j9}Reybvbd>j%kEMw0ucyo1>O2g!zt`J{9jcMOo|jQ$ z^uxLr-JnhqrQWEsXoOy0buz!wr>X+TSwE?os|0*V|43bontBEH*nqt&Mi_B=yk1G0 zt32ff?V`*OR)pjkHU@dB1}chVqj9(^iqlJISFlB&skO&$dL8r#PgF^22Hx`5TlEr9(#~(}rrq>mIuu;>=5i-}qHgnCW}^nkmuv=WLvmQC z+>g7kG=;S|UR5p9+VNpJ(+8j=zL#`|GIuW+l&__-`3e!B{*Z-XHMm@>){8er9a&N7 z#$Gu<_0?<12=!AgRtUo6o&u?gY?>OS-jXbJMlHkr)iYIIi-+&pD8Fef^+1%MN2%^) zxc*sPVbpNd+wcj-7=4H?07eq8#%fDtuy~{;0SMqR?*xu~0&1%|lNxA(I*&rpdA*LN zW2LgyRP7V?#uM>;7OJ+@<;TN(QHW;HM_g z&1#CuC!W$o-i;Y@FTDZ{0s*8fTQ2va2zFgHQPEm4UPb%ByX*P!7`{z?qQ&`FwUZqd z{HcT!6o zl$T{kv|0Vs?DZCMqxK6)4v=bmpQ z%k}Dd;d-?AqJ2@>(pNL|#xfIa(8sCjDvUJ#ZPP!iG~V8* zr@D)$#x$_OLyU`ZmMp1Fkv@F9c3ws>4HZ)r)LasPnxb21oNA%9MAzg+EfIZ{gRm!V zDL#s1@(M3tvvI5}B@9C3KDmK(QRVcKWUpGJ{EaQ-fl-;3m2XrG4FG&n5xPk#KA+wb zhh!B%F4>Sltc_fXuCPtYqIs}~YLs>g&U$zG0{7rU$a5YkmjPJomSg~fD*<4a{0!>}4PNMAKp96=fCkhIaf-~>#O z54BTz6YQ;zRlel4enhQg!FrY|BrHZn83nMAP-CQC&PW%BMQ?2${LYY=(9Y7fTCVcI zCs0HA164(<4cFFUfA=FhMdwHB>E$uYQ9plerc< za$7FZ=hI?wEQ3kz}L1)clJ=` zh?^9!D55XkuK=7RE1??dwE3;dku%Uly|z+B*Mn4jx>}EyDbj;G>aWCUqoH`H+>B{r zww`935j*%{ZGoK6>S#$SADM@UT!nt2_OiUVp-n^^w1w!T@WjQjA)Lt(NUDT0cRX1t zIf~!Fr)6(q$d~F9=_JFAC1j~|H+qu?;zdjNCwH|m3B`fdaYZ*j<2WE|&ATLK8-3ED~NBc9_dR0#D!O~edy z3YsEJs5d&xpW}O27p@|OPQVR0#j^l*vm9TPp{fP3Kx@@L(pGY@&eEK0*N>4q!cJAD zCHOfpn|2V@xS*lpD4ds}G#P(lc5*T50S#JX%yDd?cm^M5h%KTx_+O56A|JtH0Ftyr zR1q5hc(P2@fEKO-a+n?^`dWNMq+Fn&gBjoC_jo4_Ftg&*q;WL-L5pDB)V1kk3&VwwJxCkczHY`E!XjgexUr7i4@ zEJ>NaHjC`l;>1R5k8DImZ8d7fk7y&%0{#cTiv`LcJ7F~@uwuB0Nac}uo^+RPI7K=E z4kQ78GWru=;bJTx>v^jBN>X`O*$3`~mtq)Cro8~b6)MhgqRai4{H|tWs zzR*QK!eA*pc`ho+!uS$s99R_E1u4LO)kp^G8qeoJ&9OnyL9l&d&zzNscl zhN`IjVi`WAege8MoHo=Q*>!yauP?^v$M|UZ&A>cepKO!|?9DMtDPyL74OWAbY;7K2 z>b_Eka8|`2mdKjT&%2l!4~+^Q1pYfio3ObI?yd6Sop`WD&erV6_V$=V3+zV&+BJ zZQ~s2sh1}6c`LaH(1wSFqV}R58%TY{0x=yhUrTWxnjy++iGT;%q1A+9K~0p(ma|0O zgaop?O!9Jk2M27GC@G6Wf`2Oj>~2AN-x}nwV>_`8 zAW>`M*8HHniYM~+?5ggAj~lm1LAJoKCH~x`W{{P90Qep^!D2K66rvryPJKi(QjMg*n`CmQHeC{1dfOUp^48g4L+NR%@SViiV)kv=Z9Jy0R6dA%KPe!31_=tk3{7 zT3+1c0X$0u^38msG4F`!MCZH8N*r5FPsrd@y*t0X?NH-J4X$9q#7*_YquKk;HH zDjo0|BFW9}seFG*tV)oEo`L#|Pktr=D>hpXaBC-KHgYacO84z@V3HmDSwlriQ9S`w6cMxlIwz-@tl zAa@#qrm{F*3!Mji;#JJ)RaF(Yq3f89ehbgCMC9*Vf znYN;Zp_Mk4cBNlYNq})qGry*3Ok>^9L{^+&Ko(}u5Vjlue$MPRWHly>7h*k2P`mkQ zYZp~s%(0dguUWY2$-Y5Dw>RV!c8Z^Xb`2p}_g0((s zjArePg$X$F@zG|xMjel8ZSU<|bq`L^$ z>#=%jDPF9N*XFXl+)-Pi-Ndy)AmA6-f;`}vH9nHh^d=*?Ho$OK zkSONIo-j{9Mq;>Eu7VBfFDr|3d@#O@s#^QX3EWBTVHNOYJW=$e+aPaIn>XRuK~ynzu|9GR?Wtd~oRI5{ z=axPq+;YHp#b?So);HEHQ4ajnD1DVRg=Z>ZeJ2W;k7+Ad9O|ZBU@P!#?FX}=laLpU zrtR2Qv{CE?Z{rK>%Ad50egwCmnU?Ng|2nh%`ayhJHGsWw3ebtYSOY+eucpb62fIbv zlShydb3*>KHEm~3qO0jiGaJG#0b)@~U)7I>@==!Z#(Qh7wXLw|?eytnEo8?o(<4R!>kqie zI*N|g%Gz*k25XHAY8g;Sg+3=_u+qqbJm%480og4Zp|g~$G)U&oreBTG*wa{mN3$X7 zIRI)q%aJ4>eZ`YVdpal&;zzcU7;=*=z?G;@K53x<#2l}UgT3{Vb;CvJQ?i=rtQYK$ zE&%j9!!`n7vpP$s1@TIGo|U#V?x4yC-r#4$ zN!&$q#SB1ICmXBy3+!ilBkajE@VU>jLxvB(%CEz~K@u6n195dSfk#V!{ee-9?N^;- z4{UG!Zhb9!S);69#2gO!JL@r4K*d2TRaxsvf#_UROIwDwL(G@dMO~v=jZ% zY?4SD$}i}uJ{wcI(_)WZn7y8egPEop;Hz{VttsM&3GAT{IZf9BcCrB}4w?z)(I0S9 ziqoa$M|23PNtd$%cn`hA3epa+^ELshyEkj@M<5Vg{ZAGA3p`0%DXH>}j2C+@|STfJhVj^(_93wMKXymN7bZ2GszPbjuL5q!wp;LMI#*S#%}5hx5@+=hEvEx zVJ2ocC1U_X`i;B-Z0HnVtaTtM+EHpx8)8+DH3|g;d8TOL5&__7r7AGdi9w;lU&y=X{V}hxO3kL$4^I zyUka$x$+?3^rdl0xUN zT2XNtG7xR`!qx{Ol;k6G)f~ug4kyld2DDQse1+O+w^;;Yq>OMu4agpO3@rkcf$k`d zPKWh)g1#9DdlJx{!*j`c@e-dU<+wMY0FNzB&k;XTmxPgJXeT*OK59j2F*+QwXx+gt zr+7Myt=Q0OWINjh7Pg#lWSw!eyw27V19o^vmT6dFKUn2uS|69Pyw%G}D;rGvp_S+k zUCsK_4G=kCR!J?Q>rEZ#dh<%;40+ZmQWggbI>W{)Tc{`2Th{)@I&68S#TE|CGIis;@D>5Wa!Wo z6Q+AYbUcV3!%12g?_&%A!0`i!=nz{Z7*69qbr04DdyDaSB&eU1H;N&q7{pgLFkIu0 zr-+YW-Z`E688Tc9$?3vC`CEGKFygpeWpyY^nLMqVUEcR<19oUtFBCLN9X08h`s zqg6C+At|1ZvLR-P$5ZG}!f-agO52mJBn{mli?zligJfvQ)DdvTe$*Gf`WB*;71#n} zPLBmR!`N4@Wu5R1y$lN@EsSV(g&Y#QtY6eiYXKF{?}{$$CT;>i)~b*l>mfn`Fnk*C z1DtoFT1rou#=+ShWa7+GTTCy5|1gGS@P>Lee!>H_P4uD2r;S$wbax_+)rK=UK^j|H z=##D8E$x{r;9(z;9Nt=HVn;c}l6R*$3yZZ2a#60@9P>$aRI83R(#_gzZm*ps4&ngf zP!;h&Ze)y}jiwQMywXw(UC`k<;qvk`_C?1;FVK#0V-Il>UQ7ytHOz-&h%cFq3Iiy5 zp=JV=83zSc?_Pz8sTId54VUU3gyB{sS4I-Eqo60isS*VO^c!|XzS{Rra^vV6*>c%jyu>H zN65acu+CXmQp#AumJ@HID@(_zmil)`caewnT}P;0h`4t?1H{+~w78Rf)X>YUu-Q^a#POPVJ##JfE7+us)v3B^or6F63C*V^0F#zY!phL`G z)H%q=j}%>`fup#;OoUdk{Lmu!#+=MvBPUZS=B^zhfx1TbvJ(10I@IK-Wkai(J&QB- zRpX)Z=dEY!U%(&zrEcR%EYSMVG7I|6N1>UPI#yS7Z z$zb=(;1jr2&@LI7NF2u(j9mz_97CeLOy6DktopojP%s9v?<7u zEC!*9+gdvHgd3$jyG`BDZZQC|>=keyCFpH^D&y#e#l*UxUiwY88R<~9yrQi&Rbu7H z3T0L8X<>AP>^JQ}8SJq3$~+CS*FnhHTsjX~ZkXv+5-VRqlO-}TK_}}0A7jb{`1n1j zGo{K)XpE7nk0))d2aR&Hj9yg<)K@z!$3orkqNNAv!q@B9khAo&zM+0(16YE6cnThB zsY1qDf5Bj88|yo^5VGXOw25lJc1~MkRMmcI4n`bmrmfRUqhReTw4<&>r$r&ar9Wfi zaa(L5Pw`kZ8~4Vik)3u>OC*IgZ{n*pK*?ky*p2{lUHe5p)BLDEO6S3}mn;FRQA|bB zL^R82%fm!@r|GO{>SqCY}ani#GMqesx( z*-0EivABXhf`s6*O5=rzBZ$NV(#x`&UK(T~rWwU(jDA^$bETH^{OlTF+X>BpQ(lz? zs6c3mX=T{RB4VNX1nBq$s;S|iENYItCGY6n=uHKl7C9~3>+ML8ECJD#pE{=x;{%{u z;J&d>w1@HEaR&@sNFQ>F60Vi&F6rWL0h8`%au{;IAk6(#4y%G zZlPZplC`w;ytO(Ef)>kR#GCPDP;+T6Ye9u}KYa8?9hLz0hm3O);Qe1fFEgSxCrK%VxMh(<5@Le?Ke3TN#Sij=#_D2Q4naUfbl z?W8>2Ehg&g*nV+RF9cDP5C6gfg_Z7P6~#7Egf@j5&pg&#R%8Z0FJ8;4Vi-tXT$KG~ zh|VCtQ$mcFHDOINRYwtrgCXA>P2PwvDu}Iu{K;CGPY;ui^%=$m5MT<`cFHXz28HoX zxG&T?qNzPT0y)ccvYS6rA*7m|ru%?ra7-3uI{}bCgKidPxaInYC~Yx|hTKvBh(zV% znLJR`0TsJKP#emWyJQCt_3?n*)p@9ctR;iRdsz;ey!Xg!bh3<;8Bm)~2YkMvUy)uq zF?Om{<5fGD{PpC?X0tkVOkYOO_<8Yh>D_AvV289GQBLjL0q{8W^Y4bWP3O&nmp zGE?k@y>c4_oidF{vZqnQNRtdQO$LRV208L-)PkO{BRmd2g)#49bT;H$%^+mdL{SpM z7jXxuyU!u}>0+V3jBcW_bgxXOgV_+?lGcIFo{F>~O+_mpwn+q0A78c}vMirq zpa6@qY!Bp{_QGGWfVYP%`VXGLLTD+#@yBb`Xdp>|Tekt-0>5JfUk&-&cv;CPWUlVPa!Z{+%E4chV@K#dc}_H>yX7a@0{)7DAo;QmzyOgv6rGjMv;jKLFEAf^L4q^{ z-6D=MlRT-r^TL)Nme(L~TESQ=`U4_=wqA^s)KWlDVi$C6Tmc(5ii|h<;_@_AHl`~< zh$M#kg8mWRO(gQ^P?HYly~rl|Qug5P z<}tJ@NEO6_?8-ujJqz>AP)iwxFDRzF)4SYLwWNxt=!N(u^3|9Latz*R5^l+pkpme4 zgBv>`3Li{ENo`Sz#6!;MGWZ|ApmKhMq@q|-4+M26txndmi7b=!mbLh8@=DdCwV^jRv3t!41~vd zTod}F=97Y|j@}N2S)S;awkD&YQe-l>W2xFha{+ylmMX4jyHPISN9H4|I7%H+Q{Ix4 zLOJ9ieuVuX-m8U{qamaa+DOYncF&2|01=zJGK?R`Y5EX$4Ao@5{103fRi**RFwcW7 zk%M@qXiclpk8&oe#*fI4WP@Hp-^lFY{<}+O2&T`YkyPl*wGU9qdC&Tg%i^$d1~HXD zZHX}+IcNbag%v=(xf=+TeImv1R@7FTh^=Td-b9XS7f1l}!nfpO8jUU+Q&?^7Jw$nM zJ3+0xD1Ogo3C!dlxQkTNliOKK8i2ITaJcKf?{m5iZ!1!-(vHr z4*rR|>5{3OEMO`ExA7i4lDxsy)mNxgBT0JGYN!#PNM@oR+*R%+&p^`n2~;-Q zf!&xX29maHgurr(Xe8D{?tP3{Mmvga;wBj-&www|N^b5!zm7*aqgwupM2|w^-+Q=)S6)Q@sK&AX5Y@|RHcE@}bSxT=@2bjV9Es!O0k_ftcL9s^lQyE?!9#+YH&l9qK!LL}#0Y_Kzco;m zxCwlS#k4%{pc^2zvR3uxuDm*)j>pQ|BnVf9v8XaQ9bExm@)#e-+TypWg*Xeca|!G= zo(DOGva}9ADj$&TYNY<2W&uj&J5i>eDnlzTz3@n=#Lgm{(NTGoOkwMA zabY9!;r1wu1>tC#By*?+-ByoC4KYNW1=$=!uEd_&7xA2I<~7MdknTA_Ye7!@F!PjQ zB0@}7lI@h?&}mXZpQPf+Gjxhwm6Pc#UJvrXcKm?sFHZ2!Bn3RCo~n&eL;PfSu@AY% zrh|A~U3Q91q%+ts!D%+wxr=NN*!fV9i5w4;xL0r*=>dIM&md3!j#&9ks2D}7jbys^ zLWW?E{~N}Z0R8vx#+LpIjg?COrm=$aMw0UysX-|F9~vtF8L%_`o5l)sQWyKpjJmHsv0lsDE)%`nysq&;bCSD>IOR60+ovXJemm!ocF9QOIq zvC)+s$38|LD9`%z^W0K9XKOXzw+)+|94u`6ew^>s?`$WxLGQwjoLRr^O^Ifo_TT7} zFGPQGz3sB2X~SEB2+d26)xS)AZt&->U$^EDO0Hn%do3eh_{9FLuJ3Hqdg#W9wO)b3 zL_QC21F~ejfc_b-R(!1hqa{?50Ou zo21~YGGebymYZDAJIq&(JzO!NT&HzK3+yQuSLagVo%+8_lP~=2_vXa1d)3e04{e&< z`L=ogiKT^}Uti$aIo|nFuzSqn-3`9u{25+>-tCen_1opLgqpr?PdK>6?s|((Ne>?T1X(X`E6{$=?yR5|=WoZ&a`AoO z@w8jg$;PETg7bekvdCIu%b}1j-41l_aJhF`uWxDj_7-&d<4lRI6KcF0U$^Ya8Mi-e ztg~Ih2PW>? zeSZ3`-XUIO-AUJG^E+NX5LBqlh=?dzuFa1rZ{AgHyU%G=8S(sKQ)H>%V07Dk!+%~a z1Nqi99!nFV_kS5y_Ivyv#{A9Are`#pbavCOoFAz_`x*DVZ%0fybUv$0?+%+fwDCz8 zv9N&i!cn2a3LcsFQv7fPi?tNUGiY(?J_Vea}{oZ=N#eRlu zU2`H&>}S!#D;0i={T%xDVm}wlEIxntYo6H8>xOw^KO@GbU(eXL`&j-M*A1BtJzkx8 zHtgEn>icchCvIqVtB*Pw;8dRIw};FeSkXP*lyleTyU8`G?ntYOOZ9v_`TD|PyWZjd8{;&}0%7`eH~<_TwZhoyFDe`k&NnB3Nf?fBs#iA4)<-Q(AV{W2wAs#G|l^neD% z_Ix?I$>q*m)wkTkhozS~PjzT&x;)qRV~A0p!mf^i?z65|%FVeJ9MJF1w6_lB?H}~L zvAo%C$H>ZCI-UGwDt%&KF_jiK#K zJQT1cYtO^kHrM+5`z0@kJand9-`3jjr#)8><dBPIk)xe_8x=NX_!y8#LLx z^Oz3ZhjFd)N88rx9#gntm01M_mFjC}y=W@4pvub|8`4dcCXQ|X^z)P&rCNGca$9<( zf5#?^N~nZ>BbyYxvr@dYpH=D2`YHKy%8ZK9V~QqTyYsl>mXkvd?e&|xsmh#pspnK~ z@WZ{=%Os6nZY}%E)GTeu-Xr<cuW+Pc8I4MBo7(WlnG2$^tUai1z>ww#~844{OE_V!==U_q@-iDxSGKllCRhbitW znjNpa$oCKRabv%)+x-Stsd8Muw7kpxqE%1jx;gbKw#?`&Cy(st;S#p!X+jsTD4Dys z`cRpeQ!``lM4I%p${xeTrRZ0m?)p|mQ9YMxb5M4#To7YIfj&p0hF|QWElc(R+<^+GoGaJ(Ig| z&_us31A7(g;$Q5%&AugNaLKmucInyZ?*5HxI|Ed;h;L*Pe&V5JHoT31uirgk)C8lrd$@)IbzM14V`m z8B2~ZcN|{m$DWyUxlu{&A&(i(5zn}X%JjeI>>vufA<8b|P-S?q=?Y;KeYoF^} z=Q`i#E3(X~SolHqbU)h${#{#Fu1#sW5>dBO;Yx2`UilVz!!t|sPoC{tZhp!8kokz) zoMD^tOjd06uXBU-h7z4+x$cKDx6w1TzZtSc9XiQUO?je*BJ7f%B#c>kdu5xBwhJa5 zKDP4un$-By@~h6XI8XVM4kB!jTN)Y6%T(_$}Ch}BAw(r(>fDx`!GJBt+4&wnVNI=ho5Kj z@1R81?vZHhy=R=U-s-^930dD)_k~}Me}D2&Fry&yo5kmppYUjzO-fAE7oD4BrsnDo zeuzg7+-_6Q$YUQ;65U&&aMox@M#Hi^0w7F1l=xS?it^ z=<`@vI#^O>#p{AQv5xV)V&u|hXyT@YUHn7!t0%8!3`i@+a_Crg;mW)B=_#)4u1Mg$ zN@My;`=6whmYDY?-qSAHwWCQh?!mXH?NZ}$l_U`}y8d{al(p*FG|r8CN*q7t?h7}` zG4u+4K6F5JSWwx{k4>fU;fQ12+Unwhoi4!%v2Dq3+=uoX4CSo6%SiuO;re=}HWXSy z#GEa?^f0-$O&~dvFE7Sv#PnA|smryyO`eORHQN@oEv-xCYP>t)=}5E=wP+ip#@B?$ zGRvB$mh4{Mv8ugr$V%J9&*Zazb9IFw!+%la&aX;A)ZH?3Lj-g!27HCLmVZg&xzm7DjA7IClQ+qO!<>6ects$ksD zRm`g{v^u^teRJEc>Lk=5>r}(lQG1j>OG&gyb+MO1lf$a>;tgK$A%ii)TgCRBZX7JI zDX*8UQWO?7F<-Z_ebw3-m+6p~zjjQfzWK&?M#q1Peji$$Jt*0~>75dH;|h1d{`_2P zi4K?O-goy+ps@B8Bj1wt9^6-W=s>9U`o6|pg)5v7Ta?wWP2TAnomL6m^OarhyD2%| z)OFpDA(?Mkj4>gn6x%1E87tpBwd6gh8>zlH@3NEY1!;qqpCcNbx+D&bq7Sb#z7t8x zj7)YthddGCEj8py$C1t)DV+y4q-0C^M)%0PO_o+^O`{(zUOi0n`^`wG`f;{j#GzEw zXs)SJqeE$UgX!W6!RKCY4t?s}v!pq)({SZ7gF$E82nzu-nao`e_mAxJU0d}fP z54nRk&pxnwZhCXvPn`SA8@IehUWW4Lw7sAfkKAIzbn7#TOMR+HiHTYF7xCe4LyfNnOAEz0uhqiEB_ql!wa%@2?95MWU8Qf=WFa45Z zH7UB3b<4_joxU72aZH=UY#t^Ig`w)V+CXyXf5qsd^$qIyaJNC@DF7i{NSD zZR)4v#tJ@8nCRO+w)~d4$GNv{Zo`M#+B=D1dn*=;t8F#O=_zo$md+ue+!G^N5dJEv zr7vsbM^DGLysVH?LA%IBpZ08Vzb5>}P| zyxuF3RMwOQb7x6>+UBxN`ndL^4e!NP2!9w75M6#x%~>t@QAF(3RUgMzwC+6mVeah2 ztl*U=vg2w(6|bt&AD6n6oV*_9xpT?ZyQ>)ir40VEliePvK08u6o^IFvu642{I#Xbx zHNIOub9uXwsroPBLs{_GrNd)LTjG0{)oKDCP0)!#4t!Z`LwMVU6FR%AUXXb&$h;S1-U~AC1)2AP%zHuRy&&^mka;i2 zyccBN3o`EonfHRs8(xrkFUY(XWZnxh?**Cng3NnC=Di^EUXXb&$h;S1-U~AC1)2AP z%zHuRy&&^mka;i2yccBN3o`EonfHRsdqL*CAoE_3c~k%AU~B)o%$uM{8bSX@={Bf) zkAdp7|Ao26Ynpvrw<|!V|Gm#|M$Xs3&dHF&8D8Y;agI&g<4$HA489Y$`6Gh99;0qc zMmLE`ymS8WjukL=TxRg9ds(`-s?&Ck~GJy zSEj9d>Q5PM8j^i7`Me`2w9ey1o7%ZMqa1<fIpr4YlZPm_XJ56ZEbwxK^ zb@kBR6DlbjTNNem?O!udesWu~#?>o1(_kT8Qn_)$-}T z8C-qO-sycUkySglX6sMiM3#iZBKsqHYb9({bUKfCoO}?UK)LpMT)F6<*v8l0uIB9e zbm%vuAnRRmb^fT;ZWrfyx2fngrPD>b&uD-zn%n-#6h@bmrBVwBMP8Z!C z9>aSk<~mnariNXQiEpz@x}jRp=jQ&Kak`-CTWwoU+C+An&C-owwk(;DQY}mB#JZJ6 zwiQv6MEdnSo4q^3uUb$E&HYv#Tija^^2w=hSuw-IYN2I!!~#DUtkLKS>dqc`qnvc+ zoH!fX7pbOP6S`ceRX0Vjq$6TOjj`o6UH(;GcLJqDe$t~?Hw)Zvj{Bg>Q=TQP=wj90 zChn4&_PA%|?yAWj>qcXOABCKG4M)B^m1K*bIJP&nrP!h8eb}}e&@yzeeD>Lpor{4{ ze#*_dJiUVFL5bhC&2ZazxM)Y*RX*3!b8>%+!5wz_oJ7{67Omw*=%cdsQQUdWCF4_% z$DT`tw4Am}AA)C|&BWzdH%@Y2{an51;ZNtzBeyKKauW6K@9s?I9FKxF1)8nOIB)YT zM9;)it@T?}Kptnzy?x&WIx;ERfy=V9GcPA*I_HA<%8_bbNvn|6E)~x#CqF$YxcSs3 zW7m;-{>pqPA|Kk7c2+;>$9P;&%CX)^13r%rhiQczsa~;Tl0DL6Uv8z&IyMYbGVBNY zeFO!9kBC_eZLQ?}hUhkPU3y;r{7w7l&|bNY$^`S}x8xEp)$=KAtEuw^B?n@z`P!BF zh<`fd<1uBW43~d551CF@kqmeI`bgO2>2kg=*6q9UkNNz(Rdb4GHt@rVWoq6RS)0So zAJiJ%!e42J#o3r@X)4!iCXZG;xTmziy<;4E}i)D6j&$8zpWD+{4eYDH`IL*1Lx-9C4_`Uf?i{ zMv?vja|V7@f|r{QM^2daT8Ha&ZQt)}=f>`ly`SrYl&@!Fdrr-E#rHeYqRibMUl~<% zZ(IL4&WCtzd&i`1Z|}V;%^mAv?Thz+zh<4|?G+j3kjW=9)pF6ZRFKqsV1$S=*Gmeg z59UVd7jAr1=n$+CpOA5QdGL*{Az+4*!R zQn|=8F0Sy=)up0lTDyNW7QAr(Sn$Mc`+>_&ULg&)9tG8&?)H6i;LwEX_ME;*?{MK) zy%IrPL1tTr)AJ^K#*=kcn@^eRoOx%KyX0At&L@IP-rf5nd)3!bsmD&NC5BGr#^qtY zRvRw&jD^WLN|-BEefzmQoob{1v_<3LGvhMr`+d%)xxx&t!4;qDnm%|Jx{9$c zF&Xa-31qGQQu4xaD(=an+>EQ^ljEr=0%@j#P0(mx6x!T#P0u81CTo^B>ND9T+Y(l2 zJ}0>{4@%!zt8(R0_EyhY$NFObT|+SsTkaj{t3T^+AKR|JMRO|UM0iRDQz7GCoZ5)$ z&pS`6Rp8R+|YwlH^ zit~rpn^%XJF-xTT?0gRw{o1r5@qxj+oe|c#>1iLMCcCs+r)1neEIzg7aqXo1N-BAB zwGpU9T(j!P)G{=Qvk?A8YXXR~st(5a7?J5rzY^O{17R(kdy zpLROMzwMW&C4bRTE@(=sb@^hBs*|_W3z}E_su?$b=y+~p*>6VLDCe4}z~zJD`aV+K zZbiavs)u%#Xa_U$;w1FAyXxPKJQOMJytPEdaa2*qIJaKiy`kIYosyD4o%`#^m0wB? zbRwIdoflp@EA_N##}r!Uvsq{4mugaaj8E6*kYr{32WdTPvn~35tjaCt&bzy&*s!QB zgU`{sc28Z_$@n_nR|V@&*$}Gc_XF6MR0af%uS#-17_;TnsCh@_TK$@(?_W}t9%F-6 zsMi<6&8ZrdO&;fubRT(OFnOw8#5XXla?Fh19@rac;J`82V1T!sulO_n`O6yuHG>!! zj}Wi0oQSAAzIcm<$)0~Xbf_BhNm^D{*ZLU29gg27*PnUw$g=WFtJ2vlSMO`FrQVeR z{e{Ob+fFemm)*sJ{YtIt#qT;;H1#-HZAwGT4NOe^iRp*U0=3shba#q|oe28!V`BZp zj&Ij%+fT_gq}mq`PgQ3s)_CoiP+PjIN3^G+-(%pJ1(P8WI~&n<@KNP+7mteIpT#Qq zU)0Xun>xGraSAphKu7F0==TWvMOd5lzunWmTxCw{$;nV1B-W0 z@RzlcUk57oQZ)1WnqGmN9}l@W60Z$54vFm$KeajhShn*3GuNrC%4zXjz@mQovJ_6|2Fzv=93-myMlXD)AI*o z0-G-0k@>i7Pgy`ihd58k)75t#`sYg=jx3pYeBp8S$m+8hvW&_MM=QI|N6DTCY8>Al z;MqB(w_ME(we2G}j#*X>bjn|~7bjflsKXWewk-4NR;&xuoAqt=&D$l2Dtec2+0E@= zaxzPbUW`dMHE*i*I2bN=W}i--kpiK3Q@dwPb&Se}Yh6}4hdw1+DZf%q)9imXBNX5( zw>vF(rtFD-q264+S7DuB|7Mpis~{=+V(sirnfG6p2_U^mSDvxGHQz6KX!+85-8)X~ zb(`46r1j$~zQ?~spJu0S7Qa-1o-)4D=5e%rk6wZe{zSH9+kh^q-FM zu7jlvR~$bibk;FLee?ES?#1F#F2YxOUmQ7E_&mHk&oMQw(poP>mEt+KeUbX?lB}N_ zvkS{7C&~ebIzqU!YVK&?od1BAMQ3>F%d`DgWVihcc>gr9 zC*b7F^}EjBW;d!h%-HZdxO+;vzX=$-CwoTW8=de>sAF?Mz{EX63-^7|!=q1=l>ys$ zo}E2kn(LoyE;a_2klYr|zu!Y9JP-8HJyYdkDc&e;*0Hy3xjsoZ;0 zx#YSXyCV2sgHl*j5SK6&el_LgUPs69?av-*OdyuYJa2AWj(*QKN=v?dar2r+C6Dha zOMLvj%%&eBO`mwxAD!VwFKPd%Rbh+X@F;6n$i=qe$fdg`5~iw>1fOeRCAxYi#JUf2 zNe`ZRn92QGWzqE26YhnPoa!*d%b;XJ9-Mah74|kisezO>H0158ZK(Xzd|*oO2%~xR z0ZVA)_-HsX_fB+A#2Mk;;lE7W1(>I&4kjLd1+33MSkp3#qC-E!G}93+p6aU266;u`u=B zHjT>JQ70cier1m_@=dFKHUT(tO$XXkCdGIwg8 z4jkF}3w3YAa%(k z%?E~W8?G)A<-e#ta9PiF>(OG9ZKX@mZ$@P+{rCd%7==x;mNH;rkpF%&ORw-gt$waH zGN{@4c5a72bgGQYTIU@;&g6ZUFiiC@$8uU1v);Zts^`ZSE75g79v^!VIuf48L$Xcn znM1nRe+I=HevA~G)4D#LE#iKlN(n9u%Rd=8P)Y0<%(>HiVPgKi1vuv)^FJRnxNjjj z&VNly04}cMS@ZG2YDsL>`^Uc1mpHNX_;Ye@@wVnK#SNt8%WgIPP zIZ)G1t$)k=BNGR#QoH5r4NQCj#k$wsMS!K@alo(cr;=S{>L zRD%+vl5ty-3vFVx(-g%`HZTtnDySMLL7hXg1DyDB@OLK?W1a*cw*=IXDhGwWQFO3`z4WT>G?Ie@-hl^Rw0DN5u;30jO3~Eg4fby(NY6@P&YNVoZm>EGU zpx)?Ks*^H-he-<3V?8FP047g|c?>BLeHG%j6_Eplnt%IZcd1gUl%A7F3%wXEu-o*#f(P{?P-4=1-C0Y@?_K zc^2{`xd0^eF@ms)m`9j_0Kxi=nTqa!mBI04$ozSX0H7!uz=Um4WAZX6G5nKUf%>u9 zh+5`RW*F%Nuu4Y6CxCWJB`JU(yGJZ0oCe-VB+bsls=+h?W=)V8L6x8?m@i9>WXCvJcUf)NX;64Q z29%|>MYp1#Sg%0ucw=2Gl+{MR^Y6 zCNu{?G4nt{^5gV90D^O4mqxdN0_e#!C=*Mnu{Z(3rG#~c8O?G9{lH26Acb&sYM8@^ z*vqcP1h^ae8mf%5(aO|vycAglAnmoRXl5Ap9P^|;qng-90BiCkLpXf#6?7jn0NYA! z2B^H3por--Y>O$03g~^=w*QKQbR=za9PxU1iBYa?DUT8({*_pdR#w3;OdrO1GWn9pxHT|qa^b+ zG7J#R$3exe9mq-a9AguJ5$iEZ(G+GhDDy0Z?u4=_acU3Z2DOlxEK$sw844YNhVf2R zp4I|oxi^wgv^n!Mcv>+~E0F-&xtx^?N%9R@Ik zVd^O9iF$(){shqcrxU*cmSF>yO|;OLuoT#xrciD&gA&HHkt9$koD2U>tN4A18%u@jSb_5G06Nx!=BW#6z z$L~-d2tfco+=p!^m8cw09N!#K!%vYt)FD!ccn&+`+0-pM3|OBM)Bxq9*8nWUBqana z)jN7C<${IN5GIWVfIE4Czon*;P5>_d3h=_}R5k31Her0^2XsFG6=cJs=pDiZJB9;z z8On|t(e?n~xejSV<%a0sSYa5zLQjK^(X@S^?jNo#6qtQ@A>O5Hf>5LbFghK(ksw z#sE&Gft;rU(J<&D>;y_7w-F|A2-FA5z^{zfKwj!2>X0-5Lsh}A zFhu}daiZH=h=0l8QgP1Coj$5KW$Vuz~ngSW3?T937f!QPLkW9=2K93vVy0AU5o;0Rz!Gi$R zUX95EEZ`6F4TTZQK+*1(ST?FcuE*X&{Qz7milq=g5bFPiqQ&YA_&*gb=4JfTWt;a` zDFS$NBA{R~h;XvaR~!E81L!^|#>CkOlA?JTJd5W&`~Twbfr8`&g@b<(1yNE^+MzfG`qz2W8SRrl0yTe7(B zmxG;mJf)*cJB>@4tlVm@#VCq#4*b&AtSiVb!dF~lkH}4FymD#qYU&h+#JjSJl6_GI zQ3D(EX4S%iH*`F(R_RS?cy*-Y&Gm5B{%!o#&ceSLtMR=Nn=Nmpy_a@ssBV+r>oM_b z#4z4%m~w;K!#q?Da@s#cT7BA2ZXIY(d^ve*55u~CV}OW2T+~(Pk`vaw5-}fgEN|P$*JH3Xd86cu9C$BI0xr2Th4 zmJO>y!so6yM4TgD#CkWmXzV?FHt=JSchSJq?6ha3BmV)1j(QP;)Iq7shcYWIWS8$n3_l9`~NK~iQPk-%qdtZ0{htuR9 zg^Jn;x3PofVQV(Nz5c_pN4o~@j9t^VyVpA23WW!%U}>uwQMF}J$zw;1=q^*Ftd;(e zJ5lr4@jL3{a`QvVp|^<_XQQ<~P02ys(GzX{VGRAFCVN|K^w$33#3f}TQg%DWE4-1Z z=3nFa%fR=V!(PMucDY|RBij-z^DbImk=A0pbQq`-=NEx>o@CwL`fXsn+)8)US4h0l z+v7mY=6q8^vZ6$)e#QAMs|!7U9Po|ixxOK9X#w}PvIBM_t9ase=E+xY+`aU`y_yYq zkq*ZtnN75|@I)V26v<17pK>3_kQ|2Q>L!adJcDan4Bp-{b*(-q=f*!!wOX|!{g`pz zRIK@$;)?e!fd?DTX;^jFl`5UPBQ6xZ`=WcORPk4z*15hSWueCpzLsGPZ7UD9!8^Gn z4Yx#61)=O-kv74@nKqvBhUMWY4b^#awuj#ymHSmAe(pD8m5j4V%&nuAA6{~0^(h5B zPW!P4xxN^meDGpJW2f!z6^2!TUo7ER zUKv`FTe%fPQRMo+*C!us^4hGXbOQCRk%^k-ld(q=HhN71bC_{sfQPyGu_?Gn3Q23LJd$#N5D zyxgI(p7WcMboJ)}oiYE|wI@<8)C+z{*x?;#<-ByM`O*&0{(wPIw@B|3>GFviAM3ce zPq{6-SNJ$!K={kc;vN&Ai+rm?P3`928r|3BDGoHKUd1cu{ zRVcUmU54{Tp!e^4;U!2 zlNsGdj@2K?)htY_0Y!{ooi8f+!g^?D70l7U(Z%Yb(}t7F+Md7p(a&*at8h)!hMC@> zr3ytZR{JFS`t+8HZ%0K#<+H+__v9}3a*h=gj#>Wh)3phijIoPZcS=_oiYLu#r=SuC zYqI!e@c2EcVf&=#GC7tPL}f({i{Et`-CMhf!H7L0y;taS%#Wd0vnRi@f0&x6IU3Pk zN1OXJTNtii+u9^D$9qw_)FNn*Dr`d91hgeKT-k!ka$*^G4s>R%p! zBKX#)O~?BEr?!WWK8#Cddv}E^^EgDwM(N< zd1tu&==ro_8^`l;-DT}5ev4uqCE%g%ZKo{j9q2Br`WqVAVyg>uOOUo++uw|Lp~0mY zDIdSv*|pnV<46tV&X>IV+0OT|b)nh41h1k?0^SB^-ajxn65i)~KlcYY_0VLlam60R z6;3PcopL;sde`*4{lKQBT=Kb`Oc$}5F|*_oKdl-+(tVI=ur*iz?#X45aAa#nT-Pc1TCDwJI~5j*I0o$Gr>?>}Nw*ElOP{V-(l z^J;@>shxru8L3RkMz#z17JfC4^Lwu!dGuL`d6#$5u;sB7H_Kn$^P!c$9vk%UJ;HxI zwnaQR7dJ?675nqh{^X7|D`?Gl?eG+ka?b3kQ>FT>u1YIC*CxAml&PyvrD(YfPUj$t zmhU(;O3L4MFf|H#Tl?<&ivD2b7;VQ;(_I6J!@W0`n?B{-V2KIJcPk%?wiZ2irZwb9 zlk)(7qtjQ@){pU<-yFTVxlHJ^X}Y^pV2uFQTaaza0~>a4jN4~E%?JzElRF`Q=FP54 zVJdZfHk3$TmGH<*la4)Zd|VNw*AgBaYrHrlwzO~sal;V~)ebzA5HELCd!u0pm;WmF zCza{pLx-1l41_&Dnr&rs@NLTWha&CY& z`MYvVX+62t^^!Gm3TKM)_Fve%_NKSrm7&LrUIwtchn(*ni*}E9l+zpj)cb{F*GKo> z?@ehRgR70X(mq;^S1Ox{7PPz19N@WEEGCtH>qTbU8ah-%_pW=`mcq8y@iiNIIBNF4 z-}B3y&!RbOM!_@em5lB7b(W9USBLZ0MVvdWA;p`p%4w*Y^8?TQ*Yb=5^O3CiIM|;^ z*xwtvfV~AWsImD39Gpj3GmG@mgJVP>HzT zme5)>=J7o8?hZ}UXj+v+*Il~!6kkt=3b8a(P)Es z@uck)kHssNo9T)4saaX>gKU@XDz%bV+TWr(C79>u_0w+d34f)4nTo^y_r;o#!gW>$ zJ6I9b&$HY~Qo}aj*M%KiihUunBhrGa>ay<-K)de-rtfLqdn6#be(%c_&JX30V)^*%sL32ni@SW0j|5*t9R8{^zBWiR zbxgr*+U}f^wB;nXg(#0E^VEP16AT`{MrCwEve~@ zxW0K%f6;?aX)WQQN901M-eZYWrnynl$amem#62Dg6u)?c;!S^oXT$>DP%Teu23!Y{23 zO0m-o^luC}sKsMsWf!D<}s4z)C!*Oml!_ zo%aX`auN5uWa7`5|10KxWtUR0asP*S#k0Q-Yz~cbe2^KRW`ZtpcDeSe!SjG?!qD*~ z5v?xEC(#x!@>bEQo~0e~`2}0H>94KoX9Pvhuu$8$SpRPj@3tcKFeI!*LZCf=V&x)%)Gaop^bdMp0R%4GNZR`<<=;t+*oep z%ME1ShBpU78)2u5B_h*~N!6>5N5q-*T$;-@u*EqR#uv~3`uY9Gwf+AvzUKFK{`=q| z=AF?$L*p;U_KNNizIt#ZALqZFl)nZef)V&1JM~97bfJQERR<7Oz@dWkLyryqd$$N2 z4F)X21qQAhPW(IDi*1U#ZtaGQWR@ZmBkW$YaZddqRGaFB6;uL>E~r-o7>L6 z8$$D55=eUe>$3CTY|QzImw|E3qb~nC;~yXCMgLTgqt_=lzq=*1vzlh>O>`9DqDrKwAL-E$hj`$Erq0t4n7;Nzc`=u^xu1k!S=7@Hqb+ALbr|3tS>?7 zh8%x)@SiJlzMB6j*FPDbf9{aM^;a9_9d^zfCHClL>bBeC=C8vGri_0#`Om>zf0{er z1)MuQgVnPYv|qc<9|>&!|9IqldpJ24t+sTtb&e4PbdEue83q%4$1!(sJZG;(KLEV^ z96%BySUEn13*sE)O(c^{r)HrPdJ{k&pJKVOm>eS3Y#g~sL{k_n18Th=LtRKwdWHZy`E(k`Z;tN_PL2VN93~G(4Eqd@9rFT9GpB82ke@K;lp~lxB-UqM`Hf8FCn7u}R>?%%9Lt z(goX#NaB*T7szTbg>rhNkMD}{Dpi7HDdeOR{+#^1p6|m zm!pqE7rIORpijbE0HodrpuiuIY_tzr0Kmrg=oF$8pc3NB(dSkK{HvYG0|ui)H-2r`c7fy}ZB#0K@QMvyc z=6-@f{HM8pG1zzi&+jRX&QJcUL0|!FwG;pTH(>N|2qS>~BdJBad;-c=M-r=h=HK-H zdIknQ?*xedn`L{Xx%N3|=zg>K6+LszF=&^sP zZ^dp;4NE$Mhn8VRjYb#Yu899qkz zWX6wPyRJCf66@+T_N2e?ad6LF)yu^%j=Bc)UY@BQRo>U*^JMhxvf_sP{ReU^*2NkH zrBe5zZ_W8t=RT3k5_Vg9J4a?(0pdv#5gV58*%SIkrP0%4(BQR>c>?ONF}I z9wgd#EjCmS7dP#=j_6pu_cN#T2G;2+^gcJvqBZZMTV2_IytUlR%DtS?efhG?@q}0J zr+i)ZTg$0BtF5nCH82!nS`wh?zb44KSgkg7c6esN1}@mZ1snK(PD%g2+dvBWpB+@} zzc{FM^+W4UcuBwF56=J=Zz=HU{<&NNc8{1(HsVwImq!O2yq42%Y-MkZUUd;sEf)m8 z`4feM{%s@Yg;glfnG*~QU$j_sn7XL==7l$jzB}qR#l%}G;ZZKO8>_(g} zoB5s0fG5-0YWtE_T_3%5pZyuQ8i+6a(~|}lW#d};muvpV`^8EvBP3nBB-gF{4lenR zcuP9?@&Dk`{uP?|eW(>z~cHk@G?+|0i0(f~lk#GWd zrlbX;1M`rdp-b>8`Y7`}_%4NY;HxwzIPyLDltADc#1ec6aif+IOHgI<1JQ=JFN?EgG#COSPiT|F2XXP z^Mp8h3(lohV;GV}apPL3C0;-a;e+G{kWFk&_R(+ARQfRe3GJpwXif~LKGLPcWonop zu@)i{+lk$x7Nc{R9u zN+I0IVR|QtQ(NdKWDXTbKcqM)3)+^-q#@FsGNSk4&nSPo1Jj{y(DfKf>CjJ+TCAR| zK);hL+7C9MZcvxux3nvb;-=JjmMnIU7@`shTb2#W6!gGX1_$`|XPyRQ!v-_PoDdfD z6Lo-vK~Dc1bd1cy3g9aw7ZM9;<7x0ASdOCMXYf;s2YroL;_V;@)s?g&B9SCgn_?h+ z)CoEiT|$l0qZkjhk9{}!l~y2Sa9)BUEU}~HXM7xEP&W8i^fIZ9aifXETUZ@?NUdV# zg1q>XPz0Vx%OT--JiQoC#HJ}B(inFJS`aBhpW00xCe^6*6oaBja~6vprV(nI5~UI- zb@C@IL0qSl=|}>jAo@D?7M}voE|)w-i@+AtP3k!Gn%Yn8#rVm?^mXJ0zLh+M`O+bD zD%QwK04oG`)+qgvN?`U-T4WNliK6it2qLFJ?yD*Bneap&lLT@LdW?%hp)ecy6|#nY zP)sBrmc(!2$B<#78;gTSiC=gavWa{}E=N+SjT8!2hXL#d$fr~n6^HW?5ao@@P%QE% z`h>C~Y4j;^lUR>EAy=cDun3^d*aiB50g*TtNYwm=RZ<{h7quWY@gdBDBJuTj9uSbhS^P46Fm?~ z7*NvaOX4NSjF!YSk(E#@X%9bzJjn;hW#)U_6=T49AVW9~mL-0mJn&8O7IqCG$ZPlv zl1n_I&k-WzP09_O#EV!sdYzJ`pQ0BjEov(!LF}Y<6EGQtt6}QI1bQ2@B(o4P>IUa)TbM0jAUP(QK{Wah)vK6D#CM!DnC1d~i61_=k!lbj^tNl$t$P?kJr>5v{k zYxI(gpq!{t%ABepK2hwHGVVsHPzP{|yh}aDZxe~M8=Qy1gctOUQm5D)|H-9xFe{Am_dg}34f*je}hs*edk=ZJWW1#yvDm@)GqZiwxK zml9i`awvi*gwkMrvJjDhBS>fT0sM_PMDD=$6E{g5>A{t$P~;XFLa#%;$v)}H%B_0rRXcOsx)nZG@?dUAVMslN-s48&;=|^)&7%Ie$lT)xNE=f6q_`p{( z9hb%CfHvm|{+<*hx(P>eJ>^Z5kVk1g(w@wxXXspN8pHx@$sCZw|BKoL`sg&3PfQXo zs6I3s-$gVbo2df(tt<>GYJnR z3*Lrh`8ydW|K~%~S>9Naxaf2{$T+%%?uFZjuf7eGsisBD>KTA_?dMjEPLR z4ALUsgC00bMnDG8b^=Dv!JBX{V4Ny2Eld}-AY`$Jh%}*#UqaVmp)8oNCgW&l6d@k5 zEKy1FJ#Bz0kXy(*=utwCT!VWOZkRRZitC}Gm_BhEWufJy1ty6!kSh>>_zK>DuwkC0 z7J}d|q$-+$ml5qa2cVE0B;El9RRg6+L=%H_9Z=*Yu`Eb+Y8@>BRC}+u80})30jI!P$eFS zT!ka>EQ~^AF`Vqft`iqYYs84i1u7Y5GM~kd+#$W`0H8CmqZNp9;tC#uUB*=Kr5K8j z;yl1>NXIphFT@)3EYd>|&}$4N-ZQ@fwcr}q7|b|tPzcu~&SBTFetZo4`WWF!RuN3% z1GSfEBt@xQ@;Z37U9=>%h0*|HeFdpTx)Nh}5qTZV*DuK+Vi;+~y6`#Fj+mv^K-Vc= z5U1-0$Bv>SWF)--h4DzBLgAyO$>aDVdXBh4y0F#~yQyWYbTXG*!#Y7%V~3fYs0=G&leaA0hV(=EC1h0Z)NrbqHm=m19n=&EJQcR3Q^Jyn^2QE#$MBd?&qzD>; z*$~fhZu~p83B*@bkSZ{@PQk0ORm4x21HDGC0BmO!RZi#;9rPRU6jkUc;yuZrT8RlFhA1VM5*u-2G8#O=G zj#BdQW^^qc3|j$(lrGFgO%hK)WKV@~#q5DcatGT*d;`|#6Rk)|gSljqn5Jh~sYEgB z5bGtF4?Z%RiOom@GXdXh#59R-$7ZpGg*gDq8(Heu?ko;0rWKPimyRkiG64S@UNBA;q8?eD31NUP!xEXp2dkr-&NhNi8GF=nfJi`lvK2 z0L&R-PBdNeFrKAXd=rEN;SR$sNMX!;3 z5OF{FFGM4>bWFr37Ayj^X^cImts_#$Hlq@O!ukeFSeMPS6G5jqah^h(`J@ z@V7*Oay5^*Nqc}1q6a51JF!<#KeGs{VcuevVKq=H(2DtE>~IN|4kF~aXgE&7?7%P7 zhTq{JEQ;<#+3A&pBOXQDB5yGx`aR-4?@J;XIH;b4`~bZdjMd?_{||d_9#!M}$Nkp6 z?`yb+UC|&F(WDd#A+rWTMNvso38@s75R!Q)R5YPPA|y0YWJ(j6qRE_+sicr0!}<7r zf4}uS&w0*T=lpfnIcwEgGNiqC`?~Mz`b_WF8)w6suSA1zJ{`!$V-LEBtwrgy2aJF` z#cgOZ83w9B4%`c8kponn=5dIoLmZh0y5Z@94Y!d7NEz+`-6)>sw$o*BKU}97w24cn zUbG)SiSEaj_&}PDOkllb;Ik2Totcjk$ZlN6_2GljL%x%q!o7t;x`8|w()hvT8gEQX z_(pLXw^ZyW#T+lSlSXo(;z{W&{sA{sSS$!)wC9hGEZ5A=oc zr7Ccbj3gcSI+~2N`7}~Td+~4B7JOSwVp~X>bSQG5@v z3ag2JGnXWrkU6tW@{r77CqZ|r1ck6BSdqTOb|js?WG(PZK8iIbc48lP6X`E<=pt?q z!+8zJS+)~G_EnIZTUbVE*)QKS%W z#M$I5T~Fpw2R??=}HIH~0{{iSvWg35m)O)184eK99G3Mk0!e}-kJL(DNH*g8YyhK#ib+5AE-3zQGZDCh z4rXq`>2R5q!|(aNEKmeQH*PKY$!kFLR4y2yN@Byep>^agsNMe%1-guAl5DJl#}H*U z7rQ{LuZ6eZVrCp3hKtxl_BW2lul}mIq3dQr&B!4-h?;VD;6BLa;~`s%lgk%Yar@=m z_z~0$G?@y}&NV=nm@d9V*vzkh4%K~BObtadel4uoGMvl?!H#Vv`H7C=LfLAvjIF@e zrNd}GYrr|O@3=b14>Sm<%c&sbi@W$6^55hi3$Gv-K8yq8tmNCI%kg)}&0azrYl#lA zCnXX#8KuCwO@eM)BYuT)m`TKoOl6|+AIh;dSeG{;mxu}%gkB*%aWoo_%fuk)6>9SR z@kDF}d7BsQ1rhrf{Durh^`s{{fP3Kt_7QrEqnR956)j%(? zkK_*4z>!QG?5HLv2v-t!`~rU@1tpO1k+;V zCAF6J9+)ipv+~7Ujh;9KVU=plP4jm$+fTJY2Y`CaFE=vZ&`L|Y9U}rPWs6X$| ztH3FwM=i;4-U-LkZNgLfMo@(7M3nm}e}LB#HO0+XQK*)tlhIN~`8A?44dCvIt0kQf zW0bQ*@&(lT_VCddt(;;Asxs)VfJ$2 zD3T0-sPetc1*VkwK`DQbuY$T^Cf7<+q>5ZDTR|Q1EXaCZ;1KbU)QGO+i}_e~kNhk7 z58OVv7WqH?W$u&IhBv`sfvt2+Zn98(6 zR;Pk%pfYz5{gKXR4-r!_l08Etd>S&sQ#f~W7w6)!IE<};j&3s=f}Wraa6g@3Ux4yI zg-Jkj;ZarbJN5*w$M5ktqJfi%CyB*jRF}@hsc?>Z;mN{m5{0bfj`DSoo%qr*s2x8i z^6XWJ;4b1>=rgfk*AWLk82GyJ+)$hc*+(a6ZRH!g$u{l=(|u0lVjJV@!|l+ z0Hw1E#EYAV%s5q^VHZPYdx~|CewK5ge&_|qvd8&>az}Uz;w{`m4SZjDQwo`m+(Pn@ zb&@!tscZ>jzf8TJ!e&rE^dy1C>L?51;AHM|F}Kr?VPUW@~9EAB^!lf|I> zZza2sAHN<>wK%>H?DiKpo|}nUs4YIu8p)}Pi=nci%bDZlxROqV-AISq5Amvk*q7fX zqluSG&NDf@4Bka|h*3fb%pQy)>$uO-`9L6%2p{kd&WwME41ph$ik0wnE|F~)?#h*M z4J3?P!|1~t#zh}tK;JUEK%H%6VUGu0Zxr7W!1O0}sL+x%b{s#3bc@)N<0KN+^*Cq~u z8lx%pVh1B0Z(~oOkK8z1h+hdih^Opy$Ru`SmYd0GN&?Ugbb*EF6lW0x)|PX zAL<2b#WPeu#X>Z`#~z?+NLg}Oh=n+J8Tv^bkQCx8Ycz<96E4$4JQzqR8_*WIjjFN^ zygBJ5QKS#q@lc7AMbmk0IU9a5l7UFaQP?3J!2J={0l%oHd~f-)oTK~M*xmb9wCJMXRVBS~mrBEtyVdx!PGpOFIl6y+m*WXC$dDo%xKLmBRr1E?5{ zX1?NO$cZh-9q1TTx1ORQG>Pc5ulRW4#5RaJBnjDzN^oEDa*EQ=e1X_kst5asGqq>8 z!|B@yc4fuhD_?IM*z`hIpo0HrXIs%=B^Tvf}&=Mwq zcNF9B1b)4oCjHLkiSNiY=@YrfG(=PqpP^^emTzKS^H=2Jp%&!GzoY}0R+xRcC|NEj zLl#nr2D6s9jJeDlhP-D1`-D5ej$|KD4%;#@!bPqXx;^_*QxeA@90q8Uu1h4rRnk30bo6!W=J+GjH>=3k=O~*U&4%VNl!Rl*5e5uIB@@AwF z>GCPS{CNbY=XKmiPF7e?dsAg}N74>g)ElOXosL&9ZHzlkl`La6QA1{e#G970Js3sk zVx`GgFqV=$YQwv7?)VGW0eR9F@faa|U%AOV#|;(@NUq#Yxg6>vpDg!)C(l*$Fa%e6Y+pQY>+W%5nm;8M;t;Xa=*GucuDv zi*SqefyphFX=OEpbMQLuaJ$$v<`TI9(V#ri0NRNI`wlIF&dNdd53*&I;M&+DdCZ(; z+S#+{E;|TiVLK)Z=9FTYmq0Wc#4e+;FwOOX+fCP_QgJ?H7h$3~9gm_!JE4hF;0*Zy z+z$JjGF}RmfhZ;^_6WzRg%?64Q7nfNiF||4@6VAMl4Hui2B4AIYT5_DcOf^ zNv6;jz@}=G-ylDMJeOY%?|>p_!u65d!)6@EMst&-C+Rcpgxox$%J!nglKHGUU5v*- z<5w!XPv$fC8_v~sphbCc_K>r!SWGSp@v8Fs7M#Dr^P%i7~g8yhRG=J2r;A zs|u>-qwp0tJ(^H58-*O;d;YLffN|5GdB;pcRZKEOEdnzSeZ^7C3+xNe-9Y7u4|3!) zhz*hzY^f|7#kB(A>LXNebRf5zhQCRigxmZ9be8jkdQcnP$!~^yMVnA`Kyn%XK=Cql zkmtywSfPMiCq0Bx?v~7Arcu@!ab&mb8DWL^5V?u3#4eNwJvK{JD7=zO;m%SGAp|d! z4wg@#Da4pdV&;((LQmRXW(L|QQIlZqjzkZd^p{{3^QyFib>T)yX0aS^FDYaD35|?A z)D!htH)cGa!VO2(Fp0NW5<;_pAmc$#vYxDfZ?ZM4FItK$*kl$VEmn;&M(WHi*ng)n za!fI*WD?m4P&;IB2=-+=X&_EwSJN&M#zs@%cp(FRARhsow0s)OP80r+8YYmOLas84 zpq>T09Aq3LC5e(6{DSq7?SmIe*2y&DF_OFNV@{Lym1$wK7#Kqp-s3dZkOaw?agT&5 z=uzF^HcOre8|2hE8@iTHK=pE^@&b*8E`u!^OEUy(l1Fw4Z^;eDn^Tva$u1JkNCdo3 zJ`4SkJmi{?FH^_<;D2+^B}52$a^xr z5L1V+<>&|dmT5yAdyl!#1R@2-K~l`VU`9#&nJmdih*`YYFsKUrV4mXVxR7~?kCGP< z7yhBGC`H&s)-ivi)5tNVNZdt=86%+n^kBBK`mke2XsXzcI!PX&U$Sf1wPYCcf(b>b z$Xn((vq{oOR*SZz3>ERstPa;Ht%aD#fo_F4^@YMt;>_vrUARR$UW~xYZL@ zE-||7QDzsbj$9de_6AmEW}rT}j-86%6Fatm+lw1uv_1x|^X<@?HDe|T@2LTkMT4Mc za~&6P-mE)4$gO7G_`Uo);OdzO_FNOYk<38nW#147$!n$@a`jd`3U;r@^ptcWnS;J_ zN3fZIrJh_n?;~g;HR`~P1|HoCZVB5T#D9I+72GsF4OVlqa8eRUKZshAt=OAyWZ=GF zQ)M;T*@7C$k|}^Y#Tlmi6=hb+sPk$vW1t_c$s~xogsCiK56Fuo18XZ2I%G;L;-`}e zWX-2?#n2&IC!~;9LZEO9uDCVN<~JcrvQQXI2GSSeP^iNm7w!n3 z_#9DNTp(D9-Y`i(V5k2j%oeYq9Nu4ek9I*f7NrTV-AP9UC8 zUD!Y`Lm#{vCV1ztX^@SMM(25R-V|t8PEfUx7hVCuaE!1PYK>d@X!L_D z3@xO#oDchrn@A1Vd7LuVV^TOX$h{)D(Re#VA&Y4TM$kn}AV$zdno4E(kGwk2`2t8C zWGpOni;DR1C34P?qelynGAnXMBo%3M4D>B`LMJGI zB=9+c2t2D?PL|k0eHKG+Vg;IqZMapam8fwYEkHS(1nUpt+1YX~u8ZS&(UVqGqTTCKGj9F6fa_bPqQRH_;6^4X1GGkZbDEBQO=b ziV9>4siNilQ2K&fCv1hj%nt!U&Gjay#p`mD@gFXL+lB17{@f6h%-`km@k+swTgFWi z`*W9s25BHnI(&jE`XY8CvyxnAbtTF8EVgIv6MyOnr+o=O75kG+VIJ|J3%Qrrm5zW) z?G}0tbwVA)mi0!@Ve+E|dd@$n4z;JLFmWD2TZIaK6}*#uxaaf{m4_?72+QyTVBX!5 zv!Eg91K)!lr`CcsL>qTSe{Q4bDLn%74=G|4-@^Jyp5U`=JtM(B_$B1AfXzZH$s+y^ ziYMxjWz|y?ZaviAje%-sMz*r^;rUzG(|8k^f`5@|q?zYA52(JU!X$_}U%>aH9#9Q+ zr0o#%kD-Qa9`tSunS1cnSvZT2g&O;Qr~%CsOr=A))52=$GOib2BQ2m%tC7TD6?Bpb zgWiun1C!cZC5j*_!b<#r9OwP;DKY{ol3qjwGWn-a!B~JCu|HadSCio+gS;gdxaXV} zRTUTTYiTAofqcfgWIa6ZPAtQzkT!{k3)utc0zaQTB$q(RHG}Vx%JQSdaEK?9ppz*N zeaI;3a$>>M14Z!xdcoAf3fMumc#BU1V&f5E4P{1$quj5GGjGDl`cLF-( zlf`9plXRuL9UmyLpaSU4O%XTo)o7sP1DxxwEQhA?cI*SJE?^W2yth6$4%n3+upTNz zxo8o(%(_6Hwj5bt2W*V1$vo^1yg6%Z08;>oxRZ0Im!Vd=mAYY;81v>-TOxz?SS37- zccTWRK^RH3q5iiSe$ulrgEfGL2z~KtI#Y}!d+}+h2Gq-p}fFgKH$J1i}8e zj{Qbg<0UXD;f^I_h@eRh(oI4tnaJCUvIO(G!e<;!e~E#x{%3_|sL#2;)xLu0GeJxP zy~Vy_AMyLJ4G;=H;~s1yzs64^(PT^(k>;HNl(y-B~5^Jq9<3Mz)_ zFeRW#DfTAA*x67sH)q{hRj8S*XRgr$s0YsDM__Gkg;0q*#C$nrYAh5>FOh6wEI30& zF-hpdcF7*&Gb9G2mL0}qa7Q3ZJi%wOe^?cmz#76jlF{%lRcs~v8qVBc3n5am!-_CN zwhLx(u5dAs5%1+=x$)>D%#U?IXIOztL$$0H^ougl2+jenYCmog5I^H-Et4cn72o1! zK2=P_<@ATpjsqe7?_yub_M=L&za*^C#Q1ZzK*&tyPoZ(F4fhT`V~3JE$e%d^q)vV2 z9xD%%4lCgE17PE6*0%#b04igb$>3+yl7LhjQH`I>=MoIP#+5~kbQ*I2K zfh+h)>{nXNzePKRnc`=t+jNP#crWb|_d(}UTa-uk$W}mq zAvYiL>)!Yhl4m?1lgwduGg?e5OfD`(S>AZDVbKGoPi}Je zg+TEe3FlP=eG&%e=_UGE+EcoYtOs??2fTopM3w0;G?g347nA#fG1Uda<#N0Mhtn>I zU=z76plRv|k166Sg^AF4Z{#vyy&mzqgt5{Rp#>E&8>u;Vho031SoJBi6K3mzxsCV~ zR2xrWH~bSG<1@FNYvQN#fA_lsTmt8Z5A$~127ZiqlHU$}w>CkW{U~_`^jLegiWKrg zaV^kYJFy?hMUPQA%o};pfpjnT2Ks;_V6vo;dO>gZEp#N+;mm%|-;(<9j)DXxS(cy- z$!nxR^`SFs%`L+nqz!VjSo8xAMt4y)Fng=$Sk4H}6hAnfTA@R6o<`%*)KSQ#w}gIj z!=NAEB;JFpY8|XX2z7eXUn$pc=B};+3oFO^RUuKqb)7f{xR82w=%p>*&FNoW~vJp2I1Am-|FI_-WDr!JmwW z+CVJTLi^yP8US3<>6E4Ch(6iDe+8B&D+a@yLms-yCd2em3bT&NaidTneht0eeI#29 z!&9KYl*fes|3O>yk3-%6q$}?IS6lSIh=X`hkmA3J@PYqmi~qrf{0C8wU_4w_@>d}& z0MkH8Mp;FxS8rfYfK2`W{3xJ47TCXV6#f55jQ-+A{++c3gau5r|9zAmJ(U!dwE;b% zJN&;h-~Wn?l-I8qVqB(w$l>z(km4l;BRBYt*QiShKfBaaWt5_M*1C%tmd8i6C*}UE z$f{;4?!+bZ4QNlhz#eveuxF!?WpYbz$C|TK_B=I^SFBaHFjbs$WbN90I`pM=>5wI< z*R#E5E#duCjP6D9Cr*H=p5rp#t4&c_uip&rIj8|i$}6f~zj5(@_t>kC*xpbpZ<~-F zm3g`En#AhcXZyZ8VLe=EIdg1P=#ryB%Y?e6cGa7XUw*M`klrk%7&YY?4-7_+p6vJS zU3S-!y4GQl-(JrJ!#0D9YHO;tu1}v!GbU8*(j3g@9`hKzSnkp`m26d;5i6@hZp=^i zv0d4=)Nbj3KJL%H>b21DRU_iYt=+0UZ+>4t-8lnSzv17P{gH8*Uc0*CO|CbZArG@2_`N$2-!*$pveWXEvxUih8e05*2Hq>tpR{P$lYroO@y-BA?+w$m zx8Kw)zdDqS*%g+)wR-k7)$#mMbJp*5Pgmy5D&|&a?ahONUdY^C%CU{ITQ0;pYlr(b zK8aCXI=`~xkz?7Y;>`DRl2h(0er;>DxfkYI(93gY^OM$C@7cy0UuK39ZKa8pp&hqV zo)itT*|*Zx)@iJCx_DrTQFZ$drDKhXXC5$C9jTQ*&2+?v?rit_g? z_-Nmrx@lOX_0jmGUK%|geXSY3+jOyP-AAn_OmLTR#7NDxuY8}(d7j(qnrWA(axw5p zvf;^b{Zs4mw>JBlBx&t1zgl}xXIF>nD~BYbbsx1nzH9HDcWklOa{VoS5!DsmcW?f1 zTNZQ0U|p(hGB(QlcDHxX0*^V1A6@OSq~DJzp3Yi2CmR%x37zr!H<#4;jb7k2Z|vr* z`N2mD??&$b)LOSZ-+caHt=^Kdj^PSY8mKwd_`X9#oKw>h+o5OA`Y-9!bE}i<7#bv} zV!KmkV5)D`BV8!H{A$?o@nmgrpX}Y298}}Yw;StJR@B->>-!GgEU}RoJ6N`|cD?*3 z^V5%@xl`&9^GSxLMizDs2pRWBrkOc+CrGdB*z%JBw6Rw(7vNrjuRRgB4A6C*WAK9~=?c4le#;8f* zKdM!BIDC!j6>!wh=a>EgK6M%ZKrUuhpKbnr!EfJ_kvCpD@Awt6O2<5{?sMnJ>HRe; zq90VwExr=zkgs>Y>-t;!kRiBrpE z*C~wH5Y*p`PMHwBcaLsj@0!Iv;Xc!iD{k)}>Jl|-O9S&uIdAg5ouPkZ@`lV1ulO1E zw7Sy8Hzgz)W<#;nV=$k!T9SXlv!CgsoelP>uHk&5TgHc#4CMw z`6LGqnZaLvSQN}?K00UL+QAx0s|!`^tv_m|9tzv!7qw_n$wc)iwNy!T-uWAjM5XHF z#Yv7E<%buYIa9kzYPfrIx#t7V$%l#HljULTxM*wmfXh;w$QrY8i4DrBb3g0d%2>N- ziSxUu*CJP+Y9D{-%Eq8&-ru#7r*A#2amQnug~0xi;f`NW?o01B&c7CQs_=BtIkSy5 zS;qZcGfwpJxAi#wTDp4os1186`q_&``!;0i6)RYN7-zU@?cv7gBJ~?a-#<-L()MqM zA2lX^Yk;@=mimm_B|UBN^KqTC+J}5iZK*db&+%D5a)a%*UeV>kaT6b{W!6%k5hLDZ zD%k8x-S+N9V`rJ;5{+c#H3z~Kv+w*q(PR*QOzF2{%dB5<9V)j@zkWIImX_pW%vAof z^^zDJIX<( z>H1+-&8pL`SDrp<8j?n34_|uMvU1f8?-hlGue@G9tDZNY^ibOV`lmZ@4)b4G{q4rM z#-D8mJers7n$de=%Fx_-yX$5dJ`JwPUc0Ht@uGR(u0A7IeKbqW9Is}y*QP`9(}0w0 z@%8@Qk+%+Ust~}kFndwh0L5&9-^>!XL$@KL+>i?kJ=EwVBQ6_hW+b} zRB4m(K@~DTTF!WmS=%h9qG=xs;x;E{4B9knTVSI8@(Xhhdju!78=cCG82zR$vE#~* zU*=i+nrv=wOIsAOc+ty}cSrY+23T;0(f*U|Ca&nH{m>iPrEQBXmuHPVsCqr9V5t4x z=7nb#=*XPz7`H8v1n>N07^-3)n;d(oZ_waDvo`d#Os)R8KKaPHxUod>(OAdxNjJTo z&T6>kc78K+$9Q2uk2{6yRF9hJoEfj;Z(6coz(KvM{(Hk4_cUAR25i6Hc-l4hit+i8 zS~?Dn!$wv1+j_-+Oxc>QZ)M7Xy%bGv1<^;>=WZy;eN-3VBnq7~&fWY`;I}fvNPkCQ zwzXf5(`1jmYo(vxpPF*g&#u&4&ot+YYiWFLdLO^amW#Ob{fl>14JmrBSUI!@Izv`?m(9!6>X2PR{tnBLK$M4&#mES&JpjtopyX&D-ulHA0 zjozsgU3pm{>9B_8$DToVf*f*s56+t2VxFTiNVR{&_rTn?QxiPX(q4|&dS8=g7CxiN z(c7o0vQc+epNXy-^F6#OcI{sHF4MAF?^0TQ`6RzFw~yQktLpMTdn|3jF}(8judvUJ zvn<}M*3!)n_j)}s2T$+3-DH03==>aGqZ4(xhvt4klZ`gzkCiK# z?XQ(y`qaL@+WU<6V7KjE+Q9?0dX?@P;}Ybp8LHiD*tNNz@?Bep-ppU{^kHQA!YUh^ z`q;hWE!P%!Ts8Aqy`{&uAe|dDwC~M3&vkW<-PVnoM#oKloi*-U#|+b0eiTm6= zI%XyzAs+W*>|-g70x-WuC`wl|2$Js&+Cd@tsBZDxP(>Yz)X`vmVCeK6~WR;Yo4 z;lhIcd-ZlMP8^b9klkbP#1$3QqcTrcD}Bmz4%^i)t8==`Ql~LeNtn|`{_ShGJ11P2 z-Q%V{ne#(qw`Iq|PWOCu)U#%FuE(Yoi~3aTs@NK>{|G;2kKS+_yIE)Rg|e3PwnsgN zD&6>1w7Gs-+x1yt-!<-!4_f7U=5>qwQqdy8^!L=wSxIZ10%Nkrm~3rmpJ!lyCT;cA zSUbnXvK6yVM~|BqYFO6(CC$ui&W+3|=e#4v?lH}{Quvd3ukyX-chIAP;YGKa#@L3> zTobbI(THihdCLfc->+MqzE@W3y!5*y<7Tr{vt>=$uis_!H+`|lsUI;SpaA_)lLn8K zcQ$R_XK{6&SM9iB55IY}s{JPyR~$Kb&|rLwH;Ed4%x|*bXEwo2t#sO}Y~_$Qx~BS9 zALZrkc^=-aEbLYmb}I|Jm4)5P!fs_@x3aKXS=g;C>{b?bD+{}oh26@+Ze?M&vanlO z*sUz=Ru*{b?bD+{}og}eyvAHx58jy?bP%0doo77zwa;Qwxz z4q`y&zY@TIeI=D=NA~t9YMt_Vr>64}`^D?N-#gKF!?Oa<%gZmx>-tQl5lIav*Q6|q zxM`!ldDpGa{de6@){JqrOB>bFZ)+@feI^KcF(oqO zzpwf~#;iRRX%9|GxxbdSj>)ipUj09gLsdV5)ldFBUY@R&8fLRZx~yKI<7L4?#&%nQ z!ZI426Ob9?W?Gqf{&erpr9=9?UPcnWyE#UC7C4%jm`KnE72DQ=?-RFf?`pLTHW33x zK0UNC?CUER3&#e(Q1w@XPZ%BO?X9WUl{RNwd<$sh)9TVE9#5Kdd`R9xoj|YN+pJHU z;>n%m`>XG(bp^Lgc^~eZYW=ICb85Mxs{7M3>xB7_^gpL*^?kC>MSD?iX+&-Dtqxq-r*jHD zcZe7wdA&flZ6Skf)=zrkH*}J6mapiWwPkI)cFv*RRwF8ISMDgMe7Lc*a%GuAlh#rf zJuS!GlVpwrJC)kL47gr>_Ht%k?&V$~+mG3qFP>1MI_lK+-uu5k%%Ek0&YC|mDLq`a zm+URA$mn(Q;J!y!)B;aExX`&UyLYe1HQvpAYws3lEtK>#sy}x(VC{$D4i~oW&Cn0e zvi^3o$-tp%^ps_RITL0y&VKZAU(YPLiA|m@J(`zfn)(YqUe!h~RE~Gr*L-sB2zk5C zxz{Lh<=#h2cgYkDo9g6bU!iYc?VdSfLl;r=EpXaxF~Rn1{k@!uxkl^* z2kOCzT$BfbcIII36wgn4v z8T=o`?te{vd-MbYMJ2d&hRP`a=i>S61}a;(tnY}%hMbS>kC(}h*nfVIPm6<&{t%s} zr$s)t@jqG?y3HQwe8Fa3mbSit!5TT+=^S$TJ5FuRo7 zxW}V#L$s1*SeUQC8^Agg-K)&hE4s`s~yb=MT=&r-R3Dy*qQ>R3+z08bcSB zU+G_vWU(ees-=HEI79A$;k&T%#VNf3>vSjW#X zts=%b-))+Iw0#@mA62Qj$8|N@tffK94E6U6H?JjQ6MSYH!@^bM}^Je>fb*tG27z zaMAtOO%j}LB?$j@t|vkVx-B{pMQnS!y^a12J-CW&4F+qKPjZRJ8GryPhP7)dY z=&qf&0`KKNTI`p%{@2;D8SN7emUc#|R3(z8-r`P=>CgPaesgnYKYOD1#COND=lN#T z&1UY>sZqV0kz>2ZyaiHa&-Lwt2Yz~)w?q&n=LXgFKJoo-5Ba$C#_LVG_IlgK?bvW^ z(M!q6g*oRJs{CB@#&5;Sq0?<<#$1}wSQ(;nDZMxQW}0eeuF}mCZerD(+)20Q_k3h^ z>N6cFvv~3IzBsY^VA%45N0x6GyL7GP&(=9zZKempn`{(+U2^Yo*V#AfQ=?bEbqBnU z&FZ`o@$A*^*QpQeE9bAT+n=1#xMyw2q2eK}Hl8_auHMm8%BnRez8jjMzbZ1TqbjND z*gJ!$6l0nE6fYOI`}Y!-E-&zUwOq-$X=ll$_tpJ z;a@$nXzkRlkeeZ==4;}SL0LWAelAnneAEz#4n`&AqYM24cj!h0OevaS%8k4diN}HUKXM*~W={Q?;h$Nw^4Yk>4_(3x-Oo-w zHafNJMNV&27oS!y`^s^d&Wb+jSFDQ{$`y^4Z84g*H}C7-SGe}r{&9MT^YFHrX}A2= zReDa{=Sm+KXW872?Wgy?;e`5vU{f#s`;RW%Ig$3FFyebe_3!M)&*?|^W!U3D)h~); zj$WTTw5lQG$;_08v6=;)oy+~__zam=`(Ak%YiQSZQwfIk8La=&w=7GIPIlbX;+=%VwrG!=i8)|^m-#VWBF!KF33j@x#AS$uew z&8aNyP2Wc=7}?G|ZQhi3e@FJysAp-$How-qsg0{yv-!ul8;d@7jT*b)hpXxW-=zb6 z8`iXx8b_FZ7WdWnzccRinvPOCC*OeG&F^ay#{9F@tN-=W`(MZnvNApTn@m#p?;Q$` z(zL0Zj>C(zbv~{ZEi6_{*7n|g)#e_zf&KHpQ87PKZA3?u{IRE2yy ztU!|Y#+vx-o#*&e&(83RL6YOW*%NisO{uN!#9^x*+gcTDj!NLJO=!-_!%;g2Zf4C+SjoQo7&2D*=g)CJt(JML(EX_~VoS`7*K+gE zji1d4TjS$=ckkUjcgP1FtA+Xtg3^ne?As^1qz*_~ccx;~g;@%LD+m2`YLxpb>T=1# zIAC=*aytYi@c$bsUY1T4UNXCZ@fL%|N}~k>ZoO28|HV0o-}w1#2{D&Tpud4R$O(i` zVGk|vouHI5_&Wc!xn>aaeE-({4@iTrGdl38x zH((p_s?-F$62ib?;|;O_n)W-P7ykeyi522j>WTDWa2XBohd{^JTz?b|&8Bx|oUE$TZOu9gy8b%t#S)jGM>g z^82|V*jhSBD3+bfC>MEcA0}8jOt6#v3ZCvS+5ISA*n;N(-)kp7TR0x4C)VJ0&y`X)CUd>etfOAa$1z(4URF%-2J6+A-jKDZ0fmb~Wz_j-8s)WVuDWtC-BhkRfu`z^Q%2?+2$$EnEU#40iMaOlQp$ z$5LRpo^HEP8jyge0EsGEm;yY& zCgC8prls6z_8mBsX)zw)_+St0{|S5y`-anJcCwZHQ*heYh{K34HyeB$Err4OHR}q_ zs@C`t(O`7x3+6nhAa{#PC28P~WzB_x^F$x^D>$akrJ8ci*im#c zcz&fxvqc|VM*LY|_X6Y9nY9u*+z(vJQh_;toJmCch%Gp8jF!Z(L&#C&jKAgg+^nr*rkVLXUZN1N6Ks_n%T+JAagVZ?T}rB z4x)j~8PY_8!7HFk@`IHk@F`-3iIb6s>^-2n{*st5kxU}fiDn`zfBwa!FC~*Sz zp%XI^sKF8ZPkB#aGCLQI1J)x8J`wqdfL*-|DdaB6)}lX*l7s>q_5oW)U4@t6qp}}p zmF{dGb_nB1dJzNcDqIj(vu6bXNZ=9@%Jh^R=JkMbZYwpCs<0XI6XgfuD*}OCIZr&u zRRF{FF2UOJH1%V(QUKlnEp`Rd9sa2(ED=a}|F=(`8?P*9HQw zfd(>O)`hK*TqiMtEd3#gMPnpQ=mA}WwI%m}J3kV)as$Y0whs!GJx#$y6OTmds7ta1 zi1FXS-{d-~m0cs9AkGFCF-z_--%Q--Z~iv>o=)ZiB=b3*Zei2NQCf~?(g1RW+HsoX zHBW)A*T`$~lffzJ3a1OMFi$yCoXC^`adNI~2Z?7hm{HV~5!iZ);k0ywJ#rUy0S}-w z<`ut|pNpTvV|el&!a`u`84HVv8FJ&($qQx@m&2|h`aC#*{r`c>Hc^IUWdA2Fo627< z+y98!{{Bh$>vygVP&QT~VIcPZ&sSLnVW9PaJvlFkO3EtmpZ@pyD%g1Zg|X>?y*T^N z_rfFm^TEi%Uh)^l1}L^3%Dq%|{u^Qc3u4Q>a_36@O?B@z*?u-({m*2cFZ@ukx2dA< z;L)S}w?ck3P-RrcppnDdOPf+P+{?=o^5R0SF%KK=n+{W*9jme8nT~jH?|I9}ow`>` zb~rj@TzR>D$WIS5lLcB@Q}%dnT_1R<|7XoKs}*|M_UGok+0jcs?vs7hud|*_XOG-I zIb?W|zhu$*%1A|>%7Xku9ol43zktX^E-?%HU);93$*=hPoGk->)|K_!HqvBw()02W z&p&L>X`8ltRbJtzqP#292kKS$B?VZ`bYF99LEV<2Mv2WTvT!*I!lT3lq{Yeyr^%9?w%?iBL|0(&VOY3uB|x~S$`#dhLfVJ>xuY7Wy*6L z9_(?IkK4V_FWR=Zq*^c4?Dx<<|POBTC|r}giqP>@wSz*>)1mYgWq;ssoC_- zEq3gzyv7&zdN!9J^Y_VVRvEt2w2UluM9VDenlay!{)Ga8fNcvViqn~nFG#rMihy;Ql=c~6OdpQQ`>lo%VnD{8Rlt*)UrW=hxi zxaU!}hhuB<*IgK08Zk%RQChFRXHmQ#ZgiVRIIp6L9vU8``#4}FJ5v-CBlg4~?Q z!2_e$Z(A4|Fx9iSs+l(TXwoo)-*)p~IqbO{X0+nNj{B`iP{>@jQ&K0eYnnf(doDR+ zEKe`;{zr3$SsEB@Hr(N1`l9aM^b7OOX-&Uq@ysAgYcE%DaqO)#X{XvNrd%5O%*-CL`ayCv_7 z_G~!6?7_*YQ@oPhI<21L=TpvnnsfZ3;mN{Z%O0Cdt{S%0B5C!K{%?X@0vm2bz4_G7 z4Vjp&pYT90^_5ok%@HFmc~^a&u)u5BvHNeATxyk9-{r;YtSc;wYG{f{99ndCx4-(3 zob}TTOm1%Bb+7-jQ^bE{oTSBG-h-O2WECb~o?fUr`uJ-n=b7?`mo%&sRvl2wuhHM` z5%}|ghwI~rQUmRRGlG@Ad60CM6E$}-$+`LM*_sQVZ#|1T(s#T6S+C!>O=dV1o!G`r`nR|;X-I$YQM2LbM1Y!tv2_ORay5qR!%2p`HPc3&MNf!psXL4<2<3SlHKnQ zXC*)Go*L1&SJmjF3l_S>g~e`|<8rU%=fL<=fw;}SVz<+{abfLa4^J9Bb9%7XfEE|I z1l^9Lg*LxByc%71b^ej@ZT+?JLP)c-XLP;$BkMS=!4^|zD~{TGv$==g{w?+Ewk^Lh zA@*x-{;W9Pi9X?x23LBF*y74 z#jOWCXYRvHqvi( z_1#HTp+CaUIIk>!Zx*oh#O+eHXI67?{kvQ1wxI)tYE9}jD^wl&cA7Os_Hp|@tUICY zPH4Lm+U|t5JE84PXuA{I?u7RL^9k*BnI59d|AT~<|C^Hj@3|_J3dn!6(0^xvGP5V@ z+WDp4Jbq4Nc;>VhRv9;!UW^~`@$Q{@9lXY`NlbS1KP@q}e}{eklNbN}jdGCNviyH~ z)-dYhw(zw^V)o%zox8^l{B&pdHJ7-ALkC1t|9J+*h8g39o}H~5+%~5@8|*dau)>bo z*k9K?|9ND{o1s6BAS3^8-u$1L9NJT{$6pS5{{jCz$3Fu(&BtH0x$T+uq4!(EM}za^ zThCsP+gsV1H|FNX>}zo@nK9+);enevqw8eGXDL3Myg>WV+KnY^#~y#O>VrzX@1^}AU%#fkH=8OG7C+-eTIU-jvFZ*KOqdp~Gwass8n(PkN?tkL6=h>6X zntd-ijeUD`z=0F7zkH@%Kh+qgjaQ|W9yZjOF zS}(b{wWY?N@p%1uVeZsZEfeHa>c7b9t56MvvXP-9=FZyZx;_1m%*5?YH=oY1+H@~3 z^ipw&&n%7H%n4)Tj|Bg`+E4dGVtj(>*QgbZd%L!&IW)(gofvd}>$Hn&C)MO0QODy0 ztS)+aS{8r-<&L{^qBd!FXz$bTt50?>ntNrYpLASYR&>t#2Wlk?4IG)hJ~q8x@6t`t zj(Pt^=c{J=vdKLFN2-TZ`2$lv1Usm1X7UqpecDDAt7Ci?_K^ zVGzEi3@#y_@8v+oDZ*q^S`JS~6Pg~gBN473VLa(Mpc(9AQN3TgJ?k}BLp!KQV z-`T*b{id|tIci<)dlTOsUCFH_`A5cR*gCKEEDP9Xb3o_*w#S-QX-x-oR~A>!E_=Fp zQQn^VSgo7Ug{Ae*8Ps__wvj}o9Nf878JfLO#d|advfxiCp(u{Wx}{j zpPZwnL#O>8?0t1qR^8X_!#TV6Ikc!)2qv~zD2OOvU>71_VWA+33K%FhNT{UU0ivjg zomhyiUVPKZFc9nlaObq@PC?qE~Jly3S zbotitn)Q6U#kZ-v&%JUf@AZS6qH|9tp2~bN@#I9Xa7Md zO{$!k8MM0ckmFhY@64(ljX#mrYI2-sLba4mJ1$k*QK4shyPGcFeMYIi<@#lLH*^fn zYxl9z#?YW2e&6%U>@3^UX;AQ!Ep9Qk2fW9e)1!CaSTjP1*1i*eF70O4^ybw1&uUky zeqdeheRaUGNy`SF9DZ;`shNS^L#tLf;cFPVdG)yFrpp3eE_8Dnb2&Nft6#eH+tl2B zO{x{`UhWbcR4VIp*IUo3&s_9FZZER0*BDID?Gx-Xg6>WjwdPyn(w8@7cBwpZ`nN8b zuTQ*PYx*=hrfLSe8~Y*6t@p9gF&8S`iViDo`?_v~+oBhZdw%vya;)9wgGKKumTt=I z``#D5Evhv1@Hx=YsrHM{sePM`TJUGR|1bSr*MG)5m&#iXM4i6WrfykvN3Wymv|+A= zmSN31^iXczWsUn5jfxBmdD^$8Ron|Dy5{D$eQnZuPhX*qidb4R?c2KByzi#%l`ZW% zoy^}B3@@kw=&1bFdOxq4zJgotziYe$3*pb3{|<(x<=Q3_B`vF9z#x|jWanV-s-}s~ z?UyJSk08jH7kuRja(0Q0G9ub+!@m^4_NM*9@%`zpLZ+$r)&O?4gBXXU|0OD zXWn|ziVIJMezlga#ksg%EUS`Y9+%q3dhD4EpOdDA>=Ct6Tn`MrFroj|l$gjLj~6tF z9f(dp{GQT#QLB&xCu?<$Y0_goyw7!$UvdO*sb!Hkxm;R^L9&ThsGTwnmrcp+br%8LO|w+HqW&H>NMzHNl z0XqKoiv#}_@Z-vVCYJo`6o8+?aCHg@H}tAt+K9#P-~2DII+yU{ihrh*{5xhD3~-%Wn$G(<+IeQI|Jl_Ei@Ou+AwxI(JRCTBSYpw%6g&5V zKKXIIZ*8ouEegy!*Dzy~YsU_CcU?JEGva;c!p^JfJx|@}_w)Jrz}ik@kNW;HjL96{ z?T0uyvi8lj=DxL-KFhSR&sc4ki6cuLX>g>0sZzO(S($s~>7n4J&&P+|>Ku~)H1x%$ zjr-!>-7}5v7VDWFu+=^dGf%TJy?YvYk7-jT(u+-RcFcd~n35f4`9J>o^(S5Zf7oHa z+b{oh`>@~H<)6U#SFXCYU5v?8cxGwSf46A<+NzjB59Y6<4>HlEJM{H!UH$}{-4^#dOc?--j(?b1$c_TxU4eWfe{{8d>JE zG%|`Zi+cQz{R}Vok0#IW_y1?YYB00?^OAouq36rf3%?cz`ZhSz)MdXnA2Q|Q z;B~W2eKvg5W9vG#v0dZtV7?=5Yvqtycu|!H*Iyr6{@*W=!RQ}f_%|`Ba!wbr=555X z&L;m{;eQ-G@JTGq{`38B^sj|7wP{wd&l~$AHvQp=rOf_wq%it@KQp60XU59?ZRC1 zAF)I+2!^G1m$}Mz%}wq@7)E6WnEcW|5HFx_^dmYv=D-;AdgM5J4P(lu@a;H<*MTuh zXUTCMptx)9;t;x{U6;LiIPPK8hA+cg6vF(;6Qcq;iR@yV$vJAlB5^bJLohOfJrlFk zDRP;JQST_Y*(REa!^jn~187D2xC+BP{Y52hjNu|Jg@+h&U|?1x zx@>GgUx)%ahOB34s3qa#4bkyj;zbrxC-n}UMzYmDct1Idj>%_yC4C_4ipgq>bi)_9 zrD~6c0deC#4B5@Z(J%&Y5&llhjJ$BB8UbSilj$v`9qmfXp+K<~Q{>7w(3(6@iA3Ra z5vhfT6EEBYSH|5*58P8ZN^0XEquK17nhbk#yHZ{C6UUWqe7W%mXl7qiM#0#;JY)}> zbsKg-0(p}#^_HQk;RlTV^_RoY7nCW^pefYVxC(j=<|@BylBIXI7WH-KnALDN70NRAqR(dcCWJ_9T$7vNf!aJ(ZV0ige^(&AIzT&$0 zr#1|Iqe1#x^j&){73zhj@*F-3x0HVTFpLp=qkK?TGYgV|pK6s@8!`!Hsbx@S7_9C` zgY|1ToDODrq%Xd$)gs1tEQ~V_psn`kp9XDoX_NJiTpfXKHqeu|LqQ4(%+mf?BLO3)y-oGN2}y# z@QSyuxPDIG>OSGpx?W}@GI+Fyy?@|wJ#@oyVW{!+@qqU z>FoH$jdth6^t*C@;njBI^OIYAN(|74Wd%8vc8!`-P_$^S@^*74+hdLt2R(j~8spY; zvvqpwSFH=aMA@Y^df&F%$B>)Z$?pc2z22hHr;Kqcc5J_XZQbYC=J$%VBVVext7ezmoX(|4&x=KgT}|qZa?$pvM1mZt7eI&rDyt{d&z17x;y8 zkj?!)>4c!i6`%r@cKnkdLE3|rygB!L>+gHMeyCl`>`L%E)&4|C1*m`j{PTxE^cw^P zW~X^6E4wPalmC^885JJzNgMlY`FRjphjF8?coGdjH_-fvXg zrB`)Uth;5VoDb}ErBXx7F&nMET=g7xaqR<}7oL8}_94fb?Fnk$HqfHf!VhJJ%~=o? zvA~4}!&_B{GXpDs|2pu-h+t|_%D_y`EbW?xChjcw$8rE(71JfN`^T@9ng_J^uef?} z+?}ouw#dcr8Z2vGIy2^&^=h}g*|*(k`F#u88TC54dSd?PbuOb)s&9RMFxU7xyc>WD zf6tv^1&z#X{z~xwHj_ne_t#k)4wIYZL{~aGOlpHLgUom&xKOupO^EmzyJQROxKU7 zPb{|hbog594`lJqS-kd4+}HAep0 zG4epU&g!bG&`I4A#<-{RZsaI-*IKjwc#gae6!3hyO8Voka;33_cq|qf3zDI2)P|Fn zdUIstcN_tsuF9lMlogaFpN44&lAmYWf<0ag&g3$ zbu(eYk@V%)c!4%Z8zr90IywS?Ww!oN9FTi7PuWFw6xXGfwn*F)AzDp(Twc>#5*P%p zSLgTn9Q~PEL0hCX!O1vAbX6B<_vH+1tyho_#9$bWewq!`*J+uM&$}u<@aV0KhQ~3= zBzcs&iV1YD8ZUa1hw5uav8{SiQe``k@)y#2Xq4!Q;!(Oh%q&p|I|k$8$4d>U({tn& zkP|!;Z)A6pB+}$Bx`zV|o_v=c9Y(yz$$_X6GXXKe zWITsoR9CX{GKU_fwPiev2fw8S(t12l%NJdEgv=6BsPevMF4~H%+6l2&y6UsVDw(1A z$n~-q)=1OFiq_(q=FMtLXYCC>BtL5_@LqaQ>_s)@bgc`G=I3;QYilhvYn-Gv)6D4u zenrOeCi+C(5~`IO6dsMsQzv+IptYEpn!qp9Vs$Y+iU+9Y#3s4|Z4_ooE7VAvg$5!A z*@Oh5AYPVMM}=a#aHhe+5vcT2WlM3LR0P>XFfb(V;yoGj(n)d{SMoS=@ToBj-guO%DeN6b&F%NEk_62Ye(snz6{c$gd{ z0z@BiOPd3E`z<|2OOs!;LZIaymkp&ZzepPqueq=_(nIs5MeKug#;SZR^U)zWMQ$eR z`F`yox-E0$Bb>$D#RB4?*U{>+T%g$=#^exn7V%^`DdcZ~tUg;dRs7j-`GPDX zBSdd}mu1O!d=jfCGT46ZCEbNNUnygtbIIY>qp0Gn&id}L82n(cE4Qd`+ z8O@qYBj`ZS7ro_M93h?MZsoLAMch#rktIADJ=dtr1JZAy?n(=^Q`%e>sZZ40c#({f zM|fBCPJPQKs3TcN@tlUzU~*dRB)j2sb*cy_!K%h$)W+%oF@c;${dr$B70r<<$v|s) z20ezS)5m-y4&bk~I9^R0*8Fgx%+(u`3~^hopc&j$R)&G}1LYvDh&bj=jYTG{NIir` zH>8A9@Aqv7LG8o=u5 zq%C1$GHOI8i6>+P3E|TqVr&!B8DXpVWA>Ui;VZ=<-d7lDp;v)8VJ7d2TB5J0FGlks9`-wu z&xWqY$o4E+h|(_=KZzBqO!2kUdf4C zCB3OImJ9V-B8OQjmw0&+pqvtI=v!3C!cln@v(spXk(!>!lL#ZVbgfZ$x1+R-I%RKRx z+lnjFk2TQ7!>)*d2qgFfxq?5`-1Jnq6Z4GiWr3(f%-9XQRXM?@qC{1&(&(fTMRuyb zYJGa0L;#|<7jHnOd<5-;da|eVE1pc73TJH0UTJ%IC!VMe!`-0)7f8H8{8x<-6PR}rDt*dloeL$5GZ4OSUjgl;KM$pMg^O{GN;L#C4);*YAciS#<^!uLpx7IG(Hj)${Uv5rKM z%Gxes$1JpbypZ|IL~h5f@NJ|q3#U)WRa!_DGM+nPjXdC4fW7u*Ht_1F*-z4tSg~Q) zh9vNoWm|X!b`92G5pT;~;L}g$QTlnFz!%C_(u<#xR{S}8$D0aI7?vCc zQpJZPPON7|fLTsq8&Qsk6un3(URJh3HquHoK-)DVZjU#yaS*|uYR=qMSjZ3Jw78;u z}I3UVq(e`qKlN$H^iL8(^KR#tHUzkuJUG|xCdPIt8yYo+*unVNAd!F z7N5=z$vFOjwcy3Vz>Qd;Xvn703Ty_Oi64vg+!EW0NPdMRL;g8jJtUU$6%dhBRtERi zDCvIgA3Sc5KA{2+6IpDc%*>?vQ%MzB5n4cko9_(5Jkq^QED zK+I&k7I>5#qFdBW;sp<(V|l)CBYkBOTSQlDP3cXVC+e~tVzQRQ-DQq;Lp;>Nwy?vPWTrYngHt4m(tuk;c6NG8)vR2Cg2nM!N& zhPDHV=v#Ug)~Fo)N$b*OERt2$B}-A zc-(#C1n4a7oyJ6nN&s#l>OLX;Tt23=Hw2tk`vZ@L}d zQlnTfyG^>$bmod;s3l}&6LD#2f@_m0dLqaR1GUfm35$~z@D7^5W|GTfJ_{!*D@UG@ z(yR(`!{2EmG@CfVsT_ru(Mqa6IYzspfwVu}MJADKx{bD@A6Ss+$b0dQnwz*Jf^wc>~)P(9@?4Wo6@Sz3zBRj1Q4j3E`eTm5hfZY{FW8d6#d<3Y@zUqsL8 zQW=6XX>C57%!VxE72$L|3!qhDXE>3HU zX%MRl_edR9SI*`yKw`gIII~m}U&z6u^~+)=Gv@y68i^(eL|31RTp20C(N=O8eP(G8 z36oF?*+O?K?U*HgtX#&s$qqv(>!d!T{#q8_fHgLp_7!b(FVU3F=9`#>+^4-`=_Y%D zgp$iUir4g!@ePw-A`3F+Vse)@l~HJ)GGCcSOP~&!Sjgo&%@GMQVbNAuslrjK$Ac8b^jHBpppu&f{SGo|tQO*dwfpbEGx> zD%SCI>L?<}H|?HrFD*iEZyY1Sj7J%Bwn86ZQcKQd&qZHsEzg)lYwcu1ljWkP(m)wb z1J!rR1`vI3P(wh7zFqagZ&?`WMMm<4D!j7j3OoG)wv> zF}VbJ#!Hed`_U(OmQM7+{0&HL%b?f#1uaix@l?K-ogjlD5_P~ibR}&D1_VFpenTi} zq6U+NVw8BO>}G*@7O-Nx)tlt3%%#Iv9odD|rS`&vRS-R-2W>7#>OuUj$sv4w4rT zCDXKrd@ud1jmP$6Aumm!M&Xz7XtJE;<4$A@twIt>Ph5=C@e{NS?;%d=Xk0{K=aCfh z6kUgvh{7SX0u7*BX&LgAxzS7Hm~f$Ih&9B`OQf1{qU_A#wAcD1p|E(;8rgAUdK&LW z$8jR^gGwZy*Wov{QPK-FVc*FVQc(|Jp9~J_FXRB-Rh{kTK2V7yaiZPlGx2CPUj0ha z*$pyDe$>O*W*#JNk)BuXSdH(v0X*Ko?`RELg%R3?)PqdR5Aeb#^a3EDZviQB z(n92WFobAFAA@bcTdJT-kYRi8wpPPz0s&*I&26+VkpF~qBz)u{#pxu!U%GkH8o zg3P>7l;TBDm0wfq;5Dc$t;46IaV($z#14SEj;4ObDaJPRB@yfmTA@uhrW7&7ZFp9?=&@J@_FCx1sM0DO2H)hSiK47H2Of=-iWda&Y0#E_20=63ryRbxc z3&ex{I86N|$D+Yt@KVel(qTGB?eH70mS_yd2&?fgxL&LAK$J{|5lcK9yWr(`u6hS& z;LpereJAVHJYqz=&}Q5hA0?LLD%eycQCsXwZCMR`PIRH?v5)8~bn;PqP6uIYzKa|| zEp=1vow!1-l8x$iY#`BS8(GDhVTHDqo#+asA=XefG8XITP-QI6f&0i@Gy^M$v2r5V z$Rq&j+EUu<8uMfur4L=nX0f40Vf+c7r#g$*+DDd1Tks&YzgVE37puTpp+GGreKd_E zb30?H<)Hn_Dbxs`Qm4ZjEm5bV-TZ;t4sVpLSqHLHPC(MgNwQ7 z6|Mh(vT}xWQdQf5lQFb`_hI_GYRG>6g z8Y12;5y&cGH&K&2lP0nX)lekckMflO8K+g^bLniFicXLMZVb3fIZb8bpehJOGl0L5 z#yr%^fL^&G4_b|uM|pe;X(ybGgLx!A=cI6byFQ_EmI@pwL*KQ@Sy zqB+^CWkcO{N9(D%!X92htd#8}32ZH5kvj=hi`56jPniVy)EN9yHD&H#+Cq2=DlnL< zK1vP=kgFhXDZ?XaA0X;Zpw?P@{Sw*2+iEs+wQ;oZVOCuyCMl3}7aI2igOU*W2%SEZ*1&g{)CZT*CV@3c6@D3T()aofIg!rfO~eTDLfjE2VK4lk z<&+}QpQTdWs6Me*W}-Z1O7GziEsgHNW%+lgfqZ2$UkrHPO5~u#;)_ZPsMoEPea0V6 zx&ro+XHrq5Y9jnT5Y-Wl%}#>N$?r+Sq2fO_>fzo|GH45)(9X5i=CGpf&2 zB^tT`o#Ffoy z>M^x1uaDByQ1S(LQ8$w<5KEmPVzx$0kP9ZrLb;9`sc)5BY>9Hgt|(d^fm-57^%t!{ zx&fc8A)FMxG@9AqQnCV_g|>(tq6;zC`_XM`fyigR>UrD(xN9kVm1uy6C||IXGD|&0 zZX10wT0*KQla0ROmaxW+cp?5^_<%O5<>@Z117u_ksiRSQ)nqZ-Q@#$|a2 zxs0z>rkP0NcWf}PD33vHUs>)(t>|L;lrB@B@ba)5rpun{JT^$*FS{Gf7FX2IMgyob z&Zin!C$$jIl?&l=8#Ls6Y7uU&}aR~UgF(g24|+e=I?nk zG*I+}s>4gV(G$ugSiM}Mr?QG{OUf%}@HW)~g-{E$*k}oLP+SZZ)V-=b8Kr%rMquWY zLlb!~eJ!ts@3C=)2W)_hpn_F$vxRP_u7;B-`~oQHxC63Tr@WW=@i#;(~z)Q2S zN)==xF^z?uley6|zCmWIpTLSwDw9bSSw=Yql)wR`occ=Ztjsl><$IKPh#1mv$?%YO zR~kYmdL=rlw-@eo4Ly#g@o%U-vXmpBr`AD?qdx!vej>^cU-3a3L9@hA&4YT&ZDI_hoX8Z_TNVHmv17_|9Fix^3l|(bB z%#nDg)uj(*8m~x)h^?f6nuuN~2~a0XQkv$;mP`l3!UbYCe<9mwdD2|=l=;vNT?p05 zWqF$n0D(v$TEd@7SK=VH%G<2Jb{R|ucW9gCXCZN0z-dgO16F{2)qK$kT~x2}iKHW} z&uZR+5a^Jfq;}Bz`$gA_M`9A4A}nbfts*Kwm*f;P!=161a^OYZ;O(@o(EID7uao5gO}7I4Tvs21 zAz>5Mk$1!c)%UEB&cfySXfch1^Lbh<-Oew|2(p#OL66&ok0TptS^fd#lSrPAH&F*s zjs~+B=$JV20sMnDUrd9(&knIgWN;7BQN)s)V8EA&mh&7j47k2WL^{1K=S!&8wF%JQ zwgh}7jz+2#SsZ?>Mgv3FNA1pZ(guZcV=#(a$(c0AIqb0(L{9>HdLC^DeD7yq2NsM^ zLGOD3>P+78DS#`?<~7-D77w{u<{fc#`#$tlQLb(BTgu#>0*xdZHwR`fmeBQNsukbkJWfX|RyMKB)&c)vAwB&&G_ zcSk#UH=YZ|cogo8#^Mp*#r?EuytjOB)&#MSZ_6sw15nC2`$AuSP$mFj)(*v!QN_ZAznU( zwK&gw8RE;?dz>vg@kmsa*XB+*Ni<;3nUrB*Yq?mP%C~5V`Y!%lOxK?A;b@L>naoA@ zYCYPKJV8Tf2yX;P8kZIE1ae=d(6Tg)A0Qh5`N#pBbvK#}6^je101WmWC`% z2}RI+H5Y9bd%$EdKx+(HKjAuHDwW78z!Nku>YEBx(goZW>X@-46c|oFX*AvdJ-Ng9 zC*MatAagk1kHP1&03@#^TFx>^7j-|IMUu!l*^cJ2A~^`I&06`61ObEUB&h{8V;ee- zHqzQrsqPg=q2d~;?n6Gj49Y<#wNf|%R}{YZDOy3_;HoGDYL$W5MNPyGfOa>=`_OSf zgmbarJ`nku%BH*&G0}VgyIV>&QwMb^8b^DeCF(+U36ufX*#LO`y`nB@#b3+qq`tNf zaLYkj8GSLGNqa~KG8A1CH()fNBj_OZ(@;3^nu@L%qaNZZDps?&E7<-?;GVTbv(b3; z5N%hjpl{p_-G-Pqg-)V6u(WdM74%xF&?;WUV2_S*r7?FB%05mD^wdYtOrY zx#0kI71>Kq?FqRDR=a~qFTP&h0(C}vs09?m7iOYNRj|AR27X!UOI3op<(eA9Q%FrU zh9!Yb?MGsQZmU1laC8^?*>kZu*e&*jx;21n)DLZdv#S;g<7e4LScMO)k$Omdh99Ym zjLh&o#Se{yD(oqV5q0rrFg`qmiNv}&O&71_D_oZk(9+<#*Or&aIAj65q1)F2z3I8 z5i2W+hRr-lSz?sJVvv&#@q>NFdr?;r4z zw&Jx2m0jflS+AZ0Fd14E^0XwU!fzL1jG$NA$+YJ}p*-|*QIUWyu zusr6&E{It&SL_j=*)cI$Jj3mTlUU9s%lE+6>8u}@`$=haA-RulsJEC9{-g}c5xZ%7 zUYGPBi{W!VgI->taOHt~HJqc?EZ2`^C#-*V1yc3u#6M@U)1a)@|8Oz=14zz-Og)V(L8Ag8q ztF$a%&+h8w`C+K>CgbuV65_yZwhP|@6U+qc1BRI~fFfG*LKX^<1Wg4i|4o9qFK(LYIbSipxO>0W|Z!v7o7t3TK)Q{Al|>vSOHz0piEMIMo@p7WaIf(qshP83NZ_D0H4USOgik(nrBQ|X8_LAk zPEo4uo8;v>q{aEq%Xi->o3{A4ym@PpOr;%mmF z-n7bu(k`x}7X-5!Rvw*GU0RYWXIuL!^z5VrH2K#Sb6CFMB-7b4AdGc+F z)m#fzL?^jUpFe2pSUcHjP}iJxb63=@vN^yd^~I3!Yx`X2+oNm6=);qP?mwQLx8q&Z zp?dy(hFa!tJ27U2t$DvMjTa?3mRno%`jVhl3#u$1c%j8W-w!Q|4t#HWJ8z#->Gs)m zUHaW?ceV7K#d*EO^5)9kx4#Tmx_`LSY+@bD&E8LkjXKfo;}bmaX~nd1(Ln0TWv!z3%pRe@l{l5LW zt4;?>KkM^!$A?ay5gVO5XEf__^>*v^)tvsF>zGcT=&l>B@gMBuC`swk@5cqw^r~{9S?hofTOBKCo z?`fau9j~5qP|j8S^2-psbBc|f`A3gF-yY_73Qeu$FuJ_Y;qUJEzeT#Fe@n4SF0hOm zIP1QBzEVSb78Se6B{H>_YxJ>Fkq2w_oE7#of6x-^ccrF!huOYp;B<3YR_wFc>hg^y zHbsM?*u0kB+rOo*OHUY;m%cG~TKd4mPI&P_m)6m}E^HfL+IDnCmZ<9aqvwXqgBM#l zZhUlZpu@p|<(3UhdujXVjF#X$YW{=igS%C4>wnxBf7_Xv;a%JK==~Sfoobw2c79dI zevK?Qdi7a%*0amYopUbUsTqIyzztV#3ya8Bo7$RZ9)4_e&T91XsTIxgVokSM9SE5D z>fT6~4x!0mF5aEK)PCtzYr^=)DcR0JkE(Z@eY0#}?=s?t&o4trjUPjjeWstZ_D)MW zdDE+XbHPSBc#`z*pEUxZFEm`tGu7`m#mu=RG!iSDJlmoxE2(x1#~yIn*w!=J$e; z=D|abCeAC}`c%z|sArG!TRV+;v1xajI_5#oR^6?3exAGX{*7Kuhude53q5_Vf7N$$ zs$cW>y`C{XUFnhM_WtSV+0`A3rY4jxY~kC!LrA}FgTl`&pZ1{2%d0Z)VFulGcuMo# zZD+i%?{FsI>Z21+62d=M&wIP*NR;D{FUKzjE;dqR{1Qtdaucd z;xTTCuDi}hBz?dA%OK4^O|~7qsIjQfJZJk0gY%Ig@rP^7Na(XM>g4=Ut)t3(%^o2x z7WY0fH!H~4diAsT6sw`zCVuO+t9bG2)FpnoyOyq~ zvDN3d)h4g?n(1!i6#MAMB{RQ8z6Fh+^nco=WBB%!e!~k|)Y>I^i`uWB#kWrV+O2fsuz=3R z2d*vbTx-^P=nffP9|>6b%kce}ck}Th?0W{CyH#V&>6aNH?V7cIKXpev{~;MIc3pjt zzT$BCuIlmyWMT>2Y9zmHm4wad+f9kU0j^)q3jebzW;!*FI1^dL1NtqL` zbQ$fnao6xRh5qYb{iKb0Z8++lF!Eqh*_%y2e9DjOWU}gRRLb=q^OhN1ebBu|m22@$ z8(7ThJSwYt(*+_WZsM84S!)JenlQ4URGBPs?M;hP-LmJdC^vpc>dCfCocCq5@SHfp zhgfbZYim2u+u}k^%c1qJ489gWMqOArFy`oY>%k+t*v~M@belW+!^l<5Y5ejAnYZ>C z`3Br-p7=7O>!-Coa%0+)QWIb8>?HF?C0Olbb3a5Iow|7aX7#w_-s2-)MrSoeCB6Wcd%7}~wv7qeFnXBZx?yKma|-pNGM%0-iEwV0fgklHB4xkm8#*D2#) ztqqvEy~re}ef2DkO;5FSE9?LrMdZ^pzZB9$d90}Reuv@~T!I^`q z7&g6gp1qKcjV`V=!Kz!*vZVbLL+aM)5n0h~_2uvWcQX8DjVsQ4+_Uzy6U*1WsvTkM zv3f$oN%d~()1yZ^^{wyPykUINiNQxsS_Y}3rgytvce!hV>n;C}JwCl;i^QNQcXD2= z3p>?xs?+@-->c(`uLPT|*%Vl`C2oPYYu|6Ts@qf>oEp;IxqIl2t=WEqraO!my_WYK z8+WLz-+-j5h25HW$&E0-aJ{IdkELhGVwQE-!?DijtcU9SbrX-QHjlB}Fnav?jDD`| zyA2t)Wq3f~lh@-n?hOqKzEL`_$Kf%~YmWO&IJ4gQa?A3iZid%)dO$oElz+YE;wuPxO%Ad zt0{*+9zNzcwtvyW7G-mH3@cmCZhM)2l}a5+wtm(&mb*RdJ)nGY^E~x(Zo>YlmHM_x zOpfhPFo}e(Ir*UPzHeL3o-^HfwORLrM`J^mbzgq!#I_kmdp92)dhz{%nEn%bSnYYX zulb!$8~4_@)+vemG#WTRuu<{mMiE`!1#3xjUpoW5-UrN!#*w3Y(33T^yk~x|S|mJZ4CzQ19}sO9dQieECZ5y0T$m z&2PqCzYRLY@_)@r|J#fh%3xj^2NmR>kura#|Gb(raISL)myqzF#|zFl);2j<*yGf| zL$kXyFRGva;l{a$nFmHrKkbrq^tnl;F{bthYhA2cwn>MDD>_#9O7(M7yKQY6z*^QU z8a~}=p-G#j_9uetyvv@^F|~Ea)Q=W>25t0B@88JT-stNH<K=1* z$EWfcb%&g&u%OpM--)l%g4=y=lX4S2GK~5DJ>wgOOaF5K+&^bpf(FypU|Gt}s&bV^ z{~Cy6^jKf8|HJk}^FCOw-0!wPPc9R#mi`fKT4v&dL(iLyi#=u%bJw%N#Ld!S`i1ca zQyX16^-_I#a#P14OOZ@kU#eQ~Wr6+A-j+`N3^`^zw^ zM|-zsJFnl>xXFblFNQ}9i(S;-tz+YQ7KtYIS1z3X@XO#3^YwDJbK7-4)GsZEU2QtB ztJ(8un+7tAu8CI8vqp4{nV(kibefE4l(pi)MX%@Sqk7%=y0@_0v=avsd)&BKOPW@{ zJT`-g&v~cgJ zlj}PKHW)X{tNW=@EylKYNIc#trjPFxwDP-p(zttOox2@r=f%e-pSSUH++B2FW7;o+(MiV+qicQ|>Dl(k zjcy~3km4#8`UKwWQj~P2-}niG$1f=eJ$v5gOh9-{_e<~kcvfD&#LhxkpP4c4+kv$% zqjogj)WWQ2hFzZf$dSQjqnGc?X=WAJVt9^k2h$UV*v$J^T0L3&t(5J+8J&*$J}XSJ!NC6-p~>$k7*En(yF&)+P<_@G%E!<}y)39=#%Wk*&D zZLMCI>Qp5>GI#3WkLBN>nWv)`=k!tYHf3fw>}%Qg(XR77QjD79J$>jf;oVQf*8O6Vh&(dFk=?P0Op)92M`km1OuXipom$Fm=F~~L`6_Bi{~P&N$Rdxc)z)m5{q<{VKmYNl)Hv8GgYdaYu0i2;xF%lT#np`9`!k~pMM`0 zYUmwQGdQDv?$CQ>qYI+#6UsTv2(%rxc2((^I!h`Cy&gZNRQU3b=gwa2VOL>E!(D#r zciY*OZrj;5^y~dBF>(3ouWv0ctUFc^PEaR_EpEFUv0nb($Js^p<^7YJ&OvPGU%04 zDZAVCJ-hGT;u^Va!mw@w<^&eHPHIrSWw{R}y9f8Gv%gNSSm(CpUE?fLZ94?D4_cJ6 zq_3H65Lh7RBK=!1Kq^p>|Ir8z!ek02V1EqM%GTP>rJ}tnvuWC_(||vXC}@UVS+hAO zr}mQaKK}1N)LwWmyGQby^YxZ)9y}&~*`6`UQ*I~C+SvP}A-T+HI(@>Pp2rTW-8cJP}oZ)?BxdB5v$=6shEQT=unemuCz?a=T6 zZyT5Hn`@uD|8~&*>)jMXm1W;TGe&18-xw6MfBKJ|4HDlpUVG-_Qk%<>w4kIG+Q04X zpx~dpXP4VIEpG;f+`f}skM(KSb6D%8#k=FKZ~FK4)2# zmx~r=tKuJ=DyZb+Fu!5Q%(#I2%GQB<4-B;VKIL)HxCyRp+j)l{?f4*byv@=0lIU@p z5+CUK@ z%84uotKE5ysTU_FR+$*K`|ag*m*bu~F5OVmki5a)x6h^Q)x$;|@_#tWs(V4}vW>ft z-uc4)d5;74FS%~%=fDSRizeEmJzy;ciF0a;qI&(x7g9j&I9xFIW54zf*rri`&<~+D;ko(tpkL zuY0ddPHO!#Wt^zl}y15GI& z#^=s$mhb|R1?zp-`vt6aKq zFe@SU?%{=B7GC|i=fV5<%_|ap$mkLuEbDJR)zkIzz414_H{`4=f9T`KQNw!-tY9U4<^&CqIoN2e^>(*EOzK{1`%ZQEUO_7@Lx=l0&)n-%Q86td^m z(%Z2$+x?jGIB!+%lsR8_oep^a&Aox&*Ip(30*5&T-kb9LOwEOL-fJta+h#S~KIQG1 z4&4GrEG~SOx4QmsLtnZ`bMN2eUX2C|TbHKhf2~l^nXdHsor9%&tFEt4<~(b8&AYJT zKJ%<)+rEd-O4~QaW1mwkpT40b?k4B1kiiyqGGt5Sts(yYA?>ecH+zeFthTy$vd6Pe zi5=IhJ{jGx+NpX$pBj`JJ9&7Q&zEu9OY0`t3oS{E*O$W$jEn1LZ|*xII%8*8>Ar7Q zd^`|Q{)Q*r-KzEMN>?XZI6qi;ag*iU2E{&anH`uEX5Iv;)&^N)#)Soge$IQC7;!>4 zcj#c9fA~c5%X6bXmY-xe=Qyf|`gGQ_5d8g-{eaMgcKt(sb_y)1EciHj)vP;Uef}mN zIO+s#>*o#jt4Kre-^nR{55~V-CiAmT2fwNDGsIVq>6J4}PWA4#Xud6D+oLxf+j;9HFOUBmV@}sEU+FS*dGD^b96D6};JB`9c9$lV z;_I;Xm73I=nBU&>(44U5tl6uT4|=>r6`Nh!TXAfo4vXTGZ?bg*SG%l=uiwn7RIgR{ zoBLUZIi-d5Ql_X!>bxnuz5cwKjB%G}9&C&Vlb zb((|fC3qU2z8>Ge`uq2W-#th6A6MynnYwesJ3cb?-PNcIm-8Z41ukB`xMz)*_MQW) z_>GBA>E`ps%Xd@d4byg{&pz1MeDs8Bzoi_1$%a6*Hj50^o`}c7MO#rM1!&^Z1KlHM zWg1x~$BAJ=*J`oj;-s7ibfg_YK%fdgDu?i`{3poL?ALp0w(_WI1B5_NXe~Aa==aiP z2Rc>HkjI1-vL##jda_9PfOth)@r9)885+_%GhK`aNu5?AjJ@Wws2E^ z55(kMxD5^9H{^E^8u~14LEL<{TqkF#`AW;sG4c*sA0fD6* zkg@N?--U-dO=x1I5>A!_^|FnU0*a_B@p^VcIVz08R(-D>0m-@p$~YiGO2@O=e02-2 zBYc#%dKw7u6j!=}JVG2%fso1uFJ!mW1Rz#^2Q+k*StE585I-l9G$0-vis$O(K^SbO zGK&4ge&{O8LixP6EQ8yyaQ;$Rp^Ou4K)5KIT}F3!qId*16|F5)Dk)=yADW8q^M@oC zB!n{QYTZTzsaDEZUJF?gFAxT+MQ5_7G*}-ZtbyM91PE5_Ar1IY0<@XDHoL1Gl5sdq zalp@T9C2gGr?UBaFNNzoiug+CGx zxJj?2A7wEtMYW;hKpe0ct0MAbMRq~=(4Vpp5H9FX-^d-r1BAX7iS~4}R?1{0f>;`I zL9JwOl1{GaiJ}r6E4;KM?jjDU9DmWAMRC^NbVhozJd-(yVK|BVY5;yNR&L6AgfY?SYF_#<$+P)i% zlFrmYTLQ$=CLm$W7m1`531EYT7f>yp)geh%3mCmE%UWAqdHTp|i;{ltmw+K>FGY2+>)A@&Ke6c9ZACo%|9e z8ck-J&0+I_hWn5T5>Fs!5{CPMjGRtD{D7r^w234=$wuNq;;AMCFRyw?5d9;!fCMm_ zRKnlLRKqQTltkq!I|cJ&t+EgZ-ag^!c$QI;b|B7W)awKF>n&v_9)zZl8n~>INQ^km zI9fbKYcN;hfEGQbhwS*VBdm9zvwfCJKku2cK)!E~uQTzRJk zsv6EmpV1&7Ps=mzCs(kqDwPD}t&CBlke_;AOvVN5y4iG5LV2k4M?+CZT$eZ)3up;- z7ds61p;4~5eXf_`r2IExZ0Tyh!NEi9IIU2x=qpm=}>J8M&nYo9z^+epxJC99V7Ph`S2`<(0QB#`SWX#I%o!Xmo12nQZ@^BplKpYMu6a8C-jlp z$pQ@|w8S0!icSS#C&@+u5w1NsAY02U`b}#_ZqiZGPg}rFXeIG^>dT@GEMB1Hj7iuj}0exHq4kmW^vaHNn;dHbN*H><^z4$GV#xFt} zjhXZ(HdEiC>1eeY1M+Zn)r#s0)Sgt;Oti8371^U3$cIOx2BX6kzy%(ttv$V1#teJPLW9m#DVMb+gR_JFyGiy#;^9|#O5gUm|`UQI1{ zJ!(sj@|s{-MzU)_(D#r{mu-0`)`gE@waFuTl+^(u^zC#C{;Xz`HRvje0?`;1-=@CE zm#$^OAjoz{ywprUr`$>mVNQGw+s2>C7GMvb%GR*Dhw!r$fq2jj)RjyZ{c-;P1md

V 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

}h)E$)kB;VN;Hd%KQO=?|DY`*33!8 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 literal 0 HcmV?d00001 diff --git a/crates/j2k-test-support/src/fixtures.rs b/crates/j2k-test-support/src/fixtures.rs index b6a798692..abb5b8347 100644 --- a/crates/j2k-test-support/src/fixtures.rs +++ b/crates/j2k-test-support/src/fixtures.rs @@ -22,6 +22,24 @@ pub const JPEG_BASELINE_420_RESTART_32X16: &[u8] = pub const JPEG_BASELINE_420_RESTART_32X16_RGB: &[u8] = include_bytes!("../fixtures/conformance/baseline_420_restart_32x16.rgb"); +/// Synthetic 67x45 4:4:4 baseline JPEG with a 3-MCU restart interval, the +/// sampling and restart layout of Hamamatsu NDPI/VMS pyramids. The content mixes +/// gradients, flat patches (DC-only blocks), noise, and a saturated corner. +/// +/// `corpus/conformance/generate.sh` encodes it with libjpeg-turbo 3.1.4.1 +/// `cjpeg -quality 90 -sample 1x1,1x1,1x1 -baseline -optimize -restart 3B`. The +/// `_HALF`, `_QUARTER`, and `_EIGHTH` references are `djpeg -rgb -scale 1/N` +/// output from the same build (the reduced IDCTs `OpenSlide` uses for scaled +/// levels), with the PPM header stripped. +pub const JPEG_BASELINE_444_RESTART_67X45: &[u8] = + include_bytes!("../fixtures/conformance/baseline_444_restart_67x45.jpg"); +pub const JPEG_BASELINE_444_RESTART_67X45_HALF_RGB: &[u8] = + include_bytes!("../fixtures/conformance/baseline_444_restart_67x45_half.rgb"); +pub const JPEG_BASELINE_444_RESTART_67X45_QUARTER_RGB: &[u8] = + include_bytes!("../fixtures/conformance/baseline_444_restart_67x45_quarter.rgb"); +pub const JPEG_BASELINE_444_RESTART_67X45_EIGHTH_RGB: &[u8] = + include_bytes!("../fixtures/conformance/baseline_444_restart_67x45_eighth.rgb"); + /// `OpenJPEG` 2.5.4 irreversible 8x8 RGB codestream used for adapter parity tests. /// /// The source pixels are the deterministic `patterned_rgb8` formula. `OpenJPEG` diff --git a/crates/j2k-test-support/src/lib.rs b/crates/j2k-test-support/src/lib.rs index 917e4b8c2..9aac71975 100644 --- a/crates/j2k-test-support/src/lib.rs +++ b/crates/j2k-test-support/src/lib.rs @@ -18,6 +18,7 @@ mod manifest; mod metal; mod metal_shader; mod pixels; +mod scaled_matrix; pub use auto_routing::{ append_auto_routing_output, auto_routing_operation_label, auto_routing_route_cell, @@ -45,6 +46,8 @@ pub use fixtures::{ OpenJphBatchFixture, JPEG_BASELINE_420_16X16, JPEG_BASELINE_420_16X16_RGB, JPEG_BASELINE_420_RESTART_32X16, JPEG_BASELINE_420_RESTART_32X16_RGB, JPEG_BASELINE_422_16X8, JPEG_BASELINE_422_16X8_RGB, JPEG_BASELINE_444_8X8, JPEG_BASELINE_444_8X8_RGB, + JPEG_BASELINE_444_RESTART_67X45, JPEG_BASELINE_444_RESTART_67X45_EIGHTH_RGB, + JPEG_BASELINE_444_RESTART_67X45_HALF_RGB, JPEG_BASELINE_444_RESTART_67X45_QUARTER_RGB, JPEG_GRAYSCALE_8X8, JPEG_GRAYSCALE_8X8_GRAY, OPENJPEG_IRREVERSIBLE_RGB8_8X8, }; #[cfg(feature = "j2k-native-fixtures")] @@ -72,6 +75,7 @@ pub use pixels::{ project_scaled_interleaved_u8, rgb16le_to_rgba16le, rgb16ne_to_opaque_rgba16ne, rgb8_to_rgba8, scaled_rect_covering, u16_samples_to_le_bytes, PixelRect, }; +pub use scaled_matrix::{scaled_matrix_cases, ScaledMatrixCase, SCALED_MATRIX_DENOMINATORS}; /// Generates deterministic RGB8 pixels for tests and benches. pub fn patterned_rgb8(width: u32, height: u32) -> Vec { diff --git a/crates/j2k-test-support/src/scaled_matrix.rs b/crates/j2k-test-support/src/scaled_matrix.rs new file mode 100644 index 000000000..5a49d2a54 --- /dev/null +++ b/crates/j2k-test-support/src/scaled_matrix.rs @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! libjpeg-turbo DCT-scaling reference matrix. +//! +//! `corpus/conformance/scaled_matrix.py` encodes each case with libjpeg-turbo +//! 3.1.4.1 `cjpeg` and records `djpeg -dct int -scale 1/N` output for N = 1, +//! 2, 4, 8 (default fancy upsampling, as `OpenSlide` uses it). The cases cover +//! every chroma layout libjpeg-turbo decodes differently at reduced scale, +//! chroma at most two samples wide, restart intervals, progressive scans and +//! 12-bit precision. + +const CASES_TSV: &str = include_str!("../fixtures/scaled_matrix/cases.tsv"); +const DATA: &[u8] = include_bytes!("../fixtures/scaled_matrix/data.bin"); + +/// Scale denominators in reference order. +pub const SCALED_MATRIX_DENOMINATORS: [u32; 4] = [1, 2, 4, 8]; + +/// One encoded image and its libjpeg-turbo references at every scale. +#[derive(Clone, Copy, Debug)] +pub struct ScaledMatrixCase { + /// Unique case name, `{layout}_{w}x{h}_{coding}_{precision}bit`. + pub name: &'static str, + /// `gray`, `444`, `422`, `440`, `420`, `411`, `410` or `1x4` (luma + /// sampling; chroma is 1x1). + pub layout: &'static str, + /// `baseline`, `restart` (one-MCU interval), `progressive` or `extended` + /// (12-bit sequential). + pub coding: &'static str, + /// Sample precision, 8 or 12. + pub precision: u8, + /// Full-size width. + pub width: u32, + /// Full-size height. + pub height: u32, + /// The JPEG codestream. + pub jpeg: &'static [u8], + references: [&'static [u8]; 4], +} + +impl ScaledMatrixCase { + /// Whether the case is single-component grayscale. + pub fn is_gray(&self) -> bool { + self.layout == "gray" + } + + /// Interleaved samples per pixel in the references. + pub fn channels(&self) -> usize { + if self.is_gray() { + 1 + } else { + 3 + } + } + + /// Output dimensions at `1/denominator`, rounded up as libjpeg does. + pub fn scaled_dimensions(&self, denominator: u32) -> (u32, u32) { + ( + self.width.div_ceil(denominator), + self.height.div_ceil(denominator), + ) + } + + /// `djpeg -scale 1/denominator` output without its PNM header: 8-bit + /// samples, or big-endian 16-bit samples for 12-bit cases. + /// + /// # Panics + /// + /// Panics if `denominator` is not 1, 2, 4 or 8. + pub fn reference(&self, denominator: u32) -> &'static [u8] { + let index = SCALED_MATRIX_DENOMINATORS + .iter() + .position(|&d| d == denominator) + .expect("scaled matrix references cover 1/1, 1/2, 1/4 and 1/8"); + self.references[index] + } + + /// 12-bit references as sample values. + /// + /// # Panics + /// + /// Panics if `denominator` is unsupported or the case is 8-bit. + pub fn reference_u16(&self, denominator: u32) -> Vec { + assert!(self.precision > 8, "{} is an 8-bit case", self.name); + self.reference(denominator) + .chunks_exact(2) + .map(|pair| u16::from_be_bytes([pair[0], pair[1]])) + .collect() + } +} + +fn slice(field: &str) -> &'static [u8] { + let (offset, len) = field + .split_once(':') + .expect("scaled matrix slices are offset:length"); + let offset: usize = offset.parse().expect("scaled matrix offset"); + let len: usize = len.parse().expect("scaled matrix length"); + &DATA[offset..offset + len] +} + +/// Every case in the committed matrix, in generation order. +/// +/// # Panics +/// +/// Panics if the committed manifest is malformed. +pub fn scaled_matrix_cases() -> Vec { + CASES_TSV + .lines() + .filter(|line| !line.is_empty() && !line.starts_with('#')) + .map(|line| { + let fields: Vec<&'static str> = line.split('\t').collect(); + assert_eq!(fields.len(), 11, "scaled matrix row: {line}"); + ScaledMatrixCase { + name: fields[0], + layout: fields[1], + coding: fields[2], + precision: fields[3].parse().expect("precision"), + width: fields[4].parse().expect("width"), + height: fields[5].parse().expect("height"), + jpeg: slice(fields[6]), + references: [ + slice(fields[7]), + slice(fields[8]), + slice(fields[9]), + slice(fields[10]), + ], + } + }) + .collect() +} + +#[cfg(test)] +mod tests { + use super::{scaled_matrix_cases, SCALED_MATRIX_DENOMINATORS}; + + #[test] + fn every_reference_has_the_scaled_geometry() { + let cases = scaled_matrix_cases(); + assert_eq!(cases.len(), 208); + for case in cases { + assert_eq!(&case.jpeg[..2], &[0xFF, 0xD8], "{}", case.name); + let bytes_per_sample = if case.precision > 8 { 2 } else { 1 }; + for denominator in SCALED_MATRIX_DENOMINATORS { + let (w, h) = case.scaled_dimensions(denominator); + assert_eq!( + case.reference(denominator).len(), + w as usize * h as usize * case.channels() * bytes_per_sample, + "{} 1/{denominator}", + case.name + ); + } + } + } +}