From a57c9427dd70ad1d1d87dd2252b902e60de45abe Mon Sep 17 00:00:00 2001 From: Frederic ST Date: Fri, 10 May 2019 14:05:31 +0200 Subject: [PATCH 01/13] Fix typo on README.md (#6) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f5384362..645977dea 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The application manager component handles the packets that the platform recieved The WebAssembly runtime is the execution environment for WASM applications. -The messaging layer can suppor the API for WASM applications communicate to each other and also the host environment. +The messaging layer can support the API for WASM applications communicate to each other and also the host environment. When Ahead of Time compilation is enabled, the WASM application can be either bytecode or compiled native binary. From 89ad7dc1014dc6757dba64c494d598f7cbf2fab8 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Fri, 10 May 2019 13:07:58 +0100 Subject: [PATCH 02/13] fix typos (#7) Signed-off-by: Eric Engestrom --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 645977dea..8efb554d9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Features Architecture ========================= -The application manager component handles the packets that the platform recieved from external through any communication buses such as socket, serial port, PSI. A packet type can be either request, response or event. It will service the request with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URIs, it will filter the resource registeration table and router the request to internal queue of responsible application. +The application manager component handles the packets that the platform received from external through any communication buses such as socket, serial port, PSI. A packet type can be either request, response or event. It will service the request with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URIs, it will filter the resource registration table and router the request to internal queue of responsible application. The WebAssembly runtime is the execution environment for WASM applications. @@ -62,7 +62,7 @@ make ``` Zephyr ------------------------- -You need download Zephyr source code first and embeded WAMR into it. +You need download Zephyr source code first and embedded WAMR into it. ``` Bash git clone https://github.com/zephyrproject-rtos/zephyr.git cd zephyr/samples/ @@ -301,7 +301,7 @@ The pre-defined MACRO `EXPORT_WASM_API` should be used to declare a function exp #define EXPORT_WASM_API(symbol) {#symbol, symbol} ``` -Below code example shows how to extend the library to support `customeized()`: +Below code example shows how to extend the library to support `customized()`: ``` C //lib-export-impl.c void customized() From 13db1976af647952d1e254648d8fe9078bbfc176 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Fri, 10 May 2019 13:09:30 +0100 Subject: [PATCH 03/13] fix iwasm build path (#8) Signed-off-by: Eric Engestrom --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8efb554d9..ec7b29f86 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ sudo apt-get install g++-multilib ``` After installing dependencies, build the source code: ``` Bash -cd products/linux/ +cd core/iwasm/products/linux/ mkdir build cd build cmake .. From 76a40bf4f561dac1fe6d2916ac376419cf11d2f8 Mon Sep 17 00:00:00 2001 From: Kyle Mills Date: Fri, 10 May 2019 08:25:04 -0400 Subject: [PATCH 04/13] Fix: (Minor Spelling Issue) (#9) Fix minor spelling issue in the README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec7b29f86..9be827b72 100644 --- a/README.md +++ b/README.md @@ -353,7 +353,7 @@ int main(int argc, char **argv) } ``` -Comming soon... +Coming soon... ======================== We are preparing the open source for application manager and related cool samples like inter-application communication, application life cycle management, 2D graphic demo and more. You will get updated soon. From 5df8e94c29596b3ec929d77a32969165ad279ed3 Mon Sep 17 00:00:00 2001 From: Wang Xin Date: Fri, 10 May 2019 21:19:47 +0800 Subject: [PATCH 05/13] Update README.md (#11) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9be827b72..e138be07f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ WebAssembly Micro Runtime (WAMR) is standalone WebAssembly (WASM) runtime with s - Dynamic WASM application management (Not available in github yet. It will be released soon) Why should we use a WASM runtime out of browser? There are a few points which might be meaningful: -1. WASM is already the LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage comparing to those language bound runtimes like JS, Lua. +1. WASM is already a LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage comparing to those language bound runtimes like JS, Lua. 2. WASM is an open standard and the growing trend is so fast as it is supported by the whole web ecosystem 3. WASM is designed to be very friendly for compiling to native binary and gaining the native speed. 4. Potentially change the development practices. Imaging we can do both the WASM application development and validation in a browser, then just download the wasm binary code into the target device. @@ -28,7 +28,7 @@ Features Architecture ========================= -The application manager component handles the packets that the platform received from external through any communication buses such as socket, serial port, PSI. A packet type can be either request, response or event. It will service the request with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URIs, it will filter the resource registration table and router the request to internal queue of responsible application. +The application manager component handles the packets that the platform received from external through any communication buses such as socket, serial port, PSI. A packet type can be either request, response or event. The app manager will serve the requests with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URIs, it will filter the resource registration table and router the request to internal queue of responsible application. The WebAssembly runtime is the execution environment for WASM applications. @@ -176,7 +176,7 @@ WASM application library In general, there are 3 kinds of APIs for programming the WASM application: - Built-in APIs: WAMR has already provided a minimal API set for developers. - 3rd party APIs: Programmer can download include any 3rd party C source code, and added into their own WASM app source tree. -- Platform native APIs: The board vendors define these APIs during their making board firmware. They are provided WASM application to invoke like built-in and 3rd party APIs. In this way board vendors extend APIs which can make programmers develop more complicated WASM apps. +- Platform native APIs: WAMR provides a mechanism to export the native API to the WASM applications. Built-in application library @@ -206,7 +206,7 @@ char *strncpy(char *dest, const char *src, unsigned long n); ``` **Base library**
-The basic support like communication, timers etc is already available. The header files is ```lib/app-libs/base/wasm-app.h```, it includes request and response APIs, event pub/sub APIs and timer APIs. Please be noted that they may not work if you have no corresponding framework to work with them. +The basic support for communication, timers etc is already available. You can refer to the header files ```lib/app-libs/base/wasm-app.h``` which contains the definitions for request and response APIs, event pub/sub APIs and timer APIs. Please be noted that these APIs require the native implementations. The API set is listed as below: ``` C typedef void(*request_handler_f)(request_t *) ; @@ -232,7 +232,7 @@ void api_timer_restart(user_timer_t timer, int interval); ``` **Library extension reference**
-Currently we provide the sensor APIs as one library extension sample. The header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is listed as below: +Currently we provide the sensor APIs as one library extension sample. In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below: ``` C sensor_t sensor_open(const char* name, int index, void(*on_sensor_event)(sensor_t, attr_container_t *, void *), From 8c76e17e290598edeb9b6fe1ad33c56c1bc2e170 Mon Sep 17 00:00:00 2001 From: Pieter van Mill Date: Fri, 10 May 2019 16:50:10 +0200 Subject: [PATCH 06/13] Update README.md (#12) Throughout the text I have tried to make it a bit more readable. --- README.md | 114 +++++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index e138be07f..c15698726 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,40 @@ WebAssembly Micro Runtime ========================= -WebAssembly Micro Runtime (WAMR) is standalone WebAssembly (WASM) runtime with small footprint. It includes a few components: +WebAssembly Micro Runtime (WAMR) is standalone WebAssembly (WASM) runtime with a small footprint. It includes a few components: - WebAssembly VM core -- WASM application programming API (code available, but compilation is depending on the app manager component) -- Dynamic WASM application management (Not available in github yet. It will be released soon) +- WASM application programming API (code available, but compilation depends on the app manager component) +- Dynamic WASM application management (Not available on Github yet. It will be released soon) -Why should we use a WASM runtime out of browser? There are a few points which might be meaningful: -1. WASM is already a LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage comparing to those language bound runtimes like JS, Lua. -2. WASM is an open standard and the growing trend is so fast as it is supported by the whole web ecosystem -3. WASM is designed to be very friendly for compiling to native binary and gaining the native speed. -4. Potentially change the development practices. Imaging we can do both the WASM application development and validation in a browser, then just download the wasm binary code into the target device. -5. WASM can work without garbage collection. It can be designed to support execution determinics for the time sensitive requirement. +Why should you use a WASM runtime out of your browser? There are a few points where this might be meaningful: +1. WASM is already a LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage compared to language bound runtimes like JS or Lua. +2. WASM is an open standard and it is fast becoming supported by the whole web ecosystem. +3. WASM is designed to be very friendly for compiling to native binaries and gaining the native speed. +4. It can potentially change the development practices. Imagine we can do both the WASM application development and validation in a browser, then just download the WASM binary code onto the target device. +5. WASM can work without garbage collection. It is designed to support execution determinics for the time sensitive requirement. Features ========================= - WASM interpreter (AOT is planned) -- Provide built-in Libc subset, support "side_module=1" EMCC compilation option -- Provide APIs for embedding runtime into production software -- Provide mechanism for exporting native APIs to WASM applications -- Support programming firmware apps in multi languages (C/C++/Java/Rust/Go/TypeScript etc.) +- Provides built-in Libc subset, supports "side_module=1" EMCC compilation option +- Provides API's for embedding runtime into production software +- Provides a mechanism for exporting native API's to WASM applications +- Supports the programming of firmware apps in a large range of languages (C/C++/Java/Rust/Go/TypeScript etc.) - App sandbox execution environment on embedded OS -- Pure asynchronized programming model +- Purely asynchronized programming model - Menu configuration for easy platform integration -- Support micro service and pub-sub event inter-app communication models +- Supports micro-service and pub-sub event inter-app communication models - Easy to extend to support remote FW application management from host or cloud Architecture ========================= -The application manager component handles the packets that the platform received from external through any communication buses such as socket, serial port, PSI. A packet type can be either request, response or event. The app manager will serve the requests with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URIs, it will filter the resource registration table and router the request to internal queue of responsible application. +The application manager component handles the packets that the platform receives from external sources through any communication buses such as socket, serial port or PSI. A packet type can be either a request, response or event. The app manager will serve the requests with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URI's, it will filter the resource registration table and route the request to the internal queue of the responsible application. The WebAssembly runtime is the execution environment for WASM applications. -The messaging layer can support the API for WASM applications communicate to each other and also the host environment. +The messaging layer can support the API for WASM applications to communicate to each other and also the host environment. -When Ahead of Time compilation is enabled, the WASM application can be either bytecode or compiled native binary. +When Ahead of Time compilation is enabled, the WASM application can be either bytecode or a compiled native binary. @@ -42,12 +42,12 @@ When Ahead of Time compilation is enabled, the WASM application can be either by Build WAMR Core ========================= -Please follow below instructions to build WAMR core on different platforms. +Please follow the instructions below to build the WAMR core on different platforms. Linux ------------------------- -Firstly please install library dependencies of lib gcc. -Use below installation commands for Ubuntu Linux: +First of all please install library dependencies of lib gcc. +Use installation commands below for Ubuntu Linux: ``` Bash sudo apt install lib32gcc-5-dev sudo apt-get install g++-multilib @@ -62,7 +62,7 @@ make ``` Zephyr ------------------------- -You need download Zephyr source code first and embedded WAMR into it. +You need to download the Zephyr source code first and embedded WAMR into it. ``` Bash git clone https://github.com/zephyrproject-rtos/zephyr.git cd zephyr/samples/ @@ -79,18 +79,18 @@ ninja Build WASM app ========================= A popular method to build out WASM binary is to use ```emcc```. -Assuming you are using Linux. Please install emcc from Emscripten EMSDK following below steps: +Assuming you are using Linux, please install emcc from Emscripten EMSDK following the steps below: ``` git clone https://github.com/emscripten-core/emsdk.git emsdk install latest emsdk activate latest ``` -add ```./emsdk_env.sh``` into path to ease future use, or source it everytime. -Emscripten website provides other installtion method beyond Linux. +add ```./emsdk_env.sh``` into the path to ease future use, or source it everytime. +The Emscripten website provides other installtion methods beyond Linux. todo: user should copy the app-libs folder into project and include and build. -You can write a simple ```test.c```as the first sample. +You can write a simple ```test.c``` as the first sample. ``` C #include #include @@ -116,7 +116,7 @@ int main(int argc, char **argv) return 0; } ``` -Use below emcc commmand to build the WASM C source code into WASM binary. +Use the emcc commmand below to build the WASM C source code into the WASM binary. ``` Bash emcc -g -O3 *.c -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 -o test.wasm @@ -125,30 +125,30 @@ You will get ```test.wasm``` which is the WASM app binary. Run WASM app ======================== -Assume you are using Linux, the command to run the test.wasm is +Assume you are using Linux, the command to run the test.wasm is: ``` Bash cd iwasm/products/linux/bin ./iwasm test.wasm ``` -You will get output: +You will get the following output: ``` Hello world! buf ptr: 0x000101ac buf: 1234 ``` -If you would like to run test app on Zephyr, we have embedded test sample into its OS image. You need to execute +If you would like to run the test app on Zephyr, we have embedded a test sample into its OS image. You will need to execute: ``` ninja run ``` Embed WAMR into software production ===================================== -WAMR can be built into a standalone executable which takes WASM application file name as input, and then execute it. To use it in the embedded environment, you should embed WAMR into your own software product. WASM provides a set of APIs for embedders code to load WASM module, instansiate module and invoke WASM function from native call. +WAMR can be built into a standalone executable which takes WASM application file name as input, and then execute it. To use it in the embedded environment, you should embed WAMR into your own software product. WASM provides a set of API's for embedded code to load WASM module, instantiate the module and invoke the WASM function from a native call. -A typical WAMR APIs usage is as below: +A typical WAMR API usage is as described below: ``` C wasm_module_t module; wasm_module_inst_t inst; @@ -173,19 +173,19 @@ A typical WAMR APIs usage is as below: WASM application library ======================== -In general, there are 3 kinds of APIs for programming the WASM application: -- Built-in APIs: WAMR has already provided a minimal API set for developers. -- 3rd party APIs: Programmer can download include any 3rd party C source code, and added into their own WASM app source tree. -- Platform native APIs: WAMR provides a mechanism to export the native API to the WASM applications. +In general, there are 3 kinds of API's for programming the WASM application: +- Built-in API's: WAMR has already provided a minimal API set for developers. +- 3rd party API's: Programmer can download and include any 3rd party C source code, and add it into their own WASM app source tree. +- Platform native API's: WAMR provides a mechanism to export the native API to the WASM application. Built-in application library --------------- -Built-in APIs include Libc APIs, Base library, Extension library reference. +Built-in API's include Libc APIs, Base library and Extension library reference. **Libc APIs**
-It is the minimal Libc APIs like memory allocation and string copy etc. -The header files is ```lib/app-libs/libc/lib-base.h```. The API set is listed as below: +This is the minimal Libc APIs like memory allocation and string copy etc. +The header file is ```lib/app-libs/libc/lib-base.h```. The API set is listed as below: ``` C void *malloc(size_t size); void *calloc(size_t n, size_t size); @@ -206,7 +206,7 @@ char *strncpy(char *dest, const char *src, unsigned long n); ``` **Base library**
-The basic support for communication, timers etc is already available. You can refer to the header files ```lib/app-libs/base/wasm-app.h``` which contains the definitions for request and response APIs, event pub/sub APIs and timer APIs. Please be noted that these APIs require the native implementations. +The basic support for communication, timers etc is already available. You can refer to the header file ```lib/app-libs/base/wasm-app.h``` which contains the definitions for request and response API's, event pub/sub APIs and timer APIs. Please note that these API's require the native implementations. The API set is listed as below: ``` C typedef void(*request_handler_f)(request_t *) ; @@ -232,7 +232,7 @@ void api_timer_restart(user_timer_t timer, int interval); ``` **Library extension reference**
-Currently we provide the sensor APIs as one library extension sample. In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below: +Currently we provide the sensor API's as one library extension sample. In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below: ``` C sensor_t sensor_open(const char* name, int index, void(*on_sensor_event)(sensor_t, attr_container_t *, void *), @@ -245,11 +245,11 @@ bool sensor_close(sensor_t sensor); The mechanism of exporting Native API to WASM application ======================================================= -The basic working flow for WASM application calling into the native API is described as following diagram. +The basic working flow for WASM application calling into the native API is described in the following diagram. -WAMR provides the macro `EXPORT_WASM_API` to enable users to export native API to WASM application. WAMR implemented a base API for timer and messaging by using `EXPORT_WASM_API`. They can be reference point of extending your own library. +WAMR provides the macro `EXPORT_WASM_API` to enable users to export native API to a WASM application. WAMR implemented a base API for the timer and messaging by using `EXPORT_WASM_API`. They can be a reference point for extending your own library. ``` C static NativeSymbol extended_native_symbol_defs[] = { EXPORT_WASM_API(wasm_register_resource), @@ -264,26 +264,26 @@ static NativeSymbol extended_native_symbol_defs[] = { ``` -![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** The WebAssembly application is supposed to access its own memory space, the integrator should carefully design the native function to ensure the memory safe. The native API to be exporte to WASM application must follow the rules: +![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** The WebAssembly application is supposed to access its own memory space, the integrator should carefully design the native function to ensure that the memory is safe. The native API to be exported to the WASM application must follow these rules: - Only use 32 bits number for parameters -- Don’t passing data structure pointer (do data serialization instead) -- Do the pointer address conversion in native API -- Don’t passing function pointer as callback +- Don't pass data to the structure pointer (do data serialization instead) +- Do the pointer address conversion in the native API +- Don’t pass function pointer as callback -Below is a sample of library extension. All invoke across WASM world and native world must be serialized and de-serialized, and native world must do boundary check for every incoming address from WASM world. +Below is a sample of a library extension. All code invoked across WASM and native world must be serialized and de-serialized, and the native world must do a boundary check for every incoming address from the WASM world. Exporting native API steps ========================== -WAMR implemented a framework for developers to export APIs. The procedure to expose the platform APIs in three steps: +WAMR implemented a framework for developers to export API's. Below is the procedure to expose the platform APIs in three steps: **Step 1. Create a header file**
-Declare the APIs for WASM application source project to include. +Declare the API's for your WASM application source project to include. **Step 2. Create a source file**
-Export the platform APIs, for example in ``` products/linux/ext-lib-export.c ``` +Export the platform API's, for example in ``` products/linux/ext-lib-export.c ``` ``` C #include "lib-export.h" @@ -295,7 +295,7 @@ static NativeSymbol extended_native_symbol_defs[] = ``` **Step 3. Register new APIs**
-Use macro EXPORT_WASM_API and EXPORT_WASM_API2 to add exported APIs into the array of ```extended_native_symbol_defs```. +Use the macro `EXPORT_WASM_API` and `EXPORT_WASM_API2` to add exported API's into the array of ```extended_native_symbol_defs```. The pre-defined MACRO `EXPORT_WASM_API` should be used to declare a function export: ``` c #define EXPORT_WASM_API(symbol) {#symbol, symbol} @@ -338,24 +338,24 @@ static NativeSymbol extended_native_symbol_defs[] = ``` Use extended library ------------------------ -In the application source project, it includes the WAMR built-in APIs header file and platform extension header files. -Assume the board vendor extend the library which added a API called customized(). The WASM application would be like this: +In the application source project, it will include the WAMR built-in APIs header file and platform extension header files. +This is assuming the board vendor extends the library which added an API called customized(). The WASM application would be like this: ``` C #include -#include "lib-export-dec.h" // provided by platform vendor +#include "lib-export-dec.h" // provided by the platform vendor int main(int argc, char **argv) { int I; char *buf = “abcd”; - customized(); // customized API provided by platform vendor + customized(); // customized API provided by the platform vendor return i; } ``` Coming soon... ======================== -We are preparing the open source for application manager and related cool samples like inter-application communication, application life cycle management, 2D graphic demo and more. You will get updated soon. +We are preparing the open source code for the application manager and related code samples like inter-application communication, application life cycle management, 2D graphic demo and more. This will get updated soon. Submit issues and request ========================= From 179d34ac780aa68147ee7651b1c40c8fe6545c6f Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Fri, 10 May 2019 16:21:32 +0100 Subject: [PATCH 07/13] delete empty file (#13) Signed-off-by: Eric Engestrom --- projects/README.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 projects/README.md diff --git a/projects/README.md b/projects/README.md deleted file mode 100644 index 792d60054..000000000 --- a/projects/README.md +++ /dev/null @@ -1 +0,0 @@ -# From 108254974fff3e70f9eb248b1fa0c7fa0dc7468a Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Fri, 10 May 2019 16:21:54 +0100 Subject: [PATCH 08/13] add installation directives (#14) Signed-off-by: Eric Engestrom --- core/iwasm/products/linux/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/iwasm/products/linux/CMakeLists.txt b/core/iwasm/products/linux/CMakeLists.txt index 5421d11ee..4a955f1b6 100644 --- a/core/iwasm/products/linux/CMakeLists.txt +++ b/core/iwasm/products/linux/CMakeLists.txt @@ -75,6 +75,8 @@ add_library (vmlib add_executable (iwasm main.c ext-lib-export.c) +install (TARGETS iwasm DESTINATION bin) + target_link_libraries (iwasm vmlib -lm -ldl -lpthread) add_library (libiwasm SHARED @@ -86,6 +88,8 @@ add_library (libiwasm SHARED ${PLATFORM_SHARED_SOURCE} ${MEM_ALLOC_SHARED_SOURCE}) +install (TARGETS libiwasm DESTINATION lib) + set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) target_link_libraries (libiwasm -lm -ldl -lpthread) From 31de47bd92f0bdd2c90e6c8f261a65319d09beed Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Sat, 11 May 2019 14:36:20 +0200 Subject: [PATCH 09/13] Update README.md (#18) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c15698726..585821f85 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ emsdk install latest emsdk activate latest ``` add ```./emsdk_env.sh``` into the path to ease future use, or source it everytime. -The Emscripten website provides other installtion methods beyond Linux. +The Emscripten website provides other installation methods beyond Linux. todo: user should copy the app-libs folder into project and include and build. @@ -116,7 +116,7 @@ int main(int argc, char **argv) return 0; } ``` -Use the emcc commmand below to build the WASM C source code into the WASM binary. +Use the emcc command below to build the WASM C source code into the WASM binary. ``` Bash emcc -g -O3 *.c -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 -o test.wasm From 62605cfb2e599ba61b8517173def370e220edddb Mon Sep 17 00:00:00 2001 From: Johnnie Birch <45402135+jlb6740@users.noreply.github.com> Date: Sat, 11 May 2019 06:05:43 -0700 Subject: [PATCH 10/13] Updates to the Readme (#15) Update README.md --- README.md | 87 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 585821f85..7a3691313 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,25 @@ WebAssembly Micro Runtime ========================= -WebAssembly Micro Runtime (WAMR) is standalone WebAssembly (WASM) runtime with a small footprint. It includes a few components: -- WebAssembly VM core -- WASM application programming API (code available, but compilation depends on the app manager component) -- Dynamic WASM application management (Not available on Github yet. It will be released soon) +WebAssembly Micro Runtime (WAMR) is standalone WebAssembly (WASM) runtime designed for a small footprint. It includes: +- A WebAssembly (WASM) VM core +- The supporting APIs for the WASM applications (code is available but compilation depends on the app manager component) +- A mechanism for dynamic management of the WASM application (Not available on Github yet. To be released soon) -Why should you use a WASM runtime out of your browser? There are a few points where this might be meaningful: -1. WASM is already a LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage compared to language bound runtimes like JS or Lua. -2. WASM is an open standard and it is fast becoming supported by the whole web ecosystem. -3. WASM is designed to be very friendly for compiling to native binaries and gaining the native speed. -4. It can potentially change the development practices. Imagine we can do both the WASM application development and validation in a browser, then just download the WASM binary code onto the target device. +Why should you use a WASM runtime out of your browser? There are a few points where this might be meaningful: +1. WASM is already a LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage compared to language bound runtimes like JS or Lua. +2. WASM is an open standard and it is fast becoming supported by the whole web ecosystem. +3. WASM is designed to be very friendly for compiling to native binaries and gaining the native speed. +4. It can potentially change the development practices. Imagine we can do both the WASM application development and validation in a browser, then just download the WASM binary code onto the target device. 5. WASM can work without garbage collection. It is designed to support execution determinics for the time sensitive requirement. +6. Maintain the safety goals WASM has of providing a sandboxed execution enviornment for untrusted code. In addition, because WASM is a compilation target, this implies a benefit of being able to target both an execution and security profile that is consistent across popular high-level programming languages. -Features + +Current Features of WAMR ========================= - WASM interpreter (AOT is planned) -- Provides built-in Libc subset, supports "side_module=1" EMCC compilation option +- Provides support for a subset of Lib. +- Supports "side_module=1" EMCC compilation option - Provides API's for embedding runtime into production software - Provides a mechanism for exporting native API's to WASM applications - Supports the programming of firmware apps in a large range of languages (C/C++/Java/Rust/Go/TypeScript etc.) @@ -28,17 +31,17 @@ Features Architecture ========================= -The application manager component handles the packets that the platform receives from external sources through any communication buses such as socket, serial port or PSI. A packet type can be either a request, response or event. The app manager will serve the requests with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URI's, it will filter the resource registration table and route the request to the internal queue of the responsible application. +The application manager component handles the packets that the platform receives from external sources through any communication buses such as a socket, serial port or PSI. A packet type can be either a request, response or an event. The app manager will serve the requests with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URI's, it will filter the resource registration table and route the request to the internal queue of the responsible application. -The WebAssembly runtime is the execution environment for WASM applications. +- The WebAssembly runtime provides the execution environment for WASM applications. -The messaging layer can support the API for WASM applications to communicate to each other and also the host environment. +- The messaging layer can support the API for WASM applications to communicate to each other and also the host environment. -When Ahead of Time compilation is enabled, the WASM application can be either bytecode or a compiled native binary. +- When ahead of time (AOT) compilation is enabled (TODO), the WASM application could be either WASM or a compiled native binary. - + Build WAMR Core ========================= @@ -47,7 +50,7 @@ Please follow the instructions below to build the WAMR core on different platfor Linux ------------------------- First of all please install library dependencies of lib gcc. -Use installation commands below for Ubuntu Linux: +Use installation commands below for Ubuntu Linux: ``` Bash sudo apt install lib32gcc-5-dev sudo apt-get install g++-multilib @@ -78,17 +81,18 @@ ninja Build WASM app ========================= -A popular method to build out WASM binary is to use ```emcc```. -Assuming you are using Linux, please install emcc from Emscripten EMSDK following the steps below: +A popular method to build a WASM binary is to use ```emcc```. +Assuming you are using Linux, you may install emcc from Emscripten EMSDK following the steps below: ``` git clone https://github.com/emscripten-core/emsdk.git emsdk install latest emsdk activate latest ``` + add ```./emsdk_env.sh``` into the path to ease future use, or source it everytime. The Emscripten website provides other installation methods beyond Linux. -todo: user should copy the app-libs folder into project and include and build. +(TODO) The user should copy the app-libs folder into project and include and build. You can write a simple ```test.c``` as the first sample. ``` C @@ -143,12 +147,12 @@ ninja run Embed WAMR into software production ===================================== -WAMR can be built into a standalone executable which takes WASM application file name as input, and then execute it. To use it in the embedded environment, you should embed WAMR into your own software product. WASM provides a set of API's for embedded code to load WASM module, instantiate the module and invoke the WASM function from a native call. +WAMR can be built into a standalone executable which takes the WASM application file name as input, and then executes it. To use it in the embedded environment you should embed WAMR into your own software product. WASM provides a set of API's for embedded code to load the WASM module, instantiate the module and invoke a WASM function from a native call. -A typical WAMR API usage is as described below: +A typical WAMR API usage is shown below: ``` C wasm_module_t module; wasm_module_inst_t inst; @@ -171,12 +175,12 @@ A typical WAMR API usage is as described below: ``` -WASM application library +WASM application library ======================== -In general, there are 3 kinds of API's for programming the WASM application: -- Built-in API's: WAMR has already provided a minimal API set for developers. -- 3rd party API's: Programmer can download and include any 3rd party C source code, and add it into their own WASM app source tree. -- Platform native API's: WAMR provides a mechanism to export the native API to the WASM application. +In general, there are 3 classes of API's important for the WASM application: +- Built-in API's: WAMR provides a minimal API set for developers. +- 3rd party API's: Programmer can download and include any 3rd party C source code and add it into their own WASM app source tree. +- Platform native API's: WAMR provides a mechanism to export a native API to the WASM application. Built-in application library @@ -184,8 +188,7 @@ Built-in application library Built-in API's include Libc APIs, Base library and Extension library reference. **Libc APIs**
-This is the minimal Libc APIs like memory allocation and string copy etc. -The header file is ```lib/app-libs/libc/lib-base.h```. The API set is listed as below: +This is a minimal set of Libc APIs for memory allocation, string manipulation and printing. The header file is located at ```lib/app-libs/libc/lib-base.h```. The current supported API set is listed here: ``` C void *malloc(size_t size); void *calloc(size_t n, size_t size); @@ -206,8 +209,8 @@ char *strncpy(char *dest, const char *src, unsigned long n); ``` **Base library**
-The basic support for communication, timers etc is already available. You can refer to the header file ```lib/app-libs/base/wasm-app.h``` which contains the definitions for request and response API's, event pub/sub APIs and timer APIs. Please note that these API's require the native implementations. -The API set is listed as below: +Basic support for communication, timers, etc is available. You can refer to the header file ```lib/app-libs/base/wasm-app.h``` which contains the definitions for request and response API's, event pub/sub APIs and timer APIs. Please note that these API's require the native implementations. +The API set is listed below: ``` C typedef void(*request_handler_f)(request_t *) ; typedef void(*response_handler_f)(response_t *, void *) ; @@ -245,11 +248,12 @@ bool sensor_close(sensor_t sensor); The mechanism of exporting Native API to WASM application ======================================================= -The basic working flow for WASM application calling into the native API is described in the following diagram. +The basic working flow for WASM application calling into the native API is shown in the following diagram: + -WAMR provides the macro `EXPORT_WASM_API` to enable users to export native API to a WASM application. WAMR implemented a base API for the timer and messaging by using `EXPORT_WASM_API`. They can be a reference point for extending your own library. +WAMR provides the macro `EXPORT_WASM_API` to enable users to export a native API to a WASM application. WAMR has implemented a base API for the timer and messaging by using `EXPORT_WASM_API`. This can be a point of reference for extending your own library. ``` C static NativeSymbol extended_native_symbol_defs[] = { EXPORT_WASM_API(wasm_register_resource), @@ -263,12 +267,11 @@ static NativeSymbol extended_native_symbol_defs[] = { }; ``` - -![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** The WebAssembly application is supposed to access its own memory space, the integrator should carefully design the native function to ensure that the memory is safe. The native API to be exported to the WASM application must follow these rules: +![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** A WebAssembly application should only have access to its own memory space. As a result, the integrator should carefully design the native function to ensure that the memory accesses are safe. The native API to be exported to the WASM application must: - Only use 32 bits number for parameters -- Don't pass data to the structure pointer (do data serialization instead) -- Do the pointer address conversion in the native API -- Don’t pass function pointer as callback +- Should not pass data to the structure pointer (do data serialization instead) +- Should do the pointer address conversion in the native API +- Should not pass function pointer as callback Below is a sample of a library extension. All code invoked across WASM and native world must be serialized and de-serialized, and the native world must do a boundary check for every incoming address from the WASM world. @@ -338,8 +341,7 @@ static NativeSymbol extended_native_symbol_defs[] = ``` Use extended library ------------------------ -In the application source project, it will include the WAMR built-in APIs header file and platform extension header files. -This is assuming the board vendor extends the library which added an API called customized(). The WASM application would be like this: +In the application source project, it will include the WAMR built-in APIs header file and platform extension header files. Assuming the board vendor extends the library which added an API called customized(), the WASM application would be like this: ``` C #include #include "lib-export-dec.h" // provided by the platform vendor @@ -353,11 +355,10 @@ int main(int argc, char **argv) } ``` -Coming soon... +Future Goals ======================== -We are preparing the open source code for the application manager and related code samples like inter-application communication, application life cycle management, 2D graphic demo and more. This will get updated soon. +The application manager and related code samples like inter-application communication, application life cycle management, 2D graphic demo and more ... Submit issues and request ========================= [Click here to submit. Your feedback is always welcome!](https://github.com/intel/wasm-micro-runtime/issues/new) - From a595ec79ab9768775296bb299ace870763898e5a Mon Sep 17 00:00:00 2001 From: wenyongh Date: Tue, 14 May 2019 21:17:12 +0800 Subject: [PATCH 11/13] Fix code indent issue and 64-bit compiler error in libc wrapper src --- core/iwasm/lib/native/libc/libc_wrapper.c | 1113 +++++++++++---------- core/shared-lib/mem-alloc/ems/ems_kfc.c | 2 +- 2 files changed, 605 insertions(+), 510 deletions(-) diff --git a/core/iwasm/lib/native/libc/libc_wrapper.c b/core/iwasm/lib/native/libc/libc_wrapper.c index a0994a9c2..ce79fcbe6 100644 --- a/core/iwasm/lib/native/libc/libc_wrapper.c +++ b/core/iwasm/lib/native/libc/libc_wrapper.c @@ -21,12 +21,16 @@ void wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); + uint32 wasm_runtime_get_temp_ret(wasm_module_inst_t module); + void wasm_runtime_set_temp_ret(wasm_module_inst_t module, uint32 temp_ret); + uint32 wasm_runtime_get_llvm_stack(wasm_module_inst_t module); + void wasm_runtime_set_llvm_stack(wasm_module_inst_t module, uint32 llvm_stack); @@ -51,22 +55,34 @@ wasm_runtime_set_llvm_stack(wasm_module_inst_t module, uint32 llvm_stack); typedef int (*out_func_t)(int c, void *ctx); enum pad_type { - PAD_NONE, PAD_ZERO_BEFORE, PAD_SPACE_BEFORE, PAD_SPACE_AFTER, + PAD_NONE, + PAD_ZERO_BEFORE, + PAD_SPACE_BEFORE, + PAD_SPACE_AFTER, }; +typedef char *_va_list; +#define _INTSIZEOF(n) \ + ((sizeof(n) + 3) & ~3) +#define _va_arg(ap,t) \ + (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) + /** - * @brief Output an unsigned long in hex format + * @brief Output an unsigned int in hex format * - * Output an unsigned long on output installed by platform at init time. Should - * be able to handle an unsigned long of any size, 32 or 64 bit. + * Output an unsigned int on output installed by platform at init time. Should + * be able to handle an unsigned int of any size, 32 or 64 bit. * @param num Number to output * * @return N/A */ -static void _printf_hex_ulong(out_func_t out, void *ctx, - const unsigned long num, enum pad_type padding, int min_width) +static void +_printf_hex_uint(out_func_t out, void *ctx, + const uint64 num, bool is_u64, + enum pad_type padding, + int min_width) { - int size = sizeof(num) * 2; + int size = sizeof(num) * (is_u64 ? 2 : 1); int found_largest_digit = 0; int remaining = 8; /* 8 digits max */ int digits = 0; @@ -100,19 +116,22 @@ static void _printf_hex_ulong(out_func_t out, void *ctx, } /** - * @brief Output an unsigned long (32-bit) in decimal format + * @brief Output an unsigned int in decimal format * - * Output an unsigned long on output installed by platform at init time. Only + * Output an unsigned int on output installed by platform at init time. Only * works with 32-bit values. * @param num Number to output * * @return N/A */ -static void _printf_dec_ulong(out_func_t out, void *ctx, - const unsigned long num, enum pad_type padding, int min_width) +static void +_printf_dec_uint(out_func_t out, void *ctx, + const uint32 num, + enum pad_type padding, + int min_width) { - unsigned long pos = 999999999; - unsigned long remainder = num; + uint32 pos = 999999999; + uint32 remainder = num; int found_largest_digit = 0; int remaining = 10; /* 10 digits max */ int digits = 1; @@ -145,8 +164,17 @@ static void _printf_dec_ulong(out_func_t out, void *ctx, } } -static void _vprintf(out_func_t out, void *ctx, const char *fmt, va_list ap, - wasm_module_inst_t module_inst) +static void +print_err(out_func_t out, void *ctx) +{ + out('E', ctx); + out('R', ctx); + out('R', ctx); +} + +static void +_vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, + wasm_module_inst_t module_inst) { int might_format = 0; /* 1 if encountered a '%' */ enum pad_type padding = PAD_NONE; @@ -159,13 +187,15 @@ static void _vprintf(out_func_t out, void *ctx, const char *fmt, va_list ap, if (!might_format) { if (*fmt != '%') { out((int) *fmt, ctx); - } else { + } + else { might_format = 1; min_width = -1; padding = PAD_NONE; long_ctr = 0; } - } else { + } + else { switch (*fmt) { case '-': padding = PAD_SPACE_AFTER; @@ -199,630 +229,689 @@ static void _vprintf(out_func_t out, void *ctx, const char *fmt, va_list ap, case 'd': case 'i': { - long d; + int32 d; + if (long_ctr < 2) { - d = va_arg(ap, long); - } else { - d = (long)va_arg(ap, long long); + d = _va_arg(ap, int32); + } + else { + int64 lld = _va_arg(ap, int64); + if (lld > INT32_MAX || lld < INT32_MIN) { + print_err(out, ctx); + break; + } + d = (int32)lld; + } + + if (d < 0) { + out((int)'-', ctx); + d = -d; + min_width--; + } + _printf_dec_uint(out, ctx, d, padding, min_width); + break; + } + case 'u': { + uint32 u; + + if (long_ctr < 2) { + u = _va_arg(ap, uint32); + } + else { + uint64 llu = _va_arg(ap, uint64); + if (llu > INT32_MAX) { + print_err(out, ctx); + break; + } + u = (uint32)llu; + } + _printf_dec_uint(out, ctx, u, padding, min_width); + break; + } + case 'p': + out('0', ctx); + out('x', ctx); + /* left-pad pointers with zeros */ + padding = PAD_ZERO_BEFORE; + min_width = 8; + /* Fall through */ + case 'x': + case 'X': { + uint64 x; + bool is_ptr = (*fmt == 'p') ? true : false; + + if (long_ctr < 2) { + x = _va_arg(ap, uint32); + } else { + x = _va_arg(ap, uint64); + } + _printf_hex_uint(out, ctx, x, !is_ptr, padding, min_width); + break; + } + + case 's': { + char *s; + char *start; + int32 s_offset = _va_arg(ap, uint32); + + if (!validate_app_addr(s_offset, 1)) { + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return; + } + + s = start = addr_app_to_native(s_offset); + + while (*s) + out((int) (*s++), ctx); + + if (padding == PAD_SPACE_AFTER) { + int remaining = min_width - (s - start); + while (remaining-- > 0) { + out(' ', ctx); + } + } + break; + } + + case 'c': { + int c = _va_arg(ap, int); + out(c, ctx); + break; + } + + case '%': { + out((int) '%', ctx); + break; + } + + default: + out((int) '%', ctx); + out((int) *fmt, ctx); + break; + } + + might_format = 0; } - if (d < 0) { - out((int) '-', ctx); - d = -d; - min_width--; - } - _printf_dec_ulong(out, ctx, d, padding, min_width); - break; +still_might_format: + ++fmt; } - - case 'u': { - unsigned long u; - - if (long_ctr < 2) { - u = va_arg(ap, unsigned long); - } else { - u = (unsigned long)va_arg(ap, - unsigned long long); -} -_printf_dec_ulong(out, ctx, u, padding, min_width); -break; -} - -case 'p': -out('0', ctx); -out('x', ctx); -/* left-pad pointers with zeros */ -padding = PAD_ZERO_BEFORE; -min_width = 8; -/* Fall through */ -case 'x': -case 'X': { -unsigned long x; - -if (long_ctr < 2) { -x = va_arg(ap, unsigned long); -} else { -x = (unsigned long)va_arg(ap, unsigned long long); -} - -_printf_hex_ulong(out, ctx, x, padding, min_width); -break; -} - -case 's': { -char *s; -char *start; -int32 s_offset = va_arg(ap, uint32); - -if (!validate_app_addr(s_offset, 1)) { -wasm_runtime_set_exception(module_inst, "out of bounds memory access"); -return; -} - -s = start = addr_app_to_native(s_offset); - -while (*s) -out((int) (*s++), ctx); - -if (padding == PAD_SPACE_AFTER) { -int remaining = min_width - (s - start); -while (remaining-- > 0) { -out(' ', ctx); -} -} -break; -} - -case 'c': { -int c = va_arg(ap, int); -out(c, ctx); -break; -} - -case '%': { -out((int) '%', ctx); -break; -} - -default: -out((int) '%', ctx); -out((int) *fmt, ctx); -break; -} - -might_format = 0; -} - -still_might_format: ++fmt; -} } struct str_context { -char *str; -int max; -int count; + char *str; + int max; + int count; }; -static int sprintf_out(int c, struct str_context *ctx) +static int +sprintf_out(int c, struct str_context *ctx) { -if (!ctx->str || ctx->count >= ctx->max) { -ctx->count++; -return c; + if (!ctx->str || ctx->count >= ctx->max) { + ctx->count++; + return c; + } + + if (ctx->count == ctx->max - 1) { + ctx->str[ctx->count++] = '\0'; + } else { + ctx->str[ctx->count++] = c; + } + + return c; } -if (ctx->count == ctx->max - 1) { -ctx->str[ctx->count++] = '\0'; -} else { -ctx->str[ctx->count++] = c; -} - -return c; -} - -static int printf_out(int c, struct str_context *ctx) +static int +printf_out(int c, struct str_context *ctx) { -printf("%c", c); -ctx->count++; -return c; + printf("%c", c); + ctx->count++; + return c; } -static inline va_list get_va_list(uint32 *args) +static inline _va_list +get_va_list(uint32 *args) { -union { -uint32 u; -va_list v; -} u; -u.u = args[0]; -return u.v; + union { + uint32 u; + _va_list v; + } u; + u.u = args[0]; + return u.v; } -static bool parse_printf_args(wasm_module_inst_t module_inst, int32 fmt_offset, -int32 va_list_offset, const char **p_fmt, va_list *p_va_args) +static bool +parse_printf_args(wasm_module_inst_t module_inst, int32 fmt_offset, + int32 va_list_offset, const char **p_fmt, + _va_list *p_va_args) { -const char *fmt; -union { -uintptr_t u; -va_list v; -} u; + const char *fmt; + union { + uintptr_t u; + _va_list v; + } u; -if (!validate_app_addr(fmt_offset, -1) || !validate_app_addr(va_list_offset, sizeof(int32))) -return false; + if (!validate_app_addr(fmt_offset, 1) + || !validate_app_addr(va_list_offset, sizeof(int32))) + return false; -fmt = (const char*) addr_app_to_native(fmt_offset); -u.u = (uintptr_t) addr_app_to_native(va_list_offset); + fmt = (const char*) addr_app_to_native(fmt_offset); + u.u = (uintptr_t) addr_app_to_native(va_list_offset); -*p_fmt = fmt; -*p_va_args = u.v; -return true; + *p_fmt = fmt; + *p_va_args = u.v; + return true; } -static int _printf_wrapper(int32 fmt_offset, int32 va_list_offset) +static int +_printf_wrapper(int32 fmt_offset, int32 va_list_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -struct str_context ctx = { NULL, 0, 0 }; -const char *fmt; -va_list va_args; + wasm_module_inst_t module_inst = get_module_inst(); + struct str_context ctx = { NULL, 0, 0 }; + const char *fmt; + _va_list va_args; -if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) -return 0; + if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) + return 0; -_vprintf((out_func_t) printf_out, &ctx, fmt, va_args, module_inst); -return ctx.count; + _vprintf((out_func_t) printf_out, &ctx, fmt, va_args, module_inst); + return ctx.count; } -static int _sprintf_wrapper(int32 str_offset, int32 fmt_offset, -int32 va_list_offset) +static int +_sprintf_wrapper(int32 str_offset, int32 fmt_offset, int32 va_list_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -struct str_context ctx; -char *str; -const char *fmt; -va_list va_args; + wasm_module_inst_t module_inst = get_module_inst(); + struct str_context ctx; + char *str; + const char *fmt; + _va_list va_args; -if (!validate_app_addr(str_offset, 1)) -return 0; + if (!validate_app_addr(str_offset, 1)) + return 0; -str = addr_app_to_native(str_offset); + str = addr_app_to_native(str_offset); -if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) -return 0; + if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) + return 0; -ctx.str = str; -ctx.max = INT_MAX; -ctx.count = 0; + ctx.str = str; + ctx.max = INT_MAX; + ctx.count = 0; -_vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst); + _vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst); -if (ctx.count < ctx.max) { -str[ctx.count] = '\0'; + if (ctx.count < ctx.max) { + str[ctx.count] = '\0'; + } + + return ctx.count; } -return ctx.count; -} - -static int _snprintf_wrapper(int32 str_offset, int32 size, int32 fmt_offset, -int32 va_list_offset) +static int +_snprintf_wrapper(int32 str_offset, int32 size, int32 fmt_offset, + int32 va_list_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -struct str_context ctx; -char *str; -const char *fmt; -va_list va_args; + wasm_module_inst_t module_inst = get_module_inst(); + struct str_context ctx; + char *str; + const char *fmt; + _va_list va_args; -if (!validate_app_addr(str_offset, size)) -return 0; + if (!validate_app_addr(str_offset, size)) + return 0; -str = addr_app_to_native(str_offset); + str = addr_app_to_native(str_offset); -if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) -return 0; + if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) + return 0; -ctx.str = str; -ctx.max = size; -ctx.count = 0; + ctx.str = str; + ctx.max = size; + ctx.count = 0; -_vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst); + _vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst); -if (ctx.count < ctx.max) { -str[ctx.count] = '\0'; + if (ctx.count < ctx.max) { + str[ctx.count] = '\0'; + } + + return ctx.count; } -return ctx.count; -} - -static int _puts_wrapper(int32 str_offset) +static int +_puts_wrapper(int32 str_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -const char *str; + wasm_module_inst_t module_inst = get_module_inst(); + const char *str; -if (!validate_app_addr(str_offset, 1)) -return 0; + if (!validate_app_addr(str_offset, 1)) + return 0; -str = addr_app_to_native(str_offset); -return printf("%s\n", str); + str = addr_app_to_native(str_offset); + return printf("%s\n", str); } -static int _putchar_wrapper(int c) +static int +_putchar_wrapper(int c) { -printf("%c", c); -return 1; + printf("%c", c); + return 1; } -static int32 _strdup_wrapper(int32 str_offset) +static int32 +_strdup_wrapper(int32 str_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -char *str, *str_ret; -uint32 len; -int32 str_ret_offset = 0; + wasm_module_inst_t module_inst = get_module_inst(); + char *str, *str_ret; + uint32 len; + int32 str_ret_offset = 0; -if (!validate_app_addr(str_offset, 1)) -return 0; + if (!validate_app_addr(str_offset, 1)) + return 0; -str = addr_app_to_native(str_offset); + str = addr_app_to_native(str_offset); -if (str) { -len = strlen(str) + 1; + if (str) { + len = strlen(str) + 1; -str_ret_offset = module_malloc(len); -if (str_ret_offset) { -str_ret = addr_app_to_native(str_ret_offset); -memcpy(str_ret, str, len); -} + str_ret_offset = module_malloc(len); + if (str_ret_offset) { + str_ret = addr_app_to_native(str_ret_offset); + memcpy(str_ret, str, len); + } + } + + return str_ret_offset; } -return str_ret_offset; -} - -static int32 _memcmp_wrapper(int32 s1_offset, int32 s2_offset, int32 size) +static int32 +_memcmp_wrapper(int32 s1_offset, int32 s2_offset, int32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -void *s1, *s2; + wasm_module_inst_t module_inst = get_module_inst(); + void *s1, *s2; -if (!validate_app_addr(s1_offset, size) || !validate_app_addr(s2_offset, size)) -return 0; + if (!validate_app_addr(s1_offset, size) + || !validate_app_addr(s2_offset, size)) + return 0; -s1 = addr_app_to_native(s1_offset); -s2 = addr_app_to_native(s2_offset); -return memcmp(s1, s2, size); + s1 = addr_app_to_native(s1_offset); + s2 = addr_app_to_native(s2_offset); + return memcmp(s1, s2, size); } -static int32 _memcpy_wrapper(int32 dst_offset, int32 src_offset, int32 size) +static int32 +_memcpy_wrapper(int32 dst_offset, int32 src_offset, int32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -void *dst, *src; + wasm_module_inst_t module_inst = get_module_inst(); + void *dst, *src; -if (size == 0) -return dst_offset; + if (size == 0) + return dst_offset; -if (!validate_app_addr(dst_offset, size) || !validate_app_addr(src_offset, size)) -return dst_offset; + if (!validate_app_addr(dst_offset, size) + || !validate_app_addr(src_offset, size)) + return dst_offset; -dst = addr_app_to_native(dst_offset); -src = addr_app_to_native(src_offset); -memcpy(dst, src, size); -return dst_offset; + dst = addr_app_to_native(dst_offset); + src = addr_app_to_native(src_offset); + memcpy(dst, src, size); + return dst_offset; } -static int32 _memmove_wrapper(int32 dst_offset, int32 src_offset, int32 size) +static int32 +_memmove_wrapper(int32 dst_offset, int32 src_offset, int32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -void *dst, *src; + wasm_module_inst_t module_inst = get_module_inst(); + void *dst, *src; -if (!validate_app_addr(dst_offset, size) || !validate_app_addr(src_offset, size)) -return dst_offset; + if (!validate_app_addr(dst_offset, size) + || !validate_app_addr(src_offset, size)) + return dst_offset; -dst = addr_app_to_native(dst_offset); -src = addr_app_to_native(src_offset); -memmove(dst, src, size); -return dst_offset; + dst = addr_app_to_native(dst_offset); + src = addr_app_to_native(src_offset); + memmove(dst, src, size); + return dst_offset; } -static int32 _memset_wrapper(int32 s_offset, int32 c, int32 size) +static int32 +_memset_wrapper(int32 s_offset, int32 c, int32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -void *s; + wasm_module_inst_t module_inst = get_module_inst(); + void *s; -if (!validate_app_addr(s_offset, size)) -return s_offset; + if (!validate_app_addr(s_offset, size)) + return s_offset; -s = addr_app_to_native(s_offset); -memset(s, c, size); -return s_offset; + s = addr_app_to_native(s_offset); + memset(s, c, size); + return s_offset; } -static int32 _strchr_wrapper(int32 s_offset, int32 c) +static int32 +_strchr_wrapper(int32 s_offset, int32 c) { -wasm_module_inst_t module_inst = get_module_inst(); -const char *s; -char *ret; + wasm_module_inst_t module_inst = get_module_inst(); + const char *s; + char *ret; -if (!validate_app_addr(s_offset, 1)) -return s_offset; + if (!validate_app_addr(s_offset, 1)) + return s_offset; -s = addr_app_to_native(s_offset); -ret = strchr(s, c); -return ret ? addr_native_to_app(ret) : 0; + s = addr_app_to_native(s_offset); + ret = strchr(s, c); + return ret ? addr_native_to_app(ret) : 0; } -static int32 _strcmp_wrapper(int32 s1_offset, int32 s2_offset) +static int32 +_strcmp_wrapper(int32 s1_offset, int32 s2_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -void *s1, *s2; + wasm_module_inst_t module_inst = get_module_inst(); + void *s1, *s2; -if (!validate_app_addr(s1_offset, 1) || !validate_app_addr(s2_offset, 1)) -return 0; + if (!validate_app_addr(s1_offset, 1) + || !validate_app_addr(s2_offset, 1)) + return 0; -s1 = addr_app_to_native(s1_offset); -s2 = addr_app_to_native(s2_offset); -return strcmp(s1, s2); + s1 = addr_app_to_native(s1_offset); + s2 = addr_app_to_native(s2_offset); + return strcmp(s1, s2); } -static int32 _strncmp_wrapper(int32 s1_offset, int32 s2_offset, uint32 size) +static int32 +_strncmp_wrapper(int32 s1_offset, int32 s2_offset, uint32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -void *s1, *s2; + wasm_module_inst_t module_inst = get_module_inst(); + void *s1, *s2; -if (!validate_app_addr(s1_offset, size) || !validate_app_addr(s2_offset, size)) -return 0; + if (!validate_app_addr(s1_offset, size) + || !validate_app_addr(s2_offset, size)) + return 0; -s1 = addr_app_to_native(s1_offset); -s2 = addr_app_to_native(s2_offset); -return strncmp(s1, s2, size); + s1 = addr_app_to_native(s1_offset); + s2 = addr_app_to_native(s2_offset); + return strncmp(s1, s2, size); } -static int32 _strcpy_wrapper(int32 dst_offset, int32 src_offset) +static int32 +_strcpy_wrapper(int32 dst_offset, int32 src_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -char *dst, *src; + wasm_module_inst_t module_inst = get_module_inst(); + char *dst, *src; -if (!validate_app_addr(dst_offset, 1) || !validate_app_addr(src_offset, 1)) -return 0; + if (!validate_app_addr(dst_offset, 1) + || !validate_app_addr(src_offset, 1)) + return 0; -dst = addr_app_to_native(dst_offset); -src = addr_app_to_native(src_offset); -strcpy(dst, src); -return dst_offset; + dst = addr_app_to_native(dst_offset); + src = addr_app_to_native(src_offset); + strcpy(dst, src); + return dst_offset; } -static int32 _strncpy_wrapper(int32 dst_offset, int32 src_offset, uint32 size) +static int32 +_strncpy_wrapper(int32 dst_offset, int32 src_offset, uint32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -char *dst, *src; + wasm_module_inst_t module_inst = get_module_inst(); + char *dst, *src; -if (!validate_app_addr(dst_offset, size) || !validate_app_addr(src_offset, size)) -return 0; + if (!validate_app_addr(dst_offset, size) + || !validate_app_addr(src_offset, size)) + return 0; -dst = addr_app_to_native(dst_offset); -src = addr_app_to_native(src_offset); -strncpy(dst, src, size); -return dst_offset; + dst = addr_app_to_native(dst_offset); + src = addr_app_to_native(src_offset); + strncpy(dst, src, size); + return dst_offset; } -static uint32 _strlen_wrapper(int32 s_offset) +static uint32 +_strlen_wrapper(int32 s_offset) { -wasm_module_inst_t module_inst = get_module_inst(); -char *s; + wasm_module_inst_t module_inst = get_module_inst(); + char *s; -if (!validate_app_addr(s_offset, 1)) -return 0; + if (!validate_app_addr(s_offset, 1)) + return 0; -s = addr_app_to_native(s_offset); -return strlen(s); + s = addr_app_to_native(s_offset); + return strlen(s); } -static int32 _malloc_wrapper(uint32 size) +static int32 +_malloc_wrapper(uint32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -return module_malloc(size); + wasm_module_inst_t module_inst = get_module_inst(); + return module_malloc(size); } -static int32 _calloc_wrapper(uint32 nmemb, uint32 size) +static int32 +_calloc_wrapper(uint32 nmemb, uint32 size) { -uint64 total_size = (uint64) nmemb * (uint64) size; -wasm_module_inst_t module_inst = get_module_inst(); -uint32 ret_offset = 0; -uint8 *ret_ptr; + uint64 total_size = (uint64) nmemb * (uint64) size; + wasm_module_inst_t module_inst = get_module_inst(); + uint32 ret_offset = 0; + uint8 *ret_ptr; -if (total_size > UINT32_MAX) -total_size = UINT32_MAX; + if (total_size > UINT32_MAX) + total_size = UINT32_MAX; -ret_offset = module_malloc((uint32 )total_size); -if (ret_offset) { -ret_ptr = addr_app_to_native(ret_offset); -memset(ret_ptr, 0, (uint32) total_size); + ret_offset = module_malloc((uint32 )total_size); + if (ret_offset) { + ret_ptr = addr_app_to_native(ret_offset); + memset(ret_ptr, 0, (uint32) total_size); + } + + return ret_offset; } -return ret_offset; -} - -static void _free_wrapper(int32 ptr_offset) +static void +_free_wrapper(int32 ptr_offset) { -wasm_module_inst_t module_inst = get_module_inst(); + wasm_module_inst_t module_inst = get_module_inst(); -if (!validate_app_addr(ptr_offset, 4)) -return; -return module_free(ptr_offset); + if (!validate_app_addr(ptr_offset, 4)) + return; + return module_free(ptr_offset); } -static void setTempRet0_wrapper(uint32 temp_ret) +static void +setTempRet0_wrapper(uint32 temp_ret) { -wasm_module_inst_t module_inst = get_module_inst(); -wasm_runtime_set_temp_ret(module_inst, temp_ret); + wasm_module_inst_t module_inst = get_module_inst(); + wasm_runtime_set_temp_ret(module_inst, temp_ret); } -static uint32 getTempRet0_wrapper() +static uint32 +getTempRet0_wrapper() { -wasm_module_inst_t module_inst = get_module_inst(); -return wasm_runtime_get_temp_ret(module_inst); + wasm_module_inst_t module_inst = get_module_inst(); + return wasm_runtime_get_temp_ret(module_inst); } -static uint32 _llvm_bswap_i16_wrapper(uint32 data) +static uint32 +_llvm_bswap_i16_wrapper(uint32 data) { -return (data & 0xFFFF0000) | ((data & 0xFF) << 8) | ((data & 0xFF00) >> 8); + return (data & 0xFFFF0000) + | ((data & 0xFF) << 8) + | ((data & 0xFF00) >> 8); } -static uint32 _llvm_bswap_i32_wrapper(uint32 data) +static uint32 +_llvm_bswap_i32_wrapper(uint32 data) { -return ((data & 0xFF) << 24) | ((data & 0xFF00) << 8) | ((data & 0xFF0000) >> 8) -| ((data & 0xFF000000) >> 24); + return ((data & 0xFF) << 24) + | ((data & 0xFF00) << 8) + | ((data & 0xFF0000) >> 8) + | ((data & 0xFF000000) >> 24); } -static uint32 _bitshift64Lshr_wrapper(uint32 uint64_part0, uint32 uint64_part1, -uint32 bits) +static uint32 +_bitshift64Lshr_wrapper(uint32 uint64_part0, uint32 uint64_part1, + uint32 bits) { -wasm_module_inst_t module_inst = get_module_inst(); -union { -uint64 value; -uint32 parts[2]; -} u; + wasm_module_inst_t module_inst = get_module_inst(); + union { + uint64 value; + uint32 parts[2]; + } u; -u.parts[0] = uint64_part0; -u.parts[1] = uint64_part1; + u.parts[0] = uint64_part0; + u.parts[1] = uint64_part1; -u.value >>= bits; -/* return low 32bit and save high 32bit to temp ret */ -wasm_runtime_set_temp_ret(module_inst, (uint32) (u.value >> 32)); -return (uint32) u.value; + u.value >>= bits; + /* return low 32bit and save high 32bit to temp ret */ + wasm_runtime_set_temp_ret(module_inst, (uint32) (u.value >> 32)); + return (uint32) u.value; } -static uint32 _bitshift64Shl_wrapper(uint32 int64_part0, uint32 int64_part1, -uint32 bits) +static uint32 +_bitshift64Shl_wrapper(uint32 int64_part0, uint32 int64_part1, + uint32 bits) { -wasm_module_inst_t module_inst = get_module_inst(); -union { -int64 value; -uint32 parts[2]; -} u; + wasm_module_inst_t module_inst = get_module_inst(); + union { + int64 value; + uint32 parts[2]; + } u; -u.parts[0] = int64_part0; -u.parts[1] = int64_part1; + u.parts[0] = int64_part0; + u.parts[1] = int64_part1; -u.value <<= bits; -/* return low 32bit and save high 32bit to temp ret */ -wasm_runtime_set_temp_ret(module_inst, (uint32) (u.value >> 32)); -return (uint32) u.value; + u.value <<= bits; + /* return low 32bit and save high 32bit to temp ret */ + wasm_runtime_set_temp_ret(module_inst, (uint32) (u.value >> 32)); + return (uint32) u.value; } -static void _llvm_stackrestore_wrapper(uint32 llvm_stack) +static void +_llvm_stackrestore_wrapper(uint32 llvm_stack) { -wasm_module_inst_t module_inst = get_module_inst(); -printf("_llvm_stackrestore called!\n"); -wasm_runtime_set_llvm_stack(module_inst, llvm_stack); + wasm_module_inst_t module_inst = get_module_inst(); + printf("_llvm_stackrestore called!\n"); + wasm_runtime_set_llvm_stack(module_inst, llvm_stack); } -static uint32 _llvm_stacksave_wrapper() +static uint32 +_llvm_stacksave_wrapper() { -wasm_module_inst_t module_inst = get_module_inst(); -printf("_llvm_stacksave called!\n"); -return wasm_runtime_get_llvm_stack(module_inst); + wasm_module_inst_t module_inst = get_module_inst(); + printf("_llvm_stacksave called!\n"); + return wasm_runtime_get_llvm_stack(module_inst); } -static int32 _emscripten_memcpy_big_wrapper(int32 dst_offset, int32 src_offset, -uint32 size) +static int32 +_emscripten_memcpy_big_wrapper(int32 dst_offset, int32 src_offset, + uint32 size) { -wasm_module_inst_t module_inst = get_module_inst(); -void *dst, *src; + wasm_module_inst_t module_inst = get_module_inst(); + void *dst, *src; -if (!validate_app_addr(dst_offset, size) || !validate_app_addr(src_offset, size)) -return dst_offset; + if (!validate_app_addr(dst_offset, size) + || !validate_app_addr(src_offset, size)) + return dst_offset; -dst = addr_app_to_native(dst_offset); -src = addr_app_to_native(src_offset); + dst = addr_app_to_native(dst_offset); + src = addr_app_to_native(src_offset); -memcpy(dst, src, size); -return dst_offset; + memcpy(dst, src, size); + return dst_offset; } -static void abort_wrapper(int32 code) +static void +abort_wrapper(int32 code) { -wasm_module_inst_t module_inst = get_module_inst(); -char buf[32]; -snprintf(buf, sizeof(buf), "env.abort(%i)", code); -wasm_runtime_set_exception(module_inst, buf); + wasm_module_inst_t module_inst = get_module_inst(); + char buf[32]; + snprintf(buf, sizeof(buf), "env.abort(%i)", code); + wasm_runtime_set_exception(module_inst, buf); } -static void abortStackOverflow_wrapper(int32 code) +static void +abortStackOverflow_wrapper(int32 code) { -wasm_module_inst_t module_inst = get_module_inst(); -char buf[32]; -snprintf(buf, sizeof(buf), "env.abortStackOverflow(%i)", code); -wasm_runtime_set_exception(module_inst, buf); + wasm_module_inst_t module_inst = get_module_inst(); + char buf[32]; + snprintf(buf, sizeof(buf), "env.abortStackOverflow(%i)", code); + wasm_runtime_set_exception(module_inst, buf); } -static void nullFunc_X_wrapper(int32 code) +static void +nullFunc_X_wrapper(int32 code) { -wasm_module_inst_t module_inst = get_module_inst(); -char buf[32]; -snprintf(buf, sizeof(buf), "env.nullFunc_X(%i)", code); -wasm_runtime_set_exception(module_inst, buf); + wasm_module_inst_t module_inst = get_module_inst(); + char buf[32]; + snprintf(buf, sizeof(buf), "env.nullFunc_X(%i)", code); + wasm_runtime_set_exception(module_inst, buf); } /* TODO: add function parameter/result types check */ -#define REG_NATIVE_FUNC(module_name, func_name) \ - {#module_name, #func_name, func_name##_wrapper} +#define REG_NATIVE_FUNC(module_name, func_name) \ + { #module_name, #func_name, func_name##_wrapper } typedef struct WASMNativeFuncDef { -const char *module_name; -const char *func_name; -void *func_ptr; + const char *module_name; + const char *func_name; + void *func_ptr; } WASMNativeFuncDef; static WASMNativeFuncDef native_func_defs[] = { -REG_NATIVE_FUNC(env, _printf), -REG_NATIVE_FUNC(env, _sprintf), -REG_NATIVE_FUNC(env, _snprintf), -REG_NATIVE_FUNC(env, _puts), -REG_NATIVE_FUNC(env, _putchar), -REG_NATIVE_FUNC(env, _memcmp), -REG_NATIVE_FUNC(env, _memcpy), -REG_NATIVE_FUNC(env, _memmove), -REG_NATIVE_FUNC(env, _memset), -REG_NATIVE_FUNC(env, _strchr), -REG_NATIVE_FUNC(env, _strcmp), -REG_NATIVE_FUNC(env, _strcpy), -REG_NATIVE_FUNC(env, _strlen), -REG_NATIVE_FUNC(env, _strncmp), -REG_NATIVE_FUNC(env, _strncpy), -REG_NATIVE_FUNC(env, _malloc), -REG_NATIVE_FUNC(env, _calloc), -REG_NATIVE_FUNC(env, _strdup), -REG_NATIVE_FUNC(env, _free), -REG_NATIVE_FUNC(env, setTempRet0), -REG_NATIVE_FUNC(env, getTempRet0), -REG_NATIVE_FUNC(env, _llvm_bswap_i16), -REG_NATIVE_FUNC(env, _llvm_bswap_i32), -REG_NATIVE_FUNC(env, _bitshift64Lshr), -REG_NATIVE_FUNC(env, _bitshift64Shl), -REG_NATIVE_FUNC(env, _llvm_stackrestore), -REG_NATIVE_FUNC(env, _llvm_stacksave), -REG_NATIVE_FUNC(env, _emscripten_memcpy_big), -REG_NATIVE_FUNC(env, abort), -REG_NATIVE_FUNC(env, abortStackOverflow), -REG_NATIVE_FUNC(env, nullFunc_X), }; + REG_NATIVE_FUNC(env, _printf), + REG_NATIVE_FUNC(env, _sprintf), + REG_NATIVE_FUNC(env, _snprintf), + REG_NATIVE_FUNC(env, _puts), + REG_NATIVE_FUNC(env, _putchar), + REG_NATIVE_FUNC(env, _memcmp), + REG_NATIVE_FUNC(env, _memcpy), + REG_NATIVE_FUNC(env, _memmove), + REG_NATIVE_FUNC(env, _memset), + REG_NATIVE_FUNC(env, _strchr), + REG_NATIVE_FUNC(env, _strcmp), + REG_NATIVE_FUNC(env, _strcpy), + REG_NATIVE_FUNC(env, _strlen), + REG_NATIVE_FUNC(env, _strncmp), + REG_NATIVE_FUNC(env, _strncpy), + REG_NATIVE_FUNC(env, _malloc), + REG_NATIVE_FUNC(env, _calloc), + REG_NATIVE_FUNC(env, _strdup), + REG_NATIVE_FUNC(env, _free), + REG_NATIVE_FUNC(env, setTempRet0), + REG_NATIVE_FUNC(env, getTempRet0), + REG_NATIVE_FUNC(env, _llvm_bswap_i16), + REG_NATIVE_FUNC(env, _llvm_bswap_i32), + REG_NATIVE_FUNC(env, _bitshift64Lshr), + REG_NATIVE_FUNC(env, _bitshift64Shl), + REG_NATIVE_FUNC(env, _llvm_stackrestore), + REG_NATIVE_FUNC(env, _llvm_stacksave), + REG_NATIVE_FUNC(env, _emscripten_memcpy_big), + REG_NATIVE_FUNC(env, abort), + REG_NATIVE_FUNC(env, abortStackOverflow), + REG_NATIVE_FUNC(env, nullFunc_X) +}; void* wasm_native_func_lookup(const char *module_name, const char *func_name) { -uint32 size = sizeof(native_func_defs) / sizeof(WASMNativeFuncDef); -WASMNativeFuncDef *func_def = native_func_defs; -WASMNativeFuncDef *func_def_end = func_def + size; -void *ret; + uint32 size = sizeof(native_func_defs) / sizeof(WASMNativeFuncDef); + WASMNativeFuncDef *func_def = native_func_defs; + WASMNativeFuncDef *func_def_end = func_def + size; + void *ret; -if (!module_name || !func_name) -return NULL; + if (!module_name || !func_name) + return NULL; -while (func_def < func_def_end) { -if (!strcmp(func_def->module_name, module_name) -&& !strcmp(func_def->func_name, func_name)) -return (void*) (uintptr_t) func_def->func_ptr; -func_def++; -} + while (func_def < func_def_end) { + if (!strcmp(func_def->module_name, module_name) + && !strcmp(func_def->func_name, func_name)) + return (void*) (uintptr_t) func_def->func_ptr; + func_def++; + } -if ((ret = wasm_platform_native_func_lookup(module_name, func_name))) -return ret; + if ((ret = wasm_platform_native_func_lookup(module_name, func_name))) + return ret; -return NULL; + return NULL; } /************************************* @@ -830,64 +919,70 @@ return NULL; *************************************/ typedef struct WASMNativeGlobalDef { -const char *module_name; -const char *global_name; -WASMValue global_data; + const char *module_name; + const char *global_name; + WASMValue global_data; } WASMNativeGlobalDef; -static WASMNativeGlobalDef native_global_defs[] = { { "env", "STACKTOP", -.global_data.u32 = 0 }, { "env", "STACK_MAX", .global_data.u32 = 0 }, { "env", -"ABORT", .global_data.u32 = 0 }, { "env", "memoryBase", .global_data.u32 = 0 }, -{ "env", "__memory_base", .global_data.u32 = 0 }, { "env", "tableBase", -.global_data.u32 = 0 }, { "env", "__table_base", .global_data.u32 = 0 }, { -"env", "DYNAMICTOP_PTR", .global_data.addr = 0 }, { "env", "tempDoublePtr", -.global_data.addr = 0 }, { "global", "NaN", .global_data.u64 = -0x7FF8000000000000LL }, { "global", "Infinity", .global_data.u64 = -0x7FF0000000000000LL }, }; +static WASMNativeGlobalDef native_global_defs[] = { + { "env", "STACKTOP", .global_data.u32 = 0 }, + { "env", "STACK_MAX", .global_data.u32 = 0 }, + { "env", "ABORT", .global_data.u32 = 0 }, + { "env", "memoryBase", .global_data.u32 = 0 }, + { "env", "__memory_base", .global_data.u32 = 0 }, + { "env", "tableBase", .global_data.u32 = 0 }, + { "env", "__table_base", .global_data.u32 = 0 }, + { "env", "DYNAMICTOP_PTR", .global_data.addr = 0 }, + { "env", "tempDoublePtr", .global_data.addr = 0 }, + { "global", "NaN", .global_data.u64 = 0x7FF8000000000000LL }, + { "global", "Infinity", .global_data.u64 = 0x7FF0000000000000LL } +}; -bool wasm_native_global_lookup(const char *module_name, const char *global_name, -WASMGlobalImport *global) +bool +wasm_native_global_lookup(const char *module_name, const char *global_name, + WASMGlobalImport *global) { -uint32 size = sizeof(native_global_defs) / sizeof(WASMNativeGlobalDef); -WASMNativeGlobalDef *global_def = native_global_defs; -WASMNativeGlobalDef *global_def_end = global_def + size; + uint32 size = sizeof(native_global_defs) / sizeof(WASMNativeGlobalDef); + WASMNativeGlobalDef *global_def = native_global_defs; + WASMNativeGlobalDef *global_def_end = global_def + size; -if (!module_name || !global_name || !global) -return false; + if (!module_name || !global_name || !global) + return false; -/* Lookup constant globals which can be defined by table */ -while (global_def < global_def_end) { -if (!strcmp(global_def->module_name, module_name) -&& !strcmp(global_def->global_name, global_name)) { -global->global_data_linked = global_def->global_data; -return true; -} -global_def++; + /* Lookup constant globals which can be defined by table */ + while (global_def < global_def_end) { + if (!strcmp(global_def->module_name, module_name) + && !strcmp(global_def->global_name, global_name)) { + global->global_data_linked = global_def->global_data; + return true; + } + global_def++; + } + + /* Lookup non-constant globals which cannot be defined by table */ + if (!strcmp(module_name, "env")) { + if (!strcmp(global_name, "_stdin")) { + global->global_data_linked.addr = (uintptr_t)stdin; + global->is_addr = true; + return true; + } else if (!strcmp(global_name, "_stdout")) { + global->global_data_linked.addr = (uintptr_t)stdout; + global->is_addr = true; + return true; + } else if (!strcmp(global_name, "_stderr")) { + global->global_data_linked.addr = (uintptr_t)stderr; + global->is_addr = true; + return true; + } + } + + return false; } -/* Lookup non-constant globals which cannot be defined by table */ -if (!strcmp(module_name, "env")) { -if (!strcmp(global_name, "_stdin")) { -global->global_data_linked.addr = (uintptr_t) stdin; -global->is_addr = true; -return true; -} else if (!strcmp(global_name, "_stdout")) { -global->global_data_linked.addr = (uintptr_t) stdout; -global->is_addr = true; -return true; -} else if (!strcmp(global_name, "_stderr")) { -global->global_data_linked.addr = (uintptr_t) stderr; -global->is_addr = true; -return true; -} -} - -return false; -} - -bool wasm_native_init() +bool +wasm_native_init() { -/* TODO: qsort the function defs and global defs. */ -return true; + /* TODO: qsort the function defs and global defs. */ + return true; } diff --git a/core/shared-lib/mem-alloc/ems/ems_kfc.c b/core/shared-lib/mem-alloc/ems/ems_kfc.c index 10fe090ad..791a298a5 100644 --- a/core/shared-lib/mem-alloc/ems/ems_kfc.c +++ b/core/shared-lib/mem-alloc/ems/ems_kfc.c @@ -44,7 +44,7 @@ int gci_check_platform() CHECK(1, sizeof(gc_int8)); CHECK(1, sizeof(gc_uint8)); CHECK(4, sizeof(gc_size_t)); - CHECK(4, sizeof(void *)); + /*CHECK(4, sizeof(void *));*/ return GC_SUCCESS; } From 40e7c627aa4e8cf97d5d7efe8d00897b3d920da2 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Wed, 15 May 2019 14:32:35 +0800 Subject: [PATCH 12/13] implement printf syscall wrapper for linux --- .../runtime/platform/linux/wasm-native.c | 39 ++++++++++++------- core/shared-lib/mem-alloc/ems/ems_alloc.c | 4 +- core/shared-lib/platform/linux/bh_thread.c | 2 +- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/core/iwasm/runtime/platform/linux/wasm-native.c b/core/iwasm/runtime/platform/linux/wasm-native.c index b24ac184e..fad5ad71e 100644 --- a/core/iwasm/runtime/platform/linux/wasm-native.c +++ b/core/iwasm/runtime/platform/linux/wasm-native.c @@ -109,31 +109,44 @@ __syscall3_wrapper(int32 arg0, int32 arg1, int32 arg2, int32 arg3) return syscall(54, arg1, arg2, wsz); } - case 145: /* readv */ case 146: /* writev */ { /* Implement syscall 54 and syscall 146 to support printf() for non SIDE_MODULE=1 mode */ - uint32 iovcnt = arg3, i; - struct iovec *vec_begin, *vec; + struct iovec_app { + int32 iov_base_offset; + uint32 iov_len; + } *vec; + int32 vec_offset = arg2, str_offset; + uint32 iov_count = arg3, i; + int32 count = 0; + char *iov_base, *str; - if (!validate_app_addr(arg2, sizeof(struct iovec))) + if (!validate_app_addr(vec_offset, sizeof(struct iovec_app))) return 0; - vec_begin = vec = (struct iovec*)addr_app_to_native(arg2); - for (i = 0; i < iovcnt; i++, vec++) { + vec = (struct iovec_app *)addr_app_to_native(vec_offset); + for (i = 0; i < iov_count; i++, vec++) { if (vec->iov_len > 0) { - if (!validate_app_addr((int32)vec->iov_base, 1)) + if (!validate_app_addr(vec->iov_base_offset, 1)) return 0; - vec->iov_base = addr_app_to_native((int32)vec->iov_base); + iov_base = (char*)addr_app_to_native(vec->iov_base_offset); + + if (!(str_offset = module_malloc(vec->iov_len + 1))) + return 0; + + str = addr_app_to_native(str_offset); + + memcpy(str, iov_base, vec->iov_len); + str[vec->iov_len] = '\0'; + count += wasm_printf("%s", str); + + module_free(str_offset); } } - if (arg0 == 145) - return syscall(145, arg1, vec_begin, arg3); - else - return syscall(146, arg1, vec_begin, arg3); + return count; } - + case 145: /* readv */ case 3: /* read*/ case 5: /* open */ case 221: /* fcntl */ diff --git a/core/shared-lib/mem-alloc/ems/ems_alloc.c b/core/shared-lib/mem-alloc/ems/ems_alloc.c index d8682b6c7..44cfee32a 100644 --- a/core/shared-lib/mem-alloc/ems/ems_alloc.c +++ b/core/shared-lib/mem-alloc/ems/ems_alloc.c @@ -152,7 +152,7 @@ void gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) bh_assert( hmu && (gc_uint8*) hmu >= heap->base_addr && (gc_uint8*) hmu < heap->base_addr + heap->current_size); - bh_assert(((gc_uint32) hmu_to_obj(hmu) & 7) == 0); + bh_assert(((gc_uint32)(uintptr_t)hmu_to_obj(hmu) & 7) == 0); bh_assert( size > 0 && ((gc_uint8*) hmu) + size @@ -242,7 +242,7 @@ BH_STATIC hmu_t *alloc_hmu(gc_heap_t *heap, gc_size_t size) p = node->next; node->next = p->next; - bh_assert(((gc_int32) hmu_to_obj(p) & 7) == 0); + bh_assert(((gc_int32)(intptr_t)hmu_to_obj(p) & 7) == 0); if ((gc_size_t) node_idx != init_node_idx&& ((gc_size_t)node_idx << 3) >= size + GC_SMALLEST_SIZE) { /* with bigger size*/ diff --git a/core/shared-lib/platform/linux/bh_thread.c b/core/shared-lib/platform/linux/bh_thread.c index 9d45b147f..d291cbe98 100755 --- a/core/shared-lib/platform/linux/bh_thread.c +++ b/core/shared-lib/platform/linux/bh_thread.c @@ -75,7 +75,7 @@ static void *vm_thread_wrapper(void *arg) { thread_wrapper_arg * targ = arg; LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ); - targ->stack = (void *) ((unsigned int) (&arg) & ~0xfff); + targ->stack = (void *) ((uintptr_t)(&arg) & ~0xfff); _vm_tls_put(1, targ); targ->start(targ->arg); bh_free(targ); From dd5b133fa55fe496ed99a83a67821f734072a521 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Fri, 17 May 2019 17:15:25 +0800 Subject: [PATCH 13/13] Import app manager, samples and test-tools --- README.md | 260 +- core/app-mgr/app-manager/CMakeLists.txt | 28 + core/app-mgr/app-manager/app_manager.c | 406 +++ core/app-mgr/app-manager/app_manager.h | 107 + core/app-mgr/app-manager/app_manager_host.c | 303 ++ core/app-mgr/app-manager/app_manager_host.h | 35 + core/app-mgr/app-manager/app_mgr.cmake | 23 + core/app-mgr/app-manager/ble_msg.c | 126 + core/app-mgr/app-manager/coding_rule.txt | 15 + core/app-mgr/app-manager/event.c | 203 ++ core/app-mgr/app-manager/event.h | 52 + core/app-mgr/app-manager/message.c | 98 + core/app-mgr/app-manager/module_config.h | 34 + core/app-mgr/app-manager/module_jeff.c | 1744 +++++++++++ core/app-mgr/app-manager/module_jeff.h | 40 + core/app-mgr/app-manager/module_utils.c | 226 ++ core/app-mgr/app-manager/module_wasm_app.c | 992 ++++++ core/app-mgr/app-manager/module_wasm_app.h | 95 + core/app-mgr/app-manager/module_wasm_lib.c | 59 + core/app-mgr/app-manager/module_wasm_lib.h | 32 + .../platform/linux/app_mgr_linux.c | 54 + .../platform/zephyr/app_mgr_zephyr.c | 72 + core/app-mgr/app-manager/resource_reg.c | 214 ++ core/app-mgr/app-manager/watchdog.c | 140 + core/app-mgr/app-manager/watchdog.h | 49 + .../app-mgr-shared/app_manager_export.h | 300 ++ .../app-mgr-shared/app_mgr_shared.cmake | 23 + core/app-mgr/app-mgr-shared/host_link.h | 42 + core/app-mgr/module.json | 53 + core/iwasm/app-samples/smart-light/build.sh | 17 + core/iwasm/app-samples/smart-light/main.c | 67 + core/iwasm/lib/app-libs/base/bh_platform.c | 2 +- core/iwasm/lib/app-libs/base/request.c | 14 +- core/iwasm/lib/app-libs/base/wasm_app.h | 2 +- .../lib/app-libs/extension/sensor/sensor.c | 4 +- .../lib/app-libs/extension/sensor/sensor.h | 2 +- .../app-libs/libc/{lib-base.h => lib_base.h} | 0 .../{attr-container.c => attr_container.c} | 4 +- .../{attr-container.h => attr_container.h} | 0 .../lib/native-interface/restful_utils.c | 14 +- .../{base-lib-export.c => base_lib_export.c} | 4 +- .../{base-lib-export.h => base_lib_export.h} | 2 +- core/iwasm/lib/native/base/request_response.c | 6 +- core/iwasm/lib/native/base/timer_wrapper.c | 2 +- .../native/extension/sensor/runtime_sensor.c | 4 +- .../native/extension/sensor/runtime_sensor.h | 2 +- .../native/extension/sensor/sensor_mgr_ref.c | 11 +- ...xport-template.c => lib_export_template.c} | 0 core/iwasm/lib/native/libc/libc_wrapper.c | 8 +- core/iwasm/products/linux/CMakeLists.txt | 8 +- .../ext_lib_export.c} | 4 +- core/iwasm/products/linux/main.c | 2 +- .../products/zephyr/simple/CMakeLists.txt | 18 +- .../simple/src/ext_lib_export.c} | 4 +- core/iwasm/products/zephyr/simple/src/main.c | 2 +- core/iwasm/readme.txt | 75 + .../{ext-lib-export.h => ext_lib_export.h} | 2 +- .../include/{lib-export.h => lib_export.h} | 0 .../include/{wasm-export.h => wasm_export.h} | 0 .../include/{wasm_thread.h => wa_thread.h} | 6 +- .../linux/{wasm-native.c => wasm_native.c} | 4 +- .../iwasm/runtime/platform/zephyr/wasm_math.c | 688 ++--- .../zephyr/{wasm-native.c => wasm_native.c} | 2 +- .../invokeNative_general.c | 2 +- .../invokeNative_ia32.s | 0 .../{vmcore_wasm => vmcore-wasm}/vmcore.cmake | 0 .../{vmcore_wasm => vmcore-wasm}/wasm.h | 0 .../wasm_application.c} | 6 +- .../wasm_interp.c} | 10 +- .../wasm_interp.h} | 0 .../wasm_loader.c} | 13 +- .../wasm_loader.h} | 0 .../wasm_native.h} | 0 .../wasm_opcode.h} | 0 .../wasm_runtime.c} | 10 +- .../wasm_runtime.h} | 2 +- .../wasm_thread.h} | 2 +- core/shared-lib/coap/LICENSE | 38 + core/shared-lib/coap/Makefile | 19 + core/shared-lib/coap/er-coap/Makefile | 15 + core/shared-lib/coap/er-coap/er-coap-conf.h | 75 + .../coap/er-coap/er-coap-constants.h | 161 + core/shared-lib/coap/er-coap/er-coap.c | 1131 +++++++ core/shared-lib/coap/er-coap/er-coap.h | 370 +++ core/shared-lib/coap/extension/Makefile | 15 + .../coap/extension/coap_conversion.c | 105 + core/shared-lib/coap/extension/coap_ext.h | 57 + .../shared-lib/coap/extension/coap_over_tcp.c | 481 +++ .../coap/extension/coap_platforms.h | 89 + core/shared-lib/coap/lib_coap.cmake | 23 + core/shared-lib/include/bni.h | 236 ++ core/shared-lib/include/jeff_export.h | 615 ++++ core/shared-lib/mem-alloc/ems/ems_alloc.c | 4 +- core/shared-lib/platform/linux/bh_thread.c | 2 +- core/shared-lib/utils/runtime_timer.c | 3 - doc/pics/architecture_extend.PNG | Bin 223241 -> 78440 bytes doc/pics/safe.PNG | Bin 153483 -> 67786 bytes doc/pics/vgl.PNG | Bin 0 -> 49192 bytes doc/pics/vgl2.PNG | Bin 0 -> 82855 bytes doc/pics/vgl_linux.PNG | Bin 0 -> 25976 bytes doc/pics/workflow.PNG | Bin 201495 -> 68967 bytes samples/littlevgl/LICENCE.txt | 8 + samples/littlevgl/README.md | 113 + samples/littlevgl/build.sh | 69 + .../vgl-native-ui-app/CMakeLists.txt | 143 + .../vgl-native-ui-app/CMakeLists.txt.in | 29 + .../vgl-native-ui-app/lv-drivers/.gitignore | 1 + .../lv-drivers/display_indev.h | 33 + .../lv-drivers/indev/mouse.c | 95 + .../lv-drivers/indev/mouse.h | 72 + .../lv-drivers/linux_display_indev.c | 314 ++ .../vgl-native-ui-app/lv-drivers/lv_conf.h | 389 +++ .../lv-drivers/system_header.h | 19 + samples/littlevgl/vgl-native-ui-app/main.c | 165 + .../littlevgl/vgl-wasm-runtime/CMakeLists.txt | 93 + .../vgl-wasm-runtime/src/display_indev.h | 74 + .../vgl-wasm-runtime/src/ext_lib_export.c | 14 + .../src/platform/linux/display_indev.c | 341 ++ .../src/platform/linux/iwasm_main.c | 467 +++ .../src/platform/linux/main.c | 20 + .../src/platform/linux/mouse.c | 96 + .../src/platform/zephyr/LICENSE | 202 ++ .../src/platform/zephyr/XPT2046.c | 336 ++ .../src/platform/zephyr/XPT2046.h | 93 + .../src/platform/zephyr/board_config.h | 20 + .../src/platform/zephyr/display.h | 405 +++ .../src/platform/zephyr/display_ili9340.c | 264 ++ .../src/platform/zephyr/display_ili9340.h | 68 + .../zephyr/display_ili9340_adafruit_1480.c | 79 + .../src/platform/zephyr/display_indev.c | 119 + .../src/platform/zephyr/iwasm_main.c | 113 + .../src/platform/zephyr/main.c | 37 + .../src/platform/zephyr/pin_config_jlf.h | 37 + .../src/platform/zephyr/pin_config_stm32.h | 41 + .../zephyr-build/CMakeLists.txt | 118 + .../vgl-wasm-runtime/zephyr-build/prj.conf | 7 + samples/littlevgl/wasm-apps/Makefile_wasm_app | 55 + samples/littlevgl/wasm-apps/build_wasm_app.sh | 20 + .../littlevgl/wasm-apps/src/display_indev.h | 33 + samples/littlevgl/wasm-apps/src/lv_conf.h | 389 +++ samples/littlevgl/wasm-apps/src/main.c | 165 + .../littlevgl/wasm-apps/src/system_header.h | 19 + samples/simple/CMakeLists.txt | 95 + samples/simple/README.md | 323 ++ samples/simple/build.sh | 102 + samples/simple/src/ext_lib_export.c | 8 + samples/simple/src/iwasm_main.c | 465 +++ samples/simple/src/main.c | 5 + .../event_publisher/event_publisher.c | 57 + .../event_subscriber/event_subscriber.c | 36 + .../request_handler/request_handler.c | 67 + .../wasm-apps/request_sender/request_sender.c | 58 + samples/simple/wasm-apps/sensor/sensor.c | 59 + samples/simple/wasm-apps/timer/timer.c | 41 + test-tools/host-tool/CMakeLists.txt | 71 + test-tools/host-tool/external/cJSON/LICENSE | 20 + test-tools/host-tool/external/cJSON/cJSON.c | 2750 +++++++++++++++++ test-tools/host-tool/external/cJSON/cJSON.h | 281 ++ .../host-tool/external/cJSON/cjson.cmake | 10 + test-tools/host-tool/src/host_tool_utils.c | 311 ++ test-tools/host-tool/src/host_tool_utils.h | 83 + test-tools/host-tool/src/main.c | 930 ++++++ test-tools/host-tool/src/transport.c | 261 ++ test-tools/host-tool/src/transport.h | 122 + 164 files changed, 21123 insertions(+), 496 deletions(-) create mode 100644 core/app-mgr/app-manager/CMakeLists.txt create mode 100644 core/app-mgr/app-manager/app_manager.c create mode 100644 core/app-mgr/app-manager/app_manager.h create mode 100644 core/app-mgr/app-manager/app_manager_host.c create mode 100644 core/app-mgr/app-manager/app_manager_host.h create mode 100644 core/app-mgr/app-manager/app_mgr.cmake create mode 100644 core/app-mgr/app-manager/ble_msg.c create mode 100644 core/app-mgr/app-manager/coding_rule.txt create mode 100644 core/app-mgr/app-manager/event.c create mode 100644 core/app-mgr/app-manager/event.h create mode 100644 core/app-mgr/app-manager/message.c create mode 100644 core/app-mgr/app-manager/module_config.h create mode 100644 core/app-mgr/app-manager/module_jeff.c create mode 100644 core/app-mgr/app-manager/module_jeff.h create mode 100644 core/app-mgr/app-manager/module_utils.c create mode 100644 core/app-mgr/app-manager/module_wasm_app.c create mode 100644 core/app-mgr/app-manager/module_wasm_app.h create mode 100644 core/app-mgr/app-manager/module_wasm_lib.c create mode 100644 core/app-mgr/app-manager/module_wasm_lib.h create mode 100644 core/app-mgr/app-manager/platform/linux/app_mgr_linux.c create mode 100644 core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c create mode 100644 core/app-mgr/app-manager/resource_reg.c create mode 100644 core/app-mgr/app-manager/watchdog.c create mode 100644 core/app-mgr/app-manager/watchdog.h create mode 100644 core/app-mgr/app-mgr-shared/app_manager_export.h create mode 100644 core/app-mgr/app-mgr-shared/app_mgr_shared.cmake create mode 100644 core/app-mgr/app-mgr-shared/host_link.h create mode 100644 core/app-mgr/module.json create mode 100755 core/iwasm/app-samples/smart-light/build.sh create mode 100644 core/iwasm/app-samples/smart-light/main.c rename core/iwasm/lib/app-libs/libc/{lib-base.h => lib_base.h} (100%) rename core/iwasm/lib/native-interface/{attr-container.c => attr_container.c} (99%) rename core/iwasm/lib/native-interface/{attr-container.h => attr_container.h} (100%) rename core/iwasm/lib/native/base/{base-lib-export.c => base_lib_export.c} (96%) rename core/iwasm/lib/native/base/{base-lib-export.h => base_lib_export.h} (96%) rename core/iwasm/lib/native/extension/template/{lib-export-template.c => lib_export_template.c} (100%) rename core/iwasm/products/{zephyr/simple/src/ext-lib-export.c => linux/ext_lib_export.c} (92%) rename core/iwasm/products/{linux/ext-lib-export.c => zephyr/simple/src/ext_lib_export.c} (92%) create mode 100644 core/iwasm/readme.txt rename core/iwasm/runtime/include/{ext-lib-export.h => ext_lib_export.h} (97%) rename core/iwasm/runtime/include/{lib-export.h => lib_export.h} (100%) rename core/iwasm/runtime/include/{wasm-export.h => wasm_export.h} (100%) rename core/iwasm/runtime/platform/include/{wasm_thread.h => wa_thread.h} (94%) rename core/iwasm/runtime/platform/linux/{wasm-native.c => wasm_native.c} (99%) rename core/iwasm/runtime/platform/zephyr/{wasm-native.c => wasm_native.c} (96%) rename core/iwasm/runtime/{vmcore_wasm => vmcore-wasm}/invokeNative_general.c (99%) rename core/iwasm/runtime/{vmcore_wasm => vmcore-wasm}/invokeNative_ia32.s (100%) rename core/iwasm/runtime/{vmcore_wasm => vmcore-wasm}/vmcore.cmake (100%) rename core/iwasm/runtime/{vmcore_wasm => vmcore-wasm}/wasm.h (100%) rename core/iwasm/runtime/{vmcore_wasm/wasm-application.c => vmcore-wasm/wasm_application.c} (99%) rename core/iwasm/runtime/{vmcore_wasm/wasm-interp.c => vmcore-wasm/wasm_interp.c} (99%) rename core/iwasm/runtime/{vmcore_wasm/wasm-interp.h => vmcore-wasm/wasm_interp.h} (100%) rename core/iwasm/runtime/{vmcore_wasm/wasm-loader.c => vmcore-wasm/wasm_loader.c} (99%) rename core/iwasm/runtime/{vmcore_wasm/wasm-loader.h => vmcore-wasm/wasm_loader.h} (100%) rename core/iwasm/runtime/{vmcore_wasm/wasm-native.h => vmcore-wasm/wasm_native.h} (100%) rename core/iwasm/runtime/{vmcore_wasm/wasm-opcode.h => vmcore-wasm/wasm_opcode.h} (100%) rename core/iwasm/runtime/{vmcore_wasm/wasm-runtime.c => vmcore-wasm/wasm_runtime.c} (99%) rename core/iwasm/runtime/{vmcore_wasm/wasm-runtime.h => vmcore-wasm/wasm_runtime.h} (99%) rename core/iwasm/runtime/{vmcore_wasm/wasm-thread.h => vmcore-wasm/wasm_thread.h} (99%) create mode 100644 core/shared-lib/coap/LICENSE create mode 100644 core/shared-lib/coap/Makefile create mode 100644 core/shared-lib/coap/er-coap/Makefile create mode 100755 core/shared-lib/coap/er-coap/er-coap-conf.h create mode 100755 core/shared-lib/coap/er-coap/er-coap-constants.h create mode 100755 core/shared-lib/coap/er-coap/er-coap.c create mode 100755 core/shared-lib/coap/er-coap/er-coap.h create mode 100644 core/shared-lib/coap/extension/Makefile create mode 100644 core/shared-lib/coap/extension/coap_conversion.c create mode 100755 core/shared-lib/coap/extension/coap_ext.h create mode 100755 core/shared-lib/coap/extension/coap_over_tcp.c create mode 100755 core/shared-lib/coap/extension/coap_platforms.h create mode 100644 core/shared-lib/coap/lib_coap.cmake create mode 100644 core/shared-lib/include/bni.h create mode 100755 core/shared-lib/include/jeff_export.h create mode 100644 doc/pics/vgl.PNG create mode 100644 doc/pics/vgl2.PNG create mode 100644 doc/pics/vgl_linux.PNG create mode 100644 samples/littlevgl/LICENCE.txt create mode 100644 samples/littlevgl/README.md create mode 100755 samples/littlevgl/build.sh create mode 100644 samples/littlevgl/vgl-native-ui-app/CMakeLists.txt create mode 100644 samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/lv_conf.h create mode 100644 samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h create mode 100644 samples/littlevgl/vgl-native-ui-app/main.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/display_indev.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h create mode 100644 samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt create mode 100644 samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf create mode 100644 samples/littlevgl/wasm-apps/Makefile_wasm_app create mode 100755 samples/littlevgl/wasm-apps/build_wasm_app.sh create mode 100644 samples/littlevgl/wasm-apps/src/display_indev.h create mode 100644 samples/littlevgl/wasm-apps/src/lv_conf.h create mode 100644 samples/littlevgl/wasm-apps/src/main.c create mode 100644 samples/littlevgl/wasm-apps/src/system_header.h create mode 100644 samples/simple/CMakeLists.txt create mode 100644 samples/simple/README.md create mode 100755 samples/simple/build.sh create mode 100644 samples/simple/src/ext_lib_export.c create mode 100644 samples/simple/src/iwasm_main.c create mode 100644 samples/simple/src/main.c create mode 100644 samples/simple/wasm-apps/event_publisher/event_publisher.c create mode 100644 samples/simple/wasm-apps/event_subscriber/event_subscriber.c create mode 100644 samples/simple/wasm-apps/request_handler/request_handler.c create mode 100644 samples/simple/wasm-apps/request_sender/request_sender.c create mode 100644 samples/simple/wasm-apps/sensor/sensor.c create mode 100644 samples/simple/wasm-apps/timer/timer.c create mode 100644 test-tools/host-tool/CMakeLists.txt create mode 100644 test-tools/host-tool/external/cJSON/LICENSE create mode 100644 test-tools/host-tool/external/cJSON/cJSON.c create mode 100644 test-tools/host-tool/external/cJSON/cJSON.h create mode 100644 test-tools/host-tool/external/cJSON/cjson.cmake create mode 100644 test-tools/host-tool/src/host_tool_utils.c create mode 100644 test-tools/host-tool/src/host_tool_utils.h create mode 100644 test-tools/host-tool/src/main.c create mode 100644 test-tools/host-tool/src/transport.c create mode 100644 test-tools/host-tool/src/transport.h diff --git a/README.md b/README.md index 7a3691313..eb14fcaab 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ WebAssembly Micro Runtime ========================= -WebAssembly Micro Runtime (WAMR) is standalone WebAssembly (WASM) runtime designed for a small footprint. It includes: +WebAssembly Micro Runtime (WAMR) is a standalone WebAssembly (WASM) runtime designed for a small footprint. It includes: - A WebAssembly (WASM) VM core - The supporting APIs for the WASM applications (code is available but compilation depends on the app manager component) - A mechanism for dynamic management of the WASM application (Not available on Github yet. To be released soon) -Why should you use a WASM runtime out of your browser? There are a few points where this might be meaningful: -1. WASM is already a LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage compared to language bound runtimes like JS or Lua. -2. WASM is an open standard and it is fast becoming supported by the whole web ecosystem. -3. WASM is designed to be very friendly for compiling to native binaries and gaining the native speed. -4. It can potentially change the development practices. Imagine we can do both the WASM application development and validation in a browser, then just download the WASM binary code onto the target device. -5. WASM can work without garbage collection. It is designed to support execution determinics for the time sensitive requirement. -6. Maintain the safety goals WASM has of providing a sandboxed execution enviornment for untrusted code. In addition, because WASM is a compilation target, this implies a benefit of being able to target both an execution and security profile that is consistent across popular high-level programming languages. +Why should you use a WASM runtime out of your browser? There are a few points where this might be meaningful: +1. WASM is already an LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage compared to language bound runtimes like JS or Lua. +2. WASM is an open standard and it is fast becoming supported by the whole web ecosystem. +3. WASM is designed to be very friendly for compiling to native binaries and gaining the native speed. +4. It can potentially change the development practices. Imagine we can do both the WASM application development and validation in a browser, then just download the WASM binary code onto the target device. +5. WASM can work without garbage collection. It is designed to support execution determinics for the time sensitive requirement. +6. Maintain the safety goals WASM has of providing a sandboxed execution environment for untrusted code. In addition, because WASM is a compilation target, this implies a benefit of being able to target both an execution and security profile that is consistent across popular high-level programming languages. @@ -24,7 +24,7 @@ Current Features of WAMR - Provides a mechanism for exporting native API's to WASM applications - Supports the programming of firmware apps in a large range of languages (C/C++/Java/Rust/Go/TypeScript etc.) - App sandbox execution environment on embedded OS -- Purely asynchronized programming model +- The purely asynchronized programming model - Menu configuration for easy platform integration - Supports micro-service and pub-sub event inter-app communication models - Easy to extend to support remote FW application management from host or cloud @@ -35,7 +35,7 @@ The application manager component handles the packets that the platform receives - The WebAssembly runtime provides the execution environment for WASM applications. -- The messaging layer can support the API for WASM applications to communicate to each other and also the host environment. +- The messaging layer can support the API for WASM applications to communicate with each other and also the host environment. - When ahead of time (AOT) compilation is enabled (TODO), the WASM application could be either WASM or a compiled native binary. @@ -88,12 +88,9 @@ git clone https://github.com/emscripten-core/emsdk.git emsdk install latest emsdk activate latest ``` - -add ```./emsdk_env.sh``` into the path to ease future use, or source it everytime. +add ```./emsdk_env.sh``` into the path to ease future use, or source it every time. The Emscripten website provides other installation methods beyond Linux. -(TODO) The user should copy the app-libs folder into project and include and build. - You can write a simple ```test.c``` as the first sample. ``` C #include @@ -101,23 +98,23 @@ You can write a simple ```test.c``` as the first sample. int main(int argc, char **argv) { - char *buf; + char *buf; - printf("Hello world!\n"); + printf("Hello world!\n"); - buf = malloc(1024); - if (!buf) { - printf("malloc buf failed\n"); - return -1; - } + buf = malloc(1024); + if (!buf) { + printf("malloc buf failed\n"); + return -1; + } - printf("buf ptr: %p\n", buf); + printf("buf ptr: %p\n", buf); - sprintf(buf, "%s", "1234\n"); - printf("buf: %s", buf); + sprintf(buf, "%s", "1234\n"); + printf("buf: %s", buf); - free(buf); - return 0; + free(buf); + return 0; } ``` Use the emcc command below to build the WASM C source code into the WASM binary. @@ -147,31 +144,43 @@ ninja run Embed WAMR into software production ===================================== -WAMR can be built into a standalone executable which takes the WASM application file name as input, and then executes it. To use it in the embedded environment you should embed WAMR into your own software product. WASM provides a set of API's for embedded code to load the WASM module, instantiate the module and invoke a WASM function from a native call. +WAMR can be built into a standalone executable which takes the WASM application file name as input, and then executes it. To use it in the embedded environment you should embed WAMR into your own software product. WASM provides a set of APIs for embedded code to load the WASM module, instantiate the module and invoke a WASM function from a native call. -A typical WAMR API usage is shown below: +A typical WAMR API usage is shown below (some return values checking are ignored): ``` C + static char global_heap_buf[512 * 1024]; + + char *buffer; wasm_module_t module; wasm_module_inst_t inst; wasm_function_inst_t func; wasm_exec_env_t env; + uint32 argv[2]; + + bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)); wasm_runtime_init(); + + buffer = read_wasm_binary_to_buffer(…); module = wasm_runtime_load(buffer, size, err, err_size); - inst = wasm_runtime_instantiate(module, 0, err, err_size); - func = wasm_runtime_lookup_function(inst, "fib", "(i32i32"); + inst = wasm_runtime_instantiate(module, 0, 0, err, err_size); + func = wasm_runtime_lookup_function(inst, "fib", "(i32)i32"); env = wasm_runtime_create_exec_env(stack_size); + argv[0] = 8; if (!wasm_runtime_call_wasm(inst, env, func, 1, argv_buf) ) { - wasm_runtime_clear_exception(inst); - } + wasm_runtime_clear_exception(inst); + } + /* the return value is stored in argv[0] */ + printf(“fib function return: %d\n”, argv[0]); wasm_runtime_destory_exec_env(env); wasm_runtime_deinstantiate(inst); wasm_runtime_unload(module); wasm_runtime_destroy(); + bh_memory_destroy(); ``` @@ -188,7 +197,7 @@ Built-in application library Built-in API's include Libc APIs, Base library and Extension library reference. **Libc APIs**
-This is a minimal set of Libc APIs for memory allocation, string manipulation and printing. The header file is located at ```lib/app-libs/libc/lib-base.h```. The current supported API set is listed here: +This is a minimal set of Libc APIs for memory allocation, string manipulation and printing. The header file is located at ```lib/app-libs/libc/lib_base.h```. The current supported API set is listed here: ``` C void *malloc(size_t size); void *calloc(size_t n, size_t size); @@ -209,7 +218,7 @@ char *strncpy(char *dest, const char *src, unsigned long n); ``` **Base library**
-Basic support for communication, timers, etc is available. You can refer to the header file ```lib/app-libs/base/wasm-app.h``` which contains the definitions for request and response API's, event pub/sub APIs and timer APIs. Please note that these API's require the native implementations. +Basic support for communication, timers, etc is available. You can refer to the header file ```lib/app-libs/base/wasm_app.h``` which contains the definitions for request and response API's, event pub/sub APIs and timer APIs. Please note that these API's require the native implementations. The API set is listed below: ``` C typedef void(*request_handler_f)(request_t *) ; @@ -245,7 +254,7 @@ bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg); bool sensor_close(sensor_t sensor); ``` -The mechanism of exporting Native API to WASM application +The mechanism of exporting native API to WASM application ======================================================= The basic working flow for WASM application calling into the native API is shown in the following diagram: @@ -256,14 +265,14 @@ The basic working flow for WASM application calling into the native API is shown WAMR provides the macro `EXPORT_WASM_API` to enable users to export a native API to a WASM application. WAMR has implemented a base API for the timer and messaging by using `EXPORT_WASM_API`. This can be a point of reference for extending your own library. ``` C static NativeSymbol extended_native_symbol_defs[] = { - EXPORT_WASM_API(wasm_register_resource), - EXPORT_WASM_API(wasm_response_send), - EXPORT_WASM_API(wasm_post_request), - EXPORT_WASM_API(wasm_sub_event), - EXPORT_WASM_API(wasm_create_timer), - EXPORT_WASM_API(wasm_timer_set_interval), - EXPORT_WASM_API(wasm_timer_cancel), - EXPORT_WASM_API(wasm_timer_restart) + EXPORT_WASM_API(wasm_register_resource), + EXPORT_WASM_API(wasm_response_send), + EXPORT_WASM_API(wasm_post_request), + EXPORT_WASM_API(wasm_sub_event), + EXPORT_WASM_API(wasm_create_timer), + EXPORT_WASM_API(wasm_timer_set_interval), + EXPORT_WASM_API(wasm_timer_cancel), + EXPORT_WASM_API(wasm_timer_restart) }; ``` @@ -286,15 +295,15 @@ WAMR implemented a framework for developers to export API's. Below is the proced Declare the API's for your WASM application source project to include. **Step 2. Create a source file**
-Export the platform API's, for example in ``` products/linux/ext-lib-export.c ``` +Export the platform API's, for example in ``` products/linux/ext_lib_export.c ``` ``` C -#include "lib-export.h" +#include "lib_export.h" static NativeSymbol extended_native_symbol_defs[] = { }; -#include "ext-lib-export.h" +#include "ext_lib_export.h" ``` **Step 3. Register new APIs**
@@ -305,15 +314,16 @@ The pre-defined MACRO `EXPORT_WASM_API` should be used to declare a function exp ``` Below code example shows how to extend the library to support `customized()`: -``` C -//lib-export-impl.c + +``` +//lib_export_impl.c void customized() { // your code } -// lib-export-dec.h +// lib_export_dec.h #ifndef _LIB_EXPORT_DEC_H_ #define _LIB_EXPORT_DEC_H_ #ifdef __cplusplus @@ -328,36 +338,162 @@ void customized(); #endif -// ext-lib-export.c -#include "lib-export.h" -#include "lib-export-dec.h" +// ext_lib_export.c +#include "lib_export.h" +#include "lib_export_dec.h" static NativeSymbol extended_native_symbol_defs[] = { - EXPORT_WASM_API(customized) + EXPORT_WASM_API(customized) }; -#include "ext-lib-export.h" +#include "ext_lib_export.h" ``` + Use extended library ------------------------ In the application source project, it will include the WAMR built-in APIs header file and platform extension header files. Assuming the board vendor extends the library which added an API called customized(), the WASM application would be like this: ``` C #include -#include "lib-export-dec.h" // provided by the platform vendor +#include "lib_export_dec.h" // provided by the platform vendor int main(int argc, char **argv) { - int I; - char *buf = “abcd”; - customized(); // customized API provided by the platform vendor - return i; + int I; + char *buf = “abcd”; + customized(); // customized API provided by the platform vendor + return i; } ``` -Future Goals -======================== -The application manager and related code samples like inter-application communication, application life cycle management, 2D graphic demo and more ... + +Communication programming models +========================= +WAMR supports two typical communication programming models, the microservice model and the pub/sub model. + + +Microservice model +------------------------- +The microservice model is also known as request and response model. One WASM application acts as the server which provides a specific service. Other WASM applications or host/cloud applications request that service and get the response. + + +Below is the reference implementation of the server application. It provides room temperature measurement service. + +``` C +void on_init() +{ + /* register resource uri */ + init_resource_register(); + api_register_resource_handler("/room_temp", room_temp_handler); +} + +void on_destroy() +{ +} + +void room_temp_handler(request_t *request) +{ + response_t response[1]; + attr_container_t *payload; + payload = attr_container_create("room_temp payload"); + if (payload == NULL) + return; + + attr_container_set_string(&payload, "temp unit", "centigrade"); + attr_container_set_int(&payload, "value", 26); + + make_response_for_request(request, response); + set_response(response, + CONTENT_2_05, + FMT_ATTR_CONTAINER, + payload, + attr_container_get_serialize_length(payload)); + + api_response_send(response); + attr_container_destroy(payload); +} +``` + + +Pub/sub model +------------------------- +One WASM application acts as the event publisher. It publishes events to notify WASM applications or host/cloud applications which subscribe to the events. + + + +Below is the reference implementation of the pub application. It utilizes a timer to repeatedly publish an overheat alert event to the subscriber applications. Then the subscriber applications receive the events immediately. + +``` C +void on_init( +{ + api_subscribe_event ("alert/overheat", overheat_handler); +} + +void on_destroy() +{ +} + +void overheat_handler(request_t *event +{ + printf(“Event: %s\n", event->url); +} + +/* Timer callback */ +void timer_update(user_timer_t timer +{ + attr_container_t *event; + printf("Timer update %d\n", num++); + + event = attr_container_create("event"); + attr_container_set_string(&event, + "warning", + "temperature is over high"); + + api_publish_event("alert/overheat", + FMT_ATTR_CONTAINER, + event, + attr_container_get_serialize_length(event)); + + attr_container_destroy(event); +} + +void on_init() +{ + user_timer_t timer; + timer = api_timer_create(1000, true, true, timer_update); +} +``` + +Samples and demos +========================= +The simple sample +-------- +Please refer to the ```samples/simple``` folder for samples of WASM application life cyle management and programming models. + +2D graphic user interface with LittlevGL +------------------------------------------------ +This sample demonstrates that a graphic user interface application in WebAssembly integrates the LittlevGL, an open-source embedded 2d graphic library. The sample source code is under ```samples/littlevgl``` + +In this sample, the LittlevGL source code is built into the WebAssembly code with the user application source files. The platform interfaces defined by LittlevGL is implemented in the runtime and exported to the application through the declarations from source "ext_lib_export.c" as below: + + EXPORT_WASM_API(display_init), + EXPORT_WASM_API(display_input_read), + EXPORT_WASM_API(display_flush), + EXPORT_WASM_API(display_fill), + EXPORT_WASM_API(display_vdb_write), + EXPORT_WASM_API(display_map), + EXPORT_WASM_API(time_get_ms), }; + +The runtime component supports building target for Linux and Zephyr/STM Nucleo board respectively. The beauty of this sample is the WebAssembly application can have identical display and behavior when running from both runtime environments. That implies we can do majority of application validation from desktop environment then load it to the target device as long as two runtime distributions support the same set of application interface. + + +Below pictures show the WASM application is running on an STM board with an LCD touch panel. When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. + + + +The sample also provides the native Linux version of application without the runtime under folder "vgl-native-ui-app". It can help to check differences between the implementations in native and WebAssembly. + + Submit issues and request ========================= diff --git a/core/app-mgr/app-manager/CMakeLists.txt b/core/app-mgr/app-manager/CMakeLists.txt new file mode 100644 index 000000000..ef2d49c9b --- /dev/null +++ b/core/app-mgr/app-manager/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include_directories (. + include + platform/include + platform/${PLATFORM} + ../classlib/include + utils/coap/er-coap + utils/coap/extension + ../external/iwasm/include) + + +file (GLOB_RECURSE source_all ../../app-manager/*.c) + +add_library (appmgrlib ${source_all}) + diff --git a/core/app-mgr/app-manager/app_manager.c b/core/app-mgr/app-manager/app_manager.c new file mode 100644 index 000000000..6aca1659a --- /dev/null +++ b/core/app-mgr/app-manager/app_manager.c @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app_manager.h" +#include "app_manager_host.h" +#include "bh_queue.h" +#include "bh_memory.h" +#include "bh_thread.h" +#include "attr_container.h" +#include "event.h" +#include "watchdog.h" +#include "coap_ext.h" + +/* Queue of app manager */ +static bh_queue *g_app_mgr_queue; + +void* +get_app_manager_queue() +{ + return g_app_mgr_queue; +} + +void app_manager_post_applets_update_event() +{ + module_data *m_data; + attr_container_t *attr_cont; + request_t msg; + int num = 0, i = 0; + char *url = "/applets"; + + if (!event_is_registered(url)) + return; + + if (!(attr_cont = attr_container_create("All Applets"))) { + app_manager_printf( + "Post applets update event failed: allocate memory failed."); + return; + } + + vm_mutex_lock(&module_data_list_lock); + + m_data = module_data_list; + while (m_data) { + num++; + m_data = m_data->next; + } + + if (!(attr_container_set_int(&attr_cont, "num", num))) { + app_manager_printf( + "Post applets update event failed: set attr container key failed."); + goto fail; + } + + m_data = module_data_list; + while (m_data) { + char buf[32]; + i++; + snprintf(buf, sizeof(buf), "%s%d", "applet", i); + if (!(attr_container_set_string(&attr_cont, buf, m_data->module_name))) { + app_manager_printf( + "Post applets update event failed: set attr applet name key failed."); + goto fail; + } + snprintf(buf, sizeof(buf), "%s%d", "heap", i); + if (!(attr_container_set_int(&attr_cont, buf, m_data->heap_size))) { + app_manager_printf( + "Post applets update event failed: set attr heap key failed."); + goto fail; + } + m_data = m_data->next; + } + + memset(&msg, 0, sizeof(msg)); + msg.url = url; + msg.action = COAP_EVENT; + msg.payload = (char*) attr_cont; + send_request_to_host(&msg); + + app_manager_printf("Post applets update event success!\n"); + attr_container_dump(attr_cont); + + fail: vm_mutex_unlock(&module_data_list_lock); + attr_container_destroy(attr_cont); +} + +static int get_applets_count() +{ + module_data *m_data; + int num = 0; + + vm_mutex_lock(&module_data_list_lock); + + m_data = module_data_list; + while (m_data) { + num++; + m_data = m_data->next; + } + + vm_mutex_unlock(&module_data_list_lock); + + return num; +} + +/* Query fw apps info if name = NULL, otherwise query specify app */ +static bool app_manager_query_applets(request_t *msg, const char *name) +{ + module_data *m_data; + attr_container_t *attr_cont; + int num = 0, i = 0, len; + bool ret = false, found = false; + response_t response[1] = { 0 }; + + attr_cont = attr_container_create("Applets Info"); + if (!attr_cont) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applets failed: allocate memory failed."); + return false; + } + + vm_mutex_lock(&module_data_list_lock); + + m_data = module_data_list; + while (m_data) { + num++; + m_data = m_data->next; + } + + if (name == NULL && !(attr_container_set_int(&attr_cont, "num", num))) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applets failed: set attr container key failed."); + goto fail; + } + + m_data = module_data_list; + while (m_data) { + char buf[32]; + + if (name == NULL) { + i++; + snprintf(buf, sizeof(buf), "%s%d", "applet", i); + if (!(attr_container_set_string(&attr_cont, buf, + m_data->module_name))) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applets failed: set attr container key failed."); + goto fail; + } + snprintf(buf, sizeof(buf), "%s%d", "heap", i); + if (!(attr_container_set_int(&attr_cont, buf, m_data->heap_size))) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applets failed: set attr container heap key failed."); + goto fail; + } + } else if (!strcmp(name, m_data->module_name)) { + found = true; + if (!(attr_container_set_string(&attr_cont, "name", + m_data->module_name))) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applet failed: set attr container key failed."); + goto fail; + } + if (!(attr_container_set_int(&attr_cont, "heap", m_data->heap_size))) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applet failed: set attr container heap key failed."); + goto fail; + } + } + + m_data = m_data->next; + } + + if (name != NULL && !found) { + SEND_ERR_RESPONSE(msg->mid, + "Query Applet failed: the app is not found."); + goto fail; + } + + len = attr_container_get_serialize_length(attr_cont); + + make_response_for_request(msg, response); + set_response(response, CONTENT_2_05, + FMT_ATTR_CONTAINER, (char*) attr_cont, len); + send_response_to_host(response); + + ret = true; + app_manager_printf("Query Applets success!\n"); + attr_container_dump(attr_cont); + + fail: vm_mutex_unlock(&module_data_list_lock); + attr_container_destroy(attr_cont); + return ret; +} + +void applet_mgt_reqeust_handler(request_t *request, void *unused) +{ + bh_message_t msg; + /* deep copy, but not use app self heap, but use global heap */ + request_t *req = clone_request(request); + + if (!req) + return; + + msg = bh_new_msg(RESTFUL_REQUEST, req, sizeof(*req), request_cleaner); + if (!msg) { + request_cleaner(req); + return; + } + + bh_post_msg2(get_app_manager_queue(), msg); +} + +/* return -1 for error */ +static int get_module_type(char *kv_str) +{ + int module_type = -1; + char type_str[8] = { 0 }; + + find_key_value(kv_str, strlen(kv_str), "type", type_str, + sizeof(type_str) - 1, '&'); + + if (strlen(type_str) == 0) + module_type = Module_WASM_App; + else if (strcmp(type_str, "jeff") == 0) + module_type = Module_Jeff; + else if (strcmp(type_str, "wasm") == 0) + module_type = Module_WASM_App; + else if (strcmp(type_str, "wasmlib") == 0) + module_type = Module_WASM_Lib; + + return module_type; +} + +#define APP_NAME_MAX_LEN 128 + +/* Queue callback of App Manager */ + +static void app_manager_queue_callback(void *message) +{ + request_t *request = (request_t *) bh_message_payload((bh_message_t)message); + int mid = request->mid, module_type, offset; + + if ((offset = check_url_start(request->url, strlen(request->url), "/applet")) + > 0) { + module_type = get_module_type(request->url + offset); + + if (module_type == -1) { + SEND_ERR_RESPONSE(mid, + "Applet Management failed: invalid module type."); + goto fail; + } + + /* Install Applet */ + if (request->action == COAP_PUT) { + if (get_applets_count() >= MAX_APP_INSTALLATIONS) { + SEND_ERR_RESPONSE(mid, + "Install Applet failed: exceed max app installations."); + goto fail; + } + + if (!request->payload) { + SEND_ERR_RESPONSE(mid, + "Install Applet failed: invalid payload."); + goto fail; + } + if (g_module_interfaces[module_type] + && g_module_interfaces[module_type]->module_install) { + if (!g_module_interfaces[module_type]->module_install(request)) + goto fail; + } + } + /* Uninstall Applet */ + else if (request->action == COAP_DELETE) { + module_type = get_module_type(request->url + offset); + if (module_type == -1) { + SEND_ERR_RESPONSE(mid, + "Uninstall Applet failed: invalid module type."); + goto fail; + } + + if (g_module_interfaces[module_type] + && g_module_interfaces[module_type]->module_uninstall) { + if (!g_module_interfaces[module_type]->module_uninstall( + request)) + goto fail; + } + } + /* Query Applets installed */ + else if (request->action == COAP_GET) { + char name[APP_NAME_MAX_LEN] = { 0 }; + char *properties = request->url + offset; + find_key_value(properties, strlen(properties), "name", name, + sizeof(name) - 1, '&'); + if (strlen(name) > 0) + app_manager_query_applets(request, name); + else + app_manager_query_applets(request, NULL); + } else { + SEND_ERR_RESPONSE(mid, "Invalid request of applet: invalid action"); + } + } + /* Event Register/Unregister */ + else if ((offset = check_url_start(request->url, strlen(request->url), + "/event/")) > 0) { + char url_buf[256] = { 0 }; + + strncpy(url_buf, request->url + offset, sizeof(url_buf) - 1); + + if (!event_handle_event_request(request->action, url_buf, ID_HOST)) { + SEND_ERR_RESPONSE(mid, "Handle event request failed."); + goto fail; + } + send_error_response_to_host(mid, CONTENT_2_05, NULL); /* OK */ + } else { + int i; + for (i = 0; i < Module_Max; i++) { + if (g_module_interfaces[i] + && g_module_interfaces[i]->module_handle_host_url) { + if (g_module_interfaces[i]->module_handle_host_url(request)) + break; + } + } + + } + + fail: + + return; + +} + +static void module_interfaces_init() +{ + int i; + for (i = 0; i < Module_Max; i++) { + if (g_module_interfaces[i] && g_module_interfaces[i]->module_init) + g_module_interfaces[i]->module_init(); + } +} + +void app_manager_startup(host_interface *interface) +{ + module_interfaces_init(); + + /* Create queue of App Manager */ + g_app_mgr_queue = bh_queue_create(); + if (!g_app_mgr_queue) + return; + + if (!module_data_list_init()) + goto fail1; + + if (!watchdog_startup()) + goto fail2; + + /* Initialize Host */ + app_manager_host_init(interface); + + am_register_resource("/app/", targeted_app_request_handler, ID_APP_MGR); + + /*/app/ and /event/ are both processed by applet_mgt_reqeust_handler*/ + am_register_resource("/applet", applet_mgt_reqeust_handler, ID_APP_MGR); + am_register_resource("/event/", applet_mgt_reqeust_handler, ID_APP_MGR); + + app_manager_printf("App Manager started.\n"); + + /* Enter loop run */ + bh_queue_enter_loop_run(g_app_mgr_queue, app_manager_queue_callback); + + fail2: module_data_list_destroy(); + + fail1: bh_queue_destroy(g_app_mgr_queue); +} + +#include "module_config.h" + +module_interface *g_module_interfaces[Module_Max] = { +#if ENABLE_MODULE_JEFF != 0 + &jeff_module_interface, +#else + NULL, +#endif + +#if ENABLE_MODULE_WASM_APP != 0 + &wasm_app_module_interface, +#else + NULL, +#endif + +#if ENABLE_MODULE_WASM_LIB != 0 + &wasm_lib_module_interface +#else + NULL +#endif + }; diff --git a/core/app-mgr/app-manager/app_manager.h b/core/app-mgr/app-manager/app_manager.h new file mode 100644 index 000000000..0fe86802b --- /dev/null +++ b/core/app-mgr/app-manager/app_manager.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APP_MANAGER_H +#define APP_MANAGER_H + +#include "bh_platform.h" +#include "bh_common.h" +#include "bh_queue.h" +#include "korp_types.h" +#include "app_manager_export.h" +#include "native_interface.h" +#include "shared_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __ZEPHYR__ +#define app_manager_printf printf +#else +#define app_manager_printf printk +#endif + +#define ID_HOST -3 +#define ID_APP_MGR -2 +#define ID_NONE (uint32)-1 + +#define SEND_ERR_RESPONSE(mid, err_msg) do { \ + app_manager_printf("%s\n", err_msg); \ + send_error_response_to_host(mid, INTERNAL_SERVER_ERROR_5_00, err_msg); \ +} while (0) + +extern module_interface *g_module_interfaces[Module_Max]; + +/* Lock of the module data list */ +extern korp_mutex module_data_list_lock; + +/* Module data list */ +extern module_data *module_data_list; + +void +app_manager_add_module_data(module_data *m_data); + +void +app_manager_del_module_data(module_data *m_data); + +bool +module_data_list_init(); + +void +module_data_list_destroy(); + +bool +app_manager_is_interrupting_module(uint32 module_type); + +void release_module(module_data *m_data); + +void +module_data_list_remove(module_data *m_data); + +void* +app_manager_timer_create(void (*timer_callback)(void*), + watchdog_timer *wd_timer); + +void +app_manager_timer_destroy(void *timer); + +void +app_manager_timer_start(void *timer, int timeout); + +void +app_manager_timer_stop(void *timer); + +watchdog_timer* +app_manager_get_wd_timer_from_timer_handle(void *timer); + +int +app_manager_signature_verify(const uint8_t *file, unsigned int file_len, + const uint8_t *signature, unsigned int sig_size); + +void targeted_app_request_handler(request_t *request, void *unused); + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 +void * +app_manager_get_tool_agent_queue(); +#endif + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif + diff --git a/core/app-mgr/app-manager/app_manager_host.c b/core/app-mgr/app-manager/app_manager_host.c new file mode 100644 index 000000000..ac8caddae --- /dev/null +++ b/core/app-mgr/app-manager/app_manager_host.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bh_common.h" +#include "korp_types.h" +#include "app_manager_host.h" +#include "app_manager.h" +#include "app_manager_export.h" +#include "coap_ext.h" +#include "bh_memory.h" +#include "bh_thread.h" + +/* host communication interface */ +static host_interface host_commu; + +/* IMRTLink Two leading bytes */ +static unsigned char leadings[] = { (unsigned char) 0x12, (unsigned char) 0x34 }; + +/* IMRTLink Receiving Phase */ +typedef enum recv_phase_t { + Phase_Non_Start, Phase_Leading, Phase_Type, Phase_Size, Phase_Payload +} recv_phase_t; + +/* IMRTLink Receive Context */ +typedef struct recv_context_t { + recv_phase_t phase; + bh_link_msg_t message; + int size_in_phase; +} recv_context_t; + +/* Current IMRTLink receive context */ +static recv_context_t recv_ctx; + +/* Lock for device write */ +static korp_mutex host_lock; + +static bool enable_log = false; + +static bool is_little_endian() +{ + long i = 0x01020304; + unsigned char* c = (unsigned char*) &i; + return (*c == 0x04) ? true : false; +} + +static void exchange32(uint8* pData) +{ + uint8 value = *pData; + *pData = *(pData + 3); + *(pData + 3) = value; + + value = *(pData + 1); + *(pData + 1) = *(pData + 2); + *(pData + 2) = value; +} + +/* return: + * 1: complete message received + * 0: incomplete message received + */ +static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) +{ + if (ctx->phase == Phase_Non_Start) { + ctx->message.payload_size = 0; + + if (ctx->message.payload) { + bh_free(ctx->message.payload); + ctx->message.payload = NULL; + } + + if (ch == leadings[0]) { + if (enable_log) + app_manager_printf("##On byte arrive: got leading 0\n"); + ctx->phase = Phase_Leading; + } + + return 0; + } else if (ctx->phase == Phase_Leading) { + if (ch == leadings[1]) { + if (enable_log) + app_manager_printf("##On byte arrive: got leading 1\n"); + ctx->phase = Phase_Type; + } else + ctx->phase = Phase_Non_Start; + + return 0; + } else if (ctx->phase == Phase_Type) { + if (ctx->size_in_phase++ == 0) { + if (enable_log) + app_manager_printf("##On byte arrive: got type 0\n"); + ctx->message.message_type = ch; + } else { + if (enable_log) + app_manager_printf("##On byte arrive: got type 1\n"); + ctx->message.message_type |= (ch << 8); + ctx->message.message_type = ntohs(ctx->message.message_type); + ctx->phase = Phase_Size; + ctx->size_in_phase = 0; + } + + return 0; + } else if (ctx->phase == Phase_Size) { + unsigned char *p = (unsigned char *) &ctx->message.payload_size; + + if (enable_log) + app_manager_printf("##On byte arrive: got payload_size, byte %d\n", + ctx->size_in_phase); + p[ctx->size_in_phase++] = ch; + + if (ctx->size_in_phase == sizeof(ctx->message.payload_size)) { +#ifndef __ZEPHYR__ + ctx->message.payload_size = ntohl(ctx->message.payload_size); +#else + if (is_little_endian()) + exchange32((uint8*)&ctx->message.payload_size); +#endif + ctx->phase = Phase_Payload; + + if (enable_log) + app_manager_printf("##On byte arrive: payload_size: %d\n", + ctx->message.payload_size); + if (ctx->message.payload) { + bh_free(ctx->message.payload); + ctx->message.payload = NULL; + } + + /* message completion */ + if (ctx->message.payload_size == 0) { + ctx->phase = Phase_Non_Start; + if (enable_log) + app_manager_printf( + "##On byte arrive: receive end, payload_size is 0.\n"); + return 1; + } + + if (ctx->message.payload_size > 1024 * 1024) { + ctx->phase = Phase_Non_Start; + return 0; + } + + if (ctx->message.message_type != INSTALL_WASM_BYTECODE_APP) { + ctx->message.payload = (char *) bh_malloc( + ctx->message.payload_size); + if (!ctx->message.payload) { + ctx->phase = Phase_Non_Start; + return 0; + } + } + + ctx->phase = Phase_Payload; + ctx->size_in_phase = 0; + } + + return 0; + } else if (ctx->phase == Phase_Payload) { + if (ctx->message.message_type == INSTALL_WASM_BYTECODE_APP) { + int received_size; + module_on_install_request_byte_arrive_func module_on_install = + g_module_interfaces[Module_WASM_App]->module_on_install; + + ctx->size_in_phase++; + + if (module_on_install != NULL) { + if (module_on_install(ch, ctx->message.payload_size, + &received_size)) { + if (received_size == ctx->message.payload_size) { + /* whole wasm app received */ + ctx->phase = Phase_Non_Start; + return 1; + } + } else { + /* receive or handle fail */ + ctx->phase = Phase_Non_Start; + return 0; + } + return 0; + } else { + ctx->phase = Phase_Non_Start; + return 0; + } + } else { + ctx->message.payload[ctx->size_in_phase++] = ch; + + if (ctx->size_in_phase == ctx->message.payload_size) { + ctx->phase = Phase_Non_Start; + if (enable_log) + app_manager_printf( + "##On byte arrive: receive end, payload_size is %d.\n", + ctx->message.payload_size); + return 1; + } + return 0; + } + } + + return 0; +} + +int aee_host_msg_callback(void *msg, uint16_t msg_len) +{ + unsigned char *p = msg, *p_end = p + msg_len; + + /*app_manager_printf("App Manager receive %d bytes from Host\n", msg_len);*/ + + for (; p < p_end; p++) { + int ret = on_imrt_link_byte_arrive(*p, &recv_ctx); + + if (ret == 1) { + if (recv_ctx.message.payload) { + int msg_type = recv_ctx.message.message_type; + + if (msg_type == REQUEST_PACKET) { + request_t request; + memset(&request, 0, sizeof(request)); + + if (!unpack_request(recv_ctx.message.payload, + recv_ctx.message.payload_size, &request)) + continue; + + request.sender = ID_HOST; + + am_dispatch_request(&request); + } else { + printf("unexpected host msg type: %d\n", msg_type); + } + + bh_free(recv_ctx.message.payload); + recv_ctx.message.payload = NULL; + recv_ctx.message.payload_size = 0; + } + + memset(&recv_ctx, 0, sizeof(recv_ctx)); + } + } + + return 0; +} + +bool app_manager_host_init(host_interface *interface) +{ + vm_mutex_init(&host_lock); + memset(&recv_ctx, 0, sizeof(recv_ctx)); + + host_commu.init = interface->init; + host_commu.send = interface->send; + host_commu.destroy = interface->destroy; + + if (host_commu.init != NULL) + return host_commu.init(); + + return true; +} + +int app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size) +{ + /* send an IMRT LINK message contains the buf as payload */ + if (host_commu.send != NULL) { + int size_s = size, n; + char header[16]; + + vm_mutex_lock(&host_lock); + /* leading bytes */ + bh_memcpy_s(header, 2, leadings, 2); + + /* message type */ + // todo: check if use network byte order!!! + *((uint16*) (header + 2)) = htons(msg_type); + + /* payload length */ + if (is_little_endian()) + exchange32((uint8*) &size_s); + + bh_memcpy_s(header + 4, 4, &size_s, 4); + n = host_commu.send(NULL, header, 8); + if (n != 8) { + vm_mutex_unlock(&host_lock); + return 0; + } + + /* payload */ + n = host_commu.send(NULL, buf, size); + vm_mutex_unlock(&host_lock); + + printf("sent %d bytes to host\n", n); + return n; + } else { + printf("no send api provided\n"); + } + return 0; +} diff --git a/core/app-mgr/app-manager/app_manager_host.h b/core/app-mgr/app-manager/app_manager_host.h new file mode 100644 index 000000000..1d6b45c87 --- /dev/null +++ b/core/app-mgr/app-manager/app_manager_host.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _APP_MANAGER_HOST_H_ +#define _APP_MANAGER_HOST_H_ + +#include "wasm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HOST_MODE_AON 1 +#define HOST_MODE_UART 2 +#define HOST_MODE_TEST 3 + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif + diff --git a/core/app-mgr/app-manager/app_mgr.cmake b/core/app-mgr/app-manager/app_mgr.cmake new file mode 100644 index 000000000..a549f307d --- /dev/null +++ b/core/app-mgr/app-manager/app_mgr.cmake @@ -0,0 +1,23 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set (__APP_MGR_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${__APP_MGR_DIR}) + + +file (GLOB source_all ${__APP_MGR_DIR}/*.c ${__APP_MGR_DIR}/platform/${TARGET_PLATFORM}/*.c) + +set (APP_MGR_SOURCE ${source_all}) + diff --git a/core/app-mgr/app-manager/ble_msg.c b/core/app-mgr/app-manager/ble_msg.c new file mode 100644 index 000000000..3a9da09c6 --- /dev/null +++ b/core/app-mgr/app-manager/ble_msg.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if 0 + +#define BLUETOOTH_INTERFACE_ADVERTISMENT_DATA_LENGTH 31 +/* ble_device_info */ +typedef struct ble_device_info { + + /* address type */ + uint8_t address_type; + /* MAC of Device */ + uint8_t mac[6]; + /* security level */ + uint8_t security_level; + /* signal strength */ + int8_t rssi; + /* uuid_16_type */ + int8_t uuid_16_type; + /* uuid_32_type */ + int8_t uuid_32_type; + /* uuid_128_type */ + int8_t uuid_128_type; + /* error code */ + uint8_t error_code; + /* scan response length*/ + uint16_t adv_data_len; + /* advertisement data */ + uint8_t *adv_data; + /* scan response length*/ + uint16_t scan_response_len; + /* scan response */ + uint8_t *scan_response; + /* next device */ + struct ble_device_info *next; + /* private data length */ + int private_data_length; + /* private data */ + uint8_t *private_data; + /* value handle*/ + uint16_t value_handle; + /* ccc handle*/ + uint16_t ccc_handle; + +}ble_device_info; + +/* BLE message sub type */ +typedef enum BLE_SUB_EVENT_TYPE { + BLE_SUB_EVENT_DISCOVERY, + BLE_SUB_EVENT_CONNECTED, + BLE_SUB_EVENT_DISCONNECTED, + BLE_SUB_EVENT_NOTIFICATION, + BLE_SUB_EVENT_INDICATION, + BLE_SUB_EVENT_PASSKEYENTRY, + BLE_SUB_EVENT_SECURITY_LEVEL_CHANGE +}BLE_SUB_EVENT_TYPE; + +/* Queue message, for BLE Event */ +typedef struct bh_queue_ble_sub_msg_t { + /* message type, should be one of QUEUE_MSG_TYPE */ + BLE_SUB_EVENT_TYPE type; + /* payload size */ + /*uint32_t payload_size;*/ + char payload[1]; +}bh_queue_ble_sub_msg_t; + +static void +app_instance_free_ble_msg(char *msg) +{ + bh_queue_ble_sub_msg_t *ble_msg = (bh_queue_ble_sub_msg_t *)msg; + ble_device_info *dev_info; + + dev_info = (ble_device_info *) ble_msg->payload; + + if (dev_info->scan_response != NULL) + bh_free(dev_info->scan_response); + + if (dev_info->private_data != NULL) + bh_free(dev_info->private_data); + + if (dev_info->adv_data != NULL) + bh_free(dev_info->adv_data); + + if (dev_info != NULL) + bh_free(dev_info); +} + +static void +app_instance_queue_free_callback(bh_message_t queue_msg) +{ + + char * payload = (char *)bh_message_payload(queue_msg); + if(payload == NULL) + return; + + switch (bh_message_type(queue_msg)) + { + /* + case SENSOR_EVENT: { + bh_sensor_event_t *sensor_event = (bh_sensor_event_t *) payload; + attr_container_t *event = sensor_event->event; + attr_container_destroy(event); + } + break; + */ + case BLE_EVENT: { + app_instance_free_ble_msg(payload); + break; + } + } +} + +#endif diff --git a/core/app-mgr/app-manager/coding_rule.txt b/core/app-mgr/app-manager/coding_rule.txt new file mode 100644 index 000000000..4598872a3 --- /dev/null +++ b/core/app-mgr/app-manager/coding_rule.txt @@ -0,0 +1,15 @@ +Coding rules: + +1. module implementation can include the export head files of associated runtime + +2. app manager only call access the module implementation through the interface API + +3. module implementation can call the app manager API from following files: + - util.c + - message.c + +4. platform API: To define it + +5. Any platform dependent implementation of app manager should be implemented in the + platform specific source file, such as app_mgr_zephyr.c + diff --git a/core/app-mgr/app-manager/event.c b/core/app-mgr/app-manager/event.c new file mode 100644 index 000000000..2f78a406c --- /dev/null +++ b/core/app-mgr/app-manager/event.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "event.h" + +#include "app_manager.h" +#include "bh_memory.h" +#include "coap_ext.h" + +typedef struct _subscribe { + struct _subscribe * next; + uint32 subscriber_id; +} subscribe_t; + +typedef struct _event { + struct _event *next; + int subscriber_size; + subscribe_t * subscribers; + char url[1]; /* event url */ +} event_reg_t; + +event_reg_t *g_events = NULL; + +static bool find_subscriber(event_reg_t * reg, uint32 id, bool remove_found) +{ + subscribe_t* c = reg->subscribers; + subscribe_t * prev = NULL; + while (c) { + subscribe_t * next = c->next; + if (c->subscriber_id == id) { + if (remove_found) { + if (prev) + prev->next = next; + else + reg->subscribers = next; + + bh_free(c); + } + + return true; + } else { + prev = c; + c = next; + } + } + + return false; +} + +static bool check_url(const char *url) +{ + if (*url == 0) + return false; + + return true; +} + +bool am_register_event(const char *url, uint32_t reg_client) +{ + event_reg_t *current = g_events; + + app_manager_printf("am_register_event adding url:(%s)\n", url); + + if (!check_url(url)) { + app_manager_printf("am_register_event: invaild url:(%s)\n", url); + return false; + } + while (current) { + if (strcmp(url, current->url) == 0) + break; + current = current->next; + } + + if (current == NULL) { + if (NULL + == (current = (event_reg_t *) bh_malloc( + offsetof(event_reg_t, url) + strlen(url) + 1))) { + app_manager_printf("am_register_event: malloc fail\n"); + return false; + } + + memset(current, 0, sizeof(event_reg_t)); + bh_strcpy_s(current->url, strlen(url) + 1, url); + current->next = g_events; + g_events = current; + } + + if (find_subscriber(current, reg_client, false)) { + return true; + } else { + subscribe_t * s = (subscribe_t*) bh_malloc(sizeof(subscribe_t)); + if (s == NULL) + return false; + + memset(s, 0, sizeof(subscribe_t)); + s->subscriber_id = reg_client; + s->next = current->subscribers; + current->subscribers = s; + app_manager_printf("client: %d registered event (%s)\n", reg_client, + url); + } + + return true; +} + +// @url: NULL means the client wants to unregister all its subscribed items +bool am_unregister_event(const char *url, uint32_t reg_client) +{ + event_reg_t *current = g_events, *pre = NULL; + + while (current != NULL) { + if (url == NULL || strcmp(current->url, url) == 0) { + event_reg_t * next = current->next; + if (find_subscriber(current, reg_client, true)) { + app_manager_printf("client: %d deregistered event (%s)\n", + reg_client, current->url); + } + + // remove the registration if no client subscribe it + if (current->subscribers == NULL) { + app_manager_printf("unregister for event deleted url:(%s)\n", + current->url); + if (pre) + pre->next = next; + else + g_events = next; + bh_free(current); + current = next; + continue; + } + } + pre = current; + current = current->next; + } + + return true; +} + +bool event_handle_event_request(uint8_t code, const char *event_url, + uint32_t reg_client) +{ + if (code == COAP_PUT) { /* register */ + return am_register_event(event_url, reg_client); + } else if (code == COAP_DELETE) { /* unregister */ + return am_unregister_event(event_url, reg_client); + } else { + /* invalid request */ + return false; + } +} + +void am_publish_event(request_t * event) +{ + bh_assert(event->action == COAP_EVENT); + + event_reg_t *current = g_events; + while (current) { + if (0 == strcmp(event->url, current->url)) { + subscribe_t* c = current->subscribers; + while (c) { + if (c->subscriber_id == ID_HOST) { + send_request_to_host(event); + } else { + module_request_handler(event, (void *)c->subscriber_id); + } + c = c->next; + } + + return; + } + + current = current->next; + } +} + +bool event_is_registered(const char *event_url) +{ + event_reg_t *current = g_events; + + while (current != NULL) { + if (strcmp(current->url, event_url) == 0) { + return true; + } + current = current->next; + } + + return false; +} diff --git a/core/app-mgr/app-manager/event.h b/core/app-mgr/app-manager/event.h new file mode 100644 index 000000000..84742adae --- /dev/null +++ b/core/app-mgr/app-manager/event.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _EVENT_H_ +#define _EVENT_H_ + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Handle event request from host agent + * + * @param code the coap packet code + * @param event_url the event url + * + * @return true if success, false otherwise + */ +bool +event_handle_event_request(uint8_t code, const char *event_url, + uint32_t register); + +/** + * Test whether the event is registered + * + * @param event_url the event url + * + * @return true for registered, false for not registered + */ +bool +event_is_registered(const char *event_url); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _EVENT_H_ */ diff --git a/core/app-mgr/app-manager/message.c b/core/app-mgr/app-manager/message.c new file mode 100644 index 000000000..0bccaecc8 --- /dev/null +++ b/core/app-mgr/app-manager/message.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app_manager.h" +#include "app_manager_host.h" +#include "event.h" +#include "attr_container.h" +#include "bh_memory.h" +#include "coap_ext.h" + +#if 0 +bool send_coap_packet_to_host(coap_packet_t * packet) +{ + int size; + uint8_t *buf; + + size = coap_serialize_message_tcp(&packet, &buf); + if (!buf || size == 0) + return false; + + app_manager_host_send_msg(buf, size); + bh_free(buf); + + return true; +} +#endif + +bool send_request_to_host(request_t *msg) +{ + if (COAP_EVENT == msg->action && !event_is_registered(msg->url)) { + app_manager_printf("Event is not registered\n"); + return false; + } + + int size; + char * packet = pack_request(msg, &size); + if (packet == NULL) + return false; + + app_manager_host_send_msg(REQUEST_PACKET, packet, size); + + free_req_resp_packet(packet); + + return true; +} + +bool send_response_to_host(response_t *response) +{ + int size; + char * packet = pack_response(response, &size); + if (packet == NULL) + return false; + + app_manager_host_send_msg(RESPONSE_PACKET, packet, size); + + free_req_resp_packet(packet); + + return true; +} + +bool send_error_response_to_host(int mid, int status, const char *msg) +{ + int payload_len = 0; + attr_container_t *payload = NULL; + response_t response[1] = { 0 }; + + if (msg) { + payload = attr_container_create(""); + if (payload) { + attr_container_set_string(&payload, "error message", msg); + payload_len = attr_container_get_serialize_length(payload); + } + } + + set_response(response, status, + FMT_ATTR_CONTAINER, (const char *)payload, payload_len); + response->mid = mid; + + send_response_to_host(response); + + if (payload) + attr_container_destroy(payload); + return true; +} + diff --git a/core/app-mgr/app-manager/module_config.h b/core/app-mgr/app-manager/module_config.h new file mode 100644 index 000000000..0899a0274 --- /dev/null +++ b/core/app-mgr/app-manager/module_config.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MODULE_CONFIG_H_ +#define _MODULE_CONFIG_H_ + +#define ENABLE_MODULE_JEFF 0 +#define ENABLE_MODULE_WASM_APP 1 +#define ENABLE_MODULE_WASM_LIB 1 + +#ifdef ENABLE_MODULE_JEFF +#include "module_jeff.h" +#endif +#ifdef ENABLE_MODULE_WASM_APP +#include "module_wasm_app.h" +#endif +#ifdef ENABLE_MODULE_WASM_LIB +#include "module_wasm_lib.h" +#endif + +#endif /* _MODULE_CONFIG_H_ */ diff --git a/core/app-mgr/app-manager/module_jeff.c b/core/app-mgr/app-manager/module_jeff.c new file mode 100644 index 000000000..91e5770f3 --- /dev/null +++ b/core/app-mgr/app-manager/module_jeff.c @@ -0,0 +1,1744 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef ENABLE_JEFF + +#include "module_jeff.h" +#include "jeff_export.h" +#include "../vmcore_jeff/jeff-runtime.h" +#include "../vmcore_jeff/jeff-thread.h" +#include "../vmcore_jeff/jeff-buffer.h" +#include "../vmcore_jeff/jeff-tool.h" +#include "../vmcore_jeff/jeff-tool-priv.h" +#include "app_manager-host.h" +#include "bh_queue.h" +#include "attr-container.h" +#include "attr-container-util.h" +#include "bh_thread.h" +#include "ems_gc.h" +#include "coap_ext.h" +#include "libcore.h" +#include "event.h" +#include "watchdog.h" + +#define DEFAULT_APPLET_TIMEOUT (3 * 60 * 1000) +#define DEFAULT_APPLET_HEAP_SIZE (48 * 1024) +#define MIN_APPLET_HEAP_SIZE (2 * 1024) +#define MAX_APPLET_HEAP_SIZE (1024 * 1024) + +typedef struct jeff_applet_data { + /* Java Applet Object */ + JeffObjectRef applet_obj; + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + /* Whether the applet is in debug mode */ + bool debug_mode; + /* Queue of the tool agent */ + bh_queue *tool_agent_queue; +#endif + + /* VM instance */ + JeffInstanceLocalRoot *vm_instance; + /* Applet Main file */ + JeffFileHeaderLinked *main_file; + /* Permissions of the Java Applet */ + char *perms; +}jeff_applet_data; + +/* Jeff class com.intel.aee.AEEApplet */ +static JeffClassHeaderLinked *class_AEEApplet; +/* Jeff class com.intel.aee.Request */ +static JeffClassHeaderLinked *class_AEERequest; +/* Jeff class com.intel.aee.Timer */ +static JeffClassHeaderLinked *class_Timer; +/* Jeff class com.intel.aee.Sensor */ +static JeffClassHeaderLinked *class_Sensor; +/* Jeff class com.intel.aee.ble.BLEManager */ +static JeffClassHeaderLinked *class_BLEManager; +/* Jeff class com.intel.aee.ble.BLEDevice */ +static JeffClassHeaderLinked *class_BLEDevice; +/* Jeff class com.intel.aee.ble.BLEGattService */ +JeffClassHeaderLinked *class_BLEGattService; +/* Jeff class com.intel.aee.ble.BLEGattCharacteristic */ +JeffClassHeaderLinked *class_BLEGattCharacteristic; +/* Jeff class com.intel.aee.ble.BLEGattDescriptor */ +JeffClassHeaderLinked *class_BLEGattDescriptor; +/* Jeff class com.intel.aee.gpio.GPIOChannel */ +static JeffClassHeaderLinked *class_GPIOChannel; +/* Jeff method void com.intel.aee.AEEApplet.onInit() */ +static JeffMethodLinked *method_AEEApplet_onInit; +/* Jeff method void com.intel.aee.AEEApplet.onDestroy() */ +static JeffMethodLinked *method_AEEApplet_onDestroy; +/* Jeff method void com.intel.aee.AEEApplet.callOnRequest(Request request) */ +static JeffMethodLinked *method_AEEApplet_callOnRequest; +/* Jeff method void com.intel.aee.Timer.callOnTimer() */ +static JeffMethodLinked *method_callOnTimer; +/* Jeff method void com.intel.aee.Sensor.callOnSensorEvent() */ +static JeffMethodLinked *method_callOnSensorEvent; +/* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEStartDiscovery() */ +static JeffMethodLinked *method_callOnBLEStartDiscovery; +/* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEConnected() */ +static JeffMethodLinked *method_callOnBLEConnected; +/* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEDisonnected() */ +static JeffMethodLinked *method_callOnBLEDisconnected; +/* Jeff method void com.intel.aee.ble.BLEManager.callOnBLENotification() */ +static JeffMethodLinked *method_callOnBLENotification; +/* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEIndication() */ +static JeffMethodLinked *method_callOnBLEIndication; +/* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEPasskeyEntry() */ +static JeffMethodLinked *method_callOnBLEPasskeyEntry; +/* Jeff method void com.intel.aee.gpio.GPIOChannel.callOnGPIOInterrupt() */ +static JeffMethodLinked *method_callOnGPIOInterrupt; +/* Jeff method void com.intel.aee.ble.BLEManager.getBLEDevice() */ +static JeffMethodLinked *method_callOnBLEManagerGetBLEDevice; + +static jeff_applet_data * +app_manager_get_jeff_applet_data() +{ + module_data *m_data = app_manager_get_module_data(Module_Jeff); + return (jeff_applet_data *)m_data->internal_data; +} + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 +void * +app_manager_get_tool_agent_queue() +{ + return app_manager_get_jeff_applet_data()->tool_agent_queue; +} +#endif + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 +static bool +is_tool_agent_running(module_data *m_data) +{ + jeff_applet_data *applet_data = (jeff_applet_data*)m_data->internal_data; + return (applet_data->debug_mode + && applet_data->tool_agent_queue + && applet_data->vm_instance->tool_agent); +} +#endif + +static char * +get_class_qname(const JeffString *pname, const JeffString *cname) +{ + unsigned int length = pname->length ? pname->length + 2 + cname->length + : cname->length + 1; + char *buf = bh_malloc(length), *p; + + if (!buf) + return NULL; + + p = buf; + if (pname->length) { + bh_memcpy_s(p, pname->length, pname->value, pname->length); + p += pname->length; + *p++ = '.'; + } + + bh_memcpy_s(p, cname->length, cname->value, cname->length); + p += cname->length; + *p = '\0'; + + return buf; +} + +static void +send_exception_event_to_host(const char *applet_name, const char *exc_name) +{ + attr_container_t *payload; + bh_request_msg_t msg; + char *url; + int url_len; + + payload = attr_container_create("exception detail"); + if (!payload) { + app_manager_printf("Send exception to host fail: allocate memory"); + return; + } + + if (!attr_container_set_string(&payload, "exception name", exc_name) + || !attr_container_set_string(&payload, "stack trace", "TODO") + || !attr_container_set_string(&payload, "applet name", applet_name)) { + app_manager_printf("Send exception to host fail: set attr"); + goto fail; + } + + url_len = strlen("/exception/") + strlen(applet_name); + url = bh_malloc(url_len + 1); + if (!url) { + app_manager_printf("Send exception to host fail: allocate memory"); + goto fail; + } + memset(url, 0, url_len + 1); + bh_strcpy_s(url, url_len + 1, "/exception/"); + bh_strcat_s(url, url_len + 1, applet_name); + + memset(&msg, 0, sizeof(msg)); + msg.url = url; + msg.action = COAP_PUT; + msg.payload = (char *)payload; + + app_send_request_msg_to_host(&msg); + + bh_free(url); + + fail: + attr_container_destroy(payload); +} + +static bool +check_exception() +{ + if (jeff_runtime_get_exception()) { + jeff_printf("V1.Exception thrown when running applet '%s':\n", + app_manager_get_module_name(Module_Jeff)); + jeff_runtime_print_exception(); + jeff_printf("\n"); + jeff_printf(NULL); + + if (!app_manager_is_interrupting_module(Module_Jeff)) { + attr_container_t *payload; + int payload_len; + JeffClassHeaderLinked *exc_class = jeff_object_class_pointer(jeff_runtime_get_exception()); + char *qname_buf = get_class_qname(jeff_get_class_pname(exc_class), + jeff_get_class_cname(exc_class)); + + /* Send exception event to host */ + if (qname_buf) { + send_exception_event_to_host(app_manager_get_module_name(Module_Jeff), qname_buf); + bh_free(qname_buf); + } + + /* Uninstall the applet */ + if ((payload = attr_container_create("uninstall myself"))) { + if (attr_container_set_string(&payload, "name", app_manager_get_module_name(Module_Jeff)) + /* Set special flag to prevent app manager making response since this is an internal message */ + && attr_container_set_bool(&payload, "do not reply me", true)) { + request_t request = {0}; + payload_len = attr_container_get_serialize_length(payload); + + init_request(request, "/applet", COAP_DELETE, (char *)payload, payload_len)); + app_mgr_lookup_resource(&request); + + // TODO: confirm this is right + attr_container_destroy(payload); + } + } + + jeff_runtime_set_exception(NULL); + return true; + } + + return false; + } + + static bool + app_manager_initialize_class(JeffClassHeaderLinked *c) + { + jeff_runtime_initialize_class(c); + return !check_exception(); + } + + static bool + app_manager_initialize_object(JeffObjectRef obj) + { + jeff_runtime_initialize_object(obj); + return !check_exception(); + } + + static bool + app_manager_call_java(JeffMethodLinked *method, + unsigned int argc, uint32 argv[], uint8 argt[]) + { + module_data *m_data = app_manager_get_module_data(Module_Jeff); + watchdog_timer *wd_timer = &m_data->wd_timer; + bool is_wd_started = false; + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + /* Only start watchdog when debugger is not running */ + if (!is_tool_agent_running(m_data)) { +#endif + watchdog_timer_start(wd_timer); + is_wd_started = true; +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + } +#endif + + jeff_runtime_call_java(method, argc, argv, argt); + + if (is_wd_started) { + vm_mutex_lock(&wd_timer->lock); + if (!wd_timer->is_interrupting) { + wd_timer->is_stopped = true; + watchdog_timer_stop(wd_timer); + } + vm_mutex_unlock(&wd_timer->lock); + } + + return !check_exception(); + } + + static AEEBLEDevice + create_object_BLEDevice(ble_device_info *dev_info) + { + JeffLocalObjectRef ref; + AEEBLEDevice dev_struct; + + jeff_runtime_push_local_object_ref(&ref); + + ref.val = jeff_runtime_new_object(class_BLEDevice); + + if (!ref.val) { + jeff_runtime_pop_local_object_ref(1); + return NULL; + } + + dev_struct = (AEEBLEDevice) (ref.val); + dev_struct->rssi = dev_info->rssi; + dev_struct->mac = (jbyteArray) jeff_runtime_create_byte_array((int8 *)dev_info->mac, 6); + + app_manager_printf("adv_data_len:%d,scan_response_len:%d\n", dev_info->adv_data_len, dev_info->scan_response_len); + + dev_struct->advData = (jbyteArray) jeff_runtime_create_byte_array((int8 *)dev_info->adv_data, dev_info->adv_data_len); + dev_struct->scanResponse = (jbyteArray) jeff_runtime_create_byte_array((int8 *)dev_info->scan_response, dev_info->scan_response_len); + dev_struct->addressType = dev_info->address_type; + jeff_runtime_initialize_object(ref.val); + jeff_runtime_pop_local_object_ref(1); + if ((dev_struct->mac == NULL) || (dev_struct->advData == NULL) || (dev_struct->scanResponse == NULL)) { + return NULL; + } + return (AEEBLEDevice) ref.val; + } + + static void + app_instance_process_ble_msg(char *msg) + { + bh_queue_ble_sub_msg_t *ble_msg = (bh_queue_ble_sub_msg_t *)msg; + unsigned int argv[5]; + uint8 argt[5]; + + ble_device_info *dev_info; + + dev_info = (ble_device_info *) ble_msg->payload; + AEEBLEDevice ble_dev; + + argv[0] = (unsigned int) (jbyteArray) jeff_runtime_create_byte_array((int8 *)dev_info->mac, 6); + argt[0] = 1; + if (!app_manager_call_java(method_callOnBLEManagerGetBLEDevice, 1, argv, argt)) { + app_manager_printf("app_manager_call_java BLEManagerGetBLEDevice fail error\n"); + goto fail; + } + ble_dev = (AEEBLEDevice) argv[0]; + if (ble_dev == NULL) { + ble_dev = create_object_BLEDevice(dev_info); + if (ble_dev == NULL) { + goto fail; + } + } + + switch (ble_msg->type) { + case BLE_SUB_EVENT_DISCOVERY: + { + argv[0] = (unsigned int) ble_dev; + argt[0] = 1; + ble_dev->rssi = dev_info->rssi; + if (!app_manager_call_java(method_callOnBLEStartDiscovery, 1, argv, argt)) { + app_manager_printf("app_manager_call_java method_callOnBLEStartDiscovery fail error\n"); + goto fail; + } + } + break; + + case BLE_SUB_EVENT_CONNECTED: + { + if (ble_dev) { + argv[0] = (unsigned int) ble_dev; + argv[1] = 0; + argt[0] = 1; + argt[1] = 1; + if (!app_manager_call_java(method_callOnBLEConnected, 2, argv, argt)) { + app_manager_printf("app_manager_call_java method_callOnBLEConnected fail error\n"); + goto fail; + } + } + } + break; + + case BLE_SUB_EVENT_DISCONNECTED: + { + app_manager_printf("app instance received disconnected\n"); + + if (ble_dev) { + argv[0] = (unsigned int) ble_dev; + argv[1] = 0; + argt[0] = 1; + argt[1] = 1; + ble_dev->rssi = dev_info->rssi; + if (!app_manager_call_java(method_callOnBLEDisconnected, 2, argv, argt)) { + app_manager_printf("app_manager_call_java method_callOnBLEDisconnected fail error\n"); + goto fail; + } + } + } + break; + + case BLE_SUB_EVENT_NOTIFICATION: + { + if (ble_dev) { + argv[0] = (unsigned int) ble_dev; + argv[1] = (unsigned int) (jbyteArray) jeff_runtime_create_byte_array( + (int8 *)dev_info->private_data, dev_info->private_data_length); + argv[2] = dev_info->value_handle; + argv[3] = dev_info->ccc_handle; + argt[1] = 1; + argt[2] = 0; + argt[3] = 0; + ble_dev->rssi = dev_info->rssi; + if (!app_manager_call_java(method_callOnBLENotification, 4, argv, argt)) { + app_manager_printf("app_manager_call_java method_callOnBLENotification fail error\n"); + goto fail; + } + } + } + break; + + case BLE_SUB_EVENT_INDICATION: + { + if (ble_dev) { + argv[0] = (unsigned int) ble_dev; + argv[1] = (unsigned int) (jbyteArray) jeff_runtime_create_byte_array( + (int8 *)dev_info->private_data, dev_info->private_data_length); + argv[2] = dev_info->value_handle; + argv[3] = dev_info->ccc_handle; + argt[0] = 1; + argt[1] = 1; + argt[2] = 0; + argt[3] = 0; + ble_dev->rssi = dev_info->rssi; + if (!app_manager_call_java(method_callOnBLEIndication, 4, argv, argt)) { + app_manager_printf("app_manager_call_java method_callOnBLEIndication fail error\n"); + goto fail; + } + } + } + break; + + case BLE_SUB_EVENT_PASSKEYENTRY: + { + + if (ble_dev) { + argv[0] = (unsigned int) ble_dev; + argt[0] = 1; + argt[1] = 1; + ble_dev->rssi = dev_info->rssi; + if (!app_manager_call_java(method_callOnBLEPasskeyEntry, 1, argv, argt)) { + app_manager_printf("app_manager_call_java method_callOnBLEPasskeyEntry fail error\n"); + goto fail; + } + } + } + break; + + case BLE_SUB_EVENT_SECURITY_LEVEL_CHANGE: + { + if (ble_dev) { + ble_dev->securityLevel = dev_info->security_level; + } + } + break; + + default: + break; + } + + fail: + if (dev_info->scan_response != NULL) { + bh_free(dev_info->scan_response); + } + if (dev_info->private_data != NULL) { + bh_free(dev_info->private_data); + } + + if (dev_info->adv_data != NULL) { + bh_free(dev_info->adv_data); + } + if (dev_info != NULL) { + bh_free(dev_info); + } + + } + + static void + app_instance_free_ble_msg(char *msg) + { + bh_queue_ble_sub_msg_t *ble_msg = (bh_queue_ble_sub_msg_t *)msg; + ble_device_info *dev_info; + + dev_info = (ble_device_info *) ble_msg->payload; + + if (dev_info->scan_response != NULL) + bh_free(dev_info->scan_response); + + if (dev_info->private_data != NULL) + bh_free(dev_info->private_data); + + if (dev_info->adv_data != NULL) + bh_free(dev_info->adv_data); + + if (dev_info != NULL) + bh_free(dev_info); + } + + static void + app_instance_queue_free_callback(void *queue_msg) + { + bh_queue_msg_t *msg = (bh_queue_msg_t *)queue_msg; + + switch (msg->message_type) { + case APPLET_REQUEST: + { + bh_request_msg_t *req_msg = (bh_request_msg_t *)msg->payload; + bh_free(req_msg); + break; + } + + case TIMER_EVENT: + { + break; + } + + case SENSOR_EVENT: + { + if (msg->payload) { + bh_sensor_event_t *sensor_event = (bh_sensor_event_t *)msg->payload; + attr_container_t *event = sensor_event->event; + + attr_container_destroy(event); + bh_free(sensor_event); + } + break; + } + + case BLE_EVENT: + { + if (msg->payload) { + app_instance_free_ble_msg(msg->payload); + bh_free(msg->payload); + } + break; + } + + case GPIO_INTERRUPT_EVENT: + { + break; + } + + default: + { + break; + } + } + + bh_free(msg); + } + + static void + app_instance_queue_callback(void *queue_msg) + { + bh_queue_msg_t *msg = (bh_queue_msg_t *)queue_msg; + unsigned int argv[5]; + uint8 argt[5]; + + if (app_manager_is_interrupting_module(Module_Jeff)) { + app_instance_queue_free_callback(queue_msg); + return; + } + + switch (msg->message_type) { + case APPLET_REQUEST: + { + JeffLocalObjectRef ref; + AEERequest req_obj; + bh_request_msg_t *req_msg = (bh_request_msg_t *)msg->payload; + attr_container_t *attr_cont = (attr_container_t *)req_msg->payload; + module_data *m_data = app_manager_get_module_data(Module_Jeff); + jeff_applet_data *applet_data = (jeff_applet_data*)m_data->internal_data; + + app_manager_printf("Applet %s got request, url %s, action %d\n", + m_data->module_name, req_msg->url, req_msg->action); + + /* Create Request object */ + req_obj = (AEERequest)jeff_object_new(m_data->heap, class_AEERequest); + if (!req_obj) { + app_manager_printf("Applet process request failed: create request obj failed.\n"); + goto fail1; + } + + jeff_runtime_push_local_object_ref(&ref); + ref.val = (JeffObjectRef)req_obj; + + req_obj->mid = req_msg->mid; + req_obj->action = req_msg->action; + req_obj->fmt = req_msg->fmt; + + /* Create Java url string */ + if (req_msg->url) { + req_obj->url = (jstring)jeff_runtime_create_java_string(req_msg->url); + if (!req_obj->url) { + app_manager_printf("Applet process request failed: create url string failed.\n"); + goto fail2; + } + } + + /* Create Java AttributeObject payload */ + if (attr_cont + && !attr_container_to_attr_obj(attr_cont, &req_obj->payload)) { + app_manager_printf("Applet process request failed: convert payload failed.\n"); + goto fail2; + } + + /* Call AEEApplet.callOnRequest(Request request) method */ + argv[0] = (unsigned int)applet_data->applet_obj; + argv[1] = (unsigned int)req_obj; + argt[0] = argt[1] = 1; + app_manager_call_java(method_AEEApplet_callOnRequest, 2, argv, argt); + app_manager_printf("Applet process request success.\n"); + + fail2: + jeff_runtime_pop_local_object_ref(1); + fail1: + bh_free(req_msg); + break; + } + + case TIMER_EVENT: + { + if (msg->payload) { + /* Call Timer.callOnTimer() method */ + argv[0] = (unsigned int)msg->payload; + argt[0] = 1; + app_manager_call_java(method_callOnTimer, 1, argv, argt); + } + break; + } + + case SENSOR_EVENT: + { + if (msg->payload) { + bh_sensor_event_t *sensor_event = (bh_sensor_event_t *)msg->payload; + AEESensor sensor = sensor_event->sensor; + attr_container_t *event = sensor_event->event; + bool ret = attr_container_to_attr_obj(event, &sensor->event); + + attr_container_destroy(event); + bh_free(sensor_event); + + if (ret) { + /* Call Sensor.callOnSensorEvent() method */ + argv[0] = (unsigned int)sensor; + argt[0] = 1; + app_manager_call_java(method_callOnSensorEvent, 1, argv, argt); + } + } + break; + } + + case BLE_EVENT: + { + if (msg->payload) { + app_instance_process_ble_msg(msg->payload); + bh_free(msg->payload); + } + break; + } + + case GPIO_INTERRUPT_EVENT: + { + AEEGPIOChannel gpio_ch = (AEEGPIOChannel)msg->payload; + + if ((gpio_ch == NULL) || (gpio_ch->callback == 0) || (gpio_ch->listener == NULL)) { + break; + } + argv[0] = (unsigned int) gpio_ch; + argt[0] = 1; + bool ret_value = app_manager_call_java(method_callOnGPIOInterrupt, 1, argv, argt); + + if (!ret_value) { + app_manager_printf("app_manager_call_java method_method_callOnGPIOInterrupt return false\n"); + } + break; + } + + default: + { + app_manager_printf("Invalid message type of applet queue message.\n"); + break; + } + } + + bh_free(msg); + } + + static JeffClassHeaderLinked* + find_main_class(JeffFileHeaderLinked *main_file) + { + JeffClassHeaderLinked *c = NULL, *ci; + unsigned int i; + + for (i = 0; i < main_file->internal_class_count; i++) { + ci = main_file->class_header[i]; + + if (jeff_is_super_class(class_AEEApplet, ci) + && (ci->access_flag & JEFF_ACC_PUBLIC)) { + if (c) { + jeff_printe_more_than_one_main_class(); + return NULL; + } + + c = ci; + } + } + + if (!c) + jeff_printe_no_main_class(); + + return c; + } + + /* Java applet thread main routine */ + static void* + app_instance_main(void *arg) + { + module_data *m_data = (module_data *)arg; + jeff_applet_data *applet_data = (jeff_applet_data*)m_data->internal_data; + JeffClassHeaderLinked *object_class; + JeffMethodLinked *m; + unsigned int argv[1]; + uint8 argt[1]; + + app_manager_printf("Java Applet '%s' started\n", m_data->module_name); + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + if (applet_data->debug_mode) + jeff_tool_suspend_self(); +#endif + + applet_data->vm_instance->applet_object = applet_data->applet_obj; + object_class = jeff_object_class_pointer(applet_data->applet_obj); + m = jeff_select_method_virtual(object_class, method_AEEApplet_onInit); + bh_assert(m != NULL); + /* Initialize applet class which call */ + if (!app_manager_initialize_class(object_class)) { + app_manager_printf("Call fail\n"); + goto fail; + } + + /* Initialize applet object which call */ + if (!app_manager_initialize_object(applet_data->applet_obj)) { + app_manager_printf("Call fail\n"); + goto fail; + } + + /* Call applet's onInit() method */ + argv[0] = (unsigned int)applet_data->applet_obj; + argt[0] = 1; + if (app_manager_call_java(m, 1, argv, argt)) + /* Enter queue loop run to receive and process applet queue message */ + bh_queue_enter_loop_run(m_data->queue, app_instance_queue_callback); + + fail: + applet_data->vm_instance->applet_object = applet_data->applet_obj; + object_class = jeff_object_class_pointer(applet_data->applet_obj); + m = jeff_select_method_virtual(object_class, method_AEEApplet_onDestroy); + bh_assert(m != NULL); + /* Call User Applet or AEEApplet onDestroy() method */ + app_manager_call_java(m, 1, argv, argt); + if (m != method_AEEApplet_onDestroy) { + /*If 'm' is user onDestroy, then Call AEEApplet.onDestroy() method*/ + app_manager_call_java(method_AEEApplet_onDestroy, 1, argv, argt); + } + app_manager_printf("Applet instance main thread exit.\n"); + return NULL; + } + + static bool + verify_signature(JeffFileHeader *file, unsigned size) + { + uint8 *sig; + unsigned sig_size; + +#if BEIHAI_ENABLE_NO_SIGNATURE != 0 + /* no signature */ + if (file->file_signature == 0) + return true; +#endif + + if (file->file_length != size +#if BEIHAI_ENABLE_NO_SIGNATURE == 0 + || file->file_signature == 0 +#endif + || file->file_signature >= file->file_length) + return false; + + sig = (uint8 *)file + file->file_signature; + sig_size = file->file_length - file->file_signature; + + if (0 == app_manager_signature_verify((uint8_t *)file, file->file_signature, + sig, sig_size)) + return false; + + return true; + } + + /* Install Java Applet */ + static bool + jeff_module_install(bh_request_msg_t *msg) + { + unsigned int size, bpk_file_len, main_file_len, heap_size, timeout; + uint8 *bpk_file; + JeffFileHeaderLinked *main_file; + JeffClassHeaderLinked *main_class; + module_data *m_data; + jeff_applet_data *applet_data; + char *applet_name, *applet_perm; + attr_container_t *attr_cont; + bool debug = false; + + /* Check url */ + if (!msg->url + || strcmp(msg->url, "/applet") != 0) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: invalid url."); + return false; + } + + /* Check payload */ + attr_cont = (attr_container_t *)msg->payload; + if (!attr_cont + || !(bpk_file = (uint8 *) + attr_container_get_as_bytearray(attr_cont, "bpk", &bpk_file_len))) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: invalid bpk file."); + return false; + } + + /* Check applet name */ + applet_name = attr_container_get_as_string(attr_cont, "name"); + + if (!applet_name || strlen(applet_name) == 0) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: invalid applet name."); + return false; + } + + if (app_manager_lookup_module_data(applet_name)) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: applet already installed."); + return false; + } + + /* TODO: convert bpk file to Jeff file */ + main_file_len = bpk_file_len; + main_file = bh_malloc(main_file_len); + if (!main_file) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: allocate memory failed."); + return false; + } + bh_memcpy_s(main_file, main_file_len, bpk_file, main_file_len); + + /* Verify signature */ + if (!verify_signature((JeffFileHeader *)main_file, main_file_len)) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: verify Jeff file signature failed."); + goto fail1; + } + + /* Load Jeff main file */ + if (!jeff_runtime_load(main_file, main_file_len, false, NULL, NULL)) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: load Jeff file failed."); + goto fail1; + } + + /* Find main class */ + main_class = find_main_class(main_file); + if (!main_class) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: find applet class failed."); + goto fail2; + } + + /* Create module data */ + size = offsetof(module_data, module_name) + strlen(applet_name) + 1; + size = align_uint(size, 4); + m_data = bh_malloc(size + sizeof(jeff_applet_data)); + if (!m_data) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: allocate memory failed."); + goto fail2; + } + + memset(m_data, 0, size + sizeof(jeff_applet_data)); + m_data->module_type = Module_Jeff; + m_data->internal_data = (uint8*)m_data + size; + applet_data = (jeff_applet_data*)m_data->internal_data; + bh_strcpy_s(m_data->module_name, strlen(applet_name) + 1, applet_name); + applet_data->main_file = main_file; + + /* Set applet execution timeout */ + timeout = DEFAULT_APPLET_TIMEOUT; + if (attr_container_contain_key(attr_cont, "execution timeout")) + timeout = attr_container_get_as_int(attr_cont, "execution timeout"); + m_data->timeout = timeout; + + /* Create applet permissions */ + applet_perm = attr_container_get_as_string(attr_cont, "perm"); + if (applet_perm != NULL) { + applet_data->perms = bh_malloc(strlen(applet_perm) + 1); + if (!applet_data->perms) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: allocate memory for applet permissions failed."); + goto fail3; + } + + bh_strcpy_s(applet_data->perms, strlen(applet_perm) + 1, applet_perm); + } + + /* Create applet queue */ + m_data->queue = bh_queue_create(); + if (!m_data->queue) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: create applet queue failed."); + goto fail3_1; + } + + /* Set heap size */ + heap_size = DEFAULT_APPLET_HEAP_SIZE; + if (attr_container_contain_key(attr_cont, "heap size")) { + heap_size = attr_container_get_as_int(attr_cont, "heap size"); + if (heap_size < MIN_APPLET_HEAP_SIZE) + heap_size = MIN_APPLET_HEAP_SIZE; + else if (heap_size > MAX_APPLET_HEAP_SIZE) + heap_size = MAX_APPLET_HEAP_SIZE; + } + + m_data->heap_size = heap_size; + + /* Create applet heap */ + m_data->heap = gc_init_for_instance(heap_size); + if (!m_data->heap) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: create heap failed."); + goto fail4; + } + + /* Create applet object */ + applet_data->applet_obj = jeff_object_new(m_data->heap, main_class); + if (!applet_data->applet_obj) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: create applet object failed."); + goto fail5; + } + + /* Initialize watchdog timer */ + if (!watchdog_timer_init(m_data)) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: create applet watchdog timer failed."); + goto fail5; + } + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + /* Check whether applet is debuggable */ + if (attr_container_contain_key(attr_cont, "debug")) + debug = attr_container_get_as_bool(attr_cont, "debug"); + + applet_data->debug_mode = debug; + + /* Create tool agent queue */ + if (debug && !(applet_data->tool_agent_queue = bh_queue_create())) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: create tool agent queue failed."); + goto fail5_1; + } +#endif + + /* Create applet instance */ + applet_data->vm_instance = + jeff_runtime_create_instance(main_file, m_data->heap, 16, + app_instance_main, m_data, + NULL); + if (!applet_data->vm_instance) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: create Java VM failed"); + goto fail6; + } + + /* Add applet data to applet data list */ + applet_data->vm_instance->applet_object = applet_data->applet_obj; + app_manager_add_module_data(m_data); + app_manager_post_applets_update_event(); + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + /* Start tool agent thread */ + if (debug && !jeff_tool_start_agent(applet_data->vm_instance, applet_data->tool_agent_queue)) { + SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: start tool agent failed"); + goto fail6; + } +#endif + + app_manager_printf("Install Applet success!\n"); + app_send_response_to_host(msg->mid, CREATED_2_01, NULL); /* CREATED */ + return true; + + fail6: +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + if (debug) + bh_queue_destroy(applet_data->tool_agent_queue); +#endif + + fail5_1: + watchdog_timer_destroy(&m_data->wd_timer); + + fail5: + gc_destroy_for_instance(m_data->heap); + + fail4: + bh_queue_destroy(m_data->queue, NULL); + + fail3_1: + bh_free(applet_data->perms); + + fail3: + bh_free(applet_data); + + fail2: + jeff_runtime_unload(main_file); + + fail1: + bh_free(main_file); + + return false; + } + + static void + cleanup_applet_resource(module_data *m_data) + { + jeff_applet_data *applet_data = (jeff_applet_data*)m_data->internal_data; + + /* Unload Jeff main file and free it */ + jeff_runtime_unload(applet_data->main_file); + bh_free(applet_data->main_file); + + /* Destroy queue */ + bh_queue_destroy(m_data->queue, app_instance_queue_free_callback); + + /* Destroy heap */ + gc_destroy_for_instance(m_data->heap); + + /* Destroy watchdog timer */ + watchdog_timer_destroy(&m_data->wd_timer); + + /* Remove module data from module data list and free it */ + app_manager_del_module_data(m_data); + bh_free(applet_data->perms); + bh_free(m_data); + } + + /* Uninstall Java Applet */ + static bool + jeff_module_uninstall(bh_request_msg_t *msg) + { + module_data *m_data; + jeff_applet_data *applet_data; + attr_container_t *attr_cont; + char *applet_name; + bool do_not_reply = false; + + /* Check payload and applet name*/ + attr_cont = (attr_container_t *)msg->payload; + + /* Check whether need to reply this request */ + if (attr_container_contain_key(attr_cont, "do not reply me")) + do_not_reply = attr_container_get_as_bool(attr_cont, "do not reply me"); + + /* Check url */ + if (!msg->url + || strcmp(msg->url, "/applet") != 0) { + if (!do_not_reply) + SEND_ERR_RESPONSE(msg->mid, "Uninstall Applet failed: invalid url."); + else + app_manager_printf("Uninstall Applet failed: invalid url."); + return false; + } + + if (!attr_cont + || !(applet_name = attr_container_get_as_string(attr_cont, "name")) + || strlen(applet_name) == 0) { + if (!do_not_reply) + SEND_ERR_RESPONSE(msg->mid, "Uninstall Applet failed: invalid applet name."); + else + app_manager_printf("Uninstall Applet failed: invalid applet name."); + return false; + } + + m_data = app_manager_lookup_module_data(applet_name); + if (!m_data) { + if (!do_not_reply) + SEND_ERR_RESPONSE(msg->mid, "Uninstall Applet failed: no applet found."); + else + app_manager_printf("Uninstall Applet failed: no applet found."); + return false; + } + + if (m_data->module_type != Module_Jeff) { + if (!do_not_reply) + SEND_ERR_RESPONSE(msg->mid, "Uninstall Applet failed: invlaid module type."); + else + app_manager_printf("Uninstall Applet failed: invalid module type."); + return false; + } + + if (m_data->wd_timer.is_interrupting) { + if (!do_not_reply) + SEND_ERR_RESPONSE(msg->mid, "Uninstall Applet failed: applet is being interrupted by watchdog."); + else + app_manager_printf("Uninstall Applet failed: applet is being interrupted by watchdog."); + return false; + } + + /* Exit applet queue loop run */ + bh_queue_exit_loop_run(m_data->queue); + + applet_data = (jeff_applet_data*)m_data->internal_data; +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + /* Exit tool agent queue loop run */ + if (is_tool_agent_running(m_data)) { + bh_queue_exit_loop_run(applet_data->tool_agent_queue); + } +#endif + + /* Wait the end of the applet instance and then destroy it */ + if (applet_data->vm_instance->main_file) + jeff_runtime_wait_for_instance(applet_data->vm_instance, -1); + jeff_runtime_destroy_instance(applet_data->vm_instance); + + cleanup_applet_resource(m_data); + app_manager_post_applets_update_event(); + + app_manager_printf("Uninstall Applet success!\n"); + + if (!do_not_reply) + app_send_response_to_host(msg->mid, DELETED_2_02, NULL); /* DELETED */ + return true; + } + +#define PERM_PREFIX "AEE.permission." + + static bool + check_permission_format(const char *perm) + { + const char *prefix = PERM_PREFIX; + const char *p; + + if (perm == NULL || strncmp(perm, prefix, strlen(prefix)) != 0 + || *(p = perm + strlen(prefix)) == '\0') + return false; + + do { + if (!(*p == '.' || ('A' <= *p && *p <= 'Z') || ('a' <= *p && *p <= 'z'))) + return false; + }while (*++p != '\0'); + + return true; + } + + static bool + match(const char *haystack, const char *needle, char delim) + { + const char *p = needle; + + if (haystack == NULL || *haystack == '\0' + || needle == NULL || *needle == '\0') + return false; + + while (true) { + while (true) { + if ((*haystack == '\0' || *haystack == delim) && *p == '\0') { + return true; + } else if (*p == *haystack) { + ++p; + ++haystack; + } else { + break; + } + } + while (*haystack != '\0' && *haystack != delim) { + ++haystack; + } + if (*haystack == '\0') { + return false; + } else { + ++haystack; + p = needle; + } + } + } + + bool + bh_applet_check_permission(const char *perm) + { + return check_permission_format(perm) + && match(app_manager_get_jeff_applet_data()->perms, + perm + strlen(PERM_PREFIX), ' '); + } + + static bool + jeff_module_init() + { + JeffDescriptorFull d[] = { {JEFF_TYPE_VOID, 0, NULL}}; + JeffDescriptorFull d1[] = { + { JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, NULL}, + { JEFF_TYPE_VOID, 0, NULL} + }; + + /* Resolve class com.intel.aee.AEEApplet */ + class_AEEApplet = jeff_runtime_resolve_class_full_name("com.intel.aee.AEEApplet"); + if (!class_AEEApplet) { + app_manager_printf("App Manager start failed: resolve class AEEApplet failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.Request */ + class_AEERequest = jeff_runtime_resolve_class_full_name("com.intel.aee.Request"); + if (!class_AEERequest) { + app_manager_printf("App Manager start failed: resolve class Request failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.Timer */ + class_Timer = jeff_runtime_resolve_class_full_name("com.intel.aee.Timer"); + if (!class_Timer) { + app_manager_printf("App Manager start failed: resolve class Timer failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.Sensor */ + class_Sensor = jeff_runtime_resolve_class_full_name("com.intel.aee.Sensor"); + if (!class_Sensor) { + app_manager_printf("App Manager start failed: resolve class Sensor failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.ble.BLEManager */ + class_BLEManager = jeff_runtime_resolve_class_full_name( + "com.intel.aee.ble.BLEManager"); + if (!class_BLEManager) { + app_manager_printf( + "App Manager start failed: resolve class BLEManager failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.ble.BLEDevice */ + class_BLEDevice = jeff_runtime_resolve_class_full_name( + "com.intel.aee.ble.BLEDevice"); + if (!class_BLEDevice) { + app_manager_printf( + "App Manager start failed: resolve class BLEDevice failed.\n"); + return false; + } + /* Resolve class com.intel.aee.ble.BLEDevice */ + class_BLEGattService = jeff_runtime_resolve_class_full_name( + "com.intel.aee.ble.BLEGattService"); + if (!class_BLEGattService) { + app_manager_printf( + "App Manager start failed: resolve class BLEGattService failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.ble.BLEDevice */ + class_BLEGattCharacteristic = jeff_runtime_resolve_class_full_name( + "com.intel.aee.ble.BLEGattCharacteristic"); + if (!class_BLEGattCharacteristic) { + app_manager_printf( + "App Manager start failed: resolve class BLEGattCharacteristic failed.\n"); + return false; + } + + /* Resolve class com.intel.aee.ble.BLEDevice */ + class_BLEGattDescriptor = jeff_runtime_resolve_class_full_name( + "com.intel.aee.ble.BLEGattDescriptor"); + if (!class_BLEGattDescriptor) { + app_manager_printf( + "App Manager start failed: resolve class BLEGattDescriptor failed.\n"); + return false; + } + /* Resolve class com.intel.aee.gpio.GPIOChannel */ + class_GPIOChannel = jeff_runtime_resolve_class_full_name( + "com.intel.aee.gpio.GPIOChannel"); + if (!class_GPIOChannel) { + app_manager_printf( + "App Manager start failed: resolve class GPIOChannel failed.\n"); + return false; + } + + /* Resolve method com.intel.aee.AEEApplet.onInit() */ + method_AEEApplet_onInit = jeff_lookup_method(class_AEEApplet, "onInit", 0, d); + if (!method_AEEApplet_onInit) { + app_manager_printf("App Manager start failed: resolve method Applet.onInit() failed.\n"); + return false; + } + + /* Resolve method com.intel.aee.AEEApplet.onDestroy() */ + method_AEEApplet_onDestroy = jeff_lookup_method(class_AEEApplet, "onDestroy", 0, d); + if (!method_AEEApplet_onDestroy) { + app_manager_printf("App Manager start failed: resolve method AEEApplet.onDestroy() failed.\n"); + return false; + } + + /* Resolve method com.intel.aee.AEEApplet.callOnRequest(Request) */ + d1[0].class_header = class_AEERequest; + method_AEEApplet_callOnRequest = jeff_lookup_method(class_AEEApplet, "callOnRequest", 1, d1); + if (!method_AEEApplet_callOnRequest) { + app_manager_printf("App Manager start failed: resolve method AEEApplet.callOnRequest() failed.\n"); + return false; + } + + /* Resolve method com.intel.aee.Timer.callOnTimer() */ + method_callOnTimer = jeff_lookup_method(class_Timer, "callOnTimer", 0, d); + if (!method_callOnTimer) { + app_manager_printf("App Manager start failed: resolve method Timer.callOnTimer() failed.\n"); + return false; + } + + /* Resolve method com.intel.aee.Sensor.callOnSensorEvent() */ + method_callOnSensorEvent = jeff_lookup_method(class_Sensor, "callOnSensorEvent", 0, d); + if (!method_callOnSensorEvent) { + app_manager_printf("App Manager start failed: resolve method Sensor.callOnSensorEvent() failed.\n"); + return false; + } + + /* Resovle method com.intel.aee.ble.BLEManager.callOnBLEStartDiscovery(BLEDevice) */ + d1[0].class_header = class_BLEDevice; + method_callOnBLEStartDiscovery = jeff_lookup_method(class_BLEManager, "callOnBLEStartDiscovery", 1, d1); + if (!method_callOnBLEStartDiscovery) { + app_manager_printf("App Manager start failed: resolve method BLEManager.callOnBLEStartDiscovery() failed.\n"); + return false; + } + + /* Resovle method com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice) */ + JeffDescriptorFull d2_1[] = { {JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, class_BLEDevice}, + { JEFF_TYPE_INT, 0, NULL}, + { JEFF_TYPE_VOID, 0, NULL}}; + method_callOnBLEConnected = jeff_lookup_method(class_BLEManager, "callOnBLEConnected", 2, d2_1); + if (!method_callOnBLEConnected) { + app_manager_printf("App Manager start failed: resolve method BLEManager.callOnBLEConnected() failed.\n"); + return false; + } + + /* Resovle method com.intel.aee.ble.BLEManager.method_callOnBLENotification(BLEDevice,byte[]) */ + JeffDescriptorFull d2_2[] = { {JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, class_BLEDevice}, + { JEFF_TYPE_BYTE | JEFF_TYPE_REF | JEFF_TYPE_MONO, 1, NULL}, + { JEFF_TYPE_INT, 0, NULL}, + { JEFF_TYPE_INT, 0, NULL}, + { JEFF_TYPE_VOID, 0, NULL}}; + method_callOnBLENotification = jeff_lookup_method(class_BLEManager, "callOnBLENotification", 4, d2_2); + if (!method_callOnBLENotification) { + app_manager_printf("App Manager start failed: resolve method BLEManager.callOnBLENotification() failed.\n"); + return false; + } + + /* Resovle method com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice,byte[]) */ + method_callOnBLEIndication = jeff_lookup_method(class_BLEManager, "callOnBLEIndication", 4, d2_2); + if (!method_callOnBLEIndication) { + app_manager_printf("App Manager start failed: resolve method BLEManager.callOnBLEIndication() failed.\n"); + return false; + } + + /* Resovle method com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice) */ + d1[0].class_header = class_BLEDevice; + method_callOnBLEDisconnected = jeff_lookup_method(class_BLEManager, "callOnBLEDisconnected", 1, d1); + if (!method_callOnBLEDisconnected) { + app_manager_printf("App Manager start failed: resolve method BLEManager.callOnBLEDisconnected() failed.\n"); + return false; + } + + /* Resovle method com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice) */ + method_callOnBLEPasskeyEntry = jeff_lookup_method(class_BLEManager, "callOnBLEPasskeyEntry", 1, d1); + if (!method_callOnBLEPasskeyEntry) { + app_manager_printf("App Manager start failed: resolve method BLEManager.callOnBLEPasskeyEntry() failed.\n"); + return false; + } + /* Resovle method void com.intel.aee.gpio.GPIOChannel.callOnGPIOInterrupt() */ + method_callOnGPIOInterrupt = jeff_lookup_method(class_GPIOChannel, "callOnGPIOInterrupt", 0, d); + if (!method_callOnGPIOInterrupt) { + app_manager_printf("App Manager start failed: resolve method GPIOChannel.callOnGPIOInterrupt() failed.\n"); + return false; + } + + JeffDescriptorFull d2[] = { {JEFF_TYPE_BYTE | JEFF_TYPE_REF | JEFF_TYPE_MONO, 1, NULL}, + { JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, class_BLEDevice}}; + /* Resovle method com.intel.aee.ble.BLEManager.getBLEDevice(byte []) */ + method_callOnBLEManagerGetBLEDevice = jeff_lookup_method(class_BLEManager, + "getBLEDevice", 1, d2); + if (!method_callOnBLEManagerGetBLEDevice) { + app_manager_printf( + "App Manager start failed: resolve method BLEManager.getBLEDevice() failed.\n"); + return false; + } + + return true; + } + + static void + jeff_module_watchdog_kill(module_data *m_data) + { + jeff_applet_data *applet_data = (jeff_applet_data*)m_data->internal_data; + + app_manager_printf("Watchdog interrupt the applet %s\n", m_data->module_name); + + jeff_runtime_interrupt_instance(applet_data->vm_instance, true); + + /* Exit applet queue loop run */ + bh_queue_exit_loop_run(m_data->queue); + + /* Wait the end of the applet instance. If timeout, it means applet + * is busy executing native code, then try to cancle the main thread. */ + if (applet_data->vm_instance->main_file) + jeff_runtime_wait_for_instance(applet_data->vm_instance, 3000); + + if (applet_data->vm_instance->main_file) { + app_manager_printf("Watchdog cancel applet main thread.\n"); + vm_thread_cancel(applet_data->vm_instance->main_tlr.handle); + /* k_thread_abort(applet_data->vm_instance->main_tlr.handle); */ + } + + send_exception_event_to_host(m_data->module_name, "java.lang.InterruptedException"); + cleanup_applet_resource(m_data); + app_manager_printf("Watchdog interrupt Jeff applet done.\n"); + } + + static bool + jeff_module_handle_host_url(void *queue_msg) + { +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + bh_queue_msg_t *msg = (bh_queue_msg_t *)queue_msg; + + if (msg->message_type == COAP_PARSED) { + coap_packet_t *packet = (coap_packet_t *)msg->payload; + attr_container_t *attr_cont = (attr_container_t *)packet->payload; + const char *url = NULL; + int url_len = 0, mid; + + bh_memcpy_s(&mid, sizeof(uint32), packet->token, sizeof(uint32)); + url_len = coap_get_header_uri_path(packet, &url); + + /* Send request to tool agent */ + if (url_len >= 12 && memcmp(url, "/tool_agent/", 12) == 0) { + module_data *m_data; + jeff_applet_data *applet_data; + unsigned attr_cont_len = 0, req_msg_len; + bh_queue_msg_t *tool_agent_msg; + bh_request_msg_t *req_msg; + char url_buf[256] = {0}, *p = url_buf; + char applet_name[128] = {0}; + + /* Resolve applet name */ + bh_memcpy_s(url_buf, sizeof(url_buf), url + 12, url_len - 12); + while (*p != '/' && *p != '\0') + p++; + + bh_memcpy_s(applet_name, sizeof(applet_name), url_buf, p - url_buf); + app_manager_printf("Send request to tool agent of applet: %s\n", applet_name); + + /* Check applet name */ + if (!(m_data = app_manager_lookup_module_data(applet_name))) { + SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: invalid applet name"); + return false; + } + + applet_data = (jeff_applet_data*)m_data->internal_data; + /* Attach debug: start the tool agent firstly */ + if (packet->code == COAP_PUT) { + if (is_tool_agent_running(m_data)) { + SEND_ERR_RESPONSE(mid, "Attach debug failed: tool agent is already exist."); + return false; + } + + applet_data->debug_mode = true; + + /* Create tool agent queue */ + if (!(applet_data->tool_agent_queue = bh_queue_create())) { + SEND_ERR_RESPONSE(mid, "Attach debug failed: create tool agent queue failed."); + return false; + } + + /* Start tool agent thread */ + if (!jeff_tool_start_agent(applet_data->vm_instance, applet_data->tool_agent_queue)) { + bh_queue_destroy(applet_data->tool_agent_queue, NULL); + SEND_ERR_RESPONSE(mid, "Attach debug failed: start tool agent failed"); + return false; + } + + app_manager_printf("Attach debug: start tool agent of applet %s success.\n", applet_name); + app_send_response_to_host(mid, CREATED_2_01, NULL); /* OK */ + } else { + /* Check tool agent running */ + if (!is_tool_agent_running(m_data)) { + SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: tool agent is not running"); + return false; + } + + /* Create queue message for tool agent */ + if (!(tool_agent_msg = bh_malloc(sizeof(bh_queue_msg_t)))) { + SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: allocate memory failed"); + return false; + } + + if (attr_cont) + attr_cont_len = attr_container_get_serialize_length(attr_cont); + + req_msg_len = sizeof(bh_request_msg_t) + strlen(p) + 1 + attr_cont_len; + + /* Create request message */ + if (!(req_msg = bh_malloc(req_msg_len))) { + SEND_ERR_RESPONSE(mid, "Send request to applet failed: allocate memory failed"); + bh_free(tool_agent_msg); + return false; + } + + /* Set request message */ + memset(req_msg, 0, req_msg_len); + req_msg->mid = mid; + req_msg->url = (char*)req_msg + sizeof(bh_request_msg_t); + bh_strcpy_s(req_msg->url, strlen(p)+1, p); /* Actual url sent to tool agent */ + req_msg->action = packet->code; + req_msg->fmt = 0; + if (attr_cont) { + req_msg->payload = (char*)req_msg + sizeof(bh_request_msg_t) + + strlen(p) + 1; + attr_container_serialize(req_msg->payload, attr_cont); + } + + /* Set queue message and send to tool agent's queue */ + tool_agent_msg->message_type = JDWP_REQUEST; + tool_agent_msg->payload_size = req_msg_len; + tool_agent_msg->payload = (char*)req_msg; + if (!bh_queue_send_message(applet_data->tool_agent_queue, tool_agent_msg)) { + bh_free(req_msg); + bh_free(tool_agent_msg); + SEND_ERR_RESPONSE + (mid, "Send request to tool agent failed: send queue msg failed."); + return false; + } + + /* app_manager_printf("Send request to tool agent of applet %s success.\n", applet_name); */ + } + + return true; + } + } +#endif /* BEIHAI_ENABLE_TOOL_AGENT != 0 */ + return false; + } + + static module_data* + jeff_module_get_module_data(void) + { + JeffThreadLocalRoot *self = jeff_runtime_get_tlr(); + return (module_data *)self->il_root->start_routine_arg; + } + +#if BEIHAI_ENABLE_TOOL_AGENT != 0 + +#define JDWP_HANDSHAKE_MAGIC "JDWP-Handshake" +#define JDWP_HANDSHAKE_LEN (sizeof (JDWP_HANDSHAKE_MAGIC) - 1) + +#define JDWP_PAYLOAD_KEY "jdwp" + + static bool debug = true; + + static bool + send_msg_to_host (int mid, const char *url, int code, const uint8 *msg, unsigned size) + { + bool ret; + int payload_len = 0; + attr_container_t *payload = NULL; + + if (msg) { + if ((payload = attr_container_create(""))) { + attr_container_set_bytearray(&payload, JDWP_PAYLOAD_KEY, (const int8_t *)msg, size); + payload_len = attr_container_get_serialize_length(payload); + } + } + ret = app_send_msg_to_host(mid, url, code, (char*)payload, payload_len); + + if (payload) + attr_container_destroy(payload); + + return ret; + } + + static bool + send_response(int mid, int code, const uint8 *msg, unsigned size) + { + return send_msg_to_host(mid, NULL, code, msg, size); + } + + static bool + send_packet_response(int mid, int code, JeffBuffer *packet) + { + int size; + + if ((size = jeff_buffer_size(packet)) == 0) + /* No data need to be written, succeed. */ + return true; + + return send_msg_to_host(mid, NULL, code, jeff_buffer_at(packet, 0), size); + } + + void + jeff_tool_event_publish(uint8 *evtbuf, unsigned size) + { + char *prefix = "/jdwp/", *url = NULL; + int url_len; + + url_len = strlen(prefix) + strlen(app_manager_get_module_name(Module_Jeff)); + if (NULL == (url = jeff_runtime_malloc(url_len + 1))) + return; + + bh_strcpy_s(url,url_len + 1, prefix); + bh_strcat_s(url,url_len + 1, app_manager_get_module_name(Module_Jeff)); + + /* Event is sent as request so we set code as COAP_PUT */ + if (event_is_registered(url)) + send_msg_to_host(0, url, COAP_PUT, evtbuf, size); + + jeff_runtime_free(url); + } + +#define SEND_ERROR_RESPONSE(err_msg) do { \ + app_manager_printf("%s\n", err_msg); \ + send_response(req_msg->mid, INTERNAL_SERVER_ERROR_5_00,\ + (uint8 *)err_msg, strlen(err_msg) + 1); \ + } while (0) + + /* Queue callback of tool agent */ + void + tool_agent_queue_callback(void *arg) + { + bh_queue_msg_t *msg = (bh_queue_msg_t*)arg; + + if (msg->message_type == JDWP_REQUEST) { + bh_request_msg_t *req_msg = (bh_request_msg_t*)msg->payload; + attr_container_t *attr_cont = (attr_container_t*)req_msg->payload; + JeffThreadLocalRoot *self = jeff_runtime_get_tlr(); + JeffInstanceLocalRoot *cur_instance = self->il_root; + JeffToolAgent *agent = cur_instance->tool_agent; + bh_queue *queue = (bh_queue *)self->start_routine_arg; + + if (debug) + app_manager_printf("Tool Agent of applet %s got request, url %s, action %d\n", + app_manager_get_module_name(Module_Jeff), req_msg->url, req_msg->action); + + /* Handshake or Process Request */ + if (req_msg->action == COAP_GET) { + uint8 *buf; + unsigned buf_len; + + if (!attr_cont + || !(buf = (uint8*) + attr_container_get_as_bytearray(attr_cont, JDWP_PAYLOAD_KEY, &buf_len))) { + SEND_ERROR_RESPONSE("Tool Agent fail: invalid JDWP payload."); + goto fail; + } + + if (!agent->connected) { + if (buf_len != JDWP_HANDSHAKE_LEN + || memcmp (buf, JDWP_HANDSHAKE_MAGIC, JDWP_HANDSHAKE_LEN)) { + SEND_ERROR_RESPONSE("Tool Agent fail: handshake fail."); + goto fail; + } + + /* Handshake success and response */ + agent->connected = true; + send_response(req_msg->mid, CONTENT_2_05, buf, buf_len); + } else { + /* TODO: tool-agent thread should reuse the request/reply buffer to avoid allocating memory repeatedly */ + JeffBuffer request, reply; + + /* Initialize the package buffers. */ + jeff_buffer_init(&request); + jeff_buffer_init(&reply); + + if (!jeff_buffer_resize(&request, buf_len)) { + SEND_ERROR_RESPONSE("Tool Agent fail: resize buffer fail."); + jeff_buffer_destroy(&request); + jeff_buffer_destroy(&reply); + goto fail; + } + + /* Copy data from request to jeff buffer */ + bh_memcpy_s(jeff_buffer_at(&request, 0), jeff_buffer_size(&request), buf, buf_len); + + /* Handle JDWP request */ + if (!jeff_tool_handle_packet(agent, &request, &reply)) { + SEND_ERROR_RESPONSE("Tool agent fail: handle request fail."); + jeff_buffer_destroy(&request); + jeff_buffer_destroy(&reply); + goto fail; + } + + /* Response JDWP reply */ + send_packet_response(req_msg->mid, CONTENT_2_05, &reply); + + /* Destroy the package buffers. */ + jeff_buffer_destroy(&request); + jeff_buffer_destroy(&reply); + } + } + /* Debugger disconnect */ + else if (req_msg->action == COAP_DELETE) { + send_response(req_msg->mid, DELETED_2_02, NULL, 0); + bh_queue_exit_loop_run(queue); + } + else { + SEND_ERROR_RESPONSE("Tool agent fail: invalid request."); + goto fail; + } + + bh_free(req_msg); + bh_free(msg); + return; + + fail: + bh_queue_exit_loop_run(queue); + bh_free(req_msg); + } + + bh_free(msg); + } + + void + tool_agent_queue_free_callback(void *message) + { + bh_queue_msg_t *msg = (bh_queue_msg_t*)message; + + if (msg->message_type == JDWP_REQUEST) { + bh_request_msg_t *req_msg = (bh_request_msg_t*)msg->payload; + bh_free(req_msg); + } + + bh_free(msg); + } + +#endif /* BEIHAI_ENABLE_TOOL_AGENT != 0 */ + + module_interface jeff_module_interface = { + jeff_module_init, + jeff_module_install, + jeff_module_uninstall, + jeff_module_watchdog_kill, + jeff_module_handle_host_url, + jeff_module_get_module_data, + NULL + }; + +#endif diff --git a/core/app-mgr/app-manager/module_jeff.h b/core/app-mgr/app-manager/module_jeff.h new file mode 100644 index 000000000..db3961199 --- /dev/null +++ b/core/app-mgr/app-manager/module_jeff.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MODULE_JEFF_H_ +#define _MODULE_JEFF_H_ + +#include "app_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern module_interface jeff_module_interface; + +/* sensor event */ +typedef struct bh_sensor_event_t { + /* Java sensor object */ + void *sensor; + /* event of attribute container from context core */ + void *event; +} bh_sensor_event_t; + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _MODULE_JEFF_H_ */ diff --git a/core/app-mgr/app-manager/module_utils.c b/core/app-mgr/app-manager/module_utils.c new file mode 100644 index 000000000..95b59f06e --- /dev/null +++ b/core/app-mgr/app-manager/module_utils.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app_manager.h" +#include "app_manager_host.h" +#include "bh_queue.h" +#include "bh_memory.h" +#include "bh_thread.h" +#include "attr_container.h" +#include "event.h" +#include "watchdog.h" +#include "coap_ext.h" + +/* Lock of the module data list */ +korp_mutex module_data_list_lock; + +/* Module data list */ +module_data *module_data_list; + +bool module_data_list_init() +{ + module_data_list = NULL; + return !vm_mutex_init(&module_data_list_lock) ? true : false; +} + +void module_data_list_destroy() +{ + + vm_mutex_lock(&module_data_list_lock); + if (module_data_list) { + while (module_data_list) { + module_data *p = module_data_list->next; + bh_free(module_data_list); + module_data_list = p; + } + } + vm_mutex_unlock(&module_data_list_lock); + vm_mutex_destroy(&module_data_list_lock); +} + +static void module_data_list_add(module_data *m_data) +{ + static uint32 module_id_max = 1; + vm_mutex_lock(&module_data_list_lock); + // reserve some special ID + // TODO: check the new id is not already occupied! + if (module_id_max == 0xFFFFFFF0) + module_id_max = 1; + m_data->id = module_id_max++; + if (!module_data_list) { + module_data_list = m_data; + } else { + /* Set as head */ + m_data->next = module_data_list; + module_data_list = m_data; + } + vm_mutex_unlock(&module_data_list_lock); +} + +void module_data_list_remove(module_data *m_data) +{ + vm_mutex_lock(&module_data_list_lock); + if (module_data_list) { + if (module_data_list == m_data) + module_data_list = module_data_list->next; + else { + /* Search and remove it */ + module_data *p = module_data_list; + + while (p && p->next != m_data) + p = p->next; + if (p && p->next == m_data) + p->next = p->next->next; + } + } + vm_mutex_unlock(&module_data_list_lock); +} + +module_data* +module_data_list_lookup(const char *module_name) +{ + vm_mutex_lock(&module_data_list_lock); + if (module_data_list) { + module_data *p = module_data_list; + + while (p) { + /* Search by module name */ + if (!strcmp(module_name, p->module_name)) { + vm_mutex_unlock(&module_data_list_lock); + return p; + } + p = p->next; + } + } + vm_mutex_unlock(&module_data_list_lock); + return NULL; +} + +module_data* +module_data_list_lookup_id(unsigned int module_id) +{ + vm_mutex_lock(&module_data_list_lock); + if (module_data_list) { + module_data *p = module_data_list; + + while (p) { + /* Search by module name */ + if (module_id == p->id) { + vm_mutex_unlock(&module_data_list_lock); + return p; + } + p = p->next; + } + } + vm_mutex_unlock(&module_data_list_lock); + return NULL; +} + +module_data * +app_manager_get_module_data(uint32 module_type) +{ + if (g_module_interfaces[module_type] + && g_module_interfaces[module_type]->module_get_module_data) + return g_module_interfaces[module_type]->module_get_module_data(); + return NULL; +} + +void* +app_manager_get_module_queue(uint32 module_type) +{ + return app_manager_get_module_data(module_type)->queue; +} + +const char* +app_manager_get_module_name(uint32 module_type) +{ + return app_manager_get_module_data(module_type)->module_name; +} + +unsigned int app_manager_get_module_id(uint32 module_type) +{ + return app_manager_get_module_data(module_type)->id; +} + +void* +app_manager_get_module_heap(uint32 module_type) +{ + return app_manager_get_module_data(module_type)->heap; +} + +module_data* +app_manager_lookup_module_data(const char *name) +{ + return module_data_list_lookup(name); +} + +void app_manager_add_module_data(module_data *m_data) +{ + module_data_list_add(m_data); +} + +void app_manager_del_module_data(module_data *m_data) +{ + module_data_list_remove(m_data); + + release_module(m_data); +} + +bool app_manager_is_interrupting_module(uint32 module_type) +{ + return app_manager_get_module_data(module_type)->wd_timer.is_interrupting; +} + +extern void destory_module_timer_ctx(unsigned int module_id); + +void release_module(module_data *m_data) +{ + watchdog_timer_destroy(&m_data->wd_timer); + +#ifdef HEAP_ENABLED /* TODO */ + if(m_data->heap) gc_destroy_for_instance(m_data->heap); +#endif + + if (m_data->queue) + bh_queue_destroy(m_data->queue); + + m_data->timer_ctx = NULL; + + destory_module_timer_ctx(m_data->id); + + bh_free(m_data); +} + +int check_modules_timer_expiry() +{ + vm_mutex_lock(&module_data_list_lock); + module_data *p = module_data_list; + int ms_to_expiry = -1; + + while (p) { + + int next = get_expiry_ms(p->timer_ctx); + if (next != -1) { + if (ms_to_expiry == -1 || ms_to_expiry > next) + ms_to_expiry = next; + } + + p = p->next; + } + vm_mutex_unlock(&module_data_list_lock); + return ms_to_expiry; +} + diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c new file mode 100644 index 000000000..3958520a7 --- /dev/null +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -0,0 +1,992 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_wasm_app.h" + +#include "native_interface.h" /* for request_t type */ +#include "app_manager_host.h" +#include "bh_queue.h" +#include "attr_container.h" +#include "bh_thread.h" +#include "bh_memory.h" +#include "coap_ext.h" +#include "event.h" +#include "watchdog.h" +#include "runtime_lib.h" + +/* Wasm app 4 magic bytes */ +static unsigned char wasm_app_magics[] = { (unsigned char) 0x00, + (unsigned char) 0x61, (unsigned char) 0x73, (unsigned char) 0x6d }; + +/* Wasm app 4 version bytes */ +static unsigned char wasm_app_version[] = { (unsigned char) 0x01, + (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00 }; + +/* Wasm App Install Request Receiving Phase */ +typedef enum wasm_app_install_req_recv_phase_t { + Phase_Req_Ver, + Phase_Req_Action, + Phase_Req_Fmt, + Phase_Req_Mid, + Phase_Req_Sender, + Phase_Req_Url_Len, + Phase_Req_Payload_Len, /* payload is wasm app binary */ + Phase_Req_Url, + Phase_Wasm_Magic, + Phase_Wasm_Version, + Phase_Wasm_Section_Type, + Phase_Wasm_Section_Size, + Phase_Wasm_Section_Content +} wasm_app_install_req_recv_phase_t; + +/* Message for insall wasm app */ +typedef struct install_wasm_app_msg_t { + uint8_t request_version; + uint8_t request_action; + uint16_t request_fmt; + uint32_t request_mid; + uint32_t request_sender; + uint16_t request_url_len; + uint32_t wasm_app_size; /* payload size is just wasm app binary size */ + char *request_url; + wasm_app_file_t wasm_app_binary; +} install_wasm_app_msg_t; + +/* Wasm App Install Request Receive Context */ +typedef struct wasm_app_install_req_recv_ctx_t { + wasm_app_install_req_recv_phase_t phase; + int size_in_phase; + install_wasm_app_msg_t message; + int total_received_size; +} wasm_app_install_req_recv_ctx_t; + +/* Current wasm bytecode app install request receive context */ +static wasm_app_install_req_recv_ctx_t recv_ctx; + +static bool wasm_app_module_init(void); +static bool wasm_app_module_install(request_t *msg); +static bool wasm_app_module_uninstall(request_t *msg); +static void wasm_app_module_watchdog_kill(module_data *module_data); +static bool wasm_app_module_handle_host_url(void *queue_msg); +static module_data *wasm_app_module_get_module_data(void); +static bool +wasm_app_module_on_install_request_byte_arrive(uint8 ch, int request_total_size, + int *received_size); + +static bool module_wasm_app_handle_install_msg(install_wasm_app_msg_t *message); +static void destroy_wasm_sections_list(wasm_section_t *sections); +static void destroy_wasm_section_from_list(wasm_section_t **sections, int type); + +#define Max_Msg_Callback 10 +int g_msg_type[Max_Msg_Callback] = { 0 }; +message_type_handler_t g_msg_callbacks[Max_Msg_Callback] = { 0 }; + +#define Max_Cleanup_Callback 10 +static resource_cleanup_handler_t g_cleanup_callbacks[Max_Cleanup_Callback] = { + 0 }; + +module_interface wasm_app_module_interface = { wasm_app_module_init, + wasm_app_module_install, wasm_app_module_uninstall, + wasm_app_module_watchdog_kill, wasm_app_module_handle_host_url, + wasm_app_module_get_module_data, + wasm_app_module_on_install_request_byte_arrive }; + +static unsigned align_uint(unsigned v, unsigned b) +{ + unsigned m = b - 1; + return (v + m) & ~m; +} + +static void app_instance_queue_callback(void *queue_msg) +{ + uint32 argv[2]; + wasm_function_inst_t func_onRequest, func_onTimer; + + module_data *m_data = app_manager_get_module_data(Module_WASM_App); + wasm_data *wasm_app_data = (wasm_data*) m_data->internal_data; + wasm_module_inst_t inst = wasm_app_data->wasm_module_inst; + int message_type = bh_message_type(queue_msg); + + switch (message_type) { + case RESTFUL_REQUEST: { + request_t *request = (request_t *) bh_message_payload(queue_msg); + int size; + char *buffer; + int32 buffer_offset; + + app_manager_printf("App %s got request, url %s, action %d\n", + m_data->module_name, request->url, request->action); + + func_onRequest = wasm_runtime_lookup_function(inst, "_on_request", + "(i32i32)"); + if (!func_onRequest) { + app_manager_printf("Cannot find function onRequest\n"); + break; + } + + buffer = pack_request(request, &size); + if (buffer == NULL) + break; + + buffer_offset = wasm_runtime_module_dup_data(inst, buffer, size); + if (buffer_offset == 0) { + app_manager_printf("Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + free_req_resp_packet(buffer); + break; + } + + free_req_resp_packet(buffer); + + argv[0] = (uint32) buffer_offset; + argv[1] = (uint32) size; + + if (!wasm_runtime_call_wasm(inst, NULL, func_onRequest, 2, argv)) { + app_manager_printf("Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + wasm_runtime_module_free(inst, buffer_offset); + break; + } + + wasm_runtime_module_free(inst, buffer_offset); + app_manager_printf("Wasm app process request success.\n"); + break; + } + case RESTFUL_RESPONSE: { + response_t *response = (response_t *) bh_message_payload(queue_msg); + int size; + char *buffer; + int32 buffer_offset; + + app_manager_printf("App %s got response_t,status %d\n", + m_data->module_name, response->status); + + wasm_function_inst_t func_onResponse = wasm_runtime_lookup_function( + inst, "_on_response", "(i32i32)"); + if (!func_onResponse) { + app_manager_printf("Cannot find function on_response\n"); + break; + } + + buffer = pack_response(response, &size); + if (buffer == NULL) + break; + + buffer_offset = wasm_runtime_module_dup_data(inst, buffer, size); + if (buffer_offset == 0) { + app_manager_printf("Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + free_req_resp_packet(buffer); + break; + } + + free_req_resp_packet(buffer); + + argv[0] = (uint32) buffer_offset; + argv[1] = (uint32) size; + + if (!wasm_runtime_call_wasm(inst, NULL, func_onResponse, 2, argv)) { + app_manager_printf("Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + wasm_runtime_module_free(inst, buffer_offset); + break; + } + + wasm_runtime_module_free(inst, buffer_offset); + app_manager_printf("Wasm app process response success.\n"); + break; + } + + case TIMER_EVENT_WASM: { + if (bh_message_payload(queue_msg)) { + /* Call Timer.callOnTimer() method */ + func_onTimer = wasm_runtime_lookup_function(inst, + "_on_timer_callback", "(i32)"); + + if (!func_onTimer) { + app_manager_printf("Cannot find function _on_timer_callback\n"); + break; + } + unsigned int timer_id = (unsigned int) bh_message_payload( + queue_msg); + argv[0] = timer_id; + if (!wasm_runtime_call_wasm(inst, NULL, func_onTimer, 1, argv)) { + app_manager_printf("Got exception running wasm code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + } + } + + break; + } + + default: { + for (int i = 0; i < Max_Msg_Callback; i++) { + if (g_msg_type[i] == message_type) { + g_msg_callbacks[i](m_data, queue_msg); + return; + } + } + app_manager_printf("Invalid message type of WASM app queue message.\n"); + break; + } + } +} + +/* WASM app thread main routine */ +static void* +wasm_app_routine(void *arg) +{ + wasm_function_inst_t func_onInit; + wasm_function_inst_t func_onDestroy; + + module_data *m_data = (module_data *) arg; + wasm_data *wasm_app_data = (wasm_data*) m_data->internal_data; + wasm_module_inst_t inst = wasm_app_data->wasm_module_inst; + korp_tid thread = wasm_app_data->thread_id; + + /* attach newly created thread to the VM managed instance */ + if (!wasm_runtime_attach_current_thread(inst, m_data)) { + goto fail1; + } + app_manager_printf("WASM app '%s' started\n", m_data->module_name); + + /* Call app's onInit() method */ + func_onInit = wasm_runtime_lookup_function(inst, "_on_init", "()"); + if (!func_onInit) { + app_manager_printf("Cannot find function on_init().\n"); + goto fail2; + } + + if (!wasm_runtime_call_wasm(inst, NULL, func_onInit, 0, NULL)) { + printf("Got exception running WASM code: %s\n", + wasm_runtime_get_exception(inst)); + wasm_runtime_clear_exception(inst); + /* call on_destroy() in case some resources are opened in on_init() + * and then exception thrown */ + goto fail3; + } + + /* Enter queue loop run to receive and process applet queue message */ + bh_queue_enter_loop_run(m_data->queue, app_instance_queue_callback); + + app_manager_printf("App instance main thread exit.\n"); + + fail3: + /* Call WASM app onDestroy() method if there is */ + func_onDestroy = wasm_runtime_lookup_function(inst, "_on_destroy", "()"); + if (func_onDestroy) + wasm_runtime_call_wasm(inst, NULL, func_onDestroy, 0, NULL); + + fail2: wasm_runtime_detach_current_thread(inst); + + fail1: + vm_thread_detach(thread); + vm_thread_exit(NULL); + + return NULL; +} + +static void cleanup_app_resource(module_data *m_data) +{ + int i; + wasm_data *wasm_app_data = (wasm_data*) m_data->internal_data; + + am_cleanup_registeration(m_data->id); + + am_unregister_event(NULL, m_data->id); + + for (i = 0; i < Max_Cleanup_Callback; i++) { + if (g_cleanup_callbacks[i] != NULL) + g_cleanup_callbacks[i](m_data->id); + else + break; + } + + wasm_runtime_deinstantiate(wasm_app_data->wasm_module_inst); + + /* Destroy remain sections (i.e. data segment section) from list. */ + destroy_wasm_sections_list(wasm_app_data->sections); + + if (wasm_app_data->wasm_module) + wasm_runtime_unload(wasm_app_data->wasm_module); + + /* Destroy watchdog timer */ + watchdog_timer_destroy(&m_data->wd_timer); + + /* Remove module data from module data list and free it */ + app_manager_del_module_data(m_data); + +} + +/************************************************************/ +/* Module specific functions implementation */ +/************************************************************/ + +static bool wasm_app_module_init(void) +{ + /* Initialize WASM VM*/ + if (!wasm_runtime_init()) { + app_manager_printf("WASM runtime environment initialization failed.\n"); + return false; + } + + return true; +} + +#define APP_NAME_MAX_LEN 128 +#define MAX_INT_STR_LEN 11 + +static bool wasm_app_module_install(request_t * msg) +{ + unsigned int m_data_size, wasm_app_aot_file_len, heap_size, timeout, timers, + err_size; + char *properties; + int properties_offset, i; + uint8 *wasm_app_aot_file; + wasm_app_file_t *wasm_app_file; + wasm_data *wasm_app_data; + package_type_t package_type; + module_data *m_data; + wasm_module_t module = NULL; + wasm_module_inst_t inst = NULL; + char m_name[APP_NAME_MAX_LEN] = { 0 }, timeout_str[MAX_INT_STR_LEN] = { 0 }, + heap_size_str[MAX_INT_STR_LEN] = { 0 }, + timers_str[MAX_INT_STR_LEN] = { 0 }, err[256]; + /* Useless sections after load */ + uint8 sections1[] = { SECTION_TYPE_USER, + SECTION_TYPE_TYPE, + SECTION_TYPE_IMPORT, + SECTION_TYPE_FUNC, + SECTION_TYPE_TABLE, + SECTION_TYPE_MEMORY, + SECTION_TYPE_GLOBAL, + SECTION_TYPE_EXPORT, + SECTION_TYPE_START, + SECTION_TYPE_ELEM, + /*SECTION_TYPE_CODE,*/ + /*SECTION_TYPE_DATA*/}; + /* Useless sections after instantiate */ + uint8 sections2[] = { SECTION_TYPE_DATA }; + + err_size = sizeof(err); + + /* Check payload */ + if (!msg->payload || msg->payload_len == 0) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: invalid wasm file."); + return false; + } + + /* Check app name */ + properties_offset = check_url_start(msg->url, strlen(msg->url), "/applet"); + bh_assert(properties_offset > 0); + if (properties_offset <= 0) + return false; + properties = msg->url + properties_offset; + find_key_value(properties, strlen(properties), "name", m_name, + sizeof(m_name) - 1, '&'); + + if (strlen(m_name) == 0) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: invalid app name."); + return false; + } + + if (app_manager_lookup_module_data(m_name)) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: app already installed."); + return false; + } + + /* Parse heap size */ + heap_size = APP_HEAP_SIZE_DEFAULT; + find_key_value(properties, strlen(properties), "heap", heap_size_str, + sizeof(heap_size_str) - 1, '&'); + if (strlen(heap_size_str) > 0) { + heap_size = atoi(heap_size_str); + if (heap_size < APP_HEAP_SIZE_MIN) + heap_size = APP_HEAP_SIZE_MIN; + else if (heap_size > APP_HEAP_SIZE_MAX) + heap_size = APP_HEAP_SIZE_MAX; + } + + /* Judge the app type is AOTed or not */ + package_type = get_package_type((uint8 *) msg->payload, msg->payload_len); + + /* Load WASM file and instantiate*/ + if (package_type == Wasm_Module_AoT) { + wasm_app_aot_file = (uint8 *) msg->payload; + wasm_app_aot_file_len = msg->payload_len; + inst = wasm_runtime_load_aot(wasm_app_aot_file, wasm_app_aot_file_len, + heap_size, err, err_size); + if (!inst) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: load wasm aot binary failed."); + return false; + } + } else if (package_type == Wasm_Module_Bytecode) { + wasm_app_file = (wasm_app_file_t *) msg->payload; + module = wasm_runtime_load_from_sections(wasm_app_file->sections, err, + err_size); + if (!module) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: load WASM file failed."); + printf("error: %s\n", err); + destroy_wasm_sections_list(wasm_app_file->sections); + return false; + } + + /* Destroy useless sections from list after load */ + for (i = 0; i < sizeof(sections1); i++) + destroy_wasm_section_from_list(&wasm_app_file->sections, + sections1[i]); + + inst = wasm_runtime_instantiate(module, 0, heap_size, err, err_size); + if (!inst) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: instantiate wasm runtime failed."); + printf("error: %s\n", err); + wasm_runtime_unload(module); + destroy_wasm_sections_list(wasm_app_file->sections); + return false; + } + + /* Destroy useless sections from list after instantiate */ + for (i = 0; i < sizeof(sections2); i++) + destroy_wasm_section_from_list(&wasm_app_file->sections, + sections2[i]); + + } else { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: invalid wasm package type."); + return false; + } + + /* Create module data including the wasm_app_data as its internal_data*/ + m_data_size = offsetof(module_data, module_name) + strlen(m_name) + 1; + m_data_size = align_uint(m_data_size, 4); + m_data = bh_malloc(m_data_size + sizeof(wasm_data)); + if (!m_data) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: allocate memory failed."); + goto fail; + } + memset(m_data, 0, m_data_size + sizeof(wasm_data)); + + m_data->module_type = Module_WASM_App; + m_data->internal_data = (uint8*) m_data + m_data_size; + wasm_app_data = (wasm_data*) m_data->internal_data; + wasm_app_data->wasm_module_inst = inst; + wasm_app_data->wasm_module = module; + wasm_app_data->m_data = m_data; + wasm_app_data->sections = wasm_app_file->sections; + + /* Set module data - name and module type */ + bh_strcpy_s(m_data->module_name, strlen(m_name) + 1, m_name); + + /* Set module data - execution timeout */ + timeout = DEFAULT_WATCHDOG_INTERVAL; + find_key_value(properties, strlen(properties), "wd", timeout_str, + sizeof(timeout_str) - 1, '&'); + if (strlen(timeout_str) > 0) + timeout = atoi(timeout_str); + m_data->timeout = timeout; + + /* Set module data - create queue */ + m_data->queue = bh_queue_create(); + if (!m_data->queue) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: create app queue failed."); + goto fail; + } + + /* Set heap size */ + m_data->heap_size = heap_size; + + /* Set module data - timers number */ + timers = DEFAULT_TIMERS_PER_APP; + find_key_value(properties, strlen(properties), "timers", timers_str, + sizeof(timers_str) - 1, '&'); + if (strlen(timers_str) > 0) { + timers = atoi(timers_str); + if (timers > MAX_TIMERS_PER_APP) + timers = MAX_TIMERS_PER_APP; + } + + /* Attention: must add the module before start the thread! */ + app_manager_add_module_data(m_data); + + m_data->timer_ctx = create_wasm_timer_ctx(m_data->id, timers); + if (!m_data->timer_ctx) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: create app timers failed."); + goto fail; + } + + /* Initialize watchdog timer */ + if (!watchdog_timer_init(m_data)) { + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: create app watchdog timer failed."); + goto fail; + } + + /* create a thread. This thread may not dedicate for this WASM app. + WASM app instance needs to attach to one thread */ + if (vm_thread_create(&wasm_app_data->thread_id, wasm_app_routine, + (void*) m_data, APP_THREAD_STACK_SIZE_DEFAULT) != 0) { + module_data_list_remove(m_data); + SEND_ERR_RESPONSE(msg->mid, + "Install WASM app failed: create app threadf failed."); + + goto fail; + } + + /* only when thread is created it is the flag of installation success */ + app_manager_post_applets_update_event(); + + app_manager_printf("Install WASM app success!\n"); + send_error_response_to_host(msg->mid, CREATED_2_01, NULL); /* CREATED */ + + return true; + + fail: if (m_data) + release_module(m_data); + + wasm_runtime_deinstantiate(inst); + + if (package_type == Wasm_Module_Bytecode) + wasm_runtime_unload(module); + + if (package_type == Wasm_Module_Bytecode) + destroy_wasm_sections_list(wasm_app_file->sections); + + return false; +} + +/* Uninstall WASM app */ +static bool wasm_app_module_uninstall(request_t *msg) +{ + module_data *m_data; + wasm_data *wasm_app_data; + char m_name[APP_NAME_MAX_LEN] = { 0 }; + char *properties; + int properties_offset; + + properties_offset = check_url_start(msg->url, strlen(msg->url), "/applet"); + /* TODO: assert(properties_offset > 0) */ + if (properties_offset <= 0) + return false; + properties = msg->url + properties_offset; + find_key_value(properties, strlen(properties), "name", m_name, + sizeof(m_name) - 1, '&'); + + if (strlen(m_name) == 0) { + SEND_ERR_RESPONSE(msg->mid, + "Uninstall WASM app failed: invalid app name."); + return false; + } + + m_data = app_manager_lookup_module_data(m_name); + if (!m_data) { + SEND_ERR_RESPONSE(msg->mid, "Uninstall WASM app failed: no app found."); + return false; + } + + if (m_data->module_type != Module_WASM_App) { + SEND_ERR_RESPONSE(msg->mid, + "Uninstall WASM app failed: invalid module type."); + return false; + } + + if (m_data->wd_timer.is_interrupting) { + SEND_ERR_RESPONSE(msg->mid, + "Uninstall WASM app failed: app is being interrupted by watchdog."); + return false; + } + + /* Exit app queue loop run */ + bh_queue_exit_loop_run(m_data->queue); + + /* Wait for wasm app thread to exit */ + wasm_app_data = (wasm_data*) m_data->internal_data; + vm_thread_join(wasm_app_data->thread_id, NULL, -1); + + cleanup_app_resource(m_data); + + app_manager_post_applets_update_event(); + + app_manager_printf("Uninstall WASM app successful!\n"); + + send_error_response_to_host(msg->mid, DELETED_2_02, NULL); /* DELETED */ + return true; +} + +static bool wasm_app_module_handle_host_url(void *queue_msg) +{ + //todo: implement in future + app_manager_printf("App handles host url address %d\n", (int) queue_msg); + return false; +} + +static module_data* +wasm_app_module_get_module_data(void) +{ + return wasm_runtime_get_current_thread_data(); +} + +static void wasm_app_module_watchdog_kill(module_data *m_data) +{ + //todo: implement in future + app_manager_printf("Watchdog kills app: %s\n", m_data->module_name); + return; +} + +bool wasm_register_msg_callback(int message_type, + message_type_handler_t message_handler) +{ + int i; + int freeslot = -1; + for (i = 0; i < Max_Msg_Callback; i++) { + // replace handler for the same event registered + if (g_msg_type[i] == message_type) + break; + + if (g_msg_callbacks[i] == NULL && freeslot == -1) + freeslot = i; + } + + if (i != Max_Msg_Callback) + g_msg_callbacks[i] = message_handler; + else if (freeslot != -1) { + g_msg_callbacks[freeslot] = message_handler; + g_msg_type[freeslot] = message_type; + } else + return false; + + return true; +} + +bool wasm_register_cleanup_callback(resource_cleanup_handler_t handler) +{ + int i; + + for (i = 0; i < Max_Cleanup_Callback; i++) { + if (g_cleanup_callbacks[i] == NULL) { + g_cleanup_callbacks[i] = handler; + return true; + } + } + + return false; +} + +#define RECV_INTEGER(value, next_phase) do{ \ + unsigned char *p = (unsigned char *)&value; \ + p[recv_ctx.size_in_phase++] = ch; \ + if (recv_ctx.size_in_phase == sizeof(value)) { \ + if (sizeof(value) == 4) \ + value = ntohl(value); \ + else if (sizeof(value) == 2) \ + value = ntohs(value); \ + recv_ctx.phase = next_phase; \ + recv_ctx.size_in_phase = 0; \ + } \ +} while(0) + +/* return: + * 1: whole wasm app arrived + * 0: one valid byte arrived + * -1: fail to process the byte arrived, e.g. allocate memory fail + */ +static bool wasm_app_module_on_install_request_byte_arrive(uint8 ch, + int request_total_size, int *received_size) +{ + if (recv_ctx.phase == Phase_Req_Ver) { + recv_ctx.phase = Phase_Req_Ver; + recv_ctx.size_in_phase = 0; + recv_ctx.total_received_size = 0; + } + + recv_ctx.total_received_size++; + *received_size = recv_ctx.total_received_size; + + if (recv_ctx.phase == Phase_Req_Ver) { + if (ch != 1 /* REQUES_PACKET_VER from restful_utils.c */) + return false; + recv_ctx.phase = Phase_Req_Action; + return true; + } else if (recv_ctx.phase == Phase_Req_Action) { + recv_ctx.message.request_action = ch; + recv_ctx.phase = Phase_Req_Fmt; + recv_ctx.size_in_phase = 0; + return true; + } else if (recv_ctx.phase == Phase_Req_Fmt) { + RECV_INTEGER(recv_ctx.message.request_fmt, Phase_Req_Mid); + return true; + } else if (recv_ctx.phase == Phase_Req_Mid) { + RECV_INTEGER(recv_ctx.message.request_mid, Phase_Req_Sender); + return true; + } else if (recv_ctx.phase == Phase_Req_Sender) { + RECV_INTEGER(recv_ctx.message.request_sender, Phase_Req_Url_Len); + return true; + } else if (recv_ctx.phase == Phase_Req_Url_Len) { + unsigned char *p = (unsigned char *) &recv_ctx.message.request_url_len; + + p[recv_ctx.size_in_phase++] = ch; + if (recv_ctx.size_in_phase + == sizeof(recv_ctx.message.request_url_len)) { + recv_ctx.message.request_url_len = ntohs( + recv_ctx.message.request_url_len); + recv_ctx.message.request_url = bh_malloc( + recv_ctx.message.request_url_len + 1); + if (NULL == recv_ctx.message.request_url) + goto fail; + memset(recv_ctx.message.request_url, 0, + recv_ctx.message.request_url_len + 1); + recv_ctx.phase = Phase_Req_Payload_Len; + recv_ctx.size_in_phase = 0; + } + return true; + } else if (recv_ctx.phase == Phase_Req_Payload_Len) { + RECV_INTEGER(recv_ctx.message.wasm_app_size, Phase_Req_Url); + return true; + } else if (recv_ctx.phase == Phase_Req_Url) { + recv_ctx.message.request_url[recv_ctx.size_in_phase++] = ch; + if (recv_ctx.size_in_phase == recv_ctx.message.request_url_len) { + recv_ctx.phase = Phase_Wasm_Magic; + recv_ctx.size_in_phase = 0; + } + return true; + } else if (recv_ctx.phase == Phase_Wasm_Magic) { + /* start to receive wasm app binary */ + unsigned char *p = + (unsigned char *) &recv_ctx.message.wasm_app_binary.magic; + + if (ch == wasm_app_magics[recv_ctx.size_in_phase]) + p[recv_ctx.size_in_phase++] = ch; + else + goto fail; + + if (recv_ctx.size_in_phase + == sizeof(recv_ctx.message.wasm_app_binary.magic)) { + recv_ctx.phase = Phase_Wasm_Version; + recv_ctx.size_in_phase = 0; + } + + return true; + } else if (recv_ctx.phase == Phase_Wasm_Version) { + unsigned char *p = + (unsigned char *) &recv_ctx.message.wasm_app_binary.version; + + if (ch == wasm_app_version[recv_ctx.size_in_phase]) + p[recv_ctx.size_in_phase++] = ch; + else + goto fail; + + if (recv_ctx.size_in_phase + == sizeof(recv_ctx.message.wasm_app_binary.version)) { + recv_ctx.phase = Phase_Wasm_Section_Type; + recv_ctx.size_in_phase = 0; + } + + return true; + } else if (recv_ctx.phase == Phase_Wasm_Section_Type) { + wasm_section_t *new_section; + + if (!(new_section = (wasm_section_t *) bh_malloc(sizeof(wasm_section_t)))) + goto fail; + + memset(new_section, 0, sizeof(wasm_section_t)); + new_section->section_type = ch; + new_section->next = NULL; + + /* add the section to tail of link list */ + if (NULL == recv_ctx.message.wasm_app_binary.sections) { + recv_ctx.message.wasm_app_binary.sections = new_section; + recv_ctx.message.wasm_app_binary.section_end = new_section; + } else { + recv_ctx.message.wasm_app_binary.section_end->next = new_section; + recv_ctx.message.wasm_app_binary.section_end = new_section; + } + + recv_ctx.phase = Phase_Wasm_Section_Size; + recv_ctx.size_in_phase = 0; + + return true; + } else if (recv_ctx.phase == Phase_Wasm_Section_Size) { + /* the last section is the current receiving one */ + wasm_section_t *section = recv_ctx.message.wasm_app_binary.section_end; + uint32 byte; + + bh_assert(section); + + byte = ch; + + section->section_body_size |= ((byte & 0x7f) + << recv_ctx.size_in_phase * 7); + recv_ctx.size_in_phase++; + /* check leab128 overflow for uint32 value */ + if (recv_ctx.size_in_phase + > (sizeof(section->section_body_size) * 8 + 7 - 1) / 7) { + app_manager_printf(" LEB overflow when parsing section size\n"); + goto fail; + } + + if ((byte & 0x80) == 0) { + /* leb128 encoded section size parsed done */ + if (!(section->section_body = bh_malloc(section->section_body_size))) + goto fail; + recv_ctx.phase = Phase_Wasm_Section_Content; + recv_ctx.size_in_phase = 0; + } + + return true; + } else if (recv_ctx.phase == Phase_Wasm_Section_Content) { + /* the last section is the current receiving one */ + wasm_section_t *section = recv_ctx.message.wasm_app_binary.section_end; + + bh_assert(section); + + section->section_body[recv_ctx.size_in_phase++] = ch; + + if (recv_ctx.size_in_phase == section->section_body_size) { + if (recv_ctx.total_received_size == request_total_size) { + /* whole wasm app received */ + if (module_wasm_app_handle_install_msg(&recv_ctx.message)) { + bh_free(recv_ctx.message.request_url); + recv_ctx.message.request_url = NULL; + memset(&recv_ctx, 0, sizeof(recv_ctx)); + return true; + } else + goto fail; + } else { + recv_ctx.phase = Phase_Wasm_Section_Type; + recv_ctx.size_in_phase = 0; + return true; + } + } + + return true; + } + + fail: if (recv_ctx.message.wasm_app_binary.sections != NULL) { + destroy_wasm_sections_list(recv_ctx.message.wasm_app_binary.sections); + recv_ctx.message.wasm_app_binary.sections = NULL; + } + + if (recv_ctx.message.request_url != NULL) { + bh_free(recv_ctx.message.request_url); + recv_ctx.message.request_url = NULL; + } + + recv_ctx.phase = Phase_Req_Ver; + recv_ctx.size_in_phase = 0; + recv_ctx.total_received_size = 0; + + return false; +} + +static bool module_wasm_app_handle_install_msg(install_wasm_app_msg_t *message) +{ + request_t *request = NULL; + bh_message_t msg; + + request = (request_t *) bh_malloc(sizeof(request_t)); + if (request == NULL) + return false; + + memset(request, 0, sizeof(*request)); + request->action = message->request_action; + request->fmt = message->request_fmt; + request->url = bh_strdup(message->request_url); + request->sender = ID_HOST; + request->mid = message->request_mid; + request->payload_len = sizeof(message->wasm_app_binary); + request->payload = bh_malloc(request->payload_len); + + if (request->url == NULL || request->payload == NULL) { + request_cleaner(request); + return false; + } + + /* Request payload is set to wasm_app_file_t struct, + * but not whole app buffer */ + memcpy(request->payload, &message->wasm_app_binary, request->payload_len); + + /* Since it's a wasm app install request, so directly post to app-mgr's + * queue. The benefit is that section list can be freed when the msg + * failed to post to app-mgr's queue. The defect is missing url check. */ + if (!(msg = bh_new_msg(RESTFUL_REQUEST, request, sizeof(*request), + request_cleaner))) { + request_cleaner(request); + return false; + } + + if (!bh_post_msg2(get_app_manager_queue(), msg)) + return false; + + return true; +} + +static void destroy_wasm_sections_list(wasm_section_t *sections) +{ + wasm_section_t *cur = sections; + + /* App-manager-host and module_wasm won't access the + * section list concurrently, so need lock to protect. */ + + while (cur) { + wasm_section_t *next = cur->next; + if (cur->section_body != NULL) + bh_free(cur->section_body); + bh_free(cur); + cur = next; + } +} + +static void destroy_wasm_section_from_list(wasm_section_t **sections, int type) +{ + wasm_section_t *cur, *prev = NULL; + + /* App-manager-host and module_wasm won't access the + * section list concurrently, so need lock to protect. */ + + cur = *sections; + + while (cur) { + wasm_section_t *next = cur->next; + + if (type == cur->section_type) { + if (prev) + prev->next = next; + else + *sections = next; + + if (cur->section_body != NULL) + bh_free(cur->section_body); + bh_free(cur); + break; + } else { + prev = cur; + } + cur = next; + } +} diff --git a/core/app-mgr/app-manager/module_wasm_app.h b/core/app-mgr/app-manager/module_wasm_app.h new file mode 100644 index 000000000..dbdf80527 --- /dev/null +++ b/core/app-mgr/app-manager/module_wasm_app.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MODULE_WASM_APP_H_ +#define _MODULE_WASM_APP_H_ + +#include "bh_queue.h" +#include "app_manager_export.h" +#include "wasm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SECTION_TYPE_USER 0 +#define SECTION_TYPE_TYPE 1 +#define SECTION_TYPE_IMPORT 2 +#define SECTION_TYPE_FUNC 3 +#define SECTION_TYPE_TABLE 4 +#define SECTION_TYPE_MEMORY 5 +#define SECTION_TYPE_GLOBAL 6 +#define SECTION_TYPE_EXPORT 7 +#define SECTION_TYPE_START 8 +#define SECTION_TYPE_ELEM 9 +#define SECTION_TYPE_CODE 10 +#define SECTION_TYPE_DATA 11 + +enum { + WASM_Msg_Start = BASE_EVENT_MAX, TIMER_EVENT_WASM, SENSOR_EVENT_WASM, + + WASM_Msg_End = WASM_Msg_Start + 100 +}; + +typedef struct wasm_data { + /* for easily access the containing wasm module */ + wasm_module_t wasm_module; + wasm_module_inst_t wasm_module_inst; + /* Permissions of the WASM app */ + char *perms; + /*thread list mapped with this WASM module */ + korp_tid thread_id; + /* for easily access the containing module data */ + module_data* m_data; + /* section list of wasm bytecode */ + wasm_section_list_t sections; +} wasm_data; + +/* sensor event */ +typedef struct _sensor_event_data { + uint32 sensor_id; + + int data_fmt; + /* event of attribute container from context core */ + void *data; +} sensor_event_data_t; + +/* WASM App File */ +typedef struct wasm_app_file { + /* magics */ + int magic; + /* current version */ + int version; + /* WASM section list */ + wasm_section_list_t sections; + /* Last WASM section in the list */ + wasm_section_t *section_end; +} wasm_app_file_t; + +extern module_interface wasm_app_module_interface; + +typedef void (*message_type_handler_t)(module_data *m_data, bh_message_t msg); +extern bool wasm_register_msg_callback(int msg_type, + message_type_handler_t message_handler); + +typedef void (*resource_cleanup_handler_t)(uint32 module_id); +extern bool wasm_register_cleanup_callback(resource_cleanup_handler_t handler); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _MODULE_WASM_APP_H_ */ diff --git a/core/app-mgr/app-manager/module_wasm_lib.c b/core/app-mgr/app-manager/module_wasm_lib.c new file mode 100644 index 000000000..e4fc2d5a8 --- /dev/null +++ b/core/app-mgr/app-manager/module_wasm_lib.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "module_wasm_lib.h" + +static bool wasm_lib_module_init(void) +{ + return false; +} + +static bool wasm_lib_module_install(request_t *msg) +{ + (void) msg; + return false; +} + +static bool wasm_lib_module_uninstall(request_t *msg) +{ + (void) msg; + return false; +} + +static void wasm_lib_module_watchdog_kill(module_data *m_data) +{ + (void) m_data; +} + +static bool wasm_lib_module_handle_host_url(void *queue_msg) +{ + (void) queue_msg; + return false; +} + +static module_data* +wasm_lib_module_get_module_data(void) +{ + return NULL; +} + +module_interface wasm_lib_module_interface = { wasm_lib_module_init, + wasm_lib_module_install, wasm_lib_module_uninstall, + wasm_lib_module_watchdog_kill, wasm_lib_module_handle_host_url, + wasm_lib_module_get_module_data, + NULL }; + diff --git a/core/app-mgr/app-manager/module_wasm_lib.h b/core/app-mgr/app-manager/module_wasm_lib.h new file mode 100644 index 000000000..7482cddcf --- /dev/null +++ b/core/app-mgr/app-manager/module_wasm_lib.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MODULE_WASM_LIB_H_ +#define _MODULE_WASM_LIB_H_ + +#include "app_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern module_interface wasm_lib_module_interface; + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _MODULE_WASM_LIB_H_ */ diff --git a/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c b/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c new file mode 100644 index 000000000..cbfeb375b --- /dev/null +++ b/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app_manager.h" + +void* +app_manager_timer_create(void (*timer_callback)(void*), + watchdog_timer *wd_timer) +{ + /* TODO */ + return NULL; +} + +void app_manager_timer_destroy(void *timer) +{ + /* TODO */ +} + +void app_manager_timer_start(void *timer, int timeout) +{ + /* TODO */ +} + +void app_manager_timer_stop(void *timer) +{ + /* TODO */ +} + +watchdog_timer * +app_manager_get_wd_timer_from_timer_handle(void *timer) +{ + /* TODO */ + return NULL; +} + +int app_manager_signature_verify(const uint8_t *file, unsigned int file_len, + const uint8_t *signature, unsigned int sig_size) +{ + return 1; +} + diff --git a/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c b/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c new file mode 100644 index 000000000..074d359f9 --- /dev/null +++ b/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app_manager.h" +#include "bh_platform.h" +#include "bh_memory.h" +#include +#include +#include +#if 0 +#include +#endif +typedef struct k_timer_watchdog { + struct k_timer timer; + watchdog_timer *wd_timer; +} k_timer_watchdog; + +void* +app_manager_timer_create(void (*timer_callback)(void*), + watchdog_timer *wd_timer) +{ + struct k_timer_watchdog *timer = bh_malloc(sizeof(struct k_timer_watchdog)); + + if (timer) { + k_timer_init(&timer->timer, (void (*)(struct k_timer*)) timer_callback, + NULL); + timer->wd_timer = wd_timer; + } + + return timer; +} + +void app_manager_timer_destroy(void *timer) +{ + bh_free(timer); +} + +void app_manager_timer_start(void *timer, int timeout) +{ + k_timer_start(timer, timeout, 0); +} + +void app_manager_timer_stop(void *timer) +{ + k_timer_stop(timer); +} + +watchdog_timer * +app_manager_get_wd_timer_from_timer_handle(void *timer) +{ + return ((k_timer_watchdog*) timer)->wd_timer; +} +#if 0 +int app_manager_signature_verify(const uint8_t *file, unsigned int file_len, + const uint8_t *signature, unsigned int sig_size) +{ + return signature_verify(file, file_len, signature, sig_size); +} +#endif diff --git a/core/app-mgr/app-manager/resource_reg.c b/core/app-mgr/app-manager/resource_reg.c new file mode 100644 index 000000000..bbadcd03f --- /dev/null +++ b/core/app-mgr/app-manager/resource_reg.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "native_interface.h" +#include "shared_utils.h" +#include "app_manager.h" +#include "app_manager_export.h" +#include "attr_container.h" +#include "coap_ext.h" + +typedef struct _app_res_register { + struct _app_res_register *next; + char * url; + void (*request_handler)(request_t *, void *); + uint32 register_id; +} app_res_register_t; + +static app_res_register_t * g_resources = NULL; + +void module_request_handler(request_t *request, void *user_data) +{ + unsigned int mod_id = (unsigned int) user_data; + bh_message_t msg; + module_data *m_data; + request_t *req; + + /* Check module name */ + m_data = module_data_list_lookup_id(mod_id); + if (!m_data) { + return; + } + + if (m_data->wd_timer.is_interrupting) { + return; + } + + req = clone_request(request); + if (!req) { + return; + } + + /* Set queue message and send to applet's queue */ + msg = bh_new_msg(RESTFUL_REQUEST, req, sizeof(*req), request_cleaner); + if (!msg) { + request_cleaner(req); + return; + } + + if (!bh_post_msg2(m_data->queue, msg)) { + return; + } + + app_manager_printf("Send request to app %s success.\n", + m_data->module_name); +} + +void targeted_app_request_handler(request_t *request, void *unused) +{ + char applet_name[128] = { 0 }; + int offset; + char *url = request->url; + module_data *m_data; + + offset = check_url_start(request->url, strlen(request->url), "/app/"); + + if (offset <= 0) { + return; + } + + strncpy(applet_name, request->url + offset, sizeof(applet_name) - 1); + char *p = strrchr(applet_name, '/'); + if (p) { + *p = 0; + } else + return; + app_manager_printf("Send request to applet: %s\n", applet_name); + + request->url = p + 1; + + /* Check module name */ + m_data = module_data_list_lookup(applet_name); + if (!m_data) { + SEND_ERR_RESPONSE(request->mid, + "Send request to applet failed: invalid applet name"); + goto end; + } + + module_request_handler(request, (void *)m_data->id); + end: request->url = url; + +} + +void am_send_response(response_t *response) +{ + module_data *m_data; + + // if the receiver is not any of modules, just forward it to the host + m_data = module_data_list_lookup_id(response->reciever); + if (!m_data) { + send_response_to_host(response); + + } else { + response_t * resp_for_send = clone_response(response); + if (!resp_for_send) { + return; + } + + bh_message_t msg = bh_new_msg(RESTFUL_RESPONSE, resp_for_send, + sizeof(*resp_for_send), response_cleaner); + if (!msg) { + response_cleaner(resp_for_send); + return; + } + + if (!bh_post_msg2(m_data->queue, msg)) { + return; + } + } +} + +void * am_dispatch_request(request_t *request) +{ + app_res_register_t *r = g_resources; + + while (r) { + if (check_url_start(request->url, strlen(request->url), r->url) > 0) { + r->request_handler(request, (void *)r->register_id); + return r; + } + r = r->next; + } + return NULL; +} + +bool am_register_resource(const char *url, + void (*request_handler)(request_t *, void *), uint32 register_id) +{ + app_res_register_t * r = g_resources; + int register_num = 0; + + while (r) { + if (strcmp(r->url, url) == 0) { + return false; + } + + if (r->register_id == register_id) + register_num++; + + r = r->next; + } + + if (strlen(url) > RESOUCE_EVENT_URL_LEN_MAX) + return false; + + if (register_num >= RESOURCE_REGISTRATION_NUM_MAX) + return false; + + r = (app_res_register_t *) bh_malloc(sizeof(app_res_register_t)); + if (r == NULL) + return false; + + memset(r, 0, sizeof(*r)); + r->url = bh_strdup(url); + if (r->url == NULL) { + bh_free(r); + return false; + } + + r->request_handler = request_handler; + r->next = g_resources; + r->register_id = register_id; + g_resources = r; + + return true; +} + +void am_cleanup_registeration(uint32 register_id) +{ + app_res_register_t * r = g_resources; + app_res_register_t * prev = NULL; + + while (r) { + app_res_register_t *next = r->next; + + if (register_id == r->register_id) { + if (prev) + prev->next = next; + else + g_resources = next; + + bh_free(r->url); + bh_free(r); + } else + /* if r is freed, should not change prev. Only set prev to r + when r isn't freed. */ + prev = r; + + r = next; + } +} diff --git a/core/app-mgr/app-manager/watchdog.c b/core/app-mgr/app-manager/watchdog.c new file mode 100644 index 000000000..c3d9b0e99 --- /dev/null +++ b/core/app-mgr/app-manager/watchdog.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watchdog.h" +#include "bh_queue.h" +#include "bh_thread.h" +#include "bh_memory.h" +#include "jeff_export.h" + +#define WATCHDOG_THREAD_PRIORITY 5 + +/* Queue of watchdog */ +static bh_queue *watchdog_queue; + +#ifdef WATCHDOG_ENABLED /* TODO */ +static void watchdog_timer_callback(void *timer) +{ + watchdog_timer *wd_timer = app_manager_get_wd_timer_from_timer_handle( + timer); + + watchdog_timer_stop(wd_timer); + + vm_mutex_lock(&wd_timer->lock); + + if (!wd_timer->is_stopped) { + + wd_timer->is_interrupting = true; + + bh_post_msg(watchdog_queue, WD_TIMEOUT, wd_timer->module_data, + sizeof(module_data)); + } + + vm_mutex_unlock(&wd_timer->lock); +} +#endif + +bool watchdog_timer_init(module_data *m_data) +{ +#ifdef WATCHDOG_ENABLED /* TODO */ + watchdog_timer *wd_timer = &m_data->wd_timer; + + if (BH_SUCCESS != vm_mutex_init(&wd_timer->lock)) + return false; + + if (!(wd_timer->timer_handle = + app_manager_timer_create(watchdog_timer_callback, wd_timer))) { + vm_mutex_destroy(&wd_timer->lock); + return false; + } + + wd_timer->module_data = m_data; + wd_timer->is_interrupting = false; + wd_timer->is_stopped = false; +#endif + return true; +} + +void watchdog_timer_destroy(watchdog_timer *wd_timer) +{ +#ifdef WATCHDOG_ENABLED /* TODO */ + app_manager_timer_destroy(wd_timer->timer_handle); + vm_mutex_destroy(&wd_timer->lock); +#endif +} + +void watchdog_timer_start(watchdog_timer *wd_timer) +{ + vm_mutex_lock(&wd_timer->lock); + + wd_timer->is_interrupting = false; + wd_timer->is_stopped = false; + app_manager_timer_start(wd_timer->timer_handle, + wd_timer->module_data->timeout); + + vm_mutex_unlock(&wd_timer->lock); +} + +void watchdog_timer_stop(watchdog_timer *wd_timer) +{ + app_manager_timer_stop(wd_timer->timer_handle); +} + +#ifdef WATCHDOG_ENABLED /* TODO */ +static void watchdog_queue_callback(void *queue_msg) +{ + if (bh_message_type(queue_msg) == WD_TIMEOUT) { + module_data *m_data = (module_data *) bh_message_payload(queue_msg); + if (g_module_interfaces[m_data->module_type] + && g_module_interfaces[m_data->module_type]->module_watchdog_kill) { + g_module_interfaces[m_data->module_type]->module_watchdog_kill( + m_data); + app_manager_post_applets_update_event(); + } + } +} +#endif + +#ifdef WATCHDOG_ENABLED /* TODO */ +static void* +watchdog_thread_routine(void *arg) +{ + /* Enter loop run */ + bh_queue_enter_loop_run(watchdog_queue, watchdog_queue_callback); + + (void) arg; + return NULL; +} +#endif + +bool watchdog_startup() +{ + if (!(watchdog_queue = bh_queue_create())) { + app_manager_printf( + "App Manager start failed: create watchdog queue failed.\n"); + return false; + } +#if 0 +//todo: enable watchdog + /* Start watchdog thread */ + if (!jeff_runtime_create_supervisor_thread_with_prio(watchdog_thread_routine, NULL, + WATCHDOG_THREAD_PRIORITY)) { + bh_queue_destroy(watchdog_queue); + return false; + } +#endif + return true; +} diff --git a/core/app-mgr/app-manager/watchdog.h b/core/app-mgr/app-manager/watchdog.h new file mode 100644 index 000000000..3c957551a --- /dev/null +++ b/core/app-mgr/app-manager/watchdog.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _WATCHDOG_H_ +#define _WATCHDOG_H_ + +#include "app_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +watchdog_timer_init(module_data *module_data); + +void +watchdog_timer_destroy(watchdog_timer *wd_timer); + +void +watchdog_timer_start(watchdog_timer *wd_timer); + +void +watchdog_timer_stop(watchdog_timer *wd_timer); + +watchdog_timer* +app_manager_get_watchdog_timer(void *timer); + +bool +watchdog_startup(); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _WATCHDOG_H_ */ diff --git a/core/app-mgr/app-mgr-shared/app_manager_export.h b/core/app-mgr/app-mgr-shared/app_manager_export.h new file mode 100644 index 000000000..7686cc251 --- /dev/null +++ b/core/app-mgr/app-mgr-shared/app_manager_export.h @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _APP_MANAGER_EXPORT_H_ +#define _APP_MANAGER_EXPORT_H_ + +#include "native_interface.h" +#include "shared_utils.h" +#include "bh_queue.h" +#include "host_link.h" +#include "runtime_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct attr_container_t; + +/* Queue message type */ +typedef enum QUEUE_MSG_TYPE { + COAP_PARSED = LINK_MSG_TYPE_MAX + 1, + RESTFUL_REQUEST, + RESTFUL_RESPONSE, + TIMER_EVENT = 5, + SENSOR_EVENT = 6, + GPIO_INTERRUPT_EVENT = 7, + BLE_EVENT = 8, + JDWP_REQUEST = 9, + WD_TIMEOUT = 10, + BASE_EVENT_MAX = 100 + +} QUEUE_MSG_TYPE; + +typedef enum { + Module_Jeff, Module_WASM_App, Module_WASM_Lib, Module_Max +} Module_Type; + +struct module_data; + +/* Watchdog timer of module */ +typedef struct watchdog_timer { + /* Timer handle of the platform */ + void *timer_handle; + /* Module of the watchdog timer */ + struct module_data *module_data; + /* Lock of the watchdog timer */ + korp_mutex lock; + /* Flag indicates module is being interrupted by watchdog */ + bool is_interrupting; + /* Flag indicates watchdog timer is stopped */ + bool is_stopped; +} watchdog_timer; + +typedef struct module_data { + struct module_data *next; + + uint32 id; + + /* Type of the module */ + Module_Type module_type; + + /* Heap of the module */ + void *heap; + + /* Heap size of the module */ + int heap_size; + + /* Module execution timeout in millisecond */ + int timeout; + + /* Queue of the module */ + bh_queue *queue; + + /* Watchdog timer of the module*/ + struct watchdog_timer wd_timer; + + timer_ctx_t timer_ctx; + + /* max timers number app can create */ + int timers; + + /* Internal data of the module */ + void *internal_data; + + /* Module name */ + char module_name[1]; +} module_data; + +/* Module function types */ +typedef bool (*module_init_func)(void); +typedef bool (*module_install_func)(request_t *msg); +typedef bool (*module_uninstall_func)(request_t *msg); +typedef void (*module_watchdog_kill_func)(module_data *module_data); +typedef bool (*module_handle_host_url_func)(void *queue_msg); +typedef module_data *(*module_get_module_data_func)(void); + +/** + * @typedef module_on_install_request_byte_arrive_func + * + * @brief Define the signature of function to handle one byte of + * module app install request for struct module_interface. + * + * @param ch the byte to be received and handled + * @param total_size total size of the request + * @param received_total_size currently received total size when the function return + * + * @return true if success, false otherwise + */ +typedef bool (*module_on_install_request_byte_arrive_func)(uint8 ch, + int total_size, int *received_total_size); + +/* Interfaces of each module */ +typedef struct module_interface { + module_init_func module_init; + module_install_func module_install; + module_uninstall_func module_uninstall; + module_watchdog_kill_func module_watchdog_kill; + module_handle_host_url_func module_handle_host_url; + module_get_module_data_func module_get_module_data; + module_on_install_request_byte_arrive_func module_on_install; +} module_interface; + +/** + * @typedef host_init_func + * @brief Define the host initialize callback function signature for + * struct host_interface. + * + * @return true if success, false if fail + */ +typedef bool (*host_init_func)(void); + +/** + * @typedef host_send_fun + * @brief Define the host send callback function signature for + * struct host_interface. + * + * @param buf data buffer to send. + * @param size size of the data to send. + * + * @return size of the data sent in bytes + */ +typedef int (*host_send_fun)(void * ctx, const char *buf, int size); + +/** + * @typedef host_destroy_fun + * @brief Define the host receive callback function signature for + * struct host_interface. + * + */ +typedef void (*host_destroy_fun)(); + +/* Interfaces of host communication */ +typedef struct host_interface { + host_init_func init; + host_send_fun send; + host_destroy_fun destroy; +} host_interface; + +/** + * Initialize communication with Host + * + * @param interface host communication interface + * + * @return true if success, false otherwise + */ +bool +app_manager_host_init(host_interface *interface); + +/** + * Send message to Host + * + * @param buf buffer to send + * @param size size of buffer + * + * @return size of buffer sent + */ + +/* Startup app manager */ +void +app_manager_startup(host_interface *interface); + +/* Get queue of current applet */ +void * +app_manager_get_module_queue(uint32 module_type); + +/* Get applet name of current applet */ +const char * +app_manager_get_module_name(uint32 module_type); + +/* Get heap of current applet */ +void * +app_manager_get_module_heap(uint32 module_type); + +void* +get_app_manager_queue(); + +module_data* +app_manager_get_module_data(uint32 module_type); + +unsigned int +app_manager_get_module_id(uint32 module_type); + +module_data* +app_manager_lookup_module_data(const char *name); + +module_data* +module_data_list_lookup(const char *module_name); + +module_data* +module_data_list_lookup_id(unsigned int module_id); + +void +app_manager_post_applets_update_event(); + +bool +am_register_resource(const char *url, + void (*request_handler)(request_t *, void *), uint32 register_id); + +void am_cleanup_registeration(uint32 register_id); + +bool +am_register_event(const char *url, uint32_t reg_client); + +bool +am_unregister_event(const char *url, uint32_t reg_client); + +void am_publish_event(request_t * event); + +void * am_dispatch_request(request_t *request); + +void am_send_response(response_t *response); + +void module_request_handler(request_t *request, void *user_data); + +/** + * Send request message to host + * + * @param msg the request or event message. + * It is event when msg->action==COAP_EVENT + * + * @return true if success, false otherwise + */ +bool +send_request_to_host(request_t *msg); + +/** + * Send response message to host + * + * @param msg the response message + * + * @return true if success, false otherwise + */ +bool +send_response_to_host(response_t *msg); + +/** + * Send response with mid and code to host + * + * @param mid the message id of response + * @param code the code/status of response + * @param msg the detailed message + * + * @return true if success, false otherwise + */ +bool +send_error_response_to_host(int mid, int code, const char *msg); + +/** + * Check whether the applet has the permission + * + * @param perm the permission needed to check + * + * @return true if success, false otherwise + */ + +int +app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size); + +bool +bh_applet_check_permission(const char *perm); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif + diff --git a/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake b/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake new file mode 100644 index 000000000..16df591d7 --- /dev/null +++ b/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake @@ -0,0 +1,23 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set (APP_MGR_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${APP_MGR_SHARED_DIR}) + + +file (GLOB_RECURSE source_all ${APP_MGR_SHARED_DIR}/*.c) + +set (APP_MGR_SHARED_SOURCE ${source_all}) + diff --git a/core/app-mgr/app-mgr-shared/host_link.h b/core/app-mgr/app-mgr-shared/host_link.h new file mode 100644 index 000000000..d6cf59762 --- /dev/null +++ b/core/app-mgr/app-mgr-shared/host_link.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEPS_APP_MGR_APP_MGR_SHARED_HOST_LINK_H_ +#define DEPS_APP_MGR_APP_MGR_SHARED_HOST_LINK_H_ + +typedef enum LINK_MSG_TYPE { + COAP_TCP_RAW = 0, + COAP_UDP_RAW = 1, + REQUEST_PACKET, + RESPONSE_PACKET, + INSTALL_WASM_BYTECODE_APP, + CBOR_GENERIC = 30, + + LINK_MSG_TYPE_MAX = 50 +} LINK_MSG_TYPE; + +/* Link message, or message between host and app manager */ +typedef struct bh_link_msg_t { + /* 2 bytes leading */ + uint16_t leading_bytes; + /* message type, must be COAP_TCP or COAP_UDP */ + uint16_t message_type; + /* size of payload */ + uint32_t payload_size; + char *payload; +} bh_link_msg_t; + +#endif /* DEPS_APP_MGR_APP_MGR_SHARED_HOST_LINK_H_ */ diff --git a/core/app-mgr/module.json b/core/app-mgr/module.json new file mode 100644 index 000000000..9a45e8eab --- /dev/null +++ b/core/app-mgr/module.json @@ -0,0 +1,53 @@ +{ + "name": "aee", + "version": "0.0.1", + "description": "aee", + "type": "source", + "category": "middleware", + "arch": "x86, arc, posix", + "includes": [ + "Beihai/classlib/include", + "Beihai/runtime/include", + "Beihai/runtime/platform/include", + "Beihai/runtime/platform/zephyr", + "Beihai/runtime/utils/coap/er-coap", + "Beihai/runtime/utils/coap/extension", + "iwasm/runtime/include", + "iwasm/runtime/platform/include", + "iwasm/runtime/platform/zephyr", + "iwasm/runtime/vmcore_wasm" + ], + "sources": [ + "Beihai/classlib/native/internal/*.c", + "Beihai/classlib/native/*.c", + "Beihai/runtime/gc/*.c", + "Beihai/runtime/platform/zephyr/*.c", + "Beihai/runtime/utils/*.c", + "Beihai/runtime/utils/coap/er-coap/*.c", + "Beihai/runtime/utils/coap/extension/*.c", + "Beihai/runtime/vmcore_jeff/*.c", + "app-manager/app-manager.c", + "app-manager/app-manager-host.c", + "app-manager/app_mgr_zephyr.c", + "app-manager/event.c", + "app-manager/message.c", + "app-manager/module_jeff.c", + "app-manager/module_wasm_lib.c", + "app-manager/module_wasm_app.c", + "app-manager/watchdog.c", + "Beihai/products/iMRT/*.c", + "iwasm/runtime/utils/*.c", + "iwasm/runtime/platform/zephyr/*.c", + "iwasm/runtime/vmcore_wasm/*.c", + "iwasm/lib/lib-export\.c", + "iwasm/lib/aee/*.c", + "iwasm/products/zephyr/sample/src/*.c" + ], + "compile_definitions": [ + "NVALGRIND", + "__JLF__", + "__ZEPHYR__" + ], + "target": "aee", + "dependencies": [] +} diff --git a/core/iwasm/app-samples/smart-light/build.sh b/core/iwasm/app-samples/smart-light/build.sh new file mode 100755 index 000000000..f1b43c8ff --- /dev/null +++ b/core/iwasm/app-samples/smart-light/build.sh @@ -0,0 +1,17 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +emcc -g -O3 *.c -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 -o test.wasm +#./jeffdump -o ../test_wasm.h -n wasm_test_file test.wasm diff --git a/core/iwasm/app-samples/smart-light/main.c b/core/iwasm/app-samples/smart-light/main.c new file mode 100644 index 000000000..62ae5ac1f --- /dev/null +++ b/core/iwasm/app-samples/smart-light/main.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +//User LED +#define LED_PORT "GPIOA" +#define LED 5 + +//User KEY +#define KEY_PORT "GPIOC" +#define KEY 13 + +/** GPIO pin to be input. */ +#define GPIO_DIR_IN (0 << 0) + +/** GPIO pin to be output. */ +#define GPIO_DIR_OUT (1 << 0) + +void *device_get_binding(const char *); +int gpio_pin_configure(void *, unsigned int, int); +int gpio_pin_read(void *, unsigned int, unsigned int *); +int gpio_pin_write(void *, unsigned int, unsigned int); + +int main(int argc, char **argv) +{ + unsigned int gpio_value; + unsigned char flag = 0; + struct device *dev, *key_dev; + + dev = device_get_binding(LED_PORT); + /* Set LED pin as output */ + gpio_pin_configure(dev, LED, GPIO_DIR_OUT); + + key_dev = device_get_binding(KEY_PORT); + /* Set KEY pin as input */ + gpio_pin_configure(key_dev, KEY, GPIO_DIR_IN); + + while (1) { + gpio_pin_read(key_dev, KEY, &gpio_value); + if (!gpio_value) { + gpio_pin_write(dev, LED, 1); + if (!flag) { + printf("object detected\n"); + flag = 1; + } + } else { + gpio_pin_write(dev, LED, 0); + flag = 0; + } + } + return 0; +} diff --git a/core/iwasm/lib/app-libs/base/bh_platform.c b/core/iwasm/lib/app-libs/base/bh_platform.c index 0bddcd6ef..a712336f0 100644 --- a/core/iwasm/lib/app-libs/base/bh_platform.c +++ b/core/iwasm/lib/app-libs/base/bh_platform.c @@ -71,7 +71,7 @@ uint16 htons(uint16 value) uint16 ret; if (is_little_endian()) { ret = value; - swap16(&ret); + swap16((uint8 *)&ret); return ret; } diff --git a/core/iwasm/lib/app-libs/base/request.c b/core/iwasm/lib/app-libs/base/request.c index c56fe411b..4251e2bfe 100644 --- a/core/iwasm/lib/app-libs/base/request.c +++ b/core/iwasm/lib/app-libs/base/request.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "attr-container.h" +#include "attr_container.h" #include "request.h" #include "shared_utils.h" #include "wasm_app.h" @@ -138,9 +138,9 @@ static bool register_url_handler(const char *url, // tell app mgr to route this url to me if (reg_type == Reg_Request) - wasm_register_resource(url); + wasm_register_resource((int32)url); else - wasm_sub_event(url); + wasm_sub_event((int32)url); return true; } @@ -242,7 +242,7 @@ void api_send_request(request_t * request, response_handler_f response_handler, } } - wasm_post_request(buffer, size); + wasm_post_request((int32)buffer, size); free_req_resp_packet(buffer); } @@ -329,7 +329,7 @@ void api_response_send(response_t *response) if (buffer == NULL) return; - wasm_response_send(buffer, size); + wasm_response_send((int32)buffer, size); free_req_resp_packet(buffer); } @@ -339,11 +339,11 @@ bool api_publish_event(const char *url, int fmt, void *payload, int payload_len) { int size; request_t request[1]; - init_request(request, url, COAP_EVENT, fmt, payload, payload_len); + init_request(request, (char *)url, COAP_EVENT, fmt, payload, payload_len); char * buffer = pack_request(request, &size); if (buffer == NULL) return false; - wasm_post_request(buffer, size); + wasm_post_request((int32)buffer, size); free_req_resp_packet(buffer); diff --git a/core/iwasm/lib/app-libs/base/wasm_app.h b/core/iwasm/lib/app-libs/base/wasm_app.h index 5fa9276cb..03c8460ba 100644 --- a/core/iwasm/lib/app-libs/base/wasm_app.h +++ b/core/iwasm/lib/app-libs/base/wasm_app.h @@ -34,7 +34,7 @@ #include "native_interface.h" #include "shared_utils.h" -#include "attr-container.h" +#include "attr_container.h" #include "request.h" #include "sensor.h" #include "timer_wasm_app.h" diff --git a/core/iwasm/lib/app-libs/extension/sensor/sensor.c b/core/iwasm/lib/app-libs/extension/sensor/sensor.c index aac8d7d3c..53f413bf7 100644 --- a/core/iwasm/lib/app-libs/extension/sensor/sensor.c +++ b/core/iwasm/lib/app-libs/extension/sensor/sensor.c @@ -31,7 +31,7 @@ sensor_t sensor_open(const char* name, int index, sensor_event_handler_f sensor_event_handler, void *user_data) { - uint32 id = wasm_sensor_open(name, index); + uint32 id = wasm_sensor_open((int32)name, index); if (id == -1) return NULL; @@ -66,7 +66,7 @@ bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg) char *buffer = (char *)cfg; int len = attr_container_get_serialize_length(cfg); - return wasm_sensor_config_with_attr_container(sensor->handle, buffer, len); + return wasm_sensor_config_with_attr_container(sensor->handle, (int32)buffer, len); } bool sensor_config(sensor_t sensor, int interval, int bit_cfg, int delay) diff --git a/core/iwasm/lib/app-libs/extension/sensor/sensor.h b/core/iwasm/lib/app-libs/extension/sensor/sensor.h index 1e07c84c2..7aa4cb62e 100644 --- a/core/iwasm/lib/app-libs/extension/sensor/sensor.h +++ b/core/iwasm/lib/app-libs/extension/sensor/sensor.h @@ -17,7 +17,7 @@ #ifndef _AEE_SENSOR_H_ #define _AEE_SENSOR_H_ -#include "attr-container.h" +#include "attr_container.h" #ifdef __cplusplus extern "C" { diff --git a/core/iwasm/lib/app-libs/libc/lib-base.h b/core/iwasm/lib/app-libs/libc/lib_base.h similarity index 100% rename from core/iwasm/lib/app-libs/libc/lib-base.h rename to core/iwasm/lib/app-libs/libc/lib_base.h diff --git a/core/iwasm/lib/native-interface/attr-container.c b/core/iwasm/lib/native-interface/attr_container.c similarity index 99% rename from core/iwasm/lib/native-interface/attr-container.c rename to core/iwasm/lib/native-interface/attr_container.c index ed49ceea5..535beb635 100644 --- a/core/iwasm/lib/native-interface/attr-container.c +++ b/core/iwasm/lib/native-interface/attr_container.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "attr-container.h" +#include "attr_container.h" typedef union jvalue { bool z; @@ -794,7 +794,7 @@ void attr_container_dump(const attr_container_t *attr_cont) break; case ATTR_TYPE_INT64: bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t)); - attr_container_printf(", type: int64, value: 0x%llx\n", value.j); + attr_container_printf(", type: int64, value: 0x%llx\n", (long long unsigned int)(value.j)); p += 8; break; case ATTR_TYPE_BYTE: diff --git a/core/iwasm/lib/native-interface/attr-container.h b/core/iwasm/lib/native-interface/attr_container.h similarity index 100% rename from core/iwasm/lib/native-interface/attr-container.h rename to core/iwasm/lib/native-interface/attr_container.h diff --git a/core/iwasm/lib/native-interface/restful_utils.c b/core/iwasm/lib/native-interface/restful_utils.c index 5240494ec..71b5d782e 100644 --- a/core/iwasm/lib/native-interface/restful_utils.c +++ b/core/iwasm/lib/native-interface/restful_utils.c @@ -109,7 +109,10 @@ request_t * unpack_request(char * packet, int size, request_t * request) request->sender = ntohl(*((uint32*) (packet + 8))); request->payload_len = payload_len; request->url = REQUEST_PACKET_URL(packet); - request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len; + if (payload_len > 0) + request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len; + else + request->payload = NULL; return request; } @@ -150,7 +153,10 @@ response_t * unpack_response(char * packet, int size, response_t * response) response->mid = ntohl(*((uint32*) (packet + 4))); response->reciever = ntohl(*((uint32*) (packet + 8))); response->payload_len = payload_len; - response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN; + if (payload_len > 0) + response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN; + else + response->payload = NULL; return response; } @@ -238,7 +244,7 @@ response_t * clone_response(response_t * response) response_t * set_response(response_t * response, int status, int fmt, const char *payload, int payload_len) { - response->payload = payload; + response->payload = (void *)payload; response->payload_len = payload_len; response->status = status; response->fmt = fmt; @@ -384,11 +390,9 @@ char * find_key_value(char * buffer, int buffer_len, char * key, char * value, int value_len, char delimiter) { char * p = buffer; - int i = 0; int remaining = buffer_len; int key_len = strlen(key); - char * item_start = p; while (*p != 0 && remaining > 0) { while (*p == ' ' || *p == delimiter) { p++; diff --git a/core/iwasm/lib/native/base/base-lib-export.c b/core/iwasm/lib/native/base/base_lib_export.c similarity index 96% rename from core/iwasm/lib/native/base/base-lib-export.c rename to core/iwasm/lib/native/base/base_lib_export.c index b91782f49..4392a7ba4 100644 --- a/core/iwasm/lib/native/base/base-lib-export.c +++ b/core/iwasm/lib/native/base/base_lib_export.c @@ -17,10 +17,10 @@ #include #include #include -#include "lib-export.h" +#include "lib_export.h" #ifdef WASM_ENABLE_BASE_LIB -#include "base-lib-export.h" +#include "base_lib_export.h" #endif static NativeSymbol extended_native_symbol_defs[] = { diff --git a/core/iwasm/lib/native/base/base-lib-export.h b/core/iwasm/lib/native/base/base_lib_export.h similarity index 96% rename from core/iwasm/lib/native/base/base-lib-export.h rename to core/iwasm/lib/native/base/base_lib_export.h index a77168bb0..c3456b184 100644 --- a/core/iwasm/lib/native/base/base-lib-export.h +++ b/core/iwasm/lib/native/base/base_lib_export.h @@ -17,7 +17,7 @@ #ifndef _BASE_LIB_EXPORT_H_ #define _BASE_LIB_EXPORT_H_ -#include "attr-container.h" +#include "attr_container.h" #include "native_interface.h" #endif /* end of _BASE_LIB_EXPORT_H_ */ diff --git a/core/iwasm/lib/native/base/request_response.c b/core/iwasm/lib/native/base/request_response.c index 573dd48f5..641dc549c 100644 --- a/core/iwasm/lib/native/base/request_response.c +++ b/core/iwasm/lib/native/base/request_response.c @@ -15,11 +15,11 @@ */ #include "native_interface.h" -#include "app-manager-export.h" +#include "app_manager_export.h" #include "coap_ext.h" -#include "wasm-export.h" +#include "wasm_export.h" -extern void module_request_handler(request_t *request, uint32 register_id); +extern void module_request_handler(request_t *request, void *user_data); bool wasm_response_send(int32 buffer_offset, int size) { diff --git a/core/iwasm/lib/native/base/timer_wrapper.c b/core/iwasm/lib/native/base/timer_wrapper.c index 12d8f58ff..f2a8f23c2 100644 --- a/core/iwasm/lib/native/base/timer_wrapper.c +++ b/core/iwasm/lib/native/base/timer_wrapper.c @@ -15,7 +15,7 @@ */ #include "runtime_timer.h" -#include "app-manager-export.h" +#include "app_manager_export.h" #include "module_wasm_app.h" #include "bh_list.h" #include "bh_thread.h" diff --git a/core/iwasm/lib/native/extension/sensor/runtime_sensor.c b/core/iwasm/lib/native/extension/sensor/runtime_sensor.c index 135911799..ffaf4826d 100644 --- a/core/iwasm/lib/native/extension/sensor/runtime_sensor.c +++ b/core/iwasm/lib/native/extension/sensor/runtime_sensor.c @@ -15,7 +15,7 @@ */ #include "runtime_sensor.h" -#include "app-manager-export.h" +#include "app_manager_export.h" #include "module_wasm_app.h" #include "bh_thread.h" #include "bh_time.h" @@ -168,7 +168,7 @@ uint32 wasm_sensor_open(int32 name_offset, int instance) memset(client, 0, sizeof(sensor_client_t)); client->client_id = mod_id; - client->client_callback = wasm_sensor_callback; + client->client_callback = (void *)wasm_sensor_callback; client->interval = s->default_interval; client->next = s->clients; s->clients = client; diff --git a/core/iwasm/lib/native/extension/sensor/runtime_sensor.h b/core/iwasm/lib/native/extension/sensor/runtime_sensor.h index a9e803d95..ce53392fa 100644 --- a/core/iwasm/lib/native/extension/sensor/runtime_sensor.h +++ b/core/iwasm/lib/native/extension/sensor/runtime_sensor.h @@ -18,7 +18,7 @@ #define LIB_EXTENSION_RUNTIME_SENSOR_H_ #include "bh_platform.h" -#include "attr-container.h" +#include "attr_container.h" struct _sys_sensor; typedef struct _sys_sensor* sensor_obj_t; diff --git a/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c b/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c index 4b6492cfc..b2cd53d31 100644 --- a/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c +++ b/core/iwasm/lib/native/extension/sensor/sensor_mgr_ref.c @@ -18,9 +18,9 @@ #include "bh_queue.h" #include "bh_thread.h" #include "runtime_sensor.h" -#include "attr-container.h" +#include "attr_container.h" #include "module_wasm_app.h" -#include "wasm-export.h" +#include "wasm_export.h" /* * @@ -99,11 +99,10 @@ static attr_container_t * read_test_sensor(void * sensor) static bool config_test_sensor(void * s, void * config) { - return false; } -static void * thread_sensor_check(void * arg) +static void thread_sensor_check(void * arg) { while (1) { int ms_to_expiry = check_sensor_timers(); @@ -120,6 +119,8 @@ static void cb_wakeup_thread() vm_cond_signal(&cond); } +void set_sensor_reshceduler(void (*callback)()); + void init_sensor_framework() { // init the mutext and conditions @@ -138,7 +139,7 @@ void init_sensor_framework() wasm_register_cleanup_callback(sensor_cleanup_callback); - vm_thread_create(&tid, thread_sensor_check, NULL, + vm_thread_create(&tid, (void *)thread_sensor_check, NULL, BH_APPLET_PRESERVED_STACK_SIZE); } diff --git a/core/iwasm/lib/native/extension/template/lib-export-template.c b/core/iwasm/lib/native/extension/template/lib_export_template.c similarity index 100% rename from core/iwasm/lib/native/extension/template/lib-export-template.c rename to core/iwasm/lib/native/extension/template/lib_export_template.c diff --git a/core/iwasm/lib/native/libc/libc_wrapper.c b/core/iwasm/lib/native/libc/libc_wrapper.c index ce79fcbe6..fabc8b892 100644 --- a/core/iwasm/lib/native/libc/libc_wrapper.c +++ b/core/iwasm/lib/native/libc/libc_wrapper.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "wasm-native.h" -#include "wasm-export.h" +#include "wasm_native.h" +#include "wasm_export.h" #include "wasm_log.h" #include "wasm_platform_log.h" @@ -903,7 +903,9 @@ wasm_native_func_lookup(const char *module_name, const char *func_name) while (func_def < func_def_end) { if (!strcmp(func_def->module_name, module_name) - && !strcmp(func_def->func_name, func_name)) + && (!strcmp(func_def->func_name, func_name) + || (func_def->func_name[0] == '_' + && !strcmp(func_def->func_name + 1, func_name)))) return (void*) (uintptr_t) func_def->func_ptr; func_def++; } diff --git a/core/iwasm/products/linux/CMakeLists.txt b/core/iwasm/products/linux/CMakeLists.txt index 4a955f1b6..72926661b 100644 --- a/core/iwasm/products/linux/CMakeLists.txt +++ b/core/iwasm/products/linux/CMakeLists.txt @@ -58,7 +58,7 @@ enable_language (ASM) include (../../runtime/platform/${PLATFORM}/platform.cmake) include (../../runtime/utils/utils.cmake) -include (../../runtime/vmcore_wasm/vmcore.cmake) +include (../../runtime/vmcore-wasm/vmcore.cmake) include (../../lib/native/base/wasm_lib_base.cmake) include (../../lib/native/libc/wasm_libc.cmake) include (${SHARED_LIB_DIR}/platform/${PLATFORM}/shared_platform.cmake) @@ -68,12 +68,12 @@ add_library (vmlib ${WASM_PLATFORM_LIB_SOURCE} ${WASM_UTILS_LIB_SOURCE} ${VMCORE_LIB_SOURCE} - ${WASM_LIB_BASE_DIR}/base-lib-export.c + ${WASM_LIB_BASE_DIR}/base_lib_export.c ${WASM_LIBC_SOURCE} ${PLATFORM_SHARED_SOURCE} ${MEM_ALLOC_SHARED_SOURCE}) -add_executable (iwasm main.c ext-lib-export.c) +add_executable (iwasm main.c ext_lib_export.c) install (TARGETS iwasm DESTINATION bin) @@ -83,7 +83,7 @@ add_library (libiwasm SHARED ${WASM_PLATFORM_LIB_SOURCE} ${WASM_UTILS_LIB_SOURCE} ${VMCORE_LIB_SOURCE} - ${WASM_LIB_BASE_DIR}/base-lib-export.c + ${WASM_LIB_BASE_DIR}/base_lib_export.c ${WASM_LIBC_SOURCE} ${PLATFORM_SHARED_SOURCE} ${MEM_ALLOC_SHARED_SOURCE}) diff --git a/core/iwasm/products/zephyr/simple/src/ext-lib-export.c b/core/iwasm/products/linux/ext_lib_export.c similarity index 92% rename from core/iwasm/products/zephyr/simple/src/ext-lib-export.c rename to core/iwasm/products/linux/ext_lib_export.c index f5e9c34c6..8d78f3ae1 100644 --- a/core/iwasm/products/zephyr/simple/src/ext-lib-export.c +++ b/core/iwasm/products/linux/ext_lib_export.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "lib-export.h" +#include "lib_export.h" static NativeSymbol extended_native_symbol_defs[] = { }; -#include "ext-lib-export.h" +#include "ext_lib_export.h" diff --git a/core/iwasm/products/linux/main.c b/core/iwasm/products/linux/main.c index 039b0ad7c..7a87d8b0a 100644 --- a/core/iwasm/products/linux/main.c +++ b/core/iwasm/products/linux/main.c @@ -24,7 +24,7 @@ #include "wasm_platform.h" #include "wasm_platform_log.h" #include "wasm_thread.h" -#include "wasm-export.h" +#include "wasm_export.h" #include "wasm_memory.h" #include "bh_memory.h" diff --git a/core/iwasm/products/zephyr/simple/CMakeLists.txt b/core/iwasm/products/zephyr/simple/CMakeLists.txt index 2968d45d2..d9e91e4cb 100644 --- a/core/iwasm/products/zephyr/simple/CMakeLists.txt +++ b/core/iwasm/products/zephyr/simple/CMakeLists.txt @@ -27,7 +27,7 @@ set (SHARED_LIB_ROOT ${IWASM_ROOT}/../shared-lib) include_directories (${IWASM_ROOT}/runtime/include ${IWASM_ROOT}/runtime/platform/include ${IWASM_ROOT}/runtime/platform/zephyr - ${IWASM_ROOT}/runtime/vmcore_wasm + ${IWASM_ROOT}/runtime/vmcore-wasm ${SHARED_LIB_ROOT}/include ${SHARED_LIB_ROOT}/platform/include ${SHARED_LIB_ROOT}/platform/zephyr) @@ -37,14 +37,14 @@ set (IWASM_SRCS ${IWASM_ROOT}/runtime/utils/wasm_hashmap.c ${IWASM_ROOT}/runtime/utils/wasm_dlfcn.c ${IWASM_ROOT}/runtime/platform/zephyr/wasm_math.c ${IWASM_ROOT}/runtime/platform/zephyr/wasm_platform.c - ${IWASM_ROOT}/runtime/platform/zephyr/wasm-native.c - ${IWASM_ROOT}/runtime/vmcore_wasm/wasm-application.c - ${IWASM_ROOT}/runtime/vmcore_wasm/wasm-interp.c - ${IWASM_ROOT}/runtime/vmcore_wasm/wasm-loader.c - ${IWASM_ROOT}/runtime/vmcore_wasm/wasm-runtime.c - ${IWASM_ROOT}/runtime/vmcore_wasm/invokeNative_general.c + ${IWASM_ROOT}/runtime/platform/zephyr/wasm_native.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_application.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_interp.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_loader.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_runtime.c + ${IWASM_ROOT}/runtime/vmcore-wasm/invokeNative_general.c ${IWASM_ROOT}/lib/native/libc/libc_wrapper.c - ${IWASM_ROOT}/lib/native/base/base-lib-export.c + ${IWASM_ROOT}/lib/native/base/base_lib_export.c ${SHARED_LIB_ROOT}/platform/zephyr/bh_platform.c ${SHARED_LIB_ROOT}/platform/zephyr/bh_assert.c ${SHARED_LIB_ROOT}/platform/zephyr/bh_thread.c @@ -54,4 +54,4 @@ set (IWASM_SRCS ${IWASM_ROOT}/runtime/utils/wasm_hashmap.c ${SHARED_LIB_ROOT}/mem-alloc/ems/ems_alloc.c ${SHARED_LIB_ROOT}/mem-alloc/ems/ems_hmu.c) -target_sources(app PRIVATE ${IWASM_SRCS} src/main.c src/ext-lib-export.c) +target_sources(app PRIVATE ${IWASM_SRCS} src/main.c src/ext_lib_export.c) diff --git a/core/iwasm/products/linux/ext-lib-export.c b/core/iwasm/products/zephyr/simple/src/ext_lib_export.c similarity index 92% rename from core/iwasm/products/linux/ext-lib-export.c rename to core/iwasm/products/zephyr/simple/src/ext_lib_export.c index f5e9c34c6..8d78f3ae1 100644 --- a/core/iwasm/products/linux/ext-lib-export.c +++ b/core/iwasm/products/zephyr/simple/src/ext_lib_export.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "lib-export.h" +#include "lib_export.h" static NativeSymbol extended_native_symbol_defs[] = { }; -#include "ext-lib-export.h" +#include "ext_lib_export.h" diff --git a/core/iwasm/products/zephyr/simple/src/main.c b/core/iwasm/products/zephyr/simple/src/main.c index 7dc8c7ba8..fb183e387 100644 --- a/core/iwasm/products/zephyr/simple/src/main.c +++ b/core/iwasm/products/zephyr/simple/src/main.c @@ -21,7 +21,7 @@ #include "wasm_platform.h" #include "wasm_platform_log.h" #include "wasm_thread.h" -#include "wasm-export.h" +#include "wasm_export.h" #include "wasm_memory.h" #include "bh_memory.h" #include "test_wasm.h" diff --git a/core/iwasm/readme.txt b/core/iwasm/readme.txt new file mode 100644 index 000000000..16af58d7e --- /dev/null +++ b/core/iwasm/readme.txt @@ -0,0 +1,75 @@ + +1. How to build iwasm in Linux + + cd products/linux/ + mkdir build && cd build + cmake .. && make + +2. How to build iwasm in Zephyr system + (1) clone zephyr source code + + git clone https://github.com/zephyrproject-rtos/zephyr.git + + (2) copy /products/zephyr/simple directory to zephry/samples/ + + cd zephyr/samples/ + cp -a /products/zephyr/simple simple + cd simple + + (3) create a link to and rename it to iwasm + + ln -s iwasm + + (4) create a link to and rename it to shared-lib + + ln -s shared-lib + + (5) build source code + + mkdir build && cd build + source ../../../zephyr-env.sh + cmake -GNinja -DBOARD=qemu_x86 .. + ninja + + (6) run simple + + ninja run + +3. How to build iwasm in AliOS-Things platform + (1) clone AliOS-Things source code + + git clone https://github.com/alibaba/AliOS-Things.git + + (2) copy /products/alios-things directory to AliOS-Things/middleware, + and rename it as iwasm + + cp -a /products/alios-things middleware/iwasm + + (3) create a link to in middleware/iwasm/ and rename it to iwasm + + ln -s middleware/iwasm/iwasm + + (4) create a link to in middleware/iwasm/ and rename it to shared-lib + + ln -s middle/iwasm/shared-lib + + (5) modify sample source code of AliOS-Things to call iwasm_init() function + + modify file app/example/helloworld/helloworld.c, in the beginning of + function application_start(), add: + + bool iwasm_init(void); + iwasm_init(); + + modify file app/example/helloworld/helloworld.mk, change + $(NAME)_COMPONENTS := yloop cli + to + $(NAME)_COMPONENTS := yloop cli iwasm + + (6) build source code + + aos make helloworld@linuxhost + + (7) run source code + ./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf + diff --git a/core/iwasm/runtime/include/ext-lib-export.h b/core/iwasm/runtime/include/ext_lib_export.h similarity index 97% rename from core/iwasm/runtime/include/ext-lib-export.h rename to core/iwasm/runtime/include/ext_lib_export.h index d2ae82fca..a2f111fcc 100644 --- a/core/iwasm/runtime/include/ext-lib-export.h +++ b/core/iwasm/runtime/include/ext_lib_export.h @@ -17,7 +17,7 @@ #ifndef _EXT_LIB_EXPORT_H_ #define _EXT_LIB_EXPORT_H_ -#include "lib-export.h" +#include "lib_export.h" #ifdef __cplusplus extern "C" { diff --git a/core/iwasm/runtime/include/lib-export.h b/core/iwasm/runtime/include/lib_export.h similarity index 100% rename from core/iwasm/runtime/include/lib-export.h rename to core/iwasm/runtime/include/lib_export.h diff --git a/core/iwasm/runtime/include/wasm-export.h b/core/iwasm/runtime/include/wasm_export.h similarity index 100% rename from core/iwasm/runtime/include/wasm-export.h rename to core/iwasm/runtime/include/wasm_export.h diff --git a/core/iwasm/runtime/platform/include/wasm_thread.h b/core/iwasm/runtime/platform/include/wa_thread.h similarity index 94% rename from core/iwasm/runtime/platform/include/wasm_thread.h rename to core/iwasm/runtime/platform/include/wa_thread.h index c14ae5982..245dc5d63 100644 --- a/core/iwasm/runtime/platform/include/wasm_thread.h +++ b/core/iwasm/runtime/platform/include/wa_thread.h @@ -20,8 +20,8 @@ * thread relative function. */ -#ifndef _WASM_THREAD_H -#define _WASM_THREAD_H +#ifndef _WA_THREAD_H +#define _WA_THREAD_H #ifdef __cplusplus extern "C" { @@ -59,5 +59,5 @@ ws_mutex_init(korp_mutex *mutex, bool is_recursive) } #endif -#endif /* end of _WASM_THREAD_H */ +#endif /* end of _WA_THREAD_H */ diff --git a/core/iwasm/runtime/platform/linux/wasm-native.c b/core/iwasm/runtime/platform/linux/wasm_native.c similarity index 99% rename from core/iwasm/runtime/platform/linux/wasm-native.c rename to core/iwasm/runtime/platform/linux/wasm_native.c index fad5ad71e..c12e85c75 100644 --- a/core/iwasm/runtime/platform/linux/wasm-native.c +++ b/core/iwasm/runtime/platform/linux/wasm_native.c @@ -18,8 +18,8 @@ #define _GNU_SOURCE /* for O_DIRECT */ #endif -#include "wasm-native.h" -#include "wasm-runtime.h" +#include "wasm_native.h" +#include "wasm_runtime.h" #include "wasm_log.h" #include "wasm_memory.h" #include "wasm_platform_log.h" diff --git a/core/iwasm/runtime/platform/zephyr/wasm_math.c b/core/iwasm/runtime/platform/zephyr/wasm_math.c index bad81eac3..ebea5c490 100644 --- a/core/iwasm/runtime/platform/zephyr/wasm_math.c +++ b/core/iwasm/runtime/platform/zephyr/wasm_math.c @@ -39,64 +39,64 @@ typedef uint32_t u_int32_t; typedef uint64_t u_int64_t; typedef union u32double_tag { - int *pint; - double *pdouble; + int *pint; + double *pdouble; } U32DOUBLE; static inline int * pdouble2pint(double *pdouble) { - U32DOUBLE u; - u.pdouble = pdouble; - return u.pint; + U32DOUBLE u; + u.pdouble = pdouble; + return u.pint; } typedef union { - double value; - struct - { - u_int32_t lsw; - u_int32_t msw; - } parts; - struct - { - u_int64_t w; - } xparts; + double value; + struct + { + u_int32_t lsw; + u_int32_t msw; + } parts; + struct + { + u_int64_t w; + } xparts; } ieee_double_shape_type_little; typedef union { - double value; - struct - { - u_int32_t msw; - u_int32_t lsw; - } parts; - struct - { - u_int64_t w; - } xparts; + double value; + struct + { + u_int32_t msw; + u_int32_t lsw; + } parts; + struct + { + u_int64_t w; + } xparts; } ieee_double_shape_type_big; typedef union { - double d; - struct { - unsigned int manl :32; - unsigned int manh :20; - unsigned int exp :11; - unsigned int sign :1; - } bits; + double d; + struct { + unsigned int manl :32; + unsigned int manh :20; + unsigned int exp :11; + unsigned int sign :1; + } bits; } IEEEd2bits_L; typedef union { - double d; - struct { - unsigned int sign :1; - unsigned int exp :11; - unsigned int manh :20; - unsigned int manl :32; - } bits; + double d; + struct { + unsigned int sign :1; + unsigned int exp :11; + unsigned int manh :20; + unsigned int manl :32; + } bits; } IEEEd2bits_B; #define __HIL(x) *(1+pdouble2pint(&x)) @@ -107,107 +107,107 @@ typedef union { /* Get two 32 bit ints from a double. */ #define EXTRACT_WORDS_L(ix0,ix1,d) \ -do { \ - ieee_double_shape_type_little ew_u; \ - ew_u.value = (d); \ - (ix0) = ew_u.parts.msw; \ - (ix1) = ew_u.parts.lsw; \ -} while (0) + do { \ + ieee_double_shape_type_little ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ + } while (0) /* Set a double from two 32 bit ints. */ #define INSERT_WORDS_L(d,ix0,ix1) \ -do { \ - ieee_double_shape_type_little iw_u; \ - iw_u.parts.msw = (ix0); \ - iw_u.parts.lsw = (ix1); \ - (d) = iw_u.value; \ -} while (0) + do { \ + ieee_double_shape_type_little iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ + } while (0) /* Get two 32 bit ints from a double. */ #define EXTRACT_WORDS_B(ix0,ix1,d) \ -do { \ - ieee_double_shape_type_big ew_u; \ - ew_u.value = (d); \ - (ix0) = ew_u.parts.msw; \ - (ix1) = ew_u.parts.lsw; \ -} while (0) + do { \ + ieee_double_shape_type_big ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ + } while (0) /* Set a double from two 32 bit ints. */ #define INSERT_WORDS_B(d,ix0,ix1) \ -do { \ - ieee_double_shape_type_big iw_u; \ - iw_u.parts.msw = (ix0); \ - iw_u.parts.lsw = (ix1); \ - (d) = iw_u.value; \ -} while (0) + do { \ + ieee_double_shape_type_big iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ + } while (0) /* Get the more significant 32 bit int from a double. */ #define GET_HIGH_WORD_L(i,d) \ -do { \ - ieee_double_shape_type_little gh_u; \ - gh_u.value = (d); \ - (i) = gh_u.parts.msw; \ -} while (0) + do { \ + ieee_double_shape_type_little gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ + } while (0) /* Get the more significant 32 bit int from a double. */ #define GET_HIGH_WORD_B(i,d) \ -do { \ - ieee_double_shape_type_big gh_u; \ - gh_u.value = (d); \ - (i) = gh_u.parts.msw; \ -} while (0) + do { \ + ieee_double_shape_type_big gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ + } while (0) /* Set the more significant 32 bits of a double from an int. */ #define SET_HIGH_WORD_L(d,v) \ -do { \ - ieee_double_shape_type_little sh_u; \ - sh_u.value = (d); \ - sh_u.parts.msw = (v); \ - (d) = sh_u.value; \ -} while (0) + do { \ + ieee_double_shape_type_little sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ + } while (0) /* Set the more significant 32 bits of a double from an int. */ #define SET_HIGH_WORD_B(d,v) \ -do { \ - ieee_double_shape_type_big sh_u; \ - sh_u.value = (d); \ - sh_u.parts.msw = (v); \ - (d) = sh_u.value; \ -} while (0) + do { \ + ieee_double_shape_type_big sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ + } while (0) /* Macro wrappers. */ #define EXTRACT_WORDS(ix0,ix1,d) do { \ - if (is_little_endian) \ - EXTRACT_WORDS_L(ix0,ix1,d); \ - else \ - EXTRACT_WORDS_B(ix0,ix1,d); \ + if (is_little_endian) \ + EXTRACT_WORDS_L(ix0,ix1,d); \ + else \ + EXTRACT_WORDS_B(ix0,ix1,d); \ } while (0) #define INSERT_WORDS(d,ix0,ix1) do { \ - if (is_little_endian) \ - INSERT_WORDS_L(d,ix0,ix1); \ - else \ - INSERT_WORDS_B(d,ix0,ix1); \ + if (is_little_endian) \ + INSERT_WORDS_L(d,ix0,ix1); \ + else \ + INSERT_WORDS_B(d,ix0,ix1); \ } while (0) #define GET_HIGH_WORD(i,d) \ -do { \ - if (is_little_endian) \ - GET_HIGH_WORD_L(i,d); \ - else \ - GET_HIGH_WORD_B(i,d); \ -} while (0) + do { \ + if (is_little_endian) \ + GET_HIGH_WORD_L(i,d); \ + else \ + GET_HIGH_WORD_B(i,d); \ + } while (0) #define SET_HIGH_WORD(d,v) \ -do { \ - if (is_little_endian) \ - SET_HIGH_WORD_L(d,v); \ - else \ - SET_HIGH_WORD_B(d,v); \ -} while (0) + do { \ + if (is_little_endian) \ + SET_HIGH_WORD_L(d,v); \ + else \ + SET_HIGH_WORD_B(d,v); \ + } while (0) #define __HI(x) (is_little_endian ? __HIL(x) : __HIB(x)) @@ -220,14 +220,14 @@ do { \ #define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval)) #else #define STRICT_ASSIGN(type, lval, rval) do { \ - volatile type __lval; \ - \ - if (sizeof(type) >= sizeof(long double)) \ - (lval) = (rval); \ - else { \ - __lval = (rval); \ - (lval) = __lval; \ - } \ + volatile type __lval; \ + \ + if (sizeof(type) >= sizeof(long double)) \ + (lval) = (rval); \ + else { \ + __lval = (rval); \ + (lval) = __lval; \ + } \ } while (0) #endif @@ -257,8 +257,8 @@ static const double static double #endif TWO52[2]={ - 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ - -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ + 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ + -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ }; static double freebsd_sqrt(double x); @@ -270,312 +270,312 @@ static int freebsd_isnan(double x); static double freebsd_sqrt(double x) /* wrapper sqrt */ { - double z; - int32_t sign = (int)0x80000000; - int32_t ix0,s0,q,m,t,i; - u_int32_t r,t1,s1,ix1,q1; + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + u_int32_t r,t1,s1,ix1,q1; - EXTRACT_WORDS(ix0,ix1,x); + EXTRACT_WORDS(ix0,ix1,x); /* take care of Inf and NaN */ - if((ix0&0x7ff00000)==0x7ff00000) { - return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + if((ix0&0x7ff00000)==0x7ff00000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf sqrt(-inf)=sNaN */ - } + } /* take care of zero */ - if(ix0<=0) { - if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ - else if(ix0<0) - return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ - } + if(ix0<=0) { + if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix0<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } /* normalize x */ - m = (ix0>>20); - if(m==0) { /* subnormal x */ - while(ix0==0) { - m -= 21; - ix0 |= (ix1>>11); ix1 <<= 21; - } - for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; - m -= i-1; - ix0 |= (ix1>>(32-i)); - ix1 <<= i; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0&0x000fffff)|0x00100000; - if(m&1){ /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1&sign)>>31); - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ + m = (ix0>>20); + if(m==0) { /* subnormal x */ + while(ix0==0) { + m -= 21; + ix0 |= (ix1>>11); ix1 <<= 21; + } + for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; + m -= i-1; + ix0 |= (ix1>>(32-i)); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if(m&1){ /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1&sign)>>31); - ix1 += ix1; - q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ - r = 0x00200000; /* r = moving bit from right to left */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ - while(r!=0) { - t = s0+r; - if(t<=ix0) { - s0 = t+r; - ix0 -= t; - q += r; - } - ix0 += ix0 + ((ix1&sign)>>31); - ix1 += ix1; - r>>=1; - } + while(r!=0) { + t = s0+r; + if(t<=ix0) { + s0 = t+r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r>>=1; + } - r = sign; - while(r!=0) { - t1 = s1+r; - t = s0; - if((t>31); - ix1 += ix1; - r>>=1; - } + r = sign; + while(r!=0) { + t1 = s1+r; + t = s0; + if((t>31); + ix1 += ix1; + r>>=1; + } /* use floating add to find out rounding direction */ - if((ix0|ix1)!=0) { - z = one-tiny; /* trigger inexact flag */ - if (z>=one) { - z = one+tiny; - if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;} - else if (z>one) { - if (q1==(u_int32_t)0xfffffffe) q+=1; - q1+=2; - } else - q1 += (q1&1); - } - } - ix0 = (q>>1)+0x3fe00000; - ix1 = q1>>1; - if ((q&1)==1) ix1 |= sign; - ix0 += (m <<20); + if((ix0|ix1)!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;} + else if (z>one) { + if (q1==(u_int32_t)0xfffffffe) q+=1; + q1+=2; + } else + q1 += (q1&1); + } + } + ix0 = (q>>1)+0x3fe00000; + ix1 = q1>>1; + if ((q&1)==1) ix1 |= sign; + ix0 += (m <<20); - INSERT_WORDS(z,ix0,ix1); + INSERT_WORDS(z,ix0,ix1); - return z; + return z; } static double freebsd_floor(double x) { - int32_t i0,i1,j0; - u_int32_t i,j; + int32_t i0,i1,j0; + u_int32_t i,j; - EXTRACT_WORDS(i0,i1,x); + EXTRACT_WORDS(i0,i1,x); - j0 = ((i0>>20)&0x7ff)-0x3ff; - if(j0<20) { - if(j0<0) { /* raise inexact if x != 0 */ - if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ - if(i0>=0) {i0=i1=0;} - else if(((i0&0x7fffffff)|i1)!=0) - { i0=0xbff00000;i1=0;} - } - } else { - i = (0x000fffff)>>j0; - if(((i0&i)|i1)==0) return x; /* x is integral */ - if(huge+x>0.0) { /* raise inexact flag */ - if(i0<0) i0 += (0x00100000)>>j0; - i0 &= (~i); i1=0; - } - } - } else if (j0>51) { - if(j0==0x400) return x+x; /* inf or NaN */ - else return x; /* x is integral */ - } else { - i = ((u_int32_t)(0xffffffff))>>(j0-20); - if((i1&i)==0) return x; /* x is integral */ - if(huge+x>0.0) { /* raise inexact flag */ - if(i0<0) { - if(j0==20) i0+=1; - else { - j = i1+(1<<(52-j0)); - if(j>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=i1=0;} + else if(((i0&0x7fffffff)|i1)!=0) + { i0=0xbff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) { + if(j0==20) i0+=1; + else { + j = i1+(1<<(52-j0)); + if(j>20)&0x7ff)-0x3ff; - if(j0<20) { - if(j0<0) { /* raise inexact if x != 0 */ - if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ - if(i0<0) {i0=0x80000000;i1=0;} - else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} - } - } else { - i = (0x000fffff)>>j0; - if(((i0&i)|i1)==0) return x; /* x is integral */ - if(huge+x>0.0) { /* raise inexact flag */ - if(i0>0) i0 += (0x00100000)>>j0; - i0 &= (~i); i1=0; - } - } - } else if (j0>51) { - if(j0==0x400) return x+x; /* inf or NaN */ - else return x; /* x is integral */ - } else { - i = ((u_int32_t)(0xffffffff))>>(j0-20); - if((i1&i)==0) return x; /* x is integral */ - if(huge+x>0.0) { /* raise inexact flag */ - if(i0>0) { - if(j0==20) i0+=1; - else { - j = i1 + (1<<(52-j0)); - if(j>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;i1=0;} + else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) { + if(j0==20) i0+=1; + else { + j = i1 + (1<<(52-j0)); + if(j>31)&1; - j0 = ((i0>>20)&0x7ff)-0x3ff; - if(j0<20) { - if(j0<0) { - if(((i0&0x7fffffff)|i1)==0) return x; - i1 |= (i0&0x0fffff); - i0 &= 0xfffe0000; - i0 |= ((i1|-i1)>>12)&0x80000; - SET_HIGH_WORD(x,i0); - STRICT_ASSIGN(double,w,TWO52[sx]+x); - t = w-TWO52[sx]; - GET_HIGH_WORD(i0,t); - SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); - return t; - } else { - i = (0x000fffff)>>j0; - if(((i0&i)|i1)==0) return x; /* x is integral */ - i>>=1; - if(((i0&i)|i1)!=0) { - /* - * Some bit is set after the 0.5 bit. To avoid the - * possibility of errors from double rounding in - * w = TWO52[sx]+x, adjust the 0.25 bit to a lower - * guard bit. We do this for all j0<=51. The - * adjustment is trickiest for j0==18 and j0==19 - * since then it spans the word boundary. - */ - if(j0==19) i1 = 0x40000000; else - if(j0==18) i1 = 0x80000000; else - i0 = (i0&(~i))|((0x20000)>>j0); - } - } - } else if (j0>51) { - if(j0==0x400) return x+x; /* inf or NaN */ - else return x; /* x is integral */ - } else { - i = ((u_int32_t)(0xffffffff))>>(j0-20); - if((i1&i)==0) return x; /* x is integral */ - i>>=1; - if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); - } - INSERT_WORDS(x,i0,i1); - STRICT_ASSIGN(double,w,TWO52[sx]+x); - return w-TWO52[sx]; + int32_t i0,j0,sx; + u_int32_t i,i1; + double w,t; + EXTRACT_WORDS(i0,i1,x); + sx = (i0>>31)&1; + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { + if(((i0&0x7fffffff)|i1)==0) return x; + i1 |= (i0&0x0fffff); + i0 &= 0xfffe0000; + i0 |= ((i1|-i1)>>12)&0x80000; + SET_HIGH_WORD(x,i0); + STRICT_ASSIGN(double,w,TWO52[sx]+x); + t = w-TWO52[sx]; + GET_HIGH_WORD(i0,t); + SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); + return t; + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + i>>=1; + if(((i0&i)|i1)!=0) { + /* + * Some bit is set after the 0.5 bit. To avoid the + * possibility of errors from double rounding in + * w = TWO52[sx]+x, adjust the 0.25 bit to a lower + * guard bit. We do this for all j0<=51. The + * adjustment is trickiest for j0==18 and j0==19 + * since then it spans the word boundary. + */ + if(j0==19) i1 = 0x40000000; else + if(j0==18) i1 = 0x80000000; else + i0 = (i0&(~i))|((0x20000)>>j0); + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + i>>=1; + if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); + } + INSERT_WORDS(x,i0,i1); + STRICT_ASSIGN(double,w,TWO52[sx]+x); + return w-TWO52[sx]; } static int freebsd_isnan(double d) { - if (is_little_endian) { - IEEEd2bits_L u; - u.d = d; - return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); - } - else { - IEEEd2bits_B u; - u.d = d; - return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); - } + if (is_little_endian) { + IEEEd2bits_L u; + u.d = d; + return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); + } + else { + IEEEd2bits_B u; + u.d = d; + return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); + } } static double freebsd_fabs(double x) { - u_int32_t high; - GET_HIGH_WORD(high,x); - SET_HIGH_WORD(x,high&0x7fffffff); - return x; + u_int32_t high; + GET_HIGH_WORD(high,x); + SET_HIGH_WORD(x,high&0x7fffffff); + return x; } double sqrt(double x) { - return freebsd_sqrt(x); + return freebsd_sqrt(x); } double floor(double x) { - return freebsd_floor(x); + return freebsd_floor(x); } double ceil(double x) { - return freebsd_ceil(x); + return freebsd_ceil(x); } double fmin(double x, double y) { - return x < y ? x : y; + return x < y ? x : y; } double fmax(double x, double y) { - return x > y ? x : y; + return x > y ? x : y; } double rint(double x) { - return freebsd_rint(x); + return freebsd_rint(x); } double fabs(double x) { - return freebsd_fabs(x); + return freebsd_fabs(x); } int isnan(double x) { - return freebsd_isnan(x); + return freebsd_isnan(x); } double trunc(double x) { - return (x > 0) ? freebsd_floor(x) : freebsd_ceil(x); + return (x > 0) ? freebsd_floor(x) : freebsd_ceil(x); } int signbit(double x) { - return ((__HI(x) & 0x80000000) >> 31); + return ((__HI(x) & 0x80000000) >> 31); } diff --git a/core/iwasm/runtime/platform/zephyr/wasm-native.c b/core/iwasm/runtime/platform/zephyr/wasm_native.c similarity index 96% rename from core/iwasm/runtime/platform/zephyr/wasm-native.c rename to core/iwasm/runtime/platform/zephyr/wasm_native.c index 1d35be453..43276fe6e 100644 --- a/core/iwasm/runtime/platform/zephyr/wasm-native.c +++ b/core/iwasm/runtime/platform/zephyr/wasm_native.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "wasm-native.h" +#include "wasm_native.h" void* diff --git a/core/iwasm/runtime/vmcore_wasm/invokeNative_general.c b/core/iwasm/runtime/vmcore-wasm/invokeNative_general.c similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/invokeNative_general.c rename to core/iwasm/runtime/vmcore-wasm/invokeNative_general.c index 19bc6951c..3cb34cffd 100644 --- a/core/iwasm/runtime/vmcore_wasm/invokeNative_general.c +++ b/core/iwasm/runtime/vmcore-wasm/invokeNative_general.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "wasm-runtime.h" +#include "wasm_runtime.h" void invokeNative(uint32 argv[], uint32 argc, void (*native_code)()) { diff --git a/core/iwasm/runtime/vmcore_wasm/invokeNative_ia32.s b/core/iwasm/runtime/vmcore-wasm/invokeNative_ia32.s similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/invokeNative_ia32.s rename to core/iwasm/runtime/vmcore-wasm/invokeNative_ia32.s diff --git a/core/iwasm/runtime/vmcore_wasm/vmcore.cmake b/core/iwasm/runtime/vmcore-wasm/vmcore.cmake similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/vmcore.cmake rename to core/iwasm/runtime/vmcore-wasm/vmcore.cmake diff --git a/core/iwasm/runtime/vmcore_wasm/wasm.h b/core/iwasm/runtime/vmcore-wasm/wasm.h similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/wasm.h rename to core/iwasm/runtime/vmcore-wasm/wasm.h diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-application.c b/core/iwasm/runtime/vmcore-wasm/wasm_application.c similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/wasm-application.c rename to core/iwasm/runtime/vmcore-wasm/wasm_application.c index 5c43b8c8c..df67b3a09 100644 --- a/core/iwasm/runtime/vmcore_wasm/wasm-application.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_application.c @@ -18,9 +18,9 @@ #include #include #include "wasm.h" -#include "wasm-interp.h" -#include "wasm-runtime.h" -#include "wasm-thread.h" +#include "wasm_interp.h" +#include "wasm_runtime.h" +#include "wasm_thread.h" #include "wasm_assert.h" #include "wasm_log.h" #include "wasm_memory.h" diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-interp.c b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/wasm-interp.c rename to core/iwasm/runtime/vmcore-wasm/wasm_interp.c index 6f86bc7f5..f883587e8 100644 --- a/core/iwasm/runtime/vmcore_wasm/wasm-interp.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "wasm-interp.h" -#include "wasm-runtime.h" -#include "wasm-thread.h" -#include "wasm-opcode.h" -#include "wasm-loader.h" +#include "wasm_interp.h" +#include "wasm_runtime.h" +#include "wasm_thread.h" +#include "wasm_opcode.h" +#include "wasm_loader.h" #include "wasm_log.h" #include "wasm_memory.h" diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-interp.h b/core/iwasm/runtime/vmcore-wasm/wasm_interp.h similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/wasm-interp.h rename to core/iwasm/runtime/vmcore-wasm/wasm_interp.h diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-loader.c b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/wasm-loader.c rename to core/iwasm/runtime/vmcore-wasm/wasm_loader.c index c5dba2950..c37a12dfe 100644 --- a/core/iwasm/runtime/vmcore_wasm/wasm-loader.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "wasm-loader.h" +#include "wasm_loader.h" #include "wasm.h" -#include "wasm-native.h" -#include "wasm-opcode.h" -#include "wasm-runtime.h" +#include "wasm_native.h" +#include "wasm_opcode.h" +#include "wasm_runtime.h" #include "wasm_log.h" #include "wasm_memory.h" @@ -373,7 +373,10 @@ resolve_sym(const char *module_name, const char *field_name) return NULL; if (field_name[0] == '_' - && (sym = wasm_dlsym(NULL, field_name + 1))) + && (sym = wasm_dlsym(NULL, field_name + 1))) + return sym; + + if ((sym = wasm_dlsym(NULL, field_name))) return sym; return NULL; diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-loader.h b/core/iwasm/runtime/vmcore-wasm/wasm_loader.h similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/wasm-loader.h rename to core/iwasm/runtime/vmcore-wasm/wasm_loader.h diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-native.h b/core/iwasm/runtime/vmcore-wasm/wasm_native.h similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/wasm-native.h rename to core/iwasm/runtime/vmcore-wasm/wasm_native.h diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-opcode.h b/core/iwasm/runtime/vmcore-wasm/wasm_opcode.h similarity index 100% rename from core/iwasm/runtime/vmcore_wasm/wasm-opcode.h rename to core/iwasm/runtime/vmcore-wasm/wasm_opcode.h diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-runtime.c b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/wasm-runtime.c rename to core/iwasm/runtime/vmcore-wasm/wasm_runtime.c index 5df6d07f2..f6c3c5cce 100644 --- a/core/iwasm/runtime/vmcore_wasm/wasm-runtime.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "wasm-runtime.h" -#include "wasm-thread.h" -#include "wasm-loader.h" -#include "wasm-native.h" -#include "wasm-interp.h" +#include "wasm_runtime.h" +#include "wasm_thread.h" +#include "wasm_loader.h" +#include "wasm_native.h" +#include "wasm_interp.h" #include "wasm_log.h" #include "wasm_platform_log.h" #include "wasm_memory.h" diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-runtime.h b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/wasm-runtime.h rename to core/iwasm/runtime/vmcore-wasm/wasm_runtime.h index c47558470..dfd39f6dd 100644 --- a/core/iwasm/runtime/vmcore_wasm/wasm-runtime.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h @@ -18,7 +18,7 @@ #define _WASM_RUNTIME_H #include "wasm.h" -#include "wasm-thread.h" +#include "wasm_thread.h" #include "wasm_hashmap.h" #ifdef __cplusplus diff --git a/core/iwasm/runtime/vmcore_wasm/wasm-thread.h b/core/iwasm/runtime/vmcore-wasm/wasm_thread.h similarity index 99% rename from core/iwasm/runtime/vmcore_wasm/wasm-thread.h rename to core/iwasm/runtime/vmcore-wasm/wasm_thread.h index 6a03489d2..a1844f141 100644 --- a/core/iwasm/runtime/vmcore_wasm/wasm-thread.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm_thread.h @@ -18,7 +18,7 @@ #define _WASM_RUNTIME_THREAD_H #include "wasm_assert.h" -#include "wasm_thread.h" +#include "wa_thread.h" #ifdef __cplusplus extern "C" { diff --git a/core/shared-lib/coap/LICENSE b/core/shared-lib/coap/LICENSE new file mode 100644 index 000000000..031fe3669 --- /dev/null +++ b/core/shared-lib/coap/LICENSE @@ -0,0 +1,38 @@ +Contiki is licensed under the 3-clause BSD license. This license gives +everyone the right to use and distribute the code, either in binary or +source code format, as long as the copyright license is retained in +the source code. + +The copyright for different parts of the code is held by different +people and organizations, but the code is licensed under the same type +of license. The license text is: + + * Copyright (c) (Year), (Name of copyright holder) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/core/shared-lib/coap/Makefile b/core/shared-lib/coap/Makefile new file mode 100644 index 000000000..913532689 --- /dev/null +++ b/core/shared-lib/coap/Makefile @@ -0,0 +1,19 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +COAP_ROOT=${ZEPHYR_BASE}/subsys/aee/Beihai/runtime/utils/coap +subdir-ccflags-y += -I${COAP_ROOT}/er-coap -I${COAP_ROOT}/extension + +obj-y += er-coap/ +obj-y += extension/ diff --git a/core/shared-lib/coap/er-coap/Makefile b/core/shared-lib/coap/er-coap/Makefile new file mode 100644 index 000000000..d2ba2cdc3 --- /dev/null +++ b/core/shared-lib/coap/er-coap/Makefile @@ -0,0 +1,15 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +obj-y += er-coap.o diff --git a/core/shared-lib/coap/er-coap/er-coap-conf.h b/core/shared-lib/coap/er-coap/er-coap-conf.h new file mode 100755 index 000000000..8491fe75d --- /dev/null +++ b/core/shared-lib/coap/er-coap/er-coap-conf.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Collection of default configuration values. + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_CONF_H_ +#define ER_COAP_CONF_H_ + +/* Features that can be disabled to achieve smaller memory footprint */ +#define COAP_LINK_FORMAT_FILTERING 0 +#define COAP_PROXY_OPTION_PROCESSING 0 + +/* Listening port for the CoAP REST Engine */ +#ifndef COAP_SERVER_PORT +#define COAP_SERVER_PORT COAP_DEFAULT_PORT +#endif + +/* The number of concurrent messages that can be stored for retransmission in the transaction layer. */ +#ifndef COAP_MAX_OPEN_TRANSACTIONS +#define COAP_MAX_OPEN_TRANSACTIONS 4 +#endif /* COAP_MAX_OPEN_TRANSACTIONS */ + +/* Maximum number of failed request attempts before action */ +#ifndef COAP_MAX_ATTEMPTS +#define COAP_MAX_ATTEMPTS 4 +#endif /* COAP_MAX_ATTEMPTS */ + +/* Conservative size limit, as not all options have to be set at the same time. Check when Proxy-Uri option is used */ +#ifndef COAP_MAX_HEADER_SIZE /* Hdr CoF If-Match Obs Blo strings */ +#define COAP_MAX_HEADER_SIZE 512 +//(4 + COAP_TOKEN_LEN + 3 + 1 + COAP_ETAG_LEN + 4 + 4 + 30) /* 65 */ +#endif /* COAP_MAX_HEADER_SIZE */ + +/* Number of observer slots (each takes abot xxx bytes) */ +#ifndef COAP_MAX_OBSERVERS +#define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS - 1 +#endif /* COAP_MAX_OBSERVERS */ + +/* Interval in notifies in which NON notifies are changed to CON notifies to check client. */ +#define COAP_OBSERVE_REFRESH_INTERVAL 20 + +#endif /* ER_COAP_CONF_H_ */ diff --git a/core/shared-lib/coap/er-coap/er-coap-constants.h b/core/shared-lib/coap/er-coap/er-coap-constants.h new file mode 100755 index 000000000..8ed6d903d --- /dev/null +++ b/core/shared-lib/coap/er-coap/er-coap-constants.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Collection of constants specified in the CoAP standard. + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_CONSTANTS_H_ +#define ER_COAP_CONSTANTS_H_ + +#define COAP_DEFAULT_PORT 5683 + +#define COAP_DEFAULT_MAX_AGE 60 +#define COAP_RESPONSE_TIMEOUT 3 +#define COAP_RESPONSE_RANDOM_FACTOR 1.5 +#define COAP_MAX_RETRANSMIT 4 + +#define COAP_HEADER_LEN 4 /* | version:0x03 type:0x0C tkl:0xF0 | code | mid:0x00FF | mid:0xFF00 | */ +#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */ +#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */ + +#define COAP_HEADER_VERSION_MASK 0xC0 +#define COAP_HEADER_VERSION_POSITION 6 +#define COAP_HEADER_TYPE_MASK 0x30 +#define COAP_HEADER_TYPE_POSITION 4 +#define COAP_HEADER_TOKEN_LEN_MASK 0x0F +#define COAP_HEADER_TOKEN_LEN_POSITION 0 + +#define COAP_HEADER_OPTION_DELTA_MASK 0xF0 +#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F + +/* CoAP message types */ +typedef enum { + COAP_TYPE_CON, /* confirmables */ + COAP_TYPE_NON, /* non-confirmables */ + COAP_TYPE_ACK, /* acknowledgements */ + COAP_TYPE_RST /* reset */ +} coap_message_type_t; + +/* CoAP request method codes */ +typedef enum { + COAP_GET = 1, COAP_POST, COAP_PUT, COAP_DELETE +} coap_method_t; + +/* CoAP response codes */ +typedef enum { + NO_ERROR = 0, + + CREATED_2_01 = 65, /* CREATED */ + DELETED_2_02 = 66, /* DELETED */ + VALID_2_03 = 67, /* NOT_MODIFIED */ + CHANGED_2_04 = 68, /* CHANGED */ + CONTENT_2_05 = 69, /* OK */ + CONTINUE_2_31 = 95, /* CONTINUE */ + + BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */ + UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */ + BAD_OPTION_4_02 = 130, /* BAD_OPTION */ + FORBIDDEN_4_03 = 131, /* FORBIDDEN */ + NOT_FOUND_4_04 = 132, /* NOT_FOUND */ + METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */ + NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */ + PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */ + REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */ + UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */ + + INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */ + NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */ + BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */ + SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */ + GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */ + PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */ + + /* Erbium errors */ + MEMORY_ALLOCATION_ERROR = 192, PACKET_SERIALIZATION_ERROR, + + /* Erbium hooks */ + MANUAL_RESPONSE, PING_RESPONSE +} coap_status_t; + +/* CoAP header option numbers */ +typedef enum { + COAP_OPTION_IF_MATCH = 1, /* 0-8 B */ + COAP_OPTION_URI_HOST = 3, /* 1-255 B */ + COAP_OPTION_ETAG = 4, /* 1-8 B */ + COAP_OPTION_IF_NONE_MATCH = 5, /* 0 B */ + COAP_OPTION_OBSERVE = 6, /* 0-3 B */ + COAP_OPTION_URI_PORT = 7, /* 0-2 B */ + COAP_OPTION_LOCATION_PATH = 8, /* 0-255 B */ + COAP_OPTION_URI_PATH = 11, /* 0-255 B */ + COAP_OPTION_CONTENT_FORMAT = 12, /* 0-2 B */ + COAP_OPTION_MAX_AGE = 14, /* 0-4 B */ + COAP_OPTION_URI_QUERY = 15, /* 0-255 B */ + COAP_OPTION_ACCEPT = 17, /* 0-2 B */ + COAP_OPTION_LOCATION_QUERY = 20, /* 0-255 B */ + COAP_OPTION_BLOCK2 = 23, /* 1-3 B */ + COAP_OPTION_BLOCK1 = 27, /* 1-3 B */ + COAP_OPTION_SIZE2 = 28, /* 0-4 B */ + COAP_OPTION_PROXY_URI = 35, /* 1-1034 B */ + COAP_OPTION_PROXY_SCHEME = 39, /* 1-255 B */ + COAP_OPTION_SIZE1 = 60, /* 0-4 B */ +} coap_option_t; + +/* CoAP Content-Formats */ +typedef enum { + TEXT_PLAIN = 0, + TEXT_XML = 1, + TEXT_CSV = 2, + TEXT_HTML = 3, + IMAGE_GIF = 21, + IMAGE_JPEG = 22, + IMAGE_PNG = 23, + IMAGE_TIFF = 24, + AUDIO_RAW = 25, + VIDEO_RAW = 26, + APPLICATION_LINK_FORMAT = 40, + APPLICATION_XML = 41, + APPLICATION_OCTET_STREAM = 42, + APPLICATION_RDF_XML = 43, + APPLICATION_SOAP_XML = 44, + APPLICATION_ATOM_XML = 45, + APPLICATION_XMPP_XML = 46, + APPLICATION_EXI = 47, + APPLICATION_FASTINFOSET = 48, + APPLICATION_SOAP_FASTINFOSET = 49, + APPLICATION_JSON = 50, + APPLICATION_X_OBIX_BINARY = 51 +} coap_content_format_t; + +#endif /* ER_COAP_CONSTANTS_H_ */ diff --git a/core/shared-lib/coap/er-coap/er-coap.c b/core/shared-lib/coap/er-coap/er-coap.c new file mode 100755 index 000000000..88e61836a --- /dev/null +++ b/core/shared-lib/coap/er-coap/er-coap.c @@ -0,0 +1,1131 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * An implementation of the Constrained Application Protocol (RFC). + * \author + * Matthias Kovatsch + */ + +#include +#include +//#include "contiki.h" +//#include "sys/cc.h" +//#include "contiki-net.h" + +#include "bh_common.h" +#include "er-coap.h" +/*#include "er-coap-transactions.h"*/ + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +/*---------------------------------------------------------------------------*/ +/*- Variables ---------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +static uint16_t current_mid = 0; + +coap_status_t erbium_status_code = NO_ERROR; +char *coap_error_message = ""; +/*---------------------------------------------------------------------------*/ +/*- Local helper functions --------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +uint16_t coap_log_2(uint16_t value) +{ + uint16_t result = 0; + + do { + value = value >> 1; + result++; + } while (value); + + return result ? result - 1 : result; +} +/*---------------------------------------------------------------------------*/ +uint32_t coap_parse_int_option(uint8_t *bytes, size_t length) +{ + uint32_t var = 0; + int i = 0; + + while (i < length) { + var <<= 8; + var |= bytes[i++]; + } + return var; +} +/*---------------------------------------------------------------------------*/ +static uint8_t coap_option_nibble(unsigned int value) +{ + if (value < 13) { + return value; + } else if (value <= 0xFF + 13) { + return 13; + } else { + return 14; + } +} +/*---------------------------------------------------------------------------*/ +static size_t coap_set_option_header(unsigned int delta, size_t length, + uint8_t *buffer) +{ + size_t written = 0; + + buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length); + + /* avoids code duplication without function overhead */ + unsigned int *x = δ + + do { + if (*x > 268) { + buffer[++written] = (*x - 269) >> 8; + buffer[++written] = (*x - 269); + } else if (*x > 12) { + buffer[++written] = (*x - 13); + } + } while (x != (unsigned int*) &length && (x = (unsigned int*) &length)); + + PRINTF("WRITTEN %u B opt header\n", 1 + written); + + return ++written; +} +/*---------------------------------------------------------------------------*/ +size_t coap_serialize_int_option(unsigned int number, + unsigned int current_number, uint8_t *buffer, uint32_t value) +{ + size_t i = 0; + + if (0xFF000000 & value) { + ++i; + } + if (0xFFFF0000 & value) { + ++i; + } + if (0xFFFFFF00 & value) { + ++i; + } + // if(0xFFFFFFFF & value) { + ++i; + // } + PRINTF("OPTION %u (delta %u, len %u)\n", number, number - current_number, + i); + + i = coap_set_option_header(number - current_number, i, buffer); + + if (0xFF000000 & value) { + buffer[i++] = (uint8_t)(value >> 24); + } + if (0xFFFF0000 & value) { + buffer[i++] = (uint8_t)(value >> 16); + } + if (0xFFFFFF00 & value) { + buffer[i++] = (uint8_t)(value >> 8); + } + // if(0xFFFFFFFF & value) { + buffer[i++] = (uint8_t)(value); + // } + return i; +} +/*---------------------------------------------------------------------------*/ +size_t coap_serialize_array_option(unsigned int number, + unsigned int current_number, uint8_t *buffer, uint8_t *array, + size_t length, char split_char) +{ + size_t i = 0; + + PRINTF("ARRAY type %u, len %u, full [%.*s]\n", number, length, length, + array); + + if (split_char != '\0') { + int j; + uint8_t *part_start = array; + uint8_t *part_end = NULL; + size_t temp_length; + + for (j = 0; j <= length + 1; ++j) { + PRINTF("STEP %u/%u (%c)\n", j, length, array[j]); + if (array[j] == split_char || j == length) { + part_end = array + j; + temp_length = part_end - part_start; + + i += coap_set_option_header(number - current_number, + temp_length, &buffer[i]); + bh_memcpy_s(&buffer[i], temp_length, part_start, temp_length); + i += temp_length; + + PRINTF("OPTION type %u, delta %u, len %u, part [%.*s]\n", number, + number - current_number, i, temp_length, part_start); + + ++j; /* skip the splitter */ + current_number = number; + part_start = array + j; + } + } /* for */ + } else { + i += coap_set_option_header(number - current_number, length, + &buffer[i]); + bh_memcpy_s(&buffer[i], length, array, length); + i += length; + + PRINTF("OPTION type %u, delta %u, len %u\n", number, + number - current_number, length); + } + + return i; +} +/*---------------------------------------------------------------------------*/ +void coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option, + size_t option_len, char separator) +{ + /* merge multiple options */ + if (*dst_len > 0) { + /* dst already contains an option: concatenate */ + (*dst)[*dst_len] = separator; + *dst_len += 1; + + /* memmove handles 2-byte option headers */ + memmove((*dst) + (*dst_len), option, option_len); + + *dst_len += option_len; + } else { + /* dst is empty: set to option */ + *dst = (char *) option; + *dst_len = option_len; + } +} +/*---------------------------------------------------------------------------*/ +#if 0 +static int +coap_get_variable(const char *buffer, size_t length, const char *name, + const char **output) +{ + const char *start = NULL; + const char *end = NULL; + const char *value_end = NULL; + size_t name_len = 0; + + /*initialize the output buffer first */ + *output = 0; + + name_len = strlen(name); + end = buffer + length; + + for(start = buffer; start + name_len < end; ++start) { + if((start == buffer || start[-1] == '&') && start[name_len] == '=' + && strncmp(name, start, name_len) == 0) { + + /* Point start to variable value */ + start += name_len + 1; + + /* Point end to the end of the value */ + value_end = (const char *)memchr(start, '&', end - start); + if(value_end == NULL) { + value_end = end; + } + *output = start; + + return value_end - start; + } + } + return 0; +} +#endif +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +uint16_t coap_get_mid() +{ + return ++current_mid; +} + +/*---------------------------------------------------------------------------*/ +void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, + uint16_t mid) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + /* Important thing */ + memset(coap_pkt, 0, sizeof(coap_packet_t)); + + coap_pkt->type = type; + coap_pkt->code = code; + coap_pkt->mid = mid; +} +#if 0 +/*---------------------------------------------------------------------------*/ +size_t +coap_serialize_message(void *packet, uint8_t *buffer) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + uint8_t *option; + unsigned int current_number = 0; + + /* Initialize */ + coap_pkt->buffer = buffer; + coap_pkt->version = 1; + + PRINTF("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer); + + /* set header fields */ + coap_pkt->buffer[0] = 0x00; + coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK + & (coap_pkt->version) << COAP_HEADER_VERSION_POSITION; + coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK + & (coap_pkt->type) << COAP_HEADER_TYPE_POSITION; + coap_pkt->buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK + & (coap_pkt->token_len) << COAP_HEADER_TOKEN_LEN_POSITION; + coap_pkt->buffer[1] = coap_pkt->code; + coap_pkt->buffer[2] = (uint8_t)((coap_pkt->mid) >> 8); + coap_pkt->buffer[3] = (uint8_t)(coap_pkt->mid); + + /* empty packet, dont need to do more stuff */ + if(!coap_pkt->code) { + PRINTF("-Done serializing empty message at %p-\n", option); + return 4; + } + + /* set Token */ + PRINTF("Token (len %u)", coap_pkt->token_len); + option = coap_pkt->buffer + COAP_HEADER_LEN; + for(current_number = 0; current_number < coap_pkt->token_len; + ++current_number) { + PRINTF(" %02X", coap_pkt->token[current_number]); + *option = coap_pkt->token[current_number]; + ++option; + } + PRINTF("-\n"); + + /* Serialize options */ + current_number = 0; + + PRINTF("-Serializing options at %p-\n", option); + + /* The options must be serialized in the order of their number */ + COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0', + "Uri-Host"); + COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH, + content_format - + coap_pkt-> + content_format /* hack to get a zero field */, + "If-None-Match"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/', + "Location-Path"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/', + "Uri-Path"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format, + "Content-Format"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&', + "Uri-Query"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query, + '&', "Location-Query"); + COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2"); + COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0', + "Proxy-Uri"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0', + "Proxy-Scheme"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1"); + + PRINTF("-Done serializing at %p----\n", option); + + /* Pack payload */ + if((option - coap_pkt->buffer) <= COAP_MAX_HEADER_SIZE) { + /* Payload marker */ + if(coap_pkt->payload_len) { + *option = 0xFF; + ++option; + } + memmove(option, coap_pkt->payload, coap_pkt->payload_len); + } else { + /* an error occurred: caller must check for !=0 */ + coap_pkt->buffer = NULL; + coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE"; + return 0; + } + + PRINTF("-Done %u B (header len %u, payload len %u)-\n", + coap_pkt->payload_len + option - buffer, option - buffer, + coap_pkt->payload_len); + + PRINTF("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n", + coap_pkt->buffer[0], + coap_pkt->buffer[1], + coap_pkt->buffer[2], + coap_pkt->buffer[3], + coap_pkt->buffer[4], + coap_pkt->buffer[5], coap_pkt->buffer[6], coap_pkt->buffer[7] + ); + + return (option - buffer) + coap_pkt->payload_len; /* packet length */ +} + +/*---------------------------------------------------------------------------*/ +coap_status_t +coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + /* initialize packet */ + memset(coap_pkt, 0, sizeof(coap_packet_t)); + + /* pointer to packet bytes */ + coap_pkt->buffer = data; + + /* parse header fields */ + coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0]) + >> COAP_HEADER_VERSION_POSITION; + coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0]) + >> COAP_HEADER_TYPE_POSITION; + coap_pkt->token_len = + MIN(COAP_TOKEN_LEN, + (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt-> + buffer[0]) >> COAP_HEADER_TOKEN_LEN_POSITION); + coap_pkt->code = coap_pkt->buffer[1]; + coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3]; + + if(coap_pkt->version != 1) { + coap_error_message = "CoAP version must be 1"; + return BAD_REQUEST_4_00; + } + + uint8_t *current_option = data + COAP_HEADER_LEN; + + bh_memcpy_s(coap_pkt->token, COAP_TOKEN_LEN, current_option, coap_pkt->token_len); + PRINTF("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1], + coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4], + coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7] + ); /*FIXME always prints 8 bytes */ + + /* parse options */ + memset(coap_pkt->options, 0, sizeof(coap_pkt->options)); + current_option += coap_pkt->token_len; + + unsigned int option_number = 0; + unsigned int option_delta = 0; + size_t option_length = 0; + + while(current_option < data + data_len) { + /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */ + if((current_option[0] & 0xF0) == 0xF0) { + coap_pkt->payload = ++current_option; + coap_pkt->payload_len = data_len - (coap_pkt->payload - data); + + /* also for receiving, the Erbium upper bound is REST_MAX_CHUNK_SIZE */ + if(coap_pkt->payload_len > REST_MAX_CHUNK_SIZE) { + coap_pkt->payload_len = REST_MAX_CHUNK_SIZE; + /* null-terminate payload */ + } + coap_pkt->payload[coap_pkt->payload_len] = '\0'; + + break; + } + + option_delta = current_option[0] >> 4; + option_length = current_option[0] & 0x0F; + ++current_option; + + /* avoids code duplication without function overhead */ + unsigned int *x = &option_delta; + + do { + if(*x == 13) { + *x += current_option[0]; + ++current_option; + } else if(*x == 14) { + *x += 255; + *x += current_option[0] << 8; + ++current_option; + *x += current_option[0]; + ++current_option; + } + }while(x != (unsigned int*)&option_length && (x = (unsigned int*)&option_length)); + + option_number += option_delta; + + PRINTF("OPTION %u (delta %u, len %u): ", option_number, option_delta, + option_length); + + SET_OPTION(coap_pkt, option_number); + + switch(option_number) { + case COAP_OPTION_CONTENT_FORMAT: + coap_pkt->content_format = coap_parse_int_option(current_option, + option_length); + PRINTF("Content-Format [%u]\n", coap_pkt->content_format); + break; + case COAP_OPTION_MAX_AGE: + coap_pkt->max_age = coap_parse_int_option(current_option, + option_length); + PRINTF("Max-Age [%lu]\n", coap_pkt->max_age); + break; + case COAP_OPTION_ETAG: + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length); + bh_memcpy_s(coap_pkt->etag, COAP_ETAG_LEN, current_option, coap_pkt->etag_len); + PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1], + coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4], + coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7] + ); /*FIXME always prints 8 bytes */ + break; + case COAP_OPTION_ACCEPT: + coap_pkt->accept = coap_parse_int_option(current_option, option_length); + PRINTF("Accept [%u]\n", coap_pkt->accept); + break; + case COAP_OPTION_IF_MATCH: + /* TODO support multiple ETags */ + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length); + bh_memcpy_s(coap_pkt->if_match, COAP_ETAG_LEN, current_option, coap_pkt->if_match_len); + PRINTF("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->if_match_len, coap_pkt->if_match[0], + coap_pkt->if_match[1], coap_pkt->if_match[2], + coap_pkt->if_match[3], coap_pkt->if_match[4], + coap_pkt->if_match[5], coap_pkt->if_match[6], + coap_pkt->if_match[7] + ); /* FIXME always prints 8 bytes */ + break; + case COAP_OPTION_IF_NONE_MATCH: + coap_pkt->if_none_match = 1; + PRINTF("If-None-Match\n"); + break; + + case COAP_OPTION_PROXY_URI: +#if COAP_PROXY_OPTION_PROCESSING + coap_pkt->proxy_uri = (char *)current_option; + coap_pkt->proxy_uri_len = option_length; +#endif + PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", coap_pkt->proxy_uri_len, + coap_pkt->proxy_uri); + coap_error_message = "This is a constrained server (Contiki)"; + return PROXYING_NOT_SUPPORTED_5_05; + break; + case COAP_OPTION_PROXY_SCHEME: +#if COAP_PROXY_OPTION_PROCESSING + coap_pkt->proxy_scheme = (char *)current_option; + coap_pkt->proxy_scheme_len = option_length; +#endif + PRINTF("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n", + coap_pkt->proxy_scheme_len, coap_pkt->proxy_scheme); + coap_error_message = "This is a constrained server (Contiki)"; + return PROXYING_NOT_SUPPORTED_5_05; + break; + + case COAP_OPTION_URI_HOST: + coap_pkt->uri_host = (char *)current_option; + coap_pkt->uri_host_len = option_length; + PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->uri_host); + break; + case COAP_OPTION_URI_PORT: + coap_pkt->uri_port = coap_parse_int_option(current_option, + option_length); + PRINTF("Uri-Port [%u]\n", coap_pkt->uri_port); + break; + case COAP_OPTION_URI_PATH: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **)&(coap_pkt->uri_path), + &(coap_pkt->uri_path_len), current_option, + option_length, '/'); + PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->uri_path); + break; + case COAP_OPTION_URI_QUERY: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **)&(coap_pkt->uri_query), + &(coap_pkt->uri_query_len), current_option, + option_length, '&'); + PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, + coap_pkt->uri_query); + break; + + case COAP_OPTION_LOCATION_PATH: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **)&(coap_pkt->location_path), + &(coap_pkt->location_path_len), current_option, + option_length, '/'); + PRINTF("Location-Path [%.*s]\n", coap_pkt->location_path_len, + coap_pkt->location_path); + break; + case COAP_OPTION_LOCATION_QUERY: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **)&(coap_pkt->location_query), + &(coap_pkt->location_query_len), current_option, + option_length, '&'); + PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, + coap_pkt->location_query); + break; + + case COAP_OPTION_OBSERVE: + coap_pkt->observe = coap_parse_int_option(current_option, + option_length); + PRINTF("Observe [%lu]\n", coap_pkt->observe); + break; + case COAP_OPTION_BLOCK2: + coap_pkt->block2_num = coap_parse_int_option(current_option, + option_length); + coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3; + coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F) + << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_num >>= 4; + PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, + coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size); + break; + case COAP_OPTION_BLOCK1: + coap_pkt->block1_num = coap_parse_int_option(current_option, + option_length); + coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3; + coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07); + coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F) + << (coap_pkt->block1_num & 0x07); + coap_pkt->block1_num >>= 4; + PRINTF("Block1 [%lu%s (%u B/blk)]\n", coap_pkt->block1_num, + coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size); + break; + case COAP_OPTION_SIZE2: + coap_pkt->size2 = coap_parse_int_option(current_option, option_length); + PRINTF("Size2 [%lu]\n", coap_pkt->size2); + break; + case COAP_OPTION_SIZE1: + coap_pkt->size1 = coap_parse_int_option(current_option, option_length); + PRINTF("Size1 [%lu]\n", coap_pkt->size1); + break; + default: + PRINTF("unknown (%u)\n", option_number); + /* check if critical (odd) */ + if(option_number & 1) { + coap_error_message = "Unsupported critical option"; + return BAD_OPTION_4_02; + } + } + + current_option += option_length; + } /* for */ + PRINTF("-Done parsing-------\n"); + + return NO_ERROR; +} +/*---------------------------------------------------------------------------*/ +/*- REST Engine API ---------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +int +coap_get_query_variable(void *packet, const char *name, const char **output) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { + return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len, + name, output); + } + return 0; +} +int +coap_get_post_variable(void *packet, const char *name, const char **output) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(coap_pkt->payload_len) { + return coap_get_variable((const char *)coap_pkt->payload, + coap_pkt->payload_len, name, output); + } + return 0; +} +#endif +/*---------------------------------------------------------------------------*/ +int coap_set_status_code(void *packet, unsigned int code) +{ + if (code <= 0xFF) { + ((coap_packet_t *) packet)->code = (uint8_t) code; + return 1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------------*/ +int coap_set_token(void *packet, const uint8_t *token, size_t token_len) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len); + bh_memcpy_s(coap_pkt->token, COAP_TOKEN_LEN, token, coap_pkt->token_len); + + return coap_pkt->token_len; +} +/*---------------------------------------------------------------------------*/ +/*- CoAP REST Implementation API --------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +int coap_get_header_content_format(void *packet, unsigned int *format) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) { + return 0; + } + *format = coap_pkt->content_format; + return 1; +} +int coap_set_header_content_format(void *packet, unsigned int format) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->content_format = (coap_content_format_t) format; + SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_accept(void *packet, unsigned int *accept) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_ACCEPT)) { + return 0; + } + *accept = coap_pkt->accept; + return 1; +} +int coap_set_header_accept(void *packet, unsigned int accept) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->accept = (coap_content_format_t) accept; + SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_max_age(void *packet, uint32_t *age) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_MAX_AGE)) { + *age = COAP_DEFAULT_MAX_AGE; + } else { + *age = coap_pkt->max_age; + } + return 1; +} +int coap_set_header_max_age(void *packet, uint32_t age) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->max_age = age; + SET_OPTION(coap_pkt, COAP_OPTION_MAX_AGE); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_etag(void *packet, const uint8_t **etag) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { + return 0; + } + *etag = coap_pkt->etag; + return coap_pkt->etag_len; +} +int coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len); + bh_memcpy_s(coap_pkt->etag, COAP_ETAG_LEN, etag, coap_pkt->etag_len); + + SET_OPTION(coap_pkt, COAP_OPTION_ETAG); + return coap_pkt->etag_len; +} +/*---------------------------------------------------------------------------*/ +/*FIXME support multiple ETags */ +int coap_get_header_if_match(void *packet, const uint8_t **etag) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_IF_MATCH)) { + return 0; + } + *etag = coap_pkt->if_match; + return coap_pkt->if_match_len; +} +int coap_set_header_if_match(void *packet, const uint8_t *etag, size_t etag_len) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len); + bh_memcpy_s(coap_pkt->if_match, COAP_ETAG_LEN, etag, + coap_pkt->if_match_len); + + SET_OPTION(coap_pkt, COAP_OPTION_IF_MATCH); + return coap_pkt->if_match_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_if_none_match(void *packet) +{ + return IS_OPTION((coap_packet_t *)packet, + COAP_OPTION_IF_NONE_MATCH) ? 1 : 0; +} +int coap_set_header_if_none_match(void *packet) +{ + SET_OPTION((coap_packet_t * )packet, COAP_OPTION_IF_NONE_MATCH); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_proxy_uri(void *packet, const char **uri) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) { + return 0; + } + *uri = coap_pkt->proxy_uri; + return coap_pkt->proxy_uri_len; +} +int coap_set_header_proxy_uri(void *packet, const char *uri) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + /*TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide er-coap-conf define */ + + coap_pkt->proxy_uri = uri; + coap_pkt->proxy_uri_len = strlen(uri); + + SET_OPTION(coap_pkt, COAP_OPTION_PROXY_URI); + return coap_pkt->proxy_uri_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_uri_host(void *packet, const char **host) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_URI_HOST)) { + return 0; + } + *host = coap_pkt->uri_host; + return coap_pkt->uri_host_len; +} +int coap_set_header_uri_host(void *packet, const char *host) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->uri_host = host; + coap_pkt->uri_host_len = strlen(host); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_HOST); + return coap_pkt->uri_host_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_uri_path(void *packet, const char **path) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_URI_PATH)) { + return 0; + } + *path = coap_pkt->uri_path; + return coap_pkt->uri_path_len; +} +int coap_set_header_uri_path(void *packet, const char *path) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + +// while(path[0] == '/') +// ++path; + + coap_pkt->uri_path = path; + coap_pkt->uri_path_len = strlen(path); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_PATH); + return coap_pkt->uri_path_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_uri_query(void *packet, const char **query) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { + return 0; + } + *query = coap_pkt->uri_query; + return coap_pkt->uri_query_len; +} +int coap_set_header_uri_query(void *packet, const char *query) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + while (query[0] == '?') + ++query; + + coap_pkt->uri_query = query; + coap_pkt->uri_query_len = strlen(query); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); + return coap_pkt->uri_query_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_location_path(void *packet, const char **path) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH)) { + return 0; + } + *path = coap_pkt->location_path; + return coap_pkt->location_path_len; +} +int coap_set_header_location_path(void *packet, const char *path) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + char *query; + + while (path[0] == '/') + ++path; + + if ((query = strchr(path, '?'))) { + coap_set_header_location_query(packet, query + 1); + coap_pkt->location_path_len = query - path; + } else { + coap_pkt->location_path_len = strlen(path); + } + coap_pkt->location_path = path; + + if (coap_pkt->location_path_len > 0) { + SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH); + } + return coap_pkt->location_path_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_location_query(void *packet, const char **query) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) { + return 0; + } + *query = coap_pkt->location_query; + return coap_pkt->location_query_len; +} +int coap_set_header_location_query(void *packet, const char *query) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + while (query[0] == '?') + ++query; + + coap_pkt->location_query = query; + coap_pkt->location_query_len = strlen(query); + + SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY); + return coap_pkt->location_query_len; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_observe(void *packet, uint32_t *observe) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { + return 0; + } + *observe = coap_pkt->observe; + return 1; +} +int coap_set_header_observe(void *packet, uint32_t observe) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->observe = observe; + SET_OPTION(coap_pkt, COAP_OPTION_OBSERVE); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, + uint32_t *size, uint32_t *offset) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK2)) { + return 0; + } + /* pointers may be NULL to get only specific block parameters */ + if (num != NULL) { + *num = coap_pkt->block2_num; + } + if (more != NULL) { + *more = coap_pkt->block2_more; + } + if (size != NULL) { + *size = coap_pkt->block2_size; + } + if (offset != NULL) { + *offset = coap_pkt->block2_offset; + } + return 1; +} +int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, + uint32_t size) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (size < 16) { + return 0; + } + if (size > 2048) { + return 0; + } + if (num > 0x0FFFFF) { + return 0; + } + coap_pkt->block2_num = num; + coap_pkt->block2_more = more ? 1 : 0; + coap_pkt->block2_size = size; + + SET_OPTION(coap_pkt, COAP_OPTION_BLOCK2); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, + uint16_t *size, uint32_t *offset) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK1)) { + return 0; + } + /* pointers may be NULL to get only specific block parameters */ + if (num != NULL) { + *num = coap_pkt->block1_num; + } + if (more != NULL) { + *more = coap_pkt->block1_more; + } + if (size != NULL) { + *size = coap_pkt->block1_size; + } + if (offset != NULL) { + *offset = coap_pkt->block1_offset; + } + return 1; +} +int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, + uint16_t size) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (size < 16) { + return 0; + } + if (size > 2048) { + return 0; + } + if (num > 0x0FFFFF) { + return 0; + } + coap_pkt->block1_num = num; + coap_pkt->block1_more = more; + coap_pkt->block1_size = size; + + SET_OPTION(coap_pkt, COAP_OPTION_BLOCK1); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_size2(void *packet, uint32_t *size) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_SIZE2)) { + return 0; + } + *size = coap_pkt->size2; + return 1; +} +int coap_set_header_size2(void *packet, uint32_t size) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->size2 = size; + SET_OPTION(coap_pkt, COAP_OPTION_SIZE2); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_header_size1(void *packet, uint32_t *size) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_SIZE1)) { + return 0; + } + *size = coap_pkt->size1; + return 1; +} +int coap_set_header_size1(void *packet, uint32_t size) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->size1 = size; + SET_OPTION(coap_pkt, COAP_OPTION_SIZE1); + return 1; +} +/*---------------------------------------------------------------------------*/ +int coap_get_payload(void *packet, const uint8_t **payload) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + if (coap_pkt->payload) { + *payload = coap_pkt->payload; + return coap_pkt->payload_len; + } else { + *payload = NULL; + return 0; + } +} +int coap_set_payload(void *packet, const void *payload, size_t length) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->payload = (uint8_t *) payload; + coap_pkt->payload_len = MIN(REST_MAX_CHUNK_SIZE, length); + + return coap_pkt->payload_len; +} +/*---------------------------------------------------------------------------*/ diff --git a/core/shared-lib/coap/er-coap/er-coap.h b/core/shared-lib/coap/er-coap/er-coap.h new file mode 100755 index 000000000..7c15465d2 --- /dev/null +++ b/core/shared-lib/coap/er-coap/er-coap.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * An implementation of the Constrained Application Protocol (RFC). + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_H_ +#define ER_COAP_H_ + +#include "../extension/coap_platforms.h" +#include /* for size_t */ +#include +//#include "contiki-net.h" +#include "er-coap-constants.h" +#include "er-coap-conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* sanity check for configured values */ +#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE) +/*#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_IPH_LEN - UIP_UDPH_LEN) + #error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE" + #endif + */ + +/* ------------------------------------------------------ */ +/* ------ section added by the coap request --------- */ +/* ------------------------------------------------------ */ + +//typedef int (*restful_response_handler)(void *response,void *data); +#define RX_TIMEOUT (-1) +typedef int (*Tx_Data)(void * coap_ctx, const uip_ipaddr_t *dst_addr, void *buf, int len); +typedef int (*Rx_Data) (void * coap_ctx, void *buf, int len, int timeout); +typedef int (*Request_Handler) (void * coap_ctx, void *); + +typedef int (*CoAP_Res_Handler) (void * request, void * response, char **out_payload, int * payload_len); + +typedef struct _coap_resource_handler +{ + struct _coap_resource_handler * next; + char * url; + CoAP_Res_Handler get_handler; + CoAP_Res_Handler put_handler; + CoAP_Res_Handler post_handler; + CoAP_Res_Handler other_handler; // create | delete +}coap_resource_handler_t; + + + +typedef struct res_block_state +{ + struct res_block_state * next; + char * url; + void * buffer; + int buffer_size; + uint32_t block_num; + uint16_t block_size; + uint16_t content_fmt; + uint32_t last_access; + uint8_t is_get; +} res_block_state_t; + + +typedef struct peer_block_state +{ + struct peer_block_state * next; + struct net_addr_coap peer_addr; + res_block_state_t * list; +}peer_block_state_t; + + +typedef struct coap_context { + uint8_t * buf; + uint32_t buf_len; // the data length + uint32_t buf_size; // the malloced buffer size + + struct net_addr_coap my_addr; + + // the address associated with current buffer + struct net_addr_coap src_addr; + + uint8_t status; + uint8_t is_used; + uint8_t response_on_not_found; + uint16_t default_retrans_cnt; + uint32_t default_retrans_ms; + + Tx_Data tx_data; + Rx_Data rx_data; + + int socket; + char * user_data; + + peer_block_state_t * blockwise_list; + coap_resource_handler_t * resource_handlers; + + void * transactions; + void * transaction_lock; + uint32_t last_checktime; + + void * request_handler; + +#ifdef WITH_DTLS +struct dtls_context_t *dtls_context; +dtls_handler_t dtls_handler; +struct process *process; +#endif /* WITH_DTLS */ + +} coap_context_t; + +int add_resource_handler(coap_context_t * coap_ctx, coap_resource_handler_t * handler); + + +// coap_context_t * coap_context_new(uip_ipaddr_t *my_addr, uint16_t my_port); //CANNOTBUILD +void coap_context_close(coap_context_t *coap_ctx); +void coap_ctx_send(coap_context_t *coap_ctx, uint8_t *data, + uint16_t length); + +/* ---------------- end of section ------------------ */ + + +/* use Erbium CoAP for the REST Engine. Must come before include of rest-engine.h. */ +//#define REST coap_rest_implementation +//#include "rest-engine.h" + +/* REST_MAX_CHUNK_SIZE can be different from 2^x so we need to get next lower 2^x for COAP_MAX_BLOCK_SIZE */ +#ifndef COAP_MAX_BLOCK_SIZE +#define COAP_MAX_BLOCK_SIZE (REST_MAX_CHUNK_SIZE < 32 ? 16 : \ + (REST_MAX_CHUNK_SIZE < 64 ? 32 : \ + (REST_MAX_CHUNK_SIZE < 128 ? 64 : \ + (REST_MAX_CHUNK_SIZE < 256 ? 128 : \ + (REST_MAX_CHUNK_SIZE < 512 ? 256 : \ + (REST_MAX_CHUNK_SIZE < 1024 ? 512 : \ + (REST_MAX_CHUNK_SIZE < 2048 ? 1024 : 2048))))))) +#endif /* COAP_MAX_BLOCK_SIZE */ + +/* direct access into the buffer */ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#ifdef NETSTACK_CONF_WITH_IPV6 +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#else +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN]) +#endif + +/* bitmap for set options */ +enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 }; + +#define SET_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE)) +#define IS_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] & (1 << (opt % OPTION_MAP_SIZE))) + +/* parsed message struct */ +typedef struct { + uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */ + + uint8_t version; + coap_message_type_t type; + uint8_t code; + uint16_t mid; + + uint8_t token_len; + uint8_t token[COAP_TOKEN_LEN]; + + uint8_t options[COAP_OPTION_SIZE1 / OPTION_MAP_SIZE + 1]; /* bitmap to check if option is set */ + + coap_content_format_t content_format; /* parse options once and store; allows setting options in random order */ + uint32_t max_age; + uint8_t etag_len; + uint8_t etag[COAP_ETAG_LEN]; + size_t proxy_uri_len; + const char *proxy_uri; + size_t proxy_scheme_len; + const char *proxy_scheme; + size_t uri_host_len; + const char *uri_host; + size_t location_path_len; + const char *location_path; + uint16_t uri_port; + size_t location_query_len; + const char *location_query; + size_t uri_path_len; + const char *uri_path; + int32_t observe; + coap_content_format_t accept; + uint8_t if_match_len; + uint8_t if_match[COAP_ETAG_LEN]; + uint32_t block2_num; + uint8_t block2_more; + uint32_t block2_size; + uint32_t block2_offset; + uint32_t block1_num; + uint8_t block1_more; + uint32_t block1_size; + uint32_t block1_offset; + uint32_t size2; + uint32_t size1; + size_t uri_query_len; + const char *uri_query; + uint8_t if_none_match; + + uint32_t payload_len; + uint8_t *payload; +} coap_packet_t; + +/* option format serialization */ +#define COAP_SERIALIZE_INT_OPTION(number, field, text) \ + if(IS_OPTION(coap_pkt, number)) { \ + PRINTF(text " [%u]\n", coap_pkt->field); \ + option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \ + current_number = number; \ + } +#define COAP_SERIALIZE_BYTE_OPTION(number, field, text) \ + if(IS_OPTION(coap_pkt, number)) { \ + PRINTF(text " %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->field##_len, \ + coap_pkt->field[0], \ + coap_pkt->field[1], \ + coap_pkt->field[2], \ + coap_pkt->field[3], \ + coap_pkt->field[4], \ + coap_pkt->field[5], \ + coap_pkt->field[6], \ + coap_pkt->field[7] \ + ); /* FIXME always prints 8 bytes */ \ + option += coap_serialize_array_option(number, current_number, option, coap_pkt->field, coap_pkt->field##_len, '\0'); \ + current_number = number; \ + } +#define COAP_SERIALIZE_STRING_OPTION(number, field, splitter, text) \ + if(IS_OPTION(coap_pkt, number)) { \ + PRINTF(text " [%.*s]\n", coap_pkt->field##_len, coap_pkt->field); \ + option += coap_serialize_array_option(number, current_number, option, (uint8_t *)coap_pkt->field, coap_pkt->field##_len, splitter); \ + current_number = number; \ + } +#define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \ + if(IS_OPTION(coap_pkt, number)) \ + { \ + PRINTF(text " [%lu%s (%u B/blk)]\n", coap_pkt->field##_num, coap_pkt->field##_more ? "+" : "", coap_pkt->field##_size); \ + uint32_t block = coap_pkt->field##_num << 4; \ + if(coap_pkt->field##_more) { block |= 0x8; } \ + block |= 0xF & coap_log_2(coap_pkt->field##_size / 16); \ + PRINTF(text " encoded: 0x%lX\n", block); \ + option += coap_serialize_int_option(number, current_number, option, block); \ + current_number = number; \ + } + +/* to store error code and human-readable payload */ +extern coap_status_t erbium_status_code; +extern char *coap_error_message; + +void coap_init_connection(uint16_t port); +uint16_t coap_get_mid(void); + +void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, + uint16_t mid); +size_t coap_serialize_message(void *packet, uint8_t *buffer); +void coap_send_message(coap_context_t*, uip_ipaddr_t *addr, uint16_t port, uint8_t *data, + uint16_t length); +coap_status_t coap_parse_message(void *request, uint8_t *data, + uint16_t data_len); + +int coap_get_query_variable(void *packet, const char *name, + const char **output); +int coap_get_post_variable(void *packet, const char *name, + const char **output); + +/*---------------------------------------------------------------------------*/ + +int coap_set_status_code(void *packet, unsigned int code); + +int coap_set_token(void *packet, const uint8_t *token, size_t token_len); + +int coap_get_header_content_format(void *packet, unsigned int *format); +int coap_set_header_content_format(void *packet, unsigned int format); + +int coap_get_header_accept(void *packet, unsigned int *accept); +int coap_set_header_accept(void *packet, unsigned int accept); + +int coap_get_header_max_age(void *packet, uint32_t *age); +int coap_set_header_max_age(void *packet, uint32_t age); + +int coap_get_header_etag(void *packet, const uint8_t **etag); +int coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len); + +int coap_get_header_if_match(void *packet, const uint8_t **etag); +int coap_set_header_if_match(void *packet, const uint8_t *etag, + size_t etag_len); + +int coap_get_header_if_none_match(void *packet); +int coap_set_header_if_none_match(void *packet); + +int coap_get_header_proxy_uri(void *packet, const char **uri); /* in-place string might not be 0-terminated. */ +int coap_set_header_proxy_uri(void *packet, const char *uri); + +int coap_get_header_proxy_scheme(void *packet, const char **scheme); /* in-place string might not be 0-terminated. */ +int coap_set_header_proxy_scheme(void *packet, const char *scheme); + +int coap_get_header_uri_host(void *packet, const char **host); /* in-place string might not be 0-terminated. */ +int coap_set_header_uri_host(void *packet, const char *host); + +int coap_get_header_uri_path(void *packet, const char **path); /* in-place string might not be 0-terminated. */ +int coap_set_header_uri_path(void *packet, const char *path); + +int coap_get_header_uri_query(void *packet, const char **query); /* in-place string might not be 0-terminated. */ +int coap_set_header_uri_query(void *packet, const char *query); + +int coap_get_header_location_path(void *packet, const char **path); /* in-place string might not be 0-terminated. */ +int coap_set_header_location_path(void *packet, const char *path); /* also splits optional query into Location-Query option. */ + +int coap_get_header_location_query(void *packet, const char **query); /* in-place string might not be 0-terminated. */ +int coap_set_header_location_query(void *packet, const char *query); + +int coap_get_header_observe(void *packet, uint32_t *observe); +int coap_set_header_observe(void *packet, uint32_t observe); + +int coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, + uint32_t *size, uint32_t *offset); +int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, + uint32_t size); + +int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, + uint16_t *size, uint32_t *offset); +int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, + uint16_t size); + +int coap_get_header_size2(void *packet, uint32_t *size); +int coap_set_header_size2(void *packet, uint32_t size); + +int coap_get_header_size1(void *packet, uint32_t *size); +int coap_set_header_size1(void *packet, uint32_t size); + +int coap_get_payload(void *packet, const uint8_t **payload); +int coap_set_payload(void *packet, const void *payload, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* ER_COAP_H_ */ diff --git a/core/shared-lib/coap/extension/Makefile b/core/shared-lib/coap/extension/Makefile new file mode 100644 index 000000000..69f887388 --- /dev/null +++ b/core/shared-lib/coap/extension/Makefile @@ -0,0 +1,15 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +obj-y += coap_over_tcp.o diff --git a/core/shared-lib/coap/extension/coap_conversion.c b/core/shared-lib/coap/extension/coap_conversion.c new file mode 100644 index 000000000..4c0819c98 --- /dev/null +++ b/core/shared-lib/coap/extension/coap_conversion.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "coap_ext.h" + +char * coap_get_full_url_alloc(coap_packet_t * request) +{ + const char *url = NULL; + const char * query = NULL; + int url_len = coap_get_header_uri_path(request, &url); + int query_len = coap_get_header_uri_query(request, &query); + + if (url_len == 0) + return NULL; + + char * url_alloc = (char*) bh_malloc(url_len + 1 + query_len + 1); + memcpy(url_alloc, url, url_len); + url_alloc[url_len] = 0; + + // make the url looks like /abc?e=f + if (query_len != 0) { + strcat(url_alloc, "&"); + memcpy(url_alloc + strlen(url_alloc), query, query_len); + url_alloc[url_len + 1 + query_len] = 0; + } + + return url_alloc; +} + +void convert_request_to_coap_packet(request_t * req, coap_packet_t * packet) +{ + coap_init_message(packet, COAP_TYPE_NON, req->action, req->mid); + coap_set_token(packet, (uint8_t *) &req->mid, sizeof(req->mid)); + coap_set_header_content_format(packet, req->fmt); + + coap_set_header_uri_path(packet, req->url); + + coap_set_payload(packet, req->payload, req->payload_len); + + packet->mid = req->mid; +} + +void convert_response_to_coap_packet(response_t * response, + coap_packet_t * packet) +{ + coap_init_message(packet, COAP_TYPE_NON, response->status, response->mid); + coap_set_token(packet, (uint8_t *) &response->mid, sizeof(response->mid)); + coap_set_header_content_format(packet, response->fmt); + coap_set_payload(packet, response->payload, response->payload_len); + + packet->mid = response->mid; +} + +// return: the length of url. +// note: the url is probably not end with 0 due to coap packing design. +int convert_coap_packet_to_request(coap_packet_t *packet, request_t *request) +{ + const char *url = NULL; + int url_len = coap_get_header_uri_path(packet, &url); + + memset(request, 0, sizeof(*request)); + + request->action = packet->code; + request->fmt = packet->content_format; + if (packet->token_len == 4) { + request->mid = *((unsigned long *) packet->token); + } else { + request->mid = packet->mid; + } + request->payload = packet->payload; + request->payload_len = packet->payload_len; + request->url = (char *)url; + return url_len; +} + +void convert_coap_packet_to_response(coap_packet_t *packet, + response_t *response) +{ + memset(response, 0, sizeof(*response)); + + response->status = packet->code; + response->fmt = packet->content_format; + if (packet->token_len == 4) { + response->mid = *((unsigned long *) packet->token); + } else { + response->mid = packet->mid; + } + + response->payload = packet->payload; + response->payload_len = packet->payload_len; + return; +} diff --git a/core/shared-lib/coap/extension/coap_ext.h b/core/shared-lib/coap/extension/coap_ext.h new file mode 100755 index 000000000..a71596b54 --- /dev/null +++ b/core/shared-lib/coap/extension/coap_ext.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COAP_EXTENSION_COAP_EXT_H_ +#define COAP_EXTENSION_COAP_EXT_H_ + +#include "er-coap.h" +#include "shared_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define COAP_EVENT (COAP_DELETE + 2) + +char * coap_get_full_url_alloc(coap_packet_t * request); + +coap_status_t coap_parse_message_tcp(void *packet, uint8_t *data, + uint32_t data_len); + +int coap_serialize_message_tcp(void *packet, uint8_t ** buffer_out); +int coap_set_payload_tcp(void *packet, const void *payload, size_t length); +uint8_t coap_is_request(coap_packet_t * coap_message); + +uint16_t coap_find_mid(uint8_t *buffer); +uint8_t coap_find_code(uint8_t *buffer); +void coap_change_mid(uint8_t *buffer, uint16_t id); + +int add_resource_handler(coap_context_t * coap_ctx, + coap_resource_handler_t * handler); +uint32_t check_blockwise_timeout_ms(coap_context_t * coap_ctx, int timeout_sec); + +int convert_coap_packet_to_request(coap_packet_t *packet, request_t *request); +void convert_coap_packet_to_response(coap_packet_t *packet, + response_t *response); + +void convert_response_to_coap_packet(response_t * response, + coap_packet_t * packet); +void convert_request_to_coap_packet(request_t * req, coap_packet_t * packet); + +#ifdef __cplusplus +} +#endif +#endif /* COAP_EXTENSION_COAP_EXT_H_ */ diff --git a/core/shared-lib/coap/extension/coap_over_tcp.c b/core/shared-lib/coap/extension/coap_over_tcp.c new file mode 100755 index 000000000..ae50e4c22 --- /dev/null +++ b/core/shared-lib/coap/extension/coap_over_tcp.c @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "bh_common.h" +#include "er-coap.h" +#include "coap_ext.h" +#include "er-coap-constants.h" + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +extern size_t +coap_serialize_array_option(unsigned int number, unsigned int current_number, + uint8_t *buffer, uint8_t *array, size_t length, char split_char); +extern size_t +coap_serialize_int_option(unsigned int number, unsigned int current_number, + uint8_t *buffer, uint32_t value); +extern uint16_t coap_log_2(uint16_t value); +extern uint32_t coap_parse_int_option(uint8_t *bytes, size_t length); +extern void +coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option, + size_t option_len, char separator); + +/* + * + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Len=15 | TKL | Extended Length (32 bits) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | Code | Token (if any, TKL bytes) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Options (if any) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |1 1 1 1 1 1 1 1| Payload (if any) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + */ + +int coap_set_payload_tcp(void *packet, const void *payload, size_t length) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->payload = (uint8_t *) payload; + coap_pkt->payload_len = MIN(REST_MAX_CHUNK_SIZE, length); + + return coap_pkt->payload_len; +} + +#if 0 +static size_t coap_calc_ext_len_field(int len) +{ + if(len < 13) + return 0; + else if(len <= (0xFF+13)) + return 1; + else if(len <= (0xFFFF+269)) + return 2; + else if(len < (0xFFFFFFFF+65805)) + return 4; + else + return 0; +} +#endif + +static size_t coap_max_options_offset(void *packet) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + return 6 + coap_pkt->token_len; +} + +int coap_serialize_message_tcp(void *packet, uint8_t ** buffer_out) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + uint8_t buffer[128]; + + uint8_t *option = buffer; + unsigned int current_number = 0; + + if (coap_pkt->uri_path_len > 100) { + *buffer_out = 0; + return -1; + } + + /* Serialize options */ + current_number = 0; + if (0 == coap_pkt->token_len) { + bh_memcpy_s(coap_pkt->token, COAP_TOKEN_LEN, &coap_pkt->mid, + sizeof(coap_pkt->mid)); + coap_pkt->token_len = sizeof(coap_pkt->mid); + }PRINTF("-Serializing options at %p-\n", option); + + /* The options must be serialized in the order of their number */ + COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0', + "Uri-Host"); + COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH, + content_format - coap_pkt-> content_format /* hack to get a zero field */, + "If-None-Match"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/', + "Location-Path"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, 0, //'/', + "Uri-Path"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format, + "Content-Format"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&', + "Uri-Query"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query, + '&', "Location-Query"); + COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2"); + COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0', + "Proxy-Uri"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0', + "Proxy-Scheme"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1"); + + /* Pack payload */ + if (coap_pkt->payload_len) { + *option = 0xFF; + ++option; + } + uint32_t option_len = option - &buffer[0]; + + uint8_t * p = (uint8_t *) os_malloc( + coap_max_options_offset(packet) + option_len + + coap_pkt->payload_len); + if (p == NULL) + return 0; + *buffer_out = p; + + uint8_t first_4bits; + + *p = (coap_pkt->token_len & 0xF); + uint32_t len = option_len + coap_pkt->payload_len; + + if (len < 13) { + first_4bits = len; + *p++ |= first_4bits << 4; + } else if (len <= (0xFF + 13)) { + first_4bits = 13; + *p++ |= first_4bits << 4; + *p++ = len - 13; + } else if (len <= (0xFFFF + 269)) { + first_4bits = 14; + *p++ |= first_4bits << 4; + len -= 269; + *p = (uint8_t)(len >> 8); + p++; + *p = (uint8_t)(len & 0xFF); + p++; + } else { + first_4bits = 15; + *p++ |= first_4bits << 4; + + len -= 65805; + *p++ = (uint8_t)(len >> 24); + *p++ = (uint8_t)(len >> 16); + *p++ = (uint8_t)(len >> 8); + *p++ = (uint8_t)(len & 0xFF); + } + + *p = coap_pkt->code; + p++; + + if (coap_pkt->token_len) + bh_memcpy_s(p, coap_pkt->token_len, coap_pkt->token, + coap_pkt->token_len); + p += coap_pkt->token_len; + + bh_memcpy_s(p, option_len, buffer, option_len); + p += option_len; + + bh_memcpy_s(p, coap_pkt->payload_len, coap_pkt->payload, + coap_pkt->payload_len); + p += coap_pkt->payload_len; + + return (p - *buffer_out); /* packet length */ +} + +coap_status_t coap_parse_message_tcp(void *packet, uint8_t *data, + uint32_t data_len) +{ + coap_packet_t * const coap_pkt = (coap_packet_t *) packet; + + /* initialize packet */ + memset(coap_pkt, 0, sizeof(coap_packet_t)); + + /* pointer to packet bytes */ + coap_pkt->buffer = data; + + /* parse header fields */ + coap_pkt->version = 1; + coap_pkt->type = COAP_TYPE_NON; + coap_pkt->token_len = MIN(COAP_TOKEN_LEN, data[0] & 0xF); + coap_pkt->mid = 0; + + uint8_t *p = data; + uint8_t first_4bits = data[0] >> 4; + + uint32_t options_payload_size; + uint8_t ext_len_field = 0; + if (first_4bits < 13) { + options_payload_size = first_4bits; + p++; + } else if (first_4bits == 13) { + ext_len_field = 1; + options_payload_size = data[1] + 13; + p += 2; + } else if (first_4bits == 14) { + ext_len_field = 2; + options_payload_size = (uint16_t)(data[1] << 8) + data[2] + 269; + p += 3; + } else if (first_4bits == 15) { + ext_len_field = 4; + options_payload_size = (data[1] << 24) + (data[2] << 16) + + (data[3] << 8) + data[4] + 65805; + p += 5; + } + + // check the data size is smaller than the size indicated by the packet + if (ext_len_field + coap_pkt->token_len + 2 + options_payload_size + > data_len) + return BAD_REQUEST_4_00; + + coap_pkt->code = *p++; + if (coap_pkt->token_len) + bh_memcpy_s(coap_pkt->token, COAP_TOKEN_LEN, p, coap_pkt->token_len); + + if (coap_pkt->token_len >= 2) { + union { + uint16_t *mid; + uint8_t *token; + } mid_token_union; + + mid_token_union.token = coap_pkt->token; + coap_pkt->mid = *(mid_token_union.mid); + } + + p += coap_pkt->token_len; + + uint8_t *current_option = p; + uint8_t * option_start = p; + + /* parse options */ + memset(coap_pkt->options, 0, sizeof(coap_pkt->options)); + + unsigned int option_number = 0; + unsigned int option_delta = 0; + size_t option_length = 0; + + while (current_option < data + data_len) { + /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */ + if ((current_option[0] & 0xF0) == 0xF0) { + coap_pkt->payload = ++current_option; + coap_pkt->payload_len = options_payload_size + - (coap_pkt->payload - option_start); + //coap_pkt->payload_len = data_len - (coap_pkt->payload - data); + break; + } + + option_delta = current_option[0] >> 4; + option_length = current_option[0] & 0x0F; + ++current_option; + + /* avoids code duplication without function overhead */ + unsigned int *x = &option_delta; + + do { + if (*x == 13) { + *x += current_option[0]; + ++current_option; + } else if (*x == 14) { + *x += 255; + *x += current_option[0] << 8; + ++current_option; + *x += current_option[0]; + ++current_option; + } + } while (x != (unsigned int*) &option_length && (x = + (unsigned int*) &option_length)); + option_length = *x; + option_number += option_delta; + + PRINTF("OPTION %u (delta %u, len %u): ", option_number, option_delta, + option_length); + + SET_OPTION(coap_pkt, option_number); + + switch (option_number) { + + case COAP_OPTION_CONTENT_FORMAT: + coap_pkt->content_format = coap_parse_int_option(current_option, + option_length); + PRINTF("Content-Format [%u]\n", coap_pkt->content_format); + break; + case COAP_OPTION_MAX_AGE: + coap_pkt->max_age = coap_parse_int_option(current_option, + option_length); + PRINTF("Max-Age [%lu]\n", coap_pkt->max_age); + break; + case COAP_OPTION_ETAG: + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length); + bh_memcpy_s(coap_pkt->etag, COAP_ETAG_LEN, current_option, + coap_pkt->etag_len); + PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1], + coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4], + coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7] + ); /*FIXME always prints 8 bytes */ + break; + case COAP_OPTION_ACCEPT: + coap_pkt->accept = coap_parse_int_option(current_option, + option_length); + PRINTF("Accept [%u]\n", coap_pkt->accept); + break; + case COAP_OPTION_IF_MATCH: + /* TODO support multiple ETags */ + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length); + bh_memcpy_s(coap_pkt->if_match, COAP_ETAG_LEN, current_option, + coap_pkt->if_match_len); + PRINTF("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->if_match_len, coap_pkt->if_match[0], + coap_pkt->if_match[1], coap_pkt->if_match[2], + coap_pkt->if_match[3], coap_pkt->if_match[4], + coap_pkt->if_match[5], coap_pkt->if_match[6], + coap_pkt->if_match[7] + ); /* FIXME always prints 8 bytes */ + break; + case COAP_OPTION_IF_NONE_MATCH: + coap_pkt->if_none_match = 1; + PRINTF("If-None-Match\n"); + break; + + case COAP_OPTION_PROXY_URI: +#if COAP_PROXY_OPTION_PROCESSING + coap_pkt->proxy_uri = (char *)current_option; + coap_pkt->proxy_uri_len = option_length; +#endif + PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", coap_pkt->proxy_uri_len, + coap_pkt->proxy_uri); + coap_error_message = "This is a constrained server (Contiki)"; + return PROXYING_NOT_SUPPORTED_5_05; + break; + case COAP_OPTION_PROXY_SCHEME: +#if COAP_PROXY_OPTION_PROCESSING + coap_pkt->proxy_scheme = (char *)current_option; + coap_pkt->proxy_scheme_len = option_length; +#endif + PRINTF("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n", + coap_pkt->proxy_scheme_len, coap_pkt->proxy_scheme); + coap_error_message = "This is a constrained server (Contiki)"; + return PROXYING_NOT_SUPPORTED_5_05; + break; + + case COAP_OPTION_URI_HOST: + coap_pkt->uri_host = (char *) current_option; + coap_pkt->uri_host_len = option_length; + PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->uri_host); + break; + case COAP_OPTION_URI_PORT: + coap_pkt->uri_port = coap_parse_int_option(current_option, + option_length); + PRINTF("Uri-Port [%u]\n", coap_pkt->uri_port); + break; + case COAP_OPTION_URI_PATH: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **) &(coap_pkt->uri_path), + &(coap_pkt->uri_path_len), current_option, option_length, + '/'); + PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->uri_path); + break; + case COAP_OPTION_URI_QUERY: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **) &(coap_pkt->uri_query), + &(coap_pkt->uri_query_len), current_option, option_length, + '&'); + PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, + coap_pkt->uri_query); + break; + + case COAP_OPTION_LOCATION_PATH: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **) &(coap_pkt->location_path), + &(coap_pkt->location_path_len), current_option, + option_length, '/'); + PRINTF("Location-Path [%.*s]\n", coap_pkt->location_path_len, + coap_pkt->location_path); + break; + case COAP_OPTION_LOCATION_QUERY: + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option((char **) &(coap_pkt->location_query), + &(coap_pkt->location_query_len), current_option, + option_length, '&'); + PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, + coap_pkt->location_query); + break; + + case COAP_OPTION_OBSERVE: + coap_pkt->observe = coap_parse_int_option(current_option, + option_length); + PRINTF("Observe [%lu]\n", coap_pkt->observe); + break; + case COAP_OPTION_BLOCK2: + coap_pkt->block2_num = coap_parse_int_option(current_option, + option_length); + coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3; + coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F) + << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_num >>= 4; + PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, + coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size); + break; + case COAP_OPTION_BLOCK1: + coap_pkt->block1_num = coap_parse_int_option(current_option, + option_length); + coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3; + coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07); + coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F) + << (coap_pkt->block1_num & 0x07); + coap_pkt->block1_num >>= 4; + PRINTF("Block1 [%lu%s (%u B/blk)]\n", coap_pkt->block1_num, + coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size); + break; + case COAP_OPTION_SIZE2: + coap_pkt->size2 = coap_parse_int_option(current_option, + option_length); + PRINTF("Size2 [%lu]\n", coap_pkt->size2); + break; + case COAP_OPTION_SIZE1: + coap_pkt->size1 = coap_parse_int_option(current_option, + option_length); + PRINTF("Size1 [%lu]\n", coap_pkt->size1); + break; + default: + PRINTF("unknown (%u)\n", option_number); + /* check if critical (odd) */ + if (option_number & 1) { + coap_error_message = "Unsupported critical option"; + return BAD_OPTION_4_02; + } + } + + current_option += option_length; + } /* for */ + PRINTF("-Done parsing-------\n"); + + return NO_ERROR; +} + diff --git a/core/shared-lib/coap/extension/coap_platforms.h b/core/shared-lib/coap/extension/coap_platforms.h new file mode 100755 index 000000000..e3a1ac4c6 --- /dev/null +++ b/core/shared-lib/coap/extension/coap_platforms.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COAP_PLATFORMS_H_ +#define COAP_PLATFORMS_H_ +#ifdef __cplusplus +extern "C" { +#endif +#include "bh_platform.h" +#include +#include +#include +/*#include "list_coap.h"*/ +#include + +#define COAP_TRANS_LOCK(ctx) coap_lock(ctx->transaction_lock) +#define COAP_TRANS_UNLOCK(ctx ) coap_unlock(ctx->transaction_lock) + +/* REST_MAX_CHUNK_SIZE is the max size of payload. + * The maximum buffer size that is provided for resource responses and must be respected due to the limited IP buffer. + * Larger data must be handled by the resource and will be sent chunk-wise through a TCP stream or CoAP blocks. + */ +#ifndef REST_MAX_CHUNK_SIZE +#define REST_MAX_CHUNK_SIZE (1024*1024) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +#define CLOCK_SECOND 1000 + +typedef enum { + A_Raw, A_Sock_Addr, A_IP_Addr, A_Custom +} Net_Addr_Type; + +#define NET_ADDR_RAW_SIZE 32 + +typedef struct net_addr_coap { + Net_Addr_Type addr_type; + union { + char raw[NET_ADDR_RAW_SIZE]; + struct sockaddr_in sock_addr; + } u; + uint16_t port; + uint16_t addr_len; +} net_addr_t; + +#define uip_ipaddr_t struct net_addr_coap + +#define memb_free(x, y) free(x) + +void set_addr_ip(uip_ipaddr_t *, char * ip, int port); +uip_ipaddr_t * new_net_addr(Net_Addr_Type type); +void copy_net_addr(uip_ipaddr_t * dest, uip_ipaddr_t * src); +bool compare_net_addr(uip_ipaddr_t * dest, uip_ipaddr_t * src); + +uint32_t get_elpased_ms(uint32_t * last_system_clock); +uint32_t get_platform_time(); +uint32_t get_platform_time_sec(); + +void coap_sleep_ms(uint32_t ms); +void coap_lock(void *); +void coap_unlock(void *); +void * coap_create_lock(); +void coap_free_lock(void *); + +void *xalloc(uint32_t size); + +#define os_malloc bh_malloc +#define os_free bh_free + +#ifdef __cplusplus +} +#endif +#endif /* COAP_PLATFORMS_H_ */ diff --git a/core/shared-lib/coap/lib_coap.cmake b/core/shared-lib/coap/lib_coap.cmake new file mode 100644 index 000000000..8a35f3cb7 --- /dev/null +++ b/core/shared-lib/coap/lib_coap.cmake @@ -0,0 +1,23 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set (LIB_COAP_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${LIB_COAP_DIR}/er-coap) +include_directories(${LIB_COAP_DIR}/extension) + +file (GLOB_RECURSE source_all ${LIB_COAP_DIR}/*.c) + +set (LIB_COAP_SOURCE ${source_all}) + diff --git a/core/shared-lib/include/bni.h b/core/shared-lib/include/bni.h new file mode 100644 index 000000000..36e797fd6 --- /dev/null +++ b/core/shared-lib/include/bni.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file bni.h + * @date Mon Jul 2 16:54:58 2012 + * + * @brief Beihai native interface. + */ + +#ifndef BNI_H +#define BNI_H + +#include "bh_types.h" + +/* Primitive types */ +typedef uint8 jboolean; +typedef int8 jbyte; +typedef uint16 jchar; +typedef int16 jshort; +typedef int32 jint; +typedef int64 jlong; +typedef float jfloat; +typedef double jdouble; +typedef jint jsize; + +/* Predefined Java class types. */ +struct _jobject; +typedef struct _jobject *jobject; +struct _jclass; +typedef struct _jclass *jclass; +struct _jstring; +typedef struct _jstring *jstring; + +/* Values of jboolean: */ +#define BNI_FALSE 0 +#define BNI_TRUE 1 + +/** + * Return the length of the array object. + * + * @param array Java array object + * + * @return the length of the Java array + */ +#define bni_array_length(array) ((jsize)((uint32)(array)->__length >> 2)) + +/** + * Return the address of the first element of array object. + * + * @param array Java array object + * + * @return the address of the first element of array object + */ +#define bni_array_elem(array) ((array)->__elem) + +/** + * Find the Java class with given class name. + * + * @param name Java class name + * + * @return class object of the Java class if found, NULL otherwise + * + * @throws OutOfMemoryError if VM runs out of memory. + */ +jclass +bni_find_class(const char *name); + +/** + * Throw an exception of given class with message. + * + * @param clazz class object of a subclass of java.lang.Throwable + * @param msg message for the exception or NULL if no message + * + * @return 0 if succeeds, nonzero otherwise + */ +jint +bni_throw_new(jclass clazz, const char *msg); + +/** + * Throw a NullPointerException. + * + * @throws NullPointerException + */ +void +bni_throw_npe(void); + +/** + * Throw an ArrayIndexOutOfBoundsException + * + * @param index the index used to access the array + * + * @throws ArrayIndexOutOfBoundsException + */ +void +bni_throw_aioobe(int index); + +/** + * Determine whether an exception is being thrown. + * + * @return exception object if exception is thrown, NULL otherwise + */ +jobject +bni_exception_occurred(void); + +/** + * Print the current exception to error-reporting channel. + */ +void +bni_exception_describe(void); + +/** + * Clear the currently thrown exception. + */ +void +bni_exception_clear(void); + +/** + * Return the Unicode character number of a string. + * + * @param str Java string object + * + * @return the Unicode character number of the string + */ +jsize +bni_string_length(jstring str); + +/** + * Return the length in bytes of the modified UTF-8 representation of + * a string. + * + * @param str Java string object + * @param start start offset in the string + * @param len number of Unicode characters + * + * @return the UTF-8 length of the string + * + * @throws StringIndexOutOfBoundsException on index overflow. + */ +jsize +bni_string_utf_length(jstring str, jsize start, jsize len); + +/** + * Copies len number of Unicode characters beginning at offset start + * to the given buffer buf. + * + * @param str Java string object + * @param start start offset in the string + * @param len number of Unicode characters to copy + * @param buf buffer for storing the result + */ +void +bni_string_region(jstring str, jsize start, jsize len, jchar *buf); + +/** + * Translates len number of Unicode characters beginning at offset + * start into modified UTF-8 encoding and place the result in the + * given buffer buf. + * + * @param str Java string object + * @param start start offset in the string + * @param len number of Unicode characters to copy + * @param buf buffer for storing the result + * + * @throws StringIndexOutOfBoundsException on index overflow. + */ +void +bni_string_utf_region(jstring str, jsize start, jsize len, char *buf); + +/** + * Translate Unicode characters into modified UTF-8 encoding and return + * the result. + * + * @param str Java string object + * + * @return the UTF-8 encoding string if succeeds, NULL otherwise + */ +char * +bni_string_get_utf_chars(jstring str); + +/** + * Get the given Java object's class index. + * + * @param obj Java object + * + * @return -1 if obj is an array, class index of the object otherwise + */ +jint +bni_object_class_index(jobject obj); + +/** + * Allocate memory from the current instance's private heap. + * + * @param size bytes to allocate + * + * @return pointer to the allocated memory + * + * @throws OutOfMemoryError if VM runs out of memory. + */ +void* +bni_malloc(unsigned size); + +/** + * Allocate memory from the current instance's private heap and clear + * to zero. + * + * @param size bytes to allocate + * + * @return pointer to the allocated memory + * + * @throws OutOfMemoryError if VM runs out of memory. + */ +void* +bni_calloc(unsigned size); + +/** + * Free the memory allocated from the current instance's private heap. + * + * @param ptr pointer to the memory in current instance's private heap + */ +void +bni_free(void *ptr); + +#endif diff --git a/core/shared-lib/include/jeff_export.h b/core/shared-lib/include/jeff_export.h new file mode 100755 index 000000000..360bba7db --- /dev/null +++ b/core/shared-lib/include/jeff_export.h @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file jeff-export.h + * @date Wed Aug 3 18:17:30 2011 + * + * @brief Exported interface for operating or executing JEFF files. + * All interface names start with "jeff_", which is the namespace name + * of this module. + */ + +#ifndef JEFF_EXPORT_H +#define JEFF_EXPORT_H + +#include "bni.h" +#include "korp_types.h" + +/******************************************************************** + * Exported internal types + ********************************************************************/ + +/** + * JEFF file handle type + */ +struct JeffFileHeaderLinked; +typedef struct JeffFileHeaderLinked *jeff_file_t; + +/** + * JEFF class type + */ +struct JeffClassHeaderLinked; +typedef struct JeffClassHeaderLinked *jeff_class_t; + +/** + * VM instance handle type + */ +struct JeffInstanceLocalRoot; +typedef struct JeffInstanceLocalRoot *jeff_instance_t; + +/** + * Record of one native method's definition. + */ +struct JeffNativeMethodDef { + /* Mangled name of the native method. NULL for initialization + functions. */ + const char *mangled_name; + + /* Points to the native C function. */ + void (*func_ptr)(uint32 *); + + /* Return size type of the native function. */ + uint32 return_size_type; +}; + +/******************************************************************** + * Interface for operating global environment of the JEFF VM + ********************************************************************/ + +/** + * Load the core library from the given file buffer and initialize the + * runtime environment (global objects etc.) of the VM. The thread + * calls this function becomes the supervisor thread, which belongs to + * a unique supervisor instance. Currently, if this init failed, + * partially initialized states of the VM runtime environment won't be + * cleaned up, so the VM must be shutdown and restarted. method_defs + * points to an array of native method definition records. + * Initialization functions must be in the front of the array and + * following native method definitions must be sorted by their mangled + * names. + * + * @param file the JEFF file of the core library + * @param file_size the size of the JEFF file of the core library + * @param method_defs native method definition records + * @param method_defs_num number of native method records + * @param heap the heap for the current (supervisor) instance + * + * @return true if succeeds, otherwise the error cannot be recovered + */ +bool +jeff_runtime_init(jeff_file_t file, unsigned file_size, + struct JeffNativeMethodDef *method_defs, unsigned method_defs_num, + void *heap); + +/** + * Load a JEFF file into the VM from the given file buffer. It can be + * called from any VM thread. + * + * @param file the JEFF file to be loaded + * @param size the size of the JEFF file + * @param is_library whether the JEFF file is a library + * @param allow_to_load a function that returns true if classes in the + * given package is allowed to be loaded. The NULL function pointer + * allows all packages. + * @param allow_to_link a function that returns true if classes in the + * given package is allowed to be linked to. The NULL function + * pointer allows all packages. + * + * @return true if succeeds, otherwise detailed error information is + * passed to vmci_diagnostic_print. The caller can catch it by + * implementing that function. + */ +bool +jeff_runtime_load(jeff_file_t file, unsigned size, bool is_library, + bool (*allow_to_load)(const uint8 *pname, unsigned len), + bool (*allow_to_link)(const uint8 *pname, unsigned plen, + const uint8 *cname, unsigned clen)); + +/** + * Unload a JEFF file from the VM. All resources related to the JEFF + * file except the JEFF file itself are released. It can be called + * from any VM thread. + * + * @param file the JEFF file to be unloaded + * + * @return true if succeeds, otherwise detailed error information is + * passed to vmci_diagnostic_print. The caller can catch it by + * implementing that function. + */ +bool +jeff_runtime_unload(jeff_file_t file); + +/** + * Return the JEFF file with the given file uid. + * + * @param fuid the unique id of a loaded JEFF file + * + * @return the JEFF file is exists, otherwise NULL + */ +jeff_file_t +jeff_runtime_fuid_to_file(unsigned fuid); + +/** + * Return the file uid of the given JEFF file. + * + * @param file a loaded JEFF file + * + * @return the unique id of the given JEFF file + */ +unsigned +jeff_runtime_file_to_fuid(jeff_file_t file); + +/** + * Create a supervisor thread belonging to the supervisor instance. + * Threads that may interact with VM core must be either the main + * thread of supervisor instance (which calls jeff_runtime_init) or + * created by this function so that VM core required data structures + * can be set up correctly. + * + * @param start_routine the start routine of the new thread + * @param arg argument to the start routine + * + * @return true if succeeds, false otherwise + */ +bool +jeff_runtime_create_supervisor_thread(void* (*start_routine)(void *), + void *arg); + +/** + * Create a supervisor thread belonging to the supervisor instance. + * Threads that may interact with VM core must be either the main + * thread of supervisor instance (which calls jeff_runtime_init) or + * created by this function so that VM core required data structures + * can be set up correctly. + * + * @param start_routine the start routine of the new thread + * @param arg argument to the start routine + * @param prio thread priority + * + * @return true if succeeds, false otherwise + */ +bool +jeff_runtime_create_supervisor_thread_with_prio(void* (*start_routine)(void *), + void *arg, int prio); + +/******************************************************************** + * Interface for operating instance local environment + ********************************************************************/ + +/** + * Create a VM instance with the given JEFF file as its main file, + * (i.e. the file containing the main class of the VM instance). This + * function can be called from any VM thread, but it must be isolated + * from JEFF file's unloading operation so that the main file won't be + * unloaded before it's locked by the new instance. All instance + * local memory except stacks of threads are allocated from the given + * heap. If succeeds, it increases reference count of the main_file + * and returns the handle of the new VM instance. The new instance's + * main thread will run the start_routine with argument arg. If the + * cleanup_routine is not NULL, it will be called after start_routine + * returns and just before the main thread exits. It will also be + * called after the instance is destroied. It is guaranteed to be + * called exactly once no matter how the instance terminates. + * + * @param main_file the main JEFF file of the new instance + * @param heap the private heap of the new instance + * @param stack_depth the maximal nesting levels of Java methods of + * the new instance. It must be <= 16 * 1024. Otherwise the instance + * creation will fail. + * @param start_routine start routine of the main thread. Don't + * destroy the heap or inform other thread to do this at the end of + * this routine since after it returns, VM core will call destroy + * functions on objects allocated in this heap (e.g. locks and + * condition variables). Do the destroying or informing of destroying + * in the cleanup_routine. + * @param arg the instance argument that will be passed to the start + * routine. It can be get or set by jeff_runtime_get_instance_arg and + * jeff_runtime_set_instance arg from threads of the instance. The + * caller can use it to store instance local data. + * @param cleanup_routine the optional cleanup routine for the + * instance, which may be NULL. It may be executed in the end of the + * main thread of the created instance by this function if this + * instance exits normally, or it may be executed in a thread of other + * instance in case this instance is being killed by that instance. + * In both cases, this routine regards it is executed in a thread of + * this instance (the instance created by this function) because + * jeff_runtime_get_instance_arg will always return the argument of + * this instance. + * + * @return the VM instance handle if succeeds, NULL otherwise + */ +jeff_instance_t +jeff_runtime_create_instance(jeff_file_t main_file, void *heap, + unsigned stack_depth, void* (*start_routine)(void *), void *arg, + void (*cleanup_routine)(void)); + +/** + * Destroy the given VM instance and decrease the reference count of + * its main file and all explicitly used JEFF files. It can be called + * from any VM thread. If there are alive threads of the instance, + * they will be terminated mandatorily and then the cleanup routine is + * called if it's not NULL. + * + * @param handle the handle of the instance to be destroyed + */ +void +jeff_runtime_destroy_instance(jeff_instance_t handle); + +/** + * Retrieve the current instance's argument. + * + * @return the current instance's argument + */ +void* +jeff_runtime_get_instance_arg(void); + +/** + * Set the current instance's argument. + * + * @return the new argument for the current instance + */ +void +jeff_runtime_set_instance_arg(void *arg); + +/** + * Retrieve the current instance's heap. + * + * @return the current instance's heap + */ +void* +jeff_runtime_get_instance_heap(void); + +/** + * Suspend all threads of the given VM instance. This function can + * only be called from thread that is not of the given VM instance. + * + * @param handle the handle of the instance to be suspended + */ +void +jeff_runtime_suspend_instance(jeff_instance_t handle); + +/** + * Resume all threads of the given VM instance. This function can + * only be called from thread that is not of the given VM instance. + * + * @param handle the handle of the instance to be resumed + */ +void +jeff_runtime_resume_instance(jeff_instance_t handle); + +/** + * Interrupt all threads of the given VM instance. This function can + * only be called from thread that is not of the given VM instance. + * + * @param handle the handle of the instance to be interrupted + * @param by_force whether the interruption is by force + */ +void +jeff_runtime_interrupt_instance(jeff_instance_t handle, bool by_force); + +/** + * Wait for the given VM instance to terminate. + * + * @param ilr the VM instance to be waited for + * @param mills wait millseconds to return + */ +void +jeff_runtime_wait_for_instance(jeff_instance_t ilr, int mills); + +/******************************************************************** + * Interface for operating thread local environment + ********************************************************************/ + +/** + * Return true if there is an uncaught exception (thrown during + * running an application or applet command). + * + * @return true if there is an uncaught exception + */ +bool +jeff_runtime_check_uncaught_exception(void); + +/** + * Print qualified name of the uncaught exception (and stack trace if + * enabled) by calling vmci_diagnostic_print. + */ +void +jeff_runtime_print_uncaught_exception(void); + +/** + * Clear the uncaught exception. + */ +void +jeff_runtime_reset_uncaught_exception(void); + +/** + * Change current thread to a safe state (VMWAIT). After calling this + * and before calling jeff_runtime_exit_safe_state, all operations + * must be safe, i.e. no GC or system level resource operations are + * allowed because in a safe state, the VM instance is assumed to be + * able to perform GC, JDWP or termination at any time. Usually, this + * function is called just before the native code is going to wait for + * something and the exiting safe state function is called just after + * the waiting returns. + */ +void +jeff_runtime_enter_safe_state(void); + +/** + * Change current thread to an unsafe state (RUNNING) so that unsafe + * operations can also be done. + */ +void +jeff_runtime_exit_safe_state(void); + +/** + * Set thread local error code for the current thread. + * + * @param code the error code to be set + */ +void +jeff_runtime_set_error(unsigned code); + +/** + * Get the last error code of current thread. + * + * @return the last error code of current thread + */ +unsigned +jeff_runtime_get_error(void); + +/******************************************************************** + * Interface for GC support + ********************************************************************/ + +/** + * Traverse all objects of the given heap that are global or locate in + * threads' frames and return them by calling vmci_gc_rootset_elem. + * This function will suspend all threads except the current one of + * the VM instance owning the given heap before traversing. It + * traverses either all or none of the rootset objects, and returns + * true and false respectively. If it returns false, the GC process + * shouldn't proceed and is not necessary to unmark anything because + * no objects are marked. The function jeff_runtime_gc_finished must + * be called if and only if this function returns true so as to resume + * threads that are suspended during GC process. + * + * @param heap the heap for which rootset objects are looked up + * + * @return true if succeeds, false otherwise + */ +bool +jeff_runtime_traverse_gc_rootset(void *heap); + +/** + * Get the reference offset table of the given object. If the + * returned value R >= 0, *ret points to the reference offset table of + * the object and R is the number of offsets in the table. Otherwise, + * if the returned value R < 0, all reference fields of the object + * must be in a continuous region (usually the object is an array), + * then *ret is the offset to the first field in the region and R is + * the number of such fields in the region. + * + * @param obj pointer to the Java object + * @param ret points to a pointer for storing the reference offset + * table if return value >= 0, or for storing the offset to the first + * object reference in the Java object if return value < 0 + * + * @return number of offsets in the reference_offset table if >= 0, or + * number of object references in the object if < 0 + */ +int +jeff_object_get_reference_offsets(const jobject obj, uint16 **ret); + +/** + * Inform the containing VM instance that GC has finished and all + * suspended threads can be resumed. This function must be called if + * and only if jeff_runtime_traverse_gc_rootset returns true. + */ +void +jeff_runtime_gc_finished(void); + +/******************************************************************** + * Interface for tooling support + ********************************************************************/ + +/** + * This function is used to suspend the main thread of VM instance so + * that debugger can have chance to connect to the VM instance, set + * breakpoints and do any other debug settings. It must be called + * from the main thread of VM instance at the point just after VM + * instance initialization finishes and just before application code + * is to be executed. + */ +void +jeff_tool_suspend_self(void); + +/** + * Start up tool agent thread for the given VM instance. It can be + * called from any VM thread. + * + * @param handle the VM instance for which tool agent is started up + * @param queue queue of the tool agent + * @return true if succeeds, false otherwise + */ +bool +jeff_tool_start_agent(jeff_instance_t handle, void *queue); + +/******************************************************************** + * Interface for toolkit support + ********************************************************************/ + +/** + * Return the JEFF class pointer of the given class name. + * + * @param class_name the qualified class name + * + * @return the JEFF class pointer + */ +jeff_class_t +jeff_tool_get_jeff_class(const char *class_name); + +/** + * Get the mangled class name of the given class. + * + * @param clz the JEFF class + * @param buf buffer for returning the mangled name + * @param buf_size size of the buffer + * + * @return actual size of the mangled class name including the + * terminating null byte + */ +unsigned +jeff_tool_get_mangled_class_name(jeff_class_t clz, char *buf, + unsigned buf_size); + +/** + * Get class index of given class in its containing JEFF file. + * + * @param clz the JEFF class + * + * @return class index in the containing JEFF file + */ +int +jeff_tool_get_class_index(jeff_class_t clz); + +/** + * Callback handler prototype for traversing fields of class. + * + * @param arg argument passed to the handler from caller + * @param access_flag access flag of the method + * @param name the field name + * @param descriptor mangled field type descriptor + * @param offset the offset of the field in the class + * @param size size of the field + */ +typedef void +(*JeffToolFieldHandler)(void *arg, unsigned access_flag, const char *name, + const char *descriptor, unsigned offset, unsigned size); + +/** + * Traverse all fields of the given class, including those inherited + * from super classes. The fields are traversed in the same order as + * the field layout of the class. + * + * @param arg argument to be passed to the handler + * @param clz the JEFF class + * @param instance instance fields or static fielts + * @param handler the callback handler for each field + */ +void +jeff_tool_foreach_field(void *arg, jeff_class_t clz, bool instance, + JeffToolFieldHandler handler); + +/** + * Callback handler prototype for traversing methods of class. + * + * @param arg argument passed to the handler from caller + * @param access_flag access flag of the method + * @param name mangled name of the method + * @param descriptor mangled method arguments descriptor + * @param retune_type mangled descriptor of method's return type + */ +typedef void +(*JeffToolMethodHandler)(void *arg, unsigned access_flag, const char *name, + const char *descriptor, const char *return_type); + +/** + * Traverse all methods of the given class. + * + * @param arg argument to be passed to the handler + * @param clz the JEFF class + * @param handler the callback handler for each method + */ +void +jeff_tool_foreach_method(void *arg, jeff_class_t clz, + JeffToolMethodHandler handler); + +/** + * Callback handler prototype for traversing classes of main file. + * + * @param arg argument passed to the handler from caller + * @param clz pointer to one class in the main file + */ +typedef void +(*JeffToolClassHandler)(void *arg, jeff_class_t clz); + +/** + * Traverse all classes of the main file. + * + * @param arg argument to be passed to the handler + * @param handler the callback handler for each class + */ +void +jeff_tool_foreach_class(void *arg, JeffToolClassHandler handler); + +/******************************************************************** + * Interface for executing applications + ********************************************************************/ + +/** + * Initialize global environment for executing Java applications. + * + * @return true if succeeds, false otherwise + */ +bool +jeff_application_env_init(void); + +/** + * Find the unique class containing a public static "main + * ([Ljava.lang.String;)V" method from the main JEFF file of the + * current instance and execute that method. + * + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the main method is called, false otherwise (e.g. an + * exception occurs when preparing the arguments Java string array) + */ +bool +jeff_application_execute(int argc, char *argv[]); + +/******************************************************************** + * Interface for executing applets + ********************************************************************/ + +/** + * Initialize global environment for executing applets. + * + * @return true if succeeds, false otherwise + */ +bool +jeff_applet_env_init(void); + +/** + * Start to run from com.intel.runtime.core.RuntimeContext.main with a + * default message queue size and a default service class object. If + * the main JEFF file of the current VM instance contains exactly one + * class that is derived from com.intel.util.IntelApplet, then use it + * as the default service class. + * + * @param queue_size the default main message queue size + * @param default_service_class qualified class name of the default + * service class (entry point class), which must be in the main JEFF + * file. If NULL, find the default main class with rules described + * above. + * + * @return true if succeeds, false otherwise + */ +bool +jeff_applet_start(int queue_size, const char *default_service_class); + +#endif diff --git a/core/shared-lib/mem-alloc/ems/ems_alloc.c b/core/shared-lib/mem-alloc/ems/ems_alloc.c index 44cfee32a..d8682b6c7 100644 --- a/core/shared-lib/mem-alloc/ems/ems_alloc.c +++ b/core/shared-lib/mem-alloc/ems/ems_alloc.c @@ -152,7 +152,7 @@ void gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) bh_assert( hmu && (gc_uint8*) hmu >= heap->base_addr && (gc_uint8*) hmu < heap->base_addr + heap->current_size); - bh_assert(((gc_uint32)(uintptr_t)hmu_to_obj(hmu) & 7) == 0); + bh_assert(((gc_uint32) hmu_to_obj(hmu) & 7) == 0); bh_assert( size > 0 && ((gc_uint8*) hmu) + size @@ -242,7 +242,7 @@ BH_STATIC hmu_t *alloc_hmu(gc_heap_t *heap, gc_size_t size) p = node->next; node->next = p->next; - bh_assert(((gc_int32)(intptr_t)hmu_to_obj(p) & 7) == 0); + bh_assert(((gc_int32) hmu_to_obj(p) & 7) == 0); if ((gc_size_t) node_idx != init_node_idx&& ((gc_size_t)node_idx << 3) >= size + GC_SMALLEST_SIZE) { /* with bigger size*/ diff --git a/core/shared-lib/platform/linux/bh_thread.c b/core/shared-lib/platform/linux/bh_thread.c index d291cbe98..9d45b147f 100755 --- a/core/shared-lib/platform/linux/bh_thread.c +++ b/core/shared-lib/platform/linux/bh_thread.c @@ -75,7 +75,7 @@ static void *vm_thread_wrapper(void *arg) { thread_wrapper_arg * targ = arg; LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ); - targ->stack = (void *) ((uintptr_t)(&arg) & ~0xfff); + targ->stack = (void *) ((unsigned int) (&arg) & ~0xfff); _vm_tls_put(1, targ); targ->start(targ->arg); bh_free(targ); diff --git a/core/shared-lib/utils/runtime_timer.c b/core/shared-lib/utils/runtime_timer.c index 60356e930..a0e17fd54 100644 --- a/core/shared-lib/utils/runtime_timer.c +++ b/core/shared-lib/utils/runtime_timer.c @@ -417,7 +417,6 @@ int check_app_timers(timer_ctx_t ctx) vm_mutex_lock(&ctx->mutex); app_timer_t * t = ctx->g_app_timers; - app_timer_t * prev = NULL; app_timer_t * expired = NULL; uint64 now = bh_get_tick_ms(); @@ -443,8 +442,6 @@ int check_app_timers(timer_ctx_t ctx) void cleanup_app_timers(timer_ctx_t ctx) { - app_timer_t *t; - vm_mutex_lock(&ctx->mutex); release_timer_list(&ctx->g_app_timers); diff --git a/doc/pics/architecture_extend.PNG b/doc/pics/architecture_extend.PNG index b6822ed2d071fdd4b7a8dd05992c68a296673b77..31905df5acf07d13b7d36f87afb8b2e43e69ae50 100644 GIT binary patch literal 78440 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 Au>b%7 literal 223241 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℞!^$w>ECG399 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 z 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

S=+(EdHY@-TLaPL;0Z3h`R4oav)}5 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 diff --git a/doc/pics/vgl.PNG b/doc/pics/vgl.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d7a06d95687b84f551887db6f214df111c3975c8 GIT binary patch literal 49192 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%0AgHS~+X&wKmLVCu%aiU!d@^8ud7{ zJZhM^RkbQA1YNy4$*RDkQW5mX;uZjOZ1Z8n^~U~#D(6ECMNGr@S;@fe3`0JEIgLLt za9eN=%l25X-Vw8-8r;>~`rdz6K4>XF-%ArvYfpK%8juqN6N_3CqA}{_LY%!9yoWA8m^rLDEck7M3 zkQoxIOMUS0Osi_ZNmG62;=APxjhm(Z{X6#_Ud2JPwC3~eY6fHYQs#$CsEopQ#2bPZ ze9jvtV+=)7HoxzS>K^TRwd~jPaqzSXdz0!#9~dTey*Yo-P69A}6W>g^ydM{0Vh7|^ z_}yH0nuBNq)f*JpQFFx`PL1-m;eQv&{{$*|vKjTb-U{H10e+&Z=D3?e|=F zU^edbZ)9Q#jDA}sf1pZJ`^3xax|%}Wo2AZIJ!fPIGlBOp6t=pNvgLrLvfJTBB7g-W zp*i?##joP=G*j^yF?ngedpvmRqI$9jjH5#I(wxt@(ycoynD2Kezwa8nza_XaE7}<% z=gyir)}Q4%W8F{~_j26`HNmRgu2(x0fC)KluYI!iYCE<+@32WYMMHM^p1GBPjjnH- zTH3u5dvO+mPf%El1wJ6&-X0v(-NG=7R z+^RR8%AD)F&9wRXY>(2WXL~1FKc@VZ*QRd*xW{CZ#Q&FEZx z+i-);?(hzWgyZ(+W2#q4{L02;8GWh%3i({sYcLO7r!~rigkxT*Tr;h9YaES8_;Pf+ zr9r_Jux=Lho+}Q`+por+na73wklyPGZV&tCqEY{*Tbx$;&#yMwX$ED;T&9aTcBl}c zzPuD?W8@3;#Rh(Q1LTlRn7SeEoioc|@7ZD0X%P+pS}8+Od2%)DX>P6I;BbDx>Vg+z z9~*PBB|pHJnNA^O^2S;D?tE;P`aUUA@no^@3ayOFmBL-YnX=PPvl3QZE<*qCRQvDA zl%RJQd^DU-7DRTpR4R=W$z*ExOezPvud(jQmqO?EogJ@*_R8c|;jQ4pO5+*J(^tmo z!-XwRbV)D=hUpmj4UW==HF5L)jS#;>-=>(!DQj^JwI&&XeC@ZDD9>>GHN^`~R-=}> z@n|E;%e^nRmidZt^aP;NB@it}7TQxcT~f-@xZen=6xt*9mqhEY>}4TbRjE&frCaRR z_-3A5RUZNZwG>>rCH-nKSL|25i7$7R3h$(S$@Pp@W+fJv>$Mkj?pr-@Id~mx{McDl zm8;KV!6SS6`%$qo7=oz__xTuJ3M?OWuFc3%r|Vk*P=YsJwZqG+v->=2JexCGwKrto zlVdF~2Su0$V^<$G4JFU|!&k^_%XEDZyvv`;?$MyVWG*rLO5WARc=)JTl?J6APjr4! zSIae=C}(y4diTL-&{YYCRX$az zkIewJo&1dvb8u@$|6X=Hd~U1tY=36%R$6bb`_4;dnzLK8|J(t}%KBzrT|JXqWZ>DR zW&I8Us0R9hZlO}GdFlp93mg_9<%%hv81PVU0Ego(;?eG5|Ve6TL4 zTkc7_H1VDiDphyTe=OufCd+wr4r$TI>2I*0ZnkV?aJ|tBy*_7kZ#^PTdxf7yAnLLc z`sWLaOR_J#tF%8XAE!}1CK2YLo{#_ta-Qk4=eS&ooCj1Ej$ieb_45dsxv6z0#a=hf ziuT^kOvwlCPOmXDa~=;;iVOIHU*We;MiRq|Sc;stFZT3rI2Agkk{A#wHi<;>>_XD6 zriM>vk?#o$3mTetU=P^sJ^KwNI!HJ`l~1)CL#M({!^d?wxn`hEa&tbD#a`0X&YNO! zLScFF`X(mq*LQ8((w7e7cjt|tOgls7MEEM{QoS4m*|L`CF46G>H8j=jnFE@5XpA6q zujrZ=nKCs*05DF9M#O0GlrxRGcud3{Ae;Umx)UFy?p|E41F?OdLSUwuj1J zW9Sa0Jd!a0d`{GWuFa`Yl8hxsbtWFx_&LeE(ZE4xR|I6EB+MI|G6+|)`}V6qj-w2b zu9a-hDm7L@vibK++M~3kM|}PvcIn~tYwLl50PKA`>9>Bh$$hF|G&(+aST#9X!5y082`K}H+^0#UnAU`|~w zP2a@-q}=)AEpj`J`)H?UVzEf+yiUu_n-c`9ShRR)^CzyNF(4}+Yhc1OKuXm$!}>}s1jZUM+khlADx ziOt=D{x^q6?OchXboB}{T7&ha)1^c{{)3jU_|KoSe{e?Z^&RD*)E^JC02=&zs>lkL z<^#9huro^edS6o)mHBO^&Qt&xKFz4V-nEUG)imq7l+5-cvG?2mj8!Cw1ShlJmZwcR zHG}IlV~p+Vrf7S5%HMjeW~ZFq&SW`SNRSM#Z6q%dVu3ig9HgI;u-WJ3rf@|?J;}tK z5`OaHeJKDOOUCuA*q?Xr^c04T6$LN3-LF`L@Y zzA=4$Qvts}5PZkRYUsbT!3|a{d9Ikez^`ej7o{z|l*50U$efqJODPg?IP%&&iNita z*%3Opful5`OW_Yry&}A-Q!1r77t06Vlx#w$x~oqu*U58=8ylHni%ix30>jn${~^tX zeWxETM7k<&=zvBMOZY_=4A~R5UKm@2IxDPpTfFDb1-VesAw5Z>tmY@2y9x?Ma$TMa z!rKL+VW(~fAGX4tBEXfxw^f&Eg1t`nPS`(AH7$IF5IU4-g}RAq(gZ#pK^e4O?NYJa zEkoit-6nCQ_48q=!`z?p-RnWQvHWoRKZWIH@BE0kpl5libYCSS$IbZM<+43-)?)_o z&shxO@YVAIJrvuN_1~`Y{n4H|HOG5@>Ok(fdUEZJIBGtST3^lf=3(m5>Z3f;KZ~%EYXyE+@@!R1lUGgz%-^xU zZ2TY)yiAu1b%TZk4V3~hBlBpfwy-;NBi<)#v4-m8W8(R%MFeQ#FJRnUh^r2&_~73z z?YFMY{8Q1^LW1+u#}FwPpvFT;6&S8{tuZT_(Qk4vxkaq^WyDU(?e|Za81s~vx!y}& zZxkU=lVIWi(9G`Fdxq$3^vUGu#Q7FwHmI?*UB8Zm+am}gvxAy8*4tP;=82`fpY&N_ zoLsMew>cU{U!pyT%LVDwOi7+I$_d2ngYUhU{K|Hm^gM@yl>1bl39Mpf4h<;6>1qGKGSd~|}(+%`(Y`S-PGXLya?wk$0H5?Z3 z4+9vYR1Blglm%1?vtBvPTOSE+>3< z-OI?_rtgtdB>;V`^1!{|pfKIHcn12zwd_98=>6nu!yq>X+ri^tNPktx$c$7_F{&#? zw_3dDDh$hyr48?LFYvsUAlxZox@=1>o!3oLo~_;s{IVN|ho-*S<#T>acU6;2fspCD zH7Vr)!MXG_9AKA2CfnTCdXo4Ki2#U-Kyvq*tTcN)w}$0MuSYWZpA&Q)4Gj}4ZvXTi zcQak@{@Vm4N@+a2tY$2=S>{pQKvdP_e9ryh_)ShhR3-q&qQPU|l|LM>TQ)|2*nQ)w zpWK?ps&0MKhyv6j6OyybP7QjYe{(vqphuJ*n@)ccBRB9Ht?aJezuz&tAR_pjIU&g? zA>u;A6yxYu|C+ho`YXLAOEpz$#EI=ux&vi2a~kqy!^Z8N^$&Zn=YvwoXX|FNTQ7;t z)n1Id7xld@S{4NNV=yFu;H+6bwc#nZ_LEL#pa+P7)KHfz(~5ZIS2~UNCK-cycug*0 zGM%u${wXq?cv6PfV2cRZPc~d|_Ptf}A4xd4Avh+mym4Tb_?H6qoZPFW{N#lSQ`sPo zqO6_e{Nk#>f{PX>Cb{eNaR7{qm6YxsCp48jdvCPz6wFJ_?^doR^^zKeiOAZ+(5o$~ zhDkgXHgfJ4IUcVV*LXe6sCbdW?oAxt*Xr#)`&@q9W}i6WEc1s=#foc;P=aNoydnd>~_5`dAwIajh@wpUGYh>*^S+%Dzt zREv+jmYBh)P0T35taSA{yy$x*da?7dKbl_lyDTvd%_cNs^O`(mdksJNT(favtl$fA zutF<)`(e<#ss~Nd7+!8jPcZZ;*gklYFI5vcw4=b8iKa&)5DN?GmY-giD*u{Xu~E}m zIdx&hw!E7vvI?GWWX;T2aKW7MW)}_0Sty7ee&RO~1WLCXlD&i82S7+_v>V=@WnZTfM8*5v)F6G2Wh}lJMss!wv0kub> zsn4wPjfeb3zLI?&UJuR-)l4;056AIBdV?Nzd^+&`#dc!Mu6yP-&O=?Wls%SSK4Z+c zNu3wlN)f&?g&+r1_%>GO(7Nk)uoF#X_x5bv`pRZXd}rN?&-_QVWbeDD54x7w!X zM$v5NjJqnXEAVeeo9s;#)L=XMtBXy3Wf)?UD7ZXIu@b$*VoT#z=+r*u9f8?Z6D4C>|K(^@}Hc^{xJOYc0=X!nE(?MW=Jji|wp@`LSSi+Le?S zwT%smoF}c=GsohOa&Y0M*Pn`?dAoNS)?Af+`l#lG#Da!GlZep*XK&f~p3gY>6DDAL z$`JF189j~Hn~mcW*^$33JVSId4Bg|Nlc25-5q{Xvrxoko-dTFvs;Sc z8KTh`2p=>qtZ(~E#V93#+k0C$qPR&lx?H)?`d-SUbQ;Zemh=o%&s;}pEw14mHqXt(}PFi>Fk<_>#t;|XQ4WCo<~GMT&%A7 zUK|NxMGdeaM@7jNW>+$|1vT?gX#|qHE`c5?A))ksLNV+xC2n{<`gFcBZg=v!Ms?Bc z+v1J1$2D$uMo0Rp?yF$JCEtI0O-~uVs90>ZXvaR4^Yo+P-5`(Rr1fr>l)?5JOcjju z9e=t64U*W#O0YEj?SK@$E`D`fT>A(DCXNSnu zc5u`TRYSemLziW5q__VN0%A$B(s9_T@)K4sh{YoH69Uxxlcx7^xqO(^&Fn z&XKEqElqv=6Y>EbOOLJ)%jK@*q~$!`bv#-w?$7;uu%>L7==LFqGcYi$TS)o8Twv*| zeI^CHDRxSoYe*!C2kHnwN{B;#fuoHmnGaLM<^fmLca}v}{K9vaP3yM4T!S%pb-CHy z-DR1VF5Vx_blltdeD7i3bdK`1)wPn6HdltvJAt)FA4aEloDIAVP^N{&Rg2ZGWOGARaPBgK|U;Es!!j<$h;H6zQmdnm%L;b$QHXoJ1hyAtrjf$Bc zK1SG`BC#uZUwi%S?p_m%{l|2DHTZ~?bI?~XS5WznK?gzr`x}jfcZvKC%~&IqxN#f- zWj~}$&CmZ-0t9DmXT9tEFu!ka6uM-6G|u|s>Hb}uO3YU4SaXTxMn3*+TU|xQ>cZ9| z%eK9o>oI$~TkdHNuBuFP&CVo+&|xIarbE9E8*6KvvyAr)#M1K{j%SQK&yP;*5kb2L>b zbmFb5EfU;|6R@o;2R|8o`fhU>b*DwM{ga%mqq1*z&rfRO;1l^&R9;6sFeOy#s!E-P z0v`@){KyiZllic~UPFKTzzLxFb91%mQ%CS{=qKGwbpT4rpIN=hHeF83Z(Y4>(YR!4 z;q{Dbw{iL`?1^G}D^qyIQqcxIR*?M2pnK!)knC3PKljhYX#Thx(Z3!H(Ev+;_p8r* z1rPh@dGS9!B^ur}-gqWQ=pziCii2tXb+gz{#$$DHcMI>-OUWO&>L}({_Ca#|e!=JF zG*-XT-C)lv!{5|jXSKDo;+-~XN`~GU)vO$B?l{%{A@6jq&9!zUVCtc`1jxl<-JPSg zG_e7i1RhNS6fH^s@FT&Xy4`F8_a?r{sW014La^KAgE>vpXAWPie}x=SG}PCMjGl!w zgsuw8HwTjY=Dl`4$r9N@ewc?@ctZ54fsX!$GNyJs8LXrNnm7k;{#U6IrPx32T3B~H z2}ber^-RgO#Ook^25+}ny?m-#mveJfyT0t{d&*L0*qMrV@tw>3FMZvlF0SFB-Sng4 z@Z%=~eFalf=70gA%kI9`XsAcYxafprfcw(`1dG2+@9L`>~(rGm&6B@g!))noAAb@mf9b-3dG9^h!=PU|^u9 z#`gXURHF)$n4eI^A|()L1mNJNPkq0OR)$O>%#d6WF8+{N(mQ+Kdbn2|KNu^S&{Qap zW4t`4RM7N(VaX6iz7-HATdHH)y|8gwBRuQBsnis3t=Kh)WDj!fx@?PI`s&2$TKv~S z8=DJWsm5??$;>lAV*}BKF~r$sP~BXKV(G!tk zYdAS$Ml7+bJ2ZTLV!dP*TJb1ju9O8}u}@t4;w@H3$G3N3QCPxLAg-dq$F>AZCoD)B z#-RX`9x3i2j_5M5cB}RaaaUVV5O};H-!{uNS6w}neC;2NOH`rmt-IL0*nf6IZg&@l z@(rX+?R;r@ii4Gg9Ii&ht5#flVK^Jg;G`d_;WAgH5e?gULl%_Xur0cQ5dICtuG_1xzV zd<41MpOP3V@hIqci-nGaAKsXTw+97~1>V@oULex>x|J#z~rt}jfpZSLRDX|nLI5t#Y^;oL@+1RQUsIM)}WYiZ3E>7t! zJCYBk{714zd1>Ygt6Vx`f+^O({-*v$Cw-EH!z4Y6CU6JT%!cfEye12KuDEKs1PL1G zSP)rC&9AO6T(^|s-FGm-eiW}4?AOP3FPT;2p5?*v#fZrlkvHY;((=S@G;%~{oVc?N-gmRy7}nXC&l8`rBPs zMHj|^#{&dGu|T-~x{j|kMdPM%L1B?(c7oJ+RdH2#Cwr0dayElP-GgX?gW`oQ+hL}; zhg8r`%c25_x~?ur6(`Bye83hzfIHel;Uf02aCa;?>gTp|??(3C~lBiMPg__*V>E?#TZ!Q#DlpQ$dMPgGp0o~Wgno&3`;jeR&t zR)7W4<0_5-xe^=uR6J8nkV#K7?kPQRB0QDJfQ>>^ll#2=Mf$mwiXf?>7kkwM7dbH+ z`oZ^n_`3JG3br#uoV*%;9JH>JEx-BpV;uD9!6@68YeKl$0x;2H1(CVB4U(^ z&ArDN@`TA&p4t6!+x2DSeSz++U59CUU9>h1y6@o#E5)(^M;00h9uKgMWcCyyjPXJ- zsWcBXeQ-dJ37LOm54D~BQ(`Ojh$D-#C1an}?!Fu=o}9nGzZ0T;D9T-M{;I$TV2Kbrd1WAMm1hm^tApgve?H0XZKDWYQf$Tq+6C(I?~iZOv5oC*HLc9UVN@ zyIf0-*RH6CON0;B9{WAo$>QpwTzB&`j`A+ zNt&r7|J2M#8hkz>-5;*n&}Ae|bR`RvD|#=^shRmTVvNh>FX?;i%gcK74kI;K)AqYIUNN&_Q;VYfPGAZ4& z->|I~b<4D3MUONR+zkE7Ncb zN~mHg1>tB^209*>6rE3nc^(Hs+y{px^!^3VRTK{B8p@vpsiOZc{r4)$e=njykzD}n z_J0{KsnLD6)MXh(a-AZ`?X%o|S5UdX_7GRUR_l6R)xdSC*w$+~J3L%IjabC(XbEN} zeTs#poCZ#|+7AbeoI6R5t6X7AiZY_cqTGfArC=;QGu_oq;b=-x+OY7W^Q?ckH#3QvAjs1IIGWWk>TcT3y04?$81t!Hnf1)m z=g+aV2ktjBTb$=9Pc#*o?r`UcD(4vSaw!E;bK!82WP5NSYEc`C>eSs9bGr+WNSI?A zpn5UG7F}upV}-=_MvL45>`DQd7iGm77(-N{bhpy;gl&)Syfg15ZQ8 zwZj2j;((QJM`MzJZdi{tgHatkRhk>cLjthGkNX3fU2>5$#SyX%TA?PDNDLFw0P-Pt zZS*OFxV+70wCP@!<*AXXsHpNtj3!g?@ty&GEvTbhj?y=)l2SDi=oHLOw^-Vn zN5SB34;e!Z@(msj=?6COShxTW{-ibZ;VA(LN9LY<%3dkp<3;YuFEYmytoY;cnjt^f z0FH?nYD5-mrL{l?OS5WgdZed7h8E*LKS*fR4B0U$-dW%D4rh|wY&(IL#-l*9?lIS+ zFc?jt8~b#+vXPJh*p;8p1ea9vne+?4oc>I8;~2lDMW1hVj<1{*j2sehpnXc+2fGtK zV7@!Y;rzVUP;^#)mr0#KBX2-}r+KQ!T8d0lB&X#Mp1V+gZp@iW)cW(2YZbCRnc3ZS z-X&AVw_Z}uMzl9EY+Ew66|SGaVN~jA-N2KFj}lqzx^~!LVf(0 zUPY9-CHptqwrYkXYn><^?-m>HYe@gUGT>-W&>3V}?z7O!9vH8Z`7fsKuE_i z5<}y?>gg)lCbuTL#vHuCto9xzHUuh@wc*0t4S~y=(Y@>ya_eqZwW+o^=2H?d(bGo8 zRc=Vs_3_Q;)k|S!GtI@H({%${%|%l~+Il=?b8#(w0Xf>^bs>XbK5O541ZZhcB+-qQ zloUm2L4p*|wm+Uyy0eBBONFV%15q#2YU6T|Qbd6v$4gT$!gR88Rw}j`JI=VFg zOuRVxMQfVMN+gKaT^JC|!XqY65UXs&cVZ){sfVykuRpHEvNSQ=1p~Z-a z$;XJ@{d}sx1WM1VN$^!Q+hX)%r|{CsL^SJ-OB@5RFg2l`$^_}g!dIOxeWEmO*FFZd zj=(Slq}f2RcB)Mmx-eH^(+=HZFS(9-)$Xy-#VNp(3FCKunFzKCUD-hmYQ6bWU2U=b zP9`Z~jg`$*0T#C${c}WJf0&1J~WE;2Jdxh;bE{XY4Rrww6z)dcH16dAW zw==1$x(_X;j?WGN#-=FVwZ7Bhcq6Oz4SX5`$ zcE$f~3q<_c0$;rR_IO6!KdzKeO0c$Bl0VS$Pd>5_d@cxhAPalMZgtp~=TwmbD4GzL zhU}f5t}=R8Dm1JPAJW}DjTQoMSkO$S%}QI*zH^i-RUI&A8$njJDw9xbli5`DzWxJ_ z+E%2_HpmG#94834O|39dtiDvNIQ(;tdHnNQ5bSVa1ZHfim&b-8wWk79`601zL|X?# zy#))bm+A#l1-c2)k>1R-y0A6d0A@lXC|wFG++(JN11d{HDL_XIKt@)Rc-$*4JdC!vwC`w-LSF?aRF7S=Fn~T= zO)v2KJfOu4C|(Si;m9$z&?i~$(4y+J)ODoXcTY+U;0e;p3rhx%w?o|QugXP{sBWYM zieC9oA&ekUwSTZ*DuI15f8IEkn8n6CN?$(VaXaEyJ{7HLuiu?lYc9Og6bk$`p;E*k zfkPy*h*K#7i=pffoKnal7L|3Ef*9n6t00?4wC$a)nUk^nH~K}=^*2x#Dh-R~MYkXk zk~B#y@GBT!YSKHd<$+;mI|z7q4+IckY4(YRrb*5VK9?1B6+8fiWNZKD?c-=0Lx&90 z$|*_hsqofzJ(5@IA1czRB8c+?dDF9|%%eG$FHFP#_dR|h(6W0*O-lrQ-f~TxrP=%s z72qsl>eK3ys?63AWIkQ1@L$rvS(>Mdt?Vzh?20M+=FFpS!>fFViD)+EPNy7A? z_D$2M%nrf*02W4qtVnv!R2kAdds;y`P4}_;Ne@(N5#mt!=P$KIa;|+-zESSg`D?6^ zm&{no>IhI;Rpf}AIe-*+YH z#M)Wp1b{&zfko2Oi?Mqq3WI;?`Fg;AQWsG%E`zbK zmmCl@f$=+*c1}Y>j?bQ+*>ymeByCu4!70F%2P-LUu3UvYuVNVAu$3S~Q&3GMP^!hj zMn~Nt1rp&onmp$1jL|GtHERuA)g;S7kRuFK+3-yh7BL&lyP^i#u2$3T&%sq*q=DcK zTA1Q?aDicB4%smuum1g#hIqd6` z$H_hgl9iBK$Rof2$Cw537I>?sj7vnqC0;Wh>aGG+z+j{X1M=lV4vsqYyq7taE{?7V zLyjw|m$?ZvMpINNSt8UKzT8ZL7RXBG)K~kyQW8fvSyDeR6H-Q z6a!-uIUq0<9`e0t&7W;YjW74w5w4kpTYO{gwgrd{K*KlGt7e9H6Cwwgs0&;3h5f zDqd1L*fkK)!PB8@x(It13qG|R+bbmrSTO(+r>icBFlHKOx(18FA%Fo8C4@ba2F`Xc zkq6);6E+J1RK{@#ol2~LfQkSWjnO0kU(HKY9Sz`c7#xX2QX!y(L_ncy za3%yZHxeyzg9XQ9C@x8GP&P2~kHn;vU9xwil4{|7`bouj;q$Gi^mqSz%O7?fhV7Vq zJ~b8dBdk4dR5_2{s6<8GoeRHg#HoF(5%;j?{m9ElOn=2i9p6l{>AF1PlCxsA?w#3R zKNInB&wpe>?6uh$-5kBms@#|Y_r##V$SO)*$&E?#W=46$HJABf8jY;nlga3Ohxb2qjc)E;MozqMioX{w{MK&V&^2d5$;f(>TgmW% z*Z8WGl{$w<>KA$GRw>Mk`-_LN6_;6G@m8*_2VD44>2dNVEeyIdB0R%rDQ^j9x&7VKmcCD~@Y$S4EP{}W5JkHTD-7jo&j;+UOPJq2T?)lAk ztB%`zuDY(-X2Y$&PNh%Nl+)F_b0#D{PLZ+Yk}OQ;=B`ev>@u6kmhn7v56csrv{4@y z3!33i&&i+qvV8f|o&1n5AwSM$gfFosTS@K&tOlJ72i>liydB$S!I74uNQGB-Op9oJ zo7BtlOyG-A#d*wT8+W#(RRrCI3nIEI7qL7O_NvV-qfHN7ew||;OvI{|&d~dR8FF_w zV!?gixtIPQd6pHIM|{i$|A(pfj%K@m|Hr-WS*>x~v)n}NQN(J4PmK^OjlJC^VivJ# z=Y6*}5fTz&-S#RP)GS&%RPEYT#H=cz_W0(0pWh$9bDTKN$%*GRpVxIg9@i^TuR=$~ zGtH0Y-Oq6{Bkt!usN>DH;-qMMYF7G-7tQX&)SDGPB_)7}(rD6Mot&sVOTwlZ&s>3& zL8gafXKIv78(&p0jZ7Z$otC<*SFVxln+7+M4O^oGP{|;hcP8Ch8Sm=_!G} zI98&Wm6TKpMArC68v2!#Iopf{-KQx%m+Y}6vjp&D0>o`CvppGlgoqyzP~jg`hDX&F zYvc%$-648s!7!!_=it7pnk?4)xPjU6UI3&7UfK1WYGR>+4;9fIs15gR7*XL*IrECX zOU3A-?NbBFd`Ac;PTT2I^jUs6z`b-acBj8XcG_FkVvhdOaPzl9 zv9tb<*7fBarBG-0CWF~+*#^1}`o(2q1C!lL#CeA(fA^KgNsAO1SFPJpRW*1HUNs6K z+cQWwWmi)>Anc1>RC=svlBkMBJP_}zmMtfR!JY`izMtUxex9Rhe%%+u}nNlJtY><6LtASp^#4G-n5zr$_u4a{&if zJj~<(_R9f`X`W*Ux_A~UMfaCA_Ux7ZZWXTMOv%Q$fsP#Doj!`{`~{xC-%yckclqMGgMYinw5ZloDytw>e zfuj|%E^=2e-7c}iGDjhY_DxWWtA#jri<1p!A1d*a+Hmq&%W&Ju)`=a^%_U>P<^M7o z1mB*HD!lT~;yV1a?pSj~Kd#MY!-zr_r_CpuNij8DG+vFOP_!+L6ZFZCiF7Cau!Ot7 z9P{3u9#4;QoPcEuOAnA??3Y5nUtxcZDd`=&h!a!|<1Md>aB))=%r2}7G~Qm@$%Qh< zM50ag1M7j&R>Wh=QKb`*@!W*MQ`ej?+ClHJ;U&HO%cKX_W5?Z(1FnCoKPz#>1gaP> ztt>6kUCi7w-W^!B-@knpvLsp~SDVju*|^|;8u|8jUe+fK9iS4Rh1dtnwQ zV5tI*Q-j$4xXZ$+XVXN+3>k+sd3h48N3Z0-|9bcXZ&;$k1QbUweAJI6ygT~jHI|WqKFeV;_0(M387dew6I&xpjMK^o{_vl2(`&xjvHh6 z3Cpnud4^9OYPs1o?0PC^@9tYD^n9RBGwT-E&_S*Og*Z28s<=~N%f9B3Z{qtwMZ`D5OpiWIv zixI12_irYn@2P`R!8Y=-_Bf!hCfCh6201_scB`cH@5zY!5`=5%ezT=(;-cj!(PaJLtz=Gjhuh8HVMCvX8x#!`Cy=Sf+}Cp0Qs& zHt0@O@^4zxk9NkzC$PtE2*rbc(2e_EHjH-5FyQi~Kw~|UP8ySNx`R?UWXp7KcXdVj zv2r`jmgTfMX1CXN_AS{prO&>vKV=at;MQ9)qwZX+wxxMn$y^T^Tf)q&AdWCj5^-2U zR_T&iszy&@{>Dx>@f_kOrc_>2eS&xmiCn+wO-U)Q8Feg?GAL0zG(Nm#KpD5Y65ASg zkzY__VHb8_z5vZn{Zbk;V!qcCSn_f2Im&p!6|{V+JlU~Wp-wGa_zC;TP7 z)wjF!hNv)iL)30Lmtb5!FP?ZQ9h1BCtu4+OQb?xpDZZj8g{?r7&3mQyjHJCM_{w%J z?&%+`?h~#18r&;+hqZ#X55|7WKQ6M@Rx(Y8~lZD z;nRSIYr`A-jmPopQ$&E9Im-JwE`|T<4m^3Am`m;tcs*4w=v9(1)Bq{`5ZBOPY;KxO z?Xr*uf)EL-2zOcYit$X#tYVJ6oBGoWem)2;Swu~EZm_WB%&nKHP<(7I6Zm^OZAE&6 zMHD{2pNL5P)Z3!MWTpQd+3mtBrW9?|F?2%`4th6u0b{v$P)uwoKutIAw)1Y)X~*0c z^c{Q`{Lx#KpgB-z&Ta}9BkFKWr_N>0E){4tHE@KL!HOhztrHP@ zH)^o@;smzAJY|*XG%FR0W%kwPw|?VmHjg$OYwO~*q-rbL_y&AD(C2b>xkaWNsp3^N z$^pXH-Fs&2FRP@_vM46=X}?Bu1=W{T?0FK&tB7lfzqRS7eeQ9*Les8D=-|E+dGD9V z|FbRh6k>t7U4+xKayJzXqf0RmW_!y3E!Hjz|IzzHR5>v{hb`qJ4+WBSnOscC(irLtog}8i#GPO|tQoxinxZyh( zxyT*%nb5)^BBShTZk?L_-D5iTvl^^O-Fx{D%KVl0*_-2FkUF!C*uu8k7;K)1m9DCe z*)$V^U)IafqDrLn7lPf^+I?=;GTl3G86=y#zAjxS^(b2bkxseObk8(cW+LOTe7|Tlrng)_*(4e)>I* z)lE+uYP|T7_Be#(GE~MVM?#tbgw#yGUouvSO%#G(zuE4l#+w0TL-Zeuyt+Pu0H)4b zyRZ0L&CZcSf34DVz9dq&UBqn-zFx0f_3Z2nb%oG8=@=Z zSWC{sZy8?Etc~H{N)J4kq5B=s;Z%#kxQIsYTLw`|)i=gl2JbD&Drt8xpSNG}Ed$$* z|FcsG^&i#TI!aB*p3+)Ak;vzYqwjYz)a{$xDDywgK5DISrxhCLCVqkIc}U(2$OBr= z5ajjIDI|>Z@Q1UpY*8JYA{)(zO-}jRc+2oxnN2V~d}G#&pQPzqK%9Rwj*3i^d+4+F zB%h744=Pok9jJT037_5(o*KF-+^4$)>aYL4HlW|#w+#P%t^Dq?;1}3$|5KS}vh(NY z1l+w>8P{gQpRl`!(YFj_c^RW_=E6_i;|3{dh4vLEJY0+qV-fRf?%z_bavp4an3>cr zKFyI;dSNVN^L#={UB>cgIcAeyl2i!0CC0z?UltTH!oS={h5gXEEON`;;g%OrzWV(h zR$j(@8`b)0N?kS=?B4>D*Q>G4MQrWH{`tnm;d5f!SFhvKE%jXt??w!9CNR&jcxOt4 zQFp7i_HteYoH13d2muNPz-Q5vI-Vo>aFl_ppk4gE-&#j%zg-G|ylNT+n>kOH#uChD zgi2SdqCe2L83<--?IQTbv(YI3#U07a-{}R2jFTbKJngbL>LG3>6@~grZ5WoxRQh=T zjz?;{?{$YjOuxVco=K_R{Kn)h)B0OAT~o~)X}k_8+Egk{F5G9m-`k7#(DUm@#lT3m zey#%{Lj$_%APUoAUz-rO3@`f&ea%%o(AS`D{4K+i%lCYQFr6#iSc;UC__sWh5I2uF ztqH}0{ac3Vc{WFo7^z^>Ff6@9n5jsnp1i4tvmaWqOY2#cBAlMZ-9hZyC048A8#!F8aUTnDVVSR-u1? zDSuvyHpO;TTsE9JD$Hl#aHheu=Cw<->`Zhp`X)~MExH>_jx^JRGfL@enfEh3dVc*; zly_aF0)3XuUO4jNfeTHf=l!F|?r&5I24PUm?n$W9zsv)FM;aMT0;G45J%v?#io4ez z>;#>2I1+;0^7k&TkXybMelLy*ZtLgkeo=G!Yb+3?%Zu1^l_<0m(KDkzX3UYNyry-h)I4AH) z!?`I?-u0v&`E>d|({F5BX)0gmGxClcVs~Qt%Dyx;`S`aUxaZ}LKPARtWOLaFQY}!v zuh1PLXCPyRhB4II}FkVOh+ZW-{f&Sx2_y+ zgo{^*t-pydG=puhels4w&G z248FT(JjM;pyI}*QkXld+&Nc?F#D&;WwtzI^ODWtrGQp$bQ@yz(0#Y%R5>6h!E}5k z%9g6BB&e}Kv+2QpXmgPlc-6(qcV@X z%r9vHx&GIX#D1Uw2R}uWPsza32zyU9e+ntYJzFS8OZ>VrB55e%J{r| z0tJN))>wFN8F>Dn-%`R;BeDfaOEG)1FFC7RLpw7Vy^~`c^B+QQ`XejrKU?dVYFn;e zF)nOKRzY&oOe26Zfn`hKOs;MfdvHgvq zDIC44x0^aw6YM@1S;FnoD;lt$8q`_ng3%9GlPvD4O9uX@zb@dztU2E_fu1G6;&s0q z4&S#SC2#OSgB1_8>o1exxKo|!ZYtJzXGGy1R^i!)B_We&HT@`K&oo%jl<3XF-M4wl zKe}HM*(uiY!u7HuHDWhX_fuHvXJy%c z9^)-saV(0*MRdQ;uL}o6)>X#7ft(vDMn5UvkPuWf>L43E2jXQ+1wpi7^Un48^B~vG z@l-f{T(N7C`ifp_aT7g9ua1ygb`^>bdVn0nYJDF`{qjlcR+#A{1}hoY)y z?j`i)f7*;{TYYHKtIf`M9{AX-t0%wR0)L%O^Zd$(7IUaQ?>^p$F4R~bq%%0QUtjxu z65cn`_?YZ|a^ERxM;W3(q@un_0 zaJ_%jRX!?bnt%;%8H(ZkInf{9f{Ld8nZ=#M9m!h-YK@Ah2ZdKIXR2tAeecYO{mzLU z!uIutw?eXoNaU)L>o=dZZ=EEh9#HZtjtDwI_|RLIxSImQCZ$dEdc+Z z0O8o!fc+$zb?2}42Dbh*2hEQ_XH^}0WFh%l7q=(?=8+BFhZ-q96FCfD(T6a84A-8<+%gD7Giufc={@S; za9ns}^0K1n2sgB1nZBMBb<}8*M|_FWudJQt8*l>WymsD>6Pr%F2>c_xG(IzfD1;Z+ z+U|d3NzutK5&Rb8p{qwu1Hs4Rk?rYYHJcJI_?{=>nf|#VxQHijV3RUccT>YxwX<#+ zewCO)`k)rjOQu?RjRCe>Q*;dmy6!g1e3_eQ(Ja&)IX$XNDPX-!Sp{d9W!^Ei^s8K3 zr;V>o^b9xHv`H{Z``RiFhD_%jnYNzrFtTi#H1xt#O*q0u{HyR{iXlnY&zqRQ7L!j5sg%Co3=mwXGhf8xoNQ_9*M^4yb;!}<3Q)!tY{lHrSHp_ny%7)?Q4!8m^%mlS>?G=K< z?ioE)GKfaEwlh{tQ3$N$a(V4Qz)LOO-$tr-nrox^X^CJkDl%)hmg(jLpW4v^e zB!f%`i?E3|zv7gw01`~?eVKwTxIP=QzCZ~Nm*h9i39Og|?a`$&Y-e%L=Nk~x3;m%S zpuR=h`|wuP#L3mBAVqerUQ^&4K&uNw?;EU|QzxU%#P2=+C2##Qg^8_1Vpk&nX+-dR zn*EpTb)FgK0XBN=QccM0@1ctHe3YM(D13;wPjn4T_6Hyl>#Awo5#*ZzlZcg3y<3Lk zgJ*t!tqDOvl*N>C1J2?fV1j`x^(20&wF;47VEA5`UrjbOEa1HZ*pFSScO504j!>VG zDl31rrg)b9QCK1lS7@+FNwF|L5eRYMT~dq)38880)dp|j*>lZyimJ~W*j$Q*M})7o zu0$1~&o;&|y|X{L?D~(#E<~o25C}7ALkbqQXT~BwffdD-(;Jov#`10z&rI1&`z@w4 zaqw1&f`tOp?Bo8UqUbTGexSM6f+DK3fh`l+9Ewq)k2apdmTkoG4mqv7u#H{!)dtty zw?k1igwH;zG=mMtL-Z21XN+XKP^}&{Nf9rUDw7;<^#mwzs6+e3!mji#lzT?hdT2bJhz#`ox$jYT<7tfeFMFiz0_Q^0Iaq;LGE7#lwt9Sbb|AvU9>5YdZV7yl@epj9cbwy<;4RiCX>OOF$O3$WG<+R#MLK-vt~qf%^f^yl`SWzKO$h^gNoW zAg6n&7h}ZOrfMuJ(umVtJB&;ptvdGLFpqn#_}3`5XcgfTo&zX;#_LfpXqV;gKi+?n z8ErJb-o7XxGT=>0BW?9R9`H6C>{}nNgDM`XYoov1)GP{Og&*xC-ZIRL%(KQ(@LM_9 zc-#DnP4Cgp`Rk#hJpUp-dx<+^m9PKL_Dct6f_iay#Ti?QbD>K{jU{s6(Cm^OyQUYq z%)5m^AYR}k?#|;I4YN@kOOdD<%0 z^{wWNOiAncwMe9CaIdYB>w5ZsJu{VAT%|;hc5Obwx&V$lIJ!(CI@;x&>GyO!btb3X zL6jv+ts5`Kxkjfg@mXwZ=AQthMILb`y@&ECe){0mW1UEU_L>>pnaaDx8_iXUHgrFN zKOBmAyI*O_9?X%I)P$%(JNr6eM*s!pWfr-R4fkaItl>7-H4kjpfR;GN*G54%z$|M! z=iWT-MYPFVPUk~4*}3A_E(nzh${_HU=&465nG&$S zu?F=dko(qJt06+dv%8#bzrH@p^Jx=Q9R5L;hPbd_{~nkBBj;Mao@6c0!~5FJDeg{P z%JzKwF2$4Bh8bwyoGDf?uJ{OtRb7fq?)EK4%EfU#-x!NSB-uNp+#jsaWpUb0AwQJ( zRSYpWpLRIns$`*S#_Gy$8XZl_s1=e1yY+h{0W1_&;U?o_j45oz5=BC?%+G2uf%o4u zssZZcXDxWx9#)m8CTujqZHC(%Ao9`ymnA%GSkbR-k`m)TNW~Xf!hs1q!-EIp ztGBC1BEe_j52S`aybddARCmmOh8qzMf*71(fBtNe8eB~~dvd~VT+#2>)~u^cQN_&* zLOhbBcgKEMs(3#@gaiD?)ScIBb|EF>u)KAIu!fY@%hK!l;%6bnEGUYN&uHJ5>Dmy* zDN|*!V55lyDIV8gx{E8hsSWf^PrT*hbD6fQ;-6S6+7v>D;Z&4ve%>l0*{#yiDv%{x z-JL_Cn`4e|G}Ho=VXnJmiHVC&FHu}ipV3yr>$o%1%gt0r$4`?>X@;Y|!}=gknXI91 zGP$&Z64))TP0Wiy$fvAQE$Fq)hC)tCeB$fJ(M&YSrtG(P8xD@WbLHMC@inl0X_?x% zAD3wcRIcmiL@IGj#J?M7l%KRfy|`y7zG$t#AP}pD1RoBa9HDF-fptH5qtsF!KtUjJ z_d(AB@p8D&Sisxu(1T+lp+R2zjvtdQ_Hs zxwgwrca9o<@=njpN%+Y>sJH)TXO;2r^dpWH^nXizhb8OadHA`({?P0S?&eSj{S`Tr z=?;>W04ZU_&+=_{m$OebfL33XTSjJ7ZK1sp+NcKGUM5vc<=T5hmF8}nvBIp~lBc>Y z#FH1RQmpfDes*BTk_DXXc%rsbrldE=9NT@v;QOAj?w+Z5+A#e}i(4lwGxKMpMF34w z@w$J0<3r8ke)1Q%iO0Q7K zMx;4tL9)@$mM%~gYgV*a$k&yM{6?V=jn>Pcp-o!ZnVBf8w=#v@w%sq_AQRBBmEmY& z{$@-jHIjXXe_lu|>)sc$OYWhT8VV2r9NmlEAi(AhiX76dh*MLexVwfe+*4xpLEQH9 zq*~r{_ddkmeCom+~BxUfQ>vP*eIf(>7@58&!>o4~D znK4Wy!QM_2+elpOcE>KrdB%}k`!@aDW&lp8>1=ZW=WssE7|N;QQ*Nau^O%`;4dg_U zwAOmqm5pul*mJ?`cFi^1)Y0*3^13l(wR%0I%C?IOUWx8Qd^+_&4xOtGbO#5 z0wpFZ=6}Gc)b#vwW!EKP|LygoK2>r{0!#wOjZ%oNSfb~mMx>07Eb{&BvaXDjPtrV5so9u{fDCFnTAHQ84)hHNnjRWFo=+u5J&O*po}6UY>Xz% zcvkCTgLN!*T-~hcRvyqXQ=or=0}9QOQ&u1V7I6iOc|rOrbU%)<>kpOF;YcI>e*THt zf^x5ay;!8lo8I)dO%(CN4X2GvrtMr!Gxhx-?B0`{WkRt?+C${rPMWuElKzS`0!7K_ z0pGQh7m}Rdlw^KJuEaON%d#K?{UzgryqC#5OI{@?D4_#uSkq=WHT)qOoZY2=h`<^> zJO-syNCg9`ZICMVwb^*5DBP6LW}gerux!sVa)R%1FbB1Nhp54IN=Lcd;e01&?79&3 zH&k4MLS6|nv7gs3 z?F;jqOs2N&nMvUWUQJ@?pra!eUPNNPQ%S%;${n`!!|^HryIR7a=((MLrjzpDBWdvQ z8@I&X-QdSwNb5SW2EWR_PhM7n5FkrDQ^Y^b++wnZlSu}1C|A5L?mlZ)opnvo8yq$; zS+3tV4BLh}(NtBBIZF*p{@B_}-0cRf zds289*>c2PGx!2=O^5-+-;7h`pwc9_rGI@HBUv_rQUH?1X(F2jY2Xh*cuh#WBtLvd z1pu!i3`^Fl5LEx=e7FnYMmC&1U7n7Kq5o)&b1wCHx$i60`pD$ao#dtJW~2xe;Kt4c z;&y%XDi`s(Ak2WK9jeIl6jTi=uB^d2d!p!w`D`@AfwOZ0j&|d(3;yezXMkk+!ROg1 zw~jQpiX;9c0&BFK{CwQ8qRG&)9gi_^bJ4T zrw00ep$NaX6491`NKlS}5vSWy{Q!sPJ8CPVM1I`;9?Ov?xx}H=HX~K{0kdBuoJ_N~ z8~QMkb4@hxr+!b}`-9o26P!~g>w3;(60sHq)Ils;JsJI?4w6u~HZ;$Ob8 zQ);qE7#-i$)`iLsGkh{8Ez^fcFt&AYq(3$ix8^n%P8|(Al^q|bEKU}swzDkkP~=VJ zjYvhA4vIz>*m|(A#DGuq$cg??TE|KrCaJ~&z+ZXf0ePe{V#NmQ2G<&d>Y$>3+si92 zt;CuIIn49;;Fo-$RZ8pZO5HCeUT3#8=^y2BVic2Nh6r(IE0%0v-;i9O zyYPRYMIS!-xaJEz6hdtvo9T?25$cL0JyMf_@}a8E10_$W-fA1ph*wX1ZBKzorE&#p zlcxrORx^AOJe;ygBBR}6!Rp$m`iCZ~mL>Q5paU1Uv1CmI41--wk{1sYq+WD`e53G1 znWHAhZ%#opQ|ryx3uTky3-%OPP_R8x{_Xba4Gbf118G4-FimG~a5^0WsP2kxpRe%o zrMmY4Iv@qHtYQJJaDaOx=fcw94y69S{h?5;J}^$tMUB(j@VO|X8@DZ48(^I}x3d5c zf%0eY-E}Oxr?g%S`Th^tH05XDOIMT^?O$$-Xj}@zYk-bnlLkLVH-k=*lB3mY5hU6A zj5+?Cc2e}JdH4vZo)g^l;#shY(n`U|kuLYc<}r?6wAR-{kNcvmJdK8K(VHEWRC0%0< zffImgsg9nDR1f6~CYjBkOh^psZs|_A+9B~(P%xxXL<0+?c)m?Pe0zLot#y7i!tm)S zFa_G^zyfK?kuSy@!3a{Ub-)6#zo0mEy(`j^Wh}Z6Fr+Ygnu4=KCS@>Lf!i^Z27SdNcDu} zmAFs%7OAI<;JA|vj8*teqVEI}b>%H{WMASHGD}GMVj|tonTVREj4%%-QT05X(sx|%j0O z(|E~-*d45a+vKy6MWU`vyBOZ*4F=@4s}-dNOYQ$D!+4k`I!C2X2Z$PPn1@;b#y~Yj zQTbVMHO_MdnFXC43a%5<+v&izbKnTc`E>&)dQK4_*@24Mk|S_O$U&rWYN~lts0eXJ z&rU1eC3l33Y_xmjKN@4issEoIj8va@BIv}`p0BwEtdCe8d8*pZVtQpHl42nw4XWXI z0qEP=PC|vdM1Y}`@8ZuTWTJ{smvWuDRET4NomWlqxbGB}e$iUr`0Q!Svmc6AOWA3{ z6_X=H7!~n(&)m89%wSrtxya63XA)$dyKPut-q%_|Y~uHi@cWsN$SWyE?mZY~BIziS zM;z?ur1wcl{;Jkq{S|jDFLezPnk4rjJW?rWF87Bbxyw?W-0Wxb&TwM*4^x(hrk4FO z)(K+cWo0<8^kR#%jDD$L-F`7oHejV9N}C%8Qu@o$`B zPjLGWJKI8e#FW_U=Q5>Mo(6CAMyo!vPHay~6KWBM2~~+o6V>i!5k}_)BUe;|1!MbT zpvA1YI)?QLlC)+CD&738I4}OPxf!uki1~Z1F)aPW%h!wy-ODt6%gwjTy z!j@u--BHD;v%99uD}D49VqlEvNg~hkRz#`yU@8|7+w{7}}R*RN-1EaAdK0K^E~EZf8h=piA_kYLv>7cPvi z!BcGslvYqe_3#`DscuuK`bfSRZ129SM;~-jJ9CQQM4=pCZ_h4M0_>lQ>)-w@Iwa|< zlPCJ!!SCd2AsVcu;<_5v#m^eK-FNbOkP!VgjY@uy{gxy;P zF;bJ4OrVfmG3&OlxPCXlktqHOE)~Tn0|~R17&AgMK zq?~_Av%edI6y3leb4X>;rtZf<4W$*Zlq^c9U=5`rYFG1247qsTa@m+vP&M0* z6{bgnc!o7Gqo|mZ2-B_&PEE*0`?iuYee?^uWF@fF)9fI_$P8&3#ZUkGXWqRO9{fLr z1$3fmf^s5-9QC>;{~l*k&Yz|#2cDCoKmGR~bDhaZtc=RY*qvRR-cwlpnUrExG{&^7 z{W|IWo9srzew_N5XWd@7`#)~%5yHwau{vL)T%no$^t@EWaD@RNYohuh$o+81xN+=tT*VkUk z?{QE>9M`r8g~#-cNG#2KKk%$iiu}&$6HoG5Y0U)g8(-et&!~nS26|$vtoM8Zv+;sk zR_+ASiLmUm!UTeFo|87v6E!#fgGGS%ga)OXgee6e;kt#$c@_Q#?SBIX6;@GTHo-ta zEP_-@m_(NQhz-E?1=uD!+vlbwD3FKuKh~7@M5Yw^EKMUK(b~T=eNyWVtc}KI?R67d ztDREY?49#lREED>kk13;_Ar&r?a8p3l{1MnIb%^`&1IUj)Go~8VRm6r$lT;jN{N1ctBbIip8lypxkqQ zj5Ll~;!{;dd$DVImO6+G$SvygiKM}%ht~S}o=sa8l#^}@BnN8@7ks7w?-FQe7^~a6 z|E}MuCsq*?uC?dr6=&8l9RLNoyl;WrGMs9k-iHY~U&;++@HheWs^@o3L>H>{TK3>4 zTxGKaVkgO-YrgimwVQV{A|quBFhxW952G4{45qRDjqrbML?38DyxoZu0v$g|ZM{5y zHEj?GKZ3u`A()SfE!pV)Q&u^b)$+RY(L8F;bgA%NN|iV)acI&3c%t&?VWte&a9H4~ z*NU3lCi3lmb_LX~PE!`2S$xbqQpC)jmXoqkaksuLUqy4pLI~;>n&=VxX*oKv`J#G5 zZ&iA}QCxDQeC#rf`JsEX@NsQ$hO8an%xqIiUoBc_AbV#K-7Vwl8{01TbJ~7Ks5?le z5m|qkCQ;cHzwN;?IG*s)pn|%uSMH;SkPp;B|1=6I8fBFhdb)vZqW$vtv#v4>v^;m%J7zIV5NoNbPEa4=<6j5|Rbe!OoZ>5&(+J=oWO%B{atIaJ8Jx19+T zD)pRIm}zmN`>!=MFFK*!QY-oV@kK_mHMTD?_$vP>V^SxZ#wtlG0H|nL!u6wU#56<@ zP~68Pca??}+`Y`i@1ply^)8OEbdg{qV#T<9`k->ue`nU&YD5rFJ|8eOQ_`QxJrrfq zA?7+8p;4}LXt1^pD~U&Lgd zx_lyjisn;W!G$#5z`qQbTI|9EONRNjSn2o_8`@Pvb2v3aOL);WATtJ`?|m6PPb(5=vrx>G=*qKxAV6Hxn7$k!=7ITseN8d8 zf$PuB%DO0G$*iyFt2g8i;lHO(j}Ft>JgTJ{MO59734N@xIn^$Y)4-)4P|ZNYTnV|6 zD@@SjcBTZsuT_@Cc|0jH{be4`N&nY1&w`#QrtT_%LGjX>xft>6TLzrc=T6wE(r^H# z|6X!oFm|_l^~R9y0x$F$dgOD9+y`zM1ktUeXbo>d_59r*=*ktR&Q#o!;NquM2zqak z&s!wZ$(-y3)$iCSjGuY?@G?q&#C!h8WH)x%cAlrRHoJ&L!k;K{V`5RjxJ{Y5W%xb5 zyf%cxYdYz@%6@9Av)ak2EI!Z%NtJjTGoaO{Rs8Sr50X4eIHw0i==P_CEFrDY$Q+>L z_~wY)W(iqWul>rfcBnQ!1Sx6GM?mB1EFUwASLG;z{bqI8Ef$<$ti}zt_gCO+DR7@N zP{psoYP>zFr+Qmy&twqhsS!Ek-p!Xccc2Cbi(qFF^u?c_Y{e&t3Ex?4ftp5AdzyoH z^Gj>W*DI$z+5v*zHq7Sk)R>`zsq5{hzTs{9rU1)u6^W+@5A+#Q#T#mCUc;5u zr9f9VTOe6!e7-gNyozVt0G%T!L{ImAPH>>-rLq=Ky|w$xx$1rn!ux}smL^>$y5Wjf zCgu?py2HlmN6LbEWqOK~z@c0RX0f%*sx&EMJI1BLip&iakHBb+s`e7WmZc^$ffXDE zqksNqZH8qM8>T@zLjq!VqgzBWI-#}~Qv9Dnnbm)AY!O*7v$`zkUVwbl{)lgi*S_4; zaXVlpk|Wt1Ck5nttc0?Yno)%uQf=mQ)-Ae&;>~AU%&r!VYl|rp zSBYcJV9CXEDQ$W`_IGt8EybZ?DZ(DqKe)LM!p^0Vh)Z2LZqx6x++QHpLM&10A#%pm z8$y+R1-T*zd-NgKCm%WmG?XqYMfGzZP)@ID=lT7CYrS?_-(GosOr#NBM@+ZellDn%ARt0u~q}8C_IjD^!fkMFd(~ktMINV*NCt+iVb|b_9J+4 zK3U(Ba57SLg1v=bX2cH+e|J@iU6v69hF+A+)KuVA??0-Gm+g*^{xxN$sp{^7cH}~y zrKzSD`nPQ3nb~iyg?eAnt?Mw)Y9NndYC)@qY7a)AZ(pS6zRytT>6Ma-IR6 z>gQe1YfWwVuDitt`VcPbWhBRDa2VVbb<&d$;*emOUuN zw3YYO>yxZ9F^OYn^X`KI@>GfYEyHLcx`vr`lRgea)*o+7drwT{{7LdUb{jaPPL922 zotq9zv}68vr}mS#!uH;DLdL(h-4>7lDTlzG)OTm>lOE1Sh|s>16|$p>jtowf``<<$ zm3yfwlHD3bInchzQ{RC9e-jwWB!Bp&6c?zXf|drcG-9dUPD9no)!P~@o?`nNt36>UUv*5 z*5wWCM?|X%mdV$4S5HmMeco$4UU44f-MYUvYptnvMcc10D^zg);4@beox|1fxmh*j z)P)+`)QwEqFCpBI%u{v837-Qw>IQu6yMq-j12!CAb(a~VM&_oQ8tg)aP}FoPeO=4A zs$*9{cIJKl;ONJQ=k6tN|E%0ut)yw39*gwy?yIEsOaLO~R^b){P_LQ)j1ap&}q&SR_i{L~jf ziqiTlmi=Osy10f%ePL68`_i!s+iDUsEo06F$7s7dKk#U>mX^y4#uzG%I&^IwRsZD; zB}94%@{myDvj@BD zHoPCCem}HrjI>RQD89sz+kw+5uIDxL9dYL>MYb}w`B|>;N`Pq*PG1t73 z3ES6i>(E=aS=W)&zl&`>e%LiM_%Je5qKRP0tMn?}1ScWjf)WumUYmEPQJSqz zMTD)d*8O%f1RXkD*%us+m5nSWkFD6JRv|6H#+xz0k{z7USM@Ly1oX9a-4w&={Ml%c zwDa+XJq7U~S&AJ|s=;&UIVl$Wi1B+HB>!9u@`kdUL0GpA^Gz;&vZ0ebQxeGIkj9u1 z7hYgkw?4L)fD7EcA*ff#Cx3_%to6o0z`RcvZuTO5QRl~QZZi$S0B-e*KuzrBkeL;_#PW{!=0SbWz*rV;K@CQXc&uguhlUs1z-9q;b(%2T4@4f{QYQ?;~AiCVga$0Rx8)i zpzIzVs1X(B7Ov_9)vyzo|GYj`QojbO@sha8+|gRTV=!HRBEcwUv)EQqfhw{%?mU_E ztC>{P%H?jV4-pNVUOeS@wd{8Fu?$h5emUArBhKL#GohmNEldn3b7f!N;@h64YSRyn z4UMqC(l_Oay`qSsnrdJi9nj@lP2nru#z2Z6))NY?2az>JRkg#2wd#R{5$l!z!y~~$ z)W3@3DN2E2H@_+y7FX6m_n#D>KUvb7b#>BsJTGZiL@OE-!&RQCmu4B<&-pZfd~rJfta?KaYvbiYE6mGq^H6K1!cVul7^#Nq^#l+1w&N=c=T z+3^@a+EwZHCpn5-|12R^tYp|Mqc$Tn>3!0pMf#t_ENb#T`14Q@{`=ztHYXpzxV0Rfpm_IkPgYgh!La1ASE_ZK$u8(Hwzdb zC2dnGrF4h1fS`0KA|PFU_x}8@>vvuIgZ;zn+4DNjIp;a|eeRRF1bc*&$Q}z6d)urL z+qkQ(`aoRdSr(Tqev|GU$}`&&MmRWaRe4n}xlDwUXNQ~WXgSIW{qD-uy#0J@grq;9 zKz8|5Fay{xSZ@gytj{L^|B#QmTqa;PjK{8>kmR7=L?zlp>S6XH`^rGQyF>3G-tmue zLL>z@k`D)b+N=BHq|EU2gd5LJ)<2?`KprVN2cc#}`0I%DLOmWw$f?LbBFle7zdHs? zq#TQV{t>MeMX-X7S{!(>1-QqA#+r4dM<{q`)^&1A(WPMD%Xb+llYj`StNnUU$x}6- zrR;#EM(3h89yRdHdwMhzxA&xD5Lj?AZL^eEAYVvZ!g|CgWApQ}L4)!-sz2c^IovGA zpn}DW38VG^Blg8iu-Rgo#pHC@;d|x2dl9MsNeTS-L0UY_)`-7(oI&TS2cf1BW6;SJ zGYETTB93F4sHhxlxs!%^gz6plV-+v1m#g=h6?I@xlz23lplm^Q zpVM)4N7gS`;On=N#d&?CmqgXzC+nM#3fHxRNUC{U+9>Y8@)AYR(57Q4F!}^vi|jVB zc`EVvPxG@6AH$>%#fC%Q4&EQTeCBwfa9n>8k=4mq&wE&-eLWWTQ~Nz!_VAC#a?zU0 zVRJ8FRUoP7QgD4}R6fFHC6&rtFWdZF!SbE|=GRjMq0>{_N!8sOFE z%$~w>74a~6`+r1M5c`ss#fpw!gU{Q|o8G+Ma~|Vq4Tub%`1ULN=5aFN;ImIBDrCmx zzs{~u8X6sPD-r&v2g@l-4^;5beP`v{E9;x0HP7+c{(X)7ASA#_2{;gxU4o3GC$AMxdUD&kbWVmgm-dkBSGghn|xiuf!MN=CPaZc+>_rrLGx z^~w2YeBLSgQ8Z+C=g)Xy=!eFiC%1FB9D>uTZy3q~3L2goH}Vw?^xn_Rcxs%DY$@V* zR>;nEyZ>`+I)7#_G_+`S)++kkt!+!|i+Hn?Fu@q)=lK-jTwtj;*68OMqK}^aH7b)7 zx>v8RJLK6?`tkvSrAf*R}>pT5^j$GgQ>895R`!2;|}9P}?y08b2ix8iEKkWFy46 z%1x9}(_w$@p~1(SDh@fbim2wan}Q`!vP*YLs8hzn#iIskmhRPG;!z0cYtzR!ivhS{ zoY3)L+g*!?b{8g$lkmw$KIcK&g==B>^9dBd8wq6a=Jm;FYhx2q`6TIhe9b6dpBBW1HR^sv>9Wy2l=h68O=*FItk% z3TqCSR_m+(a>x^m#b5SlUaFm3w}GE=PlroiYou6v0hnUoUD|Rdc`(q1enQl`?r-)E zCV$Q=pLW{(piI`{uSzeYbnTYNu|=;+K$=kZO_it~Ez&vdY2?+>N7G>c@V^9J{!f3$ zlV#V{2DkId#>U&?qfutmcPpyiMs6At>a!?=bj4xckCHy#3$^vX#T_iX;2M9txFXbY z8tPmAxIrX%c;JLEmm9CzyzsJxkv*F5|AsLh#0dmv9h+*?92hu(1v6vTW4Z!!lh?d)9 z^fb*#oOS`rdsBuJR%?8Bs!Qs_`;&aur5h1RV$fF>xb1|j?}dsykAfJ!k4){x>nTn5 zv#H-+{0=g^DUIVF{we2wei$^_*6q{k%KBjT6Lw)&`!UFsavBw8#qy8HWYKWRzj9Bs zQh7-q@UZB0>8@v3@rgDn$^WbVX-e6h+g{D!sLns9B0=ICY?V9wsD}p0I^l&W#v!z> z_?}&C9fD0rTdzXTJN+%AJ5n@v?5+sciR_P$t-Pry2ZIM@2*pZT2Ma#QQ=QdojLOjC z$Z&;Y7e_=|!dg3m_5FI<2A0O(GvCjQ`@6RVomIg+k2L*?c!Zw6#UmkwI)qD)hmI<` zYo5-NElF?yrF|cysD#KUH%|BWC?_x?_3TRJx$FI=vuI#K24$b#`8)LI2lCm-EzRfw z2>DX~KO(b%n;=+|J%>wcd$ZyzOezg((bkzhWz0XIkb`4RFqpsNZyr(_)lBRdX;BbxY zS&GRB{!>_8+d`IG@7aSzEP*`v$NyOTNxhl>=^-phtHFFzh2g=5gJEi_yH7&s_LSrp z1I%Az9RVvh+YP;^V5srpz0o}fj?>ieSDzJiMMod__usYUr^n3^w5xC(gBNDBB0KI$ z(8({1ckRn2z^^3fJ#i2F8P%<4Z##_9^6zM;I_Iu zB>}CZMpAZw1p+Tn-1V}e0a?t{^B8qC?!1Zx9v?npD$l>RV7zF^lJgg{_L+($ZDr8K zu09?6VlU+-bE@3eauF-8V@~B{$v61G3&Ag_Um^r`88+K3wHnB^s17?jXUBgPeUJ!os|=!||{{UJzBtNQEBn!pBU%Xa2x`V+Rj zl17o)XGqsNu_uKNAqN+A<7Lwx)~ElI9a4Z{k8;E~){OAko>^k+@qAlZX~%q0&?gU} z0bWThEJ+Kwx9C-*7niGBvpTURzDR$A$;|H%e*23wOZMH|$5JoD8pw{K>0(uCw2-R#w3Fi+6#BM!a_Ll3CFJ+w?-W@B#;E*DtAuJ{#@o zxyPyzY}bRM$`^s$DCsHQQ{&uMRTEV9FEb~_Y)@o6;j?;HdxoT`X<54u`_^#YIi_5* zhn~mYgyAO@X_gNru$7mXw@>%dytwqI2D|mgO&O-R2~8TI9>wZ1U?B_FLp`w_B{Wl(|2XnDUKQ&NJo82o1bG;rT!8nY zbpH_vT@X;Wq+SVlm8ojk_?dm8+Bm@iCp-_wa=W!x`QDWcdQ5r0;>nnM-ui6075_~5 zgdjVYov|KlCF_h093lwiJc->iO38Auhvls=Jvgq5ubf~eq#ag5Sv;!xgNPi!*sW7O z&$a?WZI$NyF@a9*`Fb(i(q+o76mI#Ueoxy-C+^#+_UE~&`uO6{4j8){7j^InSkmy0 zhGS8j4B`<<+8@013hkd*0iM$v72^_RvILW$tfm)So zYG4a`Ys2m_me!Np6oeGi*S5U#S|Eo<_l4@6RvFj1!W4ra#{KCv;+{{D4PBt78p5Q6 zjm4#3caaxBW&S{Y9-)aSRC1ZlhQx%<$fY--*m$6{6@_&!E|Sd8<`3n1xLKUKi*2be zqxTR6cEfLUl>baEz z^;5Mn`|=qc=#Zh?n!2rAiRa6wBeaSx5JS&k?{iOSSQC`8L$i=E3uh^ze-?47x*LXbs;(i~7-iLj$KlHmQ zm*<|ebCJDw;tP|=^+o$4Z*b${)Vm>Iqq6&s{d-tBaBj7H;=F7JjrGWW|6WI+!uo=F z?B?wg&pXD}zpAxvZx|JBmPr96$BWAEYzH8pO#8jFwG6NK`{@Q@&QjT|((^ea9Nm8U zB(fR#3u_yW7jIJx3I`3~gLwxN{#ht{Q{_`|U)uma9J}XxaUJeAdY!zI`l~4?fRM=t ziS&d4hE<+MX|-=C|CD|yeDkp9Rt`pz5Zqd;rDgB%je8ni-`4S zM};t7#+(rUp?utizzNJv4DWj6+Q2himLF-eWg+Wsql#M1e(fStfJwTa zJ}J^`ktFp20g<+V11-e{GQsQFDI?iQg8p2gK>LUKQ_f#d1WuJerr2;D4{a;JsO+#A zWTg7LSz;>capl5c5P0{|iwWwB+0Tr3K0Xt`>z218qO79o*K=OUio7lDN2$RhH?1oc z96**+mu#6Cf94hpPmRyrPs&Yr2io^S`F{B%2D!3e{SydXcML4`k?;U8>y!wi)%sO! zP{w@L^Y~tQ1&H1=nV*?ojV$j&a=5|0pphrjIL;nK&aU5FHK%n8y~y$E%@1TS(uS4wrHd#(t6CSEEr8HEU% z{rgkFH$_jj__{Br!MMB>CltZJ$c z8VJ$s`d|>9e4WLv5m?qb{j8g4Ex86M{!SujUod) zMQ06qdWU#zRAzN}3Kr9kwMrCa_a{+dg%BPg`)6rCLoE>U?vwLzDKocSh?G)ve zRzZrWd8rKy2YTM89B{17;MUg8EY>zk=9XH)gnP=xcAw>T^8TMzHf8;~NJB7|nJ;J# z_4xIMW699%n=Y*7gBIcG7J4zg@v@_L1=yV9ltxR(MoV?>w=Y`a@9p}022^u=m=U_4 z-&;wbeS2+t9yuHjmVL2umK?ddWf z!V{kvzZqO>78vy)6LhwtkxV!M-h-(%YWt zPmx@pSFn2Ja=s9+rBY57+cFKVjq%ggdO5RoJdr7K{@=jE8?3Fe@Lk20FkIiv z#CKXx16;-H@{M|>bACNtsO8CKn_~LJ+k6`Jd-zCp;!P1jelk}4HCqm0 zmrK{Wdtn%FL zDH%x%oTtN@6f~&_J{s5dl|B{u>kS+*E9b%b$d2TW6w!xTow9zrtHiAjr@np3xTpQW z%I(%f-bDzzWiSHdzA_nCo)p*6t-xiRx3Dd0)Kr%WzBT4z$F%u(mH|WEYaV}7hje>T6!%ScewiR^ss=SivNNLCI;EGq-w^L#<5g$$z*g^iJquvvZG8)KU%N8D2F*Rb z%W?vk&X6oUdS`VH)N7mHuGP5sc_OLm`<(#UBhdErZc2bg{OWurD}jHJdZ?nyvg!;7 z_u4f|Dd4HNX!Dd)PT(jVIfm~#tpt74yA7&94(kyXIw(96tUl1G3n(Hu^axh}!4sjl z@0fJN1e?>tIB8R#${Fm~ttpg^yY$IBSpFqf<(@_X*D2)gtd2yE;0L#&6Cl1XcU5Xj zA2$%aR-tANIg| z=r?O9(w1tdnw3h-gO`frjo1_=JdR4&PwprpR<;zKSF%koVw`dlILW_>Vg~)O85k8@ z-o_CPAcC2PZ`V9NRO;Rsw;|QgOvR5r`=+U*JxD{;u>b9#MM5!CT{+A!Wrt^cb9A183nlC4`BaD;FlanjoU(!1;D8^= z?*Aav|5ZR{f?^q0uGAXI)&#%1+KQ?XAEUY+JP6?%MiR2ln{T)~zwh2goYad|dS)-` z>t&hb46!^yS?-0`wWIv1J+f`ZU1;96^{iKnf8Ahmh#V+?Vw>%Gtnti&0T0E@Hs1Hp^KTIKF8nr}t23&SxM~ z%pi$&PoLGr7FN$PWEgczt1UT`a?$#E^8>t%Kx_vW#uA;U!#po1*ow-# zn|T!#GJztuEUptg4tx{_hSV0=rgU}t5E=K1bX&?~5XrM(+N8w?l}i#<*$(K{9N#Dl zMpU@H&|(Syu373JaQ&h_1N`LfDAoRd>b7hYQXE-y$;+v%E`%Pr5N61Bao`0P$~cSW z60=g4z?ufD2Zq3r+-F{rM?x{DLIe%ePxXcD_l=UTMV}P5v=99HJ01VVUzH6}ygJy* zZ`p609&uOysqr(1RE~nXDxpS}9@r}3V@&okp`1GSEC=&V?*peTUrA)SuEL951<%8` z#WzMu^(yMUATe5yE>D+eoDw{r|O2-V}B01XZiHwAOF35HF?VKVuS-U(Tq2|&j`G~9*B`BD6-fw zBs2-`r3~HyyrgG-+N^w4v-s%cT<>2CyWt$>w{|#NJ1F(7S=`pC-n)B4+mG6F?`E+P z8f`BU2{OL(YYn|_AMMT*2u~D>31YR}evmULRngEJu!#3;ue-dlb1eG#9q=RNwXQdu zV{(5`*Fu*oKPzC@Yj->8@^7cqBD$k}jp{m$n@By=VtNPk7(vm!J< zD~EcD*BZaJb*6vh$=ofhPqHTp9~U(R|lx30GF-sR8SZptkezm)fv94GmBjk>pAiuLOsJ~ClknG#Ag&Lm&7p8W5> z{}-*ofL7TAJIG*u7;p4qg2QH_!r_)HusP^XsQCuKMCg_pm#zM=;RJuPvK2>9hMC@~ zi-!sDEqVcI$mKCO!I*>hLA-^$e)bS^#hQ?4oW;&gHxUvHcAnYozUnqJUsGZU7SvcqK< zxrkc^&6U86a-M`)X{_0=LgkDzIprV*lJs}IeHe4Fx^`R%8)7w2AL zsJJQ(FG)-<5Td##;dyJLZcyqC{^=av26{UE2I*>$j^nup*dTA3VZ;gDMpxZ&!-}GN z>$$_<{2Vx1^q-sbWY$MXj|YNB1qm8e;PL$ep>6`|V)4-Z&UZq%8OMjne!Tcc)Xu4k z`kd&i4}J=k)K2B-)0#jQ$PN{+-}GTqIbrm7hZU!4M^nS-IewXmafRrfK$-2b&Fcm+ zoqPIRdL{B$2e>~otSLn!4i}X>+f#ovbN(~N?yr%H!LEYvZra^DwS68(Svc0W=C9#W zcj1DnnERucfRj7SKUMv?=lbBj292Wu3W^dWJ?OGeUtkRc0I9@<@aF#!)xN%tLHxWk zM3+})vDo5%Hv=@mz5^b_{Dfvd5t>eYJ1?xQ1hf#(Azb{!7(f~>$QG0Z(w{k2+h`Qo zpbJ?2oPx}5zaj6R$?hYdgF|yypuBk`xb6jpeQs{fqkk4>SH#FXL!al>KXHzjb-C`H z_F5%0|EF#?&r8(7nzCGMT&2Hw)I6^lE4__A;lF*W!N13&Owv-p`~GU?)o#*AB;n~e z*_ObkZbhHaPl5h_hNKaV7&Zt7)>PuWiIco0kNUiA;TBVF^-AcJ4GXtnH#YJ0;+SB= zyfkmgDnhf~Lm@U8lJsjUhjdu9F>V?Jss0Kh^#DFM#ia?y?*A08pR{M_Mn2I?{IA8& zQCLq%*SvpnV6WMHyk}S%$8{TBtsREt7oQ9CC7}Q1<(vtN`pRWC1mcXHtE!vu*Q!h8l{Cc;cRVj@z)lm^oO{vwQLAYv9I%w`aHvBNoOItPWGd z=?3tFSG%>533y3mIjNnK3dOYl^*(}Z>;U8O>v6&gMXhtbvolFlr(hy^5qLgi&NarK z)*fdckbf_X>u+DOlk{&vmA`@sAzpgI^1Q-42p@rTE#Ne%+(4lLY}>12u1|dq@;G7N z_z(-105=s7$frotNCcfs1!W1|z?BXP{@eCYW=PnuF#iT1iipwp+(pn~bEE=*RR&_+pX}4)1YWL5)Q?etHK>HWZ{%Ot zM!6W>yKWO0=17d{Tq2#c2${UcNEXS^p@gu;ka{^dI9ZcOPyr^{coQdklYgKKQ)Hdz z=KDxwY41^Wp*MgLoayB~Ft|^a*v5W5)+CN*tOBGje@4N963r?+z;ccu%_#9eiE_#I zF3nmK+6PmjNBbW6PMz-zupAO%t&hMI6$5Id)R{@f;ELpT0^PJn2^sgOi*knVC2xMY z;TTo@9Rn`DEBx-9R)AB+2Mw`n)?bCG`EKr~RKD4Wn_{^kKJ&?YPY2_(A^O-PsN_rb z>Q5XAPo9x^JQ@IJb4H*@taoJll!Q@oex!D;@}kM;iow))Dk+)I9N58pNd5Y%aX*d< zmU|bp!N)(~oUV!3AESm3%kg*Qo|8<>J=Ye{EuV+SD({j5(cMmP7sXPB>w^rX7m@Wz zlpV|`-DBSU0cl-YQ$)TC`#Da|&FJS^dVu*Aw2`Z0hcWSTAJb4*{O$E+o?4v0!1Nh? zF7OTWZKIW_p1uLlfY!RmP_iz|j)D}Xl1^v^(oDel8``{kB#J&d42sC zk}ZZ1=9Q@QSXiT;={MNAPW&0bSe~hQAzUy!+A_AYd62(e>nL7*`oqSAcb^F^SW+l|) z%3y1a5zLm2ot?Ea8vW&)J0jL_nU}L)5ft0~(VU~_mj%q(z;Xh(qQ@#Px86`#&{f*X zn?67~?|qPToHP~2H1~siPupa5NWCO6gr{zuQt%K4u$oXA&-N`D(Kd}oQBsjt*=JL#*DWwylz$c{H!+3S#30deBWJ~)#RC|L4B56Ft=GJ z)kB>&Jtj6jgz)>R$eIkHo|Gw5KXpN7_CyeL5RTP^fT-HZYPyztLA`S6F z?NRZH_v!MnW{d~aF241o*iV?c29c{+@n~JUJ2Hl~A+rx^vpP$9VujYibp@H4!|F4C zXVTKr9>p7H`Fw;Xqf^H3QO&}|%Jj7V#8_$x2Myn6O`>Y4A8^xv^4J{f)B#fnT8bHM zO#dymnM91>3$IX$FUxqhQsYq2qQSi%=w0TfMRN*P{lsFd(u zFd_RwmLZsE>+KyYJl3%aJt6nUSS_tH~b(S3q?s39lVrvRu*Ck8zT{5~JvO z%@sQ)AUXd@kc`d7eI8UlAhGWPU%}eA;+1@y4Pg9ll(p2xsa-$L#mb@|3wDb1|5+0? zHfLgt!3Is4#S6s6znOR6_XZ9PtF4Cfe#bj@hx^nncvAjG|I9L&k}03hTjp zSUm1snKu0$YVZCt)*85(Nk4_W2-H8B(@T3&7DF-y*utxw#YH2O$ zRRH)JdF`t4yhzZ8W4t^k!aW!cqarLCn#uaO`+~1*SE`z^UPX!Skz}qalYP3;&5P$S&3sgT0 zaZkU>B7L+Kg$sXEe@>pPDL}W5RH6RkJSF(vbxZrmVE6-Fk{4@reZJ#?QMhDn^{RQ3 zt>Gvc>7<{gCR+cC%~dl(DAT5#UBs(af|Hr>Y)Iqpq}AXknJdEBhFWxO^oj(n+kac= zHUdj`F9I2$n4`S~>Ibj>ez94DmPExk61Q=>V}Tsb>N@ythA)Pk2@S)M$gsEAe?*y4 z0$HY-*ZO;g4h~nOT{c&mjT6xox-)Z%L|Nnwx7?k^`imX=A^d4)j|-1DovbMnwOsKb zI?4xvN?<gc{n-Kj!0{tb=N(x-bOND*MX4Z<}e zosLhA3bKLa&&!LmCI!|Y%*pf<^1ps1f|MjKKsz*ozML&_?&DdA|5mtg2 z!GXB*tqnY%{JwDC*uFs&00;zd8@Wn?B?ScsT;7kA1EZ4lT*tUuV%L^khH0&2iwa%vq3dB$F%CIRy!-)W^kX51H=e*Q5`F>-{z#Sgep6jV9UkX6D`(NIeX6%N;M>{YbH z8Lyth0USQi=mWIP73UfR8O6CC&Zb2fokd<*zp(OB>ddk8AcG)dl97S7Aq$pGi6b}D|+a1zcgeKc}&b*)IwpV3l#QO&5|v)`U}jynTo0q4+GL*6ON z&Pit_j0fl_Wkm}iYyzSBu6>ZZ89p@T;7X2Li5ADKhru=oO47y zFZhgo=P5g5U7kRl^o!ek7ye zuY_`K21tKjD?6AYiu52H+QUb9-CGj-T4#I|)^1c12Y4GIYb_933ycj8q=K}`L1Ks- z$k2SGok;#T%yJ1aNNX7jN11R^G-+QOp5|ThM6{n}eTq5~Sui`+0RAHyAP_0A$cXTp zShESqHbA>}z!CGs63OH#d47+}nYk<$CF#iaY|B^@D9rZ}hC{c|cMJQE-3ut@q? zw?N?`pMjzo@iGKy!)Jdb&rgZ#vsn?ryh?nUvd5@99!taj{K&n+L_25@nsD8(wKgy?!tN_l6+{8}$ty+%gsra)crb+N*gw0sFAzt-h<6#S z5x*@p$!f2;5q{_b?@vw+R9>Q(Pz)N;mgF{>Km!!P=o?Te@(#*(gqWObkkUcZ&cT>9 zAY^MbgqA}hw!0&kWEcvHrOU&D_j_=Z>0_J}^GMDWmJT>&`kWkZ;H8`b?9yp&?RC;%uV~+T!PCbt=g$H8&`9Nwh zuR4Cc;JUKWt@)i3_UV0m%$N3goIEkVnUDw3mO3^QQMiIJ%)WrX7~2tD6$0JnX4)JH zfGWskk5H%t?$9vjKty5&PX8HpD_?Z0QkAFpS-%V?<%rYA_vmtJwainkk2QtzQwtBcwaj)(M0_hjef>In z^4;49CQ4h9dM3Qoak$tF#_|@{hp(|S`CS95lT$%WlOm-e(NTK#te4!nyOs52h}n!J zAg7Q4i`&g-kW5hN(TU~_ZqLq?AB1-Zw=`Zw$SQU2#FJhUi;aV;5HbgvEk6(<~72Fj_%B47Yh$j+##DZ%GkY-c!}Wn zTDEpPnw{l>SZ=cY9FHViuxfEc92aEp0{&_}Qg!yp0B151Xj{5nx~qdJ^<)5b|2~9| z4(-nO4&4!dHE_i*vaHxft7x234@uZI<(Ug-w|40Zq~=z^DB1+|JJ-X`6wOGXDty#g z9VIF&vA}S$U@Ae4goMk)#0f4g>>iMM%*kCh^{00Bcn{Jui5J8K5N~x(vbTYq?_0A@ zjxBGkehHE9-T;ipUzv&E$BHemaOTSFe4wgmF?K{TiELG?gLABm=rd3>xrC*ot&H=p zfgYUmw_km%B||OWP2V6<=JocMW#(1k^w@>#@W!AbVQ8ZMYTWIfBtbqcVH+g#8mNA3 zpg~9iLf;0U6*v^zfzQ^;$jC0k$LQn%NKn!k@frkmG*|D$0aEW4J{jZPw{tT#4KYbh zILhbCr`{LZGmmVN_Uhb{VOVoMtGN)G(!x#F>_^QLcl{&MM9=XDL-qUaXtPAn<7*c* z_EzIPKCn?}Ep7?-X? zce)?-Hs#&mjXP2%lJ8;2{z7^44zP4(J574(T9 zI7sLj@)x$K%c5s@L?&oE)GiMe{PnOstRd6DhMOT2MG~lWv|iSoQttXoC!uD?`FXZl zR{g54h-?ujLrP`a(n0PUGsgYrBRe$RNnl}Y7H;_}tJ{ooS!p8!tzl3(~Y%J<8)0(r&Ei5BW=jOc2g=cr~k9_>0R~(O4+4t8|PP1=4Lkk zh)VhGqdsbkhuw=gX@VqGm}|t`#6q_4dwnw$`7xbG;qhIb%5iTJAs4mK%N0<=SEYYM z=_9eg*9s?ORoOa@^GuAKwiKWTWG!aKx;|}<<8|wQvW^`77Bdku+farGO{*;l)m96N z{D~!KK?dwlJ%jfD!L9I9yEqd}G-ZMA8y{{Sp>=Z&^!MzQWm!e8rKBg<)qeIxXQXKC z3RsG~sqbWQrwXGZJy>eIcb;93mJ{L8zxF3=q-j90KPG(=WTPYxUgkJ{;U;t!t{-cneu{j)4_24($Ws2U9M)?gILG_&0uR7H8pm8dLliV%e3#5<0}bgs`GsiB3x z+GhwJt)JRVx-((~nkwH7JUzi>-}T>1Q@@v+D86zn{0Qc5FpHxbFThJWC(ABvC)(%GtR4# z2&bHR^y_a*(0OFs9lOv;ccOLS^mwM$#>7OGmtOS2)og5TUf`5m-Sbh}%!A3ypTYTw zOR+!PD1Rlz=Mv&C?r#p2BB{0uKx)_xSfbbHp|Yb3^?yA zF4Uc=3ChhTRj)^KM0yO$6s`AbTa+0uXI|6qFx)IxZsqk+vp3@k^g>10l_e>wKmr}II z{EuVu2u3+o9%yx|luj9~9Xw#8{F(FV%T)nm9$m?eoG`j=$zBWZgNwU5M7n;E=qIb= zw+@om$j6*TGnv;u8O>Z6l1{h`b#jM8!tXJMxht$}ncXkRwT8&5UpOciC7jZ?E?+Tr zGXKb`0ER>{?FUOmQiBpH3*9t4Wm#JAA@6xvQe2YP51{LZtVWFY*?(x$ooI$Ui!4EA zPt{*yMfz4HITrQjpXz+238gKk(!JnC6R%tfmfpm8gEdG*m?7?Qhsb%k$7$TLX64@g zW4-&d0M^W1&Z6B+ZzQOI!xl0|aWD@XwZGG9FOAhqnEpz%OzggX!Kt2V)^E1W=2)^* zML-CMQ0${O8)E@Xk1sTd@`IIr4|Ipwq)->n1qz<+`qVZ~wi`2v29a?ZH1V9W)6AFN z8l~TiuT+lc$Ry5XjE|;`Axk$o!zsyI^hC9R+mf!u`3cj|97dupNT&OsmGCqDYl)&% z1+!ju)TfTz4Cv8YbN|bfc&+`txF&uBfItyHVhvQYt);QDQ)%6O`TQ%x4k27#$=5J7 zS|+c`vziCw&`|fpeyO3*FHYAB?z<}!tpEIp(P}5@fn0A~_kXn#I2JZg=)A8%!LN3v zy1mA=inxk#UmgU}?`b1autq=iPy_&eTRv4+IimrX#3JHjV6F4=2CFmukEkMPucY2D z6reCtyMK{x_sQ>T46DahqaMHU!rBf_J@4kmh*X14&83%_C3zlibJk{#G#x-U$2f;g zh#pdlQF}f)U88JeKVEGD{wnN3{K?w*rfNK!)gRr%ur_YZAVtCk`cfGWqN#^+EZ38= zyuuIeo(Fwtw~-hn@^OyV-|jm8I>qhEI=xIR6VH7My0i?u%Yc@4e~2XO(CjzxQ<$CD z;7M!063CRJO6lnfHBd*|{rvoT^RMl5O?LAunQOAbW8$8H_!wcgOmZsAycC8%JIHEI z9kLJqi0-3{{31CIpD+YMMB>LdLDX1r$$bes^clA{;2)9Re5F$U8ML6S9du*>7amAq z0jUOL!=(_FfB7#`%_%~PRD`^qIP2Xm+%5PEa*Gu$F<5rei+Pq+?-W$}TmP;11x7i4 zKi!IWLaOzHb#h6={;&v?HG!AYR3?2(8@6eOUW79`_w6uTp)UqFg+R{wLJ|>Yocz@l z&BPlOXHnF>L*lz0n$|~Wzle+2pv(pq7ZKXq+UG#HSqUF+S_PGp?=^ zM=5bUm~J9rV%irn1Ix>=x?=qNWh|m?hs7#errsfOcPO%8t@j09X^=VXYQhp)qu%r~ zaQE6!V^wJ>45@cyp=>c+&B?S{FSaIFoR^pBErBLuyJl2ru!08>jJx}#(PooAvm8$y z2&~ihatj(YJ;x&eu3&vRy;&Y2gMn>)w7MLJaQa*25LscK-MY1N;w>n136-XSf$^Zr zr5Wk9qKtH&o%4KjTwieC7^i#O0hC1ooezQsvYQ`J167r824%kK(v`|MA(>O;mPkvS zIjJ@9pyUeE7JiHY)L7Cx-O8C>auCAf~3BRyHS_${Yb6M1tfnxG+LmRyRp9ioAfDV zp_5q^^pML|o<`QRm{*OqLpbL5FTh7#zb0MM4s7;#DY+9p+2gwU{YP}F!8)I*ye2Co zov4-u1`5%iJDixu1+Oc}0?yxv9aidIk#BtM zx>VqQj`nQzUoYQ7Cvh@nq|4By{LSS#__GOXjzS)ciBq0HyKxmdFl=n<*8QJ!MC3fO zuJXcl$66qt{;o(aVjbo!Tkx*w5z+D>Q=rhJahhF?K{qft$W9jIr3}-2TNQI$>bS5IHVV6RlnNLE> zZxT&Ov_A{)psLa)3Y)1Teo7S0qst1pYmzM@vj(tiX8fN@rXxwnMZM6v;v_CZ|+ayH@3D3#nDjC-NdZCj{T7 ztPHODL-;$+!V{7*`TP#>{Ft-LuAU~NmF6pIK^bel_~D9?`%9T{QlGCOa?DP}ywlqDAkc=Prs`1;<0=bA>Wz0(Yndl4E7O3`3q~@`OL>TmfOZ z5mMZx2Xmi8s~311~h&+6k+o$v)Assl z?@vqes5c^jPAU7wC1_W;I{`%caJ)2l#nZ5_4W~1%Dg{0Psjr_@5nTnD(Wa5})fDk%op>xkzV;u9WO>1HrRr;GI@ zykvSi>Q?72O_y4(V6X8SLP*9*e*B2)cyF%>yF+~qL;|V5LjgbTY|DQ$&3~m&X_yqo zM+2Tp))pu(p?IGG*x-fg2=2xu18eP+p|Mmc<-)PoaDl!w&QbwW0;pgSzr#{>>>zE) zl6(#=Tii<8+A2xaKfqj(@h3rW{E2Ydf$&@FSm##{Ymp$LkKbHGGtr#OZbAa9lqWLF z6Ct~p{YlI1H%)HLVAytgB1K6n%E$B3&Tj|*oQCIAUDC4g*`{t91fHWncx>eR1h6IF z3E7cp^}AdnYuIa~!BlH)nO_S$qu>g@qHRRI@_-^{I|5+X3C?JZy{<9etW%1`@(JDv*=hL5TQ^-fJR7h?X$X zz%l)OT`}t7E@n!17NDN?9L@9UqXOE@O#Vv(eF!48V8x%3u{cO^5>-b2Ws`c;>e2;7 z+7;k(vz9K*oaiD!ML{}FW@e6d|Iq0~l7JYLQ}BNN`@@%-sS~)iCM;Al=Jtx3PWo5B z-#_w?&N>K_5*6*vWHqP{Bh}8`*Z+^AbMa@w|Ni(ka~Z=n_xspfqvn2RV==jQr&Pn- zN^;GeVQ#r>F1eFis1&9|7csZV{gQ~v?c)+LwIs#&=l3tXAMf`$=Y7uW^*oiRJ;EWn zgZA&{{kNVmPt^A1q*-lLG7K%GR;8t!^v5IFuZLtRP4ZXLP6Mrbe{XdV^@6D`Mceq- zulXxCx8)na_dogOGNuf3WCwao`n%e=ca-NO5W*Rxz7@9_u`oJ!{T;p4i^>0)*TnG} z8NE+hisB)oE8~c;Dv-e|+sFVXYm?5S1jxgm+y4>564?k%-BS(cq6CYVny7W1 z{SOiWLX!xbrAsBja$)oL6hVMbvy=jSM`o4MYkfE_H8lV83Qa`{&njUCXijr-^(p8tb z4HEfAJPdX>b396TW%R~nQ4oV-I7yZhUH`}TXu?#kJJG6TyMo}|RWD{M<{(vi@>6PE+s3;jf~u&q)|PxJSV6DmdsGIrwyfy>3jJV>d9B{P79* zuEeIy^7hYqm;M`V*}rQ}jaDI`&2oZbi_9SrHa8k-H;qrNDlhZzrcfw*6tU;Cu`7AE zA%9ur|J}7(YT>P5=TffMCt^gezlNrQ+S}Q=rp1oquy_fUvkdtF`J2Md3FD0&9J3Od z1T3AeNT^W2php`7U0^*Fc7dsvvsnouq%~~*1Tsvq%H$TC{Yr3mJDb0Y1lrOBHA0D1 zO~j5Bkf|&z779eB9uST5IRJ9+IWF_y$0s{M9SMOJ*7$SRnwrV@e_apoQGgizAd#3# zBQ_zqyN-ULKMk6wn8D-Cx%i*Qg3Z;noljD2F-wndNdYmA*M3M#_W~$ zCK!m7cX&z*jrXp-^d;%uX$y_wn%j#FS8id3Y;Lw-ek!@egiF6YlRt5NRjYhhQC1k< zQzinVd?;A;F!in3t$uf`J2X-a`c-)VHJEJ8_rL z(X9Ng-z)3f$xbCJ0LS7HSKH0SghAXt-Lyb|Dp|p-@OI}l!jL!%8<8%{Be8Xk^`jAR*O+XMg~x&scL>)Io5ya@2hMVzMzH-02?{>%PpFsOmUs|Di<2tG z(1k)AXdBz**$yQI9g){*Le(u9M}oV@HzG&Q#=K_YE57|k!^_QEeH~$)Ycyv^{HZ=E z@Lu*d`mbuu0hv~w({{tz{%3L$u^ylg(~U}A7=Ss)Dl zLhd2WkXAN}I4f_2`PSQf=$P+q+qlbb8mqQG)w(R#%giS5M?%CjrRp7_J*FmZFuy<& zDG&Z4Wn2lgvwB8mP(avi+;!hVPz7%zVOhJ+JPCb9hFQHO;=u_(x!%;onk0cDa~Val zR0}_GAVcNqdYO7-Wc=Ux6!T$nnR;_BD_T8q1D&0HV8J?hc~j%pivpI%DAC!+*-qTt zH+EbX`Y6KjX%<3=ggo9>;(Jy%C3m50EnJM;n!^kSBk~9+MKeA^19DGqJf{#>TR+ zh-b;yD=d=f@}ao}H)^ACN$t9^73ZPow&2Wy?@{j8>PntZq$j zWH@fsuj1}AU}(3PE+r2hY~y42PhvIkuPtW%K~vMK>c86ZlOr0Y`K2-C&O<~47hRFQ z$?^S`+%fOk%PDoW*Za8jL)x`)@JwOF?+Mp2pJQB_gx(AmD54Q^HfFxc(AGuO6W?!} zyEwPb#=+d=-4?sBp*DXZi|`~>Rn=c^i~7X)w~iW>YrWrwwmUYweDNal0W=oST1asALkNCx*;8JZw^fKuw*KWNk5P|# zNGSka9XmtlpdU2}-X5YRO-mttJ#PI{Ugjq*U?6jQ zDz%!wkI{$U^Q;?h{m0d_9QcGA=!(fEp81JM^;&wLnA&NO5KZdh{#bP(Tyf-@xt&SC zvHk|vkGF?Y9u1r6!Cp#x5aPwj7Gq!ZT(6;U(^|@!#cvb(gst4)z2|V2EpoIH{J<1} znODIDB`M*6+&XCw-zhp(LJ2!0tDaLr_@Nn18@7>)ocp0pSO4ksvx7<^#+WFj@w+_k zyul+hMM~~0`E$=7_a%9T2MB!K;e>xts^Axndm=EGZhq_b{UW2fx;@K^KRCF-Jg2hb zN4osJ*?>VLuChs~Q!`W81em1s%-?D{>?3Qb+mgY^0e}igHH?(Cmx{- z51Mk=evQ={e-#^FP#?zcbsZJPCWNlvzv{87LIS4{!cF4$g)+FVoQY}BeytJlQu+0% z30i6B{Ypp};SkZM%s(;FU#%Nk1O6{jOrE=N7xKO(3xS;Jxv)E(iK&$=2jzZ3Sh;P=rfk(+g8o+Wfo= z8-1oUso+OKnfI8oV!xnA_%j!Pak+uNpYHR`_!H`{l3OPVZm1l`?}~sX^hFyTZH__l z$F1cr4jaUpa>2Jif@B59;3bAKxlU1bGcnZLzb%Gvq0hWlhWm&8f9z?U9%nfe&)0`k zaaN-~#05u;?@kZSH`LP+=U%Y0L$BtlnT_B}P~~6fa6MR>RQ+kawFeTq5_Cm~cBh4# z{9=xJU=$DLUi@(klGd2eUS~<-P*+8TN#Gu6Q(Zmc* z+rE_L>EU+QyWN+f2U%BMU3v1EBuq+%^>E&Mxr5!5q;fohk}S?+@ugP#uxknTjnW_M z3q~Ax-Yl%O6%WgeVg|R)e_@)mr_hC^yGcfNB*4aOe{EMl`i9=cP7jv+a2Q=H0shuK zM!zO2b;F;h#jw>1qhp-iG4SP++H%gg;%N=JBDXCs^Y=h2=B=jcZ0oiojooc6_0Z#4 zC*O>y7iL{^0iI-Q#$}@mvXJ?T9KF&#mMFO>?1UD#h!_R(?AvRd_(H#)nYwe%iGzqW z*U?ZC(7tPNnM+R1AW3^eR=5jCwo{0x_N@WI&1DomM>_-bTxF7$*l)QQm}bp-yA$$? zRobNW6c8`>A`pPBftZoFwpI!1N7)|sF^?F%-`z}`%4fv;8U5p^MJ&h{AyJHy%MSL-IkLvqg^_u(zOPcf{&DAy2AT;wyx z0AB7ffBD_J+2^TAoj6}ot+akT{JBueqGfJrGX1OE{(3k;lR>A`8JIMcfeSXr2;mb{IM>Q@L}R{*XN-dOeNoS}jkkaZBDI|+r!_-UzSLmI*r zgj_w^_K~jH0RZ1rw^T@MGR9UfWt*HN(W;uf3;G zP#Z`=rbYO?3tF2bnyZ+Xn-eWOC*$HKvHY%0jKuGdj9PbXDFx)<5dRpFhm_35f;ZM1o9Zxk}my#KF4n>hVB9B;GbNQIUrStbXZ_ z96wJPEMuM+Q?;yk;y<$bC|JCQjZIk1xVzB+c3iO6a{HY3?o!B*ZR}nB4V7h{edCJk z?s(c4D+w}uu_}8Xxht;*>lYHDeLW{`sbwt)o{pqcSEdEcC^Gbo=t_QfxZ-LG{;KZL zQsfZ8z}}BNOcWvMeY@<0Flcv$tI^>lruiy<*Gx6*jRCAnRSXlx6Kl$yw8b; zCkl;=x3`}3O|cj*6Q7EV{_5FS&l6AOEFO?oq+zsaoEbpHjzwia?0oZqGDGZC9^m?a z{_n`2!p`%*c=ak{b;;Loxo5pADuopFXh!VfR^kPY&)#zQGGM<%+sX2h<=sWP;MU>+ zv2a-DP_t<<2iqCr(*@f_Pusf2+9v*a9;qHXiy%T&T-;h^=QH%KYbO4>7aB@c`~rKY zrS0w9oxM;>pkwpaSEL%9Eh*t(EeE^s(Z7&^VnlF13DzY3Zy-H?YXPfk$QKt2v~;4#Cl8bPD#;+=-|EwRQZwZjSPoQ!>m&0op9*6 zNQsh72?xm{{qO5HF=oh}o&xBQ=a*ZMQ?&;!V3Ok(n)uC>KD;RPGzmEHuJ*>bqVsFx zZ&L$4N5p|&B%@m#VI1ygTH&zL)`L3vtjF48f1Gs7ST;d_5`A^GN6v9A`*jVigG{+8 zg%e;inBzG+t}Pz6=);R~mL50hUt)bsnEeh8Zw3HtN9$+=BuB?)feZhE?fA{YPfjWU z2H?;l{R7sL3|g}6inGl`XD{5iB`Ltz2fhEiYwHUkFch^KZQ~BGqgO&pl20!-M5dENx@oJoe*m4?Xmh|3Q1*NIqgM1n!dQ#SO&S> zIz7#~&wPN`4`xuZ{|k`vwBjNByIt`uFR2fJEmSMbya>|1m%{PoC>(yWIGQ} zt=7E@p_>Nkw|^&u*@VfMiC*S5)iTEstqgV#aJgsq{Hk;uXS#GTw;}x>I?W4npBCoS zndGWY4efqf1p`Q}JmIo@%EiHICjSAr=B2_z~ON^tn6n=Hf`LpgfgSUZ2$_T9zZ^_RGEw zK(6W4HP796WZ_d&<41*8_=CPlWrs?{XbZI57uNC@2s_d{Sihdgb<7?=3<9qHju>$2 z+>YxzI|BM~c?_kJ*ziVNcGS{1O&NU|Oz0{0`zc;7c)VN-!JV{I$IZ%Z=iIH93&irCvt(NJ48SBY?jHWRdVhY!D8pgBp zD}{aEdJ5X<_6Lze3eqfmih(-NO zjx-U&ITyz;CYB5{f?w_QfdYjxp2f(y`1=FawO+OukYg&_y^?B-2kay=;``4U=IjI@ zPxSMYTH}kjZsw(>y+Ryw6U_UXEmW{dVM_RK{Rh<^Va)UG>MR3;0&GRS2UY-41wXe7hC82T04O5;3S^ZWJDM2@M zua_E-oB@vx8|6rTND&FUsEed5?u7FZ(}!OqdyKUDy3gJ(28+Eoq=d%=Xx@qZb>huh zyuenLkaA!6qOYcBtDMsC4EVE2*sn#M1g^qw7HqCS*^DzJ(CRjaAGr7%j8vU+U_g`f zsdA(D<1Oi3$yrMdW~F>(VEt$QZ~@Rx-E>Z4OKWv?8fG`@)&;{tiTVKp{3Uyubhg4X z!h5qg)gvRYwo#Y36kwC*H>+#@SVCuVjVAj9pko}HC@5$QtJctyC*SZR8?JfH5-qsW zz#0EU`G*plxP17FK7jPEp`n1ZZ3cGmS?{PMV$QEa^UyNd?LSL4d6?NS={=zs1B<22 zOHT+*Z1f|nq~=D$L4f{*35hf{N)oJfWIT)Z;PMu<_yq2>Ea}a2k2)!v^*Q~SWtJrc zSMdqz9ce3T2%e8LXH7^3w&$MBQC`rsi64tA(_uQ$|1r<6I!3%pmQgYkT%pgY(|eLG z77E=4xK-ZaUOMoqh`b@0`**?fVbe}#>sNy&+C=B+2MtNbiRsi9Z@t7yCp?4yWLimK*2pi|j?VoO6Q1^D-!#tj`h&|vA3#GgeCO3&>i{hR z#}Ixz1(rS~YC5CaD!ERIG~dO#LMeSglY?#zt!w)n#2ucNFIrhATgHAQknXjvSTE2a z=rl0kwQM}?lMw7}<G*b4p{5l`o7xFgpu?35iL;9>Y3F-9%^Ko~WEl-3^pU4* z^*`R2xq6BP>L$wRos20>Dv8bl<6aF5JO)D9zr%C1zZ<6Yfe^;y@);_;CTvD9@6mj= zh0zOji`3}JB6Xjzi91%`yVT(ybo4jOClE^1Kb_|;W+h&dJc2;k&;v5QFh`9>U)C}g4J`s zUx1{=irLx=x5UQyLMLqSw*URZxit|$Ux%7axX(a))-B@WyQu#Nxv+cHWSYoQ*3w_4 z%l!L}R`-pxe14ukn7AOq5lkh>zu`Qs3`;%eosJ-H@(JVpD3f8b3>ln$u>3OE-#@2s$ZHgCk6`$D9m)Um!SH9+OXN7E z<(_9y5`=0HViR(fYL_M#61XQ|fyKiXT9!jZz#$*#UITc`uQeJB2jAkw>zy?o-jXz* z)$RaYm*}jb!ngYi0I?Fv&kT1Yl!2E*)3@CIDW9*g);-%pl7^24L!RVCO^I45vM9(g zv&X|1uU))^p@O9bx`AoPxXQo93k_ zVXr7K_K1Qwu-U4MceWX}XA$fy%j3FJ$GD4sNZ;W+5vFO=D<6b9jwL&1}MP{Q$z9pty?sA3n%NkU;jnDUe#7KVg+s~AJErm?!ly(FVBWJ62n;sdrd-bk$pa$x*_yT-U zhp=+Rdv`-6hDJck5#$Izwf>8FqM6t_fTQKU$#=6RIQX4H4T0ka`Q#);2`E|+0`wk1 z&2ur)`C4}l#(g8jV$?9j05(*qqv`hLw{=x-&2S_oUKsd|(q12lYEiViE%f4=BbGV3 z@E-@Y7O=!Vt@F6!f8ziyKj9zCrk2YlE}c;X+DUFAO*9o>CN|SL`w8Wqm+LN( zj)eg|%DA-Q!LpCRMaF#s3$AxP+Iv3JkXd!LM(?w{a?*EQkDH&bAw9|68E@tGM`V~; z*tb3eLA?a>(m8bNSE-9H|aG?yu=59G8%8D4hD(J(*Q=lEqG{8E5_xQOrb zR94NH>{pYp9PaAGd?5?(InE6_>0+>JO9gO$o8behr7GS^72)mMKUN|z+Fvtpms~MN z2oWO}vb=0Yoz}%LFQx8o|E4kWafRz?p)sQY=d*UMt^7cw$;{hba=ySnY-{dpg1hbZ zC7XkTT%vSFQq$+v$y*G*kG&rOB5s@k38!7E(K!*fqj#1&#OI)JM<)-w73x>TuuKy| zI2@K>i(6a|p~>!=rlkucbLh&TErB8Ub5>{17ygwe0dvf&y*wJ93M`^tfC^J;p+w6r z^?87!Bd+kdcGk8w-_I>;Z{WhUbbimx{{i~Ne&;Gh5gA>TNG%f?3C-hOS`c&sLfE$` z=x93hpodEyldTai;D4Jz?t`c*F_qB>jOzq5u;7ttw(He|SgQoXM#jMwXq!(~q{iy+ zqI5+2`emdb_Re}57h7vGz*=g))ReEjyVUdRB0wqY2jnYBb>ghi-9cpcAYklZ#7)fz zUAu1Dkxm52X92xDW#QIm6Mpg|KbQvssCfa2UruLqR`xho631+ghl zsooS9yKwP?-xnw2XYxu!gO~~58ZkXlSz6sg`k(wC^?^1zlXFuL%jAu%l1wGqNqSkc zxuu!;F3p`hgN+{|TtPq*n_x85J~QurjGr?_K^;Qvxwi6I%P7?YW3|+MV2wJ32~Ffq zA9GGN(B52|glG2MLfCrL$j>um()676->uKG1>*b(U0oybbQagihS$*l0T5*&tiX z*CuhfV;T+ts?S!4x52M1)u9C4giriHqr#U4Fch< zu44HD>Cg1lF~mEk`&0<{e*lR8l|LpAe3YF?83&IS6&uI+2_d@I&awFgv!F5COa&yh zX95ENm;&QbSyp}V{-2ij$U|asq?bARD4uN^9o^Vbvy_czTR1GUeoVdunDi@{uCKZ+32x9%++^vE_4v%yjKXlhfJCH z^(7b3=3Mbj7#fnFA;hM=ddIeb1zr|jy4KxaDJ{0wzjRN6Of*mr`?{_We5Oi4%ZO7V z7fbDe6M54*74|D1{5x-fPrwV-nAdFjuQclOU7ntlH4z0L8w!t94Uq=~bVv5fn)AOQ zE{@Zrui!4Qa_$}>831mEU)Uh}Ew1lwj1n@_Fr}bNIiiih#~yCPA9LD|fEl}#2xS-S zG(cS3y5(*(Z<50C@}mR{sgEFEr4JqN>aj*AJgU71=GS`To0K$DV6-GGg%BJ6Z6Si@ zpRpSe0bl@!+*zzaulEnCeB^~Lcsm|tRuwI}$3{10nhV&GKi~ND-Ukp-&=5K{TAl~`7s4u`(q+jmFj8@g-CYws!Z5S8tX`lix zW3kq7GFlL2S=W9{+iPks#WTU7V%HI|ewtj(Y$b+*yWW5wK2Y0Sdsj%1a6~Cv6T0oK z&ry3XB(5fv?c=qI?%-KuG1NH2YIB}0SXwt9Xua-3oNS*r&0fbIh>B}Sw4F{a;p5FB zM$*XC2o}nHG?}uxE6bBB_)I#lI9J#%p!~sV>i-`Jnv~JdICrZD!^2lD$MGLBM*}S% zgSrKayn*z@p;_!w01SanJi)+>xAd4R#AQ-+~kaBFr7S=D@k@P}(Vto@FoYz~R6_X$QqLr_VCW zGR!zu;UkX!0f^cOIySq@r(icoXLWDVymdKs)sI&(ed`nH7J}>Ba`jvB4284*2cS*h z&@>w~V#Rjk)znd2)wt(UN%n7 zPz{Z2VDcKsPe1|d0C<1O&&aR8k50n8-&KfbD~KydB*+J?<(g1)4<@W6<~Kut*Lp5k zT@V+Zguj~M=hP-Ot!61tI4_m{w~oelZ+YN3->E)pZr4lWxb>(!zV42U=7o`4LSrih z8vG?+au*}z7FGXWA_PGwspgNoyQ+>xvS{9U54bZGA%{JDwZ1{b+4hL~tM%NriI1`} zdwF@$37tf6+2c;rWZ5fuw%G~F4k%H7>^M;QD^yi^+GS|KHfM)wnH!(;MRdJ}3x*yR zJpKnP^zW1VLABakJO#fzC(rYc1uRto_#WGkCvKe5G?6L!mb$=wM$!7gZ}@kI%_(vw zWy#>mxb?dV@9moh-JC`1P!0V9ym$`G%#J*cclBTLWjCdqpGJd0m@gvZBCdC=B6-aI z>;E6XDKxP^?!|3s^Rt)Fy?gPoYu_^^1D%$zgCCYZV#^B@iC0NHPN|LjJ6fV#6{`Je zl^hQUzIK33{ugo5$BtMpK;1}54yK*(u-2dY`U&(ufL&JMJ=){nzq9l~C+5fnKYfnR z3O!KRdgUUk+;Byi5er!~K?m^-C%Ug?_9}N(DKuARjt)<_N~SlIIM;<$-@bGrUE65V z6+ngqen<#_1sH1&Z~ti$H^L|kVU6CS9Uc}$tMi<}dZ<{;sc1DOM9VSy_W>Qra&2J6 z(@-}hvfwSiE2XuFK9$n($Xd?Stoz{zHGofuyqT3ZM>6oDX8mv&yF?H9+xXopm;B9PJ=+WoA zZ*~Xyky=-DS?&HqihM8<7z%&_z0k}*qbnYNfVZ{d{Q@Jeo;Sj0X}-1R9!4u`$Ewl| z9!@SMl~b6z*jj~MGNW%0sS|i{LcQy{kC2e+k{&rjOvV95#S{FFe;}zNxij+H=hHZa zEr@5WwLN*Vja0-t5$}zjca|%WHzqXGfSr;ysg|zS;D-%4#o<#IlUO8Qn`v%&_Hn|( zAH6z!{0UL`p=D%l88z@AU15W_7^MWMrInr&e3($r<->h`TDwa+w5`4AbNW-w^?}ou z*Z?cYIAF5oTRqZZQQCeaXjau>=`^$bvylD%AQ`}I&Hu7uL}AUoiYF__PX@`{nOO4w zAAsdm1z(b$v7nXfJg3=YE7^TG4(Z1h!hKu0UJD%Zz{aY~$HLPj@6)G=YziBDZ+k;N zKF}aX;lV?b-2|VerMwsYs)qMo^SC1(712oNB{1q6>qTmo>7vZKQnK+KE&NvZgtU|% zG(Q^r%@BCi@Me|;XKErUu8g`Qw4Pi7j~^KP7;6kDxmP|YfQ`+W+=?IlPF)uN+uvwI zCoQSpN2KVstwKa_RWn>F?dS@H?}=6Iz*cVI%hJ{pdO4d10&sqrbnaA--4eIMR6eUa z+eI@Z@#K4i&*(ilTcvLx9-;3;3+)*mbq5fQ&Z9ZkDE%iYXW}@Rv4;NyLQ{LhGf-y0 zro~jlS8Yrg})b$)&9Q&$eN|*ZprGP4V&3@jk zE$fB2uR6BS#FJ2R&y;{)ejKtZs4(-E5l9_2{&n`4FCB~#*v2h3VbILN-mACcg#L)) zd=CQjhb{FO#eW`7ackvT@-4PPQ!6+$0Me0S9;u%{{5)y>T)L)JH1l0>`Y3-+rgVi?f!Jqdl;Zof~(a6X7lOJJ~S5lPAbmh z+E_*y^abT}wom8ZMhJjkY?+ng^ALj>^-IAsrc+=o;}+Nh99Yo?(*y8x(Gu!86>O4<7APDrMhOJ^3&WV@FV?y!c;(0bxW8yXqOz>lv>mlMRJvJ3lQ6* z^J4^`sJw;8YwKA6boHHeqzCiOXHiusrIdiz5t(yIkybuqI}qs2<&xc$^OMH9F!Ap( z3aKI-I(rC;#}*c$^@tlw)O#!w(-|)c5k8aqJfwV!KTPm+eo}``L8o6Dw~Z9WI<-&v z?AF0C<;ga`Jm7csT5Grx50!F7>+y!$amL`eiGMym775i8ZL3-uD5)quRgKr(@;K=bCd1}wNMILFzpXKbQ+wR zR;{wplPEvoNPSqMq{wtj8R=i@xPT_8$L7cYk@DW@MHP)*!QN6;GgS1>P>t4k zwSAKu!laU`RWn?O!@?TI5vh@j6tZm{R36X089~33>{iMW){fTedQ~X?t6cOevhDgq zq}GeoZWt;3pRjE(U3Qxw9d4&u740Pu=|(gY`cgcT-V+NHljQK5DB?(N|4ZcWYSo}| z)c06VPUhLcqG16#k)JtaL+m!DneJEhG( zc<)t&>=C+)SJyW{l{;*k!X-#?m=wrf;923o)dHj946Fr7V)KHLv#Rt>B&8ON31M0^ zUz5vo*K@L$8UI>+Y91lY-|u7uD_c^*?|0r*JNbIZ?L!FrXkg?mJFU{JVL8x_+e$_c z*@sT0qW<`*V(hQ+CwJpKwND)AU4>UY61{O+e$q_ImHn1_Hm~?0_Y9P50CpzF7VLw# z4Ctfh2?LzvDMGPkFgt=|m)uu6!01C}@f|Wd1)@~63~fP%_v^Xla|b!kNMLMpMrke= z&LNzCTyMZ>|C{N2r%}G}N``2uIeXkYo=67Z$fkqGBBIwhD}p4{7j$w|-&urWNRZ8h z@#0awt@E=jL8+$(ozg>YWPkcwOCsQyg7g}x$yT2PL)nV{qMweuXgisvmTzeB$%I|2 zFyT|U7qZAav)oG%rs$~Tk@0d}CadGVk*{QIUa^w+J;F=e*|xAb1AVyk95z6JT9f)l z@SPAljn|?s8Dsc%?8JC1ym#{1HxpV{KYh#^TO;t0b2`g`eZ3>Q2u5=#%vLukYE!T; z90D^&CteMkW?vyz%WC{eL}GSnUGaQe5*zS^)D*^`W|rbrhyAm(Gfo%ezkFd2&!`#H z|8z;da1B@pWTn{&V#~Ku5Sf#_Sh>15t!JLuSwj9#X8_PeQaI1TK;oDtEwykhwWO;< zOe2rW)`cH8LBN%q+~-eJ9Ejs$Nde9YFE%AaD4H|**4^HWFhUNjQ_25G>@K%?ugc-l z9?LR9XXpfztLe>#`0r)d%gZF-lxxPa(PELR)Fb&cGG7TIk@5}k{j=6w(&tXMC=D7G zk#d1=F6qICEnXqtJFIfTU4|f_BW*I|=;4I}_oI^oT$mA$e900y<24iSq+oS2eKM)C zE0{}nd>l80HX^F*5Xd0?xwMQ?cQO(4Tk}TD_vwJBy5^MlTQ*b)1R#Ed8_jfz;X(-$8KNSr0CVT6H6}1dIJp zn|<{hSz5GL?jnrGgj;D`*FJ7YZ#@#I^n&Vf@!~gB-EIa=M<;jXtaRWaOafC21%S=P zb9XW??^{gyz6M-NkcgqxWn)C6nDQD-QnEw&S;)`ZKKW~EjMXkq5ssOcA;+r5205^54 zm^XgH{Kgqa9;5P{r~ER>A&H2DO{k5Nz8lq!%s{U@a8$o?XL}hW-X~|^DseI)A|#Wc zk^BLMf3-jIUWmqXPBkIUk)n6fw9FxpS#NlD&ds2^se(`5#e`PJ?`Wr( z9zjC$+4ago&VU{fwu1+zOwcr2_L(!*h_glLoNwXFP3HO6vuDf(txDY{!*OInEJ9qW zd@gsROm!?&!*Sz&$}Hbx2KjOj6UmeltjZ1_3<`r>{BZfNTbK5?PBIX=eqptt_ug!_E`;K{>RL3tpt@NIXb$_Wgt4O79OO;mPj! zQ4gj)aAT+`9;%=~W#GC4UFYwQ;hcKMO6Rd3Gk60Ll{6pDwgj8jv=G|wZioqL+q3Ke zbTB6;Wde?xeQrczoNuf`s<@gqSn#ejwf=ns39@#85dR@_1^U?NYD|@i#8y1kYW|7P zY>qQnb6}h6U9Cs}Nh;XMQ?2Ul4GKkU6)jCJ%#s&Iv~&kimyhGc%TB-MK8z~g`n|ml zx6rShVk<*}&n(lrk(~N>#n%F#BL%K31)>}pJuM8dynZKVXzrA626B{zzG=J{u z+`IBv2@*_`!T8JnF|KM+TubGg+V!V3i%gO0zzs_HABmEhM+M?9O*q>}1s5WAGSlyJ zt&@>DMtl_^t?J4;^WJlso#+LHNi(#Sukfm|0M;qtMBR5KU{>Z?!Xe}OlTLaYpZ1=) zsP~WzThgI$edCSi^|G0Hw$Rm=6@~M&k!oufo3KLFjy7sgOMrD4Iuz{Wrxw0`H1Mv? zdSPha#mf`@>fug?%W7g$(D*BcxKZDd%vGQ8Hwv9EYi+X=6^LQioJpWY$Q9Tp6MVGx zVqW?i9N+ygVdVZQIcX`&8jIG59)|Lhd%X z@iukxw%+MvHl}<&A?hynl>yc$5_SFNNHa+Da}?lvilG?;_N8da(e31~yWV_Fo~WTY z4AaD(777w!_O~9V!(|kD2^Wz%axrqCNwDmnY%fnKXLcuF!;_%7tI@EP{kRm9g!i2M z>nZE>TQMrG!DoDsXXBn7f<#uOsi-lZ2FKKy1R-noyl3+<$I}0)SPxx!1AT$i_h&EXEj0-Q*U8pSrW2*%hP@x%{{_iQXaD8AlVBKO+ac z+L&wnWY2!-xFUM^t*PJg671jTt{MMi%u?^~6*?BZ~`(N;n zIgjX*fA5{RCFF?puwsX-ssp;P6m@rS9g+Bz4<(@tp$ z?V*tqrqB{?|AylTlux9}{n| za3&D0no{CclOC|g)NtjA^8)h9v%&*^v;-2<98d(1Xcg5ftnD8umZei zL3!)HAh@>n8|S#&0Z_;FewC?^gG4nRBpE9MvUEI_GDrX}y>BqZ5;g>Y3oKOHwp}3#pF~ zzwGp~q_}KDNvY(TlWxpZPXo6GV2Rd`xoxcJYj8moRbRO@V7A}8RF2EA|KwXWp^tZ46NQp!2DiUh7gmRIohUcVSh z97-UAH_Nhloss$7H}=WCwewab)mKjU}UOvbLlkvPwGh5#`X@+(`AFZ41IDJyOP z*s7t=N`YYLn|3b!X%ouSYxI!kP~x!w*ZKLy7*cP3{>n?fYJr_kBU%VA0Wu zzx8K2rpNL>{&RY@g%q|o6H}yq*Ddu7cMHDgaor+7nsUy*+I$YPb090`Y==!mMf(To zcn!Cg7Q~LGjI{2@3E5^8Ev7=w12WVvM5=;NPm=rYC30+?gOZ90B`DR8maE??6F$=6 zZCM1BPs0kqi1#%@K$$+QFl87+s7`@?3qbHUaN<$eip3Q6`wDS5FD9&xp$Iyq7RWu3 zBdt=}!xWVRuB{K};g_pgMyOxoY`T6!HT41zW46+?_Xy2CpJc!4*PPo-9)Sk*!}|x~ zgybd;kNQwE*aA-$O0kM(!Q93Qu4N~YhQwFo_EaUw*|DWZEP`KFkZk>K>0P#PK4_o> z!YQCgoO)Bh%r&wc%RB)mnE%jGwNt+I-LSP8~yWkbq4q4B|v!K=DSD81 z)6lr`KLGHLH`TpvN}k{J5R9?rXfi@d0~n_+&-uVB=V{U($cfu(oFgaNyACh@UsG=$ z4`uhqjSmJh8DgY0`qau=gyiR??(P?5@5 zvX+LBME7s*@9%lNp6C2^Ue{T!bFS-iea`zV*ZU2x`*ZaQ9}f%Xr?1sTKZpfC-Jyuc zGYu!%#9!<9+~3g#@hf-MUhPZ?G5XhAIaNK`Ee+}E2_Dv+O#dkW<3T<|7`{SO-3kT? zeTWEq>rVLeO_FjwkTDOy#(PV zed6Yxp>&Y{KyAZvOfHAUiMIJbKZni&&9m1vZ(P&Mk8c{L=+f{-?=_zkXm+5MP0GYVKR7$AV+MO^@FKrO$90zca=WN+Qs$Cm&7YEZYeZT7vpY+qjV3Kk3b%ErT7sc02msH~ z9W}P?v*%P@E`ECOHsBT9_}r`|O3&SycMDcq6d1-X_mn+BwBn3Vn~CNW!WblXpQMz! zaZxK_Z-bYmPEJnPm~u?a!}dZJrLH^2sYM5rAtKx~R7!;SQKmPqnoM2tEMJkS=>PQc z6pkxPF0JiN>zVFhzzcP^TrED3!dtaDNNr8WUiXM`I$Vs3ILq?7Luy|ZzmuHB!G9vD z_UOA5+erngG0x(y-=~b)Ha0}pijTao3D&It8-J0EwnwU(kE6`idwF(a zu4Yb9rmTF$-w}!aEOX-83tGg)3$~N0xX49;Ph)i4oN?qCNPxh-V1~=5ou)#r6DZq%9zJD&* zx#(PaT>r=^HMme~x%bEy>I4aft!Vp@QS4(mdb&Q#H_GX^=_Azl5G&3q(rp|^E35{k zKkg*UO~EbkZs?$W;>o}#wGI!HOC% zBs9GFpKD!L%pJm+w)-~X6HtnVpk#O{Z--cFY=fj$+i15wuZVdHNjo^PS78JNeWV;I z#c+PxbMWSHGIwF8n{aCG8FXGmy*3$;U=pbS_>2qc9zAIEK4rVrR>K8PpJ4Tbq4WxX zz}8&ok7&0;zSt(+kRt6b-j9DN>aPgqdOseytI)VpDy~hHO&l<*r+ps*v4Iy-zBeyK zp7Dm2my(FcRWr5$qxi=}rOMWVnt+G@FmO`z(w9>)`4!1=bRuBPBuBSs*iVpWFj9@x zT&w5+P;4ELtP+*^$?!B?#de9CcZN0K9|Sy%4t%SJVUkD6gfFY~RGau`?TM*aMg+Ek z5^NV`Ig>eDDt-hYg^Cb356_#4HN!V7R7WrJ|4vcaLavuq0!ui`3uS9K>+c$;N_yQo z!=7TDO7Ani7B4tv#=G7l?nctP1rxxQ=1fd=dBDTx1ILI~H{o=ZRN1QOk!&renBm^W z=enk_&QvQs-=wc*5o|c`ouQ!YHIC8cPW1;b;#rs7w-(=g5t*aH?=6V8`O8hV_IuXo_vEM;`P27pYb)PwOia|0#Z@5wD1C>CCqk zu2}atOpwv0m@Y{;8g>b^WE%n?##K4}&dy7pedLzNB4_wH3s>ap+3h4#=2l8+E+3MV71H}!mQ_}Aedt&cD8(8>Mb@%Ha4nE%M7{W+y-F9gzH3=8yJ$H4#W?tZ(iv!?YTDD*fOp74Z#UOHT9;1D@VHBh!$_h+_1R$ zSIBqy`}264zsR%RWminD#urng0^+s+Gk_z;a~97MAA9>J`)+OunWZ4|nsPz0#Jy39 zHJYqOq4k!gUyXK`!CD){2@sg{|Ac^vGm_CM@8w*x(t&&2eVY_QfzM$sXzZ)f|F7xsML1d+NM@;$@LiP!4ol(EE@`vUd2kp{U|RZwki&yP$JIIE!isz7n!vc ze^caKwVyxu>WkR-73cMketlx>G@tX8wuU zbMDo-!~uXxf$=t0%ekj{h&Ax?PBrcIif)D9eC7P=%D1%7&~v%g0)MD&LR z3~l0nmX-3WoXLJLSV8px@Kk&+?exE+XB{_~UA!)e*A)1{O_()Nu?p<14S`n9eh3CG zOL=i|R*qa3t9tA0_jZ-S8ObuJ)qn^_8#*TK#dQS$~bq7Z9=SBpq%AcFCLBL27=)SDiYVML=tTIwU zeM@TbrThmxhGL0bkqs0oUw*HDAF8Pa-EE)klf$S;wn+HcEg(N&Q_oQ(xp6Ar^O!#2Vk z-|NcRrg|9lVoF9pA@OWj(!h|~%Q(T(?XX0= zVHwb>r#+)KUy|(iaHSIr7RYkUwdHiMy$}LRpPqw7OQ$<!bnA6Cx#hz<*IrBx>w|1S^Fz3B>B>SANLboa6oC<#BPeV2hhBlkRk1 zuI!Ry-3aR&Zd*m(z(Mrc&8r6uhOwZ-{wB$9@?3s&G)RqN#2T>{cZ}w0{-|M)I!pNC zOKuvN*VirxT1)APLpwfY%>@U!gYL16A?4`BrmQ+mCM6mEolRBYJQ71&aphTRv%h>L zeDaYSdC%i}PV_0x@paW7^XtBR9`A{IXQZ3~VwIXC^0I@IIJuHX6q2{}4^L3fC3?KH z77^gu6hlh;C)hn9oTgy%5NoJ%qQvTfsZ`x9{M^GjnywyALnYsm?|ef=fNb37wC&K6 zincL0t1`B4>{IYC9Mm3e*xQF?4Hj~1f(7V0oteAQPB~PbRf$%~5t$I_a06@9a(+(? zjvsLU7r@4IUVzms+W+-eIAKXws>X3$z^42`pxZUh=N$~ttPyF0-84tK!t*?&=UN&M=s( za3fIBIZq1uV?yI&TngjZ>?h&T}SogB95Kw%M-@keyn%R~){tKP1%` zuVPQQ@9wLz7?-u2XUft0?8f+_Evr(-KnK1bwy@E#eo8%t!f&V(Ye{Y)B-Q#2hFvq6 zoSd-;169|>H*2d!=6Y75-X556K2*uqO2du@wtvob^l^*wijc>!aXCG2d`Eq_!Fzs~ z9W}_&8$PGz3kv}9O+ggy;R@Umhf^}LqI{fF_v3mXGKo^R1iEU0vngf8_$H zny_;oS|vV}>_qXmS!FZ>aEPr7PfzwHc^_-- zvW}pd#(8riplp!2#hqLi#a2)DQfDwvR}s0i49nss4{*O9=B4TEXmy?q)Do5YxEOfaAEw4zX7>NAUr#V#PLOQ8p*h{VqA5UguVbccNh4#fC9O&nJq`rzZ)@m#;aFe)ETI86- z;m1~8j!XW5kixe}u}=b*E3q2uuT1TuLRUWOiBW9JH%gzoTh!{72|eD9A`B+9zG%Mru347tHz^M@)lts)MnIZ8Ze!q48 zaU?8nCSccuDY$n_P$|NyQKI$GK*AGq>)K7>#pT4t`cdm|0-m|Qq>uW3Qbx3eR0Lu~ zJ9aIJie;yISMbm%{qy?)O=}LVf9@k+iBRpR8;gxlYWZa($8P(S@P z(&^GKnQ!cN1Jgae5~pYaKd-1xizQVq!nTxxY}F+e+ty>$k`VW^T%5OiUAl(5_aJUz zni(}e&MP}1WN9YyIvFwrl4njkd0+LvkkKl0uShb@hZiVM>e9UuxejDeEFXmsZkn=$}A{!6nken|YOo zq+CBa@MW9fG~VR*8blur`6Barm`8NeIUL=!xdJDcUhql)BXhoFg=B&L1SRh!Epa z&*Zc!Spfd{=8jl$G)z1EBf$!McR`P0%tC$?EC_`Qf`&liR#{zvRRk6zF4amMHA1BX zWJC;sGuNw#;tlrre(wtWXmzwjde@BIemN&G8jSGYhghZm3U*vLdSwBDu@ ze#FficXtAEe$(+9(q&MWl$Zm)GaYy5?gD&9n*y2`^VfXGDcM;uEDd7n#DFaR=lSW} zT?*$4A8F|JR-kKwJ()iNCKO@lgHvBVSQ|<26}%+j*h7bSIJw;-9jc7_KD@tHo*E@< z2+^tnCcN?u;FO)b6_nuDqT`tVh?C~cli*#+xWpQZMNR5}%-yOh6% z-G!ZiYf#$v8Hd@bFo^~f*O!WW+8+t+I!}LJWua~wE>nwwedQ8*V)b*0cF=_SPZZ%`E#aj zSw45JJ{%+qMG;)c*nW|hxd)E(*dQNDyUEHTohdzi#?ADs-+fgdut8Up?0P(A?L75nx)4no%0eA zvS3+S238+3DncF@>6XIr!;l$?)7($39rL#ScLX88T@Ru>tlH!$Zkjh_zGUszp9X`L z4;hi`zjIs;b93b5K+7p`788YB3LeBljuSlIbA8GBqtc{$?dlOy1;*Kxdb+9a!)37B z{20vqY2E7=2}7COxkkG5d<91H=S-alnfHi5S}K9hRQ~iikr#0nwCw2m4?)| zFrG&{&&bhhDX3k7+5kZz+I^9XL;Zo~po+9s9r?Xr+Us$t`&%eExv#|YJ^W0$qZZC| z1Pfu;hzH5f|E1xRwP2@r`6lm_i}gP>hT#RgoR;q|NR$u!+CX1-pEIftENZiKa>ID3 zIfuB(6h%Ik5D>f5O=LN&y(bmMzMtB5ePeC^I@nx`O@)>djf@<2mI&&<4tIFl#cF5@ zapLeh-!>FyXDx%En=}+!*OTY;)flWc9EZOoEyv;`@2Mbrkq&11?#d^D*0r1;as{s# z?>ySiJ80m{IKI1bC}Kf@b1s&0ur749>Z6fmEU%hSjKR2B$>^+a;htW9njL7WP;@LO zMjx%DArK*gd+mxyh!#|km|%Sh>fUDMNQ@6~h6M(1ta};$2t!MmSQ5`ZJ+Ke)8mocb zpnhraU=cO>goTD$&P}octTRyYmt}2#@B}n`T0Zq+3}JRJ^Pe)4VB|B$x0D4p8Mt?s z*oeA~sjJ8t;BLhMm%Z|BbzFMb-h;@xe*ppFaimKEBZE(s<0I|Zxdh{cki3nzs_v)V z-cktW*i+{NWSKy1Skcc`t$h==q8h1bT&r6g2!sis0Dt|x_{-eR@A|+mfWi;gpo>sW za$}RC((B}2nnS5-VdY|o586n>UntcHHOiFTXgn+zY544&yNQ{Li#b~PA-bw7t3E-df7DzM zriK~~Txx<)lpF4$4{wClW4BnTNIDA zuy^Z_lL$%v1J;;Y0!OdVu}4O^Xzvcl5!R-&p~EJLbJ6oi5{WrG^rn+-=r>s9)KI^> z$3{I20D`gq*=Z2=JVF%z3uwQ&2@&r8%}4j)5<$CVOGXQ*r~nh)wJhiin*>ElEDJfm zS!5yMgup@@7<^;4g#o;=BwUO6$eimeKSQ;L5AZd7N-anSBPS%^C$_Y*c-(yNB9WA7 zH*&Gm2$=C$>8d4OCZ*|auop-&)xzvj5tZk*6w7!(VhM~Ji!K+uqk^dFldzH&U5^6W z2kT;(GGFB)uW?9m%aZi?LQApdQHrPHOh9_CgnUR+&yZblcO*fZ+PvJlN~3Yz-Rt~|)W$4ES4QiFRMnvZ{>WwWi^iS|-s2{3W@QTiu``M!((%z4c8 z2qazk-D3T;t`k=j__KLLEbK+|+k|0MqW);7hIn7A&(E&F0(vZ5!Gk^5QJNh5A}Q(T zRw>$Zn2+x^{Wi2;YB-6hGYz2}Mh86CZkxw$w0gc<4e`FDn7fQ|S=3Mvv~mE!LCAQ) z#`Ps9n1AQzY@@Y*;@*LEWFm2gnkD$y$t;cqtGCMnIwq4kaN(F&g$g_r>fWhDt?dq^ z-0_^s9dv%^tk%*wbmyvf>Iz&vg*Wab{u{NZhz725o3jbZFCNO{fD{ZPA0U+L`S}S4 z@AC4FMwr6lqGc@HUDpIH5rp(oRsc@SK5>TSPoUx1cbt&A&8vUhGJcNObiEvRfFEL# zsJZiWwI1KNoRpP0PY%5BHL%RDfFTVD0p9?(o!6CTUU<6?UF}i!^c>gFw?2%8FB(vn zEusS-B`9S7Ji|zu()r1fe;r_IXUzh%bveHU^RX_LE}?|W@Xc<>MD!BDtm)s=_qEUM zV6T3^ztN%s5s_BM+MC|F$UF$cns5NJN<3F(amLoi73O7`d|xkt1nz$y8RALLj5J|e z9c<+|)ZA8V*_&4lN&};oPgJ0C{shMoI zn0f$hB!n{baw57DOx`I~Q~bSVAo^wQuITFgEn{t=MGee~&p?aAyb8!no2rCMbgKy$ z5(Wu*evk>hqXO{g?o;P#&rUAG<6Bj%J(~@*^BeqB1>MTk-B;v<%~(_qXruSCY7!}i zJQ==*)|gqgx4AEKU%W@^p*+zqNuMVchkJ) z=p=@=zCHcivRRtLPe23nbyC6&PhP%ze;p*)DuNLoY+Sz1KJVb@?j0@Q;M~yaPKSGC zlHGj1Kjt&-8A((K_&tD}8yFaReM5mZ`c37~MhIfny4*x>`#nz$?_Sv{wJg)77b)zT zKgiZQWv-LWy4eUwy(QEtp<~Q0T{D#O)KIN0N>ahC$ZJq+sQs+^GH-=Mu!L|hRee=W z+r@{F962v#mVP6C;~K}F=OC{{;eB$5jfsCvecB^nw;HhLt=ck0L?CPqCYoq_e}Y8b zxwkv^Egw(8gk*u@O7ndKHnPIeHWa4S0vg6yn@{Dd{Lv#AN%UCYvCDh0fzPVFLpv*D zObBN^lG-1}rUI}j5-O7m=)lT+i_!M&z5?+=XFn16Q=Pu<<>{gC%hvu$PPz;TX zMBn>nD^$LfzmRkr-QZoS{EsoB^KVZh^5z;B-#Bl(sN?FHxr1%E7H})2GI%wJ5*mp_ z=JUZuStkcL^5Azgv}l{=savqo^_w?OD6Y4@=05H@ortwH;awTikb_#L40#*7stD*b z@QV?rE_;fO8;;%!OnpdvuTMTz#m3Y{n#Q#32`xx8&Z?3l##wL%&=Cc+UDXQ%iMLjgGaGSXbMAs~xmq7w?7#doqR zbu_J!8xt{}ocG@V|7kA;)1)&IhoU=K1ko26`OQ;k>;z{93ak_(w8A%t@flq1`#050Fy#!f|0#9*B4dWYCLB4>9nj@MO}|g0+;^ zfAw^Sii$*Ur$}$(VJgta(d?c2FjWh<8yeta2v4d4zV?bDu~c*<5TCreF8ei`F3S)Q z7rA*mQIR3&K7VPzJnKi?HRCn+c`neMDfpC4GXW_y+_M7IUVL(sjSEgPFm* z#=~kc4c03IZM=0PdE4a4oj;?{*P%S1GbH_bpT@h_}tXPLu>*u>y&8W7WFC(&_Wrkhf5TXle?NH>cY3=QLHAjk-cN&~UcvY^pO zFR!EtDWSy)p27H?XDb@NG2SVQ3k!5Hwt%J`k7((h4_(VqnDcDz2&_h5=*8S(pA(`; z@e9D-N5DN5ojy&j2<~rbI7G?81$)B4i(C3+Y0;I%jo}&ewOLU66klmyaz>n%DI7DMRX~XRp#Mu=m1I9W$Fv`B63D>A= zUzFPM!4Rz-A}lbT8jXjmSw=Vg=S%q&85Ffccq*!C#X0V!w$I$6JMZHkcbuCSm{cZ~ zUx(Ydnfq`>*Ez|5WEUx4A9|NUIWW7L7`UYfy-bMv5qZ~g?xw05G^6d0M7s6yFq_xK z_-@Yx2R>ga+ZXe#IkB?(5YXD4QwSO1*0Uv~Z@vZzC_Yg&!yHTLT3-)1C+0 zSMz(gt27yvzlszo-kwwcQk@l}8V8FI#{QXm+T_raY`N6PurXoTotnpE**>zLyvhT? z>xwWO5t!TvbSzL(b%k^Y$5Y|r_nBCIk>OZET2n|Jz%Edf@0t$BH!^i~lZao5LU3&M zTKoubPGLlW;X>VSMkVE{HbQ(8x@i+S^UDs`A-LaDUrDzYn{JQp9(t3WGp;FUE1V8i zve^hGADMg3<_KVGaOuU_9NewcwJGP`ddm5CL^?ixPlzr5u9=vFwz6#;Fw!|VtETHg z-D^Z@fQb%YvDcZ~0nNd@S4HzfwC=847)wnT%pbXPRX`L#8jVweXM<5XN&EfO$%{hrEm4JVoq0%??bE9cEKq-i^1cCoYaPpWyx zy96#UQ*<158#N-4HP|gdnBa`dmY9E(GtqY~beFoQ(4bg=Z(7KMTGLG3Wa3gp6ZtF7KG2qMW>@4MXKyu*omv8150~aP5 z&_^CDp9SxF{E^=Dx~n^vdK)h;$SUnH=F71r!x6Q7u2Nupx7#WGi^X>eN#T7!`w@f# zMW&GEL?P#NrErlb@jZOM^r|8EH>G-3=mt|{8ICV$z5;sZz+=}yhoNy!%IYS zXux3}Xf9ehdQ4*kR1_VYtvKXc{uxu#U0oWE(TU-((KD|4@eEY}cq7XAUhCAmD-izW zkb7r`F% zx+XrQ+IA|ZhDpP_Q%h)1)1WW6W>xlS3LVQgfN@sea~h^1hJl$=Jd%4kVNuHxnO%2y z83t(d9W^f$-$LS2jCs%yHuxLKa}hDyP&VfgB0=6bJ0XSoExRjnN44SC@?B^rT0xJ3 zK{R-g?yEpjWCy(T*}B;u)u+fJzZlW1d-YlQpGVWaH-6W3* z^An>28cMgFyUSg&&t4$paj46)lZ}xc3d#LiMJ(W>-w_vLLCO%^o80~^OC$%#oXKw* zsp?*IPhq|!8OLZIi-3QcClUrkWPDiO>!8gHAKavip#SXyoZ|(s0a#gCfUK;nY|JP# zu<)|NBvjboNL524TfU2uZv1xcK#$;mKLS83tSl@BfG|}Zb)5*l!kt!X9+NR$r28*8 zbCKkELh?XK@7>C~5)o;6{qe=^W@*SgF5EBU(gL5j^1v z&Z{H2V^oi3MwOJjo+vJ0s)dq1W%pevv@NRSHvdTh{J{7_yN9i(J)w~>+aR2j;Fke@ zWf@H>AnXi{4CZ3&B$6mJWpEE^ufvXP>0hw8?VkBth(33W-Kl=kf(?3w)Vip&YA!7Z zu03x?+VH4)XgfGGNgG6YFLkc_EiF%BO$2~My-6CMP0-CyNARPu3>Z;@GUd?&!x53- zfsD6YmEo_0<)?W$NgH}n{k+fOBZPk&45}Ll?kNbvWfnOyqfLHrBqytC$;Lbhs+K2A zDQa%QWBg;i-*Pn+B2RP&m+HzXz36P(}TpET=TNum^%Rt1NSQwrz)ODrlno_w5Rr#dK|&kpKXv-*3-XekOb}LOuyg} z-gd9fF6X+->LhJAU9@b)RiWTm=wASqVX*#JK$-JzdUxt8t@Pf^J!P?T49rDdZFLME zdM86&CNlHlrnk4ZNBGU~OPzUpXD=zrZoJ9&zHeTkB@@LfmOW*q`HqA9%CEqkqx>bu z^CE2c)ufq|ye5?~`ly=YlRCQx4}Sfxu1s*%;rXh?8)YI#ZFXCqLOt{?)d*^k_x>ji z-U&VqM$2#bEp0NCC)+yq+J1dPYM<|ge1Y_yFI*?eI*akgNGTwuohS3lG{;Z0upurs zDValzA!hPM$pmop*t07`u+SsC_B19FN9W=I;iy zJuCrlkLM~q?g{DGJP(?DvG_C6IhHk?mZ_ey(ih`ppeCM;T%8Lyzc~E~mmn&zIxUwn z*{5`=BkZ4Ja7}VK>9<+Rm|mG?mhrB~YpI_eDXZdn$hGX_2mhJL&;-*4k)UMr6hB}a z?9dg0JvwJm5fpui>|dAk_=7#+%lR)LrTVy$l$Y*(THJVQ%Q??!rMbxXYC=@CS#1P=y(P}#@@f8Rd5ii$ zDY5hEEOMH*+tV|V7hp$XdDxFjdo52_WvnLNoI59?^iV*u&!LCeK!?XdQ2YiQE~!WS zm8+D=b~s301m-s~t3TXw{t!JCtqjWCF>&M?$TX6mG@>d0&~zdl8a%ojz_6ri_BR}; zx9)RiN@^(JtU9mSSS+tM`la8@+H{IcKFhx^u=Obc&lJ@X+P2KZ<$RX=Xgs=~DI>FB z@?Y&o%3D@QQcx<6D2d1nmJ};uo$gbM^EvkGuBwd_n&ms zaBDZ?9@JuA5Z9P~nz~MOs@5|etveEXh2&$*cYWA#F+_ z{(g=HJ#@YrCLdYBp4w<)kwBkK-hv-ldW6{TBkDRKVg}qo?wN~Vk54hZI~OkTOXMJ0 z_5bsV`$irUmPoJ=kSTe(Y*O2qEi6$i+_{eX=MPwY6n(6^m_GF8+0ELa3v*^Yf6_y% znKu9__yILum?HgQ#UfMo=6A={1BUzD9|-dindRE*AH267dGZES{mr4#LjnJs{vwy& zCQ@V`HqQU5%5|via!6B0cooJ2L2S`O`t85uSf}K<$eX)-fe}q)HTwF;_Vo1CtCg~O z4-rYtgSFDLyGa4K63q%mLifnw=3}TN$u(t$>40}}SOoEnZk-(|v!?rND5YiU0LynV zT_IO(XS{pmT6MZdmwBlEqXDp3mL%AZo9i>hBB=0!AoGh1$8*_ND}Q)+qb(zy73KP9 zirk4)u)$?Hy%M1GX-ok3P0y!Y&Kz0(7f`;lvzF8!>|AO#3`}}5uPbsvUPJ(et3G;* z<_ob+FcDHO_A!M{XZggK6{WiJzluE~hz>7B1n;f%JyvfXpnrx};mp%%e6&ntRQ9L6 zM%0U_kIe5Nf%&)JAcN2W_wqb;D18;%B)h&l6Y1dF&n`OC(pkzLj5fovy|Kqa#-f= zP?*vV#dNszn|nzws#K%1ZLGjXpfS0M^fbQ+wd;_-w`C6uWE^YfGP4!9?hR7?6%^s` z1QGv#$v39`sae;(H&Tn=np`y4otN#LhJAkba9Hw>ePk6{RrqY7g{6fpQ8r{4xvDWV z+aMr+Z}7>>{y@K$zU_}<+2XXy(c%1;PRHEfC?45w>6fRcoC3^Au#&MVO!Ajp1&3#y zv#sNDr2{zIwnUQy!6xxG1O0DzxMa!(8>yKSFS~Z&X;3_jStMM8^7C9IzR}~t(Yfb) z&yy7|ol%#5RjfGk3nlz_2mUVr(SLt^ZdbaduQt!q4=VYxsz^W*ACu*G$62D&Tvdan zcfrRhzuCnF>rXZ(VY}O;O&(nqGal|R@<8QnQub1+4wb3M0+Jn!*`0TY*=!HnTikDv zO38y+VgXJ}>&@G;JxE6BxyYbz@!7Xm!z=OJWs+Fu+Fe`(dc$qD(PDqn8+P~w%y6o{ za6vva>w-uCzEMd%0)-j*&;0Pp9~uK8&Vst1NL!gl6q*gGayeCslutg{`qbZfV{H zF+5bYd7nM50ay0w;gly*C^IdtrKH;E!Hj>wL)B(x_d$wQ-HPMj*h;TA zSg<$~*2?~0Sj)!pAE^C*V6CAopQ_PCpro7o{~#^fe~{MJADjkC#P*}rjmWXOm=g}= znc9{rRI1TGCWG*~^0~&|UZa_qOnO|4<-3H3d9443 zHT_|Qmeukx3Nn-zd}4BbRO&Hmanm^bAH_=t(z;VJ75e7%q<*np7X}jpPo>#il%KaS zX|+DY-nGkVt5$Yq*1%V@nTNlNh2pJSpZu&~qSyaH*b=L}pahed&t{LsUfB$jeybXs zHIV;(VWrY9yDd8PzfAfV6JtNpD{737R$LXZ_;06s&Aw_4lAyCHZ%4|Y_PessoRIVL+GrtchwBF9Mn>n z=34`gM}rv~OeFm52}aEtB$D}Fn7SE2mHg8Y+P-G z$Ap#`!3SRoFM7Srq&UjBhFq-oHKEzO0tJ};2T!;0(f3Y7i}xIra-{{8BlG_%AbafAXown|yx z_Mu=RGWNc*fSiNJ>jXtCUl`NiEuOH?OtxSH@10tDhYcPVi-kVE{6{d|VEy{?O8;NY zgMNBH*I>d4(j&J5WW}6YwG)L4%`*j|%b%=3UZ3dwlh6N>zCY>a3u0Pp&6_AHg$PH2 zGMVB4a>Zhvq1enMWzMPRe;;rMSrQk`?I<{0f-x?rc3B3nSR%N1jm=Jd)ha^c6u0Ww){gO%w|utPA~1=>l>VjfjH>M# z(1$;mpwyGgi&pbOj&ju1BTHqU<~%1d@o(y5vC0l5P`AvE+Q|9LtUt2fn)6E}W>zTe zwtusjuyqP;?~pElXX3rI&%8^&#>7`5^dcq}Ax_2tUPzF&#p4qo65Rh?5A`Bj*}To; z1L^3JXZYt$KQPyz*`jcXe2(+%UuPtEW;PialcurH{yz7$LpNy?)GO>;M%6mW6fAhX zKQw-E&ooWOZpZU*l8DstGr#Bu!Ja@vJN*1Nxp3V*hr1`sW*e@vwP+sK8-CoUE6^lH z>?s&=vsy%i{=CKRR|ReJyQ-E#`7WR5J+8E=sC$#dt!feP+llnt@`WC(umn~8J$CrP z-$~k2|J>B*JRR9b??Bdd_I5dz4`I)LqcjYNNi~Welaq4zqdNG=AE%c=)^F@GHWVwi z^U|)}I+ioy4oPijyUu=#kLg_Jji+R4kKpt77{q15mvhx2_r`LZq6NzT*ue{L)A;Ig zUQLo1dD_i-ih5Ow7Y|T44cCG>i+8|O{iL_*d6%XI=q=bVBSp;}`S8=P=+yHTQ_O9k z?fe%6SFVb)((1EA*ywz#sm*B3p1nqh?QTqMkw>q=HyedJng1v@yKcG;S$)Pv`@4o# z3j)vEs}4?YPYivzdWcD@bKBNwi-yBRl5X43@@RbFAsu1*>K$B;k*{yWG@G4(oux3= z8ZXYD2NIJHj{Gd<*hxSQ7aL;xto zjr0VikA)U^u!ao*W3QU}MimVT2)LlM5tZd(B5%4d>hjDYLEx*H>LtWzrGPp2hYL=q zpj4;Z7FIbO!)RVV+VTF!H^^+iJlyU1IWUw@$g-T47?y6ep{V&OTL5Kong2Dm{mzv4 zNBhDyOV6l6%5A(~XJ4wx3-hac=`XS`s$;>BgpL0$)}o}_t{#xv`n=`CEr#1rCv0f8qyhtNux14;2>Bkg2r zrLBzLNb*(%?PPPk1BxTcY>Fr!vu-*I&~yKb2_M>5$1-jT^e+n_o)H(0W#mYKW&h6o Ee@NdHZ~y=R literal 0 HcmV?d00001 diff --git a/doc/pics/vgl_linux.PNG b/doc/pics/vgl_linux.PNG new file mode 100644 index 0000000000000000000000000000000000000000..65ce063070aa4f0d159cd6a8f8e3eee4c4eac191 GIT binary patch literal 25976 zcmc$`bySqy+cqpn4IKkWHw-OENC^zxLwATYNJ=*hAVb5@2o8;Ow}{dq(w)*JDTsjI zsQ2%A?q|L4v%Y`6wZ1=Cu9<7k-sgGlzY0vw#lN?c+(~)&5pMCL znzBBi41EKH#1C&7jaYG!IeXOR{E&5C%}W?iczEvL{OjikMO?gmFFzKO*wtn0Gn?%T zk%_yl5yfZsZ%Q&B+A5fLt=PA(WWO)w9)RWC3^q3&c1U)gv>|5h;hcOw|uJty(ZhdD~-Z1xkkoUs(PthbaEH<=6Ph5mu0^9l7v6OFocsOzz zJ@!9(j2gQLdsbsNHKk-wtZ91XPNZ6^5Tt!x5%C=S(Z?-J)!dP}y@|R`{+&99`pV~={zHBw-X`e=qvOkLANM=GZVk~=a| zahRYN(+WfS9dgK7$gf+Hmd2%HT*L#ek5a1)A`&v+Vf#TdJEGzoH4k^|J9%Q5j7Hym z(C6QbHlT-x@8Godc79V^^<*9W+&j6%>DRXyQndLHK0Qr)X+>p zKRwPtrxvvfYIHqoa4k&B;;de8T`F7r_87XaPYg5bdQfY2xW%@(bm56uF9dAbk>#)@YE|%;v`mIm# z7W{v_EDi68Z^c%zW+Zf2j*HA?QfgACEy%HQ`>9yT!d*8Gg+#b6)l0^+O$iQgXkZb_ zgFG{|0q8S!EO48&&gT4df%lfr-!^te$w`5!1cJEph#laaChs@T%;`ej2kywa$jO(c zLWtsK>?!#dxO=kZID`OtXNu)fs9Ly)5oRJhD}+uq(Y{1gq0`U1y+BOjJ~7`ck-@JC z(tezVqI_mu96ec7tI#&sdvD`X?~X~xn_V^D5GI}TCK&(}a!ieI_JD5KLYby2i>p$h zkfA-M^Ple407He7D)xk{&7EaAvW^NXJhYmjR6~T7pw*kiN%Rs0K;#3o&o6betA$@x zMy4@vwjcO?+GZN``apTfwNR1C+;OV)Y5RcG@cFxlR8M7R;VIFar}Ifu?it!Bjcx5R zZ)Y+_z)x2?64-QxbxVzl)j?W5qwbZ^i2?UyTiS54{eA7uwJC7Y7mPS_U1FHQS-{#9 z%+uu}`21^v z<*S7~iC;TlYP0+3;Ju;z<<7)6UHI74Dot$YKE`Z2UNRdDxsZ5|RwGkt1V6Sgc%~bw z1ce~D_4kEMwVB{|PFg;mQDk8IK~ykJ1ld02q%W8|tgm|0zZ|P~afG|^d(W)ot*eXt zBlc){$tKT&Asu>jsQX2o*ZNo`;}fxO8mqp|wd6tXQxA^iCj*%sTWmF4Y<&FA$8!6w zuMNfAKM~{UTLUT_XF8WVF8xB6w3V?u>&ve61gr!xt61IYMzKyuZYPCgE-~%g+cZmd6wd}OluDiKa#Ro|p)Xh}+=*W{|yWW{zp8lrvsB^kyi45V;Regei%IRi?Pl zBpXd1VJeI9B<@pb*xV>8azD9BgiV?ZWx|?1rEab%+joSy5IT`&E=Us}%uur%`xV=m z(R_i-JE`_z^Ee)j*Rhnm+n!3U;Hxb=GTCVRT7-kIn}or;ts=LMUs54Qw1%QOdz^XP# z)`^DrO?{F3%V5XV&YAb#S$fBV7jQqA!l1FI(ij`_G!3dy_kNk%WW>7&i88a?kylTB zT7`BRO+);1ZjQgoY2)m*$qUTJ(gbvr?C?D8)!bHIj`T>4@wP&{PUe_#Gb~?yx9Hkx zIX<3+=Q3UCDzL-;9#D-(mMDB6k&Tw@pYs_ZNo5LOc^__QmwWvOhu8_$)lNz4E zG4r*seveu=-D=(Bist<`jnuK_#6x!7X&UQqf<=6`>xRkg-|e2eg;q;}2F@~ao3E+$ zPe;qFwF4DWUJVZKMK}6$%(~%uz2V88rE&SDIwVP6@3Rv(_Wqu2dX}!^(#SO5M8rqH zuf`?>os3cQus;+|DNMWQFowWrc#IX-T{dDy5FD|D9#br3&##@Y6aX~tx2|f_X}_1s zuPk^vtn5v80)Ag+b62z=$ITxPEOuxQ$-!9-s1w`~(G;b;GnfhIxa@^D@ zg~te7Ebj|Jt|2X)+oN4Dy?@T*m(-AHu?zORddB^z4yI=A_P)*0yhA?i=eP6o8L64v z7A5?AE&;zn15)LD(4>Q!x`e4BUK%7HQ92TDhMC*r(QPCWoj)j7Fs||O;RBVPGKEO^ zYvzQtPyoxTVm_?Yc{i%~5{2SqPRh6$8_mK;Hb)KoM2dJ)AOuz1v967R6MZfQT8iCD zY7>QMw%V!Z7;XYrT9*aqXTN+Qj}v!QyqHp~%r*MY-~!C&numlj`Kq5bo(iHX?lHl? zgv$4G)W4X9v5gCs&slAAsmvRVU)o43xAdqAq~^EIY_Rt=t4N(9&UD#e{NSavDGs5R zd(mgQV)<+f_V6hewyvHymU8?Z)(F2+;+I7zR0y|~n4RGYD3@pUPx(*cR2NypMJ;RoZ@F~q)~5{LqW`0K3o_PvlP`4 zHxuey8a7dEK6QPmTyB=S(voe(ops>CZdJCpB%G`xna1i?%w9DXrC}U&u^ko6d~1ktDY%h_oh{; zHuWi4uWd6_r0t_>bg|axPhZj6BjnEjhB)hj;8x>roC{A!1l)yEhs{A=G(cWNuH@f9D% zj|1M>s$fCCjyH>??A>^_?`CqjW4~jH`(u39d6oNaSKRRZe&GW5*aPM)uG8G?CoaK* zbxdpd6y+OM_f-WgTsW&=!j6}Gf5Osfv)V2$!|ad7&CIlQ3{6Emt{iMcaA>!dx;wLBtt!ZXbA3{PueHsZb2*V~Gej$3-*0R9!q zi0{Bm;>W3Tn;%B}rmne`+Ueyi!+oPwpxQlMEk|kdXJtW;dzYiF3?saAeyuI5+2_9d zxJzWWC3YKa%-JMcN=c|CFo*e&Jr|PjfISov|31igpi1LS3~J?D1_kr^nQdfcm)1C- zu&Ba)`y#7aZ86B(=qjo1hr&Vgvi-`8IdNsk`_uy92iXzxR8PN^8x_Ijb`TD>$}lBOn8?&!H%|((o9i5-O#Y|;K@7vVvR-JrF%cOpEGvGVmr2M zqQ;RdBa#Lkn-)PT`ZmMmu8@vG-tHGLoY5@rw|1wYxAu-tijTs=^LrDwz;$TG{jA&} z7u@41FMj}s2V|4o-`cG=RoE|LD^=d@b>|kQ>6&1R9AQ&nLfzr1M^ToB&sQFUh0|{~ zVb*1yi;BG>PXf6!d7ieNp)wThD~C>RL%znB@3Si-tuYZps4@yIK_yZUz3B_upI z83=!eOUm$v#Wj1- zY!MrH6O*a^&SrOdUgafxR9GbM?Lmp`!`-6clmDh370Eyh>EvZ#~MNkuf=^706xxuD}Bn4DQua}*1!Xz7ltW?U3``CdH;#pmnv(1ZcIH;eO(eXHqC`ONWazxg!6 zci%_rQeCzcZn{mrD7n2c$!k75nfg)f+AKaI9zUvX-a)tf$=BT3=5d8dOM187#$=Ar zL1S1%&kvldkS8y0bMoG-35YU(PnGzAGlK%5Mt*cM&TF*LxId&=DPVgVk01Z0Q7ky9 znZxn^_*TEA!d4`~{cLPCNix_QV-}eARFunEXv&D{tPZbCu#EAc!)Wf&!$z(Gl69Z^ zcW-M`sPjBeI9Jd;pZjhVRt%Hpil|LTyssFX*!BDZb~bCl$;na*KX`j;3aG*dbF(>C z!(&CLzMCC?`_@(KuQzf2r5ZwWMb@xfD_k6Wf@jgeSkS7n7mWJ{P39(qX zc`jOsddkq`_Qlr7gQ__1n%LN=uOgh`ebQ;28tdP4L;}mCwd`_cJhKdxv73ebuuV(r zh6L)I#2II$aOQo9KD#=w0^UXTHTSF4k~^@!q)ThOzio8Hgas-oU10Hd_~O=67UDMW z_|!HKWA*m4)@MvW;n$gPQ3Ng&E=7BX0ZyVhymrtdq9|W^x#!;=gv0fg$ELk?LcUW% z&uuI>zEDYg9Uj}au-HG8yQXAKYWYK@4yI}^X*%x9HQFyRrJH03$<514%F7OuFHrl^ znyJLjm(*SLUVFp|tMI8h9ygreX=lFgCvJpOa>?F=Bw8jG+S6)1bl>-`>?9xJ9DWLR6Eq(fSv^r7 zj(0>4(n5$#Kvz2ron|8B;AKOPlPAED`2e27P(LN6Et1T%)k5{{(Xr$vRMyE9o=mB8A<&`N+(A{O^~_9F_OfR(F^u|ip$=T3wOSx+4@(KT^9@$Lxg!k(?I z;!P_S#Q5%WE3Cy>xWU#=U;-{Xsg$gfX7e-kJ!atIjg-#@KrT-L;Dc&g+;3~kYHiE9 z@2)2gHgWPXP?WL==>i|)NUlG9#v{)8kOPKOAG8Ux6Y!JTv0?$AxUcF!0?9)|ff}Ii zZ`mx_OhBjC_9r!uwVmmR#+Pzs-6(ZE z*NU3H-4MRVQhFvit4(&!-ukv<+ny)&FUQ3dLoqIOsLMVpYDC9J$6^r-s=)}Y5#tFq zSY}(ZWsz7~j6#}@48XX(Srnva&;3Wo%Bg~k zH1D((dNqcJ2FFOJ6VKL@DF@=>@JXjpWqNl@PvWg(W<9;D3_CkKrt5S$(?4oFjf7hd zFVO2d%B8qFI2gSKZ+~SQR>C5(#+%u*A57xQWa0MEuQHuZqsmGF@^E|*<>uz&;}aDV zG=j&=$KZAk2d2UU#!@1m5Fo1w4#iq23u%Tg;c~FoLdxgEAT@Ogc~G(bB|1=2b{rMk z*<{`CL8m=?ErtDQR(wL-KrHUPpZ!*NZ!ZDaw&Ur>M)d+GKV#U}uZ*&!C{l0UNELnG zqIsDWdGYykk!I3*KCF$JlKy<0!(7f;S*vs;K~i^6l9vyxQF#l0)O1(43IDPtmB~B$ zT^qE?Ufa!HW{)8HVY+i1^kY2R@l3|!tIQlnxTms%4FocHKo@+yweyXZ3vVczfQ*!o zIxmN|5KC=f;GH7=sA?S9R{nSegAYwEV%2*mU6Yca@cIN3N7ZM_8r}`HT-;C;oS%#HC=Dkl1MmoVqIDBpR>5%t+U-}x(>?QT;lI5`If#x<|e z)Akqh`QKU2Jt^GDd3?~FA4b6Zmi#DDjk8x*wSdVDw^{NxJL$7lJ-g+kr2{JQ#c};C z#prUR&ELemc9?js>KB_ez8UC}kdV_5!I!*J%H0bj`1rs{h-dGlMMPMb5*c*7oZgl` z@U(Q7hxpv>NlMoqNQj_3;MYVE$Pz@WzI(#^uyB`O`N%8*$IDak)ZjsV%NJ&#K@W9b zI4f{gbTW@Y<1G{&XkwtOC13&G+$~M~K|%B@H|4&1#^+=;>#MV#{P>H<)H2u-_g71? zzI*Gg#%wwxqk|6~G;(JZtkMiGxYtkqR?7V>kks5@b+O_NB=3!BCRss=o?8v0Fgv!9 zy1F_5|MTJ;FNeoB0~sHARSQ=u%kCWAPDfjy9EJ^RFD6R#UErSbusLfCE)GEFOGLVh zYYihCJ1V8B;t(Ve*p<`rwgKLfcmi@~Bv8~)Cn4hCW?^6!=*ctx^6HyBVNz$U6W)*Iwf!P7 ze#`u#?R}pK11S+Bc@{Q#lxR78fL=~H?5>J^zdh3RByQphR_0DozQxnXJXc(H0i2d;XS-7V*Wm! zp31ILdRk73R`QNlRUWf0fuB=<9nPpfU-`ncLfGL2g+%fc;IaWT5X6pwQ1_G5<*Ak< z_4A=0C~04y;R(NrBUkSGn&g9V#0WfA2inf9uEI#GNk;=J-S4)tJa^7N-Yp4|K~NEE z$srIWK$4VY(nDZSa7E0mLh1%xs{2W^T9Ur)rrfo^v)XAyUb>M7LxhcVrp5syD)1iM z>+4}V^5#k4=R-ZDna{V?$vN;h=hogTh6)m%WJV_`MJq9cvS&fH&;}+wXDzeiU@Ca3 z-&#g{y?&(?AG#V04KRU84Wo$wO6**S+lPC6*DJPp;}18w0?tq*uI+5yRBKGSi8*BB zAlQOnbPRL_GN;z>y(QkyTKvyR+>Ni+)9JoB!r+6c(3_1rs;gtO;GK)QTZpf#tIqn3 zN<#s!20VC0?`dQJ@G+Vva{hX7o}8ds+gA6} z@-oMP4oA6kPlMsieLM`ulYhhRsTxts3 zP4k64b05~`hT?4ZhOl-$c6zpprU68u_w0bd!*>cwpr`m3cq8*Z+3?_C6|=YI7WX%t zg~!Xs9rU5RaL999#3mPlzhEmm`cxV_GcS)(KvanD#lkuP!@=j3GU@wwWSc?vLGBS; z>_U8xz50B?wf-eLESv#%`TKs7^wujz=?u1*7_Yu-qt%kXrk#&mYYg0Gai(Bd+8rmj zyl#Arfr$OlVM2vildt}+d_L36sU0rSPe$f)?6Pp?Ffxo!TR&gNrLeg+;!b`(7=hsdJQ{-V0-7#4GK zUx@j@Nl144(U#K5xvFTMq6yaznKIlob#U)YTI60OUM2VCT2oVNRD_)?r`!l7&-1+F~%EhUD*s5$LyL5 z3@N$!-m7_^iFi-3MwoYDkswtj;vFMg_1LzT3JOsnAmx7c;bpWEfRu=iD)$iqC%Ygf z=Aeevj{x1Zd)@b(*OdazSiyTmkyBm5@*j|O3NQ=ZdS&Dy6d5*QXB+mTjiYLUH+a@V z!!Ri9p@>mWRzu6l^);0KrME8%$~}9VW0^1&1sypRE$t&BA~Gyj-5z1*c6sbydy0-w zlRmVrJW+)5Rp-Or`&Tv0s;oF1%W@~Dr{!DHL3Ll+>RoSrgUzKa>>#C-2pw)T`ABGl z-nV-=yraf{{$lUR;wrNvNEx*7F>a+JWJFO89AIT_+-tbVP z*;-esH122e63Z7p3RvpYHH~v!Im4}bEMNUeGIpe`*C0S<;bP= z^V(QUptC?xpy@GY{|QO_pYWHd`3z!KnvwBnamv8dTpzItVdZ0xFMXO=FlET35r-F( z5QBpaA>t4n5FQLMatdvk%UC;UfTiuA9XjRQ^$QW*0$z?si)Ge%J$YXPdVsl8`0;q#s zoxNi7s;jGmrIcTpNFB!FSn1@qcW@rm&$V~FZNQ@N_uM6N!CDy{i!B%i#Y5gvN#sH_ zHsuK_)JwCb^|RAdQ{sxJsjd0^vzu0&_m5nR1|*nD0u2W8i%m;ceHxuV8S5VXR9Vo_ z^L#Vl>b;K99|S951TM8KNIKGy&|nW^;YFdNUz-lQ{&H-ZG_R+=&-!|+TMMUlW$hRF zy!mu-&!J7>?MF!=d0oE8AG#_U-Zm9i6u0T5Gc-38(n~SC;Mn&r1iuj+EV^ zEYyt7TJ)Do@$xU5IS035noU+rA894c-b4#IUtdk@UY(Y&lLCb@&aR1I9nET{O%yIi zE2VJ;WFx=`?xljna1)YIkYvqFT`tt#U-^J;e{{x_G>vh`!`bBI@p2*eN}A)L44LOm zbpGiT;UBJ^?Mq(Dd;7ZAm>XCH*!elGwjSgK2VGhCLZmEoR>D?Pya$^xUrTld?rh|y z&WF}MX9yi9UGC@cxC;4DO*2Wd$*zgOmQ&rEph;g1OaR`meLVHNw3n{y*?lAkj`&%t zA4Pi_xn_-Jz3YwN5R~6fsEp2z_ZXnZ22W&|(rN4^R-WgK4Z)Z5j44qEwcv(AG?Tie zEGzMG0E&Qoz>M1?H8dy)7$+0X#h2*AAfw#s?rt-tvY*LKFVRkgVM89c!7Y z8JHgpk2c!Phsul*Nj?rJtGt2&rmMLnF5o0yo0H2xg?k1;G>*OgGoIdjRVu>V(u&?n zPQEvVSMBDy5c;zgN%0Z!i}>!7(qF|T;NxLwtU3HFkwZ^18rO7}3#pSZH<#>Mlad5s z7gmb%KhmUexqtxo9bGFOJ;!Xo5)2DWZ_*ROy4D3VW(hQVMuXz1r% z>t7G3h_TXT%${C`mYGue^-zWBE0rn)0jXq@)!2v)v3<32YQxfl22%z%|CrYMWH}8>2nle`tRY_ZHd!JQTAAoqfP!lBp356_|bGtBTh2GZOQ3jn#3!k^*dE$_Y%q9;B= z(i37bCon+K)mQOQTvX0igxDjKkqF|0ZW85PVy;*jPQ)6j0XPC}IJD>Q%HGLBV7Em6 z*ARQ#G1|HhF0asLkL}6?1uax@z6Se za402Z`}FZd$S2yG2iSr=Sr?LBm|!&*~y zQ}&9(ZmTA7Nn&hW>eJ7>t0#Id`zIh&bl==og3eO696#%fygT79f!4Y4F?k7PZwfdt znuK>IL)!Ay_1k!Ax8}b-FGPtNC9_D#%dz7PyVjxEz`^^JsUT5@g=mS|fi;K~blr_1KCC_S**+thRR$Gb*b&QM6q z&W*7(Owzcaqpm?q4t1m?kR z@D%Cced$6`a0qhB_wm*S4hqPcpmG0Fn95(>R@H4it0}duNgow4^G)g1x$6$bx&up+ zk$Pkj5jZIdav=h|vIcFD5545RebreaIBAc~`7E3y`y;LPI8ZO3Pl}kdxP<=R#MqoZ zYXCO3#$5R2VIt@aEEk(tYtF<^9BpFtO(G}t+aRV1HPBtxwWSVN*W1kAWNGBsVs_5I z+--QY4;^oa=Fn-G`?er!Y`ThVF-4zi#kk|zr#I{Cp7ZC&{Ezb0!4i(;2NK-MB_&xK z_0z-k{q%nC*q<3!U+0@Vzki)#Q$_zwNhYAF3Drr|ze3ju<@dsqG^411egT?G<3t81 zVdb=_i+IRr_82@Z{ju0w(Uunqf@k~22b8@nTCW8y@*?ATraO&<>``W2 z>%oSp>2m`ktlnUXed`vEo7@=|QJmXot$bipY}E_XeCvzXyd~r8ig1iB3SWU%uYyR!j12l2*P6$GwS*_ieNv1!1;gg7gKjC$F6RZNCh? z>2mahTuCVrFFkz5JV29J`7#w5%}}&Z`C`>U)+8L_p^e0_*k~4biZl2$efYInNq<{U z+PLR`R^S1!TvB7@v(w+_kmMDrZfZ;ohs?=-&wv$&%xV8N-vW&q+UbtWGma_kbXss( z;CcufFckhAidtS%fWq3Hpa6O_^O^xpU&$VJ&D<&lfK=xipC zi2PL}j9cnYY(PRxuuzg*@Jyf%aGAW0{4G$ewl%9?M<9YU?|H_xs4DlpiGo-FEz`5` z6dUYR(3^kIe!D5_KMu^RWVmZBO=9x|0~V<=$PhX{s03+{+X!TH^}Mtn$yG#5X|n=x zX#f%6xJQ~`d#8G(j{&=YEn1_Wzi)KCH0)q|c^r`wb~$?>d=zKxU1RK9`|iM`H=nyK ziRcxk7#_GxXs)3VYnvB{4Cyj^^gvU2JV69?N1)Ku)pudf5nThY@e;mQcD0At+T(ZBq z3=%mwne`=yBM%wR$PWkKET-pHtbLCHgAtHV#>MiWw(#Z3zVG_r0`KXorBcU{@BHD< z4g&}Az0w`Xcw%qNsM8N1g-$0f%HGph)`^b20<5Blt}j5D*Z2 z4;wiIp{mc62*LlewThew`o7`3cl6QI8*-RNha~Lo?`?5{1D`d5sr{l&- z?W%XbDA0HEMp-YfYB%5sXHPcqP$t_H8Vllq#wJ0hs{HQ_G$a8bWP^_**noGRc5f-= zlt8A);~YUB#rY@RzGJrA)m_sqa&z6sT6e{c+Ap?3r0T+H<}Eywc9~tO-OS$CZ56#? z8@7S_W^n?nZN7>-Bu|z`#}}|JNX8)bmk(2oMJBa&l{jPPG&W47{%vyS7PGEeUf62) zv2Gpu;|fIE=gFf3ju1$U&Cj@PEI}dRz|;G%i0ZA;U_sl@@eRza4~daA%{{*$c;45S zt9stO-fghr%kG=Y?CM!TkatbYiW=5*6aB}8)%QFDoGc&Ij-MCjK|=pQ3kd_fCj1Re zbNKRTUvByIfwO?qv&?6`5nfVWHB64B%Ya*aFQFCTQw0 zT#4|V!?bbS%Ta!uc!&-D{kT7+pR>@#(p#~))4)WU!_QyZJI>_VW5{T@zlkSrZwov? zvg)JQL%8Q2wWDl_(j+8I*}K_IN+Yd7>RtSM#5qcnxZqiw^a1oy;{ zHi!+>8(sC-*`6?Ii*DG{}&V?5rl2s_S*?TlcY!+fitTT ze*^E;Kfp_2g#Rs(j0NA(9M<8?n3u0!Q!aOZ9!*~Cc1E9Hd>gHs;SD?qNqEC_H3o`!i4)MRLVy*Sh0$HlC zf8&Ee9;AOd{&<^2)4Nh17pU4^xHy9XG+4LJvH)hyo)ThM2J;#O9D@s{H@j zz<(E*viff+4|xdw$Puf0B=YyE4u31#)*llRTQUBl4cWiUB@OyxY5UYci6};!1yr0s zso;hek5Fi^W25nZ2kbb-{}DX?S6lrL^JW77*$>tf#{WoZ>FxVR4ofTKwZp%=l{_fH z-cNHF88Kq+F723=M*~0oD`aGxEMN4DfTT9)#lRo);gJKR=i0vF8%=(^Jvoo?bNZt~ z`#K|K&}36*+>A9d+|Am34DmX%=>wSV3*FHpd8sJW7y02bV7ySfLqV4#g#%&m&}$@K zaY^wyidVAj?&QG~nu;JeB0p3immvR=5@0QhR5cQYVTOz~|9-6Beu{0>l?0Io5@TDJ z+O17jbj8lNFvE$EI#X~^`b;12ATFu?`{&lP=nX+kh*%Iaa0oK~q1?b9zj9R(#57d+ z8wr^Wc5A7X&%*!A@E2jKMgk|w`fub9go%e<|3&|2sNBP9t1YF!6KVV7|Ndo_-5M!x zFv;J^{yGFJC#8=Zjmz6V>t|vi4cq>lp3)~mCE>3~f9>>~fzs#4k;0doI4FO zTe;z^E`mSuAd?Hfj=%~3_L1BlHU6>mMXNvUYJ>FXi#wr?%}GI|e*ZjZn6IX^d>ovN5OejYa&ujZRwa`_j72~<| zpCniO_a?EZuU7R3XsYLP%^+Kz47KOI#g5#p%#@a&${(2}{}zOw9gOs3R&GikK;_~^ z2Jg-4FW7{f&2UZs$1=q%mOVaFHNK_DS^f@YN911r_fBn;T<-IkUv&K99^FzrOmkRnD3PGBaPJE*;2qj1}$6hdVyd4g( z@1%56lK8Ds@po!uKzm|3{vpPGsjxp_{MWrcoQL07{``@whTQf!oOlblo^&;au~q_7 zKlop#QPmST$=?^={kJ3-6`Z6RKnNeN9Af$i(f7_pbfU*Wt|2N=pIEoH_B`5&%2_QZqdPl$m3%?hge0w>HA_5blMB@rYV>X4Hqeg7Lt;D3@B6$bLF zT+x3V`fs4a8UNs+mK*;!I{Zm+kr8%lYDx~$f0z8fC+SEjfs-7P;(v#sT@5l3U)A|3h#LDJthku*B9#9Sbw_htENdFTer|4y0xPTQYjM9lT z`cnU7@h6_+Cl3<{IHVnoGU$TdLlU_E*i#sn8I8dx{YNI4LWb2VJxXj2k0jcXSZ#C+ zf5_+m=Uo3k^4H&#H#CKXJ_CinqarG_P`wb25>Z4!uyOzdX{&mWr=w2D%6ZClMpn7h zwhzoDBkKXBtY!wT*)t}vks=y4l;ldKHwIB|WwCm>3y|2HI!SvCA)I9j{abv?DyBdP zm;Yo_V#-jcyDYMhVv;igp!3E5F5ETD|6dYqdGxRIpU>4n)79HZVM~)(;~_6FS%Fcg zze_brEhLTSTu8jn^0$@*%9N((iXxU|99JFokE*$2t_nvx6SZsZ{qBl8Ye{GnHT2GE zVvjdc$&pu$D-9Z01o=OHLKbF*Xy@cGFd`CxEPwDA@l|I8NM=HNnb`@3}Ec_K?- z-ioXG8c*S?_)-zw`eUuji8nvE#Z+c~GrL6cZ^oqT(i64l5mYV$PWv%P{w)yRsj+#yaGCCiqP0w3 z-u78HNpNcKtV!fPjT+InZOtWOFxSKz+?~7B8n`!zt?;`vyuBQN5}#O^{KK<#PS4#d z+g()MMVn?SBNNz`SlZfQek_D%7WrYd6Zwzx&qo&;Xabxh4 zo<(gmbLdM%oo)SX*)_rJ!tDA)*o=X@Sh~x;MQ(2OP6FIVYjo#EpVG49B!sE9XMY-g z@p}1}6B}>ufHlp+7UT6Ro~3PXiz7RM#(!p#c!n?#mtaI>3FonM^J)?gsh ziZG!gux>Z8)q~Yceg4>6(y{|7QQ7h8Z&eTF+hYa(@ZkNYhw%iv1@Bt#0(!}|IG=F4 zZ;L&gJRUTq6=r?>doRlPO~GX{zdOr2GHVmCX3e8;2z4RU>$h{bX!o(fr5<7Y=4Ebu zp!tc&hz?=WjU<7gKF7jB7fOWO@+;E=F@Lugg6@S;5P{8UfLx8mBg9n39|lPo#8PMg z9=Ar;T@jQbsNnfsCSY`68U&RN%`$@-alJY$gPie`u~oPl5#rk1mjVnPCn*jK0+&g^ z!ji`0LVimzkir1<%i#{8cx2y*B+`T|q<>2x(*}^E1>^A{#6LPz3%GRto9DjF{@!0!|Lzk2TK5$oc+ZZ!5W8sm;uG=$@$e4vss^_+ zW_vCblCumz(%e&3T_*KT`auU(bx1OJHfIE%MQlzJN!x2N0S)CD5b{;x)4e76@@WQO zY1tSoxrf06SiMIU&Ffy;-)aj7)rp_j`%D_+NeC-%01Hj~e{4~$ygM>@x76)y{UfWM zw4S45gdO2zGV*$l)yoy{w%=E=l!${?Wq;!w!lVd=jFn=cyGi(fPks0?5F^MCz$1M5 zeUj!7CbZ%-*YV_r1^LeF_xGCq`yr5;NF#3~r;obaQ)PK-60CCkwWIb&=AQ#|sixOi zU1CoJzW@M&?!6DAQ?}V1nC*$@sgZ03Fco=J;9Ya@-}LmQn#hXHmjeUV zq1PwbbLefH%ohplu22p=XUixk<@|MdM~5{$R{>@RCHu?Xi+(+?$~97yQ36kL&S42n1LuM zYpZGpBEyFkw!FU2xSOfcG}GM!nZXB}oSI0VYM7Q&`K;q@UV1EQEaVc{kRbm1+I2hR@`F&{;K&c z+W;{Ev*)RADG~D)cditOc;O)t3=`epEoL~|<1va*amt{N&<#2{BKVLc)v>Vc@rzG9Xebv@^TwBrNNJ zPwx0y;)vY>&_9%k6v!E+h!OZZ0sGL0peu{-zi_Wvhcb4-*)mwB9titUBL?DV|5AYa zr?g-`sMZ-YB36nP?|>edQ8v~Ly683(Lx7M$=Tz7anSmXiI(|TgrCUKj?*@SDM3x>m zh6ayH7W8#e-IhLXu`n&7cI0fD@}b;G{}Bb znm>ciWlGlBVAsHId~r-Ou(3IhaA z#NtD|3f_@=NpXpri8`(fivSu>m6Z0@R}WKnV8lHZSkM{m%9H!%VQNz*TRF&DldQ%l z9!&;`3>uT7{}h4)dK^R3$ALWKW&#>?GTcEY-p6XK?4EYrqpHYyQ54~69a<`jy(^VV z`JCDDC_f!D?*1qvGDO~_G(WPQqxk9hIz}-H=p%^&C3?YmBo{D{B|@{2 ziG7~pC64ESQglwH@leBp$m0=}6sX3}!vs?`JxkcnA#tK9b^?WcJrnN0*J~&kZQ-n2 zgl;gU>{LtEsdK~SmpQ&$Vm&VAK_9bnzR_Z#`Y{R*5s&9fDaRm}u8F1v zg)l0f#<0h0TS*i}b9frnl67Gu*xX3sQr=B*``JFrG9<1g%U8lvwXl8=X0P~eeNXe* zNB;(NpaD*HX(I{tNRuPABD>3#Y>uTSI+>pCl(L0py@wi?9}9-dO@98k#&W**_8J!q z=kvP{&mSrq@M+@k4b&)kdI-aPD3Lqhbns9bM#m@YcSKP5NU_WfCYS1Z#g@TU4QiSi zlpB4Ii(zmQ#LF5*BLf||WMp#)`%>(`K9I!X6?03LVJ zq*+m=8#2>{q7tBLU1Y*Pus@e5k|ovP^t8}S5g{F|vb*ls=-s$0Q9Uf+ zDm%_BOMxfKfMKu5@8lOC9_s7&y7Z#~U3Mutm;#mkWQ`tuwius1h_5$OHHui5!zeWM zgBD+mk-)4UcZWDfjG3gs0-W3Lii6uP@1OzX1qjY? z|B@v*INhjVbI2%Cdj3Ahex)l9gnYZR(Ey0kAy-?_z%gX^r7S$!n&j6ZprVI_Zoz_K zh3=uoTIea74FH`?5WzoL?oQ1C4!x9ytsJ{0T0RvVTH*AQJN`(+u8B<^smEc#HaX?S z8z0-TA77q+i=>Q>NGv+mJcjXu>iLG|)0F6VqZeFnE?YIzz}SAWh8Ld$aL@S|VKfZI zcCP_Cs2&ztFH#)#En2%Kidq zUEf6g%sX>;qDi>Y$D{Ox#t3nU4P3&v`hri`1R0bM}^olot~Vy8z^W^S~mMf~G6e zwfMDo&VxOE5J%m#{bD~K-ts6R@p>(1p@TWtXP6-7eEPdU2%YZnFMAO`UaAR8hN!6-8-~76b(8ZX`#Ck{G&%8bKQA&Ot&2 zB%~Wbx*1wxND+pRmYN|1q`?7(o;!ZuUF+U|&sk@kc-L8H?|1*6=j47?@Urjeo$GD` zX%q&Bn5%f8T@Pq7I@#WQKkL8``b*c5Wg!Is^7=3jbOPC(1HPZ^2cZ47#!>j-RbbkR zZhUClB6{m^?Bl6l3D4KQH9N(N<#~{N(c0cYf7vT3Q-r9@XYnRphduT|d#39cznAqV zueC+xP-M?H<-M{n4kg56W68XtjW!_9`q8-Rc|4|#(S;OH#i6=8e)mgAPi#B}VwTLV zOQZ5NdZz6ejNARA^6>yTPJKEBq%L>-*82E9?V82zPV~FaB>{5sxX?q$O|v*=*?Hfb z+5!KRDa6(+`wHm-USMN!5o$V0aO{$FxmtF#_<-1CDo6R22JBXsPY{(0Kd(-NX^ro9 znJmxHNg(4XDh_Ovw}!5{0j+PzTO1uFD#fz>(tV%sfrS^x^(0;{$$z1Jt*h;k_gSQx zuhTQYRG+0y@$GJO&RbQ>JBXjH(pN-_XB!f=T5j+8pCf6vR`CoYtCmV;wn4H)wEF@k zjRIr22+Fri$-;D#QpyXOoBArM?mR)nn{Go63%xT7$qd{Z44*)prIitbAkVwkUBLz8!t8rP5*Szi z{e$J*+A*>dZ^q&Z9OzBr2DqmguJKV~_9QRfYUvm9!D9?|n5hS9mllEx3lXKW;^S?}~O4xLgT_!%sN5-7Ch}Yy|97R=A=vhd`Hj+jj zIp#8*^5t?WwNjf-<*ILBD%w4J$)Ij64yNpN^BCyS>>-jZH!$*G5081ElyB8mY``hz zia0N(SAJl>);{W@wR`%1p{X4X0ho{_-n?KGd#d(GHL< z@d&-Hw>8Yf#7{i}tJ9-ICqzX(?oKaID_FtM4avo<&T7?;#d_%IF(VHi_l{ORo18dw zLp%(2lbA}g33}f%KTyK?kZ2@x+qwKL2r|nqRa;zioJp!smnM!Oa}NLh56Yc1*B*Ba zs#$)xtkB#fFZ&(Z_)lOX&cdlFzAZ-lZ#Z;sJ(^-?Xq|9`g2?q`$F1?8<9{*J?dG6r z*|Wg}zsS=R{)1PDc)xC&$4xh6^arO|?MC;_Jo*?QhO>((oTQ_*U`xdZoWs?2=l}Tc zR7&2~Rn3`&h8NsY8~m;FT72d{u;An1%v8_#Rvxd%>G_@4{yeSg^sT~DBXRjULE6|% zFmZhMJ}dM?>z=!1_$PyU5^ZyW(oWsvy&oNmEx(22#eG)gdKG?{x;yOX34pH=(!1+G@MVZERIx!qxLq6Kii5^?o` zwy5*Y4bjZRv!12JAZ|@X%@>ps_c-ffK>T_A<9P;=f#Lpm4LC;QbB*ItK&{Wl^~cs5 zfe=gyNa#r7!z|NAv?^hNjB)?N-^#;iHrxJ3c~%NGr1+5)4}cPtr79j=x(j^= z=+dg!9_qHF6a*~$?lohv75m1#n_4YU9)Fv{lk$!~weEA6ShSORnR;a<~vb2P(4* z$e2#n$5E;a#CE+M=O`9@hqw6E<<(te+5}H5YrT{w?iunrHw}GBGX!3W{@978CkJcA z4EJ#`sp2?SLT>4Hts1VVnM2D|FewAr7fHBS5LIq_e7}EF;ZgO^^Hl?Kt^(RaU9I|o z+ODhP!7V4elpiWzo3gncWyJCO#CEe=QRD-0r3^EgyO*`uijxI@B7n?m7V{7x*x*H7n6en*Jpn958{T!!%7?}#DO!s*LD`edTpYs2uT<|}y z;(nK6yc5EoF*oy18R6s-o8=&7o01F}Cey2I`!PiV>!qZ7Ia?quWISh|d#@tlrIBS3 zOIXsZ4-+JfI4ZrCG}J@1@zBYUOMF+RK$ILNGkXN4{axD5B^Ac8|1#0xfKi%>;h$TA z)~WnDcwy`c8fR*tKBa?vyR-SiQQw$B9WTgclXQsD%A-0uTDYY_rG{5nip7IqlX=ytQvH6l$ zC_HGxkAAX!-)x{nfTKx$({&u;o?-y;c?#b7K9fbMZ6JO%Q~rD9K87$1R%7eX zir1BPY1n*{v7n~{t74s=t?%#&R7Umbi7A=o;3r|8tsU z;%A5HNDUcc@xC^7OY$BxRMQ5PdG(uizS*4eoW(!(tiz%_ zi^F2tp&n5EO|L?4ansSlS0W?qB+B)KlK67(aO(gje>C4v@HVVVKG6$j$u#Pyww_GS zuiRN+1kArQo1L#{s&yO^O^%dE(x#84#52I;l{lCw&u$B$P&ubL+)Qzy;?AW>uc>;d z{Ocm|V&4~v$_6qe;>B(OD^t4*X+brTW&?Ir9XiXMLRPS^c1D*m=oyQvH3`@fG(W%P z0qm?FG#N(6AP=k};?PZTZ2AaVQTuU7S5(j ztZ#4LvQ|?`Nxwv`>zj&aueC`wTPX65PrG#JeWqi5r@vd2(}Z(mF>BU&Ommmd+38a| z%2rC{31}sph*M4OhX8$(YRz?OO=%qjaPAu*GyKl5`54;Qc5)vNEf{h&f7Y=TNxl9H za6Kb*d)g!8X0Q8gHSPJx9+s{aer9{+NG<%0L+CwCDNXUUB^pY0wK6TAAAFULZeq1u zt14(zBT=N5%~3usUKW34D1x{Tm&@~PGv2;i{)-r4m?ZqSQTs!L)_-u42Gsl!`%e!ZLmoS-WCWh3(3%mp@^KS~Z z`U;Oqblu{}OkRX>K+m$-D;w?+6j$^v03T^rK!(u1UwM+~);C>(cchOz$I}(lbP4)ENm%eJ>D~fvP%BsL zuGJX(Vbe!#-`@CzP$ka%F#zrmpeBs{g5tY~)Tx_HNqKvNAV(n=EVJ_YGz2xPAWJ4s ztjcwFC$6oLyV$EfmIdn$BmeoBs!21Yl?@fQ)^>K2^P z1jk5zwxWN{^ct^HxrV!DrW*L}Bc)3H3vM-~H`o)4LkUB!tDh-!#2PKj`CVv#SezJc zx);s!r*fMWP9avks}rhMm=NV;!w|7~ZGK73?l{c1BOe%wA6Yg5sy(!jsDVhjkq-{QYi9^!sB54}B~m%O01z3aHq1y>CH zPJiI7sk08#XSv>2Ej+xvJf3;RgcKZ3dQtXq=J57BZZ#5iRD1aC9LWN|$P>rhK-^fs zkGDt1<*KA|O|?3-8$z!)Z!eI0FIciptUMN0o=6 zyX27I!Hw(n26Q{^kK${ko+mZ!e~%%z7h!+Qn)o|ut>a8cIO`a)yVqKc8i?@Jlj!IF zGeHe3-4ArT%xZqh=efg$nuVcnPsk38&-iUTs#{79J5b+l{ReubhHf9q9;OXE04m#k zEG$4rW;Nfqv$3W;R4r@aDF~LMqZ!-D{1FVTG6X^7zqIQA5E-g`WV*ZlL`#po~`8Dw`Tk%jr@jLIjr4eP}i%u zj%bk@(G)Bj&TMGMUOhxTsbnNat9fz=smyMsroCt1Qa18qzWm#h&_dhp&IcBo6K?sD z^S1#df9|cSZVnUY1v5Oxz{CP{RW#nn6()sfT;4uqe&4k#noR8nyEAN8 z8%KGq=aXYYLNaABf-}j*B#-xLtwC=^aOMAE)WCb4N-xrt+1^3t85@Mk?%LJN%8e~; zGd}s$a#w9;sK@fR?_2P_pH3mhpK{F=ESaen7D*C!9Ps@;*1b|pp9fINh8NrP(TJ+@>!dHwjQ$F2=cW5mfh9v803p zKhxHEe8+woyRWLjAT!qtP_Gd1NfSH9Hk5Jat`id)FOre_>2%=A!i0@kYqopRz~QrL zvq?5a5P_i*K`S7SYue{WxK;Nr2aEE)C3WsPBfbLhhP}>v%}L*l`H5i7m^uPYbCNiS z(3eOCTcLEJfL%B8m#D5FSPNU91BUEPY&;Zwl-x{zi*>4t+Dr8U$OZd>Dd(c(&Q_$z z0gJ-|@^ZPB0avSiS7N=Ltw|KgEb`ZLnMxACmyOqNFi#2aH?Tfsuf}pOd7G~jU~YP}uDcu{^&4x`g7VNNucwCMS_rG1V~Ydb6~)*|uj# z6GCh9G3#CR+UFnYl#Zu5D}*BoACi>Bm%)TCJG~mrbg75p(G9* z8GFHZkUt+gfq2!qrVY=Qoi~;yF|LX}Nm88;@^nlW z3KXw`jPIBk&adA0ot`a^)G>?a1o?*RKh>adce%OLDZ`IsTRdgD15{IK`=AZK>%+&* zEsc(vt61*b8S^x<=_C}GmMVIAt-+5+P|&=@edJ+06R1#D9ZV%@1vzw~!;d zq^SU8?cYm^54oBe+?BJ)Q2J08PK?5y^f-}caF6eFV$Zib4a<$#HE6v~+VgK)2cSd( z+xrv8AM$TQBtKV4_AVcBa$}*=V_}0s~4V5anTd*=s z&~P{I7j5-&&=tBC4n04Dpn{J_#{t;jXM?dFTh(lHU05_mHRg9Pfxkq4&^cOGV@=@H z?wBW#Un$2|jD2#4wU^3dU#%^{+l6ZBPqit_z-hs@Iz=*-bsa{_0wyx}FDR#6J6|puG#=B8Vy>Vf6 zQu_O9cagK@7mQCoKcg;h3ajLxAcDoSYq5>bh3VW;2Xfn5Xm?XkmyFLvKDej~U;vNB z>`8rzdheKtbSH{5#fw96-v{zI^X%tYLO0v6gt!AnyFDR6!pVJ;A`iYr4!f2G5;32&C6EKXQp zpxD$DqwD3XHF^ltS+$GS-goIb^^@Aj@;}{_nKF@(Ht^q^ZTxdRuin3$#bSvkqrG(c7um7y89EHTxH{wSLtbj>^6ZjR}D=FX~#i zYT?24L9=_fw+y}4s1~fuvOSyty(owChF#mgu=czdgkQTWL`SP3>Szvc|E?%y0{>Il zaK|<@LMT`>UI700D4pCsQkO`BOA<*7dyeR}yxL3$xTS+0=@~FHb?hAok!u@2h?(>; zPftg8_(3l=)|HP#ouVGXlz&>&Po-`@TFRH56lIk8P|z1B2#zeE^E$(x8o$oRL!#Mt z=U5VGlivtupO)DP7a=Ny?fbAp7k)k#Ev9KAvcCpc-p^1i?Sdfc%woqIDi1kFSQCo7 zr@oC%`=Feb=OKIhJzKn^@p8{shax%?E$-sqzFrayjima!a+9RvMbWN8Mbat1rA=$Vc?0dJh6Q@ z+R0Xm3R|kE(z%=4KkInGs8;=+W{_95HhITP==b^Eq%Se-RhyLQe~mzcYIvYqF?Cyu z%8U`Mq+cDY1~bEmIF}P`t)F)5UbCKHMs4HjRueeI3rBK4(oDYA{=A0NeXbp~h?eKT zm-+=>?Jc!}0=Wzs8B8ev=Ydg{(3=DAl7s~vpNoN|b<{17|$9Y5&JDQ&b`Mq!4}Vc!>WLBx+C;#UIi@uL!zi5ImGu@`f0 z+ErPZdgjK$_G+GYs^(MM4mf17$GZ`Jenv*qTjQ=8dIaEwT10Q9Cjt_BbGmp7(y%M0 zGcJ{C9L-9WO1o|;m>W}TIKW=+O3^K5Ia?Dmly)A+`Ad3}DYl=Qi%RLjLxX&_8cV*9 z%!1rPPj_os+&;HE+JI2OYrEL%Eh+`)M9vPQ z;~QDc)!WDlilhwb%T|z(d0^^qR~&}(-7@`ag16Q&(Fm*i;@7Bkz7wdgkw$9 zwriHIRvD?W^r1=X%CZA;EPCaa0Y^az9G#Cn*_xF0K0-Sz`J5%Yu_S%JMNeU%*x$49 z?(uUS7Wx%rOV}Ozq^rYmR95wDdb;9i9wX|S2n@JYcA=N4(Xi&J%<%f13&6fGy&6w| zpymO~%(ESucdMJp9QV7igwyvyWXEKDuHIyr`ppvP~?;KnYy^3r#tOvxdKi;?-I6=@xbB4{w`aDuVfFK z>&4!ke>Un5iG{b2uF&c~0lJr8O=P+*C&{rGRnJ(iG0~r}I(aA-4)0<(=f+xmeQ4kP zQx%KRiS|@%5a*An>M^64F7$^^N-E&G38xO`6(ZGvq|9+Tn@Evb_k7`!O4M3rPTVW* z4~aQwa_r%hYdL4F&!TyjF}zU#UL?ocQsO>8kq~+V2e|P0zx+zS@JI5KPGPHXv*9X# z%n9oe6)SZ{CvO~aC?0ci4*Ynmai42y&w^z9?-OHF7!3^hs@{jzHqIpbswwAo8ynKd zJ7D@uBcU2dyN5k*hupGEjN{6nH17SECq_kNcD%UjlEc_i(Jv>ezsI=i=igv;*9sAq?43j3_0ra zku+fCk2zpPQ?cW&5EvJ$`W2VrFg%J`3*^4BA;cY=+~7d_)1k2(EMTYnNWMRG4c7@2 z%xG{>!ENL*p)OrBVGbn6FX%2r7@3O8;+k@fVCwAtLhevrW;WnEWx86ciC~-+k;_Gw zqykJ0*G4F+ayw1%|7mvMop3l=H>0*)5Qv#C-7VmxZgNn0;5O0mb;7|(w}@n{5a+`N zFaZf^K@>Q5L11j*WYKjBA%}^$E$%F8X4DZSj{2-ACCUxaDqmR!3(pw@B`tuY4im&- tD%doEnD|HQR+`*6bz`r~<`MQDAP!zc!oEp{`&-H#HDxWO8sO{j{{h7pxXSC~k#f zhv$92bDit^d6FNw_Utt?_uR8&XRleYS{jNFY;tT62n119lGg!&&=DXIDm5nRlca!? z_DO&W(o)k?czk>WX$4wXSb&^Mu{12hRv*jD%hM*cRC&FgT7v4e@_>W0v-7+A2arb( zNc9bfSN-bWec#F%$hA5&G<5&`79?jkzw@_l;us`iSUPwJ63_-Ix`HIkL3X8!i;MO3 z^$rdWM@Pp+MMVt0wKyK1Z*Ttz2Gsri`mpzJiMUvt{EI0 zlnAQxFB+zxq)bjuA)YR0Rn3(A3?0W1$$;ru;3$Fk5Yv=9azv$@b zhsS4retyf#tD#L(taNm(b!EM?YrAKcpFV%??fZWD?_hNEX!^(6+vZJUx$wZrbJMH_ z7(2VXY>>OV`}_BqJw4wd-W1qd>V2syTG-f8^VT+T)7DR`-uSs6$3vkRTkOwGnby1R z*0o}R5Ezi62(9SEl-E;BJ-WNQcr&m&vRlHQq0HCRaVmLm%GL;aS?6GvU1X0o*K?MVv2%XvGQD26pBCfq(zyHhFJKk`X)-MzBr~7M|jv!8s|td(Kt2FR^_MUXCQcu9b_Wl+h2*T zKMxuxNo6^!((1Lp%`8m`uL-a!G-adB`ZCDpYQC&b>SP!f|JHqBxb@#4<9K`ZVhTrh zW?*`3;P%{j_+q6(yq|`W8&P2YLs%HAnBCgx;KStt#mKJPS>=*>C->Tw zlb=)PJ-}`-zHZpSm$itA54!%T##?`g_v&SU@|XM5W&O)9H^k+azP`T`7OouRvi^}l zm}V4;5XsqoT%*mTPBGJ5{Y2P?ga04=`sRGUfemyV(r@pQqyWJ>(fQv92^ySBuOW=84ibc}JI zPd0d%tT9v{@t28@&in80z1O4oRk(0ZwoDP9!o2cR`@E2bRGMP9uLT^Il zIz_u0$3FKuk1LCP@%ls*JsQ(26>oQx8fs==_r4HsRF><(c6ixV*kMP_(4lKF(Z$C% z4UxFKC)9N&07Q=;9QW&ln)~F5V}g! zJJF~Wp!ALg23APwpq&}v>e5AK&F%D?wxrTkMY^fIMnTq0kfPD$GQmH|g_2Ku3wnsV@pU8$N?Vu?MoCSS*eFViTPs2*gohBBH z*6y83DJTDy^J)!&yd|otcrJ6+Zt(@!hzHp4aMt_iYK0NAPmIhNY6YIj0{`}pnL5-q z#%XGuc?%D?Qb~RNMFv#d%g+s1BrZFSi#7))rR)6UO%JJ{(;K?fuDr!fBBDw)SQ$&* zOC~R$Y=7?ztxZ(#$oNyt`1MQ;(Aef$6tU*V6z3OOTTtXJWX5#=r2{C~e-u1ej^Vit zH{R^Dt<#9^?Q>FM?TCjp*|Cp#NMf@V-sHV7jZZ43<6lv0l&PumVO@YZ*^xW>yDj?+ zo*)DJs_fYrWkX3PHL8O!$F)knGoT^YR%bo*sA^5rQ;Wmnh$oz5YjI3|F1x()K?6VQ zC;S7p_DCd#WVra~$5H*s&jb6^`rzM60}WEK?Zi=i!R8Gn%< z>xkZG=z2b54$Cf`yji0-{z~O%x_72dP9;B7Yh*4!80GD*pMO}^<|8jt5oUE-83~77 zahd`NLz+Q;oF#;R)+wl6L%10*`&8SgD11MHLJmKPt`_=!&1^|etg;4%LwN;!^z{@6 zppEO{JqCA1==@CnWaQ0e3$#@Yh&@vPDJ771OM7e_5OBkf;#B<&UB;h1iyRS6f+3c= z;{o}gbJ~n3{!yRHwc4XiRaIH}H7CgzwFIl-@8`NTzb#|@U0Fb_xS|1hS%nzIyarWs zU3tAcvQPVut6!#0*%8mDdht;qZ!|sbD5uT_e|ZKpK_|-)r&b+7E1dnlUj+v1vff5C zz#!XWZy@P*?2HAPQ#nT*l2z@nUtAvpbOotpB4|6`7bDuDePG=s$UT?v`WXRs2!Ea? z*8u5XEp2Twm-afi=$uDzHFCxWkhw2G5D>E^7Y!ei((z!)_>1{@seIkTUzG-S$`LaG z`Y!_TX`OoBV`fh0ugzKu5xC#SmCu?Tg0WXwaTZ5-}nI)7GjxfeS_P4bf|v_kXpguG&Mm)8`?*Q(-& zxCrM z>=GWQ!&kDLc~O*$7J!Rcn&SE9yGbtXOB^Xr|Izc}0x!&<#Af#dfdv27fX~RD+LKts z!ssEzhQFzc@cOO2vH%BWUG&APlNhV!<_4Fe+Tkq$hNiMsfB4&X>)Av2qGTu*Eg$xH zR|Qwc#OGn+(A{DLRz*k&(!VQ*%-~3H=2wmV(~P1fYOt4kJlFa9Z}-}i_wlfL0htc^ z@kCR$UbxFIypO6tJ5qe+W+&36NKr??R3TE3cGT0UumRzD|3?lIl(3tMaHJ7~=-!^F zbIq)O`bbU^*&R0C{_b&)%1*cDGEtqMe(YhTSKB^_>t^#HbC*|UqKMe+ADgp%Lg}<~ zu7h)QzgiJpb1=xg9#(miZ~~$4PilsCke5t8x&U=aPziih zp?uNlyPiUde(;(QnjlbhOZW_g*; zdCWDjHR{iPO|&{g5nbMyphtSa;TbL(N_G zO`HbDV{%uAh$|HF473{5WABPomqiRMSz~sFU7bE#>gkw$#lsb#?u4n&8oV(c%M*vk zP1{v?{QPG{V@R&5gnGLxaB>@fEmXH*Z8VMgvX?%yp}F1l}}ZhRYl<9NvDJ@?!54g@*uP)=~C!@!dx z)ZS6>FsW3l3M+ei(BXwi$VCBysgSg&_^ioUu`pBh90?+ibrt(h$8~6}^dK0wC>*BW zG@`-{A{QICK05M=^Nm9JzaD8Mmm1y?qZh-#z++=_Re#Jo9tz^DmxRz%Z-|+S-@<*O z$~^vr7N636^xxNkJyDeAl4$>z{?o;#6AD@%D0#W#78flXA1JHsrIE&89#xA*PFPL7 zYE=O}R#!uKf}rc(#IPV8LxR*Zin?V(K}_8_BF$BKAKue|=lj zs@9w`@+}x#KWC{34&83+yKr;p+HLQAFkW8f{y2M-LUM&UT-%&Dn~jqN{sH!I6NDp1 zjqU%ul=*9%EKs54)@4*3{kdO=Eb}1h{tjZr`eXFbUReL(H#lpWi+c>6H^DFPn*(Gd#O4v(2B>bgyV9UILh9Q_C2x1=~dU2!}z!hR+z61 z?O!y^*Rf9MDU^Q#DSf3X>Yb$*-x>BZDDWQJx; z7-<@4TtC<`1rLuvJ0HfOol!q?(c}2uZ85a1p zZejLvFwEw=!>iSgcmbwYVu`$?e_3Y4vhU5=;3hpw;320B{QT;_lk>cjibriK@a>B8 zAyz6m$~XBk8*%Sv&;DSu%=E5r=wh2V`fG0q<2~-S?d2s0c~2`%@_2(QBrDvMlm{p^ zyU|ocEarbUzAtxYip@w_9v7q*xt%<&o8!4<``13rk0s)qZw2??+n7533{kvR#|=$k z#+=AjMwbOOla5M%KWZPWSKy#bbXESu$41m&$&b$VhEE>1$MjPjhV09{s%>0oxr07I zc+qbx_1vt=M(C^2>1 zSi}(`VB;_3hkI3>@V71Kjzd^fjGl38d34G&ur|T|%WKO~hLV4(L8Eo6VS@Tg23oem zRlX>#!nc&NQLHtw#IS>mn4%Iz+PH!Z=7X`!-eI@zus^)ZS?t`nxn31Y*!4|l6QW;< z&6;c>jVN2r3X%4x|02b?Uxav1%g?$I7_*Veo!OdrlY)47gCif+JlW{<4|+QDFQH*D$>C4t}F`keh=y zN(jH2nB|%Gp7d)yJL$_Y0h?6Geuf^sMv#c%Lf6mLH7u(V`2GlPB_X3y3TOLHx|5Nl zr=Z0oWVs@En+#0Bum!GR7dU8vt@@O!(FXI~^CLuRe%})VX9;khFNFH`S|gG_#P`Zk zfPH1K1vrOj2>UJ$u1XcsQ-8Gd#d+c+L5@@h=fFjS6U+_%QMm+jp}XFLdJUdTw2Ky8 z@ImbeOp!&{6%(D;B#0T#?-KW@`<>)hbynHT{>8qdwNN{I@aXYpM2#br7(9E!K!Qu- zM=gR=VV$ms+iyDXd(p?#4Rc5Z0q{)l_a5yTRe>H3fCKP334-~0@+Zjfnvl4uznuXN z%Y~nPNL$~)GC^?`_y+d(V`sqe`$_oFk0xX(@WEfsgs)IHPEe!AdSDtYgq) zqj8g#T6Gi)(J-nJ`)}M5X4Tqc+V5fWJD<>QmDO|BdNo;$aj5hcv6I$28}lXBQ)~nc zq~?mqy~iUS|2gd2EJsJ6CiifwR@+D#LJktzR%TE}D z4NyW>55l6`fO^(^^q6Tm34cY*MhRx*=9}ET=YZm#RqY&tU{_8Tmgi4qCFQw3N@!r= zdu6=ILZwwk;7_L2-ROQT@RT*{SVjM=m^FnAqP9MCVAfXUiXQR$8GkQDo_ci@G73p1 zK!wOjteo!rY@@9)6(HS$>JsK&v0EVgO(xPqKs04B1{qoDDq%x{^}(zp;IFQCQ?WoW zlxIw}ky;e~gZ}!QRW$j7uD7?wxT)rph!X>g)Ad2lH4J%lL5|=?@D6_ROGT}kDDnYO z^!$LjrE8p=J_oQfcE&WjOrhq`0_}5nwr7?MQUU$<4)VN$4TUE=j)-_~3HJxQ6%<9( zux7bf-i}X_lji3C%H(qAK8NtaADyO^oM%j}2u2}G2G>04orl+ezCQ>@4819>Ke|)H z$`QlGQqZPPA);Yg%{T8q5om`HxC(MTyFwC>$~L0;^}-~U<)Clh!Euz@DP0WyxA$W4 zi0>yghiZxS{b+Tr>^}Fjc`PD9kRt4#2F_nbT2e%J8D2uyeeikU54$H(-^tTT@Q@@d zhQHKz(sFULwxU_+W=``z>%&u2IKW0K#(zpRel$`W-^%|#jb|m+I6&R*{kZc)+V}tL zHPW?b_Wlh*k zsd7-{de5&s?8)4jedr^RAR6#Rzh-;@6G?v|u)RNs6;DZr*9frP3|c@&?# zCqF7hunYdu#a|Lzl#6<{s?C3=&PvYJiQip=q%N3x=2=OO|+=6b?4&;}G4f|H0Tw7BGFu21>5|QrTM^yh~qYX4R-Y^JXNl6uS92&Jl4;U`J-B)(teoh1p#>xxmA>%sQfAt@l}pu6|k1MgIlz zenvv|_&duSTD7k2$=wJrK=Qr@qol8Fj2#0VzMCD{m-d!UqJVk3F`B>{4KWI%%grG8 zdSv*^L(E+Iak^;&>uN3iTqEZcW0JG##QrelnX#c0n?*EYi2DEBNBKOv(TOpLYpTU2DqY<9~3SAUJ`g$Ps=7w?jkDyG<<+DI#-;nvtdAzjdA zHNe%>+Cbnrfiih)3cvFI3+(R)!W_iH09`J%A}RTS&EusmL<}E6dxO7rI0cJ*8*wTm za6s*36#5x%_`gnZKf@Dujc3{Tq5slvg$k|GTp$FZ zcdsb9f5#49*Ly@&#v^d*CT0XUnB)$6ymV_y)k|ItHmaXM9sLVjL2B#DjH0z2&@)`$ z*9#sNpSA?+*m~7+2l{Ur8FujmKF<@KZ_E~p-*zNrwcP1ZqCD{Z*YQLxir^BG5aEdv2gEQR#tSm6BDPHo@B{fUHU4Q%-vVoUDgBd-4AD(Z5MN57tEv2 zD$^&OxRiu9I)9yo(|>GR!>A9B9fYOK3x0dw`6u=GO`i;R&H21_{xN+>d9dYDM^vWi zkz7q57lbFt!G&v6Y2elSWpmDRulqXO$2}u$@lw9vYs6zg-6ZU`1%3DXKoM-SlsuM< zR65(J3MJ9#RGeEIJ1r>;N4K-aa7!#lC`516Uf;T2WyS%kK4w^_@DseMzHo5QYJ&bW zk>7>uQWhh!_Hw;`l;Y+#FeC|~e}B~_kSCG4v|57v5!#pAA*S%Vh145rx{(E;`!Y~> zTSLTmC9!E9V7{^i1 zR)67zm%d-&KotLrhz7$ zmm_F?+%;_}VR!JMM{nXM?k{y`x_D*2bTA7FWt@vVlr5SvFn@%O9Ni|d4ZYjJ+36ua z+W&*~%&2tH+8zq~-7csA{P(5tz=vqEBtY=c5n>QSmR&`R4#s>J^!^tsrw7-$x=iK2 zn@qlj)X;uaVpxHh*EnY(&J&8inh^H4@nPOfdA12EzZw>-xk>(nyrwzx6LcOw8B#u< zuR}$cDs{z6xbp`)zV!H{UyJ<8Ox8}p7?Qj%wt@p`wGG=yu(&kP0V_sF6}3t-v^6v1 zH#X>g;8^zjNd}(Y3_6oOQ^&e`h~-A;GBC`Dq9G`C&$uF*%auy?teN)^ zcm;%NOr3NuoSa#U4o;prK)|l6?xf3AIGzvZ@77`wPoy0#c@DF_n6ciV{AHhQt*t-+ z88et5!R--PHU-9Dk!0o5mi{7nGw)I;sT46>TsA<8EJ?rl-x$S|Mhwn*7+N$N1a-_W zw2<_qi248d>x-?@z_0S5cW0Z*AaleTqWXMfsfJvTl-x2o3MCEd$MN~A_}Qx|@4eF&8O=A|G%X6j-t}TmMiUn9GA_E1 zir-Bl)v8DR)FF10;wF(!ypZ&c(0V^X^@$Q`%HKA``XX0U8P;*{^mR^a#Qg;}9?w6k zt1c@sZI2yIWP=~&^ol4>mVUR0Q{}Rt1!}r7H`cxTFej}t(cbnP=Wvv=N5|6?TuAcVTK|VvLiDFsRhrz={-Md(5MU4t_T)-+@D-$G zxfK40I~x2>z0;WPWy2V0MC7=<75I(e`uoB)CoX$$B}g;hbirD)LYAia$M@qoh`b2G z=)M#7-4*C_&`vE%SXBZ~umF8gJ2P2SB>Wqr=aI0ru*&Vai`(l;F{ggpRXB`JYBl0W z_za(UG?M+bN1A$y1P6kE`ioahHZ>8C`Q)2dKf|O28WaAi?lOxp&VPdc2=-RoHHop! zCBz|@8Dg^rXT7xS^K_ub$Yc$z@tUgJo+}=WT2e8v;!A}BtNO`|>$yC^jxv$YKalC4 zMc`%f-0dn@N!g?`gPFmP(pq!_9&i?wv3^R52NDDh#t9V|=NF{n*vd$v|KtQ8*!DC8 zVz3Q|U#tJP06EGgG%NlzC25qFN17f0umH=8U(i}cZ4@(WFh=3ffPu@Pwhmb`G5Yr# zoR(kk`gc&E!elfUrK>+Wv4rg9_O^7u9o>{p;f$d-7SN4AzE(*N7NxZR0(O#He;Mc> z2A`nXNQNKz^ywciz{ajDj3G230Qqnr(FbWf)50BdVggQ3<(dvuuAt*vi7o}0{xdtv z4~w4qO#P!d*qy*eoC+J)$65zTad3fB0{ke>EERo}?J(Ejl`S+9$Bw2`X(U}63%~-T zqLBpBo(CBb8>m1mMc|^O@_`-r{IA(dKkjB2)^E&@ z|E*Lx(l_1joy_lrp8694UB?`1nFOT6t&wuW;xXKaC57dpo&u0@27igYdxrS+20W?= zZRX!{5~FXdn6LtGd~{s+{&^=2mIu4jh1NRyq2wnY*P^53?7H0isVT_@6$Pa&jzf16 z4tBbdUjg4P6sdc#>~{amjTk5O3D7 zzCdXj_Qn|;O+vPI+EY4v3e)3BQFIyN-fV@ET=Wy^rpV>~5fn^gzZ2!IHY_I|8|MV6UssVlIhN-bS6YQ*;f-z1(O9!&Y#pz^az% z(p$<5hh`{=^zQM(TQRB0H|#!N-G%#30_lFh?)*1k*T?jl#shr&_dOGx?$@XB9FBL* zB?TLj0o(RG;)!(gJyEG8nH~BbXMN@ySb*X*5_T}tsU+fc%4;#6mXbM|;%?yjW%tbT z`)hBDbyn?PKhIwxG_$jsdttU?`jn7j-VvP_+9YNP@PZ*`XwsM6zL+w8odQ8V!X%v= ze_(l=G*(@=t{zFeNz$!x6+Yb{Y~ zM1PfhqkcWCcMR00bC@iJS;4)#^T2^|Q4|9dEJc(8K3k)ZcCjFWwB(ht z_XER>i}))mIY?U27Q5OHd*+&`r5HX(1pd19f!$%pt{ul9e=u$^Cfr2DdN?rbF~YFt$HydIMsINv@~k(9rRz<1$W~j9wP}6q1w01B`XEB$K94|`wBcR zj!Sk$9dgALcId12c`R=5XF!8kV%qZ`l@mPK{Cy~3;$eMZO2?_5POmp?#_E$xBC=}G!I@t)R=8D&lo2eu+RsX z;NZNgIAU;7X5WY~Xc?g>ePy<4eT~hC!5DEIiF~)m$di}h9Sn}gY$GH3(D<#^8Fn7c zwv&uie)FX$GXYMRk7Fm{6VN~YX$6I_Nh%SJ ze#A9Q#}*$!xSIBkka}MJwc;!%*x%W6Ui|l|N z5?LZL@6PtJ=T;HUt#v2{-r6bX8+8eAb?3*v!pzL~ek-?k!>&85srf5L3lFANU9}T# zip}ABlIA{7%j|#l;Zl8Qn+Yhptix8iS5RP9r+3rx>~y_qA`EjARQoOJQxiq8Nz53O z>%Kp{YJAtyO=LGP0)^n2an|l_8IQQ#b=51FPk#98sE&A)nYIdo0xtX8M4#sl7H=-o zP-c27oh4>ZAJLSa_*9M_tna$l3VaT;Gt_vw(`c_M7>A|VpBBdB%|tJoEboL-$|ZBU zZ@@_<+Ouw-u4emY#Vd^QM`@nA=*9gAlnbfCy5diu(1z_tk-fVYdxPd{?Fy#*J2HoZ z;Jb^N^}L{m3$yO+LP^|y25B_A|0N)wI+^z1<#I7Fxc#*f~Gwe?!5k%;n*T3yhq~su!-!gXLvp z!0vpyAPCL`&ygt9{)T9UrTxs1k3ZMjcbRtEan+cg+8=ykhQ>!CKQg4kg4OQn5dD~f z%j;Qh&xolM|17n?qg9wofKP+Wo}8yCK_$yWcmz3^vW1^{im?L{{jkukf%#6?>`!EX z_Xn$|q|(8!v;RTB(Wv|!(q^>p|IE3^3J-D2tMecNmO7gdV3~E#OH;ux;x)^L4o{9q zBsJUiUzHxkg*Zd}QZEE-9`^B=q1NAx^lK!dR)*tIW4sM-5lR|nOAKhaUfbOcK z(Aj@oJTB~Ql^?qs0_$GCZ?Pe=&Nh3%gNE=AJjO;Dj4%mpRhd5r+Jb$+eje%9%~mVd zDTOX*(DI{qrd=p@5CLuF)3hHHtmZ<0d!PSeqTuerOGaApf4H%~MR~~ImkR7#u1Y)X ze-wII_V3x2*Pe!KhQpH!Hy8F_H%&aNq2Gu?(7`_falk8qB*J$@8}q_$IAiy12~j9Q zb4@7MmTh3Ih2;QRvRz@2Cq4YN-t5IZ% zN@+1!n4R5y=VL$^{8eXwEBH9fwC@BDgRv*((ZKR3hp&f0OX0ECiwxvUWoigLveff$ zT0;d>gp##jev*0W+P-PTHhrE6FNN!<6A1SX*+mPCLh>EpSF_Le1;TAq_4dxzs zd${y<_p7NEj+d`37C^M-!4AF+>79NfMIpHJ-PeOae4vPs4J==XHA(W(MfEJR(3Fwl zZM$5T^JJIs@~}fB?n!;*ZB>gSL#_ai(nG*YAw)QS#KTw;TD@ zIvwXjhxo}jCFeH!J%qD(ZW#=)q-8Lko@Xia65#FaLn}z0y8=;4gsSO$;~65NxH*;g zN1025j*3v0L1QDHfsw@Nz8qMWNTiMgO?c02cr*g3J4*CQs>Y>?*+M`{DUjv#n+!8N zK?c{^c<*;HqaGnm-rxBWpjr_EPXq+6#Nho|7tBI{xoVOSzSy#Tb1jaeY54bPBpRJ!cBs z*9>$BhBf{ap#^+JD_Q@$Hl|sfmP_)5R4O(Pi8v{t-a7K&%3{O*ZzHV>9scp*v12`x zY{~eMjogC%ysbJ*XA1LFq2qTVyQdg8hql#FK5?&U5a8;LrQfD|68K@Cb#j1w(Yu5ZO~ z!T0ft<2kU2ZHbFnypvw|&}iOl8h7mKsi(cMildZBBLVrB&$BAmZP~y?NUnwKd`GTA z)5h4G>%)-AqxNlJ)8h?SX&)*DN)T-+f&UE0VFt9JE*e^^-7g9D!vZ=kcc2f^U0()0 zDV~?WK7sJGL?l?h5b5C;(Z&)qdpNH#w2Ucuh0i)pGyKecNv~3W{(C5brrziSok&E( zEhkTIz^$39bi+e*)^ zbp|{fK?)>3zGbht8TS1ZjcuID_Fq{N)W)k0J_95~Us6WCBYJUxD$6}US(SS$3HFQGO z72b*%QB1_?sC))=y<13&VzYLhHuufh_L6_D)WYB={D%=~p1>;43F8m}`7_wY zQNX1Koi~)AxR_T)rk2-dl0!7c<53RZD1b6<>saLCkg8so-umAdjc>3{oI?mOo{g)H z%LZ@dRyBMRL(;nV-Q$;~@@0*Y2&AJLBX^|&J}MSP-@!&b)w`!`;Ph01eHR?!%;T#f z=yj{KuL6FtOwCpVxq4ZA-q4>TI#|!50T9h=L`>3900_MvI_vDW?RHES8RCUe3|)!H z7e0=_&(UixxIf+dK*{xq3Qll*(hda_w=(1x!mqdsZUkbYcS@y5TAHwRGfLjq0Bb@& z@d~XbBC_TykB1?O+ONbj`!kpwST!e&8`LJJePnz4h|n1kkPKWu_n=8R*@^~np}ga^ zdkHwmc8y)?nS?!<)Gz@1b1y z__qa$&tKV2@ggWJje(OA9lGZD>}NpO&)31|>gKhUR&9M}C+ox<317yr5frnyl&Cud z#iZ8i3A3+>3IAGk=xqIqEfy0+5c7~=h(<>U0CjUkonoc)K#|-pa>KkX3oBuw&-p7o z-~E7;OP!$!AwKqI5515!+>bOvpDnL>gGm=?{ET0yV*$$+xpm`Xxehy1Hrq<>+~AFx zC)f@3)x;$^F4t!IyREsxpO(-q`zS~a`&H)Vi%D8EfYlH<3fVOmVBqsJEyC4+CvO3w zXl$4#JWOT{d_dqE4KaF8m;CLBoJ<@|x+1DI#Ks{xD`Vo|)wkJ$wD-c;zhA;AqZ>y4@ihlm84LRRFS5`kT z;kx_8Dx@i_o*Q#P^n6FCdnz`0G>W}HDk7M6`&N8?{B^%)ik&l!Z{(N;P{-A7G1I_9 z`R|ue6SErL?7!tqVzEUKMaM37bW`G0;zzavBJ#0T&vz@mxiN5_2m@H>L5Xh9kn7u1 z>es=&y}lmddqc)cmZUW<@Goy7p5dn89_e;#7fuO)U%OFJ042Ol=q`7ulO*%WY@}<1XtZ-f zNl#G;HEMr<+TNF^U~-ZKu73WlL9@;#{rd?@qJP9Xm5#oeal|unl4u~k9WX;E{nop3 z*TpEEA=Z_Oa*UU9woB><*8;)V0zwW9eXCZwu4Py&EY-A}mavAAFoewe-d65&3|w=4274kN@QaBK3?^&NHes{@%wLLhg!I|jKj z5Wn`}T27*P<3#4N??gw;4$1sdGT8Ly-&a3yOJzUT1s+eZiaNoW5GR;0_@QZj)$U9h`EDzRobK4t_<;GQz>8iFrcPg9nR zUz*@&Or*V6wsr1ySRou|_>`$;0;gy88|J%ePu;Gp}^2U9~tAVtwC7+Vqu_orn}YGL5?GRxLy zz3EE-Si!(@@LkMM)sw8svNg~0h8+y-%YJ*3+pt3o<|)x=uz~t-P2Fry0uHEwpiSzh zKA7nwuLThT-beywrPJ@ zHrZsD;vXjaocJ-6@*PG2&j=McF}j3D^{4u$GOOZ=`iWYjEfJiFlduVXS~DC6#~en>TFv7;%dFy z%uf=5%!77N)ksn5yV@8_spyK93H4vCu+i?94F~+>1QIf0lvt&+LK04FOIK=NYp%C& z9j_!_5j3wRWxG4%i5g3ol7+NB@xTsPXhWEz{*Kp2IkQBgKJ$}*3(EfC%Ct$a*n9cw zoMzH4fRwB`Y#ZcXRf0Mg%Q4#a;XQlO5=wg~BQOdwfpL&-ZT%EK!v&~NQ#mJxR7w-5 z&L(JKIKM~#u>KuKp{z661gVSk`+_8>gx(_+KmC`0JK{MH9sl28A(UEY_jOanO2p96 z7xFN!_gRKkEiqq{kR;HVSk+SEuPGuKb22HvW$_Hx(@@-EUKMeYA>5f3{&l3E5B<`S zRS&J>@m&2$Os3r&tK~dTe>*Siztpni`YNpErE&umNfBxV@15lnol?X=sJTP(O@Ipa zaXx&X9#rqf$K1vv820knESZYf_6k`^ln$L@(Rmie@n1vlUJ@{cFYonLX0Ul;G&dRU z&3Fh;8?!g%Du zTi(0di}I5PGN#6Lb&Z6a7g0wgYf5O~KIK<&L>x6X*ZB<5nNUxoYg*22qt&#jeCCcc zBv&C(dVFd;m;#>Z(|!Oy)?a&~5o(u^bvTt_?JXb2>)l259{Co(vF=V(9b1YN;I8{R z+WBy;tl4{F@-KGFZ9sXGl`H?*7iw86g`Wa6Qhv=*d7Q^vrauHFUQR_9ulN%sC1B}|9B3f z(x!0}5~B>LT~I+IHp%CYmRBTusx5IXM$T}mNttFBhCU$KZf+zvUjabt9Fvp3jV7S& zHg7QKl-*Lw>5OLj-l=sHKc-(Sz*H2sH6fC`Mfemr2)CcA+0zYy#nDQ zw~JKB=T|hbdfG~64UP13SiQ`FpW0DfxNn6#trA7oC%*j4!>7nRNxxG1Ag4Y6L2XmFPa^-e zkFn2g9Zpi7teGKUKU+_sub>WA`9Af1y+uAO9zdfTL}Q#zB}{DmoF@-xr#yd31o54g zp->(2>(8%40T3}4|AR&Ue2FHpFuVOXt4dgq3+=<8@m}>=ov`@vgnUHS>PA;rX`f+h z+b5QwiAuOD+*a;m(1brN(x2b6!f)FKCHwG|BD1qFmC%8R?;pfuczJ3;#VaUI%+EAz zk6=W>!pZql!nvJW`+XHqXY9ks%@p*MLEiFj8CF+Yk&vS0xXPND9m}jY8dx>FdBdqu zh`p>olyN@l!R9h*TbpS77-+fuEJh}G z>mqHBq;wzhgf{B6ebXR*)^Nal31xjx#&8;NXA?C8f`ilKi#@5WU#kyF0Lm(uaulsk zF*P1qn#rA$OX{74JayyRV%(4O1OoOMyO!UK3m4r)cQRu5YvakHtlxll54Gp)uZ^;z z5rvXENQLSSijl(jZ*SlETuPzF$hTFb2E8Sbr6zwk!66ozq2D`&+<17=nJx1tfJJCwqs^uFlZU+rLu0aM zaYH?m+Pj*c{FUvdU|pOC$Y{CI4-3DM#~T{PUUV-YQni*^2hRL=7fQ}W4%rhu&0CpE#Rx*~%TY7WB zMX*MTSP^bI<~o^r(l(jt=fx<<7MxQZo+HUdEp=$EC-<5<+1?6$N0`!CB5m!y(CgxNV!wzr z-Xb+skLp*}U!DGm7($vkD&XM%S1r-ApM6W;Qptu943ZN&-#raZR~cp3tpAGyQo>8uUWo83R~}YiwVxLF3pg2h%u6VTJDn=e zQ(jv@hF8wXNrK1+!e0A$HI*RyyxKYujPeKQNmQLR{yl|GpWq}{dVqOi{y@*x2IuJ^ zxi4dz@stOA*wh>tIUamfyx4L_wl>NXM?Rl2V}FyZ`k0txt9oGQmUUAUneAls{-@Iu zdyH=aAa5!%*9cF}$uo5!IN)9Jo!FcUX3+p8U^4jCtcS2x+JCWtbH$L8R8-1{wpp zvQKnOnZ84GCxx?e%l>-~ky^VSyq__)bAPHt%v6>n=i-(PocJwf$B7#KR0|f*Km)0B zl<#Q>w#2Dp5;f&FHDVxh6lR#~G8;ettF8B^(c{Tr4u>3|cq%tcHw%0PfLZ$zTe@Yc(=kvq4mTmN z*#Z|GC20Xo8l}sx*@L>iiA*zmX$~{2h#(fzb%2n6GZvX{5r5J1O4ie-?WH*+#XQ_V zL6RKz4KY{2L8HU9O=bylz^bSIf`JMh*I78O@%aJEbRe^yIx6ndI~9l4aumKgq%V;P zUJ)7CZSV3zxPDiGmlcp7Ci`e%Yu}2B?hDjz!FUY%dLV_TDZ1X`wDLf8au1yD(2I zsRCqgUYJ-saJIFDJ|2y;lAGf{Egs=@uheIm7ZoQ|Z1KyayTbF19H#{8zx!WwPP-&y z7a@u{$uIK|rPFYe%GTd=EJI(Mvg_&vlcwvzEI2)a7rw!Mm#gdRtDWrR=3x6-j|@{B z&9Cu%def+8QX}$#Mis0&rDdq{oNkji-k$}!|KJ8@^B1l3y3E-Rn7iWf)xn4Dn<}v? zTN&;-HaXIqm?;?cJq$jeNfPxJeJ@7fYb8b}TktiZcg_TJe}3kM8?Eu0v0=VY(LSKI$>l5jU-qYozk|7+u&L_OQPLypHHfaZpRQFpLT6RWs}Vs2pl$U|(4ArYg~2RTJkmuNq|O=H3=dRE;# zI@gIn=TKcwk)>e#0qtQ=a#Z`2?*=W>rEb7}wdAp(4Pa2n_L$UN^{wRZgE}PUeRcBr&FTEpcW-MHP30j~ZQFb$h)YvQ3+%~zrxwjX8R{}uGv@{jr9 zbTdJO5+6>b@JJ!tk#7bN5(lr;7};J&`6zr86MoQL!q<1Ra)H#pY-gMEK&8>ZETpuz zG}FOrx;K~WM7Mo9xC$(N)Sl@?47)XLwW##{Y9jguB8!_lGvpik&+Sw3F)P~ zV+BNV=|)OQ8flSkE-Bp|OQWD5jl{d(-}C-=pQ$_N%sDe>X3qJ{@XJK{mujI+w+UC; zB#lz;8-Z_maGvJm>6zr=VrX;)*(```w6L2z7SCyV-G1a8WZb}W{ZmQgVu5@><_aoN zZ$T1tttcSnYa?)QF_-ZTgWI1LTQQHNlqim}L+WV;7goaHZdW2B3PRRRn?9Lt45W;iC9T%y;WW|k&n38LIGba$DP7{zSr7*Y6;Y2Akwv_iV@F(DAjX>wq!!snc zD+4c488_PL>T+4+XTRvv3k(2{sz9F4+|O1$*xWDy$Li&I6ugVZJg#Wj3HNKEf>yr2 zq*GRzfGZQyZ`V(j=Z(O&MPj4v!kZ^}An6Dcf@Oi^x#!>O4CtFp46v$TJyZJ$d1R>^ z_3$UPi-b>!wibMEY(hBWcmDjkhE_}p=puJwV)j^W32bA+Vnkx}oQI+w zT&c6YId~h+hH8ehz?7r~3ihNOEVB!aiBXwS?i2(5``xOAq2>kHzCyh&v4r$$Dxr=_ zs=Royj)YTXj^gqQG~RC$cu8FP?jUjO=1g-_x@>Hoe~CBQi&~k09%l17huy@{EXDDh z{AgTC({GC`j2HQ&!0H$=@Kyx}|1*oa-!RIJE~#J2+>H~GGgR&!g1QbxolZ=fr$3{W zXV~AWkA{cp_jTYd`ifI=JYj7d!Pjjh;13zvXi-o#Uh;#18KU6wm4@#pX zK#0gmEh-hiE9Bz87o}~uv`8;}R$c#sqDI4M@`?4N3rl!gOabcNAGYH7a8DTyV40(a zSNr@G^!%q}1dw{5=svQIeq%n}^1h!%pVfEl>ocLZriwtsc?7weN=jI1!HVlu@hHEG zg(i_Fg)O$_QsqD#m*rJ8Cn3bSW?o-15JgK6EGaQ-%goW;+Zq!t#T&Z2Slf((09$82 zjKP;{Fveb2SWBa#nwUtNsZ{8ST-3LVi8@+X z)|DVz@?K9>aELJuu^EKhchEslUrw`UndT|WOToi8-48M^7DALG@5o7&fT}PRXb+TF ze)4doujcPo-s@P0{)+hs!fH*T_~m9UHcuwq$MH~lKV`Xcfj+298TfCtc(?iB8>6un zl#PZ8cX%K0Tz^uj`NpE>*rSr}x2vWwH;2dP0kGD@flpqBMC<+;Vq7l@67uaLPoAzi z-nPcWjM4Jv#+Mh|=yB@yv1;UC=1^GE(A7LgEWD9r@ovL80wFKef_eNN&qS-JYDzrV;JQQv?n5@?dWcy9&r1BCYxg9P^` zp#vwToJi`rhveTp((@3AGhnde7Rb0pnHbzBPV3E)u+)1T%|c`$niC-v|E^Af`717P zn;9zNTJEnCm@H_x#i+kO2T@|t|hS`zJo^^9SS(=84%XQVXjr27Vu3 zqNC}A?@nZYT7YzS7!Uf&(s$Pv-HI)$2d+k0H>OTekR#dAw=W$WcT(Wz@{V|3Ml`)% zNPVLR53t9Fa*S=qi%0aal(;Ubr`LB+1Zzx;h>$LMg{}xnDrIg|YVfuU8@hH5)SpwF z5s?1E*kKrv!rVX=dqoYgHc(NTqNk62KCxEugpaj@jWlBQ~#CDB{NYz43)Gg5>T@zc6&42u({em_}o*r%Ji*KH=zayIH8+!rUDHM zVRe4wRtfBj;&Pb>{lWwOquLaCe{euY$Rg~O*^op{>FfhE#s{MO<+Sj0I=;BkX#wuj z1&l1)Vu8c&K&E9Ao!N5IF|yCvE>ji=89$RkCoK!s z$UMuu<)?9hG-66n`^ zuZ(;`n?v58?H=q~r13<=U;lr@-=d}f3E*eQO<~5lkGOsp!7|KE?=*H(C|Kn|5Yw7MIx^Q&gR-oLL_z#*i_XSlabOBl;L~AdQ!!iFD zAc{4;z9W~L%xkR(F`f-X*lU|_6gLl1@Dlr;W2=K+XcpR~Sg9K-GkAiZ%?6fXKw_1C zy!a(!|-%kPne#JK1FDeJYQBfP%0uOv3=8Oi4vr=lg=8z6O)3 zNMSmnOJ+W=K0;Z1<%_T_W#H~*s?yep=xn6yGJnL?&d&xJBH#qtUovcS2gO!rtx|%# z{!BDE0Rg^bV^h`yXCJ)6dsiAWa5$|KCC6=qRa@fLek&`L4 zfYK9&@GP07ky74i|BaAB{z5f9wKp~MOtQ7q7^*(Eq2dhLE?*2mSxeN072#o$&>(YY z3`Sazrnj#M1&(c)X?o{;%w2+WBmCluZw0@1A1~)h5rmIp0-g7Jkb8!?v+I9yN6ytQ z?BD?w{ErtG+Gb4((>Gg5-R7fS!u+qcU(A|y-hEm#qh)fLfdjqJDoWuVp^5E4(Jwr| z%^(7(-w8JYOa%fw0HUYXfv~BcCP54(C-~U{Cdr6xNH%Xm=a{|x`cGC#8E$Hv7oOvI zsYYoW#iF)+vU?Dm3uI7-11y|A4ZD3Aq^o@!!!WL@sy&&2BNHT)nd)~GppX{Es_Ij6 z`&7^ebu8l2aSlcc1}@O~;rz!*{MlGYOxP@@dKDbCB-M)&s(9c*uD3|GU&j(4nV0~E zix>70Rzht4t4i3Br4VXD3(@V@JQ$%x{FqNs1~ze=BU%px?Q4Cm?EOBVsjJY-69gnv z%D`D6%y++DbTq$704_dtIuoYD! zBiCuBJ7qwu6!z{zgBVnt6AxfWp?v(0@mriSgl|M|`yHy=um9`${q6a`^?-jDqg&@B zXnSr42DvZbCeEpTlNwS!+u3*gIjv;g#BU2P81;hS)g%-SAxV_wzfU)cfxl2gTOSeA z_{56dFPGF+DDH`ZQo&D&8V0sd*fbY0Qe010avkEkT?J#h3!K_Ba+7enAs3r3<0C^n zF=e}7GnsRQwlyq-poA&XOQqJ+{lb)Rxqv?QNTRD zMciK=(Izjv=#7GLlh!&IU`S}$nJ!=eQvy#4wLim#cD1b0`7%*~(h2lFhcrnw}3eU>5_AWb^n5U4H*K zagJXu<)kI6+CuXf#7LT~$b4vyw?Lwgd;6QcRatxYW#!r`SnG_l|{c?%<* z7*yBGW+tG_CGoepXbgKHNft!U1P4lgJQ{`UE)ta0V)cd|c9$&LlQef=hhYZ?OZB)? z`7?yTs~Nz<&aS*=tLWp8k~nyJ=grUZYMBt}oIZP$eTeQ()y9u6Cs9=lmNXO1Z1Vp^ z%08jDC?FX|ph8M&E%)wtbRhBV-xA(JpYW_#pr{w(mHTM+5 z>e_1HY+rr%?p3+^IF_iBeV13e31-SnsD0I9^y#0Ue+G_!QJ3nOe#o4)w}o?uyv!p_ zgfk(P^VxnQ7e@1yEz41^f<}h}(8FltKWL69EmchUMUWT3-*Y?$4KCsl?{&lhI6c(q z4rw#E^fsE>1|GEq-?<7p#`n0^?vc{=s?CKi739M`G9k!oHs%2ARYJ4VB=c1+(45Y; z*yIAGzLm)?`1QFh#G0u#YO(dtff4p{Nt6H_u(dc&s~s zH}4wcu}39@h&_ZM{r=F$ce%!2@S-)g<1?Le%Z;YSFPatDZXFhUDt?b|EmuX!vp zM4W`0^n?QMRE0;YeyBUWHlg%;3(C68BQupcvfd2?Z1J-E^pPIN)Y30a9)tg-a<2>b z9MkGL!q2Lt4u^b4taq>b?%s2q7kIT464gc%`oN4ZIT{F}`LFmh2QAFO659BAn_d9n zr51|lAn3#ua}v&4NH!-LHp`m0vx&(Aat~iEbH4H2R@UKdyLk(xGRJO*pm zg0rjjQa(k%+CtYq1j&f5$|~cbcME^kI8RdSk)!T})R88&Px@Vh*viYS8e7BFA-&ul zbdyWzc!c>y{Spx2Eo09`;VhvOL{FuVPi;pa%^zlhDJq<2EIqD*;GtJru^*9_=^F^@ z>_!$UxC|2)F6}ZanBbRx#y>q3T-x|`0-Ke$p^;loQ4H*+w9aq}pQXBJ=bqzsh_ftl z%3I3rRNTY&ng5a#+`lyyzZY8WhJM0bu*`El>uzD`L0aR}m(c(ly^uLHWt7~ybd_+i zp5q@D=@d})Ug@#i@=f?X^H%Y#|o|Ph@5T@hmzK%YH>M zVhQ`CYm)O#t$rf=R&Pt&t~#8u&Pf^@PIt_s_N0lqP~ngk%OX-*;9iIrh8zHn&0NF- z*h9)E@Kz2nUE&r>@ScUBPx(6=jp_-eKT#63 zn5cD5^e!*mHl5@hr;-KNbF)#&aIr8W-72pbIF2J*%>y$-uj}zKlRTh$+#=0Id%t?J zMDyeCuD7XH{t6u-U(@v0Q1pIhuR1vd%k3J2lD$sGX==T5xJ!ue*;;4_7tpmtRl}oV=q%8bs5osEDwZ znLYlBmmi_;MYV>Q6nE?Oet3Uxeddo#2AWAkIqxktY^v+cyomv0c1{2NE<;8^gB=*+w?wl` zTI07@k6*$JfC9lXX1*cBgE)cKVr5{Z_lzt6Xo9;W1vTE+OFjq%2@c~~T~#%G9!JtC zfV!r=`DrfL`fM;j6QU(aDCjsV`b&~M3H8~W1q906w-vZWc1Fthas$(wiXf2S)EmpI z*n2KN>(1N{`^IHB0`#$`n&|XtS%J1B<1HYovryzG@mA?+mvp_G5;|i>mj6(p-cAbB*L*fUqV(QFT@g4ZMhj7MI!$38>_HQ*t>dm@UDhYV*E<*P2z8fOs_6XE zqKCw>7W|Jr(n28HmR0Ko$_4Cn#r6*d|A?IY_jY1;#j{K6eoQy4mat*g_M~N!S-oSM z!z~1Xm`8_Po4Z)?YmQv#`3B~9=iXiORjrnI(^Z8gU47!uQc+;!VO;)O|xkmiup_2r~~?6*k*^!wousmvw(R_OCMA1({=;?FT-J*A=VdR7kBBTyc4$5j&YH99&#M!8Cn)p#psT&kF* zl}%ztBWKJ}|T0{#5q%8m~pp!?q8Q4SRzYEm7Cq`4m^jJ?mk!1?4~?_vmhms7sHOvYo-Om6{+ zQl)OGg_@ACm@YNNcEC&JImNeDcYTT%l|F}`2E7H2KX`1Erbmf~HE!)Ewu6nfXTdnu z*(00ROo#r@?*8#}FJRK_4u$sq*GJiCU7jg}EQ?hOqHo2bKdhp_NA<2xaM1D?8J$r& zPN;L22v%*@Cv5%FJ7v0`qIP7-!b|*2Em4(^Q~NWjmr?r%=U)&=s9|9){rmTX-u?~7 z+E$WlRJ(0%lt%Duvxd_Lq&lNm1-}Okm2gXnrgTUEKan?!z`t_Rkw5AxAM>?$YbgvP zG0boz3oPVyqrVxE@t8&&CgN0m$MyNHQJDqTTa;H(Xq0B~crnZJLozSHy$lG7Il!a2 z`_am*=2zC0^ym8?XNG&sxdte3^?2X!OI@4@JEH(+{>^1sC6fvVr&Y0=Q%aMAANEG!wr$o=|``gTS^u9}P= zCOgSG>bUrFBY4^&)U~B%rZkLZY#6SBk_e;nbYH_rmx07am!Pw`8|F_q$KNAZiyj>K zHr#Tf7llj4qYk3)2)1tq_^%&r*on=NXor}-#Hwo)`J5}s>1^_-3x2S~U=c2*p>%Z% z=1QlUxB1*WcKS;IBwBjv!LZ3{M64Y)K3=t~+1F(2vh4+P#_alHoSV&L5w0G#e59wT z9MC%Su5<0)7Yh`AQMo$DAl*{?m5d&J5AqG_<6#yoZW&6VFvJ^1tJ@rkK_!Nz1Hqm7 zN}_*4@BAKz;U)FSr_EVY`%)Ner2zTt}D+wY<;`VS74bee+9kOwck8Gmp$$Is@~s{j@**;YWzYZm!OqQR9-ZzVaw>% z8mv{7g-b?Mv-Hi4D_P1fdpldG@k>C~bqs2pBjVpasY@CVT3cv!_@Oi zf^f(gW|1Q8&(yn^G$EconA(NhkFXsO4?{*=qJ?OoM#JLmdoU|rnof**H#itYoq`U3 z^lYJbeno;5=!)Z-&&WBofzc1}tyz8Id^!~ehxDS)O;O^PyFVei?TWA{)3*YcYtq@> zmZY%Hoq?$C9^dHh60>}>t8;Y61dLyYFZZO@ed#I)%Q-E9-aaNs$yAB_Zh=y0nU@-hp^tG^q?i`cQzzBNr}t{{c)$S>LPX8UAJx$PG=H@t%a0?@(f46<4~ z;ffUnhAyc21O<|@85e1)5sYe_-tpbeqIG*xl2FjcQZ<^8bNVqD9!l6J&uF1P5L?bB zP!D~j$AAzoWkH_5Z_VPL6QdflR!)C)kX80kw(fcuQXB>6K)0n6jJljYUs_189dOO{ zV#&`~c`^Q;6u5UB6&JVeC74{jJrn3-wjR+=%eKKihOiZk>^D|;K1=il^S!TvcV;ox z26{1J>wx)OvHPcJ7fME6n)JL^wPC||!LC@TpL&8RvxZ&L1*6}?3zw$)7S_t6$N<2# zI9#Gy8Sm1Cn(=*qyIAnrGpc(go9Um?8S^>q%`AN;v)Ad?q=rd;o?=^?D!2Rrl{~X# zL?ta)k(pOiJvFB!2V4WYhg)yO=M4=@yG2QvGQ5F*V6* z=pqz6uTtXe9tz)Gkw?ONIkK1QF6m+{V2-)rJCpJTXr#VvXsl!;$|LA|Z_-paxeR%~ z@r@MH?{#KgI?fu%ZU8!75C?A;4i7*77K2**WdRYc5X!Q7^W6BZ?VX^X1-i`*tNnNF z(DAVB6Ek@9q^&6XRUJ%LOls`iC}x$=ozT@vRbu6M-dF-s>xtNnqK(@giSc0GGc zQ`r7fO3;H&*hI>Ha6kmAUQDtw2oF&E4M9dWq*^rTii`gpiNAY|wO;cDB8av0 zv0z>Cs%;#zw`Dy)I@ftquW_GQz|(Vvs1CkU^(l_O0SxFK z?F?p`YjPE~HIMxI&~LMidzqFWDg6{eB}8v1C%4IrgbD6{7ZlzK+-r+KVGUj~dh-?y8IX1EnHIh~BVpbC+#!qv(jzg%AOtYIB6U$s35>m!;SiVDCt*5DFI zFzP`bt)R2#FOMP%AUSn;}8LaTyy%r|WFe(qG(L=%XSWF^NR^Y6nBx6v$VVq1?W%MvtO5 z0Z1I1Q^EUiVOFWVw!1Po$}7ul{*G!@jPP9CS8Bd--@kea_N^mzkQKazk9|EnLhhGA z6EnbbUM#=RK5`hvComqCmVsg@NLT-Y4z)VrX$j)M--<6gDN&ctvC+spfV(|?Y`y9pNQ zL%r+|_3>-IjF{Hi0F;lx<7+w29M##Yyg*1L#6&;g5%Qhj`^4YWel{_5FkJabH4Q+D z#f_-dH957%z0bG_Gkha7QROn+dhOFAs?@4y*R zLCM#g{#x6}0s;s|I{F2{tE?%Utsug8Fr?T5mdI^j3_h~#P%iYPVB>&|T+RyV5wN7& zDf71A!ve-Po0WkII+|`M?c|I}@b+9%*?=p`bRUufByGSAR(CMC+;-cLd@OJrUP)`# z6$jM;-G==c+uT#>lHqsw;gvsx6k*&2AKrosGLLAiX^`r2kbCw=V#t)kz`%oSOGtnf zI<1&J0e!Cf5h(%^g8kr zyaP;RCF)>j4qc(KN-sSbJa#Ze)}^K*#d5)zQJI`LIQJ1FMFdYDNR}-jPmSO3^Wl)i zj50eMywu`v%NjfOEtgQ)bux1a7fADF^ge_r$ui@2K}VmSk`caTQ*`2XOg-8KEjv1e zs=*!j85mZLB6|COJSQRW-4YZ0vMQ_ODdI-?SQhayoK3XP&y?-L*X7SK9jv0^YrNHu z-<`7d@%Sq&^l5WN*tj%v?ZK#kkAYT0j59Lzia&+51pzs9mM1;4rM`|d0HACO=YI6? zTN>7DNH|gjprMlNlu9sOBE75xRwSw@`}i%VmrCYJuXt1j!pzkFbYt*8+sjI2+B5o5 z%t@HNz+U@HWFl$=On}`oQHBXzjiWDgCr^DF8)i&Gz|I2en|LGBl*_3SL0h2K>st%y%$~F z^z$O(4c+nM)l&rc<)4?r_k1UhfuyQ_MIkTUx56=SavDXX#~KoYN}l?qz7*gyP7XSa z;8iK?|I5#9v##j%Va&1)(!UJl&$<-$$I9@t9w!DZDB7MI4Xk25R{cP;S{mMdpClT9 zc<=s%1b=8$2w-__vU4zS<}vE}ck}AydF3g0a$4`?!DaolfxQrRhHBM%%_UdFP`#w z!YyO@EtS*`R}&Jyx$oKRt!z!PIVFi-+$ofr-m1M8xxLw2Z5^f*$-2`EinR_@Aq5Ip zax56~d_A%%S$f$zB`VDjylBq|NKW)eND<>W#Sck;wd&!c#{l4>^0j%D1k}@^a8Z@) z0u);;V3S}3syipGvhrvf!njwU<~$OrF;UhprUxN>ZgVybNAE;nZ++g1H6PZ|-Fgi{4!KP@{=q0jo96^E6D<;btQ_O7_S0)*$C?>02CY-gi z$O?LfEa?L>g0$k;cQ8q$5kGRKS|pI{>z~w4L64TdaZ8BehHLP$jdmaNu0USwV^x56Z>n6W5hGlcus zDgtd>^|qh%p}4yT@)r6QO>0Z7bc(S`b+ZAHuk;P@Yh7~@q$lY2U}o@wLR0*hj_8M zTXvoshPvRKc%5kN#qnanYj~$UP|5nF?FfeiT=?|eUUIP+VtT12oh{~u8~;XE+RBK? zE>^nZMLj7%DZ=gZl)K6t!39sZ8#x}NWPR-ujQXo0#K`(l*9=jXw(lK?LXqdE{QIcT zr1XUP=!r76!XYZyz&;^bJ;vpu*h*Zf(U+C)o7Q(JSY`x(`riPCt7IL%HU1Zk2&P9~ z9!a2c{Z~O$Gv22hgO!5C*tn4JFy7h``y>^a@S~m@L3NDKLnXe)uFHBU%uMlJV5Tm@ z@gQA4Zwn)*Rz_d}nzfoQ95bj!03P3Fpo=M4bGe`|S&-Z2} zh`Cb`bDtIICwb;!vOtm~nNOsO|Kn{Yoj6W6%QH?h?H84j+E-UC}>BK1gq?=RvclZbZI=5*v z0%Sl{(k&)F3hz`a_)%e4Bw*jEhfY;*iDvfHq_@5jj@ZcgCb+{hkYNtn??}6Odp@KF zue}SBcmwHHZYasfr$~VTvAV9R=h%tS7OJQ%eEg2bdlII#76G?NmHBLqj{cP7Y}otq zc8j!iU&XN`5XU%9>81;{48NMxb`LSC#snD;jb8I3m6_6Q*ZGWGig3B0+(~m~i;z@% zw0ykpnmrkjgJ0>ipB?rM>zz-2XokD-KA!mQ`&FF(bq`b|?<+Z*`4$^E+OdTrZT~n# zp2t9p(XGFa-+)2Xh+~?f0}IL2$xc^F4NBL8IjTae&6{@frT3x>x@uAiXZ|UdLl0l6 zdMnTjN>d=2=2X|2=9H>`*Sd%ryZ=?+lJ_SdjUQ*3B{S|>e!A~&RM^k`BfShgZi@UR zFW$LFqBzF%xi!B+h&y1EOp%yITK93%#z(r4oQmo`F)XWL9nm0CS)zlUv%j>+`hG%H zWtBU7Y$VhA4?>UYRTBM)*Wi!7`b_OD4;?7+ed2$0N5d0KL;zrFnf+-0tzQI>k)lC7 zoMQZEb=iM)KhO(50_d9I?=w~2VLU$SbjN8&e8Xmf66n)7zgquf$0hX#wJkFB-W&-&&QzkPe5) zg5hD}4`|QlGn_hsUm?U+97S%eEfkm<0_xxTbU~XH8N*&;vSY)1|_Z7wJ$cWpOo}R!s{m5xSK4bo?~_BlhHXh=D`a(-?pjxa4dWu7KUfXA9_l zqK)V|HjNzxO9yY^0$m9#I*&hd6ekJdXTB!+{;ran=L2TzQT+*JuOgM>q4RUxRCA}J zEV0kqnRI$ot4%{=#LWU3SyIa*cUNK_-()o+&={2^TgYdx#sohm%6(~TDy57O*(^Oj zINvJqaamJ?tZ57pqT$oBWCkSO0iO8JQP8zTSb(*ZvO(Qz-<6w|cDZ28AJ&X(rI#;D4mp!RzSumC)-Z z)SnyD(FO&FM;=TZBu0`cpg=UJigrw+{yxh$2Kr3-J(?$4j27I?jf?p5J49l7@pOzW z+EUY4s?WG^AWN2O9*O! z`NjyTHG554%5l>ep_!m8EEe%4eXt$%awftoT zmqNxbk2aS1ii{kGlmtnU%_XAnt9&x#01T{~h_OS}q~jnfP6Kl00?(sScw-$x&Wlv* zdXG0(TruRK4NYf`#;RAmR1r)Z?_XOw=Pl9WkLo+=%Z7s-ELNBc0}FK4iYW``CyX$C z_1xa$gFQ6ddX6KsoDlTDh~8*U!DF+9VB1M$*+ns`)Ey1!Cx6TN}Ia9onfU3D! zK&qGloi}3@)lqhsTH$c5aFlmtVju(N$y3N~&SoeoS_QHe3n#y;3XYaeFI^rArNe6_ z#3_p@#8zgc2TbRmo7Labx{S@i?~|BE#6LelQtu%de((qpMqwbIUlg@Mvw%2}3eIQX z@0z-=1n<04#CFzpkanZbW84t+w*sBet}_af+9wFN1P6iU^tM}$3Qlu_?vV=bp1j8Y;dM-F^iIc9=#!vQPAc2xnhhM}={y~TGa zc`SH(Y{J7li1;Go98a+_T7d9Do-$@DCjwnuP>i2%LHXAa=6@^#m!@L?B9Z zCuh~Bb3}t(;owsgJ^JG--mftPrjUCD8nF)A*2(r~f!;_H#VH^g~@>oX&85-=^T zKOmE96OSrtLUr?1oU^w+Q|YfMOoG9`C2i>Kj=}ZIoXcSNUq3|uCh}^Te5FAdo6?xp z_(WJQ?g``XiusY>KV&nIyF?VMyj*ZmIKost5=9RU+&#&<=9pB;d9EV(;SGy~38jGrqm+RaYpk>!z_OHBnmyp?l8%{rJ7&y(iAJ+--Bl* z==*s=toYxRJX>mC2s}YzhC48eZoacXa5^J62#fmGe=VmyXX=PI`a_2Fdj{s4CQKd( zI~Z7dnsyjv7hL%@0v;$=(hF^@n62wS)>^H35V0|L>3Fyj_KplincxAcJvBccJibQg zG5#AhZt!lzc=~4fc~jJ?Tc3+NJr(fW5lNhbVdL>%U8w9yuItt8zR+7!$KM1~5}(i< z^?yujhWMB*GES7fZMA!z+F)vEI70M(3}W(?P8u!B4@VXH&f_ zNYQuF2^rgVlnnGptg7{=@k^^zvAl)R^>Kq!GhhDLtJ%Wz^WugLX5xG;YaY=)%&Ef(nQWLIgcRK0FO9Ma` z-5QfEt#?qvSJbnsR}BA4Ohu{#IGIRNJ3rchy0^gCbiFzH&;P1XkAsAJ1pOoI(w&-A zfEPsvWZ*vq<3aWcphvI(VIU0m*nDPKE&&sLz0R&(fGG)UQz}AjJ|F6k|Lye}4}PwJ zIbCCii2g1l8BAiNV*I#E(9sSd^tIKBcJ5yDYdJ%2sR>=&C5-hYiI?~RxKM@gEotHW zsjMgevn|Y%`ZL8r)xRr^eHzA?Zr?^^XGD&w^w8Zk1SHe#M zPDNxq$Ci5|j_@|1=;NDpRh+7{+0D;wU(Wp>wGtUf4`!{OARF2S zL4So66+#Vl|*D)@H0nifCH5Bkm??*%uP)6P+<)AAP0_M_SR z8-sy1)hX|c1JuE#Q8;EnqK)5mxLmr;82U=>j3f?G*wU>p^by3Q4x}Qj=BH|63R3Q^ zFN_KX4QQz(U#bEaQ>$N4jbXAGq2P<7wTPAj z0}<4qIuM?LoNW<^WSNdrW!A!VA}qJ1jwb7P-#tuwQCkFmnet`pWd^sc=;>2^rz@yX zTX{X|l@*9zWhG+jF>@5lB7d1+mTxWeT3>5O{m#EWaZm&&i~HE0<21w$Q8Ime##f!f zaju1J>L6H3q{>Im|AWiTTo%Y-?>=aucPmD55PqMoNgGojlt|Hm=mzlGiiU3tR;7r( zBK%`dTZJ3lDTBO$g7B~lir*ea1{xV8(&zC(xq=FB2kPPR1Zy4Aex3a*mp0Wt8o&ot zVEV+Og)8D|>AeAMG49(fvGi|~uCt^+y%r@k{4(aIYSi4|ZvYDPvu>r=OSVlFx~%uP zzmP7ONRa`-l`@oT@2KEhJ(eJ?HJN##FgFRtn@yMEkd`jls9p!VD9+?SK&w*#G3cS{VT-P zvoFm9w7=ic=EMzbaT-Vd)^Lf)srqbMvB4>!f6@6W!}KC`*7TG8#oN23GHs!+(!yKa zA)g!nWFSTQ?SWxI$xU6AH-d-Mf>}iJ%}VDPqMKWRvib8QZ{)`A9Bi*1C2!S}@w$GS zt4z|JvLU?WCX}%t>?|xNW2rw8GZu({{_lR1P)24PII?@RJ9dnkoQ#e7GIjLkL&f&) zw{X`Vv~1JI*7~$2Ur|Qmb#}3`nY_Adqab!~#z?y-(^_O-gHnE^Ycjg4NF@mgj$mAX z_nsRgm}!6Op~(r0Kg(@a`q-T!bbEH+ntyc>Y^br@(+;!I_bPLem}v?9_shfgGY@*M z0i)k-%nuDuntz5nTjThbOu*VA#PTU7rLVK^XnyFxKjJPw_5Q=HWIWe^DRFzjL$@z` z8;FgoTg*li4M}KXEgqL7-zRmc(Q%V5zmAXDuPMjkf=;6u?V3#O5EW_%oqun|oF3b( zF4z4yO1Qqi9&o+dUM)c#8=oA(ff_}k-ey9l*tr#FL}6=K9OX)@&#++IlVVf@@_b6b zDrN9}!`B%@Hq5JZtw$OxYcDz%CHzR(gE`{jN#+G{sJwM)^&ib~68ee}MDwUkXx~QQ zveP%el@)FNHHA&VZTaTxF(q$USbnS?E;gy8W<=Pau9!>>iF^$y*7|bV=;6p1TWeZ+ zg>`_y;^JbgkFLypNA|mTvy3Z}&tHW4x<-@{#d}AWfyuV<`(M*TD@~N=zh$WEWVsPe zPu9LD$ulKT8Af1-Q$QJ`<0GqT! z*b>@gM2bP=JpBnJMtWI&lMd~)#e#MEGD=ZIjACcxOZmuy1-BB)OPruEhL)dAySckd z$EeL7>&mw#a*WKe@8xj;sDCi(JB*RPWC~YhYSuc!r>LdM)|l*QIzG&_BjU49yjayb zNo^FlMXN30fT9C}!Y+M~c6q`zTFs$OypjFjZB`_$vuqw^-mh=SgUMV!tuNJA)Xbk} zL+uc1cIlEvMlH(~pHy}jJIH>ntdLLq`Ai6sbJMdfX!tF;Slh^T`EF^av8QFF)z9+J z-f(X$sRq3{eo(YCQZ?fk4CLM;+Ycu zl(Xk;HaB}k^gXq$KDWx9xRH~I_53Gsbdv7i6X+u_@oD2P>S!?4Pxok!Uw9vr1Frq1 z+=M$BHx)t`AYdSE(^{-<oxMkO7c9>xv~f=);uEd*ExFHB=8zrcSGzSgIL4G|Sp$#gi7J zWi+H^BQA&#Q@!RrWi+fY;MuD^BsKBYghuCTUg57w<*i!`$D=^TZ>$nV=}@C&E`52! zMbASGWgFp1JGAGu%7o43=0QZaA()nMT)+U}Hvq_IT|fOwsiiWd!>};?PncTQk&_p} zwFOhI(J=N6H|eC@I36J@T*LR|i|;V;W6nV1YTI=E>*Xi%17Y!5}la3fm4 zygOZ&8y37}*XSRF>rq8wt|vK*4OSH=eDshS$e75YukWBAR7I$PMzGYo<}~Gu`Nv;K zGY>tO>)q)u4(o1G$J*qwn=OHt^l;-~)8#i*z+2;dxaU;jkOP^>=J+y(i`zNO#tEyL z?E~iTn*7~VplHI=QnRTVQgX510X!7CSbzSeKd19aK302dhn#)vV|oMzaL(M)=L9((s`Qz% zWPVU1K(!vJ^c8iBbCu=}W&%;*fQdu08M-$X>kyT*gN<@`;UO>QN zGbX~&L3G;Hbk;Tg)#}R#*!wxkdV;@cl-|!Z{%k+RXB4uAM z>J2Vk(4%dqUy(n7e4MVKuSB7QMrij=4)n%2YSbLO|JsS(QMUM;oSgj-8N|Pz9QuNL z2=fvsNe-HJVX8-l|2}O0WA5}v?^m_btL=u2vh@DVm0yQ(>C~EcPbijBKd#&JQlMgt zK<7OBNUf9&+>|r_T3+_8Uza2Vj)iK>7?r4qt@%SZ_1Got9@VVw!A{jf5K{^2*PFjw zdsZ7Z`#CXmRVb39b6E$`py|V3MW`EkE8OVqi$Id2(;~zwWBY^>!Em>>z`}ZWhH>wb zIc$+WcdqN98+dke!CRaw4<(A| z^f>pFE7|&IKjczJslEO?eN}&Zn$R zPbotmbg{MEsgW}vX&w9KM8@fFF_lHgKN4&?g69SA z&35BYs)lj<>fhTfuiv5hnOeEg)O0H9fIdJ}iTF4Dd#6X3^3C&;n5DyzLw{Nt7wYLS z$gnV&j9@59`g6h61M()i|L*StnUG{$DMA{YCF-b9A=GB{JfOyDO^tX@WxWaQq?j9G zOB*V$2^7Dy2uGI7Pah7exZx>)}V zsYI!6VCZa{={%C*SvWZ0YHr!TWhH&h7__-}?*93!yUX(*75Q!qqv8Sv#3R3`+3f72 zQgFnM6{b`%gDAh>8Ahs}(KxT;D}cu}0Hr1obsxhlL-+Wfqdqjg6^NK^v*(ytsD!B+ zL^%3*C90A0&&zZ4EzfXtj>pWX7g(SYl_YN|xcIl`Z{%KyeWDxQdh-t8&mnn)ur3cI}KT0Fq6w?ZKnSzwwv3OQbSM0 zR*lS7EnxJYiIVZBpo*`;q@oTxOc-$$I5l9Pd$}6m_K+u1|HDFUj1V}b(j{Nmuf61nUJUz z+#Z-XSvKXaa_~}S`K;*4c5w$HSmF!f`NE^mpG8h}B_wpu__UrXQBO{t3=(z)XG@Mx-rLoZxuqx{ zyGy(aWB}De48@_qzw@2Yxud#KHB>@lG(ntZMC>NP2Q7hj;_bK-=CG{UQ!R*aa&a_;Hnj=mX*Z(jpC)R%uz;Z78kBvdeT8* zzXhsVGOQF;it2DjeEGOJRkH~f@`u|Q8h``m^AQB)UwNTx4E)D+%%3VfO9s&*S6{p! zcfYTdWhxw+8+X@BlgKAQ1W~O;$_Q8Ls%tuj`|o5C)N$0yykAg5Pv2gePaaY(nZ0X5 zK4I9FmN#PC92fq9(DohB1VEH99l&6JhWpFWG5 z8Ej=`syo^xKA5l{Wt)DG)(2=`y8Wtu-lNiGA^LLF;WGS_Ws$SES&Ts|hjchVfDYZ_l1sL%D| zJb|YU-c^18ChZ?QJ}_BV6)cq<<3*GD#kmf~D+(4QFv>siSH^xh;nCH279^(jq)^D@ zQG(`GnIFLyGmXr3l-=b7?Ehdv6)iLjJVn<72TNbOeKQ4iQ$DcfDKfn2LVbJ7XW~40 zXdN@{LMYP`?6Lmi`D+{xP2g3n*RrvXS}LgnHN0rC$9FHm`^JJGycz{41E>A4 z8`PCBc>J$lLIF~VZ0gWz^2htJwXPG?YB+xIC7z%^)GocX{9pKjN5WN}i*xN|wmPf5 zsJ$pZX28&&VZxYoJi*)84gs5Yu!z;mV4-$drEOL=E0SWTZB|h>D-C>VaV*GTO1~Nf zcM(-KvwYeZkKj-4f?df%mQN z2cLmwW>grG35W+~SKfFRk%FU|0PAu zf8R4vpXxn4{o8(V=8wL=hPbs$ZGm1iAW^cefjPd z`F0jEaky~{3iq?3j^hJe=zz=3Ae@Ak4(amLV?2+!i>cg490#@(fYb=2NC_DmI{j4Z zRml+k*ny<_g4*N%sV8U=6gLXZc{@w7jck(BwY!{#is=>v5%4@7wbOx~Yi@0dC;*Mh z)XN_)08#{X+z~13bO+oIET9Ys5jm@~nDzg;9r(o={nk)$5q?YZCq^0I(B$?vuxX-x z|6d{E?L#Cd*HC;bIXF#*Ge`Pt?Lo{)upKGYU1|ZYt6<620OoQ=s)CG}RYkZ85XXYI zZxOUuMy&|gImRE#eB=qGXDWJp0;qGRJ*&pCq!gW&90csscbGRG~Znp~TNWg66%1 z6j}-0$@{rd;fE4N@W~Pf%8EMo4b0uNepVSAe?)8Alk_${4=Dt>^h=xQ`NLu9;&RnE zmFhGLkpr`eyiY>DFGNuxQO=b{mw1PTde7an3pouTV1bF6u|UuH=UB3BFffimNY4dZ z6i?z7gYOv;nQJ2t^#=+f>c%2`>S7JRGGxTK0RyAjSSZNd1A9eT@HW1~o$%e4DB!Xu zh|MY?64^;b>j?!v#Yypa$Jvv~!MDIraUscM^^`blK%bg7aje-9zge*!`thR_n-n=A z$E%sf)aySwj_j@06Hz3OemCd@xMQEmc0FWA@-1w9bIQv2b(J(0<1UuLb-X)sa63*F zZQiWURxzYbaN2n^(6plY*Rs}MD)q2!2|q!UmroW|(^!X6JpOPqTP=)iTL$Yg@g06D zeAas3QcmaQAtwzY65jHt=W|3`&r?RL6J4wvDh85+;sz}Z6>dqJ*dF!y2;XD_aM7KS{I0sp9;| z%!ao^pXEjjoaKtc0F6AN>xmxo+14ix;p1Rl;t_wL!;ZCt?W>-il?zF8%UN+KMf$$` z3#|v(9T}fYI%n=-Si4z}A^Ec-{CJrU>G;A(m~wu&3k@E!(zw=ZYw>U{BSSaNTFKVq zF0zR>XM!^%1k5q*2r|Y25@MQI=jn5X2G_1!MCsx!6NB0zw>6AxwK5R{p0l1n>>1|9 zCpa;%8;%RGw4$nI&>P%;KrJDb?OL9VyP%%sMq^boxxP zrXvy4%dgUwf)He!%=1G`t&URoRd1;ED(0Y#cu4Ht8iq4cBzxS@Nq_gCc`aW|xpK^DeF znA6iax{<|Er)KvIEchZv@>cJEWz)hCvUu3nq9Kn@S!_*yC({6A-7a$I$Ye=+bGaqk zGvGqmh8nYm{5<=Yj@r-MaSPaj&^G}rpIM;lYr&Gauem{0*K+^H?pE4-LT;M1(%#)ZjPFI1CRuTp2&KI89f zk;Ljg08gByBGQsUQchEW`TY{)26KKU;n40QNaK*9kqF`tOiZ&uhn z2dAm0EqtRiIWICf?tz8UU9TMJ)7B=)%zs2LuGvbJRRDu53`nxCW-bb?A8M6&>895P zN)7u$@8M;7`f9KBMy&=0HX7s2AQ5dufOuq%)Eh2oOx}?-y!deWSq#@Fz&XgF()L0O z17z%_A1S|zlokK}%;u0-)Xvthh)0ji!zGP^n0|)(YX&;G`D^W4-6hp-xMYh<;q6$3TiQRC9JS zdeBam3H@4eipS7FtZm#9Hwf`#jKfuQ5nd|s{Rfj2mDrd(o=y622cP5^^7Y?ixO#{P zwZ-g#jh=XvlQgXL^xT~h_RdqkgDV2{iqH5dZ-v9j*05R>ODhrJ|NY`68)^JeRSO)8 zgH;YciI~wgdp!IJ8ZQm-rc{S+;{W$8<;6qMmT}#!RjxX^$Dy8syaU#u8jn)YVNBgV z0R=?Md~MNZB#5`^SMMo_rB_U$`VEs;lj)hN)}M=L70BE_HA?KZk^$dDu-0JbSSNfR zT^7T|R-RUiU_o~~MJZ0%N5+s@yM^U+C;QT9Kq&8f>I&$lw10?Su~1aqo2;}Ni%)0_ zcjQA&uG=^noOwvYMMh2{=}1W*C8)F3L^u`4-(U(ul#@d6d#%G&`~-t~KO!PN+()GjK3-{a;t&@I=p^`HI#imQU`A25s_RugdUJ92q=Y zKrjvJy;L-ecYwZqcC+nvWqOUcsNw9r%`Ro^c;QitcruX)?Gd)O?-Ybfey0_6{@D%R z#}NE`$_$#4q7!Pqb8@t>C630({*|+Nv3AbF+v`Gnms!fVTqJTd_~#FOGxf^5@9QOP zw3E(3A{&a?k}Mv~2n3?@%{{+aA_uZ32~izdk_~ z%R*y7ERL_lz?DpNL6W1YZT&oPaDT? zbSlQ4-a4*jw9n=I_G>XDL^tELHTS0sitn79(b%3_I&Z~^8InoEK|wnV995WRc7qp*w-#(p8%e(PTgbNLZ@ik z9H7V;$$UBh1T|v`>3{)+{t|;(UtaWGre{Y&c{H4#l51+CiGl^iN!ZrfoC52o^~Ix@ zeWUWLRX`1w0H$-v-xqi>3Xh~q6EMPaOdtwSqT!FGB8!TwOL|@N(0zUp(9Yf2TDNbU z@DPcc!4@OmfSt9+y6f099u%?fYNY#WH}mTN`AgzKI7Pi1mEtGf=AtT_M}uM(wWWyk zTe0y{2WXYiU+Omwe$aAGL!d*{%hEf*<xOW)%Ux3VS2Pc&4cQ zex?XXNA=vU-8J z96}gr{3AS5s1E%OvCfnC+ZmtZN7#p5^>OlD6m!ojyqi!?d50 zqLuv$$T!6<&DIF7+6g^z8B-Wps!J|Dzt zjX{!YLk_q}U^LT8hwaD|wzk!Z0kAZqs&S?V=R|o8p}0>XU4VyyL#B%np8YhHWJU9l z9L}_?^(}9A5b^G_j2yI5-LT;C#&tB_m9ot)JmyOa9iV7r0<$uBTmf4dXr3`5lYUC$ zL6s#SLc-8U3tIpW!Z6guzcKOAi>44^Zp-A$xt!Yc| z#hTN5l@ttt!pQZNv@6@BTBnZ)P1m=_&1Ih;_DF_ob!;!0wVUx#3IWTV+c*No>@QOm+pbhk(|8%GX zPqHFW>U_xs>J}R5ckqmC+uli|Z!W)H{~RdRqNsa#JH}?dP?>m4HD?b+vSCt)#$AY) zLTj;PMzmw(EZFkHA)3L%UP~@8x9d*V{r7B$-*W*(;jqpZ^sPNe=l=6bvF_CAKNJ`P zw}tiG*LL;Uel!c_sULFp(Qb4hu0)b+x*q)9iZ_F`x_x8DvDe|o!6@U{D-S1H>y|+{ zz5RH~a#bnX9DUN(Y?t9E+Fl#C0N;{+2_h4tb~U!sEWR=0V=661Gv4Ta4egxRk&%Qr zdu7L`k-fOb7Xn#QI;Saag0(WKRbMhg;xHayi@@`?3#P@R^zVu67 z)^;GuGjma&Kq}6!DR{YKr6(o7`7pedL`&?p?HWokflU1Z$JN!=$U?$74{?ng?*&f% z9(a?j4xAbf$wVdD0R^t<`t4lO_uvKiaR_=ux}wj}xqQO>zoMII8c;Q{|I8h9zaA!4 z8^s#jd9`87Dt;1Tbs2pfApOv&>@XO->qFgrHI94m)O^yR8=n zNWIu-i;a*QAk6-x%|p71gfig7$f8~{&Qeax<6An>zd-MT)Ok%jf8T7FUyf)`n=A#P zG}{oFnybI?U)BgnmnN64h`hdcPnu3+<&^yFlgC%FyXHoERCC+v=5)k_k=;vtnf08T z%SNcZSSTuDJ9aoysH4s4W@Kn+7q-c1_tr7y1I8*L=f@}TipQrJ68oZFdwMmO1Af(Q zC&kNBc}yqr{%>*CiIUjVa3bV8u?}i~thfM=I|7o97RAFv9nqUoi>;7aT!HtoFsYln zk@z^xop<3X;%&Q_qtgQ}5a)3*u50~iI_t5{*D_G(m?o=0*gJ$PSNYQfQb~{$*i7~e`*n9xCCzY{gi0c#$}5Lt>^qfKkByv&vtJ1n~9xkE_rG$bK8PvYOorq zS%-9Hqg#c7(!VnI)&R>dx#kz>W6v+nadXtWU!PL!IW|XTD?g0%9%jUDlqsM$W}(_1 zwzLn#rZhyx)PPFwVa2OHUvSITkpF8At5+%NOesa%+aI;^Q65&|!EaJDgSx1jOIlLE~=jNfqs@YALRcydR z6kZvF;7Go#d7o>ZeQi-UvTN=*D(Pi$vMqa+QnMfg9RAjBmXVq25qF1w- zV^uo*e7F*l&wE3&_I-`i=)~Oq?sDdS&{wmiY>MBfL{`ti0KR-X7EFN=f8sY_EL{#+ zl8s(&GuNf(X0p?2?2j;)?tGO4CYF~mlJM2#_qGXf9%~;1zB~xa=Ji6^3sNAJ`?Unf z399ud$JImKxlnV}H{4EqK@X}~;OvA?*dBdEE4un3bE(AJSBaBNB5aB?EJ@gOGJ$X^ z$qgZQ)N8-(ug^UyyItFVtbDk=I_q%ohxcLdK>T=_(w-vja;ww)vSssp;E+%QXX2R8 zCCdM?V@)vPac?N9y1I==W-vnpZ(eR6*JIt93whq<%N@Ud zLI2b5>z0>jVkzRXhlOT3`oj~7dup%rS4HsCoy4~Nj(tqbQzlSIV>cY1X1@y+T*~A| z;wQ6pzx=ru3w1j<5qom6!PHOliF}VEn z59#hQIx?#+qAW37UpGsFq;ZA14+-OgfzhHxtI%F=cf7|yb*Jyz^YCxz~@QARP4eXURR=wwpUOew4){k3838Ra?pT@!8%u{@?jyBG0H2Th%WjM=$ zISkcF)3o_!&+r@a(ow6(!NJYRl`4UIx{SkV(|#B{ zWv^7%b*_dq5iVx24B175pAjp!1OSJ?z;f+|SKY7WXPc>&vO2y)>_?>*-c5f?UNq&T zrqBU>C^^Cp92h{62SA?&r$Q=t$h?1jcDKLbB4#;D{lSv-U4tEVQe>iDttegZ_XeS! z%t60{0){c~X=r_TT^U#}NY4sFhcnj)azl79n;f`TBATY`YBe*CZ7#J)E*!*^vcKEx z1yTYsE|?%f0yjfOhOUK)uX999GU&8T-`K!bKd8upW{}EY79;U)tTUfPk&8GJz7tpND6%pi4@UCA|}NdShPRyVgoBJG6AJMB=ERA zg2^ee>ieogst6Nb^l!_fuU{sD7APtI(wGV7j8JtV>N&&lHd7NH z1cMzj2#b(~pK%C=J#ovBE#ucQwus=7tmxVom4xRT^5906=c7Sgvrv+&)i9@k(^=$J zUWIsTY|+PucP0bQ^%jI)wtMTdVUXX$qTKIJG*x{NJ*LhC~X|t?yHZd4?$e zA=Q0_azjWJ#rKf3HdMGxX1yq!$Q*<&=LnqmkF;F{=7T0nh?-R6y;p(3nB$2Qf$%qycIp^tTv^e2K7R;g*bg(HcDMMqwn>c63G?^$4 zB(Xhlv@b6)@*gD@ZaD;QqAGH`WFWwt^I78Lf@q85i`GMNf zR(H8OduA=RZ~gh4%zOjO@E3i4eph*ho=a#GYY%?~428vS!K%3>`T3CC8M)%8R!7)( zYnMaM(1`u*c~Tb=ao7Y!MqeRF>gMV>DOd>Pb3DZzFY-I27NzKUGN1w{n;!NpG90O# zrQ8z|!tg8emBJ?ZfYZ_4c(p$fh?sKdGHX9B)c(UCH*;uZgPKb-1ny7n)cjSx@)Mf_ zDEw8kr==zpzF*8hj6aOc{uHujIf#GLg*F-fvzPt?*wl4^13GsZW04@ z*BIgnw1@OEsWMad8?xu?{QFz;dPdTm?yZu99HaiwCl6&2tLZ!#J^e##^}%`Pf^+pd zpVej>Xq63sI~-)PnuE5yS4(B)zyu8L4ft+PGdOv=I#-?$r3oNQ>^v-eC;X~8CV!p# zbAH8^9ql-3cH_%5&b1^f^PDjn;4vLiSQn$5Lxg9A(Rz8CG)vO&a?{STlWvT-NHb*P z9yMM+y{{jmH2(2Ks*;RW2663vEqKwY^J{X_ZGW+UFz~J+?F%{0N5D-*T4ib}7AWl}IPh!QcRjAK|%Us zy=*bY?_G{YNy#(bGn4eAS~P$dA_$v&X6>HgNYLshODo%4?#-=ulLU4?W5W4e>y)Iq zE2kObK~50)!jIj=zeK@RnoI5cVLQx+WU8*JQ1+>S@NO)BE|5YjvNhmg!o~MFiOs5+ zVO#2N|G(t->gpi5_?W<>k&IDaF?7>==Yw@r;NOqpn*T!0nqS#fqGMiML_G_sMhRYF zZ{5T7xamcqS132N8A1Q6k9rpeCta69ETdE0lcfuzHAi3thyd(ku6L&O-afoUD^!_}9L_02!0qQQxi2^REt% zRD@uiDOOF9PHmUtaFfPbg}GLg{7yd1=`z3g)isESW< z$l;)EB!Fcxxk;^SR%xOPg1VJ>YQnMtRCH#+WMR>k&7$FDzZmrFg(TSbHkW%_9rSSA z+l(0W<@!+mJQM0S%+#Z*VM%h4`N8MI!}w--L}TO0u;SP!=(tI8`0&}UuZX9jlD^#@ zJ@)?A!|<3^qwR!HX`H;@x6)@#2L)NWT<=w$)mB{!M%nggZKOe$kbW6I!UDEm?MRaS z;8NCy((j`74i{Dw}^ba0QnSzN@_ukA3bcHJbLq>m5GusKgeWsOHq~?e~C-yB@k!xOlp8kciCIXobU8&ywmh0XB0iy}O$gMlOKxD~}0Z@GB zt>wgc%3~xjdrfDgH;|TAL@!>GznMIj=(yOKj?cvkDSP54+4R}a_K~4rcCm?QUlJ`* z%Oc$#l|J`t6Xy@J^d^h~*@N&53&umgVW!;S=MDH^n%V(gnj@U$l`fcBy#{I($}@)e z?y~O1g!k@dw5F@9QnR$*E7GY!wU}g+9keY963P6XzK4NasJ%TNj%>F-s`Puyp3o76 zVnkl%>S#^SLcs=)kPlyBRT1h1F(Ysehmxp(Vs&`TQLMwWsAdbQf!TL4d}WTpootF4 zy_8QB+$gQs2Y}p?k63#y-=926HWdyZ&ChBSw~Unq{X9Dm22MNa8Hy=`n?3FQCNp-q zvrju!M8potG$M}4dE!t7G&r1MGO9&2z^GgmQ*BniC#{AGH+OJXd0|_IQ~#!H%w#6r zwu}4YZx%}=;fPnv-lp87v;TfCyJ+8WKst==LGpxtmXT52F2jq5>cjl_rH&&mqXw*+ z{(5@?>p_SL-8$r^)pFu?`jdZk4Y})jkrlSj>Uyzk{L8RS`loBu6`?c4 z>K_*F2JPAyhxE|eTz2T%9)*})tPtZ6CeuU!65O>L0+kD7Zld^oc#-im0E7tek(<1u zN`f`C^$|}#XFgq%*2-cM@}v=fB@(Y)KkI|+;9QF-S@j<3v+)JSJ|d^U`>N~F@1gzr zItTK6_hugQBp9XBf=~bigo<=qUN&$1iX>a1yipf3pC#oNjQ=U)4xOl3sMJ@NPEfI? z_|l?a5x|_JT4_V^mlu1HE02&BDl;3N89I73+5rcaSadsCdfd|)Vhqz27&eM>!k!7g zQz?Ay)&fwlih_!S)rVDLL>6r4pmn}<^Q_TNC4r-H44iNV9{ z?}mVYwXUm%HbMt-!uNvs4H_bJ64Mc$2TL={-WA5x`s`18YZCXB~4?Mfc7k`Cww^J<{Tk3E*S?_L1&FI($m<%AF7uB+>e^z69k#;g^mcMdLC^?N@i@K{+np(@^X$EHC zu(y4PaPtL}VmZ(a3evO>R3ga|0ebGs%F1e(V;Y=zU<3K?N_vLC7XR|!KO53eB z)O?JPa9c=nME3Av1;5VW+KC$@0xAr!0|>6p47viedLn=0Y05G>S}m)>sP z-q1fVI-Cf*{!lv(Nul2a8B(AiV1;H0E}(6w?Pv37!P^_OHoSYSC9|A^f3)XfI%rCp zeC?HVzq%H`>tW9Y;un^&_h33ruGZKY?dW(MiU@)}LNfn19is@e$Y27Xq>hpd$6ok~ z1$xjEF}Z&cdCU(83GwD#-uL(B{Wl-oh-hBO8?RPL5U25o!la{q;`d_Hi}MISe#{ls zFPwLsoWUNm8we`iH6kA_!!xIbS*|wREyZC_yi*pUpyrSXi$uN;Aq|h2YK7ZKeN^kw ze-|W7YAd{_R6ma!`z?2^!FFs!%b#!T1|{v&X`bXi5k-Axdh9TtH8x zT}wLfOiV=H0Im4F&bLuu)=UH6J44D*L<6Wp@5ORE;W~z8!x~$tf$xi?VQY%Lb3$}d zrcS#ntHBr+c95I!FQB(3WV(acefW?9sidUTGz#ba2=72*qEN5-0jM*JM0`QmJnYf{u-dNi#%7ZY2yabR%XjhATBohSmV290Dy&Lj%G8rq3sF#2 zSM_hdZKeHYziFk#GTFHl>^5#|WE6zJi@&xPzBL%!rehmHJu8Nbs*~T>#hT$md4gfN zEhysiF{$E84$vB_MT}Z$@n|OX0||HWJEjUu8w|u_>7duRQ^U92;BY~U(E3R>!$|H- z{>O$-CO>Kl;3BEymau5yE_^IIT%mld86>OUY{Z44waH>z`?gM&-51md>;D+(B$N~_ zo-g~Ev)rHWi5>W8U42?nGL&zkFmU41a}7qs193~~oTH_IHJUl}`#Cw6sJeVz<7+X_CJ}@GR?FYs&P`K`06%l-0SdLg$H+?k_(7-lZU167cXkGlN&`Hylmk0^9nwRd z*b6nJTL-^19(61)jn%rdCD+XK5HiDLLp_+uI~Ff^_Owp?eec2)MoahEKRyz^MqG37xw zed_2VLewH0*hVV^0NassuWOp8+&_4qPr4i^-)#B(OxuH-EseR;7fitCP#hJ0JgYW_ z1#oszC=YJXcuL|BIHcFR^}2o9F8;Bl`HT8w%S&%T;h{7>4ns~w8IV>*GADlouvGp2 z*RP1gzU13axc!~O(!v%=`@aoNBD$X{LKormDlM^gC~jLe|$ zLUn{o`t+2Zz*`}6(Tz4|jGi}Dzs4?)YVH;pvs`}WdK|UiAb}p)J(rkxi4vuF%0OX0 z3CYPhF@HO6M{lq5-l2%O35oL?t|B0369e&gXg`Xht_32&a%5#_QKO6)29rg$G*ea4 zbM2M~4qBh->n9d9x`P0aJ1E>ulmm!&!V%OirM*!kW^;`40U zAgP*j%UdHN5+|11UiBM({!rb^)-?XevzHb=syROC)Nkl~IM97iL+pp!Qq`kPaCbYl zjG7$9UKp>jRs@;Fga^b^EF|x@g@$?$)ZjuXR3xPcNa!W1a3WcG!1C~cFUz&!?^)H4 z@G5HBCKulzE;3<>AYF$BM^RJ@K{{fX=qBtF?9BT4+Ve9un*9=RBFBhki4`&!bwxuI zf_h0XzUgW)orl{XCpfW)Nit5k$@?7Z=%Rp>1&98Fk2%JLtKyrI#9B`f?;C;MI2y#Q ziw8R>XCrH>k^nR~5ALE8c((Wox)WA?&wDfeM3}kHtX}v2jcY7w+co}iT>1|bm2+Nh zF12a}j}%x}eMd475o5D8u$PGw%||$pnH)2t`MVEh#}tA-{05QgYCry4t76~bFQeq6#FYS z#?#A!O#CGjs#xhNt%bx~At8F)>+NP5Y$C@G%oQ1S?;TqlDRz~A9Dx_(v{0FWfKmfv z5I}n0Rg}E5Xxrq}aTXRM$&vLF5^?9<6N@E9aDM`M1t@YXFu=n%}XD0@NmDHL_) zc-h7FfK59^({a6(Se^HMrk2F68}ZT*C}17kJG2|n$3|N2A-k63jM9P6g=l|)PKJ$bxS^hRqcZH3z^94&K2eRgE2yGFNbLK>;0M5^^F z(2JUhuH1p1%7I>Sv}R%dZM}TG2Ck4h<;dZUnH}{$f!#rCHLyh%kmAy373B~ z0wx`7NWcn6WFG{=uISj&cO2y;W(9-TyUO4$rp)$-^5U`yqfFi3*p@77e z(4z=4_XBU2-OATjVz0+d4*YTmA_Hjpo1 zw^;;%g!G3?Q}MjW+&lKIoK~%_n~q79>xO5b;AlH2UB+*au$PSG47-VsirdY&n9MNx zXiurMLIXO3SG>r-tQX+&8FktU9-PRIYUQFjjmH3ALgKsyP(DOu5`F*IW=@Y!5+-%)M$J zgeajQa52Q!%-j&7EGZ=9>B@Gtcc9GjCvx=D20?{fRbQjxfmIq$1nTE^1dl;kdAw0q zVP5Ey*w_V!+Vl*#x{as}R8zh%!r1+!X(hQ&5HEs%dF{+W;yvTuCkB&{i+hDj8QGnq zdK0{WnPo)@{CBy$2P{Hk&>R)9u+(PW4Z=TT1fq62DafAOXbZO1!cAXq63(y0q`T=f^$0rnL(k zgxi)j?ite@j=4RE?-?R`<3j*QSdmBiG@suO)fLRJ=xbBMp+&QaHz<-(ml1fy7@DUA zcR0|!A*`t=%pCTz#b`>XwkcVG%bRQo>PyMeQ+gX+WS>KHg23&s*(tFA6A(rC;RaI9N<=4cj+`@H7;}#MXl++;qleX zE)akmcblT}_Jv#8WorgGg54>^8?g}HV_9;oeCv9*p7xMtuneGRNu#z!PTQps2UAy2 z_|z>0lk~y>dY=oM1!%Kv$_vORW0-#kj&!2na*yIIK)v?`vs}sp`}*aMJ^seJLMLJ+TGFS_q*7m=jPY z&G=T)@Tq6z49wckjH8_{*K{jUqP@-PivnL&)8*2~S2zDMMynv;6{=6BRlHykkpx6C zWV*^w3Z~7bquU_TN8pch`q*f;RBZ$nH_CRX9!G~TSx}J-Jj)c*Q%7pIM*=$e6Y`*a z-+D5pHUcRf>pr~y7=H=CgA&tKnH0_cV8j%Cncc4_55rjf8YON!Py6DXwW+D~yQd69 z&4@C?N2?kE!p=NDXfltJsH*He01z26d^XC$uuzu@EgNw$I<|1|BwnCus@!YSDqjv9 z5T2JoC3@LUX~g}N6RoiP{*C98!5Yx`kM0_AX@LOKlP7p=E+Cq4lxu}(c1HE|(DY|m z@l}g6U|}eZBxV*)oOqQ0UCR}MAZ;Uh+gg3DgD4~Yb=XM770F)zLI&kb-wY;wV3bO6 z`JOU~?Mngu9(*tdu`)~Bf0|!(b`sgwRR1o1$ef*)=oo+l`t_e(8vF(KJrk+CnrTB3>8M#t zQRyIr;uN3TohPGzLsqlE7@PJEYNWW3d|w|GFW__{&7mt4-EddaxvuP8Zhf5e7|UV;k61E2gbexXi(qD|g#Tf*w2`sMyB(*1)%}jv9s5)_ zJvYI{8lEEaHZRlv$JA9vMfrSvP(ono+NHZ==_Lf|Zb2FrkdW?fSUROkLO>c+8mWhr z?najmC6z{AzUTMP``>fsoO$NnJ2z(L+V`s4cq}RL4PF=WkbW zbUYm+&NNX_p z)qIwpsU2IGUl;ZW=qZjqb&<2mRcFi+P(SM-W@AE}FO2&V!$P&Ni}2Q*j+U*_H7LAqyX7bgdgdD#uv)5*Z}*ol;7}vyV^Tyi8C3e7V-3 zgebg!s(;IlGfz~cmEEy=GOppTIhLCTq2b9XE z7Q*wW)6SCn@s5K)nmq1`aW2LI^c>pIUn*yr1pgK5^4Gtk*=xC)14XB%lsMh=$IQIm z2UCu4Fah2MTBQlw`~B4hztg2+9&(ihj;eecfe%F;2H!q|6*w((5(@3xFcZ4|bVfu6 zU}HCTMT#Nr!#~=7K3)!KZKBL+Xbw34Jtn7+@$h+Wo2?D`(d2h~Cf(S&eN#uICj&?3 z_1#JDitBfEqX1_Zf0Ss)$3A#?O{&ZsMxzUU61t2bm)tl}r^pnwP8+1)<$bzq5Z2o7 z&rlH2vxs7_^Cmj60#twq;g?EnEr3WEcVML}#KQD-ERl4`;<_gAd8$U%oTuKLcT0dP z`GiLk(^M3&EY$pTRgI@6C4PORb)#|Mw45j6IMG%6mVmB&{bVvG=to4{f(7C(4k~@6 zrICyifAX%n;h(H4@ClOi65%0=$awR-%iCBG*{I zuA^;^MA*x+{>*cG8|?o2GxF)aQloy)PJIDX7mw063TA3aQFVipQYrrlGengY5{1^A zY%r<$FZU>x>#%{INvb~c0u;n7-H#Dbn--z!@1fJ5Uulr`>=!i7S|1dZP)r9!^vTP=HKqBL_gXn8(sY=K=bb(n z2ux<`WLeM7{BZfRST;J%=cJVbbM>%Vm%qi!*bhN(~rkY@bfF5b=CGddafPtBeEnd{YcMRXAfr z)yFcg{P1gx%XRnd{rUAxAr(F1=t6chfMt+5OYB*3kD7HG_f$-D2wUw4Cn!HGJKvlR zZa`HPt3M4hZ+AhC3q=txAoCHh+;OTBnc2C}QPTsY?hyFrGY%yp3y16SJW~m-? z42V*%UTQEOlue?I%ar7w*4Ps%7tZOQ-#?IA^YEiMk?%r-Y%T|HrsIGoA}J-^(JBtY z)i@>|GsfnB3-1zsk|@yeX9$6U7O4CaU~7>@#|6AX2`>=^0=dqg3SidRpN@_wS4j~V3kHr0wBtasv@Vl^h*2=GVJK3gA6b9e&dDIec5j7);Y7ov zYTSZWnLp`q;{BVwP2!))*j}|ou-K!IvjI^tb7JXZ#4l~}#57lvx;Dvs0!(yPl^NfW z4uQ|~g?q<`9)Kc$*A8L%u5}anc9zNNW9#u%;9vu^>jJO}@QDDH2nEHwS*d;pMROn& z6>bl2592slEMf?~Tm2uVQqqJ|f1Z{uk6Pb;9uRe2)Bx;;)Mu=>p$8N0m& zDMs$=%&4iHyRpx~2jQj~R;ow!2iDI350~v{2q7OpLi|mN^1$DZb**i5liRl_^FJ;q z0JP0FG^-sBtTu-YB{$5kasI)4UC(p=J?9Q0jlQjG&t)V|He1Ien4DN>geXivg{>9T zn@2|Wm%tK2dGMN|QDH=w?6XGT_){WmUFfX`^cP4W4iHOjq!|?{3}V~I5sO(;AO-9y zej`+iMm_G?*x8A$)4AAa45GsDc2t;G!d=P|On>!==Hwl|l;or{J2qFH*;~(fXuTFm zdYn3R2UtZF8LZlCs;L7e^n6V9Q$pOGG#wFhsTE+vhTjgDpQS|oC)6qR(ZE=0UQN8g z&w4-8Hbp7nr3~?n!wVvFTs#0&S~8g-ON)Q?GJ;S0`rwo06Ra}(5qR(;<-C{xwk#7C z;O!3h;3FPrLe$4)CtuDTof$30-V#!xDHMg&*(;LROtVeho=VRcV`k-63^F_PVFW8$-A2!@y$|LX{>w=oP%{M$t z>Ej%QgaN~$24Et1>5%=>LyI8{u4?THHJM#mp@=b9bFK>E3Kobs* ziJ0`iJB{e+>=5Ya;jgIhEo*I=fEejxmT_GL5cZ%-LX5Vm8G0F`pV#LwEAW(>?A>T_ zj?bGfl$omJZx$(A6BlKCSzo19n=(f3&qt0DWqz!n49W3XCLBx;2Mr> z|8vIk){Muc78~nbab4g;~1V6ou~EUq6ggENsGNtRS#+!zH#`} zJ^01zp$Mw?{*yzF99o~8W~1rXZuBO)Z-0o1%7rbo@-?bJwkhq%S; zjeVTPbCFK^Jt<~`2)W(N1Cwm3K8?p}QPimn{AxzBWY?HH#)=5nc@@Q2>ZvNc(TIJp_6|BaNgD1fPjVwdKD zI7z^BbrZ@){<1P4h)fM5i!W=1TdP?7V02;HywZd9=ri8^h=Z2zKjE}{CLRnTM7F~k z3{fX|^6BZ1kq&yE93{ep6y}FJD#%yWImcLGWbIl?ubr1rtP)alu_Q1-2Bw_Bqa9yA z)iK?y9J&HA*bx9kJ1dQ0tuX7ty%HWOVvX7OCC;vkk;>m8<-J8v+v>MC0I8%!c1Yf9!s+=rf~fc~_%^Pt zBlv(Y61nk0kMi=4JBe7kfu@XTCd{wM6`uXJ1g0crW%fJ6vZ$P%Z_t5IZUOP>#bWhvW^#CCQO)B}ilkNoz zPNcDpa4`wfT{|w@6!BJs1!8=NVuvV7hB{^6f88=MomyNp$0T4>2rSy^DSe@>*1X`X zpciWk{c2yNJ_yyHdW#7NJs~#B``3PJ{QNm|qMS0pmyrzek0vk^W9ed? zI0dciK4V=(cI2d$+ly!e3dH27gUA{il^)Y&ugvK{8yJt-3M^zKycTgMk&T*A6nXxd z1&wHnD!Km8jgMOo@g&s<7Rcczq9UhPMt`)jzsW&Bbmw&X9Eq(-h3xbYpqZctd7XDkE_!?;>>&B zd+AcPW?eb^O3A{WYa?N@z8QS27PlQoN!tR5D8L;U?xjZyEzZpBTG&KRqhhOd$|>ps z;Ag!CANdd^ebWU)Di5dq?w*#Q#Rg33@5*c>|E{T1(Lsxu%OoP8h6P2-7Z-;q!QLn3 zbeBD>phYOcKAxc!>DoA})c;l2CU2d*)jP=0P<_eP&6vtMX*LOWlwf3@mMVp*E@e9M zoiPmOm^7?~195`tL=4`|OOrFDfARfwPgO(etwDKzNN+9;wphnf$-tXa%A&OQ0{m@B zj<7AT#v-ofw{LY8Re`(K3^c_zxjUD77;v>&?MqilD+6$CuhDA17A>1vl>=^aLi2B# zuVEzeeR3hHkKlQ2hjx#a`Vw(541z1E*&i4n)-mY#pt&Zvx!o!S_lpN% zyugx!+g%W$QI|CMau|FmANQb-bPdgcaS2f_wq!OfT)*s!iBiGG8G7u&6?tC3rQE4$ z&E4NdM2H>EqfI{F6qm+#FDY(Ip++5SHsCtgKkH?0u=!Hg{d@&7^b}5f14C}c+QVOB zVK~qx?;8n8BO@>A0gW9=nwm5^s6M)W%n-?^1uGyTXZpfzAb=9J&6s{MxAxoRfL%*)Uyz9UYcJVTL%Ex_q^M%A`Fc-UAZP*L=&o`;GlS@I-Vl7aO43m(n2N^cJ4^xJVh?aNa} zza;p%w?<1+A5fDh9NHT2Mi86qd54AD*RTfAmFkaxxL61HvhJ4`2TJ?a#+)FS+e?RBGdpg6$x~k zP*o~WISQgL<`j!(B79el6Y6ZGq$L0HOGKkhMAy%vow`U&G1(Gq>{x=0&?CrP8M(QN zA90phpqrOhpu9_VVQya~m6+R~@_P@!*w5xT$%|rhgzDs7{qBst+lITJJpWnO9T&M6 zdRw`o9jRiM6}S&=VOWdy{q?KSTA}QAO0Zpu^qL&i#_}I9UFUlWrQ{gAghV0j&lGt` zS%#;aVv_i!)N3oIXV27;d zgG%{IBElf=?LUg7Mr(xOylh|%P|x(VpIgPjk7(uBBR`a^p2{ym+*lrKcH?Aq~a=B5&XR4RjEui|ulu-4%_WF>}OoV`*yD!P= zitv35Z+*(Q&BNYgOIdXVVG_kvJ|VJJAu;sVw404Y7y!e5*B)~hdJw+~CmAWtk~bkhJeNnuS0TsnwET z$BBIEr!jfZ=m4|+a|G6_ubrscmXLn(COpkgbS%Fkc?SudLQB3z5NUxx?;*{$SU@TT zcta@&N)_YB{_+`BUBe2xwTORUFt*ClZY#VSWO}tszV2ULOBOF0SY{F-qixiP>>O%P z&Q3e_dinReF73a&>wodI8I!++e)0hvS}cFYIRiHye`C^}Y12!ln4V4lZaYC>bqiGd z*iFKCas2KL)>?-5z>7iGFQ0KtSRMJSz#W|0YO2D+(~>QjesPg1Kg>Y0Y$j58?icy0chL#P!In`@3A zi1N&BEq;Jp$m}%{&7Uib0_lE673xDLoN%Hd!8O+<#utEd{iL)=_>l|uMf<~mpb+aX zhFIV!Lg1Vq$|BA5sIW9*U{snfyYN*$JYFYp3hx<}KUUET@V3Z1FemGl_j{lBvZi16 z8;|y$`sKDFak3(iwRfYjK-G*KbcjKay8r{^qf(-~{z2nKo3;UZGMCqP(nUX!2|Q6x zDt`Ky9R@AN1FG>9tQtHd4%R-4P(NV_>c@P;-c(&M23+PdvkgJL3wn&S<+TN!uO07q zBaKU0-0X6PBN{zMVA%~Av{0whCtKB_wHD>1`okq|QZdPCwS)zFPuYCkN$RdA6wxt% z#B+HIlIe4$8B-Av4(vs@&951~o{rfvxZL`J<)A2~_3D0MhRfGOG315^BznsuUz388*CLFXu_l$vW|mZTs4L1mDOo z=ce`V>+zN*YAAf&t2oe$fGctA^kap#zO`CLQ(qvA$txitmYhmPpGdwuS^4Hrq&@bdZ@*>h;G>mum{&IJO}KR2TlRi{!?mq z_?1&`EBxk>VJx(fC~k@fpgw0ZWh8tZ^HKb(NRaLMKXNq-iDKt^6E-owYdkULL3^sK zR~D9}aD(Rle?7fuF|4SYcEn}4BI@A)cT3VnbfwrbsM~V#2>=w&NBtE!cumfGNm+h| z4t=JfLQtN(0eu8loQ)0X4MqIMtBBA!$4E7SH{wKV$1k}`TEc$3F3M_BBVdJ&`5&EX zgRSt0coE3MRhp?`Tq)PpG?>KqGBIQnv5HHEi8!>T5!}qi+oz_-x7G+)yYnGptFgVO zh3Gj_6ObD8uBp)%s|H3^U@9{`FbhS-t+i@k=nTuJ2IlcG?E@i`9IC^OZ#d#%pZ}9K z#vLe_MCl8zLZCD@_9W4KObRcUI@D3ac1Z@@ESFCNH(0`bMvxR~rL}a@Ps+W1I^gH| zvH0Vju2}&+JRl|`G@CDGg%H|mKit!2l)5{Id{5gnI-v9?RB+%5xAMpj! z@VmDctY7gX4XURKm@ljHTDr^nw)NgxwOj!Vv8Z!3c}mvmLMgeTh2)$X39;DIlDs>NPPDi4DPhjq4F zq#LEX^EL-Yfz!tYTwdz>tZ9a@H7zf%tmCIdxHYT=?WL{X7ZzX=VY^)fZoJ#|HBxFq zbZ_$fA-iA}4KRhQPR8`cDz_IhV518-%PJ-R6juf-2zBjhFtbgM>3aI2Im2$8ATx|# zbDf*uU`tiC8;799B#`l=Gh1cAguQ*DvQiSRf zMzt^#r_-(}qJrra5z!2$TZ`X^DmEc;{d0n+CK>|hpbNytvxF8iOnG(R#{696gJZ&lUk6y`samxqOwe~V7?@=5NxYMjmH2C=5!q7-LCK_Z<|;Y9ml z+wd~N0$lJy)WbKj_#xZM(D!B@fKgR7Mao#XMxsaw`)4uOQ^!D+vQE>~T+33o=Ba!DPeF$H6V99Z@W;TOn59 zVw|kXCwO+8xppo7dcL*SOtETK;Oc|mT(bf&%OUKcp&xBCHNxrr67i$nXn=cRe|7!a zC&2G-7p2SOp_azOxU$~j(qLkLJ`$k+W8uKo8Jg&{FSl?_!RGv)jcS4=0a(IpEUf!1 z$6|ah4*wAcm~RP^Tpg79Q#reJ(1Co7XMUl0leL$B@z(D~B!p@RtpEeuRg;^=nTNyA zV)g|!b(VRg7>k2Q&)~JPlAcq2N_u5S3Kr+ii*I@?#Pd-l$nun)YrGw&oY}%3Z{UtF z`qKFp$Wi_(f`v_?^C|+GrjqlbZ4-;|==yHGd= z)WkL5sXNJ0jz-s^e9k0E61> zfvB2IGvNEw%nS@Fi4?2)@M z{=9fk{4M$7TSHv~wU+yea~vSO?{Woq=#?dx)dW3=5(4n4POVaQia2g@r~QoNCd0#~ zq|Yf@X@|RVD0Yo=1VI4LhyhuH1bElr7LnCI-Cb*J)?|gue#ra#>K(Q-SZ-yDix~%^ z+Pr~62RgPAXVpznv{ZEt>05-^A2mC9-h5@~hc2kAtB;S31$t~o_MT3_4YN~at6Xp3 z;SIu1sQ2A%&gze4E%4};I)9L?_mM+=VBkJWsyG-yeJsxgBiQ&{29`%2uhy^M=>-ZkLQO_br_KbU;EMPUo7uqNgu1>}(Ed?2T9TYtua>AcIplK1m2d#`fg zzT?=u&e0YBSixkX(Qr!jX;h$n6HMpmCdMw+N0(LxcWgz0&p!J?p(zgp?%qnU%PcWR zZL4YYkmOvvq~~#%&(DufR`hFo&$b!JkR|bKJ7ZO%Q_FLB9@q4{)hi*>AJb~2#;y*M zpl%+}ny=O`T}u4(EMHT|#f7A@(w(IA5wT$KZu~wtvPYf>pV*gQo}qY=-OVyTOFW`~ zwBMCKirjdNt28t65)`YCWX5EkSZ#J%Elq9?4E)2^*Y_dhUz?a_1tH?c+^jurAI=e$ z>vgOU$d(o$s4WSgGdZCG?PHuUvpQs&u_7ICZD*0b!WD(X|{cmyh= z;2)%w*0!rb?^wJ_lKI$IFd?VUVo-wP$h};}&fKB*yx0zgx-#?OR13UPOlw`v>hXsa zM_n}Lz$v7s!PLOfU8~Qp{zu43IX4@qo~bgH#GZuGCKoltrg>mZmh~ved7_SE2ZPt2 zzdEBnvYIap{uk@hEEBz>bc3+83HyRP>lZb5zxmg!QiI0O;YmGhJF9<1{gTZMA6}r| zr!oD^zPLF7$Dw$a`Dh-Frw772$_v4x9&-a1{zs%Wvq$a;^?Du+?x;t>{)|lKaV+Xa*$sf}D zgx$+{!;(@Zd2R6wSR3jf8**jP;8Kj$EXf~8}~^5Fy>7uC8_I8Bk;HZ?|Q2r9e~sKjh; znRdj`+>=!2hg&ly8KSmGJfl3%jsFBB(+Af`7&3RiH3Nk(FtIQz#_Cy9Ffn`yM=tJJ zToY3avfR990-X>`0XiWipfy$kjo=^}kcaRYZ1y_Q?HimAL>whhH6U7JZkp34%1mP1 zVTB7U4>Y`zF`7c`yS9=~zo>Z68L~z9b{Lma$(l1Rc}3W^YO?N)JRfe6x1|<8f^Sv9 z2}Ri2hF-1s^lPZp7q!~HeJvuyjRx!HD3KYEjC|d{*n3?S1qJ1IY1m>Ve#j}WQrx|M zUZ+&g3auGT3Q_RjL10Y=CIkKSk-SrR_&|-wpPDQYEW&)BB>nns?syU#ym}JAB@NT8 z^z{4>_3pvoA~fF=B>t-piIYA**WY9A58)-u0k$Efvh-*5I&)oK)?~Wd1fqcQ7&=A3f?a)0iF=0#)#Kth0f-EUBBTF7#kFi4A)6Q{e&jW%CJRze`21K9!^q*yBPNZ40%lC`HU@&x$)3bI_&xQ-Hi*Ets_4EgB z$~+4zZv&oZLygnQ}lq_PgI_j#e!yMKX_NdcPed~y)P z2R~b!eeneq(i6(UxAh`D~(Z=zTQ>}jJT1SHPH5V5C!14{DWw#$FA_H8&q++YLOJNd57onI~+Mb^+7 zjX@Tx)s?!)Z`-+G1vkx7&qD!4ZQQACs*K6Blt4N3d5)hiR!XLon8P)NAJD%DcZIQQW4oRX zeQa>z+|KJp8^n$3%i`C0V4hQP{a2?eaY)0xLsCsQ<`&sqI*I( z887w(33nYKL&3Na8J{sRgM-C)FqQ7C7p;Dd*(mp4qO+PKIJA=o_n7@!AnEOh>nj8! zsVF606p|xGY>raC*J{?`_`J_D8t$E!3m$7&v~V7aqptYY;xh!@3y0I?yE?j6fM~MG4OYFiZx4hXDBH5TkAH5iWS36FF%?la4UrVS%&&AVxk8^eZ)9%l z>XIZJ&wB^b+i1$mgmGS-EKR~inDOY>los)=UtW26l8zx}Zu>-Vku#yaAxukHAMjUiYS zB!fZZC~~D!ouou-1)mne>RyB?R*gZEt3?EA=zdU1N84S;g@dp9pqyjM<8z;7(hUq) znoWeE%`~zG8z*gaYG8*0`nER$7cZ16Z zM;g7h=efRt?ZC@J*r>#tgV5ECPYXhQ9pCS+Bj@oTHc^jOOYo7?(7sXTe@ckxe7Gp( zWdZJ$fN=n8i|})a%hfJ%vhu!6WkX~23j{N)Tz&GU#A(H4(tEqX+Sg*a;_VX+rNhv1 z1g%;^;O*$?eMR3LD=JO>%G11E6W{r-@dFGpW0cjn2=%~R0rfn(V@F9Y2#vwUbYLq3 zMA9EL#0-qNnqT}G2`o}v?eEiBdN1OVr_TvEOiYM&09}z!tK3B3o#-Cju;DyEwf3FqmW;n z3Z33w*V_9W{Kx6d=LFToOU8kxKKIeIKZ?|ufL`!!o!ssD0On#{f~P_Za`W)8%E`DS z1NkS{o{W3Mb?(dk-EMF?7%?e+K`V)E7i$eOaLKL!D%m?9C3g>p|C!QoAOajzT;mSN z5cbhdx!z{N%q7(C2ts0s0BF}uP_XTn0jUw!pUbZKR2u3UiQb5KWMOy7DEWAkK7u_n z5l?ZGv)zQp`Wq26=w9jLXH`7KSa|4MGQNvsS+QsuG8A+Xc-4{vIww%C>S)W)p?#o`wWmhTJ?vbwJPWSNtxJir9Dx{8af*2JWUHAu0Ji z`3!EAO?@1OY`Ko3bn$zFdJuJ<^R~slnrJAmqCi;_ZS_&s&O{W#I|o81wdD_r#S=JL zN(P|)jRI#u9#ox5h#-Gp+L-YAQNR=Q1y~m_`MB)5@pU%5kH({pZzPNqFATovM&FAk z@^%TL@v3i+t>?_Fj<=DL4}t1zWox-7;F}6+nLscDPyBhe8Y8%84I7(n>ZWmA44;k- zlXcTEKe3|$=nmvn(M`Q|HuXlWTp~Qw{KE#7Nhb>gZ{n0M$12FW^}7$8$1^A#9JvoQ z*XhWLDrxXSo@Ild}VeSLj9k>}UctR!i<1hc=0zk`{P*RrMRv21S& zjW^h|vVm}5LhL}BsM>-~XGMRO<#jbqrz zeTFta(`3Ud&z)?R_O}L^HT{_dyb7UuyQ6{BsBZ%uWYrf6sPA#|zV`5|rBXHa^t+`% zM+H1^#GQJ087AXX)m1rWx%xh*DE}Q}1>x9=xH?C7{P*i;W6EsWvkOh|cc$Fq>=f1K>dq<=h#M*+}$UWF^!Q z_%Z_F`N|1T(7LdfVW4Cgn{?W& zh<%e=!zXPVIdaAKk7I7Ra@9C2k|fE^pLswMBKtyz;G@Nif5uNIJqdJ# zD9hW{7`*p=Z33V_GWXU>hEx4-W-4&;d~ie&lA=TyRtCG+VHrj|imKEHDFrl#Q>vVl z~yco)1M`yAOP`_|PDQ*AR@`HM%or8uWM#{Js*pnDGzOBOoY-?I2)pc-p`@`l< z&by}epxu(y_@e-QdxQ|sJ#ebK^6L1P?z;kx=?TTTz=*ru59qKvn+?j_9gnO~op#1` zN}FuFkHi)~d2NgT{HXx*6aqTPP6vPkFhw;bX;m+sAuvyo#RmLr*5aVmPPLgA0(*aH<4FNIWw%NZ|KW0PkK5n`Iy=KK2?^<7tK=g%

|XZE znsq8LMVr+xepvPm2FAuNe{Y|T4HQi;>E7@{7MhUCkl={Vh1|?}BdO)?v|6bBN9@0d zEhb0X9q9u6th8*dAxSVVGBhMkb7JZ7KN29y!+<0IL?t%!I}{O%mL;E6|IUq#%3F=V z@Y@{5^E|}&Q#;`?0?KE(T!PVk4f)FyBZztaXDu}+0$jX!?il}e2+EYy=?859_x(?R zE}M$PQ1lIG_i;Z=YGku10|++2UxQnH>4x83=HOCJT#5KQlL%uxG6Q0ih3Rn5_X#hf zzFIDD`V6ope#k_*8{QK!B(J=C&9CNrF?c;9h%%BF3qjm?JT?F|uKz%bC>jaS1g(W0 zwHgl+gyN(452Vb=3xK*zxQ2xEnz0l#nj_#y?Ydp_IkMz+Y@S83Z8ql`l_|Z((v%Kl z*TI!zSXgi;i*V{;VvD(4i?YsQ9(jpRwD}OBI7B-TCeliB<)0|-Rey3D{ECqJ*WbQD zvM1kjO%Bl)8DupdStiOc_RmFr4-nGLGGU^J1S5D!==RY&JmBEne}>V9$Ti4uGg?|H z|5%xh!Y{NKjkLi91+a6lUs;VqHHcLgw&c>g2om>=89x#p5?Je3eov^r^WjAje~5X6 z5sQ7o`%2ph0+$LLu6L}kofB6K-k*_U6E~|(t1tu4;UGhkL8xxosufl6%K}wT{DXtc z3|f7bKp&Jd3#|}XOdzBq;uHDtG{^xFl7qBGt6h2a%Hw9-lt1&^4v(-Qf4)*s+_O-r zTyg-%XFaOt#5#U^SMcAFS|x+K_)W)g{PFEj=F;c zrt28#asVAjrogQI=rYHXR zpO7Y}Z^Dsv>g2@gsHHcjqJg3hdyw78YsD5GsRTqGhnop)58dz!Z_~viE8pH*y+>N0 zU04DO;Hq(aAOR|vfHf7_?Xgo>bPM$`YjdJ5%of4U6|Dp$WqqlAfRby;OOF zTiW{%hPUKSs7E?Cl2 zH!7m{`xH)}KSd(EL0_N-^3NV&IIr8O^UT;*d5cJbauQlkD;Z_P$;tex6B+%mJ$cH1 z@MKce*bWFB@~_-8@d3IP*~FWQTg00>BxtFNpN3M8+PmVh74c~mg0oT9?B>|}HZmXM z;igZPi?mItr3{umLO2!e`XW@HxiYcW)=`$ndkQyS*!mKR<+B1fOh8p%F7nx6bS?O* z+(Y2PqlO@P-MbX&zadZSfX|}{<@$YAig*pPpXYoe{m&mHz)LQ&DDr9xE4VnBL zonURH$94YX)atKjRdZ#YltITE_ULG!XCPoQ+^UH8p%5F$C%{)|KS6tl7Z8x8<@07o zAiuXSI;3=_!5y7vpNv5l@nd3?8zx;S5uAZU-*)}C-0+_ei^A?0z7?*N2GJxb$8f$R zcQL*E)}@H_2d?1&ZmfB@0l&$Q(x*V=vBt{-xcL0z0={_vHq8kUu3@Wz@Hk3Ho@diw zgt$_-AghwWy9hmZ<~`_oQi-qv;>VrgIt{D@7yy0E@h zF9iJvxw-(o2ij}_9r(Cw@79`r9HU4@50tszT=IA?>EuoI-Zw5t(x%ymqrU4eA|QQV zXK)4Rn5fQi+kn`&PeE);3fqKl|RbY+sbxxl%_)oMw z%i1cn{PC}4fqD4h>Fv#bdbte!;V2+XCqKruE z#cF-tc0=W7+IU*m)gZ3^d1NzFxSV{>Rb*6nk#;668JdpRRx3yln){}TO^d%`HrpM@G4*tarC zomcgO?&s0MdY8DXb**HL6T;|R3kiqPstFNr9;+Ij=yUgFCWK8cm^V5 z2f4X}yfVH@e#}9P0Bz;)&kZxKe%Ti4mJIKR-(=OovHQU;vld^zKtSP*1a8-KFDyTw zdUEVl@ono@6b`^u?G5aGCl*wu4}tf!Swl#CAvKx_KHT?F83@&W!fnGhr*Dq@~dij|L8HO*Xt$6+i{Re17&37JL0*eI&UM^=R zOl18bDv;@$AB7}$^+4{7E4`4TbOZ&4prO2II$|0SEkkBJjV`x6)Tz$B3lQ&^ydtZE zGrBz+!s>%1QLhn%KttTO`m|<+n zOvoQ*#{FQTNAZug)g4o>)41Bn2VLBy`HHL(&iPldn3#!=$P!wP+HRj2#p{dr&bQOB z{;pyk7<;>T>hiUKIttS*1{l4EQ5p*01PPyI^oNdso zHdc6`rx&pu%$0kYF|?TRB#HR%QVXY8WynX6q1no6@RwQAUnObs9A*g!#*of>q#J|c z9^%ZC&F-Te-1}1P+XnqhV-;X$s=?L+rF0yv9jnL*x^J>zV7Z5t{O;!JVia-J_hWq3B$r5|l1H_Xxz>w+5EK;3(lb%n|~S6TqN zfRG1!+jmjary*2LC^t}`xVSxo-Z&sr5zmDMR8Lde$RR(~7WDow?TR|;eIIX8pI|@6N9x;_AwByFU;+Y0ZX$lrCpnsxv%>e+=gnkY2`NKT>433)# znRNpTx?U7CH3>lwRuIHw<+=!VHGDk9wHQeg?Ip34;u2{a`ygKNhm%jh#keMHf#q|F zT(U>1|Kg4tN)oFPiqZSOpw3{Vmc2nE6qk6f#it{DsJen?Ph9tzQ2wn3RdLLFXl%6X z3{(aDyL0z$qE$C*cAh}izO{j(kg;ZkCGm460b7*eHYM)S9NoyuROUJJXMIYex#ZCa z^_$pb;twQl98oGjT-3YlSHveZb!JBsETZq0sLHpPJZE7^T7bRWK#Z1(ft~L-uGn8~ zx%jR(4iWe6_N{J3a9soDg67a88riOyhN0di3nfjJOq@3k7R>?Xx7wnzC=EXh19hhO zBr*`BIE&D?oAdM4mM@z*+w8%&jg&0TM2z+nin7XSk-_^oGCo?gWh98-@9bMUo8bN; zEj#U4bkWOQ?H-fQpiwd0c3*HIu>)YL#Y$RJ&Ip0BCr8COG`W!8Dx2rMHm(ZbGq9?y zL*r805Os$g(D{HU zMdJi$@l63@kJ${5M#K<-c_06FQQk+!-k=Qm{Vbkzfkx_xf%bg5K@{`=a{~mEqT-^T zN`SW-1n|WE0kb5C$*>t$Wx-#lUvu)Cclr7v3;%H6VN*mngf*WSYi{qdWY6uY-+bx) zA8Fkt`{%>s$Dqg4FC$1HP}X~>1~sc%nqY|_S69&D6JC)*>od1z#S8l{@1B@-0zY7v z!&M+6YO0Ilj$&vc*PRj5Gfp#(#7c|pHb>k%=+2ftvSxz|Ubvp+|GBrF>%_kZDGTr* z|Cyt^9j>uGL*d#fz?8_2J8K=wS~?w5ST(9bq&MrDGjrO)StGP9;J%q{>x!aotAvkl zlrSaaCL?fE%J(GS;c`vECdZnIO<%hLdXpFVf+kZT;)F_~V#h;M-lU_i`d?q&4xjD*^q{qT>vL6b~FCP);4 z&Wa8=B_;4c4H-z@zkTt>< zZVUDS?!tvYQojnulRnasL}?!9`h=Pg$;gW5_QxuYbf5aY{ z>V{8EqLgE^Ob;HM60^L6N0yU0FS=?1C*=;;^nso(OQX*>`rXNr7M>Be#Z4OtQfX=C zu~HQN)QC=wcoqnb^{iGXsQCX=_;HQ7?cf|E;0}$P%7LzJj2G(y>UNx4iT1N0Apgq>!ZD5cAviFmmib*n;MIep4LV zU$1-ON=0hEGoXJP(yOemcbZ=5xlsd;+E4w|r-v)>toEw|Oh)^8i$iM#@=+R?5rOtj zd9@?VKO$+@DG{X!(cIFmMBI6sO(@1>xp2A|aa(jQ`@cUwp>%(&eX1ho?``81s}Z2(fiKWS07Gt^xOLS4Q1AI(sYg?nb_uG5f1= z9q$;=f>ojW?}AhlwRT0_c&N7~vE;`nfk8teVUd+NyKEv@Mmp2(ZtGhsONVSgPh032H~0zJTtv4(*Ry$E)-y2$ z@}1bo@S{OUL8Ye=2%|mY0~MYZ7Lec+Rc-&%DgMUtNRJN0ha7~H*R=k>-9!qFi15I( zWAiVJP6^rPNRe2Mz?&@&I_>ACfGH4S=gU+7eL8{8n6v}YC>KY=sO@=^O+weDD(5!B z%?c`$EN|j_4Dj-oYrANfZypv>Pi=E6K?dqz?Y*OChmC zH5RX$6@73qmGg7$(%t{CsR-?$DOnf0#}b~$*9X<8O|LU8SR3}xFPeOGlm}+K*TQcZ zC?rAV51)Qr)Ou!c{sID)0%K-8-~BM{G6lMq#3QH`pEfr$@KOrAoc0#W?Pvc0Chfg; z;JS^J`(R2`xI zyB-|ukVXgY0wM5!;m#T^aQ#e(Y5?=CTP(c}zpUjps#hI?Ix;priU?GA={sb?4-P$h2oTQEFAEdjxlU^c}1 zF+|Eu?*h}DJi<&EW(jRh0T>;TbOh|sG3@Zk#)P!vcMX;sjxKlgMqiJ_6JJa9OT%r! zFngFUwy*@lg5lm1rpPy_5XuX!f>#{FJ9gADH|#K~pp`@V%%EMmw;3~lIZpLWP0M; znrRaj8g9s+)TG!IMz+-^X;Lf2E&Q3VQn`&Ti?uyPi-;U$n+OM=yFlZntg@g2)}{d%y>$h;)M z@Rcxp_$s<02hht1An#*XO@P)20rYzj)&e@$y?nJDv~I!}3!VE3OP-W8BXA5W4cGwN z*-5p64Zys6_yOSU4olmz`EE4g~A_T*N;kW*$1j$3U7q%~LYRiZQ zjBT-7$|Hp&CIH&xw%150+*EcAKuDS0)O+KTJsedh(^HceqkLIK=M`xf0Y8?V+~)8D zqvenS5XPC!cdry}&@Wn=MK&4;$+fWZb^Sbs&+3N%ieY-g0@K_v%oAFJCa2;S!~J0M z?MpaCYDQzF&Kj%7Cd0qgKenDQ3x);5Z^m%Ms18-|SskH-K^>y>wS?}+G5jC6VO90a z4fk?eH$1@iPjk9C?$U!08ljTB-o6{Q)D|x1GYv~`_*Y^0;Qt#&RtIWER7Yrie#w_&+c;`dJTNJ)te+w-#7z?{jAg)F!R7P!Ipdh<}RTPblT?FZj{L*I))e2))e)~ zg2`pjXGNm^##$k-SUolwj$x%iC~w1Z->_i#UC*MkO4KCJqC5IOCDsQRwg?u`iU+2v zhqoRU<}RUi9@dz#u2n{`@Va4`Hucs95Ya;maQP}a18+%@)w9rbG7Q6n_rN?b-8k{G z1jB-1(c5(f44=~tJ5;$AixP%wj5>N{0?4(pz|@U^j;>IT1;lF#fS$?@Q3In}I)*8; zrBJpN^i+@r3QZR@Ev%l!P$$C^-4*t z-}%iMg<$wJ5;uHli5ot@p3w6dh9fL{FaI|z7#0klQ{sltul)Fam}eNaJkOS=ZwQ73 z!zY!v;S0z-MD3F&GG*}mR-Q%oi!dy`;cH3Uu;^t8hEF4L!5t-hA%B~!=jfZ7(R{uuxrP*4Z}bbhIyTe1m403U}T3h zsSOq^v_)!mnkZFf3ABd?@C1e-(h}bt{%;22$HRfFVb@s0Xhw!*kYU$Y!)Qi^WsqUl zSi@*WhGlRYc8xWRcKsPXCoS(WGRzwGg*A+3{TVKoq~%h`Fb+06!>nQ7x-)!DTCQXm zM;o4D*068g8D5i?pBNeDHtY*)7|r@KT>q1nwT8$rYuFdoFxvHJcurboGK`}Q&+z6o z3~}2sY?D~dvXNmt6D`9=hJ)Fd;c`n#zDtY@a~t-BHH?uNuD?miQe$M8HS7y(7$Y-m zS*mB*$S|IYmSNU#G+Q%Vl>SPrC3=S88*3PQWZ0&+q~e@UK{9+I!!faj@v01~UWb=r zK{Cu54vIC5T{3LbXVUOB85xE&jWrB;n=@Rq##!PcS27H35^ETaJ$yj*PoimawJ;gx zHXM}18ir$!A5c*^4==^yWSBJ^6l)lJW!TCxylP7^G7NRB;d?uFteQX&1Yp?du1MHa zf~ai>SV>xoH0cD{Vhg)Gg7tRyB0fX7mkGX2Zg&Z$RLJCR=l*ZF*6QZJL8xU|!so+m zNH51AWEi8zH4MEBOY|SJ;k@}MrZUWb!$xrpLove=n|7#!__=MO*vc^1uu)vY(8_QT z{nsFEyZ9hNhEW5qVd!PJ2);ec{?~i!gA+20I;dX5OEPTVEiX_E;dnV6Hu{l!+#F7q zqYqI;>}A;f>{SC>o|bCYaR1qceYd?pF@_KteIbOH8f-Gd`Ml{n%wn0dT&P^b`Lm5F zSgi94RI_R_obMYJ%b--@KhJRaY-0*?g~@QDmtpqGIE^iG`5aCbjOj_{WVlezaM>$Z zl#XF13LWmP=P++odxfjXaM>$Zq_IUVy)VU_F+Dv;hBNI9m&IbK>`kJwM6S2W1N)?I z^<-Gw)rv7Ox=ZAoxb(m{sa{1H{vBfBG4Uj#!@zQ4DyqsbY;tl{*N+2a7yznAh5_In zWEcQ!A;SQ0j|pZN08I0v%kZ|?@6KKK3IJ2kb?4oFI}+bHYh4{93@HWx0000gDjhK#Bx}&^tFc#_CS z_IsS|WiJ7Mp+NZGKNJK-Y1seup!bP`!`SbaC(AC=P`CcQn*6}?t`$J`Uk_5xw6?td zXFm|01Hc>}`>zLc?_Nu||La81h43(kf1QX@koZM{wMfn`9@g4Zae!Y{Y1*2b5^p;A z*h+1G5LLC6b3BBLdGz-mafqKBakE`K@LPXB9esZM8(qTqXzuF$$@LNG?1HGrK}Su} zz;%wl`B+cmqj8p7s8o1xLli-+&M1KgI5_yo?c&vqXoEMm@9DtO(*8vy2ko!@!@{P% zyxe~ITK``h$6X+cBQ>j~W%Va1*9NE$8_83{3Gn&e;b3V*Os-EJQB2{{zvk?q`TymRi;*eNu|oV7WvzX z{}SSy&k610LZUP)oa43*ONX$36CBY<7p}4%+Yz1u*^QlAu?y%~Wq}<1@SND`5B@Qs z2|PIc(lT((CcpXZXNq7KfpzP^RhFI6zMO!??5ZHpPkP#kvOD8) z>>w}WwbNz_mu$jmVH_zE9NTLT`-dl6o2CNa|8-5hO_l2{5^~Ft?ABkBjh&+xLVQdv z!o^_v#4C|>(nULAn>$*zuJ!!FVj`LPu>xAY0gLd(iCY}tq}P!-)<6LE=Jm=W$1>mP z8wk6IG~=M9J(Qz|gbH1Nqd`(rn=eEQaIfqF!ICw3@&inBs`=@O#!`Iaz}7ICVwgu20#z+IXEs*MjI9Ws6pxtp&7DlgWgUFX{S_>1 zM0!0eIN8^wN}uA&OY0zKS$`WW)H!U*JTllgpwr6Y^Rrm0G*hdvck!|Q*2Y${{5ql{ zE-+8ckrD#EgMTW|u$taoH!4lBc)6PnU+9(Q$81S4ey~xnd;RR=xz^N$&wggD!%Z3% zoEc;;Vf#8gmgPM==a?#rY}ZY#y;o5F!@{9c=F78{?zHJ5!!=E!h(2H9@jLkT_21M) zy#H{qRScQfu=eQc@-=*WlbeS+v5*~kL6tk&1E$vV>fW$T9#{B%lvMPs$S#z55mOZs zt+aPHdSv>BH@FrhR8hjyEW~gwACtoh4@7@_AB+pGLjlshYC`CW0LM+J7#x4RJ&V0LM*XYnqsY3>;gt$Df@ zU)i#n*?1AWPm$bSgqw6*A6TO;ElZj>&L|V7_#GNjJ141HmDE}RV(|rh`V?w<2Kp{k z(n{5ak+`-7p)1Xts>OVFK}V?MPFdzrPPd~COjP=Pv8mz+LMEJ;i`#NcyE9DRugm4D zAHZo-%o?}KbI)8=b%j*LnjKfZXmxu^V4 zhoDUG^r#_tBQC$do%e%E;ev>7xGMv_mcT7;YWFReOR2hk8<~EWYBqrLDLVwC{cyQFI2OMc}|N=q?t5WFZJfe;7tGmgx0+fdSXGwY<>h|1j?$yNA_`_(<~fDM8;hKuU9!A61Ga=qd~j~An^yx zP*H>Ew>Zx70=MEs#BH_T-Lese5gB`$ToB75N~6zy2i-INyC{cy-|K$lh+HwM!}b@) zI_tN&4BoINh*(vmC*Muzvmr`f4IdlxjF!shd%b~qO0Y^UsL8I}ydz=*zHM--hv2R! zN(_9Yg}9EGerO>Ju6SY2pz80@eS6FTQbtq|5ofnSdxj3A=P3ENDpR+X5lgm@BM2qO z`nKhEkZ~)UQE2r;m9pi>2hA?OuXm%8te*Y1MNsVb?@jt^3bch_vdqU)BM0;N;w10} z18XI+_mx@%pv+MHvRG8IPZdT?Z~2jj5F?y~84-h--W*A#S}r4&ZQpRsvcg0KT3e65 zYMTIM>~$vnrYYacZe-69-O~*#Q}9@R+z1KXB#g2;0nQP7@@BK$*x+s(eydx^aT#X&2G$#Op?Yz1L!_|gV|q;O zQDxwh-OkX3HQooy$4zz3NQb|KIVUl0?EsjIYz3$}mwid5e2o$FOh=U8l3{9#R#1E3 zTIQP}e7Wa}dfGZ_hCUoIy=YchgBASlh)5&FQEB32Y;J~SBqbSem5TRtc6Yh0rw_hm z#=A#fqx7t($27R32%N)b zk^*;}bu=Z5QAu`|I=ybx&ca?+3qk9)+2xnIu4(Pmvt-U{4Ycatl#$~s^D`|cDl9uf z=I)X6r%y@$5 zN|WUF+n(+oypkk}=y+Qz`zV+H#oSy^@XiZ6lG^ zEf4g3inB~GPoBl&crvJiuF2PEIE!X~qqkPTY?ba3U+@_^!cuh&^aZYx_!x%3%6)V~ zSM;tZxv4o<59K8PpYjy;&Ww2 zjRoD4Oh0!lESK_$Jdemz+C2kQWHT)p(#5;c)quP zhP$2q?YKe`qU`K{&i{|!{zfW^Ot*LXZCP{0vaFYFe(f0`u-ul_Z3F#mZhlO9@|8Cj zh}cwtm)~o1bOZd>3%4lSf@>ea+8s!WhnK~2iy0s5eUwD2swX+oj|cagADdH*%G^X z&q02FNCUsOz_o9pMR@zcZ8NnLD<0wo;RP9ur)TdSm;a{vOjYPqGG#{YtO~(o&oy0WKt<#5YA=9Ml%yU4HKdqIctK^4gg=ki3?WBJE<92pD*oG z)!T3jG#(O>z?H}UC0g9iZm&UlCM?$LMnQ$niIVorgL80=4oss{!kq!F$xPuLM`)Ko zs-gWbW5ibvszsdmdZmmekS{G2VuNmkEc_1Wpm?%am!%U>8J|JOR9P@oOqSnGUtu=+ zi(`*2IOO{)Ll8OO;KgPv^$uS3y-zLvnqEKYi=a|VyF~ySeY%!e-9{Xe3`R7o*%!t} zdBB2Def^*JPGkxu%Gj`oA)htA;>$By)^j9#Bz?Q>vO^!6zX)7>)6~}6HufA&H03X~ z0rNj_hI|{|vi+SwIbE&_b#RGF1jxPqyp&AA6#|lL5HqGDHvZ58xI{gZ;DtXdE5>IsEaM8io!N{D37hNqLDsP^Mh<&QuL5Nx)d0dA< z!aFOEYy<-Hjqjnb;;e2n0*x}^1h(Gpo^3#@W8zr8MOPQnHdj%EK@N4U{`u93nT zjU#7)%^}L|7QT7ZPs%NMU9B0l9P}TQvrgac$q{tyTh6ae7X0YnUEUF=euqe^@S1+? z{*#Wv-!&@R6T_FNW}z(`mi$!=2!>q2#`Pd5=C+cOQer{cfS*cfU@2&;a{B~v7wRBv zonuuY@%d&G+g{#1bBleba6X>|tn3)*x7F+Zh3&V^M`nu%!?okp|Q9q$?=eXRM< zSyQ8hI6GLGcnIE*V;kT9+seAEz+{<0KK_(xi{z9atXZOx&%MO4E~It#`15 zO}1j~TI?!Oox`SbB1p`{5S1JmlYhcRGq8~>yH^=n!KJzuf z95-KsjO)(LWci61#F`Sq-7jKxF_+wzCY%ha%UKAzjEjHXx2k@XpH-RBqW+f)ei&z^ zt!KDcY0Nui8jB0dv+|J=v>u>z2*^QS5FX} z-nf>oW&PgvO6{g$7p10_e-NCioD*y%^(x#vr2HQkYi{)ydUR7)Z(w$}wy~O%Z)*Pb z->}+#)XByD)Qo*r!vY6>*J~YodFhvd8c1j zTBRULQxPc@vdT)gllF0Iqw4F`Y`?ksRtABbzqYR$zdX6)-s|kBEV7=K*8hPy;#W~4 z8xc0e^zH)K@K&bcq3U+mN1z|je{pzqfT1XS-$?Q1=k2ko*2ljHJURM|?B7SvNlE2o z?b3K4e__E+QdR)_=T&*DB`cQ&vXx~NcXp~;-vE7`cJ>a9Xd#CmKDK&nE6RNKbA%k# z{N~wPzOes&0RLPSC?|dw)9dV{d~=<3V)_?W-0SpOqJj6|B1iM(jte%1s-Jh?b+t!) zWB(Zd-5I`$rX3B~Buy=T^d4Cj_?x^LxN|Bi%-_ESqlm|bkT}ZzWJ_-puUiAx__$`G9w<49_>haed^*OsL zo9-j&f4Q&|I`!oT-T}LP7SmQP(<&YL^Ce*=)-#K*3!DlUPK760k-G3xJ|e~ovB{)b(aZEOJcSJ6saV-IGNEHAUzK6t+x!qV^! zlNEfl+uF_oQT*(`(x}as)9*EE_oldB#MbXeK@9eb_a_f+p&nI~3)&lTg{OU^g<4!u zH&A)!ABxb_Oln)YoCc(g_MZu9gFzbR^n&z4`^kHU<&hocdD_9OO{ zx~ox*{w&6}Mehy};&>mA6D(h9N?jzFcP1*K|I$~5Lx(NGN1)qoOwR%GQg;5k9kH1#sq5aHHK^X9g<;nU+Hi-b^zO?dAO>(QVq6$0g_QGxDXIwL$7!Z**EB8(=S z7)R|>{YMm58rGR-Ce4ilSXPfkrG&y9j(qUuZ*r^-HfO^m0%Cvr+iw_&fITV6oTS~} zUT0@zb+Ty1G8+;Ed#Os-hObhnGdk#=cC=F)5PnvH!}f-y4%+Lj#)9UY4ceX$)GtxF zPrO4}3lJx0A1QfECqB>^O$(bE$*bLJ3A*i@LvK%elmq8K2_h$2^`o_Ab#H(QY-r6z zKl)7GHrw&bIR`*I?@=_?Jqa2&(R&sWCEaFN6oVkS;iS&tV83{LvDxUV>TPo%IGF7z z*z%h2r9AHO=m|^MzuH0iK<4mK?UhS7!*=d#)L$C3MLwyz7t$`4&~SS!Yhb!>VLGT( zvxO%72*~iW^qcI#vpz}C%QJ<2?zZ$#yAo8!yJTnE0SL0`L;{UC8K^h)f!U7$(9*yVjU41UVtupGxj91hy@da!_|(mrX!&Kr&j zYaN2jlHc}PW0X??KT_}SA9v>1jRF#25eg8|ax)$70Zqv|u!yhxU_yCZ0) z#Mi7DR(#wm%`(p6k_8>l&IfESF-1g%O{M*A+Z57Lw-V2Qp0eM)7h1*sojLL}sW5xn zm{;S<9c8T`MzLC?_`Vru$Z3_4@_WO()(mWtS1uO=HDx!AqdB;vFE#48bhhzQG19XR zdn*+c+qG`^!>~tdsX`PVQam&&(D}Q;k%7u&&_yk z$Ynrg5hy5%b^!GkfON5@ozh z$r>oAfu&8yH`=TBzG}0Z>ET`7*6F5_#^*=F0xBgu!MoP>AD1p68xk!K0U02dl(*53 zIV#F4c7mT@g9IjyYH%cUVI>q9es{?>$Su9VYs2jsZujyKA+F)~n)J9RALXO17&Y%` zJQ1YO&`D@#_gmDHc-KERX*L|>kx764wfz-AK_gKfdTrR-wyN}7Oko$>Swv<|zcR%` zyma$YZ7yjfiIehU%xWL|l_;iZq@Ovn7nlq=wRMd*%kceyE7M@gg+= zIMWM|=EShHOUGIIO9mzu2VxlGe2x5A5$j5#H2rPAGuA+IX=%N6NIO zhTQjAgK7=ovlaSxqqsE~DU&QNQmN&AVWcb32&~4-T%ck@Dn_d_vhp1zw&Wi~lS~4z zG*qJS1B4f2vq>90eUub>Xi6Tt!5B}p#qAr*GAM<$H+CWx_KX&{ zncXh52hen&tH|YKtOsXyb{K6IY?5)D@170Je0P$eY!W|vBQRN=!$^u*>>69P6o21U zl_GAH>4xYDaN11%MAw$+T*z4amZ0{o5N!I!YW6XZ){5#&JUk>UzJ;gsg7yi-7m10T*dJUy7Zp!eR z2u)gf+~ZMN=NOF{*iTm(ch%dwR_1NcYE{oC44l9FGZjy;q{cBFMkem|>~(@&+l`BJ z%*%sutcTIA<8ONwUA~NNJrOM4HmRTFtL#v+hD&{|4D3j0Z@C1%9alq=ZfNg~-QKwHK@wWGtDO#Xoz0Nwz}Dv>sc&SCX5to17{ezW1Wc zT&=-HE}L^0pf~tZG07q(e<;fG{10oTq1QT$YSW4uJmuD3nA!9gF}$nzP44)H4VmXr zGCL!$QfATZWh|lG0Z>I0A6}pwxH|wgeN}|J2DBmFsfR)DGQVL?JC&0w>#7pnFZ1Y9 z8>r+mHov*otdOZ$$0F!M>aD{!bGcgM7Pr$>Mzw>4FTo&Fe%zD2dQsiz&5t3CQQnc% z{^{kO`WnrWl>t$>GM~~4dzYBCS)aOlI%xmO@~Is*6|PTjde?vCuzFsuzjji!$-e$^ z*twqza!MH+Rf<7c1134IR6deI-|jv8Y3*ySVFp>gzEzFzACHqG} zUt8LmW5F~Nj9TWsda*rgFqwIj9eR@+n7?Ck@#~#+ndf~gR*j+%<&kNE8c`{Ti#x^@ zdDt02NEaq{byz6+LC;6qtoZoPsI#KBMlM*W!}FS7eS}5#0jzfwU?GzL=R}XB#9hz8 zv-ZTEq#>&cQjb9Q^T~S7v!jSIbnRByUX*LRXtThi@JBt7@|QC=ujE@99#?d+#5T^G zZE<~6k(%Q;DNFT%8I$M+AREj(>aQ!Fxxi&gVb93qw(!WjA$RnWuWv#H`+kYs*zkL| zUM5BE#iunE2B;!vt57w4mg7fxA2AYlo~+x9d1lW}LbxX5O{&pSwUF8aZQJg>w1-f6 ze4eaU{K?gxUoZ5EqutTB=}pnNxAwX==({??pd|Yl8i!Ohs((@2zGb7YRM$P`Z%Bi% z>j0G)_H%xWnLr`ar1CIb)%tM0orWn? z&8D|;qD>>2xob@iB&$ApSG-zt*S%rlF#uAh?A4Mb`Htugl${^?pLySW7b}6kv<67~ zBaeM;jUOU6V;an7c{F^MZnKDeSD~0zBgUL(@XTp7Qa3&?0TFqH-l!7f+92~pAcNuB zrI>FKLzY5APeM7UEE=w#BW2h1gjP)e!uH~JVaU?lBRaerh#MF~)K*T0F{jT6-q>tY z4;(4KK&SaB{VT=*-;T@PHKiYodG^4n-dnm*p5;~RgcZ}8$R6miK8#ozHu0)G|Ac?) zvT-Z>Lw)Pxi7Euq*u&|tty(8J$8LtNOjZg!>L1V$wZ(rBvQv<(F+M5X#719`6&u{n|W&iv0|p(909Axi+YD3?ogDKLmK-DS3BoxnJbYRm74`OaH(#Wt>tiD z#%jKphVXe*iT9<=JL~F>yQYDTO{?*KtR%K88y)-LUMc+awdTqoD44egeN;mT#7Joo z-@`V1j+G!(vj6KCjJ&9=-T4F;Zl9B3mlhVXc%-T$e;Y6(5 z?su4KI6ikqcbZpLbU)3k77=+kLUqo~p^E zv5P$F%6ZzxiIKfWFhbE*$eb6=_*!{+);wa3%?S0LERcZ|0(eQ!wINyD_;u{jf`BWi z9IpQzHV)w+4%bC`mX2xV1(WgFd@Sqa8nTlyb zC^mVotR@8U>WHc@@xb(#06YwL+*|^T@1Rjsob>l}v1j51@rv0$&*D29@O6b{1VwbN zIF(D4%)PbMB3p*CUA`=te4oJ!E4M9CP#XL+A;jzUC)}7zkPy$b;*|)&hsNcM^;~;8 zL5u|7Fa9RAp?+8~XrUEcqTH%!wrXH6Do~>6t@pGoWxKg&B%MGvA)qvO4~OvSCg*?# z@LsgV(Qs{oJsv%ZBZhCm#t8w@5A8`&+iMUac$DIYaK>QwD2_ewr8psK?q!OP7+k`8 z)A)mCugLc81Q@wmKPlP@(FQBpleDp*`nIN@)~KGARR@!LU%5}{P=~fsby!@jJiimU z43Isk?*E7ND(USNVL)#3Ipe1){J%&v?6f;;dC8MD`@a8mmJDn$Pei~3db){tlK{y%sh5dNlVv#hn^pu2*m z`S4S-(r2HUSnU#gsz)d>k+_Mg2wXPq_8Y72#8z;}fSgpu|4fU1AsXY?$#sHbPS_MW z;5!dBso1H)Z=^I%_wxKpNDvt?E18q`S;&p}aM2%7(M*cH&oO%sXlds)@?cPtC2K|; z!n;Eq+Lv4Rj?h)885hW8jRNg={i$q!B7ENDYK(thl!j+j>vT!AAWa8D>nBl@pJ&qU z8coRNc^OMpvC7I^$Y563GIs=#!SBD+<`;_fi9C6k#t|*CWcu#YndYPZ%xk@fAi|-} zADr?+9ETrS&L21`k@!N!Y0_ETv)sYo$1LO90aZCm#O(Ik6J;PnSMDs#;m%NpF${yo zh`a!O6xQQr$yFc_dAKc9K;phf7)V z8^PwjlJ4Ooux{G;LgdpMvwq|76tT5UtFu|01;8Y(<>z|WtrbmKVtfx!%7X$w08JWT zUt|mE zev6J84nFRO8URz~eSKRCMIlI@Vo>x$_r~>hqktENj!f&|au3uPd?t&Y{hCs8$7t;w z_PKf42>GCu2@15YEa9NBFK$BgG1}^L!?{6JE2O!}jJ;c336Z?+Jdr z!eHaU-Lgp^hK%IS8R8yP*&8GdO=tF%B&aIFe50Prq_$2d_Hgn;zAy{MvrEWwQ2imhy=!A9+o-%*DKkffweqvO_M-rBCi+1B5SXl6W0)>3#$^G z)cV@p;6rawr0U9GER}sZHpoQVF{oRbnJT!tbnM!WW-tsQBbdKNdh~#ixyM`gcp;&Q zj*V_Nk@H-?f|sOVP86y)V){yy$9nqSt?@BKOsO=6w@0LdId)e#kdV%k6#(V3097D8 z@SrNZtK~`&zK|oraKCa3c7xe^1YCx7jfX)rnPI&_l@Kjv1gE0zNuET|CK(nua(-MY-PowO&+|$QGtxOT^T2MH?&msia4tp zOkTF7q`!!Y8aqF$hldJ^oclr(HB}JVw=-fWBoVip((YrJ1rqE4m>U%;0Etz}6(@3I zCl=v2c}i19L6El0F;uKNnTYmO{D1K!-|vJ@>DxwM(EOS;3BJh+%o;2&P&&4yC8 zy8(^mvjyXPQ#r+-2y%QXP6IG3lLuZ!j5Jc(g7U73=aDlbR@f07nQ2kzmLl&MnsXdpZULd4=aH3nUKV8ZZoO^2i7uWHxD&2@rzJOD`9OvMQiqT2|A*u zBt4g@pi(lBVY#sFwWjw(jT1>@J~i0*r8&p^aGIJsP~>B!GGbS^RkyMM8{{{SU|PR1 z7n9160XjZ8ALaU&^)0b2HG>hPnDa{OSziP0+TDMij>bpsq;c=Jcr*P6pR_|mX(G&i ze<3LxUcFb0qrx?q@P0&O<&AVrq_X6^2P5Q^=b0Gb!F@q-U~H!2OqUNQ^BC-2wXea zJx?ByF+Xf1lGnR1XQHX1S~8HK?U=f+c|N0 z#C%Th(F0OD3+?u#|B7+fyyq9MQL)8)B0E7-VJw&DvmQ?>%)H$g(qoyiKlg^*eo#QN zOLeDgCTn_j)Xr5#%jyDn5Q3H6$P6SSqU>hpT>9wCc;|ZflOi8 z<7G0UtE|pgo_D2KS~Pz|yUf64Hfj2PgF_5=ss1!eTS5r=!y)f9`eV7Kv$}^dnjA)q zCVF|rVuP}KEQe^Vw`X-yO$B&LSz?izE)|3v3`ekR4q#d1G+6W|q*^37%M!p|1yvM~ zMJj3JX9?8Wm)GSXY#=3rN$^Wt5)8`&;4Sf3*JXe(7C-Ri!zWbS?8QWu^)(%?PE zq#4;6K?3;kvp!t;{KKZ+?K_{LqBeqsrEd!hB}X7I{A#&ULLhVaOq7uQn@EA%`F90D zA{X7_Er7;j(H?3M$U!oa2+5sgP zLNfHU>AW6%R-GCLn2JbZU{>@wobC)k0oC^PvOW#ka zdA!$Exq9*#=SI-*r(@wzhtR{FS&Hy?_WRFc#a~aeNHkc~!*33DBHpLm-sqBtDouzR zrFDoK`WSFPzYcSWNfsH3d1LK&`Sf?sT~rYQ_WbBc0BEBg4n~X_xqg4rWYtosz#~Q! z*dNk6Bqi)d&V1`hb3b&vlTu0Q;hK{nCe*eC4YQDhn(v}Kb%J>3gk)dr3^d_iZj-3V zO|@@l;CjIBhk%tH+{ZlU*i(TikV@m^w{UB^8AIzyhQ}lQTTyH27C_UcyPrn;AN(mO zMv1)B0?syQ^JntC{hfuHXlA54Yh>$pSf;4`dFoaL=I}S<4(&R5PU7;_m5Gzwx`vfJ zog`Pz>bVH`*jl)qKY8R|emayZNhnMy%27sLG`hvgy|h|iB1X$T#==hY;uGZOGSD5v z-V)Q8tJn|S>tHCvHPS23LW}=2P9R$bnD)lx%Jo=z4e9FvWxG}vD_KFx1)6wHs;9KZ zr(!*=%D2JxC?i(dK0C%yy%-SN`kMm^p8UtL5&^qu4CTdu51RRB%k-Ax#H4 zk*v57#a!^fvgJ0kTQfdsyC7+KVK;epJrL3V$&58}Q+~In>O7`*tdpLSt`Sk9M4>+?<@YB8A8r`SzKiy*o z?(1R1VQO}Bb(^zVF+$7nTJ{@n9vhezaugAyXJSd@ZdY~^ZR2Rq5~%g#7hx9UswigUqPgvw(=bf>?kJ zwBq3g(+nUGO}z2JK|kW;qFjfgHuHcx5y$i``OPH1+=l6{er8hwC04jcl@aSI@&Tbg zIw9NvgfYy^l*f;0*D)iOh|cnOxPy<F#E<;wpZz43rIk_w0ERs+)YKWPFj? zdL)w{rsZ@aQAFDr6fuk(A_Sx@Q3f#cOmHCHiX;^$g2%8do2TM2pw8)?TjaGokw>l= zzp{qP3e;H2p1n7E*b3^~&YA$JzPc_Q=iY$VCy$SiOOp%_{%EStFSaC#;y_AdKxlDU zC0bR9IZRzcut1N70sBR8u3b7xhgCR2Opj4SQz%3e;!~z5deO&}s9`LIzrOc!Of$aB zQeVXQ&}75xhQ;$;K!<4@6Ev&#F&>$O4slm788$4 zlI8Q(laJ+o#CTT^TKDh(i?(q08|@s+2Tm)xDwZMJtU9*xc5LbQ7aSlettT)5@${f- z%UKGFJWcdBE?!=E(E#s@2kGL`?35neBAQx5j>flgo6gc5h_*jhc))G6tjQbd(AZmY z2Ir^S+MVzebeWDy7kT{=1uip3a6)s+*yHX7!wg4Qoyl2DE;$(S#<8pTh%ZQ$XHg+A`Mbtd8X&pbz7IgPR;3 z63*q*W2-`WL_@+ElKHO57-sj>tEZdx+R>+fAPrW*hj&4j#fI&DFR5+Z{9x&UZo4pK zHAAAN9`Gq<8C2ZfL-dkA?s!sY0$_V%C*C}mvDHuX;scNpPY)VO7Y;DL7 zG~PvqL`13?G0G=eTvSx!-l{B`1XP8V>c39YW$ed`(i1fkEu!6SDJB77DO7>NDScdd z+$0p%j9mt4PJAhM#0FtxvSVX=N;S{m7=d-Xy5`hx&n9Ea$>goF%*G+?isu&}jTt*iIOE zL^uYH;8zEUZL>me-%#HE89#nN8C%r*@jpsbPmn<-{x&%iO-3)IP&sDu#}=8u?8P%* zpf)8FzRAe`)aN~MLG?m#y+~8V66-1*v8$Cq9e8k0Kb{Zl%NO}>9DpcFsM@MLNdJ1L zhdm=@650MxOyt~ZXDWGA)HeC+KKm(13VPk;|`|^%GBTS~5iXMdm#)s7?Pzo-t3?^2hRh@O5|C^1x+fIs`38 z(PoVqkr`X|H=S#IvdIG6Jf?(*&^il$x>%+9%b|oo6zvLD^hhjtzC0FVFv4mh{)&BG zWG|j7H7&>OCc|^Cie^>VHKY)9Sc5i-j^4-Nd9-muChHx3yinxpL74{#BeBCx}Kl)@*7 zLeyY6&>Ww2MnlDj>8@xt4ghzh8;KzYNDbg>eD&Dlx!^w9_}T5YS0i%(+m7nk<|X6w z?MkJBkpsc?O}Hw;V4>O*;T}K1A#!B8tuu5x0o1?LBNJ@aG)higQy-78oy-$_?E00E zAVQ2@@=IzOzfqi(-$I$HDkZ5~G3mDY74K5QxbN>az(Or%9lFWNH)qM;vU&8rJpB*t z9Ni9X+@sC_)cW(R9gNb~H*@UOYxqcP?)^xCwjSqc0+eq4wQUOMGDtke=;f?7Z!$vZ zdY>i)9fR0$o;*3GZU2$op;6HEKeKV{#Lj2NiE2t@O&OR zlo?+oYz&y&GcPTwPESpk6`7m0y`xpcpeHhO2ceFdO>qerjv2;_RR-*tO{69r!iyUx zvBk@Pb$T4@{{0ce?wuH8atm(pN8komMo;f?Ixz1|^Yh9NfTf!_FAR|_MzCy7J1r-+ zSpyD+#S{miqy&$Yn28S?*Oa5DB!{{`4lWj*$Zet7txw_CQ0WN}yt(z2zFWfp5c7l5 zfIi$s>Y@>ewT1Fkq#?Z_g5n|njW?l1l~*S^x<3}uzn`uJ?HXkXKGQVzFw6okts4JW zi>gTszwP)k(4OIDWFAJtWD%bVi?>kp58#d4Io+ExF;g`0i1LRTWcII2C$q&JQoV+2$Ir0Mj%4B)AK8BIcO1DiARGh zvpopGJ;1t)9)cPGgjc1)|5Dazs8 ztTtQaLx3h0Xqt(~>3QYRj@vqcN_M#_0~*nXNr_(IwuB>$UDLoj%L!*->27g#IuIVz zALX#jSBBMe^Tg~Jec|CjWp(H$hWKt69B!Nhp+L(rU(SCSzc#XrUw0%Fq>*oe61_Af z_&h28_MNAKXS>09tWDRVle}IFJ}W`X|4aqOZU{c=JISeG#(o@+8RvELJzgA&0%L+S z!6eMCjtUOhy((wI&QiU`4f;?pMe8Z1J6I`Aa2BPt7L_2N33qG}xE&2}P@DKg{6Xv? zVZoYbKsdr!w%okft{>$IvPD*2gNG$*}qVYJVhK(=li zIR|Tqr8By@jqOwqvn+>pCzVSjAzZbi-SIzM(3?mr7Fj=-s4zXE^RD>ei#%lI7PQ`k_dX0p@ z+Ab>P43i8zxK^XVXrs_0-JGba%UXgg6{k_#Yq=5GG8Bn1>v67Sj)C#v{nqY225ifk zo%#A4H#a-xUO4_v2vqZgLez-E4;c0Hu9-6^@xDcNR}iiTLP>3zd+#b}sDO>{nb_D8e_?1NFK>pT#~s$RAtX5hME{o+S+0H z6oUYFUT8OJkw!@56S9XSb4UpdyAm6|PMWs)(Y;LnSk2{d?M$pM8#+f_8>vLPRF@cZ&{&SIHw0e>Dz>r*qFZs8O5?QDek)YKPuQ zGg*jVFpf4OZLkSkch!C-a5|q+Qzt>wfuHb03B-1;bcR_I3NbAnF$MRnh^jF3OJ8U! zXUt*jmoI`*e6|XT!bbqf>Nc|G)&1Pd6t4y4wU`@;L9 zUB5kQ#M}?2Neth#=Me@5cFvg`wSk5Yu2=`Lmg-~{SrvuNWg**Z*TKrp%R*u?N{+j0 z6}B*BoQ+3vXS3wx9c3>x3i@zdWxoc>xh~zGHsI0Au~!aWS3LPjhZ{oGy7Elbi?Zma zb|ljWix=MuWt)BC^A?-z=qudjS&8sCX>8g3g)~;so;^p!D5iclGLPoLbFsM&NKBks z*czY7-S3)oY*0=WQp^p%oRJc`eYPsWm#g3(e`VWbd#?-4TKgc6t_zuc*s}Z z;%9su2^o$!5rnIFw5OZt%=<#hyKw*N0uc1OW~GeXo~b=gch8(jp2IH*@T>Tp)I7>A znb`Zg>e;C`EkPCsFZ%>ToxI%Il!ucKI;N?<1A+_Mk=ky%^l(r>Y+%?et_!RPU=fBAYzG{zXj% zFp2Lb*#rPNc69L7?Yp^$CSle)0+TH!UoH4cs3kkL#6 zB8rNV_El>?OJ1&$d7WYWhX5=U{M%6n0E z91OFrJnC@CuM1BbFcn}LsQ+*R5T_7krS0e`6x_)mqoN^_Q|Dw~t@4d05QR%qy_&^= z?^YN+Xm8Yon-{)JGP*gN{vs1YHmd=xv1b{NAaTS$L5F+oy)?wI+?P-SrJMaM|X&|(BItq zkya0GpiTSLF8<^aXjGR>h63;#*gqQ}0jW9-soZY?o;pjdG9fFd)2D|4RW`q->!!X? zlI@B_+ zs5^b!kKa~@^HIO!`FZQqAhw8eCf6NJ{&+ltPDjlpd^ltj5`1W^YX=C2LnmYQfDGX_BxT3{(2sV2 zO)Ry@w7>wX@g4k${hjUil`P(m)`9BDT1G}{C$Da}M66j?)1&4ye`+`u-eYu5aiuN( zZ;tJRgVe)gTUzmv7r=D|+uA<7U&2%?TCV~7$pdM8L2Jxuf#5u!^3(MzJ&AbQK_U4j{j-fIxOjLzug z`$=-1?>y%@Ykl8e?^^GFSxe@3_r33X@9Vm@PLd~*^yChG2i?v7;DbA5|A5blt1#aJ z(gLg&am7)OFQOhGIv0NdZtLFoeb)SH6ZDqLnk{mvlFc2nf4zlY;;I|mPk6z~h+qn2 zzu$SYW%?H7!AQx1r({m3R||K=z@g`^epd) z{cDSRq=OVJEJ7tWsFvkWsYYeAIHfvYey-E%R8Ue*T60y-1d z|358XPuY^`#a!(x(YCPm014;^xN^=s@62GB*wM;0B5=Mh7J`2_(|{s?e;5+YOXoKM zIt^y5Ud*HjaOS-);>cklaQrGQ*n}ciQe6H*rjm{{QL%-zT6r4nHlMPr6T%*YuPs7TWzh66R-%K}lSm-sJb(7=;D<10$$_1;hj&k7gSEg| z)qU^ZfTF*{AL>OE@aKUvgo#t|hc*N;DJQ8IUv?$cO2fBJvVgWz-0{zTskb}9?Mv(L zjDqiN_mL&!7Tjwcj_(F5Mx0|>?Nsse30m^o;7s^~A1$^A-E$?A+=)wvJL7r2lm9ja zEpyT*axVQo+(pxLqpW*L*Tycm+PYXzhEL1SNq9ScTZvzEnafP?`9YPWfpJBS;K64DeVCHs>*fe4!%- z@(Xe5WQGH}Nr9;2*=vZ+8R2Qaz)tuq-QDa^eGg4Pm`0QAaMk{>Ca1Z?qtwuNl$h(? z;JW*C|30fP3JLH)cX;f}YsOH~+3vNk9SCmqP8bom{TzVOcbP|DphogAa@d}?XDa+aSh6!6&x}CYzIZ-*=7(`^J7F)5m)N{G3?t=LwjxFnCHfh6 zlAg!U7C43%h5RzPEpu-$zFrxAXL2K<#gZx>N-kViJpMQ`OZuoxI-Ht;d3;t#zAm!h zE$;kXiRzYwv-RL{wq5_+RDJ__T6x>{dwAtB_>F+2Ao*t3&cEa|U0?PFb*t2qez(M2 zGZgHrk1%C3#T}Mb2i!r2`f;4)>kpdOk%71R99pmVUB$)gS0<&r*GROpEo;V{yJM6y z?ymM-X|UV#4=h>wq!6W%jc1?nY19wDs5n%>b4N~)vEH_T1rT1FKihKctuWZIF%U6e z(xr=3pCoFxz%siJ?*|p8&EZOHv0cw}LU&bXz&Y)MOTpb1&Yu5)#Q>g- zaPm_d%_6(PAK&Z;tAc=LOA9TV6kT9bNlz|4WXoK-%lf-+XN~J<#KTl~106C$iv}DA zTx7Y%jPjusVnwBI2ypQaasFHL%(lrHh;?n zZjhEnF4)%fVw8v0PcP&u`fNRRmW54EF>TjOeZ2~=8m*AFdzI)sMtpdgtDudqRjbPh z9rj8&1u|Yr^-h}!qyIz1O#?hUC(d(zk#u*sDze0>=^4NCzfG=3=;SjRMEGTHVTwd2 zLPpiEJ+R*cHHvRs{x~2g+!fy#QLK4YMB#YQBpNl9nrSkenqY z^Pq6L^_v{ymVSKt5LbS;_5HMA6!qqmTj~@apfaI?3om0+S9;7 zxXM7#JiD3f`lH=s$ATir{Bz;jVW1HW@_^Um=umkan1s#xo|H#9O1(_)Uj_jfpI;!c zYIp1APihrvZXa=$1%*r7WEqBsca-*W{bN^J*P}~uW&~&^q8*v~K@wsj2_w8yOj|p( zABU?f30iy`hoE+55g(TUdfxWG*fhZCuONP|`w$ZuANf@>+HXla)i^1`U6HRumZGi( zW>t_^vmne^&WBSUPm9>2>^n0^#fJp}%!gEu-3Gfp0E7Gg`mSS{s0N{M)Hn#nB-;Oh zg@+OUy)k*XexW9q?gU|@)n>S#6K{^=+C%T2S%l;@RT{em3OEa$87liH80IIn;;-(u zFyWJ4<-7AZM<3SOvg3F)FiHbA_QSZaRY98~gG}6lt1&r3dAkAy9~;gyj~BKNlUHEq zX&u*_MvA52XnR_|E$1~lM6E0yLI}j>YG|9(Y%IjFfkWnW|FVw(-t{k-p(q{cT{0@Z z7wuG;p)xvR_L9E2GD^6el=yM^A$ek+59z7zjz|}9&a$07^`V9Ki`f70qHu9j)nlKp zJkB;WWzY}`ZYw80$?_V1s3*EoApQxz@jc}kMLWmUXJw-Q)^J_8TA-QWDTeu^l)?*Qgtf{Py9EV-G(G6#AKdm+4f+E1g;-_9*IK))@rR^3+FY=xDuB7I zu&N@#cwW&?lDAje;_rasPKr*`!xS*BJSzy_#)P)tU`=L0#@0RTht zs>S;0ZVx?obd*oSMw^1uQY3GkLbe-{UaRWdLE(TDKv5tTV`?~eq)}2f4 zS<9(5AV?sQif}-+jA% zv|ail`9(xjRo;aJfZ6;Bp}S?@*^zWShYRzkIdR@kc>U?sD^qlzRg65ggwyM`{5;68#jLWPi#eKpk+gOX=PcN_UKo468jSrj41ef`xpKljDlgj%|4?#FMTD)1!FKg}xB@|?ubKRX#>NE%S# zqYs`k0qC>xrximm5sG0kBeh7Bu}C<>A;V}ZxdT3VvZ(&THzT#OK7sY?#~NwK&9$dx zGFfzvNxTc};$e9?jcNi_GCW~9_hwZj#By%v|6p6UJB~iMd^fHad@Z#ib*f2i*UD~K zcApWRGS|NIs>kfTS5+@nNXLd1>tDkXdv;y1ncbH?=aBKc-}Bno)3xju6aGSzDo&bl z$m@P%n!#xBWXvRrQSm&1q0KboT4ZB|IY5UL#*Y%pwD4v73RIMI7&@XRN2CV(KPLvtV4|h|; z9x{Aq!%})XzR;)!XY$MSvhO?b3HyJyVB~}Lyaq^etOD(##nU8zp%f*V!)|l{T;=?( z+TFXv@DNCA$%)@be-kGI6+@E597EFi&YHi*;$n4M4?J}R$e`2V;!Im|%R3O+n1>$p9?@w$xS{tA6aZ%M03D{~(ck#eEz*RN{V$ls)D_2So-4}e^TbOi9`XRaJ| z;G67ZE=BKF0?ZyuW7$}{SD3fX4Qo_%<}V{ZOqV$%y8RXQcsoUdPy=ZZ|EasxSYCSD z@8NM^&%r|UlXdD(cdsDnOz%ozTJ#a^(eu!w_&6_*A1B;Kml zc$b@mMAN0tIY*0Zh_G{5rEMdHpr>hJc|qgy+e&MgrDR?C&7}u0MyTd7>5`hWwG&&~ zViNt;fN2v?4XyP`pVvgyhGSqd~58 zlH+$hV7u6hmt@il7T&MhdxybU>WOXr6iuo;cKcnrz*MIuelR~?2}<`qqahPw{NiZX zG|WX-;VH*r1t;)*q1yl?5jjt4sKW(^06syFs>@i;4k_7To(oI!H&;&!wZ^Dd|#|43w|X9I?XTH3Qy zrLQOUfJ^4SvzP4q=XeI6JPzw;GvwQmM?%_4)s8KulivU===TKH?t>3RS?)4ND(23y z`Q{j5{MaRIaty4bd-5KSsT|JvS$NX^QIbb9gKJU1b=09A#*u1jwzgv&DVG#ja~v~U z=#%mXHy62^^LRmM-Yox;PHczJESq@6cz%kWHVsR#G3`M7vhu_{U!|D|w-tvzy_7h> z4eu4sKlPArv~44xRiVPbTT~5PfB~nh6xF07aD+hNBB>n&ZYr z%LBL5&#H|~lR7<^0m?)BM>RWpfJ0itnyEn9Q8kPR1Gj0~2IFWXmk3RF8Wz4S$tOPx zbZnVT26!q$*ax>O9tX=*xWQ51QLcQ~!fs+@w?hyt0jrrZ>xispogV!ji{G8R0-U?C z$@}+m27|V<8~3j-GG=)57_~LVt1qC0o?;^1cS0IXMJj5vPUg*W#a1Jtj&N@o@A+u$ z^)z0B^b6R?>qu1Tdgfw!3!ZB* zL^I@if8&rHOs!zwGDVfaWD6_VvzX zG+{Iv_L};F8MQ%S8TbmXW){V!0Q2~wHOVY1#?(LZm0mEDn2h5e9R9&(4{1LU9ZTYC zB$HjgXYUQN>F3QYs6-S}gz)bBdXC3@Vl;WZQ_gOj9oS5IHOH0?%;u(1{RM9*2oY#0 z3R*CgpgxR{oyo1F(|;J-m2K5DG+1ay8YCPjA~)Tl%mf)-;iTWlvCv8 z7#37gU_>D?{8Yw3Hp=4^QN>F&eXnsYi#JRp#V8Xa7GBEBwVz9T zrw-$e>TDYJyxZMrOj2PZJ%=z7RK19?zl<@i<`G!qr_9UV;q##N#TD!~)eY*1rpi~J zKyoVB4k~IBAkAt5{c1IFWg(A5KsS(UxaG%TkQ?-jAVuXb?*XkT_CKo&b;$1xsh4wx z!|(4WMlir?C@_*|GRyLq2iv%)99E(dDZiUyc16nI;c5hDX zBk-$CBvDw>eUtC?spM@CA+x7PV!N!8*ChPM(~WvW^XR>cuLHDOO+DqcsLdS_be4cc zV&)4O?gS2ch!N^FU*_j6y$8bkJu~Sp$`fSF^9M zQk{?G1=zw7UKU3Qk(%#@IOf_7kgP|u3`u-34p_cx-o4^>KdOe=x5>rMAXCThq~}7` zqjM({tA~7TV#O`rfXO(@4rBZl&?Ven4KBQCjGqKGiy|JqjmGPh(jeE2~@N+I2a@jLB}JnNE!i}*sjW$NkL z-C36VCbx(p36J%SB|h!U3%*#)<~u5V(eqk zN%TqwZde6>PvYD#ZEnh87WxtTU+0_Td++Ks`hh&5pL@18XdMaHvEoO!hO_f=?vH{E-~!=g6fHco#e3KDcXfoTpZfyX>>&HEb% z!}IjnZvK0n?}OoYU@TMf7*>Jo*Y>74_yP}Z7Y4M3?qs`h@09KN+zpoQIJnhngp`Fp zkoh2H%0^~nr%dsXHhV7z*-z!w-#88yLD5oUL^|R=3&!8EO1gf zb|M6wfReKD-?j?N-_*36bGB=E>RQ|+4+x>wqz<|G?Vq$bB)*! zt?S*B{f2jVO>Kpb#)yjuJ<)9_CbD| z@u1(bk@g*;5~bYXYJJ9Yf&ZDJ2q<5+E66Yr%Qy zy|6&dW6E#ndw56wsZLu z)o*`xWA|3m157Gd>7IR;WYE&FMV#R+!itjL+F1;o^fd-^qT|n={(kL>E&FLHN8{p>w3}#@ z52@O^z2S6xn*>Oh?ggO+9<5$!;)SStM?`YHel1L00qc@<{G6>xj^k$c*7kPzSrge=$N6;cElm+*6P@))09q&HoAAot4C;&7n;m|# z1TR7I>=BAugHNvH7nPC>bQmg3`kq;qPv<$zO?uP<2V!jM_`iIVrLf2b`QxiNYU=IX4^}6Y z|Y46$hrYeaK zZ=-I7U_WUl2Rmvs@LpSR)r(&5Q?pgZxtT4X!~fDOwA|ZWMTVr@mnhN%E1YQn4zJHvm)Wz0?L{})juJ+l# z#Kaj%1cnB>@tcsDaFO@BPzRNDNPQ<|6C}vM784{+1P;4l2C@I^_v($Rzb(kUr|EW; z?zCxb9#(}27XCylJkO+Y$gk0rQwYk)dPprpxVn;^nzpA^N9`afu}5{)cQ_0i|KS}V z@WSrQxC29rA44=gP<;3U_K0nb2UQh%b3H1egvGHl>(GE#=NXRY?4D5#ot{&{Hfr=? zlc+4G9tL^MvA9U%RI_&2mcoJ5*Ywma1;vB*7nt*`LJ#-~Ag0UPJo+UO{la=K8?*dD zeN?c%@l_TylquNeR!E?mlj&lOIH0K(<8;Gm0>Rnd)((?@6z&~Qj(Q{9npVSMRV3|+ zfCh;lbf+9=pXCjDG6p!FyEU+9cQxJ*0q|j&bYOk3W@-MImsXN zBF_JEiKS<)UFotv4I87>^VJN4rFYx1rD7%-uD2w~HGgU}7!|C~2SS*xX9~Ix!n z*;)nub-(NGl+XFDyo2`JC3nG5N)tHScupZ8ZcyM3U=~IQBcdLV4wM=2F%xYL1U*7e zoYWhZT`0^$({|or>|4H5aO)=x|3GV-+e;+NgZ(2xd$ZNM^HQ~8 zf(U1;NO1ao{q7BVYVU2|5h97x5pVD6#dav|!p6_qL;y{`5)g^|y#zloi<@NrKa7u; zF02mgeCAkMnhyJ>sg3qBo5W7lFR)OeD$nzt2&D~x7XNDk{`2cO(eu&wA!o}C4rlXd zZ?5r6{iOGUem|yW2VM+~?= zt8>P*=gSgC!u89WO{PeyGl1Vdyw!Up;&u#N;&NOV8L6!_qrJX-QqPtfg2@%qr2qCM zDW0ZlXM7ij2LU<_r(G>jgDt!k^^}Vw8lc_Fz8TgZFT@e~Y&IRCW{l5AIRbR*_ip5o z(yl+0G5M*&3kcVG{Z;_$yweZzo%Z%z7rvGj>LGovIuDQ@1j4`2|ox$9v&v z9KJno?+Ls9rLR(z;@ak0biDItK7Th)nMy%95g85eU&;i4?BP$sNZICP2ZYE4cqimE zz?ZU4!+-i%hFe^>ILTalDEq&IX>6He5@JsdqRFx=fDm2IXxoh*s`Ja`K9_d7@xR~S zQZb>Uk0PM$tJM9~p}Bx1!iy04vy>MRt;B{D059*C-oh`85m1?mPt-VG;$Brq4+Zx& zFy{OAQ%3<2L`}QOCF%!?A8z-r7s9|5+DY^l}6CQGeT(n*4lBKeeFtiCLs8{aTX@_`o1tAjoIBzwu{nhj+^tv z3Ljkj;ROF{rNsw!J!cGmE$w1;o|y4y#?}GQU84=)M^1hjiDnsot$C{W4o;F!`r?T- zz#CX6`q7U(_3c6>O5kvtGL9N^8kjzqdaOUE}VQE`9g&}T{2d8&qr&~lSu7Ko40bGZcgW8v`yQg zPXvHXyIh*0CBn^jzt>%H-_sf=8SyUUcyzSmacf2sYz-6R?1M!P}pkR2bl5j zkY5dXjC&&bm))4ao(Pq!4g?{ zN3+K`x)gA9pjp}Zc8Mo3XNJo9M>-gL2Oo)9DE~+n7X8Xw$Pnz)K$}^j@<>yBubahA z<60WnVJ!r_cYJq{?kr>!kM#>-W)obXv|UI&%uIk7D?J6yH%>fWvIuCOu_2gajfmg- ze8^67fMcqgq!aTex^@Gb>E724FKZ%8nmQ};UyV4*g_&WVu1*0M&c#Sqo5s@7q?TXo zIU2-%%=oVVOO4-0f>|8cD$i~MR5fX~fSMVH6ma(g<|u|{^(py338EOUv(775e<5XQ z7ms=S@QZo{NBWyIC$)A(nfITvy?Mz3?kybfW~p)N@0T2X1_PBmw66=bN+C50Gr(vM z$qCqbJ=%Si`XtIYzW)DJeRx-92P3TBkT*xgGQ<^LR-BlnwCkljR=*d2akiWgD-2EQ1_W6iV2L=$FzoY z?jJO?f-UB{hs$@`g>DV}QZTt3=-N?p-QDYNE)kcGWS5Is9R}R7UO&6D{RiyNnM?{x zJ%!}lVyu+5Zo;9rA2oixhw6e{*ur{WgYqiOW_<}7i&4MV4IHm>W5(8p!nc(PM zwYtQE=QmJicJ1F~E^_4y-PISn$3$lJ1kJA-!G8L_F`ahcRFqzxiZ0cW$@|}(+umF% z0pE6S{3JW$2m}DBTDb_Q`$*YHL3)fzszOoAuka~l$;nU|5N}8kMUbCNh31od$>~8! z@VDcYn}O&+pq5+6nevAYTqa zsvw!9U(c%$aW=Rw7*t)s-}*f&LiK)F!Ffg>-Z^h~H7ldje)xS%8~8u2<)dfgR&hx4 zkF(y>RrLm&>fQa5h$-qaVb{j35bwPzuIn#>oG~8*9Rnu=okDcv9kpn-z7MR)3b}!7 zXG+Yotu8~xZtfbnKnbnu^YRoC56+%SP19P++o>T(oBH*n-Yv>uDWv_X^g5LWd+ur^ zjk#ubW&w4x1cRMa;anOXj$Yx|zWlOqp#q~&v&Hwb@X=WnVJw(y>M;;=AM=5ahP-R@%})2HU(j=htyMAU>j+vrr*f zk1@~xX|tK!8@Cz*n?HM7iWr;(T`b;gkvODjidh`9?HG?Z#m2!YHvC+F%2cwwkRlDq z>1XCvuq6fE`6*L*BS^A{_m!outFIYOQ*H3jEftcDS*d zR`0Dy21>4ME71?-x5nag@I8un8AEhpDf1Re?shwwCLFce^nb;$*w75ds(ohEETA2E zxBA-eE4wcvz)=Z7gg><+^W^A&s4W~a<`3LuqKJFWwO0o!XUQ9NlR*Cg7x!kQ?TzZ4>IN1(ebLl#ZZjlaJk%w zH8pm*RgXf^x;aQDaLTxj3J|7Lz@;YFpVujgIaklpNq!BF9pS+a8n5e&1_@>uiTdlJ z^K;VhZKRzdApQ)p^~=h}pj_23JoNFmMa|0$LTCjIuqVCC%D=+JJHvLr!_CFF6U$4d zDRn14VA+rw;@898KVPlFg8lKGna%r&GlcAZT=9q;mRut#Ee~8pZF5|X6tOOMZy5Zt z*H!NSr3z>3B{xDoaujwjlZO%fXf`VJWckA zLz>NvtFh?1w>sx*mq!sH0N_%wcT7Gk>867yGZZw*)ksMcHpzq;cXC)C?FDm%;`!KQ zdy{^4o#s2Ia-0u4xDME)26<^S&A|^Pek$WECzeW`lno>92 zsP#$!M$n*DQ#owdq`R zU7XKDdB2$L%L&&Eg(U&%HpdSlA8Y~e>j6W z&W&}snRplz zeOYdzsEKDf@<(k$ZeUWBgVe!hjC~PC(?dp~x|dR?IyaYUke!~h{8na7T&0z=o-&fU z0Wd(lr-^`}?_Etea;^f+5YoD*T10=OQ|V8VSnyo6SHL?;5Xky`Euh;an^JDHy!7_sxV{zowq5Br|rsm9Y4Go=)GdV7IEkHI^7%+~vI@EZsyJbgcd zA@Y!zjiXJWLP|r*UaIAB_st)YVg%#>#V1cnIc!v2 zk)qT+L6a@E2&?WnE6Rh%40~o1u!pWf^$Pv7#b4e%JFZc;7qgz^3y-lWsCX$;&fVc1#6G7x zG-c!RTm4g|`|)Oz^BrP9=s5ewHkqiLZ<`_z2Dk!fErzrPCO$KBd3)a}f#Aa;&-O9Q zT;#Vj`urA{fQ}8Q9GK)QA@s73L)`K5Y~KKci3}D4C4v9;sfy*h^T?&1Vqen0Gmu-% z<{akca~{lF*WiK@x&Y%t|4hN0G5>>u?@oJY+Uvg_ukp!0ZT{ig>GDJA7r={~!04!K zlit2zdn5BDAU_B=`59h$BHoE_U+_I9y32ZqTO!UzssE%R+d)B%)=$z-YBIyMJH8as zqbQ=VCyfqZpxmYl=1l9nrR#0LuZ^5doY6VbICv0e0)#{e=*N#3y78WWahg@I5sQ01 zaOrAVnl84hxEeq5qHTew2ua+1)5tNk#m+4M8HCgoW%8iC4|Jaa(Ftf59zIK8x|Xp1wA(-rEG|dt z#8lwjWJ+v*R_HE1d^SZ(^m`hF)6QCNx6ogp^f_XKQg76so&TJOe}qc9 z#6Js`EC_z0GIE_^T%Yn-lDO_`ydVcu=2@ef;3i_izW^?HnB^3hdD1^(8D%6u)np=x zT_y)QHPKbP5t=Kt!%r`zsx-O}dP~|X+Lw?0;Nr1iEA`>e4Bv-KxN~K$2ks!;mBHL+ z&f%k2Wheg5msf6|`sH>1ph6)+1Nju=Zr?8n02hD);7sciqrlCe1N`1L3 zJJA_rt(EQWEP{qFm$nj(Yi2LU7u4Ff<_?<2BtqH!C&#g4N!{vGZD%skCz9F%6MVC& zH=`g^<80dBWJ?ZPpADTjh+W!Efqz6-WJu*c;cv18DyRhEgvi7d(yhd|(grDmg4*{W z^|>YeIof0Ku>>k(dGbSHR%EHrPN#sd`%hnp4fTpYtP5{H9>WqetgJ@tz0>^K)o$)_ zZBw7JgN~{vS#)73k)~|nAM;2CGSF}0R`qtt;3n5)CW^x$v8vb`tpsXATR>2=g%>JM zGSn8E{8n#4kAhwj9Za4r_lY2gNetEbnHx81d6Fxt)WpyFN^X>#4Mos4@S$yg7Kr*= z5D|CQlC?Q_t=!J99#R`STePg&<42vn;Y`u=nt~ws@{s65hEgeh!aD)|Tw`T;LB!GbV_c)mx!+5z&l%_2^ zJ0?!5&5wdXz)pw}(a9!wWy!g5B zxFe9{=Uht9hWNENm_Ejgc&hrXt1hu^nn`&`QlvlD_Li!&$Te6gKs$f;-0O$la5$YT zxU>$HH~+EmGJs9Xdxu5yI<#WneL(+Aks0)J4Ald|+wi#+wlwN?W_y%R!2@VW`+$4#jB^sF-EU*=4~Rq|<` zq_;~xoKd+@|9V4)prM_)nX&|L6dQTGwb#KGhN|A;FNZIn$hyD5d+Mls{xz$~lh^#@ zce$0nVxr{V{NT87f?{_+X;J5b0r#v2TI41k11$Td8o1rKYepvU1tnu@byipT!<(B0 zQ$84ACv~!pIh!12V>W1i*|nCfbHVB5rFfb$rhjZyc1hbH?d#Bm5<7%O9btvcg_gqbv-Y0TTphhP9nb9Y}Vs+d^yKfgs12VVqxD_R~m$l@xLSYku zzbfU#um6$=PO>wb@H0t0`$qp^j-(H`HSlghf;7RgXCd^}mWOL>8$x%j{`Z*Ma!jxi zwK!Z9bOe-m&P)KI1(-RVr~o55fW)!^sKx02-gsS=rD4rmBF4LUGwm-YJ@@S4$#mX( z>1>zIL4{tF8~EMDT9_bh3=i6t;~$ZD6$yIxB`V6Cfa(2J8>$|fMV&?oXVkiU4WLHS z6XJ8Ix)j(fY79I<&i*myFlX1|EsyD~v6%zo=SRCTvyG zs8V(9FTdRK-xCl<{Z@kaphLp#+pgbCQgPjGuHSu`^D>E}>aI#B^H5#le=KHpL|xN) z@BJR?MV-%Np9_No%9?u&v%{=XguVUH!!M3!%}o;ckhG z)0x>2DBVWG!BpnEo~2q$vHswsHdvZg%PQ23dhk3e&d5D_$1^bMxNfVNFhVn}#|{v3 ztTec``{9(`dw}~a70^Glz%*_7LurlnOXIjaI|3V@R6Hje)+m&w5hJaGJ9NHs{)W+} zHLVAG5XNAzM-QLa&(_}ANGt)L43AIli2uF>t5_8Lr$K@Rf)z^U)Fj4JwxtK|8Wa3wJhq)XmoedoWNystHVsgVOKvwHP<>k6;r=9$w*5Nrl4%pz>k$=Bxe#u#kt+Wg@4xr6w5XYfM%l_%_;?tOK3QuC z%G<51YUnbbs20NxYPAfgONb?lx;=N@AG7GW-dgA9Z!%Gw09d5h%V7GCU5T^<8{dS; zPXWD<*)!ilTRdcfIP*hO{3NbBByZpmCsFtDw3#(y+0u2w{E~jvyK;?9d7^C;>L`PV z`dTzv-m15QguT{gvqtCxou|S-eE4P?RXPf9%6NG@HrHq|Zn$t~UTgnq;7)cS6s_%H z?<8O!^Lna6EQh$aX*i^PxA8#up@H(i>C@etmt|=zJJ!fn-w5=w0h;*@2!t1i&@|&b zHx0$NuXCIiKl}pJ-iH06z6vlG5Z$6O)<+fbWmQi{@JMOUXk52l^rg$L9=XsUqZ}yM2tJCRa%wT$ z&l9yTKgx4)Hs-~q%A7f6a&K#`Gyd@u(T!USW0vVv4?2!n{#e=3ICKpGO)p%{yG?*B zHaZ$)us2UdO zhYFOPLo%P|k0f64)DWjU2@(&5S}W z_4{4dAKOpRC5?{?e$?0TdEKT@h0$Yv#T=)Ou8-|km-0sV>tPBrzVYN zOS9KHo#vT$>@sUo(yps?*Ai$UMz9-50lbp&BDgzt!~NP>>;4OJI@v%?+E*$+ZoN5S z#gavlz*1ZzwS%ca_@(a=pw~d-zcczHo-PdRhUeLExjU9O@U|fNbGwTp| zvPwsG^1)$fg*pPQ?%9rES*0r^Cp%%1Ku3$)I2BdLoDhyw9)EF9;3WZcIYuO@cZE`` zhvNy44EEJUqvO^IsrQm9ZZ0uwyuM60Ja-5^(XT(}w-1G(>cC)+VP?j^%00S!95!?t~U5+DY4Y8jM_)M6#DSbm=5V=uO|% zuT00bg53`SN98xiL3`@PS%GY%XO>m0GHq^TV+J-UCS%nv&JYbM32zl*jRDClk`p+^ zgCM*G8ylW(1W7ci^eEGKJP5fcwqUc%dNEsX^&MW>WacEs&prOql!grD?{1oatyA4A zF#t+7aT2}Z76`pi(0exH_+|MGB^veF|Gi!Ihme%#WB&RXA(R;QCVNhziAq#)^=$A= zenIgq@r$D#l9%5d+n!yV9YED??ADtQw$zz{ygdA7v=bhWm-VC=z++#2H3wv07LYvk z)Q5%LOWxw|F=dsZJ(#hun#*aon!MLWvjXzUj<{qCv|h3WKE~r5kRi@gB@y8VqDmp_ z1=A`#UpFeE<&QKiGYoe=srZ5R6xU|O^zNN2e~*R&Szyj$Q1!^AXL+fHH<9oD1f5n>osgbCETf&jrNVo5xE zo(UT+FL>PQUkbPB48ASi>{vYQTskr35NSviFn2X*s1(L3ik6c8In z+({0U3)3nS`3B#XzfivpMX(jy)RGxvfM?Kb)yBNsj7H25nIZK`fZahRm ziC<289Y}$vvX+Q0?E}F0Z@W}!5(Q+C3GL%qT%K&R>K^=2yL}V5QvT!tXnP^L&T#F9 z)DBc7ak4g?=WSTka*e|bx9?sJR4L3I8})j00T_P87Q#0_rWmmFJ<31I zC^e(8u4{W#H7pP9^r56u*&XI%jRNRHlo|;})^>L*`<4{A(i(!r#3uA1GzaOtO=hi` zcQ^r!vKv~v@P+3GpoN^V?dNTwU6sA_$!@_^GX??YHOrrMm6tZ|I49}^YX}&hF!f3x2Lo_BIG9tR7cnJaYuukFhHTb*;Q9MYxJ>E2|q)D>kNEN(Bjq(S11f{0a_W+i zR9FzFu?>>eLB_)h3Y>M`Sdv1EcG(pF3MrKbR_;yK@ji=;tCBl9+o&pb+Ls1jwe$$b zb3)Ha;O1xc%@FjOCM&k<@U(hs^NYUdeUBEnyju-OH6Ebv*Dc;jDjBbSTxl!as4~W6?X|~XQeVlP z9jf^BsNA?xtKXUr(Jm?zxE>EBGb9HiuAuCKUrA7*h~F&tP?)%LawCpdbPe_zUF>{K zbA%BXE1glhO~J2?ge^*&N4;cCjzO&}AxiX>z%8oMj+e0I1Of75Su;noKM8E+ zDS2J5$qSQrWd%dr(zVXg1l@PRf?tlmx2%-*ZKA( zTg3Jqc?2alc)AYyI$ zkA_Sx7iPKmsk2Yvf`EL{TcDkJ2QVRnsoXnc$Jh|8 z&!S@_*(dq_%C=djd)@Par_zt1wzu~C?z@^)T-X+<$o8Y*8+MDZj8LzDa2f!!zM8*m z?&VjQctlR_BVMm33$sY3R#oL(bLXtSTfD8OGWW5qrMmF9)&wLO4D<*{JB*Br?c?Nx zcnsTi^YZm`vS&IKC_lPR8I2faZSc@wP5i!1Ir_)i0LeaLwSgnk!TH6=S`E}Kc|=go zB#-|a@Fwr~aE{ymN%!@09Ddatd-vuQ`^6Z3-yODb)Ped<+((zu<46FU5qynCLPhI# zSd(}b`sXkZ6iHt6W9C8EPUnkoE$mYHwPVCHN6Z$J*f?7iffk8t%gT0!)~hv^r>~{W zyr+=Ewr6XsrK^h0mjT;T82|Jab%#;1fstF`PffauE&9lE_#E@Ws}i9@p|!HdYVF=< z@R5C_=2vwJ6@QY{n~TJ2>VIK)$k>vrikE_z92Dh^?Qy2#42o8yl)8*}D{H5IUsb)U z@o~_Of@yoR-?#KSMVk-56*a>F-Ml}qB#MXl4s7kGQ>OkOQYQ0JgzF1FIz4Kt^@5IiNK+|W_XUPkp=3dFd% zB9k1h%VMSJogH$%Ju8x}H6Vp8^URMm`euKZ2qa|$Uz+Hkd*;@yZfCY9aiVp$z8b8( zkFZ_>^Zf%yR+!h-yR1Jjm%)R2QP}*9_huLpcmw#kZ{qm7XuL3n6 zy)9;gcb)TxE+{u(#l~N^4)qs({^MMJA+y<=n=3N*(g|T;w+~N%xX&AK117s8fv*aW zN$w{Y0~6YgV6K6ta-Lr8p|e(}#=3N4dn7c0+bpRIh!p0Z<^|tPk}{TpIt|9_*?=(Z zX|ivsEAD^4n0ESK@$Mv&?`TI&psCVj*ei_yxR`YVY^MJ@j z-KL#fdvk3M93vLK8_lhm7Hv|h%;x<Y@f^d`{3Fzp27>LRwD|AGA$U!es}nl*~H^>cf4wH()NA__^ExAZgRH~$~9 zFwWz@`qMVXMCTe_Y8_A{!F&)w#ecnVsb6DA&_1^-0h#;fIR&p;X8U?SVN?=RU=IZW zS>Dsgx`!5{(o7_%7gNsGXyWh1+%d@3DPWaz6Z^Ar>_Nnkt=u!SWP^C&2xksPD#wm8 zwa%+#1uFSWIbp93X_7mlTW`HaZWYshP`>w!8|57n*laze+#p8lO!y>Znt%}3opIkM zyMn(o@D_RB&uYVl@{wM;e}$D;1vHL2Ox$^3;_i@ASDSffBbJ!JMh>(RvFxG6EPQ5T zJ{wX;R4<%#D|OozUO3ec8)6?mu25#Ax@+^#6UBil>Yiv`AbK74rqt0_F9{ z9`;r*)YlHA8RMMD#@enB+V;9pEadqp)MG+oh?he3bL_)UI?ZHnXl(G0*zC_VTHA4o zm1j9$e-_50t3r`&6bf%t&@I|qH_O=C(Xkg6jO2Zgletwlh<;x9bg!0l0cIHG*uQ9X zeQg+XU+n&t;O8hy3RSg;`&^qh?{Xxme2;$_`kY)kJA9cj6vC&ODatjg?a#~AN5_5* z`Y>Am%C?RZN8Ih^CxiCngW}kyIrdxPX|;oSM&u1N-yi8s(>TGv5vu+UES&QkMKsM> z-}B)i_p4gD8dTD)RC8Y6Bwkwmu6(%(C<^~?0QSG>-xtZi1t&~(O7*ES1&ohnaX!2L ziG8(oi4u02wVt~z${l#~S;b6@v#j`pv}vt+fevGoITg>%b{c52;yv%sShC~+Tk<9v z(Wmq};|sj%_A1zB0IMAyI0ei8nq)u@;n-DTPbh9jg}~e45nMOmIuH!4%wea-?zW6E#gZpozQLzDnn$lmvj$(%-v9dhxk4l^O52h*j-A!c5xtf4?1Q$iDTM}V&{ zp}H2ecj11~>UF^#NCos+4{k+uG32#|tTJ^<0*_KmiymHY|Jx(eY%P>?oco^1;?0lo z5AU{7eVvyL6#`lH_01ZDND#@SKxJ5M4~Pv*?sb$d3VO*It%gLWWzcfM1eWy~u!`5p!Fg zCMfB0r)+v&u@?TR(LtFrAba4tagYt{nfU}IEA$6Yj|`X6XGGM80<*8gcBR79lLAeX z?T`N`Pdm&zaBr2`NAAX)YahfvK5gj&@C85_SJUj90MpP+ zSflXPOFz0G?}_s{f%Ee>ywufnw|GL#0hREto9z07q}XrqO{;XQd#Fj$YoG!}G7xi4 ztjAKP*kD+^L}TAsZ9D|MkQmd5Ej*AFH##0{3qC*)A2QaDHDc?X9yWfqKl;}fQ?3SS zB9$`aU+y<(w)~p1Dci<9NlTSDP0t^gUz^SB> zgP&>2Nm6J+b|##rS3sqesl>;=U3!`n@u|c&M?-61>Enz8VoUHen7GzZg}ZJyZhu5P z>1j|`{2gV59#7Xh;!cRuNGF`_Ny{`Vu@#921vlVN2rIKl0-CtEB7QhGdvvnhpgz1= z0pwD~iP1Z%O4E#ThBhs~LGS5~z?!n9UY6;;fOxT{ zMJzAUiw(6cZHXa@Q<~`%u@C;(7kv+34^AH-1sW8zE1#G#cfJ}T32HF!EQ6@<@s2k- z7OA!Z*!-<<(N7PINcQyg%ujaj$(DG$l9+$SIn^xI>T9Rw1MTLU=}&QvLs+vMX`I-I zFF64bgkRVJv1wK|FT&_-{NQL z;3G$BSB1k76tRV56~yg@2c>%t`UXMkmuZ{$rd)Thq~OCtY&v9rqu+KS7S)9j3(p4@a+TaiuYvIlyl|f3CHD&q>Q?gUe)2t=2mIC#jRGy0qk^ z4N7_olb-B^zYAT+{egPO@ z)F*&ZU7-Zsqa;p~w(_@ow8Ns#>_QcWJLR>4uv8b;`PbVV&Xc*0YS#L@P~V4i*Ens^ zyI)!dh~iOmGh^UiGt0*;e&y@wkog16obe zq!8DoWslcAgM-th#No%poM7f(aI>oI4ix2P{p{?lz;HTs@SUsQN(by}Y>_TLlu*w> zPwlte7KW9_(ecDtZ00mj9Pwqk!3{SkX(C>`{Zoh%>D7|j1V+xK0X(aByW*H^z(`E< zTQ3^sC(3&-EXeh!wwaA_t*ckoTU8O$Duoah_+YbwQ9FTgy9#oT!yUTxNPI-6r8z`w zXEd>=7aoTZ6HhPf+J0y>kExJ-+RA%ta=De(tNLuz{nw9uW2jvZ-<-*=Ff*YmZP$sc zwnj;wyx%tWp$qo8aF3j6v=BuR#cwS?yKRxU@1^> zofL>n=)OB|KEXxsyUv8QvYN5{_Sy6c$N3vBY?(d9l(~-0EmDY~`0bA&(qYyt&?^92 z+gl}rR@Drc4dkUa^ba*aCox{Vo_@S- z8-zSgW&jD{q0=%1jA0QQai*vKcI~gMX-2{NLz$f6)#FnE94`~*7oq=!AjFk*R#Ws{ z)sS^P87*6${@7wlV#^b__CRdNt|HD}!mwd0F`=gw{x3@bQQb*Q>KU@|zTpyQ=HJ^T zA|L30P(4fX1X3ZHgW|c{!tB95%Q19zvaBr`8G1qgV&+}mmjhoJ4tW&mUp;(ZpEhKFA5YPz=#$U1qYDlcHy8^U5 zmig-YGfR^SU1R5HeD)T~F{8DX@;<*hnJHD0U(`^|Q2 zHfx4dwnO%XU3Q=+^5tvc@I#&Ca*?wu33K#IA3f^wPpZJyDb8t}qf-08vrYA@r5^EN zYczK{GaDSxnBAlrl#_I9N|l}b)q{^WCHbQLkkcZy;wWI!FgzY&Eh%BI3!PNQrA#Pmj$yVw+HSospHSj@){&ruEO|gc^}fMQK9_Co#>5URiRLpvki6bghmhxs_@>!!4otG6oKs`zq+=H?O?zLCMI-E;#e|k>a1y zUT%lClt>_YSH@fl#BGX0-=KK83cW)zk>Pghb!()eV7GT@3Hnf#;wVBdZ&T+DvtdkL zfOOp=P*U_(H$n^p3?>6_17orfbDChS6b73tag#_L4)gV_i?*RIW#OAi(lvVCS+Ojg*A|yCk_p9+PO3M;b7At%uv7 zwQLEl$A)3AhSWNyJA;dzHA0(;e#&!l1x8;XWJE+O&k5(S;bNuI;#J}=;8 z6&q=jE(g&~44Xc(S648MnV$ph`>pxxbV=qcik`*KgHLdolCI=O>nW}GZXLP0?b`&)MqgjHAElSJnN=IAO(_iD&IxS%k&K-lq zo=&(2My%{)d15t0vQCcv-b;3YFt6&qD6{DaNL3!j&*L?y96lMdhLQJ&YE{Luzf}7Y zsyuKP`!+2(OOr9r7EA*wa1n!F-4C_&(`M*Io3w04Ac*WHk+-g zncAGd*5o>bU~e-->vB<2l?Kmlbi_9-`t-6K=ogHO>27B(v#E;+4Xdv}!*y8!9Of=A ze_vQc7o9U{oP#V+x@FliYuO{K>%a6tZnrs+w)sGAe;vy@t}$MRf{4M7W^;7jI(%Y3 zbN(FP=FPG=j{Npl?d>;ix4Olm$xA-bUa$%<{kdmy-_1bq8sbx@^W~;6^+@%Vl}?!tGq(C_Qb}Q zw>d@4=Bph1TA&P_^o&81UDHnqFOjwANU&6f(SCm>x5NT0liu=qtvQ}z&k&N9VR?KP z^SU{EOn<cu+wC@; zIr5}~G5xET_a5EBXhUN67QsWR_G<4d2GZ;4thyq{V1*&Y&QXh-=a0qAlCZDhps(if zRs?Alqyaw9vR+2k`S1bSzH(zLM|1kCEMD!_Pj&HT{eZ!Q)+22Nd-Bf)%pV>t2WqQz zuf{0Vw{MB@ou^S2pg0)6HOKBd$t=h=br>bj3c<~yDAI`&>P>nL#I9Kx5JXyb8`s|y znvJ?5(5 zG`qGpAPEdz%S~y1vQ70m>kZ41Y3BlYY|9fRyvUXC9_x?bv8Uk2tvVY#g4+%B@wgQ8 z!%T=fFT=QT{2#gg$n-CDJerBM32ijtZQXm%?C0?7=Fl7Z#Box|!GRwR*o-)Ivdbjl z;QFigLwX7vbY|N2vJ3H$h|mk>hzP^TJQy%p^!?RDGEoW8f@wAS`pP}u z1AY1>(mEH=^w(Z1w9|(@U^*#gjPEpN);a2XhC0rT9P)aqY>*6Z;^gH& zwo%UZPIAMLlqo+FybLY0po5I0QHS)vdlyNX^Om|pS}G>XEz|rQybc#i^BzhLiuQ@q zGE-CY#*>GYX@!-%*QtMu>8FqJcfO71LbjKTVZE=IgZmad@#z6$1$*~Su0bC~JQ#Ig z;#7mtFY+$aj78uX>&Xt^K#L{^jGcj?ndTU}mg(fH{MaqOH_&p%7x*w{`#6QZ8~gqD{dygO6uNo3qayWo(#Wgd zdnptf>=vbWl9tOz#1&B14+LZNm$0-r>-CVg8E)CeocyD$$O>#t)B9+_h8A zy;8tJ`eMf)WG=JY;XBsROK6d%UgRq(cYh4iI2n}!TJA-d@|hHOGXmbK#A#2$?Mfrh z@;zF1NI^1VgRa^jLmc%{#9n!K;u1}fso!X(EgG=1N7thF!Tib0-w(ltGBEtnUBEMn z?jtoBcNllg*?gYnxBui+aCt5~B@frCB9W-je%#q^(?8%#(y5&?uwr;uIMQ2`ys0+m zXHPM~3U@~9bL`^|Tf9yMb^nu~trk&pHDP%EUSMCGS*8b!g>HCRlSz5+vWm{SwT`s` zq1457V=jDJ3c#Ax1fk#ySvm4E2-B*yBF8Hz$l=HeB%MhkwSKL8=pRuJt;iM*3rWmY zJyV#f9ox&Ss1KkplM>0~6d8-~qqf_HbgqhO(dNKRhU3;Ut1wlrT?>@|n*^5ej>E|h ze?>U?4kGjU(8stpZosN!jBV|jYyH46FZi-&k*Z;MUjkXAhCQ))9)<+qlDv=jXk%&7(uDf z=!7k z(s1iVoa))9h4lYtcRjU?qDJ_-QJS6QP}L3f|jl>t+Z`sA%DIeEmQ=5MrG}4&{GCy zsW@9E`}t%wZrAv$L4%Y%XQIr_4O02lKQdBjW{a4R&o+OQJzM7h>$(Qa56fVF9>Hwm zV0W|X`ND7rhsv7XZq9y&2XDMqM;qzSFNxfm916QS$1oMX3z^qqLd~Maw639Vx+plS z`3*MvKSM+?Z+uFb+7Y|ND)2A=>$fJX_8+<@?t@GMb4LiLlvZMVPW6?@SkiwAS>jtD}m?+?o7B zGEG3Phdr&-d5b#ot=z5Q_2m}6S~9z*V9_`fRAu;(I=iPGB_ecisRbqej(R?S|F#E0 zB|`Avm0fBF2odM+V4%xW7jaKQqb}#zMgB2yM9LO_^b&~fE9u7y^E5ET9(>f9YXT7;hY2Lma?%P$H+J51rUKX3Dj<{8LlLB^s)7CGf*d>uYQ>C_x z$B$M-JuXtK*`=>U+90VwLZaEU>x%G4b@Jv@s7MW&WXD888#B_usU!J>#-aVGNqVS_ z+6pIaF-JKZvh?uzS1$o7n+_uNxsPcQFFHf6mODRu5_XOW|DlVT7U&Tn6q0R56&OWd z3^L1*U?Q!z*wG7jC5Oa_un%dm^eh|53xM0d%y4hT-;Eh$M@hics6Se9hpFkjS0AE2 zZeheGNtI!8C0m(vfZ;CSx$cphKTT_OSvZTYti}#MlbFW67p49QI~LWwre_cO=`O+T zAY6VjCZ)g!wH0hlsMmMIL2bnz>@9KwPnKs8SU4nh_&RDMUMTi> z$l0LaTe+$gByL!wnH%|NQ+3+@SR|S* zX$iPBD_mOQz7YXx$PocZ_g#PU!n9@#Pnin5t64SRS;#pnv@lCQl?u$~wj5fL_)2c{ zQ-EpeT;Z{)lpIW|^*NKN{zsg74==<4i20uG8o;T=nI{LBYM{+V^E6uzKp^(KVl9vh+9W&|7O3SRSsqX4o7pEu~eV==my~EbNRd$$} zuDu&cRIQ3M6J2~tnpMlwZ&o*=XCU~oOZ;+EzdE-swR$OBZB8UdJC^Gk4VA$BiXnOG zBDqN@TDmyjt=WkDhlpR8aDnsn2qmbMp}z+g1Qwym?VxI^zmhnULSDW4+Gi0MW(Sn@ z0lTxzJa7goYk?%+DdMb@KbbD*=9!)7HnJH~d7$OlDKe20$c-rt@GCw@Z2rOH)PBQF zNu+d;p6hJvu-40~TAj^S`CN^0+{WyO+SiEhgzh~VXunVAV;)AXFx~D^DwS(YJ>E0- zb`P9^#M5>tfE7F2uow9He{*1n29g!qSV*G!bMWF^cKbbVQGLJ~c4_NcKTd*3qvE?~u#zpzvXj@Oxj0B-Ja`uVSZ>CWmr?U-kar~exp)}QxJfXO zwgm9pr%2w8l1HWqM?8md__EI;$^Tp+ZN?$%L2WC!7Z055$tRAUKfbi(+SQ1?y(SkK zwjx5|^Wu)it#0tE*Z3Z-U?RQYWU@qPYD;#sasu$jIJny^mdSbD}dOSA(%1xj&}K%FkS2gs(r_F7;B2uEP#_?+bx1&L();m*?^0lz#AWB&av0C(bkJ&jM&6wtWjYWBMt;U83H z?qH3}1`%1VYjP zW_c626A5&V`LlAw=mp?(V*Wsq&w0#nYCF!s7jP!3KdTDWx#4ha@(}n|IF#iVP!tqN z-t-$b*+W~uSnA1|{r3YR7J9$+FmUoj#cy#swX$<(=l5C|pz!@Ve$_1geE=ZiJ+K^% z5c;z4ZuUGF_tj}{P!Ci&;nLv*I4cy~8Y%ku!i3%E9ttFZ8O(|}f*MQ6I&Fq#J^6cT|H0Z`J^lzu##eg#aJA!W!3ls_8np@bf<>IEPDs&Vw1 z3*`>7O!xCB)D3sM{NwEvor-jSYdDoz2ThdsfglPahn#5&))Q8&XYHOM|3Fh>$mG;ReZ}q4hLyYTr9~;Umm}CgimtHDon3 z4rlyI^zgS^70dI{p#WJES^BLPbiI+kS*kA zy`>)_gv56|eL&Xg&~Usz+jBzbVd$YpV84+Dw}Fv_b=Zw4RYt_G0oSIR=sJYgioDN~ z(=aQDE&JMEZd$|x2B?z^$jVQvoW)&n^lCCVtIv(RNpzX3q(j_U>^R*o82??l`%=Bu zdTej__wcXbReYulTl*E`4$Sr2v1op_Eo?d3&%SCtN`{`}*Kh-IZ?;=zlLe^AcBGgl zU?ds1{TlWP9R->v9g#=l;Y%bipk3l-V?A&+ourb=DATokK4a=UHe1Vaac%=4~YWZ%RL+^`PUeM3(qxCh3!;(xIck5LWwUMITlM_sGkW80sh_W9|&w5TcdV4*8koY%M;^u7U8$0|S12W`z){@tM1 zh3QAv0L?PH$B25(C_~PoIOBB*_W*p@JGTWQuuC4ls^B@}y3J6G(rE~3kp1~e`3{zm zl)NDY8@rrOTSo)W8UY~q*;RbA5@D4BFu$(i`MFcTzsZRq7;Hk!R1GHmCFdM77EIFq zGa-N8e}Cyx(`mPlOaz_3_(hGELgBxih2P{FkJ!8s$#j;wyAf+sNcU=9>{Xk>bGh>g zZFik6B`Dv$er^Xxns(4ZKBIkR=m#{kA!WZSU^;1LoW@u6n{Gw;?-nR%C^l_2vcY!{ z+xbIBIq&$zxkdM3nO0GIOZUaiTg`TVZ52>Z$aH%8a~xp*>p7S3^Dx=WnYv9s z$6H=wX^x|hW_Zp;gHL!;*hr~0&nZ*mT+@#xoch%z1=!AK=zJwOOQzvF=E1uu(`sj; z<{Y^QQK9umoj}{YF91ixY!L#DT)Jo%f|Bch8+)NV{#!U$W5Uuj<2qF#q^2=|aE zkzf+PZaGsq!uJ-N7UNC)x*t7Pc%F8)pzZE5-RHCeX3aB}=dc-<8pP9N_9n1Xl5mfI zWPEAk0G!>O#r1fV&VkPGCVhv^xmzf=kj2kD!aMbJLDu>F@$AT_8i;Oc*N&|jPjyCJ z`92k_y8EJKzFiz;F#uhB~&?GS|wFe{XKu6DM=5H zlnOyWaX>BQNz#n?@g+Q!;_|g(D0xld8=0WPn6Lcc()|HVcu?_by!F6MxhSYL^&pA| zqqW;Lmr_oenEqE(_rsT_uUvzrkYv_mpl<`@Q(Z~@PKOWd{4RYdTg0G@WL>+yD)i;&i7{9$G{X{>ue;AT~7-Ou zUTK@H=*zYDZn9|U=a`#oC0rO|rTwVdz&Q}P_f&%RyDGaxc=q)=;J+x&Vg#28YEbg8 zWdH+~;UjJ8HKkmIDuw2SU15~ejCUnjOUexlQx)`RY#8WevB-Cso$lT)CKa7E<^z<#%W z`f)kQlEYU=b^ftzr<$wJF5%8;$F^|BdV*p+G6sm-2+uq$p`*!>gxb8DlGbt_-GL>j;BG`h=)+E4Jq3+s4TT<3Fx-j#B}c%NYmeOJz69EmkPj(wivtA#Ft$hR zTM5zSDbh+W27ka5UNq||jMx@^v0&%oZ0F$N>{WS!Df{&#i*3(37@$Ghjl;R~^)s|{ z5{NmW9s>&s>9Y|$f@c};g>KQ35}!ly!LvT;YRVx*y9t}Mi+IEuT_i7VB_a@z9FEj z=RL$->FQ{&8FXLcmiJU6L0X zY_4;0{cR!Wl&`S~EEmi*mN|yZQbtnE1~MQUy=-Pe_MAMAb^(6A#fEK;W#1X`CpH z$lysrLO}(!jp_}`4$*It+J~%pBQDtY~exSB%^$6Bo?v* z-Gimvvsb$_`1f67QMomlF4CqzcR$N2BDT?)4t4XoGPS||lI9oW?KH7B`FlhL<9qq~ zL!oLph%9V!XoEh>f%Dd==0vg7oz8h`wQfMKUpsv)flgID1A6!#*WrXGpC`liS+D!N?XoDf|EVE& zG=XhT_dCH>=s}Y);CHF;!vQSN46sg0@i^5{E-9{fBkIwIuI;EM0M*>dDUH}X5LDZ- zmq-Twd=w~!+D{U3U7-&uA4!ur?s3gQrb!=zf_Ky8_KbmFj3>wu0FN7q%ZaA|*Dqjh zpHQvKOhZHnLk+cdUQL^DGcQ8(kFp5+%Jm%NVY)!T82_f!y74BWC$qt@9&VWAc)G^# zr7C)Q7kig_S9;ezOfvPW#tXxhs34r@JgPQ}ErT~l03y(jSjxK| zU>%VQT}=!Q^+H|K$~6mf%t7&lCQk~<3GBx0>Hn-SYIkJ2?6T~-?6&N_?6K^*>_s1} z4pKM874X1UYk9|o$&uJex{oOM%OK!TGQ%HQGCKZyu8eu$WOBCyO{3CX z=~5M2B&j?hPAw_t=_w8-BV9+<*WcI z8=5;-V~Dd$$km^-!zWGL02)iIb;q`Wur+IWvZNX`>^GBa&Gh?n{^u2xS1J1xn?sx5t4# ztIaaO)5PPRYm}On4bgXAyyMNDM7Nt^|^aPvZVp@D{$IxnMcw2U`8VD(-9!a_O=@!!Q(?L8nGbI zv}poYO={TKuW=-7W6>v5<3ZD2i+k4f|6XzYA3^Nh=-uqy>fPzxBPcJcg$D`C{;5@m z^#~H%XT_m%#az5_5MeRB`1D4VpRClzQ=Y6Nar3i;hV6H^k%k*> zCx;!u>4%#qR
+    https://emscripten.org/docs/tools_reference/emsdk.html
+
+ +Build and Run +============== + +Linux +-------------------------------- +- Build
+`./build.sh`
+ All binaries are in "out", which contains "host_tool", "vgl_native_ui_app", "TestApplet1.wasm" and "vgl_wasm_runtime". +- Run native Linux application
+`./vgl_native_ui_app`
+ +- Run WASM VM Linux applicaton & install WASM APP
+ First start vgl_wasm_runtime in server mode.
+`./vgl_wasm_runtime -s`
+ Then install wasm APP use host tool.
+`./host_tool -i ui_app -f ui_app.wasm`
+ +Zephyr +-------------------------------- +WASM VM and native extension method can be built into Zephyr, Then we can install wasm app into STM32.
+- Build WASM VM into Zephyr system
+ a. clone zephyr source code
+`git clone https://github.com/zephyrproject-rtos/zephyr.git`
+ b. copy samples
+ `cd zephyr/samples/`
+ `cp -a samples/littlevgl/vgl-wasm-runtime vgl-wasm-runtime`
+ `cd vgl-wasm-runtime/zephyr_build`
+ c. create a link to wamr core
+ ` ln -s /core core`
+ d. build source code
+ Since ui_app incorporated LittlevGL source code, so it needs more RAM on the device to install the application. + It is recommended that RAM SIZE greater than 512KB. + In our test use nucleo_f767zi, which is not supported by Zephyr. + However, nucleo_f767zi is almost the same as nucleo_f746zg, except FLASH and SRAM size. + So we changed the DTS setting of nucleo_f746zg boards for a workaround.
+ + `Modify zephyr/dts/arm/st/f7/stm32f746xg.dtsi, change DT_SIZE_K(320) to DT_SIZE_K(512)`
+ `mkdir build && cd build`
+ `source ../../../../zephyr-env.sh`
+ `cmake -GNinja -DBOARD=nucleo_f746zg ..`
+ ` ninja flash`
+ +- Test on STM32 NUCLEO_F767ZI with ILI9341 Display with XPT2046 touch
+Hardware Connections + +``` ++-------------------+-+------------------+ +|NUCLEO-F767ZI || ILI9341 Display | ++-------------------+-+------------------+ +| CN7.10 | CLK | ++-------------------+-+------------------+ +| CN7.12 | MISO | ++-------------------+-+------------------+ +| CN7.14 | MOSI | ++-------------------+-+------------------+ +| CN11.1 | CS1 for ILI9341 | ++-------------------+-+------------------+ +| CN11.2 | D/C | ++-------------------+-+------------------+ +| CN11.3 | RESET | ++-------------------+-+------------------+ +| CN9.25 | PEN interrupt| ++-------------------+-+------------------+ +| CN9.27 | CS2 for XPT2046 | ++-------------------+-+------------------+ +| CN10.14 | PC UART RX | ++-------------------+-+------------------+ +| CN11.16 | PC UART RX | ++-------------------+-+------------------+ +``` + + +- Install WASM application to Zephyr using host_tool
+First, connect PC and STM32 with UART. Then install to use host_tool.
+`./host_tool -D /dev/ttyUSBXXX -i ui_app -f ui_app.wasm` + diff --git a/samples/littlevgl/build.sh b/samples/littlevgl/build.sh new file mode 100755 index 000000000..ec123263e --- /dev/null +++ b/samples/littlevgl/build.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +PROJECT_DIR=$PWD +ROOT_DIR=${PWD}/../../.. +OUT_DIR=${PWD}/out +BUILD_DIR=${PWD}/build + +if [ ! -d $BUILD_DIR ]; then + mkdir ${BUILD_DIR} +fi + +rm -rf ${OUT_DIR} +mkdir ${OUT_DIR} + + +cd ${ROOT_DIR}/wamr/core/shared-lib/mem-alloc +if [ ! -d "tlsf" ]; then + git clone https://github.com/mattconte/tlsf +fi + +echo "##################### 1. build native-ui-app start#####################" +cd $BUILD_DIR +mkdir -p vgl-native-ui-app +cd vgl-native-ui-app +cmake ${PROJECT_DIR}/vgl-native-ui-app +make +if [ $? != 0 ];then + echo "BUILD_FAIL native-ui-app $?\n" + exit 2 +fi +echo $PWD +cp vgl_native_ui_app ${OUT_DIR} +echo "#####################build native-ui-app success" + +echo "#####################build host-tool" +cd $BUILD_DIR +mkdir -p host-tool +cd host-tool +cmake ${ROOT_DIR}/wamr/test-tools/host-tool +make +if [ $? != 0 ];then + echo "BUILD_FAIL host tool exit as $?\n" + exit 2 +fi +cp host_tool ${OUT_DIR} +echo "#####################build host-tool success" + + +echo "##################### 2. build littlevgl wasm runtime start#####################" +cd $BUILD_DIR +mkdir -p vgl-wasm-runtime +cd vgl-wasm-runtime +cmake ${PROJECT_DIR}/vgl-wasm-runtime +make +cp vgl_wasm_runtime ${OUT_DIR}/ + +echo "##################### build littlevgl wasm runtime end#####################" + + +echo "##################### 3. build wasm ui app start#####################" +cd ${PROJECT_DIR}/wasm-apps +if [ ! -d "${PROJECT_DIR}/wasm-apps/lvgl" ]; then + if [ -d "$BUILD_DIR/vgl-native-ui-app/lvgl" ]; then + cp -fr $BUILD_DIR/vgl-native-ui-app/lvgl ${PROJECT_DIR}/wasm-apps + fi +fi +./build_wasm_app.sh +cp ui_app.wasm ${OUT_DIR}/ +echo "##################### build wasm ui app end#####################" diff --git a/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt b/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt new file mode 100644 index 000000000..56e9d5dee --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt @@ -0,0 +1,143 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required (VERSION 2.8.2) +message ("vgl_native_ui_app...") +project (vgl_native_ui_app) + + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -g -DLV_CONF_INCLUDE_SIMPLE -DPLATFORM_NATIVE_LINUX -DUSE_MONITOR -DUSE_MOUSE=1") + +set(lv_name lvgl) +set(LVGL_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/${lv_name}) +set(LVGL_DRIVER_DIR ${CMAKE_CURRENT_LIST_DIR}/lv-drivers) + +message(${LVGL_SOURCE_DIR}) +include( ExternalProject ) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/download_lvgl/CMakeLists.txt) + +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/download_lvgl ) +if(result) + message(FATAL_ERROR "CMake step for lvgl failed: ${result}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/download_lvgl ) +if(result) + message(FATAL_ERROR "Build step for lvgl failed: ${result}") +endif() +SET (LVGL_SOURCES + ${LVGL_SOURCE_DIR}/lv_core/lv_group.c + ${LVGL_SOURCE_DIR}/lv_core/lv_indev.c + ${LVGL_SOURCE_DIR}/lv_core/lv_lang.c + ${LVGL_SOURCE_DIR}/lv_core/lv_obj.c + ${LVGL_SOURCE_DIR}/lv_core/lv_refr.c + ${LVGL_SOURCE_DIR}/lv_core/lv_style.c + ${LVGL_SOURCE_DIR}/lv_core/lv_vdb.c + + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_arc.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_img.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_label.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_line.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_rbasic.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_rect.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_triangle.c + ${LVGL_SOURCE_DIR}/lv_draw/lv_draw_vbasic.c + + ${LVGL_SOURCE_DIR}/lv_hal/lv_hal_disp.c + ${LVGL_SOURCE_DIR}/lv_hal/lv_hal_indev.c + ${LVGL_SOURCE_DIR}/lv_hal/lv_hal_tick.c + + ${LVGL_SOURCE_DIR}/lv_misc/lv_anim.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_area.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_circ.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_color.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_font.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_fs.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_gc.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_ll.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_log.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_math.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_mem.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_task.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_templ.c + ${LVGL_SOURCE_DIR}/lv_misc/lv_txt.c + + ${LVGL_SOURCE_DIR}/lv_objx/lv_arc.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_bar.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_btn.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_btnm.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_calendar.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_canvas.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_cb.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_chart.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_cont.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_ddlist.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_gauge.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_img.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_imgbtn.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_kb.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_label.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_led.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_line.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_list.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_lmeter.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_mbox.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_objx_templ.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_page.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_preload.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_roller.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_slider.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_spinbox.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_sw.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_ta.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_table.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_tabview.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_tileview.c + ${LVGL_SOURCE_DIR}/lv_objx/lv_win.c + + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_alien.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_default.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_material.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_mono.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_nemo.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_night.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_templ.c + ${LVGL_SOURCE_DIR}/lv_themes/lv_theme_zen.c + + ${LVGL_SOURCE_DIR}/lv_fonts/lv_font_builtin.c + ${LVGL_SOURCE_DIR}/lv_fonts/lv_font_dejavu_20.c + ${LVGL_DRIVER_DIR}/linux_display_indev.c + ${LVGL_DRIVER_DIR}/indev/mouse.c + +) +SET(SOURCES + ${LVGL_SOURCES} + ${CMAKE_CURRENT_LIST_DIR}/main.c + ) +include_directories( + ${LVGL_DRIVER_DIR} + ${LVGL_DRIVER_DIR}/display + ${LVGL_DRIVER_DIR}/indev + ${LVGL_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_LIST_DIR} +) +add_executable(vgl_native_ui_app ${SOURCES} ) +target_link_libraries( vgl_native_ui_app -lSDL2) diff --git a/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in b/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in new file mode 100644 index 000000000..225af16bf --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in @@ -0,0 +1,29 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 2.8.2) + +project(lvgl_download NONE) + +include(ExternalProject) +ExternalProject_Add(${lv_name} + GIT_REPOSITORY https://github.com/littlevgl/lvgl.git + GIT_TAG v5.3 + BINARY_DIR "" + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/lvgl" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore b/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore new file mode 100644 index 000000000..2372cca06 --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore @@ -0,0 +1 @@ +**/*.o \ No newline at end of file diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h b/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h new file mode 100644 index 000000000..f1b966e0b --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DISPLAY_INDEV_H_ +#define DISPLAY_INDEV_H_ +#include +#include +#include "mouse.h" +#include "lvgl/lv_misc/lv_color.h" +#include "lvgl/lv_hal/lv_hal_indev.h" +extern void display_init(void); +extern void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p); +extern bool display_input_read(lv_indev_data_t * data); +extern void display_deinit(void); +extern void display_vdb_write(void *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t *color, lv_opa_t opa); +extern int time_get_ms(); + +#endif diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c b/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c new file mode 100644 index 000000000..58f7be0ca --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c @@ -0,0 +1,95 @@ +/** + * @file mouse.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "mouse.h" +#if USE_MOUSE != 0 + +/********************* + * DEFINES + *********************/ +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static bool left_button_down = false; +static int16_t last_x = 0; +static int16_t last_y = 0; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the mouse + */ +void mouse_init(void) +{ + +} + +/** + * Get the current position and state of the mouse + * @param data store the mouse data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool mouse_read(lv_indev_data_t * data) +{ + /*Store the collected data*/ + data->point.x = last_x; + data->point.y = last_y; + data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + + return false; +} + +/** + * It will be called from the main SDL thread + */ +void mouse_handler(SDL_Event * event) +{ + switch (event->type) { + case SDL_MOUSEBUTTONUP: + if (event->button.button == SDL_BUTTON_LEFT) + left_button_down = false; + break; + case SDL_MOUSEBUTTONDOWN: + if (event->button.button == SDL_BUTTON_LEFT) { + left_button_down = true; + last_x = event->motion.x / MONITOR_ZOOM; + last_y = event->motion.y / MONITOR_ZOOM; + } + break; + case SDL_MOUSEMOTION: + last_x = event->motion.x / MONITOR_ZOOM; + last_y = event->motion.y / MONITOR_ZOOM; + + break; + } + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h b/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h new file mode 100644 index 000000000..6e7c88e63 --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h @@ -0,0 +1,72 @@ +/** + * @file mouse.h + * + */ + +#ifndef MOUSE_H +#define MOUSE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +//#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif + +#if USE_MOUSE + +#include +#include +#include "lvgl/lv_hal/lv_hal_indev.h" + +#ifndef MONITOR_SDL_INCLUDE_PATH +#define MONITOR_SDL_INCLUDE_PATH +#endif + +#include MONITOR_SDL_INCLUDE_PATH + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the mouse + */ +void mouse_init(void); +/** + * Get the current position and state of the mouse + * @param data store the mouse data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool mouse_read(lv_indev_data_t * data); + +/** + * It will be called from the main SDL thread + */ +void mouse_handler(SDL_Event *event); + +/********************** + * MACROS + **********************/ + +#endif /* USE_MOUSE */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* MOUSE_H */ diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c b/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c new file mode 100644 index 000000000..e8bbc5218 --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "display_indev.h" +#include "sys/time.h" +#include "SDL2/SDL.h" +#define MONITOR_HOR_RES 320 +#define MONITOR_VER_RES 240 +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif +#define SDL_REFR_PERIOD 50 +void monitor_sdl_init(void); +void monitor_sdl_refr_core(void); +void monitor_sdl_clean_up(void); +static uint32_t tft_fb[MONITOR_HOR_RES * MONITOR_VER_RES]; + +void display_vdb_write(void *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, + lv_color_t *color, lv_opa_t opa) +{ + unsigned char *buf_xy = buf + 4 * x + 4 * y * buf_w; + lv_color_t * temp = (lv_color_t *) buf_xy; + *temp = *color; + /* + if (opa != LV_OPA_COVER) { + lv_color_t mix_color; + + mix_color.red = *buf_xy; + mix_color.green = *(buf_xy+1); + mix_color.blue = *(buf_xy+2); + color = lv_color_mix(color, mix_color, opa); + } + */ +} +int time_get_ms() +{ + static struct timeval tv; + gettimeofday(&tv, NULL); + long long time_in_mill = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000; + + return (int) time_in_mill; +} + +SDL_Window * window; +SDL_Renderer * renderer; +SDL_Texture * texture; +static volatile bool sdl_inited = false; +static volatile bool sdl_refr_qry = false; +static volatile bool sdl_quit_qry = false; + +void monitor_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if (x2 < 0 || y2 < 0 || x1 > MONITOR_HOR_RES - 1 + || y1 > MONITOR_VER_RES - 1) { + return; + } + + int32_t y; + uint32_t w = x2 - x1 + 1; + for (y = y1; y <= y2; y++) { + memcpy(&tft_fb[y * MONITOR_HOR_RES + x1], color_p, + w * sizeof(lv_color_t)); + + color_p += w; + } + sdl_refr_qry = true; + + /*IMPORTANT! It must be called to tell the system the flush is ready*/ + +} + +/** + * Fill out the marked area with a color + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * @param color fill color + */ +void monitor_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color) +{ + /*Return if the area is out the screen*/ + if (x2 < 0) + return; + if (y2 < 0) + return; + if (x1 > MONITOR_HOR_RES - 1) + return; + if (y1 > MONITOR_VER_RES - 1) + return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > MONITOR_HOR_RES - 1 ? MONITOR_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > MONITOR_VER_RES - 1 ? MONITOR_VER_RES - 1 : y2; + + int32_t x; + int32_t y; + uint32_t color32 = color.full; //lv_color_to32(color); + + for (x = act_x1; x <= act_x2; x++) { + for (y = act_y1; y <= act_y2; y++) { + tft_fb[y * MONITOR_HOR_RES + x] = color32; + } + } + + sdl_refr_qry = true; +} + +/** + * Put a color map to the marked area + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * @param color_p an array of colors + */ +void monitor_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if (x2 < 0) + return; + if (y2 < 0) + return; + if (x1 > MONITOR_HOR_RES - 1) + return; + if (y1 > MONITOR_VER_RES - 1) + return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > MONITOR_HOR_RES - 1 ? MONITOR_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > MONITOR_VER_RES - 1 ? MONITOR_VER_RES - 1 : y2; + + int32_t x; + int32_t y; + + for (y = act_y1; y <= act_y2; y++) { + for (x = act_x1; x <= act_x2; x++) { + tft_fb[y * MONITOR_HOR_RES + x] = color_p->full; //lv_color_to32(*color_p); + color_p++; + } + + color_p += x2 - act_x2; + } + + sdl_refr_qry = true; +} + +void display_init(void) +{ +} + +void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + monitor_flush(x1, y1, x2, y2, color_p); +} +void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p) +{ + monitor_fill(x1, y1, x2, y2, color_p); +} +void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + monitor_map(x1, y1, x2, y2, color_p); +} + +bool display_input_read(lv_indev_data_t * data) +{ + return mouse_read(data); +} + +void display_deinit(void) +{ + +} + +int monitor_sdl_refr_thread(void * param) +{ + (void) param; + + /*If not OSX initialize SDL in the Thread*/ + monitor_sdl_init(); + /*Run until quit event not arrives*/ + while (sdl_quit_qry == false) { + /*Refresh handling*/ + monitor_sdl_refr_core(); + } + + monitor_sdl_clean_up(); + exit(0); + + return 0; +} + +void monitor_sdl_refr_core(void) +{ + if (sdl_refr_qry != false) { + sdl_refr_qry = false; + + SDL_UpdateTexture(texture, NULL, tft_fb, + MONITOR_HOR_RES * sizeof(uint32_t)); + SDL_RenderClear(renderer); + /*Test: Draw a background to test transparent screens (LV_COLOR_SCREEN_TRANSP)*/ +// SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff); +// SDL_Rect r; +// r.x = 0; r.y = 0; r.w = MONITOR_HOR_RES; r.w = MONITOR_VER_RES; +// SDL_RenderDrawRect(renderer, &r); + /*Update the renderer with the texture containing the rendered image*/ + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + } + + SDL_Event event; + while (SDL_PollEvent(&event)) { +#if USE_MOUSE != 0 + mouse_handler(&event); +#endif + if ((&event)->type == SDL_WINDOWEVENT) { + switch ((&event)->window.event) { +#if SDL_VERSION_ATLEAST(2, 0, 5) + case SDL_WINDOWEVENT_TAKE_FOCUS: +#endif + case SDL_WINDOWEVENT_EXPOSED: + + SDL_UpdateTexture(texture, NULL, tft_fb, + MONITOR_HOR_RES * sizeof(uint32_t)); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + break; + default: + break; + } + } + } + + /*Sleep some time*/ + SDL_Delay(SDL_REFR_PERIOD); + +} +int quit_filter(void * userdata, SDL_Event * event) +{ + (void) userdata; + + if (event->type == SDL_QUIT) { + sdl_quit_qry = true; + } + + return 1; +} + +void monitor_sdl_clean_up(void) +{ + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); +} + +void monitor_sdl_init(void) +{ + /*Initialize the SDL*/ + SDL_Init(SDL_INIT_VIDEO); + + SDL_SetEventFilter(quit_filter, NULL); + + window = SDL_CreateWindow("TFT Simulator", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + MONITOR_HOR_RES * MONITOR_ZOOM, MONITOR_VER_RES * MONITOR_ZOOM, 0); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ + + renderer = SDL_CreateRenderer(window, -1, 0); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, MONITOR_HOR_RES, MONITOR_VER_RES); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + + /*Initialize the frame buffer to gray (77 is an empirical value) */ + memset(tft_fb, 0x44, MONITOR_HOR_RES * MONITOR_VER_RES * sizeof(uint32_t)); + SDL_UpdateTexture(texture, NULL, tft_fb, + MONITOR_HOR_RES * sizeof(uint32_t)); + sdl_refr_qry = true; + sdl_inited = true; +} + +void display_SDL_init() +{ + SDL_CreateThread(monitor_sdl_refr_thread, "sdl_refr", NULL); + while (sdl_inited == false) + ; /*Wait until 'sdl_refr' initializes the SDL*/ +} + diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/lv_conf.h b/samples/littlevgl/vgl-native-ui-app/lv-drivers/lv_conf.h new file mode 100644 index 000000000..76533a8e1 --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/lv_conf.h @@ -0,0 +1,389 @@ +/** + * @file lv_conf.h + * + */ + +#if 1 /*Set it to "1" to enable content*/ + +#ifndef LV_CONF_H +#define LV_CONF_H +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM 1 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +# define LV_MEM_SIZE (64U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (320) +#define LV_VER_RES (240) + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI 100 + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 0 /*1: Enable anti-aliasing*/ + +/*Screen refresh period in milliseconds*/ +#define LV_REFR_PERIOD 30 + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#define LV_VDB_SIZE ((LV_VER_RES * LV_HOR_RES) / 10) + +/* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ + +/* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR 0 + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#define LV_VDB_DOUBLE 0 + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB2_ADR 0 + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/ +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ + +/*Feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW 1 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 0 /*1: Enable file system (might be required for images*/ +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ + +/*Compiler settings*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */ + +/*HAL settings*/ +#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#if LV_TICK_CUSTOM == 1 +#define LV_TICK_CUSTOM_INCLUDE "system_header.h" /*Header for the sys time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (time_get_ms()) /*Expression evaluating to current systime in ms*/ +#endif /*LV_TICK_CUSTOM*/ + +/*Log settings*/ +#define USE_LV_LOG 1 /*Enable/disable the log module*/ +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ + +# define LV_LOG_PRINTF 0 +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 1 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ + +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#define USE_LV_THEME_DEFAULT 1 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#define USE_LV_THEME_ALIEN 0 /*Dark futuristic theme*/ +#define USE_LV_THEME_NIGHT 0 /*Dark elegant theme*/ +#define USE_LV_THEME_MONO 0 /*Mono color theme for monochrome displays*/ +#define USE_LV_THEME_MATERIAL 0 /*Flat theme with bold colors and light shadows*/ +#define USE_LV_THEME_ZEN 0 /*Peaceful, mainly light theme */ +#define USE_LV_THEME_NEMO 0 /*Water-like theme based on the movie "Finding Nemo"*/ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#define USE_LV_FONT_DEJAVU_10 0 +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_10 0 + +#define USE_LV_FONT_DEJAVU_20 4 +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_20 0 + +#define USE_LV_FONT_DEJAVU_30 0 +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_30 0 + +#define USE_LV_FONT_DEJAVU_40 0 +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_40 0 + +#define USE_LV_FONT_MONOSPACE_8 1 + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#define LV_FONT_CUSTOM_DECLARE + +#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#define LV_OBJ_REALIGN 1 /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/ +# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/ +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 + +/*Arc (dependencies: -)*/ +#define USE_LV_ARC 1 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +# if USE_LV_TABVIEW != 0 +# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/*Tileview (dependencies: lv_page) */ +#define USE_LV_TILEVIEW 1 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 1 + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#define USE_LV_GAUGE 1 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 1 + +/*Table (dependencies: lv_label)*/ +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 1 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#define USE_LV_SPINBOX 1 + +/*Calendar (dependencies: -)*/ +#define USE_LV_CALENDAR 1 + +/*Preload (dependencies: lv_arc)*/ +#define USE_LV_PRELOAD 1 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +/*Canvas (dependencies: lv_img)*/ +#define USE_LV_CANVAS 1 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif + +/*Image Button (dependencies: lv_btn*/ +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 1 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +/************************* + * Non-user section + *************************/ +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/ +# define _CRT_SECURE_NO_WARNINGS +#endif + +/*--END OF LV_CONF_H--*/ + +/*Be sure every define has a default value*/ +#include "lvgl/lv_conf_checker.h" + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h b/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h new file mode 100644 index 000000000..9c8b1d238 --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +int time_get_ms(); diff --git a/samples/littlevgl/vgl-native-ui-app/main.c b/samples/littlevgl/vgl-native-ui-app/main.c new file mode 100644 index 000000000..59d0e6b6d --- /dev/null +++ b/samples/littlevgl/vgl-native-ui-app/main.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file main + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lvgl/lvgl.h" +#include "display_indev.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void hal_init(void); +//static int tick_thread(void * data); +//static void memory_monitor(void * param); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +uint32_t count = 0; +char count_str[11] = { 0 }; +lv_obj_t *hello_world_label; +lv_obj_t *count_label; +lv_obj_t * btn1; + +lv_obj_t * label_count1; +int label_count1_value = 0; +char label_count1_str[11] = { 0 }; +static lv_res_t btn_rel_action(lv_obj_t * btn) +{ + label_count1_value++; + sprintf(label_count1_str, "%d", label_count1_value); + lv_label_set_text(label_count1, label_count1_str); + return LV_RES_OK; +} + + +int main() +{ + void display_SDL_init(); + display_SDL_init(); + + /*Initialize LittlevGL*/ + lv_init(); + + /*Initialize the HAL (display, input devices, tick) for LittlevGL*/ + hal_init(); + + hello_world_label = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text(hello_world_label, "Hello world!"); + lv_obj_align(hello_world_label, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + count_label = lv_label_create(lv_scr_act(), NULL); + lv_obj_align(count_label, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + + btn1 = lv_btn_create(lv_scr_act(), NULL); /*Create a button on the currently loaded screen*/ + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, btn_rel_action); /*Set function to be called when the button is released*/ + lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 20); /*Align below the label*/ + + /*Create a label on the button*/ + lv_obj_t * btn_label = lv_label_create(btn1, NULL); + lv_label_set_text(btn_label, "Click ++"); + + label_count1 = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text(label_count1, "0"); + lv_obj_align(label_count1, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + while(1) { + /* Periodically call the lv_task handler. + * It could be done in a timer interrupt or an OS task too.*/ + if ((count % 100) == 0) { + sprintf(count_str, "%d", count/ 100); + lv_label_set_text(count_label, count_str); + } + lv_task_handler(); + ++count; + usleep(10 * 1000); /*Just to let the system breath*/ + } + + return 0; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Initialize the Hardware Abstraction Layer (HAL) for the Littlev graphics library + */ +void display_flush_wrapper(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + display_flush(x1, y1, x2, y2, color_p); + lv_flush_ready(); +} +void display_vdb_write_wrapper(uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa) +{ + display_vdb_write(buf, buf_w, x, y, &color, opa); +} +extern void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p); +extern void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p); +static void hal_init(void) +{ + /* Add a display*/ + lv_disp_drv_t disp_drv; + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + disp_drv.disp_flush = display_flush_wrapper; /*Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing)*/ + disp_drv.disp_fill = display_fill; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/ + disp_drv.disp_map = display_map; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/ +#if LV_VDB_SIZE != 0 + disp_drv.vdb_wr = display_vdb_write_wrapper; +#endif + lv_disp_drv_register(&disp_drv); + + /* Add the mouse as input device + * Use the 'mouse' driver which reads the PC's mouse*/ +// mouse_init(); + lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); /*Basic initialization*/ + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read = display_input_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ + lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv); + +} + diff --git a/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt b/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt new file mode 100644 index 000000000..719f866b4 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt @@ -0,0 +1,93 @@ +cmake_minimum_required (VERSION 2.8) + +project (vgl_wasm_runtime) + +set (TARGET_PLATFORM "linux") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Enable repl mode if want to test spec cases +# add_definitions(-DWASM_ENABLE_REPL) + +if (NOT ("$ENV{VALGRIND}" STREQUAL "YES")) + add_definitions(-DNVALGRIND) +endif () + +# Currently build as 32-bit by default. +set (BUILD_AS_64BIT_SUPPORT "NO") + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) +if (${BUILD_AS_64BIT_SUPPORT} STREQUAL "YES") + # Add -fPIC flag if build as 64-bit + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") +else () + add_definitions (-m32) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") +endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) +SET(CMAKE_BUILD_TYPE Debug) +endif (NOT CMAKE_BUILD_TYPE) +message ("CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) + +if (NOT PLATFORM) +SET(PLATFORM linux) +endif (NOT PLATFORM) +message ("PLATFORM = " ${PLATFORM}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wall -Wno-unused-parameter -Wno-pedantic") + +set(REPO_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) +set(WASM_DIR ${REPO_ROOT_DIR}/core/iwasm) +set(APP_MGR_DIR ${REPO_ROOT_DIR}/core/app-mgr) +set(SHARED_DIR ${REPO_ROOT_DIR}/core/shared-lib) + + +enable_language (ASM) + +include (${WASM_DIR}/runtime/platform/${TARGET_PLATFORM}/platform.cmake) +include (${WASM_DIR}/runtime/utils/utils.cmake) +include (${WASM_DIR}/runtime/vmcore-wasm/vmcore.cmake) +include (${WASM_DIR}/lib/native/base/wasm_lib_base.cmake) +include (${WASM_DIR}/lib/native/libc/wasm_libc.cmake) +include (${WASM_DIR}/lib/native/extension/sensor/wasm_lib_sensor.cmake) +include (${WASM_DIR}/lib/native-interface/native_interface.cmake) +include (${APP_MGR_DIR}/app-manager/app_mgr.cmake) +include (${APP_MGR_DIR}/app-mgr-shared/app_mgr_shared.cmake) +include (${SHARED_DIR}/platform/${TARGET_PLATFORM}/shared_platform.cmake) +include (${SHARED_DIR}/utils/shared_utils.cmake) +include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) +include (${SHARED_DIR}/coap/lib_coap.cmake) + + +include_directories(${SHARED_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/src) + +add_definitions (-DWASM_ENABLE_BASE_LIB) +add_definitions (-Dattr_container_malloc=bh_malloc) +add_definitions (-Dattr_container_free=bh_free) + +add_library (vmlib + ${WASM_PLATFORM_LIB_SOURCE} + ${WASM_UTILS_LIB_SOURCE} + ${VMCORE_LIB_SOURCE} + ${WASM_LIBC_SOURCE} + ${APP_MGR_SOURCE} + ${WASM_LIB_BASE_SOURCE} + ${WASM_LIB_EXT_SOURCE} + ${WASM_LIB_SENSOR_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ) + +add_executable (vgl_wasm_runtime src/platform/${TARGET_PLATFORM}/main.c src/platform/${TARGET_PLATFORM}/iwasm_main.c src/ext_lib_export.c src/platform/${TARGET_PLATFORM}/display_indev.c src/platform/${TARGET_PLATFORM}/mouse.c) + +target_link_libraries (vgl_wasm_runtime vmlib -lm -ldl -lpthread -lSDL2) + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h b/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h new file mode 100644 index 000000000..154071e36 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h @@ -0,0 +1,74 @@ +#ifndef DISPLAY_INDEV_H_ +#define DISPLAY_INDEV_H_ +#include +#include "bh_platform.h" +#include +#include + +#define USE_MOUSE 1 +typedef union { + struct { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; + uint32_t full; +} lv_color32_t; + +typedef lv_color32_t lv_color_t; +typedef uint8_t lv_indev_state_t; +typedef int16_t lv_coord_t; +typedef uint8_t lv_opa_t; +typedef struct { + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct { + union { + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; + +enum { + LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR +}; +enum { + LV_OPA_TRANSP = 0, + LV_OPA_0 = 0, + LV_OPA_10 = 25, + LV_OPA_20 = 51, + LV_OPA_30 = 76, + LV_OPA_40 = 102, + LV_OPA_50 = 127, + LV_OPA_60 = 153, + LV_OPA_70 = 178, + LV_OPA_80 = 204, + LV_OPA_90 = 229, + LV_OPA_100 = 255, + LV_OPA_COVER = 255, +}; +extern void display_init(void); +extern void display_deinit(void); +extern int time_get_ms(); +extern bool touchscreen_read(lv_indev_data_t * data); + +extern void xpt2046_init(void); +extern void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32 color_p_offset); +extern void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p); +extern void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p); +extern bool display_input_read(int32 data_offset); +void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, int32 color_p_offset, lv_opa_t opa); +extern bool mouse_read(lv_indev_data_t * data); +#endif + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c b/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c new file mode 100644 index 000000000..8927493a8 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c @@ -0,0 +1,14 @@ +#include "lib_export.h" +#include "native_interface.h" +#include "display_indev.h" +static NativeSymbol extended_native_symbol_defs[] = { +#include "runtime_sensor.inl" + EXPORT_WASM_API(display_init), + EXPORT_WASM_API(display_input_read), + EXPORT_WASM_API(display_flush), + EXPORT_WASM_API(display_fill), + EXPORT_WASM_API(display_vdb_write), + EXPORT_WASM_API(display_map), + EXPORT_WASM_API(time_get_ms), }; + +#include "ext_lib_export.h" diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c new file mode 100644 index 000000000..6aeaec19c --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "display_indev.h" +#include "SDL2/SDL.h" +#include "sys/time.h" +#include "wasm_export.h" + +#define MONITOR_HOR_RES 320 +#define MONITOR_VER_RES 240 +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif +#define SDL_REFR_PERIOD 50 +void monitor_sdl_init(void); +void monitor_sdl_refr_core(void); +void monitor_sdl_clean_up(void); + +static uint32_t tft_fb[MONITOR_HOR_RES * MONITOR_VER_RES]; + + + +int time_get_ms() +{ + static struct timeval tv; + gettimeofday(&tv, NULL); + long long time_in_mill = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000; + + return (int) time_in_mill; +} + +SDL_Window * window; +SDL_Renderer * renderer; +SDL_Texture * texture; +static volatile bool sdl_inited = false; +static volatile bool sdl_refr_qry = false; +static volatile bool sdl_quit_qry = false; + +void monitor_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if (x2 < 0 || y2 < 0 || x1 > MONITOR_HOR_RES - 1 + || y1 > MONITOR_VER_RES - 1) { + return; + } + + int32_t y; + uint32_t w = x2 - x1 + 1; + for (y = y1; y <= y2; y++) { + memcpy(&tft_fb[y * MONITOR_HOR_RES + x1], color_p, + w * sizeof(lv_color_t)); + + color_p += w; + } + sdl_refr_qry = true; + + /*IMPORTANT! It must be called to tell the system the flush is ready*/ + +} + +/** + * Fill out the marked area with a color + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * @param color fill color + */ +void monitor_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color) +{ + /*Return if the area is out the screen*/ + if (x2 < 0) + return; + if (y2 < 0) + return; + if (x1 > MONITOR_HOR_RES - 1) + return; + if (y1 > MONITOR_VER_RES - 1) + return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > MONITOR_HOR_RES - 1 ? MONITOR_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > MONITOR_VER_RES - 1 ? MONITOR_VER_RES - 1 : y2; + + int32_t x; + int32_t y; + uint32_t color32 = color.full; //lv_color_to32(color); + + for (x = act_x1; x <= act_x2; x++) { + for (y = act_y1; y <= act_y2; y++) { + tft_fb[y * MONITOR_HOR_RES + x] = color32; + } + } + + sdl_refr_qry = true; +} + +/** + * Put a color map to the marked area + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * @param color_p an array of colors + */ +void monitor_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if (x2 < 0) + return; + if (y2 < 0) + return; + if (x1 > MONITOR_HOR_RES - 1) + return; + if (y1 > MONITOR_VER_RES - 1) + return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > MONITOR_HOR_RES - 1 ? MONITOR_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > MONITOR_VER_RES - 1 ? MONITOR_VER_RES - 1 : y2; + + int32_t x; + int32_t y; + + for (y = act_y1; y <= act_y2; y++) { + for (x = act_x1; x <= act_x2; x++) { + tft_fb[y * MONITOR_HOR_RES + x] = color_p->full; //lv_color_to32(*color_p); + color_p++; + } + + color_p += x2 - act_x2; + } + + sdl_refr_qry = true; +} + + +void display_init(void) +{ +} + +void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32 color_p_offset) +{ + + wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); + if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) + return; + lv_color_t * color_p = wasm_runtime_addr_app_to_native(module_inst, + color_p_offset); + + monitor_flush(x1, y1, x2, y2, color_p); +} +void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p) +{ + monitor_fill(x1, y1, x2, y2, color_p); +} +void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + monitor_map(x1, y1, x2, y2, color_p); +} + +bool display_input_read(int32 data_p_offset) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); + if (!wasm_runtime_validate_app_addr(module_inst, data_p_offset, 1)) + return false; + lv_indev_data_t * data = wasm_runtime_addr_app_to_native(module_inst, + data_p_offset); + return mouse_read(data); +} + +void display_deinit(void) +{ + +} + +void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, int32 color_p_offset, lv_opa_t opa) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); + if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) + return; + lv_color_t *color = wasm_runtime_addr_app_to_native(module_inst, + color_p_offset); + + void *buf = wasm_runtime_addr_app_to_native(module_inst, buf_offset); + + unsigned char *buf_xy = buf + 4 * x + 4 * y * buf_w; + lv_color_t * temp = (lv_color_t *) buf_xy; + *temp = *color; + /* + if (opa != LV_OPA_COVER) { + lv_color_t mix_color; + + mix_color.red = *buf_xy; + mix_color.green = *(buf_xy+1); + mix_color.blue = *(buf_xy+2); + color = lv_color_mix(color, mix_color, opa); + } + */ + /* + *buf_xy = color->red; + *(buf_xy + 1) = color->green; + *(buf_xy + 2) = color->blue; + */ +} + +int monitor_sdl_refr_thread(void * param) +{ + (void) param; + + /*If not OSX initialize SDL in the Thread*/ + monitor_sdl_init(); + /*Run until quit event not arrives*/ + while (sdl_quit_qry == false) { + /*Refresh handling*/ + monitor_sdl_refr_core(); + } + + monitor_sdl_clean_up(); + exit(0); + + return 0; +} +extern void mouse_handler(SDL_Event *event); +void monitor_sdl_refr_core(void) +{ + if (sdl_refr_qry != false) { + sdl_refr_qry = false; + + SDL_UpdateTexture(texture, NULL, tft_fb, + MONITOR_HOR_RES * sizeof(uint32_t)); + SDL_RenderClear(renderer); + /*Update the renderer with the texture containing the rendered image*/ + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + } + + SDL_Event event; + while (SDL_PollEvent(&event)) { + + mouse_handler(&event); + + if ((&event)->type == SDL_WINDOWEVENT) { + switch ((&event)->window.event) { +#if SDL_VERSION_ATLEAST(2, 0, 5) + case SDL_WINDOWEVENT_TAKE_FOCUS: +#endif + case SDL_WINDOWEVENT_EXPOSED: + + SDL_UpdateTexture(texture, NULL, tft_fb, + MONITOR_HOR_RES * sizeof(uint32_t)); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + break; + default: + break; + } + } + } + + /*Sleep some time*/ + SDL_Delay(SDL_REFR_PERIOD); + +} +int quit_filter(void * userdata, SDL_Event * event) +{ + (void) userdata; + + if (event->type == SDL_QUIT) { + sdl_quit_qry = true; + } + + return 1; +} + +void monitor_sdl_clean_up(void) +{ + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); +} + +void monitor_sdl_init(void) +{ + /*Initialize the SDL*/ + SDL_Init(SDL_INIT_VIDEO); + + SDL_SetEventFilter(quit_filter, NULL); + + window = SDL_CreateWindow("TFT Simulator", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + MONITOR_HOR_RES * MONITOR_ZOOM, MONITOR_VER_RES * MONITOR_ZOOM, 0); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ + + renderer = SDL_CreateRenderer(window, -1, 0); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, MONITOR_HOR_RES, MONITOR_VER_RES); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + + /*Initialize the frame buffer to gray (77 is an empirical value) */ + memset(tft_fb, 0x44, MONITOR_HOR_RES * MONITOR_VER_RES * sizeof(uint32_t)); + SDL_UpdateTexture(texture, NULL, tft_fb, + MONITOR_HOR_RES * sizeof(uint32_t)); + sdl_refr_qry = true; + sdl_inited = true; +} + +void display_SDL_init() +{ + SDL_CreateThread(monitor_sdl_refr_thread, "sdl_refr", NULL); + while (sdl_inited == false) + ; /*Wait until 'sdl_refr' initializes the SDL*/ +} + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c new file mode 100644 index 000000000..cbb894100 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c @@ -0,0 +1,467 @@ + +#ifndef CONNECTION_UART +#include +#include +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "runtime_lib.h" +#include "runtime_timer.h" +#include "native_interface.h" +#include "app_manager_export.h" +#include "bh_common.h" +#include "bh_queue.h" +#include "bh_thread.h" +#include "bh_memory.h" +#include "runtime_sensor.h" +#include "attr_container.h" +#include "module_wasm_app.h" +#include "wasm_export.h" +#define MAX 2048 + +#ifndef CONNECTION_UART +#define SA struct sockaddr +static char *host_address = "127.0.0.1"; +static int port = 8888; +#else +static char *uart_device = "/dev/ttyS2"; +static int baudrate = B115200; +#endif + +extern void * thread_timer_check(void *); +extern void init_sensor_framework(); +extern int aee_host_msg_callback(void *msg, uint16_t msg_len); + +#ifndef CONNECTION_UART +int listenfd = -1; +int sockfd = -1; +static pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER; +#else +int uartfd = -1; +#endif + +#ifndef CONNECTION_UART +static bool server_mode = false; + +// Function designed for chat between client and server. +void* func(void* arg) +{ + char buff[MAX]; + int n; + struct sockaddr_in servaddr; + + while (1) { + if (sockfd != -1) + close(sockfd); + // socket create and verification + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) { + printf("socket creation failed...\n"); + return NULL; + } else + printf("Socket successfully created..\n"); + bzero(&servaddr, sizeof(servaddr)); + // assign IP, PORT + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr(host_address); + servaddr.sin_port = htons(port); + + // connect the client socket to server socket + if (connect(sockfd, (SA*) &servaddr, sizeof(servaddr)) != 0) { + printf("connection with the server failed...\n"); + sleep(10); + continue; + } else { + printf("connected to the server..\n"); + } + + // infinite loop for chat + for (;;) { + bzero(buff, MAX); + + // read the message from client and copy it in buffer + n = read(sockfd, buff, sizeof(buff)); + // print buffer which contains the client contents + //fprintf(stderr, "recieved %d bytes from host: %s", n, buff); + + // socket disconnected + if (n <= 0) + break; + + aee_host_msg_callback(buff, n); + } + } + + // After chatting close the socket + close(sockfd); +} + +static bool host_init() +{ + return true; +} + +int host_send(void * ctx, const char *buf, int size) +{ + int ret; + + if (pthread_mutex_trylock(&sock_lock) == 0) { + if (sockfd == -1) { + pthread_mutex_unlock(&sock_lock); + return 0; + } + + ret = write(sockfd, buf, size); + + pthread_mutex_unlock(&sock_lock); + return ret; + } + + return -1; +} + +void host_destroy() +{ + if (server_mode) + close(listenfd); + + pthread_mutex_lock(&sock_lock); + close(sockfd); + pthread_mutex_unlock(&sock_lock); +} + +host_interface interface = { + .init = host_init, + .send = host_send, + .destroy = host_destroy + }; + +void* func_server_mode(void* arg) +{ + int clilent; + struct sockaddr_in serv_addr, cli_addr; + int n; + char buff[MAX]; + + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, 0); + + /* First call to socket() function */ + listenfd = socket(AF_INET, SOCK_STREAM, 0); + + if (listenfd < 0) { + perror("ERROR opening socket"); + exit(1); + } + + /* Initialize socket structure */ + bzero((char *) &serv_addr, sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port); + + /* Now bind the host address using bind() call.*/ + if (bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + perror("ERROR on binding"); + exit(1); + } + + listen(listenfd, 5); + clilent = sizeof(cli_addr); + + while (1) { + pthread_mutex_lock(&sock_lock); + + sockfd = accept(listenfd, (struct sockaddr *) &cli_addr, &clilent); + + pthread_mutex_unlock(&sock_lock); + + if (sockfd < 0) { + perror("ERROR on accept"); + exit(1); + } + + printf("connection established!\n"); + + for (;;) { + bzero(buff, MAX); + + // read the message from client and copy it in buffer + n = read(sockfd, buff, sizeof(buff)); + + // socket disconnected + if (n <= 0) { + pthread_mutex_lock(&sock_lock); + close(sockfd); + sockfd = -1; + pthread_mutex_unlock(&sock_lock); + + sleep(2); + break; + } + + aee_host_msg_callback(buff, n); + } + } +} + +#else +static int parse_baudrate(int baud) +{ + switch (baud) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} +static bool uart_init(const char *device, int baudrate, int *fd) +{ + int uart_fd; + struct termios uart_term; + + uart_fd = open(device, O_RDWR | O_NOCTTY); + + if (uart_fd <= 0) + return false; + + memset(&uart_term, 0, sizeof(uart_term)); + uart_term.c_cflag = baudrate | CS8 | CLOCAL | CREAD; + uart_term.c_iflag = IGNPAR; + uart_term.c_oflag = 0; + + /* set noncanonical mode */ + uart_term.c_lflag = 0; + uart_term.c_cc[VTIME] = 30; + uart_term.c_cc[VMIN] = 1; + tcflush(uart_fd, TCIFLUSH); + + if (tcsetattr(uart_fd, TCSANOW, &uart_term) != 0) { + close(uart_fd); + return false; + } + + *fd = uart_fd; + + return true; +} + +static void *func_uart_mode(void *arg) +{ + int n; + char buff[MAX]; + + if (!uart_init(uart_device, baudrate, &uartfd)) { + printf("open uart fail! %s\n", uart_device); + return NULL; + } + + for (;;) { + bzero(buff, MAX); + + n = read(uartfd, buff, sizeof(buff)); + + if (n <= 0) { + close(uartfd); + uartfd = -1; + break; + } + + aee_host_msg_callback(buff, n); + } + + return NULL; +} + +static int uart_send(void * ctx, const char *buf, int size) +{ + int ret; + + ret = write(uartfd, buf, size); + + return ret; +} + +static void uart_destroy() +{ + close(uartfd); +} + +static host_interface interface = { .send = uart_send, .destroy = uart_destroy }; + +#endif + +static char global_heap_buf[1024 * 1024] = { 0 }; + +static void showUsage() +{ +#ifndef CONNECTION_UART + printf("Usage:\n"); + printf("\nWork as TCP server mode:\n"); + printf("\tvgl_wasm_runtime -s|--server_mode -p|--port \n"); + printf("where\n"); + printf("\t represents the port that would be listened on and the default is 8888\n"); + printf("\nWork as TCP client mode:\n"); + printf("\tvgl_wasm_runtime -a|--host_address -p|--port \n"); + printf("where\n"); + printf("\t represents the network address of host and the default is 127.0.0.1\n"); + printf("\t represents the listen port of host and the default is 8888\n"); +#else + printf("Usage:\n"); + printf("\tvgl_wasm_runtime -u -b \n\n"); + printf("where\n"); + printf("\t represents the UART device name and the default is /dev/ttyS2\n"); + printf("\t represents the UART device baudrate and the default is 115200\n"); +#endif +} + +static bool parse_args(int argc, char *argv[]) +{ + int c; + + while (1) { + int optIndex = 0; + static struct option longOpts[] = { +#ifndef CONNECTION_UART + { "server_mode", no_argument, NULL, 's' }, + { "host_address", required_argument, NULL, 'a' }, + { "port", required_argument, NULL, 'p' }, +#else + { "uart", required_argument, NULL, 'u' }, + { "baudrate", required_argument, NULL, 'b' }, +#endif + { "help", required_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "sa:p:u:b:h", longOpts, &optIndex); + if (c == -1) + break; + + switch (c) { +#ifndef CONNECTION_UART + case 's': + server_mode = true; + break; + case 'a': + host_address = optarg; + printf("host address: %s\n", host_address); + break; + case 'p': + port = atoi(optarg); + printf("port: %d\n", port); + break; +#else + case 'u': + uart_device = optarg; + printf("uart device: %s\n", uart_device); + break; + case 'b': + baudrate = parse_baudrate(atoi(optarg)); + printf("uart baudrate: %s\n", optarg); + break; +#endif + case 'h': + showUsage(); + return false; + default: + showUsage(); + return false; + } + } + + return true; +} + +// Driver function +int iwasm_main(int argc, char *argv[]) +{ + korp_thread tid; + + if (!parse_args(argc, argv)) + return -1; + + if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) + != 0) { + printf("Init global heap failed.\n"); + return -1; + } + + if (vm_thread_sys_init() != 0) { + goto fail1; + } + extern void display_SDL_init(); + display_SDL_init(); + + init_sensor_framework(); + + // timer manager + init_wasm_timer(); + +#ifndef CONNECTION_UART + if (server_mode) + vm_thread_create(&tid, func_server_mode, NULL, + BH_APPLET_PRESERVED_STACK_SIZE); + else + vm_thread_create(&tid, func, NULL, BH_APPLET_PRESERVED_STACK_SIZE); +#else + vm_thread_create(&tid, func_uart_mode, NULL, BH_APPLET_PRESERVED_STACK_SIZE); +#endif + + // TODO: + app_manager_startup(&interface); + + fail1: bh_memory_destroy(); + return -1; +} diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c new file mode 100644 index 000000000..24cae03d8 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +extern void iwasm_main(int argc, char *argv[]); +int main(int argc, char *argv[]) +{ + iwasm_main(argc,argv); +} diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c new file mode 100644 index 000000000..f5d071d3c --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c @@ -0,0 +1,96 @@ +/** + * @file mouse.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "display_indev.h" +#include "SDL2/SDL.h" +#if USE_MOUSE != 0 + +/********************* + * DEFINES + *********************/ +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static bool left_button_down = false; +static int16_t last_x = 0; +static int16_t last_y = 0; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the mouse + */ +void mouse_init(void) +{ + +} + +/** + * Get the current position and state of the mouse + * @param data store the mouse data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool mouse_read(lv_indev_data_t * data) +{ + /*Store the collected data*/ + data->point.x = last_x; + data->point.y = last_y; + data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + + return false; +} + +/** + * It will be called from the main SDL thread + */ +void mouse_handler(SDL_Event * event) +{ + switch (event->type) { + case SDL_MOUSEBUTTONUP: + if (event->button.button == SDL_BUTTON_LEFT) + left_button_down = false; + break; + case SDL_MOUSEBUTTONDOWN: + if (event->button.button == SDL_BUTTON_LEFT) { + left_button_down = true; + last_x = event->motion.x / MONITOR_ZOOM; + last_y = event->motion.y / MONITOR_ZOOM; + } + break; + case SDL_MOUSEMOTION: + last_x = event->motion.x / MONITOR_ZOOM; + last_y = event->motion.y / MONITOR_ZOOM; + + break; + } + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c new file mode 100644 index 000000000..5d408b562 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c @@ -0,0 +1,336 @@ +/** + * @file XPT2046.c +*/ +/********************* + * INCLUDES + *********************/ +#include "XPT2046.h" +#include "board_config.h" +#include "stdio.h" +#include +#include "spi.h" + +#include "zephyr.h" +#include "kernel.h" + +#if USE_XPT2046 + +#include + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void xpt2046_corr(int16_t * x, int16_t * y); +static void xpt2046_avg(int16_t * x, int16_t * y); + +/********************** + * STATIC VARIABLES + **********************/ +int16_t avg_buf_x[XPT2046_AVG]; +int16_t avg_buf_y[XPT2046_AVG]; +uint8_t avg_last; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the XPT2046 + */ +struct device *input_dev; + +struct spi_config spi_conf_xpt2046; +struct spi_cs_control xpt2046_cs_ctrl; +struct device *xpt2046_pen_gpio_dev; +static struct gpio_callback gpio_cb; +lv_indev_data_t touch_point; +lv_indev_data_t last_touch_point; + +#define TOUCH_READ_THREAD_STACK_SIZE 4096 +static K_THREAD_STACK_DEFINE(touch_read_thread_stack, TOUCH_READ_THREAD_STACK_SIZE); +static struct k_thread touch_thread_data; +static struct k_sem sem_touch_read; + +K_MUTEX_DEFINE( spi_display_touch_mutex); + +int cnt = 0; +int touch_read_times = 0; +int last_pen_interrupt_time = 0; +void xpt2046_pen_gpio_callback(struct device *port, struct gpio_callback *cb, + u32_t pins) +{ + int i; + cnt++; + if ((k_uptime_get_32() - last_pen_interrupt_time) > 500) { + k_sem_give(&sem_touch_read); + touch_read_times++; + last_pen_interrupt_time = k_uptime_get_32(); + } + +} + +void disable_pen_interrupt() +{ + int ret = 0; + ret = gpio_pin_disable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); + if (ret != 0) { + printf("gpio_pin_configure GPIO_DIR_IN failed\n"); + } +} +void enable_pen_interrupt() +{ + int ret = 0; + ret = gpio_pin_enable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); + if (ret != 0) { + printf("gpio_pin_configure failed\n"); + } +} + +void touch_screen_read_thread() +{ + int i; + bool ret = false; + + for (;;) { + k_sem_take(&sem_touch_read, K_FOREVER); + memset(&last_touch_point, 0, sizeof(lv_indev_data_t)); + memset(&touch_point, 0, sizeof(lv_indev_data_t)); + memset(avg_buf_x, 0, sizeof(avg_buf_x)); + memset(avg_buf_y, 0, sizeof(avg_buf_y)); + k_mutex_lock(&spi_display_touch_mutex, K_FOREVER); + disable_pen_interrupt(); + for (i = 0; i < 100; i++) { + ret = xpt2046_read(&touch_point); + if (ret) { + if ((abs(last_touch_point.point.x - touch_point.point.x) < 4) + && (abs(last_touch_point.point.y - touch_point.point.y) + < 4)) { + break; + } + last_touch_point = touch_point; + + } + } + enable_pen_interrupt(); + k_mutex_unlock(&spi_display_touch_mutex); + } +} + +void xpt2046_init(void) +{ + int ret; + input_dev = device_get_binding(XPT2046_SPI_DEVICE_NAME); + + if (input_dev == NULL) { + printf("device not found. Aborting test."); + return; + } + memset((void *) &touch_point, 0, sizeof(lv_indev_data_t)); + + spi_conf_xpt2046.frequency = XPT2046_SPI_MAX_FREQUENCY; + spi_conf_xpt2046.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); + spi_conf_xpt2046.slave = 0; + spi_conf_xpt2046.cs = NULL; +#ifdef XPT2046_CS_GPIO_CONTROLLER + xpt2046_cs_ctrl.gpio_dev = device_get_binding(XPT2046_CS_GPIO_CONTROLLER); + if (xpt2046_cs_ctrl.gpio_dev == NULL) { + printk("Cannot find %s!\n", XPT2046_CS_GPIO_CONTROLLER); + return; + } + gpio_pin_configure(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, + GPIO_DIR_OUT); + gpio_pin_write(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, 1); + xpt2046_cs_ctrl.gpio_pin = XPT2046_CS_GPIO_PIN; + xpt2046_cs_ctrl.delay = 0; + spi_conf_xpt2046.cs = &xpt2046_cs_ctrl; + +#endif + +#ifdef XPT2046_PEN_GPIO_CONTROLLER + + xpt2046_pen_gpio_dev = device_get_binding(XPT2046_PEN_GPIO_CONTROLLER); + if (!xpt2046_pen_gpio_dev) { + printk("Cannot find %s!\n", XPT2046_PEN_GPIO_CONTROLLER); + return; + } + /* Setup GPIO input */ + ret = gpio_pin_configure(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN, + (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW + | GPIO_INT_DEBOUNCE)); + if (ret) { + printk("Error configuring pin %d!\n", XPT2046_PEN_GPIO_PIN); + } + + gpio_init_callback(&gpio_cb, xpt2046_pen_gpio_callback, + BIT(XPT2046_PEN_GPIO_PIN)); + + ret = gpio_add_callback(xpt2046_pen_gpio_dev, &gpio_cb); + if (ret) { + printk("gpio_add_callback error\n"); + } + ret = gpio_pin_enable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); + if (ret) { + printk("gpio_pin_enable_callback error\n"); + } +#endif + + k_sem_init(&sem_touch_read, 0, 1); + + k_thread_create(&touch_thread_data, touch_read_thread_stack, + TOUCH_READ_THREAD_STACK_SIZE, touch_screen_read_thread, NULL, NULL, NULL, 5, + 0, K_NO_WAIT); + printf("xpt2046_init ok \n"); + +} + +/** + * Get the current position and state of the touchpad + * @param data store the read data here + * @return false: because no ore data to be read + */ +bool xpt2046_read(lv_indev_data_t * data) +{ + static int16_t last_x = 0; + static int16_t last_y = 0; + bool valid = true; + int s32_ret = 0; + uint8_t buf; + + int16_t x = 0; + int16_t y = 0; + + char tx1[16] = { 0 }; + char rx1[16] = { 0 }; + + struct spi_buf tx_buf = { .buf = &tx1, .len = 3 }; + struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf rx_buf = { .buf = &rx1, .len = 3 }; + struct spi_buf_set rx_bufs = { .buffers = &rx_buf, .count = 1 }; + + tx1[0] = CMD_X_READ; + s32_ret = spi_transceive(input_dev, &spi_conf_xpt2046, &tx_bufs, &rx_bufs); + if (s32_ret != 0) { + printf("spi_transceive return failed:%d\n", s32_ret); + } + x = rx1[1] << 8; + x += rx1[2]; + + tx1[0] = CMD_Y_READ; + s32_ret = spi_transceive(input_dev, &spi_conf_xpt2046, &tx_bufs, &rx_bufs); + if (s32_ret != 0) { + printf("spi_transceive return failed:%d\n", s32_ret); + } + y = rx1[1] << 8; + y += rx1[2]; + x = x >> 3; + y = y >> 3; + + xpt2046_corr(&x, &y); + if (y <= 0 || (x > 320)) { + valid = false; + } + + last_x = x; + last_y = y; + + data->point.x = x; + data->point.y = y; + data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; + + return valid; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void xpt2046_corr(int16_t * x, int16_t * y) +{ +#if XPT2046_XY_SWAP != 0 + int16_t swap_tmp; + swap_tmp = *x; + *x = *y; + *y = swap_tmp; +#endif + + if ((*x) > XPT2046_X_MIN) + (*x) -= XPT2046_X_MIN; + else + (*x) = 0; + + if ((*y) > XPT2046_Y_MIN) + (*y) -= XPT2046_Y_MIN; + else + (*y) = 0; + + (*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) + / (XPT2046_X_MAX - XPT2046_X_MIN); + + (*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) + / (XPT2046_Y_MAX - XPT2046_Y_MIN); + +#if XPT2046_X_INV != 0 + (*x) = XPT2046_HOR_RES - (*x); +#endif + +#if XPT2046_Y_INV != 0 + (*y) = XPT2046_VER_RES - (*y); +#endif + +} + +static void xpt2046_avg(int16_t * x, int16_t * y) +{ + /*Shift out the oldest data*/ + uint8_t i; + for (i = XPT2046_AVG - 1; i > 0; i--) { + avg_buf_x[i] = avg_buf_x[i - 1]; + avg_buf_y[i] = avg_buf_y[i - 1]; + } + + /*Insert the new point*/ + avg_buf_x[0] = *x; + avg_buf_y[0] = *y; + if (avg_last < XPT2046_AVG) + avg_last++; + + /*Sum the x and y coordinates*/ + int32_t x_sum = 0; + int32_t y_sum = 0; + for (i = 0; i < avg_last; i++) { + x_sum += avg_buf_x[i]; + y_sum += avg_buf_y[i]; + } + + /*Normalize the sums*/ + (*x) = (int32_t) x_sum / avg_last; + (*y) = (int32_t) y_sum / avg_last; +} + +bool touchscreen_read(lv_indev_data_t * data) +{ + /*Store the collected data*/ + data->point.x = last_touch_point.point.x; + data->point.y = last_touch_point.point.y; + data->state = last_touch_point.state; + + if (last_touch_point.state == LV_INDEV_STATE_PR) { + last_touch_point.state = LV_INDEV_STATE_REL; + } + return false; +} + +#endif diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h new file mode 100644 index 000000000..92aa7e60b --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h @@ -0,0 +1,93 @@ +/** + * @file XPT2046.h + * + */ + +#ifndef XPT2046_H +#define XPT2046_H + +#define USE_XPT2046 1 +#ifndef LV_CONF_INCLUDE_SIMPLE +#define LV_CONF_INCLUDE_SIMPLE +#endif + +# define XPT2046_HOR_RES 320 +# define XPT2046_VER_RES 240 +# define XPT2046_X_MIN 200 +# define XPT2046_Y_MIN 200 +# define XPT2046_X_MAX 3800 +# define XPT2046_Y_MAX 3800 +# define XPT2046_AVG 4 +# define XPT2046_INV 0 + +#define CMD_X_READ 0b10010000 +#define CMD_Y_READ 0b11010000 + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +//#include "lv_drv_conf.h" +#else +//#include "../../lv_drv_conf.h" +#endif + +#if USE_XPT2046 +#include +#include +#include +//#include "lvgl/lv_hal/lv_hal_indev.h" +#include "device.h" +#include "gpio.h" +#if 1 +enum { + LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR +}; +typedef uint8_t lv_indev_state_t; +typedef int16_t lv_coord_t; +typedef struct { + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct { + union { + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void xpt2046_init(void); +bool xpt2046_read(lv_indev_data_t * data); + +/********************** + * MACROS + **********************/ + +#endif /* USE_XPT2046 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* XPT2046_H */ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h new file mode 100644 index 000000000..1233c300a --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __BOARD_CONFIG_H__ +#define __BOARD_CONFIG_H__ +#include "pin_config_stm32.h" + +#endif /* __BOARD_CONFIG_H__ */ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h new file mode 100644 index 000000000..b820b9ce9 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2017 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for display drivers and applications + */ + +#ifndef ZEPHYR_INCLUDE_DISPLAY_H_ +#define ZEPHYR_INCLUDE_DISPLAY_H_ + +/** + * @brief Display Interface + * @defgroup display_interface Display Interface + * @ingroup display_interfaces + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum display_pixel_format { + PIXEL_FORMAT_RGB_888 = BIT(0), PIXEL_FORMAT_MONO01 = BIT(1), /* 0=Black 1=White */ + PIXEL_FORMAT_MONO10 = BIT(2), /* 1=Black 0=White */ + PIXEL_FORMAT_ARGB_8888 = BIT(3), PIXEL_FORMAT_RGB_565 = BIT(4), +}; + +enum display_screen_info { + /** + * If selected, one octet represents 8 pixels ordered vertically, + * otherwise ordered horizontally. + */ + SCREEN_INFO_MONO_VTILED = BIT(0), + /** + * If selected, the MSB represents the first pixel, + * otherwise MSB represents the last pixel. + */ + SCREEN_INFO_MONO_MSB_FIRST = BIT(1), + /** + * Electrophoretic Display. + */ + SCREEN_INFO_EPD = BIT(2), + /** + * Screen has two alternating ram buffers + */ + SCREEN_INFO_DOUBLE_BUFFER = BIT(3), +}; + +/** + * @enum display_orientation + * @brief Enumeration with possible display orientation + * + */ +enum display_orientation { + DISPLAY_ORIENTATION_NORMAL, + DISPLAY_ORIENTATION_ROTATED_90, + DISPLAY_ORIENTATION_ROTATED_180, + DISPLAY_ORIENTATION_ROTATED_270, +}; + +/** + * @struct display_capabilities + * @brief Structure holding display capabilities + * + * @var u16_t display_capabilities::x_resolution + * Display resolution in the X direction + * + * @var u16_t display_capabilities::y_resolution + * Display resolution in the Y direction + * + * @var u32_t display_capabilities::supported_pixel_formats + * Bitwise or of pixel formats supported by the display + * + * @var u32_t display_capabilities::screen_info + * Information about display panel + * + * @var enum display_pixel_format display_capabilities::current_pixel_format + * Currently active pixel format for the display + * + * @var enum display_orientation display_capabilities::current_orientation + * Current display orientation + * + */ +struct display_capabilities { + u16_t x_resolution; + u16_t y_resolution; + u32_t supported_pixel_formats; + u32_t screen_info; + enum display_pixel_format current_pixel_format; + enum display_orientation current_orientation; +}; + +/** + * @struct display_buffer_descriptor + * @brief Structure to describe display data buffer layout + * + * @var u32_t display_buffer_descriptor::buf_size + * Data buffer size in bytes + * + * @var u16_t display_buffer_descriptor::width + * Data buffer row width in pixels + * + * @var u16_t display_buffer_descriptor::height + * Data buffer column height in pixels + * + * @var u16_t display_buffer_descriptor::pitch + * Number of pixels between consecutive rows in the data buffer + * + */ +struct display_buffer_descriptor { + u32_t buf_size; + u16_t width; + u16_t height; + u16_t pitch; +}; + +/** + * @typedef display_blanking_on_api + * @brief Callback API to turn on display blanking + * See display_blanking_on() for argument description + */ +typedef int (*display_blanking_on_api)(const struct device *dev); + +/** + * @typedef display_blanking_off_api + * @brief Callback API to turn off display blanking + * See display_blanking_off() for argument description + */ +typedef int (*display_blanking_off_api)(const struct device *dev); + +/** + * @typedef display_write_api + * @brief Callback API for writing data to the display + * See display_write() for argument description + */ +typedef int (*display_write_api)(const struct device *dev, const u16_t x, + const u16_t y, const struct display_buffer_descriptor *desc, + const void *buf); + +/** + * @typedef display_read_api + * @brief Callback API for reading data from the display + * See display_read() for argument description + */ +typedef int (*display_read_api)(const struct device *dev, const u16_t x, + const u16_t y, const struct display_buffer_descriptor *desc, void *buf); + +/** + * @typedef display_get_framebuffer_api + * @brief Callback API to get framebuffer pointer + * See display_get_framebuffer() for argument description + */ +typedef void *(*display_get_framebuffer_api)(const struct device *dev); + +/** + * @typedef display_set_brightness_api + * @brief Callback API to set display brightness + * See display_set_brightness() for argument description + */ +typedef int (*display_set_brightness_api)(const struct device *dev, + const u8_t brightness); + +/** + * @typedef display_set_contrast_api + * @brief Callback API to set display contrast + * See display_set_contrast() for argument description + */ +typedef int (*display_set_contrast_api)(const struct device *dev, + const u8_t contrast); + +/** + * @typedef display_get_capabilities_api + * @brief Callback API to get display capabilities + * See display_get_capabilities() for argument description + */ +typedef void (*display_get_capabilities_api)(const struct device *dev, + struct display_capabilities * capabilities); + +/** + * @typedef display_set_pixel_format_api + * @brief Callback API to set pixel format used by the display + * See display_set_pixel_format() for argument description + */ +typedef int (*display_set_pixel_format_api)(const struct device *dev, + const enum display_pixel_format pixel_format); + +/** + * @typedef display_set_orientation_api + * @brief Callback API to set orientation used by the display + * See display_set_orientation() for argument description + */ +typedef int (*display_set_orientation_api)(const struct device *dev, + const enum display_orientation orientation); + +/** + * @brief Display driver API + * API which a display driver should expose + */ +struct display_driver_api { + display_blanking_on_api blanking_on; + display_blanking_off_api blanking_off; + display_write_api write; + display_read_api read; + display_get_framebuffer_api get_framebuffer; + display_set_brightness_api set_brightness; + display_set_contrast_api set_contrast; + display_get_capabilities_api get_capabilities; + display_set_pixel_format_api set_pixel_format; + display_set_orientation_api set_orientation; +}; +extern struct ili9340_data ili9340_data1; +extern struct display_driver_api ili9340_api1; +/** + * @brief Write data to display + * + * @param dev Pointer to device structure + * @param x x Coordinate of the upper left corner where to write the buffer + * @param y y Coordinate of the upper left corner where to write the buffer + * @param desc Pointer to a structure describing the buffer layout + * @param buf Pointer to buffer array + * + * @retval 0 on success else negative errno code. + */ +static inline int display_write(const struct device *dev, const u16_t x, + const u16_t y, const struct display_buffer_descriptor *desc, + const void *buf) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->write(dev, x, y, desc, buf); +} + +/** + * @brief Read data from display + * + * @param dev Pointer to device structure + * @param x x Coordinate of the upper left corner where to read from + * @param y y Coordinate of the upper left corner where to read from + * @param desc Pointer to a structure describing the buffer layout + * @param buf Pointer to buffer array + * + * @retval 0 on success else negative errno code. + */ +static inline int display_read(const struct device *dev, const u16_t x, + const u16_t y, const struct display_buffer_descriptor *desc, void *buf) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->read(dev, x, y, desc, buf); +} + +/** + * @brief Get pointer to framebuffer for direct access + * + * @param dev Pointer to device structure + * + * @retval Pointer to frame buffer or NULL if direct framebuffer access + * is not supported + * + */ +static inline void *display_get_framebuffer(const struct device *dev) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->get_framebuffer(dev); +} + +/** + * @brief Turn display blanking on + * + * @param dev Pointer to device structure + * + * @retval 0 on success else negative errno code. + */ +static inline int display_blanking_on(const struct device *dev) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->blanking_on(dev); +} + +/** + * @brief Turn display blanking off + * + * @param dev Pointer to device structure + * + * @retval 0 on success else negative errno code. + */ +static inline int display_blanking_off(const struct device *dev) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->blanking_off(dev); +} + +/** + * @brief Set the brightness of the display + * + * Set the brightness of the display in steps of 1/256, where 255 is full + * brightness and 0 is minimal. + * + * @param dev Pointer to device structure + * @param brightness Brightness in steps of 1/256 + * + * @retval 0 on success else negative errno code. + */ +static inline int display_set_brightness(const struct device *dev, + u8_t brightness) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->set_brightness(dev, brightness); +} + +/** + * @brief Set the contrast of the display + * + * Set the contrast of the display in steps of 1/256, where 255 is maximum + * difference and 0 is minimal. + * + * @param dev Pointer to device structure + * @param contrast Contrast in steps of 1/256 + * + * @retval 0 on success else negative errno code. + */ +static inline int display_set_contrast(const struct device *dev, u8_t contrast) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->set_contrast(dev, contrast); +} + +/** + * @brief Get display capabilities + * + * @param dev Pointer to device structure + * @param capabilities Pointer to capabilities structure to populate + */ +static inline void display_get_capabilities(const struct device *dev, + struct display_capabilities * capabilities) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + api->get_capabilities(dev, capabilities); +} + +/** + * @brief Set pixel format used by the display + * + * @param dev Pointer to device structure + * @param pixel_format Pixel format to be used by display + * + * @retval 0 on success else negative errno code. + */ +static inline int display_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->set_pixel_format(dev, pixel_format); +} + +/** + * @brief Set display orientation + * + * @param dev Pointer to device structure + * @param orientation Orientation to be used by display + * + * @retval 0 on success else negative errno code. + */ +static inline int display_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + struct display_driver_api *api = &ili9340_api1; + //(struct display_driver_api *)dev->driver_api; + + return api->set_orientation(dev, orientation); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DISPLAY_H_*/ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c new file mode 100644 index 000000000..07e77ffce --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2017 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "display_ili9340.h" +#include + +//#define LOG_LEVEL CONFIG_DISPLAY_LOG_LEVEL +//#include +//LOG_MODULE_REGISTER(display_ili9340); +#define LOG_ERR printf +#define LOG_DBG printf +#define LOG_WRN printf + +#include +#include +#include +#include + +struct ili9340_data { + struct device *reset_gpio; + struct device *command_data_gpio; + struct device *spi_dev; + struct spi_config spi_config; +#ifdef DT_ILITEK_ILI9340_0_CS_GPIO_CONTROLLER +struct spi_cs_control cs_ctrl; +#endif +}; + +struct ili9340_data ili9340_data1; + +#define ILI9340_CMD_DATA_PIN_COMMAND 0 +#define ILI9340_CMD_DATA_PIN_DATA 1 + +static void ili9340_exit_sleep(struct ili9340_data *data) +{ + ili9340_transmit(data, ILI9340_CMD_EXIT_SLEEP, NULL, 0); + //k_sleep(120); +} + +int ili9340_init() +{ + struct ili9340_data *data = &ili9340_data1; + printf("Initializing display driver\n"); + data->spi_dev = device_get_binding(DT_ILITEK_ILI9340_0_BUS_NAME); + if (data->spi_dev == NULL) { + return -EPERM; + } + data->spi_config.frequency = DT_ILITEK_ILI9340_0_SPI_MAX_FREQUENCY; + data->spi_config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); //SPI_OP_MODE_MASTER | SPI_WORD_SET(8); + data->spi_config.slave = DT_ILITEK_ILI9340_0_BASE_ADDRESS; + +#ifdef DT_ILITEK_ILI9340_0_CS_GPIO_CONTROLLER + data->cs_ctrl.gpio_dev = + device_get_binding(DT_ILITEK_ILI9340_0_CS_GPIO_CONTROLLER); + data->cs_ctrl.gpio_pin = DT_ILITEK_ILI9340_0_CS_GPIO_PIN; + data->cs_ctrl.delay = 0; + data->spi_config.cs = &(data->cs_ctrl); +#else + data->spi_config.cs = NULL; +#endif + data->reset_gpio = device_get_binding( + DT_ILITEK_ILI9340_0_RESET_GPIOS_CONTROLLER); + if (data->reset_gpio == NULL) { + return -EPERM; + } + + gpio_pin_configure(data->reset_gpio, DT_ILITEK_ILI9340_0_RESET_GPIOS_PIN, + GPIO_DIR_OUT); + + data->command_data_gpio = device_get_binding( + DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_CONTROLLER); + if (data->command_data_gpio == NULL) { + return -EPERM; + } + + gpio_pin_configure(data->command_data_gpio, + DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_PIN, GPIO_DIR_OUT); + + LOG_DBG("Resetting display driver"); + gpio_pin_write(data->reset_gpio, DT_ILITEK_ILI9340_0_RESET_GPIOS_PIN, 1); + k_sleep(1); + gpio_pin_write(data->reset_gpio, DT_ILITEK_ILI9340_0_RESET_GPIOS_PIN, 0); + k_sleep(1); + gpio_pin_write(data->reset_gpio, DT_ILITEK_ILI9340_0_RESET_GPIOS_PIN, 1); + k_sleep(5); + + LOG_DBG("Initializing LCD\n"); + ili9340_lcd_init(data); + + LOG_DBG("Exiting sleep mode\n"); + ili9340_exit_sleep(data); + + return 0; +} + +static void ili9340_set_mem_area(struct ili9340_data *data, const u16_t x, + const u16_t y, const u16_t w, const u16_t h) +{ + u16_t spi_data[2]; + + spi_data[0] = sys_cpu_to_be16(x); + spi_data[1] = sys_cpu_to_be16(x + w - 1); + ili9340_transmit(data, ILI9340_CMD_COLUMN_ADDR, &spi_data[0], 4); + + spi_data[0] = sys_cpu_to_be16(y); + spi_data[1] = sys_cpu_to_be16(y + h - 1); + ili9340_transmit(data, ILI9340_CMD_PAGE_ADDR, &spi_data[0], 4); +} + +static int ili9340_write(const struct device *dev, const u16_t x, const u16_t y, + const struct display_buffer_descriptor *desc, const void *buf) +{ + struct ili9340_data *data = (struct ili9340_data *) &ili9340_data1; + const u8_t *write_data_start = (u8_t *) buf; + struct spi_buf tx_buf; + struct spi_buf_set tx_bufs; + u16_t write_cnt; + u16_t nbr_of_writes; + u16_t write_h; + + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width"); + __ASSERT((3 * desc->pitch * desc->height) <= desc->buf_size, + "Input buffer to small"); + ili9340_set_mem_area(data, x, y, desc->width, desc->height); + + if (desc->pitch > desc->width) { + write_h = 1U; + nbr_of_writes = desc->height; + } else { + write_h = desc->height; + nbr_of_writes = 1U; + } + ili9340_transmit(data, ILI9340_CMD_MEM_WRITE, (void *) write_data_start, + 3 * desc->width * write_h); + + tx_bufs.buffers = &tx_buf; + tx_bufs.count = 1; + + write_data_start += (3 * desc->pitch); + for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { + tx_buf.buf = (void *) write_data_start; + tx_buf.len = 3 * desc->width * write_h; + spi_transceive(data->spi_dev, &data->spi_config, &tx_bufs, NULL); + write_data_start += (3 * desc->pitch); + } + + return 0; +} + +static int ili9340_read(const struct device *dev, const u16_t x, const u16_t y, + const struct display_buffer_descriptor *desc, void *buf) +{ + LOG_ERR("Reading not supported"); + return -ENOTSUP; +} + +static void *ili9340_get_framebuffer(const struct device *dev) +{ + LOG_ERR("Direct framebuffer access not supported"); + return NULL; +} + +static int ili9340_display_blanking_off(const struct device *dev) +{ + struct ili9340_data *data = (struct ili9340_data *) dev->driver_data; + + LOG_DBG("Turning display blanking off"); + ili9340_transmit(data, ILI9340_CMD_DISPLAY_ON, NULL, 0); + return 0; +} + +static int ili9340_display_blanking_on(const struct device *dev) +{ + struct ili9340_data *data = (struct ili9340_data *) dev->driver_data; + + LOG_DBG("Turning display blanking on"); + ili9340_transmit(data, ILI9340_CMD_DISPLAY_OFF, NULL, 0); + return 0; +} + +static int ili9340_set_brightness(const struct device *dev, + const u8_t brightness) +{ + LOG_WRN("Set brightness not implemented"); + return -ENOTSUP; +} + +static int ili9340_set_contrast(const struct device *dev, const u8_t contrast) +{ + LOG_ERR("Set contrast not supported"); + return -ENOTSUP; +} + +static int ili9340_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + if (pixel_format == PIXEL_FORMAT_RGB_888) { + return 0; +} + LOG_ERR("Pixel format change not implemented"); + return -ENOTSUP; +} + +static int ili9340_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ +if (orientation == DISPLAY_ORIENTATION_NORMAL) { + return 0; +} +LOG_ERR("Changing display orientation not implemented"); + return -ENOTSUP; +} + +static void ili9340_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = 320; + capabilities->y_resolution = 240; + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_888; + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; + capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; +} + +void ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, + size_t tx_len) +{ + int i; + char * buf1 = tx_data; + data = (struct ili9340_data *) &ili9340_data1; + struct spi_buf tx_buf = { .buf = &cmd, .len = 1 }; + struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + + gpio_pin_write(data->command_data_gpio, DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_PIN, + ILI9340_CMD_DATA_PIN_COMMAND); + spi_transceive(data->spi_dev, &data->spi_config, &tx_bufs, NULL); + if (tx_data != NULL) { + tx_buf.buf = tx_data; + tx_buf.len = tx_len; + gpio_pin_write(data->command_data_gpio, + DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_PIN, + ILI9340_CMD_DATA_PIN_DATA); + spi_transceive(data->spi_dev, &data->spi_config, &tx_bufs, NULL); + } +} + +struct display_driver_api ili9340_api1 = + { .blanking_on = ili9340_display_blanking_on, .blanking_off = + ili9340_display_blanking_off, .write = ili9340_write, .read = + ili9340_read, .get_framebuffer = ili9340_get_framebuffer, + .set_brightness = ili9340_set_brightness, .set_contrast = + ili9340_set_contrast, .get_capabilities = + ili9340_get_capabilities, .set_pixel_format = + ili9340_set_pixel_format, .set_orientation = + ili9340_set_orientation, }; + +/* + DEVICE_AND_API_INIT(ili9340, DT_ILITEK_ILI9340_0_LABEL, &ili9340_init, + &ili9340_data, NULL, APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY, &ili9340_api); + */ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h new file mode 100644 index 000000000..8aab97a65 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ +#define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ +#include "board_config.h" +#include +#include + +#define ILI9340_CMD_ENTER_SLEEP 0x10 +#define ILI9340_CMD_EXIT_SLEEP 0x11 +#define ILI9340_CMD_GAMMA_SET 0x26 +#define ILI9340_CMD_DISPLAY_OFF 0x28 +#define ILI9340_CMD_DISPLAY_ON 0x29 +#define ILI9340_CMD_COLUMN_ADDR 0x2a +#define ILI9340_CMD_PAGE_ADDR 0x2b +#define ILI9340_CMD_MEM_WRITE 0x2c +#define ILI9340_CMD_MEM_ACCESS_CTRL 0x36 +#define ILI9340_CMD_PIXEL_FORMAT_SET 0x3A +#define ILI9340_CMD_FRAME_CTRL_NORMAL_MODE 0xB1 +#define ILI9340_CMD_DISPLAY_FUNCTION_CTRL 0xB6 +#define ILI9340_CMD_POWER_CTRL_1 0xC0 +#define ILI9340_CMD_POWER_CTRL_2 0xC1 +#define ILI9340_CMD_VCOM_CTRL_1 0xC5 +#define ILI9340_CMD_VCOM_CTRL_2 0xC7 +#define ILI9340_CMD_POSITVE_GAMMA_CORRECTION 0xE0 +#define ILI9340_CMD_NEGATIVE_GAMMA_CORRECTION 0xE1 + +#define ILI9340_DATA_MEM_ACCESS_CTRL_MY 0x80 +#define ILI9340_DATA_MEM_ACCESS_CTRL_MX 0x40 +#define ILI9340_DATA_MEM_ACCESS_CTRL_MV 0x20 +#define ILI9340_DATA_MEM_ACCESS_CTRL_ML 0x10 +#define ILI9340_DATA_MEM_ACCESS_CTRL_BGR 0x08 +#define ILI9340_DATA_MEM_ACCESS_CTRL_MH 0x04 + +#define ILI9340_DATA_PIXEL_FORMAT_RGB_18_BIT 0x60 +#define ILI9340_DATA_PIXEL_FORMAT_RGB_16_BIT 0x50 +#define ILI9340_DATA_PIXEL_FORMAT_MCU_18_BIT 0x06 +#define ILI9340_DATA_PIXEL_FORMAT_MCU_16_BIT 0x05 + +struct ili9340_data; + +/** + * Send data to ILI9340 display controller + * + * @param data Device data structure + * @param cmd Command to send to display controller + * @param tx_data Data to transmit to the display controller + * In case no data should be transmitted pass a NULL pointer + * @param tx_len Number of bytes in tx_data buffer + * + */ +void ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, + size_t tx_len); + +/** + * Perform LCD specific initialization + * + * @param data Device data structure + */ +void ili9340_lcd_init(struct ili9340_data *data); + +#define DT_ILITEK_ILI9340_0_LABEL "DISPLAY" +#define CONFIG_DISPLAY_LOG_LEVEL 0 + +#endif /* ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ */ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c new file mode 100644 index 000000000..a8581a72d --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "display_ili9340.h" + +void ili9340_lcd_init(struct ili9340_data *data) +{ + u8_t tx_data[15]; + + tx_data[0] = 0x23; + ili9340_transmit(data, ILI9340_CMD_POWER_CTRL_1, tx_data, 1); + + tx_data[0] = 0x10; + ili9340_transmit(data, ILI9340_CMD_POWER_CTRL_2, tx_data, 1); + + tx_data[0] = 0x3e; + tx_data[1] = 0x28; + ili9340_transmit(data, ILI9340_CMD_VCOM_CTRL_1, tx_data, 2); + + tx_data[0] = 0x86; + ili9340_transmit(data, ILI9340_CMD_VCOM_CTRL_2, tx_data, 1); + + tx_data[0] = + ILI9340_DATA_MEM_ACCESS_CTRL_MV | ILI9340_DATA_MEM_ACCESS_CTRL_BGR; + ili9340_transmit(data, ILI9340_CMD_MEM_ACCESS_CTRL, tx_data, 1); + + tx_data[0] = ILI9340_DATA_PIXEL_FORMAT_MCU_18_BIT | + ILI9340_DATA_PIXEL_FORMAT_RGB_18_BIT; + ili9340_transmit(data, ILI9340_CMD_PIXEL_FORMAT_SET, tx_data, 1); + + tx_data[0] = 0x00; + tx_data[1] = 0x18; + ili9340_transmit(data, ILI9340_CMD_FRAME_CTRL_NORMAL_MODE, tx_data, 2); + + tx_data[0] = 0x08; + tx_data[1] = 0x82; + tx_data[2] = 0x27; + ili9340_transmit(data, ILI9340_CMD_DISPLAY_FUNCTION_CTRL, tx_data, 3); + + tx_data[0] = 0x01; + ili9340_transmit(data, ILI9340_CMD_GAMMA_SET, tx_data, 1); + + tx_data[0] = 0x0F; + tx_data[1] = 0x31; + tx_data[2] = 0x2B; + tx_data[3] = 0x0C; + tx_data[4] = 0x0E; + tx_data[5] = 0x08; + tx_data[6] = 0x4E; + tx_data[7] = 0xF1; + tx_data[8] = 0x37; + tx_data[9] = 0x07; + tx_data[10] = 0x10; + tx_data[11] = 0x03; + tx_data[12] = 0x0E; + tx_data[13] = 0x09; + tx_data[14] = 0x00; + ili9340_transmit(data, ILI9340_CMD_POSITVE_GAMMA_CORRECTION, tx_data, 15); + + tx_data[0] = 0x00; + tx_data[1] = 0x0E; + tx_data[2] = 0x14; + tx_data[3] = 0x03; + tx_data[4] = 0x11; + tx_data[5] = 0x07; + tx_data[6] = 0x31; + tx_data[7] = 0xC1; + tx_data[8] = 0x48; + tx_data[9] = 0x08; + tx_data[10] = 0x0F; + tx_data[11] = 0x0C; + tx_data[12] = 0x31; + tx_data[13] = 0x36; + tx_data[14] = 0x0F; + ili9340_transmit(data, ILI9340_CMD_NEGATIVE_GAMMA_CORRECTION, tx_data, 15); +} diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c new file mode 100644 index 000000000..1ed562c02 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "display_indev.h" +#include "display.h" +#include "wasm_export.h" + +#define MONITOR_HOR_RES 320 +#define MONITOR_VER_RES 240 +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif +int lcd_initialized = 0; +void display_init(void) +{ + if (lcd_initialized != 0) { + return; + } + lcd_initialized = 1; + xpt2046_init(); + ili9340_init(); + display_blanking_off(NULL); +} + +void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32 color_p_offset) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); + if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) + return; + lv_color_t * color_p = wasm_runtime_addr_app_to_native(module_inst, + color_p_offset); + + u16_t w = x2 - x1 + 1; + u16_t h = y2 - y1 + 1; + struct display_buffer_descriptor desc; + + desc.buf_size = 3 * w * h; + desc.width = w; + desc.pitch = w; + desc.height = h; + display_write(NULL, x1, y1, &desc, (void *) color_p); + + /*lv_flush_ready();*/ +} +void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p) +{ + +} +void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + +} + +bool display_input_read(int32 data_p_offset) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); + if (!wasm_runtime_validate_app_addr(module_inst, data_p_offset, 1)) + return false; + lv_indev_data_t * data = wasm_runtime_addr_app_to_native(module_inst, + data_p_offset); + + return touchscreen_read(data); + +} + +void display_deinit(void) +{ + +} + +void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, int32 color_p_offset, lv_opa_t opa) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); + if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) + return; + lv_color_t *color = wasm_runtime_addr_app_to_native(module_inst, + color_p_offset); + + void *buf = wasm_runtime_addr_app_to_native(module_inst, buf_offset); + + u8_t *buf_xy = buf + 3 * x + 3 * y * buf_w; + /* + if (opa != LV_OPA_COVER) { + lv_color_t mix_color; + + mix_color.red = *buf_xy; + mix_color.green = *(buf_xy+1); + mix_color.blue = *(buf_xy+2); + color = lv_color_mix(color, mix_color, opa); + } + */ + *buf_xy = color->red; + *(buf_xy + 1) = color->green; + *(buf_xy + 2) = color->blue; +} + +int time_get_ms() +{ + return k_uptime_get_32(); +} + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c new file mode 100644 index 000000000..23be02a56 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "bh_platform.h" +#include "runtime_lib.h" +#include "native_interface.h" +#include "app-manager-export.h" +#include "board_config.h" +#include "bh_common.h" +#include "bh_queue.h" +#include "bh_thread.h" +#include "bh_memory.h" +#include "runtime_sensor.h" +#include "attr-container.h" +#include "module_wasm_app.h" +#include "wasm_export.h" + +extern void * thread_timer_check(void *); +extern void init_sensor_framework(); +extern int aee_host_msg_callback(void *msg, uint16_t msg_len); + +#include +#include +#include + +int uart_char_cnt = 0; + +static void uart_irq_callback(struct device *dev) +{ + unsigned char ch; + int size = 0; + + while (uart_poll_in(dev, &ch) == 0) { + + uart_char_cnt++; + aee_host_msg_callback(&ch, 1); + } +} + +struct device *uart_dev = NULL; + +static bool host_init() +{ + uart_dev = device_get_binding(HOST_DEVICE_COMM_UART_NAME); + if (!uart_dev) { + printf("UART: Device driver not found.\n"); + return; + } + uart_irq_rx_enable(uart_dev); + uart_irq_callback_set(uart_dev, uart_irq_callback); + return true; +} + +int host_send(void * ctx, const char *buf, int size) +{ + for (int i = 0; i < size; i++) + uart_poll_out(uart_dev, buf[i]); + + return size; +} + +void host_destroy() +{ + +} + + +#define DEFAULT_THREAD_STACKSIZE (8 * 1024) + +host_interface interface = { .init = host_init, .send = + host_send, .destroy = host_destroy }; +timer_ctx_t timer_ctx; +static char global_heap_buf[ 498*1024] = { 0 }; +extern void display_init(void); +int iwasm_main() +{ + korp_thread tid, tm_tid; + + host_init(); + + if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) + != 0) { + printf("Init global heap failed.\n"); + return -1; + } + + if (vm_thread_sys_init() != 0) { + goto fail1; + } + + display_init(); + + // timer manager + init_wasm_timer(); + + // TODO: + app_manager_startup(&interface); + + fail1: bh_memory_destroy(); + return -1; +} diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c new file mode 100644 index 000000000..a4313df91 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "wasm_assert.h" +#include "wasm_log.h" +#include "wasm_platform.h" +#include "wasm_platform_log.h" +#include "wasm_thread.h" +#include "wasm_export.h" +#include "wasm_memory.h" +#include "bh_memory.h" +extern void display_init(void); +extern int iwasm_main(); +void main(void) +{ + display_init(); + iwasm_main(); + for(;;){ + k_sleep(1000); + } +} + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h new file mode 100644 index 000000000..5381b72db --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __PIN_CONFIG_JLF_H__ +#define __PIN_CONFIG_JLF_H__ + +#define DT_ILITEK_ILI9340_0_BUS_NAME "SPI_2" +#define DT_ILITEK_ILI9340_0_SPI_MAX_FREQUENCY 10*1000 + +#define DT_ILITEK_ILI9340_0_BASE_ADDRESS 1 +#define DT_ILITEK_ILI9340_0_RESET_GPIOS_CONTROLLER "GPIO_0" +#define DT_ILITEK_ILI9340_0_RESET_GPIOS_PIN 5 +#define DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_CONTROLLER "GPIO_0" +#define DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_PIN 4 + +#define XPT2046_SPI_DEVICE_NAME "SPI_2" +#define XPT2046_SPI_MAX_FREQUENCY 10*1000 +#define XPT2046_CS_GPIO_CONTROLLER "GPIO_0" +#define XPT2046_CS_GPIO_PIN 6 + +#define XPT2046_PEN_GPIO_CONTROLLER "GPIO_0" +#define XPT2046_PEN_GPIO_PIN 7 + +#define HOST_DEVICE_COMM_UART_NAME "UART_1" +#endif /* __PIN_CONFIG_JLF_H__ */ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h new file mode 100644 index 000000000..0ab295eb0 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __PIN_CONFIG_STM32_H__ +#define __PIN_CONFIG_STM32_H__ + +#define DT_ILITEK_ILI9340_0_BUS_NAME "SPI_1" +#define DT_ILITEK_ILI9340_0_SPI_MAX_FREQUENCY 24*1000*1000 + +#define DT_ILITEK_ILI9340_0_BASE_ADDRESS 1 +#define DT_ILITEK_ILI9340_0_RESET_GPIOS_CONTROLLER "GPIOC" +#define DT_ILITEK_ILI9340_0_RESET_GPIOS_PIN 12 +#define DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_CONTROLLER "GPIOC" +#define DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_PIN 11 + +#define DT_ILITEK_ILI9340_0_CS_GPIO_CONTROLLER "GPIOC" +#define DT_ILITEK_ILI9340_0_CS_GPIO_PIN 10 + +#define XPT2046_SPI_DEVICE_NAME "SPI_1" +#define XPT2046_SPI_MAX_FREQUENCY 12*1000*1000 +#define XPT2046_CS_GPIO_CONTROLLER "GPIOD" +#define XPT2046_CS_GPIO_PIN 0 + +#define XPT2046_PEN_GPIO_CONTROLLER "GPIOD" +#define XPT2046_PEN_GPIO_PIN 1 + +#define HOST_DEVICE_COMM_UART_NAME "UART_6" + +#endif /* __PIN_CONFIG_STM32_H__ */ diff --git a/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt new file mode 100644 index 000000000..a3b186ddc --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/CMakeLists.txt @@ -0,0 +1,118 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.8.2) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +enable_language (ASM) + +zephyr_compile_definitions (-DNVALGRIND + -D__JLF__ + -D__ZEPHYR__ + -DWASM_ENABLE_BASE_LIB + -Dattr_container_malloc=bh_malloc + -Dattr_container_free=bh_free) + +set (IWASM_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/core/iwasm) +set (APP_MGR_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/core/app-mgr) +set (SHARED_LIB_ROOT ${IWASM_ROOT}/../shared-lib) + +target_include_directories(app PRIVATE ${IWASM_ROOT}/runtime/include + ${IWASM_ROOT}/runtime/platform/zephyr + ${IWASM_ROOT}/runtime/platform/include + ${IWASM_ROOT}/runtime/utils + ${IWASM_ROOT}/runtime/vmcore_wasm + ${IWASM_ROOT}/lib/native/base + ${IWASM_ROOT}/lib/native/libc + ${IWASM_ROOT}/lib/native/extension/sensor + ${IWASM_ROOT}/lib/native-interface + ${APP_MGR_ROOT}/app-manager + ${APP_MGR_ROOT}/app-mgr-shared + ${SHARED_LIB_ROOT}/include + ${SHARED_LIB_ROOT}/platform/include + ${SHARED_LIB_ROOT}/platform/zephyr + ${SHARED_LIB_ROOT}/mem-alloc/ems + ${SHARED_LIB_ROOT}/utils + ${SHARED_LIB_ROOT}/coap/er-coap + ${SHARED_LIB_ROOT}/coap/extension + ${CMAKE_CURRENT_SOURCE_DIR}/../src + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr + ) + +set (IWASM_SRCS ${IWASM_ROOT}/runtime/platform/zephyr/wasm_math.c + ${IWASM_ROOT}/runtime/platform/zephyr/wasm_native.c + ${IWASM_ROOT}/runtime/platform/zephyr/wasm_platform.c + ${IWASM_ROOT}/runtime/utils/wasm_dlfcn.c + ${IWASM_ROOT}/runtime/utils/wasm_hashmap.c + ${IWASM_ROOT}/runtime/utils/wasm_log.c + ${IWASM_ROOT}/runtime/utils/wasm_vector.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_application.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_interp.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_loader.c + ${IWASM_ROOT}/runtime/vmcore-wasm/wasm_runtime.c + ${IWASM_ROOT}/runtime/vmcore-wasm/invokeNative_general.c + ${IWASM_ROOT}/lib/native/base/base_lib_export.c + ${IWASM_ROOT}/lib/native/base/request_response.c + ${IWASM_ROOT}/lib/native/base/timer_wrapper.c + ${IWASM_ROOT}/lib/native/libc/libc_wrapper.c + ${IWASM_ROOT}/lib/native/extension/sensor/runtime_sensor.c + ${IWASM_ROOT}/lib/native-interface/attr_container.c + ${IWASM_ROOT}/lib/native-interface/restful_utils.c + ${APP_MGR_ROOT}/app-manager/app_manager.c + ${APP_MGR_ROOT}/app-manager/app_manager_host.c + ${APP_MGR_ROOT}/app-manager/ble_msg.c + ${APP_MGR_ROOT}/app-manager/event.c + ${APP_MGR_ROOT}/app-manager/message.c + ${APP_MGR_ROOT}/app-manager/module_jeff.c + ${APP_MGR_ROOT}/app-manager/module_utils.c + ${APP_MGR_ROOT}/app-manager/module_wasm_app.c + ${APP_MGR_ROOT}/app-manager/module_wasm_lib.c + ${APP_MGR_ROOT}/app-manager/resource_reg.c + ${APP_MGR_ROOT}/app-manager/watchdog.c + ${APP_MGR_ROOT}/app-manager/platform/zephyr/app_mgr_zephyr.c + ${SHARED_LIB_ROOT}/platform/zephyr/bh_assert.c + ${SHARED_LIB_ROOT}/platform/zephyr/bh_definition.c + ${SHARED_LIB_ROOT}/platform/zephyr/bh_platform.c + ${SHARED_LIB_ROOT}/platform/zephyr/bh_platform_log.c + ${SHARED_LIB_ROOT}/platform/zephyr/bh_thread.c + ${SHARED_LIB_ROOT}/platform/zephyr/bh_time.c + ${SHARED_LIB_ROOT}/mem-alloc/bh_memory.c + ${SHARED_LIB_ROOT}/mem-alloc/mem_alloc.c + ${SHARED_LIB_ROOT}/mem-alloc/ems/ems_alloc.c + ${SHARED_LIB_ROOT}/mem-alloc/ems/ems_hmu.c + ${SHARED_LIB_ROOT}/mem-alloc/ems/ems_kfc.c + ${SHARED_LIB_ROOT}/mem-alloc/tlsf/tlsf.c + ${SHARED_LIB_ROOT}/utils/bh_list.c + ${SHARED_LIB_ROOT}/utils/bh_log.c + ${SHARED_LIB_ROOT}/utils/bh_queue.c + ${SHARED_LIB_ROOT}/utils/runtime_timer.c + ${SHARED_LIB_ROOT}/coap/er-coap/er-coap.c + ${SHARED_LIB_ROOT}/coap/extension/coap_conversion.c + ${SHARED_LIB_ROOT}/coap/extension/coap_over_tcp.c + ) + + set (LVGL_DRV_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr/display_ili9340_adafruit_1480.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr/display_ili9340.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr/display_indev.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr/XPT2046.c + ) + +target_sources(app PRIVATE ${IWASM_SRCS} + ${LVGL_DRV_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/platform/zephyr/iwasm_main.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/ext_lib_export.c) diff --git a/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf new file mode 100644 index 000000000..2375969e1 --- /dev/null +++ b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf @@ -0,0 +1,7 @@ +CONFIG_SPI=y +CONFIG_SPI_STM32=y +CONFIG_SPI_1=y +CONFIG_PRINTK=y +CONFIG_LOG=y +#CONFIG_UART_2=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/samples/littlevgl/wasm-apps/Makefile_wasm_app b/samples/littlevgl/wasm-apps/Makefile_wasm_app new file mode 100644 index 000000000..801aed4ad --- /dev/null +++ b/samples/littlevgl/wasm-apps/Makefile_wasm_app @@ -0,0 +1,55 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CC = emcc +LVGL_DIR = ${shell pwd} +CFLAGS += -O3 -DLV_CONF_INCLUDE_SIMPLE=1 -I$(LVGL_DIR)/ -I$(LVGL_DIR)/lvgl/ -I$(LVGL_DIR)/lv_drivers/ -I$(LVGL_DIR)/src/ -I../../../core/iwasm/lib/app-libs/base/ -I../../../core/iwasm/lib/native-interface/ -I../../../core/iwasm/lib/app-libs/extension/sensor + +SRCS += lvgl/lv_draw/lv_draw_line.c lvgl/lv_draw/lv_draw_rbasic.c +SRCS += lvgl/lv_draw/lv_draw_img.c lvgl/lv_draw/lv_draw_arc.c +SRCS += lvgl/lv_draw/lv_draw_rect.c lvgl/lv_draw/lv_draw_triangle.c +SRCS += lvgl/lv_draw/lv_draw.c lvgl/lv_draw/lv_draw_label.c +SRCS += lvgl/lv_draw/lv_draw_vbasic.c lvgl/lv_fonts/lv_font_builtin.c +SRCS += lvgl/lv_fonts/lv_font_dejavu_20.c +SRCS += lvgl/lv_objx/lv_img.c +SRCS += lvgl/lv_objx/lv_roller.c lvgl/lv_objx/lv_cb.c lvgl/lv_objx/lv_led.c lvgl/lv_objx/lv_cont.c +SRCS += lvgl/lv_objx/lv_calendar.c lvgl/lv_objx/lv_gauge.c lvgl/lv_objx/lv_page.c +SRCS += lvgl/lv_objx/lv_list.c lvgl/lv_objx/lv_bar.c lvgl/lv_objx/lv_tabview.c +SRCS += lvgl/lv_objx/lv_mbox.c lvgl/lv_objx/lv_objx_templ.c lvgl/lv_objx/lv_sw.c +SRCS += lvgl/lv_objx/lv_label.c lvgl/lv_objx/lv_slider.c lvgl/lv_objx/lv_ddlist.c +SRCS += lvgl/lv_objx/lv_imgbtn.c lvgl/lv_objx/lv_line.c lvgl/lv_objx/lv_chart.c +SRCS += lvgl/lv_objx/lv_btnm.c lvgl/lv_objx/lv_arc.c lvgl/lv_objx/lv_preload.c +SRCS += lvgl/lv_objx/lv_win.c lvgl/lv_objx/lv_lmeter.c lvgl/lv_objx/lv_btn.c +SRCS += lvgl/lv_objx/lv_ta.c lvgl/lv_misc/lv_log.c lvgl/lv_misc/lv_fs.c +SRCS += lvgl/lv_misc/lv_task.c lvgl/lv_misc/lv_circ.c lvgl/lv_misc/lv_anim.c +SRCS += lvgl/lv_misc/lv_color.c lvgl/lv_misc/lv_txt.c lvgl/lv_misc/lv_math.c +SRCS += lvgl/lv_misc/lv_mem.c lvgl/lv_misc/lv_font.c lvgl/lv_misc/lv_ll.c +SRCS += lvgl/lv_misc/lv_area.c lvgl/lv_misc/lv_templ.c lvgl/lv_misc/lv_ufs.c +SRCS += lvgl/lv_misc/lv_area.c lvgl/lv_misc/lv_templ.c lvgl/lv_misc/lv_gc.c +SRCS += lvgl/lv_hal/lv_hal_tick.c lvgl/lv_hal/lv_hal_indev.c lvgl/lv_hal/lv_hal_disp.c +SRCS += lvgl/lv_themes/lv_theme_mono.c lvgl/lv_themes/lv_theme_templ.c +SRCS += lvgl/lv_themes/lv_theme_material.c lvgl/lv_themes/lv_theme.c +SRCS += lvgl/lv_themes/lv_theme_night.c lvgl/lv_themes/lv_theme_zen.c lvgl/lv_themes/lv_theme_nemo.c +SRCS += lvgl/lv_themes/lv_theme_alien.c lvgl/lv_themes/lv_theme_default.c +SRCS += lvgl/lv_core/lv_group.c lvgl/lv_core/lv_style.c lvgl/lv_core/lv_indev.c +SRCS += lvgl/lv_core/lv_vdb.c lvgl/lv_core/lv_obj.c lvgl/lv_core/lv_refr.c +SRCS += $(LVGL_DIR)/src/main.c + +SRCS += ../../../core/iwasm/lib/app-libs/base/timer.c +all: + @$(CC) $(CFLAGS) $(SRCS) \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=131072 -s TOTAL_STACK=8096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_request', '_on_sensor_event', '_on_timer_callback']" \ + -o ui_app.wasm diff --git a/samples/littlevgl/wasm-apps/build_wasm_app.sh b/samples/littlevgl/wasm-apps/build_wasm_app.sh new file mode 100755 index 000000000..a88d2a76b --- /dev/null +++ b/samples/littlevgl/wasm-apps/build_wasm_app.sh @@ -0,0 +1,20 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/bin/sh +if [ ! -d "lvgl" ]; then + git clone https://github.com/littlevgl/lvgl.git --branch v5.3 +fi +make -f Makefile_wasm_app + diff --git a/samples/littlevgl/wasm-apps/src/display_indev.h b/samples/littlevgl/wasm-apps/src/display_indev.h new file mode 100644 index 000000000..7188bd444 --- /dev/null +++ b/samples/littlevgl/wasm-apps/src/display_indev.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DISPLAY_INDEV_H_ +#define DISPLAY_INDEV_H_ +#include +#include + +#include "lvgl/lv_misc/lv_color.h" +#include "lvgl/lv_hal/lv_hal_indev.h" +extern void display_init(void); +extern void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p); +extern bool display_input_read(lv_indev_data_t * data); +extern void display_deinit(void); +extern void display_vdb_write(void *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t *color, lv_opa_t opa); +extern uint32_t time_get_ms(void); + +#endif diff --git a/samples/littlevgl/wasm-apps/src/lv_conf.h b/samples/littlevgl/wasm-apps/src/lv_conf.h new file mode 100644 index 000000000..76533a8e1 --- /dev/null +++ b/samples/littlevgl/wasm-apps/src/lv_conf.h @@ -0,0 +1,389 @@ +/** + * @file lv_conf.h + * + */ + +#if 1 /*Set it to "1" to enable content*/ + +#ifndef LV_CONF_H +#define LV_CONF_H +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM 1 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +# define LV_MEM_SIZE (64U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (320) +#define LV_VER_RES (240) + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI 100 + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 0 /*1: Enable anti-aliasing*/ + +/*Screen refresh period in milliseconds*/ +#define LV_REFR_PERIOD 30 + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#define LV_VDB_SIZE ((LV_VER_RES * LV_HOR_RES) / 10) + +/* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ + +/* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR 0 + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#define LV_VDB_DOUBLE 0 + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB2_ADR 0 + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/ +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ + +/*Feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW 1 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 0 /*1: Enable file system (might be required for images*/ +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ + +/*Compiler settings*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */ + +/*HAL settings*/ +#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#if LV_TICK_CUSTOM == 1 +#define LV_TICK_CUSTOM_INCLUDE "system_header.h" /*Header for the sys time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (time_get_ms()) /*Expression evaluating to current systime in ms*/ +#endif /*LV_TICK_CUSTOM*/ + +/*Log settings*/ +#define USE_LV_LOG 1 /*Enable/disable the log module*/ +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ + +# define LV_LOG_PRINTF 0 +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 1 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ + +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#define USE_LV_THEME_DEFAULT 1 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#define USE_LV_THEME_ALIEN 0 /*Dark futuristic theme*/ +#define USE_LV_THEME_NIGHT 0 /*Dark elegant theme*/ +#define USE_LV_THEME_MONO 0 /*Mono color theme for monochrome displays*/ +#define USE_LV_THEME_MATERIAL 0 /*Flat theme with bold colors and light shadows*/ +#define USE_LV_THEME_ZEN 0 /*Peaceful, mainly light theme */ +#define USE_LV_THEME_NEMO 0 /*Water-like theme based on the movie "Finding Nemo"*/ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#define USE_LV_FONT_DEJAVU_10 0 +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_10 0 + +#define USE_LV_FONT_DEJAVU_20 4 +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_20 0 + +#define USE_LV_FONT_DEJAVU_30 0 +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_30 0 + +#define USE_LV_FONT_DEJAVU_40 0 +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_40 0 + +#define USE_LV_FONT_MONOSPACE_8 1 + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#define LV_FONT_CUSTOM_DECLARE + +#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#define LV_OBJ_REALIGN 1 /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/ +# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/ +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 + +/*Arc (dependencies: -)*/ +#define USE_LV_ARC 1 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +# if USE_LV_TABVIEW != 0 +# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/*Tileview (dependencies: lv_page) */ +#define USE_LV_TILEVIEW 1 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 1 + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#define USE_LV_GAUGE 1 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 1 + +/*Table (dependencies: lv_label)*/ +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 1 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#define USE_LV_SPINBOX 1 + +/*Calendar (dependencies: -)*/ +#define USE_LV_CALENDAR 1 + +/*Preload (dependencies: lv_arc)*/ +#define USE_LV_PRELOAD 1 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +/*Canvas (dependencies: lv_img)*/ +#define USE_LV_CANVAS 1 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif + +/*Image Button (dependencies: lv_btn*/ +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 1 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +/************************* + * Non-user section + *************************/ +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/ +# define _CRT_SECURE_NO_WARNINGS +#endif + +/*--END OF LV_CONF_H--*/ + +/*Be sure every define has a default value*/ +#include "lvgl/lv_conf_checker.h" + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/samples/littlevgl/wasm-apps/src/main.c b/samples/littlevgl/wasm-apps/src/main.c new file mode 100644 index 000000000..7bb50c20b --- /dev/null +++ b/samples/littlevgl/wasm-apps/src/main.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file main + * + */ + +/********************* + * INCLUDES + *********************/ +#include +//#include +#include +#include "lvgl/lvgl.h" +#include "display_indev.h" +#include "wasm_app.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void hal_init(void); +//static int tick_thread(void * data); +//static void memory_monitor(void * param); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +uint32_t count = 0; +char count_str[11] = { 0 }; +lv_obj_t *hello_world_label; +lv_obj_t *count_label; +lv_obj_t * btn1; + +lv_obj_t * label_count1; +int label_count1_value = 0; +char label_count1_str[11] = { 0 }; + +void timer1_update(user_timer_t timer1) +{ + if ((count % 100) == 0) { + sprintf(count_str, "%d", count / 100); + lv_label_set_text(count_label, count_str); + } + lv_task_handler(); + ++count; +} + + +static lv_res_t btn_rel_action(lv_obj_t * btn) +{ + label_count1_value++; + sprintf(label_count1_str, "%d", label_count1_value); + lv_label_set_text(label_count1, label_count1_str); + return LV_RES_OK; +} + + +void on_init() +{ + /*Initialize LittlevGL*/ + lv_init(); + + /*Initialize the HAL (display, input devices, tick) for LittlevGL*/ + hal_init(); + + hello_world_label = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text(hello_world_label, "Hello world!"); + lv_obj_align(hello_world_label, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + count_label = lv_label_create(lv_scr_act(), NULL); + lv_obj_align(count_label, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + + btn1 = lv_btn_create(lv_scr_act(), NULL); /*Create a button on the currently loaded screen*/ + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, btn_rel_action); /*Set function to be called when the button is released*/ + lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 20); /*Align below the label*/ + + /*Create a label on the button*/ + lv_obj_t * btn_label = lv_label_create(btn1, NULL); + lv_label_set_text(btn_label, "Click ++"); + + label_count1 = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text(label_count1, "0"); + lv_obj_align(label_count1, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + /* set up a timer */ + user_timer_t timer; + timer = api_timer_create(10, true, false, timer1_update); + api_timer_restart(timer, 10); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Initialize the Hardware Abstraction Layer (HAL) for the Littlev graphics library + */ +void display_flush_wrapper(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ + display_flush(x1, y1, x2, y2, color_p); + lv_flush_ready(); +} +void display_vdb_write_wrapper(uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa) +{ + display_vdb_write(buf, buf_w, x, y, &color, opa); +} +extern void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p); +extern void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p); +static void hal_init(void) +{ + /* Add a display*/ + lv_disp_drv_t disp_drv; + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + disp_drv.disp_flush = display_flush_wrapper; /*Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing)*/ + disp_drv.disp_fill = display_fill; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/ + disp_drv.disp_map = display_map; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/ +#if LV_VDB_SIZE != 0 + disp_drv.vdb_wr = display_vdb_write_wrapper; +#endif + lv_disp_drv_register(&disp_drv); + + /* Add the mouse as input device + * Use the 'mouse' driver which reads the PC's mouse*/ +// mouse_init(); + lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); /*Basic initialization*/ + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read = display_input_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ + lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv); + +} + diff --git a/samples/littlevgl/wasm-apps/src/system_header.h b/samples/littlevgl/wasm-apps/src/system_header.h new file mode 100644 index 000000000..5333432b3 --- /dev/null +++ b/samples/littlevgl/wasm-apps/src/system_header.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +uint32_t time_get_ms(void); diff --git a/samples/simple/CMakeLists.txt b/samples/simple/CMakeLists.txt new file mode 100644 index 000000000..a02e415f4 --- /dev/null +++ b/samples/simple/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required (VERSION 2.8) + +project (simple) + +set (TARGET_PLATFORM "linux") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Enable repl mode if want to test spec cases +# add_definitions(-DWASM_ENABLE_REPL) + +if (NOT ("$ENV{VALGRIND}" STREQUAL "YES")) + add_definitions(-DNVALGRIND) +endif () + +# Currently build as 32-bit by default. +set (BUILD_AS_64BIT_SUPPORT "NO") + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) +if (${BUILD_AS_64BIT_SUPPORT} STREQUAL "YES") + # Add -fPIC flag if build as 64-bit + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") +else () + add_definitions (-m32) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") +endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) +SET(CMAKE_BUILD_TYPE Debug) +endif (NOT CMAKE_BUILD_TYPE) +message ("CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) + +if (NOT PLATFORM) +SET(PLATFORM linux) +endif (NOT PLATFORM) +message ("PLATFORM = " ${PLATFORM}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wall -Wno-unused-parameter -Wno-pedantic") + +set(REPO_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) +set(WASM_DIR ${REPO_ROOT_DIR}/wamr/core/iwasm) +set(APP_MGR_DIR ${REPO_ROOT_DIR}/wamr/core/app-mgr) +set(SHARED_DIR ${REPO_ROOT_DIR}/wamr/core/shared-lib) + + +enable_language (ASM) + +include (${WASM_DIR}/runtime/platform/${TARGET_PLATFORM}/platform.cmake) +include (${WASM_DIR}/runtime/utils/utils.cmake) +include (${WASM_DIR}/runtime/vmcore-wasm/vmcore.cmake) +include (${WASM_DIR}/lib/native/base/wasm_lib_base.cmake) +include (${WASM_DIR}/lib/native/libc/wasm_libc.cmake) +include (${WASM_DIR}/lib/native/extension/sensor/wasm_lib_sensor.cmake) +include (${WASM_DIR}/lib/native-interface/native_interface.cmake) +include (${APP_MGR_DIR}/app-manager/app_mgr.cmake) +include (${APP_MGR_DIR}/app-mgr-shared/app_mgr_shared.cmake) +include (${SHARED_DIR}/platform/${TARGET_PLATFORM}/shared_platform.cmake) +include (${SHARED_DIR}/utils/shared_utils.cmake) +include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) +include (${SHARED_DIR}/coap/lib_coap.cmake) + + +include_directories(${SHARED_DIR}/include) + +#Note: uncomment below line to use UART mode +#add_definitions (-DCONNECTION_UART) +add_definitions (-DWASM_ENABLE_BASE_LIB) +add_definitions (-Dattr_container_malloc=bh_malloc) +add_definitions (-Dattr_container_free=bh_free) + +add_library (vmlib + ${WASM_PLATFORM_LIB_SOURCE} + ${WASM_UTILS_LIB_SOURCE} + ${VMCORE_LIB_SOURCE} + ${WASM_LIBC_SOURCE} + ${APP_MGR_SOURCE} + ${WASM_LIB_BASE_SOURCE} + ${WASM_LIB_EXT_SOURCE} + ${WASM_LIB_SENSOR_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ) + +add_executable (simple src/main.c src/iwasm_main.c src/ext_lib_export.c) + +target_link_libraries (simple vmlib -lm -ldl -lpthread) + diff --git a/samples/simple/README.md b/samples/simple/README.md new file mode 100644 index 000000000..01a71bd0f --- /dev/null +++ b/samples/simple/README.md @@ -0,0 +1,323 @@ +Introduction +============== +This project builds out both host tools running on the host side, an application running on the device side. The device application consists of iwasm, application library, application manager, timers and sensors support. The device runs on Linux OS and interacts with host tools. + +It demonstrates an end to end scenario, the wasm applications life cycle management and communication programming models. + +Directory structure +------------------------------ +``` +simple/ +├── build.sh +├── CMakeLists.txt +├── README.md +├── src +│   ├── ext_lib_export.c +│   ├── iwasm_main.c +│   └── main.c +└── wasm-apps + ├── event_publisher + │   └── event_publisher.c + ├── event_subscriber + │   └── event_subscriber.c + ├── request_handler + │   └── request_handler.c + ├── request_sender + │   └── request_sender.c + ├── sensor + │   └── sensor.c + └── timer +    └── timer.c +``` + +- build.sh
+ The script to build all binaries. +- CMakeLists.txt
+ CMake file used to build the simple application. +- README.md
+ The file you are reading currently. +- src/ext_lib_export.c
+ This file is used to export native APIs. See the `The mechanism of exporting Native API to WASM application` section in WAMR README.md for detail. +- src/iwam_main.c
+ This file is the implementation by platform integrator. It implements the interfaces that enable the application manager communicating with the host side. See `{WAMR_ROOT}/core/app-mgr/app-mgr-shared/app_manager_export.h` for the definition of the host interface. +``` +/* Interfaces of host communication */ +typedef struct host_interface { + host_init_func init; + host_send_fun send; + host_destroy_fun destroy; +} host_interface; +``` +``` +host_interface interface = { + .init = host_init, + .send = host_send, + .destroy = host_destroy +}; +``` +This interface is passed to application manager by calling +``` +app_manager_startup(&interface); +``` + +The `host_init_func` is called when the application manager starts up. And `host_send_fun` is called by the application manager to send data to the host. +>**Note:** Currently application manager keeps running and never exit, `host_destroy_fun` has no chance to get executed. So you can leave this API implementation empty. + +- src/main.c
+ The main file. +- wasm-apps
+ Source files of sample wasm applications. + +Build all binaries +============== +Execute the build.sh script then all binaries including wasm application files would be generated in 'out' directory. +`./build.sh` + +Out directory structure +------------------------------ + ``` +out/ +├── host_tool +├── simple +└── wasm-apps + ├── event_publisher.wasm + ├── event_subscriber.wasm + ├── request_handler.wasm + ├── request_sender.wasm + ├── sensor.wasm + └── timer.wasm + ``` + +- host_tool: + A small testing tool to interact with WAMR. See the usage of this tool by executing "./host_tool -h". + `./host_tool -h` + +- simple: + A simple testing tool running on the host side that interact with WAMR. It is used to install, uninstall and query WASM applications in WAMR, and send request or subscribe event, etc. See the usage of this application by executing "./simple -h". + `./simple -h` +>****Note:**** The connection between simple and host_tool is TCP by default and is what this guide uses. The simple application works as a server and the host_tool works as a client. You can also use UART connection. To achieve this you have to uncomment the below line in CMakeLists.txt and rebuild. You have to set up a UART hardware connection between 2 machines one of which runs the host_tool and the other runs the simple application. See the help of host_tool and the simple application to know how to specify UART device parameters.
+`#add_definitions (-DCONNECTION_UART)` + +- wasm-apps: + Sample wasm applications that demonstrate all APIs of the WAMR programming model. The source codes are in the wasm-apps directory under the root of this project. + + event_publisher.wasm
+ This application shows the sub/pub programming model. The pub application publishes the event "alert/overheat" by calling api_publish_event() API. The subscriber could be host_tool or other wasm application. + + event_subscriber.wasm
+ This application shows the sub/pub programming model. The sub application subscribes the "alert/overheat" event by calling api_subscribe_event() API so that it is able to receive the event once generated and published by the pub application. To make the process clear to interpret, the sub application dumps the event when receiving it. + + request_handler.wasm
+ This application shows the request/response programming model. The request handler application registers 2 resources(/url1 and /url2) by calling api_register_resource_handler() API. The request sender could be host_tool or other wasm application. + + request_sender.wasm
+ This application shows the request/response programming model. The sender application sends 2 requests, one is "/app/request_handler/url1" and the other is "url1". The former is an accurate request which explicitly specifies the name of request handler application in the middle of the URL and the later is a general request. + + sensor.wasm
+ This application shows the sensor programming model. It opens a test sensor and configures the sensor event generating interval to 1 second. To make the process clear to interpret, the application dumps the sensor event when receiving it. + + timer.wasm
+ This application shows the timer programming model. It creates a periodic timer that prints the current expiry number in every second. + +Run the scenario +========================== +- Enter the out directory
+``` +$ cd ./out/ +``` + +- Startup the 'simple' process works in TCP server mode and you would see "App Manager started." is printed.
+``` +$ ./simple -s +App Manager started. +``` + +- Query all installed applications
+``` +$ ./host_tool -q + +response status 69 +{ + "num": 0 +} +``` + +The `69` stands for response status to this query request which means query success and a payload is attached with the response. See `{WAMR_ROOT}/core/iwasm/lib/app-libs/base/wasm_app.h` for the definitions of response codes. The payload is printed with JSON format where the `num` stands for application installations number and value `0` means currently no application is installed yet. + +- Install the request handler wasm application
+``` +$ ./host_tool -i request_handler -f ./wasm-apps/request_handler.wasm + +response status 65 +``` +The `65` stands for response status to this installation request which means success. + +Output of simple +``` +Install WASM app success! +sent 16 bytes to host +WASM app 'request_handler' started +``` + +Now the request handler application is running and waiting for host or other wasm application to send a request. + +- Query again
+``` +$ ./host_tool -q + +response status 69 +{ + "num": 1, + "applet1": "request_handler", + "heap1": 49152 +} +``` +In the payload, we can see `num` is 1 which means 1 application is installed. `applet1`stands for the name of the 1st application. `heap1` stands for the heap size of the 1st application. + +- Send request from host to specific wasm application
+``` +$ ./host_tool -r /app/request_handler/url1 -A GET + +response status 69 +{ + "key1": "value1", + "key2": "value2" +} +``` + +We can see a response with status `69` and a payload is received. + +Output of simple +``` +connection established! +Send request to applet: request_handler +Send request to app request_handler success. +App request_handler got request, url url1, action 1 +[resp] ### user resource 1 handler called +sent 150 bytes to host +Wasm app process request success. +``` + +- Send a general request from host (not specify target application name)
+``` +$ ./host_tool -r /url1 -A GET + +response status 69 +{ + "key1": "value1", + "key2": "value2" +} +``` + +Output of simple +``` +connection established! +Send request to app request_handler success. +App request_handler got request, url /url1, action 1 +[resp] ### user resource 1 handler called +sent 150 bytes to host +Wasm app process request success. +``` + +- Install the event publisher wasm application
+``` +$ ./host_tool -i pub -f ./wasm-apps/event_publisher.wasm + +response status 65 +``` + +- Subscribe event by host_tool
+``` +$ ./host_tool -s /alert/overheat -a 3000 + +response status 69 + +received an event alert/overheat +{ + "warning": "temperature is over high" +} +received an event alert/overheat +{ + "warning": "temperature is over high" +} +received an event alert/overheat +{ + "warning": "temperature is over high" +} +received an event alert/overheat +{ + "warning": "temperature is over high" +} +``` +We can see 4 `alert/overheat` events are received in 3 seconds which is published by the `pub` application. + +Output of simple +``` +connection established! +am_register_event adding url:(alert/overheat) +client: -3 registered event (alert/overheat) +sent 16 bytes to host +sent 142 bytes to host +sent 142 bytes to host +sent 142 bytes to host +sent 142 bytes to host +``` +- Install the event subscriber wasm application
+``` +$ ./host_tool -i sub -f ./wasm-apps/event_subscriber.wasm + +response status 65 +``` +The `sub` application is installed. + +Output of simple +``` +connection established! +Install WASM app success! +WASM app 'sub' started +am_register_event adding url:(alert/overheat) +client: 3 registered event (alert/overheat) +sent 16 bytes to host +Send request to app sub success. +App sub got request, url alert/overheat, action 6 +### user over heat event handler called +Attribute container dump: +Tag: +Attribute list: + key: warning, type: string, value: temperature is over high + +Wasm app process request success. +``` + +We can see the `sub` application receives the `alert/overheat` event and dumps it out.
+At device side, the event is represented by an attribute container which contains key-value pairs like below: +``` +Attribute container dump: +Tag: +Attribute list: + key: warning, type: string, value: temperature is over high +``` +`warning` is the key's name. `string` means this is a string value and `temperature is over high` is the value. + +- Uninstall the wasm application
+``` +$ ./host_tool -u request_handler + +response status 66 + +$ ./host_tool -u pub + +response status 66 + +$ ./host_tool -u sub + +response status 66 +``` + +- Query again
+``` +$ ./host_tool -q + +response status 69 +{ + "num": 0 +} +``` + + >**Note:** Here we only installed part of the sample WASM applications. You can try others by yourself. + + >**Note:** You have to manually kill the simple process by Ctrl+C after use. diff --git a/samples/simple/build.sh b/samples/simple/build.sh new file mode 100755 index 000000000..7fe76126d --- /dev/null +++ b/samples/simple/build.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +CURR_DIR=$PWD +ROOT_DIR=${PWD}/../../.. +OUT_DIR=${PWD}/out +BUILD_DIR=${PWD}/build + +IWASM_ROOT=${PWD}/../../core/iwasm +APP_LIBS=${IWASM_ROOT}/lib/app-libs +NATIVE_LIBS=${IWASM_ROOT}/lib/native-interface +APP_LIB_SRC="${APP_LIBS}/base/*.c ${APP_LIBS}/extension/sensor/*.c ${NATIVE_LIBS}/*.c" +WASM_APPS=${PWD}/wasm-apps + +rm -rf ${OUT_DIR} +mkdir ${OUT_DIR} +mkdir ${OUT_DIR}/wasm-apps + +cd ${ROOT_DIR}/wamr/core/shared-lib/mem-alloc +if [ ! -d "tlsf" ]; then + git clone https://github.com/mattconte/tlsf +fi + +echo "#####################build simple project" +cd ${CURR_DIR} +mkdir -p cmake_build +cd cmake_build +cmake .. +make +if [ $? != 0 ];then + echo "BUILD_FAIL simple exit as $?\n" + exit 2 +fi +cp -a simple ${OUT_DIR} +echo "#####################build simple project success" + +echo "#####################build host-tool" +cd ${ROOT_DIR}/wamr/test-tools/host-tool +mkdir -p bin +cd bin +cmake .. +make +if [ $? != 0 ];then + echo "BUILD_FAIL host tool exit as $?\n" + exit 2 +fi +cp host_tool ${OUT_DIR} +echo "#####################build host-tool success" + + +echo "#####################build wasm apps" + +cd ${CURR_DIR} + +APP_SRC="${WASM_APPS}/timer/timer.c ${APP_LIB_SRC}" +emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ + '_on_sensor_event', '_on_timer_callback']" \ + -o ${OUT_DIR}/wasm-apps/timer.wasm ${APP_SRC} + +APP_SRC="${WASM_APPS}/request_handler/request_handler.c ${APP_LIB_SRC}" +emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ + '_on_sensor_event', '_on_timer_callback']" \ + -o ${OUT_DIR}/wasm-apps/request_handler.wasm ${APP_SRC} + +APP_SRC="${WASM_APPS}/request_sender/request_sender.c ${APP_LIB_SRC}" +emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ + '_on_sensor_event', '_on_timer_callback']" \ + -o ${OUT_DIR}/wasm-apps/request_sender.wasm ${APP_SRC} + +APP_SRC="${WASM_APPS}/event_publisher/event_publisher.c ${APP_LIB_SRC}" +emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ + '_on_sensor_event', '_on_timer_callback']" \ + -o ${OUT_DIR}/wasm-apps/event_publisher.wasm ${APP_SRC} + +APP_SRC="${WASM_APPS}/event_subscriber/event_subscriber.c ${APP_LIB_SRC}" +emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ + '_on_sensor_event', '_on_timer_callback']" \ + -o ${OUT_DIR}/wasm-apps/event_subscriber.wasm ${APP_SRC} + +APP_SRC="${WASM_APPS}/sensor/sensor.c ${APP_LIB_SRC}" +emcc -O3 -I${APP_LIBS}/base -I${APP_LIBS}/extension/sensor -I${NATIVE_LIBS} \ + -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ + -s "EXPORTED_FUNCTIONS=['_on_init', '_on_destroy', '_on_request', '_on_response', \ + '_on_sensor_event', '_on_timer_callback']" \ + -o ${OUT_DIR}/wasm-apps/sensor.wasm ${APP_SRC} + +echo "#####################build wasm apps success" diff --git a/samples/simple/src/ext_lib_export.c b/samples/simple/src/ext_lib_export.c new file mode 100644 index 000000000..89e572005 --- /dev/null +++ b/samples/simple/src/ext_lib_export.c @@ -0,0 +1,8 @@ +#include "lib_export.h" +#include "sensor_api.h" + +static NativeSymbol extended_native_symbol_defs[] = { +#include "runtime_sensor.inl" + }; + +#include "ext_lib_export.h" diff --git a/samples/simple/src/iwasm_main.c b/samples/simple/src/iwasm_main.c new file mode 100644 index 000000000..d70b7e4d3 --- /dev/null +++ b/samples/simple/src/iwasm_main.c @@ -0,0 +1,465 @@ + +#ifndef CONNECTION_UART +#include +#include +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "runtime_lib.h" +#include "runtime_timer.h" +#include "native_interface.h" +#include "app_manager_export.h" +#include "bh_common.h" +#include "bh_queue.h" +#include "bh_thread.h" +#include "bh_memory.h" +#include "runtime_sensor.h" +#include "attr_container.h" +#include "module_wasm_app.h" +#include "wasm_export.h" +#define MAX 2048 + +#ifndef CONNECTION_UART +#define SA struct sockaddr +static char *host_address = "127.0.0.1"; +static int port = 8888; +#else +static char *uart_device = "/dev/ttyS2"; +static int baudrate = B115200; +#endif + +extern void * thread_timer_check(void *); +extern void init_sensor_framework(); +extern int aee_host_msg_callback(void *msg, uint16_t msg_len); + +#ifndef CONNECTION_UART +int listenfd = -1; +int sockfd = -1; +static pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER; +#else +int uartfd = -1; +#endif + +#ifndef CONNECTION_UART +static bool server_mode = false; + +// Function designed for chat between client and server. +void* func(void* arg) +{ + char buff[MAX]; + int n; + struct sockaddr_in servaddr; + + while (1) { + if (sockfd != -1) + close(sockfd); + // socket create and verification + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) { + printf("socket creation failed...\n"); + return NULL; + } else + printf("Socket successfully created..\n"); + bzero(&servaddr, sizeof(servaddr)); + // assign IP, PORT + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr(host_address); + servaddr.sin_port = htons(port); + + // connect the client socket to server socket + if (connect(sockfd, (SA*) &servaddr, sizeof(servaddr)) != 0) { + printf("connection with the server failed...\n"); + sleep(10); + continue; + } else { + printf("connected to the server..\n"); + } + + // infinite loop for chat + for (;;) { + bzero(buff, MAX); + + // read the message from client and copy it in buffer + n = read(sockfd, buff, sizeof(buff)); + // print buffer which contains the client contents + //fprintf(stderr, "recieved %d bytes from host: %s", n, buff); + + // socket disconnected + if (n <= 0) + break; + + aee_host_msg_callback(buff, n); + } + } + + // After chatting close the socket + close(sockfd); +} + +static bool host_init() +{ + return true; +} + +int host_send(void * ctx, const char *buf, int size) +{ + int ret; + + if (pthread_mutex_trylock(&sock_lock) == 0) { + if (sockfd == -1) { + pthread_mutex_unlock(&sock_lock); + return 0; + } + + ret = write(sockfd, buf, size); + + pthread_mutex_unlock(&sock_lock); + return ret; + } + + return -1; +} + +void host_destroy() +{ + if (server_mode) + close(listenfd); + + pthread_mutex_lock(&sock_lock); + close(sockfd); + pthread_mutex_unlock(&sock_lock); +} + +host_interface interface = { + .init = host_init, + .send = host_send, + .destroy = host_destroy +}; + +void* func_server_mode(void* arg) +{ + int clilent; + struct sockaddr_in serv_addr, cli_addr; + int n; + char buff[MAX]; + + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, 0); + + /* First call to socket() function */ + listenfd = socket(AF_INET, SOCK_STREAM, 0); + + if (listenfd < 0) { + perror("ERROR opening socket"); + exit(1); + } + + /* Initialize socket structure */ + bzero((char *) &serv_addr, sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port); + + /* Now bind the host address using bind() call.*/ + if (bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + perror("ERROR on binding"); + exit(1); + } + + listen(listenfd, 5); + clilent = sizeof(cli_addr); + + while (1) { + pthread_mutex_lock(&sock_lock); + + sockfd = accept(listenfd, (struct sockaddr *) &cli_addr, &clilent); + + pthread_mutex_unlock(&sock_lock); + + if (sockfd < 0) { + perror("ERROR on accept"); + exit(1); + } + + printf("connection established!\n"); + + for (;;) { + bzero(buff, MAX); + + // read the message from client and copy it in buffer + n = read(sockfd, buff, sizeof(buff)); + + // socket disconnected + if (n <= 0) { + pthread_mutex_lock(&sock_lock); + close(sockfd); + sockfd = -1; + pthread_mutex_unlock(&sock_lock); + + sleep(2); + break; + } + + aee_host_msg_callback(buff, n); + } + } +} + +#else +static int parse_baudrate(int baud) +{ + switch (baud) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} +static bool uart_init(const char *device, int baudrate, int *fd) +{ + int uart_fd; + struct termios uart_term; + + uart_fd = open(device, O_RDWR | O_NOCTTY); + + if (uart_fd <= 0) + return false; + + memset(&uart_term, 0, sizeof(uart_term)); + uart_term.c_cflag = baudrate | CS8 | CLOCAL | CREAD; + uart_term.c_iflag = IGNPAR; + uart_term.c_oflag = 0; + + /* set noncanonical mode */ + uart_term.c_lflag = 0; + uart_term.c_cc[VTIME] = 30; + uart_term.c_cc[VMIN] = 1; + tcflush(uart_fd, TCIFLUSH); + + if (tcsetattr(uart_fd, TCSANOW, &uart_term) != 0) { + close(uart_fd); + return false; + } + + *fd = uart_fd; + + return true; +} + +static void *func_uart_mode(void *arg) +{ + int n; + char buff[MAX]; + + if (!uart_init(uart_device, baudrate, &uartfd)) { + printf("open uart fail! %s\n", uart_device); + return NULL; + } + + for (;;) { + bzero(buff, MAX); + + n = read(uartfd, buff, sizeof(buff)); + + if (n <= 0) { + close(uartfd); + uartfd = -1; + break; + } + + aee_host_msg_callback(buff, n); + } + + return NULL; +} + +static int uart_send(void * ctx, const char *buf, int size) +{ + int ret; + + ret = write(uartfd, buf, size); + + return ret; +} + +static void uart_destroy() +{ + close(uartfd); +} + +static host_interface interface = { .send = uart_send, .destroy = uart_destroy }; + +#endif + +static char global_heap_buf[512 * 1024] = { 0 }; + +static void showUsage() +{ +#ifndef CONNECTION_UART + printf("Usage:\n"); + printf("\nWork as TCP server mode:\n"); + printf("\tsimple -s|--server_mode -p|--port \n"); + printf("where\n"); + printf("\t represents the port that would be listened on and the default is 8888\n"); + printf("\nWork as TCP client mode:\n"); + printf("\tsimple -a|--host_address -p|--port \n"); + printf("where\n"); + printf("\t represents the network address of host and the default is 127.0.0.1\n"); + printf("\t represents the listen port of host and the default is 8888\n"); +#else + printf("Usage:\n"); + printf("\tsimple -u -b \n\n"); + printf("where\n"); + printf("\t represents the UART device name and the default is /dev/ttyS2\n"); + printf("\t represents the UART device baudrate and the default is 115200\n"); +#endif +} + +static bool parse_args(int argc, char *argv[]) +{ + int c; + + while (1) { + int optIndex = 0; + static struct option longOpts[] = { +#ifndef CONNECTION_UART + { "server_mode", no_argument, NULL, 's' }, + { "host_address", required_argument, NULL, 'a' }, + { "port", required_argument, NULL, 'p' }, +#else + { "uart", required_argument, NULL, 'u' }, + { "baudrate", required_argument, NULL, 'b' }, +#endif + { "help", required_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "sa:p:u:b:h", longOpts, &optIndex); + if (c == -1) + break; + + switch (c) { +#ifndef CONNECTION_UART + case 's': + server_mode = true; + break; + case 'a': + host_address = optarg; + printf("host address: %s\n", host_address); + break; + case 'p': + port = atoi(optarg); + printf("port: %d\n", port); + break; +#else + case 'u': + uart_device = optarg; + printf("uart device: %s\n", uart_device); + break; + case 'b': + baudrate = parse_baudrate(atoi(optarg)); + printf("uart baudrate: %s\n", optarg); + break; +#endif + case 'h': + showUsage(); + return false; + default: + showUsage(); + return false; + } + } + + return true; +} + +// Driver function +int iwasm_main(int argc, char *argv[]) +{ + korp_thread tid; + + if (!parse_args(argc, argv)) + return -1; + + if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) + != 0) { + printf("Init global heap failed.\n"); + return -1; + } + + if (vm_thread_sys_init() != 0) { + goto fail1; + } + + init_sensor_framework(); + + // timer manager + init_wasm_timer(); + +#ifndef CONNECTION_UART + if (server_mode) + vm_thread_create(&tid, func_server_mode, NULL, + BH_APPLET_PRESERVED_STACK_SIZE); + else + vm_thread_create(&tid, func, NULL, BH_APPLET_PRESERVED_STACK_SIZE); +#else + vm_thread_create(&tid, func_uart_mode, NULL, BH_APPLET_PRESERVED_STACK_SIZE); +#endif + + // TODO: + app_manager_startup(&interface); + + fail1: bh_memory_destroy(); + return -1; +} diff --git a/samples/simple/src/main.c b/samples/simple/src/main.c new file mode 100644 index 000000000..14afb0780 --- /dev/null +++ b/samples/simple/src/main.c @@ -0,0 +1,5 @@ +extern void iwasm_main(); +int main(int argc, char *argv[]) +{ + iwasm_main(argc, argv); +} diff --git a/samples/simple/wasm-apps/event_publisher/event_publisher.c b/samples/simple/wasm-apps/event_publisher/event_publisher.c new file mode 100644 index 000000000..96717eeca --- /dev/null +++ b/samples/simple/wasm-apps/event_publisher/event_publisher.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +int num = 0; + +void publish_overheat_event() +{ + attr_container_t *event; + + event = attr_container_create("event"); + attr_container_set_string(&event, "warning", "temperature is over high"); + + api_publish_event("alert/overheat", FMT_ATTR_CONTAINER, event, + attr_container_get_serialize_length(event)); + + attr_container_destroy(event); +} + +/* Timer callback */ +void timer1_update(user_timer_t timer) +{ + publish_overheat_event(); +} + +void start_timer() +{ + user_timer_t timer; + + /* set up a timer */ + timer = api_timer_create(1000, true, false, timer1_update); + api_timer_restart(timer, 1000); +} + +void on_init() +{ + start_timer(); +} + +void on_destroy() +{ + /* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */ +} diff --git a/samples/simple/wasm-apps/event_subscriber/event_subscriber.c b/samples/simple/wasm-apps/event_subscriber/event_subscriber.c new file mode 100644 index 000000000..aea0d77ff --- /dev/null +++ b/samples/simple/wasm-apps/event_subscriber/event_subscriber.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +void over_heat_event_handler(request_t *request) +{ + printf("### user over heat event handler called\n"); + + if (request->payload != NULL && request->fmt == FMT_ATTR_CONTAINER) + attr_container_dump((attr_container_t *) request->payload); +} + +void on_init() +{ + api_subscribe_event("alert/overheat", over_heat_event_handler); +} + +void on_destroy() +{ + /* real destroy work including killing timer and closing sensor is + accomplished in wasm app library version of on_destroy() */ +} diff --git a/samples/simple/wasm-apps/request_handler/request_handler.c b/samples/simple/wasm-apps/request_handler/request_handler.c new file mode 100644 index 000000000..b4820930d --- /dev/null +++ b/samples/simple/wasm-apps/request_handler/request_handler.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +static void url1_request_handler(request_t *request) +{ + response_t response[1]; + attr_container_t *payload; + + printf("[resp] ### user resource 1 handler called\n"); + + if (request->payload != NULL && request->fmt == FMT_ATTR_CONTAINER) + attr_container_dump((attr_container_t *) request->payload); + + payload = attr_container_create("wasm app response payload"); + if (payload == NULL) + return; + + attr_container_set_string(&payload, "key1", "value1"); + attr_container_set_string(&payload, "key2", "value2"); + + make_response_for_request(request, response); + set_response(response, CONTENT_2_05, + FMT_ATTR_CONTAINER, + (void *)payload, + attr_container_get_serialize_length(payload)); + api_response_send(response); + + attr_container_destroy(payload); +} + +static void url2_request_handler(request_t *request) +{ + response_t response[1]; + make_response_for_request(request, response); + set_response(response, DELETED_2_02, 0, NULL, 0); + api_response_send(response); + + printf("### user resource 2 handler called\n"); +} + +void on_init() +{ + /* register resource uri */ + api_register_resource_handler("/url1", url1_request_handler); + api_register_resource_handler("/url2", url2_request_handler); +} + +void on_destroy() +{ + /* real destroy work including killing timer and closing sensor is + accomplished in wasm app library version of on_destroy() */ +} diff --git a/samples/simple/wasm-apps/request_sender/request_sender.c b/samples/simple/wasm-apps/request_sender/request_sender.c new file mode 100644 index 000000000..f1a9952bd --- /dev/null +++ b/samples/simple/wasm-apps/request_sender/request_sender.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +static void my_response_handler(response_t *response, void *user_data) +{ + char *tag = (char *) user_data; + + if (response == NULL) { + printf("[req] request timeout!\n"); + return; + } + + printf("[req] response handler called mid:%d, status:%d, fmt:%d, payload:%p, len:%d, tag:%s\n", + response->mid, response->status, response->fmt, response->payload, + response->payload_len, tag); + + if (response->payload != NULL + && response->payload_len > 0 + && response->fmt == FMT_ATTR_CONTAINER) { + printf("[req] dump the response payload:\n"); + attr_container_dump((attr_container_t *) response->payload); + } +} + +static void test_send_request(char *url, char *tag) +{ + request_t request[1]; + + init_request(request, url, COAP_PUT, 0, NULL, 0); + api_send_request(request, my_response_handler, tag); +} + +void on_init() +{ + test_send_request("/app/request_handler/url1", "a request to target app"); + test_send_request("url1", "a general request"); +} + +void on_destroy() +{ + /* real destroy work including killing timer and closing sensor is + accomplished in wasm app library version of on_destroy() */ +} diff --git a/samples/simple/wasm-apps/sensor/sensor.c b/samples/simple/wasm-apps/sensor/sensor.c new file mode 100644 index 000000000..32705889a --- /dev/null +++ b/samples/simple/wasm-apps/sensor/sensor.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +static sensor_t sensor = NULL; + +/* Sensor event callback*/ +void sensor_event_handler(sensor_t sensor, attr_container_t *event, + void *user_data) +{ + printf("### app get sensor event\n"); + attr_container_dump(event); +} + +void on_init() +{ + char *user_data; + attr_container_t *config; + + printf("### app on_init 1\n"); + /* open a sensor */ + user_data = malloc(100); + printf("### app on_init 2\n"); + sensor = sensor_open("sensor_test", 0, sensor_event_handler, user_data); + printf("### app on_init 3\n"); + + /* config the sensor */ + sensor_config(sensor, 1000, 0, 0); + printf("### app on_init 4\n"); + + /* + config = attr_container_create("sensor config"); + sensor_config(sensor, config); + attr_container_destroy(config); + */ +} + +void on_destroy() +{ + if (NULL != sensor) { + sensor_config(sensor, 0, 0, 0); + } + /* real destroy work including killing timer and closing sensor is + accomplished in wasm app library version of on_destroy() */ +} diff --git a/samples/simple/wasm-apps/timer/timer.c b/samples/simple/wasm-apps/timer/timer.c new file mode 100644 index 000000000..d6605fe4e --- /dev/null +++ b/samples/simple/wasm-apps/timer/timer.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm_app.h" + +/* User global variable */ +static int num = 0; + +/* Timer callback */ +void timer1_update(user_timer_t timer) +{ + printf("Timer update %d\n", num++); +} + +void on_init() +{ + user_timer_t timer; + + /* set up a timer */ + timer = api_timer_create(1000, true, false, timer1_update); + api_timer_restart(timer, 1000); +} + +void on_destroy() +{ + /* real destroy work including killing timer and closing sensor is + accomplished in wasm app library version of on_destroy() */ +} diff --git a/test-tools/host-tool/CMakeLists.txt b/test-tools/host-tool/CMakeLists.txt new file mode 100644 index 000000000..00a4cd82a --- /dev/null +++ b/test-tools/host-tool/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required (VERSION 2.8.3) +project (host-agent) + +if (NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Debug) +endif (NOT CMAKE_BUILD_TYPE) + +if (NOT TARGET_PLATFORM) + set (TARGET_PLATFORM "linux") +endif (NOT TARGET_PLATFORM) + +message ("TARGET_PLATFORM = " ${TARGET_PLATFORM}) + +set(REPO_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +set(WASM_DIR ${REPO_ROOT_DIR}/core/iwasm) +set(APP_MGR_DIR ${REPO_ROOT_DIR}/core/app-mgr) +set(SHARED_DIR ${REPO_ROOT_DIR}/core/shared-lib) +#TODO: use soft-plc/tools/iec-runtime/external/cJSON instead +set(CJSON_DIR ${CMAKE_CURRENT_LIST_DIR}/external/cJSON) +set(SSG_LIB_DIR ${REPO_ROOT_DIR}/../host-agent/lib) + +include (${WASM_DIR}/lib/native-interface/native_interface.cmake) +include (${APP_MGR_DIR}/app-mgr-shared/app_mgr_shared.cmake) +include (${SHARED_DIR}/platform/${TARGET_PLATFORM}/shared_platform.cmake) +include (${SHARED_DIR}/utils/shared_utils.cmake) +include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) +include (${CJSON_DIR}/cjson.cmake) +include (${SHARED_DIR}/coap/lib_coap.cmake) +include (${SSG_LIB_DIR}/host_agent_lib.cmake) + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") +endif () + +add_definitions(-Wall -Wno-pointer-sign -DMALLOC_MEMORY_FROM_SYSTEM) + +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/src +) + +file (GLOB_RECURSE HOST_TOOL_SRC src/*.c) + + +SET(SOURCES + ${HOST_TOOL_SRC} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_DIR}/bh_memory.c + ${NATIVE_INTERFACE_SOURCE} + ${CJSON_SOURCE} + ${LIB_HOST_AGENT_SOURCE} + ) + +add_executable(host_tool ${SOURCES}) +target_link_libraries(host_tool pthread) diff --git a/test-tools/host-tool/external/cJSON/LICENSE b/test-tools/host-tool/external/cJSON/LICENSE new file mode 100644 index 000000000..78deb0406 --- /dev/null +++ b/test-tools/host-tool/external/cJSON/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/test-tools/host-tool/external/cJSON/cJSON.c b/test-tools/host-tool/external/cJSON/cJSON.c new file mode 100644 index 000000000..2776ce671 --- /dev/null +++ b/test-tools/host-tool/external/cJSON/cJSON.c @@ -0,0 +1,2750 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 10) +#error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, + const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) { + return 1; + } + + if (string1 == string2) { + return 0; + } + + for (; tolower(*string1) == tolower(*string2); + (void) string1++, string2++) { + if (*string1 == '\0') { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks { + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +static internal_hooks global_hooks = { internal_malloc, internal_free, +internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, + const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) { + return NULL; + } + + length = strlen((const char*) string) + sizeof(""); + copy = (unsigned char*) hooks->allocate(length); + if (copy == NULL) { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) + && (global_hooks.deallocate == free)) { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*) hooks->allocate(sizeof(cJSON)); + if (node) { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct { + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, + parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; + (i < (sizeof(number_c_string) - 1)) + && can_access_at_index(input_buffer, i); i++) { + switch (buffer_at_offset(input_buffer)[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } + loop_end: number_c_string[i] = '\0'; + + number = strtod((const char*) number_c_string, (char**) &after_end); + if (number_c_string == after_end) { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) { + item->valueint = INT_MAX; + } else if (number <= (double) INT_MIN) { + item->valueint = INT_MIN; + } else { + item->valueint = (int) number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) { + object->valueint = INT_MAX; + } else if (number <= (double) INT_MIN) { + object->valueint = INT_MIN; + } else { + object->valueint = (int) number; + } + + return object->valuedouble = number; +} + +typedef struct { + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) { + newsize = INT_MAX; + } else { + return NULL; + } + } else { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*) p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } else { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*) p->hooks.allocate(newsize); + if (!newbuffer) { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*) buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, + printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) { + length = sprintf((char*) number_buffer, "null"); + } else { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*) number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*) number_buffer, "%lg", &test) != 1) + || ((double) test != d)) { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*) number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int) (sizeof(number_buffer) - 1))) { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t) length + sizeof("")); + if (output_pointer == NULL) { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t) length); i++) { + if (number_buffer[i] == decimal_point) { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t) length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) { + h += (unsigned int) input[i] - '0'; + } else if ((input[i] >= 'A') && (input[i] <= 'F')) { + h += (unsigned int) 10 + input[i] - 'A'; + } else if ((input[i] >= 'a') && (input[i] <= 'f')) { + h += (unsigned int) 10 + input[i] - 'a'; + } else /* invalid */ + { + return 0; + } + + if (i < 3) { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8( + const unsigned char * const input_pointer, + const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { + /* invalid second half of the surrogate pair */ + goto fail; + } + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } else { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } else if (codepoint < 0x800) { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } else if (codepoint < 0x10000) { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } else if (codepoint <= 0x10FFFF) { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } else { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char) (utf8_length - 1); utf8_position > 0; + utf8_position--) { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char) ((codepoint | 0x80) + & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) { + (*output_pointer)[0] = (unsigned char) ((codepoint | first_byte_mark) + & 0xFF); + } else { + (*output_pointer)[0] = (unsigned char) (codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + + fail: return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, + parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) + < input_buffer->length) && (*input_end != '\"')) { + /* is escape sequence */ + if (input_end[0] == '\\') { + if ((size_t)(input_end + 1 - input_buffer->content) + >= input_buffer->length) { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) + || (*input_end != '\"')) { + goto fail; + /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) + - skipped_bytes; + output = (unsigned char*) input_buffer->hooks.allocate( + allocation_length + sizeof("")); + if (output == NULL) { + goto fail; + /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) { + if (*input_pointer != '\\') { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) { + goto fail; + } + + switch (input_pointer[1]) { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, + input_end, &output_pointer); + if (sequence_length == 0) { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*) output; + + input_buffer->offset = (size_t)(input_end - input_buffer->content); + input_buffer->offset++; + + return true; + + fail: if (output != NULL) { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, + printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) { + return false; + } + + /* empty string */ + if (input == NULL) { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) { + return false; + } + strcpy((char*) output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) { + switch (*input_pointer) { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; + (void) input_pointer++, output_pointer++) { + if ((*input_pointer > 31) && (*input_pointer != '\"') + && (*input_pointer != '\\')) { + /* normal character, copy */ + *output_pointer = *input_pointer; + } else { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*) output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*) item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, + parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, + printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, + parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, + printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, + parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, + printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { + buffer->offset++; + } + + if (buffer->offset == buffer->length) { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) + || (buffer->offset != 0)) { + return NULL; + } + + if (can_access_at_index(buffer, 4) + && (strncmp((const char*) buffer_at_offset(buffer), "\xEF\xBB\xBF", + 3) == 0)) { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}}; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + + fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, + const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, + buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + memcpy(printed, buffer->buffer, + cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + + fail: if (buffer->buffer != NULL) { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = {0, 0, 0, 0, 0, 0, {0, 0, 0}}; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, + const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) { + return false; + } + + p.buffer = (unsigned char*) buf; + p.length = (size_t) len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, + parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) + && (strncmp((const char*) buffer_at_offset(input_buffer), "null", 4) + == 0)) { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) + && (strncmp((const char*) buffer_at_offset(input_buffer), "false", + 5) == 0)) { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) + && (strncmp((const char*) buffer_at_offset(input_buffer), "true", 4) + == 0)) { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == '\"')) { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) + && ((buffer_at_offset(input_buffer)[0] == '-') + || ((buffer_at_offset(input_buffer)[0] >= '0') + && (buffer_at_offset(input_buffer)[0] <= '9')))) { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == '[')) { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == '{')) { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, + printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) { + return false; + } + + switch ((item->type) & 0xFF) { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) { + return false; + } + strcpy((char*) output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) { + return false; + } + strcpy((char*) output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) { + return false; + } + strcpy((char*) output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: { + size_t raw_length = 0; + if (item->valuestring == NULL) { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, + parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == ']')) { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) { + goto fail; + /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) { + /* start the linked list */ + current_item = head = new_item; + } else { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) { + goto fail; + /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } while (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) + || buffer_at_offset(input_buffer)[0] != ']') { + goto fail; + /* expected end of array */ + } + + success: input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + + fail: if (head != NULL) { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, + printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) { + if (!print_value(current_element, output_buffer)) { + return false; + } + update_offset(output_buffer); + if (current_element->next) { + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ','; + if (output_buffer->format) { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, + parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) + || (buffer_at_offset(input_buffer)[0] != '{')) { + goto fail; + /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == '}')) { + goto success; + /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) { + goto fail; + /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) { + /* start the linked list */ + current_item = head = new_item; + } else { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) { + goto fail; + /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) + || (buffer_at_offset(input_buffer)[0] != ':')) { + goto fail; + /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) { + goto fail; + /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } while (can_access_at_index(input_buffer, 0) + && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) + || (buffer_at_offset(input_buffer)[0] != '}')) { + goto fail; + /* expected end of object */ + } + + success: input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + + fail: if (head != NULL) { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, + printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) { + return false; + } + + /* Compose the output: */ + length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) { + if (output_buffer->format) { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) { + return false; + } + for (i = 0; i < output_buffer->depth; i++) { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*) current_item->string, + output_buffer)) { + return false; + } + update_offset(output_buffer); + + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { + return false; + } + if (current_item->next) { + *output_pointer++ = ','; + } + + if (output_buffer->format) { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, + output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) { + return false; + } + if (output_buffer->format) { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) { + return 0; + } + + child = array->child; + + while (child != NULL) { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int) size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, + const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) { + return NULL; + } + + current_element = object->child; + if (case_sensitive) { + while ((current_element != NULL) && (current_element->string != NULL) + && (strcmp(name, current_element->string) != 0)) { + current_element = current_element->next; + } + } else { + while ((current_element != NULL) + && (case_insensitive_strcmp((const unsigned char*) name, + (const unsigned char*) (current_element->string)) != 0)) { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, + const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, + const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) { + return false; + } + + child = array->child; + + if (child == NULL) { + /* list is empty, start new one */ + array->child = item; + } else { + /* append to the end */ + while (child->next) { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) +#pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*) string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) +#pragma GCC diagnostic pop +#endif + +static cJSON_bool add_item_to_object(cJSON * const object, + const char * const string, cJSON * const item, + const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) { + return false; + } + + if (constant_key) { + new_key = (char*) cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } else { + new_key = (char*) cJSON_strdup((const unsigned char*) string, hooks); + if (new_key == NULL) { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, + cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, + cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, + const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), + &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, + const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, + cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) { + return; + } + + after_inserted = get_array_item(array, (size_t) which); + if (after_inserted == NULL) { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) { + array->child = newitem; + } else { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, + cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) { + return false; + } + + if (replacement == item) { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) { + replacement->prev->next = replacement; + } + if (parent->child == item) { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, + cJSON *newitem) +{ + if (which < 0) { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t) which), + newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, + cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) + && (replacement->string != NULL)) { + cJSON_free(replacement->string); + } + replacement->string = (char*) cJSON_strdup((const unsigned char*) string, + &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, + get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, + cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, + const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + + fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*) json; + + if (json == NULL) { + return; + } + + while (*json) { + if (*json == ' ') { + json++; + } else if (*json == '\t') { + /* Whitespace characters. */ + json++; + } else if (*json == '\r') { + json++; + } else if (*json == '\n') { + json++; + } else if ((*json == '/') && (json[1] == '/')) { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) { + json++; + } + } else if ((*json == '/') && (json[1] == '*')) { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) { + json++; + } + json += 2; + } else if (*json == '\"') { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char) *json++; + while (*json && (*json != '\"')) { + if (*json == '\\') { + *into++ = (unsigned char) *json++; + } + *into++ = (unsigned char) *json++; + } + *into++ = (unsigned char) *json++; + } else { + /* All other characters. */ + *into++ = (unsigned char) *json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, + const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) + || cJSON_IsInvalid(a)) { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) { + return true; + } + + switch (a->type & 0xFF) { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) { + return true; + } + + return false; + + case cJSON_Array: { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/test-tools/host-tool/external/cJSON/cJSON.h b/test-tools/host-tool/external/cJSON/cJSON.h new file mode 100644 index 000000000..82e05af6e --- /dev/null +++ b/test-tools/host-tool/external/cJSON/cJSON.h @@ -0,0 +1,281 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + + CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols + CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) + CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + + For *nix builds that support visibility attribute, you can define similar behavior by + + setting default visibility to hidden by adding + -fvisibility=hidden (for gcc) + or + -xldscope=hidden (for sun cc) + to CFLAGS + + then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + + */ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 10 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON { + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks { + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + need to be released. With recurse!=0, it will duplicate any children connected to the item. + The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test-tools/host-tool/external/cJSON/cjson.cmake b/test-tools/host-tool/external/cJSON/cjson.cmake new file mode 100644 index 000000000..af1a9d8a1 --- /dev/null +++ b/test-tools/host-tool/external/cJSON/cjson.cmake @@ -0,0 +1,10 @@ + +set (CJSON_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${CJSON_DIR}) + + +file (GLOB_RECURSE source_all ${CJSON_DIR}/*.c) + +set (CJSON_SOURCE ${source_all}) + diff --git a/test-tools/host-tool/src/host_tool_utils.c b/test-tools/host-tool/src/host_tool_utils.c new file mode 100644 index 000000000..564bc087f --- /dev/null +++ b/test-tools/host-tool/src/host_tool_utils.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "host_tool_utils.h" +#include "shared_utils.h" + +#include +#include +#include +#include +#include + +typedef union jvalue { + bool z; + int8_t b; + uint16_t c; + int16_t s; + int32_t i; + int64_t j; + float f; + double d; +} jvalue; + +#define bh_memcpy_s(dest, dlen, src, slen) do { \ + int _ret = slen == 0 ? 0 : b_memcpy_s (dest, dlen, src, slen); \ + (void)_ret; \ + } while (0) + +static inline int16_t get_int16(const char *buf) +{ + int16_t ret; + bh_memcpy_s(&ret, sizeof(int16_t), buf, sizeof(int16_t)); + return ret; +} + +static inline uint16_t get_uint16(const char *buf) +{ + return get_int16(buf); +} + +static inline int32_t get_int32(const char *buf) +{ + int32_t ret; + bh_memcpy_s(&ret, sizeof(int32_t), buf, sizeof(int32_t)); + return ret; +} + +static inline uint32_t get_uint32(const char *buf) +{ + return get_int32(buf); +} + +char* attr_container_get_attr_begin(const attr_container_t *attr_cont, + uint32_t *p_total_length, + uint16_t *p_attr_num); + +cJSON *attr2json(const attr_container_t *attr_cont) +{ + uint32_t total_length; + uint16_t attr_num, i, j, type; + const char *p, *tag, *key; + jvalue value; + cJSON *root; + + if (!attr_cont) + return NULL; + + root = cJSON_CreateObject(); + if (!root) + return NULL; + + /* TODO: how to convert the tag? */ + tag = attr_container_get_tag(attr_cont); + if (!tag) + goto fail; + + p = attr_container_get_attr_begin(attr_cont, &total_length, &attr_num); + if (!p) + goto fail; + + for (i = 0; i < attr_num; i++) { + cJSON *obj; + + key = p + 2; + /* Skip key len and key */ + p += 2 + get_uint16(p); + type = *p++; + + switch (type) { + case ATTR_TYPE_SHORT: + bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t)); + if (NULL == (obj = cJSON_CreateNumber(value.s))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + /* another approach: cJSON_AddNumberToObject(root, key, value.s) */ + p += 2; + break; + case ATTR_TYPE_INT: + bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t)); + if (NULL == (obj = cJSON_CreateNumber(value.i))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 4; + break; + case ATTR_TYPE_INT64: + bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t)); + if (NULL == (obj = cJSON_CreateNumber(value.j))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 8; + break; + case ATTR_TYPE_BYTE: + bh_memcpy_s(&value.b, 1, p, 1); + if (NULL == (obj = cJSON_CreateNumber(value.b))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p++; + break; + case ATTR_TYPE_UINT16: + bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t)); + if (NULL == (obj = cJSON_CreateNumber(value.c))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 2; + break; + case ATTR_TYPE_FLOAT: + bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float)); + if (NULL == (obj = cJSON_CreateNumber(value.f))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 4; + break; + case ATTR_TYPE_DOUBLE: + bh_memcpy_s(&value.d, sizeof(double), p, sizeof(double)); + if (NULL == (obj = cJSON_CreateNumber(value.d))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 8; + break; + case ATTR_TYPE_BOOLEAN: + bh_memcpy_s(&value.z, 1, p, 1); + if (NULL == (obj = cJSON_CreateBool(value.z))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p++; + break; + case ATTR_TYPE_STRING: + if (NULL == (obj = cJSON_CreateString(p + sizeof(uint16_t)))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += sizeof(uint16_t) + get_uint16(p); + break; + case ATTR_TYPE_BYTEARRAY: + if (NULL == (obj = cJSON_CreateArray())) + goto fail; + cJSON_AddItemToObject(root, key, obj); + for (j = 0; j < get_uint32(p); j++) { + cJSON *item = cJSON_CreateNumber(*(p + sizeof(uint32_t) + j)); + if (item == NULL) + goto fail; + cJSON_AddItemToArray(obj, item); + } + p += sizeof(uint32_t) + get_uint32(p); + break; + } + } + + return root; + + fail: cJSON_Delete(root); + return NULL; +} + +attr_container_t *json2attr(const cJSON *json_obj) +{ + attr_container_t *attr_cont; + cJSON *item; + + if (NULL == (attr_cont = attr_container_create(""))) + return NULL; + + if (!cJSON_IsObject(json_obj)) + goto fail; + + cJSON_ArrayForEach(item, json_obj) + { + + if (cJSON_IsNumber(item)) { + attr_container_set_double(&attr_cont, item->string, + item->valuedouble); + } else if (cJSON_IsTrue(item)) { + attr_container_set_bool(&attr_cont, item->string, true); + } else if (cJSON_IsFalse(item)) { + attr_container_set_bool(&attr_cont, item->string, false); + } else if (cJSON_IsString(item)) { + attr_container_set_string(&attr_cont, item->string, + item->valuestring); + } else if (cJSON_IsArray(item)) { + int8_t *array; + int i = 0, len = sizeof(int8_t) * cJSON_GetArraySize(item); + cJSON *array_item; + + if (0 == len || NULL == (array = (int8_t *) malloc(len))) + goto fail; + memset(array, 0, len); + + cJSON_ArrayForEach(array_item, item) + { + /* must be number array */ + if (!cJSON_IsNumber(array_item)) + break; + /* TODO: if array_item->valuedouble > 127 or < -128 */ + array[i++] = (int8_t) array_item->valuedouble; + } + if (i > 0) + attr_container_set_bytearray(&attr_cont, item->string, array, + i); + free(array); + } + } + + return attr_cont; + + fail: attr_container_destroy(attr_cont); + return NULL; +} + +int g_mid = 0; + +int gen_random_id() +{ + static bool init = false; + int r; + + if (!init) { + srand(time(NULL)); + init = true; + } + + r = rand(); + g_mid = r; + + return r; +} + +char * +read_file_to_buffer(const char *filename, int *ret_size) +{ + char *buffer; + int file; + int file_size, read_size; + struct stat stat_buf; + + if (!filename || !ret_size) { + return NULL; + } + + if ((file = open(filename, O_RDONLY, 0)) == -1) { + return NULL; + } + + if (fstat(file, &stat_buf) != 0) { + close(file); + return NULL; + } + + file_size = stat_buf.st_size; + + if (!(buffer = malloc(file_size))) { + close(file); + return NULL; + } + + read_size = read(file, buffer, file_size); + close(file); + + if (read_size < file_size) { + free(buffer); + return NULL; + } + + *ret_size = file_size; + return buffer; +} + +int wirte_buffer_to_file(const char *filename, const char *buffer, int size) +{ + int file, ret; + + if ((file = open(filename, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1) + return -1; + + ret = write(file, buffer, size); + + close(file); + + return ret; +} diff --git a/test-tools/host-tool/src/host_tool_utils.h b/test-tools/host-tool/src/host_tool_utils.h new file mode 100644 index 000000000..33dafb6fd --- /dev/null +++ b/test-tools/host-tool/src/host_tool_utils.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HOST_TOOL_UTILS_H_ +#define _HOST_TOOL_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "attr_container.h" +#include "cJSON.h" + +/** + * @brief Convert attribute container object to cJSON object. + * + * @param attr the attribute container object to be converted + * + * @return the created cJSON object if not NULL, NULL means fail + * + * @warning the return object should be deleted with cJSON_Delete by caller + */ +cJSON *attr2json(const attr_container_t *attr); + +/** + * @brief Convert cJSON object to attribute container object. + * + * @param json the cJSON object to be converted + * + * @return the created attribute container object if not NULL, NULL means fail + * + * @warning the return object should be deleted with attr_container_destroy + */ +attr_container_t *json2attr(const cJSON *json); + +/** + * @brief Generate a random 32 bit integer. + * + * @return the generated random integer + */ +int gen_random_id(); + +/** + * @brief Read file content to buffer. + * + * @param filename the file name to read + * @param ret_size pointer of integer to save file size once return success + * + * @return the created buffer which contains file content if not NULL, NULL means fail + * + * @warning the return buffer should be deleted with free by caller + */ +char *read_file_to_buffer(const char *filename, int *ret_size); + +/** + * @brief Write buffer content to file. + * + * @param filename name the file name to be written + * @param buffer the buffer + * @param size size of the buffer to be written + * + * @return < 0 means fail, > 0 means the number of bytes actually written + */ +int wirte_buffer_to_file(const char *filename, const char *buffer, int size); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/test-tools/host-tool/src/main.c b/test-tools/host-tool/src/main.c new file mode 100644 index 000000000..87b170ea0 --- /dev/null +++ b/test-tools/host-tool/src/main.c @@ -0,0 +1,930 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "host_tool_utils.h" +#include "shared_utils.h" +#include "attr_container.h" +#include "coap_ext.h" +#include "cJSON.h" +#include "app_manager_export.h" /* for Module_WASM_App */ +#include "host_link.h" /* for REQUEST_PACKET */ +#include "transport.h" +#include "iagent_bsp.h" /* for bh_get_elpased_ms */ + +#define BUF_SIZE 1024 +#define TIMEOUT_EXIT_CODE 2 +#define URL_MAX_LEN 256 +#define DEFAULT_TIMEOUT_MS 5000 +#define DEFAULT_ALIVE_TIME_MS 0 + +#define CONNECTION_MODE_TCP 1 +#define CONNECTION_MODE_UART 2 + +typedef enum { + INSTALL, UNINSTALL, QUERY, REQUEST, REGISTER, UNREGISTER +} op_type; + +typedef struct { + const char *file; + const char *name; + const char *module_type; + int heap_size; + /* max timers number */ + int timers; + int watchdog_interval; +} inst_info; + +typedef struct { + const char *name; + const char *module_type; +} uninst_info; + +typedef struct { + const char *name; +} query_info; + +typedef struct { + const char *url; + int action; + const char *json_payload_file; +} req_info; + +typedef struct { + const char *urls; +} reg_info; + +typedef struct { + const char *urls; +} unreg_info; + +typedef union operation_info { + inst_info inst; + uninst_info uinst; + query_info query; + req_info req; + reg_info reg; + unreg_info unreg; +} operation_info; + +typedef struct { + op_type type; + operation_info info; +} operation; + +typedef enum REPLY_PACKET_TYPE { + REPLY_TYPE_EVENT = 0, REPLY_TYPE_RESPONSE = 1 +} REPLY_PACKET_TYPE; + +/* Package Type */ +typedef enum { + Wasm_Module_Bytecode = 0, Wasm_Module_AoT, Package_Type_Unknown = 0xFFFF +} PackageType; + +static uint32_t g_timeout_ms = DEFAULT_TIMEOUT_MS; +static uint32_t g_alive_time_ms = DEFAULT_ALIVE_TIME_MS; +static char *g_redirect_file_name = NULL; +static int g_redirect_udp_port = -1; +static int g_conn_fd; /* may be tcp or uart */ +static char *g_server_addr = "127.0.0.1"; +static int g_server_port = 8888; +static char *g_uart_dev = "/dev/ttyS2"; +static int g_baudrate = B115200; +static int g_connection_mode = CONNECTION_MODE_TCP; + +extern int g_mid; +extern unsigned char leading[2]; + +/* -1 fail, 0 success */ +static int send_request(request_t *request, bool is_install_wasm_bytecode_app) +{ + char *req_p; + int req_size, req_size_n, ret = -1; + uint16_t msg_type = REQUEST_PACKET; + + if (is_install_wasm_bytecode_app) + msg_type = INSTALL_WASM_BYTECODE_APP; + + if ((req_p = pack_request(request, &req_size)) == NULL) + return -1; + + /* leanding bytes */ + if (!host_tool_send_data(g_conn_fd, leading, sizeof(leading))) + goto ret; + + /* message type */ + msg_type = htons(msg_type); + if (!host_tool_send_data(g_conn_fd, (char *) &msg_type, sizeof(msg_type))) + goto ret; + + /* payload length */ + req_size_n = htonl(req_size); + if (!host_tool_send_data(g_conn_fd, (char *) &req_size_n, + sizeof(req_size_n))) + goto ret; + + /* payload */ + if (!host_tool_send_data(g_conn_fd, req_p, req_size)) + goto ret; + + ret = 0; + + ret: free_req_resp_packet(req_p); + + return ret; +} + +static PackageType get_package_type(const char *buf, int size) +{ + if (buf && size > 4) { + if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 's' && buf[3] == 'm') + return Wasm_Module_Bytecode; + if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 'o' && buf[3] == 't') + return Wasm_Module_AoT; + } + return Package_Type_Unknown; +} + +#define url_remain_space (sizeof(url) - strlen(url)) + +/*return: + 0: success + others: fail*/ +static int install(inst_info *info) +{ + request_t request[1] = { 0 }; + char *app_file_buf; + char url[URL_MAX_LEN] = { 0 }; + int ret = -1, app_size; + bool is_wasm_bytecode_app; + + snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name); + + if (info->module_type != NULL && url_remain_space > 0) + snprintf(url + strlen(url), url_remain_space, "&type=%s", + info->module_type); + + if (info->heap_size > 0 && url_remain_space > 0) + snprintf(url + strlen(url), url_remain_space, "&heap=%d", + info->heap_size); + + if (info->timers > 0 && url_remain_space > 0) + snprintf(url + strlen(url), url_remain_space, "&timers=%d", + info->timers); + + if (info->watchdog_interval > 0 && url_remain_space > 0) + snprintf(url + strlen(url), url_remain_space, "&wd=%d", + info->watchdog_interval); + + /*TODO: permissions to access JLF resource: AUDIO LOCATION SENSOR VISION platform.SERVICE */ + + if ((app_file_buf = read_file_to_buffer(info->file, &app_size)) == NULL) + return -1; + + init_request(request, url, COAP_PUT, + FMT_APP_RAW_BINARY, app_file_buf, app_size); + request->mid = gen_random_id(); + + if ((info->module_type == NULL || strcmp(info->module_type, "wasm") == 0) + && get_package_type(app_file_buf, app_size) == Wasm_Module_Bytecode) + is_wasm_bytecode_app = true; + else + is_wasm_bytecode_app = false; + + ret = send_request(request, is_wasm_bytecode_app); + + free(app_file_buf); + + return ret; +} + +static int uninstall(uninst_info *info) +{ + request_t request[1] = { 0 }; + char url[URL_MAX_LEN] = { 0 }; + + snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name); + + if (info->module_type != NULL && url_remain_space > 0) + snprintf(url + strlen(url), url_remain_space, "&type=%s", + info->module_type); + + init_request(request, url, COAP_DELETE, + FMT_ATTR_CONTAINER, + NULL, 0); + request->mid = gen_random_id(); + + return send_request(request, false); +} + +static int query(query_info *info) +{ + request_t request[1] = { 0 }; + int ret = -1; + char url[URL_MAX_LEN] = { 0 }; + + if (info->name != NULL) + snprintf(url, sizeof(url) - 1, "/applet?name=%s", info->name); + else + snprintf(url, sizeof(url) - 1, "/applet"); + + init_request(request, url, COAP_GET, + FMT_ATTR_CONTAINER, + NULL, 0); + request->mid = gen_random_id(); + + ret = send_request(request, false); + + return ret; +} + +static int request(req_info *info) +{ + request_t request[1] = { 0 }; + attr_container_t *payload = NULL; + int ret = -1, payload_len = 0; + + if (info->json_payload_file != NULL) { + char *payload_file; + cJSON *json; + int payload_file_size; + + if ((payload_file = read_file_to_buffer(info->json_payload_file, + &payload_file_size)) == NULL) + return -1; + + if (NULL == (json = cJSON_Parse(payload_file))) { + free(payload_file); + goto fail; + } + + if (NULL == (payload = json2attr(json))) { + cJSON_Delete(json); + free(payload_file); + goto fail; + } + payload_len = attr_container_get_serialize_length(payload); + + cJSON_Delete(json); + free(payload_file); + } + + init_request(request, (char *)info->url, info->action, + FMT_ATTR_CONTAINER, payload, payload_len); + request->mid = gen_random_id(); + + ret = send_request(request, false); + + if (info->json_payload_file != NULL && payload != NULL) + attr_container_destroy(payload); + + fail: return ret; +} + +/* + TODO: currently only support 1 url. + how to handle multiple responses and set process's exit code? + */ +static int subscribe(reg_info *info) +{ + request_t request[1] = { 0 }; + int ret = -1; +#if 0 + char *p; + + p = strtok(info->urls, ","); + while(p != NULL) { + char url[URL_MAX_LEN] = {0}; + sprintf(url, "%s%s", "/event/", p); + init_request(request, + url, + COAP_PUT, + FMT_ATTR_CONTAINER, + NULL, + 0); + request->mid = gen_random_id(); + ret = send_request(request, false); + p = strtok (NULL, ","); + } +#else + char url[URL_MAX_LEN] = { 0 }; + char *prefix = info->urls[0] == '/' ? "/event" : "/event/"; + sprintf(url, "%s%s", prefix, info->urls); + init_request(request, url, COAP_PUT, + FMT_ATTR_CONTAINER, + NULL, 0); + request->mid = gen_random_id(); + ret = send_request(request, false); +#endif + return ret; +} + +static int unsubscribe(unreg_info *info) +{ + request_t request[1] = { 0 }; + int ret = -1; +#if 0 + char *p; + + p = strtok(info->urls, ","); + while(p != NULL) { + char url[URL_MAX_LEN] = {0}; + sprintf(url, "%s%s", "/event/", p); + init_request(request, + url, + COAP_DELETE, + FMT_ATTR_CONTAINER, + NULL, + 0); + request->mid = gen_random_id(); + ret = send_request(request, false); + p = strtok (NULL, ","); + } +#else + char url[URL_MAX_LEN] = { 0 }; + sprintf(url, "%s%s", "/event/", info->urls); + init_request(request, url, COAP_DELETE, + FMT_ATTR_CONTAINER, + NULL, 0); + request->mid = gen_random_id(); + ret = send_request(request, false); +#endif + return ret; +} + +static int init() +{ + if (g_connection_mode == CONNECTION_MODE_TCP) { + int fd; + if (!tcp_init(g_server_addr, g_server_port, &fd)) + return -1; + g_conn_fd = fd; + return 0; + } else if (g_connection_mode == CONNECTION_MODE_UART) { + int fd; + if (!uart_init(g_uart_dev, g_baudrate, &fd)) + return -1; + g_conn_fd = fd; + return 0; + } + + return -1; +} + +static void deinit() +{ + close(g_conn_fd); +} + +static int parse_action(const char *str) +{ + if (strcasecmp(str, "PUT") == 0) + return COAP_PUT; + if (strcasecmp(str, "GET") == 0) + return COAP_GET; + if (strcasecmp(str, "DELETE") == 0) + return COAP_DELETE; + if (strcasecmp(str, "POST") == 0) + return COAP_POST; + return -1; +} + +static void showUsage() +{ + printf("\n"); + /*printf("Usage: host_tool [-i|--install]|[-u|--uninstall]|[-q|--query]|[-r|--request]|[-s|--register]|[-d|--deregister] ...\n");*/ + printf("Usage:\n\thost_tool -i|-u|-q|-r|-s|-d ...\n\n"); + + printf("\thost_tool -i -f \n" + "\t\t [--type=]\n" + "\t\t [--heap=]\n" + "\t\t [--timers=]\n" + "\t\t [--watchdog=]\n" + "\t\t [ ...] \n"); + printf("\thost_tool -u [ ...]\n"); + printf("\thost_tool -q[][ ...]\n"); + printf( + "\thost_tool -r -A [-p ] [ ...]\n"); + printf("\thost_tool -s [ ...]\n"); + printf("\thost_tool -d [ ...]\n\n"); + + printf( + "\t-i, --install Install an application\n"); + printf( + "\t-u, --uninstall Uninstall an application\n"); + printf( + "\t-q, --query Query all applications\n"); + printf("\t-r, --request Send a request\n"); + printf("\t-s, --register Register event(s)\n"); + printf("\t-d, --deregister De-register event(s)\n"); + printf( + "\t-f, --file Specify app binary file path\n"); + printf( + "\t-A, --action Specify action of the request\n"); + printf( + "\t-p, --payload Specify payload of the request\n"); + printf("\n"); + + printf("\n\tControl Options:\n"); + printf(" \t-S
|--address=
Set server address, default to 127.0.0.1\n"); + printf(" \t-P |--port= Set server port, default to 8888\n"); + printf(" \t-D |--uart= Set uart device, default to /dev/ttyS2\n"); + printf(" \t-B |--baudrate= Set uart device baudrate, default to 115200\n"); + + printf( + "\t-t |--timeout= Operation timeout in ms, default to 5000\n"); + printf( + "\t-a |--alive= Alive time in ms after last operation done, default to 0\n"); + printf( + "\t-o |--output= Redirect the output to output a file\n"); + printf( + "\t-U |--udp= Redirect the output to an UDP port in local machine\n"); + + printf("\nNotes:\n"); + printf("\t=name of the application\n"); + printf("\t=path of the application binary file in wasm format\n"); + printf( + "\t=resource descriptor, such as /app//res1 or /res1\n"); + printf( + "\t=event url list separated by ',', such as /event1,/event2,/event3\n"); + printf( + "\t=action of the request, can be PUT, GET, DELETE or POST (case insensitive)\n"); + printf("\t=path of the payload file in json format\n"); + printf("\t=Type of app. Can be 'wasm'(default) or 'jeff'\n"); + printf("\t=Heap size of app.\n"); + printf("\t=Max timers number app can use.\n"); + printf("\t=Watchdog interval in ms.\n"); +} + +#define CHECK_DUPLICATE_OPERATION do{ \ + if (operation_parsed) \ + { \ + showUsage(); \ + return false; \ + } \ +}while(0) + +#define ERROR_RETURN do{ \ + showUsage(); \ + return false; \ +}while(0) + +#define CHECK_ARGS_UNMATCH_OPERATION(op_type) do{ \ + if (!operation_parsed || op->type != op_type) \ + { \ + showUsage(); \ + return false; \ + } \ +}while(0) + +static bool parse_args(int argc, char *argv[], operation *op) +{ + int c; + bool operation_parsed = false; + bool conn_mode_parsed = false; + + while (1) { + int optIndex = 0; + static struct option longOpts[] = { + { "install", required_argument, NULL, 'i' }, + { "uninstall", required_argument, NULL, 'u' }, + { "query", optional_argument, NULL, 'q' }, + { "request", required_argument, NULL, 'r' }, + { "register", required_argument, NULL, 's' }, + { "deregister", required_argument, NULL, 'd' }, + { "timeout", required_argument, NULL, 't' }, + { "alive", required_argument, NULL, 'a' }, + { "output", required_argument, NULL, 'o' }, + { "udp", required_argument, NULL, 'U' }, + { "action", required_argument, NULL, 'A' }, + { "file", required_argument, NULL, 'f' }, + { "payload", required_argument, NULL, 'p' }, + { "type", required_argument, NULL, 0 }, + { "heap", required_argument, NULL, 1 }, + { "timers", required_argument, NULL, 2 }, + { "watchdog", required_argument, NULL, 3 }, + { "address", required_argument, NULL, 'S' }, + { "port", required_argument, NULL, 'P' }, + { "uart_device",required_argument, NULL, 'D' }, + { "baudrate", required_argument, NULL, 'B' }, + { "help", required_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "i:u:q::r:s:d:t:a:o:U:A:f:p:S:P:D:B:h", + longOpts, &optIndex); + if (c == -1) + break; + + switch (c) { + case 'i': + CHECK_DUPLICATE_OPERATION; + op->type = INSTALL; + op->info.inst.name = optarg; + operation_parsed = true; + break; + case 'u': + CHECK_DUPLICATE_OPERATION; + op->type = UNINSTALL; + op->info.uinst.name = optarg; + operation_parsed = true; + break; + case 'q': + CHECK_DUPLICATE_OPERATION; + op->type = QUERY; + op->info.query.name = optarg; + break; + case 'r': + CHECK_DUPLICATE_OPERATION; + op->type = REQUEST; + op->info.req.url = optarg; + operation_parsed = true; + break; + case 's': + CHECK_DUPLICATE_OPERATION; + op->type = REGISTER; + op->info.reg.urls = optarg; + operation_parsed = true; + break; + case 'd': + CHECK_DUPLICATE_OPERATION; + op->type = UNREGISTER; + op->info.unreg.urls = optarg; + operation_parsed = true; + break; + case 't': + g_timeout_ms = atoi(optarg); + break; + case 'a': + g_alive_time_ms = atoi(optarg); + break; + case 'o': + g_redirect_file_name = optarg; + break; + case 'U': + g_redirect_udp_port = atoi(optarg); + break; + case 'A': + CHECK_ARGS_UNMATCH_OPERATION(REQUEST); + op->info.req.action = parse_action(optarg); + break; + case 'f': + CHECK_ARGS_UNMATCH_OPERATION(INSTALL); + op->info.inst.file = optarg; + break; + case 'p': + CHECK_ARGS_UNMATCH_OPERATION(REQUEST); + op->info.req.json_payload_file = optarg; + break; + /* module type */ + case 0: + /* TODO: use bit mask */ + /* CHECK_ARGS_UNMATCH_OPERATION(INSTALL | UNINSTALL); */ + if (op->type == INSTALL) + op->info.inst.module_type = optarg; + else if (op->type == UNINSTALL) + op->info.uinst.module_type = optarg; + break; + /* heap */ + case 1: + CHECK_ARGS_UNMATCH_OPERATION(INSTALL); + op->info.inst.heap_size = atoi(optarg); + break; + /* timers */ + case 2: + CHECK_ARGS_UNMATCH_OPERATION(INSTALL); + op->info.inst.timers = atoi(optarg); + break; + /* watchdog */ + case 3: + CHECK_ARGS_UNMATCH_OPERATION(INSTALL); + op->info.inst.watchdog_interval = atoi(optarg); + break; + case 'S': + if (conn_mode_parsed) { + showUsage(); + return false; + } + g_connection_mode = CONNECTION_MODE_TCP; + g_server_addr = optarg; + conn_mode_parsed = true; + break; + case 'P': + g_server_port = atoi(optarg); + break; + case 'D': + if (conn_mode_parsed) { + showUsage(); + return false; + } + g_connection_mode = CONNECTION_MODE_UART; + g_uart_dev = optarg; + conn_mode_parsed = true; + break; + case 'B': + g_baudrate = parse_baudrate(atoi(optarg)); + break; + case 'h': + showUsage(); + return false; + default: + showUsage(); + return false; + } + } + + /* check mandatory options for the operation */ + switch (op->type) { + case INSTALL: + if (NULL == op->info.inst.file || NULL == op->info.inst.name) + ERROR_RETURN; + break; + case UNINSTALL: + if (NULL == op->info.uinst.name) + ERROR_RETURN; + break; + case QUERY: + break; + case REQUEST: + if (NULL == op->info.req.url || op->info.req.action <= 0) + ERROR_RETURN; + break; + case REGISTER: + if (NULL == op->info.reg.urls) + ERROR_RETURN; + break; + case UNREGISTER: + if (NULL == op->info.unreg.urls) + ERROR_RETURN; + break; + default: + return false; + } + + return true; +} + +/* + return value: + < 0: not complete message + REPLY_TYPE_EVENT: event(request) + REPLY_TYPE_RESPONSE: response + */ +static int preocess_reply_data(const char *buf, int len, + imrt_link_recv_context_t *ctx) +{ + int result = -1; + const char *pos = buf; + +#if DEBUG + int i = 0; + for (; i < len; i++) { + printf(" 0x%02x", buf[i]); + } + printf("\n"); +#endif + + while (len-- > 0) { + result = on_imrt_link_byte_arrive((unsigned char) *pos++, ctx); + switch (result) { + case 0: { + imrt_link_message_t *message = &ctx->message; + if (message->message_type == RESPONSE_PACKET) + return REPLY_TYPE_RESPONSE; + if (message->message_type == REQUEST_PACKET) + return REPLY_TYPE_EVENT; + break; + } + default: + break; + } + } + return -1; +} + +static response_t * +parse_response_from_imrtlink(imrt_link_message_t *message, response_t *response) +{ + if (!unpack_response(message->payload, message->payload_size, response)) + return NULL; + + return response; +} + +static request_t * +parse_event_from_imrtlink(imrt_link_message_t *message, request_t *request) +{ + if (!unpack_request(message->payload, message->payload_size, request)) + return NULL; + + return request; +} + +static void output(const char *header, attr_container_t *payload, int foramt, + int payload_len) +{ + cJSON *json = NULL; + char *json_str = NULL; + + /* output the header */ + printf("%s", header); + if (g_redirect_file_name != NULL) + wirte_buffer_to_file(g_redirect_file_name, header, strlen(header)); + if (g_redirect_udp_port > 0 && g_redirect_udp_port < 65535) + udp_send("127.0.0.1", g_redirect_udp_port, header, strlen(header)); + + if (foramt != FMT_ATTR_CONTAINER || payload == NULL || payload_len <= 0) + return; + + if ((json = attr2json(payload)) == NULL) + return; + + if ((json_str = cJSON_Print(json)) == NULL) { + cJSON_Delete(json); + return; + } + + /* output the payload as json format */ + printf("%s", json_str); + if (g_redirect_file_name != NULL) + wirte_buffer_to_file(g_redirect_file_name, json_str, strlen(json_str)); + if (g_redirect_udp_port > 0 && g_redirect_udp_port < 65535) + udp_send("127.0.0.1", g_redirect_udp_port, json_str, strlen(json_str)); + + free(json_str); + cJSON_Delete(json); +} + +static void output_response(response_t *obj) +{ + char header[32] = { 0 }; + snprintf(header, sizeof(header), "\nresponse status %d\n", obj->status); + output(header, obj->payload, obj->fmt, obj->payload_len); +} + +static void output_event(request_t *obj) +{ + char header[256] = { 0 }; + snprintf(header, sizeof(header), "\nreceived an event %s\n", obj->url); + output(header, obj->payload, obj->fmt, obj->payload_len); +} + +int main(int argc, char *argv[]) +{ + int ret; + imrt_link_recv_context_t recv_ctx = { 0 }; + char buffer[BUF_SIZE] = { 0 }; + uint32_t last_check, total_elpased_ms = 0; + bool is_responsed = false; + operation op; + + memset(&op, 0, sizeof(op)); + + if (!parse_args(argc, argv, &op)) + return -1; + + //TODO: reconnect 3 times + if (init() != 0) + return -1; + + switch (op.type) { + case INSTALL: + ret = install((inst_info *) &op.info.inst); + break; + case UNINSTALL: + ret = uninstall((uninst_info *) &op.info.uinst); + break; + case QUERY: + ret = query((query_info *) &op.info.query); + break; + case REQUEST: + ret = request((req_info *) &op.info.req); + break; + case REGISTER: + ret = subscribe((reg_info *) &op.info.reg); + break; + case UNREGISTER: + ret = unsubscribe((unreg_info *) &op.info.unreg); + break; + default: + goto ret; + } + + if (ret != 0) + goto ret; + + bh_get_elpased_ms(&last_check); + + while (1) { + int result = 0; + fd_set readfds; + struct timeval tv; + + total_elpased_ms += bh_get_elpased_ms(&last_check); + + if (!is_responsed) { + if (total_elpased_ms >= g_timeout_ms) { + output("operation timeout\n", NULL, 0, 0); + ret = TIMEOUT_EXIT_CODE; + goto ret; + } + } else { + if (total_elpased_ms >= g_alive_time_ms) { + /*ret = 0;*/ + goto ret; + } + } + + if (g_conn_fd == -1) { + if (init() != 0) { + sleep(1); + continue; + } + } + + FD_ZERO(&readfds); + FD_SET(g_conn_fd, &readfds); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + result = select(FD_SETSIZE, &readfds, NULL, NULL, &tv); + + if (result < 0) { + if (errno != EINTR) { + printf("Error in select, errno: 0x%x\n", errno); + ret = -1; + goto ret; + } + } else if (result == 0) { /* select timeout */ + } else if (result > 0) { + int n; + if (FD_ISSET(g_conn_fd, &readfds)) { + int reply_type = -1; + + n = read(g_conn_fd, buffer, BUF_SIZE); + if (n <= 0) { + g_conn_fd = -1; + continue; + } + + reply_type = preocess_reply_data((char *) buffer, n, &recv_ctx); + + if (reply_type == REPLY_TYPE_RESPONSE) { + response_t response[1] = { 0 }; + + parse_response_from_imrtlink(&recv_ctx.message, response); + + if (response->mid != g_mid) { + /* ignore invalid response */ + continue; + } + + is_responsed = true; + ret = response->status; + output_response(response); + + if (op.type == REGISTER || op.type == UNREGISTER) { + /* alive time start */ + total_elpased_ms = 0; + bh_get_elpased_ms(&last_check); + } + } else if (reply_type == REPLY_TYPE_EVENT) { + request_t event[1] = { 0 }; + + parse_event_from_imrtlink(&recv_ctx.message, event); + + if (op.type == REGISTER || op.type == UNREGISTER) { + output_event(event); + } + } + } + } + } /* end of while(1) */ + + ret: if (recv_ctx.message.payload != NULL) + free(recv_ctx.message.payload); + + deinit(); + + return ret; +} diff --git a/test-tools/host-tool/src/transport.c b/test-tools/host-tool/src/transport.c new file mode 100644 index 000000000..0ccb62763 --- /dev/null +++ b/test-tools/host-tool/src/transport.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "transport.h" + +#define SA struct sockaddr + +unsigned char leading[2] = { 0x12, 0x34 }; + +bool tcp_init(const char *address, uint16_t port, int *fd) +{ + int sock; + struct sockaddr_in servaddr; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) + return false; + + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr(address); + servaddr.sin_port = htons(port); + + if (connect(sock, (SA*) &servaddr, sizeof(servaddr)) != 0) + return false; + + *fd = sock; + return true; +} + +int parse_baudrate(int baud) +{ + switch (baud) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; + case 2500000: + return B2500000; + case 3000000: + return B3000000; + case 3500000: + return B3500000; + case 4000000: + return B4000000; + default: + return -1; + } +} + +bool uart_init(const char *device, int baudrate, int *fd) +{ + int uart_fd; + struct termios uart_term; + + uart_fd = open(device, O_RDWR | O_NOCTTY); + + if (uart_fd <= 0) + return false; + + memset(&uart_term, 0, sizeof(uart_term)); + uart_term.c_cflag = baudrate | CS8 | CLOCAL | CREAD; + uart_term.c_iflag = IGNPAR; + uart_term.c_oflag = 0; + + /* set noncanonical mode */ + uart_term.c_lflag = 0; + uart_term.c_cc[VTIME] = 30; + uart_term.c_cc[VMIN] = 1; + tcflush(uart_fd, TCIFLUSH); + + if (tcsetattr(uart_fd, TCSANOW, &uart_term) != 0) { + close(uart_fd); + return false; + } + + *fd = uart_fd; + + return true; +} + +bool udp_send(const char *address, int port, const char *buf, int len) +{ + int sockfd; + struct sockaddr_in servaddr; + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) + return false; + + memset(&servaddr, 0, sizeof(servaddr)); + + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(port); + servaddr.sin_addr.s_addr = INADDR_ANY; + + sendto(sockfd, buf, len, MSG_CONFIRM, (const struct sockaddr *) &servaddr, + sizeof(servaddr)); + + close(sockfd); + + return true; +} + +bool host_tool_send_data(int fd, const char *buf, unsigned int len) +{ + int cnt = 0; + ssize_t ret; + + if (fd == -1 || buf == NULL || len <= 0) { + return false; + } + + resend: ret = write(fd, buf, len); + + if (ret == -1) { + if (errno == ECONNRESET) { + close(fd); + } + + // repeat sending if the outbuffer is full + if (errno == EAGAIN || errno == EWOULDBLOCK) { + if (++cnt > 10) { + close(fd); + return false; + } + sleep(1); + goto resend; + } + } + + return (ret == len); +} + +#define SET_RECV_PHASE(ctx, new_phase) {ctx->phase = new_phase; ctx->size_in_phase = 0;} + +/* + * input: 1 byte from remote + * output: parse result + * return: -1 invalid sync byte + * 1 byte added to buffer, waiting more for complete packet + * 0 completed packet + * 2 in receiving payload + */ +int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx) +{ + if (ctx->phase == Phase_Non_Start) { + if (ctx->message.payload) { + free(ctx->message.payload); + ctx->message.payload = NULL; + ctx->message.payload_size = 0; + } + + if (leading[0] == ch) { + ctx->phase = Phase_Leading; + } else { + return -1; + } + } else if (ctx->phase == Phase_Leading) { + if (leading[1] == ch) { + SET_RECV_PHASE(ctx, Phase_Type); + } else { + ctx->phase = Phase_Non_Start; + return -1; + } + } else if (ctx->phase == Phase_Type) { + unsigned char *p = (unsigned char *) &ctx->message.message_type; + p[ctx->size_in_phase++] = ch; + + if (ctx->size_in_phase == sizeof(ctx->message.message_type)) { + ctx->message.message_type = ntohs(ctx->message.message_type); + SET_RECV_PHASE(ctx, Phase_Size); + } + } else if (ctx->phase == Phase_Size) { + unsigned char * p = (unsigned char *) &ctx->message.payload_size; + p[ctx->size_in_phase++] = ch; + + if (ctx->size_in_phase == sizeof(ctx->message.payload_size)) { + ctx->message.payload_size = ntohl(ctx->message.payload_size); + SET_RECV_PHASE(ctx, Phase_Payload); + + if (ctx->message.payload) { + free(ctx->message.payload); + ctx->message.payload = NULL; + } + + /* no payload */ + if (ctx->message.payload_size == 0) { + SET_RECV_PHASE(ctx, Phase_Non_Start); + return 0; + } + + if (ctx->message.payload_size > 1024 * 1024) { + SET_RECV_PHASE(ctx, Phase_Non_Start); + return -1; + } + + ctx->message.payload = (char *) malloc(ctx->message.payload_size); + SET_RECV_PHASE(ctx, Phase_Payload); + } + } else if (ctx->phase == Phase_Payload) { + ctx->message.payload[ctx->size_in_phase++] = ch; + + if (ctx->size_in_phase == ctx->message.payload_size) { + SET_RECV_PHASE(ctx, Phase_Non_Start); + return 0; + } + + return 2; + } + + return 1; +} diff --git a/test-tools/host-tool/src/transport.h b/test-tools/host-tool/src/transport.h new file mode 100644 index 000000000..6d978d792 --- /dev/null +++ b/test-tools/host-tool/src/transport.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEPS_APP_MGR_HOST_TOOL_SRC_TRANSPORT_H_ +#define DEPS_APP_MGR_HOST_TOOL_SRC_TRANSPORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* IMRT link message between host and WAMR */ +typedef struct { + unsigned short message_type; + unsigned long payload_size; + char *payload; +} imrt_link_message_t; + +/* The receive phase of IMRT link message */ +typedef enum { + Phase_Non_Start, Phase_Leading, Phase_Type, Phase_Size, Phase_Payload +} recv_phase_t; + +/* The receive context of IMRT link message */ +typedef struct { + recv_phase_t phase; + int size_in_phase; + imrt_link_message_t message; +} imrt_link_recv_context_t; + +/** + * @brief Send data to WAMR. + * + * @param fd the connection fd to WAMR + * @param buf the buffer that contains content to be sent + * @param len size of the buffer to be sent + * + * @return true if success, false if fail + */ +bool host_tool_send_data(int fd, const char *buf, unsigned int len); + +/** + * @brief Handle one byte of IMRT link message + * + * @param ch the one byte from WAMR to be handled + * @param ctx the receive context + * + * @return -1 invalid sync byte + * 1 byte added to buffer, waiting more for complete packet + * 0 completed packet + * 2 in receiving payload + */ +int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx); + +/** + * @brief Initialize TCP connection with remote server. + * + * @param address the network address of peer + * @param port the network port of peer + * @param fd pointer of integer to save the socket fd once return success + * + * @return true if success, false if fail + */ +bool tcp_init(const char *address, uint16_t port, int *fd); + +/** + * @brief Initialize UART connection with remote. + * + * @param device name of the UART device + * @param baudrate baudrate of the device + * @param fd pointer of integer to save the uart fd once return success + * + * @return true if success, false if fail + */ +bool uart_init(const char *device, int baudrate, int *fd); + +/** + * @brief Parse UART baudrate from an integer + * + * @param the baudrate interger to be parsed + * + * @return true if success, false if fail + * + * @par + * @code + * int baudrate = parse_baudrate(9600); + * ... + * uart_term.c_cflag = baudrate; + * ... + * @endcode + */ +int parse_baudrate(int baud); + +/** + * @brief Send data over UDP. + * + * @param address network address of the remote + * @param port network port of the remote + * @param buf the buffer that contains content to be sent + * @param len size of the buffer to be sent + * + * @return true if success, false if fail + */ +bool udp_send(const char *address, int port, const char *buf, int len); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* DEPS_APP_MGR_HOST_TOOL_SRC_TRANSPORT_H_ */

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 WXkwrZVzeP7Vj^dJ~!!x z?_uus>L*Pps^83|^TsM4cg@omUVl^yGgMKnlPxnmO^gZV;L@H3JFn5io#ak&`tu75 z?6-2`SALE2{`SQz8?Te@fYUwD_cOX%6dMS8y;B$cX%QuFpsMGodg}Z-tiO5p^#A_3 zbk+fV6l3+a2(h_wciM2X+tQsNR)*!tk0uXlftPCb&LEYnteo(nV?OIqy&oYY$CG;>)csBAVQ{)r3Ql!CLO!b&uGyKh3zrCnaH8!sJY9 zwrbHbTW<`u`MH0dpme=m<=v#&X%GioOwA%wAj~h_L9`zgOOL7zlLe_H>&~Q65y4kP ze6;g^A`Fpx|D`{vFP6F+;5{eU$Su@U&kuLk)nOc`QtIDKi|biK-bB1IZVmMiWe$EQ)KcyQaYwc=6;wq`-}`3o8LFi$f9ovt3|_|?+~U}+`QtLhb9Gzrzrx5M zCOfgraxxm~Zk0{paUo8^Ij^ z$LDeeHG(4xN#n>MwVZ>+L%VnGKV|#%4NO<^@VS>+49dm+T=yRw&_8_Vqw8lIaBhSHKHkJGz|G8+`89hL>iBknMSa_RCvXc)g>i1WOV0 zGEVXSgrg;^Q=aXiO~3JaSg)O?SVBBaohSV{pexsoW;cnCsHL}!feeq|fY9OTFzvfG z#K~OE{#L#(S5h}ig5-IsuVwS}59CY@yyZv%^};6Zmr1+$b5{InXW6#*=)b&yfVi=Y zqaIii`6)9^K8G&suAT%jTkIDOPVdAm`$O^Iub-{R;9fLcuZ+Uw+X*-I2n-$(fB*CL z-@D8li~z`D8GDr*QK}&$FV?Q-=%N4GVL4R#aL){ch z1egJ$?vgi+Hy4$755h8Sxm$wnHfY@75ngxJ#_F$a*jOJtA+|eYfyLf^-vrfbb$kun z9rH`f`ar7mW25iqD?rE$17bj-&ki{L-=0^m>ziZD04>S6pzkyVHWrG5sZ`hu+3jdbC?=+Zi=e-m=CKo}A z<|woUR{iw{301QTWRS>{NAL4TjpKl&k|fbgcjfmzRaR1qF*r(a{2`KJT%|Eg-d|Ql zz3f*>t90}!_2}vsov~@=MAaeuHqzx2@Fqt(*x&-CwcYi7#?aICcvS;1HkvtK=705t zHLtb_F9#&KhmW?Z*FtdXlAS^Xif1V^K7=QJjhNpoSC9rqk``r`WwvODzVdORLRNqq!tRCx-z2XMi^x-P}-U%Yj^iT|*{F~r$1P)KPCJ4)Fv7FB=hUY4#_ zD}2@|k4Ru)49TQ=qWSZBxc>EeF4Z9aCNO@2d$ak@6JpJ4Tp?qAs;nXO0da1I>yCs^ zAN;xkcFO5t?!DSq25>bBrn7YSKHvP!z%MHZwnSCd%sTJ+k~b12H5aA+VSsDCvMv3e zu32OLHd#_orqwBM|F8<#LUIE~L(lAd);|x|3RigxKGHi|jmiPC#ok9Y!&8M#h4d^S zYltmVqB?8lKDeQ$ju-IF(`F}^`Q!ifb4{Q0zC?SA3ci@ET&2j!-c_7y-DzveGG?IT zsfxr^0a=WhWRujpJ)UPJ{pD~-x9d?QVdNo-j2`hGI253!cI=81|!a;Hfog3$*%si zhnSa6aP#05%UnzY5QC6&xH~6KBaX$E9buXHI(G0q>kkq=m71-NKx*@omeC>3`Dsfj zks1J56jHdWzj(L-bsQVR8lWnm;rs87Zz+N!FlvV+;33;S_PDM0)#u!$1;KExtoU6+ zf=lx(4DdqdIrKn574`E=I~q~(fLZ3T+iJ3g@Jt8gceVUdxz?(t3#y~jPc8s4LJ#DY z<@69;ulkT=e@XOyu`)eRGZ!7wKOA6|nKZh%I0D-`?h8d#%$ zC}|W(ayd1;_KUWk6md3mF$r90;eD0eA(x5n#Qck(ekBFwUxfxc%H2$Q0?@m9A(xYn z2Z$$Q z`a48=ouUj0x|!Fqo)rkJR{41ht^?N7j(wjD_?z@GOy#bp;lH?6P4+4Rb2=A)G}vQf zQYo!^JNM~2|8RERN2|U7Gl*#)QR+kJ4JA}^VtM>BmyS|IQgL2_4gYXkk&xxs)*aSn zZ|({y`BmAq0Dy&zQi-G=HwKx7sz&ij%74AjKzX|VYQ!HWCZB9xQ_J?lr3&`ER*d*)~}#nzZ;exU49%va>?^$Lz-+ncjVz@8EwN)o|{_ z?7KTdaJ-cS94(dw;`;bjRA!>Ax^rSGJ>%V;j+`>}mBHK;uL`41ES*~8dv*xv3O`-K zB@RQ`Hx|7)go_134ms_^-&0&H7xV4RsaE4)rep5Hd^-&jm)k<_r?PhdU~6@yq&>}; z>26FXp2{~m;LqX_e?Yr#x*NeC!i0h_58tc!0xIfvUhPKvaBaw9ZGjJ*h1T*yU%3u z>EjAJj~g8Nl`r#qQWbOBl=5!8u^4J@?Y7d4tG07UyMDdyeGR$9mmmdL`#{VHK)YuN zNl5oFJZ^)ne5K+7fq;WQH2^tek{r+1nu)-PA>uLr^A1|7W>NVJ;5C-Sr@RptHfM1U z^yRq>`yaH{DF9GsslMJO;fahq?a+!ZZ&Rh*AILtkR*dZTIiV!Hh-ZmKu`R8wX4f}R zG}j?EDBI1%-TML%CM_mJ1_# zslvYC-sJM+Wey$r?y*k=W*^4}Z*Dss9CK7Sbt_N8dzuBbb7}0!1L>?GKc~K`kFL(K&v;{rvqx$i1zn!Jl7cx5)Nq;niQte-?ej0obE-pGctbAjWfY95I71|*f=g?{NfXF-bK z5!eeHVL6)a1Md-xux#59-aax(tuqqj=rUANOyn$BVjCOy@NM1dAQcZxWwrUGx58@w z)?`_Ea@8hlRsxmBz{Yh&%kMRv5a^cAo^r5!)7GYj+UF@~K5*{AT)H~*ccAOnir?X`-&K z!&|Ncz4dGUTWbK;9#Uy{C^;xrqvx4ENV@y~a~rCJ-pe5dWTd16J?UN$6C~!bTL*JY z8N_Ggb}Fwgm_rXXX`0|AYT?(=PSgdIZI?Oqlxz2s)caseA+@-gY6j<&U4~V!6WMj8 z6*WI)C43YZm^{$6gy(NoSamDI6KR4g>Vg0(nSq!pgQKYVUM7}kDKR06=R#Lsy>eHT zm$#htycqiV?n%sDeCv>kra9b=;F&K>1$2RI8bF$w$Xox=1tM~Z=EP=&W%b22fjemK zgLN^WSqa!ucDA*5d3a$X=f8Nqf`5rv6XV$=G42lY_iaW8!gx%rI>H7ao~xFWqSm}h znU%529D3sAE@Xp|=|>gZ{?~hZb!7zi_pR~;?2b2tQy;oqRmu>ZHNC2omLOa1oaEWf zUT|t=W3`m3RAIeIs?%VN!J%8*2W^NObwDUnRlTr72r}n#2)PfYdmTZHhg@~a{fJ4R zC!aq$-Xpn9;weNrS?zksv-O7Q=<_!BegnqCK1Zt$Fmi**91YNl+dpmL<|+k<<5 zoXX7++V(g@Jg2SyUEE^9aG2Au)!{f0{UXs1u!b!LTUcDI+BT#CDt#oK0nCj&aje+&L9zmWf*fb#Q=@X-NNC#SeI9zC@^p(5@2#I{JVELIX?Z5B_U%kuJYL8Dawc5pW8JYCU0*aJf{>k`HX%L z91<16n4!$j-kTjhygayZq-Z%m^sVCgH*XzlzgT+)yXn&4(N8mv(yBM}?Sx+SqV6hn z^DNZhoKQ>{Uc#RI*MUyKyA2p)8DjvfQ(tP`8I{j7@jO174^O50^(Hop4U%}8_3T8T zN2?h?bOL)5TGjh5CV-20F!qBZ(kUblz|k!-KjCQ1zrfL?HqpLWe=Z&q@`?Jou;u0D z!S`{CYt_c4Ry~Jn5L1*y*W1Px5dF&xI9x{g9X-6=D~1?Q533N>#r)y-WpqgI@5zOb zX4AvfLWpe-2>t|T!HLfj`CSlVwR|o0zCT4TpgBj~fM>Wr)l&ms=eNu1ox)}IXmWO- z8MbsfS72pk|7t+V^695%WJKW)*y%Oi7rtM2dEnw!;J~MZ|2%N^d^x_XC>fcLp*oPm zz*?p0L33Opp;Mf<8p@s2sg1LV-nZ=J0?pq_xz+s;`|_OVXK*~x_#-&}nf9uIJWv)L zef`>mm6H?FU+pj@Uv9oUw5m#M*|I7R@f&)a`p}e9DK%Bnv`z9*nLiRNkRTKFR_7T= zcLzymnxF8>SeRBQP$n`{+4OFIemLLqVEhCwi^aLKPJ<6|k#=3ev*Ibah@_Gn7QTI$ zT~GcIZsJhY+q!qbQMWJmJ6Ni{7Qdj8&cW_~cN+W=hTrjeXJkV;feellF&_sFy=NKl zD=(cSPIU9>4Ji4I$ouRGs=R^z_c!e)1s;^WRA{5yIfzt;v5_>GY)Nw*d(L761L=`i z(d{=k5Cy;LXMfIR<*~3hwK~R8$e6&7l^{;d8k7R&L{XG{6G(!P+u-}|H}SyyqsZI9 zzXhB^yejf`R(BDQP}N1c0E;1bpZy+ns<0j45bI;j`*a_x zyO90_Q0`sAsk|%9c zgM}FTRzk&6kohndJNJc%(u@@L4yWqP?y4y()5 zE#C|H9>cyt?prY7(eS}f<=%Q&_uRUqbb+wkchqD zWH*6h>>SRH`o5o3atPm#@5z}@!-r~qhy_v&JC*<#2mgF~{07DgN#XdTB0(7<2Sz`f z`kIh-<&=6TlWMYkL@OsVbX&WOoV9qW%WXB*v=K1{P>PtZ@^)Qj@1X7*Rwdurh{J zZz9rA+dDwakr(+BmZxb%%-1P@l*dmuhAsbkt@kp&(0{Igg*|M?}sE%|u@X=&*S^Iq>%9+6PZ6zrr&30UUFX44^!v z4E~rlm6j^=;c@wLtCk=u~--?J(J3?i#LTZM90U3-7xu^LEn#te){-8zmpnOcR+JItWSHXDdv-( z;q@P%%H0w>fF}SZeef69uEr7KP^cRU7A(J8Kl%>Kclr}nucxgT>+$ZRF6hD)N@(v( zNWp^5s^rn9fvBoLy)(j6nn)?+~lETLX`OLP1= zg7)3iNi=?M#k-O1H)1{SWE^f0u9#u;&N{5WodAeHs_hIX>-1MonF8yMV+7>(|G+hx zmrfD5L80_#5gCHjSoP2&aim)WhNW4xuhn9Nf7T6;P1#v}Hv(TDal0Sxlg7wzt=}vs zX8d#C($dIYuXT7bzjZ$!y|Zm~PVA&)ZSrSNi&-F=8bchU3iH~3rc-J}$dTNbEE5dH zH9f?UGkUQi?24HT@#0rXc^I1CpDfE~(OaM`h--;T4~E?&YORl4v z<+ebWbfwe*!|q{=DZumU_!AH)d^wd;crx3RQzUclEd#K8HBR`=sO`7}6T)lWR|(*? zw1H?R0*T;MG_9q#4)$b&n}w&c`(2xsoq!XC)}2>~OOVj^M^5?@73E_PhT2YQ)AczZ zDmgaE-7p7_#VZ_Vo|S=&v<02#DV_Y-9}K}fzc$dvX3C146=~&vc=1ps_lt~*af7Cn z<0O1Jbd~$ERJrJNyfG^4Z#9ob;*z1iokI$G@s9Lq+hha1aDhF18&I%Yq zi*?0PN0>japHWk=T zq<=ECu!pvCNBd4y(ZnZJC-0GQ@xjH7l5xNa0eReLq732tq4`SPc@zLJ*#Lk^JI;J? zybvIhUPGyUGIjut>{}t4nL>`d6!AR4uUiP(BA7i8CaG`B!}1?zstlWRYM&VxcGCdu-OvJai_bD3t~DLj5Hc|eAguq*3t(Q2o>DJY z4mGH-+A&lR!$?ByBp9%pV?Q=v?~A!En@Wbe@rI@`qvC0>rODykx##XE18Yx`JeIuJmF_B_#PcwC%4ww|XxbhZoF;PqaW!|-}&dwY`7gE)& zX=#WDILJ|yqeoZ5Dlh*$QIP4`Cc3fdPhRIrlgl@rQO}hzBQwUz7iavM*80 zWvt`0ppoEu>(6*Ll1;gUKIQWrtRg+A{d~*U(Mjoti-8iL;!VgttNVrM!uxA8!#0D^ z0;3*epBuDj{MHwG?~+8qkLL5&1p0&nJWroA>3V2;wpec<}VTO;g!l;mW&? zn>5f2%ZsnJq~Pc?R8~wZ&duw7Hn@=Yk$Kj5_jN*iQe(g#DHpnntKbr~0}uH4I!D1? z5h-6^79OrI2MxM!U zK>3fDAoc}y<@ofAucdj?WQFNYC1mp@##*`Jtt@ofX~e@!oi`Z|HVM2};&qTsR`=I7 z)vX7F4sK<^ScomRO16ig7T`w?Z=Z%@WoSm^-#_Ck@?Z70)SO+kM1R`SsIc*>!REP8 zA^!ds!L*UW)0>-3fW?3Had5Arym}}P68;GY3O^zRA!gpUdXq(BmW@v5rduHn2qK*t zZbnZsuO+gTl6R*}^eiyjBWs-olOp5RE;lS;!>Z{zF|Df9#7DQGW@Xa>(rlLJ3ncM% zMiff@yH)qul1Mr9#p`ZLprJnnp)-UENm}djj!6c?*Pl7uQt54Y9z~9*eWwxq_yMc1 zDsjsn%@Q@B*H3V+#lFY!7TT+@fC{jkZKU~1OI?$IO?F=+RkP=kN4^WPT{ejK4AM&U zCUF54if)Z|Qq@F`3={JstxK4{p z{ESTfzegtF@{=`4`Pn(rWq%U#Bb=?!;f>^K-~>bk z8ae$shDt&nb_L>gT)FuDA7n1--#_&A7RU46pN6j~I@AhkUZhl2U0{$j_>+?;dnLcB zS|%5_Wpv_CsbeMmvwSpBV?y3;u<@YJo#qOA!s0E(V_8D=l z>>>Mm61?QuWX)s?9!EFj=I>W{_hRW(de@^nY~Lk(qzk79mI8W3B3h3W>2fqF1ckeG z#i{~72TNz20Q>0xV8+pDSo6w#bDYL6p}v!n=M<`1NPX3_=*IKE;#JJ+iSF#_GI+ud z_i8mu7Z!QV^g0>jxxyHNu7g{M6qz5pFj0qAzmzrLy7T|I`s%o*|L=PR0hJc%5)e^I z=|)6aK#=Ybq`P55MM9A-C8a?cMsFYt7!6}|4C(ICvER#ge1D(M=U@1P$74I(d!Of? zb5Hk+UpO%c;VAaUepgTpeI}G6vU9WjSQCHGBf!L%WV+3xZ}lh#YLc|f7=??7{y`*z zU~6ZPsav&3KW?mG%!qP5%WO`yof51+-`KHEng>plQ*E^J5G=$(-$#Frri>1MNNlp+ zYrXC7GmbDfC?njWSgG~}Vr|6TUftdxSU!c$*ZWEtzk?EeJlOBDC=05Sx`7s+3YJQ* zvts6jZ%$Y982bL^|Nlt=12`n z4SHWKNLpR!^J>ILNj?6%bQt_IPRcldary(A#Ulf3na``%!6U1~_L%E40;K9YrWb>m zS`ntwmEth4jnl@8R1joGR`4vD`Ek&}3C7}TV`Mcg1!J%%XN#fU)!b=26I|KUSf8FA z{E)vn(dAr z7+&CMDz7KAs#RG2BS`$S5N3H?vGl30=y=FTTX2gMV4N4CA--NpjqbEf@AzKQ;bgtl z2qwZQdwEO|$G~Mp_|WLCisfhd@7x%D(}sno52xSK+6PY{*jhK+YK^~l;mlmKNb^LS z(<%wRLR8gm!K{&t!1)vOxtJD{>#5LKr1{m(wd$(D$LKrm2M)i>qUR6SGei>V@VLq;DmT&TF5|S%P4qGfV}|o!>A#?mmNDRWGik_MT*s(qE;UN;L_?{1k}&*D)!Wt|0p% z3J%6sE+eJtyJ&wrr|Fttd})7fDb2d1Cx=!|o!YNjP*azmA=apShAr+ak=s{%S0_98 z7<8VO?Ns8$&`Q8{*j@iExsDc7^^o3{{J6Mu1u|?D7R-C+4xO3;!T%XnjD^YIH$J#> z^N=W8eiis?3f~lQ%3B6@RG0FqwmWSd5c7R40SNAIyO_2J>T+N_8yl*!USo%jg?sB<2=rZ(lcyq3I4>j=lHk^c06BQuoZPJL^JF`f(_Lb0@y>)Z_Q2P7d4pucFckZkD1*(E%6}eQV_j=dkT7lVE zKNT&0Lgs(azJZzPt|>$)qc>4MQ4a64b7JR$)KbT|vqk6_)uPh^`Hn;v&FLmKB&T2w zgv3G1Oy}pFId-Unp$kvFR-T^BOL}6bARf@1Z_s&_CU;7}VP@g)Nf|Aq$WamBF7DGA zSfl5+J2_v3zSI4G^(0SfTic7LPw!rZaQTw}yNp{>VInSQ6$cT=d`gG0H`fO`33YE9 z$l-?v2a#kM$<+5cXcXEm_hv4wA?EX1h7e!^G->Q1Vyr|PF_q+_M}s)Ps0$STU>!e7%ZadXJ(hQHxq_8=rRW2_a* z+zQ#xqEB=LEL3Vk|5ZMeDn^>NYu?!oy^k+^yJYq`$&;JSqn@Z`1s$vv{i5rE(o<@Z zL+^Rk9VWJ)xb<`ePPGit%(vOKo5~e>g09`22K6b$CYJkb`2-UvyZKUYcn{ zptgH@`IwcP!fDPIq-EkbIf}jrQX)EGnBwDSc4HSVN4PMH0&1y}!MCnXs;&x88VEE`Q1)-48->>T1?=DG?fNAz7HgIhV&#kV zxUyKvC7+k483y|Y9HPt3!qAdfzVqL$4ux~vM{9?nHFjPDw^PpMq6BM=1g0R5qJ_EB z^8&cOVn_u{RoJ~mdeyGvHG=Xw(DNZQHp^`~>FRmZ+% zM(_~SGwFk?C%iV*UWh*`5_z&gUcP-Ef2?U}R$^5XJJ#J^%@id#s9;F_Nqju-f|T+> z1}J{Ra=X?AiVbVugII?tu6UdZg?oKv2rz_PE&PdWogas8>m!-q{C`Ux0ipxClOFWi zbo{Dl&N>W55D8=jX_P5QZH{JBYm~{8roWD8OxH>^y&ROqEYp_{<&P4s_Y;y7hzyj- znP`;C4Q3d}qs2GL{I4*$>;2UZC<$stbzGyg=U3&@UqU5EKkBXy<}=bK54kv9D+iZL zg?G+2%78%fYUjB~8QX=#QM>;B0MyQLfaZLvP@(NesdmMR$kTIBo&7w~|8eWV4?;~Q zds**COJagKmCl5c@Q$IrmgT%aV=Vgd<9)5uob@f9&KstUj)`Y(4IQV?8asNQxM+r- zMI_S#ItT?1mQX2oYMwl?!(^=iDBvXnU-S2vH6-blPrup}cFs9UtwSo1VjkHDJKrT1 z`@r&OXqrX_T<3upkcujXB9i+4h`p;MPszoBYEc@Q0X$SPfOgVZ-g{%D8 ztKzalT6OusnSRV<(4)Z@#`o;+ah>O0&HHJAl&dsSykEdq*9&c=*2+uK)B*3@Ple#C zUjhzQ?v0bSSS_5txH|B2pC(VPJkc~{2J)nnlVirZ_x$4~ttQHXej&byLkfazFFH2? zY)s}0X=@)4>>4PM?9R%>ty>eZY1Tc0x!VIY<<2um;I@Ct<*dZW*#z!dcVo@^5z1b({0~jD%KV}{ z-6%|2tbhtMw#JM(_X`_BtuiabgD<}cbET?N_}Ar^mlvwbxro1iRCCTrY_FHD;3@S1 z3_a67U;l|~*RDf=JW1Bc=_tKUzT0%oObPb6Nx1@g8PcR18uo4I?TdfUw=pI#!MWs2 zfX_W)-W2{yzP+f4D8mXC12?MM{?TvbO=Hj$*g?nki6u0d$4E_ekIgM235nxEH<7ct z_c1S_>4v56o&G+P=N?pC`60mhF3xe}25~AIV8>h8^PXCmb-3y1aFpU@^VOdC*WT;T>Pq}Hi@SlrGRH=V6b#0%yJ>P7B<*NeFz&AH2onX-^U`G?d@ zK%od`X{rAz_40=KomCDacG0+)PxoIs&MzMud$;vTAHu6b1GiCw?!}noP@7GqY!WG+a0CaeNSm&ai&B&IV zrHUIq_f2_dWRmN}AD9N-w5YV}4U)! zEDO29`2!B|#lMS(w?tL14&~oswX#2w4PapeUge=X}GB>qXdenJ2I=zK$PGXrMl7}kP}39uh}*B_OeC8Cp) zCBpo2&eSXz++0RiYU}rayWxr#vR)~pB|Dd63nbo8G(X34!~d6vCHY9Bpg&M`%PXXi zJJ{ehhk!owSd-I*I?92@-4_rFCA7Sie@Vn^QrjtM_N^uDfGQw5A_;{PZW(>%*K3zS ztB&&#KuAVixJ`e54g=|Bq4D*>D8zrevnv|qbTHO3*_7`%-8>x*=vKy2K;94>Ve=;g z4Vf#p?Xqo+j{iNMRE{cRY=V3I1XlskcNdM?L>j-61^;LIcs#N`6!9hWiseA8&f^?B;;xNq4JWom$5g>J1_P?8lnv$L$% zNtXrGfnTFD9+jd(#}~(lr&2SA5@QDLSgE=Nh@bRzdOGv^E(KwpUv4ZMph-0&q@4<# z$5+>)oi4teG4POD9+j<3pt4742R#aKfe>Xw#s&RFC%y0Ce@R==iGbbY(Ws?w*VX7+ zx+-ao56@4v!A$Mo#&oa8UWG=fOrj0KN0LQUQf>!Xf?jYLj{pT^_ zf-A+>f|$kewVG)L z$V=y~>UDn9xq(^MS(7!644w0T5Lv(c;C%T!*tW~5#!mf09MkJXfP9xc`a_=k`UM{8 zwtR@oXm&c=?vGgq1uctiX9tFbxA~qS>u>bFGyX%3NGJhgOSA6)TDZ~?RnS1~JgV4tcqze@c!p~_|%X4S&RPDT- zl}HAS>f1|jt7wO57fD<&Oe|TI=|}X!niiTY$L$hmR+k{xOmgwsw+v?Tf5GYXuCv+q zlZU>?S)?#h8*D4O*bqPyaIyW_sLJx*isn3R%8&n3k^kAVy!O3}T*=FHK@9@e55k#> zxKw%CH43X9$UXS^0C}TVQST?q1XC}2!eUkU?1gC34J%*fQ&HawsEj@b;j1JAvbT>( zi~4{gW=qbb<>V!}n+smper@w73J?HzGn6&M2L(|Y}bdq3j|s*3ij%sdQ@33c@$w?>GTWxe9?zX_W55l z+3r6y+2s`8Xc6K}acGm8L47;ATsAtxpAY5@>=kNvS}}dVi+B2DR(42|xyD(^2V0CU z6`;bn;ijTShlSs$4n*#G{veJ#lG_lhf*}SRR1)02J z;o!ys7FfXc9ZZk4;?SVTXjUaRX|^VJF>=r7C#oy;q<}?aoNvLmott1d#^^ZbS>3jV zhx1e>mB?IbEo3s{uIV}b_UR7JR0D?aDbJ+MEoXi~iZM;&`b6(?8rcx~RbRv#8Ur73 zdEI=xf8NkQ`AS;iFqONzsJJ@AoB>4NAdtD0slGjlzVhDNB*ah1&p*`1Fqo!Av#=+H zffJl3RSco`OMb{JkOgp=I{TCH8sE}{#!>MY$R9$-0hyrh5-QCv!uI-OAnMQ;-suGK z+f<*br-dtTVN6}}`;BTtqe-Q*4Tv0~0p2D4W^1N{Wy$=Y4BfpmRKKJ0*k_Bk;8ZQQ zstOZ8#s2s|m!~o7TZcn84n^&MBLUbI%PqX?i6hqDMh>!BV<(O&4(V{h1)TRArB)6% z3xd*=BSah{x>(aBvSJh^_cgqPb zW&)N1t3eXJ{Zh1=*NvnKDM!;6eIL~fv3jUvg=2!&;|FaO>P?d4v>R|!rb7dqs2-zg z#CcF^Q%|2;>y-z9AN zC>rWLZ`HQnc&M*s3EPqURYkV>+YUJvCca=z)};fXFnX`L=_%{i1Y!{lih~{pZ<^hM zzt5|eV7{=fquk=n-#>R0qc7#T!8*zv6`Uu=v~Ak>c$bHwbimhacKx{__3!g#(DS`( z*>qQp^#`mVGzSGV=#RxjxrS!Pr~3oO6Sjfr>#kW}jxR*4t`hw;GGCkh&MfFK zHUxAtHI&3H*Gd~fvu-07P&&aM>oRN8P3n2P$iBdjjQ6vNc}(Q%J|_p`R)i#9j}){90sU?4V^()Ma9Q|&V>`?A@~qf zzZj@mxs(j<%F!HReBId80LMc1wgg`vTz#s_OQO`I?sF11f(Fjn&jwByc+b?Xs{1YD z7qI68D5D=xc}_cLwEJO>=b9|k9C=p&`f>*VumdJM(!Yl8D^9@F^M|^TNM?9tqEW1%k?DO~%4>rK zGjvC2jePfv5TOHX^U5_G#>;ZAPt4>sn9YJS#O}b=M)H#f3ISLYDw8t%kP+9PJWV-0 zO2u3Whzt#%QAEC)t#yz%a?;84&(KMiZr)NlU-^lTA(ugsn5O(Ew=A&avBQxr}Dv6_AORH6K(%e1wQG3Li*=M&JAx~uhs0K^@^)pNMr z{*jO^95)Pgj3%~SO&~3_JxPgqpfE4^rPT9Z&X7bU+TvCmwag8I_1?)E2WqF;Mj`&$ zq+H)9>xB-=lH&tOQY`P&C;78@ArKH^M`>`rX7hzq7|SP?Faxr~y?gJM_gJI-{E7i~ zky7FA>T)^%N8cT22O!GrDVwVpH9ApunKkMkqV%N>Juc`9&{bk@q4xb0H9otm4O|>j z$azA6Vc0oay3u$H9WX!!h;nxD;jr|%`}WoY?iRBDB8*UHXEN`QZJHYL(&M$zGd(&1 zn@7ZH35q!yE#Z%t!6nTDL*p))V>1woq038z-RXL=wk@c5g_~c?*XPjTYibfb)3^S+dFnpPb7J_R57eNi^TxVt05S#YHg`7W; zUA3#jVR{U*FrEtukWVjCFvmn~>T=;)uyWRHy?TXUNTlCksJ*Ee6`p#M!y>Y+!Dhtp zGQLbE2Hdo8qsQq?Z|eMo*OYJ}?Y91<*f!6Ed9JA5yq{2XdUjX1A%jI#jDERcOAsAT<`J_HWRNfC-VD|BG{#Nr)Xq zf0|glLL{C1A|kqAvicqBV7b@saHU`S_3PL92tGozZT-i@qd! zVBYRpxVoo~@}S}OJ^LcH%y&XZa-~13VhHhMUJi@F#IJK<$ru)jGBeYw1#IEgcj(|zAgP@lU4fBSFhjU`s=@8 zBev4%3|TG(v09$)zbnhXqsXLar7j(vBI4+&PYWAxx`<3Kk@*M&~-(vX;|HpqXjoWqbTP`W5MnSf*DF zuS=2Y6_40^ur2r@abuP+C}8;-4S8eRl@qzvyGfdFwkw*}In&JB-yCF?;(jt`yR?0Q zEEi#TDPw9D32yQWI$zEYUK>ySiG&(mEA$#(@;cdKgCIx2i*~D!RlAcFS{tZ2W|GM6 z_wa9>`La=n#qWN>)#G40eRvBBp#5{nnHG5^(;fjzXnH2O_>`+K_cHM~syY2&T^Y@2 zUF>kMw{zE>qc2}eo=E&(|H(q|wOJ;y@9)eutw)NWe{@FDqkzCp)l$Qn>{_SkVYX<= z7aEfLw~lsZQ>CvkZ|KB5AFF-m4@u%NQ2_)c6LS33mo@Bs(FT2Ol+k4Ux06=azlDzD znfei(yl2jZM2cCu%e3{-`T#PyN_WnLub=$04Y{#TW6jK_vqJaz@43lbruHIj+ z&J_Oj!>N;%t2=043v*xlQMIuz^Cl56&i$%ALbaIxM&4h`F-c4it7SbP`%xeHH}P~ZjhA#YmDKAxVX1i-cwz1WNzb^GchtLr@;Jh(Ym6M_Ulq`Srprkw->^7M zH>P-RPsy^$Y%9w^j~>I^miI9>u#J(EkMQ*?1#IpBu-MicER_S%jpmZlkN-GHWssjU z4SG!648Vh3+NV!MEwped+0as3L} zdBd`%;I*lXf3cjM_NKUC))82+YE)J*d-;Rl#xcm&U=_4hM@4`H8ll`9mqNATotaGG z87%b_W=0kQ`rQGs?&O4cc<>}9YzZ#jq24l9nLd=x=?C#->6|bompq zqy+BIW3DC@hxLv~3N%+4)U9|f39dXpAp8`EOE|I05xb(Fle`*Ybir6bCm>c8Trf2B ziA9Ye&O}G(U#m087aE)O?t9ehXqd!k(VH;)(Vy}NrT{L+pv!&FRy^t<>tqv~xBLAf zbFY9*SrMtrJvgRMVDR-|hE$P8rZfhnA%k4%j<-W*%R?;S_;XC%F>tb>%e1=w`;?Ua zPJm~C^Fs!#iSSF|kBV<&E)y>ufQz1#oTdAr#B1`<&KtCS}u-3^Stb8dE_eFaO5I8*lq~Mf$X7`p(zzV%28a8h&aw87hzB{ zGY;Yd`5#?lMoY2zPe>Wn;VIjS@LkE^>*-5A{~TnN;9A+Doqw2N!r|`^g2z#Gf}7VZ zLt}c!`MXn0Ye44R`DG8>wi84!+~yrNv^3^r+lqUE9E-xrO`Db|PoJl$rd|l=F}hr* zkNJqdr>glWCr~Dy(A@O<_WAr}3o1M!I#(FMsDNPhyUhrC$!LGMD_6AJfz99Lkqqq= zzLqG3?eq0Ct=vxWI=UlRkaaS#^3w3k&0(t1Q;-tN6zBdZMos7Sz0`lM!UD?}(T5gr ztiJhnUkr=f*W2iKnV>Zw)Hruzv^W)!6D9s7N_642_{uk{wRQ@P-1DQ&)Qk>26EDgd zTja-`hE=AGiApxu=|Ti%Kw@`jH8V*4PoQ#aho7Gx1bpSsWMYhlQj0ZD3p zcEJqJGb13)vw$nogU^mc=rC8&Xb6kxcZR7dr_{;vg@t=AEiYi-WbLADw&;&VAlSq| zTD-{oSGA5)&gjhF!2OO-e|mEb&Gl>(pG&4Zg=a4ay=1F5xBH6Y_XIEX4?xQr zi%GAwcutKUyqOKbNhJnq(}0jCv07osC7mZHa~BpP-CQTV%$=%%7t&<+QJr{9KIB}4IB1RGyaaedf~pM#Piy6DC)6&6^v0RxTF?RFpfM=^)k$X%@-)B! zmG6vIJ5u6kKbh!@wiMhO!m0DtMXKkzbmnKaELyi*oy)XF@!lb3X;9 z1nz*f2R%+8(f-C`vh#yWwzX=H=O^`QkQOeZ!sO}OB-`mTiCER;pt_}&KInS`vn4!4-& zKl0}7A4fEyr!RL+Zo#ZF19rrwg0NSSx1}*da>QYb-rv@hiIf9R=fhAk*ZZVwpRrfF zK`1u_qau)NpC>RN3RhaT=}$qH)}iTQJ9wdcIIyEJBLyls$!JE2q?N%;7a$Hg%+D+) zUBU->84_XJH?c41bxxF0$2ZtzacMp?V1j4EVEI)B3Wig$eQrSPZ3xi=`(@eNa%5JI zKPv-f;yrRJyY?&c-BKfIyE}?BeC?pfcsp)DIv)k`$xqcdnq?#Wt#FQ^*(Xf^Gp4w zE|LHHBGaZyz#KM9RHNINq@|G~ed5;ztMBIYLSUZ#@M2vjIuV!&z0&4K{-PBAuVQwR z4oLaFP}}f4XdO9fryDt+0A?(gmb~vWpcm2pgJzNqR6yGnmeQ>wkpf+Q7-{aN#Vq%3 z+iqvmDg>>NT<{WOk8yKk!$24uDGz_OjoCFb%tiyju z6z#)*eY_hBTSov-jk@u% zAEUgN%>BE85BtGY(oQ=D!C-8l*;87hu)Ej*GN(YO@baA3V{SXmRD3h7Flp&cSO4p& z!}V%%xUJ!JU}K$CfcQ$gRgq59MG+{1b1h!=T9%?*^b?QdroQ<6lGPffT0JY3w<*ok ze)t>M!CN@e#h*2@p@^q{%Zsx#)BgAzzEc35pMbF;$jZ#oX-ftAoIB*7UDIezpG1Z3$lIT zZMk%3i*SMND+rjnm7Br}gRs{&MiZn=S|6*edv#NU0!WCNpM6n?q*ct}c=dx;;2jEj zMtH}HXpvxD*a@wkTDP?~VK)I06Qp|PPqNzgT?6%Qi7YgVM#kc<+BeZi_f?+U5IHgeMauCH)UtYwZ9Zpm93zFwXxk<756ubZakIJjR`X@s*c^3~;@KKN{2DOa`)Tm|~cL_8Nb(G&+*<#X8;zgQ>q$o@s>@~Zx=$e%e&kXx&yupfpY zm|x9CONE;@HQ#ZXYz#rym)@)q&!>_KJg~sLm`(9Cn}rvi(AKO?Qjp|Q^Gbh^wnxQ) z&o3Dbo7`$>?^*h^>H-Zt1he8t@cP8V9#ue0nhPd1v8sJmySs>a3%jy&&0H;tQCXYj zNI{YMjO3Y3XDEwho@ARbyS&&HMrTSx7x?Jh2j}dLaf9;bOEt2TXH!viYA1Ot(VE6 zxIT2ti@ z$hS&C$5SO#uF9U5xP7PPv=!?)CD@Vwe%1%-XL%l)gkYs_mFv@>}!0~#<0Q1;1j zW7|=gnVo%q`<9On$1NXQsGASz4%5u63C_z8Cu4%USk_ICtli<`mCJoMFXM+)gY znlH}~u{o^bzN8N0PL{Lhfkl_H1L-YX1!?u}M~|p^OjiyPi;ZF4a_4Vf+U>r-V=xg+998M_Z6D^E}p`ca7<=49>E+SX6 zQ!)kDrL7f1=oFbY3-QS8vNC}Y&8ZKS?G zzMS%85gjym+kLAmNLX`cx+MZT?0k3G<(i|z8q0gO+Bce{dFfZO12Rjb8mw-V{`vDN zuhmtrc#5d{r#!VPvG_OLcgv7!_XKK<4Qb%u(gD}1!)(38AU|?dN+SbJM&qoec&DH_aH)`vIEtH|sn{;a)+2bM%wr|pdui&Di zSyZWP?C&^qrBDg`{PUSRSIDBY<+pd%QU z7~2EU$Bn8RT2_d9G>&rc;BFQcv2<{K_=D6z{^uSJAN@ z_o;O*L+tU+&-s5;{bZktZ9G15;QmpO9zd{h>Z#QPtLmr>BBsfZu)_@&@4sYq)qk(1 zvvK>TR0s5~_ZRJZmb1VhY<-*SeMM|+ECVA~K5OZxr~LYO;lS^S2+6pHRl>t9ZU%Qi zVK6Cmb#;CkD%^>qjnN1+EWl&$x9pkzQ$Fqi+0)iw07{fdC?YDNa87P(*5`Tcdw7%g zZt~5&q*95=gqBD^^H}8!>!OB!pyV8{0+b7W@5OG0YotqKrI$b5Xsg=^zq#S;q2|wP z+~A*Hy~^VX`TdZ9l(Ng*Z@M=S3=}z zhKmKc)aARe7AYF(xjjX`z@b|zyUo)-)*KRNPM(_A+n2tdCoLg)92iOUg^=E!N?gv~vWueC;s0U?{|3_SgFcF`m9;Ne->x&o}YYBp~Slbv#vp zfj%l`Eh~E;WlPj+7Jh}}zaqSH89V7+neVTb4D<}6FF1CyGkuzhx^8Ps5Z`is*R|su z^v+DesSH!xngPMu_;>`=3Y|xdBIhces3mjaHZMDt?>@G57$_=2u}uXahV zXQ;EPA9b@pOUQuk2O{)2$hm#ww>rkhSVhQM`J0&4!$EtB&J#5ppw+1HN=UVp675y- zwQJ4Yptqu6=yTeyILa+6l{l_d7agm~(>e4999uV-HK^(E{REJMADnL5Y-v>G|9D3v zA{@22jN*jm;V^-n$#h5WZ7Z2voD1p7&OZn{&SWHtxF2VBm!$aNuab%lrWXGrl?-aJ z_iwbcPB+c4PvK^Di)6wOrOin$Q zE=>eNBQ5sk{s-K!?!mdXMz2jV?=2d@BzqwC*@FVvX12hrdY`XEDVDY7o+f;p=jx1Q z9)Kp*`a|!lWyN~;U#~aP2b-r0*Blc52cBgNKvl|s0Z?p_#fPvhqFVxB z_uLbEu>7c{YAyLD3Y+S5bUiTdZ8$@Jq*u#+6@29+G&unw=@l^c6`QBu;W;BfGE zUbSBZ547{|fl6W4Gw?kL5KW1ZuOL~mw;P$YdDu6Y&>bhp#vGjBCcNTA5 zFISOa#7G4RmH)Z^8oi~R`KO%ElwMA=u2tTM?y>LT=FE|BE3p3I~QXA{*u zz29b$Nenwohz=dNpZm$DQ`~bO^7cgA6-Dzyhd5isjj3_on!9%i=`TFbx6FNyKOOPY zT*t-2pBDWtQNbYt$f#6+xay8=V@CUi1v1bk_9;n7k*B$ zkzTHV8@#ud(8q^VY}Hj=-3p(Cp{pyF&3f-Ct2>^r&WCvpjm&Pp_wwR*Vh?1WTUK)A zD-uR|?8UrqSDa|tC2Klih`Cw$9*%Rb+z@6O3TI9H6wW|p{Zf6Qjk-fJ@KT#8T&uJ!Tqp_OS9cMBNgzxOq3d&pw~%vqPs5oPaTyinRa+MPmw3B)-T+ll`$!RBgzxS=YHO-IjyZPPC-B{LNcvR`Bj$&zS4$UyfnpT=m&?+MTVR z2kbA%1MRy=r#Ok>8Bj-Wv|2Xvlj-I~y_U5ge{#uo-y1PI`(`Sd_vTI6Tlo0#F){7G zJ~Uukvg+;>|+z%-hhM23qpsrL<$ z!yBLQ!7vbz?!G+?9d(?Bgbm-j84%%X;I07{dCg;>-k}K`9KK%R&KrKi!Y>%nH)naf zrS2nhvg&kh@4bee-aM?T>Tu7O4_l_HC=KPC@GtkDoGT|LB?E){n6(Z?^vabu}gIJAfgIl6ranmKPrAw9e zy-%(^jB;b^FD_lQqK}!~n=N8}^i9M%bR7N%-P5V#*%|9TOF};psIWR(nz!9#5%!+K z<=w-d7oYHOFQ50T_HAa!sY<9dKJ<0BZB;U*qCD8pVWHO8%1SO^3BG#uZR?mDX5ytE zH?57IzNsi=Vd}2dIa=Ji(IMdL-omQ22jr0NrR$e4dVZtnL+BEwj} zuZY-6G=^Swf7WWI-aEG6BwbXZKe#QV;*I_+zS2ZOG?@a&nAmjvK#C6-lk+C;)u(jTgU%QvvfL)uF<$Kd$4~S4Et^ zDuM~3#?(c{CM<1C!q)1|vn_MN_dWBYn}i&s)FvpLI`+xc>KmQteAG+wpe3)%QloQT zwNQQb&MgC783z%CbTsnfg@%AhMN1l!6I=IyohYrOFW+3?VI&b)p6<@g4?3^)bH9>Z zi)!iTMw6X=nw_29-z$9Ic76R}x7F3rQBukulkGBhy){v(%7iI%FPl&1HR~38kH_p1ZX#fO$o)nZ3&$aeXk9ia6+B#Q-Zaa|m5KMGp(A1m!&ZA)yDdu})2Wt)bh7FU?GR^n-jFktyb#7S1n!Z5laqbfVqwbe~M_nf-G4@j_ znhbupkrQo)S*8O=q#xF#ZLWa=n={E(vwRXs|wypok=8DpBw5&#jtD6J)0?}qY$`i2sp&yRp}9Ju$GoEl6b~5 z5R=Hb;l4XVa#qhleKJpg#oD-kWJg@2?zvVHB>N03O|Gvy(xJog3^LL(?zb0pBr(u4 zDxDpv-B)dy6(+X-^}!q4|FONLTC!O@ISd3}zpj~>9r+d^=fEfPdl&d}Ddf^bPhe%* zy3rq#@JrN%-+Fx%E4U{lMw``okApkvbktn_+fBwzy8YlVd+e)KAjWUB&`Ec7*}DdcU2T&Mxhl2&75HcC-cZWSOVdLV|5w4#%9P%39a#FaMY-* z#XRqw(2!<92Hg)9lnhjFvM4yzp@YnhwziLh&0`hyDW8;lY-3iq(=!pu|OQ%k=D+To^QgDd@eKY);lWwpz}ToW|$ZOhiw}%A|wC^15Q%aKsN4QaIyv zlO(gD#zguYS{32?mPIk)JW0+uUx-!po~kRB{te^Ik$A-r_jcDWE*fVII)0l|@LiS5 z%Dnd$@#pmLnh;<39l*S|L2w~eoSq!b7KZ3CTE0cZw+sL0!zy_&k5#zfu2|C%u* z-5n}Ma&+F$&qR{j_dYH&EDo5{%j@tcEsOqXA7sZjGm4RTWIdMb@hR%I4{NQuT2(28 z#`%bmK%{JGKb@0{dFF!!ZL6c1aN;<0elH7tTHg?>EfeDF^JYqP%<{E~Q~t~Ed?Wki zm}qY+yAwVhXS%+tCcP)1H=Xd*RnZD(D!nMDq?1YqL)9IUi%?Lyy}RT7Yc%xd;}guJ zR}UJxaGq`?DO!`(bhhu9D)4DDnZ&~aq)H{2+;cLrv|p7{qC8~&j!;VYEvR?qw~OdR zK7R6QAflOMv_Wz>q<`D-+m1;*=tyufsSGiuFIVG+5{ zbzLtvoiDa0Rdv&`pUbV%y|Z(MN!3Gji-F5_>S4$d#J8x$^+#zjUc_bJB)M}xlBzY0 zVJ>ttVD+_Dpjo2?Ki$RChe0xWsOIZL8N84XpiEGmOU+kwU2p<0lujgwKn)GWSX6Xz z0>Hz&Unbd=_P*`sV~b})XI; zp9?KwJ^uUT1XY_j5yuRj4WNFZ(E9B}7Q&T4Eb7%+=DQbP~q8e)RvdUxA z-ZbIzS%+{k1`1gs1& zSj$&e&q;QTI$(rGzK6A+va<<{r})yW89z4Eihe$_o2#^Rr5Ag#H@WZ!#AZY~t{YZGm2Qw75SwBqfdEko4H6sJBB? z{1xfX{sUhplG>lGoeA~~-9rm6-Vo~EqOEAn5!PdES*&moT4|!I5PqF`^2_#sQH^kn_AQo^dP5$C!Ldr$d$2U%H_wehpago@piudhR z#9u3i67&6sS3Nlo$fi>b7c93wl_s+B)RMdmIW@O%_-JB6|KbW}w`1Q6B_lXi1h&0> z;cT;)_0=F8_VOL2qet%LD*gmCL8RStgQJl0%mWReX3yag5rXVQOX9+3C}VVechN8! zdiq{-{g)&W3FIUs#}kux9&dfE_AoIv;T%@*_4i*~T;wQ-x=lpnPa2FzL-k%%TwE6) z9vh4F+(pMXg9u!gy2w>jRRLq9mP)wxy^|f8rLpa%ndX3K)$y|4C+ua$FdkgXSi={1 z;X1DMzrWpR=UA2mCKRBkvxbF?mrb_=TRc&>10wc3)^Xlp2+rN)B-o0zCb`cJdU<7g z+PDcECGbw&9n-~r%qXdRJ;2RnTo>u4%8T;QWJwo+=C9U@V9=)OnWfg4X|2BZm&rr} zK?7@y@_nK>5reIhVS5$&=d`@IvwCr=er!^7tWuSpCwZ$cUy>Im{{w%W%b%Y*D`iON z;+ck0Q}sGp#;)CfvM$s(h3k!lvC{1xxBGBXg1F-@O!0{HN-6m+KaAeQ>-a*+S*9|+ zC9b}KeEO>*?%ipx{_I8bQ|@zCFOas*g=+A8R)+3Ovv*{X*fYVOZz6B5%<-{vr=^}S zy9EyV4?Eclh>Zq=iow4(uHF%)R(#mQsQD6TAcmC8@ZtF9{2b%%;ykI@vkcUi`rO2$L-DDs0Q4}Yu0UBWFV?q&!sb{OMS&qw4OZseHawcFk37J zB=(Hk(7Aaw5>rzP$`bK;S&Y*i7|~S#Z`N0lrL8OZH4SHS#KJYgzqfoHgoV#S-JIvD zs@;SJBFkGl^MxjpOIye86WefzR|~a%%0t)a@0zAYkk7fY=ZjO!V!p5CcH0CI`%i7e zIp;^zWIQVKVsxvi`_=!N+KQaGq%=Awnm1#cei2#rEW;^vAtNyg1{s){xaW}$yc>01 zlJt_dpZ~NA>Gve&LymU5(qK*%UlBDBvvipM+E659x)TMli&eL@C-SaM$`#Y+AL~wt z+`(tCUFsOsv8wm65g6RboIf%m7dX36x(1i!gFro4fd3$TytO&Pl-$S&9$uIrzNgqd z@QO|zo`4ioW0ot%x3WtXii(63 z2aSwK=IJ#*jl{^@43#%^CzlPx&f_}IBt^L`W-5qNbSeoyxJqgWaWC;`b>-W=Xe6|*zc2RELM-=CSC8P z&?SwO9C7>Oi|ZSFzqf4{Rt%FWUQwUlIpdybsEAP1*xkPz@QZRbY3uHg(w`Oh?k1LH z{OzsUd|OaOkkaGwV}%Ny)m<){p)U>yYS}ZZFTFi}M&5Ds1PFJV>AOAXBzI2`r><~u zf4o5>Lr-yc4_81GM)2*|!MayO$b}7G?x^VU?tx=r2LfLI3+hhWdNivmp^*V|^YM>)+@h2)^+w~1jkZ(MbdDi!+^3er-EwO#%#qWOCl3y?Dz6X|99Z?0i1FN_+V!nL zW$0!vhc1`SE33cS|Kxw@WTAX`YR@#^yxjiO0e6ICg zEaoOmMt1&^NBGhr*7d8ku|;c4w;;H+vr@5ZOg2!pGF5ZnG>y4ZOM zfvqW9ijus<-u^UE=+jRC5Ur!*)jA(ANM9jCj)8+iDT#z6RUt#mW;U#95AI+hEB&>P z1GHb=y@&kdQ6V18*-AT$BwDm9+9zJ$hvA01GHO*TYFK<+rTfVZ6JlP^YawjhZy@6q z>l=QnmSCSdGU<~`F7dwNHqRSn(wNhYt$~$h+IQC|%(@*tQ!^F|F88cHx5s8%VJC8W zwP|pocbgph>@}dODZ^3uTH4k8saXNe41dTi$FnJ~1Im^vPq96-yUF-$c}SPgZGZXt zTN>(nv?s_$X2%tC`fcsgKX#1TFNlg5;d1ua_tv)UBIOzZ8Rn%5W_WF{D2au4Uy?{7 z3s@MM&(yjc|7b&j$TUfm?lT2VO5pwa2i8|hiQX2COa6-A%tyVk$;)K`z0V?$+5hdy zYm?caOr!iAh++@W!X8yVezW zO*ph#AKG$pp_MD5<3*ZmG<*muI|a+kQF&H zZl1?5Eu%jRY>gZmXp9>>BYVlIcq-cJJvBr0y5Q;Xa-^|zY~%43j2pTog6>FyUEN%~ zu7*B0Edf8+fq2`(?LN1)Wbn?Po%btX^U>NyW@6Ig;c<5`8+k2mtM>e6_a$M4P31@i zhMQK3N^HK{&EniII31VQ@!_H+;z3SRpBPl6Lu<#bYB&{QF3p4dZa4?|mc{+rsZQLP zRZc6Ts@QgYyC9gCbLYk$kQ5%49~R?H3}VDJZKH>^bpI4dK3fVjP1>IT{Ga1;$fl(>fn`<95=%=>GH&}0XCalL zls0@q4!k;>jt#gx=~6|17h@ zw-cc~oxPh2oir)E6H|EMptFLo_W-}^eT<8Xi-m=y_07$o@~kZ6P$41T^V>_%Jng%H zw~x>;z3*H$LP8}lF-VzUAir`odMdFZKsw$Ltl;UNa$)Z_lE6Fh4Ui$>dBv37&fMil z?*JAoeYQh1V+W_4t`hyzAbv%;oj@L$<`2hl@n9_hf6W!~d$1oP6NOYph<;9J&f5(o zaR=M=Dx7#HaJxeT3Z!Q99y!3!?em7sg~tg^TL4Rn!&BaKal_@_onWNogPS!M{^ispQPf19|G#dqxBoNEe(sN_)G^)H1#w`Zf(cQhbuaHuRCcAiFp1$~U95e5bAJ8ZS$W>SW;t zYawZw0GoptjQ*|?|B@xmXn>`?q<|ekee|xA(FIe7si6-N+zJ8BDk(=DfU_N#8``006@v61#&_<1yuVe%rfAGlwGK@YZ`5p9yT4;ub79)mt4X zsd7@ssJ|Mf+U;IoPtWE;9uj1IAmG)-SY=|ICQD9MEqb5v{DOU4Vdv=KM%^`l$Aae2 z28(@*Qt__mi%|${I2IwMw5KLE#s-_1nAiwL4>T+iE2AOcQ;_E8O>VoTDWGD& z`3B|bTDxR-&6aIq>eUtSe1FR10~iIJb{!BwTtzGdar1vE%VZ0ANH;?M4#~LOA1X2t zZ6IjmJ%_dKCASAg{o0@t0e7dTala^88BaA`s^AUCn(KJ8L^7`5Hr$;gx#(vp;^T2_ z2x_@u)B$FEpW)tGaA)bSL^GVk&;EaXD4y6;Sr9)s(ONw#;XCt6n^*L* z#<;WfGC%IE_3$Gi44v;oqNGQaOO2rjlKPscERb2^acN;$+r-MAaWM++?P(zdn2?-}A{Qum%W|B*v(<7>mdDw?Iv z9macT^|Q2EJV^=9_sG(u!Xc#CpX6EeC4zYJL!NLf_1-!yU%e0RM$RGD8Z%bj97@@8 z8#(hBp%Tyxj!q*K@QtR3H!27l_6tTmTIN~Y4xIEwX z3D?VWq&eUXD#2)jSAci(Y$rG`9wP8VjH{6{@=v9)N_?MwQ&?-h4}mNfW_=dM#+$!1 zs-gUzP)&DZv~=6Ob98{G0GB=HxoU%nGL_QpD~yNmK10_YXmq6Vf^czdL<}|G*PsaE zj^47FJwB&PMoA=vj(9>`N6i!kW0hBTNVK2_f^%=HVj1UEM-}^AokIanS9X^gh;#)# zzMIgF1D+heUpL=WEVX@q&oEbK`AQ?Wbk++P`a-;X+TXFNFseh`pZ`Z%m!ITo=?tmu zqd|Yon)mCB2YHRqozrbU179cW4oflaE8)SM#%!}{-oFlQR)gyt_d`b2u|5;cRV`p& zFS1$#(n1g;uQA@ALeMOT2Ov#<(JCuw0I3h-f9iw8#kwPa7E!9=ub(xd&s+%(;9o7_u?URIzunzyW+(~ zKQZAWN%WGZlfN8^I@PS9v#LDl_@CWTQzmZrtKDmSB#AvS_Tmg43!gb-t*>s}#RLGJ z#XxZ=e#UB@q_J-$*&=>XwDaSv&C-N0$6O1zn!#(0+EiNm!_A@cawzBZlLOis+qjKg z-J>zT8VO*Lt>ZNE`aN&#LNv}KJa5PQt2J=*^@z}?YDn`>4!4&1iGa9#O*|7lgts|;PyhSl9n)hn*+lFrjIokjbY{?T9ES)%J8CP!m+OPtaCGcnvxnz zRpFI21gN;Eni)&R*4E!UfmrfHr5Na&;n9`vZ;trcduBr2)^@WaCO3=)h)yf^N3Wg+ zyk1Z-0+8tfD*u_SLPTh>ad8L!I=lNWlBk_tPnpy6eaY?g2`*cyvJ+{%JLHs-8;3iw zInfNl{uFtRfF<9aPtle}Y--<4Ap0-@gf4J$LUcV@%8^c@sq;AVUo2OzOfB)DXRH`h z)KgXMow1nky1p+%c7}AnPdOogcfA_btJ@0~GtQqPXDpZpRn*3f)Mf#Jpk9Ab;u9drW%C>J-4KM*QxTwySBLU$IQ$0~QZ(2;bF8@kRRjGu?fQm1& zGl%sqb({UgE`Kf5GA8BpIl&CS5%bIADIs^JoG*$VLNt5y-~ z5b}V76wiFOxB(0nr5+)yz?M-_c-i-6!H8@{02)TH_NEYkV9n3v{FJiGQMAp+Y-@%C z226@_ew6#gasDyHLyo%5j_`XW;rgl|(S-T*tvUTYmn_XMaY7@e=?lf!?!`W>r2q&N zjm$PTHJ~|Se{oE@yWR8lTWLPBDd!>sNWQ^SJ?^Jme-!7R409jD(M4mQ*q zi;(a$=-jd8{X^oOQMYn{yaE?+g7-hn|G_gVcP2iVX4pTlw##8Jj)_UzglJh+*P>DhL3riLS@zJMOrBa;%VHAfGFDM)laA zjQkP|Hv%)|b}$_a1p`;>enLnp>`N!QF+HuU-{}P!(dZNOyw_BqCoc#)6Y-={tOhqx z?-6zQ?!ZBaT8QObvsJn#iF_vFD0W-5`m~dbx!ibWe9{tIq0^Zl8XoWb+C$B(-!i;Y zuE7^@09~q(n>?3i{FJ+8I|d#dZXnWZbS62{u%|K`v>#n2?W-O8!njP@RRKBb%M@=2 z_NINbyEB}%=Bbp(rg1psQ$KAPn!zhB!1Q`5!9P%=)F{(U5W!ggYnDY}t7XW@j%4te z$3FX(Gs2ZIECjqlT7n{^B@ndm)k1h7DW-fe|rctM_vN zl|~#c_m%zc#%$xh1V3o}mfl2pNzPe&jpqS?=lH*4(vg<+^wQTP|5UC)*6N`MLm%#E z*0`s;GpDUlwi1saBkw0$h(MG+%N6c~8emZ+>9*8DxNc_mSxHKW!cTOc=xp>M1?1&u zC9<=_;`MM%BaSyvL(UVIp-1TKSH(A9V&mfc4c0-{TSn4HU>!`k~BSI2l%i_;pN^3kYaFv`gXanlg|n;zyF^}54H&KGF|X39oTd?WZm{P91~9iE^45YVdMbwXeJBZsMt{I>gq z#LLLo<@otC`r=|NKAUl}AiAEqx+vd^*yqphhK7c=cXw-D50oL>HMJzXh@ZNYlQcmn zi~i6Q2pYn{8L4#`v7zTgK;!PH%}`3l*LZ-T+>ci%(IkM7i&T8tkQBPwWg8vkIv{Yw zVj^$v{$lG`#5J)}AU>hf9*aS}%B1g-Yr9%Ya`zXBrW7MZ%L*9Lmd3^!{hwF+rvOuM=a#s7o~zwoVR50+>NNb z;}`B8a!7YsFtb$$&Sh`b{{z|Tw%G<{ zqg>49ZmPtJuGvt}oDuPm0Tmj)8X$m@2gp_2=7<%aC%AQfO^15-$HJ(Q)T003!Wc+? zw3P1T>ZmuzQ`Uz-hT?w1{_{8xXW0khRhXh5W!g;6OyrWl1UGT5B$}a&E^32=a=tZW z9Fz>H=VivY&2De!wpXOHrr*+VY3+Z@F#+G1{3$8+CJ#bv=jd(}I@6;msIvTvipsek6fJo)9^`lzg=sY(1K8)TH9hZN2LGDum2 zB!$+_fYQuKjF@~8Vh9t|c(VTL+Eg%4?cuk|A`CcaiXO1|>f$g+8VdCJGL+=I;>iGO ztp)`-al)wmeaQVbqOL%wV9V(u0%_@?=|^;8l49?dV}XrFJrM?5S=kBli;G7-Ow%2JEpGxNa>dL>=yhsRH1H|%XQMva;_pcgZIL9W;tpjvzCUdCzQB%d4f)oz z@*Px&ytuNO70ofGnOy;DGeya*V%^wBU~<3xu>MR%6y{~k%D<8v4RWI&Y}i$LGmPW> zW1RJQ?3|F-)QXjCs0*2wN*1b?$EjC=r%FDEMNVMjv}=O1F+q zVpAe9B6n#P_N`3lK!yjt5X3HJTy{YYtfXBU9vN3fEN%PSAuy+m+CI+T)AJ7{D{};5 z%`RgkM=`J(Yvwps>$GBo+(3Rjbl;KXRma}lePa&ogucyf8*hg^wKGq{TI221Q1iVn zgHA&SJ9ZUg4c)rAbY%TYLp>urvMh)3-Sp$Z7A*!AhP-3(b5F{PieVGGAg)SHhu>2i zG7k?T`zT8zs01`(!JgOPa4NE*pX;!t6WLpk*KD1OY6jVS4=&yQ%DGcPCdB-%5hMa= zwf0xSbJhBwX&f8PHd`(TEBle&fmWRa&1CtN_cmwTc=>@-fdp-R`t;qd-Gp-KlzHlL zhvLNuUK=yR_Smw9aw}5`n7H6@P3q>;>h~y_=aBzUNfRZ{YVcm3XN#@H)hdt?>iws7 zB#T6bu9!iA=gaL@l&FrP|E(1PH{5dao@k+YcFzWX=P3TlqdbV>qzdUA0ZSAzn(xCL zgdRKpe)9PLxY*KhV0Qi@W)FMaQo}Q5xKc@g!!26&Qgc|GI@f`nR;=xogB7hjEx&47 z_xTFoP!4rwXJrU08N1VT?T)g^{R|_1e0+1e;vK1h9>dAQ2bSoKg)no$`!CT0Sgv%R zesoxf?DxbbW%05yMQkB`U2LgmQDm1}%a=F|Jun5Fzhqlw2?oHZpf<#Z)j3ohZ;n2V97V5a; zZyn4*1sU~KDoKBG|L}5mphc&S^=p>%!+C4hM_f=%is6~~sW9G%)dTP_n#V4Pr-|dc z;ZoCY&3Lq^rl%14_qq3oiUx;QbJqB1_7hQAAs2+1YJ^_q2du1ix=lAlFX z?mCt=#kRyED5GjnQa8c4M@*6oPshQxB4_ABgN0rgQ(aHYFN>-HRw6&#rK8$4>G0qU z31V5c9c37fDjI7S4xPMZtRodq2;@009F|Td`|AJtZTV5z@t@|gVE_}Vrj8aO{t2;0 zA7Wr1f9^$zeu(muEoHVDSOam|&q;(eeHtvU)vRhe-8z9rE{BXdJromwcRhs?u?bL4 za&nB2+!Q4The~EVxsXuK97MKl)PrBNTWU-z3@6&*%=ZtLOH5ReR*){#x=KaHPak=H zh~C~e#9)IA{r6GFM?Cfrcv{GQwHY*~<6#=eND%`GwM_L;@YK8;@^L>gpGnQBSOLWT zDNn6&y|Kov)Eu}pdkDE(W!S@YxAZ|SRoJUJb0*wVcyc=O#4f+psIjjJH+ypUrmmjg zUZ}f`n|i4H+v!V)S@eVRe~fLgnuVgS$!QTv-u2+xRR9M*?voPGA*GM+nO^l38x_AJ zoa49>v3mS(l0{bf)CY$Z!Y6f|ll5?6DPLFLG%Vu;ki4FqM?Lo(Hqxs<(}R63 zJBvxHpix^JkTi58F6Ql~@XG#c;>9~xjRk&$fArD;_^FcR3O9{hStw@A0GSX={tVSs zN$2V@c`w_rPPN0?*)?RKTXZ+I1emyvAS;mR4rC?LCU<^M+>#%1DDKW)Y19?q%_z_S zHrKKx&EHMa;hXjKN9uW9o@36Vj&AlN2p!nm8b*Yb1FAqRtgv|GmRu{?*N zUpk!ZN`vOXD~Vr^U(?$@>XS!RvBfICZR~H*P@%w(973V_jRPy&6z$3stc@PbD2iMS z7duV8+9xQG_9j~sL2fgjC(3AlodK@C9}&a|74{dJxj4#=GMLAHZdDE32vm>`ah0M` zb@qHRrJ#~*kR>mXPn@l$#Q^hXY~xB7amP_oGlUg+*YuW9W2Piaxf&DKAj(Ikb-+^< z7bT|u_-gr?4mEWyJ*o{v5gU@5E6AIZ5f?$q-6Pi-*Jf*C8y;OO0Oh`0f6Hkm0YD^} zdz|H&vq*HUp7Y$V8`jFYv0oyVaWePFMhb6pYa&$*e##HnQ6Q3yIwSU)ClqG-$1uO4 zUI*~rra^-s0LcitGXD?T3vjEMmqbWa6!cq>vy~18HFckEfbw{m4$GqVB@_dykm+Hg z&vs>pWL^rI74Ho{Ml77n-CB4=gcL<#0pxdhe*R&fh-OT3@LSKfkg!*Tp!dY6C`f4} zqy&+9d7ZOyiQB4}Fpp>jURSt9GIk7~K1GG05V3h(nwpR0LaGNztI_s-xkh!03v9J! zb0*~VC03JN+Y-5)@ngO^ty)|9ETDby`n^+?ZtM8!(_OK}A%+LpN}8YIWu*X+3Y^+~ z{(zLm=YNU(en7#gXr1cmj?DaN&aOf)Z(^E@NVC~lSaz<`cq(&@QKuH>?G(PoJ^*3q&P3y3ONd;|Qo+#HA#?x6f>y+t+4%mIAfvMHgenX% ztCJN&@o?aeTzwb-S3WpnlBieXszf;MOZ}Ft(w@H}eO2tb+tc<{Ulk6eBo>$kj&a`P z?2@UmeE0-cpt62`M)N;YJqkx7<3uoXYikzH?|@JFUCn0R5kc0Wl#uRw{Bb?Yf4q|A z0v6@}BHrUS+&jY!Hre3LV7`mf(a1&<@UfGiw`ZCi10LHNI9-2^%gVZPOo>Onzj@YF zsQ^z>qG9tfzkNlhF6&63wAQrW^p?dE6uro=yTqGhQ7yyQ>W+ZqQ=|lF5sDv}-|X*o z%@y?N*)e;~Ugr9qIA6TN+nTzkh~%l_pC$=Z0ND6`@{tS$d=$+aSKvQBwD>%v&vA+Mj?O`}R}?&42)zc7&elnHt_*j_Q{vMK?(zf&*={9W;g=R%BwnBgI7}mb7Jx zl=29bau%&hwH3Qn?51=znY@e)XJjO#JyD_KrG5Tdv7K(JY&;_!D^JePipfKSM*v4; zb7WLO4Ocz`QXTl*0!K+)p?d*r1PzUgjmsZf{fv&TLPbHY-*+e${hfiEK;vB`OKL*< z$D$rb=VfehtD@Tq4W;VoHD`H7=NVSH{KxZ)uKW|`>&id9DR3h%sE5MG?qYc}YWux$ z5`qF#%3Nw%#8_=n-TG;rvVxv>U&oB%poo83akxE)-II_+MYCdc-<=iPo^VEz13J$p z1qP^UgJ=Jfy&ucg?9+$ams6}+Yi>lRGO@5;3{vzjrXiduOJ5vSF){LMsNlpga0tF? zs(#$S_%0?Ef=)v4#nuy>jeNSX%d+6v1OXuyB*GXrm($AbI!d?XZl$Pg{%O_6&1`%{ zt3tayF@@+#tHU3LVb0F5lC#rn0QHu1VPq;OIGfiiJ*hO_Y4ey%L9eOjVI-~D`-I)Y zUTC+?7Bm^H?Ft4J%mKez&nx;Gq6x+BJ!YfEByo> zuT2@r0QxeI%rTnv4XZKgbfjy^0fQGqJRO^FhyRh<{L~|LL6Q2aI~KyzHNn~Xo3gU+!&TZIXT(re zDy^eUik?uOuf7IsZTTZjvG)MxL7+wlnvg`Bv!c!mBam?4-EGWDVZk*Yv2ymr__&NU^S7cdx9~e##PO*lG7*qCfcoJiC8p-!312@rzb+Wtdie>2N?Xzdn-+Zc?&Ve@Zp<@F9F$Fe)n#Z%)ABmY@l# zmm)XR#bGd}>-;P-D&yg11X2>`-E^V6a)u;s3!I)yYw z)7HupZ`c_}T9YX1X2EV2mkn}cPf~o}-jy!ml%=Y)q9}_^lA4e%&^ISWnJz3#BbJx( z6&zxV>=hqKKqruOHibqhm>!HNlQdQ$)^DszKO`_LDi$ZPldm|^T(>=t0t8c+(0KD6 zSz#4b#saIjBjJ`7_ASrt8VF}6e~B~6qkPRiNl(}ui4((f=bJarOQLyi&(+jwZYpka zkNA&ZUG~hk0qKZ)aG<}K{IC~8uu(#qR#=bObiEvMgnDnNKy`Zi0Xr6|koj~1CY(K8 z!PFgE1c`SNfP5Ztur<=Bvz7O@EmpLeVd1VVO7G5Q!M*dlUwjttO^5WVey0NCA8EE*BRyo@ z0(=IHP)`N=r$kG6{l6lUdPLUkO}N}{T8&G0cpgCGvFPtTH@E8Y`s6U+F+09oaxoh; z^=4p|^65LuIYUXJo>@%f+CfaA&=aDoA%k`?{{F9xw#x%?^6-oG_5?}lyI9jlu;Z(W zCg2nH)0~NosS{X*Rq^X{>1+Xm?vgEf_dHLkRTC$JUcajCyxwjR2wVR*>Q~`?`Rhl2 zP4JF|{!ZAp;B+CQ_O=t*1KI8k5g}}K>F=P~r`=dCv%uUCYKbMNm@3-$I*3!<1eh5rJWIMgd2M+4@Vl1L3qzPrG)x zxG7HdBbe%q9Gi2g2&c^KW}qKpaV&B>x0fX=3!MoXKpv;Nd$`nHuHEC?TiplYh&mgM z^XDP8Q-{it?--5Qnz`eB9ooe5zq%JY_;n4;2gBmRh%>fFcI``C-Rn%hnb@G#Pnmqn z#K@XqT1flZ&8W!K_%v%CB+3-FU{lv48oj%_BzHGwT<0LqK33$f4&)}x)0taX1~9q$45zQ0iz=(PB~E%w|>yAI|`?HYFq zagU&E(?iDSu``aa#geT@4%w2j#F70P?U|U_m$bwfSx=KlM4LD#?Wu0w>J+LiaDM%B1o?!5 zUFvesXWKkzyMM@nl$Yke1L_{^KLe^a11-xh1f`THh!_~fBe=VGgt=?m5-EKy7qfIc zU~>N6xI~29{gDA$va`4F4Qu6b1ylz{@r7UeXm}0-eMO4-;|Vh7G>5gz=dhv)n> z0AsI>mRIJeO^5lTU<0+&)P|S@EIRsTyg>+AcTI;_2rVW-qJ*XtJ9&O2Z0G<6I!hGHhgSyBY z8=e|_dEujZJCmytnByh?s23kam+e7+uk)rL6ANDNXJ|=9y^Vzj8{$si&>#jpKEDe_ zjfvdNo(zs`LH|Ti$+)_su5a9De7#YX0vUDoFm-9RhJDi~+tth6ae7a@zL)&rXa*Jo zaVNf=&Pd&>w;K!1@4~CnoX(t~s!1&zPu$=p>@9vR-|&yGPSm~~o7@=QTdcYMJH@_R zzeSN4nea0MN|QZ^ZyfA}f!?^4G>hXQ0U?p++ZpK-9JScqy28MXPmR!Fo!%naZzdmz zlCC}fa-JQyQ{5>~_lMn!khm>mTfBSj)<4{N6@}~ND_s3c@7!n$-u;V3zpPqM_O;;V zR9Gk2T#yvny>=H=uqrqh42-G3YfcF#c)bQtiad}pD*o!eFn>!c4{r0iy(gzuWN|*b z{`%pzVsDL~j2W3{PxF;ZMpnPZ&lg&9K4$CESf_Dszs_y#E*V#3>rXjea+=6C#Fliw z8#A`D(a9jb9>0eGGG3_Z@uZ-kvQkI2EzDB<6? zoa-G`CDX8>JibO@<>4Hd8w{D;MTAAQ)5V|{q#|;F3WewDDh=Ql_EWhy$@%)Znra9U z)-^t@+fivx^DDm?)|7D6U?cPgNi1r<7B|j|O5+Fz0#V~=-o&i_Bxb%!Y3Kt!#95nk zsh0{^LQ^UwgU=g}h^BvJDFlSRANSI+7l@XTkxF}8B3tFxOmn7sZ+tTqFUCCHj1JAG zM>R)PY?@{MvebS@hN+9pEZaw7%>8Yie@_Rmt#PWDD?hZ4P{|i>`$*c+@j*r=>S6! z|MV-Et37+ep+uAl-Gxx6LIl!9Hp=mH0FI2GIC!5D?z)O}5t*T;Aj0J|9^UvO}H_Pw` z?V;cqJwf)AtcMd%Z+|Rm#oMcr`UsvK7W(Gqkf2;|#@IQd`Hx8YOsqSDmU#B3$32U$ zj}?)VW;QN*r!PN;hSplLa}UP)Fv3Q!W=z})P?0uW2?!0l#(ykjBRs^VoN_ImYQ)Bp z{@FJw8G=>R!+o;GGAW4;{|*O<1#`w-QcX_3eb|&X!Avz<+QCe`3f?Eqd z+7h56$%87pzm@L>dSJe`V6pYjO+>5I`Hg}=E0S|CxdbI~up&=N-J1esCdn!}Q>-xAvv#X+ zFy;d_C1(&Exf3UX!bfU4Vg?w>3c2Hp8bE*F9JYoHN8%y>M!Cc1A7OA-ElXmDmKgey zX}kIg^$6!bMFVM#;?!sFoQ!=UNS05mYrzItt4x%OQ`9*xe(Zc~jg<513I+SxP>_&( zx`2jMJ*C@;Y)$|(@hf;k?}58$q_dv)_UD1*V3t?%M%{;W);D|?^=#9devac6uUye5 z7G=kCiUBme&E5?(zq8vd4~_E)%ucHSTx{G#?zB$kO)j(PW1ZnO+;77!`qCoGR@SBE@Y&)bwg#nCD9P8LK7rf3-&W^X3V%bIZKIMVHB`7rSWmGBc#Q71_5T^(*3a<^-h#{bou&xc z3*#F4K&z5|AJ#St``CcTm`yOaWKDkU?%)gR$-Rze>XI{rjlx9w%&08)Yq{k9sLu2C z-`bYsiZ|9R;Q+hVl5 z5%}D%h!0)>AHdR1^Hg`em{-u(k1lWCYF*RaO2fodueGfmZO`36U|HNZj*cS1cbI5g z5Za+GPh4>{N!JAhFG|T6OAO%Vq^b8}{0<`8WTPUgZewfxSmneaY55W-8E8Jl8dJ%zDLTd|Ry>c< z>mx%GW68iuzPVHh`yaeA?&i~Uge5U0R*(4FT==rB6;7_Bq>_7KTL;toq86cOKVX2f2Y6qM z$jjKHMsmNs-tsw!+2E34#6F(r@I~GCZ}G%vyF~*^;8~GZLXGYftYMjUs@LjRWpxzW z6ZQ_;T7J-!k4R-c{8*pTI4AOc|CY~lPT-A~M~+s!Q|h@V)NOGt3LUnV<`lYh|#ovM21!p_2eu z%uV)#RTnz1W|N^&Yl-$zVv4P#2w6l5HmMk+Y10kGC08MB8X6OLvhz&(A;M|(HwF;qHwygLs&_GOaq;|bhU!lC+R!ly5_Xc{DEIovkrb0b>>!n! zM@m^(k%3z>QoxI1e_h$%SP=jqZ{_#c)B4u<=SR8dO;h`1%q9Fdw$N|cp+cn(XCaP0 zvD7?!_%*^WL?x03&gQX*p?Iars+XzLn-o=f&0VKvBYYjKafwGNURux^9*q`?rP?uQ ztmcxr7!E)JC-)Ex4T~k0Uv=DD!Ihe;Yf+oc{44lHefgwu#G_?nP3RovV(GQ&+am6> z>z_Znse4MhS1UNUFu@7f)J~VeMbc1cYr->)X*&}ldSLm<-N*xGIr{$0gt8`Z8%yDm zdZAFwgBVyy^4hR{;ixxf44lEd(B1>+leAG?x!)l5OwlIGX_P||v5&5xx{OeuBZ*iSY`(k%XCZt&dB6pydfdLW02!L{ zA^y}%PehqI9Ao{od1Mai$jP;)d3m3)fIN4LRYD$C@1r`Rt$kM494g}Res<5=DFHFr zawJ|_Z{VTGSDvZ3*#<~Hy)y_B=s*f+do_tRdCOGAg#J(t1M0;8fF#`~0~RjL{u(7a zOpgck=klZLv|L$)j6XGtFmo{VgGCwGox~kuWC}_1b7fb?EJALy{-Jdn9QLHG6}?_# z8?~K!K5{sW#0rJ!3PeC(0eK9{_eiWzQk}7Vhap2}-Dm$Us({IQ%el5?ujFxzs3BQzkm>b|&lBWGX2^at$})LJi`X96*)*aWH_enOgT9q!nW z^-{>F`Iwb<^?N4v%qjj-M7vDL8!2j(OO1A4Tiuzgz>Q3m0`9c!U`^$xQOb@1_a6Sd zzSb){-BzKlnmxS=Z-f5d^J>H`BFU*_8`DRK_U+VnzH}+gOlZV=3$Mg;LLVH-d^374 zCZwJ=gf~=Jw%GP5+?I)ZS~i$nrzcF-Hs3J|F>kECzzMfkZ3&&Dt_iVhExvqUqpWgy z%KuN)9e(zzl!dQtZ=icv>~~~aRh<^62@=FA^#R^q9Rhod-hU{cN?|@Dk4x0wypsB# zFRHOMBl}9;DY7fi`9nnt;d6y|>GrNx`3t1=&J%t|*`YIe>fvWVcMx4IiAIOUbSM14F^c}D8u$8T@jOQxLhm8po zT820`I(Thpph)|HR^Y-pm$sNzmyWMQ)atu%A6^B0^9hB#9o^F5=OKEF+)9qUsVF6V zvgn`JF z^o<74x-(-C@s3=*xQn?p_l3Z=b4U==fBRg_&$JN7l2?>mTJ4D5PA^DowkIpNIH9>wuUAmE* zMkB9sPLLg;XfN0Svvqz(rUw=3BZ)rCk^RHoD8vJmwq6AR<3u#lnn*$}3t>|`91Hv@ zC?pkwiaVY{ylbOms)#Ex-+zXeuniuRShqPenp{GVNJKRW@E44o#?6M8}5i<)w613nb@OE(q_6T*4)5<~d{QT=<+} zl|S%-K~H^2s&Uq+I20A>gliGqzCSb7$<{JsaIP_Nxv#F!ca5CUdmbv2k()!BxB{PL6PP9CB4IOVTwQ^eJEU zJvX|uijbG$?GMdgIb4O_1dMUCYes(I)Zv$M`&bE9N02W6yr^X_pjqn+xW=J?l&1SW zC8R<>I?k#+OGedW#-Ed2zB|j;I45E0eat|9S*(fd)%w zT)y6`{iPF32hFYVif85b*KHC@y#j(hYR^!}RmXXh|B<1}f9xms`g}2)B0$u9ZoaYE z06>R|kV6H%M_2FO5CV6Xlf6NGo^nY0ALdrwW5fgv?i3Isj1&hSwHpX`+!MVDXb%ZI zHfW2XJn=TP^(k#WPRf1%&wfK;lVwA(8it|ud z0f+|MfoIDSp0doBN}!+S>NyZ4bWe}Ye|z`}q`snUJs6AFZ+m(G`fUWWz(Ert$uY*u zww9Acl(Yy|2)D||Jtnr5dobr1S8(3Ay)=xwt{PKf;ZUy!?t0HV@TIEdz-U1vS%|gY z$?Vd0t#zWFgya86{GqC!27Gu8m@>-%Le=S&n^db1p^RmwXB}+OFRFs^k^EFvR&o%? zvcv8GaGuEWARDRQ+f;2=m=`3(@doz9{xF4z`*_ly^AHG-!*8QLR`}o>>3xmd$CptJ zXDwI`MW3h1zMtEmLSS8?NG!soFy@WAE}5z&;*2f+lH|$mj5%bTEN1QwouP$jYSx>y z`Y|``2Fp^FB_X>W)>%0e(nqsDVq*ZJJmGw-;lKH`2iJ>tGsNe047( z;!AYF@?FeaPSqO2${ zDR+vqOzXr_RYDGjwwzED+`WH(1b3TF!c<(H8s+%lO{{sGANmmGK_xzcdt1R=R^BLQ zuW1+iE>IJ~X%`1BDD$U#j{C0AX{5A>Bp%WA51~{no?;92(M{JPA$C{L#~g~rx$RhE zyE>D$YM*mbC0QLBaGprtH{J59vwbuOICy?q>#_OiiUJvP=bvb_X7ZGnKk3>hy+KNI zYWX#(*8=D7UEBf|YRJ9ji=VDNOe$e-reB|bPqT!AK48D%VM5M+BznTTE>ttPeNqJ5 zsb1?)=b}Ik#?<^h81q*6a18Dn*;^bri^0o!i#}VDH_W@<(!3#cI$KpavA}-we`U7o zfggdKxT`=*#bJ15avwaReVKg8Q?Ay43J)Ie_09PIw&P#LeMviC!$+|WhY$WY_K#PG8ciiz{Xkoago_Esa=1a2hVBxkl0<}PF z6K5?hkpMwWc^)ZC+`>2SiG+eNH_zstA8C@6UhYHR6Nz$HR;@;g*&cOC%Z6Y@?D~7P zFDwfQ;!E~jTwMM?uHLb+&UWp>ZJRW98mn>A*iIVTXq?R0wrw=FZ98c&W81cE?)mgt z>s@>AKX88=_c*T;$54cEhO8#yPdgf7<<>OoS{uSXJ;@yb`ff;^uq30K1AF99TNmc? zA`@usE$T5*PWvZYmrr5K#xQ^3^>Z9fFNvUfR;Xhhn(r6@zKg=9;VkJ{>PqRx(ff(c z0`*mYWD3Sz;l_p-Yjdx=+CCyg5$eh@e+J8iI(5^{njtW~6tKNAeG zq-v4Igsvc_A_~$Fie05n{l*a~#C$ZSSF*vJ2_cO#WRm`KzpZ#{^i-&}7R4kvMoi`n z99wc+9F*j(P9&`mHzY2eE9?ey_0GGPlB#Qb{kuVB+|e|scgv9P$~DE=harnY zEO0u8iE<%H?o7prb5cDcofemgeR@Bw-&%n$IL4fUVKx-ok6dnn4J=H&vM@!Rn7_X| zJzn>@ffc=c?gKhk?1=t{%4F_n^C;=JwE-R&xPI35MONkTY-J&KWTUD~HE~>!6T`J$ z_;WaELPE#>(hU&;zPH#*yT7WClmM{>;YY~wAm6sL9I+`_;~492rgQMKd5qXP_}Zi- zRK9oU7=Noc#%nCfyi8QaN5Y&h=+Qrj91az~*a^RHxd%kI%PtPKfg`pEUruUFzw&t8 z;BWHXG7t)8Au%4(=DbxQWw>WPw(kVoElHSMNP{D?3;w>$h6Uf#j=6Wn<2!QU1-sbc zIfVYx5)F;%f||9u(hT1oxZ{(?4&Ur+d=CE#q1{_`V7uCi+f}jvcooqmak^JjNK8Uu z>qPp9Nh(>{L!zZ|(p|dzZUi3%$ZSLe-c~F&tnoh|`a7h#`Sj;Sp>RKb))pk#Cd??Z z{%CV~=nQUi@QCI|ygKm=^RlNKq1T?R_>s{|m+)_Gt9-az&{nR|9{i`GX!rs$;VV7< zygn_YQ>NFi>zl)ae~Q}=DQI?04!cLCThLytSK0r@tN$Pi>@}KZ#D<&RWS=}4+!I$` z?xcf^8J*0!APvzz-dRJi$eOsyHhp1`R9=_3ZIh~IPeAy-xF(jTiA1Jq&+gV`a%K~PZ*h(QUIajaN;&bChe&H8=tp7i&w(QI_sOgfV0Y+_Q#$>Q=8!p zhVf$Is${ysJ6%g7 zjB_mKw3^-%S=hd8Dm{gOYDLSqyZ_K{F<3fuDTm1VP*-G-@_B&_>)IihE{W`@y0Qj> zDy|^~N3Zv%wcs=R3FDk%nhO<=$f7yZ)JAIJ`hCO$tC8?;{1hYgW*oDesyyF>0_031 zH^zVVH7hHf0`|zZdAPqeZ9%)hMFQ=`sI^@g9`}W}xY%JnR!v?ZMUWTi{JQ>ZfrGSJ z?~J*{(-U$`)S`$vbp{MI#}TnukwZ}jE&cz91$Vt{p-@QswToG~z?>LiRAay@O;lz} zq{ablz#6+s?|WMAf^9@LNs;#jj;)fMLrVyOJSHwvC~nr}SUq*iWKXO*0p4=k!*rQF z(XdXGDNh3yJrYYo#)7`_S-n|oVR>>rq@L5wfqvS^w~o+w&8&J(E!fwnRm!#sxN2aX z$QEH>IfKdC7@;q@!rtgCwmtbfk(;+Aqv?9kj6mXFH%0M=3-0`e`93E1Xe@!&{X^rG zT$<{qQ6B>=Y*ww=nF!}?iWpFv%63duqGGbo1GP2vSpI}TY>j_y9x?>aE{F^^bJA-^ zgApAKnfsp5H!l;3jKgjgOaL4zab8%~L*O<*R4AfFba4<;D8fT#HUxzzC=r$QnSn45 zADMfbvKyF*%6yCEE13Vb3+>_|t?nGyl~Z*&;U2WH8Ah?!MaTv<+(rww?c=*}h2?^F zunOw}_veRYo1p5t;FssM?v5A3Rd=lzUgzk?qlqEytJvF?iBK%^+)!AX(`JnDM0a|V z=CozdGv%zi@Ckn#!lK|TKsh40Bb9^dff2BzmMYT`l;m*EJIx{#?MkclV($mq+tA>Y zWdqseMmROsV_58UETSFUhr+*k209t6)Ejh&QsnEXKmO)#%uf_~e+@>Xc!hQJevj5w zeRMnjM|a`>Ki#<>?oK{jgza{Z{WB+B!DIA-?O4G7)pmBE&SZNF`Bn#*m2230H$lH6 zIu>1H?dy#GSl@EbM1LbFIY8x8`|yug;`oPg?D{WZ@WJ=Lr{T4PmMQZbfmhOgSaDn3 zhYlDbLq3Z!tKgy#{allD{V}{#GPmK5dN!$$#7wKn>x^N-Yl>=1q!9@%6{;-FJS)Z# z`={?~+;r62j;_eo!`5>5E`+2_sd64`aoebc@wg1RyT6&&j0LV_1jp~EjV3}MR#g*v z@&a2mPqVx0GWs=>i-9E!``qc3eev{`B8DP%rpc@e*Ps}wpV7#Fo~7>QjFPjE!~O4) zQB4NhziTB5r%bYqC(&-bms?>9wHnfxna_3&ia{dc2;#zl5OWEC7ziW%ps`aTUaG;l zgZj1@NFXk_hXjd8MK{xMD7kch2EYaRKL;XDbERKuZw1^zk>{FYPGty&9$`vow%Kfx zlGnqN*GPkl(-4cBp-H=iV;-|bCuB@fM~xOj8w~5R$DE2x*XJ;gMHR`be2HX4{gE4V z(${HEGNk?O@Cpd227)pzFQ>oeIxL?asc>A+Q9D(37;)+Cr9yvZNHd!46kGj zRnos*Af4l3o5e?1pRFa-d2eLUSQQ_}+u$>Epf)=hQu1DDZ=u8Dfk(s^a>0$mP`Z#z zIkCY(QE&v$pMxRf0g=@4uYT1G571biNt?*A!5icbkAgkHd}IQ4kJX|9;(PwVyh%B> zm-L^bvyezCU@`4Pucb}B*`RQp{Iijp3ZA$g5t<`^U1)$Kw9Bpr9L#3jgpCT*iKV^y z49fqyJamOQDSV+HTMd+7Mvs_Y&`*eyU5k1V+p^(^`1I-HR$Pc*X?R6E_-F;I(Sizg zp4wpM*pynM#qT|QVp4aWDfR#zm22;F%1rnm{zuquOmxACn@m@65lQ5qz7ldd?PsOZ z0cYf;Snm=cx))iL7x}-PSTEVo&xhCp2#FhLJsJ!6UQJ(Vv)cNi;6*oRlq-1uN|Fkc zpb)L=a^THBGzJ2_y{Z4NG5Zg}_TbjLA$5G__2cGU%hnmVae1*KY`IiwBcFmfelYV~ zv3YCW2ud8t_*3EZ(rI@$Ya6iK;x z5aG_u>7GGz;^z51IG59ZDq+7nj0t8nv0&(Yk(z#@9rrd?R!1R~1;|{!g`qcc%_oEv zfJ-JY>EiYVOB6|AWEqP4!>az{S3A+wXiT_;Ad z!9fpyKpJwDci9u(j>GW1_)Y(62fRwcrKgYG^oo5EL0Tq{tzJh4v4#y6==HcjeO&p} zMnvKoE$~oFVlgvRal0}o1$EK5b;ck!8vT-u+%Is(Ea6q3fRU(!<1wogp{J+d*oMD^ z;13MMtmHlirOnCans$(^R*c%#J9W*hCbqKnduY6A+}<)@Rb zDmHmZ4vy$9KHF@UOa2X+^PaFM_h>fTEP#iN6iuvwW z4G0W~PHc>9l^qNbz394B^b@kuH|_KS;-k<%eva{kg~qpu&YofmO|cKYor^B+y#5@@ zRE5m2&3vwPufJ>p8>F@}CA}e@@$7D6+8UgX-*&|4Mow&es(T(bN3GTAXK21q0~nLI zUZB-K9v)-Puups}nJ{7AVL4I^A52viyB{?+kfI`U9M(`E`=fhU_yV%!@s(?$^>;2& zxL;OMAdu+$&C~rI zo2*`q<2LS#-ni&OZHEd7{Dlk5F8a1kqUXFSOKFY;#b%>h&%(Sj`|5~EHY;1tK8C-5 z|4RIH?`_H^4AJw0y<7X%63Q zPO0KV-NA0pWwzp4YG#a4ida-u4Gqc(?gyV-3wmNCLeb-v4)h@L>_49{@+oC8SUr!% ztCin_2F3$183{jSjJ`x}6vUe(rU)n$^F@&rva4}U^-d^9 zp}+61bOQ7Z1^j|h)heAxR+1+xD!+n#u@Gxu&8}!*;IWieH7@Fw4_2qHp4F?)V^9Pe zOHSFJ$Q?zRXAUh5!L-5~h_bqCuC+t4meg)HNBf}u*OSdble|^kM@jyz;pbWFDp6UT zTDu*upy=e@+aX0PE(?17Yls@_7j3Imm+^k-uk|?XiN6s}Y{#`_?z#vbJ2P*Jv1&fQ z6heyQx@H>LS58{3*{4>~=60uJka&E=CSO&BWM29Wh6V=6x_y5_N8ZtvNSu#!|M5hK ztbdNmD{(z2YBwA@7()kz=bBQ@ps>V%2#xa;u(>4*?Ex9|7R;AO9HU6iSF}D_WI*RB zGJY&dLe~sx_z@>JEQQJVOPds02{gTnSfpAJSKr9g+CMOwEc5S|vk&&eb1k(1h;dY^ z^u}sQcj+|5-a$L}sx9H`H{-wA-%}kB5JPcpV&kt!^G7|TR#yjlrRa!FEjV}%cn*5~ z55CD$%xy*AJ)7SKg98(Aepf^BV0gVfH~fPr+Rc12Y^Bc;gaO(MU@2^*wSW6%7nhDn?OJRhdQE~T<&f>|2j;nbdW2&x`Jsg9wg8*2 zW5jL`Sr51yT(`hx@{tC%Ra-i+$&_o2R?HN+Jmto-S%SvW#M8&^3zK{b}jcsSr9M0K8OUV`C^^!1 zo#gWyLlbc&-&AawO^`*6ZrB-92jb?KGlQgsdTof*h%$tTO?kO|gVe5=hrh{Wi~EzL z8jx(8n)~J@grGO(Bq(8kz-umI2L#xg{2@tT8N@tCsJl{~nAReF?o-3lKKSPd)KZav zvJO@aYV*maD0JeE(d5j{VZ@_%>LD0I%NYvR`VfHq3iv&|Y4;2)+Q;Qxi4H_Ap66<# zSJ_wGcXu(2hLs;0xGxJnfGdpF&IO&G(w7e9$L+6aO_s(#tw6^(G6p>l8%%b)6s(ma z2jdAV>C5gBuZ|~6tq)M)*B3D}AGiou!3YjL~@>^9p8h<1>=X<{*;4u@pOkyJ%vzWk<-33nOwBpTq2ZR8^~S=2Ip zPfQ6=uzdEOBv((1@Wn{t8n zkHimsV1?j1MJ6B9dL#b`J~nH(cz+;mTm>?xs1H61(iNyv#l1>Be^kj56W#`c0ZYS` zeK)VK?Lf$K!=(6lIZe%S)tYU-8Uj9#;ec+*cS=ZGL+4@qmp`vF0~01$45=AuQC`(q zSv#P(m8ra?hg&Na;mlvZM6T!@reKHZoQh8Gx$joI$;00T=aNFagujM)OG3W1kSsTY z@*oyL_t<}{>00M3s}Jx%0;^YRsn*>R8XYth@wG-ie`STHvxUbCcrxV8TjFo%KB_)? zj)vYPpoa0mwe?qEX^0at2X*dXV0`<8@_#b@_=^9zIqf9Ce3!4pL<@Jz(QOUbs>CQ`)<}HIaZQ)y)XCHFWTS9d(#7gd4PuGE*w8a{ulL0K zG-oQOiOj#L3XJnbr$r9}=SrI)X{NP&)x^Z#lgRo;(5iYkU0eCpT+x59X#t>@pIwN6E_AR#e>6-6X;Z4-Toziu_ zU)c+-1?d1(bGdBST8}WdaldxvJlQ~NI)yKd2M+7ku|cp|$b2Qg7j3Pf2<{?67$!pS zKVla{=|W%L19uO4r97l&A0dS#qOzc-^hcm^?v#Fb2loy+o75jdSIoC(pS22L)3gU) z`0OOJY{;DTI-2xZ_cNP9${cAxTi1k(yhSq^-McznwDexhG_kv1F+xV418&CWEEZeC z8m2)c&5j^as`+XOsb70cy5n9wK^VFVFQ0tpKup?oh!U?WHG0VBt)xSYUH&?euikaN5 zJ)p28G%A%>@`nUTw#CM+@32MI2BSV-Z%tTZMlaucTOD(}UraAXq_Jy-yf&c18K24? zY;U_vE45mly5D*CAQAD0Rhp!)=x*w`UR*u96d?GloxQ2(%BUU+XrAGxyhFT%Zpm|X zkl(^#kbb@QT(kUd^8r!?@*8iGJ-M*Qr$8Nxce+*g2PKWh((>3=%Y=$yt}+C>lI!d+ zDA762E8|_5`f;F259LJ3lAmiR=CYM3 zwflgPD{TyaAx`8=_`K=J6Gs1Lhl&3E9qE8!R+iT; z>~T}Yd!=b|4|SiFsd3qZ+e0wx+oe&67`rp(X5#!aUb$4{l^7}8GVq$e3t zNo@j%h0zGco)s`UMT}elWRge{_ndTB;%jg-SwaQ*B6e28QZ&~ZGTIJkFL#$&GcN|W z=5CiQhM9E*seVPVFc`_AO5XRHU3ZvUaxUZ01N%a_MLjvi@sUjiT)c7IW?6{Ggdpwl z;3G~Bw@pif<09!;3lT7nj<$XuMJr}O4Nc9Sp@u&AP<(+DMNP$_l+L>x3-7TOs|T$N z6+Hdsk1b#XxxC4TSkG77#2IlRq%|JD#Y*H}N8}jb7Ku{?Nr@l{#Ng&ywimM;w|)~IO`@a5UDq6X0F+tex?y6=qp`!GlM+H1BD4x6gwW0 zQ1?~#xy6!a<_*l-xt;yU>nlCTA9Iu1t{>=?^^z#}>4}pJ$xDt>Fs#YzMWCgO>BqHi?6^eu~mTw^Bx?kju9r}-M*!fW*T3rS)hJ~$Pi`gHj0UYL3wYDpnU0nu7m#OOSjAhb&zzc52@l6+5vISh4708~{U%kBq)Polgi z@Rtr(%N7i0DXV!DUbEK7Ua2MYwht3{@9Tdm@v{*)sNykr>>@2!)BZdi&`-nhy(s$8 zy#K+@b{_4(nMjH zP=pZ$cK0e)I*Ir2G+90i|I+6VC7f5KHSc4$_lW;bG|+OFjbVq^P3l2lGzf_V4#`Rf zn2UcOJxv%|G|GXSxHNF-XpJbn=uL)jiiqQG{DY@|yfQqJ$CUpBry(+1XQ-OW<2vND zOC~-8M@QBWYIqjnbefepvVZlaw#XYrSyCxwj?&%u{$~|OHEm|>j(uS`7VoZH^|)Xp zrW%|2uB1A~+qpt1D{2ES0J z4UxMj@)DEZAU?8?Gc0+bBzR3mo*0sDv;H?qyj(F$0%@~0)#HXxLc#pF-|16~pb%B~ zwEkh;X26b1Ee`2qHGpUdo@&#kE}cXn7p$6vv1fQO%7V^Vy(m!MQZJ&-7ojo8t@+4o zD^DJls$!Ys*mT=mUjkB+$0+%vdY(Uxhf+JDGEbUGQ2P4#n2BX6oa63QEfufdtVElw zKEz1!K&jFqxo_o~U;{NP_V2;|GYW{|%H*>(Fo9oZc4HP4F{ppsd-Y0h3bTQj)zy!t z(c*N4%;lU3SSrO!Z?_R9k;#5NlMEXnP<(C`6Up5k^V+(mX_f8>Fur*^6fQ3m=~8#d zb;^ya{`v+{20gqYSv2-=^yh%ZlC6VG|6NkA(_5ssSs=F`1C^^J{&A>}M9Q7N&XMlW zb(01xia!lL8Vb(|DJ~stHcBVT>DA~q?mjoB8MUon!-QQAgU^CbuzPG})y2WTjBVWZ zUg~pjG@hYzH#7o9`u5@b7X+)di9ciRi#3L9Wo%Z4=f`t!86BCk{AD#(4M=H;lA*`# ziMuiy&?e5G7GwrMgX&M8d7NiF7FiRkmd4ItMJe3eV)TxlVGCfB-0K(6d|nlwXM6$3 z9i;E4zg|r`?GF(C@TgFzl&fBmpDoxTcgqVxl`)4s58PWbU3fkrWvvIeJjC*${^mj3 zI3M9#%-Y`AA18Lddd34+=-!H0wKW@g2MxEv4~>Pq^TM#-)k&7i|KD#32T-b9zYP55 zh2@Xzor6Y+FEE~`(fp|}WYE7!zQk|z?EO*`8$TuKV9rx{|LP)@qjONLw}L4Q2Y#x24t~|64oHjaVq15?5NOE zB`QBZx+y(q9q#Cdyp=STl$jHLCZQ5EM=P&fRSBTV65QJj;@B<0W5C zGJBJq>nKJfw9QC}{xGil8$Q#{Hv3QLc@-AiFO{bg#!T*3;1My`VzVypO>l$0$bvy( z)4je?U8|J!Y1eGfy;S0>XCv4KTdkpjAQzdz5)&sd6L547C+?^#7Yp{bjW=k%*&WjV z4mWab=&s+v2i( z%#Ds_o}7zedM2Lr>Z*Aq75Uss7IZ61gBoXwiSHZTz*P7QLTlpaS(*4%q|rpB@HRU{ zcQwe8RCeTDo#O~j`k3_CQ{krL_=jL4;9*Led{Fefh@wuBrw(Sy3q6Do6>132+E^@5 zY;%gnEK-K;Mlmqr%9zu2*$8I>J_j>t^v6vR1(h3pK_CZlc+!Qi_j+fF<^6U^Qkf-s zSGr-$QDHTuEiY@?fP+6FCAFkm4TKrIZ*>bFF8J+y5Vbi|!Ep{zOv-^s_IUj(CUpbC z{$Nv$xAn}~ae;|S(etBXcluUuKNDHtjHPG9SR11ZHx6amTgh2kvk3n~)d7_t#-D%_ znP|19J1RlD@CPrUiYX+ny_YrR8fg=E=FW?CFG!L}m7AcP3_I5=9O*l*v$xyG*$0WW zp@wj}6y^saLQ5xk9xt8`ayPIIQfmP^S3Jk+566E+7>(A*&tyNu7Ra@^*Al*k1{8hR=i+M z=sQ;yO_&o1X|`q!Sar{mmnMzz<=ttfj0P;I#?-sP1YWvl%MI6e;hj!sC=2DKox?Ys zO5T|C)U2a$2FS&R2?4$p6X*{^tRvlw^{-o@5$<|jGuT& za)UOKP8v_MKG_w!vwevb*-GO1nuT6>Y1Mh@|Mug3@0_J@N7Ux=Vs-?tsPXi|aH=!J zOXQX$jlUqSTetZJBAXx*aJD!6nd zIdO}!SB`{0a2o}hvh3x7PjVTc-h}kmCtmHU>4B3#<*X98r(RdhHix9y%|8UU-aQSm z1Al@o5&*d{ho$~ar6*;YqM)S+zGJ19aV3=_MN`B8rI8;<6yu$C9CL4_njcwTQcIr| zoM}qmJYf7(tk_B&OLw54o*8_Ux|d`#{97AKrU&kF!Wt_ygFywwLhx|uj?#LP1Ygmg zKtAQ@kKxh@&sQmr*K$y!{3xVWQfFmol zGj!DODB9t!cLN}U7VHg7!chI=`aU^D-AdON$+q)!Y+GWbZw>T{WR8X`7+58OtsJM+ z4(lXE#$vdcF)Rp%lV&z7VJO9!*UT+q$%Vf+E?dY}1GIB7f*ViCtA6oO!#7+xI~KTV zG7_h<8d;R}*UL(fOfG@Jf-y-s9P8$oM>N#YM49q7JBIdF$ii85=wF`Uh%WlD=R$}e zukoc`ey#}+pQ(Ol5W0^{%nQnM7e=1psr>@u97&dA4|kQJCwBZz(r&;+fwTAbGHnn< z#fC6kQy6)fA@0%`30ow2TTKYIOg=#7OQao&=_*M|ee?Iz6HGl*3qikdJeB=trLuc? zH_ir=B&@!cnXkBf&HmDg1Cz@W@O+|N>S~8f>k7ehQOmdvm3{kA76`;~bM`v%($srE=Y<3l_??%6S|TJd4JetgpED$1^~gpDgC{ zHqW<5-q!TgR*jgLVnViS?XGe915sO3Zy&}N)SIQM&mSMF8yBu#A4S$1=HGPz#F!Le zVWEq<&H(3whK@!GnzirQ$sucNM1Fp2Yo9~1KD-|2o67};_Yb;eiYUgPHiM(gwY zx&sO{h6#RYUI^YP+W`-u-f;@dc9`rVJhT>EFo}t38>$3{s+ZTWVC^>@tU30O7uW@s zFj1KAjEBxc57s)H-FG)3yqH0P-LS|lX5U#yt^7B|_b&+)F|>i^`eVAN>`SvjS|94F zOQKBfE^5*0wcoX86G#}K_4G$C)DW%K%DRdg@HMgHgEV+}7UyZe4vZjF=V}=X=gNGR z?%+08ga|MyB(_Y#w-=`m*>I2bLZCkAn>pHcnzA|vsyg4G@`m@OI)q`Rj;AoF`XhX2 zZlRMovgwxR*+lQ`=H&RBxPK&8e#*lZDV|xvH9}qKv5+B8o;VNKudA3e%Vb%mJM=*y z2_#)E3IXK4jXG6lPT|kbaAwB|4N&4uCgfl4A{;VI!SD=dGH^k|0b7oosT zJc}pY`QSuPMaH0!i+T0H;4Gc8^&WU03(lNgEn2XYTSa>;ej=f};B^mCAzt3@xqJMM zI!Oz@u(`QM)ok&=GmZkyJS)gJ5Cm>w%{kuc>b1MA`#lVzJI(QbB^S! zl}`49QvC%0?95PT5N&xL*2c-vTH)gB~6Od$C7N9UwnUN(~K4dzO^?y@4GSd@vY@MmX&z{@Phho-58dK6663NN$a|`tn=;zw%tF8Kib$3R*HIZTB*4^yZHLxD@bI0$wkU>UN^u7061#MepHb_x(aJLjVKw4*!Sox;OAk``A^{#cjGl1xFbN%_eKkMi0pYNv+Y2nh6 zFGMD(r0oOD0Vg(!>?3~7=%VB3w71$JhJywZ5&v))UG^Z$L6$?o)Rn5 z=J~lkGD)q+`zq)c4&c`9f$Hed3NBN{Nq46-8gA3?;gnxM^pWXH3pG4{sR+47CFs}J z6WPbD;0yWJ2Oaqi3E_IH^)IN9h<#y0aa;73+(z)H;ZE>4z+wRwrAelrq@G}y*ed?w z!6GK?jqs_X$03C%H1E{{X&iU}o(*ig1681zihKP>UWO24ecIG#yuvu#!aWks>>C4f zhm6(FYvM?<)$`>n+~ew*9OWr2t5{&74t`^kQJ5tBdM=ljm4{1xU-}{TW#j>KF%OgsGJ%n<0KArA?zm`%wX%gCxh^z%O=*E$Y;Zcdab^+^H@n;+B@6R=Hk>A zCU9+u{Wj+y5a}8YakIC5z!C^(e2K8gn@4Abw@%_IITU71y_0R*i=*TExj{>{_p%c2 zrP`u|MpKL1fWx8;2`Gw~CBPoK6^{iZ2~5E>@?H}sAt4>{kcd5&5fiw6X?l!*MYb-` zw|PI;2N@xRr}3Gu_=L@2lUDS`vK9Z;IhTCt1nrS?Hs0i!&8NMUERl@NUqy|W z#a7`wmEz6VOY7i4twRY5|2nI5h99$(Yz&aCF;OV3Wm-5+asR*eDH5_p-Gu&X z*%jA=Rz$m%I3^7enakv}I0(k$LrMf!}RZ5pb;n4csF2%+K$IaK-Zxv}-ucjJKqfWX?EU3$E> zps3Fma9`93D%hPh>c<|LTaV5#u=ZebzG^42NeVnOL(Z56h~Lrw4c6E@=5AdEF= z50GEw55Y;wke`llpB&#Sv!iEItnh`(EU7ycfz0Lt5Y@FlhGaIQP#4jgEW<8f4$Ie` zdVOXouCw`D$>1q-Bj!B%~&ZN@e{(qh*`T&AcZrM=Ya0J1Rp2 z38l0b=87nZr$o<7zK}<@M~i`9{2SDIOdI`#GutyAr_VCjy+9L?KmOd|OG4|p;Mh9O z6hHxdpYEz}sO|w7?+r;C-?tglk$;&Nnjn^U^N#E2p@)sY_GO(%Gor;0gwN8~*ag{J zJ=)d^f^Om)XFX;kOoLlXSG^8}RFGTlGL)ziRtvGzb4NJF}E*`0Ma*WdG=l{0(}G zMB-5QU#|lxE&izdgBdk3fzY;?I!-%lrYuf(!`*Fz7>8=uHfE^?kRvtne>JJ;2j#3} zjsZBxB&&2%&Il067UxF9=uOJ&vMAC?2gN!!ii8!0{X9&av^hO%NWulsm3I~_2|8{LVg-4S|zA@E<8M_p!4;#Lx4 zcL8j)%5mi&M<9}W?0;H}zEsR=$E@>mwEQ+-*=4%Mwjlu{L%Fn7c8LMaNQm+mziauUBFpAB!XW+wRZ z0%V|PSy@H0?p2a`2O+5Xqq=%>z^0lKNTuMVZXB!1x)0gXlr-_gquC9WAJU?_^y;$?J$-wDFX0C3?h~ zz(*yHbPWSz7maVJ?j20Qi#U}x0qWRRmgZe$Z5)0ttip@giHr2@@I>SfKUZ0;J%~7x zB7b}H9Yj>M`z+Hk>$xoOQmYwJNdoi&D|m<$dM^Pez^$Wj08HueOc5I+L0sJLOXSDz zhNRz-he))=vB}A{CSwE_>&@9%38I2t5?$bQTre#mt%WY2w=mf@AnngGkdO?b&DrR- z?N-ssZEyNQXOecu;`ls!U!1M44&SvjTb#fS^sBZfhi(>eTVTx>EPJ0VgXz}*u%jX_ z*%CUk$&27X1EKG5!B1T-$pobi&VGI0McJRud!OtNF8Ak{o-j$o@!lS_mwklz19Wb6ekfF8Ke-wb8+t1+MM(5>uo@48|0Hxiw^3@kMjhkT>GCMOF_lV zq_L$CXFV9?-|mkchfK4;am8iv{BjoRgd^S|7#^~za)9}*1Tv6W zznPDQl5k{829rA%6?=h6-FJpsV&xZv8Z#mH3I9ji6 zCd)*lh*RSAo+-jnqD!HQq!9~!KznCn(_9TPYV5eDOwG{6p&at!d|!2?3Tu9)zPEqN z(pLA0z5P!fa`Y1P(}Vr^<1lRTSr2j0gZ>etM!D_X>?mfVV^`zgS}GP$RF;t2gIG^t z9@D5UV96ckIXV6nAvB9utV&!=LL&arXE&N4U+Tz9<{9lsf16yB6WL#yaBJFy!#8;1 zT>rq=|IxmMSY@Tcx2cUO9S^;WqZiS*N`&xum;?OL?fY>rmWNwW$$?-G*J_J1{ME0j z9SaBCdpy42u@xsGY73smb51`s+7(^aegb7k_ndpAUrJ3^B9YxW^mvU3cQ2LQi(h@& zZFbqWCoXzs$ZeUUu?SG&ev2j1rLw0NZ=H{|UEbUURaHf+O8EIX$x#OB>*?*{Jfu#; zxBvW(v@0sr4>45LKpr&6m^|*T^K(SHUK5Jx=!?Al@H5>pg+#IxqTp>IXgB2Wc|P{A z$psqpC=>jr=>l>wA*8=gw%@4eE%jq;3dy?sb|JwEkFnK6@pjSTe6eCuvn=mLQz3HgH8CAm!2YBEmz1;%pItn{lhq2;WFRE%~PgICg|GT_@(O) z28^Rd3LXyVRTuHxbv=6o4r_?*8GY(rV0rY2D%D>4(kGD8FIJ^v@sY4m!l)x|R9A_0 z%C4AkyJRx;LYj=NRK;}TRt(8|V zEe|S|{kaDr+ufc%v2BlUKdw729(I1|mJ}tlD<>6LRuK}5tA!%tuu%WvuAb;S@Y8-2 zZxv~Kq!cN79x z!If*8VN|T%2=n7GL3pngO|Hxep80eN7ag@+m!kodn%r4{3;LvF{*bdz{pPYo{A|)v zLDV5@7J7|bJ@4TW;gGG8_&NHBI(+LrkF!U_?QCiWrQru=S92_(x(b`n)3w{<(ZPkh zL=*dP;!L1?!8GPv9SwQ}4%~}84?w+!dKmo$ZO&0bSLJD&U1f(YK$$Yg6-^S55JStI zsvIDi1Oaur23lE71H65QwZL0|PHJ-7LKW||2zq_tF!tE{I_m^L27(fq25R@p6#A;q zenevaaeVn4h07Cp37@v>&J2@@Stus;93W)s4RWd9*E*7v7X=qeKP2~#G7+GgaqXdT z=7V<*bMl()Ul5{jIX+<=DBCn@KpZGbZq=G`XnKIzJRO4y$=0BsS)YWmIDB^ljK$s` zv90+?Hm`1exp;gajEnZ^J#_0Ywz7Ol6Y#HbU+{VbU<9SI$`mtC!rzIw_AK@zItEpW zuJQAl@Oq%_w^a14?}*xNjRLs69KyYZ_prtyNRBw~t^^s+wL7DKRv|q;g|GzeW#jFJ z0(MHaKz)ClD|pNEtU(BjksJZ^7zMmzY;nceirAZ9HAgw>g#3r z+ELUP&x8dXt1P80zeX}u40qyROPw>Cm;Dg`zTsuA+vGtE+MMuZEmV{*y(wj0DR~jJ zRM3#19M=_yZnBo@s&QiSn~T$)eE%^rW9*3SFV4SSZdpM6i$KS3%t84f1y58v1Ma?~ zE}QkRPCXgrr~#NQccCNVsryncLq5%=a_c#LB?lw_ynaMLH9J7o!5MNJ#pY?W6VkZ% z_DZjc*REd>beyYuw&qp&B>HtZaak9n`SvVgR@xHjQo*N;f(K7D*1sK=1){$l79NK3 zE2ir*p`L*Um+M!2T4B6C=!t~IRUl^Cii(I!-ZWHMS@7>xPAF4#1oLupeOqUy(PN9S zlnS%%rW#tA2Fg&yv0IxOdGYcxZ5XcOM1igpJlS5W`iY@S}gKT3K^&%wPueO0aSEMMl3dq`bdB6pw{;gE6$nupv$q{=p9 z%GkpAHg3{dJKDBgvEcDzCr;WKJrJl!;%6;g$_!PNP=9Bo|+Qtq@a0R>7iEH z50TkYKQ}{1`8FkJ)ufpL&bV536D2sR5e#6M1nHKBEF!*2!`4~_p`RhcD$17NitdFU zz{NIhK4#2ourtg4-7ZM{P69(Uj9^0RCacSqS{5>HWr{6BvZT&*I#7#dAhXnM)yL1nU9bf9*~SC}1WbNOfz+nJW@mft4x9@=JJku}}b z%qao=6&OH+kYA~m;a^ZK$+v)+odv^y?PZX;b+|Azd02h#wLumP*&PY!FMUy2PBt!pzVIURr`U+lta9^{`v3r@%|C+*A|UUE}0?=^0(J zRet#Y!_-*?M8R%fUlHl0EVJhS&&zqR*Eehg>(?}QxuY)ERflx$@M=!3r6wTyI#a#)Tb*S*X_&4Jjf zojynj{Yl*AfsC<~imfJyix;t;L3coNx=PUZC29mRv+Hj{Ta%b z2+ZIk$VS>!iQwX#Q>g7WYhi)0&qof27lr%UW{cG?GvaK}hZV9XY^AIlGGV0IjC%R0 zq6RR_KZFXQ9)b6g?=VVGo?0PShg$jTJmXFNRp*$6T76EKXQMp(!`QY z8OjexIky3{V6>9!2CEd+*%ViV>=e0k6=h+0Hk3wRHV&JbE#RG&8Y4)uvvhaVlOp(L zSUBV|ppe55$YmRP-gVL6+&sw);f@(k2yMpwGx%Vb-}J}m!fM?lbSfKC`@!|-qa<^Y zX8MYourpp*`#XeGPP?a!=;LvKzp>(G(nU^v&6Kr(U79$&snRXCW5uF=7j4jdvaudi z=Wn>AN~HF&af+h^5x5yrxzFD2?^9q4ogA1yGq_Hjia0RRSA;Th@Y2gI!xG4%^{1) zmk5%bzodso!tXg(UH)|O_sEG$e7^j7fNfK6kKCMvSCXBod3`Y3_Q8=<@`{TLKlW}a z&L{h&W7+3RxJC6_Ue@i89v2y9npIn`YMalMP*=~JIEvy0sIl=;%XVWN4pat%CVaXZ zA8jG1idngI8~oXA~;ymai{NA;h5anEijQfGYuLh(4kJs}DiLRby zSNJExNK~=+y(BU28j}Nffp=U~CG%B%SIkCWxEy2;W=hCI5gO& z6s*BicLf*8fP?O`UGVy@baD8|tc%;osuR+pVVOMhNGb7nF6JKd7%hA!T&iV^jZ{=L zU%t(?*vc&{P#F|-M?YEV&Wyn`(IZ^AR$HsW4&f_BGQp?xZsbq2Mn}H1jco*Gn0KhS z*;Cqu4I7A^GT;6&(fY*rKQ)b#yPYtVb8u+e$2{#V4UHtIoQ)|#oRLv0Ll#5A_W?1p z`Ge{B>LbMWhyja22o3q3A8c^MhHmaBLhSALdL1ol16FZ*Cxy`kI>x8oa(z(AlJG*6 zyQ1n}jXZ)u9K{42mZCy51i_CFuVCRhvcEq+G0mT;%~0*fk#!JRY`*0@T=YZKARgPi zNXLf@_Cd>P!dNqE`w}7yUMH(5$AKMm{_DSqzeGkle73@v?gT#;ICNeGG!R zzOJEsl-G@3I2dyt1}do<`6W(?s8B=#yV*-Z>6&@GEfL?9XjI6YztdD0Zq-r;etOaD zZ)O#ggt>bB^e|EWB3EbGb@A_{9{!K?99B8y`t+R-J0oW4T;xfZXDi(w;ph)=jUQYp zhB~UkP+}~{W~ch)TR#H9!SR)Psw=Z_1-MI0Tua?1=ht=TCJ* zbvc7>!|zaR43P%s*m_dPQ#S?wOw3B z3QL}5i>-}eBbhCUc5r6^^GD{Ii12}w$vkttnYmlaZ6(nAOvSr2E3;sQ%L?-VOG=D# zbu?*AMN@~_O%$H07uR>%>r1c~j+6&IHGa~Fm)vqTT~;uz@BD8|F1tH;+ce{Cu0jTI zo&NUVO*qh8Ym6j1dcBOVr&Li<4aN-&aaMDh`kI;utDV3E_yT5&lg?LlB;x+R5Gg3< zOt;be^stiX#^f=&0v^c{s3m%;$h~l>-7q6Osr%kULAxu$k*Ux!u@xn#L@y!j7kJ~x3&-1D<>_}ELY;8#9C)B4`r>Gp4nF!r}afIrEkgGtDO&W;h( z0%QBw@T1lns|^Sg2Yb*akhrMwkhv33tWQ6AV05Qzt9{|bnTsPzX7&=-wjhC000eNf z3>V;M$#d=JVbaw{)*jl;GbRLH*e|>wmwH$~0l%mpyplQEC!DB^emS7a8Ha`B%Qe9o zW!@hso$gwsu>d9u;55eQS0a)=BAcCTGh!XtT|#auj4<0+f7)Fu=ievI$kSY~Wh&7{ zO2NcXAFLG6zW~3FnAF)7nj_1W^Z1afVKhC02B)qK+Sukui9?)HHczVzDU^nYLn1U3y!FX?J1R&K z`~>n{TRz^ts#uAz&zAhc?uEtpM zQq81uU=~cYtOUMaMDrD7J5bkztOk#^lC+U<@Qt-arT3%o(;~2%mrVFPQ z^NqZL2pQ&)LLLGoZTBVDBFvz$J6R)o!IkcvR^WouPn-qF++7d&|SsZPKw@!9z)YlL0 z`Stfly`X=J@;nXraQDhy6l?gzq*Lh^=n<5qj0?T+J!#o7DLeEu+yv2Ae@8K6fd=cU z<{6b^pC`_f7rQY`){PN-q&^&FH-LQ>8fL!)9^6*^@`xOFNm6&%U*xlNi~hf# zc2YBO>sC=-fc!>##3!egtKo?}$wmIq(F2tvlfd1Bx1r!XbzbX=6nD#+$c+QFfN%5U zJ1O|^;gV|Rq?hP|{Gdvt7KR5Q>qH;uo-O9j%GB-EbBu6>arr&^AxF9X})vksfaSev^A5O*8$uNlB9jC z{^Dz?Waiw+a|12KU?AV?Z3q^()n-m`T&Xgh?4{@rcqV*)eClG-s}m~ME(>i^fyu{vI8C_ui+NJs(t@!<{0AU+O`7&Zr9xN#d~kDa^^LKk?3&H zpBWDo-nRb2Njg1-`q3%omJzaC-rTxnwcy0XWzvG}t^@i^I-)`%;(K~lUt@W4)V(Rb z-itCT|1(>m>wRd#VLl|{>@SxI>;=Xl zUmc1>mnxkJx!;h)Q;A3aR?FRhMj+BLF#Nply^3g2+Z;+^J=er*=mgi)bTvF1;1Cj~ zv?e1)nQ>bHT3t9fSGv&=Z==|MI}TfT1|Gh;EI^L}CSGxE*Fy0_Np)PFfS~yY4@ghFr!C zX{aw<tyEj@`;P((x*Dq<^5xTzX|~Lq`R7-8Edfgp+}?Klfa=&T1sd^MeTzPhSF`{!rf> zHJeP9N*Y}pPY`XjUiT&D3jjpjU&!ity#KT4p+4G8Lg>z#m)QBzcAiW2;Lby1DUYQ* zwFZ$F8qK6tOaM1;d0A5DrTyG2FitFk&Rz+dYL*nIv2!c=QONBxEdHG82z`j_4BjZ?}og{opge z^>gair&g~*diq3~qn51e%}WEr*f_bqF)`(BcwhfocPB8SR^N7ba*|Y4 z)$aTCRUJuuo9k9Ri8wL+ymY;fNr!(JJU>Z$B})*WEfI5stY&KTD*(}HG3e63vwLoi zw7!_*%a*IihiZeEq=>7nnc6}j|J^(`PihI@V6}^{qGd}83e?jVxmIZPk#TWhZEYg$ z?Kbb=5(wM^xLM#8n1*kH!1~x38MDFjPpg@0`WDhPXm-+clm0G9iC6Bd*+&oMZftfUqj!LPr|?ti>`fPq@p3C-aIbs> zzeQ0+p)3Y|_OhJIFrmkPC?lG`8W{YQZiM)XP<2wVa(jIe9HCkyw9^^w$GR6sAv1VA z>`P){DX8Ur%>~s=ngW=8$L`V>7Fx~|;%L6Xv?hNHk86y!_&{hBTUCr*l3@v+S;V;F z6*09nL3ejjN1r29EVQ2G*)=nKnPj_Xv7NT+eCjIowTp4J3m68MZ!9*v$uW){gH)@? z^QK}ZTJV1Atwavlq}Pb=(?Hr99P zhBs1Jby@pPJ#M^_*B@G9T!D1qCY}CK5!ffRPgZQISrQRO$nh4BAR|B<4FcQ-4NXcy zUS2_{wYz^wA>ob!w@U}3p!c}sZn!nZU7!OR=GgC_TDsUupOrDDrFT`cgubzazd{HG z+s!-b5lH~=K5|HJ_d|bwC--_(ICvfGFWr?~L@OU!*D%0b@4&pSbMv*;J$2<9x~dix>;>Hd3wz~OI(T%~DsHv}^N+=TrOBXui7n~WoLa;thn z@K7V`W^?j`6poXL0dh(Sl56uYniK{xcPNSKD>WvrT}fBEz!dCcgPldRjUfKBVeb+? z%h&IunM3zPiWhns>=D_qzxj@(=A}dVLI5LJLLw`U zIpv;%4hdUwmC67^PhelZHd4XrKfgL&>w48?S4#RyqEyF$%J)1qv+JQ%BOQ52G3R; zY4$rWrx0-ai&v2ZoUR9beCE#*A&!&2S9{~XVr9P!#?36s4PrNF{$WRQBI1m&Q zS zY$>DBVmGCzRzUt2%P`)K62Bd-2K?#ngj;_dQ@_j1GPWt@5m<+BDOy-cSeGpF+2rz9 zL6A%y{Iq@R&#YQ~T&Pf#TntSjX%t2IvQYTKpbNS3NkpFf@ycr zjS1dST9ZG(l~N^BV}42qDJa+)69}7QLcY$htSwcgr!c0DXZ3RGwK%h{q*_3(cuEVc zebs9E>q}FbXyq#gEZaEt4JwGsJ>K$D7TT6A(#>VF$?3G3#FoVKEoZ>ZnFLdzE}p~w ze1B+l_UZ5SmjE$Grf>s~FET5_rJDH|0XKWd59ia@fR0aOtL?23N+nq4g$HP{@WJxY zR_6ny5#`K0d)Pbe3+L|dBv>;{;quT;fTj_#l0F%<)=13TlP|>N8tGj6cdtW+#V|xQ zGVbDa;)2HQ-TzN&j%DA2U5msFjXE|CH>0#GvcSN5s^!kd7mTV|{X6WqkqYVD$_Gfp zIw?;zuoi4o1qkq(28%-UC3ROLz_J;sf^vD|xREH}<;E%M@|OvZOq?c1TF=Afm^4@g z{8<+fVH6S)g7)`o`+9^nd*!i(bDDG_nXJ9f5+kM`mr}jE(ZfjM6ZaD)L%yQunNz`q zHCeL0ZF20bUJ;@5G#fky3I*<=tttTvI){c0oXtTsd6^jLNcM2fVBDj7?#fx2kIMprGXOj>d4ZSHQ#AGRf=LQME(5|FjW8j z64>vBhATCdC@|6}OD29yR|Tt=;I|(o!;NuJ&mGwOp59SBM0b2kH)ESEd5Nc1g#J+3 zmJIzWy+~teh%dNVY*wvDgev$jUyuVa<*u!;X%>x7AeTMYASJEAWNf9HOViVptG%6l zTf(k6?b@dcnIkuNvdKc-%=Uf8IVsJ*4hL7%dmae1xAyc;RlWPPyD5-K7B=1xWNFmFWvtKFObP+wYqsV_Lg_Q(5S6IHi; z@EzLioB4@Re#j(FqCe|t?Z^3KhzBj-HOtT-Wh>VsdZ|@x_B9e;32)Qq}!B2f(6T@~hfPT*q3 zR>}CV0-e8nUyL=U^Zua>Vz@)^`78&ZeFS%`I^gsiGb}=vtGz=Shpdj!@0wD!uPGZ= zfBmL_)99PY5#?O>*eWT9-ST%`#+w_Y4aH?l!|1q(+(0hX+;^Oma(e)Vz`ht=PM7Bm zY4}VU@AkV8x5WaxN%pXBhkdCix9AeZpo_{6`>;Q|EqA`U_+Eh_aG|yPB7+TBEPZ-) zBx0Dd9}^iFT3Cp#!)AhM%_!*YdqeZ)4UY9#*0*`$V!xSYr?sKW3D(zQ-5iV>>;2BC zdq~D_e!$}|-?HiC5{&$^!v8Sy1~U7$P%G9`!pV$~Sp|fYA`KwHMLFBB>040K_BOBg zrM*1vBp)QBuPifF4QwcpEcEw@PFmTpeRw!aNRl_WqHZ^XO^3 zdD7tVpai4YBvvZK1x8+)sm zk#OW-pBfVzWk*F;w5y|%~;%Yer z8f$`XM{Nrox6e!U%lIzfNf!6A#8Mqq?5YE@p3k@bkjHnF)B1CAadoZWN@G%X)|3#R z7ELZrBZ?GvrJf&P9u^Xk_3O>9!jC`KGz!aK+J3D0LLK-(1?QE!&W6V&3Y=zL(NPaH6|`> zn8NIpfhp9+?t_E7v}>Yl1c=gfZ@;iJ`rlqM`^k3T{6^~ClLMmQ}%PRBK$NUain zbD_Js0eU)kIm+n=)7;|chy{l2?h1XdUqKaN^nwYu_KdQ=pjwrzBVj;zC1^SrA0p&= zh+uBM<#O`_^>8VWgt)-`mnC&p*2?-i1SwwCQIq;mtDh@nJ7xnpGNvoOG^Q5T@%zPG z)mrS=31Ww46QCPvFg;ZMbF>4BTTH!U^;~2~lyZ>d$M#O21BqD-*D;8zu zCFqnT5hzInjliZJI9ejJmcI1A$xDZ&PBWdF-&~^}AO`zO9s)0;i(Q?eWTW=`(@1lT36=QHcG`6#{CFa12_dZr@NT*L1=dPu3$Ci zPBwp;Gw5oPdO!8f*vb0~TlC)Y68I-YGSy*HvAvn)!@ikeZR0=%raR+nw`Q9E$|ZOx z&CQP&{o|PIwA|DA_yHuWh(%3Ile6)xq3m|5@54Nm&T4{=myZw;BnJpGcfN$2Ax)hW z1xi=Z|AAOWll><{M*KHJ7D_Uv-~M!p#OJ&msdvALFHHTz= zjf~c>sei)QfeYYEIZ?%b=j9MKDeVWHb3_$5M3ITSW`S38Y(J5#GdFvj(T=4{wIp{R z-yLQu*&|1ngnk#|RT`+f$f|!syO3buBXfw^>~Mif{}hu}IiliTN~qqYB8hqzl5E=S z2Wu!=X`TTd!(A(hdOpUE?yNL;k`pEb6rvLK`(orrtI@2_|L`;&c=o6!u|Aj^kUUTO zG~e|cGS%8|W@ht6lApy~aZ8_MC657VzB)Ag&etZdB7{&|k){rQVMKuA<)9)xS4Dsf zo2@qT)sf1^>Q9USF)|B>XDbwH%P{;L^s}p?`orxu zqSXKzcn$aVHgBG8OhZU0Iajuf{s-MBp9s)cYpFgmXo(lTtf78M-aQ@Ax798_#4h}X%-W9`ltH*n1yLm)b%s{zkH2Qq4O)q%ND`8@u9jjhH#movomA(HFdVz(>y;6YXOHS5Z z5G(Hcktt^V&a$>m)x{nzpzNi1aIF;}ftm!ulC*)|o}W>kja6`Y8Zfci*t^?Gyfotz zJ^$CRY~Vm^YW>C~^)TAnkh^DRsVj8b%$Ayf5RZEr)!ddZkq#oxx95Z{4~2u{@b{P* zv3li2?w89`^hHGME@!y70-c3YJLbGZ!CDFJK#t$gR2Ho^>Y}Y-ROU_KlpWmsF}W4F z+^JNZYK1jz4~LJinCruhrX$Uszcj+RiD0Yn^Fcb%z*~gt@3mxp?^MfAD%%NUV67^e zz_zo)TlAK|6a3Y!N906E29WNXl2qE!Ns&^mv$Jz=^3UnB!4V%o>nD16e-Z|lrhe9k zc^xf=l$P3LiTaS;UsJz#cjsGepM((U8>ER3KONNzl>Ji^MM3_+Ek>^>89qP9=z6-mL-cI8CX~KwWs9;JGn;nBae?P_?$wy zKD@$!t-D5yvIX9j!~1`UVWI?+XSr5e+h3W0g6|$`9Ci%{+GIbI(}dSk zUyvW(C!j)}FKEUFvU)&2JWidBg6Q2COc!@MNfyT8hfy2CRGM{m*Jkk^Tbm@;II1Qp z3SZmbdG@xy=EVVz!4a#9)8CMQwAs#=Ai>JWufh#|9~82xpGB}{IfLpkmDWu=%mEIS zAR^%xI{`HD!j+$7M<+@V$EJ!x$tpxg@d8i_E3T9wJd{3U-%Q3wPn1}EP zG?Ya+Piw*qn-QDl*rVQQE9L_iG)oOssgGh=3PTk5FZlR-hdM!k8TjULa!^E)j|ZX` z&*0NuHn>(AlZ~4xey?%Z%%wsYFxyFGC^8@6l`w#EIE_GFay4*Nf3KMk)AWC(jSG#? z>;p?IFC&;*|BnA5j|ate-Z_*xgw+z4s7-6)=+;{N7Dq&M`ck5Xf*{@0D?x{F+VG=dC3e-$@(|`r8N3w-{CPf$V zBlhXoi0wahgJS|}L{LVx?4HiY2(Y+6I$W8FupT!VvS4L?r;x*48TJ`Igo z+U203ayAcs;7C?X7&>TuJZu=eJ6?2pjosJcM*NAn-FloV{b0Uk*gQS>SZP6%!2NL7 zn7;(xYo8|kRmo4QT0n0<&1bjtk6M2P7v<@K27;~T>vXSjHV==iKko}AzIE3lO&p~I zq`Mc-k5xxZ*+WBSrEB&@E$`b~;o*hS-1fXq4dW_!eOnT<_JQlLB#*URBRTh*0AE`x zLlb#`E1JWP0z4=Zap)@b4rXSdM=0&ETTZ>u$yW_SDwm3*ON8dJjZc^^X5*rL#=?w! z&KmhB(HqoNeik#zTJ5X1&3w=5Q@)?jtJQHnQ6_dZP;rT|sWSWS)t_f6O-Rg5-t`2M zYu<#WY&{J#TeGkCR9thVwS6;C{drjR`;24zI{o(v9>fwcxN>UBC6OPsdBkeUkg1OcP+5R2eqa8~oCuz+fAey&HOK2hjR%8ITDvdBKD z&vEZD-j}|%F&@iP!Q%*I{3_N1T*|^um>+^Wt7sA1f=eOW1bxuC1XtRU-psSa;8*}D z?43|f#N)VXGpLC8s>Ayo_IoB5F{q5lyPLhV5HW4zfOb|}D=`twa?*a1TakjD=LoiK zT#*~ZoF*27#~}d614O}u_YlR(CNH_Zt5*=8-`r!yk^KYgOSr88tWv#A-GZha7e0b> z4lpdIXJ_x5YH3)w5iIbAkK==pr2m71VTUI$ zBm!%z?!q*THiM7JPr;?aQ$x%`Rh=3Hi^vz^f;1Y{&2M{ zQPyz+IC#pangh*jKKYdk`Lx&7N0&kWV7%G|-;!zZc!!xL=7%*9pZ>+gg3)YsSq1qFOyIS3_d+)ajpN69$Ol@$CXIF#Sq?5KbJ zT6JqpCz#94U}?pkV)>cP#sF_X`BdEh@}-%zW6?s6I+{_l^qK2Bw8i+QlV85OF%I5` z5Ox59%{5d60e`}PsTl^ zdL5|!{k<43Q$bFY=Z(6NW=EQ#ea_Qnpi@__8!43O-#ybKzj#FR->geZrT*fqLN;vM zGfbP$WC)~=ZQZHY9DbS^q*pNxLE=4=Hc92XBxJzqE9p3kkL(;~FZnfB-+=vcGX)o= z4q9;J@R{x>9sM(B#)8T=h!w5026-`j%{5G)@Qo_rqP>h}I?k4+b4t^alO}@PesZXtHswgg_n4N;@&W_6FJ&Z& z-Kn|KW(VpK3*a3X?Aj}%$<2PAMcQKmHjmB_+LMW z!`>V=ON-)2)dM(Mr;phn_oCX8x*$Xhw-1d_BY~GcO~)F>^LiXyVvzyd2plfEA(o8y z!*OK_4%tDPJG>6#o+2e(=f^u0QQ#fH$!dpMw!{715jlmhKcZYh_SbnbPgl=~`WWP_ zEKxJ-5#aG=*H)!bFi{7;(GLE4VxW`vkUyel zVE7@POv#GZ(-4Y?-#bLl(#f#Pax0?_d@X|k?+4O}QP6nUynRHm;A=JDs|u`T1J|~g z1npuTI(G_=gmA8z26L~CCYK+wTP|ZWpKls>#;N8gV#gagYxAvtT?e;sU(*DXoeW<& zgT^NjN3AMW&ee9WJe0ILxyF%v%pz+!}=YAHjpOZ3MX7hgP~lB2Ax} z;biP$31|!Tbx-Q4)r*SH=68Bhk6k^+u4M3DX2AA!C;4$^ac3_QK9u-GEY*ZJ^QEZJ zX_{etO36ALM5%klPA!R@Z{d3LG<>p+JbgAqEF_AlVsW3z88#)>Iw}R zyryxTCqhK@>+$S2eBl1fB#XHl9kjBP?=+~hJNpw)Ojtk9?%ryuf}SCkGJ4hy)HA(= zrBsa3-=4!>J5eWKHCqwO9Bv7QsZ-PND{X@H6te8q5i;#kzhviQwcG7(m`VffYqSt} zZMEfYAhj@EHEc6}cdpK0af+YtbAk0vDt5}ygWNC`qmy~O6iPeKEK5QSE* zg|jbRZI0Y3MaH+V)X*zqr_yr!)3E3mOKq+`4tn2%9$zzwRjSle^etUGxorMo&JuUS zg2!y8MZL!+RfwQiSjQCH6!c0a4B<{IEpeqW+?u`(?V)|)ak$0*`sFE3wl`AiYSlD)&Cm5WVEjR%mozl^}j>3ago)%s}BdD^eB#vIPq@CSZV zT?)KQrb9P{J6Guh#e7#!b|KYYO%NNk)%#An2EtJhUz7b^&Z7wLn#W_yR*E-Z-(qa` zz|3jokGGH;pRf)R+C=WrCs@8Srh2_Oh>!pc3SGXXPa?iB zLgB8ojE*EJwtSnsb?d*Ymew`_2)N0rqflca@Q~jJHR{KcjsBMG+EU~bOwZbRC=H#% zE?(%qz-bw(A}%Q_;o>0uMg@0xSu;_Um1Itb@RU)sNQvOAp`_X~j2yu5YP2{G&^6Yz|@dgvU8oX%c>K2e6MYGgm1mO5E%&4&{R( z^sSyYL5@1`8NHGdRIQJ~DIp@nnHj#Y!p^l;C$J+>8oei5R9ou%IW#>PWO*9JfM?b3 zQfbUhQDcJ8wtryW#yrX~*Q1)Gd0L}`b`YzykynNVHzMJJKI6wZsCQZXnXDyuZ8Vk6 zN0zX!w!#4G(vUchVNK&Heu$zk0MIP@l)PxXV9aX(E3}ioxp0i0h!VpIWJ0+4 zP%qQyB>z9rgpXS}Kn?YE)JAs005}^xYwo7|XFu{)e2(U#nPG1$>be*y}tz za2?4$9u@+hBR6~dha)>&jf~OL=p2> z3$R4=;AWOJZlVaj1SC&_fpP1{+1BoCvxGeoHuUtH1-Ik!CvTryi}9RS@CKf%$$lj~ zGEzS49S{qfT6FH>+JYxh;nQ%h?zGQ#t$EENTB~pX?u@J?F7)}URzLwH)PjNwy9h zTXDT>qin1DnEUj`%dzXV&oDL=L8E!W|JJZ7d@7J)e|)7H{C+<5Kx4z(&xJ2hE&av) zbNRQ=UfJ8Z67OuTz*2QTd80X(UR-y4U#m1JA(#r7@OlGZro;T*90K@F1!(v#{4|}f zX1mDXWd!4>i7p3LPA6;k;-ksL1!B6(eLf&8owEJbP7!+Elg+o4+TmozqX6or`=aFD z2<<|KxE!!XGxa-9lpUP=C3dyfH9T>>&eR@}GK&B1^01{_c7QX@I{SGKBBJt6;681! zSah51lm3a2n54?%M-FSr$9!S$16nQenbZrZ6{J~dhx)wh2CVuz3`r$N^@*z)>ZY28 zj@HUI2jI(auK}GNPOU76C7Q^8M9Q~+MauIElDVeR+c`<$eTPlt<$&`SgJU`Ge+Zkf znFye34KBeg&+6T^4oY9IrVn0r= zAuMUy6$nJ6pm4R7bC`oMRSDVNmU{@Ekb@3F2^pxbR<;$UE?3aPjm6L3-6KqIW?dSA zs(n!lb|l3p*Q3&z9V#%g-0LvYgX35UM~xRaGv&gDmHXZO1;U_)%5Y1NEMRJYKy~hN z9mHb*TPxE1z6;BR?`?@x)+7J>HPGt;kJ}#3 zmm#c39_!!xL%{-$A53PKyX7Tv=|a}lT0<%l*51GZ{hIdie^Cce{fe=5NQFxAhd@4Z z>cWX^g#Ycz@K^Q@Qd4_7HHIN>ouh-n`c99~8$U%;y^Y4i&rK2|knt>J`=g_AJ|jN& zgY+oJ%@_pp8i`-xy@eDo#F4w5{@8v}^pneCyS~XUYee{i?zwB`!iS#*d@3r@%5bB? z#v2?GM*K|kO`)fc1wTvl=g=o6gNU@(H5fk^wFGmAE_tGqJXjAb>*G`K(ubztFeJR8 zwN6Y8WuH|6pEp$1u~p>mTLH~17p@fbMnk!V3mpJHca@cy;#yqkD%&<99@K~ngZ{Jb zf0Y^If5C6#Uw^rmH14eHZ>P+p32W`|FB(Zc950|@WBZL{^1rkQzxbk(Ah0`IOYiG$ z6IAVxneUcaOag1;wHnXHFo*~P+zpb9?5~o!8O-(Ps$g)JI9iTyv%S)tK9A&M4Y7z* z-1-F76oLogceI&;2%+KTel>Fd>kAR9k5m0TNmFU&#+W*owgqwN+!^U)J-y#qWan5C zwi|~`Wgnx{CLlZ@uNu_foyB1C39_c6eKQqnUT;q)#9VO|T!Cux&3OBMMjuu8W5hVx z)&Ioi--Lg@4TIer0A!SeA>K63M+|HRd$C{EF(cbNiRW$RoDca8JC*B0iso78wX80T zldO*i;8ZL;jx{_i%am%Ar+cR?{;jB9+U01#BkP?P*3w(AUdy9*D1NptpaBi-Z%uef|2T=GpK5iqbGPz6V~qxU~*#GXhndY?KFdqf^)fGhwQg@DdwqD(=#&58Ui7=#-E7k9~J|KfAIZ{e-c4p0hj6`0o;T9)80`dyq+;Y2T& znLAag)$fs~v?KU!__Hv>NBDX|#Fh~WS;U^wS@YXvqiJ(V+q*T{i1*EH_)qUdnN)6r z$B50-o|5H&+ySjBcMj$(&c(;SN&6MCp2)pjxQf76Qk_?}aM*yramHU5gG_B_huD_~ z7mCDxm;Y^nX{0l8q(k9xZX(T8aEDJRjf$g$BId;Fk@KR>OU3O~F0N?4dK&Y5K)NU` zL<9Jl?fduI%P%Pt=eP}`h^QOSk?B3@y@-tXxytV6R8n&1TFhR0Ov4jbwo!^)`AYS6 zdSv*`1a#UdiJ+8{I{=yF_6)CgnS}EC`M&xXn$>xx>E}?*3zq5Wip-P}btl>hs=NB{ z1lkPZ;-B=q@3)0 z-y6BP+btnx>kG=}Qc-eQ%zc0fvk#QhPs1YsA|s!*iR;Nf_7ZHlrg3bjw^20BOb_<> z(yyB+Avet`(N28Fc!*On(~%LYEZ0R68?h^}3|X{U0TZ?I)g+in`{p-V(z^3iAgnp2 z;74F1doHRDR4`@~VY{*Z&yaNI9yzY368DMD z`+5m*I6=d%F|Dj~OEs2u-XF0v?7BtKtyxKVeL8E`yuHwyYQFi&ak-t9Qzm~|#&U(u zmee)pgXX!MsP8#RZEB6FT_2Vn((nO>QVmvoH5@a66RY#vMRa4?F;bdSay~kzNsMaF zzsD%cj)v<f6C3&OwRyF>JOA_@{uQL8{_1+4vf_KaC_WQ7ZI5ne-3wXOD zR=wJuP_I!d(U3x z`6zlip8v8eSIO(?;gr5!wqCt@%l4rQSMqZcbL1xl4Au}(ymu!tL>yn})GO|*i00v+ zM7*CTjSNxSb~Qx(TuHq;mnCT2SwSSlTfC;Bx}C{TJ_ehXNVp1d`pIDEMkz@AI?Z&f zBT5ZBN1Z8l0=i~{isFey`vkvHIYnr0&T2g93gXby(yphBk zk1ct7N_qvWr;n?#C`&;Z9Pr5li6b+mGP#>z|M3k#Z`=M8L*Oj@ueFrAtfDB=-WECX z-)B?T=W2UQ&#xJsKm%Qa#BqVU|13humiB=!LZR(*ev16A_S5@Zhd0Lieia4cQ#p_Y z*CJd^i7yV8(N;bqxkT*Ly*XYf!z@-MNA^oCat3hYyWM&8&B(%y#s=ZynX*^~?P1ez z`BeUJ@I-4xGqSQIWFn)8tGR$GOJ&&9IY}SPQxg-9X`65Hn6Yc;5Oro@5BB|J_u+yA zxl8u$wEQF5Dkh70N(!@Kn_#f+$-wE+JOzz~2#v2bjyOHzuSI(^G%~sNvlL?Wr7#(c zu9V}pcuI+|SPI8HG=RrMMqu4LT!$Gx1S z(uWBkd5;w`Yl!&pwa3(b==TrpYByi*;rCw-UWo{|^sbtz?8lmMuD$V*+9q6a^2dMGSxT6erkeAzCh@FfB-{6Xa21m(CMgBL-p(){&t3Pgc2 z6Wntk5-UybJ0@c9%0;F=XC(8q`0+}Y<6BKEkyv|Bt9@u9%D5)ed?D{Ok~pomR6h93 zi(Jj;$aK3UMx3}P0=g|AYBmh|sII7!qioqD&YJH^r&(qk>`-GL5w&sgi{-W2AzlM} zMW(6wwOt?APg9~HVbb=_X+MvQ_iYotP=%k*tdy3mgmaZ5h6JFr^}ow?vgQ7*DeSq3YF^geOsi7|6uB# ze3`~eYho{~L5Fb^q zN~b^NJP-s3*Raw^8seMh;0{U zD~-Wgbo%Ev=elLHLgWTU9~ULHut;>F!sJF z87=OP8h)!LyDxg9aoioo^dolalz&vpH^$40HVmY(MaWWvoR$^=t3}LKja3obMEtl@ zRY-GQY;h`L?zNqMdWiZu!D`TR6bGZ1G_T0Iz0^fQpC^f37~gK^Y-$eRd=g|01d+NQYSt5vQJ~y#MlRZ|Aq;}U!ohGP`L8_$`0>jpFN)b%%i3$8X_Nu zjenXzcF>RmsCS%}&DtD5*+6urkQ zaFLx*Q-~N|I1Fmc@@UiNxCBF&L8x%7M_?&!f2-e9JZ(`hSMq@^jx519-aQIV8X$;F=rN zD_3kF>JK9h-cCdjdWpsIS7VZi7D8VSoA6@?vixRk^jPwDFNSr;LY6X$(nRVw8T8Z4 zRkz9kbEQ1?cA#)COtH}UseWO6F~m7`WNhZq6$l@~L8@e$jGp~&0X(_GzcJH7lO-bf z#d;hGg=7)wn-aqtD=#j*RqN-lKzQkGzE5Qpuh%@(#s+ad7cE z#I1zWWrO#9Os-yvi`L;^jztnUfY)5+WRvvF_s+q-&F@ z6WsT%fV^_UCD?;!Z#IY)8;PP$?--zDRyrQO7Z%e`W7}Er!-`zF%GXA{@hYU{O+%r{ zgP2sX=NNPfPYmiH#dkxTV5+kA!wu6v%ZmCaCsR%ur4HEcB6}ea!yc`;z$6tZLN+6% zj+zji;I{(g3JaLB)K#{(Xdf24=+*Il=STIa>FR|yp)255q;ZiYNBZQOeWo@`SkG{` zHd6TF!?og`w%np^IyTI4untSr?dee6Y;#t_s9~s@vk{nH!cG07j0geotb(8#eKZLFV z36TGTq(o7y$xh0f?PN&fV&CK^jbk3O-2|M=S(z;X7Az3F67PpxLY~N6+DvDL3b6jn|Js2hJ-E6jGwk- z7>~v>GjrUJ!0qbrNB^+y-TG|*qbT9>0V&$gScK~k+W`G-?(0BtGNU_kA^|6~Eucr_ z1k|>?eu!Jcnf+@aF@-)ip@lte${AW;aOG&Xk*>uRy~I$EVZh*Ud38xno-Blb&o4}s z2C)3W3ner0+1DQR&W8#&I%eUU#pIM$uB7qB(e|)W8K)|@1wP#a2xs$^H?U&!xNFnq zTtH7zx`)ccJE5P)~&dQ%d5eg3G5FzQz@+7 zqas@QOXu9%oC8|z5SeBSqyQmulikBn!9 z4}Ov}L1fL05BtY<;~h8v=$DG!FDfFR!Q|PzC_Lh!J|g8NIb~c)AKF~~8SGv(3(P8y zV`YL)YnBHz00oS;6PT)8xq94d17wt(t;;qDbbz2L`e`$!MyVG$Od)ajAYd`zr;>L< z+FGG2twG;$76F+SvE$Cd>l5J<`_g(7l13ZRkY5u*?W+1vrx)bG$Y!x!cd_>v=z4;k zVaT-A+>`K79Qp2^&L3=bvJ5CTOE7OM(~ak<+coNqNNiGuzQ#K~R2PO&CpUgX4)HWK zFjqs1AXEh#CqOhNN>RkTQdh^vq^^gFU`zCdR>o^#7d#u^ef>5(vu7G|$HQzLm|n5( z#Pgr}k&|r@y@>2_aH};kS;fGVV{u@_Wt`#1lI1%45M1$Wm;5jZW_GokLqLcd*=p5~ z-U~uEpdu_q8Tz9*cWC>OmE8aFM1w;m?IOym^=_Ho^*{*4eo3*(3#NNQ0NbBDV}-O8 z!}oFTCD9j*IDyNR?XV9`?k7n3)Wg}$p&TVFQb)#)ci)LyJ=K_%0U|EGdh7nBQ=Q%SeD%-U>w@K0K-;d}y@umCU z|GY2S3(5b~y4u04J6iMO9f)Klb`N)bGIzGK6~7nhQ`Jw&k9gnhr;@cL1}@~5N`|rZ zxJ_45OfP@F8lkv&x%2+n2OJ)$R|Dd~RWG~elDo6V;MrJ&=`YT1u-e-1v#BsIe-cV6 z#Pps*uT-GpBWOo757sM)LEt}xc%uWWZd=7DG&JQ0F^37+F*8A%%5*6~27s;K=d_kO zlNVEEnU0{mU#WEHd2z07DKm}plu>GKgNNw6vYzK@`bE~%$gY_wBBVg^Fow+SX&|RZ zkWO?7#-h^jc921R^mn;vKkGuzgJIM}7JM$?3^^J*_fxK~!dxVO9Cq1XXhHoXFUw}V z|0eQa7KgGT!_cH3CzY)U-Ue4bAYp={B3%G(f}gXm=T?=iQcrxaN*zv~39=lzh0@dC z`_*UR58f*)v}u5GSS*3{wwe2C|K8k2TZpicMKbRBBxh#Cf5aFLp@vacPy}08M8gfn z1rGCJ=pJ$co~!fZ%O=+s%=&Fn430cc$+53mP&4#h<^3%NX@annx36$#H|QBoFA*2`IN=IcYFz;gf@A7s{o3CAO2YZxyp_ zL{jn8!u8_6z7Nj5V$9M@a+%;BN+?lA&o` zu((B|KXX_aG$x5@^%)X5Ex45R@>h@AJz7XkI(`Tgye*)2ci^!nF^E&rNQ(@XUn>Tj z;Fz6t5Z>!fnZDe<|p9d>9E2zolSE^;f=3TwwF&H?Y^WAMLm1Sc7} zm)P%2?tPg(UbH-2JbGkkxJm4sgpD%fv@n=kdWQ6x?`3z-^f$wF;?|W`^>mj2OYY;3 zGkZ?LLkK{p;SzWLBsT|jQSNpc=xW`h8T}w0T`+M<{}2Qi1>Kv!S;@Shy>4K2EXN*` zNxfGcX2ro4^i6G&NbYTI1ta}pI2WM58BS#L*h|lZ<7YgFI=%i67{@L;;Tvmk2J%Y{ zsS|C~$*2c#(;jOp)fTUlL3REkt7RH3HfY~b4q>+1lO1;EF%MrbVz7Q8jE0+Eo6XYj zc0U8UC5!${xUm`k2?wlUhB*5|ZR~Zg09#orwtX~na|K>Lk517pDD4|P{cE66kD!ek z4fHW%Q>Dh$YR4qYqDugh=djQA-QglU&(R+tyfk_5K6cnk1x@?lWn~m zS52_v6C4MG3f{UQ;i&-u!8@)Hi$|nmxk-fiLV<}syF)h7PKTt^;84x( z#{L=cTO?aj=p2*TfHl%tVRo*8SZ#7cxMc2-d)#VQfbPf8LC42n3 zqcR?G8hjCN<~H~tpH8Ux%(7LC66G9}eb&sZd~%O}2wN@Okc+b=wL$u<<&7w1h*9dd zk3=-&APzqOYuv7CNRS={7O9hbXoMmVV6|qPR{?PN6!|B|0&Y>I`qzq;!AVXn0&o_t zh3-ncu3E{g1lcGJRUo}PdU`=xC(!KyH@*ud`}tPPeOQfQ$LpTfDmsZ^Pm3GrI#-0|C?@84Y)eniyIFr_kq-ie0&y&F zLk&fhz|u<ZRbE;v&JbKZ1G;F5g=%kFE2s6d>~Ed6Q<=2uHwAyS21*^93W}^i=s?1s|Pp z8_Jh}`-3wqER#@Ya=aq*2T`cZal@;1zi_z^v7~QGn&lpm2i2vg5#*b}2)`b9>)`JP z9-#)PuKx78`n0y5CuO5ii%p_pyUaR+@X8KU zo!5^Zjf6~ZI+n5uTG>?eh^mGsg~RK1l2%um@~=l z!F9RXDMA$H8xe2jGQ#j4<-eerOCn(b)-+tVJ`x7oq)Zs=TKHF#kJJ%EW(7so-ZH|{ zMlxQl2RSo)Rq)!{SfI=$Y+@Sc_{N9wi%HIl4dgniU__b_$(Y8Fr62@%$s@V8v?xLA zyP%hgZf4v#`X1Sv#XK#esmnhKacLl2_+Yhh-|=?#@Wwjnp`Z2{kJsugkCqJ>2u=~O z{wqzMKgk!Vy?vKa+DhuUwB0^5Vqg>P^Qa}aD@EZglBxnm?8ns3dYixf1H?Jj;lH=} zMqkfx@HTbg8bZyxK8V>jp&k5jMNYgdl82jr8BBhoVg$hf05e;ruSHMwdHSl}NOn|m zN-QwflYE?XEcwQOj#(mMrY(#Kqs3u=(xXSG+5bg|0tK%PmY{b4240Q05r_A4sh9BN zWbQ%@M}mK3R;@TKxV+O3e>>T$p_AC;dw`QI(@3IyBKHgR$vzMFSyz>9q0NN=P8$n(kv_8vEQc6rjG^;2ZG@S?wAVGCQd z>1zc5jcUI~;*M0gg~9;~4+*v?WYgJ9F{t*rorwCQ$DJC`1?PC#y;Ps}r^HaP;qA8y zSwo6)BMn4pz4$JfSy?d+dXXtb-wa3H@yUYqltW`v|BAp3C4o&!FW+Yuc|dK*o<$?w zPgQh}u3MBb*^9~^m<%!KXt^Kv;BDP!knYcae!mYfs+zW+*}Gwg_QLLdsGM5oN=smN zmJu?m%IP7y2|Y|9VvhUL!4s2Ov^Y4P-kErLnv3R|rI~06x&NeyaXH@ldzhT5$KetjEl$AZy@{Eb*;Z{9m4gztQg6*e zA^eE8x^_tB{GbK{6GCa?19K1N=@N0r>f*MMRNTh7zOD+;U*-o?NKpwT!%(PrPydfM zgGIa^!N;>7#+p1YaI%Fx$}qaHmG5#a%p8owAp6USkA*k!7G=m<#=N3QpB{3{f8dJR zBC#>jy-f!i7*}E4L95el7J@D#Mo=o{{5kZhy`|;_^U_sNu%K#=5C4~jz!sQO z!F6U#G`e1xm345v1e{${{@7_F6%-0^yx8?wXgWb4y#N!7|={su&hAy zEE<8i@So}qK-9BJ*j-67q`Q*?CtU;-mCYMHT{PlP zJ~_T@kZMBK>5VvwAOE#by!>Pzxf^n1M)m7%`0)+wU$6-r>_i{xCsW$%AXgiAt&qXe zhy@&vZ9z5{C_hzQ{urNM;p~@%g(1cb+u!U55HKGMo+n2`XKQhnH|1ret~|`+tlr3 zbLgcM2?l2~)9rSecw7jhCMOFy=n0&6C9DY0)#RIP&0=#+DU!gq@9z2-ptqHWl3D|I zrXEOoOKFMU2e}_JhpCtc%#-`(dHD4zj&^S?&DdlMj6oX+rrM{?p_IpUz594W=`|x* zOAcpYq3|Ue>?ihzAI=cfHoqopJD<^&3c0k$cWz~_yDs`n61jP{UGLH`#th4$58yuQw9Etr2o!^P%kNlnI{_KM}qG`)L_Q`lwI^&L)K1~pTi4&ka0p-De4kcJK zAqUCI&^2Npz!SI2@Rw@D+gH;-8oo5(I;tDxa z+xX2#?_}8Svn<^>*>hqk0VQ1$ z-f&9c;~~Wl#qlUpG!o%{%Ek@WD8xlMPv5N&wHF4H4uOn*vm=H=6G~+_PsU0waS&jZ zFsq2+#*?mC+>iH3SqbcVnJ7o!Y&ra%Ze^qpf%`{rC0)l$i06dH_UN@g=W!!_V#BA& zc<1iA<^?pe*+53u$739!3m$*WQ=t*@1)YtZghq7)l{@kPW>%^=-6tp0C&w$stzK8c zrrhkr$M-Bj^ho}AXfF|*V6eIgb}}y5LCSq1o>|2em;ePVt;x-iyi4Ix!8ihp8YnUY zw*L2ntf_6%i^=ukn5pA*3iK6akp$d#>e;rL%A{D`5Kd|t=}(}N5dz0gmKnL+bbt{M zn?I4`i5>9B8`{|}BxlWUbb2t{=K`g5(`UsNl#f~%fzM6q8M1^45)_!&Zt@viFDA)n~g0nhLEA6!aJaUjCb|p&|4V1>BXb{cyu?WW4Hlu*i_rDC8>J`A5BcnA+JrOZfD`j>46HxO-k;7?M-O}FKo$ecHd4j)F zo6Vd46$hPF&UJ?_EhZfz)e2c1FCa`r0uG|FXwKg5{Y(Pu$wb9ZP;w+@bgmOlE;wHm zGD6tBV1feSB&66nYXI^X`2G*+m5Y#z&la{WcD_o%!yA7Mi@fti`MZS#cz3YGC+vvY z=b(R+-MKpVxkESXm4R<+hW$E0i_OfuI8(nD%NTt0!!O)=+Me?Al&eRtIXD%nzA@e6 zcDOcM3+T~7Affhk=GnLFq4$h|n%LfKf}DV$0i%|Op^$|(XE}*{Oon^}PYuvmgHy~c zJJgd4KnwhbE%E6o64|dCZU{7Vfe9rvaf!Qf8r21ve*YAOYW&F>gk<4b&9A$*?st9f znp@Wc^D79rjWv99);}nP*Fl+PD)bgl5kULw80Fc`vaE3f8IGV0%{G~V3TDabZ{gLd z;fCM+^p@~IHY&3KFAD-z_@O~GCwGQ?X-a*$TT;Q%FMNh8bZtWo;fBbHL&oBOKc?B( zbS!)R@UUUC;AX4T1|2Q6deS!jWCG9q1Vpq1TzHjS^o-vGoZg~MJQZzQk|=~|3J+-% z7T>GoBS!X+kOBPe8zgNw#B{DdYOYCX*PM@(HSrh53%$qtXW2|eZAl_1$>BY~5l_{Q z>4v%}>|b50{bGwt*um*i%;6X=6BvWp_|a38%B$1vjjCR?*i*mPczisD<$WDXW?NMj z0rr4`$pVs;5PGUR-o#Rx*$cD8utm`gd8Tzf_OEk#pc;y62Cub4o!VQIfpds6lMYX; zt2;f1+Sa^CC_DYqI&S{`Xz;dZ9k8$*8KSjlMnGzChG{#EMzvqkNSAnB!c-MF;NHN3 za-&li@6-GYtHjDudIz*$!@lccmu8__!hundsVRG!3~tmLQZxq%*v;l6WKI9y52Jdv z%YLa{TnubR-_K*e1PpQ3KH0QXR&uBbG#O6qav`AT#DvB}^p6~GUd(ff zrNVm1a>0@#wd0YjvbU8`-sQZ}Y+KdPnW`IK#uK7jv$3V5^PugNMr=FaIHo!+rYIEakWc6-z_>9+= zi~v`@ckR+;XhhshwBt`_&WzWE4&-k#oKpLUj%b8R?o9*r8?N^h?Xdy(+U{iJu}No{ z-H`zC1L^CWmG-g?Q2L<1XiJghI8Ybmk{x&VaD{p(ihZH5UOztA63Lt4gtwc$f1;&P zx4lPxvsU8k{r|0WkEda!4YlAX(x^V2-%RZ_@_OtN0Sy8q0Dc2Nt8?fFDIt&e>Ur5& zlg}M9uq6b(P*D4Df_6w5!|K`K_~gzFS0Ek^w#RrvyUaKP;M^0Y?pfrW9tIU-a;489 zGn6q(40~U{{XSgzV~k?>d#(x+q}LgmB8d;hHSc*klbv%pO+9Wwalj(o+Ct4zaW2sV z#nP*gXhh@&^okfr4X99M)K@9nn|U=<$hO;T>a{p+LJkO~+_a)5QtLeaoa&|wr>}xI zTgoiqUME-iJtxpH)Qskpko$rR*-UYzOy;X)KGbaefFEI?DJt{wu(SAte*`P z@UPJ)23@I6=09EbaQ;+YC>lfIW1%Dg_H5Mh=MI56J=)So`r<8pXI@t8XZuv3Sy``8 zu?!OJP!u|loGmX>dPJ>g^Be+8HE?VP3<*R48aWea7zjQZuK6P!Biv3=FbYM?EkvgmlyP*zssw}R{5;}fqW5&{E zWp+}`1mG7Ae<*lY-d^Cl{dYLnizt}N&Wb2Yh_VoNtM5m{iy}9{SsM#a)vYmMx)}7f z664}SbRW`5TGzpi4;Yf08*m`!nzRa#!|NhOhHl|n{I9#zMDDdV_&`m|j#c{}o9#ug3dqSW|n^P6$=bYj4- zf&;S$vb@2N=Si|KbsvB@CE^FB-HdX>Rpv#G?V*+@ZJ`q3wc9E-ZgRMFvUDQoAPFKc2zh3Uo2y^$QFC6hc4XQ}UoY6E?k9pW7p$?@Oj&=w8T-O1E27xFq@mW+ zw^|21;8xsp=Pr}?+p{*$Iph0aUeFA74y4DHhxOo_N}9-Uhin^tG0+Rl^}V05dPDFy zQS7%n#NVdA#gMl_yq%O(GICDFo5ft7x8ztP*wScKE@Ei%`45*N^E}ajG{9nsS(W|0 zW&Jj=DG?Y1jNBdPrV8raH}HR>m};@Zi}<83)y?B_nmMTEYt-=#%-X9*&ALi@&eQnP zNaJ51WQ#F%RF2YB6&|E3AuSpMW(kIu#pMP5ox->gaU%Z|Le{YXvzqv2D)Ms1Zj$1@ zcdQu?9~s}W-pIJbFTd|<$P>J9wUSbzL-u3bW42nMk6j_|aPsUielU zi`vpP0-Ih{x^@evs|H5oYMdS@;$)RmzLOOfQC!*x1!ZN(7p_}@nONA2QzHbmQ+HLz z+XhIT_-KOWCktJoa0lYq2F-DYvm$#FXh)PyO+*6==@Oba8B&T8dZ?Ra+y!is#Xs(y zUX;bV+$z%Y#U#0jTjat~nv&uvI99WL_&~e!x)P(i=Uc4s zg3}GE>!)dMXH-R`g$01J`4>fTf038migFsmnUMW7x)~B)0eY36W;l>9r8(HJ zE`1JmFhg&m5riT)I9{xq(pYFB#&^|u_fQdfHS2QKW%lNx`K`uaFxR{>&5!H7WkU!zI3BE5gMomwlW>9Ifoj2=(Bx$`cST3!*HO!fM)uh|sgFACKmZ-o9Afz<`J}T)Ggb zHq6rO*v-i7Ng643omI-B+xe5CN&qAaI)<$C%rxuGkJgLQJA6PU5B^vFs1D5xd=la2 zex=Nb;C;@*LnbXN%AP2#>ZzJ+IIgZK(F}UgNmAXXEdh?3Y@G zC7Pki2AWr*n^)~lu2O`Ub0_e&`551Q((?^a!t1T(Uu=_&En;ON{mka>_eCs8wALcc zf~phBP!MRs%#f2tNA1)i$W;FoQgt;y#8g1lc6(QsNr}9m^dkid_Pn%EZ{82i^(os} zGqU?Ozd!FQle}=QDP+wj5UT<3KrTvcF!iFg7@QLsRIH*N6@uDxMgyFr&i4GsYMXw! z+AQ#hlFn8g*x#9O4Q6&9%6NLuv&Zr3mgMC6iaT=$Mkg~|JgbJyIg?Ax`DOI@!AaA$ zYEhp*daxP-~>0OD|bIIRNMioZr*Y-_q%-AbXSN+0D;T^qT_{^RB`rPi5LQGtQV6sG(ON``61Vx%T`z!(sW z3aj{7Y0A3PUMA*q3bBEz@msL#D)~jqjZ#fmg0#FD3{N%qGSUVtWmHIC(8Nzc73k>q zjZ%SD=_h&+R3cN*TPeFu#(H`jWVnm`mR?Qz&FeGw^@i=CidL70va(tS#0?bPIfc1J zSG!n7B};D3gz~tR5YsXOuM;h+8*qDJaD0^q88NW}KrzU#Ai@I5ke7w%z-sZ?Pil1B zOh1Jk5`HDRU+XRbkLG_Bs~Yd*^IwJ1LHM)sNLD zgH(&RDZO$|MlQ2=!mbG!xAf83Ey2_xAs51s<%qO&WfBUF3ar3q&c?YmM<&w;_)7Z`~`f{f5E`6ILH({u;Oe6wv^nL1Sa!|!sK0=sR?mNcV(gJ5-(SlqfZGTp92pu>j&vrmO4w~lP};Z3w#MrLVufu+PgLzFz#ntFhD^ia z2zHxMTWIp(`C+@QnpF}AInO!W!rhUS&*_indUPUTsGaj-8rJ`EFFt!OqXtk_(*L|i zF>+tu?1X>9=!U5j8DzL(dJ<$k`@P5*=wkwJ=JbK?*QU?EzOyoli0?h#=g*&KYR%Cf zjnu?>%bY|u%SV{Z)12hNQUSb+j- zJC@pguAy)2|ML)Nzv(`H`6L7e46YDsk?;hnwc76n_iDMn9bPch(jh@53u!$p)mSpd zT9}>e(^~;0Fy>HVaked}D;4H5dnH+H+W-E#JowQuc1#&Q@5=_gcHqVSKJmhK;SD%3 zlqWKFDaPs7Mn_~eMhaRbvfkr~5(NxW(wMg)Xe%r)+5jkv@tfTwyCTP*H#7U;eaFZ1 z^m_{EURxuXQ+en~*II(Y?%WxJ5}-!Fh{@BEA~@+!>l?WAs& zcWoxjUta>dsaaeJr#t3Qw|mh+V4>CNHMRIVU&Q}8H0t1lgoLM|(Ip~a%{cnl*ch+- zF&Vf0Vq|VEnY)Ka=g<)9r%#_WYR#g6j7sqfH(((+1?=l}xGNYJd~Ci&&Awo;en_@%7|=7~N`Bo4?vEpT`w>Y1DA;gk)XE{tGHgxY{^anWJQ0(kUG>{lLFTU+x2Jn3jm^sjf=Z88 ztnk<`E)OKoHhtKNZe4T$fl%`E^Bq>YU;$fIK^Ace?g*2O0g1-`Ic;cB7767vRAD z;;*dy9S<&Egoa{w+tYo}F3R-nM=}FTQXSzI$wy>sj3t`&JEdRSzJZpb_&OC*CY~A; zFwD~X2EGP1>NNTNY;Wxe1g?PAf384Pvu_cu_`}KvDobf36_TN2)lJK{C>$0ItlBl; zcaEZo-8<5T;J=@Zn4y`&G8?{LHkmb1s2^R5B~S3w>|xIQ8aTJkF+{f=Br#eHV|D(3K{+oLxTQ* z)IUCKJJ(6fjUV&f@|2fO>lIOQbW8KRDIB69ju@Js(38$MO~oet?XDAM53mmsR14>5 z_hfnxeDbm?g=YVk-THk28A>zj{BR7C1f3o-#{0;P{pDLRPd{D!e||b}Q99RIAIe}5 zjlkbYfIfye*5CIbHepZQQ)y-9DK~q^X%L!2(QZ-z1w^wS>8SKNx|SW#1!~-L1CfWEvIhMKp$cO z{6KViiiEYX$=LspvLq|1K^d|}^1v*T7_F{0|F77eN}3ZdvU<8>dwe%RAPcV^xFu+v zDN=(GhKNW{{chdtfBs)mPya6fkH7rS=g-vZ7?0>;4B-HV=^S_==rc`1Tv5qh2AJw? zkE{VC29l=i@%=Il`+QU>BOj$6znh5v>qI~(<-G-+3sGgt@vGMB)nr@1h8cH*CF-`* z(+|ivt*u=WfT{2CZTFI;y{Sc57~ogEnLI`FFHAGcyV&L%{x)OZfTx{A4Ta}j>I1?; zs8CWo14X0Q{{)2MJ&@FeX=U^}Yydc{($We*STo zGHh@@dR&@wV&A~j<8}A0tb*beZO!W-M1q9BXqBb(^Bz{p?MWBD9I?UsAuqtaSP+yjY=DJ)_*Qo)p5g+2P7r!oKpEE!^`^Z{|CC(WA`iA3MAlxWffKulD} zm2x~D6roP0B6Kmp9+rlQdAEif#?qzt$-8;qw(kr}_i}~D&0YBTT_;&wBk4+sY^#`| zy9HP0F)%iSA2a#_ZoSBAJTqrc4Eqzoml<$dJ>kcgT~#ELIlboh;=a@^ z%Bi`3qqpNq!_!b&M?9PF)yiE;9!QvPsN4|La2dM6K4!|HR0OidtYZ?VVMTEW`34j* zCKy&T{2q_3EPG;usf+n{bfnkNK;j^+ujA%w$q*%v%d~;d zk?o}5cVxD2tA)qeR7ey|`H*%g8T!X352_zbRue8_f^M%(FL-O6uq)(?5Z=ecRYdZT zv>MA+VV`FwsgU5R@s#I)Z!hbYIHoFzIL;x_QK#+`R}!Kw)km?!SaZQi1-BZbUKf{j z#6HD2+MXle`himp@WY^rB5A2lLk{FXGXuLK^AxX?T4XQAN$~T527bfHxy(ixs+zgl z?Qj5z{Pc)DD~|%B01@XiKv3`dC zpycyDS~22%w!v_Ph>b`R1yi}AfFQZJa;zAA$K-=zLqDXvh;}an@YNkz#}}7aLhlUB z(CR5Ov@L^5r(9gIPFe>CN^j8p>U;a?0+oQ4&(ad(r;Q(Go07SVohHpyJ zINC?e7asD(QbdCo!j^lepa$G`;*&nia$v)Kt7G48zVF1=dAkTWh+jy^LVw0BmxT7* z=QHPb^VhORQyUuDPJS94^ppLPX;s4o{Ha947B(kj^h9U5fpr`DtlSl}jUf4dJ(1(- z{)9XA>fR4XHj-0cA#q%v2YlEMmm;MHhJ2~~Kw^Wv9}v!+`X<=|Mysp|QFcv(npGr> zq7KAt^!CDZGp3EUHecGzzYGjLCfonfjyQ%Zzcyq&)SO=(=q&>IYyIW_P&f*)JV0di zB42kHTd^);6*Z0rdeJKGVk_F+fvH;ibV@R;F6mnLbO0M@d{Fk2QHRM#N?3_*BMTGB zDg)>WifGP`>~~@LRFKw*?E12L^qY`~-pS@I;8KH-%)Z;}=}%TSNC}^w&a&nEew>(m zp0a$w#L%DS(+FA14Sb;VS4OK@OCNJrNr+=q&A&%;cVRFWt*zVl9eF3QgmJ(Sbh`yM zupK*5E9Nki>rZIgB6h>s1#FX*Q)umys)b8}GAOD>rwj7zPNWsY$J@K7M%e=EhcRVv|Q)iO&&1sU#tMEkg9mLQrx!!f9 z2i8(aLJjTo0+l@)yqPwkO?iUgSG9eHJCSi3j4Ms<1mC|@ef=c&jJN5-i%W@MS(|q{ zAZ%e8>qormz$8G^W_6jZSzhcoq_%{{cO9Nf)5Ch;#D=X4ByHi9Bh{{ls7Y4&J zrB1!yX^6L90~w0X`) z=DGx<_Yq2IZ)Ov1{aFdSHh9H-Ae z+d{7#aV`si;zk=TuE(Xa=Znz9?8nGg5_IKGR+ZZ2h7?~|<(e9+;Hk5{X;$u4{L*7j zSD=FO>Ov;ptcbn3RGpaet}Y~|n_@pkCxkdd%whj4nz#E;=Auh5;r}z6wA!Nzl^(2? zX8^8b;|xB<&Zc|;y4|K_w}K~8I?>={n_NzaN;0wcu=H?=;78iWA)gx#*tQaHHTg8j zgJN~uN?ec!q+MAbd`JXR$u@AQaSe^^VciS4#VfrNQ(UZci`fwLEXwsQjhSwwDVeUS zLL?7CX5mZvSBOhs5v??4peQ&B5p_x(S}h`TEWz%n_%tZy0h;kWn=`*C z6W2BC=PTexTx44>GL`UrP)YdftN|rQvXX!%Vs?`n$<}!v`;+zDU^^)s@OS6@Qe^Zq zf#NiAS927sW~LC2-(}~M9tay)X0R+zq!wun4hpa`C?64Qb$4Q+rafBgEy$RubrmL} zO*NXLGY*_Z?~IyRqi@au4qH3WqpIsGGt;^$#rK)vw=HI7tZWs3lz&gQP+r0==K9## z)AZU(jq6R4)0fg*eKDM#4QJn!#gss$-kMU?**`Yx%cVQ+W(=TOEH-E-eg0V)ajB`F zV~3CaO<6n*Ad%4>|AKLM$+0h0Wz;aUK=Tac(r0!pzrO)|Y4QwY$b|1P}O zQd4>VM!rg4pAdvL0`vse9mquq|L6U}7?~!D(J=GfNtKdyTd0Z&{o6`?45l ztA`B{)S}7|`@=3iQyMU53%1g4wRt}NAs^9Kpx#2Gv3C%fmGOMtB{1atFmMCe%uu%) zcR}}n&2pVA^?NDOi--79D@7cMq}Nh8v)^JTSV&kv1YGxV}P8_Ze2 zG*@+b`l)B~HR#)w=LY{jqvery*E$WNk}1FRu*%4qiU`Np$82%guGFbK>`%bhr=oC% zob3E-bE1SlO)uy-YMqMhJzX$3wNu5I9BN+&TN2JCD>g{8I#vpEGrG^O(>i%RK%`@d z4lTG}O-S-1^67jXOU9a$!eLFol7O3-b&ZdL)lUb3p_n;@bmO2$P0X=VH+zsuhaEYbNa5Y%IDg$$k~r2J#p!QoHXNH2#TzYyl_#Bz za;rLAS#B`6=6giEQiWF2kD|J*$y2ZkB0RLXz7dF!sNR`E#0r^E#(Kf#GD$Xw$MfFo zb|x>C%Mm+yFb%H76uG+37hf<-%^)j=gB#Xk`SHNM@rV!gUmP0Z6KN#s|BFjpYy=n5 zz=mn*2?xAm4AN?6pNZ5q6#|Yl-II{ULK=x-0x`ZC8-o88@+Hv}9|Ten(a=)sWyONZ zAbtu2UutJb`7sJ35pGdyUe7=Qo}BGO8k=j5M{M7FPiqm{!QyZaseC}44Dg# z6N$V>-Y2yWzAE;p zBo(M4fmf^XB^NNHDwgS^&RLwe7Abl_9|KQF2#9-r`ip8t8;EoR5Ju5gWcMiRb|Cu2 z9>T7+{FkcF=(;{`Hb-B@IAn)A zyH)q^HbKsut5x&;I^P)1Gjg~xldS5HGy9w)q^|3Dk=Swb8#DbDr9A0O=r)!BhL1Pl zr9Il$h<-Q6-BDM@bT)!Dz;&T8?t%K&a6Ggf(}&g9f;5tFoDi$974fYX^oTZ&m4pMv z4}=#jUQ5$y+50^3_EYDW&pa0~-JgFCCjMf!|L1_Em9leHe10n721N}=s76k~JgNT?7EVQ3WYWLsGn07AE zeOzq*6^iLGl{~OX5Xf6tlGs)rJqD{`;CC1o0oMfNvZvvv8pJlF6IhNi8k)Pbwz57Y zx2XzAf($n<8bm`eV?Oe94Y;_L(EpyTi#Ivm9{NvzO=Wc$k>x?UQtFTHbbgWzpZ=wMk z!k;*bm*+`m(NRVudQk1@F>i_+-woKj6vcJj*4lJvVg3Wd(nlJlie(FVJ236jaCI&` zs$x_dy*$*JxZn4Ua6et zNcmyzC~eoMKSXcGOMOcvgK>sUDcSfzg_M@RuflHQN_+?MFtW>5*iP4v-Bxm>^Pu|? zTIA-9$eleU(jimod*N>8a@v>2UCL{Zc-V3OSPp1^|I2I9R~V)C*1|i^Y;!+DhEwYv zk1OVF>U~AJxK&B_aC}Lfi5u0OpJwd%xa~@I!xVjh)RT8${dvHTTK-5sL}B2_(c}nj zkVxdEG2GSH>lGh1I}LkHBn~z~J1K=of>F(UWSrql82f3}YTaviPZz5gPp*%74Tj>A zRi>eR#r30wdbX+4WzQnu>e+l240OWz6UH;Z7^g>D|KRQs*ce|TAPN3z#9L^Io|-Lri47^DlsGfsBq7!Ab72gBBX7fJ5Tk2zS@Gn0D*%TN3OUt z|KzjE+}YwmfRpq^jo+(GdryTlmVNBy9BwWA0cNS1 zp&!y{YyAMIIRL9U{wUSe0t=yrFsAs6Wq840CezE)&-JazI|dwRQ2M$&-N{Ojk|ZG zKQ!EMGE>ZFbAoh$VOPCbnGm0bf;kDcaa|5hdcx4o_T}~(F)`-_SIN{h6XP`rhpq~f z&YCs%R0(%%WGFgxH5Xj7mw4aEP>)JW)cdpep>3derInv0CzQk6#VP*?JN4XkD|(`J zx+=4!TQb>5bApSv+FOW^PxBS4xNw=z7^JdJe0Ljfe;p@VXgzRi(a8bEM^>cyE|Ab_LzXu=$6{tdxa$~AI6*)p2UM$PZE8M6xWO@mAqEL`io~A z`@oq;ZxB56jN5VU;SFE2mHMCTBoy;JS+UaY6srPf7OXaCH&*I)jNJ@2xX@hn^}xhQ z8*QN-ivpLP6wr3wD;qsrft`u2;UwFjsyk|fJ0rme*+)B~6_3k~P4(w_f~SHY{_G>y z2*6}{0Wa#xLFZ*I&_{Pkgz^U)o@;KOik*;DHt$TC;=nXH){&fTyrluZlwis0pT_+K zyAJa!d}gQ{--|n|Wq03XA48-fw@Z*6dc0NIp3HM+70f4Z974sit3<^lvXan(-C>{G z;8dI|BNS|_He+~iQzpp!MdLoj*x?O|!Ln@78mcL-K7-&zY+CrrR%S@lF8V08`f#4z z9<{jK^x4wk>;8btHz~7}%KDM+&B-=;Tb5F6QN{u#0o9ujO z2?P&q&}X4#Zbzz+=!-sd@~uE=oVps4M63pWrc_Sbi<{=Xc7fj4kf1@x>8;^;0MT8^ z{mSBMsR#z)wvqDHUFnyavq6ufBdri$mXcBW5xI&Co=MK}?ca6OoEB7KPpUOao!m%y z73FhuZppekhmYxKKPXG2QW($nW@MeqgVgroEoDNK_OApR$jE>HhMQ$?T1jHk zGdjC<4MUjyti1kalciP_wHLxkz=R(B1*>FmFE-USSCP64JotfT{qtzC_)@*yO6hcs z)iIkkBIW$DXlc6Vq=b-$Rumq3CEkBxZ%%^=D+-@7zkH~;(<1w5TyEwuZ-5zy&;s-k z`Bx*2$A?dnoVeRFiU}K&&ZPELw6WzKdXnC}QStmqw_!E}WPn{KQpu0?%b;p|Z%y9P z%W5^(Rfnb<$EchfjM5oScS9>aD3eued{&%YO4Yrop=+1L5znV5w{2~690=80Q17i$ zv{>xR4c^A|s2@;`C`_zc8MaopJ}xv*gJkboamO6%>a+#<@fj}oM;E&Hjqq-vWK4(} zsL?eQlftr^`q4C0gKZNhn+v9jd}>Tm&hY#fFDuPJYF>9?aimw>67;2%Y6}W8`WhJu z3W5z#UiP>2*-g1~^XaS(atjTg+kjwTl6wO>ArY0q2xcqdJ}_}7_~A!Z5DycSWYNox z;*u|^4DVZ{ai`<~$>OHBt4|R;7~@5E?#;bC@OA!SOHel2bB4RnahN4O#<`;XyQkkW zcM1bt?TPUVn@v&sJ@3MKwAg!C8 z5h<#GiYZI<%I1h4qG|^FS7=FG4ZxuJrI|pib-;2aVK7X1Jd@{ZoUO$B!zLpZQke^_ z;twe*lwu^Fsyw8sn*ClnD(D>EyI_(01^eYsVEFx!+aks!QbmteY5L@u97R-OR90?! zAFs&v)U+isOH_gjbOP{!Yo(9WG%r8r z5ZFlFod_-!-ZK1KWcuhi^U8jsTkj!5Xrn*Eb`vU`SvDq7(z2~%)Y^zXhv1pE-H{i6 zhyY^D@&q^!^m~kXPIVD5h5CjHwbgKylig_fK~-g9?_(pao%Ud3Ds06cQAQTF=TZ|e z+@N^Bt+-mz$ao?Z*(p$lJhZ`yRSFdlpRB13mp?BZ6L5@zYR__SJ21E)G?u z_1DbvE`pOe;f?|BPUfrOq=tD?}eK%9 zX}vbGE*H8$$>PUWJX~#M6kVq#o%W}<7<#T2?4YE?Z)Y4jNA&o(w}sZ7DDO}0*4|d8 z9J^VOtRp`|mCq~p1>!GO!Vgv}mvvZlbAZM3*@cN$)oH3r@d#}?$hOv>7jyGWD^7Hle zwa%y;kyK)9xUAPda*`}exD+k6Ei_#59ImwHSkb<`#W!4OnNy7$naFTg=_l9s;Ig>! zFk+NoH$t?oydK=Jkm6birx;U97}Hd&EVXd!zlN|hsK$ODQmQPm;P9~@MP^=izPFi* z?yXRkb$y0jDI`S7-o0!f;0IxFQ87ysFMk#SuPjMzr4Pr^myA} zJ^NS$H~O)qo&q)(h|@7z8=NLHzPyHpvV^XT-%5>bSk43eElEYcbB`4_b6T+#*?INw zp;{=Z)KT34&3ol>$Yy>l$-NBKIl!?P;RdR-4si%ubA+u?V*MFd{Z7~_d2G*}3-pZ8 zejOg^ls(M(aL}}igUj}&Mbhr^6KM|nrcdwEAk_M)bo)xjFKi<@l6xOmui1rj(2hRw za(I?ZEpnt)+z6?0{%%CkUz4@HJSNvEiPN#iQcQ$1Ip)P2k83MpYGFjJ zW)tlk>;)b@APS-P0sQ6158`lvKsKGRxlQaw$M9BO=e7&Ob#?_u#~Zov?9G}%2Xma_ld~9x*bQYGLKsEQs?aD@y8xX5KzY66b;pEpNeEq zsbtaL0?$+bhq(ueI40=h*XM{3Y8fF6h7BY4)31E8H+pUpf#8uhJT)LRxbxhf1_VAe zpvdfbG(DAwGrwc5(DAk_lFn=QT9(})$$P~_|K9b=RD}Rz z$J-x0)ru_7@f7(n$4NZOt1R~4hFgw4DjaJEl`0#2sWB|M#+}Mc_<%0V zWH$zAA-o-4NM-2Wb8B(DCK0q4%gjKy8=1tFJeQy?6>C25S)r&>qqUD@Eet0nn8ITL zu0C1S=@~SM`IUgbf6!Ao^(<@DGAyaEI-_rvfsuko4V<~YUQ5L0dGTU&U=1s{;bzKd zUJ`)`s{siRGUX<}`xdEr)0gzBH5b6Sv{h;rzt_~x=UOogHxsFoD6YI}v$SBTK_#K9Im_szN3L&27YM4`69BgeuI?^?hOBsN-XuDW81UDnAT^z}#<6B8Las070J zYPT+n;QI4h52A@?zou|9gB$ktb7k}6OHC5~236au_y$e&vlhe-SRRGzIjrzG1|GFj zOj;Vz*Mbd5kw5~2dclMv|3pdk2TIku2Zzp3>Q=50iiWmPx+F{N0L}QcZ&&%9-yANf z8tuK6zu8jRYQK=H(OOJPt~ixku~{}D#fa}#94(51asf#@0lL{o*IJ?hy&0>&4y$;N z7`FeW(iMZ`5>?5o+I(!LzGiMVkrVR5df*Q6@-U0yyh^Nt*Pd?CjSbn+K^iF?;e)Pu ztTjiJClw0W>3F*^yIgp)@?k0YjW(=f)8<}CbT9kI>{-XPTb^#S@@q-dW~1rx{d+x& z_Dc!_bDe>>xz+$@T9ZpuFc*ik>f<$Uxh}SUaJs8GB5-ec)RzrX5pS0~4+kw~5mzh1 zk9hJI_Ozwl`5tmn_vvUC)4+~G$ZxRd`+S3I3y_)@La(DM1X zk3H3(b)SOE$JnJygVa~5CVjhHe~(s43B=ymz@s^hM5FQKWW$FONW=a9klsu)-HMGR z#ktKbFP6*s*{niP*EFb0C&_z+h)LVNl!#)dRDS!-+D{0P&7!wnw{&f46}(Q60keo~ zu1E_mDgD8GZI;93Q;TX_eO%2QHGcbcArX)eTfXGJyHk4OS{rOs<3Vc5IAfWG2JF)A z^2j~yv3}J~ks1Ddx1A+kw)|-EjczO%d}=)Lk|{{+&N#n6t5kjR@wpx_lkb!3m8EM8 zE0p7G9X4R5j(jTXRSDnnuY2D|Hk~Tm&BMi=*FV4$Zd(#r?O1^DPg#I)0VFB#4;Ju) z7G4y}JFIza#AF-`rO&U$1{_uVV+lDH&f$=ziQ|^ueUm5w!Gb9(&T(oQ#>=_RD(J< zI+IxzQZ{HRa=nFs$$rNpHE{kjAgL|0X)#y5RW#hKd_JtFdUJGhE0`5d(V(;Sb~e2C zy1m63Z3HSed%JCsOC;GQJoEBWYlVrI{;~d!c|_kPfvaVg@o?GBkkq>d-m6uD^T;%m zesGF{aqF*y=>q+u`kQ3#_&olvtcde9zeFQ!sbOGTfnh#X~cB#GV2%XSU#uR6GDre2k~ zZ94HJuX3B(40`y$tmnI2mSfWg`;GHb;Y1cm3<6%8u!`k+2czB=uio;`0sEEf3yQ}P zB86qe>n?ytyjn(UGFB-DU3L#rG&C_tTmE|W>U}L{Obl1lE7$Q4HlfzNA5ENFSAY<3 zc{Yj80|jnKPK2@(I@$0ectC)W5E-E|&kkP~Ij*uXLF;cxKeXXcerHYD5Jh)tFr+f+ zzS2xs0z(kKK)@)PC*-d%%wMGU4GWqiZ_vKa8xG?Otf}6qdpoN^2MW{jKIx{&fBh2i z#hXU*D89YYGpE@6g%5xE{ME&=>eB6%5xJ%QO4WlG)?7rH6HJl!FNXwdH7+ zv{j^%J{Gv(qqKav8%$shr1KCf5UR$&R4(BM-#McK#E^5X6uOlOK_ zZRUgqI$Dt#Q;&qL-QC&L)WH}NG#ytW$sE%22iNHK~nu-p*Yg5 zge&aZxK3NQUh?}XZm#G+*)79?2(3cwu}I;I<0lkx&WenLmD&kHIh$WOWsKuH#J z!(O=qIj5t4SeRu0*pXr+BN#xb2=cl^X{u$z*%HbCm`n`Aed7CFw~A)B5xwVr*DfM< zJ}v6d!i4qWZ|*M_b%F9c^eQ4rkq2p?^-y< zM0%ln_g^MlJe74Oe^}9UqLsV+cn_!HW`cI%nvhh4iWC=LkpAA6t)9JN?8IS*V4{lD zN$JttOy=fLRpk5cB`fv|NE;gRzN^x(p*pn3%!K_~a->oJ%e=?=^RB!`rXe8Az$5Mc z+}nK2pqT5s9Z}I&)F*_H925|v{xggHpTqm>u$L-67_9f0vr>3w^2xnC$Q5w`w zQoDLg3>JC|msNE4mw4jXT(KLTJ$xJ=x z9;W^hk~F}`)R;)9@_2!_P~U`=vs~XP_D0+s@FFKLpIe!YCj02-0unYl*owUc zZn#&N@$Qb(H8~bGxGG~JDkmI*JA81Gl*h}HAF#bPtn22q%A&l43J2(>j(wX(E#t)D zQtWK42-)0}ZeoazzKc%lgZ(W!FDeP2_Q*aeMY5kNVmVdnP09ww#CMP+O2FZso|;T7 z!uCt|kMQI1N^>??CGIj@>sx3wpYHK?Pls{*MWDGw(^v*+BjQ^ppTm@YQkEJ22$V4_ zN&616te=m=&^<1Go~8s&VAoC1W8YPxVPZIRipk@|v_w=fwFbGHwDh`XwiaHtZ>9wo%b`!wDn!N=Z9cH zKZV{RT8m@CRXN7Iauu<+$fxDKnIG`Nyidlu{Bvf~K}qCnRAen9dCGoG3q%76Oh0>u z>x~en!r<(RZ2rBjo4@K63WGB!aP8r0)!cxFzJQ|CC)MN0Z$8XX=ecXPBRq~antLK{ z(Rr-D65sBYHBKFziP#m^`%>(a7Yj<0sBFhy@?BrTCDrJUiaRZ9E{IG)3#4LH5t4bO z3ZXt4)a1=&NWA5Sg@U!YSbfO@iYo8w6&csOL#5Y$2RrDI9uI>Hj*1FSf0VD1FMudm zb>CdgI!n(oTV{J0M}z^2}EPkM)5Y-mZe_8Qh#BymYl&e4Hn& zK?XV8)s|BvWn18~E$uKBZCbxv6vDSQu!SGAc( zw}{#g>i0|>bhe1*(mDXDXzB-AOJv8luR`Y5xB(mJ0#n!r$V5u{;G)hb8?POteOv5j z#ZbZE*$teIVONY};m2Z2){FhGC>rk*o6H~7hqZRm%&^n^kR>`t&3pFFVms8p!*id5A%_I>*i5i+02%zszbDViPdS2q>Xsel`zLI3Lc-(jI z_TMZz=uzt#*xouh^Zml)nGS=wiIbWK<_o&_VM8C$qT8RNZb-5eAxNS-gT3jA*1%>l z(cpoyj2tcTQ9xqYUd=*K>s3w?$MYBFgE}!c`{Z^b=ZG@fuo2Nca}4T<6bMOQq4y1&wW#82$t^Q zZ>4ybzU^&y#_XiquQ;S3c=U7+r8#78NXeSBHS>8`O-J|DO4GUQ;$6T^juW^B8|D%s zO3NmSX$49yZYY8cpK}LKJxhZq0bFG7>?t8XD%>1khAY718{;53BHgTxI;{bzNsJ#t zQ#l0=OFlx9d?gRpnhPEJD7E0hqVzLT_-PS1lSK)T%5Hvw9zwrAzDl~(C*W%J z?6Zs>fEoVii-9@nXNYlqk;2ALBc>y^e<&0(yVp^KVaB^}IqY_3M^C zL8>`7y_$jY8()3BS%%^9d!0F~K?Sd!ZJrW1iFwAlBeDnIVXhRff;Zh;g@Ug<6izp& zUs-0uDs*%tvp*&DS)n1pq!s7D+`>>LlsL!mBIZlHNHs*CxJC~Q=?fRbRPsGI_UqWwB8q&T7c0CQ zN?I$4E}NA7Z0?CQT~Af21xX_=8H5Ga@caAt0aaCB(rKa}B~8kXSDE?cs>F0zw5{-v z_=d@^L?((gf#YKv=vVssw{i}4_(J8s6}lUmh9(*fe$p#+!3wupsOe{hEYl2omE~yj z-d9HpDXK3fG;DorNoe9T!nOGo*38C1;2K{{EYdjQCG?m`R_V(~kddvjZf%XiJQTT z9z5rY{OBW7#Sj{zKc~v4k&IRV0;8z@`czJN(9jq(`Za1`=DB}fjf#;CJ2%f8gXzy% z7Ksh!=PyNFwJw^ZlXS)`-*zaL04Uye~F^u(N}9;E0??+Jz-`4 zxsq52&N}?*TN8zzP51ZD7Cjo4nj8$9(#77}4vVvD6#x=JzHlYH@e#~LG3}b9OQ;fM z6oZ=oeA_I21+STWiW23B4ioX>?LIkdtk#Tw%j^`+$gqyO;`?@_;hm2oo6Y)bvG`Sj zZ2)Bf{LdelTDMdQ=0-bDND6MS{#yQ37|fWr3dxw@ljw8*~W?Y$D9=6>WJRFA9EDbhXlZx!ap^w#1V-moHMgJ)v zb(jAr=*I7P%I)IWcMWF4rK^{wQfY#>CRPO>4@%et_EYy9?(NZi1FXnc;;^y7eitbD zj{vV5sWGkOsBnk?tqwmVSSXHJoFQm~2g(|)t}qyF=teSnFY2CVMN93Xmbg+qVA2Lg zL)YIaQAaW0Mg}0;=D>@K%xu&6%a6qD=PH;LJLtR>2%NLH>)h?Dv=+ccKF$z)w;>f`j{|E!kbg`j$cagI z%mHY(W)oy3zLHCo;OlIY-Ab2xu$I7!r+QlysR4L!*rY^AmRt$y3<`^>z#li+4W?BL zy*yRp$q`-Cfi|Jj0rK5zrhnjD(qvuWyuox1LQw|iPeZ|!yw zCtsmjb;jYAdhV%~x@AY7AUX3qgZPr>#N?cji)B0EtIGLdiCj`om!Nx&71-A{idFss zb9oA~9lTfE%dXv5o+_E=d**C53@A~GL~|=b`k|$~)V%wyFO)t|{a%)0#PpQBM#4Z< z#&y#UZlDWHY+hJe5(18p3?}w-k^L57XWMB@Lj!lwyn>}um&~Z3E9c!Lv7l#7dWV{R zsVgNx*Qxa}_ma^LJ+%d06wUUzNI37;Dw^*L)uRKm5BsHjqhkNb3zc2r24aMwAGWMc zrHf!gRU^cgbbI!h zvc$ij*cX%9FX8Y`Zg!{Q!f@8^guBL|q)S!*#igl`*#Q zcsa{sKuNBYCcLX|yWS>)lPER`t(ovgE|HIUHQYjKyfA{HB$F`(nQ;Cmx9EQV9K>F5 zc{-B8157WrvmkY>7t@)_h5@)$l~8U3KprBGMOGL;>cS}ci<04VBZ|f<6!aErsqBfH z*C3XBVB|e&9m%uLO4mbnvS&lPP9D@R>5BfR{1C>0kCeC* zC$K!CA}>fr5I>{{6V@~ZF*iEaoECVc^4z`Hel~sVLHw_S8>vz%St6chLBy$9)zvYR zk)bWUu8|*Rzf}}k;4Zn^9=}+0+fwd5$i&>vS93URc9?%ibNjsFTEq@JdE6XhKPga_ zj)wTH4A;+{pWEn~Ki)gymbHTZGA3Enxsb9Qq&I6JjHlazPg|Fv#W>9 z7n1WVc#3&fpR_fvekZh(O-{dsFLW)|Xe(2GqqoWs?A5m~b|h?UNnhoEC|86rnX+}`esBt3$@8vm$%{+xPT zwA1B2?F$ISq@-T@SzMB)Z1|eb{b*pjncRzk{YFRF;aUO*37StA0D;r9sw_6sF+ZHj zT$dvlGZ?W5M2^yQLPMPmdl(kjY^h%G&4!*g!mU1Zd5p#8=rG!}V=CsCDZ%gh>;HBH z{Qm5E`E}UOv)nq2k@vTwTNw@$yyb-EN{@N%?}Uu?R)+I`_WYm(UvAKDsOn!1rmQW1 zKil$}p@dyn8!1=!atB_hH#-xWF5s{KYfFvHg}|%-W*^<)hoO=uM-Hx2&UG=4*{iYV zi{21_&T_1YB2eQCr>z{aC3WH$r zt?zmw+XvY_+Mh#yt$YEMzCYR1!#5Z=fMH(sg6PQ}~ zPB-(8X6Fg09g!i95l z`19h!gkKu60L%MVTLh~44m(W?smPD19vo}6TbV#*N~67f^2B33gj5 zFgutp&y$O7rV522%+JF;r5O`?7pv#iTJe8!)xEu$&v5Ynk}~ThYX!2o)!c z>J1CY)AxZf%7E}~A+wlLaPes|B*)*P8Zv*oWsMfMzlr2V64H4*3%NL@EuA`AclQ2y@BDA4&y}dz!h~ClL{^YV}V1?8nl;Vt1c{6H9Mx&HNLckp4n3Sz&BwA+T}+H z`+7O7bP=4Eqkz^uqTngt@;q`NG)^@;cB!2IIpLygc=Bu0kH!@qhO3*DU(J^g+Rj5M z_X1(%ZQm^igZN+R8oq_(c-QAo81NE&)_)fy=&wfqW(_UqXW-&y@*H+UqBQ&B1K3_% zARR_8?DGG?-G9UA@}8BF&6Aoz#eY5+*7TOivtP-UFKhx29yjl%@o7bBg`!AQp9=Wz zfD61>r~MG?8@uOF$Cfw$U~WI%{Ru}xqT!bQW}^&q-IMJT@m7NW^nN9y^uLA-+v|8i zCH~n7!RYsoO$cul1Q~HK3TO&kfCrdd~cZ!gJouOQ>3d!Xnp|ix7=o0sH7nQ9iS73%&xAC=e1TPLoKwxnxqk0QEC|%19MT9y++q= zg4Nxi%D(hf;$M`xqRKE|vvFtM8`Y5Dji|R+?72ol<4j3Me7f+&Ei2%ihCN;yk*bkn zn!vxMMw(eZj^5NrEavbn9AQ2PvT}00aJY>7uCXG!LL!er6_PF$g_2u%WNwbflH-W& zpeQeLQKoHZH?f5C1*^>v{R?wDd|roag97jC4>czw5D}gn?;NMDH_K71=o~F`l5EGJ zEtr0ZP4dsTV>32p51^z^=5bJ%caG+a%qV7r{2V1La*<@#=uNWIvVXTaird9XH5DgP zt+Gu))e*T&J=U2#-I_S6er@Dqt4Eh~dfkycYG3{7f3dbZkv5E3c{uZjuDcA0vWv}+8`>pR1TNHM z#+T9+l37nmm~iS`QTT{`Yb9)s+k3cNcvHPkCuFdpep4_?V(|}-L!z-O!)HN`OohT*wm@25og;LO}0mxHeOJ@86d>&mm`WL z4J#1(f~0>*=wXefphgKwyKX;>gY-+7tW%N#xf|N4`hjmLs)YLjKUYkd6zP_Ly6l0c z8OSfJ$Q01K9bRoau-QB$C5l}PEX8b85A8<^F=w$9t3>Xn_?(-#@&qk;+xox4#*2bW z-y_pe*4wx=EcfMs_aLu4zhmO-bJq$ZEvy1iPy+d(n__nThMiB*g89oUKoefSg*&}+ z`haRtmo#!wWM~H?*`F~AU7$QCOgk&ETAUBf%q(q+K7+yc9e+rTZy$}S{RUZCVMFaN zInU$ZuOSzPtx#LVQju-Wsh}+JPmE$-uh>4-2BG|2CTg&;xSO9wyHlOC-tCl!d^oIL zNcbh@GeYvfaa{b?<K-;p znsAb&;iNn2Rr}QI$eJWo4qu%u?^NkIZWQ@m>N1Dt%Zs)Ot5NO|tODJ8H&NuNgeosX|zDOqVEheWR_rV`QWDcrn|>s@pSf?eU@F?xN3Cpz)<=(`8NKMrqSX>@PV1 zK*!y)avkCSBK;R^N^k4YzVc9J)*GsTlG;6SP_aQ@ArdI;q3v+)lO|nQBDdjEiTE#R z43D4nZEW@DsjQ2c3F@V-7x9UDXC|-P-|o%}2zF^rle{@ZBIkCb+4_DL@0%ltJI~2X z!n}L2OaA6g4byg>7oKnmQwr(Q28=Yr+B5F!zI%^nX)6(Q;p3zOsh(qE>F`t9JLuyl z!=q6yJNT9X%dpDQ+lS-KZ?S&6W7AVhQcaG;r+92rNBoA!j4P%W#vFkx4ng_=x z#xXN#b?=+q$1-+eM_o$RkS;cBTgMR;Lj`z;0?c*EWzqE0*sa_C1x1KW=dHh;^aExECTV#5R^zoU6-_qcc5{{?2t?1Pf== z#1T=+LZhjDqOjmc5#WF2ozU}lZk=mVyc2FHEq`f)Pj9ED3>0yPGov+)T*KakIlxKl zrG3~q!e#E&V49RgI&HS{*8wgZ_0{`F@U32le$RyNnIW`SfwZgVg*#d{uc1KoOob8X zW)zib8c5w}!*9_EXhUb3Zqi_+n|34!Hvqr~FWz?hqz1es>nGs98Q@-$b1F7=wLv7i z+K4QCg+%j@8NaOz6h)+zBK%;4xS-A?ILAty5+uc{we2u0z(cSpRCtbyKfNbDKik$DNUxu2tD1%hb@p z6&k|4&5?ZJQZKz8NmJ?vJz321h8BA~TM8ocy>nyJ%m{x+cJmlt->vuHG&y89&LJIUp-vrz|EaKu< z2sS#neJgz5IQ6Y(UY?f*6qmnKK9c1*MI!`=_E)*H2t~<;RvX>{S)&IQwQzW@HAMei zVHs=I_S0&??~*9zHA-@~T$g;myNy(^;X8kwjbF{!kiE>ujrJfIed4q{7PY(kBUu0qIkF+9>Kp;HaO>}6r;qT1tL zbvKI=uYZQgVdM^P7C%L@iu$jJ)-;zQN58wUckSLA`%@^8g~heq{cHE~6x*2y_GpW` zbcI+ZCp2RZ7a4o_6X?ZkCR?ZaPo~rGu0=s*Qu;$Y!dCMf!gI>YH6-*d`BwI~Lk~m* z9;`TFBvB$wGE%TI9h2bl_J>qr5T_LlXr^_wVC8{6ol-Rk$dtWQ8tZ)a30ANPNYF6Z zF1kX@C4kSHbkE<#We%-Kr@GL|*os@CYG3T6PKy%$in^$rE(-sRqZOun9jj6Lw?uvP z=60h*RW-V6Whnnsb!v~xOmL_h2MVXRh2IDr&y-8S9Opw?tYc$#O9?+|nKbj|7F7cq zBX1Rsnr19~+-Y7SY>LLOd_(@WW@sYcnQr8R)stvc^^@B{O$mGz2*pC2iH$=rMThS4 zjG2B#tr`m4z4q1J1GlOxa%IFYb|-y8I^CX8@K1H<+A}D;;=S`nvOQW zBOF#ELF=SLUrev=4%?x7<46oxyKXtPjP!OwzE#heFyWUW+1(OT9aa5yVpSDe?By6h0(e7o# zE?p`PLSp{Irs4xziv6fP(CiWk6=#43%8M$O%zlONy9LgOGm7N|AEPT_M6O7M zwa4KJ6Z>jZadZQEtj4GzRqKJrv_z;&b7_y;^BsHz_@C<1KhG>%=LHg~Khd9SXepsH zjd!^ibBvfsF?#3!(PHp5lT{wYc_;gz%J4hWc=s^tG0l>Pe59R(qm~(iZ&PB+F7Lrt z9Xe+3xK?phqXb9h_+KeUtv4%H)|gfmr|RPJOo7_NeX$-Ui5nxKg+l>W=rxMbmo*(k zBY9S@RB5HEIu*#gZ0hh2gY&&!oH=v#P~ooh6Zb~QwCAp0YRdB-c@Q$wxZ zV~RTI-P4$|i#bT5oe<;dj@?V5Y$WZZ!A()hnj11xHaw00LwOda&%^jJ%FWz&RnB%1 zdHoyw=^nCvyCa=*7}~J$XrsdTR5T&%b6T`$~={DZ6)wvn3VogPUs|zWuF#cg0I-e7DS$GU<}f zM|AjW-%BT9P As#m+IsG?5gAr2DUZB~?H~%8lSxj|!w78mG$gbnXKz!0%2SZ7< z1vWduu{7)BC^QnR`fgdl)?;a}2S~0P9r`@|)oYQ|Z|{lAs_wd$;YZgfBO7Lm9c1I; z%}24RngiL_GwOW3TsDbOZe9mPgEIm<{p-G}vAU_0 zp-!%GsaQyfvN^%?L|xkXcWsjT)Up`1PzY$bbZH;Yig}i|X9btnRj#DX?M929nHi(6 zlHlrR1T1cy&(NE@@^ZaXRdp$0KGun}3tSrP+&?u=G7a3>;b3iuy#2qXS%Xu_{ukl& zYKFHUoeH*HMPM0PBt7sBh^;&)FKd*&rvi3)Q2lor*u9)^w@637s02%2m@`nV9Pzap zF}{%M!b=SXjPBe84MPj zi7N=1S(24d(V(mR3c1;DVN-T_z@^Ycgt^aK6nL)#cGp(}5DxNJ3NUK@U^#u)-6`Sk zWEWP}R|z*lawo@b+DL`Z{`-Ri1bO+WzlJT+$9A6zpg__8f+cLIL`uH@1(vUmyeL0S zbDo!#?qA*XwCw#ik)181jYp!-2!we|k!QpdA#D=xKylIg|1;_rvV>n$_`TqY4C8`n zVpzM}kOkdFj7JGbU&I%E{nzO?{|7?zb)vx?zutmk{BDZ!>lGe;d8wej(JEs*-tUx+ zi%W^0|2~JJ(ni^Z0*kmULVw>(z&DKL zuhToA{dxUQIa9eCVcRDcIlEgILLHa>xIfkFgoG~y3iNkQj%56{kpA!C=a(8{F$DUt z)eu+*Vw0hDFg!Sve%q^KEgy}yH$BlZiO4&Sdbrs5! z_+`<=|MtNFa7tC0<%~(18~uP&z~S+$r0W#-^MED0wktiq?NRZU>es1ToVG#(dmE4y zLp&a1HhSj|3haUB(4+J=JwmO@jcj%{X7zu10#L#jzgCLa-edm0^iP|Z6FrZ634(Fo zsWleQqG*3#GyK~Um>)HV)41M9{8Z2RR(1(=M9pzYkyS z3W6sF@4Kq^t=PzS5$X%ZeY1(2Y(fi&f3~Fm=nPT@HjVsu@+lpE}bPPz3|cB`$bLJ+Q7$h$PIgk6}!zIZ^=Mo=(X!Qsh&=n zBZKibKMK+y{ zAE==2r)#Z%2C_%M(ex32?~6+a;`gr`G=E)O=>$KT$ka9Gw4#dDM;hY zPybT|64q(wZTr;d0oQy&gBIKGOCHIT4ekKZhMlqj7~r+*w|c;NXHFNlU!YIBnT+81 zT8O9V06qy@)#s)QGKM`7{9dAg<~=bb23~nFvUvsA27$Hi_lI*ec28QjEhQW;tRI6%tMvj1Xy-Ws?5&(rqx%eS2~gJ{wS$mg&83 zMA0xg8$;H<+=Ja=ZX28iY|{36Kbo`a!Kf(NY-P*tQE<#u%ZJk)EAIU?QfDd6Sl|<5hJXb^bG$=DzXUjmICS&Mmt1U90duR(IW~sJmap z&jvrJBiDyazyJq&?}fW)Z@$%@dfO6EJ~p$11pE^h8=eA=`~%xNOxO{Udp!OI&wIfS zX~dj2C>!eD%yMaz1a7;sFZ?!q!f87#;%k9jZ~CJ5kQ-{+@YpR%cr?>xrnU~DkXVYD z!M0G+ zlg6V2_>|t`T&J>@hNmA31K452TX=5)UZ!x#^CmCJy>ORHeOKpiD=CRzqhGys3?LXn zW*@8bK^upDyn;w7lu~PIU^X_Hk=|wl9-Z%#OK%!lyw_3UsPS6^=FZ$(l#?PngtxSQ zcothH*jhmQvj82}03}I;`Q-xu2?KR9+UFe&PiOr*2|0i>yg&Mme`T7b{XtyJn|vOK zf$?S#=^70h zXGA61rumrO8I*q6Z+2inP76y$}fz3DZb#&T8ViUt*ylMlGr`umIAmG;VMWdxSLIqrt)9lpMeIl=l;MyjADFZpdg9PBK^wEUVkUJi7N$P5G zbztT{o*F`VSTLYqo&+?V382>GSi}sRxFv9CgUtBDDS8@>!x?-=d#X{q=%XfZV@A5G z((Jd$A15T4E}WNqgW~b4fZu3+{KFj}2p-|pDK^nV0!78|%43c`r)QIY&L2}>+#hf& zq5hjKzjuLsT*lM!b1^&|-6sK1_4|S9G~D2wkjX;Bb=&dT(?<2HR4N<-B==ly z21#D4n1(12cj$vg%1-aSl_SSxC1}Cd5brejeb$75hlDH^I+9L@mIZ6l(x7HK{&E<5 z`fI!oyER#a(a#G68*t}QiJrP!MDul%(`x|V(84=~x!2}L#QpIX;KSp$u=xA$fLZv0 z03xIxjRYU}VN%=3y!Yix#ew$M)St=Z^i05)<&Et6!CvXW!eJZ26JkjqR(%!^G6T`= zLuVsTJh^P-2zpZ)@RwTaJXmxX@N?EDtHSYiV<=p5^QcS+=zk9A$2A!}i?byp%|UfW zN1}U9>uZxU-@1JA3B3VQd0lZJ#p}RqW3yjP1sQpT)^nO-*mKfMt8Rfpt90kxSk3Xf zu}8M5OnH(lGa6FtGd~9Q+eh@-Bayuq>zK*WZ*@MQgi<86v_}$q9$Y7(hGHtn6T*12 Xmm%7s=B;OdABB4l@8-!od;PxvN3`>t diff --git a/samples/littlevgl/LICENCE.txt b/samples/littlevgl/LICENCE.txt new file mode 100644 index 000000000..beaef1d26 --- /dev/null +++ b/samples/littlevgl/LICENCE.txt @@ -0,0 +1,8 @@ +MIT licence +Copyright (c) 2016 Gábor Kiss-Vámosi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/samples/littlevgl/README.md b/samples/littlevgl/README.md new file mode 100644 index 000000000..5933c4d36 --- /dev/null +++ b/samples/littlevgl/README.md @@ -0,0 +1,113 @@ +Introduction +============== +This sample demonstrates that a graphic user interface application in WebAssembly integrates the LittlevGL, an open-source embedded 2d graphic library. + +In this sample, the whole LittlevGL source code is built into the WebAssembly code with the user application. The platform interfaces defined by LittlevGL is implemented in the runtime and exported to the application through the declarations from source "ext_lib_export.c" as below: + + EXPORT_WASM_API(display_init), + EXPORT_WASM_API(display_input_read), + EXPORT_WASM_API(display_flush), + EXPORT_WASM_API(display_fill), + EXPORT_WASM_API(display_vdb_write), + EXPORT_WASM_API(display_map), + EXPORT_WASM_API(time_get_ms), }; + +The runtime component supports building target for Linux and Zephyr/STM Nucleo board. The beauty of this sample is the WebAssembly application can have identical display and behavior when running from both runtime environments. That implies we can do majority of application validation from desktop environment as long as two runtime distributions support the same set of application interface. + +The sample also provides the native Linux version of application without the runtime under folder "vgl-native-ui-app". It can help to check differences between the implementations in native and WebAssembly. + + + + +The number on top will plus one each second, and the number on the bottom will plus one when clicked. + +Install required SDK and libraries +============== +- 32 bit SDL(simple directmedia layer) +Use apt-get
+ `sudo apt-get install libsdl2-dev:i386`
+Or download source from www.libsdl.org
+ `./configure C_FLAGS=-m32 CXX_FLAGS=-m32 LD_FLAGS=-m32`
+ `make`
+ `sudo make install`
+- Install EMSDK +