From d3d0cbc594b20f7f9f07ee739e426d0a0cdc0801 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 12 Aug 2026 18:49:56 +0800 Subject: [PATCH] feat(ppa): add PPA FreeType font compositing example --- .codespellrc | 2 +- docs/en/api-reference/peripherals/ppa.rst | 3 +- docs/zh_CN/api-reference/peripherals/ppa.rst | 3 +- examples/peripherals/.build-test-rules.yml | 10 + .../jpeg/jpeg_encode/sdkconfig.defaults | 1 - .../ppa/ppa_freetype/CMakeLists.txt | 8 + .../peripherals/ppa/ppa_freetype/README.md | 97 ++++++ .../ppa/ppa_freetype/golden_text_overlay.ppm | 4 + .../ppa/ppa_freetype/main/CMakeLists.txt | 33 ++ .../ppa/ppa_freetype/main/idf_component.yml | 4 + .../main/ppa_freetype_example_main.c | 288 ++++++++++++++++++ .../ppa/ppa_freetype/partitions.csv | 6 + .../ppa/ppa_freetype/pytest_ppa_freetype.py | 207 +++++++++++++ .../ppa/ppa_freetype/sdkconfig.defaults | 7 + .../peripherals/ppa/ppa_transform/README.md | 6 +- .../ppa/ppa_transform/golden_result.ppm | Bin 230415 -> 230415 bytes .../main/ppa_transform_example_main.c | 95 +----- .../ppa/ppa_transform/pytest_ppa_transform.py | 1 - 18 files changed, 675 insertions(+), 100 deletions(-) create mode 100644 examples/peripherals/ppa/ppa_freetype/CMakeLists.txt create mode 100644 examples/peripherals/ppa/ppa_freetype/README.md create mode 100644 examples/peripherals/ppa/ppa_freetype/golden_text_overlay.ppm create mode 100644 examples/peripherals/ppa/ppa_freetype/main/CMakeLists.txt create mode 100644 examples/peripherals/ppa/ppa_freetype/main/idf_component.yml create mode 100644 examples/peripherals/ppa/ppa_freetype/main/ppa_freetype_example_main.c create mode 100644 examples/peripherals/ppa/ppa_freetype/partitions.csv create mode 100644 examples/peripherals/ppa/ppa_freetype/pytest_ppa_freetype.py create mode 100644 examples/peripherals/ppa/ppa_freetype/sdkconfig.defaults diff --git a/.codespellrc b/.codespellrc index ef27af48047..9c9720e3ebe 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,4 +1,4 @@ [codespell] -skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb,components/wpa_supplicant/*,components/esp_wifi/*,*.pem,*/COPYING*,docs/sphinx-known-warnings.txt +skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb,*.ppm,components/wpa_supplicant/*,components/esp_wifi/*,*.pem,*/COPYING*,docs/sphinx-known-warnings.txt ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart,wheight,wel,ot,fane,assertIn,registr,oen,parms,aCount write-changes = true diff --git a/docs/en/api-reference/peripherals/ppa.rst b/docs/en/api-reference/peripherals/ppa.rst index 9414289b5bf..8ed24ba8af1 100644 --- a/docs/en/api-reference/peripherals/ppa.rst +++ b/docs/en/api-reference/peripherals/ppa.rst @@ -175,8 +175,9 @@ The PPA operations are acted on the target block of an input picture. Therefore, Application Examples ^^^^^^^^^^^^^^^^^^^^ -* :example:`peripherals/ppa/ppa_transform` - PPA transform image processing example. The embedded RGB565 image is transformed by SRM, highlighted with blend, framed with fill, and emitted as base64 for host-side PPM reconstruction and golden-image comparison. +* :example:`peripherals/ppa/ppa_transform` - PPA transform image processing example. The embedded RGB565 image is transformed by SRM, framed with fill, and emitted as base64 for host-side PPM reconstruction and golden-image comparison. * :example:`peripherals/ppa/ppa_color_key` - PPA blend color-keying example. The example generates a centered RGB888 glow foreground in software, then demonstrates two blend effects on the embedded RGB565 image: replacing the keyed red `ESP32` text with the glow, and preserving the keyed text while blending the glow into the non-key area. Both results are emitted as base64 for host-side PPM reconstruction and golden-image comparison. +* :example:`peripherals/ppa/ppa_freetype` - PPA FreeType icon compositing example. The example uses the `espressif/freetype` component to rasterize Font Awesome icon code points (two rows of three) into small per-glyph A8 alpha masks, then uses the PPA blend engine to composite each glyph over a software-generated gradient with a fixed icon color. The final composited RGB565 frame is emitted as base64 for host-side PPM reconstruction and golden-image comparison. API Reference ------------- diff --git a/docs/zh_CN/api-reference/peripherals/ppa.rst b/docs/zh_CN/api-reference/peripherals/ppa.rst index 58f4001603f..9b62cb26c7d 100644 --- a/docs/zh_CN/api-reference/peripherals/ppa.rst +++ b/docs/zh_CN/api-reference/peripherals/ppa.rst @@ -175,8 +175,9 @@ PPA 操作作用于输入图片的目标块。因此,完成一次 PPA 事务 应用示例 ^^^^^^^^^ -* :example:`peripherals/ppa/ppa_transform` - PPA transform 图像处理示例。嵌入的 RGB565 图像会经过 SRM 变换、blend 高亮和 fill 边框处理,然后以 base64 输出,供主机端重建为 PPM 并与 golden 图像比对。 +* :example:`peripherals/ppa/ppa_transform` - PPA transform 图像处理示例。嵌入的 RGB565 图像会经过 SRM 变换和 fill 边框处理,然后以 base64 输出,供主机端重建为 PPM 并与 golden 图像比对。 * :example:`peripherals/ppa/ppa_color_key` - PPA blend color key 示例。示例先在软件中生成居中的 RGB888 glow 前景,然后在嵌入式 RGB565 图片上演示两种 blend 效果:一种是通过 blend color key 将命中的红色 `ESP32` 文本像素替换为 glow,另一种是在保留命中文本的同时,将 glow 混合到非 key 区域。两种结果都会以 base64 输出,供主机端重建为 PPM 并与 golden 图像比对。 +* :example:`peripherals/ppa/ppa_freetype` - PPA FreeType 图标合成示例。示例使用 `espressif/freetype` 组件将 Font Awesome 图标的 Unicode 码点(两行,每行三个)栅格化为小的逐字形 A8 透明度掩码,然后通过 PPA blend 引擎以固定图标颜色将每个字形合成到软件生成的渐变背景上。最终合成后的 RGB565 帧会以 base64 输出,供主机端重建为 PPM 并与 golden 图像比对。 API 参考 -------- diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 90f9bb4e7a6..c614127e9fd 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -528,6 +528,16 @@ examples/peripherals/ppa/ppa_color_key: - mbedtls - soc +examples/peripherals/ppa/ppa_freetype: + disable: + - if: SOC_PPA_SUPPORTED != 1 + depends_components: + - esp_driver_dma + - esp_driver_ppa + - esp_hal_ppa + - mbedtls + - soc + examples/peripherals/ppa/ppa_transform: disable: - if: SOC_PPA_SUPPORTED != 1 diff --git a/examples/peripherals/jpeg/jpeg_encode/sdkconfig.defaults b/examples/peripherals/jpeg/jpeg_encode/sdkconfig.defaults index 87d024ce27f..01fa5c7f82f 100644 --- a/examples/peripherals/jpeg/jpeg_encode/sdkconfig.defaults +++ b/examples/peripherals/jpeg/jpeg_encode/sdkconfig.defaults @@ -1,6 +1,5 @@ CONFIG_SPIRAM=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_ESPTOOLPY_FLASHSIZE="4MB" diff --git a/examples/peripherals/ppa/ppa_freetype/CMakeLists.txt b/examples/peripherals/ppa/ppa_freetype/CMakeLists.txt new file mode 100644 index 00000000000..c2c20aef474 --- /dev/null +++ b/examples/peripherals/ppa/ppa_freetype/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(ppa_freetype) diff --git a/examples/peripherals/ppa/ppa_freetype/README.md b/examples/peripherals/ppa/ppa_freetype/README.md new file mode 100644 index 00000000000..4aa0f273bf4 --- /dev/null +++ b/examples/peripherals/ppa/ppa_freetype/README.md @@ -0,0 +1,97 @@ +| Supported Targets | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | --------- | + +# PPA FreeType Example + +## Overview + +This example demonstrates how to render [Font Awesome](https://fontawesome.com/) icons with the FreeType library and composite them over a picture with the PPA blend engine, all without any display hardware. + +The example uses the `espressif/freetype` component (declared in `main/idf_component.yml`) to rasterize two rows of three icons: + +1. `star` (U+F005), `heart` (U+F004), `sun` (U+F185) +2. `face-smile` (U+F118), `bell` (U+F0F3), `envelope` (U+F0E0) + +It then generates a vertical gradient background in software, and lets the PPA blend engine composite every glyph over the gradient with a fixed white text color, one icon per `ppa_do_blend` call. The final RGB565 overlay result is base64-encoded and printed to the serial console. The accompanying pytest script reconstructs the composite as a color PPM and compares it with the golden reference image. + +The processing pipeline demonstrates: + +- FreeType: initialize the library, load an OTF font from a LittleFS partition, and rasterize each glyph into a small per-glyph A8 alpha mask +- Blend: call `ppa_do_blend` once per glyph, moving the blend target region (block) to each icon's bounding box and compositing the A8 glyph mask over the gradient using `fg_fix_rgb_val` as the icon color + +Blending one character at a time avoids building a full-frame A8 mask in software and allocating a large intermediate mask buffer, and it shows a multi-blend loop that moves the target region for every glyph. + +## Hardware Required + +* An ESP development board with PPA support +* An USB cable for power supply and programming + +## Build and Flash + +Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +```text +I (1555) main_task: Calling app_main() +LittleFS mounted +FreeType library initialized +Font loaded +Compositing text with PPA blend... +Rendering icon row at baseline Y=120: U+F005 U+F004 U+F185 +Rendering icon row at baseline Y=180: U+F118 U+F0F3 U+F0E0 +IMAGE_META effect=text_overlay width=320 height=240 format=RGB565 encoding=base64 +IMAGE_BASE64_BEGIN +IMAGE_BASE64 ... +IMAGE_BASE64 ... +IMAGE_BASE64_END +PPA FreeType demo done. +I (10085) main_task: Returned from app_main() +``` + +## Pytest Visual Check + +The accompanying `pytest_ppa_freetype.py` script captures the `IMAGE_META` and `IMAGE_BASE64` output, reconstructs the composite image, and saves it as: + +- `dut.logdir/ppa_freetype_text_overlay.ppm` + +The test compares the reconstructed RGB888 image byte-for-byte with `golden_text_overlay.ppm`. This turns the example into a functional regression test and a visual artifact generator for CI logs. + +### Getting The PPM Result Locally + +If you want to inspect the processed image on your computer, first build the example for your target, then run pytest from the example directory with the matching target and serial port: + +```bash +pytest pytest_ppa_freetype.py --target esp32p4 --port PORT +``` + +Replace `esp32p4` with another supported target such as `esp32s31`, and set `PORT` to your board's serial device. + +`pytest-embedded` stores per-test logs under `$IDF_PATH/pytest-embedded/`. When the test finishes, pytest prints a log line similar to: + +```text +Saved PPA artifact to .../pytest-embedded//esp32p4.default.test_ppa_freetype/ppa_freetype_text_overlay.ppm +``` + +You can open the generated PPM file from that log directory with any image viewer to inspect the PPA composite output locally. + +## Changing The Icons Or Font + +The rendered icons, font size, baselines, and icon color are all plain `#define`s at the top of `main/ppa_freetype_example_main.c`: + +- `EXAMPLE_ICON_ROW1` / `EXAMPLE_ICON_ROW2` - the two rows of Font Awesome code points (3 per row) +- `EXAMPLE_ROW1_BASELINE_Y` / `EXAMPLE_ROW2_BASELINE_Y` - the baseline row of each row in the 320x240 frame +- `EXAMPLE_FONT_PIXEL_SIZE` - the pixel size passed to `FT_Set_Pixel_Sizes()` +- `EXAMPLE_FG_R/G/B` - the fixed icon color used by the blend engine + +### Font Source And Format + +The example displays Font Awesome 7.3.1 Free regular icons. Font Awesome ships its Free fonts in several flavours: WOFF2 (`webfonts/fa-regular-400.woff2`) and OpenType (`otfs/Font Awesome 7 Free-Regular-400.otf`). The `espressif/freetype` component is built without WOFF2/brotli support, so it cannot decode a WOFF2 file directly. The OpenType (OTF) flavour, however, is fully supported by FreeType. + +So instead of committing a font binary into the tree, `main/CMakeLists.txt` downloads the OTF variant from the Font Awesome 7.3.1 release at build time (`Font Awesome 7 Free-Regular-400.otf` from ) and packs it into the `fonts` LittleFS partition as `fa-regular-400.otf`. + +The font is cached in the build directory after its first successful download. If the download fails, CMake stops with the upstream error instead of producing an invalid LittleFS image. diff --git a/examples/peripherals/ppa/ppa_freetype/golden_text_overlay.ppm b/examples/peripherals/ppa/ppa_freetype/golden_text_overlay.ppm new file mode 100644 index 00000000000..c502baeb0ce --- /dev/null +++ b/examples/peripherals/ppa/ppa_freetype/golden_text_overlay.ppm @@ -0,0 +1,4 @@ +P6 +320 240 +255 +)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!M!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!I!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!E!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A!A<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889U{9Y8888888888888888888888888888888888888888888888888888888888888888888888888888888888BY{9U8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888881UB]88888888888888888888888888888888888888888888888888888888888888888888888888888888JaBY888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<<8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889YJe88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888JeBa8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888B]Je8888888888888888888888888!AZqskJe<888888888888 +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "esp_littlefs.h" +#include "esp_log.h" +#include "mbedtls/base64.h" +#include "driver/ppa.h" +#include "freetype/freetype.h" + +#define EXAMPLE_IMAGE_WIDTH 320 +#define EXAMPLE_IMAGE_HEIGHT 240 +#define EXAMPLE_RGB565_PIXEL_SIZE 2 +#define EXAMPLE_IMAGE_SIZE (EXAMPLE_IMAGE_WIDTH * EXAMPLE_IMAGE_HEIGHT * EXAMPLE_RGB565_PIXEL_SIZE) +#define EXAMPLE_BASE64_CHUNK_LEN 96 + +#define EXAMPLE_FONT_PATH "/fonts/fa-regular-400.otf" +#define EXAMPLE_FONT_PIXEL_SIZE 40 + +/* The final composited image shows Font Awesome icons arranged in two rows of + * three, so six icons in total. Each row is rendered on its own baseline row so + * they stack vertically. The code points below are the Font Awesome Free + * regular glyphs (fa-regular-400): star, heart, sun / face-smile, bell, envelope. */ +#define EXAMPLE_ICONS_PER_ROW 3 +#define EXAMPLE_ICON_ROWS 2 +#define EXAMPLE_ICON_ROW1 0xF005, 0xF004, 0xF185 /* star, heart, sun */ +#define EXAMPLE_ICON_ROW2 0xF118, 0xF0F3, 0xF0E0 /* face-smile, bell, envelope */ +#define EXAMPLE_ROW1_BASELINE_Y 120 +#define EXAMPLE_ROW2_BASELINE_Y 180 +#define EXAMPLE_FG_R 0xff +#define EXAMPLE_FG_G 0xff +#define EXAMPLE_FG_B 0xff + +/* The Font Awesome icons to display, one row per line. Each row holds three + * icons and is rendered on its own baseline so the two rows stack vertically. */ +static const uint32_t example_icon_rows[EXAMPLE_ICON_ROWS][EXAMPLE_ICONS_PER_ROW] = { + { EXAMPLE_ICON_ROW1 }, + { EXAMPLE_ICON_ROW2 }, +}; +static const int example_icon_baseline_y[EXAMPLE_ICON_ROWS] = { + EXAMPLE_ROW1_BASELINE_Y, + EXAMPLE_ROW2_BASELINE_Y, +}; + +static const char *TAG = "example"; + +static void print_base64_payload(const unsigned char *encoded, size_t encoded_len) +{ + printf("IMAGE_BASE64_BEGIN\n"); + size_t chunk_count = 0; + for (size_t offset = 0; offset < encoded_len; offset += EXAMPLE_BASE64_CHUNK_LEN) { + size_t chunk_len = encoded_len - offset; + if (chunk_len > EXAMPLE_BASE64_CHUNK_LEN) { + chunk_len = EXAMPLE_BASE64_CHUNK_LEN; + } + printf("IMAGE_BASE64 %.*s\n", (int)chunk_len, (const char *)&encoded[offset]); + chunk_count++; + if ((chunk_count % 16) == 0) { + /* The complete payload is large. Yield periodically so the serial + * monitor used by pytest can consume every line reliably. */ + vTaskDelay(1); + } + } + printf("IMAGE_BASE64_END\n"); +} + +static void encode_and_print_image(const char *effect_name, const char *pixel_format, + const uint8_t *image, size_t image_size) +{ + /* Binary image data is not safe to print directly on the serial console. + * Base64 turns it into ASCII that pytest can capture and decode. */ + size_t encoded_len = 0; + int ret = mbedtls_base64_encode(NULL, 0, &encoded_len, image, image_size); + ESP_ERROR_CHECK((ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) ? ESP_OK : ESP_FAIL); + + unsigned char *encoded = calloc(encoded_len + 1, 1); + ESP_ERROR_CHECK(encoded ? ESP_OK : ESP_ERR_NO_MEM); + ESP_ERROR_CHECK(mbedtls_base64_encode(encoded, encoded_len + 1, &encoded_len, image, image_size) == 0 ? ESP_OK : ESP_FAIL); + + printf("IMAGE_META effect=%s width=%u height=%u format=%s encoding=base64\n", + effect_name, EXAMPLE_IMAGE_WIDTH, EXAMPLE_IMAGE_HEIGHT, pixel_format); + print_base64_payload(encoded, encoded_len); + free(encoded); +} + +/* Report one rendered icon row to the console so the serial log and pytest can + * verify the exact set of Font Awesome icons being drawn. */ +static void report_icon_row(const uint32_t *icons, int count, int baseline_y) +{ + printf("Rendering icon row at baseline Y=%d:", baseline_y); + for (int i = 0; i < count; i++) { + printf(" U+%04X", (unsigned int)icons[i]); + } + printf("\n"); +} + +/* Rasterize a single Font Awesome glyph and composite it over the output frame + * with one PPA blend transaction. Instead of building a full-frame A8 mask in + * software, this helper lets PPA blend one glyph at a time into its own target + * region (the glyph's bounding box), so no large intermediate mask buffer is + * needed and the example shows a multi-blend loop. */ +static void compose_glyph(ppa_client_handle_t ppa_blend_handle, FT_Face face, + uint32_t icon, int pen_x, int baseline_y, + void *image_buf) +{ + ESP_ERROR_CHECK(FT_Load_Char(face, icon, FT_LOAD_RENDER) == 0 ? ESP_OK : ESP_FAIL); + + FT_GlyphSlot slot = face->glyph; + uint32_t w = slot->bitmap.width; + uint32_t h = slot->bitmap.rows; + /* bitmap_left uses the same right-positive X axis as the framebuffer. */ + int dst_x = pen_x + slot->bitmap_left; + /* bitmap_top is measured upward from the baseline, while framebuffer Y + * increases downward, hence the subtraction. */ + int dst_y = baseline_y - slot->bitmap_top; + + /* A glyph may produce an empty bitmap (e.g. a space); nothing to blend. */ + if (w == 0 || h == 0 || dst_x < 0 || dst_y < 0 || + dst_x + (int)w > EXAMPLE_IMAGE_WIDTH || dst_y + (int)h > EXAMPLE_IMAGE_HEIGHT) { + return; + } + + /* PPA accepts any addressable input buffer, including FreeType's internal + * SRAM bitmap. Its pitch is the row stride in bytes; use it as pic_w so + * PPA advances to the correct row when FreeType adds row padding. Negative + * pitch denotes a bottom-up bitmap, which PPA cannot consume directly. */ + if (slot->bitmap.pitch <= 0 || (uint32_t)slot->bitmap.pitch < w) { + ESP_LOGE(TAG, "Unsupported glyph bitmap pitch %d for U+%04X", + slot->bitmap.pitch, (unsigned int)icon); + abort(); + } + uint32_t glyph_pitch = (uint32_t)slot->bitmap.pitch; + + /* Blend the single-glyph A8 mask over the current image, writing the result + * back in place into the glyph's own bounding box. The target region + * (block) is moved for every glyph by changing block_offset_x/y. */ + ppa_blend_oper_config_t blend_config = { + .in_bg = { + .buffer = image_buf, + .pic_w = EXAMPLE_IMAGE_WIDTH, + .pic_h = EXAMPLE_IMAGE_HEIGHT, + .block_w = w, + .block_h = h, + .block_offset_x = dst_x, + .block_offset_y = dst_y, + .blend_cm = PPA_BLEND_COLOR_MODE_RGB565, + }, + .in_fg = { + .buffer = slot->bitmap.buffer, + .pic_w = glyph_pitch, + .pic_h = h, + .block_w = w, + .block_h = h, + .block_offset_x = 0, + .block_offset_y = 0, + .blend_cm = PPA_BLEND_COLOR_MODE_A8, + }, + .out = { + .buffer = image_buf, + .buffer_size = EXAMPLE_IMAGE_SIZE, + .pic_w = EXAMPLE_IMAGE_WIDTH, + .pic_h = EXAMPLE_IMAGE_HEIGHT, + .block_offset_x = dst_x, + .block_offset_y = dst_y, + .blend_cm = PPA_BLEND_COLOR_MODE_RGB565, + }, + .bg_alpha_update_mode = PPA_ALPHA_NO_CHANGE, + .fg_alpha_update_mode = PPA_ALPHA_NO_CHANGE, + .fg_fix_rgb_val = { + .r = EXAMPLE_FG_R, + .g = EXAMPLE_FG_G, + .b = EXAMPLE_FG_B, + }, + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + ESP_ERROR_CHECK(ppa_do_blend(ppa_blend_handle, &blend_config)); +} + +/* Render one row of Font Awesome icons. The icons are spaced evenly (using each + * glyph's advance) and the whole row is centered horizontally on the given + * baseline row. Each icon is composited by a separate ppa_do_blend call whose + * target region is updated to the corresponding glyph's bounding box. */ +static void render_icon_row(ppa_client_handle_t ppa_blend_handle, FT_Face face, + const uint32_t *icons, int count, int baseline_y, + void *image_buf) +{ + ESP_ERROR_CHECK(FT_Set_Pixel_Sizes(face, 0, EXAMPLE_FONT_PIXEL_SIZE) == 0 ? ESP_OK : ESP_FAIL); + + /* FreeType stores glyph advances in 26.6 fixed-point format (pixels × 64). + * Shift right by 6 to convert them to whole-pixel pen positions. */ + /* First pass: compute the total advance of the row so it can be centered. */ + int total_advance = 0; + for (int i = 0; i < count; i++) { + ESP_ERROR_CHECK(FT_Load_Char(face, icons[i], FT_LOAD_DEFAULT) == 0 ? ESP_OK : ESP_FAIL); + total_advance += face->glyph->advance.x >> 6; + } + int pen_x = (EXAMPLE_IMAGE_WIDTH - total_advance) / 2; + + /* Second pass: blend each icon of the row into its own target region. */ + for (int i = 0; i < count; i++) { + compose_glyph(ppa_blend_handle, face, icons[i], pen_x, baseline_y, image_buf); + pen_x += face->glyph->advance.x >> 6; + } +} + +static void prepare_gradient_background(uint8_t *bg_buf) +{ + /* Generate a vertical RGB565 gradient in software as the background. This + * demonstrates that PPA can composite a rendered glyph buffer over any + * user-produced picture. The top color is brighter and the bottom darker. */ + const uint32_t top_rgb[3] = { 40, 80, 180 }; + const uint32_t bot_rgb[3] = { 8, 16, 60 }; + + for (int y = 0; y < EXAMPLE_IMAGE_HEIGHT; y++) { + uint32_t t = (uint32_t)y * 255 / (EXAMPLE_IMAGE_HEIGHT - 1); + uint32_t r = (top_rgb[0] * (255 - t) + bot_rgb[0] * t) / 255; + uint32_t g = (top_rgb[1] * (255 - t) + bot_rgb[1] * t) / 255; + uint32_t b = (top_rgb[2] * (255 - t) + bot_rgb[2] * t) / 255; + uint16_t v = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); + for (int x = 0; x < EXAMPLE_IMAGE_WIDTH; x++) { + bg_buf[(y * EXAMPLE_IMAGE_WIDTH + x) * 2] = v & 0xff; + bg_buf[(y * EXAMPLE_IMAGE_WIDTH + x) * 2 + 1] = (v >> 8) & 0xff; + } + } +} + +void app_main(void) +{ + /* Mount the LittleFS partition that stores the font. */ + esp_vfs_littlefs_conf_t littlefs_conf = { + .base_path = "/fonts", + .partition_label = "fonts", + .format_if_mount_failed = true, + }; + ESP_ERROR_CHECK(esp_vfs_littlefs_register(&littlefs_conf)); + printf("LittleFS mounted\n"); + + /* Initialize FreeType library and load the font. */ + FT_Library library = NULL; + FT_Face face = NULL; + ESP_ERROR_CHECK(FT_Init_FreeType(&library) == 0 ? ESP_OK : ESP_FAIL); + printf("FreeType library initialized\n"); + ESP_ERROR_CHECK(FT_New_Face(library, EXAMPLE_FONT_PATH, 0, &face) == 0 ? ESP_OK : ESP_FAIL); + printf("Font loaded\n"); + + /* Create a software gradient picture, then update it in place for every + * glyph. This preserves both the background outside glyph blocks and any + * previously composited glyphs that overlap a later glyph block. */ + uint8_t *result_buf = heap_caps_aligned_calloc(64, 1, EXAMPLE_IMAGE_SIZE, + MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + ESP_ERROR_CHECK(result_buf ? ESP_OK : ESP_ERR_NO_MEM); + prepare_gradient_background(result_buf); + + ppa_client_handle_t ppa_blend_handle = NULL; + ppa_client_config_t ppa_blend_config = { + .oper_type = PPA_OPERATION_BLEND, + .max_pending_trans_num = 1, + }; + ESP_ERROR_CHECK(ppa_register_client(&ppa_blend_config, &ppa_blend_handle)); + + printf("Compositing text with PPA blend...\n"); + /* Composite each Font Awesome icon with its own PPA blend transaction. Every + * glyph is rasterized into a small A8 mask and blended over the background + * at its own target region, so no full-frame A8 mask is required. */ + for (int row = 0; row < EXAMPLE_ICON_ROWS; row++) { + report_icon_row(example_icon_rows[row], EXAMPLE_ICONS_PER_ROW, example_icon_baseline_y[row]); + render_icon_row(ppa_blend_handle, face, example_icon_rows[row], EXAMPLE_ICONS_PER_ROW, + example_icon_baseline_y[row], result_buf); + } + + encode_and_print_image("text_overlay", "RGB565", result_buf, EXAMPLE_IMAGE_SIZE); + printf("PPA FreeType demo done.\n"); + + ESP_ERROR_CHECK(ppa_unregister_client(ppa_blend_handle)); + free(result_buf); + FT_Done_Face(face); + FT_Done_FreeType(library); + ESP_ERROR_CHECK(esp_vfs_littlefs_unregister("fonts")); +} diff --git a/examples/peripherals/ppa/ppa_freetype/partitions.csv b/examples/peripherals/ppa/ppa_freetype/partitions.csv new file mode 100644 index 00000000000..78f5b641182 --- /dev/null +++ b/examples/peripherals/ppa/ppa_freetype/partitions.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +fonts, data, littlefs, , 0xF0000, diff --git a/examples/peripherals/ppa/ppa_freetype/pytest_ppa_freetype.py b/examples/peripherals/ppa/ppa_freetype/pytest_ppa_freetype.py new file mode 100644 index 00000000000..d3379a63272 --- /dev/null +++ b/examples/peripherals/ppa/ppa_freetype/pytest_ppa_freetype.py @@ -0,0 +1,207 @@ +# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import base64 +import hashlib +import logging +import re +from dataclasses import dataclass +from pathlib import Path + +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets + +IMAGE_META_PATTERN = ( + r'IMAGE_META effect=(?P\w+) width=(?P\d+) height=(?P\d+) ' + r'format=(?P\w+) encoding=(?P\w+)' +) +IMAGE_META_RE = re.compile(IMAGE_META_PATTERN) +IMAGE_CHUNK_PATTERN = r'IMAGE_BASE64 (?P[A-Za-z0-9+/=]+)' +IMAGE_CHUNK_RE = re.compile(IMAGE_CHUNK_PATTERN) +TEXT_OVERLAY_EFFECT = 'text_overlay' +EXPECTED_PIXEL_FORMAT = 'RGB565' +EXPECTED_ENCODING = 'base64' +RGB565_BYTES_PER_PIXEL = 2 +RGB888_BYTES_PER_PIXEL = 3 +PPM_MAGIC = b'P6' +PPM_MAX_VALUE = b'255' +PPM_HEADER_RE = re.compile(rb'^P6\s+(?P\d+)\s+(?P\d+)\s+(?P\d+)\s') + + +@dataclass(frozen=True) +class ImageMetadata: + effect: str + width: int + height: int + pixel_format: str + encoding: str + + @property + def rgb565_size(self) -> int: + return self.width * self.height * RGB565_BYTES_PER_PIXEL + + +@dataclass(frozen=True) +class RgbImage: + width: int + height: int + pixels_rgb888: bytes + + def __post_init__(self) -> None: + expected_size = self.width * self.height * RGB888_BYTES_PER_PIXEL + if len(self.pixels_rgb888) != expected_size: + raise ValueError(f'Expected {expected_size} RGB bytes, got {len(self.pixels_rgb888)}') + + +def parse_image_metadata(meta_line: str) -> ImageMetadata: + match = IMAGE_META_RE.fullmatch(meta_line) + if not match: + raise ValueError(f'Invalid image metadata line: {meta_line}') + + return ImageMetadata( + effect=match.group('effect'), + width=int(match.group('width')), + height=int(match.group('height')), + pixel_format=match.group('format'), + encoding=match.group('encoding'), + ) + + +def collect_base64_payload(dut: Dut) -> list[str]: + payload_lines: list[str] = [] + while True: + match = dut.expect(rf'(?PIMAGE_BASE64_END|{IMAGE_CHUNK_PATTERN}\r?\n)') + line = match.group('line').decode('utf-8').strip() + if line == 'IMAGE_BASE64_END': + return payload_lines + + chunk_match = IMAGE_CHUNK_RE.fullmatch(line) + assert chunk_match is not None + payload_lines.append(chunk_match.group('payload')) + + +def _rgb565_to_rgb888(raw_bytes: bytes) -> bytes: + # PPM stores 8-bit RGB triplets, so expand each RGB565 pixel before writing the artifact. + rgb_bytes = bytearray(len(raw_bytes) // 2 * 3) + for pixel_index, offset in enumerate(range(0, len(raw_bytes), 2)): + pixel = raw_bytes[offset] | (raw_bytes[offset + 1] << 8) + red = (pixel >> 11) & 0x1F + green = (pixel >> 5) & 0x3F + blue = pixel & 0x1F + rgb_offset = pixel_index * 3 + rgb_bytes[rgb_offset : rgb_offset + 3] = ( + (red << 3) | (red >> 2), + (green << 2) | (green >> 4), + (blue << 3) | (blue >> 2), + ) + return bytes(rgb_bytes) + + +def _encode_ppm(image: RgbImage) -> bytes: + header = b'%s\n%d %d\n%s\n' % (PPM_MAGIC, image.width, image.height, PPM_MAX_VALUE) + return header + image.pixels_rgb888 + + +def _load_ppm(path: Path) -> RgbImage: + ppm_bytes = path.read_bytes() + header_match = PPM_HEADER_RE.match(ppm_bytes) + if not header_match: + raise ValueError('Invalid PPM header') + + width = int(header_match.group('width')) + height = int(header_match.group('height')) + max_value = header_match.group('max_value') + if width <= 0 or height <= 0: + raise ValueError('Unsupported PPM dimensions') + if max_value != PPM_MAX_VALUE: + raise ValueError(f'Unsupported PPM max value: {max_value.decode("ascii", errors="replace")}') + + pixel_data = ppm_bytes[header_match.end() :] + expected_size = width * height * RGB888_BYTES_PER_PIXEL + if len(pixel_data) != expected_size: + raise ValueError(f'Expected {expected_size} PPM pixel bytes, got {len(pixel_data)}') + + return RgbImage(width=width, height=height, pixels_rgb888=pixel_data) + + +def decode_rgb565_base64_image(metadata: ImageMetadata, payload_lines: list[str]) -> RgbImage: + if metadata.pixel_format != EXPECTED_PIXEL_FORMAT: + raise ValueError(f'Unsupported pixel format: {metadata.pixel_format}') + if metadata.encoding != EXPECTED_ENCODING: + raise ValueError(f'Unsupported payload encoding: {metadata.encoding}') + + raw_bytes = base64.b64decode(''.join(payload_lines), validate=True) + if len(raw_bytes) != metadata.rgb565_size: + raise ValueError(f'Expected {metadata.rgb565_size} decoded bytes, got {len(raw_bytes)}') + + return RgbImage(width=metadata.width, height=metadata.height, pixels_rgb888=_rgb565_to_rgb888(raw_bytes)) + + +def save_ppm_artifact(image: RgbImage, output_path: Path) -> None: + output_path.parent.mkdir(parents=True, exist_ok=True) + try: + output_path.write_bytes(_encode_ppm(image)) + except OSError: + logging.exception('Failed to save PPA artifact to %s', output_path) + return + + logging.info('Saved PPA artifact to %s', output_path) + + +def image_digest(image: RgbImage) -> str: + digest = hashlib.sha256() + digest.update(image.width.to_bytes(4, 'big')) + digest.update(image.height.to_bytes(4, 'big')) + digest.update(image.pixels_rgb888) + return digest.hexdigest() + + +def assert_image_matches_golden(result_image: RgbImage, golden_path: Path) -> None: + assert golden_path.is_file(), f'Golden image not found: {golden_path}' + golden_image = _load_ppm(golden_path) + + assert image_digest(result_image) == image_digest(golden_image), ( + f'Generated image does not match golden file: {golden_path.name}' + ) + + +def effect_output_name(effect: str) -> str: + return f'ppa_freetype_{effect}.ppm' + + +def effect_golden_name(effect: str) -> str: + return f'golden_{effect}.ppm' + + +def expect_and_check_image(dut: Dut, effect: str) -> None: + metadata_line = dut.expect(IMAGE_META_PATTERN).group(0).decode('utf-8') + metadata = parse_image_metadata(metadata_line) + assert metadata.effect == effect, f'Expected effect {effect}, got {metadata.effect}' + + dut.expect_exact('IMAGE_BASE64_BEGIN') + base64_chunks = collect_base64_payload(dut) + + result_image = decode_rgb565_base64_image(metadata, base64_chunks) + output_path = Path(dut.logdir) / effect_output_name(effect) + save_ppm_artifact(result_image, output_path) + + golden_path = Path(__file__).with_name(effect_golden_name(effect)) + assert_image_matches_golden(result_image, golden_path) + + +@pytest.mark.generic +@idf_parametrize('target', soc_filtered_targets('SOC_PPA_SUPPORTED == 1'), indirect=['target']) +def test_ppa_freetype(dut: Dut) -> None: + dut.expect_exact('LittleFS mounted') + dut.expect_exact('FreeType library initialized') + dut.expect_exact('Font loaded') + dut.expect_exact('Compositing text with PPA blend...') + # Row 1: star, heart, sun (U+F005, U+F004, U+F185). + dut.expect_exact('Rendering icon row at baseline Y=120: U+F005 U+F004 U+F185') + # Row 2: face-smile, bell, envelope (U+F118, U+F0F3, U+F0E0). + dut.expect_exact('Rendering icon row at baseline Y=180: U+F118 U+F0F3 U+F0E0') + + expect_and_check_image(dut, TEXT_OVERLAY_EFFECT) + + dut.expect_exact('PPA FreeType demo done.') diff --git a/examples/peripherals/ppa/ppa_freetype/sdkconfig.defaults b/examples/peripherals/ppa/ppa_freetype/sdkconfig.defaults new file mode 100644 index 00000000000..a9234cab581 --- /dev/null +++ b/examples/peripherals/ppa/ppa_freetype/sdkconfig.defaults @@ -0,0 +1,7 @@ +CONFIG_SPIRAM=y + +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000 +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y diff --git a/examples/peripherals/ppa/ppa_transform/README.md b/examples/peripherals/ppa/ppa_transform/README.md index 75cf831bf5b..0ba71cc8fee 100644 --- a/examples/peripherals/ppa/ppa_transform/README.md +++ b/examples/peripherals/ppa/ppa_transform/README.md @@ -5,14 +5,13 @@ ## Overview -This example demonstrates how to use `esp_driver_ppa` to process an embedded RGB565 image without any display hardware. +This example demonstrates how to use `esp_driver_ppa` to transform and fill an embedded RGB565 image without any display hardware. -The example embeds a pre-generated raw RGB565 image, processes it with three PPA engines, then base64-encodes the final RGB565 buffer and prints it to the serial console. The accompanying pytest script reconstructs the image as a PPM file and compares it with a golden reference image. +The example embeds a pre-generated raw RGB565 image, processes it with two PPA engines, then base64-encodes the final RGB565 buffer and prints it to the serial console. The accompanying pytest script reconstructs the image as a PPM file and compares it with a golden reference image. The processing pipeline demonstrates: - SRM: rotate the full image by 180 degrees -- Blend: overlay a cyan A8-mask highlight using a fixed foreground color - Fill: draw an amber frame and blue corner markers ## Hardware Required @@ -35,7 +34,6 @@ I (1555) main_task: Calling app_main() Loading embedded RGB565 image from flash... Embedded raw image size: 153600 bytes Transforming image with PPA SRM... -Blending highlight with PPA blend... Drawing border with PPA fill... IMAGE_META width=320 height=240 format=RGB565 encoding=base64 IMAGE_BASE64_BEGIN diff --git a/examples/peripherals/ppa/ppa_transform/golden_result.ppm b/examples/peripherals/ppa/ppa_transform/golden_result.ppm index 6842b444b12f8c609ee1281f8911c5172ba70026..0ba1459a58e706938ac5ea2c5d8df7778b8e86ab 100644 GIT binary patch delta 78508 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 delta 80263 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 diff --git a/examples/peripherals/ppa/ppa_transform/main/ppa_transform_example_main.c b/examples/peripherals/ppa/ppa_transform/main/ppa_transform_example_main.c index 97ed5ac462d..091aaca0174 100644 --- a/examples/peripherals/ppa/ppa_transform/main/ppa_transform_example_main.c +++ b/examples/peripherals/ppa/ppa_transform/main/ppa_transform_example_main.c @@ -18,10 +18,8 @@ #define EXAMPLE_IMAGE_HEIGHT 240 #define EXAMPLE_RGB565_PIXEL_SIZE 2 #define EXAMPLE_IMAGE_SIZE (EXAMPLE_IMAGE_WIDTH * EXAMPLE_IMAGE_HEIGHT * EXAMPLE_RGB565_PIXEL_SIZE) -#define EXAMPLE_ALPHA_MASK_SIZE (EXAMPLE_IMAGE_WIDTH * EXAMPLE_IMAGE_HEIGHT) #define EXAMPLE_BASE64_CHUNK_LEN 96 #define EXAMPLE_BORDER_WIDTH 8 -#define EXAMPLE_HIGHLIGHT_ALPHA 160 /* The raw RGB565 asset is embedded by target_add_binary_data() in CMakeLists.txt. * RENAME_TO "image_rgb" gives the linker symbols below. */ @@ -144,73 +142,6 @@ static void draw_border(ppa_client_handle_t ppa_fill_handle, void *buffer) fill_rect(ppa_fill_handle, buffer, EXAMPLE_IMAGE_WIDTH - 56, EXAMPLE_IMAGE_HEIGHT - 88, 16, 48, blue); } -static void prepare_alpha_mask(uint8_t *alpha_mask) -{ - /* The blend stage uses this A8 image as a foreground alpha mask. Pixels with - * alpha 0 keep the transformed background unchanged; semi-transparent pixels - * mix the fixed cyan foreground color with the background. */ - for (int y = 0; y < EXAMPLE_IMAGE_HEIGHT; y++) { - for (int x = 0; x < EXAMPLE_IMAGE_WIDTH; x++) { - const int dx = x - (EXAMPLE_IMAGE_WIDTH * 2 / 3); - const int dy = y - (EXAMPLE_IMAGE_HEIGHT / 2); - const int distance2 = dx * dx + dy * dy; - uint8_t alpha = (distance2 < 70 * 70) ? EXAMPLE_HIGHLIGHT_ALPHA : 0; - if (x > y && x < y + 80) { - alpha = EXAMPLE_HIGHLIGHT_ALPHA; - } - alpha_mask[y * EXAMPLE_IMAGE_WIDTH + x] = alpha; - } - } -} - -static void blend_highlight(ppa_client_handle_t ppa_blend_handle, const void *bg_buf, - const void *alpha_mask, void *out_buf) -{ - /* Use the transformed RGB565 image as the background and an A8 mask as the - * foreground. fg_fix_rgb_val provides the cyan color for masked pixels. */ - ppa_blend_oper_config_t blend_config = { - .in_bg = { - .buffer = bg_buf, - .pic_w = EXAMPLE_IMAGE_WIDTH, - .pic_h = EXAMPLE_IMAGE_HEIGHT, - .block_w = EXAMPLE_IMAGE_WIDTH, - .block_h = EXAMPLE_IMAGE_HEIGHT, - .block_offset_x = 0, - .block_offset_y = 0, - .blend_cm = PPA_BLEND_COLOR_MODE_RGB565, - }, - .in_fg = { - .buffer = alpha_mask, - .pic_w = EXAMPLE_IMAGE_WIDTH, - .pic_h = EXAMPLE_IMAGE_HEIGHT, - .block_w = EXAMPLE_IMAGE_WIDTH, - .block_h = EXAMPLE_IMAGE_HEIGHT, - .block_offset_x = 0, - .block_offset_y = 0, - .blend_cm = PPA_BLEND_COLOR_MODE_A8, - }, - .out = { - .buffer = out_buf, - .buffer_size = EXAMPLE_IMAGE_SIZE, - .pic_w = EXAMPLE_IMAGE_WIDTH, - .pic_h = EXAMPLE_IMAGE_HEIGHT, - .block_offset_x = 0, - .block_offset_y = 0, - .blend_cm = PPA_BLEND_COLOR_MODE_RGB565, - }, - .bg_alpha_update_mode = PPA_ALPHA_NO_CHANGE, - .fg_alpha_update_mode = PPA_ALPHA_NO_CHANGE, - .fg_fix_rgb_val = { - .r = 0x18, - .g = 0xf0, - .b = 0xff, - }, - .mode = PPA_TRANS_MODE_BLOCKING, - }; - - ESP_ERROR_CHECK(ppa_do_blend(ppa_blend_handle, &blend_config)); -} - static void encode_and_print_image(const uint8_t *image, size_t image_size) { /* Binary image data is not safe to print directly on the serial console. @@ -237,10 +168,6 @@ void app_main(void) assert(embedded_size == EXAMPLE_IMAGE_SIZE); uint8_t *srm_buf = alloc_ppa_buffer(EXAMPLE_IMAGE_SIZE); - uint8_t *result_buf = alloc_ppa_buffer(EXAMPLE_IMAGE_SIZE); - uint8_t *alpha_mask = alloc_ppa_buffer(EXAMPLE_ALPHA_MASK_SIZE); - - prepare_alpha_mask(alpha_mask); ppa_client_handle_t ppa_srm_handle = NULL; ppa_client_config_t ppa_srm_config = { @@ -249,13 +176,6 @@ void app_main(void) }; ESP_ERROR_CHECK(ppa_register_client(&ppa_srm_config, &ppa_srm_handle)); - ppa_client_handle_t ppa_blend_handle = NULL; - ppa_client_config_t ppa_blend_config = { - .oper_type = PPA_OPERATION_BLEND, - .max_pending_trans_num = 1, - }; - ESP_ERROR_CHECK(ppa_register_client(&ppa_blend_config, &ppa_blend_handle)); - ppa_client_handle_t ppa_fill_handle = NULL; ppa_client_config_t ppa_fill_config = { .oper_type = PPA_OPERATION_FILL, @@ -263,28 +183,21 @@ void app_main(void) }; ESP_ERROR_CHECK(ppa_register_client(&ppa_fill_config, &ppa_fill_handle)); - /* The three steps below are deliberately simple and independent: + /* The two steps below are deliberately simple and independent: * 1. SRM transforms the source image into srm_buf. - * 2. Blend overlays a highlighted shape into result_buf. - * 3. Fill draws visible markers directly into result_buf. */ + * 2. Fill draws visible markers directly into srm_buf. */ printf("Transforming image with PPA SRM...\n"); /* PPA is backed by DMA2D, which can read the source image directly from * mapped flash. Only the destination buffers need DMA-capable RAM here. */ transform_image(ppa_srm_handle, image_rgb_start, srm_buf); - printf("Blending highlight with PPA blend...\n"); - blend_highlight(ppa_blend_handle, srm_buf, alpha_mask, result_buf); - printf("Drawing border with PPA fill...\n"); - draw_border(ppa_fill_handle, result_buf); + draw_border(ppa_fill_handle, srm_buf); - encode_and_print_image(result_buf, EXAMPLE_IMAGE_SIZE); + encode_and_print_image(srm_buf, EXAMPLE_IMAGE_SIZE); printf("PPA image processing demo done.\n"); ESP_ERROR_CHECK(ppa_unregister_client(ppa_srm_handle)); - ESP_ERROR_CHECK(ppa_unregister_client(ppa_blend_handle)); ESP_ERROR_CHECK(ppa_unregister_client(ppa_fill_handle)); free(srm_buf); - free(result_buf); - free(alpha_mask); } diff --git a/examples/peripherals/ppa/ppa_transform/pytest_ppa_transform.py b/examples/peripherals/ppa/ppa_transform/pytest_ppa_transform.py index 2cec4ecb0e2..010e0e4667d 100644 --- a/examples/peripherals/ppa/ppa_transform/pytest_ppa_transform.py +++ b/examples/peripherals/ppa/ppa_transform/pytest_ppa_transform.py @@ -170,7 +170,6 @@ def test_ppa_transform(dut: Dut) -> None: dut.expect_exact('Loading embedded RGB565 image from flash...') dut.expect(r'Embedded raw image size: \d+ bytes') dut.expect_exact('Transforming image with PPA SRM...') - dut.expect_exact('Blending highlight with PPA blend...') dut.expect_exact('Drawing border with PPA fill...') metadata_line = dut.expect(IMAGE_META_PATTERN).group(0).decode('utf-8')