From 5ebea9672c7341e95fa2c3e466d80f432079f892 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Thu, 31 Jan 2019 23:51:34 -0600 Subject: [PATCH 01/50] Initial commit of C API library --- Cargo.lock | 7 +++++ Cargo.toml | 2 +- lib/runtime-c-api/Cargo.toml | 13 ++++++++++ lib/runtime-c-api/README.md | 6 +++++ lib/runtime-c-api/src/lib.rs | 50 ++++++++++++++++++++++++++++++++++++ lib/runtime-c-api/wasmer.h | 24 +++++++++++++++++ 6 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 lib/runtime-c-api/Cargo.toml create mode 100644 lib/runtime-c-api/README.md create mode 100644 lib/runtime-c-api/src/lib.rs create mode 100644 lib/runtime-c-api/wasmer.h diff --git a/Cargo.lock b/Cargo.lock index 9d4912143..aab4ff843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -728,6 +728,13 @@ dependencies = [ "wasmer-runtime-core 0.1.2", ] +[[package]] +name = "wasmer-runtime-c-api" +version = "0.1.4" +dependencies = [ + "wasmer-runtime 0.1.4", +] + [[package]] name = "wasmer-runtime-core" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index b570c9b09..d84cd66d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ wasmer-runtime-core = { path = "lib/runtime-core" } wasmer-emscripten = { path = "lib/emscripten" } [workspace] -members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests"] +members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/runtime-c-api"] [build-dependencies] wabt = "0.7.2" diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml new file mode 100644 index 000000000..938233964 --- /dev/null +++ b/lib/runtime-c-api/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wasmer-runtime-c-api" +version = "0.1.4" +description = "Wasmer c-api library" +license = "MIT" +authors = ["The Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" +edition = "2018" +readme = "README.md" + +[dependencies] +wasmer-runtime = { path = "../runtime", version = "0.1.2" } + diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md new file mode 100644 index 000000000..d5df888e4 --- /dev/null +++ b/lib/runtime-c-api/README.md @@ -0,0 +1,6 @@ +# Wasmer Runtime C API + + +## Generating header files +1. `cargo install cbindgen` +2. `cbindgen lib/runtime-c-api/ -o lib/runtime-c-api/wasmer.h` \ No newline at end of file diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs new file mode 100644 index 000000000..ca9f68c53 --- /dev/null +++ b/lib/runtime-c-api/src/lib.rs @@ -0,0 +1,50 @@ +extern crate wasmer_runtime; + +use std::os::raw::c_char; + +use wasmer_runtime::ImportObject; + +#[allow(non_camel_case_types)] +#[no_mangle] +pub enum wasmer_import_object_t {} + +#[allow(non_camel_case_types)] +#[no_mangle] +pub enum wasmer_instance_t {} + +#[allow(non_camel_case_types)] +#[no_mangle] +#[repr(C)] +pub enum wasmer_compile_result_t { + WASMER_COMPILE_OK = 1, + WASMER_COMPILE_ERROR = 2, +} + +#[no_mangle] +pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { + Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t +} + +#[no_mangle] +pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { + if !import_object.is_null() { + drop(unsafe { Box::from_raw(import_object as *mut ImportObject) }); + } +} + +#[no_mangle] +pub extern "C" fn wasmer_instantiate( + mut instance: *mut wasmer_instance_t, + bytes: *const c_char, + import_object: *mut wasmer_import_object_t, +) -> wasmer_compile_result_t { + let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; + let bytes = &[]; + let result = wasmer_runtime::instantiate(bytes, *import_object); + let new_instance = match result { + Ok(instance) => instance, + Err(error) => return wasmer_compile_result_t::WASMER_COMPILE_ERROR, + }; + instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t; + wasmer_compile_result_t::WASMER_COMPILE_OK +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h new file mode 100644 index 000000000..3d57c81ea --- /dev/null +++ b/lib/runtime-c-api/wasmer.h @@ -0,0 +1,24 @@ +#include +#include +#include + +enum class wasmer_compile_result_t { + WASMER_COMPILE_OK = 1, + WASMER_COMPILE_ERROR = 2, +}; + +struct wasmer_import_object_t; + +struct wasmer_instance_t; + +extern "C" { + +void wasmer_import_object_destroy(wasmer_import_object_t *import_object); + +wasmer_import_object_t *wasmer_import_object_new(); + +wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t *instance, + const char *bytes, + wasmer_import_object_t *import_object); + +} // extern "C" From 6f051467371550f0e990a27632179508c7f1942b Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Fri, 1 Feb 2019 18:52:22 -0600 Subject: [PATCH 02/50] Use build script to run cbinden behind feature flag --- Cargo.lock | 93 +++++++++++++++++++++++++++++++++--- Makefile | 3 ++ lib/runtime-c-api/Cargo.toml | 10 ++++ lib/runtime-c-api/README.md | 4 +- lib/runtime-c-api/build.rs | 28 +++++++++++ lib/runtime-c-api/src/lib.rs | 6 +-- 6 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 lib/runtime-c-api/build.rs diff --git a/Cargo.lock b/Cargo.lock index aab4ff843..9bdf7ccfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,21 @@ name = "cast" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cbindgen" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.28" @@ -327,6 +342,14 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.26" @@ -335,6 +358,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.6.11" @@ -470,6 +501,14 @@ dependencies = [ "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -505,15 +544,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde_derive" -version = "1.0.85" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -564,6 +606,16 @@ dependencies = [ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "0.13.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.26" @@ -595,6 +647,19 @@ dependencies = [ "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.1" @@ -623,6 +688,14 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-segmentation" version = "1.2.1" @@ -662,7 +735,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -732,6 +805,7 @@ dependencies = [ name = "wasmer-runtime-c-api" version = "0.1.4" dependencies = [ + "cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.1.4", ] @@ -806,6 +880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" +"checksum cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32e01024aaf5390d6a8145047371a4f5b0063a14c1e411bc731353bd2278ca44" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" @@ -841,7 +916,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" "checksum proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "38fddd23d98b2144d197c0eca5705632d4fe2667d14a6be5df8934f8d74f1978" +"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -857,25 +934,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "534b8b91a95e0f71bca3ed5824752d558da048d4248c91af873b63bd60519752" -"checksum serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "a915306b0f1ac5607797697148c223bedeaa36bcc2e28a01441cd638cc6567b4" +"checksum serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ac38f51a52a556cd17545798e29536885fb1a3fa63d6399f5ef650f4a7d35901" "checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e" "checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3" "checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04" +"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9" +"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/Makefile b/Makefile index 44d2f6037..4a700f222 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,9 @@ spectests: emtests: WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten +capi: + WASM_EMSCRIPTEN_GENERATE_C_API_HEADERS=1 cargo build --manifest-path lib/runtime-c-api/Cargo.toml --features generate-c-api-headers + # clean: # rm -rf artifacts diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 938233964..d1e2b7cff 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -11,3 +11,13 @@ readme = "README.md" [dependencies] wasmer-runtime = { path = "../runtime", version = "0.1.2" } +[lib] +crate-type = ["cdylib"] + +[build-dependencies] +cbindgen = { version = "0.7.1", optional = true } + +[features] +generate-c-api-headers = ["cbindgen"] + + diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index d5df888e4..954d2e0cf 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -1,6 +1,4 @@ # Wasmer Runtime C API - ## Generating header files -1. `cargo install cbindgen` -2. `cbindgen lib/runtime-c-api/ -o lib/runtime-c-api/wasmer.h` \ No newline at end of file +Run `make capi` \ No newline at end of file diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs new file mode 100644 index 000000000..c1d68e431 --- /dev/null +++ b/lib/runtime-c-api/build.rs @@ -0,0 +1,28 @@ +#[cfg(feature = "generate-c-api-headers")] +extern crate cbindgen; + +use std::env; + +static CAPI_ENV_VAR: &str = "WASM_EMSCRIPTEN_GENERATE_C_API_HEADERS"; + +fn main() { + if env::var(CAPI_ENV_VAR).unwrap_or("0".to_string()) == "1" { + build(); + } +} + +#[cfg(feature = "generate-c-api-headers")] +fn build() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + + cbindgen::Builder::new() + .with_crate(crate_dir) + .generate() + .expect("Unable to generate bindings") + .write_to_file("wasmer.h"); +} + +#[cfg(not(feature = "generate-c-api-headers"))] +fn build() { + panic!("environment var set to generate wasmer c API headers but generate-c-api-headers feature not enabled") +} diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index ca9f68c53..8f95e8331 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -5,12 +5,10 @@ use std::os::raw::c_char; use wasmer_runtime::ImportObject; #[allow(non_camel_case_types)] -#[no_mangle] -pub enum wasmer_import_object_t {} +pub struct wasmer_import_object_t(); #[allow(non_camel_case_types)] -#[no_mangle] -pub enum wasmer_instance_t {} +pub struct wasmer_instance_t(); #[allow(non_camel_case_types)] #[no_mangle] From 62f7bb607e48d852884108d1e45d020bed7ec38a Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Fri, 1 Feb 2019 22:10:36 -0600 Subject: [PATCH 03/50] Add first c test to test the C api --- lib/runtime-c-api/README.md | 6 +++++- lib/runtime-c-api/build.rs | 2 ++ lib/runtime-c-api/src/lib.rs | 2 ++ lib/runtime-c-api/tests/.gitignore | 12 +++++++++++ lib/runtime-c-api/tests/CMakeLists.txt | 11 ++++++++++ .../tests/runtime_c_api_tests.rs | 4 ++++ lib/runtime-c-api/tests/test-instantiate.c | 9 ++++++++ lib/runtime-c-api/wasmer.h | 21 ++++++++----------- 8 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 lib/runtime-c-api/tests/.gitignore create mode 100644 lib/runtime-c-api/tests/CMakeLists.txt create mode 100644 lib/runtime-c-api/tests/runtime_c_api_tests.rs create mode 100644 lib/runtime-c-api/tests/test-instantiate.c diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index 954d2e0cf..7792a8c17 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -1,4 +1,8 @@ # Wasmer Runtime C API ## Generating header files -Run `make capi` \ No newline at end of file +Run `make capi` from wasmer project root directory + +## Running tests +`cmake . && make && make test` from runtime-c-api/tests directory +(TODO run this within a rust test) \ No newline at end of file diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index c1d68e431..40398c2f9 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -15,8 +15,10 @@ fn main() { fn build() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + use cbindgen::Language; cbindgen::Builder::new() .with_crate(crate_dir) + .with_language(Language::C) .generate() .expect("Unable to generate bindings") .write_to_file("wasmer.h"); diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 8f95e8331..5decf8d75 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -23,6 +23,7 @@ pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t } +#[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { if !import_object.is_null() { @@ -30,6 +31,7 @@ pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import } } +#[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_instantiate( mut instance: *mut wasmer_instance_t, diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore new file mode 100644 index 000000000..4e3d6fb5d --- /dev/null +++ b/lib/runtime-c-api/tests/.gitignore @@ -0,0 +1,12 @@ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +test-instantiate \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt new file mode 100644 index 000000000..4687b27da --- /dev/null +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required (VERSION 2.6) +project (WasmerCApiTests) + +add_executable(test-instantiate test-instantiate.c) + +target_link_libraries(test-instantiate + general "${CMAKE_SOURCE_DIR}/../../../target/debug/libwasmer_runtime_c_api.dylib") + +enable_testing() +add_test(test-instantiate test-instantiate) + diff --git a/lib/runtime-c-api/tests/runtime_c_api_tests.rs b/lib/runtime-c-api/tests/runtime_c_api_tests.rs new file mode 100644 index 000000000..f9112c83c --- /dev/null +++ b/lib/runtime-c-api/tests/runtime_c_api_tests.rs @@ -0,0 +1,4 @@ +#[test] +fn test_c_api() { + // TODO run `cmake . && make && make test` +} diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c new file mode 100644 index 000000000..f801fa044 --- /dev/null +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -0,0 +1,9 @@ +#include +#include "../wasmer.h" + +int main() +{ + wasmer_import_object_t *import_object = wasmer_import_object_new(); + wasmer_import_object_destroy(import_object); + return 0; +} \ No newline at end of file diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 3d57c81ea..6fd391dec 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1,24 +1,21 @@ -#include -#include -#include +#include +#include +#include +#include -enum class wasmer_compile_result_t { +typedef enum { WASMER_COMPILE_OK = 1, WASMER_COMPILE_ERROR = 2, -}; +} wasmer_compile_result_t; -struct wasmer_import_object_t; +typedef struct wasmer_import_object_t wasmer_import_object_t; -struct wasmer_instance_t; - -extern "C" { +typedef struct wasmer_instance_t wasmer_instance_t; void wasmer_import_object_destroy(wasmer_import_object_t *import_object); -wasmer_import_object_t *wasmer_import_object_new(); +wasmer_import_object_t *wasmer_import_object_new(void); wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t *instance, const char *bytes, wasmer_import_object_t *import_object); - -} // extern "C" From be19e9666967f80251023be57e8c1d62271a0938 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 00:26:10 -0600 Subject: [PATCH 04/50] Implementing instantiate and call --- Cargo.lock | 1 + lib/runtime-c-api/Cargo.toml | 1 + lib/runtime-c-api/src/lib.rs | 66 +++++++++++++++++++-- lib/runtime-c-api/tests/sum.wasm | Bin 0 -> 71 bytes lib/runtime-c-api/tests/test-instantiate.c | 26 +++++++- lib/runtime-c-api/wasmer.h | 12 +++- 6 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 lib/runtime-c-api/tests/sum.wasm diff --git a/Cargo.lock b/Cargo.lock index 9bdf7ccfa..091154677 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,6 +806,7 @@ name = "wasmer-runtime-c-api" version = "0.1.4" dependencies = [ "cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.1.4", ] diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index d1e2b7cff..4d049ad1a 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" [dependencies] wasmer-runtime = { path = "../runtime", version = "0.1.2" } +libc = "0.2" [lib] crate-type = ["cdylib"] diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 5decf8d75..3235e4196 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -1,8 +1,9 @@ extern crate wasmer_runtime; -use std::os::raw::c_char; - -use wasmer_runtime::ImportObject; +use libc::{c_char, c_int, uint32_t, uint8_t}; +use std::ffi::CStr; +use std::str; +use wasmer_runtime::{Instance, ImportObject, Value}; #[allow(non_camel_case_types)] pub struct wasmer_import_object_t(); @@ -18,6 +19,14 @@ pub enum wasmer_compile_result_t { WASMER_COMPILE_ERROR = 2, } +#[allow(non_camel_case_types)] +#[no_mangle] +#[repr(C)] +pub enum wasmer_call_result_t { + WASMER_CALL_OK = 1, + WASMER_CALL_ERROR = 2, +} + #[no_mangle] pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t @@ -35,16 +44,61 @@ pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import #[no_mangle] pub extern "C" fn wasmer_instantiate( mut instance: *mut wasmer_instance_t, - bytes: *const c_char, + wasm_bytes: *mut uint8_t, + wasm_bytes_len: uint32_t, import_object: *mut wasmer_import_object_t, ) -> wasmer_compile_result_t { let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; - let bytes = &[]; + if wasm_bytes.is_null() { + return wasmer_compile_result_t::WASMER_COMPILE_ERROR + } + let bytes: &[u8] = unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; let result = wasmer_runtime::instantiate(bytes, *import_object); let new_instance = match result { Ok(instance) => instance, - Err(error) => return wasmer_compile_result_t::WASMER_COMPILE_ERROR, + Err(error) => { + println!("Err: {:?}", error); + return wasmer_compile_result_t::WASMER_COMPILE_ERROR + }, }; instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t; wasmer_compile_result_t::WASMER_COMPILE_OK } + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_instance_call(instance: *mut wasmer_instance_t, + name: *const c_char) -> wasmer_call_result_t { + // TODO handle params and results + if instance.is_null(){ + println!("Instance null"); + return wasmer_call_result_t::WASMER_CALL_ERROR; + } + if name.is_null(){ + println!("Name null"); + return wasmer_call_result_t::WASMER_CALL_ERROR; + } + let func_name_c = unsafe { + CStr::from_ptr(name) + }; + let func_name_r = func_name_c.to_str().unwrap(); + let instance = unsafe { Box::from_raw(instance as *mut Instance) }; + let result = instance.call(func_name_r, &[Value::I32(1), Value::I32(2)]); + match result { + Ok(res) => { + wasmer_call_result_t::WASMER_CALL_OK + }, + Err(err) => { + println!("Err: {:?}", err); + wasmer_call_result_t::WASMER_CALL_ERROR + } + } +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { + if !instance.is_null() { + drop(unsafe { Box::from_raw(instance as *mut Instance) }); + } +} \ No newline at end of file diff --git a/lib/runtime-c-api/tests/sum.wasm b/lib/runtime-c-api/tests/sum.wasm new file mode 100644 index 0000000000000000000000000000000000000000..135da2604ae37187b5a44036332649df14822496 GIT binary patch literal 71 zcmWm3F$#b%5JkcFcg3LM4J>jrQwTwfg^P8rE>1g?Xabb9Tkq;_A|-je4dzLSOxC%u T4R>jWM)9Am!tkqx{HgH)a(xRp literal 0 HcmV?d00001 diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index f801fa044..aeaad9f8b 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -1,9 +1,33 @@ #include #include "../wasmer.h" +#include +#include int main() { wasmer_import_object_t *import_object = wasmer_import_object_new(); - wasmer_import_object_destroy(import_object); + + // Read the wasm file bytes + FILE *file = fopen("sum.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_instance_t *instance = NULL; + wasmer_compile_result_t compile_result = wasmer_instantiate(instance, bytes, len, import_object); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_COMPILE_OK); + + wasmer_call_result_t call_result = wasmer_instance_call(instance, "sum"); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_CALL_OK); + + printf("Destroy instance\n"); + wasmer_instance_destroy(instance); + printf("Destroy import object\n"); + //wasmer_import_object_destroy(import_object); // error here return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 6fd391dec..5951a82a7 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -3,6 +3,11 @@ #include #include +typedef enum { + WASMER_CALL_OK = 1, + WASMER_CALL_ERROR = 2, +} wasmer_call_result_t; + typedef enum { WASMER_COMPILE_OK = 1, WASMER_COMPILE_ERROR = 2, @@ -16,6 +21,11 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); +wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name); + +void wasmer_instance_destroy(wasmer_instance_t *instance); + wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t *instance, - const char *bytes, + uint8_t *wasm_bytes, + uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); From 3c7ad109bc4a17ebb077c9a8bdfe9f166f77ce42 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 08:43:29 -0600 Subject: [PATCH 05/50] Fix instance null ptr bug --- lib/runtime-c-api/src/lib.rs | 38 +++++++++++----------- lib/runtime-c-api/tests/test-instantiate.c | 4 +-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 3235e4196..af63b88c9 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -3,7 +3,7 @@ extern crate wasmer_runtime; use libc::{c_char, c_int, uint32_t, uint8_t}; use std::ffi::CStr; use std::str; -use wasmer_runtime::{Instance, ImportObject, Value}; +use wasmer_runtime::{ImportObject, Instance, Value}; #[allow(non_camel_case_types)] pub struct wasmer_import_object_t(); @@ -42,52 +42,52 @@ pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import #[allow(clippy::cast_ptr_alignment)] #[no_mangle] -pub extern "C" fn wasmer_instantiate( - mut instance: *mut wasmer_instance_t, +pub unsafe extern "C" fn wasmer_instantiate( + mut instance: *mut *mut wasmer_instance_t, wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t, import_object: *mut wasmer_import_object_t, ) -> wasmer_compile_result_t { let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; if wasm_bytes.is_null() { - return wasmer_compile_result_t::WASMER_COMPILE_ERROR + return wasmer_compile_result_t::WASMER_COMPILE_ERROR; } - let bytes: &[u8] = unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; + let bytes: &[u8] = + unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; let result = wasmer_runtime::instantiate(bytes, *import_object); let new_instance = match result { Ok(instance) => instance, Err(error) => { println!("Err: {:?}", error); - return wasmer_compile_result_t::WASMER_COMPILE_ERROR - }, + return wasmer_compile_result_t::WASMER_COMPILE_ERROR; + } }; - instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t; + unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; wasmer_compile_result_t::WASMER_COMPILE_OK } #[allow(clippy::cast_ptr_alignment)] #[no_mangle] -pub extern "C" fn wasmer_instance_call(instance: *mut wasmer_instance_t, - name: *const c_char) -> wasmer_call_result_t { +pub unsafe extern "C" fn wasmer_instance_call( + instance: *mut wasmer_instance_t, + name: *const c_char, +) -> wasmer_call_result_t { // TODO handle params and results - if instance.is_null(){ - println!("Instance null"); + if instance.is_null() { return wasmer_call_result_t::WASMER_CALL_ERROR; } - if name.is_null(){ - println!("Name null"); + if name.is_null() { return wasmer_call_result_t::WASMER_CALL_ERROR; } - let func_name_c = unsafe { - CStr::from_ptr(name) - }; + let func_name_c = unsafe { CStr::from_ptr(name) }; let func_name_r = func_name_c.to_str().unwrap(); let instance = unsafe { Box::from_raw(instance as *mut Instance) }; let result = instance.call(func_name_r, &[Value::I32(1), Value::I32(2)]); match result { Ok(res) => { + println!("Res: {:?}", res); wasmer_call_result_t::WASMER_CALL_OK - }, + } Err(err) => { println!("Err: {:?}", err); wasmer_call_result_t::WASMER_CALL_ERROR @@ -101,4 +101,4 @@ pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { if !instance.is_null() { drop(unsafe { Box::from_raw(instance as *mut Instance) }); } -} \ No newline at end of file +} diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index aeaad9f8b..52a095593 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -17,7 +17,7 @@ int main() fclose(file); wasmer_instance_t *instance = NULL; - wasmer_compile_result_t compile_result = wasmer_instantiate(instance, bytes, len, import_object); + wasmer_compile_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_COMPILE_OK); @@ -26,7 +26,7 @@ int main() assert(call_result == WASMER_CALL_OK); printf("Destroy instance\n"); - wasmer_instance_destroy(instance); + //wasmer_instance_destroy(instance); // error here printf("Destroy import object\n"); //wasmer_import_object_destroy(import_object); // error here return 0; From 3633ab8ef4c988e1f47d6400007d26272e4a4e95 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 10:44:08 -0600 Subject: [PATCH 06/50] Add parameters and results --- lib/runtime-c-api/src/lib.rs | 28 ++++++++++++++++++++-- lib/runtime-c-api/tests/test-instantiate.c | 6 ++++- lib/runtime-c-api/wasmer.h | 9 +++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index af63b88c9..2d6d3a4b4 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -1,7 +1,8 @@ extern crate wasmer_runtime; -use libc::{c_char, c_int, uint32_t, uint8_t}; +use libc::{c_char, c_int, int32_t, uint32_t, uint8_t}; use std::ffi::CStr; +use std::slice; use std::str; use wasmer_runtime::{ImportObject, Instance, Value}; @@ -71,6 +72,10 @@ pub unsafe extern "C" fn wasmer_instantiate( pub unsafe extern "C" fn wasmer_instance_call( instance: *mut wasmer_instance_t, name: *const c_char, + params: *const uint32_t, + params_len: c_int, + results: *mut uint32_t, + results_len: c_int, ) -> wasmer_call_result_t { // TODO handle params and results if instance.is_null() { @@ -79,13 +84,32 @@ pub unsafe extern "C" fn wasmer_instance_call( if name.is_null() { return wasmer_call_result_t::WASMER_CALL_ERROR; } + + if params.is_null() { + return wasmer_call_result_t::WASMER_CALL_ERROR; + } + + let params: &[uint32_t] = slice::from_raw_parts(params, params_len as usize); + // TODO Fix this conversion and params + let params: Vec = params + .iter() + .cloned() + .map(|x| Value::I32(x as i32)) + .collect(); + // let params= &[Value::I32(3), Value::I32(4)]; + let func_name_c = unsafe { CStr::from_ptr(name) }; let func_name_r = func_name_c.to_str().unwrap(); let instance = unsafe { Box::from_raw(instance as *mut Instance) }; - let result = instance.call(func_name_r, &[Value::I32(1), Value::I32(2)]); + + let results: &mut [uint32_t] = slice::from_raw_parts_mut(results, results_len as usize); + let result = instance.call(func_name_r, ¶ms[..]); match result { Ok(res) => { println!("Res: {:?}", res); + if let Value::I32(x) = res[0] { + results[0] = x as u32; + } wasmer_call_result_t::WASMER_CALL_OK } Err(err) => { diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index 52a095593..3347c5cc9 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -21,8 +21,12 @@ int main() printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_COMPILE_OK); - wasmer_call_result_t call_result = wasmer_instance_call(instance, "sum"); + uint32_t params[] = {7, 8}; + uint32_t results[] = {0}; + wasmer_call_result_t call_result = wasmer_instance_call(instance, "sum", params, 2, results, 1); printf("Call result: %d\n", call_result); + printf("Result: %d\n", results[0]); + assert(results[0] == 15); assert(call_result == WASMER_CALL_OK); printf("Destroy instance\n"); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 5951a82a7..86f5a539b 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -21,11 +21,16 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); -wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name); +wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, + const char *name, + const uint32_t *params, + int params_len, + uint32_t *results, + int results_len); void wasmer_instance_destroy(wasmer_instance_t *instance); -wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t *instance, +wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); From 9120a9d1f8f325738bb4d701b15bc58947af3064 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 14:53:07 -0600 Subject: [PATCH 07/50] Implement tagged enum for params/results --- lib/runtime-c-api/src/lib.rs | 95 ++++++++++++++++++---- lib/runtime-c-api/tests/test-instantiate.c | 17 +++- lib/runtime-c-api/wasmer.h | 24 +++++- 3 files changed, 115 insertions(+), 21 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 2d6d3a4b4..41d4e0383 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -1,6 +1,6 @@ extern crate wasmer_runtime; -use libc::{c_char, c_int, int32_t, uint32_t, uint8_t}; +use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::ffi::CStr; use std::slice; use std::str; @@ -28,6 +28,31 @@ pub enum wasmer_call_result_t { WASMER_CALL_ERROR = 2, } +#[repr(u32)] +#[derive(Clone)] +pub enum wasmer_value_tag { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub union wasmer_value { + I32: int32_t, + I64: int64_t, + F32: f32, + F64: f64, +} + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_value_t { + tag: wasmer_value_tag, + value: wasmer_value, +} + #[no_mangle] pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t @@ -72,9 +97,9 @@ pub unsafe extern "C" fn wasmer_instantiate( pub unsafe extern "C" fn wasmer_instance_call( instance: *mut wasmer_instance_t, name: *const c_char, - params: *const uint32_t, + params: *const wasmer_value_t, params_len: c_int, - results: *mut uint32_t, + results: *mut wasmer_value_t, results_len: c_int, ) -> wasmer_call_result_t { // TODO handle params and results @@ -89,31 +114,45 @@ pub unsafe extern "C" fn wasmer_instance_call( return wasmer_call_result_t::WASMER_CALL_ERROR; } - let params: &[uint32_t] = slice::from_raw_parts(params, params_len as usize); + let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize); // TODO Fix this conversion and params - let params: Vec = params - .iter() - .cloned() - .map(|x| Value::I32(x as i32)) - .collect(); + let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); // let params= &[Value::I32(3), Value::I32(4)]; let func_name_c = unsafe { CStr::from_ptr(name) }; let func_name_r = func_name_c.to_str().unwrap(); let instance = unsafe { Box::from_raw(instance as *mut Instance) }; - let results: &mut [uint32_t] = slice::from_raw_parts_mut(results, results_len as usize); + let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize); let result = instance.call(func_name_r, ¶ms[..]); match result { - Ok(res) => { - println!("Res: {:?}", res); - if let Value::I32(x) = res[0] { - results[0] = x as u32; + Ok(results_vec) => { + println!("Call Res: {:?}", results_vec); + if results_vec.len() > 0 { + let ret = match results_vec[0] { + Value::I32(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_I32, + value: wasmer_value { I32: x }, + }, + Value::I64(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_I64, + value: wasmer_value { I64: x }, + }, + Value::F32(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_F32, + value: wasmer_value { F32: x }, + }, + Value::F64(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_F64, + value: wasmer_value { F64: x }, + }, + }; + results[0] = ret; } wasmer_call_result_t::WASMER_CALL_OK } Err(err) => { - println!("Err: {:?}", err); + println!("Call Err: {:?}", err); wasmer_call_result_t::WASMER_CALL_ERROR } } @@ -126,3 +165,29 @@ pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { drop(unsafe { Box::from_raw(instance as *mut Instance) }); } } + +impl From for Value { + fn from(v: wasmer_value_t) -> Self { + unsafe { + match v { + wasmer_value_t { + tag: WASM_I32, + value: wasmer_value { I32 }, + } => Value::I32(I32), + wasmer_value_t { + tag: WASM_I64, + value: wasmer_value { I64 }, + } => Value::I64(I64), + wasmer_value_t { + tag: WASM_F32, + value: wasmer_value { F32 }, + } => Value::F32(F32), + wasmer_value_t { + tag: WASM_F64, + value: wasmer_value { F64 }, + } => Value::F64(F64), + _ => panic!("not implemented"), + } + } + } +} diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index 3347c5cc9..4ad4c1ec7 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -21,12 +21,21 @@ int main() printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_COMPILE_OK); - uint32_t params[] = {7, 8}; - uint32_t results[] = {0}; + wasmer_value_t param_one; + param_one.tag = WASM_I32; + param_one.value.I32 = 7; + wasmer_value_t param_two; + param_two.tag = WASM_I32; + param_two.value.I32 = 8; + wasmer_value_t params[] = {param_one, param_two}; + + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + wasmer_call_result_t call_result = wasmer_instance_call(instance, "sum", params, 2, results, 1); printf("Call result: %d\n", call_result); - printf("Result: %d\n", results[0]); - assert(results[0] == 15); + printf("Result: %d\n", results[0].value.I32); + assert(results[0].value.I32 == 15); assert(call_result == WASMER_CALL_OK); printf("Destroy instance\n"); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 86f5a539b..d2c9e2f15 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -13,19 +13,39 @@ typedef enum { WASMER_COMPILE_ERROR = 2, } wasmer_compile_result_t; +enum wasmer_value_tag { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, +}; +typedef uint32_t wasmer_value_tag; + typedef struct wasmer_import_object_t wasmer_import_object_t; typedef struct wasmer_instance_t wasmer_instance_t; +typedef union { + int32_t I32; + int64_t I64; + float F32; + double F64; +} wasmer_value; + +typedef struct { + wasmer_value_tag tag; + wasmer_value value; +} wasmer_value_t; + void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, - const uint32_t *params, + const wasmer_value_t *params, int params_len, - uint32_t *results, + wasmer_value_t *results, int results_len); void wasmer_instance_destroy(wasmer_instance_t *instance); From ffb3dc083ad23a05be87777fd96dd0d042f76cee Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 17:43:59 -0600 Subject: [PATCH 08/50] Add test to import function and call it --- Cargo.lock | 1 + lib/runtime-c-api/Cargo.toml | 1 + lib/runtime-c-api/src/lib.rs | 65 ++++++++++++++++++ lib/runtime-c-api/tests/.gitignore | 3 +- lib/runtime-c-api/tests/CMakeLists.txt | 5 ++ .../tests/test-import-function.c | 46 +++++++++++++ lib/runtime-c-api/tests/wasm_sample_app.wasm | Bin 0 -> 1356630 bytes lib/runtime-c-api/wasmer.h | 9 +++ 8 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 lib/runtime-c-api/tests/test-import-function.c create mode 100755 lib/runtime-c-api/tests/wasm_sample_app.wasm diff --git a/Cargo.lock b/Cargo.lock index 091154677..3c96a0a46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -808,6 +808,7 @@ dependencies = [ "cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.1.4", + "wasmer-runtime-core 0.1.2", ] [[package]] diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 4d049ad1a..692c03cd7 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" [dependencies] wasmer-runtime = { path = "../runtime", version = "0.1.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" } libc = "0.2" [lib] diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 41d4e0383..db01f7fe6 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -1,10 +1,16 @@ extern crate wasmer_runtime; +extern crate wasmer_runtime_core; use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::ffi::CStr; use std::slice; use std::str; +use std::sync::Arc; +use std::{ffi::c_void, mem, ptr}; use wasmer_runtime::{ImportObject, Instance, Value}; +use wasmer_runtime_core::export::{Context, Export, FuncPointer}; +use wasmer_runtime_core::import::{LikeNamespace, Namespace}; +use wasmer_runtime_core::types::{FuncSig, Type}; #[allow(non_camel_case_types)] pub struct wasmer_import_object_t(); @@ -12,6 +18,9 @@ pub struct wasmer_import_object_t(); #[allow(non_camel_case_types)] pub struct wasmer_instance_t(); +#[allow(non_camel_case_types)] +pub struct wasmer_instance_context_t(); + #[allow(non_camel_case_types)] #[no_mangle] #[repr(C)] @@ -53,6 +62,13 @@ pub struct wasmer_value_t { value: wasmer_value, } +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_memory_t { + pub ptr: *mut uint8_t, + pub len: uint32_t, +} + #[no_mangle] pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t @@ -89,6 +105,7 @@ pub unsafe extern "C" fn wasmer_instantiate( } }; unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; + // Box::into_raw(import_object); // TODO Review is this the correct way not to drop wasmer_compile_result_t::WASMER_COMPILE_OK } @@ -125,6 +142,7 @@ pub unsafe extern "C" fn wasmer_instance_call( let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize); let result = instance.call(func_name_r, ¶ms[..]); + Box::into_raw(instance); match result { Ok(results_vec) => { println!("Call Res: {:?}", results_vec); @@ -158,6 +176,53 @@ pub unsafe extern "C" fn wasmer_instance_call( } } +#[no_mangle] +pub extern "C" fn wasmer_imports_set_import_func( + import_object: *mut wasmer_import_object_t, + namespace: *const c_char, + name: *const c_char, + func: extern "C" fn(data: *mut c_void), +) { + let mut import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; + let namespace_c = unsafe { CStr::from_ptr(namespace) }; + let namespace_r = namespace_c.to_str().unwrap(); + let name_c = unsafe { CStr::from_ptr(name) }; + let name_r = name_c.to_str().unwrap(); + + let export = Export::Function { + func: unsafe { FuncPointer::new(func as _) }, + ctx: Context::Internal, + signature: Arc::new(FuncSig::new(vec![Type::I32, Type::I32], vec![])), + }; + + // TODO handle existing namespace + // let maybe_namespace = import_object.get_namespace(namespace_r); + // if let Some(n) = maybe_namespace { + // n.insert(name_r, export); + // } else { + let mut namespace = Namespace::new(); + namespace.insert(name_r, export); + import_object.register(namespace_r, namespace); + Box::into_raw(import_object); + // }; +} + +//#[no_mangle] +//pub extern "C" fn wasmer_debug_print(kind: uint8_t, thing: *mut c_void) { +// match kind { +// 1 => { +// println!("wasmer import object:"); +// let import_object = unsafe { Box::from_raw(thing as *mut ImportObject) }; +// println!("after import object"); +// Box::into_raw(import_object); +// }, +// _ => panic!("unknown kind {:?}", kind) +// } +//} + +#[no_mangle] +pub extern "C" fn wasmer_instance_context_memory(instance: *mut wasmer_instance_context_t) {} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 4e3d6fb5d..30324d55c 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -9,4 +9,5 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps -test-instantiate \ No newline at end of file +test-instantiate +test-import-function \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 4687b27da..7d47da19c 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -2,10 +2,15 @@ cmake_minimum_required (VERSION 2.6) project (WasmerCApiTests) add_executable(test-instantiate test-instantiate.c) +add_executable(test-import-function test-import-function.c) target_link_libraries(test-instantiate general "${CMAKE_SOURCE_DIR}/../../../target/debug/libwasmer_runtime_c_api.dylib") +target_link_libraries(test-import-function + general "${CMAKE_SOURCE_DIR}/../../../target/debug/libwasmer_runtime_c_api.dylib") + enable_testing() add_test(test-instantiate test-instantiate) +add_test(test-import-function test-import-function) diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c new file mode 100644 index 000000000..eecacc347 --- /dev/null +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -0,0 +1,46 @@ +#include +#include "../wasmer.h" +#include +#include + +static print_str_called = false; + +void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) { + printf("In print_str\n"); + print_str_called = true; +} + +int main() +{ + wasmer_import_object_t *import_object = wasmer_import_object_new(); + wasmer_imports_set_import_func(import_object, "env", "print_str", print_str); + + // Read the wasm file bytes + FILE *file = fopen("wasm_sample_app.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_instance_t *instance = NULL; + wasmer_compile_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_COMPILE_OK); + + wasmer_value_t params[] = {}; + wasmer_value_t results[] = {}; + wasmer_call_result_t call_result = wasmer_instance_call(instance, "hello_wasm", params, 0, results, 0); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_CALL_OK); + + assert(print_str_called); + + // TODO review import object ownership, instantiate moves it + printf("Destroy instance\n"); + //wasmer_instance_destroy(instance); // TODO error here + printf("Destroy import object\n"); + //wasmer_import_object_destroy(import_object); // TODO error here + return 0; +} \ No newline at end of file diff --git a/lib/runtime-c-api/tests/wasm_sample_app.wasm b/lib/runtime-c-api/tests/wasm_sample_app.wasm new file mode 100755 index 0000000000000000000000000000000000000000..7c8c4b72abe90b282fd6ba5ef053c845f2c109f5 GIT binary patch literal 1356630 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°k#uMFX@t8OxCdk z9>+Lzh3=;}2{Ob_r*yH-EmO1%V=Gu<@gHNRi|esERO-+XOH^%*?~L0^P2Od4g27%2V-pp{z9Kj{&v=;U)h!!d@yo zBbIyC@umJIyzra(`|e`EPNT**3%6Pr?n+xNL~5%=rfnEzI8V1`Y|GN_oi|y zb_MW>HrKpVJ|+hg{rJ|oWiIq`40HX zW5&xeclQVTUAkfTZ`|+Fg7?9GmpNcJH#{F0%ni3m+s+Ml2)eo9WnecqoPHKh9*JeO z-$mb06w`Vc?Rg35Wf|>z2}n0jT!+i(Jh7@x`3D*8ebJ|KT>fEJ`(N~lWWG47JuvzV zeTSdDIYN^WIqiiB%)c>rT!~3^Ka8Ox`(Z@OlVCrLq1^;DM&EZoOrz3>ZAjV=qc4LJ z9ZaT*)@J!&F-P?3?TzWQ_%Wr!58EhpW@xg4Hp-I!p2d&8ceEawxq-HD z_$gheXwK-{TBp*y*^3;TMte${>Xzt_>*Qd5Tu<>qwGUoOT~V{OBT@JfU9B5XBcAlD z2fyNZN1{etOvCdhx+I^VFi=G>CEzLMvlTZ_!r_As&L%$}_eN|T>mxnptG&&jkC5Kz zSlIR!&>yjV?7MpwUcU!_YabsNagOU^n!qGXX5pzKKVlynn9Ad`=;?m45mRD0ai%Yg z8gXFEPOoYn@RhHe!?j6{OD6Mk1wUrz3u&U3^f~rOkS6odHZ5sFiz|ePTK7KRt5nyi z{c+FRub=5TEd{FQRC)3)q{0*E_chz^YJe--eplILXZGgF-hk|`uCt{bpM}41Cfp<( zLL0jJ3CYl8>Rh$pW=?23945St&^2lM2X>8rjM{HlrY9!)RC4!g%pMjYwdS#W7h`IS z&BoD8+6CO*I{2I(gFcbfkNdg393N^hsyRjIg&`iDE+LO+x-W1bWzW^qX4>KXILrwavZ_)?oor7I*FzK4glgRT~jR=hS~Sn)cfZ!6w1;L0jqMioz= zVzFA4uQR9ZnE{S*Rf|bahW?4%Z{4smS3*WBvuInHD{n=Jq}y@)*IW>5MRV8}X|HlV zW(_iH56zT7!+x2{HtYc4b9C-t$s$Ly>yPTG8l`V1)TEb9-5QBsu5OJ7{$HtEVVX;p zO1bZSwuEYF^_x1wm@SDWPfVIAs^UZkd5GOX!Jv}jE?^lH}hY*1?@E~7z;js$7R zFvuSyT#%gaTxwrCFU`h=`L=lQK*`B%j4bI#J9~Z&omEl<IRkdzo(vSq&aDvZV~Bdv)t4ZD;!moBn^yy$6^S#TNJ7J<~HgJF_#h z3%iI4xVX#;2(pUcDu^orVgzJWR76n0MNly#Cd`;o5m8YwA!f`NFJ{b`F=NJrm@$99 ze|2^DEONQLUhn(8{X8}EKUJsFsZ+VS8aoxF8ewzFvdhbUFFax&^fqyZpWo|nTx{B% zFg;FUSL4>|eSEKx+f!+1?IhnPUF{dBn|4~e$&b#BIh$K5mb~*q-oCO_Jh}8D?$7io z-l{U$F>h6!O=r#d#9%SZNhlBo05eI$Co8%sNb9!6pcVWn0_!$o1vkh0j0h8x&M~V= zMT<9D*ZYl(x@E~$IJVw^2DUgY^;o97R8E+Bysn75_R%c{ticR$amti^Gye}kiV0ubEy6+K!4<#d>iO5 zec-ZOxp?D(m_sh&q+rcwl#Ap&@N6yEP_iEh{EgBs`2e7ROI`pdQYW#HUrv6i)@`i9 zagrxtv-f&HFL^f5RJ>I3VxWn=EIAvf0KD=jWYJGz?<8&~39KkGTyQSg+5|WZ8&f6A zOr14hr$Vnz;uliX+Dobput}JYje%bBi2$Zdyvl)B7J4>0GVx+dG>MI1Z)h;Oy)C6l zcDm8oHW-nV$VPH-*6a+M(~xLHYL@%Czi`XOa68`p)C!|09X+Ec9}*rxhlP`himogw zr}E^X)2+}dqay2&JO*1+rmd5w1I_93Hj%2Z5US|L;)F6uD#xib98*SvSFAwK`4v{} zl4XfW3kLoM5c%Frn6Tzmic3X zA;Wc`Z;EKG16^&CDSoX3O}8`!Vb=tmvXO+@nv4@3HS>?nO&K^8#ZOxsjgr>*W#A;v zF(uS$FUm7$>zw4iSe~a6HoeawP}f*0mOK&a9-nd&Vzf=)tMlQf^A>k=t2N~%h11cf z2#t>PXJLcUhF9*j`csyi++bmOq(A<$E={BVnrS&Qn*tvBuzv@L=Gg~fr#l!&KIPkK zwD}r#t=N$m`J8Xp9=o2eTEDOOb~V_|z|Q#nF!CFF&H7#H+aUsHGt7eT^)8` zVrSCwhi@mf+39r~URjArb06#;`or=K@XyHXjosRIhCXsgWOsC6H-<9v9=HbaXcEH^ z$j|$H!d85v2Aa9YDB$TVM;NPXDlT}5Q3j93Wus>E{}KUE3b#GM9ghAG>M?8#q#$l) z_l7+=wF29y6>y@LTzK^bN5k0K#B?P=wj(CZh(_(1p9Fs$x;1Jq^QzuJ;7VTA^XKrN z;&muqH9;D6cK%enj+EDP%p&+?dG+6bn*r2{;Jt9nm9@VjxIoaZ2rdTO6~X1e;E-SW zORUq_H{d!7`-l7*fOZvdnBdA!i%ygW|1kPgU~pP=j<7u~Iv-56GjG5x5~dZ?^N+s) zr;;mr1J01q8*m~uztK}Z1KnLlT1K5y@%;hDicK=eOVcClnot{&(<`1toOr zwyn@Sbkr5;IreC`$fDIiaTmWSC)&O#muSOsmA!PpUxn+u0XBzWMm?ywymhGC>#xBC zDF1Bs!E|TFPXWsx;qUet zejZD|Vg0bU<)j`DPs)p|IuAc7g`qO)5B~}B^IW~G6wD=%GO1V7!OaEua8mDt7Z-@+ z;)3)iHWsxesn^2IMUhoI!sKoAYs^ocmZPsGOqtX-`A--+)P0Dj@5+aaWv2tEH)%{x z%3-|~Hks5<>2Li}hB*hG`lVt|*!5^KUBc4-myrrR?&inBKUu+V zW@4HJ9KT%{in@pKgVK+U=btBy8NWkjW)WHZg*Fv&OS@-d3Sl%B&k(0fs>IEtf5(Dn z6ed;brVqD?6D5bAI!+hnB!eDydB+UU%( zSFqgLxBMB)#P|F#P52FazjN}K8a;sJIFNzubrd!#&)Z+JC6~6N&T7L59)^0($ zc691L$Jc1N2 zWV}Q0z_SsC3}${h*pP0O2i;-Z3}P?!>s#N+_@4{dN=P*&@1Svz?9zOX4=`36s;}e ziXvJiIl_uu?wTqLv2+^RFHI+RAH`HJ3D5J3bMVTG)4VQbx}@7kOy{K}=ppKfH(i;z z-_OiUf<1F@Wya5gDd7%SJ_fs~UZt^2y-i~q>`T+J%=$&N(mc_oQSM6fxWA^E?$mGc zw))y?j;1+Y`Ih|Lupuq{?fg8+?sn!jzlCp$3vPRf;gDurYqMz_aJhZORoUY;|ALd! zWo#*&`U;aMe3X9a*6J*gy06mSuD|@R+v?w?f6USyl#VmkG%TbKEFEv&gj)g(2C2?R zSldBrYhizoS_k~U_a;hy23_tz#eQ&pjh`K7GH}1{=}v38%C{589MH4bxM=@&D~^lc zNnb-SdZeqRhgH-Nlpc}$ZR?~L+H(mi{n8`TN7yD(t(NV-<`J=J`MYB0%)zumf&(PQ z8NL*i$cud`0z)Z&jCCMIVJk)8|7|HM_REbFCj$R#DPFmv6wTJN)6e5dL&T!7OX&@H z9e|jlm~S`teasj1MX(51Bm(t9#WNn!|JW;)`ObOQS*Ez}Nl&+<yKGBUOePF*Y^B1Er^@7Xtr!uS@4D7UPzBjN5SpQA_2S%ck1^F;7 za0W2@aUyr;mK>@S{w0y030?rs%}k$X2SG^^k!z|LU=>be{&s#)*`S|QI_sZI2mP!_ zdf}j-^~tcG6-hta?54ZoSI*_0znUNWq_3{^ksQ1^*@ugz@dHI!etkWw|0KHf{`98% z_`EdrPU(Z0u0`aUUEPZI#q_h}V1%`3E&hLHb}AypKcJWv|EvA|-q(yw=7-m@imZL8 zBs&%H=~1OMA41ebqi)(mo2Hll9AjH0H2M}lp?o4y}f zPYI^<&2;TxLm3j4+<ir3ivIib!OB2r{377?62dGS_2tdT~Z_4@hL6k?cd-%6}GKk$-c6bo-|Sl78FvUDO4q zba8r#B^w|)e}5t^%X}4~|F+B`pg(~L%2MMjyai<`vZyS5GAlLGQ;O+Qy+T(02W7h! z@f4S>p^M5^baB}l+Lmoz$Ca0n&(crAqsr~!Cs)ByWlILfzuJ?I+GD$UKdsU&==-X3FJxe!o%f3g_^NFvtr<-lx!*89-l}BjTj)B$g zl=h%{8IkmZ(tTj&BCtjBYR5*)g#Cd*>dR0p)q*Qu25rE}ie(ru5X%H%E0!tXKrFL_ z|534+Pmi1H;@TpPZW2j9cVqHrra%qQN6Ky&H~Y$P+4|oqFWr--T*MWa(_qjVLFvA3 zwvC;po6hfC*V$A|`gw<`X1OL)m-(UZjVw22axy{lnP*)i$)>LeY82-7+{!%ydfaNs}^|x+CFUu=>KWd(lZy$(LkfUaVrSX_4J?3G~15DCn zO4p2Kisu@o?PC9NvQfEdCHGrmN`GY)=W#;zp3~1u`gwz&jo#y@`ZL;vehDH={0V7S z{=R24#sZPHfel>o{{1bvlu<`1)9aE*Sf}FOo2j2G^<$QdwB_MlD^l~y%`~sPkpWTW zHhXX8aca6c$-6qgao=!5JuI1j3r;aSz1iNaF}h;Teeg0Y8Yi!gFh53@x_66pn)!1UN;+r?5Q*C}C7k*cO*#ucYiq zM`4uxfWsLi=0%dO3g&!|IRe6Dsz5?dg2>87&oWG5UOcz&Bvkb@gY$1PKwJRcY0t9f zfQy0tXJEo0rv4=eJ}a&umMe&7<0go51Z;!o2rLRh9nn1mk-LGP2HXlu;+e~AiprIu zjyL9Dif!$ zVHBld+Qj3(6guL@llLBh@Q7XjPq6}MhQ-jDYNlbqT{eo$%i7yU{PG;COwG2 zFGIOXIhvO+&PJ>ZtemqD>3oUx9H$t2k)aHLd zoJ%z|wRxkMTicrYYU=FBm}``?AMq%OVY)P)DNdJYlP*({CBuG8ZLLm041q8KNkSta zvU1jA>cD*KIs}VuUl+MnU{QF-F5T0#J0<7SwqgoDx?vEe41S{FdY5FknuQ|so?&fI znwkli!T@_Q+uB4p7_X*fT053gM8i%c{5G*Ls45#@rZ8c59qC9+4;7- z=be+ER%N| zWcg`+kRj(C(rdBnc>+_oCrV7Q&pPYVPmD_bplNY){d3{Ln9=(zcG3)!SN%K-gAu?} zkqVh6zYl{?^anF4z~oiDlXr)1SpM^KAoTDz+C78yr)y&nb2OBSW^@ zRuNMjJ(Z%#&{2RbrrU)49Lp&ola--gV>u;ahVcI=0j7*ckN`#WA9L^@8Nw{4Bt)`k zw35c(d4vq=qe_KR|GpI24ZX;}>b+3r+jYS1Gwh7^wvG74(5)N0K5rRl5To72zbTUiF}5_?0$ayoDE|uI~fUFL`A@en;iUvGBWR>d+kFcfIgV`i|mz zZ3X&OpLc4XV)iFji^EKE z64|xk)MFCi`U#w&P-2N}kib&hNuY^+p4>cYx~aozSTClc8QoF;`oIt9&ICJxSwsG6 z6X~jb0X(7^!K8{ve*{yzWR7k73JJgM>j~>Fm)M%!C6VcB>q{%_3oL3W9zCL|;bD}< zy(mi2MNx|MqqG&SCl=2K@$_6Fo=yLectSzV{*i9?_v>xjv#rhPdZb{$rMAisNo2*P z$FvNM3BO&a#p0=eX^%vim=>udMp%YEH2d4n^uNJf7#%5xnFoxC=syXlFeZ^X#uiZ@ zOK)c7D|)Ado7vc^h3J+!FSA||-F}UhnMSo#JQ}37Kec5=()!mZchI{|+1Aj@NMQTZ zO!lM7e>I6Tm4949b;}IOdR%5J|A7ff!}$sGEOw@%AD%E{zw$Fk_z^a@*TAst<(A>N zgz3VEiQ)K!uZnlVu|Z{UUbnMLZn|EDm3WSLuQ@AHGZ5r{&6R9npy1q>0sibP0_+b&EqVZ zx0qpJ(Y!@;QJfM6w(9t;N{Ns)|l{Y21uIbV6OxaM<8lvhk(R|lD z#SB*c%K9P@-(ato8Q@QF?m5_Tw31OXjZuHELpW=O zsksYc*3JIFwdQDuHE-dY%$Sj3Sve;G{yV^D-#<9qpuFtRQmX4hDz><_<9QKwe3 zdn{W(`}L?Lu9@IZ?IzF>fitQZdQ@dZH!Fp|Q%Rgmt&LtA1vR_*(M?r!d&e>=X+0)7 z=w{LVokF)uKMxV6;x!}6xhq7*GOUUGzmLpltm5iUTwz9MD*Um2Mi>6i;`Xb{!^EZX zU1^~%TcJ=*#{ZE*H5pgjYbxV`f|(LNa^(tEeilM0Qm}t6EqXLn3`^Jzw^_q;T&AbTtG;~qu3da6|q{Jk|+zNndB9?xv_3 zvQrxP=V^;+tYwmLr*+>`77bZvOSy7&C#G>dzt%eGBdzTbvaQdoW&NmUDlR$Eq3)Nx zP|c+&4BfE$Mm?I zQEhglm2Vj~HPhneiq}Q*37&ftixuGDir3V6Y#cx7=I-a9U^O_nNxL2#T=6;>Y_E82 z0tQ#SP8L4N%^${lr89*6D_-XUgDYMafQznp&5)qn{-L6Z%wNurlRkkk^lXeNy5d!2 z@fELzZhpn=YmLzt%a==>x6wN4g>~L90@LxBDJYl ziX#7ODNZDcK#Eg^trX{gi==4cnoopQit}*}q_{}fN^#l0^Jb)&nuZk5_oY}34s@{| z97u66IFMo!IFRCGu$AHrV4#b0g{>492>Vi83=E{W9Q;3)V)=!U6gvuADK>ytA;n=h z2U46MY^6Bm-+435{w!Q;PWlhc{zH`aMO#nxPp^RKhUs zdfSTM9MAk>4_K$MuepVt^*(+T7G0Z2g=dRRhkcGTM-zB+Nb3%}j9630hi#eWS9`5q zFXNVv@YWNp75<71t(jd$%w-MbFC%g%jAl0T7_bG)h}NnlL#g24#7(d)!&|ypw>Bjl z*C|7PYgs29j1)}>r!^1o?+i42$?QmaHel_>EJ$3`c^ZN-DRm9QxgftkVV1~T@;`pqX0z)qiBE1(jOb;#3)f0h)c-7S?YSx zSV`^P!AeVoHD8*gD_OOg<*yXhq<8@y+UbdGZeUdW5vFGEc&__zSe{K%_lf6@`2&3e z5ADPkxxsZ{`yq;fg8qjnMgoH-Ya%#kvZjKACTk8jXtL&mZIiVK7&KYSgl&_hcVcam zRSgW9ta|YOQIoYFc`52XMHY9ThHl<{4kn7A;cpVQP1a=aDw?brI0sGETw&W}E%>+I zSRB~9jpHna0a0fU0_!QoK(mT_F4Ka<1)3Z9-x#^|7ack?1*u8gcQ?kJx|_IH;TC`P zEW2LNhsy3P-;UuAMv^3a4J5p962z9qBsj()CWcY0tqJj&@na->^5c0M+4 zYQ-q{%76A3;C3F1loe{{{Gl`sm=0sz&Yf6uUBvmA4*R>t$BFoO%lhcBm9bJgQuhmA zE;MXiq0C<7ky!bmqz4@+OSY&n9mZz*7LhI9=C0%ejH_{O!Jf6pX# z**^?KWQ*!p7>J>xKsw-D`fHeyBWxfw3S?|%Y!RuH1jnW1T$B=Jb0~rMIZU5qeYH~{ z`-g#uR7!$C3>~FpFPtxpQgVY0WP}14o4KrrR7$26(@`Mwy3WT@O75{-T0|fvK_DWP zk{}R6n?Shjkb*rn*>7YtGy|S&8(Le}Z=yXWpF7AWw74N2)S~ zqk5UfHg09VyItob3{$7dJNREFys=w(<2|mk7}HqeRz7e)y);HV>p#E|6pVPr|I2l5 z#K`_V{;SyFYTVqd+LZsJ9s(D*MDdD;Bc^x3Yd_+99`&^AT#RYl)2&Q$&r*Mk0vg5t z)v`att-KWcmh4Y;D~CMGt|tbb7D&Yzi+U}oqSw#xqi07f8n4J#RWn6oJi~19PfZa8 zugHI=8RB%{8Tn6vb%H14KV}9uQm{+@Eo>(Xo>;Cmj9G#sob*Rqny}6HmKsmY#0XrE z%7NFVD!#E(K+%n=QT|i;$#aoZ3(q4lOygB2y87lHoqynb%K8O z1`F;VF41VbMizO}lB1r*n8q7Ii5k+E=mb9)Npz~9FVVSzzC;%Z`Vw_!0R1Sd1y2m4 z%qsj5PF_;2H%>W8bTANUmP?vV#u`5VsnDTAJ;v+JLY3<;jD)-3MGh*y?p)vu zd8sYUod}*Q{C;Wf^+B9D6@I$3>}l{~uvwYoP4ytO3Wau`5#4f}8}C;XPG!>~*SQWO z{r`ync5i?Ox@N$}60&n6MYOl$E`7uS-h= z{kl|sx#3moR3{kKCAAYlT^eYdOkElY4C>NEW9`c*_|1LTm$fE2WZld)R$`jp=(Ww_ z`A%bgg{{k?F}?VU#`K1a#`Ge?F}+hc{vA31jLLio|LeYM%DnQW_gtr9v2Qx7 zF8oHlT#7D?5pPR3vye??J&gIC#&z8EW5x84^b0m08_Ky$`Yfv#7gF+#JEe2$`kqDB zEzK;kevNBuH~n@oJtY084Qr4*cgasCtT__bPWex8nGdvDvq-j8zSb-g_O&L(mXy_+ zj)E)Kn)D39)zcc&IJDwB8>>j^Zbbut$21;|`D@@FsL&eo4!LOp+Eh%D?HYb6<_P<# zSRm-@?qb0x6<0&5?p1zLjF}-)Cv;S~0kYTw{@O$^T_OKgPfNow4`l61AH#XuJc{xS8vE z0#&W=a?Ra3>>s&Rm)~cJ0T4$q0KAK(b{6v8s{2TjA?hGHF15rEh{89P819maTM4f6 zL4I0m2)c=DZf~mmlrgBWsCO%C9%KlpaVR+bxa%Cma8mfzuUzwzhVV^frdpW;Urz>f z@E6QIA9ysLH*qT~@n}4Q2O%ZB;X#a*kCQs%8T<%|GoCl$gyU29+RSrCrFJICFp?O9 zBs9*gI)fjR#aeQ;(W91F&m~t&aH?F!Pd^68jSX()))d>ND!K+-HPEfRg&*Vl1h?{L zM!4T=lzXVnzr#qR)dpoPpsAQ{!)H8vDORvu?`k|*~Ho; z=*K$QXHcxO1XmVo#aLT$=^mWMSNN&Syvm>)(}=El8WdJe;m3&PcWg8UsXBrmV^cz@ ze)Xm$QV^%VWruUIhe*FZso>wb7x_M_kZ7Y9>IVePko!w@v2E6 z6Hyhxm3&}{RuG*&w8R>OUG+RYq~WW?sr|>6SPSC8fLI&icp3o1wvG~{=Ai1Uz{4H?xi1!9=~B#yU5>c`?07dLKIr8X@N{`Nwdb zeMC$U{$)H@3wB8lv`wd0L)e77*s6*tHIka%*}9MN z-P<&Y14qTc$3ZyQ0v9WU`0RYVzgV{JoCNWjJC=3 z48YLTrL|Qa($RK#4>?EM2 zgQu9p7r^Pnd%*HBrmTWf7z==HN}D zwa-TA3uU)uWOp6(o3gux0&=|PHs$9P{e%~UeRvti#_R=QFZ71VM4M6^t{1$=?Y{=D zd;TkXzYsI6=;+PuDlwrsN5AiX1z>dV^!4<T+=BxFMmFen7_sJ|SBDnw}qhR%DB)}yQ83nCJv=XS`^%(j93E4j0 z{qG~KNB9xga$UEw{o$^&J!Z?EbU!7Z*+pQ@WPaJ6J;ojQz)Y`-vw!yeE4+Ta%}2gW z*xhm7e1n+N?*uid#%dT=ljUoMDV|QUmu^hKPHW)(uIN0TSYF2TyWQV6Q>aUDHg?yf zJ9hFDtkUjxO~qM<@y}z(+pQ)@(RbL^_q$Dx5$ z+W+WV`PxL3bHi7z#MrOQ?sAB@0S~G^{aQu40*4K@QC;MkfK4W_Gnts-W_7Yxk4g3n z8<-L_YKTqHWxhw*JrUUb;AY2ISyy1+??>xVmAGann~LAu+D-rDQVmJ7McnlSsy?J{ zY8=sTDV?iH(HHosA8J$iRV*{EvoBYZy`{0t=fA_iW9Sy~^sp@=_x@e8y;v;Lqb03u zCuJ{pV=vaR+L$cjJc)}n7R zux##97Nme(&2jp&k8oKGiC?0qJ=1f25w^6)5j$c#gIpN7E{kRQtskYbAM}sE!@y&5 z(K4PMU7U-$%ygRzZ9-*xmS!(Lz;GLtEWcZ}M0zuC!rxg!8d}>()f4|tq{i}xSms_E zX&(E2(6K+{j{z_SPwBOfGNhsV_sj%okn`5J$5ty5PVMm}EGuLBt!Y!C-fy4AxNrGm zEVD%yKkFKy_k-?eV>R@e@i0|dG}!v3SePo&{d;DER2k>n{h(^wlya^f)2|(hBv7@G zAEQXW1&Z_?{+}luhVR!{=1!Xq)vX}Jph zw^;58LTlYFQlvUC_C}EggRLS>09r+wVxUo^Ilv-Cnh%Lz;*~m>QDyI)ZFP&qbM=3) zBr6s#p1-Jp!3Vg1Z6+u^2`2kfDl9%LsId5waxc;$)r>%g{9$Q-Y*fv1s#~dbh^a+9 zuXpeF8JA-EZ_f7_EeV6 z(U^|kT6zAgn(2(f92;28cAd^gf60y8n0{ZgEye#!!e98iK5qP?(J4^{(%s|V|a?bU;W!T%3kJ?N{3@~&$Z z%>|21q|oMaGSKF72GHhmuAqOx;sRih%f-Srm&?Kb&*ZYAJ0+xtR+OCiTjZ*TrF4lK zVfr=rU8n4NK{v^6T-0?=p>u2ZHGbEPWv~4iCLYsu)^O}ugxZbUV0shN&wi~zqm&P! z_v?zsr~R|~3y2{_(_M$@w>Xx2gPK^U4*vaE{z>p)aR1i%3xG|)`j`9*Ed}j`mcT&X zbA^KoEy1fLZ>QoK+xORyJ|egca@~?u^+Z^C)Es30 zOlBvKHl(39>5<^=Dw-=j3Nq`IWES@=q9?fNSBmJ>Ih>OHbf^i>yb_&_mE`)6nvP0M zswCHg$Oa2%OTv_?OUxcw5~fVFQkLrr^F%REEXn;$DrN}3=H|Wx&jaUvbTdhN2)Y%X zax-I@Lu@as0?gg%W=9v%ElSf)=AQAm@EC@9Zsyz~y5;Wi?4IL%cQwH+8GthIE}7(8 zsn^V19?SfCR74Nh)=i&f3T^p+yUPR|_b~2|}+9c|_ zSa@PqG-o}_?xPMYQjRZIfFp>;J*qwZ*UFqe z$WVsV`SN3mXuA*C`SsUg&Tp80FT0iQ>oKQ*>Gy(Lxf#QxQ5f29$D3N_U+iX*KJoUr zb3JC4TimL{D&x*Im|f1&3f8bLnmQ7gzaqRJNTZ1{y;y0>Wc>Tx$82V2Y3q{IC%@)o z4qRiZ^IHyQXYDJPH_ERKTnw~Fw3Y*dBUePbpgtNN( zq9a;nB(Py3yS=T3h7OKs5u4pVFJim)J)!7<3A zoQAEbTW&XC9k5Fwp1XSk_K1Z0#luS{vm~NRZ!h~8ZhE9LT{dTon!T=rvG8pQT#Ghq z6W>CuVpF$@X+@+KW^+F>qa8``%w}_+GdY|nT;=B80Z#=pNi4g7N#Yz~J3-8MA_w!a zXsXM%0WOoDKXa92rh1v5naSi}Fu18Mb0|=chR|FHnhh=lHT3!1yS+idxcg~7f;7*w zlTu}?se5=4r^up2^1lgKQ?frgkY%TgJIMgk> zWIgl~T*Xb%Jn6e_X=~Dg zaGZXn>Tj@&jpJSOOQ};6VHvYqzAw5r71*>%z6Wp)5aIs`!+b&Nl+%r~D==Vn>qDv`P88+aW;%n`{0i|Nm&d-z1Qput^XO zngnpzBnTI+85Mec$?L~tu$Sh6C9b(&vc&1doY_fug{l)-YNQ!2=(Y)tPH=AkU$oi; z&|3%CHt)a>T}ZFC{FQipYWPc)#Ev1T&2UL*X~>CB;73-DS4bX>Pi9($_NP*^^zVg% zY1fGh%qAhH;GtIxolJPWPQxMDJYKp0LglxR99I+J zdpjsDN)nUXm6%Q9E`o~pVM4h-;kAa)fNW22o!GdHEl8vZ_rh4V&jC2_AYCVSVJvf` zO-Gez25iB2Oqt9TjmJbY9xKy$Y_PCD77IpFCYwbgsUVyGVI)OBRUhxdsTF#R>{PB* zx)1QXh&FMzs+6{8TTFHUF7G|&IL~3S2eMZ-Yyr#Pm~36bt-9?gJ_(P>eu$rGdDnRt zlU)kiGQei#5Ie@)s_g+6i#QeHeL!^u#2@%Ms=ezxh{@iE%hQ0&x)3K2>5l9&Pse1B zB%a3r$$E$u5J$17^#CUOs>|YepAMmFJ&!<}tJY70tZF^FFy_Qw#LqU`?gQ*ALaBcL z<(Sjq6&spaPOZ8UK_|wOtFw}B)uJO-p|WlW{UVxvqs8IH-s=*FsTV7d}aI zC)tlIajSko?xUZExQJ9P`<#nYzkv7&0ga<8{TP$IS}ru)hWHU;%O5#OiOH4`fM#l1 zt;ybx%Lu^Y10mKbb*m=F*>lHaH-h+q<+4Lk5d9$LRCA(m1Z=kvPg};D%NS;6Pa=Tl z2h+Jcg3DnL=U?oy2w`0|;;6vY7!%LSw=wKxVayQY0dI*=qz~K~bJo2J;vk5_Uu9^D zQRbYg9mv^H%H2l^H*wAnVS!)5^rv}&kEI_rZOJWg?TaxwyUtHsIg81TC)9gzZgY!>^Be$tl?GOb{IZ3|iC@(fXuL$`|WDh@KWktPF3Qbm~#Y1Tu!3@_hDY<`9`EcTGcBd4FJWom=?=O7bKo&!O!-wqeN_Kl#ht$~F{i zUgkC?pO*$q`?!@G2233D7=pGQhsi(VR_?GPuc}~#ubjfFH%9nf{xhfhc*`>#=Rl0? zH@t%TQ8B{r^PijL_fd$=~l*zVjLXO7wKM zay_)D5hMQhP@=MXecb&kPS|2(|JfgW&iGFsH>KHZ#bEDvBQjLW(fm+{HPX48fr{r; zl|MxrgQ@L7PuB1PA4bR2Zb*02mijpqQ~MLe_%u7InLZF7Q{PS+-eeA6P9#lE?Jgx@FJ3 z=uFm+#neuM*p-VTTQ%VFAbm~Z5wgtPXbXwoC5hES~8E8VB);1Ew+;^G{UoM?m$}9O%MSt{KZdieEh`Ol6x`#zQal z(C&&(FSjE<(dCb%zqDjtH^V=XQ`N{|>z)-$A`tG;GQ^QfXER#r!2 zTa(7C8B*LifUX`>sk3>BU&|Q~ddb;@*NUKNkDm#km;4dIOSE1plrSIbUNbC+ccX&1 z$1e!Y1WZ8;p+CI<6Bfi&(z%R6=-J*ch@WlFa>@t=F##dzp&>N|v2PJgK@2M`mCR0H^PkM!TQ}F1 zq}A4cP+Kk<iJ@9$M@7x>zuIjFRyt@5MN zS%`A9TGv;QZZDpe8`hLgBuB!XB~DfgalN?Cu>OUKhIq*b+h z)AeF1AD}yLIg`E}V~D5FruAoAV$LnJ1h-mZ;)}dbi>dq_UE6dkX2Y1u*CE#5mW4Qs zaY^mT8C;BUIdnf>PsJFQ?h|=U4r5%7J>GRbz!;bBc_*v!48AI_(2fDTFGBIOIE(L6 zV@%ra{)iFG$3B~r_-x-$T^CZ)cGk0nne~(e`K`*2=9+p;sIGe6mro5t2T*K&S8OQRf;B7nv=-K znHPou$Ndq#+Q~tFz}r0)1iZ&I&J{PTLg&TW&`=Wjc>JO;;B}&aNBRLD#)$SeNiuQa zbe6GJm141y;>btcrD4FmqJU5I1Kx!5`+mUbOPKzzDqyh^aOlJF`qhx2Mt)LWn=A$V z2g`+?)8-h`S)$RlSJIA4A^hOCh0SqS&StCcl}8fqg9g1ici!+`EKs;jCImVxCY{VX(W9(!7Y=qs$ zTV&c=FCsTc#?uv+F38KX>2s-edVI3^5R;m<>LKPzt6utBJIJJUB!;j%5$O+QGk+9u zbi67Wh6XIA%U401SX2;4QV_$)XiyLnz_uW?)?o``mf+tgh<^0gdTc=qD-yg4V!I+* z1<`Ybg6L#vVh;;qbn}83v_e5_)x02PHZO>6i#tr@+@I965=m1ol4JgYWmyjzu8i?wh} z$7firI&y8-nTL_X7ye1Zb!2zk5SZH-w|_KvSi!w1_Isk%b0T_ zMjkH6agopaXbX5qKJHwE>39=sF%{gTOA@iCtJKHF*3vrVhka?W-L;?M&sqCT5sufF z9S-vmvP8wkW_ffV7N_i@c0aizV^F(sbl94#q~cOCs23A$K-D>$#GG$1dys9vy{~+? zN6gu~CsyaURdu}9^B8823YJ*`^Eo%pHg(aa(t@;3j;RpQ;J~{S7-|^@JiScmL{}bz1g27%D5n&+KZFb05=Qli{-D?z90<`a?%K z{((!$fx}|X$rNT)drr#qWXo@OUsl3?**E5VIvV0uHWw1#_cmo4iq0|N50Zeqq)PlN zB`9UWzuOOgIKh5~x4)*bWONYYjbma?XQVTHZ&uho1B`2exCEl>Si;;3;!}u=kB&Lj z$3Wc8!iTpvc}OG(*>N{;5}5!zq{+Q(4%g69VC|s-<`S-7Oqv**kZI#~@kAduiBk5R zth|Skij{C$FLnfh@r`isQB#f3>p`XNT!)A};ao>=g7hK;Z=Ctb?bB1*zsLcWQia1lg9dqttbD9Wq z4&oe?!k(#^gX1wK#f52f5#w28H!QbBEDr!Ji*|k<3Rqr=Sl)|R>S|r*6IgnyYuwVD z>+nO2qlGrowdmXZ5PNAsyu>q6c8D0d0d15D<}8>D%hnOg)x(2?_Z88zBgcdBUxTBG_MyoCQxS_gk3Ip*`w`2R5z7z2-C;@W z%nut}{rNirSrv~0JU;<#Xu#s@@niFSG6@(LguVs#R(9J)EJJ~p!cxd??mA}xOio5) z8=nwyeaWok=D_hpIi4LkK65^Ali=9vd45V#Cbu`?Y$LlTcO(xj(z>2G@KcQdfo{Ew@KZ#k;_uFuE@{7A{S|m?@}mXb7N^s+uzU zPZ{nm%v0Xq@$>J>yJQI(@SEyfVJaSfXaAva);2Nceiow(4*|Yg2QZrP-1f{WP0F?y z8Olv3pNdkpTjZj1Ohqn-MlSD73S5k&PQxXBK0iM9n*G-$Ev|98N=`Sg)agMvEm*13 zA~}7yqLWGa&)C`$pSD-Ca%ed!bh)m%OV`MytS(5o32p1hW#i^9qav5#&0UU;T(lWi zB%uo<7gf|Ems=y3i>QZ1E>A@+uK<0Qge1t2Zzgj56kGOC3fih(h;^Z&Ps|zF0iYuQ z`>?!I$n4G0QkJ;4>Zg?;zl7UkXXVrd_}6f^z*ga2!{$$VJ?m@N$k*O0^>w)QwJsCj z(*j>-N4{pP)YpyH*N4QF?MS5G&SUYG<%YtV+cS+}x?AW)@6<~`F9Nq)-=^o&DCBR$ zkPE*8&+4Z9#`Yn}UuU}@ew7F0O>;7GLZ8nW&7SGHpa z?GM;`ooqr&e78Z!ecE5SpJBP{H8={N0cI0$;VPI8z^4DBG$Q?`LiM|yAE!`4cQ#b4 z^7AdMMi*bk&6e2f&0CAFB9}j3YoJ7R)pwQm^2Q*Sh5j8xMwZV@p`-oADim)#2Ed*;?T(DIH2#Ra6otV^_jUE&(kB8DK!`=EDuL4&qgeh>E8PXEFVQIUq>v{PzTTkR~z*iD8oM%Ry z(<4sZM}07yhUJ!s<=%+p5#ar>6y7M0IadU{Z$`WyN4%<~ivpJ4BbF31d7E90ncogr zs=6R{i|vCN@>`UEVeM=aAKmOFpqcuK%> zQ^ayl#PTF8(*l+kB9=EJmNwLqdtfOH8A~g=nN8HM5pR;^3!8h5g43H@mUh_N+;@st zbfb6`EWP^hQ{s4+ZNazQUT)wcJFNW7q^ms*UeBpK?w6QzD`x!qZsoSW#+;)t<2QFJ zf8$?=!NzaJ6;i*&oOdweInvoYpxK1#-(8-(HGp379^lLS6MU-S7vN`t$tdXJWnW%UC~wP2mp? z1PyzYfUB^!6V}4NHg%oDKEbuuBz7%Z^Qm6RAh8)h2Z%1&4xkj>Z~$QIcO0kP!GMnl z;h0lgXTW`Z@LIP%uM?b%^{-f0o{IJM*c8^FI$m%t)>;5v?^+8s0wg-UZEpCLZkx|+ z`n~Di3?~>|7H~9crYR@!;fK7A<5vRX>NA?}aQckKwvtcBe-biU*KU-U^%I5&<1QV{ z`ii1HVgS8|AEJRNr=T^~#D)}DKNhrJVqvqlR*n5qD06yi!PqAiNY-!Qdg{Sp$VIL}$a5x! zu0Zus1b0o!nCS%=wx zjx5pjd@|+?DBBigxgL#a_XO5kVEv)2AD0g80QJ}+sIg*N12w+;b(r?Wdi)z$cb8%> zV~GChhgjFs`Th2>1xI}j7_>i4=}&;yFLIr?IlJf_Ou>83Q(8=Nb6Iw$ovrz8$HKxW z{`Cx`kYndVz~i6S`w>FMt%+UEpLZKS%S87@m&GKHa*=U+CbyCukE~tNgq(n+ju(%}?#**?TyEp7#{+580*?>*qaZ-F1NF zZekL+Qh2JHI3d8(+{EeNjO=H)iL(Mc(@jhbcxJhYO9Fh2o0tP`ui)pniDiNPJU8(x zxWB@Az)d7cpowd~n^gLhizC9phdachh44cZj$>?v|!1J!c@sz1&SV@_(uDY`AU#EE6#V z;?Olb=XQ*HCB(XGdd_H!yQb%sz5u9POMcw+Bm8@7gZZXhdaX8|vn$5sV#oAO?L6l^ zjQa>KGXWopcopJDz~<{fR1nx;z*!=0aMKs^|C;b~aD50UR6|sGZn`^Qf{0sVZu*4w z9&gYuw_VqB&cwL4yXjFio^vh6?STKg06&QM1TWWh@SM*u?mZCQ3!ZZr#_dGN zCjb_R*wAy0xG%|46%h4a68GDg^{MtF(Pa0_vR5dx$%1?_iC>|?r1bDU)|58*rR{d@{8-_~)e<+d!}2B=51z&$mYyOLn^82WNF zBSkM^9_Fl$`?X0{z5M=ek~K`wCTk)%NY)Hto2+?Yo2)V=Ymxjo?qAZC>tqv?R#Zth zOq_D$mbhW!3{B$lTUie|F>r_S;Nk$LCc^+sZZ2L)?wqn4Nzig7sMIZ+2QFV5{A9dL z;;$2aJ#I2OP}pX4Bsj?EL}8oJsbHJY+~fGy(*onZ8P9!TX_L3N_)easjaXl!rOE|@ zHi>oJRAsgN+oJd_HH!+Z$FxbmrlwgkgO&SB*?9yvM@cMq%f^A{3vU!JTS|E@623ZK z_C9zSSV^A-PPOrqej2zM93(wvrI=FC8^^OhL)YW(ZW7NmbL$l^lPV3C+t%^s(q5S^ zg#}!pkhhJ8=Q@nLecY5`lM-ahaI&y1!x_T14CjJ_GF%`W)FE&n zi2vg<%=fgSGiA7AJk(f2&rUkIpitE{xf{lFL8%&9*TtPwOPe1flJ`@AnwS7S$oIFd zj7S`}jhi~gYJs7zaLRNE=5pn-otqzGc^OeUZeu)GQVrlSQQyo<719$u#`DhcymTd` zua4)XF9D6H^3s`*zPL0ey$NV5vaIehs%uLEc8heyguiDz7pSaJ`6J>+PX~&3lCP&D zg{_`W1P6LLRhZ&Yd~?7-@idd=Q7g!DVidora+BjZ>9L+FjC+c&yYm(2`TxhdJ8cEs zz3}hoZrQsOz#=7JdOY`%Eev(W?(@DLFPGa3ep^(|X_G*YI|^GpZU6^*JWSZ?@dR)n zsK2krrl@8_dTeO)*lAwbw~E?kqo}maVO=-U=f2QpRb$`^9tbk8rbN%W7`JEC`kOe5 zniE5-Yigc`t}6st+&@$*$hyDNKZMyZUCf3nWTSqCILSuYJ8tI{K z?si*U*>iE+UEKVXY5f6I=_k5%fI5N^HRBKi_D5o7VHdC~8xo-$3M} zEQ2Y7L)`3v&oJYaHLVb?G7Uy1%I(5rE*OXyflO7r?;^aZa%~&cb(2C{*XPL1*7f4{D$G%h`|Wun^>q$MvIq4>SX9U$a_5{R8Jb+)7-E= z8OQmt+>ymnd?gkRFpT@Fv9kX79W1}E#lkky=wWBCjAJ!Ulib$#vKr)07T(kg$5tl6 z8#7>PUed2eSqK$27)i3T>9{Y&!jXvSyH;x?nU`+pX^(N=jIF32;b6x!Mi(Z-C`?XQ zD+(tsEz)xu#(gW2h)Jf^q#2Te)ug$?R+AP8TTNOF4m4@Gu4p zhKC}CpctI|a+^Umu^e}doBvlefX6hyb7QG3stsxGhe*C_>vKm^?KVX{h6!#Z%~GTX zCPn8*O{k&&(raC~LUTWT1rO>7o%CBw;@a0TXS5>wGt)&A{*BC=DjWfBiLv(1Qu! z*~o**_A`-(KyAWYc2O?hU%|sF1-v9F@ac?q7P3=1s}lD+K?>O48G;gI*Ld z1Tu8WuBv8|sQ7MS9Ra)uoEQ+#Z4cHXPQULBrhKLf-t6XkSn(Tey4elag^Vy>^p}mC z?L38-J8=HI~BC5Xigjkb=3`fftqHWo^_K)T#PQQvLcS1I9Y z`53%Hlv_nfQj6nm5xE;$NeZf*X=7lw z&>Cn3<0up5-VuYLX@0^c#1zg(F>}?u!!oV26v5YZMfl^QgqXHsd=!eI)#}}7OUG2w z16C0JL4GH^Ov*AT>T-%3lhnGn*~X+=c%_X=&_UKn;KxQCq?zhYONJe!Y4TP!h|15i z=``{=BFc!NuOcHst7yb=VpL>?VVa+jdL?lB$}=*oC?ga8ZAOB@g6YXGiUtd--;;-f z1tW{gBU#wNWGD-xOGSf))gO;Ut79ga=lz{zno;W%$$^)(f*ES@SYwvl>{w%-upMhG z6t-iHCE#GJ;c)sc7;Cf!|LsvL-EK#^-A*WYTP@Q94inMdbEQ7cHq_!isQ)Rd0-wag z#gNUVd!PPwF(h~X8uG@6RWa^Y@vPdTI#THV6gP_+1BHKx=dQ4Prl6L_!$lOMaZ92_ z6hjv+qKHNc;UbEmixyEtTWL7y@5oAz&ZN9xv$G@FnL$?GQ+67>T#}ic9+Qf#yj)95 z8$IvmnWdGHO7Y&FSpu9WY?oH1f>j<`&Y2@@msaM3Z3?mnwx&mrpD~`3-inl*q|`i% zq|XIBBVr-MD}ZWk7$g$@2Vzg;NPb7dQJRBPV&yTf~zi z4<=*9O_f;%IK>MaX~QtZGvl6RO8GP|)YxWCRR`RHrb>8~O;s&2b}#b64tT|;>c1Jw zH*3tMu8`H@#>}YXWnS1tnylXLXSH5gxO3%M9bA;vrhl8&W{ufh-rty(G;hovh@|xo zHfFis&`3RIDdjq^tdxQ9WMyiO7p?$oh`al`x6&1W8RFFnK(-Y==ZgB;TcM4-_3z|9 z)G{-Y`K#O|l~(x-+lZUvsPdAsz($B;q)Ta{7X8Fz)pb zI{{7?aUjH0!1E%mOd^9FNPo5GZOq>z)GB1K8BjOWd*xmOu$y3OZ)>30wQZAbK^AsV zer_eS6KIzuANK)>`yeDYcfNvNf)~Vl6Mtrll}%Qlk+f%Iy0d~#c^?Epm!(G|3~lGS ziwNxr_7!8=PFw&{2Iwc^6@o5(mi^N|wTHT^Tl%0jMkxt*U$=A+|0f9#cT3Oa|6$>g zD9a>DKCL(zshYKdpY_hyH;+XlXpq-s-l747h*)`P9(gXFKotCVU~ zt<8_q*J&lmEyup)JH~O1HONA$q*9{ud8(aOPtbers{BW`+=;LwEO%nt@-}`-+*aD7 zei#^Aj*`WG*AH8>PCCucP)zIwWHAXaU&QnhH@#bx=Ujy`F3$m4wz4h-6!1WdahZYa z{=~$Z(sZ1$kL2Bi{5fck7DPUy)J>la_&`Jx6Zc*ObQ8w7d;r)4Ny`QQf3P*}`;QUj zc9{6rDL4HL@@`2bhK*X)hv*UTK{&C+L>Bv4KT1sL z7oa22u;e?$$aC1v(t!i$Nj!H?6rhbWo!?nI^EE>L^-S(dC~raZfUrm28iBInkk1GF zd7tX%3;le~sV5m%G8H%fc1D@%VF zIQFK`av1bvoNw&~%RA}INOE;8sd?9T)_Dx?8qb-6iM^WH%7(B3*0I;h7HGuGBeHCr z(z0}CL;5ruqL*+gMUUJ)uEbsg_j*G2MwjG{Byod<$CTvu2RDI}^)6;Qcd~NNqmEGw9cGqXz<>RFcgyxLu&mc~Xhfx{P&Y`H5|oat*hJhWo;O69$g_mT>D) zksBY=2*w1pk@ayrE_cHHoA0CSY^y%Qd>>_#Ev>16H#8Nhlk~(phpnbVZ4}%33}yQ( zUpzfAF)lqFOx#OIaLM&<+2cwdk31)9GI?D^tjEyy(o;u^i~faXvpi={3<)=OmDnE% z{jhK6t+~DDw7zyQ3_~!-s+IJ{QM`#M^+xcAfhUq0xX#Dsc}$79h4NV6U6SkWtIfWM z`zXdv9F;u)$NRB$Nn2u@|Bt=*0FR@(-iK#av$L~Bt5vgCE_iK&Ei7Y;F1i5Qh%TBj zU6^LNXhwu4x~LJDV!Egn-AO3IV2}ZW00RnDlz<2%F`)?pK@gJs-}lVDvv*|)%Z51l zzUMd3b9di!=azHNJ@?!?Ga%M;vZ{plRU%Q*H7BcUm7-N6V#vx9T@#pcQ?NQAB!g3< zOAu`)O7CRc;YjmFW?OEB7s1Px*0K+zWgj0~S*0#RwOojXT1&)9-BW zSd?n$R1xL~uoXTIKQO3d@$WD-Xw16;t|!?O>>>>?PttO-tk z1qo~l#=OlPJH77aiaE^h9uSGMofE7hnmAbl6VUAE1Jf=)D*O+o{;UVz5@8_rvjT4$PL9R}wuu~Qq=IM$JH#Pjk0Cx!F3#Z!iG@K3+9 z8>GBDFrKSTj{ulX0xw2RA3g_T8#wQike%A-YV`bYjI!l*$O4X0QtRF5Sck*m25OuF z-NF|r4H@4U0;S}iFU6C5De~UU{yqN5JfQP+{hzQCC>r$ zkhl{g6X$BA9$tbU*xl>!Cq0Gb-U;{wChInI^c56d%&YSzkQf%OI1ar9McW0Vlq-E> z!%p!f?e{cnZE9Z}&qIvp6;RDqO<=5_PVetn_rpaSaHr=m6>JfRi)Ja}IRsn%a24zh z+<6?t0Wg)(hwzdKE4|&`j&&Mb^zZl-BW-{BHc-X;z-MC=G7TWa4Imco2bE!V7kYO3 zq&ggJgo{pz+380Q#E5YwhyxL94wddE5IaLK>C2G9<4o>TXl@6tj65qIoH&VftVU$n~gOwd6Fo_*#!h+QI^C>@d&xx?YeHCWv zIlXW8UV7n0C>hMgYFoh0g|FOLvYN9@RuB7$k93*VbA57(=(Z6ya-t_{C%9*YFFsZh z?^!1C;<%K50UHd+E7Idnw#%7or}+^;yCSd$UnOr}!|WtHg(C zPN82vmzp`>Waf-_Yq4+33Q&!t{lQiCUb+;??*+Hooyd8wGti;I2@$)%v37zZVTGGd z=7hBPi!2+Zcv=L~EW`pXYSAzK7@zPB+V*e$}10JxTJ)|c}AKXjNN7~=PtrlZW z>orJ$XCSFueL2<4iI2u3TR$h1cEg-XRHdaSatiLH_d?pY!mTzN>K`7{C}n!e$jL7g zAD|D)^mj8SlTsLE0C?`DI!Hgi4%16+SXJ~yX2HGmj!6DW zIKNnL0HIiU7*ggIYaD!nVr}RXL9w>&uUPa%PQktOk4Ss!g{oM-nSbclFsF~>r?MIT z=X1In-VzWjoWBeUcbP0K=)*$L9ZHi|+CopT5Zp`egtV_@9zvK$cBj$iO9>jG3pOC=!HXwv^rEyA)`HE`LX5;PAzTdt z&c(t~I)TIvfWyZN?DU%$V2|7p#4wBn$^mXA!PM>p7{3#UnIQf$-LW>=6U4EI^DV$x zGeA6peC7ZQ*$c$WATj_#j6tTYAVy+LEG^;RXL2|-P1vg0GLT)B-m*Kkksbj z&Kh-&brhVi^C-Yp2ZFd79JFAF{}(v9bIGLusAXZa=qAUiK+)Y;9Jc!38_FPn6Pd%M z_jKFgBhZm~%whfnC4+kP&DabK@i1&)41aVkF$DTC8vGb~0G>V&5gvzgKSL>pAL3Xi zz_~wS%`ZHmHb|>Go4Y_itqc9MbdR219}$}2n3feTM!6I#yNZz!Rs{Oduk)kpfp>Z& zA~aAKjEyH?T}P4R{VK`iDgr?w{xsR;R>-NnLZPm^f6o^mLw7MaQLT> z#?RFZfK^B#rU}$u5@cm{n9lD;Q=1F(uH9B z_W;`+4C0-L?QkHS-sw4u23(TUi7fGfQgI@~ndvHk&9IvG>diKjW%U2qcY z8-No}SHbQB$ef{qU41Tucb*EiKfwDWnA({bS$z#BsimOvr^A&dAgJuTChhEuB?P!3 zF^X)Re>V`Jt){i>ryGuEpWqR%{aSUmTrfF#dm`lS(rex1DHvo z65?-xL0Sq|aw-f(^Kp*#7F-F|%8_s_{GI9eN$rcD%i)Hf4fX=c}?*6Kg}IZ=T{<@4(@q9y>kzct{K` zaT4wwP6muSSD+c5q37%qWNL5yZrA7dSD+q)g>e7M90q2wFLIfc(4C8mXvYfrGO za^idK&j1cz9orE7Og-TN@z5lu=Pzf6kBEMSK$=Y6BrwSZ>LwaGRYNV$g*+SN<&mb|SAro-4N!!xY!(%dPMoq3AS&PTprFa!NHX)K9U3mF;mz z0xR3hn+09U!fopp)Wfr1x}fF2C}@%ets$NnNwSc2#Q3%s3)ldR!WB$MI=q-@_^MD) z*izDiENnB<`o#*H;64E_j!0101osMfk;Z;Og8K!$gkCL{;GRK1zYs0pzJaFI-a#Nh zj(rRPwu14*j=lgpiIt}G0&4+gHp&XHhFA%(9@rFMK9XKp0nSBQeFR9IGPQ;D;I!pG zDnPC%83LRS#uGdH0_-AI0<<>H3b345XvG6OQL{fDMtch@ED7vvhCvSr%FHx9l0N#eO6x{=bc`h$GV*<8J zSwkIp$8q$n0Q^eh<>_)8w!+WSKUL^x$lk zU$k=(el-+pKNjutyyPJ$nzt#6_C;RuLKGnb>}={6tr|Fd+475~d*7eIn`}VNL_0ke ze6^6b^_~2KpqzE&Z38E9Jox0b4P0VFCr8}QpYwv9YqTZH`D`uI6|X-v|@6u0_~8AlnZp-@w|vjPYgMUog2&J`;6Z}qqU6=x-eh6ACJW>FFw8A4?WdefFE()tDUCRq&Y zlSSWpOCUhsdXw`H-e%B}5n(HR(zRIRf=g6mVv&CX*7M*J-*b*5J0r!LV2%x!z}Lsp z>u=^*bKnyA`dIo;80b&uXd7pl(!T{5dx9dq#jyKWOgIwv;LhQgb-V*7!45dvvEGK0 zJFj61G6j<_-WiMHi78%qFV-3``cGWpiXUy_YWFF>Yh9^;qv6*GKTaJIEpGBUBXkP5=K$w#jCjB!&auaEkUy9BE*ay`XAm{U?*LZ4SU2Gyda<}Z zbHZ##+#MV_5iZsa2SYujdZW+|##tPShSWTOR(9C?Fnw(psn#)( zIiUg_m^a;%BL%0a$Z^tGddX2XM(BIIMW!S8DrzN_Jqsz2JDNpiD6s#FBSU=RgR^oTFlA>sNasyYo`x<|PGJy~AN#*l^ z>$a$P?)D|(k^H;BZ95W3BqE8k*I*oFYd~woj=?YSM4yvJlELZ>P65A;B&BUk^rQ{Z zZ@mXp8(KH(*9^Ze;SyVV!VdeCuR$L_AAXN|iFL7L%8Oc&Sl|`>sMLdhWjs+Nv91Gk zGGa)qm%QYVF*xqULcHuHuZ47ah_`f;mjHX!kWN!5c{MuDa^l)h?o{-!Wv8Nglp-_T z>Df_Jmu7UW&SEj9p%8vbW{_ri0L5zhUt)&W0(%1 zWtt70U`@>foYk{W@EGg9_=Jq?R!(xFtQ5Q|@$2+(<=1d$IP3*45 z+BC?~+E6g~v_ZSCv1}r+3jiK@Pzh`&Tm1Hd-;jrt-(jfaXRgGGm*ckK&tIZ)p8(tw z7T8G$Gi)!PVF4_VjH=747>;?lPiLOt5O#K~(9PkM_GoYQypH z`z@2a7&YKH>{dqT>gAbFZ zKLg-;zJpJer}x0R+R&{*@chk3Q*mSvCwUxv7Ce0))(F3XbMRg9^aYnY)+=y0WN4>n zU4c_5aLy(mG8j+Q!8!O6c-n%En*!&&gFBDR#r6zF9S*)Uti*O2fP%sLDK_Ua7^ScBK8w%_IDg)Sm0%s2iMv z@1Ca@1Mp;^gYTZFJ2AdGhxLIEkEiEUV-FL~!MC~7MHf5P6>v^3?yLc=x&qF@H^9@c z0<3)%h@F@k0NbyF?}n$Z2jE((vk&epfG8_&1n~eyY*(N$6yFSDwr7iC9taVgj#fg` z?cC`lL(rKnig=zU)~|>7WKXQ0w^i2qWr%(2R|Tl8UoEh*ezOQy#QL!z8rDw+N{00l zT3J7YbV{i0m*Yom+1vr^0c}4`YrEr~5BOI!ckJrv-J=NUU&B9D4$+?s7k>D9Nv0SUM;zK)$f3L7pj!iDj% z=+vIuqe;SrKe1Dzj>RE0xbRzcI)?T!6E2L;?xsHg*bHqXjL#pW+oAZwt^dJb**Nx0;#cIt=iu+IUPoM(?ig4X76-$5-n4o_BEsX03AL6DFR zdy+k#Ve{c;KZLVZaLJD?C$AE!RKTB7{FD#F4-d=P$N2}!H(m#fu8AMi+XURZ5M3|o z?SZv13&BtcpWmUul5=dX`!#&OfiHHOS4R{d${y{yxFcYF0DR^hzg75BpvnvhZUA@% z)AsrczahfoKmoTMmx$u@69@-*s5iT;%Z=os4e@6c)sV29`yoeZ(@qYFI>8Pp? z;0j&`A@}9hOi(*L=u2}9Mi(w(r9@46jJCy1H9y5BAtWf*7<;_`R&cOg2k z5uU%ZzYEa~tQuM`;UF3s@_kveoqhvoJE(UGU*ix%u+YY_P3X{}^Wcfqsdyzgz_kfn z>Mq;g9vP1j(gU`?Jp!y30IPwu1(*S>7^^273}gQG2tudk+cKY+53JX0yMXngH$QEu z*K9Mysw1cdMn@1B`eHCW*af3H#O-6~X==;`BhrIgFzRQTmpBo9GcT$_>Nj>=FW9kD z#{!*RuT!L6uT!L6uk*=Zy^f^0UdJ{#==HjQBThb2cV{``kiy_dk(wh#YL0v|;D{tR z3RVn-?ssgCfWZSB93iHDX9w#ai@%XV_B<{btmIj8lvJ zX5_7zZAKYj-HfV$RWqt39CS09h0v*|{ASb)tea6Aux>`(#A@rqngFbtQ3iNrn^865 zuDWLQbXI9qL-}tvqsOxxsfMCCQsjT48EMmk!-H1pxhw}IppAyCNX>yFbwl>apdphS zbVClh2@btei|wFcqn8s}uZod|DhA79qzBuuXHZ2|!>$L`4ZDe0HS88*)v()uSGZxz zBDf4M1M|p=Go`x9>J=66TMP(skoS=d%~OCk!Sh}CU?751fcJv>&Zn#}Z>ht3Jl%w& zwg=+~)7|j3!VIYH@py%KFZ~$q6ijwLc)2x5g!vlA0l2S=LQb)yVgw(AnNaoZl(dT@-fr$G-bi6%Cs(&6I$A@RJ# zJt_y%I9`;z33Lx@cvd`7$j%)XEis>I(zyvO`+7U6)L38c;qd|tbL7G}lBp#wQ7NEE zq@!;cbovHAY+_qZ*>N$E&_#B^rUqTIHq>24L|z3%f;Zd9fe~OmBB}w_rhFE#GUZK# zgE8d=H&U3mc7-e2D3sp}{cJ&OU{q7~2;#r?z^jU<<57`IF%g+{5#}CnBOb-H;?%2f z2W|vD-IgAUD!u}41ZFarnZr9(t?%>XjXcO9BhodQD?cVaycJVYxU$#cQ`imS;s~bf z^~8n-IdWbo@f%g&ygd@%P`({>8+i4OXCcOL{kjum*&7KiU-P0+v4kBgRg*TCs#!B! zs!njJnimJx=5jRyn9J21|8TilMvqI8nO==fO+m7e!bbG{#OU%`D?hc zU*qALa}L4noA5L0Q21Pq+l|LyDu>xQ2|N*Wlw;io$H3NT<>( zi|Q>q${)JT2iEPq16a5BZeTq%BOFY7Pp%0urtqbovZL+f2;eHW9JqsJ4oG`pJUq%6(CM=PP3$qOOrc1rdQ zJ9#Q`ZFSe7f1D69wJKV$J-yRL_M5jkC&$`6j)GE5@$@r5ZZf730^!(kkQEL9C45QkL8>XDoym zzrf%~#TW)qLi86SP*16P#KIv}>PvPZHV5NWdmBF(v*?tn=99gwuhN@R%W(jset zb&ISg?#;evLOKaUr-i0Y2W@JlTcxz2X69$K$U(NDWm{yx&(9l{w2~hgmN-2pVu1Ni z{P3yvvbXdo@{Y+EyMT3V_W?V}WHS#dtb|G%T=O$^F1z3ZE>5wkO_F{r&_LF7ck5c)_6YC{^-f(B%kQ zx@j!A0OF}8t_&w{Ly9wiS8KJCGq=GrHNffB&^92tCSar;$cbB`{m2Qv39YtUbC^*X z4%C*kskW;luxYT^qnN4`bi#q6^U(rRbq9IkT%xfAMNB3(3CFVp^L)>U#eC>%bU2@O`eQ4`Rr?B5dwP9swVtDS!u1#&8_RsP0J<$`w8O*>JMbdDCZ;PhMjEx5&}L2A7nN<{rpVpCtp+hDD;!J%Ra?e26|WtnUsBo7wba@Yk~XI&&zSI z9`~r9YbgE0r(MO$r45=^ZXM9g2umyXI;7l63<)n(5@z$Fgg@H}02gUWSWA>N_~}QY zfvVT^v2djS&%*hl)T>495WBK)pD4AX%EO{1cB9$BrPc6(<*VUmE2V~`nai=LoY38P zkRGmVwNRp)`(C(az`tx%DA;8nlOvwV?lO?(E<^q)FzsC^4Q|RNLyy9ID%IN{J6y~F ztI0tX;UI>K$pc4DcD>(EV(P;;dJ&=|sD|7%FixGdy1`y-H*Et5~o7t>UKUVq>98o!$Od6%pCL%*RxrL>6?kgg zfQ6gD7pi!EN$!JBW?#g42%v%|Onvt9tV{+Hy=_C>-W*^Q!MO;xF~B6g^=~rYt~Z&l z0`!AEgB#&WB6Y2uZE57J#on8rlHBx3=8Z2*CHFJlq7pV`^VrqQH*; z74=B5QfkziFb|unc)os@d1ya!cFnODJ%owB^#gvtJ`1P09)@^vHDf#z+8jh^YyND* zpPl(L13!5O;OA3p$l^^RoH%TXAwsi4yz4mdz(wndJfh9Wn-}T)R@{?JtB@Wt^~f2oQE;(? zZI5~JB8}KVevEDACp7cJ6{eVGAwhexh^dKb`(kP#^u^Q$sKwMtoE6hjhEihkz`hn! zB`}#7T#;%SQ_HcLgpy;MpQOlfsY>#fl4ELH$@G_#V>J@AD@BfVOxu@Z1EDX+WG!wpQsAXtX z74^i5tCnAwtByWg{cO|Fiv;a;q$<)of^WYnDhd6nr~%YfQAeDuiUx*KRWX-X6}lbR zv`;_R9(FTr!yf*0Rit)8XjK)J#EPpr;9rufCZ=t0^>eDiiY@#YL&ZPgaK)Ck3=~FT zcV!a{5dp@3&I_^>+Oty7lhmPu&r{y*b?_fz-qwc-g(hi zfO)a+N%CbmVGd|!FyPBFo~Z}aBZekoju^tPqKj+s11$z@15ErY&wB)Md6ApMxsLao z>Pbn*pDYfBI;6wuo$@tcxsyq~Vug1HUJ7hq;E`WmGP3BfJulM0eQEd%*L6yMXi0&vTam_Yk+*k$HQ9`(4DJg|Z^=p*R_M z6zmWUSmOY=V2dnkq|FS4CTsAXH{G_X5Fa(o!D%hw#WMV>2gJ}!Dzgb#S7r-wF#K!t zLk)8H*TvAr@Q+)H=J1cSIsB91V0LiYi|F-|H(5%e@gjur^v{8-p|JD*=&Smha zBFy=KT9_RSqJ-H^tc2OiF#Q=@v0EwBjuvP+uoh@FagIQD0=uR_SIlzK^}<67lRrWR_&GVKf^K0*t+~Kj(4E9Nf<6!hGut*- z#m#XEX;XYc2gY(K($j+W_8nNz<-Dgg7g!5=2C>#$-#;tpCU`*5!MKEDMRQz2+GI^= ze_RrDO5FChpOpb=3z7q5kJApQ2Bckp{mM}Wq&*Di4@kZJAUd_cmLU!Xq*b6|FN@`_ z1q`Zj7X8)evJu#Rc6p=AU|7tKCOg7xVM4k#frHv4W^Kv{b16fu^a#`1KUzb@5RyEn=`=boXO1HqntVt$l)}&-$41QIHj4vb1HpI6V%LucZaEXkP ztOHPBHNs2->)NR#4n|2eeyBl?l4dcqi~SdlW}86RFG*glekw8|YX{bObrA=7_4uI% znOCaL$g2{B{j%g$OMg|aS-?84M&cl^xqhfY=GDf~C|5oQ?7Y}m&>GlhcHtgAh{qvX z51=;j-hqg+$PRRt`=+oy!HkG>zb(g~6*0Eb*(zYIv$e!I7H9{i`=TxLoLRW5?MWjr zv{2?XbBXoX09b2X2eHz+Zr>lNVY8O=8eSY@D`Oo$Xo7fI6Y*ysn*ZolKFNSy33#Z* zeEKTRsWEKgyj`|7AII>ZSe9se8er{YCEV`OB!DJy()3yia{= ztXQOHBBX7HyP=1b#2blj)Bwhs{8?2Uu-1(RV$qH7F@S9LLq&d%$z&@q#Arp1LH)M# z#)VLCCffzV-c*w9@gs+4U>8W zuZTwjr~{_l*#a7Xbqi=_7&WeLC02cJJHre($mwE8rTIO;TJt@uXXk4E&fsa~Ep`U! z>9$f0Jdnk%<2}`O8h~}%X(m=}r`7idKgwda!$Y+jm!_}_v<;iYRhnL4ZJ$zyX6ve) zn934t9u0baE?ZC4hz}bjn^twigPGgnTn1{5mn=mMvjchz{OsX<=n=O2uZ5^(ByX=~ z=YOKi1UsC<_bvBx6t$W6M%l8)*-AF9eT6@OnX-SF&H>>lrR zOl5hIjE@Ng+dHJge8Xydfts*3!UqxVGsuFMT<=qr9&Z=y;YNSh3ILZRxO?3DOob=& z@jc?+5`$*=GnHU?zu;voJqIy_-RapFq|F#Y=fq%l5#KW#gR~h#XvT2Km3J6~G9&Ji zqYN-YM#xPSv81c_8YJBr*}X5Ju@@DvDjxd`BI96tOT@8HHc6q?_LemFT5w^H^PBrD zVBOpsfpv4AORSpve1;jYxpy$6YVO^@S}}Twb2_?O$V_*1sae^^TMn!{x@uxQyaLvZ zwVqfHuY7-`W^{DLAasM3X&wThkp4UmSkLnSg8}MN`hV-&KYenDa~sI)*@;rRwC;1{j(zKfrl0mwazJ3NX;RTKX%ko5k>J`XX%t z)*@|X7}fK35G#>(Gt7V@?PW-%b*ZDXA}uHW1w~qo^t4FpfCmz3Bkw7Z&IQ&YolmSp z+Tr_WMcNGyQ>4A1p>-nC)G;WazeZRN7>Kl*{tzjvUF_BMuJ z%kSB{=&xoTJ-~Vt<{b+h%seun2GuwFy*fj?I1&+V$8%I5?9sN{i>|GaiH?hUqu|d= zEd7U3?+ev$3jIPf`k_Iq5u97pj)g2gE$`gL65SFzk7E=%d|>xw0Mo|M>#1S_2gUTc zkaII$eNHh!tw1pun#JUrO&thi7EGPE4*?YprcR`x#hF3fKAmQVU`@8{i=-oIB%5`?#rj`2UXhLOjUwHNLPj z20v%Qg?6=hBn;PKSZ`l~c^q$tZp)d+g<5}l9v8Z6nR#6Jk`pmTLaWk++$&}B!~MILp$=Y|9~ z5m))Rh4>RF2s1nn?nwkLPGOGCd3NXle13B-HnF*p9l9S?Xod2gz?(nU#81X6jpOfh zsETKmrZn_QhiI589S(Rdbtzps3UKTVXo`sbPRIYbBa*_!cf5_c#M`M;DEat%`30fyFog7eXIo<~&3{~_!o&Py=1MT( z(+U#&#BX}d56#*c^LZ{$KUhIYCG{_I$*%%ZVH@Le2b^_9%PXk^`OoJZ& z6)5XO33N1IC1Cu5cre?e!p857dzUa6E-t{w?~6xI0*kzazA$d(2DpED0Ur2?0BjKP z`Pl$MBMX;2)RDgj;}PcHK#Uuf%QJ}0KIf5Z5vmm!{R4`}>2^D)lA9BpZFd1;rY+t* z^uArZy_3Y-DtY*OzFRl_dIc;|`%MtEHOwk~q8(>$v1|t!53@_}Ly$5>g-U+|YNAhB zB@CEwN^e2`@ga*@?3bMb{IvlU-G&b=_){Nq-%+3q!aHV&@2fQb{AMyBjL;LQuxjV zMDOcez8J~jlKO7R4r7Go8y+mlX+C4VC^>Zi>YTcXnNxmIJ5xbuxRMv)hWv}KrYimN zpLjE{=xOOUfY;xNf_tLy4-r z$Hv?d@V8C|ek1CYQYUapev6|~&!A;-hc~59O~NF21+Fy(u4ETma!MnWlKuUhDw(3n zsfJkPRJQ^-x%+{&1}1u}?bZS}`-w)j25u#$rSZF5_A)!5$h7blS4H;%QTPT-V$lg< zt7Jd)zb69RN8&7e3-ob-e~>7`ok=H!ts~${@@>2D5SY$e;TWgTL4UnDT*=M2b8kb~ z`ZJsm)u)85Q{hV1K(KcKhWttqvjH9?@h0LFof@`k;Ydh#9qYUyY<&THTk@gb3_J5I z>wMJ_mfRooE$j$O?q9Kv5YhiT9pV44nSE1gV%194Z)CS4=P$KtoM3x;9Kmr)31~e^ zB5e)~NOR!vKNta=4Ua#HPiLba%e%GMpBRmS$M6~2_j%=e6n$^SPYc8TQ~7=fj}h0x z=OqB!9@&OJYvckFBNyT~H1bLO=8as0UuWdg_zjPI7QgPu4*W(&zKCDX3Z0Bmbm&a{ zlw6CSv{!l_{-h)EN-xvUA9v^9%z?QKv(bH9&z88>Kei8BWfQE}$o#N11Fmdezb$_N z^J$m5))sJO8-;IP7iRWXcusT+88ca@0v;%1rZk`)GgT7PlErDRdC~lq9q7?w^Ac-3 zJnBtrC#C4Iv8Y&XO{=%5=_F_v%W8roNFu)=38BZvJe`ElgX{nTHrWxBZ6D+z2LX*d zgf{XJ+Q@^Qf86L~WH7)T1Y9Dz8p>;X5nWwYbPa~+nziV%vSUfgb_BeKX6k}xG-V2${O>} zRopU-AyDV+l(P~(+wI~{;L3){Kxs1gzgK%@a^{z1nZeC3Grxl`e~3)v+wr{wV9!5Uk$vPcwItGK+z?J&y@K<=<4)P;eFreQWlGE~{e^)dOL~;ubKXW2P@MPHXVnBWQl%$N2A4W2JK-UxB z?}nKi29raE#W|_t#gnWgRx-f&HLO})kAO6s&U56I7m{D)(4CdF24uC$82Hdvp7+2L0J!9EIi^B7KcP7l3SyKXRANjv2BpIX?Q{&Gb7IiaCx&NZh^04T z2%QsyDwG(Njlp5OnTODf;U8i08c?Qc*|x6))T`b#z??erY0*03U~#{}4>ibRMROS% ztKQ-8?wCJ;7_y}tTJEO*AM<&BnHTjl_P)&D{b_R*6ye-&&>*&vZT4Qq+*Y>PQ>P%N zzs+6_$ZmlTV^$N3z4w)}2`O$1r3`0KaWimp$X;#?6;%(2*>r?U4Nbs>YuMgURe=;{ z;W#^g4YedE^i+6?zP2!ty{*)>@v!v@+>q&Z>ghz-ieS_-q|}ZLF9=)v!VOs)jd^4Y z6O}dblk!T(;!iC}jt7**M^9RM3TYpOl5!A~p6vGs(xhr|<5_T@{|_~7q++J;vr_9I zfotH>_xi&mTDexF;1s%6dO?_R+QDb~vA!{V(<0*^1U;O=pA;U}LJG%&e4Ad2rSoB^ zzk;mAidXuDASK>Qzu-4m2H6IW@-HPXFXoR^_CkWZ=-0rm2y)S8TnJD%r3~*`sjqbz z-u25s>vbp6k}`Y}W}GgT;jevTX3G#NR%Q4iC_^2*qzqV^#zh97gO`-y`yeG@@cV2T zR>u%j%J4(}$z~aTuu|({#ybHn{XFU!Q(D2jKFdicZ2QB0mzXZk>7LW&gX^B_@VGgm z>gC@J!S4XezYPf4fA{RqZ3^-%>l~EhakzAq?NaS~D8Nl^(f%~X%}V<#0k!tm01saK z>zK&iRXhC+5Fu*k1+eCGBT+~c&VtbPmEfGe>qoZ?ZS~;uaR5VK4E}f0P3#({rWMyLl zZk1JI&F3}vk4S~BVGp3)avMPOryRGNF)rl-|FB0BMSr%e491qj7UVM$uhrm&E$~Bs z1bnp`A`QDSM<0gWI5>T%#UKn(wLbjBcEGFwhihUxb^tHCZ3&~V=eWgW^tNE2M$#M@ zktf3~{YtPXu1;gFKR6Pl;&XL&%ds-cPUR!oR%& z=YA;K=iNI1X8<}Kt~(dFf%xf2boLyk?yr|QcSfR5;vO&dm(IM1<=ww6dk}xkiV=RV z0JJ>uqT3DtO=&}7Z6gy0}!k-tx9+_f}Ny^CItIE2w{|&4l6SnqU#O9%TsRG7v#6yrBuEwr<7{ z$Qd9cHP*snO)#~wqYZ%^10oQ}Lz2xOkVLxFq_ zBB;~#S2v1qiYA!a>mY(U9kGT{ggQ;I2#NIbhQG{(Y!6MuWBB+JGf(VK*X}lts z>4hMII{g?#P=tx)>JE!g4S3z24=avNIvXCiD&X>l7f0CodmFK^IJ_7Gih7KB;quNXunUg|SV&?s z5St$tw$_Bpy9UI?0B@4m4aEMpgaZo~bQ&-0s7%Mqz-!7*%XmGJ>qSFcwX+VzDZf0Y zefZw4H6Jc7VF!Ls_VHuX$UeE@=(lq}e%JKl*WJgD-SC8cReBG3g*7jStrobv(xfle zbr9e<1b7B6Z)P&u$U#4@k#KnjC4D2B1o459N_*c_Hb8*!`(;ykR;7|LQ(-wyMIey@ zcqx0O4=-a7;Atb3#J2Fj#Q{aY3sV`oe>Rol`%C2j1kfegb)Zy!XQc9C-&C$aHa{Av z%vGrz+LxDI4hVP=J?%h%>*2>CTi)@7IZO7WS7?p@|DzFntzk|54U*WS4yyI*!a(Qu z2i@0iVIM!n9eH4GIQpI5kKZ4%eo_Nmr`ddF5ZBvOS&BR1pVwR%y?hY>E>6z!?kkGw zl@yNS@*XUTzPo`xjPpo8RODVd4acWmgk^cO$ZZ7fAU>}sasqHSF~0%iT?dL6=LC5R zi@XOF&G}~DrA5(sCXGpj<>{q;3DH^R57(9bC!(P#*Ifk{Kq_nGu66tsxu-zds{2W6Y%K}z@j0RNQ{&-H3@ zUCQ_n&t)bJ@tkGSBA!;|<1z-sqv!i<=F~&|-Wj1+wRlcIt_uzE)GP7q0{@i}&kIvg zDqIJ^Q9KJx8seF6(juO>luw2+AfB%jJ)AVe^RY>DTjI5at9X}1wErXUd8+3Bqax2dqnQVKd51Jz9@19uFH^K=IFuyMg%K%>UaLqPu@toc#9tt{(|Qo zzr#{RiT9FY-R_kB3s{cXS*3aKnZYAvPH`dN4sbE7$`$YRs$*RZ7uy@(?VkR+V_gOp zyUtGCh~t|9pGYL*u^dQ?OF_~#Iolg@wY$}Zh=Ysb`X46P_{2R7~g+NusfSnuaQ*hL7i0alpu%x##4eM z&8GxO%WhVfPYISIe(WBXPY6~6;^{z_PY2E*Hl7S*!-yMC26BPad@_)<`P81!FT;8V zkK0L%6?!sIVi->b4w#2L8CXw2s3!xPeD3ARz!qZRq-rsk#1)1^$l$R_p|P(5{?M# z7m5mvBc$G%Dgh3Fc!qfDL4E?Pv&0S_Ueb#I8I}jYAFJ>^EgXauk3#`GSDL527G{+eBM3I2iIdQj@7BZE+c6$^=dy|Uz&mO4fp^m81Mg|X#{=(T zy)NWE?AXd)Z6$AH_i9;L*sGOrzXRqoWw|B%dXOcoVZz_YI|b?hbqO1YgAz9Tfmp&; zz@JmXb|&?$&p8#HPq)d=cNcHy$J&53C*C896M5u318N1H_hM+{b!x>F8y;BK?@1l*rE}%9+^NEea4;;zx1s+nq#s!Ge?gjpZUZgB(XK1kw_Fr9IMN>AYSKG^*@@p9tZ?CaZpQEtbyomzuU>9G4 zsVAQ^iFIOXS^U0Z&4P<ZVW;;qZEc7$^N;#m8`#dfztG7)_f z8}NJ*Fm?}W2cnP%Jck~lrk>;BF;)|kKup#|4Tw!ZaI|J|spUr;Gx75muLe&LsKr$FM`ti1i3!o8wmTIwj!Np%qjsbUxCS`xVXPxcL(9y^--GAgWk75^_dei= zSY8=c$Ane$Y+%A_1l~-{<|(haYh|dFZkp|gt(#^yF#5rMo2K<7?y07k2G&ipl2|p( z8sDFC@|$KIJkT_Q7Z&E>hWVO1(q@K2`!6gEs)=ti64BoRHGLAI=XO`@O*?wkd(6kO zj)053XS-7{#BD%^u|L=mzBIZSSbB8^Y~_vj@jBEqp9yPqPQ3=KT7By4#bK@gsr{b| zYh|`Vx3}SB)M(qgys@X<(%38vbS);*GJIia6y zHK0y*2C*a?oCW6Q2!<8&uVs4Mpc($j#vv;h1LKh8#&DTOJ%xgC2tzjka~wi$T8L#FqR%>q z!6Fx5^vPwRx%k3lc*z7Di!VB3(q`d=UN%X*mZ@)&OfB{6r-DU1haRuN-2i1$3o)$o zHZX~Wn7Vf86ro?|O96GATZ@7^zgN}ShDZnNDmNP>)>ZcB><}04a$RK?gXX%*0jh?1 zpX(}*8wZHF$e@cLDuh)CcLOAlX70H8dsV%(bzFfsS>;U;a?xXkLCc~C{8baFLK0Yk z;G^QTOieYBS-M;awv0vwTI8Qgd>=9Y05SOsrn$59!K_1Ugq&KL-plepaXT|o@0aKz zmRWiO3fJQYIug)(3U&tT5JxE?vGH>qLcg|!G}j?M+zkc{7in3C@Mb+N9-=#ppDuM8fPsGsqDu7or$fF~vRcB!R5*%IzxN{-eNJLbZ1BFhV{BgOMwh!K__S zDzli^==iNL9+v%HrR z%Y?89cd9{g%6jf%#Kk3*fF}=hwF%AV2qGM~%wTAo^Ov6KZ>ZQkPzUDPMLh$kwTmWT z^hCkh1)GUE1rT~FJY}t-g)xn_iZDZ~wTd?0Q)?BSeyaXj1+c7kSjFSfk?GwA;ch;- zn*;9j!UW}FJ%eGvHAS123hlL3; z(&1+z_0$cl8R;bs7)dP_b_dBwIYWaHzoH&M$$t+~s0|qDI%^oh?~&^WeKXnssLf3? zv2>kkAc9o(o8ju+7va73SwzL619fZ`u;#sySa|1K4(9ryB1;i!KClc=INI&t4JLH1?A9-5gov$C6dJl;|U<4X^A52S$h~0ixEd*0V34_jKzpW zz~#VPj5y?Ym`!3VM$7=7!7wYe7{NhIJ!50G!`{9LSSxJ{F_qS9QzL~bEFES%H>027 zMf=HDv|nM+C}s2{)xYvS<}R?WjM0YlIOAdHE?_exZ7pXxzuL~WdU+4{XyDZI{*34C z8kC+GGoFw3#MgU#f5d{wPJw7ZIR)=w%tLHRB}H?BkE}73N?@dd@WmTFAI`1;Tn9q00f>zngCOsN z9W_7p)>Bn568@MYd*cln^WVVyc!))tbRjE3H=bh^^JC8F(PIn$LSmtvY}?k)~R86Dzgq_5D$3rB*4Nfa643 zYkVGVa3ZZWp0t^v(Edbv6cZT-H)StZuj)uuVZqzF2Yv(1r|*R(RU%)`r`eKffRTq4 z;e5J|H!z>Z6*{*ECm@>fgJ=J&=YrRfT?QZj*}v2rz*pdkcC}OQ;lBj$rz=|9P92B; z+lVv%@r3h`9ABd*Gv7`SeBYYPc2mfT@0s&oC3hMIUenduokJe@d|DC*oLQEl(wyg! zib|Jz@ZQHlY__98qc>Ya{*IS&UfskTF8%aHrJ@za4 zE-vzN@_l|V`Ho~4h^q`P@1-I)1$r)1zpyBh2Rxtn80JeccaYLz=9boR5b>?6T+F+Z zS*Y+7#XMKTDCP}K8e*Pc(jw*~l@FT{&kgQx(l|G`i%AFKUfM_8l0U?qlRw10{QR#l z(|@VRJI|yqEQ&UmbRc%?3}5VGz+llWo`vqK)&nY~l9tN@&>5zLGvPb{T}6yD;XD9c zODv6CAAsiK0wtsmK#K{1gkDn|3cbosR*Lq`Qewz}HR~ma;bCarU;5X+KpLj$YhnV> zo5)nA07DN)z4<|vNoeTJ=O!&unWSRCB#Tr=n>3_SV$!QtDlMi|-bI`ICnPed?7wCD z_E3_L76#eYm^5U&iAhVFJWcsCYb9g|zTs{xCnR%dH zUTxB7mlv9J&@S7R=%rom3eI>CdcbyRYGSw2M1ArZb0pD3eezjoNK2o57W#kqKT zUQ-iafHut z*8r|04tj+eQbs2%`Jz|I$rswU{Cp2J^F=4T7w9^sj!t+7;0EGA>zYZS6Bezz2WD{7 zezZ=83G*4!csfW)MxGAp;63$pP&cu9I;fXeH0?UYmF_DaRJ2%0v`hVTkkG5v=A|0J zq#lRV=3$x-Eqip8YnmSJy{jZM2HM8{mmj5mTXuN zya3|#t@r{6nFBh=@?{8{?}f;7i)q)a1L631Yw=V>k;zH2m@CP6YH2zghT(SM;Q-fZ z;(mY+H1QmsP3nb{V2Rhl)@E=dtWahFp7iI-B|?+&GkOYsz(?`lHujIsk8^GR#Ud3D zYv&sN#BJP#IWJ5ecTs{f%^By|*0@XJhfGD2!Bq-3?ow|rgB-b*9pBNUm*gL>NX8lY z8~jL8^-Sur@Kq>q6X8|C9`d0~HGK*8-gb(e_+ zX3x9GePS@z+yto(FxT|n8)&W>@bZb~<$+vY9vB=i8RRhTfx+-nH6Slm$-&RaJ9Vey zZ|U`XnM3J5fW6lNdZl$5COABm7l~{%&b6o+;}(h+_Xbae7vqn6O}rxTx))wdXWS=& z*B{`O8t+=;{*CviZUm)uN)!0Q!5wB=0yuh_WI6)ym~-*o3O`fkPzgn2;Bk8e$sGbO zMjCfe;B_6m7S3_DQmVa+o zgi}v}?609yIuo#+F}%`00LpvVS11SRRG-v?lmkCHwgIJ^|wBLZ_4{JOSW7rd@;tgw~EjM7QNCSMrsUi`Z4mJb*xG+eKqnf6OG^-tobUq1@OUs z0N!BzAQFAar>qj*sze#Fgz_Qz1^2wKyh<-XB*ZFdg&$s8J#kTg(r(605wTZ#gN9M7 zz~VWRX^4O69W1FBb81?iWR2DOS1Y&m(Yt)9V*>DwAVVFu<$qcm9`VOw4!nJ;ct7r-3Jit|P zOK7>xSsvi3Y_cr`9!z_#LD2r!u|j0E@Xz?+;irl{9P|l=`-iPoxQY;7aPg!jwghp` z0bwgshdX#7a^Zsj`y2@3Fc6bxhOP7ADn7;gjPE}rZ0&g{h;g_RJuGZJ4p(s!h&K*5 z68Oy#MgnUcWh8Jeh#-Mejy4i#K1T6IcIu8b;@p2KUa@)_@_7&(91D0T-*DWx*i*@b%nA5pc{J7lKAd9-Q&}CKpIGD!Jh>-m^h9dHUtsQHF0?_!59;C2`Q-nTLD`m$pBCp;81`*+ zyb|ZveZ&cRdE)eRQ|dz9RD8XPMVedtE5h!Z{|$D14d8PzH*1mi_R#>)gVKO*YC!Lx zG@$pVHQ;lwW1pZjU_M^oiJ?BP4d5z34~m`CAHdH1yuq~Zas=(aeHR}3cf4-_uHriz z9}Kt}9dosp9R^j(2up@wRi&5W=0!425vzcn1|Qz=-)C82=ecKLY*NP#xG2v(5x7aP zO!Q=3M!;5d=cM`7u2L1wUxsDED+t;#7uEC$09DULz;YaV( z!8@S|DSW+(Bi+Kafu4tR?!Y_vUII9*5X2%7M*|4)oNE`(EDBrUV%&KsVu$EkSPY88 zQM`!I9t(+E6X2d)+x0yUjubw1rV4N+X7YubPFJbTMAENn;v6JBYfr_&R=D#c2+3zU z2@DQ}w+0YboS_o90>lKQExg_3+ScmKo$DuuBKLW4&d7)=T?B0J0_R+amluxP4d=`8 zOog*ChNV|);)amF^g#=<+9clsI@jhGaa4$lO~|>I&PdeC9O`JW&o|N zz(`f4YrSakwY5%;wRVb}!CC8Wa$e*N##;9xX#dtaVCQbI!-8vf1nUl0buVAWG_&R>1Wh~8y;@^94*lM4I`v*enCScMf#6r%D zFwdF?=WHGIc|8sF99!45n2Ph4eD`he+H^U@vNYe@Pnmd_N6VR;^lA;dVylq1M3sy8 zE8I{}P6>ZnEGVbYMmb5Fj~S3w<%HQi8M(BQgKLxSNw9q#z!kGX;UnO`l=wQgc@8?h zD*%Uv+;f1-ft{N|Zrg+C>xefAiS=(F?zLSW;co%%w;z&_Z47B+NQ98Qq$-SFOK9mQ z79$T{QYhQcr<1WE03Dlc%gjsYWn;Uc=&NRGkxyyKf(hCk=szUmtQWIo`JFfY*wI!yL0T z08iT5<#44L5JMGjCtzMM2v)o?``ss@ugre;iL|QL{A-acFG^z46oL40Z(>~|S?8vt zI|p^$4qP!i6uun(UBqv??$sFZ5LSfT?@@r%l?eVs$UPmsOC|Blkjt}4wZy|i!Gj4R zb9^&QKbRmi9!#)2eI{@OIB-_a#*jKTVhGI`xiVfo6uk&}^I`~RTqsD9V+Uva3a2=} zPl{{yNpZr8q{vRmnb1eGCT3~&56+}4%|6Jfgsw#G?fp8+qt6o|Uw7&u){05K?lciA z-D#n?mF~0wYu)Jt*1EG4Sm};+)i0_$-q}hASpyX)?GIZ4;F3Cv^R%bs7DIE=$k(|o z>5hk$s3e|})mN##JtKjJkk)3XaK@2g>vlM&9VWINpzuZfh>4BksF{rY-+{cgf$ijN zCzfe?%8GR`xUynPiIo-et_JS4 z1M4!NEf7mq&d`P>qby8YB=oYjNLjLK#x^Y3AY=c8CF3UJidiygMaq)RAU|Tsyv2|l zFPx~QHS>0Yw0Q~rsqN9CX&N=)(W>#<6%N|z(Xwe;YiK=^R~p&`_;alr%W7CRDqsr> z(BUg!8?m8)G)a!3fTRNjoQMU@*>KLMP{3Y*LK|~UQNT%B0q;bKE`|c~wzF2!TX-W2 zi1)I?-K%m3i%;xKV>t;%;DVUVDMH@}}kn%3BWjbCs9cr<6A^uk_DFN&dn*2oqRM|%DQ@*|}4)(I+|IXUa& z&Ya~=$z*-J9;;%`oWabdJ#$UbdBa{V8?u4cNjBcF2gAqG0r?Pxqf9Q+GHK3TadkisYKhZ&AM7*_YQ;5; zp#9HMg`MeO=PS+5d%0`w4(R2rxy$=4E6L7#t9ZTL%236&0sp(6q$d5><>f5GJJ;iz z5N|V-|Iw%>&R8uEXAUa$poHzF8c{k|RKFaOo=EdP&#e_2CWS^n$(EBpugQ#o5T z@p0i?`GX#m{2R#sxNso<`*Y=wR{Nijf589cn*W+U{DU48|IOsT=D)%}&Dyt`|2GQy zShs?~nUhxX|3<-JtXn&R{)9OpJ9Q^3b@-?cJD>+;-MYxmM}uOgXFzs}&vO+UZ(su_ zbZaeM*l|C8@EA@j{vO3ZS$(gE3oE-}zor>(;s}lxEP7oJ@-=#8{8ii#7j0vmyM(O+ zb`4t-w*-$2x;>J72f=uE;wJg`sMQb`tMqR$npoRF#XoL$fZNP&n%ZaP1ES=zJ;^|VBrG$Q2tc$Z{NfWEGR1&MQ z)Bq1q7LigN?oT|+UqmDHQ*LGoN=mK7D&=-!m2wyG04c}0|Hmr=H}Qh#w08XCB8eR` zYkBv>8!WY)tA<*h>h3&b8W=@+^)G+lAGrN%i*b?`{aoi z6Pp$#KWS~Y3uNJhYp*RAFESrg|5hn~}H0j>EP zsf|ExBu%_K*casT(!@Igk`v2`H~c^L{sTU$qWc5J=Wh1y-rdbY)=eZ-mp~v=LvJFX z3W$n4me`|Mu*V*;MFas0MnoS_)Yu>v6dT4$?6IKOgB4UX`k+QdjRkza-`BxTZ+4Keg1-L`4Kh}dA34Yv`FWsfU>8ugPg!4k z(6$EV0tP8(3(jrd3H8)Nj0)v^iy4KgYY<+Kl>q^;oOCi=X*^RSLVz9jEF%(w=6)mJO#6Mo*+zf{o@ zrK0h4)A}z0ysi2VtelUreg?MGRSyfle}y~I;8q6K{aQV8zRz=uBk?HeODY<8#wD<0;dr(Ff(&%x@9Rp@g64dee6D|XWlFvU<9KNk>>18@P6FAO8|nM34> zd=>cUg)5H$dHrV>($o13JWV%3w|YHI$I>i@ctIL2L&su~DO@megK6a; zG(NKY{9uOe^5AA}0D4({xGB=PwxE?|8* zX3SZLA@dbfdD62|Q!1Z%7GludyAXr8YDq$NwJI~l9+uoDn!!~W!>!=PiC8;8c$l&u zPq>GIrxDJ#L~JzHpj-swZ-r6pUeio*42-{)zvo;`mU%s1SawEuv|L!0buqw4FiV9o z2ijZ*G>5oa_4XLHkYFL&BlxI=XgU0lNMyE9i_RFG#NJ_;+?G_NZi1k?O7fWH%bD`l?00ylCav!S6>0kN9moO6f=?}j+{7;RX6);6DOnPesuoedf zP7DEop9GR#dngh7A0N|OQEg=sMzX1~+b zA3}Q29qVS7p13_$NxZ4CZf9`zf965N-uulIL+T+xCv0|FggcQo!ARudKTWY72D!+H zE&toZGGSyX!-vwp3MWYW-p4EU8D6bE!``)lnA=+TjbD5S({c**l#8RIkAP|UD$33f ztoV!#$Ll&695iRdzQD;?L!LAxB77_9{yJVgHo*NrxE~9*7w8T|#CAn~pA6ITA?SHk ze=PPK0Avi1fj41;AdEx~e#jJMFfDHm7~u^7x;zZzcf-fIxbT!mO>qxQ%Rh~9w`WZ; z0|v10{SC{Qe+70d!Qk*xBlbR=dLlm%5wY7IH^mn)Qm&q0{5TlO6}uOi=SvtF;fR%{ zI3ETP#zrAiOoyRf^rF(vVEHnbmIYY;cRH$$H((_4#EsbAL>b_MHOMD_t#{pq&j7Ru zCiaOD>yMKDCQPieVT7MUk5VMnq6cK2e?eu((bBaD~Gpz9{`seI;je~K&>3k#wVb>a`T)7{aNi`d-W<=Kigho z3xcKy;b^GH2FUn6c80zGCy>8@9Po=N?uChb3FHX?Eq(=(m5#Og>Cek%fwA zB&cF}K*h53Bb>tx24m09H${i*;2p7O)bc|;wP9$E?jcn z^ov_zBCRn=dpCgJh}?>N6kP2WQ(z)oyvp;5M8j-}xONZy%F{{j*;zfRTQ#+~^lA zegQ%evH?hhBHRKb{wrK4!kz$LCb9%U2Y&O5Sul}HBZhAyfY@fdZmNgPY&bs*Kq6NG zd2*cTx)koE5xQJE!Q;|vqU$1JKmLvkiH0rm2v%kn0{D^$b@UZ7P0?RKC}Lu>mZ~eH zx(`U+-*91K9s*!Jkr#mc20%)c1F}odP1*<}rFz6L#ULLL3V$#FiBR}YfJ{l#Wcj8k z&V!L@Q3}99eG_>Yp|wG#wlyA}8a2iJFp(2cB=Ynh(??{8y#p-JC zNEo5DxJWa4KagvHyayv0J#+@PBfvyDq@x|Z(iFeJ$XxdHRp?G%t&x@h<`QA1|8^c0 zlc0H!NKaIEOJOAPQUx|P-K~+smO&vfky13#D;_}pKqpC--f@qit%H#Yc@#h|bb_Qp zz5{SF8Z((`qv#FY03-c;k3Nso4lAvVFXIT?YPhg++#kSVBCH(m1|Z7@E5|EV;ddP- zG81I$HsYvT*6}|;g!j-}*v~++LLQO%;ag4}e;j7=&{pSYWzlR6gd+Z$a0#?DWArhIlqQ1mm2%DSJZ+2LbpbE?X zMslNeFFZJn+6Aba>_$ywPTJ&zHP_`!f-0;m6;^e3-E^G{4==%}rfWA;3O>HVUGU<< zz-|Rb_)=5|5eQ2D$K)2+a|S)&|dkDMEER`o`S;||BCv^z(>ah*}H_C+De$;o-R$j^3^ z^Q#9b$I2!h4_1z=wPS!jYl##p2QjNbkQ|ne;GBNO$4BCbQ&>moI)}rPSu88n9 zUfS*41;N3IZihN!x^k?-vl)fBO6AR3#?O?8A2rGf+?!}pB}laQwY!~Y8==G!GR#D? z9qmM;V_B1qNHjWDXvYA3RuMs>(V?cHFFVob$j42zQyL`N7n(yi(azTt9HQ@bsPIii zA0>P;Ub1MNVT4DbYa(GxrOFAN$B>;TqBxPV+mVsTb23i30Jn{oAH2aO^gtVHr#= zqL(&wHj5B!Eqz`ockqhYh+AJ+kxiHtV`PL@@Dq&f%0OSB`E;Be2~@%Vc*0QLVOn`o zQc6b0B0Az8(k2~C=m@1XbhPM`562ZEP?}9(t6c_NM&D2x9V-Y^Y1Van8PaQrUXkRh zsw67wD5*SkRH`V4^@Yg(kHSQHgye8x6+`J661nt3f>+^avhUbe5v(OazmVY6jbPzx z2ggH6FgTQX$pSgL&zAP9a;K%0plThvsMe9&vSp)x1w5>Wk*#Cw&pXgE{5gzu#;F0P;oMcpF_8SiI$gaRvGxuqbsXa?yc+#eB!&6zB{V_d8zRfbg&wq?Mt5lI56G zN2JmF`hM|&v)%Qh3D^_2$E1jR$E1k!_!G#K1+^gX=g@hQLJA+(K>Nnxl{phH3^weG z&z@MxiGJSs0M!{j;oZ;+zTi?*N=k zu;tQF{+sY&md!ag`jkGmfOSyLLVeB{@=4AmkyXeTe5S+Xltf<9loHJf4oA3iKp5}g z4?Qo{qh>$igOEhd-xF)oobw%&&1lYaIg47sNG?crxe(55OvM>6{NHkZwEkggu8IL& z-B1vQq7HDQ+QMnWRg;%<6`H@98s1>U23@Y1~;i3G<%YurdiHJ*P`3FqiJ?BnbZ}CmW%=Jvb+l z0$l5p0CD&Ijo`Q{Y+44)rBN17NZ=EPfunOUJ#n0r5aLM*e2B}_5-fYM2mN&)+F<9S zXSE02v3SebNk&}FqXfwAWOCEb2$EHnZZ-F2?t7gOr9gA?10w-01n9pfVD$&gr!$Oy zfjeEDL;QR-UA>&NdWx=Eh3G6rp<=w-G9~U|j<{kDfK{z0pqZBuTj;0x0PqlxUL^(L z#N1l)*+)*P*E4R2Y#lZ0;P5d}TmM znRmiJs;;IgAuDS>9OVqPKWh;{Ss#VM4*-;P(C?}aLX9ZWhw3`$%}6U<2cfPPIjgPi z??6I4sMZ=UkNzOJ=>FkW9&OffV|LZjbQl6c#N z*zcf|>435E1o#qDq2lpK2qtWMJ8Mpfqy0U&JcFq!by;lQ2913^FgmXEW4~ z6a5%3TacNyKnJVorH5hnH0-3`lZ?QZ5F($!o@_V*am7SVyT$?q_Jl^plenW{9j}v= zISonb2rF|QRVJ*xwE}xEyi*M8EbXOB11}wwJKiGmYqT9nlE_AlT+jRfoq4i5jT}6b zBDt87gybt{u8?o%Tx&bjsY*2oV#!<>Tv*M-nj+Htw5xXA4H{bD2B9dfFYU4 z9E~a@l?*xwbTWfx`&8OtA&vOWPS5p*b)05+5$tomGOWXO2E7J2lEiu$8sj62?AHy_ zv$d~52Hj{lX(%)7Zw)f+H%(^Pa_G0o3PWbtDr)~*H(<7HIdxQ>>{r$T$RDONV@sFe z7|Akx$t4O5TW4yC&n7{Z&$?PC(V4&@u{o7UbVScyV6h$yO zWk`|J0aOr~0AvM#ABe1B@|=barRDE31s^rk*QGT^9ZNXshYsuYu=d@ASLUmD`Tg>& z%Jp;B|+E9d1U0T*nY1bXS`;b>RA_Km&F_#-lXWxtOe!|T!Ek^#LAVg7?@vTPjk^Q>P~ ztG_AMix-arzgE@&^p|(N4PZv>dCd9!R>jJ;N-SNtN2CvTQ z*v)f4WG$054mQscv_$4`z?MII22l5`&jGMpB58Tn=TKnF6ec>-$?|8?4y8dJ`H5dT z=vZVv3_Bcvx(`0`d{dD%1)xAPV`OJt2vD9S>d%@1urq8S%Q73x5bZd#cqVYeXkUnr zXnzEe_EYipwLb~(G?BR!A8?xw-!8XT!Lpd)$&*R10d|?jd|B56yFp`VS+@eaSz#iR z-jYSgq~Bz#jts!^ccf1X5#VN7HHA48sW6J9%KIzu#4_aP{wZ^^Y^rAizf|15y7H%y56+va?=ApkF=%EhgL?mKUGd z9Wz$Qd-3I_5&tURl->XMA|PktKj2=N_!|KueiZ&T7Qn=3W2Sr!`eIT1|HZpvb;Z-y znqmV?d<2j>0G;Op+23!(cf~~g-Z1e45WwpI(iZ`_1py=g96}_HxsKC4h^&6_cO!0s z>MBTawLes++iMPE$N%jQvOzDr3*~UJ-+JseDprW0F!7uHay4`@-2CHHIjkk=;E)NZ zc{k~(*eQ=c<`0BF!7m}Bde$Fg>8>E$*_4+kRuS%EM!(U+=q=y}w?c;Q`3eA@J}~ia zrnUKLiOQ4N;yoJCi$E(xQp3QWRFTwsBFVtGKvR)CrX%5BNGg$t*to^6&ZU}hNUrEU zA|Nh-Lwvp8x^FKw02uXQkYD?w_WT|3XpIPTgdBNfr_LW(54Zqu%dv(${bw5Cg0NiA zR|eQ#&R$7aFK1s%STAQ67|g)hJvm>IO_=NUWa8xm^LtkL$w4vC$v+ZLTII)V0Uy%$ zc>4CN@JrEm;}w3+nn9-Owx5?#M1JH_cJ#Ym(0R2p75s}o`Onf9au$EGna7`{vtCp# ze4K|9mh}%Y@ooKk!*s@b`WKU#fNa=Bs2}k(Gx;=~2@O_Hrc$hg6XY-k8UAks8MqjY zZV9x>;OutxMFy`+V;S8%rIFIHH2$#F1?8Mu+=7xoDB{L6Ar3`BxgQSkfu{9NZ`$f@ z%|p%f*A7O-fao*7O8)?06~Qmvx`g9U@jcBzZZ8ybayiK~f2l%Of^^?mt0@H@{;_d6 z>!1Hp#ZcnR=+Q~+sN*>eCi8m{Sh^0GsR98_c2)5P+-y}O=+=ZPd|xvZ1PJp_bq4bn zREJ?37z~_31CTy}{#yJ9Gnj=?1~Z1KW{_e`CVZS3qCFq>qv98uL2^BfZfBeFKGssg z=a}+7)`fuW`&gF~=6$Rd?_=e|!2?i+YO9DT9E82d6sR!&G zu3@d^9j<9Z+*7FJh=r$65%(4^O! zlJ_adpTZz4K8Bjvjfy{RI(E?l^ipZ}fonG$cIDTKt*~QX zAU-%CBVze7LgyLYgV%O~+Wrp}P8; zLQPeok;YeMJUaN;Rf}DQjwr{`;)nRb7du_CNAZ$Y&!SJ4junj(dD3qr=)D9&zl;8v zw7kvlRL8Oox&yrmAG;K>%kYvUIC@|BSb4^t!%JFCrWI?H*g(8yv1&OIR+2j=`4Dg? zJ1KlEKuSpIP78*1(em&IE`EAYWo71>Z)~DDL8*aU*!2LhwVU=KTiu1hAVbKw8x_Z` zC~^)dsiae$c9OCG1!4M((y`wa43RB9WHF9$Rc_=fpofZ}?D`Y}w!1#Xgmu?v4q@H( zsQ~QVwm_NP?oSmdJ>4IZuAc6X#GCE@)X?|;q3%x|`H|fp%e#{=es^%|xAFzJmCw2d z%Dyis_wwZdw)gUlC)~_lz9PEmf$tK)-dbL&(^Jb!+*8XFw`+N)f7TI}_Fld+Pv8~X z6Zm%Q=^ehhs zIQfu(@A$((Ir~rm*xt}rMA);TuM_#wvk#?o(}}PU@U|v`+|ak2fq7;h*minnABZ=Y zePAgAZ=tuqKOf?%VU|j(Mu-r}5ub}w;*SJXh13EFYYkZ?l%hLyo?Rt8>-vyY!gE0< zpD$wwP=>u_mAH4yDg*UwSyiY{MEdJ7q}FtQH+s`v_~Ky|*Y+vbnH5*t4;nh7fH2wl zV9%zEpBp)C9LaBSGbf*x_%ykp)6s#<0x!4{Cg3anQc$UZ^B&LGYIr^9{5(=e@l`?R z=aD#m9vyet8TPmnhr9f_Udu#S9SpLTttb3OP{i)K4Wq3v@ehJV0>mPUn1eV0Ra*WL z3=H@V^*MTn@jrvkz$7z3{Ig)->^9gLMYr0Zd3>JP&r*(c<$z zqE|dpln-qlr#W#ZU>%?4@F-CakHqB?1OlQSiO};}+;IpKpB@Y>L^90z5$QHP7-g@M z4~t}Zcj%SH*VCRm?LR4>fs@Lx-( z#papFAmS&0kEQR443bT7LW3L;-J2O758r(z$_$cELX|-#1GFoi=dIvF|MMMzxGq9kyr|RTzP5%K zjBvc^!9mW(=}`&F$)JQjpMV_G2tHx*&#si<_+V`nrq%)Shc5k0XmdI3Cq`d@M?U;V zX;cuSm+Q3xQtkUlwO7-h61NthEv~gOSzI{+>}!GAgZDgLVf+WfC2?8!D;$G=X$JP7p$(r(xJsywkH zEPj#c7hq2}o3QQ+=M!dMSR`P?sZenO-nc=GMRC~+n0-}Voh@ubKo_ZtIE9lX^xt% z{%S!v4V1e2DciX! z{tFOVwjpW?p;pv`|h;ce#M(|na7?P_%T`5{#{ z`WRbozA`|W4@#up6{!Bl6Rb=xL^D-HaALF_2>AR%f02Yru!R6^!72%R1WQ98&Gr|~ zJVaB&fNn8w03US(6(82`P4SVeZ`nR3NT~QI0BG}3L^xGGQ1~k`V#R$x@xHp6I35aE z2gUCGZ&_fhN9(0R!~obs!4?PT_#6cj?`JtTQLkLZ0{h2Bb)@3(-;pHx;qpt2sFIUvN+yI2{2t z^l9Jk;;=y6%K~wB1pW_t&{8t9Rzt#!MM}@7p}88brS!JqDK}R|@SI|ERRYpxnyUoZ z66Ea;@bw?f+XdjQtSR17Jqn_Nyrp&&L{;;=IeB*MjRA2r3`)J^_gnG{{6ESr@Y@(v zVv66Svy5`b0JG4HBOu+v-!ht@W+KE2}(OaCVp}BvAi1*&e=q*m?|9*J) ztWd20ib^_i%R2z@aQrUkyJpwf%8KXvsS&nFm7|<=|{otd7pyH#9U?V=7$W9d`RN1K-pv^}u;Z*rR|H9a$`xhAB ziydeqKL?Ej)sO*gaU@ioDO9>UbeX}XPg+b|2Qgeu~4vvFwmif!V zLQ^Wk{{IZM7?*^5f*l1PS14ajHT?+izm#3XBfUFr^c{E8rPN{iM>4R)Msc9*L8k4hCPh zD&AtdW02?!HBe;4E&{-l^qoJ2Gm$f%2PJQECHHS*ewoiie29Oh@jW!Y^?wf6>aPAU zgvvjMCoou5LmBYraQ-S8nLNLaGpHA#>fjTEk@KzF_UBN?;PszFhT(Jm9P$9eUjI21 z5c{wFIfw)q=MPh)JRtrB1N8;=-PI6$l_64|-Kha3GciW(Tgdd3G)Q{~z*LW;_Ehq~>*=TMf%DD|bY4o?T!K8-c%Aw;v znB&-ha0(fYn&T)YsOA>t5KLu`qnw1Qeyaj#*KcbHr&_<6_25IKAs{u!kxfwXkxwv{ zIgarpRD4VWX!9|LaH@Rh62aos{q}%33kGQsI26UH0^tBQ&jMTxxY^>w-}4LM@dfSq z&;DpalxL?;$=~fxFFGAyqTW6wasC@`Exl%+8GZv|?|+A4e-$#k<(KRy7w8l-d;)$` z%kYCi*-U|U8i~`v)nke?$L?+5ZSIuZCLlYnAQYp3U!m-*vG|GLb0R)S1V=Ah`y;`* zj{o~V68wP?97JXn7k|dole~`^MywMq&o~(dN-z?j5EsH!Kucf!B^%N}UOL93RaytQ z%4?c}gNH)&Qo@zgq@(yccpZF~t9Z5r2LNBJ>;k-*X`u=tsfUsB1x?H0ImHW_szJJ? z%<~ZV`oqKTIPlwc3C{9>flfl_U!pP!7gGWku>-Ims8KUg3~Jqs1P+O!HBb`DMPBs^ z*6Y8R3Zzg=!%SI*L;{xLe3&N?j!q4!;55XBqw7eP9uQ*90G!=3Fd%yG5*g8( zme|i{q6Kbe<#ki&8~9{S^+o!y>x^eSOlW+xA3M+*&3*;_lS%Miybx=HkM)HP(Lu3+ z$UNT{Fz}~XLAO$0`pT{tuLPXGSOkiyFo{n4GM_x^B4d&43K8R*xY+34~ikvp1k9xXkeI#yl^)Vi>t&bwWXe^{YN(ejpDAQEb$8y42 zAJxi-)W=%FS|8lvwAK26;P*lo8>x>jky2Y9e&ml{maUI3sgET_Bo%#R+yqXS8i6SC z!+63^8R@ShKNJDB^Fs;kpD|>9CMIkiQ7Q^gh6mUDgdfQmY$E;We|T zTQ{)JoH^Pj7ui?RZ7-i(WWSo6b_oURS7IiEFc;a&8bsV8sbme34cOLLKJ6!{8e}|R zTVq9psWH9n5yz&9KOoDP!BU>3kf#JBkjKu;vTQ@1RPypd#@dWLtLdiYsU;U$9&xKz zo@`*ClJevOw&fX5do529eb_YsVUIjDX+oR~St=>dk&#Dq{+t2p-X}OReMvoknp*iR zW6Yna@>xyzCsjVz0=BuUr~PlLd}frp+~pDWa90U7J||~5n*-cEtGPQ-ahFtjz+Eb( zrvNe7+?5d4+?4^gxvQYP=B^5`t-Bh+io0<4|KRvRnBD^oxwWtA0=KD^%eG zl@{n%ZBDaRKTliC*1^PserpdsVnUpUllAuCa>-QS6Zo+1ME^DH4;%#71YjORI05ir zz>4a9tp1uzs#gBMD}ajur*BRRehc4ag!k|VPTm_G8x7z5xDZuu07Bl$!Oh!q~k*zYOB5Fnxv_;j7;>MKuiJ z8_@lH3x@DxADZGP7{bqggu^*t2w(7-DOSJ`p1l^EZeR#^|I!r4!w~**y(xD4O2IFD zgPT!cXdn9y6B#gs-^Vxhy@D6v`>uxT@$L76vOfslYc>2RzI7Uo*O_8p7>08uzRNVc z8sEr|%D($g;0J~@SK#}ihBx5b^=E0Xj*80o0Gi<1wm$QWj3IZJ;&PZiU5$*Z@co7G z`9^pMb|^`j8;y*0HvEc_@f|d0`~4M~v*80jaQ$uuZ2LX5M#J!1X~T%O)f&fdxFxi1 z(`Q5Lc9R3Mp@gIS8q5hdCCxzz%cIuU-0^Y#4n0>B8YOiWoi74ao@3P==pyEd-5slQ zVKs9jthz}n)?&}XY7MQrODi^_(TkIqU^{RytQs(JC#)JU@dKg0$!^_Ku9ATkWITZWl&%8gND$A#c@`|FV(yIZH@#StyHn~I&|;IDQ>=9W)#j80 z!Bpm@2a`~ZhZh30e^^Thr#c>PzOx(Vf*8;(=G)+7IYGroHNi%FG%^3VmV}BA@wv-K zf^e#Qh>X+GZ0bfy_Tg`Y$`f<7Hs_h2g1G{Os3#2y2~LPIdHL|&^u~x{5-R4($dFzt zyPR;U%w_aL)9vML5u&@uloypRsG*d~?<)rzwNUKSxIH_aoS~D46Z7nCvy#O`{e_qbi227N*n?bQgp)pJ(bwsQAhF+T|yo@K*Ellgm#V z@G}{KXnv*j9u$wE#Xu-aq5}OD9B9SN#w@1_KY8B*GUxR(Bu1mZug1PQ|1C&4{nfm;#PCPaj%B`74QBq#>x zNHB-?jU-6U^G&5eIsNG(0MJf@wS>1>f{Y6>Ord^344JPUhBV=;obs_J%f|*p{G{9% znoUrb4}empOE|AZ`-#zSx~V=?)8*s3gOqE4X{I)Y7SW$B9{_Ec$_a0?OpY8Ux^hfp z`Cw#9jv9ixd;oOhu)b?bjt1qU2{{tb z$Nr4QGSxbbLp;m%~l9Mx!DM(xe=B&8DYj?j5?|zBh_3SgUF9{BhT)$mBKGWfJ%ZCoeE(XBGk$qe@7VxwQtx5-i1sHC5t)^J zOxR_e+Y%SjfiZnxS2uWG2Q=elIJe8diTY3K1J0y6^WZ!*q4H9vRq4B6CavaDLv(s0 zN>6+^bk^w&HE+wx>UNv@uPCYca4M+NCPnfE;O9@$0X~?t+OgAvsV(na{UI25FqP%K zwV-Tz!J4ePCxI6({&ZF=vO@Y_tooFyWM^mhleOf(IdKkQoWD6MO^JF}n(hXiD@{$g z)#@Wi{@ae-W+gIi&=b_1Uc~9gt@@f`ADB)<3`6C$_f%e6BJanywlph zgtx!_Yj~R?b4Zn6WcahE3@|(=MAPSd*g#7-&)NdXB8~a7=t9HGc$3`wq{BcsXiGYg3$V1{=Nh(Gtnjo&L!#1G8Gm4`gjD0~E<3YfMR z7~y#bnBsGowyTWT&-ji$5HPBZ*qZ>l9t7lVpAqvPf-9Y1+MWrQ;-gLREKJ*laJgbG zYDAc}D-9#OsT^dt0YQAimw{X(Bb23K9{5S`s7gcUtD-zglh2_rov#*>gjL10y1;a9 zmsC}BZkJkBk&OZaubcK!brrXoG;=>{J}8^6D!@9`Bx{T(5C9M1idx7AeAuYx-X}kT z(>xu9;6|mDkd&u8=3Ziick8EN%oTnM_<;9ezgRUFpTNU8S_iq`M0y}#KCF^+zl}b8 zutM2a&z%z;tXx0|RM&S1$PEOzC9%@*#bV$cA&clqz`Cj}_%hoo}e#=cW9CdSDf=AsF zb=57kKSP9U^-J6^l5rn6k;nEGL1TzoYOjQFmf>hmr;JECvMu*;LuE9qofR()!wpP4 z059N-YAs0gH3TgOl}*k9j?<2cM2%WGjKKol+9;2OfGOL zpHFAvZH-3hpbwtqT96V1Bb9t1uH--*GE2Xx<2fG$?}9*DUSot>K?pwQz~q+c#Y;Ze zosG&!hO)+xhsI@G1|dH-9CgTa`NYL#M*mdN=8<+?1GmqWTLIlLo-J!Vviq(b(f3CD zrb5kbv7w3}T7OZm>zLe2lIob;OH!+2#-rwdSG$fGgeaS-V~U!sV`P1|0X`2nMQdfA z(?Oshx$~S30@0>A2>)-RSLK9l#BXEJh4b#NO!bU{5~f^AXB3qEbINT>6XH=j;0bC59q~*CCo5!6bIGP{&K42Z>lBo0Z+{(Fzfnbn*LhR+ihh4bxR$eMU=Medf4{%ocFO&01G93VfM2@MpY%TmGCM zk^FHWF7<*<`1T@gU2+$S-?&Twa^#BH@-8*Ekp^`m7P2dLu5sf{A{B zELGtW#SQ{e4ih~OgIAdsy@XLJBl|PR)tZB*1~vp_FEGiPyZ$~?d<+vUVpI`aC5_B65kVzqj#FXdWR8m!;$#l@=4nsnpe54Jaf@Xm z?89NCQV;nYcc{Tg5IcgB@eMX4kBTaRb0$_~N#d&38 z_K_1B>f}<`I69fH5GU8wCTU;iI$A;}j$5n-Vdr5;D>@gsuJ8~KQc~(cHr#{@B^QH? z`5_l9i&-!;^RWLNCi+8~yn8({69YbVxZiHt6qBi#F|i@X{b1v8JVqf-D!R9nds2~> z;Mj4CosF=cfgvlgkC7e;W*!!r{s68Zf>ezC^^z$HUREw5^Q0prL$|pM?atA5nTcQa z@>J7+C;N7Fk?G+{4T9!4Zn5(a{4+4j!?ClcnW7SgJc-Od%4E!K_im_)Jz?XhVn2mA zs@Sl^TXb}7M@y)}af|JCttqC#M9;-ILFRkc$(Uv}imAdI)8h?daxZ@O2uMrBDpQ|zfQC2qEr zGvgeuxY?GhDQIbV++q(P@Lyq~BdFM6OH7erWuM(Bs)b2W-R+Gk!^$C7Zl#o=qLQq7 z++uqn@G=;wSquR`hYIizyfTl$tNAv4>e<+ub0S{1!{jeE!ats8if$zmM)P-i$R0^P z2hgPT7%N?E#CFBzm8meTFftSy@t!H>!nA6GG2%(@dt6TW(1YY-1Bl~i!SsBn4&hSl4>{D8B3l3>vlubuJ#82KLZjTpxo{Vhop!kN8%-Xyy#xe zojnQwb7%MCBicVmBsP2xQ(Oa+Hw)}nqXu!1uV#3VA1?DCi)VU}^|L(4{L4Ma9>c5HvCZVQHQI2jsfsKkw1X^1)%sag+Q3%SD>GB@XCA(uL3LUe0)^S z&AQMAt*m*_pq%6wEGIX1-49taBWs>bke_uOKuNGiR=cPCq6)_{p-(gsbZ^2%WX{1m zVP#!n`w&?(Y|zT${iZU`jI3F@T8HU!NZ-VzPTSkIYT*(ybRy5|A49zI1tQV zWi!8bvLg3REjdfc{NAY~=fY+cDgRX1Yg%vfa)J93o`C&e;9Kl9IiZZvd#ndv)gTn$ zTMQ+`m!=bQcO(1|;4D85lPNI5f8xvI;{k&sUp9(%=Jl`1{|{c#T!{raXeXVHuKb_F z)j8r3oYnFTjLG9F;1Q<3g{yL5JXYx;#0ulFx&r9RWUEa;`-YRK<^p{t+3IJYd66Wl zkwDK)wz?PST4^PVckGC_a6>YTc~8KIU5LK1MD|2InfSynj)yUCz=@R;Yc-N>8nL0@ z<7Q$Q>1Q5*cZrbf65J&ADvZehIvS=TBXSB5NyY#^AC5h$FlGXgeu+!nurFTu*$2S& zL`W9D$`nV!$k0v(@Gud&?02^*ZiJC8OE;;bHO)m4T+?d=gyn-45UGf@?15e@jQI^( zqtO5^B61p<+1qUvhKJDMpN9odI@I&G10LRz95270T${2 zgHPxHIqS=#V?vWyit)6D2{OQgBPzh)R|s&%IV!-Q3UK3x2(TWn*k5?%;-HQeJ)n_Z ze*6i-v>1-=V=N!m(&>;i!#59zVqpQG-|6ECbgHxPkHo-QJO`v*onKrE(_#gX*$8I? z!>R=GWK<1Ev^XBfZun7J0@I>CO#F*^Kob7OK%FlCgmw==V%W5xWSlWiTx^ zKok2TKpALHL>I9G1tMa{*h(4;wXjKy`IhO>y6WK;o+8>)54W`F>Q+CLjJRF>G&dpT z{44&?Jb)1&r-t2h4Nt?bEv<0%a=5UsnmHysv!4r(y4e(W!(_Z=gkQtA?=1@6c#lKF zkRR`kZtY6E!f)VZp^SAnNB-Mj(Gc8AF|I||4kx7lg}M0bOAXPXI7*OD5T--1%4|N) zg@)fo06qWX7adAkiKGTY6Jbht0TpI1I zQFcvYbx=iBFKFRayrck^YXMG#a~T4mYlm5pu=d5Kp~K}N`(|w^K(1l6($1Vvk99Gk zxq3~8#K(f+DPXvW3|}7fLD~|VVFn=Q7Q!7=Yu2F*EG>pQW94|g1hd=8DC)j}`AD!~ zc*REHRRWXP7&I~$1Hihs0Z;nHizjnnC$*zeq(BmSqz0E~DC+Ij5=Z6A4Frr-s zE)vs2^5UHe!1l#ERfKu*j`g}u8Oj05&@wN6qOI_1xDGyE@t;`fbgfu45-Yb@l>UF6 zUQG>s3uXM<*1_q1tL;h5sH&_aiv6L#s4W|R2ki}S60=qz0gC<3Zrp4TG(K&U3$PQQ zY;@YDTu?ihE@}bgWP**B&6?bNIgL*0l+99tYUATVf~jo5Tuwr@!hAJAdxd!&Vb2P4 zHVHU_s_Cod`G-L`2>MYu99gagFBnemBO+Krjl^^ zBvcBU4A53sG2v7dCXYugV?g=}ID(3gDuSsbTnz~oAN2rjKC)MD1s^)$rXt}EJVDns zC~4Dl!pS-cC2fKiXTtg0;?D;Wc@wVbeec|IIvJEuI4{|mMo?`$EhX4!yC=8f^Wmv9 z`clS)BvgV{0<;CKA)K z@JBrgzuv20DEwS6PKEae`{jse%L?Zu7M0{wDSS0SrSMvUjRb8%;o@ya&;&qR&;r7# z3MwzLC}KcL;UxqWA7um^@zI3BD@dpmUJcOZqn2>0d}xIqhFq03&CTJ@c@+$W-{Hln zaGq>$y_1TRVoLWuoW1U8Sy0iea zl~zI6qqG(f+QCJ&}xRPE(2XlQ1M?+Q1PGffrtM*AdUG?PUWWf zFQ7lge-S{N|5C!+%)c&nOyFBR34D+@K~d}md2uH2$4Itv#JuGMt_5W!Syu_XnxIlp zEkUIqQR7iiHju^&+HwNt)1Ok%WPrAUiV1JCg5-6FWeiy*a0Nlde-%N+e+@tP&h^_3g5xun=o=XVHp5D zobdE1ayVfHY~*kP??}mf<^#uF4>!CF8^=9%?iy3v2O|Sp1;FQ%V-sr-m`}t$fQ?H$ z^J7yy0V9b&0-%Y1QN-(E;}Q?WQF_HNlK5Hxm|*9qN9|6ysHSdBR3F))oY)|$lQ2n>d5g-kl>42#m}hhN zQIh~qt1L*jnKv;D=J2E3UQ;=aZdF*a12=w@+odXl(QOj~!+a4x%IzAJpXkOT*Wt#G za@&l98j%U;7QK~uDTg2Bwn1eOx~a)(&$@-y_9nyoae*oc{=Z# zK4unn!qWLLWUgBHHaP&}olMjRf3i&z;uXr(DD`9#*_<(o-25V+G>?ya)JptUB0K2zcyH>ytqun5%Ts2C+J)t|t)6sCen*_V6Sr!sJ z4E#^pUEtc869Zy@n4Ue<7D&<^3496dKE<>_d@6Wthu4uXJuyusOYTu1TMm*xNcNLI zaMhVOVQ;x1dj9M;qtC+)aIewG2sly@U?gE!`vT^}fv`wv$jUkZO0n?;ZWopAx{DfJ zgkbq_V5HX=eVYa2UISTWq-z;z(3FwZyOCx*_}`0E_=!j5zWoB>&Xy*{V#taay zCA`24O#uy`G#JE0Q09trVSNbVxruRQHi#>$>A1v0Zd^r#bzD`1n~n=*>EFkorFtAM zZsx^j%wpDdS$6__aS1>x{4&6FWZ7OLv10Qi0QV4?Xmo$N!W8u;7Jq@@7tmUw2fg`F zQ5xAsj|br_gAhiKM*v@mir%RA_jnAjjKwl~JYmyh7+onmmZXZd$QClb9$@clWS9E!sQy6el5%xlwINWHh2f_>49 z1p}%XlNG`gNZ??io5k+mmiP*k}xCF#WAVP;? zr6wQNatKny^CTSp)Wu#^2op;KFQ4F2F%E~Jj~c}Z38pH$6OJ+2ib$I zO5eMXBV=Z{0z92sg3R!^&I}`9(f1f%VBTmPLrjM5FoKr?o&z|oPgn$AL=u-P2df4W z@L`eXA^LU(A&xkl97J4ZkcN6X26__6qIdiVrjFKnB2R0eBWZb(FF^h(8RN;mCfQu= zVYAlDrnq17|6gHKHH`DY+5uy65d}=&GZbstjO9#UfEpZ3SZi;xid|}N8em6zrOM&I z!xHuS!`q=oELF7_fGPYd1tF#tTBVESe^z}q&! zJGgj9(sxWl#fXR!K*WbWoZgL?TcRrOyV4h`#9|6Q95n5_*%x|I<7^6n2a2iyp!Mr( zrO7*{vH_z74vvF;K4D(3;rL=x)HgjXNdCvuS5(18gwvRnalFR^=xAi|<*cwJn|GqW zL@xUu?zA8YSoc4|X+elK`5!G?A%?Np4&$}tFkats81U_DV>2Z?at!c@Ns6ffM;T5U zBw#L*{#> z()^b<+x*Kk`vRf1uF#r3ICswrp?ZY?#j3X z><0k1SH=-=YLVXXYD;zxbh(2{8JWLw`IdFJ`|wvYLmWaf8pp6|PCyRuDPGV?n)&zEf< z^Hwmad$0qUXP*Cl`Vevb#YE8EoXH0D{`+_-(rXIML{dqBk1QU%k_qXCw8^_Ay_()0k(T-|Nxs$~Gdj zGxPji+sAx%GV?n)&-+(wm*(?#8uQHa$7~<-<97!07?>A5xumMs-*{mSK=0#L_(jm4 zenZ3(T6mGRqUQlva;U=IUt~UtLutH6)d_j=iCl%QEKf%st$S8(j z&8Ck0=1Mz?%t6?U(QMe#-x;pIC$F{r$ymGNj3!C4z$F=tWs4rU?sr|dn$zP_?YeYI zcKO_O;pv$kKYzI{U9iT-d1XqRMPmxQUX$tF48B{{<-S=$vG=AY5*&UHx^ zxFk&FgKd)gT$0CJ67JVH1|+?Y#4G5NvcKes@Xy*qxze=SGb)8Q5uf znU)N!6YR7KdbyNSQ5tWv0~_a(?C+Ay9W2D>Hpz)D$=NQ+MF2y%%c*w&ub@h}>s-oP zJd~qwO&N$JODkNGXI&EBc{al)S>uv?>5}m3r&^ojFP9{UbzNEoy#HxZm5yjP*lXFl zxg@+_>J*z~luNRYOY#>;uD3~!b4iL_l9mGv@s3S0$0fPWB?*r;#P2rAy)MZLm!#u3 z><$axv=HYiyGA z+Z|q70o0+agbtV3B)wgdp)Sd2fa^ihe-eOd03DykOQ?q87}v|Gu9sa=u+v`D63%i- z%3P8~023g|%*IP6!DFy%kf5ye((RDmbVK^k4T-h;?l#F!F3BdBq!3m1kv2)z9gZRr z0JS2n07)DNYRg0!?2?RjNwQ|+3?!T6Fqh*d>|klDvbJjB{*~+gy_S zT#_-6=ysdr1()Pamt+-M<@aoouU(Q4oK{x~V%+J-dRB6S*4B0D0#Iw=8w5M)Wvzuh zU6Khd$=P7;W}D<_m*fkKBs@6Q!hwP^ zqJvzLqg@gn;X2YLIo~Cj>5{C&mW11ElEp5`QkUd5Gz9P2Br9E#S6vcref$w5y}!rH zRK@TcmvW;^$qkLalkyi*s?K8^+iJ85Isnuv=nBw>Qw@9b)I`6c9PUz%cPaM=7$GH( zL-bpoesiAa&pPQLoLeb@CvD(m9AGIsL^FN>P~BaK|KK!A2}Cxb2KWOnT?5QT=*cyJ z?4k}*z2(e@uo*~Ge$j}sKf5+dLD8Sp`zK{s7f&12=Sm1qw|i}x=-(Q9iXOpXm6`YA zijrT0@b&018h}IZgDwvla(d`o(^i@Ho0}!+0BA9>dOdaTMMyd!~sc`0^wCU_#w)EJuYJx%Et)V?YGhUhg#WybK|yC@l!5e^0;{w_yiNq6ue~Nb z3Kr%H5YpK<0d%(k2rR|xT+pR;H!3)R2I|d^!!_-RfFOX= z8int}CjpS#-WaBNsZ&tU!e3yOBRD>E^N+HYX%tH~g@2s2N~09ie}IMZEFbB5c<9vg z6xsqG|0Urf4{A*|!W*<_I$H}uk5PuUTU!oS=oL`aKB+oT91osuGqbW4gMvY!(ye+MI{IVfX^Oh+WoAx!x) zUjx+oX>4~x4^7HB6z|IrElJXQB}JRwCw)G&Py^P}FK}F_{PaDN(Q!gj){}B^1E*wk z4@H^X9+X!$a7sqUVS|cCTj}>gj@YwEuU2>w$Os_4X1}Dis{h8h|qygFBm$8>By%eOf_l@DPm~;praS zI@t&Zy!fI}vh%(z(07iz5GRs#JUJz=*>|P64Wz^^{;M3{= zFYS!zSMZVtIDVfJY&_r=Xx~Mc*^Ccah~m0SulA7FA_vOB0uFk>J=X}|MnXLF7VU0? z7kF@%poAAk35t7g#aMC>`P&ji^k;-Rjj|0fEIU1@trnk(@RObxqZ5qq{T`g!9_q!R z?VcW7X*)THN!t>H)P5;BJX~qNTxp*U z%-&6BMrNmcAkk??lv!y!Uu5a^l`plej0mOFT!Lt$mp00bPP(vy$0a6C(#i_ole7}|BrS1WkeEBlsJz)m zlsTh9E04LNN-K{!qQ+I8ouOo`Gq)vHN3i?I_`F7f$=p&$uC7tJB_pBAD)T`;U^};r zCoFRdOLq~l==I7+sqzv18@!j3YKhVEb@;9%JXSb4iW@Ew8VYn$t%U0U06L5btEm;7}Hh2-({Qz`}4*_s9O!v$DG`2#Hb z0_py>Va~?)O~M-u-#UEFukj+#vo~VN+Z8rF@gmS`H`ts)n=|kt(3_3ia@thlMIhgT z%_iEUwF(LXeReg>F@R^l^r7o40Opl=5$HP>Hm}p>ExZWyBTWYSeCDor5$JEi=3v?! zh8KYW-C@%QeL`~}UIYfx*EzH~A1?xfdctM}ZJxr5z~Di!*+iSPHsB4w5Xv|Ph&cf- z0z=!u=5^Ys2{ymb<`29GjOYNHA?;u@5-$P; z?7&@4n=A1mFtQ_T7PW`Xt#}a_-4-@$Y4a6c1jaDrt{q_03oim=+r#Dz+MI(IfpORk z?|XnEkWIjyy4TkS7e9e3CBCrqj`3-G;z>C1XaoFUezi$r2i@<)=!*8_t z3oinb*^M8T1Dla}5!jz8{w!@?#A`o4eivF8riIQuEvNK1%&~xfSrrgdazHr)h&dZC z0{?;(a=W*96Wv3W9h$7o>35=YT{z4qy2YKY9Jg)djkT7u+l^-~Ox~f^a~fr%n0K5* zOxwH@k~%IxZNFF2^`vCKMdyn5_wZP4gkqK7;GFw(WiaV29tj!9yy$I&5^{VY5Ym>wrNF)_sMza+`ny&iV_ zb&y>%{#?;yZDs{8)T$*#xgs4@^0Yb=_q&7q-M{Qtm(k3gDXOZ^MC&9S z-4LP^S`sZlFnz{5a#Klt+G;`L$Xu*gX%Op$ATLagm1^oc&hahLGaV)vTi=<^KO=t< z`yQ*qeisO! zLY-s7tNqW)e&T@s)=l{EnG78b7?w_SIT#r*){%-jNgEMbN-8`&K_YFc3 zHJx^%NTx2@0yX@|B7llswm@u!pp+LN$LeIIkZfSsiH%Ab7*Ephz#clVOCdcQFB&N2 zeXW$kla<2KIH;FZt6j^84slRc2ZP2q=q#e+tUomISwzP=C@+Q|w3m+kLa@e0kOr}* zQ%!jGhc%MKhw&mlU15fHbol2fQA4{~9W?RYMEg1DenfjFqXkyJmw0e8IyQY2Tx+4i zp_8qaI!>n0o`Xd)<-lZgbaE_H98|J&fI~cqEd9$tClEc*Q;a#LLZgduHxwwg=rl;* z1HfFya9K&&3SkKvk>eO3~M}8 z@u-*imf0FTEZHStw*;(Q0al8V#b)g_x`UG~STsiuapa^HMvrq`G36pgPjOr&@c}xj z4Ty?;9U4Tn7*Wk>EcKW!j$D*_%os;5Nq+wbfQ_YpbpGs7I?kq}Eov=}7aJC!`0N zy@AX|$jmgC5y10`jMSyn^B{?tF&=`4^hbJ-`aeiL(@P4ao?m1*oKny4sZt*eNk+OR zJrFS=Y90J0c?BHZ^K{raQ$AJZuzDl2){r-Byc@_n-*`#D9k#%Tzw^j@nDLS{JZzyi z=LSXFS0U#}>!k;@^;fh-GR5BlNBj|O3moxB@@_$c5iSeJJKiIS793_m7gFd9;5l%SCt4!_FL?>;1 z;k=yDskxx6n&_PS%$(5)Q;I&7(&0zMEu7>vnH;d)$&Twb-pP)#&qA!uj)^_MpPhk% zQ~%w`orx`Xa?cJ$sqUbR`^tcq_|yEQiE=`^{-8Xu@N6e*O6wwA!=@XJDS_!o7sZsk zF3N8LV2dfMOT5LDR67`wVzTfuZ@3#nl4%Q<`NC;_!IGs6MbRvh9&q1bpsXDQx>OI! zf6;=_v8u_aCX2onio05H(Z#0IP=hY|hmnXRh8F$Xgi`Y_`j6N9VW}R{Nw6=<3zWL` zk45?2HMtKEJ3K*;8{p3Hx+x%c3Rn|-tN~?nOpe)$W#JOCSL5(H@c`G~vOJ1`H zrS{HCneme#&%@Zj^`I@>WNM%Xd2a^C+$!_dY)<`kaiM1=YjK$;v&9gzoY~)zHCZX> zL1q^tvlqOC_CaPx7KH{XO^YZyvfKmtktDPCH+Ucx0%d2Q~gBGGECxHe?XLFP&t(RK=yodvaTPf*Ha&^cY0R zdk2h@w;g|ao)2cM!~$_3(CY*EMXyirH_$5&ukw18;BS8LnEw`vZFq)O1%li0|71}l zhE~w-f}Mq8I-a350dDPe$hzl@B7Q(_pCM3IC+CTw8$*@D5QHB^8#+Fez*;8#2=bv5 zLoaS*AM4dar-b^PBE3|%q0>WSl$WII(7Bz&oPEuZ~+t5Qor@Ot&MCjAOGB0BB zp&Ma-1O0DOU5=9^*W!JDkW3F0nV*4V`t65j=xK&*62?PMG-NX+tzNPd-q1Famg@*) z7$H)?YEcwD3ZWf@&=wP&gv95HP_e2qBeX>XXQFjCQ46a^rH(lo@tO})GT79~-$5Oci zQKqll5OSjdNQ}Vq36)E4=;tn%NU5iCwKN9??s7S9M!6!d1YmKme;)DwHm!)C-aA9z zSPDOW)YXS9@YH6=f{HDtW5Au5hY)r?%+6v0g?_{FAdL?mSqx>n1I5teFJ`f~n8jsO z+ZQPB#r`_W%w9)k1=EZ8L1wqQX+GW{LF3wx<14-fnzvJC(ixgWPD3*Z(;>%ar}yBdR@fUNVx0n;Tm}<&fI_ufVHCfEg>^0ej_8Exm>FK?*;y%=*g`&4ttOePdrSoby zuW+2-W2dRXXsSWGsX;!xU`h!TouC1<)AA$bsye6k@~@v|fuvv_eZ@}vh6idbPYr9Q)u zp`x22sV@yVL#BQL?!`z+52(_ef?45QZlfzGGwHmCon^$nPqH&RMbtx%M}GA9^Sp@j ze3ep5=MHuj6WR0|fM>`>e$pkabd0qXdD4S?sln+-vS`TV71R{nG5jj$ICdHYX1<)Ap_g0cYD2FlUsCwaMV|B^U#&LL*fiu1p>Mn7 z-jF}Y8s31QixHb1e~MQ_=eR`UkXL02ECY&fAT~W<*ogpPGg0`ax41WDY#M8CMofB; zzaH~RHyiSfm!fwZita&ddi*Kg^-}b%Oi>Gp9z<+<6h&7MMeloydtb)B2t_}JnDqE- z{9)(-ca1-kDZY*r&mlHF{uDbyJ=`gF$`o{`=*x&rPw$17A8a=T|&3;Csr+H6Jt?5!AlDwYCBfODEdLxev4Oazm&Z9zy zxYWv;F(#CAcD$s6*Gw^0B5k1NAaBkG88SF@p^41(Ur|ho2mMHAsaa(NBZazD5K3E} zp$d2tpU}0$rizSwOXw7(W|Q_%lQ3QmjT>EvYn%#AQfP6VIznqyT5g9825Ao6P(e9w zBwko=TAM@Go7N^Twe~D`Yp)Nzpu9}dR}FI92wRPp^Sa2;z}|}u4Gi>Xo5l`PSbSv*cLp^W5oQ$vRCAa6kjnJRGTLKB(c zSW!%K3;NMa1foSNRK8gTMb08xJc&=}T4GaUC0agF;(_L;5G~r9U9_xHt;BWe2)(Y- zGNWxUz;oz^3d*W`Jy>JCX?zY@ZyKMx)c7s##$O-Wu2_W|VSQ+rDuom{T#2ns4jj7G zn|7-S<&rKk6teeXLm@Z9#a^;b%OFd)KF2;Iq$|%%cy{Py#W_4Eom>2gBAQyT<{VF( zR6!1D4rWfe(#tDXRuGUQ2&(H%L@xAt25}~ZZ1YmPErVJQh}*m%ZZkkIpWkj^Vi0c+ zec3CeLd#GI{1~-64Nq|7JH3(bGR>o87`4_)A{atTH5_O29aCraemC@n0*uq$Y}!!? zEzMe7=5iBR$uJ$t*e^4oobxhoxr2;cszQxOq{%INdHL5UsQ`UVu6#J#45ihO$ZfLN>s@Yi8?Jo1tP*0Pib_eB zwkjScNUN|L!{|Ls&^j|`Bqpxi==bWzxb_@FBBwpa zkjMpH7dlsU9!`6$p-P4tmLsWByVbB9d5Pt;!HvPVI5b9)MRWPuubaF$@ePKlxan^- znjM#PTLooRPf*?C<&isB=UYr6cN(7NG=31w>P%nX6c+s_-ipHcF--ow11 z!%Qf*V~q*ra%)UC<#J&V3BFqnOIJ6ihZli_^U%BLf#@op3PA9C86Cg&heq6z&_FNO zg8-8~+zeu>muodp_j0!yh+eJ}Gvs58O2utG!3>pLjfqA)aW%Ya5w(-Ok*9bgJDOc3 z5#3-0BPM#9Ny~z3hBxgDqZM+6=XfI@>WzG;iOfVUGdcyQUFFdVAp^Rk6`H&ljz}3P zi7iqFZPWlJeVrMD8L|zg({fW~ba>sa z9D2HeTY2ZHj>e6V(f{3=6#Bn5-ZP-^sdJaQ$t*L^HYd(nLWt^8H`<715)5_Y zjcC?#!fkp&upU5&HR~oBSxo#?S8qlPs(Ia1Bi1=|syFgtf;z1h_&ht@fPBExpoW9a7`k%F5(&b>v9g+)E1fD)#SysTgyZLOd_epKlJ<7$P9^` zaJi{CjjMI5OemwYs)EeWD=FKQ;Yp$gUTvP?i1(O|PxGL1Jjj{K-M?ZY9h&2SCR zDV_+fr62Y5x^s#jRSOF2tttJk%iHH$U{G)JFB>n%Ki8Yvxn0cdJa2C2dviO#i@ANp z^ed+A64vP2sg&;BnV>6~RqEDl z>abZ(OJGuNAVEv@2*NCi&2xI7V+^r*&OOrA!S9KW1M!~t6~6fJYjXx8*E3K-{&QJ) znWQX>t9(h}*GXA643$Z@$)wsULL*z<#6XGLHdTlHqB(RA!YosmmFnEM&Qk;Bl-u{H zpoWZ`eB#W&!>uvgfrAMf?W@!1Ksl*7&r;SG23XJ84mUBn;e5{Mq=4}=i>17aG<68q zdIHBkIZ&$gBnI=sfTve%ry`skw@)jSV-|`Vkex-MC`QLT&C(~ga{MvZKQWO5T ziqGXe5GZ-vEk+**n6)noha5GH&-8!aS3dljPdUHuIOVhd+YTRcdiXukb6ubt`McxP zTV0!j9jC=f@juN15%_W4P7D;kq=YH^-!FZ}j7~@3_ ze{jE_6X-_#H-g$@ZlKhyP-gfK36$z>Hk{YofLG-0^k|%QpLjz*F*+p+@{hftADd7n z>mw7&E&q{M)P4XC$@>!ob?|Nc8G-Yv!_~^>tq8dh!kQjTMK3*+m`R9R@C;vIMuST7 zI`dqjXLyZKF{$N;*O~#1yfpiF>oo}0y^81?KC<{^S0fBRAViyC=tpf*wMiKDpJR_Q zE2R`Xe6*Q5P!AqH#biw#X!s11HOau?2brwNOIhm`3mR62&or^Ag@(^GvB^uZ^`O9n z%=8u&Hj8Hr!E~cAG6d&|3Q9Z^oHBflx0pE@#ptn#shDF%Wn#(Uv%RIx#ygRBIgFGf zAhEF&n+j@+_^B-BS0~|B9bVB>*@s_^!mBax(o;E_U(La*1L38oath8&BS*QZ?PIw9 zjHl|Oe7K-cfRJ8^wuZFqupLnW%6{vjemxbatc&ge1mD8Uo6qn$sdLdAG#j{TQ zf5AtA&83BTmL@BOm#{(hHx<*QEq_r2!Czxhv2 z{I^~&6ffebN(U;>dBcfw*PG7!!{2h=PychF_&T1dvjUZq{^GbleA~(MzP~zYSNzS1 zv*Yhh-H-T(Q{Ow`R#-9G)Js3vAIJPYL^+p|WlmJ%p>1s(PTY9Z0Y&0Fc&ff*UOhtI zQFxlns~UJW(W@59Q;=2uOYq7DtGE%uX~%es#HYzkdbBKc_F+(}A5<1bT5qn}QhdXS z_#Z#&GgVtcGuN|EdY7vWew6k$O8c5S?b+V6XJ@1}l)eVC))#})6ZjR0jr!4^`p~Nj z@yb;n>N{`Ym1H{4bO?hj^?05~JVJDRtmq<5pz0(ia1#Y;(aV7yayngth_lAv2*|(D z3L8T|0$B8;Ziddzcpd=vHxNbP`4pmbpWxs*9Kp0cVOAwzm?S*6ufhNL<-n7(rnDa+ zYsqV&7gXt-!`a>(GEwCmND3_PtbpE@tZ0K){xID)qCB@+h-m`3Byhazl}6L z&ZEtVrlrcpWpG{#Uimoh$9N@MikpEr@B7e=DhkjHBU~8KaB&S`^c&Sav{Vj^?miL! zjo%U>R+Dvq~CWKC(@gANdZg0aYS54^EV|eAN3Gv)=DpYU%VxDnv z+k6V#l!MzYqQIZJ0~NQ?Xft)EMotU9k$PfQqf!)>$z_7$XY zaT}SpX#=U@#y=z6CFiKDIg>nXM6bSqS1!3Q1+U)6D}_`Yh*{}E>L>(9fKj6#7q1-<2Oq8BBkpM=&zu3XM59SV#D>IKT8kv@LE5-`W9Zfc#U4=PxjP*2(Bf1mY^QbQh<_cgAniw3J8JF?G&K63_VahfDENftC$I3LfBTU zIczb4drdL8Ekf`J3RdF-ZB-mk*{();^C)0Taj0|Lm^Ub064^@bsyGJOwovM`y{R+N zWDjFH(cA zd37dUNgah>5f#73E2*CFE6RWB)FSZ_w%=F%n_tnNtG%x%)=uv$l7lBScoI_fKk>ez zD%W9?xhs3h>pb&{#os`@qGdrd&0;+ivudvOIE2#T9(#_1hnCbh9kC5f$ayAyE;WQs zGYKKIAi!x_;2|@7gu%k)8zXD*% z8U-qcV5pbFeV}qP+_G^4l~-b;fQr-iYh^{^FL(KfxCK`4*nO!9eiA zpBIWx@$~H;2<~{QP#p9$+@*+qKgIkZ{_Lcf0|LR~pB0M3@Q^!%nDg=U9UKTAjuaPC zD%{Y~Hv|=V5uV<)fdKJ?pl&`Ln)Mbucv<#0puQEiZ}nYX_5(O?CFkn0i{N~ioCC{f zBz=LLg*={ahZB9YSQ{URSNawi+XHzaGE6YBN#9}<%v{rkcbF+G1MR`1@#jja#K=If z6xCipRUa8(?NQ7?v4XxULw!7)X-)Z-B7<>m-m@fVgw1>?R2$IVEuqlT!gnP6Z^KdxN;c6mg_J^u@5< zcPaSb3OuICMAow=^ABia<+_L!&LBy{DkY6cK{(=Gb3aV(L>=lsnJ#x-s zP@W~H1m!Q}l%R-OI3*}maQ@GO;$`B46%)?{3af?jDnv8 zdj0!UP|&Lc|DGmq7WJU>1uQqvPX+63>5|S}6jc#`dbES;US(FAIGWeVxWa56;`)_&LrYCt7NbsROTFIc^K#k}Lx=PlI>?JQ1bbEf3Y^sse^%h>UmXbE z3uDu}c*uPzj7-nrfm?Ff(@1gq&u15H*OT5k?rlk(bsY8lxSW)cZADrmps32;Ia-`@E= zuYyi)Z{$>JSLCb6Z9XbR4=Q##Dz=rvn?qkw6|1E3h8Zt)P*m)0cTL8H9&&rfhyLlU zm_AypDyDN*71Jk;NqI)aX!`oFtQbvVUzHWx#RRs3GTEUj#tQCBC~RH?mv5g>Z8aQK zT31H%q!Hw-;n~tmIH^P5t7_U`)>M1B;v+*pb60I##c$zVNqLN~_!PBlm(Cv}i*w0& zpvjFHqCWJr%AEGWqINWO+C~v)@C52vICnjP3KhF)m{CD_?%+(InLhz(NKfybQjzRH zK}*q^mr;vCk(|65ERXvp`X|fwI|ic&IgdAs0o(>Xi)Vl=`q9`8NvKzpcxXRK6q7lF zek=m|7{i8^G<_6#+`g6G*nK;X-Mg6VDD>mReT+qgyiiyTq1?^88$y*((}ZeDXrB-L zRIqzxrhnzGiqh+doVb@+QeeV*8A3R;+)GHgK`bjF5%EKAhW(!`QL-dy~jcNqQz567SL@eIVobQl&XR^uV};J+4% zWAMN&r}+&iC(#TkxPK$=FhtPLD;||&zLl@yqHYk^rNmnu-q8MSrT-Jva=}| zR}c>DUO@{4)o=oiT`UfmGC0#7X53R=_oz6q%u7L;p8{pSm<}>tSc{5HZbbVKL9@-6 zq$=hflTb0Ty3&t23M!`UuiS4?F|t1|mK7r_bi1tBE-cVy+*38tgpz<8SnX}3>dZzWH9<_mvl!IT0}6YB!WW3F zN!FUccp^8G?-W*z;iFW000W3WblX1SyJ>Fcq`KTSGqX)IS7~O0H>M`(yvdwVL zBU<~2x6}nUlXEY0!EKa}?1B%&`FVFiQ9-Kf3q-`kVp>_FALBmJtg(@o1zqJb zAV&`YeH{J|#_)%Mjw&b@ATEW_11PTrXxl0CXxZE7xfeQp z3+2C>fvR>9wwCG*mb8D6(lsa5fKwTn$y6Ee$5HW zUK1FQ9zC?*1>lZG@A?MyFerP&Vla_VUae&ZgWX;w=R7kiv*;^g6*e>)A?0PXKv2z2 zUM8rA6QYO*y~XspI}duB>GiG$JyMNtrBppwHGWt+>Fo>TEaTF)vy)2;jp5Qzh02d0 z*yz#qx*0ETN1gtz>h&?|RgLHa+sg(=q1co2m@-<2X(wk5uf}Yn{C2q-!_|M1QVnA= zUzJWGa|b!Anau9^degvaCUXRwET6&RuVHsUUktW1G~b3D0k7bpp*bI``gz6p6YPdR zi|`D>aD3#ug<>lnxTVNgjB0(1D$xTzfBZzq3FJQLP&2uuCK}YuOnphI8PwflR2Wpj zXQfwCx^8B2PP{m%!tDMfJrfaW7T+!-YD)-5EHUW{DPl>8BGQi*Lk5*#D7u~MayS0` zgX+>BpG??ZD87UTZdsRO5j8jxTZHhSE*Gss|DmFe4AD9Z{bngnD5CDTBxBPhtzTnpOqo{qB5>ht;rljia|q6jvQLeIsS#xIU!616w17Ov_vq3 zKZjD2jDwzq>Wsv~INVP2RG>Qaph``xC}SKlTV)!6Gn>j)s-lnv(^5?MG)8CdUb8d?RO^(W|n}%z6Ao|MHAfF!e6`twBG$^*gc3(Ukf9Q88o0Q7_UQeL%yYm^>jpVFg=T>rdGdq`<-U@S)gXXcs5~A;WD0DI~GY0H-yzK|9 zjwifo1I0uI{ifj=bfTe$y$(I>mGs=|(DSfE&kMUpkEr|_h@nR#(TH*%i35r8_(MM| zB8x#Aimw50(vQ8%&2)?ASA%L9g6&jftrvn?qfpY!Yfzo>av!ZW-f{}18B5FLq95eL1K0B$k-p&xV5 z8O80?0kn6u7qcwrUiO9H3GhXH-aIokbM&V}?0eba|IO!39REQl<#7RUA z{g_w2WawhALl=9q(pCSN=z@?q;JrdQbGj3y{|RK7J$lqF2H$49LFskx6-B7_Qhyoz zv}dQ&;BSh`ambw>0N))k#JBPErYh63vy94H49W-p-W0PJN|mzhVH7n4#n7XQYN4Xu z*sDd64Nr8#GYZAf(|aesnu%AF;iaed&ff5eMR?xmQ0vUA;OPOIJ)?qASjQX_B!%coh?fB5J96i5GdhEx+}ik%E$4yh|=k*0yLy#L(m_t^QVTT z_$yR;O|L(`-k`4$)bTZ7z7{j}Q{kq5QA4X8R2aT#Rrv%W(xW4jl=v1R{zFA3iSa5$ z9!Q+rZz^nQC*m0}A|U#&LfC*c_yeIX27ZG3qKiU<1g_l;6>->L4(l%Ze+hAP8uxQ9Hq2MSv8b&k961m6mPkh}-* zy5I-+^H)5D>HL69elRZexd2aLxFAq)B^-3iPhnLsP%!OBD&+RUK*3q?aLDCFfr6Ef z6p9=0aGJZ}_<%f=X8li82&MTkJRE{FqTrPu;Ip|Phl<86#3)4)upO@B5Eik|K^-Qv%%^L?JTJ71?M+T!9q=FC^n5l@aK$s&+K#8^ck=?l1Ta?t!JWT#+;9BexC^d=0sJjIJ=^mF z1wCGIQWt#R?U|3eW4?)}=Rj2VUoH^K*22RA~+vUzdTU#2}oM- zEIbzl3XXlQP~3#4-(}#?+u$e!kMxV9_{ZVUNecRb_!d0_(ra(m=u2&~9{qq|YVrEJ3@`hFA{SjGp^Ao<3KhUKKC6JpY7; z(^Ny`?m(9`(Vjs=nB3Z5c17!nmf)=a3CQAT2~IPoBv7#WPp&kVVEKhMHTEe+*0bJl zMQeG}6;k|`E99^6jDu;vPYSuc3y1N12S#Q?Xd4WCChP97ikWCzF=wJ(l6~F{1q$AT zgQJ}SKpNgF6yL;f?MF&PM*SUkl_C+6!Y-(DS&K03J#Oz8hA`@Z@^>HjK-jA z(saOM(mV@~X`g=oc0sio9@<0M=P>|sFB}~0U<_3s!^2g02JJKRKdR6}(S^PYk4f_j zcubl;AGp%2f`W`OsDECE7z-=Y6Cy7zXC6 z`NZXU%{$Ovuj%LU5_Z0{5Sb z&zni^|0-OhVNAOd)O=?^5o;CGUc^9oW)1ForI6c6&Q2JlQ#8Q!6+8z&K_jFXSd0!< zR4{M^{v(OpyW5zi=$ekTtJ@-tv3RqZRf~IG$g5BR?Hy~z94m28}zN;hdQ!lN4-8Wz!i z@_j7P(6FYXxjCAQBG$nj%}b&YWak7THN{yJ*|a8_@pdT!<4YnN!uW|t*W%wtoWv|XvYD(HHk#4cwil!p#|+7RDJPk z8>-Tnh^I0uGe3@;JT+=hQDs{qO#k9Y& zw}JRk)l64vlT)eoWTG*eLiUP_=Em1Ah;ABHofRog-P{b$OQcq((#ZCR)Y5b^7GE14 zr5P8n3uE!Cl0Y|cv+UM?(U;#^ql=@-wpc1fY#^?IH3kh2&Qqem$IOaz)+9D^2Tp99 z&K02!8N+;3vApUCl4o7=CTpu_opFQ*8Ch-s!6Jq#mgxHSD zoShJH$Up9go)%X@mazykMZiHNEloFpQx+x~*NKUvxG7m)>>-}w(IJ#q z3d4Y6izItUAo0r)BURrg8X$8L=(}_2KXgJSQ8pD&OEg9x$7VH>RFE;mcURS!>X&bGHi2nMhoc>+TOL`pQ$Cem0QIwYBBJ9tw%nmQ_$ZoyE&6fKCwo5XE>O^vw% za)5I;@1Y%$WD^PhY+^4FOOZ@p%>Q$)x?+AVG1-7;|A3LHgNNtp=J<$_)uY4N1?9f! zU%C4>^{026!E&+5lf>a4;?stSSbT9L-6ES%{PdcDfLK?&;T@{7vR)@ei3^U`-7Fnz z!&tO*6Grs5WpIo4{)TTabTo@C3rUTMozxMX-ccVG9Z&^2#!nVEP_Iy} zbvS8^F+bKgpS6wAPh-7`JE>T6B36vtDwe1k<5ADtjK_+H5#x(CEpK0&gz6-fkHcGZ z#oN&+V7p|rIks_jqOBb%ATEx89Lu76Fe^%phP#A!c<9)LxZ6X7Q8^M8IS0I`qq#f> zSV$Ym%1RmSopV$W`70ciP;sEqTXU&;nZSg_U0Q*Z1ZC5f#hlhWF`^NQqLL1*q{g75 z&Tn5oc~(;s-c#sE(eDH>M0;y2efWH(xJ;*ju()Uo*n?y!%cI}Xm=E!zRV-KAp#@i? zD|9Hm%_C?$t-A;^H?mgo%vB4V;hOT5b)lji#UC?_uz2NI&0LwPnW#L#!?7beCQlkw zjXxv9;`J;-A@^V;i*F~TPiyV+RXUPd*U+#bvJTb5xE5(W3eKb);{Op4fO8VTDOP0; z?Nalg_+ioGoq$j}=)6d(1rvmUzD_YhvBYj@m{Qr@{rIY30m`Yc&d*A&?P#NJ`52Tf zmv)rV-BVFg&mjT%f9BAzC_f?(IW+D*zlsYm@snavkHS(T5>G*&(8R15FE(PCa#1AS zfqHG4lT5TvUzO3fvX8~ns>hE%E-WUEGaSVUP2|}vm^3bBp%=zpMo*eS4T)lO#2KY09!U(^QN$PY6t1z z@uu~Wq<99SBm*;IqS8+;wp6Y#femm8?uqKC*7SilQz@5IF{5lm7hHc1l z_|bgs>sq3Jej{#jRThOIQ~cA+Tzm`-UB0(_{axC9Z9RNOT&_T z4oSUb(lPtcymG{bcoYa~1~N7yBVs>4^UA_#q`9l6m5Xx7T-0Z`bU^X$a!e7I!9cYr z(w^BH_7)0Z@gC%@cjmQ6lNr%;Z9uTn;-4M4<*qnjrjZ-m!mKNjyu$c~nS3-&3eJj2 zVX?^>DI{Gk?Ll@EpSec9lyTiff?d5+4Zmz}lZxYKQZ2*cHm_E=d!%&|t4nHOSp3P6 z!?^$u$3rLJ(THYH;^tvS!H_BB)N@WplE-0fuk^kRi+)c9#Oz38OLSIiY%O}IX3gx% zIfjfB6u)c+Wi`uiDd?uNyYf=8bUxq;9$YYP_l2#eE4+Z&6thEC%rm4+&KVU-z7c$M za01hm4aiemg&l^<2B>n$B;Qp@2-86Zc-BHR((w)`am$jM$UuX6krMpRKa55L(vj9> ziFMJqpzo?FI{+7#V}v@36yQ$gIAT2ZtSC#ClTV{GLC^N6m|TJi(e@&kj(y_<_ohSQ za&mr3gTX{<0PZ|g?qRVCGPW$ABG!OPqC_;4 zhR5|a(%v<#5SPPfglVVv0nQ4Ov|JoXrlQO>;xuLEUWVl`@i-(?ZqAq8p)1lxjD)(+ z8FHKZq0j>1bJN_yVngOU*iTiC23iB->^i7)uu;&u7drP7(+oS*k&g5Fca@GWjh5UT z-nrABXj`{B%aE?#n$5Zr7WWM{J=QJaA%no%5_KLIZ7&h7iVad z^vFWX9*Wq`i@xgMJb`7Q6;ZYBnpFUrwKK&BhqflxV0jE@33Qjjik*8-;$IYc>Dh#PiG2bvrfV@VKn)Qd~> zeAC5?olZJ`@pFi>WTL5~anFZfosSk-SdIop-W3^M7z3=d(6^c=JiCeEc6|BCElt)( zVG^JwR_*6nd^;qLg%ciT!s10pX19^I^Vrkgmy3V1(&?ml+c$pgJ5w0V9-wc%gY69#yHZ^2*= zy)E5bF9+yL&FY0q4w+GY?#5V}6!ngj7~`M*Fk7fiEce0S?%l?b+mK6KxUUx*pPFYl zEXU+ZS$EZ*3`|2{OL-5HHlBzR|B517&RWH4@wDoR$B9Z}=T%UGlE;Z@pIr^hv}f&C zf>LP)!&d2Qupr@5V8v}_nD9$&UYIDubram@#0K1~GKY30vHBn`dsueHxVU9C+1?Q_ zFWTA;-a52P(?l*L>Kzbad@da=MB*f? zK+Bm@#8>8txlL=M;%7X#@j~HPm=CqUN{Oeb5i&DS8pyAxV|c{a8nel2PZS@~6oY7> z^%n6UYNw$3B37RhLycacP{`f8_t_?={~;@!UMuX1C5||3cj9+>RQn&og{_mY<6Q=! zWcCfnVJ7Tb?^9!#BTmffx@(3iP9KhL$m{ou(? z|KHXj7;Q0lA8(x7l}d(*gx=%$1Xg26BhJuI8s&0LLj#Nrv~Cj?n;~;~*P@uxq8Gi! zV}4O~un}~;b~gy4Fpt6F&-kznR(Y11{V8g*1-4v>o1Wpp4y1^?T@!G*vL^lvjXw9d z(Ab(tbtJJYR&U%UNs>$|joVA2jnUY8%mv8+{MO-_(0leyxMe~U_7doA z9O8ATZ1b^s82fd_jV}xFx$X!&{ydn^oYi$vj?06*qqLlOsvQTZuz03c%d>-NFZ9+! zJ@wv0JJsINI%pw!jBiFN*`@_MH?ZfKw$Ut&wU3{;1e+n7P^kx~OUm5}SuG&PiGQH) z#;^j9Ee_I@p=|)9)9zxXPEnK$TFPb)tmv!*jh}e8Z)D|c9uB6l;x5CvJ(5@xT|b`o z%gdc0$BDs<^Mskqiyvg{#K@XCOS!BS4y!F0)o-f>3UR`&M!#&E+GBbWm?2Md%=g64 zUi8|Fr_*#LEDoavl3maxG!Hy658T@kUnlO9-7kk>GV8$nUY9pP%g*oa$V1Q3Qk$Ao zeB12Rqp_aE!co{SpcWXiwg5Np_kS9I&C4ZBDnZ)rn^2VYv`e*C?{8-lig>_h?a64N zFLc{uSWNCmhW)lS95}!}jm!br%wmkSsBH}lcr?1* zcb{h?3-x|SuI-6^dtM3g$v!ySAwJH=3=$q~%olHBJ}GxxENzcAiXe9JE;)+X{>u?+c6XWbV7r z)Z|`y+K1{>SX_cD0+O8dg`9ABL?>m ztigd#g6UDm8XUYQxbQVHi`q;mFLl5 z!lJqJV+fgheZ=UwM!1nt6bDBA(_%;EJWiCIuJ-4N-cUed^`du%CLkC7rOGOIW@rh> z64y0t-?f?~&T?5&VsY{MT+GMaz=26%UNbKiQ+8R=;LH&7)(Xd+euD!mee(4YP~#j`uD}oPQ&7- zKKqiQIQI~y$9rBx5j(IPM`s~_P1hjohIrWLrrc$p!LH?6ZC5J&Qn`x2NW*@H=6y0i`2#_@#Cp-dL(|)01=Oi59Dl7suQuZ;SB^N*Ia7%RXYtfg|F_3TElFSp$DRqjA6eY*Oqx7aHQo;s7DEP`F+%OCH4+g* z-L>oLd8}@^_6^e>zb#k|fu1K1$&H^V?*2&7p=ookM)&D@-;MY&zCZzk2yXLWW7*BQ zw`ihNaZ^{j+~=Y--tVJo-`VYSQ({hidl$EB^NNgIOTyIj^i}`2d79ewh@^%iEUL#F zQNV1f4Oh$fMu)H%x4?v}!5-R$?~v**aQ%v-HHw|ahDTQ1(|mI=m*Ar#ShU@dw!!6` zmi^OZGLfbcrqgYsa!D){c<%A&Lv*HBS5h76y#yNjf)(N?&OylzdD=g^5yzn7)itwg z=-@w()E)K6Xd$*MYo$ik-M0}dbD-9{QSezuPv4e0*H5m?aUiABQnRWqJj7 z{yB3hwW|fYZ1(-I_&se4%QpIm7e2Q>%eMBgcpv8s^z@Li$ZE<8i##kpciN(292(Rm zaI?0lVsg)gKUpK@ZhW-EBY(qbUNV1*Qqr?!2Hw>`QB`Ab1j_jTB*`fLhn@{5k)OEqw3wv33PAY zT@{V!0j}#uM8wBTywUw9z4ZVp+9&&@PZy2{h?58Ce0U*DFMk8ih6dN1><`Yet=cj0 zR9T*I&VGseF-@Z#zy#CZXqcsCHBoaiEjMq1y%jo@_$sYB`2jG?EZF@yo|`d&{YbeZ_ERE0OMndN&7b5HD}i-CHcd z5_6qgxfV0Adsdz|Oo~3VTI%N2jP))#_O8i(4!`gewHrbo>~P8OrOs9dQ3wNZof647 zdhu(S>z1nawwKJguM4XX&A#uSU!VxF<@I)ABTr|Q*J(nEhqw?<@B2xLS5Sr!eT8p z$GgT7wMTeHY)#bwQ9bkpsOqdXEb6&`OiK6EN_Tl~eb8t@1(jpi4)+ z8!f`(d!L|dxen8dULSj2OcoE*Lbn^l3|UIj(OF>LldT{(`_$jhr`WKF8zq_BQypZ^ zeGA@w`gRi+f$nQx#7{qvJ#98I`vK-4k9!ecoa8dClOgEsoZTSXZfenU*LLN7ZC(wF zV#oSVH_e5prjl7QJBGMu&va6Cfg=vNDsa{Dr+-2q=xI8)hikOnjJA68%hH6Iv-U2HqHi`BsqSKR*R=>?u@l>Bm9vayOrV)) zHqFj+$FN>eQCA1=c6_$Uh`-_J#6COd^FMT(G1Yc=4((_(=_cdRovZamzU({~>oR2d zxhU(fptrWo!5WG-WbW$~&Gjg2pEc|M&^aZIXIGk5Eh$xNky?rP1_4)HY7nABvtB^Xq7| zKNUy4EmLOS|3>nra<%c1RBb`px%DdboX8lBq4Ux*UXY#jFc9>h; zSk#C=XWFB*A$oGb@rT(Q@R8B@eVZZN+TK;!bFbTJ>ZEyauv8!dxteQX#bjalAaF>X~%!Ym<*S#H*K17KQ%>3-Fc{ z(QejlsK&5qnJrb~OA@KLV_k3ZH6+_ti%fMpWoT_r`7&aEvm%{pvQakEqbRu2?o=8}QpcbMio_lvkV2BZ=KOL?tG ze0Ba_->SX$dhmhRtj6Q>BqyLqFVF=n}R^R9k(#YI8(HBuM?pRDl`Y$gD_R;#G+3xcqC z!#Onx^f1S`2{#3x;q=E$?&!+e>8|M%m(IcbmDlIRk2~L-pCJPtgjrF3iA1ei@jeGp z%j&eV@jokPINJ0aND{UC$-C(8+q0&$lCJB3daTJx$L_N^8F%lS>ZqhNo?>aFOX~4w zIkfHUc^oO8K}VL2B^9i3nBVXfS+vhqOrgPpBokMPSPKsNZ&!wEaW76W(;?=1te2~c zAa*+sb#5~(ewRx*pbPu4fG7H8-T%Wnus9d0qiX?LH4Am|>>W(Jj{OXB$(V-4dEP5V z>D4(jfuiLK@j8}WJY!Y%Ef(TTpK|XaLTaT_&vFlgv0)e$)Ys<3x1hR9iASJke(B2* zIA82J263xv+rJ)EJX>_aV!^`9LAevV-BUR={oK=0vQh72!!S+@VNs2(l43o!S-Ci@ z)6G`?p+&BeP^&tc1uOuc@khfT08j#f!Z{qk)X5Hm@a3;|94r3DZ+4SL5wM(;{cHWSjX6e))H6pq2ixcpkgDU|Cp?-B%>%CO{um(v1`b@e-&bVwLoAgbqqH-&F+zLh=9qgLS&A zD`9fEB#)GQ*=hVH7;*XU1L(RNl96`6EN=K0b!0ifokaYVRn3sYf^&&YSX@cFD2WNO z3ShAw!KzikieGmQL2|Roj11S{E~6WLry<-MHOy`C1F*pfrzKOOr+;^{i%GN6ub}AC zceb8z+3$>2vO6;h5p;}DUbCb*Ui5EtQN!dUm(^@q-v5rHO#51?+3pdxX3pwsVN zO-$PfF&HnF8w)Yyh|8dK%VCW6ABt)HvHcKt;!@BG-?nI;fzkq*`-32A;=y6R(Lbv%4Q;oRrU|5V$_HfScc6roE`nw@w{l^aX1`=X{o9!OqyfM>eXk zILn;m5ohBorb`kDbr{0kJIuJ`v5M>U65r&ASth&j2V0GO&8bF)Y^^7cMTiX;97u4A zzhi2z#E_Cxx%IhyU5&x6jU}?@NvY*h>N@F=E(xcP#D&GQA!d&5&Ji=lMP2`tv2Ge! zlK;B@f$z(k)5X!wcrDA!dbgWcfL)LJ<_~dt&d-Er9X;^5ze9{Tk%i!%Zis;;QFW(Q z#sCr)RnFYjC4kHrgRjNttMj#L;V_V#7`cu)%yX{F5N9}skiB%!B&YG@Vy}*`^sV1# zAMN&*T|o59m@9b~CB-#3g{+Uuzl9F}Im~=S`RBJiZg0s&41+K4?yTW|WhBAZoVJh* zX~#(_*Q}a*5a}g6Wyt+G2a1BY^xsnR4Q}9YtQjF>XETF=KIj2`CoJlm+orfc*Q|zC zij`WLv$re`8zG^^$QQVA@^t4kTbel!=r&-MA)M=-RnfsUjG4=nSqBKrqHqXP z?eyUcvyY_Wx=*G4yi^?!xDAKvXTw&%G#W|bb6!a?+Gj!9{q2lO~6V^ktX0XPH=q; zAjdokQ`ZHg=PTATpDUrmikEvWg?=4&#UwER*I9M?b-dPHWHDLHz>x-Z*Q8iVcM{;# z5Zzfn1?Q9;8=vR_k)&**au%nByIj@7aU2|n<(VA!b+LXlHH7zo>t2$O;#K7BQg>9R zcgA7IED#pw*T|WHDBG1RiN(X>E3g35go@YkH^aASTaS#ev5{ctG(rQ#5SEo#;VmiLh#)_x7%dtNb8%)G-&J(RK*jQHs`_EpS#sE7K z_`9;olbP`QRm4oGj@EQ1=N+?4tDIv0;~&YDOxaaGh1^r$g6gQxx!=xFCuJYVEE2a4 zz+Sf03}WJ$m1fO(x_1hZeG9|?&WL^#9mG%!zK2xpc2kSwC+ONu?eegZ_#vI3+2y_u zEs4~u?Hg*==ByZrugh!Dq!Qta{%7n1R2D$8Bi>}T9&qEjHtdTp`9=foj+Ey6Yt>c{ zMk|vkc=N#$GIzSCS1t*bbv$;*-CIgJR2}@f;mH$UC*u(Nh4?kUDNE#uXRC#%#C(v& zlPHCYtLa>L<+$WUdSg3_;@mAXbTGO_RNj^KW4Pz&D-$0bNZJG4WBmbM(#Z=LkF3b}fmt%x3>f%m8GeMzUldK-iM>agjsm6iU zqwiADhZfJrFyT)qCNA@&^X-Wvcja1JH3`0j~K-StQzaEp!W!%VSWE?o?L zb|vcTtQl|AJ~;rtfe}~V7%_&LoJte}9n93=y*ZC`rw)9);16i^tg!b4mDvwH=Wahg z`(PpzWR)8qz>TL<;^GPosRBv>7IQPdp2YZ;GVcci(SH1!kd-=HKrQz^=;I+6@92I) zr{R8Npu_@;84^8I&(3n#deZ7i$C?;pb z7dlLmqt|g0V)X~KdYDYy0EX>kVc`fAs7eBPFA%G!&k2a99e@;+o;rK>5@)tlwX3CY z`}cKDIbF_7yxLPiNnqd$C&Y=J&I!d5MA6kkTUVExPL>nD<_Od(=*dph%>JlkTUbm- z1CfZnR8vMQRO=M#5@P<(G>F5facKnvfXAGMb|ukG0Nik!qWi-2|Db^uCsO>yW^oD< zJ9~p!V$$h@QPr+GdL``0>d|4fQ7y@8Bv}Pmog~h7QJ_@)Z%v_oy#e|HU>}0w)~6$D zTBG92js)nuA@E6JYAot+|0&E600i0#-0xfxlepXJ;<{Oz^SzLpPd#dRae4J=U{cy496sjgQs-%y$?CAlKyQVlAqSSjA zXdddwN#sOvg|DW}BKq^sNg}~jb;f2DW}0enqVjMm-i_9q%4Q~%^bE0M%a&KYfl13VO$hB*3t7m^dVSihMkmfsQ( ztvBNG6j`b?p5wwdXIC@Vo-b=t6El7>KXp_KBB$CTjr7elnOcP$o=DGaYfo1fGx7l^SQ$zcrNW16{ zWc0q&CQ*XCDO-H|v?+$|!%>sFhe#LsV$n7O0Ojs*w`|Q}-v~$r?fxUMDNSGfIAM}_ z1BbJ;zVAw>SWb4+rH@MiPs=RC3-3LzD92Gc@nff8k5-rxlV5V`loU^5Gdq?o(_;2F zQKHiqc^-mq-$rOx-2AroRxt(bSvP{X4EN)S3x45MhgpAmYZ0yLlV}uwI0O^qcG_XB zZ54N2kMztZ7o15#O@G#WzdvX-Xdd$9!JnYQRpCw*+}J4$M4g|v&|q#pV(wTLO}542 z5&C>GXX@c6T7gW#Sc8ONarMn0PmPc94&1ob+?t-yMBo1jAD&T@C@+`&MI}#4Nb{nqXKA2U*Q%(!LYHAgRU}i~2|- zikRIRNu@-QzdbzNR?5x|P6s3IxVNh<Liq0%H=K2o$;org2Z4TvBaL{loDCV864yH82#XNRGFeOIi=!W%Kt_6ebDHAv zYtbD-UI`xE6UDVYQSZ^QZbu#_Ip;dV>0Cy;7MBvs$m3I&9cJ2D_MbX`w~`Z9`%aoW`o7hwJ8s1n2( zz5T@HlE-0j+3A2H5|1Zv8$3_f=EoPeLW#ls^&YttLu(Z{An?e!p@R%kn@HEyO(cdu zmb#T8F$Yvi4BrA(tRX|Zb~L8N3NyCM$51lgD;qJ&;7Ej)f0BNWPCy6B=AbZY$CNmg zN`VUayNfb3EY<*(D&|HtOPZ$YTPu%7%t^61tofGeHAuaxRW*jy2%t(!JmQo*P2$fn8K@ z7eTPgJ^Udi7hDl>`jfuG#(flCqTudnZpCC70F#%+0k%=q_%l)z>0ZYy`U}w9xkfzS z8FjfztW}CDNd(u6=X|41=j6ObiCBR>4WL65y#-!Y4a~j#H!f9$BZjdv49m5#we=e( ziu)avA;FWDh6XixaSz2$VA|c(#C^WNBy*F3|)82nWI)2MIpqu?)vrOUp^G2^ayvo<(=Vn zAxd|#=FmeN*&{3E8C!tW$6dmcPm&q_#>6eCTCTwX68_R*QGwH*@PWkKaC&95XL zCq6}?^wrsUELg$qi8Ll5?INvbFQQ^H4cA^xy*bxdu0@Q9dIPZgW8>$94P zXwZFiIFAG@Pj)z+!Q1DgW(b?WW~vI$5bMP?-XUIbbje)ApfhNn8f@pI>K8g$OX>T? zOXEpdF?6sIk3f>TzL|Ld2`v)P7ZV7w>sF@#!l`fhR z=Q*9)C){b?RE`>v9p-(OQlPCFIV~!CvN*{fmnKm z5MNr4RU&Z39Jr-k@q6qqP`1r)oMLS7qyUD+nVZN8k9}G5QSs3q@->so^8bXT4pe*-`l0kv-z3A1-(xVYx>hcDKC>tck_gdZ; zVepibM@5CV8%5P&6~=>1x|>w+^l+tux2Ggvd@mt-N#e*^IYww2s}ZTU@dnA;XJVi? zBK0jtt+3LO3ul6@N!Am(EAUT7YG_NX-b{=J31m%m-p0YTXF%!Y_W1Xx}9m;E*w>+-oc$wWn z{hSgem=a2(s`g%{Us0mXz)f<=J zHJCi9o5(z;?FSYJmzJWU(*xiRA!ZCk`_z<9!J9AzmX?O$Jc#=e(IUi5hg-l2vt)cB z4wl&qF}pWdU``O(2r;)eXL?9)_K6%FS@zd_56#>r1rCe~#Gt>rLKJ#?&@KvbRiwbF z2&x!#e5h7oCNV{sMTfja7dzw<>y#KTcT<)fED#V@W&{EXW67aKMK@QT2xH0NNR{p$ zBESTYAl_GyAuhq!%W2?B*}%P>2JWN#Vqd4FbHOKDch7{aPqr4jYD#dCSL5Rrv>Gl4 z1s`A@LF*C1-AxmeQj7HPNx+_30``(3w9+F&drJ}8$0b7h`mwGu1#lbp^RNw?ufM}p zr6gJhcp`wLfiBrNh@|RZDLjXGOX40}t=ns;H;}lX#xN8z9p)*8xnw{8E6%Z2W<+BQ zcpaax+>VnZb= z98o6aSV1NMK{p_U#)CE~GK>aKh(a9Ba`PlYoi5D$lfjiPj&%?JXo7BTl#INskcblA zF4mNzRu3;LDNR7N2e%?}ITmg95*;b5)%>nU8OwM^MKa zDLdBwUYgZ_d4OwN80BOK78otLcZ|cmV;$BW=P>ek6#+?Usy)?(UG-26mpbJxC>QQ|h2JdTd01r}6sq(Zs zGbUuU7Ixqwiqu~=^#G?O2RcnX$Z6`q4lfLG^}uR}Z;;tg&Du4xvkmifw*6#ht0l%1 z;*$p|O4W>~H5QNdpAirR;;CXG0)fEC-OA}diianVN;Zydjjc(go5rSFlF>+$aJ`8o z+`iPN)au4WTU#RTdh2qI9W!Pu@=3+on#})^WMj+Nrf53an0CiRR%16rQf*>vvLlsl z96PnSDKe#T!i0%an$}DmKQ20HeADE}l<^ayQzH|`Pn^1D;(-&Q2Oe0zW~?GE(%PD6 z{H%!^6UpeFq#YaY_{@Y;*<(|i;*D-Jnww*LL{D>DdXLhlT4Rk-H$m~}o@LnB5=rh6 zMTz#*9;J_^qkBd`DxGu#;%~9WL~AQpI+lp1#SzYaY?IFEwMK0=lG}JQJ)l|EzvY4nIe$_5fDp|J5Pv6dUbSTEWJ9` z)=qEog;*15T$fHp8l%cDg^tIw8hty`s$Qvlk&+3Zw*^A9N8+)@b+Pzbiegnp^AKoyhGwvKdkBN2wSYmByXg94&tG}Y0XruXo) zMY#^_O1C7MI3L&qnmgj$yC_8fmF z3+I5=Yl|?(l_*}K-CKxgd_9qY&`5HvhSabp%0kD9r8xiWJL2Ph6th+5!xfkR8;d& zx>2(Z_ZL;2#@0k!4_#z4d)v4Zr$%;vrR=w3{z(0 zQJoJ?)wpo20nsr@9@;Gtmx9ODgeX_HCMwh1k?u%xVR$cFjvO1PSSki|Nr|;O7H?)L z=e#k3$Aua~H>8{ERZ=Kg4%v)}|oZ1jg!L z6a)&o14Kgp z_Lg30q^ZciB0fD>RyaK<^8b4BnBaiI{QL5M8|*i(pcg1Tt6(K^&wpa$7cZsa$PfpWI5Gktp?TZE1(%Zv=WAncitcL53 zU~OUk2l=Sbd8ei+x4VPY9fkSNo_wvW-S6_N^8!?lN)7K7fVX?FTS@+FJ&D#|ow$)p3OMY{3zrr!W(lb$sP+|Tp z1!D^O}g^ zr6;!=Hptc$`45A8!C|i#p)*~xv6;&L%*@bFv*UXr5S&`_pkxu>+dI1OR^`xF=le=t z05YT|7~D{pe>DV2e`2J{>b!2$8Fnw$0G-$66@g%=WN0vWog~NveAq1zJh%jMsc&#{ z{*B44g=Yq*6oy8?vk~0+r_)0#^REq5lcTy|K=6pd{ExcbAt~@>K}-w?_CE>#-CHjrh>2sxdb%89!gi7)sK|eVn z|Hr4lmo@L|fyv3n*=vK9g)=z2m&+k@&N+z!QN}gMp|30SB`35JvMj(A&HsJ* zwb@H3Tp3(=ZSaWfb^Cwpy$N_#)w%zlbJp31Lr6#_HFf*1r91tWtfN&s<098pkk9)F+jT6^#0oFq(Y z`+M&H_wYRA?6uck!@J(~u6JHZ?|9y~_VRll9P8NC>uoL{S{+X`m@g_en+u~!K#@3J z@a-KxJWgS>ea0CV5A||hvWM_ zuO`;l>trrHyTQx42BMZQ6UA!u@w%8RvrDP*T!xxUm}^Iu(C8DDH7yUNRpgEJ^Ll2Q zkB8A{chKUp%mPYs%;eH)ucvvQ{gjCFCT_l}NOX+#GvlJF$WtxV_S0jX$GKNo0JqW2 zOv|aZ#W$V5y~%fl_B%&8E`yp{Dwl$oyFwZc6+jm^ACK@`X$f}p+&$C070hIkok@2J ziun{E#m(iFb`Bp!>>Mty)EovH9yNy@6>bh=b2W#7=8DES@SW!HQN;B=X(w}NnS6jW zxtZpcrbzR0t4K3|)tm;SB_w$z)&i2m26&w^&Aj0j|Bf*$+7?ifWXX!blpCYq53~^; zBzjOJHo!a>(ufb z-B}|{zrIpjV!}L9T1vaGwJ%LWWvI-zLFHzXK-x@(mm|h&G=C3U;m=2Lv@oeWOOsm5K4^qEuAMj8w!RH;8 znT#fc@jZjm8zT`f56;TxH@xiI<3`*+>xcR1H4>h93(X}i&YS{Uple?9P`YQN+hlomC4wFUgx-ZEbfmr+@0!V zP-bFSY%s+8>L^SSC-_6<^{Tzhz$i@f4uA&aR>gne9mtOZs8M7dEU!_8<*IOZ3l&l- z&nt)3dX}nwL;qnLqQ&DITTJ=j?(!;4F>c;UB-t-hy{-$HQ-;|zvL5-fvH)?Rwpc=3 zPMnvqllAfhU#dXrH1A{-AV6O~#)`+{=$(Y&*YL%-L0(q`;si40#1RbwRou*rq%%J& z>`I!>oUMH&t49y&NX5jkw4>-dsdi9+KC3{g7)aGtNEMde%ut$_zUNBg{$>bkyYfVF zysF+w{JBBvjFq;n?3z+0HAFkptIkTCRTfqgor0k*gkTGwwcHd-vnMOlLc2&BZl!DZ zo0Nd~EmquO4?2M6{bNNkbMHu?PI5>dy+Kv&gYi8ot-agS^ zck*%*PkNnh2n{lyH?+1tt{cF4* z#mxeEZU$1%PVXaO^@e?6ug;)m7c=v;BF^KH)wFeJ+*}p|pFb|EiyaK{G4FLun)7SX zU=&CZ5jUI9L1H@?-fv0=z&q{ik{Al5$J!u>tARdVN0bZu(!l28YTAY@J=TV&Mf7^G zw#Nq@Yu(Wv&hMkf`5mq~#m!jw&7N^{L0+PWiJsgz(az@6A#S2Hjk@Z&3T?f+D;vBc z5g^+n;WUaF0$PtJd$G|_Amp**7oAk#3YQI(Od(a&k75U#MQ1_OK0T{I6!q(l(4ckH zN|?vq;gSza=267w1-(aItnZ0>KqNJqrYH7wFG zEYcBnk?z{NMOu}%NaN4-7wM~97U_{aU8HA%MLIA*!fkCL;COW3JcwMvd^s9c_CR*} zcrQ`nm(&IYuyd{onguhvq9&Rr5|rN3z}8!0=ziNlQ>8m=>AM@#A+3*T4`=t?wY2we z+AmnUsh)H+N5+1L?)00{+84#~A4APz=JuE*@0pdQ=(fH@SKCx|87Q~d^8E^=)w1NA zeVvhv*TweJUS2Fk>`SAQw2XL^Oh!9vrT_od?;!!4A53VEBt`&?YV+6#(HZlw1Zocb ztoUHB<5Z~kRMFtYBWlDrJeFW{E<&n2RPehAjmm$RSI~(Z9^dW=*1X&*-t{&s&P5-M zrm3QUhtH!`{3`YS9SVtBzfa;g)-quhdnMHEW0s7r(#K{_ZlQf%b8ZbP|9Y=S{AjiD zCA#n)X1pnl@9X6)guoY~CLe6SxHY$!FS?tT&#mFPqj@a18s`@Y6mZ~!@Z?4U*78K|Fqe#XXlq#KzDBs7N$T6EAPimj*{iSCV z#D0Pz)4YsStM4XtszJa%wUD2EOZCdU^$%f#-qiEv&wA6RxP>>T6`sVa-VH6h`U|q} zj5A<6)^$#TYoC`Vg=^qhk-A>l$s+vy|7egwYGY^D?f5e}gm0lD6He&e34@ zGm|@^AT$l&cTT)e2&?_KCXesI6mbhLb>sJ~C3WHtR_CEtG+R6@DQ4nmp|r(d6&z+R zry$pS0aaYIxcP|jH%@t zsx8PVVTrn!_lGvv6}q&I_PmzJic%K|?4OVF(fVoF3Ts&l1*`SoLM}pJ_LB~0(_Wxz z8O#K3iioJoti{Z>V-do5WY*iM{ zHg8E5p5D4FtQNDI3EVGGnwOdQnU_1r%R2=*kliaeFgu<&FHH{omsfobQi>%x(=>qN z-NF1>qpB@{CbTKuIe_9Arlr9H)axQ_@R_ZHiB4Jolj|D2#I@`b+xJ#%!CD;pMv5Q& zPm$v7@YAJu4LBDr3M4dFWEbxl4hkk_>iP9<7q<(jxo{Nabg?}q-NBJo99mUT#Z$!07qPgsOnN{L6t&4Y9JKYCrw;zve*tFz;F7w#qnCA(?f(+En@$kS+lQ7y7k79`YIHVl4aY_@OjemAM1>!Q z`f3=LL`&>2k}5W{Djko#IET$~-HA1(_lXT|n_O^=(?7^XdcX0XHCA_z>xPee@Qp#}D_s6emH7CBF>XC`6i z7>>xsrhUab_8$<_A%*2{+@!Xb%?8= z-h&mbA=Kp~gixdGg3jTLR!?g=!w)yNT6yOCMW=})8qsM+PD|+Y*oYK#+Kl?-Ux!Z5 zOM`RA$nOK4x|-L0bh;D|7opS7s$xfhCl^)r*Yz#p`;i3ZfR3sDaOQ+ zb-%Wn*8^%9;5M9=4yVzf?hvRM6BOn{-rmN1i+R9Ik4F!MY}^adL60txQti_b06RyN z=V2$`;K`rHEPP!;uYkdwrChsG*l^Gx>Z+us4qUt_k+x zW*YWW5wO}ZRk0tMxfN(EAezh#THluG>=>TZDtx7>jnmY8mBpUW!j#ERY3on^nQSde z!rXH{!s3xBROpGI&Yjt%w$4lEYY%0ayGAC>y+~IP$y@7L?yfqL??)5Z!OV(DzR5A$ zGdUyfKFcl;Mv}I*92CPhJE;PxCgs##5p;B0*pYJ^YqcXptTG+wz~`y91y-3E5ZEYA`MG0R8b7HCKDoPLcg|W z)O(TPNZl~y){%27whU`?47=PKG%y2)(9{+V1SN0r>g~L@mLbDl*?KdVS_iYlQC^>g z_RL48Wk+z!7^F%u0WW9N1_kc;e;L;;5%Q(@Fg}Odue4ny#C|~gHQ5b)$W;`st1@}{nUQ6wV z5wpmoce<2~5-`t=GkX$78?^HxzGf?I@nz3PhzH6zhx`RS*sL~k3i=6_(P+O2db;%) zIBR%WJG>4E5Yin!-Yz;o8nn)4+TTSnYsUEAu4^)UHAhLP=J5T7Su!~!- zqeiA1s8l&_!EyY8i}WPN;Ep)fB2MMra4+e9r6NNpRK$_Tjp_;#kTS$oUszhlRm zuVVG~yjjkndo1Vv{E<~&B!PQz4a`IP6wl+q&@^eW+V#V=VEN{qw#7%;1LUhA+SANfhsQuE`#v?=W0YKimne88Dpsv+KM;99(**g}~pvDfn^X(qOkSXo3Hl%;G;<@Heyo{u(bU@%LRp`zt|v+;<1A>JIeJTVGKcx-_wq}#8{Wp>3t6spNv8N&?D)1>rhdAKJ_rE~Kb zK}>*^)YS~Gi=)i#<}n3$Ak)p-^44cJpO%FH_M{F$_;8D*^^`ho-jiP9K+ikL`3Qtx zt>%4UaO#Jp1kbe4!^T~-wP_dc-)^zh_jmEtCoO*Ub&I7}h-YsG8A*E0OQ*M3DveL` zx^r7Bt)sLB*meyz>Qi7L@^_|OLKJhTu9rTmHxVp-q_Fux+M z*LnHavRF5HsGnZxejfk0-f%_64Myy#EzZj)qCB# zix9s~4CZo^~%$!Wlf2=;D zA@AbxC-`h0wYiDy$JvTrw<^?HzRfWA!b>Tp%&dr^GEi8V-BB}P9K=X|Xc{aFII#@v zDHbiynZZIOb5}7JTV;KjP_fwskhxk%A&zMjwFb23eD)PNj2=5oa6#1PB-d{%}gX&khpr|H&U8Jg3@ z81^(>g#%qoQKHlNHe?GQaY9pKwTSd-b=YxhjSe`jA*x9H|Ney+ACic@eDszlmtxRH675&%6cMb7w?Y zXM?{HQm6fjEghH!j0=zeI0WX7Nh(SvG+KvkO@zlmqRKRnOC#FVEQ&@CkY2ssB*ckJ z+fW)4mo)brt$x0_&P0D91xLc%X`;W6*s={UgNIQvEoZZr*9R5#nX(@{N!^*_4-+ap zm>>NeqZ#VgDG)PUm#-MOM4?%Brosn$;3L+#)Jy)6wU~p)lL86AlvmC`ZL_13^vwyg z@_c7wz8}SWSMT4<^mAq7?rrYKNuXt3a%N()YnbnromnlmEN-rdCe6E1T+uE8c@M)I z%q+@x`nZil5~%&(8qG$((Zk-|4Yo3?#Jq|1)|WIJ0L!CM*j#N@D`!sj5OX(=-W>gz zINT7H(}1;?+0PvbVd+dD%!xyAMp+;t2{>j&dkx<+9}T0iXGcp4vqFGVr8TztFyGr_ zbZJI#jPBB~tadLS-oPwrH#jIAgAk5u795uy*Bzs)fof9@L!U3v9G`&{q@Jwd=a0cv z4Z?Bxhw8CM7Ns z=}?idz=g0$nK7rfJD^vF}_w};=;w8p<-ZAuvGlBPx(?x`^ z_?&7SXTwZsk(ag5OH46YHD1m*yf3XgUEI8120mIzRzT8B&}I7tPGzzU+U^RV?Ny^J z#*S@Mk_Nv^F@$i&`uvDhh=hZ?g$9q&9U+(3Gz+3!7Sj zwZ;

qhOG$UogCoyc$Jb9=1cBZq{p5UOX}z$zofD|X_OHuWq=QT$*y#F65Zzm%C^ z{K#s#kbJ7&myCpJvzlMGsY*M-tJ^~VGR?0d=w?ZbNa z;q_xuzx>Sqa$f6SZsbc5j#PsFnrrV1IEluQbTC&93)H}DP}IOODn2$497d1YE`G31 zWX6YTWZp@e0St3|L)z1uh8OaqkiU%+u(Y{Rof@vq2d?M$TJISIT!u!*YGU3lF0o$3 zP7_m)CdLBDc@filG2SHkt zQAk_Tco`PQ-SoK;ZCg4T(l`#Cc`KxGEWT8>-En)??n<@$<*@X2dk4Jem$=^BeT6Yy zCr9|=R;##0$0q&EbFhqx$g8ce8XTVMAO%+I@@2VWT3Xb?z*UtYy-bMJ!=#~!r4bf? zI#Fc~QN!MzqH8<7`LSJr&4#x<9Vzj=#4qD!HtMugkcDk-qD>qiGR~4);a; zu*wdqpqk4xe|I&y`v*r@;Ubu4*wjq3j(*g}tcV}#6IPiV@YjpkW!W71;;*GXx~j#5 z0_@X&8lP>UJrxaf>eAj5OzHuDQY#|9+#OD83Jfcz!c4QhZE0Man;kv3n|00t3@y8< zyX|fJoF=yamGVL}%@n3}etXdJmbUUFYe%!3^+ZmlH7omN6RKgG^`(hI_`LLHX9dk} z-t%VXXtZk>?VM)K-WN3cBF*+j+j{$O3k`F1zugALJT>C4d@W2{ z+&cp%FL6!Uo4G#2XgQnXf^$&IBmIu0lws+EmP76vwI~&qz8CQMn_K7e|IWB}gU>&Z zT35A={wQLG7nscI*l}#EkIP{fuijm5J{;ADjI{`jUFujjFk9JkquLZwQslrLTja%T)r>);z+w8Ng~R5^GDK97^|xk=)}-U*D6GVia5o&XB$u*RcFgw9JtQD{Dmu_T1Ans?h4GIE>`Bk07ta7JgCch5zN zG1n220Y1mgi=#@Y(Z$?`5{3HcLi~{<_4vW8dolqFtCSVKofXEKXWn9kk)LHDl_~aH z$lJ$Z$DNU59gDV{i<-&K;|uu4pQ2}bc9bnJv*Rqpg_t+LXRPRqXyju>=VJ2)Sg{Ma zULH?C9M*brZqnH}!;LnT5D*bIOBQ|^kh=@8tMth{N$ZEegJd?}3j;2Hsr@kyoELYt zzJs*1;3W?DfI(WKE3u^>4NqU7FU{7WR{dCSQ(`T!DX~I%Ye7yj_Dl2|tIn@p3zC!S zrVx+M;~@}e60IclLJ&m|j_eXf)=A;n9l^zhKC}ifOuy zx%X6DBRNTV7dLO>YSt4604RppB$P1ghfCl31GA!?Q`8Zoq(Kuj5&JcjX7Cqdy162T zGVl7)(H~g-)6Vc|BwJ%o=z1CgVR^g|77wTGYa{`08(ty;b!j_(e}d_+iD5rs9+JB2 zc``%%QkL*Z(FQwor5S_#xX4(z@{I(Ch*RzuA8v(N45{We0-#V!LN(Dxx+Sv^GItT` z@k@PPgHwaRxv4#Rq`OB~f#uJ6vOcvOonXINOMH@Dv;{eWJx;afR}ZC6LeGoMs}=YZ z5bz>}=F1hk)I?c~MJ>zv$Ib0$LGE5^h6yvkgaa~@-jCzH*cRf*Y~JY9?-NJIfW|8B zCv*xc%-dCk1?g=U1v}%3Kp^(p3}0M`)MS;DD=YC$NJRo)UH3z_TC|`m^cDyN+Be5{ zh0P!?GIrBD$+7siL`TPPgl}P~9Y2%sox{R68+hYo4)n4HdEP}{7CuA&aC)t<#uwDc z$~=nmu7ZSh3b-rv_KO#r3vf{qZKw*&65$t1FqYXb7M9yDp5TiE_~OBG_r;UVzStam zaijatHKVcQ|A_5hCpFo8aTG%NjV8b@E=LSUa7{`r@J($nZHP z2>(R({+I@xOX1kFGV#^wmbeYub63;7m{!`FJIf&gF1=IRIPTtw4PM*x&<%`{-jv2< z2kFasv9&CE2-F2l4h6YSdi|q^ep!^@1hkA=ynOO-;u zME-Q`2yDP~(!wNdbz<$K(U0LNi->)ki$VtgTc`QBS!G-9t5VnUDnikV@b{P-;rx81 z%xZs0C&->JOE)ouxPrK8m)e{Z{RwNh&c_oPxQn&x2B7*Cn}#y!;T^V!dy_HIEE2CH zSb`*1m!3aFSBM zRaTr(8+^v@8&$~5T=PsE>U!yj0=M1PWE7>Zz7YAQ^MswL^hxFa)6B>)2yDMHVVRzb zMsRe(cYKI_L)`58k&xu?Ch>?en{a-8D&M?Ih#v+9adQ+8$L#WyaNFj$!3um4kY-a@KDo_>#E8R=QzKgI_6dmsj^US4RIFu^q4C z*jAp;#*P~i$^TF?j)+kf92y94Ek-2kdp=M=h)4jEOKwAoLwelsmXInlIm+9`7|{Kb z4_x&<@zejhbqzr&Ev)s;|02K8MoE405B00C7OMp`r@@`|aX}@!7b+DMj*WxaQM}L- z8O}4VF`-9jCn=)ARX|MTKsC@(&vw5e#aNLbp20$TISo2(zQ+0A5A`_eu89`2QIJ2Pu@6^<+l&+XxhA$Ji)&v3=v2Jd5oa04mE zTlK=>HAW&CdTCM^`QiHyldF?m#4O>3FFIETbi#Z=TD4rWtqF8^ZK@HZBuf0YgxU!+ zm}6oVkr@8oYmJufromR^`JD)g9Ld?x0+#LtL@4pt^Wv~Y+lF&=O(B9!p>@}g0{6R$ zkYZzc<^u(=z75maM;!-ox$xVq^U-oxF(T7F(x%cj{*@?h^E4*M#vU7@+Q5<;M4p3+w~?w2YFK0M>RtUL=G zWB#tuk#iZV;P#4AO=z!JR5Lqm6c#M83x!28+l6RO(@+N?4QT*sBPE;#d@`uAD}y#x%H)%L0hw?@EG@%Ay$2pLKrJ zWwj;NVbmpKN1hNBxROkg>EV`k^}o^TZ$zX{S?6B~749a8ykp9_H8WVLrHzE`+frNQ zYjU)9gicLBJaLv1Ais8%EKV+ zUXm?hEeFFB-Yf5R@r+r7>q$S=+1#f9=TC9irm!jbNkHkg4VOgvU8u@ZDP55}19pe9 zb%P=*?bxO)gqiE`O5dG;;!?Z3C|U9RXJ^;ydqBPL8f%4m?bfl&Qax-K*4)vF z0<+3fq#LyHs`hAHgu0RTWbjeKiOxIbyutS|rW3%)e z9sg3F@^T*PsLo~uB6HOHh53nZwG26xCBYCrw?pW`@m|d#UbwSEoR*F>horakL~G2@ z)mZhdXehHgL;9XY!;o`508q?`+2}X3sEn9Zp5;TCCJz4NyAlUK7s-1C|DUFO$1cRd zfZ>Ej?8HSeT&)KHCC5aj`5MPBNzo7H+ue^pZ>g9jad zSjfn%LD(5=8m#m)8O2Vo8jfKxYD;TlPG@?T27`NFsbskwQxO%3@0*qX~m!;j3wVP&1MmXKvpt_7j;q6$Q$JId=~$jX~!^Q?idu~Ojd zHp!s~bWh+#swG;V!OMC0fmmM=GW??SBV5YL%g-Yh?gQS}DHX|C_2E?!;S^T{Q+#Ky z7wvg}(cW)y(W?DLo9r*zW`EIM{caZRsb-7zR4}7A_j*Pz`ZId3#Ti}e&*(;fMsG4B z=_+sa3R85Iq<{SWb(L&@EOS3ONnix38AhnIOqg#*VZ%fphmeTsQWfK-pa!O;SUf|Z zg|rRK9|3yseWOWzw{7a-H)3$OQm5KBSj2&@es<4R8*;uW{0k#eZVJK@-p$z=i)=UV zGtKZoHye>2n^E{|b%xS3B#}k|lAB-%-0%dMQ)g^7zf-IXi&q)lA4AbUrhx?PP4O!+!#AH3c8I?i@ zhHT;()^TQeF=V2azt}6KKq=BT4@ia9)-1&yAU*2BGGq~JSKa+~^+6i>Y0@S#8(n4= zU?8p8sex3Q1)IJNz6V>&`Aq#&+(RruTE_75r&?!$1}^Tcc12iRu(Vl80a2m-m$!1J9EK#f|kYD-C7!R9ZrQ> zp3eviLw{rSL-n#gEx=xcJ#D)1cOwc%c8vTUsUTio{Lk`1bcvE*a58{=h0nQP8@7T*D@uk)noEvev zw2bUUa<+nzB^}T|!N!rsuO9hb@vGxwAY}uV)ji->6+aW0FVf5wj{+Ubn|{bD?>V#N zsCdNjrl0vKfl_T07o)or|2G{Cq*i$&NsVkQOUTVA8BL44>FQu`Z|v3JQaCxZp!Svp z>GGZ)4x`HbF4eIpm&CZ=h4F#{jZaxv*(bV$FCb89AX^iR>b37~RF)4Wt<(YDKy!=T z4q4=ZtMt3zV#41xQG&ji{J*)M>t_=qJ%3ci?ozMcWmSH8$n~0cV ziKQKBa$SW@?H8lo{pc{XzPFb{P-e6~qV>UuUepP{7bu5|l#g()wSaI5GsQ=^t1ZGM zuq!xDZxW7MO|8=ZkJI}na(WwsJ1oOp{}Om$IlYIV`0jjZX^%Eoq}nPppV~T7y&5$3 zV6(2f@Wp11Z?S}8E+Me)!b+UyUq}^XAV|C%}9tU15FlQ}=; zMaZa2Hh3mZM)v42k(fjwx7ekzF6Je>*a?y|x%IgbSA-}U={wLFC@bCb#CMC?MsY&0 zHme%_Nk_dvIT#_vUYlY>k>%u^aRyFKgnzy3a zo0%lwkQ;^anP!=OQ0yrq!9_F@5YGe6(*`AnPRhAt2uS_(^`@UXe|i790{oOD$}AMv zmJ;TDpcqqS?T*Su`GxgA?nFT`zqJh;>ngJoRaQnCeXDm{l1;_aW$L_cbUiq(fq03j z1U%oX^kz}BI;v~Xcw(S>z^_ZMP_gn<<3a^Od|u(!_IL~0xBlPSrmWY$W^Gq%ZSURt zwH*}rO+A3ly91uLebKgCm+Q@>XTu}aOey!(<6%|h9id95xl?LCSq(Rlnp@Ig4cGI? zA>;K?_|203{xU*5!1wVcdb<6DD-^6l2Nk5Da21fvK7~f>`{`V{AeF&l5+~?+2|8~X zRTpPFL3%pw&p3VKDw)mheEoc7eqhIJ%u{Q{hSy3Tw%mqiCd@_WC`E7=EOb&K%0Q!# zY)le081IU$>5iiy#R0*!^992ey+&D;Z zLi=||m;^ou`r&n=%T{fAaz@yND~-a(CCkbuSPsJaK?)N{BaXb?3|CpkOqN|*Q%#Db zK{$P_mS}lh6Ni24ur1GR=eQkO$$n+s4K!BVn*U2q2O%!Z^y7`lUqn7r#a`Ev`zUt@ zStdrvU6^UgAGn`_0KX!U$pLZmDoO7Kk)&_6q+L$p$)gJ5)q76bFiXPZ%S^C#M2S>u zvwaKvt?g=r4KicCPZoZ+GR}|G&WM z66D5`mhgXC@V!i$N7`85%V+Vuq<>(ryIwigd!Aj#nZtD=R)rse`V9+eb8HfafFrB@ z6!^tHmk2_o3m`Q>84+olLUpbgkuJHVG~1c54D#9!`~LIVyAk=BGgHQpoq4Qt#0*O( z5P;TE`LsF>C#&6T{Gf)g#IS9o=dNysQbMII?0^uJgj`d6Rc`aE^ui-@kSNskIb2PV z_&XaUceyGjVrK}~i*jd~9ERQ=QYt2JN{+uy0|H8V3$Cfw zmpx%V@fz^yz@c-jmwg&|AS#AqXNi~n=iq6So=y#(M(gQM{!`*FUiK-$@4tH4CkMa( z=4Jme`2F8PFmq3D7J1%DoZAB+aprd2S&Od}da>v5pa-4qq$GocP554UJoqF%9CKac zm|yy5kGaT=c@ZN_l4}kanL+H)N4U+0fj<&lmJyD1ogM2@UN&iC8mK%zT4Vm4Bmiy- z9AmC|T@uPS!|O@wSj68dxhTKWhNJ>!$0(Y;tx~aV_Ez6stcMpr!<9iT$OGvvDh#`N z-*(lPu4dX8n(?TxJ<}kL^D@`Y4m;}G?5L+Gb%A-T!cR32wsNHl-!NBrHrL$U?ylW6 zG$4#XOE3r5eJ~?w=8Y)U;Hs4b48MY65;UyfY{(Y%tSPHCn;@m_<72&!fA`w=_BxG& z-V$vBA**0S?^PttwJ^Bvk;tk&WHy%cI-cRR@9A~AHmG;EUoU(=-fQ2>>pUTNe@}&< zQ6L=q9d_(}J&zz65&rN6DgVIo7GB^%Png#Lz+M$+jHlZlz54x);I3}wOFWea0Hn)@ za9wO_gV&*}Ou~Q!u_0kkcLhpJmt4Pb2r}O$GtG&@^+7C5pR^X0y^i;Fujjd zPx5*Ql(&>`)=Bk>;_Igo?g9h}I%hAJC-oz(nU7pE)5avhgH0LLp4Ts}#!U#lbVTwL zYSd@wOuCgcr{*PtD`7mrNt50qWZ*GzZi`040!+rP+TM_H$$ZHjg4yQ6h-_drWiThy zn+&ld0aRHLzmohdR!On{BP=NO3-rQ9s?@}o(5A8^9F-qA90K%SH{8u2Ac~;~kUJ@D zLQAa_Z?K@VRu_)(Lwv&qUUm)4XTCyEG;xWkJ4Mg|n2O4hA=Wj)N^}W!o4+Z&{f+z% zFgF!5{mjVW2tIKG++ug%+;Tz6tRiUV-^?VgkxQ7j*gN?qQ?z8bN^g+Axp|vX&)is< zzQR{{(zTifzcpzRTw}9|vf<&`wAN~EYtPx%<}_=KEN7zs$9rAYagG#|-K$QA#@$F> zUCbE;?Ch_J*ZnSTsfMp`Il_?2T|`z0Aa~myyD11a3*X#fC#yHU*F*SbHg5>fJdP2* zDaM_9w1L{Ux<}jdUQZj?Jll!kW{&T)n|IT?d5CWM5@NW2kTEQr<)i-md+IdS0gz5M z$WPAt4TlixssuB#7-1h9Nimz%qUuus+s536O|J33z#+DdHSWk42FE1{IQ}>5n|-s@ zeM7uD=+VV|;FSnTNOL4IxhAU=GI_X}Gn8~=uE1VnYTheN$gQeCi6IwZ-G!DC+S9D@ zPi^Dl(KI;R8&5*7pcxnhGo5y6zHMV~pzm-|yGGT)$O+N$>X!`X#&eJkDovadoL&90y}FE{@~q zLTo=H#gMnau2mr+(cq1o)EogBEgWn&QG=vVW2r%KtG4$AqT+-dr!Y77xN2KCA^mFC zw^Z#(S54x40wJEPty#$SNpFxiI>r8oIZG!mZ@NL=Z-dL2c7ypv(%c8@ilERRnv^9S z1RgHs0d|$~gG+|ItkL`!tskSnAh2sBf50wo`V@8z=g$TH(u>JL8}rxg(p8#O8Qc9d z!!>kduLMM3i2gDX)Iy>e0k^P%oX5QY`wiR+3R!tC;ivHnci~rV=r#6;_1W&+gS1ZQ zclqMVwl*ssx18{^P`91z!QXVET0>qq7W1nLEv99>(;+#Z8Z749+(Ozv@c{d)*Ek?3 zuKL727kK^q!Ajl436^Evpbh=5LP&Vi{?^Gxw3Yu`uC2orcVcd7gI@~~`3Yo*C%BOd z*Q+ZLytJ5MquYqkxt(}ci#+Ku*U)G~=F?jL;9 z?etph4Pem4h{h*2KE*|kvhlmMkw>#2UtN(o+aizNFua%_Mf~OddbA(zx{^}&e!JdV zbqM7!pEX`@e7t83uOoM+d5NN9h-&E)ALiu_wc*28kBS~FJU~}Z22F3@*|zj5obLQG z7wAj1K|wV@bE_^Q>udYA^)J*#TLXaHmvNiAl#9}u+?}BpU$_^u^x=WXp^W6n)R9~l zj^y1YBe~We31x01RP#sju99}#sRq$<*x8zHwOXAC!wVfSSl1hd7b(x{R{HDxM}Bd2 ztrTg3?r4k%qhPIp7x1j+ui&b`#Qp5#llnbv)wNdDd;my#pj~&ZtCm-(^lo76-L<@4 z*HRvKGWhQP;Hz65teP*CX6zegpDR-e(uD3LdVM6_|ivzCD+y5qW*LxK+wf^<>+h?6e$_DAPg>J26M+I+hDngR+=>BsY?D9Md=Mq-94gt)Jl59A+~|_e zE}+@2<^~etnQw4jv-4>IG$dzspwKN8`@K#pUCfj1pae=BtSR*|uMM@A*M2n&r6RB? z-V@lwOKU-b1et@r8HOSO)odoPe3uN5oaa`B=oEq>MVVw1I`#29KcPkV;&xI>GQ~`D zOAm-AP?h`r0GNRn{s!`H7?w15He)_!(HLAW%IRV7qlhb+R=I9&=pjZHY8hntq#YCv z&G@!?!T0s<`v?8+uWa%Ah0VTylJB!6{-;moY1{C4uggNn;Rtr_ykYiuYG~HP^KJ-K zvut=?0l&_+AHWG9?l=2jv;BbEJ7DzT>m$ydAV3Ou_ zuYgsM{ehH>xUl7cYmc>2qz)v1X>Y{}<(q}43G47KF(|ffWLe*Awyf_k#Y3A-{5?wd z5wM$`QXlfh%R~c-&sl-DuUT){<^$~5AfsCQ60Q<$wn(4-g7wLA|r z4F+iP?DeDQHnPO`$90kK`ni^-Q>m@ls1k%EVfUT%c9hv*o3Tf@nPD5IggPXwyU_VZ zg*g5d14U+k9hE_EJkuq!zsm0)qVJFbU=!Em1zdh_%Eb8FGN0p5nklyIHPt&s{64uj z8cR+V@876E=-((gH2(V2Fxngqhv+_hnUg?|(R_Td?x60ZNy`Br%IonCQ=5;|3XI~+x5(U;_bF3e7`F-3t!h2cphkD)!vdqD-Lvt_2 z6JA0A-o36~k=IkigP=kQ2w`8>MIm~Ca$&(O0PCRWl8TK zpf*4{hFj9UpUGHJwHzdN<+;jeAy1|@QixV^s(0WHX84&^E?rg`Jr*0oYFgxoT?W(Y znJtwZQ!0U>BM2D0?GXK0#QX>Ud0l2R6+FYcz{>T+)777OgXLJOO#|1~^ixasoI}y) zm7BfZt_?5xr~I@LF0#-(3W@t?ozh-CZC~}(*sX#L+SRdof;-AecXNTdBf6%@+>bnTWrH)bE|3C zGZzf;uR{wzf2~RPALIxN66We5>fYU_*tq(i+nRlCdmD1ZK&$SZwr(iahwWaA{y0av z3qR>m_+mOQQe=hj&HcOy20V=*WDWS$W&?iQeQ$?R?GO0<76<%d(37v|4LkZEc##gW z3$22c6C(W!Jcr$&)4!PNzmVz7>ebSrHk}H+bm&A6_jNeoFqF7Qkmw>NRr@9V+j&8+ z(VwM%Yj17LG_bhf;~cJ9^SCux{0jWB=iT6rjj$(f^UX9f%dm;Mox1^g+|zVvzH`VIcT(vsTT+!I-2rM{huO|_$3d%|3Bg+K3{K0x3n7Hyo3;-W5#j*8vtE{@ z&15UR^wdmRTo*elRzkCCbzwBC{Y*;>)55Givi;dveNR26&+ton9EgVcKrXLKJzOsE zf;Z8_{WNkR^e^O{c1mx!dUi@y{74Ll{1wtd%s=CLAIR~g9#Y;Xqm%sbxsk8|XY1&L zn5G8cC-I+I(8sPN`ixTwEURyp^(zH>3G>*gaF*L?l0f8}WEHAzf#mt2+iABy4o>D2jdP%XV@~)jH;k}E<^+9vVDyNH{ra z4Y(&)!tM>Dy)J|8d?uBl!0lpgh$cj!_cya+ z{E)-XOQY~_Y8>eOcAze(2&d9uq{~xA`f59R&`_t^p4%Mcwx$H?bSDsZy@q4!YB5eR(xiEO@E#S!BEBWX8H&zBRmtL3Hyz z$Yu3|DGJ;!Ib-1dde#jUzVwigDBC)xD ztgaLzFSsvptK{R;j9``4`>SNWB2`y_hOOlr4jbI5`qRrn3-^~cZ#?T&_H`+VwC57ORBQ_0OcUOS_ zn*SJ#ob4LiEQBv+FQ|D2<8Cpe-+HTkS9RcV@xy9^9AU3=4N-rxwN4$$IVIkZ0}Ir; zxS|H&wKJa)V6N$1Ob%_)W}cgK>$SFlKI9C(6?&v(J&%wnO4Vz0DU$D1@`pf-ybC$+ z_u6V(#c?V7&O=68N;!nZFbI+mrozAEB>ZL-XL(9O+wjfCR^M>pYonp_grN5+NKN_V z6an!&M)&U)FH#onKggTb^iL$s;oO~jFrI3|pr84eo8s*LgX0H*Wd+{BC0^%3jK~R) z?cy<2il6=*8`!}d^!;nR&LwJNu0n5rFQqDOnCzjcV<3o>k42Eo#b1KEckyj-L2Y?kU5F)e|BcSJa~6QqW~m-TSe2M6OWnkk0U9Anx1 z-&=-cQ-)QxaxJt*^#gkSLy7r8G6YwFIlSJ1OKhYC*LE&mW{jF}l_m@bG+_%WeqY2b za7`v3){ria*+Jr%9Sr#I8IvH$PYb~iJ_=LcjvT=qF%cMz?UjWB9Df6#=9@1C)CLup zyCTW>leo}~#tN~KybN-h5;X$=74-oz2ZGi^X)cw?zzXfPUHjR;LU1~HJ%Ri4!W)f+0Y8Kbps-1+2VMcS!#O^01uVAR!d-#72l~f|4c$mAu&2j6 zl?=?SNCCfor#tq{a*cLAtErWd7J^Nes-4$(#>zlu*<4=Hq)>`Z925CipZ~cw^ zK`_oW$a4AR@XAuGn7`wfYL8~^zN|N9HdT>IZB3jHR0`A?7n>$Ql~cN}3Ifs;^r6mv)96T$>rQoA(V zlESLZ?AIpP#O<7HTu4k~E%p}~+(kgNaoIT^q4(;UINHmf<@MCX?;XvC4kb{5Vuq2S z{Fb)tnY?O`r1SV?aLd=(+W%GNNrZ5m>lWk`S-aAX3Z;`efxUh;xz%AE%?A*Aoex)X zPMqK!XU3h6w_dCG^xz4rM?v)X^Y$37p5f0cvG-S&B~dB%U9W1sgkYy9Wg z_PGyNE4uo%_IV%koc}z_vyf#P8rfBMP(bRp-3&cH$2YhG@+zo)!?aV;8*si5C?=384u#-38F6l3kcCcNq z;20_lkD4KPX)EHgDuy7P;6OS_J5^gi$7KLF?fOzy zu~=+Uro@79FIX(MN1Cww2XHoINz`J@9>dMRT8wMP)UX&Q+QmThQ37bYuUcxv@I!>5(D(R{Ty@sQANYyd%g{BBU z>ITzfA2Z{rW2)(}$WE19U9C;E8MYMv-+(R3JTyZo@79;=V70JgXQdKt&P+kBL*jK^ zCu-S*6Up%hu!7S&F--!_zzADVh^D|LR#O_gIp_gXP*0L&h-{x%mZt4gu41=5W(8;T z{$_K;3e;KVPW*-#-~Kr2gTdbf5*7u|MK)Xffi=?Bu>#%Cn+bH>ma8R3pgTwcU8-o? zW3cX?Rnq&$T_M4(k*pwbMG*>VzuK&>khsPq?u$ZihNq4HK{x)_xaT@eA<#D%f)oN! znMR4yDFjY{l$Ej{EnE07ZD(ESc}J%)hfb9br%gOWiu^9H)@hCqk20l0PoHEn`Mr>B z03nf>3>#PMb=b@$M84$eC6RACKqyVekR96ud$yn|WbO}q* zCHTN@NS`U?UCct1xyqjXxIKKjn1?FBzd1qI0R+}Y{X0R!{+@UJEpc;yIOwk~3Nwo^ z8O;3;ntKX-8+8}R;0$24?h$sgj~?1Fn0~ZhM{`>+3NJB@5zdK5e+`=7>LBn+GYGuy zM)W{MpnGtUyXYQhwI$tyLsfJSN{DDt6{Ub3c%$yYm9&bg7POPfbk9Q<=^pAWHR~ev zgEj1RNL00?fzW#5GxZaubAy}CmS)qDLB`r$b~qJc2>F|MA>Y$HDb@cg5Xoj!8snlZ z8;#W?D8*P6BeEycd=ld#CM@=sm6hoFC9(onal@7Ja7KKGweTC<3}YwCW$pGc(c>c^ zM_Y3|Tx<_cQQe>XZe{f65wV&tqld~NoJDsEw}lU@;;XKvzMO`6USP&zOAE{E>wj1DDrH0I zg4CApf27+%=ADxf^j6>(j(oOIGRji1TR2#g02rZiIViOsyGVH=>nmi@LPrzcny7H3hgDj{&VG109`bdYc2312oP44;RmYyu&rC~9oLEIO$`kIM#1K5hPK zp(w}-g_0l_%s;zF6kNZ|n&_+7NybYOb~pdA9x zlDz_u|7i+FY)IoKx)4F>o#h*=&M=ue!51!5No$x^^ROx&GobO z%&ouK2x4nNr=wiXJi-S>&WPqW#)L5pwm5YN}2Jre6@O6$|NRGkB+Ne>_ zTwRV*gHrDZyyN@24+jQs_-Z}kDv`rsvwv3X`Ptx!V-G>DzVl*HK z1o{9#ozWokI zV%CrvkM#`xGEa+wt@hpW+q7-dz_uBjNshgiw#^adZGTm7u&a8EoDv(4GE(c=}cY3b)G<<{2Nb zcl%BA{H>baLJ z>;S*;2l%u< zFY57z<4~!KRXbTHJj@pJA@>KP8z@a|Mj45>8}%NIA%3ORTpHFS{vfPb-$KoCo)s_K z!Qmva-(vFgl4u&lv>bug=L+X-5f0&Es^`kk+jA-$?5YZe8{8?nvwK@(ebL;1eICqS zJbE6NS|vIX=@>oDUT?Kup4Tby3wRo&q#klweII}H&X>~hFf%2)Kn3PC(%<8q?#$6Qplwp&+r(KX4#PgQL8NVb zMUD9qrXRud)hPViZTLg9$Gc8J3ePCou}_@$@ZdVu&|O`^6=pr?0?MiabXl6g;bg0Z z%UeZ47aF?VLt=bkbO}GI`D>*v{5r^6cy9zYdwn@P0G^EzG=uly%-0paK-`K@zw5}n z*2_Ht7Udpyw;bAQ%1cpTlL~=PF@NMWt#+rY_LN`kK85yb^fGx|ify31`2<^%l+(TA zgMp{DE~A{Y;M|J5;=s8QZe)LRKcGU73(Lwal@5N`RS@&dJv24oK)lM(y^P*Yr6zjM zCNAzFV!rQ1kNp8`{RfE)gk)Z0zteE(A*}kPusM0=6YSO*{I+ouSayg8#YxUw zX~D{!@2f=E0zL;HJ6pkuF`uE1`Cx5l zz-;>3`sRjn?dRL^K53!mhHc%Aa-JsONJosm5&zGaDB69)^ ztrz`6UK&DN4?^_8i@qE^%WhI8j6$MJK*~|3;&jR+g$7_=Uv9OgPho{@LZ0fI?!k~c zHEs=?U!@tbN;chHun`cezF4Z56GnXU$7wI$&|V`G0ngBmaAZnh%y@-|7ZV#@B(3%-G);CF;QxXLk`YoNV3;%B2sWe2!oKZd&=>U6O;8Wb4i9Q}aUZ@x<|@80 zH(6JiN#yKQb59Mi`1=Nl;`&I}a%C6rVF&&r=zSJ+;q&^_>-3|^Uz_t9y2kedxvW{I zT01j0Ta=tMqc%Yjti}i*Yil6y8JOolnYQHe(#gnLPfv2YP2v`Q{*!RE2AM;+%1Jt^ z&M9NV17RTuYwx%Bp7hm0)~g_VzhoEhpS14{jFIVVEjnk)$Vu|8d~+syrzPfS6`wRR zM;DjxCUa!^z!zB#>BaN7dXyC)d$x)GkMw?uuCcmP(J+p{Dnm7$K6KkIddH%eL!K8rMdgti5tIY~kXjElgD&vYoYX zSqm*(OADPd&0A%O63_)ST_PE030zlaFJX5w9L=U*R9US;o0#0|Lc%S2>l^=}*K0Ax-;wnK+*9IX z?yH22<|nkWln2h0S;}O-b|j3Cog5G2QMXz?t_9L)`9QIIA+r+_+D6Js*c24B4H|te zU9h(=(JgbeXPiZ}uI6j(>`hwHTQjy}5eHx)2cQ&C12C(R#!W}vomnFMz44DFmUSpa zu+J7WU5Sb$3?=~04OpeckG(Cok@ZT#fKQ6%_xQ*oeyBk{6U3vfX>C#NoC7AnonWN8plsVjc1RJY&-p?N4#AWMs#1L&1c{^ zN-=8xmvfYi5WwDS7Y8YW)PKUqhM^Wg&FwyZzJNH8JQ@`3U>+}v9xW=BG!Mn1gGHrO zCX<6oioNdVlZ9wx6tfc-EBjYN5V;O&p?&N9da&jb{Wagxbj`2!*Zc#m`O~a9>%3U& zyksQAEnrq@>a1E)K@CKqSK#_H0c5a+XbGWAKX*a0> z;_0R~K)Ht1`M0=vok1suStR&!bbuJ+y#O)39PJQeJOYXkWAe!8aSb>aF z*w972V8cp|4K3{_qe`2c2x~NzIpDBQ-{oi(oM`j{m1={H?LMC>LX!fB&@?sQ*XPx4 z3w+RQ3w+wfSF&(p)9y0pIAREu7d&3jpnA z180l4%{y+T=``IM^{dMIhf zyKP}&CZ9(b0H4gk67MDQqupgI52>pu3}1ZCr{Sb}=UnuW!B*8iaJF*=TB( z>i0_0OR&nYv^Q>9`$J?LZGlC)iS18E}cP#5g=P>E`Yp6Dc+4a2t6 zQLdS39pOGjf5l3_Ng|AdxsgN|XcHe8AvnwZJ^%>1@x22`3#jP;qKmnA1&~4=Jk{vX z9D>^GPye?f=o=uYb!Q5<=%QfNCw!|_KPg;w;ig@BBK~ubxd>0SYyYTS`-jQC(lh>3 zA)2|8)c-;JMGs&42Vhu29qf3ME8{JOT!EA^j9IhQ*gv-|~IN-ITYZVJZh=4SrpQF*Sa^9?L2|uC- zj@&I3jlnuG=^O zCdUNUVh;Cv3@DHeW}>SYST+ubPsb#WCCoi#(9JEw>iHaZKkIj_v0K1RB;1s?whZ%c zjNWWhl};Wb@(G1lO`eccZOSJu$p*Qop>?akmo#GccsrkhTs~YI&qdbsW)!brRuO$% z7xQz6hUmAkofJ6c&I&cTG3p0ihOh6+@^i~yOyaV8NMpWmM2-27u%2$_IhIbe96+=} z%XQ>==A-g-ntU&fT0&PdY>#QOK161Tl=$-tNY^fDxn+n-;?e##z~*M7+oCSHw2v&aCy4f_}+5k z+j{GVjMt+3J ziVL-g2wxsz*DrMb*V%~*@3DcLXfkHEiyzEi6fn;BGGQj1!m)oFp4-+|`D~|ZYblbN zaUWxo(FvAEI$LV8B&GWLB!m`OkalVJNfHG#p3u;Cm;q%OR2YS!Cr{5V7J5HT1r2^*?KL{wK4kS#vdj=Qye!0&$8U&iBnkakja*`^iEr+ z1xH-MfvdSZZ&}op+yd0YlPF)@f+#P#N2ugFc)I=tX)?WiXFbdj<kiJpEpa96rl0(jg(kvHaI_)1z4a8}P&y%Wu=#2YKGZ zgXzs+ji(I5`N=JE^{&=f&An9CKm;GTfE!2%;U)e~BFb~?LgB|HrU-i(+rh`AaeL9r z^fC0ZT-ILo^7%Qf_A;Y`JrU-dhorVUrzYm(6ZT0vRhGLpuGrl+u-}q6+>4%`9*uBG z$4IP~7_=I~3~hpdIgv0yfZK5G{R9Cam?j6`Ts6cADIeyf3q~uba-5o7t?T5Kcc89x zGg^IYepZ$uxlglZUk{pHM4B|d$u;+Z8{B(iKH)+`YT*Cm_UD(v_{I!3b0H1mf#2(HYkOIzU$RO#*=lS#6{r0SZFM_69h zyqlE{>{qCYg*4ODp9SEA^$+4CL5X?dtQs0Q-aOM@It|af9ji$j$(wl=8MmFYXKd(y z?Iy=(7Drna$3A!czVLnZ`%EkSj?K68UHg6YyS|lvFQH#WW2LGju6LyvBtf?~;j*+y zH{z>ry^SV01@mf>{ptng|NJ7C0WL(Oh55cR;JULL_EKQBl;MZw{V3PkrQzTb2dwLq zU~zXSm7_90G@rE4*5po7mGtpEKTa*2!fm|x3CbE9r*={hk)}JGRBG?02uq)&^e{@T zmO3nbic;rB6aDWl4!^^9?3I*m!x#6q_TrV+UcASpuYc60y}BH(U$?J5ggzq(ZR980 za9*`|)dkAwQ9n#~gJSAffmZAk*xxs!*jUZIxK`ul395*d#29y>F8VV!lLIiHOtNl- z`6YZoN|{)R9q?ymC0Hg-!2n?M8pE8~L2F)*ACs0Ll4&a+5og_JUwVX6lkFM7)=W}>}0B-Zlx%J*4)3yPyc%-)2%kos3RqXbcFuXgZtMD?;9Y+O!w-d4q6U$tjn; zcoNlf37xFvqq*Ri+P*l_;2bu?%D219N7}YGkxnI-oG^mzT+VoXGL5_4Y@}-V$=!V7 zW%_Eduyh`!q6?|i;z3IPqgm;CO81f5u$1^8u_*&p?@36-E08R+PWSd1Y2R*3d;1Le z&3Ky_$pQ^0ESCl{$-1_`8I9x7AI<3Pk9dindfvt~5Z;2<#t}g>>u}6lC_S`U={8Ek z8)L${A5+?tc!n>YLjg@VZ|o{S(qVIZmi^E%z~Kk0DD4Tv zqOt=1DWJvsMhMk_ms=Tg{$HyqFm*i~;N%+8D7fTg`8bQd4K3gTV)Iru%ISPwyny!p zPh{;|Ca1CE6-y1NvhHn*E4G80?7lEVSHAo{-Vg5R3Hv7x3YW-dngyK;X&XJl+1zP> z7f_OhxfpN=;j7-rxcRxgYaX|DL>%>e^|_@~AY%w=t-UiGZiH<T@A!u3c ztmg{EtikHZ)O4=mWl!_@nM$y8HD(c4!FFJ#!oq5bb1(}8H!PDzLo?}zM5}9-|D?_F zY=-Z#9(KAm==9d0Q>k>+<0Lz^UAOtN@?70Ara{NddfK7jQo(`7a)qz$>`mQicyy{-7)wS#4R$MhVLIM5-t2v< zP;Q1Y?5rmzufNOarui;A6(4(YICa(@4>4pZTu(lEoppgrK0z@`Ddoiv;v}pfsRgH& zCc1#@UI>9F+CBAS>|O-6C{b@U-i)UJ3@%(NHn-!c!JuA_`nLM8vrU%8B1e?H0n3U; ze-3bXoAIg5_{d&T8;NQ!VR96#o@rm#1h&xjV2@VC$ej;wVv<9>c3e8d$TQ64<-`>b zl@NozU0{8Kc9&L#!yn7e@j(F~dIAU(q9=J-s02PKgN+1!?a(__65tZ(kA<@S!dJsUt*T-LL#^a~FHw zM<@Zve+$VU+a3!2Xud4JDwZITK~EznI&`aK#fyc=$ee55uGdr;$4q!&a^UaEI#{-GDpK4{br!ZKG%WUQS!nF0_i$~ZPLQX5Xg{6-p zQ+4usWSV#Ju2lawmde?FzH_!;8)K-mxNDOT!!_gww^S$mb^|RoWs1TVui6*p-f~&x zpE0Gb&%=WuP9|{tIGhLmJMJgV|7-B(bq2p*rcU{o*$mxwJ5=-C;JKZ8y{TkZ$fq)@8@^K;@0z1RqIov+Q} zw)Ie(<$AO2(OY|+S#ue>H0%=znQV`u>B@-HxbILRvZe|!9Jr8XqxG@B5}RGEQ}CvA zoCP>>Q^-mm3j(K*yl`P&CD)AQ)~?TnTl=e^amf%eAaayO*)=`P{v7%w5Mtq3hZh)( z&$dvvAB>XIuar}Xoqmf^-5TMYJf{k%)75-%J`9k=NpdFsRP8^{Jum-V1(k@Sh@-(aw!z-t_qYEg=bR)04pZKH^U)9apZ(weUDjTE?bY^L#pV`M zp^ia6K&g87*T8$0smyH5sr8CDn{@J4$&^1&+_%yOinA6yu?lIO*Q}%=Fxrlv$i6iq*Lp0@2WptHY;?-J-<+C+JX!{Cn z`i-Op0#mNm^P2!exAOu{{3O^t|6mW`zKX4qyv2eS1hI*eY6y0qw4DD$Ngg%2VF{$o zDmETC@;IKIv1lVe?-jku$=T`j9L~rh+`SboPCEMpyo>N)I|-KijT!;(AhQO}vA}$Y z?u2v7d^D|@PvhoeNflUo&GprFBFW~(X(E84$n4f=D@ATn44=lxAzau|JRgPCXGaDw zZvpsX5YSGLv#iiuO7AXRE{D|Kh{e<+wNW!7NvcTazS6igK==%52WLDIJCWHuRF0al z%IW|K`&xmX&z7UwchPK(q^tRZjqe7PK1suV90#zT99LXrImv9#z;|E28r&ab3)8D| z`>Wp7qXi3fK3&@t^ip4p@@btCyXO-K%CZGP=?adzllj23C|>X==x06298`p9wbU!9 zbO~|r(No?55sr(+2#UAaw({fVF~6-<$`f%iQvRb}TdP9pZSC+sT5CTt53`p~R%lcD zj`0f!r~zVldIi9HfvY13I)2}8Lun}^qlj3lHtzM>c*1YvUayTOl$|EMjn8Zw0Ai6p z_#N)xW9BAr@H^TJ{#*Oe;c;^*A322_mxtF_n0*u?L%8L0gF!Ba2QF*_e?rB%@PAu@ z#AT%Xuy|KQ5r1D8Q}6UFgH^zYuU&jg*HX&6neCJp!KZ%<#+|G*I%NtM`5!Pg>RF6? z%!|nublu{y-)Zahj^Fp=kRNsZL~+7)y=6?j24!AlUmOFmT@dE>`ckO2k_<7FrQT4s zGL(EgA8&&TvH=BeQ!1}*BD>U5tV$u&KYQnKFdQP7(L7N58e5UmwH0dTnl@0|1VMs} zaBoXGu@jZjC6a=5&rsudR2WvB9Q5%#ee@Jw*J`7TGT&x|51^%;X^W!NGGbD!mVUIq zRmggf&0aBIAd%=?KSmISuXE3QF~=fiR5AbPGF-=$y1%^YrIFFh`-xeeYl!jN-3WII z@rs)hBq;(VV*16RKXE$OaHMD6Lh}u#5*;gKCD5^SvbXV!d4;v;WNsuHpPq5^I6-Dq zc+c0lZG-ov`55g41?D0MDGFkDrRvECrQ`ap({|^;S)jvpO?S7g-=9u!dSmZ9y?;ij znHy;^{G}!8EOLm-J%Tnj&$LQPGOUXwknI{Bs60_Eu^T8EHiKB$QuF3Lj|DBA)vzS@ zxGJVjL`rD(9dpz<#P4YdwRa)HTRrA8gh}nd2%bV!bLAKPsgAk};h25S9`_HHDiNMNFSY4HPCnlh4U=U?Gu<& zPVs9Ohn!>mh8@4KhsQo`&nu5$pEkElBpd8-MwEX z$DBv%h*MEx;2rc+Td)`cek!g)FQOdo#a(YI!SIIa`8eOK#qvt#K8z`9_E8*>GYB}^ z;_*!>;=ftTTRwd)6S{Q6H0j}8o`BZzvSLfAiRZ(0w&6Mq48>*vh@jFf)4+pE(2O0T z7VeA-pVggvoq0lo?e8x52&r;>ofhN6(!y0YwbSIcLvJDUDhc2zr9Y~?_431hh|}KX z8R{(0kg5$0AbqF@=?maszBiy7S^+rbTL1!FhjEJH@q7tq-@@u|BM^9$%6+ z)>CB*DP!RO0Y~Fc!$pgzj~3thk~wieMW%xn*Mq;k<7PkCH~#85vK%SFg`bZC=G;7z z*Bps5ta+0-^~V6#ov75}J6W?z^UJ{YR6?B$Yi-eSw^2Hj6*vm`J3ehdZ_}@mt=Z9> z<`1){rza=Pox8tJ_upJ#>-U8y9Bk^i4SG71`~&WtLYXj@RNCLG=2W_eQ1DeVUlqq= zKO(4Ro_Uji==rOlJTsfL)*B2uj~kssVAk_%qyNTTq*5h^&95*kXOh{#GJ8(`vUVz@ zRK8F5%%7z#uc3dj4bkH9tu3Z}u#AYC!Ns7xb41sqZ>jdIH^C%twZehPQYcRA=0P+U zc>wBUEh33*17VT~vtswy8YvDRo?1uLmnvWeJ8%v1Ro+JS5?86B2Se_$?=kro@mna2 zHk-wqFV<`EMgq8Kr!BDY9&ET6+d9kq${4|)k6yMPHJF9F{RoDsfeh^$o@!{kPYOFt#t+)ZWu!q@pr^FGE1#yTRTFcS7%sNeAQ2HPy|{~+6gNqV`mhw3~MQ&n*i5?m=G11dU<{&wR)PTCLmh= zBx=^qRwP{|Y=k4bg9F3Xt?!_2107-$SY1SVy29B1Qm3RU!2K2P)Sl56vw@%)$gL}j zfWl*^Ym!Lm*Q2*783EqhiPb~^p(oH9QL>AB;%v5vS!9+&`<40UT)Z|i=W6}T`6%GL zO#yH$G{5uXT=T`aN+(i-lN#}6G7%OdsAeP4M)S4BY`eYOQCRfva1^NxAr!o3m~*xn zsQcVisFs3p?P+V}!LZ!cYFVK{m1L+rfjBB=5D@zimjecPn*ouw&1~c$d|Zg9S~HDq!awEvhnzuhbn*oF1Bd(w z{4uWd4*4axBIx(l+1??a>3{U0wdNKgQ|7_*qNg$2tDDTFbJ*!aoc`ofwmL=#N?mT1 zef_~CHte+u*pw+@;!EE?9P?XT35SF-EN<@2Es4Zn5}%sn-Tn%ytoN&|%Ppr$#H^i! z`8$L+lh~`E+Ga>-$k(<9rO#0siT|VJ>#xtP;QO9t2cAZeyR8Gk@PrHTp#BFmIaV2* zR*|7MoBRvN=SAY6$M7l6A__TkG3s3EM9m?nn@_RjkA*x#Qqa&RwjsptCTi=`2k`|- z9r4$;N^#sgZu_Dq{x3$M88s*4`J?Dq*axDAnf-R5*Mt@qqua;``dp>4d^JmBfjvL8 zgotXYra6L4=Y*jw?pql0ClMiu4vuFL9R5(unm8EotBHGyW5uxZp2eJ0>rJvb4JzlM zC$Ugj?2eSmK3JUW#ZglsJ*W!~_D~iSjJ#L-nZp4gZX!|QmH%6lJFMTLaJ4v|x#v~`% zpFh&iZXLd)X7>te<}c)!a2_%+{w5fWeLgyv*i|gAomhR! z#OBKtfr-72i}s#OOdLXYg*QAULBECO9dA(E6k3l7h0Mvw&n(*l) zXVx{L3jQ|vLbhawc7$vecVd&~1OrLrZ^^;8;whm?zJPMOXiB8JnFM2}rObzaA$K9s z%iSPKYcLaZr_l-M472#K0AX0P?CETnElDbC6Hwy2(0pVGcc>0C4oWfFNAOkbtk5Vq z@SzO&f-^Y2KV`&(>O*x5_y~O$DHhz9N61rSmPEvT=9yh_w$!q*bcjepUPiYG1a+a# z6P{sPeq8SF2Eo>R0N0(x-RHVUHktUi)Fd1i1F;1AY`)pbm1_&qT7FIBFbyJZevaQrtk4;FuV!%rFdRsPRmuGP z9D{{_`Rpp{v2C^kK6U#p;;u&d4m>yGA|qYOxMB<+bf7{VDlTcW{;ial{4$-zHm13R zYc?q^;kA4K3_Y6rr;}`NU64pKH9<06xP{O9`xB?Sra{dPq3dK<0w%aIeYrv9Mb6v zZkd-zDdrVvV78#q>0jpLpQzBa{M%jsdR0W+R7J|SjMy8RZYegehP`+2xBKQ9U?9E0 zj@%X+E;NfKk$*@gL|&Wz*^@VCV7;Mg|FywRQ)E&|BA~9Tgn;)Hn#YIP7c@^9mnS zImh8QBINMYnadoZIQg|^dPxU@F|FcjOOJ_8uqQ)e%T>5m?ZBHLNC^@&x*o%Vl8ab7 zP*A$nnj6p)lsj3!1ncYZ4Pr0+Dl(pcE*c+9TbMMXX`j8uXSs26KrHd0)BQu_H1PxV z&S5Ci@WPCm-*EpkV*0|A-04KlOau9sOb=2JC*7qzLW@l!?BGBEnn#vzaO3y0$vn$Y zV&NeL3<0V*Ptk_iNxvmEj-pADM-SxBHv898eW#I)T=s4RFZuIY2df9*K1DdLAW?^W zhNWrO7N=+%B76+TGbpmY+c7I$!Ieeaq05yHC!h6sy-*05Wv(4dJ7>xCld8T7V0k98 zG_%539qDEs#S>d-+=wIgZl^{+8DwhYLpv!>kd7w>F9dh35g~%Yhwm@mG8lvWC-#q< z9M&TeZ4P%!d3hg_86b%RPB=Jg7||YoRM{n)SOQOnugDrn>ORZaXfky8pn-FH#JYpC z%J_!58oZ$Uhv+^l{$nTqU?+=2d-=a~vX;5(x1frwL}(n&1=)zJZA~*eikmH_i}V(n z@vc_47Lt+WWSX5Bbxfwx+=ja}+aig-f_=l(LnQ|DdrVm4899=K%S-(aXv>;6!*cPy z%*o!WikNFFobGF!K1*%wX4THZiR2Db>J{iz%r{HexZPuiz^#yodnU5MO0tqY26M`Y zAie~~)Q~RHn{Q2pYvc^(Xnh@UwC32)mA0tawRi>ZFTk_LF2utbtqYN5uI8vt1L(z^ z^I3BJJJiYYtZ6|jS6lOOxNjFLAY3!6(IrAvKEK-A^RF60$XyVNyOvT{<(N&ml~AKT z<_ioBByqL&FtOoH9TFRR^8TZ%Qt|wzI2s{4zHPvDz_GT0?^Ib^V3VSgGg`XrE1`?x zcmF`%pzg=mqItFmwKqkDgsPwBWQY58v#)-O=2$GidE!7|0pL@HHprJiD+a4@n|wC5 zVFgG&&E-v?MJs}Jo73VH)S$%zW$d~A327c((Xe4pL__PMm1GY{%}3m>#@!kYgq`m= zIPFYjWEo~VZaLq{vsdZ#UylH4jnct#Hv8ho4lyS3X=5#ATIpt9w!B%)ya5j+ChHoK z1vY2YVWxAfoGPbP^M-5%w;%|lZKL+q7iS#l+VGD^H6O%%^y(vJz3c4n7oEegkfrpw z5h6}!P2$hp(b7r?#}PyY2oEfRXhv{VGdfWIDx7aY;B+ zgzPxK{I}gLgQFeV$H}h|7JDZAfAXu~BVdQZ&C;Wz(8CfaxESs8q59-3NB>8dO@hsT z9%^vm9DKRh(y-P^w2nOTuYT(*m}qB>y(a_cT!Wt5A3(8RNv=+LfXGNbD~6t0R-U`iVdIvpwipKZ&dwR?i=CP~}0Yz+|EVj`el&tCQ9ssM6$5 zN>u%4<1Td2}L5(HInRq>Ikuai~H(3c6fl9r{yAGU0?9{%-p5fAstj;p^y^{xUa z=^4XALnNIf)f<@_%XzZtb^q2LbZzwa86Lt8@@K7p%XZe?K*p5C3aV_%B4(y$N)pI_ zh?*|g&B4V1QFA(zUp|E`u{oTJJA-@YP#uqD+;&=AF)UR6E?v8}GT=2DRF02^rGW2?mwgZ;BaO z)nQPry|(_l{kF=}hDD?mx3OM6xUK*>+zm_my?WT#CgE&n7iYUh4VI_FQLvN?$@n=Q zETUp16_pJtcA!^2ExDW!D?Ne+s*>MuZuAM>{3iJgogNgtIZ>Ss3OYR@xgxuzEU5S& z?i&sb2IS#=Fg1iC=TM9H=P28uGQ1Fa8%#)lD8a7tRXF`~+3~nI=bpShMBnexWI4oV zDE@YUoI!tI@j= zZGV3xUocUeU)}4BL8&Yah@o-w+-!Vu(u5WX>(@>SpTdX90;)bRqfro~mL5sz|0qxU z{&2qc;#i8fLg4vSuH6^qt?yZ@KpTu_F542Vi4!{8B}KuD8#;P%Q%5gu@92e+wc0t~ zypQHQ)SdHdy_+HIVgwXyW>1{pDoRQpTHxozpf`es_IB zkqN@=saX3D!LAZMxWI|+GF6SHhrDudm5^RXdc}qq4-?SmKZl>6{4j1Qg0LogVLZd+ z|0caK;0{l-i59-w0|PmXD|~-6I}RygCH#N19RaumL>$7`%!^kJEj% z5{x)#%=>$hS_3o&ReQz>IO&G2p<`X-x@(emh6dH}gv7YT?RJzE{w01{g%)tX&+#Zr zP`%C>7>;9H?P*YWpssOvh5zo?d;~~_{3sPi z`lXw^!!7nCIGCa;{XSd=2py6S+&z1Gto@nBLE7|C46F73z2ndhma~k#^$|d62?si+ zmQLQa(|{}M;j*2&uhGTR2nO%^xU8?<<$CXe)17@NzMKH2POeAEf;}dUgcUfXryNj| zBya?HhSYMnL=yK_kwi_egP;asD{T$;22E0pVLk$a{{gB8h5eEWhxj!?RdOqOftCU{ zo=X^J+8j>G$jFFf9LB$)Q0U8C89qZH{o?QQB5$DA~A=41SkZ z*XVVI-&bF8J^h`~<91{Er9afL1bsQk6c?+P`D(P?UaBY8Bu15;Ja*j3v12EU`c2KL zW5$)0mg;}Mtc<~Al)3eesycb(5u=6-8G6LYCmnUz;L$%g?Bv5o9&y-^(MOFOa@f$L zP8#~dA)|lz!y`}9H=4kx3Du+jlyA$%PagLteLp5Ky82IQpl0ltQKK_5d|-GhFfmcB zr*KBbxCtlg$z)_q9a%HZdp&C0MDKO=$nmF))^jAN>a@F*yFibYvxQ^Uh$OBh% z!<&3IvN1i(#gaTkGh9CG4c6C)?Sv8VRz;rT110w2gFE<{$H=-zhj8m^U0hdD`wxp9Rbw%cm>0B1a)9DT(49V3osvFjq%%~zV%7bVGmWEAt{0$SuI#?Gj{S71Y8 zMGtX`%IGG+i{4JrF;4%VFdz84tXeZ80YI_=?nQiu56UN4s*AXTkXPm8NY{Uuh1@;l z6d^g5c?uv$%xgFc$(G6$eNrCX5E7U51|BsLF5?(YQWj)Rr>}=+|yLe@dPI7~}qQAio1Z=b42h zbtz#r^KdZ0l}hM|U+$CD^3gWmM&(j))^sj?a)T|igjqMi9ev6LrXKvRK1L47hq{4)VXU;gOk_C$vlNZb~amrZO(1e zN*h0IG08AUXcJCE=Q;z4pzFxb@?{K!06jfd1m7um4)Zvkrz+txe#bHMPF#~uxQqOs z!k~U;J)5lnNOg&pIRz(zceAQA^*h6*OYCgFv9rxLwUgDttE6fPn_im1gi14s$$nhj z90@a7yD5_ZzzFI9a`png`p8LeFYppVbHvz=Nl0j6&=z4YqA?ew<}0EDl$aMGSmXz> z_}fePOXk!9bGvBJozx`2A7!7_l=6H*jzTSUG1svxV`g(kgD&_wTKa!2C(dq^18QAPhTX>%IwR6hZhE{kV~MZWx+(hD$DaaEW;;+_1Fw@DsJRSoZ6= zhK0im**QXH6OIkVL>|(9TNkc8QL{b^=j)I;b6Nr#_}q*pZfbSXCb&%~cp2oDcDE?; z*RpBKTxquQmU~|6`liWsP7fUHxPOdjAS&|=krzVd>#4F;J&kEzW%tGrC*j4-ms5fB zPlvbHCG$5G^#Z|-q!%NxM`mSovIhbeEf~O7LJMFV-;on0Uwb!VL)SWaI0=YC;^d+D z29HcvW;&<_7-FdgKBw@%of6z!gdR7!wEIyAhwup(j>hS@aGcvoXthomjLm9paR;=` zL#wnU4lo9%0vwYq(y|Bk0BuE~WTFm^X8tG4fLy!arz5v*uc6UH(@-E?ZEveTF&DIQI z*pfNv7zXS%u$3U&giLV}Mg*^mdCWbP%}Tx5mm&ePG>_F&NRfCFfT?+O)oiZUSt>a<7l19u3%dx*p?y(d$=v@Qt-YA zEHNeA95Cm`n`p$6Y0{2?ti`&5l%?YdKoZ0)`U3`D<>YBN=63S#1F)$9d)?Q%+3h1M25y4bkq3$QC?0qB1ZXar!e zM@NdhvH)XOc3ihUYKhUre&2|9kXVgi zKH;Lnf+-Ad+40bnd)ynZ&*+;|=%&^z zhEIt-SS~_;2Edx2P9UGW;!4g|!4~eyq6WIh0O=>WJ;ZF9)s1_jl%d^bhX%2AX9G<) zC$Mk7CDCjaJ&u&#V)C_NsO1qVs*PgPR`1AH6aK-9bZnzT>)bkeu1$b zB;CHzva0L0uYaN557DW1f_$|<6vQtkT#uci8`jeonQjxb;>(<(n?NtNzc6X&p&-Y6 zQh2%uClJ3KE;)rr^fdbkAi#2KE}bd{5%K{TZsD_m=9Q@}&c86~0iLY#4(bUVqO9|k zRPKtb(=$5I=`ozvms?-3r*ycQ`}n%;98Rd*&{`Uu!Ze50(pA5Tk z9}$ZH)0b@Bm!>wF3)GhRg6^~v01oeN0nNJzngJ$qnPHjjdND5DKuTPdh17O+vG5Fb zygnp@nMWH0xi<(IChdU_xwmnNq*~mpMGG7<|CBJ_OpVo3nBT?J3nt<2qbqWy~Z)Rj$GXh-u5)IXmDzgn63Gj~S}(n+REgrTqJL84>$ zEG}R#akxTIO3Y_4!2t3mg}2m@saEGw^0Q*%#eCk{P7Ab3pB4w&Z=I5}cwOA!zGaaR z_}WrzYW?DNn6C_i@iQ*84A|Qpq=*4L8`2okr1oMX!zu*H8qZN1|j9(scHP{%o2L4b#w4u7Hdg4>DJ&K z(OJFfzf__Gz1TH2NTC@j@aAls^h{kVR@C*7u~koseZxNI9UFXJP!5QC*vQ3a(;)fb#=^ypFEegDo-5^}4A{;E(j$WinS@ zo&4dHT?A3;0xh64=WL1=ut_LlLwJ$AJYrRXV7fMgRWU!RrFBWe=J^aay`Yal-;i?G z(w+v?6Cqt-1P?Z6z*3ois$|>NnNNr+PFfT$enW;nn_|h(TsS_D3|$>@$u9?wcQJ`iC@jE~vK1qodtUOC5ACI9RY*#4r$nm_6Lzq;LI)Ttw@ zGcv|cIN4f1Fh6;Q5=#slRFc<<-Sza?<26V^1DkUE_V=*Q4`j?SBNFyc*UyO+eH=c=1_tLQbPD-M$3;HM4$BBnNwaLhj|v&_y9AXOS_7)#;t4U z?Q6u`jl!6`i!CY>QhFiT3v%W{!U(|+m%=**HS*%H*u&}ytU^C0YNlr;PV1z^IUWN4 zb1%d~J1^^lmx1ASQz+ycbF+MyT|utTe~y+H*N=cmyY=NGk3De>?i zuaUU_vC>pz$HNB{+5vwxgOe@}D|imPtXI^nPe=#lAhQ>1*IQ4t`niX*p=_sC019QoBVjKTfXvcf=$8TkXZ_L!Q34d zul$sh@WHdy#Sya8$s4AcTj4!WdEaRg&XAwj2{#iZFJ;2Qc{^d0`Zj-6CF#Nye}m5z z$5>FgdJdwOuFvKR7?t!bj68k3%jLkHT8bX=RJKN0XmMu;<9XV>o z%Yv@KZi+-Q9{y^VG~REC^UdmeE|CwXxnQjW>X@X}r@>s@6v-lvfkwDF;(?pW4w>{Uvvk zuRHD)d)|>1UN%QRY^9s@+{+>otmR6rQ>UN+ZI_?dy6B5SC%_ShB{+wSO70TC+X`3y zcJX4pX7ErlUNr0-UhHxalmuG-wg5{WQ>!ayHhwQGDe!mveOB4k4@}XWZ=E*l-P5MX z{2on<3Kmq0+;%amG1?VkoBAV{R&^S^T!hp~P%ZZAD`P~yv3q=rF^3qn#Eyy%!#xSJ zNgXTut<<^ZEK|u-Igu~fE5wXNm5gg1p2uvmNFDgku7pOSY`|hkF`<}swH`E+r%po+)Z`y{|mC6g`|yHkMhs%ryz)CSo+Vi1jTP> z+Jh;XzIOKkgnu(oz*+h;$e*t2%g*m#+i#BaFn?f_qCMLPqR>M%W>hNL6p=?2#{O%f zW)um_l~FZH{H!JdU4g3R=}DqsqNsmBdq(x;T;%RP_)j2X7Fcb_ScOwYDu5C~?55BR zt*jKGRiq5ekTNtNcOuZ)=AP<0OXmPg3Zd(+&zfOx@OW`~p8!&Cb9sREi<@f|Ou;4k zE}3k5%6aQo1xSj_M+KOBx@#D(jL|Nqhcz*TP~DMVc}AU+8FRe{GHj$gP>++MOM}Hd z-O|rhPG{oIS!8_{y@`!<@-TX%*3fvU*zI>4iJdH*)jjR>@4&~YibgWT#=%29;iAlztUVdOM!m) z?25b=hWkZm7suEi2}q$KK1@KIEVkVE0tDCvS!Z5XupcW%$SyXLNht*tA*Sbp-#`~6w%+8QXbHmJX^e83HFhUKc z{fczeHYZA#M*k4E(33`w_Yn8)yW8DYQ^F>h#-u)hL}kf}ypFiC-MK%u5f=;!%nI16 zVn`ZfZWAyTq+J}H3nQ;--^JbcG>Bh08yNo%FtrPDmwwjSj}>9mMfd~=ui$lVU`P+E zlxZx_{9!s+wQ!=GDC{N>)St^pZoosy80PA2xjcBARsvev<+ESr{*rF1WVTzf}dM{@dk#` z-84znpTsM=A_qrF)5KbL)m!YUSAv{*re$me%yEH?k8i^ZIPLI-8j!>+_jq%8$^8Yu zi*@#WG&4Mi8+3$kDUj$EQ1j(PXtC7%X@%-`sdW=#R;p%rFmq)I5b%>Z9;JNo*I$ee)-!TVCW20+&e*mIVw9)Bi3GxPl z|90bcDz~PJqF6!JkV_$DBeF=k%hFwTu$6q-8ER2tX&NNDpvqe|!E)Vc6&8ArEA7a0 zO0vRYDmjV{)>Xus?U1i?|m5T<}K1M6|vtGEVwrZ zZJS`hv=qb&R?foqstTw~_JvLjPVd+%^bEUL0~T@>2B7Yw0C8Eva}abPg&m2dc2_l% ziVi|$8Y8h%k0|8mXtqbgC*kVy z*y+1O0ve0LccU2a!WA<=2KgY;b^EhWbTgdkhAH&7_RG{T#H~!58_(ElDY4fLxqMt&JmbA=jVt0T zhQchnt+gM|cz^szI*exw@L?vJLk$+4xB?7fUd(1SL5Slneu(27fVf~f$0X|uK>$^^ zS%QH0ax1ik*Gj(^-VkD;7gdYem%+mmkh~3d?^AnM>l09mSD+S90kXxPMB z^>}>-3OO*@T#H_%;Mn#N>aJFVarQT0ITg0HjuhYxBM9E(s-v4pugi(hjb{i zzqw9qi*&bM{B*EK@zZyU2{;?VvtE&e3DYfkX-Pwb8_*Q>679Htjd{s%Fh$>P;g1aR7X!b4AhiQU+{ zZzg@&)#T3j{&JdSv7QZtv}T={lDe=R?94^zziyIcn%jtJN!l~5sH-tclE?sej-u9Y zW-(B!?=s8JXyk`dRx|dy3+i~CW1bqPa6U&bdHQT*OBiJtl|K3NcoyOjiO5cFZ53OIA?5hV&lP7VYr_RY6^9W4eo(Btf;F zOZ>&C!=}~Yf0>PoNDE6_1-E?|J57OKdHD!x70g=Zf9Wnu6oesZMH-W8EDvzz%{e!U&U{L}R!W&#Nh&7G!n;Tdv^a+9V@(fSE=Lorq>okNG) zMGkCAIRe9H`sM;(ca8ZkbpxfrVnb$#&QZb6v)H|#SxH<5E&E#qzP3Y#z49cTGq{U( z-rCSA_E7ok9CoK2sjKwpW>zW@wzL>YiViXkMp)}DnD*>EHfC}#tso7jRmLc-nv;Qw zWQNv;X>QD{bVG&)%leK#mG{VZ6~T4x_uf<H8Y#+zv@U8MPyK=-j7e~@7h@RxB7X1N1&c2)~l zKqXW~u7TMhr74$BB05#W5X5=Y!08<4M;t;B#NKGgR&#Ajwq8)~8B&^gX`TME`Jn>q zW_$Ue(k-0UuppzkG*}{+EO#T(Wpku%3YNPrZjGjKb0#X<9CJ1bR>Esc6?zc?1 z=jl8$#LOe%IfAiyfpna)6R6aP2HQ2x=a~19{3GTZd(L(z8g40&jG42zZA!Q1%!n6+ zF6eb@jy2d*Yk)bj)K>aeF)X+wCfsi>$oBGi1mC>FH(ZaWk{9A5c=KB>-`h6}(hl{x zyy(FvxW6)cFXTw@+137MUZ9`g#ezztU6ae z=c1R^>ODUVW-!R#=7tEtowRmMvY#wH~`tZS6RT}h{5b+?0(h)Rw zPrIdS+bw;dv!b|}r3pDAY|U=Nv~A{n%=(gKo3m<=thq=97Uf3=Y00C5Ew#Me8vd|$ zk=08XS^kIZeLs_M#LPX#ttHvnlqee)Yy&~P|BQOl7m!@y43C69)tN1H_xKilmODGk51D;0ead6biF?E{00?!0ZT>Ja$z_ zTaI~#ynhs!JEt(bYoSBz8C{D!Z@1H}QwkPy?gphXa5$*}yYLBod zbh15SFYLn3VV5Tz&GK+zsl@6g9nArkmc-nqm<_-T9nkLa%xI&A1WfLx3g)r6v&VJq zNcc=wM{4JQ93efL4<|JaY9N+eAqXM)evxuuk!TcDHq3 z62hZ6AIHrOJ&F|)L}5M3s>UXU;H_AO6XeLm=u@WqjRez#?eX$WIWX-e+6$=_M;*5rbk>ElPG)R;`<7925C$`T`MPERQ~ zb!5${DFuXGsY#q%GiKb$coO5-$^$N))gw=Fy*+WGJ*9d~&189grnuC4uAMm2dLFW@ zK-JJ8s)xgE)!{$zo<`Rs#*Fj*QSlvRt_;#Tq4MjbF{iZp=C(T6w)%~>`km6g=NrpY zvXd*`rGft{uL8eT%1<6M{Wn!(Cyca?w5_32THRoFp)*BB`f!i$} zvUm$u*$69?PaIiYV?AVBopAM(;uITOcDCMJv>OV&q9oD)n zDlv1z<>`OjgCaAnwfk*rPZI*!wzf^Jp-;BWaesAp%>^#X@HJiH$K#~k-MrLUQbE4C zc|3CZ7$+LV5^iJ9gz$k4OS;JN2XS=BIV$e)g+bx5Ds(-F{dz>l%Z$e!#3B(sN}gm~ zF?*h)JsWxBcb#=<2y+$+I2mop(Ms}HI4c;8Gsh*UTtuv!2B*)z;Wo2Qsklg>CGIX} zZiYpT<3LwmqZ}jM%-P)eEwWBXD!rX3m0X?%K1IWy7g)H+$PJ<}SI>6gX~&3^sE#42 z4+hjsX0#3lq_Ny+q!COR3r_BgrD7kArBq|VU>z6dxdErR-aGAhUdp!sq8xMA<9KBC zHoqfgP_Jl{CJi79fZFoYaPWvLI*=DBgv?6zEgnQFH}l5rQh|8~yMSP%NoQCyl9V#& z0G$1{I>p1CqfZ0OZ`&jTN1OS$MCn(hxr(Qwx1wX3RZjd7ZdVg_8#k(>%{-zw`Blg) zWd48~b1|`)(CIZ7d90M-%*V6Z4#(+ZuC$|P zK#ZOdYiPEYFG+f;c0R=OSiQD-|9c?e0z4WPu3Tv%?5p7bTke+g*{4AGUCMeQagrU; z&WA=o-g^r*>U{INv87u zy*(>dZvmIG)RzITcaU&X7r4PW`b7Hz+LijIHfibW{iUySm!2>k=vDszTYAzVL!R z(zhQAqC8ojT3@)>%tbs!3PwMSd~ryDwFE_EHpU{vUxXUIzpYp?$0Fv1Qz}(p9xav( z5HSy)g1MfAtuS<5u~Qy34cPWJ2k5>;7jwQ6KDUvH`XLk5xiS%zY5VgG^kn(56P==| zBnmqLIiuV;H2QPenXYVIMX@WK{6Dt$azIBf4?BX;cq;ekWj>N?j8_6=Q2__BguSDNkp*=qqwe}XDfY0k+i%xB+cc^+Bw3_qu^}uecK=Z{-cx% zIm0YdUiLUH5nK~2rDUji&+!69O01%{?S)bZ%RGb}v}iKsH=Bl7($L}r!$UMHQvj0p zxx;hRFt|O0G~#=3nWfCUhr~wkv@Rp~I@_$4Ysxk!`vh9jX@o%bEWz@MhQ}75KA&wR zwC6*FAmI)`tsM(d>m{e8yLj4hZSlsHr*XYQRzVnX^GYNURi4WX^V+GE-1|eixizE$ z0_b&aP+RvRReI%uKsR$eBB0*?mdLh>4E{+%(O#C2pI8WT%^Br@*XEpNRyTChH#ug@ zcttf0-r6WJ7b>0ar?Vvoxbr8{31Yq=k@}!7xxS#B-M7qX!iQc@i}m!9o^ICDc0Dc9 z)605VsHYuzx@nFCza;XILKf)wISr#hdG5W{LyUKq#22syuNw`9Pc0#dIep<;;`5&< z(6V%hX|5bypDx&Y{fa?Qzb*T)U)$wVoe37%?o|IAT}qEo>u;#CC^FGe&8%#Hd-QG%@sA|Hkt`M3(OaflcX~82S>V)}ScENVe-hfIr5g;W%j$44 zm|c>z@9($!zNyW==lY^nfi3^}G@3qtHvfD<-Tlmy^5K18W`%R0X)@YgcIv4#XwUch z-cFg_9ZZ=?ZkaB^gg&TAw>Tb{Sp|3jN7C`B8EA{0&lN;V688ac(ug9FFk2x6?hG`W zW+#;1R10vR#%93;g8Usy9v)dJZ5EUo|E8dXnHD;(3lrNp8U7}4=?Tv17)K4T+CDqM z;AA5wYc2TfVVBDXbc9_YaSceJ9tje0atTn=J|RE#5xjgjXR#QcDtxyrizs3SRB0x( zaj%#akuC2;e%d8l`<7R6$8|e5V4zx!gs5kf8}OM(CfF{d{tO%nj&hgJ5LOi>b0&&6 z88a^^hQdnt7TA@jc~4QVlS+k?&@h=HQjxM%?C6N-sk2rd!{Ya2ppee|`2}tqNox4K zhMbqr4|CJTQ{e9d9>aF^ROgPms^9lrwP7o~S?$xVEP{)r=opdMc3!krL0o+3tr5lH z%QUa!;G*Bx;vJ+!46oZu|NEJbNT7KjUNar>6GBaRXO5fot!y!O{CC4I>&%oXW_>2v zOnrs{d=kT81DI~(WY3E#Y-02$+7h?UCb@&0%c8?-;Ci7zNX)MY1#cwJXGbXLOTPYJ zwmztpA_@jFp?yegNHL0EP#?Dn&G+ovbfH^aTek#X+1dY_S;dc1EkDNch~@yL6Gd zRZIlph>4$45{QWx02Pl1vtpt-k9&2gB4U+O*5b0YY~wd(64V=6$&$9kg^KN%FpI`= z^Iz0Qma9JIozoHV_9wszVj;m$6rfMRPP$wU6z(Fxj|?vB3KaFy-ia4Ux?xO}6Tg&} zC6C}R`y|QVMNFR0cLfMA$f`k@B^{NkRz8^yTAc19QtI(?EuM+qC~DgqMPEA#*9^3- zpv4JXjhijE+S^AeqKMj2|b&huG7=&db(Cm zZ|Lb7J-w-?t1Vjt(|(Q^`meZ;lOjF)q^0$=YdrxqrKGbiiSjUx7>RJDllpp=4O4m% zxL%;V?f5AFfSu9g~WXAg5C3iu+s z%MQkDe42JyiMgYT$rRnkzBa;F#){>-W+wwD*f2 z;L>J`pH8VRyDGL*b6KeLmz+KsXyC?Zb28H=cB%AC?eLd>@^MtzdK|H#x8Nh5EvNAp z3l%>{D>N8j>B5hBA8%Y4n_a);i>8)B*+TezqyFK`9o9yjB=|`JlFvaOPuu|GS(Vs94(qsT3e>`|xDjQ%4Hp+te8s#n3(*_c{*MrH60E7z2;dzJn7Q{w@s0l4qu`7`h*+#jrP zhE_TQ3GDDVNl{=eSMma>qyldJXHMQuY&Ly1N?mKEkqrWGBknN34Z`me_Y`DI0dGi> z+Wnq2sx=zwSJfP78JU>1#6l2-3NeGbbmlEm<#jVxg(@7P#C0p@x6<{QYvJo-(S&)O*S+{v z;dIvzcyUg;tGUus#J6uMl{?$%Ix2S}S@2F<`8rjuMbOj*m&DXaB0cbk{P#A&dW={b6q8qVT`F%bD5b@n*ZF2>uCI&RbIrvZ~e>idF zx?uZIM8}Z|CT=ZP(~fkqV?SeVB~knM>vkVcv!$`FG>~28XZ>)lwUSTch z?{Io6;7;HzbDAly$3l9C!oWK$!dkop^URMcSu^w#tXUQ!bAe#Bh=2|&oX!KCE>n>@ zrjzt-gp>c@PG_zk4{|!sbNWuB7MTMH@!$C}r(iO6KVpZ}AqXrW--bFi%^9U?i{2E> z4}UhmU&sZFGQh17;mWa&`$74JNOE-4`%b5GZ~Y?W(tM|2xYPMy=g>{;WXx$a+W82l z?{pm0G;#u>JZ~q}8Mu*zE;ifg+<%zUWtkmQ=jf5?gFL#OLBbG*A#N;tp&_Pwrn#FX zP*S9n!09!p<0P76E>P#_7=Y|0l0>Z>%AA=LqoZ=fm?sA5CHp{8Mhw~TG zgQK4^Q=0SeJy9YAz8aH2&YgwS2|c_B^Jgz}&K#IQ^HoNz^RMPyo_m;08Ke*(6pSea z65FU5o>AZ&#I`H6eB&rZFthC{KU2Yqm9%})9Nm-XS}N{#tD9nLIX7kawHcB^(iTRL z!L#m6T4A{OR~l;c6jj+o6?X25FbEH}S@L*GXQh5qSjfKU=Em#lO`lqZG&pgVKKTS2 zNrCw-@gD8%R-}AWe`xHKqcvDm5#KS`Xsn)Zs?_1trV7c3)Ie;BYmIW&xR&z%+LMaH zhVA1`Wl&ng-B~)_J`)OKf8<2jDlg4Mim=VV0Pkrty2L%G)G1N4JhzPk(U#jy6Bx`; zkXbGi_5GB?4KZAgn|TBc&0@)LFG`xbMNhxe)2(`XK~J~oX`7yI*VFTQxa#;v0-3!Aw;>EIJclF=yH#w)hB1hngyuk+!N}NaymS~ zcRBI!z#?D-RriRgjQ@%nOOTMYMih*6idsIl2VMYsM@yN&KbX%6n4HG}nL-(zye22B zN?X*@M=}BlPk!Z5%)aEW_sJ!px;h}21n+4>E}`+{4Qz*EUc-*dTMB6+cg$axG`)yL zwsZKvZX6U1=0@lNJK=4cM$DJ@feCI2v5&DkkPPU|h|<<=J_8IFW%~FGyS85w(Kn`q zq50-CDAU=N_! z40h|)1mD`9(~E7kf2Dboi=ph}YaF7$kgA%M`k7O>((s4;BFoG#K*vYm8RS-KsSHuP5?**_u95PBI zfsJVDrFu$vuoUeMN91LONIGjz)iVi!i_3`~pE$#%Xhed>7knlay%5Yi5%F0&R}5o2 ztl*sl759ilnI#fWYTdxJdo`LTX2f=hNZdyV2TLT1d=~Or_({%{xVgVT=L)VUsEE|X zvt4S@3*8a2#-ARNcBB_7l8?d%V@jO^NbO`bL30VNOR0H3x$ttY@V(^1E4r4H*{bi1 zY36%RlQgeu2`aDuR&3%NGgm6sSK(Lb<@yksDd~`|W*78FM@Q%z^YrNz`V`hv$Kin- zZ{5^=>z9;rvE>1;^z|{Azi4l7N(HoqusUP_keqb|apjWatWtV|1-?1N70Q=p*Xcpk zFtW*ap@{AJ&h$DY1B`vP8o+<4jR7qJd;{B><)1Z5U=Jq^dh+PGINXm~tq3jkTO^at zU|-Ir58K=QnYtk!NPiX7VtKv8OiDwu0H)lAl?;}8rDe*8Io)D6;b(%eg;+HY(P3{+ z-d-hUJ*<8y1r^T0mG;L!+8;lv;ub2)u?8UoL4inij&r{Ib07hI08~FniWBA5167oM z!Hp&nbo;37){rh~Z#!lbRt-m=Tp4D-tsPo+m@VBz|1s$70}P&Zdz{htG+Fj6g$pWh zjdE}?FA|Qah*#GUHxJRx?Cb<$G)+XkFS~@UViP-ooApJoQw#C!Dqa@5fr{PC*M*8d zm~Xy0y#beGYjsdSN!ze**toH);6KzXIUVf1Z+4Te?Y^inFD5`(il7)+iXs7c-Ud8f z$<0E7H)U&11|3&kZYPR7s}`= zO=l4|gtwgTCNyjv<;RTD#zu0}6S}i{xRZcdX4ZN@T}v>+BAQvRTQg>Hksy~o7gVk0 z`fN@Qq?01?+Bb1ST+m-ediZSTShE1$mKWw8g2U!7)%Ry3`SdnlhpeYM_w@@^A>Z6R z*1GDQ&B_CB8?xgY`AAuSqkwg}r~u9vbG0rK@9X3&wP%OR4cR!=Bn{TBDmLCLNChC( zostT~>P81oo?H{Fxsf)HFjsKrO)K&4cvl^K2^37fKUCsz@{vsjJsX|;TFcBs+ZTmP zVtpo8ldP}Wi47Z$Jfa#f^e!*mm&(L|dSMngvnotNHn$*p^o_{5^g3C-VD;M78+0G7 zahA>POh$!1p5~%nu(>3Hxjt>@I*iDbKS`b}Qgmi)86`^ZSf)Pg#NHqZ zXAvuK%>*W9e($hsW&szcvZr`ZDD%c<79fuxe7%8+B=dRN5wW@&m@(UTWXFrfS{(k* zC0r)(!)reQ$7221QeVucojy4Dmg0O|DSG`rk+vC2fq6CG4J=^E*@6i$Ep_h1pVf4i zYP!$qsX0lrN^u6BaX&t^zlra9~QxWuG5RW zDb7&Q$WJt7P@!&G_B4fkg%&XP_|DgTSjKO^l=af;6(l4~D6$wt$* zi}_gSlEyw{@m!M_V z=vzD^byab@Bg1Pq!hwVjR5nE4xW2UT@6rBtIR^Yd>GM1ob_VDAnb130WV zG$PZpXzN6*?nj9yr+1JILIK;1=L6_d=7ct*%b8=h#uI|z2=^xdZIXiF0pC44AX#0t zi#BDXBh*&gwQe3XnA_(Bte=a-@6UkGe32_%-DHt`8a`Ag{fh>+03$*rHb)-D1*EXV zy?(3Hc{mU#=M6nAciS>AQK0?s{tSUD1Q!K@Eg}k3Dys92p+C>?>@id9@4nKIO}S)M zzd_*=NDon3@RN@+h)=nPT?|ikCd<+d>PP1&5c?QBgG#IfH?EJCd!x(f-Gx~@>nbY2 zV@8j0_j=H<*jFchtZnv>Ttg_PnX_oNBuYZ;=s3qYKrMMJqt}u%FdPwy4H{W(N7v7B z(p!JTzUafQ<=|Zjuggd`_&YrKd?Rf!ErROcTUG4*5Dx<{%1lt@alZ-&G*yOiMyFT# zod=>yvW;~%TRjkg@@+vR?sl;S(X}p!c7!-(Vpp}Dz?&94zp_m}<$-6B1&`*k*aOeJ zq*ff$sV)sX?{);950k<3TNgYZw*k**%$+I4%{mV}tJ{F*bHB=aw#qPbd7COL;9hd$ zuxZbOcsb?<1V1@QZ7Qz7HKWm%tvpRWN{RM11si+cZHfYO*=(sl+1BXBctC^D=sz^I zd1#LQ+Kg@ZWZ}Yvr)kfapEWv#Q|-2F|7dFGVA8#<#sfvs z8ddaIh|W8iQjGXxJk(sOF^+Xd1g8vWozN8bCnx)(c7S5VGy@8rv<2B-L9x2xgYe-D zK{dL-KdWH6{YghTt+q?Kued@}upBKMK(Y7;APU2CjkMfvWK{5wkQ(mg4C$>FGKW4q zH@42dopoYj*NoFbMU=E-sQJRNKg?XBP>NG(%G8mnStlZ$h;#PBIM(mg*#a=j@`0UH zS0?oZq=$lcZ9#XhfYbL23UvA+vN`(?XU($QckCYa%n$0EtQx2H0^ln#12A3Pg)3!% z0_8nn(lsu)c)WdL;h}j>-pnZip9BYZw*TZ}~365(O^|2;glv_`vKjI`-d!bT-j~=4sP<)uX zPlD2i+btzJJxV}?ucZX~0^3&1W*f2cm*5C3B2a(?=;b5wvg4G}EBLq(VjKbN?{#YC z$HY4KquTHO=yC6(cfF5j3IrvQAZX5oF}94owQ~<(1Y4R^{(#6uL{anC=kfEQi7k2v z=j)6P=5`D8|A+B@;HuQTb78IsEn`KFoKhDIK?=3rVhKzxmeE5PG719)dBmJxrc`d+ z&*{9@Gs*6)je$n`xoa2nG}!jEA1tIf88o@vJqz~mP;i|2d^eiId@i(g;c1R@b6WFT z*l1lOu;s^wgQbCGx(8;Cdw>OotU53odY^9V#&Pv*g? zf$2B#zLS}kS4zO(3~+7)f**=>O!WLZ6XP^EeSWB=44r+0`3zkwy^bh1dU`{LY5ZUon7s8)+HR@T>;8bi^*TOZq(XWj41J=xW1=3OSQpGJv!+ z=F=Jw&@|>yb)9C`$mn}>h&`$wYt+KSBdiz6a|4=Kz7b6#28tDeept|#5DhR zgI|E5(H7`}vTAs#S=)trvkP^xhXL5Rnrz`N4ypsVYkKz#K&X3iM4)nn2xtvFkb{DP zxz^-6U~a?WdN6MSpd4Adkj?;@2V}0jT5ERNI#^@FS7=4@&FUWH?{vWmbw=e&zVrcR zV-Ib*6{Ab-v(|sbXt_ds(WBn!{SyJTRUl@FtO}8igfFxp&8$X!bDly=^XkDgOxf#E zKOpRB9Fa8YC;d_1KZ0Qa#{mh(c*SUq{k9%LjBR$j?|S3C+efJu7o{-7t`c%sG})x5 z`1HzhXCsLEKAgq7q%G<&C__~`Rq%OLKz@lpi_Y0K4f}`|alg%&; z{KE1)-ZYHhxbs$$xTJf$%afO~BwWQk07ncSi(7rAx2gxp#l>+(?yDVerf zcwJ4n|2V(D&8_ev2pGVCu-L$*pobK!=4k9+%9vwvXl-Vax7J>PH;T*y# z64JK;g6`nj@s zA8#%Jf3rP~B&%)i;)bsKD{V43Jq{kFS^&zVc zPjeg}#rnC2`K~=b%v1TjKg(Gz4mABNuW0uy7ssa~e8p(QKhAaL;U4R>0A4IVO*))C z;qCV9gm(v)dctd9?Vj+KrPJWHF}QrQv&SwC33kvw<--Hvx)}BzG4shgYmbk4#qaT@ zD({#Nq^kChd3QJ2K$hA}dn7^a4eXLn`wE@*@OCMuz0Sx_YtX!y>t{8)tBBIYJ@I4k ztsL}i8Q$F!rZmyjl|W;nMSs2{$UW}=BBD@VPZY98`Xh0;G*Ioq$u`I2C3yL1hlmyB zV5(?yF!_5$EWNu~#0&n#1R?8;Bfgj+--FPLjC`RT@-~J{*#hE>7Mb72EoptXhazC< zXiYuBAiRGG+34JXt|G*wu-TVTniEIS`oVDWMb-_hO3y_JX|?-aT8aJr>aW{z0n)3uooe372p=Bek;CeJ z-0FKrTg+T8DBwo+L59=-IrkEtaylB)-+;DUsu)TpsGR6k`hg@`H^<&-`B1vq*nhes z2s-*UBP1m=K8@IGj#1_)dsPauIip0TWjP!jgnZ;wkecqtX8swR-Dl3hXZ_z%Ayx6% zLg|^lbt`E0OeE^gB$Hu)`Ifu{eXzun$V_o-{ z_6#DOmC1aI1G&m{52TV-4lu9Sh&5d5)e<8oV_qf{7LFL_wHeiAY2YsL!TlKtGe9?t zaWm2TqqW43mfSrV;`X~>3_u%cdeu|tn6<{!I`{EEeuB(i_T$aixBF1#e$v~y6AS7* z=ht~X?$)_}vWK}rmEZeS9`KrZylpdY`gNZ1nz_qwrk_8WM&{_m4{&luTJ8FAj2!H4?gkj;AF%}vJoufuWoSQ zvWa(2rGts0q@4aC5A$$ik+zpr=;=zjUW9$fk z>7L+Mj+q)``{J(J;IOflgy4RhAK-CQlIUnAko{jd`IDeVICxlM*piF0jM_TCCIx2C+XtKfcdHIaGUAy(kv zSHduv^)!aMj%$dtd~dkK8L-mH*ScqMuB^k;YB26c6yp`iN=x1#3&84dRq|hbx`aA| zYN%5r1pwbswv4h2F1zD+M?b5>m1*m|#)YoxtX6UWDs9kR+eW&;|4@JBZM_ahuNbi- zStIie{vg(WEkKsXy+&f@VkmhIcdpI?b|5URJ%hWQJz;~|FHk!x&aE_VFOpf2Yf{2A z(_2^{F~6<^*)Y?psJn_7*$d!|e&0%3EDGBD4NR5c8J!Y24(fSi4wuhCz5z)&HeL+J zIEWX|s&J8_c`vY4lh_fC(bP@AWCzI?`0Jyv)-T6=W-<6?!t>a==@Wk6f`=TgEaykF z;3AYQR>R{ThG*AFRN_dpD#W&}b5{=UPG>+3g|En@?G=*Jjgr@7zEnvv9ckVT9l=!y zb?cEFvohG%x!5LhawJy3)^0^ljxTn_tP7=+ln>mA{u*bAG)%zU z!^r>DY|V%z(vas%KC*0sm%%N-lS}P2CUYcETS**J^B6Z{`r+h-GvYw*gr1F6k^4)1 z@Snm(6EEEUZsBsb@F}@w-c3{*mSiqYv#B_EpLO|^x2ksIZ{R-UlnZLDn`yCjtzm7} za(-fSe!wUlr8@qVknz!(^=i|v!9#7@jJDZ5bkJM~u0!ofe&<<%F32vm1)nFlZLAvS+XBa&J6S~cDhAab<&~ z%QcJR4UvItyB8;0kQGxP$L8?S1uAB zocelTq<_5yp#JzvVtDq3^c!=Fd zh95u(cjp^4vX-^Z#X?+6&oK@%;CTQ5``s+gf48K;FL2GCUX=({>eJeKg0?t2a$u1L z(%8uwNS^8C{i@_wC({S6ARL!a7i1Zmo9$v%?4Kfi!Gp&^D#c|n%i_q%eYLCKWw*h6 z;Yut|PI30fL=FVUzBG+gh?%)ukfqw2U=^q8C7kkwK;VmPz0Ei0C2TO(4>|I54uzx% z`DnJ6XLWvdiEZMW$x21-nA*6Pkgt;u=J&|EYLWh%89EI+F+|Q#R}u0xiFLgK7dl_# zIpY?1M&X0}W?+Vr<*%T;T;;I^bdhU51k(>sU%cp{F#iaF%9k&kcvM(2>9SuiZ^TC1-`QGj9YMI- z4YJ7>eh4d-pgBpM(Zd-)w)v(&Zv2(phC!-DO^yGA4ELPQR}zZJn1kdIPF$y!BuF1* zUh^P*gN3wyyO91;;hJ1XCsz`rTPuBKD_KZ)T2DS_8n|x4r((by=KzX;#tkVO3tt#|sgXA8XcozgKr{AO?h~)P_6Oyv40BA?KQ|wf4?r)O>hqoogat;ZXARX` z-_`x@A;I!8>veu0RI3}6KRmV3yC{ik)~SuUF`4vN`wtY_B|oD}QMCxQtpM>~&GO~? zl3T!v&(Q~OyP{|UAFTsjl>U-SqdrO(DN?y};CU9dU$wpfli{XFq01_2WpUhj5{MGh zAnEEU@OmM{<(eXZI>;FW>+Jz#VOIfuka^kry~z8$-TQrWSMJ1_;o9MY%-Mt+6C4(I zZ2-lvBHTDz+jx*!bGj~*m6+QtfCic875(93mdn3W>O!^`mrw+(&rYq=L-Jpt;M0Xj zpP*Z-3nh(%co&DNT*S-vDd!S0szx~b3Ps<|+KHTf*F%9FXI69i1Sh5T#EN1(3VVn9 z6)6F1>dnT^`UDE@Nd@n`|&9Plw&R` z_72Zr(9hXpFLo>^%>oX_9P{>Yx9a?Xp0InczZzVqa?jZ>bh-xfJDBz#im*%jCC_gM zH?{XULvXN8*u^9s)|}oyqai|pnH%xu6b$stsE%wdBz!X+_7@WLf7p8y_^66(@jvP6 z+jKfBNeBT^n$-nJSVTl4E;GNGH}Soh_x^8YjOdIHkthnXb=VgTxS*l|)Nu_UxDo_h z1`MJiqCrs*HMpRH1l&Lr7u@}SPu0CQ-JNboAaQWy^HI`wt2%Y+)Twh$o#om9xKVp2 zAXof2u1q$R*#V4%tP*(9E{y63B{v4(^<;;c!;+GWM%}p?@}VMrP*Nq{#_JEk`E7kTAKUWK=-pgcdE~yZU{mg)Hn`E^M2G|AD;p{PR+}$NOnCX5w3URyb z=62hyDY|7gr{Ra6?jtLczy!;9oV8O>J0 ztHO0*1HW&i{$%->3Yn=D0q{i2Yf1`5&VD+;J|c0}S}34|9SLSoV8t0X8(#y?b@be= z2_O+UbEj66=yR0k0)_pNZt-mugVDV-$Sgi@&*DF27T1|sWXzN}k#tMuwRH7H0GT~S zI*`vaSd~#wwOIiau>oRMZGgJXVMHZb=8Xpp&QK*~lDuJmz?k{_T4dwJLu`aT>E{SY zFs%@~Ix(%<^>A;BoD$)rEwiQG8^-MCvre)+{a~^mjT4DTT~FdG%QFrOyxd^VnjHut z#v{DSFZ}~&W4X7Id*V~b&&T!8Sa*d!YT3E4cwUcS@wHy^T^)XMgjUxK%Xe>T*W~t5 zH&05mlEpvU$N3GD@>`iw!UZdYtkjpyD!g6Ul&&GvJKf(x=IIfPV^Ght2}a1PoKlGQ zG@J4KlpwEWtI81cD&M}>Ovk+AfX0~`OTddK_P4{zcqv6EHakMKk!4#%`I6ZBMA=ZvjS&?FketA{qeiJ>pQ<|8AR7z>jkIDY%5EMk6XCq-QL;5vO9Q<70l8?CUB-2}nA%s=UvMncYIQ)4~I~g^u-aVUgX!b50A7=@wel zzlEiC3#*+LR_Yd-*J&YnB$2|v9aQ&`16>ff&U_M7kLXWYM}NXz!Rr$CV%~qtdH-(x z{;{?1!vZ#BiA^tp&&1+A@$MBEJBQ1A{-JF_$U@!MiM?!(+B&(C!wW>4bl;n>oFW2a z^F#z<Z&n1 z-NRHbJF^bv)tk)P=HkyIQP_3AlW!`x-;+8Mim#GYXR$Eqlo{+Q?w7KD2*B1YJV-7g z?hOMOIJsSM15C{c2VsX8f(=3nU<6y?942a&Ksv-{Y zi22>uQRx_#2}kEH{lVxosn?_xLzivT+anQZ1-QQzfzo8EI*V)ufTSS+*srJrobD@D z*O<$%^<_w1JxORC4!T;XdZkXSjX<@o1=6-nJ}K%a^6@3BPq4KMCM)-WNwO};VJA(! zIb4^AHntn>pA9p=4P&9;^G>fewyJH|Bv@&xVss6MawKUWs_l8si8G8jZ%2}d4jJmU z(bbHV(hf=G_O%p$lF9!9ew3y5V4^ke(afXBxZUN{R1DyDFv{Xown5f?4X?3+H;C)O z5|rjtq2%l2Eai)dp5qdMjp=ejx4e!dbc?g5?;^sDe$|!{_F=mF%7^f#V-a3Y_StHg z`-GEt*X)hmlk;f%9Kn5KBc^O`z<)L-S!x0_tDy_8+BVi7L_A$6xnH=CbwUbJT>&Pv zs6>(wE3w4*t-1|;9p2DhpJ{0NINi_{aT@wARzoW}4oMGST+f!1Bi~xEpQb)*#^D~l zr>Gmo8uRLB%^dS;KYb`53z7L>txs>#)F()9kd}7rIoUon0DG`f&R=xQy$ku1KFQY= z2&lb59geE59v~~vk}Nsq)WvjifYHe)YnZPZ-rC^icJU#u>E9ktlj zf4b%WUlh{>PT|Kif$pmZb}M3^=)T{L75-|eE1KE5@4pH3HzfAF*5(s4|(ys*&s^Nd{g+!xQk0f)Psj?x8Tz1~&AyVj|_wA9p zF#KM=o{Roq9nqhMsE}BObBKB5iLmzLt(@LyQPRqGE9Wfovyjm$fW(!|qLtQBXkVwD zR{pc$wxJ63Msg*83$Q7^A-8>-u)K!y)SJl_{4L;bx%?FefVcGXVs&?@jNj$_)#-!Z z;dZu$$x&g!Zr@nMJ)Mw1*$%{MEg_V)v>Rg@lEv_qh&WY1cSp7sh&*f}1J!lf9#K=<{}7 zfUIxlm-6t|Uo;(uugsEF=o-B*%hwVZT#W#{- zEW96{$Y6M~DC!BYy=$J#i)xK0ubL+nQBP=Xt9de~ZfozEC*@J!paN|+PZrdD^0Ild z*nMISEZwzwN18rziegpUxcfVt4*v@k{m-RVUa7|~r*ZCA^D`0yYV$CT={O}JhWnNb zi8L!!9}Kh2Ih<|i1u|3eOlNjyp0tDeHB*9w3=Pv$en$rB4XAa>0}R!i-GRdG!-{47 z+=IcS*CsThVyl-}Krr8v3Fclpk>54a;{zES)cGHx*CLUC-j=*B?Av?nUSo+(+6FRT zAXo;bN$stkW@&(|H2{~YR%D0>gf96EHUljduWJG0(JjENqNLk9MY=5z1WwhNIQOU@ zNUvvqW@0t8T_=W2Twr8inKUg*mt)LyKQ*4|BD6XJyy-}b&BSm=h|S(q()J=amutzB z0jfk|Z;U1;S;_iL+-{J$)uPrmC#Rdc zS{}~PYYbWYnvoEw`YIKD+s^AE$s!=>qA5>!o@mO(8)Y+8Eh;?LO6ODqD4{f zX}df;U?s{9DsXftWNt%k*sOM`nlKGaNL4g5dnz48Dtz|qNjQ;I;3!Y7t|jYg#>HYL z>xBAX$z~~1KDz_jUvqyxSV>mfQcJzC5A`gWJ6d-d+b$}krF_;>0cf$l0p>iZ*u1 zT*&maQSVFub=xK&rrE0~q+i7=K^EU#BV+}qsRt(%S;yWA{czyUd+HvofYM^DxBO}q zI<34mKkjQrPc1dG;=w>W7*dbtOkDKK1_?+3RTDXsow^<668{ zHVm)Z1g{$>6qtk4AIKW34fRtw=ZuX)LA(r@5vz4xEa7T5UcQ{2ka|*3RXxN!dmyVQ zN*bQtMpwZNsGG-YrsyUdz!yQJFufWKcT8YGxJ=2Ycd@Jrj&(ruLAd3C*c5O!F^o{o zBO#>y+7!%OvC+j|2Qj832B}xYBz5&Dew~_b;bP%*YYZ!bSgqlTv7%V8?W(MT9k!(F zurcSTbtCawSC6DdPe6q;0iR;((9^u_B6kwl-eN5S>G@^sR(fuKMazJll@xpS5{Q}& zdkF}m5y}Pci`&?a4(>kiavRw!P)n`twnLuwJ#(LbwV&sAwY3+^52Gb0#joC_Ok*4M zn0Y)DQNb*|E0gSC0=KuNPHUgot$nRqd)#U58Qt3Kn62GZ zr?sa!S!o-vGhVuVT+>c(kCtUeo#ZHYC}#`5{mL@GcMu1)B=nzDO8_B1(`VkN$!0wJ>ELO zlgC$*Ycz=r!dMhYA&kjiy_2XP+%`d{`3+RmTV*%l&31WBK?d6}D$Oo_klA8j} zJ3y09>eQcPa`&vtR2G|k3iTHSjti) zvmr96k35_Fssf#E240c$!H}=}BLB%#r|R`zn{ZbQu#%8h+R_Pmt#m1+f}sWjIeJZttMK*)ci(#15wDzpD&U?TR+@p<&DblL`oaqg*J)gT z>Mb%&-7ullD;0bQZy+;h;uq%Zunr+tl44I2G9p7QA@_igUl&4V&Jl*M^%M$0D-!St zJxjL5D0-H{nIM?sU}zW`hn}nXCBAD=vrx*fiJF-`sQ557|7_Gugx|RV|I?b5-%b>3 zeG}928V~14FtWdSPBx6WYcykSD|~r?u;ngr<(DS1=pPV^clAWJ35P2mB~1Bz;mPe_ z$--CHQhEHafljML3zZl%vOjFY1TVVn%i z@Wg4OtlS6eyya&`^29R36JcP&6VHSv${qGMcw)OzSld=nHqiE?V00A3G@!@kgv-Q_ zbFD_z!>Y(Mux?_=aKaw4o7UlkhIa1J8#=Vpq#OF7N;ZZ<50ecmtiELP0%5_(9s%`^ zLK@8H1a={nenl$$XA=|A3(81^n_Q{zxM=2cx0VXulDOY*h+Kk)Eb#{Yi!eP*AlT92 zJ`1!=xLM1D_Zpe-<@hpT5BC1YC+MRk^{iJyT?(ySu?b`nKa?&4tt~IU$_cRFzamN= ze8d3o0#b^R1NXo_C7>~%$U9+QI3WTma^7+;ounXXX87`vrlwB)6pn%Kng~kzM~&}H z>>+@H;O7l~{#n@FRTHYco?6k7v&Ar`Cjwqu#5QtzrTDj5ZAp%wa+XdNu#95%T3Fgd z=F!A2ILDY$W7y0CBF0vO6>#{B{C?bsWp-wB4&x=ysm_n)%2wf|QR$L~$XSp^)9+3H z#`Ga#<}aTCdODU3J0GZ{D1Y2lPe?t4IBev`?U*9?rpJJ`~$%-dq04rYd1(+3&0)(@rs($Nb z>xdp!%GT2nohOzX1@IxI#Tg0D4qL@i=>?tV9=(bmv@$-mQpnMI5+`sI?Q$({B7D81 zKhjG&O8s%Cz$o%eL6h$Lhbs2<*6_1ozrABc!R8|NB%eC3Miz8?d_W)rN#DY~zi~RH z{i&B@Drl#sP9d`g=Wd?%nQD!RFMg4VI&Il~(DU1Jg2q9dPju;Gi#m8*b@Qn~98JGC zsZ8>6Y|zz|JF0i7OVfp#P4lQr12w73v16mNitVu0<@?#rqQ;BB+lvRe>dJFr@Qdm7 zH=NAshRB|-8)~bj4I^ab7A+D_qkLHxiI>G`xSJX)cC2Ley?(Eqx{h->O5$lBB{KdV zrMEJ59}Yn6#hTDnAJqO?TNaK9A@80QO~vhfs=FK&C9AhHsyR>Rbde!YxJO&A<9lSW zus#rvtgA5ihquAGfEc$Q8pBp(>VMGKkD1a%yvD-)i}J*AU>P2u;&JiOaJa>Jm0~yS zjfQikxXFO~8zmp}&fzs-UOn#Q?}Gc~1U#LxbSUI4-ZC1Z&KXq)+YHpB%kZ6QC2;Nn zk09Ihr+6!KRfd%eWrE7W9H@0xyUFa`9&mS$D&^xO@ySY44+%$=#$K}H5V;}ovz*>} zPR*1jXh$VA`Gl2-I6-QbJ;HrBC&@SG7|KjigVL_zXfUfcfAPAY#IAoBf$+i<1&Vh|_V6N+Ujb<#Lv1l}zf zh`5o$O{Hg|XDn-`Ii`0zeF+Dv9Ekvxh}LCFkk(#3Pk>G*oR`|`v*=^ZWX-TAYeNWr ze!t@sD!!tEmS;x$%kwoJRwM~gWvDfyQIXwQnoAX(rkJH3W|p2BU86gH3L=uupB^n+ z!2)p-VB{MTgDM-G`)%KQcl0=(aron+{9_m8;!c*LZnqP&)(#vne+S zVHkH=n1Fh9G|sA7-J$Zy*I}u>lkrQHnz*bB) zz`oxs0$8aYtW#sSn5_X=m)zzhhLhW^+9|cO`h?SK;j>#t3%TJ>f@7MR!Le`zxxG0S za?6F>uE7YFp}xZ2L$xhI*nC0`gbLo~4VQUbJ+TRyM?1BF@P=?oTtc}Gfnmeg;$9l4 zg}6rQJDbL$w6kg_8shvOquj+poVn4w{CcktC(41D)=%)?5gMF6#-+heCrIU4b(2>% z8X=uM1n9O${J5S%OtKH&f%k!2*Vz7|cewtdjyq_3*|2Z++U}rPj$HN-Ed4kHGh7_f z)eT5l87okDDH02DKdbP5n9Dj~VoH5~K+4Lqy7ERLc~r{fh3Dmk#W7xpc=^$Z*jQfS zRlA|z>xO9YKWkfz_+atGQbPe!#oqE~8MiPORVqaH`;dlRb_}* z$PnXh8?`o7Y+AwoH20w0Tu}Y50b-r@LdzB>0D4GPuM83Tuhh|xt%*K)OzJ;MP$e1x zg)!Bq;{sb`R>QdBytvoX7$T95Aap1el7f75EWi8Oqr z>YuU+00++U)GyvI7Q`n>xI+eKym+Z09lt-uu$7kx#^CZHGG_SIOFZM1GcoSIKc;|J zC5{V?$#nhK zutHD`N<&;N4yNoNWNoke;LeWi>i!;DmCVThOf!b@eZJW_3x!`f|#Ff_1;PLEKy)us?5 zhZm0L=$3FA^d8OOchP$*b<4ye1Z%{v6v{P~?d97NU6JHL#?gs9mm5U@W6B<;ExCTt zzJ4qzIBK-jemmd2olxdSGLjGbFj15^IF6HNj(G^eWwz#1YbvWmGyOT^Xd5NGK}>(P z!_32Wg$N!F(`V?qYm&*u?YgE;*VAIOEc;Evw~#bRAyZrDTDV+_T8nBY6$_V*5gSt$ z^IOv_55mx@<_8HJ@nQQd39FPSAMN#2gDQfP#`$Y{Hr0+-PjKG>T)+AxKBOS3gt5tX z|17>QI{L$1EOS{bS+aphnV?>5HbMf>2W}3B%Ek|IiemHjX!s?d-3^VWKtHVuEP~!z z*QmEf!<3S+*Vh?bO%e*)?W6so6dO0g)zmSR{bPY&LJJ^=8%Gm_2XmANpIcdw@ZX(D zReA}(LP%Veu+mk;@{6_PNlXiR%|AAwOh*ff<8y>-U;KbUX+>Oh55~2x;o*X$n3S}O zBLAA)mHUVo)M+R0MYl2U76EK0P>;inIJ|0K!uvCb0I_%ZWcA#rLMsc~#4W;XU}TpC zn5E0WXBHM4!DrcMVhRPjGn$v7rC!Q5FGeQgd$+1Y7^o9FSfqC2tff6czmek9S4|R^ zV&SeBj`z)8vC3U6?t*OSFL-5kyQ}3^75rO#*%H(b@Hfq-p`Q9Qlm+uu*JxIoR_Xtf za7>m0mKUkl_I(LM)jX^+nulS5bl4}XxS{N`X=LUo4gyMJbG$_y`1^4ZipT354uart zSpeh3WuvKF0Xw+?r@2UW@@T+~UPF1wmSy?Cm~wJ#rl=88ygf;!mzpav;d3SVIC&Q5 zDhsjjEmrptqkyjlWh8});Q;V73^`jAj-81ZYHlQ)kb#kXLsBu^TcWqZRr34E5=q=y z6{xxM6^b|`Ag&Pm8*ABhG%aUU3t)Wx!&qW~q(b*9@-Wl(N|cSZ_>i?B?Gc8SJZ=

8#ym*SA{Z76>Skn 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

bN^v>pXI}bo|Yvn5vyIAJLvH@YQ=e|EWy6 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 ArT_o{ literal 0 HcmV?d00001 diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index d2c9e2f15..f0cee98fd 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -23,6 +23,8 @@ typedef uint32_t wasmer_value_tag; typedef struct wasmer_import_object_t wasmer_import_object_t; +typedef struct wasmer_instance_context_t wasmer_instance_context_t; + typedef struct wasmer_instance_t wasmer_instance_t; typedef union { @@ -41,6 +43,11 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); +void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, + const char *namespace_, + const char *name, + void (*func)(void *data)); + wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, const wasmer_value_t *params, @@ -48,6 +55,8 @@ wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, wasmer_value_t *results, int results_len); +void wasmer_instance_context_memory(wasmer_instance_context_t *instance); + void wasmer_instance_destroy(wasmer_instance_t *instance); wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, From d31c1c60685f6467283ddabd7d2baf92bee354cc Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 18:07:37 -0600 Subject: [PATCH 09/50] Fix lints --- lib/runtime-c-api/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index db01f7fe6..74b039132 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -176,8 +176,9 @@ pub unsafe extern "C" fn wasmer_instance_call( } } +#[allow(clippy::cast_ptr_alignment)] #[no_mangle] -pub extern "C" fn wasmer_imports_set_import_func( +pub unsafe extern "C" fn wasmer_imports_set_import_func( import_object: *mut wasmer_import_object_t, namespace: *const c_char, name: *const c_char, From 5d9e05c2f699fea75523ad487839800f99ce8e4b Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 19:10:08 -0600 Subject: [PATCH 10/50] Add function signature parameters to set import func --- lib/runtime-c-api/src/lib.rs | 25 ++++++++++++++++++- .../tests/test-import-function.c | 4 ++- lib/runtime-c-api/wasmer.h | 6 ++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 74b039132..445aa8262 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -183,6 +183,10 @@ pub unsafe extern "C" fn wasmer_imports_set_import_func( namespace: *const c_char, name: *const c_char, func: extern "C" fn(data: *mut c_void), + params: *const wasmer_value_tag, + params_len: c_int, + returns: *const wasmer_value_tag, + returns_len: c_int, ) { let mut import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; let namespace_c = unsafe { CStr::from_ptr(namespace) }; @@ -190,10 +194,15 @@ pub unsafe extern "C" fn wasmer_imports_set_import_func( let name_c = unsafe { CStr::from_ptr(name) }; let name_r = name_c.to_str().unwrap(); + let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize); + let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); + let returns: &[wasmer_value_tag] = slice::from_raw_parts(returns, returns_len as usize); + let returns: Vec = returns.iter().cloned().map(|x| x.into()).collect(); + let export = Export::Function { func: unsafe { FuncPointer::new(func as _) }, ctx: Context::Internal, - signature: Arc::new(FuncSig::new(vec![Type::I32, Type::I32], vec![])), + signature: Arc::new(FuncSig::new(params, returns)), }; // TODO handle existing namespace @@ -257,3 +266,17 @@ impl From for Value { } } } + +impl From for Type { + fn from(v: wasmer_value_tag) -> Self { + unsafe { + match v { + wasmer_value_tag::WASM_I32 => Type::I32, + wasmer_value_tag::WASM_I64 => Type::I64, + wasmer_value_tag::WASM_F32 => Type::F32, + wasmer_value_tag::WASM_F64 => Type::F64, + _ => panic!("not implemented"), + } + } + } +} diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index eecacc347..c96ae38f9 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -13,7 +13,9 @@ void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) { int main() { wasmer_import_object_t *import_object = wasmer_import_object_new(); - wasmer_imports_set_import_func(import_object, "env", "print_str", print_str); + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_imports_set_import_func(import_object, "env", "print_str", print_str, params_sig, 2, returns_sig, 0); // Read the wasm file bytes FILE *file = fopen("wasm_sample_app.wasm", "r"); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index f0cee98fd..c10859f2f 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -46,7 +46,11 @@ wasmer_import_object_t *wasmer_import_object_new(void); void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const char *namespace_, const char *name, - void (*func)(void *data)); + void (*func)(void *data), + const wasmer_value_tag *params, + int params_len, + const wasmer_value_tag *returns, + int returns_len); wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, From 6f7db9062d32581285ba828cffc31f51c6f7a3fb Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 2 Feb 2019 20:16:53 -0600 Subject: [PATCH 11/50] Run cmake tests as part of a rust test --- Makefile | 1 + lib/runtime-c-api/README.md | 6 ++- .../tests/runtime_c_api_tests.rs | 37 ++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4a700f222..62bf5d05b 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,7 @@ test: # cargo test --all -- --test-threads=1 $(runargs) # cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) cargo test -p wasmer-spectests -- --test-threads=1 $(runargs) + cargo test -p wasmer-runtime-c-api -- --nocapture release: # If you are in OS-X, you will need mingw-w64 for cross compiling to windows diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index 7792a8c17..02ba9a705 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -4,5 +4,7 @@ Run `make capi` from wasmer project root directory ## Running tests -`cmake . && make && make test` from runtime-c-api/tests directory -(TODO run this within a rust test) \ No newline at end of file +The tests can be run via `cargo test`, E.g. `cargo test -p wasmer-runtime-c-api -- --nocapture` + +*Running manually* +`cmake . && make && make test` from the `lib/runtime-c-api/tests` directory diff --git a/lib/runtime-c-api/tests/runtime_c_api_tests.rs b/lib/runtime-c-api/tests/runtime_c_api_tests.rs index f9112c83c..b605da49e 100644 --- a/lib/runtime-c-api/tests/runtime_c_api_tests.rs +++ b/lib/runtime-c-api/tests/runtime_c_api_tests.rs @@ -1,4 +1,39 @@ +use std::process::Command; + #[test] fn test_c_api() { - // TODO run `cmake . && make && make test` + let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests"); + run_command("cmake", project_tests_dir, Some(".")); + run_command("make", project_tests_dir, None); + run_command("make", project_tests_dir, Some("test")); +} + +fn run_command(command_str: &str, dir: &str, arg: Option<&str>) { + println!("Running command: `{}` arg: {:?}", command_str, arg); + let mut command = Command::new(command_str); + if let Some(a) = arg { + command.arg(a); + } + command.current_dir(dir); + let result = command.output(); + match result { + Ok(r) => { + println!("output:"); + if let Some(code) = r.status.code() { + println!("status: {}", code); + } else { + println!("status: None"); + } + println!("stdout:"); + println!("{}", String::from_utf8_lossy(&r.stdout[..])); + println!("stderr:"); + println!("{}", String::from_utf8_lossy(&r.stderr[..])); + if r.status.success() { + assert!(true) + } else { + panic!("Command failed with exit status: {:?}", r.status); + } + } + Err(e) => panic!("Command failed: {}", e), + } } From 6185eb73a8821896ded619245eafaab464b1cd97 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 3 Feb 2019 12:14:14 -0600 Subject: [PATCH 12/50] Configure cmake to find dylib/so/dll wasmer library --- lib/runtime-c-api/tests/CMakeLists.txt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 7d47da19c..b8ad14445 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -4,11 +4,19 @@ project (WasmerCApiTests) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) -target_link_libraries(test-instantiate - general "${CMAKE_SOURCE_DIR}/../../../target/debug/libwasmer_runtime_c_api.dylib") +find_library( + WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll + PATHS ${CMAKE_SOURCE_DIR}/../../../target/debug/ +) +if(NOT WASMER_LIB) + message(FATAL_ERROR "wasmer library not found") +endif() + +target_link_libraries(test-instantiate + general ${WASMER_LIB}) target_link_libraries(test-import-function - general "${CMAKE_SOURCE_DIR}/../../../target/debug/libwasmer_runtime_c_api.dylib") + general ${WASMER_LIB}) enable_testing() add_test(test-instantiate test-instantiate) From 358c306ceaa07bb3d57d188003561b086e350bda Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 3 Feb 2019 12:33:42 -0600 Subject: [PATCH 13/50] Add runtime-c-api as external project to build dependency --- lib/runtime-c-api/tests/.gitignore | 3 ++- lib/runtime-c-api/tests/CMakeLists.txt | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 30324d55c..2e8c46610 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -10,4 +10,5 @@ compile_commands.json CTestTestfile.cmake _deps test-instantiate -test-import-function \ No newline at end of file +test-import-function +rust-build \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index b8ad14445..ea9cfd84e 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -4,6 +4,21 @@ project (WasmerCApiTests) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) +include(ExternalProject) +set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/rust-build) +ExternalProject_Add( + wasmer-runtime-c-api + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND cargo build + COMMAND cargo build + BINARY_DIR "${CMAKE_SOURCE_DIR}/../" + INSTALL_COMMAND "" + LOG_BUILD ON) +add_dependencies(test-instantiate wasmer-runtime-c-api) +add_dependencies(test-import-function wasmer-runtime-c-api) + + find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll PATHS ${CMAKE_SOURCE_DIR}/../../../target/debug/ From fa959fa6ee78b5f1a0f972653bbe85eb4b9e7d08 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 3 Feb 2019 13:21:59 -0600 Subject: [PATCH 14/50] Call cargo build during make test to build C API lib --- Makefile | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 15 --------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 62bf5d05b..4c3618e80 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,7 @@ test: # cargo test --all -- --test-threads=1 $(runargs) # cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) cargo test -p wasmer-spectests -- --test-threads=1 $(runargs) + cargo build -p wasmer-runtime-c-api cargo test -p wasmer-runtime-c-api -- --nocapture release: diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index ea9cfd84e..b8ad14445 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -4,21 +4,6 @@ project (WasmerCApiTests) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) -include(ExternalProject) -set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/rust-build) -ExternalProject_Add( - wasmer-runtime-c-api - DOWNLOAD_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND cargo build - COMMAND cargo build - BINARY_DIR "${CMAKE_SOURCE_DIR}/../" - INSTALL_COMMAND "" - LOG_BUILD ON) -add_dependencies(test-instantiate wasmer-runtime-c-api) -add_dependencies(test-import-function wasmer-runtime-c-api) - - find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll PATHS ${CMAKE_SOURCE_DIR}/../../../target/debug/ From 6ed72a50ce9e38caff10050276774aa46b60b25e Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 4 Feb 2019 19:49:28 -0600 Subject: [PATCH 15/50] Add instance_destroy back to test --- lib/runtime-c-api/tests/test-import-function.c | 6 +++--- lib/runtime-c-api/tests/test-instantiate.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index c96ae38f9..c6d723664 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -39,10 +39,10 @@ int main() assert(print_str_called); - // TODO review import object ownership, instantiate moves it + printf("Destroy instance\n"); - //wasmer_instance_destroy(instance); // TODO error here + wasmer_instance_destroy(instance); printf("Destroy import object\n"); - //wasmer_import_object_destroy(import_object); // TODO error here + //wasmer_import_object_destroy(import_object); // TODO update instantiate and try this again return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index 4ad4c1ec7..bd6a35004 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -39,8 +39,8 @@ int main() assert(call_result == WASMER_CALL_OK); printf("Destroy instance\n"); - //wasmer_instance_destroy(instance); // error here + wasmer_instance_destroy(instance); printf("Destroy import object\n"); - //wasmer_import_object_destroy(import_object); // error here + //wasmer_import_object_destroy(import_object); // TODO update instantiate and try this again return 0; } \ No newline at end of file From 2defd27fac4a68af44ab1d39a56b9971216bfa11 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 4 Feb 2019 19:54:12 -0600 Subject: [PATCH 16/50] Also generate C++ bindings --- lib/runtime-c-api/build.rs | 11 ++++-- lib/runtime-c-api/wasmer.hh | 71 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 lib/runtime-c-api/wasmer.hh diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 40398c2f9..bc8ad1af6 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -17,11 +17,18 @@ fn build() { use cbindgen::Language; cbindgen::Builder::new() - .with_crate(crate_dir) + .with_crate(crate_dir.clone()) .with_language(Language::C) .generate() - .expect("Unable to generate bindings") + .expect("Unable to generate C bindings") .write_to_file("wasmer.h"); + + cbindgen::Builder::new() + .with_crate(crate_dir) + .with_language(Language::Cxx) + .generate() + .expect("Unable to generate C++ bindings") + .write_to_file("wasmer.hh"); } #[cfg(not(feature = "generate-c-api-headers"))] diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh new file mode 100644 index 000000000..161a9f90e --- /dev/null +++ b/lib/runtime-c-api/wasmer.hh @@ -0,0 +1,71 @@ +#include +#include +#include + +enum class wasmer_call_result_t { + WASMER_CALL_OK = 1, + WASMER_CALL_ERROR = 2, +}; + +enum class wasmer_compile_result_t { + WASMER_COMPILE_OK = 1, + WASMER_COMPILE_ERROR = 2, +}; + +enum class wasmer_value_tag : uint32_t { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, +}; + +struct wasmer_import_object_t; + +struct wasmer_instance_context_t; + +struct wasmer_instance_t; + +union wasmer_value { + int32_t I32; + int64_t I64; + float F32; + double F64; +}; + +struct wasmer_value_t { + wasmer_value_tag tag; + wasmer_value value; +}; + +extern "C" { + +void wasmer_import_object_destroy(wasmer_import_object_t *import_object); + +wasmer_import_object_t *wasmer_import_object_new(); + +void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, + const char *namespace_, + const char *name, + void (*func)(void *data), + const wasmer_value_tag *params, + int params_len, + const wasmer_value_tag *returns, + int returns_len); + +wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, + const char *name, + const wasmer_value_t *params, + int params_len, + wasmer_value_t *results, + int results_len); + +void wasmer_instance_context_memory(wasmer_instance_context_t *instance); + +void wasmer_instance_destroy(wasmer_instance_t *instance); + +wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, + uint8_t *wasm_bytes, + uint32_t wasm_bytes_len, + wasmer_import_object_t *import_object); + +} // extern "C" From 8d8dea7ec8babfe728888d4ce1e6d68bf6672b8a Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 4 Feb 2019 21:46:47 -0600 Subject: [PATCH 17/50] Implement basic C API memory functions --- lib/runtime-c-api/src/lib.rs | 65 ++++++++++++++++++++++++-- lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 ++ lib/runtime-c-api/tests/test-memory.c | 23 +++++++++ lib/runtime-c-api/wasmer.h | 20 ++++++++ lib/runtime-c-api/wasmer.hh | 20 ++++++++ 6 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 lib/runtime-c-api/tests/test-memory.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 445aa8262..a8f4d1278 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -7,10 +7,11 @@ use std::slice; use std::str; use std::sync::Arc; use std::{ffi::c_void, mem, ptr}; -use wasmer_runtime::{ImportObject, Instance, Value}; +use wasmer_runtime::{ImportObject, Instance, Memory, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::{LikeNamespace, Namespace}; -use wasmer_runtime_core::types::{FuncSig, Type}; +use wasmer_runtime_core::types::{FuncSig, MemoryDescriptor, Type}; +use wasmer_runtime_core::units::Pages; #[allow(non_camel_case_types)] pub struct wasmer_import_object_t(); @@ -37,6 +38,14 @@ pub enum wasmer_call_result_t { WASMER_CALL_ERROR = 2, } +#[allow(non_camel_case_types)] +#[no_mangle] +#[repr(C)] +pub enum wasmer_memory_result_t { + WASMER_MEMORY_OK = 1, + WASMER_MEMORY_ERROR = 2, +} + #[repr(u32)] #[derive(Clone)] pub enum wasmer_value_tag { @@ -64,9 +73,16 @@ pub struct wasmer_value_t { #[repr(C)] #[derive(Clone)] -pub struct wasmer_memory_t { - pub ptr: *mut uint8_t, - pub len: uint32_t, +pub struct wasmer_memory_t(); +//{ +// pub ptr: *mut uint8_t, +// pub len: uint32_t, +//} + +#[repr(C)] +pub struct wasmer_limits_t { + pub min: uint32_t, + pub max: uint32_t, } #[no_mangle] @@ -74,6 +90,37 @@ pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t } +#[no_mangle] +pub unsafe extern "C" fn wasmer_memory_new( + mut memory: *mut *mut wasmer_memory_t, + limits: wasmer_limits_t, +) -> wasmer_memory_result_t { + let desc = MemoryDescriptor { + minimum: Pages(limits.min), + maximum: Some(Pages(limits.max)), + shared: false, + }; + let result = Memory::new(desc); + let new_memory = match result { + Ok(memory) => memory, + Err(error) => { + println!("Err: {:?}", error); + return wasmer_memory_result_t::WASMER_MEMORY_ERROR; + } + }; + unsafe { *memory = Box::into_raw(Box::new(new_memory)) as *mut wasmer_memory_t }; + wasmer_memory_result_t::WASMER_MEMORY_OK +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t { + let memory = unsafe { Box::from_raw(memory as *mut Memory) }; + let Pages(len) = memory.size(); + Box::into_raw(memory); + len +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { @@ -82,6 +129,14 @@ pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import } } +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_memory_destroy(memory: *mut wasmer_memory_t) { + if !memory.is_null() { + drop(unsafe { Box::from_raw(memory as *mut Memory) }); + } +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_instantiate( diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 2e8c46610..789a20e67 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -11,4 +11,5 @@ CTestTestfile.cmake _deps test-instantiate test-import-function +test-memory rust-build \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index b8ad14445..ee7b10970 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -3,6 +3,7 @@ project (WasmerCApiTests) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) +add_executable(test-memory test-memory.c) find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll @@ -17,8 +18,11 @@ target_link_libraries(test-instantiate general ${WASMER_LIB}) target_link_libraries(test-import-function general ${WASMER_LIB}) +target_link_libraries(test-memory + general ${WASMER_LIB}) enable_testing() add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) +add_test(test-memory test-memory) diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c new file mode 100644 index 000000000..0201a36c1 --- /dev/null +++ b/lib/runtime-c-api/tests/test-memory.c @@ -0,0 +1,23 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 10; + descriptor.max = 10; + wasmer_memory_result_t memory_result = wasmer_memory_new(&memory, descriptor); + printf("Memory result: %d\n", memory_result); + assert(memory_result == WASMER_MEMORY_OK); + + uint32_t len = wasmer_memory_length(memory); + printf("Memory pages length: %d\n", len); + assert(len == 10); + + printf("Destroy memory\n"); + wasmer_memory_destroy(memory); + return 0; +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index c10859f2f..168918638 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -13,6 +13,11 @@ typedef enum { WASMER_COMPILE_ERROR = 2, } wasmer_compile_result_t; +typedef enum { + WASMER_MEMORY_OK = 1, + WASMER_MEMORY_ERROR = 2, +} wasmer_memory_result_t; + enum wasmer_value_tag { WASM_I32, WASM_I64, @@ -39,6 +44,15 @@ typedef struct { wasmer_value value; } wasmer_value_t; +typedef struct { + +} wasmer_memory_t; + +typedef struct { + uint32_t min; + uint32_t max; +} wasmer_limits_t; + void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); @@ -67,3 +81,9 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); + +void wasmer_memory_destroy(wasmer_memory_t *memory); + +uint32_t wasmer_memory_length(wasmer_memory_t *memory); + +wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 161a9f90e..7e1d72b67 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -12,6 +12,11 @@ enum class wasmer_compile_result_t { WASMER_COMPILE_ERROR = 2, }; +enum class wasmer_memory_result_t { + WASMER_MEMORY_OK = 1, + WASMER_MEMORY_ERROR = 2, +}; + enum class wasmer_value_tag : uint32_t { WASM_I32, WASM_I64, @@ -37,6 +42,15 @@ struct wasmer_value_t { wasmer_value value; }; +struct wasmer_memory_t { + +}; + +struct wasmer_limits_t { + uint32_t min; + uint32_t max; +}; + extern "C" { void wasmer_import_object_destroy(wasmer_import_object_t *import_object); @@ -68,4 +82,10 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +void wasmer_memory_destroy(wasmer_memory_t *memory); + +uint32_t wasmer_memory_length(wasmer_memory_t *memory); + +wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); + } // extern "C" From 309246e0d6c7ffc68643de682a316e095429ecf1 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 5 Feb 2019 00:01:01 -0600 Subject: [PATCH 18/50] Add validate function and test --- lib/runtime-c-api/src/lib.rs | 11 +++++++++++ lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 ++++ lib/runtime-c-api/tests/test-validate.c | 22 ++++++++++++++++++++++ lib/runtime-c-api/wasmer.h | 2 ++ lib/runtime-c-api/wasmer.hh | 2 ++ 6 files changed, 42 insertions(+) create mode 100644 lib/runtime-c-api/tests/test-validate.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index a8f4d1278..98c00e196 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -85,6 +85,17 @@ pub struct wasmer_limits_t { pub max: uint32_t, } +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_validate(wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t) -> bool { + if wasm_bytes.is_null() { + return false; + } + let bytes: &[u8] = + unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; + wasmer_runtime_core::validate(bytes) +} + #[no_mangle] pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 789a20e67..76d5a7d2e 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -12,4 +12,5 @@ _deps test-instantiate test-import-function test-memory +test-validate rust-build \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index ee7b10970..d682bfe3b 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -4,6 +4,7 @@ project (WasmerCApiTests) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) add_executable(test-memory test-memory.c) +add_executable(test-validate test-validate.c) find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll @@ -20,9 +21,12 @@ target_link_libraries(test-import-function general ${WASMER_LIB}) target_link_libraries(test-memory general ${WASMER_LIB}) +target_link_libraries(test-validate + general ${WASMER_LIB}) enable_testing() add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) add_test(test-memory test-memory) +add_test(test-validate test-validate) diff --git a/lib/runtime-c-api/tests/test-validate.c b/lib/runtime-c-api/tests/test-validate.c new file mode 100644 index 000000000..689cf50f2 --- /dev/null +++ b/lib/runtime-c-api/tests/test-validate.c @@ -0,0 +1,22 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + // Read the wasm file bytes + FILE *file = fopen("sum.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + bool result = wasmer_validate(bytes, len); + printf("Result: %d", result); + assert(result); + + return 0; +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 168918638..26b343e29 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -87,3 +87,5 @@ void wasmer_memory_destroy(wasmer_memory_t *memory); uint32_t wasmer_memory_length(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); + +bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 7e1d72b67..37400cea9 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -88,4 +88,6 @@ uint32_t wasmer_memory_length(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); + } // extern "C" From c3707efa084b848b8691e86957a9117d2173fed0 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 13:09:54 -0600 Subject: [PATCH 19/50] Update for merge from master --- Cargo.lock | 112 +++++++++++++++++++++++++++++++---- lib/runtime-c-api/src/lib.rs | 7 ++- 2 files changed, 106 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d061df27b..82e1fb81c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,7 +28,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "block-buffer" -version = "0.7.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -60,6 +60,21 @@ name = "cast" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cbindgen" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.28" @@ -404,6 +419,14 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.26" @@ -412,6 +435,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.6.11" @@ -547,6 +578,14 @@ dependencies = [ "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -582,6 +621,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde-bench" @@ -602,12 +644,12 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.85" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -625,7 +667,7 @@ name = "sha2" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -669,6 +711,16 @@ dependencies = [ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "0.13.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.26" @@ -700,6 +752,19 @@ dependencies = [ "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.1" @@ -728,6 +793,14 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "typenum" version = "1.10.0" @@ -772,7 +845,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -815,7 +888,7 @@ dependencies = [ "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.1.2", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -843,6 +916,16 @@ dependencies = [ "wasmer-runtime-core 0.1.2", ] +[[package]] +name = "wasmer-runtime-c-api" +version = "0.1.4" +dependencies = [ + "cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime 0.1.4", + "wasmer-runtime-core 0.1.2", +] + [[package]] name = "wasmer-runtime-core" version = "0.1.2" @@ -860,7 +943,7 @@ dependencies = [ "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-backend 0.1.2", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -920,11 +1003,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "509de513cca6d92b6aacf9c61acfe7eaa160837323a81068d690cc1f8e5740da" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" +"checksum cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32e01024aaf5390d6a8145047371a4f5b0063a14c1e411bc731353bd2278ca44" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" @@ -967,7 +1051,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" "checksum proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "38fddd23d98b2144d197c0eca5705632d4fe2667d14a6be5df8934f8d74f1978" +"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -983,6 +1069,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" @@ -991,7 +1078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "534b8b91a95e0f71bca3ed5824752d558da048d4248c91af873b63bd60519752" "checksum serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d733da87e79faaac25616e33d26299a41143fd4cd42746cbb0e91d8feea243fd" "checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3" -"checksum serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "a915306b0f1ac5607797697148c223bedeaa36bcc2e28a01441cd638cc6567b4" +"checksum serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ac38f51a52a556cd17545798e29536885fb1a3fa63d6399f5ef650f4a7d35901" "checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" @@ -999,12 +1086,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3" "checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04" +"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9" +"checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 98c00e196..252322e2b 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -87,7 +87,10 @@ pub struct wasmer_limits_t { #[allow(clippy::cast_ptr_alignment)] #[no_mangle] -pub unsafe extern "C" fn wasmer_validate(wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t) -> bool { +pub unsafe extern "C" fn wasmer_validate( + wasm_bytes: *mut uint8_t, + wasm_bytes_len: uint32_t, +) -> bool { if wasm_bytes.is_null() { return false; } @@ -162,7 +165,7 @@ pub unsafe extern "C" fn wasmer_instantiate( } let bytes: &[u8] = unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; - let result = wasmer_runtime::instantiate(bytes, *import_object); + let result = wasmer_runtime::instantiate(bytes, &*import_object); let new_instance = match result { Ok(instance) => instance, Err(error) => { From 4e5e525626883c8c71c183508692bb132966dfc0 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 13:37:07 -0600 Subject: [PATCH 20/50] Add basic Table functions --- lib/runtime-c-api/src/lib.rs | 60 ++++++++++++++++++++++---- lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 ++ lib/runtime-c-api/tests/test-tables.c | 23 ++++++++++ lib/runtime-c-api/wasmer.h | 15 +++++++ lib/runtime-c-api/wasmer.hh | 15 +++++++ 6 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 lib/runtime-c-api/tests/test-tables.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 252322e2b..84ee8cf38 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -7,10 +7,10 @@ use std::slice; use std::str; use std::sync::Arc; use std::{ffi::c_void, mem, ptr}; -use wasmer_runtime::{ImportObject, Instance, Memory, Value}; +use wasmer_runtime::{ImportObject, Instance, Memory, Table, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::{LikeNamespace, Namespace}; -use wasmer_runtime_core::types::{FuncSig, MemoryDescriptor, Type}; +use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type}; use wasmer_runtime_core::units::Pages; #[allow(non_camel_case_types)] @@ -46,6 +46,14 @@ pub enum wasmer_memory_result_t { WASMER_MEMORY_ERROR = 2, } +#[allow(non_camel_case_types)] +#[no_mangle] +#[repr(C)] +pub enum wasmer_table_result_t { + WASMER_TABLE_OK = 1, + WASMER_TABLE_ERROR = 2, +} + #[repr(u32)] #[derive(Clone)] pub enum wasmer_value_tag { @@ -74,10 +82,10 @@ pub struct wasmer_value_t { #[repr(C)] #[derive(Clone)] pub struct wasmer_memory_t(); -//{ -// pub ptr: *mut uint8_t, -// pub len: uint32_t, -//} + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_table_t(); #[repr(C)] pub struct wasmer_limits_t { @@ -118,7 +126,6 @@ pub unsafe extern "C" fn wasmer_memory_new( let new_memory = match result { Ok(memory) => memory, Err(error) => { - println!("Err: {:?}", error); return wasmer_memory_result_t::WASMER_MEMORY_ERROR; } }; @@ -135,6 +142,44 @@ pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t len } +#[no_mangle] +pub unsafe extern "C" fn wasmer_table_new( + mut table: *mut *mut wasmer_table_t, + limits: wasmer_limits_t, +) -> wasmer_table_result_t { + let desc = TableDescriptor { + element: ElementType::Anyfunc, + minimum: limits.min, + maximum: Some(limits.max), + }; + let result = Table::new(desc); + let new_table = match result { + Ok(table) => table, + Err(error) => { + return wasmer_table_result_t::WASMER_TABLE_ERROR; + } + }; + unsafe { *table = Box::into_raw(Box::new(new_table)) as *mut wasmer_table_t }; + wasmer_table_result_t::WASMER_TABLE_OK +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_table_length(table: *mut wasmer_table_t) -> uint32_t { + let table = unsafe { Box::from_raw(table as *mut Table) }; + let len = table.size(); + Box::into_raw(table); + len +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_table_destroy(table: *mut wasmer_table_t) { + if !table.is_null() { + drop(unsafe { Box::from_raw(table as *mut Table) }); + } +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { @@ -169,7 +214,6 @@ pub unsafe extern "C" fn wasmer_instantiate( let new_instance = match result { Ok(instance) => instance, Err(error) => { - println!("Err: {:?}", error); return wasmer_compile_result_t::WASMER_COMPILE_ERROR; } }; diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 76d5a7d2e..8ac4f1ab0 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -12,5 +12,6 @@ _deps test-instantiate test-import-function test-memory +test-tables test-validate rust-build \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index d682bfe3b..58b1ac3cd 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) add_executable(test-memory test-memory.c) add_executable(test-validate test-validate.c) +add_executable(test-tables test-tables.c) find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll @@ -23,10 +24,13 @@ target_link_libraries(test-memory general ${WASMER_LIB}) target_link_libraries(test-validate general ${WASMER_LIB}) +target_link_libraries(test-tables + general ${WASMER_LIB}) enable_testing() add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) add_test(test-memory test-memory) add_test(test-validate test-validate) +add_test(test-tables test-tables) diff --git a/lib/runtime-c-api/tests/test-tables.c b/lib/runtime-c-api/tests/test-tables.c new file mode 100644 index 000000000..88d86d842 --- /dev/null +++ b/lib/runtime-c-api/tests/test-tables.c @@ -0,0 +1,23 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + wasmer_table_t *table = NULL; + wasmer_limits_t descriptor; + descriptor.min = 10; + descriptor.max = 10; + wasmer_table_result_t table_result = wasmer_table_new(&table, descriptor); + printf("Table result: %d\n", table_result); + assert(table_result == WASMER_TABLE_OK); + + uint32_t len = wasmer_table_length(table); + printf("Table length: %d\n", len); + assert(len == 10); + + printf("Destroy table\n"); + wasmer_table_destroy(table); + return 0; +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 26b343e29..0d72375c9 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -18,6 +18,11 @@ typedef enum { WASMER_MEMORY_ERROR = 2, } wasmer_memory_result_t; +typedef enum { + WASMER_TABLE_OK = 1, + WASMER_TABLE_ERROR = 2, +} wasmer_table_result_t; + enum wasmer_value_tag { WASM_I32, WASM_I64, @@ -53,6 +58,10 @@ typedef struct { uint32_t max; } wasmer_limits_t; +typedef struct { + +} wasmer_table_t; + void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); @@ -88,4 +97,10 @@ uint32_t wasmer_memory_length(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +void wasmer_table_destroy(wasmer_table_t *table); + +uint32_t wasmer_table_length(wasmer_table_t *table); + +wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); + bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 37400cea9..cb271c9d5 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -17,6 +17,11 @@ enum class wasmer_memory_result_t { WASMER_MEMORY_ERROR = 2, }; +enum class wasmer_table_result_t { + WASMER_TABLE_OK = 1, + WASMER_TABLE_ERROR = 2, +}; + enum class wasmer_value_tag : uint32_t { WASM_I32, WASM_I64, @@ -51,6 +56,10 @@ struct wasmer_limits_t { uint32_t max; }; +struct wasmer_table_t { + +}; + extern "C" { void wasmer_import_object_destroy(wasmer_import_object_t *import_object); @@ -88,6 +97,12 @@ uint32_t wasmer_memory_length(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +void wasmer_table_destroy(wasmer_table_t *table); + +uint32_t wasmer_table_length(wasmer_table_t *table); + +wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); + bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); } // extern "C" From 8364c39b4c983bc75b45e427da939870c49d82cb Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 13:58:50 -0600 Subject: [PATCH 21/50] Add Table grow function --- lib/runtime-c-api/src/lib.rs | 16 ++++++++++++++++ lib/runtime-c-api/tests/test-tables.c | 17 +++++++++++++++-- lib/runtime-c-api/wasmer.h | 2 ++ lib/runtime-c-api/wasmer.hh | 2 ++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 84ee8cf38..9f2ffb12c 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -163,6 +163,22 @@ pub unsafe extern "C" fn wasmer_table_new( wasmer_table_result_t::WASMER_TABLE_OK } +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_table_grow( + table: *mut wasmer_table_t, + delta: uint32_t, +) -> wasmer_table_result_t { + let table = unsafe { Box::from_raw(table as *mut Table) }; + let maybe_delta = table.grow(delta); + Box::into_raw(table); + if let Some(_delta) = maybe_delta { + wasmer_table_result_t::WASMER_TABLE_OK + } else { + wasmer_table_result_t::WASMER_TABLE_ERROR + } +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_table_length(table: *mut wasmer_table_t) -> uint32_t { diff --git a/lib/runtime-c-api/tests/test-tables.c b/lib/runtime-c-api/tests/test-tables.c index 88d86d842..7e3f51a2f 100644 --- a/lib/runtime-c-api/tests/test-tables.c +++ b/lib/runtime-c-api/tests/test-tables.c @@ -8,14 +8,27 @@ int main() wasmer_table_t *table = NULL; wasmer_limits_t descriptor; descriptor.min = 10; - descriptor.max = 10; + descriptor.max = 15; wasmer_table_result_t table_result = wasmer_table_new(&table, descriptor); printf("Table result: %d\n", table_result); assert(table_result == WASMER_TABLE_OK); uint32_t len = wasmer_table_length(table); printf("Table length: %d\n", len); - assert(len == 10); + assert(len == 15); + + // wasmer_table_result_t grow_result1 = wasmer_table_grow(&table, 5); + // assert(grow_result1 == WASMER_TABLE_OK); + // uint32_t len_grow1 = wasmer_table_length(table); + // printf("Table length: %d\n", len_grow1); + // assert(len_grow1 == 15); + + // // Try to grow beyond max + // wasmer_table_result_t grow_result2 = wasmer_table_grow(&table, 1); + // assert(grow_result2 == WASMER_TABLE_ERROR); + // uint32_t len_grow2 = wasmer_table_length(table); + // printf("Table length: %d\n", len_grow2); + // assert(len_grow2 == 15); printf("Destroy table\n"); wasmer_table_destroy(table); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 0d72375c9..08f891fa8 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -99,6 +99,8 @@ wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits void wasmer_table_destroy(wasmer_table_t *table); +wasmer_table_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); + uint32_t wasmer_table_length(wasmer_table_t *table); wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index cb271c9d5..c0d266489 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -99,6 +99,8 @@ wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits void wasmer_table_destroy(wasmer_table_t *table); +wasmer_table_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); + uint32_t wasmer_table_length(wasmer_table_t *table); wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); From 94c5acedbfb89b3cc6048fba6e2bc19d415cc7f6 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 17:39:15 -0600 Subject: [PATCH 22/50] Add basic Global API --- lib/runtime-c-api/src/lib.rs | 105 ++++++++++++++++++++++++- lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 + lib/runtime-c-api/tests/test-globals.c | 30 +++++++ lib/runtime-c-api/wasmer.h | 19 +++++ lib/runtime-c-api/wasmer.hh | 19 +++++ 6 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 lib/runtime-c-api/tests/test-globals.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 9f2ffb12c..1bebd8336 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -7,10 +7,12 @@ use std::slice; use std::str; use std::sync::Arc; use std::{ffi::c_void, mem, ptr}; -use wasmer_runtime::{ImportObject, Instance, Memory, Table, Value}; +use wasmer_runtime::{Global, ImportObject, Instance, Memory, Table, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::{LikeNamespace, Namespace}; -use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type}; +use wasmer_runtime_core::types::{ + ElementType, FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type, +}; use wasmer_runtime_core::units::Pages; #[allow(non_camel_case_types)] @@ -79,6 +81,13 @@ pub struct wasmer_value_t { value: wasmer_value, } +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_global_descriptor_t { + mutable: bool, + kind: wasmer_value_tag, +} + #[repr(C)] #[derive(Clone)] pub struct wasmer_memory_t(); @@ -87,6 +96,10 @@ pub struct wasmer_memory_t(); #[derive(Clone)] pub struct wasmer_table_t(); +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_global_t(); + #[repr(C)] pub struct wasmer_limits_t { pub min: uint32_t, @@ -196,6 +209,59 @@ pub extern "C" fn wasmer_table_destroy(table: *mut wasmer_table_t) { } } +#[no_mangle] +pub unsafe extern "C" fn wasmer_global_new( + value: wasmer_value_t, + mutable: bool, +) -> *mut wasmer_global_t { + let global = if mutable { + Global::new_mutable(value.into()) + } else { + Global::new(value.into()) + }; + unsafe { Box::into_raw(Box::new(global)) as *mut wasmer_global_t } +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_global_get(global: *mut wasmer_global_t) -> wasmer_value_t { + let global = unsafe { Box::from_raw(global as *mut Global) }; + let value: wasmer_value_t = global.get().into(); + Box::into_raw(global); + value +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_global_set(global: *mut wasmer_global_t, value: wasmer_value_t) { + let global = unsafe { Box::from_raw(global as *mut Global) }; + global.set(value.into()); + Box::into_raw(global); +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_global_get_descriptor( + global: *mut wasmer_global_t, +) -> wasmer_global_descriptor_t { + let global = unsafe { Box::from_raw(global as *mut Global) }; + let descriptor = global.descriptor(); + let desc = wasmer_global_descriptor_t { + mutable: descriptor.mutable, + kind: descriptor.ty.into(), + }; + Box::into_raw(global); + desc +} + +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_global_destroy(global: *mut wasmer_global_t) { + if !global.is_null() { + drop(unsafe { Box::from_raw(global as *mut Global) }); + } +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { @@ -396,6 +462,41 @@ impl From for Value { } } +impl From for wasmer_value_t { + fn from(val: Value) -> Self { + match val { + Value::I32(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_I32, + value: wasmer_value { I32: x }, + }, + Value::I64(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_I64, + value: wasmer_value { I64: x }, + }, + Value::F32(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_F32, + value: wasmer_value { F32: x }, + }, + Value::F64(x) => wasmer_value_t { + tag: wasmer_value_tag::WASM_F64, + value: wasmer_value { F64: x }, + }, + } + } +} + +impl From for wasmer_value_tag { + fn from(ty: Type) -> Self { + match ty { + Type::I32 => wasmer_value_tag::WASM_I32, + Type::I64 => wasmer_value_tag::WASM_I64, + Type::F32 => wasmer_value_tag::WASM_F32, + Type::F64 => wasmer_value_tag::WASM_F64, + _ => panic!("not implemented"), + } + } +} + impl From for Type { fn from(v: wasmer_value_tag) -> Self { unsafe { diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 8ac4f1ab0..6a96cd53f 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -9,6 +9,7 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps +test-globals test-instantiate test-import-function test-memory diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 58b1ac3cd..d15934df5 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required (VERSION 2.6) project (WasmerCApiTests) +add_executable(test-globals test-globals.c) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) add_executable(test-memory test-memory.c) @@ -16,6 +17,8 @@ if(NOT WASMER_LIB) message(FATAL_ERROR "wasmer library not found") endif() +target_link_libraries(test-globals + general ${WASMER_LIB}) target_link_libraries(test-instantiate general ${WASMER_LIB}) target_link_libraries(test-import-function @@ -28,6 +31,7 @@ target_link_libraries(test-tables general ${WASMER_LIB}) enable_testing() +add_test(test-globals test-globals) add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) add_test(test-memory test-memory) diff --git a/lib/runtime-c-api/tests/test-globals.c b/lib/runtime-c-api/tests/test-globals.c new file mode 100644 index 000000000..a694d2e75 --- /dev/null +++ b/lib/runtime-c-api/tests/test-globals.c @@ -0,0 +1,30 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 7; + wasmer_global_t *global = wasmer_global_new(val, true); + + wasmer_value_t get_val = wasmer_global_get(global); + assert( get_val.value.I32 == 7); + + wasmer_value_t val2; + val2.tag = WASM_I32; + val2.value.I32 = 14; + wasmer_global_set(global, val2); + + wasmer_value_t new_get_val = wasmer_global_get(global); + assert( new_get_val.value.I32 == 14); + + wasmer_global_descriptor_t desc = wasmer_global_get_descriptor(global); + assert(desc.mutable_); + assert(desc.kind == WASM_I32); + + wasmer_global_destroy(global); + return 0; +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 08f891fa8..c6e649bd4 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -37,6 +37,10 @@ typedef struct wasmer_instance_context_t wasmer_instance_context_t; typedef struct wasmer_instance_t wasmer_instance_t; +typedef struct { + +} wasmer_global_t; + typedef union { int32_t I32; int64_t I64; @@ -49,6 +53,11 @@ typedef struct { wasmer_value value; } wasmer_value_t; +typedef struct { + bool mutable_; + wasmer_value_tag kind; +} wasmer_global_descriptor_t; + typedef struct { } wasmer_memory_t; @@ -62,6 +71,16 @@ typedef struct { } wasmer_table_t; +void wasmer_global_destroy(wasmer_global_t *global); + +wasmer_value_t wasmer_global_get(wasmer_global_t *global); + +wasmer_global_descriptor_t wasmer_global_get_descriptor(wasmer_global_t *global); + +wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); + +void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); + void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(void); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index c0d266489..7ac6b1e19 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -35,6 +35,10 @@ struct wasmer_instance_context_t; struct wasmer_instance_t; +struct wasmer_global_t { + +}; + union wasmer_value { int32_t I32; int64_t I64; @@ -47,6 +51,11 @@ struct wasmer_value_t { wasmer_value value; }; +struct wasmer_global_descriptor_t { + bool mutable_; + wasmer_value_tag kind; +}; + struct wasmer_memory_t { }; @@ -62,6 +71,16 @@ struct wasmer_table_t { extern "C" { +void wasmer_global_destroy(wasmer_global_t *global); + +wasmer_value_t wasmer_global_get(wasmer_global_t *global); + +wasmer_global_descriptor_t wasmer_global_get_descriptor(wasmer_global_t *global); + +wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); + +void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); + void wasmer_import_object_destroy(wasmer_import_object_t *import_object); wasmer_import_object_t *wasmer_import_object_new(); From a8dcc0ee872ec3502c77dc8e23c8e50a1296c4bf Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 17:42:58 -0600 Subject: [PATCH 23/50] Fix make test exclude --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e91aff4bf..2506f196c 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ precommit: lint test test: # We use one thread so the emscripten stdouts doesn't collide - cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) + cargo test --all --exclude wasmer-runtime-c-api -- --test-threads=1 $(runargs) # cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) cargo build -p wasmer-runtime-c-api cargo test -p wasmer-runtime-c-api -- --nocapture From a0288c87acb27288ee5165a3bc0573a36631bd32 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 17:53:03 -0600 Subject: [PATCH 24/50] Add Memory Grow C API --- lib/runtime-c-api/src/lib.rs | 16 ++++++++++++++++ lib/runtime-c-api/tests/test-memory.c | 13 ++++++++++++- lib/runtime-c-api/wasmer.h | 2 ++ lib/runtime-c-api/wasmer.hh | 2 ++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 1bebd8336..d7d513604 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -146,6 +146,22 @@ pub unsafe extern "C" fn wasmer_memory_new( wasmer_memory_result_t::WASMER_MEMORY_OK } +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_memory_grow( + memory: *mut wasmer_memory_t, + delta: uint32_t, +) -> wasmer_memory_result_t { + let memory = unsafe { Box::from_raw(memory as *mut Memory) }; + let maybe_delta = memory.grow(Pages(delta)); + Box::into_raw(memory); + if let Some(_delta) = maybe_delta { + wasmer_memory_result_t::WASMER_MEMORY_OK + } else { + wasmer_memory_result_t::WASMER_MEMORY_ERROR + } +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t { diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index 0201a36c1..631a6a983 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -8,7 +8,7 @@ int main() wasmer_memory_t *memory = NULL; wasmer_limits_t descriptor; descriptor.min = 10; - descriptor.max = 10; + descriptor.max = 15; wasmer_memory_result_t memory_result = wasmer_memory_new(&memory, descriptor); printf("Memory result: %d\n", memory_result); assert(memory_result == WASMER_MEMORY_OK); @@ -17,6 +17,17 @@ int main() printf("Memory pages length: %d\n", len); assert(len == 10); + wasmer_memory_result_t grow_result = wasmer_memory_grow(memory, 2); + assert(grow_result == WASMER_MEMORY_OK); + + uint32_t new_len = wasmer_memory_length(memory); + printf("Memory pages length: %d\n", new_len); + assert(new_len == 12); + + // Err, grow beyond max + wasmer_memory_result_t grow_result2 = wasmer_memory_grow(memory, 10); + assert(grow_result2 == WASMER_MEMORY_ERROR); + printf("Destroy memory\n"); wasmer_memory_destroy(memory); return 0; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index c6e649bd4..4df5001ef 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -112,6 +112,8 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, void wasmer_memory_destroy(wasmer_memory_t *memory); +wasmer_memory_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); + uint32_t wasmer_memory_length(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 7ac6b1e19..5fb292cb1 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -112,6 +112,8 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, void wasmer_memory_destroy(wasmer_memory_t *memory); +wasmer_memory_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); + uint32_t wasmer_memory_length(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); From 2fa9cec0ed200de804464fbb2ed6f6ecd0967118 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 9 Feb 2019 18:07:05 -0600 Subject: [PATCH 25/50] Add include guard --- lib/runtime-c-api/build.rs | 2 ++ lib/runtime-c-api/wasmer.h | 5 +++++ lib/runtime-c-api/wasmer.hh | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index bc8ad1af6..f78c5cf69 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -19,6 +19,7 @@ fn build() { cbindgen::Builder::new() .with_crate(crate_dir.clone()) .with_language(Language::C) + .with_include_guard("WASMER_H") .generate() .expect("Unable to generate C bindings") .write_to_file("wasmer.h"); @@ -26,6 +27,7 @@ fn build() { cbindgen::Builder::new() .with_crate(crate_dir) .with_language(Language::Cxx) + .with_include_guard("WASMER_H") .generate() .expect("Unable to generate C++ bindings") .write_to_file("wasmer.hh"); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 4df5001ef..0cfd919c9 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1,3 +1,6 @@ +#ifndef WASMER_H +#define WASMER_H + #include #include #include @@ -127,3 +130,5 @@ uint32_t wasmer_table_length(wasmer_table_t *table); wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); + +#endif /* WASMER_H */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 5fb292cb1..1d2c7d0af 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -1,3 +1,6 @@ +#ifndef WASMER_H +#define WASMER_H + #include #include #include @@ -129,3 +132,5 @@ wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t l bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); } // extern "C" + +#endif // WASMER_H From 0cfe864fe63e5e25a6ad2c04ec8138c0d535705d Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Feb 2019 14:14:42 -0600 Subject: [PATCH 26/50] Add Memory data length --- lib/runtime-c-api/src/lib.rs | 25 ++++++++++--------------- lib/runtime-c-api/tests/test-memory.c | 4 ++++ lib/runtime-c-api/wasmer.h | 2 ++ lib/runtime-c-api/wasmer.hh | 2 ++ 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index d7d513604..7dddd7ef7 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -7,13 +7,13 @@ use std::slice; use std::str; use std::sync::Arc; use std::{ffi::c_void, mem, ptr}; -use wasmer_runtime::{Global, ImportObject, Instance, Memory, Table, Value}; +use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Table, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::{LikeNamespace, Namespace}; use wasmer_runtime_core::types::{ ElementType, FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type, }; -use wasmer_runtime_core::units::Pages; +use wasmer_runtime_core::units::{Bytes, Pages}; #[allow(non_camel_case_types)] pub struct wasmer_import_object_t(); @@ -428,22 +428,17 @@ pub unsafe extern "C" fn wasmer_imports_set_import_func( // }; } -//#[no_mangle] -//pub extern "C" fn wasmer_debug_print(kind: uint8_t, thing: *mut c_void) { -// match kind { -// 1 => { -// println!("wasmer import object:"); -// let import_object = unsafe { Box::from_raw(thing as *mut ImportObject) }; -// println!("after import object"); -// Box::into_raw(import_object); -// }, -// _ => panic!("unknown kind {:?}", kind) -// } -//} - #[no_mangle] pub extern "C" fn wasmer_instance_context_memory(instance: *mut wasmer_instance_context_t) {} +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_memory_data_length(mem: *mut wasmer_memory_t) -> uint32_t { + let memory = mem as *mut Memory; + let Bytes(len) = unsafe { (*memory).size().bytes() }; + len as uint32_t +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index 631a6a983..42a957e23 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -24,6 +24,10 @@ int main() printf("Memory pages length: %d\n", new_len); assert(new_len == 12); + uint32_t bytes_len = wasmer_memory_data_length(memory); + printf("Memory bytes length: %d\n", bytes_len); + assert(bytes_len == 12 * 65536); + // Err, grow beyond max wasmer_memory_result_t grow_result2 = wasmer_memory_grow(memory, 10); assert(grow_result2 == WASMER_MEMORY_ERROR); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 0cfd919c9..99fd96def 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -113,6 +113,8 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); + void wasmer_memory_destroy(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 1d2c7d0af..4c1134a5c 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -113,6 +113,8 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); + void wasmer_memory_destroy(wasmer_memory_t *memory); wasmer_memory_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); From 7ef472dae230c886175f2ccf763b5542870ee6fa Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Feb 2019 14:24:36 -0600 Subject: [PATCH 27/50] Add instance context memory --- lib/runtime-c-api/src/lib.rs | 10 +++++++++- lib/runtime-c-api/tests/test-import-function.c | 8 ++++++-- lib/runtime-c-api/wasmer.h | 3 ++- lib/runtime-c-api/wasmer.hh | 3 ++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 7dddd7ef7..74b6fa6c7 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -428,8 +428,16 @@ pub unsafe extern "C" fn wasmer_imports_set_import_func( // }; } +#[allow(clippy::cast_ptr_alignment)] #[no_mangle] -pub extern "C" fn wasmer_instance_context_memory(instance: *mut wasmer_instance_context_t) {} +pub extern "C" fn wasmer_instance_context_memory( + ctx: *mut wasmer_instance_context_t, + memory_idx: uint32_t, +) -> *const wasmer_memory_t { + let mut ctx = unsafe { Box::from_raw(ctx as *mut Ctx) }; + let memory = ctx.memory(0); + memory as *const Memory as *const wasmer_memory_t +} #[allow(clippy::cast_ptr_alignment)] #[no_mangle] diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index c6d723664..8f4deeb13 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -4,10 +4,14 @@ #include static print_str_called = false; +static memory_len = 0; void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) { - printf("In print_str\n"); + wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + printf("In print_str, memory len: %d\n", mem_len); print_str_called = true; + memory_len = mem_len; } int main() @@ -38,7 +42,7 @@ int main() assert(call_result == WASMER_CALL_OK); assert(print_str_called); - + assert(memory_len == 17); printf("Destroy instance\n"); wasmer_instance_destroy(instance); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 99fd96def..39ff3f0c6 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -104,7 +104,8 @@ wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, wasmer_value_t *results, int results_len); -void wasmer_instance_context_memory(wasmer_instance_context_t *instance); +const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx, + uint32_t memory_idx); void wasmer_instance_destroy(wasmer_instance_t *instance); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 4c1134a5c..12b0ecebb 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -104,7 +104,8 @@ wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, wasmer_value_t *results, int results_len); -void wasmer_instance_context_memory(wasmer_instance_context_t *instance); +const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx, + uint32_t memory_idx); void wasmer_instance_destroy(wasmer_instance_t *instance); From a502da58e3398de39bb456f2782510e50dcacd90 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Feb 2019 14:27:08 -0600 Subject: [PATCH 28/50] Fix import object destroy --- lib/runtime-c-api/src/lib.rs | 2 +- lib/runtime-c-api/tests/test-import-function.c | 2 +- lib/runtime-c-api/tests/test-instantiate.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 74b6fa6c7..adb520071 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -316,7 +316,7 @@ pub unsafe extern "C" fn wasmer_instantiate( } }; unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; - // Box::into_raw(import_object); // TODO Review is this the correct way not to drop + Box::into_raw(import_object); wasmer_compile_result_t::WASMER_COMPILE_OK } diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index 8f4deeb13..83c5b7535 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -47,6 +47,6 @@ int main() printf("Destroy instance\n"); wasmer_instance_destroy(instance); printf("Destroy import object\n"); - //wasmer_import_object_destroy(import_object); // TODO update instantiate and try this again + wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index bd6a35004..e3ef602eb 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -41,6 +41,6 @@ int main() printf("Destroy instance\n"); wasmer_instance_destroy(instance); printf("Destroy import object\n"); - //wasmer_import_object_destroy(import_object); // TODO update instantiate and try this again + wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file From 66bf13c9dd92c0b3c08f9b1cca5a2695265f3d84 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Feb 2019 15:20:35 -0600 Subject: [PATCH 29/50] Add memory data function --- lib/runtime-c-api/src/lib.rs | 8 ++++++++ lib/runtime-c-api/tests/test-import-function.c | 12 +++++++++++- lib/runtime-c-api/wasmer.h | 2 ++ lib/runtime-c-api/wasmer.hh | 2 ++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index adb520071..1072f5cd3 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -439,6 +439,14 @@ pub extern "C" fn wasmer_instance_context_memory( memory as *const Memory as *const wasmer_memory_t } +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_memory_data(mem: *mut wasmer_memory_t) -> *mut uint8_t { + let memory = mem as *mut Memory; + use std::cell::Cell; + unsafe { ((*memory).view::()[..]).as_ptr() as *mut Cell as *mut u8 } +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_data_length(mem: *mut wasmer_memory_t) -> uint32_t { diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index 83c5b7535..13ce81cab 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -5,13 +5,21 @@ static print_str_called = false; static memory_len = 0; +static ptr_len = 0; +static char actual_str[14] = {}; void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) { wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); uint32_t mem_len = wasmer_memory_length(memory); - printf("In print_str, memory len: %d\n", mem_len); + uint8_t *mem_bytes = wasmer_memory_data(memory); + for(int32_t idx = 0; idx < len; idx++){ + actual_str[idx] = mem_bytes[ptr + idx]; + } + actual_str[13] = '\0'; + printf("In print_str, memory len: %d, ptr_len: %d\n, str %s", mem_len, len, actual_str); print_str_called = true; memory_len = mem_len; + ptr_len = len; } int main() @@ -43,6 +51,8 @@ int main() assert(print_str_called); assert(memory_len == 17); + assert(ptr_len == 13); + assert(0 == strcmp(actual_str, "Hello, World!")); printf("Destroy instance\n"); wasmer_instance_destroy(instance); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 39ff3f0c6..0bffb7859 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -114,6 +114,8 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +uint8_t *wasmer_memory_data(wasmer_memory_t *mem); + uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); void wasmer_memory_destroy(wasmer_memory_t *memory); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 12b0ecebb..6d2a9d878 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -114,6 +114,8 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +uint8_t *wasmer_memory_data(wasmer_memory_t *mem); + uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); void wasmer_memory_destroy(wasmer_memory_t *memory); From b70e319f5c17250286fb7f40579fc701f38cb359 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Feb 2019 17:57:23 -0600 Subject: [PATCH 30/50] Add initial error messaging --- lib/runtime-c-api/src/lib.rs | 65 +++++++++++++++++++++- lib/runtime-c-api/tests/test-instantiate.c | 13 +++++ lib/runtime-c-api/tests/test-memory.c | 20 +++++++ lib/runtime-c-api/tests/test-tables.c | 8 +++ lib/runtime-c-api/wasmer.h | 4 ++ lib/runtime-c-api/wasmer.hh | 4 ++ lib/runtime-core/src/error.rs | 18 ++++++ 7 files changed, 131 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 1072f5cd3..d1ccf69e4 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -2,6 +2,8 @@ extern crate wasmer_runtime; extern crate wasmer_runtime_core; use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; +use std::cell::RefCell; +use std::error::Error; use std::ffi::CStr; use std::slice; use std::str; @@ -139,6 +141,7 @@ pub unsafe extern "C" fn wasmer_memory_new( let new_memory = match result { Ok(memory) => memory, Err(error) => { + update_last_error(error); return wasmer_memory_result_t::WASMER_MEMORY_ERROR; } }; @@ -185,6 +188,7 @@ pub unsafe extern "C" fn wasmer_table_new( let new_table = match result { Ok(table) => table, Err(error) => { + update_last_error(error); return wasmer_table_result_t::WASMER_TABLE_ERROR; } }; @@ -381,7 +385,7 @@ pub unsafe extern "C" fn wasmer_instance_call( wasmer_call_result_t::WASMER_CALL_OK } Err(err) => { - println!("Call Err: {:?}", err); + update_last_error(err); wasmer_call_result_t::WASMER_CALL_ERROR } } @@ -537,3 +541,62 @@ impl From for Type { } } } + +// Error reporting + +thread_local! { + static LAST_ERROR: RefCell>> = RefCell::new(None); +} + +fn update_last_error(err: E) { + LAST_ERROR.with(|prev| { + *prev.borrow_mut() = Some(Box::new(err)); + }); +} + +/// Retrieve the most recent error, clearing it in the process. +fn take_last_error() -> Option> { + LAST_ERROR.with(|prev| prev.borrow_mut().take()) +} + +#[no_mangle] +pub extern "C" fn wasmer_last_error_length() -> c_int { + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(ref err) => err.to_string().len() as c_int + 1, + None => 0, + }) +} + +#[no_mangle] +pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length: c_int) -> c_int { + if buffer.is_null() { + // buffer pointer is null + return -1; + } + + let last_error = match take_last_error() { + Some(err) => err, + None => return 0, + }; + + let error_message = last_error.to_string(); + + let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length as usize); + + if error_message.len() >= buffer.len() { + // buffer to small for err message + return -1; + } + + ptr::copy_nonoverlapping( + error_message.as_ptr(), + buffer.as_mut_ptr(), + error_message.len(), + ); + + // Add a trailing null so people using the string as a `char *` don't + // accidentally read into garbage. + buffer[error_message.len()] = 0; + + error_message.len() as c_int +} diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index e3ef602eb..604f9544d 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -38,6 +38,19 @@ int main() assert(results[0].value.I32 == 15); assert(call_result == WASMER_CALL_OK); + + wasmer_call_result_t call_result2 = wasmer_instance_call(instance, "sum", params, 1, results, 1); + printf("Call result bad: %d\n", call_result2); + assert(call_result2 == WASMER_CALL_ERROR); + + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + assert(0 == strcmp(error_str, "Call error")); + free(error_str); + printf("Destroy instance\n"); wasmer_instance_destroy(instance); printf("Destroy import object\n"); diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index 42a957e23..d9379c78a 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -31,6 +31,26 @@ int main() // Err, grow beyond max wasmer_memory_result_t grow_result2 = wasmer_memory_grow(memory, 10); assert(grow_result2 == WASMER_MEMORY_ERROR); +// int error_len = wasmer_last_error_length(); +// char *error_str = malloc(error_len); +// wasmer_last_error_message(error_str, error_len); +// assert(0 == strcmp(error_str, "Creation error")); +// free(error_str); + + +// wasmer_memory_t *bad_memory = NULL; +// wasmer_limits_t bad_descriptor; +// bad_descriptor.min = 15; +// bad_descriptor.max = 10; +// wasmer_memory_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor); +// printf("Bad memory result: %d\n", bad_memory_result); +// assert(memory_result == WASMER_MEMORY_ERROR); +// +// int error_len = wasmer_last_error_length(); +// char *error_str = malloc(error_len); +// wasmer_last_error_message(error_str, error_len); +// assert(0 == strcmp(error_str, "Creation error")); +// free(error_str); printf("Destroy memory\n"); wasmer_memory_destroy(memory); diff --git a/lib/runtime-c-api/tests/test-tables.c b/lib/runtime-c-api/tests/test-tables.c index 7e3f51a2f..f50a5af5f 100644 --- a/lib/runtime-c-api/tests/test-tables.c +++ b/lib/runtime-c-api/tests/test-tables.c @@ -30,6 +30,14 @@ int main() // printf("Table length: %d\n", len_grow2); // assert(len_grow2 == 15); +// wasmer_table_t *table_bad = NULL; +// wasmer_limits_t bad_descriptor; +// bad_descriptor.min = 15; +// bad_descriptor.max = 10; +// wasmer_table_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor); +// printf("Table result: %d\n", table_bad_result); +// assert(table_result == WASMER_TABLE_ERROR); + printf("Destroy table\n"); wasmer_table_destroy(table); return 0; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 0bffb7859..3f4a34a94 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -114,6 +114,10 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +int wasmer_last_error_length(void); + +int wasmer_last_error_message(char *buffer, int length); + uint8_t *wasmer_memory_data(wasmer_memory_t *mem); uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 6d2a9d878..c7ddb5bdd 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -114,6 +114,10 @@ wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +int wasmer_last_error_length(); + +int wasmer_last_error_message(char *buffer, int length); + uint8_t *wasmer_memory_data(wasmer_memory_t *mem); uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index b72c74242..d75a2ca90 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -1,6 +1,8 @@ use crate::types::{ FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type, }; +use std::error::Error as StdError; +use std::fmt; use std::sync::Arc; pub type Result = std::result::Result; @@ -154,6 +156,14 @@ impl PartialEq for CallError { } } +impl fmt::Display for CallError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Call error") + } +} + +impl StdError for CallError {} + /// This error type is produced when creating something, /// like a `Memory` or a `Table`. #[derive(Debug, Clone)] @@ -168,6 +178,14 @@ impl PartialEq for CreationError { } } +impl fmt::Display for CreationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Creation error") + } +} + +impl StdError for CreationError {} + /// The amalgamation of all errors that can occur /// during the compilation, instantiation, or execution /// of a webassembly module. From 019ef9ea01d3aac1f09a5db0387e25cbb5a0e261 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 11 Feb 2019 19:07:28 -0600 Subject: [PATCH 31/50] Consolidate result type to one enum --- lib/runtime-c-api/src/lib.rs | 74 +++++++------------ .../tests/test-import-function.c | 8 +- lib/runtime-c-api/tests/test-instantiate.c | 12 +-- lib/runtime-c-api/tests/test-memory.c | 14 ++-- lib/runtime-c-api/tests/test-tables.c | 16 ++-- lib/runtime-c-api/wasmer.h | 49 +++++------- lib/runtime-c-api/wasmer.hh | 49 +++++------- 7 files changed, 84 insertions(+), 138 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index d1ccf69e4..97267866d 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -29,33 +29,9 @@ pub struct wasmer_instance_context_t(); #[allow(non_camel_case_types)] #[no_mangle] #[repr(C)] -pub enum wasmer_compile_result_t { - WASMER_COMPILE_OK = 1, - WASMER_COMPILE_ERROR = 2, -} - -#[allow(non_camel_case_types)] -#[no_mangle] -#[repr(C)] -pub enum wasmer_call_result_t { - WASMER_CALL_OK = 1, - WASMER_CALL_ERROR = 2, -} - -#[allow(non_camel_case_types)] -#[no_mangle] -#[repr(C)] -pub enum wasmer_memory_result_t { - WASMER_MEMORY_OK = 1, - WASMER_MEMORY_ERROR = 2, -} - -#[allow(non_camel_case_types)] -#[no_mangle] -#[repr(C)] -pub enum wasmer_table_result_t { - WASMER_TABLE_OK = 1, - WASMER_TABLE_ERROR = 2, +pub enum wasmer_result_t { + WASMER_OK = 1, + WASMER_ERROR = 2, } #[repr(u32)] @@ -131,7 +107,7 @@ pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { pub unsafe extern "C" fn wasmer_memory_new( mut memory: *mut *mut wasmer_memory_t, limits: wasmer_limits_t, -) -> wasmer_memory_result_t { +) -> wasmer_result_t { let desc = MemoryDescriptor { minimum: Pages(limits.min), maximum: Some(Pages(limits.max)), @@ -142,11 +118,11 @@ pub unsafe extern "C" fn wasmer_memory_new( Ok(memory) => memory, Err(error) => { update_last_error(error); - return wasmer_memory_result_t::WASMER_MEMORY_ERROR; + return wasmer_result_t::WASMER_ERROR; } }; unsafe { *memory = Box::into_raw(Box::new(new_memory)) as *mut wasmer_memory_t }; - wasmer_memory_result_t::WASMER_MEMORY_OK + wasmer_result_t::WASMER_OK } #[allow(clippy::cast_ptr_alignment)] @@ -154,14 +130,14 @@ pub unsafe extern "C" fn wasmer_memory_new( pub extern "C" fn wasmer_memory_grow( memory: *mut wasmer_memory_t, delta: uint32_t, -) -> wasmer_memory_result_t { +) -> wasmer_result_t { let memory = unsafe { Box::from_raw(memory as *mut Memory) }; let maybe_delta = memory.grow(Pages(delta)); Box::into_raw(memory); if let Some(_delta) = maybe_delta { - wasmer_memory_result_t::WASMER_MEMORY_OK + wasmer_result_t::WASMER_OK } else { - wasmer_memory_result_t::WASMER_MEMORY_ERROR + wasmer_result_t::WASMER_ERROR } } @@ -178,7 +154,7 @@ pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t pub unsafe extern "C" fn wasmer_table_new( mut table: *mut *mut wasmer_table_t, limits: wasmer_limits_t, -) -> wasmer_table_result_t { +) -> wasmer_result_t { let desc = TableDescriptor { element: ElementType::Anyfunc, minimum: limits.min, @@ -189,11 +165,11 @@ pub unsafe extern "C" fn wasmer_table_new( Ok(table) => table, Err(error) => { update_last_error(error); - return wasmer_table_result_t::WASMER_TABLE_ERROR; + return wasmer_result_t::WASMER_ERROR; } }; unsafe { *table = Box::into_raw(Box::new(new_table)) as *mut wasmer_table_t }; - wasmer_table_result_t::WASMER_TABLE_OK + wasmer_result_t::WASMER_OK } #[allow(clippy::cast_ptr_alignment)] @@ -201,14 +177,14 @@ pub unsafe extern "C" fn wasmer_table_new( pub extern "C" fn wasmer_table_grow( table: *mut wasmer_table_t, delta: uint32_t, -) -> wasmer_table_result_t { +) -> wasmer_result_t { let table = unsafe { Box::from_raw(table as *mut Table) }; let maybe_delta = table.grow(delta); Box::into_raw(table); if let Some(_delta) = maybe_delta { - wasmer_table_result_t::WASMER_TABLE_OK + wasmer_result_t::WASMER_OK } else { - wasmer_table_result_t::WASMER_TABLE_ERROR + wasmer_result_t::WASMER_ERROR } } @@ -305,10 +281,10 @@ pub unsafe extern "C" fn wasmer_instantiate( wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t, import_object: *mut wasmer_import_object_t, -) -> wasmer_compile_result_t { +) -> wasmer_result_t { let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; if wasm_bytes.is_null() { - return wasmer_compile_result_t::WASMER_COMPILE_ERROR; + return wasmer_result_t::WASMER_ERROR; } let bytes: &[u8] = unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; @@ -316,12 +292,12 @@ pub unsafe extern "C" fn wasmer_instantiate( let new_instance = match result { Ok(instance) => instance, Err(error) => { - return wasmer_compile_result_t::WASMER_COMPILE_ERROR; + return wasmer_result_t::WASMER_ERROR; } }; unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; Box::into_raw(import_object); - wasmer_compile_result_t::WASMER_COMPILE_OK + wasmer_result_t::WASMER_OK } #[allow(clippy::cast_ptr_alignment)] @@ -333,17 +309,17 @@ pub unsafe extern "C" fn wasmer_instance_call( params_len: c_int, results: *mut wasmer_value_t, results_len: c_int, -) -> wasmer_call_result_t { +) -> wasmer_result_t { // TODO handle params and results if instance.is_null() { - return wasmer_call_result_t::WASMER_CALL_ERROR; + return wasmer_result_t::WASMER_ERROR; } if name.is_null() { - return wasmer_call_result_t::WASMER_CALL_ERROR; + return wasmer_result_t::WASMER_ERROR; } if params.is_null() { - return wasmer_call_result_t::WASMER_CALL_ERROR; + return wasmer_result_t::WASMER_ERROR; } let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize); @@ -382,11 +358,11 @@ pub unsafe extern "C" fn wasmer_instance_call( }; results[0] = ret; } - wasmer_call_result_t::WASMER_CALL_OK + wasmer_result_t::WASMER_OK } Err(err) => { update_last_error(err); - wasmer_call_result_t::WASMER_CALL_ERROR + wasmer_result_t::WASMER_ERROR } } } diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index 13ce81cab..f0ca17504 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -39,15 +39,15 @@ int main() fclose(file); wasmer_instance_t *instance = NULL; - wasmer_compile_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); printf("Compile result: %d\n", compile_result); - assert(compile_result == WASMER_COMPILE_OK); + assert(compile_result == WASMER_OK); wasmer_value_t params[] = {}; wasmer_value_t results[] = {}; - wasmer_call_result_t call_result = wasmer_instance_call(instance, "hello_wasm", params, 0, results, 0); + wasmer_result_t call_result = wasmer_instance_call(instance, "hello_wasm", params, 0, results, 0); printf("Call result: %d\n", call_result); - assert(call_result == WASMER_CALL_OK); + assert(call_result == WASMER_OK); assert(print_str_called); assert(memory_len == 17); diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index 604f9544d..db24544f4 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -17,9 +17,9 @@ int main() fclose(file); wasmer_instance_t *instance = NULL; - wasmer_compile_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); printf("Compile result: %d\n", compile_result); - assert(compile_result == WASMER_COMPILE_OK); + assert(compile_result == WASMER_OK); wasmer_value_t param_one; param_one.tag = WASM_I32; @@ -32,16 +32,16 @@ int main() wasmer_value_t result_one; wasmer_value_t results[] = {result_one}; - wasmer_call_result_t call_result = wasmer_instance_call(instance, "sum", params, 2, results, 1); + wasmer_result_t call_result = wasmer_instance_call(instance, "sum", params, 2, results, 1); printf("Call result: %d\n", call_result); printf("Result: %d\n", results[0].value.I32); assert(results[0].value.I32 == 15); - assert(call_result == WASMER_CALL_OK); + assert(call_result == WASMER_OK); - wasmer_call_result_t call_result2 = wasmer_instance_call(instance, "sum", params, 1, results, 1); + wasmer_result_t call_result2 = wasmer_instance_call(instance, "sum", params, 1, results, 1); printf("Call result bad: %d\n", call_result2); - assert(call_result2 == WASMER_CALL_ERROR); + assert(call_result2 == WASMER_ERROR); int error_len = wasmer_last_error_length(); printf("Error len: `%d`\n", error_len); diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index d9379c78a..68ff27712 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -9,16 +9,16 @@ int main() wasmer_limits_t descriptor; descriptor.min = 10; descriptor.max = 15; - wasmer_memory_result_t memory_result = wasmer_memory_new(&memory, descriptor); + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); printf("Memory result: %d\n", memory_result); - assert(memory_result == WASMER_MEMORY_OK); + assert(memory_result == WASMER_OK); uint32_t len = wasmer_memory_length(memory); printf("Memory pages length: %d\n", len); assert(len == 10); - wasmer_memory_result_t grow_result = wasmer_memory_grow(memory, 2); - assert(grow_result == WASMER_MEMORY_OK); + wasmer_result_t grow_result = wasmer_memory_grow(memory, 2); + assert(grow_result == WASMER_OK); uint32_t new_len = wasmer_memory_length(memory); printf("Memory pages length: %d\n", new_len); @@ -29,8 +29,8 @@ int main() assert(bytes_len == 12 * 65536); // Err, grow beyond max - wasmer_memory_result_t grow_result2 = wasmer_memory_grow(memory, 10); - assert(grow_result2 == WASMER_MEMORY_ERROR); + wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10); + assert(grow_result2 == WASMER_ERROR); // int error_len = wasmer_last_error_length(); // char *error_str = malloc(error_len); // wasmer_last_error_message(error_str, error_len); @@ -42,7 +42,7 @@ int main() // wasmer_limits_t bad_descriptor; // bad_descriptor.min = 15; // bad_descriptor.max = 10; -// wasmer_memory_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor); +// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor); // printf("Bad memory result: %d\n", bad_memory_result); // assert(memory_result == WASMER_MEMORY_ERROR); // diff --git a/lib/runtime-c-api/tests/test-tables.c b/lib/runtime-c-api/tests/test-tables.c index f50a5af5f..3f8c29805 100644 --- a/lib/runtime-c-api/tests/test-tables.c +++ b/lib/runtime-c-api/tests/test-tables.c @@ -9,23 +9,23 @@ int main() wasmer_limits_t descriptor; descriptor.min = 10; descriptor.max = 15; - wasmer_table_result_t table_result = wasmer_table_new(&table, descriptor); + wasmer_result_t table_result = wasmer_table_new(&table, descriptor); printf("Table result: %d\n", table_result); - assert(table_result == WASMER_TABLE_OK); + assert(table_result == WASMER_OK); uint32_t len = wasmer_table_length(table); printf("Table length: %d\n", len); assert(len == 15); - // wasmer_table_result_t grow_result1 = wasmer_table_grow(&table, 5); - // assert(grow_result1 == WASMER_TABLE_OK); + // wasmer_result_t grow_result1 = wasmer_table_grow(&table, 5); + // assert(grow_result1 == WASMER_OK); // uint32_t len_grow1 = wasmer_table_length(table); // printf("Table length: %d\n", len_grow1); // assert(len_grow1 == 15); // // Try to grow beyond max - // wasmer_table_result_t grow_result2 = wasmer_table_grow(&table, 1); - // assert(grow_result2 == WASMER_TABLE_ERROR); + // wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1); + // assert(grow_result2 == WASMER_ERROR); // uint32_t len_grow2 = wasmer_table_length(table); // printf("Table length: %d\n", len_grow2); // assert(len_grow2 == 15); @@ -34,9 +34,9 @@ int main() // wasmer_limits_t bad_descriptor; // bad_descriptor.min = 15; // bad_descriptor.max = 10; -// wasmer_table_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor); +// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor); // printf("Table result: %d\n", table_bad_result); -// assert(table_result == WASMER_TABLE_ERROR); +// assert(table_result == WASMER_ERROR); printf("Destroy table\n"); wasmer_table_destroy(table); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 3f4a34a94..1b53f3123 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -7,24 +7,9 @@ #include typedef enum { - WASMER_CALL_OK = 1, - WASMER_CALL_ERROR = 2, -} wasmer_call_result_t; - -typedef enum { - WASMER_COMPILE_OK = 1, - WASMER_COMPILE_ERROR = 2, -} wasmer_compile_result_t; - -typedef enum { - WASMER_MEMORY_OK = 1, - WASMER_MEMORY_ERROR = 2, -} wasmer_memory_result_t; - -typedef enum { - WASMER_TABLE_OK = 1, - WASMER_TABLE_ERROR = 2, -} wasmer_table_result_t; + WASMER_OK = 1, + WASMER_ERROR = 2, +} wasmer_result_t; enum wasmer_value_tag { WASM_I32, @@ -97,22 +82,22 @@ void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const wasmer_value_tag *returns, int returns_len); -wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, - const char *name, - const wasmer_value_t *params, - int params_len, - wasmer_value_t *results, - int results_len); +wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, + const char *name, + const wasmer_value_t *params, + int params_len, + wasmer_value_t *results, + int results_len); const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx, uint32_t memory_idx); void wasmer_instance_destroy(wasmer_instance_t *instance); -wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, - uint8_t *wasm_bytes, - uint32_t wasm_bytes_len, - wasmer_import_object_t *import_object); +wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, + uint8_t *wasm_bytes, + uint32_t wasm_bytes_len, + wasmer_import_object_t *import_object); int wasmer_last_error_length(void); @@ -124,19 +109,19 @@ uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); void wasmer_memory_destroy(wasmer_memory_t *memory); -wasmer_memory_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); +wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); uint32_t wasmer_memory_length(wasmer_memory_t *memory); -wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); void wasmer_table_destroy(wasmer_table_t *table); -wasmer_table_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); +wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); uint32_t wasmer_table_length(wasmer_table_t *table); -wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index c7ddb5bdd..68b935202 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -5,24 +5,9 @@ #include #include -enum class wasmer_call_result_t { - WASMER_CALL_OK = 1, - WASMER_CALL_ERROR = 2, -}; - -enum class wasmer_compile_result_t { - WASMER_COMPILE_OK = 1, - WASMER_COMPILE_ERROR = 2, -}; - -enum class wasmer_memory_result_t { - WASMER_MEMORY_OK = 1, - WASMER_MEMORY_ERROR = 2, -}; - -enum class wasmer_table_result_t { - WASMER_TABLE_OK = 1, - WASMER_TABLE_ERROR = 2, +enum class wasmer_result_t { + WASMER_OK = 1, + WASMER_ERROR = 2, }; enum class wasmer_value_tag : uint32_t { @@ -97,22 +82,22 @@ void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const wasmer_value_tag *returns, int returns_len); -wasmer_call_result_t wasmer_instance_call(wasmer_instance_t *instance, - const char *name, - const wasmer_value_t *params, - int params_len, - wasmer_value_t *results, - int results_len); +wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, + const char *name, + const wasmer_value_t *params, + int params_len, + wasmer_value_t *results, + int results_len); const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx, uint32_t memory_idx); void wasmer_instance_destroy(wasmer_instance_t *instance); -wasmer_compile_result_t wasmer_instantiate(wasmer_instance_t **instance, - uint8_t *wasm_bytes, - uint32_t wasm_bytes_len, - wasmer_import_object_t *import_object); +wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, + uint8_t *wasm_bytes, + uint32_t wasm_bytes_len, + wasmer_import_object_t *import_object); int wasmer_last_error_length(); @@ -124,19 +109,19 @@ uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); void wasmer_memory_destroy(wasmer_memory_t *memory); -wasmer_memory_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); +wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); uint32_t wasmer_memory_length(wasmer_memory_t *memory); -wasmer_memory_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); void wasmer_table_destroy(wasmer_table_t *table); -wasmer_table_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); +wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); uint32_t wasmer_table_length(wasmer_table_t *table); -wasmer_table_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); From 34c45aee3d7047b112907e92b878dc9a008c8ad2 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 11 Feb 2019 20:08:54 -0600 Subject: [PATCH 32/50] Update last error for every error result --- lib/runtime-c-api/src/lib.rs | 41 ++++++++++++++++++++++++--- lib/runtime-c-api/tests/test-memory.c | 11 +++---- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 97267866d..319447d0c 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -5,6 +5,7 @@ use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::cell::RefCell; use std::error::Error; use std::ffi::CStr; +use std::fmt; use std::slice; use std::str; use std::sync::Arc; @@ -137,6 +138,9 @@ pub extern "C" fn wasmer_memory_grow( if let Some(_delta) = maybe_delta { wasmer_result_t::WASMER_OK } else { + update_last_error(CApiError { + msg: "unable to grow memory".to_string(), + }); wasmer_result_t::WASMER_ERROR } } @@ -184,6 +188,9 @@ pub extern "C" fn wasmer_table_grow( if let Some(_delta) = maybe_delta { wasmer_result_t::WASMER_OK } else { + update_last_error(CApiError { + msg: "unable to grow table".to_string(), + }); wasmer_result_t::WASMER_ERROR } } @@ -284,6 +291,9 @@ pub unsafe extern "C" fn wasmer_instantiate( ) -> wasmer_result_t { let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; if wasm_bytes.is_null() { + update_last_error(CApiError { + msg: "wasm bytes ptr is null".to_string(), + }); return wasmer_result_t::WASMER_ERROR; } let bytes: &[u8] = @@ -292,6 +302,11 @@ pub unsafe extern "C" fn wasmer_instantiate( let new_instance = match result { Ok(instance) => instance, Err(error) => { + // TODO the trait bound `wasmer_runtime::error::Error: std::error::Error` is not satisfied + //update_last_error(error); + update_last_error(CApiError { + msg: "error instantiating".to_string(), + }); return wasmer_result_t::WASMER_ERROR; } }; @@ -310,22 +325,27 @@ pub unsafe extern "C" fn wasmer_instance_call( results: *mut wasmer_value_t, results_len: c_int, ) -> wasmer_result_t { - // TODO handle params and results if instance.is_null() { + update_last_error(CApiError { + msg: "instance ptr is null".to_string(), + }); return wasmer_result_t::WASMER_ERROR; } if name.is_null() { + update_last_error(CApiError { + msg: "name ptr is null".to_string(), + }); return wasmer_result_t::WASMER_ERROR; } - if params.is_null() { + update_last_error(CApiError { + msg: "params ptr is null".to_string(), + }); return wasmer_result_t::WASMER_ERROR; } let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize); - // TODO Fix this conversion and params let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); - // let params= &[Value::I32(3), Value::I32(4)]; let func_name_c = unsafe { CStr::from_ptr(name) }; let func_name_r = func_name_c.to_str().unwrap(); @@ -576,3 +596,16 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length: error_message.len() as c_int } + +#[derive(Debug)] +struct CApiError { + msg: String, +} + +impl fmt::Display for CApiError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", &self.msg) + } +} + +impl Error for CApiError {} diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index 68ff27712..d472c2b08 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -31,11 +31,12 @@ int main() // Err, grow beyond max wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10); assert(grow_result2 == WASMER_ERROR); -// int error_len = wasmer_last_error_length(); -// char *error_str = malloc(error_len); -// wasmer_last_error_message(error_str, error_len); -// assert(0 == strcmp(error_str, "Creation error")); -// free(error_str); + int error_len = wasmer_last_error_length(); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + assert(0 == strcmp(error_str, "unable to grow memory")); + free(error_str); // wasmer_memory_t *bad_memory = NULL; From 27cbfc0b0bc87e877ad0b5ef4c58381818da1c51 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 11 Feb 2019 23:14:32 -0600 Subject: [PATCH 33/50] Add documentation to API functions --- lib/runtime-c-api/src/lib.rs | 90 ++++++++++++++++++++++++++ lib/runtime-c-api/wasmer.h | 121 +++++++++++++++++++++++++++++++++++ lib/runtime-c-api/wasmer.hh | 71 ++++++++++++++++++++ 3 files changed, 282 insertions(+) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 319447d0c..d5443ba7f 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -85,6 +85,7 @@ pub struct wasmer_limits_t { pub max: uint32_t, } +/// Returns true for valid wasm bytes and false for invalid bytes #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_validate( @@ -99,11 +100,22 @@ pub unsafe extern "C" fn wasmer_validate( wasmer_runtime_core::validate(bytes) } +/// Creates a new ImportObject and returns a pointer to it. +/// The caller owns the object and should call `wasmer_import_object_destroy` to free it. #[no_mangle] pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t } +/// Creates a new Memory for the given descriptor and initializes the given +/// pointer to pointer to a pointer to the new memory. +/// +/// The caller owns the object and should call `wasmer_memory_destroy` to free it. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[no_mangle] pub unsafe extern "C" fn wasmer_memory_new( mut memory: *mut *mut wasmer_memory_t, @@ -126,6 +138,12 @@ pub unsafe extern "C" fn wasmer_memory_new( wasmer_result_t::WASMER_OK } +/// Grows a Memory by the given number of pages. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_grow( @@ -145,6 +163,7 @@ pub extern "C" fn wasmer_memory_grow( } } +/// Returns the current length in pages of the given memory #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t { @@ -154,6 +173,15 @@ pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t len } +/// Creates a new Table for the given descriptor and initializes the given +/// pointer to pointer to a pointer to the new Table. +/// +/// The caller owns the object and should call `wasmer_table_destroy` to free it. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[no_mangle] pub unsafe extern "C" fn wasmer_table_new( mut table: *mut *mut wasmer_table_t, @@ -176,6 +204,12 @@ pub unsafe extern "C" fn wasmer_table_new( wasmer_result_t::WASMER_OK } +/// Grows a Table by the given number of elements. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_table_grow( @@ -195,6 +229,7 @@ pub extern "C" fn wasmer_table_grow( } } +/// Returns the current length of the given Table #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_table_length(table: *mut wasmer_table_t) -> uint32_t { @@ -204,6 +239,7 @@ pub extern "C" fn wasmer_table_length(table: *mut wasmer_table_t) -> uint32_t { len } +/// Frees memory for the given Table #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_table_destroy(table: *mut wasmer_table_t) { @@ -212,6 +248,8 @@ pub extern "C" fn wasmer_table_destroy(table: *mut wasmer_table_t) { } } +/// Creates a new Global and returns a pointer to it. +/// The caller owns the object and should call `wasmer_global_destroy` to free it. #[no_mangle] pub unsafe extern "C" fn wasmer_global_new( value: wasmer_value_t, @@ -225,6 +263,7 @@ pub unsafe extern "C" fn wasmer_global_new( unsafe { Box::into_raw(Box::new(global)) as *mut wasmer_global_t } } +/// Gets the value stored by the given Global #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_global_get(global: *mut wasmer_global_t) -> wasmer_value_t { @@ -234,6 +273,7 @@ pub extern "C" fn wasmer_global_get(global: *mut wasmer_global_t) -> wasmer_valu value } +/// Sets the value stored by the given Global #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_global_set(global: *mut wasmer_global_t, value: wasmer_value_t) { @@ -242,6 +282,7 @@ pub extern "C" fn wasmer_global_set(global: *mut wasmer_global_t, value: wasmer_ Box::into_raw(global); } +/// Returns a descriptor (type, mutability) of the given Global #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_global_get_descriptor( @@ -257,6 +298,7 @@ pub extern "C" fn wasmer_global_get_descriptor( desc } +/// Frees memory for the given Global #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_global_destroy(global: *mut wasmer_global_t) { @@ -265,6 +307,7 @@ pub extern "C" fn wasmer_global_destroy(global: *mut wasmer_global_t) { } } +/// Frees memory for the given ImportObject #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { @@ -273,6 +316,7 @@ pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import } } +/// Frees memory for the given Memory #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_destroy(memory: *mut wasmer_memory_t) { @@ -281,6 +325,12 @@ pub extern "C" fn wasmer_memory_destroy(memory: *mut wasmer_memory_t) { } } +/// Creates a new Instance from the given wasm bytes and imports. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_instantiate( @@ -315,6 +365,13 @@ pub unsafe extern "C" fn wasmer_instantiate( wasmer_result_t::WASMER_OK } +/// Calls an instances exported function by `name` with the provided parameters. +/// Results are set using the provided `results` pointer. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_instance_call( @@ -387,6 +444,12 @@ pub unsafe extern "C" fn wasmer_instance_call( } } +/// Registers a `func` with provided `name` and `namespace` into the ImportObject. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_imports_set_import_func( @@ -428,6 +491,8 @@ pub unsafe extern "C" fn wasmer_imports_set_import_func( // }; } +/// Gets the memory within the context at the index `memory_idx`. +/// The index is always 0 until multiple memories are supported. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_instance_context_memory( @@ -439,6 +504,7 @@ pub extern "C" fn wasmer_instance_context_memory( memory as *const Memory as *const wasmer_memory_t } +/// Gets the start pointer to the bytes within a Memory #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_data(mem: *mut wasmer_memory_t) -> *mut uint8_t { @@ -447,6 +513,7 @@ pub extern "C" fn wasmer_memory_data(mem: *mut wasmer_memory_t) -> *mut uint8_t unsafe { ((*memory).view::()[..]).as_ptr() as *mut Cell as *mut u8 } } +/// Gets the size in bytes of a Memory #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_data_length(mem: *mut wasmer_memory_t) -> uint32_t { @@ -455,6 +522,7 @@ pub extern "C" fn wasmer_memory_data_length(mem: *mut wasmer_memory_t) -> uint32 len as uint32_t } +/// Frees memory for the given Instance #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { @@ -555,6 +623,15 @@ fn take_last_error() -> Option> { LAST_ERROR.with(|prev| prev.borrow_mut().take()) } +/// Gets the length in bytes of the last error. +/// This can be used to dynamically allocate a buffer with the correct number of +/// bytes needed to store a message. +/// +/// # Example +/// ``` +/// int error_len = wasmer_last_error_length(); +/// char *error_str = malloc(error_len); +/// ``` #[no_mangle] pub extern "C" fn wasmer_last_error_length() -> c_int { LAST_ERROR.with(|prev| match *prev.borrow() { @@ -563,6 +640,19 @@ pub extern "C" fn wasmer_last_error_length() -> c_int { }) } +/// Stores the last error message into the provided buffer up to the given `length`. +/// The `length` parameter must be large enough to store the last error message. +/// +/// Returns the length of the string in bytes. +/// Returns `-1` if an error occurs. +/// +/// # Example +/// ``` +/// int error_len = wasmer_last_error_length(); +/// char *error_str = malloc(error_len); +/// wasmer_last_error_message(error_str, error_len); +/// printf("Error str: `%s`\n", error_str); +/// ``` #[no_mangle] pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length: c_int) -> c_int { if buffer.is_null() { diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 1b53f3123..6b855404a 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -59,20 +59,49 @@ typedef struct { } wasmer_table_t; +/** + * Frees memory for the given Global + */ void wasmer_global_destroy(wasmer_global_t *global); +/** + * Gets the value stored by the given Global + */ wasmer_value_t wasmer_global_get(wasmer_global_t *global); +/** + * Returns a descriptor (type, mutability) of the given Global + */ wasmer_global_descriptor_t wasmer_global_get_descriptor(wasmer_global_t *global); +/** + * Creates a new Global and returns a pointer to it. + * The caller owns the object and should call `wasmer_global_destroy` to free it. + */ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); +/** + * Sets the value stored by the given Global + */ void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); +/** + * Frees memory for the given ImportObject + */ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); +/** + * Creates a new ImportObject and returns a pointer to it. + * The caller owns the object and should call `wasmer_import_object_destroy` to free it. + */ wasmer_import_object_t *wasmer_import_object_new(void); +/** + * Registers a `func` with provided `name` and `namespace` into the ImportObject. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const char *namespace_, const char *name, @@ -82,6 +111,13 @@ void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const wasmer_value_tag *returns, int returns_len); +/** + * Calls an instances exported function by `name` with the provided parameters. + * Results are set using the provided `results` pointer. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, const wasmer_value_t *params, @@ -89,40 +125,125 @@ wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, wasmer_value_t *results, int results_len); +/** + * Gets the memory within the context at the index `memory_idx`. + * The index is always 0 until multiple memories are supported. + */ const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx, uint32_t memory_idx); +/** + * Frees memory for the given Instance + */ void wasmer_instance_destroy(wasmer_instance_t *instance); +/** + * Creates a new Instance from the given wasm bytes and imports. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +/** + * Gets the length in bytes of the last error. + * This can be used to dynamically allocate a buffer with the correct number of + * bytes needed to store a message. + * # Example + * ``` + * int error_len = wasmer_last_error_length(); + * char *error_str = malloc(error_len); + * ``` + */ int wasmer_last_error_length(void); +/** + * Stores the last error message into the provided buffer up to the given `length`. + * The `length` parameter must be large enough to store the last error message. + * Returns the length of the string in bytes. + * Returns `-1` if an error occurs. + * # Example + * ``` + * int error_len = wasmer_last_error_length(); + * char *error_str = malloc(error_len); + * wasmer_last_error_message(error_str, error_len); + * printf("Error str: `%s`\n", error_str); + * ``` + */ int wasmer_last_error_message(char *buffer, int length); +/** + * Gets the start pointer to the bytes within a Memory + */ uint8_t *wasmer_memory_data(wasmer_memory_t *mem); +/** + * Gets the size in bytes of a Memory + */ uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); +/** + * Frees memory for the given Memory + */ void wasmer_memory_destroy(wasmer_memory_t *memory); +/** + * Grows a Memory by the given number of pages. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); +/** + * Returns the current length in pages of the given memory + */ uint32_t wasmer_memory_length(wasmer_memory_t *memory); +/** + * Creates a new Memory for the given descriptor and initializes the given + * pointer to pointer to a pointer to the new memory. + * The caller owns the object and should call `wasmer_memory_destroy` to free it. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +/** + * Frees memory for the given Table + */ void wasmer_table_destroy(wasmer_table_t *table); +/** + * Grows a Table by the given number of elements. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); +/** + * Returns the current length of the given Table + */ uint32_t wasmer_table_length(wasmer_table_t *table); +/** + * Creates a new Table for the given descriptor and initializes the given + * pointer to pointer to a pointer to the new Table. + * The caller owns the object and should call `wasmer_table_destroy` to free it. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +/** + * Returns true for valid wasm bytes and false for invalid bytes + */ bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); #endif /* WASMER_H */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 68b935202..24c4f3f14 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -59,20 +59,33 @@ struct wasmer_table_t { extern "C" { +/// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); +/// Gets the value stored by the given Global wasmer_value_t wasmer_global_get(wasmer_global_t *global); +/// Returns a descriptor (type, mutability) of the given Global wasmer_global_descriptor_t wasmer_global_get_descriptor(wasmer_global_t *global); +/// Creates a new Global and returns a pointer to it. +/// The caller owns the object and should call `wasmer_global_destroy` to free it. wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); +/// Sets the value stored by the given Global void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); +/// Frees memory for the given ImportObject void wasmer_import_object_destroy(wasmer_import_object_t *import_object); +/// Creates a new ImportObject and returns a pointer to it. +/// The caller owns the object and should call `wasmer_import_object_destroy` to free it. wasmer_import_object_t *wasmer_import_object_new(); +/// Registers a `func` with provided `name` and `namespace` into the ImportObject. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const char *namespace_, const char *name, @@ -82,6 +95,11 @@ void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, const wasmer_value_tag *returns, int returns_len); +/// Calls an instances exported function by `name` with the provided parameters. +/// Results are set using the provided `results` pointer. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, const wasmer_value_t *params, @@ -89,40 +107,93 @@ wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, wasmer_value_t *results, int results_len); +/// Gets the memory within the context at the index `memory_idx`. +/// The index is always 0 until multiple memories are supported. const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx, uint32_t memory_idx); +/// Frees memory for the given Instance void wasmer_instance_destroy(wasmer_instance_t *instance); +/// Creates a new Instance from the given wasm bytes and imports. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, wasmer_import_object_t *import_object); +/// Gets the length in bytes of the last error. +/// This can be used to dynamically allocate a buffer with the correct number of +/// bytes needed to store a message. +/// # Example +/// ``` +/// int error_len = wasmer_last_error_length(); +/// char *error_str = malloc(error_len); +/// ``` int wasmer_last_error_length(); +/// Stores the last error message into the provided buffer up to the given `length`. +/// The `length` parameter must be large enough to store the last error message. +/// Returns the length of the string in bytes. +/// Returns `-1` if an error occurs. +/// # Example +/// ``` +/// int error_len = wasmer_last_error_length(); +/// char *error_str = malloc(error_len); +/// wasmer_last_error_message(error_str, error_len); +/// printf("Error str: `%s`\n", error_str); +/// ``` int wasmer_last_error_message(char *buffer, int length); +/// Gets the start pointer to the bytes within a Memory uint8_t *wasmer_memory_data(wasmer_memory_t *mem); +/// Gets the size in bytes of a Memory uint32_t wasmer_memory_data_length(wasmer_memory_t *mem); +/// Frees memory for the given Memory void wasmer_memory_destroy(wasmer_memory_t *memory); +/// Grows a Memory by the given number of pages. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta); +/// Returns the current length in pages of the given memory uint32_t wasmer_memory_length(wasmer_memory_t *memory); +/// Creates a new Memory for the given descriptor and initializes the given +/// pointer to pointer to a pointer to the new memory. +/// The caller owns the object and should call `wasmer_memory_destroy` to free it. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +/// Frees memory for the given Table void wasmer_table_destroy(wasmer_table_t *table); +/// Grows a Table by the given number of elements. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta); +/// Returns the current length of the given Table uint32_t wasmer_table_length(wasmer_table_t *table); +/// Creates a new Table for the given descriptor and initializes the given +/// pointer to pointer to a pointer to the new Table. +/// The caller owns the object and should call `wasmer_table_destroy` to free it. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +/// Returns true for valid wasm bytes and false for invalid bytes bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len); } // extern "C" From 93979aeae20db75eec41ab48e9220baf0d4e1ebc Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Wed, 13 Feb 2019 20:02:11 -0600 Subject: [PATCH 34/50] Add get exports from instance --- lib/runtime-c-api/src/lib.rs | 135 +++++++++++++++++- lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 + lib/runtime-c-api/tests/test-exports.c | 43 ++++++ .../tests/test-import-function.c | 10 +- lib/runtime-c-api/wasmer.h | 42 ++++++ lib/runtime-c-api/wasmer.hh | 31 ++++ 7 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 lib/runtime-c-api/tests/test-exports.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index d5443ba7f..e6e82dc0d 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -5,6 +5,7 @@ use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::cell::RefCell; use std::error::Error; use std::ffi::CStr; +use std::ffi::CString; use std::fmt; use std::slice; use std::str; @@ -75,6 +76,10 @@ pub struct wasmer_memory_t(); #[derive(Clone)] pub struct wasmer_table_t(); +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_func_t(); + #[repr(C)] #[derive(Clone)] pub struct wasmer_global_t(); @@ -85,6 +90,47 @@ pub struct wasmer_limits_t { pub max: uint32_t, } +#[repr(C)] +pub struct wasmer_func_signature { + pub params: *const wasmer_value_tag, + pub params_len: c_int, + pub returns: *const wasmer_value_tag, + pub returns_len: c_int, +} + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import { + tag: wasmer_import_export_kind, + value: wasmer_import_export_value, +} + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_export_t; + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_exports_t; + +#[repr(u32)] +#[derive(Clone)] +pub enum wasmer_import_export_kind { + WASM_FUNCTION, + WASM_GLOBAL, + WASM_MEMORY, + WASM_TABLE, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub union wasmer_import_export_value { + func: *const wasmer_func_t, + table: *const wasmer_table_t, + memory: *const wasmer_memory_t, + global: *const wasmer_global_t, +} + /// Returns true for valid wasm bytes and false for invalid bytes #[allow(clippy::cast_ptr_alignment)] #[no_mangle] @@ -413,7 +459,6 @@ pub unsafe extern "C" fn wasmer_instance_call( Box::into_raw(instance); match result { Ok(results_vec) => { - println!("Call Res: {:?}", results_vec); if results_vec.len() > 0 { let ret = match results_vec[0] { Value::I32(x) => wasmer_value_t { @@ -444,6 +489,83 @@ pub unsafe extern "C" fn wasmer_instance_call( } } +/// Gets Exports for the given instance +/// +/// The caller owns the object and should call `wasmer_exports_destroy` to free it. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_instance_exports( + instance: *mut wasmer_instance_t, + exports: *mut *mut wasmer_exports_t, +) { + let mut instance = unsafe { Box::from_raw(instance as *mut Instance) }; + let named_exports: Box = + Box::new(NamedExports(instance.exports().map(|e| e.into()).collect())); + unsafe { *exports = Box::into_raw(named_exports) as *mut wasmer_exports_t }; + Box::into_raw(instance); +} + +pub struct NamedExports(Vec); + +/// Frees the memory for the given exports +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_exports_destroy(exports: *mut wasmer_exports_t) { + if !exports.is_null() { + drop(unsafe { Box::from_raw(exports as *mut NamedExports) }); + } +} + +/// Gets the length of the exports +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_exports_len(exports: *mut wasmer_exports_t) -> c_int { + if exports.is_null() { + return 0; + } + (*(exports as *mut NamedExports)).0.len() as c_int +} + +/// Gets wasmer_export by index +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_exports_get( + exports: *mut wasmer_exports_t, + idx: c_int, +) -> *mut wasmer_export_t { + if exports.is_null() { + return ptr::null_mut(); + } + let mut named_exports = unsafe { Box::from_raw(exports as *mut NamedExports) }; + let ptr = &mut (*named_exports).0[idx as usize] as *mut NamedExport as *mut wasmer_export_t; + Box::into_raw(named_exports); + ptr +} + +/// Gets wasmer_export kind +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_export_kind( + export: *mut wasmer_export_t, +) -> wasmer_import_export_kind { + let named_export = &*(export as *mut NamedExport); + match named_export.export { + Export::Table(_) => wasmer_import_export_kind::WASM_TABLE, + Export::Function { .. } => wasmer_import_export_kind::WASM_FUNCTION, + Export::Global(_) => wasmer_import_export_kind::WASM_GLOBAL, + Export::Memory(_) => wasmer_import_export_kind::WASM_MEMORY, + } +} + +///// Gets wasmer_export func +//#[no_mangle] +//pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) { +// if exports.is_null() { +// return ptr::null_mut(); +// } +// let named_export = &*(export as *mut NamedExport); +//} + /// Registers a `func` with provided `name` and `namespace` into the ImportObject. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. @@ -606,6 +728,12 @@ impl From for Type { } } +impl From<(std::string::String, wasmer_runtime_core::export::Export)> for NamedExport { + fn from((name, export): (String, Export)) -> Self { + NamedExport { name, export } + } +} + // Error reporting thread_local! { @@ -699,3 +827,8 @@ impl fmt::Display for CApiError { } impl Error for CApiError {} + +struct NamedExport { + name: String, + export: Export, +} diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 6a96cd53f..c8dfca857 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -10,6 +10,7 @@ compile_commands.json CTestTestfile.cmake _deps test-globals +test-exports test-instantiate test-import-function test-memory diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index d15934df5..ce970d4bf 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required (VERSION 2.6) project (WasmerCApiTests) +add_executable(test-exports test-exports.c) add_executable(test-globals test-globals.c) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) @@ -17,6 +18,8 @@ if(NOT WASMER_LIB) message(FATAL_ERROR "wasmer library not found") endif() +target_link_libraries(test-exports + general ${WASMER_LIB}) target_link_libraries(test-globals general ${WASMER_LIB}) target_link_libraries(test-instantiate @@ -31,6 +34,7 @@ target_link_libraries(test-tables general ${WASMER_LIB}) enable_testing() +add_test(test-exports test-exports) add_test(test-globals test-globals) add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c new file mode 100644 index 000000000..8516d562b --- /dev/null +++ b/lib/runtime-c-api/tests/test-exports.c @@ -0,0 +1,43 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + wasmer_import_object_t *import_object = wasmer_import_object_new(); + + // Read the wasm file bytes + FILE *file = fopen("sum.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_instance_t *instance = NULL; + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_OK); + + wasmer_exports_t *exports = NULL; + wasmer_instance_exports(instance, &exports); + + int exports_len = wasmer_exports_len(exports); + printf("exports_len: %d\n", exports_len); + assert(exports_len == 1); + + wasmer_export_t *export = wasmer_exports_get(exports, 0); + + wasmer_import_export_kind kind = wasmer_export_kind(export); + assert(kind == WASM_FUNCTION); + + printf("Destroy instance\n"); + wasmer_instance_destroy(instance); + printf("Destroy import object\n"); + wasmer_import_object_destroy(import_object); + printf("Destroy exports\n"); + wasmer_exports_destroy(exports); + return 0; +} \ No newline at end of file diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index f0ca17504..b42817abc 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -8,11 +8,13 @@ static memory_len = 0; static ptr_len = 0; static char actual_str[14] = {}; -void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) { +void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) +{ wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); uint32_t mem_len = wasmer_memory_length(memory); uint8_t *mem_bytes = wasmer_memory_data(memory); - for(int32_t idx = 0; idx < len; idx++){ + for (int32_t idx = 0; idx < len; idx++) + { actual_str[idx] = mem_bytes[ptr + idx]; } actual_str[13] = '\0'; @@ -54,8 +56,8 @@ int main() assert(ptr_len == 13); assert(0 == strcmp(actual_str, "Hello, World!")); - printf("Destroy instance\n"); - wasmer_instance_destroy(instance); + // printf("Destroy instance\n"); + // wasmer_instance_destroy(instance); printf("Destroy import object\n"); wasmer_import_object_destroy(import_object); return 0; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 6b855404a..86230de1c 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -6,6 +6,14 @@ #include #include +enum wasmer_import_export_kind { + WASM_FUNCTION, + WASM_GLOBAL, + WASM_MEMORY, + WASM_TABLE, +}; +typedef uint32_t wasmer_import_export_kind; + typedef enum { WASMER_OK = 1, WASMER_ERROR = 2, @@ -27,6 +35,14 @@ typedef struct wasmer_instance_t wasmer_instance_t; typedef struct { +} wasmer_export_t; + +typedef struct { + +} wasmer_exports_t; + +typedef struct { + } wasmer_global_t; typedef union { @@ -59,6 +75,26 @@ typedef struct { } wasmer_table_t; +/** + * Gets wasmer_export kind + */ +wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); + +/** + * Frees the memory for the given exports + */ +void wasmer_exports_destroy(wasmer_exports_t *exports); + +/** + * Gets wasmer_export by index + */ +wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx); + +/** + * Gets the length of the exports + */ +int wasmer_exports_len(wasmer_exports_t *exports); + /** * Frees memory for the given Global */ @@ -137,6 +173,12 @@ const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t */ void wasmer_instance_destroy(wasmer_instance_t *instance); +/** + * Gets Exports for the given instance + * The caller owns the object and should call `wasmer_exports_destroy` to free it. + */ +void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports); + /** * Creates a new Instance from the given wasm bytes and imports. * Returns `wasmer_result_t::WASMER_OK` upon success. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 24c4f3f14..32b6e435f 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -5,6 +5,13 @@ #include #include +enum class wasmer_import_export_kind : uint32_t { + WASM_FUNCTION, + WASM_GLOBAL, + WASM_MEMORY, + WASM_TABLE, +}; + enum class wasmer_result_t { WASMER_OK = 1, WASMER_ERROR = 2, @@ -23,6 +30,14 @@ struct wasmer_instance_context_t; struct wasmer_instance_t; +struct wasmer_export_t { + +}; + +struct wasmer_exports_t { + +}; + struct wasmer_global_t { }; @@ -59,6 +74,18 @@ struct wasmer_table_t { extern "C" { +/// Gets wasmer_export kind +wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); + +/// Frees the memory for the given exports +void wasmer_exports_destroy(wasmer_exports_t *exports); + +/// Gets wasmer_export by index +wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx); + +/// Gets the length of the exports +int wasmer_exports_len(wasmer_exports_t *exports); + /// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); @@ -115,6 +142,10 @@ const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t /// Frees memory for the given Instance void wasmer_instance_destroy(wasmer_instance_t *instance); +/// Gets Exports for the given instance +/// The caller owns the object and should call `wasmer_exports_destroy` to free it. +void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports); + /// Creates a new Instance from the given wasm bytes and imports. /// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` From bfd5e21605be3db7b1a8eb1be9c0c5a2632efb67 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Thu, 14 Feb 2019 00:00:39 -0600 Subject: [PATCH 35/50] Add export_name and export_func --- lib/runtime-c-api/src/lib.rs | 101 +++++++++++++++++++++++++ lib/runtime-c-api/tests/test-exports.c | 26 +++++++ lib/runtime-c-api/wasmer.h | 38 +++++++++- lib/runtime-c-api/wasmer.hh | 30 +++++++- 4 files changed, 190 insertions(+), 5 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index e6e82dc0d..1931656e7 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -131,6 +131,12 @@ pub union wasmer_import_export_value { global: *const wasmer_global_t, } +#[repr(C)] +pub struct wasmer_byte_array { + bytes: *const uint8_t, + bytes_len: uint32_t, +} + /// Returns true for valid wasm bytes and false for invalid bytes #[allow(clippy::cast_ptr_alignment)] #[no_mangle] @@ -557,6 +563,101 @@ pub unsafe extern "C" fn wasmer_export_kind( } } +/// Gets func from wasm_export +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_export_to_func( + export: *mut wasmer_export_t, +) -> *const wasmer_func_t { + let named_export = &*(export as *mut NamedExport); + &named_export.export as *const Export as *const wasmer_func_t +} + +/// Gets name from wasmer_export +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) -> wasmer_byte_array { + let named_export = &*(export as *mut NamedExport); + wasmer_byte_array { + bytes: named_export.name.as_ptr(), + bytes_len: named_export.name.len() as u32, + } +} + +/// Calls a `func` with the provided parameters. +/// Results are set using the provided `results` pointer. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_func_call( + func: *mut wasmer_func_t, + params: *const wasmer_value_t, + params_len: c_int, + results: *mut wasmer_value_t, + results_len: c_int, +) -> wasmer_result_t { + if func.is_null() { + update_last_error(CApiError { + msg: "func ptr is null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + if params.is_null() { + update_last_error(CApiError { + msg: "params ptr is null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + + let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize); + let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); + + let export_func = unsafe { Box::from_raw(func as *mut Export) }; + + let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize); + // TODO implement func.call + update_last_error(CApiError { + msg: "wasmer_func_call not yet implemented".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + // let result = instance.call(func_name_r, ¶ms[..]); + // Box::into_raw(export_func); + // match result { + // Ok(results_vec) => { + // if results_vec.len() > 0 { + // let ret = match results_vec[0] { + // Value::I32(x) => wasmer_value_t { + // tag: wasmer_value_tag::WASM_I32, + // value: wasmer_value { I32: x }, + // }, + // Value::I64(x) => wasmer_value_t { + // tag: wasmer_value_tag::WASM_I64, + // value: wasmer_value { I64: x }, + // }, + // Value::F32(x) => wasmer_value_t { + // tag: wasmer_value_tag::WASM_F32, + // value: wasmer_value { F32: x }, + // }, + // Value::F64(x) => wasmer_value_t { + // tag: wasmer_value_tag::WASM_F64, + // value: wasmer_value { F64: x }, + // }, + // }; + // results[0] = ret; + // } + // wasmer_result_t::WASMER_OK + // } + // Err(err) => { + // update_last_error(err); + // wasmer_result_t::WASMER_ERROR + // } + // } +} + ///// Gets wasmer_export func //#[no_mangle] //pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) { diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index 8516d562b..b00adb790 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -32,6 +32,32 @@ int main() wasmer_import_export_kind kind = wasmer_export_kind(export); assert(kind == WASM_FUNCTION); + wasmer_func_t *func = wasmer_export_to_func(export); + + wasmer_byte_array name_bytes = wasmer_export_name(export); + assert(name_bytes.bytes_len == 3); + char expected[] = {'s', 'u', 'm'}; + for(int idx = 0; idx < 3; idx++){ + printf("%c\n", name_bytes.bytes[idx]); + assert(name_bytes.bytes[idx] == expected[idx]); + } + +// wasmer_value_t param_one; +// param_one.tag = WASM_I32; +// param_one.value.I32 = 7; +// wasmer_value_t param_two; +// param_two.tag = WASM_I32; +// param_two.value.I32 = 8; +// wasmer_value_t params[] = {param_one, param_two}; +// wasmer_value_t result_one; +// wasmer_value_t results[] = {result_one}; +// +// wasmer_result_t call_result = wasmer_func_call(func, params, 2, results, 1); +// printf("Call result: %d\n", call_result); +// printf("Result: %d\n", results[0].value.I32); +// assert(results[0].value.I32 == 15); +// assert(call_result == WASMER_OK); + printf("Destroy instance\n"); wasmer_instance_destroy(instance); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 86230de1c..f55014bee 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -38,12 +38,17 @@ typedef struct { } wasmer_export_t; typedef struct { - -} wasmer_exports_t; + const uint8_t *bytes; + uint32_t bytes_len; +} wasmer_byte_array; typedef struct { -} wasmer_global_t; +} wasmer_func_t; + +typedef struct { + +} wasmer_exports_t; typedef union { int32_t I32; @@ -57,6 +62,10 @@ typedef struct { wasmer_value value; } wasmer_value_t; +typedef struct { + +} wasmer_global_t; + typedef struct { bool mutable_; wasmer_value_tag kind; @@ -80,6 +89,16 @@ typedef struct { */ wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); +/** + * Gets func from wasm_export + */ +wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); + +/** + * Gets func from wasm_export + */ +const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_); + /** * Frees the memory for the given exports */ @@ -95,6 +114,19 @@ wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx); */ int wasmer_exports_len(wasmer_exports_t *exports); +/** + * Calls a `func` with the provided parameters. + * Results are set using the provided `results` pointer. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_func_call(wasmer_func_t *func, + const wasmer_value_t *params, + int params_len, + wasmer_value_t *results, + int results_len); + /** * Frees memory for the given Global */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 32b6e435f..02de6f52b 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -34,11 +34,16 @@ struct wasmer_export_t { }; -struct wasmer_exports_t { +struct wasmer_byte_array { + const uint8_t *bytes; + uint32_t bytes_len; +}; + +struct wasmer_func_t { }; -struct wasmer_global_t { +struct wasmer_exports_t { }; @@ -54,6 +59,10 @@ struct wasmer_value_t { wasmer_value value; }; +struct wasmer_global_t { + +}; + struct wasmer_global_descriptor_t { bool mutable_; wasmer_value_tag kind; @@ -77,6 +86,12 @@ extern "C" { /// Gets wasmer_export kind wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); +/// Gets func from wasm_export +wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); + +/// Gets func from wasm_export +const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_); + /// Frees the memory for the given exports void wasmer_exports_destroy(wasmer_exports_t *exports); @@ -86,6 +101,17 @@ wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx); /// Gets the length of the exports int wasmer_exports_len(wasmer_exports_t *exports); +/// Calls a `func` with the provided parameters. +/// Results are set using the provided `results` pointer. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_func_call(wasmer_func_t *func, + const wasmer_value_t *params, + int params_len, + wasmer_value_t *results, + int results_len); + /// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); From 3ebb80e50e8049da79a270880d8dcd070d63df43 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Fri, 15 Feb 2019 09:40:28 -0600 Subject: [PATCH 36/50] Update imports and add func_new --- lib/runtime-c-api/src/lib.rs | 93 +++++++++++++++++-- lib/runtime-c-api/tests/test-exports.c | 7 +- .../tests/test-import-function.c | 41 +++++++- lib/runtime-c-api/tests/test-instantiate.c | 6 +- lib/runtime-c-api/wasmer.h | 42 +++++++-- lib/runtime-c-api/wasmer.hh | 38 ++++++-- 6 files changed, 196 insertions(+), 31 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 1931656e7..511f4304a 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -3,6 +3,7 @@ extern crate wasmer_runtime_core; use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::cell::RefCell; +use std::collections::HashMap; use std::error::Error; use std::ffi::CStr; use std::ffi::CString; @@ -99,8 +100,9 @@ pub struct wasmer_func_signature { } #[repr(C)] -#[derive(Clone)] -pub struct wasmer_import { +pub struct wasmer_import_t { + module_name: wasmer_byte_array, + import_name: wasmer_byte_array, tag: wasmer_import_export_kind, value: wasmer_import_export_value, } @@ -389,18 +391,63 @@ pub unsafe extern "C" fn wasmer_instantiate( mut instance: *mut *mut wasmer_instance_t, wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t, - import_object: *mut wasmer_import_object_t, + imports: *mut wasmer_import_t, + imports_len: c_int, ) -> wasmer_result_t { - let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; if wasm_bytes.is_null() { update_last_error(CApiError { msg: "wasm bytes ptr is null".to_string(), }); return wasmer_result_t::WASMER_ERROR; } + let imports: &[wasmer_import_t] = slice::from_raw_parts(imports, imports_len as usize); + let mut import_object = ImportObject::new(); + let mut namespaces = HashMap::new(); + for import in imports { + let module_name = slice::from_raw_parts( + import.module_name.bytes, + import.module_name.bytes_len as usize, + ); + let module_name = if let Ok(s) = std::str::from_utf8(module_name) { + s + } else { + update_last_error(CApiError { + msg: "error converting module name to string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let import_name = slice::from_raw_parts( + import.import_name.bytes, + import.import_name.bytes_len as usize, + ); + let import_name = if let Ok(s) = std::str::from_utf8(import_name) { + s + } else { + update_last_error(CApiError { + msg: "error converting import_name to string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + + let namespace = namespaces + .entry(module_name) + .or_insert_with(|| Namespace::new()); + + let export = match import.tag { + wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export, + wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export, + wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, + wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, + }; + namespace.insert(import_name, unsafe { *Box::from_raw(export) }); + } + for (module_name, namespace) in namespaces.into_iter() { + import_object.register(module_name, namespace); + } + let bytes: &[u8] = unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; - let result = wasmer_runtime::instantiate(bytes, &*import_object); + let result = wasmer_runtime::instantiate(bytes, &import_object); let new_instance = match result { Ok(instance) => instance, Err(error) => { @@ -413,7 +460,7 @@ pub unsafe extern "C" fn wasmer_instantiate( } }; unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; - Box::into_raw(import_object); + Box::into_raw(Box::new(import_object)); wasmer_result_t::WASMER_OK } @@ -563,6 +610,40 @@ pub unsafe extern "C" fn wasmer_export_kind( } } +/// Creates new func +/// +/// The caller owns the object and should call `wasmer_func_destroy` to free it. +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_func_new( + func: extern "C" fn(data: *mut c_void), + params: *const wasmer_value_tag, + params_len: c_int, + returns: *const wasmer_value_tag, + returns_len: c_int, +) -> *const wasmer_func_t { + let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize); + let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); + let returns: &[wasmer_value_tag] = slice::from_raw_parts(returns, returns_len as usize); + let returns: Vec = returns.iter().cloned().map(|x| x.into()).collect(); + + let export = Box::new(Export::Function { + func: unsafe { FuncPointer::new(func as _) }, + ctx: Context::Internal, + signature: Arc::new(FuncSig::new(params, returns)), + }); + Box::into_raw(export) as *mut wasmer_func_t +} + +/// Frees memory for the given Func +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_func_destroy(func: *mut wasmer_func_t) { + if !func.is_null() { + drop(unsafe { Box::from_raw(func as *mut Export) }); + } +} + /// Gets func from wasm_export #[no_mangle] #[allow(clippy::cast_ptr_alignment)] diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index b00adb790..c0c6a4a7b 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -5,7 +5,7 @@ int main() { - wasmer_import_object_t *import_object = wasmer_import_object_new(); +// wasmer_import_object_t *import_object = wasmer_import_object_new(); // Read the wasm file bytes FILE *file = fopen("sum.wasm", "r"); @@ -16,8 +16,9 @@ int main() fread(bytes, 1, len, file); fclose(file); + wasmer_import_t imports[] = {}; wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0); printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_OK); @@ -61,8 +62,6 @@ int main() printf("Destroy instance\n"); wasmer_instance_destroy(instance); - printf("Destroy import object\n"); - wasmer_import_object_destroy(import_object); printf("Destroy exports\n"); wasmer_exports_destroy(exports); return 0; diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index b42817abc..2c241be55 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -2,6 +2,7 @@ #include "../wasmer.h" #include #include +#include static print_str_called = false; static memory_len = 0; @@ -26,10 +27,32 @@ void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) int main() { - wasmer_import_object_t *import_object = wasmer_import_object_new(); +// wasmer_import_object_t *import_object = wasmer_import_object_new(); wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; wasmer_value_tag returns_sig[] = {}; - wasmer_imports_set_import_func(import_object, "env", "print_str", print_str, params_sig, 2, returns_sig, 0); + + printf("Creating new func\n"); + wasmer_func_t *func = wasmer_func_new(print_str, params_sig, 2, returns_sig, 0); + wasmer_import_t import; + + char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = module_name; + module_name_bytes.bytes_len = strlen(module_name); + char *import_name = "print_str"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = import_name; + import_name_bytes.bytes_len = strlen(import_name); + + import.module_name = module_name_bytes; + import.import_name = import_name_bytes; + import.tag = WASM_FUNCTION; + import.value.func = func; + wasmer_import_t imports[] = {import}; + + +// wasmer_imports_set_import_func(import_object, "env", "print_str", print_str, params_sig, 2, returns_sig, 0); + // Read the wasm file bytes FILE *file = fopen("wasm_sample_app.wasm", "r"); @@ -40,9 +63,15 @@ int main() fread(bytes, 1, len, file); fclose(file); + printf("Instantiating\n"); wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 1); printf("Compile result: %d\n", compile_result); + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); assert(compile_result == WASMER_OK); wasmer_value_t params[] = {}; @@ -56,9 +85,11 @@ int main() assert(ptr_len == 13); assert(0 == strcmp(actual_str, "Hello, World!")); + printf("Destroying func\n"); + // wasmer_func_destroy(func); // printf("Destroy instance\n"); // wasmer_instance_destroy(instance); - printf("Destroy import object\n"); - wasmer_import_object_destroy(import_object); +// printf("Destroy import object\n"); +// wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index db24544f4..63adf11c1 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -5,7 +5,6 @@ int main() { - wasmer_import_object_t *import_object = wasmer_import_object_new(); // Read the wasm file bytes FILE *file = fopen("sum.wasm", "r"); @@ -16,8 +15,9 @@ int main() fread(bytes, 1, len, file); fclose(file); + wasmer_import_t imports[] = {}; wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0); printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_OK); @@ -53,7 +53,5 @@ int main() printf("Destroy instance\n"); wasmer_instance_destroy(instance); - printf("Destroy import object\n"); - wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index f55014bee..efc840400 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -75,22 +75,36 @@ typedef struct { } wasmer_memory_t; +typedef struct { + +} wasmer_table_t; + +typedef union { + const wasmer_func_t *func; + const wasmer_table_t *table; + const wasmer_memory_t *memory; + const wasmer_global_t *global; +} wasmer_import_export_value; + +typedef struct { + wasmer_byte_array module_name; + wasmer_byte_array import_name; + wasmer_import_export_kind tag; + wasmer_import_export_value value; +} wasmer_import_t; + typedef struct { uint32_t min; uint32_t max; } wasmer_limits_t; -typedef struct { - -} wasmer_table_t; - /** * Gets wasmer_export kind */ wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); /** - * Gets func from wasm_export + * Gets name from wasmer_export */ wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); @@ -127,6 +141,21 @@ wasmer_result_t wasmer_func_call(wasmer_func_t *func, wasmer_value_t *results, int results_len); +/** + * Frees memory for the given Func + */ +void wasmer_func_destroy(wasmer_func_t *func); + +/** + * Creates new func + * The caller owns the object and should call `wasmer_func_destroy` to free it. + */ +const wasmer_func_t *wasmer_func_new(void (*func)(void *data), + const wasmer_value_tag *params, + int params_len, + const wasmer_value_tag *returns, + int returns_len); + /** * Frees memory for the given Global */ @@ -220,7 +249,8 @@ void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exp wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, - wasmer_import_object_t *import_object); + wasmer_import_t *imports, + int imports_len); /** * Gets the length in bytes of the last error. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 02de6f52b..0192e8555 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -72,21 +72,35 @@ struct wasmer_memory_t { }; +struct wasmer_table_t { + +}; + +union wasmer_import_export_value { + const wasmer_func_t *func; + const wasmer_table_t *table; + const wasmer_memory_t *memory; + const wasmer_global_t *global; +}; + +struct wasmer_import_t { + wasmer_byte_array module_name; + wasmer_byte_array import_name; + wasmer_import_export_kind tag; + wasmer_import_export_value value; +}; + struct wasmer_limits_t { uint32_t min; uint32_t max; }; -struct wasmer_table_t { - -}; - extern "C" { /// Gets wasmer_export kind wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); -/// Gets func from wasm_export +/// Gets name from wasmer_export wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); /// Gets func from wasm_export @@ -112,6 +126,17 @@ wasmer_result_t wasmer_func_call(wasmer_func_t *func, wasmer_value_t *results, int results_len); +/// Frees memory for the given Func +void wasmer_func_destroy(wasmer_func_t *func); + +/// Creates new func +/// The caller owns the object and should call `wasmer_func_destroy` to free it. +const wasmer_func_t *wasmer_func_new(void (*func)(void *data), + const wasmer_value_tag *params, + int params_len, + const wasmer_value_tag *returns, + int returns_len); + /// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); @@ -179,7 +204,8 @@ void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exp wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, - wasmer_import_object_t *import_object); + wasmer_import_t *imports, + int imports_len); /// Gets the length in bytes of the last error. /// This can be used to dynamically allocate a buffer with the correct number of From 9ee86138b961ec682697c0e69ba792ba4ea6d848 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Fri, 15 Feb 2019 19:16:19 -0600 Subject: [PATCH 37/50] Impl Error for CallError --- lib/runtime-core/src/error.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index e88a5692c..33c9fd15f 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -260,6 +260,8 @@ impl std::fmt::Display for CallError { } } +impl std::error::Error for CallError {} + /// This error type is produced when creating something, /// like a `Memory` or a `Table`. #[derive(Debug, Clone)] From 56079ad58937be68ba9188bd56135544bc36c6ff Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Fri, 15 Feb 2019 19:47:00 -0600 Subject: [PATCH 38/50] Add compile Module function --- lib/runtime-c-api/src/lib.rs | 41 ++++++++++++++++++- lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 ++ .../tests/test-import-function.c | 13 +++--- lib/runtime-c-api/tests/test-instantiate.c | 2 +- lib/runtime-c-api/tests/test-module.c | 27 ++++++++++++ lib/runtime-c-api/wasmer.h | 17 ++++++++ lib/runtime-c-api/wasmer.hh | 13 ++++++ 8 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 lib/runtime-c-api/tests/test-module.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 511f4304a..733e10fb8 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -12,7 +12,7 @@ use std::slice; use std::str; use std::sync::Arc; use std::{ffi::c_void, mem, ptr}; -use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Table, Value}; +use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::{LikeNamespace, Namespace}; use wasmer_runtime_core::types::{ @@ -23,6 +23,9 @@ use wasmer_runtime_core::units::{Bytes, Pages}; #[allow(non_camel_case_types)] pub struct wasmer_import_object_t(); +#[allow(non_camel_case_types)] +pub struct wasmer_module_t(); + #[allow(non_camel_case_types)] pub struct wasmer_instance_t(); @@ -379,6 +382,42 @@ pub extern "C" fn wasmer_memory_destroy(memory: *mut wasmer_memory_t) { } } +/// Creates a new Module from the given wasm bytes. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_compile( + mut module: *mut *mut wasmer_module_t, + wasm_bytes: *mut uint8_t, + wasm_bytes_len: uint32_t, +) -> wasmer_result_t { + let bytes: &[u8] = + unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; + let result = wasmer_runtime::compile(bytes); + let new_module = match result { + Ok(instance) => instance, + Err(error) => { + update_last_error(error); + return wasmer_result_t::WASMER_ERROR; + } + }; + unsafe { *module = Box::into_raw(Box::new(new_module)) as *mut wasmer_module_t }; + wasmer_result_t::WASMER_OK +} + +/// Frees memory for the given Module +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_module_destroy(module: *mut wasmer_module_t) { + if !module.is_null() { + drop(unsafe { Box::from_raw(module as *mut Module) }); + } +} + /// Creates a new Instance from the given wasm bytes and imports. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index c8dfca857..6ea57c28d 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -14,6 +14,7 @@ test-exports test-instantiate test-import-function test-memory +test-module test-tables test-validate rust-build \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index ce970d4bf..788ee1c6a 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(test-globals test-globals.c) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) add_executable(test-memory test-memory.c) +add_executable(test-module test-module.c) add_executable(test-validate test-validate.c) add_executable(test-tables test-tables.c) @@ -28,6 +29,8 @@ target_link_libraries(test-import-function general ${WASMER_LIB}) target_link_libraries(test-memory general ${WASMER_LIB}) +target_link_libraries(test-module + general ${WASMER_LIB}) target_link_libraries(test-validate general ${WASMER_LIB}) target_link_libraries(test-tables @@ -39,6 +42,7 @@ add_test(test-globals test-globals) add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) add_test(test-memory test-memory) +add_test(test-module test-module) add_test(test-validate test-validate) add_test(test-tables test-tables) diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index 2c241be55..54390b863 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -67,17 +67,20 @@ int main() wasmer_instance_t *instance = NULL; wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 1); printf("Compile result: %d\n", compile_result); - int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char *error_str = malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("Error str: `%s`\n", error_str); + assert(compile_result == WASMER_OK); wasmer_value_t params[] = {}; wasmer_value_t results[] = {}; wasmer_result_t call_result = wasmer_instance_call(instance, "hello_wasm", params, 0, results, 0); printf("Call result: %d\n", call_result); + + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + assert(call_result == WASMER_OK); assert(print_str_called); diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index 63adf11c1..f276b8dee 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -48,7 +48,7 @@ int main() char *error_str = malloc(error_len); wasmer_last_error_message(error_str, error_len); printf("Error str: `%s`\n", error_str); - assert(0 == strcmp(error_str, "Call error")); + assert(0 == strcmp(error_str, "Call error: Parameters of type [I32] did not match signature [I32, I32] -> [I32]")); free(error_str); printf("Destroy instance\n"); diff --git a/lib/runtime-c-api/tests/test-module.c b/lib/runtime-c-api/tests/test-module.c new file mode 100644 index 000000000..5948fd26b --- /dev/null +++ b/lib/runtime-c-api/tests/test-module.c @@ -0,0 +1,27 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + // Read the wasm file bytes + FILE *file = fopen("sum.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_module_t *module = NULL; + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_OK); + + // TODO add module exports + + printf("Destroy module\n"); + wasmer_module_destroy(module); + return 0; +} \ No newline at end of file diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index efc840400..3434d1a10 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -33,6 +33,8 @@ typedef struct wasmer_instance_context_t wasmer_instance_context_t; typedef struct wasmer_instance_t wasmer_instance_t; +typedef struct wasmer_module_t wasmer_module_t; + typedef struct { } wasmer_export_t; @@ -98,6 +100,16 @@ typedef struct { uint32_t max; } wasmer_limits_t; +/** + * Creates a new Module from the given wasm bytes. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_compile(wasmer_module_t **module, + uint8_t *wasm_bytes, + uint32_t wasm_bytes_len); + /** * Gets wasmer_export kind */ @@ -317,6 +329,11 @@ uint32_t wasmer_memory_length(wasmer_memory_t *memory); */ wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +/** + * Frees memory for the given Module + */ +void wasmer_module_destroy(wasmer_module_t *module); + /** * Frees memory for the given Table */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 0192e8555..3b6ca9551 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -30,6 +30,8 @@ struct wasmer_instance_context_t; struct wasmer_instance_t; +struct wasmer_module_t; + struct wasmer_export_t { }; @@ -97,6 +99,14 @@ struct wasmer_limits_t { extern "C" { +/// Creates a new Module from the given wasm bytes. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_compile(wasmer_module_t **module, + uint8_t *wasm_bytes, + uint32_t wasm_bytes_len); + /// Gets wasmer_export kind wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); @@ -256,6 +266,9 @@ uint32_t wasmer_memory_length(wasmer_memory_t *memory); /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +/// Frees memory for the given Module +void wasmer_module_destroy(wasmer_module_t *module); + /// Frees memory for the given Table void wasmer_table_destroy(wasmer_table_t *table); From 7bb947aba755a393c39c29e085d4a46539946a17 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 17 Feb 2019 14:12:05 -0600 Subject: [PATCH 39/50] Add func signature lookup functions --- lib/runtime-c-api/src/lib.rs | 125 +++++++++++++++++++++++++ lib/runtime-c-api/tests/test-exports.c | 20 ++++ lib/runtime-c-api/wasmer.h | 34 +++++++ lib/runtime-c-api/wasmer.hh | 26 +++++ 4 files changed, 205 insertions(+) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 733e10fb8..6b6e5567f 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -674,6 +674,120 @@ pub unsafe extern "C" fn wasmer_func_new( Box::into_raw(export) as *mut wasmer_func_t } +/// Sets the result parameter to the arity of the params of the wasmer_func_t +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_func_params_arity( + func: *mut wasmer_func_t, + result: *mut uint32_t, +) -> wasmer_result_t { + let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let result = if let Export::Function { ref signature, .. } = *export { + unsafe { *result = signature.params().len() as uint32_t }; + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: "func ptr error in wasmer_func_params_arity".to_string(), + }); + wasmer_result_t::WASMER_ERROR + }; + Box::into_raw(export); + result +} + +/// Sets the params buffer to the parameter types of the given wasmer_func_t +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_func_params( + func: *mut wasmer_func_t, + params: *mut wasmer_value_tag, + params_len: c_int, +) -> wasmer_result_t { + let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let result = if let Export::Function { ref signature, .. } = *export { + let params: &mut [wasmer_value_tag] = + slice::from_raw_parts_mut(params, params_len as usize); + for (i, item) in signature.params().iter().enumerate() { + params[i] = item.into(); + } + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: "func ptr error in wasmer_func_params".to_string(), + }); + wasmer_result_t::WASMER_ERROR + }; + Box::into_raw(export); + result +} + +/// Sets the returns buffer to the parameter types of the given wasmer_func_t +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_func_returns( + func: *mut wasmer_func_t, + returns: *mut wasmer_value_tag, + returns_len: c_int, +) -> wasmer_result_t { + let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let result = if let Export::Function { ref signature, .. } = *export { + let returns: &mut [wasmer_value_tag] = + slice::from_raw_parts_mut(returns, returns_len as usize); + for (i, item) in signature.returns().iter().enumerate() { + returns[i] = item.into(); + } + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: "func ptr error in wasmer_func_returns".to_string(), + }); + wasmer_result_t::WASMER_ERROR + }; + Box::into_raw(export); + result +} + +/// Sets the result parameter to the arity of the returns of the wasmer_func_t +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_func_returns_arity( + func: *mut wasmer_func_t, + result: *mut uint32_t, +) -> wasmer_result_t { + let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let result = if let Export::Function { ref signature, .. } = *export { + unsafe { *result = signature.returns().len() as uint32_t }; + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: "func ptr error in wasmer_func_results_arity".to_string(), + }); + wasmer_result_t::WASMER_ERROR + }; + Box::into_raw(export); + result +} + /// Frees memory for the given Func #[allow(clippy::cast_ptr_alignment)] #[no_mangle] @@ -955,6 +1069,17 @@ impl From<(std::string::String, wasmer_runtime_core::export::Export)> for NamedE } } +impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag { + fn from(ty: &Type) -> Self { + match *ty { + Type::I32 => wasmer_value_tag::WASM_I32, + Type::I64 => wasmer_value_tag::WASM_I64, + Type::F32 => wasmer_value_tag::WASM_F32, + Type::F64 => wasmer_value_tag::WASM_F64, + } + } +} + // Error reporting thread_local! { diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index c0c6a4a7b..2ac339e6a 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -43,6 +43,26 @@ int main() assert(name_bytes.bytes[idx] == expected[idx]); } + uint32_t params_arity; + wasmer_func_params_arity(func, ¶ms_arity); + assert(params_arity == 2); + + wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity); + wasmer_func_params(func, params_sig , params_arity); + assert(params_sig[0] == WASM_I32); + assert(params_sig[1] == WASM_I32); + free(params_sig); + + uint32_t returns_arity; + wasmer_func_returns_arity(func, &returns_arity); + assert(returns_arity == 1); + + wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity); + wasmer_func_returns(func, returns_sig , returns_arity); + assert(returns_sig[0] == WASM_I32); + free(returns_sig); + + // wasmer_value_t param_one; // param_one.tag = WASM_I32; // param_one.value.I32 = 7; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 3434d1a10..6af262a0a 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -168,6 +168,40 @@ const wasmer_func_t *wasmer_func_new(void (*func)(void *data), const wasmer_value_tag *returns, int returns_len); +/** + * Sets the params buffer to the parameter types of the given wasmer_func_t + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len); + +/** + * Sets the result parameter to the arity of the params of the wasmer_func_t + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result); + +/** + * Sets the returns buffer to the parameter types of the given wasmer_func_t + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_func_returns(wasmer_func_t *func, + wasmer_value_tag *returns, + int returns_len); + +/** + * Sets the result parameter to the arity of the returns of the wasmer_func_t + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result); + /** * Frees memory for the given Global */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 3b6ca9551..e00c17531 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -147,6 +147,32 @@ const wasmer_func_t *wasmer_func_new(void (*func)(void *data), const wasmer_value_tag *returns, int returns_len); +/// Sets the params buffer to the parameter types of the given wasmer_func_t +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len); + +/// Sets the result parameter to the arity of the params of the wasmer_func_t +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result); + +/// Sets the returns buffer to the parameter types of the given wasmer_func_t +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_func_returns(wasmer_func_t *func, + wasmer_value_tag *returns, + int returns_len); + +/// Sets the result parameter to the arity of the returns of the wasmer_func_t +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result); + /// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); From 36767e0bd66ae9d11017948e40b93d7fd816b458 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 17 Feb 2019 14:39:26 -0600 Subject: [PATCH 40/50] Move ctx pointer to first parameter to fix test --- lib/runtime-c-api/tests/test-import-function.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index 54390b863..a93a33340 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -9,7 +9,7 @@ static memory_len = 0; static ptr_len = 0; static char actual_str[14] = {}; -void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) +void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) { wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); uint32_t mem_len = wasmer_memory_length(memory); From a77d1be983c9aeb0fac42e8a79f50d75b07e0cb0 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 17 Feb 2019 14:48:30 -0600 Subject: [PATCH 41/50] Remove unused API functions --- lib/runtime-c-api/src/lib.rs | 63 ------------------- .../tests/test-import-function.c | 7 --- lib/runtime-c-api/wasmer.h | 28 --------- lib/runtime-c-api/wasmer.hh | 22 ------- 4 files changed, 120 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 6b6e5567f..16070ccbe 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -157,13 +157,6 @@ pub unsafe extern "C" fn wasmer_validate( wasmer_runtime_core::validate(bytes) } -/// Creates a new ImportObject and returns a pointer to it. -/// The caller owns the object and should call `wasmer_import_object_destroy` to free it. -#[no_mangle] -pub extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t { - Box::into_raw(Box::new(ImportObject::new())) as *mut wasmer_import_object_t -} - /// Creates a new Memory for the given descriptor and initializes the given /// pointer to pointer to a pointer to the new memory. /// @@ -364,15 +357,6 @@ pub extern "C" fn wasmer_global_destroy(global: *mut wasmer_global_t) { } } -/// Frees memory for the given ImportObject -#[allow(clippy::cast_ptr_alignment)] -#[no_mangle] -pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) { - if !import_object.is_null() { - drop(unsafe { Box::from_raw(import_object as *mut ImportObject) }); - } -} - /// Frees memory for the given Memory #[allow(clippy::cast_ptr_alignment)] #[no_mangle] @@ -901,53 +885,6 @@ pub unsafe extern "C" fn wasmer_func_call( // let named_export = &*(export as *mut NamedExport); //} -/// Registers a `func` with provided `name` and `namespace` into the ImportObject. -/// -/// Returns `wasmer_result_t::WASMER_OK` upon success. -/// -/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` -/// and `wasmer_last_error_message` to get an error message. -#[allow(clippy::cast_ptr_alignment)] -#[no_mangle] -pub unsafe extern "C" fn wasmer_imports_set_import_func( - import_object: *mut wasmer_import_object_t, - namespace: *const c_char, - name: *const c_char, - func: extern "C" fn(data: *mut c_void), - params: *const wasmer_value_tag, - params_len: c_int, - returns: *const wasmer_value_tag, - returns_len: c_int, -) { - let mut import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; - let namespace_c = unsafe { CStr::from_ptr(namespace) }; - let namespace_r = namespace_c.to_str().unwrap(); - let name_c = unsafe { CStr::from_ptr(name) }; - let name_r = name_c.to_str().unwrap(); - - let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize); - let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); - let returns: &[wasmer_value_tag] = slice::from_raw_parts(returns, returns_len as usize); - let returns: Vec = returns.iter().cloned().map(|x| x.into()).collect(); - - let export = Export::Function { - func: unsafe { FuncPointer::new(func as _) }, - ctx: Context::Internal, - signature: Arc::new(FuncSig::new(params, returns)), - }; - - // TODO handle existing namespace - // let maybe_namespace = import_object.get_namespace(namespace_r); - // if let Some(n) = maybe_namespace { - // n.insert(name_r, export); - // } else { - let mut namespace = Namespace::new(); - namespace.insert(name_r, export); - import_object.register(namespace_r, namespace); - Box::into_raw(import_object); - // }; -} - /// Gets the memory within the context at the index `memory_idx`. /// The index is always 0 until multiple memories are supported. #[allow(clippy::cast_ptr_alignment)] diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index a93a33340..4e52f113e 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -27,7 +27,6 @@ void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) int main() { -// wasmer_import_object_t *import_object = wasmer_import_object_new(); wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; wasmer_value_tag returns_sig[] = {}; @@ -50,10 +49,6 @@ int main() import.value.func = func; wasmer_import_t imports[] = {import}; - -// wasmer_imports_set_import_func(import_object, "env", "print_str", print_str, params_sig, 2, returns_sig, 0); - - // Read the wasm file bytes FILE *file = fopen("wasm_sample_app.wasm", "r"); fseek(file, 0, SEEK_END); @@ -92,7 +87,5 @@ int main() // wasmer_func_destroy(func); // printf("Destroy instance\n"); // wasmer_instance_destroy(instance); -// printf("Destroy import object\n"); -// wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 6af262a0a..d37a9dbd1 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -27,8 +27,6 @@ enum wasmer_value_tag { }; typedef uint32_t wasmer_value_tag; -typedef struct wasmer_import_object_t wasmer_import_object_t; - typedef struct wasmer_instance_context_t wasmer_instance_context_t; typedef struct wasmer_instance_t wasmer_instance_t; @@ -228,32 +226,6 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); */ void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); -/** - * Frees memory for the given ImportObject - */ -void wasmer_import_object_destroy(wasmer_import_object_t *import_object); - -/** - * Creates a new ImportObject and returns a pointer to it. - * The caller owns the object and should call `wasmer_import_object_destroy` to free it. - */ -wasmer_import_object_t *wasmer_import_object_new(void); - -/** - * Registers a `func` with provided `name` and `namespace` into the ImportObject. - * Returns `wasmer_result_t::WASMER_OK` upon success. - * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` - * and `wasmer_last_error_message` to get an error message. - */ -void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, - const char *namespace_, - const char *name, - void (*func)(void *data), - const wasmer_value_tag *params, - int params_len, - const wasmer_value_tag *returns, - int returns_len); - /** * Calls an instances exported function by `name` with the provided parameters. * Results are set using the provided `results` pointer. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index e00c17531..a8931496d 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -24,8 +24,6 @@ enum class wasmer_value_tag : uint32_t { WASM_F64, }; -struct wasmer_import_object_t; - struct wasmer_instance_context_t; struct wasmer_instance_t; @@ -189,26 +187,6 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); /// Sets the value stored by the given Global void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); -/// Frees memory for the given ImportObject -void wasmer_import_object_destroy(wasmer_import_object_t *import_object); - -/// Creates a new ImportObject and returns a pointer to it. -/// The caller owns the object and should call `wasmer_import_object_destroy` to free it. -wasmer_import_object_t *wasmer_import_object_new(); - -/// Registers a `func` with provided `name` and `namespace` into the ImportObject. -/// Returns `wasmer_result_t::WASMER_OK` upon success. -/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` -/// and `wasmer_last_error_message` to get an error message. -void wasmer_imports_set_import_func(wasmer_import_object_t *import_object, - const char *namespace_, - const char *name, - void (*func)(void *data), - const wasmer_value_tag *params, - int params_len, - const wasmer_value_tag *returns, - int returns_len); - /// Calls an instances exported function by `name` with the provided parameters. /// Results are set using the provided `results` pointer. /// Returns `wasmer_result_t::WASMER_OK` upon success. From ee81560e06d1476901f6c0799c9690081a4e4768 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 17 Feb 2019 16:51:59 -0600 Subject: [PATCH 42/50] Cleanup tests --- lib/runtime-c-api/tests/test-exports.c | 2 -- lib/runtime-c-api/tests/test-instantiate.c | 1 - lib/runtime-c-api/tests/test-module.c | 2 -- 3 files changed, 5 deletions(-) diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index 2ac339e6a..3f458ebab 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -5,8 +5,6 @@ int main() { -// wasmer_import_object_t *import_object = wasmer_import_object_new(); - // Read the wasm file bytes FILE *file = fopen("sum.wasm", "r"); fseek(file, 0, SEEK_END); diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index f276b8dee..2a675de12 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -5,7 +5,6 @@ int main() { - // Read the wasm file bytes FILE *file = fopen("sum.wasm", "r"); fseek(file, 0, SEEK_END); diff --git a/lib/runtime-c-api/tests/test-module.c b/lib/runtime-c-api/tests/test-module.c index 5948fd26b..bacd37c3a 100644 --- a/lib/runtime-c-api/tests/test-module.c +++ b/lib/runtime-c-api/tests/test-module.c @@ -19,8 +19,6 @@ int main() printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_OK); - // TODO add module exports - printf("Destroy module\n"); wasmer_module_destroy(module); return 0; From 123d55cb4a230dc31b4a8584ac17a53e50091689 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 17 Feb 2019 17:10:15 -0600 Subject: [PATCH 43/50] Remove commented out code, cleanup build warnings --- lib/runtime-c-api/src/lib.rs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 16070ccbe..38414c8d7 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -6,18 +6,14 @@ use std::cell::RefCell; use std::collections::HashMap; use std::error::Error; use std::ffi::CStr; -use std::ffi::CString; use std::fmt; use std::slice; -use std::str; use std::sync::Arc; -use std::{ffi::c_void, mem, ptr}; +use std::{ffi::c_void, ptr}; use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; -use wasmer_runtime_core::import::{LikeNamespace, Namespace}; -use wasmer_runtime_core::types::{ - ElementType, FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type, -}; +use wasmer_runtime_core::import::Namespace; +use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type}; use wasmer_runtime_core::units::{Bytes, Pages}; #[allow(non_camel_case_types)] @@ -841,7 +837,7 @@ pub unsafe extern "C" fn wasmer_func_call( update_last_error(CApiError { msg: "wasmer_func_call not yet implemented".to_string(), }); - return wasmer_result_t::WASMER_ERROR; + wasmer_result_t::WASMER_ERROR // let result = instance.call(func_name_r, ¶ms[..]); // Box::into_raw(export_func); // match result { @@ -876,15 +872,6 @@ pub unsafe extern "C" fn wasmer_func_call( // } } -///// Gets wasmer_export func -//#[no_mangle] -//pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) { -// if exports.is_null() { -// return ptr::null_mut(); -// } -// let named_export = &*(export as *mut NamedExport); -//} - /// Gets the memory within the context at the index `memory_idx`. /// The index is always 0 until multiple memories are supported. #[allow(clippy::cast_ptr_alignment)] From 380d7669435b5b653507d74726bddec1f3b443d9 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 18 Feb 2019 23:30:08 -0600 Subject: [PATCH 44/50] Convert from Box into/from raw to pointer ref-deref to fix free issue --- lib/runtime-c-api/src/lib.rs | 50 +++++++------------ .../tests/test-import-function.c | 4 +- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 38414c8d7..bcd4fd344 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -196,9 +196,8 @@ pub extern "C" fn wasmer_memory_grow( memory: *mut wasmer_memory_t, delta: uint32_t, ) -> wasmer_result_t { - let memory = unsafe { Box::from_raw(memory as *mut Memory) }; + let memory = unsafe { &*(memory as *mut Memory) }; let maybe_delta = memory.grow(Pages(delta)); - Box::into_raw(memory); if let Some(_delta) = maybe_delta { wasmer_result_t::WASMER_OK } else { @@ -213,9 +212,8 @@ pub extern "C" fn wasmer_memory_grow( #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_length(memory: *mut wasmer_memory_t) -> uint32_t { - let memory = unsafe { Box::from_raw(memory as *mut Memory) }; + let memory = unsafe { &*(memory as *mut Memory) }; let Pages(len) = memory.size(); - Box::into_raw(memory); len } @@ -262,9 +260,8 @@ pub extern "C" fn wasmer_table_grow( table: *mut wasmer_table_t, delta: uint32_t, ) -> wasmer_result_t { - let table = unsafe { Box::from_raw(table as *mut Table) }; + let table = unsafe { &*(table as *mut Table) }; let maybe_delta = table.grow(delta); - Box::into_raw(table); if let Some(_delta) = maybe_delta { wasmer_result_t::WASMER_OK } else { @@ -279,9 +276,8 @@ pub extern "C" fn wasmer_table_grow( #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_table_length(table: *mut wasmer_table_t) -> uint32_t { - let table = unsafe { Box::from_raw(table as *mut Table) }; + let table = unsafe { &*(table as *mut Table) }; let len = table.size(); - Box::into_raw(table); len } @@ -313,9 +309,8 @@ pub unsafe extern "C" fn wasmer_global_new( #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_global_get(global: *mut wasmer_global_t) -> wasmer_value_t { - let global = unsafe { Box::from_raw(global as *mut Global) }; + let global = unsafe { &*(global as *mut Global) }; let value: wasmer_value_t = global.get().into(); - Box::into_raw(global); value } @@ -323,9 +318,8 @@ pub extern "C" fn wasmer_global_get(global: *mut wasmer_global_t) -> wasmer_valu #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_global_set(global: *mut wasmer_global_t, value: wasmer_value_t) { - let global = unsafe { Box::from_raw(global as *mut Global) }; + let global = unsafe { &*(global as *mut Global) }; global.set(value.into()); - Box::into_raw(global); } /// Returns a descriptor (type, mutability) of the given Global @@ -334,13 +328,12 @@ pub extern "C" fn wasmer_global_set(global: *mut wasmer_global_t, value: wasmer_ pub extern "C" fn wasmer_global_get_descriptor( global: *mut wasmer_global_t, ) -> wasmer_global_descriptor_t { - let global = unsafe { Box::from_raw(global as *mut Global) }; + let global = unsafe { &*(global as *mut Global) }; let descriptor = global.descriptor(); let desc = wasmer_global_descriptor_t { mutable: descriptor.mutable, kind: descriptor.ty.into(), }; - Box::into_raw(global); desc } @@ -458,7 +451,7 @@ pub unsafe extern "C" fn wasmer_instantiate( wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, }; - namespace.insert(import_name, unsafe { *Box::from_raw(export) }); + namespace.insert(import_name, unsafe { *Box::from_raw(export) }); // TODO Review } for (module_name, namespace) in namespaces.into_iter() { import_object.register(module_name, namespace); @@ -524,11 +517,10 @@ pub unsafe extern "C" fn wasmer_instance_call( let func_name_c = unsafe { CStr::from_ptr(name) }; let func_name_r = func_name_c.to_str().unwrap(); - let instance = unsafe { Box::from_raw(instance as *mut Instance) }; let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize); - let result = instance.call(func_name_r, ¶ms[..]); - Box::into_raw(instance); + let result = (&*(instance as *mut Instance)).call(func_name_r, ¶ms[..]); + match result { Ok(results_vec) => { if results_vec.len() > 0 { @@ -570,11 +562,10 @@ pub unsafe extern "C" fn wasmer_instance_exports( instance: *mut wasmer_instance_t, exports: *mut *mut wasmer_exports_t, ) { - let mut instance = unsafe { Box::from_raw(instance as *mut Instance) }; + let mut instance = unsafe { &mut *(instance as *mut Instance) }; let named_exports: Box = Box::new(NamedExports(instance.exports().map(|e| e.into()).collect())); unsafe { *exports = Box::into_raw(named_exports) as *mut wasmer_exports_t }; - Box::into_raw(instance); } pub struct NamedExports(Vec); @@ -608,9 +599,8 @@ pub unsafe extern "C" fn wasmer_exports_get( if exports.is_null() { return ptr::null_mut(); } - let mut named_exports = unsafe { Box::from_raw(exports as *mut NamedExports) }; + let mut named_exports = unsafe { &mut *(exports as *mut NamedExports) }; let ptr = &mut (*named_exports).0[idx as usize] as *mut NamedExport as *mut wasmer_export_t; - Box::into_raw(named_exports); ptr } @@ -666,7 +656,7 @@ pub unsafe extern "C" fn wasmer_func_params_arity( func: *mut wasmer_func_t, result: *mut uint32_t, ) -> wasmer_result_t { - let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let mut export = unsafe { &mut *(func as *mut Export) }; let result = if let Export::Function { ref signature, .. } = *export { unsafe { *result = signature.params().len() as uint32_t }; wasmer_result_t::WASMER_OK @@ -676,7 +666,6 @@ pub unsafe extern "C" fn wasmer_func_params_arity( }); wasmer_result_t::WASMER_ERROR }; - Box::into_raw(export); result } @@ -693,7 +682,7 @@ pub unsafe extern "C" fn wasmer_func_params( params: *mut wasmer_value_tag, params_len: c_int, ) -> wasmer_result_t { - let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let mut export = unsafe { &mut *(func as *mut Export) }; let result = if let Export::Function { ref signature, .. } = *export { let params: &mut [wasmer_value_tag] = slice::from_raw_parts_mut(params, params_len as usize); @@ -707,7 +696,6 @@ pub unsafe extern "C" fn wasmer_func_params( }); wasmer_result_t::WASMER_ERROR }; - Box::into_raw(export); result } @@ -724,7 +712,7 @@ pub unsafe extern "C" fn wasmer_func_returns( returns: *mut wasmer_value_tag, returns_len: c_int, ) -> wasmer_result_t { - let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let mut export = unsafe { &mut *(func as *mut Export) }; let result = if let Export::Function { ref signature, .. } = *export { let returns: &mut [wasmer_value_tag] = slice::from_raw_parts_mut(returns, returns_len as usize); @@ -738,7 +726,6 @@ pub unsafe extern "C" fn wasmer_func_returns( }); wasmer_result_t::WASMER_ERROR }; - Box::into_raw(export); result } @@ -754,7 +741,7 @@ pub unsafe extern "C" fn wasmer_func_returns_arity( func: *mut wasmer_func_t, result: *mut uint32_t, ) -> wasmer_result_t { - let mut export = unsafe { Box::from_raw(func as *mut Export) }; + let mut export = unsafe { &*(func as *mut Export) }; let result = if let Export::Function { ref signature, .. } = *export { unsafe { *result = signature.returns().len() as uint32_t }; wasmer_result_t::WASMER_OK @@ -764,7 +751,6 @@ pub unsafe extern "C" fn wasmer_func_returns_arity( }); wasmer_result_t::WASMER_ERROR }; - Box::into_raw(export); result } @@ -830,7 +816,7 @@ pub unsafe extern "C" fn wasmer_func_call( let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize); let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); - let export_func = unsafe { Box::from_raw(func as *mut Export) }; + let export_func = unsafe { &*(func as *mut Export) }; let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize); // TODO implement func.call @@ -880,7 +866,7 @@ pub extern "C" fn wasmer_instance_context_memory( ctx: *mut wasmer_instance_context_t, memory_idx: uint32_t, ) -> *const wasmer_memory_t { - let mut ctx = unsafe { Box::from_raw(ctx as *mut Ctx) }; + let mut ctx = unsafe { &mut *(ctx as *mut Ctx) }; let memory = ctx.memory(0); memory as *const Memory as *const wasmer_memory_t } diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index 4e52f113e..bd09938d5 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -85,7 +85,7 @@ int main() printf("Destroying func\n"); // wasmer_func_destroy(func); - // printf("Destroy instance\n"); - // wasmer_instance_destroy(instance); + printf("Destroy instance\n"); + wasmer_instance_destroy(instance); return 0; } \ No newline at end of file From d2f30231911484254355b23c715cc5d988c54fed Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 19 Feb 2019 00:05:08 -0600 Subject: [PATCH 45/50] Allow specifying optional max value in limits --- lib/runtime-c-api/src/lib.rs | 22 +++++++++++++++++++--- lib/runtime-c-api/tests/test-memory.c | 5 ++++- lib/runtime-c-api/tests/test-tables.c | 16 ++++++++++------ lib/runtime-c-api/wasmer.h | 7 ++++++- lib/runtime-c-api/wasmer.hh | 7 ++++++- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index bcd4fd344..d4286a9ca 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -87,7 +87,13 @@ pub struct wasmer_global_t(); #[repr(C)] pub struct wasmer_limits_t { pub min: uint32_t, - pub max: uint32_t, + pub max: wasmer_limit_option_t, +} + +#[repr(C)] +pub struct wasmer_limit_option_t { + pub has_some: bool, + pub some: uint32_t, } #[repr(C)] @@ -167,9 +173,14 @@ pub unsafe extern "C" fn wasmer_memory_new( mut memory: *mut *mut wasmer_memory_t, limits: wasmer_limits_t, ) -> wasmer_result_t { + let max = if limits.max.has_some { + Some(Pages(limits.max.some)) + } else { + None + }; let desc = MemoryDescriptor { minimum: Pages(limits.min), - maximum: Some(Pages(limits.max)), + maximum: max, shared: false, }; let result = Memory::new(desc); @@ -231,10 +242,15 @@ pub unsafe extern "C" fn wasmer_table_new( mut table: *mut *mut wasmer_table_t, limits: wasmer_limits_t, ) -> wasmer_result_t { + let max = if limits.max.has_some { + Some(limits.max.some) + } else { + None + }; let desc = TableDescriptor { element: ElementType::Anyfunc, minimum: limits.min, - maximum: Some(limits.max), + maximum: max, }; let result = Table::new(desc); let new_table = match result { diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index d472c2b08..63913c73b 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -8,7 +8,10 @@ int main() wasmer_memory_t *memory = NULL; wasmer_limits_t descriptor; descriptor.min = 10; - descriptor.max = 15; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 15; + descriptor.max = max; wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); printf("Memory result: %d\n", memory_result); assert(memory_result == WASMER_OK); diff --git a/lib/runtime-c-api/tests/test-tables.c b/lib/runtime-c-api/tests/test-tables.c index 3f8c29805..66ebf832d 100644 --- a/lib/runtime-c-api/tests/test-tables.c +++ b/lib/runtime-c-api/tests/test-tables.c @@ -8,7 +8,11 @@ int main() wasmer_table_t *table = NULL; wasmer_limits_t descriptor; descriptor.min = 10; - descriptor.max = 15; + wasmer_limit_option_t max; +// max.has_some = false; + max.has_some = true; + max.some = 15; + descriptor.max = max; wasmer_result_t table_result = wasmer_table_new(&table, descriptor); printf("Table result: %d\n", table_result); assert(table_result == WASMER_OK); @@ -17,11 +21,11 @@ int main() printf("Table length: %d\n", len); assert(len == 15); - // wasmer_result_t grow_result1 = wasmer_table_grow(&table, 5); - // assert(grow_result1 == WASMER_OK); - // uint32_t len_grow1 = wasmer_table_length(table); - // printf("Table length: %d\n", len_grow1); - // assert(len_grow1 == 15); +// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5); +// assert(grow_result1 == WASMER_OK); +// uint32_t len_grow1 = wasmer_table_length(table); +// printf("Table length: %d\n", len_grow1); +// assert(len_grow1 == 15); // // Try to grow beyond max // wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index d37a9dbd1..8d328836f 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -93,9 +93,14 @@ typedef struct { wasmer_import_export_value value; } wasmer_import_t; +typedef struct { + bool has_some; + uint32_t some; +} wasmer_limit_option_t; + typedef struct { uint32_t min; - uint32_t max; + wasmer_limit_option_t max; } wasmer_limits_t; /** diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index a8931496d..ab2808bf3 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -90,9 +90,14 @@ struct wasmer_import_t { wasmer_import_export_value value; }; +struct wasmer_limit_option_t { + bool has_some; + uint32_t some; +}; + struct wasmer_limits_t { uint32_t min; - uint32_t max; + wasmer_limit_option_t max; }; extern "C" { From 64519b15813c9e37393cd4549a815a8957230507 Mon Sep 17 00:00:00 2001 From: Jordan Danford Date: Tue, 19 Feb 2019 17:01:44 -0700 Subject: [PATCH 46/50] Fix formatting and grammar in documentation --- ARCHITECTURE.md | 33 +++-- ATTRIBUTIONS.md | 22 ++-- LICENSE | 4 +- README.md | 64 +++++----- integration_tests/lua/README.md | 4 +- integration_tests/nginx/README.md | 6 +- lib/README.md | 18 +-- lib/spectests/spectests/README.md | 199 +++++++++++++++--------------- 8 files changed, 177 insertions(+), 173 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b2f30f753..e3d87738d 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,19 +2,19 @@ Wasmer uses the following components: -- [Cranelift](https://github.com/cranestation/cranelift): for compiling WASM function binaries into Machine IR -- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and also to run WebAssembly spectests -- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly Modules +- [Cranelift](https://github.com/cranestation/cranelift): for compiling Wasm binaries to machine code +- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and running WebAssembly spec tests +- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly modules -## How Wasmer works? +## How Wasmer works -The first time you run `wasmer run myfile.wasm`, wasmer will: +The first time you run `wasmer run myfile.wasm`, Wasmer will: -- Check if is a `.wast` file. If so, transform it to `.wasm` -- Check that the provided binary is a valid WebAssembly one. That means, that its binary format starts with `\0asm`. -- If it looks like a WebAssembly file, try to parse it with `wasmparser` and generate a `Module` from it -- Once a `Module` is generated, an `Instance` is created with the proper `import_object` (that means, if is detected as an emscripten file, it will add the emscripten expected imports) -- Try to call the WebAssembly start function, or if unexistent try to search for the one that is exported as `main`. +- Check if is a `.wast` file, and if so, transform it to `.wasm` +- Check that the provided binary is a valid WebAssembly one, i.e. its binary format starts with `\0asm`. +- Parse it with `wasmparser` and generate a `Module` from it +- Generate an `Instance` with the proper `import_object` (that means, if is detected to be an Emscripten file, it will add the Emscripten expected imports) +- Try to call the WebAssembly `start` function, or if it does not exist, try to search for the function that is exported as `main` Find a more detailed explanation of the process below: @@ -22,7 +22,7 @@ Find a more detailed explanation of the process below: As the WebAssembly file is being parsed, it will read the sections in the WebAssembly file (memory, table, function, global and element definitions) using the `Module` (or `ModuleEnvironment`) as the structure to hold this information. -However, the real IR initialization happens while a function body is being parsed/created. That means, when the parser reads the section `(func ...)`. +However, the real IR initialization happens while a function body is being parsed/created, i.e. when the parser reads the section `(func ...)`. While the function body is being parsed the corresponding `FuncEnvironment` methods will be called. So for example, if the function is using a table, the `make_table` method within that `FuncEnvironment` will be called. @@ -41,15 +41,14 @@ Once we have the compiled values, we will push them to memory and mark them as e #### Relocations -Sometimes the functions that we generated will need to call other functions. -However the generated code have no idea how to link this functions together. +Sometimes the functions that we generate will need to call other functions, but the generated code has no idea how to link these functions together. -For example, if a function `A` is calling function `B` (that means is having a `(call b)` on it's body) while compiling `A` we will have no idea where the function `B` lives on memory (as `B` is not yet compiled nor pushed into memory). +For example, if a function `A` is calling function `B` (that means is having a `(call b)` on its body) while compiling `A` we will have no idea where the function `B` lives on memory (as `B` is not yet compiled nor pushed into memory). For that reason, we will start collecting all the calls that function `A` will need to do under the hood, and save it's offsets. We do that, so we can patch the function calls after compilation, to point to the correct memory address. -Note: Sometimes this functions rather than living in the same WebAssembly module, they will be provided as import values. +Note: sometimes this functions rather than living in the same WebAssembly module, they will be provided as import values. #### Traps @@ -66,5 +65,5 @@ Once that's finished, we will have a `Instance` function that will be ready to e ## Emscripten -The Wasmer Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs. -We provide this integration by filling the `import_object` with the emscripten functions, while instantiating the WebAssembly Instance. +Wasmer's Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs. +We provide this integration by filling the `import_object` with the Emscripten functions, while instantiating the WebAssembly Instance. diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index eff1434ab..54e0eed02 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -2,7 +2,7 @@ Wasmer is a community effort. In order to build the best WebAssembly runtime it's our duty to see how other runtimes are approaching the same space -and get inspired from them on the things that they got right, so wasmer and its community can benefit from a solid +and get inspired from them on the things that they got right, so Wasmer and its community can benefit from a solid foundation. These are the different project that we used as inspiration: @@ -10,9 +10,9 @@ These are the different project that we used as inspiration: - [Nebulet](https://github.com/nebulet/nebulet): as the base for creating a great Rust WebAssembly runtime - [WAVM](https://github.com/wavm/wavm): for their great integration and testing framework - [greenwasm](https://github.com/Kimundi/greenwasm): for their [spectests framework](https://github.com/Kimundi/greenwasm/tree/master/greenwasm-spectest) -- [wasmtime](/wasmtime): on their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs). -- [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys. -- [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility. +- [wasmtime](https://github.com/CraneStation/wasmtime): for their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs) +- [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys +- [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility We would love to hear from you if you think we can take inspiration from other projects that we haven't covered here. 😊 @@ -21,10 +21,10 @@ We would love to hear from you if you think we can take inspiration from other p ### Nebulet -``` +```text MIT License -Copyright (c) 2018 +Copyright (c) 2018 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -47,7 +47,7 @@ SOFTWARE. ### WAVM -``` +```text Copyright (c) 2018, Andrew Scheidecker All rights reserved. @@ -69,7 +69,7 @@ The contents of [Test/spec](Test/spec) is covered by the license in [Test/spec/L ### Greenwasm -``` +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -275,7 +275,7 @@ limitations under the License. ### Wasmtime -``` +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -497,7 +497,7 @@ Software. ``` ### Emscripten -``` +```text Emscripten is available under 2 licenses, the MIT license and the University of Illinois/NCSA Open Source License. @@ -557,7 +557,7 @@ the following conditions: Neither the names of Mozilla, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior - written permission. + written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF diff --git a/LICENSE b/LICENSE index 689596400..7e40523b0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,4 @@ -The MIT License (MIT) - -Copyright (c) 2018-Present Syrus Akbary +Copyright (c) 2019 Syrus Akbary Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index df4ac0186..bdb921afd 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,24 @@ -

Wasmer logo

+

+ + Wasmer logo + +

- Build Status - License + + Build Status + + + License + - Join the Wasmer Community + Join the Wasmer Community

## Introduction -[Wasmer](https://wasmer.io/) is a Standalone JIT WebAssembly runtime, aiming to be fully compatible with Emscripten, Rust and Go. +[Wasmer](https://wasmer.io/) is a standalone JIT WebAssembly runtime, aiming to be fully compatible with Emscripten, Rust and Go. Install Wasmer with: @@ -18,20 +26,20 @@ Install Wasmer with: curl https://get.wasmer.io -sSfL | sh ``` -_**NEW ✨**: Now you can also embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how to do it!_ +_**NEW ✨**: You can now embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how!_ ### Usage -`wasmer` can execute both the standard binary format (`.wasm`) and the text +Wasmer can execute both the standard binary format (`.wasm`) and the text format defined by the WebAssembly reference interpreter (`.wat`). -Once installed, you will be able to run any WebAssembly files (_including Nginx, and Lua!_): +Once installed, you will be able to run any WebAssembly files (_including nginx and Lua!_): ```sh # Run Lua wasmer run examples/lua.wasm -# Run Nginx +# Run nginx wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf ``` @@ -39,13 +47,13 @@ wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf Wasmer is structured into different directories: -- [`src`](./src): code related to the wasmer excutable binary itself +- [`src`](./src): code related to the Wasmer executable itself - [`lib`](./lib): modularized libraries that Wasmer uses under the hood -- [`examples`](./examples): some useful examples to getting started with wasmer +- [`examples`](./examples): some useful examples to getting started with Wasmer ## Dependencies -Building wasmer requires [rustup](https://rustup.rs/). +Building Wasmer requires [rustup](https://rustup.rs/). To build on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/) then follow the onscreen instructions. @@ -66,13 +74,13 @@ Please select your operating system: #### macOS -If you have [homebrew](https://brew.sh/) installed: +If you have [Homebrew](https://brew.sh/) installed: ```sh brew install cmake ``` -Or, in case you have [ports](https://www.macports.org/install.php): +Or, in case you have [MacPorts](https://www.macports.org/install.php): ```sh sudo port install cmake @@ -86,16 +94,16 @@ sudo apt install cmake #### Windows (MSVC) -Windows support is _highly experimental_. Only simple wasm programs may be run, and no syscalls are allowed. This means -nginx and lua do not work on Windows. See [this issue for ongoing Emscripten syscall polyfills for Windows](https://github.com/wasmerio/wasmer/pull/176). +Windows support is _highly experimental_. Only simple Wasm programs may be run, and no syscalls are allowed. This means +nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmerio/wasmer/issues/176) regarding Emscripten syscall polyfills for Windows. -1. Install Python for Windows (https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine. - You should change the installation to install the "Add python.exe to Path" feature. +1. Install [Python for Windows](https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine. + Make sure to enable "Add python.exe to Path" during installation. -2. Install Git for Windows (https://git-scm.com/download/win). DO allow it to add git.exe to the PATH (default +2. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default settings for the installer are fine). -3. Install CMake (https://cmake.org/download/). Ensure CMake is in the PATH. +3. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH. ## Building @@ -113,7 +121,7 @@ cargo install --path . ## Testing -Thanks to [spectests](https://github.com/wasmerio/wasmer/tree/master/lib/runtime-core/spectests) we can assure 100% compatibility with the WebAssembly spec test suite. +Thanks to [spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) we can ensure 100% compatibility with the WebAssembly spec test suite. Tests can be run with: @@ -121,7 +129,7 @@ Tests can be run with: make test ``` -If you need to re-generate the Rust tests from the spectests +If you need to regenerate the Rust tests from the spec tests you can run: ```sh @@ -138,20 +146,20 @@ make integration-tests Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction. -Below are some of the goals (written with order) of this project: +Below are some of the goals of this project (in order of priority): -- [x] It should be 100% compatible with the [WebAssembly Spectest](https://github.com/wasmerio/wasmer/tree/master/spectests) +- [x] It should be 100% compatible with the [WebAssembly spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) - [x] It should be fast _(partially achieved)_ - [ ] Support Emscripten calls _(in the works)_ - [ ] Support Rust ABI calls -- [ ] Support GO ABI calls +- [ ] Support Go ABI calls ## Architecture -If you would like to know how Wasmer works under the hood, please visit our [ARCHITECTURE](https://github.com/wasmerio/wasmer/blob/master/ARCHITECTURE.md) document. +If you would like to know how Wasmer works under the hood, please see [ARCHITECTURE.md](./ARCHITECTURE.md). ## License -MIT/Apache-2.0 +Wasmer is primarily distributed under the terms of the [MIT license](http://opensource.org/licenses/MIT) ([LICENSE](./LICENSE)). -[Attributions](./ATTRIBUTIONS.md). +[ATTRIBUTIONS](./ATTRIBUTIONS.md) diff --git a/integration_tests/lua/README.md b/integration_tests/lua/README.md index ce2b03f6f..208e3438d 100644 --- a/integration_tests/lua/README.md +++ b/integration_tests/lua/README.md @@ -1,8 +1,8 @@ # `lua` integration test -This starts wasmer with the lua wasm file. The test asserts on -the output of wasmer. Run test with: +This starts Wasmer with the Lua Wasm file. The test makes assertions on +the output of Wasmer. Run test with: ``` > ./integration_tests/lua/test.sh diff --git a/integration_tests/nginx/README.md b/integration_tests/nginx/README.md index 9df8af773..3e9e46d8b 100644 --- a/integration_tests/nginx/README.md +++ b/integration_tests/nginx/README.md @@ -1,11 +1,11 @@ # `nginx` integration test -This starts wasmer with the nginx wasm file and serves an html -file with some simple text to assert on. The test script does +This starts Wasmer with the nginx Wasm file and serves an HTML +file with some simple text to assert on. The test script does the assertion. -Run test with: +Run test with: ``` > ./integration_tests/nginx/test.sh diff --git a/lib/README.md b/lib/README.md index 44b316865..79ae446d3 100644 --- a/lib/README.md +++ b/lib/README.md @@ -2,34 +2,34 @@ Wasmer is modularized into different libraries, separated into three main sections: -- [Runtime](#Runtime) -- [Integrations](#Integrations) -- [Backends](#Backends) +- [Runtime](#runtime) +- [Integrations](#integrations) +- [Backends](#backends) ## Runtime The core of Wasmer is the runtime, which provides the necessary -abstractions to create a good user-experience when embedding. +abstractions to create a good user experience when embedding. The runtime is divided into two main libraries: - [runtime-core](./runtime-core/): The main implementation of the runtime. -- [runtime](./runtime/): Easy-to-use api on top of runtime-core. +- [runtime](./runtime/): Easy-to-use API on top of `runtime-core`. ## Integrations -The intergration run on-top of the Wasmer runtime and allow us to run WebAssembly files compiled for different environments. +The integration builds on the Wasmer runtime and allow us to run WebAssembly files compiled for different environments. Wasmer intends to support different integrations: -- [emscripten](./emscripten): run emscripten-generated WebAssembly files, such as [Lua](../examples/lua.wasm) or [Nginx](../examples/nginx/nginx.wasm). +- [emscripten](./emscripten): run Emscripten-generated WebAssembly files, such as [Lua](../examples/lua.wasm) or [nginx](../examples/nginx/nginx.wasm). - Go ABI: _we will work on this soon! Want to give us a hand? ✋_ -- Blazor: _researching period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_ +- Blazor: _research period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_ ## Backends The Wasmer [runtime](./runtime) is designed to support multiple compiler backends, allowing the user -to tune the codegen properties (compile speed, performance, etc) to fit your usecase best. +to tune the codegen properties (compile speed, performance, etc) to best fit their use case. Currently, we support a Cranelift compiler backend: diff --git a/lib/spectests/spectests/README.md b/lib/spectests/spectests/README.md index b9c26d864..669246528 100644 --- a/lib/spectests/spectests/README.md +++ b/lib/spectests/spectests/README.md @@ -1,136 +1,135 @@ This directory contains tests for the core WebAssembly semantics, as described in [Semantics.md](https://github.com/WebAssembly/design/blob/master/Semantics.md) and specified by the [spec interpreter](https://github.com/WebAssembly/spec/blob/master/interpreter/spec). -This files should be a direct copy of the original [WebAssembly spec tests](https://github.com/WebAssembly/spec/tree/master/test/core). +These files should be a direct copy of the original [WebAssembly spec tests](/test/core). Tests are written in the [S-Expression script format](https://github.com/WebAssembly/spec/blob/master/interpreter/README.md#s-expression-syntax) defined by the interpreter. ## Autogenerated Rust test cases -This files will serve as base for autogenerating Rust testcases +These files will serve as a base for autogenerating Rust testcases when `WASM_GENERATE_SPECTESTS=1 cargo build` is executed -([src/build_spectests.rs](https://github.com/wasmerio/wasmer/blob/master/src/build_spectests.rs)). +([src/build_spectests.rs](/src/build_spectests.rs)). -The result autogenerated spectests live in the [src/spectests](https://github.com/wasmerio/wasmer/tree/master/src/spectests) -directory. +The resulting autogenerated spec tests live in the [src/spectests](/src/spectests). ## Testcases Currently supported command assertions: -- [x] Module _mostly implemented_ (it should support named modules `(module $Xx)`). -- [x] AssertReturn _mostly implemented_ (it should support calls to named modules `(invoke $Xx "call")`). -- [x] AssertReturnCanonicalNan _fully implemented_ -- [x] AssertReturnArithmeticNan _fully implemented_ -- [x] AssertTrap _fully implemented_ -- [x] AssertInvalid _Fully implemented_ (it should not require to do validation separate from compilation) -- [x] AssertMalformed _Fully implemented_ -- [ ] AssertUninstantiable _not implemented yet_ -- [ ] AssertExhaustion _not implemented yet_ -- [ ] Register _not implemented yet_ -- [x] PerformAction _partially implemented, only function invokations for now_ +- [x] `module` _mostly implemented_ (it should support named modules `(module $Xx)`). +- [x] `assert_return` _mostly implemented_ (it should support calls to named modules `(invoke $Xx "call")`). +- [x] `assert_return_canonical_nan` _fully implemented_ +- [x] `assert_return_arithmetic_nan` _fully implemented_ +- [x] `assert_trap` _fully implemented_ +- [x] `assert_invalid` _fully implemented_ (it should not require validation to be performed separate from compilation) +- [x] `assert_malformed` _fully implemented_ +- [ ] `assert_uninstantiable` _not implemented yet_ +- [ ] `assert_exhaustion` _not implemented yet_ +- [ ] `register` _not implemented yet_ +- [x] `perform_action` _partially implemented, only function invocations for now_ -### Covered spectests +### Covered spec tests -This spectests are currently covered: +The following spec tests are currently covered: -- address.wast ✅ -- align.wast ✅ -- binary.wast ✅ -- block.wast ✅ -- br.wast ✅ -- br_if.wast ✅ -- br_table.wast ✅ -- break-drop.wast ✅ -- call.wast ✅ -- call_indirect.wast ✅ -- comments.wast ✅ -- const.wast ✅ -- conversions.wast ✅ -- custom.wast ✅ -- data.wast ✅ -- elem.wast -- endianness.wast ✅ -- exports.wast ✅ -- f32.wast ✅ -- f32_bitwise.wast ✅ -- f32_cmp.wast ✅ -- f64.wast ✅ -- f64_bitwise.wast ✅ -- f64_cmp.wast ✅ -- fac.wast ✅ -- float_exprs.wast ✅ -- float_literals.wast ✅ -- float_memory.wast ✅ -- float_misc.wast ✅ -- forward.wast ✅ -- func.wast ✅ -- func_ptrs.wast ✅ -- get_local.wast ✅ -- globals.wast ✅ -- i32.wast ✅ -- i64.wast ✅ -- if.wast ✅ -- imports.wast -- inline-module.wast -- int_exprs.wast ✅ -- int_literals.wast ✅ -- labels.wast ✅ -- left-to-right.wast ✅ -- linking.wast -- loop.wast ✅ -- memory.wast ✅ -- memory_grow.wast ✅ -- memory_redundancy.wast ✅ -- memory_trap.wast ✅ -- names.wast ✅ -- nop.wast ✅ -- return.wast ✅ -- select.wast ✅ -- set_local.wast ✅ -- skip-stack-guard-page.wast -- stack.wast ✅ -- start.wast ✅ -- store_retval.wast ✅ -- switch.wast ✅ -- tee_local.wast ✅ -- token.wast ✅ -- traps.wast ✅ -- type.wast ✅ -- typecheck.wast ✅ -- unreachable.wast -- unreached-invalid.wast -- unwind.wast ✅ -- utf8-custom-section-id.wast -- utf8-import-field.wast -- utf8-import-module.wast -- utf8-invalid-encoding.wast +- [x] address.wast +- [x] align.wast +- [x] binary.wast +- [x] block.wast +- [x] br.wast +- [x] br_if.wast +- [x] br_table.wast +- [x] break-drop.wast +- [x] call.wast +- [x] call_indirect.wast +- [x] comments.wast +- [x] const.wast +- [x] conversions.wast +- [x] custom.wast +- [x] data.wast +- [ ] elem.wast +- [x] endianness.wast +- [x] exports.wast +- [x] f32.wast +- [x] f32_bitwise.wast +- [x] f32_cmp.wast +- [x] f64.wast +- [x] f64_bitwise.wast +- [x] f64_cmp.wast +- [x] fac.wast +- [x] float_exprs.wast +- [x] float_literals.wast +- [x] float_memory.wast +- [x] float_misc.wast +- [x] forward.wast +- [x] func.wast +- [x] func_ptrs.wast +- [x] get_local.wast +- [x] globals.wast +- [x] i32.wast +- [x] i64.wast +- [x] if.wast +- [ ] imports.wast +- [ ] inline-module.wast +- [x] int_exprs.wast +- [x] int_literals.wast +- [x] labels.wast +- [x] left-to-right.wast +- [ ] linking.wast +- [x] loop.wast +- [x] memory.wast +- [x] memory_grow.wast +- [x] memory_redundancy.wast +- [x] memory_trap.wast +- [x] names.wast +- [x] nop.wast +- [x] return.wast +- [x] select.wast +- [x] set_local.wast +- [ ] skip-stack-guard-page.wast +- [x] stack.wast +- [x] start.wast +- [x] store_retval.wast +- [x] switch.wast +- [x] tee_local.wast +- [x] token.wast +- [x] traps.wast +- [x] type.wast +- [x] typecheck.wast +- [ ] unreachable.wast +- [ ] unreached-invalid.wast +- [x] unwind.wast +- [ ] utf8-custom-section-id.wast +- [ ] utf8-import-field.wast +- [ ] utf8-import-module.wast +- [ ] utf8-invalid-encoding.wast ### Specific non-supported cases -There are some cases that we decided to skip for now to fasten the time to release: +There are some cases that we decided to skip for now to accelerate the release schedule: -- `SKIP_MUTABLE_GLOBALS`: Right now the WASM parser can't validate a module with imported/exported mut globals. We decided to skip the tests until Cranelift and wasmparser can handle this (original spec proposal: https://github.com/WebAssembly/mutable-global). Spectests affected: +- `SKIP_MUTABLE_GLOBALS`: Right now the Wasm parser can't validate a module with imported/exported `mut` globals. We decided to skip the tests until Cranelift and wasmparser can handle this (see [original spec proposal](https://github.com/WebAssembly/mutable-global)). Spec tests affected: - `globals.wast` -- `SKIP_CALL_INDIRECT_TYPE_MISMATCH`: we implemented traps in a fast way. We haven't covered yet the type mismatch on `call_indirect`. Specs affected: +- `SKIP_CALL_INDIRECT_TYPE_MISMATCH`: we implemented traps in a fast way. We haven't yet covered the type mismatch on `call_indirect`. Specs affected: - `call_indirect.wast` - `SKIP_CALL_UNDEFINED_ELEMENT` - Tables are imported into every spec module, even for modules that don't expect it. We need to figure out a way to prevent import of objects that are not explicitly imported into the module. + Tables are imported into every spec module, even for modules that don't expect it. We need to figure out a way to prevent importing of objects that are not explicitly imported into the module. -Currently cranelift_wasm::ModuleEnvironment does not provide `declare_table_import`, etc. so there is no meaningful way of fixing this yet. +Currently `cranelift_wasm::ModuleEnvironment` does not provide `declare_table_import`, etc. so there is no meaningful way of fixing this yet. - `call_indirect.wast` - `SKIP_SHARED_TABLE` [elem.wast] - Currently sharing tables between instances/modules does not work. Below are some of the reasons it is hard to achieve. + Currently sharing tables between instances/modules does not work. Below are some of the reasons it is hard to achieve: - Rust naturally prevents such because of the possibility of race conditions - - ImportObject is just a wrapper, what we really care about is references to its content. - - Instance::new contains a mutation points, the part where after getting the object (memory or table) we push values to it - table[table_element_index] = func_addr - - Instance has its own created memories and tables and references to them must outlive Instance::new() - - Possible strategy + - `ImportObject` is just a wrapper, what we really care about is references to its content. + - `Instance::new` contains a mutation points, the part where after getting the object (memory or table) we push values to it + `table[table_element_index] = func_addr` + - Instance has its own created memories and tables and references to them must outlive `Instance::new()` + - Possible strategy: ```rust // ImportObject should be passed by ref From b073145dbb09912dd83c13baa86e00322a072f4b Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Wed, 20 Feb 2019 09:52:42 -0600 Subject: [PATCH 47/50] Clone import in instantiate to prevent import move --- lib/runtime-c-api/src/lib.rs | 3 +-- lib/runtime-c-api/tests/test-import-function.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index d4286a9ca..5b1dd1955 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -467,7 +467,7 @@ pub unsafe extern "C" fn wasmer_instantiate( wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, }; - namespace.insert(import_name, unsafe { *Box::from_raw(export) }); // TODO Review + namespace.insert(import_name, unsafe { (&*export).clone() }); } for (module_name, namespace) in namespaces.into_iter() { import_object.register(module_name, namespace); @@ -488,7 +488,6 @@ pub unsafe extern "C" fn wasmer_instantiate( } }; unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; - Box::into_raw(Box::new(import_object)); wasmer_result_t::WASMER_OK } diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index bd09938d5..e7caed874 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -84,7 +84,7 @@ int main() assert(0 == strcmp(actual_str, "Hello, World!")); printf("Destroying func\n"); - // wasmer_func_destroy(func); + wasmer_func_destroy(func); printf("Destroy instance\n"); wasmer_instance_destroy(instance); return 0; From 14e5fb0e76acec214ff070f5c54106f670cdf5d4 Mon Sep 17 00:00:00 2001 From: Mackenzie Clark Date: Wed, 20 Feb 2019 13:58:30 -0800 Subject: [PATCH 48/50] move the installer and update appveyor --- .appveyor.yml | 4 ++-- {installer => src/installer}/wasmer.iss | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename {installer => src/installer}/wasmer.iss (100%) diff --git a/.appveyor.yml b/.appveyor.yml index 16432ed6b..e90075bd2 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -27,9 +27,9 @@ test_script: - cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../.. before_deploy: - - cd installer + - cd ./src/installer - iscc wasmer.iss - - copy /y .\WasmerInstaller.exe ..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe + - copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe - appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe artifacts: diff --git a/installer/wasmer.iss b/src/installer/wasmer.iss similarity index 100% rename from installer/wasmer.iss rename to src/installer/wasmer.iss From 1a951a9abf4530dc30268464d495f7ce80dfafe9 Mon Sep 17 00:00:00 2001 From: Mackenzie Clark Date: Wed, 20 Feb 2019 14:05:12 -0800 Subject: [PATCH 49/50] stub wasm32-unknown-emscripten target imports (#193) --- lib/emscripten/src/emscripten_target.rs | 175 ++++++++++++++++++++++++ lib/emscripten/src/lib.rs | 67 ++++++++- 2 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 lib/emscripten/src/emscripten_target.rs diff --git a/lib/emscripten/src/emscripten_target.rs b/lib/emscripten/src/emscripten_target.rs new file mode 100644 index 000000000..4f831e909 --- /dev/null +++ b/lib/emscripten/src/emscripten_target.rs @@ -0,0 +1,175 @@ +use crate::env::get_emscripten_data; +use wasmer_runtime_core::vm::Ctx; + +pub fn setTempRet0(ctx: &mut Ctx, a: i32) { + debug!("emscripten::setTempRet0"); +} +pub fn getTempRet0(ctx: &mut Ctx) -> i32 { + debug!("emscripten::getTempRet0"); + 0 +} +pub fn nullFunc_ji(ctx: &mut Ctx, a: i32) { + debug!("emscripten::nullFunc_ji"); +} +pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 { + debug!("emscripten::invoke_i"); + if let Some(dyn_call_i) = &get_emscripten_data(ctx).dyn_call_i { + dyn_call_i.call(index).unwrap() + } else { + panic!("dyn_call_i is set to None"); + } +} +pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 { + debug!("emscripten::invoke_ii"); + if let Some(dyn_call_ii) = &get_emscripten_data(ctx).dyn_call_ii { + dyn_call_ii.call(index, a1).unwrap() + } else { + panic!("dyn_call_ii is set to None"); + } +} +pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 { + debug!("emscripten::invoke_iii"); + if let Some(dyn_call_iii) = &get_emscripten_data(ctx).dyn_call_iii { + dyn_call_iii.call(index, a1, a2).unwrap() + } else { + panic!("dyn_call_iii is set to None"); + } +} +pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 { + debug!("emscripten::invoke_iiii"); + if let Some(dyn_call_iiii) = &get_emscripten_data(ctx).dyn_call_iiii { + dyn_call_iiii.call(index, a1, a2, a3).unwrap() + } else { + panic!("dyn_call_iiii is set to None"); + } +} +pub fn invoke_v(ctx: &mut Ctx, index: i32) { + debug!("emscripten::invoke_v"); + if let Some(dyn_call_v) = &get_emscripten_data(ctx).dyn_call_v { + dyn_call_v.call(index).unwrap(); + } else { + panic!("dyn_call_v is set to None"); + } +} +pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) { + debug!("emscripten::invoke_vi"); + if let Some(dyn_call_vi) = &get_emscripten_data(ctx).dyn_call_vi { + dyn_call_vi.call(index, a1).unwrap(); + } else { + panic!("dyn_call_vi is set to None"); + } +} +pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) { + debug!("emscripten::invoke_vii"); + if let Some(dyn_call_vii) = &get_emscripten_data(ctx).dyn_call_vii { + dyn_call_vii.call(index, a1, a2).unwrap(); + } else { + panic!("dyn_call_vii is set to None"); + } +} +pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) { + debug!("emscripten::invoke_viii"); + if let Some(dyn_call_viii) = &get_emscripten_data(ctx).dyn_call_viii { + dyn_call_viii.call(index, a1, a2, a3).unwrap(); + } else { + panic!("dyn_call_viii is set to None"); + } +} +pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) { + debug!("emscripten::invoke_viiii"); + if let Some(dyn_call_viiii) = &get_emscripten_data(ctx).dyn_call_viiii { + dyn_call_viiii.call(index, a1, a2, a3, a4).unwrap(); + } else { + panic!("dyn_call_viiii is set to None"); + } +} +pub fn __Unwind_Backtrace(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::__Unwind_Backtrace"); + 0 +} +pub fn __Unwind_FindEnclosingFunction(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::__Unwind_FindEnclosingFunction"); + 0 +} +pub fn __Unwind_GetIPInfo(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::__Unwind_GetIPInfo"); + 0 +} +pub fn ___cxa_find_matching_catch_2(ctx: &mut Ctx) -> i32 { + debug!("emscripten::___cxa_find_matching_catch_2"); + 0 +} +pub fn ___cxa_find_matching_catch_3(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::___cxa_find_matching_catch_3"); + 0 +} +pub fn ___cxa_free_exception(ctx: &mut Ctx, a: i32) { + debug!("emscripten::___cxa_free_exception"); +} +pub fn ___resumeException(ctx: &mut Ctx, a: i32) { + debug!("emscripten::___resumeException"); +} +pub fn _dladdr(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::_dladdr"); + 0 +} +pub fn _pthread_cond_destroy(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_cond_destroy"); + 0 +} +pub fn _pthread_cond_init(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::_pthread_cond_init"); + 0 +} +pub fn _pthread_cond_signal(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_cond_signal"); + 0 +} +pub fn _pthread_cond_wait(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::_pthread_cond_wait"); + 0 +} +pub fn _pthread_condattr_destroy(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_condattr_destroy"); + 0 +} +pub fn _pthread_condattr_init(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_condattr_init"); + 0 +} +pub fn _pthread_condattr_setclock(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::_pthread_condattr_setclock"); + 0 +} +pub fn _pthread_mutex_destroy(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_mutex_destroy"); + 0 +} +pub fn _pthread_mutex_init(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::_pthread_mutex_init"); + 0 +} +pub fn _pthread_mutexattr_destroy(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_mutexattr_destroy"); + 0 +} +pub fn _pthread_mutexattr_init(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_mutexattr_init"); + 0 +} +pub fn _pthread_mutexattr_settype(ctx: &mut Ctx, a: i32, b: i32) -> i32 { + debug!("emscripten::_pthread_mutexattr_settype"); + 0 +} +pub fn _pthread_rwlock_rdlock(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_rwlock_rdlock"); + 0 +} +pub fn _pthread_rwlock_unlock(ctx: &mut Ctx, a: i32) -> i32 { + debug!("emscripten::_pthread_rwlock_unlock"); + 0 +} +pub fn ___gxx_personality_v0(ctx: &mut Ctx, a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) -> i32 { + debug!("emscripten::___gxx_personality_v0"); + 0 +} diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 3ed5c36dd..a58b3b118 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -27,6 +27,7 @@ mod file_descriptor; pub mod stdio; // EMSCRIPTEN APIS +mod emscripten_target; mod env; mod errno; mod exception; @@ -92,8 +93,17 @@ pub struct EmscriptenData<'a> { pub memalign: Option>, pub memset: Func<'a, (u32, u32, u32), u32>, pub stack_alloc: Func<'a, u32, u32>, - pub jumps: Vec>, + + pub dyn_call_i: Option>, + pub dyn_call_ii: Option>, + pub dyn_call_iii: Option>, + pub dyn_call_iiii: Option>, + pub dyn_call_v: Option>, + pub dyn_call_vi: Option>, + pub dyn_call_vii: Option>, + pub dyn_call_viii: Option>, + pub dyn_call_viiii: Option>, } impl<'a> EmscriptenData<'a> { @@ -108,6 +118,16 @@ impl<'a> EmscriptenData<'a> { let memset = instance.func("_memset").unwrap(); let stack_alloc = instance.func("stackAlloc").unwrap(); + let dyn_call_i = instance.func("dynCall_i").ok(); + let dyn_call_ii = instance.func("dynCall_ii").ok(); + let dyn_call_iii = instance.func("dynCall_iii").ok(); + let dyn_call_iiii = instance.func("dynCall_iiii").ok(); + let dyn_call_v = instance.func("dynCall_v").ok(); + let dyn_call_vi = instance.func("dynCall_vi").ok(); + let dyn_call_vii = instance.func("dynCall_vii").ok(); + let dyn_call_viii = instance.func("dynCall_viii").ok(); + let dyn_call_viiii = instance.func("dynCall_viiii").ok(); + EmscriptenData { malloc, free, @@ -115,6 +135,15 @@ impl<'a> EmscriptenData<'a> { memset, stack_alloc, jumps: Vec::new(), + dyn_call_i, + dyn_call_ii, + dyn_call_iii, + dyn_call_iiii, + dyn_call_v, + dyn_call_vi, + dyn_call_vii, + dyn_call_viii, + dyn_call_viiii, } } } @@ -491,6 +520,42 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject "_dlopen" => func!(crate::linking::_dlopen), "_dlsym" => func!(crate::linking::_dlsym), + // wasm32-unknown-emscripten + "setTempRet0" => func!(crate::emscripten_target::setTempRet0), + "getTempRet0" => func!(crate::emscripten_target::getTempRet0), + "nullFunc_ji" => func!(crate::emscripten_target::nullFunc_ji), + "invoke_i" => func!(crate::emscripten_target::invoke_i), + "invoke_ii" => func!(crate::emscripten_target::invoke_ii), + "invoke_iii" => func!(crate::emscripten_target::invoke_iii), + "invoke_iiii" => func!(crate::emscripten_target::invoke_iiii), + "invoke_v" => func!(crate::emscripten_target::invoke_v), + "invoke_vi" => func!(crate::emscripten_target::invoke_vi), + "invoke_vii" => func!(crate::emscripten_target::invoke_vii), + "invoke_viii" => func!(crate::emscripten_target::invoke_viii), + "invoke_viiii" => func!(crate::emscripten_target::invoke_viiii), + "__Unwind_Backtrace" => func!(crate::emscripten_target::__Unwind_Backtrace), + "__Unwind_FindEnclosingFunction" => func!(crate::emscripten_target::__Unwind_FindEnclosingFunction), + "__Unwind_GetIPInfo" => func!(crate::emscripten_target::__Unwind_GetIPInfo), + "___cxa_find_matching_catch_2" => func!(crate::emscripten_target::___cxa_find_matching_catch_2), + "___cxa_find_matching_catch_3" => func!(crate::emscripten_target::___cxa_find_matching_catch_3), + "___cxa_free_exception" => func!(crate::emscripten_target::___cxa_free_exception), + "___resumeException" => func!(crate::emscripten_target::___resumeException), + "_dladdr" => func!(crate::emscripten_target::_dladdr), + "_pthread_cond_destroy" => func!(crate::emscripten_target::_pthread_cond_destroy), + "_pthread_cond_init" => func!(crate::emscripten_target::_pthread_cond_init), + "_pthread_cond_signal" => func!(crate::emscripten_target::_pthread_cond_signal), + "_pthread_cond_wait" => func!(crate::emscripten_target::_pthread_cond_wait), + "_pthread_condattr_destroy" => func!(crate::emscripten_target::_pthread_condattr_destroy), + "_pthread_condattr_init" => func!(crate::emscripten_target::_pthread_condattr_init), + "_pthread_condattr_setclock" => func!(crate::emscripten_target::_pthread_condattr_setclock), + "_pthread_mutex_destroy" => func!(crate::emscripten_target::_pthread_mutex_destroy), + "_pthread_mutex_init" => func!(crate::emscripten_target::_pthread_mutex_init), + "_pthread_mutexattr_destroy" => func!(crate::emscripten_target::_pthread_mutexattr_destroy), + "_pthread_mutexattr_init" => func!(crate::emscripten_target::_pthread_mutexattr_init), + "_pthread_mutexattr_settype" => func!(crate::emscripten_target::_pthread_mutexattr_settype), + "_pthread_rwlock_rdlock" => func!(crate::emscripten_target::_pthread_rwlock_rdlock), + "_pthread_rwlock_unlock" => func!(crate::emscripten_target::_pthread_rwlock_unlock), + "___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0), }, "global" => { "NaN" => Global::new(Value::F64(f64::NAN)), From c3065a3869af343308e8573518a2bcaa8c17eef8 Mon Sep 17 00:00:00 2001 From: Mackenzie Clark Date: Wed, 20 Feb 2019 15:42:07 -0800 Subject: [PATCH 50/50] add cargo cache for appveyor (#194) --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index e90075bd2..488e400fd 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,9 @@ environment: ABI: msvc TARGET: x86_64-pc-windows-msvc +cache: + - 'C:\Users\appveyor\.cargo' + install: - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe -yv --default-host %target%