diff --git a/.clang-format b/.clang-format index ac1edc7..0a5370d 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,3 @@ ---- BasedOnStyle: Mozilla IndentWidth: 8 Language: Cpp @@ -10,10 +9,10 @@ AlignConsecutiveMacros: true AlignEscapedNewlines: Left AlignTrailingComments: true -AllowShortBlocksOnASingleLine: true +AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortLoopsOnASingleLine: true AlwaysBreakAfterReturnType: AllDefinitions @@ -38,7 +37,7 @@ BreakBeforeBinaryOperators: NonAssignment ColumnLimit: 120 -Cpp11BracedListStyle: false +Cpp11BracedListStyle: true IndentCaseLabels: false IndentWrappedFunctionNames: false @@ -47,10 +46,9 @@ KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 2 -DerivePointerAlignment: false PointerAlignment: Right -SortIncludes: false +SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index d1bd04f..736dc71 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -4,7 +4,7 @@ on: [push, pull_request] env: LLVM_VERSION: 13 - WASI_SDK_URL: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz + WASI_SDK_VERSION: 12 WASI_SDK_PATH: /opt/wasi-sdk LANG: C.UTF-8 LANGUAGE: C.UTF-8 @@ -18,10 +18,10 @@ jobs: - name: Apt Update run: sudo apt-get update - uses: actions/checkout@v2 - - name: Install LLVM + - name: Install Clang Format run: | sudo ./install_llvm.sh $LLVM_VERSION - - name: Clang Format + - name: Run Clang Format run: ./format.sh -d test: runs-on: ubuntu-20.04 @@ -62,6 +62,7 @@ jobs: echo "/root/.cargo/bin:$PATH" >> $GITHUB_PATH - name: Get wasi-sdk run: | + WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_SDK_VERSION/wasi-sdk-$WASI_SDK_VERSION.0-linux.tar.gz wget $WASI_SDK_URL -O wasi-sdk.tar.gz mkdir -p $WASI_SDK_PATH tar xvfz wasi-sdk.tar.gz --strip-components=1 -C $WASI_SDK_PATH diff --git a/.vscode/settings.json b/.vscode/settings.json index 4a59539..86a6061 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -116,7 +116,7 @@ "tenant.h": "c", "route_config.h": "c", "http_router.h": "c", - "admissions_info.h": "c", + "execution_histogram.h": "c", "tcp_server.h": "c", "stdint.h": "c", "scheduler_options.h": "c", @@ -144,7 +144,20 @@ "algorithm": "c", "stdio.h": "c", "get_time.h": "c", - "unistd.h": "c" + "unistd.h": "c", + "wasi.h": "c", + "stat.h": "c", + "functional": "c", + "sandbox_state.h": "c", + "ratio": "c", + "tuple": "c", + "type_traits": "c", + "perf_window.h": "c", + "http_route_total.h": "c", + "sledge_abi_symbols.h": "c", + "mutex": "c", + "lock.h": "c", + "route_latency.h": "c" }, "files.exclude": { "**/.git": true, diff --git a/Dockerfile.x86_64 b/Dockerfile.x86_64 index 35c4d3a..fb9163f 100644 --- a/Dockerfile.x86_64 +++ b/Dockerfile.x86_64 @@ -1,9 +1,12 @@ # using ubuntu 20 docker image FROM ubuntu:focal +ENV LLVM_VERSION=13 +ENV WASI_SDK_VERSION=12 + ARG DEBIAN_FRONTEND=noninteractive ARG HEY_URL=https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64 -ARG WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb +ARG WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_SDK_VERSION/wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb ARG SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.2.4/shfmt_v3.2.4_linux_amd64 ARG SHELLCHECK_URL=https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.linux.x86_64.tar.xz @@ -74,12 +77,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ vim \ wabt -ENV LLVM_VERSION=12 ADD install_llvm.sh /sledge/install_llvm.sh RUN ./sledge/install_llvm.sh $LLVM_VERSION # WASI-SDK -RUN curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb +RUN curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb && rm -f wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb ENV WASI_SDK_PATH=/opt/wasi-sdk # Create non-root user and add to sudoers diff --git a/applications/Makefile b/applications/Makefile index cbfa492..382b870 100644 --- a/applications/Makefile +++ b/applications/Makefile @@ -27,15 +27,11 @@ all: \ license_plate_detection.install \ resize_image.install \ cnn_face_detection.install \ - scratch_storage_get.install \ - scratch_storage_set.install \ - scratch_storage_delete.install \ - scratch_storage_upsert.install \ + get_jpeg_resolution.install \ .PHONY: clean clean: @make -C wasm_apps clean - @make -C scratch_storage clean @rm -rf dist @rm -rf ../runtime/bin/*.so @@ -69,7 +65,7 @@ dist/%.bc: ./wasm_apps/dist/%.wasm dist ${AWSMCC} ${AWSMFLAGS} $< -o $@ dist/%.ll: dist/%.bc - llvm-dis-12 $< -o $@ + llvm-dis $< -o $@ dist/%.wasm.so: dist/%.bc ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ @@ -109,6 +105,9 @@ license_plate_detection.install: ../runtime/bin/license_plate_detection.wasm.so .PHONY: cnn_face_detection.install cnn_face_detection.install: ../runtime/bin/cnn_face_detection.wasm.so +.PHONY: get_jpeg_resolution.install +get_jpeg_resolution.install: ../runtime/bin/get_jpeg_resolution.wasm.so + .PHONY: trap_divzero.install trap_divzero.install: ../runtime/bin/trap_divzero.wasm.so diff --git a/awsm b/awsm index e2ba697..e3abafa 160000 --- a/awsm +++ b/awsm @@ -1 +1 @@ -Subproject commit e2ba697861201f2aaca37460842ab5c34c8d1716 +Subproject commit e3abafa1e18b6d600fc0ca7e0810fea1f6621ea6 diff --git a/format.sh b/format.sh index 4aaf5fe..793175b 100755 --- a/format.sh +++ b/format.sh @@ -1,7 +1,9 @@ #!/bin/bash +LLVM_VERSION=13 + validate() { - utility="clang-format-13" + utility="clang-format" utility_version="$("$utility" --version 2> /dev/null)" || { echo "$utility not found in path!" exit 1 @@ -11,7 +13,7 @@ validate() { declare -i major=0 declare -i minor=0 declare -i patch=0 - declare -i required_major=13 + declare -i required_major=$LLVM_VERSION declare -i required_minor=0 declare -i required_patch=0 @@ -43,14 +45,14 @@ help() { dry_run() { find runtime \ - \( -path "runtime/thirdparty" -o -path "applications/gocr" -o -path "applications/TinyEKF" -o -path "applications/CMSIS_5_NN" -o -path "applications/sod" -o -path "applications/**/thirdparty" \) -prune -false -o \ - -type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print \ - | xargs clang-format -Werror -n -ferror-limit=0 + \( -path "runtime/thirdparty" \) -prune -false -o \ + -type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print0 \ + | xargs --null clang-format -Werror -n -ferror-limit=1 } format() { find runtime \ - \( -path "runtime/thirdparty" -o -path "applications/gocr" -o -path "applications/TinyEKF" -o -path "applications/CMSIS_5_NN" -o -path "applications/sod" -o -path "applications/**/thirdparty" \) -prune -false -o \ + \( -path "runtime/thirdparty" \) -prune -false -o \ -type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print0 \ | xargs --null clang-format -i } diff --git a/install_deb.sh b/install_deb.sh index 796c031..b83e1e9 100755 --- a/install_deb.sh +++ b/install_deb.sh @@ -1,12 +1,14 @@ #!/bin/bash -LLVM_VERSION=12 +# Note, wasi-sdk versions do NOT match llvm versions, e.g. wasi-sdk-12 actually uses llvm-11 +LLVM_VERSION=13 +WASI_SDK_VERSION=12 ARCH=$(uname -m) if [[ $ARCH = "x86_64" ]]; then SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.4.3/shfmt_v3.4.3_linux_amd64 - WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb + WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_SDK_VERSION/wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb elif [[ $ARCH = "aarch64" ]]; then SHFMT_URL=https://github.com/patrickvane/shfmt/releases/download/master/shfmt_linux_arm echo "ARM64 support is still a work in progress!" @@ -64,7 +66,7 @@ wget $SHFMT_URL -O shfmt && chmod +x shfmt && sudo mv shfmt /usr/local/bin/shfmt sudo ./install_llvm.sh $LLVM_VERSION -curl -sS -L -O $WASI_SDK_URL && sudo dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb +curl -sS -L -O $WASI_SDK_URL && sudo dpkg -i wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb && rm -f wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb if [ -z "${WASI_SDK_PATH}" ]; then export WASI_SDK_PATH=/opt/wasi-sdk diff --git a/install_llvm.sh b/install_llvm.sh index 635031a..5153857 100755 --- a/install_llvm.sh +++ b/install_llvm.sh @@ -8,28 +8,28 @@ echo "Installing LLVM $LLVM_VERSION" # Script Installs clang, lldb, lld, and clangd curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | bash -s -- "$LLVM_VERSION" +# Installing "libc++-xx-dev" automagically installs "libc++1-xx", "libunwind-xx" and "libunwind-xx-dev" apt-get install -y --no-install-recommends \ "libc++-$LLVM_VERSION-dev" \ "libc++abi-$LLVM_VERSION-dev" \ - "libc++1-$LLVM_VERSION" \ - "libunwind-$LLVM_VERSION" \ - "libunwind-$LLVM_VERSION-dev" \ "clang-tools-$LLVM_VERSION" \ "clang-tidy-$LLVM_VERSION" \ "clang-format-$LLVM_VERSION" -sudo update-alternatives --remove-all clang-format -sudo update-alternatives --remove-all clang -sudo update-alternatives --remove-all clang++ -sudo update-alternatives --remove-all llvm-config -sudo update-alternatives --remove-all llvm-objdump -sudo update-alternatives --remove-all llvm-objdump -sudo update-alternatives --remove-all clang-tidy +update-alternatives --remove-all wasm-ld +update-alternatives --remove-all llvm-config +update-alternatives --remove-all llvm-objdump +update-alternatives --remove-all llvm-dis +update-alternatives --remove-all clang-format +update-alternatives --remove-all clang +update-alternatives --remove-all clang++ +update-alternatives --remove-all clang-tidy +update-alternatives --install /usr/bin/wasm-ld wasm-ld "/usr/bin/wasm-ld-$LLVM_VERSION" 100 +update-alternatives --install /usr/bin/llvm-config llvm-config "/usr/bin/llvm-config-$LLVM_VERSION" 100 +update-alternatives --install /usr/bin/llvm-objdump llvm-objdump "/usr/bin/llvm-objdump-$LLVM_VERSION" 100 +update-alternatives --install /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-$LLVM_VERSION 100 update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/clang clang "/usr/bin/clang-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/clang++ clang++ "/usr/bin/clang++-$LLVM_VERSION" 100 -update-alternatives --install /usr/bin/llvm-config llvm-config "/usr/bin/llvm-config-$LLVM_VERSION" 100 -update-alternatives --install /usr/bin/llvm-objdump llvm-objdump "/usr/bin/llvm-objdump-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-$LLVM_VERSION" 100 -update-alternatives --install /usr/bin/wasm-ld wasm-ld "/usr/bin/wasm-ld-$LLVM_VERSION" 100 diff --git a/runtime/Makefile b/runtime/Makefile index a90f1b3..4cc7362 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -38,6 +38,10 @@ BINARY_NAME=sledgert # Feature Toggles +CFLAGS += -DEXECUTION_HISTOGRAM +# CFLAGS += -DEXECUTION_REGRESSION + +# It is recommended (not mandatory) to enable this flag along with the EXECUTION_HISTOGRAM flag: # CFLAGS += -DADMISSIONS_CONTROL # Debugging Flags @@ -56,6 +60,7 @@ BINARY_NAME=sledgert # CFLAGS += -DLOG_TO_FILE # Various Informational Logs for Debugging +# CFLAGS += -DLOG_EXECUTION_HISTOGRAM # CFLAGS += -DLOG_ADMISSIONS_CONTROL # CFLAGS += -DLOG_CONTEXT_SWITCHES # CFLAGS += -DLOG_HTTP_PARSER diff --git a/runtime/include/admissions_control.h b/runtime/include/admissions_control.h index c7dbcab..9590ff2 100644 --- a/runtime/include/admissions_control.h +++ b/runtime/include/admissions_control.h @@ -1,18 +1,19 @@ #pragma once +#ifdef ADMISSIONS_CONTROL + #include #include -#ifdef ADMISSIONS_CONTROL #define ADMISSIONS_CONTROL_GRANULARITY 1000000 extern _Atomic uint64_t admissions_control_admitted; extern uint64_t admissions_control_capacity; -#endif void admissions_control_initialize(void); void admissions_control_add(uint64_t admissions_estimate); void admissions_control_subtract(uint64_t admissions_estimate); uint64_t admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline); -uint64_t admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us); void admissions_control_log_decision(uint64_t admissions_estimate, bool admitted); uint64_t admissions_control_decide(uint64_t admissions_estimate); + +#endif \ No newline at end of file diff --git a/runtime/include/admissions_info.h b/runtime/include/admissions_info.h deleted file mode 100644 index d2e0dfb..0000000 --- a/runtime/include/admissions_info.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "perf_window_t.h" - -struct admissions_info { - struct perf_window perf_window; - uint8_t percentile; /* 50 - 99 */ - int control_index; /* Precomputed Lookup index when perf_window is full */ - uint64_t estimate; /* cycles */ - uint64_t relative_deadline; /* Relative deadline in cycles. This is duplicated state */ -}; - -void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, - uint64_t expected_execution, uint64_t relative_deadline); -void admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration); diff --git a/runtime/include/arch/arch_context_t.h b/runtime/include/arch/arch_context_t.h index e1c1bac..bdb3e0e 100644 --- a/runtime/include/arch/arch_context_t.h +++ b/runtime/include/arch/arch_context_t.h @@ -3,9 +3,9 @@ #include #include +#include "arch/arch_context_variant_t.h" #include "arch/reg_t.h" #include "arch/ureg_t.h" -#include "arch/arch_context_variant_t.h" struct arch_context { arch_context_variant_t variant; diff --git a/runtime/include/auto_buf.h b/runtime/include/auto_buf.h index 9071d25..74095fb 100644 --- a/runtime/include/auto_buf.h +++ b/runtime/include/auto_buf.h @@ -1,5 +1,6 @@ #pragma once +#include "likely.h" #include #include #include diff --git a/runtime/include/current_sandbox.h b/runtime/include/current_sandbox.h index fa84dff..ac58b4c 100644 --- a/runtime/include/current_sandbox.h +++ b/runtime/include/current_sandbox.h @@ -3,6 +3,7 @@ #include #include "current_wasm_module_instance.h" +#include "listener_thread.h" #include "sandbox_types.h" /* current sandbox that is active.. */ @@ -30,24 +31,25 @@ current_sandbox_set(struct sandbox *sandbox) /* Unpack hierarchy to avoid pointer chasing */ if (sandbox == NULL) { sledge_abi__current_wasm_module_instance = (struct wasm_module_instance){ - /* Public */ - .abi = - (struct sledge_abi__wasm_module_instance){ - .memory = - (struct sledge_abi__wasm_memory){ - .size = 0, - .capacity = 0, - .max = 0, - .buffer = NULL, - }, - .table = NULL, - .wasmg_0 = 0, - }, - /* Private */ - .wasi_context = NULL, + /* Public */ + .abi = + (struct sledge_abi__wasm_module_instance){ + .memory = + (struct sledge_abi__wasm_memory){ + .size = 0, + .capacity = 0, + .max = 0, + .buffer = NULL, + }, + .table = NULL, + .wasmg_0 = 0, + }, + /* Private */ + .wasi_context = NULL, }; - worker_thread_current_sandbox = NULL; - runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX; + worker_thread_current_sandbox = NULL; + /* This is because the event core does not maintain core-assigned deadline */ + if (!listener_thread_is_running()) runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX; } else { sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi, @@ -55,8 +57,9 @@ current_sandbox_set(struct sandbox *sandbox) sledge_abi__current_wasm_module_instance.abi.table = sandbox->module->indirect_table; wasm_globals_update_if_used(&sandbox->globals, 0, &sledge_abi__current_wasm_module_instance.abi.wasmg_0); - worker_thread_current_sandbox = sandbox; - runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline; + worker_thread_current_sandbox = sandbox; + if (!listener_thread_is_running()) + runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline; } } diff --git a/runtime/include/execution_histogram.h b/runtime/include/execution_histogram.h new file mode 100644 index 0000000..bcbb580 --- /dev/null +++ b/runtime/include/execution_histogram.h @@ -0,0 +1,14 @@ +#pragma once + +#include "perf_window_t.h" + +struct execution_histogram { + struct perf_window perf_window; + uint8_t percentile; /* 50 - 99 */ + int control_index; /* Precomputed Lookup index when perf_window is full */ + uint64_t estimated_execution; /* cycles */ +}; + +void execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile, + uint64_t expected_execution); +void execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration); diff --git a/runtime/include/execution_regression.h b/runtime/include/execution_regression.h new file mode 100644 index 0000000..deb8159 --- /dev/null +++ b/runtime/include/execution_regression.h @@ -0,0 +1,26 @@ +#pragma once + +#ifdef EXECUTION_REGRESSION + +#include "http_session.h" +#include + +static inline uint64_t +get_regression_prediction(struct http_session *session) +{ + /* Default Pre-processing - Extract payload size */ + const int payload_size = session->http_request.body_length; + + const double regression_params[2] = {payload_size, session->paregression_paramram2}; + + /* Perform Linear Regression using the factors provided by the regressor performed AoT on Matlab using training + * tenant-given dataset */ + const struct regression_model model = session->route->regr_model; + const uint64_t prediction = (regression_params[0] / model.scale * model.beta1 + + regression_params[1] / model.scale * model.beta2) + + model.bias; + + return prediction; +} + +#endif \ No newline at end of file diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 3b83206..2472e27 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -1,14 +1,12 @@ #pragma once -#include -#include - #include "http.h" #include "module.h" -#include "route_latency.h" #include "route.h" #include "route_config.h" +#include "route_latency.h" #include "vec.h" +#include typedef struct route route_t; VEC(route_t) @@ -22,7 +20,8 @@ http_router_init(http_router_t *router, size_t capacity) } static inline int -http_router_add_route(http_router_t *router, struct route_config *config, struct module *module) +http_router_add_route(http_router_t *router, struct route_config *config, struct module *module, + struct module *module_proprocess) { assert(router != NULL); assert(config != NULL); @@ -30,20 +29,35 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct assert(config->route != NULL); assert(config->http_resp_content_type != NULL); - struct route route = { .route = config->route, - .module = module, - .relative_deadline_us = config->relative_deadline_us, - .relative_deadline = (uint64_t)config->relative_deadline_us - * runtime_processor_speed_MHz, - .response_content_type = config->http_resp_content_type }; + struct route route = {.route = config->route, + .module = module, + .relative_deadline_us = config->relative_deadline_us, + .relative_deadline = (uint64_t)config->relative_deadline_us * runtime_processor_speed_MHz, + .response_content_type = config->http_resp_content_type}; route_latency_init(&route.latency); http_route_total_init(&route.metrics); - /* Admissions Control */ - uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz; - admissions_info_initialize(&route.admissions_info, config->admissions_percentile, expected_execution, - route.relative_deadline); +#ifdef EXECUTION_REGRESSION + /* Execution Regression setup */ + route.module_proprocess = module_proprocess; + route.regr_model.bias = config->model_bias / 1000.0; + route.regr_model.scale = config->model_scale / 1000.0; + route.regr_model.num_of_param = config->model_num_of_param; + route.regr_model.beta1 = config->model_beta1 / 1000.0; + route.regr_model.beta2 = config->model_beta2 / 1000.0; +#endif + + const uint64_t expected_execution = route.relative_deadline / 2; +#ifdef ADMISSIONS_CONTROL + /* Addmissions Control setup */ + route.execution_histogram.estimated_execution = expected_execution; +#endif + +#ifdef EXECUTION_HISTOGRAM + /* Execution Histogram setup */ + execution_histogram_initialize(&route.execution_histogram, config->admissions_percentile, expected_execution); +#endif int rc = vec_route_t_push(router, route); if (unlikely(rc == -1)) { return -1; } diff --git a/runtime/include/http_session.h b/runtime/include/http_session.h index 707d4dd..8c76054 100644 --- a/runtime/include/http_session.h +++ b/runtime/include/http_session.h @@ -57,6 +57,9 @@ struct http_session { uint64_t request_downloaded_timestamp; uint64_t response_takeoff_timestamp; uint64_t response_sent_timestamp; + bool did_preprocessing; + uint64_t preprocessing_duration; + double regression_param; /* Calculated in tenant preprocessing logic if provided */ }; extern void http_session_perf_log_print_entry(struct http_session *http_session); diff --git a/runtime/include/http_session_perf_log.h b/runtime/include/http_session_perf_log.h index 98ba049..0e5b016 100644 --- a/runtime/include/http_session_perf_log.h +++ b/runtime/include/http_session_perf_log.h @@ -1,8 +1,8 @@ #pragma once +#include "http_session.h" #include "pretty_print.h" #include "runtime.h" -#include "http_session.h" extern FILE *http_session_perf_log; typedef struct http_session http_session; @@ -15,8 +15,8 @@ static inline void http_session_perf_log_print_header() { if (http_session_perf_log == NULL) { perror("http_session perf log"); } - fprintf(http_session_perf_log, - "tenant,route,state,header_len,resp_body_len,receive_duration,sent_duration,total_lifetime,proc_MHz\n"); + fprintf(http_session_perf_log, "tenant,route,state,header_len,resp_body_len,receive_duration,sent_duration," + "total_lifetime,preprocessing,proc_MHz\n"); } static inline void diff --git a/runtime/include/json.h b/runtime/include/json.h index 547a686..71c00c5 100644 --- a/runtime/include/json.h +++ b/runtime/include/json.h @@ -2,12 +2,12 @@ #include #include +#include #include -#include #include #include +#include #include -#include static inline char * jsmn_type(jsmntype_t type) diff --git a/runtime/include/map.h b/runtime/include/map.h index a40f9db..de44819 100644 --- a/runtime/include/map.h +++ b/runtime/include/map.h @@ -98,12 +98,12 @@ map_set(struct map *map, uint8_t *key, uint32_t key_len, uint8_t *value, uint32_ } struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node)); - *(new_node) = (struct map_node){ .hash = hash, - .key = xmalloc(key_len), - .key_len = key_len, - .value = xmalloc(value_len), - .value_len = value_len, - .next = bucket->head }; + *(new_node) = (struct map_node){.hash = hash, + .key = xmalloc(key_len), + .key_len = key_len, + .value = xmalloc(value_len), + .value_len = value_len, + .next = bucket->head}; // Copy Key and Value memcpy(new_node->key, key, key_len); @@ -174,12 +174,12 @@ map_upsert(struct map *map, uint8_t *key, uint32_t key_len, uint8_t *value, uint struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node)); - *(new_node) = (struct map_node){ .hash = hash, - .key = xmalloc(key_len), - .key_len = key_len, - .value = xmalloc(value_len), - .value_len = value_len, - .next = bucket->head }; + *(new_node) = (struct map_node){.hash = hash, + .key = xmalloc(key_len), + .key_len = key_len, + .value = xmalloc(value_len), + .value_len = value_len, + .next = bucket->head}; assert(new_node->key); assert(new_node->value); diff --git a/runtime/include/module.h b/runtime/include/module.h index b2ab6ad..390379d 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -1,22 +1,11 @@ #pragma once -#include -#include -#include -#include - -#include "admissions_control.h" -#include "admissions_info.h" #include "current_wasm_module_instance.h" -#include "panic.h" #include "pool.h" #include "sledge_abi_symbols.h" -#include "tcp_server.h" #include "types.h" -#include "sledge_abi_symbols.h" -#include "wasm_stack.h" #include "wasm_memory.h" -#include "wasm_table.h" +#include "wasm_stack.h" extern thread_local int worker_thread_idx; @@ -28,9 +17,15 @@ struct module_pool { struct wasm_stack_pool stack; } CACHE_PAD_ALIGNED; +enum module_type +{ + APP_MODULE, + PREPROCESS_MODULE +}; struct module { - char *path; - uint32_t stack_size; /* a specification? */ + char *path; + uint32_t stack_size; /* a specification? */ + enum module_type type; /* Handle and ABI Symbols for *.so file */ struct sledge_abi_symbols abi; @@ -41,12 +36,13 @@ struct module { struct module_pool *pools; } CACHE_PAD_ALIGNED; + /******************************** * Public Methods from module.c * *******************************/ void module_free(struct module *module); -struct module *module_alloc(char *path); +struct module *module_alloc(char *path, enum module_type type); /************************* * Public Static Inlines * @@ -115,7 +111,9 @@ module_alloc_table(struct module *module) static inline void module_initialize_pools(struct module *module) { - for (int i = 0; i < runtime_worker_threads_count; i++) { + /* Create only a single pool for the preprocessing module, since it is executed only by the event core. */ + const int n = module->type == APP_MODULE ? runtime_worker_threads_count : 1; + for (int i = 0; i < n; i++) { wasm_memory_pool_init(&module->pools[i].memory, false); wasm_stack_pool_init(&module->pools[i].stack, false); } @@ -124,7 +122,8 @@ module_initialize_pools(struct module *module) static inline void module_deinitialize_pools(struct module *module) { - for (int i = 0; i < runtime_worker_threads_count; i++) { + const int n = module->type == APP_MODULE ? runtime_worker_threads_count : 1; + for (int i = 0; i < n; i++) { wasm_memory_pool_deinit(&module->pools[i].memory); wasm_stack_pool_deinit(&module->pools[i].stack); } diff --git a/runtime/include/perf_window.h b/runtime/include/perf_window.h index 5b2b37f..f42149e 100644 --- a/runtime/include/perf_window.h +++ b/runtime/include/perf_window.h @@ -72,8 +72,8 @@ perf_window_fill(struct perf_window *perf_window, uint64_t newest_execution_time { for (uint16_t i = 0; i < PERF_WINDOW_CAPACITY; i++) { perf_window->by_termination[i] = i; - perf_window->by_duration[i] = (struct execution_node){ .execution_time = newest_execution_time, - .by_termination_idx = i }; + perf_window->by_duration[i] = (struct execution_node){.execution_time = newest_execution_time, + .by_termination_idx = i}; } perf_window->count = PERF_WINDOW_CAPACITY; } diff --git a/runtime/include/pretty_print.h b/runtime/include/pretty_print.h index 72ce7db..edd0205 100644 --- a/runtime/include/pretty_print.h +++ b/runtime/include/pretty_print.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #define PRETTY_PRINT_COLOR_CODE_RED "\033[1;31m" #define PRETTY_COLOR_CODE_GREEN "\033[0;32m" diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index 0fddfc0..7b1650c 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -3,8 +3,8 @@ #include -#include "lock.h" #include "listener_thread.h" +#include "lock.h" #include "panic.h" #include "runtime.h" #include "worker_thread.h" diff --git a/runtime/include/proc_stat.h b/runtime/include/proc_stat.h index f36e959..7fe8637 100644 --- a/runtime/include/proc_stat.h +++ b/runtime/include/proc_stat.h @@ -2,8 +2,8 @@ #include #include -#include #include +#include #include #include "runtime.h" /* For runtime_pid */ diff --git a/runtime/include/route.h b/runtime/include/route.h index a574932..e7812cb 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -1,22 +1,32 @@ #pragma once -#include #include +#include -#include "admissions_info.h" -#include "module.h" +#include "execution_histogram.h" #include "http_route_total.h" +#include "module.h" #include "perf_window.h" +struct regression_model { + double bias; + double scale; + uint32_t num_of_param; + double beta1; + double beta2; +}; + /* Assumption: entrypoint is always _start. This should be enhanced later */ struct route { char *route; struct http_route_total metrics; struct module *module; /* HTTP State */ - uint32_t relative_deadline_us; - uint64_t relative_deadline; /* cycles */ - char *response_content_type; - struct admissions_info admissions_info; - struct perf_window latency; + uint32_t relative_deadline_us; + uint64_t relative_deadline; /* cycles */ + char *response_content_type; + struct execution_histogram execution_histogram; + struct perf_window latency; + struct module *module_proprocess; + struct regression_model regr_model; }; diff --git a/runtime/include/route_config.h b/runtime/include/route_config.h index 78b743b..e2fd2a4 100644 --- a/runtime/include/route_config.h +++ b/runtime/include/route_config.h @@ -13,8 +13,13 @@ enum route_config_member route_config_member_route, route_config_member_path, route_config_member_admissions_percentile, - route_config_member_expected_execution_us, route_config_member_relative_deadline_us, + route_config_member_path_preprocess, + route_config_member_model_bias, + route_config_member_model_scale, + route_config_member_model_num_of_param, + route_config_member_model_beta1, + route_config_member_model_beta2, route_config_member_http_resp_content_type, route_config_member_len }; @@ -23,8 +28,13 @@ struct route_config { char *route; char *path; uint8_t admissions_percentile; - uint32_t expected_execution_us; uint32_t relative_deadline_us; + char *path_preprocess; + uint32_t model_bias; + uint32_t model_scale; + uint32_t model_num_of_param; + uint32_t model_beta1; + uint32_t model_beta2; char *http_resp_content_type; }; @@ -45,9 +55,15 @@ route_config_print(struct route_config *config) printf("[Route] Route: %s\n", config->route); printf("[Route] Path: %s\n", config->path); printf("[Route] Admissions Percentile: %hhu\n", config->admissions_percentile); - printf("[Route] Expected Execution (us): %u\n", config->expected_execution_us); printf("[Route] Relative Deadline (us): %u\n", config->relative_deadline_us); printf("[Route] HTTP Response Content Type: %s\n", config->http_resp_content_type); +#ifdef EXECUTION_HISTOGRAM + printf("[Route] Path of Preprocessing Module: %s\n", config->path_preprocess); + printf("[Route] Model Bias: %u\n", config->model_bias); + printf("[Route] Model Scale: %u\n", config->model_scale); + printf("[Route] Model Num of Parameters: %u\n", config->model_num_of_param); + printf("[Route] Model Betas: [%u, %u]\n", config->model_beta1, config->model_beta2); +#endif } /** @@ -59,7 +75,7 @@ static inline int route_config_validate(struct route_config *config, bool *did_set) { if (did_set[route_config_member_route] == false) { - fprintf(stderr, "path field is required\n"); + fprintf(stderr, "route field is required\n"); return -1; } @@ -73,9 +89,9 @@ route_config_validate(struct route_config *config, bool *did_set) config->http_resp_content_type = "text/plain"; } - if (scheduler != SCHEDULER_FIFO) { + if (scheduler != SCHEDULER_FIFO && scheduler != SCHEDULER_SJF) { if (did_set[route_config_member_relative_deadline_us] == false) { - fprintf(stderr, "relative_deadline_us is required\n"); + fprintf(stderr, "relative_deadline_us is required for the selected scheduler\n"); return -1; } @@ -84,36 +100,80 @@ route_config_validate(struct route_config *config, bool *did_set) (uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX, config->relative_deadline_us); return -1; } + } -#ifdef ADMISSIONS_CONTROL - if (did_set[route_config_member_expected_execution_us] == false) { - fprintf(stderr, "expected-execution-us is required\n"); - return -1; - } +#ifdef EXECUTION_HISTOGRAM + if (config->admissions_percentile > 99 || config->admissions_percentile < 50) { + fprintf(stderr, "admissions-percentile must be > 50 and <= 99 but was %u, defaulting to 70\n", + config->admissions_percentile); + config->admissions_percentile = 70; + } +#endif + +#ifdef EXECUTION_REGRESSION + if (did_set[route_config_member_path_preprocess] == false) { + fprintf(stderr, "model path_preprocess field is required. Put zero if just default preprocessing\n"); + return -1; + } else if (strcmp(config->path_preprocess, "0") == 0) { + config->path_preprocess = NULL; + } + + if (did_set[route_config_member_model_bias] == false) { + fprintf(stderr, "model bias field is required\n"); + return -1; + } + + if (did_set[route_config_member_model_scale] == false) { + fprintf(stderr, "model scale field is required\n"); + return -1; + } + + if (config->model_scale == 0) { + fprintf(stderr, "model scale cannot be zero (to avoid divide by zero)\n"); + return -1; + } - if (did_set[route_config_member_admissions_percentile] == false) { - fprintf(stderr, "admissions_percentile is required\n"); + if (did_set[route_config_member_model_num_of_param] == false) { + fprintf(stderr, "model num_of_param field is required\n"); + return -1; + } + + if (did_set[route_config_member_model_beta1] == false) { + fprintf(stderr, "model beta1 field is required\n"); + return -1; + } + + if (config->model_beta1 == 0) { + fprintf(stderr, "model beta1 cannot be zero (to avoid divide by zero)\n"); + return -1; + } + + if (did_set[route_config_member_model_beta2] == false) { + fprintf(stderr, "model beta2 field is required. Put zero for just default preprocessing\n"); + return -1; + } + + if (config->model_num_of_param < 1) { + fprintf(stderr, "model num_of_param must be at least 1 (just default preprocessing)\n"); + return -1; + } else if (config->model_num_of_param == 1) { + if (config->path_preprocess) { + fprintf(stderr, "model_num_of_param cannot be 1 when using tenant preprocessing\n"); return -1; } - - if (config->admissions_percentile > 99 || config->admissions_percentile < 50) { - fprintf(stderr, "admissions-percentile must be > 50 and <= 99 but was %u\n", - config->admissions_percentile); + config->model_beta2 = 1; /* This is to avoid divide-by-zero */ + } else { + /* For now we just support up to two params */ + assert(config->model_num_of_param == 2); + if (config->path_preprocess == NULL) { + fprintf(stderr, "model_num_of_param cannot be more than 1 when just default preprocessing\n"); return -1; } - - /* If the ratio is too big, admissions control is too coarse */ - uint32_t ratio = config->relative_deadline_us / config->expected_execution_us; - if (ratio > ADMISSIONS_CONTROL_GRANULARITY) { - fprintf(stderr, - "Ratio of Deadline to Execution time cannot exceed admissions control " - "granularity of " - "%d\n", - ADMISSIONS_CONTROL_GRANULARITY); + if (config->model_beta2 == 0) { + fprintf(stderr, "model beta2 cannot be zero (to avoid divide by zero)\n"); return -1; } -#endif } - +#endif return 0; } diff --git a/runtime/include/route_config_parse.h b/runtime/include/route_config_parse.h index f3a1be0..8abdde4 100644 --- a/runtime/include/route_config_parse.h +++ b/runtime/include/route_config_parse.h @@ -6,12 +6,10 @@ #include "json.h" #include "route_config.h" -static const char *route_config_json_keys[route_config_member_len] = { "route", - "path", - "admissions-percentile", - "expected-execution-us", - "relative-deadline-us", - "http-resp-content-type" }; +static const char *route_config_json_keys[route_config_member_len] = + {"route", "path", "admissions-percentile", "relative-deadline-us", + "path_preprocess", "model-bias", "model-scale", "model-num-of-param", + "model-beta1", "model-beta2", "http-resp-content-type"}; static inline int route_config_set_key_once(bool *did_set, enum route_config_member member) @@ -30,8 +28,8 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t int tokens_size) { int i = tokens_base; - char key[32] = { 0 }; - bool did_set[route_config_member_len] = { false }; + char key[32] = {0}; + bool did_set[route_config_member_len] = {false}; if (!has_valid_type(tokens[i], "Anonymous Route Config Object", JSMN_OBJECT, json_buf)) return -1; if (!is_nonempty_object(tokens[i], "Anonymous Route Config Object")) return -1; @@ -61,6 +59,11 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t if (route_config_set_key_once(did_set, route_config_member_path) == -1) return -1; config->path = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start); + } else if (strcmp(key, route_config_json_keys[route_config_member_path_preprocess]) == 0) { + if (!is_nonempty_string(tokens[i], key)) return -1; + if (route_config_set_key_once(did_set, route_config_member_path_preprocess) == -1) return -1; + + config->path_preprocess = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start); } else if (strcmp(key, route_config_json_keys[route_config_member_admissions_percentile]) == 0) { if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; if (route_config_set_key_once(did_set, route_config_member_admissions_percentile) == -1) @@ -70,15 +73,6 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t route_config_json_keys[route_config_member_admissions_percentile], &config->admissions_percentile); if (rc < 0) return -1; - } else if (strcmp(key, route_config_json_keys[route_config_member_expected_execution_us]) == 0) { - if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; - if (route_config_set_key_once(did_set, route_config_member_expected_execution_us) == -1) - return -1; - - int rc = parse_uint32_t(tokens[i], json_buf, - route_config_json_keys[route_config_member_expected_execution_us], - &config->expected_execution_us); - if (rc < 0) return -1; } else if (strcmp(key, route_config_json_keys[route_config_member_relative_deadline_us]) == 0) { if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; if (route_config_set_key_once(did_set, route_config_member_relative_deadline_us) == -1) @@ -88,6 +82,49 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t route_config_json_keys[route_config_member_relative_deadline_us], &config->relative_deadline_us); if (rc < 0) return -1; + } else if (strcmp(key, "expected-execution-us") == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + printf("The \"expected-execution-us\" field has been deprecated, so no need.\n"); + } else if (strcmp(key, route_config_json_keys[route_config_member_model_bias]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_model_bias) == -1) return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_model_bias], + &config->model_bias); + if (rc < 0) return -1; + } else if (strcmp(key, route_config_json_keys[route_config_member_model_scale]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_model_scale) == -1) return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_model_scale], + &config->model_scale); + if (rc < 0) return -1; + } else if (strcmp(key, route_config_json_keys[route_config_member_model_num_of_param]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_model_num_of_param) == -1) return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_model_num_of_param], + &config->model_num_of_param); + if (rc < 0) return -1; + } else if (strcmp(key, route_config_json_keys[route_config_member_model_beta1]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_model_beta1) == -1) return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_model_beta1], + &config->model_beta1); + if (rc < 0) return -1; + } else if (strcmp(key, route_config_json_keys[route_config_member_model_beta2]) == 0) { + if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1; + if (route_config_set_key_once(did_set, route_config_member_model_beta2) == -1) return -1; + + int rc = parse_uint32_t(tokens[i], json_buf, + route_config_json_keys[route_config_member_model_beta2], + &config->model_beta2); + if (rc < 0) return -1; } else if (strcmp(key, route_config_json_keys[route_config_member_http_resp_content_type]) == 0) { if (!is_nonempty_string(tokens[i], key)) return -1; if (route_config_set_key_once(did_set, route_config_member_http_resp_content_type) == -1) diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 4fe0ec2..c467bf1 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -1,10 +1,10 @@ #pragma once #include -#include /* for epoll_create1(), epoll_ctl(), struct epoll_event */ -#include /* for pid_t */ #include #include +#include /* for epoll_create1(), epoll_ctl(), struct epoll_event */ +#include /* for pid_t */ #include "likely.h" #include "types.h" diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 754d40c..0f28516 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -1,12 +1,12 @@ #pragma once -#include #include #include +#include #include "panic.h" -#include "tenant.h" #include "sandbox_types.h" +#include "tenant.h" /*************************** * Public API * diff --git a/runtime/include/sandbox_perf_log.h b/runtime/include/sandbox_perf_log.h index a7a96de..0610f2d 100644 --- a/runtime/include/sandbox_perf_log.h +++ b/runtime/include/sandbox_perf_log.h @@ -15,7 +15,7 @@ sandbox_perf_log_print_header() if (sandbox_perf_log == NULL) { perror("sandbox perf log"); } fprintf(sandbox_perf_log, "id,tenant,route,state,deadline,actual,queued,uninitialized,allocated,initialized," "runnable,interrupted,preempted," - "running_sys,running_user,asleep,returned,complete,error,proc_MHz,memory\n"); + "running_sys,running_user,asleep,returned,complete,error,proc_MHz,payload_size\n"); } /** @@ -36,8 +36,9 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) * becomes more intelligent, then peak linear memory size needs to be tracked * seperately from current linear memory size. */ - fprintf(sandbox_perf_log, "%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u\n", - sandbox->id, sandbox->tenant->name, sandbox->route->route, sandbox_state_stringify(sandbox->state), + fprintf(sandbox_perf_log, + "%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u,%u,%d,%d\n", sandbox->id, + sandbox->tenant->name, sandbox->route->route, sandbox_state_stringify(sandbox->state), sandbox->route->relative_deadline, sandbox->total_time, queued_duration, sandbox->duration_of_state[SANDBOX_UNINITIALIZED], sandbox->duration_of_state[SANDBOX_ALLOCATED], sandbox->duration_of_state[SANDBOX_INITIALIZED], sandbox->duration_of_state[SANDBOX_RUNNABLE], @@ -45,7 +46,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox) sandbox->duration_of_state[SANDBOX_RUNNING_SYS], sandbox->duration_of_state[SANDBOX_RUNNING_USER], sandbox->duration_of_state[SANDBOX_ASLEEP], sandbox->duration_of_state[SANDBOX_RETURNED], sandbox->duration_of_state[SANDBOX_COMPLETE], sandbox->duration_of_state[SANDBOX_ERROR], - runtime_processor_speed_MHz); + runtime_processor_speed_MHz, sandbox->response_code, 0, sandbox->payload_size); } static inline void diff --git a/runtime/include/sandbox_set_as_asleep.h b/runtime/include/sandbox_set_as_asleep.h index f96bd2a..a1a2263 100644 --- a/runtime/include/sandbox_set_as_asleep.h +++ b/runtime/include/sandbox_set_as_asleep.h @@ -5,10 +5,10 @@ #include "arch/getcycles.h" #include "local_runqueue.h" -#include "sandbox_types.h" #include "sandbox_state.h" #include "sandbox_state_history.h" #include "sandbox_state_transition.h" +#include "sandbox_types.h" /** * Transitions a sandbox to the SANDBOX_ASLEEP state. diff --git a/runtime/include/sandbox_set_as_complete.h b/runtime/include/sandbox_set_as_complete.h index 9ef7dd5..2c2c684 100644 --- a/runtime/include/sandbox_set_as_complete.h +++ b/runtime/include/sandbox_set_as_complete.h @@ -3,7 +3,9 @@ #include #include +#include "admissions_control.h" #include "arch/getcycles.h" +#include "execution_histogram.h" #include "panic.h" #include "sandbox_functions.h" #include "sandbox_perf_log.h" @@ -46,15 +48,24 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) sandbox_state_totals_increment(SANDBOX_COMPLETE); sandbox_state_totals_decrement(last_state); + struct route *route = sandbox->route; + +#ifdef EXECUTION_HISTOGRAM + /* Execution Histogram Post Processing */ + const uint64_t execution_duration = sandbox->duration_of_state[SANDBOX_RUNNING_USER] + + sandbox->duration_of_state[SANDBOX_RUNNING_SYS]; + execution_histogram_update(&route->execution_histogram, execution_duration); +#endif + +#ifdef ADMISSIONS_CONTROL /* Admissions Control Post Processing */ - admissions_info_update(&sandbox->route->admissions_info, sandbox->duration_of_state[SANDBOX_RUNNING_USER] - + sandbox->duration_of_state[SANDBOX_RUNNING_SYS]); admissions_control_subtract(sandbox->admissions_estimate); +#endif /* Terminal State Logging for Sandbox */ sandbox_perf_log_print_entry(sandbox); sandbox_summarize_page_allocations(sandbox); - route_latency_add(&sandbox->route->latency, sandbox->total_time); + route_latency_add(&route->latency, sandbox->total_time); /* State Change Hooks */ sandbox_state_transition_from_hook(sandbox, last_state); diff --git a/runtime/include/sandbox_set_as_error.h b/runtime/include/sandbox_set_as_error.h index 39020ed..68a13b7 100644 --- a/runtime/include/sandbox_set_as_error.h +++ b/runtime/include/sandbox_set_as_error.h @@ -3,16 +3,17 @@ #include #include +#include "admissions_control.h" #include "arch/getcycles.h" #include "listener_thread.h" #include "local_runqueue.h" -#include "sandbox_state.h" +#include "panic.h" #include "sandbox_functions.h" #include "sandbox_perf_log.h" +#include "sandbox_state.h" #include "sandbox_state_history.h" #include "sandbox_state_transition.h" #include "sandbox_summarize_page_allocations.h" -#include "panic.h" /** * Transitions a sandbox to the SANDBOX_ERROR state. @@ -48,14 +49,21 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Bookkeeping */ assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; + if (last_state == SANDBOX_RUNNING_SYS) { + sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration) + ? sandbox->remaining_exec - sandbox->last_state_duration + : 0; + } sandbox->duration_of_state[last_state] += sandbox->last_state_duration; sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_ERROR); sandbox_state_totals_increment(SANDBOX_ERROR); sandbox_state_totals_decrement(last_state); +#ifdef ADMISSIONS_CONTROL /* Admissions Control Post Processing */ admissions_control_subtract(sandbox->admissions_estimate); +#endif /* Return HTTP session to listener core to be written back to client */ http_session_set_response_header(sandbox->http, 500); diff --git a/runtime/include/sandbox_set_as_interrupted.h b/runtime/include/sandbox_set_as_interrupted.h index e2ee369..b49f51c 100644 --- a/runtime/include/sandbox_set_as_interrupted.h +++ b/runtime/include/sandbox_set_as_interrupted.h @@ -25,6 +25,10 @@ sandbox_set_as_interrupted(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Bookkeeping */ assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; + assert(last_state == SANDBOX_RUNNING_USER); + sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration) + ? sandbox->remaining_exec - sandbox->last_state_duration + : 0; sandbox->duration_of_state[last_state] += sandbox->last_state_duration; sandbox->timestamp_of.last_state_change = now; /* We do not append SANDBOX_INTERRUPTED to the sandbox_state_history because it would quickly fill the buffer */ diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index 2eec1bf..239322c 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -3,8 +3,8 @@ #include #include -#include "auto_buf.h" #include "arch/getcycles.h" +#include "auto_buf.h" #include "listener_thread.h" #include "local_runqueue.h" #include "panic.h" @@ -45,6 +45,9 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Bookkeeping */ assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; + sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration) + ? sandbox->remaining_exec - sandbox->last_state_duration + : 0; sandbox->duration_of_state[last_state] += sandbox->last_state_duration; sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RETURNED); @@ -60,5 +63,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) sandbox_state_transition_from_hook(sandbox, last_state); sandbox_state_transition_to_hook(sandbox, SANDBOX_RETURNED); + assert(sandbox->response_code == 0); + sandbox->response_code = 200; sandbox_process_scheduler_updates(sandbox); } diff --git a/runtime/include/sandbox_set_as_running_sys.h b/runtime/include/sandbox_set_as_running_sys.h index 5c00013..556b11a 100644 --- a/runtime/include/sandbox_set_as_running_sys.h +++ b/runtime/include/sandbox_set_as_running_sys.h @@ -41,6 +41,11 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Bookkeeping */ assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; + if (last_state == SANDBOX_RUNNING_USER) { + sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration) + ? sandbox->remaining_exec - sandbox->last_state_duration + : 0; + } sandbox->duration_of_state[last_state] += sandbox->last_state_duration; sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_SYS); @@ -55,6 +60,8 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) static inline void sandbox_syscall(struct sandbox *sandbox) { + if (sandbox->module->type == PREPROCESS_MODULE) return; + assert(sandbox->state == SANDBOX_RUNNING_USER); sandbox_set_as_running_sys(sandbox, SANDBOX_RUNNING_USER); diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index bf6ade7..801968d 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -6,10 +6,10 @@ #include "arch/getcycles.h" #include "current_sandbox.h" #include "panic.h" +#include "sandbox_functions.h" #include "sandbox_state_history.h" #include "sandbox_state_transition.h" #include "sandbox_types.h" -#include "sandbox_functions.h" static inline void sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) @@ -37,6 +37,11 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Bookkeeping */ assert(now > sandbox->timestamp_of.last_state_change); sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change; + if (last_state == SANDBOX_RUNNING_SYS) { + sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration) + ? sandbox->remaining_exec - sandbox->last_state_duration + : 0; + } sandbox->duration_of_state[last_state] += sandbox->last_state_duration; sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_USER); @@ -61,6 +66,8 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) static inline void sandbox_return(struct sandbox *sandbox) { + if (sandbox->module->type == PREPROCESS_MODULE) return; + assert(sandbox->state == SANDBOX_RUNNING_SYS); sandbox_set_as_running_user(sandbox, SANDBOX_RUNNING_SYS); } diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 796c4b3..49cfb80 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -9,11 +9,11 @@ #include "sandbox_state.h" #include "sandbox_state_history.h" #include "tenant.h" +#include "wasi.h" +#include "wasm_globals.h" #include "wasm_memory.h" -#include "wasm_types.h" #include "wasm_stack.h" -#include "wasm_globals.h" -#include "wasi.h" +#include "wasm_types.h" /********************* * Structs and Types * @@ -38,6 +38,7 @@ struct sandbox { uint64_t id; sandbox_state_t state; struct sandbox_state_history state_history; + uint16_t response_code; /* Accounting Info */ @@ -61,10 +62,12 @@ struct sandbox { uint64_t duration_of_state[SANDBOX_STATE_COUNT]; uint64_t last_state_duration; + uint64_t remaining_exec; uint64_t absolute_deadline; uint64_t admissions_estimate; /* estimated execution time (cycles) * runtime_admissions_granularity / relative deadline (cycles) */ uint64_t total_time; /* Total time from Request to Response */ + int payload_size; /* System Interface State */ int32_t return_value; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 69c96e7..927be1e 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -9,19 +9,19 @@ #include "global_request_scheduler_deque.h" #include "global_request_scheduler_minheap.h" #include "global_request_scheduler_mtds.h" +#include "local_cleanup_queue.h" #include "local_runqueue.h" -#include "local_runqueue_minheap.h" #include "local_runqueue_list.h" -#include "local_cleanup_queue.h" +#include "local_runqueue_minheap.h" #include "local_runqueue_mtds.h" #include "panic.h" #include "sandbox_functions.h" -#include "sandbox_types.h" +#include "sandbox_set_as_interrupted.h" #include "sandbox_set_as_preempted.h" #include "sandbox_set_as_runnable.h" #include "sandbox_set_as_running_sys.h" -#include "sandbox_set_as_interrupted.h" #include "sandbox_set_as_running_user.h" +#include "sandbox_types.h" #include "scheduler_options.h" @@ -106,6 +106,31 @@ done: return local_runqueue_get_next(); } +static inline struct sandbox * +scheduler_sjf_get_next() +{ + struct sandbox *local = local_runqueue_get_next(); + uint64_t local_rem_exec = local == NULL ? UINT64_MAX : local->remaining_exec; + struct sandbox *global = NULL; + + uint64_t global_remaining_exec = global_request_scheduler_peek(); + + /* Try to pull and allocate from the global queue if earlier + * This will be placed at the head of the local runqueue */ + if (global_remaining_exec < local_rem_exec) { + if (global_request_scheduler_remove_if_earlier(&global, local_rem_exec) == 0) { + assert(global != NULL); + assert(global->remaining_exec < local_rem_exec); + sandbox_prepare_execution_environment(global); + assert(global->state == SANDBOX_INITIALIZED); + sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); + } + } + + /* Return what is at the head of the local runqueue or NULL if empty */ + return local_runqueue_get_next(); +} + static inline struct sandbox * scheduler_edf_get_next() { @@ -163,6 +188,8 @@ scheduler_get_next() return scheduler_mtdbf_get_next(); case SCHEDULER_MTDS: return scheduler_mtds_get_next(); + case SCHEDULER_SJF: + return scheduler_sjf_get_next(); case SCHEDULER_EDF: return scheduler_edf_get_next(); case SCHEDULER_FIFO: @@ -177,12 +204,13 @@ scheduler_initialize() { switch (scheduler) { case SCHEDULER_MTDBF: - // global_request_scheduler_mtdbf_initialize(); + /* TODO: loading */ break; case SCHEDULER_MTDS: global_request_scheduler_mtds_initialize(); break; case SCHEDULER_EDF: + case SCHEDULER_SJF: global_request_scheduler_minheap_initialize(); break; case SCHEDULER_FIFO: @@ -204,6 +232,7 @@ scheduler_runqueue_initialize() local_runqueue_mtds_initialize(); break; case SCHEDULER_EDF: + case SCHEDULER_SJF: local_runqueue_minheap_initialize(); break; case SCHEDULER_FIFO: @@ -222,6 +251,8 @@ scheduler_print(enum SCHEDULER variant) return "FIFO"; case SCHEDULER_EDF: return "EDF"; + case SCHEDULER_SJF: + return "SJF"; case SCHEDULER_MTDS: return "MTDS"; case SCHEDULER_MTDBF: @@ -287,6 +318,7 @@ scheduler_process_policy_specific_updates_on_interrupts(struct sandbox *interrup case SCHEDULER_FIFO: return; case SCHEDULER_EDF: + case SCHEDULER_SJF: return; case SCHEDULER_MTDS: local_timeout_queue_process_promotions(); diff --git a/runtime/include/scheduler_options.h b/runtime/include/scheduler_options.h index 930dbd6..360a714 100644 --- a/runtime/include/scheduler_options.h +++ b/runtime/include/scheduler_options.h @@ -2,10 +2,11 @@ enum SCHEDULER { - SCHEDULER_FIFO = 0, - SCHEDULER_EDF = 1, - SCHEDULER_MTDS = 2, - SCHEDULER_MTDBF = 3 + SCHEDULER_FIFO, + SCHEDULER_EDF, + SCHEDULER_SJF, + SCHEDULER_MTDS, + SCHEDULER_MTDBF }; extern enum SCHEDULER scheduler; diff --git a/runtime/include/sledge_abi_symbols.h b/runtime/include/sledge_abi_symbols.h index c7acb69..1bd6f1e 100644 --- a/runtime/include/sledge_abi_symbols.h +++ b/runtime/include/sledge_abi_symbols.h @@ -5,8 +5,8 @@ #include #include "debuglog.h" -#include "wasm_types.h" #include "sledge_abi.h" +#include "wasm_types.h" struct sledge_abi_symbols { void *handle; diff --git a/runtime/include/software_interrupt_counts.h b/runtime/include/software_interrupt_counts.h index 9daa5af..8347fd0 100644 --- a/runtime/include/software_interrupt_counts.h +++ b/runtime/include/software_interrupt_counts.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include "worker_thread.h" diff --git a/runtime/include/tcp_server.h b/runtime/include/tcp_server.h index 41d5a9a..b683068 100644 --- a/runtime/include/tcp_server.h +++ b/runtime/include/tcp_server.h @@ -3,10 +3,10 @@ #include #include #include -#include -#include #include #include +#include +#include #include #include "debuglog.h" diff --git a/runtime/include/tcp_session.h b/runtime/include/tcp_session.h index 8baab85..995d877 100644 --- a/runtime/include/tcp_session.h +++ b/runtime/include/tcp_session.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include #include @@ -9,8 +9,8 @@ #include #include "debuglog.h" -#include "panic.h" #include "likely.h" +#include "panic.h" static inline void tcp_session_close(int client_socket, struct sockaddr *client_address) @@ -21,7 +21,7 @@ tcp_session_close(int client_socket, struct sockaddr *client_address) assert(client_socket != STDERR_FILENO); if (unlikely(close(client_socket) < 0)) { - char client_address_text[INET6_ADDRSTRLEN] = { '\0' }; + char client_address_text[INET6_ADDRSTRLEN] = {'\0'}; if (unlikely(inet_ntop(AF_INET, &client_address, client_address_text, INET6_ADDRSTRLEN) == NULL)) { debuglog("Failed to log client_address: %s", strerror(errno)); } diff --git a/runtime/include/tenant_config.h b/runtime/include/tenant_config.h index d907718..15d9f44 100644 --- a/runtime/include/tenant_config.h +++ b/runtime/include/tenant_config.h @@ -45,8 +45,10 @@ tenant_config_print(struct tenant_config *config) { printf("[Tenant] Name: %s\n", config->name); printf("[Tenant] Path: %d\n", config->port); - printf("[Tenant] Replenishment Period (us): %u\n", config->replenishment_period_us); - printf("[Tenant] Max Budget (us): %u\n", config->max_budget_us); + if (scheduler == SCHEDULER_MTDS) { + printf("[Tenant] Replenishment Period (us): %u\n", config->replenishment_period_us); + printf("[Tenant] Max Budget (us): %u\n", config->max_budget_us); + } printf("[Tenant] Routes Size: %zu\n", config->routes_len); for (int i = 0; i < config->routes_len; i++) { route_config_print(&config->routes[i]); } } @@ -71,19 +73,19 @@ tenant_config_validate(struct tenant_config *config, bool *did_set) if (scheduler == SCHEDULER_MTDS) { if (did_set[tenant_config_member_replenishment_period_us] == false) { - fprintf(stderr, "replenishment-period-us field is required\n"); - return -1; + fprintf(stderr, "replenishment-period-us field is missing, so defaulting to 0\n"); + config->replenishment_period_us = 0; } if (config->replenishment_period_us > (uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX) { - fprintf(stderr, "Relative-deadline-us must be between 0 and %u, was %u\n", + fprintf(stderr, "relative-deadline-us must be between 0 and %u, was %u\n", (uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX, config->replenishment_period_us); return -1; } if (did_set[tenant_config_member_max_budget_us] == false) { - fprintf(stderr, "max-budget-us field is required\n"); - return -1; + fprintf(stderr, "max-budget-us field is missing, so defaulting to 0\n"); + config->max_budget_us = 0; } if (config->max_budget_us > (uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX) { diff --git a/runtime/include/tenant_config_parse.h b/runtime/include/tenant_config_parse.h index 14b7aef..e7cee19 100644 --- a/runtime/include/tenant_config_parse.h +++ b/runtime/include/tenant_config_parse.h @@ -9,8 +9,8 @@ #include "route_config_parse.h" #include "tenant_config.h" -static const char *tenant_config_json_keys[tenant_config_member_len] = { "name", "port", "replenishment-period-us", - "max-budget-us", "routes" }; +static const char *tenant_config_json_keys[tenant_config_member_len] = {"name", "port", "replenishment-period-us", + "max-budget-us", "routes"}; static inline int tenant_config_set_key_once(bool *did_set, enum tenant_config_member member) @@ -29,8 +29,8 @@ tenant_config_parse(struct tenant_config *config, const char *json_buf, jsmntok_ int tokens_size) { int i = tokens_base; - char key[32] = { 0 }; - bool did_set[tenant_config_member_len] = { false }; + char key[32] = {0}; + bool did_set[tenant_config_member_len] = {false}; if (!has_valid_type(tokens[i], "Anonymous Tenant Config Object", JSMN_OBJECT, json_buf)) return -1; if (!is_nonempty_object(tokens[i], "Anonymous Tenant Config Object")) return -1; diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index 423f6b6..ddd2a7e 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -3,16 +3,15 @@ #include #include -#include "admissions_info.h" #include "http.h" #include "listener_thread.h" #include "module_database.h" #include "panic.h" +#include "priority_queue.h" +#include "sandbox_functions.h" #include "scheduler_options.h" #include "tenant.h" #include "tenant_config.h" -#include "priority_queue.h" -#include "sandbox_functions.h" int tenant_database_add(struct tenant *tenant); struct tenant *tenant_database_find_by_name(char *name); @@ -30,6 +29,7 @@ tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config) case SCHEDULER_FIFO: break; case SCHEDULER_EDF: + case SCHEDULER_SJF: break; case SCHEDULER_MTDS: /* Deferable Server Initialization */ @@ -103,7 +103,7 @@ tenant_alloc(struct tenant_config *config) struct module *module = module_database_find_by_path(&tenant->module_db, config->routes[i].path); if (module == NULL) { /* Ownership of path moves here */ - module = module_alloc(config->routes[i].path); + module = module_alloc(config->routes[i].path, APP_MODULE); if (module != NULL) { module_database_add(&tenant->module_db, module); config->routes[i].path = NULL; @@ -115,8 +115,30 @@ tenant_alloc(struct tenant_config *config) assert(module != NULL); + struct module *module_proprocess = NULL; + +#ifdef EXECUTION_REGRESSION + if (config->routes[i].path_preprocess) { + module_proprocess = module_database_find_by_path(&tenant->module_db, + config->routes[i].path_preprocess); + if (module_proprocess == NULL) { + /* Ownership of path moves here */ + module_proprocess = module_alloc(config->routes[i].path_preprocess, PREPROCESS_MODULE); + if (module_proprocess != NULL) { + module_database_add(&tenant->module_db, module_proprocess); + config->routes[i].path_preprocess = NULL; + } + } else { + free(config->routes[i].path_preprocess); + config->routes[i].path_preprocess = NULL; + } + + assert(module_proprocess != NULL); + } +#endif + /* Ownership of config's route and http_resp_content_type move here */ - int rc = http_router_add_route(&tenant->router, &config->routes[i], module); + int rc = http_router_add_route(&tenant->router, &config->routes[i], module, module_proprocess); if (unlikely(rc != 0)) { panic("Tenant %s defined %lu routes, but router failed to grow beyond %lu\n", tenant->name, config->routes_len, tenant->router.capacity); @@ -160,5 +182,6 @@ get_next_timeout_of_tenant(uint64_t replenishment_period) * @param tenant * @returns 0 on success, -1 on error */ -int tenant_listen(struct tenant *tenant); -int listener_thread_register_tenant(struct tenant *tenant); +int tenant_listen(struct tenant *tenant); +int listener_thread_register_tenant(struct tenant *tenant); +void tenant_preprocess(struct http_session *session); diff --git a/runtime/include/wasm_globals.h b/runtime/include/wasm_globals.h index 6a5493b..e6fe242 100644 --- a/runtime/include/wasm_globals.h +++ b/runtime/include/wasm_globals.h @@ -85,9 +85,9 @@ wasm_globals_set_i32(struct vec_wasm_global_t *globals, uint32_t idx, int32_t va wasm_global_t *current = vec_wasm_global_t_get(globals, idx); if (unlikely(current->type != WASM_GLOBAL_TYPE_UNUSED && current->mut == false)) return -2; - int rc = vec_wasm_global_t_insert(globals, idx, - (wasm_global_t){ - .mut = is_mutable, .type = WASM_GLOBAL_TYPE_I32, .value = value }); + int rc = + vec_wasm_global_t_insert(globals, idx, + (wasm_global_t){.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I32, .value = value}); return rc; } @@ -99,8 +99,8 @@ wasm_globals_set_i64(struct vec_wasm_global_t *globals, uint32_t idx, int64_t va if (unlikely(current->type != WASM_GLOBAL_TYPE_UNUSED && current->mut == false)) return -2; // Returns -1 if idx > capacity - int rc = vec_wasm_global_t_insert(globals, idx, - (wasm_global_t){ - .mut = is_mutable, .type = WASM_GLOBAL_TYPE_I64, .value = value }); + int rc = + vec_wasm_global_t_insert(globals, idx, + (wasm_global_t){.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I64, .value = value}); return rc; } diff --git a/runtime/include/wasm_memory.h b/runtime/include/wasm_memory.h index 8be98b9..51247e8 100644 --- a/runtime/include/wasm_memory.h +++ b/runtime/include/wasm_memory.h @@ -8,8 +8,8 @@ #include #include "ps_list.h" -#include "types.h" /* PAGE_SIZE */ #include "sledge_abi.h" +#include "types.h" /* PAGE_SIZE */ #include "wasm_types.h" #define WASM_MEMORY_MAX (uint64_t) UINT32_MAX + 1 diff --git a/runtime/include/wasm_module_instance.h b/runtime/include/wasm_module_instance.h index 837ada0..c551d5e 100644 --- a/runtime/include/wasm_module_instance.h +++ b/runtime/include/wasm_module_instance.h @@ -1,7 +1,7 @@ #pragma once +#include "sledge_abi.h" #include "wasm_memory.h" #include "wasm_table.h" -#include "sledge_abi.h" /* This structure is the runtime representation of the unique state of a module instance * Currently this is not spec-compliant, as it only supports a single table and a single memory and it excludes many diff --git a/runtime/include/wasm_stack.h b/runtime/include/wasm_stack.h index 95d5ac3..a5374b7 100644 --- a/runtime/include/wasm_stack.h +++ b/runtime/include/wasm_stack.h @@ -2,9 +2,9 @@ #include #include -#include #include #include +#include #include "ps_list.h" #include "types.h" diff --git a/runtime/include/wasm_table.h b/runtime/include/wasm_table.h index a149966..fa57e27 100644 --- a/runtime/include/wasm_table.h +++ b/runtime/include/wasm_table.h @@ -109,5 +109,5 @@ wasm_table_set(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t /* TODO: atomic for multiple concurrent invocations? Issue #97 */ if (wasm_table->buffer[idx].type_id == type_id && wasm_table->buffer[idx].func_pointer == pointer) return; - wasm_table->buffer[idx] = (struct sledge_abi__wasm_table_entry){ .type_id = type_id, .func_pointer = pointer }; + wasm_table->buffer[idx] = (struct sledge_abi__wasm_table_entry){.type_id = type_id, .func_pointer = pointer}; } diff --git a/runtime/src/admissions_control.c b/runtime/src/admissions_control.c index 77d6705..5ddda8b 100644 --- a/runtime/src/admissions_control.c +++ b/runtime/src/admissions_control.c @@ -8,6 +8,8 @@ #include "panic.h" #include "runtime.h" +#ifdef ADMISSIONS_CONTROL + /* * Unitless estimate of the instantaneous fraction of system capacity required to complete all previously * admitted work. This is used to calculate free capacity as part of admissions control @@ -19,40 +21,32 @@ * success or failure) */ -#ifdef ADMISSIONS_CONTROL _Atomic uint64_t admissions_control_admitted; uint64_t admissions_control_capacity; const double admissions_control_overhead = 0.2; -#endif void admissions_control_initialize() { -#ifdef ADMISSIONS_CONTROL atomic_init(&admissions_control_admitted, 0); admissions_control_capacity = runtime_worker_threads_count * ADMISSIONS_CONTROL_GRANULARITY * ((double)1.0 - admissions_control_overhead); -#endif } void admissions_control_add(uint64_t admissions_estimate) { -#ifdef ADMISSIONS_CONTROL assert(admissions_estimate > 0); atomic_fetch_add(&admissions_control_admitted, admissions_estimate); #ifdef LOG_ADMISSIONS_CONTROL debuglog("Runtime Admitted: %lu / %lu\n", admissions_control_admitted, admissions_control_capacity); #endif - -#endif /* ADMISSIONS_CONTROL */ } void admissions_control_subtract(uint64_t admissions_estimate) { -#ifdef ADMISSIONS_CONTROL /* Assumption: Should never underflow */ if (unlikely(admissions_estimate > admissions_control_admitted)) panic("Admissions Estimate underflow\n"); @@ -61,14 +55,11 @@ admissions_control_subtract(uint64_t admissions_estimate) #ifdef LOG_ADMISSIONS_CONTROL debuglog("Runtime Admitted: %lu / %lu\n", admissions_control_admitted, admissions_control_capacity); #endif - -#endif /* ADMISSIONS_CONTROL */ } uint64_t admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline) { -#ifdef ADMISSIONS_CONTROL assert(relative_deadline != 0); uint64_t admissions_estimate = (estimated_execution * (uint64_t)ADMISSIONS_CONTROL_GRANULARITY) / relative_deadline; @@ -76,31 +67,15 @@ admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t rel panic("Ratio of Deadline to Execution time cannot exceed %d\n", ADMISSIONS_CONTROL_GRANULARITY); return admissions_estimate; -#else - return 0; -#endif -} - -uint64_t -admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us) -{ -#ifdef ADMISSIONS_CONTROL - assert(relative_deadline_us != 0); - return (uint64_t)((uint64_t)(estimated_execution_us * ADMISSIONS_CONTROL_GRANULARITY)) / relative_deadline_us; -#else - return 0; -#endif } void admissions_control_log_decision(uint64_t admissions_estimate, bool admitted) { -#ifdef ADMISSIONS_CONTROL #ifdef LOG_ADMISSIONS_CONTROL debuglog("Admitted: %lu, Capacity: %lu, Estimate: %lu, Admitted? %s\n", admissions_control_admitted, admissions_control_capacity, admissions_estimate, admitted ? "yes" : "no"); #endif /* LOG_ADMISSIONS_CONTROL */ -#endif /* ADMISSIONS_CONTROL */ } uint64_t @@ -108,7 +83,6 @@ admissions_control_decide(uint64_t admissions_estimate) { uint64_t work_admitted = 1; /* Nominal non-zero value in case admissions control is disabled */ -#ifdef ADMISSIONS_CONTROL if (unlikely(admissions_estimate == 0)) panic("Admissions estimate should never be zero"); uint64_t total_admitted = atomic_load(&admissions_control_admitted); @@ -121,7 +95,8 @@ admissions_control_decide(uint64_t admissions_estimate) admissions_control_add(admissions_estimate); work_admitted = admissions_estimate; } -#endif /* ADMISSIONS_CONTROL */ return work_admitted; } + +#endif /* ADMISSIONS_CONTROL */ \ No newline at end of file diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c deleted file mode 100644 index 540a24d..0000000 --- a/runtime/src/admissions_info.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "admissions_control.h" -#include "admissions_info.h" -#include "debuglog.h" -#include "perf_window.h" - -/** - * Initializes perf window - * @param admissions_info - */ -void -admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution, - uint64_t relative_deadline) -{ -#ifdef ADMISSIONS_CONTROL - assert(relative_deadline > 0); - assert(expected_execution > 0); - admissions_info->relative_deadline = relative_deadline; - admissions_info->estimate = admissions_control_calculate_estimate(expected_execution, relative_deadline); - debuglog("Initial Estimate: %lu\n", admissions_info->estimate); - assert(admissions_info != NULL); - - perf_window_initialize(&admissions_info->perf_window); - - if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid admissions percentile"); - admissions_info->percentile = percentile; - - admissions_info->control_index = PERF_WINDOW_CAPACITY * percentile / 100; -#ifdef LOG_ADMISSIONS_CONTROL - debuglog("Percentile: %u\n", admissions_info->percentile); - debuglog("Control Index: %d\n", admissions_info->control_index); -#endif -#endif -} - - -/* - * Adds an execution value to the perf window and calculates and caches and updated estimate - * @param admissions_info - * @param execution_duration - */ -void -admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration) -{ -#ifdef ADMISSIONS_CONTROL - struct perf_window *perf_window = &admissions_info->perf_window; - - lock_node_t node = {}; - lock_lock(&perf_window->lock, &node); - perf_window_add(perf_window, execution_duration); - uint64_t estimated_execution = perf_window_get_percentile(perf_window, admissions_info->percentile, - admissions_info->control_index); - admissions_info->estimate = admissions_control_calculate_estimate(estimated_execution, - admissions_info->relative_deadline); - lock_unlock(&perf_window->lock, &node); -#endif -} diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index feaf670..3427e0c 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -1,15 +1,14 @@ -#include #include #include #include "current_sandbox.h" #include "sandbox_functions.h" #include "sandbox_set_as_asleep.h" +#include "sandbox_set_as_complete.h" #include "sandbox_set_as_error.h" #include "sandbox_set_as_returned.h" -#include "sandbox_set_as_complete.h" -#include "sandbox_set_as_running_user.h" #include "sandbox_set_as_running_sys.h" +#include "sandbox_set_as_running_user.h" #include "scheduler.h" #include "software_interrupt.h" #include "wasi.h" @@ -194,5 +193,5 @@ current_sandbox_start(void) current_sandbox_wasm_trap_handler(rc); } - current_sandbox_fini(); + if (sandbox->module->type == APP_MODULE) current_sandbox_fini(); } diff --git a/runtime/src/current_wasm_module_instance.c b/runtime/src/current_wasm_module_instance.c index 02e64db..5dc2514 100644 --- a/runtime/src/current_wasm_module_instance.c +++ b/runtime/src/current_wasm_module_instance.c @@ -1,20 +1,20 @@ #include #include "current_sandbox.h" -#include "wasm_module_instance.h" #include "wasm_memory.h" +#include "wasm_module_instance.h" thread_local struct wasm_module_instance sledge_abi__current_wasm_module_instance = { - .abi.memory = - (struct sledge_abi__wasm_memory){ - .size = 0, - .max = 0, - .capacity = 0, - .buffer = NULL, - }, - .abi.table = NULL, - .abi.wasmg_0 = 0xDEADBEEF, - .wasi_context = NULL, + .abi.memory = + (struct sledge_abi__wasm_memory){ + .size = 0, + .max = 0, + .capacity = 0, + .buffer = NULL, + }, + .abi.table = NULL, + .abi.wasmg_0 = 0xDEADBEEF, + .wasi_context = NULL, }; void diff --git a/runtime/src/execution_histogram.c b/runtime/src/execution_histogram.c new file mode 100644 index 0000000..e7f5936 --- /dev/null +++ b/runtime/src/execution_histogram.c @@ -0,0 +1,50 @@ +#ifdef EXECUTION_HISTOGRAM + +#include "execution_histogram.h" +#include "debuglog.h" +#include "perf_window.h" + +/** + * Initializes execution_histogram and its perf window + * @param execution_histogram + */ +void +execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile, + uint64_t expected_execution) +{ + assert(expected_execution > 0); + execution_histogram->estimated_execution = expected_execution; + + assert(execution_histogram != NULL); + perf_window_initialize(&execution_histogram->perf_window); + + if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid percentile"); + execution_histogram->percentile = percentile; + execution_histogram->control_index = PERF_WINDOW_CAPACITY * percentile / 100; +#ifdef LOG_EXECUTION_HISTOGRAM + debuglog("Percentile: %u\n", execution_histogram->percentile); + debuglog("Control Index: %d\n", execution_histogram->control_index); +#endif +} + + +/* + * Adds an execution value to the perf window + * @param execution_histogram + * @param execution_duration + */ +void +execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration) +{ + struct perf_window *perf_window = &execution_histogram->perf_window; + + lock_node_t node = {}; + lock_lock(&perf_window->lock, &node); + perf_window_add(perf_window, execution_duration); + uint64_t estimated_execution = perf_window_get_percentile(perf_window, execution_histogram->percentile, + execution_histogram->control_index); + execution_histogram->estimated_execution = estimated_execution; + lock_unlock(&perf_window->lock, &node); +} + +#endif \ No newline at end of file diff --git a/runtime/src/global_request_scheduler.c b/runtime/src/global_request_scheduler.c index 05ec3dd..31dab21 100644 --- a/runtime/src/global_request_scheduler.c +++ b/runtime/src/global_request_scheduler.c @@ -24,9 +24,9 @@ uninitialized_peek() /* The global of our polymorphic interface */ -static struct global_request_scheduler_config global_request_scheduler = { .add_fn = uninitialized_add, - .remove_fn = uninitialized_remove, - .peek_fn = uninitialized_peek }; +static struct global_request_scheduler_config global_request_scheduler = {.add_fn = uninitialized_add, + .remove_fn = uninitialized_remove, + .peek_fn = uninitialized_peek}; /** * Initializes the polymorphic interface with a concrete implementation diff --git a/runtime/src/global_request_scheduler_deque.c b/runtime/src/global_request_scheduler_deque.c index af151b4..1f6a242 100644 --- a/runtime/src/global_request_scheduler_deque.c +++ b/runtime/src/global_request_scheduler_deque.c @@ -1,8 +1,8 @@ -#include "global_request_scheduler.h" #include "global_request_scheduler_deque.h" +#include "global_request_scheduler.h" #include "runtime.h" -#define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 19) +#define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 12) static struct deque_sandbox *global_request_scheduler_deque; @@ -57,11 +57,10 @@ global_request_scheduler_deque_initialize() deque_init_sandbox(global_request_scheduler_deque, GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY); /* Register Function Pointers for Abstract Scheduling API */ - struct global_request_scheduler_config config = { - .add_fn = global_request_scheduler_deque_add, - .remove_fn = global_request_scheduler_deque_remove, - .remove_if_earlier_fn = global_request_scheduler_deque_remove_if_earlier - }; + struct global_request_scheduler_config config = {.add_fn = global_request_scheduler_deque_add, + .remove_fn = global_request_scheduler_deque_remove, + .remove_if_earlier_fn = + global_request_scheduler_deque_remove_if_earlier}; global_request_scheduler_initialize(&config); } diff --git a/runtime/src/global_request_scheduler_minheap.c b/runtime/src/global_request_scheduler_minheap.c index cee34f9..5f0b894 100644 --- a/runtime/src/global_request_scheduler_minheap.c +++ b/runtime/src/global_request_scheduler_minheap.c @@ -43,10 +43,10 @@ global_request_scheduler_minheap_remove(struct sandbox **removed_sandbox) * @returns 0 if successful, -ENOENT if empty or if request isn't earlier than target_deadline */ int -global_request_scheduler_minheap_remove_if_earlier(struct sandbox **removed_sandbox, uint64_t target_deadline) +global_request_scheduler_minheap_remove_if_earlier(struct sandbox **removed_sandbox, uint64_t target_latest_start) { return priority_queue_dequeue_if_earlier(global_request_scheduler_minheap, (void **)removed_sandbox, - target_deadline); + target_latest_start); } /** @@ -65,6 +65,8 @@ uint64_t sandbox_get_priority_fn(void *element) { struct sandbox *sandbox = (struct sandbox *)element; + if (scheduler == SCHEDULER_SJF) return sandbox->remaining_exec; + assert(scheduler == SCHEDULER_EDF); return sandbox->absolute_deadline; }; @@ -77,12 +79,11 @@ global_request_scheduler_minheap_initialize() { global_request_scheduler_minheap = priority_queue_initialize(4096, true, sandbox_get_priority_fn); - struct global_request_scheduler_config config = { - .add_fn = global_request_scheduler_minheap_add, - .remove_fn = global_request_scheduler_minheap_remove, - .remove_if_earlier_fn = global_request_scheduler_minheap_remove_if_earlier, - .peek_fn = global_request_scheduler_minheap_peek - }; + struct global_request_scheduler_config config = {.add_fn = global_request_scheduler_minheap_add, + .remove_fn = global_request_scheduler_minheap_remove, + .remove_if_earlier_fn = + global_request_scheduler_minheap_remove_if_earlier, + .peek_fn = global_request_scheduler_minheap_peek}; global_request_scheduler_initialize(&config); } diff --git a/runtime/src/global_request_scheduler_mtds.c b/runtime/src/global_request_scheduler_mtds.c index db755ed..5d4c1b7 100644 --- a/runtime/src/global_request_scheduler_mtds.c +++ b/runtime/src/global_request_scheduler_mtds.c @@ -230,12 +230,11 @@ global_request_scheduler_mtds_initialize() lock_init(&global_lock); - struct global_request_scheduler_config config = { - .add_fn = global_request_scheduler_mtds_add, - .remove_fn = global_request_scheduler_mtds_remove, - .remove_if_earlier_fn = global_request_scheduler_mtds_remove_if_earlier, - .peek_fn = global_request_scheduler_mtds_peek - }; + struct global_request_scheduler_config config = {.add_fn = global_request_scheduler_mtds_add, + .remove_fn = global_request_scheduler_mtds_remove, + .remove_if_earlier_fn = + global_request_scheduler_mtds_remove_if_earlier, + .peek_fn = global_request_scheduler_mtds_peek}; global_request_scheduler_initialize(&config); } diff --git a/runtime/src/http_parser_settings.c b/runtime/src/http_parser_settings.c index 1c74f8a..50f1c11 100644 --- a/runtime/src/http_parser_settings.c +++ b/runtime/src/http_parser_settings.c @@ -3,8 +3,8 @@ #include "debuglog.h" #include "http.h" -#include "http_request.h" #include "http_parser_settings.h" +#include "http_request.h" #include "likely.h" http_parser_settings runtime_http_parser_settings; @@ -211,7 +211,7 @@ http_parser_settings_on_header_end(http_parser *parser) } } -const char *http_methods[] = { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" }; +const char *http_methods[] = {"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"}; /** * http-parser callback called for HTTP Bodies diff --git a/runtime/src/http_session_perf_log.c b/runtime/src/http_session_perf_log.c index cbc4155..e458d1c 100644 --- a/runtime/src/http_session_perf_log.c +++ b/runtime/src/http_session_perf_log.c @@ -18,8 +18,8 @@ http_session_perf_log_print_entry(struct http_session *http_session) const uint64_t sent_duration = http_session->response_sent_timestamp - http_session->response_takeoff_timestamp; const uint64_t total_lifetime = http_session->response_sent_timestamp - http_session->request_arrival_timestamp; - fprintf(http_session_perf_log, "%s,%s,%u,%lu,%lu,%lu,%lu,%lu,%u\n", http_session->tenant->name, + fprintf(http_session_perf_log, "%s,%s,%u,%lu,%lu,%lu,%lu,%lu,%lu,%u\n", http_session->tenant->name, http_session->http_request.full_url, http_session->state, http_session->response_header_written, http_session->response_body_written, receive_duration, sent_duration, total_lifetime, - runtime_processor_speed_MHz); + http_session->preprocessing_duration, runtime_processor_speed_MHz); } diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 7856016..4af8802 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -2,16 +2,18 @@ #include #include "arch/getcycles.h" +#include "execution_regression.h" #include "global_request_scheduler.h" +#include "http_session_perf_log.h" #include "listener_thread.h" #include "metrics_server.h" #include "module.h" #include "runtime.h" #include "sandbox_functions.h" +#include "sandbox_perf_log.h" #include "tcp_session.h" #include "tenant.h" #include "tenant_functions.h" -#include "http_session_perf_log.h" static void listener_thread_unregister_http_session(struct http_session *http); static void panic_on_epoll_error(struct epoll_event *evt); @@ -193,11 +195,34 @@ on_client_request_receiving(struct http_session *session) { /* Read HTTP request */ int rc = http_session_receive_request(session, (void_star_cb)listener_thread_register_http_session); - if (likely(rc == 0)) { + + /* Check if the route is accurate only when the URL is downloaded. Stop downloading if inaccurate. */ + if (session->route == NULL && strlen(session->http_request.full_url) > 0) { + struct route *route = http_router_match_route(&session->tenant->router, session->http_request.full_url); + if (route == NULL) { + debuglog("Did not match any routes\n"); + session->state = HTTP_SESSION_EXECUTION_COMPLETE; + http_session_set_response_header(session, 404); + on_client_response_header_sending(session); + return; + } + + session->route = route; + } + + if (rc == 0) { +#ifdef EXECUTION_REGRESSION + if (!session->did_preprocessing) tenant_preprocess(session); +#endif on_client_request_received(session); return; - } else if (unlikely(rc == -EAGAIN)) { - /* session blocked and registered to epoll so continue to next handle */ + } else if (rc == -EAGAIN) { + /* session blocked and registered to epoll, so continue to next handle */ +#ifdef EXECUTION_REGRESSION + /* try tenant preprocessing if min 4k Bytes received */ + if (!session->did_preprocessing && session->http_request.body_length_read > 4096) + tenant_preprocess(session); +#endif return; } else if (rc < 0) { debuglog("Failed to receive or parse request\n"); @@ -215,30 +240,29 @@ on_client_request_received(struct http_session *session) { assert(session->state == HTTP_SESSION_RECEIVED_REQUEST); session->request_downloaded_timestamp = __getcycles(); + struct route *route = session->route; + uint64_t estimated_execution = route->execution_histogram.estimated_execution; + uint64_t work_admitted = 1; - struct route *route = http_router_match_route(&session->tenant->router, session->http_request.full_url); - if (route == NULL) { - debuglog("Did not match any routes\n"); - session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 404); - on_client_response_header_sending(session); - return; - } - - session->route = route; +#ifdef EXECUTION_REGRESSION + estimated_execution = get_regression_prediction(session); +#endif +#ifdef ADMISSIONS_CONTROL /* * Perform admissions control. * If 0, workload was rejected, so close with 429 "Too Many Requests" and continue - * TODO: Consider providing a Retry-After header */ - uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); + uint64_t admissions_estimate = admissions_control_calculate_estimate(estimated_execution, + route->relative_deadline); + work_admitted = admissions_control_decide(admissions_estimate); if (work_admitted == 0) { session->state = HTTP_SESSION_EXECUTION_COMPLETE; http_session_set_response_header(session, 429); on_client_response_header_sending(session); return; } +#endif /* Allocate a Sandbox */ session->state = HTTP_SESSION_EXECUTING; @@ -251,9 +275,15 @@ on_client_request_received(struct http_session *session) return; } + sandbox->remaining_exec = estimated_execution; + /* If the global request scheduler is full, return a 429 to the client */ if (unlikely(global_request_scheduler_add(sandbox) == NULL)) { - debuglog("Failed to add sandbox to global queue\n"); + // debuglog("Failed to add sandbox to global queue\n"); + sandbox->response_code = 4290; + sandbox->state = SANDBOX_ERROR; + sandbox_perf_log_print_entry(sandbox); + sandbox->http = NULL; sandbox_free(sandbox); session->state = HTTP_SESSION_EXECUTION_COMPLETE; http_session_set_response_header(session, 429); diff --git a/runtime/src/local_runqueue_list.c b/runtime/src/local_runqueue_list.c index 20e19c7..5ee1a68 100644 --- a/runtime/src/local_runqueue_list.c +++ b/runtime/src/local_runqueue_list.c @@ -2,8 +2,8 @@ #include "current_sandbox.h" #include "global_request_scheduler.h" -#include "local_runqueue_list.h" #include "local_runqueue.h" +#include "local_runqueue_list.h" #include "sandbox_functions.h" thread_local static struct ps_list_head local_runqueue_list; @@ -81,9 +81,9 @@ local_runqueue_list_initialize() ps_list_head_init(&local_runqueue_list); /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_list_append, - .is_empty_fn = local_runqueue_list_is_empty, - .delete_fn = local_runqueue_list_remove, - .get_next_fn = local_runqueue_list_get_next }; + struct local_runqueue_config config = {.add_fn = local_runqueue_list_append, + .is_empty_fn = local_runqueue_list_is_empty, + .delete_fn = local_runqueue_list_remove, + .get_next_fn = local_runqueue_list_get_next}; local_runqueue_initialize(&config); }; diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index d4d92a0..7d4c312 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -9,8 +9,8 @@ #include "local_runqueue_minheap.h" #include "panic.h" #include "priority_queue.h" -#include "sandbox_functions.h" #include "runtime.h" +#include "sandbox_functions.h" thread_local static struct priority_queue *local_runqueue_minheap; @@ -84,10 +84,10 @@ local_runqueue_minheap_initialize() local_runqueue_minheap = priority_queue_initialize(RUNTIME_RUNQUEUE_SIZE, false, sandbox_get_priority); /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add, - .is_empty_fn = local_runqueue_minheap_is_empty, - .delete_fn = local_runqueue_minheap_delete, - .get_next_fn = local_runqueue_minheap_get_next }; + struct local_runqueue_config config = {.add_fn = local_runqueue_minheap_add, + .is_empty_fn = local_runqueue_minheap_is_empty, + .delete_fn = local_runqueue_minheap_delete, + .get_next_fn = local_runqueue_minheap_get_next}; local_runqueue_initialize(&config); } diff --git a/runtime/src/local_runqueue_mtds.c b/runtime/src/local_runqueue_mtds.c index 6f7c0ca..318339c 100644 --- a/runtime/src/local_runqueue_mtds.c +++ b/runtime/src/local_runqueue_mtds.c @@ -9,9 +9,9 @@ #include "local_runqueue_mtds.h" #include "panic.h" #include "priority_queue.h" +#include "runtime.h" #include "sandbox_functions.h" #include "tenant_functions.h" -#include "runtime.h" thread_local static struct priority_queue *local_runqueue_mtds_guaranteed; thread_local static struct priority_queue *local_runqueue_mtds_default; @@ -172,10 +172,10 @@ local_runqueue_mtds_initialize() perworker_tenant_get_priority); /* Register Function Pointers for Abstract Scheduling API */ - struct local_runqueue_config config = { .add_fn = local_runqueue_mtds_add, - .is_empty_fn = local_runqueue_mtds_is_empty, - .delete_fn = local_runqueue_mtds_delete, - .get_next_fn = local_runqueue_mtds_get_next }; + struct local_runqueue_config config = {.add_fn = local_runqueue_mtds_add, + .is_empty_fn = local_runqueue_mtds_is_empty, + .delete_fn = local_runqueue_mtds_delete, + .get_next_fn = local_runqueue_mtds_get_next}; local_runqueue_initialize(&config); } diff --git a/runtime/src/main.c b/runtime/src/main.c index d918abe..ada0cc9 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -2,25 +2,25 @@ #include #include #include -#include -#include #include +#include +#include #include #include #include #include #ifdef LOG_TO_FILE -#include -#include #include +#include +#include #endif -#include "json_parse.h" -#include "pretty_print.h" #include "debuglog.h" +#include "json_parse.h" #include "listener_thread.h" #include "panic.h" +#include "pretty_print.h" #include "runtime.h" #include "sandbox_perf_log.h" #include "sandbox_types.h" @@ -40,7 +40,7 @@ enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_B bool runtime_preemption_enabled = true; bool runtime_worker_spinloop_pause_enabled = false; -uint32_t runtime_quantum_us = 5000; /* 5ms */ +uint32_t runtime_quantum_us = 1000; /* 1ms */ uint64_t runtime_boot_timestamp; pid_t runtime_pid = 0; @@ -105,7 +105,7 @@ runtime_allocate_available_cores() static inline void runtime_get_processor_speed_MHz(void) { - char *proc_mhz_raw = getenv("PROC_MHZ"); + char *proc_mhz_raw = getenv("SLEDGE_PROC_MHZ"); FILE *cmd = NULL; if (proc_mhz_raw != NULL) { @@ -116,7 +116,7 @@ runtime_get_processor_speed_MHz(void) usleep(200000); /* wait a bit for the workers to launch for more accuracy */ /* Get the average of the cpufreqs only for worker cores (no event core and reserved) */ - char command[128] = { 0 }; + char command[128] = {0}; sprintf(command, "grep '^cpu MHz' /proc/cpuinfo | sed -n '%u,%up' | \ awk '{ total += $4; count++ } END { print total/count }'", runtime_first_worker_processor + 1, @@ -127,6 +127,7 @@ runtime_get_processor_speed_MHz(void) char buff[16]; size_t n = fread(buff, 1, sizeof(buff) - 1, cmd); buff[n] = '\0'; + pclose(cmd); float processor_speed_MHz; n = sscanf(buff, "%f", &processor_speed_MHz); @@ -139,7 +140,6 @@ runtime_get_processor_speed_MHz(void) pretty_print_key_value("Worker CPU Freq", "%u MHz\n", runtime_processor_speed_MHz); done: - pclose(cmd); return; err: goto done; @@ -208,10 +208,12 @@ runtime_configure() scheduler = SCHEDULER_MTDS; } else if (strcmp(scheduler_policy, "EDF") == 0) { scheduler = SCHEDULER_EDF; + } else if (strcmp(scheduler_policy, "SJF") == 0) { + scheduler = SCHEDULER_SJF; } else if (strcmp(scheduler_policy, "FIFO") == 0) { scheduler = SCHEDULER_FIFO; } else { - panic("Invalid scheduler policy: %s. Must be {MTDBF|MTDS|EDF|FIFO}\n", scheduler_policy); + panic("Invalid scheduler policy: %s. Must be {MTDBF|MTDS|EDF|SJF|FIFO}\n", scheduler_policy); } pretty_print_key_value("Scheduler Policy", "%s\n", scheduler_print(scheduler)); @@ -284,6 +286,18 @@ log_compiletime_config() pretty_print_key_disabled("Admissions Control"); #endif +#ifdef EXECUTION_HISTOGRAM + pretty_print_key_enabled("Execution Histogram"); +#else + pretty_print_key_disabled("Execution Histogram"); +#endif + +#ifdef EXECUTION_REGRESSION + pretty_print_key_enabled("Execution Regression"); +#else + pretty_print_key_disabled("Execution Regression"); +#endif + /* Debugging Flags */ printf("Static Compiler Flags (Debugging):\n"); diff --git a/runtime/src/metrics_server.c b/runtime/src/metrics_server.c index 999772f..e3e1284 100644 --- a/runtime/src/metrics_server.c +++ b/runtime/src/metrics_server.c @@ -11,8 +11,8 @@ #include "metrics_server.h" #include "proc_stat.h" #include "runtime.h" -#include "sandbox_total.h" #include "sandbox_state.h" +#include "sandbox_total.h" #include "tcp_server.h" /* We run threads on the "reserved OS core" using blocking semantics */ diff --git a/runtime/src/module.c b/runtime/src/module.c index 093106f..577e305 100644 --- a/runtime/src/module.c +++ b/runtime/src/module.c @@ -44,7 +44,8 @@ module_init(struct module *module, char *path) rc = sledge_abi_symbols_init(&module->abi, path); if (rc != 0) goto err; - module->pools = calloc(runtime_worker_threads_count, sizeof(struct module_pool)); + module->pools = calloc((module->type == APP_MODULE ? runtime_worker_threads_count : 1), + sizeof(struct module_pool)); module->path = path; @@ -106,7 +107,7 @@ module_free(struct module *module) */ struct module * -module_alloc(char *path) +module_alloc(char *path, enum module_type type) { size_t alignment = (size_t)CACHE_PAD; size_t size_to_alloc = (size_t)round_to_cache_pad(sizeof(struct module)); @@ -120,6 +121,7 @@ module_alloc(char *path) }; memset(module, 0, size_to_alloc); + module->type = type; int rc = module_init(module, path); if (rc < 0) goto init_err; diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index e2c7918..4acc18c 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -1,14 +1,13 @@ #include #include -#include +#include #include +#include #include #include #include #include #include -#include -#include #include "admissions_control.h" #include "arch/context.h" @@ -19,10 +18,10 @@ #include "listener_thread.h" #include "module.h" #include "runtime.h" +#include "sandbox_perf_log.h" #include "sandbox_total.h" #include "scheduler.h" #include "software_interrupt.h" -#include "sandbox_perf_log.h" /*************************** * Shared Process State * @@ -63,8 +62,8 @@ runtime_set_resource_limits_to_max() char lim[uint64_t_max_digits + 1]; char max[uint64_t_max_digits + 1]; - uint64_t resources[] = { RLIMIT_DATA, RLIMIT_NOFILE }; - char *resource_names[] = { "RLIMIT_DATA", "RLIMIT_NOFILE" }; + uint64_t resources[] = {RLIMIT_DATA, RLIMIT_NOFILE}; + char *resource_names[] = {"RLIMIT_DATA", "RLIMIT_NOFILE"}; for (int i = 0; i < sizeof(resources) / sizeof(resources[0]); i++) { int resource = resources[i]; @@ -118,7 +117,11 @@ runtime_initialize(void) signal(SIGQUIT, runtime_cleanup); http_parser_settings_initialize(); + +#ifdef ADMISSIONS_CONTROL + /* Admissions Control Setup */ admissions_control_initialize(); +#endif } static void diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 48b74fc..6c9cbe1 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -8,9 +8,9 @@ #include "pool.h" #include "runtime.h" #include "sandbox_functions.h" +#include "sandbox_set_as_allocated.h" #include "sandbox_set_as_error.h" #include "sandbox_set_as_initialized.h" -#include "sandbox_set_as_allocated.h" #include "sandbox_total.h" #include "wasm_memory.h" #include "wasm_stack.h" @@ -154,6 +154,7 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session sandbox->route = route; sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline; + sandbox->payload_size = session->http_request.body_length; /* * Admissions Control State diff --git a/runtime/src/sandbox_state.c b/runtime/src/sandbox_state.c index ab0eda5..2b756d8 100644 --- a/runtime/src/sandbox_state.c +++ b/runtime/src/sandbox_state.c @@ -9,19 +9,18 @@ const char *sandbox_state_labels[SANDBOX_STATE_COUNT] = { - [SANDBOX_UNINITIALIZED] = "Uninitialized", - [SANDBOX_ALLOCATED] = "Allocated", - [SANDBOX_INITIALIZED] = "Initialized", - [SANDBOX_RUNNABLE] = "Runnable", - [SANDBOX_INTERRUPTED] = "Interrupted", - [SANDBOX_PREEMPTED] = "Preempted", - [SANDBOX_RUNNING_SYS] = "Running Sys", - [SANDBOX_RUNNING_USER] = "Running User", - [SANDBOX_ASLEEP] = "Asleep", - [SANDBOX_RETURNED] = "Returned", - [SANDBOX_COMPLETE] = "Complete", - [SANDBOX_ERROR] = "Error" -}; + [SANDBOX_UNINITIALIZED] = "Uninitialized", + [SANDBOX_ALLOCATED] = "Allocated", + [SANDBOX_INITIALIZED] = "Initialized", + [SANDBOX_RUNNABLE] = "Runnable", + [SANDBOX_INTERRUPTED] = "Interrupted", + [SANDBOX_PREEMPTED] = "Preempted", + [SANDBOX_RUNNING_SYS] = "Running Sys", + [SANDBOX_RUNNING_USER] = "Running User", + [SANDBOX_ASLEEP] = "Asleep", + [SANDBOX_RETURNED] = "Returned", + [SANDBOX_COMPLETE] = "Complete", + [SANDBOX_ERROR] = "Error"}; #ifdef SANDBOX_STATE_TOTALS _Atomic uint32_t sandbox_state_totals[SANDBOX_STATE_COUNT]; diff --git a/runtime/src/sandbox_state_transition.c b/runtime/src/sandbox_state_transition.c index 8664409..d50bb24 100644 --- a/runtime/src/sandbox_state_transition.c +++ b/runtime/src/sandbox_state_transition.c @@ -9,33 +9,31 @@ sandbox_state_transition_hook_default(struct sandbox *sandbox) /* Called while nonpreemptable */ sandbox_state_transition_hook_t sandbox_state_transition_to_hooks[SANDBOX_STATE_COUNT] = { - [SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default, - [SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default, - [SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default, - [SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default, - [SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default, - [SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default, - [SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default, - [SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default, - [SANDBOX_ASLEEP] = sandbox_state_transition_hook_default, - [SANDBOX_RETURNED] = sandbox_state_transition_hook_default, - [SANDBOX_COMPLETE] = sandbox_state_transition_hook_default, - [SANDBOX_ERROR] = sandbox_state_transition_hook_default -}; + [SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default, + [SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default, + [SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default, + [SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default, + [SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default, + [SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default, + [SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default, + [SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default, + [SANDBOX_ASLEEP] = sandbox_state_transition_hook_default, + [SANDBOX_RETURNED] = sandbox_state_transition_hook_default, + [SANDBOX_COMPLETE] = sandbox_state_transition_hook_default, + [SANDBOX_ERROR] = sandbox_state_transition_hook_default}; /* Called while nonpreemptable */ sandbox_state_transition_hook_t sandbox_state_transition_from_hooks[SANDBOX_STATE_COUNT] = { - [SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default, - [SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default, - [SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default, - [SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default, - [SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default, - [SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default, - [SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default, - [SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default, - [SANDBOX_ASLEEP] = sandbox_state_transition_hook_default, - [SANDBOX_RETURNED] = sandbox_state_transition_hook_default, - [SANDBOX_COMPLETE] = sandbox_state_transition_hook_default, - [SANDBOX_ERROR] = sandbox_state_transition_hook_default -}; + [SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default, + [SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default, + [SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default, + [SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default, + [SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default, + [SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default, + [SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default, + [SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default, + [SANDBOX_ASLEEP] = sandbox_state_transition_hook_default, + [SANDBOX_RETURNED] = sandbox_state_transition_hook_default, + [SANDBOX_COMPLETE] = sandbox_state_transition_hook_default, + [SANDBOX_ERROR] = sandbox_state_transition_hook_default}; diff --git a/runtime/src/sledge_abi.c b/runtime/src/sledge_abi.c index 6d1424a..63a1fe8 100644 --- a/runtime/src/sledge_abi.c +++ b/runtime/src/sledge_abi.c @@ -1,11 +1,11 @@ +#include "sledge_abi.h" #include "current_sandbox.h" #include "map.h" #include "sandbox_set_as_running_sys.h" #include "sandbox_set_as_running_user.h" -#include "sledge_abi.h" -#include "wasm_memory.h" #include "wasi.h" #include "wasi_serdes.h" +#include "wasm_memory.h" EXPORT void sledge_abi__wasm_trap_raise(enum sledge_abi__wasm_trap trapno) diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index e263900..14c1ab1 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -1,14 +1,14 @@ #include #include #include -#include -#include #include #include #include +#include +#include #include -#include #include +#include #include "arch/context.h" #include "current_sandbox.h" @@ -18,8 +18,8 @@ #include "module.h" #include "panic.h" #include "runtime.h" -#include "sandbox_set_as_running_user.h" #include "sandbox_set_as_interrupted.h" +#include "sandbox_set_as_running_user.h" #include "sandbox_types.h" #include "scheduler.h" #include "software_interrupt.h" @@ -269,7 +269,7 @@ software_interrupt_initialize(void) sigaddset(&signal_action.sa_mask, SIGFPE); sigaddset(&signal_action.sa_mask, SIGSEGV); - const int supported_signals[] = { SIGALRM, SIGUSR1, SIGFPE, SIGSEGV }; + const int supported_signals[] = {SIGALRM, SIGUSR1, SIGFPE, SIGSEGV}; const size_t supported_signals_len = 4; for (int i = 0; i < supported_signals_len; i++) { diff --git a/runtime/src/tenant.c b/runtime/src/tenant.c index b2064da..98e48cd 100644 --- a/runtime/src/tenant.c +++ b/runtime/src/tenant.c @@ -1,4 +1,5 @@ #include "tenant.h" +#include "current_sandbox.h" #include "tenant_functions.h" /** @@ -23,3 +24,50 @@ err: rc = -1; goto done; } + +#ifdef EXECUTION_REGRESSION +void +tenant_preprocess(struct http_session *session) +{ + /* No tenant preprocessing if the wasm module not provided by the tenant */ + if (session->route->module_proprocess == NULL) goto done; + const uint64_t start = __getcycles(); + + /* Tenant Pre-processing - Extract other useful parameters */ + struct sandbox *pre_sandbox = sandbox_alloc(session->route->module_proprocess, session, session->route, + session->tenant, 1); + if (sandbox_prepare_execution_environment(pre_sandbox)) panic("pre_sandbox environment setup failed"); + pre_sandbox->state = SANDBOX_RUNNING_SYS; + + assert(current_sandbox_get() == NULL); + current_sandbox_set(pre_sandbox); + current_sandbox_start(); + auto_buf_flush(&session->response_body); + + char *endptr; + long num = strtol(session->response_body.data, &endptr, 10); + if (endptr == session->response_body.data) { + printf("No digits were found\n"); + } else if (*endptr != '\0' && *endptr != '\n') { + printf("Further characters after number: %s\n", endptr); + } else if ((errno == ERANGE && (num == LONG_MAX || num == LONG_MIN)) || (errno != 0 && num == 0)) { + perror("strtol"); + } else { + session->regression_param = num; + } + + session->http_request.cursor = 0; + pre_sandbox->http = NULL; + pre_sandbox->state = SANDBOX_COMPLETE; + auto_buf_deinit(&session->response_body); + current_sandbox_set(NULL); + sandbox_free_linear_memory(pre_sandbox); + sandbox_free(pre_sandbox); + + const uint64_t end = __getcycles(); + session->preprocessing_duration = end - start; + +done: + session->did_preprocessing = true; +} +#endif diff --git a/runtime/src/tenant_database.c b/runtime/src/tenant_database.c index db90980..2c23671 100644 --- a/runtime/src/tenant_database.c +++ b/runtime/src/tenant_database.c @@ -1,14 +1,14 @@ #include +#include "panic.h" #include "runtime.h" #include "tenant.h" -#include "panic.h" /******************* * Tenant Database * ******************/ -struct tenant *tenant_database[RUNTIME_MAX_TENANT_COUNT] = { NULL }; +struct tenant *tenant_database[RUNTIME_MAX_TENANT_COUNT] = {NULL}; size_t tenant_database_count = 0; /** diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 0b8d86f..ae993ec 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -1,8 +1,8 @@ #include #include #include -#include #include +#include #include #include @@ -12,11 +12,11 @@ #include "local_runqueue_list.h" #include "local_runqueue_minheap.h" #include "panic.h" +#include "priority_queue.h" #include "runtime.h" #include "scheduler.h" -#include "worker_thread.h" #include "tenant_functions.h" -#include "priority_queue.h" +#include "worker_thread.h" /*************************** * Worker Thread State * diff --git a/tests/CMSIS_5_NN/imageclassification/run.sh b/tests/CMSIS_5_NN/imageclassification/run.sh index fd07a60..286c11b 100755 --- a/tests/CMSIS_5_NN/imageclassification/run.sh +++ b/tests/CMSIS_5_NN/imageclassification/run.sh @@ -63,7 +63,7 @@ run_perf_tests() { else image=$same_image fi - hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -D "${image}" "http://${hostname}:10000${route[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & + hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -D "${image}" "http://${hostname}:10000${route[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & done pids=$(pgrep hey | tr '\n' ' ') [[ -n $pids ]] && wait -f $pids diff --git a/tests/CMSIS_5_NN/imageclassification/spec.json b/tests/CMSIS_5_NN/imageclassification/spec.json index 4162968..36d7994 100644 --- a/tests/CMSIS_5_NN/imageclassification/spec.json +++ b/tests/CMSIS_5_NN/imageclassification/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/rand", diff --git a/tests/TinyEKF/by_iteration/run.sh b/tests/TinyEKF/by_iteration/run.sh index dc52dad..c08d1b4 100755 --- a/tests/TinyEKF/by_iteration/run.sh +++ b/tests/TinyEKF/by_iteration/run.sh @@ -68,7 +68,7 @@ run_perf_tests() { done ((batch_id++)) - hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -D "./${workload}.dat" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" & + hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -D "./${workload}.dat" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" & done pids=$(pgrep hey | tr '\n' ' ') [[ -n $pids ]] && wait -f $pids diff --git a/tests/TinyEKF/by_iteration/spec.json b/tests/TinyEKF/by_iteration/spec.json index 0908723..5daa065 100644 --- a/tests/TinyEKF/by_iteration/spec.json +++ b/tests/TinyEKF/by_iteration/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/ekf_first_iter", diff --git a/tests/TinyEKF/one_iteration/spec.json b/tests/TinyEKF/one_iteration/spec.json index 4530a41..ce5ebef 100644 --- a/tests/TinyEKF/one_iteration/spec.json +++ b/tests/TinyEKF/one_iteration/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/ekf", diff --git a/tests/bash_libraries/experiment_globals.sh b/tests/bash_libraries/experiment_globals.sh index e066d2c..ad6e98a 100644 --- a/tests/bash_libraries/experiment_globals.sh +++ b/tests/bash_libraries/experiment_globals.sh @@ -40,14 +40,16 @@ declare -gr SANDBOX_ROUTE_FIELD=3 declare -gr SANDBOX_CPU_FREQ_FIELD=20 declare -gr SANDBOX_RESPONSE_CODE_FIELD=21 declare -gr SANDBOX_GUARANTEE_TYPE_FIELD=22 +declare -gr SANDBOX_PAYLOAD_SIZE=23 # HTTP Session Perf Log Globals: -declare -ga HTTP_METRICS=(http_receive http_sent http_total) +declare -ga HTTP_METRICS=(http_receive http_sent http_total http_preprocess) declare -gA HTTP_METRICS_FIELDS=( [http_receive]=6 [http_sent]=7 [http_total]=8 + [http_preprocess]=9 ) declare -gr HTTP_TENANT_NAME_FIELD=1 declare -gr HTTP_ROUTE_FIELD=2 -declare -gr HTTP_CPU_FREQ_FIELD=9 +declare -gr HTTP_CPU_FREQ_FIELD=10 diff --git a/tests/bash_libraries/generate_spec_json.sh b/tests/bash_libraries/generate_spec_json.sh index f4ed01a..e80448c 100644 --- a/tests/bash_libraries/generate_spec_json.sh +++ b/tests/bash_libraries/generate_spec_json.sh @@ -7,20 +7,11 @@ jq_admin_spec() { jq ". + {\ \"name\": \"Admin\",\ \"port\": 55555,\ - \"replenishment-period-us\": 0,\ - \"max-budget-us\": 0,\ - \"reservation-percentile\": 0,\ \"routes\": [\ .routes[] + {\ - \"route\": \"/admin\",\ - \"admissions-percentile\": 50,\ - \"expected-execution-us\": 1000,\ - \"relative-deadline-us\": 10000},\ + \"route\": \"/admin\"},\ .routes[] + {\ - \"route\": \"/terminator\",\ - \"admissions-percentile\": 50,\ - \"expected-execution-us\": 1000,\ - \"relative-deadline-us\": 10000}\ + \"route\": \"/terminator\"}\ ]\ }" < "./template.json" > "./result_admin.json" } @@ -33,17 +24,22 @@ generate_spec_json() { local jq_str local tenant=$(printf "%s-%03d" "${TENANT_IDS[$t_idx]}" "$var") local port=${ports[$tenant]} - local repl_period=${repl_periods[$tenant]} - local budget=${max_budgets[$tenant]} - local reservation=${reservations[$tenant]} jq_str=". + { \"name\": \"$tenant\",\ - \"port\": $port,\ - \"replenishment-period-us\": $repl_period,\ - \"max-budget-us\": $budget,\ - \"reservation-percentile\": $reservation,\ - \"routes\": [" + \"port\": $port" + + if [ -n "$MTDS_REPL_PERIODS_us" ]; then + repl_period=${repl_periods[$tenant]} + budget=${max_budgets[$tenant]} + jq_str+=",\"replenishment-period-us\": $repl_period,\"max-budget-us\": $budget" + fi + if [ -n "$MTDBF_RESERVATIONS_p" ]; then + reservation=${reservations[$tenant]} + jq_str+=",\"reservation-percentile\": $reservation" + fi + + jq_str+=",\"routes\": [" local t_routes IFS=' ' read -r -a t_routes <<< ${ROUTES[$t_idx]} @@ -53,17 +49,34 @@ generate_spec_json() { local workload="$tenant-$route" local wasm_path=${wasm_paths[$workload]} local resp_content_type=${resp_content_types[$workload]} - local expected=${expected_execs[$workload]} local deadline=${deadlines[$workload]} jq_str+=".routes[] + {\ \"route\": \"/$route\",\ \"path\": \"$wasm_path\",\ \"admissions-percentile\": $ESTIMATIONS_PERCENTILE,\ - \"expected-execution-us\": $expected,\ \"relative-deadline-us\": $deadline,\ - \"http-resp-content-type\": \"$resp_content_type\"}" + \"http-resp-content-type\": \"$resp_content_type\"" + if [ -n "$PREPROCESS_WASM_PATHS" ]; then + local preprocess_wasm_path=${preprocess_wasm_paths[$workload]} + local model_bias=${model_biases[$workload]} + local model_scale=${model_scales[$workload]} + local model_num_of_param=${model_num_of_params[$workload]} + local model_beta1=${model_beta1s[$workload]} + local model_beta2=${model_beta2s[$workload]} + + jq_str+=", + \"path_preprocess\": \"$preprocess_wasm_path\",\ + \"model-bias\": $model_bias,\ + \"model-scale\": $model_scale,\ + \"model-num-of-param\": $model_num_of_param,\ + \"model-beta1\": $model_beta1,\ + \"model-beta2\": $model_beta2" + fi + + jq_str+="}" + if [ "$index" != $((${#t_routes[@]}-1)) ]; then jq_str+="," fi @@ -74,7 +87,7 @@ generate_spec_json() { done done - jq_admin_spec + if [ "$CLIENT_TERMINATE_SERVER" == true ]; then jq_admin_spec; fi # Merges all of the multiple specs for a single module jq -s '. | sort_by(.name)' ./result_*.json > "./spec.json" diff --git a/tests/bash_libraries/install_tools.sh b/tests/bash_libraries/install_tools.sh index 82b7480..bf18348 100755 --- a/tests/bash_libraries/install_tools.sh +++ b/tests/bash_libraries/install_tools.sh @@ -22,6 +22,37 @@ if ! command -v hey > /dev/null; then fi fi +if ! command -v gnuplot > /dev/null; then + if [[ $(whoami) == "root" ]]; then + apt update + apt install -y gnuplot + else + sudo apt update + sudo apt install -y gnuplot + fi +fi + + +if ! command -v jq > /dev/null; then + if [[ $(whoami) == "root" ]]; then + apt update + apt install -y jq + else + sudo apt update + sudo apt install -y jq + fi +fi + +if ! command -v htop > /dev/null; then + if [[ $(whoami) == "root" ]]; then + apt update + apt install -y htop + else + sudo apt update + sudo apt install -y htop + fi +fi + if ! command -v loadtest > /dev/null; then if ! command -v npm > /dev/null; then # if [[ $(whoami) == "root" ]]; then @@ -33,6 +64,7 @@ if ! command -v loadtest > /dev/null; then # fi # installs NVM (Node Version Manager) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + sleep 5 export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion @@ -63,37 +95,6 @@ if ! command -v loadtest > /dev/null; then popd fi -if ! command -v gnuplot > /dev/null; then - if [[ $(whoami) == "root" ]]; then - apt update - apt install -y gnuplot - else - sudo apt update - sudo apt install -y gnuplot - fi -fi - - -if ! command -v jq > /dev/null; then - if [[ $(whoami) == "root" ]]; then - apt update - apt install -y jq - else - sudo apt update - sudo apt install -y jq - fi -fi - -if ! command -v htop > /dev/null; then - if [[ $(whoami) == "root" ]]; then - apt update - apt install -y htop - else - sudo apt update - sudo apt install -y htop - fi -fi - # For SOD: # if ! command -v imagemagick > /dev/null; then # if [ "$(whoami)" == "root" ]; then diff --git a/tests/bash_libraries/multi_tenancy_base.sh b/tests/bash_libraries/multi_tenancy_base.sh index 88f9544..10fd3f1 100755 --- a/tests/bash_libraries/multi_tenancy_base.sh +++ b/tests/bash_libraries/multi_tenancy_base.sh @@ -151,7 +151,7 @@ process_client_results_hey() { for workload in "${workloads[@]}"; do local t_id=${workload_tids[$workload]} - local deadline=${workload_deadlines[$workload]} + local deadline=${deadlines[$workload]} local var=${workload_vars[$workload]} # Some requests come back with an "Unsolicited response ..." See issue #185 @@ -273,7 +273,8 @@ process_client_results_loadtest() { # throughput=$(grep "Requests per second" "$results_directory/${workload}.dat" | tr -s ' ' | cut -d ' ' -f 14 | tail -n 1) # throughput of ALL throughput=$(echo "$total/$duration" | bc) goodput=$(echo "$all200/$duration" | bc) - printf "%s,%.1f\n" "$var" "$success_rate" >> "$results_directory/throughput_$t_id.csv" + # printf "%s,%.1f\n" "$var" "$success_rate" >> "$results_directory/throughput_$t_id.csv" + printf "%s,%s\n" "$throughput" "$goodput" >> "$results_directory/throughput_$t_id.csv" # Generate Latency Data min=$(awk '/Minimum latency/ {sum += $13; count++} END {print int(sum*1000/count)}' "$results_directory/${workload}.dat") @@ -338,7 +339,7 @@ process_server_results() { mkdir -p "$results_directory/$workload" local t_id=${workload_tids[$workload]} - local deadline=${workload_deadlines[$workload]} + local deadline=${deadlines[$workload]} local var=${workload_vars[$workload]} for metric in "${SANDBOX_METRICS[@]}"; do @@ -386,8 +387,13 @@ process_server_results() { END{printf "'"$var"',%3.1f,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", (all200*100/NR), NR, ok, all200, total_failed, denied_any, denied_gtd, x_denied_any, x_denied_gtd, mis_dl_glob, mis_dl_local, mis_dl_wb, shed_glob, shed_local, misc, guaranteed, besteffort} ' < "$results_directory/$workload/total_sorted.csv" >> "$results_directory/success_$t_id.csv" + total=$(awk 'END {printf "%d", NR}' "$results_directory/$workload/total_sorted.csv") + ok=$(awk -F, '$2 == 200 && $1 <= '"$deadline"' {ok++} END {printf "%d", ok}' "$results_directory/$workload/total_sorted.csv") + throughput=$(echo "$total/$DURATION_sec" | bc) + goodput=$(echo "$ok/$DURATION_sec" | bc) + # Throughput is calculated on the client side, so ignore the below line - printf "%s,%d\n" "$var" "1" >> "$results_directory/throughput_$t_id.csv" + printf "%s,%s\n" "$throughput" "$goodput" >> "$results_directory/throughput_$t_id.csv" # Generate Latency Data for csv percentiles_table_row "$results_directory/$workload/total_sorted.csv" "$results_directory/latency_$t_id.csv" "$var" @@ -477,7 +483,7 @@ experiment_server_post() { if [[ -f "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" ]]; then mv "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" "$results_directory/$SERVER_LOG_FILE" process_server_results "$results_directory" || return 1 - rm "$results_directory/$SLEDGE_SANDBOX_PERF_LOG" + # rm "$results_directory/$SLEDGE_SANDBOX_PERF_LOG" else echo "Sandbox Perf Log was set, but $SERVER_LOG_FILE not found!" fi @@ -487,7 +493,7 @@ experiment_server_post() { if [[ -f "$__run_sh__base_path/$SLEDGE_HTTP_SESSION_PERF_LOG" ]]; then mv "$__run_sh__base_path/$SLEDGE_HTTP_SESSION_PERF_LOG" "$results_directory/$SERVER_HTTP_LOG_FILE" process_server_http_results "$results_directory" || return 1 - rm "$results_directory/$SERVER_HTTP_LOG_FILE" + # rm "$results_directory/$SERVER_HTTP_LOG_FILE" else echo "HTTP Perf Log was set, but $SERVER_HTTP_LOG_FILE not found!" fi diff --git a/tests/bash_libraries/multi_tenancy_init.sh b/tests/bash_libraries/multi_tenancy_init.sh index ec48485..6603370 100644 --- a/tests/bash_libraries/multi_tenancy_init.sh +++ b/tests/bash_libraries/multi_tenancy_init.sh @@ -9,16 +9,21 @@ declare -A repl_periods=() declare -A max_budgets=() declare -A reservations=() declare -A wasm_paths=() +declare -A preprocess_wasm_paths=() declare -A expected_execs=() declare -A deadlines=() declare -A resp_content_types=() +declare -A model_biases=() +declare -A model_scales=() +declare -A model_num_of_params=() +declare -A model_beta1s=() +declare -A model_beta2s=() declare -A arg_opts_hey=() declare -A arg_opts_lt=() declare -A args=() declare -A loads=() declare -a workloads=() declare -A workload_tids=() -declare -A workload_deadlines=() declare -A workload_vars=() assert_run_experiments_args() { @@ -82,6 +87,7 @@ run_init() { reservations+=([$tenant]=$reservation) local t_routes r_expected_execs r_deadlines r_arg_opts_hey r_arg_opts_lt r_args r_loads + local r_model_biases r_model_scales r_model_num_of_params r_model_beta1s r_model_beta2s IFS=' ' read -r -a t_routes <<< "${ROUTES[$t_idx]}" IFS=' ' read -r -a r_wasm_paths <<< "${WASM_PATHS[$t_idx]}" @@ -89,6 +95,13 @@ run_init() { IFS=' ' read -r -a r_dl_to_exec_ratios <<< "${DEADLINE_TO_EXEC_RATIOs[$t_idx]}" IFS=' ' read -r -a r_resp_content_types <<< "${RESP_CONTENT_TYPES[$t_idx]}" + IFS=' ' read -r -a r_preprocess_wasm_paths <<< "${PREPROCESS_WASM_PATHS[$t_idx]}" + IFS=' ' read -r -a r_model_biases <<< "${MODEL_BIASES[$t_idx]}" + IFS=' ' read -r -a r_model_scales <<< "${MODEL_SCALES[$t_idx]}" + IFS=' ' read -r -a r_model_num_of_params <<< "${MODEL_NUM_OF_PARAMS[$t_idx]}" + IFS=' ' read -r -a r_model_beta1s <<< "${MODEL_BETA1S[$t_idx]}" + IFS=' ' read -r -a r_model_beta2s <<< "${MODEL_BETA2S[$t_idx]}" + IFS=' ' read -r -a r_arg_opts_hey <<< "${ARG_OPTS_HEY[$t_idx]}" IFS=' ' read -r -a r_arg_opts_lt <<< "${ARG_OPTS_LT[$t_idx]}" IFS=' ' read -r -a r_args <<< "${ARGS[$t_idx]}" @@ -98,10 +111,15 @@ run_init() { local route=${t_routes[$r_idx]} local wasm_path=${r_wasm_paths[$r_idx]} local expected=$(load_value "${r_expected_execs[$r_idx]}" "$var") - # local deadline=${r_deadlines[$r_idx]} local dl_to_exec_ratio=${r_dl_to_exec_ratios[$r_idx]} local deadline=$((expected*dl_to_exec_ratio/100)) local resp_content_type=${r_resp_content_types[$r_idx]} + local preprocess_wasm_path=${r_preprocess_wasm_paths[$r_idx]} + local model_bias=${r_model_biases[$r_idx]} + local model_scale=${r_model_scales[$r_idx]} + local model_num_of_param=${r_model_num_of_params[$r_idx]} + local model_beta1=${r_model_beta1s[$r_idx]} + local model_beta2=${r_model_beta2s[$r_idx]} local arg_opt_hey=${r_arg_opts_hey[$r_idx]} local arg_opt_lt=${r_arg_opts_lt[$r_idx]} local arg=$(load_value "${r_args[$r_idx]}" "$var") @@ -112,13 +130,18 @@ run_init() { expected_execs+=([$workload]=$expected) deadlines+=([$workload]=$deadline) resp_content_types+=([$workload]=$resp_content_type) + preprocess_wasm_paths+=([$workload]=$preprocess_wasm_path) + model_biases+=([$workload]=$model_bias) + model_scales+=([$workload]=$model_scale) + model_num_of_params+=([$workload]=$model_num_of_param) + model_beta1s+=([$workload]=$model_beta1) + model_beta2s+=([$workload]=$model_beta2) arg_opts_hey+=([$workload]=$arg_opt_hey) arg_opts_lt+=([$workload]=$arg_opt_lt) args+=([$workload]=$arg) loads+=([$workload]=$load) workloads+=("$workload") workload_tids+=([$workload]=$tenant_id) - workload_deadlines+=([$workload]=$deadline) workload_vars+=([$workload]=$var) done done diff --git a/tests/deadline_description/run.sh b/tests/deadline_description/run.sh index fa38539..1fcb45b 100755 --- a/tests/deadline_description/run.sh +++ b/tests/deadline_description/run.sh @@ -26,23 +26,23 @@ profile() { local -r results_directory="$2" # ekf - hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m GET -D "./ekf/initial_state.dat" "http://${hostname}:10000/ekf" > /dev/null + hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m POST -D "./ekf/initial_state.dat" "http://${hostname}:10000/ekf" > /dev/null printf "[ekf: OK]\n" # Resize - hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m GET -D "./resize/shrinking_man_large.jpg" "http://${hostname}:10000/resize" > /dev/null + hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m POST -D "./resize/shrinking_man_large.jpg" "http://${hostname}:10000/resize" > /dev/null printf "[resize: OK]\n" # lpd - hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m GET -D "./lpd/Cars0.png" "http://${hostname}:10000/lpd" > /dev/null + hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m POST -D "./lpd/Cars0.png" "http://${hostname}:10000/lpd" > /dev/null printf "[lpd: OK]\n" # gocr - hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m GET -D "./gocr/hyde.pnm" "http://${hostname}:10000/gocr" > /dev/null + hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m POST -D "./gocr/hyde.pnm" "http://${hostname}:10000/gocr" > /dev/null printf "[gocr: OK]\n" # cifar10 - hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m GET -D "./cifar10/airplane1.bmp" "http://${hostname}:10000/cifar10" > /dev/null + hey -disable-compression -disable-keepalive -disable-redirects -n 256 -c 1 -cpus 1 -t 0 -o csv -m POST -D "./cifar10/airplane1.bmp" "http://${hostname}:10000/cifar10" > /dev/null printf "[cifar10: OK]\n" } diff --git a/tests/deadline_description/spec.json b/tests/deadline_description/spec.json index 8af5c4b..fb81e77 100644 --- a/tests/deadline_description/spec.json +++ b/tests/deadline_description/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/ekf", diff --git a/tests/depth_to_xyz/run.sh b/tests/depth_to_xyz/run.sh index db2951d..e91038e 100755 --- a/tests/depth_to_xyz/run.sh +++ b/tests/depth_to_xyz/run.sh @@ -13,6 +13,7 @@ export SLEDGE_HTTP_SESSION_PERF_LOG=http_perf.log # export EXTRA_EXEC_PERCENTILE=10 # The global configs for the scripts +declare -r ADMIN_ACCESS=false declare -r CLIENT_TERMINATE_SERVER=false declare -r DURATION_sec=30 declare -r ESTIMATIONS_PERCENTILE=60 diff --git a/tests/depth_to_xyz/spec.json b/tests/depth_to_xyz/spec.json index ca5dde3..eed90dc 100644 --- a/tests/depth_to_xyz/spec.json +++ b/tests/depth_to_xyz/spec.json @@ -1,44 +1,19 @@ [ - { - "name": "Admin", - "port": 55555, - "replenishment-period-us": 0, - "max-budget-us": 0, - "reservation-percentile": 0, - "routes": [ - { - "route": "/admin", - "path": "fibonacci.wasm.so", - "admissions-percentile": 50, - "expected-execution-us": 1000, - "relative-deadline-us": 10000, - "http-resp-content-type": "text/plain" - }, - { - "route": "/terminator", - "path": "fibonacci.wasm.so", - "admissions-percentile": 50, - "expected-execution-us": 1000, - "relative-deadline-us": 10000, - "http-resp-content-type": "text/plain" - } - ] - }, { "name": "cmu-000", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/depth_to_xyz", "path": "depth_to_xyz.wasm.so", "admissions-percentile": 60, "expected-execution-us": 950000, - "relative-deadline-us": 4750000, + "relative-deadline-us": 0, "http-resp-content-type": "image/png" } - ] + ], + "replenishment-period-us": 0, + "max-budget-us": 0, + "reservation-percentile": 0 } ] diff --git a/tests/depth_to_xyz/template.json b/tests/depth_to_xyz/template.json index 721dca5..ff900a4 100644 --- a/tests/depth_to_xyz/template.json +++ b/tests/depth_to_xyz/template.json @@ -1,9 +1,6 @@ { "name": "tenant", "port": 0, - "replenishment-period-us": 0, - "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/route", diff --git a/tests/empty/concurrency/spec.json b/tests/empty/concurrency/spec.json index d0d98e5..c06b42a 100644 --- a/tests/empty/concurrency/spec.json +++ b/tests/empty/concurrency/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/empty", diff --git a/tests/fibonacci/bimodal/Makefile b/tests/fibonacci/bimodal/Makefile index 0cd9332..afb2832 100644 --- a/tests/fibonacci/bimodal/Makefile +++ b/tests/fibonacci/bimodal/Makefile @@ -44,7 +44,7 @@ client-preempt: (http :10010/fib2?40 &); http :10010/fib?10 client-fib10-multi: - hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "10\n" "http://${HOSTNAME}:10020/fib" + hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m POST -d "10\n" "http://${HOSTNAME}:10020/fib" client-fib40-multi: - hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "40\n" "http://${HOSTNAME}:10010/fib2" + hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m POST -d "40\n" "http://${HOSTNAME}:10010/fib2" diff --git a/tests/fibonacci/bimodal/run.sh b/tests/fibonacci/bimodal/run.sh index acdb15e..264c4e4 100755 --- a/tests/fibonacci/bimodal/run.sh +++ b/tests/fibonacci/bimodal/run.sh @@ -50,13 +50,13 @@ run_samples() { local -ir PERF_WINDOW_CAPACITY printf "Running Samples: " - hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10010/fib2" 1> /dev/null 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m POST -d "40\n" "http://${hostname}:10010/fib2" 1> /dev/null 2> /dev/null || { printf "[ERR]\n" panic "fib40 samples failed with $?" return 1 } - hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:100010/fib" 1> /dev/null 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m POST -d "10\n" "http://${hostname}:100010/fib" 1> /dev/null 2> /dev/null || { printf "[ERR]\n" panic "fib10 samples failed with $?" return 1 @@ -94,7 +94,7 @@ run_experiments() { # Run each separately printf "\tfib40: " - hey -disable-compression -disable-keepalive -disable-redirects -z ${duration_sec}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "40\n" "http://$hostname:10010/fib2" > "$results_directory/fib40.csv" 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -z ${duration_sec}s -cpus 4 -c 100 -t 0 -o csv -m POST -d "40\n" "http://$hostname:10010/fib2" > "$results_directory/fib40.csv" 2> /dev/null || { printf "[ERR]\n" panic "fib40 failed" return 1 @@ -107,7 +107,7 @@ run_experiments() { printf "[OK]\n" printf "\tfib10: " - hey -disable-compression -disable-keepalive -disable-redirects -z ${duration_sec}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "10\n" "http://$hostname:10010/fib" > "$results_directory/fib10.csv" 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -z ${duration_sec}s -cpus 4 -c 100 -t 0 -o csv -m POST -d "10\n" "http://$hostname:10010/fib" > "$results_directory/fib10.csv" 2> /dev/null || { printf "[ERR]\n" panic "fib10 failed" return 1 @@ -125,12 +125,12 @@ run_experiments() { local fib40_con_PID local fib10_con_PID - hey -disable-compression -disable-keepalive -disable-redirects -z $((duration_sec + 2 * offset))s -cpus 2 -c 100 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10010/fib2" > "$results_directory/fib40_con.csv" 2> /dev/null & + hey -disable-compression -disable-keepalive -disable-redirects -z $((duration_sec + 2 * offset))s -cpus 2 -c 100 -t 0 -o csv -m POST -d "40\n" "http://${hostname}:10010/fib2" > "$results_directory/fib40_con.csv" 2> /dev/null & fib40_con_PID="$!" sleep $offset - hey -disable-compression -disable-keepalive -disable-redirects -z "${duration_sec}s" -cpus 2 -c 100 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:10010/fib" > "$results_directory/fib10_con.csv" 2> /dev/null & + hey -disable-compression -disable-keepalive -disable-redirects -z "${duration_sec}s" -cpus 2 -c 100 -t 0 -o csv -m POST -d "10\n" "http://${hostname}:10010/fib" > "$results_directory/fib10_con.csv" 2> /dev/null & fib10_con_PID="$!" wait -f "$fib10_con_PID" || { diff --git a/tests/fibonacci/bimodal/spec.json b/tests/fibonacci/bimodal/spec.json index 10f0e1e..ac1faa5 100644 --- a/tests/fibonacci/bimodal/spec.json +++ b/tests/fibonacci/bimodal/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10010, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/fib", @@ -26,8 +24,6 @@ { "name": "conix", "port": 10020, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/fib", diff --git a/tests/fibonacci/concurrency/run_hey.sh b/tests/fibonacci/concurrency/run_hey.sh index 1cf8934..e8faddf 100755 --- a/tests/fibonacci/concurrency/run_hey.sh +++ b/tests/fibonacci/concurrency/run_hey.sh @@ -47,7 +47,7 @@ run_experiments() { printf "Running Experiments:\n" for con in "${concurrency[@]}"; do printf "\t%d Concurrency: " "$con" - hey -disable-compression -disable-keepalive -disable-redirects -z "$duration_sec"s -n "$iterations" -c "$con" -o csv -m GET -d "30\n" "http://$hostname:10030/fib" > "$results_directory/con$con.csv" 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -z "$duration_sec"s -n "$iterations" -c "$con" -o csv -m POST -d "30\n" "http://$hostname:10030/fib" > "$results_directory/con$con.csv" 2> /dev/null || { printf "[ERR]\n" panic "experiment failed" return 1 diff --git a/tests/fibonacci/concurrency/spec.json b/tests/fibonacci/concurrency/spec.json index ae79b08..b6ae5d3 100644 --- a/tests/fibonacci/concurrency/spec.json +++ b/tests/fibonacci/concurrency/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10030, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/fib", diff --git a/tests/gocr/by_dpi/spec.json b/tests/gocr/by_dpi/spec.json index 7cafb50..4112042 100644 --- a/tests/gocr/by_dpi/spec.json +++ b/tests/gocr/by_dpi/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/gocr_72_dpi", diff --git a/tests/gocr/by_font/spec.json b/tests/gocr/by_font/spec.json index 89b3f56..cc169f8 100644 --- a/tests/gocr/by_font/spec.json +++ b/tests/gocr/by_font/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/gocr_mono", diff --git a/tests/gocr/by_word/spec.json b/tests/gocr/by_word/spec.json index 4089777..9925280 100644 --- a/tests/gocr/by_word/spec.json +++ b/tests/gocr/by_word/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/gocr_1_word", diff --git a/tests/gocr/fivebyeight/spec.json b/tests/gocr/fivebyeight/spec.json index 492325a..aab5c87 100644 --- a/tests/gocr/fivebyeight/spec.json +++ b/tests/gocr/fivebyeight/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/gocr", diff --git a/tests/gocr/handwriting/spec.json b/tests/gocr/handwriting/spec.json index 492325a..aab5c87 100644 --- a/tests/gocr/handwriting/spec.json +++ b/tests/gocr/handwriting/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/gocr", diff --git a/tests/gocr/hyde/spec.json b/tests/gocr/hyde/spec.json index a3ee5b3..ea7aa5b 100644 --- a/tests/gocr/hyde/spec.json +++ b/tests/gocr/hyde/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/gocr", diff --git a/tests/html/spec.json b/tests/html/spec.json index 456ee45..107d0fe 100644 --- a/tests/html/spec.json +++ b/tests/html/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 1337, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/index.html", diff --git a/tests/multi-tenancy-predictions/.gitignore b/tests/multi-tenancy-predictions/.gitignore new file mode 100644 index 0000000..fe70990 --- /dev/null +++ b/tests/multi-tenancy-predictions/.gitignore @@ -0,0 +1 @@ +out* diff --git a/tests/multi-tenancy-predictions/Makefile b/tests/multi-tenancy-predictions/Makefile new file mode 100644 index 0000000..9f67f93 --- /dev/null +++ b/tests/multi-tenancy-predictions/Makefile @@ -0,0 +1,102 @@ +SLEDGE_BINARY_DIR=../../runtime/bin +HOST?=localhost # pass arguments to change this: make client-lpd HOST=10.10.1.4 +# HOST=arena0.andrew.cmu.edu +# HOST=c220g2-011017.wisc.cloudlab.us +PORT0=10000 +PORT1=15000 +PORT2=20000 +PORT3=25000 +PORT4=30000 +PORT5=35000 +PORT6=40000 +HEY_OPTS=-disable-compression -disable-keepalive -disable-redirects + +default: run + +clean: + rm -rf res/* + +run: + SLEDGE_SIGALRM_HANDLER=TRIAGED SLEDGE_SCHEDULER=MTDBF SLEDGE_SPINLOOP_PAUSE_ENABLED=true SLEDGE_HTTP_SESSION_PERF_LOG=http_perf.log SLEDGE_SANDBOX_PERF_LOG=perf.log LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} ${SLEDGE_BINARY_DIR}/sledgert spec.json + +debug: + SLEDGE_SCHEDULER=MTDBF SLEDGE_SPINLOOP_PAUSE_ENABLED=false SLEDGE_NWORKERS=18 LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} gdb ${SLEDGE_BINARY_DIR}/sledgert \ + --eval-command="handle SIGUSR1 noprint nostop" \ + --eval-command="handle SIGPIPE noprint nostop" \ + --eval-command="set pagination off" \ + --eval-command="set print pretty" \ + --eval-command="run spec.json" + +valgrind: + SLEDGE_DISABLE_PREEMPTION=true SLEDGE_NWORKERS=1 LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} valgrind --leak-check=full --max-stackframe=11150456 --run-libc-freeres=no --run-cxx-freeres=no ${SLEDGE_BINARY_DIR}/sledgert spec.json + + +client-cnn: + curl -H 'Expect: ' -H "Content-Type: image/jpeg" --data-binary "@input-cnn/faces01.jpg" "${HOST}:${PORT0}/cnn" + +client-cifar10: + curl -H 'Expect: ' -H "Content-Type: image/bmp" --data-binary "@input-cifar10/airplane1.bmp" "${HOST}:${PORT1}/cifar10" + +client-gocr: + curl -H 'Expect: ' -H "Content-Type: application/octet-stream" --data-binary "@input-gocr/5x8.pnm" "${HOST}:${PORT2}/gocr" + +client-lpd: +# curl -H 'Expect: ' -H "Content-Type: image/png" --data-binary "@input-lpd-png/Cars0.png" "${HOST}:${PORT3}/lpd" + curl -H 'Expect: ' -H "Content-Type: image/jpeg" --data-binary "@input-lpd-jpg/Cars0.jpg" "${HOST}:${PORT3}/lpd" + +client-resize: + curl -H 'Expect: ' -H "Content-Type: image/jpeg" --data-binary "@input-resize/picsum_512x512_01.jpg" "${HOST}:${PORT4}/resize" --output "out-resize.jpg" + +client-ekf: + curl -H 'Expect: ' -H "Content-Type: application/octet-stream" --data-binary "@input-ekf/iter00.dat" "${HOST}:${PORT5}/ekf" --output "out-ekf-iter00.dat" + +client-fib-curl: + curl -i -H 'Expect: ' -H "Content-Type: text/plain" "${HOST}:${PORT6}/fib?30" + +########################################## Choose a random file to send with curl: ########################################## +client-cnn-random: + @dir="input-cnn"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ + curl -s -H 'Expect: ' -H "Content-Type: image/jpeg" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT0}/cnn" + +client-cifar10-random: + @dir="input-cifar10"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ + curl -s -H 'Expect: ' -H "Content-Type: image/bmp" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT1}/cifar10" + +client-gocr-random: + @dir="input-gocr"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ + curl -s -H 'Expect: ' -H "Content-Type: application/octet-stream" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT2}/gocr" + +client-lpd-random: +# @dir="input-lpd-png"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ +# curl -s -H 'Expect: ' -H "Content-Type: image/png" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT3}/lpd" + @dir="input-lpd-jpg"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ + curl -s -H 'Expect: ' -H "Content-Type: image/jpeg" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT3}/lpd" + +client-resize-random: + @dir="input-resize"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ + curl -s -H 'Expect: ' -H "Content-Type: image/jpeg" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT4}/resize" --output "out-resize-$$random_file" + +client-ekf-random: + @dir="input-ekf"; random_file="$$(ls $$dir | shuf -n 1)"; echo "Random file: $$random_file"; \ + curl -s -H 'Expect: ' -H "Content-Type: application/octet-stream" --data-binary "@$$dir/$$random_file" "${HOST}:${PORT5}/ekf" --output "out-ekf-$$random_file" +############################################################################################################################# + +client-fib-once: + echo 30 | http ${HOST}:${PORT6}/fib +# http ${HOST}:${PORT6}/fib?30 + +client-fib-loadtest: + loadtest -n 10 -c 10 -P 30 "http://${HOST}:${PORT6}/fib" + +client-fib-hey: + hey ${HEY_OPTS} -z 10s -c 72 -t 0 -o csv -m POST -d "30\n" "http://${HOST}:${PORT6}/fib" + +client-fib-wrk: + wrk -t 1 -c 1 -d 5s -R 1 "http://${HOST}:${PORT6}/fib?30" + + +client-admin: + echo 5 | http ${HOST}:55555/admin + +client-terminator: + echo 5 | http ${HOST}:55555/terminator diff --git a/tests/multi-tenancy-predictions/gocr_generate_dataset.sh b/tests/multi-tenancy-predictions/gocr_generate_dataset.sh new file mode 100644 index 0000000..290394d --- /dev/null +++ b/tests/multi-tenancy-predictions/gocr_generate_dataset.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +VARYING=(72 108 144) + +for var in "${VARYING[@]}"; do + mkdir -p "$var"dpi + mkdir -p "$var"dpi-orig + for ((i=5; i<=15; i++)); do + shuf -n10 /usr/share/dict/american-english > "$var"dpi-orig/"$i"words.txt + pango-view --dpi="$var" --font=mono -qo "$var"dpi-orig/"$var"dpi_"$i"words.png "$var"dpi-orig/"$i"words.txt + pngtopnm "$var"dpi-orig/"$var"dpi_"$i"words.png > "$var"dpi/"$var"dpi_"$i"words.pnm + done +done \ No newline at end of file diff --git a/tests/multi-tenancy-predictions/input-cifar10/airplane1.bmp b/tests/multi-tenancy-predictions/input-cifar10/airplane1.bmp new file mode 100644 index 0000000..7577ad9 Binary files /dev/null and b/tests/multi-tenancy-predictions/input-cifar10/airplane1.bmp differ diff --git a/tests/multi-tenancy-predictions/input-cnn/faces01.jpg b/tests/multi-tenancy-predictions/input-cnn/faces01.jpg new file mode 100644 index 0000000..a21de9c Binary files /dev/null and b/tests/multi-tenancy-predictions/input-cnn/faces01.jpg differ diff --git a/tests/multi-tenancy-predictions/input-ekf/iter00.dat b/tests/multi-tenancy-predictions/input-ekf/iter00.dat new file mode 100644 index 0000000..9a960e1 Binary files /dev/null and b/tests/multi-tenancy-predictions/input-ekf/iter00.dat differ diff --git a/tests/multi-tenancy-predictions/input-gocr/5x8.pnm b/tests/multi-tenancy-predictions/input-gocr/5x8.pnm new file mode 100644 index 0000000..5e7a4c2 --- /dev/null +++ b/tests/multi-tenancy-predictions/input-gocr/5x8.pnm @@ -0,0 +1,4 @@ +P6 +331 42 +65535 +ÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞöÿÿÿÿÞö \ No newline at end of file diff --git a/tests/multi-tenancy-predictions/input-lpd-jpg/Cars0.jpg b/tests/multi-tenancy-predictions/input-lpd-jpg/Cars0.jpg new file mode 100644 index 0000000..34a752f Binary files /dev/null and b/tests/multi-tenancy-predictions/input-lpd-jpg/Cars0.jpg differ diff --git a/tests/multi-tenancy-predictions/input-resize/picsum_512x512_01.jpg b/tests/multi-tenancy-predictions/input-resize/picsum_512x512_01.jpg new file mode 100644 index 0000000..aaa3c16 Binary files /dev/null and b/tests/multi-tenancy-predictions/input-resize/picsum_512x512_01.jpg differ diff --git a/tests/multi-tenancy-predictions/latency.gnuplot b/tests/multi-tenancy-predictions/latency.gnuplot new file mode 100644 index 0000000..016f4e2 --- /dev/null +++ b/tests/multi-tenancy-predictions/latency.gnuplot @@ -0,0 +1,79 @@ +reset + +set term jpeg size 1000,500 +set output "latency.jpg" + +#set xlabel "Reservation Utilization %" +#set ylabel "Latency (us)" + +set key left top + +set xrange [-5:] +set yrange [0:] + +set style histogram columnstacked +set key horizontal + +set macros +# Placement of the a,b,c,d labels in the graphs +POS = "at graph 0.05,1.03 font ',10'" + +# x- and ytics for each row resp. column +NOXTICS = "unset xlabel" +# XTICS = "set xlabel 'Load %'" +XTICS = "set xlabel 'All Requests/sec'" +NOYTICS = "unset ylabel" +YTICS = "set ylabel 'Latency (us)'" + +# Margins for each row resp. column +TMARGIN = "set tmargin at screen 0.90; set bmargin at screen 0.55" +BMARGIN = "set tmargin at screen 0.55; set bmargin at screen 0.20" +LMARGIN = "set lmargin at screen 0.15; set rmargin at screen 0.55" +RMARGIN = "set lmargin at screen 0.55; set rmargin at screen 0.95" + +# plot \ +# for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:7 title 'Tenant '.t_id.' p99' w lp, \ +# for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:6 title 'Tenant '.t_id.' p90' w lp, \ +# for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:5 title 'Tenant '.t_id.' p50' w lp, \ +# for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:4 title 'Tenant '.t_id.' mean' w lp, \ +# for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:3 title 'Tenant '.t_id.' min' w lp + +### Start multiplot (2x2 layout) +set multiplot layout 2,2 rowsfirst +# --- GRAPH a +set label 1 'p99' @POS +@NOXTICS; @YTICS +#@TMARGIN; @LMARGIN +plot for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:7 title t_id w lp +# --- GRAPH b +set label 1 'p90' @POS +@NOXTICS; @NOYTICS +#@TMARGIN; @RMARGIN +plot for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:6 notitle w lp +# --- GRAPH c +set label 1 'p50' @POS +@XTICS; @YTICS +#@BMARGIN; @LMARGIN +plot for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:5 notitle w lp +# --- GRAPH d +set label 1 'mean' @POS +@XTICS; @NOYTICS +#@BMARGIN; @RMARGIN +plot for [t_id in tenant_ids] 'latency_'.t_id.'.dat' using 1:4 notitle w lp +unset multiplot +### End multiplot + +# plot \ +# 'latency_A.dat' using 1:7 title 'A p99' lt 1 lc 1 w lp, \ +# 'latency_A.dat' using 1:6 title 'A p90' lt 2 lc 1 w lp, \ +# 'latency_A.dat' using 1:5 title 'A p50' lt 3 lc 1 w lp, \ +# 'latency_A.dat' using 1:4 title 'A mean' lt 4 lc 1 w lp, \ +# 'latency_A.dat' using 1:3 title 'A min' lt 5 lc 1 w lp,\ +# 'latency_B.dat' using 1:7 title 'B p99' lt 1 lc 2 w lp, \ +# 'latency_B.dat' using 1:6 title 'B p90' lt 2 lc 2 w lp, \ +# 'latency_B.dat' using 1:5 title 'B p50' lt 3 lc 2 w lp, \ +# 'latency_B.dat' using 1:4 title 'B mean' lt 4 lc 2 w lp, \ +# 'latency_B.dat' using 1:3 title 'B min' lt 5 lc 2 w lp + +# 'latency_A.dat' using 1:8 title 'A p100' linetype 0 linecolor 1 with linespoints, \ +# 'latency_B.dat' using 1:8 title 'B p100' linetype 0 linecolor 2 with linespoints, \ diff --git a/tests/multi-tenancy-predictions/run.sh b/tests/multi-tenancy-predictions/run.sh new file mode 100755 index 0000000..36f0eb2 --- /dev/null +++ b/tests/multi-tenancy-predictions/run.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# shellcheck disable=SC1091,SC2034,SC2155 +source ../bash_libraries/multi_tenancy_base.sh || exit 1 + +# Configure SERVER parameters: (this is to skip the .env config file) +export SLEDGE_SCHEDULER=SJF +export SLEDGE_DISABLE_PREEMPTION=false +export SLEDGE_SPINLOOP_PAUSE_ENABLED=false +export SLEDGE_SANDBOX_PERF_LOG=perf.log +export SLEDGE_HTTP_SESSION_PERF_LOG=http_perf.log +export SLEDGE_NWORKERS=1 +# export SLEDGE_PROC_MHZ=2660 + +# To reduce post processing time, provide local-only meaningful metrics: +# Comment it in order to use ALL the metrics! +declare -a SANDBOX_METRICS=(total running_sys running_user) + +# The global configs for the scripts +declare -r ADMIN_ACCESS=false +declare -r CLIENT_TERMINATE_SERVER=false +declare -r DURATION_sec=60 +declare -r ESTIMATIONS_PERCENTILE=60 +declare -r NWORKERS=${SLEDGE_NWORKERS:-1} + +# Tenant configs: +declare -ar TENANT_IDS=("cnn" "cifar10" "gocr" "lpd" "resize" "ekf") +declare -ar INIT_PORTS=(10000 15000 20000 25000 30000 35000) +declare -ar ROUTES=("cnn" "cifar10" "gocr" "lpd" "resize" "ekf") + +declare -r NONE="0" +declare -r GET_JPEG_RESOLUTION="get_jpeg_resolution.wasm.so" + +# Per route configs: +declare -ar WASM_PATHS=("$CNN" "$CIFAR10" "$GOCR" "$LPD" "$RESIZE" "$EKF") +declare -ar WASM_PATHS_PREPROCESSING=("$GET_JPEG_RESOLUTION" "$GET_JPEG_RESOLUTION" "$GET_JPEG_RESOLUTION" "$GET_JPEG_RESOLUTION" "$NONE") +declare -ar RESP_CONTENT_TYPES=("text/plain" "text/plain" "text/plain" "text/plain" "image/jpeg" "application/octet-stream") +declare -ar EXPECTED_EXEC_TIMES_us=("600000" "4000" "8900" "16700" "62000" "30") +declare -ar DEADLINE_TO_EXEC_RATIOs=("500" "500" "500" "500" "500" "5000") # percentage + +# Regressions Model input: +declare -ar PREPROCESS_WASM_PATHS=("$GET_JPEG_RESOLUTION" "$NONE" "$NONE" "$GET_JPEG_RESOLUTION" "$GET_JPEG_RESOLUTION" "$NONE") +declare -ar MODEL_BIASES=("1500" "2000" "2500" "3000" "3500" "100") +declare -ar MODEL_SCALES=("1500" "2000" "2500" "3000" "3500" "100") +declare -ar MODEL_NUM_OF_PARAMS=("2" "1" "1" "2" "2" "1") +declare -ar MODEL_BETA1S=("1500" "2000" "2500" "3000" "3500" "100") +declare -ar MODEL_BETA2S=("1500" "0" "0" "3000" "3500" "0") + +# This is needed if you want loadtest to time out for requests that miss their deadlines (timeout = deadline): +declare -gr LOADTEST_REQUEST_TIMEOUT=false + +# For HEY -d is text, -D is file input. For LoadTest -P is text, -b is file input. +# ALso, LoadTest now supports -B for random file in the folder. HEY supports a single file. +declare -ar ARG_OPTS_HEY=("-D" "-D" "-D" "-D" "-D" "-D") +declare -ar ARG_OPTS_LT=("-B" "-B" "-B" "-B" "-B" "-B") # "-P -P -P") +declare -ar ARGS=("input-cnn" "input-cifar10" "input-gocr" "input-lpd-jpg" "input-resize" "input-ekf") +# declare -ar ARGS=("input-cnn/faces01.jpg" "input-cifar10/airplane1.bmp" "input-gocr/5x8.pnm" "input-lpd-jpg/Cars0.jpg" "input-resize/picsum_512x512_01.jpg" "input-ekf/iter00.dat") + +# This is needed if you want loadtest to log the randomly chosen filenames +declare -gr LOADTEST_LOG_RANDOM=false + +# 100=FULL load, 50=HALF load ... +declare -ar LOADS=(20 20 25 10 25 1) + +# When trying varying values, you must set ONE value from the above params to ? (question mark) +# For example, for varying the loads, try: LOADS=("50 ?" "100") +declare -ar VARYING=(0) # no variation, single experiment + +# Add the word "nuclio" to the end of the client execution command to run for Nuclio mode (stick to the same port and use keep-alive) +[[ "${!#}" = "nuclio" || "${!#}" = "Nuclio" ]] && NUCLIO_MODE_ENABLED=true + +run_init +generate_spec_json +framework_init "$@" diff --git a/tests/multi-tenancy-predictions/spec.json b/tests/multi-tenancy-predictions/spec.json new file mode 100644 index 0000000..6f345bf --- /dev/null +++ b/tests/multi-tenancy-predictions/spec.json @@ -0,0 +1,116 @@ +[ + { + "name": "cifar10-000", + "port": 15000, + "routes": [ + { + "route": "/cifar10", + "path": "cifar10.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 20000, + "http-resp-content-type": "text/plain", + "path_preprocess": "0", + "model-bias": 2000, + "model-scale": 2000, + "model-num-of-param": 1, + "model-beta1": 2000, + "model-beta2": 0 + } + ] + }, + { + "name": "cnn-000", + "port": 10000, + "routes": [ + { + "route": "/cnn", + "path": "cnn_face_detection.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 3000000, + "http-resp-content-type": "text/plain", + "path_preprocess": "get_jpeg_resolution.wasm.so", + "model-bias": 1500, + "model-scale": 1500, + "model-num-of-param": 2, + "model-beta1": 1500, + "model-beta2": 1500 + } + ] + }, + { + "name": "ekf-000", + "port": 35000, + "routes": [ + { + "route": "/ekf", + "path": "gps_ekf.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 1500, + "http-resp-content-type": "application/octet-stream", + "path_preprocess": "0", + "model-bias": 100, + "model-scale": 100, + "model-num-of-param": 1, + "model-beta1": 100, + "model-beta2": 0 + } + ] + }, + { + "name": "gocr-000", + "port": 20000, + "routes": [ + { + "route": "/gocr", + "path": "gocr.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 44500, + "http-resp-content-type": "text/plain", + "path_preprocess": "0", + "model-bias": 2500, + "model-scale": 2500, + "model-num-of-param": 1, + "model-beta1": 2500, + "model-beta2": 0 + } + ] + }, + { + "name": "lpd-000", + "port": 25000, + "routes": [ + { + "route": "/lpd", + "path": "license_plate_detection.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 83500, + "http-resp-content-type": "text/plain", + "path_preprocess": "get_jpeg_resolution.wasm.so", + "model-bias": 3000, + "model-scale": 3000, + "model-num-of-param": 2, + "model-beta1": 3000, + "model-beta2": 3000 + } + ] + }, + { + "name": "resize-000", + "port": 30000, + "routes": [ + { + "route": "/resize", + "path": "resize_image.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 310000, + "http-resp-content-type": "image/jpeg", + "path_preprocess": "get_jpeg_resolution.wasm.so", + "model-bias": 3500, + "model-scale": 3500, + "model-num-of-param": 2, + "model-beta1": 3500, + "model-beta2": 3500 + } + ] + } +] diff --git a/tests/multi-tenancy-predictions/success.gnuplot b/tests/multi-tenancy-predictions/success.gnuplot new file mode 100644 index 0000000..fa85d87 --- /dev/null +++ b/tests/multi-tenancy-predictions/success.gnuplot @@ -0,0 +1,17 @@ +reset + +set term jpeg +set output "success.jpg" + +#set xlabel "Reservation Utilization %" +#set xlabel "Load %" +set xlabel "Requests/sec" +set ylabel "Deadline success rate %" + +set xrange [-5:] +set yrange [0:110] + +plot for [t_id in tenant_ids] 'success_'.t_id.'.dat' using 1:2 title t_id w lp + +#plot 'success_A.dat' using 1:2 title 'Tenant A success rate' linetype 1 linecolor 1 with linespoints,\ +# 'success_B.dat' using 1:2 title 'Tenant B success rate' lt 2 lc 2 w lp diff --git a/tests/multi-tenancy-predictions/template.json b/tests/multi-tenancy-predictions/template.json new file mode 100644 index 0000000..061c457 --- /dev/null +++ b/tests/multi-tenancy-predictions/template.json @@ -0,0 +1,13 @@ +{ + "name": "tenant", + "port": 0, + "routes": [ + { + "route": "/route", + "path": "fibonacci.wasm.so", + "admissions-percentile": 60, + "relative-deadline-us": 5000, + "http-resp-content-type": "text/plain" + } + ] +} diff --git a/tests/multi-tenancy-predictions/throughput.gnuplot b/tests/multi-tenancy-predictions/throughput.gnuplot new file mode 100644 index 0000000..fdb345d --- /dev/null +++ b/tests/multi-tenancy-predictions/throughput.gnuplot @@ -0,0 +1,17 @@ +reset + +set term jpeg +set output "throughput.jpg" + +#set xlabel "Reservation Utilization %" +#set xlabel "Load %" +set xlabel "All Requests/sec" +set ylabel "Successful Requests/sec" + +set xrange [0:] +set yrange [0:] + +plot for [t_id in tenant_ids] 'throughput_'.t_id.'.dat' using 1:2 title t_id w lp + +#plot 'throughput_A.dat' using 1:2 title 'Tenant A Throughput' linetype 1 linecolor 1 with linespoints,\ +# 'throughput_B.dat' using 1:2 title 'Tenant B Throughput' linetype 2 linecolor 2 with linespoints diff --git a/tests/multi-tenancy-sample/spec.json b/tests/multi-tenancy-sample/spec.json index db117b3..80aad7b 100644 --- a/tests/multi-tenancy-sample/spec.json +++ b/tests/multi-tenancy-sample/spec.json @@ -4,7 +4,6 @@ "port": 55555, "replenishment-period-us": 0, "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/admin", @@ -29,7 +28,6 @@ "port": 10000, "replenishment-period-us": 0, "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/fib1", @@ -54,7 +52,6 @@ "port": 20000, "replenishment-period-us": 0, "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/fib", diff --git a/tests/multi-tenancy-sample/template.json b/tests/multi-tenancy-sample/template.json index 721dca5..696dbd2 100644 --- a/tests/multi-tenancy-sample/template.json +++ b/tests/multi-tenancy-sample/template.json @@ -3,7 +3,6 @@ "port": 0, "replenishment-period-us": 0, "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/route", diff --git a/tests/scratch_storage/spec.json b/tests/scratch_storage/spec.json index b369d63..b55223b 100644 --- a/tests/scratch_storage/spec.json +++ b/tests/scratch_storage/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 1337, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/set", diff --git a/tests/sod/cnn_face_detection/spec.json b/tests/sod/cnn_face_detection/spec.json index df93e48..0d6e03a 100644 --- a/tests/sod/cnn_face_detection/spec.json +++ b/tests/sod/cnn_face_detection/spec.json @@ -2,9 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, - "reservation-percentile": 0, "routes": [ { "route": "/face", diff --git a/tests/sod/image_resize/by_resolution/run.sh b/tests/sod/image_resize/by_resolution/run.sh index 23367b4..2c81556 100755 --- a/tests/sod/image_resize/by_resolution/run.sh +++ b/tests/sod/image_resize/by_resolution/run.sh @@ -95,7 +95,7 @@ run_perf_tests() { done ((batch_id++)) - hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -D "shrinking_man_${workload}.jpg" "http://${hostname}:10000${route[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & + hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -D "shrinking_man_${workload}.jpg" "http://${hostname}:10000${route[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & done pids=$(pgrep hey | tr '\n' ' ') [[ -n $pids ]] && wait -f $pids diff --git a/tests/sod/image_resize/by_resolution/spec.json b/tests/sod/image_resize/by_resolution/spec.json index f185925..b59f2ab 100644 --- a/tests/sod/image_resize/by_resolution/spec.json +++ b/tests/sod/image_resize/by_resolution/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/resize_small", diff --git a/tests/sod/image_resize/test/spec.json b/tests/sod/image_resize/test/spec.json index a88aa8d..f8ef301 100644 --- a/tests/sod/image_resize/test/spec.json +++ b/tests/sod/image_resize/test/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/resize", diff --git a/tests/sod/lpd/by_plate_count/run.sh b/tests/sod/lpd/by_plate_count/run.sh index 8659e1a..3936bf7 100755 --- a/tests/sod/lpd/by_plate_count/run.sh +++ b/tests/sod/lpd/by_plate_count/run.sh @@ -103,7 +103,7 @@ run_perf_tests() { ((batch_id++)) get_random_image "$workload" random_image - hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -D "${random_image}" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & + hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -D "${random_image}" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & done pids=$(pgrep hey | tr '\n' ' ') [[ -n $pids ]] && wait -f $pids diff --git a/tests/sod/lpd/by_plate_count/spec.json b/tests/sod/lpd/by_plate_count/spec.json index 0f24048..24e5a7d 100644 --- a/tests/sod/lpd/by_plate_count/spec.json +++ b/tests/sod/lpd/by_plate_count/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/lpd1", diff --git a/tests/speechtotext/spec.json b/tests/speechtotext/spec.json index f3bcabf..1eac634 100644 --- a/tests/speechtotext/spec.json +++ b/tests/speechtotext/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/hello_ps", diff --git a/tests/stack_overflow/spec.json b/tests/stack_overflow/spec.json index 1c4afc3..cb6a613 100644 --- a/tests/stack_overflow/spec.json +++ b/tests/stack_overflow/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/stack_overflow", diff --git a/tests/traps/Makefile b/tests/traps/Makefile index c609122..fa59cef 100644 --- a/tests/traps/Makefile +++ b/tests/traps/Makefile @@ -62,4 +62,4 @@ test: echo "4" | http :10000/divide client-fib10-multi: - hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m GET -d "10\n" "http://${HOSTNAME}:10010/divide" + hey -z ${DURATION_SEC}s -cpus 4 -c 100 -t 0 -o csv -m POST -d "10\n" "http://${HOSTNAME}:10010/divide" diff --git a/tests/traps/spec.json b/tests/traps/spec.json index 60492df..227ce7a 100644 --- a/tests/traps/spec.json +++ b/tests/traps/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/divide", diff --git a/tests/workload_mix/run.sh b/tests/workload_mix/run.sh index afe1439..dd7c83f 100755 --- a/tests/workload_mix/run.sh +++ b/tests/workload_mix/run.sh @@ -47,13 +47,13 @@ run_samples() { local -ir PERF_WINDOW_CAPACITY printf "Running Samples: " - hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m POST -d "40\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || { printf "[ERR]\n" panic "fibonacci_40 samples failed with $?" return 1 } - hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || { + hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m POST -d "10\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || { printf "[ERR]\n" panic "fibonacci_10 samples failed with $?" return 1 @@ -140,7 +140,7 @@ run_experiments() { ((batch_id++)) for workload in "${workloads[@]}"; do if ((roll >= floor[$workload] && roll < floor[$workload] + length[$workload])); then - hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -d "${body[$workload]}\n" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & + hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -d "${body[$workload]}\n" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null & break fi done diff --git a/tests/workload_mix/spec.json b/tests/workload_mix/spec.json index b4c0992..87ad4ab 100644 --- a/tests/workload_mix/spec.json +++ b/tests/workload_mix/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/fibonacci_10", diff --git a/tests/workload_mix_realworld/spec.json b/tests/workload_mix_realworld/spec.json index f9e64a2..28211e5 100644 --- a/tests/workload_mix_realworld/spec.json +++ b/tests/workload_mix_realworld/spec.json @@ -2,8 +2,6 @@ { "name": "gwu", "port": 10000, - "replenishment-period-us": 0, - "max-budget-us": 0, "routes": [ { "route": "/cifar10_1.5", diff --git a/uninstall_llvm.sh b/uninstall_llvm.sh new file mode 100755 index 0000000..d76ca26 --- /dev/null +++ b/uninstall_llvm.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Uninstalls all LLVM tooling as much as possible + +echo "Uninstalling LLVM" + +apt-get remove -y --purge \ + "llvm*" \ + "lld*" \ + "libc++*" \ + "libunwind*" \ + "clang*" \ + +apt-get autoremove -y + +update-alternatives --remove-all clang-format +update-alternatives --remove-all clang +update-alternatives --remove-all clang++ +update-alternatives --remove-all llvm-config +update-alternatives --remove-all llvm-objdump +update-alternatives --remove-all clang-tidy +update-alternatives --remove-all wasm-ld \ No newline at end of file