From dfd779c9ec89fb78c7a34400c6210c301b43f20d Mon Sep 17 00:00:00 2001 From: meilier Date: Mon, 8 Aug 2022 11:10:35 +0800 Subject: [PATCH 1/2] patch structure init with integration test --- VERSION-openeuler | 1 + WasmEngine.spec | 25 +- apply-patches | 38 + gen-version.sh | 91 + git-commit | 1 + patch/.gitkeep | 0 patch/0001-add-experiments-to-tar.patch | 667 + ...2-add-another_json_minimal-to-vendor.patch | 1871 ++ ...0003-remove-unused-code-and-comments.patch | 116 + ...pull_wasm-return-result-do-not-panic.patch | 56 + ...d-pull-public-https-repository-image.patch | 65 + ...-args-for-consistent-wasm-function-i.patch | 83 + ...integration-test-init-for-wasmengine.patch | 23659 ++++++++++++++++ patch/0008-typo-fix.patch | 35 + series.conf | 8 + 15 files changed, 26713 insertions(+), 3 deletions(-) create mode 100644 VERSION-openeuler create mode 100755 apply-patches create mode 100755 gen-version.sh create mode 100644 git-commit delete mode 100644 patch/.gitkeep create mode 100644 patch/0001-add-experiments-to-tar.patch create mode 100644 patch/0002-add-another_json_minimal-to-vendor.patch create mode 100644 patch/0003-remove-unused-code-and-comments.patch create mode 100644 patch/0004-pull_wasm-return-result-do-not-panic.patch create mode 100644 patch/0005-wasmengine-could-pull-public-https-repository-image.patch create mode 100644 patch/0006-wasi-use-json-as-args-for-consistent-wasm-function-i.patch create mode 100644 patch/0007-integration-test-init-for-wasmengine.patch create mode 100644 patch/0008-typo-fix.patch create mode 100644 series.conf diff --git a/VERSION-openeuler b/VERSION-openeuler new file mode 100644 index 0000000..944912a --- /dev/null +++ b/VERSION-openeuler @@ -0,0 +1 @@ +0.1.2-1 diff --git a/WasmEngine.spec b/WasmEngine.spec index 740783a..aa84f29 100644 --- a/WasmEngine.spec +++ b/WasmEngine.spec @@ -2,14 +2,20 @@ Name: WasmEngine Version: v0.1.2 -Release: 2 +Release: 3 Summary: WasmEngine is a webassembly function engine, which provides high concurrency and sandbox security. License: MulanPSL-2.0 URL: https://gitee.com/openeuler/WasmEngine Source0: %{name}-%{version}.tar.gz +Source1: git-commit +Source2: VERSION-openeuler +Source3: apply-patches +Source4: gen-version.sh +Source5: series.conf +Source6: patch.tar.gz -BuildRequires: rust,cargo,rust-packaging +BuildRequires: rust,cargo,rust-packaging,git BuildRequires: gcc,dtc,openssl-devel %description @@ -17,9 +23,16 @@ Based on Rust programming language, WasmEngine is a webassembly function engine, Summary: %{summary} %prep -%autosetup -p1 +cp %{SOURCE0} . +cp %{SOURCE1} . +cp %{SOURCE2} . +cp %{SOURCE3} . +cp %{SOURCE4} . +cp %{SOURCE5} . +cp %{SOURCE6} . %build +sh ./apply-patches rm -f build.rs mkdir -p .cargo @@ -47,6 +60,12 @@ rm -rf %{buildroot} %attr(550,root,root) %{_bindir}/wasm_engine %changelog +* Mon Aug 08 2022 jiangpengfei - v0.1.2-3 +- Type: bugfix +- CVE: NA +- SUG: restart +- DESC: patch structure init, sync upstream patches + * Mon Aug 08 2022 xingweizheng - v0.1.2-2 - Type: requirement - CVE: NA diff --git a/apply-patches b/apply-patches new file mode 100755 index 0000000..4ab3490 --- /dev/null +++ b/apply-patches @@ -0,0 +1,38 @@ +#!/bin/bash +# Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. +# Description: This shell script is used to apply patches for the project +# Author: lixiang172@huawei.com +# Create: 2020-08-21 + +set -ex + +pkg=WasmEngine +cwd=${PWD} +src=${cwd}/${pkg} +tar_file=WasmEngine-v"$(awk -F"-" '{print $1}' < VERSION-openeuler)".tar.gz + +mkdir ${src} && tar -zxvf "${tar_file}" -C ${src} --strip-components 1 +if [ ! -d patch ]; then + tar -zxvf patch.tar.gz +fi + +cd "${src}" +git init +git add . +git config user.name 'build' +git config user.email 'build@obs.com' +git commit -m 'init build' +cd "${cwd}" + +series=${cwd}/series.conf +while IPF= read -r line; do + if [[ "${line}" =~ ^patch* ]]; then + echo "git apply ${cwd}/${line}" + cd "${src}" && git apply "${cwd}/${line}" + fi +done <"${series}" + +cd "${cwd}" + +cp -rf "${src}"/* . +cp -f VERSION-openeuler VERSION diff --git a/gen-version.sh b/gen-version.sh new file mode 100755 index 0000000..9ec6d3e --- /dev/null +++ b/gen-version.sh @@ -0,0 +1,91 @@ +#!/bin/bash +################################################################################################### +# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. +# iSula-Kits licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Author: Xiang Li +# Create: 2020-05-18 +# Description: This script used for update isula-build version and release. Enjoy and cherrs +################################################################################################### + +# Basic info +top_dir=$(git rev-parse --show-toplevel) +version_file="${top_dir}/VERSION-openeuler" +spec_file="${top_dir}/isula-build.spec" +commit_file=${top_dir}/git-commit +color=$(tput setaf 2) # red +color_reset=$(tput sgr0) + +# Commit ID +changeID=`git log -1 | grep Change-Id | awk '{print $2}' | head -c 40` +if [ "${changeID}" = "" ]; then + changeID=`date | sha256sum | head -c 40` +fi +echo "${changeID}" > ${top_dir}/git-commit +commit_id=$(cat ${commit_file}|cut -c1-7) + +old_all=$(cat "${version_file}") +old_version=$(cat "${version_file}" | awk -F"-" '{print $1}') +old_release=$(cat "${version_file}" | awk -F"-" '{print $2}') +major_old_version=$(echo "${old_version}" | awk -F "." '{print $1}') +minor_old_version=$(echo "${old_version}" | awk -F "." '{print $2}') +revision_old_version=$(echo "${old_version}" | awk -F "." '{print $3}') + + +# Read user input +read -rp "update version: Major(1), Minor(2), Revision(3), Release(4) [1/2/3/4]: " input +case ${input} in + 1) + major_old_version=$((major_old_version + 1)) + minor_old_version="0" + revision_old_version="0" + new_release_num="1" + ;; + 2) + minor_old_version=$((minor_old_version + 1)) + revision_old_version="0" + new_release_num="1" + ;; + 3) + revision_old_version=$((revision_old_version + 1)) + new_release_num="1" + ;; + 4) + new_release_num=$((old_release + 1)) + ;; + + *) + echo "Wrong input, Version Not modified: ${old_version}" + exit 0 + ;; +esac + +author=$(git config user.name) +email=$(git config user.email) + +# VERSION format: +# Major.Minor.Revision +new_version=${major_old_version}.${minor_old_version}.${revision_old_version} +new_release="${new_release_num}" +new_all=${new_version}-${new_release_num} +new_changelog=$(cat << EOF +* $(date '+%a %b %d %Y') $author <$email> - $new_all\n- Type:\n- CVE:\n- SUG:\n- DESC:\n +EOF +) + +# Replace version and release for spec and VERSION files +sed -i -e "s/^Version: .*$/Version: ${new_version}/g" "${spec_file}" +sed -i -e "s/^Release: .*$/Release: ${new_release}/g" "${spec_file}" +sed -i -e "/\%changelog/a$new_changelog" "${spec_file}" +echo "${new_all}" > "${version_file}" + +if [[ "${old_all}" != "${new_all}" ]]; then + printf 'Version: %s -> %s\n' "${old_all}" "${color}${new_all}${color_reset}" +fi + diff --git a/git-commit b/git-commit new file mode 100644 index 0000000..9ddc646 --- /dev/null +++ b/git-commit @@ -0,0 +1 @@ +72af9798974345d587fe8f3ea2c121adc1696651 diff --git a/patch/.gitkeep b/patch/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/patch/0001-add-experiments-to-tar.patch b/patch/0001-add-experiments-to-tar.patch new file mode 100644 index 0000000..0f2844f --- /dev/null +++ b/patch/0001-add-experiments-to-tar.patch @@ -0,0 +1,667 @@ +From 6d7bed672d69a3fb60d98ff84182ff5eceb0c452 Mon Sep 17 00:00:00 2001 +From: build +Date: Tue, 9 Aug 2022 19:06:59 +0800 +Subject: [PATCH] add experiments to tar + +--- + experiments/application/add_one/Cargo.lock | 7 + + experiments/application/add_one/Cargo.toml | 11 ++ + experiments/application/add_one/src/lib.rs | 4 + + .../authentication-wasi/Cargo.lock | 74 +++++++++ + .../authentication-wasi/Cargo.toml | 10 ++ + .../authentication-wasi/src/main.rs | 68 ++++++++ + .../application/authentication/Cargo.lock | 154 ++++++++++++++++++ + .../application/authentication/Cargo.toml | 18 ++ + .../application/authentication/src/lib.rs | 91 +++++++++++ + .../application/echo-string/Cargo.lock | 7 + + .../application/echo-string/Cargo.toml | 11 ++ + .../application/echo-string/src/lib.rs | 5 + + experiments/application/fibonacci/Cargo.lock | 7 + + experiments/application/fibonacci/Cargo.toml | 8 + + experiments/application/fibonacci/src/main.rs | 18 ++ + experiments/application/hello/Cargo.lock | 7 + + experiments/application/hello/Cargo.toml | 8 + + experiments/application/hello/src/main.rs | 3 + + 18 files changed, 511 insertions(+) + create mode 100644 experiments/application/add_one/Cargo.lock + create mode 100644 experiments/application/add_one/Cargo.toml + create mode 100644 experiments/application/add_one/src/lib.rs + create mode 100644 experiments/application/authentication-wasi/Cargo.lock + create mode 100644 experiments/application/authentication-wasi/Cargo.toml + create mode 100644 experiments/application/authentication-wasi/src/main.rs + create mode 100644 experiments/application/authentication/Cargo.lock + create mode 100644 experiments/application/authentication/Cargo.toml + create mode 100644 experiments/application/authentication/src/lib.rs + create mode 100644 experiments/application/echo-string/Cargo.lock + create mode 100644 experiments/application/echo-string/Cargo.toml + create mode 100644 experiments/application/echo-string/src/lib.rs + create mode 100644 experiments/application/fibonacci/Cargo.lock + create mode 100644 experiments/application/fibonacci/Cargo.toml + create mode 100644 experiments/application/fibonacci/src/main.rs + create mode 100644 experiments/application/hello/Cargo.lock + create mode 100644 experiments/application/hello/Cargo.toml + create mode 100644 experiments/application/hello/src/main.rs + +diff --git a/experiments/application/add_one/Cargo.lock b/experiments/application/add_one/Cargo.lock +new file mode 100644 +index 00000000..f33516b5 +--- /dev/null ++++ b/experiments/application/add_one/Cargo.lock +@@ -0,0 +1,7 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "authentication" ++version = "0.1.0" +diff --git a/experiments/application/add_one/Cargo.toml b/experiments/application/add_one/Cargo.toml +new file mode 100644 +index 00000000..e218947f +--- /dev/null ++++ b/experiments/application/add_one/Cargo.toml +@@ -0,0 +1,11 @@ ++[package] ++name = "authentication" ++version = "0.1.0" ++edition = "2021" ++ ++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ++ ++[dependencies] ++ ++[lib] ++crate-type = ["cdylib"] +diff --git a/experiments/application/add_one/src/lib.rs b/experiments/application/add_one/src/lib.rs +new file mode 100644 +index 00000000..da5a5692 +--- /dev/null ++++ b/experiments/application/add_one/src/lib.rs +@@ -0,0 +1,4 @@ ++#[no_mangle] ++pub extern "C" fn add_one(x: i32) -> i32 { ++ x + 1 ++} +\ No newline at end of file +diff --git a/experiments/application/authentication-wasi/Cargo.lock b/experiments/application/authentication-wasi/Cargo.lock +new file mode 100644 +index 00000000..7aa6e8f4 +--- /dev/null ++++ b/experiments/application/authentication-wasi/Cargo.lock +@@ -0,0 +1,74 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "another_json_minimal" ++version = "0.0.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "77ba8341e1396c8a379f62de1b47f31256f2fe0846f5f95e9c60014d2102d9bd" ++ ++[[package]] ++name = "authentication-wasi" ++version = "0.1.0" ++dependencies = [ ++ "another_json_minimal", ++ "md-5", ++] ++ ++[[package]] ++name = "block-buffer" ++version = "0.9.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" ++dependencies = [ ++ "generic-array", ++] ++ ++[[package]] ++name = "digest" ++version = "0.9.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" ++dependencies = [ ++ "generic-array", ++] ++ ++[[package]] ++name = "generic-array" ++version = "0.14.4" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" ++dependencies = [ ++ "typenum", ++ "version_check", ++] ++ ++[[package]] ++name = "md-5" ++version = "0.9.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" ++dependencies = [ ++ "block-buffer", ++ "digest", ++ "opaque-debug", ++] ++ ++[[package]] ++name = "opaque-debug" ++version = "0.3.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" ++ ++[[package]] ++name = "typenum" ++version = "1.14.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" ++ ++[[package]] ++name = "version_check" ++version = "0.9.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +diff --git a/experiments/application/authentication-wasi/Cargo.toml b/experiments/application/authentication-wasi/Cargo.toml +new file mode 100644 +index 00000000..b862de82 +--- /dev/null ++++ b/experiments/application/authentication-wasi/Cargo.toml +@@ -0,0 +1,10 @@ ++[package] ++name = "authentication-wasi" ++version = "0.1.0" ++edition = "2021" ++ ++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ++ ++[dependencies] ++md-5 = { version="0.9", default-features = false } ++another_json_minimal = "0.0.2" +diff --git a/experiments/application/authentication-wasi/src/main.rs b/experiments/application/authentication-wasi/src/main.rs +new file mode 100644 +index 00000000..df00eae3 +--- /dev/null ++++ b/experiments/application/authentication-wasi/src/main.rs +@@ -0,0 +1,68 @@ ++use another_json_minimal::Json; ++use md5::{Digest, Md5}; ++use std::{env, fmt::Write}; ++ ++#[derive(Default)] ++struct Response { ++ status: String, ++ body: String, ++} ++ ++fn main() { ++ let args: Vec = env::args().collect(); ++ if args.len() != 3 { ++ eprintln!("usage: authentication "); ++ return; ++ } ++ ++ let arg_uri = &args[0]; ++ let arg_body = &args[1]; ++ let arg_secret = &args[2]; ++ ++ let arg_func = "argfunc"; ++ let content = format!("{}#{}#{}", arg_uri, arg_body, arg_func); ++ ++ // create a Md5 hasher instance ++ let mut hasher = Md5::new(); ++ // process input message ++ hasher.update(content.as_bytes()); ++ let result = hasher.finalize(); ++ ++ let slice = result.as_slice(); ++ let mut hash = String::with_capacity(slice.len() * 2); ++ for &b in slice { ++ write!(&mut hash, "{:02x}", b).unwrap(); ++ } ++ ++ let mut r: Response = Response::default(); ++ let html: String; ++ if &hash == arg_secret { ++ r.status = "200".to_string(); ++ html = "

Auth Pass!

hash ".to_owned() + &hash + "

"; ++ r.body = html; ++ } else { ++ r.status = "403".to_string(); ++ html = "

Auth Forbidden!

hash ".to_owned() ++ + &hash ++ + " secret " ++ + &arg_secret ++ + "

"; ++ r.body = html; ++ } ++ ++ //we use complicated another_json_minimal temporary ++ let mut json = Json::new(); ++ let status = Json::OBJECT { ++ name: String::from("status"), ++ value: Box::new(Json::STRING(String::from(&r.status))), ++ }; ++ json.add(status); ++ let body = Json::OBJECT { ++ name: String::from("body"), ++ value: Box::new(Json::STRING(String::from(&r.body))), ++ }; ++ json.add(body); ++ let serialized = json.print(); ++ ++ println!("{}", serialized); ++} +diff --git a/experiments/application/authentication/Cargo.lock b/experiments/application/authentication/Cargo.lock +new file mode 100644 +index 00000000..9d96c7b1 +--- /dev/null ++++ b/experiments/application/authentication/Cargo.lock +@@ -0,0 +1,154 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "another_json_minimal" ++version = "0.0.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "77ba8341e1396c8a379f62de1b47f31256f2fe0846f5f95e9c60014d2102d9bd" ++ ++[[package]] ++name = "authentication" ++version = "0.1.0" ++dependencies = [ ++ "another_json_minimal", ++ "md-5", ++ "serde", ++ "serde_json", ++] ++ ++[[package]] ++name = "block-buffer" ++version = "0.9.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" ++dependencies = [ ++ "generic-array", ++] ++ ++[[package]] ++name = "digest" ++version = "0.9.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" ++dependencies = [ ++ "generic-array", ++] ++ ++[[package]] ++name = "generic-array" ++version = "0.14.4" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" ++dependencies = [ ++ "typenum", ++ "version_check", ++] ++ ++[[package]] ++name = "itoa" ++version = "1.0.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" ++ ++[[package]] ++name = "md-5" ++version = "0.9.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" ++dependencies = [ ++ "block-buffer", ++ "digest", ++ "opaque-debug", ++] ++ ++[[package]] ++name = "opaque-debug" ++version = "0.3.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" ++ ++[[package]] ++name = "proc-macro2" ++version = "1.0.34" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" ++dependencies = [ ++ "unicode-xid", ++] ++ ++[[package]] ++name = "quote" ++version = "1.0.10" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" ++dependencies = [ ++ "proc-macro2", ++] ++ ++[[package]] ++name = "ryu" ++version = "1.0.9" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" ++ ++[[package]] ++name = "serde" ++version = "1.0.132" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" ++dependencies = [ ++ "serde_derive", ++] ++ ++[[package]] ++name = "serde_derive" ++version = "1.0.132" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] ++ ++[[package]] ++name = "serde_json" ++version = "1.0.73" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" ++dependencies = [ ++ "itoa", ++ "ryu", ++ "serde", ++] ++ ++[[package]] ++name = "syn" ++version = "1.0.82" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "unicode-xid", ++] ++ ++[[package]] ++name = "typenum" ++version = "1.14.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" ++ ++[[package]] ++name = "unicode-xid" ++version = "0.2.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" ++ ++[[package]] ++name = "version_check" ++version = "0.9.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +diff --git a/experiments/application/authentication/Cargo.toml b/experiments/application/authentication/Cargo.toml +new file mode 100644 +index 00000000..47729792 +--- /dev/null ++++ b/experiments/application/authentication/Cargo.toml +@@ -0,0 +1,18 @@ ++[package] ++name = "authentication" ++version = "0.1.0" ++edition = "2021" ++ ++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ++ ++[dependencies] ++md-5 = { version="0.9", default-features = false } ++another_json_minimal = "0.0.2" ++ ++[lib] ++crate-type = ["cdylib"] ++ ++[dev-dependencies] ++serde = { version = "1.0", features = ["derive"] } ++serde_json = "1.0" ++ +diff --git a/experiments/application/authentication/src/lib.rs b/experiments/application/authentication/src/lib.rs +new file mode 100644 +index 00000000..0aa5d980 +--- /dev/null ++++ b/experiments/application/authentication/src/lib.rs +@@ -0,0 +1,91 @@ ++use std::fmt::Write; ++ ++use another_json_minimal::Json; ++use md5::{Digest, Md5}; ++ ++#[derive(Default)] ++struct Response { ++ status: String, ++ body: String, ++} ++ ++#[no_mangle] ++pub fn authentication(data: &str) -> (*mut u8, usize) { ++ // fulfill data p ++ let arg_func = "argfunc"; ++ let json = match Json::parse(data.as_bytes()) { ++ Ok(json) => json, ++ Err((position, message)) => { ++ panic!("`{}` at position `{}`!!!", position, message); ++ } ++ }; ++ let arg_uri = json.get("arg_uri").unwrap().print(); ++ let arg_body = json.get("arg_body").unwrap().print(); ++ let arg_secret = json.get("arg_secret").unwrap().print(); ++ ++ let content = format!("{}#{}#{}", arg_uri, arg_body, arg_func); ++ ++ // create a Md5 hasher instance ++ let mut hasher = Md5::new(); ++ // process input message ++ hasher.update(content.as_bytes()); ++ let result = hasher.finalize(); ++ ++ let slice = result.as_slice(); ++ let mut hash = String::with_capacity(slice.len() * 2); ++ for &b in slice { ++ write!(&mut hash, "{:02x}", b).unwrap(); ++ } ++ ++ let mut r: Response = Response::default(); ++ let html: String; ++ if hash == arg_secret { ++ r.status = "200".to_string(); ++ html = "

Auth Pass!

hash ".to_owned() + &hash + "

"; ++ r.body = html; ++ } else { ++ r.status = "403".to_string(); ++ html = "

Auth Forbidden!

hash ".to_owned() ++ + &hash ++ + " secret " ++ + &arg_secret ++ + "

