Bug 1910796 - Integrate libz-rs-sys as a replacement for zlib. r=supply-chain-reviewers,firefox-build-system-reviewers,nika,sergesanspaille

Nightly-only for now.

Differential Revision: https://phabricator.services.mozilla.com/D218165
This commit is contained in:
Mike Hommey 2024-08-13 15:03:42 +00:00
parent 15306bdb2e
commit ce3936e0fb
73 changed files with 26852 additions and 3 deletions

View File

@ -50,6 +50,11 @@ git = "https://github.com/jfkthame/mapped_hyph.git"
rev = "eff105f6ad7ec9b79816cfc1985a28e5340ad14b"
replace-with = "vendored-sources"
[source."git+https://github.com/memorysafety/zlib-rs?rev=692b0fd5a367cf4714b0b24e9e498e2a064d673c"]
git = "https://github.com/memorysafety/zlib-rs"
rev = "692b0fd5a367cf4714b0b24e9e498e2a064d673c"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla-spidermonkey/jsparagus?rev=61f399c53a641ebd3077c1f39f054f6d396a633c"]
git = "https://github.com/mozilla-spidermonkey/jsparagus"
rev = "61f399c53a641ebd3077c1f39f054f6d396a633c"

14
Cargo.lock generated
View File

@ -2333,6 +2333,7 @@ dependencies = [
"kvstore",
"l10nregistry",
"l10nregistry-ffi",
"libz-rs-sys",
"lmdb-rkv-sys",
"localization-ffi",
"log",
@ -3418,6 +3419,14 @@ dependencies = [
"libc",
]
[[package]]
name = "libz-rs-sys"
version = "0.2.1"
source = "git+https://github.com/memorysafety/zlib-rs?rev=692b0fd5a367cf4714b0b24e9e498e2a064d673c#692b0fd5a367cf4714b0b24e9e498e2a064d673c"
dependencies = [
"zlib-rs",
]
[[package]]
name = "line-wrap"
version = "0.1.1"
@ -7228,3 +7237,8 @@ dependencies = [
"memchr",
"thiserror",
]
[[package]]
name = "zlib-rs"
version = "0.2.1"
source = "git+https://github.com/memorysafety/zlib-rs?rev=692b0fd5a367cf4714b0b24e9e498e2a064d673c#692b0fd5a367cf4714b0b24e9e498e2a064d673c"

View File

@ -261,6 +261,9 @@ export IPHONEOS_SDK_DIR
PATH := $(topsrcdir)/build/macosx:$(PATH)
endif
endif
# Use the same prefix as set through modules/zlib/src/mozzconf.h
# for libz-rs-sys, since we still use the headers from there.
export LIBZ_RS_SYS_PREFIX=MOZ_Z_
ifndef RUSTC_BOOTSTRAP
RUSTC_BOOTSTRAP := mozglue_static,qcms

View File

@ -53,9 +53,13 @@ if CONFIG["JS_HAS_INTL_API"]:
USE_LIBS += [
"fdlibm",
"nspr",
"zlib",
]
if not CONFIG["USE_LIBZ_RS"]:
USE_LIBS += [
"zlib",
]
if CONFIG["OS_ARCH"] != "WINNT":
OS_LIBS += [
"m",

View File

@ -84,7 +84,8 @@ SOURCES += [
# zlib library
DEFINES['FT_CONFIG_OPTION_SYSTEM_ZLIB'] = True
CFLAGS += CONFIG['MOZ_ZLIB_CFLAGS']
USE_LIBS += ['zlib']
if not CONFIG["USE_LIBZ_RS"]:
USE_LIBS += ['zlib']
# png library
DEFINES['FT_CONFIG_OPTION_USE_PNG'] = True

View File

@ -896,6 +896,13 @@ pkg_check_modules("MOZ_ZLIB", "zlib >= 1.2.3", when="--with-system-zlib")
set_config("MOZ_SYSTEM_ZLIB", True, when="--with-system-zlib")
@depends(with_system_zlib_option, milestone.is_nightly, when=toolkit)
def use_libz_rs(system_zlib, is_nightly):
return not system_zlib and is_nightly
set_config("USE_LIBZ_RS", True, when=use_libz_rs)
with only_when(cross_compiling):
option(
env="JS_BINARY",

View File

@ -2769,6 +2769,12 @@ who = "Mark Hammond <mhammond@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.27.0 -> 0.28.0"
[[audits.libz-rs-sys]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.2.1 -> 0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c"
importable = false
[[audits.linked-hash-map]]
who = "Aria Beingessner <a.beingessner@gmail.com>"
criteria = "safe-to-deploy"
@ -5410,6 +5416,12 @@ non-1-byte-aligned type, however right now that is not the case
(submitted https://github.com/zip-rs/zip2/issues/198).
"""
[[audits.zlib-rs]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.2.1 -> 0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c"
importable = false
[[trusted.aho-corasick]]
criteria = "safe-to-deploy"
user-id = 189 # Andrew Gallant (BurntSushi)
@ -5566,6 +5578,12 @@ user-id = 51017 # Yuki Okushi (JohnTitor)
start = "2020-03-17"
end = "2024-10-25"
[[trusted.libz-rs-sys]]
criteria = "safe-to-deploy"
user-id = 1303 # Ruben Nijveld (rnijveld)
start = "2024-02-23"
end = "2024-09-01"
[[trusted.linux-raw-sys]]
criteria = "safe-to-deploy"
user-id = 6825 # Dan Gohman (sunfishcode)
@ -5871,3 +5889,9 @@ criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-11-15"
end = "2024-09-12"
[[trusted.zlib-rs]]
criteria = "safe-to-deploy"
user-id = 1303 # Ruben Nijveld (rnijveld)
start = "2024-02-23"
end = "2024-09-01"

View File

@ -98,6 +98,9 @@ notes = "This crate has two testing-only dependencies which are specified as reg
audit-as-crates-io = false
notes = "This override is an api-compatible fork with an orthogonal implementation."
[policy."libz-rs-sys:0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c"]
audit-as-crates-io = true
[policy.malloc_size_of_derive]
audit-as-crates-io = false
notes = "This was originally servo code which Bobby Holley put on crates.io some years ago and that was moved in-tree as first-party code later on."
@ -231,6 +234,9 @@ notes = "Local override of the crates.io crate that uses a non-vendored local co
[policy.wr_malloc_size_of]
audit-as-crates-io = false
[policy."zlib-rs:0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c"]
audit-as-crates-io = true
[[exemptions.ahash]]
version = "0.7.6"
criteria = "safe-to-deploy"

View File

@ -316,6 +316,13 @@ user-id = 51017
user-login = "JohnTitor"
user-name = "Yuki Okushi"
[[publisher.libz-rs-sys]]
version = "0.2.1"
when = "2024-07-08"
user-id = 1303
user-login = "rnijveld"
user-name = "Ruben Nijveld"
[[publisher.linux-raw-sys]]
version = "0.4.12"
when = "2023-11-30"
@ -798,6 +805,13 @@ user-id = 48
user-login = "badboy"
user-name = "Jan-Erik Rediger"
[[publisher.zlib-rs]]
version = "0.2.1"
when = "2024-07-08"
user-id = 1303
user-login = "rnijveld"
user-name = "Ruben Nijveld"
[[audits.bytecode-alliance.wildcard-audits.arbitrary]]
who = "Nick Fitzgerald <fitzgen@gmail.com>"
criteria = "safe-to-deploy"

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"fae5e9fa3b75aef7028e3d109e1cefbd37dd879ee8e1b9e2783786514e543b1c","LICENSE":"7d60612df8fcd9d3714871a95b4d3012563246fdea8f6710b7567f83cfa3c8ef","README.md":"e6dcd6f09a9fd73b6571826bbadb3e19afebce521a6ce87028f6bcb4240c272a","examples/compress.rs":"b4bd15580da75e6a1dab7063f5f49c801a0073f3c87a1246e11e2012bc980cc7","examples/crc32_bench.rs":"26c57ba94a3ca6353f227627a3c064e3c4812807c3a4975a63f6bf2ef26c47a2","examples/uncompress.rs":"b78027d7a3d0e82b7f77d1114aa13ea778d8d11fa178e2d44d8acd4a3a728bb6","src/lib.rs":"24b70f484fb4e43d59e97bbb7d208889da8ebaad1b8e3bcae7afb4b64b7c1519","src/tests/deflate.rs":"c51a3e281b7858cee54c28e02269be8fbac41dfb77ee63a86c1f6aad1fce0606","src/tests/inflate.rs":"17690a215a2f676f1e485081af9df434a685339f5912b8eff4080113dbf66c56","src/tests/mod.rs":"b50934837e152598f9825927eb559cbc738c8484ca21aaaacaa2a7be02b1513a","src/tests/test-data/issue-109.gz":"b34d11c665984769dfe84384130077621ac30dbf9bf1580b54cd95a2e7fa6959","src/tests/test-data/op-len-edge-case.zraw":"01fe65d328666e5f0ec685b5523198002f9ff280688a7d948b75573fbebdfb12","src/tests/test-data/window-match-bug.zraw":"40a844f32fb06b1c5a2c9896fb2bdf5e5e5dcae37d365df99519818c961c296a"},"package":null}

69
third_party/rust/libz-rs-sys/Cargo.toml vendored Normal file
View File

@ -0,0 +1,69 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.75"
name = "libz-rs-sys"
version = "0.2.1"
publish = true
description = "A memory-safe zlib implementation written in rust"
homepage = "https://github.com/memorysafety/zlib-rs"
readme = "README.md"
license = "Zlib"
repository = "https://github.com/memorysafety/zlib-rs"
[lib]
crate-type = [
"rlib",
"cdylib",
]
[dependencies.zlib-rs]
version = "0.2.1"
path = "../zlib-rs"
default-features = false
[dev-dependencies]
crc32fast = "1.3.2"
libloading = "0.8.1"
[dev-dependencies.dynamic-libz-sys]
path = "../dynamic-libz-sys"
[dev-dependencies.libz-sys]
version = "1.1.12"
features = ["zlib-ng"]
default-features = false
[dev-dependencies.quickcheck]
version = "1.0.3"
features = []
default-features = false
[dev-dependencies.zlib-rs]
version = "0.2.1"
path = "../zlib-rs"
features = [
"std",
"__internal-test",
]
default-features = false
[features]
c-allocator = ["zlib-rs/c-allocator"]
custom-prefix = []
default = [
"std",
"rust-allocator",
]
rust-allocator = ["zlib-rs/rust-allocator"]
std = ["zlib-rs/std"]

19
third_party/rust/libz-rs-sys/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
(C) 2024 Internet Security Research Group
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

90
third_party/rust/libz-rs-sys/README.md vendored Normal file
View File

@ -0,0 +1,90 @@
This crate is a C API for [zlib-rs](https://docs.rs/zlib-rs/latest/zlib_rs/). The API is broadly equivalent to [`zlib-sys`](https://docs.rs/libz-sys/latest/libz_sys/) and [`zlib-ng-sys`](https://docs.rs/libz-ng-sys/latest/libz_ng_sys/), but does not currently provide the `gz*` family of functions.
From a rust perspective, this API is not very ergonomic. Use the [`flate2`](https://crates.io/crates/flate2) crate for a more
ergonomic rust interface to zlib.
# Features
**`custom-prefix`**
Add a custom prefix to all exported symbols.
The value of the `LIBZ_RS_SYS_PREFIX` is used as a prefix for all exported symbols. For example:
```
> LIBZ_RS_SYS_PREFIX="MY_CUSTOM_PREFIX" cargo build -p libz-rs-sys --features=custom-prefix
Compiling libz-rs-sys v0.2.1 (/home/folkertdev/rust/zlib-rs/libz-rs-sys)
Finished `dev` profile [optimized + debuginfo] target(s) in 0.21s
> objdump -tT target/debug/liblibz_rs_sys.so | grep "uncompress"
0000000000081028 l O .got 0000000000000000 _ZN7zlib_rs7inflate10uncompress17he7d985e55c58a189E$got
000000000002c570 l F .text 00000000000001ef _ZN7zlib_rs7inflate10uncompress17he7d985e55c58a189E
0000000000024330 g F .text 000000000000008e MY_CUSTOM_PREFIXuncompress
0000000000024330 g DF .text 000000000000008e Base MY_CUSTOM_PREFIXuncompress
```
**`c-allocator`, `rust-allocator`**
Pick the default allocator implementation that is used if no `zalloc` and `zfree` are configured in the input `z_stream`.
- `c-allocator`: use `malloc`/`free` for the implementation of `zalloc` and `zfree`
- `rust-allocator`: the rust global allocator for the implementation of `zalloc` and `zfree`
The `rust-allocator` is the default when this crate is used as a rust dependency, and slightly more efficient because alignment is handled by the allocator. When building a dynamic library, it may make sense to use `c-allocator` instead.
**`std`**
Assume that `std` is available. When this feature is turned off, this crate is compatible with `#![no_std]`.
# Example
This example compresses ("deflates") the string `"Hello, World!"` and then decompresses
("inflates") it again.
```rust
let mut strm = libz_rs_sys::z_stream::default();
let version = libz_rs_sys::zlibVersion();
let stream_size = core::mem::size_of_val(&strm) as i32;
let level = 6; // the default compression level
let err = unsafe { libz_rs_sys::deflateInit_(&mut strm, level, version, stream_size) };
assert_eq!(err, libz_rs_sys::Z_OK);
let input = "Hello, World!";
strm.avail_in = input.len() as _;
strm.next_in = input.as_ptr();
let mut output = [0u8; 32];
strm.avail_out = output.len() as _;
strm.next_out = output.as_mut_ptr();
let err = unsafe { libz_rs_sys::deflate(&mut strm, libz_rs_sys::Z_FINISH) };
assert_eq!(err, libz_rs_sys::Z_STREAM_END);
let err = unsafe { libz_rs_sys::deflateEnd(&mut strm) };
assert_eq!(err, libz_rs_sys::Z_OK);
let deflated = &mut output[..strm.total_out as usize];
let mut strm = libz_rs_sys::z_stream::default();
let err = unsafe { libz_rs_sys::inflateInit_(&mut strm, version, stream_size) };
assert_eq!(err, libz_rs_sys::Z_OK);
strm.avail_in = deflated.len() as _;
strm.next_in = deflated.as_ptr();
let mut output = [0u8; 32];
strm.avail_out = output.len() as _;
strm.next_out = output.as_mut_ptr();
let err = unsafe { libz_rs_sys::inflate(&mut strm, libz_rs_sys::Z_FINISH) };
assert_eq!(err, libz_rs_sys::Z_STREAM_END);
let err = unsafe { libz_rs_sys::inflateEnd(&mut strm) };
assert_eq!(err, libz_rs_sys::Z_OK);
let inflated = &output[..strm.total_out as usize];
assert_eq!(inflated, input.as_bytes())
```

View File

@ -0,0 +1,295 @@
//! a binary just so we can look at the optimized assembly
use std::{collections::hash_map::DefaultHasher, env::temp_dir, hash::Hash};
// we use the libz_sys but configure zlib-ng in zlib compat mode
use libz_sys as libz_ng_sys;
use zlib_rs::{deflate::DeflateConfig, DeflateFlush, ReturnCode};
use std::ffi::{c_int, c_uint};
fn main() {
let mut it = std::env::args();
let _ = it.next().unwrap();
let level: i32 = it.next().unwrap().parse().unwrap();
let mut hasher = DefaultHasher::new();
use std::hash::Hasher;
match it.next().unwrap().as_str() {
"ng" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();
let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len();
let err = compress_ng(&mut dest_vec, &mut dest_len, &input, level);
if err != ReturnCode::Ok {
panic!("error {err:?}");
}
dest_vec.truncate(dest_len);
dest_vec.hash(&mut hasher);
dbg!(hasher.finish());
std::fs::write(temp_dir().join("ng.txt"), &dest_vec).unwrap();
drop(dest_vec)
}
"rs" => {
let path = it.next().unwrap();
let Ok(input) = std::fs::read(&path) else {
panic!("could not read file {path:?}");
};
let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len();
let err = compress_rs(&mut dest_vec, &mut dest_len, &input, level);
if err != ReturnCode::Ok {
panic!("error {err:?}");
}
dest_vec.truncate(dest_len);
dest_vec.hash(&mut hasher);
dbg!(hasher.finish());
std::fs::write(temp_dir().join("rs.txt"), &dest_vec).unwrap();
drop(dest_vec)
}
"xx" => {
let path = it.next().unwrap();
let Ok(input) = std::fs::read(&path) else {
panic!("could not read file {path:?}");
};
let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len();
let err = compress_dynamic(&mut dest_vec, &mut dest_len, &input, level);
if err != ReturnCode::Ok {
panic!("error {err:?}");
}
dest_vec.truncate(dest_len);
dest_vec.hash(&mut hasher);
dbg!(hasher.finish());
std::fs::write(temp_dir().join("xx.tar.gz"), &dest_vec).unwrap();
drop(dest_vec)
}
"qq" => {
let ng = std::fs::read(temp_dir().join("ng.txt")).unwrap();
let rs = std::fs::read(temp_dir().join("rs.txt")).unwrap();
for (i, (a, b)) in (ng.iter().zip(rs.iter())).enumerate() {
if a != b {
panic!("index {i}");
}
}
}
other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"),
}
}
const METHOD: i32 = zlib_rs::c_api::Z_DEFLATED;
const WINDOW_BITS: i32 = 15;
const MEM_LEVEL: i32 = 8;
const STRATEGY: i32 = zlib_rs::c_api::Z_DEFAULT_STRATEGY;
fn compress_rs(
dest: &mut [u8],
dest_len: &mut usize,
source: &[u8],
//
level: i32,
) -> ReturnCode {
use libz_rs_sys::{deflate, deflateEnd, deflateInit2_, z_stream, zlibVersion};
let mut stream = z_stream {
next_in: source.as_ptr() as *mut u8,
avail_in: 0, // for special logic in the first iteration
total_in: 0,
next_out: dest.as_mut_ptr(),
avail_out: 0, // for special logic on the first iteration
total_out: 0,
msg: std::ptr::null_mut(),
state: std::ptr::null_mut(),
zalloc: Some(zlib_rs::allocate::zalloc_c),
zfree: Some(zlib_rs::allocate::zfree_c),
opaque: std::ptr::null_mut(),
data_type: 0,
adler: 0,
reserved: 0,
};
let err = {
let strm: *mut z_stream = &mut stream;
unsafe {
deflateInit2_(
strm,
level,
METHOD,
WINDOW_BITS,
MEM_LEVEL,
STRATEGY,
zlibVersion(),
std::mem::size_of::<z_stream>() as c_int,
)
}
};
if ReturnCode::from(err) != ReturnCode::Ok as _ {
return ReturnCode::from(err);
}
let max = c_uint::MAX as usize;
let mut left = dest.len();
let mut source_len = source.len();
loop {
if stream.avail_out == 0 {
stream.avail_out = Ord::min(left, max) as _;
left -= stream.avail_out as usize;
}
if stream.avail_in == 0 {
stream.avail_in = Ord::min(source_len, max) as _;
source_len -= stream.avail_in as usize;
}
let flush = if source_len > 0 {
DeflateFlush::NoFlush
} else {
DeflateFlush::Finish
};
let err = unsafe { deflate(&mut stream, flush as i32) };
if ReturnCode::from(err) != ReturnCode::Ok {
break;
}
}
*dest_len = stream.total_out as _;
unsafe { deflateEnd(&mut stream) };
ReturnCode::Ok
}
fn compress_ng(
dest: &mut [u8],
dest_len: &mut usize,
source: &[u8],
//
level: i32,
) -> ReturnCode {
use libz_ng_sys::{deflate, deflateEnd, deflateInit2_, z_stream, zlibVersion};
let mut stream = z_stream {
next_in: source.as_ptr() as *mut u8,
avail_in: 0, // for special logic in the first iteration
total_in: 0,
next_out: dest.as_mut_ptr(),
avail_out: 0, // for special logic on the first iteration
total_out: 0,
msg: std::ptr::null_mut(),
state: std::ptr::null_mut(),
zalloc: zlib_rs::allocate::zalloc_c,
zfree: zlib_rs::allocate::zfree_c,
opaque: std::ptr::null_mut(),
data_type: 0,
adler: 0,
reserved: 0,
};
let err = {
let strm: *mut z_stream = &mut stream;
unsafe {
deflateInit2_(
strm,
level,
METHOD,
WINDOW_BITS,
MEM_LEVEL,
STRATEGY,
zlibVersion(),
std::mem::size_of::<z_stream>() as c_int,
)
}
};
if ReturnCode::from(err) != ReturnCode::Ok as _ {
return ReturnCode::from(err);
}
let max = c_uint::MAX as usize;
let mut left = dest.len();
let mut source_len = source.len();
loop {
if stream.avail_out == 0 {
stream.avail_out = Ord::min(left, max) as _;
left -= stream.avail_out as usize;
}
if stream.avail_in == 0 {
stream.avail_in = Ord::min(source_len, max) as _;
source_len -= stream.avail_in as usize;
}
let flush = if source_len > 0 {
DeflateFlush::NoFlush
} else {
DeflateFlush::Finish
};
let err = unsafe { deflate(&mut stream, flush as i32) };
if ReturnCode::from(err) != ReturnCode::Ok {
break;
}
}
*dest_len = stream.total_out as _;
unsafe { deflateEnd(&mut stream) };
ReturnCode::Ok
}
fn compress_dynamic(
dest: &mut [u8],
dest_len: &mut usize,
source: &[u8],
//
level: i32,
) -> ReturnCode {
let config = DeflateConfig::new(level);
let (output, err) = dynamic_libz_sys::compress_slice(
dest,
source,
config.level,
config.method as i32,
config.window_bits,
config.mem_level,
config.strategy as i32,
);
*dest_len = output.len();
ReturnCode::from(err)
}

View File

@ -0,0 +1,61 @@
//! a binary just so we can look at the optimized assembly
pub fn main() {
let mut it = std::env::args();
let _ = it.next().unwrap();
match it.next().unwrap().as_str() {
"sse" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();
let mut state = zlib_rs::crc32::Crc32Fold::new();
state.fold(&input, 0);
println!("{:#x}", state.finish());
}
"crc32fast" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();
let mut h = crc32fast::Hasher::new_with_initial(0);
h.update(&input[..]);
println!("{:#x}", h.finalize());
}
"sse-chunked" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();
let mut state = zlib_rs::crc32::Crc32Fold::new();
for c in input.chunks(32) {
state.fold(c, 0);
}
println!("{:#x}", state.finish());
}
"crc32fast-chunked" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();
let mut h = crc32fast::Hasher::new_with_initial(0);
for c in input.chunks(32) {
h.update(c);
}
println!("{:#x}", h.finalize());
}
"adler32" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();
let h = zlib_rs::adler32(42, &input);
println!("{:#x}", h);
}
other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"),
}
}

View File

@ -0,0 +1,111 @@
//! a binary just so we can look at the optimized assembly
// we use the libz_sys but configure zlib-ng in zlib compat mode
use libz_sys as libz_ng_sys;
use std::{ffi::c_ulong, path::PathBuf};
unsafe fn uncompress(
dest: *mut u8,
dest_len: *mut std::ffi::c_ulong,
source: *const u8,
source_len: std::ffi::c_ulong,
) -> std::ffi::c_int {
let lib = libloading::Library::new("/home/folkertdev/rust/zlib-ng/libz-ng.so").unwrap();
type Func = unsafe extern "C" fn(
dest: *mut u8,
dest_len: *mut std::ffi::c_ulong,
source: *const u8,
source_len: std::ffi::c_ulong,
) -> std::ffi::c_int;
let f: libloading::Symbol<Func> = lib.get(b"zng_uncompress").unwrap();
f(dest, dest_len, source, source_len)
}
fn main() {
let mut it = std::env::args();
let _ = it.next().unwrap();
match it.next().unwrap().as_str() {
"ng" => {
let path = it.next().unwrap();
let input = std::fs::read(&path).unwrap();
let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len() as c_ulong;
let dest = dest_vec.as_mut_ptr();
let source = input.as_ptr();
let source_len = input.len() as _;
let err = unsafe { libz_ng_sys::uncompress(dest, &mut dest_len, source, source_len) };
if err != 0 {
panic!("error {err}");
}
dest_vec.truncate(dest_len as usize);
let path = PathBuf::from(path);
std::fs::write(path.with_extension(""), &dest_vec).unwrap();
drop(dest_vec)
}
"rs" => {
let path = it.next().unwrap();
let input = std::fs::read(&path).unwrap();
let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len() as std::ffi::c_ulong;
let dest = dest_vec.as_mut_ptr();
let source = input.as_ptr();
let source_len = input.len() as _;
let err = unsafe { ::libz_rs_sys::uncompress(dest, &mut dest_len, source, source_len) };
if err != 0 {
panic!("error {err}");
}
dest_vec.truncate(dest_len as usize);
let path = PathBuf::from(path);
std::fs::write(path.with_extension(""), &dest_vec).unwrap();
drop(dest_vec)
}
"xx" => {
let path = it.next().unwrap();
let input = std::fs::read(&path).unwrap();
let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len() as std::ffi::c_ulong;
let dest = dest_vec.as_mut_ptr();
let source = input.as_ptr();
let source_len = input.len() as _;
let err = unsafe { uncompress(dest, &mut dest_len, source, source_len) };
if err != 0 {
panic!();
}
dest_vec.truncate(dest_len as usize);
let path = PathBuf::from(path);
std::fs::write(path.with_extension(""), &dest_vec).unwrap();
drop(dest_vec)
}
other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"),
}
}

673
third_party/rust/libz-rs-sys/src/lib.rs vendored Normal file
View File

@ -0,0 +1,673 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::missing_safety_doc)] // obviously needs to be fixed long-term
#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
//! # Safety of `*mut z_stream`
//!
//! Most functions require an argument of type `*mut z_stream`. Unless
//! otherwise noted, the safety requirements on such arguments are at least that the
//! pointer must be either:
//!
//! - A `NULL` pointer
//! - A pointer to a correctly aligned, initialized value of type `z_stream`.
//!
//! In other words, it must be safe to cast the `*mut z_stream` to a `Option<&mut z_stream>`. It is
//! always safe to provide an argument of type `&mut z_stream`: rust will automatically downcast
//! the argument to `*mut z_stream`.
#[cfg(test)]
mod tests;
use core::mem::MaybeUninit;
use core::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
use zlib_rs::{
deflate::{DeflateConfig, DeflateStream, Method, Strategy},
inflate::{InflateConfig, InflateStream},
DeflateFlush, InflateFlush, ReturnCode,
};
pub use zlib_rs::c_api::*;
#[cfg(feature = "custom-prefix")]
macro_rules! prefix {
($name:expr) => {
concat!(env!("LIBZ_RS_SYS_PREFIX"), stringify!($name))
};
}
#[cfg(all(not(feature = "custom-prefix"), not(test)))]
macro_rules! prefix {
($name:expr) => {
stringify!($name)
};
}
#[cfg(all(not(feature = "custom-prefix"), test))]
macro_rules! prefix {
($name:expr) => {
concat!("LIBZ_RS_SYS_", stringify!($name))
};
}
#[cfg(all(feature = "rust-allocator", feature = "c-allocator"))]
const _: () =
compile_error!("Only one of `rust-allocator` and `c-allocator` can be enabled at a time");
#[allow(unreachable_code)]
const DEFAULT_ZALLOC: Option<alloc_func> = '_blk: {
// this `break 'blk'` construction exists to generate just one compile error and not other
// warnings when multiple allocators are configured.
#[cfg(feature = "c-allocator")]
break '_blk Some(zlib_rs::allocate::zalloc_c);
#[cfg(feature = "rust-allocator")]
break '_blk Some(zlib_rs::allocate::zalloc_rust);
None
};
#[allow(unreachable_code)]
const DEFAULT_ZFREE: Option<free_func> = '_blk: {
#[cfg(feature = "c-allocator")]
break '_blk Some(zlib_rs::allocate::zfree_c);
#[cfg(feature = "rust-allocator")]
break '_blk Some(zlib_rs::allocate::zfree_rust);
None
};
// In spirit this type is `libc::off_t`, but it would be our only libc dependency, and so we
// hardcode the type here. This should be correct on most operating systems. If we ever run into
// issues with it, we can either special-case or add a feature flag to force a particular width
pub type z_off_t = c_long;
#[export_name = prefix!(crc32)]
pub unsafe extern "C" fn crc32(crc: c_ulong, buf: *const Bytef, len: uInt) -> c_ulong {
let buf = unsafe { core::slice::from_raw_parts(buf, len as usize) };
zlib_rs::crc32(crc as u32, buf) as c_ulong
}
#[export_name = prefix!(crc32_combine)]
pub unsafe extern "C" fn crc32_combine(crc1: c_ulong, crc2: c_ulong, len2: z_off_t) -> c_ulong {
zlib_rs::crc32_combine(crc1 as u32, crc2 as u32, len2 as u64) as c_ulong
}
#[export_name = prefix!(adler32)]
pub unsafe extern "C" fn adler32(adler: c_ulong, buf: *const Bytef, len: uInt) -> c_ulong {
let buf = unsafe { core::slice::from_raw_parts(buf, len as usize) };
zlib_rs::adler32(adler as u32, buf) as c_ulong
}
#[export_name = prefix!(adler32_combine)]
pub unsafe extern "C" fn adler32_combine(
adler1: c_ulong,
adler2: c_ulong,
len2: z_off_t,
) -> c_ulong {
if let Ok(len2) = u64::try_from(len2) {
zlib_rs::adler32_combine(adler1 as u32, adler2 as u32, len2) as c_ulong
} else {
// for negative len, return invalid adler32 as a clue for debugging
0xffffffff
}
}
/// Inflates `source` into `dest`, and writes the final inflated size into `destLen`.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// - `source` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads for
/// `sourceLen` bytes. The entity of `source` must be contained in one allocated object!
/// - `source` must point to `sourceLen` consecutive properly initialized values of type `u8`.
/// - `dest` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads for
/// `*destLen` bytes. The entity of `source` must be contained in one allocated object!
/// - `dest` must point to `*destLen` consecutive properly initialized values of type `u8`.
/// - while this function runs, both read and write actions to the `source` and `dest` memory
/// ranges are forbidden
#[export_name = prefix!(uncompress)]
pub unsafe extern "C" fn uncompress(
dest: *mut u8,
destLen: *mut c_ulong,
source: *const u8,
sourceLen: c_ulong,
) -> c_int {
let data = dest;
let len = core::ptr::read(destLen) as usize;
let output = core::slice::from_raw_parts_mut(data as *mut MaybeUninit<u8>, len);
let data = source;
let len = sourceLen as usize;
let input = core::slice::from_raw_parts(data, len);
let (output, err) = zlib_rs::inflate::uncompress(output, input, InflateConfig::default());
core::ptr::write(destLen, output.len() as _);
err as c_int
}
#[export_name = prefix!(inflate)]
pub unsafe extern "C" fn inflate(strm: *mut z_stream, flush: i32) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
let flush = InflateFlush::try_from(flush).unwrap_or_default();
zlib_rs::inflate::inflate(stream, flush) as _
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(inflateEnd)]
pub unsafe extern "C" fn inflateEnd(strm: *mut z_stream) -> i32 {
match InflateStream::from_stream_mut(strm) {
Some(stream) => {
zlib_rs::inflate::end(stream);
ReturnCode::Ok as _
}
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(inflateBackInit_)]
pub unsafe extern "C" fn inflateBackInit_(
_strm: z_streamp,
_windowBits: c_int,
_window: *mut c_uchar,
_version: *const c_char,
_stream_size: c_int,
) -> c_int {
todo!("inflateBack is not implemented yet")
}
#[export_name = prefix!(inflateBack)]
pub unsafe extern "C" fn inflateBack(
_strm: z_streamp,
_in: in_func,
_in_desc: *mut c_void,
_out: out_func,
_out_desc: *mut c_void,
) -> c_int {
todo!("inflateBack is not implemented yet")
}
#[export_name = prefix!(inflateBackEnd)]
pub unsafe extern "C" fn inflateBackEnd(_strm: z_streamp) -> c_int {
todo!("inflateBack is not implemented yet")
}
#[export_name = prefix!(inflateCopy)]
pub unsafe extern "C" fn inflateCopy(dest: *mut z_stream, source: *const z_stream) -> i32 {
if dest.is_null() {
return ReturnCode::StreamError as _;
}
if let Some(source) = InflateStream::from_stream_ref(source) {
zlib_rs::inflate::copy(&mut *(dest as *mut MaybeUninit<InflateStream>), source) as _
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(inflateMark)]
pub unsafe extern "C" fn inflateMark(strm: *const z_stream) -> c_long {
if let Some(stream) = InflateStream::from_stream_ref(strm) {
zlib_rs::inflate::mark(stream)
} else {
c_long::MIN
}
}
#[export_name = prefix!(inflateSync)]
pub unsafe extern "C" fn inflateSync(strm: *mut z_stream) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
zlib_rs::inflate::sync(stream) as _
} else {
ReturnCode::StreamError as _
}
}
// undocumented
#[export_name = prefix!(inflateSyncPoint)]
pub unsafe extern "C" fn inflateSyncPoint(strm: *mut z_stream) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
zlib_rs::inflate::sync_point(stream) as i32
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(inflateInit_)]
pub unsafe extern "C" fn inflateInit_(
strm: z_streamp,
version: *const c_char,
stream_size: c_int,
) -> c_int {
if !is_version_compatible(version, stream_size) {
ReturnCode::VersionError as _
} else if strm.is_null() {
ReturnCode::StreamError as _
} else {
zlib_rs::inflate::init(&mut *strm, InflateConfig::default()) as _
}
}
#[export_name = prefix!(inflateInit2_)]
pub unsafe extern "C" fn inflateInit2_(
strm: z_streamp,
windowBits: c_int,
version: *const c_char,
stream_size: c_int,
) -> c_int {
if !is_version_compatible(version, stream_size) {
ReturnCode::VersionError as _
} else {
inflateInit2(strm, windowBits)
}
}
#[export_name = prefix!(inflateInit2)]
pub unsafe extern "C" fn inflateInit2(strm: z_streamp, windowBits: c_int) -> c_int {
if strm.is_null() {
ReturnCode::StreamError as _
} else {
let config = InflateConfig {
window_bits: windowBits,
};
let stream = &mut *strm;
if stream.zalloc.is_none() {
stream.zalloc = DEFAULT_ZALLOC;
stream.opaque = core::ptr::null_mut();
}
if stream.zfree.is_none() {
stream.zfree = DEFAULT_ZFREE;
}
zlib_rs::inflate::init(stream, config) as _
}
}
#[export_name = prefix!(inflatePrime)]
pub unsafe extern "C" fn inflatePrime(strm: *mut z_stream, bits: i32, value: i32) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
zlib_rs::inflate::prime(stream, bits, value) as _
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(inflateReset)]
pub unsafe extern "C" fn inflateReset(strm: *mut z_stream) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
zlib_rs::inflate::reset(stream) as _
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(inflateReset2)]
pub unsafe extern "C" fn inflateReset2(strm: *mut z_stream, windowBits: c_int) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
let config = InflateConfig {
window_bits: windowBits,
};
zlib_rs::inflate::reset_with_config(stream, config) as _
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(inflateSetDictionary)]
pub unsafe extern "C" fn inflateSetDictionary(
strm: *mut z_stream,
dictionary: *const u8,
dictLength: c_uint,
) -> c_int {
let Some(stream) = InflateStream::from_stream_mut(strm) else {
return ReturnCode::StreamError as _;
};
let dict = if dictLength == 0 || dictionary.is_null() {
&[]
} else {
unsafe { core::slice::from_raw_parts(dictionary, dictLength as usize) }
};
zlib_rs::inflate::set_dictionary(stream, dict) as _
}
// part of gzip
#[export_name = prefix!(inflateGetHeader)]
pub unsafe extern "C" fn inflateGetHeader(strm: z_streamp, head: gz_headerp) -> c_int {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
let header = if head.is_null() {
None
} else {
Some(unsafe { &mut *(head) })
};
zlib_rs::inflate::get_header(stream, header) as i32
} else {
ReturnCode::StreamError as _
}
}
// undocumented but exposed function
#[export_name = prefix!(inflateUndermine)]
pub unsafe extern "C" fn inflateUndermine(strm: *mut z_stream, subvert: i32) -> c_int {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
zlib_rs::inflate::undermine(stream, subvert) as i32
} else {
ReturnCode::StreamError as _
}
}
// undocumented but exposed function
#[export_name = prefix!(inflateResetKeep)]
pub unsafe extern "C" fn inflateResetKeep(strm: *mut z_stream) -> i32 {
if let Some(stream) = InflateStream::from_stream_mut(strm) {
zlib_rs::inflate::reset_keep(stream) as _
} else {
ReturnCode::StreamError as _
}
}
// undocumented but exposed function
#[export_name = prefix!(inflateCodesUsed)]
pub unsafe extern "C" fn inflateCodesUsed(_strm: *mut z_stream) -> c_ulong {
todo!()
}
#[export_name = prefix!(deflate)]
pub unsafe extern "C" fn deflate(strm: *mut z_stream, flush: i32) -> i32 {
if let Some(stream) = DeflateStream::from_stream_mut(strm) {
match DeflateFlush::try_from(flush) {
Ok(flush) => zlib_rs::deflate::deflate(stream, flush) as _,
Err(()) => ReturnCode::StreamError as _,
}
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(deflateSetHeader)]
pub unsafe extern "C" fn deflateSetHeader(strm: *mut z_stream, head: gz_headerp) -> i32 {
if let Some(stream) = DeflateStream::from_stream_mut(strm) {
zlib_rs::deflate::set_header(
stream,
if head.is_null() {
None
} else {
Some(&mut *head)
},
) as _
} else {
ReturnCode::StreamError as _
}
}
#[export_name = prefix!(deflateBound)]
pub unsafe extern "C" fn deflateBound(strm: *mut z_stream, sourceLen: c_ulong) -> c_ulong {
zlib_rs::deflate::bound(DeflateStream::from_stream_mut(strm), sourceLen as usize) as c_ulong
}
#[export_name = prefix!(compress)]
pub unsafe extern "C" fn compress(
dest: *mut Bytef,
destLen: *mut c_ulong,
source: *const Bytef,
sourceLen: c_ulong,
) -> c_int {
compress2(
dest,
destLen,
source,
sourceLen,
DeflateConfig::default().level,
)
}
#[export_name = prefix!(compress2)]
pub unsafe extern "C" fn compress2(
dest: *mut Bytef,
destLen: *mut c_ulong,
source: *const Bytef,
sourceLen: c_ulong,
level: c_int,
) -> c_int {
let data = dest;
let len = core::ptr::read(destLen) as usize;
let output = core::slice::from_raw_parts_mut(data as *mut MaybeUninit<u8>, len);
let data = source;
let len = sourceLen as usize;
let input = core::slice::from_raw_parts(data, len);
let config = DeflateConfig::new(level);
let (output, err) = zlib_rs::deflate::compress(output, input, config);
core::ptr::write(destLen, output.len() as _);
err as c_int
}
#[export_name = prefix!(compressBound)]
pub extern "C" fn compressBound(sourceLen: c_ulong) -> c_ulong {
zlib_rs::deflate::compress_bound(sourceLen as usize) as c_ulong
}
#[export_name = prefix!(deflateEnd)]
pub unsafe extern "C" fn deflateEnd(strm: *mut z_stream) -> i32 {
match DeflateStream::from_stream_mut(strm) {
Some(stream) => match zlib_rs::deflate::end(stream) {
Ok(_) => ReturnCode::Ok as _,
Err(_) => ReturnCode::DataError as _,
},
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflateReset)]
pub unsafe extern "C" fn deflateReset(strm: *mut z_stream) -> i32 {
match DeflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::deflate::reset(stream) as _,
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflateParams)]
pub unsafe extern "C" fn deflateParams(strm: z_streamp, level: c_int, strategy: c_int) -> c_int {
let Ok(strategy) = Strategy::try_from(strategy) else {
return ReturnCode::StreamError as _;
};
match DeflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::deflate::params(stream, level, strategy) as _,
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflateSetDictionary)]
pub unsafe extern "C" fn deflateSetDictionary(
strm: z_streamp,
dictionary: *const Bytef,
dictLength: uInt,
) -> c_int {
let dictionary = core::slice::from_raw_parts(dictionary, dictLength as usize);
match DeflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::deflate::set_dictionary(stream, dictionary) as _,
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflatePrime)]
pub unsafe extern "C" fn deflatePrime(strm: z_streamp, bits: c_int, value: c_int) -> c_int {
match DeflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::deflate::prime(stream, bits, value) as _,
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflatePending)]
pub unsafe extern "C" fn deflatePending(
strm: z_streamp,
pending: *mut c_uint,
bits: *mut c_int,
) -> c_int {
match DeflateStream::from_stream_mut(strm) {
Some(stream) => {
let (current_pending, current_bits) = stream.pending();
if !pending.is_null() {
*pending = current_pending as c_uint;
}
if !bits.is_null() {
*bits = current_bits as c_int;
}
ReturnCode::Ok as _
}
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflateCopy)]
pub unsafe extern "C" fn deflateCopy(dest: z_streamp, source: z_streamp) -> c_int {
let dest = if dest.is_null() {
return ReturnCode::StreamError as _;
} else {
&mut *(dest as *mut MaybeUninit<_>)
};
match DeflateStream::from_stream_mut(source) {
Some(source) => zlib_rs::deflate::copy(dest, source) as _,
None => ReturnCode::StreamError as _,
}
}
#[export_name = prefix!(deflateInit_)]
pub unsafe extern "C" fn deflateInit_(
strm: z_streamp,
level: c_int,
version: *const c_char,
stream_size: c_int,
) -> c_int {
if !is_version_compatible(version, stream_size) {
ReturnCode::VersionError as _
} else if strm.is_null() {
ReturnCode::StreamError as _
} else {
let stream = &mut *strm;
if stream.zalloc.is_none() {
stream.zalloc = DEFAULT_ZALLOC;
stream.opaque = core::ptr::null_mut();
}
if stream.zfree.is_none() {
stream.zfree = DEFAULT_ZFREE;
}
zlib_rs::deflate::init(stream, DeflateConfig::new(level)) as _
}
}
#[export_name = prefix!(deflateInit2_)]
pub unsafe extern "C" fn deflateInit2_(
strm: z_streamp,
level: c_int,
method: c_int,
windowBits: c_int,
memLevel: c_int,
strategy: c_int,
version: *const c_char,
stream_size: c_int,
) -> c_int {
if !is_version_compatible(version, stream_size) {
ReturnCode::VersionError as _
} else if strm.is_null() {
ReturnCode::StreamError as _
} else {
let Ok(method) = Method::try_from(method) else {
return ReturnCode::StreamError as _;
};
let Ok(strategy) = Strategy::try_from(strategy) else {
return ReturnCode::StreamError as _;
};
let config = DeflateConfig {
level,
method,
window_bits: windowBits,
mem_level: memLevel,
strategy,
};
let stream = &mut *strm;
if stream.zalloc.is_none() {
stream.zalloc = DEFAULT_ZALLOC;
stream.opaque = core::ptr::null_mut();
}
if stream.zfree.is_none() {
stream.zfree = DEFAULT_ZFREE;
}
zlib_rs::deflate::init(stream, config) as _
}
}
#[export_name = prefix!(deflateTune)]
pub unsafe extern "C" fn deflateTune(
strm: z_streamp,
good_length: c_int,
max_lazy: c_int,
nice_length: c_int,
max_chain: c_int,
) -> c_int {
match DeflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::deflate::tune(
stream,
good_length as usize,
max_lazy as usize,
nice_length as usize,
max_chain as usize,
) as _,
None => ReturnCode::StreamError as _,
}
}
// the first part of this version specifies the zlib that we're compatible with (in terms of
// supported functions). In practice in most cases only the major version is checked, unless
// specific functions that were added later are used.
const LIBZ_RS_SYS_VERSION: &str = concat!("1.3.0-zlib-rs-", env!("CARGO_PKG_VERSION"), "\0");
unsafe fn is_version_compatible(version: *const c_char, stream_size: i32) -> bool {
if version.is_null() {
return false;
}
let expected_major_version = core::ptr::read(version);
if expected_major_version as u8 != LIBZ_RS_SYS_VERSION.as_bytes()[0] {
return false;
}
core::mem::size_of::<z_stream>() as i32 == stream_size
}
pub const extern "C" fn zlibVersion() -> *const c_char {
LIBZ_RS_SYS_VERSION.as_ptr() as *const c_char
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
mod deflate;
mod inflate;

Binary file not shown.

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"ec3eadbc9e13ef2ceae8ff8feed443b9e6fd9ceaf3a98e0e0cf245964b4e594f","LICENSE":"7d60612df8fcd9d3714871a95b4d3012563246fdea8f6710b7567f83cfa3c8ef","README.md":"9938581c82330440be5f3b6b9125cc02c0874b250dc62093f167bf2158dbe29a","src/adler32.rs":"8a8f70daf888f55625ce316b5ff3432eb1713fd101f8b3f88ee4c3f08cbfe6bb","src/adler32/avx2.rs":"d4ef3e0729a5246a0af08c3078cabad17720585ee7a2ab2dfabe13c6d307a002","src/adler32/generic.rs":"cfe8da0e145faac42ed31e9de1ccb718e389265517a007533b8c997cae68f1a7","src/adler32/neon.rs":"8c30926d74573ee5b74b013c19bb1fcebe980ebaf8384df66dae4f957d856036","src/allocate.rs":"81ad93751a1c3206a1b0a63b1970c75b6f59556b094055626472e64380fe81dd","src/c_api.rs":"b41685bc20b96760ea7fdc0e1d30d550901be5dc12292f9c905d7dea177dfeca","src/crc32.rs":"30be91db6a8a6d7004b9dcab43c9fe7e8623c7425e31bf4eff5c537b0204dcab","src/crc32/acle.rs":"e2990813a358629a4ace5b409897416685c84ebebb1becbcd4062d2a2c3dee0a","src/crc32/braid.rs":"1b83372b944f49d954c39e7348707f1668fc7d1dad2c8b881fb5f98d3c98f8cb","src/crc32/combine.rs":"a1aded8c5f1886f60daad9765886299c65feb5240f24f8e9f67ebced14e267f0","src/crc32/pclmulqdq.rs":"891a57eea0e8d5ca4b5d5ee0dd69c62d0c9ecaa741c26ba09abedefe53fd446b","src/deflate.rs":"5ced180868deb00914496f6e012b88c167a59f348a44cd0166a9f791b1b83312","src/deflate/algorithm/fast.rs":"686c0a35c1baff2d842287354f919e166fe5eca1748ad46ed14d6127611bffa0","src/deflate/algorithm/huff.rs":"2ed0a098571d4e056bb4e1d8655ec8d37e6d291ba3e2d5d7c581c2486e6abbce","src/deflate/algorithm/medium.rs":"6b3b3e99ad870a6c35921b0abb4b10569e49bf3d5f57a8af2179c886a94e54b6","src/deflate/algorithm/mod.rs":"15f980186da0355eb363eb97e1580c3ecfb90b0cc7d58ed3c25081f13983931b","src/deflate/algorithm/quick.rs":"3a77e897d13ee1cc7681a05a47e32030eedf64091dc186aa6dc00c397b897a44","src/deflate/algorithm/rle.rs":"549427a5a8a69610afd612f89a9cbde97fe78c38c85442083b5dde10e8be4d73","src/deflate/algorithm/slow.rs":"2fa351c77604fad7d5e113ed3b90ba2abc83be0ff589a0e367d012aee5ce967b","src/deflate/algorithm/stored.rs":"c3ea25d2b7e0ace89f7d3a02887f78072ef1c8f2306a143705d7f82917014af8","src/deflate/compare256.rs":"bba6aa1dc8d19ca36ba2ea343d15c086169b43eaed613c0894bb31c1905e0d5b","src/deflate/hash_calc.rs":"bf02da0eb13aef78ad8411c07e57b8a770b6b466bdf8a916eec7c54f127bbbb7","src/deflate/longest_match.rs":"3bc61d20d5f327d3530ac84c8198e101add84fe467a31c771449ed482c877355","src/deflate/pending.rs":"84f0860b650570e824607e3ceb53dcc9fbb91a667ba110728cc9d4c995f1bb05","src/deflate/slide_hash.rs":"4d16e26919152b56cfd5bba40e5fa46ba34f967fed85e064c57bd62fcea8527b","src/deflate/test-data/fireworks.jpg":"93b986ce7d7e361f0d3840f9d531b5f40fb6ca8c14d6d74364150e255f126512","src/deflate/test-data/inflate_buf_error.dat":"254f280f8f1e8914bd12d8bcd3813e5c08083b1b46d8d643c8e2ebe109e75cb8","src/deflate/test-data/lcet10.txt":"1eb5d7bddb1c3cb68064d5b5f7f27814949674b6702564ff7025ced60795a6d9","src/deflate/test-data/paper-100k.pdf":"60f73a051b7ca35bfec44734b2eed7736cb5c0b7f728beb7b97ade6c5e44849b","src/deflate/test-data/read_buf_window_uninitialized.txt":"88dcffb0155e55464871bf98c66dd008e61ba8c49d12c9efd103c5d081255c48","src/deflate/test-data/zlib-ng/CVE-2018-25032/default.txt":"d7f8278db331c47bd1208bf41e7903cbddee4f7b47c666c40afdd3c96237752e","src/deflate/test-data/zlib-ng/CVE-2018-25032/fixed.txt":"3b27a98edd2f3f580033f9add11d3469d7808c969a1128ee00c18ac7a12cef57","src/deflate/test-data/zlib-ng/GH-382/defneg3.dat":"b22bef6b7392401c9e7b079402c4a4074053d7a914d050400e37fd7af6fe26d5","src/deflate/trees_tbl.rs":"503c65c7648405619a95dc9f5a52ecd558e439e870c116f61ef94128c6a4c52e","src/deflate/window.rs":"6b9680a0250fd950118d56f50ced6cc174487f5f1c6f05652b39df65557ab059","src/inflate.rs":"cdd1ecc5a6eb3a277281723c9938cddb325b467b719eada8670344af1bdccbf9","src/inflate/bitreader.rs":"1161043209b7949ccf7700b7187bc90370003dd0872bbf3bd344f11db40e31bc","src/inflate/inffixed_tbl.rs":"eb1ed1927ca07b61fe30ae8461ce62e7da28c595416e687a26db57c8eac8f4a1","src/inflate/inftrees.rs":"44efb568c9cc2dbbc6c51e50f3cc38d6c8e896b93936f47b3879396fc814abfe","src/inflate/window.rs":"8b175bdba8c7f7cd346a4ab408f0218c84ae177f32f2ac581872064269677423","src/lib.rs":"61d5837f5695f81ca78dfc5e2f8afe3f40086a5a50b555f76ebe10fe387fdcf9","src/read_buf.rs":"33d03bb0a8250393879e1b9ff4835bfe405b5941a88c809a2f11d461b897ab38"},"package":null}

63
third_party/rust/zlib-rs/Cargo.toml vendored Normal file
View File

@ -0,0 +1,63 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.75"
name = "zlib-rs"
version = "0.2.1"
publish = true
description = "A memory-safe zlib implementation written in rust"
homepage = "https://github.com/memorysafety/zlib-rs"
readme = "README.md"
license = "Zlib"
repository = "https://github.com/memorysafety/zlib-rs"
[dependencies.arbitrary]
version = "1.0"
features = ["derive"]
optional = true
[dependencies.libz-sys]
version = "1.1.12"
features = ["zlib-ng"]
optional = true
default-features = false
[dependencies.quickcheck]
version = "1.0.3"
features = []
optional = true
default-features = false
[dev-dependencies]
crc32fast = "1.3.2"
libloading = "0.8.1"
libz-ng-sys = "1.1.12"
[dev-dependencies.dynamic-libz-sys]
path = "../dynamic-libz-sys"
[dev-dependencies.quickcheck]
version = "1.0.3"
features = []
default-features = false
[features]
__internal-fuzz = ["arbitrary"]
__internal-test = ["quickcheck"]
c-allocator = []
default = [
"std",
"c-allocator",
]
rust-allocator = []
std = ["rust-allocator"]

19
third_party/rust/zlib-rs/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
(C) 2024 Internet Security Research Group
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

6
third_party/rust/zlib-rs/README.md vendored Normal file
View File

@ -0,0 +1,6 @@
# ⚠️ UNSTABLE⚠
_the public interface of this crate is unstable!_
A pure-rust implementation of [zlib](https://www.zlib.net/manual.html).
For a [zlib](https://www.zlib.net/manual.html) -compatible rust api of this crate, see [`libz-rs-sys`](https://crates.io/crates/libz-rs-sys). For a more high-level interface, use [`flate2`](https://crates.io/crates/flate2).

133
third_party/rust/zlib-rs/src/adler32.rs vendored Normal file
View File

@ -0,0 +1,133 @@
use core::mem::MaybeUninit;
#[cfg(target_arch = "x86_64")]
mod avx2;
mod generic;
#[cfg(target_arch = "aarch64")]
mod neon;
pub fn adler32(start_checksum: u32, data: &[u8]) -> u32 {
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("avx2") {
return avx2::adler32_avx2(start_checksum, data);
}
#[cfg(all(target_arch = "aarch64", feature = "std"))]
if std::arch::is_aarch64_feature_detected!("neon") {
return self::neon::adler32_neon(start_checksum, data);
}
generic::adler32_rust(start_checksum, data)
}
pub fn adler32_fold_copy(start_checksum: u32, dst: &mut [MaybeUninit<u8>], src: &[u8]) -> u32 {
debug_assert!(dst.len() >= src.len(), "{} < {}", dst.len(), src.len());
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("avx2") {
return avx2::adler32_fold_copy_avx2(start_checksum, dst, src);
}
let adler = adler32(start_checksum, src);
dst[..src.len()].copy_from_slice(slice_to_uninit(src));
adler
}
pub fn adler32_combine(adler1: u32, adler2: u32, len2: u64) -> u32 {
const BASE: u64 = self::BASE as u64;
let rem = len2 % BASE;
let adler1 = adler1 as u64;
let adler2 = adler2 as u64;
/* the derivation of this formula is left as an exercise for the reader */
let mut sum1 = adler1 & 0xffff;
let mut sum2 = rem * sum1;
sum2 %= BASE;
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if sum1 >= BASE {
sum1 -= BASE;
}
if sum1 >= BASE {
sum1 -= BASE;
}
if sum2 >= (BASE << 1) {
sum2 -= BASE << 1;
}
if sum2 >= BASE {
sum2 -= BASE;
}
(sum1 | (sum2 << 16)) as u32
}
// when stable, use MaybeUninit::write_slice
fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit<u8>] {
// safety: &[T] and &[MaybeUninit<T>] have the same layout
unsafe { &*(slice as *const [u8] as *const [MaybeUninit<u8>]) }
}
// inefficient but correct, useful for testing
#[cfg(test)]
fn naive_adler32(start_checksum: u32, data: &[u8]) -> u32 {
const MOD_ADLER: u32 = 65521; // Largest prime smaller than 2^16
let mut a = start_checksum & 0xFFFF;
let mut b = (start_checksum >> 16) & 0xFFFF;
for &byte in data {
a = (a + byte as u32) % MOD_ADLER;
b = (b + a) % MOD_ADLER;
}
(b << 16) | a
}
const BASE: u32 = 65521; /* largest prime smaller than 65536 */
const NMAX: u32 = 5552;
#[cfg(test)]
mod test {
use super::*;
#[test]
fn naive_is_fancy_small_inputs() {
for i in 0..128 {
let v = (0u8..i).collect::<Vec<_>>();
assert_eq!(naive_adler32(1, &v), generic::adler32_rust(1, &v));
}
}
#[test]
fn test_adler32_combine() {
::quickcheck::quickcheck(test as fn(_) -> _);
fn test(data: Vec<u8>) -> bool {
let Some(buf_len) = data.first().copied() else {
return true;
};
let buf_size = Ord::max(buf_len, 1) as usize;
let mut adler1 = 1;
let mut adler2 = 1;
for chunk in data.chunks(buf_size) {
adler1 = adler32(adler1, chunk);
}
adler2 = adler32(adler2, &data);
assert_eq!(adler1, adler2);
let combine1 = adler32_combine(adler1, adler2, data.len() as _);
let combine2 = adler32_combine(adler1, adler1, data.len() as _);
assert_eq!(combine1, combine2);
true
}
}
}

View File

@ -0,0 +1,258 @@
use core::{
arch::x86_64::{
__m256i, _mm256_add_epi32, _mm256_castsi256_si128, _mm256_extracti128_si256,
_mm256_madd_epi16, _mm256_maddubs_epi16, _mm256_permutevar8x32_epi32, _mm256_sad_epu8,
_mm256_slli_epi32, _mm256_storeu_si256, _mm256_zextsi128_si256, _mm_add_epi32,
_mm_cvtsi128_si32, _mm_cvtsi32_si128, _mm_shuffle_epi32, _mm_unpackhi_epi64,
},
mem::MaybeUninit,
};
use crate::adler32::{
generic::{adler32_copy_len_16, adler32_len_16, adler32_len_64},
BASE, NMAX,
};
const fn __m256i_literal(bytes: [u8; 32]) -> __m256i {
unsafe { core::mem::transmute(bytes) }
}
const DOT2V: __m256i = __m256i_literal([
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9,
8, 7, 6, 5, 4, 3, 2, 1,
]);
const DOT3V: __m256i = __m256i_literal([
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
]);
const ZERO: __m256i = __m256i_literal([0; 32]);
// 32 bit horizontal sum, adapted from Agner Fog's vector library.
#[target_feature(enable = "avx2")]
unsafe fn hsum256(x: __m256i) -> u32 {
unsafe {
let sum1 = _mm_add_epi32(_mm256_extracti128_si256(x, 1), _mm256_castsi256_si128(x));
let sum2 = _mm_add_epi32(sum1, _mm_unpackhi_epi64(sum1, sum1));
let sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1));
_mm_cvtsi128_si32(sum3) as u32
}
}
#[target_feature(enable = "avx2")]
unsafe fn partial_hsum256(x: __m256i) -> u32 {
const PERM_VEC: __m256i = __m256i_literal([
0, 0, 0, 0, //
2, 0, 0, 0, //
4, 0, 0, 0, //
6, 0, 0, 0, //
1, 0, 0, 0, //
1, 0, 0, 0, //
1, 0, 0, 0, //
1, 0, 0, 0, //
]);
unsafe {
let non_zero = _mm256_permutevar8x32_epi32(x, PERM_VEC);
let non_zero_sse = _mm256_castsi256_si128(non_zero);
let sum2 = _mm_add_epi32(non_zero_sse, _mm_unpackhi_epi64(non_zero_sse, non_zero_sse));
let sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1));
_mm_cvtsi128_si32(sum3) as u32
}
}
pub fn adler32_avx2(adler: u32, src: &[u8]) -> u32 {
assert!(std::is_x86_feature_detected!("avx2"));
unsafe { adler32_avx2_help::<false>(adler, &mut [], src) }
}
pub fn adler32_fold_copy_avx2(adler: u32, dst: &mut [MaybeUninit<u8>], src: &[u8]) -> u32 {
assert!(std::is_x86_feature_detected!("avx2"));
unsafe { adler32_avx2_help::<true>(adler, dst, src) }
}
#[target_feature(enable = "avx2")]
unsafe fn adler32_avx2_help<const COPY: bool>(
adler: u32,
mut dst: &mut [MaybeUninit<u8>],
src: &[u8],
) -> u32 {
if src.is_empty() {
return adler;
}
let (before, middle, after) = unsafe { src.align_to::<__m256i>() };
let mut adler1 = (adler >> 16) & 0xffff;
let mut adler0 = adler & 0xffff;
let adler = if before.len() < 16 {
if COPY {
let adler = adler32_copy_len_16(adler0, dst, before, adler1);
dst = &mut dst[before.len()..];
adler
} else {
adler32_len_16(adler0, before, adler1)
}
} else if before.len() < 32 {
if COPY {
let adler = adler32_copy_len_16(adler0, dst, before, adler1);
dst = &mut dst[before.len()..];
adler
} else {
adler32_len_64(adler0, before, adler1)
}
} else {
adler
};
adler1 = (adler >> 16) & 0xffff;
adler0 = adler & 0xffff;
// use largest step possible (without causing overflow)
for chunk in middle.chunks(NMAX as usize / 32) {
(adler0, adler1) = unsafe { helper_32_bytes::<COPY>(adler0, adler1, dst, chunk) };
if COPY {
dst = &mut dst[32 * chunk.len()..];
}
}
if !after.is_empty() {
if after.len() < 16 {
if COPY {
return adler32_copy_len_16(adler0, dst, after, adler1);
} else {
return adler32_len_16(adler0, after, adler1);
}
} else if after.len() < 32 {
if COPY {
return adler32_copy_len_16(adler0, dst, after, adler1);
} else {
return adler32_len_64(adler0, after, adler1);
}
} else {
unreachable!()
}
}
adler0 | (adler1 << 16)
}
#[target_feature(enable = "avx2")]
unsafe fn helper_32_bytes<const COPY: bool>(
mut adler0: u32,
mut adler1: u32,
dst: &mut [MaybeUninit<u8>],
src: &[__m256i],
) -> (u32, u32) {
let mut vs1 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler0 as i32));
let mut vs2 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler1 as i32));
let mut vs1_0 = vs1;
let mut vs3 = ZERO;
let mut out_chunks = dst.chunks_exact_mut(32);
for vbuf in src.iter().copied() {
if COPY {
let out_chunk = out_chunks.next().unwrap();
_mm256_storeu_si256(out_chunk.as_mut_ptr() as *mut __m256i, vbuf);
}
let vs1_sad = _mm256_sad_epu8(vbuf, ZERO); // Sum of abs diff, resulting in 2 x int32's
vs1 = _mm256_add_epi32(vs1, vs1_sad);
vs3 = _mm256_add_epi32(vs3, vs1_0);
let v_short_sum2 = _mm256_maddubs_epi16(vbuf, DOT2V); // sum 32 uint8s to 16 shorts
let vsum2 = _mm256_madd_epi16(v_short_sum2, DOT3V); // sum 16 shorts to 8 uint32s
vs2 = _mm256_add_epi32(vsum2, vs2);
vs1_0 = vs1;
}
/* Defer the multiplication with 32 to outside of the loop */
vs3 = _mm256_slli_epi32(vs3, 5);
vs2 = _mm256_add_epi32(vs2, vs3);
adler0 = partial_hsum256(vs1) % BASE;
adler1 = hsum256(vs2) % BASE;
(adler0, adler1)
}
#[cfg(test)]
#[cfg(target_feature = "avx2")]
mod test {
use super::*;
#[test]
fn empty_input() {
let avx2 = adler32_avx2(0, &[]);
let rust = crate::adler32::generic::adler32_rust(0, &[]);
assert_eq!(rust, avx2);
}
quickcheck::quickcheck! {
fn adler32_avx2_is_adler32_rust(v: Vec<u8>, start: u32) -> bool {
let avx2 = adler32_avx2(start, &v);
let rust = crate::adler32::generic::adler32_rust(start, &v);
rust == avx2
}
}
const INPUT: [u8; 1024] = {
let mut array = [0; 1024];
let mut i = 0;
while i < array.len() {
array[i] = i as u8;
i += 1;
}
array
};
#[test]
fn start_alignment() {
// SIMD algorithm is sensitive to alignment;
for i in 0..16 {
for start in [crate::ADLER32_INITIAL_VALUE as u32, 42] {
let avx2 = adler32_avx2(start, &INPUT[i..]);
let rust = crate::adler32::generic::adler32_rust(start, &INPUT[i..]);
assert_eq!(avx2, rust, "offset = {i}, start = {start}");
}
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn large_input() {
const DEFAULT: &str =
include_str!("../deflate/test-data/zlib-ng/CVE-2018-25032/default.txt");
let avx2 = adler32_avx2(42, DEFAULT.as_bytes());
let rust = crate::adler32::generic::adler32_rust(42, DEFAULT.as_bytes());
assert_eq!(avx2, rust);
}
// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable.
unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
&*(slice as *const [MaybeUninit<u8>] as *const [u8])
}
#[test]
fn fold_copy_copies() {
let src: Vec<_> = (0..128).map(|x| x as u8).collect();
let mut dst = [MaybeUninit::new(0); 128];
for (i, _) in src.iter().enumerate() {
dst.fill(MaybeUninit::new(0));
adler32_fold_copy_avx2(1, &mut dst[..i], &src[..i]);
assert_eq!(&src[..i], unsafe { slice_assume_init(&dst[..i]) })
}
}
}

View File

@ -0,0 +1,136 @@
use core::mem::MaybeUninit;
use super::{BASE, NMAX};
const UNROLL_MORE: bool = true;
// macros for loop unrolling
macro_rules! do1 {
($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => {
$sum1 += unsafe { *$chunk.get_unchecked($i) } as u32;
$sum2 += $sum1;
};
}
macro_rules! do2 {
($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => {
do1!($sum1, $sum2, $chunk, $i);
do1!($sum1, $sum2, $chunk, $i + 1);
};
}
macro_rules! do4 {
($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => {
do2!($sum1, $sum2, $chunk, $i);
do2!($sum1, $sum2, $chunk, $i + 2);
};
}
macro_rules! do8 {
($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => {
do4!($sum1, $sum2, $chunk, $i);
do4!($sum1, $sum2, $chunk, $i + 4);
};
}
macro_rules! do16 {
($sum1:expr, $sum2:expr, $chunk:expr) => {
do8!($sum1, $sum2, $chunk, 0);
do8!($sum1, $sum2, $chunk, 8);
};
}
pub fn adler32_rust(mut adler: u32, buf: &[u8]) -> u32 {
/* split Adler-32 into component sums */
let mut sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if buf.len() == 1 {
return adler32_len_1(adler, buf, sum2);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if buf.is_empty() {
return adler | (sum2 << 16);
}
/* in case short lengths are provided, keep it somewhat fast */
if buf.len() < 16 {
return adler32_len_16(adler, buf, sum2);
}
let mut it = buf.chunks_exact(NMAX as usize);
for big_chunk in it.by_ref() {
const N: usize = if UNROLL_MORE { 16 } else { 8 } as usize;
let it = big_chunk.chunks_exact(N);
for chunk in it {
if N == 16 {
do16!(adler, sum2, chunk);
} else {
do8!(adler, sum2, chunk, 0);
}
}
adler %= BASE;
sum2 %= BASE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
return adler32_len_64(adler, it.remainder(), sum2);
}
pub(crate) fn adler32_len_1(mut adler: u32, buf: &[u8], mut sum2: u32) -> u32 {
adler += buf[0] as u32;
adler %= BASE;
sum2 += adler;
sum2 %= BASE;
adler | (sum2 << 16)
}
pub(crate) fn adler32_len_16(mut adler: u32, buf: &[u8], mut sum2: u32) -> u32 {
for b in buf {
adler += (*b) as u32;
sum2 += adler;
}
adler %= BASE;
sum2 %= BASE; /* only added so many BASE's */
/* return recombined sums */
adler | (sum2 << 16)
}
#[cfg_attr(not(target_arch = "x86_64"), allow(unused))]
pub(crate) fn adler32_copy_len_16(
mut adler: u32,
dst: &mut [MaybeUninit<u8>],
src: &[u8],
mut sum2: u32,
) -> u32 {
for (source, destination) in src.iter().zip(dst.iter_mut()) {
let v = *source;
*destination = MaybeUninit::new(v);
adler += v as u32;
sum2 += adler;
}
adler %= BASE;
sum2 %= BASE; /* only added so many BASE's */
/* return recombined sums */
adler | (sum2 << 16)
}
pub(crate) fn adler32_len_64(mut adler: u32, buf: &[u8], mut sum2: u32) -> u32 {
const N: usize = if UNROLL_MORE { 16 } else { 8 };
let mut it = buf.chunks_exact(N);
for chunk in it.by_ref() {
if N == 16 {
do16!(adler, sum2, chunk);
} else {
do8!(adler, sum2, chunk, 0);
}
}
/* Process tail (len < 16). */
adler32_len_16(adler, it.remainder(), sum2)
}

View File

@ -0,0 +1,243 @@
use core::arch::aarch64::{
uint16x8_t, uint16x8x2_t, uint16x8x4_t, uint8x16_t, vaddq_u32, vaddw_high_u8, vaddw_u8,
vdupq_n_u16, vdupq_n_u32, vget_high_u32, vget_lane_u32, vget_low_u16, vget_low_u32,
vget_low_u8, vld1q_u8_x4, vmlal_high_u16, vmlal_u16, vpadalq_u16, vpadalq_u8, vpadd_u32,
vpaddlq_u8, vsetq_lane_u32, vshlq_n_u32,
};
use crate::adler32::{
generic::{adler32_len_1, adler32_len_16},
BASE, NMAX,
};
const TAPS: [uint16x8x4_t; 2] = unsafe {
core::mem::transmute::<[u16; 64], [uint16x8x4_t; 2]>([
64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42,
41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
])
};
pub fn adler32_neon(adler: u32, buf: &[u8]) -> u32 {
assert!(std::arch::is_aarch64_feature_detected!("neon"));
unsafe { adler32_neon_internal(adler, buf) }
}
#[target_feature(enable = "neon")]
unsafe fn adler32_neon_internal(mut adler: u32, buf: &[u8]) -> u32 {
/* split Adler-32 into component sums */
let sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if buf.len() == 1 {
return adler32_len_1(adler, buf, sum2);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if buf.is_empty() {
return adler | (sum2 << 16);
}
/* in case short lengths are provided, keep it somewhat fast */
if buf.len() < 16 {
return adler32_len_16(adler, buf, sum2);
}
// Split Adler-32 into component sums, it can be supplied by the caller sites (e.g. in a PNG file).
let mut pair = (adler, sum2);
// If memory is not SIMD aligned, do scalar sums to an aligned
// offset, provided that doing so doesn't completely eliminate
// SIMD operation. Aligned loads are still faster on ARM, even
// though there's no explicit aligned load instruction
const _: () = assert!(core::mem::align_of::<uint8x16_t>() == 16);
let (before, middle, after) = unsafe { buf.align_to::<uint8x16_t>() };
pair = handle_tail(pair, before);
for chunk in middle.chunks(NMAX as usize / core::mem::size_of::<uint8x16_t>()) {
pair = unsafe { accum32(pair, chunk) };
pair.0 %= BASE;
pair.1 %= BASE;
}
if !after.is_empty() {
pair = handle_tail(pair, after);
pair.0 %= BASE;
pair.1 %= BASE;
}
// D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32.
(pair.1 << 16) | pair.0
}
fn handle_tail(mut pair: (u32, u32), buf: &[u8]) -> (u32, u32) {
for x in buf {
pair.0 += *x as u32;
pair.1 += pair.0;
}
pair
}
#[target_feature(enable = "neon")]
unsafe fn accum32(s: (u32, u32), buf: &[uint8x16_t]) -> (u32, u32) {
let mut adacc = vdupq_n_u32(0);
let mut s2acc = vdupq_n_u32(0);
adacc = vsetq_lane_u32(s.0, adacc, 0);
s2acc = vsetq_lane_u32(s.1, s2acc, 0);
let mut s3acc = vdupq_n_u32(0);
let mut adacc_prev = adacc;
let mut s2_0 = vdupq_n_u16(0);
let mut s2_1 = vdupq_n_u16(0);
let mut s2_2 = vdupq_n_u16(0);
let mut s2_3 = vdupq_n_u16(0);
let mut s2_4 = vdupq_n_u16(0);
let mut s2_5 = vdupq_n_u16(0);
let mut s2_6 = vdupq_n_u16(0);
let mut s2_7 = vdupq_n_u16(0);
let mut it = buf.chunks_exact(4);
for chunk in &mut it {
let d0_d3 = vld1q_u8_x4(chunk.as_ptr() as *const u8);
// Unfortunately it doesn't look like there's a direct sum 8 bit to 32
// bit instruction, we'll have to make due summing to 16 bits first
let hsum = uint16x8x2_t(vpaddlq_u8(d0_d3.0), vpaddlq_u8(d0_d3.1));
let hsum_fold = uint16x8x2_t(vpadalq_u8(hsum.0, d0_d3.2), vpadalq_u8(hsum.1, d0_d3.3));
adacc = vpadalq_u16(adacc, hsum_fold.0);
s3acc = vaddq_u32(s3acc, adacc_prev);
adacc = vpadalq_u16(adacc, hsum_fold.1);
// If we do straight widening additions to the 16 bit values, we don't incur
// the usual penalties of a pairwise add. We can defer the multiplications
// until the very end. These will not overflow because we are incurring at
// most 408 loop iterations (NMAX / 64), and a given lane is only going to be
// summed into once. This means for the maximum input size, the largest value
// we will see is 255 * 102 = 26010, safely under uint16 max
s2_0 = vaddw_u8(s2_0, vget_low_u8(d0_d3.0));
s2_1 = vaddw_high_u8(s2_1, d0_d3.0);
s2_2 = vaddw_u8(s2_2, vget_low_u8(d0_d3.1));
s2_3 = vaddw_high_u8(s2_3, d0_d3.1);
s2_4 = vaddw_u8(s2_4, vget_low_u8(d0_d3.2));
s2_5 = vaddw_high_u8(s2_5, d0_d3.2);
s2_6 = vaddw_u8(s2_6, vget_low_u8(d0_d3.3));
s2_7 = vaddw_high_u8(s2_7, d0_d3.3);
adacc_prev = adacc;
}
s3acc = vshlq_n_u32(s3acc, 6);
let remainder = it.remainder();
if !remainder.is_empty() {
let mut s3acc_0 = vdupq_n_u32(0);
for d0 in remainder.iter().copied() {
let adler: uint16x8_t = vpaddlq_u8(d0);
s2_6 = vaddw_u8(s2_6, vget_low_u8(d0));
s2_7 = vaddw_high_u8(s2_7, d0);
adacc = vpadalq_u16(adacc, adler);
s3acc_0 = vaddq_u32(s3acc_0, adacc_prev);
adacc_prev = adacc;
}
s3acc_0 = vshlq_n_u32(s3acc_0, 4);
s3acc = vaddq_u32(s3acc_0, s3acc);
}
let t0_t3 = TAPS[0];
let t4_t7 = TAPS[1];
let mut s2acc_0 = vdupq_n_u32(0);
let mut s2acc_1 = vdupq_n_u32(0);
let mut s2acc_2 = vdupq_n_u32(0);
s2acc = vmlal_high_u16(s2acc, t0_t3.0, s2_0);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.0), vget_low_u16(s2_0));
s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.1, s2_1);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.1), vget_low_u16(s2_1));
s2acc = vmlal_high_u16(s2acc, t0_t3.2, s2_2);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.2), vget_low_u16(s2_2));
s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.3, s2_3);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.3), vget_low_u16(s2_3));
s2acc = vmlal_high_u16(s2acc, t4_t7.0, s2_4);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.0), vget_low_u16(s2_4));
s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.1, s2_5);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.1), vget_low_u16(s2_5));
s2acc = vmlal_high_u16(s2acc, t4_t7.2, s2_6);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.2), vget_low_u16(s2_6));
s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.3, s2_7);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.3), vget_low_u16(s2_7));
s2acc = vaddq_u32(s2acc_0, s2acc);
s2acc_2 = vaddq_u32(s2acc_1, s2acc_2);
s2acc = vaddq_u32(s2acc, s2acc_2);
let s2acc = vaddq_u32(s2acc, s3acc);
let adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc));
let s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc));
let as_ = vpadd_u32(adacc2, s2acc2);
(vget_lane_u32(as_, 0), vget_lane_u32(as_, 1))
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck::quickcheck! {
fn adler32_neon_is_adler32_rust(v: Vec<u8>, start: u32) -> bool {
let neon = adler32_neon(start, &v);
let rust = crate::adler32::generic::adler32_rust(start, &v);
rust == neon
}
}
const INPUT: [u8; 1024] = {
let mut array = [0; 1024];
let mut i = 0;
while i < array.len() {
array[i] = i as u8;
i += 1;
}
array
};
#[test]
fn start_alignment() {
// SIMD algorithm is sensitive to alignment;
for i in 0..16 {
for start in [crate::ADLER32_INITIAL_VALUE as u32, 42] {
let neon = adler32_neon(start, &INPUT[i..]);
let rust = crate::adler32::generic::adler32_rust(start, &INPUT[i..]);
assert_eq!(neon, rust, "offset = {i}, start = {start}");
}
}
}
#[test]
fn large_input() {
const DEFAULT: &str =
include_str!("../deflate/test-data/zlib-ng/CVE-2018-25032/default.txt");
let neon = adler32_neon(42, &DEFAULT.as_bytes());
let rust = crate::adler32::generic::adler32_rust(42, &DEFAULT.as_bytes());
assert_eq!(neon, rust);
}
}

357
third_party/rust/zlib-rs/src/allocate.rs vendored Normal file
View File

@ -0,0 +1,357 @@
use core::ffi::c_int;
use core::{
alloc::Layout,
ffi::{c_uint, c_void},
marker::PhantomData,
mem::MaybeUninit,
};
#[cfg(feature = "rust-allocator")]
use alloc::alloc::GlobalAlloc;
#[allow(non_camel_case_types)]
type size_t = usize;
/// # Safety
///
/// This function is safe, but must have this type signature to be used elsewhere in the library
#[cfg(unix)]
pub unsafe extern "C" fn zalloc_c(opaque: *mut c_void, items: c_uint, size: c_uint) -> *mut c_void {
let _ = opaque;
extern "C" {
fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int;
}
let mut ptr = core::ptr::null_mut();
match posix_memalign(&mut ptr, 64, items as size_t * size as size_t) {
0 => ptr,
_ => core::ptr::null_mut(),
}
}
/// # Safety
///
/// This function is safe, but must have this type signature to be used elsewhere in the library
#[cfg(not(unix))]
pub unsafe extern "C" fn zalloc_c(opaque: *mut c_void, items: c_uint, size: c_uint) -> *mut c_void {
let _ = opaque;
extern "C" {
fn malloc(size: size_t) -> *mut c_void;
}
malloc(items as size_t * size as size_t)
}
/// # Safety
///
/// The `ptr` must be allocated with the allocator that is used internally by `zcfree`
pub unsafe extern "C" fn zfree_c(opaque: *mut c_void, ptr: *mut c_void) {
let _ = opaque;
extern "C" {
fn free(p: *mut c_void);
}
unsafe { free(ptr) }
}
/// # Safety
///
/// This function is safe to call.
#[cfg(feature = "rust-allocator")]
pub unsafe extern "C" fn zalloc_rust(
_opaque: *mut c_void,
count: c_uint,
size: c_uint,
) -> *mut c_void {
let align = 64;
let size = count as usize * size as usize;
// internally, we want to align allocations to 64 bytes (in part for SIMD reasons)
let layout = Layout::from_size_align(size, align).unwrap();
let ptr = std::alloc::System.alloc(layout);
ptr as *mut c_void
}
/// # Safety
///
/// - `ptr` must be allocated with the rust `alloc::System` allocator
/// - `opaque` is a `&usize` that represents the size of the allocation
#[cfg(feature = "rust-allocator")]
pub unsafe extern "C" fn zfree_rust(opaque: *mut c_void, ptr: *mut c_void) {
if ptr.is_null() {
return;
}
// we can't really do much else. Deallocating with an invalid layout is UB.
debug_assert!(!opaque.is_null());
if opaque.is_null() {
return;
}
let size = *(opaque as *mut usize);
let align = 64;
let layout = Layout::from_size_align(size, align);
let layout = layout.unwrap();
std::alloc::System.dealloc(ptr.cast(), layout);
}
#[derive(Clone, Copy)]
#[repr(C)]
pub(crate) struct Allocator<'a> {
pub(crate) zalloc: crate::c_api::alloc_func,
pub(crate) zfree: crate::c_api::free_func,
pub(crate) opaque: crate::c_api::voidpf,
pub(crate) _marker: PhantomData<&'a ()>,
}
impl Allocator<'static> {
#[cfg(feature = "rust-allocator")]
pub const RUST: Self = Self {
zalloc: zalloc_rust,
zfree: zfree_rust,
opaque: core::ptr::null_mut(),
_marker: PhantomData,
};
#[cfg(feature = "c-allocator")]
pub const C: Self = Self {
zalloc: zalloc_c,
zfree: zfree_c,
opaque: core::ptr::null_mut(),
_marker: PhantomData,
};
}
impl<'a> Allocator<'a> {
pub fn allocate_layout(&self, layout: Layout) -> *mut c_void {
// Special case for the Rust `alloc` backed allocator
#[cfg(feature = "rust-allocator")]
if self.zalloc == Allocator::RUST.zalloc {
let ptr = unsafe { (Allocator::RUST.zalloc)(self.opaque, layout.size() as _, 1) };
debug_assert_eq!(ptr as usize % layout.align(), 0);
return ptr;
}
// General case for c-style allocation
// We cannot rely on the allocator giving properly aligned allocations and have to fix that ourselves.
//
// The general approach is to allocate a bit more than the layout needs, so that we can
// give the application a properly aligned address and also store the real allocation
// pointer in the allocation so that `free` can free the real allocation pointer.
//
//
// Example: The layout represents `(u32, u32)`, with an alignment of 4 bytes and a
// total size of 8 bytes.
//
// Assume that the allocator will give us address `0x07`. We need that to be a multiple
// of the alignment, so that shifts the starting position to `0x08`. Then we also need
// to store the pointer to the start of the allocation so that `free` can free that
// pointer, bumping to `0x10`. The `0x10` pointer is then the pointer that the application
// deals with. When free'ing, the original allocation pointer can be read from `0x10 - size_of::<*const c_void>()`.
//
// Of course there does need to be enough space in the allocation such that when we
// shift the start forwards, the end is still within the allocation. Hence we allocate
// `extra_space` bytes: enough for a full alignment plus a pointer.
// we need at least
//
// - `align` extra space so that no matter what pointer we get from zalloc, we can shift the start of the
// allocation by at most `align - 1` so that `ptr as usize % align == 0
// - `size_of::<*mut _>` extra space so that after aligning to `align`,
// there is `size_of::<*mut _>` space to store the pointer to the allocation.
// This pointer is then retrieved in `free`
let extra_space = core::mem::size_of::<*mut c_void>() + layout.align();
// Safety: we assume allocating works correctly in the safety assumptions on
// `DeflateStream` and `InflateStream`.
let ptr = unsafe { (self.zalloc)(self.opaque, (layout.size() + extra_space) as _, 1) };
if ptr.is_null() {
return ptr;
}
// Calculate return pointer address with space enough to store original pointer
let align_diff = (ptr as usize).next_multiple_of(layout.align()) - (ptr as usize);
// Safety: offset is smaller than 64, and we allocated 64 extra bytes in the allocation
let mut return_ptr = unsafe { ptr.cast::<u8>().add(align_diff) };
// if there is not enough space to store a pointer we need to make more
if align_diff < core::mem::size_of::<*mut c_void>() {
// # Safety
//
// - `return_ptr` is well-aligned, therefore `return_ptr + align` is also well-aligned
// - we reserve `size_of::<*mut _> + align` extra space in the allocation, so
// `ptr + align_diff + align` is still valid for (at least) `layout.size` bytes
let offset = Ord::max(core::mem::size_of::<*mut c_void>(), layout.align());
return_ptr = unsafe { return_ptr.add(offset) };
}
// Store the original pointer for free()
//
// Safety: `align >= size_of::<*mut _>`, so there is now space for a pointer before `return_ptr`
// in the allocation
unsafe {
let original_ptr = return_ptr.sub(core::mem::size_of::<*mut c_void>());
core::ptr::write_unaligned(original_ptr.cast::<*mut c_void>(), ptr);
};
// Return properly aligned pointer in allocation
let ptr = return_ptr.cast::<c_void>();
debug_assert_eq!(ptr as usize % layout.align(), 0);
ptr
}
pub fn allocate<T>(&self) -> Option<&'a mut MaybeUninit<T>> {
let ptr = self.allocate_layout(Layout::new::<T>());
if ptr.is_null() {
None
} else {
Some(unsafe { &mut *(ptr as *mut MaybeUninit<T>) })
}
}
pub fn allocate_slice<T>(&self, len: usize) -> Option<&'a mut [MaybeUninit<T>]> {
let ptr = self.allocate_layout(Layout::array::<T>(len).ok()?);
if ptr.is_null() {
None
} else {
Some(unsafe { core::slice::from_raw_parts_mut(ptr.cast(), len) })
}
}
/// # Panics
///
/// - when `len` is 0
///
/// # Safety
///
/// - `ptr` must be allocated with this allocator
/// - `len` must be the number of `T`s that are in this allocation
#[allow(unused)] // Rust needs `len` for deallocation
pub unsafe fn deallocate<T>(&self, ptr: *mut T, len: usize) {
if !ptr.is_null() {
// Special case for the Rust `alloc` backed allocator
#[cfg(feature = "rust-allocator")]
if self.zfree == Allocator::RUST.zfree {
assert_ne!(len, 0, "invalid size for {:?}", ptr);
let mut size = core::mem::size_of::<T>() * len;
return (Allocator::RUST.zfree)(&mut size as *mut usize as *mut c_void, ptr.cast());
}
// General case for c-style allocation
let original_ptr = (ptr as *mut u8).sub(core::mem::size_of::<*const c_void>());
let free_ptr = core::ptr::read_unaligned(original_ptr as *mut *mut c_void);
(self.zfree)(self.opaque, free_ptr)
}
}
}
#[cfg(test)]
mod tests {
use core::sync::atomic::{AtomicPtr, Ordering};
use std::sync::Mutex;
use super::*;
static PTR: AtomicPtr<c_void> = AtomicPtr::new(core::ptr::null_mut());
static MUTEX: Mutex<()> = Mutex::new(());
unsafe extern "C" fn unaligned_alloc(
_opaque: *mut c_void,
_items: c_uint,
_size: c_uint,
) -> *mut c_void {
PTR.load(Ordering::Relaxed)
}
unsafe extern "C" fn unaligned_free(_opaque: *mut c_void, ptr: *mut c_void) {
let expected = PTR.load(Ordering::Relaxed);
assert_eq!(expected, ptr)
}
fn unaligned_allocator_help<T>() {
let mut buf = [0u8; 1024];
// we don't want anyone else messing with the PTR static
let _guard = MUTEX.lock().unwrap();
for i in 0..64 {
let ptr = unsafe { buf.as_mut_ptr().add(i).cast() };
PTR.store(ptr, Ordering::Relaxed);
let allocator = Allocator {
zalloc: unaligned_alloc,
zfree: unaligned_free,
opaque: core::ptr::null_mut(),
_marker: PhantomData,
};
let ptr = allocator.allocate::<T>().unwrap();
assert_eq!(ptr.as_ptr() as usize % core::mem::align_of::<T>(), 0);
unsafe { allocator.deallocate(ptr, 1) }
let ptr = allocator.allocate_slice::<T>(10).unwrap();
assert_eq!(ptr.as_ptr() as usize % core::mem::align_of::<T>(), 0);
unsafe { allocator.deallocate(ptr.as_mut_ptr(), 10) }
}
}
#[test]
fn unaligned_allocator_0() {
unaligned_allocator_help::<()>()
}
#[test]
fn unaligned_allocator_1() {
unaligned_allocator_help::<u8>()
}
#[test]
fn unaligned_allocator_2() {
unaligned_allocator_help::<u16>()
}
#[test]
fn unaligned_allocator_4() {
unaligned_allocator_help::<u32>()
}
#[test]
fn unaligned_allocator_8() {
unaligned_allocator_help::<u64>()
}
#[test]
fn unaligned_allocator_16() {
unaligned_allocator_help::<u128>()
}
#[test]
fn unaligned_allocator_32() {
#[repr(C, align(32))]
struct Align32(u8);
unaligned_allocator_help::<Align32>()
}
#[test]
fn unaligned_allocator_64() {
#[repr(C, align(64))]
struct Align64(u8);
unaligned_allocator_help::<Align64>()
}
}

228
third_party/rust/zlib-rs/src/c_api.rs vendored Normal file
View File

@ -0,0 +1,228 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use core::ffi::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void};
use crate::allocate::Allocator;
pub type alloc_func = unsafe extern "C" fn(voidpf, uInt, uInt) -> voidpf;
pub type free_func = unsafe extern "C" fn(voidpf, voidpf);
pub type Bytef = u8;
pub type in_func = unsafe extern "C" fn(*mut c_void, *mut *const c_uchar) -> c_uint;
pub type out_func = unsafe extern "C" fn(*mut c_void, *mut c_uchar, c_uint) -> c_int;
pub type uInt = c_uint;
pub type uLong = c_ulong;
pub type uLongf = c_ulong;
pub type voidp = *mut c_void;
pub type voidpc = *const c_void;
pub type voidpf = *mut c_void;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct z_stream {
pub next_in: *const Bytef,
pub avail_in: uInt,
pub total_in: z_size,
pub next_out: *mut Bytef,
pub avail_out: uInt,
pub total_out: z_size,
pub msg: *mut c_char,
pub state: *mut internal_state,
pub zalloc: Option<alloc_func>,
pub zfree: Option<free_func>,
pub opaque: voidpf,
pub data_type: c_int,
pub adler: z_checksum,
pub reserved: uLong,
}
pub type z_streamp = *mut z_stream;
impl Default for z_stream {
fn default() -> Self {
let mut stream = Self {
next_in: core::ptr::null_mut(),
avail_in: 0,
total_in: 0,
next_out: core::ptr::null_mut(),
avail_out: 0,
total_out: 0,
msg: core::ptr::null_mut(),
state: core::ptr::null_mut(),
zalloc: None,
zfree: None,
opaque: core::ptr::null_mut(),
data_type: 0,
adler: 0,
reserved: 0,
};
#[cfg(feature = "rust-allocator")]
if stream.zalloc.is_none() || stream.zfree.is_none() {
stream.configure_default_rust_allocator()
}
#[cfg(feature = "c-allocator")]
if stream.zalloc.is_none() || stream.zfree.is_none() {
stream.configure_default_c_allocator()
}
stream
}
}
impl z_stream {
fn configure_allocator(&mut self, alloc: Allocator) {
self.zalloc = Some(alloc.zalloc);
self.zfree = Some(alloc.zfree);
self.opaque = alloc.opaque;
}
#[cfg(feature = "rust-allocator")]
pub fn configure_default_rust_allocator(&mut self) {
self.configure_allocator(Allocator::RUST)
}
#[cfg(feature = "c-allocator")]
pub fn configure_default_c_allocator(&mut self) {
self.configure_allocator(Allocator::C)
}
}
// // zlib stores Adler-32 and CRC-32 checksums in unsigned long; zlib-ng uses uint32_t.
pub(crate) type z_size = c_ulong;
pub(crate) type z_checksum = c_ulong;
// opaque to the user
pub enum internal_state {}
pub const Z_NO_FLUSH: c_int = 0;
pub const Z_PARTIAL_FLUSH: c_int = 1;
pub const Z_SYNC_FLUSH: c_int = 2;
pub const Z_FULL_FLUSH: c_int = 3;
pub const Z_FINISH: c_int = 4;
pub const Z_BLOCK: c_int = 5;
pub const Z_TREES: c_int = 6;
pub const Z_OK: c_int = 0;
pub const Z_STREAM_END: c_int = 1;
pub const Z_NEED_DICT: c_int = 2;
pub const Z_ERRNO: c_int = -1;
pub const Z_STREAM_ERROR: c_int = -2;
pub const Z_DATA_ERROR: c_int = -3;
pub const Z_MEM_ERROR: c_int = -4;
pub const Z_BUF_ERROR: c_int = -5;
pub const Z_VERSION_ERROR: c_int = -6;
pub const Z_NO_COMPRESSION: c_int = 0;
pub const Z_BEST_SPEED: c_int = 1;
pub const Z_BEST_COMPRESSION: c_int = 9;
pub const Z_DEFAULT_COMPRESSION: c_int = -1;
pub const Z_DEFLATED: c_int = 8;
pub const Z_BINARY: c_int = 0;
pub const Z_TEXT: c_int = 1;
pub const Z_ASCII: c_int = Z_TEXT; /* for compatibility with 1.2.2 and earlier */
pub const Z_UNKNOWN: c_int = 2;
pub const Z_FILTERED: c_int = 1;
pub const Z_HUFFMAN_ONLY: c_int = 2;
pub const Z_RLE: c_int = 3;
pub const Z_FIXED: c_int = 4;
pub const Z_DEFAULT_STRATEGY: c_int = 0;
pub type gz_headerp = *mut gz_header;
/// gzip header information passed to and from zlib routines.
/// See RFC 1952 for more details on the meanings of these fields.
#[derive(Debug)]
#[repr(C)]
pub struct gz_header {
/// true if compressed data believed to be text
pub text: i32,
/// modification time
pub time: c_ulong,
/// extra flags (not used when writing a gzip file)
pub xflags: i32,
/// operating system
pub os: i32,
/// pointer to extra field or NULL if none
pub extra: *mut u8,
/// extra field length (valid if extra != NULL)
pub extra_len: u32,
/// space at extra (only when reading header)
pub extra_max: u32,
/// pointer to zero-terminated file name or NULL
pub name: *mut u8,
/// space at name (only when reading header)
pub name_max: u32,
/// pointer to zero-terminated comment or NULL
pub comment: *mut u8,
/// space at comment (only when reading header)
pub comm_max: u32,
/// true if there was or will be a header crc
pub hcrc: i32,
/// true when done reading gzip header (not used when writing a gzip file)
pub done: i32,
}
impl Default for gz_header {
fn default() -> Self {
Self {
text: 0,
time: 0,
xflags: 0,
os: 0,
extra: core::ptr::null_mut(),
extra_len: 0,
extra_max: 0,
name: core::ptr::null_mut(),
name_max: 0,
comment: core::ptr::null_mut(),
comm_max: 0,
hcrc: 0,
done: 0,
}
}
}
impl gz_header {
// based on the spec https://www.ietf.org/rfc/rfc1952.txt
//
// 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32)
// 1 - Amiga
// 2 - VMS (or OpenVMS)
// 3 - Unix
// 4 - VM/CMS
// 5 - Atari TOS
// 6 - HPFS filesystem (OS/2, NT)
// 7 - Macintosh
// 8 - Z-System
// 9 - CP/M
// 10 - TOPS-20
// 11 - NTFS filesystem (NT)
// 12 - QDOS
// 13 - Acorn RISCOS
// 255 - unknown
#[allow(clippy::if_same_then_else)]
pub(crate) const OS_CODE: u8 = {
if cfg!(windows) {
10
} else if cfg!(target_os = "macos") {
19
} else if cfg!(unix) {
3
} else {
3 // assume unix
}
};
pub(crate) fn flags(&self) -> u8 {
(if self.text > 0 { 1 } else { 0 })
+ (if self.hcrc > 0 { 2 } else { 0 })
+ (if self.extra.is_null() { 0 } else { 4 })
+ (if self.name.is_null() { 0 } else { 8 })
+ (if self.comment.is_null() { 0 } else { 16 })
}
}

259
third_party/rust/zlib-rs/src/crc32.rs vendored Normal file
View File

@ -0,0 +1,259 @@
use core::mem::MaybeUninit;
use crate::{read_buf::ReadBuf, CRC32_INITIAL_VALUE};
#[cfg(target_arch = "aarch64")]
pub(crate) mod acle;
mod braid;
mod combine;
#[cfg(target_arch = "x86_64")]
mod pclmulqdq;
pub use combine::crc32_combine;
pub fn crc32(start: u32, buf: &[u8]) -> u32 {
/* For lens < 64, crc32_braid method is faster. The CRC32 instruction for
* these short lengths might also prove to be effective */
if buf.len() < 64 {
return crc32_braid(start, buf);
}
let mut crc_state = Crc32Fold::new_with_initial(start);
crc_state.fold(buf, start);
crc_state.finish()
}
pub fn crc32_braid(start: u32, buf: &[u8]) -> u32 {
braid::crc32_braid::<5>(start, buf)
}
#[allow(unused)]
pub fn crc32_copy(dst: &mut ReadBuf, buf: &[u8]) -> u32 {
/* For lens < 64, crc32_braid method is faster. The CRC32 instruction for
* these short lengths might also prove to be effective */
if buf.len() < 64 {
dst.extend(buf);
return braid::crc32_braid::<5>(CRC32_INITIAL_VALUE, buf);
}
let mut crc_state = Crc32Fold::new();
crc_state.fold_copy(unsafe { dst.inner_mut() }, buf);
unsafe { dst.assume_init(buf.len()) };
dst.set_filled(buf.len());
crc_state.finish()
}
#[derive(Debug, Clone, Copy)]
pub struct Crc32Fold {
#[cfg(target_arch = "x86_64")]
fold: pclmulqdq::Accumulator,
value: u32,
}
impl Default for Crc32Fold {
fn default() -> Self {
Self::new()
}
}
impl Crc32Fold {
pub const fn new() -> Self {
Self::new_with_initial(CRC32_INITIAL_VALUE)
}
pub const fn new_with_initial(initial: u32) -> Self {
Self {
#[cfg(target_arch = "x86_64")]
fold: pclmulqdq::Accumulator::new(),
value: initial,
}
}
#[cfg(all(target_arch = "x86_64", feature = "std"))]
fn is_pclmulqdq() -> bool {
std::is_x86_feature_detected!("pclmulqdq")
&& std::is_x86_feature_detected!("sse2")
&& std::is_x86_feature_detected!("sse4.1")
}
pub fn fold(&mut self, src: &[u8], _start: u32) {
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if Self::is_pclmulqdq() {
return self.fold.fold(src, _start);
}
#[cfg(all(target_arch = "aarch64", feature = "std"))]
if std::arch::is_aarch64_feature_detected!("crc") {
self.value = self::acle::crc32_acle_aarch64(self.value, src);
return;
}
// in this case the start value is ignored
self.value = braid::crc32_braid::<5>(self.value, src);
}
pub fn fold_copy(&mut self, dst: &mut [MaybeUninit<u8>], src: &[u8]) {
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if Self::is_pclmulqdq() {
return self.fold.fold_copy(dst, src);
}
self.fold(src, 0);
dst[..src.len()].copy_from_slice(slice_to_uninit(src));
}
pub fn finish(self) -> u32 {
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if Self::is_pclmulqdq() {
return unsafe { self.fold.finish() };
}
self.value
}
}
// when stable, use MaybeUninit::write_slice
fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit<u8>] {
// safety: &[T] and &[MaybeUninit<T>] have the same layout
unsafe { &*(slice as *const [u8] as *const [MaybeUninit<u8>]) }
}
#[cfg(test)]
mod test {
use test::braid::crc32_braid;
use super::*;
const INPUT: [u8; 1024] = {
let mut array = [0; 1024];
let mut i = 0;
while i < array.len() {
array[i] = i as u8;
i += 1;
}
array
};
#[test]
fn test_crc32_fold() {
// input large enough to trigger the SIMD
let mut h = crc32fast::Hasher::new_with_initial(CRC32_INITIAL_VALUE);
h.update(&INPUT);
assert_eq!(crc32(CRC32_INITIAL_VALUE, &INPUT), h.finalize());
}
#[test]
fn test_crc32_fold_align() {
// SIMD algorithm is sensitive to alignment;
for i in 0..16 {
for start in [CRC32_INITIAL_VALUE, 42] {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&INPUT[i..]);
assert_eq!(
crc32(start, &INPUT[i..]),
h.finalize(),
"offset = {i}, start = {start}"
);
}
}
}
#[test]
fn test_crc32_fold_copy() {
// input large enough to trigger the SIMD
let mut h = crc32fast::Hasher::new_with_initial(CRC32_INITIAL_VALUE);
h.update(&INPUT);
let mut dst = [0; INPUT.len()];
let mut dst = ReadBuf::new(&mut dst);
assert_eq!(crc32_copy(&mut dst, &INPUT), h.finalize());
assert_eq!(INPUT, dst.filled());
}
quickcheck::quickcheck! {
fn crc_fold_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v);
let a = crc32(start, &v) ;
let b = h.finalize();
a == b
}
fn crc_fold_copy_is_crc32fast(v: Vec<u8>) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(CRC32_INITIAL_VALUE);
h.update(&v);
let mut dst = vec![0; v.len()];
let mut dst = ReadBuf::new(&mut dst);
let a = crc32_copy(&mut dst, &v) ;
let b = h.finalize();
assert_eq!(a,b);
v == dst.filled()
}
}
#[test]
fn chunked() {
const INPUT: &[&[u8]] = &[
&[116],
&[111, 107, 105, 111, 44, 32, 97, 115],
&[121, 110, 99, 45, 115, 116, 100, 44],
&[32, 97, 110, 100, 32, 115, 109, 111],
&[108, 46, 32, 89, 111, 117, 226, 128],
&[153, 118, 101, 32, 112, 114, 111, 98],
&[97, 98, 108, 121, 32, 117, 115, 101],
&[100, 32, 116, 104, 101, 109, 32, 97],
&[116, 32, 115, 111, 109, 101, 32, 112],
&[111, 105, 110, 116, 44, 32, 101, 105],
&[116, 104, 101, 114, 32, 100, 105, 114],
&[101, 99, 116, 108, 121, 32, 111, 114],
&[0],
];
const START: u32 = 2380683574;
let mut in_chunks = START;
for chunk in INPUT {
in_chunks = crc32(in_chunks, chunk);
}
let flattened: Vec<_> = INPUT.iter().copied().flatten().copied().collect();
let flat = crc32(START, &flattened);
assert_eq!(in_chunks, flat);
}
#[test]
fn nasty_alignment() {
const START: u32 = 2380683574;
const FLAT: &[u8] = &[
116, 111, 107, 105, 111, 44, 32, 97, 115, 121, 110, 99, 45, 115, 116, 100, 44, 32, 97,
110, 100, 32, 115, 109, 111, 108, 46, 32, 89, 111, 117, 226, 128, 153, 118, 101, 32,
112, 114, 111, 98, 97, 98, 108, 121, 32, 117, 115, 101, 100, 32, 116, 104, 101, 109,
32, 97, 116, 32, 115, 111, 109, 101, 32, 112, 111, 105, 110, 116, 44, 32, 101, 105,
116, 104, 101, 114, 32, 100, 105, 114, 101, 99, 116, 108, 121, 32, 111, 114, 0,
];
let mut i = 0;
let mut flat = FLAT.to_vec();
while flat[i..].as_ptr() as usize % 16 != 15 {
flat.insert(0, 0);
i += 1;
}
let flat = &flat[i..];
assert_eq!(crc32_braid::<5>(START, flat), crc32(START, flat));
assert_eq!(crc32(2380683574, flat), 1175758345);
}
}

View File

@ -0,0 +1,181 @@
#[cfg_attr(not(target_arch = "aarch64"), allow(unused))]
pub fn crc32_acle_aarch64(crc: u32, buf: &[u8]) -> u32 {
let mut c = !crc;
let (before, middle, after) = unsafe { buf.align_to::<u64>() };
c = remainder(c, before);
if middle.is_empty() && after.is_empty() {
return !c;
}
for d in middle {
c = unsafe { __crc32d(c, *d) };
}
c = remainder(c, after);
!c
}
#[cfg_attr(not(target_arch = "arm"), allow(unused))]
pub fn crc32_acle_arm(crc: u32, buf: &[u8]) -> u32 {
let mut c = !crc;
let (before, middle, after) = unsafe { buf.align_to::<u32>() };
c = remainder(c, before);
if middle.is_empty() && after.is_empty() {
return !c;
}
for w in middle {
c = unsafe { __crc32w(c, *w) };
}
c = remainder(c, after);
!c
}
fn remainder(mut c: u32, mut buf: &[u8]) -> u32 {
if let [b0, b1, b2, b3, rest @ ..] = buf {
c = unsafe { __crc32w(c, u32::from_ne_bytes([*b0, *b1, *b2, *b3])) };
buf = rest;
}
if let [b0, b1, rest @ ..] = buf {
c = unsafe { __crc32h(c, u16::from_ne_bytes([*b0, *b1])) };
buf = rest;
}
if let [b0, rest @ ..] = buf {
c = unsafe { __crc32b(c, *b0) };
buf = rest;
}
debug_assert!(buf.is_empty());
c
}
/// CRC32 single round checksum for bytes (8 bits).
///
/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32b)
#[target_feature(enable = "crc")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))]
unsafe fn __crc32b(mut crc: u32, data: u8) -> u32 {
core::arch::asm!("crc32b {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data);
crc
}
/// CRC32 single round checksum for half words (16 bits).
///
/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32h)
#[target_feature(enable = "crc")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))]
unsafe fn __crc32h(mut crc: u32, data: u16) -> u32 {
core::arch::asm!("crc32h {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data);
crc
}
/// CRC32 single round checksum for words (32 bits).
///
/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32w)
#[target_feature(enable = "crc")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))]
unsafe fn __crc32w(mut crc: u32, data: u32) -> u32 {
core::arch::asm!("crc32w {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data);
crc
}
/// CRC32 single round checksum for double words (64 bits).
///
/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32d)
#[cfg(target_arch = "aarch64")]
#[target_feature(enable = "crc")]
unsafe fn __crc32d(mut crc: u32, data: u64) -> u32 {
core::arch::asm!("crc32x {crc:w}, {crc:w}, {data:x}", crc = inout(reg) crc, data = in(reg) data);
crc
}
/// CRC32-C single round checksum for words (32 bits).
///
/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32cw)
#[target_feature(enable = "crc")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))]
pub unsafe fn __crc32cw(mut crc: u32, data: u32) -> u32 {
core::arch::asm!("crc32cw {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data);
crc
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck::quickcheck! {
#[cfg(target_arch = "aarch64")]
fn crc32_acle_aarch64_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v);
let a = crc32_acle_aarch64(start, &v) ;
let b = h.finalize();
a == b
}
fn crc32_acle_arm_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v);
let a = crc32_acle_arm(start, &v) ;
let b = h.finalize();
a == b
}
}
#[test]
fn test_crc32b() {
unsafe {
assert_eq!(__crc32b(0, 0), 0);
assert_eq!(__crc32b(0, 255), 755167117);
}
}
#[test]
fn test_crc32h() {
unsafe {
assert_eq!(__crc32h(0, 0), 0);
assert_eq!(__crc32h(0, 16384), 1994146192);
}
}
#[test]
fn test_crc32w() {
unsafe {
assert_eq!(__crc32w(0, 0), 0);
assert_eq!(__crc32w(0, 4294967295), 3736805603);
}
}
#[test]
#[cfg(target_arch = "aarch64")]
fn test_crc32d() {
unsafe {
assert_eq!(__crc32d(0, 0), 0);
assert_eq!(__crc32d(0, 18446744073709551615), 1147535477);
}
}
#[test]
fn test_crc32cw() {
unsafe {
assert_eq!(__crc32cw(0, 0), 0);
assert_eq!(__crc32cw(0, 4294967295), 3080238136);
}
}
}

View File

@ -0,0 +1,178 @@
// Several implementations of CRC-32:
// * A naive byte-granularity approach
// * A word-sized approach that processes a usize word at a time
// * A "braid" implementation that processes a block of N words
// at a time, based on the algorithm in section 4.11 from
// https://github.com/zlib-ng/zlib-ng/blob/develop/doc/crc-doc.1.0.pdf.
// The binary encoding of the CRC-32 polynomial.
// We are assuming little-endianness so we process the input
// LSB-first. We need to use the "reversed" value from e.g
// https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Polynomial_representations.
pub(crate) const CRC32_LSB_POLY: usize = 0xedb8_8320usize;
const W: usize = core::mem::size_of::<usize>();
// The logic assumes that W >= sizeof(u32).
// In Rust, this is generally true.
const _: () = assert!(W >= core::mem::size_of::<u32>());
// Pre-computed tables for the CRC32 algorithm.
// CRC32_BYTE_TABLE corresponds to MulByXPowD from the paper.
static CRC32_BYTE_TABLE: [[u32; 256]; 1] = build_crc32_table::<256, 1, 1>();
// CRC32_WORD_TABLE is MulWordByXpowD.
static CRC32_WORD_TABLE: [[u32; 256]; W] = build_crc32_table::<256, W, 1>();
// Work-around for not being able to define generic consts or statics
// Crc32BraidTable::<N>::TABLE is the generic table for any braid size N.
struct Crc32BraidTable<const N: usize>;
impl<const N: usize> Crc32BraidTable<N> {
const TABLE: [[u32; 256]; W] = build_crc32_table::<256, W, N>();
}
// Build the CRC32 tables using a more efficient and simpler approach
// than the combination of Multiply and XpowN (which implement polynomial
// multiplication and exponentiation, respectively) from the paper,
// but with identical results. This function is const, so it should be
// fully evaluated at compile time.
const fn build_crc32_table<const A: usize, const W: usize, const N: usize>() -> [[u32; A]; W] {
let mut arr = [[0u32; A]; W];
let mut i = 0;
while i < W {
let mut j = 0;
while j < A {
let mut c = j;
let mut k = 0;
while k < 8 * (W * N - i) {
if c & 1 != 0 {
c = CRC32_LSB_POLY ^ (c >> 1);
} else {
c >>= 1;
}
k += 1;
}
arr[i][j] = c as u32;
j += 1;
}
i += 1;
}
arr
}
fn crc32_naive_inner(data: &[u8], start: u32) -> u32 {
data.iter().fold(start, |crc, val| {
let crc32_lsb = crc.to_le_bytes()[0];
CRC32_BYTE_TABLE[0][usize::from(crc32_lsb ^ *val)] ^ (crc >> 8)
})
}
fn crc32_words_inner(words: &[usize], start: u32, per_word_crcs: &[u32]) -> u32 {
words.iter().enumerate().fold(start, |crc, (i, word)| {
let value = *word ^ (crc ^ per_word_crcs.get(i).unwrap_or(&0)) as usize;
value
.to_le_bytes()
.into_iter()
.zip(CRC32_WORD_TABLE)
.fold(0u32, |crc, (b, tab)| crc ^ tab[usize::from(b)])
})
}
#[allow(unused)]
pub fn crc32_braid<const N: usize>(start: u32, data: &[u8]) -> u32 {
// Get a word-aligned sub-slice of the input data
let (prefix, words, suffix) = unsafe { data.align_to::<usize>() };
let crc = !start;
let crc = crc32_naive_inner(prefix, crc);
let mut crcs = [0u32; N];
crcs[0] = crc;
// TODO: this would normally use words.chunks_exact(N), but
// we need to pass the last full block to crc32_words_inner
// because we accumulate partial crcs in the array and we
// need to roll those into the final value. The last call to
// crc32_words_inner does that for us with its per_word_crcs
// argument.
let blocks = words.len() / N;
let blocks = blocks.saturating_sub(1);
for i in 0..blocks {
// Load the next N words.
let mut buffer: [usize; N] =
core::array::from_fn(|j| usize::to_le(words[i * N + j] ^ (crcs[j] as usize)));
crcs.fill(0);
for j in 0..W {
for k in 0..N {
crcs[k] ^= Crc32BraidTable::<N>::TABLE[j][buffer[k] & 0xff];
buffer[k] >>= 8;
}
}
}
let crc = core::mem::take(&mut crcs[0]);
let crc = crc32_words_inner(&words[blocks * N..], crc, &crcs);
let crc = crc32_naive_inner(suffix, crc);
!crc
}
#[cfg(test)]
mod test {
use super::*;
fn crc32_naive(data: &[u8], start: u32) -> u32 {
let crc = !start;
let crc = crc32_naive_inner(data, crc);
!crc
}
fn crc32_words(data: &[u8], start: u32) -> u32 {
// Get a word-aligned sub-slice of the input data
let (prefix, words, suffix) = unsafe { data.align_to::<usize>() };
let crc = !start;
let crc = crc32_naive_inner(prefix, crc);
let crc = crc32_words_inner(words, crc, &[]);
let crc = crc32_naive_inner(suffix, crc);
!crc
}
#[test]
fn empty_is_identity() {
assert_eq!(crc32_naive(&[], 32), 32);
}
quickcheck::quickcheck! {
fn naive_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v[..]);
crc32_naive(&v[..], start) == h.finalize()
}
fn words_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v[..]);
crc32_words(&v[..], start) == h.finalize()
}
#[cfg_attr(miri, ignore)]
fn braid_4_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v[..]);
crc32_braid::<4>(start, &v[..]) == h.finalize()
}
#[cfg_attr(miri, ignore)]
fn braid_5_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v[..]);
crc32_braid::<5>(start, &v[..]) == h.finalize()
}
#[cfg_attr(miri, ignore)]
fn braid_6_is_crc32fast(v: Vec<u8>, start: u32) -> bool {
let mut h = crc32fast::Hasher::new_with_initial(start);
h.update(&v[..]);
crc32_braid::<6>(start, &v[..]) == h.finalize()
}
}
}

View File

@ -0,0 +1,115 @@
use super::braid::CRC32_LSB_POLY;
pub const fn crc32_combine(crc1: u32, crc2: u32, len2: u64) -> u32 {
crc32_combine_op(crc1, crc2, crc32_combine_gen(len2))
}
#[inline(always)]
const fn crc32_combine_gen(len2: u64) -> u32 {
x2nmodp(len2, 3)
}
#[inline(always)]
const fn crc32_combine_op(crc1: u32, crc2: u32, op: u32) -> u32 {
multmodp(op, crc1) ^ crc2
}
const X2N_TABLE: [u32; 32] = [
0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517,
0xed627dae, 0x88d14467, 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f,
0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e,
0xbad90e37, 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c,
];
// Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
// reflected. For speed, this requires that a not be zero.
const fn multmodp(a: u32, mut b: u32) -> u32 {
let mut m = 1 << 31;
let mut p = 0;
loop {
if (a & m) != 0 {
p ^= b;
if (a & (m - 1)) == 0 {
break;
}
}
m >>= 1;
b = if (b & 1) != 0 {
(b >> 1) ^ CRC32_LSB_POLY as u32
} else {
b >> 1
};
}
p
}
// Return x^(n * 2^k) modulo p(x).
const fn x2nmodp(mut n: u64, mut k: u32) -> u32 {
let mut p: u32 = 1 << 31; /* x^0 == 1 */
while n > 0 {
if (n & 1) != 0 {
p = multmodp(X2N_TABLE[k as usize & 31], p);
}
n >>= 1;
k += 1;
}
p
}
#[cfg(test)]
mod test {
use super::*;
use crate::crc32;
#[test]
fn test_crc32_combine() {
::quickcheck::quickcheck(test as fn(_) -> _);
fn test(data: Vec<u8>) -> bool {
let Some(buf_len) = data.first().copied() else {
return true;
};
let buf_size = Ord::max(buf_len, 1) as usize;
let crc0 = 0;
let mut crc1 = crc0;
let mut crc2 = crc0;
/* CRC32 */
for chunk in data.chunks(buf_size) {
let crc3 = crc32(crc0, chunk);
let op = crc32_combine_gen(chunk.len() as _);
let crc4 = crc32_combine_op(crc1, crc3, op);
crc1 = crc32(crc1, chunk);
assert_eq!(crc1, crc4);
}
crc2 = crc32(crc2, &data);
assert_eq!(crc1, crc2);
let combine1 = crc32_combine(crc1, crc2, data.len() as _);
let combine2 = crc32_combine(crc1, crc1, data.len() as _);
assert_eq!(combine1, combine2);
// Fast CRC32 combine.
let op = crc32_combine_gen(data.len() as _);
let combine1 = crc32_combine_op(crc1, crc2, op);
let combine2 = crc32_combine_op(crc2, crc1, op);
assert_eq!(combine1, combine2);
let combine1 = crc32_combine(crc1, crc2, data.len() as _);
let combine2 = crc32_combine_op(crc2, crc1, op);
assert_eq!(combine1, combine2);
true
}
}
}

View File

@ -0,0 +1,342 @@
use core::arch::x86_64::__m128i;
use core::{
arch::x86_64::{
_mm_and_si128, _mm_clmulepi64_si128, _mm_extract_epi32, _mm_load_si128, _mm_loadu_si128,
_mm_or_si128, _mm_shuffle_epi8, _mm_slli_si128, _mm_srli_si128, _mm_storeu_si128,
_mm_xor_si128,
},
mem::MaybeUninit,
};
use crate::{crc32::slice_to_uninit, CRC32_INITIAL_VALUE};
#[derive(Debug)]
#[repr(C, align(16))]
struct Align16<T>(T);
#[cfg(target_arch = "x86_64")]
const fn reg(input: [u32; 4]) -> __m128i {
// safety: any valid [u32; 4] represents a valid __m128i
unsafe { core::mem::transmute(input) }
}
#[derive(Debug, Clone, Copy)]
#[cfg(target_arch = "x86_64")]
pub(crate) struct Accumulator {
fold: [__m128i; 4],
}
#[cfg(target_arch = "x86_64")]
impl Accumulator {
const XMM_FOLD4: __m128i = reg([0xc6e41596u32, 0x00000001u32, 0x54442bd4u32, 0x00000001u32]);
pub const fn new() -> Self {
let xmm_crc0 = reg([0x9db42487, 0, 0, 0]);
let xmm_zero = reg([0, 0, 0, 0]);
Self {
fold: [xmm_crc0, xmm_zero, xmm_zero, xmm_zero],
}
}
pub fn fold(&mut self, src: &[u8], start: u32) {
unsafe { self.fold_help::<false>(&mut [], src, start) }
}
pub fn fold_copy(&mut self, dst: &mut [MaybeUninit<u8>], src: &[u8]) {
unsafe { self.fold_help::<true>(dst, src, 0) }
}
#[target_feature(enable = "pclmulqdq", enable = "sse2", enable = "sse4.1")]
pub unsafe fn finish(self) -> u32 {
const CRC_MASK1: __m128i =
reg([0xFFFFFFFFu32, 0xFFFFFFFFu32, 0x00000000u32, 0x00000000u32]);
const CRC_MASK2: __m128i =
reg([0x00000000u32, 0xFFFFFFFFu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32]);
const RK1_RK2: __m128i = reg([
0xccaa009e, 0x00000000, /* rk1 */
0x751997d0, 0x00000001, /* rk2 */
]);
const RK5_RK6: __m128i = reg([
0xccaa009e, 0x00000000, /* rk5 */
0x63cd6124, 0x00000001, /* rk6 */
]);
const RK7_RK8: __m128i = reg([
0xf7011640, 0x00000001, /* rk7 */
0xdb710640, 0x00000001, /* rk8 */
]);
let [mut xmm_crc0, mut xmm_crc1, mut xmm_crc2, mut xmm_crc3] = self.fold;
/*
* k1
*/
let mut crc_fold = RK1_RK2;
let x_tmp0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x10);
xmm_crc0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x01);
xmm_crc1 = _mm_xor_si128(xmm_crc1, x_tmp0);
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_crc0);
let x_tmp1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x10);
xmm_crc1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x01);
xmm_crc2 = _mm_xor_si128(xmm_crc2, x_tmp1);
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_crc1);
let x_tmp2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x10);
xmm_crc2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x01);
xmm_crc3 = _mm_xor_si128(xmm_crc3, x_tmp2);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
/*
* k5
*/
crc_fold = RK5_RK6;
xmm_crc0 = xmm_crc3;
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0);
xmm_crc0 = _mm_srli_si128(xmm_crc0, 8);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0);
xmm_crc0 = xmm_crc3;
xmm_crc3 = _mm_slli_si128(xmm_crc3, 4);
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0);
xmm_crc3 = _mm_and_si128(xmm_crc3, CRC_MASK2);
/*
* k7
*/
xmm_crc1 = xmm_crc3;
xmm_crc2 = xmm_crc3;
crc_fold = RK7_RK8;
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
xmm_crc3 = _mm_and_si128(xmm_crc3, CRC_MASK1);
xmm_crc2 = xmm_crc3;
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc1);
!(_mm_extract_epi32(xmm_crc3, 2) as u32)
}
fn fold_step<const N: usize>(&mut self) {
self.fold = core::array::from_fn(|i| match self.fold.get(i + N) {
Some(v) => *v,
None => unsafe { Self::step(self.fold[(i + N) - 4]) },
});
}
#[inline(always)]
unsafe fn step(input: __m128i) -> __m128i {
_mm_xor_si128(
_mm_clmulepi64_si128(input, Self::XMM_FOLD4, 0x01),
_mm_clmulepi64_si128(input, Self::XMM_FOLD4, 0x10),
)
}
unsafe fn partial_fold(&mut self, xmm_crc_part: __m128i, len: usize) {
const PSHUFB_SHF_TABLE: [__m128i; 15] = [
reg([0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d]), /* shl 15 (16 - 1)/shr1 */
reg([0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e]), /* shl 14 (16 - 3)/shr2 */
reg([0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f]), /* shl 13 (16 - 4)/shr3 */
reg([0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100]), /* shl 12 (16 - 4)/shr4 */
reg([0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201]), /* shl 11 (16 - 5)/shr5 */
reg([0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302]), /* shl 10 (16 - 6)/shr6 */
reg([0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403]), /* shl 9 (16 - 7)/shr7 */
reg([0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504]), /* shl 8 (16 - 8)/shr8 */
reg([0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605]), /* shl 7 (16 - 9)/shr9 */
reg([0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706]), /* shl 6 (16 -10)/shr10*/
reg([0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807]), /* shl 5 (16 -11)/shr11*/
reg([0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908]), /* shl 4 (16 -12)/shr12*/
reg([0x008f8e8d, 0x04030201, 0x08070605, 0x0c0b0a09]), /* shl 3 (16 -13)/shr13*/
reg([0x01008f8e, 0x05040302, 0x09080706, 0x0d0c0b0a]), /* shl 2 (16 -14)/shr14*/
reg([0x0201008f, 0x06050403, 0x0a090807, 0x0e0d0c0b]), /* shl 1 (16 -15)/shr15*/
];
let xmm_shl = PSHUFB_SHF_TABLE[len - 1];
let xmm_shr = _mm_xor_si128(xmm_shl, reg([0x80808080u32; 4]));
let xmm_a0 = Self::step(_mm_shuffle_epi8(self.fold[0], xmm_shl));
self.fold[0] = _mm_shuffle_epi8(self.fold[0], xmm_shr);
let xmm_tmp1 = _mm_shuffle_epi8(self.fold[1], xmm_shl);
self.fold[0] = _mm_or_si128(self.fold[0], xmm_tmp1);
self.fold[1] = _mm_shuffle_epi8(self.fold[1], xmm_shr);
let xmm_tmp2 = _mm_shuffle_epi8(self.fold[2], xmm_shl);
self.fold[1] = _mm_or_si128(self.fold[1], xmm_tmp2);
self.fold[2] = _mm_shuffle_epi8(self.fold[2], xmm_shr);
let xmm_tmp3 = _mm_shuffle_epi8(self.fold[3], xmm_shl);
self.fold[2] = _mm_or_si128(self.fold[2], xmm_tmp3);
self.fold[3] = _mm_shuffle_epi8(self.fold[3], xmm_shr);
let xmm_crc_part = _mm_shuffle_epi8(xmm_crc_part, xmm_shl);
self.fold[3] = _mm_or_si128(self.fold[3], xmm_crc_part);
// zlib-ng uses casts and a floating-point xor instruction here. There is a theory that
// this breaks dependency chains on some CPUs and gives better throughput. Other sources
// claim that casting between integer and float has a cost and should be avoided. We can't
// measure the difference, and choose the shorter code.
self.fold[3] = _mm_xor_si128(self.fold[3], xmm_a0)
}
#[allow(clippy::needless_range_loop)]
fn progress<const N: usize, const COPY: bool>(
&mut self,
dst: &mut [MaybeUninit<u8>],
src: &mut &[u8],
init_crc: &mut u32,
) -> usize {
let mut it = src.chunks_exact(16);
let mut input: [_; N] = core::array::from_fn(|_| unsafe {
_mm_load_si128(it.next().unwrap().as_ptr() as *const __m128i)
});
*src = &src[N * 16..];
if COPY {
for (s, d) in input[..N].iter().zip(dst.chunks_exact_mut(16)) {
unsafe { _mm_storeu_si128(d.as_mut_ptr() as *mut __m128i, *s) };
}
} else if *init_crc != CRC32_INITIAL_VALUE {
let xmm_initial = reg([*init_crc, 0, 0, 0]);
input[0] = unsafe { _mm_xor_si128(input[0], xmm_initial) };
*init_crc = CRC32_INITIAL_VALUE;
}
self.fold_step::<N>();
for i in 0..N {
self.fold[i + (4 - N)] = unsafe { _mm_xor_si128(self.fold[i + (4 - N)], input[i]) };
}
if COPY {
N * 16
} else {
0
}
}
#[target_feature(enable = "pclmulqdq", enable = "sse2", enable = "sse4.1")]
unsafe fn fold_help<const COPY: bool>(
&mut self,
mut dst: &mut [MaybeUninit<u8>],
mut src: &[u8],
mut init_crc: u32,
) {
let mut xmm_crc_part = reg([0; 4]);
let mut partial_buf = Align16([0u8; 16]);
// Technically the CRC functions don't even call this for input < 64, but a bare minimum of 31
// bytes of input is needed for the aligning load that occurs. If there's an initial CRC, to
// carry it forward through the folded CRC there must be 16 - src % 16 + 16 bytes available, which
// by definition can be up to 15 bytes + one full vector load. */
assert!(src.len() >= 31 || init_crc == CRC32_INITIAL_VALUE);
if COPY {
assert_eq!(dst.len(), src.len(), "dst and src must be the same length")
}
if src.len() < 16 {
if COPY {
if src.is_empty() {
return;
}
partial_buf.0[..src.len()].copy_from_slice(src);
xmm_crc_part = _mm_load_si128(partial_buf.0.as_mut_ptr() as *mut __m128i);
dst[..src.len()].copy_from_slice(slice_to_uninit(&partial_buf.0[..src.len()]));
}
} else {
let (before, _, _) = unsafe { src.align_to::<__m128i>() };
if !before.is_empty() {
xmm_crc_part = _mm_loadu_si128(src.as_ptr() as *const __m128i);
if COPY {
_mm_storeu_si128(dst.as_mut_ptr() as *mut __m128i, xmm_crc_part);
dst = &mut dst[before.len()..];
} else {
let is_initial = init_crc == CRC32_INITIAL_VALUE;
if !is_initial {
let xmm_initial = reg([init_crc, 0, 0, 0]);
xmm_crc_part = _mm_xor_si128(xmm_crc_part, xmm_initial);
init_crc = CRC32_INITIAL_VALUE;
}
if before.len() < 4 && !is_initial {
let xmm_t0 = xmm_crc_part;
xmm_crc_part = _mm_loadu_si128((src.as_ptr() as *const __m128i).add(1));
self.fold_step::<1>();
self.fold[3] = _mm_xor_si128(self.fold[3], xmm_t0);
src = &src[16..];
}
}
self.partial_fold(xmm_crc_part, before.len());
src = &src[before.len()..];
}
// if is_x86_feature_detected!("vpclmulqdq") {
// if src.len() >= 256 {
// if COPY {
// // size_t n = fold_16_vpclmulqdq_copy(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, dst, src, len);
// // dst += n;
// } else {
// // size_t n = fold_16_vpclmulqdq(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, src, len, xmm_initial, first);
// // first = false;
// }
// // len -= n;
// // src += n;
// }
// }
while src.len() >= 64 {
let n = self.progress::<4, COPY>(dst, &mut src, &mut init_crc);
dst = &mut dst[n..];
}
if src.len() >= 48 {
let n = self.progress::<3, COPY>(dst, &mut src, &mut init_crc);
dst = &mut dst[n..];
} else if src.len() >= 32 {
let n = self.progress::<2, COPY>(dst, &mut src, &mut init_crc);
dst = &mut dst[n..];
} else if src.len() >= 16 {
let n = self.progress::<1, COPY>(dst, &mut src, &mut init_crc);
dst = &mut dst[n..];
}
}
if !src.is_empty() {
core::ptr::copy_nonoverlapping(
src.as_ptr(),
&mut xmm_crc_part as *mut _ as *mut u8,
src.len(),
);
if COPY {
_mm_storeu_si128(partial_buf.0.as_mut_ptr() as *mut __m128i, xmm_crc_part);
core::ptr::copy_nonoverlapping(
partial_buf.0.as_ptr() as *const MaybeUninit<u8>,
dst.as_mut_ptr(),
src.len(),
);
}
self.partial_fold(xmm_crc_part, src.len());
}
}
}

4431
third_party/rust/zlib-rs/src/deflate.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
#![forbid(unsafe_code)]
use crate::{
deflate::{
fill_window, BlockState, DeflateStream, MIN_LOOKAHEAD, STD_MIN_MATCH, WANT_MIN_MATCH,
},
flush_block, DeflateFlush,
};
pub fn deflate_fast(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
let mut bflush; /* set if current block must be flushed */
let mut dist;
let mut match_len = 0;
loop {
// Make sure that we always have enough lookahead, except
// at the end of the input file. We need STD_MAX_MATCH bytes
// for the next match, plus WANT_MIN_MATCH bytes to insert the
// string following the next match.
if stream.state.lookahead < MIN_LOOKAHEAD {
fill_window(stream);
if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush {
return BlockState::NeedMore;
}
if stream.state.lookahead == 0 {
break; /* flush the current block */
}
}
let state = &mut stream.state;
// Insert the string window[strstart .. strstart+2] in the
// dictionary, and set hash_head to the head of the hash chain:
if state.lookahead >= WANT_MIN_MATCH {
let hash_head = state.quick_insert_string(state.strstart);
dist = state.strstart as isize - hash_head as isize;
/* Find the longest match, discarding those <= prev_length.
* At this point we have always match length < WANT_MIN_MATCH
*/
if dist <= state.max_dist() as isize && dist > 0 && hash_head != 0 {
// To simplify the code, we prevent matches with the string
// of window index 0 (in particular we have to avoid a match
// of the string with itself at the start of the input file).
(match_len, state.match_start) =
crate::deflate::longest_match::longest_match(state, hash_head);
}
}
if match_len >= WANT_MIN_MATCH {
// check_match(s, s->strstart, s->match_start, match_len);
// bflush = zng_tr_tally_dist(s, s->strstart - s->match_start, match_len - STD_MIN_MATCH);
bflush = state.tally_dist(
state.strstart - state.match_start,
match_len - STD_MIN_MATCH,
);
state.lookahead -= match_len;
/* Insert new strings in the hash table only if the match length
* is not too large. This saves time but degrades compression.
*/
if match_len <= state.max_insert_length() && state.lookahead >= WANT_MIN_MATCH {
match_len -= 1; /* string at strstart already in table */
state.strstart += 1;
state.insert_string(state.strstart, match_len);
state.strstart += match_len;
} else {
state.strstart += match_len;
state.quick_insert_string(state.strstart + 2 - STD_MIN_MATCH);
/* If lookahead < STD_MIN_MATCH, ins_h is garbage, but it does not
* matter since it will be recomputed at next deflate call.
*/
}
match_len = 0;
} else {
/* No match, output a literal byte */
let lc = state.window.filled()[state.strstart];
bflush = state.tally_lit(lc);
state.lookahead -= 1;
state.strstart += 1;
}
if bflush {
flush_block!(stream, false);
}
}
stream.state.insert = if stream.state.strstart < (STD_MIN_MATCH - 1) {
stream.state.strstart
} else {
STD_MIN_MATCH - 1
};
if flush == DeflateFlush::Finish {
flush_block!(stream, true);
return BlockState::FinishDone;
}
if !stream.state.sym_buf.is_empty() {
flush_block!(stream, false);
}
BlockState::BlockDone
}

View File

@ -0,0 +1,45 @@
#![forbid(unsafe_code)]
use crate::{
deflate::{fill_window, BlockState, DeflateStream},
flush_block, DeflateFlush,
};
pub fn deflate_huff(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
loop {
/* Make sure that we have a literal to write. */
if stream.state.lookahead == 0 {
fill_window(stream);
if stream.state.lookahead == 0 {
match flush {
DeflateFlush::NoFlush => return BlockState::NeedMore,
_ => break, /* flush the current block */
}
}
}
/* Output a literal byte */
let state = &mut stream.state;
let lc = state.window.filled()[state.strstart];
let bflush = state.tally_lit(lc);
state.lookahead -= 1;
state.strstart += 1;
if bflush {
flush_block!(stream, false);
}
}
stream.state.insert = 0;
if flush == DeflateFlush::Finish {
flush_block!(stream, true);
return BlockState::FinishDone;
}
if !stream.state.sym_buf.is_empty() {
flush_block!(stream, false);
}
BlockState::BlockDone
}

View File

@ -0,0 +1,339 @@
#![forbid(unsafe_code)]
use crate::{
deflate::{
fill_window, BlockState, DeflateStream, State, MIN_LOOKAHEAD, STD_MIN_MATCH, WANT_MIN_MATCH,
},
flush_block, DeflateFlush,
};
pub fn deflate_medium(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
let mut state = &mut stream.state;
// For levels below 5, don't check the next position for a better match
let early_exit = state.level < 5;
let mut current_match = Match {
match_start: 0,
match_length: 0,
strstart: 0,
orgstart: 0,
};
let mut next_match = Match {
match_start: 0,
match_length: 0,
strstart: 0,
orgstart: 0,
};
loop {
let mut hash_head;
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need STD_MAX_MATCH bytes
* for the next match, plus WANT_MIN_MATCH bytes to insert the
* string following the next match.
*/
if stream.state.lookahead < MIN_LOOKAHEAD {
fill_window(stream);
if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush {
return BlockState::NeedMore;
}
if stream.state.lookahead == 0 {
break; /* flush the current block */
}
next_match.match_length = 0;
}
state = &mut stream.state;
// Insert the string window[strstart .. strstart+2] in the
// dictionary, and set hash_head to the head of the hash chain:
/* If we already have a future match from a previous round, just use that */
if !early_exit && next_match.match_length > 0 {
current_match = next_match;
next_match.match_length = 0;
} else {
hash_head = 0;
if state.lookahead >= WANT_MIN_MATCH {
hash_head = state.quick_insert_string(state.strstart);
}
current_match.strstart = state.strstart as u16;
current_match.orgstart = current_match.strstart;
/* Find the longest match, discarding those <= prev_length.
* At this point we have always match_length < WANT_MIN_MATCH
*/
let dist = state.strstart as i64 - hash_head as i64;
if dist <= state.max_dist() as i64 && dist > 0 && hash_head != 0 {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
let (match_length, match_start) =
crate::deflate::longest_match::longest_match(state, hash_head);
state.match_start = match_start;
current_match.match_length = match_length as u16;
current_match.match_start = match_start as u16;
if (current_match.match_length as usize) < WANT_MIN_MATCH {
current_match.match_length = 1;
}
if current_match.match_start >= current_match.strstart {
/* this can happen due to some restarts */
current_match.match_length = 1;
}
} else {
/* Set up the match to be a 1 byte literal */
current_match.match_start = 0;
current_match.match_length = 1;
}
}
insert_match(state, current_match);
/* now, look ahead one */
if !early_exit
&& state.lookahead > MIN_LOOKAHEAD
&& ((current_match.strstart + current_match.match_length) as usize)
< (state.window_size - MIN_LOOKAHEAD)
{
state.strstart = (current_match.strstart + current_match.match_length) as usize;
hash_head = state.quick_insert_string(state.strstart);
next_match.strstart = state.strstart as u16;
next_match.orgstart = next_match.strstart;
/* Find the longest match, discarding those <= prev_length.
* At this point we have always match_length < WANT_MIN_MATCH
*/
let dist = state.strstart as i64 - hash_head as i64;
if dist <= state.max_dist() as i64 && dist > 0 && hash_head != 0 {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
let (match_length, match_start) =
crate::deflate::longest_match::longest_match(state, hash_head);
state.match_start = match_start;
next_match.match_length = match_length as u16;
next_match.match_start = match_start as u16;
if next_match.match_start >= next_match.strstart {
/* this can happen due to some restarts */
next_match.match_length = 1;
}
if (next_match.match_length as usize) < WANT_MIN_MATCH {
next_match.match_length = 1;
} else {
fizzle_matches(
state.window.filled(),
state.max_dist(),
&mut current_match,
&mut next_match,
);
}
} else {
/* Set up the match to be a 1 byte literal */
next_match.match_start = 0;
next_match.match_length = 1;
}
state.strstart = current_match.strstart as usize;
} else {
next_match.match_length = 0;
}
/* now emit the current match */
let bflush = emit_match(state, current_match);
/* move the "cursor" forward */
state.strstart += current_match.match_length as usize;
if bflush {
flush_block!(stream, false);
}
}
stream.state.insert = Ord::min(stream.state.strstart, STD_MIN_MATCH - 1);
if flush == DeflateFlush::Finish {
flush_block!(stream, true);
return BlockState::FinishDone;
}
if !stream.state.sym_buf.is_empty() {
flush_block!(stream, false);
}
BlockState::BlockDone
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct Match {
match_start: u16,
match_length: u16,
strstart: u16,
orgstart: u16,
}
fn emit_match(state: &mut State, mut m: Match) -> bool {
let mut bflush = false;
/* matches that are not long enough we need to emit as literals */
if (m.match_length as usize) < WANT_MIN_MATCH {
while m.match_length > 0 {
let lc = state.window.filled()[state.strstart];
bflush |= state.tally_lit(lc);
state.lookahead -= 1;
m.strstart += 1;
m.match_length -= 1;
}
return bflush;
}
// check_match(s, m.strstart, m.match_start, m.match_length);
bflush |= state.tally_dist(
(m.strstart - m.match_start) as usize,
m.match_length as usize - STD_MIN_MATCH,
);
state.lookahead -= m.match_length as usize;
bflush
}
fn insert_match(state: &mut State, mut m: Match) {
if state.lookahead <= (m.match_length as usize + WANT_MIN_MATCH) {
return;
}
/* matches that are not long enough we need to emit as literals */
if (m.match_length as usize) < WANT_MIN_MATCH {
m.strstart += 1;
m.match_length -= 1;
if m.match_length > 0 && m.strstart >= m.orgstart {
if m.strstart + m.match_length > m.orgstart {
state.insert_string(m.strstart as usize, m.match_length as usize);
} else {
state.insert_string(m.strstart as usize, (m.orgstart - m.strstart + 1) as usize);
}
m.strstart += m.match_length;
m.match_length = 0;
}
return;
}
/* Insert new strings in the hash table only if the match length
* is not too large. This saves time but degrades compression.
*/
if (m.match_length as usize) <= 16 * state.max_insert_length()
&& state.lookahead >= WANT_MIN_MATCH
{
m.match_length -= 1; /* string at strstart already in table */
m.strstart += 1;
if m.strstart >= m.orgstart {
if m.strstart + m.match_length > m.orgstart {
state.insert_string(m.strstart as usize, m.match_length as usize);
} else {
state.insert_string(m.strstart as usize, (m.orgstart - m.strstart + 1) as usize);
}
} else if m.orgstart < m.strstart + m.match_length {
state.insert_string(
m.orgstart as usize,
(m.strstart + m.match_length - m.orgstart) as usize,
);
}
m.strstart += m.match_length;
m.match_length = 0;
} else {
m.strstart += m.match_length;
m.match_length = 0;
if (m.strstart as usize) >= (STD_MIN_MATCH - 2) {
state.quick_insert_string(m.strstart as usize + 2 - STD_MIN_MATCH);
}
/* If lookahead < WANT_MIN_MATCH, ins_h is garbage, but it does not
* matter since it will be recomputed at next deflate call.
*/
}
}
fn fizzle_matches(window: &[u8], max_dist: usize, current: &mut Match, next: &mut Match) {
/* step zero: sanity checks */
if current.match_length <= 1 {
return;
}
if current.match_length > 1 + next.match_start {
return;
}
if current.match_length > 1 + next.strstart {
return;
}
let m = &window[(-(current.match_length as isize) + 1 + next.match_start as isize) as usize..];
let orig = &window[(-(current.match_length as isize) + 1 + next.strstart as isize) as usize..];
/* quick exit check.. if this fails then don't bother with anything else */
if m[0] != orig[0] {
return;
}
/* step one: try to move the "next" match to the left as much as possible */
let limit = next.strstart.saturating_sub(max_dist as u16);
let mut c = *current;
let mut n = *next;
let m = &window[..n.match_start as usize];
let orig = &window[..n.strstart as usize];
let mut m = m.iter().rev();
let mut orig = orig.iter().rev();
let mut changed = 0;
while m.next() == orig.next() {
if c.match_length < 1 {
break;
}
if n.strstart <= limit {
break;
}
if n.match_length >= 256 {
break;
}
if n.match_start <= 1 {
break;
}
n.strstart -= 1;
n.match_start -= 1;
n.match_length += 1;
c.match_length -= 1;
changed += 1;
}
if changed == 0 {
return;
}
if c.match_length <= 1 && n.match_length != 2 {
n.orgstart += 1;
*current = c;
*next = n;
}
}

View File

@ -0,0 +1,83 @@
use crate::{
deflate::{BlockState, DeflateStream, Strategy},
DeflateFlush,
};
use self::{huff::deflate_huff, rle::deflate_rle, stored::deflate_stored};
mod fast;
mod huff;
mod medium;
mod quick;
mod rle;
mod slow;
mod stored;
#[macro_export]
macro_rules! flush_block {
($stream:expr, $is_last_block:expr) => {
$crate::deflate::flush_block_only($stream, $is_last_block);
if $stream.avail_out == 0 {
return match $is_last_block {
true => BlockState::FinishStarted,
false => BlockState::NeedMore,
};
}
};
}
pub fn run(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
match stream.state.strategy {
_ if stream.state.level == 0 => deflate_stored(stream, flush),
Strategy::HuffmanOnly => deflate_huff(stream, flush),
Strategy::Rle => deflate_rle(stream, flush),
Strategy::Default | Strategy::Filtered | Strategy::Fixed => {
(CONFIGURATION_TABLE[stream.state.level as usize].func)(stream, flush)
}
}
}
type CompressFunc = fn(&mut DeflateStream, flush: DeflateFlush) -> BlockState;
#[allow(unused)]
pub struct Config {
pub good_length: u16, /* reduce lazy search above this match length */
pub max_lazy: u16, /* do not perform lazy search above this match length */
pub nice_length: u16, /* quit search above this match length */
pub max_chain: u16,
pub func: CompressFunc,
}
impl Config {
const fn new(
good_length: u16,
max_lazy: u16,
nice_length: u16,
max_chain: u16,
func: CompressFunc,
) -> Self {
Self {
good_length,
max_lazy,
nice_length,
max_chain,
func,
}
}
}
pub const CONFIGURATION_TABLE: [Config; 10] = {
[
Config::new(0, 0, 0, 0, stored::deflate_stored), // 0 /* store only */
Config::new(0, 0, 0, 0, quick::deflate_quick), // 1
Config::new(4, 4, 8, 4, fast::deflate_fast), // 2 /* max speed, no lazy matches */
Config::new(4, 6, 16, 6, medium::deflate_medium), // 3
Config::new(4, 12, 32, 24, medium::deflate_medium), // 4 /* lazy matches */
Config::new(8, 16, 32, 32, medium::deflate_medium), // 5
Config::new(8, 16, 128, 128, medium::deflate_medium), // 6
Config::new(8, 32, 128, 256, slow::deflate_slow), // 7
Config::new(32, 128, 258, 1024, slow::deflate_slow), // 8
Config::new(32, 258, 258, 4096, slow::deflate_slow), // 9 /* max compression */
]
};

View File

@ -0,0 +1,149 @@
#![forbid(unsafe_code)]
use crate::{
deflate::{
fill_window, flush_pending, BlockState, BlockType, DeflateStream, State, StaticTreeDesc,
MIN_LOOKAHEAD, STD_MAX_MATCH, STD_MIN_MATCH, WANT_MIN_MATCH,
},
DeflateFlush,
};
pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
let mut state = &mut stream.state;
let last = matches!(flush, DeflateFlush::Finish);
macro_rules! quick_start_block {
() => {
state.bit_writer.emit_tree(BlockType::StaticTrees, last);
state.block_open = 1 + last as u8;
state.block_start = state.strstart as isize;
};
}
macro_rules! quick_end_block {
() => {
if state.block_open > 0 {
state
.bit_writer
.emit_end_block_and_align(&StaticTreeDesc::L.static_tree, last);
state.block_open = 0;
state.block_start = state.strstart as isize;
flush_pending(stream);
#[allow(unused_assignments)]
{
state = &mut stream.state;
}
if stream.avail_out == 0 {
return match last {
true => BlockState::FinishStarted,
false => BlockState::NeedMore,
};
}
}
};
}
if last && state.block_open != 2 {
/* Emit end of previous block */
quick_end_block!();
/* Emit start of last block */
quick_start_block!();
} else if state.block_open == 0 && state.lookahead > 0 {
/* Start new block only when we have lookahead data, so that if no
input data is given an empty block will not be written */
quick_start_block!();
}
loop {
if state.bit_writer.pending.pending + State::BIT_BUF_SIZE.div_ceil(8) as usize
>= state.pending_buf_size()
{
flush_pending(stream);
state = &mut stream.state;
if stream.avail_out == 0 {
return if last
&& stream.avail_in == 0
&& state.bit_writer.bits_used == 0
&& state.block_open == 0
{
BlockState::FinishStarted
} else {
BlockState::NeedMore
};
}
}
if state.lookahead < MIN_LOOKAHEAD {
fill_window(stream);
state = &mut stream.state;
if state.lookahead < MIN_LOOKAHEAD && matches!(flush, DeflateFlush::NoFlush) {
return BlockState::NeedMore;
}
if state.lookahead == 0 {
break;
}
if state.block_open == 0 {
// Start new block when we have lookahead data,
// so that if no input data is given an empty block will not be written
quick_start_block!();
}
}
if state.lookahead >= WANT_MIN_MATCH {
let hash_head = state.quick_insert_string(state.strstart);
let dist = state.strstart as isize - hash_head as isize;
if dist <= state.max_dist() as isize && dist > 0 {
let str_start = &state.window.filled()[state.strstart..];
let match_start = &state.window.filled()[hash_head as usize..];
if str_start[0] == match_start[0] && str_start[1] == match_start[1] {
let mut match_len = crate::deflate::compare256::compare256_slice(
&str_start[2..],
&match_start[2..],
) + 2;
if match_len >= WANT_MIN_MATCH {
match_len = Ord::min(match_len, state.lookahead);
match_len = Ord::min(match_len, STD_MAX_MATCH);
// TODO do this with a debug_assert?
// check_match(s, state.strstart, hash_head, match_len);
state.bit_writer.emit_dist(
StaticTreeDesc::L.static_tree,
StaticTreeDesc::D.static_tree,
(match_len - STD_MIN_MATCH) as u8,
dist as usize,
);
state.lookahead -= match_len;
state.strstart += match_len;
continue;
}
}
}
}
let lc = state.window.filled()[state.strstart];
state.bit_writer.emit_lit(StaticTreeDesc::L.static_tree, lc);
state.strstart += 1;
state.lookahead -= 1;
}
state.insert = if state.strstart < (STD_MIN_MATCH - 1) {
state.strstart
} else {
STD_MIN_MATCH - 1
};
if last {
quick_end_block!();
return BlockState::FinishDone;
}
quick_end_block!();
BlockState::BlockDone
}

View File

@ -0,0 +1,83 @@
#![forbid(unsafe_code)]
use crate::{
deflate::{
compare256::compare256_rle_slice, fill_window, BlockState, DeflateStream, MIN_LOOKAHEAD,
STD_MAX_MATCH, STD_MIN_MATCH,
},
flush_block, DeflateFlush,
};
pub fn deflate_rle(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
let mut match_len = 0;
let mut bflush;
loop {
// Make sure that we always have enough lookahead, except
// at the end of the input file. We need STD_MAX_MATCH bytes
// for the next match, plus WANT_MIN_MATCH bytes to insert the
// string following the next match.
if stream.state.lookahead < MIN_LOOKAHEAD {
fill_window(stream);
if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush {
return BlockState::NeedMore;
}
if stream.state.lookahead == 0 {
break; /* flush the current block */
}
}
/* See how many times the previous byte repeats */
let state = &mut stream.state;
if state.lookahead >= STD_MIN_MATCH && state.strstart > 0 {
let scan = &state.window.filled()[state.strstart - 1..][..3 + 256];
{
if scan[0] == scan[1] && scan[1] == scan[2] {
match_len = compare256_rle_slice(scan[0], &scan[3..]) + 2;
match_len = Ord::min(match_len, state.lookahead);
match_len = Ord::min(match_len, STD_MAX_MATCH);
}
}
assert!(
state.strstart - 1 + match_len <= state.window_size - 1,
"wild scan"
);
}
/* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */
if match_len >= STD_MIN_MATCH {
// check_match(s, s->strstart, s->strstart - 1, match_len);
bflush = state.tally_dist(1, match_len - STD_MIN_MATCH);
state.lookahead -= match_len;
state.strstart += match_len;
match_len = 0;
} else {
/* No match, output a literal byte */
let lc = state.window.filled()[state.strstart];
bflush = state.tally_lit(lc);
state.lookahead -= 1;
state.strstart += 1;
}
if bflush {
flush_block!(stream, false);
}
}
stream.state.insert = 0;
if flush == DeflateFlush::Finish {
flush_block!(stream, true);
return BlockState::FinishDone;
}
if !stream.state.sym_buf.is_empty() {
flush_block!(stream, false);
}
BlockState::BlockDone
}

View File

@ -0,0 +1,160 @@
#![forbid(unsafe_code)]
use crate::{
deflate::{
fill_window, flush_block_only, BlockState, DeflateStream, Strategy, MIN_LOOKAHEAD,
STD_MIN_MATCH, WANT_MIN_MATCH,
},
flush_block, DeflateFlush,
};
pub fn deflate_slow(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
let mut hash_head; /* head of hash chain */
let mut bflush; /* set if current block must be flushed */
let mut dist;
let mut match_len;
let use_longest_match_slow = stream.state.max_chain_length > 1024;
let valid_distance_range = 1..=stream.state.max_dist() as isize;
let mut match_available = stream.state.match_available;
/* Process the input block. */
loop {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need STD_MAX_MATCH bytes
* for the next match, plus WANT_MIN_MATCH bytes to insert the
* string following the next match.
*/
if stream.state.lookahead < MIN_LOOKAHEAD {
fill_window(stream);
if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush {
return BlockState::NeedMore;
}
if stream.state.lookahead == 0 {
break; /* flush the current block */
}
}
let state = &mut stream.state;
/* Insert the string window[strstart .. strstart+2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = if state.lookahead >= WANT_MIN_MATCH {
state.quick_insert_string(state.strstart)
} else {
0
};
// Find the longest match, discarding those <= prev_length.
state.prev_match = state.match_start as u16;
match_len = STD_MIN_MATCH - 1;
dist = state.strstart as isize - hash_head as isize;
if valid_distance_range.contains(&dist)
&& state.prev_length < state.max_lazy_match
&& hash_head != 0
{
// To simplify the code, we prevent matches with the string
// of window index 0 (in particular we have to avoid a match
// of the string with itself at the start of the input file).
(match_len, state.match_start) = if use_longest_match_slow {
crate::deflate::longest_match::longest_match_slow(state, hash_head)
} else {
crate::deflate::longest_match::longest_match(state, hash_head)
};
if match_len <= 5 && (state.strategy == Strategy::Filtered) {
/* If prev_match is also WANT_MIN_MATCH, match_start is garbage
* but we will ignore the current match anyway.
*/
match_len = STD_MIN_MATCH - 1;
}
}
// If there was a match at the previous step and the current
// match is not better, output the previous match:
if state.prev_length >= STD_MIN_MATCH && match_len <= state.prev_length {
let max_insert = state.strstart + state.lookahead - STD_MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
// check_match(s, state.strstart-1, state.prev_match, state.prev_length);
bflush = state.tally_dist(
state.strstart - 1 - state.prev_match as usize,
state.prev_length - STD_MIN_MATCH,
);
/* Insert in hash table all strings up to the end of the match.
* strstart-1 and strstart are already inserted. If there is not
* enough lookahead, the last two strings are not inserted in
* the hash table.
*/
state.prev_length -= 1;
state.lookahead -= state.prev_length;
let mov_fwd = state.prev_length - 1;
if max_insert > state.strstart {
let insert_cnt = Ord::min(mov_fwd, max_insert - state.strstart);
state.insert_string(state.strstart + 1, insert_cnt);
}
state.prev_length = 0;
state.match_available = false;
match_available = false;
state.strstart += mov_fwd + 1;
if bflush {
flush_block!(stream, false);
}
} else if match_available {
// If there was no match at the previous position, output a
// single literal. If there was a match but the current match
// is longer, truncate the previous match to a single literal.
let lc = state.window.filled()[state.strstart - 1];
bflush = state.tally_lit(lc);
if bflush {
flush_block_only(stream, false);
}
stream.state.prev_length = match_len;
stream.state.strstart += 1;
stream.state.lookahead -= 1;
if stream.avail_out == 0 {
return BlockState::NeedMore;
}
} else {
// There is no previous match to compare with, wait for
// the next step to decide.
state.prev_length = match_len;
state.match_available = true;
match_available = true;
state.strstart += 1;
state.lookahead -= 1;
}
}
assert_ne!(flush, DeflateFlush::NoFlush, "no flush?");
let state = &mut stream.state;
if state.match_available {
let lc = state.window.filled()[state.strstart - 1];
let _ = state.tally_lit(lc);
state.match_available = false;
}
state.insert = Ord::min(state.strstart, STD_MIN_MATCH - 1);
if flush == DeflateFlush::Finish {
flush_block!(stream, true);
return BlockState::FinishDone;
}
if !stream.state.sym_buf.is_empty() {
flush_block!(stream, false);
}
BlockState::BlockDone
}

View File

@ -0,0 +1,271 @@
use crate::{
deflate::{
flush_pending, read_buf_window, zng_tr_stored_block, BlockState, DeflateStream, MAX_STORED,
},
DeflateFlush,
};
pub fn deflate_stored(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState {
// Smallest worthy block size when not flushing or finishing. By default
// this is 32K. This can be as small as 507 bytes for memLevel == 1. For
// large input and output buffers, the stored block size will be larger.
let min_block = Ord::min(
stream.state.bit_writer.pending.capacity() - 5,
stream.state.w_size,
);
// Copy as many min_block or larger stored blocks directly to next_out as
// possible. If flushing, copy the remaining available input to next_out as
// stored blocks, if there is enough space.
// unsigned len, left, have, last = 0;
let mut have;
let mut last = false;
let mut used = stream.avail_in;
loop {
// maximum deflate stored block length
let mut len = MAX_STORED;
// number of header bytes
have = ((stream.state.bit_writer.bits_used + 42) / 8) as usize;
// we need room for at least the header
if stream.avail_out < have as u32 {
break;
}
let left = stream.state.strstart as isize - stream.state.block_start;
let left = Ord::max(0, left) as usize;
have = stream.avail_out as usize - have;
if len > left + stream.avail_in as usize {
// limit len to the input
len = left + stream.avail_in as usize;
}
len = Ord::min(len, have);
// If the stored block would be less than min_block in length, or if
// unable to copy all of the available input when flushing, then try
// copying to the window and the pending buffer instead. Also don't
// write an empty block when flushing -- deflate() does that.
if len < min_block
&& ((len == 0 && flush != DeflateFlush::Finish)
|| flush == DeflateFlush::NoFlush
|| len != left + stream.avail_in as usize)
{
break;
}
// Make a dummy stored block in pending to get the header bytes,
// including any pending bits. This also updates the debugging counts.
last = flush == DeflateFlush::Finish && len == left + stream.avail_in as usize;
zng_tr_stored_block(stream.state, 0..0, last);
/* Replace the lengths in the dummy stored block with len. */
stream.state.bit_writer.pending.rewind(4);
stream
.state
.bit_writer
.pending
.extend(&(len as u16).to_le_bytes());
stream
.state
.bit_writer
.pending
.extend(&(!len as u16).to_le_bytes());
// Write the stored block header bytes.
flush_pending(stream);
// TODO debug counts?
if left > 0 {
let left = Ord::min(left, len);
let src = &stream.state.window.filled()[stream.state.block_start as usize..];
unsafe { core::ptr::copy_nonoverlapping(src.as_ptr(), stream.next_out, left) };
stream.next_out = stream.next_out.wrapping_add(left);
stream.avail_out = stream.avail_out.wrapping_sub(left as _);
stream.total_out = stream.total_out.wrapping_add(left as _);
stream.state.block_start += left as isize;
len -= left;
}
// Copy uncompressed bytes directly from next_in to next_out, updating the check value.
if len > 0 {
read_buf_direct_copy(stream, len);
}
if last {
break;
}
}
// Update the sliding window with the last s->w_size bytes of the copied
// data, or append all of the copied data to the existing window if less
// than s->w_size bytes were copied. Also update the number of bytes to
// insert in the hash tables, in the event that deflateParams() switches to
// a non-zero compression level.
used -= stream.avail_in; /* number of input bytes directly copied */
if used > 0 {
let state = &mut stream.state;
// If any input was used, then no unused input remains in the window, therefore s->block_start == s->strstart.
if used as usize >= state.w_size {
/* supplant the previous history */
state.matches = 2; /* clear hash */
let src = stream.next_in.wrapping_sub(state.w_size);
unsafe { state.window.copy_and_initialize(0..state.w_size, src) };
state.strstart = state.w_size;
state.insert = state.strstart;
} else {
if state.window_size - state.strstart <= used as usize {
/* Slide the window down. */
state.strstart -= state.w_size;
state
.window
.filled_mut()
.copy_within(state.w_size..state.w_size + state.strstart, 0);
if state.matches < 2 {
state.matches += 1; /* add a pending slide_hash() */
}
state.insert = Ord::min(state.insert, state.strstart);
}
let src = stream.next_in.wrapping_sub(used as usize);
let dst = state.strstart..state.strstart + used as usize;
unsafe { state.window.copy_and_initialize(dst, src) };
state.strstart += used as usize;
state.insert += Ord::min(used as usize, state.w_size - state.insert);
}
state.block_start = state.strstart as isize;
}
if last {
return BlockState::FinishDone;
}
// If flushing and all input has been consumed, then done.
if flush != DeflateFlush::NoFlush
&& flush != DeflateFlush::Finish
&& stream.avail_in == 0
&& stream.state.strstart as isize == stream.state.block_start
{
return BlockState::BlockDone;
}
// Fill the window with any remaining input
let mut have = stream.state.window_size - stream.state.strstart;
if stream.avail_in as usize > have && stream.state.block_start >= stream.state.w_size as isize {
// slide the window down
let state = &mut stream.state;
state.block_start -= state.w_size as isize;
state.strstart -= state.w_size;
state
.window
.filled_mut()
.copy_within(state.w_size..state.w_size + state.strstart, 0);
if state.matches < 2 {
// add a pending slide_hash
state.matches += 1;
}
have += state.w_size; // more space now
state.insert = Ord::min(state.insert, state.strstart);
}
let have = Ord::min(have, stream.avail_in as usize);
if have > 0 {
read_buf_window(stream, stream.state.strstart, have);
let state = &mut stream.state;
state.strstart += have;
state.insert += Ord::min(have, state.w_size - state.insert);
}
// There was not enough avail_out to write a complete worthy or flushed
// stored block to next_out. Write a stored block to pending instead, if we
// have enough input for a worthy block, or if flushing and there is enough
// room for the remaining input as a stored block in the pending buffer.
// number of header bytes
let state = &mut stream.state;
let have = ((state.bit_writer.bits_used + 42) >> 3) as usize;
// maximum stored block length that will fit in pending:
let have = Ord::min(state.bit_writer.pending.capacity() - have, MAX_STORED);
let min_block = Ord::min(have, state.w_size);
let left = state.strstart as isize - state.block_start;
if left >= min_block as isize
|| ((left > 0 || flush == DeflateFlush::Finish)
&& flush != DeflateFlush::NoFlush
&& stream.avail_in == 0
&& left <= have as isize)
{
let len = Ord::min(left as usize, have); // TODO wrapping?
last = flush == DeflateFlush::Finish && stream.avail_in == 0 && len == (left as usize);
let range = state.block_start as usize..state.block_start as usize + len;
zng_tr_stored_block(state, range, last);
state.block_start += len as isize;
flush_pending(stream);
}
// We've done all we can with the available input and output.
if last {
BlockState::FinishStarted
} else {
BlockState::NeedMore
}
}
fn read_buf_direct_copy(stream: &mut DeflateStream, size: usize) -> usize {
let len = Ord::min(stream.avail_in as usize, size);
let output = stream.next_out;
if len == 0 {
return 0;
}
stream.avail_in -= len as u32;
if stream.state.wrap == 2 {
// we likely cannot fuse the crc32 and the copy here because the input can be changed by
// a concurrent thread. Therefore it cannot be converted into a slice!
unsafe { core::ptr::copy_nonoverlapping(stream.next_in, output, len) }
let data = unsafe { core::slice::from_raw_parts(output, len) };
stream.state.crc_fold.fold(data, 0);
} else if stream.state.wrap == 1 {
// we cannot fuse the adler and the copy in our case, because adler32 takes a slice.
// Another process is allowed to concurrently modify stream.next_in, so we cannot turn it
// into a rust slice (violates its safety requirements)
unsafe { core::ptr::copy_nonoverlapping(stream.next_in, output, len) }
let data = unsafe { core::slice::from_raw_parts(output, len) };
stream.adler = crate::adler32::adler32(stream.adler as u32, data) as _;
} else {
unsafe { core::ptr::copy_nonoverlapping(stream.next_in, output, len) }
}
stream.next_in = stream.next_in.wrapping_add(len);
stream.total_in += len as crate::c_api::z_size;
stream.next_out = stream.next_out.wrapping_add(len as _);
stream.avail_out = stream.avail_out.wrapping_sub(len as _);
stream.total_out = stream.total_out.wrapping_add(len as _);
len
}

View File

@ -0,0 +1,216 @@
#[cfg(test)]
const MAX_COMPARE_SIZE: usize = 256;
pub fn compare256_slice(src0: &[u8], src1: &[u8]) -> usize {
let src0 = first_chunk::<_, 256>(src0).unwrap();
let src1 = first_chunk::<_, 256>(src1).unwrap();
compare256(src0, src1)
}
fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize {
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("avx2") {
debug_assert_eq!(avx2::compare256(src0, src1), rust::compare256(src0, src1));
return avx2::compare256(src0, src1);
}
#[cfg(all(target_arch = "aarch64", feature = "std"))]
if std::arch::is_aarch64_feature_detected!("neon") {
debug_assert_eq!(neon::compare256(src0, src1), rust::compare256(src0, src1));
return neon::compare256(src0, src1);
}
rust::compare256(src0, src1)
}
pub fn compare256_rle_slice(byte: u8, src: &[u8]) -> usize {
rust::compare256_rle(byte, src)
}
#[inline]
pub const fn first_chunk<T, const N: usize>(slice: &[T]) -> Option<&[T; N]> {
if slice.len() < N {
None
} else {
// SAFETY: We explicitly check for the correct number of elements,
// and do not let the reference outlive the slice.
Some(unsafe { &*(slice.as_ptr() as *const [T; N]) })
}
}
mod rust {
pub fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize {
// only unrolls 4 iterations; zlib-ng unrolls 8
src0.iter().zip(src1).take_while(|(x, y)| x == y).count()
}
// run-length encoding
pub fn compare256_rle(byte: u8, src: &[u8]) -> usize {
assert!(src.len() >= 256, "too short {}", src.len());
let mut sv = byte as u64;
sv |= sv << 8;
sv |= sv << 16;
sv |= sv << 32;
let mut len = 0;
// this optimizes well because we statically limit the slice to 256 bytes.
// the loop gets unrolled 4 times automatically.
for chunk in src[..256].chunks_exact(8) {
let mv = u64::from_ne_bytes(chunk.try_into().unwrap());
let diff = sv ^ mv;
if diff > 0 {
let match_byte = diff.trailing_zeros() / 8;
return len + match_byte as usize;
}
len += 8
}
256
}
#[test]
fn test_compare256() {
let str1 = [b'a'; super::MAX_COMPARE_SIZE];
let mut str2 = [b'a'; super::MAX_COMPARE_SIZE];
for i in 0..str1.len() {
str2[i] = 0;
let match_len = compare256(&str1, &str2);
assert_eq!(match_len, i);
str2[i] = b'a';
}
}
#[test]
fn test_compare256_rle() {
let mut string = [b'a'; super::MAX_COMPARE_SIZE];
for i in 0..string.len() {
string[i] = 0;
let match_len = compare256_rle(b'a', &string);
assert_eq!(match_len, i);
string[i] = b'a';
}
}
}
#[cfg(target_arch = "aarch64")]
mod neon {
use core::arch::aarch64::{
uint8x16_t, veorq_u8, vgetq_lane_u64, vld1q_u8, vreinterpretq_u64_u8,
};
pub fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize {
let src0: &[[u8; 16]; 16] = unsafe { core::mem::transmute(src0) };
let src1: &[[u8; 16]; 16] = unsafe { core::mem::transmute(src1) };
let mut len = 0;
for (a, b) in src0.iter().zip(src1) {
unsafe {
let a: uint8x16_t = vld1q_u8(a.as_ptr());
let b: uint8x16_t = vld1q_u8(b.as_ptr());
let cmp = veorq_u8(a, b);
let lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 0);
if lane != 0 {
let match_byte = lane.trailing_zeros() / 8;
return len + match_byte as usize;
}
len += 8;
let lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 1);
if lane != 0 {
let match_byte = lane.trailing_zeros() / 8;
return len + match_byte as usize;
}
len += 8;
}
}
256
}
#[test]
fn test_compare256() {
if std::arch::is_aarch64_feature_detected!("neon") {
let str1 = [b'a'; super::MAX_COMPARE_SIZE];
let mut str2 = [b'a'; super::MAX_COMPARE_SIZE];
for i in 0..str1.len() {
str2[i] = 0;
let match_len = compare256(&str1, &str2);
assert_eq!(match_len, i);
str2[i] = b'a';
}
}
}
}
#[cfg(target_arch = "x86_64")]
mod avx2 {
use core::arch::x86_64::{
__m256i, _mm256_cmpeq_epi8, _mm256_loadu_si256, _mm256_movemask_epi8,
};
pub fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize {
let src0: &[[u8; 32]; 8] = unsafe { core::mem::transmute(src0) };
let src1: &[[u8; 32]; 8] = unsafe { core::mem::transmute(src1) };
let mut len = 0;
unsafe {
for (chunk0, chunk1) in src0.iter().zip(src1) {
let ymm_src0 = _mm256_loadu_si256(chunk0.as_ptr() as *const __m256i);
let ymm_src1 = _mm256_loadu_si256(chunk1.as_ptr() as *const __m256i);
let ymm_cmp = _mm256_cmpeq_epi8(ymm_src0, ymm_src1); /* non-identical bytes = 00, identical bytes = FF */
let mask = _mm256_movemask_epi8(ymm_cmp) as u32;
if mask != 0xFFFFFFFF {
let match_byte = (!mask).trailing_zeros(); /* Invert bits so identical = 0 */
return len + match_byte as usize;
}
len += 32;
}
}
256
}
#[test]
fn test_compare256() {
if std::arch::is_x86_feature_detected!("avx2") {
let str1 = [b'a'; super::MAX_COMPARE_SIZE];
let mut str2 = [b'a'; super::MAX_COMPARE_SIZE];
for i in 0..str1.len() {
str2[i] = 0;
let match_len = compare256(&str1, &str2);
assert_eq!(match_len, i);
str2[i] = b'a';
}
}
}
}

View File

@ -0,0 +1,209 @@
use crate::deflate::{State, HASH_SIZE, STD_MIN_MATCH};
#[derive(Debug, Clone, Copy)]
pub enum HashCalcVariant {
Standard,
Crc32,
Roll,
}
pub trait HashCalc {
const HASH_CALC_OFFSET: usize;
const HASH_CALC_MASK: u32;
fn hash_calc(h: u32, val: u32) -> u32;
fn update_hash(h: u32, val: u32) -> u32 {
Self::hash_calc(h, val) & Self::HASH_CALC_MASK
}
fn quick_insert_string(state: &mut State, string: usize) -> u16 {
let slice = &state.window.filled()[string + Self::HASH_CALC_OFFSET..];
let val = u32::from_ne_bytes(slice[..4].try_into().unwrap());
let hm = (Self::hash_calc(0, val) & Self::HASH_CALC_MASK) as usize;
let head = state.head[hm];
if head != string as u16 {
state.prev[string & state.w_mask] = head;
state.head[hm] = string as u16;
}
head
}
fn insert_string(state: &mut State, string: usize, count: usize) {
let slice = &state.window.filled()[string + Self::HASH_CALC_OFFSET..];
// .take(count) generates worse assembly
for (i, w) in slice[..count + 3].windows(4).enumerate() {
let idx = string as u16 + i as u16;
let val = u32::from_ne_bytes(w.try_into().unwrap());
let hm = (Self::hash_calc(0, val) & Self::HASH_CALC_MASK) as usize;
let head = state.head[hm];
if head != idx {
state.prev[idx as usize & state.w_mask] = head;
state.head[hm] = idx;
}
}
}
}
pub struct StandardHashCalc;
impl HashCalc for StandardHashCalc {
const HASH_CALC_OFFSET: usize = 0;
const HASH_CALC_MASK: u32 = (HASH_SIZE - 1) as u32;
fn hash_calc(_: u32, val: u32) -> u32 {
const HASH_SLIDE: u32 = 16;
val.wrapping_mul(2654435761) >> HASH_SLIDE
}
}
pub struct RollHashCalc;
impl HashCalc for RollHashCalc {
const HASH_CALC_OFFSET: usize = STD_MIN_MATCH - 1;
const HASH_CALC_MASK: u32 = (1 << 15) - 1;
fn hash_calc(h: u32, val: u32) -> u32 {
const HASH_SLIDE: u32 = 5;
(h << HASH_SLIDE) ^ val
}
fn quick_insert_string(state: &mut State, string: usize) -> u16 {
let val = state.window.filled()[string + Self::HASH_CALC_OFFSET] as u32;
state.ins_h = Self::hash_calc(state.ins_h as u32, val) as usize;
state.ins_h &= Self::HASH_CALC_MASK as usize;
let hm = state.ins_h;
let head = state.head[hm];
if head != string as u16 {
state.prev[string & state.w_mask] = head;
state.head[hm] = string as u16;
}
head
}
fn insert_string(state: &mut State, string: usize, count: usize) {
let slice = &state.window.filled()[string + Self::HASH_CALC_OFFSET..][..count];
for (i, val) in slice.iter().copied().enumerate() {
let idx = string as u16 + i as u16;
state.ins_h = Self::hash_calc(state.ins_h as u32, val as u32) as usize;
state.ins_h &= Self::HASH_CALC_MASK as usize;
let hm = state.ins_h;
let head = state.head[hm];
if head != idx {
state.prev[idx as usize & state.w_mask] = head;
state.head[hm] = idx;
}
}
}
}
pub struct Crc32HashCalc;
impl Crc32HashCalc {
pub fn is_supported() -> bool {
if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") {
return true;
}
// zlib-ng no longer special-cases on aarch64
#[cfg(all(target_arch = "aarch64", feature = "std"))]
// return std::arch::is_aarch64_feature_detected!("crc");
return false;
#[allow(unreachable_code)]
false
}
}
impl HashCalc for Crc32HashCalc {
const HASH_CALC_OFFSET: usize = 0;
const HASH_CALC_MASK: u32 = (HASH_SIZE - 1) as u32;
#[cfg(target_arch = "x86")]
fn hash_calc(h: u32, val: u32) -> u32 {
unsafe { core::arch::x86::_mm_crc32_u32(h, val) }
}
#[cfg(target_arch = "x86_64")]
fn hash_calc(h: u32, val: u32) -> u32 {
unsafe { core::arch::x86_64::_mm_crc32_u32(h, val) }
}
#[cfg(target_arch = "aarch64")]
fn hash_calc(h: u32, val: u32) -> u32 {
unsafe { crate::crc32::acle::__crc32cw(h, val) }
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
fn hash_calc(h: u32, val: u32) -> u32 {
assert!(!Self::is_supported());
unimplemented!("there is no hardware support on this platform")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn crc32_hash_calc() {
assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009);
assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466);
assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201);
assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009);
assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466);
assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201);
assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009);
assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466);
assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201);
assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009);
assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466);
assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201);
assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009);
assert_eq!(Crc32HashCalc::hash_calc(0, 170926112), 500028708);
assert_eq!(Crc32HashCalc::hash_calc(0, 537538592), 3694129053);
assert_eq!(Crc32HashCalc::hash_calc(0, 538970672), 373925026);
assert_eq!(Crc32HashCalc::hash_calc(0, 538976266), 4149335727);
assert_eq!(Crc32HashCalc::hash_calc(0, 538976288), 1767342659);
assert_eq!(Crc32HashCalc::hash_calc(0, 941629472), 4090502627);
assert_eq!(Crc32HashCalc::hash_calc(0, 775430176), 1744703325);
}
#[test]
fn roll_hash_calc() {
assert_eq!(RollHashCalc::hash_calc(2565, 93), 82173);
assert_eq!(RollHashCalc::hash_calc(16637, 10), 532394);
assert_eq!(RollHashCalc::hash_calc(8106, 100), 259364);
assert_eq!(RollHashCalc::hash_calc(29988, 101), 959717);
assert_eq!(RollHashCalc::hash_calc(9445, 98), 302274);
assert_eq!(RollHashCalc::hash_calc(7362, 117), 235573);
assert_eq!(RollHashCalc::hash_calc(6197, 103), 198343);
assert_eq!(RollHashCalc::hash_calc(1735, 32), 55488);
assert_eq!(RollHashCalc::hash_calc(22720, 61), 727101);
assert_eq!(RollHashCalc::hash_calc(6205, 32), 198528);
assert_eq!(RollHashCalc::hash_calc(3826, 117), 122421);
assert_eq!(RollHashCalc::hash_calc(24117, 101), 771781);
}
#[test]
fn standard_hash_calc() {
assert_eq!(StandardHashCalc::hash_calc(0, 721420288), 47872);
}
}

View File

@ -0,0 +1,318 @@
use crate::deflate::{State, MIN_LOOKAHEAD, STD_MAX_MATCH, STD_MIN_MATCH};
type Pos = u16;
const EARLY_EXIT_TRIGGER_LEVEL: i8 = 5;
pub fn longest_match(state: &crate::deflate::State, cur_match: u16) -> (usize, usize) {
longest_match_help::<false>(state, cur_match)
}
pub fn longest_match_slow(state: &crate::deflate::State, cur_match: u16) -> (usize, usize) {
longest_match_help::<true>(state, cur_match)
}
fn longest_match_help<const SLOW: bool>(
state: &crate::deflate::State,
mut cur_match: u16,
) -> (usize, usize) {
let mut match_start = state.match_start;
let strstart = state.strstart;
let wmask = state.w_mask;
let window = state.window.filled();
let scan = &window[strstart..];
let mut limit: Pos;
let limit_base: Pos;
let early_exit: bool;
let mut chain_length: usize;
let mut best_len: usize;
let lookahead = state.lookahead;
let mut match_offset = 0;
let mut scan_start = [0u8; 8];
let mut scan_end = [0u8; 8];
macro_rules! goto_next_in_chain {
() => {
chain_length -= 1;
if chain_length > 0 {
cur_match = state.prev[cur_match as usize & wmask];
if cur_match > limit {
continue;
}
}
return (best_len, match_start);
};
}
// The code is optimized for STD_MAX_MATCH-2 multiple of 16.
assert_eq!(STD_MAX_MATCH, 258, "Code too clever");
best_len = if state.prev_length > 0 {
state.prev_length
} else {
STD_MIN_MATCH - 1
};
let mut offset = best_len - 1;
// we're assuming we can do a fast(ish) unaligned 64-bit read
if best_len >= core::mem::size_of::<u64>() {
offset -= 4;
}
if best_len >= core::mem::size_of::<u32>() {
offset -= 2;
}
scan_start.copy_from_slice(&scan[..core::mem::size_of::<u64>()]);
scan_end.copy_from_slice(&scan[offset..][..core::mem::size_of::<u64>()]);
let mut mbase_start = window.as_ptr();
let mut mbase_end = window[offset..].as_ptr();
// Don't waste too much time by following a chain if we already have a good match
chain_length = state.max_chain_length;
if best_len >= state.good_match {
chain_length >>= 2;
}
let nice_match = state.nice_match;
// Stop when cur_match becomes <= limit. To simplify the code,
// we prevent matches with the string of window index 0
limit = strstart.saturating_sub(state.max_dist()) as Pos;
// look for a better string offset
if SLOW {
limit_base = limit;
if best_len >= STD_MIN_MATCH {
/* We're continuing search (lazy evaluation). */
let mut pos: Pos;
// Find a most distant chain starting from scan with index=1 (index=0 corresponds
// to cur_match). We cannot use s->prev[strstart+1,...] immediately, because
// these strings are not yet inserted into the hash table.
let Some([_cur_match, scan1, scan2, scanrest @ ..]) = scan.get(..best_len + 1) else {
panic!("invalid scan");
};
let mut hash = 0;
hash = state.update_hash(hash, *scan1 as u32);
hash = state.update_hash(hash, *scan2 as u32);
for (i, b) in scanrest.iter().enumerate() {
hash = state.update_hash(hash, *b as u32);
/* If we're starting with best_len >= 3, we can use offset search. */
pos = state.head[hash as usize];
if pos < cur_match {
match_offset = (i + 1) as Pos;
cur_match = pos;
}
}
/* Update offset-dependent variables */
limit = limit_base + match_offset;
if cur_match <= limit {
return break_matching(state, best_len, match_start);
}
mbase_start = mbase_start.wrapping_sub(match_offset as usize);
mbase_end = mbase_end.wrapping_sub(match_offset as usize);
}
early_exit = false;
} else {
// must initialize this variable
limit_base = 0;
early_exit = state.level < EARLY_EXIT_TRIGGER_LEVEL;
}
assert!(
strstart <= state.window_size - MIN_LOOKAHEAD,
"need lookahead"
);
loop {
if cur_match as usize >= strstart {
break;
}
// Skip to next match if the match length cannot increase or if the match length is
// less than 2. Note that the checks below for insufficient lookahead only occur
// occasionally for performance reasons.
// Therefore uninitialized memory will be accessed and conditional jumps will be made
// that depend on those values. However the length of the match is limited to the
// lookahead, so the output of deflate is not affected by the uninitialized values.
// # Safety
//
// The two pointers must be valid for reads of N bytes.
#[inline(always)]
unsafe fn memcmp_n_ptr<const N: usize>(src0: *const u8, src1: *const u8) -> bool {
let src0_cmp = core::ptr::read(src0 as *const [u8; N]);
let src1_cmp = core::ptr::read(src1 as *const [u8; N]);
src0_cmp == src1_cmp
}
#[inline(always)]
unsafe fn is_match<const N: usize>(
cur_match: u16,
mbase_start: *const u8,
mbase_end: *const u8,
scan_start: *const u8,
scan_end: *const u8,
) -> bool {
let be = mbase_end.wrapping_add(cur_match as usize);
let bs = mbase_start.wrapping_add(cur_match as usize);
memcmp_n_ptr::<N>(be, scan_end) && memcmp_n_ptr::<N>(bs, scan_start)
}
// first, do a quick check on the start and end bytes. Go to the next item in the chain if
// these bytes don't match.
unsafe {
let scan_start = scan_start.as_ptr();
let scan_end = scan_end.as_ptr();
if best_len < core::mem::size_of::<u32>() {
loop {
if is_match::<2>(cur_match, mbase_start, mbase_end, scan_start, scan_end) {
break;
}
goto_next_in_chain!();
}
} else if best_len >= core::mem::size_of::<u64>() {
loop {
if is_match::<8>(cur_match, mbase_start, mbase_end, scan_start, scan_end) {
break;
}
goto_next_in_chain!();
}
} else {
loop {
if is_match::<4>(cur_match, mbase_start, mbase_end, scan_start, scan_end) {
break;
}
goto_next_in_chain!();
}
}
}
// we know that there is at least some match. Now count how many bytes really match
let len = {
// TODO this just looks so incredibly unsafe!
let src1: &[u8; 256] =
unsafe { &*mbase_start.wrapping_add(cur_match as usize + 2).cast() };
crate::deflate::compare256::compare256_slice(&scan[2..], src1) + 2
};
assert!(
scan.as_ptr() as usize + len <= window.as_ptr() as usize + (state.window_size - 1),
"wild scan"
);
if len > best_len {
match_start = (cur_match - match_offset) as usize;
/* Do not look for matches beyond the end of the input. */
if len > lookahead {
return (lookahead, match_start);
}
best_len = len;
if best_len >= nice_match {
return (best_len, match_start);
}
offset = best_len - 1;
if best_len >= core::mem::size_of::<u32>() {
offset -= 2;
if best_len >= core::mem::size_of::<u64>() {
offset -= 4;
}
}
scan_end.copy_from_slice(&scan[offset..][..core::mem::size_of::<u64>()]);
// Look for a better string offset
if SLOW && len > STD_MIN_MATCH && match_start + len < strstart {
let mut pos: Pos;
// uint32_t i, hash;
// unsigned char *scan_endstr;
/* Go back to offset 0 */
cur_match -= match_offset;
match_offset = 0;
let mut next_pos = cur_match;
for i in 0..=len - STD_MIN_MATCH {
pos = state.prev[(cur_match as usize + i) & wmask];
if pos < next_pos {
/* Hash chain is more distant, use it */
if pos <= limit_base + i as Pos {
return break_matching(state, best_len, match_start);
}
next_pos = pos;
match_offset = i as Pos;
}
}
/* Switch cur_match to next_pos chain */
cur_match = next_pos;
/* Try hash head at len-(STD_MIN_MATCH-1) position to see if we could get
* a better cur_match at the end of string. Using (STD_MIN_MATCH-1) lets
* us include one more byte into hash - the byte which will be checked
* in main loop now, and which allows to grow match by 1.
*/
let [scan0, scan1, scan2, ..] = scan[len - (STD_MIN_MATCH + 1)..] else {
panic!("index out of bounds");
};
let mut hash = 0;
hash = state.update_hash(hash, scan0 as u32);
hash = state.update_hash(hash, scan1 as u32);
hash = state.update_hash(hash, scan2 as u32);
pos = state.head[hash as usize];
if pos < cur_match {
match_offset = (len - (STD_MIN_MATCH + 1)) as Pos;
if pos <= limit_base + match_offset {
return break_matching(state, best_len, match_start);
}
cur_match = pos;
}
/* Update offset-dependent variables */
limit = limit_base + match_offset;
mbase_start = window.as_ptr().wrapping_sub(match_offset as usize);
mbase_end = mbase_start.wrapping_add(offset);
continue;
}
mbase_end = mbase_start.wrapping_add(offset);
} else if !SLOW && early_exit {
// The probability of finding a match later if we here is pretty low, so for
// performance it's best to outright stop here for the lower compression levels
break;
}
goto_next_in_chain!();
}
(best_len, match_start)
}
fn break_matching(state: &State, best_len: usize, match_start: usize) -> (usize, usize) {
(Ord::min(best_len, state.lookahead), match_start)
}

View File

@ -0,0 +1,95 @@
use core::marker::PhantomData;
use crate::allocate::Allocator;
pub struct Pending<'a> {
buf: *mut u8,
out: *mut u8,
pub(crate) pending: usize,
end: *mut u8,
_marker: PhantomData<&'a mut [u8]>,
}
impl<'a> Pending<'a> {
pub fn reset_keep(&mut self) {
// keep the buffer as it is
self.pending = 0;
}
pub fn pending(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.out, self.pending) }
}
pub(crate) fn remaining(&self) -> usize {
self.end as usize - self.out as usize
}
pub(crate) fn capacity(&self) -> usize {
self.end as usize - self.buf as usize
}
#[inline(always)]
#[track_caller]
pub fn advance(&mut self, n: usize) {
assert!(n <= self.remaining(), "advancing past the end");
debug_assert!(self.pending >= n);
self.out = self.out.wrapping_add(n);
self.pending -= n;
if self.pending == 0 {
self.out = self.buf;
}
}
#[inline(always)]
#[track_caller]
pub fn rewind(&mut self, n: usize) {
assert!(n <= self.pending, "rewinding past then start");
self.pending -= n;
}
#[inline(always)]
#[track_caller]
pub fn extend(&mut self, buf: &[u8]) {
assert!(
self.remaining() >= buf.len(),
"buf.len() must fit in remaining()"
);
unsafe {
core::ptr::copy_nonoverlapping(buf.as_ptr(), self.out.add(self.pending), buf.len());
}
self.pending += buf.len();
}
pub(crate) fn new_in(alloc: &Allocator<'a>, len: usize) -> Option<Self> {
let range = alloc.allocate_slice::<u8>(len)?.as_mut_ptr_range();
Some(Self {
buf: range.start as *mut u8,
out: range.start as *mut u8,
end: range.end as *mut u8,
pending: 0,
_marker: PhantomData,
})
}
pub(crate) fn clone_in(&self, alloc: &Allocator<'a>) -> Option<Self> {
let len = self.end as usize - self.buf as usize;
let mut clone = Self::new_in(alloc, len)?;
unsafe { core::ptr::copy_nonoverlapping(self.buf, clone.buf, len) };
clone.out = unsafe { clone.buf.add(self.out as usize - self.buf as usize) };
clone.pending = self.pending;
Some(clone)
}
pub(crate) unsafe fn drop_in(&self, alloc: &Allocator) {
let len = self.end as usize - self.buf as usize;
alloc.deallocate(self.buf, len);
}
}

View File

@ -0,0 +1,164 @@
pub fn slide_hash(state: &mut crate::deflate::State) {
let wsize = state.w_size as u16;
slide_hash_chain(state.head, wsize);
slide_hash_chain(state.prev, wsize);
}
fn slide_hash_chain(table: &mut [u16], wsize: u16) {
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("avx2") {
return avx2::slide_hash_chain(table, wsize);
}
#[cfg(all(target_arch = "aarch64", feature = "std"))]
if std::arch::is_aarch64_feature_detected!("neon") {
return neon::slide_hash_chain(table, wsize);
}
rust::slide_hash_chain(table, wsize);
}
mod rust {
pub fn slide_hash_chain(table: &mut [u16], wsize: u16) {
for m in table.iter_mut() {
*m = m.saturating_sub(wsize);
}
}
}
#[cfg(target_arch = "aarch64")]
mod neon {
use core::arch::aarch64::{
uint16x8_t, uint16x8x4_t, vdupq_n_u16, vld1q_u16_x4, vqsubq_u16, vst1q_u16_x4,
};
pub fn slide_hash_chain(table: &mut [u16], wsize: u16) {
assert!(std::arch::is_aarch64_feature_detected!("neon"));
unsafe { slide_hash_chain_internal(table, wsize) }
}
#[target_feature(enable = "neon")]
unsafe fn slide_hash_chain_internal(table: &mut [u16], wsize: u16) {
debug_assert_eq!(table.len() % 32, 0);
let v = unsafe { vdupq_n_u16(wsize) };
for chunk in table.chunks_exact_mut(32) {
unsafe {
let p0 = vld1q_u16_x4(chunk.as_ptr());
let p0 = vqsubq_u16_x4_x1(p0, v);
vst1q_u16_x4(chunk.as_mut_ptr(), p0);
}
}
}
#[target_feature(enable = "neon")]
unsafe fn vqsubq_u16_x4_x1(a: uint16x8x4_t, b: uint16x8_t) -> uint16x8x4_t {
uint16x8x4_t(
vqsubq_u16(a.0, b),
vqsubq_u16(a.1, b),
vqsubq_u16(a.2, b),
vqsubq_u16(a.3, b),
)
}
}
#[cfg(target_arch = "x86_64")]
mod avx2 {
use core::arch::x86_64::{
__m256i, _mm256_loadu_si256, _mm256_set1_epi16, _mm256_storeu_si256, _mm256_subs_epu16,
};
pub fn slide_hash_chain(table: &mut [u16], wsize: u16) {
assert!(std::is_x86_feature_detected!("avx2"));
unsafe { slide_hash_chain_internal(table, wsize) }
}
#[target_feature(enable = "avx2")]
unsafe fn slide_hash_chain_internal(table: &mut [u16], wsize: u16) {
debug_assert_eq!(table.len() % 16, 0);
let ymm_wsize = unsafe { _mm256_set1_epi16(wsize as i16) };
for chunk in table.chunks_exact_mut(16) {
let chunk = chunk.as_mut_ptr() as *mut __m256i;
unsafe {
let value = _mm256_loadu_si256(chunk);
let result = _mm256_subs_epu16(value, ymm_wsize);
_mm256_storeu_si256(chunk, result);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const WSIZE: u16 = 32768;
const INPUT: [u16; 64] = [
0, 0, 28790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43884, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 64412, 0, 0, 0, 0, 0, 21043, 0, 0, 0, 0, 0, 23707, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 64026, 0, 0, 20182,
];
const OUTPUT: [u16; 64] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 31644, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 31258, 0, 0, 0,
];
#[test]
fn test_slide_hash_rust() {
let mut input = INPUT;
rust::slide_hash_chain(&mut input, WSIZE);
assert_eq!(input, OUTPUT);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_slide_hash_avx2() {
if std::arch::is_x86_feature_detected!("avx2") {
let mut input = INPUT;
avx2::slide_hash_chain(&mut input, WSIZE);
assert_eq!(input, OUTPUT);
}
}
#[test]
#[cfg(target_arch = "aarch64")]
fn test_slide_hash_neon() {
if std::arch::is_aarch64_feature_detected!("neon") {
let mut input = INPUT;
neon::slide_hash_chain(&mut input, WSIZE);
assert_eq!(input, OUTPUT);
}
}
quickcheck::quickcheck! {
fn slide_is_rust_slide(v: Vec<u16>, wsize: u16) -> bool {
// pad to a multiple of 32
let difference = v.len().next_multiple_of(32) - v.len();
let mut v = v;
v.extend(core::iter::repeat(u16::MAX).take(difference));
let mut a = v.clone();
let mut b = v;
rust::slide_hash_chain(&mut a, wsize);
slide_hash_chain(&mut b, wsize);
a == b
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,598 @@
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=10 M=100 Y=50 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>10.000002</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>50.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=95 Y=20 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>94.999999</xmpG:magenta>
<xmpG:yellow>19.999999</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=25 M=25 Y=40 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>25.000000</xmpG:cyan>
<xmpG:magenta>25.000000</xmpG:magenta>
<xmpG:yellow>39.999998</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=40 M=45 Y=50 K=5</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>39.999998</xmpG:cyan>
<xmpG:magenta>44.999999</xmpG:magenta>
<xmpG:yellow>50.000000</xmpG:yellow>
<xmpG:black>5.000001</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=50 M=50 Y=60 K=25</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>50.000000</xmpG:cyan>
<xmpG:magenta>50.000000</xmpG:magenta>
<xmpG:yellow>60.000002</xmpG:yellow>
<xmpG:black>25.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=55 M=60 Y=65 K=40</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>55.000001</xmpG:cyan>
<xmpG:magenta>60.000002</xmpG:magenta>
<xmpG:yellow>64.999998</xmpG:yellow>
<xmpG:black>39.999998</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=25 M=40 Y=65 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>25.000000</xmpG:cyan>
<xmpG:magenta>39.999998</xmpG:magenta>
<xmpG:yellow>64.999998</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=30 M=50 Y=75 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>30.000001</xmpG:cyan>
<xmpG:magenta>50.000000</xmpG:magenta>
<xmpG:yellow>75.000000</xmpG:yellow>
<xmpG:black>10.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=35 M=60 Y=80 K=25</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>35.000002</xmpG:cyan>
<xmpG:magenta>60.000002</xmpG:magenta>
<xmpG:yellow>80.000001</xmpG:yellow>
<xmpG:black>25.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=40 M=65 Y=90 K=35</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>39.999998</xmpG:cyan>
<xmpG:magenta>64.999998</xmpG:magenta>
<xmpG:yellow>90.000004</xmpG:yellow>
<xmpG:black>35.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=40 M=70 Y=100 K=50</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>39.999998</xmpG:cyan>
<xmpG:magenta>69.999999</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>50.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=50 M=70 Y=80 K=70</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>50.000000</xmpG:cyan>
<xmpG:magenta>69.999999</xmpG:magenta>
<xmpG:yellow>80.000001</xmpG:yellow>
<xmpG:black>69.999999</xmpG:black>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Grays</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=100</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>100.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=90</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>89.999402</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=80</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>79.998797</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=70</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>69.999701</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=60</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>59.999102</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=50</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>50.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=40</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>39.999402</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=30</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>29.998803</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=20</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>19.999701</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>9.999102</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=5</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>4.998803</xmpG:black>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Brights</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=100 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=75 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>75.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=10 Y=95 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>10.000002</xmpG:magenta>
<xmpG:yellow>94.999999</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=85 M=10 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>84.999996</xmpG:cyan>
<xmpG:magenta>10.000002</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=100 M=90 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>90.000004</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=60 M=90 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>60.000002</xmpG:cyan>
<xmpG:magenta>90.000004</xmpG:magenta>
<xmpG:yellow>0.003099</xmpG:yellow>
<xmpG:black>0.003099</xmpG:black>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<pdf:Producer>Adobe PDF library 9.00</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream endobj 145 0 obj<</Metadata 144 0 R>> endobj 1 0 obj<</Contents 3 0 R/Type/Page/Parent 102 0 R/Rotate 0/MediaBox[0 0 612.28302 790.866028]/CropBox[0 0 612.28302 790.866028]/Resources 2 0 R>> endobj 2 0 obj<</ColorSpace<</Cs8 117 0 R>>/Font<</F2 122 0 R/F3 121 0 R/F6 118 0 R/F7 125 0 R/F8 56 0 R/F9 70 0 R/F10 71 0 R/F11 61 0 R/F12 65 0 R/F13 72 0 R>>/ProcSet[/PDF/Text]/ExtGState<</GS1 113 0 R>>>> endobj 3 0 obj<</Length 8934/Filter/FlateDecode>>stream
hÞ”[MsÜF½ëWðn<>mU(s™<73>e{¥ÝñØkjw²`7ÈƨhhÒœÝ_±‡ù½ïe€&rl(BÑÄG¡ª2óåË<C3A5>úæ_oûáÍ·ß|óƒ»H.>Þ½)V¥sæ"þ§ËWq\X¯âØ¥÷obÞïïåÇÇ5þ{|ó)ú¥^×íxy<78>ºl•D<E280A2>]ÿE~gÅ*<2A>vMû¥Þè_YôþÇAÚ¨jqÕÙèÝ·?ób¾*¢]ýPïøW¹rÑØñ‰UÝ×mž©?ôõ04]‹»±\¹}ºüüñßÞ\¯Ê²¼¸NVIîd=ßɼöuÕÊp6wòñîN~¹re¢ßŽU;6c56c³®v¸„uì» gƒ¿ŠèSšü3Í>_áïD04í½¬îçQwñ#<23>*Îåã¿Èׇ}µ“ÁL<C381>%´ÇýmÝË_9f€¹˜ÜÊ0ܲ^YצY<C2A6>ÓN¾9nëpsìe)ë¾9Œ²òŠÃ&ò„|÷€O"–Ý~lÆíüýms¿•=2yT­×ǾZ?­ø'Ñ=ÊV÷Wø;“ù¨`L)·T0¦XåA4&ÅåÝq'×»êIGJd½×©Å·ÍC7bb©1QßíêðtÓrJ1EãÊ\ES·Ã±çR!â"º«dîwÇ<77>
?‰ÖÝþ°«G³ÞqÏ p§Û¢õÝ_ß⧫}}؉øü+.ÅDûöAèþ¹˜É¤$&þ¼
*÷vÐoˆ¼:UçTæ¿išÍksØô÷?ây'ÒÛVƒ^4Ñm]Oß½ëŽA½©Ä$xI;#<23>ŠúŠ¹4Õ.|ö®ëý®oîýŽQˆwÇv­KÊ,ăñ2kd‡6ÕX³,‰4#.CÍ¿ ²]ó¥Þ=éF6­õw¡âQD1ü{~Û´Õ(µ}ÒËE´œK_ßw•*hZ@CtûEAËgÛ/Ê)rjöòìJÿ´Ñ‡vS×è\a¼ #ŸxhêGý­FšæØ“õ¶ïöøØü}l¶<6C>cYŒh<C592>)ùª¨â(»·Ç<C2B7>TþæNšÒÉþ¨ñÈSb”²áû[,Ê”¥W%üÊ£MswW÷/S2²¨ÌXËGåO¨¥ªáï5Œ´Ìåþr>ë®ýû,ž„Ø ¼Îb`'<27>%ÉóÍÅE,Bþ>ö|$•G0§,1%ñž@ÜèÏT/¿2Ž;ë‡,žBQC)e¸‡™]…MÎR™Ø¶±~˜Rmê[Qž<51>¾<EFBFBD>
P  ƒ] î©QÉkO‡NFšáJ_¶Øù•É‡·Íz{θ‡C½nîš5”ÚÉ<ÂòeƒÚH²˜¥Q`S<>u/JCSI£cÛüvôf“F·M·ëî¡asÖ£ßpΪ?™äŸÆ²ó·Ý€˜'°#‘ó¡°ø;¥nåi*s¨ð#}ðêÞõO¸<C2B8>ß×ëmÕ6າˆY‚Â^<5E>õzÉ .R`cß­aôXg|_Ž½~¬á"ÒÜhjñ@÷þͼ ú,<2C>Îø=qrÐf²Î®½Â¥Œš40ÆP“Ûu}€ž`‘Ë@ ë;ÂzRìÏ—¶{í»¯u,"ÞM¡ØOµ&SÔ&´©÷"a™*W`è<>Õ"IˆF$—,Ñb¥OÚè¦És=<¦Ò#jáâå¬ú{ˆ~ñ›rå-"ß"· .êYF}V$¹[ù'=ù<0E>žªJ}ÛJéZÄgŽÂ6`v©õÆ&v—¬Àeøœ¬z|$Üã¥lUr«»«iÚƒþ]ªÀ³øŽ=Xê3M˜‰-ÉuÕ®<C395> ÛîQ/ç1y°Ü8âöî8ˆÑ@š®ôv…—å´pËÎÓ:c²‘Ș‰…€ei$ˆŸeTW=]C
Çè]•¼E³Á;ÍÈ»p×
åU{¯»Q*0÷5á.õxr"ÎCŽ¾ë»¡;l]uùñï³$ÍJĘC…8Þ÷22´Õá×@<40>Hr… ü4AïØÉð$[ˆ­Z«ë3‰£X+!M²·Í?86À[T°¢><3E>yúÙœh×<>ÝÒ°q ¢Pç$ð
ŒY¸p%«öb¥#XŠ5¡|b¥^Q*B;óN™º<13>ËJ:”à§3RÕÿüã…ò»¬Èå*<a_o…·©jØ"á ÕÒîvµw‡ŽT·xMÜ/GtÖRf¸àwÄî–#£TÖ‰ßλ†NÐKÂ"œ ®mú°0õïÿúî§ï¾˜ä½¿×ëQɽÀt¯A”mSjù¯õR.Ìÿ¸ijòüsêƒNR¯j¯©£]¥‰Jú̘.wŽ­Œ°áS½­©áLm¤€ŽZ JÖfT3^‡îdS½ñãX±F-ÐB¼ã@¯ú'½+Nä×ü}Àš¬Õ8¢÷ïP¢x´`t} æØHM[”Q}÷¶9¨Õf 4ð]ÊYR»4{$~çSd§È±x(àá3÷}ŠŒ±ÃžPKÿŒ?<3F><>ÐÍï`Éq"ßW<>ÍÄö†u²Ý´,•×<E280A2>²]<Ÿ2ƒÑ.\û%/m£ øfå-TïÑÁê|ДÓ1tbùOtúò—˜¢„åÖ¡¾3Ý ôl9½Ü2f¯ãòÿ¼0k]³‰a#ùâJݕʇǾ¹=pâ<ø1$÷Ý Œ¡hD˜ŽG-.8ÓYàÜp0æA?nuÃgâ·<<5F>;Î"í«ESÄíÃwûúú±ÙÔ2ÅLtÄTl¾Â<¨ópÓ` vû1Sdúj'¨¼YÌ<62><C389>UßtÇ!låÚ3,Èf|:Ôßñèßjý%¾j³ANAiWªæàï
UìšvôãÑqðQkýE€­ £ýý¥®dc§½½º%`ŸÞl%ÞýRÝ{÷J£?oê 8-㹟²DÑÎ_/ LÂWŠÂyÐùË  ®¥Ö1U#RÎ]q;$ƺHX…9”HæD Þz™÷I›ò\<Z"ÆmlãáOÑu«V“l*v\ @º8³§²«zÊç:/su•BðÈÄŠüQÀ?™Œ,½Ä!¼L^8dŒ"È%ìðIG-Kƒ\<5C>¸ƒî¹ëEhúYŽ·BšÎø0JŸ\x\+aJº07ë4>ðÄ›9"‰a½­÷x¼pNA
è
S²b' Uäp~tÜ…å6ûC×<43>äs$Œ<>t€Wh¿eÞ¢»+<2B>hªq², GFÙIHÆø[W5‡SØa<<3C>DèŽìßXÝî¦ÝSq-¾Í˜Ô1æ¨+£"G[»†‘!&f,Ý­pág âä|ùž‰ùç­v0EÂQÍ<51>`ÒŽIYZå)Ž+<2B>S ÄÔåðˆwMïï¹@Å]ÁàÚçG\¡Ñµc¬v[ŸøCÝ?0˜!ÿ¨Öâÿ8äÖC1Rµ<<3C>*—ªåùŸ`yqY¦ˆ!K5¦_¨Ñq7ß|èM ¾õQS:¦Y0âªްYuÈIaf>]"B<>ç] <-W½{0psõïÛ涹¼f^HãGØè¾Ñ¸ÍÆÁ†dV`)0¥ÉÐÒØYohjVÆBÕ訅ôù¤<C3B9>aRpvã)<29>øP¬¾ßO¢ûÓí%‰Ãâ̹ Wˆ-%Œ~©×— >ì-œ@¨Üe\‘Ô¬¸ ‡+pÌXÈËðI”ûRt/<2F>€·¸'* Ó<07>O€.©áXIMh=N`B—šû©epxcš_<C5A1> ±¾~¿»dâ¦~§žÐR„‡'%¤ÚWº( &­£o×·+,NyL'³$RxÜa9™KBˆ<42>YXW<>2¿ÆòÓ¨ò³/0Ã,sJý1yX>(f$ÆWò(»J
쇮ŒÃ<EFBFBD>D~äŸ1R­ÎáîûîQg#¨p©øpœ2 :}R·ŠHX0 <0C>â= ³#Î1pëë<C3AB>:º­]<05>³cö®ÕQ3&Ÿs<C5B8>ëÙÖ̤j¸¾×íoF?<3F><>¦ÛË8âV&Ñþ–Ó’™âñSnÞ<6E>#ÅÂ:tÂb0£2.£»±¡×žz••D-º‹;„¸+,ø=߃`®p©ð!jΰL “D]asÉ ÀäáF½cÊÌT óÊ\0ø¦>I/LPaªf¡¿ rF“´ HKìØ™e(ÕÎçO/ìe£ì;ex~<7E>ÎZôYï þPŽÉò3c³»d|¾¸Võ4ádOЇÒ)óñZ~Fë$¸Ö•K$tI¦‰@[µAuÆ0\¼d ™FdõÕZ¸sËj†?K~ºoXŽå&=xÕï ìØ6U8¬~.PTZ;@°WaNCnuÿ›ðùè¡ùPä(Ψ-ñ&âfM¿Ȳñ!<™ó±×lÿ×ÈÄømC ãåÑ5c<1E>Â^A®Ö<C2AE>—Y1xU2Ðg¦t´i¦´Mc¡¾%='0Ä>ÿâ·¢ÖÚ“uWHh*ZCw3ÿ¨ÌH£¶ÛVwAûðкÛa Hœ¯‰Êð“*^<5E>¶I˜Ø½SÄ®¡lÖ«p*><3E>Q„!:MÖ¥¥€Ml±µ<C2B5>™¡Õ²"rÙ9ù1LAéëm]X؆¡IÓ)ÑW”'Szó»¾S4CBå…lĉ‡™&6¼q“j¦ÈŸ©:î ·ŠS³”H+z·ý ãG?_KtÉŒb~£Ùî> 4=t£Uÿ¦® *¡8g2a¨¼Šj£DÖÒ&§üý_ß©Büô¬å{õ
 Åg­B$E»Ä³Mõt|G
þǨ>#!8ÂJM:<3A>>ž„3ðw•Îy².ê#®­Á˜3—Ÿ:0QãIó.Žµ8k±"tNÈZ}õGÍøØ%@i"çÜ·µL¥ž€·5)³½w?/Æ>Ñ+ú$´.&Ž¡NØô3ꔈ{[ª“-R 韹¡n<75> e›ã‰P 4~ð€z¥£åZÝË](œiæîð~ð|¢Máë 6A8°*¡Ÿî‰®;Ù:±üMãõê‡ùh!÷¥GÍ°þÁÖ#;ÌB­Î¡±jPëDía•¦h±¶S~¯È—wjyÇ¡Q£|¨ÃãáE‰½êQ÷©ú'ࢳ»ªX
Î|J1c@«Ø"ëA¾'cÝeI3ÈŠ°Z²G£#s>]žME÷Ìnó,ÓÑR\ÉFuNT':òƒnÉö<>jœD“JÁXI…¹<>gc÷ëq«¸Ðm¼†7óÌ°¬Ž5“zÚŽDyò®Öý¬ú¶<C3BA>F ÇAN;·etS?L°£óÙ…1g«<67>B†üÔþBÐ@¨Ï3V̶žºžuÙD»|±<>Ãonh®ÓAìJF*§ƒgyÆhL<68>¤“V¨<>²â±VÎBb¬eh£¿¯‚Ì×”†|é0*n7AHRiDª£ÆH§Ä*ÎH,puÉ¢—)?Ëe —÷°;šÐÉÍ<h¯).xžAœ0z]‡˜<6A>J­»!<?…Z<²6ã“qŸÕ0WšœÉ¢ôÍgt«Úl¸çG«Ö&î Ç8š8gÒf_ý]×<Y:Š[9ó$˜@îàËúå´ìåVüì<>X,æ"°—°H2gÀÙipä¢~Wð¼ÿÔ¸ó<ÿ²cÅ¢yIÕº‡áOœ|Y³+¿
*Tnn¦•qOiÓ&÷b$qðÌ;”¡þ<C2A1>­¹<>Ò¨îb.†ˆêX%8ì²ÉbÁHJ±<>ÞµÆÊ0 P-PJ!$ËÏRŠÂ¼bk­Fs/|æ±A½2ëbö<62>Ðè,öÁM•ŽèËû…œ•~µ
Iy|Á PPu9UšzFÄZ5εñ Cr6J´Ðn¢/·¡¾òØx=ØHÜ!Ïc<öÜQ÷—¡¢U:ÊS^†&7ãÊÏonBYw‰Äò s}W­QYêtÏÆa£ºÁú^AÖoÚ/r
5y<EFBFBD>Öh"Àë1/`•÷2gÊ&Zêå·O¡A‰[5H®RA
(O ìÕ-øE§ü2Øn¡˜¬ñ¼Œ&'i<1C>èºëtrý~ÐE€")ñÚ#g)°k­ñ
›”@êmS+Ô÷U¯.j½Å­ˆàõ µ{•À0zÒ'eÌò=MP´S•+5ÊK
§èçQÞæœF;ïø`ŽŒ £!žñ׺ÿh'pq*bY øP{bÙ€XÀ!²0[¦´'<27>ȱËó3Ä-sjärMÃ:7¾¦ì³Ï}i;<3B>tÏ;2Ùjݽ‚ÁbóÍœ¼¦~³S¯é&¨©hié\./·Z×S¾ä“ŠZ½aŽŠ¢f <>nŽêͬH±÷yŸvô{Ô?<3F>šû#Ü“#2¹¨v“Ðþœ³ŒNè%ÑÞãÈ!ˆ;NÜ—¢Žsšñ}.ÔLxFfèxá¨a/·Ø9€Ï`C†ë¥OÕ©(²Õ‹ü|FÃ8<>Pµ¶,ò<>”§2î<bÈ$€ß÷êCjˆ%›ÈqrÉí¨
V™†Ñ¨B6ùCíÏ+!Ô™Ä.”{
µÕ ¥Ù(
é¼Ïã2<C3A3>
«õVr}PUê»ß}*pÏRiæœóKÇäÙ³c"l®´¥8&æy©²ÇݨDoÐôš™iü@hr-Ùu8Sd)ÆeWˆìD
þúÁÚH˱¶MZÃs ŒXìUî©;<3B>cbøðC×éRúÐ$³L…Í÷ü·ŸÄó,Ü:»Ueé»StsÛûsê“à âØ×­O1]dX#»d? li \»I…<51>
TÝ4>55§îåÎܬÓ_눉8Û¼SíYéMÙˆ tþ¾mî4„BXIâÞŽA…õ•<.}ûú"!‡.ðüõÌd>?3Aq«ÝæÌxîHÁã—Šžt} lh*Qô„®ðLPô3ÉC{ËA+Í¥Þ[Ù²Ìü<C38C>½“Äþêz'ñw—/ýéÙKiž„·ŠsoÉEúú×óý$ö¤¡(ž
{giÉÿ´â0sä
úäIÌÑŸŽ¬â8õ48²'eö—ŪLL"<22>ã\F _¬BOù!¬óÑ'o¯=µ`$žjð† Ï̵õ4ËÝ©Â#,$Y¡·†×»ÛØãÛµì½ÈR²…Gíª,|{`²Œ§öWlÐŒš•/†¬Âpïí¿«aÕšÉ%ã/·÷Š—è[Ó$¦G¢RŸ"/ŸAØiôŒ£;F«ÓË6ä”+um`P­þ,ÎåÑ€À••¿¥‘ŠŒ^T½tÄÇfTˆ'Íã)É{.<2E>\¯Ur!|©ÖOÚÄ
ÛùÙS¹ªÔËvíÿ*
¡<>ó«…Å<E280A6>!Xwµrñ»»Fá,ÄûäýXÑ•vvºhë™0z +õ'wJ)s² üüî]hµízoá‰/1#œ—AËû-—ø+Æ/ÇÎ6ñ=ânò„f©Ý˜`7‰µötÄòåˆ<C3A5>/­-óÉî(þÀ†¨<E280A0>¿ežÍ>Ίe£h"ÙAOàä'Þê¡ñ¶yôám(‡K@ ®6®~J2U#œ
Òã<↲<E280A0>ÖãrñJqÃä¢óé[ä $ÊÓêo0-ó¸xf>f¥A´Q'n¼C*Ë9»Ṳ́Çœè VJ|×vœœØðª?2*“×( XŠ¦dø\îÓ0)IPÐù«sföèOˆœ§ñ.Í7Î'£N£
„àÅâ8ÉltGÖšÈü®,Ìœ¡Œ¬Kñ‰dîÆG´ÆdOšH^e1g³µpÆ5ö%Æ‹$æ$¯Aé¤/9hoZK¿Ä`_Z%SæBõPV<50>çß[þZ¦ì´P7ô/¬¥±ŽwV•S6p½O®´‡Quîl6à ×” ˜­F±akï׊¬'d§yvÕèyi¸ù*m4,Å<C385>>éÑ ÜG]<1A>ž“Õ 9D7ÿ"˜¶*™éœ¨ºWíAØh8ªD1¥qšuÄ51Ëc¯ƒ÷u«YÔéñתkÒæÌŒÏݱ+ezˆÝ¡80T,•ŠÉÀôäÜJµ®™*y+š¢Â”L^5•³F浿îzï¦ãV1àÜgª¼ì¡eþu×­µL[yzÝü#ä·<C3A4>¦cƒñŒA¬m“´×GôüDÛþL-d>ô©šâ{[sGžíÉ•,£ê5yþ¥i5,çiKàèäÖç ôv7eÈä™W
ïĺ‰ái´”[v¡Ÿªx~ÊÖe@Upžé<08>RDOÿï¢ÂUhâåV•F;€uCǾ4Ö&Èä!ˆÖ¼æ3Ð,§3xeÁ(ÏCH<43>ϵÍìŬ,Ì{Ë¢j ¯ðAsùJè6ǯBäõ OÆÌÏ€+œ}ø ɯp9)êÈeš;Á)¨g…ùäe»ÓrŸb­Z«Ã7N}Ç£4)[V~¥ñæšãóVû@õ‡¿©P?œe·ýÏ_~
—%Šø_ßþ ëæ¼-wQ[ž ól‡¯²6bÙ¤çåjc{޷뫾ÖÀs”ÈÉøLÆ2=éÂÿZ%ËH<k!+c5½“Z}1×Ñš3Ì@K @—5g!2n*"LL Ù°8<C2B0>¾­µº1—1™ILõ ÛóÜŒ4ƒ¡kjr‰»ƒoʃ‡(Òg«» UêÞÉ{XþeÅÕ0çÜU`ˆ™<E280A0>g­mó)¼mã¹Ñvç?î·>0èÛi4>v:ò26¿
#œDiæyé
m—È8#ˆuïK˜€àhÑæK#ziT”\Ýûá =e̽òݲ±ž%œ>â¸'o?þ¬¹Þ¨'{H4Ày±'<>ªõ•LŸ=ÇÌëÞ‡xŒŸ¯…ŸÇ»jí<1D>1|}óc£ª^i¾ïÝÉÕùtB×}¥[Ñ~<7E>¾„VÀ;-9¼l¯ÔNï§[pô#[rÂÙøùäë<C3A4>«s¨n!à†¹OŒEtôp·`ÓÜôÖí|v+bþ<62>EšyoXT€`Ûãz§Uw(#äE¸ ¥žRõm÷à3Oý•+´©-ÖÍBoU`úÇÆ{ÌmóŠäÎUÐî”0ÎvU0ù{òÜÕØÓ4AÔ#x/kqC8øÉ&(Ž£/^Ôs²äÓY×g2ê"@grÞ½É6Ò™™â6˜ÚðÕÑL9À9·.o³KùœMPºWtôu)="kúÔRfH©ûkßÊÓoØQΤļB[ÎHi}?ÜqísS<73>Šg“°©èxËOhï¢ý” ­S )·C¥Ìa)žÔºYð:ìk=<3D>ƱYóÅÑ—".òS²èar/{˜DÒ¦Lç¢t:µ h¢MlÈæÏÚ²KL¾ŒbxD®ºÑÌAÆ/­<>'V˜å¥#”_lÇ×wŨŽ{ù-“å™P3´¯°ŒaæÄÚç„ô09úpŒ,Æœ,†ÿsÕ<73>¾;Ð+šW!ÀEëÏ _Ehí¾çÔ­•D6•vÃ$ÑtxédôŒ¢ß&ÜwÑc£my82Ñ+pÔÕFO)ŠW%_6AˆgYý<ÈUÈ*<n½åø´Ä3êMœni5Ó½ÂqÀqb½Ãp}ã KäWégà™¾[úPuWõ°X¹liœ
&¡åÁ~& .XÒ9wuãøÛ÷¨K!^¼¿÷aëÀ#IŒ<—ùËs•'ÛõöÍýV˜þ©"ºÕšµòÜwh×oðäPªÑõ½?K1ù!<21>dª‡…ÏDõ¬éÂÄ!¦0ÙÊüQ. Ý·Žn@Ïú)`ˆ‰Î-† ½ÛðM<pRéÅiçŒOEð¡„
åáë<EFBFBD>ïfÇ(<ØIǨ…Cí˜ <ÛºñÕ~S=7½WŠ<57> ÷´¬ÕÐXbÑ•¢…yåè„ÀFTÿ~ÐjlÝû¾çEc§à!¦ÐùBä°üÐ <09>+Æ«ÀâhÀo*…cZ]6Úܬ½ª)<29>!oB9¼jv¾Aš­œ€ÿrªkŸ.«d)†¿pó˜õïkÕŽÝq£„ ÖË2…oÜu³hÐ÷ÞtT¿!N±ó]ÌÓó¡<C3B3>ï?¾ùæÝP\¬‡Uv1¬Û7è;Î/laW±µè3OLrfñ*NÜE_¿¹{óíǯ<C387>ßBY!ͳ‹àdKߊù@<>cžG°¦ÀXž' nŽ{ÄÂz¤ëéô0×ËšÑô$‰kS-}[ ³D3Zœ0%,?Œ¶p£w1ŽÙÁü ¨ˆÐ 'EgñÛ•`®zÚVo$ÑŸ‚—ÏѺmK•DwÇÝIì—¤þ˜Ùæ¨G·¹ï`vÌ´ÃQ[û|"ç¯2 “g§„`WG‰lôÔeégmÙ»-⬛x9¦Åçc—éçëßyZÛ÷­w‡'¥k‰¯Ï·¾É XÆANÖ4èÕmÍ´z<02><EFBFBD>y4Õn¥/ZXØY¥Ã'ªÔg¶@Hã¹ Áp ~k!"Ü¡ªŸù#£ÈóIÆ+}ºÔÙ"S<>.Éw-¾Ã3\¢¨Þ~lÌ®¢a였5(~u¹1…u%â ;ž«²1(œ<>7­n[fDæAîŽíúô£ÛŠ‡d»´'ßÖÚK þYm²×Ühh$5Â1«p';ûXõä{Ðü‰ä({½Oøó©èIß6õC½9'éQ¶Jt©ç{<7B>Kl&BöŒdeÁŠŸ†ü‰† ÇVÌîe%âH=ýVúÐËŸ<<).L²}Ü2A
\ O¥Õ<åmÕ©&PŸÛjàBXd`´‡®örq~V¯ ö&¼áQÝ•ä¢Ý®<C39D>_ªþId7LµÒ`§&K4ª “Ö*mŠÖΞu¢ ½ã!O­á! kZIÆVêzþØ`i2ÂÓÉ[gˆ'÷”a\<ÿ¦e¾XÏÏR¦<Åû“þ<E2809C>?y ±¡õÇ<C3B5>æJ8Âf“s²­qxYëf9{Ÿ„Wì€*ðo9<6F>¼. çˆ æÃ9´v_µ­fë}Êqò@齞v6ee°%´f™g uiPPVËy$[w e™Õä>:p|+ó<öá¬ðºîµ„Æt}8…,!e„óÉü4@áË„R\s!{ô>ú%!e
éÌþ¶·É0ÒZw<1B>?ŒO~cÇ=L"RÈ'mSQhkŸ£Y¯ð9
¨ëŸtË žÿ>·ç}½¯T-ŒwÆS0k Í»ªG ®‚Ý÷µÿKâËV6Uøg½<67>l×ûšç"ñªcéOGžQ¢ëe÷âtd=ÎÙyyÜ<…*J-VÞ©Òoq€ z[<5B><>áå…X@4¯Va`ñ) ‚º? Ù-aoN`,<2C>‡ÝiîšÙÀ´*¦Í<C2A6>…æ¿ü™v6jøidçØÅS…4DÎõš¸ :QßæÜð°ƒ>ü·Z¼l­êúQ]güÎõYêà"ÁïÍb}$ˆ âP<C3A2>™è‰òqŠc²¥ÍiGY^;ò;®äaEv0ÌÐqಙ±Þ•“¢º¢ -Œ…¡øª^ÌJ÷d49[ŸºaArë]½÷ îŒvFMTQÒ¨8<C2A8>ÃvǾ¹=2IžÇ>V´l“¹;öãVy Èg½;®<C2AE>¦Ó]á<>âŒ(—f„¤¬7#6vûæ7Ãã[M Å?oª} 2´
€£ŒCf© `Ü ôsthC“ÿ‰BV.ÿ]àXA™+YýýDZmGÓ'̇ <0A>˜ó£Li7<69>ŒõÓF©¾¥ðÿœè[Š½ÿ¨Ð¤§­ E¦¼¸.eÂQuù?ÿ姰ØwÝþp9bË¿¥÷„I±)ÿp6»ôøø¸:ìºA(?<3F>𳫮Ǚ
ÇtZzy]:œþ­j<C2AD>ZËM±—iœX<19>§e§ÿ«Û÷µúï=arÝ?`KhŇaÀ &ˤk¢¯%óûuÇÆ&e/þO€¦±.µ
endstream endobj 4 0 obj<</Contents 6 0 R/Type/Page/Parent 102 0 R/Rotate 0/MediaBox[0 0 612.28302 790.866028]/CropBox[0 0 612.28302 790.866028]/Resources 5 0 R>> endobj 5 0 obj<</Font<</F3 121 0 R/F6 118 0 R/F7 125 0 R/F10 71 0 R/F11 61 0 R/F12 65 0 R/F13 72 0 R>>/ProcSet[/PDF/Text]/ExtGState<</GS1 113 0 R>>>> endobj 6 0 obj<</Length 7551/Filter/FlateDecode>>stream
hÞÌ[ÛäÆq}çWì#0Ž™.uá‡%)YT<59>¥][K>`z03»M=Ãa8üþ^ç9Y…KO/I…eKÁª²2Ož¼Ô¯þí]öæaøäÓ÷Ÿüê7îMöæýý'å¦r®x“ÊáÒÔö<>Ï<C38F>I3óæýþ“”ôrñ~‹ÿ=ò!ùíp¬®2¿©ôê¦0~S$õUš øC^•?ø«Oöu•Yù廦Ço©üÖÝã*ß”I½Ý^eÕÆ&Í0´W™Ì"¹Ý5úœI¶<49>òn±É“n_ã¦KÆö°»…ë·».½ÜoxÅÈ8õî*ËäßÝ5~±xåñ*Ëå£Õ'»v<C2BB>1ˤ›«ÌÉ﮾}ÿ;Y×M¶É¼Á|.ë;ö ^Ë“»Vfhäý±}šr©“»g,-O°2—æae¶²r5Èœø<C593>¬ÇVF.“9<E2809C>z½h¾™ìøµLæ"Z™ÿI…éÒLÆå<>¤Éã˱ƒÜy]Cû#„“͛ŚÊÜèššZÌ·H,=<>
¿Ì=<>-·.Ï!þn<C3BE>çmrÛj|T&ÞõíUžb·!|ÑáËSU26ýS2É®ÖMxÁ<78>•Ìñ¶Ÿu¨¦ÁVe<56>ÆÅÝÕéøˢšÞÿ3Vù@Ínwøº“A®nŒLÇR ú‡›õëÔÇñ܃îÝɈ.¶œG´ÇQÅÒv ÃhÉy
•ßl{¡Júf‡Uù¤[Ì¢HºÃðI‰JãÏ­l‡3òÆQÕj×^Q7ó¢¶âÂçó*•Ï<E280A2>ížfá“Ã(~^zä ÞΚ<E28093>WNž>4?Œxˆ{ÜLzÛan2Âp<C382>Xé3^)ñ©BÀšñbå©jaØVUϹIïÌ,‡¡6œý¯~S(žT"¹#\„ˈ'N.r—åÀ“Ég¢X7NF…b<E280A6>¢ÙX`ßR¥Ä´ ѼÃØ··'™”LÎë†è-ÅŽT^ýÍ™ñu>€½<E282AC>1ïÚÃÃlyOFÝaûK*í à!KîpE<>ÝÙq¸¡UÅÜcÈðaÁA<05>[ƹ©>ŠªÎoÒ,{ãd~EšzÂ;$æÚŽØ!5zД<C390>‡þí»;H[6y§Áyg¢n:(âBôµ¥frûË„š ¡S3]%³ÄS™èCƒ©8Ž;7ÍœsÔUÞlªªZÃÊeT ø~Àë¸VX\|þû·ºQåÒ¶Ðñ|9Yu«ò/ðÚ÷úÚI Q&]->7k³ÂB<D?Ô‰6OnG<6E>íÚ qÖúàÍ%/@¸Ë Á.O!Øc=â£h'Ÿð´<C3B0>,•1Ãð˜ÿ¶å)rß(<ÖãIÇê1m¬&N ~¡ SO=¶øJš%<25>€™äáAéï ìisZÝÁng1ááX«¸¶Íõ%§Ð=5œj•ÜÜãÍvT= ì²%jMm
™ãÚágžöÏdÉ¡½× lo!ÿÖ‡Q­X<C2AD>³¾ƒÿ ÔhGQÐWûûîäJí4[™U7N*ÞŽîꞘi“Wˆ¿6k$QÐ ƒ:ȧZõh×Þ)°¯USFªº'ðV—4£§ê0qmîïâ-f…ï=ÁJñü>.k¤3Mn~Ôå7óºÚq£c•ÉûGhå €.€‚]Ó~Óäjuk»ø·ºƒ·W·õ 3ž'ªÂ6- S
0F(=8G;ŒqKkÕola»“§º7ÈÛ—ø†x‰¤~“|Ù( ¨e˜ Ööövнév'UƒÔ ÊøN J¼ïá;%õþ­fÖC=ÂÓYò.Â_³•äÌm…Ë?1<>¤‡çY ?f“¯šñQ—ÛÝ JÝLrßõ—¬ç®ë€O»AÅöÍ•`hÚö¡°zïÚXEo¯õȲpˆŠ"ªðN™²÷ÇF©ãžK Ë<>3oj<C¸ÃÆ<C383>:v™ƒ²Œz§± Vê æ4s<34>HùŽ»FïþÐŽúièhî¡ïNP0ÀQA ­£'ô‘˜Ê‹Q%_^½ÿËì#Å r£LA¨£wåÌUÈmþÆZ<C386>D'NF¼dá­×5“g„NyX´?Ä)Cë÷J;«åúqÇ—MœëÛA5wÅwê‡5è29ÅžÄ×ô‡¢ë¾X+Ŷkî5æ¹ôÁºÚæ0*|<7C>Q@><öy8ªo¯ûAA£D­ d6üvÉy船L{§`ÕaÈÒÉ$=`<60>.Ä;JEA§‡Nö<>šTøˆß^UñHß mÇÝ Öâ“ëK¶{_ouêí
S*™¹¹Í¡C+·9 öuôÐ7£ZË
s1@µ4)Ljƒ{ØÑ?5âÑè<ð góœ²z BĪè¾<E28098>ö“€Ø1eø èÅjE<µZÀ“\&¡…¦Ål )49ªkÁv5Om §r;”ávíuáÇ]§÷BX6y$§ ½k‡­FÈtÙä¢Ö=ùpÿa« Ñ ¿ãþŽqi´ìiƒ„ÓÄ°T9p}eW÷hTÊ×ÞS0^Åþ­ò8{¦˜XG¾D|áÉsÍ÷AOÇ0ƒ}Àd~žeQ<1F>ø /8ix<69>§]ˆÐeK°§?<3F>dZ n~8FF¨Ë¥‚áôñs#³´¥cØ·nß©„F,ûp#QÈ“Zh¶e= ÿXËöæiäéÖ ÛÓÇ+1© vóÙ§_jìYÂ<59>å…v<Û Áœ¨½)¿UKЈ+’ð< êú›öá ° Z3,?Ëè•v§AtÄX~<I,áM̱ÙéD¹<44>û¾Þ7Ï]ÿÝFŸ02n?Œ×z_ ëÐ~j>ÈôEwš~ÐðØHT<48>)æ&zñÎÝûlEë^ÂÑP¨ºÉ9×”Ý(¯ìëö ¡NVEßn¨²”QGP<>¬À7êà /.þû«<E280BA>Ò˜êIÕ$AçÒɇl˜gM<>"ïá$”!¹)ŽÂÇ,Âáæ¾ÛöT%ÛÜñÂþ>‰ë½ ±¤‚=¯Œ lW.á_æõæþB†XÀy߃A9¥ÇDqGl9õÇn€[°þgÃ%Ô6yíæÝQj»Ú<C2BB>"ÍÂÞ@²@êƒòH ~N·ÜÞ)56OI€¿?1š'©„Ðltœ÷"Þk}BwChh½}œ÷QxÅá.z@Œ™{È\e,à+¹Òbe²úŽ Ó£Pâ†ð˜± ¸AËœa^2½vêú„(ÚÇ[|aš™Œ
<EFBFBD>[Q†ÇvG<76>ç!ß&¿æJƒáÛrËÌGsHy!üÉ­Rm<P-_ìý¼k1¹æM&sTÎ}<7D>b¼¤lq§Ý¨X^Î[U}¢Â—@þ ò%<25>ª¸ÓeC<16>ùw·cÍ”\éBâ' Æ­¸ jî.:P|<7C>¾Áñך2Qž“¿l·§¾Þ¾(°*+ B+Þ8ª N8 ¼˜<7F>% Q°Ìíq¯-Y
pbÚ­»æ>Ø/· < +±Pª¯?ûL½uÆ$¥¦'<ܾ©ÁTf.`­¦rÛBH‡&Fâh»R<52>3Ú€ÀNp<4E>z¯Òùs³ \õ:ºdØ`j·{ù18æ c1;¶×ÄYL™1Üڧ&f³ŽÝ3y“åbF<1F>mx Ù'—#Šû3áÏÑ½É ü Yìš'*<2A>#ySåq9¢¼¿t Gç(zhïäþݵ¸¨qLû#FßÊÀ”¢Ód·Ê,”£p™&§5°ÈB¦QX·€rb^c,×
²pë¿Â­4ÜÂòõNîdᎩ*nýËÙK¹Ïâ[6]Å1HI|¨÷à€¢.\dŸªEÕ!æ¿;%´Ú ó©û—AªtÅÚ”ç<E2809D>ÀÉÞo¯•y™äSuiÖ³"NîÄÌ2Ro­µî‰¾üØ><RøˆD‰ÊO—V°Pž ¦)çç‰ÇõŸ”êܵOíxe5ÑÚésCRÇe<C387>k0o©ùÇalQÍÉ V5èÿ &÷þ‘‰yë9rx§Ú‡Ìf??Š×Ç\m‰Œƒâ…€\•Ôwwm€Ÿ* åKÖµdó}jt¤OPq»†ùi<C3B9>©Ã¥Ñ2<C391>“”ˆ×*(ÃóЈYÜÝtý¦fŠŠ/OãÇV»ÓŽ1?Â4qâ.U¸\¥šŒ^¦hÒ½Bõ# S@°Œ™ƒŒàƒ”<C692>“ùÒÓš¼$ºÖ!sà$`ÞuÏÊ¿rð„Š¼ô Úþ )ËU‰Ñ—¹&™V<>ÏÃLpm_««Ó@u/ÚCTp~k<_¾Æ<C2BE>ˆ*±o3”+œùÿ ·‰y¼ @ ÷ÑÀ¡".É>Óß#Ó-Ϭ±‚?ž¿'ÀðÍ•ä7^dÏÀ}8=<ÀJÈñ<C388>Wû‡·¤Ô½°Žé A Üp)a|áa°5Ö! œÊ2<C38A>>hÈhe“†*ƒk$W{3•EMY2ƒ<{J¹•²´ ŽfÉï»±¾Ý½@P• 9ayó<>Hf*ÛEКMC ÁzH¤u&j~D¾mõlòMòÇí â*“C7Æk\ȃô~x‰uªA¨nÃ:*~R³·>ÕLóEÙöÂ,èõJˆ¬e—hGl1³³$*•™œi”ocW,Ý=¶ý„*E¥œvasBœc>GY|Å72²Aœ£¬»öNŸô* ¡¶]ß7"·F“¼•zaù°r
³`Œ©¡’† <13>ZhÇB\é&À_@»W†,ð䫵GÛòyZFãú׫Ì<E280BA>Â
¶e %ˆÔ™¹ûÍÈ• :ê_qÇ&ŸÁ¿Ò §«ª\«Õûú»†ô¯<>Ýý ½“S˜HÚµ6>¨ã,è%·]NR ÒÎY YKbÌØÇfÊw[:^Ìø—ã®I¡é[úùŠL[`~¤)<29>CY2æ=+Ø$T¿çÌð¦K^>œ1윕fVàh÷á3× >
`ÿÐîe’ŽÂ'…ý§kežZ¥DÈ.)ìS-È*×Ú±,¿þâbsfÜ&­¼û[…ÀŒŒ0Qäb˜GÇ…ê3fµ"ñ±»Tzþ?.-gð÷E¨,ÿÛq¢6à:ñ¹Ò¼¸Dø¢`=<¢6l™XœÜ¶-cýö+\6C,` ­6Ý},°ÐR/CÇõžä¡õ‹ð6„¦EÐг¸žCV<43>>mðN1`-dnC LOêô?Û-“?]CÎøY.í"n"5,à )…8‡)e7[ %
´°%™s5lQœòrYx³èZ,"¾p¹ ?¦¯9~œ9ƒË!`€Ýç¨R9r@ø:ÇìüšŽMö½®æ<C2AE>4~@K`^!ÌAòl)±ôÊOmw¸³L¼8³h®œ@/ªokÆÄ“öš÷*ÖÜBÝ6àÚúW ¹é8ag*Ƙ°³Y̸9ëÖìA,gêŒaa÷Nóч—Kê´ y
ˆÙGù6¤¾ýôf )J²ý»€'Ú^çÑNï»a‡ÒÔ@©õ=-
[w®ÌÞI `3¢&"ÚBSݨ±SñšÈiHÅÜ—<C39C>h#ScÞɦÚŶšƒ> ¦Ðmah†Îq%‚«ÂqUHnÈoÆî†K5%‰»ø<08>&èb'l1´}`)Í4ÙàÅʘÐá H´Ý®{<7B>½Þ-?ZÄ>†Ó(ï³¼i,‹¯Ù ®Æ±Å%fH1ë̾<C38C>)d4lcˆœKgËÂËY€xaÁëOtuê¥K{™W­ú­Æ„mˆû<CB86>¢}êuB¹OIé”/j®ñŒg/ò$ÄYú«2<C2AB>ÔΗêShúP1eæŠÞîÃv'¨©ÀœFØŒ¾µÚœ ò¿˜z` r~™plT¯²=÷¢€çù1ëýG°43ö"ê€etÉËÀPøAþ×<C3BE>V`wK³ÞÿeÞV—}
€½æºW!Xá³)CÎKÛfœÓ0`•Ô#¨R‰Ž»¢ñ&4RB‡.lø¡ì±71ï <20>*xÞ„¶²“òxüíÕW{6Ý®|µ'\DŽâ<C5BD>¦{ÖUþ•1$Ÿ÷ÝÐÛ]½«|¤p“ÇÛh»®GLÄ3-kÓn…¦uPäíño©ìŠT)Ö<>ðk91Š¦Ðpî…)ˆ² ¯tóÂ,Vr[*6.Àck*ä?šÙQøÓ`û<w”5ÑE`Cz{˜<>!Èœ$a]E6íZÛULt¦Ü²ýà 3>úY\X­­^yµÔÐ<C394>h\´èú£ºÃØØ´šì&#þpÐÀ¥XVš†zßè=*¤ÊàÅ¡~ /ØœÖC"](¸þÉ¿<C389>ÉF¾Z,<2C>á°_ +9ŒZ<C592>¢VÃÒØ4}g\5(ÿ¿¤oP;€Äú6IùŒ)¼zDôHYr³_ƒ)
é;<3B>¨ÏQ¦ÓÉZ63ëôîÙE ®Ö†°)krA²…Clóýü"¹œS"
Ùl­,ðµòfÛ„2à„oi5qõkUtŽáS²Ù„[2FÒüðØÞ¶cìßuÏš|È3¾ÖŸ
#S7©cÁÚHG°[ »šþiáÇ.ãØMï2ùùÔ>uë8Lt¼È}T€cÓ<63>S¹:kyh¡Í<GB<>Ó ÔÙ" ]SvŒ-<2D>
#6­c'ûSôÔݪ\úõs;žFªî£`vFB>å”y•áQÀàNÝî”îa¯ÖÀ€<C380>lb©`æ«Ö¾z­dè \Õýä/vZÎ1²þÎC|ÊsÇlÑâ+©'!þu"Ù,Žïë—XeN÷2`8²P-Y<E28099>wÒRêU/hÚá´¿Õ˜<E2809A>çË,ï¾ÑæTÜÚ¶ýöÔŽ¡A¼ä>Fé‰Se(´áxÄ £ñéE<C3A9>6ªo×­s‡ö}_!ôNû½@Á5þFã@Ñ—Õb§ôwÝ)y'xsvä“ã~óD¾d³ÌÍaùB¯W¹"ÃV-f”IÿÕzáUyÁ¸”áÒŸerYŠ<Á˜<14>ÉC²áÂ0Ÿ8;íØGYk,1)ÝžºÝS¸<07>u K…Tò`<60>Sµ! iþzA¬ËW)™Y!!¢åß<C3A5>gÙ`I“&³.ªÚlv§…<C2A7>‡C
SM™tè|,ç1=€î¥jù+õÖ!¹$—°¡Ú-sYH<>P)
=€ò‘\™ª²Yfy6}†ÔmZUùl_™föRþ,äçc\,Jp#´ÝYãÛÀ1™Ë’ˆƒ†Ç!Ü/X2;?Å1çÎxRäPŒfw]—×V)‡Wy3öZ.&ã1ôVßTÚŽˆTãä˜È‚—<¬BnûòsY¸Q<>´(åÞѱs‡F©dÍ\n&«zPgÙ¦i<C2A6>²ŠI-üʲËS󢧲IF|ätn>¸`óL´Ûô\2ŽÆ¯s­j ìlºìÒuÌ¢„F*Ç8;p¼áٽࢠí^.›ü"ÀÖ('Æ™ŽÇÚèœÕ¾¥A]YÐ5‡i„T `‘“×^
çÙ¤}Š•öu”µ,v\bß¡㜠Êøœr_æ#
<EFBFBD>a“÷YÄâåK5y¯ž?2_ÒÃúâBŽíL>»0ÌÈ<C38C>÷Ùв2”TÚ´,äöûS­]*ûZûžðÀúï7ÉWï”M2MJÿy9Åâyû‚.ñî¸ýž©$†ƒ»®Ü3°ÁǼ™²°AÀ3í2‡ÆxÊKhŒùx6tª3|ûæöå#‰!XPq-c¥<JpFÖÝ&õçí ?—jõlDCèrNÌI4§<34>>Å_ïÌ[
Rì)<FjSu¬|vf{““˜Z°(ωÝÓ£
²]¢ ÇŸÌʯ¼Z´p[ç<>ý»7ÁœÕ·5²?—©<E28094>ÒÐÚô"0]¹³ø¨ r€{*aÞ“Š¥ýö½(]öw¨ðg?Yá7öµVö¶Lå{&'ÞŸ³G“¿ÓBj;T}jýy(܆”y51žœ'cu1Þ<`“ų—S[s<Ëk3@\ž/óÙì<C399>iyëcJây>?¶ÛGTà ØÄçØÍ;¥1Q[Õ=;mts9CºŠ<ÓxÇi_ˆ<>9xqy$ìò¢ ä ¯4r¨wìfcƒé[ßqó=Pm•ï"c«G±íªôÅÌ܈—ç’×™ <20>ãÛ+Jç<dÈœZΚÙÊëæ…_zݼж zx¦þY¹ÍÙÒrËT‰Æ惦}Œya¹ékÏNpo»Ó¨üÆ<C3BC>SEø§5U þç<E28099>´vÌãZýç*nÈ;%¦ÝÅÞèÂMm>X´ÞÍdZºÐŽ¤© m¿G·¹F¼å¢•P£êØhN^O;jòé,ln—ÏfwÍìÌtðËcÇ#Q…*çF<÷-¤쵊…ýkÎAro”äå‚0{ªlõ¹ØÀ2'FB'`,ú¯[
Mb <0B>7,¤ÿû!t™M½—Á®*L¸iWý^jôÚat¦ßQ8ZêÌÍDG-;FtÔæZø˜?•‹Þ•<0F>† Ïâ×ÇÂÄÝT>.‰pV1Ì”É*—a«Ò¶2Ÿ:0½à¤:¨lh³*%ÔºA[ïæ¢r`Ùýа5I{©ž Tmdžø9
mQFëæ¬ëLusWÄî íªšbë4²î%><63>eS¶Dí 8iHc˜C"‰]:ˆm˜ùL1ÕãeìøðÁhC3ˆvø, Î:Õ/ÞXd¤Iÿ¦-¹6µåÇ|±³15kÜG}1<>«c>ñ­¥—iwšG÷S&óZ{mr× Çvlôn¡¾‰ç\Cq˜GyWYö, ¦* ÖV«
Ã?Š˜Šì'ÄÄ#>È£h>ۼ纽åÚgö†ë¹¢Ð9˜©èÉ£œýñùR{yˆjÖð,Ä_ ë•gÉ#4¼¡'7¶ÿ³$v뱜<a»­0·H¬Q1!Ì”<C38C>¿lbóï{…P[ú)st¹¦9§pî²¥Í]X\ìëšú<C5A1>µ ,[DøÌF-NyHXÜww§PÂÀPá„5 ê•1qŽ²ÏB¦·îÑ")&Jî;…§ú°\úóô{΢Oq¡7˜¯Ÿµ';3W¯o.#Pè2«\ÉðŒ”J×eò…x"ž0<ã\Lû7Ìmüåtˆ%žD_BØ…¦·<C2A6>%2 žºª)b¢Eö?çBʈbØáiß×´®qQ1@5ë¯ñzŠô!4zdª©ß…]±“†~.^iáÿu|'üˇC>ÿ©èG>×­šrJkÙ!¤Y,Ëü!ј—ÿˆÎÄU?¹tVQ×%»Œ½Tyåbê7gÎþ¬è¨Ï,m 'ÕÔ.<2E>¨ºàL> £Ãã¡8ŠTrïBS6*Ÿ±wÚóˆmèv6Þ/2x¡dRfëµYì€V¡k-ŒJÏ}ÙîC\´Ð°eg>;ÀdìyÜ0U¨ >³a™!ÅfT 9+K—û M
VÏB…¼ ÑŸâN½7—y ÖÞxúU³csɆG$˜•Ï<17>åJìÍ/3÷<33>ÚÅ"ˆ˜>
DãvË…‚<4јÎ|Ø€`íܾÀyæl\[æ> kû¶¼kGàšSiø%<25>MB!‰MB¬™kŸ<>ñ Ë_´·Å_È•²þrž ]Õdª>Í™0— ê^þ÷Æ<C386>*_M˜ÿñ„nãgÃëx” îè«é rÇCH»µÉ4‡¨þ´Šp¹ÅïŠiLèÛÍŠêÍ<C3AA>Ø[é[(¨¯¿üû˜ý쬆Êüê§ì:{ÑÖ5“ü§Ð†NåùùysÜuÃöŠ4Y^EÚ¦ëÑ'ãxˆ¹¸º©\…³¤¿«'MƒQGó438Å€­Ÿü<>nwÚ³cAXâ÷ð€©°%_ ¹¯¯eóûM¦…É´×ï?ùW)Ý»
endstream endobj 7 0 obj<</Contents 9 0 R/Type/Page/Parent 102 0 R/Rotate 0/MediaBox[0 0 612.28302 790.866028]/CropBox[0 0 612.28302 790.866028]/Resources 8 0 R>> endobj 8 0 obj<</Font<</F2 122 0 R/F3 121 0 R/F4 120 0 R/F6 118 0 R/F8 56 0 R/F10 71 0 R/F11 61 0 R/F12 65 0 R/F13 72 0 R/F14 80 0 R/F15 83 0 R>>/XObject<</Im1 14 0 R>>/ProcSet[/PDF/Text/ImageC]/ExtGState<</GS1 113 0 R>>>> endobj 9 0 obj<</Length 4318/Filter/FlateDecode>>stream
hÞœZÉrãF½ë+t™pF„Q­7<C2AD>íðÒ¶¾´ú 7Ð(ZŽ‰ùŒùÞÉ—YÅÅ-M8&Ñ µdåòòeB_üóV]oÆ«×wW_|•_«ë»õ•OË<7×ý<1E>O3gܵ*ò´4>¿¾Û^e<aØÐÃÝÿ®>$M7ÕCµœš¾gs£UZ&z:Ôu‡Ÿ6uÉ×ßã<C39F>r©Iî“ÙÇ»oé`eäd¥R<C2A5>–ö½{{• ³»_ñRËËÔ¹L…Wÿ¯²°.ÍH¾ð. ïTXfËÒ…W_^.£Ã\^VÞåŸïø!¹<>Ä:-Ûýn×ÖÛºªá 7*R|ÕlöC<C3B6>_&õÉ­}}?»á‹Í]¸4æz®Rå}!-ûnÝ Û¦ÛÌæÚ*RIß-i¹6ŽWªéð#Oódz¨&<zÑ"é÷, ­‡j[úá¿¡<C2BF>ÝP¯Ö>o<>TËåžÌÑÔ#Ës÷w:¾Q-é¿ë'1EžTÓt™ñ¡®Œ4J¢Žõoûšå3ÊCÖ5ž
j1qtûí§)뺚H5c_Ý6Û¦­†öéæ$Ðz?ÐV´Úæ9­©Ÿênä+XW<46>u¢Ž³2Üö«ºÅ•,žð¾ û4ݲ݇¥¹ ÂÊÒŸx5¿­/ª±^<5E>ÎÞÔ.A“5e¹ÉuÒÖ<C392>u T®û-=“D:ùà²<C3A0><‡6î‡ø´Ý·SóX M5…=óäëfµb×'¡óäûjøÔ?žNÿ"Í-9NtN5ÁØ6Ã<36>Ɖ¶åWA'«§?⧧Ÿ"”ÍJz&<26>¼ûáÍ<C3A1>oßÉ€¡¹æãé¬U³buØìÐÜØlºfÝ,«nj¡DºF™4ÛÝÐ?ÖòóÒ¥0b¢S±Ö-ø,ŠÉ%èöêÅ(ÎíóQœÄp¡âªBÿ)†­³ªn…—síRE÷¸ ÉU5qdä3gA1>ô‡î~F¼º«>±1 ¦T2õ~{#Ábá<62>#‡INÖ O"wãNMGJ¿ ×*6ÞùäÍë÷çáIrÎ<72>Fô1R:m%d<>ƾբųÉè|þ?GÌ®eÐpÚ“ <0B>m³y`ƒ:$EŽ!ËáMt.æ\ÀeÃ0‹ãÄ‚ú(8s@„HÄ ·?¼ÂPFÖê]«…Y†dœšnpz¾<7A>6p×q¿ÙÔã$°ç<C2B0>èVÒ6Ay²çtèeœ\´žÎ”9óL#²à·¥ß„T“è „êvÕ05U %Ä÷ÛsàÎ3h¦éÖý° ²cž î6Øà[üÚ7'†.S&Ëj V7<<3C>Ô<EFBFBD>˜Æa{ÓÚâ,Š %ZB°Ðås<C3A5>s. <0A>ðŠ¬,)^rŸZc9Û~HîH)9ùÙÐï7ØNpÐØŒ]µOcŸ³Š-óXW `F°|»˜Í=é½éª˜  Ã+ÊZi%ñÐŒ´¢2º ãtZ3Ã.ë`sÚD—0àC5,ú¡‘%Eó—
¨Ø³ÁKhæÓ>Ä
á-bìJjcSœÄÉ*XœjA—G®Ý#lÈS½ø ÝÜòèƒt8Ò#8B„ጢó òaærzOæ#XS¢ó¯k
Žg²².,{˜<65>Ü<34>3 /oV4$i!UaO¾«Æ™¢Ä
Ÿ¦T¢¡Å™ÂÕa9<EFBFBD>˜£‘„,9ìÅñT€@@ŠlÞ=DTnÉË¢;z
! ¥€¸"<>1ô€ŸÍ8×<38>²år°¢-m®6SH<53>ÌØl‰8ÑîJpÒxP-=ŒF?:HO±Þ>ý1S`"@œÌÁQxªÂ=±3"êô–’ D@%V$ʲYhzØô,]-ã*`cÍÑh!ÚØ@Çã8ŠØº©q”¡Õ4#¿Ô:‡BÆ Ž±„[$j/>E<lù@[ÐÄcO©x"<22>Œ¦î!™nœÄt•ˆEñUµt ºv Å>N7âšt¼XàRžÈn<>ð¹Ä÷ÉWŒaª¶\bH'Ð&ëuÉT ´‡ <à/¦)x¹<>•D1 *僆y9bÛëʾdCámð<6D>W-î–‘ºü¦<>Ç+lkÞ“LÃ<3î3!ÌáJëç\ÁåyW0Z`PËsH0É¢ýI½d÷.hæsÕcÅ$mV ¬bxÎ×ÌÚ²å1:oιÒZ$~Åñ<C385>ĘüU»Ý ŽÑ“<C391>àPrD&S¼%ò«f^´8²Üú hm!;=<q<>;A€ÉA·~¬Ù8%€:„ ¼CR†´ƒæšúá«Sª¸fLPÆóÜ%>U`óMÝsxÔ"É44ÐKšàa!2Ü„ô0±B)ªIŒ‡Ó7,—Jvý(‘‰{<18>8ª8G;ã)÷í^<10>¡<EFBFBD> 6ô Ib=8=Ì »–¿Œ)´%$€9fåuÈ
Ç;Ü¢á<C2A2> <<3C>Ÿõ4ÍX=R, æä4B^2ˆòÁ:l©“<C2A9>P¯Ê(ï²ò3˜t"®'×TÌÎñŠE_Õ;#tZñ| u­$`Õ2`Pä žjv+böeDƒwwW¿]YhÇjNPTm§%UÜ\Ûkà<6B>ÊÜõr{õÅ7[uý¶¿úIŠ÷À¯i¯"“¥á1ïsJo^R[,Z-Wu*Ånt»|¨A‰RcX$W²ˆ$…À5ZuL磟 Ó?ËP#5ª˜—+U«A)8‡Y2P^r`ø”Y6q9Â1±ë\*rÉsà¼lR°ñ©ò¼`[.™Ïb)qŸ¼ºŸqUÇá^D<Ž.TØ[*/§¡âĉèDI¤
rѵü(ƒ6²âB¦ô\E†ŠúÎ2acôy¢1胰ûX)5¡¶™Ô[wýÏ7²ž2v»¯ãÁtRMbiË âŒUÔ#ù©eÚ¨$ÌÞ£dÂh3XòX×<79>3i±¬[_ad—ìváÑ0(“—Äg)®¼+àw‰Â²Ï}Ô’—[¸k.<2E>
bd˜|ΰ±
¤¤*ÇÓ…¶Ó‡$Mg(Ï£<C38F>O!¢Ña27¨âfþX6fæü*Ÿ_€
âåâ<02>lc^Œ60P•]Þäñd“ .OÂÔ(¿•ª4—ž·ªUÃà`
Ãl»ml ‰ÈåTualS0õPGþmOT +r<>sÉwì¡FÒb`¥ŒD^ÑOܸ)l(ï䈊ÑöRÂlòi<C3B2>!8ý<38>îÒ$·SäÕhù‰pÈ^Ìox^#™ýîöVv†WIA]cï8Ey},˜%T
ÃÂìö!ÏÛX {”»äÈCó{LL
x?WëgiÂæ{Ÿ,úiâî<C3A2>wDÖúsœh,
<Vœ÷'Ð<>ôdO <20>¬'}3ÎNu·¤¸æ+£jAÊ”"  l8¾³ìÛ~À%8å@V“z<>õÐR*5]È!4Ù^š¥œ!9¯ò0©8åɤRç(ãGÃ{ǵ¬Ä8<C384>µê·Í£3á<33>ý°
ççg[WgJ .˜ìêa»Ÿ¤c‡·Ç8W¥<0F>óþ"Ò‰9tL¥F)8ݪMRÕ„BÏ"m:épßélÅ$M¼àò?•ºÉˆ·èœ!ö´¸È0 /€tœ« Ðñý(µTÁ½©Ë¬,”]
x9Þ— -\žR±®¤0Ã"Ôáú¡²ùºoW±h[=çÿ~¬Úf%™¿Kå…M^A67 =-ÍÂx·ñX?EÆàþæ6!}Á<>¸¦ª4U¹7ך\£´Fÿ/@<40>I_#þ|Y
±Ís$‡O)H_œ“…9á~ÆpKxþ8òg­<67>¾8.€–`c“W¿]ÀƒœžU'<27>éî/j§RlDfbGvåÙ„àò”“? kÅ#Pà#â­–Ÿ¤§;6œ#ñÒ‡î-7­žÝÃù凇f
ÕD~ÜñI|_@-÷1ýKí£“C5ʾ6j8çB4ÝZTI\K² \༾Ì— 8'T;6àÊÐŽ×|Á{®x‡Q<ÑIDºcC‡Šè<><$º¸H <09>s99ú²³\ŒÆî°vÌ™¸rñTEWí^ &J#¢ÁiÎhãdœOÔC9¥qJ3È
<EFBFBD>>g=4èáI<C3A1>)ý=,AiS<69>ûAv—tòV Hº8éøé'
Æ.”{Ÿ¼fgÉ@—Þ Þçè3î%×1tÍ•_É}vˆ´ÀÐqØÏ2Ø>ÿþö<C3BE>l<6C>¯BM>Âd(§Öû.~Å)øE%Ó¢<C393>Ø8ê;­†æ<E280A0>TaW<61>brRÇÚœlûÍ ÁŽ´”™¿Øeʪ¿îÈvEiòk¸qŒw°F!mæH´ŽôÚË|aË¢Œùâ~õì[ÉPœ%T¨ÖE¤6Ì<36>ÙñFùåDë(äÄ¿Öj!sªž48Ù…ÓM Ö±<ÙøXï¤<C2A4>ËHW࢕ëÕ†Â5ŦœXÑÊãvä†ý ^â<>v %œ—
ã†OEЀ¸ßDÚ÷0yl³Ýoe¹“ø ú=¼)
ÆósVCuè„u˜³3WÕø ²¸p(wxJ4l_Eâ@£’‡[Xž'4íÔT<18>Ä\8&+‰Ô“ &! xd|0Œ0Â}G‰D}Ž@…:Fh¨<68>Ͼþd:Þ}Š\©è>áS¥FYlWDำp„|ò“Ö<Ê<>·æ1„¸b&ø¹`«DŸThcˆ
×m*‡ùHTÔ%#„2¼|ÐÊ;!óñs{)º¹).Xl¤3™„ZËÅ%ò~F¨†pÇâ¼ú€ÊÏ@Ÿï×Ö¤U*<2A>& ¤úÃ~ò^´$
E™Nn2îGÑù ÀÌiü¯+Å•—¢½<C2A2><C2BD>Ž½ Ùßq7šžtï|,ðÆXãóØEì<45>Û¾Ÿd¹âæ[Ëê崴‡èé)6ëF[€ÕB¼]ÛO©¼Sò)WޔϹ”Ðt<G\É|s$™Üëëeß­æÜ°V|ÍÙŸVHÓŒ¹ïø¸B.ßY,€ÿñëâçèo‰+MÚd”ûJFñD¿P¡ƒ‡¾Öš¤ô>|!¹GwÉæy$<24> Þó<C39E>è¬&ÃfäÞåtþ²™[÷ÌéL&Þβ„]Õq©Ö­BqM€V^Â=KÄõþgÌW#§64Íδ9ÉC€ä^ª÷©Žõø^¤ñ&“&Á?.‘Ê‘ò"Rëäž¹À;f<> þÇ <0B>QJÅÿ|ƒcÚ„˜.Tò¾®†gæJ€©<E282AC>1•k.<ëõºYrA!âÇP<C387>”É<E2809D>(Ck™h% Ä/M§ÏÔØö,þþ\®ÜH=§¤~fÈe/ˆð”£<E2809D>ñ·xóßós˜nFK&ðê‚à&‹†"bê‡ö<E280B9>!ÚRÄ6ÞÓŸþÂàÄ+â_øÓõDLøý%:HÅ$]é,V}ó%)SQ53㯜_üÚjÓÝrѤ<è:(¾”¥-m<>¯zžÎç­Í„ ¯¤¿‰ÅVpD
™ÓßÒŸò½S£øó9†þÈw"·óxàM‡"žøþ»oå3Q¼é·»PÝs¢×@æ× aßÖÁ4ä_øF‡û‡”°n\Š#ÑÒÍLû<4C>„¤Œd`gó2/]¿­º}øÓ(@“&R‰ïy aÇ éÛý]GžF“¿*òËÌöqä¦f‰†´¾V¢âØ0ÿ¯¹ à
endstream endobj 10 0 obj<</Type/Encoding/Differences[46/period]>> endobj 11 0 obj<</Length 214/Filter/FlateDecode>>stream
hÞTP»nÃ0 ÜõSt<53>mt4¼äµ›]hW@M ´<øï+)N <€GîH¹oò<C3B2>î0À`É0Îna<6E>pÁÑ«ÃÖeÔ“ò £¸[ç€SKƒƒºò;çÀ+ìNåÛkñò“ ²¥v}ùsŽD·xÿ‡R€š Bîß•ÿP‚̺Ù¯¡Ê}¹Y;ƒ³WˆPWØ\É<ÏnŠË ëfQTÇFÄÝ<C384>MªtÌ=<3D>^˜c¸|qŽ<71>Ì-áý)Þùä•Jü 0fdi`
endstream endobj 12 0 obj<</Length 117/Filter/FlateDecode/Subtype/Type1C>>stream
hÞbd`ad`ddò ðò ðÑvL) 0q6q5µ‰Šþ<C5A0>æËùÝ÷«ægëyþ+Ýßy…@ÜHꀀ<E282AC>Ÿ<EFBFBD>IHïû¢ï³¾ÿmXñ»Ärj.+ˆr@tEñâ¼¼ââ¼¼ÅÅ+V,^¼BŽ ÀªÅ'c
endstream endobj 13 0 obj<</Type/FontDescriptor/FontFile3 12 0 R/FontBBox[-31 -250 1000 750]/FontName/MPJMPL+AdvP4C4E59/Flags 6/StemV 0/CapHeight 677/XHeight 431/Ascent 694/Descent -206/ItalicAngle 0/CharSet(/space/period)>> endobj 14 0 obj<</Length 409790/Filter/FlateDecode/Width 2032/Height 1612/BitsPerComponent 8/ColorSpace/DeviceRGB/Type/XObject/Subtype/Image>>stream
hÞìÛO«+ÇÁ'àûÄlf˜Í+È:AÙ½Œ ÖÖÆzg6Yi“<69>¥ !Ûƒ<C39B>÷<EFBFBD>?€£p Z_o´t6ƒ áÞ…!Èp `4' ƒÁp¦¸<C2A6>vWÿÓ¿sԭ硸Ü#u—ZUÝ­î_U?>p6»ÝîEƒétª}ÆêîîîÅ æo-—Ëõz½ßïµ'À¥…K¯Ë³ív«‰FéÄ<¿"Ü]Jõ.'ÏóÉdÒ~=¦•Fé¼y~n0×뵆¸„p¡Õy=–繆Ÿ³çù>À%ÌçóÎ+±,Ë4Àø\(϶ۭæ8£ý~ßç2l:<3A>j+€ñ¹\žïFà¼V«•™7«)ÏŸN§ó.<2E>7ëõZ œK¸Bë™ç/—KÍ02My~x½ÏêÛív65ÝH. - p›Íæ ‡%ó<×hcrbž„[ŦH:<3A>ja€³X,µW\MWbYi4€19=Ïl<7F>-¦…N—çyíµÖd2Ùï÷fVܳäù<C3A4><àr²,«½ÖZ­Váݦ)úÛíVÓŒÆEóüÉd¢…N×”Øïv»ðîz½®}w¹\j:€Ñ8Kžn$k+Y,ZàDM×ZÓé´X Ïó¦‡%Ã[`Î’ç/—ËÚJÖëµ8QÓµVe-À <C380>žç7ÕpŠÉdR{¹µßïã2ÛíÖ%À¸5¥ñËårÛj½^¯V«p‡Øôp÷f³Ñ¼'
×Zóù¼²dÓ…Y¸rÓŒ#ДçŸh¹\j[€ÓÍçóÚË­õz]Y²ež†f<18>Käù¡N pºý~ßtÅ•çù) 08çÍó'“I:U €ã:å¾i2e`è.1?±Xì÷{m p¢étZ{¹µÙlj—_¯×µË‡z4&ÀÐ]"Ï7 àtÛí¶é‰È¦Uò<ïÖ®jÓ¤ƒv¹<?•ka€ã,—ËÚK¬ÕjuÄZáuM
0hMyþ|>¿kn$Ã2³Ù¬=Òozyž7]_ív»¡N 0\My~ÿ©õáÆ0,Üôd÷t:ÕȇZ¯×gv2Ô©a†ëô<¿°ÛíÜ9œKçS<C3A7>GujX€á:WžßRÕb±ÐÎýµÌ”8Q¨Yó Ôóüý~_[Õt:ÕÎý­ åùËåRó Ôóü éÎQ;ô7™L.”燚ó<×ÂC$ϸ*ëõúÅ%…ú52À<10>1Ïßívò|-‹Ú ªét:?DX¾¶žÙl¦†èŒy~Ó½g¸<67>ÔÎ}ì÷û¦ Íæ ªZæZ„·45Ààœ+Ïϲ¬é†qµZig€>š®©&“ɵ5MÑ_.—š`pNÌó·Ûíz½žÏç/š™ÐÓyøÑ<E28093><ϵ6À°4åùç2ŸÏ52@Ûíö¼$ò<oªp½^kp€a¹tžor>@OËå²öj:<3A>]çb±¨­s6ip€a¹hž*×Â}äy>™LÎ~MµÙlÌ»‡ËåùËåRóô´^¯›.«öûý)57 ¸ZKäùáž1Ë2m Ðßl6«½²
¯ŸXójµjºfËó\Ë ÅyóüpWnOœBpkò<Ÿ7Øl6'V¾Ûíš*ßn·`(Öëõü«Õêî­,Ë­¢ö §‡‡<07>Wîó,ûòåKí×ìÍë׿ú<C2BF>égŸ|ª)àš½÷λ¿ú<C2BF>é‡ïðæõk­5cuÿÕ«WÚýâ_ýÇ´(ŸgÙÃÃ6<C692>«õáûx f¬Þ{çÝpÖ4¹¿¿<C2BF>y~(ï½ó®9¢pµ¾|ù²x &¹Zcd>ϲй¿ûècãª4ùÝG—#ý"PúÛ×_k¸6ÅAúÛ_ÿæ¯_|¡AÆ$Ž®†ÎýòåK @ª˜ñ›©>\¡?þþñ ýðýÞ¼~­MF#thù ì) €‘ùêÕ«ß}ôq,ŸgÙ¡å³O>­Íó¥úp!á Çì¡3±Ã!_9Hÿò§? ~¯Ä›×¯Ë'äCWOGWîòðð aÆáó,kIãÏU>|ÿƒCSG Éï>ú8>tõßþú7•#4¼êü>»¿}ýu¹_]=ô`zúÕ¹£ñ4y~Œ•L…Ó<E280A6>˜çÿåOn:B¿ÏëÄ<?øãïÿ sÆê)óüß}ô±YúpºóüJhœ¿ùÓŸïïïµóÓ;=ÏÿêÕ«ÎAU<41> 0PýâJä~Déœ/„3*táÿŸgÙ¡¥çÜW¯^ií§ôåË—å.8¢g{vîÿ<07> 08§O½¿¿oIò?ϲ‡‡í gÔ9ˆvÆòÙ'Ÿjð'ó”L…óó_¿øB Èéy~e†¿$.í òü÷Þy7Úá'ö4y~èÜ/_¾Ô¹ƒszžÿÞ;ïVÂ"I>\ÔEóüPù—/_jägqé<?tn8çkg<>:1Ïóúuyõ?þþ÷÷÷Z.ªœç¿÷λáσÊoýaïuª<îth϶ ôè\81Ïÿì“Oc¨øÕ«WÚž@9¶ý<ËZ÷ááAØ{µN<!ßßßë\;1>zï<7A>wÃZùÓŸ4&<<3C>Sòü/_¾,òá¯hÒ+qâ 9ì •Î5Ì
0&§ÄG_½zõÛ_ÿFOì”<ÿÃ÷?(¯k$e€õ¸€ëwJ|ôy½yýZÂ;:Ï¿¿¿/Öúðý¼Wè”rèÐb­°{„ŽÖ˜ãsâtPàé<1D>燅Ã*Ÿ}ò©6¼N§œ<C2A7>ÿò§?0nò|œ£óüßÿà«W¯4àÕ:å„üÞ;ï†Õµ!ÀˆÉóapŽÎóß¼~­õ®ÙÑ'äû·4 À¸ÉóapŽÎó¹rNÈ´ÁàÈóÇÊ â#yþX9!ÐB|ƒ#Ï+'dZˆ<5A>`päùcå„ @ ñ Ž<¬œ<C2AC>h!>Áç<E28098>2-ÄG08òü±rB …øGž?VNÈ´ÁàÈóÇÊ â#yþX9!ÐB|ƒ#Ï+'dZˆ<5A>`päùcå„ @ ñ Ž<¬œ<C2AC>®ÄÝÝÝ·¶Ûíõl•øèP¡ûŠ~ ª5xòü±rBnÙ~¿ß6Ëó¼iÅÍfs÷Öz½•t~Ðn·+–ϲ,ü¿vyþÑBOµôcKõé—Ê,Viê&y>ÏNž?Vò|à–ŽVm`»Ùl¦ÓieÉÕjÕô»Ýn>ŸW¯¤ƒòü£Å½Vm®Þ¿_
áõårYY>ì é(€<Ÿg'Ï+y>pËÒD·=Ï_¯×åì7˜L&ÅŸËå2­·ÛÅf³YX>Ž„?+ѱ<ÿhíã2i®~P¿<¾ óÃë1ÃËÇ?C=•H_žÏ³“ç<E2809C>•<¸eEžß3wÝív1òÝï÷Åå¤w½^——o)ñd2)Gôqšwe´¢éBoöYøÐ~ EñVVŠFãàN¨­¼°<Ÿg'Ï+y>pËŠÜu³ÙôY8Næ¯ÌÇÎó¼˜ì]Éuc>Ÿ%yZ¬*Ž <Êóëõ:´I¹‰Ú»fµZõ©öÐ~‰ùüb±hªª<”#ÏçÙÉóÇJžܬ<Ïûççûý¾iòv°Z­Ò¨¿˜^ ù ›Í&<26>”kóüíÏúja3ŠµÂw<±•ž1>*Òõ>ß½xD¢g~~h¿ÄyûéÈBÜ…ÊQ\<5C>„O,Öê3¨<¬äùÀÍŠ¹kŸ…³,k™ÌŸF¸»Ý®x¥iÒxñî|><3E>¯”óü<ÏÊŴÿBøX MƒãGo…eÊk§¤úƒÈóû<C3B3>ËÑ/E{Îf³<C2B3>,ïE•<45>!ì9ÅB¹Gjóùòþ­¬>¨ò`4ç<E28098>•<¸Yëõºižvj±X”cóT%nÏÿërà˜ç‡UŠ ç©ðzebzܲÖd29:
¾þ<?>:Ñgû¡ýÒ™ÿ§OU”óü8·¿O<C2BF><>ÖK'yþXÉóU$±“ÉdþÖb±¯4åÞEÌ­˜Mgqǘ·©Â˜ÙÆ|>®RTUž<55>¿Ùlâ¬ûJ°Óã"Ìß"ÆÚá£c:Ý4½¼Óõçù±æ? M××Ú/±ò¬!-F…Êq•¢+=Ç\Ò)÷cø7~ñ°zèô8ÐgØ+y>Àà„ÛÀí/<2F>¥ÚpǺMê wµáF8¦ñþ:܇6ÝY×
ŸnœÃ-pyªa¹´„-íMV «Ç<$V¶Íì<>¡i2êYv¶güŽa»ûY9l9ñ@†¢itøihš;§ß§*óºÓé÷é¼îøJí4ìp:Š?aåSSL<53>ƒð<C692>ÒŠ¿¤ÇMí¾þ<?&êÓé4½ö8´_Ònª(ÏÆ?±GZžÂb¤_['”ÉóÇJž08•œ¼ånô ñÙó²CïC%娼ÿ<C2BC>uE¸<45><C2B8>w¬-jÃZᶺ<(вmϘ-_J㜱eÊ)Ç÷áƒÜÝÝ¥ûjüŽ•£,æ3Àø”õŠ1ßò€oåWæ)óü¦O‰ÁuyŠ~<¯†m®~Ýï÷§LÑ¿þ<?\Z”ûq±X”Oò•Ìü)óüC{¤óg·˜ð_~¦jÉóÇJž08ÊókãîpÚ¿†¦)ŽµZF
ÂýiŸì½eúbEŸ¡<EFBFBD>²rBrËFœç׎^”ç‡<C3A7>d^rÜ|Wà:í÷ûÅbÇyËo=ežßtb ¿éfÄójËÏküm=¢M®?ϯm¨òÃåÇž2Ï?´Gjw¼²xUcíäùc%ÏœKäù»Ý®)ÜîœK_8(Ìo¹Ã=4ÌïŒô<C592>Ø0<C398>±FœçÇÉ<C387>Gçù&ðà ¤gþÇl<ÌË?1O™ç·œuÓ8Í“S§äÀOúcݧc{ÙŸ2Ï?´G:÷±pa槇>äùc%ÏœKäù-3Øû$ÛM<C39B>Él6+f/—ŸyoÏáËSéÊâDè¦í,ϻ묭¼m§¤ã6Ö<?ì*és(ÅΰÛíj<C3AD>2y> Ô)y~LMÓ¸eît1\~bŠ?ãÏPí<50>ÔciÐ9ÏóÊ*-gÝ4Žî“÷©¹Épóüø8C¹×í—ؼMóÂë•YG÷Hgžß§fx”ç<E2809D>—<`p.ç7MW.¢Î2ôߤÅbQ¹GÞívéb•H$|Pšü‡ÛÕÊåtƒÓq‡Ú‡BýY•+ ÿ·áµ#1ݽMcÍóÓOO;:ìw%éw—çÃ-H“ÕÎyÝ•U:#ô´Â[Îó[¾ì)¿AG4re•ÎæM+”çóìäùc%Ïœ³çùiî] ·f£Ei˜ßãËQj´f wþìü¬°LSD¿ßïÓ1»é[p;yþ釡PF)ýQlí¯Iü=<3D>ç„xÂiú9+~ËÊ?7}R÷b­øÀc¿Œ7|£Oz#ÈóË× GôKûNÚ¶õHyšAçHØæ³ÿ.3Jòü±’ç ÎÙóüøPy ½ã fg>ÿX—Ž¶Ü`¦cåÁ‚bôùjñ~6*?þè|ûÚùü•§ Ú…ûñmIü¸PIøjóŸ…ÿWª-žQ,°Z­6MŸO õ„Ãò±òPIh™þO´lÛAÝV ûIQIøOø³eú'êEË”¿`gåíûj<C3BB>î9±Ëb¢ê/wel“ðŸâ•ÙlVy<¤ÒéÀÐ¥á|ùÅp^JW©<57>âÓì=ª<>|c%MQsí6ĪZ~²[¶¤Ó óü4œ?¢_j³÷BœcPþˆ£{¤iBŸ-<2D>2yþXÉóçìy~e¢ûr¹\¯×<C397>h¹gL³Ùö,zþKíy~Ëçîv»JUå(5­*|¯Î¦¨ m:ïºÒÅ}ýjµzQ'~ñðŸJÄÕ[¾þ~¿O·¶²z{ú*oª¡ÈˆúäùE/4mÃl6«]«Ož6¯©é
Óé´ç¨Gô¢KÜÚ¦é÷é~噫˜šVÆ銇¹Ây»rŠo…˯Ç3mz>ŒQä<>ç™J=éZå
ËçÕÚ<EFBFBD>ÅXíqÏ<37>c¸•ñCû%^¥ ?¢|ISîÚ¹q­J…í<E280A6>(ÆjýÜÐIž?Vò|€Á9ož¿ÙlÒ4>Ïói6{ô=f;Ô¶RŸ‰Óéýƒ¾Kšç·'Ò¡©Ó¡“J^é‡í¬hÕVf˜§Ã<1F>y~ûÆ·lCgžß¹y ÓDò| "œNk³ÖxLO2ñÔWy+®R9éÅçÅ*§ô¦zÊç™ðVåW ¾[9۔ϫáƒ*_*~V: ÑÓ•çùÅóqéëñ§ƒ#‡öËci(§|E+ÑÞ#ñÝ´GâZá­Ê—*ÿúŸòÀ7Bž?Vò|€Á9ož_‰mãóÝqrZçÓâ<C393>u1i¸«Í²¬6$iƼEdÍÒíé¹bq·~\óV¶¿3rO?«iª|Yÿ0¿%Òo™Tß™uz†ùµÛЙç´y-ƒM<C692>;ª<n\ñ#8ÍÂÉöî­ðŸxŽmT<>§ˆp/ÖŠ¯Ôžâ©#Ô\|PüñMãÜbáðÑň¸mq 3¬Õ”ÇeÂGT¶íE×t-®<Ï/~B[ÅoÄÙJ\¿<þòÇ«ø òÞRÙ¸pñ)a±¸måK¬´Gâ®UÔ¾~±Vù-½6€”<¬äùƒsÆ<?Ü«Vá8-Mk[ÂùJø_™aî:9ÿ}6©%©.niûLHKŸ/蟲¦ÍÛ(¡v<"F1-­T|µ°XšðÇ(<28>¸S¦š&j¦ÛP@ZòütÏ)}*‰SyÊÍØžç§ïÖÆYG Ö¤H [
±¡šòü°mµ­[¯ÿàp ZÎÌá´Ótþ¯×;†ÚšV©}\+œÐÒœ¹ˆCý¡ªÚÍK'{?þ2=®=ɇóðÑaþãÕçùYµü¶\Àôï—BhÛô篶mc<6D><6Œ§Óï †ï<E280A0>~t[#Ï+y>Ààœ1ÏOoùã i|=Êšojsìl¿e“:ç?—ãÓ¦Ûít{úßü¦Ðÿöôs+Ï5Ôå†Íó<Í«ËADÚei|”~J¦)¤QI¡ÓĻҕVJ§>¦ÛYžLØžçW>=I¿`Ӟг›:<3A>²tÿé\Šp)†\ço…ÿô|¾,œLÂùªX+œâ:,B<>a±bù°bÓð_1nß ×jú -çù•Ï
ßèˆÇÜ*ž1>
_omiÞÐq±GÚ¯Žè—(´ òÞRÛ¶¡Úbœ·ügŸ)ÿö•?+8âÉGn™<¬äùƒsÆ<¿2ñ¯2¼’ú†?[ªª<C2AA> Ø$|P¸«mº“­L§ÓôÖûzòü4I¨ÌµKç§-YÞ€J§„Õk1<E280BA>ÒKGj*i!<21>¥_ތʷ¨M?ÒÌ¿¥¡ZöðÚ¾«l^vÈ]ª<ŸJžvâ£'Ó4ç<E28099>2Ààœ+ÏÏó¼=×MgA·Ï
Ûn·iÜÅ7Mœ ]ûŒyËtýr¬}=y~g÷•g­7U7 ÿC¡afà÷œÜž.7£Rye(J·6~ÐAy~¨?<3F>Ǫږ4_QžœÅß¾þúó,+Ê—/_>ïÆÈó{
={-|©+ÜBy>ç"Ï+y>Ààœ+ÏOç<4F>o6òýÓã²ív»\.{û“ɤi~±…Å¢g°_¾óPžŸnXKž:¨O´[8ÿé³ÿ¤#Múú®AÓÖÞPéŠñ °ña¯hùÖOÖMò|àó,qÊï>úøy7FžßÓõ'œò|ngoç8ò|€Á9Wž?›Í:gYW™N¸bÜívëõº3Û¯<Pk»ÝfYÖ™íÇ)èéHDX·çf‡%z*¡²<C2A1>ÍóÓ »ÿ~<>¦×Sý7£§øeÛ*Ïó>ƒ8¡§*#POÙMò|@ž?Dò|n‡<¬äùƒs<?M¼kgYWòüö á-ò</&Û×NÑ?t˳,K7¬Ú§S»{ÖŸÖÜÛäùgÉóßõ|Ä#ôסû¤<8 Éó¹òü±’ç ÎYòü,ËŽdW«Õ)¿ßïÓœö¸14•- ¤±|Ÿiöyž=ð(Ï?_ž_hJû=tÜw“<¸ª<?üÎߊ<C39F>ª<EFBFBD>—<ÿÉýxâå boç8ò|€Á9Kž_;¿½<C2BF>é´¸^¯ËSú;“„°@KP\_o²\.›š"Ü7…É-Ò¤ú êKçùiÓµ RTÆMB[Õn@Ú¡…ô Ž¸•Á #æöÌóˡ†Z,“ɤv·ŒßîɺIž\Užiò|°·s%äùƒszž¿Ûí^œ 2<C2A0>¾²=åIòµZòêÊëÅ¢½ªùêéwìœÅÞMã⃞¸tžŸ~©¦Ñ“4<E2809C>Ï~¾<>K­vP eØ¥²…<C2B2>=~PC…^ØþRº÷†ïR驃¶Ažœ…<ˆ$œÜ{ûXÉóçô<?<3F>»~<7E>Ê\è4ÎZoÒO<C392>1{úÕÚãôÊSáÏwZ"ýôÓ+vºtžÿ˜ÌºošßÚo6>O.¤­7#´­PgZCøÄÊqZ*}«v¸OÜMò|@ž?DNn‡½}¬äùƒS´ö£ìJ&\NÔkµÏ…NÓÑ°@S¤^oÉÌÓ:lj:Cûñm¤¼\.+ ¯V«ö +>.#Øï÷iø_ Òûx<?m¢Ê·®­¡û§<C3BB>!„?+mNίlFúPF%uŸ6iÜÍÚçç·<C3A7>Õná³ÏÏO{=yþI8¹öö±’ç Nšç÷T䱻ݮòúb±hÿÄ49¯ÌÇ® çÓiX1ÎÍŸR‰ ëõ:Ö³ßïk— õ¯V«XUS ¤¹Ó-O+¬Ýø¦¹Ýäùi_Äõ¡Ãb¡_j¿re`"]¦i©¡RIí NhÒbä(T•Žïö†Jû7¼Rl^±…¡ªJ#tîÃgï¦tD£Ø£Êû30nòü!pr;ìíc%Ïœóü4­íL 7M{Ö½ÛíjsøNi [;3¼<33>Ú'jg‰÷Öjf¡ÖäùµÝÑ.<2E>:^;(Ðsÿ‰šbÿ>íÙÞPµV´mOÐMM‡aùQ`ÜäùC$áävØÛÇJž08'æùi<C3B9>Û'¸®¬þ¬,pD¤ß”™é·Ì¥?"Ò?.Ì|ª<ÿ &jj™Îþ
Ö¹=#ýétZyt¢³¡ÚÒ'è¦,ËäùpãäùC$áävØÛÇJž08§äùéÔît†|­4¹ UUÙï÷ý·- H˦N§Ó>õL&“tKRi:}܆µ{²<ÿñí,ýö&
-Óþ]Z"ý"!ï¹íãaKGú4TgÍÅwì|ºäBÝÔ4N$χÛ!Ï" '·ÃÞ>Vò|€ÁY¯×wGÙï÷ͦòbmH
UVlJÑw»Ýjµjš^ϲ¬2[»IøˆårÙ”Z/‹Ðý'Ò‡%ÃG7<47>8´aMÂê•Vêì¾´ýÓJZ¶*ÔÚ¡ÜÚ¡¹Âw ߥOË„eBýqõÉdjtèf”{*lCØ ÂÎptCjû@ew
Úûg隸†¯9/9ôa`¸äùC$áävØÛÇJžÀåìv»íÏš¢Ýž¶%'¦îçÝ0n“<ˆ$œÜ{ûXÉó€èþþþó,¥çbåòåË—Mkýíë¯Ö
o5­Õ´J(a3ݼs•rVöÞ;ïž½þÐ ×SþúÅåø誶í òáûÄoñ—?ýy(ýððàÔÄ¡äùc%Ï¢žAAe±ri™¬^žÓ^)-qSÓ*E°|èæ)Êͦc³åxi:0[Žeå¢=Ø¿üö׿)<29>9´®rÍ¥<.Y¤Ê<C2A4>—/_¾|®aåûûû¦Ušf\?:µåÍë×M«„·šÖjZ¥²m®ð€±’ç+Š<_ž¯(Š¢t^n<>÷º®å²üÀQ¥ô¼æt…ŒÕEóüÏ>ùTž¯(ò|EQEž/Ï8ÝEóüÛ1y¾¢ÈóEQyþA<17>M«Èó1¬<ÿáááÐÍSy~ÿãEž¯(Š¢Èó®Ö°òü#6OQäùý<C3B9>y¾¢(Š"ϸZò|EçËóEQy>Àõ{óúu¸iŠ¥çbåòÙ'Ÿ6­ÞjZëË—/+ o6»»»ívÛ´Êq7”"=PäùŠ¢(Š<ÿQžpõÖëõŸm6 Â-{óúõß¾þúôê©­ÿáá¡i•ûûûÚUÂëgÙ$¥ùêիϳLQŠ2ô1kåŒå½wÞ•çwnk €‹úß~øß&“¢ü×bqhÐÑBgÔ2딉dÀÉóàúÉóàúýßÿú?ÿó¿ÿ<C2BF>¢ü¯ÿüÏß}ôñAåÍë×Ú.m>Ÿ¿øÙÝÝ<C39D>€+$Ï€ë'Ï€ë'ÏžÑ~ÿãrùÝÿ¯(áÿáÍ)y>ð\v»&“ob˜_”ðŠHRò|àYl6yæe6{£} <½õú_µI~,«Õ½V€2y>ðIJìûö0¿(­ ’çOi¹ü®O˜ÊdòMžÿ¤Å  ÏžLÿ0¿(óù· ´Ûí¶Ûí~¿/¿(Ïž@žÿ4½9(Ì/ÊÝÝ?µ5k·Û¥oÕ&öåÓÐ^ž\ÚÑa~Q¶ÛkCèo¿ÿ15¡ìv?h<>JˬV÷óù·E ÿ¿»ûgKɲïtàhEö¾ÝnÓ·jûöwåùÀEív?L§?:Ì%¬žç?iIh±ßÿ¸^ÿk¹ü®r¸ÍçßJõ Yöý‰'¢Í&׌ Ån÷ÃdòÍ)ZQhLH<4C>¯,û>íGYx׈Øf“Ÿ~"ò¸G<>烰Ýþû,a~Q²ì{M
=3üJY.¿»ñv;ñ)¡ò,};!‘ç?¯Í&_,þ1ŸÊrùÝ~ÿ£6<C2A3>Ôzý¯žùØlöf·û!P<>K†Å4,7(üÐÜÝýóÐ ßásÄé¨O }aŸ ?yþ3Z.¿«Ü×O&߸µ‡ŠƒÂü<ÿ)¬þíÌ*ãÂp;V«û³¤Ðóù·7ۆ皜÷<7F>ˆ.'Üçn6»_
/îv;<3B> ”<ÿ¹dÙ÷Mw÷Óéß·Ûk"x¬öj ˱X8ˆ:W •kanǹÂü¢l6ù ¶áy'ç;\BžçYÍf³­&“Éb±X¯×Z yþ³è|sö¸qýÃüÚ@¬OzFíÌ-Øï<o
=<3D>þýñ¼“ócÙí~°‹œÅf³™L&/1<>NÃZš
yþÓ ·í“É7}nðÃbÂFnVÿy°-³[g³7<C2B3>GÙ~ÿ£ÖfôæóoÏžBßÝýÓIé,%ôŽ]àtëõºvþü—¦Óiº˜‰úÀP¼8<C2BC><ÿPyþSÏ0¿|/oäõœÛ>æŽ<>Î#n6{£µ·íöß—H¡ÃÁuSÏ]hr~Q6ÜŽ
pŠív[žrŸeYí¤µh·Û…ef³Y\Ë,}`äùO)Ïêœ-l$<öŽû<À²Ùä<C399>õ¬V÷Úœ»\ÝòtÌÈtNÎï[l_=ô‘à‹Å¢¸Ͳì Ãòq@3×o~šÊc‰òüvÅ?N‰MÂÍþvûo͈ƒ¥˜Ü:ërù]çñåàb¬²ìûCg݇0¬µÛýðØc,àFŽ<46>övè“ƯV÷î.§¸ ],G¬»Z­ŠÕÛ§ôŒ<><¿EŸD±OY,þ‘ç?iOF¬s"ëdòM4öÔçјP§#‹ñ {uØ·ûŒ©˜á—u>,3Ÿ;úf¼»ûg{#ô^ìì g!€£m·Ûâ&t³Ù±ú~¿w Ü&y~“õú_g óã-}¯U«öèìÐ0¿Vé<²n!äÖtÎ  ì÷?¶W<0E>öJÂo܈۰3‡ïêèX.¿³Ó!æùGO°w Ü&y~­ÎÉ<C38E>Ç•ùüÛ#RMžWžÿtw÷ÏÐwE1.Sk:ý{Ëžt£…;«Ð;ÚŸÑèÆ
ÇZŸz:™ õŒxbyg~åû×Ö~~ Å/;Àbž¿^¯<>XÝü|àfÉóSáƼ}^_œ!Ù9ò\•yÆ<79>a6{SéÄðʈs°#l6yûnJs-ÿè<¬SŒFç¼úp¸õ¬ªój¬cagœœ_è<ÅyPà8ÅMèl6;bÝpëzâô~<>çWäùO<C3B9>3ñBY.¿+–¯Í{oyV䘬×ÿj
…âÀcWä~b[õ9$ÃèF༹qg¬ÞÝï_3žwr~¡sœåˆ:X,Å}høOžçýW̲¬Xq2™hFàÖÈóËòü§>á|X¦²b}ßgJÿègEŽIçÔVMTØï¼tÌjè<¦FKrk:‡®}%ü6õ<1E>³OÎ/„–ï©·j·ÛÅ[ÑÉd²\.7MK°ϲl:<3A>ƵŸš¸5òü²åò»>a~íìúýþÇöYÊ'Æ2<™žÃ:fcڧž+ãêœp»ZÝßòî}CÍçßÆ$3ìÃáEûçh¥£³÷γÙÈNe—˜œ_è¼BȲïíƇZ¯×/êÌ©œáGËåR—sÐóƒOIžu†¡L&ß´çðMÞ9Á²i?×`»ýwÏG-ŒÈÚwøõú_ç;Y}Û~lÞÚŽšeßÿöÍ/ÄŽì<ðzôCD*a‡! Å&Æ,¤À;ì—ÆYðîãZ{`½YÖS/Æ »‚Ç ˜fÈ,fm‡d<ctB3a¼ZßØòÎ8šõ”¤-wãÛÕ²:]O«ë¶ºu{®tWw?éxŽÏÔŸïœ[OU}?Š¦ÿÔ=uêü«®ß÷Ûáíßç0G»<47>f•Ã_SCÉ*C_Êòå«·´Ülu}DÑs °,ëÔ2†A™ùA†á`0X]]…¯ð=~2ÛhÛ6üסçí<C3A7>Ïg û*
W%¯^çUBpÀi4¡´ÂóÆŠÛ+úf<C3BA>³ðý¨6»%•i%Æ4$¦pƒ®{KeóHL`iîwç…tïXgæNuÉùŠåS<04> "7ÃáÐqÃ0p“oY¼_k,GA„nA Úo†ëº±'Â0d?ö߈ž7E>ÿqÏNU´ØRÆÊÄÓ‰Ù†3šY:Es©ò¢XL¼Ñg§ÜËáγKiÆ|XzÞîKqÏHÖašë´<C3AB>Dg¤Ï èÁ"åÃF ì@ЧÒä|Žt 
oÓÃá^¨Wƒü²ÒëÂKý<4B>  ˆá0.ý_•-`YSúðÕqœ¬-<2D>ùü ˜ª¸²|IwREÜ=ÙF¢h¾TÎs隺¥H%aéYª=»dÒ—&õ£ÛûZ<>4øëûQÁKHË;£¬:9Ÿ<39>oJ¢Ç:ADKA^ö ¢‡¸®Û<C2AE>G<÷Þð wguunÍ4M~Q%ÿ°, þäû~͵*g/ôÜç+ŠÜÜþVš.‡ç<E280A1>é_èfQ—ùÐ$E9¸=ƒV­¿³òÅÝ4$ gåÊ|
EiK=~XåaÔêpX=Éù iü¥”ÀAQ'ð"¬"7~ãÉßþÜK¯fôg/<2F>ÿ! :Cžïa²{á©øž<>oÛ6ûÆ4M×u‡ïD€KC=Oî¹Ï—¾•3-EóÜ—<C39C>ºøҥ¤âÖá8;Š.Ô4×KO8o5Ð õgƒC±ølêÏÒ”ï(¸ 5Ï£5;>wà°íQ{›±žä|†t£ô) l ˆrñ}õ1ƒÁÞÍK/ñù8ýëO?ÿM8àG¯Ì?øÙWß~'õ€?µQל>}úÌ™3O=õ™«¶C]I]IèÆ“O>Ùê®ìÀÿžç±{IýçATâŽãÄ„ý°ƒb@¡Ï>_jÚ™,j®Ä¼Ab)¤K4]dAÕ§O)' < ·(<o\Ìç½CùÚ µÐån9îEjéÀ¨39Ÿ! ÓÎ; ˆ¥€·ìÁ`ÀŒ}lo;ühFÌ0À;l%V€û|(9ö§µ<C2A7>#¦ë/îÃ<>F‡Y>ŽÉ¬}ï ÛÛÛë<C39B>999¡¡Øj¨+©+ êÊâ ‡Ã.ù|×uSî ø#ëé_?|+<2B>ã8*ç÷ÙçK5»a\)%; g¸j€Ã÷£^5¾Hs,ù±ººGÍöGH9ÎNu—vÝ[ŽŽ©,¥äGj¡K<C2A1> ‡w¥Û7ÚØu&ç7ÕwA]%Š"ö®-bš&ÓõüE;‰a1ó_Äç_Ü=f®þüÖ~¼<ž">ÿÚ<C3BF>GÆææÑýK{÷6'íؽ¹¹ÉtÓññ1 ÈVC]Ù666¨+©+¢c>ŸIï,Ý ÿ„°;õ<¯ñªŠ[U¶"öÖ竸Ü»4áÞýkFjc(“! gx»•ÓóêU#<23>3â‡i®«Ÿì8;´ì4H#9Þx$®<>;\¤!°Šb|5ï­ ‚è*âÛhL×Ã[¶išü7eÁÉðU<Gå…WÄç_»sÂu=üx{úñùk;GpŽwu¿Eéú‡‡‡ÛÛÛ»»»4Ûëʽ=JE£®$¨+óÓ+Ÿ°;…»n¶žð?<3F>¸QÅÏ÷Öç×/R¤šÎ¶GýiÿƱ¬ ©í„s°y55ƒgÈ×<C388>âϦJwTŠ4ð—*ðaé€òÀÞ;ÉÎjuø£½HSå¡g«¸®4Öºà²ôi^Ý2. ŸÑg0ˆr~å1¢Àç߈Þ¾çRÜ“.ñù¢À‡ï®OÀ ±t} h äó<41>ˆg5¨ÜZß|~Í¥i«¥_TjQÊÝ@ Hý…WpðlØò{áÝÛí"M3æw·²²µººËEÖmŸTŠâÒÊS?Òou;ƒ¤‰åpBfMýOsq¢áW¯hkADgµ<o…oàGü•VLÝ—¾ðª€øüEÂÏŸßš )ú“ÙüÜ<C3BC>HL×' ˆ¶@>¿Ä ‰ŠŠ¾Ÿ>·†q¥ë²„Ì6zÈv<C388>«`ž´L‘¯ksé<73>ÇJG*x—Ê¥‡3U6¡´QáöaªÔà íLbyƒÉùŠÓ¶º¸ AD@:KÍÊÀç™l¥¼ƒã>Ÿ |æç/íÝC|þædvq÷XL×' ˆ¶Ð1ŸÏ2LÓ\Í€ÿ³±šMÕ•Œ%ç+¦è÷Óçã&°R¯%5l®{<16>ê©Jº²º5í!¸¿ª4Vf
®¾ÛÕªž7ŽÌe‡eÍm{¤®ô¡g)ŒU:èti@¡O¢f“óÒgJëÖ" ˆÚàÆ^c“õ<ùëâqŠ~‰ï°¸Ïçß»ú(cäæÑ}Äç_Ü=ÞœÌÄt}êk ¢-tÌçóç{*­!ü?cFêuñÿpzèó¥£R¢â“)<29>¯²i2ÇC9ìðý¨žúÀHƒ¾nWwKZm¡}jRʽHGfî8£J¤@ fÕ6þ{t£V=.ÌU·O­DOÎW¬F· 7© öø_µù|Qàßž>€ß >ÿÜ<C3BF>èdþ<64>ÿxíÎ õ5AÑ:æóyz€¶>‰8†aÖ{èóñ ùÒù¤2Ç4×)K¶þ®¯awúWT@†q¥žëG«¬xMv
T}#Åv8¼«É}2-A!<21>ÝÀ_ëi|­¶Ð:$ç3¤bx¦ÓÈ'<48><C382>ïûÈ_uðù€wuŸùùËãG#ç·&ˆÒ?™?<w#b߯íQ_Am¡c>? ÃÕÂTZ½¬ä|†ã8YŸíÏ—ŒrzáÝÞîuÈÏ츈f‡m<E280A1> €ÔÈB+ü3®­j€¾éàE ¢’?_|]
ÙJ<KŒ ´hƒC€EoyµUO,_YÙÒ¹%¥Kz=Éù i˜žRô ’À;,ò®Ê_À³2Ó¸p Å+#õùF‡ÌÏŸßšÀ<C5A1>—öî!>s2»¸{̾?{ý€úš h óùšcÛ¶tw@VbCß|¾&úBV¨'²Ðƒ}<15>Y<EFBFBD>þEÌ Œö6c#þ<0F>éïФÙÚ%î‰í
Q9jsËÐpßÀjìº·à—¾Á¼¨ÓÍV‡tå¯9[šâ®s³ã§þð(¾Ѷ; ˆTLÓdï¡A,ûYþ
œã³I¤>ÿòxÊüü…Ñ!üxóè>âó/íÝÛœÌø<C38C>= ˆv@>¿¦F°,+õã½òùRwQ§ý“æ ïR©T™Â µPVV¶ZšÔ¼©M%xZ¬þ“oÒ*nA%¶“•zHß<48>¤)뢅ú8Îô;ÜHë<¿tgVý= 'u)øþ<C2B8>!­RY<52>9 ˆ.Á-:àºnVZŒ(ŠÇaŸ2M³ÜšdùüÅãœüµ<C3BC>£ÛÓðýÉü!âóÏoMÄ®Ý9¡¾& Zùüz€fxVƒ”T]ß+Ÿ<>+ôš#£h.u;ôú_O;ÃáûQmUÒMè)¢g*¯´V:oyð¼q#a&•¥Oè8X<38>—ªrØöHÿ Mxì‰ÝEýµnºÑ³1ñ0DýÉù üYÓÈ& ý±,Kå¥uñ蟇Ðu]ñíð}¿”j¨øüçnDˆÒO¸<Öú¿”ƒƒƒõõõíííùœžS톺ºÐ<E28099>ýýýÖueß|~žç9Ž³òø`0DQTõuyfB*|"'¹±?>Þ£qwT¿<÷ýHê©ô—Tš#Í®¿ëñ*i¢<E280BA>‡Ã¬6žÝݔٓ†3©Íö¼qEW‡õPejÄZ²¸<C2B2>ƒ}ËÚ(EãWt¨¹»Úk€W¬Îmkê<6B>©gKRŠ>ADà•9öÒšõNšÜoÜeU#‡Ï¿¸{ŒøüG÷oOœßš¬í<1C>ÌêÜë<>9>>¦Ùj¨+©+ êÊâôÇçAKà†Q©!‡`øµÇñ}?öOÎâqƒçy<íÁ4ÍX”¡ŸEsÏÛöøFÏ 4ib#ÕÆU¤Îv7FΠ…g‡™:¨¶#WÐMåÄJÓtõL)×VúIãbz®HR<48>^ÃÜ—Åä&¦ÜFÕ°>”•<E2809D>ß"ùÌ<C3B9>.õ š^mCum¬0>¯)EŸ " x<>…÷YöÒªâóá6™¨V„>s2C|þ¥½{miü7o2Ý4ÍÚRgE¢( l[†™çya¡5DÁÇ>”QQæg‡»2uA`99G§ÔÐ<C394>Àöö6ôãÆƆJW€„̶m>ÎáG|ï’Ê(Uo‡Ó¤?,Õ•úL®>ø|˜#†aœB<C593>˜æ0;àÒ0UÅ<55>IŸ/ž2Ó4aš¿/îóƒ`S4ð£†Y妹®a¯t×€æ ÆÌá#mkÛ£¦f¥©pXÖFývEÚé
4i8LçÙ]]{n JÒlózrŒa­Æ[¯ y†»€E×½¥[w‡w¥<77>5¯¶éîY輡@Ú׎O ˆ¶†!“T¸ŒÍGŸ2ˆøüó[“µíññqÇ pEŽã  e¥kÆR7¡üÔ¡ÈÇ\EÑE÷¼+³XÊ7f<37>ˆçyÒr`̈©¢—êJXMÓDFiâS¥¶mgÝ£ÊÇYªz´…ÖÍÊ>ø|X½¹Ì‡o\×eòÀ`01…^
©ÿÉ >?ëƒ}~™¬MF)È»Úú
iv±VJ?¦l/ÆRy¶¦¹îº·êläd˜)u”6xæEëÓN7Tx{ÂðÓª1a"Hg<>1XÆa…YÊ™Ãx€6g|~L=ªÎÆGL}² ¡&ÒpFSA϶LpÍc ­7ºÅG úwÍ^Þ?øÁJ}þÉÉÉ|þË3Î^?@”¾´>bQYÀ pµTQ,õQE6ƒd9*>Ÿ—<C5B8>
(šR¯õà²EáÖ+V”ŠÏ·,KZ”ëºY>¿þ¶Â#Vbä(iÔsŒÒX­Ô?žÌp¦Ñ®yQ}ðù|<7C>‡I<E280A1>r
Ã<EFBFBD>íêJQñùYwÏç#Y¦ZüýºñthÛé¬ôó9ü¬¦®!yruuO¥ª ¦qJSôµÚ”¡ú®´†Ãáݶ,GM­5¥ß«8Ùz“µiØÝ1ô—äŠÓG‡<¤ùÚî¹#è61—Êúúúk¯½†²··çlll°d˵<C38B>#ÄçÿôŸßQ/*øœ§ÁÉT”bQ¯¿þº(óÇ¥+üõÙgŸ=}ú4bÍ ÉÓO?½š—<Léïï¿ï¥RÜëñÜsÏ<73>¿øE^mÛb ¡Ôƒ9ŠB¬W²¨Ô“ᯱ ™1+* ÏOýmõ©O}ŠWj5 xå£(ò}†™¨ôc%ðQú<C3BA>|$9D<39>XTë•W^‰ÕJ´ˆ q´Ç¦‰XíúõòË/wÛçÃá2?<3F>Mù*Rô“ôùŸ}ƹøýdÇOÞÎ|ççÀñûÖeÄ0<>Å<>ˆÇAÆÖ¸zêùŠµ¸ºÔõ=ÿç?ª¿Vâi*ùºY)»ÕÕŠeíV¡ø L(9®X+N긮|≷Têð©O¿Yb[áµJWRË÷ÚkWë¯U긶R±5×*6Úñ ó<>üÇ<C3BC>Ô*y2E67Õ³Šžÿ"KzëŽßý½·¾ýâ_Û¥õ¼qã°æZ¥Ž«_ûµÿ«ý¬¹V±ãí@2}` ×_«ä¸ÆèÅz¶íÿ_ ˆ¶¢°½¾¾¾½½<C2BD>²þÇÇÇðãµ;'ˆÏÿß?«•Êx<fç,U«>õÆo<ùä“<+8™<ÏÊ<C38F>Ó>ô¡qKÎä†ä•W^ɺÜp8äAÏóÄ?qS
ßdÝ \ÛN¸õ`Ž¢ë•,*õd^_b]+
†Sì|îókn«¯}ík*I¹/¼ð?-k”ž9s&«Vb~òÇ>ö±X­Mº¿¿+j0$cÌã7˜,**J½¨ÍÍMiQìœsçÎuÛçû¾Ï&r”ábgÖÓZù|n÷ù¸è{≷©UìL©åËJ)¯¨Vp¡u-knœÅ}
Ú•o¿¸„Š„3w>Òýÿü™ŸÖ_«Ôq¥(úšõùÒœØWÿþ<07>ûü ˜J§UjØ®ÎUô³Ï¼Ù „‡öYYÙÃ4×CWTúõ¯íÒ½ÐÚ<C390><qãJ1l׬Ïæ™uõ…½AŸ/<2F>ã|ô£ÿD>Ÿ ¢aò¤PÅ<50>(æçç;ßA
a)Žóù£÷—ÉlŽøüW¶"õ¢RáÙ± p**«¨3gÎdYúXQpEžkS<>Ü<EFBFBD>¬­­!µúÊW¾šü,ú|äa ó<>ÇΡ\ª(•ü|^žŸƒeYHQ| q'5?¿ž¶<C2B6>Í
ßøÆ7ð¢ž}öYƒH¥Ï=÷R+Q0Æj•lÒÔämÅ¡i½ª¨¨ñx¬R”J~þ+¯¼ÒmŸÏÆrßJ*Y;¹J§~Ÿ<>Ó\_4íóß~† ´/=ûtðù ó“ªôK¯UÎkRâá8;Ïÿù<C3BF>bÆUÑ®À§>þñ«_ë‰'ÞŠ]¨)ç#MÑOæi×P«Ø¸ Û×Fj•:Úq|æOÞhÜç[ÖÞãÜšÖY«d~ûÅ*îs)7ºîq`
ü…w ágŸy7¿o]þÝß{kY¥Ïùš×<76>¤kQƒOœØ¸:ÿ7?TYŽšõùxl1ù4ojm_<zyÙÁÛ6ù| ˆÜˆ¯½¥Èí–â >çìõƒ,Ÿï]ݧžªÑsª¸ž<ëtnHðBø D|>^žüœz!ø¥çy,hUMî5è9K­Y'óä®> ìB¸óç]œÚq0á÷<àèû>Rf <15>[‰µU¥xÓIÛŸ§7§ÖF5ŒmÖP0ÚkP¦„
¥?auƒ|¾¢ï6ëó¿ðÅ˸êI:ä¦ìJÍ¥º/©ôË­•ç<E280A2>kHËÇ,ÏüÉ0®Tì
ôÝgŸy7<x¾n³ÎGš¢ï8;õ×*6®p}꺷©Ujâ›\b;qê÷ùÒð Î7Þ¼Ys­²ÆÕ²a²")ôŸúô¯½vu©9ÕûÖ·~ª¾X1Ó[çÚ³[ºÅ€]M|¾tÛì ú|<¶©©(CjJSôùnvý÷K¡ úøü £C$EÿöôuVmp?ŸÌ²N%Š¢•÷¯è󹨴m;u,IMiÖ…<ÏãVÎ'«Ï)×çCænÖàˆ'dù|Q®ëò ˆã8QÆÿüâïe>6`ªÜ;T˜ å/;J¡Î©éýêíŸößóxÜ<>â}ÕÑyŸÏVïä¨F&~¹Q9i³çðù_þò—áµ”w<>Ž²>ÂÏažËmÛ£“““ØGøñàAú8põÔóÕkÅ<6B>ßú­©ÞŸþiØH­ MRÏç<7F>
(¦ô˪Õ÷‡{ð×4ùIûúÌ3ëçßÊj«o}k7G
ñK/Ý®´íùRô«®W0*Ô«W[­²z0Šæxmÿê¯nÕ_+4”T>ýëÿ\s­¤ãêoÿö<C3BF>ê|ðtðýBs0¦Š &Ÿ~úz<C3BA>k»tjÃí7þĉ<C384>+XT¥qê¯?ð'TêÓ¼Áµ}¡<>¢¸Ù›A
¼b§šØÜäöù—ÇSÄç_»sB<EFBFBD>UŽãàJVEŸoÛ6;MÔ¤e|>³¢¿å‰âYP3£\Ÿ¿ÒïSKø³|~ª æ<>+}<íŸìùV<|”ÂTâñˆ|íÏ£lbØDz<C382>΢R:ïóy Jú°`ë<,57{ŸŸoÖø~”CHÖƒÎuË"¦ŠMÌÒ/ˆT=5x@k8ÎÜlÍßçwñ(J2¹6+IÎýzÀ}ôní‰WضGMU .<2E>N Ñ|Ó-ë0ÍuÏ—µöªokb³‰/#•"Í͆Y¯áÓÀ—£:¥7©†í)]Þµ<C39E>õA=dYŸíÎÉ¥½{'ó‡·§Ÿ¿¶sDm[ܦ4ÞRŸÏÒ°³ö(šR®nD1Ë ÅŠYÊð{><3E>jážPºÏ<17>Ñö§ŠwþKè) <>ž~ä#_^T|>7áC™*£Ôó<¶×¾&ÛD±ýùlââÚ„; ø`†Fãµ¢¸Un&³ùÍ£û é¼Ïç#“ ¬sxŒªÔˆÏ¼¸a’««{ÍõÑžr§N¥×R·aˆÆô¼ñpxwñXb@ÅŠj?¤<19>-’ùŒ|)ú5 h ʽì5ð®†<C2AE>)­•¶v—³»øü…Éˈr<CB86>G¬K5(}i¤ÁÇ"¬“zúgm+†#]Þ5\E úÉR>s2cºþÂè~ô®îgùü³×ô¿÷ù|><1E>wwwÇažMg †Yj…ŸSPwsCbYÖJ1¾O^KÅ”ÞÔbæ3×G©J9kG@¬+<2B><><EFBFBD>³®ëºß7Œ¿<uêë:PCÇù‡(zï&Þ +
¨øü ²RvcJïLø§æñ á{1R{66r Ø¬®ä猼¨Þb0PÅý#ÉöϺÜ)±â<C2B1>óŒýÔaŒìh)ÒYY"7<>î³GÏÅÝB—ëƒÏç“šÅà|ßç9ŒUœ|ÎÖBmÊçãªÇ0®4ÔASü=º
³Tbå•>œ™ïQ4Ç ‰¢ÃG*Å©îXYÙÒYj¢<E280BA>‡Nšš×R4 /Jc[0<>´ŸâtÎÒæ0ÅRBÐàpˆûk®± ¹—Màf¥ж—µMƒ×Žty×y0AôŠ¥|þµ;'ÜØÃ<C398>F‡HŠþdöè_ “ùÃG÷Ù÷º±½½½¾¾þÔSOinòERefYJ4$80lŸ/5¥ISÄÿšª<C5A1> `%dù|Ö•ÀÉÉIò¯®û}ÍM¾x¬¬|ï¦|#'µ>ëÅ$ü÷7ÝûR÷S}~Ö~ të»T79PlVW*îþP_ñ¤Ø¶<C398>ƒÀã)Ü…&kË/-î@‰M@ žŒèÚجYY.w<>ÙsçüÖ¤H9}ðù !´„G<E2809E>9[.Mù|ék#ïÚ¸Þ±¬ ÍG—¢Ò‡sr¸©áð.®=³Ì´*îð3fʾ4aµŠ*¬sÔ†£aŠ>LêîwÀÃõÛ3if»¶©Å­C*Ò .›ŠGºnk¾(áku#ïYmc JÑ'hKùüÉlÎuýædviïâó¯ÝyäpÎ݈à{ï꾆Jssóõ×_oÌÏrõû|&íc¶GÝ”&MÏg†ord„BW2s˜š Ü"™ÏŽ0Äœd>?æí91ÏŸêóù†ÜVM,vcc#µ+ë÷ùl &CHê<1F>eÚó |hÏÚLiƒdueœ½~@ùùËÞi,ö„/ïUW¦Ÿ¿ÐOžKmd+Þ «PúùÒò¡ë¯0œ­®îåˆ#äÛ>ЊœgÞ2øíÔŸ¢¯aˆA}„ã³Æ÷#}*£sK¶XØÕ7<14>®®¶=Ò¿ u“çZð§¥èAp|߇Rx?µ,+öZ ¿´mÛó¼Š^®—òù÷k“ŸÏ¼
ÿñòxªS“?âðððµ×^#ŸÏá†D´µ"0a(rkšfêXB€îºnÒØÇ|óYÕHíÊíííÝÝÝÔ¿¶Îçö:¿Tw+ú|èYöhv±»c¿Lõùb¿ÃØpg0,µ^‰Å²®ÜÛÛË:§,ŸŸUN†Pq)ŽÅ8T¢0€“Iø0ìùÜasê·œ#€Õ
²º²tb<EFBFBD>æ"EuÌçóÑžu u˜°\ìØdó·æz6èó¥B²æŒDÜFjžÎ'RDéC§@³Ã­‡ëÞZYÙR—]¼døl¹7åûm<E28098>ª“ùp§Q¤ãnV<"V³õ•Zèúã %6f<36>BUjwKŸ\„âšYÅH†KK—ÓV,MZm¸“þw¡DLºs¤EÑg ˆŠ€÷PÑðH3¢KÑ^Öç¯í1mrîF´t}ò`'œßš°õì$GQCR»‰»ÇA©ÏgDQÄM<1C><05>+•:˜Û/â<WV¾Û"™oš/â·S…Ï_$RñiIû©>_<3¦µ“n0&îÔX¾ïóñPÊŠ'¥|ÏH,;ˆï…šºà0· ÉÖKýýåñ”?w
^¢o>_ôù YO‡k—C“:"nŠ  à°¬<C2B0>²Ä8”V<E2809D>*‰¢¹ç<C2B9>ña£U…+E«ýö&ç+N™zê/­,S­ <µeÍT_á̲zAºšµEÛâq(¸ÍÞV&7øÿ$m ôATAEÉl|àS%æs.ëó7'3nN&³9×õ©œÀMwUÓMâA¨‡TšÅ4ÍT£ÅÅc2%8 .Å}>ày^RuÏ <C2A0> %§Î è£ÜÁ¬ æ­<E280B9>ù†ñ—xrþ¢2ŸŸ´÷Ißåó<17>ÓÚ¡„TY-ŽÛÜ>Ÿoëƒ&P¥üŠ±}(Å}/TŒÏÙІôpL…­$F‡ì)Ï£W!ŸßÍú|ß<>4q€Ò\¸Ö)_é•~Æ•ÚÔSÍággÙ½15Zó<1E>ÒÑ$E¿íÉù \çÖ“¢/µ»5ç9÷
ÆêJ?uÓ²HWi¨O[ZO«”x­6 T7<h«Aý$&ó À—Sx'õ<oø~ƒüÞ¶mÑ9—¨ô—õù'ó‡\×_»sriïâóá„ÛÓüGø^Ûî<>¬ú§Úu„0 S͉ºÏçúE6Å}~¬G œ˜Û—V ­óÏõ?¢è]é<>Tä󹾆á”ü1ÖÅHGÀèò}?æö¹†…bWð3¡»“å%ó5P1<50>¦Cr@.5JS[¯Dß ÍÍsûŧO÷—¬äØó®î³GÌ[oïòùõÓ¬Ï_h“<15>kœVØÈ$u*}Û5òïºî-| %]\7¼¨Ô¡Õ“‰Úöä|ÅùâûQ¥<15>Æ7ÛWÜ^¢h.<2E>•µŒH£`p´ˆG£`•Öa"C·¨I)EŸ " Ë6MS=ëØ÷}.¾Í­zM}>pîFÄäÉÚÎÑÍ£ûˆÏ‡´w<C2B4>º¾
DÙ¥¢:y&¶˜·¼XÆçÃP¬ÔçÇîŽÙ²†}«©Èç/ÞŸ<C39E>ŸL×_¨ù| xD]jDQÄï]Ü„¢>JÅr·¿"lgJêvB<1C>Éü|ñ4¾ðo?)´Á<C2B4>|~#4îó=oÜø«÷px·KRE¤¥}TµçT$ g0œl{$Íiì‘êÇF/®%ëÉl/ŽÔ¯šæzu#JƤŠ'„¥Ì©R4µô*­#k"Ò5 +”‚ôŸJÑ'¢‡0oTRà|®ô“Tqrøü»ÇLžœ½~?">Ÿ<>°¶sÄ~<¿5¡®¯.7bŠ> žçÓ§ê>ŸU×u“c)‡]a™Øbi±a¿ì(í0Õù|Ñán?ÙÅ|„ð|û,]ÏC?ȨPôù¢ô}*ü^b÷¨>JáŽø®<C3B8>Üí«RlÇA û A dÿêyôOo/ΟZ\,´D<C2B4>Ïo„Æ}~Íñ×Õò¨q¯ÒöœØJ•¾m<C2BE>4tãP%ß<> [cz¶ÁMÕ!MÑ7ÍõfXÂaRÅZ<C385> ”îqhé.¡–²Ô² ψe—Aé^Œ–¦^㱞æÒõ°u<C2B0><<ÑÆ;"(Ϧö</ÇǹSOìGÈáó7'3nì'³ùù­ ¢ôá„kwNø<4E>'ó‡4ª@ô!Hör&{\ÑçsÏ™•¼<E280A2>îðZ¥F¸¸Ï—F+ú@u>?>„Rר¤xç]“ÞÉõ
YîÔÓþù5 Qúâ<10>•©8J¡pöŠ­´E|>û ´ 2 àº4ȳ·dÓñýbO?dþfèû˺VšNœY¹©¹ñù ™C³¬<C2B3>J[@úú_ƒ¨š*”¾i®·ÂÓÁÔóÆÐR ]i'žUÞ®p˜t5¨(I®ÐÚÝVãûÞ)±õPe`À9®{KºXµÚØhpwÍ®<06>W t¤)úé#¢WðW×ÜoÊ%¾Ãæðù'ó‡ÜÏßž>¸´wñù×îœLfsþã愸UÁ»õfR| ®(á›äþnH<ÏK;PhQbéôE|>ÿ¬ã81¥?r½\J «íTçóB"tê& Tñ.Xiðq©Aö©û| âÆŠ…mÛ΢±‘–:Èaâðñ§Èí{ùÊe&[ZO<1A>ë'¼;`p&ÿÊ.þÄ»Ð'wðtÕ硆zêàóƒ`Ú`~/ž[unsm”«ô]÷ÙE}€¾hÊw)9_eA¨(ÂhÛ£NÚݶÏ&ènÅUfYVð7 gЃ*¿í›ÂO<>o|ƒ@PŠ>A§í>¸vçäüÖäâî1|óè>âó×vŽàœ³×Ø<>ì#DEˆw+CüeVnsì489&Þ‹øü˜§…Y} |ß•Þ7*õù<‡<µÁSÅ»èâLÓ„Xßá^]Zlbæ<¿(ä±`Dª_ÊpB<70>É™RÄsŠS Ú‡54¯yj ­Ïˆ+Cê(bå/¼}àôÃÇ>ÿÝ"—#Ÿß[Ÿ¿<C5B8>½®V—~&¡•&6×>&÷ú“ß7¤<37>[Ñ$êRr>_¤Þµ\».Í¿íLT±<54>Àx<C380>F[²Lã«GRøÓÜuoUwi<¼Ïú6©4ç¡ÒV%Њ0 UW¾ï—˜«œÏçÇ@|þÙëpÂÅÝcöãù­ €J<E282AC>á³<>IŸ% }¾iš©þ¤ˆÏ_¤yZ˲báƒÞR©Ï‡^àIæÛg‰wX<58>#M8_Êç/;^1X<31>R²ò±ká° <52>+â9¡@¾a!õ¢©<C2A2>¶>#­¬Æ‰þÁ<C3BE>Þ`ÇÊÊõ"—ëªÏ_)@ õÔÄçK³|+J?ƒ·`üºËBwœ<77>ee &7ö©….]v/9Ÿ!ì†q¥ÄIÚqAkœ¥¡¶=‚©!ͩJõꞪ †ªv·wCADx6æ²öFÔA¥¤qâó/Œ¥?™ÍoOœ½~à]Ýßœh´ëàà`}}}{{{>ïÚ–íÁ``Û¶˜® ýëº.>ÞàS«(žç!% ‡CvZî<5A>'0¼á㢨1 nDºêpW¦ÎYF“Ù/S$¹Âð.Nþ ~ã8Ž(«aøÁoTƒX¬zWÂÉ0¤ÅÑWd£ ýðk!àu^ªý³&T[Œ^Á<>0¹:±*eVòÀ ²=ÇöW>ÿöKEêÜUŸ¯y=5ñù ™Ôª"O^jíªÛÐ ¾‰MmW˜®‡…F†šŽV'ˆöèY|<—î|ðÄãVg•K#_¶=*åBž7®çBDñù…oæ*å¨Tw×ÞPÅ…ÃpÖHV@=àwG>Ÿ ˆ^!戦ʱTƒ7´eeÍ•âó/<2F>§ˆÏ¿vçDÏ^ØØØXÌññ1<C3B1>ÉVC]I]It¯+ù^¶ÔÝ"¿ä pÿ½÷žÏ?|ËûŸEêL>¿-Täóñ¸<52>à6²í¯ÿD‘¦û~TÖµ¤á°Vï戢¹TÞoL•«Ð*¤A0•n¦(xtc¾ñ ž¼õ_´Æ 2zÞ˜¦'A½BLdeɇ®ë²ÔP2mÛ¶˜Ì ß—’œ¿(Éçßž>@|þÚΑž]póæM¦f3úOµÝPWv†íímèÇ<C3A8><C387> êJêJÑ®gn^¸¶jþfÈ|þïœú_ó%·¼!Wì@<17>Ï_(š×):ððm$¦ø¨.1g<1E>´:9Ÿ Ž´1 ¦RKwT±/‰(ô¸4jûèÌCGš*_Åþ¯F6Ôܪ©÷Ø<C3B7>=AKEmÛ§Ç4Í ˜²)ÅçÞÕý,ŸÒ¶Ž<><C5BD>IvêJêJ¢{]麮eY™ÉùÅÎËÎ{Éùÿj¾T°ÂäóÛBE>!³[%&õe½Çpx—¢uàIªe)ân'çs¤æZ;wá*ÁÒt-<2D>e9Ûu©»ñ¹Ïúr/‡GߪØß×°hÄþu<C3BE>«ŽA´ß÷Å×RÃ0à½53M1eùü £C$Eÿöôõ5AQ.ƒÏÿÊç¿â|³`iäóÛBu>_*¸Êrì•j:h<E2809A>(šã±*øk<16>Úw>9Ÿ!M3.i,]…|?¢ñ¬-ƒÁ¾4(¬rÀd<C380>ÇMñ)©aûà«P¹Á |6ué<75>íæycÛÁßPÈ<50> " CÏóÇ<>WTÃ0bÙøðKx]õ}¿ŠK—åó/<2F>§ˆÏ‡¿R/AåbÿÇè=Ÿÿó_ ¾[°4òù2 àF kÄ_Vçóµ$õù~„ Ú½N´Ïã#¼à<êIr>cuu¿Ù|û†pÛ ¬„45'™,½¬Æïvf5Þ8%®Ò¸[÷Â%A”åóoO >ÿÂè<C382>šš (Ãøerþïœúá÷ý(
•Ö1Ÿ·³ú˜S÷±»¨ÔçK5WÁsiö2¥ÅÀ4׫ÛêbÛ#<Ö·Æô¼ñ²«<C2B2>´ÌnÞÎ]iYêf‡ã씵ÑLs\÷Vé<56>°¢ÐAQeù|À»ºŸåóáOÔÔAD¢(bIÚžç…a(þéÔ©ŸŸ:µøð'ÞýwŸ¿÷ôóGýãéú/ÿïý§,AÇ|~7¨ßç/döluu¯Háø?½ûÝ@šBŸ{œKSa ÎÐ66¦a\Y*Î(Íù‡eŠÆp<15>ß·HqmkEm B¤DŸatˆ¤èßž> Ö& b0†qJÀu]þ×uúò^ŽÄgÍêöÿð¿½Ey®E>_Cñù¸ì*’ýÓr½Ah<y·ðÑžOsáêfPͻטRakÛ#Å¢¤³«mØm²vÁÀè³O®BÅcøž¾îm" ô¡DŸy<E|>ü•Z PÇ÷ýSi0¥˜ÌçÇÿøVž2ù| iÄçGѼ
 XÖFßR‰Þ"õƦ¹¾¬7îar>_”ð`E3 hÛ#¼ÏÓèm#A0uœ˜V0T˜Æ§¸ .Û™o‡v+r <d@[] ˆê(îó'³ùÍ£ûðÍíéÄç_RkAêX•êóÿõ¿ýhE/¾:Ëzâ|åïò<qÈçkH#>!ˆµ¬<C2B5>ezÞ ùŠ%mqÝ[åê÷~&ç3¤f<>ÀïáãÒ\eZ…ˆî! „Á˜Ï½nH7ÎІ; ¢:
úüÉlî]ÝÿêÛï\Ü=†Ï^?Ȳ+pµ6A¡H©2ÿ /á™rîFô«GYOœÕäyâ<79>Ï×<C38F>¦|~Lñ—ôe3úà¥^j†Ã»ÔãD—<44>f•Ã_Õ}Wo“ó9R!ŸLöýHªi":Œ4‡m<E280A1>r”,<2C>W„¥ö' ª£ Ï¿<žŠº~mçIÑ¿=}À>5™Íù÷ 2ŸÏÇãñññ1 ƒ¶ÓÛ®Œ¢h8AЙ;
Ãpmmmk ûnÙuÝ•ÇÀ7ðŠ* ; VßÃ÷ýê®E³2 tnRæhå?ðgÊ—Ö<0E>'NŽ+Ï×<C38F>¦|þB¦Îgg©Òl{„¿ø/[ A´iV¹úÈ—zé'ç3¤ .äƒ`꺷¤1ÄR¬&AhŽÊΔe£<65>Ò• 8‡Ÿ ‚¨Ž‚>ÿöô<C3B6>¨ë¯Ý9AìÊ¥½{ì#bJƒloo¯?æää¤íýÈåÆp8Ì}²hHÇQ¹®iš5H•^ueŽ~ ü7\HªÌ謓ù²@«Ô ÿH¾Å„ñ£ýJ8}úô/~ñ‹ÔàfùUØ톡2ìÕ‰¢Z@Û"e‰ ã” (Ú*«ÂâÌÎA* Åg%ôlòöÿèÏ^@ž2üøëËyÔ(ù|mW¹F|¾ôm]]ú~„eW:¯"‰ÞbYÅsÂ¥©þ=‰ˆ­®îá<C3AE>išëp,¥ñsì• ˆ«‡Ê¤€'µb<C2B5>*2&µ<AQ)}>Àä<—ÇÓÉlŽ–ó[8ÿÒÞ=1¥¿A677™nê@^wé>ß0 i9Aˆž­AŸß¥®TÇ÷ý¤o/Ýç*ùÿ¢z-âó766>ùÉOB!®ë&ÿE\Ȳ,ø†ý& CøQ1è Ülɱm×Aä”2©!3ŸÏÃ
©ÐèÊ"³’ ï$_Z{[Åç¿~9ÌqQòùÕ1Ì õ¦|þâQÌz÷‡*^Å$PÑééÿ–µ!-Dê±ûã¢óéúÒó“ ¢EÁTÅÀÃiÒ¢Td>M( ¢Šûü £CæOàøñìõıÀ 7<>î)ý Þûáááöööîînú±tŸø¾<C3B8>—㺮&>¿K]©3Û±äüE5>?U­ÄÔkŸ]ÉRôSãìB±É2öUR <52>X`Âó<î¡Y˜ZäF=YøÙ$±HA²aù„ÂSKˆ)}<7D>‡èÁÁÌʽ½½¥Ú߶mÇq`xÃ7I™ÿOþ¶ŠÌ‡ãÆFžÕ€|~uœ*FS>_ªáõÎÁ­¾ëÞ YYÙ¢BtÛåi…ál8¼ëûÌ2JÎçHã#9Ó\§-BD·Qñðµ<E28093>OE™/-‡  ŠSÜçÇòí×Çróèþâý)ýÔ¥P…ÏO͉ÉÉ}~ogn2/½
Ÿ/Í~‡¡RÏ LÃ*z*#‡‡HØ-gèy2æ¥68 CÑTÃ<54>ËNd±±hNgÖ±Øä|ô<>?¯"óÿûÚF¾
<EFBFBD>ϯŽú|xWysG¬¾JN`òŠ‰Þƒ\:‰<o óȶG++[˦ ÷m9ÎN¹>ß÷#¥M8` Êú¸¢Ì‡ÕŒëAD ÷ù±|ûkwNÍriïÞBHé?¿5¡.(…r}>ó<>†a …A žL>¿NÂ0dmîy^ìOåú|Þ¹xö;Óàüäâ>Ÿ<>._Í®EQÁò¨„eYxilG@ª<>W´Á<ëAʼn\|ÝÖÞé¬ R¥îç^zUÅçÿõ•wòÕ<C3B2>|~u¬‰>WýèQ÷fLHÆ>nYø§VW÷ôê*¨jØ+=«¼‡ÉùŒ(šã–ÊÌ'™O<xð w*}(g=—Õe~P¾"AQ¥x!nQ.<2E>§“ÙÑ,LàÎÿdþ<64>z¡8åú|®+}ßÏ*ÄuÝØɈT `ø˜˜ü$òÁÍsR;—ëóyçBwgƒ$v2ri¨ðð=ðº1£o €Ò˜ÌGª§±ÉòŠ6˜·pVÖ1Þ>bmÎe<14>tÔ<ª Èíýa|àô¯«È|8®Žþ%_Èç·…:}¾J}LŽÁ[?û¬ç<C2AC>¥'So=¡DM;\<16>þûŠŠ4ô…ãì´ÎäÍçsšM¥ó½ï}ïàà€¢¬+ŠÓ<C5A0>d>AQ'¥øüó[fQÖvŽàdz×Ór2(:ÿÍ íG+<2B>r}~Çq²
aÂͲ,nÀR%îè8†aÀ™mqŒ÷N¹>N<>zu1¸€\Ú󼤤…3³F,œ<> i¸Tí Àe~†©ù½1x|
ó"<xaÛ¶øûz|>r!ß÷EÕÉ€WÙéÐì¨f½‰$çøŸQôù{?#Ÿßqêôù<C3B4>/·•#åÕóÆRi0Þ¥Þ$úƒbëRLÏÞ¶gŽ¥ Ûñ˜¸zõêÑÑM%¢*azÑÌÃ7*!’ùADÍ”âó/íÝcåìõGýµ<C3BD>´0<C2B4>Ï<EFBFBD>? )×çÃ÷,íÙ0ŒÔ àÉÉY>Ÿ ÏTLÓ¤\ý|ð†M5´¥û|îÕ³²Ö™†eZ;µ´(Š² -¢ãx
zR°û¾Ï.
’Ž"$Þ$ÂkˆìIQAÑóËÅZUq"óÐIìBÉðY,z¢ÿ¨fõL­ÿÓÏ“=5V°<7F><bþâÍÉ] òùm¡fŸ_06ëpœêJ¢oXÖF¹ó¨ÏA±0œ©oy€÷¼qµ;¹<>|>Q
*±E˜20_HæAÚRŠÏ¿ytŸ»øqs2CdËÅÝc8¾Š!¢ ¥û|®×Rõ&OfÃ0Õ—Âï™q…¯pòð=àž¤mYu\X¨…5~ò¯¥û|îÕSÓàaxˆÁ…ÔÒøh<C3B8>ßÃil$À7¢|Nfl¨ÄJ¬4(J1¤èó˲¸*åˆ o"óé)–ÀûÚ<>Úø%\Ž§¾ã{ä>Æç^zUÅçÿýÛ¹«A>¿-ÔìóäûÛÅAä`8¼KÉù%²ºº'Ý+亷Â<C2B7>vCÄûpœ†d>A¡-¥ø|àÜ<C3A0>è«o¿s~kߟÌ"²… |ÑùOfM¿ÒÞòo:+Z?q·‡YwÀå†ã8«2¸.C|>ONfG/Þ­LȧúRn,“ZRÌÖ.˜ ­ÔîƸÎÔP¥=XÓem<65>àÝ}$ ܨ#>ñžk…“—ã%@·.Ò|>H©+ ÷Ò©Á¹àIìlcHê˜Ìîz¹Ï­àHcjƒñ,Öh©sñùð'îç=Ïã¿gÝJ íÆ?ükãðý>l£GÖþâ3ð¼øÒÚÁ<><47>X(Èç·ƒú}þãáq^íËò<C38B>ƒÁ>õ#ÑOT4%ç«cÛ£TÁíLŽ JÙ.D2Ÿ hŠ²|> jy¦÷³v&ÿñæÑÿgßÜ£âªÎþŸ?»Þµº^úÇûG»Ö»Þù½ï]ËÚMâ-È<>Üu !$$“û<E2809C> ¹z‰bÔÞMÆK<C386>¶VÆKÒX'*jm©£F£fLˆ¤Da A,r ad~ÏœÍl7ç²çÀœ3ÃÀ÷³ž•3‡3ûìËs2Ÿýœ+©ì3%ÃcÒ&jý†!Ê ëH|~$fSõÞ˜Ë7æ }©æTx!q²ê*#Ô<>t y—ðÎ7[°¢<C2B0>´ŽÜçÓ@k¼:‡Ybš*ìWýÙâêt¾¹#ÉNÜZÓ+ô‰•F˜iêAùüÄӠŧ«Ðwf$ÞÆœ×ëåÝÅvÄ«_d-åð]!êñ© =Þ….Ïd¿äæRrì˾6,àóÓ…”øüØ$±Á꣨ŒfB¡+%¯Ø³NII3“Ô±nwm   Oˆ‹¢„ÏEXnR…<52>>_äxÓ%‰r9ÙÝÅ®hìdåúÝá¾”]<>N2Ÿâ¨qý°×Nkªè¹ …Bx>?ɦÅ<C2A6>ŒŒtòùr<C3B9>È{+t³lôù4Ðý6Õëãû24UØ+Ÿïr¹Ø„±ßGà³H2ÏÍ4õðôùfM²¾<C2B2>õ;q»bxŸà`»ò«>9gQ<67>äæò豄j5áóÓ…úüØTIÈê‡B=D0š))iZ,­;·»–þ<00>8Á`v¤)ùü‹]½åRVÛ>®½µµµá£§ÓÌç6¶L\nø|¾Êxð_¹ÏçžÍãñˆ‡¹\.zNÂ~5ô¥|/€I­2¬F¶q(«ªªêêêÂá°þÝô’ùˬ™ÂâÃAÝw&pa.÷ùX= ½x·¯¼JÜðllÂðêë@  ˜WP×ì4Ì®e¸Õ絓š!ÖØkZeÑç»Ýnýæˆ(ÃéZƒƒÝ@IæªÔw>ë ÉUS¿Èž·³SrsÙ±ÿr"m†ÏORîócf(V¿¤¤ #€DéÓ²¢ðz/Ð1ô_Zh°÷‡ðû[ ó¤#ù|ÂwºÅL¹Ð[ÃáÚ«‰OßaõùVJsÍÖø|Âív3 Ë_ ƒ|〽bæK Kmé#œpû4U*<2A><><EFBFBD>úwÓ«>_èlÙ<C399>ëó­¬h³ƒõ>Ÿqìhbhž0<ý ;RÄårº}q(‡ Ù³upyNŸ¨—]A³a1,Ú`ÞŸÔ3b˜3;'<27>GÜ)àçO•Û—¯J±ÙlzÐ|з_äÁ<12>¯Ð»»¼Uâó7nUi3|~º0L|~lÚ Âê»\UŠÆ‰Þ|{|¾æ’’&ú—Öú<00>|<žzÈ|i‡s>¿¬¶]b]:®¤üÚªªªš+6¥“Ï¿‡|>/³ú?×ëõ²W¸”Ô?Ó[lGÀPìÛhõÙP==\~:ù|j­dŸÏ<C5B8>7Mö
M öŠ_h±ÙG+ŠBçä…úá,^K]]<1D>cuu5 å˜AÂ/p°—®ˆo
6 æ Ù3+îñx$OFØŽ8”q;“²Ÿcf(óL¹ñÉm¥èˆò”ïX"m†ÏO†•Ï<E280A2>»\Uq Œ%0ÜÈ̬†Ì<00>^8çóÏ|Ý-/<15><>Ãáò;;;£®ébeäLIµÓ‡|¾¢(ܲW˜ÍÌÌäÇH|>?I  wEÃD®<44>5ÃýCi](µnøGÜÑK•Ï<E280A2>Äü3¯`çÏ_ˆŠ8îGƒAŸÏG«qû|@Êdú|>9E».<2E>og Ùçeâ>ŸA+Ëï÷S¯jܾ¸r<C2B8>&ËW¥¾WhˆÛíV^vO(èÜV¦¯oU^ž<>HáóÓ…aèóô_bõÝîZŒ0ÜP”pFƧ<C386>ùÒç|~[OX"^JÏ)è|qÈç¬À>###¢ÊXv€ÏçãÄõù"Š¢ˆõâÅV žO•Ïçͬ )Á,«ø‡ƒJ&tQáêKLJàó%×(ŸŸüê,~ðD3‡‡‰Ï …Btul¼¬oX$ÃÇ7DgëYôTáÙc_ TDNxi|~º0l}>ÃÐêgfV+Jc CÁ.È|púº]¢ îðz½Ù*ÌM<C38C>ZœóùDé9Eâ^ºÃ}˜ÏváœÏ÷ûý\rû*ÖÕúR¶Héo @îܬÙðÞÖˆ¶û|>j4 xuºfˆõgãÛìY ^篟º|î%âë,ú|~uVßØÒ¬…È`|>ßÕûpÈ>Ÿš!¿3ÚÒ™ÎÁg”!*ÔUJɱï¬}Z¿-ë >˜S°8ÿÿþÇ5äøàĉ$4¾õ»ÝµÙÙçé_`˜C7k‰Ì÷xêÑE<00>†5<E280A0>*cHÎãDdZ÷§fµ¢±S¢_Î|Ý<>ùlÎù|EQØ<1E>Ðfffj~I²#YU¿!ðùC#îVˆs>?SÐ4¸\ÂkŠêõgãY|¦ÃÊg‰o™ý­¬??Â/Šæ­dŸ—.™«xúÉ×ón¡Ïû0Ÿoq£gxú|±ÜZË'ÿ;î°ä†Rx ½rï5ÎP"Í€ÏOÒÂç ½ðxê!óÀ!¬ø|+ßÇáó5ýé„Y­è—òúÌg»pÎç‰GC¹jè ¹54±ôbâžvÔÂÂl¯ÄQŸÏŽµA¯ŽõgãžÙåriäDuã­ˆDž¢²î±ycX{ Ÿ.¡³‰Çè¯(î݇®…¯¹1ñ†v—-<2D>éâß?og©ä†2v~säõÌ[ŸŸ.ÀçÀ ôJßë½€n€Ä<E282AC>Ïw¨?ª”–èßi<~nŽú|^KÌ…B⻆¾TttZ:{d†~àŸb¨CA\¸˜Õ „f8œðùïª7Þ†gëÞ½^/~Š~æD†ù<îSVT]z0äMbM½]¢B­åeùþ1ƒAó¨K$±¸N©Ï<03>ëgŸÏÇUÿð|"FÜà0“ùDÑJÉ eåüÒÈ'Þ[ŸŸ.ÀçÀ!*+ÿ]RÒÄ"êA‡€-Àç;ÔŸyž²Úv‰<76>¹ØÕ)m Žú|EQ$ÒÌ—jv4˜éPÞ±fäÎù|BtÚfÕéš³Ñaâ_éñx<ú¶ñ½Ãw­3(ŸÏ>—/‰‡7½Öe¾×ëMp!ëqjö0ÜA£&‰{(¾óÝÿœºp)ýð½ü·äV²»¼u磕ý½!Á{
|~ºPýÙgœ81ähooG@Ò€Ïw¨?íòùÝá¾ÃçÛ~qê_Ç.ѯ'›»$Çëõf«Xäfó×%¢wÈt³·hqéÕhFF†Çã1¬-VàþÓívëßåÃa¨-Ì£0œNü-3µ™R<E284A2>^ÛfffîJD„m@ <20>HwIæ§úPþ½(?Ov<hòÓ̼ú ²Y¿ñv±Ä<C2B1>úx>#ÙøûÞþ»äØt§XûÄѱóó%·t÷I¤1ðù€íÀç;ÔŸvùü†Ž+\­Ð¯»z<C2BB>s/ ]¨Œ<C2A8>š|[àeØÃÓÐJ…B|2ÈÏJú].WjL36§.õ-ïça¾w¦ß}àL(XÏožÜJJŽ}É~(«M¨î>°ø|‡úÓ.ŸßÖ接¦­‡^9x¶UâaºÃ}tÌ™¯»égß醎+I»öp8ÜÒÒÒÙÙ‰e•îÐP677<37>ž¡ …BlÙú|¾9”ï¾û.»ÀAÕƒ´[•¢?×ÃþÚ'ŽZù'›»i3|>`;ðùõ§]>?"üŠÆ¨É)¯ï<C2AF>¨æüŸoc¿ÒÁI»öººº*•îîn¬¬´f¥×ëåë å-·ÜboRÃdUúý~š´4²ìé þ¤‰žï|÷?ùmBîóÅhë 'Òføütáþ}÷rTöú|¾Cýi£:ã¿ôœB¿Ö´õHô ø<15><>ì׃g[“ví555L7¡D?Ý…C©(JFFÆÈ«`¯®®~óÍ7œGÆPjV%Ÿ´ìÑþ˜‰!cçç[ôù¼>?ñÛGÊ}>uõ ÝŽyG™!ù/Ðh `qþÿý<C3BF>kÈñÁ‰<00>4àóêO}þ™¯»¹ié÷QHT 30 Wø+»z“sííííuuu<75><75><EFBFBD>XVéÎèÊ@ 0òJôi(,X@×åõz1±ÓšÖÖVZ•MMMü~»!‚Á ø«ž…ûaw„¢#•»ËOY)ÎgO„%Bj}>õ -ç1րχÏ€t>ß¡þ´Ñç‹¿¦­‡^)=§H$L[O˜Žá¿žlîÂ<À
,<2C><>¤}V³<56>¡(
Æw$!ç³Û<C2B3>¼½äØìŽp×s/[)Îç·DH¡Ïû>?.ðù<00>FÀç;ÔŸ6úüˆ ðËë;è×ãM—$B† ü²Úvöëáóm˜çXAQÊ`Á`pÄ\Q(¢+¢1¸# ±Ÿ†Øï÷KdõUÙ³ù ¢ìØ3}~â<>L¡Ï÷z½ìs].u–€ÑçÓÏù|ƒŠ .  iÀç;ÔŸöúüŠÆN&Xžm¥_/võJ„LYm;s²¹¿ÒîÃTƒ¦8Ÿß Y¸ïþ;ȇ§J߯”Ü>v—‡ÄûH¤Ðç»\.&óñdŠDŸÿ<C5B8>χ€á |¾Cýi¯Ï¯iëá¾¥­'L¯øN·Hœ @‡ñ_éÏ1Õ`d ƒc¤ì.?Åîw=sÚŠÌçÏy%H
}>ûP¿ß?
§G(òx<™™™Ôô¿¸<E28098>'Àç@ŸïPÚëó»Ã}\³4t\¡WÊë;$Z† üƒg[Ù¯t0¦:Œ<42>¦8ßãñHd>Ão ÷Énwªã;Ålã8ARîóGáHü~?Ÿø|Iˆþ¹Äþ•°Äöl;|¾C>Ÿ(«m5Ë™¯»%Z¦¢±“Ž¡Ù¯϶bªÀÀívÅùŠ¢èý­ˆßïg÷]‡ë ´Kno~úÕÅ®ÞãM—ìz¤+…>ŸÕ<02>Q57B¡ïp<C3AF>ÇS©âõzãþa>ÿÅ^ ¿B ,>8ñ<38>Ck}@ #/ðí04D]o ðùùüîp_CÇ^3I?H´ ø5m=üLõQ-F¶Ýæ÷ûEA‡€Ä¡‰T#nÑïÈ# ú|>ZSôoJ.Ÿ
ÛH¼xFFFÿ_žð¸Ç$w<>c-Á`»í)(U>Ÿ’ž7âaRÊÃIÐçŽ@ ò=èÐGß"ÄÈ‹Ñö}
`ðùõg4Bé9E"g.võòcè_LõAáõz³UÁà<C381>æ¯>k†Äãñð?ñûýCn¿¢(™™™­×¦<02>€fñÒ˜²á°âÇ̦¡äÃÊl\hÂð?¬šsP(DÍàÏa‰óŠ•Ç]f¸Ýn‰»Î ú[ævÜŠn.K9¾¤WÔpŸO=¯¨È‹óé–ÔŸžr]•Ý#¹eøÊöM¿ú|‚åÀá°|Ÿ ƒÝÀ…ÏG àóŸH#àóêÏ$øüãM—$ræds;Œ‰}0(˜Ù³8ŸÍæ¯.Wü;u(2qC€‰GŸÏǬ5,33“ @ ®Ô9ÌWãÈ…¤•mv°&ÍZ©ëÍyÊkŒ­Ü&hÊÎ.qÈ1ô®ÖïPôA No6|Ôó†çaõÞt™løè_·Û<C2B7>[^ à[ôƒ¼[ú'Û…€½gá¾É-cìüË••—ímjj}>ßÖdÛ£•RFÀÃ&üBW=Ø¿…ÏG àóŸ£dúü9sø|[’¯½µµµººº®®.§û8Úî󉸥þ>ŸÏ.ŸÏÄ£ø
+ëµXó?’†Ò:L<>jV®>?nQ7¯ÁN<™ÐPVUU%2”š¢tjLI ·Û-‡gffêM¸uŸ¯Ÿ´Aî86` ßpéÑ[ú]9öxBÒ¬f(5;€²þ<áq<C3A1> ì.o•Ü2¾ó]꼑ãóÙƒ!ò‡ìʷÄA%+ 6úüŽýÑ<C3BD>fŒ¿zÆøçŒÿIÎøŸª™3þš™ã¯<C3A3>9~ìÌñã¢1nü¬h\§Æõ³ÆÝ0{Ü<>³ÇޤƄÙc'RÌ;iÎØÉs®¥Èšsmöœk§Ì<C2A7>ÆÔ¹×PL{ÍtŠyј¡FN42gª1k~4fÏÏœ£ÆÜhü”bÞÍ?<3F>Õ¸E 7Å-?¡¸U<C2B8>±ÈÃ<1D>…Ñø1E±Èb1<62>[£‘¯‹%ѸÚ,
î<>qËÀ¸™Ç<E284A2> æˆÆÜ<C386>1g`̳ÆÌ<C386>30f1Ý ò£ñ“hLSÆ”<C386>=0²„˜¬Iúc1DÞM?e±hB,T#W (&RdÞªÆsO>æÐ2ÏɺvF,¦ŒiÙј,Š)ј˜¨ÆŠ©ã(nŠÅ<C5A0>±¸A<C2B8>ëYLw],ÆGc¼ã(¦<>kcqM,2cñS5~ÇâêéÑBñ#5®šq ö+{ëêœh†añ!Õ°l<13>™ÑœÃÒε±ä3VHAãfõg!<]KJ7Ì{c,nÏQ,MMRÓOVY±”•=·?k©‰ëÛÜÕŸ¾bLŸÇ4©Œe³Ù&9MŸÖÌ2Û­²ÌfœÓX*Ò—Qš²š…ÔD4Ø\do:Òd¤¸IÉƼd˜<64>$©IŸ<49>Ì”>G¦©Üþ4õm¦¢pÇâXÜL1©?æÇb^\37s(&÷ÇìXÌŠÅÌXäPdQ\+É]†ég0yÓç1ÃT¦Ïf† í:]BëÏi&iMÙâæ·«&fÂçÀp#™>Ÿð<C5B8>nø™îp_2¯½ºººJ¥³³3ÝÇÑ ŸoX~,ÂJI÷KÌêÍëÖÏ9†Ò"\<5C>jÑ Ÿ·zVSt<53>H2Ip(ŸÝnÃfñêô“\¾”E¡‰*®ÍaüäfS7 Š HÐÊòÔ_©ÙÕ%íé ýPj¶ZLó‰2¾ÿCÙþoÑ%óªÛÛœBŸ?¨<>$ø|}þ5[æM{sÏÌ¿ì™ó×Ýó+vßZ±sáßv.~kgAåŽÂ··{Ž¯9V¼þïÆw¼[ßÝæ}·hû{E»ßÛzÛû[ï<±åî6ßóÁæû>Üüó7ýêäÆß|´ñÀGúxÃ#Ÿl8øÉúÇO­{âÔÚ'ƒkŸútí3Ÿ®=tzÍÓ«Ÿ;½ú…3«ÊªV=»ê•³+_=»òõ³ž?æùKõŠŠs+Þ:·¢òÜòwÎ-?þ÷Â÷j
OÔ,ûðü²<C3BC>Î/ûøü²Sç—~úùÒÓŸ/­ú¢àìÕµKÎÕ.©©]r¾vÉuKjëòëBùõ¡ü†úÅê7Ö/þ²>¯©>ïŸõyÍ ÑøWC^Ë?Q|ý<>Š…mþ[<5B>Ž ¹<>r/5F£«1·[<5B>Ë_F£çËÜ+ÑXÐÛÔa5¾Q£/·j"bi¼5ráÖ>Š,èkXÐW¯FhA_ݾZ5¾XÐ÷ù¾ó¹}5¹}Ïí;§Fuî7Ÿå~sV<73>ªÜoNÇâÓÜo¹ßœÊ þ87üQ,N.  Æ‰…½ï/ì}O<>wö_ØûŽÇõ¾½¨·R<C2B7>·õþmQo…]Ôû—E½o.ºòfÞ•?ç]y#ïÊëj¼w¥<ïÊ«Ñèy9¯çh,y=/åõ”åõ¼˜×óBÞåçcñÜâËGÔøãâˇ_>¤Æ³‹/?³øòÓj<•ÙŸ¹4ÝOæwÿ!¿û 5~Ÿßý»üîÇ—Dã±%]<5D>Æâ·KºYÒõð®‡t=¸¤Ë·äK.=Ðüû<C3BC>öýÊþ‚ÖK[,ý—oéW¾e;eÿô-kò-k|pÙ…—ýã¡Âú‡
CÖ>\øÅÃË?xùù‡—·|ph™}ríK¥kËJ×¾PºîùÒuò¯;â_ÿGÿúCO­ö© Ï<½áé§7øŸÞPúô†?<½á‰g6üþ™<C3BE><E284A2>?»ñ±g7<´é·‡6=rhÓÇ6?xx³ïðæ‡7?ðÇÍ¿ùãæ_ÙüË#[~qdËÏ<C38B>l¹ï¹­ûžÛzÏŸŠJþTt×óE{Ÿ/ºãù¢ÛŸ/ºí…m{^ضëÅm;_ܶýEoq™×[æ-*+ÞZV¼ù¥âM/o|©xC xÝÑâµG·¯>º}ÕÑí+<2B>îXñòŽå/ï(|eçÒWv¼²sÉ«;¿º3ïÕ<C3AF>^Ý™[¾kAù.÷k»nym÷ͯïžÿúï™óúžY¯ï™ùÆžœ7öLÿóžiÞ3åÍÛXPb™þæžœ¿DÓˬ¿F3̼Šh¹¹b—»b¥šf¼·¢_¹cI厥•;Un_þööoo_ùvñªcÅ«<C385>¯}‡RPñ5 m>¾mËñmEïnÛönQñ{Ñt´ã½¢<C2BD>ïíyoëž÷·ÞþþÖ;NlÙ{bË]'6³ìt/%¨6ßÿá&ÊQ¿8MS¿þhãmØÿÑJV¾<56>7<Lùêã ¿ýdý£Ÿ¬ìÔ:ÊZ¿<5A>%®ÒàZpíÓŸ®}öÓ5”¾Ç2ØógV±$öRÕª@4•­¤TV~våkg=¯FÙlÅÕ+„„¶âmžÓþ^ø~MájZ;©f¶Sç—?g™­@ŸÙ>W3[ˆËlߦµ¯(­©9­õ(›µ«ÙŒ¥².5ƒQîb)«ObYÈZ"êã‰È,iÒÑÉÜð‡æé¨?#©éh°éµþŒMJ¯y‰'%5/]æyéO&yé<79><C3A9>—žÎ<C5BE>—šòYjú6;ýv`ve§ýÆ JÙ¿ôk£%¤©eõj¦ªfªå_¨iŠâï<C3A2>¬8§Æg¿]qö·+ª]qZ<71>ࣞS<C5BE>z>yÔóÑAŠ•>¶òƒÇVžxlÕ{<7B>GãÝÇW½£ÆÛ¿[Uù»UoýnuÅï£ñ—'V¿ùÄš??±æu5^ûÃÚWÕxùɵ”¸OFWYéºþÜUÍ]ÑôõÔ€ôõ”š¾¢ì™o3X4‰Úô¨<C3B4>Ä:ÔŸÄöÿ±?<3F>ýú¥²þ<ö³#[îWSÙ½ÑT¶•RÙݱlv§šÐn{¾ˆ²Ùn]BÛf”ÓÖGÓÚv1­y^îÏl˄̯f6Š…±ävëkÑüvókÑä6/ßf«ù<C2AB>bÒC«àó`¸dŸ_^ß!Q45m=ɼö††¦zzú¹N`¯Ïg¢^_Ü+Â}2·úCöKŠ¢PK4…ÊLõX¬ÏIC9¨×v{}>\C1Ρ©"œH2©««£q¬®®ÂPŠ2V>sè]3!oq)ñÃ4åîq}>ƒ?ÛàL`Ý®ïsj¿fÔh‰%³>_3”VŠóy*»§¯¿$¹YL(èº'wS¤5hoS^Ÿo¹qx"yŒÅbö€Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï€QK}~M[<5B>DÑ”×w$ùò;;;G†×çsÙ ÍNÂ<4E>á?ØX/J ËPÑHþÑ0”ûÇÌZÛëóÅQ6; MÍÁ &“!%ŸÀq-‰µâ¿mq)y×Å]4½ã®2+ð½ yƒC¡3ÿVR„-„Ãaq(­ç³¸³*‹Ž(’›Å÷Øüùÿ‹ô(ö¶9…>TŸŸŸŸŸŸŸŸŸŸ`È$Ùçw‡û$ŠÆwº#24ìõù¼VâEy ?7`z<>©(Šßï§ÓruIÇ»ÝnI#飙÷£?IÐsŽ`¨Yé÷;ìõùt¯½7; MÍ´1ühMY^ÃÏ£²²eS©"Ÿ|[Áâ6?^óŠÅ¥·ëâú|³쪡ã 7&Ĩ1ìl©*ê¶RœÏ·HˆïýàkÉ<6B>bwy«ë¿>ŒTØÏ…>?ú4D `ø½Îg©<oa>ÐÙø ¥…ÊÓ>|>|>|>|>|>|>|>|>|>|>`dC_ékc‰
}?¥/’èN}>qø|DÔ\ìêÅ  {}~DÐõ†g…¿™Ï§uÇT°!n·[#]éWf†322,jÞÑ ÷·Ô‡úwm÷ù¢®7<‰(üÍ>šŸD ·™NäX¹"Þf3­mxùŒ!,%®"5{^ úüÁ®Ûß!ôïR;™É§nIá½ÏJq>ï<>1c~0vþçÛļ<C384><C2BC>ÞYû"ç|¶·sú|6“iÖi&îC$îRZoá¿ðùðùðùðùðùðùðùðùðùðù€4…Õ1z½^ú2hXvÈtÃê3ïóO6wIDÍñ¦K”!`»ÏçºÒ°ZR|×ÐçÓÚäK/33³$† ìxW®1aòãÂ=ÏÈbÙîóy»áÇiÞ5<Ÿ-4èl&Ð|†Ä}ÃÊñ©• r´²”èöÁç5·>Ÿoʈ~°«FßÃâ}<7D>ÎÆþÐív§ö~g¥8_<Æã).<ð‰ä6qUvO ø¦HkÐö¦ŽBŸÏ&‰f^‰3œ¦"Ÿ<>~loÃçÃçÃçÃçÃçÃçÃçÃçÃçÃçF ¼ìÐLžV—‰E¡ëÙ$ßç·õ„%¢¦ôœüNèS”ÞÊÊá}æ"…ûZ•ñ`µ÷rŸ/Vàë?N¬Þ7ôù\0ê%0­;¾rù¤:º$»Ã} W†P;ã^ /Æ6Î|8¨KãÎ>LŸX<>¯AS½ox66ÜúàˆP¶mø¬ÇJŽÒOª¡!_J<5F>@€.™–~Ù¢Ïç.öê`W<>~ÐE+ˆÆp§;ÉX)Î<17>¡y"¹G”kÉø<C389>†ÈQG¾J$ÍçÓ Òœ·/i¤Jƒ•­[+îñáàSïÜÙ8£àóáóáóáóáóáóáóáóáóáó£
½ÐȱºL¢ôQ œ|ŸO<Û*Ñ5m=ádö@8T22ZÇŒþAí ¸×:Ÿ(í5KTý†>_s* |¯<>ý 3Evé)=»z}§[$Snøµ“Z+¿^Âmø®($­#÷ùi¯o —Òú³Në—cvZ³c×°Ö—’¡Øä]G7)Ã=:@|jLô¨ƒZ5†—/®VºÁÉ÷’ƒ•â|ºSkÿwÜ„ïÿðjúµ¦­G²F
´çו}üNÜ•2æóùÿO¸0l·kpõ÷6ú-<öÿ.Ã'Dìmø|ø|ø|ø|ø|ø|ø|ø|ø|ø|Àˆ‡1Šf^£VDáOßI¹3aEq¶#N_ãó/võ>ßVVÛÎ\}Ec§Dלùº;™=<3D>.2ŸÅ¿M†É ŸÏš¦XóºÜçZzEQ˜Ûd~X¿¢í]¡¥ç”´<E2809D>ù,žm•_ŽÜ7:áóyi®¦n\ÿºÄçe: q/y¸ù|ºïè éy×YA£Fµjä—χ&îXÛˆ_Eó¢•â|êÆy;ïgóÿd}sy}‡Ôçeq¥ <0C>äû|þTª|>k‰8p|kF“½nãü<C3A3>χχχχχχχχχÏŒ÷!z¹AÇð\.—¾Ÿ]E‰~r|þáómÌÀT4vÒ¯òò˲Úö¤]~8L#™ÏÂðB¸ ¢Q^,÷ùš:|Ž¦nßÐçV“þ<hòX?ƒYSm)ÚO#™ÏBRxÌ=­ÙåÃAw&p×*÷ù]>C_·¯?›˜±éÏý~ÿRnJ|¾ÙRr»Ýâ=H³:¬û|½<>Ôª1k6û+³A7|¬ÀÆ[‰x]mqG#:W<>}Á&ÿñ¦Kò§i¶>þñðù4
4hEðµC¯” »hbÔ¶0iÈØô¦>>>>ß:ðùðùðùðùðùðùÀ ï¼ü붙—q<>áJÓ!¹‘.$ÇçózËÒs
{E¢k|§[Ø1¬ŒÿàÙÖîpŸC û&J/™¯è C^Ùkñ`<60>Ï<EFBFBD>èÔ}ÄHòú|EQØߊÅÌt~:fPÒÒÎçK&|\6(Efv°ÞçëÕ}ÄHòžMLÚ\ì{<C·oh5%;¼…ܱ'¸Ekq)‰î]ì1£š™XºC62U3¨ `;¢·w»ÝúVIŠó©7®ÊžÍ'ÿÉæ.ÉÒ¸û•O~xJܶ—¤ùüá¿d6Ùø:Òï71ó¯y¨Ä<C384>†Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡ÏŒlÄâI³c¸zÊ0Ÿ„Ïç{žÑ@r|¾X<C2BE>ßÖ¦WÊjÛ%Ò†Ž<E280A0>öds—­
‡Ã---_]}ùüK<>õëÂ^ŸÏ— ׉úW }~D•“ôŠXÉ,ZJzËÆGcØPvvû=¶1”.!>%U>Ÿ [_L<5F>é_‰˜ÒÓyÌÔ.½.ÎøجÊ}BïˆBÞúyøÓ †O¦èu¨†¼jRèó©I| ú}Ãâ|·Û]xà^r/_­÷=úWþsCÇÛ¯eú|q&;núQfÓÒÆø|ø|ø|ø|ø|ø|ø|ø|ø|ø|À(Á°$R/q 5$òEr$ŸßîãæÌ×Ýô
ý+6¬ðòðù6+†sÈÔÕÕUUU}öþûJA<4A>1ÌM~ËÕenòùúj|}ž™Ïçús½§¥SÙ¥ôÙPÝÝ݆oºtðlë07ù¾Ó-4óåO£¤ÊçGtÕø†ûò<C3BB>¦#}>¥eQÿjž“š4iÒÐ|>o<>ϲÜã'ç¡õ¥Ä¯7AŸ?äU“BŸ/Ú`~Õ\ÿÊ‹óéÈüÂåâÖ­|<7C>î|ºV󗽤ÐçƒAútÉl ËífÛFl¶Ó»6îÃÂçÃçÃçÃçÃçÃçÃçÃçÃçÃçF¼"TRx,<2C>\ìŒÂ2<=Éñù<11>œoë K¤ÍÁ³­tÌÉæ.þŠMª©©aج®;<3B>pÈçG
|½Þ<C2BD>Xðù"<22>@ÀãñpÑ缇ñC)'…>_#ð5zŸaý£™Ûç{¯<¥¿ôÒK¥*o¼ñFe ®²+upÿÉíº¸Ù$<24>W<EFBFBD>kŽ·¾” {Ï.Ÿ?ØU“*ŸÏ»]Ó|¶È‹ó#÷vÅ'¹ôQt¤~ÿ‰²ŸËë;]_Éÿ<C389>A+Ó†­'˜EE±wvÁçÃçÃçÃçÃçÃçÃçÃçÃçÃçFV¾ý‰ßǃÁ älðù$ú|.çy]eé9E¢nÚz»zù¯ WloR{{{]]]ccãGç|¾Ïçã«IüY¿âD¿Ä\«Ù´ýé˜4”q[kç|>ßN¥i þ¬ox¶P(Ä&ƒYY¯f6²¡ljjŸÖn¼yµ¿•U ñ¢Ö—_âƒ`‰øüDV ß±±|:.4¸¼Ïé¾·"Þ… ˼ù<C2BC> ôã`EÍYÉMaÿß.hžó²<C3B3>´ðùìÈðh!|>|>|>|>|>|>|>|>|>|>`4`åÛ×)q¿<71>ÃçGèóõr¾¢±S¢nN6wÑ1϶²_<C2B2>7]Âü—àœÏkòÅZ}ýªM³|Jéä̺ 7¨†ï:çó#BM¾¦V_2¬\z9v³ÏÂl᧢.oæòV‰byPK‰þŠõ†æÒñù‰¬šäßΨø&ø[âë†ðm ñA­3åù¥ïWJn
÷má?w‡ûœ¸¨4ªÏ‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï¤V¾ýq#ÿ†È-%|~ÒÌ*—ó<15><><EFBFBD>†_eµítLy}Géæ9ó_s>?ÓGÜ^z½^ÃU)š(·Û-iÿÍ©À ÆZãÒ5}ë„Ï矋}Í õgã•üfíá—#),·xE¢aÎÈÈ0[ ➯Og­,%z<E280B9>F¿'âó‡¼jøí,™Ž—·Vó„ß+1Cœ6ü¹-Šæ²«%w„ÝåMOžúJ¼;8Á0÷ù4ÃùûÜèä4vÔ ùŽ¡½-™·~¿ŸÞÕÏy}þU3®»eÞø­ó®ß:÷†­so*š3±hΤms²¶ÍÎöΞâ<C5BE>=Ý;k†wVŽw֬♳gÎÝž3_<33>[väܺ#gÁŽœ…;)fäíš±x׌%»¦ìž¾t÷ôe»§bÏ4Ïž©«ÔX½gêÚÛ¦¬»mÊúÛ¦l¸}ÊÆÛ§lº={óÙ[îÈÞzGÖ6Š;³¼wfß™µýά{³vîÍÚµ7k÷Þ¬=wM¦¸í®É·ß5ùŽ»&Ýy÷¤½wOºëîIwGc"EÉÝïQc_ÉÄ{K&ÞW2ñþ ?cqÏ„Ÿ«ñ{nú¥¿Ú<17>_«ñhÜøŽßÆþXˆ…/ˆ¼/Å<>{c±O<C2B1>{nŒF‰wRÜ¥Æ^5îŒÅjÜ®Æmjì»ÕØ<>7EcÇM>ŠíjÇÂ+ĶX©±U<C2B1>-Ñ8°yBlRc£b±^<5E>uj¬<6A>Æ~Š5j¬¦˜<18>UB¬TÃj,W£P<C2A3>e±XÚP¨±$ùj,ž<14>¼X,ŠÆoÔøuÞ¤_åMúeÞdŠ_äMþùâÉ?Åý³îËϺ7?kŸ÷äg•,ɺ[<5B>·^ô;´Ì7.ŸF±aù´õ+¢±nÅ´µ+¦¯Y1}µ'«ÔX©†gåô+g,_9£P<C2A3>e«f,í<>œU9KVåä¯ÊY¬FÞªœE«r®î<C2AE>ÜÕ9 (Öäܺ&ǽ&ç53o¦X;s¾óÔ˜»vÖœu³f¯5K<35>™ëf嬧˜M1cýìéfOÛ0{ªS6ÌÎÞ0;kã“7Ι¤ÆÄ<C386>s&lœ{Óƹ7nœ{æþ¸>ó®Û4oüæyã6ϫƵ[æ]³%úïX5Æm<C386>¦—ëb&Eso,Š¦Š ”p¶EÎd5çDÃÛŸy¦ª1Í;‹¥ …rŠgÎ,žÉrÑœh:Šf¤y±¤DqóŽhjrDzÓ<C393>9¹j¢XD±«?SåïšÎËWjÊšN)by⚶rÏÔ•BúZË`ýIì¶hS#[HeÙEwd© Í{gˆ9Í0­‰™MLn,³í˜ÙÄ´&æ4Íx*ÛK\ÑLeœ…,'¢½<ËEšt´Ý(y¦#žÔ¤t`ËÀŒ¤IJ&%!/í<1F>—&šæ¥•ó’&5jSSüì´x@vÒ$¨_Å”>Gݟߟ¦î<C2A6>¥)1SQÜ¥ÆÞ¬;Õ¸£ ëvŠ¥Ù·-ÍÞÝjìZš½séŠK§lW£xÙo,¶©QT8•bkáÔ-jl.œº‰bùT¸ús×rž» ÒË`!ƒ±$¶l@›Á’˜><3E>-ZmœÊx6»eí·ÙL“ÐxN©Ëi<­M¥5}fËl<¹EóÛ&ãüF™?><00> ô}Sþ][<@þ½8èÝÂ($™>_/ç}§[$§;Üwæën§ 2GŽú|<7C> ÓT>ú|þbFF½ÎÍ3ý@¿r_dh¤<68>Å5+VDë{Þ ŸÏå¼™ 7<›¸Ç*¶™~æoy<I;­_µ<>Ï.ÞéZ*cÐÏ|[ÊìCy“èo³<6F>Ï ï¢D|þ<>W ¿<> áC‡†8¨£ø^ ý ö¿!b¡{Kï[o˜»¦Ir;øÍ¡jÍÓ[N<>wïCÙ/Cn‰~àÄhÖÑ@Ó1öÎ"¶¦ 7vÅ]3ýÚ·Ñç#ˆ‡|:”åз1òbø_ O¸K1ôô ×L³hðx<V<Òˆ'™>¿¦­‡ ö
7ü†AÇ·õ„Å_1ÿÍpÔç³hª#&>_\bÉñQ£®RÍ$˜s>?"d`C±lx6<78>c7,Ø–çGãóÙÇq (ÁìÙ¾
âbø@">È«†?7¡Ùksîíé_qìâ¶_Óíü¡­«²{ŠŽ(ÛÁËÇÿÅ÷é¾àÐu%Ùçk6ȬcoŸ?,ÛÝØÚ7ÜFtö°»ûÀç#ðù<02>€Ï¤5\~ŸåßCåUdâwöQ.“éó»Ã}LÈпì±ü^åõ¡€³¢±óß G}>Á©Þ‚šù|6» E®ËåJš0±¦ß[‰8ïó¹ú3ÌÀfÍ
q Í$¥t¹Ì<C2B9> Òç3|>Ÿ¦<C5B8>žãv»%Ë$®Ï§)Mg ‡a³ôùC[5lyÎç…BÔ<42>b'ˆ7V³®ÓtÚÅ®ÞÃÁOŸ=üè÷~ð<>ä^PrìËP¨<50>>Þt©¡ãŠs•dŸ¸Afe ‰æ§oðúÚbàë°hÚ'ó>Uàóø|<02>@ÀçÒ±T˜Õnñ·ÄÊ@IÕ½X,jïÃãéH2}>ÑÖ>ÙÜÅ«+»Ã}‡sðl+SÑØÉ~=|¾ ó?íP¥²²²$†ÏçKZ ñ†º1Éõض@­õûý|2<02>¸&ßÞOÔøç±jx<6A>wÒD«YãªiãÝóŠì{rï™PÐ%¹Ü´19W|ŸÏa'Íöœa°ÿ-¸Ýî$·Ð Ÿÿ¾{é  /8´~Ñ·1òbø [ÄgÃÙ÷Pú®§)hÔ—_*Š<44>âüHÒ}¾^~o»z:® >Êf,ãI6.Á(<28>ÝÔô¥ï)i†ã[Lg(rxŒë¿B…Ú%79+{s£Ð糇;4<>~H|~òÿ«à„Ï<00>|Øsßfè·ÖòÃF!)÷ùÇ›.I4ÎÉ殈±«ƒ€få¦ÜâÔÂwv|)Uš<55>@`L<Œ18SR¹7û;ß•=¨Ur¬e̘Ëɹ<C389>ú|ö ‰¾ÁiØÅjÒ|>'0Tôf^0d¾¦gRåó/võJLÎáóm# q¹\))èÃÀi&¤° ¡PHó|œÓYzÔå™ì;ÿ²ä.°p_‡ËÕœœkI¡ÏOm±âóYý›äÂçÀH"
ù|>úv™­âõzÍjÛDŸŸ™™©y´|4“rŸOøN·HdNw¸Ï¡Ïmmm­®®®«« ‡Ã˜ iÍèGX‰> eUUxq~òºEè*—ù.—MÑ`0èñxèNÝ?c[ƒÊÿ¡h—ÜÆοì]ûa2×Ô¨òùÌÒûý~ñE}ðÉ–ü Dø|<18>ЗtúJßXC¡zCd8øüòú‰Ì©iëqès««««T:;;1ÒšQ;”<1E>g„•ècUZ‡eïÔ>köÿÙ7ûà6ª{ïëOÊ þhfîTÓç<C393>Îô™¹£ç<C2A3>ç<EFBFBD>Â-5}á5¡KH€„„n)ÜR¨!ô¦´æ¥o<C2A5>JHÀ"“@J LE0o /Â/ØØoLŒ¯C­ŒËŠ…õü¼':9ìJÇ+k­]IßÏ|ÇcÉ«ÝÕžõ9»Ÿý<C5B8>p8ì<C3AC>gŸ}-L£ {Ge6<11>\:é”iIÿO¡¢«O¯Ì×ñÏ<E2809A>ÇãÔ² RÁ Sÿõt]$>saX<61>ohÚ½
ø| >¿óHZ"sZŽÏÓv™9Ìd29PÍÔmSêºNÿÂj é¬<C3A9><C2AC>jÇžžüWÎ
µ;µ¾³3Dû]ŒÅ‹³¦æglÃYúw2þå†1ÿÉ}¹Ý<C2B9>Ê#Wþ<57>ù#<23>Yqð)^ `JŸOô<10>í{n8× ´ Út±'ðù€ˆ|~:+«ÏlêNÌߦS©´am€¦DSÑu]UÕH$"YÀï÷Ë<C3B7>s0eËsSMŸbÏ t}ÒçË-¹S6?ëôE“¡³ïͽ®Ì·vÑçÓ1¡ÃeÇäÓbt0¹{/Ÿx<Î2p{O—Š¢ð?Ñ/ŽçG£Qö4<C3B6>|> âŸO4÷ê¥321…€Ê ºåbJßN%9w³´kay,ö™Ï÷^ã¾QIçÒ)ÓÑÕgæFb•ùâ.ú|>+ŠÂ\=;¢·WUÕï÷MÓœÝ:µ”üimÔq™ÏˆÌ·ÏÿäËáøKJâx:l¤ÓœO)]_O·ýÓ<C3BD>„ôé=žO(S3é3ÒŸÏ'F>Mö:6“FŒhcý<07> R¾ìûÌÈ¡/û†Œ|>Þ7<þ1åÆ?ÿøpj&_¤>þWªw4Õ{„r´7q´W?Ú›<Ú36ÑóåDÏøDOj¢çhú£‰ôGéôG“é<E2809C>Ž¥»§&»³“Ý_MvOgºs™®šJöð|um5v ê$“ÅÒ=“´½LHst¶¤º§g͸4_Î1IJ£Ï„4GldT¯(ÿbù¨p¾°—ÃÒŒHó?ö2,Íç³eÈFÍ–ÏÇ‚{%ÀÜ {ÛFGqü¾¸ºðˆÏo>*Q:ûOàÌ
`*W ÉR>pHà<03>€°¡Éï5<.éùoÚ®ûOÌíôWì»»èó™½b«ÏÏíó7^G"ëc:¨¹­šÝ©CMçfDß®àÖG eú|ñã< Þ?O=Ž-·K€¹aG#”„ƒ“Ö«úxºëóG&¦$V§¥?‰3æx<ÎÝ;s¹V+ÛCQ¾¼X†m¶{v·Kzþ³O„ξ7÷v¨b_ßEŸo<C5B8> ÁŽUq³§-Õ·ƒ§AÌÀq<C380>Ï¡3DòÀhVàó>A<04>ÏTðùót<Ýõù„Ú1*;éì4N~˜?"Ȭ2ß$ü øECN£L_2ÓÒŸlJ±¿Ê»ýo~gê·Ûö?ÛÙ921U™#àºÏ/HØè‡MK²÷C!gs°‰Šâs„J~ß9gø|<04>ÏGAàóU„Éç7”<37>uw}ÏÊûü‘‰©æ^<5E>Â\MëÁq‰ØéKfpòÀ<‡Mös“ù&)ØôAMÓ¸À?Ö÷ÅaIŸÓö…k>g¿ÓèP™ƒà¢ÏgV<tÑh”=U1-ÉFm§†lW.èD*s»ðùŸ<> ‚À窓ϧ[àP(4¯ÏëäxVÞçï:0&ºšÎ#i‰Û©˜Ï€ºB×uêÿÅ<C3BF>•Æ…q9/Aü¬ªªâûƒãÇx—>21µëãAIŸ¿~ÃÃMÿü€ýÎëùç}>kõëjší‰©xžµSCv0dS**ùeùqöÏÿ÷+ÎùÞƒ×Ô@δæ¯39ËFþCÈ÷<C388>çjÊÙùü€òЉ4äseãÕ?4ò£<C3B2>!ùÉÆйWQÎÛ¸ê|¦U4­º°iÕEMW-Ü4“E®ºxÓJŠòðL.yxåâGV^úÈÊ¥F.Û¼âòÍ+–ÍäÊ囯\±ùÊ•[®¼jËòУ˯~tù5<C3B9>.ûÙcË~þز뚗]ß¼ìÍWÜÐ|Å<>ÍWü*ry8rù-<2D>_¶æñËnÛºô×Û®Û¶ôömKŸXrÇKî~òÒ?<¹øÏ-ïyêû¶_¢nWØ®<´CiÚñÓGž¹øÑg.Žì\´mçÂgnßµpçs=½pOôÖèßs~ÛÞóc{Ïko=÷­ÖŸ¼S[êß6Oÿì5v ê+ÏÙ+dO>»ó‰Zò\>»fòö³Bv²œ{"Ïäót>;òÙ~î[¦<e¤…å¼™<iä !ÛŽçMž­ù<žO$ŸæóÍyÌÈ£B¶ä³ÙGòyØÈ&!MF6ÊCFþz"o<hä¢Ù<>Ï}–üå‚Yoä^!÷ùóñ´óü)Ÿ?
ùƒ‘ß[r÷L^g¹ËÈ<C38B>Bî`¹ðx…üÎÈo…Ünä7¬c¹h&ÿmä×íc¹ÍµBn5²FÈ-3yMÌÍFVçFJËæ ðù€ò¡Û@vûibn¸èóÛ†RÌÕ¨£ô2<C3B4><32>¸<E28093>¦î[¦¥?IËwI£í |D™O#©É3t]/8òš0<C5A1>#Üç³"s±ÏOO$$>åé{n¨üü,}>;VŠ¢ˆoÒU BûFW8¼±ÔÒ%vAØ,¢2—Oš¦ÑOŒXž&K:èóÿÏ/6¼ôk/çœòò×nó#!?¶ä'/ϹFÎrþ+ÇsÁ+·]øÊZ(mk¶­]4“[)·ÝúÓ¶[#—´­YüêšK<C5A1>,yuÍÒ¬¹ìk.ÿÇš+bkÅnY»åÊØ-+b7¯ŒÝ|Õk7¯zíæ«_[};Õÿ¹oõµ¯Ïäº×Ã׿¾¡<C2BE>ò«ßøÕ¯Þ¸7ÝüæMkÞ¼éÖ7o¼í­×½õËÛßþåoß¹¡ñ<C2A1>îz熻ÿyÃÿù‹{öÿ×½ïþ×}ï^¯¾{ýƒï]¿ñýëþàç›?¸ö±øµ<C3B8>þì©Žÿ|ºóšg»®ÙÝ}ÍóÝW¿ðQ襞U¯ö®Úׯ|§Å{ý+>üäÊîO—|`Ù<><C399>eƒÚ埼ì‹Áˇ–ŽZ2ùù¥_ /Î _RSß1_ÿó5v ê$Ÿ2rh&Ó,Ÿ-žÉ ƒB´|Œò©OŒô³\:“>#éÒ“ÏG—~EéÒe¤ÓH‡<48><0F>Ä<EFBFBD>|0“,ËûFÞËç]!û<>üsÉLÞ9©·<C2A9>¼eäM!oi7òº<C3B2>}KgòšØ×óiòŠ<E28098>¼4“c/]6“¿yÑÈ ç…ì½,CÙcd·<64>¨çŒìò¬<C2AC>3™¤<#äi#;.ŸÉv!Oi1ò¤<C3B2>'Œl3²UÌ<>i>ôcF5²EÈf#<23>y˜eÙñl2Ò´l²QÈCFþjäA!¹ßˆ:“£<ŒÜgä/È\òZø"ø|€SÐ-!ÝBì—<C3AC>>dbJ¬Õ¤wZú“½CËì?<Á~oîÕÑvP>4h²Q sªŠ¢Ì*ói=º®›>HC <0C>ÈlµÔoóùV<C3B9>ƒ½Þþw{?nkû½øÀ·2¸èó骆m—öA|“·Î¬‡zΰ§´Î
\8™¦XJÉ<>χχχÏGàóáóáóáóáóÕ Ä~™¸èó µc”›¶¡½äº¾`è¯}É ™ÌdËÜz6M¥R8 ª4e-5åáÇє•$‰PÿOÃe1EÌ«Äå2ßô,ÀÔ”ÔcóÞ»óHº¹S“ôöϼ¬5}p€ËÿŠ
}>këózǤô­‡º|èJ)°g:áp¸±8âã†9ŸŸŸŸ<>ÀçÃçÃçÃçÃçGÓ4º e7¤ûöq×ç·gƦ©;ûzž5-ýÉtvZ4Ben}`` Ë <20>Nç@5ƒ¦DSyVŸ "‘ˆ¼)©Ç>1Ùê_ŸHºzÊkí‡øï}ÉLž¬»>¿º®«ªª(
Óô‹ƒ•ù­ÓW
tÍààqžó…|>|>|>|>ŸŸŸŸŸ¨%âñ8ľ}ÜõùÖzû¦î„Dò¤³ÓͽºSE}}}L7¡¸ÚASÖ ===hJï`§2¿ Ì·6å®c¬ën~/þn×~þ/Ïõ· ¥ØïjÇh%¿¯7}þ¼ŸŸŸŸŸ<>ÀçÃçÃç#ðùï ûlF¹ã3Ö«w}>ÁÎþÃ9¡b¿`ú™öá£bI<39><C592> á4¨vД5C"‘ ¦Æ¡p³Ó”jÇ(ëºÛ_^ÛôÏ$ýü‡ï÷:øܶ$êÐçG"ÆR Cäàq†Ï‡Ï‡Ï‡ÏGàóáóáóáóáó  r±_çVßuŸ¢h³WÏ}½bßšÖƒãƒãÇøˉ)œÞà8eÊ|b¿}×<>;$<24>|ã¾Ïµ¾Qñn%¿uú|W€Ï‡Ï‡Ï‡ÏGàóáóáóáóáóÀ&ž#ÅfÕë>¿óHš«d&ÎNKT«É7•ôp
]×mÊü`0hs<68>|^Uã¾Ñ…kRN~ÏîvêØùK*ùÝ=âói7f-¯êKø|ø|ø|ø|>>>>>ì<13>FM¦>ß]Ÿ/
üÁñcôNKRb{F&¦xI?Óû¬P÷N{8¶ÿ]׃Á M™O Û\í»½¬Ó^rçxã¾QI¯uõóbþÖƒã>b®û|j2¿ßoçøÓÕ{fÂçÃçÃçÃç#ðùðùðùðùðù0+Lã¼M†Ïw×çç<04>ŸÌdé¥Xœi ýU,陘Âé "4ä‰3Ñlsöe> ¦š¦•°C;ý¿¹ûÁ³–ž¾hRÒ½?ÔúÁ´ñŒ`pü.ÎϹíómN€ÏÏÁçÃçÃçÃç#ðùðùðùðùðù€ÚE¢ñ<03>@8ŽÇãu~ˆ¼àóÓÙéÁñcLæ#SáÓÒŸ¤eÔŽãžíÃGqž#‰Pgnïì¸w ÅGr™_ÚÐy N[çó^r縤{_ÿä<C3BF>»GÏEŸO '^ŸÐ¥K£§JèB¨¡h?<Îðùðùðùðù|>|>|>|>|>0 ñíãŸo¥©;!q>´@ÛPŠý>8~ <0C>HÄ*äƒÁ ñKŸ-8bÚ”ù4àÒRt`}!¹î ŸoóI§LK:vÊ© ¾*]Í:‰‹>ŸÏŒP+{¬O*0/>>>><1F>χχχχÏð¦Ïo=(«áìKfh™Áñc#ShA@<40>¸ÕäÓ;6K©iÜ´érƒÁ ®ë¦<C3AB>ÓØ*DFb¹_ð[«}¾O_4)éØoÚ®û|ô]&]<.ú|¶Q:˜Þ®}ŸOgêóáóáóáóKn>>>>>Š<00>_Þôù<C3B4>íÓ6”BÃ@îë
Z4ùVñnEÓ4^>7™Oã/_@Q”ÛاÄnÿ_>ßzŸ¯ûÚ-IIÇ~Öò Ÿ<>vÉ+³Âfµ3™ÂYè)&EUUv}åHe¾é8ÃçÃçÃçÃç#ðùðùðùðùðù€ºnBÃá°µ(¿$¼éóÓÙi‰öiêN á ÷u í—OÓ >·/ói<C3B3>åk _
<EFBFBD>¹ûåŒ<C3A5>Ï·þÔG%½:å¤S¦ƒßz'—Ñ=r0+¼iö`%<1A>£¦g»§nÎåÇ>>>><1F>χχχχÏÔš¦Aã;ˆ7}>ÑÜ«KÌO2“-‰D¢§§g`` Ízê»4e=7eWWš²$TU¥ž¼¤ÒnÞóÛ<C3B3>F«Ì§wÄ<77>Øú<1C>Ï·Åù[ÏZ>!éÒWnóùrëB¹˜GÒEŸO<C5B8>XtŽƒ ++vX4'fPØñù´!É)í Ïÿ÷+ÎùÞƒ×Ô@δæ¯39ËFþCÈ÷<C388>çjÊÙùü€òЉ4äseãÕ?4ò£<C3B2>!ùÉÆйWQÎÛ¸ê|¦U4­º°iÕEMW-Ü4“E®ºxÓJŠòðL.yxåâGV^úÈÊ¥F.Û¼âòÍ+–ÍäÊ囯\±ùÊ•[®¼jËòУ˯~tù5<C3B9>.ûÙcË~þز뚗]ß¼ìÍWÜÐ|Å<>ÍWü*ry8rù-<2D>_¶æñËnÛºô×Û®Û¶ôömKŸXrÇKî~òÒ?<¹øÏ-ïyêû¶_¢nWØ®<´CiÚñÓGž¹øÑg.Žì\´mçÂgnßµpçs=½pOôÖèßs~ÛÞóc{Ïko=÷­ÖŸ¼S[êß6O]G<>¨úÊóFö
Ù“Ïî|¢–<—Ï®™¼ý¬<C3BD><C2AC>,çžÈ3ù<<3C>ÏŽ|¶Ÿû–)Oia9o&OyBȶãy“gk><3E>çɧù|s3ò¨<C3B2>-ùl¶ä|6²IH“<E2809C>…ò<E280A6>¿žÈû…¨F6äsŸ%¹àDÖ¹WÈ=Fþ|<í<Êç<C38A>Bþ`ä÷–Ü=“×Yî2r§<72>;X.<žF!¿3ò[!·ù<>%ëX.šÉùõEûXn³d­<64>[<5B>¬rËL^Õù„Ò²yE|> ßãé5Ÿß>,+æì<.===]©T
gBUƒ¦DSÄb±Ä‹
…¬+áÛeXSþô§O>ÿ͵­ I—~ú¢Iÿɺþx nëósùý‚Ó 8X¢/ñùš¦ÑgŽÐKëã$}> ¨÷ÏS¿<53>c R{Áý`n˜|¾¢(<28>åáH±Y O¯ùüÁñcù³ëÀ˜dæ0“Éà?«ªASÖ ÔŽ===hÊX,fÕ˜å@k ‡Ã¾R å ®G”ùÅÆÖ” <äó­?uA»¤?oÜ7êóåBgGro‡\?æ.ú|:°t0y•üÒ¥¤éŽÀöÍKºîbßÂ:­ƒþD_ŸÞ× Ø´ëFáó>A<04>ÏTÖúü2©üM±7<C2B1>§×|>¡vŒó?ô'G6  k4em<65>Ífë¹)u]<5D>F£¼>™~:¥ôK-˧M[]+ƒv<C692>/ ‹í!kÊo|Åç[ú¢$>É<7F>ã>_.ºZÉ<5A>ÄÜ=þîúü\)W8´d…÷<E280A6><C3B7>?¸T0<54>QŠ¢ÐvM¥ðùŸ<> ‚Àçªøüy:žôù»ŒIÐàø1ü;jMÓTUeõÏŽ<C38F>P´rfDí ãñxÁµE";2_$´tÓÊ Ý’Îü» ™ÀiZn·ûwîú|qÖƒ×|>o÷P¨Òs(ØUŠé>AàóAø|@A7• ŽRÌZÔ ^öù<C3B6>Ô6”¿ zÑu=KÊæm
sÉú©‡g¥þöQE²QîuíÎÈè<C388>ÓÖ5î+:ÙŠþäóåÂ竹^ÕõqÑ竪*¶;<3B><18>R*VŠ@gdµ1Сp¼>¨^¼ì󓙬Äç7÷êh>@õR° ŸëÜ2Ÿ5ÏÁäª 5JËØÙ½‰©]Æz¥û» »%=ùÊ c'<27>2ý‡è‡ô{ûðQw[ÄEŸÏŠó©É¢Ñ¨NÂbgfå…Ž‰u»ðùê¯ùüd&ÛÔ<C39B>P;FûzÙÜ«KDP:;<3B>T)&ß®(Šªª¦:ä9‰D$5ÿÅ <C385>q¶ä{×<>±|þçnüêköÞ|ÛÓü¥»-â¢Ïg¥¹ÂÛµïóËœ-27Ø%Šõ|>€ºÅk>¿}ø¨X~ß6”ˆ Î#iþÁd&KAƒª…H$Bo(rª${n&Ÿ=Jp\Õª£’Þ›'Ñôo-oìöȬ+×}¾³<C2BE>Tì0«Ïƒž¢%A¥ ­[ÿŸ nñšÏïKf¸çIf²âKkZŽ›>Ūú ~Ðu<C390>zò¹™|¿ß?ªvdbÊŽÌß²7|æßøËý‡'Ü=.ú|æÕ]ÑæÞ$<1E>ÓÉYlR|>ÅÂápƒ<70>¢(<28><><EFBFBD>š¦9¾¯ùütvÚT~/qAjÇ(ûTK½³ëÀÎ@<40>@ƒB(òûý¾9ACŒãeùŒý‡'ìøü—žòÝö?ñ—Ôÿ»{<]ôùHÄ;±ëÈe~>PÓPHãÑ< Ð`Î4Ðý{Á¿Òõ+Õ³Bï;kõ½æós9O?%:hdb*÷uw”Ìdqjh4ª(Šo®<02>X,æünˆäzÕ\F—÷Û<ZWSwÂ;Oc]ôùD(¢íR³Ö¹Ã™Uæçàó5
îâl»ù{ìæ€D¡Óe¼ØþJ{Ní‰}¾(çs³ÕyÒ_s_¯êgïØ!ÍŽŽŽ¦R)œ<>Õš²šòðáÃhÊbÄãqº»ŸsAþüú<C3BC>ÎÆ\o&o‡ÔŽÑYe~ã¾ÑážOø˾dÆõÃë®Ï'Ø3jßP(Ô(Å©Ç1¬x€V8ë´K´p±:Ïp¿]çÄL• ðù€Úƒ:ÀC6Ž €G<E282AC>(t±2?ÐU»yƒ¢ÒwªJ߃>dbJ4<âKkZú“ìS¦ª~; t¤Óiœ“U šMYÛP‡¯ªªX³77Eqv†× 2zn§Ÿùü¿/´Sœÿôs¯· ¥ØïjǨŽ³‹>¿Ø¤¼bØ1ðö·kgmlI:…\9¦=„ÏÔl”èx„b
=‰ð7ÕrŸÕwêžÚƒ>ŸhêN0ÉÓ6”_L:;<3B>³TõÛ¡¯¯<C2AF>™CW;hÊš¡§§§šn½©kUËÖŒñxÜô0wÎPo§¢;<1A>Ò4¾”lxq~‹ïÝ®íøü×^ý˜—ñ·÷BÃÁçϺ¤G.àóµG±<47>À© Y LŠ)tEQŠÉ|†®ëÜí8R­áMŸßzpœIž¦î„ø²`ú’Z&™ÉšÞ™•±±±<C2B1><C2B1><EFBFBD>¡¡!œ<>Õš²fH$Ô”ÃÃÃÕûâñ8/¤Ÿ›Ò§;÷p8\~5>ƒ† *€6:G]lçGWÿoÿÉwN[wß«‡ìøü—^îá¿<C3A1>LLy¡í\ôùH¤±œÒ;6}>?2ðù0Oˆ£°È|M¬%Rì¾Øï÷Óû<C393>@@òÙh4ê`µ†7}~_2Ã=O2“_Zà ;MUýPaâñ8ëÆKõùº®G"P($~¼Lh(¡uÚÙº¦i¦Y4ДðµßçZ|<7C>ÓÖù|ë)<29>û>ŸUæ¯ß½÷sñ¹­pÑçW:+ò𫎆âˆç†ê yŸ¨=h,¶^85#”O1…ÎއÒÏêº>—úÉ"xÓ秳Ó\ûtI/­á.¨m(å5;¨"ˆx'N<>ꬳ¨èæ]UUV#í ´B&?g<#w~·ÿÙRZ®Å¹î &ómúügZ»G&¦ÔŽQÖÉ{¤ëÄç_³$èÜpdb`ùÀçjêŸÅÙy¡PÈ#½.ÈÍæógõ5ïó‰]Ƙö™˜¢—-ýI‰Jf²9KU?N3ˆD"¢ù¤{ðY—ïÙ<C3AF>¶[ÒÔ­p8,~< ÆãñÒ¾y[ƒXœOùæw[¹¡{mkBÒi¿Öþ…±N|~.?°$EÑ4Í#ûŸ¨ah ¦ñ&ÀkSèlV;êóƒãǸo>*QCûO°Åø;ôYœf€Ê`ùòΙnÒYWï ~¿?
•¤[­»1—:ÀCÑ\O]ù}.óóy±qßh±þt$®y®=ãói7è2€ÏÚô»ªªº&ø9À£äG<ó|>
SL¡³RIºy—|£h4ZþžxÙçŒLLI|~s¯ÎcÚŸ^¦³Ó8ÍÀTâN]t±%u]…BΚü`0H[,Õôjšfz Ùm»úoøO¾Ëäó¿}F\Òc¯Ü0VÊÊáºÏ§vä¿àSÕiwÍ6çHy@%<25>Ï€*BÓ´˜£¸2™ß‡Ãaº<61>æõoôíèMúS±{vÚÛ@ À>^R)f1ªÅçjǨDñJ~¨¼ <0B>UæS¯ÎºwG <47>€†<E282AC>9<EFBFBD>¢¸ƒs/Ànñ…ξÜRœ¿~ášÏ%Ýõé‹&ÝxK;,•ß:<3A>ïvÎ<76>P(äàFÙD€9>Íqø|¨"Lò¤|bn” J ¿<>·ßÓ;Á`ÐYý^E>¿õà¸Dµ ¥ðߨ0¼šZRâN£ ïºË„¶
…ʶt]W…Fœ2 ³ãÛ~a•ù>ß曶ë’îúœ ¿òfkºëóÅs‰ÚE|ÈB;&Îì¨:ýî8ðùPEԆϧoA÷æüæ½ &ÍbZxîå”EŽ§÷}~_2#DMÝ üw*L4õ듳<02> Ö‡¼®ÓаÃêóO]Ð*é«oÚ®—÷ aqÑçG"¶]EQŠM¤sŒ=ñ§ŸuþŸ¨a¨·wk
9À<Q>_„®Öhè^ž¾ÝÈso/ñùÖæUÏ'ÔŽQ‰&™˜Â?À#°ør†§`0<>zzë8±Øg…Šóן¾è=IG½pMÊíQWò<57>\óù¬ü>ÈßÃùx¸C+o”Bg£G¦ÀçjêÛi à#õº°ú¨yølt¿ßO×?tgªiÿ+ýN×Hô>+oóøŒuºxw>—÷ùôÓÙÕåóÛ†RMD-im‰D¢§§g`` ÍâߧªAS¢)½F<ƒsÓøÔ«ªj<ˆ¦% úü•I:êoŸq̳ßÈEŸÏŽ<>Ëö<>ˆ.fÜ:] ðK#9<>Þ˜\Ÿ¨=èÊÁÚë:ÛÛx ºÚá&D^É@åæßËJß]ãÍG…Fuùü‰)‰&jêN”´¶žžž.ƒT*åýïДhÊj!<1A>Ú´£&ú`uUâÅbŸ56¾Xp¯èó÷<15>HER/×|¾ý ƒlÔvpÈæWDv@}>ÌÅzc”è VÑ4<C391>ƒA×Éû5<C3BB>óJuù|¢©;!Qú#SöW588ÈÌa&“Á?QUƒ¦¬¨{zzª·)y§jßä;åHiøSU•:óJóÅZ_eþ7¿ó˜¤^¹aÌËòµ}><3E>{lÓ<6C>@€ÖL;Àæ•Ð‰ËÃfÐOï8%ø|@íÁæb[qvj6€wàþ$<1A>Úüݲ<E28093>„B!º*òùmC)‰,¢¿´¶T*\ )kƒl6[½MIÃJ±ñb„ÃaG©¦i4‰“*vûÿƒÿ÷gÑ矵üo.úôE“ñ¸w[ÐEŸÏÎ;b˜owê Ûn àç!{Çtþ°K…J>'Ÿ¨=ødsu^{†+”9|Šnc]Üsºe…B´\ªÏZ¨É ¼#;Pu>dbJ"‹šºøwT]×™hµ u¹q'Ôv4!^on*Χ¬Ü𾤋>óÉÁñcžmD}>‹ý~¿ÜÛðrzûÕ rØ3 UPâ¬ßú<ˆ]¨Ä½ñ<>P{Pÿ/>—gPŸŒ#€Z¥Ÿ_ùÛvN±2Œ`0(¹e®sŸO4u'$¾¨/‰"m@E¡?<>º[Ÿõ¹­<C2B9>Rp£Ô™W¾8ÿ¤S8}Q”"éœç<ªb¸èó5Mã§G±æSU•-#Ó—‰u6»* Ÿ¦%ÙGJôáó5 õÆâÈ
…œêí<7ó%UŽñw÷¹˜ð)výV‡>?™É6u'ÔŽQæêÛ†RSÔzpÿ€òá–^®ßi1kA]1Á`ù÷æÑh´à¨A7þòêng‰<ô</Ë_rçÛvL>KKÒ-î¢ÏÏ Ã1+ÈTU5‡þ$§Šós…|>`½$`»çKø|@ C×Ô-Ãä æáwÁ¡PÈæGøm{0¬ü³ûe.Òé%íÝ¡Óþ‹ïË¿¬³‡ÎË>¿}ø(³@ͽ:½™˜’˜"µc”0™ÉRð(S/]l±d¾ýJŽ8R°jmêÉç÷Æ?¥ÍD@×'ýþ¹Ï_ÛªÙ÷ùÔ¥{³ÑÝõùÖ–-Hù“;DXi<58>¸N:
H°%áó8Ýut«+ë¤ò
 ím,ãû¦ºK­CŸßy$ÍEóóͽºD±2~ú)¾˜´j±a"<1A>Ú—ùjX¶]V<>ï`©vQDr-¾™:±­;nmá2ÿÔ›ìË|ÊÈÄ”7ÛÝuŸÏW,Å7=¸q¼¹Ãá°õIS÷t±º}]×ù¥-ï…–‚Ï€Ý~òHMÓ
.ÆnK¹<4B>¡_\™Ì(WètÃ.Ù½:ôùéì4A<>GÒôÎþÃYÔzp<g©ê€Y¡.WM$2_,à—C=¹©Ô¹šHÄs;ýÇ}~çñC¡uwp™O9kùßìË|q
•×ð‚Ïç{B'^ƒ<>¢(ô;SëŽÃÊ!诚Äã`¢ØÅU…<55>Ï@×u^ôΠ—ì.˜
…L ótƒ,‡ß)KÊ5YÉœµj.W—>ŸhéO2´ëÀ½Lf²³ú"kU?HˆÇãâ0á÷û•CÛ—ùÔµÚyj¬išjàÊ#æ¢dôÜ Áã2Ÿ2co7œõ°èóWnxß¾ÏgÏ[½‰w|~%¡Ë :ñL¢¾àîà“2<E2809C>Ï€Ú@×uEQ¼_0É<30><C389>äi}>‰À´ŸõéóyA>¯ílîÕ%ʨ/™±Võ@1¨Cæ½.Š<>üyë¬XÈš MÐÚh[ö?RQÞçZ|ñ?.PÎ….¸M×'é½è“/2Ÿb_æ{¼7vÑç³R|:<u4蚊ýSÐ/®Ô?>j ºå¤b¹É…B.Ö@Úñù9¡:ÎdÚëÓç<C393>LL‰®>'~I (wþ¬ªßD6M¥Rø¯©vДhÊ2‰F£¦é]ÅÆ>‘ùš¦ªEñJcˆäZ|úoN[Ǽ½ª¾§ë“<C3AB>÷Š2ÿ» O—äóÓÙiÏž~.úüªˆ½|> &¡kºx`RéR¤Ø$A€Z….‡"H8nhll¤ë"M>ß7vç>k%]ȱ%Å˹úôùDSwé ¶¡×—Ìd%ÊHíMg§Eço]áÀÀ@—A:<3A>êýêM‰¦,Q­óð4vÈ‹¨Å#­‡w¼V™ïÖÄ13‰x®ÅGQÎqu‰tݱîSqþÂ5ûìËüæ^Ý˧Ÿ‹>ŸÍ.ôûýè쟨=ÄÙÙv.'@… ìÎ]þp<C3BE>»ZKžºõùmC)f„šºì^~_0<5F>GÒ¢ógUý"}}}Ì¢®»ÚASÖ ===®4%ï Ý8S_Í°ÎJ$)¶!êÕYÿoš2æ…gÍ'HÄs;ý¹_äº3¸·ohØ¡õ šd>em«fßç·õòéç¢Ï§!žm—NEw<45>ý 4x¹¥àóµG8.8¯GÀ#pw éöY²$¿´ãJ¿n}~_2Ã¥P2“¥wÄò{kZŽç„ª~öRdlll```hh'dµƒ¦¬5åððpå7M¬¦iÅþd-™›ƒÌ'Lë¡ÞCŸÑs»¹<5F> ü'ߍ½ßÿ ¦%• #&™êMöe>edbÊ˧Ÿ 3‡<33>tV;ç 6gÄtršˆF£Þ)…ÏÔÅæÊojvãI7§Š¢4pÁB¿ðBww÷P¼qƒ¡P¨`9œ©(4dPŸ>ŸàRhÿá z)–ß[£vŒæ„ª~öJ¾̧Åhè¯<E28098>¯Šº\/ FèUs->}Ë7§­ãÞ>ý$Öúºµ8ÿÛg<aGãoÜ÷%õÀÔ{¼­Ý­Ï§­Ó%
Ÿ¾ACCqä<EFBFBD><EFBFBD>´iÎHAŸÏÞ¬ðƒ†bÀçj~g£W ÎA·œ¯…¸*g•ôÓõ{Ò‚Ž¨Ø—•¾³¶¡º|~ëÁqSgKR^ Já/û’ü<>ì‰Dlåó)Trhêu”±Îs(ªoùFð[«¹´‡ÿ¡ë“<C3AB>÷Z}>eáš}×né—ôÃk[ M¯ŠævÑç+Ë,FÁ€9@\æ³Çü ÜC<C39C>”èÃçjq ¾pdPÛHª(M>Ÿ¹×<>
{ú î³dIú
¦oçÈ>T—Ï'Ç<>q™Oì?<!ñH¬´©;Á^¶Å¿ À&Å*åæ,ó«æ‹/ÝÄu}CÃÓ;…ªôßôÃwo=T-_¼}¾ªªl…ôÝù<05>@8¦7é§Z
>P“ð>™€ÚF×uQwÓpÃï|M~F¼<46>uÚ º~õöœ¾c$¡¯ÀÊõÙtÕù|ÉLVâš{uZ¦óHš~oêNÐÂøOÌ
u¶öý*uÈ´|Í|wU}<7D>ú`p«®OF6·Kd>åÇ×i~ø–û&«å»»èóãñx¬œšcÈÎsÓåGÁ#À®¿T /N6lÒŠ}mŸ¨U¨{gw…ÑhG5õbá=¿7ïUéMnþ<03>@<40>·j÷ù9¡ü¾`àð%<11>Çih°)ó©ç¬%™Ÿ›ÞdÞï ÿ令>óµ[Nxõº¯ªå»»èóÝ]™Dze|¾¦iÖ§f6? ŸÕÝr™/Þ–ôù¹¯ósù_«Ð—eeawÓ+V¬X´hd%Ùlvtt4•JÉ·E Ðb´p%Wõü'£•Ôy$íÊ^aUXUE£ÑunWE#8ÕKN(ª½Ã<1E>·Rè—\F§_äÅù>ß‹’xmkÂ4ÆzùXµµµÕÏ/øe ¾ôùtÙÆÿÑèZm0´¿ò2}þ³;wÒ§ayçíw橇Á±E©½ÔÉE2 2¨ªZÐÛóù9CÚ°?)ŠRÛÇZÿf¥«««££C²<C2B2><E28099><EFBFBD>.ƒt:]l™T*Å–¬äª^éøDb“žüè°+{…UaUX•VÅ$¤ÕO\Ÿ¯dZsÍö;Ö½0Ì_ÿ|@Ò/¹s\Óæå ҟ쬊þjU[·n­7ŸÏ®ìÔçƒAñ´/>§’®Áø ûS]ÊôùâÇy@½žz[A<>ÚK<C39A>\$*ݲCÓ=©ÄççòÓÌ<03>ïìÔšvuu HVÒÓÓÃt‡¤Êqtt”-SùUýåƒ/$BÉ­½Âª°*¬ÊÅU½õÖ[gžy¦ØÑIV¥ë:Œv'v% ;{Õ××ôÔªb/uÎ*óC¡/½í¨¤û½ôÆ´g¿ uUÍÍÍõæóÙ/>Ó„a=üjÊ)<29>ôïÆ+óí;|ø|<04>ÏGAàóÕ/A7½/÷ùÅ>åeâñxC¡»ï†â:ÍÍÍkÖ¬¬$H IÉf³ƒƒƒ´˜DÌÓªv¥}½]Ù+¬
«ÂªÜZÕž={N9åîfý~¿ÉCŠ«Òu<C392>ÕÛ<>V<15>F­«¢-.X°@RÀìñÃNËïëúd`Á½r™ nU”îk·$%Ýïêu_Ü«±±±9ìÕ|¯jïÞ½®û|:QEaC³„W5s@Ó4¶BU°â¦#@ÿŸ}³’¢¼÷ýþ­JÝηêƪS™:§NYÇœh+˜_`xµ£øÆ‹´ ¢Øˆb≎c£¶r_0Û®q±MÜ@<‡ã\B¼$\“,îÞÅ°Í!ìÉ:=v˜0÷7ýì>ôÎKOÏìÌÎtÏ÷S¿¢všž~yúy~Ïô§ÍŽ§lýžÿmVö ’ðù|><02>@ àó~§q|>?£J Ûš÷uÈþφ\„RÛá<C39B>¼ßŠÅbÝÝÝ.žø\J\J'ªª:Íg(ÊzuË w•^E1ï¦h¡óM¨\é:­hq¾®ÚÔôKî]Ó{î¹><1F>ÊŠÏ°%QRW¬”ÏO<C38F>”賟š¦qÃωvÄûv¥vÊx”½Á
úü '|ù¢_ F|yÆå—L¿ü²é—_>íò¯Mø<E280BA>©¯š2aÒ” áð„©á˦O¾lÆäË®™té¬I—^7éÒ믾töÕâ W7^%Þt•(]%~ó*ñæ«.¹ùÊKn‰9vÜÊãŠKn·ÇÅUˆÌöoµ Û7íã¼ÉŽ탟}uæDèt®µÏÎnæ¤Ké4§<34>Ä´ðetîS™F˜l·ÆÕS&P³\9eÂS3MDñõ©©¹¾:m"µÅÄé—O°±h\ê9Doq‰·¸Ø[|Å[üëôË7¼ùZ•ÒšÿÇTV\^<5E>øW/1Ý-¾Rz\ì9¼ôÉ¢}»èqh
ÇDgL;——™±Ÿ_ã1u8¾žßÈWŒŽ+<2B>1…"“²âêÑ1itLæÎDxtL9”è2éÎÓx8²bnÌpÄÌáÈäÒk×:â:v6æ1{8D6Ñ°¸ÇH&¿idF¦!7çLI·äLOÎjôÄtq=Ÿ+³çPgÜz…c¶uœàœ-<2D>¶â ˜™GæG{Š¯Ï™%3¥}­³fIê]|Šdó#u{63ÒøºøÊKàóUBevoH÷¡Îåî>Ÿ×ùèLáóó2”:ëâ”6ˆåýVGGG»<47>{ý*¨p)q)9|:àÀ.ź®;=¼;…6•%ó Õç×û#é]R:fúíµÝEe¾ª~Lñ<4C>ßvɽsÖ|ðA—<41>Fe }>u-ï]±²>?wÔä…Ö©ÔîêÊç_zÿìðß
FÌØñè7ùÈ_¬^¦¯ZýŽòøÛ+ŸÞ|¿Úºâ•Ÿ,×ZýT[º­ùÞ÷__òÁ¦{>|uñîWýöå»?Þx÷^ZØùï ®¿ëÐú»¿¸àÈó<E280B9>½0ÿ¸:ÿ„:¿W<C2BF>ÿWu^ßóó>{~žõÅÜøssûŸû·g‡c w&ì8Y¹ ÍÒ¾h¿t~aþt¯_@GHÇIG»oƒüû<C3BC>òï^¾ûÿ¼²èׯ,Š¾ºhçkµéž_¾¾äç?^ònó·ïݬ-}ë<>eo´,ûñ›Ë^ýÉò oÝ·þ­û¨5žÝ¼âïkö5Ñco¯|tëƒÔ\Ê6åþwW-×W-yï¡Eï=´ðç«yÜÅâ«dâaŠù£cžŽ;sâ;n‰ÛFÇ­#1§<31>â[râf;¾IñËLH£bÍM#q#Åö57äÄì¸><13>^7:®Ýþè[ÿ³J™mÊxuþ)Œ_<C592>©Ùñ(<28>ibº{ìÈÄŒÑ1st\S(¶?:Ë×:âº|q}&ØE?ײ»ë6vðŽ4ªƒ±Ž7Ò oÎêœï?2‡ú­£;;6ëí¬ó;‡ÃÜ_d<64>ç8ZðóÕ F†sÊï­¾ÛŽEöØd±ø½‡î±cÉHÜ«¯¢Xª¯Z64œ—¿»ê>;VŒÄýÛV=°mÕÊxpBAÃÕH<ôŽ²:>lÇ#ï<¸fk&µã[[W~ëí•ß¶SÅ¿Ùñ<C399>·W>nÇo¯Œü,Of"“dÖmyà»#ñÔæ¾·ùþ§íøþæû)ýÐŽg6¯xæ§+~ôÓÏÚñ\ëŠç[W¨v¼ÐºâÅ·V¬ÏÄ}ÿþÖ}/½uß;6¾ußË?YþŠ¯¾¹üµ7—ozsÅë-Ëší œOٯŎ7[ýä<C3BD>eo½A)qi«¶t³[´¥?k¾÷m;¶6ß»-™ä©ÿxÉ{?Î$Ò_¼¾ä};Ú^_²}Å=;6ÝCif<E28093>ÿØ´ø?_[LY÷¿^[L³ eàÿýê¢]v6¦øÍ+>²c<C2B2>=ËP¢Þ»ñîÿ‰LÞþÃÙØ Ó¼³oÃÂý¶¿”I韼´°ãß3ÓÐÿ³g"Š?Ùó¥}óÅ4+õÐÄôÂü£/d¦š›øôôßê|š&(bö •™žì‰©²óQIpÄÀpd&Ê¿9²ßžL)¬áÈœÂgö¹PüõùyÿmŸ`¯}¦ì”ÿl·µC<C2B5>Ý&Ô8ÔDŸÚÍEM×a·$5é7,¤F¦§ßc_>KÒµ£ëH×”.ñ;Í÷nÉÌK©Ÿ¼þæ2êH/ÙS$õCêŸÔ<C5B8>©WS·§A£†Æ—ôÜ]ðù€*¡iZÞ{CŸÏ+Ðüå±é°##TdƒÁðùDs§å¢•N žÉýJOO3‡ÉdƒÈ×àR†îînºŽå]Ê,-éž'ùÄá…B>ë‰@<05>gUHZé<5A>átkS&ÞËÿkÜøÍïŠÊüpxK:£ O-^û.‰÷†e+ûRÖ„ú|>Sw¢¿³ŠÆêÉ…Þ CRKwæ…<1D>;’þà?i¨ñ½o>>>>>>>>>>àwxaýk_îâóùí$Ý]6rÓÆçï>~ÒE+ííÌû­D" p)ƒA*•*ûR:ý<ÍîzÐKA2ßT¡i"ë‰@½Ëü˜qøLæSlsW1Œ^AXï.óiË:•YûD´õ7ï¹$^å™ÄßOù¨ûÕÐçó<06>¿a*mfù¢/<2F>P ЯIÂ6´¾®ë.o¸
ÿé5Æ7àóáóáóáóáóáóáóáóáóáóÀYÛÆ5N^Ÿoš&¿£¤;h´[0|þ‰Á3.Z©¹Ó Øp»î.Ei
EÑ»Ì/´©,™_Ô”Ö˜C7ùÖ¦óoº4£÷GcY§Ä~²hq~4z„òmÏÀéôþˆKÖõcϯö#!UUiûÔó³S÷¦³·×h˜Ð<CB9C> þ"ý¡¤â
ø|ø|ø|ø|ø|ø|ø|ø|ø|ø|@0pÖ}I¤Úð{d^uæ40%½ßH|íó·êÿþþÚz0Î>n<sÑJC©³#Êù”Ó\䤮ëìe./ˆ¢X¨29«¼¿ÞßóÚ#s™¯-<2D>È´|$òѨu•ùŠòaW<É]}QŸOá£þSCŸÏºeI5ê%Áæú܉žýpªÞ~]f,û…χχχχχχχχχÏ˲²t½{Õe:…èhª½G_û|îºâIúØvxÀÅ)íÿlˆ}k(u¶gàt<™Â<E284A2> q ìª(J“gdY.$ó Ãð<C383>ÌOZéí"—ùʬ¹™‡·8W”çþ´¨ÌÅôȃT<C692><54>ú|<7C>°_/Õ{˃•7侓ŸŸŸŸŸŸŸŸŸŸŸ¨9š¦ñW¹ A7°†aÔÉÓ°7Ð]=°× \ŠNËÆ×ä· <>¼j4o°uø·Ô}}¨Ø A 4+Š¢w™ï®U)óä\×/yÅŒôV<C3B4>™|kÓyáYæ”óšÖÎW|òÖ¢2_ÖF/­LÉÓ»Ïßy,á£~RCŸÏvM¿^
=EûજËáóáóáóáóáóáóáóáóáóáóáóu®ëtÓš%pè¾UQ”ú1ù¦iºhüB%£•µú¾öù;<3B>%˜2R÷õ¥íÂ{­ÄÖI;ªúyÅ> Àhš&÷4ë¥Þ><1A>Rò¬Æ3ÖJ²Kb2ßxúÐÿ|ÌiæuýSGû´•ùì+î<>Msƒ½<åjèó öþHo¯ ü÷ ÚKĆÕ?ÐE¼QXðùðùðùðùðùðùðùðùðùðùàG Ã(I19Ëõ+øHÂ×>ÿÄà™,k´íP¿8Më4wZYû€ ÂiM²kíÙI·6iK'
ç¯ãZ^[X™=Ãøð/2ŸóSÚ,Éçûë5¨qðùeE Ô»(Šš¦E])ãYRÙ¿:œT¤>>>>>>>>>>|݉;o«%Ibeo¹*‰Ö¤åªªÒ:Õ<>N¾öùÄÆ1§œßÛ;èbvKÐ:»<>ŸÌªØ˲JzJÅ@É|ï|©å%I·¬Sü<C3BC>?pªþB!Ë;øW(mz—ùÍ<C3B9>¿šk|¾sãïÕé…,Ëðùðùðùðùðùðùðùðùðùðùðù€šcFØFÓ4<C393>_¡5ÙWj"pø µ$IÞ«ì,ËâV¿RúÝï>籄SÎÇ“©¢rÉYÕÏ*öƒ{(òn))µR X#(ʇN-‰|äü_Mk÷"ó%Iç_éŠ'K*Îg<C38E>P}Dà}>ƒ½#±aÄ~D¼A_{#ÀçÃçÃçÃçÃçÃçÃçÃçÃçÃç¿Aö~o8öÛɱÀŠóEQ,㻼â´"O"üîó<C3AE>r¾+ž¤%Í<>_Š'SiG‰éûŸö%>3N —T*ÕׇKðKÉ^VòòTÓ4ç PEQK÷<4B>¾ ÞÂœ¼ ¬×õOG7Q{Q“O!Š-¬žß0zé<7A>¶Ã%ùüß™'ü5*ÇÁçóòƒ1â½z¡X' <09>ÿ!ø|ø|ø|ø|ø|ø|ø|ø|ø|ø|(Ãçó
ùñ÷ùt;Ïv]Þý8ÿzE”ß}>±ñ@Œ¹£¶ÃiGÅ~ÞØÛ;Hëp+µÁøK{{ûÐЯéîîn·Á¥ ê¥Ôu<C394>)zú×} <§y!
Õä­ñ!S<>ÅÃèÍZîEæÓw™Ì—åì#ê1þÐþ‰¿Få8øüzCQ”
>ð|>|>|>|>|>|>|>|>|>|> ᯊ3¸œ÷øÎ8ÝÀVä¥õ²žíºì÷Ö+xäðù\à«ûúècÏÀi¿ÔÜiÑ:û?:gø÷w ®Ûïtuu1 ŒKéw:::r/¥3c»ˆV˲$Iò.óiâ ¯4Z {—ùì)€ª~Ì–\þYI2Ÿ=-õרl@Ÿ_àóáóáóáóáóáóáóáóáóáó HI˜îèº>ÎÏ<>Ay»¶, >ßɉÁ3Ü õ œ¦%îE¤ñdj(uüõ¡¿`@ù<>þþþîîîcÇŽ¡)üN,£KyüøqöÑ4MQ³$|Þ/RbÌZÓA\
)+R>ÿ©að(ó)týÓtæu°^AXÏ\9÷—^4þ÷ÚºYþøÈ_<C388>—ÒÀç<C380>ðùðùðùðùðùðùðùðùðùðù¤R>¿& yIÊøº¦i|ŸOl;ÔÏkÃ.ºioï ­Óz0Î>Òw1 ¨C(Å àE—$óiMÃ0
픿í<£ûäcÛ=Ê|Mkg_žpËc×µ}ztÃÞøœµn öÍöoÕÐçSߦž©SÓ¦iR …B¾~µ>>>>>>>>>>ЀÐ<E282AC>79t“ö†$I.õ™Õ†°Zâ}¨a\pUäv>>?®xÒE71í¿·w<C2B7>}l=Ç€ ÞPÅ£„/IæS¢+”9³¶C™¶®(i¥wI™H˜E×µ¬S¤—*óey_¨Ìº1ÝÚ”>U”ôMq—»cû_ýÛëjèóé7‰Ëë'NèwNM^-¬ uåó/šñÕK˜¸˯/¿næÒY×/™%Ý3sÎâ™w.š¹àîwËÓïY8mÙ]ÓV,˜ºrÁTeþ”Õó¦<2/üè¼ð·çNþ·¹“¿sòwN~òŽÉkîŽÉOÝ>ù{·O¢xúöIß¿-?¸3qõ3,n½úGŽx¶ÒAÛ¤}Ñ~鞺}ÛöAÒÑ>6wò·æ…×Ì Ó)Љ¬š?…ΈÎëþSï»kêò»¦-]8mÉÂéåéäéòÝÓïº{ÆüE3æ-šA­qû¢™·.δÌÍ÷̤&ºqÉ57,¹æú%×\{ï¬kî<6B>5séµ3^;uÙµSf±œÅu“½Å¤œ¸:'®Ê×_™W8ã¾ë¿/¾î!¾‰ÙYñÕûfoúek•{<7B>™Ërc…טPJL,%./öÅÊ_+þuo·_}#«ûåtÎ|}xT'Ïn£†<C2A3>µÑ<03>bª#¦9bº#f,=3³ƒ†ö¬kfÆ8Ŭ¸Ö×<>%O;®™=7äÄ<C3A4>#qÓ=,2É„Å7G2ÌÍgÞ2sFe¡[eâ6;n‰;ì¸s$æÚ1/3xP6÷ŒvÜeÇÂáȤ;Yž~·±ØŽ{2A&dbÚ½vP¶\zWfv X~.2¹ô¾SWØA©õ;VÚñ …<>uyP~h^&VÛñ°<1D>ØYz<59>=Ñð Ôým{ÞyÌÊçß±ƒæ 6 ±ˆØó›’جô];ì¹éÜôÄf¨ ÏPÃÓS5¦¤²'²¼Aè3#GûÃá>Ü6<ç²³ûž#èÜY#¬³Û„µOd¤Å¨õ¾c·ç·íùñÑ)òaûº(ŽYr…=KÒå¦>°xáð,I}‰Ol~¤ŽM]ýºÌ´8Æ×·M†ÏT ~^ö½á8CwâN¿¤iZQ9o†³pTQ”ŠI }>¡îës1Nñdj(u¶õ`|ã<>XW<‰<>ëç)õÊ<>™ÞôKÚ4M3Kæ»Ôðמ„™Þ.f;Åž"Ø0z<30>e~$ò_(~i•µé¼ôV<C3B4>öû¿þá¬Kj<4B>ìê«ÐÔTjèóY7öRfÀ~ øå×N^êÊç#ˆÕª4ØѶ¼ðño}@ýá;ŸŸ¹%Ï*@ ‡ÃÑÐj´<6A>×äó5+RœŸ®Ïo;<à"<22>ööPŸð¤Ä¼ºát¾¯äNIÛqy .ˆµÎd>Åïݺ®*ëK•ùô_(œ¿ÎxúÌŽŽfJÂ/
»½ý4g퀇óú¥†>Ÿí”Àãñõ”mšfÔ†þ(o ðù|><02>@ àó~‡n ™ýör/\?¨ªêQF9$©R2?\Ÿßw“NÍ<4E>V<EFBFBD>N€ A‰ÑW/Iæ»lGÓ´,™_Á[y²dþv1<76>,x´Î„õÑè†íuþ×°Ìß%¥3<C2A5>¡ÓsÖº=*½(œôP`^¿Àç×ôÓ®ÐÈ…ÏG àóŸhL4M£ûb­¦ö<C2A6>=‰…BM~ÅXÕçê¾>ïO¦0¨C,ËRm\¼ºw™ïîç)ÿ;W뼸Ü!óµ¥™o×õOóµá)IÒ½Ë|Ãèåß ‡·œ«Ø_:1³»÷Bì©<C3AC> ¤×´Å\òêç>¶Ü‚뺠†>Ÿý ðòƒ„½Ü¶Ñu<C391>ÿ.¢?r­þ}þSk×Ѫ“¯¼Šá¥_¹¸Ú»CT$èJñ«FW°qN|ÛÖwª4¢ÑÕ§cœ}íuEקuœ_Aú"0¥Ö[ò'(À_Ð=#+ݬ‡ƒ¡ÛUö|A¤°ºsgïT©d4À>¿í°[éÞÞA üˆ®ëe¾»Ÿ§¬ë\YQ”º>í|2Ÿ"ù(kEÓŒbKy2?<3F>ÑÅ;Ø=yËÌÌîh§´ë̳<C38C>ô/<ãT—l¢ýú»kÕÐçÓÔïe"¦_¬óÓÜÈÑM- ØÐ0gW„}Ìú 4FŸ?ÐQ9}Q /Vð¨ÿ~Ð@N9ÿÛ={Š®Oë ÌØw`J€FÀ4MfÅ¢(J­nÛëŠûü®xÒE=5wZ/øŽ¬Šú²e~z´Ï¯íZÅ) ósëó£Ñ#°¾l™OXÝ¿¥]諾Ìv—>4Ü2”ž¾ô¤KR½rî`<60>?)J }>ïØî]ÿtaº;x°B 竈ªªæ6 |>¨P¸<00>ÁwÀç7˜R ðp5]¡PCOåöù„º¯ÏÅ>Å“)Œ|DeþpŠPUIœò°I˜…d¾¦µ<C2A6>><3E><>=š|
Ql±¬Syv·K<14>*_LSÄÊÍKFýâ…gê¼!RCŸOЯ¶kµ€;â2?À¿[˜ÏϽ(Yï#Àçƒj Ð||~#€)<>®ëMeQïe™U&Ø>¿íð€‹}ú¯?õvtttww§Rûþ&áRþR:_ªªˆÌ÷ '¢Ee¾e<C2BE>åÞe>­\pw{äa™¿gT3¾ülÌ%<25>®i ïGem}¾ógL(¢Ù9:u~nû\œŸ†Ï5
 øüFS*ç­®(ŠtKÈ—ÐáAà«Ñ ²iš ÞnÁöù]ñ¤‹€Ú`ü¥Ý&H`ùšŽŽ\Ê:GÓ4“Ýe{¡KIßò(ó³¼_HZéí¢Ì7͸(¶x—ùYUýyv·?â¬Ìgüñ÷<C3B1>.étÎÚIòý¨¬­ÏO{{…~º8QÀçƒ Ð||~#€) ¿Á0 ¾œÝŠ¢è\Y×ufõ³7&Áöù„º¯ÏÅAíÝŸ1NÉd×ôôô0sˆKYo˜¦IIÆù ÕÝ”vwwÓuìèèp^Jï2?¨ï[iZ{!!o½°Þ£É§5iýòŽÁýu§Âɬ¶Ï{)뜚û|v ì§K.¡P(À•ù ø|PC p:ƒï€Ïo@€áR:ëŽ<C3AB>/·,˹Ü0ŒÀVrÛtAòùñdªgà4ûÛÝAí>ƒ‰D—²®ˆF£y=¼{ªI¥RÎKI©[Å—ù†Ñ[HæGÛ~-œ¿Î£ÌÅË:å}¿C©³”?)(£¦‹=<1B>ìÊüïÞÞÁB—Ò/<2F>¶æ>ä¢4;óW éïÀ›||>¨!P¸<00>ÁwÀç7˜R ÀHÄnÀ<6E>Åùi»Ÿ-§ûÁ¬¯p<C2AF>mšf#7]ð|~ÏÀiæ—vKÐÇ®xÒÅA5wZ>TMÓòJxZXr§|žUØ߀2?<3F>ñ™GòÊü¬¢}÷<>å¥îw÷ñ“,On;ÔbðŒK"åÑz0î󦮟߰Àçƒ Ð||~#€) 9=k9¿7Ï­Ã7M“ý—ÚØ?Òçó¹ƒR÷õ±%îe¥¬ôt(u¶gà4ûP6ykòiaîCUw4MóhòA(uã¾#ù(Þ¢ëŸ:Ú§™¯ª—±Sž9Y•¾Ÿ¿íP¿¯Û>¿æ(ŠõkÄ0 ZõÀΩÚÊ/ÎgŒ@>ø(\€Îà;àó`
ù|˲ØrºCÌýV(
’Ç.<2E>àù|giÏÀiZân¢ööÒ:ÄØ#€¡ÔY (ʆgcfÚ)ÔñTÞ‡…d~ÖkY $ÑÁäý_¿ã]æ ÂúhôÈè9¥ªG"Ñ.»ØÿÙ<C3BF>3º?åAßòuÃÂçûø|Pí~…‹Î€Îà àó`¸G.²ºÐS€†"x>?="ç)vKÐÇ®xÒE@5wZ´ÿH+c@P6š¦ ŠbV=­G,Ë¢ïŽQæÓBú¯àe¶ö*óE±Å4ãÎïÒGZÈþWw¸ì¥õ`œ¥DJ§î)Ô~
ŸïàóAµû.::ƒ/€Ïo@€áR:× 15$Bî·àóÓõù¼ ã<7F>[â^\O¦š;-ö7}
€š<10>F¹‡/
åv˲r7Â(ðÕdYR©êÇe¾,ïȪÀ7Œ^AXï\¡Ð^(%:ß`rÅ)ëÙ¨ß{ |¾/€ÏÕîWP¸è è ¾>¿À”
Æ0ŒBåš$±ÿÒuݹܲ,ܶ§êó<C3AA>Õ¤ñd*í0üycoïàÎc ö·º¯
'”TUU-¯ÞÞ#”<>EiòŒÌw®&ËrÞÕꎄ™>-º–,ïð(óUõãœUÕ/þó“Y¶ß O˜)…º?å±ûøI¿wuø|¿ÐñÉ'¿Ý³§ìèïï¯öB>ø(\€Îà;àólB¡¿ ‡Ã\=q½C+8ÅŽ,ËÁóØeHŸO8]}z´áÏ<C3A1>ÖƒñƒgøGZ
48ÌáKä¬uW«sK«ëº3<EFBFBD>…ŽÊÌWÅm}HK·6eâ÷nì]ækZ»ûwåI·[ÎKïÉÿæÂPê,øm‡ö6äEæSPõ{·‡ÏòÁ<C3B2>tߟß`J€`ã¼ wÚi˲¸<C2B2>¢?E‰D"¢(ò5«ZtZÿÕço;ÔÏ]=[â^b:”:»ñ@ŒýMßÅ€<02>¥JJ†”!)é”.*¾Sþ
•G
CÌ÷Mb<4D>é­Â°ÏßY0 —-ó-ë”(¶8Wxò™î»s
üƒgx.uÊŸðù R@>ø(\€Îà;àóx4MãêÞi§UU-¤†DQlðF ªÏw*©¡ÔYZÒvxÀEFÑú»<C3BA>ŸÌú
ð ©Tª¯¯/H )ʆ¿²äRošf÷¨ëº³ø¿(´2}%廬 ó)i.<2E>'™/ë£Ñ#Î/Fo(ôÚ¹Î_§¯úò¹ÝÍߘÍ<CB9C>KƒOüÊúÁ³g=çS À¨„ÏòÁ<C3B2>tߟß`J€FÀ²,UU%IRŹœ>æÚ¡p8Lë7xÕçÇ“)§«§%]ñ¤ŒÚv¨?÷+À/tww·Û á•InY¾ ´<>RD4­ì¾hƒ.ozöj­™¦éw™o¾ð…è+«-ëTîZÞe¾aôæ\Ó-|ñK«Œ§/´ß˜¸xœpÃ)
—´ù@ó¹Ò}J°•ðù R8åÃ¥_¹xîíw ê?èJñ«¶lɽèÆ<C3A8>ŒÓçO¾ò*ŒŽº<C5BD>1ú|4 /‚Æ |>42¦i*Še¹P<C2B9>TŸŸvT™î>~>¥Ü
MÕ}}ίl;Ô<>¾á#ººº˜9D‰¾˲¢Ñ¨Ç§–”K<>ªªçc„òpÑò¾àrN뙟´ÒÛEf×<66>§/Î_×Ôô£P赬µÆ"ó IÒÙ
ÒDÙÚtް̧ý&ݺKƒ+7[MMé%›â.i³eÛ ¶2ý»<E280BA>ŽŽß<>Jø|P)œ>áÇ€2jp²D1ÂQ†ÏG 9>%À>¿+žT÷õm<'SlɶCý.nŠÖßÛ;È?òo<C3B2>ú§¿¿¿»»ûرchŠh4ªªª,Ë¢(òÊöz80˲ò¾'UÊQE7Nç
…ü(ó­Mç‰_ZÅÍüè““ÌOgžžÄŸ¼ãVuÁÕÃ&Ÿb<C5B8>ì.óÓö£Ïž<C38F>ÓŸûüÙ/\ðw—„IñÉÎnZŸVλ<C38E>X,F£òøñãþ>ðù "ÀçC_ŸŸ<>@rê™ûü\ö6äâ¦Ú8køO žA÷õ<>iš4Š<34>?<17>%úUöNG(B©&?
E£Ñ™O!M”¹™W”ù*c—ùöGΙ|
úè MK75¥¯œ;è0<ß_ÓnUàóA¥€Ï‡2¾>><1F>ä Ô3 åóãÉ”žÚx <E28093>ëÁøîã'Ñ7@ýcšfQ+.IR­¯l“O(ŠbϧG9ö'o™Éͼ(¶ðU*#ó‰]Òð¾¶
飺÷c¤Ù ©)½r³å0'Üpªv=«ZÀçƒJñÛ={^TÕ‰5«`œÔ;[·¢72Ô=l'_y•S<E280A2>㤎=ZôÊÒ:HÈHÎ@h(ŸO4wº*ÔäáÔ<C3A1>Ah8+Š¢ëz­¸iš²,—gò[–ÏØfŽ]_õe§™·¬Sìÿ+&󉘑ÙÝ.)ó‡g ##ó¿pÁß]RedW­¼I>€2ȪwEƒPÿ8_@xQUÑ <20> @ÝÂýs¥²8*¥=ÄçïítT;<3B>%0Ä@m1 CUUMÓ<®/IR(¢ñKcY×uÓ4k{üÌä—<C3A4><E28094>é,YÏ9ª§·
ÆÓç¯ãržùJÊüråŒÏŸýpÂ%UÎY;@ëOÀçPÐGøøü ‚„  n<C2A0>ϯR{6ˆÏ?1xÆER5wZb`œ1MSÓ4EQh :S“ê·Û+:¬S( Q Ãh„+nY§B¡×¸œ×´v¶¼d¾e¥!ãó×´Å\RåEá$­¼ËŸ@@à;àóƒ
2€º>¿JíÙ >ŸØxÀÍSÅ“)Œ2Pm,Ë¢¡GƒN—Ju_œišŠ¢¸œHQ軾{x1Âá-\Î+ʇ™EI«d>Aס©)ýÅ Ýž{FvõÑ:¡ Þ#ÂçPÐGøøü ‚„  n1M3ZY<59>¥žHDÓ4þ¿¬;Ë_i¹eY<65>Üž èówK¸¨ª½½ƒe ÚH䮸iÊuu~º®<C2BA>¥ Ÿ™|JA<4A>„¹œ‡·d>'-ù¦ï—!ó5­<35>×öW
šššÒ³vKô¿´Ž¢ðÒÀçPÐGøøü ‚„ ÀwhšÆ{É=ý/³ú´¦a Þn èó{N»¨ªÖƒqŒ&Pmr58%%EQ(<28>ÕRÒu]–å±ä3h#ŸY¨ª$í/Š-MM?¢-ë”w™
½æ”ù¼ž_U?®à±ÉrÆç¯is{‰é‹ž¡uêþqS9ÀçPÐGøøü ‚„ À_XÅäýëEÑú\é£>¿Ñ|>¡îës±UC©³SÀ;ÑhT×õˆ<C3B5>ûÃDŽa$ɲÌÞòÅiVJã³lãñ±ÏÕÌÿ¨ÏÉÈütZžûS/2·É©px ÿ¯Hä£
XÊ0ZÂßvI<76>kÚbMMiQ ìX†Ï T <54>ððùA €¿PU•Ý€kšæñ+¦i²¯D"FnºÆôùm‡\„Õþφ0¦üE,ëèèèîîN¥RUÝå ¦îeY¦!“+·iI<69>–Η²«$IMÍýù…óR
…øwé0ÖoßøáKeÈ|VÞÏBÖ;öÇΙhtóóoº¤ÇÙ'ššÒ^nýÇmTVø|ÊúߟT<><54>ø ®J*¶geŸbP ½Ñ˜>¿+žtõcLùŽŽŽvD"Q½½8]Ÿ ~oLÊ¢¬ßéÒÇmÐKM>¿”mmmÎÇ%”¨ö.•ñî3c”ùâ—VO_<4F>îTÇr»<>Ÿ¤Œwbð ûO¦\r#Å/<C}ÜÃkpã4*«7Æ4™P:ÐGøøü ‚„ À_„Ãá2nÀËûVÀhŸ?”:»·w<C2B7>ÕÞÓß.ÂJÝׇ1å/zzz˜9L&“¹ÿkšfÔFUÕÈaŠ¢”4Xò"Š¢$Iº®û±©‰4M“e™=å¬,´ÿµéîî¦ëøÔSOeUõLæ[í[„ó×<C3B3>Qæ[ÎK·6¥wŸº)²¤×Ü9ܼ;<3B>%\rãÊÍÖ?N<ÙÕGwÅ“^.eGGGÞQYŸÀçPÐGøøü ‚„ À_p3ïݼú´®q|~ÛᦤööÒÇm‡ú]´UQUª<>eYÑœBž>:×O$…d¾³Ì»Y[Ë mŠ% Qi¼Ð1ÐñÐKJ;õ9<>$I^Ú§ ´ýR§¯¯oÉ%Y<>‚Ö¹iâ—VUFæSü^)û@6ˆeù|u_ŸKb|èñ¿<þîpæl=wßx*•*4*ëyPÀçP*ÐGøøü ‚„ À_(ŠÂnÀ#‘ˆÇ¯˜¦É¾
5ôLÇ}¾ eT,³Æ»â}SYUÓ¹¨žpjšÍãïþši¨çö˜ôñ»?Þ⢭Ú°íœ<Óz0N#…1 ÃãQÑšQW¼ËO^s>öM9<4D>*ï zqݯ ÇÎàQÂ{iy§ s1Ï>uò%Aç¨ë:°MÕ„¶O°Œ#¤ šõ‚€êë{Ìù<4E>'Ý^1™¿§ü‡¼8Ÿ½¸ä\]}Ñw?¼1Ÿ@@à;àóƒ
2¡ë:÷r^ŸeYÜ°ø³¸Ï/¯bÙ,­ì¦¼\_Z'÷‹n¸ƒ¨/\ð.æJÝ×Ç6Õz0ÎÐ×]ŽÊ‹ Î{Tå‰e/ºÛ㦼•ÇÿÎàeSÎÁ
…ø“øü<C3B8>E€e><3E>š¦it²üu¤êA]Žv4Æt>h ­•÷P .HZéíbÆ·ïýÞSÌИ^’Ì·‡Ã‘ŠË|¢¹ÓbÉmã<6D>¼ñÝ£Ná7^àó(è#||~PABà;¸­*j<>è†ÝYÚu¹.¸øüq¶Á7UvIöç>ÿ?¸‰š¾t -yâW†¼:1x&íðù ž³~u}nª<C2AA>Á²¬¼þÙù‰÷÷><1A>ñtø ʨ´Gºjc<rIø½¿öR<C3B6>솕{«C 'LãÙŠÊ|AXo½£GVoÅe~ÏÀé¬â|ç¼ñî«âù°¹Óòãe))"“àè#||~PABà; ÃpV,‡B!EQTU<54>Ž i-qš|Bmø0ÜçSEx—iº®G\ñ¢‚t<>Ü7Eûò~^ányŸÉ¨5m ööºÈ«<C388>Ç´ç:_¿zr8ŲeY\W¶æqSY=y,rm¶ìôrý-i뺈4ʨyéR}q£²ŸRh‰Ò¦è,|Ÿ<C5B8>êçd¾£>ß|sŠpþº¢>_×?ÍݤñáÑïüS¥d~Úñ¤’ç·pɇo:|¸÷ïY<C3AF>|>e}€ï€Ï*HÈüˆa%Õ£Bæ§>ߣþõ5]ñ¤³üžÂÅ_1ͯ°€‰F£”ÁdY.úd§þ5~ HZé­Â°u§?#­Ô©†ÿeYQ™‰|”³|<E280BA>ùÎRüÝÇOÒ¡ÔY÷âüWßèu>ܤõƒ:¬àó(è#||~PABàS,ËŠD"E+TC¡<43>÷¢ñ`ÓP>ŸP÷õ9Ëï7ˆ¹(¬ž<C2AC>Ó´Ns§Å>n;Ô<>jE >AIU$MÓ ñ°K:'Þ;UË:e½é„];¡¨Ì—$½àf+'óÓŽâ|ʇÌÌï>~Ò%®iuV#dBø|ÊúߟT<><54>ø˲4MË_ápXQ˜|'<27>æóÛ8ËïwK¸X,Z™Öi„ªTP‡ÔVàó´@)Â0 \OÕω÷]e<E28099>„õQÿ ¥hq¾(¶Ðú·|HK

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
oフ厠?フOフテフhファフユフ>フフ猯變ケフ侘ヤフEフsフ領採4フ厠体「フ6フフリフ賣\フフ5フェフイフ蔑mフフ摸醂コフ慘ルファフフ﨓﨓摸<>mフ<6D>ホフオフGフ<47>Oフロフ フテフ<EFBE83>ホフ<EFBE8E><EFBE8C>;フ販<EFBE8C>フ栂モフタフラフ,フムフ「フ睥Aフ9フサフ賣のツフsフ<73>フシフンフフュフeフ<65>ンフUフuフ﨓アフヒフwフ<77>蔑Dプフ粁スフtフ槊」フケフ<EFBDB9><EFBE8C>Oフ閒﨓<E99692>pフGフ<47>ーフタフ(フフ、フ{フ椴゚フ<EFBE9F>ユフ<>フMフ#フ變﨓オフdフキフIプフhフ_フpフJフヌフ「フホフフoフ⇔<EFBE8C>チフ;フ<フ侘ZフネフムフoフWフ<57>ソフ}フ睥フ:フ睥ァフ蔑サフeフFフtフ(フEフoフ猯pフフ「フ(フ;フ<><EFBFBD><EFBE8C>!フケフケフノフフ慘閒ヨフ4フネフ3フ<33>粁Bフ捨ニフuフPフ6フ椴<EFBE8C>フ&フヲフウフ蔑チフ<EFBE81>サフフTフタファフbフフメフユフ<EFBE95>{フニフ。フハフNフ9フヌフフBフム

View File

@ -0,0 +1,140 @@
#![forbid(unsafe_code)]
use crate::deflate::{
Value, DIST_CODE_LEN, D_CODES, LENGTH_CODES, L_CODES, STD_MAX_MATCH, STD_MIN_MATCH,
};
const fn h(freq: u16, code: u16) -> Value {
Value::new(freq, code)
}
#[rustfmt::skip]
pub const STATIC_LTREE: [Value; L_CODES + 2] = [
h( 12,8), h(140,8), h( 76,8), h(204,8), h( 44,8),
h(172,8), h(108,8), h(236,8), h( 28,8), h(156,8),
h( 92,8), h(220,8), h( 60,8), h(188,8), h(124,8),
h(252,8), h( 2,8), h(130,8), h( 66,8), h(194,8),
h( 34,8), h(162,8), h( 98,8), h(226,8), h( 18,8),
h(146,8), h( 82,8), h(210,8), h( 50,8), h(178,8),
h(114,8), h(242,8), h( 10,8), h(138,8), h( 74,8),
h(202,8), h( 42,8), h(170,8), h(106,8), h(234,8),
h( 26,8), h(154,8), h( 90,8), h(218,8), h( 58,8),
h(186,8), h(122,8), h(250,8), h( 6,8), h(134,8),
h( 70,8), h(198,8), h( 38,8), h(166,8), h(102,8),
h(230,8), h( 22,8), h(150,8), h( 86,8), h(214,8),
h( 54,8), h(182,8), h(118,8), h(246,8), h( 14,8),
h(142,8), h( 78,8), h(206,8), h( 46,8), h(174,8),
h(110,8), h(238,8), h( 30,8), h(158,8), h( 94,8),
h(222,8), h( 62,8), h(190,8), h(126,8), h(254,8),
h( 1,8), h(129,8), h( 65,8), h(193,8), h( 33,8),
h(161,8), h( 97,8), h(225,8), h( 17,8), h(145,8),
h( 81,8), h(209,8), h( 49,8), h(177,8), h(113,8),
h(241,8), h( 9,8), h(137,8), h( 73,8), h(201,8),
h( 41,8), h(169,8), h(105,8), h(233,8), h( 25,8),
h(153,8), h( 89,8), h(217,8), h( 57,8), h(185,8),
h(121,8), h(249,8), h( 5,8), h(133,8), h( 69,8),
h(197,8), h( 37,8), h(165,8), h(101,8), h(229,8),
h( 21,8), h(149,8), h( 85,8), h(213,8), h( 53,8),
h(181,8), h(117,8), h(245,8), h( 13,8), h(141,8),
h( 77,8), h(205,8), h( 45,8), h(173,8), h(109,8),
h(237,8), h( 29,8), h(157,8), h( 93,8), h(221,8),
h( 61,8), h(189,8), h(125,8), h(253,8), h( 19,9),
h(275,9), h(147,9), h(403,9), h( 83,9), h(339,9),
h(211,9), h(467,9), h( 51,9), h(307,9), h(179,9),
h(435,9), h(115,9), h(371,9), h(243,9), h(499,9),
h( 11,9), h(267,9), h(139,9), h(395,9), h( 75,9),
h(331,9), h(203,9), h(459,9), h( 43,9), h(299,9),
h(171,9), h(427,9), h(107,9), h(363,9), h(235,9),
h(491,9), h( 27,9), h(283,9), h(155,9), h(411,9),
h( 91,9), h(347,9), h(219,9), h(475,9), h( 59,9),
h(315,9), h(187,9), h(443,9), h(123,9), h(379,9),
h(251,9), h(507,9), h( 7,9), h(263,9), h(135,9),
h(391,9), h( 71,9), h(327,9), h(199,9), h(455,9),
h( 39,9), h(295,9), h(167,9), h(423,9), h(103,9),
h(359,9), h(231,9), h(487,9), h( 23,9), h(279,9),
h(151,9), h(407,9), h( 87,9), h(343,9), h(215,9),
h(471,9), h( 55,9), h(311,9), h(183,9), h(439,9),
h(119,9), h(375,9), h(247,9), h(503,9), h( 15,9),
h(271,9), h(143,9), h(399,9), h( 79,9), h(335,9),
h(207,9), h(463,9), h( 47,9), h(303,9), h(175,9),
h(431,9), h(111,9), h(367,9), h(239,9), h(495,9),
h( 31,9), h(287,9), h(159,9), h(415,9), h( 95,9),
h(351,9), h(223,9), h(479,9), h( 63,9), h(319,9),
h(191,9), h(447,9), h(127,9), h(383,9), h(255,9),
h(511,9), h( 0,7), h( 64,7), h( 32,7), h( 96,7),
h( 16,7), h( 80,7), h( 48,7), h(112,7), h( 8,7),
h( 72,7), h( 40,7), h(104,7), h( 24,7), h( 88,7),
h( 56,7), h(120,7), h( 4,7), h( 68,7), h( 36,7),
h(100,7), h( 20,7), h( 84,7), h( 52,7), h(116,7),
h( 3,8), h(131,8), h( 67,8), h(195,8), h( 35,8),
h(163,8), h( 99,8), h(227,8)
];
#[rustfmt::skip]
pub const STATIC_DTREE: [Value; D_CODES] = [
h( 0,5), h(16,5), h( 8,5), h(24,5), h( 4,5),
h(20,5), h(12,5), h(28,5), h( 2,5), h(18,5),
h(10,5), h(26,5), h( 6,5), h(22,5), h(14,5),
h(30,5), h( 1,5), h(17,5), h( 9,5), h(25,5),
h( 5,5), h(21,5), h(13,5), h(29,5), h( 3,5),
h(19,5), h(11,5), h(27,5), h( 7,5), h(23,5)
];
#[rustfmt::skip]
pub const DIST_CODE: [u8; DIST_CODE_LEN] = [
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
];
#[rustfmt::skip]
pub const LENGTH_CODE: [u8; STD_MAX_MATCH-STD_MIN_MATCH+1] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
];
pub const BASE_LENGTH: [u8; LENGTH_CODES] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128,
160, 192, 224, 0,
];
#[rustfmt::skip]
pub const BASE_DIST: [u16; D_CODES] = [
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
];

View File

@ -0,0 +1,146 @@
use crate::allocate::Allocator;
use core::mem::MaybeUninit;
#[derive(Debug)]
pub struct Window<'a> {
// the full window allocation. This is longer than w_size so that operations don't need to
// perform bounds checks.
buf: &'a mut [MaybeUninit<u8>],
// number of initialized bytes
filled: usize,
window_bits: usize,
high_water: usize,
}
impl<'a> Window<'a> {
pub fn new_in(alloc: &Allocator<'a>, window_bits: usize) -> Option<Self> {
let buf = alloc.allocate_slice::<u8>(2 * ((1 << window_bits) + Self::padding()))?;
Some(Self {
buf,
filled: 0,
window_bits,
high_water: 0,
})
}
pub fn clone_in(&self, alloc: &Allocator<'a>) -> Option<Self> {
let mut clone = Self::new_in(alloc, self.window_bits)?;
clone.buf.copy_from_slice(self.buf);
clone.filled = self.filled;
clone.high_water = self.high_water;
Some(clone)
}
pub unsafe fn drop_in(&mut self, alloc: &Allocator) {
if !self.buf.is_empty() {
let buf = core::mem::take(&mut self.buf);
alloc.deallocate(buf.as_mut_ptr(), buf.len());
}
}
pub fn capacity(&self) -> usize {
2 * (1 << self.window_bits)
}
/// Returns a shared reference to the filled portion of the buffer.
#[inline]
pub fn filled(&self) -> &[u8] {
// safety: `self.buf` has been initialized for at least `filled` elements
unsafe { core::slice::from_raw_parts(self.buf.as_ptr().cast(), self.filled) }
}
/// Returns a mutable reference to the filled portion of the buffer.
#[inline]
pub fn filled_mut(&mut self) -> &mut [u8] {
// safety: `self.buf` has been initialized for at least `filled` elements
unsafe { core::slice::from_raw_parts_mut(self.buf.as_mut_ptr().cast(), self.filled) }
}
/// # Safety
///
/// `src` must point to `range.end - range.start` valid (initialized!) bytes
pub unsafe fn copy_and_initialize(&mut self, range: core::ops::Range<usize>, src: *const u8) {
let (start, end) = (range.start, range.end);
let dst = self.buf[range].as_mut_ptr() as *mut u8;
core::ptr::copy_nonoverlapping(src, dst, end - start);
if start >= self.filled {
self.filled = Ord::max(self.filled, end);
}
self.high_water = Ord::max(self.high_water, self.filled);
}
// this library has many functions that operated in a chunked fashion on memory. For
// performance, we want to minimize bounds checks. Therefore we reserve initialize some extra
// memory at the end of the window so that chunked operations can use the whole buffer. If they
// go slightly over `self.capacity` that's okay, we account for that here by making sure the
// memory there is initialized!
pub fn initialize_out_of_bounds(&mut self) {
const WIN_INIT: usize = crate::deflate::STD_MAX_MATCH;
// If the WIN_INIT bytes after the end of the current data have never been
// written, then zero those bytes in order to avoid memory check reports of
// the use of uninitialized (or uninitialised as Julian writes) bytes by
// the longest match routines. Update the high water mark for the next
// time through here. WIN_INIT is set to STD_MAX_MATCH since the longest match
// routines allow scanning to strstart + STD_MAX_MATCH, ignoring lookahead.
if self.high_water < self.capacity() {
let curr = self.filled().len();
if self.high_water < curr {
// Previous high water mark below current data -- zero WIN_INIT
// bytes or up to end of window, whichever is less.
let init = Ord::min(self.capacity() - curr, WIN_INIT);
self.buf[curr..][..init].fill(MaybeUninit::new(0));
self.high_water = curr + init;
self.filled += init;
} else if self.high_water < curr + WIN_INIT {
// High water mark at or above current data, but below current data
// plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
// to end of window, whichever is less.
let init = Ord::min(
curr + WIN_INIT - self.high_water,
self.capacity() - self.high_water,
);
self.buf[self.high_water..][..init].fill(MaybeUninit::new(0));
self.high_water += init;
self.filled += init;
}
}
}
pub fn initialize_at_least(&mut self, at_least: usize) {
let end = at_least.clamp(self.high_water, self.buf.len());
self.buf[self.high_water..end].fill(MaybeUninit::new(0));
self.high_water = end;
self.filled = end;
}
// padding required so that SIMD operations going out-of-bounds are not a problem
pub fn padding() -> usize {
#[cfg(feature = "std")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
if std::is_x86_feature_detected!("pclmulqdq")
&& std::is_x86_feature_detected!("sse2")
&& std::is_x86_feature_detected!("sse4.1")
{
return 8;
}
0
}
}

2284
third_party/rust/zlib-rs/src/inflate.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,203 @@
use core::marker::PhantomData;
use crate::ReturnCode;
#[derive(Debug, Clone, Copy)]
pub(crate) struct BitReader<'a> {
ptr: *const u8,
end: *const u8,
bit_buffer: u64,
bits_used: u8,
_marker: PhantomData<&'a [u8]>,
}
impl<'a> BitReader<'a> {
pub fn new(slice: &'a [u8]) -> Self {
let range = slice.as_ptr_range();
Self {
ptr: range.start,
end: range.end,
bit_buffer: 0,
bits_used: 0,
_marker: PhantomData,
}
}
#[inline(always)]
pub fn update_slice(&mut self, slice: &[u8]) {
let range = slice.as_ptr_range();
*self = Self {
ptr: range.start,
end: range.end,
bit_buffer: self.bit_buffer,
bits_used: self.bits_used,
_marker: PhantomData,
};
}
#[inline(always)]
pub fn advance(&mut self, bytes: usize) {
self.ptr = Ord::min(unsafe { self.ptr.add(bytes) }, self.end);
}
#[inline(always)]
pub fn as_ptr(&self) -> *const u8 {
self.ptr
}
#[inline(always)]
pub fn as_slice(&self) -> &[u8] {
let len = self.bytes_remaining();
unsafe { core::slice::from_raw_parts(self.ptr, len) }
}
#[inline(always)]
pub fn bits_in_buffer(&self) -> u8 {
self.bits_used
}
#[inline(always)]
pub fn hold(&self) -> u64 {
self.bit_buffer
}
#[inline(always)]
pub fn bytes_remaining(&self) -> usize {
self.end as usize - self.ptr as usize
}
#[inline(always)]
pub fn need_bits(&mut self, n: usize) -> Result<(), ReturnCode> {
while (self.bits_used as usize) < n {
self.pull_byte()?;
}
Ok(())
}
/// Remove zero to seven bits as needed to go to a byte boundary
#[inline(always)]
pub fn next_byte_boundary(&mut self) {
self.bit_buffer >>= self.bits_used & 0b0111;
self.bits_used -= self.bits_used & 0b0111;
}
#[inline(always)]
pub fn pull_byte(&mut self) -> Result<u8, ReturnCode> {
if self.ptr == self.end {
return Err(ReturnCode::Ok);
}
let byte = unsafe { *self.ptr };
self.ptr = unsafe { self.ptr.add(1) };
self.bit_buffer |= (byte as u64) << self.bits_used;
self.bits_used += 8;
Ok(byte)
}
#[inline(always)]
pub fn refill(&mut self) {
debug_assert!(self.bytes_remaining() >= 8);
let read = unsafe { core::ptr::read_unaligned(self.ptr.cast::<u64>()) };
self.bit_buffer |= read << self.bits_used;
let increment = (63 - self.bits_used) >> 3;
self.ptr = self.ptr.wrapping_add(increment as usize);
self.bits_used |= 56;
}
#[inline(always)]
pub fn refill_and<T>(&mut self, f: impl Fn(u64) -> T) -> T {
debug_assert!(self.bytes_remaining() >= 8);
// the trick of this function is that the read can happen concurrently
// with the arithmetic below. That makes the read effectively free.
let read = unsafe { core::ptr::read_unaligned(self.ptr.cast::<u64>()) };
let next_bit_buffer = self.bit_buffer | read << self.bits_used;
let increment = (63 - self.bits_used) >> 3;
self.ptr = self.ptr.wrapping_add(increment as usize);
self.bits_used |= 56;
let result = f(self.bit_buffer);
self.bit_buffer = next_bit_buffer;
result
}
#[inline(always)]
pub fn bits(&mut self, n: usize) -> u64 {
// debug_assert!( n <= self.bits_used, "{n} bits requested, but only {} avaliable", self.bits_used);
let lowest_n_bits = (1 << n) - 1;
self.bit_buffer & lowest_n_bits
}
#[inline(always)]
pub fn drop_bits(&mut self, n: usize) {
self.bit_buffer >>= n;
self.bits_used -= n as u8;
}
#[inline(always)]
pub fn start_sync_search(&mut self) -> ([u8; 4], usize) {
let mut buf = [0u8; 4];
self.bit_buffer <<= self.bits_used & 7;
self.bits_used -= self.bits_used & 7;
let mut len = 0;
while self.bits_used >= 8 {
buf[len] = self.bit_buffer as u8;
len += 1;
self.bit_buffer >>= 8;
self.bits_used -= 8;
}
(buf, len)
}
#[inline(always)]
pub fn init_bits(&mut self) {
self.bit_buffer = 0;
self.bits_used = 0;
}
#[inline(always)]
pub fn prime(&mut self, bits: u8, value: u64) {
let value = value & ((1 << bits) - 1);
self.bit_buffer += value << self.bits_used;
self.bits_used += bits;
}
#[inline(always)]
pub fn return_unused_bytes(&mut self) {
let len = self.bits_used >> 3;
self.ptr = unsafe { self.ptr.sub(len as usize) };
self.bits_used -= len << 3;
self.bit_buffer &= (1u64 << self.bits_used) - 1u64;
assert!(self.bits_used <= 32);
}
}
#[cfg(feature = "std")]
impl std::io::Read for BitReader<'_> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
assert_eq!(self.bits_used, 0, "bit buffer not cleared before read");
let number_of_bytes = Ord::min(buf.len(), self.bytes_remaining());
// safety: `buf` is a mutable (exclusive) reference, so it cannot overlap the memory that
// the reader contains
unsafe { core::ptr::copy_nonoverlapping(self.ptr, buf.as_mut_ptr(), number_of_bytes) }
self.ptr = unsafe { self.ptr.add(number_of_bytes) };
Ok(number_of_bytes)
}
}

View File

@ -0,0 +1,555 @@
use crate::Code;
const fn code(op: u8, bits: u8, val: u16) -> Code {
Code { op, bits, val }
}
pub(crate) const LENFIX: [Code; 512] = [
code(96, 7, 0),
code(0, 8, 80),
code(0, 8, 16),
code(20, 8, 115),
code(18, 7, 31),
code(0, 8, 112),
code(0, 8, 48),
code(0, 9, 192),
code(16, 7, 10),
code(0, 8, 96),
code(0, 8, 32),
code(0, 9, 160),
code(0, 8, 0),
code(0, 8, 128),
code(0, 8, 64),
code(0, 9, 224),
code(16, 7, 6),
code(0, 8, 88),
code(0, 8, 24),
code(0, 9, 144),
code(19, 7, 59),
code(0, 8, 120),
code(0, 8, 56),
code(0, 9, 208),
code(17, 7, 17),
code(0, 8, 104),
code(0, 8, 40),
code(0, 9, 176),
code(0, 8, 8),
code(0, 8, 136),
code(0, 8, 72),
code(0, 9, 240),
code(16, 7, 4),
code(0, 8, 84),
code(0, 8, 20),
code(21, 8, 227),
code(19, 7, 43),
code(0, 8, 116),
code(0, 8, 52),
code(0, 9, 200),
code(17, 7, 13),
code(0, 8, 100),
code(0, 8, 36),
code(0, 9, 168),
code(0, 8, 4),
code(0, 8, 132),
code(0, 8, 68),
code(0, 9, 232),
code(16, 7, 8),
code(0, 8, 92),
code(0, 8, 28),
code(0, 9, 152),
code(20, 7, 83),
code(0, 8, 124),
code(0, 8, 60),
code(0, 9, 216),
code(18, 7, 23),
code(0, 8, 108),
code(0, 8, 44),
code(0, 9, 184),
code(0, 8, 12),
code(0, 8, 140),
code(0, 8, 76),
code(0, 9, 248),
code(16, 7, 3),
code(0, 8, 82),
code(0, 8, 18),
code(21, 8, 163),
code(19, 7, 35),
code(0, 8, 114),
code(0, 8, 50),
code(0, 9, 196),
code(17, 7, 11),
code(0, 8, 98),
code(0, 8, 34),
code(0, 9, 164),
code(0, 8, 2),
code(0, 8, 130),
code(0, 8, 66),
code(0, 9, 228),
code(16, 7, 7),
code(0, 8, 90),
code(0, 8, 26),
code(0, 9, 148),
code(20, 7, 67),
code(0, 8, 122),
code(0, 8, 58),
code(0, 9, 212),
code(18, 7, 19),
code(0, 8, 106),
code(0, 8, 42),
code(0, 9, 180),
code(0, 8, 10),
code(0, 8, 138),
code(0, 8, 74),
code(0, 9, 244),
code(16, 7, 5),
code(0, 8, 86),
code(0, 8, 22),
code(64, 8, 0),
code(19, 7, 51),
code(0, 8, 118),
code(0, 8, 54),
code(0, 9, 204),
code(17, 7, 15),
code(0, 8, 102),
code(0, 8, 38),
code(0, 9, 172),
code(0, 8, 6),
code(0, 8, 134),
code(0, 8, 70),
code(0, 9, 236),
code(16, 7, 9),
code(0, 8, 94),
code(0, 8, 30),
code(0, 9, 156),
code(20, 7, 99),
code(0, 8, 126),
code(0, 8, 62),
code(0, 9, 220),
code(18, 7, 27),
code(0, 8, 110),
code(0, 8, 46),
code(0, 9, 188),
code(0, 8, 14),
code(0, 8, 142),
code(0, 8, 78),
code(0, 9, 252),
code(96, 7, 0),
code(0, 8, 81),
code(0, 8, 17),
code(21, 8, 131),
code(18, 7, 31),
code(0, 8, 113),
code(0, 8, 49),
code(0, 9, 194),
code(16, 7, 10),
code(0, 8, 97),
code(0, 8, 33),
code(0, 9, 162),
code(0, 8, 1),
code(0, 8, 129),
code(0, 8, 65),
code(0, 9, 226),
code(16, 7, 6),
code(0, 8, 89),
code(0, 8, 25),
code(0, 9, 146),
code(19, 7, 59),
code(0, 8, 121),
code(0, 8, 57),
code(0, 9, 210),
code(17, 7, 17),
code(0, 8, 105),
code(0, 8, 41),
code(0, 9, 178),
code(0, 8, 9),
code(0, 8, 137),
code(0, 8, 73),
code(0, 9, 242),
code(16, 7, 4),
code(0, 8, 85),
code(0, 8, 21),
code(16, 8, 258),
code(19, 7, 43),
code(0, 8, 117),
code(0, 8, 53),
code(0, 9, 202),
code(17, 7, 13),
code(0, 8, 101),
code(0, 8, 37),
code(0, 9, 170),
code(0, 8, 5),
code(0, 8, 133),
code(0, 8, 69),
code(0, 9, 234),
code(16, 7, 8),
code(0, 8, 93),
code(0, 8, 29),
code(0, 9, 154),
code(20, 7, 83),
code(0, 8, 125),
code(0, 8, 61),
code(0, 9, 218),
code(18, 7, 23),
code(0, 8, 109),
code(0, 8, 45),
code(0, 9, 186),
code(0, 8, 13),
code(0, 8, 141),
code(0, 8, 77),
code(0, 9, 250),
code(16, 7, 3),
code(0, 8, 83),
code(0, 8, 19),
code(21, 8, 195),
code(19, 7, 35),
code(0, 8, 115),
code(0, 8, 51),
code(0, 9, 198),
code(17, 7, 11),
code(0, 8, 99),
code(0, 8, 35),
code(0, 9, 166),
code(0, 8, 3),
code(0, 8, 131),
code(0, 8, 67),
code(0, 9, 230),
code(16, 7, 7),
code(0, 8, 91),
code(0, 8, 27),
code(0, 9, 150),
code(20, 7, 67),
code(0, 8, 123),
code(0, 8, 59),
code(0, 9, 214),
code(18, 7, 19),
code(0, 8, 107),
code(0, 8, 43),
code(0, 9, 182),
code(0, 8, 11),
code(0, 8, 139),
code(0, 8, 75),
code(0, 9, 246),
code(16, 7, 5),
code(0, 8, 87),
code(0, 8, 23),
code(64, 8, 0),
code(19, 7, 51),
code(0, 8, 119),
code(0, 8, 55),
code(0, 9, 206),
code(17, 7, 15),
code(0, 8, 103),
code(0, 8, 39),
code(0, 9, 174),
code(0, 8, 7),
code(0, 8, 135),
code(0, 8, 71),
code(0, 9, 238),
code(16, 7, 9),
code(0, 8, 95),
code(0, 8, 31),
code(0, 9, 158),
code(20, 7, 99),
code(0, 8, 127),
code(0, 8, 63),
code(0, 9, 222),
code(18, 7, 27),
code(0, 8, 111),
code(0, 8, 47),
code(0, 9, 190),
code(0, 8, 15),
code(0, 8, 143),
code(0, 8, 79),
code(0, 9, 254),
code(96, 7, 0),
code(0, 8, 80),
code(0, 8, 16),
code(20, 8, 115),
code(18, 7, 31),
code(0, 8, 112),
code(0, 8, 48),
code(0, 9, 193),
code(16, 7, 10),
code(0, 8, 96),
code(0, 8, 32),
code(0, 9, 161),
code(0, 8, 0),
code(0, 8, 128),
code(0, 8, 64),
code(0, 9, 225),
code(16, 7, 6),
code(0, 8, 88),
code(0, 8, 24),
code(0, 9, 145),
code(19, 7, 59),
code(0, 8, 120),
code(0, 8, 56),
code(0, 9, 209),
code(17, 7, 17),
code(0, 8, 104),
code(0, 8, 40),
code(0, 9, 177),
code(0, 8, 8),
code(0, 8, 136),
code(0, 8, 72),
code(0, 9, 241),
code(16, 7, 4),
code(0, 8, 84),
code(0, 8, 20),
code(21, 8, 227),
code(19, 7, 43),
code(0, 8, 116),
code(0, 8, 52),
code(0, 9, 201),
code(17, 7, 13),
code(0, 8, 100),
code(0, 8, 36),
code(0, 9, 169),
code(0, 8, 4),
code(0, 8, 132),
code(0, 8, 68),
code(0, 9, 233),
code(16, 7, 8),
code(0, 8, 92),
code(0, 8, 28),
code(0, 9, 153),
code(20, 7, 83),
code(0, 8, 124),
code(0, 8, 60),
code(0, 9, 217),
code(18, 7, 23),
code(0, 8, 108),
code(0, 8, 44),
code(0, 9, 185),
code(0, 8, 12),
code(0, 8, 140),
code(0, 8, 76),
code(0, 9, 249),
code(16, 7, 3),
code(0, 8, 82),
code(0, 8, 18),
code(21, 8, 163),
code(19, 7, 35),
code(0, 8, 114),
code(0, 8, 50),
code(0, 9, 197),
code(17, 7, 11),
code(0, 8, 98),
code(0, 8, 34),
code(0, 9, 165),
code(0, 8, 2),
code(0, 8, 130),
code(0, 8, 66),
code(0, 9, 229),
code(16, 7, 7),
code(0, 8, 90),
code(0, 8, 26),
code(0, 9, 149),
code(20, 7, 67),
code(0, 8, 122),
code(0, 8, 58),
code(0, 9, 213),
code(18, 7, 19),
code(0, 8, 106),
code(0, 8, 42),
code(0, 9, 181),
code(0, 8, 10),
code(0, 8, 138),
code(0, 8, 74),
code(0, 9, 245),
code(16, 7, 5),
code(0, 8, 86),
code(0, 8, 22),
code(64, 8, 0),
code(19, 7, 51),
code(0, 8, 118),
code(0, 8, 54),
code(0, 9, 205),
code(17, 7, 15),
code(0, 8, 102),
code(0, 8, 38),
code(0, 9, 173),
code(0, 8, 6),
code(0, 8, 134),
code(0, 8, 70),
code(0, 9, 237),
code(16, 7, 9),
code(0, 8, 94),
code(0, 8, 30),
code(0, 9, 157),
code(20, 7, 99),
code(0, 8, 126),
code(0, 8, 62),
code(0, 9, 221),
code(18, 7, 27),
code(0, 8, 110),
code(0, 8, 46),
code(0, 9, 189),
code(0, 8, 14),
code(0, 8, 142),
code(0, 8, 78),
code(0, 9, 253),
code(96, 7, 0),
code(0, 8, 81),
code(0, 8, 17),
code(21, 8, 131),
code(18, 7, 31),
code(0, 8, 113),
code(0, 8, 49),
code(0, 9, 195),
code(16, 7, 10),
code(0, 8, 97),
code(0, 8, 33),
code(0, 9, 163),
code(0, 8, 1),
code(0, 8, 129),
code(0, 8, 65),
code(0, 9, 227),
code(16, 7, 6),
code(0, 8, 89),
code(0, 8, 25),
code(0, 9, 147),
code(19, 7, 59),
code(0, 8, 121),
code(0, 8, 57),
code(0, 9, 211),
code(17, 7, 17),
code(0, 8, 105),
code(0, 8, 41),
code(0, 9, 179),
code(0, 8, 9),
code(0, 8, 137),
code(0, 8, 73),
code(0, 9, 243),
code(16, 7, 4),
code(0, 8, 85),
code(0, 8, 21),
code(16, 8, 258),
code(19, 7, 43),
code(0, 8, 117),
code(0, 8, 53),
code(0, 9, 203),
code(17, 7, 13),
code(0, 8, 101),
code(0, 8, 37),
code(0, 9, 171),
code(0, 8, 5),
code(0, 8, 133),
code(0, 8, 69),
code(0, 9, 235),
code(16, 7, 8),
code(0, 8, 93),
code(0, 8, 29),
code(0, 9, 155),
code(20, 7, 83),
code(0, 8, 125),
code(0, 8, 61),
code(0, 9, 219),
code(18, 7, 23),
code(0, 8, 109),
code(0, 8, 45),
code(0, 9, 187),
code(0, 8, 13),
code(0, 8, 141),
code(0, 8, 77),
code(0, 9, 251),
code(16, 7, 3),
code(0, 8, 83),
code(0, 8, 19),
code(21, 8, 195),
code(19, 7, 35),
code(0, 8, 115),
code(0, 8, 51),
code(0, 9, 199),
code(17, 7, 11),
code(0, 8, 99),
code(0, 8, 35),
code(0, 9, 167),
code(0, 8, 3),
code(0, 8, 131),
code(0, 8, 67),
code(0, 9, 231),
code(16, 7, 7),
code(0, 8, 91),
code(0, 8, 27),
code(0, 9, 151),
code(20, 7, 67),
code(0, 8, 123),
code(0, 8, 59),
code(0, 9, 215),
code(18, 7, 19),
code(0, 8, 107),
code(0, 8, 43),
code(0, 9, 183),
code(0, 8, 11),
code(0, 8, 139),
code(0, 8, 75),
code(0, 9, 247),
code(16, 7, 5),
code(0, 8, 87),
code(0, 8, 23),
code(64, 8, 0),
code(19, 7, 51),
code(0, 8, 119),
code(0, 8, 55),
code(0, 9, 207),
code(17, 7, 15),
code(0, 8, 103),
code(0, 8, 39),
code(0, 9, 175),
code(0, 8, 7),
code(0, 8, 135),
code(0, 8, 71),
code(0, 9, 239),
code(16, 7, 9),
code(0, 8, 95),
code(0, 8, 31),
code(0, 9, 159),
code(20, 7, 99),
code(0, 8, 127),
code(0, 8, 63),
code(0, 9, 223),
code(18, 7, 27),
code(0, 8, 111),
code(0, 8, 47),
code(0, 9, 191),
code(0, 8, 15),
code(0, 8, 143),
code(0, 8, 79),
code(0, 9, 255),
];
pub(crate) const DISTFIX: [Code; 32] = [
code(16, 5, 1),
code(23, 5, 257),
code(19, 5, 17),
code(27, 5, 4097),
code(17, 5, 5),
code(25, 5, 1025),
code(21, 5, 65),
code(29, 5, 16385),
code(16, 5, 3),
code(24, 5, 513),
code(20, 5, 33),
code(28, 5, 8193),
code(18, 5, 9),
code(26, 5, 2049),
code(22, 5, 129),
code(64, 5, 0),
code(16, 5, 2),
code(23, 5, 385),
code(19, 5, 25),
code(27, 5, 6145),
code(17, 5, 7),
code(25, 5, 1537),
code(21, 5, 97),
code(29, 5, 24577),
code(16, 5, 4),
code(24, 5, 769),
code(20, 5, 49),
code(28, 5, 12289),
code(18, 5, 13),
code(26, 5, 3073),
code(22, 5, 193),
code(64, 5, 0),
];

View File

@ -0,0 +1,358 @@
#![forbid(unsafe_code)]
use crate::{Code, ENOUGH_DISTS, ENOUGH_LENS};
pub(crate) enum CodeType {
Codes,
Lens,
Dists,
}
const MAX_BITS: usize = 15;
fn min_max<const N: usize>(count: [u16; N]) -> (usize, usize) {
let mut max = MAX_BITS;
while max >= 1 {
if count[max] != 0 {
break;
}
max -= 1;
}
let mut min = 1;
while min < max {
if count[min] != 0 {
break;
}
min += 1;
}
(min, max)
}
/// Length codes 257..285 base
const LBASE: [u16; 31] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
163, 195, 227, 258, 0, 0,
];
/// Length codes 257..285 extra
const LEXT: [u16; 31] = [
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
21, 21, 21, 21, 16, 77, 202,
];
/// Distance codes 0..29 base
const DBASE: [u16; 32] = [
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0,
];
/// Distance codes 0..29 extra
const DEXT: [u16; 32] = [
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26,
27, 27, 28, 28, 29, 29, 64, 64,
];
#[repr(i32)]
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum InflateTable {
EnoughIsNotEnough = 1,
Success(usize) = 0,
InvalidCode = -1,
}
pub(crate) fn inflate_table(
codetype: CodeType,
lens: &[u16],
codes: usize,
table: &mut [Code],
bits: usize,
work: &mut [u16],
) -> InflateTable {
// number of codes of each length
let mut count = [0u16; MAX_BITS + 1];
for len in lens[0..codes].iter().copied() {
count[len as usize] += 1;
}
let mut root = bits;
let (min, max) = min_max(count);
root = Ord::min(root, max);
root = Ord::max(root, min);
if max == 0 {
// no symbols to code at all
let code = Code {
op: 64,
bits: 1,
val: 0,
};
table[0] = code;
table[1] = code;
return InflateTable::Success(1);
}
/* check for an over-subscribed or incomplete set of lengths */
let mut left = 1i32;
let mut len = 1;
while len <= MAX_BITS {
left <<= 1;
left -= count[len] as i32;
if left < 0 {
// over-subscribed
return InflateTable::InvalidCode;
}
len += 1;
}
if left > 0 && (matches!(codetype, CodeType::Codes) || max != 1) {
// incomplete set
return InflateTable::InvalidCode;
}
/* generate offsets into symbol table for each length for sorting */
// offsets in table for each length
let mut offs = [0u16; MAX_BITS + 1];
for len in 1..MAX_BITS {
offs[len + 1] = offs[len] + count[len];
}
/* sort symbols by length, by symbol order within each length */
for (sym, len) in lens[0..codes].iter().copied().enumerate() {
if len != 0 {
let offset = offs[len as usize];
offs[len as usize] += 1;
work[offset as usize] = sym as u16;
}
}
let (base, extra, match_) = match codetype {
CodeType::Codes => (&[] as &[_], &[] as &[_], 20),
CodeType::Lens => (&LBASE[..], &LEXT[..], 257),
CodeType::Dists => (&DBASE[..], &DEXT[..], 0),
};
let used = 1 << root;
/* check available table space */
if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS {
return InflateTable::EnoughIsNotEnough;
}
if matches!(codetype, CodeType::Dists) && used > ENOUGH_DISTS {
return InflateTable::EnoughIsNotEnough;
}
let mut huff = 0; // starting code
let mut reversed_huff = 0u32; // starting code, reversed
let mut sym = 0;
let mut len = min;
let mut next = 0usize; // index into `table`
let mut curr = root;
let mut drop_ = 0;
let mut low = usize::MAX; // trigger new subtable when len > root
let mut used = 1 << root;
let mask = used - 1; /* mask for comparing low */
// process all codes and make table entries
'outer: loop {
// create table entry
let here = if work[sym] >= match_ {
Code {
bits: (len - drop_) as u8,
op: extra[(work[sym] - match_) as usize] as u8,
val: base[(work[sym] - match_) as usize],
}
} else if work[sym] + 1 < match_ {
Code {
bits: (len - drop_) as u8,
op: 0,
val: work[sym],
}
} else {
Code {
bits: (len - drop_) as u8,
op: 0b01100000,
val: 0,
}
};
// replicate for those indices with low len bits equal to huff
let incr = 1 << (len - drop_);
let min = 1 << curr; // also has the name 'fill' in the C code
let base = &mut table[next + (huff >> drop_)..];
for fill in (0..min).step_by(incr) {
base[fill] = here;
}
// backwards increment the len-bit code huff
reversed_huff = reversed_huff.wrapping_add(0x80000000u32 >> (len - 1));
huff = reversed_huff.reverse_bits() as usize;
// go to next symbol, update count, len
sym += 1;
count[len] -= 1;
if count[len] == 0 {
if len == max {
break 'outer;
}
len = lens[work[sym] as usize] as usize;
}
// create new sub-table if needed
if len > root && (huff & mask) != low {
/* if first time, transition to sub-tables */
if drop_ == 0 {
drop_ = root;
}
/* increment past last table */
next += min; /* here min is 1 << curr */
/* determine length of next table */
curr = len - drop_;
let mut left = 1 << curr;
while curr + drop_ < max {
left -= count[curr + drop_] as i32;
if left <= 0 {
break;
}
curr += 1;
left <<= 1;
}
/* check for enough space */
used += 1usize << curr;
if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS {
return InflateTable::EnoughIsNotEnough;
}
if matches!(codetype, CodeType::Dists) && used > ENOUGH_DISTS {
return InflateTable::EnoughIsNotEnough;
}
/* point entry in root table to sub-table */
low = huff & mask;
table[low] = Code {
op: curr as u8,
bits: root as u8,
val: next as u16,
};
}
}
/* fill in remaining table entry if code is incomplete (guaranteed to have
at most one remaining entry, since if the code is incomplete, the
maximum code length that was allowed to get this far is one bit) */
if huff != 0 {
let here = Code {
op: 64,
bits: (len - drop_) as u8,
val: 0,
};
table[next..][huff] = here;
}
/* set return parameters */
InflateTable::Success(root)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn not_enough_errors() {
// we need to call inflate_table() directly in order to manifest
// not-enough errors, since zlib insures that enough is always enough
let table = [Code::default(); crate::ENOUGH_DISTS];
let mut work = [0; 16];
let mut lens: [_; 16] = core::array::from_fn(|i| (i + 1) as u16);
lens[15] = 15;
let mut next = table;
let bits = 15;
let ret = inflate_table(CodeType::Dists, &lens, 16, &mut next, bits, &mut work);
assert_eq!(ret, InflateTable::EnoughIsNotEnough);
let mut next = table;
let bits = 1;
let ret = inflate_table(CodeType::Dists, &lens, 16, &mut next, bits, &mut work);
assert_eq!(ret, InflateTable::EnoughIsNotEnough);
}
fn build_fixed_length_table(work: &mut [u16]) -> [Code; 512] {
let mut lens = [0; 288];
// literal/length table
let mut sym = 0usize;
while sym < 144 {
lens[sym] = 8;
sym += 1;
}
while sym < 256 {
lens[sym] = 9;
sym += 1;
}
while sym < 280 {
lens[sym] = 7;
sym += 1;
}
while sym < 288 {
lens[sym] = 8;
sym += 1;
}
let mut next = [Code::default(); 512];
let bits = 9;
inflate_table(CodeType::Lens, &lens, 288, &mut next, bits, work);
core::array::from_fn(|i| {
let mut code = next[i];
code.op = if i & 0b0111_1111 == 99 { 64 } else { code.op };
code
})
}
#[test]
fn generate_fixed_length_table() {
let mut work = [0; 512];
let generated = build_fixed_length_table(&mut work);
assert_eq!(generated, crate::inflate::inffixed_tbl::LENFIX);
}
fn build_fixed_distance_table(work: &mut [u16]) -> [Code; 32] {
let mut lens = [0; 288];
let mut sym = 0;
while sym < 32 {
lens[sym] = 5;
sym += 1;
}
let mut next = [Code::default(); 32];
let bits = 5;
inflate_table(CodeType::Dists, &lens, 32, &mut next, bits, work);
next
}
#[test]
fn generate_fixed_distance_table() {
let mut work = [0; 512];
let generated = build_fixed_distance_table(&mut work);
assert_eq!(generated, crate::inflate::inffixed_tbl::DISTFIX);
}
}

View File

@ -0,0 +1,267 @@
use crate::{
adler32::{adler32, adler32_fold_copy},
allocate::Allocator,
crc32::Crc32Fold,
};
use core::mem::MaybeUninit;
// translation guide:
//
// wsize -> buf.capacity()
// wnext -> buf.ptr
// whave -> buf.filled.len()
#[derive(Debug)]
pub struct Window<'a> {
buf: &'a mut [MaybeUninit<u8>],
have: usize, // number of bytes logically written to the window. this can be higher than
// buf.len() if we run out of space in the window
next: usize, // write head
}
impl<'a> Window<'a> {
pub fn into_inner(self) -> &'a mut [MaybeUninit<u8>] {
self.buf
}
pub fn is_empty(&self) -> bool {
self.size() == 0
}
pub fn size(&self) -> usize {
if self.buf.is_empty() {
// an empty `buf` is used when the window has not yet been allocated,
// or when it has been deallocated.
0
} else {
self.buf.len() - Self::padding()
}
}
/// number of bytes in the window. Saturates at `Self::capacity`.
pub fn have(&self) -> usize {
self.have
}
/// Position where the next byte will be written
pub fn next(&self) -> usize {
self.next
}
pub fn empty() -> Self {
Self {
buf: &mut [],
have: 0,
next: 0,
}
}
pub fn clear(&mut self) {
self.have = 0;
self.next = 0;
}
pub fn as_slice(&self) -> &[u8] {
// safety: the slice is always from the initialized part of buf
unsafe { slice_assume_init(&self.buf[..self.have]) }
}
#[cfg(test)]
fn extend_adler32(&mut self, slice: &[u8], checksum: &mut u32) {
self.extend(slice, 0, true, checksum, &mut Crc32Fold::new());
}
pub fn extend(
&mut self,
slice: &[u8],
flags: i32,
update_checksum: bool,
checksum: &mut u32,
crc_fold: &mut Crc32Fold,
) {
let len = slice.len();
let wsize = self.size();
if len >= wsize {
// We have to split the checksum over non-copied and copied bytes
let pos = len.saturating_sub(self.size());
let (non_window_slice, window_slice) = slice.split_at(pos);
if update_checksum {
if flags != 0 {
crc_fold.fold(non_window_slice, 0);
crc_fold.fold_copy(&mut self.buf[..wsize], window_slice);
} else {
*checksum = adler32(*checksum, non_window_slice);
*checksum = adler32_fold_copy(*checksum, self.buf, window_slice);
}
} else {
self.buf[..wsize].copy_from_slice(unsafe { slice_to_uninit(window_slice) });
}
self.next = 0;
self.have = self.size();
} else {
let dist = Ord::min(wsize - self.next, slice.len());
// the end part goes onto the end of the window. The start part wraps around and is
// written to the start of the window.
let (end_part, start_part) = slice.split_at(dist);
if update_checksum {
let dst = &mut self.buf[self.next..][..end_part.len()];
if flags != 0 {
crc_fold.fold_copy(dst, end_part);
} else {
*checksum = adler32_fold_copy(*checksum, dst, end_part);
}
} else {
let end_part = unsafe { slice_to_uninit(end_part) };
self.buf[self.next..][..end_part.len()].copy_from_slice(end_part);
}
if !start_part.is_empty() {
if update_checksum {
let dst = &mut self.buf[..start_part.len()];
if flags != 0 {
crc_fold.fold_copy(dst, start_part);
} else {
*checksum = adler32_fold_copy(*checksum, dst, start_part);
}
} else {
let start_part = unsafe { slice_to_uninit(start_part) };
self.buf[..start_part.len()].copy_from_slice(start_part);
}
self.next = start_part.len();
self.have = self.size();
} else {
self.next += dist;
if self.next == self.size() {
self.next = 0;
}
if self.have < self.size() {
self.have += dist;
}
}
}
}
pub fn new_in(alloc: &Allocator<'a>, window_bits: usize) -> Option<Self> {
let buf = alloc.allocate_slice::<u8>((1 << window_bits) + Self::padding())?;
Some(Self {
buf,
have: 0,
next: 0,
})
}
pub fn clone_in(&self, alloc: &Allocator<'a>) -> Option<Self> {
let buf = alloc.allocate_slice::<u8>(self.buf.len())?;
Some(Self {
buf,
have: self.have,
next: self.next,
})
}
// padding required so that SIMD operations going out-of-bounds are not a problem
pub fn padding() -> usize {
64 // very conservative
}
}
unsafe fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit<u8>] {
&*(slice as *const [u8] as *const [MaybeUninit<u8>])
}
// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable.
unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
&*(slice as *const [MaybeUninit<u8>] as *const [u8])
}
#[cfg(test)]
mod test {
use super::*;
use crate::allocate::Allocator;
fn init_window(window_bits_log2: usize) -> Window<'static> {
let mut window = Window::new_in(&Allocator::RUST, window_bits_log2).unwrap();
window.buf.fill(MaybeUninit::new(0));
window.have = 0;
window.next = 0;
window
}
#[test]
fn extend_in_bounds() {
let mut checksum = 0;
let mut window = init_window(4);
window.extend_adler32(&[1; 5], &mut checksum);
assert_eq!(window.have, 5);
assert_eq!(window.next, 5);
let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) };
assert_eq!(&[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], slice);
window.extend_adler32(&[2; 7], &mut checksum);
assert_eq!(window.have, 12);
assert_eq!(window.next, 12);
let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) };
assert_eq!(&[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0], slice);
assert_eq!(checksum, 6946835);
unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) }
}
#[test]
fn extend_crosses_bounds() {
let mut checksum = 0;
let mut window = init_window(2);
window.extend_adler32(&[1; 3], &mut checksum);
assert_eq!(window.have, 3);
assert_eq!(window.next, 3);
let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) };
assert_eq!(&[1, 1, 1, 0], slice);
window.extend_adler32(&[2; 3], &mut checksum);
assert_eq!(window.have, 4);
assert_eq!(window.next, 2);
let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) };
assert_eq!(&[2, 2, 1, 2], slice);
assert_eq!(checksum, 1769481);
unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) }
}
#[test]
fn extend_out_of_bounds() {
let mut checksum = 0;
let mut window = init_window(3);
// adds 9 numbers, that won't fit into a window of size 8
window.extend_adler32(&[1, 2, 3, 4, 5, 6, 7, 8, 9], &mut checksum);
assert_eq!(window.have, 8);
assert_eq!(window.next, 0);
let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) };
assert_eq!(&[2, 3, 4, 5, 6, 7, 8, 9], slice);
assert_eq!(checksum, 10813485);
unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) }
}
}

193
third_party/rust/zlib-rs/src/lib.rs vendored Normal file
View File

@ -0,0 +1,193 @@
#![doc = core::include_str!("../README.md")]
#![cfg_attr(not(any(test, feature = "rust-allocator")), no_std)]
#[cfg(any(feature = "rust-allocator", feature = "c-allocator"))]
extern crate alloc;
mod adler32;
pub mod allocate;
pub mod c_api;
pub mod crc32;
pub mod deflate;
pub mod inflate;
pub mod read_buf;
pub use adler32::{adler32, adler32_combine};
pub use crc32::{crc32, crc32_combine};
#[macro_export]
macro_rules! trace {
($($arg:tt)*) => {
// eprint!($($arg)*)
};
}
/// Maximum size of the dynamic table. The maximum number of code structures is
/// 1924, which is the sum of 1332 for literal/length codes and 592 for distance
/// codes. These values were found by exhaustive searches using the program
/// examples/enough.c found in the zlib distributions. The arguments to that
/// program are the number of symbols, the initial root table size, and the
/// maximum bit length of a code. "enough 286 10 15" for literal/length codes
/// returns 1332, and "enough 30 9 15" for distance codes returns 592.
/// The initial root table size (10 or 9) is found in the fifth argument of the
/// inflate_table() calls in inflate.c and infback.c. If the root table size is
/// changed, then these maximum sizes would be need to be recalculated and
/// updated.
#[allow(unused)]
pub(crate) const ENOUGH: usize = ENOUGH_LENS + ENOUGH_DISTS;
pub(crate) const ENOUGH_LENS: usize = 1332;
pub(crate) const ENOUGH_DISTS: usize = 592;
/// initial adler-32 hash value
pub(crate) const ADLER32_INITIAL_VALUE: usize = 1;
/// initial crc-32 hash value
pub(crate) const CRC32_INITIAL_VALUE: u32 = 0;
pub const MIN_WBITS: i32 = 8; // 256b LZ77 window
pub const MAX_WBITS: i32 = 15; // 32kb LZ77 window
pub(crate) const DEF_WBITS: i32 = MAX_WBITS;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DeflateFlush {
#[default]
/// if flush is set to `NoFlush`, that allows deflate to decide how much data
/// to accumulate before producing output, in order to maximize compression.
NoFlush = 0,
/// If flush is set to `PartialFlush`, all pending output is flushed to the
/// output buffer, but the output is not aligned to a byte boundary. All of the
/// input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
/// This completes the current deflate block and follows it with an empty fixed
/// codes block that is 10 bits long. This assures that enough bytes are output
/// in order for the decompressor to finish the block before the empty fixed
/// codes block.
PartialFlush = 1,
/// If the parameter flush is set to `SyncFlush`, all pending output is
/// flushed to the output buffer and the output is aligned on a byte boundary, so
/// that the decompressor can get all input data available so far. (In
/// particular avail_in is zero after the call if enough output space has been
/// provided before the call.) Flushing may degrade compression for some
/// compression algorithms and so it should be used only when necessary. This
/// completes the current deflate block and follows it with an empty stored block
/// that is three bits plus filler bits to the next byte, followed by four bytes
/// (00 00 ff ff).
SyncFlush = 2,
/// If flush is set to `FullFlush`, all output is flushed as with
/// Z_SYNC_FLUSH, and the compression state is reset so that decompression can
/// restart from this point if previous compressed data has been damaged or if
/// random access is desired. Using `FullFlush` too often can seriously degrade
/// compression.
FullFlush = 3,
/// If the parameter flush is set to `Finish`, pending input is processed,
/// pending output is flushed and deflate returns with `StreamEnd` if there was
/// enough output space. If deflate returns with `Ok` or `BufError`, this
/// function must be called again with `Finish` and more output space (updated
/// avail_out) but no more input data, until it returns with `StreamEnd` or an
/// error. After deflate has returned `StreamEnd`, the only possible operations
/// on the stream are deflateReset or deflateEnd.
///
/// `Finish` can be used in the first deflate call after deflateInit if all the
/// compression is to be done in a single step. In order to complete in one
/// call, avail_out must be at least the value returned by deflateBound (see
/// below). Then deflate is guaranteed to return `StreamEnd`. If not enough
/// output space is provided, deflate will not return `StreamEnd`, and it must
/// be called again as described above.
Finish = 4,
/// If flush is set to `Block`, a deflate block is completed and emitted, as
/// for `SyncFlush`, but the output is not aligned on a byte boundary, and up to
/// seven bits of the current block are held to be written as the next byte after
/// the next deflate block is completed. In this case, the decompressor may not
/// be provided enough bits at this point in order to complete decompression of
/// the data provided so far to the compressor. It may need to wait for the next
/// block to be emitted. This is for advanced applications that need to control
/// the emission of deflate blocks.
Block = 5,
}
impl TryFrom<i32> for DeflateFlush {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::NoFlush),
1 => Ok(Self::PartialFlush),
2 => Ok(Self::SyncFlush),
3 => Ok(Self::FullFlush),
4 => Ok(Self::Finish),
5 => Ok(Self::Block),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum InflateFlush {
#[default]
NoFlush = 0,
SyncFlush = 2,
Finish = 4,
Block = 5,
Trees = 6,
}
impl TryFrom<i32> for InflateFlush {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::NoFlush),
2 => Ok(Self::SyncFlush),
4 => Ok(Self::Finish),
5 => Ok(Self::Block),
6 => Ok(Self::Trees),
_ => Err(()),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Code {
/// operation, extra bits, table bits
pub op: u8,
/// bits in this part of the code
pub bits: u8,
/// offset in table or code value
pub val: u16,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(i32)]
pub enum ReturnCode {
Ok = 0,
StreamEnd = 1,
NeedDict = 2,
ErrNo = -1,
StreamError = -2,
DataError = -3,
MemError = -4,
BufError = -5,
VersionError = -6,
}
impl From<i32> for ReturnCode {
fn from(value: i32) -> Self {
use ReturnCode::*;
match value {
0 => Ok,
1 => StreamEnd,
2 => NeedDict,
-1 => ErrNo,
-2 => StreamError,
-3 => DataError,
-4 => MemError,
-5 => BufError,
-6 => VersionError,
_ => panic!("invalid return code {value}"),
}
}
}

553
third_party/rust/zlib-rs/src/read_buf.rs vendored Normal file
View File

@ -0,0 +1,553 @@
#![allow(unused)]
// taken from https://docs.rs/tokio/latest/src/tokio/io/read_buf.rs.html#23-27
// based on https://rust-lang.github.io/rfcs/2930-read-buf.html
use core::fmt;
use core::mem::MaybeUninit;
use crate::allocate::Allocator;
/// A wrapper around a byte buffer that is incrementally filled and initialized.
///
/// This type is a sort of "double cursor". It tracks three regions in the
/// buffer: a region at the beginning of the buffer that has been logically
/// filled with data, a region that has been initialized at some point but not
/// yet logically filled, and a region at the end that may be uninitialized.
/// The filled region is guaranteed to be a subset of the initialized region.
///
/// In summary, the contents of the buffer can be visualized as:
///
/// ```not_rust
/// [ capacity ]
/// [ filled | unfilled ]
/// [ initialized | uninitialized ]
/// ```
///
/// It is undefined behavior to de-initialize any bytes from the uninitialized
/// region, since it is merely unknown whether this region is uninitialized or
/// not, and if part of it turns out to be initialized, it must stay initialized.
pub struct ReadBuf<'a> {
buf: &'a mut [MaybeUninit<u8>],
filled: usize,
initialized: usize,
}
impl<'a> ReadBuf<'a> {
/// Creates a new `ReadBuf` from a fully initialized buffer.
#[inline]
pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
let initialized = buf.len();
let buf = unsafe { slice_to_uninit_mut(buf) };
ReadBuf {
buf,
filled: 0,
initialized,
}
}
/// # Safety
///
/// The `ptr` and `len` must for a valid `&mut [MaybeUninit<u8>]`
pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize) -> Self {
let buf = core::slice::from_raw_parts_mut(ptr as _, len);
Self {
buf,
filled: 0,
initialized: 0,
}
}
/// Pointer to where the next byte will be written
#[inline]
pub fn next_out(&mut self) -> *mut MaybeUninit<u8> {
self.buf[self.filled..].as_mut_ptr()
}
/// Pointer to the start of the `ReadBuf`
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut MaybeUninit<u8> {
self.buf.as_mut_ptr()
}
/// Creates a new `ReadBuf` from a fully uninitialized buffer.
///
/// Use `assume_init` if part of the buffer is known to be already initialized.
#[inline]
pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
ReadBuf {
buf,
filled: 0,
initialized: 0,
}
}
/// Returns the total capacity of the buffer.
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
/// Returns the length of the filled part of the buffer
#[inline]
pub fn len(&self) -> usize {
self.filled
}
/// Returns true if there are no bytes in this ReadBuf
#[inline]
pub fn is_empty(&self) -> bool {
self.filled == 0
}
/// Returns a shared reference to the filled portion of the buffer.
#[inline]
pub fn filled(&self) -> &[u8] {
let slice = &self.buf[..self.filled];
// safety: filled describes how far into the buffer that the
// user has filled with bytes, so it's been initialized.
unsafe { slice_assume_init(slice) }
}
/// Returns a mutable reference to the filled portion of the buffer.
#[inline]
pub fn filled_mut(&mut self) -> &mut [u8] {
let slice = &mut self.buf[..self.filled];
// safety: filled describes how far into the buffer that the
// user has filled with bytes, so it's been initialized.
unsafe { slice_assume_init_mut(slice) }
}
/// Returns a new `ReadBuf` comprised of the unfilled section up to `n`.
#[inline]
pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
let max = core::cmp::min(self.remaining(), n);
// Safety: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`.
unsafe { ReadBuf::uninit(&mut self.unfilled_mut()[..max]) }
}
/// Returns a shared reference to the initialized portion of the buffer.
///
/// This includes the filled portion.
#[inline]
pub fn initialized(&self) -> &[u8] {
let slice = &self.buf[..self.initialized];
// safety: initialized describes how far into the buffer that the
// user has at some point initialized with bytes.
unsafe { slice_assume_init(slice) }
}
/// Returns a mutable reference to the initialized portion of the buffer.
///
/// This includes the filled portion.
#[inline]
pub fn initialized_mut(&mut self) -> &mut [u8] {
let slice = &mut self.buf[..self.initialized];
// safety: initialized describes how far into the buffer that the
// user has at some point initialized with bytes.
unsafe { slice_assume_init_mut(slice) }
}
/// Returns a mutable reference to the entire buffer, without ensuring that it has been fully
/// initialized.
///
/// The elements between 0 and `self.len()` are filled, and those between 0 and
/// `self.initialized().len()` are initialized (and so can be converted to a `&mut [u8]`).
///
/// The caller of this method must ensure that these invariants are upheld. For example, if the
/// caller initializes some of the uninitialized section of the buffer, it must call
/// [`assume_init`](Self::assume_init) with the number of bytes initialized.
///
/// # Safety
///
/// The caller must not de-initialize portions of the buffer that have already been initialized.
/// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
#[inline]
pub unsafe fn inner_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.buf
}
/// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
/// initialized.
///
/// # Safety
///
/// The caller must not de-initialize portions of the buffer that have already been initialized.
/// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
#[inline]
pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf[self.filled..]
}
/// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
///
/// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
/// the first use.
#[inline]
pub fn initialize_unfilled(&mut self) -> &mut [u8] {
self.initialize_unfilled_to(self.remaining())
}
/// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
/// fully initialized.
///
/// # Panics
///
/// Panics if `self.remaining()` is less than `n`.
#[inline]
#[track_caller]
pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
assert!(self.remaining() >= n, "n overflows remaining");
// This can't overflow, otherwise the assert above would have failed.
let end = self.filled + n;
if self.initialized < end {
unsafe {
self.buf[self.initialized..end]
.as_mut_ptr()
.write_bytes(0, end - self.initialized);
}
self.initialized = end;
}
let slice = &mut self.buf[self.filled..end];
// safety: just above, we checked that the end of the buf has
// been initialized to some value.
unsafe { slice_assume_init_mut(slice) }
}
/// Returns the number of bytes at the end of the slice that have not yet been filled.
#[inline]
pub fn remaining(&self) -> usize {
self.capacity() - self.filled
}
/// Clears the buffer, resetting the filled region to empty.
///
/// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
#[inline]
pub fn clear(&mut self) {
self.filled = 0;
}
/// Advances the size of the filled region of the buffer.
///
/// The number of initialized bytes is not changed.
///
/// # Panics
///
/// Panics if the filled region of the buffer would become larger than the initialized region.
#[inline]
#[track_caller]
pub fn advance(&mut self, n: usize) {
let new = self.filled.checked_add(n).expect("filled overflow");
self.set_filled(new);
}
/// Sets the size of the filled region of the buffer.
///
/// The number of initialized bytes is not changed.
///
/// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
/// example, by a `AsyncRead` implementation that compresses data in-place).
///
/// # Panics
///
/// Panics if the filled region of the buffer would become larger than the initialized region.
#[inline]
#[track_caller]
pub fn set_filled(&mut self, n: usize) {
assert!(
n <= self.initialized,
"filled must not become larger than initialized"
);
self.filled = n;
}
/// Asserts that the first `n` unfilled bytes of the buffer are initialized.
///
/// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
/// bytes than are already known to be initialized.
///
/// # Safety
///
/// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized.
#[inline]
pub unsafe fn assume_init(&mut self, n: usize) {
let new = self.filled + n;
if new > self.initialized {
self.initialized = new;
}
}
#[track_caller]
pub fn push(&mut self, byte: u8) {
assert!(
self.remaining() >= 1,
"read_buf is full ({} bytes)",
self.capacity()
);
self.buf[self.filled] = MaybeUninit::new(byte);
self.initialized = Ord::max(self.initialized, self.filled + 1);
self.filled += 1;
}
/// Appends data to the buffer, advancing the written position and possibly also the initialized position.
///
/// # Panics
///
/// Panics if `self.remaining()` is less than `buf.len()`.
#[inline(always)]
#[track_caller]
pub fn extend(&mut self, buf: &[u8]) {
assert!(
self.remaining() >= buf.len(),
"buf.len() must fit in remaining()"
);
// using simd here (on x86_64) was not fruitful
self.buf[self.filled..][..buf.len()].copy_from_slice(slice_to_uninit(buf));
let end = self.filled + buf.len();
self.initialized = Ord::max(self.initialized, end);
self.filled = end;
}
#[inline(always)]
pub fn copy_match(&mut self, offset_from_end: usize, length: usize) {
let current = self.filled;
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("avx512f") {
return self.copy_match_help::<core::arch::x86_64::__m512i>(offset_from_end, length);
}
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("avx2") {
return self.copy_match_help::<core::arch::x86_64::__m256i>(offset_from_end, length);
}
#[cfg(all(target_arch = "x86_64", feature = "std"))]
if std::is_x86_feature_detected!("sse") {
return self.copy_match_help::<core::arch::x86_64::__m128i>(offset_from_end, length);
}
self.copy_match_help::<u64>(offset_from_end, length)
}
fn copy_match_help<C: Chunk>(&mut self, offset_from_end: usize, length: usize) {
let current = self.filled;
let start = current.checked_sub(offset_from_end).expect("in bounds");
let end = start.checked_add(length).expect("in bounds");
// Note also that the referenced string may overlap the current
// position; for example, if the last 2 bytes decoded have values
// X and Y, a string reference with <length = 5, distance = 2>
// adds X,Y,X,Y,X to the output stream.
if end > current {
if offset_from_end == 1 {
// this will just repeat this value many times
let element = self.buf[current - 1];
self.buf[current..][..length].fill(element);
} else {
for i in 0..length {
self.buf[current + i] = self.buf[start + i];
}
}
} else {
Self::copy_chunked_within::<C>(self.buf, current, start, end)
}
// safety: we just copied length initialized bytes right beyond self.filled
unsafe { self.assume_init(length) };
self.advance(length);
}
#[inline(always)]
fn copy_chunked_within<C: Chunk>(
buf: &mut [MaybeUninit<u8>],
current: usize,
start: usize,
end: usize,
) {
if (end - start).next_multiple_of(core::mem::size_of::<C>()) <= (buf.len() - current) {
unsafe {
Self::copy_chunk_unchecked::<C>(
buf.as_ptr().add(start),
buf.as_mut_ptr().add(current),
buf.as_ptr().add(end),
)
}
} else {
// a full simd copy does not fit in the output buffer
buf.copy_within(start..end, current);
}
}
/// # Safety
///
/// `src` must be safe to perform unaligned reads in `core::mem::size_of::<C>()` chunks until
/// `end` is reached. `dst` must be safe to (unalingned) write that number of chunks.
#[inline(always)]
unsafe fn copy_chunk_unchecked<C: Chunk>(
mut src: *const MaybeUninit<u8>,
mut dst: *mut MaybeUninit<u8>,
end: *const MaybeUninit<u8>,
) {
while src < end {
let chunk = C::load_chunk(src);
C::store_chunk(dst, chunk);
src = src.add(core::mem::size_of::<C>());
dst = dst.add(core::mem::size_of::<C>());
}
}
pub(crate) fn new_in(alloc: &Allocator<'a>, len: usize) -> Option<Self> {
let buf = alloc.allocate_slice::<u8>(len)?;
Some(Self {
buf,
filled: 0,
initialized: 0,
})
}
pub(crate) fn clone_in(&self, alloc: &Allocator<'a>) -> Option<Self> {
let mut clone = Self::new_in(alloc, self.buf.len())?;
clone.buf.copy_from_slice(self.buf);
clone.filled = self.filled;
clone.initialized = self.initialized;
Some(clone)
}
pub(crate) unsafe fn drop_in(&mut self, alloc: &Allocator<'a>) {
if !self.buf.is_empty() {
let buf = core::mem::take(&mut self.buf);
alloc.deallocate(buf.as_mut_ptr(), buf.len());
}
}
}
#[cfg(feature = "std")]
impl std::io::Write for ReadBuf<'_> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
if self.remaining() < buf.len() {
const MSG: &str = "failed to write whole buffer";
return Err(std::io::Error::new(std::io::ErrorKind::WriteZero, MSG));
}
self.extend(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
/* do nothing */
Ok(())
}
}
impl fmt::Debug for ReadBuf<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReadBuf")
.field("filled", &self.filled)
.field("initialized", &self.initialized)
.field("capacity", &self.capacity())
.finish()
}
}
fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit<u8>] {
unsafe { &*(slice as *const [u8] as *const [MaybeUninit<u8>]) }
}
unsafe fn slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit<u8>] {
&mut *(slice as *mut [u8] as *mut [MaybeUninit<u8>])
}
// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable.
unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
&*(slice as *const [MaybeUninit<u8>] as *const [u8])
}
// TODO: This could use `MaybeUninit::slice_assume_init_mut` when it is stable.
unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
&mut *(slice as *mut [MaybeUninit<u8>] as *mut [u8])
}
trait Chunk {
/// Safety: must be valid to read a `Self::Chunk` value from `from` with an unaligned read.
unsafe fn load_chunk(from: *const MaybeUninit<u8>) -> Self;
/// Safety: must be valid to write a `Self::Chunk` value to `out` with an unaligned write.
unsafe fn store_chunk(out: *mut MaybeUninit<u8>, chunk: Self);
}
impl Chunk for u64 {
unsafe fn load_chunk(from: *const MaybeUninit<u8>) -> Self {
core::ptr::read_unaligned(from.cast())
}
unsafe fn store_chunk(out: *mut MaybeUninit<u8>, chunk: Self) {
core::ptr::copy_nonoverlapping(
chunk.to_ne_bytes().as_ptr().cast(),
out,
core::mem::size_of::<Self>(),
)
}
}
#[cfg(target_arch = "x86_64")]
impl Chunk for core::arch::x86_64::__m128i {
#[inline(always)]
unsafe fn load_chunk(from: *const MaybeUninit<u8>) -> Self {
core::arch::x86_64::_mm_loadu_si128(from.cast())
}
#[inline(always)]
unsafe fn store_chunk(out: *mut MaybeUninit<u8>, chunk: Self) {
core::arch::x86_64::_mm_storeu_si128(out as *mut Self, chunk);
}
}
#[cfg(target_arch = "x86_64")]
impl Chunk for core::arch::x86_64::__m256i {
#[inline(always)]
unsafe fn load_chunk(from: *const MaybeUninit<u8>) -> Self {
core::arch::x86_64::_mm256_loadu_si256(from.cast())
}
#[inline(always)]
unsafe fn store_chunk(out: *mut MaybeUninit<u8>, chunk: Self) {
core::arch::x86_64::_mm256_storeu_si256(out as *mut Self, chunk);
}
}
#[cfg(target_arch = "x86_64")]
impl Chunk for core::arch::x86_64::__m512i {
#[inline(always)]
unsafe fn load_chunk(from: *const MaybeUninit<u8>) -> Self {
// TODO AVX-512 is effectively unstable.
// We cross our fingers that LLVM optimizes this into a vmovdqu32
//
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_loadu_si512&expand=3420&ig_expand=4110
core::ptr::read_unaligned(from.cast())
}
#[inline(always)]
unsafe fn store_chunk(out: *mut MaybeUninit<u8>, chunk: Self) {
// TODO AVX-512 is effectively unstable.
// We cross our fingers that LLVM optimizes this into a vmovdqu32
//
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_storeu_si512&expand=3420&ig_expand=4110,6550
core::ptr::write_unaligned(out.cast(), chunk)
}
}

View File

@ -157,9 +157,13 @@ USE_LIBS += [
"nss",
"psshparser",
"sqlite",
"zlib",
]
if not CONFIG["USE_LIBZ_RS"]:
USE_LIBS += [
"zlib",
]
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
# The mozgtk library is a workaround that makes Gtk+ use libwayland-client
# instead of mozwayland. The reason it works is that by being a dependency

View File

@ -86,5 +86,8 @@ if CONFIG["MOZ_ICU4X"]:
if CONFIG["JS_HAS_TEMPORAL_API"]:
gkrust_features += ["icu4x_calendar"]
if CONFIG["USE_LIBZ_RS"]:
gkrust_features += ["libz-rs-sys"]
# This must remain last.
gkrust_features = ["gkrust-shared/%s" % f for f in gkrust_features]

View File

@ -113,6 +113,8 @@ url = "2.5.0"
# Since we're building with at least rustc 1.63, enable rust 1.57 features (use of try_reserve methods).
fallible_collections = { version = "0.4", features = ["rust_1_57"] }
libz-rs-sys = { git = "https://github.com/memorysafety/zlib-rs", rev = "692b0fd5a367cf4714b0b24e9e498e2a064d673c", features = ["custom-prefix"], optional = true }
[target.'cfg(not(target_os = "android"))'.dependencies]
viaduct = "0.1"
webext_storage_bridge = { path = "../../../components/extensions/storage/webext_storage_bridge" }

View File

@ -126,6 +126,9 @@ extern crate oblivious_http;
extern crate mime_guess_ffi;
#[cfg(feature = "libz-rs-sys")]
extern crate libz_rs_sys;
#[cfg(feature = "uniffi_fixtures")]
mod uniffi_fixtures {
extern crate arithmetical;