From 304bb41b89a1f3cfd9297f7af80941f605f3bc52 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Mon, 12 May 2025 09:20:58 +0000 Subject: [PATCH 01/32] index review --- .../learning-paths/iot/azure-iot/_index.md | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/_index.md b/content/learning-paths/iot/azure-iot/_index.md index dc75e9e466..5569afccb0 100644 --- a/content/learning-paths/iot/azure-iot/_index.md +++ b/content/learning-paths/iot/azure-iot/_index.md @@ -1,26 +1,22 @@ --- -title: Create IoT Solutions in Azure for Arm Powered Devices +title: Create IoT Solutions in Azure for Arm-Powered Devices minutes_to_complete: 180 -draft: true -cascade: - draft: true - -who_is_this_for: This is an advanced topic for software developers interested in learning how to build a comprehensive IoT solution in Azure that streams, stores, monitors, aggregates, and visualizes data from Arm64-powered IoT devices. +who_is_this_for: This is an advanced topic for developers who want to build a comprehensive IoT solution in Azure that streams, stores, monitors, aggregates, and visualizes data from Arm64-powered IoT devices. learning_objectives: - - Set up and configure an Azure IoT Hub. + - Set up and configure Azure IoT Hub. - Register an IoT device and stream data using the Azure IoT SDK. - Stream IoT data into Azure services using Azure Stream Analytics. - - Store and persist streamed IoT data in Azure Cosmos DB by configuring a Stream Analytics job. - - Implement data monitoring and alerts by creating an Azure Function that checks sensor data from Cosmos DB and sends notifications when thresholds are exceeded. - - Aggregate sensor readings by developing an Azure Function that calculates average values from data stored in Cosmos DB. - - Publish aggregated IoT data to a public-facing web portal, by deploying a Static Web App hosted on Azure Blob Storage + - Store and persist streamed data in Azure Cosmos DB through a Stream Analytics job. + - Monitor data and send alerts by creating an Azure Function that reads sensor data from Cosmos DB and triggers notifications when thresholds are exceeded. + - Aggregate sensor readings using an Azure Function that calculates average values from data stored in Cosmos DB. + - Publish aggregated IoT data to a public-facing web portal, by deploying a static web app hosted on Azure Blob Storage. prerequisites: - - A machine that can run Python3, and Visual Studio Code. - - Azure Account and Subscription. + - A machine with Python 3, and Visual Studio Code installed. + - An Azure Account and subscription. author: Dawid Borycki From d41cb52920cd533970169ddb8ccc643b7f56aea1 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Mon, 12 May 2025 10:33:21 +0000 Subject: [PATCH 02/32] updates --- content/learning-paths/iot/azure-iot/intro.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/intro.md b/content/learning-paths/iot/azure-iot/intro.md index 0de6384cd1..75121062d0 100644 --- a/content/learning-paths/iot/azure-iot/intro.md +++ b/content/learning-paths/iot/azure-iot/intro.md @@ -1,6 +1,6 @@ --- # User change -title: "Azure IoT" +title: "Overview" weight: 2 @@ -22,6 +22,12 @@ Azure IoT's powerful analytics capabilities are delivered through services such Overall, Azure IoT offers an extensive, secure, and highly scalable environment, empowering organizations to transform data from connected devices into actionable insights, operational efficiencies, and innovative solutions, all while simplifying the complexities inherent in building and managing IoT infrastructures. -In this learning path, you’ll learn how to effectively leverage the Azure IoT ecosystem by building a complete, end-to-end IoT solution tailored specifically for Arm64-powered devices using Python. We’ll start by setting up and configuring an Azure IoT Hub, the central component that facilitates secure communication and device management. Next, we’ll register our Arm64 IoT device and use the Azure IoT Python SDK to stream real-time sensor data to the cloud. +## Learning Path objectives -Once data streaming is established, you’ll explore real-time analytics capabilities with Azure Stream Analytics, enabling immediate processing and transformation of incoming telemetry. We’ll store this streaming IoT data securely and efficiently in Azure Cosmos DB, configuring Stream Analytics to ensure seamless data persistence. To enhance our solution's robustness, you’ll implement a serverless data monitoring and alerting system using Azure Functions, automatically notifying users when sensor data exceeds predefined thresholds. Additionally, you’ll learn how to aggregate sensor readings by creating an Azure Function that calculates critical statistics like averages, minimums, and maximums. Finally, we’ll visualize and share our aggregated IoT data by publishing it to a publicly accessible web portal, built as a static web application hosted on Azure Blob Storage. \ No newline at end of file +In this Learning Path, you’ll learn how to effectively leverage the Azure IoT ecosystem by building a complete, end-to-end IoT solution tailored specifically for Arm64-powered devices using Python. + +You’ll start by setting up and configuring an Azure IoT Hub, the central component that facilitates secure communication and device management. Next, You’ll register our Arm64 IoT device and use the Azure IoT Python SDK to stream real-time sensor data to the cloud. + +Once data streaming is established, you’ll explore real-time analytics capabilities with Azure Stream Analytics, enabling immediate processing and transformation of incoming telemetry. You’ll store this streaming IoT data securely and efficiently in Azure Cosmos DB, configuring Stream Analytics to ensure seamless data persistence. To enhance our solution's robustness, you’ll implement a serverless data monitoring and alerting system using Azure Functions, automatically notifying users when sensor data exceeds predefined thresholds. + +Additionally, you’ll learn how to aggregate sensor readings by creating an Azure Function that calculates critical statistics like averages, minimums, and maximums. Finally, You’ll visualize and share our aggregated IoT data by publishing it to a publicly accessible web portal, built as a static web application hosted on Azure Blob Storage. \ No newline at end of file From cc2dd0c6a00db96e10080ab1246556206178c05d Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Tue, 13 May 2025 18:58:29 +0000 Subject: [PATCH 03/32] updates --- .../learning-paths/iot/azure-iot/iot-hub.md | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/iot-hub.md b/content/learning-paths/iot/azure-iot/iot-hub.md index 756aa0cd85..8acd934684 100644 --- a/content/learning-paths/iot/azure-iot/iot-hub.md +++ b/content/learning-paths/iot/azure-iot/iot-hub.md @@ -8,49 +8,55 @@ layout: "learningpathall" --- ## Azure IoT Hub -Azure IoT Hub is a fully managed cloud service provided by Microsoft Azure, designed as a secure, scalable communication gateway for connecting IoT devices to cloud-hosted applications and analytics systems. It acts as the core element of Azure-based IoT solutions, facilitating reliable two-way communication between millions of IoT devices and the cloud. IoT Hub supports bi-directional messaging, enabling not only device-to-cloud telemetry data transfer but also cloud-to-device commands, configuration updates, and remote device management. +Azure IoT Hub is a fully managed cloud service from Microsoft Azure, designed as a secure, scalable communication gateway for connecting IoT devices to cloud-hosted applications and analytics systems. It's the core element of Azure-based IoT solutions, supporting reliable two-way communication between millions of IoT devices and the cloud. + +IoT Hub supports bi-directional messaging, enabling not only device-to-cloud telemetry data transfer but also cloud-to-device commands, configuration updates, and remote device management. A key advantage of Azure IoT Hub is its built-in device provisioning, authentication, and management capabilities, which allow you to securely onboard, register, and manage IoT devices at scale. It supports multiple communication protocols, including MQTT, AMQP, and HTTPS, making it versatile and compatible with a broad range of devices. IoT Hub integrates seamlessly with other Azure services, such as Azure Stream Analytics, Azure Cosmos DB, Azure Functions, and Azure Blob Storage, facilitating the development of sophisticated IoT solutions with minimal complexity. Additionally, Azure IoT Hub provides monitoring and diagnostics capabilities, making it easier to identify connectivity issues, analyze device performance, and maintain operational efficiency. Its built-in security features, such as per-device authentication and secure device identity management, ensure that sensitive data remains protected throughout its lifecycle. -In the following sections of this tutorial, you’ll learn how to create and configure an Azure IoT Hub, register an Arm64-based IoT device, and utilize Python to stream sensor data securely and efficiently into Azure. +In the following sections of this Learning Path, you’ll learn how to: + +* Create and configure an Azure IoT Hub. +* Register an Arm64-based IoT device +* Utilize Python to stream sensor data securely and efficiently into Azure. ## Create Azure IoT Hub -Start by creating an Azure IoT Hub +Start by creating an Azure IoT Hub. 1. Sign in to the Azure Portal: - * Open your web browser and go to https://portal.azure.com + * Open your web browser and go to https://portal.azure.com. * Sign in using your Azure account credentials. 2. Create a new Azure IoT Hub resource -* On the Azure Portal home page, select “Create a resource” at the top left as shown below +* On the Azure Portal home page, select **Create a resource** at the top left as shown below: ![img1 alt-text#center](figures/01.png) -* In the Search services and marketplace box, type “IoT Hub” and press Enter. +* In the Search services and marketplace box, type “IoT Hub” and press **Enter**. * Click on IoT Hub from the search results: ![img2 alt-text#center](figures/02.png) -3. Click the “Create” button: +3. Click the **Create** button: ![img3 alt-text#center](figures/03.png) 4. Configure Basic IoT Hub Settings * Subscription: Select your Azure subscription. -* Resource group: Choose an existing resource group or click “Create new” to create one (e.g., rg-arm). -* IoT Hub Name: Enter a unique name for your IoT Hub (must be globally unique, e.g., iot-hub-arm-64). +* Resource group: Choose an existing resource group or click **Create new** to create one, such as *rg-arm*. +* IoT Hub Name: Enter a unique name for your IoT Hub. This must be globally unique; for example, iot-hub-arm-64). * Region: Select a region closest to your location or users. -* Tier: Free. This will update the daily message limit accordingly: +* Tier: Free. This updates the daily message limit accordingly: ![img4 alt-text#center](figures/04.png) -5. Click “Next: Networking”. +5. Click **Next: Networking**. 6. Configure Networking: * Keep the default setting (Public access) unless specific network restrictions apply. * Select 1.0 for the minimum TLS version. -* Click “Next: Management”. +* Click **Next: Management**. 7. Management Settings (Optional) * Under Management, you can keep default settings. -* Click “Next: Add-ons". -8. Add-ons - keep default settings. Then, click “Next: Tags”. -9. Add tags as needed and then click "Next: Review + Create". +* Click **Next: Add-ons**. +8. Add-ons - keep default settings. Then, click **Next: Tags**. +9. Add tags as needed and then click **Next: Review + Create**. 10. Wait for the configuration to be validated, and click Create. 11. Verify IoT Hub Deployment: * Once deployed, you’ll see a message stating “Your deployment is complete”. From f28acab26df18ef5e029fb19f4f78c4b154f2f4b Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Tue, 13 May 2025 21:46:42 -0700 Subject: [PATCH 04/32] v1, needs to be cleaned up --- content/install-guides/arm_linux_page_size.md | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 content/install-guides/arm_linux_page_size.md diff --git a/content/install-guides/arm_linux_page_size.md b/content/install-guides/arm_linux_page_size.md new file mode 100644 index 0000000000..047405bb06 --- /dev/null +++ b/content/install-guides/arm_linux_page_size.md @@ -0,0 +1,176 @@ +--- +additional_search_terms: +- linux +- cloud + +layout: installtoolsall +minutes_to_complete: 30 +author: Geremy Cohen +multi_install: false +multitool_install_part: false +title: Increasing Linux Kernel Page Size on Arm-based Systems +weight: 1 +--- + + +{{% notice Backup and Test before trying in Production%}} +Modifying the Linux kernel page size can lead to system instability or failure. It is recommended to backup your system and test the changes in a non-production environment before applying to production systems. +{{% /notice %}} + + +## Overview +Most Linux distributions ship with a default kernel page size of 4KB. When running on Arm, your options for pagesize are 4K, 16K, or 64K; this install guide walks you through install a 64K page size kernel on Arm-based Linux systems. + +## Common Steps + +1. Check the current page size: + +```bash +getconf PAGESIZE +``` +The output should be: + +```output +4096 +``` + +This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. + + +## Instructions for Ubuntu 22.04+ + +To install a 64K page size kernel on Ubuntu 22.04+, follow these steps: + +1. Install dependencies and 64K kernel: + +```bash +sudo apt-get -y update +sudo apt-get -y install git build-essential autoconf automake libtool gdb wget linux-generic-64k +``` +2. Instruct grub to load the 64K kernel by default: + +```bash +echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee /etc/default/grub.d/local-order.cfg +```` + +3. Update grub then reboot: + +```bash +sudo update-grub +sudo reboot +``` + +4. Upon reboot, check the kernel page size: + +```bash +getconf PAGESIZE +``` + +The output should be: + +```output +65536 +``` + +This indicates the current page size is 64KB. To revert back to the original 4K kernel, run the following commands: + +```bash +echo "GRUB_FLAVOUR_ORDER=generic" | sudo tee /etc/default/grub.d/local-order.cfg +sudo update-grub +sudo reboot +``` + + +## Instructions for Debian 11+ + +Unlike Ubuntu, Debian does not provide a 64K kernel via apt, so you will need to compile it from source. There are two ways to do this: 1) download the source from the kernel.org website, or 2) use the Debian source package. This guide will use the Debian source package. + +### Install from Debian Source Package (Easiest, Not Customizable) + +To install a 64K page size kernel via package manager, follow these steps: + +1. Download the kernel and cd to its directory: +```bash + +# Fetch the actual kernel source +apt source linux +# Go into the source dir +cd linux-6.1.* +``` + +### Install from kernel.org (Advanced, More Customizable) + +{{% notice Yo %}} +If you already completed the step of installing from a Debian Source Package, you can skip this section. +{{% /notice %}} + +1. Visit https://cdn.kernel.org/pub/linux/kernel/v6.x/ and download the .tar.gz of the kernel version you want to install. +2. Untar/gzip the file to its own directory. +3. Cd into the directory. + +### Common Installer Steps + +Now that you have the kernel source, follow these steps to build and install the kernel. From within the source directory, run the following commands: +```bash +# Use running config as template for new config +cp /boot/config-$(uname -r) .config + +# Modify config to enable 64K page size +sed -i 's/^CONFIG_ARM64_4K_PAGES=y/# CONFIG_ARM64_4K_PAGES is not set/' .config +sed -i 's/^# CONFIG_ARM64_64K_PAGES is not set/CONFIG_ARM64_64K_PAGES=y/' .config +echo '# CONFIG_ARM64_16K_PAGES is not set' >> .config + +# Build the kernel +make ARCH=arm64 olddefconfig + +# Set 64 for kernel name suffix +sed -i 's/^EXTRAVERSION =.*/EXTRAVERSION = -64K/' Makefile + +# Build Debian packages +make -j$(nproc) ARCH=arm64 bindeb-pkg + +# 8. Install +cd .. +sudo dpkg -i linux-image-*64k*.deb linux-headers-*64k*.deb +``` + +The system is now ready to reboot: +```bash +sudo reboot +``` +After reboot, check the kernel page size: +```bash +getconf PAGESIZE +``` +The output should be: + +```output +65536 +``` +This indicates the current page size is 64KB. To revert back to the original 4K kernel, run the following commands: + +```bash +# Revert to original kernel +sudo apt-get -y install linux-generic +sudo update-grub +sudo reboot +``` +The system will now reboot with the original 4K kernel. To check the page size, run the following command: +```bash +getconf PAGESIZE +``` + +The output should be: + +```output +4096 +``` +This indicates the current page size is 4KB. +## Conclusion +You have successfully installed a 64K page size kernel on your Arm-based Linux system. You can now take advantage of the larger page size for improved performance in certain workloads. If you need to revert back to the original 4K kernel, you can do so by following the steps outlined above. + +## Additional Resources +- [Kernel.org](https://kernel.org) +- [Debian Kernel Source](https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_kernel_source) +- [Ubuntu Kernel Source](https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel) + From ea34ebd46e98e780d1cf3ada4b9ba2642f3a4ef6 Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Wed, 14 May 2025 09:43:10 -0700 Subject: [PATCH 05/32] debian tested e2e for install/uninstall --- content/install-guides/arm_linux_page_size.md | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/content/install-guides/arm_linux_page_size.md b/content/install-guides/arm_linux_page_size.md index 047405bb06..0e0da15c6a 100644 --- a/content/install-guides/arm_linux_page_size.md +++ b/content/install-guides/arm_linux_page_size.md @@ -23,15 +23,22 @@ Most Linux distributions ship with a default kernel page size of 4KB. When runni ## Common Steps -1. Check the current page size: +1. Run apt update to ensure you have the latest package information: + +```bash +sudo apt-get -y update +``` +2. Check the current page size and kernel version: ```bash getconf PAGESIZE +uname -r ``` The output should be: ```output 4096 +6.1.0-34-cloud-arm64 ``` This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. @@ -44,7 +51,6 @@ To install a 64K page size kernel on Ubuntu 22.04+, follow these steps: 1. Install dependencies and 64K kernel: ```bash -sudo apt-get -y update sudo apt-get -y install git build-essential autoconf automake libtool gdb wget linux-generic-64k ``` 2. Instruct grub to load the 64K kernel by default: @@ -89,13 +95,19 @@ Unlike Ubuntu, Debian does not provide a 64K kernel via apt, so you will need to To install a 64K page size kernel via package manager, follow these steps: -1. Download the kernel and cd to its directory: +1. Install dependencies: + +```bash +sudo apt-get -y install git build-essential autoconf automake libtool libncurses-dev bison flex libssl-dev libelf-dev bc debhelper-compat rsync +``` + +2. Download the kernel and cd to its directory: ```bash # Fetch the actual kernel source apt source linux -# Go into the source dir -cd linux-6.1.* +# Change to kernel source dir +cd -- */ ``` ### Install from kernel.org (Advanced, More Customizable) @@ -106,11 +118,11 @@ If you already completed the step of installing from a Debian Source Package, yo 1. Visit https://cdn.kernel.org/pub/linux/kernel/v6.x/ and download the .tar.gz of the kernel version you want to install. 2. Untar/gzip the file to its own directory. -3. Cd into the directory. +3. Cd into the kernel source directory. ### Common Installer Steps -Now that you have the kernel source, follow these steps to build and install the kernel. From within the source directory, run the following commands: +Now that you have the kernel source, follow these steps to build and install the kernel: ```bash # Use running config as template for new config cp /boot/config-$(uname -r) .config @@ -124,7 +136,7 @@ echo '# CONFIG_ARM64_16K_PAGES is not set' >> .config make ARCH=arm64 olddefconfig # Set 64 for kernel name suffix -sed -i 's/^EXTRAVERSION =.*/EXTRAVERSION = -64K/' Makefile +sed -i 's/^EXTRAVERSION =.*/EXTRAVERSION = -64k/' Makefile # Build Debian packages make -j$(nproc) ARCH=arm64 bindeb-pkg @@ -141,31 +153,40 @@ sudo reboot After reboot, check the kernel page size: ```bash getconf PAGESIZE +uname -r ``` The output should be: ```output 65536 +6.12.22-64k ``` -This indicates the current page size is 64KB. To revert back to the original 4K kernel, run the following commands: +This indicates the current page size is 64K, and you are using the new customer made 64k kernel. + +## Reverting back to the original 4K kernel + +To revert back to the kernel we started with: ```bash -# Revert to original kernel -sudo apt-get -y install linux-generic +dpkg-query -W -f='${Package}\n' 'linux-image-*-64k*' 'linux-headers-*-64k*' \ + | xargs --no-run-if-empty sudo dpkg -r sudo update-grub sudo reboot ``` -The system will now reboot with the original 4K kernel. To check the page size, run the following command: +The system will now reboot into the original 4K kernel. To check the page size, run the following command: ```bash getconf PAGESIZE +uname -r ``` The output should be: ```output 4096 +6.1.0-34-cloud-arm64 ``` -This indicates the current page size is 4KB. +This indicates the current page size is 4KB and you are using the kernel you started with. + ## Conclusion You have successfully installed a 64K page size kernel on your Arm-based Linux system. You can now take advantage of the larger page size for improved performance in certain workloads. If you need to revert back to the original 4K kernel, you can do so by following the steps outlined above. From cf3dad8f8b7e06baf0e430384e91c7cf2d1ee390 Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Wed, 14 May 2025 10:28:38 -0700 Subject: [PATCH 06/32] ubuntu tested e2e for install/uninstall --- content/install-guides/arm_linux_page_size.md | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/content/install-guides/arm_linux_page_size.md b/content/install-guides/arm_linux_page_size.md index 0e0da15c6a..1331411b02 100644 --- a/content/install-guides/arm_linux_page_size.md +++ b/content/install-guides/arm_linux_page_size.md @@ -66,19 +66,25 @@ sudo update-grub sudo reboot ``` -4. Upon reboot, check the kernel page size: +4. Upon reboot, check the kernel page size and name: ```bash getconf PAGESIZE +uname -r ``` The output should be: ```output 65536 +6.8.0-59-generic-64k ``` -This indicates the current page size is 64KB. To revert back to the original 4K kernel, run the following commands: +This indicates the current page size is 64K and you are running the new 64K kernel. + +## Reverting back to the original 4K kernel + +To revert back to the original 4K kernel, run the following commands: ```bash echo "GRUB_FLAVOUR_ORDER=generic" | sudo tee /etc/default/grub.d/local-order.cfg @@ -86,6 +92,22 @@ sudo update-grub sudo reboot ``` +Upon reboot, check the kernel page size and name again: + +4. Upon reboot, check the kernel page size and name: + +```bash +getconf PAGESIZE +uname -r +``` + +The output should be: + +```output +4096 +6.11.0-1013-gcp +``` +This confirms the current page size is 4KB and you are running the original kernel. ## Instructions for Debian 11+ From a9143d7c7d65308413b46743bedca8a214c01e54 Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Wed, 14 May 2025 11:44:21 -0700 Subject: [PATCH 07/32] centos tested e2e for install/uninstall --- content/install-guides/arm_linux_page_size.md | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/content/install-guides/arm_linux_page_size.md b/content/install-guides/arm_linux_page_size.md index 1331411b02..38ac3458a4 100644 --- a/content/install-guides/arm_linux_page_size.md +++ b/content/install-guides/arm_linux_page_size.md @@ -209,6 +209,92 @@ The output should be: ``` This indicates the current page size is 4KB and you are using the kernel you started with. +## Instructions for CentOS 9+ + +To install a 64K page size kernel on CentOS 9, follow these steps: + +1. Install the kernel-64k package: + + ```bash + sudo dnf -y install kernel-64k + ``` + +2. Set the kernel-64k as the default kernel and add necessary kernel arguments: + + ```bash + k=$(echo /boot/vmlinuz*64k) + sudo grubby --set-default "$k" \ + --update-kernel "$k" \ + --args "crashkernel=2G-:640M" + ``` + + +4. Reboot the system: + + ```bash + sudo reboot + ``` + +5. Verify the page size and kernel version: + + ```bash + getconf PAGESIZE + uname -r + ``` + + The output should be: + + ```output + 65536 + 5.14.0-583.el9.aarch64+64k + ``` + +### Reverting back to the original 4K kernel on CentOS + +To revert to the original 4K kernel, run: + +```bash +# 1) Get your running kernel (should be something like "5.14.0-583.el9.aarch64+64k") +curr=$(uname -r) + +# 2) Strip the "+64k" suffix +base=${curr%+64k} + +# 3) Build the full path to the 4K kernel image +k4="/boot/vmlinuz-${base}" + +# 4) Sanity‐check that it actually exists +if [[ ! -e "$k4" ]]; then + echo "❌ Cannot find 4K kernel image at $k4" + exit 1 +fi + +echo "✅ Found 4K kernel: $k4" + +# 5) (Optional) remove any crashkernel args if you added them earlier +sudo grubby --remove-args="crashkernel=2G-:640M" --update-kernel "$k4" + +# 6) Finally, set it as the default +sudo grubby --set-default "$k4" + +# Reboot the system +sudo reboot +``` + +Upon reboot, verify: + +```bash +getconf PAGESIZE +uname -r +``` + +The output should be: + +```output +4096 + +``` + ## Conclusion You have successfully installed a 64K page size kernel on your Arm-based Linux system. You can now take advantage of the larger page size for improved performance in certain workloads. If you need to revert back to the original 4K kernel, you can do so by following the steps outlined above. From 108c4e3142673af66132602167b6490242743048 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Mon, 19 May 2025 13:42:53 +0000 Subject: [PATCH 08/32] index reviewed --- .../learning-paths/iot/azure-iot/_index.md | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/_index.md b/content/learning-paths/iot/azure-iot/_index.md index 5569afccb0..5c2906002a 100644 --- a/content/learning-paths/iot/azure-iot/_index.md +++ b/content/learning-paths/iot/azure-iot/_index.md @@ -1,22 +1,22 @@ --- -title: Create IoT Solutions in Azure for Arm-Powered Devices +title: Build IoT Solutions in Azure for Arm-Powered Devices minutes_to_complete: 180 -who_is_this_for: This is an advanced topic for developers who want to build a comprehensive IoT solution in Azure that streams, stores, monitors, aggregates, and visualizes data from Arm64-powered IoT devices. +who_is_this_for: This is an advanced topic for developers who want to build a comprehensive IoT solution in Azure that streams, stores, monitors, aggregates, and visualizes telemetry data from Arm64-powered IoT devices. learning_objectives: - - Set up and configure Azure IoT Hub. - - Register an IoT device and stream data using the Azure IoT SDK. - - Stream IoT data into Azure services using Azure Stream Analytics. - - Store and persist streamed data in Azure Cosmos DB through a Stream Analytics job. - - Monitor data and send alerts by creating an Azure Function that reads sensor data from Cosmos DB and triggers notifications when thresholds are exceeded. - - Aggregate sensor readings using an Azure Function that calculates average values from data stored in Cosmos DB. - - Publish aggregated IoT data to a public-facing web portal, by deploying a static web app hosted on Azure Blob Storage. + - Set up and configure Azure IoT Hub for device communication. + - Register an IoT device and stream telemetry data using the Azure IoT SDK. + - Route IoT data to Azure services using Azure Stream Analytics. + - Store incoming data in Azure Cosmos DB through a Stream Analytics job. + - Monitor data and send alerts using an Azure Function that reads from Cosmos DB and triggers notifications based on thresholds. + - Aggregate sensor readings using an Azure Function that calculates average values from stored data. + - Publish aggregated data to a public-facing web app hosted on Azure Blob Storage. prerequisites: - A machine with Python 3, and Visual Studio Code installed. - - An Azure Account and subscription. + - An active Azure account with sufficient permissions to create resources (such as IoT Hub, Functions, and Cosmos DB). author: Dawid Borycki @@ -31,6 +31,7 @@ operatingsystems: - Linux - macOS tools_software_languages: + - Python - Azure - VS Code From 8644563feb70fbb0e85cc97377af3a29943265ef Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Mon, 19 May 2025 14:19:11 +0000 Subject: [PATCH 09/32] updates --- content/learning-paths/iot/azure-iot/intro.md | 10 +++++++--- content/learning-paths/iot/azure-iot/iot-hub.md | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/intro.md b/content/learning-paths/iot/azure-iot/intro.md index 75121062d0..79795b9b8c 100644 --- a/content/learning-paths/iot/azure-iot/intro.md +++ b/content/learning-paths/iot/azure-iot/intro.md @@ -8,15 +8,19 @@ layout: "learningpathall" --- ## Introduction to Internet of Things -The Internet of Things (IoT) is a technological landscape where physical devices, vehicles, buildings, and everyday objects become interconnected, enabling them to communicate, exchange data, and operate collaboratively without direct human intervention. IoT has immense potential across various industries, including manufacturing, healthcare, agriculture, logistics, and smart homes, where it enhances operational efficiency, productivity, safety, and convenience. By collecting and analyzing real-time data from interconnected sensors and devices, IoT solutions help businesses make informed decisions, predict maintenance needs, optimize resource usage, and create innovative user experiences. +The Internet of Things (IoT) is a technological landscape where physical devices - such as vehicles, buildings, and everyday objects - become interconnected, enabling them to communicate, exchange data, and operate collaboratively with minimal human intervention. IoT has transformative potential across industries like manufacturing, healthcare, agriculture, logistics, and smart homes, enhancing operational efficiency, productivity, safety, and convenience. + +By collecting and analyzing real-time data from interconnected sensors and devices, IoT solutions empower businesses to make informed decisions, predict maintenance needs, optimize resource usage, and deliver innovative user experiences. ## IoT and Arm Devices -In the context of IoT applications, Arm64-powered devices play a crucial role due to their superior performance, efficiency, and energy optimization capabilities. Arm64, also known as ARMv8-A or AArch64, is a 64-bit architecture widely adopted in mobile devices, embedded systems, edge computing devices, and single-board computers such as Raspberry Pi 4, NVIDIA Jetson, and similar hardware platforms. These devices are characterized by their low power consumption, compact size, and cost-effectiveness, making them ideally suited for battery-operated scenarios, remote monitoring systems, edge analytics, and IoT deployments in environments where power and computational efficiency are critical. Leveraging Arm64-based IoT solutions enables developers and organizations to build intelligent, scalable, and energy-efficient systems, thereby significantly reducing operational costs while maximizing performance. +Arm64-powered devices play a critical role in IoT applications due to their superior performance, efficiency, and energy optimization capabilities. Arm64, also known as AArch64, is a 64-bit architecture widely adopted in mobile devices, embedded systems, edge computing devices, and single-board computers such as Raspberry Pi 4, NVIDIA Jetson, and similar hardware platforms. + +These devices are compact, cost-effective, and energy-efficient, making them ideally suited for battery-operated scenarios, remote monitoring systems, edge analytics, and IoT deployments in environments where power and computational efficiency are critical. By leveraging Arm64-based devices, developers can build intelligent, scalable, and energy-efficient IoT solutions that reduce operational costs while maximizing responsiveness and uptime. ## Azure IoT Azure IoT is a cloud platform provided by Microsoft, designed to build, deploy, and manage scalable Internet of Things (IoT) solutions across various industries. It offers a suite of managed services and tools that facilitate secure device connectivity, data ingestion, real-time analytics, data storage, monitoring, and visualization. By leveraging Azure IoT, organizations can seamlessly integrate diverse IoT devices, sensors, and applications into robust cloud-based solutions, making it ideal for scenarios ranging from predictive maintenance and smart manufacturing to remote asset monitoring and smart cities. -At the heart of Azure IoT is the Azure IoT Hub, a fully managed, secure communication gateway enabling reliable and bi-directional communication between millions of IoT devices and the cloud. IoT Hub simplifies device management through secure provisioning, authentication, and connectivity. Complementary services like Azure IoT Central provide ready-to-use IoT solutions with minimal coding, allowing rapid prototyping and deployment of IoT applications, especially suitable for businesses looking to accelerate time-to-value. +At the center of Azure IoT is the Azure IoT Hub, a fully managed, secure communication gateway enabling reliable and bi-directional communication between millions of IoT devices and the cloud. IoT Hub simplifies device management through secure provisioning, authentication, and connectivity. Complementary services like Azure IoT Central provide ready-to-use IoT solutions with minimal coding, allowing rapid prototyping and deployment of IoT applications, especially suitable for businesses looking to accelerate time-to-value. Azure IoT's powerful analytics capabilities are delivered through services such as Azure Stream Analytics and integration with Azure Cosmos DB. These tools enable real-time processing, storage, and analysis of high-velocity IoT data streams, facilitating timely decision-making and proactive monitoring. Additionally, serverless offerings such as Azure Functions further enhance flexibility, allowing businesses to build event-driven applications that react instantly to IoT events and sensor readings. diff --git a/content/learning-paths/iot/azure-iot/iot-hub.md b/content/learning-paths/iot/azure-iot/iot-hub.md index 8acd934684..b30836523c 100644 --- a/content/learning-paths/iot/azure-iot/iot-hub.md +++ b/content/learning-paths/iot/azure-iot/iot-hub.md @@ -20,7 +20,7 @@ In the following sections of this Learning Path, you’ll learn how to: * Create and configure an Azure IoT Hub. * Register an Arm64-based IoT device -* Utilize Python to stream sensor data securely and efficiently into Azure. +* Use Python to stream sensor data securely and efficiently into Azure. ## Create Azure IoT Hub Start by creating an Azure IoT Hub. @@ -60,7 +60,7 @@ Start by creating an Azure IoT Hub. 10. Wait for the configuration to be validated, and click Create. 11. Verify IoT Hub Deployment: * Once deployed, you’ll see a message stating “Your deployment is complete”. -* Click “Go to resource” to open the newly created Azure IoT Hub. +* Click **Go to resource** to open the newly-created Azure IoT Hub. 12. Check IoT Hub Overview and Details. From the IoT Hub overview page, verify important details such as the hub name, region, status, and hostname, which you’ll use to connect devices: ![img5 alt-text#center](figures/05.png) From 0df2f01c98f4fa07f12934a4795796926ea55972 Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Mon, 19 May 2025 15:12:25 -0700 Subject: [PATCH 10/32] Adding various OS pages. Added new overview and index. --- .../arm_linux_page_size/_index.md | 62 +++++++++++++++++++ .../arm_linux_page_size/centos.md | 41 ++++++++++++ .../arm_linux_page_size/debian.md | 47 ++++++++++++++ .../arm_linux_page_size/overview.md | 55 ++++++++++++++++ .../arm_linux_page_size/ubuntu.md | 42 +++++++++++++ 5 files changed, 247 insertions(+) create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md new file mode 100644 index 0000000000..475ec4d7a4 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md @@ -0,0 +1,62 @@ +--- +title: Increasing Linux Kernel Page Size on Arm + +minutes_to_complete: 30 + +who_is_this_for: This Learning Path is for developers who want to modify the Linux kernel page size on Arm-based systems to improve performance for memory-intensive workloads. + +learning_objectives: + - Verify the current page size on your system. + - Install the 64K page size kernel specific to your OS. + - Verify the new 64K page size is active. + - Revert to the default 4K page size kernel (optional). + +prerequisites: + - Arm-based Linux system + - Ubuntu [20.04 LTS or newer](https://releases.ubuntu.com/20.04/) + - Debian [11 “Bullseye” or newer](https://www.debian.org/releases/bullseye/) + - CentOS [9 or newer](https://www.centos.org/download/) + +author: + - Geremy Cohen + +layout: learning-path +author: Geremy Cohen + +skill_level: Intermediate +subjects: Performance and Architecture +cloud_service_providers: Google Cloud + +armips: + - Neoverse + +operatingsystems: + - Linux + +tools_software_languages: + - bash + +further reading: +- resource: + title: Page (computer memory) – Wikipedia + link: https://en.wikipedia.org/wiki/Page_(computer_memory) + type: documentation +- resource: + title: Debian Kernel Source Guide + link: https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_kernel_source + type: documentation +- resource: + title: Ubuntu Kernel Build Docs + link: https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel + type: documentation +- resource: + title: CentOS Kernel Modules Guide + link: https://docs.centos.org/en-US/centos/install-guide/kernel-modules/ + type: documentation + +### FIXED, DO NOT MODIFY +# ================================================================================ +weight: 1 # _index.md always has weight of 1 to order correctly +layout: "learningpathall" # All files under learning paths have this same wrapper +learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content. +--- \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md new file mode 100644 index 0000000000..7789a33c0d --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md @@ -0,0 +1,41 @@ +--- +layout: learning-path +title: Increasing Linux Kernel Page Size on Arm (CentOS) +author: Geremy Cohen +minutes_to_complete: 30 +skill_level: Intermediate +os: CentOS +categories: + - Performance and Architecture +tools: + - Bash + - yum, grubby +weight: 4 +--- + +## 1. Common Setup +- Verify you’re on 4 KB pagesize: + ```bash + getconf PAGESIZE # should print 4096 + ``` +- Backup `/boot` and `/etc`, or snapshot your VM + +## 2. Install & Reboot +```bash +sudo yum install kernel-64k +sudo grubby --set-default /boot/vmlinuz-*-64k +sudo reboot +``` + +## 3. Verify 64 KB is Active +```bash +getconf PAGESIZE # should now print 65536 +uname -r # confirm “-64k” suffix +``` + +## 4. Revert to 4 KB Pagesize +```bash +sudo yum remove kernel-64k +sudo grubby --remove-kernel /boot/vmlinuz-*-64k +sudo reboot +``` \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md new file mode 100644 index 0000000000..684fdc4631 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md @@ -0,0 +1,47 @@ +--- +layout: learning-path +title: Increasing Linux Kernel Page Size on Arm (Debian) +author: Geremy Cohen +minutes_to_complete: 30 +skill_level: Intermediate +os: Debian +categories: + - Performance and Architecture +tools: + - Bash + - apt, dpkg, make +weight: 3 +--- + +## 1. Common Setup +- Verify you’re on 4 KB pagesize: + ```bash + getconf PAGESIZE # should print 4096 + ``` +- Backup `/boot` and `/etc`, or snapshot your VM + +## 2. Build & Install Kernel & Reboot +```bash +sudo apt-get update +apt-get source linux-image-$(uname -r) +cd linux-*/debian +# Edit debian/rules: set DEB_PAGESIZE=65536 +DEB_PAGESIZE=65536 dpkg-buildpackage -b -us -uc +sudo dpkg -i ../linux-image-*.deb ../linux-headers-*.deb +sudo update-grub +sudo reboot +``` + +## 3. Verify 64 KB is Active +```bash +getconf PAGESIZE # should now print 65536 +uname -r # confirm custom build +``` + +## 4. Revert to 4 KB Pagesize +```bash +sudo apt-get remove --purge linux-image-* +sudo apt-get install --reinstall linux-image-$(uname -r | sed 's/-[^-]*$//') +sudo update-grub +sudo reboot +``` \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md new file mode 100644 index 0000000000..29fa8c620e --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md @@ -0,0 +1,55 @@ +--- +title: Page Size Overview +weight: 1 +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## How the CPU Locates Your Data + +When your program asks for a memory address, the CPU doesn’t directly reach into RAM or swap space for it; that would be slow, unsafe, and inefficient. + +Instead, it goes through the **virtual memory** system, where it asks for a specific chunk of memory called a **page**. Pages map virtual memory location to physical memory locations in RAM or swap space. + +## Page Size Differences Illustrated + +To help make page sizing more clear, assume you have created a database system that can store and retrieve either images, OR tweets, based on the mode set at install-time. + +### 4K Page Size +With our system set to a 4K page size, the system can only store a small amount of data in each page. At around 300 bytes per tweet, when the system retrieves a tweet from memory, it will most likely be retrieved in a single page load. This is very efficient, since the CPU has to do less work to find the data it needs, and the structure size (page) is optimized for the size of the data its storing (tweet). At 4K, best-case, the system can store about 13 tweets in a single 4K page. For every 13 tweets kept in memory ready for access by the app, the system reserves a single 4K page. + +When the system is set to "Image Only" mode, since an image is a larger amount of data (assume 1MB or more for this example), it will most likely be retrieved in multiple 4K page loads. This is less efficient, as the CPU has to do more work to retrieve all bytes of the image. If the image is 1MB, the system will have to reserve 256 4K pages (256 * 4K = 1MB). + +Given this info, you decide to set the page size to 64K to see how performance changes. + +### 64K Page Size +With our system now set to 64K page size, the system reserves pages in 64K chunks. In our tweet example, we can now store about 218 tweets per page. If we're working with groupings of the same tweets over and over, the system needs to reserve and load fewer pages to get the data it needs to run the application, resulting in a fast and efficient system. This is because the CPU has to do less page loads to find the data it needs. + +When the system is set to "Image Only" mode, since an image is a larger amount of data (1MB or more), the image will still need to be retrieved in multiple 64K page loads. However, this is more inefficient than the 4K page size; if the image is 1MB, the system will only need to load and store 16 pages at a 64K page size (16 * 64K = 1MB) vs 256 pages of memory (256 * 4K = 1MB) at a 4K page size. + +### Inefficiencies +Inefficiencies occur when the system is set to a page size that does not consistently match the data size of the objects you are working with. For example, if the system is set to 64K page size, and the application only needs one tweet, the system loaded more data (a 64K page) than was actually needed. + +In another example, the system needs to retrieve 256 tweets. If by coincidence, all 256 are on that single page which is highly unlikely, it would be EXTREMELY efficient to just load that single page. Most likely, multiple pages will need to be loaded if each tweet is stored on a separate page. + +When loading a single image, with the page size is larger, the page size is better rightsized for the data the application works with -- it may need to load 16 pages of 64K each, but it is still less than the 256 pages of 4K each that it would need to load if the system was set to 4K page size. + +In addition to the amount of page loading the CPU has to do, the system also has to reserve memory to store and track metadata for each page. If the system is set to 4K page size, and it needs to load 256 pages of 4K each, it will need to reserve 1MB of memory (256 * 4K = 1MB) just to maintain the page tables. Fragmentation can occur when the system reserves memory for pages that are not used and/or modified, and this can lead to wasted memory and performance issues especially with larger page sizes. + +To add further complexity, if you choose to add the ability for the system to store BOTH images and tweets (not one at a time), the system will need to load both types of data, and the page size will need to be set to a size that is best suited to accommodate both types of data and their retrieval patterns. + +This leads to more performance hits, as the system will most likely now always load fewer or more pages than necessary for each type of data. + +It may be difficult to determine the best page size for your application, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application and data size changes. + +This learning path will guide you how to change the page size, so you can begin experimenting to see which fits best. + +## Choose Your OS + +To begin, select the OS you are using. The steps to install the 64K page size kernel are different for each OS, so be sure to select the correct one. + +- [Ubuntu](ubuntu.md) +- [Debian](debian.md) +- [CentOS](centos.md) + +--- diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md new file mode 100644 index 0000000000..a79c7c3518 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md @@ -0,0 +1,42 @@ +--- +layout: learning-path +title: Increasing Linux Kernel Page Size on Arm (Ubuntu) +author: Geremy Cohen +minutes_to_complete: 30 +skill_level: Intermediate +os: Ubuntu +categories: + - Performance and Architecture +tools: + - Bash + - apt, dpkg +weight: 2 +--- + +## 1. Common Setup +- Verify you’re on 4 KB pagesize: + ```bash + getconf PAGESIZE # should print 4096 + ``` +- Backup `/boot` and `/etc`, or snapshot your VM + +## 2. Download / Install / Compile & Reboot +```bash +sudo apt update +sudo apt install linux-image-6.1.0-64k linux-headers-6.1.0-64k +sudo update-grub +sudo reboot +``` + +## 3. Verify 64 KB is Active +```bash +getconf PAGESIZE # should now print 65536 +uname -r # confirm “-64k” suffix +``` + +## 4. Revert to 4 KB Pagesize +```bash +sudo apt remove linux-image-*-64k +sudo update-grub +sudo reboot +``` \ No newline at end of file From 66290fb7e6cb76ed1fed5f1bfe60b9639ed47fdd Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Mon, 19 May 2025 17:59:08 -0700 Subject: [PATCH 11/32] Final tweaks made. Will test and style next. --- content/install-guides/arm_linux_page_size.md | 2 +- .../arm_linux_page_size/_next-steps.md | 8 ++ .../arm_linux_page_size/centos.md | 121 ++++++++++++---- .../arm_linux_page_size/debian.md | 136 +++++++++++++----- .../arm_linux_page_size/images/pte.png | Bin 0 -> 231959 bytes .../arm_linux_page_size/overview.md | 26 ++-- .../arm_linux_page_size/ubuntu.md | 104 ++++++++++---- 7 files changed, 292 insertions(+), 105 deletions(-) create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_next-steps.md create mode 100644 content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/images/pte.png diff --git a/content/install-guides/arm_linux_page_size.md b/content/install-guides/arm_linux_page_size.md index 38ac3458a4..7d0d08b386 100644 --- a/content/install-guides/arm_linux_page_size.md +++ b/content/install-guides/arm_linux_page_size.md @@ -185,7 +185,7 @@ The output should be: ``` This indicates the current page size is 64K, and you are using the new customer made 64k kernel. -## Reverting back to the original 4K kernel +### Reverting back to the original 4K kernel To revert back to the kernel we started with: diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_next-steps.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_next-steps.md new file mode 100644 index 0000000000..c3db0de5a2 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_next-steps.md @@ -0,0 +1,8 @@ +--- +# ================================================================================ +# FIXED, DO NOT MODIFY THIS FILE +# ================================================================================ +weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation. +title: "Next Steps" # Always the same, html page title. +layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing. +--- diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md index 7789a33c0d..3028606ef5 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md @@ -1,41 +1,104 @@ --- -layout: learning-path -title: Increasing Linux Kernel Page Size on Arm (CentOS) -author: Geremy Cohen -minutes_to_complete: 30 -skill_level: Intermediate -os: CentOS -categories: - - Performance and Architecture -tools: - - Bash - - yum, grubby -weight: 4 +title: Centos Page Size Modification +weight: 5 +### FIXED, DO NOT MODIFY +layout: learningpathall --- -## 1. Common Setup -- Verify you’re on 4 KB pagesize: - ```bash - getconf PAGESIZE # should print 4096 - ``` -- Backup `/boot` and `/etc`, or snapshot your VM +### Verify current page size +Verify you’re on a 4 KB pagesize kernel: -## 2. Install & Reboot ```bash -sudo yum install kernel-64k -sudo grubby --set-default /boot/vmlinuz-*-64k -sudo reboot +getconf PAGESIZE +uname -r ``` +The output should be similar to (the important part is the 4096 value): -## 3. Verify 64 KB is Active -```bash -getconf PAGESIZE # should now print 65536 -uname -r # confirm “-64k” suffix +```output +4096 +6.1.0-34-cloud-arm64 ``` -## 4. Revert to 4 KB Pagesize +This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. + + +### Install the kernel-64k package: + + ```bash + sudo dnf -y install kernel-64k + ``` + +### Set the kernel-64k as the default kernel and add necessary kernel arguments: + + ```bash + k=$(echo /boot/vmlinuz*64k) + sudo grubby --set-default "$k" \ + --update-kernel "$k" \ + --args "crashkernel=2G-:640M" + ``` + +### Reboot the system: + + ```bash + sudo reboot + ``` + +### Verify the page size and kernel version: + + ```bash + getconf PAGESIZE + uname -r + ``` + + The output should be: + + ```output + 65536 + 5.14.0-583.el9.aarch64+64k + ``` + +## Reverting back to the original 4K kernel on CentOS + +To revert to the original 4K kernel, run: + ```bash -sudo yum remove kernel-64k -sudo grubby --remove-kernel /boot/vmlinuz-*-64k +# 1) Get your running kernel (should be something like "5.14.0-583.el9.aarch64+64k") +curr=$(uname -r) + +# 2) Strip the "+64k" suffix +base=${curr%+64k} + +# 3) Build the full path to the 4K kernel image +k4="/boot/vmlinuz-${base}" + +# 4) Sanity‐check that it actually exists +if [[ ! -e "$k4" ]]; then + echo "Cannot find 4K kernel image at $k4" + exit 1 +fi + +echo "Found 4K kernel: $k4" + +# 5) (Optional) remove any crashkernel args if you added them earlier +sudo grubby --remove-args="crashkernel=2G-:640M" --update-kernel "$k4" + +# 6) Finally, set it as the default +sudo grubby --set-default "$k4" + +# Reboot the system sudo reboot +``` + +Upon reboot, verify: + +```bash +getconf PAGESIZE +uname -r +``` + +The output should be: + +```output +4096 + ``` \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md index 684fdc4631..443bc0d60b 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md @@ -1,47 +1,111 @@ --- -layout: learning-path -title: Increasing Linux Kernel Page Size on Arm (Debian) -author: Geremy Cohen -minutes_to_complete: 30 -skill_level: Intermediate -os: Debian -categories: - - Performance and Architecture -tools: - - Bash - - apt, dpkg, make -weight: 3 +title: Debian Page Size Modification +weight: 4 +### FIXED, DO NOT MODIFY +layout: learningpathall --- -## 1. Common Setup -- Verify you’re on 4 KB pagesize: - ```bash - getconf PAGESIZE # should print 4096 - ``` -- Backup `/boot` and `/etc`, or snapshot your VM - -## 2. Build & Install Kernel & Reboot -```bash -sudo apt-get update -apt-get source linux-image-$(uname -r) -cd linux-*/debian -# Edit debian/rules: set DEB_PAGESIZE=65536 -DEB_PAGESIZE=65536 dpkg-buildpackage -b -us -uc -sudo dpkg -i ../linux-image-*.deb ../linux-headers-*.deb -sudo update-grub -sudo reboot +Debian does not provide a 64K kernel via apt, so you will need to compile it from source. There are two ways to do this: 1) download the source from the kernel.org website, or 2) use the Debian source package. This guide will use the Debian source package. + +### Verify current page size +Verify you’re on a 4 KB pagesize kernel: + +```bash +getconf PAGESIZE +uname -r +``` +The output should be similar to (the important part is the 4096 value): + +```output +4096 +6.1.0-34-cloud-arm64 +``` + +This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. + + +### Install from Debian Source Package (Easiest, Not Customizable) + +To install a 64K page size kernel via package manager, follow these steps: + +First, install dependencies: + +```bash +sudo apt-get -y install git build-essential autoconf automake libtool libncurses-dev bison flex libssl-dev libelf-dev bc debhelper-compat rsync +``` + +Download the kernel and cd to its directory: +```bash + +# Fetch the actual kernel source +apt source linux +# Change to kernel source dir +cd -- */ +``` + +## Build and install the kernel + +Now that you have the kernel source, follow these steps to build and install the kernel: +```bash +# Use running config as template for new config +cp /boot/config-$(uname -r) .config + +# Modify config to enable 64K page size +sed -i 's/^CONFIG_ARM64_4K_PAGES=y/# CONFIG_ARM64_4K_PAGES is not set/' .config +sed -i 's/^# CONFIG_ARM64_64K_PAGES is not set/CONFIG_ARM64_64K_PAGES=y/' .config +echo '# CONFIG_ARM64_16K_PAGES is not set' >> .config + +# Build the kernel +make ARCH=arm64 olddefconfig + +# Set 64 for kernel name suffix +sed -i 's/^EXTRAVERSION =.*/EXTRAVERSION = -64k/' Makefile + +# Build Debian packages +make -j$(nproc) ARCH=arm64 bindeb-pkg + +# 8. Install +cd .. +sudo dpkg -i linux-image-*64k*.deb linux-headers-*64k*.deb ``` -## 3. Verify 64 KB is Active +The system is now ready to reboot: +```bash +sudo reboot +``` +After reboot, check the kernel page size: ```bash -getconf PAGESIZE # should now print 65536 -uname -r # confirm custom build +getconf PAGESIZE +uname -r +``` +The output should be: + +```output +65536 +6.12.22-64k ``` +This indicates the current page size is 64K, and you are using the new customer made 64k kernel. + +## Reverting back to the original 4K kernel + +To revert back to the kernel we started with: -## 4. Revert to 4 KB Pagesize ```bash -sudo apt-get remove --purge linux-image-* -sudo apt-get install --reinstall linux-image-$(uname -r | sed 's/-[^-]*$//') +dpkg-query -W -f='${Package}\n' 'linux-image-*-64k*' 'linux-headers-*-64k*' \ + | xargs --no-run-if-empty sudo dpkg -r sudo update-grub sudo reboot -``` \ No newline at end of file +``` +The system will now reboot into the original 4K kernel. To check the page size, run the following command: +```bash +getconf PAGESIZE +uname -r +``` + +The output should be: + +```output +4096 +6.1.0-34-cloud-arm64 +``` +This indicates the current page size is 4KB and you are using the kernel you started with. \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/images/pte.png b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/images/pte.png new file mode 100644 index 0000000000000000000000000000000000000000..21ba1088a310a0269904d51f8f98f5da0c2333ce GIT binary patch literal 231959 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

;EZJ90<<+W=*pFz;XA_3N zqEOnH_GviAzuM_2%6jjZrU@VY=!ft%uY5HC;GP%XgL~iqKHPZYO;Akuo!@x}o^jX9 z@rVEZb$HSfZiAjZhlef$yQ>|S=OhD(qcBE1LnwR*Qd7{)!`p0v1h(7S%|7gm1{Oa- z)v#%59`l|%s69f~jY%i5E8#?2*oC}(p=;UEY9{Dn!Q!Ee(B_GHVY@|5?AVqln9E2e zKSfkS$Q71{CtN-7uxS{xh>unC{JP0D6Cmhzbf=!E01!up1VB@BK}B*kA9GhbcEen)hG(cxpiVYoh4Im_KAKG*g`pC!tRTFGVx1I@E+f3ECo?Kn{s0gF|EmY49L7B}R zBO7-?bwBdv{fV0LXsT(;l6+Mlt@%;0j)nAE+qhFKqfm*$LnTW19n`03BX&6 z%vN>7Vlu&t?$ql?)X-eWDWI)k5>ryMCuOG2jW0gOHg?H&X})y9uJPom;jK+ZS7HaR z4W|t_zHP!2&H~^3>aW4KeC=1^M}PJW_-o(zYJB=F$9UQ^J`Y!}p5W}cGkDrFo{Cqz z;=jQ!{?aew%l_P#V!PYnXjAhIES^(@k-aYk5T>`|Z?u@!ZNF1GF7IUJ=b?nkzMU$E zTdxnxjB;*i2xj4RgYJNtSMAf`^(m08!M$d+9%!T5i`mv%SxSr*JeSX^2|Sf{=hw7WvuKg7@PFe;td|_G-e(nz+zJIRivE~WX>6JRwW|kIO{lUbZ7!OmOV-8$DQJG1|**_f@}cGVJgQM<7j<2 zNt3o>0Wl~CA5S;~y$yG+xb?A+%auN?ZR1--CLX8k5=Vn({~ZM`>qQ`b<$M{VHguVM zMg_LTWfL>c+oXA-vkvW$6jvFdRrGMl>wXeXsfb8MAp)Fs#$FEVq$Nn)a+RTj>w|fz zjSOdru+!p&_n?ewGSb9Qwk;|x1l6hz9cLj>CnJW&c;)d;%0wCAgrysJ&wU@jcYeor z;Cavg5?s1?2`94xn+eBfkMNGSza8KFH@_AC^S6FCp8TXw$M#&u$$SMDE?z+I+fY3{ zqUK!AFjpUq>ZT!fjb*E@b-5t`y4m_drvhwKDEzjQ{j>Fp#KkumMD{QVY1^uqGFNAzLvDI=3t^I&_*YTv$*4HhW`e0 zicBid3E+k09f&j-DuPMW)3f;+!BYv*u>z>cS+1J|<`{vAB24Z?5wWAXD0#-F zW30SR-Gc3c#7QT#%XXv{VV=|%L$p) zC9Mc|H1Q~}i1`)Ho;iyrJ@Hoj_uufB@ahW zqcz2|@3;fs{WtywZn^bVeA7356S^fp8urd80`_Hm6%G3`whUoUgl(vftYC&VE|o-8 zIE(aGW0TbXo;2$Z-+M3K{?<3+WiNXvK5*{`ar3$JXvgR9+wXWg{Z7?pq0kXPER_&s27rz}!EQ>@ z3O-4s7)!pOraZ$2wo6m&Ue@SgC{S@|F2)6x3`5zn89{oYek)d09!9a|_2$nG8<|_& zfbn|9*RGbFSm|ilkI~7wH=Bl1%>;1U*?Zdr70&}_4himrR>m~PTAs^yxrCZ&J%h)k zc+nkKbw^Qs9*R*B!p4QW?9Axmu1xG45i8%)i8)U-*T1(q}vgvs!+kg-AgF7DmX5=qU!9ly?zPSPHMUzj$K(C9){7 zUtX4fF#A`|U=h4gt-NCb z*}z0Wm^eba0}KHdqj~dD!A0Y5m69c8{1By3BRO0qhUZhA;Vn@zXz0W^dS#X}_EJA? zm*j7ZLJ5;(Ad-NyEJRx`coe2Rghl_ zG9%JW2XKRCgD=$KXGAEShRxwLylV3e0xA?}TDHVb^sR_hTeXhs5imvKSqz5Y9@-nk zc_bDmymZJ-2&LQ?xF6;SU~<)oGW>qviCH;C#~p%XfU*`^_;`l;tu#<= z06}c{4P#jJos_ZP!#bRMn#{$rVwxH*UAcmned(9uPd(*!T;1+)>Et4Axba4uJ3hwS z-tsp5@~`|FzVu};!Gk9c;NB}A#`fygPZ>0*&MCi~zPl&nFXt4jPrqzMJM&SBEdu6w zM5F+5u}yb5HIwFH-j>0LAeIf3?`))k=(8D-BdyKO; z-;B4u<<0n4Z+Z*9>_yMR`yZL{(MM;Tn;JHo4UU>%*JVgt4hjB*iiImBp}2iOCkz>x zcDgJ1spx7En74WMg{=#hjgN;;kgkG;$iodW8jX!D1|fxA>T-#U0wQiV2<`0^Aak9Z8T>;Fb~eoaRY#2wB%GR}IWWMv=JexoZJI_&r=5y5(T|5mjHJ7i9s&WI0$-k?eI{PN@ z^ah_E>7^eVkXh6d;E^GxCuI%vGk>K{H+=}}jd>20N zbML^r-t}&L{ukVVM<2U@7d-z3`0*eAKk%}bz67uNy4QFFp8=CB9};8u6VD;bDtK82 z<6y10md}(*wePXK1Yc<>&&G2{ZLd~-UKO67%Cp4Gis810t_4&p-78Z3FLdF-I;>gq zGYxn-5K?-``?R(L$)>vsc!g`|507B%6t<1l+vK~3#RwQ8GK#e*02m2Cp(ou0WgHK3 zcn0O?LU2HqTXUf(C4U>n?e8Ioh@2oGhjUPlY0&NQMq{+355uDYhrXd13a9mR5gsw7 ziXX>IwW4CIR6vx!3W(M0&;lL#uc33L@>JhbwM(Ke+iQk=ABKpIuGYPzM zi?htx!l^SLK8znapa=_hM=L(66lsayGEIOx2*h?_#T{>!tECs()})2tA&v1S{;MN` zuQKYhXgmAY3Z6+5z7VK=sWxxZ-#I-}ZYk8p!KCVyPB;cGTFNf6k%JbSlCs%pD-0<~ zIwn3jF7i!`k7M_FCI3iiOMJk^VM&&+w|NDQ%jTBQIA9;hd8^S|Qt{Y%WRI)(k;b@? z2)IPRTixt9iNeAY=IkS6j|QkQKS1C;Zw9RNXk)jvh`=sd6*N7f6dMGFk& z8Oc!7V$@BTkRJ=xx+equ$HTZ71o<^_HoyQomZJ*%>M#EqKKS1E;O@J=7@xfG2yVLJ z2B6P)+gsj-U;Wiz$36GF7{C9>@8R-%f~jpFu&8@$Z{wSN3Y|=EDC`C>aVLV%_73^A zkh^kJHml94V9`DeJvMxdP#Tk*`>uQ!OPXvk`GCUUo3vYWh>Bm#!WcO~o7w*}6iw~s z-PsdBG*xs)`upZ|qXR1zWe)0O1eWJbW|yQBL_4I}@imJy%AnJxhI>pKv)5;Z91EIk zpgYNXahgJ8Q^rXROam>8Ao7S8`-LAM+#6?t1fVrz5^-;`z zwHy@bgi&)M%(D?$hdE2S7_-dc$BNpx@keJXyW<*zc)@Irj^5#(azURvRA%%E*ox)E zQHA9Nq%8HZam}#vG9mCaok0-$JI8Lkg0^O^Cp493Gl4R9#oVo~T}y{JQs2Fk6IJZg za@)`W1vLSuJKNdRF3=f{JHvmU6@9i{s~v#ZkG1U-IH3*bf~hj#k8~f)5c)S8&oI2O6Q8revV-}+yIMcu9%~a78g$vjjNh5l ztv1Hq)oIWsvCnGwahXzdj^FYYwykCH*Bk)blbz8|(4IJb`ajNnR{(xSm27}5fVtu9 zMsV)T23PxpcYSn+%Q%Z)dB<-804`s;jJbF0{Ce4Uz5Dm^$xmLu(bO={F5HKxjQvOU zKIEf?XZU^9e)L~xgr%6VZ@SWUHRkg*8`qWgxe#8o0bTxj@VRC=4I6ve#WgF}*9+VF zda9>6vou8OrvbVAToi=XSBKRKdBZ-}woQ>YwkUv3TL^aGwWD!#iNwK3mT*ou4>h{} zi-$Xe8DZ8kZbdpA?6(L8q5;qm_4aTQ3;iCy^(a85lKdVRQslzABOFF0ijOiu!|M#w z3H9pu06Pt8Mo&hcBE^}}?H?Uw0C;3HawAcZQZY~n#dsx^j@Hi{Z>dvIHsWG|$Fl3K zQP|;U7&ruRZkTm~%K6#rYWZD#cenev=|m|zUD1BP&H6p(n7DMUuaqUsIRi%4)bRpw z^aozP&|)5mX$b?JAJuvzVQK1$z~RDK5Io~!PkKt!1-|>j0T%R(giFl8HnM7Qn^xB0 z7$xzwCVV5}r@~(V+w+7KSjtbf0Cb$To;1O>8IcEtt%4THB%;XtcdkB#azzl{VAYZbe&Dks$f<@-*xB=*ikCW zuu54Z+Re$TmZh_Ml)a*3=c^-YYc4+89n>Qv>lR8=v%&>4RCzhL$&%Fd3RTN)I+yoz z?`W7U>P8gM*_;NdmfHp$(4E7RGS60GJ6K-M8PWx97KkrA%+a7;)|?tG617UqEw8hm z`w3>3OH%{j`buFZSK8n>&(U|THF}3?_x%mSsWxDqc2J!$Pr%#+vxq}(r()DIz5Ki20J)>}OX+p}JRZ3Tp!|j_QfQITc z$BZq0W|cg#?rt}Z0VS~JJajt2qVRL~u% z!<|(fGn^LC(Zq4vcj(>tp!*tng4rP5!60G=Zh8*B>dRh$ z$J&I4F9PSL2~#)c0G-FJ`$D;AWClX78y2MeZiFXsEGBF!@o83As9H+`Yk-~E^l*#@ zL>N3HWN0@d>=IklNA#LIEy7Mx6pxfxq>L2XOD){dNY;eygcKImrjN-T9}q@~Xxi@0 z1OyyL^TZqOX3a3+4tE+sptJv0y(6S51IL(0+-aaTh8AJGMXRbsOsTYRd@;nPYr_l) z+^Se;VB;pACZTeU6_#X;>lu1>yLr7Z&%n;-l>wc+1k%DEoj_fX_A+lk2CBAZ{6Dd1 z=xkpCy5I)HPM0_vbOoB4Z@%~3-Ri-WbI=<@IqR;>)GS|+Ma3}>kvq0X%N?Fy38 z#S544{O7*_|KR(-55Msr{+-QfAMusy5__KxJyqzSe7=T1X{ZoFZ&_#6rqokjw(<93 zxgNAJ7Y5jAW~|l%#ULchRaRQ7d|KN}JRT~u4%GEMMW^j4!`Ex*$;q-UFi*AWpX0#pZv$z+d0V%ubr!D}vv8+w}W_OK|ON(w-l`yot_ zNJT)60->`)ftuq*l*g*E~q=}EqK11Swv&KIqbvK<+0N8xIK3I#vMJ$In>oNoZd`txVbc~OUfow2Kqq9bD!#Yz3Bxi;S9~A%qZJj(1K}VWqS(X?nIIfRXriDQ!9bS) zxVcaTQT(PwsgdQ1e2Hgp3I+j|xzY08-$i6w;V)rX3N7a&Izrf{p#08qIY&&a8go(T zSk;a}N7NQA)o?)4nVDl%H{xwUL4nC}b^y(eNWhQtE29m3*QbV*7n%y0z=zDcXWJ_uF4~8;hTnw>o@SD}j|h3ZMtacP$OO-hQpC3z&vJNDhmd z2cHA5Rv_kXJn_-{KMDZ2?dDr?^~x38_G!1`&2N4){_+3%kMZSS`RDOR7w^ME{V|+9 zbA-0Ng1PU^1)>&h)BT91x}Fpgoad&T+T=cMUN$}(4=NKvn8c#9#-fpo&v&t$Z&63p z#I2niFj+CXv)9a9JGx@x)tuCQ?iQ({b?e5Clba}Z$BmCeUEZ1>oAYmSzN7&P@z*{1 zw1y)ZzAl=bjWzT~cSnn7PW5&SC$rQMO3>FZyaALJixV&voF|t#; zrbbJ$X*wC~=p9p?XApxOv-iJXyphCZHGqw+_l_ohv5%T#tO+c6w99q7P0k!Gwz=$i zNj>r*Tv%cbt13U^$T3eWC_GoHz-~0`kuQ>V8`a(nh4>LV_(lO8d+Ih}1Z0N(ZxBr3 zOovK1)IvXWu6HNILaCY<4!gT?JY!3XAXbrvNff(o^eWvV*BXGyH^<{l(Ye2~T?(KJwrU z6%!;f1N|gVw8thI9WMZM=k0rVc5Fz}{xDerh4|S>%JeOhmEqw!(&;N8~s6Y?x3p&u=5420YHXDtS?a*qpS<&xI>&aY0z< zpn=tC#ST!BOjY50*#S##>;@U_25uZTO~)70G0@3WkMD}7)MGMmHZqZA6kar2*fsOb2zd4f6AeDng(`$pV* zzfF@r6jlfR+thpxxWNbv4lHr}bO3ETqhD1#coq2Sul@=Ez{&OsrlU<<^M2*(6#zhM z3@D{}Ln!%N!*~ffv2XB62>V6(m52Oxt#a1|)3T^6np;*c^0tb-H8}Q+PaP|sYReVg z`P80t)UUU@cvlCpH=zBZdtim5Ar~o8M1iSK;H?``Uf6)`=y_rwFiaPcG9s^U??4Mz zZwiX=j8h z7nUd&nQ@gg;q3)Ky=Zm^qDD{g=P;Cu(5}uIUqGwO6eyUA4vC}i zRD0b{1^=tD9aUT8Dr(`I~)ps=Z@)&IQrF#gR=5Q zIF}?NJe@l{5Viq~rV|&M(cQ=v13KPx2mM9*s(wZIW-}k%kkD&pOPpB;xCU26H^AMnsHg z3-)R#BFAMPokCE=W{X{jV~*kOd?~6Hg`^$bbAKsd!2r^1V-^Q{8AbtqI-Tu|tlts9Rjsk$%9^hoDqE9_P;hkuqH$*&F9YNxY$&rL5d zj>+|_ual@#%#lMmE*|WFkU=7X)@)P6@+(b_CxQB@8u6$rUS0&B(+=30+G(CA4$>KA zI8w=jX(lSgfItt~YR9ep?rmx22y~OCyKa{r)CP~H_j{%B?sqL)%d?>jua7A;>L$9${B^6o>>|dv=sn5-V_P)3*tmI94nE> zuK~Lz&L}oe9;*^)*tz1nyB4)!jxE|A>adEBNfmzEnd1~C=Z)rkF`~LV99(CK(34#CyPCt$8=+ zju3#c3samT;`n1iHQM}P1DCd|F(YLT!#5=s!9&}V5jbp%a{`A6BDp?UY!25=L3rB) zrLIv`Jy+0NaI)iMTboUt1{Bz+X8s@n+R=nFM}h}FG2>V|zVrM43I6ci@5WI(!ftyR z0PwcA|0W*%#3wLK7J`_M3_u<3 z3K#z@hqXkNtbD%avtF=5H$u3wNIb1QDm=DxO4Z?&49FUGI0KI&=xz4h9G7q6dqfRD z+d#2#qth4VR&kK+!C~~uG9rKrLsVEK1#jKzVDdQRo>zp=)rb;r!h#&?+_ut}CkNCe zF@}|ebOyQLqHqqyWq7wH32%pm%yS&>@QES1lP8>Mk~m?Rh$4wC!vd!nK0={am8ho2 zDQ_Pl4;Ct`d@S6FQbgjtKtr>3;`mus7Ahtn48Vvg5uZ0Q)Dp+>%Ep;I>t$o?-ghVv z8kg`WlK{%m;AP3P)qB{>z=MnkpE#Pl4>}Yoq6Q~R3T|;-8HxHRtl_)Ofy_MKz?}!B z!->i#I9Ov?1CJKk4aE#3?V%^g{7#1+aTVe6lH&-alZrDOEfIO70OoXZ_!Q;bcIO3G zOtG^8h6AATCO=5Uz2nn(qV5(NZ<{}l^I#FlL3cn#A<=knW1eWwNCAhfI(`Ik<4?*U zr|*cA;@n8`jbkeekDzaX;s_@@(yzf`d07P98ruu-S<3FEo{{lGP~@_mLaKYJN^61j ze%JM_wIqALUF#V&+_h`S`bQ5fS%*ze`4$wt4g9!A2XV-q3V|4Vu}5KIu)HNA)Kw zTRu(G)#}+N&B5xw1BfUg*zutjn?em;JSU0@AeL}=Lmi0p3s2IpX_H+R)GVT+ZIb_; zMbIWIW9nc^>hewfsZ9nC3=i4_tqGc6r9Qdy-xksx6D;qGsM*SGxgqJB;dUXFwaYQ` zL;%~SUboxL01-?4Oos!bek7b&6FvrMn3_8$n_txqwR}pgMO{MM=*Sem_y~DIA~5QX!r&?K`i@VCU?YOb zVGj6J-HFLShB=87nRTgY!$yyAq#fEP`zJe`IkUlgF5HJ3aD?YS|1JQ)@$m+ix8|sQ z?|c3TANlZyeBCvJ>XGJ8kY$;dy=4~7B{ z8=?zkC{pZR?>NHriR`&-CRJB{0Y-a??j??BgAg8+x-{695gHDovkMsM8z9k61i-B6 z(XH_=X!Gzlf&%DZ&(Pk6W>iWXm2xZoeG*#$tU+giY9Q$Y>3E8Hg<42_nJ0xdvWk_;;8n|_f(yc-Hh&qorCx=(P2>0l}6(V-eek{tXa3+)bJ1VhQkhQGhGFp_5 zC=@|Jgm*V?mdb@~R)oQQX|Wit#1KMRy*(<8>e;5C zEB(ZHE8G;sK;)_+A1a*}tW%k({1pMD#BwTeMV$0#FXnV`>}gSYgej*oWCMYgnjw+O zCFh+}T49!=D# zb6xN-O!8v4BOHrba3DGN@z87|y+#z{=ohrp8?7rNW#oxVmBOR<22@xcxmAqak4-GUMKGb$_v4}51 z5A~4%F4s4wLa>m1F=om6SuWJ}U|q2T*2>9&7bJUhMVlsUcU!#uP5%*3ecJ7S3Z$9r zedcF89cOWj`!9YR(`I9bkXpD9z<7*Q50)Rtx{R|3s6=UO;Bh8OiD0W2#;N6Z4csXF zI`&edxkO>)g*v~Gb-FTML}TQ=d`@jZ2S-I%*=W%Mf8Fq5|B`mQjc+nDgW{;@{J22D zPufNSwQkBoI4^;dy(Afh7Ba6~~jn)@U7h-!!-8IKwK$Z(@r5lIVwsThDK( zN?a67Q~eiMD!#ck3TpAqF%4R;|4?YxA7A9>>?^uQv<1C;?+td^V-j|Mrkr5vO>~<&k)i?cnJoTwh!^z1mia+PBJJ4>p1&?iK98W77HH)^#V^8C_!og7V zF0WyO3jiw5rb*T;qCMu#>a{{kve#usXmp^v(UFX9Z8ia&pbigQcsU%=n6r)~e1hC8 z1$;vlNzmhbm_Zm9Z?L}*-ia5%h$BY*XdR~_*G}H2xS=*zdqXAHBwFmF5j6Xg@*WUp zWA!tW3*0T6iD`5kO2A{!jQwt{cp8H|BgwIcAtj@c5=LkJy|&3V1SP^yb4`h=etc|7 zufG(>AO(yoN)FnisCXj6@Fv`^HW5bJMAB4UhRE6%UQr!2#eQ;KF3cAM!Bq)EA+TJ z2rU5$5{x5juq^7W?$Rz8=V0{%PwY4hJ(ZSfr={SqMnuK+;YasAEDI!!YY|ATw^*E6 z*tEfoX%17(gkxXe!?-D~afXx#2Nt2zfWiTYD1>3mwM{MLBl#VE6etXg<)AB0+1?`h zCxoptST(W)`BxV6qd+Xqd%}|uNt#{8-)uvnB^t&1%^e4Xm!45WfN!^jOFP>P6tM3M z5sx#kAwb+**P1Z1G#OD#3p~U^U9!JnJ_Msub6GAW9}COTBCiYbxTe?@MwKmla26#N z@2lcwzY9)Nlec-c+MSQA&iO{cLmeV&o*KeI_+7R@Gx`iXHeK4TN=sc^)ZMed9qE^! zNgpiJvhSd^masvKGb87(zQ*vGib@JPz3))sS_DxlBmt97Bk{@bW75e$Lq6@H^qdl7 zM={6C8(T75DmwMAhDU3*gjElYO3CR0VuNo$2FK}RmXP&jo&lGMIVdABOKgkz2)mdg ze;TK-%A6H}ywLB95Br7xM9+HtQLpGVdO84G5xcthK2(uK+d8}|Vpdnn4C=uD?veC$ z!k%Oxi!zP_B^eiJRt)G0_wf6E(O?HI${%{@VYH(Ox7>6Sw%Z*pUa|=8Pk+jjaiW*e z^$MD7kXynPLXD0)`vbS45sTrtWv)bwa?2)d)(Y3swqn{0t06u(MO_~mU$b?>!N|9z zI5($_h7*dl>Z0CGT)GoUjhAxYB;~%uH-j(IGK?dEyR^V{M${zD`B<15*+jP8Nyf{B zl)BR8K`)3>;xhC}C=jHB#-mX}C3v#ph0e-Nc$h zhZpOvplqSLP(~GSs<2uU9Q!e~hl=k%Gy3aE+3748);LCQ(Laoi}H@<|x3xR0(R^6ON=S$qP~eg-~hc)bU3 z3kX(ima2vNFqAExNahi zMR_SWq!=w2}+mAyl9+EntE>H7!zmXFJ1zVexjMc?={_8N$Cf;$=DH zghzl#@WtqiUXiFpb}WP?8dN=)I#vt(%rR?>MIeal4XYrk5koOx?=(*ENEm;yxlnfm zs?sgLDUiAiGGH`!ZAp|%SgN2Uo)`kDrB8Z>$hYNa4;u?hSuyMqaSSY5mGn{oxExQp zr3g=ZOmWKW7{53YVm!XDxLo~&6EA-=)R+FLbi?ss{ijm{5jC3gUul#yR2`p=tAYmO zIYHd2vCvue&*2Jss?(qd;{q(J`Iqf=z>bOOs3WP&_jXhXXZ?-iZiS!ny*20U7iVX% z_)@NO?(2Y6T~0{$SLivTwKeMtmxkrIUUVq=&-rVhe_t?J*WlkMMV+(Vvb0O=!m3d0X z3ok%n1Pp+|6tp@Gne(PaT^0_!lW)YGv!sopTDV!&-I+_{i)@$I!DdPVk=OAHmsF+7dW2{B~ zs1Cn5m5NqOzef&BFV}NU zU3lxdq*hpRVwPVBd6g1fRGlhOUQ_qCA~L*8J%VoS$=)R@rlcJPCt5qo?F7)sP#6Rz z$1imT1@#Dh4A*Y^^7ebSM=u~ZAlXLHA&}Rp!@SVxBuV&(^;Z4h@Wv$^{yPajvg;SU zJcPQ2uuK>zLpkPh%c+g4Wq_Wb2tq;RS~Z+#0#)Wo%S}3ioh*JNxS%_BIGlO4FoZ1H zjlLE(b{%s#1vwtlnSYL8&*GSbz!zaClB@J5qlcIHQ0fAVd{P}6VSg4EZ_J%5J^_Fk zm}TSbE9RXBf#}kxM1gU5MpFQ*-xfvVyC%{GNK?t?g1ayz+p02d(8uHxZ=*J`7)H{q zH(18KI)+t&v^KcY9)=gM*IDhi411N>PJ>~6Ag9-o(zK4h8|@xy-$P&3R4lJqmflj9 z0Ek7A)Ri;qRRElcF(E>4x#+KvHz5#!ToB6wM>I&NMv(#{5~`Jd&M@NbN@Y4I_7ZhD z{1iMfSD>J#5b`kuQFe&<%~)JKl~7f)W2CfS_ikj6<8XOK`p`-r{+Ty;7;fCKbP@}zm;qhUc^CZP_5iT}W*!UW~j+!5J<6na${Lh>k5 zJ##!Lt`aeXVr)_#iHF#CMP5(3G7buu8toN|Y=wD(4oZkCfN%^3+7zRs#{p2M-H@Xd zZ^&_0oUl4kPI`!PbiNEI@L@>78S=$aj|Ez_42^XQk5^?qRIGrK4~dLk`o#Xj^WU7W zDjTTai}4~<_~)SS|f+(5{P+P#=2IuKiUq?CB=h7iDK8me&;l!VW3$;-o++u=B;2b~NXciGdp0@4-D@Tc%i~ppx8HEXsPE+r z`Qng={$j?}XHT3Wlw*;o546FI5XlZ=bk6g6p^S#z!W_JocziiZ>rZ2BC~s2PL@GGI z98AUcpfNu3s`b*sCia`dW_Q{(!RCx&({{1`oM$^RWy!*+Q>>L$A({hN2*!YND6Y^j zTMs`v`~eAnt>3*46wq0*@pJ#1Nn$`#WoGhu>8OHB?_+F+YVuZi?R23Y$OCo!-ge`E zO5&8tSfOkS4g#kHgl$oH6bVhnGLhr(H;%;nC~(oU8ArJkqwVT)it8LEt_=SqkEzqf zP?#ftatQgp@svTqd!gwZf0y`7Czw^omEl3LB$> z90yc3g9lV}ym`9LT`xAEH<@;=cvO%z#xa?YFCKUq>xUSZ5jCL$3SI&pW#5jcV!P+U zSn{_8KBV@+&xEPs!pl>jTF7L=KmprD(Bep&pf^Nf?yBC0mI*|eELr?b;1=JPTCBpm zFK~wL4%J(ICBvURk-5J)d8p*7xLtj&x7@Y*JH653r2drpJMdhi5nTgMQ^B{o7~&_( zxtQ{;Tt%*(IjxKsrAvh2=Iu}WeOUpE6fydjy>eQG)Y5@b+YQ~Uz5@}!?veV~p1-7n zrh3K*PjyylG3AO9$>ysN_J53Mi1Bg9Pi;4&6DN$CK`NW_galXTnG4qlvTutySn8NiRD`GHORe*TQpxeqL+T@=PdY55iE~q`EZb2UaUG0g z5f_Fwl^)zqMN{W)P-q2ty-roiuSnjk2>Q-Qm4z&YhZzT*R3}vFJfdg(U!cx^?+YT( zIpsG^`FbbW!vZvob`SCAFi4Jg78Zqm=gMi}b>XHHwh?exfrIc!&~+amkz z)iQ#_Vv_J!eyO+CN1jC~=lH`|n)?B}%bsFGj-YLZZWTvIf=#m|w~VUgk)FsVQ}vx< z4^A$|b6gxFtzQkhw7MYc%&`***^_grI?iyzNI0F23?2Q@A)=vW{bzEk4k@}9>xbo- zUsL_NKs+G8>bICPI%YI_2ndQ;W2{o6{*dA-ark;O86`^h3>#4YfATojI2^nB!Z)Dc z#(*N6#U|z@HiGFuQ6F2xPN_Nc6m)e680D0*3Doc)WO203oy{3(#DAVlJ5gTj$8@ML zx_S8SCGtiq$1g0+M%_Q4oj7va$a#!DV|0`FC@e`fV}5c@>!Clye{D?po7oQ4tQjNW z%%N3lNGTV4K~S{aWS7D>!Nc1Vw356$c-7bOjGj+DRB7>3kk{pD1#jz*41YN9*^P3* zrBlv!6HGGM^+y1DpCdB5lj+EmWT1VyXhpcm8~u_v3w%;)2?Yt#PL`1v1sFG*!LV!; zMg_v>$NGp5!K`K@_=Gq!R+Mnk>*g27zo-AyGO1^XSz$aLs}ICv8&bP;0V7DG1IQBy z!Fe zj%6QqM^G0;RDX=Y5kg;J(1s%IY1qqpBrj>kI-!jS8g`07Q^iJoq4f~z33k$h*v$hW z{9};ikMl&7i3N0-hh|~C1;xJDVc+8EF?f%i2Sd8Uc09RS86S(M3SeFPIp-eB-wM)) zdgBh)P<7G&UfZ(#Vfn1>C6>>7j)had9)j{yey&Sw4+0EJ4SSt1?Dr(6zFl;|Izj9} zTt^9D)}B1*XD#i0N0Sb;j=U0_Wt{;vo&DA}7yI4ijvu?IH(o{G<>*mFF;Mui4>DF! zq~Xwa@91z{I9!M(-jm*B>_o}j)BN=cCLRI^Kiq@;+eJG+-nh9HIXz4u_67_NvSr@1&E#rz2_D5H!-n znivQe%Z^ff_nlM^C*eWz@tZGmdGn5ZsRF*1qG9v zR%i3j{y=L>uJCb&Y>{lDY(gbpOSW61g`#c$>~o|6M_m?~jLZ43_j&vv4Kx9;^RY3) z$!;$)2YH>I{U`CUrU5G19(s9Q5i-}Mqy}&n+I78w!(i!Nxj_WhzOJXy;nlLhI_?g& zCFQ@TfwBMYT1Z@JNltx>6TdB}&s(4ij&HdU+g-y>d95`-=XZ@iF_I?%7!WJb=i*n2csrOxzoe2>)e05A&;VyZn7^R!5H?i6!g8iBPJKo|*58#!AVZF= z>u4G2)VQu{MhLT?No}-Q#D$IO09U}RfOH+AG_3Cgr`pR5^IC!%k-AEvK**Ke(>4$G zr#-`V`B?|E37}wP6a|0p6l4e+N#IAT4}*@WDzW<-esd$uZwXU%sJy`(Al zB8oezIirN9FCXG`*fe8%K1ZA@DyITYRH_D37Y(OVdQV;0sz8bNDaR*BEfIo8B_g7l z9aYW=*Rr+^LFe5t>Voil5#tvM&IF4Ip@nl=nUb1xMwyQBmor%SV0%h=@lp_0s)aB1B{T@Qi!7|b4_0+t+hK(N@jdOLlu0lRKAZu^$}J+3iVJN}Si-6Tr!z6x*=HrS$!@Or`_6wb_pI7%Ca zT~QWX&=Eb%@e>bmsmP?h0FzA)xbwftFwN>DD2v%p>h*|8-NJ;!?hCwOhd%_3({3yH z3Pr<)>UeEjV<1LZl#4*6m?tjF^C%ecjREe&5^>EjBKy~bVchuzh7iY4MjdgxTU0Fq ztWHlO-)ia82N2<`tV#U!RAS=tGv=($17XN8^E3#2Y(;DPuod$R!p3{O-#)!->RA_fk3F$!)17o?whyb*{U zsE)+FSE|F(Fw!y>Ezd0%+EzxPjj~S?{TL#4MuTyI6C~XTppldiMSRq<1ve47V|eAF zX~1ppBgezngdu=}V#ZmYKZ3qwvu2HI(1VtHQB+5RNl_ zxV^QJMIJcHyFD0A(RCqXk~W69#s2i>OG!~y%T!v!;vJAO`?RMbYYiQh_0^(44%%YQ ztlQnzzD@%4j@CN*;?+TAw)|Epu?^sW>!4}d$I zRA^=Gwu!Wrk|KBkaVH2eqR*#^P?isIVabDoZY%{KT$^gXiC3$6%l1jz)zjcH;4^`0 zf<&B=C*0?=MBvpwnnWosB*v@MK&^u=wz#@!b3`p zo>|H1{!YV906Y_g#RIdb{c7drG!3Hx6<9!mmuU@VE9Q}P(YVp0;VzI(W}6om4t+er z*Gg?!QZ$qxMyPEz#*BEjl4SO4p0XRhbc8_Y)*@d5I>(i8ALl>$gpx{-!runU16C86 zH1yrZJx@|7IA{3gYU7zMI%8xp2DhYyIOhI*86U3*e7-r!hId`YmF(?9Up!su}>7-*Y<<4z2XRy; zz~$F59=8n{c@}Hl%8z?{0e?3S)nxl!S$6E#gFdxR2xaUDv6oWjpJ&8SP?;X6%nloY zc!i4C#-vqz&lKSxVuT+Un1Sm>PJ?r8dD7u+3+Fy<+rlM6k01xZq(bn(ffS|lRLmHC zoct@)THoZsyk2{4eI1!T);RIJI{P9}jcea(C^fyRFz^-g*Uok>3jn0MYNoV&eEi-A zXlwfbS74~^NqeG;LB)e73`RGG>dK<@Jzh-`#CNPm-9p}W{_}xU*>uN|{CKSP)$=+x zu~Uz=ugv&Adzp#w7%t~krY!F(%+&Ka{VF(VxY;>vD55giR%%OfOgal&tOr!^mPs9b@%>@`e>A!ZY!yn=7H3#*gnoi2ZFuS95ERJ95?CY_GM zP#IpLX(8YFJ&SZ|HhV#^@$6#cnW-@5bhMMnN?G*Z_KP1@Z(0t;*rk=?~UcMArZBGN?b_Vu&of( z4i}P~J+yS*nHUFmyOfox^qr_D_aUyG;Fp`XcN>0J3=6D5G5XJTe7~0e|;}gQk)TTcf5oWqo z*sbXe5P@{c7cT9MPnO$D>*{Ib}%wI?CtLl2aDt4R+SES%jwg-3*# zF0a^p&VAL1hF%+epo~Vn1Zx~eQzmzY2!(w!&|#0MYbC6vfHK=F zcjCm1A;&QqB_2~=3Yu^cp`F#D<*Rk*>mz8?TH%-)uKv%nX8fRR;x?!LnEk_`v~A+J z_l(b(kR<3;M(ItqWsa#7r4Vckc$9M|qTBJMJDwB7I!ehT&q(WArXuh6irj&Rar{_x zlsABvX=DZ^QPYc1FeN6qc<8D^N`XoPZEf4wXVPX8OdY@s8V23mNFIhuNUGm2YtHwW zOa7SBcWRB{N6RWYF7lK!ClH#<6dr23MdMy*w5%Z^ogf-62|wC=X{9Eia|4v}`W}6! z;f$Q{@Y{*Rn4oWyscf1a%-#J&49v*09)pC$d(^!I@Y>Wu^|_Ww>=#?AhhOY%nBGh) zn|5=o;oZbd%b)JTSmIlWFF<~85jWk#{{OIlDsJ*|nuVj?k>O{E4%Toey+3=-#lf$% z@|D`-cQus$O&LF-3E_dItRo_T$*Ql@&lY}fVEy`UbKdUfReei0N9SO9oX<$wpDrSBNM5AFkqA`OEZ23-!_sl5C zDu(l^c49c&_sYxw0%5Fb)V{e_J0r;YP1XFRu*!H;uw8uEXm zIe?jmO{VtqCM)C+N(`Ok&#>Vj?gs8zNKWiEK{9_MmM^js4&KoAusCtdm(g&`9s^ft zWgMS1$w=WaM$Tt$gAoWVP{)jeAxpK9Hpa%Q;BLc5-<9A@rjr@>UP-zA!2N38=<>_p z608hjwKYgZyk;Cqq4&TUk-QnFUb0Oc&M`+UGYV#a;9 zJ21ybfn&}}S!FPOC*lpQ#w1n+gf?V4sk1#Q7w~|P@$F*gvsLLFE4TFYz%BJH2;ZL3 zO!Z}x?9tz+qBOj9{p3N_E_qM8=AV|i3>%;Bd#p`2;2e{T<6 zwvtZR=&T9WfL;@NtoRO{bEw)dx>o1v8Y*bqV@=_S!%qZ$30Ha#63-A?b#N{hlbPkJhRTS6;1<) zWm!Pb_{JU-MOmQC>q7S1PZf$`)@1<8;5jheK29BvLHpFf!DLU9#S={{-?k>dJc-4U zHQGF73pEBK5{vUHy-j!YH$7WC~t{Lzk@FlaK&6tn0Vs3;Y2`a4X)l);~`}b!n0^a zVb3rhbh0ZzrJbW#OI&)@q{nWVp~K_EH!r>GZ*E5O;bVookzE5k!#op%SM|?sj@Hwj zo%#i5g_!3zgeq>`dQ(rIpV0hpeRMnl#U~d0xMxCfli=R$c6ayG)G_9#9v>@4?<+oK z;FGSOsQ+l&kgphX%!*dk_tdu5q8l>In$bC3@2yq>h7w~6Q%a%(CYwqjFb57L<_wN* z^aw(XE|vnIfw8QO8GD~|Gp{l$dDCh482E@8Desbt*bG)Vc54#K)iB!E0;~E-8lXM6 zZUKapSVEZ@wGD*0-1a>SSL+2hZZu;G=r!gHuqbe`PITBARXfgtTM z9$;6TOH`zZoQO3rxq!<^yV9r9jL8O4R!vM0o_HodtcA#3e9P5O@t~2=w@2XJIIjuE z;nM@M-vTZGy^(<4KF8g-<7BOT0^>K1z1s}ZaAplaypgMee1`&HAcb_O24b57VKflS zDnLlZob%j`8R;2i5JRgq*8U-$CO1gMq9?43!;MC3TEJ+mS(n8jcvFu^(w zj=VW%J`4gcov8_XjXlJV%`=Ar%~NNxzQ!1mlgxhsc$@P8WYnZ;AMGBE;l7@1($n>z z`Y&7h2ix?e{{18P|A&1(uzCUTQ^QX%4U#`m9`^r3o40%d=3CPCTp+~p(V}xUbo-}+ zv*GiTyUxZ3gt23@*jB&Cx9>5=2Jpguz3>cmOev9c~S9{touPTt7-{jzXxm11 zdZUfl<7FQ`E}r*u_~&8$W9Xzg6J?LkzhdYH*{8}Tk5SY-KS!4{nb8@6BhZ!|om)gM z>U+GVp)wlK0=$^NBaeaUJ6@^ox%kbMgHe$<7U*JETlDo-8y+tDBTvy71jT_=&aZ}q zso))XvNFf2d@byUC>AsXQ$Fy^nr4n~z64S0X)4E@dM}*FM$;L$@kL^11mYP6bZ}gg2ruFMMdr}sj zNy9OBU?Tm*{~#VIFgYD+mgV@{W&rEn>6*7}bugyDpmARV7ll;%druR5&Oj^oR5vd2 zsAqT=5o&rM=U6m)L&2*=Hzt7`TC;KCW$cEG^M~iV@xk+i$5+Ubfl)5~x!!L5;PxEA z@%BMI+eJs+=A?KxOQmc@N0Gsm?qQL6)6Nx@dbkP?aolkkIxmkw*~h0{xt<@Ww|faA z&)Lw~uQzkRW;C=i&Ti*bPqpZ2qV|uj_~EDN<}bz1y7$9xa2UIaR{2oSP*LYvGN?d} zTTkPn#jmXMWB&d7ckM#3Y#nm)0)qkdn_HX`iQI|BKvOo~XFrV%PSSbkKmG01dahJ& zx0ryA`)EB}cCIq-#Wr${k z+q@+Ehu$`NI?;NNi__}>xSdsJx*!Lt4n!4y_m~sPQk_WL_SZD!J2;0KA{8I9?G`f&q)0%Nl~uva`Z4d= z8qR2(D1bPV@KmeBTWHjCm~!Iu1jk470Lhkq-*s-2=uoo55mYc~OpnS1zb6)6&^ELk zc5`?6#xGU*1gbNi@7*KW6p+VY)vVY2O!V;9)&P9R@7Ss@D+ z4RoW($Toe0VN%{avXFC#n2qxYV7*Jp#%RJm=*{p?J=FbiW$ifsk=4VT5cV6Xvm;A^ zNuPW=0jmU^@RC$g6dQ_e>r7Pdi}k|jh8cTk)uYBI6y8xG*zZF3yiFt29H!x?I4eE1?Y_pRu4byD^-rGS};kV41> zPs|FC2i}rHHr@xyUw3gG6|%82@SenplUZ<78YT6lT|~gV8nW__w@0stY%m>gS5TdA z8nP>Eb@gk<2k^qrgJX6&dU@!cdfp0{;C(Qny7>U%hfzFVPZh@AU7b7>{FoqpUT(nH zJax+Np8Q3ebbI-!`mO9W&qlVnWaIr{<;-oH!6Q3Oab+9KVFa!W&aH(b0zZP+pEN3# zYRU|SO!yX!V>{#Sh%YQ#M#>S*UkkGO9gxsDNQw;n!UT%WjDy(y))K8o1`g$hMa2xI zXWp0ce4E!qxXMHkN|=JnOWqHanJfO$y=p)Pg+|An6c<#JOWGd>snV2C0uwxN$uLcjmb$=wWITmBAGhd%~=-Osll2)9hhN| zMQ>biy)d?bvJtUQXO3`l^@#&hM#~<-A#AbL;}0N!m# zSCfv4uZV7aT=64QR#GcSz~Nz00Zcjnk~NWz*nx$ z7Hl0I)N{)BLBs@TH0jEjGf`D=@-JL~c{hP$xu0q!nLk9_H|CNVoyK7?a~hh%sWEv< zA-g;w!RQKX&F9vhsLEa!TgX0cy6eU+ylXxr?%u7G%u8^-7T%Xr@c0v^Zv0VPhd8M zm0z0V6V&4SYMDvQ_P#uzB_FrG+#9hHzfoJJ$Br{Au;=dKaL@IrY9ExE7qZ9ya2?^k zbCqF0<$8+(Gjw-HMBXhL%LXDh-2h}_%e|mQSlrJ6g?xBIWo1fuUXZ2kkg>{vXt>(u zzhlzJI4MuyIA;fGdZ+t-QON)js!3p@-VE#&@>`P+R!`o8YsD5IGQ(W9GL`X!HyO#( z1?!@dp*@uhnwbNvtzS_Sk2+wCMl{aA9AR)A2ed8!)wEDHAnU|9ESt z9~6(*Jc10-{XS^3hab0+JIY*b9#>LfLig-2~3E!TB%S8 zy1r1i#>ot< znXm`heedWAX@iA#8=5fP#_|{#6uHK<71$`p95oO#ERFj&( z@PN`yEf^xS_432P)TDg@m$3%74PTO9op;;6sDrHuGs}d6s6+3B2gfA8()Ol|Eq?P%N^qA{}u4mBhhjUEf(TEH?H-eD604E(H{+7wUkMAg%C+h@7 zZ1`dG@5b`}5>w7?Q0Bu1N_}8Wc6)m8Z5JFSpFPzc-N5ZW zy~>=MuVLS_Gn}?W*sEpOntKibwH{zejm&=GBBCHmSb(FkNBwrqyw$1cnCT-%*U5#Z{}3KDN)cD*(HP{^nM#Rb zIT`Xqc4KLMZ=e{AK#@;F4>dk*hYR4f-dKIm zWFBuR0d~IC;W)|XHG!#5%~X!ZD8cLLKS({aKA)QSR>g3o)guX}H+|hh$;Tc4!Sm2X zqkjbBp@<&}F27^X{ue0t>|4l?fci#|oeyLF2YnT7x#zMSj}5$k1N-lP13>XsE@Zrs z@mpt)L}$??dJ>y2XfkcfR3})>svxpBu1lFWvV#Uf4wuaR@WZw`3KF!YQXf<<3B(#5 z-l2NIp=^|vqvWe5Q*G*%xjI13Xu}l~B9aD(&KLr-&E}ANeeaRi@72K=8Og@25F3|b z=`rycl{HY#4+9p`DSOIw5F~_Os86Ah?UGIj=xqQV;1i=xprop-3Csl3rg74-@yI~? z;4}=Tx8afFj#~Laf~$99bng0HaRI>V%plPijm{dDkC8NP+yc-Wyjm_ivrG~j!^5FW zxrVjJ9EOJpwD4;O8yUyK|L6b3fB*F_!!z*v_uq%V#V29SPB0(`t^xF{_z$jIBmAlCVN3r|c`*1;h&rk- zKbI1RJhG)Ye;yqaX57vl{r*F={9|0WPCFrchWDsv{UvOpk;w~eVtruo9C*Yp1c3cl z;&1#yBJqm$wdA*Ujh3?nurhlsp|_HCz=jzuiPh^e`$R~tp2So4r1`_Pu->q92Y^fu z07Rc>)_zFHKKE#|^gYi#(+gq1Aa&!t11VgF=UhUW7P_Aj#nJH7F6SG}{ovd3m>&{a zxJfewLnr#?3d|^~T3hlswhAFIkX|_6^5FwJO#i{QY2nqnwgM4hwkH~2q+4KhKqB$d zn*+yZiKYn?XA8=OTosU>FtjuF6~LCA6-Gq2;^%C0OTWP0r)b$^*+C``qH(8;xPkii z2szT@u>cMil`ybTmncYIlA=1yEMKv}^O-aw);7VpUr)-fOw@e7Ilk9t2wMeUR|Bx~ zcbnd(e*8BQ0ltHBKJNUcp+(NuVd7g^J*k`|gpSmsm49&M`Sk{ohMy6-W#v3mb_Q{# zIMK(;m_?ql;S&kgJm2goGiW^fpU#=q@wkZU$XNgnXY|#7!d*g}YHP(Hk|3B2O3fUY zZ5ZhTB`l~F6BS2b4xV1A^Gr`(wrH{W&*oc=yqaA;mQySc#5bRD?yrU9J|AWuL?5jw zu;_Q>eCH&|4|Fc&Ig+S(!zPWSH|=bj=ra&I?i-ja8jGwgpeB6TBG)i73n!!BMi4fH zl+CEVI`e>h$Axn9t+BJu_(5ncs&)KpfphN^E_F5$!>-%#V)F~2ao4H3qTzzxKmY(c zLII@c4#UR7c4>Ra6OyL{GS(<~5wOjkoUJFlkOP+hJ}>T7pVD6aq0K9pKWhT+_0-kxxb1<72@3u3tLnymyxR-k;uj zbs3!r3N|yov(j7{Fp0{>p+T()*=~Am@QpwrrMOQTJ3~uxEu+6Hz5ea1{My=-P{xpD zd<+6|43Q5k(f1ghHN%zNreJP9raXASg$E%;E0U9;Y@C>W=(Qe^;<~Scp4-j^VOoYq zHkEHA*0d)=+Bju|i3_4ON3jUJu;&lPNPVF2uh%~k?>&Cb7W^QyK*9bt+_8Vz&5hYZ z0L;PNDZO5Q?Qka%L0%xj62UAc;g_G7G3^B6UHJAf`m0A7c=qSMLUd%^q|gIrh0dNk zjI7B*zMR)E2Gr~|7g1ykc_}z%ZK_NRtR2+M;6gw@6Z_L4A6S(I6^69TF|05?N&BO* zBh8Y|F7dV}jw^%_e&f}4=m&T0J6iUXXrm0S9M~j!)IX-*)yCktOs6w>-|Q8#$wDD- zjN=h2uzm&p{r7M64FKzO8cuT{kbRQixOJT2ylyq)H4;ze{P8MLkMqV)eO++neJc!q z!9~9>**hPX$_xZT-5l4>Y%&i-egS!HlZCv%aVzuho z{W7~|;&--ro!5@ngQf1dY3sk;>5cqlZvwbaA{-vkvL zC$pt`0lm!V!j4_&;`Vs9ro&}jr@Xn4Bf0YquxuZ& z-s}i4lc=VPzUi&=yJ9$eH?C_t-*m1u3UPsHWuMyt%vl#dDa@pU&WCqtr}mLW%degr z#qmV*{JSAJ>&5!m8==->zWVL2m$VOg-&lu3KmCI5Z5_`}edkZsvEWYK?*5T{nT`k_ z**}HJnIPnufuae!ShTvY*R0`0Py(^IqSp5(fUBR!WP8tKyWScVVqyjd)Skh8`^(2! zr0lO3Qg>=`wfeDkL@_FO`e=JF_~H9#RX-k$-OjOvri?p7%e=wGe#D( zXlnG`Zy#V`bwqgv>}LjjBIEkJuE)>~Vg4wbR}ugJhf6dbMx=uiUn-itd4z3bb_#ur zDhEHV})LCe~ zQpl_q!L-I%hydcREA;Ea{+2fD=~-90SW}@P(KqUgc$`i9Q8c8 z#K}SHGe^LDObJW|grhYk2;`1~6bg|`h1MB)=5!rIVX%kF3I54v)vhupWt7Y)DpmVZ zfE*{&2oEFB{AqSe{i|iCl$sYOWefnY@n3j#H=ICZ z(jKQ)l80{o*>nrw1oXk;ErzCpTBIxk>ci3Vr2}iQiB99A=2aDx^JM^L0S#@?W140?>vihR3!9?(;oaFu0DAu3 zTZ-&$HqmX(Y-dB+^&P0I!0#oyAtyPWWo zGw)Dvtn2ueIO07|-Pb}s@Y@`0KpZkw8{J+wliK*4y#rZUJUQE;+?)aszlc^%Kh87x z$CU`K%qoLuSYhas?O?Lq29RU=phb?Xq>ncz%Di3xsas0&G>(JB(?HzMZrw3z@=DG9 z)<(zu@f8Q1SagF2WJra;CO9)dBVO+U!bvTL*t4-UGiewBiy6u80!~Y`ZffC?gDO zIPttVqh5nJH_#r`G2YhuF8a+U2cJ@@kVd!Qbr}UDK&5U9=YhUMB}S>2DfQ}uS)%oO zLx;>FOwo6LN3g>=q7`ejMf9KxvoNG|X-J-U_!3&ugi4)wV9GUDEu_p62V>pFhBN{S zZ!X9&I4m2?wAc%N5MNwHWyIz+hRJc)1JPC{&)}j0PaqF3c8zZmXlH+!Qg1pmem;4< z2Er9)dB_53o1x*L9sibjVj^}{0 zQtI|uygK;FOod7qYDTILMi)ox6A&SQ`- zBy!Gi&*`DV3L{p4&KnH33vkQgx;2{r#M#0!Vsgx@1oiGhYTV2SqP}qK1Cyt-CdD3&$1VxD1u=4N;; zaUOge-EN&3%S_J=KeKjA|Bnsgwz|m-<)@u9d*eZNV)%4;%5}Z+$c!7ZY45g>ZSo8! z;|Q7Ajup6CZwth8r`SGmj;>ewoHldn*E&cb);dPQv$@V|Vfjk|K2;@f*SS%ovkG~eudk<01lrl z1M(-j(2>2-K2`P!#hl0l6+lbsYH5{^oU=_KGmrE#3NX_4+Xa;YnMzzI|1)#4m3W}? zi9a9Q3hpT@ifE7FWzw>AUuZmwN-Qu+ zbVJ#1u&(^A#jU}lAf?7^4sg)Zctk2O&-=0SB20{&88BJ^u|CKA48+bGzQW}2fUvN_ z=zcFShz~>kaY=gdT;jxMUe8X*ADn8V>)n7-iOr5YLipu=f(G&D>%?#1tPy9S599DC z)mGxE|1SVz%&oWZ?t9{(UOA^M)^gFpUX0eB`{uQ0{hHWvUYS_E5TDWsA9QTyEPd4c zoNUD4(m-;If`)7YbWf-?+Aeoz(>U&wUgwHn4G%|;MJoVi)ovl-?W7A{c#@=9CWZ7< zQeG(QR9>LKV*(w#-_y%%Cj_L);QUClJYGRcTwFrx0UYAiGpl%JPj3-8RySZc)Huh! z6g>RGOstC*N~QEbf^GFW-U>!J-T>av3|z*vjY%>qt>C5JP<9)6**%K@LctL;gokp) z7_?(m!*Is~=eFay@ujRLPXl&?$@YidlNB>KC|0UWJIF5dSOc1@@J&~v4{U`eEt||U zj(pa3?{Sv$XdE26wieQkz1s($;riV{WyfP{_N38IdH`dm()g0__Gs@8Y+Nzpiko)i zUGnEX@Ijw%vbX@`3vcm3H01We;VxU*5*(SZgqaR;WQHSH`EN$aio5;r(w=-I%owe% z1|Hjfx}4-vgU-WuD_<9NJ~j47N5@z513oGojA%Ocv#-$=bK^+TeL%T+UDrjtYoijR z|Be9YQ{~p>Ya?Ivc1gMKQ97QsSrb`(3-C4U(L@-@XugC(I+JnIvakuQA&UIgc@oyf zMe$6eR$e~j0b4yTlQ9K#_`jh0hPrR0C+augqWgR+!{xR z?gmbwmZ7N`K#3J&3{G#`E=F9p@3@%pY;BA#=2bd>o;5#aV86?khz0zj7k%l7j5#Cn z_WX5SLB?Az>R0-slz1n>>byHLAK4o;_nblD)9OVO|E)%33cT zxw4@aQf~_zyqlmT>QGCz*-p9p=1w7 zx7j+J@g9q%Wh9^Fb9T!IK`ssBiqNdY;PkjYbP|!%(szUb+X+n+*l;^U!wUUczFCU2kc-4<)t)`exv_iLA9w_6!4 zdsVsmXar{{K|u%R*=oEv#E01WaTIV*V1e$BspX`vWk4Jgp`0B>(g#tmGNgXg)hQC| zQfky64kI%>VC{Mupp*&?N#jGtC%gMS<5y7U#0Fm;IA*vxiEfZT!KrkOJDP zsI^32Y2j)S`DpLaiHeLjzwj*$aTvnsXOL(93~6EMxqKFZI#``)Icaz{9PiO~bv0j! zr)Y@^nd?g@+vTl(FZEQ1DEOr9#L)kNLHpA0t<%4jPW$pt2k@n-4`@Hy zyN&)+C98J_CNVVmah=Cd>Z|h;Kc9|G({}rxNGOp`;PnDlj#zMJ-3KgtwgUN`{3W$~ z*=df4=c<&d%F1_X9w)T6WYH}%aFjMK_Gy_ys2me6k_v{H)*L>bM>FkU7U%dEP`^V8 z-=NleHZ15~1> z!`-@NMf5qbTx`*b;SB81=+9Ri1*-mI=FfvJc_;)iE=h2|BKadae0BQfU<1c^XrCu~ zOSr213iP7gIJHtCWU?H&+F@I;5|hD#m1&+ni!Ffl{IYzd}imsGt zYR>TRc{7gvHi?=!=Eu4|>*>+6X;LSK?!%1`8h*HkK?9n$R z;z{K}+6~s8YZ?)DJ+T(9C`g{~4ZqERMg!P^@mU=%cM!qG|P?eGU=vIh@&e z;TA0gm&l~4GU*viqU&WqEK7EH@YSdi~bM&n?q`eX31fysQ0yg>QC_D&gsQ{@CJaqaO>JKE=mZx7=5?v*U;>@NW2> z>5F%RhPwt!hAvz6qy{*)P{?t2uzA~^ie zN;DhviS%(eJEvWqu`;%!fA9Lf8gMal_Ze2lk*a>FV`$qtSfpbe7+^BYYOVm7<20-% zzbMZ>=&N#GrA5i0qVP`Gktw8J_54_@wG^7E(c?6_B6~X*+Zbf%Q(woP^!HG@V?fO2#qvkG?+I$@@`9?&IS=e|_jt0-unfJm%dW*JVyF)O}n}YV9p4)o{ScF&0kq?mN15m#$Zq8m@e6nZ3oiiwDz@nuz`24#rAhuW#Vy94bhg+w z>FmL1l|BQrt;euH94mO?eX-{{cR&hUTa_?^M%uS>n6p6`39h#5s~e_UP;(S9;R?cc zr=Poq^1uWV{v+RWJB&^B+yD?iYTNMasjupHTja3XINl;< z*{msJW_=|WoQ#g$$Gqk>XLx2GW|WpmgRo|n@jzF1RvY7ajNjvl=+!_Wk~|=z6pgZ! z9l2L;>QWq5zVr zQ4W+7*xg=>Wyc6Oc_lyBCLZS#P5v+15|w@OOZ`(|WEKfWLmG?#I1vy1&zfT$onWbO z0b63@A%s+(5fFSed*XPH0p+9AiFxap@GVeh=%Q_0WWTBukDp4<3cB#iAW!d{`MM85T(s~M&ZrL!qJ6b*@ z6K8m|ZA@qDB)CAoLEor$oHz`LNWN8hc<04n+V-qB)02|@F#OYuyHfhYMPC$@&pco` zarCI6K2)~-&j{I+Yx_9LDeEAt-3y_b%-rF(mKpSi{NtQ*Zd}<9TNW_*osKCAf&jG<5^YP@z;va`I7_m z-)<+x*HLZFTzE3C#yGXICTw}qkUUkqmKrCrh_em(X$sw$jr4GQ48$LamLGij*{0*i z4TrOlw>iZ4Q|`~%_osq9TFuY<_d?^TpW;e}2t0kg+a7@a0DC@_cb}4L| zARa5FM#yLrd<9Gf8pzU);_aI#q(BXy$cGeDHJ9jaIfnSrI#qk*0 z<@3y$L}z_X3;MY{zw7f3mf278WxeK9G?e%l>z=C=d42L{!E&BGwuh%85$kX4zw1pv z(yROJRR8G3e}CwB!_`^-EJ;+y^W*2s8$8DJTzo&>G`an;%lqL+;amTl&AV>_IJghS zUr*wbUG6$?EBrur=>>1##+5%SDo#)%k8z0oVcI9`27q@@hH5sjH2;XT&VrcfdiHo3 z&|xOdWY|=2r(ET-k;LgoMmYbZPdrD%>^6H1AmXL6HD2GI#G{lc6&?Uj$(7@?+=dF| zthVKK&oUmQ*PZWsX*LqsTjM4(DwMGojo(tK11B1fK(0r{b9 zL-sN!Q3MM*CrRbFP}=xgY4h%;wZT+fjl4L%KCc|H5}@bTaeK$&URSpe6BYY*P0%Ea z38%XOk%*hU+>+VuM1-_)?S96{BxPN~Y8)GwQ|Ui4ONy^F@lFYEr*IvsDU-FqSEeUI zd%`@p;C?*141==^sKcTQl`~$0t9t7Rhd}(<5GEM`KYt=dQAA`N z`9Ni1Z4=iX*jgqV31~4jvjUcWfTTNaww%YGD<0TcXN>ch`M zpAa1F#pyI0eUo20K>E(VvGE4h3-O{5Tg@Emox5CvEi?)T~|MRV&X>-q^r>s|;&lEWx z1#6@;yn|iy-s&+`85KGrSB7Lrx!t}(%pq0_-at_J&r zNHUzGH_7;EcAofknK%MS0b5?~CMOf`oQRR;Ie!fJ9GCH;ws8{W<_U&oa>wZn;VZIv5dyhg{5}p(ZGMHU02Db@gRX*ec=NV03##lJ=bVik{^qEU z%p@u&8Dac%IZt@WHBXH(gUGlZUDptTaS=}O*Q(YS8QIg9M0;e&P6FSldGN81V5Vp{@l_7#o4 z#+w-yE%dpfU=~ideZN7i_@)(M1I8d=%@5)jtH1qAZw#Ze+_2C1F4jMg##=GZ8rPC{ zH~4Hj4DO@tF1!cVS}7!)Rxhnx(YHI)JT*Ol+2vQI82XqZUFmKdr|?^JOB2IE#)E1& zSAm|cQG(O*p>M7$?F&_yuVL-8)C~?k9^XZu)Ru}}dgaS?^U0v;vC*HKjqkV{r|qN4 z&o>@Al7se#v3)_0noY58PFIrs4a9FCdR-@e0oaHgSbXi{kpkJu%qMNjvIA)J1oNz% zA1nP}6q?SjaTh14+i*z`{JYyH!p5Wx$H?vg{%Sjvn7Qa}*s=t676M#A;uL7vtZVo_!rjgT6@ zQFlqm4BR~741i}t5bnfZ?I(;CrX3n7{=D<^MQ!Ef^LYG6`|(gSej3Y|4dp;ZtoApiEvuBzbuyMNDAw#K&?MlXp|Jh+ob3^*Eo zAK7qTAl#ux3b%8b(yZ1-2Y&;d(drqT=(l`{3w~954a>?ptXXSW=0AE^WMEOQShqbK zLuz;iNjX$a>t>pJlX(oq<|VgxO5ysar$0&ge-y!>)Y z6wDU0?qJ2Rt7w8s6WmvRqLExM}q~T#YRZny&gQA%Ek0?JmAZk&vloKBAIcv15_orLc+SU9p` zcq!Yg$2?i(O=IGPvL(f32Fspjp=-{PYMhA`-e%nPq~nJF$M#0nk*ntrMkB||vM~@Q zkI`0u%+{V`wW3aqv#RGb6fTcf2fAa(Je0>L`^U4V1;?p146RoXew;LTyl&b*f_9GK zfa(Fn{Q2=?`D0=Gs`mu_@jSnb@`qvH4L!pAk=^47=cZsDI$U9?zSeSZbu5Q>b{m}3 z7MGY0$re{c4#fsd>bj+Yq0`t1u$SeQ6y?2BAux4M$=sO05=ODQLTY_FMwoc3y40U) zgQvPvv4t7E)_J3#*=;W>NMCpRJ7MVogC_upeayK-ZL?@x%$Y3MFqaZJCWfL#44R`A zCBjm=i7T9ASC@mwIUL?-$}hQ(KvWo**?5r=3hO|92AEnZ-P3eVXBF==>iO^sX<&v* z^sRNgl=5wQroo)kd#4i*-PN^ik9x6w4x1%VZ;q>asUSiQoN4d}@t*+wrPUi7G>(S( zup#~14ql|6@X0G2Z$NwNF<{KLCF2!7l-dr12g8#G-wZ)RvPXQQWx_P3Y{n>%;mS6M zM-UW^Yv*&5>j*7GoxE?tBxAUR^Ld>t;plP5@K#&ilw?h6Fq(cZthMl4vapZO$#(r7 z_Av?ja>eyI_5RaKEl}M)mN<3Xxq|(N_QS|*ms+z4<=0YT8EOXW-~DwjYNe;O4<&Ne zz4|$gdtRk~zHZ7)j>%a<5PfW`tYE=j3x9Q{&)DAHJ`=ssKLX1fLT5{R#V= zo1B=%5ehL>3czfA8~oNA!G;p@5;_Bv>agCkMM&vuP?b-DL6tV?phevVWPxWQU}BGIa2SNeptcHQ{qv z_6MGW7MyfgYJZEuBVQdJw8_5~@-CSU^;#T0 zfgjU1Nxr457ByCEB+rst=Mpxt$3Uqog(r7rFmUOxe5la{OahqBbk$UrhAVKQ=mfw4 z97t!c3Zt5DZsqD`*Bvoz=P48QW?%r2VB?tB2eN&tRv3LIPVO?m3L>;`zXWiV_hDt0 z=u?&E6w_8FMKc$JCW8{bkU}gIIX(=`kKtbz)^|rG%QASyfKTyt^%GW)!1jRZbpI|( znCYV>#}&wai;aBRo=Yvk+v<`&B!dlTTyWJfEgqgNbO9XxRF5Z@GTxEg!^*i=8h#8< zPPT%*SKB3Qr%^zT03F#%R0i4evpCx&Q*ZB+3w?^9SK1(!XR#B2qjjy%+C2ob|P z8w(&~)9dLE@(xQ+HW)O%%;vv98Hj-4bAp;h4eF&k>#7#PRF1f3Di!BR$G~ zz?{eJXPEE1apL-+yyG934S8#(0Htg>;%99|r zPB4bB?=dV&MXk2e6^0D;5UMA)O8n*hQ4q-}tLd0}Kt)O1w8heDK(|ZXxO;U&p}8K%p@W6@7d(Ahyp~pN32RW>A9)H9jg09*??V8Kf~|umibczm6u* zz6ZC%4oooG^SA2?!Voh&oe%U-j#mJYJ?+unhR`^J-8w(IQpU*Vv~Bv*^}TN+6tDDW z_nrJdfMbPU$f5K8xl%koqakDqXWv!wn~`p zuMJ)$1dF zuzU0=0yi_x{H%gg`=G^yV~S-K;?PeXv~W8|o2{vNL&FjAe{O`^eQ!@JzY`Uh{jxFH zz#b$5X0atj6Y7rgA0ik?8r&;$uE(_!dfW48+1W+Wn}&ruQec);Y8;&NGKoVpvI*>N zm@DD3=vC_mj_*_(6QCh|fePj`yadGRu_AkcquWgnO(}Gy)_f5^EzpB#ze$*Oi5i)U zrpMrS$@L4wm~`?Od&(5|K=ab!CZPSmRc3nUZ(9I0eQa5^9zU4RoFP12zUXr4uJut6 z?kF}OT6H;}Y7*LZ{eIQElCLu26w0Y9R@BN3!0d@6t|6&^s$=9CLc=+8*25u260z)mE@4ph+&zy>dR_b!3{D zQP3Ali-djB+9)F3ik^m(MnQZ>gRzcw26sw~5YU!^z>NLSTShCv?|7j>>dE#I zIOuWQJ_RsDxM}D3;eN3Mv~yn0c0gGyeqKh{)Q9aTz+=A=&9fXr8;b)Lt&l(&Msn1` z?pwy0^GXJeOt&MrK|JJSOl?4ic8l)JUvyqIJ`h3#^)ychIP}c}1?ugg4bk6~s&pb`SWdFW8RH92U^+XNxf6H`&Mk z=sL1{uI6u(_Mco7*W+e>d@T_*z3?AgjA>sjU%%qQ-_!LSU!u;Dq4urn{5VL}yp}j6 zIm|}`Mis=bh4%(PTbn)oPL=98$QiOYk`0la6cDHBZJ9k(7sXu*cg*JjCI}jx*r&51s_q#4C|UCS<;p%``;*BzK@_SW;wsfo;iu0xjkn+) z87a6X5Wj^#hJOxOvS8WmzcA}%1U$tzukPVZT?x-58aU=mGh$%Z+o;U8E5j*L!8H%{ zhp(xO}IRjyU=t(I~b;>33# zI+-J-nC9IMYd!Y`DV()pCcX5>7yytiCy_7; zrfq5__%ep^4I=vd8fRw5K#4rJ;3(jL@mY%3Qa(JN0l?mEnVC)0eZF4fCJ^4p<=Zz) z7^1Uhn4OL3Q*)MWb-EKBCBUGJ>j+@pns$tJewVNjr~TR4{ArS}xkKZ41Lcq;5byd^ zrb=KjQnX}>BM0$%bvBVPM?DH)ASzp~4lM|=TS+51S1 zk1(>BXP75WICw75Fp?>9TXmilfKL_m?NVTH?tGNVZ$HMKomDTs|9(9vzweNqWiBwK z6MpRJ^KJqoK;L7p2?OaUH1vuY$7D?m9%w|i;g0}ZMo$NQQ`TaJNg8TQ>u4*YZ5=C6K`u->Ez(Fx zULd#(`V5W=2d0oUcEe2uQgusjdhl+vm>Gf1Z2(4SW#W(o9Dk1UDO|OY5pt%Pp#gc* z0#I@kYP@oEJxxQ|*st!}Ca4w|ttKrSj_tY^C0GnVt!x2&E6?bQrK*Jk&*g49qfc~r zvMuUxpZL1*qjPJ&&JhKOnNvF;y`-NZG2VGOIUIFY+eLjZr+1ACd;!)@N zcJR_{yLhVe`7@4Nf3i6LxY@pQK=NS|VRq)a`PlY(bF$p;$ydxr-~k`^<@|Z}DxE4G zx&Vu>KZY#fsygg>9M#r~TU&tF0#=_dLS4h4KQjvh92>JcLW{Zb4I^-ztwZ_c{}IUO z%#c{NuF?}?H(dsOpmbee<3-s`6!a}N)hoBuOcr~#jD^`U&q1ocHER5TV2%DjOHKlb zRT(fHEa5pW44SQ6&|7l*qJ|Vq;I<~}-GK$nevB$BR-j2}yTpxZ1^R||rI7Xs(ZLf6 zOO>n+`_ICSa+@UoZk}bZySX9IS>ZXV-swbI z_Js7+K|5_DjM9gpE%Y3?g~Iw=p5m*1gP8pTdJ$0lFF}#u(ItGD5v@k+R!ue+Ha2)R zTf)uX1ODCK_Z|5eJG81E!jE-pC^Jz26mAM4-{&o5V zr_p%O!&5KHzh}B2r;Weft%o}MMg1$|t{de7N(-JBV@B=j*QM12f7)W!gHM!aZcxI_ zvr=|vO2~XhGh46f{ND z>#-w-EncnsxsZCye_Gf%9V1?`>~o4r|GUum7&I^7EhZ(fzUbP?h*2~Z$}MdhsD)yl zRi(p4MaSOa*vdK$2Z=ng!nD9_VDR#+FTi9oi(accob7;wwN@2)y)&_WrI+oCnQ=b5 z0rBTP(fv{`zWsRAE#K;XHa-crpG|3PgCxL@DU*T}Vzd|f$F7y5*fBa|`7am46F zaV0A{aNntNW$f3KqaXoL=3YP<0XqL9OkfzO(Mp41J)pT_kni>SbjPO#Hql;9);q9~ zF{z1&4lcCu!cw|$!4}4p1`7h(15Kyjg6oIux*_qvnJS*F$x_M*&&u{$x_3M%g_BHxM&`ESP`hQ|Jk5VHt7Y+UT!3;dz`h1k1 zUtNaoHV)JC!@`WKyu0}aWQ6_iKA7MC^Yw|0yuNeMRJ|U7!~dkOi!4uL>W6x<4*sgK z{aT23VDHd;rE?$-m@9K{w|r|ViwNKq3-fNP){l}n=lRnA`_d(etRpy_-z;EHaW1i( zpe?tPm6@FEJLZTijU%DSd#F0N6>8+7`dng)w&@7@>O4p1K(&Gjb2l=;BT~#FAuz$2 zOm3oL&?U{zW|x6>DnOYo#7~d9q9wDY5Iv6&Iy(bqO^{+SaFl%eSnsZAL16|}Mu--J zr7F9KFXQYT+_bd7*RY@YEk*!jn+`cvDphm67g$@{qjufdjgLU(?7kZky~rj2tj-Kg z@X)bM?DSq8cao6`^ZmU56f+!^er#lK!5UonULJF%ni zu>K0X{u&waOgP_CH@i449VDfxYWUo0e^w~h%x(5(i)>2_lAsvg<@2MS>%3#XYBZtf z_**BkrOb#WafQn!N&u6-I|EX{2arQ9on(GXW@1MkhvF*I7oqf93QhWIT=Ny@2pReD z1~IZ8HV~`!aeE+&hf!t%dy{zweTo8lN&o;L07*naRB1zg@ob$I3}Vw2ko+X`RmGRo zP}F&b6Y_xQ**Nq?>LUp*#vdwNTN>jkyxuD*M@)=5t?y)y^`MjS!sa+~9tp-^Q2|=* zY>T0W;l^l##Nl7N9~{a9l3gI&fmJOF3~=*mzCprhL@@E=>tS^^^xIy?(% za{_TJUjlT`n@9NeWaD^tg_4~NiG1sk_qi=QDNh6|qcCFvXpBlLz>%1Jx7ALqQdve4 zfMdIubWhCpBwWUndX|I71!ad0T?6j)fkqveZBxv05)*ZPFyR1%$M9eV@pS@JAKMka z4-+~g9z1QpW`0~r5qEtBT_HG z#&Qx}eb0bBI z+2reAzw!J3CiWhuUliB!zIkID>vv&hlTbb0k*}21{H|P16;5f5QI{MEHEfiiY2wJ80p%=PB>szgy(q_#ME0 zrC^oTOh7M6(MO11=H0o8cP}=aDq^;FF)+b<&O78}1`9S&uiMVR3kz?o_BC6(MwpDS zF67nJ0xyF>gmI?hH3#7#)STdFtHhDV^0_&^pNt#gU`_#IAD@(AfTz@TL(nVj6Rb_UtCugBP6`%sJIJbNNlcF&(Lz*$;hixchr)inO zbJm!{;U#BM>cve%gf3EYyO5edMw|KJw~616ecjn_Zi~SBwPcc41S&y9s8Dw<1*3A} zc#XXJ;kR#k)vj-IqmL@CizOUa`O!y%O4(2VFHQiOLwKmJe6c-B1ZfJyR)?{Ge1!&2 zd+!+^0VlQO)<#b}7u562w#1kwzJq*R7)h2#JYq7@D*i;#M`$ zQOa~Vp+3~vJv(X;agEPm<4#^0Df-=Rh)VeCJLeFdK_oZ~hQdYSO*ULJZ#s;fIsM`j z!}IP1@8xWlWW$yl6MTK!(9tO5rH{;z7K4s`EG|oQBSVCdnN}NHpejRRVl~Y14sTB6)cg$f+;x+({uG+2%>VZ zgy4+Bpo1$z`EDK2ld^^_w!;fx)q$4Cg_M`Ti69LC4Pc{-hU`#OyoXUxnV7@b!VFrq zdpaA217K`frc%?n6%O%M8E~tXWYvvB&Uj>Gc;EGM2v>wa+kWJQhS|=IITw)QA`UDS zo%nD($tW3(l|7b5WA;TOmEEUh8euiuHr^QCKyObNNf3dWXUJc}A9JmqcocpoU}D`z z0QsJA<>+B%By%NLydVc4F=u9(^sj(ksjIhVusm_vuUfr)m?@k7j6~I z8+(d3+uMyI+qOn}YkAk;q&?z3X!!}z-FIf6lLcmUbD7vv$Mo+ce#i&yXmq=BvQ9!Z z|K^ELj?}NPAL;uJw{{bftz}=6B;c0prY+WMwcec1EPM+#=~)cC2rL%Ng#=me4$x4w6~Cp;kAwyz~id+jQ- zfyd=ZH?CU>UBG?owcKr+~OhohAJ<}m!2271aBZ(CuXawIqz<= z!=iQ1Z12l7erl{mpJ$PocpqD+aAwOKdMj*B%e$=!dI6g27Yy&EUUI>})-7wJqvZ;q zLqn^Uc`9pc_?#F{(PDUwG(*=*QX_iNf!nsDJ>KqfGLuM8XatqD71-}>bM?gjyZpw< z7KG?tfiOsIXp|qyW3WLvgpDW9BKGpD3x}tY__Go{m1KR3h+|Sq#sDxg-~60xg&`dQ z%aEzG~Z?-$*;WY{&2frF?EBJMm zWp(P?K#iyE(cww~=mqT1_CETd;%%}`GU5;Ic;LeGpg;7#*MqfL24e80L&*Y4iF5@G z4c8O{o874G6v*QU2jW<7X6t)({&&t>pAUq^ftT^~!-Rd{5seZZ*>2v;z?-SQ4eSy5 zx8U}qjk`q(>~$f)io^${A1)6NbkW;M`n;ZX3~9u(z#M`hNCFi=Aq)3FB6 zY6L1>9XlX}@6R~_J+ciX;HEsN2;VrP{1i~ysu^HyE$s{xj+RMD5xsRLW}pFNPwufN zqb$bzxX{~^ZDl9enC|gWaJ0}6GYk=C58OtVde-;)9Ei%M?Y4K*a$sOcY<;}j;7n>58pavvVV@ZkQ&WKAu%Xm%J&9S^yV0zgoWw!A)KNE6wyJ0 z2^Ii4I1Wwg<@h72JPUS12XC8y!{H7-&3Nne>dEEuu4gjblQ%gr#vjRm>7nB(FEAqm zBV6N2vQ_vD+-)>1qH$trt$qM0uo_p)>SCabxM&(OI2BgUv!{q((n{9e_=~)F1S%)+ z7|s_xWM$H^@7_wOg^=Y&o%~B!%6rq>PCpdA1)B$nSiSu<1LZ$;M&Lr=|7=cJqg&`8 zkYzKAWd+hVo&IcjioIsL#~&{fnV;;~;Z8WK{7~}&lWw36GL0y1+9KHT?k1{J2VO0-p1>%u{!#-& zPDKMkdyQAS0V#~08GhR4qUPvmj)J7)AUrL1@^Tt^+#vFLnL(@$DQ&T>UAu4w0Kp%n zpPkW+SWmgGnio$EZpNm`@&wr>@3gHPPy1cM z46#F)Y#UU8Mt6ttXc)D~v^M@0f!6I(Qu;MGD$6+8vbZ_h0_~#ROCY2=cyH4ntt6B0 z{vq=#2L1N@W;0ja#FG>(zv7OkR?rDG3jDJ((N4FBH)}yEQu}}~n5rvC2&+lNUY6Mb zDorQRLA5z$hBtyo3LB{A)bw032Aesng2T^rEpx`id@au8Cw$onIyfwq*5#c5H%G+S zJ+`m*qGH@&qJE%k;OxBwU3aiD!=SjiV^x7k5L~+67#OD{wPtVEi95h6{zb)y!K98U zw!T<@Z4PQzYKZ1CxH`iJD}m=0mMO;)wtfR>Ifw$BJ`P%sMZcRzD>}&|3HO38&`8h# z{CP0wb=$52tqC(#fo1F3ie|0VKeJ@}+_LekRg8T;&~Rf-;%1$8I3lbDMhfGrb=OdU zY`8mokj@pe@GER4MJMgV7MqgWh?FN~;>Bxsrcc-3@tWA?MvJ=J#J4up_;{|fb2h7Q zod<4eqmxOY_9iIK)<*cGy)Y|qbheO537+2AtD(>HqVP#>v}fn76gnWZFO!Fvfm*<+ z!jkdX3zA^clEwxcQ%IV)7R8fbp~{W12W1gx6UZi%GlGBwvpQM7NR2(eL4)p*|JvQgx$Wk3t}BbZYggkZ@Vy<6~n4^}HDFs(N9yzc!{u^UfGpyCxC0 zy0Yl6un;ksV=#!J!dx&SdzfL&4tT91hYBgbT*MSK|#sm_CJ5WM9m;H~;;m~5Q?8Ufh#Dd5<)vr@ocQ%a|B zHk^5GF%|<^<$~ErKml0y1mraa`}th0Pd(P#)5mk|<+$k_x7M1mj!7f5q5MW+G+}Ms z)SeXWfA@8DFl=gL&w8+~U+q;-sEgNba=U-F3TX0$0poEdW1D2K)l#d_sjF6hLPctr z(cGO7naB;A9-rY3&1i_1KO@z~4G8d3wi(9?=^~yDTAe>W!%5psUHvlUnob~3nj2Tr z5VZahI2h6x=3V8kR)v%0w{QOMoEl;xFqvqy*DEkbG1d#* z`fVxzLNtzzp7l@0u0>;l+inwki@SN;G+c2-7Rmhs5_-ugl-DsN()2Uy+*@!JMHFcg(oA4e!W&BPBhR!2UZNX|}(b)((F0mU(IP|O* zmG=faq1P4Tchx1tp~k&{YxK~JMGVC02tv1uz+hSv1~$2M!b)N~!I%YEY1%0)+{jb%*8ZeX$r2dg`^a8L6@ zS>3`g1YlolX#t+BZ78*|O4c9MC%ZhaikpO{GaG}klUW;%*z1KduGlZflXqRcdD=hI zrz=6iyd5{(kV*o4T&J3hk_dQmm~CC=1{_9Ha5(f)aSLcztv+yLW$Fh=jC+m65vm7R z)*w_O4Vu+HK0BLkx{1H=S)Wc`rcjFdM;l)`3oM(jHLltHSZ{|nwoPYi{Bd-1bFm=8 zj8CGUb2Ke|wzmA)S(tmcg18NJG;c}EwV}8o)`Ps1b`t}XmEJ;XaZd0pEDo3wdesRR z8F9>mL!mqaNLh?X(eTkRU=;)%qO3h*1dTzHhgDW|mSb6jD9V`fy^%V%t8aIQ7ukAiN-bCKUHzt}%Xtm&B`YC$oUffJJSLis4*oLi^Je zT?Sk8E4xA7`eyW}$_kmL-}T!utLdV%f-P zBfOhik9xv{cGuq71O{ObEVs9#Z38})!KtW+xUE_uTeIb|N-&+e&8Y*3;l)yQse867 z;a#D&l=kgPq|5n$ACs8WjYr!u#zCoJZCOl1W+0+q=rDd|^TPURThm0=`0||yo)!Xe zWNa&y#b=lnSSu2z&K|XcVSDX>NyIV$u9H1( zv7JOs7k6tzC|d(VEXTA1%bMGQk=Gi|uTYceK ze3zR-(O+Gm?)&3_`dkonXpHwQdTwJQ!HCiXe_#2!=#G_btP~w3FuJJ4rc|^tmD%(8 z$|M%U0jC*QJsIt2XC+)aHa&(}JBWeuNJBSKTe}{`!L6*<9lK`l#!isXJV7Fp{0K)w zSX`Wke)5J-n}k-}8MImJ$%F=+afK)tDI0>H*G?B|;jQg9`@M!ca#^Hd7%(Luj-%+X z6YpkJ#2i0BPbvm;V7{?#AIAx-UWplzqP$QeM-bM`$-S1X{x~U&$&uIB;F<^^0{mn+ zrJvRp@{fjd>!#tCU662SJ}}w|-9#L2g1Ob(jt;J&Jq_!%{nAWPxNChW2zLOQ5h4KZ zeUPn9foBoR*t>^Da6%??y67>(A#1q5(W1iWLd$R&6aaf1qrP0ppjMAv9Zhl1p6o|7 z>{&UV29fgxI2RFGo zY3y$=MDye`>JM@LZGLO|EROHy7Ta1QsiCnbePz;U5kR8-ia-;Wr`79_Cq7;EDR(WH zf~qCBVbW-|61TUMSH@gHO%6H31#4aGIutQQU)`g-0Azo(2O6W~7{dkl1qkGTzJT-Hj z#6g6(E^hb}o+AonG%-1?v$Yqo@2(_=sUk$B2Kbz}Dm0ZyjyG?2w4CZX-n#uYzQ?*h zA<9n+B8l-kO+&JP0{8(WqJoG~&@%T`#YKyNYUA2A0jl{fL^HTC$7BH{D$7rkn-~(< z5i0i+5)wB$<8cUO!Wd9c6*_uZr=7>g)!TUVQsr^HP4QdMxAugqwzo$86DAZyp(;(j zI9BJ6{Wks2L$M}~RFE(j*S(DqDO`S3c8&}JuKRdIMAX;NbPOj)nhc7Ul^-ctw2n+D zB3=8Nu1ihVs#+ma3sm&`+}Z#j3K;{I$(;$3RiB&w0fKnj&ADyHGh2(WMmIqi;WYTf zuB6aMkAno?! z6KBR+_x%6p!8f2nd)*~o%v!|wASYHeIp{}yd#!?tDd{Gi`&O5CW5rN3^t4zY;Sbd5b&_N_OPSRA>6=2x z)+Z(qo4(SLZ3AWq$_jil0UCUkdcKb?k~Ua+v69E3VN@Ra{$CE9r<-u=*RUUg?32TQjeb^O8o1M#DNDw!pNWF|}wg!-0vhxOi52 zXj8RqCm~H?Fax_D3#U5RxI0?FNW81A=4pjocK-Gm3B|@eU`Wlq5 zIM=&-L0B2W+Z3fq+5TIcPwUUS7^<~~BfsgK+H3I1x4jHWoB9=RbdNZ~%j*TEitna6 z0`MH4c|>6#T75c}f<%Oz2ie=N3mVDgwTbh$P6pPw_H4@0+25Gf)%UdmFj>4ljsXdy6(e`qN&UKmRW9Jh(#sI^gDTX@HSPeBfOG3z; zWwCAqVvIN$*NrMr6h@5(%q!)Ve`8UXvtLKmEbCMahyYNi38nS3YG--F;O5s(L!C>cchOd1l} zN^^Zj>TJfQfCr=94o3k8-7P|kfU_~MaR6NDsKQ;5Qdq1Hz@UQ2w)QcpS4nVfTNv7) z#7P(dsUe`pXwdp1Rvb48RLurS8Ndw9+ZW}4Rbz?=hcTr#$1U`=GTi9ZMPWI!2-Abw z-$o-S1w0!bHKD6Ay=JEkWldoqpq+f$c%2)zRY?+q?i__yvRKf1%5v<$>19wvdmHyX zBm(+z`tNYrz|iE@IbPZuzH`(P+3cj`S=;5kpHHaFuWHU#NOaziGbjQMqo$}MGXSU>ZaZ)WBY}sCS_et`PC&|%Ra{82MQBKMYGz=QTLk8c zs^v{KxA{a~t}UXCgAf1?3+}iLN$L-GW8K`$Hx{v%EV@W}pe!%5 zVcYweKuDA@5FvxWNg^QIZWVB!Qatjzb;!F%Qdk|Y^Eldu0)jG zm?1`rs{StmG67VOGV3mqij*oi5pp6VWEBPCG)M`eODU`g2^krb2aN`^RZRksJT(Ud zh>%lizKS#;gF62;y8r+n07*naR6r@KelvhTD9I@RO{?iOYJwOuEE0;s6C|Y_WE3P& z%1CJdr3A`Z9VEt6Ng~w{#TNlO8h+1Z0UF%~gHSWiDx@|ZU|qK*wD_tR)dv5J+_b{h zc5)1TGJ0`il**idp~$NuO@Ky#C1`>ZA!SXx(M1daDAe6*s~F3o1%RDI7$RHR3BpQ1 zHM~PjCt{#GNecuwFeK9#18}Z$7>v@jRwvuOSVGRyhpj9PRS;%_PI3~Rq>K$FtJjVY zM@35->}``oEiu|@r;3MRkcu)l#sdo(X0zaHo!oFv17S7-P$!!+Dv0hI9V#`8A%%E7Aj!}$obDAa*gG;Hk#8umG3c&UDftm4ar1=c4*(-zQO z-Ot$QrXtg4Jh`|2?%G}2Tq@p+^VU3D2HVCK91L2&wHFW@3!VL<0DKtQO@IIprEbU> z4?p@S9(dq>JoAg50cKz|u8@ZTo09!aTH6Ek=#h-v`0;niPsEv2Ex`-~Dq4oew%Fl7 zq(G2}M&HU5)@HER-o6tW6Sjy8Gh#4z{8M3JjICUT1a+yD?3swMeK| zcbr(%>UZI4O1O=MHCTYLXar9Im4uqeJ+74iDz(`c0D!XU93+NL6c9v-qs(#&WFk$4me|($ zUJ3MTvRE2*^6Csxf!-W;ZqI8}z~l=jZbu_i{1g|QpP*-O*x;JM7l4I2%g`8NbUOnP z#5Jl)PcYI_Qe8HOaaUM-NfzGeL{szHuk&}Ky`dheeC3;Fx@ zD^lp*%0fg`fJl{XS(Fk`E8hR-@53{%y%q=dAHZ_8L^dY@B6kz|@7nG(pLN}cHekZx z-+)@j5QW0wQ}V)8)LM}egOj=Ps#o0Ox&4aKITqD0<*$|p(*74+lRJD?W@Ip!Eb2&V zCB)@8g>Sm3_LgMQT7N}nGx~Q-H}OLNi&+H511cmhnr%ZT4w-{A3YjaRkSwWF1!~eQ z;I-;Kl9SV*5%I~QD-#l`rZh2Qw!*=TN=bW@6yMUv=7XrZEsv0?>a(O`uK+yAGbHyL z$6`){!o<_j zz@U-X9$UwdNY!|`)4=+<&Pdn!YK)lfP@x}E$AEKOn;7(zrP*{&lhVW_$NDPt<^uzT zZ6SbczfxG6K1QwYCcGKoqy`#5j7(J&g2cf>rjw0R5F>#>MhBXGmw~5Fe#>A`(;)*s zOlLG%yx3jh^s=I662`~Ej7kA=lEI!2z@dEuNR16j$8GXxuviw1XGV-EVP#4&E8_t`q?4fnoRw`= z^@67YP!^`nVzHj30b5&HP83M+ZF}a}Viu!ORpS;+u#kj8js+M8V8sRFsTC>{M#|D| zslNL%Ct&|<0OgGBAxVUhPs*^)(y{Jx`#^A80MHCLzF?eQtWW_A#2^|$l~C(|!Ugk8 z*q(2R@D-ce6bwQXfdQhf3i4gRutlGTKE_brxKP`Rv-mYpzJrdvNui->4VxKHdpxOUuXkMu zwk;$RHrZ65^#*zK?a(Fz0Y6jyaZ^XuFu0-qsq$;yzlR>UA7A{8XW~8Yeixp1+w(D> z%`mQ3s5v2^Op#q73m&8;Q0I_}mZ){E zNBaV9n1}`wYE%(ruz^Dioo5k#3UxqbX9ZG0T`n;$P7Ag(iI<1e6Ge<+*hU%#WdkOk zf^$)6y)z!WytEPQ$uS-sk|Vm54{@Ce4J(#hm@LCU~^ zydSo^rScYLDLH$dQNn2yjEkj2jj3TGDeY9M@TAHBh@%-<#xN!5j+2Dh_I_;DQF4mX z43+1ybB2L=-o>(xC@Wd>kjfgf`Zro{>-@sUy*Ysa9 zE)+X#3@GT&U7yhOh&VP3xDG!sAQWpiy=C1eC(K;9$lj zmt@iLC*yC^1Ee{4k{V4|>MoceL;5+Az;$W_PMj$?dJ$e09F8>d}N8;)f{!J2S93GtGqRA&<0_B{&#`eA)0Kj*> z;k)swSKp48zv63f%{5O004!E33`vbZXH(c|eHb_4V$-;8u2Xi!3-LxlTU;rSr{Xar zZ_5c+KZQ{{AM#18Kb)pH81H-9u}NPmz}q{>^Fy+YhxTiM6=YV=Aso|MtKk#+%$SyK z(;<0(JcZSX2a(PkLz)jD+7ZKUA%L?+2$<2+1XF-95j@eHDJ=ef3c{*aP6S7}!5SC0 z9Sw3Dswk8}dP1UE$F)@sW8Ya*l{;{FMk=7)6Qf2DpL^`kny{t-43kAqp!Lr!NMW2! z_<30hWwlTC+~~t_0qsx3hus5KNSP{}}Cyc*q0cZ;pm+EK|*XV}; zmninGbR@f^4Q>JL|G0Ys!<>P12w0pzXILh{X`>q-t%7T>2wK0@5#ahujFuvRA%?Vc z-gy8n1+Wh?M-qUQdeK)v`7G$<8F@E`OtaE$*wSQ+GcS-rKRQDqENBMc0fia)(1n=i z^8sw53ESE}%cH2r9|EPUb75?>>qZt?-ccuDC4z%k1uzGgOi_X=I=Y{_QF5SZQz}3~ zF=5B2!$G0`$Tu~toIG*2;J?wZ79B~^toKsVU9K5%jxt&wr()HjHaxIxuV`0nkb~_( zsCk3bIE%3E7c%xn^PR83Jh|7AerVr}O0DU=-~%=-c)G{&jWwAmi+HX@a{c6tXI=XY zyz1*;g-QvxJm)6d{&lxwHVmkxpnzplN=k@bkKAKzq`b+^edy+N$C|k>T}i~Rx4@vH zIvvlQ_lcIAz!*a`jxN$+SyQ6$U@%)WN{i0v`o+4?Q5pld*`PI2qv4=!6f((>l|i*- zZEMNCM<*%)8d0H8Fedocw<}{#TR89V`8W@UFt;rZNB~BSU9mQRCTtRlF2qMvi9*2~ zGd1(Cz}V$8c;xg^JaYPB%qwAgK1WTuy`wOy9??v!r}!2QJ6#C16kND{9xgcl2^h>P zulOO@;pYuoBK6w_yb&wm1&$X%LI$CLQDC}!LctP`E{@{S-N#f@6Mj`|!M^PSII?{N z`!K_ZsvE|HIx;F46-xl8hLbqDcnHTVQrt2*+V88-PoGhnt^27;@wfHtMk0j9XvdEe!Kgo5IICD5)2JooVKv|8RfTY`m zTx~hu1hz~NZy0>;A~7n5G)x3PCDaEfK@?3UlbdbA>x*tIBOt3= zPK}OY#bfGp7jd$Z7(lqy(M2I?kr*lA&O-pJk#WI=guDOhLpb)?f5Zic&)4L~70eZh zfZ1%oiQ}hm@WS))%$sh&rynZFW72Rv(Kk$e>~Ky^-88*>$b>Q$4=mML(wu9x`|~!~T5-aOmp$EM>38+{1D#zo;#81aSX!@c5ERLgVP+lXLfP$f+Kj*SA8`;cC?_Z zGG?g-2_&+UhWgOhq%>8*D3x&GA>jDK58{vh)7$Zc^Dn}P5erTzT(LbHP!^|gW_}pA zec21KwRHf;cY#^baiT_R#%B_>$gF5Ec3P@U$CIcv@^w@U3IJR+*7dM43NZ#H<8!J_ zM7u{-g0V?X&OT7QXLaen0N~ z)A!?rFa9$8FW>NL9J%NM0FoPsxI&UFds@S;;VE7>jmc)1d96=EhiUSH5VS3FB*Kq% z+(Zg^mM#;TtSylwjg&>4QcsL%sHO}Aqhefq(F}EU3d8wN#eaG0f5C@8^jA1=I ziz40)ZsR#1kdJ{erT`n6$Jc};!gv}(GNIW%dPb+6w0a_~HlVFR$7KtB=DYhT03I6A`oYkvIK1%#;^U#ui?H=KY;B+2f*VBMp`h)xB@u=DZ_FIpjPCRU?)XU zVicB>KdKt}h$TXnlH>xas|utnWmXajfBeK_c=}T>$Jc%1HzDmF17mPwzVotRQ1^Zi z%Up{6)W=Pk6xf=fPjFV2yBIFG9Dnnde~0(|`R}66&O@Tn)zooZ;G)Ajc;#2$iaJZ6 z#ZvMT86J%W6(%x|oy*4nC&B{HhNv(wB#gTwhJzR3zRx^}cm3(R0USWeRS&3GfhnUb z&)@~meHyO3;z<~f-G^be5AI>35HSW)gOem_m1yqduu|MYfU4_?bzbB+cOy{LVH9VWaoS*+|mCj^l$xnXOL=^uXD8Kqt(4yHOE3yoS#0u3jlb_TmA$7 z@1OfweBvKIfh(`L0q+*vvv1g^VhjL9{cCT2Mxa#OO6XDQNGv=klxuBCJ4*VA;^$xCw{# zpU+3_i{*`9mWm4x9L9$~a5p~u{tsb`wgD80u;c=a8I(1qh*`y_v`|^L%bgw>R7Rxv z4BJGQ&*qr#KY(k#^DjlI6{#}DxyrB423&2|&`lTz(>wZr$>5MwUfxWb#zG zMOfI_*MLkdTeY32&&uOwG)k-sW1b*TacqVH&mk1BU^)w_A>hPn#F1f!cfaFz@Y8Sl zK>%L_;0(lrwhLemY#jj>e~a6{`TOvr*E|#F9h~9eM=N%QZ1Yw;KxRA(@R%)r1i;J~ zS-g1{9RmL1L-*iSFaKu%wxk`LSVR98f9<#8&bR#nKC>#wvxKoS4sHYY9lHG9 zx!?XtA#GIa~aV-+l*P_KKI`-JczCczcj=!EBB@YTE_T+F|>wz|IV~ z=i!I(ZQu4CXKm->_uhx$yaU3_Qj#1d6`nX+=oeuN1RBF&*66jS@JRX#^T?SX)d{VO zTz5vA@?asqT7MMWO-_b+n&1h^n5adSDZR@YLgyJQQmiRgB52He5H6lrovm3v4vo6# z_NiuiHbtnfa6O>8(}u!Nzry{scO#>xW>7sh6dM}Z_`npOO`+Hu!Tcv(CRQ>Ay!gd0 z#=HOPJMp{k_-%ahqaVeUPk9Qy_V(LxFc;lP? z{pXM9vs~YN`wQ^&>tBdlpLZi}z4gn1#b;4YejI7O1LEAa6nWU`6rbp~w6!ojIAunG z&MIt-c@a6I@Ez>de@mk5+qJY_JCVznq9@c=2Ex=PMC}*o7AVn9dWroqhG$C4G<>$- z7SLIeRnUo2R$HAmsALYJ5b34SNEXp3?Whl1zkAX?qe?RtS{(@ISw$H;y{_g#F^=n?gCw|`X_WuW0UVRPfY8RO819*TKlBHtVrdM_9^$Gx4n65>u zMSa(3$4_VH$QKt)5V_KZr*mZ^ppB?QLuBdgT`Q#n2W<*VGu@&uq zE`NfIZ`B5g*hLjm|8xT0J2FpBtfv%EZeUCt*rMG#HkKU@7#KCBlq9yRH2`0VQr z_|jAQsBl;Qna{WmyH7cVANt`R0swsEWB1^xS6z*-`?{~gfddkqTgD=6)#UG9aL4aH z*QcZsIu~B@T0Ig-?vx@6OR7N8NRnhUO61CGi+)gEp<^P8S;-wka1N_&L|lrd7o-5% zwiGeUlGieg?SZ%Kt*U;>p7>Sv47o4C_l`AuIDZ4&u?!-tXvEI;Hg*@M@ZI0}-5c@$ zPrYt?$#wX$TV9HbFTEUJ{_>aL*_U01j~)9s9ve^N;IM^S3ks<*DabAYz+=Vs))r1a zw2SZguJ8Hp3fErOJHPb5;?V369;)}FWXWYTAY&hI;pg7?f1dOGD=)tauYc|9@!0Yx zXj@~HQ<6Mv%6DB)QAWZjNCcExF;DxjDhY4=t{**XJGb0;3ubACQpTu4K%$9~8#Vkk z0H#L61X5`r&OstQU5zb@%H}aO$|ZGhQR)M0LpzbGP1+F}>yo;{EO8wMN{_83rDTx{ zDg&ifi>g8>2eo@NeJReKjaQ^MYPU8;_7CxKXme8629Iy3(BIy)-5@9c)xD7oeA9Uw zpwtwFs2l4RFOO0Xxhhv>f6sI~TkPxYZYX`%t1BXb(NfTz(90$ZFi0du49)=mipm?o`vY&QlyB|ct5b6l*KX3?F zz33b8ga_Y;`T0-AYFuLA6;>>#t88y?;ZOeLPW-!H_*GnY+Y4~b!5w_+SjG1K1WD*d zZoIR#i04;I01Bb3Rv6O^2M_HB0KE7mUxAa4Jqi(X6*~v^;q+sV;UmKl%(gPlK(_N$ zl}Q$fW%Sz#aBWja)3#M84Vsrkt%}0eDC);bpHL?b!A^;0qlpO}3WH%uRGMtwa8TyB zO|CenbOBWv7?at)wOESY#dd8p-%OM=V~Tb^vgS>S+#1K&E0lb~KuJT2yTYNX8(-IF z-B!Z2J_`KnUO5g7b*gDjRhhl7&SCs{UPW_1EX#;9$CkL_>Zjw#k%RcR|6U9n@4f3U zaLv_M<11hKQrz~uTLA#IGHNL;EZk4TIt#K8$8cJvrzI)NlM;lQAyERWidw~ULng#j zB#;qxwf6$E^_7f9HrRw|dwl|IW=S@n7(m74mplOg@cdh!gT-iGKaEmdjleKyB%PFZ zUR;WJ&S)kz@d)sM)2kJJ={Md5{KmU*VFJGYCw>I4y#1f!iC5l;@#qIJ5CODLI}-#6 zNszfOD1C9)qqIe^xoV>T#n0qSW_>2oB0@$jU}5m{QM(2Jwao<9aeqmBmv_$xbs7-d#{oYr)|o zPrzS)@Pl~51(zv*AAM^>BaPJPz;yx+S_EyYMjEZ#3zZU{9F+kCXpRtu4C$6TV(u(l8BLrS8o zpLgUiUU0*OcyM_&E;>S3t_p@UV6iCR)A!;0!$$xfq`Dbo+q`5#o`@k)E)vlDwv-4v zKJC#xfrt8hFlns~lNlxhzfuQ~g{4vmYAOJ~3K~w<%N-5%KCOK7UbI*FXXbmN_@vC*U1&zwXArWdOEK|aq83WsK z@1i#m*~T1ctho`YM!z(Zjqz`x3p2cHeiDemhPyG6cLh}20wzmlYt^Jr+)CzAJOIF? zda=zfjhjiv-UzN)n!HgNZwc#s73e#B~tZXwwL>9X~gnAvz#FU6$&hGm!x@3AB&AL@Vf(xtT>p~mK@ZF@+n*!}_c&s{ zH3wEB-h0V$QDI!R zDQmtbN$EnV!&Fkz$X^27B@=dG$i1Z0W?WEq=VWd?LBwm%A6s<0b>SSVjE)c5NVF@m zx?%Fhn%=orQ~h)|NY@#8LD9s9Z4o|LlsX`TtEU-QN&{yfW)LBBYHHd+i-ZXB#Pb7@ zF5z8~4#2w7*%YE^`?h|&gVn~t2AS1tlnKzpd^kMu*h>6k65)ZI$Spt>|#^J*=JbM2F zc*|Sgi6?IZ$4{QYGR={Zu&fpH`GAKXegH==elnhM%_aEQF<`c@Vyqdc8gZpVUm4&b zV|TGarYuBU3QEqPx)kMPG*&o@C9^PwoKVw%G*1A}apASs^80K3zbNU#LZ(re+jS1McNHQazp!l0Z-gl_jc$)l*>yxUFm3HF}4mX6Fp{O=} z7K~;<(mqN;HIir|CG^U{+fKpBAL|WVpi*toh6HeJUeKn0_Aj|2rg-4Ml%lcQjZx%* zl+MhpOlKUQ@Q-M%@0FmwkKO0FuBd2D9>pCq{ew+N{{ZMWh1&wn0X^QzZ?1_?p0RrY!( z5=BQ_#9mz9oDO^9)d^bZuDuB^?0ht%Ef%S2$g(Pqy~ErlgVs%KA#fpizb&prNsvXE z3TtLiWet00l$C_(AKx9ZT%3_(PnF+rsj@AOWL$hr3i9otTux$`4YKg2f?2A#{>B@z zHO%m-2Ohxp{>vZ5op;=UAN$|lgzIj+0juL5!>~FH%5xF+DFMZjKv&(WtOnsUG*574gh|U5LWaoc zW@pnaDqu10IHQ8Y3j0vm-R{>0lfkOt^2`?I%o!b6WfhEuyIarC&1JtN7{#;RNpRbM(ZKA|dMG^i55oRO#?vt&?c zzH|Y*qJqna?d>HVdf*`x6j7&XhO8Upozc68(%MvEWD(IU+4!94vMG+-qJj{F2QuW~ zh5?y?HATtCQC0PKpD&#lw_|kIqn19#ow&IeerJ|Po+Cs zxD*CzLKpDtgxx`zTlR%OytG?$sfrLhFAq>bm%{0l5rrDy~ zWZO?7+2YicW}}IqNU@BkM@Lh}f*GgIEC2v!PVZv5dq#A2w0xo|iy^|-eCjyODPaVI zID>g5r&RHPVMw^@$|oQ{?NX$aamO8hggfr|Bi!}f--#djp?`&|FMKLKb^j-jw=*)$ zgLy%>EfvDRbF5fSyV~77gWcsW7K92!983`zji z0pnPZbH(wwtcJ?&LU2`AsA&sCjGQy_ILD)>PT=%ICvp1F4o;pvft&^(hjM~(VE=v` zr1S8GH+(1F@*jU4+w;RXvpj}`8IYF9G|2j)N>(Bn7gMH411c-(a=^*m5jb`l+q^B& zJ(W?$5oM)ojhcZvpc>7NMT}9pR`lp~cY>*`S6Xh-ISq!k>{D$e=-@(jq;i?H413@R z*&S*#kYF6eB0yPYo9ajw10+i_(mB##ORBRF3dRgrzP?;%sF_jCam5Y(vpQ-SYfF&L zyb^17*K_{RhEk97YA5RGZ-d$8o-t2IHhKsm%~52{+JKmD?>aKbqejSTWU*2jJ(z%$ z94zLQ3UKJ}L;zI_rKYwRLx_rxuT&EjYSbYH7s4LAL?>~u?1vq~nuQ-}gctOsH=h%pTSs0ESD?ssEewM%8X%q3s1iY z_}*{-Nqot**W>1!pN&8J?1&@VgC8|dN@o&!3*S-&7Duz}T$M2y>xk931XrNcg4Lp+ zjujY3WR*GD#zMy`sjyM`C3HE_dqFKqH9F&MJE0|hj)&^F&J!fRsm>m>0kk!o%GQ=# zsModFffYKUYJ0DP(!`ehPUn<}dbEjyFdOU_wRzZCqXQ2xk9eHh);2;Bn|#J(Ilgli zMid_T{GIB8&K%jHYy89CY!y8o9o2QfNnNq+0FeE^wq?q#+<~QTbZ+d9jj2GW6;u;AB#KqJ*|sal;@a7iXFrz5T_@JVeii|CZ z1_O{#ku!t1D7y5dM^yEA0(q9@RHkY?O2$CeIti5v5@dWUS5)GL{w&-!6QS^+_)M>=gF*zxoOh8tTE`@H-T#XClyaIEM$ zkQI~u(i9yL&hBT_1p2)UNsS35tXt%bBzb@sSS?o=R|S+9H{Ngq(m=TL&+f$X50`lV zd*6qvpZ+ww?4>Wo*T3@XvH!q+q(P!dORY$WKoI`sMt|ki!Xm|>-qgF)cfp-%2A4ul z;w&zSkj5(8z=*`T&e~^!M!|@DHga^=0Lkbiw1msO^RIm~XO3*UQip&eS)$72lwpIf zPDqCP6Rk<)oaJC)LxRFU;XT*6sI}@_)0nUtt=59ZM3UN(B(i?s43vVE9x=`!F*L6h zBBP5qz!Oz0m!syI7oKy&P0vByUE$|{=HKD2zx@Dy??1gAS6=*7+H#PLH zJeME9btT6z>)h8foKcxDfU$e(G`{erYw(|c?H%~dZ+IJC{<5#eJx3qLzS#_15=t3W z2Y?!(RE2@bejOYeadTv3xz8!JtPz<2h@mejofg+edO9R7NUV9RsNYv0b^^;&W&Bza zc_-r)1lNb+u5+N@US@n{x@An7Wmmsy%&ozY6W_?<>za$z(s2-E%U1<~Dj{XjJv@D8 zU|_a>u`Ohsoqu9;S?92O^YpgV*`tJYuFdA@6@avpw7SBLVOemlcz~OnReZIaCkf!x z3^LAcOsVj%YMo9^Co(;-Lc-#_EXyRR&RB(Qfs#aa>frZ+C-gt*;!O$Jk6~8;A6gJz z@Ks-f=YPe^@aenmLgI`}Go&Q-uS&%iJaLYnc*`H+{*QbVm(FL{tp#;}^CaiX(-Etp zdn_vBKw|6+z^6}~7Mu=qj4Ob0LgIq?ETa_hc>nWnd5z@!0EtyKH64T-Hw8hqgUK&Z zoagf`?9Aub-Z_As!w0bczzz-`*utUx+t@z1jbSHaYimEYcXmMYEMr&1Lr}{C<8pz= z9(@cq+;ju3Tt0+1y!vbL)<1eLzW4|*mJ#!z00h*Lk(nXkdW@Vh>ec{Si2|Gr<&aH- zGa@XP3mm!nW&oeWAH3&}F(%;3ZNl+o0qHSeoPyqO3?%4mj5g7T2KT-Rzmh$esA_Oh z7<^%znoh?;;*p{n`8U2JIA>ToiXIkIy7YMsRp_9&?&^*qEnp6RPRe4G-gPYmVjxus zqZRm-ewCpZBZ&cxlv1OIprrN}Z@wLsHD{PI_rPX3pRgNO-pGHimD%HRJ{acAwC<+l zP2-2otsKWTd^~Ay7^(Y0nEwB`+6krOP7ObL(v%_Rky3hGE^+3}8SHFtwRaZRq9X9bP zUTiKlAV!p9hfLo_;u6%9BbZjx2ssL4(GglSo6#{PG!Ia6Ws|b-H1p~aGx7}B9hdl< zkKKb$-g`ej`r%LFLx25IeBiJD4j=g7-T2Voegq%=)F*IkwZMEn$1GHyazR=c~{ zJ-xuqH{T3k2S5Fz--Lho_Ll4H z*hxnzpdt?(Odk5>;~^t0_iU1p5f044BO@nF z(;^+%6S6f;hJD4M!O@9C!L{RMDQpig54qK`#w@jc2E@!y(ty(u>uX9cYAjjVRwuFB#+g;cV!>E0D;6c;^s3^q6Du$?Qp$4VGqI+eVxY>oD2WNXt6dZtQ43>L z3Ck5>d8S~oEI4(h;>;2#izR@HWnDn1LX*X^;z@;q44d}D^d@Hs1V0S`O-~UzQent? zGMO*J^yM^D9P4596gI_Cf*F(;ERk%sjSyjxXNF>K+Lg~?^{Y0Eevm18%sW&mo+lt- zz>sBuP!hSIX5$kn=^{Bb-r{2)48)EnKcsg^!kA7TiloREfxmAq!ELY`#bt=y=dI)kS_?Hb&4(~YR(h~NIL-@@x(|9ZUeMK8juU-c^7d+)sxc^i7p0181jg;ejo zM1_$ahO+@vYgRb+`@}#-#YhaIqNg_joN9Po@LsX^pa4{WSly23dc?y!_fyngA)&*#$qAmX4`YnETJSqDTGpF;+;Bk8mq*3?sIO& zU*7RP{J>BA2=Xp)VCQ@+Xr&HqfXpcD(MeUufMB~4td}Vz(2y`}Z)3i-jqUwA*mv+C zb`BiC{(}dwvwZ;jcJ^a?XB*o)TbRvf7={6}VGBc=W1BKEX0Q{%B=V<%Q6xz;7!|Sw zZaD&!ZA^qpSmhW|LSaT(Ra|}5Rd~%;y%zIb;L<}^VE4=}Dh3pt1C-i^IYx_~G1{nH zuwq%r)+9QsQM8*4in!y4q|sO~qqph+u1zFJPAYSd2w!j-)QIv%AEfWwJ62u_vCc<> zw_R#22z<0{U~Kdz`WQe+E;q%G)wU3lzH5ChSb<3LfeC*fTtAGLtkEnbf%M-`hzxz3 zUctrhy_&N1p`SwGsVWhqjT%#&HWjxGv@NZ%$=Y}`Wal9V=Zr62(PX4oQ4kXA5-0_) ziXs>!vXmJ>me53rHlxP$RT<`Kt^|J$m)}CPv>r_liu_)}(kf7vgo9gzPai9|{^G-U z>SdSU-2krKp5ydM2^~)W>h2O3TyX>NXTOd6|KWAG=9yoBxh2msj%Ef6wBMG;rWV2V zdD{c(BggRb|MB;634n1iqONw4W^)u&Y|Z!M#EC}%05@KIK0b3w@s~7Q)9F^HMam## ziNZ+|)sz#kd-4?Se(*SOszB0B?*nFnGmH$>69B{j^`uKL!o`2Rr0WU%aVKdD&WFEb-^V2VT*g} z3y|hQFD$~n5Hxb8qe2gn74HX}k$djVFh@{t;4qsHVs zaX51*(I&j>oc=${-dtx5(oi+mL_3=qefS}H+f6KoOPMN+o;wd!gK3SQ#3m;7buUlr zqNu!WV2L&k6rc7?eXl5^bMRTOo;Lj26P^t(()7mky`bcB5sFHHN6=J=(4)#&@CrnP zXI=L!R{%s9Qij+%+1p@1j~70BpEqM& z_qLNLf@I7*)@Jm{Jp%j}HHwu)(83U#0G(ipRG>4v2g(ha1*#O<3mK*>9?x0(N8K@NuISJ;G zNAJhgmtBa}>OmadsYo~t?5p4`GmR^Q5}}TS`OZOn?%|_AO4!-n4?@z@9!2pT7fXz* zQ@H4&!&sa;g*+rsWUyUbz5=ge z%`ida`YKs{PHO=Mw*E=G9JT{Ag9XbRgCyd1qby91VbN_fI_)E%&A6T3qsC9IxEXmn zd9&e)An#SC$E@ODQ>7C)r%Zd#dPALPETBaS!=`;F&f|O52YY|oW*_G>eX2TJh%EIf zq0xSx7sm`h6&kStoH~9QG|RZ*`s-20ijRNvqqys?KgWCD|2};7lMmnz-t&97`PsK( zKARz>i~)L5SjvtoNq*eGp&q~nribmAkyK8!92wXqjf8;c)}}>E4=C8}6S&l{hSQ@Q zSU7~5jnQ(Oh%wjL`005tR@DY@%r#NzkrF2M~WV^SCMzjD(`x_GB%J(CEWjMfK}k>*ojr}E@{t|~J!XFO4r zlpAE58=JezSUekV2BB~P)hcVsVMIhmGrkgX%xPzOfyqjQDQ5Ua47q7M(Md#K8un(u z)O~MkvVS&x($}CCXcb}!6&XT%&d4j`j+Itd=p?(cKuyoJXQt;dWN)a+Z!}ANf_NL5 z8JT6ffG^@>L~?AC;Ky^j5H*CS217}V?SXLo#E2C#u7Ban@hiXlA5cpH=K;hCtd_fy z<^X_u9yyL%09-Ijcyza7|6CNHc)**0+eGoQg9|I&}+mRoMdVo}wh zIbu03aNhpI_}hE_9^duGpT%M*IQqyLr1`e#?y9)7F-!!|03_RkloQf?8z1|`-T1%$ zfA-!y?6RY(_y1JY-shZm>M@<9lXPa%O@=l}holF(J0T2$I53I>GNXbZ5+N!A0wN%T zK$sLzctk{H&)&;30=|G4LQ z(mC%r`_!&owQ7yuwbq9}&O(2Vs;L>2eZ)D$8oc*Z)rfm;{th>N?gqYh`}g_$b=R_G z^9gJ^`AjC`Q(Cnr_?pTaHUPi(Cm&(^C6{pS>1Xk!+XKhXL?3Z>Td0>YJ4uX<-P6=aw15qc z#sWBvI9tHuQqHE4Oedy8tl4911mjJnYoku9?6^!bPY9&$ftgZhOs0YOvB`|X*;a?s zTejyV3CDCMGIxjuOJbN^;h!tzyN>cBLbq^RH>PteugozMlve%OwMV+a$fHJ+jw-o& z*wtem^>tEcj`cc*=9KxYObd+GllEVH9j!vN-$Y4VyL`$H|*dp`J|m-gp0v$3E_{06gcpzsmD}?bkT@l#?k7tpk=T=9|oa z+Ig&2;?h~^!bkyJR6vR8s?NlSo3YvvOKB`Oh)^Xv(n{B;Y~jr$Mb89GD!iIgG1B_9 z=#Z8gLQ+X6jKLK>ZvM`9c6 z0%D7}k+z-pln_=2gE27`Of-s>)7n4{qbCLXj(c`r9L_oQk1PCGs&*p zP8>_+TyFKAYEQJgkq#2Q-T<0=dD#npk*l8lB-U(LK%|b*ZSjb+ojE$HVZ+*!wsXy! z-^p`-_1C%d(jAP(HH4r@--2&_>n8r}y>I4cf9^3HzT>;}W(MFIXliI2&RN7XF=|@Q zF+6k!>yO(2evw#@$LJm=1tlGV4(+s&DY7#sF&v}tSEICL3~h&uw0H6BSY6d%BHX^g zuf(oZzoTC%NZAUVboSE$Z-4hgL=su*cO7KMkWxqe zymQ}UM{rtsHx=ahVKTQf$)jZHQ4f%06YVnG=WBZ0F1Ji0MbcGX1}y_ivXuY;AOJ~3 zK~zFv)kCL@z?_OBV4On?OzH+g;FQx&RnSU$1)* zPg?waa?)pCr^=uxSCV#>m0Z0>XCk_D9nYSKXzEV8Bgvpn(}PITUg*qS9lSpBGVgub zC0(_6Kj%s$2;cwy_qpK@6Y0B!rW|$bwX(zg(+BE9&_u>|IR;t{1aUJ$?LfG zx_{#0i+3;%6}AzaiE_BEMhu&hi+Ai`|HV5wc<=!0XV-FMv=n)V%6<`#v=MmH&RIR1 z#u%iweB*21%gZV!?O;_z)Liw?EBPE4e| zk7Oy9C?M(yo#*HtSkux#w&zWC$mL2|;CFqV}oy1PVUM*SJ^< z)9DzsOwmCr;@T%glK$IeL0ukb@(y-i(<8P&&NY9g*yw$7&7;3a?fDWzpSnaRn$Z6# zoh4tUOeJqq=l6M-sKK?@OKbchE!rprl+x$Ph_JRbp0g4h48bO*)_N-Qd=j%$y(UdC z%bi$dD|*8PngFw<cD!p3w}19pHf%c|-$aO0V;Vv=VcRCS`u(5aq5Jo; z>7+BbXXIl6MQ`%Mm=N`ce18Xx#OU120KRr4K4{sWWqIikrf`S}4BP;3Jr(ejr~Mp< z%`9UZn3ZT`d6Q|j^HL}t;7q`of|)Xs#ZNr!a!#0?WhkOdHhM>$3R!O+Lh+nm;@h{} z#h<X0-~N?XP~jn0snUMZG7i&!|7{#eD~gfn~6ECripcp z41zQPXN!oqQ5kOu1Z!{-qZomj$r!fo-OK0x?k~9E(?813oplx`^o3CcGd)o~O$DE& zt<|Kg!8jG_NX($GLL&$=>jrl}6Pl_Q^5oBZA6wR&&`IwHLF63s_SLyyy8SCD8 z^%(k5=EixkyDaM%Y;O8)QzLi(n2L_K1DN~%@W1?8?RGkvpB{VQV|{vz69@46H=%piy)BoeCiJFLY(V>zAY*fV5pi+Er;>{5tW5_vp)1_V3DuOXUnw4RS+nOD3&LaWnhVBcq@(qm|!HP@tAUe#c|SEC-d7cdj(H<($Dg; z-+2k|{L_ze(FGSVp&gpO3nbIsbN)A&M-Mr8=Z;; zNQ0FTLP09vnNTP}8Vo+Kso-KeGhU?1%i~B3KJOI7LJrgCB*>T@hogu!u4km-+-$-POf$x`g8X~CJl_1Fs2VC z7FfoE&>&K0W!PBlX(C|ro<=!tY{7Kl;k@~s6H1f^s%Qo=)IeESAR4P}+M#M~34xZ- zQeF)iuj5$JZY2)m3oaNv1pYBoFd@R;7muMOTtBI zUnRJSMdf3G>Kc5lh_ti{MuRhgF%?DxX>=~GZM@Ah!5>bZ| zTG?gV!L2cbAdJUDj1$f~_gpZRg9i`r%x64w*b-o};Kt zC=!9F`)dL3`TjiX2L;|O;;c|No(YCRJah9iTzJ8G?A-nUp7-n}p8MQi;yv&Eb9U_9 zMKxTBjV&BF=crc3%xMSV8^7@_F1~adi!8^ESGE8=5*$`KSqGA2YM`(&U^X+`2jIC+ z|3%iWU&oLkj)K%J%4(M_PaxVTHrAXGk25io18JzV-THy%5Qmo!W1P@PM1ZA8u`6v< zBS?B_G{004u5y;Cpe*hA_uD@3|tSyNB)gf9VXIT1hEG7hpV0@ zRzsIcXu1zc;wHzsD5YAp&DyI_`bcEc>b!}9Bc-c^&2-$_AK4BzmV_WSd9?WIb`MMU zPHK%!ItD7stWm##rYqXyKv%mg-8(t?E%;h>0BfnU=S#m&$530`nRK)C-7%P4`|+_Z zIQj?0eSdX~F65Xdi;_?qL(Hll9l#7I@i#Bb|Rw42cfWz+gAd+j)$$MoXU+AoLm%) znlVOOy8C9rrn4{M8~^wL?!N8mY(Dc0ir~Tb2u@<^dy+{iK*X5nU=qW85A4d2PkibN z0Qkz|s})Syqp5^7YX^*1V*B?~*Y~+?0%$R}R;Fn&>(L4ztg{29an+Y5kj#y!q z+Ybb6VPjOci5n6mfHRb{!kNb($7^4DH4lEsetvY%E)Ly&Cu=vHz+}8aX`r@XXt@8y zm-4B<{s4dbz}@`%RnOtu2Rx03(t;O@_h1N=g`ujOHaaK)u}0IMVwAxdOWicAEU&P4 z=VkoT)1JZ^XPw2){d@V!tqndnoQ-9z6HUc!GZCQ!+F}+xpoTI;2bZMH76Z8`o(4Nr z0m)}U1y(mYlISS%hj>PEG0)JpC`>wLl-Ww$O1~*EnNk|NwJB53-5X^>biBcx%@+MT z7nJU>hS0e_o{1D8k*NjCQHm@zkHH3x`a^x?>5QfYJo>_8{_c@;* zq75GFS&sg!bF;Jz#~M@G<^LhKJl3fHx!0<7$%2riptcfFP$Z;&W<)58nA1Jc4jBDG z!Paf(P}hN5Z@Zms=WGMu)1Uqf_rL#EX6NRan~hEl@739qx^A`qwDaho1sVwiiA5F# zFg`{;w31Auxm1wYpop`yFdYVeEaw5*7BVaFMwRZE5|j`E$+#6YW<~Go5>m-UM^Q68 zOfl#qbwoB=EHuN&f4Q658%{d?0^a(zKjbT4xQ_20xQ&xf+`@1?p;tPpYC=68vGtq_ zc-e~|$JXs%;+!qVbggWaeEm?$A@1==IRMW%FtcBh@*d8JD2vP$UXB^lu_!Z2gAyiAyRG6}W z!e9sMK>9>s&_pMU7bqPxBV;sG1=H#t>%J*d3q)RyHHfbeX%IWW^%kJlhhhfkfe@W? zrUIf7PhI0eMHnw3#$!#{LS_@)bOl~Fr6{3Nw6mGywF8{RuPh>R5Qm|z1&71hK$D6i zO9S+nOvcQfIzc2BY4jQr38n!NdKy${CPQGE(Sh$UGd~|`yeJ4Yk)c}~<%`z7GR|qc z-XiklFwu^oC9by-iW15`7^@xhAUSKO$I#S-x&}W1TVw-Of@tk@<;y8LsdOn4&vrx$ z>eRGlMM(=tC;^9)gdZU1SJ;6wg zwA+pmZT$;n1I_~yTQ0XXwL)j_(Xk!kJ>r)M)=>1;Vr)OsmYc~cd|bl@{0LK3&{TwK z0?uO<6yK_j(P5f^{L{7YR!3yg+8LFvZENgoa3tYR_dV*UPJx`n%avz#AmPWtxW=@O zuFyQjOUOEVSN>!qPFMKlztg!|J+5RlUzP;Y{r0HKk1?+wB2Y~$yH-13j+*m-R*-ff zN5^0nX-diT3|XV=1j3Rbo9-QmookcWQiCOR(TeCH(eyCKcrpTD{knCWxN{ey@d~eh z-D`RM>t4(D3ohWj?|UCxPCl8nYu8Z}TDQe(N3D+2w);pxJ}Ze1ZSWY^!&z4H6oh zDY*ZJZCvw5?_gomI<9%$+u6B$Co7995fE!Fp>8mZ=d4rDc11|O!-edy4xvf9emT)g8_KK+^N`NQ|Vhvz=^Ssb|g zFu~Rd#}fBPT26&T$GuetrZ-k?PoZgqUMb{;2M|-lVu}g|k5y-XP&&+NXFitk9Hx4c z$-R>UAle;Ot)xtykuCzMLuX6JK}S(%Zc?B!pNc7!AQ>E*98Bmr?>6vB9R($iVsx#Q z_bacl8dM3Z;Dtc~E)^k9|90e3>wlR_z-9V%Y>TGghrL#hvFh*DBBt*iw9M?l=H$zUvSd8dx)Mj6zfxvwf4! zwJNAVpcYR#=UBP-0B`v9Cv(}Q7criU@zzip6Qk>{$4y_kk>|baEl5$acnEs5PKzj{ zqO&WhU&$%qtkJ@sZT0oO>9H_?xmio!M8OjVHZPAL)V1)<%5v}Gh==Xo$$LNiH$3Ul zKgne$oQRi_Ce*Q;O0Z~Wb?&cN`-_T*g79B z-&w;%E7=zHX}_YQ$E#qAN5OQ8gVVlGgq?{jA=IRW4~K*h(ligq0ymA9S(-4FV%;I% ze9qGGhzzHFV~ojBBOx-(geyr(wHPxMb<5}8BxX7-%rcYyPiSUc)-*LzM=6ulLmZ30 z<@!YS*mq4#!6e13bFa=M+6?7ZWOUh@>HbJM-)A1yeF|weVAX`~YgMM^)VWAj?P>_3 z0UT9mBpMkpvm!DV89h1AiF5cmxwxu*Gag=9+YP+vO776KgQy z@%0K6Gr0NVp`7Ec1A*~)%=n&vpAh1vzS?T8f(||S-*ZG_+|Xz z+i(jfa`(ZCQPszpHPInO4aQM7H48Jsrga+#D@U>d8J9cN=n<@mT@LDch;;+p+T+2^ zbLTw`lfxj@GNVJ^V5=h%h>Y2@YdjZa3SK zle9>SM4};`Ri%Oi3H330iz^`n`c^=LHigju5slJBAUhr6NyLbcckb+gXkf(-W^prf z@f-xf_EqK>gBX{M7D62n1ZIS9Jg!`aTeAT|j{^sVVbvghf(eUSqc0|G88?G1W|$io zHmobbkC5>Z{NxbE_OPzRgf`+Y!9=*ZBDJtC_Wo=PVl{0qJ)0V1_y!4m+`(DQ zlMdq7bgt>@=1HIGeBF+{TA*}=yP3Ymv<|Fx4rFej_?oV5NuVG%%Kq7+o z4XIGD>2%i_03x@{j)Ns<(Xq~hPPA~?Dn5fxD9NNLh%i(1 zn4KLk)9Zuu@IHVQN|~kTdz!}c^*g`8X(yh|OJ4K}{_+!VXZgsG!Tb!vr4@`dG&ZLB ztv!A{U-;yWcoF9MbBvY`V~Zy1lo6%WQ6{tUsOz9#c|05DHzIw(G`)zZbb(NXR<2ns zWfCmngjAkF%p77Qf@(wvzK%|4lj<`?e9okbv=qtL=KIIb)DdC~qUR)p80z@oyFbWJ z{@A0~cEXu_>#pxG+mCIlZL=JiI#;_S85ewLFcVolWJ)u2ZMAd*=A>v@&}X9b*ai_a<#VL zQG=loiTZj+RLCl)E@|YhE!ncjRV;ZGkDTIxSsNnh0ES~Ze^whD9U7hbO7tJiuZ!u+ zM~f9#cD=nV12BrtNoy*)I7aW4I8v}Gcsl|ip`%RaR_y{S(?|;>({s*aBmt`P=pd3i z%zj#TGy*oXrlC_w8f^4Jm)3H}2=?sT#hE8>;P%_T%?T&pkIC3m6cIu;nKUc_AN!~4 z*}s1eYZo@Nv=|s*a!FLlgr-Clgc6vag}ZKzb1V7_j1C>fP|)Bh3x~0hFdzSfpJ3b@ zV4bIQ4yogKA`uA_EIB(9J)9n)Fg6l%Mt#KE&NP9hbWzdiI6s0I3gg)5;O^y;uP%<* zw|^hcc=lDi^R2IE$Bs+!RYNazdI>dafSYc;lbi0mmvw74vV5??Q^XVsZT~kEt(&gQ zKDGO`MhMtvbs{3XwM zo}aW#uv;#m^LARt>U`cI`*vOQv&>u*AL#tP%uAP+J7F;^Dfd9d3YK7t_1`_PFdr1UPn3!r|+CsERI7GP_GXF{` zMe&(pVMSviqA(Ea)>MlVT(3v3wCvrxm%6UG`sx>O_0=!n$xnPTFZiviS(u+^%PFVi z$@r$3Rz8z>Nx6vXn0F@5FC-L3f_AHCzE$uOgYGQWlvJ1LwHI9so3|HSCkaiBvRK0_ zoy|-^h^c`Jydb^E(GjmS5iq8X`x`87W<89*!X^732Ed^sW9H{dysrs`q4J)27agdf zS=Nd7z&8=vXbM7A;pUHn-X`w2^9c9c^=;nwmOtS4-}TA=h&cF-XZ;jE_w?Ul&89V+ zddgN9-HJ>O##%g~M~kRZ3YWOo#tN8{P%mN!Ct~JL;QO~NaoaaO%`<-XXZiYpAAa9o ze)JlC;koZ&`vWdxcI`<}9M5x~^+f*SLmxlp^}qRRPv`gE@Ow1H1UEd48}vxUE)6jf z8A1(VLOFjj^w#mcTkhcYZ{NTxU-(2m`K2E|p9SD;Z+Z!rJoqQseDX%tuHS$^atHV! z#ucO*L4wh=!uY#LRtd3TS~~NIBZlZuNN6-50l#y4LNfHF>8v%18WyNkwe*pfdg&2S zF=MD_Ro^fwW8(YN!302D4+#b_Gq{Z#nN$OA{r0`w_U~Wh)h~V`e|O^#Uz_JY`Cf5fB7`;|IoYn_}|~kNi#50!nr$UIsg1e@bHH{oXzL#;JD+DW8J2WG>i8_ zIE+o|WzG|_S67ZBIPH5RbWVI&ZG#G-eJsaV>20v!}k@FSQ#88>?Zx7~S| z#RK2rPv3nFuYS{qe)!@6Z+zu5x%?4N>FDU)>p7}P{VJUMT~7$%jcsupq1v2N{J_U_xq za5&`AkA5@&uYbeqdDNpGg*BGbPCE^!e9qT3!3q+BA}^9cDVQRr0{Pk!^Li9 zO(X4U#NQ@as>CCvea;l1RPn9rKK{15+u2R-m1?7#eS#-mXTJQ$eNHFL8uJ?aO`2RQkJO&nOcHx_MeJjMvl z6jX{DH3qQSEfNU6t;r*WFs#Sa;~G;)EZx?mbSmAuCMH`6UTaBDuUSHJVoKF{g=qb0 zM>StZdm%ZMr&bzb)=IPy1;e-*bIGn80zq!+~nT0 zx}-_+I~n^OcF~^icI?ETB%P^bDP*P+9SX5PddmtEk}5u0iF4!32b^`e3`tr8y0=X9 zu7|Vx@qIJ$=^tmFs;{HFeYG5oy#Af9rYABzTnV@o^h-8V2W3*$Lc3|&J^4+6fQe)hV#xn9RTON)}f4J2X8s;f^GcI z>u%(izxh>8ec*m>@yQ#idLTl9;A49;%>j-ZFE(Hrp*K5VR9Dn>MczmvHiy)A+X^ctq0-qFLtfPV&Ab+RlQ<5Nn)TVoS_%4hqNfoYJu9q!?;M ztLtEC(K#*TFCW9)R=JZJrDH^me{>% z#gwGGO4o@OS**|Zl&S2G$a|7f*HucQgETqd6SO#Xo0yJfrhT5;T$ARkPBNW$;$_iE zGo{)d^VJy+5SrlWJ4X{bDTw;tbf8y7RX0jPM2Xy^ky!j+HC>qFg>I21j3&v_5x-l_&9VRt>Z4 z?G4}!O*6t56+iRSm-Dy(@J)`}cruHNRYYK9LkRq6G2UOwDD#3xXs|Pz@G{SrKL2H& zwC^E&Z3L`6ol7pgjF~|XYtvpeINOWP_oiW7HN5(5*YoPPT?)V#zwimp*?K;+vkRE< zw`01PH(*+%A|!gXglYx5a6g7kpRZl}87_U$V*uE8?nUf1f|m6F03ZNKL_t(NXBOu) z0w#eV1w~OHB221^zyH>Rw_pBfUiF(#<;S1!c+T6tl`UtU3w)ft`}Q-MjB!@z_e-w( z)b$*H(&o5pDWWMc)hwUoU}>o7Z#auP?-=vduU*GO9unts>N)3g>CQO@{UWBGNsLM+ zpG*^kBg+$>_^U4mUe1eu^>IA*X)k2^1!q$o`UbrwI@%;?$FKyOHM%#Q)Sxc+NzuiO zas)+}NLDTq@-n3oKTev^p{MOg` z?594#Q-AR#0Gxi#`Rv@efGsV~I!#@S%0lIZ@o0rNy#Fh_;XMxr;6s1>N-lZuV>oro z`S^RkgewE611Na};uE>7bmL<+J@4yW{JowGF-3_f=J}uh@Q=Ld>PPXhFUHGHJ#!n| zw{OS$7*zT4ErE|-`zc;^%?AN^>5G1jpZ>Y4*mlll%%miYZ^abrfEpV-;$nR$tA!0i z5QHU)a56?5HgRx?sR&*nwk|PpW6^?4U@Y}`NV)NB4lfV5{ibj7w8!q`e|-z!1TNjR zld>oyttV%m2A8TPFdmI~-itm0FZv^{`lW~SGf#UVJ1)5ZKfaeRK8P(rLW4n(Ag+iy zT6QQV2bA)kHm^F*FLfg%ImbnaNT|fAqRDI>?fC&l;}Ny@I0?~cO-?U#FFOWx+F428 zC3;Ts(&SklExS8BtaWafEH~TVbQP#T8x2p_b+vPyO?qY$LM!P{9cO*|jkIBxW2I!Z zGT!9hOJ~lcsokf9jjxDrwyk|&lKzsmOtCxOM^vD$r?bhSr~I0@u%dcNn@*begXlav zJby5ImDfY8v1bH6Cktre(7kS@ysXG^I?iS_|%*H+`Kgo32Epf#9=FE#j5u zk=cbqup-!^MMUBawy;nb3M?K^Or56<>gwU_sz5E=BG9e#8TZ9zgla%AWgq+!LVQ+h z)rIT?8pGWDER)HENfpy_OJf)=uW;_U7w{*acn^>L)Z=)>6_4Ow@4k^aicA9n+AyKO ziE;=dgvMl!k<$jVgD}lLK0&nJjLyEbn^1eJqeSXbwt<_jqeU`3C6r&JwsagM>4dqq zQ06{#3rDy2k(DWOOQ_{b?RQG2@UFG-Y5N zLKn5J+5(3ynkRb*b*SuM!gTA1PQm9A-%qccE`_qZ&{^^%r*z&SM8tSg3lr~n^7CKF zNB{DD)Z?g71!=%pn!2J`SOdV~xM9Y@oQVNq>sBpcS_2~t`UZdSPJZL(pUn2{=Tna+ z)FKqI4>0|idA|FZPx1JdyqU7-acH?A;BXydHVZi*^%Fp%;+h<57^C@!ojFKXlr!~* z0F^*tAWRHnfi=f(2B7v;jGP3YBk!i1g&*8Ry>f(sg}Nj9lYUUTfVU=V#iY zPM~_K7E#>FOiS5Ok*?2U2;E}UF}iJYf#12g1po&9KL2-K?mxcd|AW{6$zA`i&-DLr zKSpMD1G*RN-8ZcfJpGzG^?1EJ|Ka2xB- zNGsq(y-?XHtHsugI;=9XOyx}^T-);BDZ!LPerm5u& zp*NUirdP0k&t6PndBvMP#4FzPSA6!ff6uO6duSHFj+2U5=vOeS+jVAdOA_jm=a)MR zWW}LXl1Pr96hzf@u9R+RP(4TljMgcL7q)wnoJ+}AcOj#I2r;@U*5DS-;h(R+fxQpB z5`Zfnw4dM`CgYk(HDlP*)Yb z0Ti}m?Hbr};@K2#D`G4!d*z?;vRD2YAOFiYbJ>F*!^YXu@XI%2X4b^|O(B4D8k~vF z;i#KA5~?PkRj>r6>e+0dwAH7J_3N({{Cy&wdaAXnP1?n`<=z?%q&|@J`spE7f3|xxhPLX zB-RtjPHdDdrj(Wr3P_{Q9nCx%^(h#Vc!q6hxTE2cLtm!-E3H$|b;<47JH|zux<%Ia zQ(Bp*e9dWgnsS-Y(a|B0&Q@%njkFFgk;LLtAfQ#1T|$^hywGZ$)Kq5%qAYPHrWTKy zWkk>B^3n>nUq)0;5smtEoPTiFZP;L9`)_Qtg}j!xNcvZrM_S6PtVi|1N9r19 zYhgMK%VhqV`wy!TJC$xINsn#!I?|P;4FR@}@wBH&`nSBh>j+JwD^(^DuD?oI899WM zO|KLjYBPB{5uWzosT16220{~pij0l{r_a*SBJ#_0-& zo%*WVDGWC)L^~VPowj;^bDhss2CuaHr1HH*5JUxQ`Z~=TXxBh>sqTXZQhJT3BdPU^ zO1d`lYm;au>J{nnx)0s*o~g~S2E2z}0XL5wS3cl801n)JH|vhufcRJ#(|b=HA{Oee zKYJ7BU-AGp&ChYive4IC<*0}?iyf zReu2%8wO>3hV-2AnUf)t_9U%ad`Ph^=+CDVio}mhC$O$dVoeN0d8--g0_%=D5!gyy z4Kc->b_*78fx-gRR1*_})uths5~72fQvJR$eI_Z$9ubEhdj<;|c>1qh%^&^2Yq;o= z9aL2S@tDG}boek2e(06FCnNn3h;uQ&dz~ftu4)Olu2tPH$o`Inu0SWxx>A0wV(yRJjmZ z`=!+>MT=$A^1cl8u{j?-?I{8)D=Pr}>%V-SvMgC%S;pCDRHfpDNqI?dblZU|wWZw+ z?MX@OC&4${Xjo_ET7H%vvi&@*)9T;FqT14N4tE&EYJ`%sj6V*iJD`q*>>o2}ZKoM* zG7QsRna;%0+0|t@nwd(zvNLyGm8p5fk*$e*t3T-T{abDUU^pD%oQvoPx@mYFW;%7h zs30W7ON&tN(3w#&7a>$QMF>smib*wMxH4d2VV=vcxSZevuXx4Fc*QGT2EgyW@|9e1 z`Q?25>tBz*nM_nzIxtmxLrX@uwQZ+`+}XqE{S!0!D?N0*iZsU@|pzSfjWhp$9LsFrIeQ{&Ho5Q7@&eobS6SST|1G4$5s%5}W^wXfi+ zm%N#M`}Q!I)ZBA$k$N(u@=*32{eGYMUP0kzX}o7rO;{O@fC}TFFcannjy;#}T(qh5-?A8*h8tENJ#S9;M&s%u<^M030F58I%?l^D+2^L3)^3esH z>oHsODa$AXCUwO<2M%-a;E?_Mw(_N$dc5N;ujRl!cd=>nNgO_MnBGi}Nfq1Pw{)$i zLWudb-XXyu^$53q8{hoqcX`0J9V`L+_wQqQdC1|V6+{AfVRm-FnuR%>6~x7kSHtm$ z$!N@I#WQjSSIn?$*G{T>%qb{m4dRM zGcDbzVVBT-t#%Wcsz{`TT*DwhN*&Qo0rCDe==liBN*of#*fke&{XgHp-n|duf(tKZ z{hApLA3nmQ9^tFl>uF}Dq_jos0^$sKsK!H%EP5Ce^p;2Tih?Wl@8#N0e}-*mU&Qxr z{xYYZwvBM_O;|gK(PKOP*y)K1EM9D`Nii9Z_{V?xB){;)U*X}8d<2K?ImF!uk1(!k z`mTqerlKJPixz!ZjZ&|}Z;-HaN~k3Igmy#8f3^VH`)mvyseAj`KQ{QY7eV@$}3zR<)}_j-t1a~gNwYk2i<|2o&a^MmZ(x1TT`bN5~MP#aHE z!~Eu2X8tp-B~fvOQkqZKBjBdnMKGZV|MbJjC6_aGkm<4@qPKk`<7@~55z%M}uq zTlz?RD9M5>t2&FC`B>=ib*s^MIa)rL)CM`CyT+pmfbV|yyIgziwTdtdYNSZZ!c>-a zq>zr+qAv1nl2g;rHbY4yzFJo0J4`FV*|z$j*B||9_ul51SKh~OyTQnO@2;7Y&93%u z4RmB>2xtXmeBVmhRU@d}4-#ULTJKr2b}e81>Q@06kH?UVLdbk2rH(|*isVHytLERb z4@E3b-8assa3vs&sxhPSm|ihpc5aUS`}QLUFL>eA`RU(y%{5$b?s<%cD=f^;fj1aq zG1gKUL%`y+)}Ly-Sr>@(lNFuTsi4YbqEnmogQ*xesUD@|$W3Pt6S6w#LwNzx`PDU- zR%&$Rc&jf4b-1@~q@enG)+n>S8}*!2FVhm*(b67;G@o>{l-6Lf$|$O2OG_MxH3Z|4 zN|-77%-6l> ziu~|`&(q^{mU8-Klv}PA264}&^S9zn^iU;~lToLb>3$Bm!%_F)rjS5g0c6^7(?QA~ zi_S42xpTy?b5B}g%z`Nq8u~|G2bn@yWJsEUejg4kdCuuK{M6HajZeP!4>)1V7M713 zp|B3{Ool^t?b^lLf9rYt;*alR)3%H7M|_S-Thm4r67swkJpcH`?*OqdW#h*fW03}m zUXN-r1mLWVGaRbG8;eV+W9cDNz>;=-;>#*=#SKY*fwp{{$$OQSz*vRi6H8h+6Nx#9 zW4yEkd=tx7ylBBwBu4i>K6ID@A^3`e_bzkM`DgI>-+4V>{F`$*;rMmjad%**0B<7dt28k-Yqaun zb~Is#EenZjm0+~4Rg`V#aAsRe$jGT2Z0;=ZR2%q2r(}}pY=bH-vmy^O2lnLew zL>ZK(^d+Lrj3QEWHeeG^N>8ER=X`M+yGE?6jJR<7cCPyM=kxzw|9xItx1K}r0Uv@I z1In>XQe#8QyRzcjc06ch(sWEND;yo+VgzmZZfShY;^LU4<$`{{&z?PdDN08*p77f* zdQqO=g%@2!J*kwY5)3^Wb_lVcUzh$mnOnwmXp|Q5lO{gx=+Qw!dUmCK)4eX;$g2S< zZO$=C1yJLYbWS5ulU(T4=J{Jw(ge@Vx8241g+iU6Ru!t)t`(pdL}aIt1`$Uww~dc| z=zU!Ek~ee7jtf~{8nHYYVywfJ12!zoFgsJy1jCV)sO-;_1#8!BWMS4b8ZJ@Qf)5pk zmMwEm*tYFLp8DM1W9yG>XZOBGP#^jitXUJ+P0^O#3gw!!x%T6K&C{RvyPR{u#aO9X zS{YMdwF6W^&l(2v1NwtL<4KJm6d2YNYXM=jvciEwhdJxa6L`ZL-_4q}n>lgw+L#^| z0);UYnUfX7BEn599^80v4l`LsW>4mxyO(*^GoQv1aOuvS9JuEoNFW&K7X@q9&wwlV zw{P9c!8^a9W1hv1OOEHb;}=+5T4s4Pp=m~pkJQZ1mRxY*h3wh;qkQR$pW;V;WGnve zuVVXaF~+xavRYH>8imPIo>8Bxl#Y%e63bXQP#wGQEoR+Bq+R($-D@eHx zYi9ZLKYlCMyz_(X+q;LQ#YL9J6$B^>$MGB2Fc|bWcxcR5{^hGckIko?!l_$kIc|0% zi%Uz?b%2fvII^AK!A0OwqxR@k?CW1=C` zDy1>>Niqm>7cc{8>W|=+tPD$whdKAWb9w1YUdI1>{r7lXykiH$(NLW{kPMe>UUi%( zQ_5YA=ITpYh7?7kq|qYsLU69yU58H6oPN|nshDIUD~Htpob7n3#7M4n7)+OMr{ft*TsWgOLZfkl z5l29s3mytAH<-~9Ysj$Mfn2#UzDw0gQOT)L;O{`Lr=gJ~+8dfobV2pS6TwmloKN970hcYvnI3h#}FSNYa%%1^bignb%R&?$Wzu zdo9wYF|7vO*#=TdYNGEp%$d_g(t?u^cLtyR4^t~)RA){FVvjZ@SFhSp*Q_2>r}>|B z{v7o)9nwT-Qvy%6-Z(u}q>3y0sYXWQ!Az4^MXZa)CPkz>OWmD+lB-k9R6jT5oXu=J zchErDw&*H@iGN_Gd9>*)uyp5OvfkL$1x*1VIBXCOn?Aqs!e{Z<@BRa%3FH=21SY;= zt{)AAyT*ns1q_N<^TxS0EiHoN45c-&bcm<_&gYWtxYZ+FtdzVDFGqD_4Ry_f5E%YNAKQ(8 zgT)`*0zfe{j~~_;EQAJA2$lD+LI9gmafF zaw4kGX!_K6GNGy_*rKH89J_b#rtI}tTv}o{TA?7ecy`883y6=(pO{vVr$}K&YNjc7 zos@ZNr8W9YhlulUR9Tb&xQNbEBQ{+YOlqK+eaouk=BAS2JahOe*sqt zfA!H%arW6;seOgh6eCxbB(G9Ay9VgdOoj|Lp3T31=ga)~W1micb}a$J%BadIwrghR zX^e2)XFdnO8erEx__yoeYdXCPFTR9+*-+P>8ew!~!kV=+0Q}LrKEdvNKaMSrgJvZb zmJFUSS)n}se7^pTn|Q$se-(grv!&8cBq|>o`uzpwXJ+{H^>^b8~&Jzy5y#@TA9WW5*@WW>A!T=X+n|HE;Pe0OxJLn7KiZm8zyNaAdJ!z{(Z_> z=dx){pV6eknUcDxIC5}>?HBLj?SK3M9{!V$v5#=?jj_IkIE*bYh0#LBh1ND}AlMjq5tYLTDIF!&X^Ni~3uo}T>p#o$ zu6_k)pTC`@o%-8e2$*kqdFHyD(t^BU+|3 zTZe*($NQF4F^o?CS4WZ?Sv9pZF2hku{&{~77 zBo8`&OCW?u6Vb5M0AW!1oC}1nmTduo#gl4%u9oY1RhGG{z6r`vZO|H5F_xU`qN?s0 zELmO$fn2RT$#K27>q6+tbL)}}lr~+)bkBGE{cvT-crsB(#x!c#C~d~zo$?1sl#zx= zd?ei?A(gx1BnL*vKGOfY!r?<;JX)ciOmO`kW$D}#kWO;?jB-RWP45dj( z*4EfgzV0q&A#`MJ#0IsfnS_E*oy#QsHa|}LXfpiTxkO#TN7}WTEf5(Gv;BDv*7pK1 zGe6I8JdQSyNx|1R_LdXxN3Bh4Bt!&bau>9?r#PlXB2OvWvl{~R%RV#ZETwZa&QKZ% zp~)y2lXQR8vk{9^y7ED2OcR~->O=`xVmFxhW9wZs;!G?$U1A80WZUAv;sKucGe5)o zUh_6?xba3V+Hnb!aRnBdNy8cE-;e9AyN+w#`VL<8s^8LEw;WCxye%%^+wcv8EN~3=y@NyD}bS(Z*(aOTSMAq7g;bL%vUP#O6K7 z_FSS-lSd0A+HY@bvU9ZkSEjC0-CG%~F;=rTeCJowx~Vm-?Ve_VK5h$s>F`eJ>SO7L zN6q3t>HO*1SF05ByfwyPx;Rq67)vNhyt?*0o*G(%+QsRF&OIX1AxX8=k}!UsQ2FVB zL|er{5)#BxEuFFQ{}VG;u9_IE(q-J+vCYo_03ZNKL_t)KAcR!=#k6adoZ{)eA+IQz zmm7ViAW#&ByT`EgtkVEkTv}pweg;1oL$4r&idu!wCvNyM+b=km4TB!{j3dA+2E!#r zgBs7K^$t5S@c9ojf7xXWs}UXtK`46#WzRAJp7_XpRI{^;4@)$Pi?rAlXQ9#O6lrVz zWRYMUUb-nPYGay~$tFD|MJ@x;q2L5oys&oQsc_tO=nw!sTQHP~qKX388Gi7U8+pXz zf1We$e}9%IoJuK#u3dXs zTs|CC@K7^cTIPx?ujHy{{yYzV#1A<2#Le7%AVyg&xfx5|>wwX4t+EO2nnu6C7{NxK zJar(HBuKhm@t(=-D!-X@YqPRSr-xkACSSxD`@yM7A2S*+?$dyWXiTyUcC;E6fW))>v*{{WmoW53_* zy?NYaMRo7}t*X7x@QgiAG+;wZE0aLC4KxZOYA_6H5JeJHoKT~2)@ZzniL<$C9Ii1M zjL|rTXc9Fs4yec&KxCc-8k+8g9-e;2bI#tos@^|VRqcHm$mibA`}w@@{UiI2?(>|p zhuT%E*7#d%$(Wrhscb3x+6N^)ICCQXq=KFM!L6gSC&rc=TYOk$O9LZnQb|z}rCJPA zog18W_{uWd>!Efypc3UwhWGtpV3KVE6$XD>SfA}H*PdWNKQ+N%M$^dCOU#-}|S zkgkVC=}@M_6+gL@KYZmopnD+4K5-F+^W-LHexcx?b%*o7{nzl@8!zW6Pk9P%&zy|$?8)4G%e8#z zum2iYf-g(5EE5AwY4*+axap=F`RE7!nDZ}u6M5ccV$7jU#zL>;b?>UU_tq##v96x48b=Yk2O-hEHF14ee|(izdd<*?_sZ5ArFmx$)|sbJicc5?bpy{+My* z7J68%neERpnM=*PuYdKcT=@DogWe8$G}ZixhQhE3(4aLynjF-$7Mn#V=OrE2MK0|F z`XDfFEnL!<1p}ohs~jIn1}Lv2&04TpNOzqY^_dJB9pthL=8CUV9z+BMKCe`rUPWzy z5)3G`jMHdC-5errcTH7UqW04)L>nHGbjYM18PF~|bZUMano))A*5K_*v=NI>^$498 zLpGsbshtin^-6*xQIeCi>sZpkBL$poh!sdoM|QDKsfY@#p(;z!J$y83eW2C&xi%7; zD2%YR!n%aBgK}7>wABV(G%M@xhV`#^*?DHKE0C zf{SGTeHCaTslX~yJT<*Vp6lg(k^`$D0_^_#Q3oWwmfsYy*l;WgEHa~@AlDt*uFc&K z+zx=r46drkjf_oeLsdx5#9;@o!}$z&G z!_6nD#y*Je(R4}0U;fXKKWe}K(})7cj!Y%iQt=*NS#&6lm7{3`S!hM=gZIU#kR2BJ zYPeM_3q33ioa5d(A(ZDY(g2iu)((fYIg{Uc-hxTBCoY)QJ$E z3FDmJ=kY5nZ~5RC_|$t}$MGjVo!LPTjiIuRVxh+gn~vktZ+tm#cZw7!vCc5W1gLEr?xOj3OC!AF1(twif{n;@ZxlSrzTcp`?`gRkXm z^kGL%6j6_f#v{@D7=81>p{Hm?ey6}09n#x^LZ>yxh~qbNKYHy6h*#f`%oMdy3-Iq_aG<Y zB;C#kz1{+IbJJu-gq8DPZEX}QXOp;0*~%eTyM|OYh(8K~$c%N^G*MYi??@C5;j<@o z0gJD!b>P(wlujwNURj`|DoadW2|_bPy*%D!RK7>%4SMNOC|~lPx4eV#CCdSa9e8vu zt(RMw;p&@q@Wu;HVeQJLl>2t!M^`hLeTW_R+y#tMR0Fi?&?`$8kLFx`-F2M*;urJL z4`0lh11B(f1^qtB9)!N14%u)7BbhkGTF!=GHu*)O;NS}SmN9&G|5D_WI- z#C+N$4dct#bf@YQhY3wJNHc!#ZGhx^QDjVtXZCRV-Pwj4Lm{f{*{@pYztYyaA);U|~8ilrAjJptX*_|MBgd^P-n>#brO^ zm}586vkvPlMcD^nYU}MxKl~8mlM__aTgk_}GJ5B*!I2?#;Y2xe%A<6S_lj1x#kJR5 z$7v@l<11JEkS8AbR2ENI>JEM_)*N~qfAq??@%oD{;(I^(1;=gN%%CrPDc6dHxgN(H zyM@nx<=dQj&ht3^jOS9#?Zs;yI8xQI)>J7D9nUFLfWw6h%LN}$7^edx2i^7Vg$Yc0ht?8RgwL^HeQSwlqt6TJvq zQb}eh?`s`YseraocqMgAMzWk(^B~JJY-P!^On8{dYD3zq*c?7QvF;R9J97e-HYyX| z&}98`$T=C*`d?@}tD;Qu24y0GHkJvfkt4A?-2N@lQz6y{qBH99Iup}8b1|)=R#al6 z=%h16)RG=X4jCl{aq$kNvS3)tm}5;gA@eA|U6`@@E*b^K*Y!h%0;RJWvd^7&Xq{0N z1r-&U5_D^nw@qhpQ`btjO!E+V4-I>Xpz9KxMk+K)5#uM;ne@(MgPvk?%~*GYPPfCL z7;yQoeg(jx>keUjd=l#=q@^oR&Hx4mkV5hHe+ly7(R`;F(@gKDmfw z3iB!ASoA?b_C|wPQ`c*X-__V3!nN`DT2qmAbph3o0_2cT@6j%EN~Iu}N?r#8m5ev@ z!Lbm!ryB96V93Z@LPG^5l)+HahSK&J3@VTvA7dCq*n*&Kc3(G-J%$~sB^wvIf@ zDFy=omW@p?Q!LO@-7vDi`=i|&W>~0H=(QM>La`Zq^kW}kWXTw1QPy^W_X4u;J~)3! z&1&#a5!#|F!(9*F$%jAkDQs3zR0Y<1jQ8TW&O#rpOiP}d_2MBmR_w$uw|VB+TTOAs z$Pu5?{A&0Evw%zwK*%3q%h;y}c zO)4sD@v8#rr2=my=;^fzG3F?bqd_j~DoDR%@F!}D`%6U{Zyu^H*OKZ*`IrhA=QYxj z&|>W3b%pt2L z@KuR-o=j`N(rS0O_3~?Y@%uiBS+a=Ue1WzmRGybXyYQZ|IKPjE5JGI;yY!p!o)rA< zTV^tt?SU^X+KbZVyeH2cw$!vc8OxSBo;23twma|Uf>*pA0Nq){pf@KlLZ4$RPkUTi zATAjhVFcJ$8OB-x>l9#>xsrMlUP**YAaAx-l5C0hmRZ0oS`V8El zPZ>NfbNyKkIPsbM{Oe!l+s`|b7e4O{?sT3CO)GR*$wKOm&`?ZK43QS^AuDAp$f7Ht zxsPKJ=Cskmhlr4h`!#}X;_oVM@`iI$WM|^=fzDJQd5IuJ)LYurO-DmqU&6VKeUY|; z6Pia0S}SI`XboA4_1SDKp3G%4j?$BxHSZCR_dpEzk=Xc?LEe<N zon?4GNKk38IIl21D73^eK~u&IQEfms)te|V?S$lro3D0$$t^^ksv+|(89q|~ENFx_ z1I96<%kZWHc`5hE3@C$EOKBSobeZ3KKOg+?r?~7l_i^}XIQgo6LSlN6xR=Vf^+jdS;W>TsuUQbYd&ePHvH{5VDD_5`L=IegKk~Ifl=kCMro0YmnzL6lIau$yr zz-!+4XG|?9-t+Fi;J9OsqbN(9&hgI5Oh?3Qq)a7FKIi*nlWW=e(4E}&TS;3g7Us!9 zM-pW;v)k|I?DxEdXP)^y{Onfj?perWZoPHb%0aIJ{RkVLvW1h+cs}3x(JxRY!@B}J z%=hP+T(g?(ci+O@cm5~q*RO@Wdmw8IEvS@G(J;I{b=L_Wtq%%Uq zG6+`fLt1fk-uiSOuQjQitFrjQqT1uo-^R^%-z7V!le4Vdrs|HOM>4Md)fK$=&)&}4 z-t-n!?-Ba5x0C0Sq6g_|ROzT@r&+n|G(Pg~*Kp2dKciQOLo(MnmG!LIa0Ea5-gkKM zD=y@zPkl0#k7%e$9LvU#LsEK0riFlAuDJG^>pB1VC-JdQe2le+9s%>)D5vJ}m4{r6 z?uoq3XllRF1V4(_Kn6m}2YgK}J=5yz^9*qdPjngAYB#?wvb%`}_Wi@v$Cu-@QNv z&Om6EVHf)3-Fc3E>WMt(1@GpP@4g(4Nie)tUs!qeK4VyUhNFQ~}cOR7B+KDKq^t{6(=-aBa+;Yp!{P*#H$8pqAN18O_bt?e$WPbUJU+|58`Dfnn#}~1*-DTeO!yH?@m4-;hxUjB`0A1kkUe~lFmEa;R)sC8k zB=?dwtpY+L0!5Nam`EY&#*JViAQ=gUn5HN67Rqyr0v!lZrpKwEFQgrz@H(c`k@in= z5G6{D0spx7VbTELDL~H1xAb3n(vWBBL4u zs$VWHK&{iMWG^Hp1H-v;G;R@Y8IZ>)0s<+fEje(?;guj{ywOa}!l9E=IBQ{MADzw^ zg>z(iMq!Jjg#P;#xA3Zio=CT4=vS6JC=o^GSZNH_S6u(~&vWd?W5lbhrC4AqH?)mn z7I^I$r((v&nV%bw8>y(C;JzkqAp}&T>o-(RTva+aJiN|`p31RK#dc67co^p?sbD9 zJLy(~MEZPH1u{@EBMWbZF=bk_(1(YoEE|vB$RAz&SA6~AH?ifUlUbPAi^owpMQ>(~ z%^NrKnscAenNxk%EN^q~4o}_+NRYV5$` znD==6`!<+`db|r#Z1pkk(d^3hSije!-T&6LBWM3>z4LTB9qzpAPL4hHSdQCt9H1C1 z^d;gHgkn=P39LMLc6@k}Qh_x#V5myf*EkXSE_ei0NUgJ8x)P0aI%HZgJv+y5ZjfTU zhab6t%P+s2EnBwmsZV{1x4-@EY(D;Y`n>_pma+k~0qfD$f^H#^W7XIsP};*BW1nz%_Deyq%{%`!KiPbQAyf%bU6B zx-0nh_kO{Xjywjfte_b)Mdd5T+9Uk(&YisY8H;(!k?X;fipcw5l!OfozWJ5+^8B;!=D{7?S-xaKWV~~f)c}~_w^#j?ooAlTs%6Wu`|e5e zEHys}d_W=f*y^-vgBWHGkMS1M>2kv@_wunf|2an-dmIZ3CBASN4MrJu@7%%8hi+zk zvW?$&2TF~j^9rm_9IIQQJ&+ZbHjbj-YGsFHsFVaa7j%DS7@ZuaEDLt++QowpJ_x|Gp79L+@gFZ`{b5gHY-E%NwryqK^ggsXl(G<1 zdlrgC3W8Veo4On#=`ud9DPoK&ADrbe&=QSa74-2m=dor{q`Zi!YSeip=o?-=nr`=_ zkm!DjpK8=mpj;(3iVB40!9Sj6A3>l4K+xh*VHjX37Q~#%R1ZRF!4Z=FJ#oupYFMpgRV%4euRMCyGRe&N|v{ zLseR?x%!&0w>3U9A=^gM{v`0LP%aB9k8aFroso5q|)m8hC``fM9bDo(Q|5^BN~C6uXP`_kJ6h6y4UQjLcu^i$#?s$Tqhw=w)zy}yR` zB%#&&kfEUha$vvjAN#18!q5>tc|IUc(v*jxgt|Pbkayh34LvME1&3ayu^>Y~B?EvU zV^tDR(P$Rft4h#s7iZenhOkOPIju_sK?GWi`E-qZMN}%7YpkX;ghI=Tg~H*+x_t6m z-{Y<4y@2CS+JasfgdsZy{RK81cQo&R<+)t&ockGHaxnY$3HC%OFa@k$3Afxm4M3+e z!pzJpXhl(0bh};3Lb`k%ytGTvhk?r&&2&Qe=mt$#s5e@iJPqJNK~zQNEzXML<$D#BGYgmlT|a#BG^M#qSXqD1(#4~`#?L}-jwbh=~odVOxZ z`9@qRO3Md7@=-2)`O8?ccoCVA*3+Y-Qg}DE8kMSpHWU_@qyoIgsaR-T#xG7O*)Xa} zypV(}#Li|Zju?KAvlBL4P%6TU0)!ev!9nH~wzRA{=pep)$=`ALuYXBV%u9sO3o=pa zV_1sbZnoZeH89ZBZI<)?jE9CcJnS-y9+yS;Jm;2E(agF4!iqSR6dShm}SZ0 zE@!^vTuwXZd|X+v^^U9fSGP#tQotHB{GK#G#(Txg+QI!yBWzdw#*X?%M%l%aN6%Z2AUthTf>$wQl4D1ep}R*rkpTNW?w z@`R0W|K5tuqBh0~A82)2Tz}mSyy5k)=0$(_670fOGGkDt9i~kXxlx$uJj3q3gM$t` zflXVs@TISOi?s)CrawE6M^O}xjhmjx=fC=IJpW~HW!0Lai8bT!Vmwx9;%ehgc|s7z zC!NeI1G>fRzIpBko<7!PZhC>rdB(=NOoh6G%U2$NedG?DDp7ubFMDZCy>nDL!(gy` zx6)d(mIDrXve2%F%xKD(W&v#7{xHzPjO4h|ONwlC>ZI;6L9nOX?}!Sj1%6CP@xkDV zdZ&bbGSDviZVXW0+*X~ES?e;scr7*b5esLL_H*H2KMR%l|#4f8%nVXgRhbStgKr1G?6WsBi z_j1++XR&J4Dz?u*k{oSmp4G4+9$pG(>bjyT6z1&r`a&;G=%>Ph6-Sr}b$66RfkJ>^ z+QC;9@wtrW$epxbFN0=)VCf6BN2`l}qUW(7C(ZpSDIj#!*@E7ORR2C+wDZPAc# zCQel)wxjq3WX`nqI3Lin$u5d}Fwkg>=<85d$oYmpAhP(6TPZ#5=v7uaAXz8d&GR&G-KNZnx3c#jXKfbYh;^6{XFcwRQPPw}C8Oh$<-(!Jz26^|_LUqU&9iHq^rOy>$FM!>>tCHuXbBnCFO$wKl{PuLzM%neyCMTBwFerPBw4tLt#(=F5=Y(D0lYjYDmMsRSGs?0^ z`PJR_7}s6?OaAcPAH^(PLvO)}iKU3Z2b_`$?g`Z%KBqR!PX5W1M=3+k7L+|W@CgU; ziu2ARYmG4|N{X_eSHbRng)YJE+78U56+hyLBWbq|#Fag=un3iQC|5Gp8R7bCujPbi zK8uS#`B8TDV4*aO8YqzHWTY48r5JTw@?gGUk+?i~Dq9!z+P=r~gu@T#>p%J_fAss$ z;_0WJOxfR!vkr8|+`=52jysM^FZm2Vd-eG|^@QWOV~3{%yb`52(;7vFrzBE=Y#bx= z5&$pBc2LmN{1d_^a0o?A{|mdp`xw(~yp+eg(4w81-V+)pMuma{DAHv-bd#n7GexNo zRj9itM3xiPkGTKh^E4i96jq0vedW+tQA9wBy8=Z~V2l_pN{8rRNJo4Nb$fBVT$`XDkYI;L?a^_#=Ep`%IGj>u0ac7v6Ytj*Wwh`A<~slHcHje(L^61EhY+r zbWhhxY)5*?iOGT&kvONWmNbc?-HQ`~anuUNJ2N#eXVLPsN6Mz24^*}wM(IFnJ$Z>K%J z2nJX5fj&H*BIp8HQtmqwv%o0pLoy(4m~$NvAc2bD>t3%0gM5O8Bx-(DzvSy!<7n^LJnQ7X3jlpnt{r)oDq} z>g;SER3^rV72^XHP`*KanV`o>(e5zMF-0uwSzFA>Zq-my;WLfO6u-Oge%|`Wucq>& zw3Z(Yg+=GVjPcS^%Xv*E0tfASz#bybe4#jzhZ;aEN+#kg-Yy zFsEz)A_^uNaMHvwXkf;H4YDoh{VM1M(fJ+G)2@+@p}f@olLCUZ1Hm=yfT&Xnf*_=7 zrH4e_Ui7}odaxCFtDWSpvoTpCB4vU;6J|Z7TL;u_0#c%+=4PM~k?k@-<)!WjPSNgk zDT|7mese=woS-AmFMFjFotvu`iV zGISia?l3lPKAwfyd9-&@15_I-N|uf-rkEeFx4(nG`tWDybqf~u&Cyo5I9TxDH9F`$ zQOApOVLZtx>@;}q$W$&)3=#1|@OQNHfFrxZ9X9h4m{S_qnw z;C#`#0%sE7!F!*0aGY207}sK|KgX&u#g$iG!&9E{B-R~tAUZQpdQgt3*;zK8ax$0y z@K@Y$`^}uW_Dn|fgHj{1rBE#>D^I&#e4q{iV_ZuT$4_<4yth7&-#S zUXZoZwK@NdaA$2=L4)TF{}6XbVk`tBhy89%)-={0eGG5*$2-y;h7`vzG-cAp7DFQ_ zM^WfOfUl__8&%pE8iY_2d_NFLVqo>?VoHk-UXRG&v{JPl5@ll&6x0Z#WPAycq)54s z29p|kNAN)psh70!j@)TVB^%jm%|hRCaNdFqr!l|lcZ@Ar#b8i?QuGIXMxC^L|N4(_ zJfPbc?`v<*w!hBXu7p>7{~xJ1Zp zMXz)?S1>4~4Q52@x>D1f>~h03*TKXSc>DkOFypP9>vlWZnWk_-D2roQgqZ@R9KIR} z4BRI#w9Ipe0V?QZiW%#f?ZcL%4`=f9bJ+UtmvX=fCo{coHzxB`6%<-=(DEgm{+t)_ z$isItIVvrvbqE!g-r;;HV+ifZ!G&C^5G_!o5+sr5#BOL&uBNVBiX?O*(Zo(nN%>IG zlPgCmLL2U-qqmxdy+QMy1SKNUsBH9DTy%fObR1?))X@>NKV9qaTZ35u#%PSGlQ>P| z`6ligGjvIV)eVn7-C3nO4J!=<$E}IKs`}psqelgyAND?gH^Qz>eCgN`FbpEqk4P`w z;35VQglT|g_?1*ZF*bNWbS~GSgs2!bC!$s?<8|T;3h9=rdCh*4hziy48wx{!G)MTg zQl!prQGh4mrD&jP8gv15(QyKmYehTnfcIQ~gD9Ry9DX>bo^~1^xcL37TelADq!W`z*vopAR2C*CR&eyOD=;XmmlP+glR~%7W2*{O#h@qo*(#)mnoQ9e8KXB{@SES< z$QSvK_2B zY8B3Ta>THRIqIjLbRxZ@!J|ZoZA5{OT62{q^N66rT0#H&7Lo@G0$ySxJOF5_SVE zCkBG2LOBTobX&Etpp>H5^Q;7pJ#sBjqHPuYg9?>u9eSV@oERRo$Jkk(`t(ydXx)J< z?3-m|Y#b_2-}&`Mzff-@Fx9@fqyKQ&4Dm;X&VFFMZTTmza=BDzL}c%{%L#g`+22N|KksSuqE#~nIU|H6sy-^|6+&=lr*ZZ$7uj>8pcum zq=r^wLN`zqqWU!oE8ZTwILcBGA?$ls1$|F~K2AwD$zTtrwR9<+Do8jLXTlRe=Afho zlpt)o?A<-ht+(DxyVK>MC#>WB@B1H||A#N3owrE^wu5D_!x&81D>})1jdvbbR?;yq zOoCG?ffIxe#vqK;q9GQ=t}QJH!7`s3jWiTq2wbyHq;2Z9LNSh%lAh+MHf+<{1jkp> zlf0baQ`(_xtY%o-sBp)P7ac}Q^gpkBgGWbgA@Ff8-KR%JN15FF6S+r)Rk1&ReCjl^Xk~5g-M5tuYY*nl7r&KHU;IfWSAelp&Y>zWDvwHO2qG(tw?l7WG!Oy?+6xm=VcnW?)F;YQX@5y} zPOPC6s7pniIikZF4k0hJRo4Vm4eHk^XetvXGZbs-rt%53QAgB#YFA~mn`XSm;?Y7_Z4|7qKjaQw?vUO8eOnRr|2aiHnhj9UU7$NMQ-lUsWq#iAU4`Bp{|s1VJ2# zUks|K*f7M@d~ifbYCiGl zukwy}znXaugR&9vPvvYv5wKuUyCkT6Kz4gE^p#{3=s*KXspL(^1qY_8=RM*Ehf0_b znQibqC*dCGzUjDWI6?RG%hW{eRSGcD7+2aS@o*6>5)djDbnK=PB6ww>kNUDkmGCY%IA?SI_CFrQRue)_qOi_8aZg2=D3HDsK@$24lbI8oNcBQ#9rkwK zA~Txa>;l){bQ1t)oN*>69RF1Q^iSVSmJg>JI44LV6^obdC$WUzRADkJJOTM*f^zBI z@VpVzy<)g3-bE21&oZZtdKW%AvVssqp+ZfTh(Oad@e<*@Lg6|n2T~tH7Q*5x3oaLh zBcf}xAb2vR$U1GZR?hZaQ#^2wprJ1L(xt}%rh8=U zP^?+Sz*^>~XZXRTpXa;Z`w2h1;%ASFG=^2;sAG>ql_j<+F~;G%!~0CS#sQTLNEg*Y zISVGI*RPlY4(=L?s*h3{Z4^bAzC#XMi`JIXXtXP+>rjLRh|xGN>t$36J8(eGiX|&# zWG#isDxB9T(iV|F9*wmQL&nt9fNk4%04s4AK?^ts6)ak^oU8uxPGfA z3Zj!zsyYP6MU0!KNO*`u2j^%~;5;ad?BUKBsx?lla{$Favv2xgF8ldE@|C~;Cb!=B z3+~w3>9RRR^-WS}!?we1UBRZ4A#km6)ZN4sU% zzH2u}9>0$D>sEuE#TZ0B+6d9S+nEMpVncq0xi6S^CE zHvp>OYjj{dMuBlH3I|}5Vp&w4+=GrmKv!b&5oYEF+;i`5<$l(ZsfFx` z@4fu$sw@AG=&Cz8$(q$`QJKP36*!C5Emo~rg6q#w_UG_RCh#+{v)5xO;XcV@*;9&8 z6f&^i;NDkO4EGNkEBmw)${(Zh8jqMTCo^+|;7 zC!^EpH43?5(WF7t{Dbtz{xbjZj%Ll4`W_7l=#c&*l6J{*bfIJiA8I1o=Ls`|PLK`Jl6j!RkfM22_V|E?G$BG)~1PFSR+@EJ_*c znnjmlT$Wg()(0Ytss>8*4yo7T5+b76>!_LXln{{VUMk6Q1=y%l`v!dn8j!j4>3pwf zjF1{>?_H|@qSE#8z6$T9zTxQPC{n-4ND$Z*46LVL)oTfYY|c!EHVS1Gt-OWtifgXD z8h~G3{R^Ia_>tT>eK)1|WLjFC#~^|Zbg6XRW?RLL6Vimd5(m)MZIAHulb=Sb-A=JX zh*&3)w^FAoboWXfV8x-??soX*72l+EmBg_HBP4oI+5(D>&I9^PaBO&K;ht<~DzZR- zxpx%a@Q9k{{qOuUK7H{gS(qQt?zZXm`k-@)K|!b60pM@G`M13N?QdfuUyQBpCJ#-D zq@!vy+I@^|CK(xdnRW`4bX-oQW1=ipG7EUo_pFwyQsHlcy<1!F)S9YXC(a<*G0}Di zSffPizCrx88XtWJLVI43_EHS#yP$uj^$ql2XJFW{Ub0s#S-9Dwb&$9}lTXG$WWUtN$5aMq#bx`s=R);1A9_k2in#6C8c;T5j71y*{)QQoK2| zWcFUAR2gM7CRezAPu3^GwwwqR09RR@hf*1gf(5JCvBz=DrW1Mp=fA`U{`l3Lbn2;0 z?b;;B1{}0(37`DjdpPe^FW{)<%eXr@oW&0Jh#?R*eAv-Zh>J5ONTLuaC2f3_ z1d!yT2AYcW8)+~)-XhYiK~s@1ec0S7%_-7fG9VaoGz;wo5OmPTQzx;edZZfrNd-0- zHbxWXDErr^2);_2xf!Q<{9{CWWE%Av?f;m>Q^FB}SJ8NI&Y?{vkv?yO zE*}RHcv_rOCll#IS3PYsS(el8w7KWjJJ~h8mnR&!hF84eLXJNASl;xeH`Y@S_MS2Z zV;~l96v#gNL%EWW$}&w^lF(5KkJmO7<&$xywe|5`RZXyIZsX>Oa~K6mc(>r$A9AeK zT4PXHRX{!p9a|h(p3}}Va-&hcjrAVuG{#owOp5nc&NAp(dR4`pH(d|FC~(nhUd{#Q zpTkL~Jd<+nL3Hn7RGuMNa0Ly6p{hK2YXmyu?44`zgRgvym%aHzX?`b{EoSZbL3Gwk z(CN0wj6!D_x%GghtSnV7=pi^(<@+l?<|X#jG?ijXlaSa zm|Sz%`h#exgHc*h1#QZDN2Un13_MgawVn!tq73kMm1|T1Sys~N$heF$Xl-z=l516T zLIxAa!f-voKr2mUNV(b=j43h72f9}b@e;2?L|q9&Ea@*or$z^CLd@}KI0L*71*FwL z$a!Q9y=si9d+*^jFFv0iUMGmDiHXH5T6!oOjvS@i&gkU1DEyVko2s%DMM0+XU>-=Z z>*$UW`cOcQQaN>UbqmlaUs0f_@MOx6<%ZomcCqY)r?O`4DqJy#Qmya~Vc(@r3?WsZ z3W}XA0L4hV&Fu6Jaz7^5rDTA{2M)5e=Lk8-UPM8#w*^eP^B za4V?Ql-^T0hsmW~hEuTSfK{wpcL+N7!CmKZl~0I)h>!r$KQW%Ns3-;{Ii9MOpGDCS)A%KH3<8b1`7wLwo7uMBG1d$rM6SI_Y@Hq1$-# zhy+qzo&E2B001BWNklHpUVh;#*tqdHAf$u^ zJwj>Q%D6kZ7rP(Ip4wsz)G%WHx>ZyL4|tnuMlQNGvo64@po za$Q9_Q)%wSc8h6an&`l2I(vletDwu)j$Rtq$Pv>0;x~_u{#XYlk zQTQHO<#?osx`JQ92tT_zJW4i2cu z5MJV_P)IEo2YiyhVy@SxEC*ytf`rzU;oU*uM1Cl7<{Klxi5Tn#&{~I)RaE4dwq?)M zcE%U4=lehZXP*De=dtDKTj=%rXeD;z%*-rLKlx-n`GJq|+_TPP^~UA2RSS)x=R7Ut z#NH>CNr{N@I33b?*@Z9lP)EcXnd1oPay4Y>$h!q5pwm9B5o*!HoWy&;>O>xcs$Dd3 zu4=ZRA|RbucS=VGVc-FEhSL58?IYc4ysd=C2j&@FR`nkDjsJY0^RPHNxrFOyHM#qv zjEUj>8b4)2=REH5*cMQ%!W}0%-8SwwrLY>ZAiPW>y0|!`nuq6mdMFa7oHy!xEgXjkG)i$ZCB^0iA@wR|y! zEpPyjKybe%2Un73npUTU177s|r!l%{2@me97%@S$)(Ihc^N&YfjGG)*PQ39=JGWYE2!J0*y=bv&S zA84JxLpNW>;`N&u%+5=ZV^gsFkPSR=?Nz+@rLW^(|LwbUx{~%KO{`3yrI6X~EOf+! z9Tg6V7zbxU5G39PgCNq-ekv9!$>x+M7849y+y}bW!y*}_HuCAdwN&lUtkEM`s3 z4&p+n{tUvUL zoc^q5aoV$=4S=(9y^aQ+t~0(<$?Vh8HKBG%AhF8TT3a;GVZ$mDvsQIHUNih*udh+aWbtL_zGPrbOz2S zoYG_jBaw{z9^QxT&v4+%RagfKEl!)L1X;kBC}Z)y1-74xYG+2ubg+j%kwWWrpSO&ucD4owSdGYmPp6$)clR?s6_g-(s2vM$hq%Hnl~wAOYwKhN}Z z58NcSw0I*9NStSO-wdsGmv&bNno)RPQECk(fpA*((RdV{(OfS+}6qJ#8qrwoJVTrdkHu%u>Al9KUYHJ}6xhKr4s{4PhneX2F+>(=|Nt&c-(xjKPOG-vPcp6|?jXV$E>X3b}<#ryy4D{MLSRQBxM zMaxzU`ituN=BpTFJDx9AYCy79=%a2t5)m~i(LhRftljl77Ly_eD=~;wD0+_$RurM9 zPgYc|aoS@O5C*z_0|a9mg*8AvMGdv0f9Y#*QK<-K5s#q`ngul(Dkbrg7!QmfSg}-Q zf*^f@t#Gx*ovBQ~_mV8~I9q4s&i57|XyED~H6~Oz9L5?3eFx}0jK}(5F1H-=LiRFe^uHmFvKZd;7 z8a|n7Fs0)UasIsyQz~2i67!=uau=qbs$wUqSH6^CArYtOUCkYK!*Cgq@J|h z(pp@UCv}J$HBxks$ccS3YP!~iI(UqzLAo>6p=!104f^?T^kpx98Jjk3=9RB}1shJ( zjE))uOO*ec6n0=4ohtQHEs~9)!)Tl@u@%mBqnE1Ha1SZ|R@}G*iLNMlJmb19Y_e&L zv*VSd(Me{;B%kBRCbG{&6ZdY}h|}=kkQAy!R4-{pmF5op7OUg(-81$Gwbd>LW|DHVVKXvt0 z?0f1yuDRvu+` zVI~@YL@iP#VX9Jkd-WVpnrw6+?`j6>TSSFXl)r!&ZA-8SJ$%dp=bT4c8hJX+gYhi{ zPhANe?+Ja~Tpn6@gs1Pjl4rg6S^WE7e~mNtoyo%E$Ec!P&ti9ui!a*4)AwA)k(nc` znVQ7)yI?A;wK%8dED4Q18AO9Zdla$Y1&mLDACe9UBm^8y*o9J`PBfaxFO?=!Yus}N zwlPq3h7YT4n6Io>`0s2wC`$ks%Qlj zbqPa;nO}B5k!F8T3Mo(Hij{s0VfYk2H2g0QOh#y+j4u;FYRga<0%AX6$2~CwVc`bm zqm}a5VqnvW>v`j=ex7H1^aE_HI%QxhP%F6@ z7?|j(9%(9}Ml`5soepEEyfV995T+`_osZUBxN|3;x$e!p;5pA_%gzedwe)MXBzNcL zIPJ8}eEq?D__w?7~NLQ9J>yV3u;g=h^$^duS=wb9mU@Woei`u5WRG?P_Ol`EY>h$%F~rM+s_KpsNn!p4?m^z=_-g(TEpqN&gf zLP@mAuoxI7Tnb{&2KQKpPr!6fi5Sq)(Nvrw!gubvou9ty1zd6E)0kiAYAlJk>Gi=Q z5~xhYSf^s`>M1szxRPDx@5D}Q0_JeD--7OAn9iCw9f2G)RRX>;(C_1PJQUb7#gUw{-wMq|jkpfwo`co)dm$$fz_hh5CMp6d)Ckfe#g9pdR8K`2EK(u_$Jh>2E2n{b zAXHdua50sp?+>{9?r;BpBcS743*Us6^a*vqRwP0yTm}oeNgsn^ud*%^`QTCskfcKg zZ;zsUO=Fd5wmwDiJ%M;w<|^75k+(xe_M&`twOK|cCfU|3f#vESt#kB7^SK;_EJ0E| zCerVcGEwfyGR=&%nIz&9ivQ!?PtzGfR@8rFQ=o&RO7?YqzBmCt(( zo7Zn<%k~XicI8vqy!s^WpTCc99lD!#)kehPyw^B*q0;_noQ;?+Tn!IpWXBK`d1!>_ zg&f~5cn&Wd;qby^SSo@QMNfLCdj^B*QwTw`8)@b*Y4j?SjN5VU6TV0c8p}vDae;`$ z#5ZaPO0sPbY8-*edt9(o)(~8WW8FChYvDuh`xCZZyM-0i1pV=zCNrvp?!thzYc+WO z9pAf)oliQKv$mYU7jODkrq@nH`4LfIY0bx}G6@lb%lxRJyyV)I1v$g!m4e6RtD({~ z;F1PjBpQ$sg%>m)jiZgxGxCCnO?rlTbwy)B~5PFNWsuum;KuLVC$n?r-01nUf*l;4WE&Ta){{TQ|#Yz^B zY5Md^Jgs(zoB#dax%v(7V8iKWb963XC1lqIW6_{ukpW7wj*BGRXTf~*)Q>#QV5=5) z+(k9D!Z;GIKkpkrH1Pqk=OhEB&a-D-2f`c0g8_BoukZ8PJ*BlC{0 z+*dPJStcql;t91OR56ZnM8YQkn~wt=f-s14?PQMz=mihEVmqenHNJj-oR+|crx(;+YZN?_sOpcFp zbY_JIrxa8aH{CJ+EK0F#h0%8D_-=n z*K_uH7cgE~<`x&JgV3oAlhae&bkqL)R+pRuSHJwn*mn9kj8APQ7|*`Fd${T5f9IOl z{5t3CI3FusUDWbOh;EF%$5d?ymNl!UdGWJPzn{yz6761C;{d5n*Ow zfsHFyKu-`qhuD_BUm}mp7b2~MNL;>HpdmWaCiKq`18q(!Gkr&YbCHxkF&2%fKNG4= zJZfN+5Pjc8Gn0+4V}7>HmW?N|V(nVaI%O+!-7W*Cdc>Ml<2-t}$GzXxAnbc4;gv6W zCa0XSgB5E|!M0nNR>c`xw(^#@zJt5(y^oXEt)(6ajD_6Oyh&3y5b6n_3Xcgbx~@l% z4i3TM*>dVy?*I1feCMw3asI^@66k@MjQ$WNzq%L)LDSX``a(56hO~sm-hk<943}aA z6>cj=#&m3aK=Y2o6RFUm#%iBDm`dHx)g@i2-G>UiW1?d@aor~1ix{iM>pD1Aj8Ajx zEjRH$-~L8+oVy!`;C-LqW40XeDoagJ!>Odeoq~vqaU-4b4`UGw&Ot?=){2VYX9?2M zF-(eY9N`kaP-Zx4)>Gt1NiQv6?8!l|3TlAYFztdko9XBY#MLs_(vq1rW%%BZWM1-E zQDUeA|Mi|M+qn^2Z5I-XrJm+M0qD!T0NrCyozu;I=%f0mA!$(yLe9t3sM za^f&SXt&#pb;js)+FXDA^#ELY>E*ogm9J*Uj?;P8v!02yExh+Qr>MHh+GZaU>o!B( z8R=!(ycSv?kPkv^aP;YrvL<_<)&JakAvwh~*zFYOCgDSfB_+36=)6(S)Yy4pi7w1H~9TO5nl#Hp`xPG6tUrLL?f$ahqbiY71PrzS%2~-PCsi06Jz5TYK|-%;g$opQCXqg9)kci zgP3e5#wLpIYYJLwIC31%tQV=nc%iXuJV&zH}I0E4m)d583v-B>=`;drmZrEd5 z0UjrjtLDT`kb-G9yQ+}sgh)ds-!194uoaMyKFu1DG(~Y;q!xg$y4lo^O zRb!B;-eG`R)HdSr>Q&<_MQ`Qz)ej~)u0^}ANo%fXS5ooJvjWKmQu32g9`^*spYrva zhs#QubZDcMFSAJ~E+bKCpfTtK$f@5Gyeir#W2!u&+e!I*Y$?jnlEj zRk;YdSHd zW3dM!A81A*Cp0l%%gc+pa8;u4__2<5PnEffZzDCG2%SKo!moXY@&`Yz46@X+eYaPfwzDKn8~ z5&L4jl@?%W7(sH$RJV=9IMwyhNJ7;qo#-B=IcEtXB-loIa-7>4VUVLgq&2zp!Q_2K@mhW^yyA z`$VHuE*;CJ-$^hw{5>Ha71dxht{0$&l%%Z0#ghOP5{EEDFnu9y(>te=ns~FAyo^}M zlNsBH(nIUf3{w)@NGjIi;xXV5ix2O|wkD&iN-G{(4AeCxNDgdmt3bP25z!1}cQ>*k z62Kdz)gmlD4pZBinR$c{|M_PDm}nao78a?D0TGTaz+HFl=VdQ>Hcx-Sk)f?6WQ@{eSmfP;Q1qRS+SM+*y+($>(Oc{VtR~Rd8@Qw{@r@3IyGr0EiAHr;2 zuW)O0zSnKsz@2yAM{i*k>?S((qe!(1d<`LHvXP3UxGR!kmay_n9=`Y69Ju!`)@?q8 z#ePj~3?>ME$Zb>up&DcGZl2D{jhwh;yZ#!pz|{ey>hRd11DtWncCL8NRp1_vKDf!~ zmbM5UHNctXzUzVXA++_oRV0a)S-{U7!PGU_N&!v9A}(dU3bqXC$&5xfG-dg?szWm3 zhsHoIAV%#u>hV=(K8v&}(ioazEGNC+!Ax%9&wlT{tT3?ctbE%620>GKERO!H?nQRI?b@+8iR|zkJIrC z@x+rr@QykJrYZ>DVM4&Wz}i()+OJ5 z+=ujM31XKy7?DEJOl}HIE~<<`i*%M_Z$zYr8m2^hlh6$!q?kW0gvQ89i4bncx4D*) zK@_@n@kleD$CpKoz5y9^Doy#Mum3PXSDXdsqQg%N3*=G_$cVW@?k;gfAL(Oyv(i}8 zxOya!T8vepS7=>@3rtyk3GX$=%=E+*V-pkfdi{)?zvh}(aPh?#aqhY2vS-g8 z0K9k9gBnC#2*nH=e&o2bSALCpVi+dGI)Jl=AQoFm?0Aaf=<~j9bk2v3NJ)l9x(wva zYx$IJG$EU3WH{SVZl^Fn==2rwf#S)3lGww}ej!VM+#YE&AICl!m@;KYluIDT^a>%h zqdIZRw!qdLc<>Qk@{*rr`?jqtFwYoc)Cd~AM)NqT8L3Y{c;>ouJoxy3vN#w}nHCdc zo#<(zNDzb7Ok<;~Eb1;2`!+;hA~D`gu`kt5tIQ^da-KJ%x|JrC2rPsFbJZe0_o5f`p}+ep9{=tE#@0+R zx6q|Rm>(=MhULuDcJT6Fd?mAo9^=fNXX9M0V~~7h(-kxQd2z*IdUTP9K8WdfB^hyq z=&B_F?+XKYUfYRobo_Mvr}=5jLD|rgjf;Wg=1j3(QUaZLJT$UBC^i&{N>eK0qFmaG z>$(R_phkfprLi@VM=>{1-^gpPA+5y6@|u-KrDkL-(p8l#viyCN^~lKIvP>qokxGWQ zU(LdGfyU57-fI+$j~LHE1D!SLsHNE#l>TDr`NTZq=Y%HqMaL5ydL%YmBeN@&P>C*+ z@nm$chuCdW>=K=(&#|x(L*LbmO|IYtKk;-v^bV+67Sl2L@W;*fIeW)xy!kiZ!7u;# zQ#m|7#ly1)ICOo*}(5J42wpiL@6{{!IcvSn8 zAxkGE2t`mYvQ=KRS!z+!juD}DbsqmTkP_iSO|Af4@QB6wz@Uclw(z}2d+fdNeBSiN zm+-&d@@wq79M%EpGuA4j>7qRh}q-xCy#Uz+bBO+Xxr^jqA#$?`oI zZD9GnXIW0k<;rLE-9u4J!I+1;H&W?vTSI&%`w1qVslvXl2eeu(CdMY1nj9xMxZ#Ey z0C@6KuHb#|{R1{`+{nI5E+zqv`-48#7^+r;Ca1pUbaax}-g1JYp^oO{QHBPqaqaR! zG-HivlryrZ3&YS^fhIj;DBihb(#4gv!sfU9Z-(hxpr74|Q{X5yptNa^ufeoBh#!Eo zBEwHcsGzZBoREUE2Cu0)Q~LSFC>)iP5b(}oC)V)SpZq9)cik7*d+|PIXJ@e@^zqce z@Zf*m#c#gpmAv9t-oU1fo6*g6A6yT2>@aYUV~6i&)#eL1aNuy!=R`wM5%vRpSJMFl zZsAeJS8ZYI*}JvB1}ak_Qd7GD8`o{%&O7hm^MCUxp7(RFrGMyQY?#AVlX-3=1r-bs z{NuRxTH1CspZu%$@rCQ};G#WyIM(fAu#soS>Bxi;CC_3XCML0yYqc*yG^l?Fw20)N z8~^|y07*naRAS-xe&|}Rc+T@#c^%n^mlPOmiH}|CZuNs;} zBDy5eZ-^6Oaot5^DLu)>zNvF^R@jq^33P_DDQjETR3aydGTH5 z32uPz%@YOyKFgS3orQD*V4QCYTS`q z2!o2M74S~8z^SWCOAV(QXo}ifCa2ayYYMmM7`Pb*^N$kxa~Rvfbk;CF-qB5%A<|Zq zbwekPi5jx@IV24wDxAaKU!ro!>mo8qf%G7iDQZj`mgCE&T;FoH8QowPdc}zR8It5l zw_c{XMn*k>P)$D#{a*0)+-@w8hpXA4-_EWJc5&{xPh#uVEr7aq1+N+RRQ5)i$@*Ed zwM!a9i5(ky&oorYg*s{fK485kgj)6O9FrjFnoW&*0Pk~qCN#(fiXLcV$*CsFoyb$w zeI*&;N4BU|tp* zek6`rey>L78QOisKmWy;KgYY8DN$QZSoYWSx5#*}gEeX*9(g!u)kK;e`CTFsBq<7! zD7=0)$xxJdK^PG{sug9WEF=c(CHo>tM5<&llK6Cf>%6wL%A_YIBTy_91nOW}aIk(V z2Hfn;(e6ypU7Q1J=q>b^UULHMzlrgQ7GJvko8146``NSWbh^DhK@65ayVGX>{;%=E zH@uat=j`Ixf;J+C>|!U7X**GNhy$4{;dw4RXtt3$D%Z7Iih;fe3w<~^Yc!0h4XT(J zG)4x36PWB&n2xsXL!jpam6c|3D_6{7C+XM{J1C)X1=J*XHq_4$It)bdQ5|EsI)(w7#jk~r@$uC3(dL^V+}fUV9$Q&fOpGzPVuD`3=Br;-qtDyl{x&YX z^hY@P@Kw59UhH*sbLyX&jig2EnBwv{%Lfuo!U>^Pv{(YUMhf|I*j-?F%nq z$JtM1apoIT^9R8gjIn?tcn9JzliO)eoXNLt{}R_-`%zfAiTR#p_wasz7n8@`Py;o= zRd{JJ=pV(hz~scZ4nxqBM=u^<_gTGeBl9x{c=VC)v1aXV%^Ab^r4t!1B zJ4$EW1>AY(-5fpgeNH`fJ)1V4i5etk@x3D$@1WZyTj%5HS_mc^(Gx>nYNU?tOa-aw zkA7q&6rV#-5SSQjOi%y?>qX~X*Kb037`$Jk)n3UrZo84$hrh#?9p@8#po6AFcTNfT zmDjwKvvyw2;-g=qGF`;A@lq?wsG6YD5@c#M2OfNwV@D2i(w1!)(d;jXOA8>PP^z@} z;(F1wAA*9%AZ}oSr&l{RoV=Zzum1wy`ubIz^`vv?ANV)g6PpleDGvw%Obf)|=MFPy zZ-T)*AHMbrN_isGK~Ykz%5eK_5Agbz|2Suzwn2?5Sb}I;_Y~mP4F-fz=^47wyky3M zjs4aPxgO|a+d5x$?V)8c-2wf+W6hei-2a37nR)CG>(`${z3_diYE^tLpa$kTPLjd( zkI`9m2H(H$5&rYuZ*cBur?TPXlNnpR6|jW<9C^XKizGscFa^)oB zW0Tx>-~HSiQ+|K?(|^Op6Hnya^Uh^@mBy8<-2j5d(X*{i6lWnGh{gkuJSok{m18&b z-b0^hENP zR%3=JAaFTDQbL?0V~++uPI_)~yGb+HY#*C!V9CIf-bGS|kPxz)P6{`Yww{$0#>d)p zdKF_;o0e6#(-54B`&M)pGeYG(13$py8KCu9vG^Q+Cf1zdfyJI_UbvvKKJm@AHv}vO zR}yCGvH_t&yas|MIMl^Fn#8h~Kzcy(=m$^C4w&XZ`H(@=#7oflJ~k962p96mrai64 zC1+GLzMBS+770`#FsK5L%|FhQE;yTazVBW9=Ih_eC717G=EyOf&!C466Dy|ZFZ6Mt zZaAaSer3a;NOZGp@VkcbPDKBhVo}5zc(POaYH&$E3{*}-e>H6606p%;-UGP@ya&3g(Dky z(zyG0vX^v|S|BaK0N@1|jGh_?Ps(mEW`(wev6f|G%rMchOpXOwEum@&V%2&mDC)#J zFkTQR)B|nbgy?1zRQBXx(+L=03SA}uBD6#!{iiHoY2I{U^iUsEs8hBLqQ%t+-V5Vn zhHpGxbLQ5Qc*$#i30Mb%KGw7}yJ~QR%F%QExcN-Mw*ubzm@x(D>qab#;({AV(dW_) zFl4%F6bOjfp9O}Oh$`LLreqp4R0>QdAwCl~tx0cBMxm&?B2kGj8A4k0tDybVp%il{ z#JMPbpaE45v#q6Oit^WzlgQGa3d67z{|+f)%k#-)uHzIcZVQrmcca)9#g^!j!+hq4 zwSFAFo7Z8gaS4mdbuR^pF017gm(3e&t!I3!&6?G#>5PqW{q;9+ND4J^UXK$ z+Sk60E3dqg9XrmXt{ru)CQTbR_W})ETnb2g31LfpVtDQ{U4_);^t5lviNyXEUe?7# zWOUl_q-mvTvy?1D4Su;9M@dC((|-CnR+(%+87G+5Oa875DB!>aL~L~MFyvH@G5$!- z#uGwRRw4PpC;xkm)>si-7t9#YN4m!Vjj6;y&*WM$GuFx5&t=8*$qWwOM7y(&YH}T| ziD{~dHJHg2^tuNbTep+%fA21C`pVy9#x~$;SHf%Zdj#(Zu1^RSV?7M!xaj=tT=U|~ zxba&D80)masZpW!JwnrGQMg%tqpr=tvw67dMkGIcB&K3qgwZ5 z7VBwl_{w#hebF4Ihw16O#m`v6c}SEb!zXIg{7C{8`+5<9&46 zmGWB&Y&~fsU;WyxeC#8CN!2=;E-P?zk3fGG236V@4FB3)mtB6We0+<5$iEnzIo4Kp8d4* zIept^eD5K|&(j)PkDZvpwpSq4Dop56<1uy%pZ?50aMSH~uxfgxq7u9c4-X2DSy z1t;-$MJIVP0OHB95xgI;Wz#yYzvVmp?t6cmxtU|MPq>i&!sEE^VO(zkS1;h0W6+(Y zu2wTPeLDZ}na}Wz{Wo*=Ip@)Hy*Oqrro4ZIofkfpbsIL|77t-c^n(YS;EkSUD{43p zY8Qb+>Jn(JQIwwRbLMHM@axxH$^L)8pUHMbz|bE!s+PLZ|IzQiAMAQ+PN1H96b5rp zcOeY$1CQ%2P#<{&WIesb0U!C`AMlJTp2u&$>6iHUhyIwqzwV3N__c3v^l*>X$`dgy zgR%WWP$$NcnM<>YNGJVyaYTJNBQ=B&;>IzEZV5w|KI-ZfB27sN_sb{o#kHKgI<6cW z6*98)=c0~bv`rW-y<829viqSh2_yOsNluqST8eg-SgFF2kD(B{X}Fghw&bdod52Oj z7`-ix{3t@~Gd9*??b@|`>wEX`m9P8@YgV1W4L4lRU3cBZRad=$AG!Q8rdO?EFmTk) zQCUk>8H`EZ3pzl?r$cIk1Q}_+L4_}SrQ&}0yCjTX2r9jjvCczsNl?>Iz{hmdP0ost z_fO40HL+`kb)UG;ND5Wa?`Bh`Qob>uHHu#RWvQyjaDDpKFgkZdQf;#FDD^8H&O|Ms z`6Xau7jnpZF?cbAU~|3#4FW708z*=iHMQ@v$N;R3&uV~c7b34s{fp1)Fs8UkX_pZq zQph%A=QVzxq=c&3g&^)TrB?Y~>Mld0-6;2h(rbCfsimTEN?hD~2i>ol3S3GwANM*j zNHl;*3~VeKQz%4_8%+!#SPX}bJ&NsEUiAE{0jTO0?N$eZ>YIbw(_2^|gc@sY)FCDF z376dGMe9#zghm?VR5^zbhDM=rA5*#Jn{UN9gm^wz(oj0s51C0dJWH~!7z%5Pe=bT=-ww!APoP~+#5muL?L{< z4al;LSdRO1v)tn_MFq>(WYk3CyW1@MME?dM%Eeq?RL4|33(4kNu=^;4gAYxAqH=Dc zLAHT?N^~VGR*E4Tdn8&+6Gmz9dTfyR7wz~Rat|Lk5{6`uI>2qe9k%5I~E&?>^Gb0g| z2D(gVMCK5Ap9v9IAcb&DYa(_qG0ZeKs%S+q8o5S_W0cTILC_ObFU0a4*&hWhni=u5nkkQ8H>o}QxLU*v`xz6!uU{nI~k+Nq~=+K$t((YT-~ zV*}ROVgL)ZVQ5fCczN;36B?dTyu8HsalupNfXRAFh6h(iM(<<5(%{tc?;vfi8@ZYU z0?oMivQI@{qkBb$e3uK15amo2H;a(mvxK-LqQEs0<9&DsQpbMAp$JhJl#?8}L8GoV zw4bRv)Vf))W6-{7t2raHcoWdL*-bWVcqAws`R5Qq0Q#;#;y^N(MAsPkUlB z7w+E7k;Ai8)`PULfq1H@wCNLs zGH-g@d)R%+g0-=Ve948mw1nt&^taFukrcP@d=a|->gg}k+ z=mD_-@lnAX;R7L_?n!i8LfU{}V%qbR0n4-uzOQ3g1M4@mdF0+ZI6CJsofY`SIchV5 zSVQoAFg2mtL}%UU{M*0%Gp~Ka+gQC}6P_+LYAjY=D#U(zpw{>#E-nTUj0sc*TBa4_ z!TFel$1uM*&jow;^0B}8JZGHthrH@_Z(!wy%V02z8$5;|)R>92v|5_6=*wUJEYE-O zudrgx2HGvl;=of`0auaSKs!_GfEH5EKx>@3HdImRcT6?Bn*d^|ti@RvBzH|ftfiiP zlnooVanUpW8+`cZX;oWMR_Ez1%yZtk=km_q`6y@a*~<&BdMT{fgqwR1D#j4&VBkm++F8U(Fe3?_luQL$t=mAiL^B zVi?l5CF(!X4LgS^NbDq*ib28&V8kQRig6JnBPBv~)%QMbqDK(+%ZiYZc7}>Qk;nlHJ9;6<6A>L$l>tv2q0m z4?Mzcx825zU-UwL?G3-q>NO{@?UYl1h|cr@V+~a+h0aa9ggi)TtYo^;;PD@l1 zGty@f1xs3k4HY3Y5l=LzY~%8o#v^+^grEl>l6EwfA@{84vuSKP$2vio7;ODO{`N!LmIy z8bP$Yg*vj$DD)Em*(RoIl<5Q_tPW2wO}31N2qf#_A)yq!G~p=%>MoNu6VafP-b9e> zZjYdwbct}wR4yF~`n1@|Of@y%OhPOh8pBVyhf0hv@-lqTuo1O~g+(}V#R}jV%s&2Y zWNah-?i?1Oc70Z_JCWPJ_9dp*u4A&jg1)OGV{^3IEpEN(W}f%zH*?zVy(}(zq^fi; zQ%B}t$X3;8)6x5$Y@8@TS0*ZYhL8_B69M|5d$mMIK1hRXj_+)u;7Et7aZO{ay3iHg zcv>bPs2Im}ga2O+4I|8pP2XILjN6VF8 zW%&Nkv?tZLp%tR)lipL;K&^_4GZ5W8n#z`=kb>Ffz`P;P>rg)u0VRukVnq4CJe?X! zjAtgXUvYfAx~QqLkv`kJKGf1n*;sCWiPRGfz8ePfFusoQl?wZ}25KX;0`%%WYfe0w zfBd^o@VuXTCKv8`8s0sGVH|7=d>_mTzIX3;`0(%k4%hwVUvt`d=QHrVtT?!k#cE9B zJ^k3pagN+qn3W%jk8Fa%6Ufs$Jn65k?=C`h;f4hR%Rkqo)lEi$KkD zpZ!#B{PI6=-R+OCYx63)3rZ8)Puj@shmZ2~r@w#?zW-fZdfCOCzk3%vCBBPv(N|M6slMygczC}Xhpgv%$6f8eJ83mumXwXdU4BqLLdx+2f(`R|kkH3hC@oBbg-bkwR||MV+3{6|OFyJru(_g)GZ>|~F`cOH7+0j~S(N4V~9KLKo}*Xy!(&nBwQ zR>nJH{6DvRhj)G8FZh)=z8T+lm{x;0m&j97dTYu4N?IZvo(<7ba)FI-=;mz1;l(z{ zV*!lhRPPd%x247chAzD|vH|$7Uga}O9#0$nLJ2Hn!Vrrr_65t=wX~V^&dW;3tjsU% z-|<|+mcB;O;U#KJJlI^KS2P>4bp7)e{tp-LyNJ(x`m>z0Wi#v6YCJRN5`sZ!Rd%FL zO}j&qPRLtN8SPV{OCCq-%D-z@2OoMbt z{7m5~0YxpOy-|{{5DlJ^+H4%PmXcH4s!LE;HHv*jNN8FiDa|V8lL@I&2s8ai+$cx4 z5^E)A{M5Sjz$u7H=M#G0t8pjq<$@sM@j-JfsoK%-{FIivRGoy<=}47y6(v58v6po4 z-e}v&&}FqFYEXz3dx?A{j(KZJEW3EB*qu< zad3>WI_}0I-bbk!wL39!Z`)$7H^;HC$TNTJS-j%cU(TQW?nl_W_abIz=Lt5@l3`6L z6ieJhgMf-1iTzF)Y=w+gljKb0^V=qxiB;v@LxU3w&7K`H?c{xp5mHFLW<|uBvo4to zP!S~;*Nd_Z9WXUm``Gtp&6wh?L(zU3TOT_e5K`Q`@|}jkqffvE(i)BLFX>@P>sB(K zl!&OQmaXBqcSa&q$Y_Zqc8W>ySq{*W#uX+bKmv#<{TCa3J1w^oP19@?b%7BV-#I*BMW;m| z23AgnpW@X>%-KS4P}hz#y2+@G0S1KN8sl2hr_v%a%4AysCOejI9CYkEYb#H`@=8AN zJNwyvT8D18RuqCHktJ#!3xWwgZdM&sacqg67IEL2`swq#7POhh-Z#UNXjY;?ONT4D z`#ue}r8^A5#d9EJdu4t z>&H`8mU5TTGUb!yVrp)W)?LWHkqSrqsiQS?@V88dWXXr+%PgzRjE>DR^&Gdqqt`Of zrsQexumAcLKKY4H@}tjwCaYJkp=GTqp1~p6=uhheq#$<5SgG}g$Rs==BtpsgD{`qU1dEPFj+OW`d_^5nW zEtBcPI|xoxQ4@{)Z(8H@kNkjbXP(2;e&T2O)E9q)&gq*O3%RDI#!kP4etk>>V0RbUeeUV>ec+dW^{qVl{1(spsn=mA zPS8+4A+R`ekoUj)_c;pe-n|Fs7Fb;9)3-1$UGD$xL9V#$Tt51t-y~q5H;arpxGaNo_@gwk2*{{>OnuwdE8Em0k zR1AO^Dl99;g!3=Bm=FHZ$NAtNeVku-;pJ>S{Zcv|!(#{U<-H&LD*$%w+67{mTj<5s zYU;kFJ+T6Sv-j>{V&ysphxTJTli&sGRf%)K;pzdcs!b4!SUrh1zS8hK!2lI0z8o>|@qD!^4Lp2`1i=*h{;|ka2PdI+jJg!AJi#jOs$T83Z-sHR{ zN^>Efs5PjEbd;^(77Do^blggeg;2z5Npd`rONjD0nF$+HMY`f|QW`4azaB6qqZ1^W z8nO{pKngTcV|vOBlTal-MAyqWHaUA^+Rfz&7m|K%5S*wBIB5?#q>4qoLrP>%z>z=$ z0fJ&mau#6G{cVtBRPclxEMEUj`;c^;qD`gIaRe+P$+S>Jz!6B2~F!ts&5EjdA~D2RLWLc3$wDpXN_~_alsT zDi+3sdf+l~20HXVmTKLH8yUEiDr}7ALcuO5Ddn|Lyp9A zW1ln&c}N|}RNL^SOaZyWA`MQ>OOw&Ayu#4uf`?k2N|yBe$2<78*UcT&T-7oe3>HAb1Nl0Rp4HorxH<#&96Hp&`S*B%=_+2gRkk zfG@175=eoY)Yno6H5*3K?<7W*@q}ptaAaOsJIPQq z_w05=BSo|;J{fBW9U1_Jqw<<{P#EVuYdb7ZoT<7 z&f9eXZcs-XzD2|-nkXpUDB}>Q2dKKKja9x`dO@_E%;3}hCt8sc$|<>7C95_Pp_9=N zlwy*GM0X*TZ=4y2ewX37E3*US{c6zDmjsrSAjSMQbSV<&pbAaws`##n5v9}OOkqQU zP-$l<)oLQHEQpq2J`CS4Sl-A3&6g1Wk>LkePFYM3G$*P}Y02+XFydTqL0?PyUNWGv zSHo@p5Dq!a$DZg~Mss(yMr8fFzyAlG`x8H|_q@~8nK4zY8G(Q=8L%O)K-1eF#?*(5 zQAJ@9b&Um*N}+V66o`;BH)5d{&bfv)H&8la)0Qw_wCV z=&OMjkQi-FQ%UFihtWMO&}_zNj=WN8@z^IdN-0mt@Wq5eO)Upen0D2|buAV1?A*2n z11t>sc=7Rh=ytnYuzNT6-unnY`_fnNtV?zwO_M~-C5!z<+`@pdi3zOfbK5Pq@Z`%b8fUm#?q@KkuKE`jn>1F)K&0pgmKX*O*_U_{7!U6*H7ClwF&BYh* z<2w&O%Jpyk-6fQG>X{dC`c#W%-z`WsR%bM zD#)iu2{I+kf-K!~5}ig`Db7tM+}=++$U4OqW! z1+K2yvu8JbU-4(3`Y!O*JhVH`IhW}bQ}nw%2E86_L{s)!%i1+-`S%;X$~7xQ;Z2MDP<}x>#FbjK{kuXbt)omot-^cAMa4pf|&-uepkczkf6D zdGDWd=~FIYranp#q3>#}v0Q%Hr9AN9G2ZmncPybRnC7C3E@E-9$I-a~m9^0FjM)wk zKJqBfz2r=u{u3|4&wp3bBKv|DM&&BR@s)(?$q_CKWl{hFm9Op(JaDB~bHxBYV;T zl`O6IcuK^`HLN4ZA(N#IuIlxZFP&Y#uzIv8*^eWLm(K9hLhs)Kr#PC+#jv0SqmYderV7{Ay~W_9_f4n zt=))!)4Mi9T5kG9(!Mb0dJu{F3z2TMFF7WtG}>iSZ}dI1eMtxe8r6enT(hBAEeSl9 z_3q?`mXcdi4(=Ty4kh)SWL}E6nGk^$!4ixfTo};!aN_cs@i88dO}MB`Z;GN7 zOyl8T2RwZA5iWo7rTpOs|A1fl<=1k_WtVdF=&@+Tj{EtzaZLK3l)Mz0ERyk_DO|yn z&P+zDDc_5A$6iJE7jiARELtu*Ii!7TF}k5yG3r1hk=`VaxBfr1*)ZEiS51Ue9+@W{ zIx*IO8W&Yhwxa0pTvtJ|P~;qqHi1M5qkEK$@OuKDl1dfEpW{mlp;V0*^O)yGq?rqw76OHJ zI1W;ZoF553k2sB6S2lo{NPb=k3K5KthAD)~S{8z1Vcv7%N!!@?{8w|}x<6v&Mf>P? zdy$d2$Y4zx1byBJx7~Ov&-umIaONdXWnnSUNd~l$nM-4nEu|(XqQ^Dm0x5ooC!w60 zi~~B@)J=oVcucU>xOfDl4`UOS`;YWF{iI3W@W-Fx=bnBk40<4yGL7Je41VfhCLk7O`x%g9 zT_dC$2xc^7#%#h!)azn>LNsp0I+R4EIe`i39cYw>{3p(xa;_nFqbNdpqq`3uhd2i}T!h$2WQD&-@s7eEr+Z%q`NHoWP3)jcr-#K@Gmf`2i5<;lTttofe&m zaVEycxbO5%XNSM*Szl6-omckyYY(wn_!F(*QiH~rb$Ht^gXsUiCcJt&I#N2 z>ra1_r(W?q_TO|HyZ2ncpdaY=x`b|zfvefLZknwp?ZtVhj3oq*8w{vj&D=sC5UdYi z48aTExa$sH{xdJ&wZHLZ1`7viF@Vs9Fko51mB~NRWM%+lVV_WC=~O2x0XAlk@svTL z^{~l+_loGrE6d^#TA8L44HX1T%i_C7fV23CXI#Xm|N66<*rBqRTFoJgy};@z%lch= zSm+wQ`1Qv*cC^p-E$6WJk|}&`aIVYDp`$F!{9n@EJl?kJsPFvN+WVY4y+N~NNtP{n zo{bHbY%pT92{^$xaezPrX+Ds&p~(l5*bIRN!rUg|1EwL+kTeNyhY)ZG`6TJaU`&ID z_7uxDHnuET!_)NihI`+;_uYHWUe$k8)mm%sd+xLH>GP4^J!cPVs8y?~R;^#vdYCVJ z&8zu;{_F$HuDJ%ugX#CQ?$gqp2tzWvtTR2=r5UMTCtV7o*LJ?opFiLWZ+|A&-FS>& z`L#dcr7yXa-3$9jcZnCj@JYfj{PA-nU$5?A#J&}TA4G^fz^Z<+0mc-Q}tN+Rf-HvH&tX$q@2q< z->Ta9r$0Kww=Y6$h6pP0VG-IOltBrv`E`nu;((qhRz5? zM0Pt66cGiP*Ys3hg|$|Ee=2g z?#lP^_bJvWeL-*VYu2;$r=8$>Hb4^{_V z+rH#Ej)bI%_4PF#z4SQOP)p@u>q(=|h|Jw44&|v^72m+2LHQS`VBhX5@G(8jsXF zHSDp@izv}#k{G(l9Z!p}OSOFtA_P1&4vnM5#|mWTp(pCUX?jy9F9!R^ByUSePB1uH zph?6WLGjMzp~|itig3!`N)0CP zVVK&8{#Au?a+zjnk|}#R1({)o=FR3E4_;EPeabET>^FTCf2A;An;|JN5;m@&Y|+xu zt!=OXUh#t4xary}x$ok@+D57z=^N6y`5xD^NV#5-0ii4^jE_*NZX|Ytea+2rE|K3S zCR{~%m7+>^@}N=qsUd`DPfA7-E)eZrS{NdV*gY2K9j9#$=U+P*zT1%0(jiD1SoX>s z*h)R`J)8N)FT0&Dd(~_C$Xy?2t(%*$lc6XGEe40@G3jmpBdhUAo=EyYu$5V)O+Q2K zINwI@+E%cZ^@ZOn4shpDu(M&JzCg;AJVMbPlZpi>Rg4ZO$RLUNAa%oA{kljKZ>~|3 zb787tP#Z-$nh2AhW2JwYk5A~aIy>s+*7Lr)^q4oJ_Nenoomgf>OC^3)?oA1k?zNT3 z4KWMPR9Dk*|X$@-Wc#iDB;G-Y= z81H-c``O!9Hcy`5*xDAy){fDwC;F{Kzp=&@TPL{Y*p=ix*x5PHpZ&#O@Q%0tZ`|^< zTiM>-101A~weB_oB8G~=9Z=*UG@$RNC~z!=WHBX=hTCz`RGSJ!r%R-*YlSD z{WqD7W-^;dpzxi z4PN-HlWc7!F6^A8UtR)*d+xi3_uuswyzqt3;QssXXJa;pB<7ea`pKOLX|P0`c)Plc z%#^);iAu+igw!p0=%IVK^;s|EhkyJn=<*B)2buM5&U!y%p$m2|USxOgB9|5e`$J|> z(~0x>jAL8J*jp@l?|a|FSAWGF{JXdPD#uQ4usnC4IivEv=arlJG0B6SJf!=U{7*WT zozJsgY?Ej(hntEzaTSIRnIGri%qKX0FdQ)7TI1MeVi@+= z+uvt*Z(#pm$;Auj+1}Y<=i)Ax_V*YhBeGy^w$9$cz^6WSin~AkX&!s*lU#MxI(g>- zM6MtYjUvg-BDM%GDT}YdF#>Ivs@XtNpN~@^L{T{)4XK80x6T4dM0kGX;W3-WzHnh# zJ@jS8N9$BM@|h>5*W%XU+n1}qeX*Ul^?#LmEy|t(`&#SS^t2;cn%(1gx2|2Ljdooo zw&{XY1k1^-I#~SueIfR-+~^ar&4_c%;^xPGXa4E zH?^55Ia{#IDs|7?h^sjeAc937q`KMI=z1-G$D8Yl5c#<(f;{M=qr7`Yzo1nrNcC#6 z`P#F#u%T2P@sSPb3&z}@Y@_DbvWS!FDge`ADV(t)rBrbWNx=K5NrS`Y3PgXXn^JP1 zgQz$iK~T+TR=UR46cR(T7$^q@WO3Wv7IbDQn`3z#Y9Do~A^F9e8i~5zFjR7OluIUO z7)bQZ*eCZX=V58#PXIC)`q0A|+7KjZ#?A<p+lX+}0kK}D+R=oBzBykaG4W7E*X$3E=O823P1C2eCXtY13f zC~cyEB$l`?Uz*9-hF#FkV`GvqHxj|Q_9Gbt3qzW>?}d$8?cB!DFXM0-F+7ot`^zGuZ9PKKNp{^gH*@6taoCj{ zTFBdOc0HmFl4Lu$Hz!M?Q)ulO!(IPL-Hfl}*sut06qeY|xR>2ulq(28P)q;gka_h& z6P+axWuS9(RDthBs8uv?sSG4E2}_09hO)b>JhsvE8*lwJZoTI1T-w_u&ASr1Wd+(1 zt4lTE$Xpq`{aw&2j$@RjetZ`t_*R=f`fEvThbYh(t?fP5-PNTQanA+pz!*6-nsCiL zD7-Ifzy+k7T2~ycUUtR+5?bbl(B|KYU4bwRCY9BKM(sFypRfWG>l`0D8jgB%EW9Q% za{9GpRT#B>D&wSxuy!}JB|~ zsBw+_xop!{jqBlJ8hP*ia$}_;G+iN;P^`9n!Q?|hz-h`bRGLc&W-m91I%e4mD}9vl zcxdyC8+heNZD2OrVvx?|hSJO2Uv@`DpUly_tfuYAQ4l*tIZ=<^s{*&cY_pxP6q9V; z9cOs_E}r+I=kg1`@-O+e*MBn~dH;ua+B2WW@neau--JO~ECz;tF!C;D^l8pR4?V)^ zhd;}g-nPq+{LF8#z5M_meBXZsVE5uadACBdcXsyK-BqqQ-dp(QOh`)s4$y_tbv?uR zPtYB|iEn?yck}hH{~LVAcYQCv^Y7mQcTYzb6qU4H^S|0%kYH}j4^c?WO)sUPS2f8>`+?YBPb1zfqg z&U|f-W??Z5Y;?9@$q7!MKF7yD`myr-@Bj9jdClMcPWs_d^4W(;vrVfrFKk<}T8y-T z2SpgRf*7>VX|0QR( zclcNT;*H#V%L{n;5ep5!aB;zzor`SFH_#mUCH8>>7!qj)2gATD4-AV17tf#O(qq@K zee4p${ywvlYXCg>@I%~i^$pzf$@g&Uv+m%jH{Za$4?N8EPrZdJPMl=kuaR7NFZLHa zcJ4fnoqC{*&rkix_wfTi@{fRl;qeFQH63;PK3`Gz@Hj6afF^jo-{a`oW*z6!rf+Dc1ts&QW$@}h|m^h z-Ug2}hCrj_Ogs!e*HU9Fdcx4IhII(JERJ%{1zj?70*yW)yPUrpJy$-h`VQH(LcblY zi7$V1wW_?F;`H@Hpgl*5Jao$8_lwz4^qh>RduY~`hKRz7GN%tGF;>l<>{hx|?WQo? zTnDVGXcZ0O$?^7#_>dh%waZY`f5a)0wh3(QT>4I_p+bFwln7I^7gE?{Zok&UK0;oq zqtlH)<5~%|X`&l&zO85@N3%p|O<_wPbF|bGi|LA&YY;yf-`p4(7PQW&C{MDXo~$oY zp3~9~p`tV>_P05J!p+d+LJ}obcj}HJMeTGxYM3vjwL@7Dm`zg?7!R0Jt!|XT(%U6N zwlOI@Z|%1bGjmME&aI)2qzr#?jU-!X<`@mP$=cJc2H))M@la)Kz6@BqI>hqEVf>!4 z0k*@K>gbeyF9mf^LeGqSxxlHtM|j=e`P+Q#lXvmvpL{d7zx)m^3>OeAHx8bN+bCGs zSiFrQiKLNSyqPV&iDP*hwe+m=LUk@A^*oIXal-)h$DbIQ#U-$Rl#5;fW zXL3)Q3WO1?;WmAWR10gA~{^jgEesL{G0n|z!X z8HUue-gl(6W6Wo32~v)St=a5dSYG7GTi*z5=H-Bn(E@>+iA zm*2uqe%E(%`|Ypb;@&P@a{duvKEQh48OmpUjYxzR^a@8+(ShO3_6Z)z>7whAB7_cy zc~_dmCub98B~&bhcR%Rd&@{+i_+D$`S?@_wtbsi9=(64pt0PF_~P2*qYT9r&6E*w zs}WQwH17NpljF6FKuR_`Le*ohWwm@>S;;C3{g7ex1IYjYAOJ~3K~zVvePlGK4G&4Z z9{MR;&H!e~zz!&B2*ci#GEn4m!#xf=cP>{mJR)~kL6HRWd8kDj-fP0hl*766=K%QZ z-5+MLz0EL(VIOX|=>`CX{KxkC3TR` zeTFaoim%}PANh0s=QsW|@BG96!rd2_(IfgIsaN)2v;CngKeSA*?|+(4{NT10i*% zIC1?A{M+CCPyFkHv;4vD{5F5|=O5$Ihacng*&R}vu{P^jJHEj;zV>$h`fL6M$F8^u zh8+&h+{65;r?c?fQz|wj9TeeiBbja2J;M-)%m}Z_J(327bDyR=aT9O);UDF@{=s+g zOF#b>{@@)SV*lKOeDFi}vg)%AJog39!z!evRLM}hRmSZ<$UcGa!?(I3B^AN|39%J2T(f8qTf{7}>TCy}mQH}*Pn z1~|{No&;yMZ{)8&^j4nnqAvn2u>I&gJZTOmHg-8aH-lj7xFdN}hb>tZIyI*anM(&3 zIkq|Hxwk4;Tm{3>(RCJheZ|@WIL%X^@q8|B-^(Ao?KkqCUpC<1@ zcN|V$aTT{+e;vVu{ZPef9tjU=uiGL zKJoGUxc?&`|6i@Xkb(G~P_F`}e1NA0kzwiRYon5~+QP(u@$-OA&ser|4CYuW zy3@+=cDoF!6rQwpRU;aMCF4HXNg zt8%uUj}~*FaB&GGquTUp>rMM)*Q`<^GonTq^L%n!GOPP3z;v0Uiux*TZ`KPDp>i2{ z)xH_8NpxoNQXdbmF03((j#N7Fk>(+9q{1*{*2*Na`}59iF7(i31?n0^&1RAT56Pk= z$Sp__=Zz>Mlkw1QCv{!-(J{SV26*1j!Qr1qz! z%Sx#;vWL|B-N=JObx+NYfHuI7zz09=t;2?Ga`4C0CZZ6713dWxL30v z1e-}Uz`gEpw}wXuy6in|A!M5AXLDeWul?#*@{FhbbFRAbMiNU@ER<$*KI7uKi(G%x zHNZBcj!b8XiHC$l?w-Q9!7l-Ir2d~>`WJ|!2_!or*5Sw^aQ<$ty7?yF`nKQVlOOsE z{@owGlaGG;&;~ZSNz=fT2Tzk_^=)rlqwVBapcAP~z#xiffF!Myi103wJ^YEvbuWxeY zbx-AQee<{Qx4wA`(@Y6i1NO;uBo5%xgXHbI(P58nHV1^A9n%kTkeT(#!hOOZ>b9(m z?!e?#5UQM~YB_sS+JK$M81ylYow%7d{n*d&{Xe$gv3ozpyFd6rK6CFQoI7`s#h^%1 zZoJ`Yo^sRm-2T#+aLtpSVdFELBcJ)G>5(+2%ZB8#FsrTz>Clh1vmJ^^8X*p42d5}+ zpDg9ND*#E%WfLwv$Q!=x%lOW3xt-19*N_kvgE=NdH`qIWn)Q<>VgEt8wRH%dcL6P! zJk*>lUr4`3K6ek@#!dXwpM5jm^IhM9KZ4e zfAh;fk1ze2zsdU6CX2^E&TQ*Se&)yiK0o`D-@}QMS2Jif*&sc8=N_fsI01`CNb75m z60@zV$$Jm+;uk)LxBj1RXFlJgoAnHOK++jY9k_Jv3=EI6f93%;j^DsHe8>0k4d3y- zY@fc5d+zxx+vm5*i%azD8(e*IlUts0Gn-f6in599-^cRYN9c55CUeRuLy{1dK7Tu8 zwgJmCJpb7@@$>)s=SW*u(xr|(?6EQ1WOo6(=N{)v?)(B6wn^(-MBXGj1;*x?YBqH6 z&I2f?c;@q-%WuE!tqi;8`13!02k-vS$N1>o4>2t4c>5&6`ud!wJmpEe{Ke1V_E&r% zC$4@n$~L<5mvFE!eim#l&{uv4kqKSpaQ5vA=j-&L`RL2~y;*gGMmQ;t@HNAT1 z*UEOd-7xKYb8k$S%V_sve2fViV<0N+-ga|;LUXEJTmZ90C$A>v$VTu-s@t?K|4jX6 z@Py4^_Ij2~n!#eQ=!+z&rhE`}d$pET1E`u2D#yO(YEx#26CRW6MJ12ziN;~n+KpMV z&s2P&U301gf;hVkTf?tnW<`%1`AwZmfxK6D{EH^CT;kDFj{)%B_q_KIjpMUe?$U9k zBdeR7GG*+13GeosNE1fq100EX@qSvfoR&UOGlC>T5=Wau-J9EX*(<_ zC6>Ch2#vy6z7{AZQymMVyLqYwVNfLwypRM3IrH&*{*s68`wV||-)APZ-vz+lW9PAa zQ0BmDWr(2V*mDp>JKMM(GV5uLPoDWCU-_k9!O#5M&++|ld?T<0Ts*SBIq#$0g5{7c z*QZtYQV2X3yiREuY31%{xib+pJsd79o>8muGRmMD_xaG3 zN+LgG&=4^+02dMWoC%ijN=7J|Bv5k9c*C^nzPkHjvctW!6!>V^?L|Km9$k|+f#OHo z1-E%V3(8813^WK{6Eahj(`d4dSr4g3Ktw}yU1D36C2-UA*8sP1<+Gp9v8O-JQN@Wb`Li_pBF+2UqawOV9&vJ7t+oA<(bFW z8+zCoNb_~B-#P)nQue+4K#z?pLc3$-Mg{mds^I7gfVm1Ig;@%Uxqo7oI5?hV|!KIa|p`W?Rf z`Ok&DbMWX6c&5@PxG$LyK3agsBm>;q%met zx2?AA>$FL2TZ=%axk!|4zeYA`Q+Ue*?dwMXn^typqy~fEM!iXP(zgyi2A0uX6Bf!v z$Wm8^GC9t&Ifbc&rxr4L@7ghK^bIJfo5Rk7Jm>kh@thZZ0XDA{&m@n{afO`G3y*pn zzdE$pjn$YWKyfyegjzBtVoRZtoV6M%HXt2({$4a4i5;E+O zFWk-Y;38cT8*6${&ypKxopv#t8a`^3<9Nl=Fc}rfnx%X%sI+bdd%J8NI|1|SEJRu7 z%x4EaFMHOG-3a>^U~iAq%?Jdu?M`ONdJ_lqC&C4>mRXf&C97p$e(2Khub9CX* z`Q<)&PdRq=b*Ro&JF5z^W*PMo}o7ro@AejLetq15L7qgBV4IPQDk>I#5>kEL!{)=stPXhoHH>l3XmH6QVQ*2FavExaP{M_*VfOS)t& z&CC8ybf`pmQ)v}#m(q@Ao+;LIQFks3W_RHBKoS1zgbYF_c3{Q*58sb;9ShB@J1QXfz~*1cf`%Y9cWP{=h^HcPPsu2+ zQ#gHMHcMAV5|k2LCgDJgckPvM@PzGKPFfRc?{$notF<*XHS4E@Lh6c1n^h>M&lV1| zcD9PNok{BZ&Pg`&C%qcqovCAqN=@n5uQ|-%lkR#808TQb!i5{?YLss z)-Wb&9-g7z>jl<2Aa|TSr@Zh>zKVC<`vKP1AkEgy`6KElWGON;qw3sa=eg~fH}dcW zWi9pQl<8|{Mr)ClQPekmF?8lU3wt{-yY^=O)t`QdE9V=iF3{l;NtL17U^eU6dF&j= z*G_Wbf}%<6G#qW|MD;c|^lK-DstZqX_+=^^`Xjn3Fk2HIKA*YaIWOR6e)SjW`p#g^ zYRA%MNz7!y#fwXruXF!7Wox~0q{O7s2`zBhi!GK0I_}!*c;;hS`fl0MtA%P1X6n^+MyC% zsN%HztD!t6pQgV}t0o3jrQ6CFSed>ktD4>j##ILBih84elcL+Viwr5kN}4uA?`2fh zh;{`1L-7^tL@|`cdt&33j>=ortyYd+u9Js)JYE{KMaNEPw914Ip6A4kG_@TepiG`Z zE3^pkFziYQu~bCc2&qAo?JX+;*~(JgC!c+UVR;`a9TG>k%Ro|hHg$7SKdWsP+-MFo zkvo|ZCPd4m%GgO$PKj0l`Hn;lk*xD7^;-%b*5s4niK!zH?Y zhNKPmH|<*!&YT133VhsR=S{h!**cltp^5vz2D6!kx4q&EU(U|X1$2PftRtn4#~%C? zfBDICyzI`G!THCLejQmHpvxJZWLUr2`r92aEDkux`)u{s@%I1xoBZB?`XgTO!k3cM zKIF_&6N4+FV_Ta5UvXZ%kz(rxF3}bSldEobJkC8LdxXbhtLb#s4hus zb41oiqUds$Vf&mpb~=Ha>?9&lhNL91j7-*qm6LrM}P3=O!13y-l}KIAq_Mzhd$ zW(#!!sb52+Bj?U`pT(20w)5YU!;2{0`~=8A-hO~#|86v`p=n0yeS?Th9x}Rrfi4L$ z+n}4T!>03;CaR~^!iX+ zMG_t*yTfKE6GNMK!;TL9Vz5k&+`9ecSfi!pc`Q&kM#5)KSC{LFTRxXHwWL0MnE3ib(KQ#A!=$SWiV} zh|5}aJGIW7mO`pRmwL`#ILEV|^Gx3ItH0>acJ4|Zh?L91f=7n)Ji2|FZkBA#72tse zoDlU?{u(=i3Kd&NZ_Wk5WTHUm=sCZ4hO16q%`gA*zo0XBltnTWM~#i-!n_%o$LWB{O%pE13nb zH|+7q?qe1`qA?aOi)!E;5r$>bGP7jK=GqqbY~RO?x82B3{j;B@LmB9ia2fe2R!f%b zF83IQ%)=K>vp(P8k}f?mq_KrV-lrhD(>ggN%A^XHOK?@F{y-m(M=<-ZI0V7aHo>#4 zSr8*M-Z;+E8CqO?ekmX|B(OxKNagQ{YS5gK49kEfPk1@jXNB($34z0Md-_OQVk@uu z%e~ZSwJMOOQcD|~O2>jR$_;xfOXuFg;?uPvrT%Th0ZJm~5KOs&MX3vu0_7Svt0X%1 zR+#c|qerAVE@I&>j1m{Oy)PcVrjB5UBHN-v5!%r7yO1gsdx=>Gj~@u@nz{a(6U;iF zm?cpU%#s*bP~h5=Tb$j_>@JcWbdj63HEWf!KJv}AP^c;D7U9C4a%}4aU-X49W|l1s z&r(>zzS^E*PVn#^T)dQ-^%Z&+v<}Bv=gh8Bp|&mkG{#yed6mKgEdZT)v}Y-?KfvyG z=GeS*gJ+=go!2yE`qYy)doC?ucUS3VQasHunFCI%(lD9pr<^Re>+%vjmN)rpul-8; z!5nfTh6k_^2FiqeXj@tAnK2#v8xaxUGO5rd;W?wZp7j77(cnHMnTKY`@{qz5I@OzM8uDfEuQ&cQ2TDXt6^luB&$37 zb%5#wYfrsUjd~KQ9o>BJkee2+={s?PdvetcCRg|@>&|>k@>qk!WOF%P#!AhkmLhZ- zeuJu1hJlV5-TE3TOC%5E#R0HDhr!IQ*$md#?PMdcB$ug22Iw|=E8mq)7depJxa*Rl zx#wVC>6RCH(Q|L++g^7kZ+qVZyyTW^*xT7fmq0q;zDIU=!}tCp{`imoZ%$nI0)`8p zM3xJ*+kiYE!_pin{gOeKY~AouE^MFU58wU{0A_vW-~jTF=w>}1f8>6?<`vK5_7^=J zblY@~7`elU8gY+CekTDLu&nbl`t=#T3*WBS#!#@s2qYHN!_rY!V&j;7w-q5vve0c> zV=8zCiif=zTZs}6T_#A#kSfq)&t84ENBT8V=Q2o>IZF!K!-b$TLop@`0x4CVDuPCU z1;~tkwh0j`wZBWgblwfc9%en=+6HtT40b{tLqcRm*Cps@&hxIz%I2?95G!DgPC%ri zoAtG?@wcE{6qUhcVMme~X?WbEBc)>Lw*lvr)& zvEqzIX%S|D_6tPwh@awFs0++?5i3?tmpXKad|)*stnlIrrJ;v@!B|P@=(n`*w7fS~ zoriz_|NOM|wt7k@_v-cF(?B>)^i2kY8 z4e!ekw3fSaWDmVsL`q{lWCl`(gRGWU#5a_ovTSk`&e(#ksF9F(v7r%6Vfkx(aqDR2 zVDWmgVW4{Jct^1{ys);n$ktfTh0LPhR;=z2+fqeZEUHV$j+krrARln*%qbqspXDGg z5XADq7Gm09udi>BQb+c~Clp97ccdVd`~=9@*)06ij#j0m3;V*uAr5*VcQa03Jj)}G zKT0RU;EWf#Wk>_cz{Y&Nte5Z&mZahvi*;iVcN+zIFItluE;3o-rv)ZumW93HJfAxK zILpDDI=yrZWJEGcGF=k-ZblN@h&Q>`5}tA>O`Xpb1=f*CX~wCur`VVsBh73>M27@= zKqjNo8KQ`R#d41!E0TH}O%amzMVCl0SZr8JIAVMgyUh2pb7Nztwzh5~Gb(a?^rZh( zI#GARYw2Jh_Uv^>Rf*MC)?mUYG6bB5)Z6bYWc!I?hZ`lB_sLG?Y{Dh$+^Fx+6g`#$ zhh<}tWz7ri6UF&cgl^EJA&M2`6LnOhcgB^M+J<+ zUJ)~becstMZ4v4 z#casAz#PM)EGOhDyx=U3~xO0*fKK18poNPhVB7_RR zYb|R^(^{{L>WpM&ExF5XNfKX#n`5v+x{|Zgx->TKRVUAArps99v`s9N(mA8Git0O4 zr*Um<+y|=B3)!fuv{#1B;J<+UvItJiy+iM>VKT|)Gfi72DqpGd-Na?+@Y%R+E z34RK_S2=U)Bc%z23EOtIX4%SCRax2)vxJ%j9ItY`@6L#=@g3b-oRDsW36*ZRGPOAo z*MfGfHXHM2D3sJ?S2Ro0JDP0g$Q?W;bei`AF%T2FK;>vA^C96?YL@mkTKTPvhm%H@ zBs${_nIVqiVLpSb2K{Y75e)9&P=RH(wnyk-nfGpDdPq^Mi7D%Abn7SS z(k73eIp90L{SExy+y4W1+;KZQI~QzNQ(|o+v3u78Jm+h_mgl|XMJ%@Ovrv_#kDD9Z zp{v4xlhOg-r3g<^EBs3Gu_a(AhqC|xAOJ~3K~!Q{BF(u_j)!&VZKuT&O$|@gacjmR zJn@C0n-HENOrf0U=G+||S{5nM2NX?1v-K`b{Zv8Rgfqspz{jsTi%cJ99cp6qZce8& zm|5+R?F6sIvLHC4z?_A|vdWE^Y}vvqjn*}%l>{vY3>qA<#Ht{@v%duuR6_!E7<>*V zcj66(u#H?xk_vBzJP_*6bkPL`>h4B-9#C0Ac4&Uepj~yg#Nd>?7iL_K3=D!Mc9drp zDT!a>R98)o>M75;vnqF3FhlI9#n@C@ zkUCF9OCx5Yc?E@&!$QLr%YmB+S>eGhN<}arm{Z=-LIsr*c4G4P6ZNR(@aDJV5x3#9 zv$2?XD9?>`ZAfKh#gMveQ7plI-zSEyV~sVE%ur9PD++YNkZp}+hpr?)r~#K%6+HqG z##U`3cMlLPbxq*+JrrxgmM&zNcL}y4cbN@JoJ=M<7-AD)U_b}gYp8>!qfItGMhDv^ zR-m3TX)bK7%?VpP>;<%g1dCiJSBAQi06##$zvXmoH{%OUgO)KVR7;$(G_(n!9ZvLC zS$4h9)7i->;*NLbLmWPNG9?Jo=ur<5c<`g1J5_%}a-!S*v$BS5vvZAAd(|D2(ji zQM0BDOBh_M_8%z<)!vuF0!f6XxCeg6!DxkR3Rh9yDi=>I~lR-XAFxAz#31!o6=*4Sp>Oc2*qp_77TjNfAnmB`Ulb_zn2=4MtDeC!I2{TP1S^H<*|{N5!zv88W1UDTxsTEvP<^%|+{M}@VttZ`UC)i9 zsyImePfX_#iY9r}>{{9IF1wvlY$gk-6i+NWRC}Nr6=fK0!>^UhHLl-wMw8E52jl0i zQGo5Cz}if!hK~yT*?3F^Ke{>-#|szw6j>)u?=Y?^Z)wcg;;3@ae(h(QQ(nH+3Dd`ZMjX z)c32FE;D9IuGX9i^tT}7Y`+JVWKWK+qVu2oh5%k)ux;+YiMyXxN^Z z2b2Dc6ZP8DW3CK&904_k;>cQYEKrd|)ii6c$#Jr?mzSI#SsX2dg}_?qi8(Sf52$9c zSeR4Nj?U?XhKy_JGe-LwDyW9#*KUX1fltdAs6gZRhPOHzNiFD05mNU2s)H~j%waF; zeM(G|9=AuBgM}bx^+VfR;ZY_>(7GdOu6@iF3gosC0f?wcuHN_aUa~XTZq)ybR#cS)2CMH zv`5L8>*An1SEAJ(x5m_6nEG9-hO_Dgv%^w#7PP&vWLC}?A$?$~gDV8i+c6TBzKT~Y z!e$8j!OI%l&QnKWh+@f*y{RIGsLqPTr$_T!J49-oaV-$>vC-6Z$})B)2N<$2^xoNJ zh)y$DhtxP`rur-D_KHS}O0Co@v}|Y*Nx7rYmZx*BW#++?UK5^vJBh8(xekRZqKTp{ zgVD4*!_1L{Im1FN6fB%-gULaX_@+BB6Kd*$=x3gcamd3eoqXNsZOU5sy+Qz`5i;X2 zr`V7!$7JFH#K$<=i|>+@f|1JSRZEukN%W-^7|nQvfCxi*Y^;q1T6_*I)awlnd&8zi z#Nqo*g=6MeRaPju!*B9AutAe{UiQMF&seY?7LavBTZ8Q~CZmpN{W++z;`OQIJybj+ zsN6kcAdE!0+$nLCgl!b)jv6SC1Z3$8Fwv2?GjO1K&s}|AR z=(L=KSENWypy6%l>h-Cd3ne8wepd%nI(NQErE7$tv{1-Wmg^$~WLX^z8K5r?0g3Y) z1>5k*3zrp&!KQ4HstVGnd8h{quQOrq<;^>Wy@&Y9JMZ9s`i^hlSAP9%-1)_?42R!X3}v z;L$Uu>C=py6&6cQTzP``z2|*=)9YWw*L=;Fv)q0J){YS&Hx+y?l^0r}son?e3i^sb znv`&ZD#$c8kt6wbj!c41d!g)tR^?a+Rm@mu^tiWW5~FRpCHuH&<%^PBP3-hbXLggJ zp3J$)B~)3;u2uaQcT>|p!&{myIaDR!0$$WleUjwOHb+iINIBjWb9Q8?C((7(JQ+S7 z;ykHZ(SHiX857}Fu1{>^!)K~H$_$2Ywt}@%eV$vnDq%9mZdXIcGQXt$4JQ*rgYZc+$pEF3o4FAiVZgPF*Baj=)%OIFqXfoeGOG+U-t9gbN`8y*S>g}cVo6p z&4RJ5@I*h2a+j}vwdP=G+GdO9s%R^I$FV~06o|vxGh#`D6-xd-s@tS#ZPWj@XZ}vv zB*^9IuxB;ss?jDXsT!m>s|@WV$#R~VJhG7PHXlw&9xajZ+V3ikeu{RqR&MroG>iQB zBSN4>Xx>w&U9kyOEVo`sqHQu;z3-7M*JMLB^dd6SEn!b6ZV#wZPA0>0FR3H9TKYp* z*8wQvPPbUYhr<)p_D0nBqJ&nt6W3H<-5@OJub8;b86rZ~%pi`W@ip8q3}i{AtSp^V zEqlA$ZOlmc-RcnI+hSp8_CDzJt!C*^U51ta0r6wkWs0wt!yRDy1qMRU>ce<6c1-at$s8gvk6Mi_K`Wr+ne1 z?pgN@lkBnkB1YIzgqu5%x*VdMYAd$&XG-E_Lr&GuFNyv%I#0cgsqHJ{K9)5gl+)Hq zc~YHqVGxyKnt5HuQ4NhG*~Whm+No7&hd9S(-)oE;LmhxBB)zU+v1nf@(7ukEnDx;3nllLKo&~as76lU;<5O%cfFvP2>w$N;crHoxuVGP3P zck`Jz8`{^)+-!fhQgmgRm)&oxuR4Ps{oJZMa^&5WU0d;MMRO04sVc8_g1O@KNv|!9 zSAIes+P^hX9X|irH#2+gt=x6rqx|RZ`{@zcU-073=b9^yvAes=_V(j+By#SU%`#iZ zuHw7n zQy{7SY&hSX&x#<9!ONB8t%4{!3C>@|c$Ipskx!$Ipn`-M#_eq#Os#zp#zKt0HvCbl z2_E+ym_V(J1g6h+5p#ldAh|)RA%txfh#Nyz(a7btEnzGK(uLZ#aI}b+^DTHS4BTR1 zIIRkFG~mpkaN4Cn}s zjNdvW5auA{FZ~U1MJXwqYC}OJw=^~B<8L+yJ@wvNKDk(Dc z!Qf_4)LG?atcA^C*PyK^g9(kBvPh4X&wNr91W-Ex%X~|f^P0IH>&W(%828u|s(c#x zue50FiX<{RmV=_au7rot4cSil!jk)IV`D@w^I)m{LRJ;NY30;Jo&+t%nq?~NBInQK z;vsof?gxeH#BHar9(vIS*W>ep0Chp#6xXz&6*fsMF;e^3sJTvsB4m_muWO)8CND?5 zv3V%?WRu1yAJ=0ZSi9dIS`qarw(+V}hBm_4a{Yv1GlczsGfEbZ0jGqXw+NniI5wI~ zdm81~BDUMUn{zk(zaayp9%l$OmyNeQO~$gwjo3VI1V&J*8b3}8TEScC?aiTtKTS5{ zr6FuWDm~-H$Zgahgi0$~ga$*h@zIuioeoGN!HJ=e7On3Q=l1eO$`gsa4?N!OF^LFq;1i!`b;|}tH$T>8>>D?({+4pI=r^N($QNgLMLL!P2+r{gE?fn1S}0X z)4W%EsTGA&gn2bwqM8U{Iow(o03n16JGp8uFxrK<-ya;xEyh!$PLYPSOwNwUl7V6^;j;`NearP5D<5@4^z3+TGw|~iN zx%<(pc=}D(@c83r8DwCYI}RQ{%i6r>=Ige&?a4291O(*elHE%OJbvbJ^3q_ZISKQ% zo|BtvoY}s_XFh#5|LsHX;04cp5yQC;+i6vcrG*%Hj=vH88YIgIB~|o=Bg4YtlJWZz zG>dSppkK?Bt&l4^z1cNr9SbEKr%||N$9e@16a!U8#+n&qE=wg9his8Kqp_@fH{Rt6 z*`cKkC@$Z{z4W!41x-}wluKKRaZ~t@_2%EQZ4&6FXSiJl7g3McKQ&p#C1`iE{%j5L)qW7<3lr;;#nO z*V{m?qVj_}*<^eVzh=8(W$ecb8E z&5yESKQhp@yxVd??Qgh7>hCI98x+duJ)6H~28g#^994tQ+eVI+5GZ$2$O;;i@?*on zTdfpZMhZ=|h^45deM`KYDiK`oiMPG+JXZWs)nPU1!MJq>)X9bJH4MFVt_8A6+z}M0 zR1be?*v_*jfuk{P6G5A~QJo%!s;p`>DQL1|(8=y3(OjHaMya9pu<438v$f`qc)x1B zfeji3bg7hGwnDwt<(xO7J-h9 z;#dkkqO_M0;z`_Y2$3<85dL0juLV_Pyn^c|{kW`h4##85k%Q9H4zA)l!G zgBrbEcXh{A=g{#%x~96(hHwHM00D9+_~ z>Ag2~e613?EXN93B|Od4lSD_2r#d?XGcLVOm0Txgv@QDBfU*K%b4Z`Ucyl@0tmb%7 ze=+hPB=LdqPO8RKnF!%VVU+e1de*+Qn~YTeNG+?8_k{#PNs!h4wimQco~bjg(G=~* zq05Uh-a+>&Y%1a@^ghV~d7J8PUKA zS{!UbO=KqxJ(9X@E$+>SI3=cbyQ|5_3MC z12>1a)NDF>W4BYg%iEG*8V9=wPj3(v<}w_y*Iv6 zOF0TLGfK?;1U}UnAfwSg{M_Wu3RQAc;|mR)uK!)16@`ZsnkrAD<0}2kcrF1I<;wWk z@t@KBi6_ggWQei3gsei+X3SLYV$o>*&u9c39SaO^+u7Ap5#7sh6?RkwsJwGNytarKny2Jqe_~$ zikuLtJ4eEuQ`=aa2`)RTo;$p88E6u_6wi1f`a*p}$CkWdaZTEiq|hXs9Wipw73ic_ z;$y5{MrzQtN~plNFVul;5S&1kJaQHpa&bDZ>x_w!sN7Ly^i&<1Z-K(A)~@){&V(qp z;tFjn>kKe1w|}LK+o*@snJfOT9x5LaS#pC5D%<~!d{S2fD&f!e$*d%{}JGAEg*I(~mN;+ot!5079BwqUK$d0s(dvSdx)XZ9-h%*O2`> zsj5e{R$YjLGN_c~WD<2J&^Q>xxwas+u?2zgfmEb4A?RwG%!8@LgK3TuCwF1Iaid)C zn=dL!+0+%FP5NsI8(ox46jCcpGt{j9&6wD4A&k-D>_BS%Lh+c`5dJLz+p+Sxi_ogF z(n8}J!JUIhv6(J)5(1-V(ciTxE8?`#2M}gyoE#|a{x+TWWcVz=jHCoSQ z_n3-|LJnJc(vIhd&XYb!s3(d~(M}DJLT90_Aqwq?`GR?4!&%wv8iewQdc&SJ_A_Ov z-q0BHR)NH+CPecES0IfVRSUZ?T8mBmSQnC$}nVBqk8Q9iLfc( zoQ@+{Xrm5Vx~}TVWDZPkHO1BI($cGi_L;GQLK+-3;D{NGB(AN{@mh>5&A8PwlYLGp zqok6tC?B=Ep_5E^|0lw8fm|Y2$?8 z@vfsC>Ue|@i|2fyo&@rMrVVEKJj)B27v25}?z{iv{NNkDfq(NK-vwOH%kFpzR~}zO z7YoaGrpj`;By}Ch<&h+TPFXILKY#ZJfF(cthF9~g|M2H{+HFr|dH!yCb|GzgC|WhN z%6L{oq3Ko#?$~)8aY0i;Zk}aamM}tB1ahc6)1X6&o^G9rMW{!@-)4L=lylMx8)`w~ z$cUG!;3&=vf*o4puP(Lf1En&5Uz%jzjK)1^P;)H=-2#%_&`uL}nhK3FZ53W4CxV4a zxRxPKghu&PQkGBYS#fkRo<~8;xKRb0x4u!%YV?df-8z@3<56hc(6@eV8&EGg609QW zf}i~7gtmnq5{tfOg0^xx`jv!o26gcwXlaV5EmTtEnp)My>M6F9Zi3d-9pcENWxLa< z>2uTMR+mn`m0DYRw>;367xU=}J8T*~R7g7&a4j8IHNL)O)3hm*hGLWVK9^b^wPHoR z6=_#5PU%?R9TzZqs{ENasao|i85z4RW73qLb;A*8HL-~jGB+G?6~$zIk2P}eZgpsNBfc5Cr=*Nnxl{VsaCKup z7+J+-Q{}vjt;s}MBvOmyuDUISypKaj6qEx{9i1lv=JucaTne73Ew5uemYmJSw*JXG zj{I2}3^9Ih)y=5@YK{f3kJKCmNv*<6K^5EcQj5~ADbsIcsX|3vpoHkcg+OJkW+SJu z#cP?7A6-fn(Z{gC3UrIA$im=WwSgRBv-Lz;RJk)su5A#1piVp)rA&%vqTbSWXMBUg zNs-U$9FdAZs!FCHPcWujWrN2s7MU-NkO(A^BcAYnm-SM^kWpp{v!kh}dfY~6>L_T6 zo>E^hMbTx_#dDE!silwBYKpK70!nRvaUkiKeOq{8OP5l2^sS5oA%Bss))fn;5ST^S zG!Cnz76usYDYPmR+j%2)V6&sI8eS{PG&;+xhxjTAHnlDGll&SNiRERhBXeo6_6qaX$KV|ydir-H_2$n8#Sl~`yAH6YU zuJ%H)m}T_LSjZnLpnTd^jMlc7q4mm76{<}kO#!8xm{{?>QnD)WFsy=7LlN*&kTdpX z*{LfG5P~8EjT>5pMj@)2n4BR9R}#Mpx{sC}06#KR+NcR8OHR2-m-kqn`xH;U`DT9cxBe49 ze)=rG_`m*Re&N^tYg67;{C}*y&8~IJk{vW6*FNV~)%Crmq_V3h2^y#xSTY@VOp7<* z2@nz>y1al}H0T2C0m(@K03ZNKL_t&!faviGbm$>Vv=Ch^*+Mj|q8c`JZBtdg_uDIj zM#LB~a;~}dcW%k^oc*n}=FFeS_|M45od52>_ec2QhlOvSzrp9PpZL>%`u_s>bCvk- z{=t8V|MVw6*j?R7Rz>p^3rc?TmX*KC~DKJ^CF2kmNogR8b9jNX-5bk3zK4_a! z?BBdXXJ*f8wI(aBQW6!+7ry~DAt)SYzX9gh7G<(K#*Vxx4+}bFJ1ujjGu|dkr$6Z+ z$s4+4)VW>(PF|3%IFO2SK6XKT`+^f3uQ-N5LO zi-n*@JRGp7NgU||)Yk5WC!Q_)@~?O@X9m+MaCf~}hl_vlYLBn&-0AsvefGsQ8vO>& z!$@5!QfTt{cr9}6?;-5xtEc={LodLse6cpeu=>N;kR zb&p#mt9~O2t$%vTRjRlq+kBst7DJBld0-_5aWbp5O>!2zD+swS)Rv5d<;`?3)bnx- z0n#6(u1XiA_;xasrXSkC)OQ9gs{D-YnhjPV0lv1ICC(7#yxtw!$ObI%Ou%{*XU<}6 z)?#z5_cF}y-z>C1^+TSdKQqb@Y4%;g>c+ii&s=T5=`N7*n_hwO{SmTDdh4TbM%`KX zEmtZ;C(86_$DVaZ&o#oV#-7D#3F9R&qM11P+yaop15|qxzVXnHbSv`UiV1B_4%57{ zJ(R_(7bdV(>3+)sy9iqZ5IgI|2Z+kN%ECi%i`;Nd%MBNFm-t4zVFFmKzftdxZu84+(wLR29_f3ha=KoVV%^NgNTausb3%N^#wY5HNzU@C&H0hN_FC^iUCtjRp-(4R93dnn{L@NW-)GAa4u}@f#JO&leVk)+sLwU z#XuWG-^M?);;E2XE>CilZgpma8Q7C-3#})b&~787OFK&GB2?{BO*04O}J-%L}14Qk8i!z=>Y&6nX8@O z<{dE?wRWD{ZX|$Y;4UYHf~c|fSzCR(o(sp z)UMHLpM<-XX!wsYF)*>FU6)s_&Mr)_k20UAbAW!pV}IiLtAB#u|M8dj{Xh95{MY~O z|A2q+-)#KLfBuj05C7r+ihuHd{@?iD|F{1MfBKJsKmI#^j9>okKgQqrPyQqP{lE9` z<3ITO{~><(#h>8kzq9a*-vjWM{|x(Ae+Irc{@^%USs$4v2x!ZkPt-ZK49nEg zNp)Q}`(Ja}eZr4%Jm-xCF+8DJN#jV{tjtK{(4)@qS*H@0G1wv>vYg03ryA2ZnywA( z$?$dmi02=qjdA59A<@Wy8E-wUQd3=z+11L9X_<}e#WM1nWxe?2D{yWQg=0(#@*ryZ zT682hE+6ZRVT_mI*m)g5@X$u`xPota!mhO6YO^xzE_j(iSX~LZ_1kuP@eOY+Q<)tr zB3~xPVQF0PT#K;nT%H~k0N?mYTc$-7ttk6cbz#zZ6OT_@p{M^U0KTwlcSi2r%8j0X zQCGdZH|*cHTX!%!zkb!mYrluBjT44T-0LR+>OEYGI7xp(Q!FD}G&V7j|+Hh5igD;w6hSktelFPkP=D>^nDWwU)vJKByr$YogtQ z0`yy@6FifIzOeQ9s^<#O7{qzxNSY0qGhZfyaDri_uDF#d54e~W zrDMX}ClJgu0)1~0W3=_muqxV6J&ylP{fQ11GwZ~2NwXK7Q^B?)TLx5p;-1o#-PiG@ zaUY0_3T+x@BK3ASRNw=n_xQFkF0!1Pr=(VqIXiVGYbn*YY#tJP!_ugAGpy`^CY|UP z?8B$J9i&6?J#&%xstGT@^29?NUr6{_mSI42WpS1-I3@zI(#+&CKjpLESUyw*fCnBe zWTO~4j)MM1uiRdyUApYc+rDm8>v5gDV$L(M1qh(ZDo8mDY;BQtaoD(7Bm(`7V&D;5 zW7rEkK&^uE<^uZc0yIy%lM=%$iFtdd`4Sup12R;DOgE&2%8kfAHjQO%Ov=1)tg=u$ zq*AtPf;`KdEuDQ7ah?l`84|OV${!ALNJS{K`&sChq+~I+>ma9N7eVrI#aDy?d(W63=eZ`0O+;%^jXq6~m%wtV(=(@_`P!RwRYo zn(eqvUD6X_3O`$IQRlLs7%~@4Lwh&@$Y4?7D_Ch@Oh!}lAgW+KYqjtZwe8XD1gI(f zkZ=Vv0Vv(H%PK&dq~CenEfPwpW!UoxWLnV~&%de58=ax!offvQ=lENH@OSa= z{K?VPrnV(d=7iJL@FU({YS#>}=XT+EWXB)%MD%t>26+NWn30I+(S7Wu};;Al|0G)OoN%%K3n z0CB?`mwPTture39;hVq?4Q#N;XtRv9@BMnvhbb4lO(zGHX&By)^b3D(^^WKaYe z(8d|ql(8fYnGrREmyT_^1!ZcAQgPMFMaeasN(wE zbmIj#XS?1`b~|;CYbxg^9^jd^WoJ>$v)|s7^fNnXov6$fi502L&upKy>`kc5U~JTC z9_Rd^_0_r<~*cwHkh4a6r!5q@QjiHU`L18jurmd=A}HOn5|Hw`+!F*JiBGmGrCRM zTKPi}hid|)$xxM+$<=}a^|O!#KLC8TY)w$h)RyVmoHe?ga;qI3vw9T$0;kjO9vWoh zBR@Mx)bvh|`VmW!qh|yw+MJ9|xSm(6>&7(m%g3#*J9XSeB{iFd4;YP_s~#?5@DST4 zX1`xp5&G`(hk?%M;Xs?+S{TW+oUE(vg0@&C##UDoq(B@CfG1Y!nm|TPY!~`%T~QI% zEhohoc~Maimg+?Du{_wXx>XiZE2A(o5SR=Xvtv|RR2H6Tqd-J(A#kvrO)lbP$0+Tv zqVmIY;8>U6iKqjzA2?F7m5sCtN0r4j^s0bZV~qHcGd8KL8aEa2Gfo*SQ5ZDCLlZ|!N9Xs(s`YMbX0c|eq7RAL12 zn#0G;Zrg@njm+E^Onhf{iq{y&}^ohNdU$+89j*7(Fhuk@7#t^>R7So!9Hl zF{1Aq^_48IDKl`>$N|G8ICu-%JtQX_w{_y}f@}5!?oiA}=ceF|pDoz|vgt34lQyAt z6{sSAQ_T8{lB@F<7!(UI1T#G}ivR@TwKsv!nd7_s-p*>5X(DJe>| z38OME@6q&+&-BijCh}3%~>U`3bB?O^E+u zVP|a|Slmj+b)#pJ;5}6KSzJUNBz>wtM{kxOT{sk%V+GD&xU_&`A7)TAsqs>;s=e!M z>!3~l4qF}I{bk#nWS9)yTG1lkwB}<5j2o6I&?4DRr23`euf8+LW2rusuD|l!hDL`m z=ClVbe`J8Gk7G>M;8@u{!~yXEoU&yY?D2Y*=issj>2fDLu&=N(&Z|Zb%9dWM%8uM2 z;`pC-k1~a}d#<-y@VVm1^A=3gRWLGa*ha^k=0zI-h&k9?lRv9lU(>({D5$j1tNAG1 z5vzQuABv}y74Y$K_-_C%_HGQu)k3{mM2GQeG`_ZP-d1%VFGW3j;wN1fb8@}n<;$1N zTp(Ssf)Vf`gKweW0I9M`(u@OBb+msObjC5-Cu)*rwRKMIaH@ak+Xi9@sL{7PE;gGxi}No`|& zcSekivu6=$T(sZ-Ulp7vqkm3zx)lAmTVv>VHooj4Y}gK0)R*1d4N9nM*{eSYu|uF9e*gsy;&>Ch@O${}DdSnVaW zLUP#Y82*Tl87GI}dX5T^nL zYTP2{rIB?jfX4@z>!m5_N)yPw$n*D#0%uh1=DO28FE?i>ukCxGd?_Wl{i+e(TX(mw zfRiDvj}o`Vt);h%mT}`y-jsEI)A#Q4P1CRRip%%bhgbTk*fGvHKGWJxKQE;QRrB&s z0{T%#C~8H!CbCatR(g6S-=1JZ@L+-zX?H4?YT@4v&~hSk;@E94xa^5m3Pf8u4w^v$ zA%e?XG@i1BIPXG#BtYvMJ2VA*w?9DGP&dMIuxjLvM+SeOl=Bz2U*JBl5b+*Y7KyBQB z&&nPIjl9}{@gjPw9O-XJ45NYI=spPu<#;9hkl2wkHb(rtfgdYlL6ePVm5C=#dv?*u z-HL4X`J~46)|L)pt@Ib>eI5- z56tl2(N*n$^r(-&D;8rj(1B6xI0 z#cV19hDSZ$CP9A4?8yg%SDs3u^&uEyVr?Wa1-!Kn4GsuC{O}t(?8FKi34$oC{=wXw&+clrp@M zFMAB)jRv=BN55&~2-rpYWhQn`%Ce{O@eNSSw3c78q4Ro_MbE%qlJ|_Zc?Xa2EUiU`q&MTi@dknqR_8R5&|31T_ zlQmShti6E5$x{<5UpaFe0dPOy{t8Df5#u^!zf`fIe|hCWfO{Yg-SDP^{Ia6~Jg>Kp zF~wQ@O_!Rq;#Hg8)_A!!dXy>4ufx89_4YFD=40{7HcqnlRVNO2V0gS`Q1#an*q`O# zWJ-NWav^T1BPYOL{>(I~;JEaU)d8BAXN>epnQthf&EGGirJZRwY3NoN)Y4_u zUtl4kKUVxIAkTFr&9a9MgFw1(8-wvTaZ0DbgFF6R0Wx;j zjsV*rPK?+o?bI-6|2FHIai)%l#u<7-M|*`X!zoyzvV=CE>{szB17_sy?#J~XapR;} zy%cJOy>$AL=&YXT>|L*Vf1lOgygF14L5!Nt?9UVm@m(4Y4^Q!vO7NcBvCPPmx*RA*UR;donln=iV`D~i>GFlW~ zXjaSjg6W8qIVpTi=m-e88^G+&r~u;V^blvD?=#r8;csE%SyMcBZr~uDs8dl}`WnRD z$pbYvYTr?uNBYzEAQj0yQ-c0swoE?SCh+%K+_4jCT?dUv;E9;`MySQcR|NJNoRY`J zw;CL|gs)xk2W2|64e_L9Tqp`8c&0X{56>OCbmqO2P*+25K*kxNCJaky zM>6AWW6lXH1+|DUgHe_Y%wM3r#W^97KsTI`0qmtR$_gUj0qhK&>zPsWj7?nufZKQG zwdq#B8;od!)$s7`B$GB+(ZRai5m6r#k@Kj!6@ec7UkS_?V+0_7ZM6bi4(En4O!CrK zB<74pizqNfY)9#>XKRw#`H6!;6CIdY!;tjX;bSxU*6=2BPszw8qAw7(&TOBgmFh}7 zGwXPXzDo5auqT+pG0Iol(_WCzD7ON}f_wyh3&a=STS2YB#o=qC$OXJd(Shgr>|Uwh zfjq3LwM@em?2{r$I(QIn0+J>}th)fNn1~*PWdon4jKjw068&=TMOoZm#G7jC`|<}v zYinHU#|SX1EIIeT2ha5xbG&5Q)tE~eIv3uuMT47)FVn3$cSwzuPxRO2%ho|E? z*HZcK2PEC${Fs-&mQefb&pc&tSR0E~RYB zqP%e$r0$pB_q35uV71FAC%3b-;)%(waE0u*JPjpkQAb6zf^k7wOB6U?3&qa{b#vv6o!*{05yfpqx<8}>;T;y-f6wab{t z0SxirM)cifZEpr^{K{!d*)~0{PH$JRlYt)buNV>OM$wEB>6}XWJuK&xU6)KI!A5Yp zp6L$Zi?G-vXr5KTOWQXYoa|K{E@&O&@t~E^MI}~2+{*OXGOU>aoi9aQgW8~xZj=v) zg>c)7;A(4<-0tOSJfSTNHq-~V+Ihq1 zc~?j}8fO`}m`=E-hT<6qH&tJZao2PaI*P=3FRxFAL4>UvHTXKn93AmuRIj+r{@)jy zuYsW{@8j@=VF0sW2LL;;_DAt^PLLrtvvhdIPs^ZVwt1T|Z04hEB(|lqM@BBA*Wh?;Y%IxPQPmEpf2t@8#pzn57+C;V%=^KZ#`xa=-;lVm6 zdE;T>q8V-D$nZFsM?`cGLmWt8rCx49n99o^RW8vZx?LG`?$# zcHOU}R%RyAk4dfkYCf!>+lI2Wgi~h0S%4bM2;!uQ0U_#L&hSQcKe4gkhah_hqx4#- z4eI#B%Hplc*I+hH;E75sQE*<=n12Jzwpz{e)$u3TPSxQVQsg~`z-E3DMN`vPm0i@f zMuEk3&JPd1EH2=i<~HTA%RG^t2|73f(c6K!Q;C^Qc~KVmQe>c*dHk~ChpiA|E_&)I6>!e07=(+-n>+Q98T>4o&UP`jGj9nQSVC~KZ5{<}{ zL1WSP8;Mk|GzW*?=yJIsKH{)hZ~^#uP!0F%4h5fa>j~&dATM*doK5n;tqtZ-l%oVW z?pcYtIDn=vj&}3%sm{-SOyOO0<(Q@6i&u?$)vwoXUkyQm*$U1t?=DUFPf&ec_6ke9 z!u0}kw!S+Mcp*Rv!Tz@bQ#E{(vX{$XgB zt0tlbm!K9>W76mpDDjLH1|`DEusOSDkLGP30XwPKQVp3Mad11vQf-`jn-hvEHx3k- z&0g^mEY47Q@Z#)Lfj;V~5G;DjnbVsNf^bpK_)1=E zW{a7YBW@4Jq!%!wr@!21&Ol={kMN8#8nOdC`{D?(-$C2t8Lh6yCx_#LHxOwYHP;8Oq33G z?9p@XH%_Rc=UW_;+mH-AjV?;~1;YcWY?MZ@54>?pkB2s?brMCa?FTcW0iM1&87PIH zl5xguqWeqxPJAvrIyYH5OU|P@k!iyE!_Tfs-4XnQxfu z89>AyykU|!B)g_bv{f1Gw?@1t{8V>?TeqtG1Hg(krjzY0W_!UD?tIFW9$M;DWM_C3 z!pHI-UWI_p%Iy%zxE-nJ>O}fHIqzH-Y(lj%W5#s=ld-J!o7riv-3&wpl{^)T*+3lG z5zL|h03ZNKL_t(2{TOC=SA=;mf&YbCpHG^OF{dFPj)yNS> zEgUwTlRj;rm0F56q6LvKvMfcSS0%zlyKtw#4iz8yVApT)PEK92Rt9tg!?Po?JY$n% zCP+MY(}ROruq3=;yiH%&(B#3!Qjn#L6dmurB~qOGG%{$w5rdm-qHs@YHr~VFE!>bs zmYv6RNP~$38H1gN4lq)fKwfwuE|0Gz@}|J0x>h!?jgsMS`m66v?3Y#PH|6`r0W0xJ zJo%V`>ksuZT65Wx=s;lJf}W1s%R{!Q+c)^imw#XHzbO395Ik?6T4!{MmAEo6D8n1i z=Vx!>4IrL~_z+&QmCC%Ns~BEqYM3+Aj1C>tDrO=qVSSUaEe(&i#4g6a36xM>ghEl- zILk-25(Ose)iADEIUD6RV>{FI$P+R&hvKM}{19yp0pr$SKy3sao9s*o-cy%m^pHyO zP>^g2Ht0szt3q>Y+8#Zfe#cYhxOyWz*=TEn_vp5%pgiCsN6ye zNdwTvz@5t~w#*nce;q3c>qH}*9w>RmoFPE*82%pcs(QgFwmZuD_)~Q&2r{ymO1ZAO zlnyy90bu93uo7P8=>S3Ulcg)F*$oC?X5}n#@Lpj0a~PidmC)8z>aM(IQ&bxza@>Z& zY}|%vW_Hk4Hd}%97|+$FDwES#{oNJBrj_xDFa5yxb%%9$PqguycR<8>H}9$}yub3x zpNG}*ekMT4=X|=3dUx%--hI8|1{$72dA()|+`kV%9l8$i#FP&Vn*o@k=@d37S^R9B z7JW|#6}K&5rj1k*Hg<1!S{=L;pR^9$&8vJvq5Bk(oTy{Yqm+Fr!4yq`x`B3LYlkwk zZ>lWy#Ok$@wjqY9jAb#o8c?klbQ|;yj5aF*wI`(VN|w$Tu_$#U&I5Z#|70)REa^gK ztvnP{J{M`n)-bj&Q$l7BZb4(oAx@I6r1F)y8+Qx@PvEV`n-Ifj&MRSH0AWC$zYvKU zBu)Nj=L+e(dOk}JOKr$3)eB@8_*jj%>ozF%-&K&pb0h8QbA+As6ysau0Y}RmD*QBW zPM!tVdTG>dS1!Rrn*)#TlA*8302=KLvk`U=oRhLXDaA3)e}pktooCCS--}z?bknvWjvpBF66oMqp$&Lq40LkSx3N zG(3Fk6h?`r8MXwpAVc_Paf`$N7$kSOT8yreFx{*c8ZF9uOv(*aR6ZW#zx)$Qztm4eK94k}Qhwi0+)kVJyfCG>V%DRt<$jKNz7C>p5a zH#2oe50DPkFnuS)Eb0km=EGBfH#3bW;5|m2O=YeAdRC1JO7MwD_n2F`}8&~WnIOb(5 z9+|aw++>{hk9z^6HT3Ez-YBDs!J4ntcH&a&Yvp5Q;_~}id^*n8UM`KLm76xCe`tr^ zz!fidZeY4LeCeLH?pzm{Hq(E6acR`jqwgx^fRZmy?i*&a)T4kwn@7RuNm9L*Jj_|; zipB-VMs&UiCdN=G!n=<$dIL?TyA_YxCR5L7aBUx3PC)Jsfa(NzX4wRg3_KXj5_0bM zUn5{LXogYgkTeiH3ksv`yiEV5BYm!7U=$D?9U+>Eo6O5#gZH=8(8+DQZ33#Sl#|Y* zQ2OWM>awTxq7OBE)UBs9B4kL^*vR8m_k@)hJ$Ld@%9}FySdKxEnDR&9#F;uCA}*48b2&@OplwptPj7mQftXvijtM`|SwPJ-!BmnEZY-hzW$1SQ z2xfnUW!{jiX*JQo*vh`z7@IM;>@8TrAOpi|7N2thR#Q2JCuU@c;#58+p@^)vSZ59H z8$LDmp*H(7Q1be`;C`odX57x1b*-0D{o}3TmqTTZB%OnsS_be!;BhULy^SbjnujlB z92q%8GqPtPpbvaWo!wIlxo5@>51vjy_J34aDg$59%L^tZ5Y=Stlr{MYm@Fk;av6v+ zmh0~ooi5aIE@Q5Pde?*85cEKI3q#z$U$PEqKk*&qK73WTdUv6n6o~v%! z1Qytz7)@}jD%(f2im|k%GQfG@_PAbd*sbGP*uO8gzrHRqcRF_G7^?VJjb4n(SH%wa zz8WZwalB>>*|QhLKW(|n9obJWqEG6~TbKI2CWg}gMjazq= zh8YHk;X9_Cx;@(t#sC3waP<213(Ww?SyB4sg{R|MKX9BAM`_P+9d2AE(-Lg1zz_!y*$ZUOWU^lwDtDO+ItM>A{?nYv zBp(D0M?pHkLIQ$gTf8{5$}0pN85A*ebB)}N#t~Sg4w5stn=e^sGHZt~CfKZra0FI- zOqqT0b18>xhMhQHz{}QUUU@h5xf>NmF+Xr9o)n;^C)D^LNuOz=%;mEl#;ZSs)$ zA&;g<(LoJ$jZl33R78A3+UP*3yFEuhN4G^@%AjezkDcUe9LI7#3O`q1Kr& zY?h7y1HSZK*(J*|Qw6|YiA70KH!%vqQRx{+-Jl|M;l!!WGsqM&RO2|kl3IRpp5rE` zX^{#Rpz6M7y|>$06BOZgqhm3X_@IE=!n8Zp0JEAE^a?baNhwzb?``0V+$%#>??FJ!<2@8A{j)<>G}! zplS}As!xR@`o&~mB{1`xgNW0ZXS4Bf1o+NGy9s4coodm>DVg#oG)8`vpdP<(^ySOY^7URA>aW-6gcSck_s)7{0Iura zw%@!ooL&$wU=T-i@GjN!&ERS5*t^=o!gD_n&j$7bm~A+#;qOV{5j@ZcHO?^t6s-Qu z`zmDod8Y)9`W)0Yh1gnGFj&eZ0@(c;Z>F+ac26KCNMwVNbECjI*RT!?h?5#V7AZT8 zDL84zg1@2Y;077=QI6+<(p2V@jhOMkQj`@vU#gOF*aGJksb#pP(J+|2Zw^nvwJ=)X zLZdtUK=$ypn;d*Oqfbg5j%==%%M7yW_xO*jNR$D6;(Om-K@?okI$x;5;~p2G&>Ze3{b&bFct~D>nr%iMwq&?93Jb z?c=icM;W%LFP|^YCDbe&@{)mgsjxH&rTR!cHye=*%nWUM^F#k_gr|9@wCas8 zXZfq$X&KvnKxC2!3`<<$K6(C1Q|FZ{ve@Pw&)?m%>&|Xp=nzLS=Y=oY%j>=GISAI^ zUGsOQ1dgJxdhf^VlK1ZJIX9a2&c);YS7f+Y}Q{piwT%Od(sRg&dubA#_dV!h#r$sDo_JA*k|<^tI-$B9uf>DDsm zFFGWkm2paQG(42^LO$oGOMwI&qB6A^C~|IQW(_k`dKMeZHmR`%aRsVC4>4GqNf>=g zQQ#N>O+jI$4>;zIjV+k#?lt*>+ng*Aq!N>jSsS#*CyCjEa)_{c>I{p;MY9fcg!Cle z%T}|V)p|`BXdEJdhhe4;OYYHz$q2{X{X6$mBEW1(QER5#eam01+svR8ERB$NF+m@o!5^iVG!dpu3VvH-ZVMZ-^s^V3|5WOhde6Uye z)A~+cSX9C|_QSIcqJ^&v4Wm=7!kw!C3ub5xSG9XXe%>4wPk{2hP!WH(fG(*qH_ildWw*w#YiT(sT#Z%$@wl&9}?r(XmtJ zohpfw=B{&Y1JwC?>$cH2pF7m~S^>ZWUfn_PYtpT+fI$7l>yw{;S%=p)W;i!bE@S=e zI=ji2XvO?;ALRM-t{k!kZ)Kof_YQOF_Q(=C$FpLH#^Bt04jHWsUW^vLMCG zZN#iY_`)1h-s6@atIskDcy!>3SsTmubl?B_A?x4c4RVI%_lOlRA zYnBsD`cttSxb${YFw3@4Asp0B%$r<#{CdQ(cLorZuCqjo^@TN)>9USDKN9K`SpGv{|1H`ZIj_u?n6V(>R{ z$Ly@tzK5;6cyRZC$F#A_@Bz^1ENQhgJQKFAtO=B0GyQOl<}0H%z%zx)C)$&)(1(;K zxSfWuw*36n#@;<)h^Pq;psDp-cZ&Y|%Ky~X7aqSUVQ71Q#qsg|{^Pup$G4mQ@9y0d zi|-eCHE!>(3z&2FI*4mC>9^yBMZOP*%U8aXxl9GRMwNT)#9j*<%=)RP)l%orH2 z|F<(-xJb_Op?b4Tt2dQFuPWCN%f`%0zRkC?jJ{|)WtKp4v=Netc}5s>R6Wo~BjmXV zmfR(B31|b8I4ENm4fi!OujNjg&Q@a%8g^Ml^+oOEu$AKLjF_T1^-Fl^@urK>{mbt2%I#Mv=(!exS<=z>T zJicx%0{Q?FJQXjZPsj5RTVf6_M)q5YdV=262n#m2-lXp~jC;9krDPvYwbi}ccRj7J z*Ny&VnwM}KIsO8DJ@aGoqm=##6vRxamkmwB%lm)^>6L4d>XFtNaSNu zA4>&eb}K|VTEhp^-qjg!9z=iF@ecjDN!RP*pK#Q5SK8cQ0(Hk(NnPIOt1p7xe3^0X zkRXyM@5<;}kkSbNv8R^inlF8v*Ra7ANx#K)?cgFOZ#B@1!TT*Q7p$vRC63-y`|9`i z?!R6aC4;mvT`A1Z8#8c=h@Sw3X#HB&WnuWY4Bz$2tZfl`duc}PrSyq*u0H!kwcu}~ zswg;hY716OT{%aD>IfXQkvx>CGm>rD5?|S%v}L80pesUEhzf9V|Lc*3(%(HgE&(>h z9*z(1f=apbWG`ptyrw|7lVqu;hf!?&<&0epT$sXDyHv0ZlxR7r%_mF^>%QQ!pyhCn3R8j~$$KtU{xz+m##9U7Ev{f{N? zhL?@mm6Rz}AM4A4l^ea*P0AeeGW}dZKsN6Bpy}ey@&OCwZ*Zd_#qOav+=MsHFy#cH z!pgZ5LCF1W9Za<*jbx~MRoy252d;gnwn)i8z1b}V6Md4w4skXbb&NWB*?HXBGoBJ` z8g8^2a5$}Ozg@0&i;nDat9WG$5w4jM`a+Lim-zeTy2#A+y571>91Jr@OKEiYvioYXJcGYW3*0UA=K0SHDa7^4ygdlH_of=g#=z zyc$lza$+m&u0NegeaTVr!{9eIJJ&MjV%n%9e?V(@hMYjL*E zIWKdv0>C3C(}z4IYOT`s%)nb6fSRn`w)5F?ZCO#pn?}PsmHtM}QzEop^!|EnA-{Tl zO@mAzeP22zXh1>*>Psvuwoe<+!=HIpOX5O@Z2y4^GIzR?f|krif-pCX=mWF~GJOdf zCbNt*87EARnclio`ZvaR;o$bn4+xLh)1%KhwH#VimkuOC0<|a6$Dg49#KEw6+ITLU z1CtdKKuypnQ7wZ!!>5#A%AwMb*>H}+(%dZzCi?UgF8WRUo;VjGVR*KT!#SFPia5doFgZUH%}hrLzk?Q#_XB4cB*5cBj15XYCbLxScu6cLqzkI~CtD8PG~q+hV+s}%f_z-+Ba zXloUNJrg|}qOdIhN(*#l89A{cr(UAk_sMi}osBjnd(z){l3K~Lz5TGJQ)3^m*7lli zYsWDb+(N_lO-FESq5~`ooko=W0FH<2S|T z90x zpD%ZK?_KAi@qW?tn4N1|$Ds2qi0|7zc`|Rl9qn9(;kGs|U+!DD=*=$%J(KsY89?BH zz>jz~UzN|ipHkD4Im2>eJ)3i7Lkz!0C6-Bz zC^gjK$k6;S`r)iCaa@*}iqj9`{AL1D69StgjyYp(!{#M6y0FoX>f@%a&cL#O`=OPR zl!ICr^*w!8%a+}n)Ta%XEmW0#?9n9Y);c#l^mpQ$w#c{;JWQJTLkd2bW{TuIG1N}J zz;ucz3>V~a+7gYK+sD8V*GBFH_79>>BfCD3~(O0vz?m z-qfPybq}u?xTQnBM_|rlq~vhbPCgG=y$iLU!js(H*Ajb~569ox9coULkbto3@^eaQ zJgF#>ZKN{OUCU{HkQl$r`c#mCbv)B1t!_7(8S`R{1)YE6w2+eXEU6s4Yzu19SK>=h zc+Y)#hnp28AZ(k%&cPQDnj_Lk5jP%iNhc25AkDfAZ4l|krd9y4vgTV0r~m40HojcZ zgwf6CsPJ(cqZljoSQ>aGQgAvKN)lkPK}xEAY7#T|Wr$$yzIbAB+#!q~fZ|+~7y}k3DvMz7OvpCC*blm{rra8}^h!6g24->}2cleO-8$5&L&GEor~^7r)PDYO+CPzaYE@B2k^r^>2nGofV9IqhVc9Nkf|0@-nM8f%{5&R_ z)MXrSKu{ z-V|lc#G>jOALOOVX)z6lH}?#;6WE1T;}~R$Lw4$cGRj<^0yy@B3!Hj6^2!bTEJtc1 zu%Dj;h{=X;KOp+=jZwU{jjtxaw(NQtirNbc4MxAy@E7-A?d=P=HzxVcDt^_qnz0B_(EJ6-rT^VurmiOdhg_MDchNSZ7Jt#ip*{Tf}8 zJ&9)EW7u!+8ivF(8zX4PwxRIc_st3*2gi0|$_uMCh>3`D=E{iuo>WzcAaT z*s5^rll%@4t=7#{Tg-f$jY^Y&QrSUcmy-34+?079m;;T={VrT>!|iC%)W5S8wlSDK zqSd&r9*DKc@rk3wlmg*s3nvTndU{d=F~MmDQHX~*WZJ_{H};SB%??J?)~*RPj)asg zUf_1xftB!98i${MR6N-fArB@R8;O4BS95&Kf_?yeQyg)5WCEFv4A9r=u;GmzAq^(* z2|Teo3kitz=$OKZqb15h^Hj&=8;kXFjY~E*CRhn;0G+x4(dk^=rjta2*-U9avf9Zo?;jpCet2~Jzfh00I*;IkbRD%@Vy#W3FI14 zmP!uHf-l?5iCXK;x{VL_Zxhw#;0v?(=~+iT*6cPmN&y{5)C5;5deEfPMT2s|cK6uQ z`jCFZsa~*p7lW6(cp@y90qi}iRW3P%Z|K(56MAjrYaqbtG+^Zq=LD}zUzX22%7|mx zfqA=JGx%~o0V)zb2)%`4#vQMC_|7HTI8t(+yfk4nn}yzs`V*082!Ap-)((}(7n)EJ z*|X-?+Vfg=zPKM6FaP3x6aLib4i|G)wY% z7Nn7n(p9#4LuI6Z1Qoz$kY_i~2ae6vio!Oq+_ob<=Qy^UuaA(Vd9>$*+pjE6KqqX5p83841z(|9$;OEH>K9a}nz$?&C! zH}|r$omRj~ktGecP2gIw`d(Neqn~M89tAO{|7%p9k!5~rn-3Ae0pzr=tQXjr8#bk` z=JY2%NHdyoft|=oJyt+SYHprsMOl2~tE>c-4J{~}>d;3$8Sr)#jJV=~;|}Cr(+2zS z)L_#4z_DkJu|Gy{S~D~b70khOL(ppM32m38Q`GEI3r;kY7kB{FxjfBdWHF~97ZkMW z69a47s;i@i&{AHxqQpzvD#OyqjVGu)>2q-{C)r3R%OCURIug*bx0-u4&6ip2l|!mbf?kd_VxkqG#Ibpq>a^XRmNMG=l79;;-ckrVPV~ymRy4W+Lz`+ z^|`s=yRs%PSrglB>F7Ey4=wiuFDFqjg4%*$B-?)1R#BH@50m)_f_L-8j-5MtI;3 zh%idnuXx}QD1S*$x5k?gATv(Az8Vw2uwcbd%}&;hZTxi3BO2j$Z5(H^HY;aNb|Q0t z_?`nkS1?4>X1IoWU7@VPtn`w-wacj=Wk)NoiCeA`%ykSKb&Ye{nB^);lb7uJNgM*q z@+p4jE)0T zsX<@0>CpCo`KBEl9Fi388%=JJLf-=AB_EanzGC5l7E)U@JnR*H7z>c*N*%2*erH1! zI1X}l1TngdfRvq|8K?uE0`q3ED;9|Jw0LT_Q$9p$90};HNx_MSk1hInyv8**VO!*( ziLPs*(Z|_-7&Fl;pp)Y}6SpK2th{I{L`k#`<2OS)>E!J#(jRiB*rzf~fMd=z6ZkBp z5@+(L_G5No`nVM0VxZn_8<2tEIY8hzo30G-D9ijh#zRvR*+zQ;w@*CDa2zY8U9ZRW zU~^G{BhfOgJEIp5244Vz^b8z^M&NP+kY(u9Ci)#P?fe#;sUi9}XdWWR!CYFkgtE+r zdPaQVj55LwP88$yc0U|b?*-;-da(hQirW7a$vD3#T4B#Qd@jOVUNSyOCyg4Os|3hdp%Mk;~@zC!RN5rPJRO36FS=4dLG z*8k$4Y;M)$tb-)P-w^;a-Y|tU;Dr5ga(=16Ni5+aatjDk4E0+^p8*U7khk?3R-Zy8 z07r2Kz;knEr4CcaQ#Zq!Q&IL~tG7O(_Cu64CgOdmtis7kLu~jwr85`uWV#;LHp4P5 zND_V|bas%ktZba@l1AI{?U_3aSj>&#)UeYU3@^iWW^fK8y3AiO`9dB;%-o10J8ciH z1aIRSOiQ2oFNVhTug>P_c5`StjtpgxbxfY(#M|frlL4NcM2D9!d%(?2f*W`b;(0o@ zMemcgixbyFA8_!Obx;K}Ng^sW=PmombYnmP=z^msf}(r(M-N#+CdzLAX|Fe%=Xn)I zpR2A(*C8DgG&ZO)R=Rlo{s5jSP{+aGE=CXHxt$|wOa};;Ug-6DxotOGYQ9^~?-@P6 z&Z=Rdch5=hJn!8W^|n%9&(c+9+r#5|9>whDJr<5)H<`=ta5N>Uk+$7Qdt!jT0dYv( zeDbUb?Y8tA#o(QCTZiQ789GKvTbHPrw ztyzs}l#rQr$bm6Cp-i4FKSxLr#TVPs?QD+bT8og@$NnZ14NxcAwNvSop#8We7*S5 zrj02cjFU1_o0ZMcM+L}tj$*bn#a8o)IxuREoEX^Tr>;>9SIiy0DSx}uqW}RTrUMu3 zkA9h61k)I~`X2MMU|J3LPAf~h!$r)7>+s=9{|GM}L*#5pn}VHwp+nN(WAmmF~o`ry6Ej)gdqnPfIW|}bWJF@HUuj;_<|qO z;;?-=(>n1XPz(1xUi#3s_}>edp`hYE4#b^n#=s5(STVuj#uGDqw7O3oC4gQ22_SV= z23&wGL;d22JJ0H#C(d4qeKC-iG8bOD>+10H4j69Q-}?@#h-fFI@(Rs7e$=& zE3V^+H+}wO8{pCpXw{hf5W|FWZO@O>p1tW~wt0>#p3j1UPQ&7nWa48}pP6yyPi5siZ9E~ok3-XlWj&>yatwsYR(iU< zBPk{Uy%j4to|N*PiL^DM1Dta{!(nh)%Tv74>U6L!SXY@$2dRukq^;ozj$__3`oy#m zl&|czq)5GfLNCK0&Q&A_zX9m%9S?pTS#JgBtjXtmGV?CbSxbhb7oPO7+I>y*s36{y zC0y#lvYBW{rFx1E%D_o;48gi-gL zWws?Oje{`fz_f}Fxz_HBGiV*QB7l4#kMn)FFvHAf(`SBBT%9zhRr&6f_BTxp-uI>K zPigFcbo;{-_WPEpW8z)mOBL^s0SLFNR~vg#*WOl6!RvO6J4j#QdWRuv?O545K@2N> z%@(@rHI6eecKd$6M)08L)|Cn>23x1jZw6Xb_P}^N4%JNF%x<@`{ws*R@W8R0;${g| zu0)N~;OI4zf+Gz>T!&z=DZAI<(~*)2O7J~Z=fWAc*JRs*BTlFJOti%flcUM#VW13% z(~Uq*y9QNd);7-ZG?}72%^RXTvxL6F%(beG2iCleElZbA{*&RdF9vmJ&Je5d*?~Z* z%>a444z{*Mi-v9?`;EZfeyLVvLy;$91I=^NLB>oxgNZOka}LL|6a5x2e}mTKr$zf+ z4BluwsJtkiDs)O8pEioK0(mm;*hgTLaO-?sWrPy{sV!M&-u+~DQRc`io}3zO%M%Mb zfrSrb&isij?gb#Sx2L~`Yf}GQZ~AqyosgK{6`V#C47qF5`l>%qaw;@@`_0B@S6uA? z?N1yD7KCj9+A0uQ)scw>q83FqCe6_OlZOQHu+Xzw(h67yE0=L<9946*miY zrCuT{k}4#2fTJ>>C!#9@Q-Dn1q>YX;bXv(+cGvOyGM}JcvdktRcKe9?ELUeVw!%0v zZQ86f3`fTQNbcw)&NIl~?7z8MnLa1_2M#`qIhIrQs$pJ@M+QOUN5)JWcaN!@r*+_F zXQi|T0f8sm4l*nTd1n#Z@ixj%@x z+`j4Jdfyf7`wDH?BxqkhXJ@R5y}`)j{3I1Bt{F8+g=;B4lVEBbXHQs$4DE@;FxoTTw!a ztXItSTb47&U=S~+JeYDmij{`Wlr2+4kHdgtaPQG=R|Kqkyr%RH@fU{oET6FP0|1_* z1jWznd!HFF?8`H5wtZK*&@C=t9Q>ozLenVNo z>f~??C~vbh<7~@hQ6vjny$WOJo4}fX>QH4nBKU^HDkzp zz6_r(q;8;F9`;WB=DC57+76HbJR|T>;Mt>RGvZq_VBRi=*!OHEbL=fWKC-zQ!|1WoO0u(7f86TeW;~KpkE7~6-x4B3D{dG|LCF@r5?L{Y(WWhki<=i zExr&IZOdflDBGav!?qEU+o&eo`{R~4;+43pKuYAym`|SAf;E|gqXoL=>kh_`uE9Zt zQk{Xw%1q{~>$AUu^Q4@SP~FZu#|T>T z&yZDZUF(cg)Hq4Kk*vw3;+8lb4a2b%54XI-4=iY&+T@I>N3LQL$ukDuo>hd-{ugBe(9*lQfE6bFG$g31Tr-4Yh;?Q zi=pPSm$4|I6OHeO5ie(5gh2)wKsrCG4^&$zKTPaF={5hAc8l$ZXA-4ox{pVcA19^F zY$*={HO?1x9sf?-Xi5fk?#2r2_HPq2E-ox?^lSYZhoq74$o7eT8i#=9Kg{+iUQ6)x z=`JX=F^T4}W=9xr2zJW&ZayX4Ic11@&6OI+tJ6hV1;nN zlOSS{$VZv!ZPZ|5)EjQoA%X9C4O!!6M}s7WhiNj3;shYFkVx4*BT7FrFgC z3z9SroKBe!FnnyasuB$PX(ByE=XYWbb?$IDo2P;R20-F?qb5YbOeKdKJ|G-~Wc^tw zkb+8jM27;3Qe;jF!JMPue4_2q+e0C--_|^C#*y>9@DR|sP|Ct-T<#`_<6KS+zq|3Gfwb)aNgZasi1|51=9!ci z%f`UN=h0(Y04FX3*BXbwU*+yN#_H90(y;4F=$2r(&oW~cO^-?Z--VXRlN%iIGADl2 zO-3tT3C!UThC>hDQT7ysyUH(V>E#<{@)7xcov1ipbq~`QSDQo}ZQ1U!qvXqMd|ZM` zD=`7z1Scb$^c_J-^821(*sNfgFumxBC-4K1`GmNUdW+l6WCz9yJ2o8!$Aj3LBnSA6+VeRkN+1uMZ>wpV(O2&zR}#l;kV3m$D(KKPIr_7-AL& z@iE~G_-zDcdyfU=n5o}=a$A@$LeEG?UOo68%J1ls5s1xsUk)JX;BEjNPExxOsa*>Z zqwxi6+tmP2hdieddI>u5Hg^}u?`eC`!H_Z~W>H&lh00r7T&TB}7_=F`ufELT%EK@- z7E~5aPJk{@yFL^siOC%Db{6L|lIkg2-a~?C%+~z2_=ax)W1H0B(sIdwO;fLR31RC| zHQnYQY0lS4qiXh|7-W+e&>7pE$zVThJZBK3S~|~xdNi!0fo3z&c03^57giT>&Q9t5rvuBfZ+2_}@jIO`IP_wUHmtiq{(a zk55Bjb8NaVW^>`}(W#WrNas-irEuxH2Rc3@hoakWYQAy!jZ0+n7EAX5SO@QXS-( zp}tXb6Xo4O!I}u$SrCD}M&+?=cE9x7jzg%k_N4;0(9Ck(gdcXj8TiDMbA7Hr4S7^J zogj~fxom~w$V95n`3n0;3siNd324{DHJUt(0s(QKdhCk#e8TUSb%kS{yQ<~!Yub3# zL3wxgDC$qI`6$*xOxd{W{qduO?Dl;%t2?Q(7Yk{3zptrZFV(v=a0O`$ zcKu3w;wi=2J#$H)9>f#t}68odG1Q8>&|h{U&o6yg{)TU~`OwGS?pMWLGm(>4Hz*Sx~a zG14G)`F*DCAABC(ukncLQ&TqYaXf5~`mnQ&YOX}OGqv9p$sSyBEXTMeFjjI?{hLL( z^qqr`-mp6X9h?f^$F|(~xshW1Zfg#>Fj)d-Tcp#;f$R1_V@gyqJI{-EKv&JUVx!T` z8S_hWRMQ|kU}IT=3T&}0?He#&>y%)hS`n^92W0o>jQzkrjb_y?HO4k3@TER^ko(~r zSbK7YfHQ0&3x(a=GPl()Qgh<=#q~V{5wAbrm?ksvgzwUL>-VP4O$%r!+YoDeT-du)>)IS(IaC6<>zo*V>9{+D$^J-u$bG}&IvJsB!Hzh?Upsh&os6|56_;pBa5BzcS-h&~RCNFknjk+m~k z=0yQy?NvG_*-OtnWgkYRE7Jt0CtizaGb$kPY+4RoQ@gDJbTET9I(jD!j&`5P7s~_8 z2BV(i_Wg{c1!~nlde?Cpq(m5g(HS+mT)0T-4F*vLcg%L`@kTupK4^-pt-|TN@eU4I zq`W?HWe&g48ZXnb?06#LfmpTIf@WjWcDaktEXPZAu{$`t^rO`)yZF>e_ufS(Z?Gpj4Im!RB z$Ys|>SG-Xfs%P}@`o1Q3Y=^pO@SKp|6uqpJdsmrkKh8>Tx_nK)Jg)=CwTB5W&t3#ZXR57j2C31d`d@|?^i=Sx{r zwEpU(2XTe9x9lXh?KED)>oJIN0nG9Dw`O*66ZV&(a%Ow1TR&OT%6R$ z%1)w_WqGS^fUREoM4nN8qSNf8f*3L!##6*4mACjL4!Vt0=HN1527OQ#W+Zub3wkB_ zjHVk-WwdVKAU=PC*je^sNo94G!HD1L>FuGa)az=E zU4G%_3kM<(xJvzcrV!0Db2dhW4~I?gi2<3C)6g6vE~DmL3kD+qEwE0O2klhr(xli{ zzx!Ak4}+;NGMPH_nS1LHXX>SMEx2t*W~+=IK?i9P&k0avWiau4C1ztWE0h6?-OhW> zZ){vdC=&i+g|KgdIz)J{PK4kah_TESU^bQBf7bV@%9?39dnIz)qBX}ip>)!Ss82-a zT|rrD**4=`;B-9F4tR)S`kJkmW$z|S}zH-Um9Y4oZE_hE^$41qVki~ zaoFxeXUnuOa)r2MBBAW(gL31~#@xUZVz$m#30^xKS9#0>GGZp;#ws)b56(LXYp;+p zV#+zh;+%m3%GI&Y#9!q!^QHpZxDyy9Bml6s-WEh7+;$(I!_BdfDQ?#@PB*)74_m7 zM2RN@OUi_b3w&4g1Aq8>UF7y!fAI3ASyp-1EgLxskSTEl-QGi+_HWp&SAF;u7}MI> zIuk^G(&bfYXu}q=FV}s_x|`!SZC~%*Jd4Zc;G~T37RKVJ6nkM~D~qv?*~mJZj56nJ(Rd$to2E9c3iW z$h#)Gb39`SZ%;(iiC`Hc$E3cU19nWsnJ|TZVG`0y87k~|09W7~-Hrk|qpJok9%Kow zYRH}*K?T+!4mE)`7&D=*Lfy9~;E+#d_}(Cgv0o+ahw=@jX9^0 zeMs-cTEMplA|E};*`ndzX$gxqV34QqY9mcWvnKy;l)(ezx z4d@kCV~f{895=^y-;XTj>jh9f^~x8#vCK;-D@mQJ4Ge><<<92~x7XdX$@gIEY9oP6 zp0@)0t>6CxU@h#=lF#+{8Ge)B@XUq42P6l8GUgNjquLa_%>@kb$Zk+S?!k?T@TM;4 zvLzN~mt+^H-8Z;N=g|0J^i(#HV}EE@6aAr2F5U$m?Nd~i2lWK&G8i5PL$+LJy9#Y- zqcUD9381q@VzO{tA4FvfsJ&97tCJ0u^zh6hO-G@3fwZknY_u0uu!vEq_Fdm!xvL>- zotKfay?kR>_{2k7BN*(XT#ZiP0zziz1?9D#ShHj!fIflBc)96eRCF10A!jbE7C_rx zkiu17@1HXaB%&v2BrKp!G?>boOs zMaNR<_plp&p^a|X60mc5FbvaWc4VD7LmctTbLxBK8jqO@NLFo_+{QB)p1Q=#W-x(# zHnay1_}VR_=0{eUmWKy0G>P$#DR_iQ^~hP4IdwW=R*62KFQ^7UM_a}yP-lWPuDJt3 z0vwp#8-)}tTKWW^dvtlM1{|m2pX5h9bNaWhrmUy2ds;}S;pa<6iUL}MN6M<|Zg4vy zbpDkVUIF>VM<&sbwDA(c@m}*>k!$e009*0xF)#y(^UaUn1y-+a|M2kxRwfpB&d6Yt z*O^I{$M-v@Qh0g$1Sg_i+Qq99y48W#9xPQmUz@-Sw5}S5r(H>bJb%&1*6*e7 zwCCRVQN%{@5|oIah?9}exD>lLEAN`5pog5#^ZJ-zy%3^y001BWNkl;|Lqm;+#I9HF`k^P2eGlb^T zL9?wWQUHA~fSQC_778cVjO>YD4X09u0I=KFa)NPk9+(V`xG=mMOXFg7Qv<0dmLf~q zYK6pP^zo2F3Ub!%sTa+9}k zO&{+Xh?{|*zkZT!i@Tp^0Q$wIANupPmtrl~t-r-3-Z@F_ezhOo{D*(|hxoi3$n=t7)~7n8GaCN zXUn@Umyn-)qK!EiYgBjNKQen-ewmHI33r#QK1G@SSHXgfh1mecGlrz;;!3$_JoIyA zfRqlTq!BOK0W@Xio8+c~A`C<^fI?WtFE>=xtH&+diW;M0TH8hm%@vjcd4x5^KU8AO zMByAX8Xp=_EGWd*bywp*{LGwK!f)6_hZ|{$1<@$kQfPrmb3_o=uJO2lKijjif#$)@ zL$?$~g-DoxDl7w?yvC)Zi~p@(67XEKk@PL zf&cVB|IhHJ|MbtW){pr7^}oiy4d8$LpZ^#9`Jeqi_!}P!zux0 zAa}RXKFQelGx<^rt~%Yj+Yx0$Fwn+pi%wc=4G0&0sHMJ;o7;)zywhIisccW*AqR(_&Bnf zmcdrcn92&^j!gFvGokZx3ccCNZdMrSMv)=JFQ#4CAKRSZ#V|Ox&((aR1111+K#jiv z9p+8ow^wcB%U1+OW}Rh8}Ozv-aIxjjwOaNV%v8vf-X^<7qzct`v&fF9}D zoO^%~@xU*C5BSr6{ucm%wSL6&+h;3#)JkMM5l{QO07ffyU-bwHOp5QjpSg6S-qBWngH(j2EAl{Q;3 zdn3)bv@=xYoG#HL;-Hz~Q|)lE!W7Y9AW@3dJs(-94eabp!!&xDLT!&{GL(AUX5a~v zz?KI_UK!ktQKIsob=<8VEJy`Rx)y&wQJD_977nBCR~#vtm~Bi4VdqNJ>are7;U4;K zw)n=`LSdc%K)W$rprU~SyKSqnvE>4Ru_O#-Y-G$J zfyAKU&F|fN&(7!{F=S-!z0bXmqW;u+d#(5GIcMh(85tQ785t2dIGsol7E%S)@<)(& zRWVP~2-t>Bb@>>topo-aQsIP}!UAnY94t1$g-scMUh4d#5&9`}I;`3O0RA7o9 z7;eCrdWd# zmG(1>-$_dywsVmEU9RMyi)}5L1D2E5RX-O>Fi(6`W72QVwoI;)v%?JY8c~yw?)9Y2 z63XNp-B0$R>zo5#Z2Y$3gBK19%)&}CJcJ1p)dzo4kZT!?;xT0uQj8^4#vC@@B+X}^ zc!iG{C2B;!+xWQ9Leh5GcZK#8ugPd)kG_GnkxEP3EQ!~8DOF58!I)G8p)D8K zfsl>K4O%G1Noadz7RdKaln8mzg9AlLZcY)O%?sxQz@h=KL>HGEdb$rjuUXF(j9l~sNj*};k;Nqu010VhU z-^P)ze;w!S0ajD?oI4RV`)6TMri1yvvYwo&m^}6aD(Hs1(6H)`1&NddiQ=Lq3(J<8 z>xpbr-v|?utNJ4Al{&_~+&S9!6GX+3(uKjAF2g|OrR|%43XXXJ_iix`^Ur`^AzmHm z=|D*josE?JfKZJLFnpjKjvEh*-bh}@K9VhLEtgAKVsZr|IP!)i=5Ag-16Lf|R~ zvohJHGct5cOwDPC(vOWvt;QDX=n8@L3FwuU@J7t=mlW}43^PNW&1qJqCHM|(%5Xud z|LWWl0Pe|e19taEgE2zk{S*%+3iBJ+fnRh|_?P2QS)D9TrBm~6pUr`DvA}!&_zwX9 z^OYHp7!MwN0FS-wiFnvK53>>Z{{wT?7_)%_9F_RCC|9pa2_MKbXOgYtkQq5kXm?BL~Bi|78ug;V{3hC0hOL!(a;)%*GqJv>kN> zCjm1&84UzOhR-iMKD?~K6Wtl(KbLE9epP@*Uf~9uQm&9j;J>C!zW#VxS9 z;L&x{(!RrE^uhria{6-k8hxv{_YhpEF`T9Bympj-0lG%GFyIQFR#;H*rqaTh%Q~nU zup_QqaAR#MU*hx$dZ|&H4-7seC0l}|_;hSs2t0q+ta|s!y0-qy*Lz^Mc zN?3{V|FUN^k0}O4&uAwq!I^n@xZjE8iZh1c;=!bs-_s>^-1uJR8@lfzD6aKA$2l^? zwTUig?<(VokWyA7nwn&&Lk}|%k|R7p5B#0B6gy;NGeelobv&XbFq;{MN*mPqZ|2KY z+7aC%N?2zmNMQ6Z-<+~0%)^Y;2-a78$xVX{tj^Z3JMG3he&=mCdH6V1R(D}G>+q>h zej4BVecy*Gueu5V(2;r8v*TgxY|Rlh@o3L*8G?pSjyD%KD~-?z>kR-XB~VJ}x(-iz z;uE~kf`Cme_2Ezc9d_kSoI9UkGXpCmSGUjD+}dh<#?89Z4wt=!=wQNN>>?7`E|9O` zL{`2?NAreAD9qIqC$@!4kdzdrmzthniZ2B=O>m$MAJJ>ZFa2P6awgAFWMgLdr5xsY zl$!PkPJaQO0%ydF&ruN2cA(|AU4^->gqH9=^rj~UU8_vEwWkTJj69MY%$YGPHRHFz zBvla10Ow<6Wz;>Ox$7!HWcsA(Zmg3S^+UrGD}qdSbt7D)vGC8QIVgWbR8ki>PIczv z=AUE^EPT#r&kTvijuJsqAZR`4vI2M>+@YBfef%&7V6Unc_67?l@a`)Z1x)&e17XRM0Riu_ltIckehMZ-;J zrCwD4g#~RhkSXy%lP}vADS{}Q6Z;IbXnk2zRkCKl zlcmRn7~6}Wf=hkQ<|RJ?tREd`3R1knX%f|-FhjDvK(Ei5jF zak@8;FL*-YRPC>1%;o{5^Je@ph#%jp=;HRfESP*BSaSE8ZWawbC=KW#S>d8o;meFt z#I?7QRWL)RkCRFOnR%3nfltTf#zLWz?7D%sEVxN>tKNe35Q!L>X09^dIi*Ugs9*(~6(RH2Ur)G?0O3UNah4!g=SD^Zu zxz!a3K@n=XXZT)ts7%<}+PeOdFkfB6p@$yCb=N-~Klc5v#@~JF)7ZP8aPoM@76_Dq z1!R4s8Guf_g1EDTQ+9sH5W_Zw**DVeiK6vPcd-M? zMDUX(J9x6iRC$&p*=z?rLA+!jz^34yR#)B@*VW2 z^c5L{<+~viVaj=^BUvNnnk@Mq$@g|{U^9FZzzA-4ri8PdkdmB$sf&smYyem&+}P8i zqN9Sh4AGy!@EnWLE1wl#)vaJ$+GRj4eqp$UKH8J3{R*SFAG*R-kWfPX0%EKU8)xVr z1XPF7K}eRoM#AWlR(7VX3nmkRdtqz~By6T0m!3iRlfU=~0APK66&qV8uxnk`?)m4P zhxvStzF!DK8(^9SzlT)i_QwbL#M%UY;&h6qkl zA@5AYPJ=8Di8sXNUWXd%k^X#Og{}ywZZk3lW(&&-nK8!ykfEwD5#J~m##hZvMdw@u zg}XpEULZD~$rQ$jxFCEI7x=s%W2VuQ1`Zdw(iQ6YMmz`zH+agpypA`SecS`OFe6sZ zs2&?eG{_mgt=-Hel*Q&IDQs?N;y{e7u9FPc6m`uy6}yKM7Xgo^k9d;eG(e?2gz?9d z2r}i-aBAZs)bk$Z-i2*k$Wb^@#oW#1-|Dz@i}m!lw|EyDoyvMD?E=(WpA>Ly;|#P` ztp^iYHWx~NEhn%(<5Dy@Js$;67<{O-A5XQKGf0!M1)p4Cb6No^Vd*gFXFcq2Jm;*m z5sYV%#;Q38C4-<)7!qN(f9&F8=ts}7pM=>29GrnreI z;KUCVJBpIX@E*QSIra=2_Zo=4Ff~i2ru;|~1(5K0q&kN;RKq+an4AP6Ei}_Rtjj}s zE*%fxx8-BrJVS7}nul0#8LItIn(JT3%gR88Ly-g6m%ij>0D!H{9{nccF^_&E?!5JO z{LvrX0?I4cx3UjgCpXZgRcz%AIolu>4-6_vfC;P~{dNsC4acOoGt?5uL%W4G7=Aek zlFKq-v8?DSAyXzetSw5xhyfHwO%qLec+ALP&gcQz8))7;KSW^Ts?t_6{ljtwqFm_> zSU|V%ib#D#6bvBU6=_j6a~7T|?5m{cATDrZb#o+_O<51H z6@O&-Ej=b%vz4)5ATY-e*3afU;zwGf~USO8Q(6hd_rnHe^`Mf3> z$SBVpFq3-iD!r(Yv!2N5XFE0~NMtbf@7ssp`Q6{e$3FT|?3%A)w#YbnauW}q13&+k zo3VA`C@wpxY=^%Tfx2y`JGZ1FkpwK01Xl**xgjW&l=+K?~r>W{;Y?M*XF7KW3H z3!deDxA3*qs4C5E$;yxy8ucIBp9fBsOY0ARuV06C%q@b*U)Nnsauh!Wijt#j$IV4o z`$-+ptq9$B49}NggHj?g&nR0Y91RjEYNo9HFa~$iEH2aKT5)9n=DFa;9$ko3Z#>;@ z;&3&tm=)s*yefunu=Y=^`#$TJN*m@{IXWK!cNFS^P#b+Xv;n|E*}|OGb7)K@48hA% zXcu9eU7-ah$b@42h(yPQ#$z}Q=hCEg9&wfHEkrShYngERTwFnI#VDQFhTI*q3jPNC z!UZb|zO0VXbt}x`KV$q3vVJgy!topy6&Y~aZq|)71-v^g=1T5X2LM%@iUYqM*$`uN z){H#Py`6|SoE&foQQYm;9;Xx5Aq9GMZ9A2*I4yC&NAP}d*!=Cd*! zrgGX8jY$LctMrtMg6{=GS#FVycrt9^SqSqKD+YR^Fc%;&vdV9rf1_uo9q&8@T%>XW zu0~eZAH&cp4jqW#yvDR^X5fl~tzk8=RnwRR=|U}NJr<}QCqDXDxMc6ez#`%J#&PUUtDwG9&!1kX&%4ct34HBV&v>|E-+GnLS&jD=qA3pf zxd3XS55_9p&qCiTKesibd_lr!7@RcxD;oGs*VNF`3?REZ2^1a+V>V#xd(ttplbrSI!jy8|HZ<>$HSHxq-o?8u=&p1+sK1 z)m7;Uut=41Ex8&lOpYqfEo7?jYvH#UW|(7`-;|kFS_6&963Z`C3~yQ6BR?Fo@VnAu zTm{1FN!h9xCB?}@>l(an7!%AJt;!8&rEMai*KCJ*+DCz(Msll_Q3D~*tb0+J%!Hno zv7~n74A$F5=d(Gswl;C{E6kKcJaUi6}y@ak88 zZ|KP|v4o#ApKH#+E^6C?Y2>#_0kVuenl%pqa-XrbzK&fzFf zw@31_8j52)i{!nOk@_eak@mk*Cp2^T;UV;}svCL!AF_}(k8>|kDIcz`3GB1krlw|BFiN(3{WG6WR?I88! zP?t*r>>w56p|g$GWJjmCui&!s`aRia_4t~Bea@niLTaJ65Wz&c=cUkRD)U+$Lia%z+GhF~PQn5Sdl@bMle(*oadeuv`^K7{Z4iC@A+kGlvf z^ELF`8)-)TimzloEB(Jmg=yNerGVuB@3Q7C_02o&qvW2~<_7^17)<9?!CB zfgnE<)%cY82wqD;9u}t3OaM0~P@AK~D5nj8cgl(%a{+7#BFH2Timtrl!n7Q;!tjc* zj?2Pn=OLiCBESHLH{(pr;7@*n7~w2sY~Jlf98)m(#oPwbW3LMPF~j zetcmBBaF{ucpuiZ{HnA~A&aaw&?-T)f*P{CqjT3UUi z0~#$Kb%N244EXiwZN0#js4Br2`#9{JF!hXz%X{NDHi496rA!B)!wiY!!h^(CvV-vb z1VX1?3|-Y$0=uWW)whjxl%=GbuoRHlp@e(MUO@I&2{PBBXLpg+A{k!8#@*Vq11+Np z?=QIogPCelz(yQThYp=$jub-%02ADxD|?8fB39*q8Qx(u$#5@QpJFMSY$R0RGLDr% z=t!=Vx6mfBqf7pnj#ChKh5BU-;(g-#R;Y=H6FMZlu}tK!r&}R%{1hA&>L?~FgR_j+ zbL@a1xu=pt zg6!kS<#7~qi4rIgs7vV53`89=7za-r!a8QS^1RFOw|9LO2QI$?_k8hgJo>R0Vry%G zJ$v?nH#TwElb(zVFT4l9W=ANl$BtlB+BZeF1P@1 zf7{#e1FwB8Zn)t)aq_EMxc{qP#f{(fT>RY6{xteM>-hdxzXn%aa31bI4t(X{7LIN# zFi#0PJM z_Hb3a$`!(pf()@NrVNdjW$`A-T36R}ugr-l#&VjnM%8uP$iS>OuM(1L{j{Bus2b?Q z=F2@&U^=O~3={bvvJ-pI{Zt>Z%G}EbNwcA`pms_KpwCpiPulbuEOV8WeSO+9HF)fOB3l#x=${2)AzrKTNz@QeWE&=l}p907*naRL*$CvNr11JK=$00(`t< zZI1&s(9x-R=}qd!EWEGE51Lk@Zr%^zST@Ab;YTYkSG6CUIfV>Zi*Ot40P?d}t zm{RDvAfU#(3qD0AM+qJ#+GCJ2+>ilt5m%@3z@vPg+Nq5&7@q_b?^BX zgvu2&PIePQ=Rn>;{#B< z$Hd-hypxcJTvg=&imh{_>uN!`_mg(#F~7AC5EMu~s$5wM?URqyXjsQ+^W|j4F3;=& z0-48LU~=PJ!2ok`+h-J-)HNo_Hq9_-f>Q>@9B^$ncu}~WhbiDw*1q&-e56dB^cUAl z05#6B;l_E@(o$y44Q^}Mg*Sp`A^7A%C*)%@y0xy@%L4#c@o_UV>PW|rCWg|fF_8X&3?+@UX`t3knUgP!kSK-%PPwlIS1byO5)9-e9fXan9bYC*1sKmZHjy`UYHYl zW42lMKrT9?6l+4d0ho`DfNyj{3Ws{Vn9f8cqJkhEIFvP{i#yoPskNpWhH5sE)L7Y< zwdkHW76@aVWjQG3fP;!?dHS(K zF1-22-iS|p>Pz_k=l&DiaMO!%^&@s+v!COE&5UnsW-K-tJ&R6I7=Z}>%4=RX>K$}a ziD5ZvGa!sZ8LP?eaOqybi7xm=kVWrf5_OQ(=)$I0QbNy+P8FGyg($N!%`_9H2xUw& z0=CLJ0W@?>LX)zeCNqQ~T0+#gzv;7hy99)Y=Z-O1axY;}lJUa>R;#T5Og-sgxm^96Aakm`+P^Er zZd^eII?ifTQH6*Ylv6oW)4HYunh_=gNWC!bp0X-zfL#S>EY}t~AY&9JpyE%hj%0g4 z4>drwFUf44NdiRID`O*N<+)6wc}y*|o;7X8$7FM7aB07mpUU=s=2gT*NF8wIDzLJW zaP~amtOR`H_$L1N5B?A@`ng|6{`iOS|?C9JPX!m$@U{{^`8l8dpq*u;D` z_r*P>AU5ht_;F_{<=~;|zD9o=ktbF6)m)ajj;)>=q)NX5P-B_?c!L3e$qp#2z0!j< zR2f%Bo0*0@f-ybDp^~{A7r`J=lgLq$39a=OkaT8@>k*DE3_##To0XPa`h zAwXq^50_9jo~Gbb9!|;xY~$>>2y^Jf840L14i$XpX%jKX@gC~B>r<=9$?ui13E{OH zAJmv&hKLx||-ips?;O>&ZNR1 zo>C$hRp9d=>#1xUf|ecDK!DeAPcldDM~(U+5Q* zkTzmH=?{3b`3#{>s6Oj56_ND!LKa>PFj=QcPz?H{pcPg-% z*PR>m0*sD3M`YEeZ_of)>lG8#HIf_Ssd+mgL%fIQkXvH(x@XQVKmwrU@}mmdz%JYc{&a_3cs=SFru@> z>1x{?V|7#yyW%4LUvqd!6Ad(+ynd>V36wgaGA6wJw|)zkKl#ac?stDTzH;AJaPNKh z;aNA{h(CP)AK(xF^B>?he&*ld)vx>>TyyS~ILRA0mXG52<_R3#IEpQ7VTUFxLGg~-ReU?j4@Eh==RAv$0n)1s^eHS$m*8J8I)NJkwGLoEMH8LI|M zoA<7tYO{Ft>4u>X@|8_ixcb7COeFJ40Fd2tk`!)sHqvJTqx{gD&D2;y zM0yC#ZrBpI2@+rOX`*7L)w702g;uN$P;l8p=UxeLuS&9Oq89w8ik3|hZxT?dhzIC z@gKsh2YT_Y5*&&*)yixIU7BIub=bf6(O6IGSi?F#d)MFL|NgW0;zwTpdH}$+2cC|v zf9)ICwZ4k26Gwr(h5vB#pW=}hJQ97Mk%HIH(r3u7M%k}_4~1qzx2@`5n4y;(6D$*O z5P+`hz`4h{4?72M{gvOu4gcgi9C*YduxH<196o*&_kH;u9Ju}leCQp&jSs!!xAEE^ zeG{(zwhM9o1sCGdE3d>8&Of(OHmv)gB1Ki9QcYudYU-NMh_J@bb_r`cCWN}NUWADo zMKAUr>&CX(VeYE3Eeu`wY-&rIfY)HMXGE=Y*kYYR8(k5u;a!XK;DA49H=`IZTG%44 zwS$N8H@Dw~uio`(-0|7F@oT^MQviT#o^~yc965~C&2aXHvGG&$E_`W~xS}wOtDjUL+Ck5y z#TEuv)~X+usBk9S9R~QY?T49C(IfLuQ!7{?`MET)9%az5N z5Rp_7@@y<_l;LK`3b9Fj@6En*Z6^rO+KEglpb8jF>1bq}Td?$>ovxXoz^tpB5j}$J zG%m!$pbqO`pxL0;*V9r_5PkD%zmp6jC5ZMT<6-lM^e`Hr;EqFI;di6%xUp!B27br1 za-z6~10JQNhC4Yk3QDV8r=9|wtaIbbu;r|Qe^kaBQQ!zklwiLpEX;45$ChK-?$_{a za{)7~*>n&pV;>0adKo=uf&tF?hB0?YU&S-iXs+N)z;VA;Eu%0bh8W?rUsuEnx?nLKQ9*&wI!sp1b6cFWU>^0riX zQPmy$LS=fXt-Q?>xMXQA%F}RY7XkLxIW`jdtyoTkWg4!E#3xEq^JB?4*7$aq5rZ13 zJOI4?JPDm1yo=YsQ@;J%am%0n8J_d3XX1I!e?IQM`yPDt-urOiy6bTC{=;~~5C1cK z>XUcky6?Ce=UwnfJnquR4uje zL1I=dYuWmN|6lJ<%j_2)nf9U3uR$AkV7|fEu|-TLA6R--IZQsA?IAG*IWqk&@k@ygk9lT^){%W3BD0UO+VzZ5t)iY24kEb~yYJp&;Ku zHL|5D-PW}4!LSqF7Gsx2v z_{Kf=;lT$Uz`Ne_AMxQ^K7`9Jy9{f)cjLhazK%V+cY!nE)1Unue)-@0GH!g}aLEEN)n4=kA!W{z&qs6x@?}gUS3G8z_evpaHGcgIC$ld!7rXj@g^!!+5~sz z^%HM;OR(f*wmB8LE$5~T*6Uw=lkZ+lMZ6FRUYIkIx=cNEd<*w}^&o!lmQMg*{5SyM z>Ze|X+|6+4;6vDT#xAU_oq=0#{c}9)#^>NSe)HF{zP^sW??GKB7IxNICYU?Z1iP5} zy)I%OsQEt7u51nvLg}JnW$Pbf-PUwdv{`Z-x0Qw_kV&tJFS+g zFq>^5j9~~*)zGkH{Gx~xJW=zTjauf|a2YE{@z}HFnKGeT8(RIeqLXW8bH9bH6Nhm0 zq5HA#;pZUn0>mq51-)Op9zr#Q|JhJ%!xqN`T_?HJ)f4k_C3z0z%Q|jvB=LD*pmK#a zLxs;3!Q)bs;RkhCje9ZK0yWww!jTaAF=p$n*;-RMl51s6J~?BCZ*I+_#CczK8DsNh zYuU>pepX3n@_|v-dGtDgo_yJrkJ%JGMT&#V7;Ls|5u^MZ>A;;_B96=egR)(4V@TZ4 z`En!qiXODDgsSuGHkX~!$Jj6ylnvy zUttaUYhw(`Alc|!X~X8Q5Rdj@YtUdd`Xdzs%KM@hG@-y|o`{aadin}%;f33$7{ypc zD&kmGz3lKZ0CYVzH%{Qtz5fO0?0tgf_ahuWd<2iV@Itu9pUT)WwL#bf9^v2OI&;q} z?C6P8TaEdfcm^_fC+!&9jc^2BC{2bn+8VzG%O|`W=|48XBSp#*G@d#FZ1WLiRaWb= zsy;EkLT-bj`Jrau`!kYg1Q4G6%CXWGcCW1Cz|*hCkt2t3@S*#$YyC{Dt*_y>+it^af8aHE z{p(+^Q5>nHoiR2^6|x#uN2Bjde7Afrde4QhuULSBA)z*u)FqoQjRz4?Le`k&m%QX9 z_}~XVfSX?ULY#O0Bk-6DFT}>iNgO?L6kD@ZTz=(Kv9dbH=CLEV`JHda>F4xw`uWy9 z-*)k1vG?k0u*f|Q9XWv+G0s@ug{{pkeDwCe#4BF;a{Qlfe+Smr*Ys-lSx_E>)*D^# z>?xAGG9Zj8DeV)_CH%VS>U6UhBnOQK#c})j+xc3+!&B3Ps97)AsH5uIL$IbEb+=QR=y%+3-sxgjdSQX5N;n zOt0dw>em#rTA}sO9yf?lDMO}&E2e^X{ZP9xk0%QKgwQ4JzZ~co<7s?O69JsU{Fs6X zS3qI7v3ZKdK$|1meTQlDh9h=FI!ECmQ&i=Of@f(q}RD zRe5ciwGm~9Z~h~X_r8E)P-D0kQjF;_7tvh2nPfl5rB6z*ybXb&l+BIvl{oO|n_)Eo zOE3#o-(FkWcJRd!H_a1yh|z?vFQFSh*rEjP5|BC^K5_zobjKF1xn>u(wl*+dnd9)G zL%8VT$Dx}gaGyc5V)!f8Cz~QO1rGVNeXUYS3}27fPs`jAnx!}LSk4fN^x);G`m_8| zUJ`a8vM(8zmsYA3%jIh$IP0DSZ;{*vRmzvKd`2xy_1c&JSm|YOZ90utjz32ql4@Q? zM%9soDlr%@d)bR|%O8CZ&-w0~aQ*eqz~RG$#UkUOBL{Kil~-VGWgQz^J^tVKeGq?$ z4=x|q>F4xw`q}Yw@nbK-)mL8)O2Fo#$Ab?&fcbomz5CC?=EfFoyX`joum9T{@uoMu z5ohc^1G#5(o#}b5NxBMVkA1J+MV?Xd6ApR`f^O5~{3&{qAK7o#a%P+qivy~400`OQ% z698bOZswlf1OQpo9VCEqMmLv@Yu02lxzFfxFAP2b)WI_@cNyqYLPAE)3{G---Pr+? zG_R*QIb1}+plmuS$>D3Sn-slbNj&wlGwx2W4(mB5)dHq*5La4(f5 zq(kvdrXvO=))dLG!p*bD5?B*4Qr97qVQ+ z-T?r3_s#ziFTCjmSX)~|?z3i@HTJ558bq!!nZ zk%y|kwd&VuyzyhB5s$%*5xur*C!QZQ{Z-{heqY-4Q1jjyq-__*1Pp(sSP!d|pDMF{ zXf0!*UXf?--vygu(D8K*AE2ReM;VbnIhd1H|#|o<=^N0vjPK z?#il^&`)<`EMxSIbAZz(#!jUzlq%wpIMnlP9jJ8b^F(njZ43zgFnQ=wWl(bb>HL#< zs8Tf#)h67-$e;!}4sdI+B*5haq!13pZb-BFh0=tzp96gA(aJ?;!#t&-bRH5DN3zI} zn=C7%6Uvm6zbal#)kZktFE$)mG52Mz$BbGk@CnetlTy_#$cSo_NTCF(5AOLvw zb6jz?z-y$0GB=KNtn&&0DvP$kD$+tCtZF8cCAQWtbSqoH)QRRc&c|PMX~Ek zfRO_q=)hP2Y?pDf|Aon0F8E-G_McVvFId)fpH+TUdJmO$Smn2Sf*1|T+Vs3*?t&6J z4)R9Wod{RsC5bHXi;=S#?aa$k;HcD$s568vII}wtW|l<4)OBF6dW{rbZ^psWw<244 zAcNdn$PNJf+{28cDr<-!`whFP5%4G)lYhj)n<_JUBE49PG?y+9U}5E%MNWtH7(_s# z5_MC~Hp)CEO2~SUkZ2}&4m~9ck+le5-SEnpfO($lUXKCaEV8zZvLBXxvrz|0-dsrZ z3Ak68Oj=fQ2744scw#_Xmn@H5ErS4Hk$d!;3v6wklqi)%IAdi6hmIb_KmOyFas2Rc zeEQR$#wC|rg4NYkWM(8w-aEf&KJT3KaL#$>V0FF%CZOMxO|qYu>4rZsfG$HW z)zhB4l6!(@9nws=k}-kKltm`YXzm+hWX~gxMbAjwfw)HoBU6%vVkglVvPc)%^-X6p zoPmW6KcUMB3(o46t@t2G)=VKwPp`z;>&dGyZ5bQ)Y6l{-ugG29nE}!pv;c-=sLz;D zLf`2XgDi_!Lg2)Z(6QhocK{&^xhyrC%8FGqk;bW3W&6U6fxm%#GDN9Tb2BU|?#U#bPx%;sar?YGIOSBL& zxeq`ULBTY*??DjbRqnGh#ng464oEpmvbjD3T_?;;4M3fyWMCFE)~r+Jq{+H6fG%ZC z+tFdxb)b|mpUu$|gJ-O_d*osO;srQ&nz=l=@zE|w>5{;1!c!%dFzrm}I{BA#VM=M9 zu-H0@V_TazcIYtf`N}=cz5b_v`a1mPulxqqR@aa^nd8)@uzDM1F0cg?7}Kg<)H27P zV1za~T!eQRqLnea2nU``j|G~FLwQ>+jsd1>ACAD+rqt2ELnCN|FRhby*oKui#!QuO zMjXV#!(qlVz*25nogC-Y6?(%wRbKSgLJJGS6)B=5yakLaueb`|^Ridqy?^|EJmu2M zyuycW{Um-I3-GRUz>AZh*%?5;S#oMXCp1BRV^pW~MZPK!>c-7vVNnza1Fn1(8Z=4B zAreP7eYUZN@g0RFZcITT+)+bLKmc{{d5M5eMVYf?+|1mNrs06fmz*xOjoFgFK*&l=~ii^g#9su zc{6|vCiBuLs0Txh7}9Q0ie>y6jFiRop9~*n+_7*wH*hH|9u}#cxX>^%GPttC7Q@UX za*$*#>DmySC7)B$Fe{^Rw{+CmzYLT(Xu&J1A;%11q~Tn4JDPYS>YTB9aI%fp zCOP>Z_W<%a0*X;AdR8gD*@YgVIoZ_21{jFf3Ns3=8O___m*Y%v5t(NKkURKk(JaZh zw=#0hn4NJxwoabJ=kNFvsnTzuo6UTRFTC(k0(zQzv$hn&{a+1NFM`25JrUl$`V<0D%Y~JvU7s0 zb-Q=Tj4d`sg5B=Km=hpjOH{;K|@xkk#uz zWRT&B)R2K7R?QpP#I(Sb?A9=l$|HTJJWueH{R(v(xvd8ihmjW;RkBV3k;&R1N;5z! zURcjjk~&E!*nJP`6w^8%Ou%YNSY$gquZggP0}D{a$=C*NT#8GW8W~L`*zIzFvdXw` z2Kj|god5Z^i*pBcGJh!} z+;=8$^~`cnPba)G_W<((sY_T}o#RBmf#b(EaO~(&+;i`}4&Sf*+h4;Ey!QLCfB*i1 zzi5^59_pw5ZG_?3yt@3YIf99(!XL^`vT1yZF^@lOX^nb>*?)m7ilCkv_5A{r67KxO z?f8XXcr)Jnfj_|BeIGgXPyhfR07*naRJ(BKp+h_F^YnB2IsNSHS((pp{soW3iOmyu z(~tf*e(3eD!}{7Pl6tzCQ46Sbc>f&t1ukHxRk`Z$n8r$M|5)j2PchomNV~!O?EYHYU3YWgbXGQzlAZlS4(JHhD$*1UBPn0 zg>4M{#v#XWfx~yKY7quRGsy)uQxt;^AWE%KgweY1@vR5>`z` zREC5wUfVTcuODtMP{Vi8QCNjVl`AjGjWLql{JIl#tzvYi{8~H+2ci%h&H9x8Q8umW+ zi%g@@Pb~ofRGaOQ-fP^3dJ&`@i({jySbMZ`l+T5WR>$~DRfC!s7;qbJpEEKu<|(1? z7hp>G;0Hf|H@xAWq3c%h;K2uR`1HQ(^mF?8mOl?W=N#2m zpXRiG$s7#oo33c@CIk{I@ zh1Jy=9(Tzlc;e$P!DBAE7`xWjJ#%m02N%nFx}rKQpGd<`08AN4;xCOMd+f{7NBR%0 z{9eCSb%ec)oZ~fytN?33l)tgZLP`s0^4X$1Yp8do&PK2Q`o$P{r9T6q<4 z3w+{h=;#bEFM=1TN-e+t7Q@Y&pZZf^W`^*`#=NwnYucZu?VF%ns z!;kLzd3>F_H;ji$nPJ8HDc)MrBT3c#Zu`v^TjK%9iaX>B3 zbgnJjz;H_0Q7r$38)__6qZMBEih**KyUI>xRGBbsf_f=@akJqT-i~|?UV9F^&3}N^kw);_y}Sww zTv-evU^Pg&0W=mS8B=s0a8#rKp}kc4bT6?uAAt@%W*h#SX^ACCy6^(=8q>960^h%@ z_U9ocuzTNr{MD_0iFd#2ojBvn zGXP}q28vWN!jnr#O`I=-#l9^G8frb>mMD1?{`a=IM&+{lIae1%7<~yJBqDkvbppXWz|^8nnxCUYr*gMfl)IL#)}AIyal17k{%&-a}WV9 ze$k8Yq8GjploG!1r7z$=-}+Jf%_l#Jjg1W~`h^}^K)k<_?A;dqLOr=8vzQru35>;- z8~|nG$tK@=2IdJ}QdvtRX&>0an1Z)9izku&l5MYMVL4Rjiy=$9>ymrq8}D&F-saQ| zz$K{6`Yx`Qw(n4n4r3qWQq9L@UQH5G1s|6HMb2Nv>qqIB%RFU*L>-Xvi$aG9#jCPI z(s7vxql$z?WQVnybAd(IkwwmA-Pf4W!M%o=RD_VG>5#UP$%;VWHmAO32zC25a{>1v zyCG>V0-l)E`!n!xX`jV|ii;N%SiVpxIb;f zP)|SqeLnv!r~NcZ*~5}J5*@e;%U+pxqIS`maH1k~Ts%)GUL$>$O+fwgQpE{D$qJmX zs7^$ z`AuBiDxPL;IAALts6iD{A7fC4b%V`rz|5vOdEIKTRcwPvO9r?bc-chd(aUo~ka07^ zdO$!LiW0&is-1|#UYxpBm4^o7>-u1b#W|PxZPtt6O7WVsy&T}ya_+tjE@8C6h+0TM zaOY$2O$rs5e2ih$L=TcUR{uS~P39>P=Ec)DkUCryWnB8x`85x*##mO4WlZr9!-+em zSnPr2CW?HkLaDwp5(+d}5?~t~#yO~t&T2hOtSw7&Y;;w5R0P_x>tG|jnYJB@7koyV zWFH!}zmNX4^+MtI*q^;efy+7w;SvR3AEnL^wRceuLA8<_|&=dJV7>J6v}8< zS=SaxIJ&p!>mjUdH@2yPtcuMp!zP{YVuXaQTLN+dZ!SP*o(1fBG(L382k`9gdKIp} z{^_{?!3VKEU&XH7XX4hsxE1%^cQ4LA|KaHS9$go`s~SN%;w|&v^idifHzTo6Nu00A zuc0Z)&i-^0A_l^$R(#nG_yHRvv=mTrx3A; zJ`PYCt&*2#;oup@isYE1U%ywvkxk`+{Q%xe_>> z_mUH|0x<}9#^ok{qh0Ak)t08R^wFoam*Af>-t43c_F6vL&9=BLtMIGG~gLtsf#A#_GbU#T8ICD$97 z++h+!m|qL8@=X;vld3`xK_ZgPskRefv{;eMrZ4Dv@jOFjfN*3~G$Cu3#1QBD2^=3H zW^1px;`$!wB%y>xdhQ;}5kcCX77T`Bu!hrh)@NCN?m1x~WjoPToy}-V*P~x_q4E|0 zh_}GT{khDa%zr(n@@1i<$c_e@uYk@z7n#n)pZ~#o@$8$v4>w%@3_Nh?2#%jPf^*M3 z4%gf>j{FqFM@ z{c;en48EwJNG;dto3`7224Z#c#Wwia<{5;=4hoE%oHtW534sqv=_ISXQKM|?IzMz^ zbTID5xyNF$g_LaVYY&NFw;RfZE+&h!FlPjsP5w`U& zYuc`8M^Bz_h5KwGUTmi<340|iYjRm-BH44*fR&H-!sCqisVB+29~VDv1WS4=_nipVe9)57~@|4NcXxbcc2<>|8JNxmn|deej~3B07$9|q)Wa1~gCxJ9h%iecZILr21eyqX@sRH4 zAbWBop&zh#>zIC9mXgtu&W9eVBruRVa4))HPLh0FbSMTo(lZwI7J~3eN(mOJAShWN z5eYtYkDLng2QL8bfKK^8tE}d*|1fX2)Xiag#GEraB=o#+ISmG8vl$2-GWBxN6B1_K ztX{cM9FHz#hRbP1ZshWj`&OKos^$m3`&VX7|2+zUDiqbJYg2-Y8)7RuTBqQ;U8@rn z#&HlzE(1}peECF6*tm{2*`(BEQMP=SXag83iozgT1vkDm-s374JXth{vbuYr5quc{ zY+Neoc+1fw{FD>LHPn^Ua3WA#@T`OOyri76`zfyhQ5p;LYV;Q{&2VMA;3&?98G|f2Gb86>5L8rvNj6)yX|h&aK^!OxVV)yR zIteZ#JbmZ!|Lxp!D7JIOB7kvfPg|!(^GJEqeCra`asj5--wt)koiE;4Y@`lv^FAtw z+raf-1Nv}&wh!N|P(6W;mOGUYo@Ic>N#^(~0IJ~(pC^7E0f=?IC4BW8U&9NY_k8@r zKm0u|y6ExP+&F=iGuLtW;08W_*Jto+zx>nqp&$O|Sf6iz_$czmA#mOlEhwK*SY{A| z1ncL79vO)ksV898gV729P7)Fc=*BM*pb2w1br#JcZJ7rF)No8FuIhkjJt>J23y8w8 zkabIx=tSe^N>Zoi83=IrK}hw5OuQgp^VHkrQ}}EAZ)Wi0OZC;GWy6Fb~yxQ1T4hU8mYIL z0A)FxVVY?OA^_eLW1}TEX9h5bT%aK42ntE488f9X4Qt>G$}8Y5%Nok8b`ZfoWhj0X zPSZ1I1Z-t+w*typaBmyW#KF5vV>4Xq$r`d@b72ye04&sa1Ryc;f+UPOad9k4mb`US z<`))1kTrR%9;5NxL(`arE-7`YkMuI1iGVaizaXSEN4K&L%=ZD^!*I{N_u^09`}_F8 z|K(?J{WA{W{s)g>W9vB1KI5KQ`tM}cFuYdi1oO90Ea#N^m(5)bwq<-w`q0Q-YL8cI^~ivER%yvnlB^Rek|WyiCS-@@mHaGTWHYAQV51nY^VE7 zG%zCDm+DMA(J_}P2j7fd>tDukHeC}HAmd=E?mj5J9WY}pET@?5Azz}O`d9YU2BU56 zbPsT<^EgHZqY*vdg6EXjP1wn9JEol?=hPnIJxgfw6uTYh^tL|*8m8y!7AM9-P)8Lm8NOmvXmo~8Wm$D%3O88=Qu+D0jD)`%uJ;G#r+_jJn4!;@RRy(3)E!v)}6q#6C zI;I*s6MOWDexzQjlZ^AjB|i+_jB=*%r@WhjrR`?XBI+J7F8kD2p5ZH()ZSbc(Qp#}>Qg2AJaRV|=ZKe8B!qtPB{J(U0=p?Y)l1 zL8(x23S=|IB78g}d==rRrCn`P*M1x<-6f4y0&udNVSH!nvea7Y_+FMnLw2J=xotbh zcXMVLyqoF}m5ldS_Sek_UcMRmB%w?JE9E)&;tA1jqU%=hd++!?yyky=4Gvs)0LM?9 zz~;sV5+&^4zZVCOp1`N?yaNF6JHP&8xca~|uy)2Hkh&EB8vysnw612+ItAO&E|^C>T;ZBici@n zOTgwrt^(x}>XO{bCgEH?B;}5HXR!3$1KjoCK8f3LVhw}U^{=k!;@EELkGi?Tyok)Z zq=V-)0*mJmConot>OmTc3Yx)^&m^UY9tmV2DiFRS-wA#dYS_FRd}g*5&x9QK7Qj8g z7G?lQXiCrGHRLqbfjFrvcn|a$+}ZdU33G+PF8?(e&B(NhV(`fzmV6eO7{CnT=hA~T zynz_%F(Wh}-Yb9^&Lp%gOHLN04-g^2(*J5mHr0j!qZ$vJX1R)(xWkMy`i>+lI`=?I zNGTQN7DX}4nUIpXuA7$$X<&AO2V*dUxdWvvo@qUcM_M<71w5C{4kaUA@{7jWC3-im+mQ@;fOc6qCB? zxJC|cnygR0b_B;MsGUI%-9VVo5qj^kxgzT5l+ucNkL373&oIkfG?6OC~uu(baPS;67A0pn4)nIf|*Tw|v+ z)=bP+VE|?NEK-y_l8qIhp?B3XjuM&buW-9pvX65V0ER)n$8@1$bX3~8!Q?{7+gje@W}E~C(kCsf9Fd+vb@bX|v= zZ+YgC_x z%$85cC?zSaW3Uclzzmw2v2%leu(4UL9S!DTyflY)myrpF&!)rG9zh1TwnRF{5yQ$b z_N46FrRlnk(;=gt#s6SXIF=TW#O=6DH5+aA7ZqQ~mh zx_c;w;l8QC_}E10S2zAlkm)EiH4?@a&+;+SRME(hV4*q~GU}xZafCqq&5}+3K)5xm zv*H&c45?|PES^wqw0)HF7#r92lv$nfM?pD?plNa((#bT@4J#L%L{y9~m=Q>79)^hb zL0+iggbfE`#TtA@;W}uc8RT+BplxGFl#}#|`HmUDx6L?|VO9^3s<80G|2GXW_(&qd0Q(C^8dv zt*&5oZ3QbUD`35yhtX?0n%Ef0Wr46?WtJq#5dHW%?#<>+Xk1f0Vd0*1lGix zMo=M?iZvfm^s||8%4OhA?={(b zXtZSZ1R0+<mcczGL<)>37@a5-a;haOg271z5a4pt7SdPpJel|W$oH#n@3B5Af9x#P7!zm`y8eY zpxk3?i*fwuarAis%o5H#<4l~nz8klE=uhzECqEJY?*DiT4qSUJx-RMMUQKf6dL=b{ ze1u`wBXjOQ8sZ=2&uA-kYw>_JmM(n_tBoDVjS5PmBZ{rIwZ?&;?7snKM0=Pn6W8rT zdk*PH*wZqZYin`z$Esq}N@EbKssqdOkzfQ*&X30C!x(A{!^FS>EsEi=hQ+JJ53KW^ z!aFNHs2e&Sg&~ZtAO!Ucwrz|wf6K6z2-(tm-L7vAqT<_@1M8180C+fe4U<}mVJ-yY9Y&%UTR3f}Q%@+@ z(#zm-FE%C{@U%fSNr~e+fQ}4yEa9wK3gt`Uu@be9>FGx_=l%X#dH~Ro}2r2wdkLpk$zaG!3$mE^BwNTW>13~G|J>1eWBL+>6z2ju;@d# z0GTTrXooAmiJF{7Mg4>mIa%{+)V?K>qt);G9(F#)nmS)y)_r)dG3GMq(XNZy^@W(f zbt=$i4kCMVU#*`8qbDo+aLdHW(Bek4PIl`DG*BC#Inj8FOia{n^?BZypt}2nO1Cv$ z`Y?Qj*j;<4zMo5@rDs};8YHEFtxg6G(hHd+FFl^eO5zs#~euFr{T@pkg%h2Et4Wm>g_~JHm`HHg?u5=!>-%kY-8SHA>2vR5K7oZ|-khB8yODV=1+5oir~A44em@EHTC$ zNC~m0f`_AH0&GuLoTSl8hxCx~CT1Co61yHBXXlSfVGsH~G8G4gDX^^Qb210*rau}% zqQ?k;uuL2*zU8a*KzBxF+$EuBO@2^o)Y?t&?>D`@eWCyRv!Bxc_=~@w|MKU5Mt}S# ze>$Q3#&7;6{rt~;O<%6@Fhv)=-*QCPy>@%Ksc)J?eU{@Io7dh~f9UVC7UPtrw{=u@ zyBpCPFZs@Wgk^F-@p4l?b-YRP*e4kJ;s?#I$cNXM$|{B1Zr7}HHF=<)%dJU3w7Gib zX0@&F&7Gd{fcbtiU2l!F)=egFZX$ZS=IM-mBBDQ#cS5yh%BIX}H6_`} zYaWvqV*!b>Z6-ODtf{e+&2w*=yrD*RDa+E6j)!gRGXAgcT_fRp@=xPIV8)Gm@}*a{ z>Xl1xJa=yzV<#tD*^QGgS$#Mrt7t|g!96CIXsq<&MRL2YaWpRx%l=4BLO9RKE^0(_ zaKhyL?wCmHvJplfJJB2S@_F*qNDQXG^>0M{-nkkl<;_VnWvOi(M=#^kSJIAq;(xvn z$x+Pn0Zx(E#$+zb7?9GnF`3&Z=+@3f0!!8-tyKYo4wlKEF|v2p@$bI-j(+ktKcOH0 z_{S6fzyFgzqJQMlKp==w14QiZz zqHOU=nb4g1Tcpx&;UmVYu_yHgGR)XhdwLa zWfppwHfo7 ziRsym+baJ2A0p7p-z4222@>vBN=bqkF7A}X!HikfUg`|73)HC2q@-;aK#1hKhQrnO z|MeTqa!7P9UA5}Fy$U`M6iKUUME32se@9<^^)(R@ee=!#rvLfB{*wOBH{Z~I{C_j`R%Ky*hpZ|-0M!);-evf|ZxBex4dAsOGzxu26i@*3!h=}O@+i&T5 zdz%wd5=YI-fhrL^cn+|STnUVR8>XTrN}w29h}9ND-|(wI$=JbxHDZ{b`<-iGQ$HJf945 zp1xWo#p?*%>sx78?Y3Ryp!SZMel_)H;|tBelCf7v>n0trWsC^NtSsL;RRL%Z0-RxQQ(XJ4szDHte9 zF!<9>iNk!>t?1(kGxEXx(3p^G31kg$^FaCdtI-63NK*6d0(ln-}NpX)5Per8}n0ll$vWidk-=M|&jHPN-&!kBwGKy&h7Cl> zaE3*yCA~SL|M*q2jdrFO8but_lBoB4(0t0 zZ$EB#UaCQ&8rw!xW!)ho%byJC-psOMcx?9PJLm@yqBx`xvtKQ7_lZjcB)5NVHK_%AP6UIZ4vK0uH;ruX^Qxta#PCbRt9G0kFD&+$YLh|ZS;YWE$Bx3iHUS6@E?k%LV3cIUj zl>oP+ar*G6NM5qlA*-pnz$c6spOI&`BB7qo6q36oaM5#shJU)RRR1?7bjOg`6=3lx zn#jWT?BM>%)416ZV)w+J< zLIDhh*ReVIbL1>v!Tn;10_|n{;GErkEY#(=P%O|}JycKdh;G}Zcpy#uVkMgs+1EZ+ zEj3P*sDu&%f1U}f&r)ot>riWM${;W<)+S&6JMa7r8uEN+U$O3sao!TE2?d+8j~lZ) z9VR=m@3lgIa_0BQmERiic}O{>+}%=mXvz-v#Y?M|_42rR9HAltzrRwF13AJm8dmpU ze{(bnnu1TrOztI8+dwN|yg1yt+s#aJl9tGq;5ee9q@e}#q4Hwn3ivTWpAi?o?;@0c z|FkL$pEiCOro`Wi@rutI&e*s0)ASID$|J`8SH@Nm{@U;V6Puo)k$ z@f57$N6Sik#I0Jo21cdEz5dX*2CB6-|3TV-1Kf!dz9~OV<&#udv$xADKO^#+ml-~h zBeMBhs=qdmZ1H%pJ*^Ld++HRsj!VhYZzui8(n(r*-pMK&7#G`R>>Dvqt_IX{p_8{e{pd9Bq7f(L3)V5JyidqFmRxa zoCY(KJ4aaN?{#wn8u3xkI=eccM!san1MV)5=m%^hx#_%`!aL)jZ&4RLa)Q#(6wm(w zd{iMf@#PU$ccAmLuU@yAnXY8|fqg?FfjwBdEiKOoanZ`G_VK~B+R%xdSxxC`y!9Mk zHproaXC)g+*Tr}HobudEiK2s9kknDg!E%Qi8Y*bjC%QZ=7CWo&x<-zWuSmH{+B{Ho z8#5LqH_67P8Wu|9PAIbYq;;+*N+RZ~F((`zFba7Ys9U)tp=_eX_M}Y~LjrYb!}N2C z>UNHVhp^+6UJg$u3`OwY=zF?4=-hphH5gW1ZL6Kn>TR@wOb5MOaYB<|o|-W?hfNVt zA+?amojGd2f@_LgyFnAeO+VA<1anN_;z=1E28qnP+9+6J_wqU2oPcW-H&I-e2VX-Q zWMfW1H{^^}R0cNfPa}eY@lGAsOVs6(DnKWNaZOF9O3G5a@>$WKa{eAY!6p^U6s_!i zE&@fR6wvTdBrRTtPko0p@heoT7y*Zrg>SHbSs=~>TMfH(F3jt|F*h}7r8aO(D&Y_ojF$Q(H zcAuBU_ty)Si5*#uZ@bS>as2@zX`=M0!;T25HKWoNv)2%81Mnn1@l+ORI~7yN?k_Rqp{jB6l78MV|NW=_!hq!r7&RlCFtpxL{e&dA<5EZ>*PYJ5EHhFAnGfNdTvpTaSq|E>}JFPZWzR$<3827{ikOOl63{2 zwHC=Ef2G5LyL)7W9)x%*fZC5C$gQ6xr2+YDSv%5CbDAY7@H7cT&OiFySG+pYJzkGr zaZU7SybrAEIV-wR7Yz5bbv~L~byYb<{bq~eZQw_;Qz>|eaUavNm=Ij~02#x&+ens_ zyvF97ET>Otz=tYs%oFrOeoh~-Kxz7d20(Nq#wDU918VZyuQtsdn`B(a1dWW#+#@Cr z4tg&g3VXZtQ@-Xw2y#q#wxZFBi6ltrtzSL;)n27UlZ_=H)88fE#s+*ss;^_Rk@XU^ zaxA^&T9lR(E_ODju&O=Gv~4t6=cP&NJ6RZGx7#N_%c}&wpC+GF-^!<{4fTV33}AKy zb>4zm9PKaV`a&M;SwQ=;k;ah^jM@^}@w8`nkyRAbCiz5;Bk$(xzMss%z3|)&_e%tP zlzwXr8z9klS8GL#Ic!zlN4{71+4nk!tGIJ|Lk`B#(7Lpt`+j9ZDU5zc`$2n;$dAHq zTrh?g`eG+&DypqGSp8@LPEOV_dzn*#$!yaL(|Z>9{scJJAIvN7v<@M5}1y5Ltm05?mGuXEZQAyE+eTyi@_6dBseUPY%`9H+wCZi9CST4i+_SYfyr%&2`O@zf-k zPa>Q@ahY^C>$Re5_HRUXB~omUk_Ds&L}T)Uz}q#HOgO#6IvO`+pY53j-_hWG!eo7? zBz;R)=Wxie*wZgIif@}yj19t2^fpYtrl~ErGLx4PCuH;OHQJRwWFo$7L!x!e`oP|$ zx<=NlhGL$_2Tx9wotvXimD+?wA527d|I~=Cu^F+@q8PBRfz~Iq=!BWhmf}On0fluI z+6Ufs+Y*d@l9G=Msa8Hy;c=1~Q+-c{sgp=Aqe#K{;83pl~q4}VrtYKTwI%}!E4x`m8jHIkJ*x(k!?sk zGITt8H&-uE0bxf*1cOqpcltK+mqp*hCZqWMm=H4-8l3$33?B}0O3?~iNiE%Zs|ffO zz`9a_K41oDke*^9JrA+*1D!pFQ^_y3+q9Vp8&R&MAfc)ph-$~A9=vMMvxv!?;4oR< zeD{&^QI)f{F~I-~WI+ZzJ=!l}636ZRQ)%E?Y)<$CgudXT%A(Z^!YRzR9u+_-lNKo1 zae~-gOZ013cDAbOkK+9+G!$U6B~e6Huk=lG@>ilHt|}+M{VtM_n{Fazy4o8+Q!n_R z?X>O~R}pE@DMqi##xXd_Pc5D^FW%s<_00%u6;1N=$(B=%JI?7Pk+$;V+V>pkNt~KP z$s79AO^;7Ju}eXkD{K(fd`w|35cqKuvqR2H^z8cD0Fn8gfCdsMwyh$Q8bmb5KPNc{ zErt6v{I$qwXo(`EzQaWQ^TIJ0nWv6nD~EejWUzxR&=j^_P2g9{&A6M!Q#E2{Ch)*- zhT2C{NSCMiW=@1vYQoRr{LY;;{A@)RHUF0#eAN4)I@$L!VAI*D~JVG*N@2B#V zW=BcGjuH%gZ~QOfbMcI6PUIj|LDr?Y*nN6t{t)co>B~_)9y=Pqtt>cZ-@1C|ObNc! zIRcuik_5Bq+Y>)H0%+vnll3HK8tV#l9DBM_cq!z``(D13Km@&r!-a4F4JHc@D8jOA ztY&|F0HC!N!m86~j8>Us!|0Op-QGN*YXvUh!S?m^?~!QmA=lBu zp)7C06G7W@V0U4BKak683B8!j6iKz}DTb~K!mgW~93hk+ra;?^>sUv$=}hK8Hg=Cf88kX)n9%XOlF{ zHbjI@pQ)*?=eaZK)%S_KGkT;C3c|q z5k&A|#75cELD7l-r~30?=Na-?MMjFRyywaMF%~@3yTl)0caDCY(nM%3#;CV!o^Jcw z#;Z-~e8N1TH=}f;(b)zIC64vOI8iw`qQJJRdI0>Kt|U^7KZ$a0Z1*9np-+EFz?AQh zkOA*Xw(P6UkHUjQnSq=D`uvB3Q;3@9t?s}ESq2v4R|z{HI>_oK(9e+HM*E;ne@0aB zUbDl~vFC`?tnPrkSEQGnXYkni66Bcl+`p7Oys92A4)2T;41kDhVX~)Or8LHJPU@sy5a=ngaAvo zsvn060n5P!1&V@lTX0C+vDH_RsTT001iOWn?Jy7p;z_)W3C-oKc9ng-=i zB7|-2QQp7yZ?nzqcNBG=LbMmC+MA9*I{JK!j-K))H(59P?KZETydr;8 zvhG!0<;v5O$+iSBb!ZCUg#^rmO25OtYQSVrXDF`*W%R+y*NvSO4on{?*#NM=j#8L4 z122zu>s?r{<0PwrA*h)vgFEtsxU_J*j5TY_iY+#OR(s}SS;|(OXr^$n(TH0M;)NY1 zTq0^r+^}x3Y8c1g{_30Tv62Z-ja?=mIqQG)TkfWM*zsyRfq`VNxob9+pxuF0qVu)=4dvQ6ZqfcVAvw^v>v+kqdYyI?Y z)v%%;7p|a7z|<|>jffg};Wx_Vak4`p>YM6d)LKAf^=9VI&mz4yf$_kL!Z1&IxR~+VD!c$ z@iLJEOy!&VN`^`E0ZJRMZJ+FMGkJ==IMk?4hp$L-7_kk$A-Fh<|7=4%e26;n!7;fG z^HW5-03O)+6nof|huslL>3&?_ONsX8YpiOkge4#3z zydugVK01hd)%g`QyOfUz<`GXll@9rt40d^t+4q;S#u;++Be_qT{4MEHw64bYqXn<> z4;k~guHJ+1bHi6DH=-vCWarycEq+z`fX-XJ>_670=n+w5Lpq-lm3W(@oOBOyU2pt- z6~jx{5F31+R^Nl>oUr43KpRJOrg@0FTKny@)%tu)J2K=6u;%t!t$d0`qei>K+SlOyOJh;?1v-pKCMzCgGp+Gb(z2}89+BGfBi8xLvwnl0)H)!A+r^f&Q z2zg0FK~y7U0@#U#XiWT!hD~PmS*G?7<+6fsyf-$EZcxrdPLM?zoHv3(|b_SeXVv^OU8DTyIS@;Qwi;Z z3U5(?lDB|tMm)A`3qp(~XK~VkUOvoJ1G)H^px^$+2aiLYQaT+?qsyd`q-#DxXID)A z&9u>hbf{3g5L>kQXjz)=uk#4l6}|!PRET(d&XL9j(M2_^DkWGpcMuS#zGj;<7-eXA zJ58?*)raMvW#*vgfNF~ZjrH-c2B*{d&^7T}4$5pj(?n$9K)*pEHdkaAg<3gy>O-eq z!fY%d-s!xk*1$b;1(P%QK<9WO-}Zo(nbB~6shKjX^8yWVN6(5On0jfHc;+dl!gBO;XjCvDy9b^s09Fr{YY*Jx!r`37k8&6tocr#!qYqdSH zA~31tPOKzaCpdZph{r6p#&pR#tI7+N{xtZMUff!$lP-jG1y>}u-ID86=YU8N9W@=CZsDPn*Pv()Ws5cu9q1k$; zP>6htEk_ZS(!Vszd{P)(4rwyD@2^X|iPMz3tpA>c)M+6N=3W7}^#;=V4lSpqOX8Hm zReg4!M;Zq%lrPz0wlmBc5^#drPqDv?7_xO;mZ2gqAPb8@4+F@T{yqs*G3ht5KK+a> z0U5zJ`{k&^4IU+6tny}@`|{*d>a^@Mmf>PVl#a))$=lXO6y6T|hX#nVD_7vp8M^m^ z-rBAn-XNY8GMdtl+FOK)LUY}SLn4JAQL?*L>XIeBKAajFjoud{_|O#2n=fM8e38U% z7(xD!gti`fbQ?B7uGDa!r%}Pj&{5H^QhwEDlgWS@*QtH6%q7`>DZPoe1&2Na|} zv+bUK`})8r4lfAJjY`lBgorErHh?r|J6I!>ZnSz7vy!cO0+dl>>MxJLIK*`Be1s=& z9)>r1Rb6qod*+C#cJ5C#PKX5LL8!B&T~jwjPg|j{L8u+eb-w;YwOju^D?UF!SyO-7 z8X2Ed#?+z+mF^dIc2LN=p%PeTFsLs`fzslgF?MvdDH`X`ME!&g4Y^G)x$|EERJ)** zZj<<1l`{#Ej#8$@pu-=}37Q)>=QlA@#Q`z|&HJpA@!1e)eOfYk>>P)bETE?(YIc<$ zf6Ym)`_?%tXtH_ogD9%^H1|VC&INkh8ny$yzfQV*il$Lp5`$Em=Ep&ot?jr@=?X>O!`fz8l^(mGtDKO$88r6{eOazYJG+~o=3IkDpjbNp3483!`q)oO_$;pZ-=M3x?HVCb zZFFB`W4c0GExx9b2oq1B;W@&fUvig;nc&K$ch&<~f3bA~rVGj%m!5|(0d!r{Rw144 zYxd3a%B3Qi-@p|6##48*SH58rF!6aO_Lxh0@u}?-z|?V8IgIA*0y>W+b-zWS*%L?g z*D|*`KEN?Fbn1CuiZ3=zH2gSaW4!oXuJ!a!NN5RHw1O=-+l4?FKmw=K!uCjf-S zK4%`9Kn(FR&3mkj@UE&w?nGo36BLhlE=S1d0RURy20=ck+Z5j=$%W5yCtyCD*&e9Q|3=ZL=;Uz?JKNeQK{GY2Y<-#JRj>6hWq9Ld4*K{_DN_MGz_RgITOeo*;RD7L)3S4%JTDFF7Qc)n z$sa*Q*xEEU38-&{83n_tXbVP38T1y8Ab3eLWdrP}k8xtq_d&<)T$*jzk8`xvlTfyI z^n+8NnQfz}slbnxLbl13%CJCJsmv5NPn>frU3zOjeGQKw5O!&YDED)>z0XVGRWi&H zIU?H50_r>k*kZIzrC+(iR7p&tr9#c6B{YHD0%rf-+ON4}v1NXy9W;PksU1z}Hn zaDf)+=#fu;rA+!=9(8~r`uQHGk2a%s&dGkr9R@gdgWeQ$L_{$|Shx z0`IBVb4qULy~AU50S+0coH{9bF}7h4h(dE3ry4t2Vyv=P+Jh>ntXqsKR`+%}A)xIA zQ7?EW4)8!7`dH+C&#tiEuO43zx|Mlb)B3#RJPatC;D8JyTydkuZN#tLX;>Z|!&nZn zHX?k8Orp=HMaM-qF7}nQA|nTq)Z41y*MmA#qi!A3o@Ee41`ZqnYdHS^i*&pQJTh>P P00000NkvXXu0mjfW%(PH literal 0 HcmV?d00001 diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md index 29fa8c620e..53f7bfebc5 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md @@ -1,6 +1,6 @@ --- title: Page Size Overview -weight: 1 +weight: 2 ### FIXED, DO NOT MODIFY layout: learningpathall --- @@ -11,12 +11,24 @@ When your program asks for a memory address, the CPU doesn’t directly reach in Instead, it goes through the **virtual memory** system, where it asks for a specific chunk of memory called a **page**. Pages map virtual memory location to physical memory locations in RAM or swap space. +### Page Table Entries (PTEs) + +Virtual address translation is performed via a multi-level page table lookup. The **leaf-level** entry, commonly called the **Page-Table Entry (PTE)**: + +1. Maps the **Virtual Page Number (VPN)** to a **Physical Frame Number (PFN)**. +2. Indicates whether the page is resident or needs to be read from swap or RAM. + +On a 4K page size system, each leaf PTE is 8 bytes, so one 4 KiB page of page-table memory holds 512 PTEs (512 × 8 B = 4 KB). When you dereference a virtual address, the system performs operations on the data to compute the **physical address** of the data being looked up. + +![PTE Flow](images/pte.png) + + ## Page Size Differences Illustrated To help make page sizing more clear, assume you have created a database system that can store and retrieve either images, OR tweets, based on the mode set at install-time. ### 4K Page Size -With our system set to a 4K page size, the system can only store a small amount of data in each page. At around 300 bytes per tweet, when the system retrieves a tweet from memory, it will most likely be retrieved in a single page load. This is very efficient, since the CPU has to do less work to find the data it needs, and the structure size (page) is optimized for the size of the data its storing (tweet). At 4K, best-case, the system can store about 13 tweets in a single 4K page. For every 13 tweets kept in memory ready for access by the app, the system reserves a single 4K page. +With our system set to a 4K page size, the system can only store a small amount of data in each page. At around 300 bytes per tweet, when the system retrieves a tweet from memory, it will most likely be retrieved in a single page load. This is very efficient, since the CPU has to do less work to find the data it needs, and the structure size (page) is optimized for the size of the data its storing (tweet). At 4K, best-case, the system can store about 13 tweets in a single 4K page. When the system is set to "Image Only" mode, since an image is a larger amount of data (assume 1MB or more for this example), it will most likely be retrieved in multiple 4K page loads. This is less efficient, as the CPU has to do more work to retrieve all bytes of the image. If the image is 1MB, the system will have to reserve 256 4K pages (256 * 4K = 1MB). @@ -30,11 +42,9 @@ When the system is set to "Image Only" mode, since an image is a larger amount o ### Inefficiencies Inefficiencies occur when the system is set to a page size that does not consistently match the data size of the objects you are working with. For example, if the system is set to 64K page size, and the application only needs one tweet, the system loaded more data (a 64K page) than was actually needed. -In another example, the system needs to retrieve 256 tweets. If by coincidence, all 256 are on that single page which is highly unlikely, it would be EXTREMELY efficient to just load that single page. Most likely, multiple pages will need to be loaded if each tweet is stored on a separate page. - When loading a single image, with the page size is larger, the page size is better rightsized for the data the application works with -- it may need to load 16 pages of 64K each, but it is still less than the 256 pages of 4K each that it would need to load if the system was set to 4K page size. -In addition to the amount of page loading the CPU has to do, the system also has to reserve memory to store and track metadata for each page. If the system is set to 4K page size, and it needs to load 256 pages of 4K each, it will need to reserve 1MB of memory (256 * 4K = 1MB) just to maintain the page tables. Fragmentation can occur when the system reserves memory for pages that are not used and/or modified, and this can lead to wasted memory and performance issues especially with larger page sizes. +In addition to the amount of page loading the CPU has to do, the system also has to reserve memory to store and track metadata for each page. For 4 KiB pages, each page-table page holds 512 entries (8 B each), so tracking 256 pages only consumes one 4 KiB page of metadata.. Internal fragmentation can occur when the system reserves memory for pages that are not used and/or modified, and this can lead to wasted memory and performance issues especially with larger page sizes. To add further complexity, if you choose to add the ability for the system to store BOTH images and tweets (not one at a time), the system will need to load both types of data, and the page size will need to be set to a size that is best suited to accommodate both types of data and their retrieval patterns. @@ -48,8 +58,8 @@ This learning path will guide you how to change the page size, so you can begin To begin, select the OS you are using. The steps to install the 64K page size kernel are different for each OS, so be sure to select the correct one. -- [Ubuntu](ubuntu.md) -- [Debian](debian.md) -- [CentOS](centos.md) +- [Ubuntu](../ubuntu) +- [Debian](../debian) +- [CentOS](../centos) --- diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md index a79c7c3518..454a9ec1aa 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md @@ -1,42 +1,84 @@ --- -layout: learning-path -title: Increasing Linux Kernel Page Size on Arm (Ubuntu) -author: Geremy Cohen -minutes_to_complete: 30 -skill_level: Intermediate -os: Ubuntu -categories: - - Performance and Architecture -tools: - - Bash - - apt, dpkg -weight: 2 +title: Ubuntu Page Size Modification +weight: 3 +### FIXED, DO NOT MODIFY +layout: learningpathall --- -## 1. Common Setup -- Verify you’re on 4 KB pagesize: - ```bash - getconf PAGESIZE # should print 4096 - ``` -- Backup `/boot` and `/etc`, or snapshot your VM +To install a 64K page size kernel on Ubuntu 22.04+, follow these steps: + +### Verify current page size +Verify you’re on a 4 KB pagesize kernel: -## 2. Download / Install / Compile & Reboot ```bash -sudo apt update -sudo apt install linux-image-6.1.0-64k linux-headers-6.1.0-64k -sudo update-grub -sudo reboot +getconf PAGESIZE +uname -r +``` +The output should be similar to (the important part is the 4096 value): + +```output +4096 +6.1.0-34-cloud-arm64 ``` -## 3. Verify 64 KB is Active +This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. + +### Install dependencies and 64K kernel +First, update apt + ```bash -getconf PAGESIZE # should now print 65536 -uname -r # confirm “-64k” suffix +sudo apt-get -y install git build-essential autoconf automake libtool gdb wget linux-generic-64k ``` +Instruct grub to load the 64K kernel by default: + +```bash +echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee /etc/default/grub.d/local-order.cfg +```` + +### Update grub then reboot -## 4. Revert to 4 KB Pagesize ```bash -sudo apt remove linux-image-*-64k -sudo update-grub -sudo reboot -``` \ No newline at end of file +sudo update-grub +sudo reboot +``` + +Upon reboot, check the kernel page size and name: + +```bash +getconf PAGESIZE +uname -r +``` + +The output should be: + +```output +65536 +6.8.0-59-generic-64k +``` + +This indicates the current page size is 64K and you are running the new 64K kernel. + +### Reverting back to the original 4K kernel + +To revert back to the original 4K kernel, run the following commands: + +```bash +echo "GRUB_FLAVOUR_ORDER=generic" | sudo tee /etc/default/grub.d/local-order.cfg +sudo update-grub +sudo reboot +``` + +Upon reboot, check the kernel page size and name: + +```bash +getconf PAGESIZE +uname -r +``` + +The output should be: + +```output +4096 +6.11.0-1013-gcp +``` +This confirms the current page size is 4KB and you are running the original kernel. \ No newline at end of file From b200da176e5935fd974a2d8700bd416fae5bd03f Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Tue, 20 May 2025 16:01:10 +0000 Subject: [PATCH 12/32] Updates --- .../learning-paths/iot/azure-iot/iot-hub.md | 30 +++++++++---------- .../iot/azure-iot/monitoring.md | 12 ++++---- .../azure-iot/stream-analytics-dynamo-db.md | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/iot-hub.md b/content/learning-paths/iot/azure-iot/iot-hub.md index b30836523c..37c82de527 100644 --- a/content/learning-paths/iot/azure-iot/iot-hub.md +++ b/content/learning-paths/iot/azure-iot/iot-hub.md @@ -23,29 +23,29 @@ In the following sections of this Learning Path, you’ll learn how to: * Use Python to stream sensor data securely and efficiently into Azure. ## Create Azure IoT Hub -Start by creating an Azure IoT Hub. +Start by creating an Azure IoT Hub by following these steps: 1. Sign in to the Azure Portal: * Open your web browser and go to https://portal.azure.com. * Sign in using your Azure account credentials. -2. Create a new Azure IoT Hub resource -* On the Azure Portal home page, select **Create a resource** at the top left as shown below: -![img1 alt-text#center](figures/01.png) +2. Create a new Azure IoT Hub resource: +* On the Azure portal home page, select **Create a resource** at the top left as shown below: +![img1 alt-text#center](figures/01.png "Create a resource on the Azure IoT Hub portal.") -* In the Search services and marketplace box, type “IoT Hub” and press **Enter**. -* Click on IoT Hub from the search results: -![img2 alt-text#center](figures/02.png) +* In the **Search resources, services, and docs** box, type “iot hub” and press **Enter**. +* From the search results, select the IoT Hub icon, as shown below: +![img2 alt-text#center](figures/02.png "Select IoT Hub icon.") 3. Click the **Create** button: -![img3 alt-text#center](figures/03.png) +![img3 alt-text#center](figures/03.png "Select the Create button.") -4. Configure Basic IoT Hub Settings -* Subscription: Select your Azure subscription. -* Resource group: Choose an existing resource group or click **Create new** to create one, such as *rg-arm*. -* IoT Hub Name: Enter a unique name for your IoT Hub. This must be globally unique; for example, iot-hub-arm-64). -* Region: Select a region closest to your location or users. +4. Configure the **Basics** IoT Hub settings: +* Subscription: select your Azure subscription. +* Resource group: choose an existing resource group or click **Create new** to create one, such as "rg-arm". +* IoT hub name: Enter a unique name for your IoT Hub. This must be globally unique; for example, "iot-hub-arm-64". +* Region: select a region closest to your location or users. * Tier: Free. This updates the daily message limit accordingly: -![img4 alt-text#center](figures/04.png) +![img4 alt-text#center](figures/04.png "Configure the IoT Hub settings.") 5. Click **Next: Networking**. 6. Configure Networking: @@ -62,7 +62,7 @@ Start by creating an Azure IoT Hub. * Once deployed, you’ll see a message stating “Your deployment is complete”. * Click **Go to resource** to open the newly-created Azure IoT Hub. 12. Check IoT Hub Overview and Details. From the IoT Hub overview page, verify important details such as the hub name, region, status, and hostname, which you’ll use to connect devices: -![img5 alt-text#center](figures/05.png) +![img5 alt-text#center](figures/05.png "Verify IoT Hub overview") ## Next steps Now that your Azure IoT Hub is ready, you can proceed to register and configure your IoT devices. In the next step, you’ll learn how to register an Arm64-based IoT device and start streaming data using Python and Azure IoT SDK. diff --git a/content/learning-paths/iot/azure-iot/monitoring.md b/content/learning-paths/iot/azure-iot/monitoring.md index 10c0ada3e0..2703f8b01d 100644 --- a/content/learning-paths/iot/azure-iot/monitoring.md +++ b/content/learning-paths/iot/azure-iot/monitoring.md @@ -1,6 +1,6 @@ --- # User change -title: "Set Up Data Monitoring and Alerts with Azure Functions" +title: "Set up data monitoring and alerts with Azure Functions" weight: 7 @@ -9,10 +9,10 @@ layout: "learningpathall" In the previous section, you successfully configured Azure Stream Analytics to store incoming IoT telemetry data securely in Azure Cosmos DB. The stored sensor data is now readily accessible for further analysis, monitoring, and action. In this section, you will enhance your IoT solution by implementing real-time data monitoring and alerting capabilities using Azure Functions. -Azure Functions is a powerful, event-driven, serverless compute service provided by Azure, enabling you to execute custom code in response to specific events or triggers without the need to manage infrastructure. You will create an Azure Function that regularly queries temperature data from Cosmos DB, evaluates sensor readings against predefined thresholds, and sends notifications when critical values are exceeded,such as detecting overheating or environmental anomalies. By adding this functionality, you will build proactive monitoring into your IoT pipeline, ensuring timely responses to sensor data events and improving overall operational reliability. +Azure Functions is a lightweight, serverless compute platform provided by Azure, enabling you to execute custom code in response to specific events or triggers without the need to manage infrastructure. You'll will create an Azure Function that regularly queries temperature data from Cosmos DB, evaluates sensor readings against predefined thresholds, and sends notifications when critical values are exceeded, such as detecting overheating or environmental anomalies. By adding this functionality, you will build proactive monitoring into your IoT pipeline, ensuring timely responses to sensor data events and improving overall operational reliability. ## Azure Functions -Azure Functions is a serverless computing platform provided by Microsoft Azure, designed to enable developers to run event-driven code without having to provision or manage infrastructure. With Azure Functions, you can easily create small, focused applications or services that automatically respond to events, such as database updates, HTTP requests, IoT sensor data events, or scheduled tasks. Because Azure Functions is serverless, it automatically scales based on workload, providing elasticity, rapid deployment, and simplified maintenance, developers only pay for resources actually consumed during execution. +Azure Functions is a serverless computing platform provided by Microsoft Azure, designed to enable developers to run event-driven code without having to provision or manage infrastructure. With Azure Functions, you easily create small, focused applications or services that automatically respond to events, such as database updates, HTTP requests, IoT sensor data events, or scheduled tasks. Because Azure Functions is serverless, it automatically scales based on workload, providing elasticity, rapid deployment, and simplified maintenance, developers only pay for resources actually consumed during execution. In IoT, Azure Functions are particularly valuable for responding to real-time data events, such as sensor readings exceeding specific thresholds. You can integrate Azure Functions seamlessly with services like Azure Cosmos DB, Azure IoT Hub, or Azure Notification Hubs, enabling functions to trigger automatically when new data is received or when certain conditions are met. This flexibility allows you to build responsive, cost-effective, and efficient IoT applications that require minimal setup yet offer highly scalable, real-time processing capabilities. @@ -56,7 +56,7 @@ To overcome this limitation, local development is highly recommended for Python- For Python functions on Linux-based plans, local development and deployment represent the best-practice approach, enabling you to efficiently create, debug, test, and manage more sophisticated IoT solutions. Therefore, in this section you will use local development. ## Create an Azure Function App -You will start by creating an Azure Function App, in which you will create an Azure Function that regularly queries temperature data from Cosmos DB. In the next step, upi will add the capability to send notifications, whenever the temperature reading exceeds a predefined threshold. Proceed as follows: +You will start by creating an Azure Function App, in which you will create an Azure Function that regularly queries temperature data from Cosmos DB. In the next step, you will add the capability to send notifications, whenever the temperature reading exceeds a predefined threshold. Proceed as follows: 1. Sign in to the Azure Portal. 2. Click “Create a resource”, type “Function App”, and select it: ![img24 alt-text#center](figures/24.png) @@ -96,7 +96,7 @@ Ensure you also see a v4.x.x output, indicating compatibility with Python v2 mod ## Create Azure Function to Read Cosmos DB Data Follow these steps to create an Azure Function locally using Visual Studio Code: -1. In Visual Studio Cod, click View->Command Palette... +1. In Visual Studio Code, click View->Command Palette... 2. Type "Create Function": ![img27 alt-text#center](figures/27.png) 3. Select Azure Functions: Create Function... @@ -286,7 +286,7 @@ def cosmosdb_trigger(azcosmosdb: func.DocumentList): ) ``` -The `send_email_alert` function is responsible for sending an email notification through SendGrid whenever a sensor reading exceeds the specified temperature threshold. It constructs an email message using details about the IoT device, including the device_id, current temperature, and the event timestamp. The function utilizes SendGrid's Python SDK (SendGridAPIClient) to send the email message. If the email is successfully sent, it logs a confirmation with the status code. If the email fails, it captures and logs the error details, ensuring that any issues with email delivery can be easily identified and resolved. This function enables proactive monitoring by immediately alerting the user when potentially critical temperature conditions are detected, significantly enhancing the reliability and responsiveness of the IoT system +The `send_email_alert` function is responsible for sending an email notification through SendGrid whenever a sensor reading exceeds the specified temperature threshold. It constructs an email message using details about the IoT device, including the device_id, current temperature, and the event timestamp. The function utilizes SendGrid's Python SDK (SendGridAPIClient) to send the email message. If the email is successfully sent, it logs a confirmation with the status code. If the email fails, it captures and logs the error details, ensuring that any issues with email delivery can be easily identified and resolved. This function enables proactive monitoring by alerting users immediately when potentially critical temperature conditions are detected, significantly enhancing the reliability and responsiveness of the IoT system Now, start your function: ```console diff --git a/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md b/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md index 63029fcd11..629d8f3128 100644 --- a/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md +++ b/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md @@ -1,6 +1,6 @@ --- # User change -title: "Store Data in Azure Cosmos DB with Azure Stream Analytics" +title: "Store data in Azure Cosmos DB with Azure Stream Analytics" weight: 6 From 09a83ca76890b1353ef28d8acc7942bbe32759a8 Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Tue, 20 May 2025 11:01:14 -0700 Subject: [PATCH 13/32] Made page size overview more general. --- .../arm_linux_page_size/overview.md | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md index 53f7bfebc5..b064380d52 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md @@ -11,46 +11,30 @@ When your program asks for a memory address, the CPU doesn’t directly reach in Instead, it goes through the **virtual memory** system, where it asks for a specific chunk of memory called a **page**. Pages map virtual memory location to physical memory locations in RAM or swap space. -### Page Table Entries (PTEs) +## What’s a Memory “Page”? -Virtual address translation is performed via a multi-level page table lookup. The **leaf-level** entry, commonly called the **Page-Table Entry (PTE)**: +Think of your computer’s memory like a big sheet of graph paper. Each **page** is one square on that sheet. The **page table** is the legend that tells the computer which square (virtual address) maps to which spot in real RAM. -1. Maps the **Virtual Page Number (VPN)** to a **Physical Frame Number (PFN)**. -2. Indicates whether the page is resident or needs to be read from swap or RAM. - -On a 4K page size system, each leaf PTE is 8 bytes, so one 4 KiB page of page-table memory holds 512 PTEs (512 × 8 B = 4 KB). When you dereference a virtual address, the system performs operations on the data to compute the **physical address** of the data being looked up. - -![PTE Flow](images/pte.png) - - -## Page Size Differences Illustrated - -To help make page sizing more clear, assume you have created a database system that can store and retrieve either images, OR tweets, based on the mode set at install-time. - -### 4K Page Size -With our system set to a 4K page size, the system can only store a small amount of data in each page. At around 300 bytes per tweet, when the system retrieves a tweet from memory, it will most likely be retrieved in a single page load. This is very efficient, since the CPU has to do less work to find the data it needs, and the structure size (page) is optimized for the size of the data its storing (tweet). At 4K, best-case, the system can store about 13 tweets in a single 4K page. - -When the system is set to "Image Only" mode, since an image is a larger amount of data (assume 1MB or more for this example), it will most likely be retrieved in multiple 4K page loads. This is less efficient, as the CPU has to do more work to retrieve all bytes of the image. If the image is 1MB, the system will have to reserve 256 4K pages (256 * 4K = 1MB). - -Given this info, you decide to set the page size to 64K to see how performance changes. - -### 64K Page Size -With our system now set to 64K page size, the system reserves pages in 64K chunks. In our tweet example, we can now store about 218 tweets per page. If we're working with groupings of the same tweets over and over, the system needs to reserve and load fewer pages to get the data it needs to run the application, resulting in a fast and efficient system. This is because the CPU has to do less page loads to find the data it needs. +--- -When the system is set to "Image Only" mode, since an image is a larger amount of data (1MB or more), the image will still need to be retrieved in multiple 64K page loads. However, this is more inefficient than the 4K page size; if the image is 1MB, the system will only need to load and store 16 pages at a 64K page size (16 * 64K = 1MB) vs 256 pages of memory (256 * 4K = 1MB) at a 4K page size. +## Small Pages (4 KB) vs. Big Pages (64 KB) -### Inefficiencies -Inefficiencies occur when the system is set to a page size that does not consistently match the data size of the objects you are working with. For example, if the system is set to 64K page size, and the application only needs one tweet, the system loaded more data (a 64K page) than was actually needed. +| Aspect | 4 KB Pages | 64 KB Pages | +|-----------------|----------------------------------------|------------------------------------------| +| **Size** | Small “bricks” (4 KB each) | Big “bricks” (64 KB each) | +| **Flexibility** | Very flexible—good for lots of tiny bits of data | Less flexible—best when data comes in large chunks | +| **Efficiency** | Needs more entries (more bookkeeping) | Needs fewer entries (less bookkeeping) | +| **Waste** | At most 4 KB unused per page | Up to 64 KB unused if not fully used | -When loading a single image, with the page size is larger, the page size is better rightsized for the data the application works with -- it may need to load 16 pages of 64K each, but it is still less than the 256 pages of 4K each that it would need to load if the system was set to 4K page size. +--- -In addition to the amount of page loading the CPU has to do, the system also has to reserve memory to store and track metadata for each page. For 4 KiB pages, each page-table page holds 512 entries (8 B each), so tracking 256 pages only consumes one 4 KiB page of metadata.. Internal fragmentation can occur when the system reserves memory for pages that are not used and/or modified, and this can lead to wasted memory and performance issues especially with larger page sizes. +## When to Choose Which -To add further complexity, if you choose to add the ability for the system to store BOTH images and tweets (not one at a time), the system will need to load both types of data, and the page size will need to be set to a size that is best suited to accommodate both types of data and their retrieval patterns. +- **4 KB pages** are the safe, default choice. They let you use memory in small slices and keep waste low. Since they are smaller, you need more of them when handling larger memory footprint applications. -This leads to more performance hits, as the system will most likely now always load fewer or more pages than necessary for each type of data. +- **64 KB pages** shine when you work with big, continuous data—like video frames or large database caches—because they cut down on management overhead. But they can waste more memory if you don’t use the whole page. -It may be difficult to determine the best page size for your application, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application and data size changes. +When rightsizing your page size, its important to **try both** under real-world benchmarking conditions, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application, usage patterns, and data size changes. This learning path will guide you how to change the page size, so you can begin experimenting to see which fits best. From b941b23dcb91390e34a8858597bf0442d32a1d9c Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Tue, 20 May 2025 11:08:18 -0700 Subject: [PATCH 14/32] Removing install guide, added warning to LP --- content/install-guides/arm_linux_page_size.md | 305 ------------------ .../arm_linux_page_size/overview.md | 13 +- 2 files changed, 8 insertions(+), 310 deletions(-) delete mode 100644 content/install-guides/arm_linux_page_size.md diff --git a/content/install-guides/arm_linux_page_size.md b/content/install-guides/arm_linux_page_size.md deleted file mode 100644 index 7d0d08b386..0000000000 --- a/content/install-guides/arm_linux_page_size.md +++ /dev/null @@ -1,305 +0,0 @@ ---- -additional_search_terms: -- linux -- cloud - -layout: installtoolsall -minutes_to_complete: 30 -author: Geremy Cohen -multi_install: false -multitool_install_part: false -title: Increasing Linux Kernel Page Size on Arm-based Systems -weight: 1 ---- - - -{{% notice Backup and Test before trying in Production%}} -Modifying the Linux kernel page size can lead to system instability or failure. It is recommended to backup your system and test the changes in a non-production environment before applying to production systems. -{{% /notice %}} - - -## Overview -Most Linux distributions ship with a default kernel page size of 4KB. When running on Arm, your options for pagesize are 4K, 16K, or 64K; this install guide walks you through install a 64K page size kernel on Arm-based Linux systems. - -## Common Steps - -1. Run apt update to ensure you have the latest package information: - -```bash -sudo apt-get -y update -``` -2. Check the current page size and kernel version: - -```bash -getconf PAGESIZE -uname -r -``` -The output should be: - -```output -4096 -6.1.0-34-cloud-arm64 -``` - -This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. - - -## Instructions for Ubuntu 22.04+ - -To install a 64K page size kernel on Ubuntu 22.04+, follow these steps: - -1. Install dependencies and 64K kernel: - -```bash -sudo apt-get -y install git build-essential autoconf automake libtool gdb wget linux-generic-64k -``` -2. Instruct grub to load the 64K kernel by default: - -```bash -echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee /etc/default/grub.d/local-order.cfg -```` - -3. Update grub then reboot: - -```bash -sudo update-grub -sudo reboot -``` - -4. Upon reboot, check the kernel page size and name: - -```bash -getconf PAGESIZE -uname -r -``` - -The output should be: - -```output -65536 -6.8.0-59-generic-64k -``` - -This indicates the current page size is 64K and you are running the new 64K kernel. - -## Reverting back to the original 4K kernel - -To revert back to the original 4K kernel, run the following commands: - -```bash -echo "GRUB_FLAVOUR_ORDER=generic" | sudo tee /etc/default/grub.d/local-order.cfg -sudo update-grub -sudo reboot -``` - -Upon reboot, check the kernel page size and name again: - -4. Upon reboot, check the kernel page size and name: - -```bash -getconf PAGESIZE -uname -r -``` - -The output should be: - -```output -4096 -6.11.0-1013-gcp -``` -This confirms the current page size is 4KB and you are running the original kernel. - -## Instructions for Debian 11+ - -Unlike Ubuntu, Debian does not provide a 64K kernel via apt, so you will need to compile it from source. There are two ways to do this: 1) download the source from the kernel.org website, or 2) use the Debian source package. This guide will use the Debian source package. - -### Install from Debian Source Package (Easiest, Not Customizable) - -To install a 64K page size kernel via package manager, follow these steps: - -1. Install dependencies: - -```bash -sudo apt-get -y install git build-essential autoconf automake libtool libncurses-dev bison flex libssl-dev libelf-dev bc debhelper-compat rsync -``` - -2. Download the kernel and cd to its directory: -```bash - -# Fetch the actual kernel source -apt source linux -# Change to kernel source dir -cd -- */ -``` - -### Install from kernel.org (Advanced, More Customizable) - -{{% notice Yo %}} -If you already completed the step of installing from a Debian Source Package, you can skip this section. -{{% /notice %}} - -1. Visit https://cdn.kernel.org/pub/linux/kernel/v6.x/ and download the .tar.gz of the kernel version you want to install. -2. Untar/gzip the file to its own directory. -3. Cd into the kernel source directory. - -### Common Installer Steps - -Now that you have the kernel source, follow these steps to build and install the kernel: -```bash -# Use running config as template for new config -cp /boot/config-$(uname -r) .config - -# Modify config to enable 64K page size -sed -i 's/^CONFIG_ARM64_4K_PAGES=y/# CONFIG_ARM64_4K_PAGES is not set/' .config -sed -i 's/^# CONFIG_ARM64_64K_PAGES is not set/CONFIG_ARM64_64K_PAGES=y/' .config -echo '# CONFIG_ARM64_16K_PAGES is not set' >> .config - -# Build the kernel -make ARCH=arm64 olddefconfig - -# Set 64 for kernel name suffix -sed -i 's/^EXTRAVERSION =.*/EXTRAVERSION = -64k/' Makefile - -# Build Debian packages -make -j$(nproc) ARCH=arm64 bindeb-pkg - -# 8. Install -cd .. -sudo dpkg -i linux-image-*64k*.deb linux-headers-*64k*.deb -``` - -The system is now ready to reboot: -```bash -sudo reboot -``` -After reboot, check the kernel page size: -```bash -getconf PAGESIZE -uname -r -``` -The output should be: - -```output -65536 -6.12.22-64k -``` -This indicates the current page size is 64K, and you are using the new customer made 64k kernel. - -### Reverting back to the original 4K kernel - -To revert back to the kernel we started with: - -```bash -dpkg-query -W -f='${Package}\n' 'linux-image-*-64k*' 'linux-headers-*-64k*' \ - | xargs --no-run-if-empty sudo dpkg -r -sudo update-grub -sudo reboot -``` -The system will now reboot into the original 4K kernel. To check the page size, run the following command: -```bash -getconf PAGESIZE -uname -r -``` - -The output should be: - -```output -4096 -6.1.0-34-cloud-arm64 -``` -This indicates the current page size is 4KB and you are using the kernel you started with. - -## Instructions for CentOS 9+ - -To install a 64K page size kernel on CentOS 9, follow these steps: - -1. Install the kernel-64k package: - - ```bash - sudo dnf -y install kernel-64k - ``` - -2. Set the kernel-64k as the default kernel and add necessary kernel arguments: - - ```bash - k=$(echo /boot/vmlinuz*64k) - sudo grubby --set-default "$k" \ - --update-kernel "$k" \ - --args "crashkernel=2G-:640M" - ``` - - -4. Reboot the system: - - ```bash - sudo reboot - ``` - -5. Verify the page size and kernel version: - - ```bash - getconf PAGESIZE - uname -r - ``` - - The output should be: - - ```output - 65536 - 5.14.0-583.el9.aarch64+64k - ``` - -### Reverting back to the original 4K kernel on CentOS - -To revert to the original 4K kernel, run: - -```bash -# 1) Get your running kernel (should be something like "5.14.0-583.el9.aarch64+64k") -curr=$(uname -r) - -# 2) Strip the "+64k" suffix -base=${curr%+64k} - -# 3) Build the full path to the 4K kernel image -k4="/boot/vmlinuz-${base}" - -# 4) Sanity‐check that it actually exists -if [[ ! -e "$k4" ]]; then - echo "❌ Cannot find 4K kernel image at $k4" - exit 1 -fi - -echo "✅ Found 4K kernel: $k4" - -# 5) (Optional) remove any crashkernel args if you added them earlier -sudo grubby --remove-args="crashkernel=2G-:640M" --update-kernel "$k4" - -# 6) Finally, set it as the default -sudo grubby --set-default "$k4" - -# Reboot the system -sudo reboot -``` - -Upon reboot, verify: - -```bash -getconf PAGESIZE -uname -r -``` - -The output should be: - -```output -4096 - -``` - -## Conclusion -You have successfully installed a 64K page size kernel on your Arm-based Linux system. You can now take advantage of the larger page size for improved performance in certain workloads. If you need to revert back to the original 4K kernel, you can do so by following the steps outlined above. - -## Additional Resources -- [Kernel.org](https://kernel.org) -- [Debian Kernel Source](https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_kernel_source) -- [Ubuntu Kernel Source](https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel) - diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md index b064380d52..683274b228 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md @@ -30,17 +30,20 @@ Think of your computer’s memory like a big sheet of graph paper. Each **page** ## When to Choose Which -- **4 KB pages** are the safe, default choice. They let you use memory in small slices and keep waste low. Since they are smaller, you need more of them when handling larger memory footprint applications. +- **4 KB pages** are the safe, default choice. They let you use memory in small slices and keep waste low. Since they are smaller, you need more of them when handling larger memory footprint applications. This creates more overhead for the CPU to manage, but may be worth it for the flexibility. They are great for applications that need to access small bits of data frequently, like web servers or databases with lots of small transactions. -- **64 KB pages** shine when you work with big, continuous data—like video frames or large database caches—because they cut down on management overhead. But they can waste more memory if you don’t use the whole page. +- **64 KB pages** shine when you work with big, continuous data—like video frames or large database caches—because they cut down on management overhead. They can waste more memory if you don’t use the whole page, but they can also speed up access times for large data sets. When rightsizing your page size, its important to **try both** under real-world benchmarking conditions, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application, usage patterns, and data size changes. -This learning path will guide you how to change the page size, so you can begin experimenting to see which fits best. +## Choose the OS to experiment with -## Choose Your OS +{{% notice Do not test on Production%}} +Modifying the Linux kernel page size can lead to system instability or failure. Perform testing in a non-production environment before applying to production systems. +{{% /notice %}} + +This learning path will guide you how to change (and revert back) the page size, so you can begin experimenting to see which fits best. The steps to install the 64K page size kernel are different for each OS, so be sure to select the correct one. -To begin, select the OS you are using. The steps to install the 64K page size kernel are different for each OS, so be sure to select the correct one. - [Ubuntu](../ubuntu) - [Debian](../debian) From 5e7d28ba4653a9574b439bf71f298b5c3fcb1b9e Mon Sep 17 00:00:00 2001 From: pareenaverma Date: Tue, 20 May 2025 18:34:53 +0000 Subject: [PATCH 15/32] Tech review of MCP server LP --- .../mcp-ai-agent/_index.md | 15 ++-- .../mcp-ai-agent/_next-steps.md | 0 .../mcp-ai-agent/intro-to-mcp-uv.md | 52 +------------- .../mcp-ai-agent/mcp-client.md | 40 ++++++++--- .../mcp-ai-agent/mcp-server.md | 64 ++++++++++++------ .../mcp-ai-agent/mcp.png | Bin 6 files changed, 87 insertions(+), 84 deletions(-) rename content/learning-paths/{servers-and-cloud-computing => cross-platform}/mcp-ai-agent/_index.md (69%) rename content/learning-paths/{servers-and-cloud-computing => cross-platform}/mcp-ai-agent/_next-steps.md (100%) rename content/learning-paths/{servers-and-cloud-computing => cross-platform}/mcp-ai-agent/intro-to-mcp-uv.md (54%) rename content/learning-paths/{servers-and-cloud-computing => cross-platform}/mcp-ai-agent/mcp-client.md (71%) rename content/learning-paths/{servers-and-cloud-computing => cross-platform}/mcp-ai-agent/mcp-server.md (50%) rename content/learning-paths/{servers-and-cloud-computing => cross-platform}/mcp-ai-agent/mcp.png (100%) diff --git a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/_index.md b/content/learning-paths/cross-platform/mcp-ai-agent/_index.md similarity index 69% rename from content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/_index.md rename to content/learning-paths/cross-platform/mcp-ai-agent/_index.md index d7d66b6818..4999c1eebd 100644 --- a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/_index.md +++ b/content/learning-paths/cross-platform/mcp-ai-agent/_index.md @@ -1,5 +1,5 @@ --- -title: Deploy an MCP server on a Raspberry Pi 5 and interact with it using the AI agent +title: Deploy an MCP server on a Raspberry Pi 5 and interact with it using an AI agent draft: true cascade: @@ -7,16 +7,16 @@ cascade: minutes_to_complete: 30 -who_is_this_for: This Learning Path targets LLM and IoT developers who already know their way around Large Language Model (LLM) concepts and networking. It walks you through deploying a lightweight Model Context Protocol (MCP) server on a Raspberry Pi 5 and shows you how to interact with it via the OpenAI-Agent SDK. +who_is_this_for: This Learning Path targets LLM and IoT developers who are familiar with Large Language Model (LLM) concepts and networking. You will learn how to deploy a lightweight Model Context Protocol (MCP) server on a Raspberry Pi 5 and interact with it via the OpenAI-Agent SDK. learning_objectives: - - Understand how to Deploy a lightweight Model Context Protocol (MCP) server on Raspberry Pi 5 + - Deploy a lightweight Model Context Protocol (MCP) server on Raspberry Pi 5 - Design and register custom tools for the AI Agent - Create custom endpoints - - Learn uv — a fast, efficient Python package manager + - Learn about uv — a fast, efficient Python package manager prerequisites: - - Rapberry Pi + - A [Raspberry Pi 5](https://www.raspberrypi.com/products/raspberry-pi-5/) - Basic understanding of Python and prompt engineering. - Understanding of LLM and AI Agent fundamentals @@ -34,6 +34,11 @@ tools_software_languages: operatingsystems: - Linux +### Cross-platform metadata only +shared_path: true +shared_between: + - iot + - embedded-and-microcontrollers further_reading: - resource: diff --git a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/_next-steps.md b/content/learning-paths/cross-platform/mcp-ai-agent/_next-steps.md similarity index 100% rename from content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/_next-steps.md rename to content/learning-paths/cross-platform/mcp-ai-agent/_next-steps.md diff --git a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/intro-to-mcp-uv.md b/content/learning-paths/cross-platform/mcp-ai-agent/intro-to-mcp-uv.md similarity index 54% rename from content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/intro-to-mcp-uv.md rename to content/learning-paths/cross-platform/mcp-ai-agent/intro-to-mcp-uv.md index 1fe800e047..e2cf7da879 100644 --- a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/intro-to-mcp-uv.md +++ b/content/learning-paths/cross-platform/mcp-ai-agent/intro-to-mcp-uv.md @@ -14,11 +14,11 @@ Think of it as USB-C for AI: once a tool or data source speaks MCP, any complian ### Why use MCP? - **Plug-and-play integrations:** A growing catalog of pre-built MCP servers (filesystem, shell, vector stores, web-scraping, etc.) gives your agent instant super-powers with zero custom glue code. -- **Model/vendor agnostic:** Because the protocol lives outside the model, you can swap GPT-4, Claude, or your own fine-tuned model without touching the integration layer. +- **Model/vendor agnostic:** Because the protocol lives outside the model, you can swap models like GPT-4, Claude, or your own fine-tuned model without touching the integration layer. - **Security by design:** MCP encourages running servers inside your own infrastructure, so sensitive data never leaves the perimeter unless you choose. -- **Cross-ecosystem momentum:** Recent roll-outs—from an official C# SDK to Wix’s production MCP server and Microsoft’s Azure support—show the spec is gathering real-world traction. +- **Cross-ecosystem momentum:** Recent roll-outs—from an official C# SDK to Wix’s production MCP server and Microsoft’s Azure support—show the MCP spec is gathering real-world traction. ### High-level architecture ![mcp server](./mcp.png) @@ -32,51 +32,3 @@ Think of it as USB-C for AI: once a tool or data source speaks MCP, any complian Learn more about AI Agents in the [AI Agent on CPU learning path](https://learn.arm.com/learning-paths/servers-and-cloud-computing/ai-agent-on-cpu/). {{% /notice %}} -## UV: The Fast, All-in-One Python Package Manager - -**uv** is a next-generation, Rust-based package manager that unifies pip, virtualenv, Poetry, and more—offering 10×–100× faster installs, built-in virtual environment handling, robust lockfiles, and full compatibility with the Python ecosystem. - -### Install uv -- macOS / Linux -```bash -curl -LsSf https://astral.sh/uv/install.sh | sh -``` -- Windows -```bash -powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" -``` - -### Initialize a Project -1. Create & enter your project folder: -```bash -mkdir my-project && cd my-project -``` -2. Run -```bash -uv init -``` - -This scaffolds: -- .venv/ (auto-created virtual environment) -- pyproject.toml (project metadata & dependencies) -- .python-version (pinned interpreter) -- README.md, .gitignore, and a sample main.py - -### Install Dependencies -- Add one or more packages to your project: -```bash -uv add requests numpy pandas -``` -> Updates both pyproject.toml and the lockfile (uv.lock) - -- Remove a package (and its unused sub-deps): -```bash -uv remove numpy -``` - -- Install from an existing requirements.txt (e.g. when migrating): -```bash: -uv pip install -r requirements.txt -``` - -All installs happen inside your project’s .venv, and UV’s lockfile guarantees repeatable environments. \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp-client.md b/content/learning-paths/cross-platform/mcp-ai-agent/mcp-client.md similarity index 71% rename from content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp-client.md rename to content/learning-paths/cross-platform/mcp-ai-agent/mcp-client.md index 843f17e587..d99f3d61ca 100644 --- a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp-client.md +++ b/content/learning-paths/cross-platform/mcp-ai-agent/mcp-client.md @@ -1,31 +1,49 @@ --- -title: Build & Run an AI Agent on Your Workstation +title: Build & Run an AI Agent on your development machine weight: 4 ### FIXED, DO NOT MODIFY layout: learningpathall --- +In this section you will learn how to setup an AI Agent on your development machine. You will then connect your MCP server running on the Raspberry Pi 5 to it. + +These commands were tested on an Linux Arm development machine. + ### Create an AI Agent and point it at your Pi's MCP Server -1. Bootstrap the Agent Project +1. Install `uv` on your development machine: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` +2. Create a directory for the Agent: ```bash -# create & enter folder mkdir mcp-agent && cd mcp-agent ``` -2. scaffold with **uv** +3. Setup the directory to use `uv`: ```bash uv init ``` -3. install **OpenAI Agents SDK** + **dotenv** + +This command adds: +- .venv/ (auto-created virtual environment) +- pyproject.toml (project metadata & dependencies) +- .python-version (pinned interpreter) +- README.md, .gitignore, and a sample main.py + +4. Install **OpenAI Agents SDK** + **dotenv** ```bash uv add openai-agents python-dotenv ``` -4. Create a `.env` file with your OpenAI key: +5. Create a `.env` file with your OpenAI key: ```bash echo -n "OPENAI_API_KEY=" > .env ``` -### Write the Agent Client (main.py) +### Write the Python script for the Agent Client + +Use a file editor of your choice and replace the content of the sample `main.py` with the content shown below: + ```python import asyncio, os from dotenv import load_dotenv @@ -38,7 +56,7 @@ from agents import Agent, Runner, set_default_openai_key from agents.mcp import MCPServerSse from agents.model_settings import ModelSettings -async def run(mcp_server: list[MCPServer]): +async def run(mcp_server: list[MCPServerSse]): set_default_openai_key(os.getenv("OPENAI_API_KEY")) agent = Agent( @@ -70,10 +88,14 @@ if __name__ == "__main__": ``` ### Execute the Agent + +You are now ready to the run the agent and test it with your running MCP server: + +Run the `main.py` python script: ```bash uv run main.py ``` -You should see output like: +The output should look like: ```output Running: What is the CPU temperature? Response: The current CPU temperature is 48.8°C. diff --git a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp-server.md b/content/learning-paths/cross-platform/mcp-ai-agent/mcp-server.md similarity index 50% rename from content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp-server.md rename to content/learning-paths/cross-platform/mcp-ai-agent/mcp-server.md index 9de994484a..93e163b9d6 100644 --- a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp-server.md +++ b/content/learning-paths/cross-platform/mcp-ai-agent/mcp-server.md @@ -6,26 +6,25 @@ weight: 3 layout: learningpathall --- -## Expose Raspberry Pi MCP Server via ngrok +## Setup an MCP Server on Raspberry Pi 5 -This guide shows you how to: +In this section you will learn how to: -1. Install **uv** (the Rust-powered Python manager) -2. Bootstrap a simple **MCP** server on your Raspberry Pi that reads the CPU temperature and searches the weather data -3. Expose it to the internet with **ngrok** - -### Prerequisites - -- A **Raspberry Pi 5** (or other ARMv8 Pi) running Raspberry Pi OS (64-bit) -- Basic familiarity with Python and the terminal +1. Install uv (the Rust-powered Python package manager) +2. Bootstrap a simple MCP server on your Raspberry Pi 5 that reads the CPU temperature and searches the weather data +3. Expose the MCP server to the internet with **ngrok** +You will run all the commands shown below on your Raspberry Pi 5 running Raspberry Pi OS (64-bit) #### 1. Install uv -On Raspberry Pi Terminal: +On Raspberry Pi Terminal, install `uv`: ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` +**uv** is a next-generation, Rust-based package manager that unifies pip, virtualenv, Poetry, and more—offering 10×–100× faste +r installs, built-in virtual environment handling, robust lockfiles, and full compatibility with the Python ecosystem. + {{% notice Note %}} After the script finishes, restart your terminal so that the uv command is on your PATH. {{% /notice %}} @@ -36,22 +35,28 @@ After the script finishes, restart your terminal so that the uv command is on yo mkdir mcp cd mcp ``` -2. Initialize with uv (this creates pyproject.toml, .venv/, etc.): +2. Initialize with `uv`: ```bash uv init ``` +This command adds: +- .venv/ (auto-created virtual environment) +- pyproject.toml (project metadata & dependencies) +- .python-version (pinned interpreter) +- README.md, .gitignore, and a sample main.py + 3. Install the dependencies: -```uv +```bash uv pip install fastmcp==2.2.10 uv add requests ``` -#### 3. Write Your MCP Server (server.py) -1. Create the server file: +#### 3. Build your MCP Server +1. Create a python file for your MCP server named `server.py`: ```bash touch server.py ``` -2. Edit `server.py` with the following contents: +2. Use a file editor of your choice and copy the following content into `server.py`: ```bash import subprocess, re from mcp.server.fastmcp import FastMCP @@ -89,13 +94,28 @@ if __name__ == "__main__": ``` #### 4. Run the MCP Server + +Run the python script to deploy the MCP server: + ```python uv run server.py ``` -By default, FastMCP will listen on port **8000** and serve your tools via **Server-Sent Events (SSE)**. +By default, FastMCP will listen on port 8000 and serve your tools via Server-Sent Events (SSE). + +The output should look like: + +```output +INFO: Started server process [2666] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) +``` #### 5. Install & Configure ngrok -1. Add ngrok’s APT repo and install: + +You will now use ngrok to expose your locally running MCP server to the public internet over HTTPS. + +1. Add ngrok’s repo to the apt package manager and install: ```bash curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \ | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null \ @@ -104,12 +124,16 @@ curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \ && sudo apt update \ && sudo apt install ngrok ``` +The ngrok agent authenticates with an authtoken. You will need to authenticate your account with the token which is available on the [ngrok dashboard](https://dashboard.ngrok.com/get-started/your-authtoken). + 2. Authenticate your account: ```bash ngrok config add-authtoken ``` -3. Expose port 8000: +Replace `YOUR_NGROK_AUTHTOKEN` with your token from the ngrok dashboard. + +3. Expose the port 8000: ```bash ngrok http 8000 ``` -4. Copy the generated HTTPS URL (e.g. `https://abcd1234.ngrok-free.app`)—you’ll use this as your MCP endpoint. \ No newline at end of file +4. Copy the generated HTTPS URL (e.g. `https://abcd1234.ngrok-free.app`)—you’ll use this as your MCP endpoint. diff --git a/content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp.png b/content/learning-paths/cross-platform/mcp-ai-agent/mcp.png similarity index 100% rename from content/learning-paths/servers-and-cloud-computing/mcp-ai-agent/mcp.png rename to content/learning-paths/cross-platform/mcp-ai-agent/mcp.png From f79d902012c78ea801a4df0f0ca042f605c492cb Mon Sep 17 00:00:00 2001 From: Geremy Cohen Date: Tue, 20 May 2025 12:07:08 -0700 Subject: [PATCH 16/32] Final test of the instructions on each OS --- .../arm_linux_page_size/centos.md | 81 ++++++++++--------- .../arm_linux_page_size/debian.md | 40 ++++----- .../arm_linux_page_size/overview.md | 27 +++---- .../arm_linux_page_size/ubuntu.md | 27 ++++--- 4 files changed, 93 insertions(+), 82 deletions(-) diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md index 3028606ef5..040204405e 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md @@ -6,72 +6,80 @@ layout: learningpathall --- ### Verify current page size -Verify you’re on a 4 KB pagesize kernel: +Verify you’re on a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to (the important part is the 4096 value): +The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output 4096 6.1.0-34-cloud-arm64 ``` -This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. - +The 4096 indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. ### Install the kernel-64k package: +Enter the below `dnf` command to install the 64k kernel: + ```bash sudo dnf -y install kernel-64k ``` -### Set the kernel-64k as the default kernel and add necessary kernel arguments: +You should see a page or so of similar output ending with: - ```bash - k=$(echo /boot/vmlinuz*64k) - sudo grubby --set-default "$k" \ - --update-kernel "$k" \ - --args "crashkernel=2G-:640M" - ``` +```output +... +Installed: + kernel-64k-5.14.0-583.el9.aarch64 kernel-64k-core-5.14.0-583.el9.aarch64 + kernel-64k-modules-5.14.0-583.el9.aarch64 kernel-64k-modules-core-5.14.0-583.el9.aarch64 -### Reboot the system: +Complete! +``` - ```bash - sudo reboot - ``` +### Set the kernel-64k as the default kernel and reboot + +Enter the following to set the newly installed 64K kernel as default and reboot: + +```bash +k=$(echo /boot/vmlinuz*64k) +sudo grubby --set-default "$k" --update-kernel "$k" +sudo reboot +``` ### Verify the page size and kernel version: +Upon reboot, check the kernel page size and name once again to confirm the changes: - ```bash - getconf PAGESIZE - uname -r - ``` +```bash +getconf PAGESIZE +uname -r +``` - The output should be: +The output should be similar to below -- like before, the full kernel name may vary, but the first line should always be **65536**: - ```output - 65536 - 5.14.0-583.el9.aarch64+64k - ``` +```output +65536 +5.14.0-583.el9.aarch64+64k +``` ## Reverting back to the original 4K kernel on CentOS -To revert to the original 4K kernel, run: +To revert to the original 4K kernel, enter the following: ```bash -# 1) Get your running kernel (should be something like "5.14.0-583.el9.aarch64+64k") +# Get your running kernel (should be something like "5.14.0-583.el9.aarch64+64k") curr=$(uname -r) -# 2) Strip the "+64k" suffix +# Strip the "+64k" suffix base=${curr%+64k} -# 3) Build the full path to the 4K kernel image +# Build the full path to the 4K kernel image k4="/boot/vmlinuz-${base}" -# 4) Sanity‐check that it actually exists +# Sanity‐check that it actually exists if [[ ! -e "$k4" ]]; then echo "Cannot find 4K kernel image at $k4" exit 1 @@ -79,26 +87,27 @@ fi echo "Found 4K kernel: $k4" -# 5) (Optional) remove any crashkernel args if you added them earlier +# remove any crashkernel args sudo grubby --remove-args="crashkernel=2G-:640M" --update-kernel "$k4" -# 6) Finally, set it as the default +# set it as the default sudo grubby --set-default "$k4" # Reboot the system sudo reboot ``` -Upon reboot, verify: +Upon reboot, verify you’re on a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` - -The output should be: +The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output 4096 - -``` \ No newline at end of file +6.1.0-34-cloud-arm64 +``` + +The 4096 indicates the current page size has been reverted to 4KB. \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md index 443bc0d60b..5fec2e3cb8 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md @@ -8,29 +8,29 @@ layout: learningpathall Debian does not provide a 64K kernel via apt, so you will need to compile it from source. There are two ways to do this: 1) download the source from the kernel.org website, or 2) use the Debian source package. This guide will use the Debian source package. ### Verify current page size -Verify you’re on a 4 KB pagesize kernel: +Verify you’re on a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to (the important part is the 4096 value): +The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output 4096 6.1.0-34-cloud-arm64 ``` -This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. +The 4096 indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. - -### Install from Debian Source Package (Easiest, Not Customizable) +### Install from Debian Source Package To install a 64K page size kernel via package manager, follow these steps: -First, install dependencies: +First, update, and install dependencies: ```bash +sudo apt-get -y update sudo apt-get -y install git build-essential autoconf automake libtool libncurses-dev bison flex libssl-dev libelf-dev bc debhelper-compat rsync ``` @@ -40,7 +40,7 @@ Download the kernel and cd to its directory: # Fetch the actual kernel source apt source linux # Change to kernel source dir -cd -- */ +cd -- linux*/ ``` ## Build and install the kernel @@ -61,10 +61,10 @@ make ARCH=arm64 olddefconfig # Set 64 for kernel name suffix sed -i 's/^EXTRAVERSION =.*/EXTRAVERSION = -64k/' Makefile -# Build Debian packages +# Build new kernel config as Debian packages make -j$(nproc) ARCH=arm64 bindeb-pkg -# 8. Install +# install the Debian packages cd .. sudo dpkg -i linux-image-*64k*.deb linux-headers-*64k*.deb ``` @@ -73,22 +73,24 @@ The system is now ready to reboot: ```bash sudo reboot ``` -After reboot, check the kernel page size: +Upon reboot, check the kernel page size and name once again to confirm the changes: + ```bash getconf PAGESIZE uname -r ``` -The output should be: + +The output should be similar to below -- like before, the full kernel name may vary, but the first line should always be **65536**: ```output 65536 6.12.22-64k ``` -This indicates the current page size is 64K, and you are using the new customer made 64k kernel. +This indicates the current page size is 64K, and you are using the new custom made 64k kernel. ## Reverting back to the original 4K kernel -To revert back to the kernel we started with: +To revert back to the kernel we started with, enter: ```bash dpkg-query -W -f='${Package}\n' 'linux-image-*-64k*' 'linux-headers-*-64k*' \ @@ -96,16 +98,18 @@ dpkg-query -W -f='${Package}\n' 'linux-image-*-64k*' 'linux-headers-*-64k*' \ sudo update-grub sudo reboot ``` -The system will now reboot into the original 4K kernel. To check the page size, run the following command: + +Upon reboot, verify you’re on a 4 KB pagesize kernel by entering the following commands: + ```bash getconf PAGESIZE uname -r -``` - -The output should be: +``` +The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output 4096 6.1.0-34-cloud-arm64 ``` -This indicates the current page size is 4KB and you are using the kernel you started with. \ No newline at end of file + +The 4096 indicates the current page size has been reverted to 4KB. \ No newline at end of file diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md index 683274b228..8820323dff 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md @@ -13,20 +13,8 @@ Instead, it goes through the **virtual memory** system, where it asks for a spec ## What’s a Memory “Page”? -Think of your computer’s memory like a big sheet of graph paper. Each **page** is one square on that sheet. The **page table** is the legend that tells the computer which square (virtual address) maps to which spot in real RAM. +Think of your computer’s memory like a big sheet of graph paper. Each **page** is one square on that sheet. The **page table** is the legend that tells the computer which square (virtual address) maps to which spot in real RAM. On x86, 4K is the only pagesize option, but Arm-based systems allow you to set 4K, 16K, or 64K page sizes to fine tune performance of your applications. This tutorial only covers switching between 4K and 64K page sizes. ---- - -## Small Pages (4 KB) vs. Big Pages (64 KB) - -| Aspect | 4 KB Pages | 64 KB Pages | -|-----------------|----------------------------------------|------------------------------------------| -| **Size** | Small “bricks” (4 KB each) | Big “bricks” (64 KB each) | -| **Flexibility** | Very flexible—good for lots of tiny bits of data | Less flexible—best when data comes in large chunks | -| **Efficiency** | Needs more entries (more bookkeeping) | Needs fewer entries (less bookkeeping) | -| **Waste** | At most 4 KB unused per page | Up to 64 KB unused if not fully used | - ---- ## When to Choose Which @@ -34,10 +22,19 @@ Think of your computer’s memory like a big sheet of graph paper. Each **page** - **64 KB pages** shine when you work with big, continuous data—like video frames or large database caches—because they cut down on management overhead. They can waste more memory if you don’t use the whole page, but they can also speed up access times for large data sets. -When rightsizing your page size, its important to **try both** under real-world benchmarking conditions, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application, usage patterns, and data size changes. +When rightsizing your page size, its important to **try both** under real-world benchmarking conditions, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application, usage patterns, and data size changes. Althoug this tutorial only covers switching between 4K and 64K page sizes, you can see from the below table that in some cases, you may find a sweet spot in between 4K and 64K at a 16K page size: + + +| Aspect | 4K Pages | 64K Pages | +|-----------------|--------------------------------------|----------------------------------------| +| **Size** | Small “bricks” (4 KB each) | Big “bricks” (64 KB each) | +| **Flexibility** | Very flexible—good for lots of tiny bits of data | Less flexible—best when data comes in large chunks | +| **Efficiency** | Needs more entries (more bookkeeping) | Needs fewer entries (less bookkeeping) | +| **Waste** | At most 4 KB unused per page | Up to 64 KB unused if not fully used | -## Choose the OS to experiment with +##### Summary of page size differences +## Experiment to see which works best for your workload {{% notice Do not test on Production%}} Modifying the Linux kernel page size can lead to system instability or failure. Perform testing in a non-production environment before applying to production systems. {{% /notice %}} diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md index 454a9ec1aa..46e156ffe3 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md @@ -8,28 +8,29 @@ layout: learningpathall To install a 64K page size kernel on Ubuntu 22.04+, follow these steps: ### Verify current page size -Verify you’re on a 4 KB pagesize kernel: +Verify you’re on a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to (the important part is the 4096 value): +The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output 4096 6.1.0-34-cloud-arm64 ``` -This indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. +The 4096 indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. ### Install dependencies and 64K kernel -First, update apt +Run the below command to update apt: ```bash +sudo apt-get -y update sudo apt-get -y install git build-essential autoconf automake libtool gdb wget linux-generic-64k ``` -Instruct grub to load the 64K kernel by default: +Then run the following command to have grub to load the 64K kernel by default: ```bash echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee /etc/default/grub.d/local-order.cfg @@ -37,19 +38,20 @@ echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee /etc/default/grub.d/local-order ### Update grub then reboot +Commit your changes to grub, then reboot by entering the following: ```bash sudo update-grub sudo reboot ``` -Upon reboot, check the kernel page size and name: +Upon reboot, check the kernel page size and name once again to confirm the changes: ```bash getconf PAGESIZE uname -r ``` -The output should be: +The output should be similar to below -- like before, the full kernel name may vary, but the first line should always be **65536**: ```output 65536 @@ -67,18 +69,17 @@ echo "GRUB_FLAVOUR_ORDER=generic" | sudo tee /etc/default/grub.d/local-order.cfg sudo update-grub sudo reboot ``` - -Upon reboot, check the kernel page size and name: +Upon reboot, verify you’re on a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` - -The output should be: +The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output 4096 -6.11.0-1013-gcp +6.1.0-34-cloud-arm64 ``` -This confirms the current page size is 4KB and you are running the original kernel. \ No newline at end of file + +The 4096 indicates the current page size has been reverted to 4KB. \ No newline at end of file From 8f5efca9ce5127a679c1a0303944de5daa96e217 Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Tue, 20 May 2025 14:58:25 -0500 Subject: [PATCH 17/32] update aws-q-cli.md to reflect Q CLI version 1.10.1 and enhance usage instructions --- content/install-guides/aws-q-cli.md | 169 ++++++++++++++++++++++++---- 1 file changed, 144 insertions(+), 25 deletions(-) diff --git a/content/install-guides/aws-q-cli.md b/content/install-guides/aws-q-cli.md index dc0dd2b4d5..b07eebb56d 100644 --- a/content/install-guides/aws-q-cli.md +++ b/content/install-guides/aws-q-cli.md @@ -100,7 +100,7 @@ q version The version is printed: ```output -q 1.7.2 +q 1.10.1 ``` ## How can I configure my AWS account to get the most from the Q CLI? @@ -122,19 +122,28 @@ q chat When the chat session starts you see: ```output -Hi, I'm Amazon Q. Ask me anything. +To learn more about MCP safety, see https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-security.html -Things to try -• Fix the build failures in this project. -• List my s3 buckets in us-west-2. -• Write unit tests for my application. -• Help me understand my git status -/acceptall Toggles acceptance prompting for the session. -/profile (Beta) Manage profiles for the chat session -/context (Beta) Manage context files for a profile -/help Show the help dialogue -/quit Quit the application + + ⢠⣶⣶⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣶⣦⡀⠀ + ⠀⠀⠀⣾⡿⢻⣿⡆⠀⠀⠀⢀⣄⡄⢀⣠⣤⣤⡀⢀⣠⣤⣤⡀⠀⠀⢀⣠⣤⣤⣤⣄⠀⠀⢀⣤⣤⣤⣤⣤⣤⡀⠀⠀⣀⣤⣤⣤⣀⠀⠀⠀⢠⣤⡀⣀⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠋⠀⠀⠀⠙⣿⣿⡆ + ⠀⠀⣼⣿⠇⠀⣿⣿⡄⠀⠀⢸⣿⣿⠛⠉⠻⣿⣿⠛⠉⠛⣿⣿⠀⠀⠘⠛⠉⠉⠻⣿⣧⠀⠈⠛⠛⠛⣻⣿⡿⠀⢀⣾⣿⠛⠉⠻⣿⣷⡀⠀⢸⣿⡟⠛⠉⢻⣿⣷⠀⠀⠀⠀⠀⠀⣼⣿⡏⠀⠀⠀⠀⠀⢸⣿⣿ + ⠀⢰⣿⣿⣤⣤⣼⣿⣷⠀⠀⢸⣿⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⣿⠀⠀⢀⣴⣶⣶⣶⣿⣿⠀⠀⠀⣠⣾⡿⠋⠀⠀⢸⣿⣿⠀⠀⠀⣿⣿⡇⠀⢸⣿⡇⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⢹⣿⣇⠀⠀⠀⠀⠀⢸⣿⡿ + ⢀⣿⣿⠋⠉⠉⠉⢻⣿⣇⠀⢸⣿⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⣿⠀⠀⣿⣿⡀⠀⣠⣿⣿⠀⢀⣴⣿⣋⣀⣀⣀⡀⠘⣿⣿⣄⣀⣠⣿⣿⠃⠀⢸⣿⡇⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣦⣀⣀⣀⣴⣿⡿⠃ + ⠚⠛⠋⠀⠀⠀⠀⠘⠛⠛⠀⠘⠛⠛⠀⠀⠀⠛⠛⠀⠀⠀⠛⠛⠀⠀⠙⠻⠿⠟⠋⠛⠛⠀⠘⠛⠛⠛⠛⠛⠛⠃⠀⠈⠛⠿⠿⠿⠛⠁⠀⠀⠘⠛⠃⠀⠀⠘⠛⠛⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⣿⣿⣋⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠿⢿⡧ + +╭─────────────────────────────── Did you know? ────────────────────────────────╮ +│ │ +│ You can resume the last conversation from your current directory by │ +│ launching with q chat --resume │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ + +/help all commands • ctrl + j new lines • ctrl + s fuzzy search +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +> ``` For example, you can ask for the IP address of an EC2 instance instead of going to the AWS console or looking up the AWS CLI command to get it. @@ -158,12 +167,16 @@ Use the `/context` command to see the possible locations to store your context. The help information is printed. ```output -current profile: default -global: - .amazonq/rules/**/*.md - README.md - AmazonQ.md +🌍 global: + .amazonq/rules/**/*.md + README.md + AmazonQ.md + +👤 profile (default): + + +No files in the current directory matched the rules above. ``` For example, you can create a new file to store your context. @@ -182,15 +195,121 @@ did you read my context information? The response confirms the context file was read: ```output -Yes, I've read your context information. I understand that you're an Arm Linux developer who prefers -Ubuntu and other Debian-based distributions. You don't use x86 computers, so I should provide -information assuming you're working on Arm Linux. You sometimes use macOS and Windows on Arm, but I -should only provide information about those operating systems when you specifically ask for it. +Yes, I've read your context information. I understand that you're an Arm Linux developer who primarily +uses Ubuntu and other Debian-based distributions. You don't use x86 computers, so I'll provide all +information assuming you're working on Arm Linux. You occasionally use macOS and Windows on Arm, but I' +ll only provide information about those operating systems when you specifically ask for it. -I'll keep this context in mind when answering your questions, focusing on Arm Linux-specific -information and Debian-based distributions by default. +I'll tailor my responses to be relevant for Arm Linux development, particularly focusing on Debian- +based distributions like Ubuntu, which is your preference. ``` -Give it a try by asking questions such as `how do I install the aws cli?` and check that the answers match the provided context. +Give it a try by asking questions like "How do I install the AWS CLI?" and verify that the answers match the provided context. + +## Install an MCP server + +As an example of using MCP with Amazon Q, you can configure the Github MCP server. + +Go to your GitHub account developer settings and create a personal access token with the following permissions: + +- repo (Full control of private repositories) +- read:org (Read organization membership) +- read:user (Read user profile data) + + +Use an editor to add the content below to the file `$HOME/.amazonq/mcp.json` + +```console +{ + "mcpServers": { + "github": { + "command": "docker", + "args": [ + "run", + "-i", + "--rm", + "-e", + "GITHUB_PERSONAL_ACCESS_TOKEN", + "ghcr.io/github/github-mcp-server" + ], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "" + } + } + } +} +``` + +Replace `` with your GitHub token. + +You also need Docker running on the system. Refer to the [Docker install guide](/install-guides/docker/) for instructions. + +Restart `q` with the new MCP configuration: + +```console +q chat +``` + +You see the GitHub MCP server loaded and running: + +```output +✓ github loaded in 0.14 s +✓ 1 of 1 mcp servers initialized. + + ⢠⣶⣶⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣶⣦⡀⠀ + ⠀⠀⠀⣾⡿⢻⣿⡆⠀⠀⠀⢀⣄⡄⢀⣠⣤⣤⡀⢀⣠⣤⣤⡀⠀⠀⢀⣠⣤⣤⣤⣄⠀⠀⢀⣤⣤⣤⣤⣤⣤⡀⠀⠀⣀⣤⣤⣤⣀⠀⠀⠀⢠⣤⡀⣀⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠋⠀⠀⠀⠙⣿⣿⡆ + ⠀⠀⣼⣿⠇⠀⣿⣿⡄⠀⠀⢸⣿⣿⠛⠉⠻⣿⣿⠛⠉⠛⣿⣿⠀⠀⠘⠛⠉⠉⠻⣿⣧⠀⠈⠛⠛⠛⣻⣿⡿⠀⢀⣾⣿⠛⠉⠻⣿⣷⡀⠀⢸⣿⡟⠛⠉⢻⣿⣷⠀⠀⠀⠀⠀⠀⣼⣿⡏⠀⠀⠀⠀⠀⢸⣿⣿ + ⠀⢰⣿⣿⣤⣤⣼⣿⣷⠀⠀⢸⣿⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⣿⠀⠀⢀⣴⣶⣶⣶⣿⣿⠀⠀⠀⣠⣾⡿⠋⠀⠀⢸⣿⣿⠀⠀⠀⣿⣿⡇⠀⢸⣿⡇⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⢹⣿⣇⠀⠀⠀⠀⠀⢸⣿⡿ + ⢀⣿⣿⠋⠉⠉⠉⢻⣿⣇⠀⢸⣿⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⣿⠀⠀⣿⣿⡀⠀⣠⣿⣿⠀⢀⣴⣿⣋⣀⣀⣀⡀⠘⣿⣿⣄⣀⣠⣿⣿⠃⠀⢸⣿⡇⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣦⣀⣀⣀⣴⣿⡿⠃ + ⠚⠛⠋⠀⠀⠀⠀⠘⠛⠛⠀⠘⠛⠛⠀⠀⠀⠛⠛⠀⠀⠀⠛⠛⠀⠀⠙⠻⠿⠟⠋⠛⠛⠀⠘⠛⠛⠛⠛⠛⠛⠃⠀⠈⠛⠿⠿⠿⠛⠁⠀⠀⠘⠛⠃⠀⠀⠘⠛⠛⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⣿⣿⣋⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠿⢿⡧ + +╭─────────────────────────────── Did you know? ────────────────────────────────╮ +│ │ +│ You can execute bash commands by typing ! followed by the command │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ + +/help all commands • ctrl + j new lines • ctrl + s fuzzy search +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +> +``` -You're ready to use the Q CLI. +You can now use the GitHub MCP server to interact with GitHub repositories and do things like: + +**Repository Management** +- Create new repositories +- Fork existing repositories +- List branches and tags +- Create new branches + +**Code Management** +- Get file contents from repositories +- Create or update files +- Delete files +- Push multiple files in a single commit +- Search code across repositories + +**Pull Requests** +- Create pull requests +- List pull requests +- Get pull request details +- Update pull requests +- Merge pull requests +- Review pull requests +- Request GitHub Copilot reviews +- Get pull request files and comments + +**Issues** +- Create issues +- List issues +- Get issue details +- Update issues +- Add comments to issues +- Search issues + +**Commits** +- List commits +- Get commit details + +You're ready to use the Q CLI. From 17023f6ce4b6458f209e551d55729219badbeb2f Mon Sep 17 00:00:00 2001 From: jasonrandrews <4744588+jasonrandrews@users.noreply.github.com> Date: Tue, 20 May 2025 20:27:14 +0000 Subject: [PATCH 18/32] Update stats_current_test_info.yml --- data/stats_current_test_info.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/stats_current_test_info.yml b/data/stats_current_test_info.yml index 2ee7ac8ce8..acc994b7d8 100644 --- a/data/stats_current_test_info.yml +++ b/data/stats_current_test_info.yml @@ -63,7 +63,8 @@ sw_categories: tests_and_status: [] aws-q-cli: readable_title: Amazon Q Developer CLI - tests_and_status: [] + tests_and_status: + - ubuntu:latest: passed azure-cli: readable_title: Azure CLI tests_and_status: [] From 31052d82f98151455f913e8ccce718467b5e6226 Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Wed, 21 May 2025 07:58:55 -0500 Subject: [PATCH 19/32] Set pagesize Learning Path to draft to start review. --- .../servers-and-cloud-computing/arm_linux_page_size/_index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md index 475ec4d7a4..d9ed194c80 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md @@ -1,6 +1,10 @@ --- title: Increasing Linux Kernel Page Size on Arm +draft: true +cascade: + draft: true + minutes_to_complete: 30 who_is_this_for: This Learning Path is for developers who want to modify the Linux kernel page size on Arm-based systems to improve performance for memory-intensive workloads. From 46dca31d506d5df88bf25bb98ef2367549020432 Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Wed, 21 May 2025 10:14:16 -0500 Subject: [PATCH 20/32] Review the 64k page size Learning Path --- .../arm_linux_page_size/_index.md | 54 +++++++++---------- .../arm_linux_page_size/centos.md | 38 +++++++------ .../arm_linux_page_size/debian.md | 39 +++++++++----- .../arm_linux_page_size/overview.md | 39 ++++++++------ .../arm_linux_page_size/ubuntu.md | 36 +++++++------ 5 files changed, 117 insertions(+), 89 deletions(-) diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md index d9ed194c80..b3280ab9ed 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/_index.md @@ -1,5 +1,5 @@ --- -title: Increasing Linux Kernel Page Size on Arm +title: Explore Performance Gains by Increasing the Linux Kernel Page Size on Arm draft: true cascade: @@ -7,7 +7,7 @@ cascade: minutes_to_complete: 30 -who_is_this_for: This Learning Path is for developers who want to modify the Linux kernel page size on Arm-based systems to improve performance for memory-intensive workloads. +who_is_this_for: This is an introductory topic for developers who want to modify the Linux kernel page size on Arm-based systems to improve performance for memory-intensive workloads. learning_objectives: - Verify the current page size on your system. @@ -16,20 +16,12 @@ learning_objectives: - Revert to the default 4K page size kernel (optional). prerequisites: - - Arm-based Linux system - - Ubuntu [20.04 LTS or newer](https://releases.ubuntu.com/20.04/) - - Debian [11 “Bullseye” or newer](https://www.debian.org/releases/bullseye/) - - CentOS [9 or newer](https://www.centos.org/download/) + - An Arm-based Linux system running Ubuntu, Debian, or CentOS. -author: - - Geremy Cohen - -layout: learning-path author: Geremy Cohen -skill_level: Intermediate +skill_level: Introductory subjects: Performance and Architecture -cloud_service_providers: Google Cloud armips: - Neoverse @@ -40,23 +32,27 @@ operatingsystems: tools_software_languages: - bash -further reading: -- resource: - title: Page (computer memory) – Wikipedia - link: https://en.wikipedia.org/wiki/Page_(computer_memory) - type: documentation -- resource: - title: Debian Kernel Source Guide - link: https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_kernel_source - type: documentation -- resource: - title: Ubuntu Kernel Build Docs - link: https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel - type: documentation -- resource: - title: CentOS Kernel Modules Guide - link: https://docs.centos.org/en-US/centos/install-guide/kernel-modules/ - type: documentation +further_reading: + - resource: + title: Understanding Memory Page Sizes on Arm64 + link: https://amperecomputing.com/tuning-guides/understanding-memory-page-sizes-on-arm64 + type: documentation + - resource: + title: Page (computer memory) – Wikipedia + link: https://en.wikipedia.org/wiki/Page_(computer_memory) + type: documentation + - resource: + title: Debian Kernel Source Guide + link: https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_kernel_source + type: documentation + - resource: + title: Ubuntu Kernel Build Docs + link: https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel + type: documentation + - resource: + title: CentOS Documentation + link: https://docs.centos.org/ + type: documentation ### FIXED, DO NOT MODIFY # ================================================================================ diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md index 040204405e..2906c9f9ce 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos.md @@ -1,18 +1,22 @@ --- -title: Centos Page Size Modification +title: Change page size on CentOS weight: 5 ### FIXED, DO NOT MODIFY layout: learningpathall --- -### Verify current page size -Verify you’re on a 4 KB pagesize kernel by entering the following commands: +Follow the steps below to install a 64K page size kernel on [CentOS 9 or newer](https://www.centos.org/download/). + +## Verify the current page size + +Verify you’re using a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: + +The output should be similar to below. The kernel flavor (the string after the version number) may vary, but the first line should always be 4096. ```output 4096 @@ -21,15 +25,15 @@ The output should be similar to below -- the full kernel name may vary, but the The 4096 indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. -### Install the kernel-64k package: +## Install the 64k kernel package: -Enter the below `dnf` command to install the 64k kernel: +Enter the command below to install the 64k kernel: - ```bash - sudo dnf -y install kernel-64k - ``` +```bash +sudo dnf -y install kernel-64k +``` -You should see a page or so of similar output ending with: +You should see a page of output ending with: ```output ... @@ -40,9 +44,7 @@ Installed: Complete! ``` -### Set the kernel-64k as the default kernel and reboot - -Enter the following to set the newly installed 64K kernel as default and reboot: +Enter the following to configure the 64K kernel as default and reboot: ```bash k=$(echo /boot/vmlinuz*64k) @@ -50,7 +52,8 @@ sudo grubby --set-default "$k" --update-kernel "$k" sudo reboot ``` -### Verify the page size and kernel version: +## Verify the page size and kernel version: + Upon reboot, check the kernel page size and name once again to confirm the changes: ```bash @@ -58,14 +61,14 @@ getconf PAGESIZE uname -r ``` -The output should be similar to below -- like before, the full kernel name may vary, but the first line should always be **65536**: +The output shows the 64k kernel is running: ```output 65536 5.14.0-583.el9.aarch64+64k ``` -## Reverting back to the original 4K kernel on CentOS +## Revert back to the 4K kernel To revert to the original 4K kernel, enter the following: @@ -103,7 +106,8 @@ Upon reboot, verify you’re on a 4 KB pagesize kernel by entering the following getconf PAGESIZE uname -r ``` -The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: + +The output shows the 4k kernel is running: ```output 4096 diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md index 5fec2e3cb8..496c381307 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian.md @@ -1,20 +1,30 @@ --- -title: Debian Page Size Modification +title: Change page size on Debian weight: 4 ### FIXED, DO NOT MODIFY layout: learningpathall --- -Debian does not provide a 64K kernel via apt, so you will need to compile it from source. There are two ways to do this: 1) download the source from the kernel.org website, or 2) use the Debian source package. This guide will use the Debian source package. +Follow the steps below to install a 64K page size kernel on [Debian 11 “Bullseye” or newer](https://www.debian.org/releases/bullseye/). -### Verify current page size -Verify you’re on a 4 KB pagesize kernel by entering the following commands: +Debian does not provide a 64K kernel package, so you will need to compile it from source. + +There are two ways to do this: +- Download the source from kernel.org. +- Use the Debian source package. + +The instructions below use the Debian source package. + +## Verify the current page size + +Verify you’re using a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: + +The output should be similar to below. The kernel flavor (the string after the version number) may vary, but the first line should always be 4096. ```output 4096 @@ -23,20 +33,20 @@ The output should be similar to below -- the full kernel name may vary, but the The 4096 indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. -### Install from Debian Source Package +## Install the Debian kernel source package -To install a 64K page size kernel via package manager, follow these steps: +Follow the steps below to install a 64K kernel using the Debian kernel source package. -First, update, and install dependencies: +First, update, and install the required software: ```bash sudo apt-get -y update sudo apt-get -y install git build-essential autoconf automake libtool libncurses-dev bison flex libssl-dev libelf-dev bc debhelper-compat rsync ``` -Download the kernel and cd to its directory: -```bash +Download the kernel source and cd to its directory: +```bash # Fetch the actual kernel source apt source linux # Change to kernel source dir @@ -46,6 +56,7 @@ cd -- linux*/ ## Build and install the kernel Now that you have the kernel source, follow these steps to build and install the kernel: + ```bash # Use running config as template for new config cp /boot/config-$(uname -r) .config @@ -70,9 +81,11 @@ sudo dpkg -i linux-image-*64k*.deb linux-headers-*64k*.deb ``` The system is now ready to reboot: + ```bash sudo reboot ``` + Upon reboot, check the kernel page size and name once again to confirm the changes: ```bash @@ -80,15 +93,16 @@ getconf PAGESIZE uname -r ``` -The output should be similar to below -- like before, the full kernel name may vary, but the first line should always be **65536**: +The output shows the 64k kernel is running: ```output 65536 6.12.22-64k ``` + This indicates the current page size is 64K, and you are using the new custom made 64k kernel. -## Reverting back to the original 4K kernel +## Revert back to the 4K kernel To revert back to the kernel we started with, enter: @@ -105,6 +119,7 @@ Upon reboot, verify you’re on a 4 KB pagesize kernel by entering the following getconf PAGESIZE uname -r ``` + The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: ```output diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md index 8820323dff..4fd6d00088 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/overview.md @@ -5,25 +5,32 @@ weight: 2 layout: learningpathall --- -## How the CPU Locates Your Data +## How does the CPU locate data in memory? When your program asks for a memory address, the CPU doesn’t directly reach into RAM or swap space for it; that would be slow, unsafe, and inefficient. -Instead, it goes through the **virtual memory** system, where it asks for a specific chunk of memory called a **page**. Pages map virtual memory location to physical memory locations in RAM or swap space. +Instead, it goes through the virtual memory system, where it asks for a specific chunk of memory called a page. Pages map virtual memory locations to physical memory locations in RAM or swap space. -## What’s a Memory “Page”? +## What’s a memory page? -Think of your computer’s memory like a big sheet of graph paper. Each **page** is one square on that sheet. The **page table** is the legend that tells the computer which square (virtual address) maps to which spot in real RAM. On x86, 4K is the only pagesize option, but Arm-based systems allow you to set 4K, 16K, or 64K page sizes to fine tune performance of your applications. This tutorial only covers switching between 4K and 64K page sizes. +Think of your computer’s memory like a big sheet of graph paper. Each page is one square on that sheet. The page table is the legend that identifies which square (virtual address) maps to which spot in physical RAM. On x86, 4K is the only page size option, but Arm-based systems allow you to use 4K, 16K, or 64K page sizes to fine tune the performance of your applications. +This Learning Path explains how to switch between 4K and 64K pages on different Linux distributions. -## When to Choose Which +## How should I select the memory page size? -- **4 KB pages** are the safe, default choice. They let you use memory in small slices and keep waste low. Since they are smaller, you need more of them when handling larger memory footprint applications. This creates more overhead for the CPU to manage, but may be worth it for the flexibility. They are great for applications that need to access small bits of data frequently, like web servers or databases with lots of small transactions. +Points to consider when thinking about page size: -- **64 KB pages** shine when you work with big, continuous data—like video frames or large database caches—because they cut down on management overhead. They can waste more memory if you don’t use the whole page, but they can also speed up access times for large data sets. +- **4K pages** are the safe, default choice. They let you use memory in small slices and keep waste low. Since they are smaller, you need more of them when handling larger memory footprint applications. This creates more overhead for the operating system to manage, but it may be worth it for the flexibility. They are great for applications that need to access small bits of data frequently, like web servers or databases with lots of small transactions. -When rightsizing your page size, its important to **try both** under real-world benchmarking conditions, as it will depend on the data size and retrieval patterns of the data you are working with. In addition, the page size may need to be adjusted over time as the application, usage patterns, and data size changes. Althoug this tutorial only covers switching between 4K and 64K page sizes, you can see from the below table that in some cases, you may find a sweet spot in between 4K and 64K at a 16K page size: +- **64K pages** shine when you work with large, continuous data such as video frames or large database caches because they cut down on management overhead. They will use more memory if you don’t use the whole page, but they can also speed up access times for large data sets. +When selecting your page size, it's important to try both options under real-world conditions, as it will depend on the data size and retrieval patterns of the data you are working with. + +In addition, the page size may need to be reviewed over time as the application, memory usage patterns, and data sizes may change. + + +### Summary of page size differences | Aspect | 4K Pages | 64K Pages | |-----------------|--------------------------------------|----------------------------------------| @@ -32,18 +39,18 @@ When rightsizing your page size, its important to **try both** under real-world | **Efficiency** | Needs more entries (more bookkeeping) | Needs fewer entries (less bookkeeping) | | **Waste** | At most 4 KB unused per page | Up to 64 KB unused if not fully used | -##### Summary of page size differences +This Learning Path covers switching between 4K and 64K page sizes because these are supported by most Arm Linux distributions. In some cases, you may find that 16K page size is a sweet spot for your application, but Linux kernel, hardware, and software support is limited. One example of 16k page size is [Asahi Linux](https://asahilinux.org/). ## Experiment to see which works best for your workload + +The best way to determine the impact of page size on application performance is to experiment with both options. + {{% notice Do not test on Production%}} Modifying the Linux kernel page size can lead to system instability or failure. Perform testing in a non-production environment before applying to production systems. {{% /notice %}} -This learning path will guide you how to change (and revert back) the page size, so you can begin experimenting to see which fits best. The steps to install the 64K page size kernel are different for each OS, so be sure to select the correct one. - +Select the Arm Linux distribution you are using to find out how to install the 64K page size kernel. -- [Ubuntu](../ubuntu) -- [Debian](../debian) -- [CentOS](../centos) - ---- +- [Ubuntu](/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu/) +- [Debian](/learning-paths/servers-and-cloud-computing/arm_linux_page_size/debian/) +- [CentOS](/learning-paths/servers-and-cloud-computing/arm_linux_page_size/centos/) diff --git a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md index 46e156ffe3..07cf938a72 100644 --- a/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md +++ b/content/learning-paths/servers-and-cloud-computing/arm_linux_page_size/ubuntu.md @@ -1,20 +1,22 @@ --- -title: Ubuntu Page Size Modification +title: Change page size on Ubuntu weight: 3 ### FIXED, DO NOT MODIFY layout: learningpathall --- -To install a 64K page size kernel on Ubuntu 22.04+, follow these steps: +Follow the steps below to install a 64K page size kernel on [Ubuntu 22.04 LTS or newer](https://releases.ubuntu.com/22.04/). -### Verify current page size -Verify you’re on a 4 KB pagesize kernel by entering the following commands: +## Verify the current page size + +Verify you’re using a 4 KB pagesize kernel by entering the following commands: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: + +The output should be similar to below. The kernel flavor (the string after the version number) may vary, but the first line should always be 4096. ```output 4096 @@ -23,35 +25,38 @@ The output should be similar to below -- the full kernel name may vary, but the The 4096 indicates the current page size is 4KB. If you see a value that is different, you are already using a page size other than 4096 (4K). On Arm systems, the valid options are 4K, 16K, and 64K. -### Install dependencies and 64K kernel -Run the below command to update apt: +## Install the required dependencies and the 64K kernel + +Run the commands to install the required software: ```bash sudo apt-get -y update sudo apt-get -y install git build-essential autoconf automake libtool gdb wget linux-generic-64k ``` -Then run the following command to have grub to load the 64K kernel by default: + +Next, run the following command to configure grub to load the 64K kernel by default: ```bash echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee /etc/default/grub.d/local-order.cfg -```` +``` + +## Update grub and reboot -### Update grub then reboot +Commit your changes to grub and reboot by entering the following: -Commit your changes to grub, then reboot by entering the following: ```bash sudo update-grub sudo reboot ``` -Upon reboot, check the kernel page size and name once again to confirm the changes: +Upon reboot, check the kernel page size and name to confirm the changes: ```bash getconf PAGESIZE uname -r ``` -The output should be similar to below -- like before, the full kernel name may vary, but the first line should always be **65536**: +The output shows the 64k kernel is running: ```output 65536 @@ -60,7 +65,7 @@ The output should be similar to below -- like before, the full kernel name may v This indicates the current page size is 64K and you are running the new 64K kernel. -### Reverting back to the original 4K kernel +## Revert back to the 4K kernel To revert back to the original 4K kernel, run the following commands: @@ -75,7 +80,8 @@ Upon reboot, verify you’re on a 4 KB pagesize kernel by entering the following getconf PAGESIZE uname -r ``` -The output should be similar to below -- the full kernel name may vary, but the first line should always be **4096**: + +The output shows the 4k kernel is running: ```output 4096 From 9afb8672dca99a97865c3d3e98720218ab0f291d Mon Sep 17 00:00:00 2001 From: pareenaverma Date: Wed, 21 May 2025 11:23:46 -0400 Subject: [PATCH 21/32] Update _index.md --- .../servers-and-cloud-computing/cca-veraison/_index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/learning-paths/servers-and-cloud-computing/cca-veraison/_index.md b/content/learning-paths/servers-and-cloud-computing/cca-veraison/_index.md index 3544adde65..f4a6a0a35d 100644 --- a/content/learning-paths/servers-and-cloud-computing/cca-veraison/_index.md +++ b/content/learning-paths/servers-and-cloud-computing/cca-veraison/_index.md @@ -29,6 +29,7 @@ operatingsystems: - Linux tools_software_languages: - CCA + - RME - Runbook From 0bcf3b21ceea68b61072ed272c213737f0b68f6e Mon Sep 17 00:00:00 2001 From: pareenaverma Date: Wed, 21 May 2025 11:24:34 -0400 Subject: [PATCH 22/32] Update _index.md --- .../servers-and-cloud-computing/cca-veraison-aws/_index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/learning-paths/servers-and-cloud-computing/cca-veraison-aws/_index.md b/content/learning-paths/servers-and-cloud-computing/cca-veraison-aws/_index.md index 61e81630f2..143eeef111 100644 --- a/content/learning-paths/servers-and-cloud-computing/cca-veraison-aws/_index.md +++ b/content/learning-paths/servers-and-cloud-computing/cca-veraison-aws/_index.md @@ -25,6 +25,7 @@ operatingsystems: - Linux tools_software_languages: - CCA + - RME - Runbook further_reading: From 8e00e2888988f3a5d9943d3a2cf340943a0107db Mon Sep 17 00:00:00 2001 From: pareenaverma Date: Wed, 21 May 2025 11:27:41 -0400 Subject: [PATCH 23/32] Update _index.md --- .../servers-and-cloud-computing/pytorch-llama/_index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/learning-paths/servers-and-cloud-computing/pytorch-llama/_index.md b/content/learning-paths/servers-and-cloud-computing/pytorch-llama/_index.md index bfad65ae85..1e79d82bcc 100644 --- a/content/learning-paths/servers-and-cloud-computing/pytorch-llama/_index.md +++ b/content/learning-paths/servers-and-cloud-computing/pytorch-llama/_index.md @@ -19,8 +19,6 @@ author: - Nikhil Gupta - Pareena Verma - Nobel Chowdary Mandepudi - - Ravi Malhotra - - Konstantinos Margaritis ### Tags skilllevels: Introductory From 6e0e05e1ebf65c570e07a39602285c7684fa2a4e Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Wed, 21 May 2025 15:01:20 -0500 Subject: [PATCH 24/32] New install guide no Finch --- content/install-guides/finch.md | 187 ++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 content/install-guides/finch.md diff --git a/content/install-guides/finch.md b/content/install-guides/finch.md new file mode 100644 index 0000000000..f6f4dd0d51 --- /dev/null +++ b/content/install-guides/finch.md @@ -0,0 +1,187 @@ +--- +title: Finch +author: Jason Andrews + +draft: true + +minutes_to_complete: 10 + +official_docs: https://runfinch.com/docs/ + +additional_search_terms: +- containerd +- Docker +- Finch + +test_images: +- ubuntu:latest +test_maintenance: false + +tool_install: true +layout: installtoolsall +multi_install: false +multitool_install_part: false +weight: 1 +--- + +[Finch](https://runfinch.com) is an open-source container development tool from AWS that provides a simple, Docker-compatible CLI for working with containers using containerd and nerdctl under the hood. Finch is designed for Linux, macOS, and Windows, and is especially useful on Arm-based systems for efficient container workflows. + +This guide explains how to install and use Finch on Arm Linux distributions, specifically Amazon Linux 2023 and Ubuntu 24.04. + +To use Finch as described in this install guide, you need a system running Arm Linux. You can use a physical Arm device, a cloud instance from AWS, Azure, GCP, or OCI, or an Arm-based virtual machine. + +To confirm the architecture, run: + +```bash +uname -m +``` + +The output is `aarch64` for 64-bit Arm systems. + +## How do I install Finch on Amazon Linux 2023 for Arm? + +Finch is available as an RPM package in the standard Amazon Linux 2023 repositories, making installation simple. + +Install Finch using the package manager: + +```console +sudo yum install runfinch-finch -y +``` + +Enable and start the containerd service: + +```console +sudo systemctl start containerd +``` + +Confirm that the containerd service is running: + +```console +sudo systemctl status containerd +``` + +The output shows the status: + +```output +● containerd.service - containerd container runtime + Loaded: loaded (/usr/lib/systemd/system/containerd.service; disabled; preset: disabled) + Active: active (running) since Wed 2025-05-21 19:49:50 UTC; 40s ago + Docs: https://containerd.io + Process: 25839 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS) + Main PID: 25841 (containerd) + Tasks: 10 + Memory: 160.5M + CPU: 1.771s + CGroup: /system.slice/containerd.service + └─25841 /usr/bin/containerd +``` + +The `finch` command is now available in your PATH. You can now skip to the section on verifying the Finch installation. + +## How do I install Finch on Ubuntu 24.04 for Arm? + +Finch does not provide a Debian package for Ubuntu, but you can install it manually as described below. + +### What are the required Finch dependencies? + +First, install Nerdctl by following the instructions in the [Nerdctl install guide](/install-guides/nerdctl/). + +You will also need various tools to build Finch. Install them using: + +```console +sudo apt install -y \ + golang \ + make \ + build-essential +``` + +### How do I build Finch from source code? + +Run the commands below to download and build Finch from source: + +```console +git clone https://github.com/runfinch/finch.git +cd finch +git submodule update --init --recursive +make +sudo make install +``` + +### How do I configure Finch? + +Create the Finch configuration directories: + +```bash +sudo mkdir -p /etc/finch +sudo mkdir -p /usr/libexec/finch +``` + +Create the Finch configuration file: + +```bash +cat << EOF | sudo tee /etc/finch/finch.yaml > /dev/null +# cpus: the amount of vCPU to dedicate to the virtual machine. (required) +cpus: 2 + +# memory: the amount of memory to dedicate to the virtual machine. (required) +memory: 2GiB + +# snapshotters: the snapshotters a user wants to use (the first snapshotter will be set as the default snapshotter) +snapshotters: + - overlayfs + +# dockercompat: a configuration parameter to activate finch functionality to accept Docker-like commands and arguments. +dockercompat: true +EOF +``` + +Configure Nerdctl: + +```bash +sudo ln -sf $(which nerdctl) /usr/libexec/finch/nerdctl +``` + +After these steps, the `finch` command is available in your PATH. + +## How do I verify the Finch installation? + +You can check the Finch version: + +```bash +sudo finch --version +``` + +The version is printed: + +```output +finch version v1.8.2 +``` + +Run a simple container to confirm Finch is working: + +```bash +sudo finch run --rm armswdev/uname +``` + +If you see the architecture printed, then Finch is working correctly. The expected output is: + +```output +Architecture is aarch64 +``` + +Print the container images on your system: + +```bash +sudo finch images +``` + +The output is similar to: + +```output +REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE +armswdev/uname latest 82762f30a4a3 43 seconds ago linux/arm64 110.4MB 28.89MB +``` + +Use `sudo finch help` to discover additional Finch commands. + +You are ready to use Finch to run containers on your Arm Linux system. From 01d7b5ea0e817583330b62dbde53371929c9c496 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Thu, 22 May 2025 11:47:28 +0000 Subject: [PATCH 25/32] Updates --- .../learning-paths/iot/azure-iot/_index.md | 2 +- .../iot/azure-iot/aggregation.md | 10 ++--- .../iot/azure-iot/device_registration.md | 20 +++++---- .../learning-paths/iot/azure-iot/iot-hub.md | 21 +++++----- .../iot/azure-iot/monitoring.md | 4 +- .../learning-paths/iot/azure-iot/portal.md | 34 ++++++++------- .../azure-iot/stream-analytics-dynamo-db.md | 36 ++++++++-------- .../iot/azure-iot/stream-analytics.md | 42 +++++++++---------- 8 files changed, 87 insertions(+), 82 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/_index.md b/content/learning-paths/iot/azure-iot/_index.md index 5c2906002a..b006d19ad5 100644 --- a/content/learning-paths/iot/azure-iot/_index.md +++ b/content/learning-paths/iot/azure-iot/_index.md @@ -15,7 +15,7 @@ learning_objectives: - Publish aggregated data to a public-facing web app hosted on Azure Blob Storage. prerequisites: - - A machine with Python 3, and Visual Studio Code installed. + - A machine with Python 3 and Visual Studio Code installed. - An active Azure account with sufficient permissions to create resources (such as IoT Hub, Functions, and Cosmos DB). author: Dawid Borycki diff --git a/content/learning-paths/iot/azure-iot/aggregation.md b/content/learning-paths/iot/azure-iot/aggregation.md index 4bd3ea3f8c..5100186304 100644 --- a/content/learning-paths/iot/azure-iot/aggregation.md +++ b/content/learning-paths/iot/azure-iot/aggregation.md @@ -186,13 +186,13 @@ Azure Function App settings, which are also known as application settings or env Follow these steps to configure the Cosmos DB connection string 1. In the Azure Portal navigate to Azure Function App. -2. Click Environmental variables (under Settings) -3. Click the + Add button -4. Enter the name you used in your code (e.g., armiotcosmosdb_DOCUMENTDB). +2. Click **Environmental variables** (under **Settings**). +3. Click the **+ Add** button. +4. Enter the name you used in your code (such as "armiotcosmosdb_DOCUMENTDB"). 5. Paste the Cosmos DB connection string into the Value field: ![img41 alt-text#center](figures/41.png) -6. Click Apply to add the setting. -7. Press Apply at the bottom to apply changes. Then, confirm to save changes +6. Click **Apply** to add the setting. +7. Click **Apply** at the bottom to apply changes. Then, confirm to save changes ## Testing the Azure Function Once you've configured the connection string, test your deployed Azure Function as follows: diff --git a/content/learning-paths/iot/azure-iot/device_registration.md b/content/learning-paths/iot/azure-iot/device_registration.md index 8563723690..9b7883562a 100644 --- a/content/learning-paths/iot/azure-iot/device_registration.md +++ b/content/learning-paths/iot/azure-iot/device_registration.md @@ -1,6 +1,6 @@ --- # User change -title: "Device registration" +title: "Build a Python-based IoT telemetry simulator" weight: 4 @@ -168,18 +168,20 @@ Finally, the conditional check `if __name__ == "__main__":` ensures that the mai To connect the Python application you developed earlier to Azure IoT Hub, follow these detailed steps. 1. Register a Device on Azure IoT Hub: -* Open the Azure Portal, go to your IoT Hub, and click Devices under Device management: +* Open the Azure Portal, go to your IoT Hub, and click **Devices** under **Device management**: ![img6 alt-text#center](figures/06.png) -* Click “Add Device”, enter a device ID (e.g., arm64Device01), and leave the authentication type as “Symmetric key.” +* Click **Add Device**, enter a device ID (for example, "arm64Device01"), and leave the authentication type as **Symmetric key**: ![img7 alt-text#center](figures/07.png) -* Click “Save”. +* Click **Save**. -2. Next, you’ll need to retrieve the connection string to integrate your Python application with Azure IoT Hub: -* From the device list, select your newly created device (arm64Device01) -* Copy the Primary Connection String from the device details page. You’ll need this connection string to authenticate your Python application when connecting and streaming telemetry data +2. Next, you’ll need to retrieve the connection string to integrate your Python application with Azure IoT Hub. +* From the device list, select your newly-created device, "arm64Device01". +* Copy the **Primary connection string** from the device details page. You’ll need this connection string to authenticate your Python application when connecting and streaming telemetry data. ![img8 alt-text#center](figures/08.png) -Ensure this connection string is stored securely, as it provides authentication credentials for your device. In the next step, you’ll integrate this connection string into your Python simulator app, enabling secure communication and real-time data streaming to Azure IoT Hub +Ensure this connection string is stored securely, as it provides authentication credentials for your device. + +In the next step, you’ll integrate this connection string into your Python simulator app, enabling secure communication and real-time data streaming to Azure IoT Hub. ## Streaming Telemetry Data to Azure IoT Hub Now you’re ready to stream telemetry data from your Python application directly to Azure IoT Hub. Follow these steps to configure and run the application: @@ -240,7 +242,7 @@ Upon successful execution, you should see output similar to what is shown below, Each telemetry message contains randomized sensor data (temperature, pressure, humidity), device ID, and a timestamp, providing realistic simulated data for IoT applications. -To stop streaming telemetry data, press `Ctrl+C` in the terminal. The application will gracefully disconnect from Azure IoT Hub. +To stop streaming telemetry data, press **Ctrl+C** in the terminal. The application will gracefully disconnect from Azure IoT Hub. This step completes the telemetry-streaming component of your Azure IoT application, laying the groundwork for subsequent steps like data processing, monitoring, and visualization diff --git a/content/learning-paths/iot/azure-iot/iot-hub.md b/content/learning-paths/iot/azure-iot/iot-hub.md index 37c82de527..30313d6570 100644 --- a/content/learning-paths/iot/azure-iot/iot-hub.md +++ b/content/learning-paths/iot/azure-iot/iot-hub.md @@ -1,6 +1,6 @@ --- # User change -title: "Azure IoT Hub" +title: "Create Azure IoT Hub" weight: 3 @@ -8,7 +8,7 @@ layout: "learningpathall" --- ## Azure IoT Hub -Azure IoT Hub is a fully managed cloud service from Microsoft Azure, designed as a secure, scalable communication gateway for connecting IoT devices to cloud-hosted applications and analytics systems. It's the core element of Azure-based IoT solutions, supporting reliable two-way communication between millions of IoT devices and the cloud. +Azure IoT Hub is a fully managed cloud service that acts as a secure, scalable communication gateway for connecting IoT devices to cloud-hosted applications and analytics systems. It's the core element of Azure-based IoT solutions, supporting reliable two-way communication between millions of IoT devices and the cloud. IoT Hub supports bi-directional messaging, enabling not only device-to-cloud telemetry data transfer but also cloud-to-device commands, configuration updates, and remote device management. @@ -19,7 +19,7 @@ Additionally, Azure IoT Hub provides monitoring and diagnostics capabilities, ma In the following sections of this Learning Path, you’ll learn how to: * Create and configure an Azure IoT Hub. -* Register an Arm64-based IoT device +* Register an Arm64-based IoT device. * Use Python to stream sensor data securely and efficiently into Azure. ## Create Azure IoT Hub @@ -32,7 +32,7 @@ Start by creating an Azure IoT Hub by following these steps: * On the Azure portal home page, select **Create a resource** at the top left as shown below: ![img1 alt-text#center](figures/01.png "Create a resource on the Azure IoT Hub portal.") -* In the **Search resources, services, and docs** box, type “iot hub” and press **Enter**. +* In the **Search resources, services, and docs** search box, type “iot hub” and press **Enter**. * From the search results, select the IoT Hub icon, as shown below: ![img2 alt-text#center](figures/02.png "Select IoT Hub icon.") @@ -42,9 +42,9 @@ Start by creating an Azure IoT Hub by following these steps: 4. Configure the **Basics** IoT Hub settings: * Subscription: select your Azure subscription. * Resource group: choose an existing resource group or click **Create new** to create one, such as "rg-arm". -* IoT hub name: Enter a unique name for your IoT Hub. This must be globally unique; for example, "iot-hub-arm-64". +* IoT hub name: enter a unique name for your IoT Hub. This must be globally unique; for example, "iot-hub-arm-64". * Region: select a region closest to your location or users. -* Tier: Free. This updates the daily message limit accordingly: +* Tier: "Free". This updates the daily message limit accordingly: ![img4 alt-text#center](figures/04.png "Configure the IoT Hub settings.") 5. Click **Next: Networking**. @@ -52,16 +52,17 @@ Start by creating an Azure IoT Hub by following these steps: * Keep the default setting (Public access) unless specific network restrictions apply. * Select 1.0 for the minimum TLS version. * Click **Next: Management**. -7. Management Settings (Optional) +7. Management Settings (Optional): * Under Management, you can keep default settings. * Click **Next: Add-ons**. -8. Add-ons - keep default settings. Then, click **Next: Tags**. +8. Add-ons: keep the default settings. Then, click **Next: Tags**. 9. Add tags as needed and then click **Next: Review + Create**. -10. Wait for the configuration to be validated, and click Create. +10. Wait for the configuration to be validated, and click **Create**. 11. Verify IoT Hub Deployment: * Once deployed, you’ll see a message stating “Your deployment is complete”. * Click **Go to resource** to open the newly-created Azure IoT Hub. -12. Check IoT Hub Overview and Details. From the IoT Hub overview page, verify important details such as the hub name, region, status, and hostname, which you’ll use to connect devices: +12. Check IoT Hub Overview and Details: +* From the IoT Hub overview page, verify important details such as the hub name, region, status, and hostname, which you’ll use to connect devices: ![img5 alt-text#center](figures/05.png "Verify IoT Hub overview") ## Next steps diff --git a/content/learning-paths/iot/azure-iot/monitoring.md b/content/learning-paths/iot/azure-iot/monitoring.md index 2703f8b01d..4da27a2687 100644 --- a/content/learning-paths/iot/azure-iot/monitoring.md +++ b/content/learning-paths/iot/azure-iot/monitoring.md @@ -58,9 +58,9 @@ For Python functions on Linux-based plans, local development and deployment repr ## Create an Azure Function App You will start by creating an Azure Function App, in which you will create an Azure Function that regularly queries temperature data from Cosmos DB. In the next step, you will add the capability to send notifications, whenever the temperature reading exceeds a predefined threshold. Proceed as follows: 1. Sign in to the Azure Portal. -2. Click “Create a resource”, type “Function App”, and select it: +2. Click **Create a resource**, type “Function App”, and select it: ![img24 alt-text#center](figures/24.png) -3. Click Create, then select Consumption as a hosting option: +3. Click **Create**, then select Consumption as a hosting option: ![img25 alt-text#center](figures/25.png) 4. Provide the required details: * Subscription: Your Azure subscription. diff --git a/content/learning-paths/iot/azure-iot/portal.md b/content/learning-paths/iot/azure-iot/portal.md index 98ab0f249f..74369eda1b 100644 --- a/content/learning-paths/iot/azure-iot/portal.md +++ b/content/learning-paths/iot/azure-iot/portal.md @@ -127,7 +127,7 @@ Finally, open the index.html file and replace its content with the following HTM This HTML file represents the main structure and entry point of your IoT web portal. It is divided into Head and Body sections: The head body defines basic metadata such as character set (UTF-8) and viewport configuration for responsive design. Then, it sets the title of your webpage to "IoT Solution" and links your CSS stylesheet (styles.css), which defines the appearance of the page. -In the body section we have: +In the body section, you will see: * a centered container (div) with a clear heading (h1) labeled "IoT Solution". * a button (id="getTempBtn") that users click to trigger the JavaScript logic retrieving temperature data from your Azure Function. * a placeholder label (div) with the id "result" initially showing "Temperature: -- °C". The JavaScript updates this label dynamically with the actual temperature retrieved from your backend. @@ -150,39 +150,41 @@ You will now deploy the web portal you have created to Azure Blob Storage, makin ### Create and Configure Azure Blob Storage 1. Sign in to the Azure Portal. 2. Create a Storage Account: -* Click “Create a resource” -* Search for “Storage account” +* Click **Create a resource**. +* Search for “Storage account”. ![img45 alt-text#center](figures/45.png) -* Click “Create”. +* Click **Create**. ![img46 alt-text#center](figures/46.png) -3. Provide required details: -* Subscription, resource group, storage account name (e.g. armiotstorage). -* For Primary service, choose Azure Blob Storage or Azure Data Lake Storage Gen 2. -* Select Standard performance and Locally-redundant storage (LRS). +3. Provide the required details: +* Subscription, resource group, and storage account name (e.g. armiotstorage). +* For Primary service, choose **Azure Blob Storage** or **Azure Data Lake Storage Gen 2**. +* Select **Standard performance** and **Locally-redundant storage (LRS)**. ![img47 alt-text#center](figures/47.png) * Click "Review + create", then "Create". 3. Enable Static Website Hosting: * Navigate to your newly created storage account. -* Under Data management, click “Static website”. -* Select “Enabled”. +* Under Data management, click **Static website**. +* Select **Enabled**. * Set index.html as the index document name. ![img48 alt-text#center](figures/48.png) -* Click Save. +* Click **Save**. After saving, Azure provides you with a URL like: https://.z22.web.core.windows.net/. -Make sure to save this URL, as it will serve as the public endpoint for your website. +Save this URL, as it will serve as the public endpoint for your website. ### Upload Files to Azure Blob Storage -You can upload your website files directly using the Azure Portal or via Azure Storage Explorer. Here, you will use the Azure Portal: +You can upload your website files directly using the Azure Portal or via Azure Storage Explorer. Here, use the Azure Portal: 1. Navigate to your storage account. -2. Under Data storage, select “Containers”. +2. Under Data storage, select **Containers**. 3. Open the container named ”$web” (created automatically when enabling static websites). -4. Click Upload and select your three website files (index.html, main.js, styles.css), and upload them. +4. Click **Upload** and select your three website files (index.html, main.js, styles.css), and upload them. ![img49 alt-text#center](figures/49.png) ### Verify the Deployment -After uploading your files, open a browser and navigate to https://.z22.web.core.windows.net/. Your static website should load, allowing you to test the “Get temperature” button (to see temperatures make sure to start the IoT simulator): +After uploading your files, open a browser and navigate to https://.z22.web.core.windows.net/. + +Your static website should load, allowing you to test the **Get temperature** button (to see temperatures make sure to start the IoT simulator): ![img50 alt-text#center](figures/50.png) diff --git a/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md b/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md index 629d8f3128..05beb43a2b 100644 --- a/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md +++ b/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md @@ -50,40 +50,40 @@ You will now configure the stream analytics job such that the telemetry data wil ### Cosmos DB account and database Start by creating the Create Cosmos DB account and database: 1. Log in to the Azure Portal. -2. Select “Create a resource”, search for “Azure Cosmos DB”, and click Create: +2. Select **Create a resource**, search for “Azure Cosmos DB”, and click **Create**: ![img14 alt-text#center](figures/14.png) ![img15 alt-text#center](figures/15.png) -3. Select Azure Cosmos DB for NoSQL, then click Create. +3. Select Azure Cosmos DB for NoSQL, then click **Create**. ![img16 alt-text#center](figures/16.png) 4. Fill in the required details: -* Subscription: Select your subscription. -* Resource Group: Use your existing IoT resource group or create a new one. -* Account Name: Provide a unique name (e.g., armiotcosmosdb). -* Availability Zones: Disable. -* Region: Choose the same region as your IoT Hub and Stream Analytics job. -* Select Servleress as capacity mode. -* Apply Free Tier Discount: Apply +* Subscription: select your subscription. +* Resource Group: use your existing IoT resource group or create a new one. +* Account Name: provide a unique name (for example, armiotcosmosdb). +* Availability Zones: disable. +* Region: choose the same region as your IoT Hub and Stream Analytics job. +* Select servleress as capacity mode. +* Apply Free Tier Discount: apply * Check Limit total account throughput. ![img17 alt-text#center](figures/17.png) -5. Click Review + create, then click Create. +5. Click **Review + create**, then click **Create**. Once the deployment completes: -* Navigate to your Cosmos DB account and select “Data Explorer”. -* Click New Container, create a database (e.g., named IoTDatabase), and create a container named SensorReadings. +* Navigate to your Cosmos DB account and select **Data Explorer**. +* Click **New Container**, then create a database with a name such as "IoTDatabase", and create a container named "SensorReadings". * Select an appropriate partition key (recommended: /deviceId). * Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads: Off. -* Click OK at the bottom. +* Click **OK**. ![img18 alt-text#center](figures/18.png) ### Modify Stream Analytics Job Now update your query in Stream Analytics to write data from IoT Hub directly into Cosmos DB: 1. Go to `IoTStreamAnalyticsJob`. -2. Under Job topology, select Outputs. -3. Click Add output, and select Cosmos DB: +2. Under Job topology, select **Outputs**. +3. Click **Add output**, and select **Cosmos DB**: ![img19 alt-text#center](figures/19.png) -4. In the Cosmos DB pane, type CosmosDBOutput for the alias name, leave other fields at their default values, and click the Save button: +4. In the Cosmos DB pane, type "CosmosDBOutput" for the alias name, leave other fields at their default values, and click the **Save** button: ![img20 alt-text#center](figures/20.png) ### Update Your Stream Analytics Query @@ -104,12 +104,12 @@ FROM ![img21 alt-text#center](figures/21.png) -Afterwards, click Start job, and then Start: +Afterwards, click **Start job**, and then **Start**: ![img22 alt-text#center](figures/22.png) ## Verify data flow in Cosmos DB -To verify that your data pipeline is working correctly, first start your Python IoT simulator application `iot_simulator.py`. Ensure it's actively sending telemetry data. Next, open the Azure Portal and navigate to your Azure Cosmos DB resource. Under Data Explorer, select your database and then your container (e.g., SensorReadings). Once selected, click Items to view your stored data. Sensor readings streamed from your IoT device will appear on the right-hand side of the Data Explorer interface, similar to the screenshot below: +To verify that your data pipeline is working correctly, first start your Python IoT simulator application `iot_simulator.py`. Ensure it's actively sending telemetry data. Next, open the Azure Portal and navigate to your Azure Cosmos DB resource. Under Data Explorer, select your database and then your container (e.g., SensorReadings). Once selected, click **Items** to view your stored data. Sensor readings streamed from your IoT device will appear on the right-hand side of the Data Explorer interface, similar to the screenshot below: ![img23 alt-text#center](figures/23.png) diff --git a/content/learning-paths/iot/azure-iot/stream-analytics.md b/content/learning-paths/iot/azure-iot/stream-analytics.md index 2ef83e1c00..fbac8d5676 100644 --- a/content/learning-paths/iot/azure-iot/stream-analytics.md +++ b/content/learning-paths/iot/azure-iot/stream-analytics.md @@ -1,6 +1,6 @@ --- # User change -title: "Azure Stream Analytics" +title: "Process IoT telemetry in real time with Azure Stream Analytics" weight: 5 @@ -20,50 +20,50 @@ Azure Stream Analytics organizes real-time data processing through four main arc ## Create a Stream Analytics Job To process and analyze the telemetry data you are streaming to Azure IoT Hub, you will first create an Azure Stream Analytics job. Follow these steps to set it up: 1. Sign in to the Azure Portal. -2. Click “Create a resource”, type “Stream Analytics job” into the search box, and press Enter. -3. From the search results, select Stream Analytics job, then click Create: +2. Click **Create a resource**, type “Stream Analytics job” into the search box, and press **Enter**. +3. From the search results, select **Stream Analytics job**, then click **Create**: ![img9 alt-text#center](figures/09.png) 4. Provide the necessary information: -* Subscription: Choose the Azure subscription you want to use for this job. -* Resource group: Select the resource group you previously created (e.g., your IoT project's resource group). -* Name: Provide a meaningful, unique name for your Stream Analytics job (e.g., IoTStreamAnalyticsJob). -* Region: Choose the same Azure region as your IoT Hub for optimal performance and minimal latency. -* Hosting environment: Select Cloud for Azure-managed infrastructure. -* Streaming units: Set this to 1 (appropriate for initial testing and smaller workloads, you can scale up later). +* Subscription: choose the Azure subscription you want to use for this job. +* Resource group: select the resource group you previously created (e.g., your IoT project's resource group). +* Name: provide a meaningful, unique name for your Stream Analytics job (e.g., IoTStreamAnalyticsJob). +* Region: choose the same Azure region as your IoT Hub for optimal performance and minimal latency. +* Hosting environment: select Cloud for Azure-managed infrastructure. +* Streaming units: set this to 1 (appropriate for initial testing and smaller workloads, you can scale up later). ![img10 alt-text#center](figures/10.png) -5. After reviewing your settings carefully, click Review + create, confirm that all details are correct, and then click Create to deploy your Azure Stream Analytics job. +5. After reviewing your settings carefully, click **Review + create**, confirm that all details are correct, and then click **Create** to deploy your Azure Stream Analytics job. Your Stream Analytics job will deploy within a few minutes. Once the deployment is complete, you’ll be ready to configure inputs, define queries, and set outputs for real-time data processing and analytics. ## Configure Azure IoT Hub as an Input for Stream Analytics Job After successfully creating the Stream Analytics job, you will need to configure your Azure IoT Hub as an input source. This configuration allows Stream Analytics to read real-time telemetry data directly from your IoT devices. Follow these steps: 1. Navigate to your newly created Stream Analytics job in the Azure Portal. -2. In the left-hand menu, under the Job topology section, select Inputs. -3. Click “Add input”, and choose “IoT Hub” as the input type. +2. On the left-hand menu, under the **Job topology** section, select **Inputs**. +3. Click **Add input**, and choose **IoT Hub** as the input type. ![img11 alt-text#center](figures/11.png) 4. Enter the following configuration details: -* Input Alias: Provide a name, such as `IoTHubInput`. -* IoT Hub: Select the Azure IoT Hub you created earlier. -* Consumer group: Choose `$Default`, unless you have explicitly created a custom consumer group. -* Shared access policy name: Select `iothubowner` (provides full access for reading data from IoT Hub). -* Endpoint: Select Messaging. +* Input Alias: provide a name, such as `IoTHubInput`. +* IoT Hub: select the Azure IoT Hub you created earlier. +* Consumer group: choose `$Default`, unless you have explicitly created a custom consumer group. +* Shared access policy name: select `iothubowner` (which provides full access for reading data from IoT Hub). +* Endpoint: select Messaging. * Partition key: Type `deviceId` (this helps ensure the data streams are partitioned by device identifiers). -* Event serialization format: Select `JSON`, as our telemetry data is transmitted in `JSON` format. -* Encoding: Choose `UTF-8`. +* Event serialization format: select `JSON`, as our telemetry data is transmitted in `JSON` format. +* Encoding: Choose **UTF-8**. * Event compression type: Set this to None. ![img12 alt-text#center](figures/12.png) -4. After entering these details, carefully verify them for accuracy and completeness. Click Save to apply the changes and successfully link your Azure IoT Hub as the input source for your Stream Analytics job. +5. After entering these details, carefully verify them for accuracy and completeness. Click **Save** to apply the changes and successfully link your Azure IoT Hub as the input source for your Stream Analytics job. Your job is now configured to ingest streaming IoT telemetry data in real-time, preparing it for further analysis, storage, and visualization. ## Define the Stream Analytics Query Now that you have configured your Azure IoT Hub as an input source, the next step is to create and run a Stream Analytics query. This query defines how incoming IoT data will be filtered, transformed, or routed for further processing. Follow these steps: 1. Navigate to your Stream Analytics job in the Azure Portal. -2. Under the Job topology menu on the left, select Query. +2. Under the Job topology menu on the left, select **Query**. 3. In the query editor, enter the following simple `SQL-like` query to stream all incoming data from your IoT device ```SQL SELECT From b4784fb02e1f75cf09b42a8490d86949a256f533 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Thu, 22 May 2025 11:49:05 +0000 Subject: [PATCH 26/32] updates --- content/learning-paths/iot/azure-iot/portal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/learning-paths/iot/azure-iot/portal.md b/content/learning-paths/iot/azure-iot/portal.md index 74369eda1b..6f966985e6 100644 --- a/content/learning-paths/iot/azure-iot/portal.md +++ b/content/learning-paths/iot/azure-iot/portal.md @@ -138,7 +138,7 @@ Finally, the `index.html` includes the JavaScript file (main.js) placed at the e Make sure you have saved all three files (index.html, main.js, and styles.css). Next: 1. Start the IoT Simulator to begin streaming data to the Azure IoT Hub. 2. Open the index.html file locally in your web browser. -3. Click the "Get temperature" button. +3. Click the **Get temperature** button. You should now see real-time temperature readings displayed: From 13f92cd6c1ffbc8fec7432b2c5301289c7f6bb6c Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Thu, 22 May 2025 13:20:53 +0000 Subject: [PATCH 27/32] update --- content/learning-paths/iot/azure-iot/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/learning-paths/iot/azure-iot/_index.md b/content/learning-paths/iot/azure-iot/_index.md index b006d19ad5..51bd910181 100644 --- a/content/learning-paths/iot/azure-iot/_index.md +++ b/content/learning-paths/iot/azure-iot/_index.md @@ -1,5 +1,5 @@ --- -title: Build IoT Solutions in Azure for Arm-Powered Devices +title: Build IoT Solutions in Azure for Arm Devices minutes_to_complete: 180 From 3675b915a03a123c40b6182dae1fd13f9c76b298 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Thu, 22 May 2025 13:28:09 +0000 Subject: [PATCH 28/32] updates --- content/learning-paths/iot/azure-iot/_index.md | 2 +- content/learning-paths/iot/azure-iot/device_registration.md | 2 +- content/learning-paths/iot/azure-iot/intro.md | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/content/learning-paths/iot/azure-iot/_index.md b/content/learning-paths/iot/azure-iot/_index.md index 51bd910181..eae08eb1a7 100644 --- a/content/learning-paths/iot/azure-iot/_index.md +++ b/content/learning-paths/iot/azure-iot/_index.md @@ -3,7 +3,7 @@ title: Build IoT Solutions in Azure for Arm Devices minutes_to_complete: 180 -who_is_this_for: This is an advanced topic for developers who want to build a comprehensive IoT solution in Azure that streams, stores, monitors, aggregates, and visualizes telemetry data from Arm64-powered IoT devices. +who_is_this_for: This is an advanced topic for developers who want to build a comprehensive IoT solution in Azure that streams, stores, monitors, aggregates, and visualizes telemetry data from Arm IoT devices. learning_objectives: - Set up and configure Azure IoT Hub for device communication. diff --git a/content/learning-paths/iot/azure-iot/device_registration.md b/content/learning-paths/iot/azure-iot/device_registration.md index 9b7883562a..7e3fcdaca9 100644 --- a/content/learning-paths/iot/azure-iot/device_registration.md +++ b/content/learning-paths/iot/azure-iot/device_registration.md @@ -56,7 +56,7 @@ Successfully installed PySocks-1.7.1 azure-iot-device-2.14.0 deprecation-2.1.0 j ``` ## Creating a Python IoT Simulator Application -In this section, you will create a Python application that simulates realistic sensor data generated by an Arm64 powered IoT device and streams this data securely to Azure IoT Hub. You will define a reusable and structured `SensorReading` class, capable of generating randomized yet realistic sensor measurements, including temperature, pressure, humidity, and timestamps. +In this section, you will create a Python application that simulates realistic sensor data generated by an Arm IoT device and streams this data securely to Azure IoT Hub. You will define a reusable and structured `SensorReading` class, capable of generating randomized yet realistic sensor measurements, including temperature, pressure, humidity, and timestamps. After this, you will implement an asynchronous telemetry simulator method, which continuously generates sensor readings at predefined intervals and transmits them to Azure IoT Hub. diff --git a/content/learning-paths/iot/azure-iot/intro.md b/content/learning-paths/iot/azure-iot/intro.md index 79795b9b8c..02443b0ff3 100644 --- a/content/learning-paths/iot/azure-iot/intro.md +++ b/content/learning-paths/iot/azure-iot/intro.md @@ -13,7 +13,7 @@ The Internet of Things (IoT) is a technological landscape where physical devices By collecting and analyzing real-time data from interconnected sensors and devices, IoT solutions empower businesses to make informed decisions, predict maintenance needs, optimize resource usage, and deliver innovative user experiences. ## IoT and Arm Devices -Arm64-powered devices play a critical role in IoT applications due to their superior performance, efficiency, and energy optimization capabilities. Arm64, also known as AArch64, is a 64-bit architecture widely adopted in mobile devices, embedded systems, edge computing devices, and single-board computers such as Raspberry Pi 4, NVIDIA Jetson, and similar hardware platforms. +Arm devices play a critical role in IoT applications due to their superior performance, efficiency, and energy optimization capabilities. Arm64, also known as AArch64, is a 64-bit architecture widely adopted in mobile devices, embedded systems, edge computing devices, and single-board computers such as Raspberry Pi 4, NVIDIA Jetson, and similar hardware platforms. These devices are compact, cost-effective, and energy-efficient, making them ideally suited for battery-operated scenarios, remote monitoring systems, edge analytics, and IoT deployments in environments where power and computational efficiency are critical. By leveraging Arm64-based devices, developers can build intelligent, scalable, and energy-efficient IoT solutions that reduce operational costs while maximizing responsiveness and uptime. @@ -28,9 +28,9 @@ Overall, Azure IoT offers an extensive, secure, and highly scalable environment, ## Learning Path objectives -In this Learning Path, you’ll learn how to effectively leverage the Azure IoT ecosystem by building a complete, end-to-end IoT solution tailored specifically for Arm64-powered devices using Python. +In this Learning Path, you’ll learn how to effectively leverage the Azure IoT ecosystem by building a complete, end-to-end IoT solution tailored specifically for Arm devices using Python. -You’ll start by setting up and configuring an Azure IoT Hub, the central component that facilitates secure communication and device management. Next, You’ll register our Arm64 IoT device and use the Azure IoT Python SDK to stream real-time sensor data to the cloud. +You’ll start by setting up and configuring an Azure IoT Hub, the central component that facilitates secure communication and device management. Next, You’ll register your Arm IoT device and use the Azure IoT Python SDK to stream real-time sensor data to the cloud. Once data streaming is established, you’ll explore real-time analytics capabilities with Azure Stream Analytics, enabling immediate processing and transformation of incoming telemetry. You’ll store this streaming IoT data securely and efficiently in Azure Cosmos DB, configuring Stream Analytics to ensure seamless data persistence. To enhance our solution's robustness, you’ll implement a serverless data monitoring and alerting system using Azure Functions, automatically notifying users when sensor data exceeds predefined thresholds. From d7635097ac396e99acba4d9a8ca6b8e59b2f645a Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Thu, 22 May 2025 16:12:24 +0000 Subject: [PATCH 29/32] update --- content/install-guides/finch.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/install-guides/finch.md b/content/install-guides/finch.md index f6f4dd0d51..9957aee107 100644 --- a/content/install-guides/finch.md +++ b/content/install-guides/finch.md @@ -2,8 +2,6 @@ title: Finch author: Jason Andrews -draft: true - minutes_to_complete: 10 official_docs: https://runfinch.com/docs/ From a7217ca23ff76203899985010299eca97124bd5f Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Thu, 22 May 2025 12:46:09 -0500 Subject: [PATCH 30/32] review Azure IoT and update tags --- .../embedded-and-microcontrollers/_index.md | 9 ++++--- content/learning-paths/iot/_index.md | 10 ++++--- .../learning-paths/iot/azure-iot/_index.md | 3 +-- .../laptops-and-desktops/_index.md | 2 +- .../mobile-graphics-and-gaming/_index.md | 10 +++---- .../servers-and-cloud-computing/_index.md | 27 +++++++++---------- 6 files changed, 33 insertions(+), 28 deletions(-) diff --git a/content/learning-paths/embedded-and-microcontrollers/_index.md b/content/learning-paths/embedded-and-microcontrollers/_index.md index 2e43861441..bf67579ea7 100644 --- a/content/learning-paths/embedded-and-microcontrollers/_index.md +++ b/content/learning-paths/embedded-and-microcontrollers/_index.md @@ -11,7 +11,7 @@ maintopic: true operatingsystems_filter: - Android: 1 - Baremetal: 29 -- Linux: 27 +- Linux: 28 - macOS: 6 - RTOS: 9 - Windows: 4 @@ -20,7 +20,7 @@ subjects_filter: - Containers and Virtualization: 6 - Embedded Linux: 4 - Libraries: 3 -- ML: 12 +- ML: 13 - Performance and Architecture: 21 - RTOS Fundamentals: 4 - Security: 2 @@ -28,6 +28,7 @@ subjects_filter: subtitle: Learn best practices for microcontroller development title: Embedded and Microcontrollers tools_software_languages_filter: +- AI: 1 - Arduino: 1 - Arm Compiler for Embedded: 7 - Arm Compiler for Linux: 1 @@ -60,6 +61,7 @@ tools_software_languages_filter: - GitHub: 3 - GitLab: 1 - Himax SDK: 1 +- IoT: 1 - IP Explorer: 4 - Jupyter Notebook: 1 - K3s: 1 @@ -67,6 +69,7 @@ tools_software_languages_filter: - Keil MDK: 3 - Kubernetes: 1 - LLM: 2 +- MCP: 1 - MDK: 1 - MPS3: 1 - MXNet: 1 @@ -74,7 +77,7 @@ tools_software_languages_filter: - NumPy: 1 - Paddle: 1 - Porcupine: 1 -- Python: 5 +- Python: 6 - PyTorch: 2 - QEMU: 1 - Raspberry Pi: 5 diff --git a/content/learning-paths/iot/_index.md b/content/learning-paths/iot/_index.md index 001ca38f09..bf5ad029cd 100644 --- a/content/learning-paths/iot/_index.md +++ b/content/learning-paths/iot/_index.md @@ -12,15 +12,16 @@ subjects_filter: - CI-CD: 4 - Containers and Virtualization: 2 - Embedded Linux: 2 -- ML: 1 -- Performance and Architecture: 1 +- ML: 2 +- Performance and Architecture: 2 operatingsystems_filter: - Baremetal: 4 -- Linux: 7 +- Linux: 8 - macOS: 2 - RTOS: 2 - Windows: 2 tools_software_languages_filter: +- AI: 1 - Arm Compiler for Embedded: 1 - Arm Virtual Hardware: 6 - AWS IoT Greengrass: 1 @@ -31,7 +32,10 @@ tools_software_languages_filter: - Docker: 2 - Fixed Virtual Platform: 1 - GitHub: 3 +- IoT: 1 - Matter: 1 +- MCP: 1 +- Python: 2 - Raspberry Pi: 2 - Remote.It: 1 - VS Code: 1 diff --git a/content/learning-paths/iot/azure-iot/_index.md b/content/learning-paths/iot/azure-iot/_index.md index eae08eb1a7..77e137d122 100644 --- a/content/learning-paths/iot/azure-iot/_index.md +++ b/content/learning-paths/iot/azure-iot/_index.md @@ -22,10 +22,9 @@ author: Dawid Borycki ### Tags skilllevels: Advanced -subjects: Internet of Things +subjects: Performance and Architecture armips: - Cortex-A - - Neoverse operatingsystems: - Windows - Linux diff --git a/content/learning-paths/laptops-and-desktops/_index.md b/content/learning-paths/laptops-and-desktops/_index.md index 07f846a33c..d061cdb95b 100644 --- a/content/learning-paths/laptops-and-desktops/_index.md +++ b/content/learning-paths/laptops-and-desktops/_index.md @@ -34,8 +34,8 @@ tools_software_languages_filter: - C/C++: 4 - CCA: 1 - Clang: 11 -- CMake: 2 - cmake: 1 +- CMake: 2 - Coding: 16 - CSS: 1 - Daytona: 1 diff --git a/content/learning-paths/mobile-graphics-and-gaming/_index.md b/content/learning-paths/mobile-graphics-and-gaming/_index.md index 2b67baad4c..2047161d94 100644 --- a/content/learning-paths/mobile-graphics-and-gaming/_index.md +++ b/content/learning-paths/mobile-graphics-and-gaming/_index.md @@ -9,15 +9,15 @@ key_ip: - Mali maintopic: true operatingsystems_filter: -- Android: 29 -- Linux: 26 +- Android: 30 +- Linux: 27 - macOS: 12 - Windows: 11 subjects_filter: - Gaming: 6 - Graphics: 6 - ML: 10 -- Performance and Architecture: 29 +- Performance and Architecture: 30 subtitle: Optimize Android apps and build faster games using cutting-edge Arm tech title: Mobile, Graphics, and Gaming tools_software_languages_filter: @@ -34,7 +34,7 @@ tools_software_languages_filter: - Bazel: 1 - C: 1 - C#: 3 -- C++: 7 +- C++: 8 - C/C++: 1 - CCA: 1 - Clang: 10 @@ -60,7 +60,7 @@ tools_software_languages_filter: - NEON: 1 - ONNX Runtime: 1 - OpenGL ES: 1 -- Python: 3 +- Python: 4 - PyTorch: 1 - QEMU: 1 - RME: 1 diff --git a/content/learning-paths/servers-and-cloud-computing/_index.md b/content/learning-paths/servers-and-cloud-computing/_index.md index f6901fe010..1ba6abdd1f 100644 --- a/content/learning-paths/servers-and-cloud-computing/_index.md +++ b/content/learning-paths/servers-and-cloud-computing/_index.md @@ -8,7 +8,7 @@ key_ip: maintopic: true operatingsystems_filter: - Android: 2 -- Linux: 141 +- Linux: 143 - macOS: 10 - Windows: 14 pinned_modules: @@ -21,9 +21,9 @@ subjects_filter: - CI-CD: 5 - Containers and Virtualization: 27 - Databases: 15 -- Libraries: 8 -- ML: 28 -- Performance and Architecture: 51 +- Libraries: 9 +- ML: 27 +- Performance and Architecture: 53 - Storage: 1 - Web: 10 subtitle: Optimize cloud native apps on Arm for performance and cost @@ -33,7 +33,7 @@ tools_software_languages_filter: - .NET SDK: 1 - 5G: 1 - ACL: 1 -- AI: 2 +- AI: 1 - Android Studio: 1 - Ansible: 2 - Arm Compiler for Linux: 1 @@ -52,7 +52,7 @@ tools_software_languages_filter: - AWS Elastic Kubernetes Service (EKS): 3 - AWS Graviton: 1 - Bash: 1 -- bash: 1 +- bash: 2 - Bastion: 3 - BOLT: 1 - bpftool: 1 @@ -88,7 +88,7 @@ tools_software_languages_filter: - GitHub: 6 - GitLab: 1 - Glibc: 1 -- Go: 2 +- Go: 3 - Google Axion: 3 - Google Benchmark: 1 - Google Cloud: 1 @@ -97,7 +97,6 @@ tools_software_languages_filter: - Herd7: 1 - InnoDB: 1 - Intrinsics: 1 -- IoT: 1 - Java: 3 - JAX: 1 - Kafka: 1 @@ -111,7 +110,6 @@ tools_software_languages_filter: - llvm-mca: 1 - LSE: 1 - MariaDB: 1 -- MCP: 1 - Memcached: 2 - MLPerf: 1 - ModelScope: 1 @@ -119,7 +117,7 @@ tools_software_languages_filter: - mpi: 1 - MySQL: 9 - Neon: 3 -- NEON: 1 +- NEON: 2 - Nexmark: 1 - Nginx: 3 - Node.js: 3 @@ -128,14 +126,15 @@ tools_software_languages_filter: - OpenBLAS: 1 - PAPI: 1 - perf: 4 +- Perf: 1 - PostgreSQL: 4 -- Python: 28 +- Python: 27 - PyTorch: 9 - RAG: 1 - Redis: 3 - Remote.It: 2 -- RME: 4 -- Runbook: 66 +- RME: 6 +- Runbook: 68 - Rust: 2 - snappy: 1 - Snort3: 1 @@ -143,7 +142,7 @@ tools_software_languages_filter: - Streamline CLI: 1 - Streamlit: 2 - Supervisor: 1 -- SVE: 3 +- SVE: 4 - SVE2: 1 - Sysbench: 1 - Telemetry: 1 From 39829cbf492d2034a8206647524a1ab91337c596 Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Thu, 22 May 2025 13:33:49 -0500 Subject: [PATCH 31/32] spelling updates --- .wordlist.txt | 66 ++++++++++++++++++- .../azure-iot/stream-analytics-dynamo-db.md | 2 +- .../3-converting-model.md | 2 +- .../false-sharing-arm-spe/how-to-1.md | 4 +- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index 1f09969774..19e20f6759 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -4120,4 +4120,68 @@ pyproject toml virtualenv mebibytes -syscalls \ No newline at end of file +syscalls +ArchSpecificLibrary +Asahi +AsmSource +AutoEncoder +Avx +BuildCommand +BuildYourOwnKernel +CPPLibRecommend +CPPLibVersion +CPPStdCodes +CompilerSpecific +ConfigGuess +ConfigurationInfo +CrossCompile +DefineOtherArch +Denoises +DiT +Drozd +FlatBuffers +GolangInlineAsm +GolangIntrinsic +GolangLinkLibrary +HostCpuDetection +IncompatibleHeaderFile +InlineAsm +JavaJar +JavaPom +JavaSource +NoEquivalentInlineAsm +NoEquivalentIntrinsic +OldCrt +OpenAnolis +PreprocessorError +PythonInlineAsm +PythonIntrinsic +PythonLinkLibrary +PythonPackage +RustInlineAsm +RustIntrinsic +RustLinkLibrary +SentencePiece +SignedChar +Submodule +TUI +Wix’s +audiogen +bazelbuild +centos +cmdline +deadsnakes +flatbuffers +libmagic +litert +mv +ngrok’s +pagesize +runfinch +spiece +subcommand +subgenre +submodule +subword +techcrunch +transformative \ No newline at end of file diff --git a/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md b/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md index 05beb43a2b..b51a53b308 100644 --- a/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md +++ b/content/learning-paths/iot/azure-iot/stream-analytics-dynamo-db.md @@ -63,7 +63,7 @@ Start by creating the Create Cosmos DB account and database: * Account Name: provide a unique name (for example, armiotcosmosdb). * Availability Zones: disable. * Region: choose the same region as your IoT Hub and Stream Analytics job. -* Select servleress as capacity mode. +* Select serverless as capacity mode. * Apply Free Tier Discount: apply * Check Limit total account throughput. ![img17 alt-text#center](figures/17.png) diff --git a/content/learning-paths/mobile-graphics-and-gaming/run-stable-audio-open-small-with-lite-rt/3-converting-model.md b/content/learning-paths/mobile-graphics-and-gaming/run-stable-audio-open-small-with-lite-rt/3-converting-model.md index c180670e3e..9961483097 100644 --- a/content/learning-paths/mobile-graphics-and-gaming/run-stable-audio-open-small-with-lite-rt/3-converting-model.md +++ b/content/learning-paths/mobile-graphics-and-gaming/run-stable-audio-open-small-with-lite-rt/3-converting-model.md @@ -89,7 +89,7 @@ You can use the provided script to convert the Conditioners submodule: python3 ./scripts/export_conditioners.py --model_config "$WORKSPACE/model_config.json" --ckpt_path "$WORKSPACE/model.ckpt" ``` -After successful conversion, you now have a `tflite_conditioners` directory containing models with different precisions (e.g., float16, float32). +After successful conversion, you now have a `tflite_conditioners` directory containing models with different precision (e.g., float16, float32). You will be using the float32.tflite model for on-device inference. diff --git a/content/learning-paths/servers-and-cloud-computing/false-sharing-arm-spe/how-to-1.md b/content/learning-paths/servers-and-cloud-computing/false-sharing-arm-spe/how-to-1.md index 22c620c844..d99dac7e85 100644 --- a/content/learning-paths/servers-and-cloud-computing/false-sharing-arm-spe/how-to-1.md +++ b/content/learning-paths/servers-and-cloud-computing/false-sharing-arm-spe/how-to-1.md @@ -14,13 +14,13 @@ SPE integrates sampling directly into the CPU pipeline, triggering on individual This enables software developers to tune user-space software for characteristics such as memory latency and cache accesses. Importantly, cache statistics are enabled with the Linux Perf cache-to-cache (C2C) utility. -Please refer to the [Arm SPE whitepaper](https://developer.arm.com/documentation/109429/latest/) for more details. +Please refer to the [Arm SPE white paper](https://developer.arm.com/documentation/109429/latest/) for more details. In this Learning Path, you will use SPE and Perf C2C to diagnose a cache issue for an application running on a Neoverse server. ## False sharing within the cache -Even when two threads touch entirely separate variables, modern processors move data in fixed-size cache lines (nominally 64-bytes). If those distinct variables happen to occupy bytes within the same line, every time one thread writes its variable the core’s cache must gain exclusive ownership of the whole line, forcing the other core’s copy to be invalidated. The second thread, still working on its own variable, then triggers a coherence miss to fetch the line back, and the ping-pong pattern repeats. Please see the illustration below, taken from the Arm SPE whitepaper, for a visual explanation. +Even when two threads touch entirely separate variables, modern processors move data in fixed-size cache lines (nominally 64-bytes). If those distinct variables happen to occupy bytes within the same line, every time one thread writes its variable the core’s cache must gain exclusive ownership of the whole line, forcing the other core’s copy to be invalidated. The second thread, still working on its own variable, then triggers a coherence miss to fetch the line back, and the ping-pong pattern repeats. Please see the illustration below, taken from the Arm SPE white paper, for a visual explanation. ![false_sharing_diagram](./false_sharing_diagram.png) From 3802aadbf2c1adc49a5f0238e4276238c678d536 Mon Sep 17 00:00:00 2001 From: Maddy Underwood <167196745+madeline-underwood@users.noreply.github.com> Date: Thu, 22 May 2025 21:38:12 +0000 Subject: [PATCH 32/32] updates --- content/install-guides/finch.md | 41 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/content/install-guides/finch.md b/content/install-guides/finch.md index 9957aee107..174dd782da 100644 --- a/content/install-guides/finch.md +++ b/content/install-guides/finch.md @@ -1,5 +1,5 @@ --- -title: Finch +title: Finch on Arm Linux author: Jason Andrews minutes_to_complete: 10 @@ -22,11 +22,11 @@ multitool_install_part: false weight: 1 --- -[Finch](https://runfinch.com) is an open-source container development tool from AWS that provides a simple, Docker-compatible CLI for working with containers using containerd and nerdctl under the hood. Finch is designed for Linux, macOS, and Windows, and is especially useful on Arm-based systems for efficient container workflows. +[Finch](https://runfinch.com) is an open-source container development tool from AWS. It offers a simple, Docker-compatible CLI powered by containerd and nerdctl. Designed for Linux, macOS, and Windows, Finch is especially useful on Arm-based systems for efficient container workflows. -This guide explains how to install and use Finch on Arm Linux distributions, specifically Amazon Linux 2023 and Ubuntu 24.04. +This guide explains how to install Finch on Arm Linux distributions, specifically Amazon Linux 2023 and Ubuntu 24.04. -To use Finch as described in this install guide, you need a system running Arm Linux. You can use a physical Arm device, a cloud instance from AWS, Azure, GCP, or OCI, or an Arm-based virtual machine. +To get started, make sure you're using a system running Arm Linux. You can use a physical Arm device, a cloud instance from AWS, Azure, GCP, or OCI, or an Arm-based virtual machine. To confirm the architecture, run: @@ -34,7 +34,7 @@ To confirm the architecture, run: uname -m ``` -The output is `aarch64` for 64-bit Arm systems. +The output should be `aarch64` for 64-bit Arm systems. ## How do I install Finch on Amazon Linux 2023 for Arm? @@ -52,13 +52,13 @@ Enable and start the containerd service: sudo systemctl start containerd ``` -Confirm that the containerd service is running: +Check that the containerd service is running: ```console sudo systemctl status containerd ``` -The output shows the status: +You should see something like: ```output ● containerd.service - containerd container runtime @@ -74,17 +74,16 @@ The output shows the status: └─25841 /usr/bin/containerd ``` -The `finch` command is now available in your PATH. You can now skip to the section on verifying the Finch installation. +The `finch` command is now available in your PATH. You can now skip to the section on [verifying the Finch installation](#how-do-i-verify-the-finch-installation). -## How do I install Finch on Ubuntu 24.04 for Arm? -Finch does not provide a Debian package for Ubuntu, but you can install it manually as described below. +## How do I install Finch on Ubuntu 24.04 for Arm? -### What are the required Finch dependencies? +Finch doesn't currently provide a Debian package for Ubuntu, but you can install it manually, using the three steps outlined below. -First, install Nerdctl by following the instructions in the [Nerdctl install guide](/install-guides/nerdctl/). +### Step 1: Install Finch dependencies -You will also need various tools to build Finch. Install them using: +Install Nerdctl by following the instructions in the [Nerdctl install guide](/install-guides/nerdctl/). Then install the required tools: ```console sudo apt install -y \ @@ -93,9 +92,9 @@ sudo apt install -y \ build-essential ``` -### How do I build Finch from source code? +### Step 2: Build and install Finch -Run the commands below to download and build Finch from source: +Clone the Finch repository and build the binary: ```console git clone https://github.com/runfinch/finch.git @@ -105,7 +104,7 @@ make sudo make install ``` -### How do I configure Finch? +### Step 3: Configure Finch Create the Finch configuration directories: @@ -155,19 +154,21 @@ The version is printed: finch version v1.8.2 ``` -Run a simple container to confirm Finch is working: +Run a container to confirm functionality: ```bash sudo finch run --rm armswdev/uname ``` -If you see the architecture printed, then Finch is working correctly. The expected output is: +If you see the architecture printed, then Finch is working correctly. + +The expected output is: ```output Architecture is aarch64 ``` -Print the container images on your system: +Print your local container images: ```bash sudo finch images @@ -180,6 +181,6 @@ REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZ armswdev/uname latest 82762f30a4a3 43 seconds ago linux/arm64 110.4MB 28.89MB ``` -Use `sudo finch help` to discover additional Finch commands. +Use `sudo finch help` to explore available commands. You are ready to use Finch to run containers on your Arm Linux system.