"; ++ r.body = html; ++ } ++ ++ //we use complicated another_json_minimal temporary ++ let mut json = Json::new(); ++ let status = Json::OBJECT { ++ name: String::from("status"), ++ value: Box::new(Json::STRING(String::from(&r.status))), ++ }; ++ ++ json.add(status); ++ let body = Json::OBJECT { ++ name: String::from("body"), ++ value: Box::new(Json::STRING(String::from(&r.body))), ++ }; ++ json.add(body); ++ ++ let mut serialized = json.print(); ++ (serialized.as_mut_ptr(), serialized.len()) ++} ++ ++#[test] ++fn test_authentication() { ++ use serde::{Deserialize, Serialize}; ++ #[derive(Deserialize, Serialize, Default)] ++ struct Data { ++ arg_uri: String, ++ arg_body: String, ++ arg_secret: String, ++ } ++ let p: Data = Data { ++ arg_uri: "uri".to_string(), ++ arg_body: "body".to_string(), ++ arg_secret: "secrect".to_string(), ++ }; ++ ++ let serialized = serde_json::to_string(&p).unwrap(); ++ let (_p, _l) = authentication(&serialized); ++} +diff --git a/experiments/application/echo-string/Cargo.lock b/experiments/application/echo-string/Cargo.lock +new file mode 100644 +index 00000000..18266ede +--- /dev/null ++++ b/experiments/application/echo-string/Cargo.lock +@@ -0,0 +1,7 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "echo-string" ++version = "0.1.0" +diff --git a/experiments/application/echo-string/Cargo.toml b/experiments/application/echo-string/Cargo.toml +new file mode 100644 +index 00000000..51c4cfa7 +--- /dev/null ++++ b/experiments/application/echo-string/Cargo.toml +@@ -0,0 +1,11 @@ ++[package] ++name = "echo-string" ++version = "0.1.0" ++edition = "2021" ++ ++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ++ ++[dependencies] ++ ++[lib] ++crate-type = ["cdylib"] +diff --git a/experiments/application/echo-string/src/lib.rs b/experiments/application/echo-string/src/lib.rs +new file mode 100644 +index 00000000..56f38f7e +--- /dev/null ++++ b/experiments/application/echo-string/src/lib.rs +@@ -0,0 +1,5 @@ ++#[no_mangle] ++pub fn echo_string(input: &str) -> (*const u8, usize) { ++ let r = input.to_owned() + "b"; ++ (r.as_ptr(), r.len()) ++} +diff --git a/experiments/application/fibonacci/Cargo.lock b/experiments/application/fibonacci/Cargo.lock +new file mode 100644 +index 00000000..06a56e63 +--- /dev/null ++++ b/experiments/application/fibonacci/Cargo.lock +@@ -0,0 +1,7 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "fibonacci" ++version = "0.1.0" +diff --git a/experiments/application/fibonacci/Cargo.toml b/experiments/application/fibonacci/Cargo.toml +new file mode 100644 +index 00000000..9cd048ef +--- /dev/null ++++ b/experiments/application/fibonacci/Cargo.toml +@@ -0,0 +1,8 @@ ++[package] ++name = "fibonacci" ++version = "0.1.0" ++edition = "2021" ++ ++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ++ ++[dependencies] +diff --git a/experiments/application/fibonacci/src/main.rs b/experiments/application/fibonacci/src/main.rs +new file mode 100644 +index 00000000..4c6c79fb +--- /dev/null ++++ b/experiments/application/fibonacci/src/main.rs +@@ -0,0 +1,18 @@ ++use std::env; ++ ++fn fib(n: u64) -> u64 { ++ if n <= 1 { ++ return n; ++ } ++ fib(n - 1) + fib(n - 2) ++} ++ ++fn main() { ++ let args: Vec = env::args().collect(); ++ ++ if args.len() != 1 { ++ eprintln!("only single parameter is needed"); ++ return; ++ } ++ println!("{}", fib(args[0].parse::().unwrap())) ++} +diff --git a/experiments/application/hello/Cargo.lock b/experiments/application/hello/Cargo.lock +new file mode 100644 +index 00000000..c3aedd77 +--- /dev/null ++++ b/experiments/application/hello/Cargo.lock +@@ -0,0 +1,7 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "hello" ++version = "0.1.0" +diff --git a/experiments/application/hello/Cargo.toml b/experiments/application/hello/Cargo.toml +new file mode 100644 +index 00000000..fb1ec2c9 +--- /dev/null ++++ b/experiments/application/hello/Cargo.toml +@@ -0,0 +1,8 @@ ++[package] ++name = "hello" ++version = "0.1.0" ++edition = "2021" ++ ++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ++ ++[dependencies] +diff --git a/experiments/application/hello/src/main.rs b/experiments/application/hello/src/main.rs +new file mode 100644 +index 00000000..b3dbf1ae +--- /dev/null ++++ b/experiments/application/hello/src/main.rs +@@ -0,0 +1,3 @@ ++fn main() { ++ println!("Hello, Budda!"); ++} +-- +2.27.0 + diff --git a/patch/0002-add-another_json_minimal-to-vendor.patch b/patch/0002-add-another_json_minimal-to-vendor.patch new file mode 100644 index 0000000..826accd --- /dev/null +++ b/patch/0002-add-another_json_minimal-to-vendor.patch @@ -0,0 +1,1871 @@ +From 40ca80de7dd4b07b7748fafe82c869863ebd2552 Mon Sep 17 00:00:00 2001 +From: build +Date: Tue, 9 Aug 2022 19:36:16 +0800 +Subject: [PATCH] add another_json_minimal to vendor + +--- + .../another_json_minimal/.cargo-checksum.json | 1 + + vendor/another_json_minimal/Cargo.toml | 25 + + vendor/another_json_minimal/LICENSE.md | 19 + + vendor/another_json_minimal/README.md | 316 +++++++ + vendor/another_json_minimal/src/lib.rs | 790 ++++++++++++++++++ + vendor/another_json_minimal/src/tests.rs | 658 +++++++++++++++ + 6 files changed, 1809 insertions(+) + create mode 100644 vendor/another_json_minimal/.cargo-checksum.json + create mode 100644 vendor/another_json_minimal/Cargo.toml + create mode 100644 vendor/another_json_minimal/LICENSE.md + create mode 100644 vendor/another_json_minimal/README.md + create mode 100644 vendor/another_json_minimal/src/lib.rs + create mode 100644 vendor/another_json_minimal/src/tests.rs + +diff --git a/vendor/another_json_minimal/.cargo-checksum.json b/vendor/another_json_minimal/.cargo-checksum.json +new file mode 100644 +index 00000000..eb4596a4 +--- /dev/null ++++ b/vendor/another_json_minimal/.cargo-checksum.json +@@ -0,0 +1 @@ ++{"files":{"Cargo.toml":"5976a21419a8e5226318259a855ca3f520f9480511b4af6a152f4fb4850fa480","LICENSE.md":"35e1404ccc3a758c529c821ca1c4df4e6a810227d6f28c6951d168a4dad6d485","README.md":"edb5cadb71dac49f1b66bcbf5ed8c18b06a2e7ef7bd70aae7775e3f89eaef678","src/lib.rs":"170f6a19395b229fb60049f136655318e6897cdb58e59f42a2a7ea99fd254714","src/tests.rs":"8b45652fdee66d58b849b596663f43657c6cf58f87b1e29dac0f4267d6266b1d"},"package":"77ba8341e1396c8a379f62de1b47f31256f2fe0846f5f95e9c60014d2102d9bd"} +\ No newline at end of file +diff --git a/vendor/another_json_minimal/Cargo.toml b/vendor/another_json_minimal/Cargo.toml +new file mode 100644 +index 00000000..61e86752 +--- /dev/null ++++ b/vendor/another_json_minimal/Cargo.toml +@@ -0,0 +1,25 @@ ++# 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" ++name = "another_json_minimal" ++version = "0.0.2" ++authors = ["36den", "meilier"] ++description = "A minimal json crate." ++readme = "README.md" ++keywords = ["json", "minimal"] ++categories = ["encoding"] ++license = "MIT OR Apache-2.0" ++repository = "https://github.com/meilier/json_minimal-rust" ++resolver = "2" ++ ++[dependencies] +diff --git a/vendor/another_json_minimal/LICENSE.md b/vendor/another_json_minimal/LICENSE.md +new file mode 100644 +index 00000000..5147935e +--- /dev/null ++++ b/vendor/another_json_minimal/LICENSE.md +@@ -0,0 +1,19 @@ ++# APACHE ++ ++Copyright 2020 36den ++ ++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at ++ ++`http://www.apache.org/licenses/LICENSE-2.0` ++ ++Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ++ ++# MIT ++ ++Copyright 2020 36den ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +\ No newline at end of file +diff --git a/vendor/another_json_minimal/README.md b/vendor/another_json_minimal/README.md +new file mode 100644 +index 00000000..f5869899 +--- /dev/null ++++ b/vendor/another_json_minimal/README.md +@@ -0,0 +1,316 @@ ++# json_minimal ++ ++A minimal json crate conforming to https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf . ++ ++## Tutorial (creating jsons) ++ ++In order to create a valid (i.e. generally accepted) json you should always start with: ++```rust ++ use json_minimal::*; ++ ++ let mut json = Json::new(); ++ // which is equivalent to ++ let mut json = Json::JSON(Vec::new()); ++ // ... ++``` ++ ++To add an object, simply do this: ++```rust ++ // ... ++ let greeting = ++ Json::OBJECT { ++ name: String::from("Greeting"), ++ ++ value: Box::new( ++ Json::STRING( String::from("Hello, world!") ) ++ ) ++ } ++ ; ++ ++ json.add(greeting); ++ // ... ++``` ++or alternatively: ++```rust ++ // ... ++ json.add( ++ Json::OBJECT { ++ name: String::from("Greeting"), ++ ++ value: Box::new( ++ Json::STRING( String::from("Hello, world!") ) ++ ) ++ } ++ ); ++ // ... ++``` ++ ++As you can see, whilst the crate is minimal (in my opinion) it may not be the quickest to work with. This becomes clearer when adding an array to an object: ++```rust ++ // ... ++ ++ let mut days_in_the_week = ++ Json::OBJECT { ++ name: String::from("Days of the week"), ++ ++ value: Box::new( ++ Json::JSON(Vec::new()) ++ ) ++ } ++ ; ++ ++ let mut days = Json::ARRAY(Vec::new()); ++ ++ days ++ .add( ++ Json::STRING( String::from("Monday") ) ++ ) ++ .add( ++ Json::STRING( String::from("Tuesday") ) ++ ) ++ .add( ++ Json::STRING( String::from("Wednesday") ) ++ ) ++ .add( ++ Json::STRING( String::from("Thursday") ) ++ ) ++ .add( ++ Json::STRING( String::from("Friday") ) ++ ) ++ .add( ++ Json::STRING( String::from("Saturday") ) ++ ) ++ .add( ++ Json::STRING( String::from("Sunday") ) ++ ) ++ ; ++ ++ days_in_the_week ++ .add( ++ Json::OBJECT { ++ name: String::from("Total number of days"), ++ ++ value: Box::new( ++ Json::NUMBER(7.0) // Accepts `f64` ++ ) ++ } ++ ) ++ .add( ++ Json::OBJECT { ++ name: String::from("They are called"), ++ ++ value: Box::new( ++ days ++ ) ++ } ++ ) ++ ; ++ ++ json.add(days_in_the_week); ++ // ... ++``` ++ ++In conclusion: ++```rust ++ // ... ++ ++ let mut conclusion = ++ Json::OBJECT { ++ name: String::from("Conclusion"), ++ ++ value: Box::new( ++ Json::JSON(Vec::new()) ++ ) ++ } ++ ; ++ ++ conclusion ++ .add( ++ Json::OBJECT { ++ name: String::from("Minimal in my opinion"), ++ ++ value: Box::new( ++ Json::BOOL(true) ++ ) ++ } ++ ) ++ .add( ++ Json::OBJECT { ++ name: String::from("How much I care about your opinion"), ++ ++ value: Box::new( ++ Json::NULL ++ ) ++ } ++ ) ++ .add( ++ Json::OBJECT { ++ name: String::from("Comment"), ++ ++ value: Box::new( ++ Json::STRING( String::from(";)") ) ++ ) ++ } ++ ) ++ ; ++ ++ json.add(conclusion); ++ // ... ++``` ++ ++Calling: ++```rust ++ // ... ++ let resulting_json = json.print(); ++``` ++will result in a `String` containing: ++`{"Greeting":"Hello, world!","Days of the week":{"Total number of days":7,"They are called":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"Conclusion":{"Minimal in my opinion":true,"How much I care about your opinion":null,"Comment":";)"}}` ++ ++If you would like the json string in a different format you can easily make your own 'print' function. ++ ++## Tutorial (parsing and working with jsons) ++ ++Parsing a json value from bytes is even more minimal - at the cost of being more cumbersome. Let's see how we can parse the json we generated above: ++```rust ++ use json_minimal::*; ++ ++ let json = match Json::parse(b"{\"Greeting\":\"Hello, world!\",\"Days of the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Conclusion\":{\"Minimal in my opinion\":true,\"How much I care about your opinion\":null,\"Comment\":\";)\"}}") { ++ Ok(json) => { ++ json ++ }, ++ Err( (position,message) ) => { ++ panic!("`{}` at position `{}`!!!"); ++ } ++ } ++ // ... ++``` ++ ++Let's first talk about what information is given for a parsing error. As you might expect it is minimal. `position` above is the position were everything went wrong and the `message` will be something like`"Error parsing array."` if, for example, a closing `]` is missing somewhere. Continuing where we left off: ++```rust ++ // ... ++ match json.get("Greeting") { ++ Some(json) => { ++ match json { ++ Json::OBJECT { name: _, value } => { ++ match value.unbox() { ++ Json::STRING(val) => { ++ assert_eq!("Hello, world!",val); ++ }, ++ json => { ++ panic!("Expected Json::STRING but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::JSON but found {:?}!!!",json) ++ } ++ } ++ }, ++ None => { ++ panic!("Couln't find Greeting. How rude!"); ++ } ++ } ++ // ... ++``` ++Unfortunately all of this was necessary because, even though we were able to confirm that `"Greeting"` exists, we had no way of knowing what it really is. It's not over: ++```rust ++ // ... ++ match json.get("Days of the week") { // Hint: You can also use `get_mut` to aid in editing/creating jsons... ++ Some(json) => { ++ match json { ++ Json::OBJECT { name: _, value } => { ++ match value.unbox() { ++ Json::JSON(values) => { ++ assert_eq!(values.len(),2); ++ ++ match &values[0] { ++ Json::OBJECT { name, value: _ } => { ++ assert_eq!("Total number of days",name); ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!",json); ++ } ++ } ++ ++ match &values[1] { ++ Json::OBJECT { name, value: _ } => { ++ assert_eq!("They are called",name); ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!",json); ++ } ++ } ++ ++ }, ++ json => { ++ panic!("Expected Json::JSON but found {:?}!!!",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!",json); ++ } ++ } ++ }, ++ None => { ++ panic!("Days of the week not found!"); ++ } ++ } ++ // You get the idea. ++``` ++The function `Json::parse(...)` can also parse 'standalone values'. Example: ++ ++```rust ++ match Json::parse("\"What's up?\"") { ++ Ok(json) => { ++ match json { ++ Json::STRING(val) => { ++ assert_eq!("What's up?",val); ++ }, ++ json => { ++ panic!("Expected Json::STRING but found {:?}!!!",json); ++ } ++ } ++ }, ++ Err( (position,message) ) => { ++ panic!("`{}` at position `{}`."); ++ } ++ } ++ ++ // Another example: ++ ++ match Json::parse("[1,2,3,\"four\"]") { ++ Ok(json) => { ++ match json { ++ Json::ARRAY(val) => { ++ assert_eq!(val.len(),4); ++ }, ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}!!!",json); ++ } ++ } ++ }, ++ Err( (position,message) ) => { ++ panic!("`{}` at position `{}`."); ++ } ++ } ++``` ++## Changes & Improvements ++ ++* Lonami (github) has made improvements: ++ 1. `json_minimal` can now parse non-ASCII strings and escape sequences. (I overlooked this, I admit.) ++ 2. The code is cleaner thanks to the question-mark operator and using rustfmt. ++ 3. Some parsing stuff that didn't work now works. ++ ++ A thousand thanks to Lonami !!! ++ ++* `json_minimal` can now also parse 'pretty' json like this (as long as only `\r`, `\n`, `\t` and whitespace were used for formatting): ++``` ++{ ++ "Array": [ "Hello" , "World" , "!" ] ++} ++``` ++This should also have worked from the start but I did not include because it of my aversion to energy inefficiency (although it is, perhaps, unfounded). ++ ++--- ++Please let me know if something doesn't work. I can't promise i'll react immediately, though. +\ No newline at end of file +diff --git a/vendor/another_json_minimal/src/lib.rs b/vendor/another_json_minimal/src/lib.rs +new file mode 100644 +index 00000000..0aad96a3 +--- /dev/null ++++ b/vendor/another_json_minimal/src/lib.rs +@@ -0,0 +1,790 @@ ++//Copyright 2020 36den ++//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: ++//The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ++//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++#[derive(Debug)] ++pub enum Json { ++ OBJECT { name: String, value: Box }, ++ JSON(Vec), ++ ARRAY(Vec), ++ STRING(String), ++ NUMBER(f64), ++ BOOL(bool), ++ NULL, ++} ++ ++impl Json { ++ /// Construct a new `Json::JSON` ++ /// ## Example ++ /// ``` ++ /// use json_minimal::*; ++ /// ++ /// let mut json = Json::new(); ++ /// ``` ++ pub fn new() -> Json { ++ Json::JSON(Vec::new()) ++ } ++ ++ /// Add any `Json` variant to a `Json` variant of type `Json::JSON`, `Json::ARRAY` ++ /// or a `Json::OBJECT` (holding a `Json::JSON`,`Json::ARRAY`,`Json::OBJECT` (holding a `Json::JSON`,`Json::`...)). ++ /// ## Panics! ++ /// Will panic if the conditions stated above are not met OR if an attempt is made to add a `Json::JSON` to a `Json::JSON` ++ /// without wrapping it in a `Json::OBJECT` first. ++ /// ## Example ++ /// ``` ++ /// use json_minimal::*; ++ /// ++ /// let mut json = Json::new(); ++ /// ++ /// json ++ /// .add( ++ /// Json::OBJECT { ++ /// name: String::from("Greeting"), ++ /// ++ /// value: Box::new( ++ /// Json::STRING( String::from("Hello, world!") ) ++ /// ) ++ /// } ++ /// ) ++ /// ; ++ /// ``` ++ /// See the tutorial on github for more. ++ pub fn add(&mut self, value: Json) -> &mut Json { ++ match self { ++ Json::JSON(values) => match value { ++ Json::OBJECT { name, value } => { ++ values.push(Json::OBJECT { name, value }); ++ } ++ Json::JSON(_) => { ++ panic!("A `Json::JSON` may not be added to a `Json::JSON` if it is not within a `Json::OBJECT`."); ++ } ++ Json::ARRAY(vals) => { ++ values.push(Json::ARRAY(vals)); ++ } ++ Json::STRING(val) => { ++ values.push(Json::STRING(val)); ++ } ++ Json::NUMBER(val) => { ++ values.push(Json::NUMBER(val)); ++ } ++ Json::BOOL(val) => { ++ values.push(Json::BOOL(val)); ++ } ++ Json::NULL => { ++ values.push(Json::NULL); ++ } ++ }, ++ Json::OBJECT { ++ name: _, ++ value: obj_val, ++ } => match obj_val.unbox_mut() { ++ Json::JSON(values) => match value { ++ Json::OBJECT { name, value } => { ++ values.push(Json::OBJECT { name, value }); ++ } ++ Json::JSON(_) => { ++ panic!("A `Json::JSON` may not be added to a `Json::JSON` if it is not within a `Json::OBJECT`."); ++ } ++ Json::ARRAY(vals) => { ++ values.push(Json::ARRAY(vals)); ++ } ++ Json::STRING(val) => { ++ values.push(Json::STRING(val)); ++ } ++ Json::NUMBER(val) => { ++ values.push(Json::NUMBER(val)); ++ } ++ Json::BOOL(val) => { ++ values.push(Json::BOOL(val)); ++ } ++ Json::NULL => { ++ values.push(Json::NULL); ++ } ++ }, ++ Json::ARRAY(values) => match value { ++ Json::OBJECT { name, value } => { ++ values.push(Json::OBJECT { name, value }); ++ } ++ Json::JSON(vals) => { ++ values.push(Json::JSON(vals)); ++ } ++ Json::ARRAY(vals) => { ++ values.push(Json::ARRAY(vals)); ++ } ++ Json::STRING(val) => { ++ values.push(Json::STRING(val)); ++ } ++ Json::NUMBER(val) => { ++ values.push(Json::NUMBER(val)); ++ } ++ Json::BOOL(val) => { ++ values.push(Json::BOOL(val)); ++ } ++ Json::NULL => { ++ values.push(Json::NULL); ++ } ++ }, ++ json => { ++ panic!("The function `add(`&mut self`,`name: String`,`value: Json`)` may only be called on a `Json::JSON`, `Json::ARRAY` or `Json::OBJECT` holding a `Json::JSON` or `Json::ARRAY`. It was called on: {:?}",json); ++ } ++ }, ++ Json::ARRAY(values) => match value { ++ Json::OBJECT { name, value } => { ++ values.push(Json::OBJECT { name, value }); ++ } ++ Json::JSON(vals) => { ++ values.push(Json::JSON(vals)); ++ } ++ Json::ARRAY(vals) => { ++ values.push(Json::ARRAY(vals)); ++ } ++ Json::STRING(val) => { ++ values.push(Json::STRING(val)); ++ } ++ Json::NUMBER(val) => { ++ values.push(Json::NUMBER(val)); ++ } ++ Json::BOOL(val) => { ++ values.push(Json::BOOL(val)); ++ } ++ Json::NULL => { ++ values.push(Json::NULL); ++ } ++ }, ++ json => { ++ panic!("The function `add(`&mut self`,`name: String`,`value: Json`)` may only be called on a `Json::JSON`, `Json::ARRAY` or `Json::OBJECT` holding a `Json::JSON` or `Json::ARRAY`. It was called on: {:?}",json); ++ } ++ } ++ ++ self ++ } ++ ++ /// Get the `Json` with the requested name if it exists. ++ /// ## Panics ++ /// This function will panic if called on a `Json` variant other than `Json::JSON` or `Json::OBJECT`, ++ /// as only these two variants may hold `Json::OBJECT` (which has a `name` field). ++ /// ## Example ++ /// ``` ++ /// use json_minimal::*; ++ /// ++ /// let mut json = Json::new(); ++ /// ++ /// json ++ /// .add( ++ /// Json::OBJECT { ++ /// name: String::from("Greeting"), ++ /// ++ /// value: Box::new( ++ /// Json::STRING( String::from("Hello, world!") ) ++ /// ) ++ /// } ++ /// ) ++ /// ; ++ /// ++ /// match json.get("Greeting") { ++ /// Some(json) => { ++ /// match json { ++ /// Json::OBJECT { name, value } => { ++ /// match value.unbox() { // See `unbox()` below ++ /// Json::STRING(val) => { ++ /// assert_eq!("Hello, world!",val); ++ /// }, ++ /// _ => { ++ /// panic!("I expected this to be a `Json::STRING`!!!"); ++ /// } ++ /// } ++ /// }, ++ /// _ => { ++ /// panic!("This shouldn't happen!!!"); ++ /// } ++ /// } ++ /// }, ++ /// None => { ++ /// panic!("Not found!!!"); ++ /// } ++ /// } ++ /// ``` ++ pub fn get(&self, search: &str) -> Option<&Json> { ++ match self { ++ Json::JSON(values) => { ++ for n in 0..values.len() { ++ match &values[n] { ++ Json::OBJECT { name, value } => { ++ if name == search { ++ match value.unbox() { ++ Json::STRING(_) => { ++ return Some(value.unbox()); ++ } ++ _ => { ++ return Some(&values[n]); ++ } ++ } ++ } ++ } ++ _ => {} ++ } ++ } ++ ++ return None; ++ } ++ Json::OBJECT { name: _, value } => match value.unbox() { ++ Json::STRING(_) => { ++ return Some(value.unbox()); ++ } ++ Json::JSON(values) => { ++ for n in 0..values.len() { ++ match &values[n] { ++ Json::OBJECT { name, value: _ } => { ++ if name == search { ++ return Some(&values[n]); ++ } ++ } ++ _ => {} ++ } ++ } ++ ++ return None; ++ } ++ json => { ++ panic!("The function `get(`&self`,`search: &str`)` may only be called on a `Json::JSON` or a `Json::OBJECT` holding a `Json::JSON`. I was called on: {:?}",json); ++ } ++ }, ++ json => { ++ panic!("The function `get(`&self`,`search: &str`)` may only be called on a `Json::JSON`. I was called on: {:?}",json); ++ } ++ } ++ } ++ ++ /// Same as `get` above, but the references are mutable. Use `unbox_mut()` (see below) with this one. ++ /// ## Panics ++ /// This function will panic if called on a `Json` variant other than `Json::JSON` or `Json::OBJECT`, ++ /// as only these two variants may hold `Json::OBJECT` which has a `name` field. ++ pub fn get_mut(&mut self, search: &str) -> Option<&mut Json> { ++ match self { ++ Json::JSON(values) => { ++ for n in 0..values.len() { ++ match &values[n] { ++ Json::OBJECT { name, value: _ } => { ++ if name == search { ++ return Some(&mut values[n]); ++ } ++ } ++ _ => {} ++ } ++ } ++ } ++ Json::OBJECT { name: _, value } => match value.unbox_mut() { ++ Json::JSON(values) => { ++ for n in 0..values.len() { ++ match &values[n] { ++ Json::OBJECT { name, value: _ } => { ++ if name == search { ++ return Some(&mut values[n]); ++ } ++ } ++ _ => {} ++ } ++ } ++ } ++ json => { ++ panic!("The function `get_mut(`&self`,`search: &str`)` may only be called on a `Json::JSON` or a `Json::OBJECT` holding a `Json::JSON`. I was called on: {:?}",json); ++ } ++ }, ++ json => { ++ panic!("The function `get_mut(`&self`,`search: &str`)` may only be called on a `Json::JSON` or a `Json::OBJECT` holding a `Json::JSON`. I was called on: {:?}",json); ++ } ++ } ++ ++ None ++ } ++ ++ /// Enables matching the contents of a `Box`. ++ pub fn unbox(&self) -> &Json { ++ self ++ } ++ ++ /// Idem. ++ pub fn unbox_mut(&mut self) -> &mut Json { ++ self ++ } ++ ++ /// Returns a `String` of the form: `{"Json":"Value",...}` but can also be called on 'standalone objects' ++ /// which could result in `"Object":{"Stuff":...}` or `"Json":true`. ++ pub fn print(&self) -> String { ++ let mut result = String::new(); ++ ++ match self { ++ Json::OBJECT { name, value } => { ++ result.push_str(&format!("\"{}\":\"{}\"", name, value.print())); ++ } ++ Json::JSON(values) => { ++ result.push('{'); ++ ++ for n in 0..values.len() { ++ result.push_str(&values[n].print()); ++ result.push(','); ++ } ++ ++ result.pop(); ++ ++ result.push('}'); ++ } ++ Json::ARRAY(values) => { ++ result.push('['); ++ ++ for n in 0..values.len() { ++ result.push_str(&values[n].print()); ++ result.push(','); ++ } ++ ++ result.pop(); ++ ++ result.push(']'); ++ } ++ Json::STRING(val) => { ++ result.push_str(&format!("{}", val)); ++ } ++ Json::NUMBER(val) => { ++ result.push_str(&format!("{}", val)); ++ } ++ Json::BOOL(val) => { ++ if *val { ++ result.push_str("true"); ++ } else { ++ result.push_str("false") ++ } ++ } ++ Json::NULL => { ++ result.push_str("null"); ++ } ++ } ++ ++ result ++ } ++ ++ /// Parses the given bytes if a json structure is found. It even works with `\"Hello\":\"World\"` ++ /// (doesn't have to be like `{...}`), i.e. it can return any of the variants in the `Json` enum. ++ /// The error is returned in the form `(last position, what went wrong)`. Unfortunately the error ++ /// description are minimal (basically "Error parsing ...type..."). ++ /// ## Example ++ /// ``` ++ /// use json_minimal::*; ++ /// ++ /// match Json::parse(b"{\"Greeting\":\"Hello, world!\"}") { ++ /// Ok(json) => { ++ /// ++ /// match json.get("Greeting") { ++ /// Some(json) => { ++ /// match json { ++ /// Json::OBJECT { name, value } => { ++ /// match value.unbox() { ++ /// Json::STRING(val) => { ++ /// assert_eq!(val,"Hello, world!"); ++ /// }, ++ /// json => { ++ /// panic!("Expected Json::STRING but found {:?}!!!",json); ++ /// } ++ /// } ++ /// } ++ /// json => { ++ /// panic!("Expected Json::OBJECT but found {:?}!!!",json); ++ /// } ++ /// } ++ /// }, ++ /// None => { ++ /// panic!("Greeting was not found!!!"); ++ /// } ++ /// } ++ /// }, ++ /// Err( (pos,msg) ) => { ++ /// panic!("`{}` at position `{}`!!!",msg,pos); ++ /// } ++ /// } ++ /// ``` ++ /// See the tutorial on github for more. ++ pub fn parse(input: &[u8]) -> Result { ++ let mut incr: usize = 0; ++ ++ match input[incr] as char { ++ '{' => Self::parse_json(input, &mut incr), ++ '\"' => Self::parse_string(input, &mut incr), ++ '[' => Self::parse_array(input, &mut incr), ++ 't' | 'f' => Self::parse_bool(input, &mut incr), ++ 'n' => Self::parse_null(input, &mut incr), ++ '0'..='9' => Self::parse_number(input, &mut incr), ++ _ => Err((incr, "Not a valid json format")), ++ } ++ } ++ ++ // This must exclusively be used by `parse_string` to make any sense. ++ fn parse_object( ++ input: &[u8], ++ incr: &mut usize, ++ name: String, ++ ) -> Result { ++ // if input[*incr] as char != ':' { ++ // return Err((*incr, "Error parsing object.")); ++ // } ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing object.")); ++ } ++ ++ loop { ++ match input[*incr] as char { ++ '\r' | '\n' | '\t' | ' ' => { ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing object.")); ++ } ++ } ++ _ => { ++ break; ++ } ++ } ++ } ++ ++ let value = match input[*incr] as char { ++ '{' => Self::parse_json(input, incr)?, ++ '[' => Self::parse_array(input, incr)?, ++ '\"' => Self::parse_string(input, incr)?, ++ 't' | 'f' => Self::parse_bool(input, incr)?, ++ 'n' => Self::parse_null(input, incr)?, ++ '0'..='9' => Self::parse_number(input, incr)?, ++ _ => { ++ return Err((*incr, "Error parsing object.")); ++ } ++ }; ++ ++ Ok(Json::OBJECT { ++ name, ++ ++ value: Box::new(value), ++ }) ++ } ++ ++ // Parse if you thik it's something like `{...}` ++ fn parse_json(input: &[u8], incr: &mut usize) -> Result { ++ let mut result: Vec = Vec::new(); ++ ++ // if input[*incr] as char != '{' { ++ // return Err((*incr, "Error parsing json.")); ++ // } ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing json.")); ++ } ++ ++ loop { ++ let json = match input[*incr] as char { ++ ',' => { ++ *incr += 1; ++ continue; ++ } ++ '\"' => Self::parse_string(input, incr)?, ++ '[' => Self::parse_array(input, incr)?, ++ 't' | 'f' => Self::parse_bool(input, incr)?, ++ 'n' => Self::parse_null(input, incr)?, ++ '0'..='9' => Self::parse_number(input, incr)?, ++ '}' => { ++ *incr += 1; ++ ++ return Ok(Json::JSON(result)); ++ } ++ '{' => Self::parse_json(input, incr)?, ++ '\r' | '\n' | '\t' | ' ' => { ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing json.")); ++ } ++ ++ continue; ++ } ++ _ => { ++ return Err((*incr, "Error parsing json.")); ++ } ++ }; ++ ++ result.push(json); ++ } ++ } ++ ++ // Parse a &str if you're sure it resembles `[...` ++ fn parse_array(input: &[u8], incr: &mut usize) -> Result { ++ let mut result: Vec = Vec::new(); ++ ++ // if input[*incr] as char != '[' { ++ // return Err((*incr, "Error parsing array.")); ++ // } ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing array.")); ++ } ++ ++ loop { ++ let json = match input[*incr] as char { ++ ',' => { ++ *incr += 1; ++ continue; ++ } ++ '\"' => Self::parse_string(input, incr)?, ++ '[' => Self::parse_array(input, incr)?, ++ '{' => Self::parse_json(input, incr)?, ++ 't' | 'f' => Self::parse_bool(input, incr)?, ++ 'n' => Self::parse_null(input, incr)?, ++ '0'..='9' => Self::parse_number(input, incr)?, ++ ']' => { ++ *incr += 1; ++ ++ return Ok(Json::ARRAY(result)); ++ } ++ '\r' | '\n' | '\t' | ' ' => { ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing array.")); ++ } ++ ++ continue; ++ } ++ _ => { ++ return Err((*incr, "Error parsing array.")); ++ } ++ }; ++ ++ result.push(json); ++ } ++ } ++ ++ // Parse a &str if you know that it corresponds to/starts with a json String. ++ fn parse_string(input: &[u8], incr: &mut usize) -> Result { ++ let mut result: Vec = Vec::new(); ++ ++ // if input[*incr] as char != '\"' { ++ // return Err((*incr, "Error parsing string.")); ++ // } ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing string.")); ++ } ++ ++ loop { ++ match input[*incr] { ++ b'\"' => { ++ *incr += 1; ++ ++ let result = String::from_utf8(result) ++ .map_err(|_| (*incr, "Error parsing non-utf8 string."))?; ++ ++ if *incr < input.len() { ++ if input[*incr] as char == ':' { ++ return Self::parse_object(input, incr, result); ++ } else { ++ return Ok(Json::STRING(result)); ++ } ++ } else { ++ return Ok(Json::STRING(result)); ++ } ++ } ++ b'\\' => { ++ Self::parse_string_escape_sequence(input, incr, &mut result)?; ++ } ++ c => { ++ result.push(c); ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing string.")); ++ } ++ } ++ } ++ } ++ } ++ ++ // Parse an escape sequence inside a string ++ fn parse_string_escape_sequence( ++ input: &[u8], ++ incr: &mut usize, ++ result: &mut Vec, ++ ) -> Result<(), (usize, &'static str)> { ++ // if input[*incr] as char != '\\' { ++ // return Err((*incr, "Error parsing string escape sequence.")); ++ // } ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing string escape sequence.")); ++ } ++ ++ match input[*incr] as char { ++ '\"' | '\\' | '/' => { ++ result.push(input[*incr]); ++ } ++ 'b' => { ++ result.push(b'\x08'); ++ } ++ 'f' => { ++ result.push(b'\x0c'); ++ } ++ 'n' => { ++ result.push(b'\n'); ++ } ++ 'r' => { ++ result.push(b'\r'); ++ } ++ 't' => { ++ result.push(b'\t'); ++ } ++ 'u' => { ++ const BAD_UNICODE: &str = "Error parsing unicode string escape sequence."; ++ ++ if *incr + 4 >= input.len() { ++ return Err((*incr, BAD_UNICODE)); ++ } ++ ++ let hex = (&input[*incr + 1..*incr + 5]).to_vec(); ++ let hex = String::from_utf8(hex).map_err(|_| (*incr, BAD_UNICODE))?; ++ let value = u16::from_str_radix(&hex, 16).map_err(|_| (*incr, BAD_UNICODE))?; ++ let value = std::char::from_u32(value as u32).ok_or((*incr, BAD_UNICODE))?; ++ ++ let mut buffer = [0; 4]; ++ result.extend(value.encode_utf8(&mut buffer).as_bytes()); ++ *incr += 4; ++ } ++ _ => { ++ return Err((*incr, "Error parsing invalid string escape sequence.")); ++ } ++ } ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ return Err((*incr, "Error parsing string escape sequence.")); ++ } ++ ++ Ok(()) ++ } ++ ++ fn parse_number(input: &[u8], incr: &mut usize) -> Result { ++ let mut result = String::new(); ++ ++ loop { ++ match input[*incr] as char { ++ ',' | ']' | '}' | '\r' | '\n' | '\t' | ' ' => { ++ break; ++ } ++ c => { ++ result.push(c); ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ match result.parse::() { ++ Ok(num) => { ++ return Ok(Json::NUMBER(num)); ++ } ++ Err(_) => { ++ return Err((*incr, "Error parsing number.")); ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ match result.parse::() { ++ Ok(num) => { ++ return Ok(Json::NUMBER(num)); ++ } ++ Err(_) => { ++ return Err((*incr, "Error parsing number.")); ++ } ++ } ++ } ++ ++ fn parse_bool(input: &[u8], incr: &mut usize) -> Result { ++ let mut result = String::new(); ++ ++ loop { ++ match input[*incr] as char { ++ ',' | ']' | '}' | '\r' | '\n' | '\t' | ' ' => { ++ break; ++ } ++ c => { ++ result.push(c); ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ if result == "true" { ++ return Ok(Json::BOOL(true)); ++ } ++ ++ if result == "false" { ++ return Ok(Json::BOOL(false)); ++ } ++ ++ return Err((*incr, "Error parsing bool.")); ++ } ++ } ++ } ++ } ++ ++ if result == "true" { ++ return Ok(Json::BOOL(true)); ++ } ++ ++ if result == "false" { ++ return Ok(Json::BOOL(false)); ++ } ++ ++ return Err((*incr, "Error parsing bool.")); ++ } ++ ++ fn parse_null(input: &[u8], incr: &mut usize) -> Result { ++ let mut result = String::new(); ++ ++ loop { ++ match input[*incr] as char { ++ ',' | ']' | '}' | '\r' | '\n' | '\t' | ' ' => { ++ break; ++ } ++ c => { ++ result.push(c); ++ ++ *incr += 1; ++ ++ if *incr >= input.len() { ++ if result == "null" { ++ return Ok(Json::NULL); ++ } else { ++ return Err((*incr, "Error parsing null.")); ++ } ++ } ++ } ++ } ++ } ++ ++ if result == "null" { ++ return Ok(Json::NULL); ++ } else { ++ return Err((*incr, "Error parsing null.")); ++ } ++ } ++} ++ ++#[cfg(test)] ++mod tests; +diff --git a/vendor/another_json_minimal/src/tests.rs b/vendor/another_json_minimal/src/tests.rs +new file mode 100644 +index 00000000..3b351c1d +--- /dev/null ++++ b/vendor/another_json_minimal/src/tests.rs +@@ -0,0 +1,658 @@ ++//Copyright 2020 36den ++//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: ++//The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ++//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++use super::*; ++ ++#[test] ++fn test_make_json() { ++ let mut json = Json::new(); ++ ++ let greeting = Json::OBJECT { ++ name: String::from("Greeting"), ++ ++ value: Box::new(Json::STRING(String::from("Hello, world!"))), ++ }; ++ ++ json.add(greeting); ++ ++ let mut days_in_the_week = Json::OBJECT { ++ name: String::from("Days in the week"), ++ ++ value: Box::new(Json::JSON(Vec::new())), ++ }; ++ ++ let mut days = Json::ARRAY(Vec::new()); ++ ++ days.add(Json::STRING(String::from("Monday"))) ++ .add(Json::STRING(String::from("Tuesday"))) ++ .add(Json::STRING(String::from("Wednesday"))) ++ .add(Json::STRING(String::from("Thursday"))) ++ .add(Json::STRING(String::from("Friday"))) ++ .add(Json::STRING(String::from("Saturday"))) ++ .add(Json::STRING(String::from("Sunday"))); ++ ++ days_in_the_week ++ .add(Json::OBJECT { ++ name: String::from("Total number of days"), ++ ++ value: Box::new(Json::NUMBER(7.0)), ++ }) ++ .add(Json::OBJECT { ++ name: String::from("They are called"), ++ ++ value: Box::new(days), ++ }); ++ ++ json.add(days_in_the_week); ++ ++ let mut conclusion = Json::OBJECT { ++ name: String::from("Conclusion"), ++ ++ value: Box::new(Json::JSON(Vec::new())), ++ }; ++ ++ conclusion ++ .add(Json::OBJECT { ++ name: String::from("Minimal in my opinion"), ++ ++ value: Box::new(Json::BOOL(true)), ++ }) ++ .add(Json::OBJECT { ++ name: String::from("How much I care about your opinion"), ++ ++ value: Box::new(Json::NULL), ++ }) ++ .add(Json::OBJECT { ++ name: String::from("Comment"), ++ ++ value: Box::new(Json::STRING(String::from(";)"))), ++ }); ++ ++ json.add(conclusion); ++ ++ assert_eq!( ++ "{\"Greeting\":\"Hello, world!\",\"Days in the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Conclusion\":{\"Minimal in my opinion\":true,\"How much I care about your opinion\":null,\"Comment\":\";)\"}}", ++ &json.print() ++ ) ++} ++ ++#[test] ++fn test_get_mut() { ++ let mut json = Json::new(); ++ ++ json.add(Json::OBJECT { ++ name: String::from("Greeting"), ++ ++ value: Box::new(Json::STRING(String::from("Hello, world!"))), ++ }); ++ ++ match json.get_mut("Greeting") { ++ Some(json) => match json { ++ Json::OBJECT { name: _, value } => match value.unbox_mut() { ++ Json::STRING(val) => { ++ assert_eq!("Hello, world!", val); ++ ++ val.push_str(" How are you?"); ++ ++ assert_eq!("Hello, world! How are you?", val); ++ } ++ _ => { ++ panic!("Expected `Json::STRING`!!!"); ++ } ++ }, ++ _ => { ++ panic!("Expected `Json::OBJECT`!!!"); ++ } ++ }, ++ None => { ++ panic!("Not found!!!"); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_number() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_number(b"36.36", &mut incr) { ++ Ok(json) => match json { ++ Json::NUMBER(val) => { ++ assert_eq!(val, 36.36); ++ } ++ json => { ++ panic!("Expected Json::NUMBER but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_bool() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_bool(b"true", &mut incr) { ++ Ok(json) => match json { ++ Json::BOOL(val) => { ++ assert_eq!(val, true); ++ } ++ json => { ++ panic!("Expected Json::BOOL but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++ ++ incr = 0; ++ ++ match Json::parse_bool(b"false", &mut incr) { ++ Ok(json) => match json { ++ Json::BOOL(val) => { ++ assert_eq!(val, false); ++ } ++ json => { ++ panic!("Expected Json::BOOL but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_null() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_null(b"null", &mut incr) { ++ Ok(json) => match json { ++ Json::NULL => {} ++ json => { ++ panic!("Expected Json::NULL but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_array() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_array( ++ b"[1,\"two\",true,[\"array\",[\"another one\",[\"another one\",1.5]]]]", ++ &mut incr, ++ ) { ++ Ok(json) => match json { ++ Json::ARRAY(vals) => { ++ assert_eq!(vals.len(), 4); ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_json() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_json(b"{\"on\",\"off\"}", &mut incr) { ++ Ok(json) => match json { ++ Json::JSON(vals) => { ++ assert_eq!(vals.len(), 2); ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_json_2() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_json( ++ b"{\"on\",\"off\",\"OBJECT\":{\"ARRAY\":[\"on\",\"off\"]},\"on or off?\"}", ++ &mut incr, ++ ) { ++ Ok(json) => match json { ++ Json::JSON(vals) => { ++ assert_eq!(vals.len(), 4); ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_object() { ++ let mut incr: usize = 0; ++ ++ match Json::parse_string(b"\"String\":\"Value\"", &mut incr) { ++ Ok(json) => match json { ++ Json::OBJECT { name, value } => { ++ assert_eq!(name, "String"); ++ ++ match value.unbox() { ++ Json::STRING(val) => { ++ assert_eq!(val, "Value"); ++ } ++ json => { ++ panic!("Expected Json::STRING but found {:?}", json); ++ } ++ } ++ } ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}", json); ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse() { ++ match Json::parse(b"{\"Greeting\":\"Hello, world!\",\"Days in the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Minimal in my opinion\":true,\"How much I care about your opinion\":null}") { ++ Ok(json) => { ++ match json { ++ Json::JSON(values) => { ++ assert_eq!(values.len(),4); ++ ++ match &values[0] { ++ Json::OBJECT { name, value } => { ++ assert_eq!("Greeting",name); ++ ++ match value.unbox() { ++ Json::STRING(val) => { ++ assert_eq!("Hello, world!",val); ++ }, ++ json => { ++ panic!("Expected Json::STRING but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}",json); ++ } ++ } ++ ++ match &values[1] { ++ Json::OBJECT { name, value } => { ++ assert_eq!("Days in the week",name); ++ ++ match value.unbox() { ++ Json::JSON(values) => { ++ assert_eq!(values.len(),2); ++ ++ match &values[0] { ++ Json::OBJECT { name, value } => { ++ assert_eq!("Total number of days",name); ++ ++ match value.unbox() { ++ Json::NUMBER(num) => { ++ assert_eq!(*num,7.0); ++ }, ++ json => { ++ panic!("Expected Json::NUMBER but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}",json); ++ } ++ } ++ ++ match &values[1] { ++ Json::OBJECT { name, value } => { ++ assert_eq!("They are called",name); ++ ++ match value.unbox() { ++ Json::ARRAY(vals) => { ++ assert_eq!(vals.len(),7); ++ ++ for n in 0..7 { ++ match &vals[n] { ++ Json::STRING(val) => { ++ match val.as_bytes() { ++ b"Monday" => { ++ ++ }, ++ b"Tuesday" => { ++ ++ }, ++ b"Wednesday" => { ++ ++ }, ++ b"Thursday" => { ++ ++ }, ++ b"Friday" => { ++ ++ }, ++ b"Saturday" => { ++ ++ }, ++ b"Sunday" => { ++ ++ }, ++ d => { ++ panic!("\"{:?}\" is not a day of the week!!",d); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::STRING but found {:?}",json); ++ } ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::JSON but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}",json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::JSON but found {:?}",json); ++ } ++ } ++ }, ++ Err(e) => { ++ parse_error(e); ++ } ++ } ++} ++ ++#[test] ++fn test_parse_2() { ++ #[allow(unused_assignments)] ++ ++ let json = match Json::parse(b"{\"Greeting\":\"Hello, world!\",\"Days of the week\":{\"Total number of days\":7,\"They are called\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]},\"Conclusion\":{\"Minimal in my opinion\":true,\"How much I care about your opinion\":null,\"Comment\":\";)\"}}") { ++ Ok(json) => { ++ json ++ }, ++ Err( (position,message) ) => { ++ panic!("`{}` at position `{}`!!!",message,position); ++ } ++ }; ++ ++ match json.get("Greeting") { ++ Some(json) => match json { ++ Json::OBJECT { name: _, value } => match value.unbox() { ++ Json::STRING(val) => { ++ assert_eq!("Hello, world!", val); ++ } ++ json => { ++ panic!("Expected Json::STRING but found {:?}", json); ++ } ++ }, ++ json => panic!("Expected Json::JSON but found {:?}!!!", json), ++ }, ++ None => { ++ panic!("Couln't find Greeting. How rude!"); ++ } ++ } ++ ++ match json.get("Days of the week") { ++ // Hint: You can also use `get_mut` to aid in editing/creating jsons... ++ Some(json) => match json { ++ Json::OBJECT { name: _, value } => match value.unbox() { ++ Json::JSON(values) => { ++ assert_eq!(values.len(), 2); ++ ++ match &values[0] { ++ Json::OBJECT { name, value: _ } => { ++ assert_eq!("Total number of days", name); ++ } ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!", json); ++ } ++ } ++ ++ match &values[1] { ++ Json::OBJECT { name, value: _ } => { ++ assert_eq!("They are called", name); ++ } ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!", json); ++ } ++ } ++ } ++ json => { ++ panic!("Expected Json::JSON but found {:?}!!!", json); ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!", json); ++ } ++ }, ++ None => { ++ panic!("Days of the week not found!"); ++ } ++ } ++} ++ ++#[test] ++fn parse_strange() { ++ let json = match Json::parse(b"[0,{\"hello\":\"world\",\"what's\":\"up?\"}]") { ++ Ok(json) => json, ++ Err((pos, msg)) => { ++ panic!("`{}` at position {}", msg, pos); ++ } ++ }; ++ ++ match json { ++ Json::ARRAY(vals) => { ++ assert_eq!(vals.len(), 2); ++ ++ match &vals[0] { ++ Json::NUMBER(n) => { ++ assert_eq!(*n, 0.0); ++ } ++ json => { ++ panic!("Expected Json::NUMBER but found {:?}!!!", json); ++ } ++ } ++ ++ match &vals[1] { ++ Json::JSON(vals) => { ++ assert_eq!(2, vals.len()); ++ ++ match &vals[0] { ++ Json::OBJECT { name, value: _ } => { ++ assert_eq!("hello", name); ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}!!!", json); ++ } ++ } ++ ++ match &vals[1] { ++ Json::OBJECT { name, value: _ } => { ++ assert_eq!("what's", name); ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}!!!", json); ++ } ++ } ++ } ++ json => { ++ panic!("Expected Json::JSON but found {:?}!!!", json); ++ } ++ } ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}!!!", json); ++ } ++ } ++} ++ ++#[test] ++fn parse_escape_sequence() { ++ let json = match Json::parse(br#""a \" \/ \b \f \n \r \t \u2764 z""#) { ++ Ok(json) => json, ++ Err((pos, msg)) => { ++ panic!("`{}` at position {}", msg, pos); ++ } ++ }; ++ ++ match json { ++ Json::STRING(string) => { ++ assert_eq!(string, "a \" / \u{8} \u{c} \n \r \t ❤ z"); ++ } ++ json => { ++ panic!("Expected Json::STRING but found {:?}!!!", json); ++ } ++ } ++} ++ ++#[test] ++fn parse_escape_sequence_in_array() { ++ let json = match Json::parse(br#"["\"foo"]"#) { ++ Ok(json) => json, ++ Err((pos, msg)) => { ++ panic!("`{}` at position {}", msg, pos); ++ } ++ }; ++ ++ match json { ++ Json::ARRAY(vals) => { ++ assert_eq!(vals.len(), 1); ++ ++ match &vals[0] { ++ Json::STRING(n) => { ++ assert_eq!(*n, "\"foo"); ++ } ++ json => { ++ panic!("Expected Json::STRING but found {:?}!!!", json); ++ } ++ } ++ } ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}!!!", json); ++ } ++ } ++} ++ ++#[test] ++fn parse_non_ascii() { ++ let json = match Json::parse(r#""a ❤ z""#.as_bytes()) { ++ Ok(json) => json, ++ Err((pos, msg)) => { ++ panic!("`{}` at position {}", msg, pos); ++ } ++ }; ++ ++ match json { ++ Json::STRING(string) => { ++ assert_eq!(string, "a ❤ z"); ++ } ++ json => { ++ panic!("Expected Json::STRING but found {:?}!!!", json); ++ } ++ } ++} ++ ++#[test] ++fn parse_pretty() { ++ let json = match Json::parse(b"{\r\n\t\"Array\": [\r\n\t\t\"First\" ,\r\n\r\n\t\t2 ,\r\n\r\n\t\t[\"Three\"] ,\r\n\r\n\t\t3.6\r\n\t],\r\n\t{\r\n\r\n\t\t\"Sub-Object\": \"Hello, world!\"\r\n\t}\r\n}") { ++ Ok(json) => json, ++ Err((pos, msg)) => { ++ panic!("`{}` at position {}", msg, pos); ++ } ++ }; ++ ++ match json { ++ Json::JSON(values) => { ++ ++ match values[0].unbox() { ++ Json::OBJECT { name, value } => { ++ assert_eq!(name,"Array"); ++ ++ match value.unbox() { ++ Json::ARRAY(values) => { ++ assert_eq!(values.len(),4); ++ }, ++ json => { ++ panic!("Expected Json::ARRAY but found {:?}!!!", json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!", json); ++ } ++ } ++ ++ match values[1].unbox() { ++ Json::JSON(values) => { ++ ++ match values[0].unbox() { ++ Json::OBJECT { name, value } => { ++ assert_eq!(name,"Sub-Object"); ++ ++ match value.unbox() { ++ Json::STRING(value) => { ++ assert_eq!(value,"Hello, world!"); ++ }, ++ json => { ++ panic!("Expected Json::STRING but found {:?}!!!", json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::OBJECT but found {:?}!!!", json); ++ } ++ } ++ ++ }, ++ json => { ++ panic!("Expected Json::Json but found {:?}!!!", json); ++ } ++ } ++ }, ++ json => { ++ panic!("Expected Json::JSON but found {:?}!!!", json); ++ } ++ } ++} ++ ++fn parse_error((pos, msg): (usize, &str)) { ++ panic!("`{}` at position `{}`!!!", msg, pos); ++} +-- +2.27.0 + diff --git a/patch/0003-remove-unused-code-and-comments.patch b/patch/0003-remove-unused-code-and-comments.patch new file mode 100644 index 0000000..47ed2b4 --- /dev/null +++ b/patch/0003-remove-unused-code-and-comments.patch @@ -0,0 +1,116 @@ +From ed978016ca2d2619e5473cf998515e606d1324d8 Mon Sep 17 00:00:00 2001 +From: meilier +Date: Fri, 5 Aug 2022 15:05:42 +0800 +Subject: [PATCH 1/6] remove unused code and comments + +--- + src/function_store/module_store.rs | 17 +---------------- + src/main.rs | 14 -------------- + src/wrapper/environment.rs | 7 ++----- + 3 files changed, 3 insertions(+), 35 deletions(-) + +diff --git a/src/function_store/module_store.rs b/src/function_store/module_store.rs +index cac3027..12616a6 100644 +--- a/src/function_store/module_store.rs ++++ b/src/function_store/module_store.rs +@@ -1,8 +1,3 @@ +-/*! +-Registries allow you to define "well-known" modules in the &environment that can be looked up by +-name and version. +-*/ +- + use anyhow::{anyhow, Result}; + use std::{collections::HashMap, sync::Arc, sync::RwLock}; + use tracing::info; +@@ -24,10 +19,7 @@ impl ModuleStore { + } + } + +- /// Insert module into the registry under a specific name, version and wasi capabilites. +- /// +- /// The version needs to be a correct semver string (e.g "1.2.3-alpha3") or the insertion will +- /// fail. If the exact same version and name exists it will be overwritten. ++ /// Insert module into the ModuleStore under a specific name, module and wasi capabilites. + pub fn insert(&self, name: &str, module: Module, wasi_cap: bool) -> Result<()> { + let mut writer = self.module_store.write().unwrap(); + +@@ -44,9 +36,6 @@ impl ModuleStore { + Ok(()) + } + +- /// Remove module under name & version from registry +- /// +- /// Exact version matching is used for lookup. + pub fn remove(&self, name: &str) -> Result<()> { + let mut writer = self.module_store.write().unwrap(); + +@@ -113,8 +102,4 @@ impl ModuleEntry { + pub fn capability(&self) -> bool { + self.wasi_cap + } +- +- fn all(&self) -> ModuleEntry { +- self.clone() +- } + } +diff --git a/src/main.rs b/src/main.rs +index c4e7ec0..450910d 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -1,5 +1,4 @@ + use anyhow::Context; +-use clap::Parser; + use serde::Deserialize; + use std::{collections::HashMap, error::Error}; + use tracing::{info, instrument, Level}; +@@ -23,22 +22,9 @@ lazy_static::lazy_static! { + ]); + } + +-#[derive(Parser, Debug)] +-#[clap(about, version, author)] +-struct Args { +- /// Log level used in wasm-engine, TRACE: 0, DEBUG: 1, INFO: 2(Default), WARN: 3, ERROR: 4 +- #[clap(short, long, default_value = "2")] +- log_level: u8, +- +- /// dir that contains preload apps +- #[clap(short, long)] +- preload_apps: Option, +-} +- + #[instrument] + #[tokio::main] + async fn main() -> Result<(), Box> { +- let args = Args::parse(); + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .try_init()?; +diff --git a/src/wrapper/environment.rs b/src/wrapper/environment.rs +index b7ea873..bb9bde7 100644 +--- a/src/wrapper/environment.rs ++++ b/src/wrapper/environment.rs +@@ -12,10 +12,7 @@ pub const UNIT_OF_COMPUTE_IN_INSTRUCTIONS: u64 = 100_000; + /// Environments let us set limits on instances: + /// * Memory limits + /// * Compute limits +-/// * Access to host functions +-/// +-/// They also define the set of plugins. Plugins can be used to modify loaded Wasm modules. +-/// Plugins are WIP and not well documented. ++/// * Access to modules + #[derive(Clone)] + pub struct Environment { + runtime: WasmtimeRuntime, +@@ -36,7 +33,7 @@ impl Environment { + &self.runtime + } + +- pub fn registry(&self) -> &ModuleStore { ++ pub fn store(&self) -> &ModuleStore { + &self.store + } + } +-- +2.27.0 + diff --git a/patch/0004-pull_wasm-return-result-do-not-panic.patch b/patch/0004-pull_wasm-return-result-do-not-panic.patch new file mode 100644 index 0000000..dc57ccc --- /dev/null +++ b/patch/0004-pull_wasm-return-result-do-not-panic.patch @@ -0,0 +1,56 @@ +From 0ce3f371a26deaf1c29a71af2fc7cfb8e5c25451 Mon Sep 17 00:00:00 2001 +From: meilier +Date: Fri, 5 Aug 2022 00:59:24 +0800 +Subject: [PATCH 2/6] pull_wasm return result, do not panic + +--- + src/function_store/pull.rs | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/function_store/pull.rs b/src/function_store/pull.rs +index 40bbc15..2ba4185 100644 +--- a/src/function_store/pull.rs ++++ b/src/function_store/pull.rs +@@ -1,3 +1,4 @@ ++use anyhow::Result; + use flate2::read; + use oci_distribution::{manifest, secrets::RegistryAuth, Client, Reference}; + use tar::Archive; +@@ -21,7 +22,7 @@ pub async fn pull_wasm( + auth: &RegistryAuth, + reference: &Reference, + output: &str, +-) { ++) -> Result<()> { + info!(?reference, ?output, "pulling wasm module"); + + let image_content = client +@@ -31,19 +32,22 @@ pub async fn pull_wasm( + vec![manifest::IMAGE_DOCKER_LAYER_GZIP_MEDIA_TYPE], + ) + .await +- .expect("Cannot pull Wasm module") ++ .map_err(|err| anyhow::format_err!("Cannot pull Wasm module {}", err))? + .layers + .into_iter() + .next() + .map(|layer| layer.data) +- .expect("No data found"); ++ .ok_or(anyhow::format_err!("No data found"))?; + + // webassembly oci spec definition: https://github.com/solo-io/wasm/spec + // for IMAGE_DOCKER_LAYER_GZIP_MEDIA_TYPE, we need to unzip iamge_content + // into raw wasm file + let gz = read::GzDecoder::new(&image_content[..]); + let mut archive = Archive::new(gz); +- archive.unpack(output).expect("Cannot write to file"); ++ archive ++ .unpack(output) ++ .map_err(|err| anyhow::format_err!("Cannot write to file: {}", err))?; + + info!("Wasm module successfully written to {}", output); ++ Ok(()) + } +-- +2.27.0 + diff --git a/patch/0005-wasmengine-could-pull-public-https-repository-image.patch b/patch/0005-wasmengine-could-pull-public-https-repository-image.patch new file mode 100644 index 0000000..22f6700 --- /dev/null +++ b/patch/0005-wasmengine-could-pull-public-https-repository-image.patch @@ -0,0 +1,65 @@ +From 3382e85c5be6fcf9bf79bf618eca7672b150543c Mon Sep 17 00:00:00 2001 +From: meilier +Date: Fri, 5 Aug 2022 01:00:34 +0800 +Subject: [PATCH 3/6] wasmengine could pull public https' repository image + +--- + src/function_store/local_store.rs | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/src/function_store/local_store.rs b/src/function_store/local_store.rs +index d68c451..2afcd96 100644 +--- a/src/function_store/local_store.rs ++++ b/src/function_store/local_store.rs +@@ -1,5 +1,6 @@ + use super::pull; + use anyhow::{anyhow, Ok, Result}; ++use oci_distribution::client::ClientConfig; + use oci_distribution::{secrets::RegistryAuth, Client, Reference}; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; +@@ -100,11 +101,13 @@ impl FunctionStore { + )); + } + +- let mut client = Client::new(pull::build_client_config(true)); +- let reference: Reference = image_name.parse().expect("Not a valid image reference"); ++ let mut client = Client::new(ClientConfig::default()); ++ let reference: Reference = image_name ++ .parse() ++ .map_err(|err| anyhow::format_err!("Not a valid image reference: {}", err))?; + + // pull the wasm image into the local func_store_path +- pull::pull_wasm( ++ let pull_result = pull::pull_wasm( + &mut client, + &RegistryAuth::Anonymous, + &reference, +@@ -112,6 +115,24 @@ impl FunctionStore { + ) + .await; + ++ if !pull_result.is_ok() { ++ let mut client = Client::new(pull::build_client_config(true)); ++ pull::pull_wasm( ++ &mut client, ++ &RegistryAuth::Anonymous, ++ &reference, ++ func_store_dir.as_str(), ++ ) ++ .await ++ .map_err(|err| { ++ anyhow::format_err!( ++ "Pull image both failed with https auth: {}, and insecure http: {}", ++ pull_result.unwrap_err(), ++ err ++ ) ++ })?; ++ } ++ + // only one wasm module file should be in the func_store_dir + if read_dir(func_store_dir.clone()).unwrap().count() != 1 { + return Err(anyhow!( +-- +2.27.0 + diff --git a/patch/0006-wasi-use-json-as-args-for-consistent-wasm-function-i.patch b/patch/0006-wasi-use-json-as-args-for-consistent-wasm-function-i.patch new file mode 100644 index 0000000..3716445 --- /dev/null +++ b/patch/0006-wasi-use-json-as-args-for-consistent-wasm-function-i.patch @@ -0,0 +1,83 @@ +From e47f84d178d3f63b45e84c576b0f690b553f2135 Mon Sep 17 00:00:00 2001 +From: meilier +Date: Fri, 5 Aug 2022 01:02:28 +0800 +Subject: [PATCH 4/6] wasi use json as args for consistent wasm function invoke + +--- + .../authentication-wasi/src/main.rs | 18 ++++++++++++------ + src/wrapper/wasmtime_runtime.rs | 10 ++++------ + 2 files changed, 16 insertions(+), 12 deletions(-) + +diff --git a/experiments/application/authentication-wasi/src/main.rs b/experiments/application/authentication-wasi/src/main.rs +index df00eae..91b7a87 100644 +--- a/experiments/application/authentication-wasi/src/main.rs ++++ b/experiments/application/authentication-wasi/src/main.rs +@@ -10,14 +10,20 @@ struct Response { + + fn main() { + let args: Vec = env::args().collect(); +- if args.len() != 3 { +- eprintln!("usage: authentication "); ++ if args.len() != 1 { ++ eprintln!("too many args"); + return; + } + +- let arg_uri = &args[0]; +- let arg_body = &args[1]; +- let arg_secret = &args[2]; ++ let json = match Json::parse(&args[0].as_bytes()) { ++ Ok(json) => json, ++ Err((position, message)) => { ++ panic!("`{}` at position `{}`!!!", position, message); ++ } ++ }; ++ let arg_uri = json.get("arg_uri").unwrap().print(); ++ let arg_body = json.get("arg_body").unwrap().print(); ++ let arg_secret = json.get("arg_secret").unwrap().print(); + + let arg_func = "argfunc"; + let content = format!("{}#{}#{}", arg_uri, arg_body, arg_func); +@@ -36,7 +42,7 @@ fn main() { + + let mut r: Response = Response::default(); + let html: String; +- if &hash == arg_secret { ++ if hash == arg_secret { + r.status = "200".to_string(); + html = "

Auth Pass!

hash ".to_owned() + &hash + "

"; + r.body = html; +diff --git a/src/wrapper/wasmtime_runtime.rs b/src/wrapper/wasmtime_runtime.rs +index 415dd57..6d5e9cc 100644 +--- a/src/wrapper/wasmtime_runtime.rs ++++ b/src/wrapper/wasmtime_runtime.rs +@@ -64,11 +64,8 @@ impl WasmtimeRuntime { + } + let stdout = WritePipe::new_in_memory(); + wasi = wasi.stdout(Box::new(stdout.clone())); +- let mut args: Vec = Vec::new(); +- for (_, v) in data { +- args.push(v); +- } +- wasi = wasi.args(&args)?; ++ let serialized = serde_json::to_string(&data)?; ++ wasi = wasi.args(&[serialized])?; + for preopen_dir_path in self.config.preopened_dirs() { + let preopen_dir = Dir::open_ambient_dir(preopen_dir_path, ambient_authority())?; + wasi = wasi.preopened_dir(preopen_dir, preopen_dir_path)?; +@@ -128,10 +125,11 @@ impl WasmtimeRuntime { + //let wasm_function = instance.get_func(&mut store, function).unwrap(); + let wasm_function = + instance.get_typed_func::<(i32, i32), (i32, i32), _>(&mut store, function)?; ++ + if serialized.len() > WASM_PAGE_SIZE as usize { + return Err(anyhow!("input args size larger than {}", WASM_PAGE_SIZE)); + } +- ++ info!("serialized.len() is {}", serialized.len() as usize); + let memory = instance + .get_memory(&mut store, "memory") + .ok_or(anyhow::format_err!("failed to find `memory` export"))?; +-- +2.27.0 + diff --git a/patch/0007-integration-test-init-for-wasmengine.patch b/patch/0007-integration-test-init-for-wasmengine.patch new file mode 100644 index 0000000..eb584a7 --- /dev/null +++ b/patch/0007-integration-test-init-for-wasmengine.patch @@ -0,0 +1,23659 @@ +From 0b9677ed8967cb77707b3762e51144a5a5e13c4a Mon Sep 17 00:00:00 2001 +From: meilier +Date: Fri, 5 Aug 2022 01:04:08 +0800 +Subject: [PATCH 5/6] integration test init for wasmengine + +--- + .gitignore | 1 + + Cargo.lock | 7 +++ + Cargo.toml | 2 + + Makefile | 14 ++++- + tests/authentication-wasi.wasm | Bin 0 -> 2103848 bytes + tests/authentication.wasm | Bin 0 -> 1821403 bytes + tests/store.rs | 102 +++++++++++++++++++++++++++++++++ + tests/wasmtime.rs | 74 ++++++++++++++++++++++++ + 8 files changed, 197 insertions(+), 3 deletions(-) + create mode 100755 tests/authentication-wasi.wasm + create mode 100755 tests/authentication.wasm + create mode 100644 tests/store.rs + create mode 100644 tests/wasmtime.rs + +diff --git a/.gitignore b/.gitignore +index 01b1f25..3c31371 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -2,3 +2,4 @@ + .vscode + *.swp + target ++target-cover +diff --git a/Cargo.lock b/Cargo.lock +index f79ad85..df6be98 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -41,6 +41,12 @@ version = "0.0.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "ec8ad6edb4840b78c5c3d88de606b22252d552b55f3a4699fbb10fc070ec3049" + ++[[package]] ++name = "another_json_minimal" ++version = "0.0.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "77ba8341e1396c8a379f62de1b47f31256f2fe0846f5f95e9c60014d2102d9bd" ++ + [[package]] + name = "ansi_term" + version = "0.12.1" +@@ -2762,6 +2768,7 @@ dependencies = [ + name = "wasm_engine" + version = "0.1.0" + dependencies = [ ++ "another_json_minimal", + "anyhow", + "clap 3.2.8", + "criterion", +diff --git a/Cargo.toml b/Cargo.toml +index 716bb32..c92a4a1 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -34,6 +34,8 @@ anyhow = "1.0.44" + + [dev-dependencies] + criterion = "0.3" ++another_json_minimal = "0.0.2" ++ + + [[bench]] + name = "benchmark" +diff --git a/Makefile b/Makefile +index 170d5b3..de63f05 100644 +--- a/Makefile ++++ b/Makefile +@@ -3,8 +3,8 @@ RUST_SCRIPT = $(shell command -v rust-script) + .PHONY: wasm-engine + wasm-engine: + @cargo build --release +- @mv /usr/bin/wasm-engine /usr/bin/wasm-engine-bak +- @cp ./target/release/wasm-engine /usr/bin ++ @mv /usr/bin/wasm_engine /usr/bin/wasm_engine-bak ++ @cp ./target/release/wasm_engine /usr/bin + + .PHONY: apps + apps: +@@ -15,4 +15,12 @@ endif + @cp build.rs run.sh + @chmod +x run.sh + @./run.sh | grep -v cargo:rerun | grep -v cargo:warning | grep -v cargo:rustc-env || true +- @rm -f run.sh +\ No newline at end of file ++ @rm -f run.sh ++ ++.PHONY: cover ++cover: ++ cargo tarpaulin --target-dir target-cover --skip-clean -o Html --output-dir output --exclude-files src/main.rs benches/benchmark.rs target/* tests/ ++ ++.PHONY: cover-clean ++cover-clean: ++ cargo tarpaulin --target-dir target-cover -o Html --output-dir output --exclude-files src/main.rs benches/benchmark.rs target/* tests/ +diff --git a/tests/authentication-wasi.wasm b/tests/authentication-wasi.wasm +new file mode 100755 +index 0000000000000000000000000000000000000000..edc0e1c1e27da55c517532b8b1ed939845e557e4 +GIT binary patch +literal 2103848 +zcmeFa3%p%beeXLT>$UeQ_JK>7U +z@}YIJ*}7@@TlI3jJ!q=_`BAbnZXJH^i#NXPjE%2&@!1<+`dgdMID5lc=e+E!bN`Rd +zi#Pnn#xs87tW8mK4<(jZiH$G&-Lv*yuJixCuo6%%5ZZx=Pw$o-Sjrr3_xr_PN +zPFoZHUz)afrvJLFR@#h{Bx$z&L9@lxgx|%f{)^+uSpPK}tx!ZiZT*+V6KS*A>ont5 +z6i0EZ8B?W^PE7E>hW-d9{EqtS{d9A--JAJoSG8vJcE +zfU2#&8tsO?6Fkkd*=|jwG)QZ-XMgCE(WXg@hppDs)RM+hMlm_rYBjToX0J8TTXx8y +z&9*wG#iZG4EN@J-GF~@o?E(&EMMaJ4w_% +z$K$mt<-0!t}7^haP_95!3&1=I5UEzn%CqKl`7beZnt&Jh?EwAiW^| +z#n;5Q#=me&d{^>6HlKa&@2vmr^EPb!z2DsQyRSIsd4HT-n*RFD@o7JQ%Ja{qdGf*J +zlJt|w7m_a~7pGrJb|zm=wx$=Qlh<6(xj1b`*?n<$MI3KQ)@E1E&(BAL=y_979%T<) +zz)jTcz9)_oUM~EXClo8 +zm2(D6n+75u{?Fi&q5;AhT(xeQ?VUep&*qnHe_oMn0)+PVelyWT#x{`+A8{C}hNl`o +zmn;u>(1_LW{*5^H5x0ySecm|>@|9j>#~?GI{tpCH_@{u#HD2ueTbo$etADh!AJI1uUbsc+4Gk|LsPJO +zy>p{=82pym>GQWA_~yZv=w@N_bqFfhYs2p@=P4uBAGkI9`wNAXyJq5vl09xs*9{`) +z4;p(Un#=w`JjC^`cusP{9&&L^8m&oro=3-|=dDS1X$I{z<+8UqBOCe9RfcegPd04w +z);b@E$Hl~*>=wf&#da}iG^6(qA&#cK@!j#7^nP)~%Ne%6gABxJ<+j=STWo7qTysJR)lKjpk;pNlWH>btega1*5^oQoYsWw`JcCWxA0K3 +zvv&)HB_FLq8f7>8M5&XVR;V*9B$Vuk7LqTy>q!y;DR+$|c0C*UeE0E*c7pt$40 +z9jc)b>5KVPaFp8=?9_5hxL2Fp!mC| +z1QeftN%A7D8BNPfa0r92`CF3^LfbO43UNlHgo@(pr?qtx;TX`e#ej@ +z>6qy6RcVbi(V@*_qVEkKWcJ{(;RCEsN?a<_#jE57#ua)XFsw6~JG0jTz?BWz>j~iq +z_vSEliavvSHSZ`Zr=w5V8H^^yB(SyT@;2`)6Ap_>CN;i3R;atDcs#qXrsq?dr6x{B +zysnr$&HNjRGp6pa{mZca&6dY@GrJYwuPlMb&P=R4_MGgvHba?--k{g3Bfyh$HJ`3Y +zcZ0*?!2}1P*Xb7Kjug)*?v;6+UFRN4^>o+Rr(1=gm5-mJSl5yVgT+r>}U2|_k42zsk3)d}LA!v{_f +ze>8mH1o6S)gP$@AxubkAB#3u1={t=eoWT1XX0S#WKfMRSXp1n~b9rYBVL&W_P$=kIqOk;nS2M8`$$0IA9GNB6NV9-4L3EdED)R=dyQ+ +zpNm#SOEjfM8j!*>qq{{4qCw)GGtr&8GxjQQs%Q>ZD7!$k&h?hVK{r@=SL;LHHSrV_CCQ +zMi3NRag@w5uQvXBY*yR_58nID?(Nb>cKuQ`9M;YbQe05^tVuGOlsBqYhzrAPp7I%H&+n0M)p|$MZtG&=)NZXCR +zcy86%+C}eKbT0d!)~udY%^rvr2tM<_ +z3s|VDfs)if=|hX!|`8qL+4^m^!S(gmAuvRFUkjG8BLfVvlBP5KuzqxHY85tlq3nIy5oT?Nr&( +z4(ql^=mn)whis|c9db^wdn{xX;N?iBSZ#<6P^U~FMS(S#r$M?dk4;%&OT|G^=|vsn +z1p44*&{RZD(Ot-RV5+9Fh`O7G#4uc>0#K0yYg-h?iX=3u`9CHxIc1N6J}n>Rv0Zg2 +zkDBmUn96x546;nBH5bV8MYil6Y#WPW+wWygW*Gk(=v}!jnHr!gRWKNBqk{1AWl-M4)2HJj&(!_UnRp}+hP-cj4%z2|Ma-@V0Pq0K`< +z)J$~rU^yM=YI<-ORq_ei%n!Bx4#^ModN*DEwmXR@ZF-acDqc +zK*j66`sJ68>wa+L`nlo{F8$j39Tx@yk2IQR502Ehd=4F?!BLdH?#g>V4ptqgSm-If +z^07y5WrCXL%7dZK;R53j_)D~uA0~L>oVq+?(u*BmzwkoldLqnq%%e};_Wk!k8cRwn +zcufd3V@{}08IP%o$vwxpS|LNH!eWIrEk9Pogi@m +z1d?zSmjo1i=UuyQVg~9cxcG0b_#{(UL4ahK%d;^ZKXTWf{l;+Q&V2du5qOv6nvuV~ +z_>K=jUk*-esDJev-}Oz%k$#!xWqG`D0LyHgEB^c+UpiMboJckKbe*be7?HOZeCMtY +zQLAgS4Owo4y_fO)`al2Yhv*57;M_5nl;?Dd2?H!DdPDG+} +zKujl)=0-#sY^X}s=)2zbZ(js8bOy($p`CyDoezLjdJ$==SV<2X0cEb({m2jh`S+|R +z$sHbi^wIC!$y`=FEe%Yt5z*;W;XVE9C%1kEG8p!B@t5z|4h7YE3WUGRd%E~fx2>#q +z^e5Xs{Rzrf9ocNzydnO)kFUM|yB{3(!2t7;B{v$D9{K*O9>r4jE(QG8Zhr4OAS>`@ +zoGb?1U{iGGoi|(u8d~KfnYc89+ip;^xYG+C +z{rH~_(VI_7b)&MUoEhra{lJ6Y{wDMmI;9*&FWR%ls*darz2i%tg$%>MDc7MKx;Cg6 +z*PD+1*KU9F15n9f=TfRsU%`i%!V3P5ByPxtz){7pxMedd^Q9rGUluyu9$;}F^T-1d +z_e693W}Z&Py{09t%wcDwGEtipKMf1j*7I?Mm5DMmUA!f;UOG#uSbQXsIV;N^3q@w< +zFi6tOTiKh;HpLfTM@|Xv6vM&}C0V4n@?so;Y`aI9tlRMD_2E$pB*iu>byawjU=@@0 +z13<;v^#dYejbyFoQ!#M5AU^{>4!y?I_Y@6&s~in*jIC6fVz&0$>3%Uu6LM*)G@+eQ +zmHvbXii>hpmz8KC4hTTCI;VS<@;ifszD~jd)UU9p-(u%hjqu8HIJDE7bJ&VV=#X#F +z!Qc||NS>K1=FMo2y-8d#pr(ZNk{G7t)nJuLf)Uy%o|CuMWe>{VIVu2BoJ@$pP0?nF +z28YilN_`c88EUEXJ26fhv*{&@urM#7mQ8Z7%;f<~+X=Zh7`Z=2X*=I0O|(v(_tvRX^dO>G;MX`QLMqvnq7TuK)6q<_ +z)?$XDJ)-2qLn(@PVA(i>cpdId?-j;ZBq=CnMiNV!8lk)2<8eAmV5x`cAgn$yMJ2GL +zmcT-z4Fxe`wG8!)#vtTr;$Q*aYXx7iMWu3O3MtbN20K+bg~&L|Piv_1psD;cq)l@> +zuSlH~3pGM?tfh{KbsUqf)reZgCK3Q#m}4k}5Oh+;VMs?L-7GU8ylj=!gm-SKGdVBG +zd=Z!>5(VTc&{FjJX%Ux+J$XZ}xELXnwjuEVFRI}qTRSjzZp&Xgbw&33E*8m+>XX$e +z!70gnOv-|ZP%ajy>l)~c6vR0Eqd*0agnDKGCvYZN-f#4jLd4~<`ZIF?rxiIviz_`k +z#Z|swV(~dOkW2$H86qrH1JR_D0aOVO&0h#BmD!qy;@(TxWbYGQASRQg-K8depq2OQ +z+0yP2p$v1GX17^6LZeH&B5Z2@z)L+-5JU)U7j}b4(v0{|=F^2)bb6A=#VA+pkyuKi8TadiltM>FMD!tgSs6m*iPmgMqAunyWpFOJt`M277LW6M1`Ol@ +z1FMr68&~n53fHn4Gm96e$3+O-xh2VDcLIK89I|M5xTNh=+}7feJst%#6dKaHVr;Ms +zS&m7uLVAeY*~nH`G))a(1vxZXOKYB08*^m>SrU^@vk#giRCp?^SV`nhzZ_YI7>Tkq +zQOv!sCrWN-+?jMdqFQ0G*cQ?eeD#jdd>%wV+&F&HbGF=Fg*u5~rhtl?OQEUdv{ty){ilUl}8a|}EKcE(^MGY;} +z=$~3_k%=UbBqq18Q>5`sT9iWNp35qsg0{X-ca_vQs0{V^&Yk(_%6i=4X$ +zikv6GzY>%WfHE2(E3KlSHx{ZLfBXd14)*@urM+xo^b^V??7ETKq0^vtSer4mqir`Z +z?H<&Q`3Vcvj&0W}g%T8UPyrdMc19q8jt(jWWBGIh0{I&Ub27%Noe>D2)VkW)pSiEA +zosqV&lT7WjP!jvoFlr($)y_!69r5Wtx9DnTq#7bD_e$>GsXIuS00OTy}uNwMgS2c)mhYS$BtJEE~Q7s|!O+HK#D`kMC +zcZB1Is5D`3x;E#M +zJR3AkQ(0Q_o#Ym=SGV6v*X9JLQUPlKDoEjl^Tbj(yl{@ge$h4`~7_w?Tsp2juvnU{@Hk2M7$WJBKJzFbC0jp +zj~E(TS`(E79I4j&z(UdbzyP(OfeA$nj4FmbZBK5p1Tg<<^UEg0=Y-aLuS`Ie}= +zmD{k}!W=6*EVzlh+r_RCVjhdh&p$3ES-ko&z$9yjd&A`YBbfA9lh!kw2Q9ZWkr)u; +z-CHqU$(6%^8T@7(=K-^6h22Ze6XQ&WFoUy|$RKc3zL=vzTx$%EzO$yWq~Q)p@!fB|_p2>sFFX6glRX@K +z*&@%I>MgEjLR<|DSc!i4!Oy(g>QWmmq`Ej>dTV>G+oq)2y>7SIf>e|c8#G~+W67aI +zjsE=91nk``&Ywe7v3@kYshIxlLAUtumggf&;^JxR`^_F^ezSPxNQuc}tq$oRwNwRy +zh#BdSblUM9HXgr26yn}Hlx8e83!DqdM^*7bbjRE!EuAry;RaLMVSG1xVu(y=6b+csoMMW`|CyvX5xDggL}JpgFNS5!3X?>RLlAZct4z7Oopifk2Wqoc)o+jb^U) +z>^=5Ogfc95t3AU?tUY_LJ){5Hv-jCEA$nN%{d%U1l5#nw`=%vHb9lhXZWg^8CDKe` +zn{pNC?Ca3VK!eqo)UqWKrGZ#RZlgF}`naKqkk!#n*N(&W=re$7nhfX^=guwp?I?<4 +z{SaWR8O$AJ3R3;1e=m+ +z;XChyv;N6;`H;T_IpGd;Q6EC75TEgn7qzh`LaZK7-6a5PFH9_fPqSJlf +znlTJ&!btHmJ^i;_`9Z8`ejluyr=Ha5jGj{`JSV`KN)0Pwu +zN~%^di6h%Gc2V2RPkcCvT3N9wk=T +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 +zg4~XvZ>zH$q9DJNo%W<7tvM9 +zw%P3Kp*OcdunI6rSl@5zlsXLrJ&W1Fc+B$5C)cEE1(TZoMWCzfIJ*VZFW8}dmxH5R +zrTt53v9mP7^G5eSgGv*>kW-v}!{CYRdY514;=o&Ut?g@E&r8#U>qqo_k#`99$Hiq= +zfgQsBZ&^^}BX(aqObj^}j%yuyosU_eyOOcr6iBotQtb?)E8DWA-zWVk0VyB8G*HBS +z|1va^qS&iah9IzZfWCbi +zfaj&^@V(eh=&jD!!~U#1A!BV}8mj4lc+T9EH!ck!s*#g%0ZpRgRKT=QNAn~t +z6m**z$W0!ye-FK)wTsG35D98$I={?K6P6W>!r>S*Q<@=LO&ysjo;C)} +zYNo6Z4nu9GAd~t`abSbA8TW(T<1&LVod(w<72Wb!O7ITp%Wom^@FRyb#1|Px(kHN;E +zv)%S}+5;j{?9r3ss&PZ>I+mMEWdTP@wBS>gwcXlT7I~Y@@?Q`j^sU_*EW4L-RyE{D +zq04RirvqUnt{wrzlVfUtAnS&JXj(-zt?czru$Cd(%lbelq+&si0bD6j +zx<77;;&T!Y{dj~`yPrrB9hM!!6nUj4ipY$5d6Z&5vvyN1H<%8x_T-+{_={INDqaoVE@_lA}$g|>~qV7-4Wq+ZX#bb}9>j%y3 +zD!(CTiBOh9rzw^_;>H|j(_(a?|Ymc +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 +zmAb +za#c!HX@V9^AX0+V6|7;|3N-`?cr$=nW+TO-H;*|!R9}RlxWjMela(q56N?UI9tAp- +zWf$mhC6_@svIeDL9?O#(-estr$zyJ`Dm86a{vlI6n}HZKcqg`al+x<%^{Q%>A0wCL +zpxUB72xfg+MnhPiRu(CZ8d}RoYy?O&m7-EJlZ(sW4s2W^F>jO1M(F6(aU@OJ#`dVV +zO(nE2Kbvf2A;NNR*=Lb(2A$<6hqMi=V)?nIP*#`*8DWVrtTgDv&~E)L-y`#g^1SY<(uC15hZuxAw+69@N`vd?6#C~|CMS!;c1(m|StQ(K-S3+LlSdVYXcJB;%wSPx5|aOY{gW^+_~Oq{ +zW`j|_HrwL|FJ?%(285IDt?w60m84tmszj +z+-CPmjMbO&ANU4V0QnNya1vR2X4DDoVBZ9}>;-kii*zlmu}X}r5(4OQ)|^+VWbFwdSeY=GeXMK6%Ci_9N4pO3g&?(7XrptC7DuVwqQoA +zEjb3tbuxSeyWQdon9Hu@EV{6y6JbJ!!)8j@4^H%TyAu2_Fkgn=$YN=}~IxHg{0S*J-Un*ecE%dhCi!@*zhHEo!h`* +zO4LSfhy|@RPS5^T@R(GuF!P7$(1n-jlsIY}69zTfCtA{o;_?IR9yZfbucROdjIuve +zyWBjx`q10Tx#BIFS+M)xZ@q4Zp3HFhR)5Kd;JDEz-uwe_+K80fvraI45}DPu +zQKnBzxE%^PK`Ttra3ZvBBqgaL0>W^Wh-}sEou1F2Zr|qJ_UHl;xKWwe$)-V6JS29P +zGb5)$?;iSK^}s(vCwLr2LFyE5`a=r_Byr#@@g*@ +zM3J(nNK+~;&OGW)(nfZL@Y?;CW~#k&^^is!2w3!<{iR9`C#<~6V^7eOGNWUcIO6u@ +zgA@WJJmqw&d?00I=9pvXHX(%XLOq{r9-YK(h)1;`t)^Gf#?oy9T$y3eT+&sio=OHK +zo+4#eQ8b<@+eAeu`kLOIMk;^?hs8LoDtDcl^37Y6H0rI2MN|6z9E}4rwihl%hSIgO +zZBmP!brd@zD%i+7+bh7Iw-9VQmtY7sAHkRq8Nq&TUr)&8GKss~P|%-LFL|Sn?1Wdf +zk-4kcn+h!KSx6cxjaEbLG1P9}%csDPGw&1?TZVMgzf2eD-t&$FreB-Ab0KEV +zfJGuxkFPZl0uh9S +zjVj8!Loud@K4@QqE-jPpUyP(Ij}cB9n^v0n=_$Ct{GkwpHY9k2t%zEQOh6i?E9xVW +zH6xiX89zwFDfmc}8K}|xPSL4JEhtt*>ydEDT@zNv@Qu2ra&}E9+e_d_>y9um#xjEK +znB>?s$?;rKY!yGWi#$?Ol0}#zjSU7)HZNa_OYbq^7Pi?-c`Ujz@IY{kYUYG1HHkP)pZlUxBu= +z6o2+{wrhOw0ZO3*f%ZSe0}Vj3Eu1)`=-O2 +zZ;gEu@#dkiZ=TMZ?~Z-5oHx72zB!yX|2XyypH?p(9{XmBH~%vB%}U-pGWN|+7c<4b +zE`Gzx5v)=BzEe +z1lfbO)Dez=|6E)TAmU0iR-!cLBh3)K@gY~DyhFCm)9RxboX}$GrV%zr;csb!POI7+ +z#pLH~a?s?{mNk=xjZfa7c5ZQ01+k$;yKk_}!!{zDB|POG>RWQg3j4mMFi+mGNy^&h +zoVO&S>(p51VQ8~x5e?7(*(zO%_aJo9iMumu2-35N@CfPU4G3=_lZANF@WRuXoD5tQL>oic;qo^Dt6pAH}z*`QLVWn6nm +zN&1)Li!irj4GejX=eC!nsgRl6_>vURfx}hgZJkBtx$sPkW4@C;s7b~lZ +z8HNcsNtJT9UQNB?S}Psm1eLKOsDpuWhA;e!O-d&51^?zcXA~pj`hq_$n227CS|@r9 +z4!S9co*C4jy6;X2ZaJBP$&|xc%Cjf7a3UH15jetj!f@kbrL09Y3qCvzaxpMPj9Ouo +z@#m35Gso<+IC5n$q*}!zW}$06(Z7^skQL|IV4B6*;rFHC_ssD7qVRiq_&vpbTXW$* +zI&aG3poa8t{gKCs&p6GB>S6XrVA +zhk0b$u;>`}K5=Zi*>a|q*q)=*dmot^V#kDVhnpIx%y_bHB4aTqUXPzomD0PUl;P1!)T+DvVLy=TUi8pxZ^NcS>H_LSC}A +zzJXJBwQYx@(#5+rQ8*f}@7gr}A*kHxCk2Pw0S5vmETGt0?g`E&-tzdRTP6~4J*o3LZI%2atiPj9&1nCKKP!-9!#me!D7WMHo13ZkTd +zuig0YZd1KV<=6Jgb`Kzjf6Rfiq?Dg<_)j=oe1Bj$e4E&~;_%^}IAbw~`}>l^ueMa! +z1son~9as*3+f$3fcgG_cR*jWNmHEhR_r1jK_UPgw_)$o9vJ8^n&X%dUUP`LjWBhL6 +z`7+WRl5cn%eyYE15>QN=D59dt(i|K%QwH-?(9&pzu1N^Vj)eENwc?3dY<*$H9l7dA%A--gvaJKcz +zmOyWnU8V{O1t(tTHL$3w@J$EbRb$8})erUq!RvKp+>WR~Jv4+%&IhsQ`aQ;2#;xQ> +zdtIu@&j*BzCRva=U@pZ +zbs6a%GPWdb5vc#M*ot>mGR(&U6Om&AR*79>=&#J{+oW%oG}1;)n7!C-;r^Loo6P8P +zt4R^tS&RjX)N)m#;x)Diz9hR`3Q`Rz*M_K(xf#fM?#S!(ekk6NJV4rz;*=yYiEQWN +zS710t#j2B5c(!dk!`;`v_1>?xPU3VSvAxAsn7A?#3?Nd6K2O+;LIN@QQe9x8h{08) +zTmqub17Q)t#wB3ObT!s$7jLrqE2&UrF^63Q2jpanAN8p-8pPAhI4GF;up$lC%=^9f +zoy=^}&AwSBL}Z`RWk04w4OgE}h7ki+49ixOs)i0xW7+Rl(+{I6lB))oYNddXFJehq +zMbw8v@oR`QYhqBC$t3yRHMJ7}+>Oh~lsiP3UlQWxA1b0Xg +z43gqHO${fxh24PJyPOb?iHzt(rc~P^dC6Lz6N8*u5Jv`=HUx+R53=r1#l9*6ObIP_>E1hFYE-K}z+2 +zXc;Lt*E^Z%0m1YTY2l6}N6~a~`@2DgR|qdxiZhsLq0O$~mKndIV9u4=w%ub)wZN6E +zTRCVfyF`6O3@$w`ns!+S$sE16@Bynq;S^`uz>d`N(6|60D08Mqsv>{Mrd4pPe5fz( +zNO!|vw`&e10~ATM8-cFW8BW9k@{)W~Nl1oTChjt>;_W3%!tp0Y&(TO732E^h<4oCs +zIRj?=c{yBqqHyRbjGM{TxQ%W2Gb-TqK+8+y!&kgTK2UAkb>2e3AGlG0k|!}L27aJM +zCDn0Uv`fO!<_ZkjjdTaZsaXm{85VsY#d5-Kl=yW*Trd@)I|u_0N04Gc?^(7zQT%HW +zYDZ1})InRda7jw!6!xM(PTU}b!+O-nnD(XOe;uw?q77pggh++Il!_{DwWFfGCAyW- +z=_)Myw%tpXAoR4F0J^ln!30B`{gFgS)O~M~=uquoCaoG8IOgl8u(6ONNe3D&r_R$)^+aCzq&gf&c@>*jP_~QAa)4%h%j5D(H=-wo`OaoRS5I*y7rE+ +z5`1KFiLjB8*wiP(k^CZoG@D<@#^#s#E;!dbY!HdjNxG{ct42amv2zqhU43g~(Zf3@ +zhS<`c@1_%P!LAeu&9E3V@Y4ruVMg*?g24{0LlUTv9cQOh426@ZhYYjVTr0)FUaOw| +z5dcDw>7&6Qi6TMt?LvaKp5k++lj&PCH0w#R0H~dV9CO#eUV@ou*F|2xD5H +z2yLghNCaiM48nDaS;1>4pMCwy!%H@c7(jJM);c85c1TX3&egBmAyIZbmzA93-~u(j +znne@~>?d2-nwS#zgbMcYw+CO8pj!7OYR +z_i{35wW`O70A?2gzOE3Q8i<>3mZl-?3||aa{`Fu$CQQQ)viDpLQm<;dt2wmYN{_N? +zo$RU5x{_&BZM1c7Sgo7YX@y9Ot+zg691c4WdcY#>8+ul8A@rCGsc?IypA8{Q-6NBK +zb#l6)2XX9Mju)fncsH9t&+$T!25^Fz%?B7g);bgwT7MGgIbn$Z?hrrYC>MbvGGcGf +z10pzC@gg@#WhW~Ui|!nYA~F$b*kLXdzqumRl6-3@zT49+Ys3gCQi(>LqGu5EnlApX +zD)*T;$@3W9YVMN4nNu50?TTq5@+=m2_XKC`4p(Y4w%3WjvtkiCt@;;NT&e~fmXT8x +zJ{u2X3CbHtRx)ZzA~!4VO?OH5=W4-RIjO1=jfoc3s~cgFEgmHnCDa2JkI$tbI58Th +z-GMxTOSHV&e4#opSukT)@(azWDbcCd@*Yp;7fF=ZhbE;m!?^Tx6tQhYHs(_IHMQ{( +ziUp&&;VFQr(nAT!}hDWC-R+YZehuAL|fP@c|z3!nGotFrkeb}Sc& +zlNukcfpmXoh;8hh3K}|=$MjL5*aRz?bMm9DSGn^ey(Z6!m*`coB&5sLd(~j%ONE}x +zfRE>FPDqgg!v9{zip8PD{zI?bUHMG$TN;55Fq+|e& +z5rVHr`%>`uF&epo7`oBHGUX5ejrJ=r>4BaqFwY!^An!~lV$k$vWFwQuJ3!2;H#+d} +zWv&6xfkkMz7OJWa%z3?Ai0w_5YQqkGps%&xPF79EE;%_6? +z6X;47g%s#Fc&<-{718V#5@K}A<^23sFtUSLkCzB;*i^!5kR-4vv$D+Mi0aW=>0x=h#RX>qNtls9&@U8qYr +zAKUzKxWnX3i+RiPrT#TG%3|sI@|sJ1S^R1}w><83#VHu6d^*k$E)3i!s8%PJsac>& +z9aS)^q0r%bM4-a9w&i-RIDyK+<<-=V{>#}pD&d!`RqGF#xq=+$@u71dkl(I8!ds;0 +z3>xPETWW`nr=%?AjSZX@pjX;{>BC1811?Fe%vZ8jc5r7P3o78Gg*OF=&Eot#IhTW- +ztUI&B$V)MxqtlMUZ)bqY&&MLur%o9OUEqs>1?93wvfF9e@zUTxCrSYP!v=htmO$z197@R{b;;=v9H0&^c%zs +zx{uE(k_GoVx!&J%ob)1W2nAXsT#SO~T$1d^At5y+ATrr$QzF5T>bNM;U|5kINpdV0 +zgEW!KNlp!WJk7 +zp)dN8q3Y2^ez+FXXk!cVhHaTPU)C&_z+=1s +zoy3(>AngMd6IUDc}r= +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 +zs=|Qw$9hKG^mr9QibU=Vu6%4~eXHZsFxUf +z-b6gti&|;~KDwyKbRlbQM!l8)0R)`2UZY+$oa-Aaun~?Fk)Vat+uW1?5!FLZm<${u +z;nYhf<3moo;M)xHKNiNDB-=!4OnT{mC~Q&sAC>q*xC=-~#l@W@Jg5y-7kV4YoJ0cE%bPf&EN^;nliQczV$*UK@vxjQF@bDgekzj}v~g!X2C*qR#mCUG +zH5MZUgplTE{=+cMkN)h*Fh<(k!%BtVu@yKZ`6l{a7$Xf!Z~A;y(1Jt3ROaEhhoL2z +zGG5x$7&KgHv+^+XbuI-mVD@r|8Zfv9^@}5>Qc=o>OEG5czyo7H&p@$-I6;g#EKM35 +z45mLU#NmHgN26W#LeF$b>wJZQ%7$#iId3cf!bm}rpomkq`&NBI%e5Ybw#>br9N4OKY5x*$rdrM3AF)Gd&+QO#3e)0B!)+pkFd2VF +z-jIM0&6Qq*c?JTW0&*O!e1e +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 +zaEp4C<|Vw0rx{eSv2+$|NUgGjAc&2K +zE^T!{u`PbRrL92Q#(2w^sdu-keREG-7VJ@vV-x^+%Ph +zdvF2j0J46E7gz6(+hDBETZ;z2)h$$`)lEz$+I*WYrPxW=E`WgM9{L9$R=Zmp{jD^B +zwY|3Fk!YyRx4F}X$HoLt=$lOa2cYhJIf0se=A{F5x4y{(1rMBExJ?sAev*_X6zU)J +zV1BB~WP4EO+84GMj39)mXaci?65j#ae_?^!ZM;3pY1S}Wv^tti*gNU%$e|ac(@1zB +z4hhePgy*w_=SQaCl&BbriWx*sF8}+0fSPG^Nw{ +z4`lZzlBU|wCBegwN<&p+x8WHpk_YV}CknRf7=M_MmSs7@Fd?6XIfm{m0M(I2vvrd3z7({~kCGrEiR-^*I~(YR4=^Tt +zNc52-tBVip1#R^I`PQi-OjZ$GGq)Py(nVu;9%oN+xk;L|jJSMC4TkQJr?MylpopvzIJ+ie7 +z%GjN3XLyv9@3bC=O4^yV=$?8O2Gzcx#Z1&(O_fD$O{0Spb*qCEciEkeMc8V0tGK(- +z?pAVlo!vUeBua==8E+bz<^yzbL1^AtuO)vwA;AD5F^BP!QOrxDtK@oI6ZJZ +zkOJ2uQHTvd9#;u1AOQye@Am+@6W`$-=J0*ikYEnO^CnT+4GE(DL;kCmNB=zheTe!; +z^P(Or;Oe#_Y}@ECKaL?2j$s@rhj`*X`d!*;ir33pulsP0{QB)it-9oyw**-GQiy6F +zO_KOX@wTBzu81^}X(5@aJB1u+x9_3b8ZwGC-_?>BevIx|%%CxPNuL+!?L*ZgRt}?m +zb$etw1~|e7CMk_w97TuJS)q=JT?~7(Qm$2Wgyl>y;Zzh^P(^wo>ulM5>i0z5y92`& +zl=N^uNnp_~L^SgXV{4FOC1*po0u`k;FvQub^WS9}8GDn-W{FKAk=yLccql$3Pjc<{ +zxQ%qIk1!yX*p&5zb4FsN(6T=4=ntUtU9#YMZ>I!4ML2@F_Ds<#!7};e7H!rMMikAC +z++xqP@6NRUP;($17^==T`-cu3In)?5=As2-R3)dz;B|Zh^DrYTZ3cAuIvu=R!cajn +zQlenYc2E-5+@qbms?xVu?*Kd@zJIOdt0zQ_Fbk@efKQSQSS|0v&cP_oHDkV#cSPN-OoWP4365N%t$Ybd%NMx!LpC5i;_SbuPU^&ZP&yYN3M?o%LYbQNFoa=4?532aLOZiIq-A&e +zK9huL@y?;!-mkS{76?kqYzvJ>!9|8+&T%C3Y#Gm`T%Xjq*s(xOOELFcjAHS2%?N5Sst4s3@J +zwC%-VRcGBxOryRR187XGVlIYkR7wsTb(h1Wm-UbP@}<^3Q%NfD78pj(g4Pd~{mMVD +zX@vMRwk33?r@%3;1yV&}1~pb=gnXh-xNE&;TV;(y4j>R7wGKqSY0Q2zrZXZ3^j)WL +z9)y|e_0hG_Zts5-^MK7U2ucVX5n#|!)vBbzCYtY+U1X|GXeM}r2NbG2VCX;9ZRRKi +zNE}zSWX8h;@S=wYxdlKKI%>}mK>!n|YPrP92HjfqqYB0J;ys~)UeVLLSQ=G9BPCvC +zf8IoGr8X(PUbaM{ERsP}57h}jiJT?+R*`)K@~TenDK#E3R)+^Xn#g3HU4m?INuk`W +zqzk11hJNS6KlQ6mKJxE={&%87X>I7l&wlp#XaDhU|Ki$1&DtG9imkir?qkPiZ#(LH +zdCA>gzE+9?`6O)BHbg?5MTZim6HpZ#N4ANB)huGN?~?JjdMq5yoGR_L)_}T7n|30v +z4T`!cLom(!l<7uM7>NRv1^g5 +zy)^a2gC7;rLvebkzCVSr{~z^$!0k}nJK*K)^dts4;h|X)JNCMFS(ID^_m_zYk#Wev +zMg`iHgdMr&BbZ5*4gJ6j%Hqp66$`mcDLm3aEin*M&) +zAEI*}J3majPs?N&y9fhVftT*D?(5&<>ND<5W3@kt6REiNY)Ek>hTSX(OXK_9A2IYV +zxgQhbgKV7itj%Vrh&%RUpQAjS_(M=^h_gPA@(Cv~73z}9L$?7l+VL*CIUb>gao38G +znbs_Dj`7j7j1*R9a1YF1Qpkz^I3zo2%Y$jpA@gabJvt?d7AsJ~ +z_$m#}Y@-LNWvOmfVxYbgiP&O`=CFa(HfiQ9MaIg!Q4)exBDYr<5KmMgbS5K(2f%@I +z$%%lJx@)i>ko3RULW;hJ!y)3M(qsq}EIcl9n3%}&a=NobVzDAquJA +zHS_|bsgvg&9pW-O`}JPE%aWc{(jzB&jvQinI|!Kl?XRx$Y8+lg_?EHjz@ACbmkQPO +zAn)Y>rR*jo@O#}N6FIomao*5e@TnaXO-QBEprW+LzG*`+FKif9t1YS;4fs&%qX+dN +zxu8vRVQ0>@F7Ey$yPbtf4n>Y;#ds +z2j7UU8=5^U8uhf=91sYL(!P}EK8n%zhABg*6{@L|&^=6p!>eiiFeMF2o;CZ@+95*- +zopmWTrRUr*4Qf3{d|h;VRWc@x?|D)iRu3ghXGBQ^$uK~`%sVwb3$CwPv0K3Srsd~a +z$QNH@DDH=Rd}C&5oON5es<)ej_!jIY!}I;O2`|sy{hxpHj~+bP{~oXqY-rWT1WoT| +z>h2LvA+9)p?H94Q0g{f+%Bm@pu}l%pIgr_DANTscTJ?+6XkgiZRK^zf1zSwc$I!AM +zJr)9ukrjr46t?PN8?R4-ZrG^5mWp^%u*7uNEk21D*+nS>d7inHydbT~Epi>>e}~%` +zpqOz%pSyxX$`X>x@helhVOZyHO78dkP0@YD-xQQG$v>%E?QW4Kwa0pF^*8G-vlS$P +z@HkqSR+V4`5KV9cqFosWi9#g+_IucswZ;lQlVqk$K3uLWygx@%LQJhM`T(*g!f-Y+ +z`>X|oUlW%Lwx()K3v%8B44z+rAQ!aH2rk}G8 +zVI8MnGL)$jtY73qc{Ah@!c_U(Vy#l2Y2l8h5^6>0qd#%&y=|vqJ0eW{(&04p^USb9 +z7SV=eks%0ow1V8=%?nv7Q^33ikT1!p%N27syXA}HkC9scqWCDPZJEDndEbMt(x%=l +zYFbfGa$*A3Ib3*e&PbcPpqjP|^7H4G;ioLGN>nTs+a5H!>7gxWCnxw?_ +z$33gH+jIt{h)dD}1*IkS+&K|5@K2V +z(uG(pBLuPTw?4?wDjUI^8r50ZIe5W#C_jho(o4m**7Fp=Evu~}r^(Rcf+Sx&wpQ7TrNmFsJl$nNvg-0=-Xsu<|!U}k!kjhzJ +zV8XVR0yS2L-V?&#UCvyhQ&+oxd8C5lR=6?#QuPWN6}!|{UL|=d1=M&-fizL7AWFq) +z%{^e0q9=h&>hP56H~UKH6_$-skO*tL(GN{*)F8(P8bu}zDpXVwQ9XG?EF^>^pFA(! +zq)9db-74wMzO>J+BH*CUn}0IssZ1qS)3OM6`=9>WgOwv`6$#cNT%WTEEujwk0ZAwx +z0t5+_w5*(v@N4h;Pv12s#_P|U4wph(v@f79DZ^fE**nh!0sO!Vp|R>hq! +zqE{8BDA$uKNvRtq7!S}C8GD}m{V5C5Ab)=#J?gBxw8C6M*E$H@-y-z!=tU`Q3zu4y +z{0o875a*D|uYCicV-}p|s%>gipuMgfduIYnf-5l`Ozx?q(?9YE=lc*KPvZ(M) +zea<&e|LqIEH<16v;$ka~z`yVfTjg|d+R=~ySu~f|up}iRPbFYd@minuBr#sY{~hu( +zAU`Fq_547*Hfy`RcFO+#yn$12139VE?;bT?EMTq>7IS`>0}Pm<(YwR+2U;uVL$k*&%a_JUa(K*^1^f9dGr}E +zLy%NeXS>W*ocvH?2T{A5e}4IqKloTqx>a4pH%qe{{+n~=eDkeue)i)XysaJlU^Y4B +z{5R>GZ|?f^zdzQOhpp={`LkdD@3s6lHUCYm_06g|-~80`U;Y*5`r0_? +z^WXHfzF9rzo1UaglgY6j?aTB`vnZj_Qnjj?8L +zl}f=AajMREmhX(0gw8m)U}tRU{UG=UPOCHacL@HrhM%>408qb*0LvL;Hc@XDkeOr! +zw<6ai2i=GNL?+pa&MsLO<;^71m{^KlO1_ThH;cO`9rT8HBUTb21jwk=2AgSBc9~4D +zh8)@`{+_hotaKelfISE5km7xqYdQr%?geJjP;dRaZG?<6Xe{Cj65OiIE2z6Mkk%fw +zP?}!%#F5~H9YA%$rrzgei)l0+Y)Zc3KKV6`o|-X_40}BLm>J-G_0;d4QLAO=G4P&D +z7iBOv@usEv?hs%;WW~%=2+gBMX{>{(A?s89i;{R!qZ>(sVDdCq&2t%Ds*QkQiAR~(DS{17#bYWEh1 +zqd}O(q>I4j?exc*8;vy)1M(q`X?l$$O)ZNTxUWFTs+McYOU2k&1Xpy5S$bM-fE!p* +z`xxSACQ+J~tMr4YH;zHnz6TqFLogK;;94SkK@+t4kKzXu>;P!sBQbKw)Jq2;W?dt$ +zx`sxI>!Ma*kU1h-%V6k}^QKP~7D=q%&qSX2Tgf#A*L33x@lQ_0g4pl?ABoW6SC5qO +z)Iz$r`x{za(*zzHv=Z67g3&Ln)Vw5Z>E)Nu0z-_D3q}A@7$KlW7^w+XFv2_hH~CU{ +zW3!vRwdY<_h>3D~W#(QuUTuXddmNq4-!#@F8i5fs>cRqh2r5E{yLz*SUD|_K7j0(#IbI!|O}pZC@p8ar0`3ZYBZ_}?^eK&f_^TP6`j%#u5Jv{! +z4#cI|JxgghvpS3i&*uB`70D;HBIN-bTviCn%PFM1P$3Uwndg+$b4Bu~V%1JCM6!~4 +ztfZcWN;;8c?k>qaQ}89Yd)t88)Kz^$;Tilu4-T!rb7=hs(#p_nhYlVd`t6_o+*8FP +zL$g2kdgVW@~+#`O$`Td8lho3|kZ)NTcKWFKC2I`_=CJBfz&F#bQMRhCr*` +zzKrmpFP8&*6?{xYA*aQKI#@Hv +zXQovyW6j0*2$pS5&q(_=Pm)tP7N=)!CUx=V$;M&|p$_#zRh2GHmmsp6ORx_lv(rWD +zlLm@jur3wMXvC?qxfr}m+>>aP#p&Wu2i;k9#Hyoa;Hjj#1WHdRur8s(m(Ie>z|dHu +z4i!=)^F7R_vM+U^xddUy59G!gh3ixCcyY3^oLhAqZgr>_m$PXE(m9r}1oRjpu)9JU +zuV_?-aNi0l5!kS~qN^m2wLqUe#to-^px$fzX)H@#c +zd5`JZ%KMO|Uh1CeNPWgqH@JuXTR!h`J-IdRWIk10qRWGamdSMzSwO8WBci}k3*rxE +z4h@$Nrdbt3r#SO0oUvbgC=uQtcu)>*kr#9@`DYy+zUSoDxVg;SKUBBOXueFndfDmF +z{48j0gOcEU_B1DTL73;K-^)mI`ANZI7nYa3YHz;n<WJ@>~n1DLV6*O{Vg_pS|A0Hw7ldn5Js$QBrA`@6I6R(XM +zEWMJTwvSHs%>U6ziEX_sgpbaBaZ63bMoly#XKM5`Ux8wJMN7j{nv?(v>pX6yt+`FP +z^~Ou1!L6E4YLi=m%kBBx3J7jja?9nFT)eJtyec%~0$q=l8VH(IG`4Xe%JuDyp^Cd%d(QnUg>#$ +zKDz+h{#2%cz5c%g$Da4U9G2$R|u(Af{ +z7_X^Z8Njej5$T{_= +ze(T`SV`)aErJ_i?~|^b!-S!N-vVKfAxZcow^_F*x>rK)sa{b+wfI{ +zDYoZI4Mc`w1_$HZ)!eNH4vd8#xhB-t=h!LB+Vl4h*2wAB|EN&58}UoSFrEfTsGodR79<`zWP +zzve*i2SnE*p=$unmJnIgfwDzH*&?BAkqzTk3ugm{v(<*P)xz28Q{aqI+JZRy*Brt9 +zfH+$%oYldZe2uF+aJE`FTP>We*60i=nj6m$Ac^4Z^aj#>ujwboT-}*qYzl3AO*JgS +zb79`GD!!v?CRCUnIJHpue$=)fnm}*#6LdyDy?P9Vd>exNBJXLVR#vcTrojXjZhh}o +z!{@RXA57nxC~~hy4`|h*oP%To{#ePeX}OD#Gs)QIej??$y7g%_EYInq+QeOqCIk}~ +zNp@@EfD9L9>vu?hwcv`7=j)|0y*~>LiTU$tea~xm_x~r?Q??>}X?{e$fI-yhcIp_z +zBj~%w_?@{G!92TgjmVtt?-%7EqPum!U)}MZr!F5uXZ^Ie?IfEEtw))HzQEQSVq$00 +zS1aTcLoMqOP +zI|9?~K~Z~(&845%F#=^Go&sEcA*Cih^r}GoF_r6}j4XlpEG4wVVHFQg +zLUtTx!Lhhq3E4J*1;=rGN=RE}RD8n9Rzj~&Sk+2kPFSC;ZY9)w!unQ1pHH}?mC)}K +zE^8$W_=L+_34=c2ILp~X>*_w`;dTlWyQ)|lnS?xxeae^GDNB6HiFV3TpQ8Ol!dJ_D +z%46-6GknV9?UXZp$`kFBaPowo}gWDNnak&h;tJ +zv{PQ;Q=V<7oaa+!5hJ1G)Ti9hPHFg*yV@yDpYq{$%K1L!?sm#bpYqXm$}4@!J?)fN +z`ILLxDHr&ZW9^hxq`=ADyjxR6t=y^JUw~C}&w8N2(1L8nuqUb5c!i?3Y=Ls{msI9p%m~)`Ddg*}*l4Mt0i4L|3 +z(sX9R9zkR3=n9+Du>)QhC|ClCpv5BwR2pZS@hd9Z1lR|#JQ{QH8 +z-Yx|F-`0)4KYlfn$%P~5W|PS$%DbB-FZcxPLjU>cV-lBaYfU|1U?)} +z%bGl96~p1QtjXipPZ!geE0R8B8$!vZXuBqRdu_&;b*{`9>z+wy6G6EdoE?5rOZWV5qO(rbE4z;#T)`Wo9)tQ}LZ%&TY$)>;&? +zhAPa`wr5%G>$JCXmX))>9*UWGWA&={Q2RRYQ0IeqN;>%S0aQi<+YNsu)fyG|Z +z1u(O@Q(qE%!FdIWp^!(Eyf)EeCXuv8d&pyRbiL*lGPY!%&;vvK0$kV7juf_WRB +zuNvrO^hQXQy|8hs0v4F2XD|2~Q*?K*E&S|9zxjA!wpmdihQgXFKIO<^Wm51=ccxqx +zg$WUWO?T*p|NSnBemWMrQ0mkM%9PqFD^y2iEL77P(E;s1z=RhQRwcO!)Gzofhoy|6 +z$EU;wShAK%Kc@$ed%+#eRZ6bbq2q +zJl8S{q4|CL$Qnt%DgEUjsNU!iXV +z3Z1c;)B)z+ArXCAK`XjwejiWyShJqZ?=La(8}Z~q5A*wW$TGYEkP-;$7FHLFVM7)0 +zs;bcR{(y&01ufPXs3$N3R()=IAN-6d5}=eWwvMfd2Yw*6S0hM$B;kgGSMH2Kfp+6ubf*oCISArCs{b%uYa^=^& +zE7FGin$Ty!PbnA$70v1A$NargTLW^D=)2x*PQRQkVQ~@KXCU*E3`lS&6+(i+FnM1- +z)I{(DHArj{%a$eEoPK!2oc;oDnA4y4jg$wKAHC3LU$s4_f6Rs> +z-E;a6b);r<`o}v`vpM|}9jV!z{uBAsPH_V(bek}}9sNOro|Xs~J>Z`O@kSFvgVE%0 +zptL^Ul<)WA%iI+VAjGUKZv{taM?ArG3M;SJm)UgcnUWo-I`yJiqFk6x?feJ` +zXSIuiUS`v&%X1$E{W#|%)S~Y!^ysrfrQDt!isE(!xB8mfbGS8&qj7FX%qC%9VY02U +zEYyfbUX?tSFr~_Mw%AB@eW286(DY`eJuD8f=~v>n(+G#43u|5lY&UsQr==s9xoMxE +zWu)EIGp$3?PixY(^d9I=JVn~j4{30|iYlh(pSt5q+0fh7@uB%?_j{VMQaxY8&GP|C +z{6JL*@Rht;221fEpY{2Y){B&8S*ZLcEIk*BxfkV%NZ#oxkHwq=TZDy8&% +zI+Lq_%kve{u`EsXgLo!Q@eH1tc<}r8Lp-Pxg!Zz=BK9feSLsVt&IrRFjLwT1=lj`Q`l_e%`FT3?Fi&4S`(K*Q +z-F@}cbUyQ?&{;-~bvEeCpnj#So({^+Pp|ZRj4OUn$|Q4QQseaOsFxy6#TQwhL=xcm +z=XqI1D@3R7lV>Q^(`s4PC(p2Md)B#cafgGNTuJTvlC6t}fk-DVdk6ix!fr +z=ci{#uAY&})i$k2pCeZ@1Jj$oFDhF(R#o)ENUuOIRN+dd-!-ipn;<34PwN^@aL@=X +zHjWVHz)*XLsx4=jWtGX9*_33)24!4_nhEiQr(tgnrh^OEn+v?b-kkT%{Pw03l|7U&cmc_c2o+{JSo +z?_TV+|KfI#nFA$QNdYWM-L^GKFp6U7GK>>x*n%J%Az0Ke +z`-x`B?Gb`SfG+R`ip~2bP%K3K%2JWt3@D01&M5~Vl@DM+h!~Hxh>z{fAdC{Qyv@DR +zrvaY^Y>eF~HjvQfRyEPnU?^qAF}^9R$qExcL|mI-vRDRiAQcjujYxr6NqpHFdm!9GaOe&58WI +zEzZ%sEziMMz{XAXR6eZ5I`6ipf@6^m$=QEt&ydbR(ZBP^!R)I%vCUY(7t@Lz+6a=j +z;@}{wKxf@fua;f!8)GEM3Yt4{Hj&_8&dwf>!h24h)cbnZ``OtzWZ>jVWvI-_kk!C} +znaWU{lfl=)t0cUt4ZZ0D_j}coEpw^LS^~!EL +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 +znY7a%Iuers`qNjxON<`XOee}*yI&` +z*V(UtS*8roSW5~8dJ%fgy+9=LdiPaebR3Q+#IYrUS+yo`M1Vn#gX2;>0FKx~Sq+{= +zEG<)`U41o2vtymUaZyZ*SKr(z9Z7pQo{KWDv0+F3A>okm1u9gm3`vQk4z +z+F$!GrMQ}5IWKvTDSqi(!Eq7-l43|-%ocSV0{B6Uh!4ODx9k+I3+tFN0iY?MlJ)&? +zN`a<)bg+BFF7<}=SC~)JY!2Kj_Z@vzb7SOdYWre^c&A2XOjzz$<~DB+bfsn-1KRbC +zkHQA<=nYw;)DdDKvvUPtWGyu6vkEvRO7t&Hqax|jw!Ju~7|CiQ9^^eGn=c3-A&J)qhRh +z5lY8UgrXrXg)c|H*fHU7ZNy#J2A`8tr9c_zx@Wus#hMk&G^hTlP>}5~7|Lxx@q{LZ +z-c&%k4L$ekU-*g7fBBK0`1ox#aUhksSvzZ1%k~V0HW$~vR^VJIjJ>;)NJ(O_RJ|3}VBId$z$r$MFX`XfcuCB$J`x{*iXu2|6CC9Gm +z2Qvr-zk}ulJi~V$feCY{)(`8yq1Nk`vD4(uE;-c1ELCOrKFZYPA +zOnlSBVHBvGdMZoS!J!4tyI>Vh6Y5X9dmpEvVp6`qk7bFs5hOzA5-`zdODDI+k= +z|7nbAQZ2mk1b`>cQ(LrHhAKZ_vQnGG|f0&yAP|CJb#EJ#loU$^H=>T5e``^@J +z1f|SD20n~eNtO9;UYU}ek^>K7h=V=%t-HwHGQ&wlrh(eU38w|J(7YdZOrG%EKtxhja7FMrn}@2!kiyPwoKq^n +z-jtWLBKs(tr)*t}o#cnVR*?ua0&^0EvqsYrJ5aA`+@|yRpw#kdw|s_0IJOd~%3-?n +zcL30QSwE%`7@1DV8gnwcSOCh=-{3ersC=TaO+1B@k0VBbS=`q;O#2b_-PUlKeEVx( +zjN{}sguuhbWdg%Mk>(gE7NR(jon%gbsg0jc^sQJt5~u1q8f9}j +z5eLbTpL2ct(zy1;Bmj5Yh{bo++OFi%F-mHgA=MtPQc~Z91<9*+s<){NTb`;&7BQEX=c*oQsYbRfRO7 +z-5|OX&B5hl&0$TfbiHp5LckwVN&D32X}KRaV4eW57nGP2QSE)@0?td04W>T%yPU9o +zP#XawArKo#gn(cq3a*#-5m|+di%=_qfVO&`X1`v)y3H1<z~B)X0{k`mop#C=i0-6CI#L*`z@n$flDM`g&_MQ-QN76LqqV>xvQT{tqHN`3(I+ +zkTQhln6@~9sjL_qFzT$DN?*U?#kAoxrB_uo42S5TV#Gw*9plS^xRCot&*}O?-86iW +z0l}Ad^JOWHq6nPBDT7$LnB2&D9XnCemmZx>a_A!@7Du>2?qD$2X +zJP$#igeXV%?RVo>GSOhL>H@5`3wc#1TJ`q`393JXj;W3ubP{fJXw;DdzNCN3r)wQg +zcQT|kkjHWgA0N-dpUf>$wE%`#91=cwN7{Rbj#G-vEh7mMrW9ox;L?eBBh$0?%|fC+ +z5Td1yN3Er)^c(iwk(YzPr!FPwFtfay+Dg31DkFxy%BHQwm%E>_!RXKGufzc-uJ*8h +zIB_98D{ydi*`3&Z*@xgFQ3>a?t3*9v`uOC7~W +z`kE-+7+t12q`XEfsHhEvRa~kY3Mm&YBDpkKZ&x+E{`>C(co1w$XF^+BiE`0!s6?)n +z%DF08?>-hr{ybdL#+x~V)r?Y#jNceZ!XJ;a!9iq)%37_*Rclnc7*BDae4X=qS4x6l +zpNUoaxPSqP1943K3;v5w#_dlStS8}YTS{rhv8LJU +zKchC(`rzg?zEJ0wMYSFta214WpIz5P_1b4}H)g0&rw9#&Q3}Z>0}-dqeL4WmAtgQR +z8acL(c8iitWK`K&+^#m$5RL2p)+1x7THvvuLb+#a1#_V$L&*l5rHT8LidQ3*vksOn +zLmdh+t3q?bNJN$lN<+qr05CE{LmztbFMjg7pZ@W$e)={Y;oGYI>6fp1#>1+#&!ESP +z+sOhXbZ`NTB$}rJ#b^!1=n*e*Z{#+#`ErU@VV5Sm>`p!4ZFVP# +zfuQHDP;nVoiez%*BVI=FoElXnyaV+tNyFkcK^Z^T%hZ1_kZkze!wITm?qhB6U!*-* +z3+{W-7NkIX-AilBa^s-DQaL?Pn`TfGNS +zhy&#>;oA~&T(VDhUiRgcr<7tw?&nHzugzTh(X~1p9bBCc1D;DI3)R5-l_V~@kDBtN +z8@J`Ptbd)@sb$qk=C8CdhHSY;?kI1#MF;P~fI7BJqc2WO^Ni1sNx=r@d8b?OABP{C +z-`|exz%rHrj#~&sVMfZ#*6fu=K{%T=z`&LWSumS4x255WB{D#i8-`O(l$iKLCboPc +zVp)4;rNG_)q?k;N76qr2Gu`#SN~-X;a|sXEy=gB{}zr*fITz()sG7Pxdga0X1V*Mbs#iJ +zw@KZQ^MK3+aj}L6KL0OTegzM84FfE{Dn!#_whnSJtvg8H7cB~AXmjU2VMP?$rm^7o +z1xqAb$LK*mJMb#=S1R4NDotuXE=Q2Hs}Y9=Ngj9)Ndgo~1=D&bCXZW +zyAl4Bnmj=B$0+Fmbqn!H#q$XeH02%&oI>*~ +zoggo-Wz;(otq0?IO=PRXl)Kdjl;8J*PiOo(mlllpMZ2dp>jS~&_7oZ0Vjy`0%|8MI +z-BC!2orCwlKvY=-s;m!d@XoXU&oj5IHM~~VM{U~Ne8*q}bI^w0hzkMq8v$g6Xz@u~ +zl%b4NhV5UZ>U?(Z1d!LZE4v@7SjN-g4}xFBA6RHM(B`TW&$-m)p^|gh2HFNg;13u> +z{L%BG{9(jckUtdLK*vCG<~oMvdb4pg{@f0Zsnwx7UnKQElvqup+6F{2Esb*&5Vk?y +za`&ZxPabj(4}}KBwV%w*gd>lWwlHW@j@Tq)GzL?`zN|HlIF0>d(+pUNDDPgz*=cd7 +zK`~pD7;goPjX289Sdg1+0eTBlWH3xNOl43puMQNZXz4w +zR6VLvrWAX*T~7yd5rrjkIBCcg<~k$PCH;Fh`WeljSsIf)>N-VYq#DfB_-2E~5=*lf +zq$Du|4s050dRcNu_I$>L%7+tP1PLBmlV^? +zmz-*d0QEljqGN6uG3eudC>VnpGlg~_-k4u%TK^Jw7&@FNUreGnN@PBwbG)ENp&cMM +z7smCP<)R8)d!-C(U_^+tHA5wv`ND5a{VYdgRz65%kP*z9q(uP}1mO{c1CkJhtzqFr +zxb-&!fT6~!n_HqFVR4c2Nv8B{j8ZP_UuR)GfUmi(mfkGYezvy~Gezuw1zT^B4K^`- +zi$TA}|0SGZ7pL(ssKP)}Px1luOx*PxZLMyct=vI+eCLohJ>%ctQ64WLF8T##LMkk? +z9g2?CAjntm&R?xz1c1J;y +zLP*7Z`4*F0clFLck(9`Sb1l&p9O0}$xxhfGmw4ezIcoK(k&#V +zL>Tx3eBKa0C9lB1hQbqEnZPeRre_q^30-l-{gn+M(7~Ek^c}!rDuTI$(cz9OTF<|t +zrO^#58Vsmd1$e)=k^Jk=DO2_u5tGnm^8Zl-+q!WgJvZzpWMlhc6c^-pC&Yo%t^mmW +zj!L;S`Ka!R`n+2}GD3S;SN6g?u4~cVEd~1s@&@d|67A1F|B^pvig((v;wMB7Gm-N) +z43a$n`q}3&f;A;XZTvl9f3XzMOb6UDjxUsu*v;%6$At4YQHWdpKfG@iED&dEhrbz< +z$VYm2#YD&P&XW3Z4E&-#5I3^ttnE)4{j^l= +z{1WX{7%bw+C|7?>=r*jKtc(T0Q?C6(c_9Hci>Urz0;>NF@vX1}@@bzJPrG!T$>(hY^{s6d?_fL96lb@7cRF38)K7G3SafT3ObK$;4Kw)$o& +zN#QM`^PqMP>G)r*_a)4KL2DGrdM=^&8E3sAhEc>$ +z(_H9%hz)YAqW9g}(fjmW=zXX4o%Oy@A6g>L&5Rk%%I`=9ydX*5cF22=9DnfuO*FPyiFc&+f +z?~$?$8a13KI<^9DcOmM`b)jRe=;w0nj!J8*d-}P%$O4u85S^g|n`*CMfTlPXfAG1D +zAsDJ@%oDpcxLk~Vh*{QLd=&g|k{YfqZzuC=^{)$J6D&%%Y-XAlwChu^eP6&_wmpO> +zLJn~AXccg7TXe9c6z~Y8v7%52deDe7&H^y>kmMf^fO4f- +zHbyHk(Z<98_L`%WumT$G+edpb?%=&Rm8V#(`i5GC*ftfajjkG&fI +zscC*BXbv1}Y=Bt9WE1_?mPR$%1g`yh5ZPr_4GKGkgn+|Tg^*D;c2V@x!f5GmGFOhfOJPQ?ork{$wR3MLbSLFtpIV{r3X5T^sUoH|2_6>!MZj4xRnxtL8 +zS*4U~ILCRW{~T3yW1ca!4XKGKpBItxkq0QfBjRO1WR&BlPQ=-pa~i;@QM-cX={gV! +z=!Ab!m-G0wQ&kw_J41=)xDiKf2T1YNe +zIyd8Ns83KC;Q`#Ta$q)|+!*QL6x=}v+!K20v#0Wb*6V(T)wUx8xfGZPl|=4*350o4 +z0^c0B60k;09OSbMT9(BJ+{t+>X~B>I)z28*`z_2{<-PdeGUsQAYx~k4!yLpd4Tk}<-{v6{9vah2%w9I# +z)+5ORr`q<7nR<&;uO%r9^;XeGN}(si1ugZK(4BJ+IrWCyu=U0`81+VUn$#OA%1`A+ +zouyee#DfBtQExq#jmEG*2>42}@70b&tij75KqI2+6#9}k?*%=H{Tkztr`p2cr;mWC0f^2lb3L-0kw43*lCAejV~0j9`)`h?RQlyq|%^G%q2 +z%KYfkyNNl=_rRb%T)&Y=PSlyCP16FI+;oU +zReov-Qif!{;)vcy?X0vsV2^@qT-{D)X2gQPyah)*sj?o~n8zuGWzp&%60cqJvkL^2WkVD&DzjJp@TJ*d>KyuJegh1&V)i5J_v7!cWl!mT +zPJ63e0v@tnIyas|O@MPCs*m&_Gj6!rWfXXd&-}E%pZi3XZj3ZTDPyLlFdF;N{brb< +zJ?%PIQ0D@2r?w_aHdzzJK<;Vloh2U+D#PEMw3IAD^y8IyFeiEnD>WBoHZ +zsh8=rg1%{=8I#9$#mO=kl$rO7wRh~vXunQo^75QTYm$Oht%T^8cCUY01AaBpnn|<- +zpbxMTD~^DbN8$q3M1&mE{YXG^ZSF_6r;4G`#jj@M!fVZEMVJawTASG5RN_H%iRa3x3@7GJB|Vsnu-2r~w}CyhbJq@5PY +zR;(3+1I1!7R#4D@;hl}Rd96cwo(ow*wsKFgKud|RDe_X^OXzV16|2lJV)@ETx&c<8 +z8Sxz!PFiQ)(yC|cDlIhAs+vi3jCSsIY__|iQCEu)(Vg?n^MIOxTZ#)2*jpIfba0^D +zQ)1FF0oa844It*fI)DZERzqx%pQMYr;I{1%*w@k^*Tk?bk&{noVffi@896B&C#-_> +z!)1WbvO*1+u|Sw07K;^`^|xU!hi#!6+4*U=1U^ik_WEU%D#a94l*V8PS(+&~ik36V +z<5>?Ktfc^nz*?WBV^K+98A|D78QG=H7V0Ig6(r^Ryf;#;=D1z+0K$&a;}B5(fg--c +zIhG1=i|-{n(K#0&WHMu@S!#(2l|v6=OAp_#=&ZK75sO69npapPS{dJnMS05Op$H9v +zwFQU7jYy1GpuUiYTr8>VfkSLblLU#-gfFcTi=hF_iee3AuW<+~Z%v6ItPOs-LyJ`k +zwLcakz&&2s7Bp;5wI+18V~C{Xgv}E3=7g~t`WYzF6#^}6t({}9t7c`l99wu6 +zF>?^-5&Q!(kYAW;_^{Xw%Lh|vA2kZ`Gke_`+23)VjECozczE87aus(~&6bk$l=!1_ +zGydqj8Q(iM<9p}L$nwu}SJeme8430kCT`spEHw +zvT!#h9~o_Vn`=(O=f#e&h7Ff|x|8L9*bQ +z)?S88tP0g-6QdE9=yInyCkW-%07X^-G*?=a^RV1(tCoOV?aV5O% +z*~4N~VsuT3ZSpi`60IzrLvCQcu-)_ILsDIOqoKJB@~HM;+zw7x7)KHmqs9xyN)e2N +z7Nbr4OcfNm_fpcXIt>l6z&*N?EYFKl?vCO2M#2{l*v@L&`+%y7L$k>iv|@3na#sUI=_AwC +zk0dN~)dp)IW*!lc>;Fcym(+p{>FG6KgEap?Km4??s~dJbc9Q-t6C-_VRrLDSf^m02 +zaFj(u>?EzN+!ZK})k``;qu_dpr%+TXHXQGiX_igJxg0rsKOS&%qv7~sbP-Rx-2)LC7H=A@Lu6r)odFYGLm#17r+)zL+T! +zttVKY>5^jYr{aQwt&>A0w-~kCa26TH;W;wI<21UcK%ap_ZF9T&A4?2M%)^h(!e>Q} +zv|u}zYuCZMxKNQVAvEkt7-J5q(0#D)JHtyHF`J8Wl{nE4FwB6jCsU}lz3h%X;IOuVR49<@@6b4zJO4k*`&g>uO&3&Y4TghS+% +z<$}TJ;s#0{=(S3#k2^Uj+;2%h)c-*2cy^j-l~yF(;~f-)H>HuU)mFCiXkHAmfM)AG +ze9~H@C9RvSo{P#{Xkb3EkoD$?@y8m&1wEGWk8{OC&ECvA65YV9@=&eJRkuM9T)(eipZDgEl8RknO{I@YxLEgmMVoEGlC}N@jEw7NTecLwG_&FZ<%jJT3!@ +zYvXbGNJ{5!ozalS*=<>8t7FX)cwoFg2~z{wUId!rMpaC>t!6B&EAJZR@# +zkn0Y%z2~Tu2M;0mVwN4G$&o{c*zKj(8`aD8p8D6~T0eJu8`l@ToThod0bU595&BXY~*7U&eo|%y>>-8g3 +zGkd1HvyP`*-!eHFvPMxk^8aEkJ^ZF8Ceppb;|J5>$(yIDQM4SSecX)Js +z?c~(ft?BS|x^H4?RG_3=w>BD$=tJaF86W04$n|4fi(H{`RO7mgUq3&Jy=i80w3WV` +zvd?Oxv4BW~O(g*9}iiH7;Mr34|gtsick9*-y +zv{*MeF)_Vv?RMHfv2JqY=FzF?$%E@ep_@micg<{DyM1Esnu|xaZ@=_4uYdiHZLc5M +ze%WhYyKdW_iS4`BY@6A+b7XSO`n9iLyWT$8GrA3$;=Zg$H&FH+`~*Yx`~mLI%sqdI +z`xUuo-3zWPe=|JC=fCCV5B}1Zzy18*)@`iSe|8uckEcT^;LUkrqijB +zJv+Cq-a0aDk_PVfT(1lpH@^Lb +zYp>b5I^F7@-1XPHe@nNR%o460diz`6yk%>;Yhuq1idS#ReV5DVzg(Mco=$HWo@&>$ +zF^!_*;O8^6?fb+1@c6{^u93-`#(?*xy`$r!dx!TxgY|1)lc&L5g?jYE)NwDrMf_YR +zpuz&>2npa1VK6<>-Imdv>F9JiI%WB8ff+_kIQZrUJgkkLrk;O8`B{CJbFcoHJ>TB- +zti0-voix08WEvU<`b~`tPj26}F?|)Rc)An=(R1;9N3kAl%fa$I_rgU6+oRl{!|!E= +zMO@J0i&HbqykJN5Qa$=e4$gn#K9AGC<~ilJb9m3x2v_lw{$=fYC&Kepx#zcp=Vo(b +z^BKzKG5SZYl2_St_U%vcQZn}%m}6KvV01?+PD^)AOzs_?M%>f7eZ!Me;{J(kV_IS-SY@hAr1`zUIo#^fO2|8OBvO&+?SuRDi>Am&8eGk{!-?{I|M+(s@ +zjDlD4n8B$&qbjAh^XX)ZUd`{Ku5>)^W;=*>`TXm6Ue6EzT}S$Bcz!LvOZW}%nH(A3 +zffkyeN8K{AL*MJ4TKYPE7zrbjrr>rCk7BKDO!v|gFMp#cxwU&n##ddK*=DC<#(6lh +z@-O8k`}lMWJHeLO6&tv}Ecg6+?(=Qm*!3*JjE+x_OpXulNk=3-Hl`zbM(50ogM;n6 +zhPUlO71O2GP0mbBZ(lcj*=sMpWMt=t9qUK7Z`iisb=zP2+DnIbzGnODFMHjFZ99i| +zUh>-Y>tC~N=k|4&8YCve(_cY@6_}TgLZOS)>0JR8p^$id)YrTQzPlbP6W)3jT@(TiBC3e+&(io +z3Eoy+m}z8e=BZI(Zg?lyOfd=gDenbSDd?a9J7`9Vfr*kI8BceNAh0G5j_l}$!haRe +z7CjFvl3Bk%M>?OYZ=B47n@7e+CWog-AloQXG}M-E{-KTOw$bUSeZ$+q)vddRq2b7m +zXmwvb60c28?HPp&RQcr8uF<`|4R7Q7HGCJtJd!Dxu;BCNiOJFT0+)3TGws4H +z7A;(`cVzFx&W(* +zY3sHs1Jq6(oE({&n3?1gJy@z$2LvN}nmPzq>`nL2Ou&;Pw{9PyupLt)Ba}W4L+P$n +z-uMKpKQTFcGdfmWBYXEvAH;+nPFv}+x^s_hy4^A{vu8(YBP&QYI?b>-=!lV9A>Y)t +z$%){Ps;_1~Gg +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 +zILFSPj%HwMP +zdq1XcF>qzb>ah;8n@emz@h&hZEAHM%cY2MS8eqEcfLkjy0TL<>E +zsqRm-#_!sLXM1>mNuKt@PH%?BBj_nepAcEFa833>M33RVaN<^n%4wIO(+G2jEIii~ +zukH4-td^mjfFRG^N<lyw}NbEHFAz^pxGh^oz_Ez7E<;#1lPUb@Kkq1Er +zj`)eX4x`T&qWB6O^i+dKP8>huecA|RN*xY(?W@=mLi@ZG-OF$fp7kO$w|9L-FdEIk +zH*cTZk{q)oCK-)qV12u^rrXvUO{FM4l0trS(tmEPSe$wX&1B%W4mrnbv&~+(Vc?!+(w{}XOdecCxW&L{ +zL$*FT*(TMxjnK-#udL_p`LbC!BZAPuz)O@R)4MO{^qeGgGjQ6aw_B|rJT0sw^fIuX +zNkQJzy(cH`69yTW*CelC)v8_BJ`%`HuQmWW!%Gol^?7m2;CNPa&1)K?aoiMbj?9vkL$mI2X-Ftu>~Ky*w~nb|Cy$__}~bmGD8;)AC`ZGc@1IkeEu^GYohT- +z^4amcVTEDip17-dDpUv$`GKASGyGX6a+f1|7Un=X4^V5;Dz +zz@{@7=-}nT#?mZo>h{|XZ&iQ#na{!sa>}4^W9ek6Y^tp6ru@(9`^$95+bIO}3)u05 +zLHXlzkZu0H-ngL9!QaW%BLoz90ztzZRClFzc;Grx43$~X8*+D(a@?XSFQukw=P0EB +z@g((OvtAr!8T*D( +z{vPhz0~a~cr9ksz8x*{wqdc8yiGMGV0y^#x55A`y4kn(*WH33wJjIIN5x)PEpIhJu +z&j(J3o!<{&hnGE`UYrh|W_&)4&x!ZID}_IM=<;-VFr*X}>HFm2ztlbk0ArslT~?mH +z +zMO9T*O;uf0Lse5%OI2G{M@?BxMNL&rO-)@*LrqgnOHEr%M_pN6MO{^0Oc +zb_hfm0FlyT>f>vIiT5XL8e3U3K(O`y^?_vk4x?L9)#CFMDOsjw<|0NG*y&ea%9KZK1``Chh%=aEF#jGm-q!HA|50|V +zBX>#+4Q+f!n=#!(a)8c!@GlClCcFrUIbj2U0AffAjgKzQF`HAAi@9GwP^ki0ZTRRuuBCs;wxMi!ogR9$-qeT$p +zcJr&=zELhdQ`lJ#kG@z_SKrw+`YGx_TwZ=%{p~w#?a!XC$f&*7*w$`txn|=gdxt{_ +ziRG15^*0*tbnyv`Y}xwl`}9n>_s*BExFvmj#U&i}?LU7Z>{^Ym$Q((t<(6w~H*dAy +zA9ne6M`!owr?372iGe|B3lxzXuY43VQ +zzFPVQMy5$et=)r~n(se&^7Q@m3`kFWCR8zu%okD09bQ6`q(z7kXM+S<2~&sN +z2$Vvm@X@V!_$f9ZCKjiI@EP_YK=KaPX_AN>WRzQoWJwXDYy=6qFqai(OjIDE7$2F3 +za|tFf-$BY7^PC^vM2ajUijpIzh?^+Fv{^JkPC-sjGMy|+-b9fjnbGCpVmXwk!Xb}| +zk~xUsrQoEbvYHs4N7WC!4#4bNtZ(4 +zo<$311uH8I_Y9$T5ew8QVk) +zkD4V;7pASk!Vi;6@;F5>m0T?1*#ZhDi4>mC8}XHbN-ZXX>k%xxjwnXt;X+{Z3o-|y +zehL9Z@B})E1Fi?=MfnK)Bmq7_REQu#n9U_llAy|fHR$=i`zD@fRKG*hx3XrlwH4n{(_J1F?;Df +zBqF9j+(tx|6vHDWh$=kdm<(+WNseTKaW4)pCd*(lm@HMD!_qiHizZB`&eAp2A-Yg$ +z%EF|%L@^R-sEw^8DPeTjPBWBRh;h<1iAzYL6pWK%Wv->hrAASt(jykEvy`PS78YF~ +zE+|5?ga}NyW>e_o71V{aAP$3Ni^;kqI(aSZu<#N|;c?D$R#55T`S#ML9CR|5z!EZD +zQyvouzpCeI&AEa`H!~GmLAB;GkD!>*C5X$-wTRqQI$4K8kI+mWUu4tvi2a(HjuSV)n7Gqn<3+QHaS&~3x*%r5zm=1-{5a)sPaccDA#kAA!Bh(a# +zd>Az%{t)Ix;v&*0yvdHsX@Pp--{=8UKOwX56M~!@X|uy)BbE~n81V>2TSoUXNMh=Q2yS`Im2(3<{JgdVmptsx +z5xB|WC!(G}rn!iLoSP`nig-9NZODu)RoXIQJ*N7a>zL&!L57M}PfU}1?7z~1$KyMEC +zD}@OzKF9s%B-_WAd8YQCF0LMMr$qoP%GLj6&BQ!;hl|#c&5w1HA6t(N8|dbe7Zn@u +zjk~#tZL6?NrQDXu+jRGi#jg6Lr^DWyuQvatz%^PEYG>`+cKFrt&Hdd0p}g|)PsUP6 +zH!9_Fo*eb~u=4OpF-qtUvz>XGO_r6>Jui1e_N+*+$~dyxWOvWo`6q>`^Tfoa{KG=Z +zJmb9+zDsfUeH~SvUXz`+^}q=AqDIkLdo_jH+Ih=sE^U*Gdl@P4P9r=-{@kuo8)c~p +z;W(An3v;bnbXOe{@zVQnwfmfYz1U)zI*V5!FAl79{$Tx->%wXEbKVkNUd3v@`a3&f +zx1Z}XjCb{qA*UiO@kg4AZqAZidtr)u`-ewHhSYq +z$M4FOE75~Tm+sf?XgjN5udPvg=G3wQjW#=rLq_dagJL2}SCQ9Ue3P@gE%i{uFZ2O=?D& +z)S*b1@_73IsZ(VdHg*m^6*kT_FO)Qs3U5n96{~+gH232kxz20G75v|O=XIh%gZ*a} +zblq%<%e+qbXwIM8tafqv_@TOij!g0mdbE$nwd<#j?~?bKPd8cdiEI8{;{iYN^}Ekq +zH^wZ!mnOT>-ZPnuY1i;C9aj{pr@F9kYTn4&|*#)GI7mv`De?b?nQO>5_Y*YV*xGs-Jf6j2GmP2#dQu +zn(Zr=Aj`Wx;lk6^z4qrv2Pqb(%T)#YcRsgr%KG+H{zJ15=|Xm?%EChrw@NReimTMI +z_XWsf#VhD8wch(eBCclXuYOD|?|jyJO`c}?ar9WE+310@3Ad?^U$4!dyI@Frp6!kT +z%g^8FS3WPkQ0yy9k@s2t;LZ68u5A~-irzI1jeefj8o7EXsVV!&Q!BmnbT|ICuroQb +zm#ZnCc=|Z^O--lWaA*Jk{mIq73 +z6N9*-Qtyb!c#d5Cn$+1+%|Ypb&ziS!~Lyg=Ppy3 +z3G~BFgMxdDyFVpUdKTEBjNO=l%mI9R0X@f@1d-Ddp7Fu>#NqSWd=`M +zzdmc0-kKZ>eG2u;xq2hg_hVR1{zNw0QXnS6Z)~b@o +zdoZc&%HYKZl#$~HI1HvQ3Kds$zblZ8Y4$|i+uCYho#=RT?Df$C_gW)IWLfUxxYsh? +zTjj4cy=L!|&GI=I@V)=1?TYPbNnf{wJv(*C(<&%W=Yj%izdQ7J;z44X(Yj`Gw0B6v +z*C$ux;|Mz%STGyHk0@AX&B +zPb@Cw&si~WeMPa-SX|l0$pi_<`wO1Qe0r9m`-#0TXG^VmOx3@=YbZkIvWQ5_X`j2U +zoGasZt>1py`}B+MeJ!-9eeHHiDMbVh8i&w&yXjSX?Tj^ae>{4V-?!k%`k$vRc#B$~ +zxA)vS!JF+@)_bK-|!pknT7pJWbJyPp_ +zd)e3E{9_*PY)_Jt~YzS0NHIXY9^@tX+LMhH70nITb~S3j6wWn?kO0;a&HKd!}R> +zTweL#cdW_NFM1gsvu96eC?blrw+YyCcK3B4C5nY?46 +zVv_r}SE^<^pL&H?T0cMYM7$dL!rE8OlYQ9Ao%bPpbl-)k>rsVG_b!sd`R_?P?XVNm +zFVB1UGs1x?wK3c))J0UKaX7yrvrLy1sHyz6Wzw-WxHxI7A@eYq&t&p>o$l3Aq0Wj= +zV#a$7e!Mg<<~D$S0ueVEa|vf02-JMV!U +zxpm(9;Ha6S?JpLZogusIq1MYUvT+ToH0mrDS=FQ~dUrTDz*Aqc_n5^g35V*tQcJ%s +zKIj~CEFp6^(tl6I{`E&#`^Lt_^VXbjI@PZt*)aAaqVZ)%%3u%jljOSp%MWcmKD{{X +z#iJvJHBm3^{j`_I32~e^?O0K6RU(tNE1o=i_}P)C8)+wB$UHu$+bojT-cdLn`?xQh +z-gS0WUyZ~OBK^^~qE(V}@2zUjwwH7Bi*Ah#?2vT#K%^R$?_%#$2fSW}j6EG(L~9Se +zBSN1zn`FBV*~z8Jk}#w8lh}sxZ=sGPmM}Qi}v${ +zBB%FyT5aaeId?_(`V{%$r_8(J2YN^Os891Plxq)~DVj{VO{S%H}E_@Dzfd>$GPWR)wh_7@ujl%;nfH0kf&VbcPDg5JZ{FC +zT`?*cHe9pTPX8y}3%j()_8tG)#e8SZR&aK|yV=7d`aQA4zk1-n`_bjcasr+odp&k( +z1CNKB``n>TR}NY|yfW+aYkBL2r8hjbD+k#4M+K}&kDm}&a%Yy&vN`PomabOwYA^iE +zp#C_O{Gcz2wePP}Z&79T-Sm}zfn8f#!^%TZRSBx`)p1^H_`XK$tvFTU>ZWR-ROCZG +zZR3CXq*Kh}+UaTTJ=XN513|H-=#)T=rh`Mjd?2~@{ks0NWs?~Nm{!$1ZN3%qIR$4X +z*Xo8nxQ(5aj}hAZ{nmxcIpm)^Mapo(|cAg#4< +z!Ep-d#}O6D#=eyP_G>fi{KCx5f|Hj$*D72Eq`PvZlH3yDbjkcPxak9*Au<^ +z703H@hwA3p3VcexbnRQ%ra1TO +z`EtYZinc@hay$b^M5+w6S3FPY7T;K5nRm1BCNrM;!S +z+~4ZB=Dq3Q+d-R@HR`Ml9zAB4zjn>T%Gj`mFF$s3u-RYY3q^fWarT)&&4{W^+ +zfAe#$UE<666zopkY5caNsQu&F1iUB}WBxjagEaqQBeN%y^trD?3$+qQAHtCEVtF)!}9zdWyd9k=tmEhVi#fVT+l|B4(=<^9+R3 +z(1GKomI?I_+E!ZW9BDr}5#f6M@td7WF*ogd5BfDk?moS5bk%0dYYPK**|GIfe8+h^ +z$0?pm1}?}}jx6Z87N==L|9%KN)c5@2nUb<+1B%fDt%0Sca=y)L%)HJwC1)k`Bh7If +zx-Hk%wN?%k-CX~3W1_-5ev3%6qHI^U +z^OTQbsb>Lv?rc+m+4Go$mXqGtipR^8|`c9}gC|L1v7NO-iUqs=<$;-qy#j|r4 +zWZ$e^_xSWW%HA_3$2%R&N6pl{->*D-EL!2+-LM1C6*h1h=K1+1u=H-$UG?Izy0@z3 +z;sVJ6%DMFW1qEgTd5F}0rI3IonO6JACRxt-ZAeFg?uMkF3Sr+)|5W8s3P%q4-}O=t +z{V}Ja(Lx5d#8FuCcC+7Okv;Mr(DJ=b~y&` +zh8nMN`G<<@TODQV`7A!#mhQ4DFKBPuipy`Fdz`EmeY3RgLQJz5;iUAlbtX5rI~{L3 +zx8=jc>6^<+lH5B#H(WI^I_}@|^XzPzSGD8qbkPp?=Iq#e-8_yhr2Z?FwNlMDuEq8v +z>jkuzE}!QvGqhdzVsZaGbP>nf7|vbSHB;ugU7-6{=KN@5=@oe_-ExGxmpXp)W^%xl +z_|*3p_eEuX369FES9Mo>39e1Lxx&|8?sH?gY@vndXy;(X7f}w)%JbTDRM)+b+QA{) +zQ}*UagUhqV`3}~HQ|3`N9pOHwy?OtN%#B(fN<#-%Tqs-nq;WKBbCiOK^sJ19V$ZwX +z62^C!s`QSt^_XUC#avrXC5YXA_HbBJA+FRwNm_runSW34(b(eX@pD}~*F0M#o^Wp& +zs7@JJcda$1zv5;#|MLEfv;8_}7Y>9K$~a$I-jy-WfZO$8LV0iY!*fe=W^;uNCLCHS +z^kaDVOjM~1ro6q~dbV7`=Bna>_`EI!lAcjRp#xiQYIP{Ng?}tri?4pEgN;Z+_sIBSfT2t;#{+4PSDV?aniG__`M&I}m@5nPR=r6te&v?DdMBp#wQ!sA%Iv55 +zoh2+itwn~@3B*FPzBGpu(IL+h>(%bp`eW-dUhe&V{p^N^0V9Sc-iZgcEloRjB4gn$ +zm%`LSi@Z<)4Ja^}U +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 +z@J^#$N(LXxDtI*w8{1)7BhY(bltf +zQ^lUf&ima744j +zB%PGRr`o$e>lL6Dp9kah+;wzaYS6nPG1O%~=>ks)YC0)BKLN9yoEd1<>vGXxq$skXC +z_PM-{B_VWo{@a{Av8d@jC(oqYGI86&tB}E{Uf^K+mJ%IYh52+v)0ak +z6X2nfGae9Pe{sKyjrv>4kq>X?x$arP@!Y|_#uM!}FLQn-uYW?c?dbO)uiL2g*6s=3 +zkXFOoWxJ{uxrn{FboEdcy(O#(>n~!T12nl;oBh+&Wxd*`yVX34RJ&3Q&n*uX*;{n| +zaa~8zrmz^h6|Jo$2}9<7@x$hV%94eFn`i1beBQn_UdeOo?8yZW`BY|n2Nk0Ns_bq) +zO|-L(D%n4C+j>f+Y5rH$`(FYT^K9(HstWfmt@gcWa7&qg$-R#n4t)>B+GN@14lhM) +zX?J-L9=fez?QBhZn;c1J)rK0a+KtV*a_qy{3244oKlXGBl0w}d?uPpx-fWOUd^V1vGaC^->4rL);)D4uw2?P|Iht3h( +z!m)%#LubJ?E}%*W7IfD`@bb0kkI+y$K@=qrbU^7EE}S6} +z(K&F{3I~qi(iIF9BnX2_HuwhGa5oH*PMCx0LRd}+DGTI*Dk#9BaJvZygDRdRh?Ib1 +zae@w{j~$Byx&m%U0pf6d%UYB`;iNjlojx373xXKXLs2bm{F)aM2P#8Dw_$Lt44f^Q +zO~8n}7#Dn!Q69Kj2q8)k=D?pJT&4rp3USa-P=!Z>2-4^-xI2i3l8Miu5FoX1Hx9&1 +zCDRG0vZM;8448z<(m3I_&cOpw8yq1ZaS4?`$RMIzaM=z-NF+2GB51>0gm?sXltRcJ +zaElE}mm*jZ;M4@9eKy=vlTHxj=Ry}yXLBeLl_75g!a~#-N}fRAgnTKXYCsk4T!MTr +zhO2Of@nVBJY7kzyP86v0psDzUIB;8)ESx8X-w(kM!f_52Y!9l*vj}oYC#nEN3aU?( +zfh&@hqMQVE8fYn_4sZn%3T2Q3H`oXnr~xjVK~WLBM4_H=Unt=tqzf+o +zA&3!dsJM+MUKZf$MuZ9_!DUK>uTbm24QLX?hM`h)Su&%R$ONJy6gEPE!a&yvLqdSc +zZn%;MOenz>cvNs{4+7@_5Yzx$i+?K;MBvUUB3#1+m-EcQQizBarbn15m%Z+}fpGAmcyodWH+P8h!kL@XVjPODZq7mOj0@8(67UO? +z@CQThN7La@{ro8W8Ws3qfF%qAIj9M#NYX(N!XiQVXQB%K(&01?K@h%(+OJ5+9tpTC +zs|_XQekUOr;_!V8C2B#lUL(!4kC;P5;&A&4l(^|T0a?KZ-^D2Lm?#Np7K86bh~XO? +z#v!cIf^?h^BO-gb!Fn3X0wM6ji9uq~Su(O#6zukc*D&ZFh#EB*(`FmkY$t(713a*4 +zBP*~00nakQ0#EMO#o$sXgd#`h0EsQYGUf+J$fYR?g7HHwEteo7KGOi8-4U~6i3seC +zBG?m@I6aIalCo69o$U3vA9ivc?`6}Rz6H=XBh#`hT00f{J>r|7G01*HKC>9MDB|XBw#lhFcWuPg) +ziAC%Z{H7S)fkjN|2N6+s1<(sgvk;>oVrnePLva|whZE2M%AIS-NC*ykQ0$!xfmv!{ +zKv~m-fW-HM10KE}wo^*rxE3R8y>BqY#FiE3**-Gz6E8Kqpt6&pIJU4{1WibYs1wU& +zK?ng+g$uSAh3oW)gq%+XfQL!4Cm=iBz#AUVw;~b}#RD$oaGe<3EQS=Rf(yqlg=@I2Hpg +z!36}wa4v+|4*5*_f*`qYK^LU +zcaz~Qp%iGA+CkcXfVUy=w*Mi5v_J|O)Q}qp@`V?G6S&+gBqL^cv#0~WTSi8<3jo*x +z#pQbxMJ$!@`~qk_PeN*N7fbL~Y)xSjI1ZroFv<+G2fV2S6OduJr;8CLD-uOi@LcW2 +zNyCN{gFq~Roy`Q~8D5ma5aufMh1>8j_?2%KvJ}J>1t1RI)b}IEB%U@H)v)_7P(%xF +z4btFZWJ5s0;5IV63`qEId?!OMgAF0X>}EJ;+MGs1EQH7n(Em9q!A%{r=TbI9r-A#U +zLf?UTU?S9P8JNa^Bj$w(QMJ6`u74b)kp-xSHzG(G0Lpa&7ww8W+$aTr{FBHJ_fUPc +z{ew&zS%~uC4-26a;OCbYytBp9$pXK;;1&!ol$X#M;E7>*fveI^vXTb|o+4>#DJ1VT +zo}wL)JQGOXI6HaikUU;xR`O0k@?-(9lE<@&NfB66o!+j +zfhjQCf}V;Ba`^p0hStMHarpz26>x?@ekBIV3t>=UCkD6pOJZ;fR$>sc71Vzjx{y5fR0SESOEH#F#{3l!l&x#E)?BLoV=W@LM`8md>TS`!O*i +z8k`k^S*(EPmdOena;z}^kWUK(A+jXkCdm6L9RW^u#_;f~I0YDdH;TLQ3jAljV=(TY +ze1}^wBm2*+#%PScSdEJJ!E9EOWr1Hj!eGlkS&d=wC#&HWf2m#Ef>pZ|ocHlUViX(B +z|7;e<+Xwc)&wGq`{!ATi@t4%$7Hr=8#VU9mt`hsrDvT1snd`4U`2XPpZ$g}(^_iK( +zE84Se4C@#$QL4#tjroS +zIQ9^bp_%`~-giJ*Rcza?9nLc)W4* +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 +zHB-d0S^g@kA6 +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 +zvf+alM_5{ +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 +zb9Y(q#g-WXGo3LdAU}QXMSJOIY7|*Qiq(rz +zo~SxK8Ia?7y^w`T0r_#87jkC4BQZNa+@~Z|v +zzhy{Ld#^a6hDZd%60}vfeLEfX`YG|6CB@FAtei9 +z?QV(3dgmcrHYo4aw8RRm)^cHmC7Ag+HY+)0VF`|P5P4X0Gqd5qI^6(9>scB{jH$hh +zcH)L1KWFyTf5bXNmJl!`KYn5A7p$;ZuL5jo00+i(6%6~8J+{o&mLd^L=fNMm`ji}H +zN;kbwbmQBAEc*lbK=AHkLFUSIScTbyKlVeb9Qg)oxWUa>_S}UH?QtUk@PiR{Ui7q& +zarje#ir9ap^;BT*Vv+p>OjG=TC99xI3KSV_%9eO9%?&f4)(KUbEcorVSzme~8LD9& +z7*z_sfP9X@Fc*a#3O)gDH5M6a08nY#LUcv&{!#Dd$({F8Op6f&SMv8 +z7gSh*cI$9P1PgoQhLaw7pnNCr$6o!k$dT4z30#5%zA0+TF4&X+fBkCjM{wHU)v1sp +zxr4G3r|JVqI9>2XL;Rpd1puabel>mxtq;;Lc7m&l6tchh8e2V*jhfcVpi22bF?-98YLqlhazJ928h;${C?)R2*k;F(MsR4rE6C&+AqBKOnL1!4?GE@Gaf3f^4X9XCrt>L&;73k@YX?e`euZ4Zk)$xHL}U$!*XV9w``?7V;w +z*7Uxtjw~Wz3AVn5Sts^aRLDEuII@p`A!`R)GKV!~8apEfegcO4@PbGsf)HwYaE-`> +z^IoQB9(Lq{F6hn?IJcrhu4X}h(FN^*6_m5Ora1;+=S72CPY2|XZl4dcIC6N7$2wO- +zLt5P9NmRyR`C}-L4us$Pe8gf4Y +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 +z4GlGt6_@UNW5{mIOi&6XX0(~x?ldQN +zn-G<^g*dvmzmN2L-g9g5n%C(Vo>t+pnq!~bhP20e5G#BNtFbItHyu@F?)N&H;J?Z2 +zD)%+I={P#u=@*Gw|3g{aVI?mLqU%(#fg`sHtAa+@DOu2LUP1q39n{qhtdO|k&#=^% +zmlwE}eJs2dmZ7!h#YJX%gi$DzagUK4S&R?H7(~LLK-ReGa8F671cEs_Ik>@#fUPtM +zG!Nz$KSo6rqp}|(pN;`}w1qa13${?0k2WLGM(e4UaNPqF3UDY7y%fI6ofcu7n&K@hBa- +zw6(RZ`+$_n5s#*b6(4r~VM2;VOq}5n>w1^89K{?9lKu8o?opt=$#^QD>BBg6K!Zt8 +z8+mbMon1*pM!JjD5-g>8`hnGC8!@WgQOG}v1ofx`eJFt% +zusE26yPanw`e|I{1+H>$Mg`*E%oa(F!v6DeOvaMB&&$DDAfpDFP5xH`a%(EIdZA)A +z1Yyz4H1?U1kj5;oX+1;AV&>IW6(AhBj3t_Cz&t@&urFSw>xwT;D2l`W>OnS5@E>H; +z1pOczaelDyU!4;ug#YSX6NExr#ea2<1VoVNSLb?y2Ep@jHTTuIeqJR1K{icDdyuU^ +zqCf|u9%M`Z*a)!J!kVmQ{xYbW5mC!rV_!@pq=`uaYy%u`ahvWJ4E+Z?_%df$G&7BT +zW+bFBi|YuPlk~PKKsYkzeizpURx+RJ5o&@^w4V_l+4ZQaCX`3fR(NBmWT!NOdb=}p +z3w~WT$gpT@BOG22H7X4dSs0Jsp<(Z7$RMN)#Q}6K=q^W|b84u^{4~LR +zc2Gi3F2oZFOn#q{G1LWMIzX}Ib|Bmo04tbMth|Mh2rPJpm&rQ-6nxCdu1+tL&=3S3 +zVe+pt_ym2O!6)eJ3=MRWfAU5U%E27m8$kg6X +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 +zOgBmWAY7#djy&HJAO^RF`aV-<&ZQ!C)w +z1kl9ot~<$Jwm19Wj~&@>%PAb#EYDNh^RC#k^*F!>0Jq=6cy=`;<=eoGYmc>`hpu=a +zJ#NPI=oXRkw-N2r2jR|qh&23lwK7vh_TsU|@}&V*pTG|}O$bZ*_uw0~#)5SnBj}2=Yw*Z2N43kM1mECM&}=I_(6|~- +z!Qm9PVz4Y9Zs06I8fM!04cvi;|E9o>e7G;dR(J&r=B>i0f?F{vBxfx{raj|vYmG@> +zR~%L-&)-{Y(GJ(u2pR+Y{ub^if8<4LH_4J0rh+x=GZw$f@jD(TQDw`J&ym$TkcKi? +zGz7n*I2qAc>O6QFq_YlL&<4BsWKF>*)Wq}!2Ut{bQm~)7Sy%h!a{);|&NMjl$%c!nigk`rj&y7738d8-OX>|k2+Niu2j1df +zGqN}@!gPIwrxX=P#Z}CChY-S=E``D9Od(RQm!tRgrt(pu;~z%vrS33fM-b~8yLGgR +zj?B<{(0jijZ|ep=HqDkXvk;A}tFFUu4v-s5P#f=07o@1j`n``V`Iu#cM8*9jweK1R +zW#2xKDqv#uN*9rvM?8?PBrd-m^FZ5~mNfs~1I=a`^4n1loV_4&O^39vVn~_qypUcW +z`C64{T}a$VJMXA?NUB!WgO!LFlr`C>`y1r+}Pe +zFJs8|&R7r8AZ!PvzK(YImL&yQC`QYC5eToV-seaK7V4^d +zy%%9_zbv0|W!tB4xLI!nn2_MO8FYn?*2IMmmBH^Y-Znky +zYAkeJ{5s0JZ7k`91v^!PPFcZoJZ{wN#j0J^UQo_8eFE|-0Uv4pezPTy5xj|zN^=aE +zK`UI+ +zaon9^D=U_;6o;wIgFhN<-XiBCxQljnLr{7y!D}9vuy06-NY9DTxEm`hSqayw=M!kM +zQD|fHmBNtmweCV2!({!Ij%j4+%82#afk3rjBpu1LVoJ;C5FA03vSI};4^YpgNZ +zD-+BaUvbeym2QPm5n1HU(2U4*dcm%qdVnw7nf{j;$~bIeQg3g)%Pt9c<`)(uL! +zcf63`7kJA{=QH;TUR5~ag|x{MkQANfK3o`>-xCZfK{+?4ccg0tFVpSlK08N3Ft;JE +zYnZUQ@+yuv9Y%p1j-!Y+)Ujp6dcZ`8Xwz^@GR_9G5)hGEPyB +zvm~fiH+Yxl#)DA8uy(wOU+;N5tiF$p!5;De_dC;NODaurzgNLg{|ql`Gk$%?k#~nH +zx>#*)!fHGLPz1Meab;-fAou(2U$J@0#GwE3B8GcrhHv>9zv=XpqQl0St=LhjmB63= +zm_=9>UlG}eOLg^-&DCR;T)7N0gYQ}wOnKp0NPQoNB%9$HAL!oY%<{#8QZ64TOAPb7 +z@*YF$#ri?{3ni=f4kQ3#?_~VBjBmS50b3rriko4$T5pfTGg1BXhg`7pmMJIlxxjsX +zz#26fyWDsmrcYVJ>WGE0DGS~2E#0w>3y&3a@Eykc#-#pX +zd32az#bYX*yv6Y3xUIo*E0*|`iWrOg=w!7aYW@FC<`I6@w +zuRHR|ljO5O_r=@b_M!R~ +z(;Hd<~bR7RF +z#!&V`2*;VLhh+>FEX`|ZY^xXUBL8?1l;Vt;j}r$K^Qkv*WIU`W4{6w7hJ{6O8SmM;J6+?hgonP=v)y1u`U}IZ*yR^ +zvyVt0+!~$XKp=I##*PL-0tPp;H6mH_6EUEYlm!%3%UO+KR7q*gJicY=6n)4*+_$X~ +zktIzH>*OOMSDy{bk{(7>DOOy@^9p#Of61dvnO5qpHG*<|H|X%2Rq@nZNiFFHss?2s +z#fu!8Rj#=ertc4PJ9BCNVW9QqkgfiTv`B;A9mS_N{$kE(#x +zj;+i_{ZyD4#?;bG#2@?Y0^Ih%@9Ncl8G?9mCN`A2L|pJ2-sD<`F_Vc>fp*Y;oh~xmjc?68hIvHc3Lzcer|%hrpV=r8 +z23^dJSV%KxaXadhCL;6ON2F0Plj89i^FZD0j=Y0gHY%iFJxd(iX;t9BG5m}I*)YvwEN`{I=7SqjF(74` +z8$!gah2;d*r>yR)0@A!uL?+`0^nSt2vL7MZ?POgMbXZYs>akJ3_kTZ8vh +z$Bzlsj>wc|7;eipcI0=wd!oQwM-6!nn-2t@4tDquZ*Sq``;-(!UONaIs2DC4$cF9Q +zk1(BA;JL|$T);#{fw}0FC2_x3f%^|*jn4Ey73@mB4P|18D^L68BaVECeU~Xeqpd38 +zAo0TNhNVO(0m +z8b`a+@LF(o@hC>KcAtZL@zb{aNRSB+LLB}K6@%Gpw-NiJL*YbK#&?aG6r>AQ)6jM(gp~_D;|iXs +z>DvODH4{6dSU%~S4a4&HXc&G&cfKBl*$=<*R!N7_vNQz}dHF|EE~2gacchR$gwojKD`65q(k@m;JzKC5PdXk##rqdw +z8DGhRKZ1T>_bp{gj`>09w}`2yVJ*teJHeEP;a~Kt$kaF49WP?=Y{OV4jTy{6_Rt$y +za&#U@6PQq4;3zjD;F7kHgsprS>5MqCz*t>KVoB_t74XUfoUVTEOAm_Hpp7A~BHDl# +z;B%gO)s}ZLnhcnPX;C$78@-Iy8$hS*cq-n%%nVQujvJ%c-Mg9Um4*S6v0!6&y$DI8 +z-UIT&-K|g^KhCJZ?7WU_{K*UXC_SEJ!JLE9Q0HurMRUxrtj$;9Eko~?cSi;BQ;zfu +z8*;qq3b9x-Z1Qpu{t-y+p`FL6CTx-6?n%Gy7y)^#uW2lIs8%F7GN90d>HMXsZUw= +za!b1RId-T4us6mIKIoM00NY7zXg`O2v$HVr>3$@M<4~sJuXzb0Yyov(_Yg`%A30rT +zlHl6moXJY850Ny1>@T3^)`I;abMcXGfsvVGLq8Nvua)-0PtnXm+0wmhL{=xI-5p5x +zo{=2a4pyHDY9m4JCHW!;8>ityKU)cr_Zql_dl8|~S`e0cgkm71JcwUnpVZuqQJ93a +zc<^5TWCn&7l+(zde)*7@C;|@O1^ENUKB172SAt7WCsLq?iirdZG;%3WL*@h7;h%K` +z&TG9boWK}Xx8iux1f~ezV%A6d*p-&SBc~Wnnno6~1JRem&ih5iF)+8KWYiK3sAUv< +z#Z)IQ()G7OSu+`u+79ssSb3Z)_^65ha^J`j+J^skz<=F8GP8um_vi0lU +z+v&c2yORzO(g`7uu&QvQz9X4zC +zF!3b{Vob-8=DJhwqcGu-e5N05lTV-BPv0%AZn&Vf2%WcqEEN2l+kcK=m3~ +z-now39sFL6{CVer-vS@&@L%coir?;75POf$?>+=HziS9+e%BK4`8|){KED^^+wi*? +zz%R^i>kJ`UByB#w*8(`DUt9S7AlRA@^Zu0nx$dj@?t|}>XMx{O0~kx7!h){Fzc9bg +z1HU5|JdWK5bba0;OqXM7;0?ss%X^agVj6NpCL)-hkG|#okti8`u>f}qF6ji6$N_2{ +z=kM4fN-nU5gd|OVXd83Fz>qKO17d5-)?Mu{Z&LofYb5trBuFy=>+ZRWr +zZIrj1vyz-|a__c8&LbGh&q4u0ciso}Y_EeFu{%R@4b#!tL-YW1vpo%@HXq2~&7BFyi2}=iy*w +zsuO@B&ld0TmpFiRAK)QDOpmE<0H%H6h+~*+7=V}H>3NFDuuh7+^c6PrJOJ$g47&i+ +z8+eprOxTLqaPDB-rV0W49#)5toL>X7gI2PA`1}GBe{1S +zfN?j&i3kZz-2mXPuOVigY*_+e>0ht~$yPlEVCqRelkWyFe!3-kFwZgo?;nyQzU>3x +zVN1;g)J9t0_nIR_J;W__u9`3RfB-_QavFNVzHa0X7hB$>=ad>N$B(H?aF+2%AJH8p +zr6$+|yw9IhDbhqdiH<_H>g%@K=^- +z5LC>hSO_^SQg3KhEZ-#}T(T1@8tLXK*lm$NR&b-EJcN2QlFLEY|5Du`Khy)4FL#n2Ket29_`c6KEFKBCo-C3Oe& +zgMB@G?9T4vazsNhaMLX3s9uQ8%HSJbqVEuwx4IX;XQLJ8K)jsJ?PDTc1q`lQyRbU~ +zWk?7ffnQP_6L0c+98&Jb5qtrxE-aHp>IBQFzCTA`Jugxx;#X|d3Fq4ZxE_yk^uFaB +z+!-zz*oGk0sXf^ecVHorf`Jz4KPxKA(dnsG(6_feiJQhKL&xLFLRx=CWY?)Q-Ke=P +zZSP3yKD8(@>$Geqry9C=hnl8PkrcyjbpDx5o0P*(mST(*$A0;q8*aA02V(masb!E3E=kEQ^TGRAxo;7Qg9IxL0;hw7Xg5LT`!GpYpx(6}r*9<+XQlR|m2j54pIpM|h2;~PH@5iH|{AS}y>(kxs8!KfhfGuvNP-z6MLc+!>jQ(K^B1lke>g^(L@G`{_ +zs)!MLcT9 +zZ;xDW`(0HA!sg@)<%oT0PQDPq&i0RaCyV`Rs73nr?ip=f4ygp$efzX?UwaTnH@+vN +zoOpBfmwr!;xlglvYseLEtX{Fj{UH{AFSf{GR#5xIx7=eIsHT +zi~SN6(_JVl22ZIBt%k#nw#6L&yx#I2fFdKqN?7YZtkT$3ekDW{XDlpvg}n@bJcXJM +zo}mb*VQ+-N*A*j+ZO8Y)j5wOpsbiP8oUW%5h}d0RPSx`XV48M0O*a7uP0{S9>=fPN +zrxmd~{YjO2kwtm?`E>525b;FkyHzh?f)d3?wl{M(#hcnUq33QQf*P2j64bzijRy8~ +z%%xOtIj}Bt%q0;r2vf&g8ibCyGzcAYX%NF|6s-mkT&@2=h^1izX(W3Md6?;7;|9nh +zB1E1+Xz~m~lV=c`JdN0NNGMH)5WPfXLqZ`cs~{B4*)VSDL`-2zSc=}KT5f)aLzCxI +zZt`sJkf#+_U_ppf$}UKb@)7V>iqyY~L~Oi|pp>NAp|x-N2+qW*d^;z0W)P8v8RU(5 +zMwNOpleD)}QasmEu;yA>{!!DW&PGt4?p`87{4)s6KZDTxGYHK;jo38*C;%b;5s~Fz +z>|9^$IaQEe5x;gRKD&T=G{tpB+oFg-2fLH|!Q(JH0F2p% +z39|pxSTH*D^X>4&buau>sB~x(Yfjr~sY6=`6xki64qZn;>(KnNAJm~0_?c;2=};8q +z9TC)_MRrbDhpzc~bZD_{nL%ds-&WJ1U~gE52FcU<&(q`?gw_EDp>=>kXdR#to7MqR +zB;TdZeC)aMl&LtBxy4TI1_LnF-4*noTg +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 +zRA!Og|(CIqmHb3+^-wv_%C@X0_kO +za?Xdb_&QqIz8|h|n+Sc51nqJC+h>1-h+?j7Kh$#GyabnW^Lu+Nt-C&hd)t@@7Xc;u5@^i#0dc^N?AHLXghh_Zye +z@h3g%Vn0obN;6#Z=RlbTcPxnXzi}U@Ea$ha%BhoS;9L{wGpcQs=1i4_hOG7m^G$YK +z9W?~BE_w%VC3XWz!z^cHy(Qjkhwl-VJY8I+s&*QNpQ>KvDeRe?@Ul9z#}KH(UPVIo +zIh~-o>>)AS`P&yi_TAv8=(HU1A-btBqpr$IH=Qr!{SAc&tE1d7GAIjHLv_p&NxBay +zQPf|Bcts1(Mu0eHCf?Y1q!&=*@fPJ@EpZmcOyNY`NdroJ)|?B>?=hn~XJ9EW(_8@z +zZ^Y^J*0r!#(6xn^0E6p=MEYParU>K(w +zH9QKBP&fL>1i>Qrc`quj!6-ak*w>-y#iQOs?m!85BJ6OVxt=IotS(`bC7?c2Mf^NG +z?}Rl>;VKaE7U-8eDA@4|^&ocm=lZ6 +zvNqsJ`7?NNb0~g0Mjcg6Pg$*)RP=Z&O6x#mB1GvEgEmI!*Dy+)9j|jlr_Lz$B~(8$ +zCOpV=(W{p8y9u}jtUJDOIR7K)gGjw6iq=_9yZv!Gtsn5~)$lkYz|+{HxO5fcspt>M +z&Il=_*wP9pdOn_b!#5W!&pJzVJp){< +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 +zfFGMTwh7(_7%g_r68 +zb?9JO1p_+eh-U`@*aN`WhjH0G0Uc9vwJOkR_yPsGx1zw+|An6mtai~W0jvYizPMd- +z#XYJCRPpUo@#MW2%B-36wlAP*Ectm7K6KY4z;o|=l*)9Y@k56UobAg{sQWp9J#ifD +zF_cmUpnYlF>vV%Ek*mUk%I)%4ZUE8ypH?SflF)oTsE0kkBq2g3!T%K@Q}Lk*Aq}$L +zs$jiiw{X2OaPS*cE4ybY9AuwXqM0)-mz=F*)w9rka(F%g&EZDUQQR(%9A3%q0C%~- +zP~3IT8j7CLg^;!D2t0ujW%K?UfM#zQ0nOej073Rj-UZofc-KbuLcC^vXv;T=W9pzMkt +z*eoMC5`m_9lpK=+%}Y>vG$PnUn$IB#BI3tL5QY)MfBy=I@ +zdeo;&BF+X~&--){(Z0OU8{!LcF5rVcu*ze-1Bl-DQ?hju**hOweN7VCJ4}Lqv2&)W +z1{VTg)uO<<0YPR}fcVO^TqsB}JcX(M3yjChxGjqq+<_$5TP_^x6Uaa2(}=)UUG&x2MnPptdQjahX3*x}l!-gX6JuRJE6IPX9t@hOS*eT*X +znY2~FKlTrlX1^lpD9zr_cFCe@31Mb6C%tyEVR`rJei^(km8?bsZfRvXnppnLoTnRIox-NiU99$n;i?D +zm+a8UTJ5VbTgf8x14W*))RNCOcDM^gVs}QRF!R~9H>guY9UP1}<#)Lh%3Q{3raydD +z)tBBwMHbNl)Q$PFni-BoJ0rL491#|jzZXU016nO%hzosx#>-EyHV)^!j9CnKCM*V*C&7~Q9pv%y$b3+J1| +za^$JZ^mWKJ6pfY92*_w!(0_@Lp%3Yk(2r?k +zSi0GY?YN6lYGAKOKM3cm8m#I45bGt=%vC*dK7N;?aSk#B?3Iq_XeBaVsu;iYPEPzA +zuyxHTC~$<6@@_s#akGRqjC6`OeN_QPICNEkMr``30?wqNs|tuPR~5{FAh07(X4SuO +zdd5h+MkEh%cLH99>vX&i-n^^OFxixcxAFONfNF|+DzYEwq~y(m6$B1;+R1huc_(%h +zSol~cSGG$d%;f^dB86^-yj&oNknJLZ3vzS0^T|Mj+NBY?U6PK`q~lPhPn=PvMf*6zNfCG#IN83QZ`m@ADSfPJ-yG&X4qa7^ej|H&G52_9`xrZt +z2#)jg5GN&!ywLby5>+$`P(?Q)j_!+r_-V2#dNGThf{c;^ldNZ#9MQ-%yz`&9{V`UyhZhoU(lW>(2x>wIQu8RX(3I_b +z8aC-kjX`K?3_??*5r!IUR_<`95Pw2ZV^LI(6QjlQ@bQO0)BquC=i%cJf`^Yo2p&HE +z2w6tyEIfSt2@u0HVsFg04CV41PtQx+aD$J@Npj>Cuw4cphlQn +z2Jsa~sr;Af{E`s&;uC|#X*hl)rU*9p2w+1Eo&rRu!65`2973?cCn8Iz!6yR|YH$!C +z8$2)A;KjiP--x`e8+?zCGY!@V(_n)LG`I!1*fc$$_F|jAgyMJyKkSYlDE%Ifu4qI* +zh=)99r4eS&UnBIMKVh!p%u$wRw85OS`pl=-9A_bd5*j?t;(tb +z{r-F;p*zm(_siRe_faYyH-W%&JMiup)q=MUSSq>YNG^vt_ZeG2B`>s#a;I-CfLT@X +zDEAsgBff{LYxaupt#`3lLJB2tOE#$=Q6>VrSojO(YV8W$^aB^xRiI3BVOgYy( +zAEr8bCBAh>7o3B&447p)S|dUo-2m9VSj(*lpWW+-wjM_4YfZC$S+z-;U+B$@4Ytdn9G>;&!skScm5jz6WZ?cv2R!vdT +z#$nlSf2%OI4O+#rh!{A}Da1C&42AKSG*PTap**Ng_f$8A5ES +zA-fQCuutS{+XTS$2dis6`DmQ!MUB{0E-(oHBLBwiNe59Gug$R{6E3mDnFRX6VEgFg +z91$UKG=REwQE?TAGLsGa2SUCH@Rxu8!4h9}fhk9z;9*CMya)gbnEP;4oIq2KzvLW& +zm-D_;fb>SJW9?*nK8!23&GP6De4;OR|;7^_gQvZ5Zy1!NHsTW=9!ak_S=)!6MS{IJx +zx33GQ;#)U&+HTc#taagH09qF|`B{xFGzhH= +ziQq^xlb%Lobz$xRIB1OX+vV?Y2(#`1(RlpESvZwMz{)9b&#Xg) +zH~}xGFzP@Z6k%A#yTsjmd{^=Nay+HC{B(?B0&{TS_1!~+xC=E!NKJ36f9#b2LRu#H +z0Yje?O)WC@*e2RRniO*YXznh=x909YP*_NqG{WbuWN!QspSeS$>I&R65R$n-cx>Px +zAU;6FJu0J}WFwncxo+et0=kiF0HBc`8+jqJQ6sXUF*ej7&{(#kKgwRu+{v6=_cUz8 +z7u^hCbwnMHeFE7XBs;sLvpgQFVc9M6Sjk_JqB~PypC12mKSxiNA&cy#Z@R|BHnM?g1VApqS=&HUEA)Ivb_(n)_%#-ZsYjmY+rHxtvwSx7etykt*# +z-`yu9;*X%U-?>=4HDc~z3L+-Fmy9QPtV|=$?AI=_E|6o&Y$af8LC1t0sb5DtAFNC5rLgVy08@G7J*mh-9r2e +zSUCu1Mhjw31rS5_v_0W+J-Lwe&W)-&qlQ8(&_!7bJcQtM9zxJC8-^@<=qxnMwg)0) +zm<18iFl$1UW;$O5z)Z}OkT;6Lf{W)_KF&<%8ewu7M8GJ^e=)$1v6>(AfDQ3OBeMKh +z6XeGeNFU-y2tj^?5ah@2ktM{Br-2CZBZ!dvSRdp^{%rw%e1p8L`4M|b;S4`C!tlc& +zviykD&9%g{^f}Q2IeyQW$lU_~Oc-G|!BZr693r<4vc$EXEBY<4tlX=i8ID3n<<8J)Q_L;#=1O-1h +zxSsS~yBAT!(M1f#)-k*1*jKa2`c!;1;Ix +zHLz5SYk@G@SDY5$U;Lp~{39a3KRM5qAqN$jy7Ys9R>fmkmR7}e0JJJz$RD&SZYH2r +zaSH&`Tf3sR)~a{{aG~Cs?2}}AOCz$qbrO;Udn^BDAR+K=em&iX54IGVo +z1&^DGRYwm1llVJ5>rUy#Q5pN&?_(=+6AsG{9g3f$_!;MO@o7I&fjf24Us*ohXx$E0LXdjfi!`TncqSga2w2hY7}RXx`lxOZdxa +zmb>IDZ01kI5I7eT{FeY~0rVIEPqcn{Vs|t%^zsA|czGi6<`-&_Tu%7fyu@L3YP~Dr +zaoZ>7o}Pspw2jhi_!5BHLlA~5GReA*w +z*`{#Pa>=MgPugz5YUr|z-Tj*2)nJdh9xefVRa&- +zVKpMFVTlQ7*sv7t0b+|Gg+-{jVo$3ec^%XQb9iW6W@=%SW3>W5W~OGxDYPZWX=3l4 +zRa%a3j8n56DaZR6HY*io6mVp*1`%oB+Ywdlj=@mb$G>5Vxzw1@-}aMzp-0;I8K?3V)no18mXtcEod^V&zC>pecdxEqT)sS03xFNZ>$2wY8?VmD>#`OT(7ued +zsKzJ=zBr>1MhYMhdxK%k$W?i3$Ee(?z;|Y5p*$G%6$&_j%<>OL8Q4FapjGMqfU~MJnE_Ld0V<9pl}(-G8#$-?MN}^B +zD&NSN>t`XnBhr5cm~vNnbAIA0NW)`*2N1qL$7@$>8JMecf@Ig5u&_r76t&qiO7R!} +zq9koCd4GS7OR~gdl{`w4iU5F|cr)gM3Vin(9_t}#ODtEkW@#$|rW^%o+B9rvBLYHb +zXw$HyjZf#5A^{mT`}E%OHnMJjDLR0qyG6rNa%5}zA_cp|v_?d7zl?|)iui*VD7&wS +zit{imD)07Wm?~6Xd9&X!f6&Qw$Giyy +z`@wXKMr1qYZ6uLo>5lmt2szr>F~aFG+Yy&h4F734U+kPCirJ)xt;n7wj@XCz5~yZ% +zso%x@pq~GGF!(p*h=|AoREhgt-?<`3w6DPTWmfvJsg8JTTYO)o&fn#OHof*-{&J2C +zma05oy8mkeKT(rQ6<$Lz^i}vcj$*CC>i}pKKA+!Og*Ot=Dx3mAb{KcGMg&y2eCB}+ +z(R5K`N@Rxsl4{YvzN@i5B0NY{<+bVnF)B29sfMKbSqZFGKdbR=)Q_ehtA2>VD#oZE +z4IA}CL>DB`s!_v6{SXmUKZJwoN5fh5Lrh4SqH*V=2pLD%G0>o!C#lfH%Fod0|Apm{ +z3>`WFDdY<1(nTsbtMYG_ii4tbekEh#P1OJMI&p`uRZv&e)H3M(5%jX=e +z)H)A6cgFjriGF_CRiNmM4>~6H@(U+Ca(O%NkQ0XMVVa+a#(bR;~kZ+@H?Ft*^gf?ih7_}fUBeK|#B +zc*2J{mg@(mlIxCFzf-E}d&NcGgC}Eu2<7m{;B6#;g?Ss0HK4SlUd|=`(r4lI5%P^! +zmexO78}xaXuBL)0>qz(eE0LLS8n+%_ruT@DbIpKrTjk^O+p}uJ|d7 +zg;)sy1wosJr}b^^US@!Jtc=rooO8oE=BTuLhv)b~c+NLSd?gUx-9CS>U;(??9iyby +zJqg6U($f%2O&KIs!X!4j2*mbb>Q_5T>tGzdQOq_jje&&(FagCM2ha>a&NXpv(y!)E +zm}gM1dkALy^@O*#ixc!@%^d~k0+Bhh&|DNi7_mc}eDSg?eh*m^M6}(KFzfCzWXqhX42f|d +z42HTiB}<^u@wC>Qkx +ztu4Y?Ys>Jc0BG>24Zfkov%VyJjx6NJo_NZqg}=`|A~zud +zzfULsf;mUTrK5U1$+_4qb=xCx{wV-1aXUuGfY3ew<_s7R9S^lygYPMab&mcE +zT5cS^>)$Vm(r~ZCcje=`Kgn*F7N|B4skW#IDrp`jg8rDwM@r3sZA@1xMkdNN$wCsb +zqS)xI2=h~KL6_`>Ry9fDJ0_0v*+I29cXa>cQ9geqJdrk!{+CCUwugjSq4TINA*!eoUWiN2Gr_bBvXKuQ({N$R%HEynFQf`v>dG#Aeh +z4qiO-V@NY2TT+G_v;VW#S5kJVqReTao2s>Y$`pDWDcwvLmAvZU-@2MlFSP{yP?=Ms +zufrEM=X88dD|C~8hY;ht$0rCl`Zs=PBCy2Di~SQ^;gF!f_t?kk68qQRlwrWR89UA? +zm#(K(OgEoxmyZZ88q9iJrWj;VDP!wNJL+oyWTs`ite9}X0m#uAbN~`g`wqbLsPY`S>ym+9 +za+1YSF&Ou0W|}Q&_@*n$Vsif`Gs8-MyL&|5-;$|Ug#{n?Yn!dGZ +zSJoA(!TX+6_C?JIbOy_Ha?tB@r^(0c|A(eTv{1qVBFD4pp +zH7nN9aO(iT?I1_*dwy0kdJRImABf=KFzyG9$hsdAPtL;qqz|arhzxE$r=BEC=L6UV +z{}AO53t`2jmxqJiq4??2#CPBle_IQ3GxG~&V3rGYV*<1K5YT~HH3W2wPAvc(m^F{z +zIxuT70Uemd!Z~xBz$}fB20ng(RZmf(i`9hBwE)oFu@>LDJD4}r9U9?xM>rr~htDyQ +z>lv0MLO*%qDw6htC;AFc68kbs$nL0Ue0M)U<(gAd-fa +zLnU}7(+@!19s+-ULC;1pZ7$~RQ4WE|AY`a9@(VOM+mT{R9P6n#4N)!f~S9i2pO=m7*(xQBHP7D;^xhrZ2VPy$Qy0QiP;d +zysyn#v1!&Xt`%3IN~0Cm0QkAJA}%!6i>n`_71MK4l62YR@`HyhdQ>h +z(XX-6yTQ_><2`eor9A&#(V2SqRIYL4Q_q=d%lrCvbrUWO7A~Rly^jNkLB&?ed)r6Q +z2pBZd>XK*)A|6S4!x0IQ6T&A5?L!#jO%=Xf8!lSS;9XGgtap93Uz$1`y&b1Z-u-W2V`n)$Dw +z`Nkai2t{U`Wyw983qc)t<23v`8WnB@*fQ60$){>CB6AiZL&&eO1T?><2KhCw6~Bs6 +zOORiLw+O$uVH@I?LjCJce+2-u^dAjCt7&%gPhR@F@7|3)2iAvWf2^;+ +z%I8EjWJnGU&TXC}z+37IuAC9Uf!G@jO5lmu{vB?@czsS#s0>h$Y&B?x!s@qDc&BqFFLhzK0d_jgR; +zy;Pd1xKB*{7Q;7ll^T8X(S4b#{n6J*K##ta0F1U;4d8#Twt^1liLiph9=DZh`qWoi +z?ZGxZ-K6%3iRt~opm!}JqHxoS%$k6RQUxm!l}c}5Ape@%qB1Ta^PUycBF^2t%=?&Y +zbR=S#Mr>XrqO6p&uqOJ^F*vk@86fjfE27tKjOf@TXcLN|M>3E^O>3_KlB%0Z%B6Bz +zd=7rs%4sEljVh-Yl@p7jrZEa?4U=mHCC&{fs4@UsUO`o()SpK|$==(zf>N>DGMr&I +z#XY;>vIAB80gV~;==j%{`0o7Q<5r+``#H*=-{N1h8SKYDUx0%WT56=!J-M+CR7TQc +z+FR4~g$hB>Jd+hUs;bN?h+Os2s&g(zYKeFp3n=y$Wf+f)6niry2})JBh}*@sX9x@=^k1jF$EFX1rjRI8lww-sMrzx +zxmg;+Y}M0nCKpY>E`_XOD9lFg(U1c4il`WduyIE16R{%@!TlP-!TlP960~_M$t