Merge pull request #185 from adafruit/add-favicon

Add favicon icon support
This commit is contained in:
Ha Thach 2022-01-25 18:12:49 +07:00 committed by GitHub
commit 9104f7c114
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1021 additions and 227 deletions

View file

@ -29,7 +29,7 @@ jobs:
- 'imxrt1020_evk'
- 'imxrt1060_evk'
- 'metro_m7_1011'
#stm32f3
# stm32f3
- 'stm32f303disco'
# stm32f4
- 'feather_stm32f405_express'
@ -111,54 +111,3 @@ jobs:
asset_path: ${{ env.ENV_PORT }}/_bin/${{ matrix.board }}/update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
asset_name: update-tinyuf2-${{ matrix.board }}-${{ github.event.release.tag_name }}.uf2
asset_content_type: application/x-binary
# ---------------------------------------
# Unit testing with ghostfat
# ---------------------------------------
GHOSTFAT:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
board:
# Alphabetical order
# test_ghostfat
- 'test_4k_cluster'
- 'test_32k_cluster'
- 'test_base'
- 'test_huge'
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Checkout code
uses: actions/checkout@v2
- name: Build
run: |
make --directory ports/test_ghostfat/ BOARD=${{ matrix.board }} all
- name: Copy known good filesystem image
# NOTE: test_huge's knowngood.img file starts as 1.5 GiB
# Compressing once with GZip results gives 85 MiB
# Compressing it a second time gives 10 MiB ...
# Therefore, store known good images double-compressed...
run: |
pushd ./ports/test_ghostfat/
cp ./boards/${{ matrix.board }}/knowngood.img.gz.gz ./_build/${{ matrix.board }}/
popd
- name: Decompress known good filesystem image
run: |
pushd ./ports/test_ghostfat/
gzip --decompress ./_build/${{ matrix.board }}/knowngood.img.gz.gz
gzip --decompress ./_build/${{ matrix.board }}/knowngood.img.gz
popd
- name: Execute native self-test
run: |
pushd ./ports/test_ghostfat/_build/${{ matrix.board }}/
chmod +x ./tinyuf2-${{ matrix.board }}.elf
./tinyuf2-${{ matrix.board }}.elf
popd

82
.github/workflows/build_selftest.yml vendored Normal file
View file

@ -0,0 +1,82 @@
name: GhostFAT Selftest
on:
pull_request:
push:
repository_dispatch:
release:
types:
- created
jobs:
# ---------------------------------------
# Unit testing with ghostfat
# ---------------------------------------
GHOSTFAT:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
board:
# Alphabetical order
# test_ghostfat
- '4k'
- '4k_favicon'
- '32k'
- '32k_favicon'
- '512b'
- '512b_favicon'
- 'huge'
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Checkout code
uses: actions/checkout@v2
- name: Build
run: |
make --directory ports/test_ghostfat/ BOARD=${{ matrix.board }} all
- name: Copy known good filesystem image
# NOTE: test_huge's knowngood.img file starts as 1.5 GiB
# Compressing once with GZip results gives 85 MiB
# Compressing it a second time gives 10 MiB ...
# Therefore, store known good images double-compressed...
run: |
pushd ./ports/test_ghostfat/
cp ./boards/${{ matrix.board }}/knowngood.img.gz.gz ./_build/${{ matrix.board }}/
popd
- name: Decompress known good filesystem image
run: |
pushd ./ports/test_ghostfat/
gzip --decompress ./_build/${{ matrix.board }}/knowngood.img.gz.gz
gzip --decompress ./_build/${{ matrix.board }}/knowngood.img.gz
popd
- name: Execute native self-test
if: always()
run: |
pushd ./ports/test_ghostfat/_build/${{ matrix.board }}/
chmod +x ./tinyuf2-${{ matrix.board }}.elf
./tinyuf2-${{ matrix.board }}.elf
popd
- name: Compress newly generated self-test images
if: always()
run: |
pushd ./ports/test_ghostfat/_build/${{ matrix.board }}/
mv ghostfat.img ghostfat_${{ matrix.board }}.img
gzip --keep ghostfat_${{ matrix.board }}.img
gzip --keep --force --best ghostfat_${{ matrix.board }}.img.gz
popd
- name: Save newly generated self-test images as CI artifacts
if: always()
uses: actions/upload-artifact@v2
with:
name: ghostfat_selftest_images
path: ./ports/test_ghostfat/_build/${{ matrix.board }}/ghostfat_${{ matrix.board }}.img.gz.gz

View file

@ -89,14 +89,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x0117
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Camera"
#define USB_VID 0x239A
#define USB_PID 0x0117
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Camera"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-Camera-revA"
#define UF2_VOLUME_LABEL "CAMERABOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-Camera-revA"
#define UF2_VOLUME_LABEL "CAMERABOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -63,14 +63,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x00EB
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Feather ESP32-S2"
#define USB_VID 0x239A
#define USB_PID 0x00EB
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Feather ESP32-S2"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-Feather-revA"
#define UF2_VOLUME_LABEL "FTHRS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/pid" // TODO update link
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-Feather-revA"
#define UF2_VOLUME_LABEL "FTHRS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/pid" // TODO update link
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -95,15 +95,18 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x00ED
#define USB_VID 0x239A
#define USB_PID 0x00ED
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Feather ESP32-S2 Reverse TFT"
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Feather ESP32-S2 Reverse TFT"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-FeatherRevTFT-revB"
#define UF2_VOLUME_LABEL "FTHRS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/5345"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-FeatherRevTFT-revB"
#define UF2_VOLUME_LABEL "FTHRS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/5345"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -95,15 +95,18 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x010F
#define USB_VID 0x239A
#define USB_PID 0x010F
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Feather ESP32-S2 TFT"
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Feather ESP32-S2 TFT"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-FeatherTFT-revA"
#define UF2_VOLUME_LABEL "FTHRS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/5300" // TODO update link
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-FeatherTFT-revA"
#define UF2_VOLUME_LABEL "FTHRS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/5300"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -92,14 +92,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x00F9
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "FunHouse"
#define USB_VID 0x239A
#define USB_PID 0x00F9
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "FunHouse"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-FunHouse-revB"
#define UF2_VOLUME_LABEL "HOUSEBOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-FunHouse-revB"
#define UF2_VOLUME_LABEL "HOUSEBOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -64,14 +64,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x00E5
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "MagTag 2.9 Grayscale"
#define USB_VID 0x239A
#define USB_PID 0x00E5
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "MagTag 2.9 Grayscale"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-MagTag_29gray-revC"
#define UF2_VOLUME_LABEL "MAGTAGBOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/4800"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-MagTag_29gray-revC"
#define UF2_VOLUME_LABEL "MAGTAGBOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/4800"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -60,14 +60,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x00DF
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Metro ESP32-S2"
#define USB_VID 0x239A
#define USB_PID 0x00DF
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "Metro ESP32-S2"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-Metro-revC"
#define UF2_VOLUME_LABEL "METROS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/4775"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-Metro-revC"
#define UF2_VOLUME_LABEL "METROS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/4775"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -58,14 +58,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x0111
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "QT Py ESP32-S2"
#define USB_VID 0x239A
#define USB_PID 0x0111
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "QT Py ESP32-S2"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-QTPY-revB"
#define UF2_VOLUME_LABEL "QTPYS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/5325" // TODO update link
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S2-QTPY-revB"
#define UF2_VOLUME_LABEL "QTPYS2BOOT"
#define UF2_INDEX_URL "https://www.adafruit.com/product/5325"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -64,15 +64,17 @@
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x239A
#define USB_PID 0x0119
#define USB_VID 0x239A
#define USB_PID 0x0119
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "QT Py ESP32-S3"
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "QT Py ESP32-S3"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S3-QTPy-A"
#define UF2_VOLUME_LABEL "QTPYS3BOOT"
#define UF2_INDEX_URL "https://adafruit.com"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "ESP32S3-QTPy-A"
#define UF2_VOLUME_LABEL "QTPYS3BOOT"
#define UF2_INDEX_URL "https://adafruit.com" // TODO udate product link
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -73,4 +73,7 @@
#define UF2_VOLUME_LABEL "SAOLA1RBOOT"
#define UF2_INDEX_URL "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html"
// Use favicon
#define TINYUF2_FAVICON_HEADER "favicon_adafruit_256.h"
#endif

View file

@ -74,12 +74,18 @@ else
# Bootloader src, board folder and TinyUSB stack
SRC_C += \
$(subst $(TOP)/,,$(wildcard $(TOP)/src/*.c)) \
src/ghostfat.c \
src/images.c \
src/main.c \
src/msc.c \
src/screen.c \
src/usb_descriptors.c \
$(subst $(TOP)/,,$(wildcard $(TOP)/$(BOARD_DIR)/*.c))
# Include
INC += \
$(TOP)/src \
$(TOP)/src/favicon \
$(TOP)/$(PORT_DIR) \
$(TOP)/$(BOARD_DIR)

View file

@ -29,6 +29,7 @@ SRC_S +=
# Port include
INC += \
$(TOP)/src \
$(TOP)/src/favicon \
$(TOP)/$(PORT_DIR) \
$(TOP)/$(BOARD_DIR) \

View file

@ -35,8 +35,8 @@
#define USB_PRODUCT "SELFTEST"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "Test_4k"
#define UF2_VOLUME_LABEL "Test_4k"
#define UF2_BOARD_ID "32k"
#define UF2_VOLUME_LABEL "32k"
#define UF2_INDEX_URL "https://www.adafruit.com"
#endif

Binary file not shown.

View file

@ -35,8 +35,8 @@
#define USB_PRODUCT "SELFTEST"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "Test_32k"
#define UF2_VOLUME_LABEL "Test_32k"
#define UF2_BOARD_ID "32k_fav"
#define UF2_VOLUME_LABEL "32k_fav"
#define UF2_INDEX_URL "https://www.adafruit.com"
#endif

View file

@ -0,0 +1,6 @@
CFLAGS += \
-DTINYUF2_FAVICON_HEADER=\"favicon_adafruit_256.h\" \
-DCFG_UF2_NUM_BLOCKS=265000 \
-DCFG_UF2_SECTORS_PER_CLUSTER=64 \
-DCOMPILE_DATE=\"Mar\ 11\ 2020\" \
-DCOMPILE_TIME=\"17:35:07\"

View file

@ -35,8 +35,8 @@
#define USB_PRODUCT "SELFTEST"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "TestBase"
#define UF2_VOLUME_LABEL "TestBase"
#define UF2_BOARD_ID "4k"
#define UF2_VOLUME_LABEL "4k"
#define UF2_INDEX_URL "https://www.adafruit.com"
#endif

Binary file not shown.

View file

@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018 Ha Thach for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BOARD_H_
#define BOARD_H_
//--------------------------------------------------------------------+
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x0000
#define USB_PID 0x0000
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "SELFTEST"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "4k_fav"
#define UF2_VOLUME_LABEL "4k_fav"
#define UF2_INDEX_URL "https://www.adafruit.com"
#endif

View file

@ -0,0 +1,5 @@
CFLAGS += \
-DTINYUF2_FAVICON_HEADER=\"favicon_adafruit_256.h\" \
-DCFG_UF2_SECTORS_PER_CLUSTER=8 \
-DCOMPILE_DATE=\"Mar\ 11\ 2020\" \
-DCOMPILE_TIME=\"17:35:07\"

View file

@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018 Ha Thach for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BOARD_H_
#define BOARD_H_
//--------------------------------------------------------------------+
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x0000
#define USB_PID 0x0000
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "SELFTEST"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "512b"
#define UF2_VOLUME_LABEL "512b"
#define UF2_INDEX_URL "https://www.adafruit.com"
#endif

Binary file not shown.

View file

@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018 Ha Thach for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BOARD_H_
#define BOARD_H_
//--------------------------------------------------------------------+
// USB UF2
//--------------------------------------------------------------------+
#define USB_VID 0x0000
#define USB_PID 0x0000
#define USB_MANUFACTURER "Adafruit"
#define USB_PRODUCT "SELFTEST"
#define UF2_PRODUCT_NAME USB_MANUFACTURER " " USB_PRODUCT
#define UF2_BOARD_ID "512b_Fav"
#define UF2_VOLUME_LABEL "512b_Fav"
#define UF2_INDEX_URL "https://www.adafruit.com"
#endif

View file

@ -0,0 +1,4 @@
CFLAGS += \
-DTINYUF2_FAVICON_HEADER=\"favicon_adafruit_256.h\" \
-DCOMPILE_DATE=\"Mar\ 11\ 2020\" \
-DCOMPILE_TIME=\"17:35:07\"

View file

@ -373,11 +373,14 @@ int main(void)
{
int r;
printf("initializing UF2\n"); fflush(stdout);
uf2_init();
printf("generating new disk image\n"); fflush(stdout);
r = DumpDiskImage();
if (r) { goto errorExit; }
printf("comparing against known good disk image\n"); fflush(stdout);
r = CompareDiskImages();
if (r) { goto errorExit; }
@ -385,7 +388,7 @@ int main(void)
return ERR_NONE;
errorExit:
printf("Failed -- %s\n", GetErrorString(r));
printf("FAIL: (%d) %s\n", r, GetErrorString(r));
return r;
}

View file

@ -1,5 +1,5 @@
idf_component_register(SRCS ghostfat.c images.c main.c msc.c screen.c usb_descriptors.c
INCLUDE_DIRS "."
INCLUDE_DIRS "." "favicon"
REQUIRES boards)
target_sources(${COMPONENT_TARGET} PUBLIC

View file

@ -54,6 +54,13 @@
#define TINYUF2_DISPLAY 0
#endif
// Use favicon.ico + autorun.inf (only works with windows)
// define TINYUF2_FAVICON_HEADER to enable this feature
//--------------------------------------------------------------------+
// Constant
//--------------------------------------------------------------------+
#define DBL_TAP_MAGIC 0xf01669ef // Enter DFU magic
#define DBL_TAP_MAGIC_QUICK_BOOT 0xf02669ef // Skip double tap delay detection
#define DBL_TAP_MAGIC_ERASE_APP 0xf5e80ab4 // Erase entire application !!

View file

@ -0,0 +1,490 @@
#ifndef FAVICON_H
#define FAVICON_H
const unsigned long favicon_len = 7705;
const unsigned char favicon_data[] __attribute__((aligned(16))) = {
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x03, 0x1e,
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x04,
0x00, 0x00, 0x00, 0xf6, 0x7b, 0x60, 0xed, 0x00, 0x00, 0x1d, 0xca, 0x49, 0x44, 0x41, 0x54, 0x78,
0xda, 0xed, 0x9d, 0x77, 0x7c, 0x95, 0xd5, 0xdd, 0xc0, 0xbf, 0xf7, 0x66, 0xef, 0x84, 0x24, 0x8c,
0x10, 0x32, 0x20, 0x0c, 0x09, 0x33, 0x40, 0x00, 0x95, 0xe1, 0xc2, 0x89, 0x82, 0x56, 0xaa, 0x6f,
0xa5, 0x56, 0x41, 0xab, 0x62, 0x07, 0xd5, 0x4a, 0x6d, 0xad, 0x55, 0xdf, 0xb6, 0x1f, 0x79, 0xd5,
0xea, 0x5b, 0xf4, 0xb5, 0x75, 0xb4, 0x56, 0x69, 0x1d, 0xe0, 0xa8, 0x13, 0x11, 0xab, 0x40, 0xd8,
0x7b, 0xaf, 0x00, 0x61, 0x85, 0x10, 0xc8, 0x24, 0xeb, 0x26, 0xb9, 0xf7, 0xbe, 0x7f, 0x30, 0xcc,
0xb8, 0xe3, 0x99, 0xf7, 0x9c, 0xe7, 0x72, 0xbf, 0xe7, 0x1f, 0xc8, 0x7d, 0x9e, 0xf3, 0xfc, 0xce,
0x73, 0x7e, 0xcf, 0x19, 0xbf, 0xf3, 0x3b, 0xbf, 0x63, 0x23, 0x44, 0x7b, 0x22, 0x29, 0xe4, 0x7b,
0x5c, 0x4c, 0x37, 0xa0, 0x99, 0x03, 0x6c, 0xe1, 0x1b, 0x56, 0x51, 0x2d, 0x5a, 0xac, 0x10, 0x81,
0xa1, 0x0b, 0x73, 0x28, 0xa6, 0x15, 0xf7, 0xf9, 0xe4, 0xa4, 0x8c, 0x7f, 0x31, 0x86, 0x30, 0xd1,
0xa2, 0x85, 0x30, 0x9f, 0x74, 0x5e, 0xa0, 0xbe, 0x4d, 0xe5, 0x7f, 0x97, 0xb6, 0x73, 0x3d, 0x36,
0xd1, 0xe2, 0x85, 0x30, 0x97, 0x54, 0x5e, 0xa0, 0xc1, 0x63, 0xf5, 0xbb, 0x71, 0xb3, 0x8e, 0x61,
0xa2, 0x05, 0x0c, 0x61, 0x26, 0x71, 0xfc, 0x9a, 0x1a, 0xaf, 0xd5, 0xef, 0xa6, 0x95, 0x97, 0x89,
0x17, 0x2d, 0x64, 0x08, 0xb3, 0x08, 0xe3, 0x76, 0x8e, 0xf8, 0xa8, 0x7e, 0x37, 0x6e, 0x8e, 0x70,
0x95, 0x68, 0x31, 0x43, 0x98, 0xc5, 0x48, 0xd6, 0xf8, 0xa9, 0x7e, 0x37, 0x4e, 0x5e, 0x24, 0x5a,
0xb4, 0xa0, 0x21, 0xcc, 0xa0, 0x3b, 0x6f, 0xd1, 0xe2, 0x57, 0x01, 0xdc, 0x6c, 0x63, 0xb0, 0x68,
0x51, 0x43, 0x18, 0x4f, 0x34, 0x8f, 0x50, 0xab, 0xa0, 0xfa, 0xdd, 0xd4, 0x73, 0x7f, 0x68, 0x2e,
0x10, 0x6c, 0xd8, 0xb8, 0x9e, 0x62, 0x45, 0xd5, 0xef, 0xc6, 0xcd, 0x42, 0xba, 0x88, 0x16, 0x38,
0x84, 0xb1, 0xf4, 0xe7, 0x4b, 0xc5, 0xd5, 0xef, 0x66, 0x37, 0x85, 0xa2, 0x05, 0x36, 0x16, 0xbb,
0x68, 0x01, 0x04, 0x93, 0xc2, 0xbd, 0x8c, 0x57, 0x71, 0x7d, 0x26, 0x05, 0xa1, 0x4e, 0x20, 0x78,
0x88, 0x60, 0x06, 0x27, 0x54, 0x7c, 0xff, 0x6e, 0x5c, 0xfc, 0x8b, 0x24, 0xd1, 0x62, 0x87, 0x30,
0x8a, 0x4b, 0xd9, 0xa4, 0xaa, 0xfa, 0xdd, 0xb8, 0xd9, 0xc5, 0x28, 0xd1, 0x62, 0x87, 0x30, 0x86,
0x5e, 0xbc, 0xdb, 0x6e, 0xd9, 0x47, 0x59, 0xaa, 0xe3, 0x5e, 0xd1, 0x82, 0x1b, 0xc9, 0x85, 0x3b,
0x06, 0x88, 0xe5, 0x87, 0x5c, 0xab, 0x61, 0x8d, 0x2f, 0x96, 0x31, 0x24, 0x88, 0x16, 0x3e, 0x84,
0x5e, 0xec, 0xdc, 0xc8, 0x01, 0xd5, 0x5f, 0xff, 0x99, 0xb4, 0x95, 0x41, 0xa2, 0xc5, 0x0f, 0xa1,
0x97, 0x7c, 0xbe, 0xd1, 0x58, 0xfd, 0x6e, 0x6a, 0xb8, 0x5b, 0xb4, 0xf8, 0xc6, 0x71, 0x61, 0x76,
0x01, 0x69, 0xdc, 0xcf, 0x25, 0x9a, 0xef, 0x4e, 0xa4, 0x90, 0x38, 0xd1, 0x45, 0x08, 0xa1, 0x9d,
0x48, 0xee, 0xe3, 0xa4, 0xe6, 0xef, 0xdf, 0x8d, 0x9b, 0xf5, 0xf4, 0x17, 0x5d, 0x88, 0x10, 0xda,
0x19, 0xcf, 0x36, 0x5d, 0xd5, 0xef, 0xa6, 0x82, 0xdb, 0x44, 0x17, 0x22, 0x84, 0x56, 0x7a, 0xf2,
0x21, 0x2e, 0x9d, 0x0a, 0xe0, 0x62, 0x1e, 0x31, 0xa2, 0x0b, 0x62, 0x0c, 0x17, 0xda, 0x18, 0x20,
0x86, 0x7b, 0xb8, 0x46, 0xb7, 0x31, 0xd7, 0x46, 0x01, 0x19, 0xa2, 0x8b, 0x12, 0x42, 0x3d, 0x76,
0xa6, 0x72, 0x4c, 0xe7, 0xd7, 0x7f, 0x26, 0x9d, 0xe4, 0x26, 0xd1, 0x85, 0x09, 0xa1, 0x9e, 0x7c,
0x56, 0x18, 0x52, 0xfd, 0x6e, 0x5a, 0x79, 0x96, 0x28, 0xd1, 0xc5, 0x09, 0xa1, 0x8e, 0x14, 0x5e,
0xd1, 0x60, 0xfa, 0xf5, 0x96, 0x96, 0xd2, 0x5b, 0x74, 0x81, 0x42, 0xa8, 0x21, 0x8c, 0x59, 0x3e,
0xbd, 0x7e, 0xd5, 0xa6, 0x32, 0xae, 0x11, 0x5d, 0xa4, 0x10, 0x6a, 0x18, 0xaf, 0xc2, 0xef, 0x47,
0x49, 0x6a, 0xe6, 0x0f, 0x44, 0x8a, 0x2e, 0x54, 0x08, 0xa5, 0xf4, 0xe2, 0x0b, 0x43, 0xab, 0xdf,
0x8d, 0x9b, 0xff, 0x90, 0x25, 0xba, 0x58, 0xfa, 0xb9, 0x30, 0xa6, 0x81, 0xd1, 0xdc, 0xcf, 0x95,
0x86, 0xe7, 0xda, 0x9f, 0x01, 0xa2, 0x0b, 0xa6, 0x9f, 0x0b, 0x43, 0x01, 0x6e, 0xe0, 0x1e, 0xc2,
0x0d, 0xcf, 0x35, 0x9d, 0x51, 0x44, 0x88, 0x2e, 0x5a, 0x08, 0xff, 0x0c, 0x66, 0x9d, 0xe1, 0xcd,
0xff, 0x99, 0xb4, 0x88, 0xee, 0xa2, 0x0b, 0x17, 0xc2, 0x1f, 0xa9, 0xfc, 0x43, 0xb7, 0xe9, 0xd7,
0x5b, 0x3a, 0xcc, 0xe5, 0xa2, 0x8b, 0xa7, 0x97, 0x60, 0xef, 0x02, 0xc2, 0xb9, 0x93, 0x5b, 0x4c,
0xf3, 0xe3, 0xed, 0xce, 0xf0, 0x50, 0xdc, 0x00, 0xb9, 0xb9, 0x82, 0x83, 0x26, 0x7d, 0xfd, 0x67,
0xd2, 0x87, 0xa4, 0x89, 0x2e, 0x62, 0x08, 0xef, 0xe4, 0xb0, 0xd8, 0xd4, 0xea, 0x77, 0x73, 0x80,
0xb1, 0xa2, 0x0b, 0xa9, 0x8f, 0x60, 0xee, 0x02, 0xe2, 0x79, 0x90, 0x89, 0x26, 0x3f, 0xa3, 0x27,
0x85, 0xd6, 0xde, 0x28, 0x12, 0xbc, 0x0a, 0x60, 0x67, 0x2a, 0xd3, 0x4d, 0x9f, 0xa6, 0x45, 0x52,
0x48, 0xb2, 0xe8, 0xa2, 0x86, 0xf0, 0xc4, 0x28, 0x36, 0x9a, 0xdc, 0xfc, 0x9f, 0x49, 0x7b, 0x19,
0x21, 0xba, 0xa8, 0x7a, 0x08, 0xd6, 0x16, 0xa0, 0x3b, 0x3f, 0x67, 0x68, 0x40, 0x9e, 0xd4, 0x93,
0x51, 0x56, 0xee, 0x04, 0x82, 0x53, 0x01, 0xa2, 0xb8, 0x93, 0xc9, 0x01, 0x2a, 0x5b, 0x2c, 0xa3,
0x43, 0x1b, 0x45, 0xe4, 0xc2, 0xc6, 0x64, 0xf6, 0x07, 0xa4, 0xf9, 0x3f, 0x93, 0x42, 0x71, 0x43,
0x24, 0x63, 0xa0, 0x8e, 0x4d, 0x1f, 0x5a, 0xd2, 0x69, 0xee, 0xb6, 0x6e, 0x27, 0x10, 0x7c, 0x5d,
0x40, 0x32, 0x0f, 0xe8, 0xd8, 0xf4, 0xa1, 0x85, 0x78, 0xc6, 0x12, 0x2b, 0xba, 0xd8, 0x5a, 0x09,
0x36, 0x05, 0xb0, 0x33, 0x99, 0x5b, 0x03, 0xbe, 0x46, 0x57, 0x40, 0x2f, 0xd1, 0x05, 0xd7, 0x4a,
0xb0, 0x29, 0x40, 0x7f, 0x66, 0xd0, 0x35, 0xe0, 0x4f, 0xed, 0x6b, 0xdd, 0x28, 0xa2, 0xc1, 0xa5,
0x00, 0xb1, 0xfc, 0x80, 0xd1, 0x02, 0x9e, 0x9b, 0xc0, 0x04, 0xab, 0x6e, 0x14, 0x09, 0x2e, 0x05,
0x18, 0xcb, 0x34, 0x41, 0xa1, 0x1c, 0x87, 0xd3, 0x43, 0x74, 0xe1, 0xb5, 0x11, 0x4c, 0x0a, 0x90,
0xc2, 0x74, 0x61, 0xae, 0xda, 0x03, 0x18, 0x22, 0xba, 0xf8, 0xda, 0x08, 0x26, 0x05, 0xb8, 0x8c,
0x49, 0xc2, 0x56, 0xe7, 0x93, 0x18, 0x6f, 0xcd, 0x8d, 0x22, 0xc1, 0xa3, 0x00, 0xe9, 0xdc, 0x2e,
0xb4, 0x19, 0xbe, 0xc4, 0x9a, 0xee, 0x61, 0xc1, 0xa3, 0x00, 0x97, 0x30, 0x4e, 0xe8, 0xf3, 0xfb,
0x31, 0x5c, 0xf4, 0x2b, 0xd0, 0x42, 0xb0, 0x28, 0x40, 0x0a, 0x53, 0x04, 0x4c, 0xff, 0xda, 0x92,
0xcc, 0x68, 0x2b, 0x6e, 0x14, 0x09, 0x16, 0x05, 0x18, 0xce, 0xe5, 0xc2, 0xcd, 0xb1, 0x17, 0x5b,
0x31, 0x84, 0x64, 0x70, 0x28, 0x40, 0x0c, 0xd7, 0x4a, 0x30, 0x0d, 0xcb, 0xb3, 0x62, 0xe0, 0x98,
0xe0, 0x50, 0x80, 0xde, 0x5c, 0x66, 0xc2, 0xc6, 0x0f, 0xb5, 0xa4, 0x5b, 0x71, 0x55, 0x30, 0x18,
0x14, 0xc0, 0xce, 0xc5, 0xf4, 0x13, 0x2d, 0x04, 0x10, 0x41, 0xbe, 0xf5, 0x4e, 0x14, 0x09, 0x06,
0x05, 0x48, 0x60, 0x82, 0x24, 0x2e, 0x19, 0xc3, 0xac, 0xe7, 0x1f, 0x18, 0x0c, 0x0a, 0xd0, 0x57,
0x9a, 0x09, 0x58, 0xb6, 0xf5, 0x76, 0x09, 0x58, 0x5f, 0x01, 0x6c, 0x14, 0x90, 0x2d, 0x5a, 0x88,
0xb3, 0xc4, 0x93, 0x23, 0x5a, 0x04, 0xb5, 0x58, 0x5f, 0x01, 0x64, 0x72, 0xc7, 0x88, 0xa3, 0x8f,
0x68, 0x11, 0xd4, 0x62, 0x7d, 0x05, 0xe8, 0x46, 0xbe, 0x70, 0x0b, 0xc0, 0x39, 0x22, 0xc8, 0xb2,
0xda, 0x1b, 0xb5, 0x98, 0xb8, 0x1e, 0xc8, 0x23, 0x53, 0xb4, 0x08, 0x6d, 0xc8, 0x90, 0xa6, 0x35,
0x52, 0x48, 0x30, 0x28, 0x80, 0x4c, 0x03, 0xaf, 0x74, 0xab, 0x85, 0x91, 0xb6, 0xba, 0x02, 0xc4,
0xd1, 0x4f, 0xaa, 0x28, 0x1d, 0xa9, 0xa1, 0x16, 0x20, 0xb0, 0xc4, 0x92, 0x27, 0x5a, 0x84, 0x76,
0x24, 0x5a, 0xcd, 0x2b, 0xa0, 0xb3, 0x01, 0xd5, 0x46, 0x18, 0xe1, 0xaa, 0x15, 0xc3, 0x89, 0x53,
0xd5, 0xf5, 0x2e, 0x5c, 0x86, 0xc8, 0x1f, 0x2f, 0xc1, 0x1a, 0x40, 0x5b, 0x92, 0xac, 0xac, 0x00,
0xf1, 0xe4, 0x92, 0x43, 0x77, 0x52, 0xe9, 0xa2, 0x7a, 0x61, 0xb3, 0x9e, 0x1a, 0xdc, 0x2a, 0xae,
0x6f, 0xa6, 0x82, 0x66, 0x4e, 0x53, 0x4b, 0x35, 0x15, 0xd4, 0xd1, 0x4c, 0x8b, 0xaa, 0xfb, 0xcf,
0x91, 0x4e, 0x62, 0xe0, 0x5f, 0x9a, 0x0f, 0xc2, 0xac, 0xd6, 0xa6, 0x9e, 0x53, 0x80, 0x58, 0xc6,
0x72, 0x2b, 0x63, 0xc8, 0x24, 0x01, 0xbb, 0x86, 0x42, 0xb8, 0x55, 0x56, 0x9f, 0x1b, 0x37, 0xad,
0xd4, 0x53, 0x4b, 0x2d, 0x55, 0x94, 0xb1, 0x9f, 0x7d, 0x94, 0x50, 0x4a, 0x39, 0x0d, 0xaa, 0xda,
0x92, 0x2e, 0xd2, 0xf5, 0xb9, 0xb2, 0x4c, 0x49, 0x15, 0x72, 0x46, 0x01, 0xe2, 0x99, 0xc9, 0x83,
0xe4, 0x06, 0x58, 0x7b, 0x23, 0x89, 0x25, 0xfd, 0xec, 0xbf, 0x5b, 0x70, 0x50, 0xc9, 0x21, 0x0e,
0xb0, 0x89, 0x4d, 0xec, 0xa7, 0x9c, 0x16, 0x45, 0x79, 0x74, 0x91, 0xcc, 0x1d, 0x3b, 0x8c, 0x14,
0xd1, 0x22, 0xa8, 0x23, 0x1c, 0x88, 0xe0, 0x87, 0xfc, 0x46, 0xf0, 0x64, 0x2a, 0x82, 0x08, 0xe2,
0xc9, 0xe2, 0x52, 0xa6, 0x71, 0x8a, 0x9d, 0xac, 0xa1, 0x88, 0x1d, 0x9c, 0xf0, 0xdb, 0x1a, 0x44,
0x4b, 0x35, 0x07, 0x00, 0x0c, 0x1a, 0xdb, 0x04, 0x8c, 0x70, 0x60, 0x2c, 0x0f, 0x49, 0x33, 0x97,
0xb6, 0x11, 0x43, 0x2f, 0x7a, 0x71, 0x39, 0x27, 0xd9, 0xc2, 0xd7, 0x2c, 0x61, 0x2f, 0x8d, 0x3e,
0xef, 0xd0, 0x32, 0x72, 0x30, 0x0f, 0x27, 0x35, 0xa2, 0x45, 0x50, 0x47, 0x38, 0xc9, 0xdc, 0x27,
0x61, 0xe0, 0xf3, 0x08, 0x32, 0xc8, 0x60, 0x22, 0x77, 0xf2, 0x15, 0x9f, 0xb0, 0x9e, 0x3a, 0xd1,
0x02, 0x29, 0x46, 0x2e, 0x85, 0xf4, 0x4b, 0x38, 0xe3, 0xb8, 0x4c, 0xb4, 0x10, 0x5e, 0x89, 0x61,
0x30, 0x03, 0x99, 0xca, 0xe7, 0xcc, 0x67, 0x33, 0x4d, 0x1e, 0xaf, 0x91, 0x6b, 0xd0, 0xd5, 0xa8,
0x70, 0xec, 0x22, 0x0d, 0x76, 0x6e, 0x10, 0xec, 0x4d, 0xeb, 0x8f, 0x30, 0x72, 0xb9, 0x97, 0xd7,
0x98, 0x43, 0x9e, 0xc7, 0xca, 0x96, 0xeb, 0x8b, 0xab, 0xf6, 0xa2, 0xa6, 0xd2, 0x12, 0xce, 0x78,
0x0b, 0xcc, 0x5c, 0x23, 0xc8, 0xa7, 0x37, 0x13, 0x79, 0x91, 0x2f, 0x68, 0x68, 0xf7, 0x4b, 0x1d,
0xcd, 0x52, 0x59, 0xdf, 0x2d, 0xa7, 0x00, 0x76, 0x72, 0x45, 0x8b, 0xa0, 0x90, 0x18, 0x26, 0x32,
0x8f, 0xdf, 0x75, 0x70, 0xfe, 0xa8, 0xf6, 0x33, 0x44, 0x0c, 0x34, 0xe5, 0xd4, 0x8b, 0x16, 0x41,
0x1d, 0x76, 0xc9, 0x9a, 0x50, 0xdf, 0xf4, 0xe0, 0x67, 0xcc, 0x63, 0x4c, 0x9b, 0xae, 0xe0, 0x84,
0x64, 0xc3, 0xc3, 0x52, 0xc9, 0xe4, 0xf1, 0x8b, 0x9d, 0xfd, 0xa2, 0x45, 0x50, 0x45, 0x14, 0xd7,
0xf3, 0xbf, 0x4c, 0x3e, 0xbf, 0x09, 0xf4, 0x14, 0xa7, 0x44, 0x8b, 0xd4, 0x86, 0x56, 0x0e, 0x58,
0x6f, 0x10, 0xb8, 0xcc, 0x62, 0xa6, 0x0b, 0x3b, 0x85, 0xcc, 0xe5, 0x96, 0xb3, 0xab, 0x15, 0xf5,
0x94, 0x88, 0x16, 0xa8, 0x0d, 0xf5, 0xec, 0x13, 0x2d, 0x82, 0x5a, 0xec, 0x2c, 0xe4, 0xa8, 0x68,
0x21, 0x54, 0x33, 0x80, 0xb9, 0xdc, 0x42, 0x18, 0x50, 0xc7, 0x2e, 0x5d, 0x0a, 0xec, 0xa6, 0x86,
0x63, 0x1d, 0x06, 0x96, 0xda, 0xa9, 0x64, 0xaf, 0xe8, 0x57, 0xa3, 0x96, 0x30, 0x8e, 0x93, 0x4d,
0xa1, 0x68, 0x31, 0x54, 0x93, 0x4c, 0x3e, 0x47, 0xd9, 0x87, 0x93, 0x34, 0x26, 0x69, 0x5e, 0x0f,
0x38, 0xcc, 0x1b, 0x3c, 0xc7, 0x9b, 0x2c, 0x25, 0x82, 0x1c, 0x03, 0xf6, 0x16, 0x15, 0xf1, 0x4f,
0xc9, 0x06, 0xa5, 0x8a, 0x18, 0xc1, 0xee, 0x80, 0xc6, 0xd5, 0x33, 0x2a, 0x6d, 0x65, 0x22, 0x70,
0x91, 0xc6, 0x98, 0xc0, 0x4e, 0x96, 0x31, 0xe9, 0xfc, 0x4e, 0x9e, 0x4c, 0x5e, 0xa2, 0x51, 0xb7,
0x44, 0x8f, 0x59, 0x60, 0x4a, 0xed, 0x81, 0x30, 0x7e, 0x4e, 0x83, 0xf0, 0xea, 0x54, 0x9f, 0x5c,
0x2c, 0x26, 0x8f, 0x78, 0x5e, 0xd7, 0x70, 0x24, 0x8c, 0x8b, 0x6f, 0x3b, 0xc4, 0xf8, 0xcd, 0xe5,
0x73, 0x9d, 0x47, 0xcb, 0x94, 0x33, 0x49, 0x74, 0x55, 0x6a, 0xa9, 0x7c, 0x70, 0x73, 0x80, 0x7e,
0x0c, 0x14, 0x2d, 0x8a, 0x6a, 0x6c, 0x64, 0x11, 0xce, 0x52, 0xe2, 0xb9, 0x52, 0xb5, 0x03, 0xcb,
0x1e, 0x1e, 0xa5, 0xa8, 0xdd, 0x5f, 0xaa, 0x69, 0x62, 0x22, 0xf1, 0x3a, 0xe4, 0xd9, 0xc0, 0x8b,
0x56, 0xb3, 0x02, 0x7c, 0xc7, 0x28, 0xb6, 0x0b, 0xff, 0xa2, 0xb5, 0xa4, 0x53, 0xdc, 0xc5, 0x30,
0x36, 0xab, 0xbc, 0xab, 0x8a, 0x07, 0x3c, 0xf4, 0xf8, 0xa9, 0x7c, 0xa4, 0xab, 0x3d, 0x7a, 0x4c,
0x82, 0x1d, 0xca, 0xaa, 0x39, 0xd7, 0x67, 0x6d, 0xe4, 0x19, 0x2a, 0x44, 0x0b, 0xa3, 0x81, 0x54,
0x1e, 0x24, 0x85, 0x35, 0xa8, 0x31, 0x67, 0xb9, 0x59, 0xc4, 0x02, 0x5a, 0x3b, 0xfd, 0xbd, 0x82,
0xc5, 0x3a, 0x86, 0x70, 0x87, 0x58, 0xe2, 0x21, 0x4f, 0xe9, 0x39, 0xa7, 0xb3, 0x4e, 0x3e, 0x60,
0x08, 0x3f, 0x91, 0xce, 0xbd, 0xc2, 0x3f, 0x43, 0x99, 0xce, 0x26, 0xaa, 0xe8, 0xa2, 0xf8, 0x8e,
0x12, 0x5e, 0xe7, 0xa4, 0xc7, 0x5f, 0xd6, 0x70, 0x4c, 0xb3, 0x97, 0xf1, 0x37, 0x6c, 0xf7, 0xfa,
0x9b, 0x8d, 0x18, 0xe2, 0x89, 0x21, 0x92, 0xe8, 0x36, 0xad, 0x84, 0x83, 0x66, 0x1c, 0x34, 0x51,
0x47, 0x93, 0x2a, 0x05, 0x36, 0x94, 0xef, 0xc4, 0x39, 0xcd, 0x3c, 0x2e, 0xe2, 0x5a, 0x51, 0x82,
0x68, 0x26, 0x8c, 0xc9, 0x54, 0x52, 0xac, 0x78, 0x2a, 0xeb, 0x62, 0x11, 0x2b, 0xbd, 0xfc, 0x76,
0x88, 0x62, 0x8d, 0x0a, 0x70, 0x82, 0x05, 0x9d, 0x8c, 0xc0, 0x36, 0xe2, 0x48, 0x21, 0x8b, 0x7c,
0xb2, 0xe9, 0x45, 0x57, 0x52, 0x49, 0x24, 0x91, 0xe8, 0xf3, 0x95, 0x7d, 0x9a, 0x7a, 0x6a, 0xa9,
0xa2, 0x9c, 0x52, 0x8e, 0x71, 0x90, 0x62, 0xaa, 0xa9, 0x09, 0xf4, 0x62, 0x52, 0xdb, 0x5e, 0xab,
0x84, 0x67, 0xe9, 0x2b, 0x99, 0x9f, 0xbd, 0x12, 0xd2, 0xb8, 0x86, 0x72, 0x5a, 0x14, 0xb6, 0x5e,
0xc7, 0x58, 0xe0, 0xd5, 0xf0, 0x53, 0xc9, 0x01, 0x4d, 0x12, 0xb8, 0xf9, 0x82, 0x55, 0x6d, 0xfe,
0x6f, 0x23, 0x89, 0x3c, 0x46, 0x51, 0xc8, 0x50, 0x32, 0x49, 0x20, 0xca, 0xe3, 0x42, 0x76, 0x4a,
0x9b, 0xfb, 0x5b, 0x68, 0xa0, 0x9a, 0x12, 0xb6, 0xb3, 0x8d, 0x1d, 0xec, 0xa3, 0x9a, 0x66, 0x11,
0xaf, 0x32, 0x82, 0x59, 0x54, 0x0b, 0x1f, 0xd8, 0xa9, 0x4f, 0x2d, 0x94, 0x50, 0xaf, 0xf0, 0xda,
0x77, 0x7c, 0x3a, 0x92, 0xcf, 0xd6, 0x64, 0x0d, 0xd8, 0xdf, 0xe6, 0x74, 0xb2, 0x48, 0xfa, 0x32,
0x93, 0x85, 0x94, 0xd0, 0xa4, 0xa9, 0x2c, 0x4d, 0x1c, 0x63, 0x19, 0xff, 0xc3, 0x14, 0xb2, 0x03,
0xb1, 0xc7, 0xa0, 0xfd, 0xb8, 0xb5, 0x85, 0xb7, 0x19, 0xc2, 0xdd, 0x96, 0x1b, 0xcd, 0x86, 0x2b,
0xde, 0x20, 0x7a, 0x9a, 0xcf, 0xa8, 0xf5, 0xf1, 0xfb, 0x11, 0x1c, 0xaa, 0xc3, 0xbc, 0x38, 0x78,
0x8b, 0x35, 0x00, 0x44, 0x33, 0x98, 0x9b, 0xb8, 0x96, 0x81, 0x3a, 0x42, 0xc5, 0x44, 0x91, 0x41,
0x06, 0xe3, 0xa8, 0x61, 0x0f, 0x2b, 0x58, 0xc1, 0x0e, 0x0e, 0x05, 0x76, 0x8c, 0x90, 0xcf, 0x7f,
0x84, 0x7f, 0xd1, 0xe6, 0xa5, 0xf5, 0x7e, 0x76, 0xf0, 0x8f, 0xe7, 0xa4, 0xea, 0x3c, 0xbf, 0xa0,
0x37, 0x10, 0x46, 0x3e, 0x7f, 0x60, 0x2f, 0xad, 0x06, 0x4a, 0xeb, 0xe2, 0x34, 0x1b, 0xf9, 0x0b,
0xb7, 0x33, 0x98, 0xc4, 0x40, 0x59, 0x19, 0xed, 0xdc, 0x18, 0xd0, 0x13, 0x77, 0x02, 0x99, 0x5c,
0xbc, 0xe4, 0xa7, 0x59, 0x1d, 0x46, 0x99, 0xca, 0x3c, 0xf7, 0x73, 0x1d, 0x36, 0xd2, 0x99, 0xc9,
0x5a, 0x9a, 0x4d, 0x92, 0xfa, 0x34, 0xdb, 0xf9, 0x3b, 0x33, 0x28, 0x20, 0x25, 0x10, 0x6a, 0x10,
0xcb, 0x1c, 0x6a, 0x84, 0x57, 0x96, 0x19, 0xa9, 0x9a, 0xdb, 0xfc, 0x94, 0x7d, 0x10, 0x25, 0xaa,
0x72, 0xac, 0x61, 0x0e, 0xf1, 0x14, 0xf0, 0x06, 0x55, 0xa6, 0x2b, 0x6f, 0x1d, 0x7b, 0x98, 0xcf,
0x2c, 0xc6, 0x90, 0x6e, 0x76, 0x50, 0xec, 0x1e, 0xbc, 0x69, 0x68, 0x53, 0x26, 0x4b, 0xda, 0xe9,
0x37, 0x94, 0x63, 0x5f, 0xb6, 0xa9, 0xc8, 0xaf, 0x99, 0x57, 0xe9, 0xc3, 0x6d, 0xac, 0x0d, 0xe0,
0xdb, 0x6a, 0xe0, 0x00, 0xef, 0xf3, 0x30, 0xe3, 0xe9, 0x6e, 0x84, 0xd5, 0xc6, 0xf3, 0x70, 0xef,
0x38, 0x2f, 0x90, 0x67, 0xf5, 0x63, 0x91, 0x3d, 0xb0, 0x8d, 0xe3, 0x7e, 0xae, 0x70, 0xab, 0xf0,
0x2e, 0x70, 0x53, 0xc4, 0x87, 0x4c, 0x67, 0x26, 0x3d, 0x03, 0x58, 0x86, 0x18, 0x72, 0xc9, 0xe5,
0x06, 0xca, 0xd8, 0x49, 0x11, 0x1b, 0xd9, 0xc6, 0x49, 0x1c, 0xda, 0xb3, 0xf3, 0x36, 0xde, 0xdf,
0xcc, 0xf3, 0xf4, 0x92, 0x2a, 0xf8, 0x8a, 0x7e, 0x9c, 0x6c, 0xf5, 0x39, 0x03, 0x38, 0xf3, 0x3e,
0x94, 0x8f, 0xdf, 0xf7, 0xb2, 0x84, 0x3b, 0xb8, 0x51, 0x88, 0x57, 0x72, 0x24, 0x59, 0x64, 0x71,
0x25, 0x27, 0xd9, 0xcd, 0x4a, 0x56, 0xb1, 0x9b, 0x63, 0x38, 0xd0, 0x30, 0x57, 0xf0, 0xa6, 0x00,
0x2e, 0xbe, 0x60, 0x30, 0xb3, 0x75, 0xad, 0x8e, 0xc9, 0x46, 0x0d, 0xbb, 0xfc, 0x5e, 0x13, 0xad,
0x78, 0xbb, 0x79, 0x15, 0xbb, 0xb9, 0x8e, 0x42, 0xa1, 0xc6, 0xf3, 0x70, 0x7a, 0xd0, 0x83, 0x71,
0x54, 0xb2, 0x8f, 0xd5, 0xac, 0x60, 0x27, 0x47, 0x68, 0x54, 0xa7, 0x06, 0xde, 0x07, 0x13, 0xcd,
0x1c, 0x20, 0x97, 0x01, 0xd6, 0x74, 0x71, 0xf0, 0x48, 0x29, 0x2f, 0x73, 0xc2, 0xcf, 0x35, 0x99,
0xdc, 0xa1, 0xe8, 0x8b, 0x76, 0x51, 0x43, 0x4f, 0x06, 0x48, 0x61, 0x31, 0xb1, 0x13, 0x47, 0x16,
0x85, 0x5c, 0xcd, 0x78, 0xf2, 0x49, 0x00, 0x1a, 0x95, 0xdb, 0x11, 0x7d, 0x8d, 0x26, 0x6b, 0x38,
0x6e, 0xdd, 0xc3, 0x90, 0x3c, 0xb0, 0x8b, 0x57, 0xfd, 0x7a, 0xff, 0x0d, 0x62, 0x9a, 0x42, 0x07,
0xb3, 0x38, 0x12, 0xa5, 0xda, 0x96, 0x66, 0x27, 0x86, 0x4c, 0x46, 0x72, 0x25, 0x57, 0x31, 0x98,
0xae, 0xb8, 0x71, 0x28, 0x19, 0x1b, 0xf8, 0x9e, 0x4e, 0x94, 0xd2, 0x18, 0x44, 0x47, 0x23, 0x2f,
0xe7, 0x43, 0xbf, 0x4e, 0xdb, 0x85, 0xdc, 0xa8, 0xc8, 0x00, 0x6b, 0x93, 0xaa, 0xf2, 0xdb, 0xca,
0x15, 0x43, 0x37, 0x86, 0x73, 0x19, 0x93, 0x18, 0x41, 0x37, 0x6c, 0x34, 0xd1, 0xec, 0xab, 0x53,
0xf0, 0xad, 0x00, 0x2e, 0x4a, 0x48, 0x61, 0xb8, 0x05, 0x17, 0x89, 0x3b, 0xe3, 0xe6, 0x33, 0x96,
0xf8, 0x1d, 0xe3, 0x4f, 0x62, 0x92, 0x14, 0xcd, 0xba, 0x3e, 0x6c, 0x44, 0x91, 0xce, 0x60, 0x26,
0x72, 0x15, 0xa3, 0xc9, 0x20, 0x8c, 0x26, 0x1c, 0x9e, 0xcb, 0xee, 0xaf, 0xb0, 0x35, 0xfc, 0x95,
0x01, 0x5c, 0x2f, 0xa9, 0xbe, 0xab, 0xc1, 0x4d, 0x99, 0x5f, 0x87, 0x0d, 0x1b, 0xbd, 0xac, 0x16,
0xe4, 0xc9, 0x27, 0x71, 0xf4, 0x25, 0x8f, 0x6b, 0x29, 0x65, 0x0f, 0x45, 0xac, 0x66, 0x07, 0x15,
0x1d, 0x43, 0x6e, 0xf8, 0xd7, 0xf6, 0x62, 0x5e, 0x20, 0x8f, 0x01, 0xa2, 0xcb, 0xa2, 0x9b, 0x66,
0x05, 0x7b, 0x88, 0x62, 0xe9, 0x19, 0x04, 0xaa, 0xde, 0x1e, 0x1b, 0x31, 0xf4, 0xa1, 0x37, 0x57,
0x50, 0xc6, 0x0e, 0x8a, 0x28, 0x62, 0x6b, 0xdb, 0x20, 0x16, 0x4a, 0x4c, 0x8a, 0xc7, 0x70, 0x31,
0x5a, 0xba, 0x60, 0x4c, 0x6a, 0x39, 0xcd, 0x3b, 0x7e, 0xb7, 0x6d, 0xf4, 0xe0, 0x4e, 0xb2, 0x44,
0x0b, 0x6a, 0x0a, 0x36, 0xc2, 0x49, 0xa6, 0x2f, 0x97, 0x72, 0x15, 0xc3, 0x08, 0xe3, 0xe4, 0x39,
0xf7, 0x55, 0x25, 0x0a, 0xe0, 0xa4, 0x98, 0x6e, 0x0c, 0x15, 0x70, 0x28, 0xa3, 0x9b, 0x56, 0x5a,
0x71, 0x1b, 0xf2, 0xe4, 0x2a, 0xfe, 0xc9, 0x61, 0x3f, 0xd7, 0x0c, 0x60, 0xa6, 0x15, 0x0f, 0x7e,
0x52, 0x41, 0x38, 0xc9, 0xe4, 0x73, 0x39, 0x83, 0xa8, 0xe1, 0x30, 0x2e, 0x25, 0x5d, 0x00, 0x40,
0x25, 0xf3, 0xe8, 0xc7, 0x15, 0x01, 0x14, 0xb4, 0x8e, 0x3d, 0x6c, 0xa7, 0x84, 0x0a, 0x9c, 0x44,
0x90, 0x4e, 0x3a, 0x59, 0x64, 0xd3, 0x8d, 0x44, 0xcd, 0x43, 0xb4, 0x66, 0x05, 0xce, 0x56, 0xb9,
0x2a, 0x3c, 0x0b, 0xad, 0x8b, 0x8d, 0x54, 0xa6, 0x32, 0x8c, 0x3f, 0x30, 0x9f, 0x66, 0xa5, 0xaf,
0x73, 0x17, 0xcf, 0x90, 0x1b, 0xa0, 0x58, 0x42, 0x2e, 0x36, 0xf2, 0x57, 0xbe, 0xa1, 0x9c, 0xfa,
0xb3, 0x23, 0x57, 0x3b, 0xd1, 0x24, 0x90, 0x48, 0x6f, 0x0a, 0x19, 0xc1, 0x60, 0x32, 0x4d, 0x39,
0xa1, 0x2f, 0x8c, 0x21, 0xd6, 0x3b, 0xf3, 0x47, 0x23, 0x36, 0x7a, 0xf3, 0x14, 0xb5, 0xbc, 0xaf,
0xfc, 0x96, 0x48, 0x1e, 0xe6, 0x74, 0x40, 0xd6, 0xbb, 0xd6, 0x31, 0xce, 0x6b, 0xa3, 0x6f, 0xa7,
0x0b, 0xc3, 0xb8, 0x9f, 0x8f, 0x38, 0xae, 0x72, 0x1f, 0xcf, 0x41, 0x46, 0xf9, 0x29, 0x61, 0x17,
0x3e, 0x15, 0xbe, 0x5e, 0x19, 0xd8, 0x54, 0x44, 0x6f, 0xe5, 0xbd, 0xab, 0x93, 0x3d, 0xf4, 0x62,
0x88, 0xe9, 0xa3, 0xe4, 0x7a, 0x9e, 0xe3, 0x23, 0xaf, 0xf1, 0x01, 0xdd, 0x34, 0x52, 0xc6, 0x06,
0xbe, 0x64, 0x39, 0xe5, 0x24, 0xd2, 0x45, 0xf1, 0xf8, 0xa0, 0x9a, 0x05, 0x94, 0xfa, 0xbc, 0x62,
0x10, 0xf7, 0x92, 0x6a, 0x72, 0xe9, 0xe4, 0x22, 0x8d, 0xa3, 0x6a, 0x86, 0x57, 0x8d, 0x14, 0x33,
0xca, 0xf4, 0xa5, 0xcf, 0x32, 0xfe, 0xec, 0x77, 0xb0, 0x06, 0x4d, 0x1c, 0x62, 0x29, 0x4b, 0x38,
0x44, 0x32, 0x69, 0x8a, 0xc6, 0x05, 0xb5, 0xbc, 0xef, 0x73, 0x23, 0xbc, 0x8d, 0xeb, 0xb9, 0x35,
0x28, 0x4c, 0x5e, 0xca, 0x89, 0xa0, 0x45, 0xdd, 0xf8, 0xba, 0x9c, 0x4a, 0xc6, 0x99, 0x6c, 0x1a,
0xae, 0xe6, 0x3d, 0x8e, 0x29, 0xba, 0xd2, 0x45, 0x05, 0x6b, 0x59, 0x4c, 0x29, 0xdd, 0x48, 0xf5,
0xdb, 0x12, 0xb4, 0xf2, 0x39, 0xc5, 0x3e, 0x7e, 0x4f, 0x60, 0x16, 0x05, 0x41, 0x67, 0x05, 0xf0,
0x47, 0x9c, 0xda, 0x09, 0xd6, 0x41, 0x62, 0x19, 0x6d, 0xea, 0x77, 0x62, 0x63, 0x39, 0x3b, 0x14,
0x5f, 0xed, 0xa6, 0x86, 0x75, 0x7c, 0xc3, 0x69, 0x7a, 0x91, 0xec, 0xa7, 0xfa, 0x16, 0xf9, 0xcc,
0x77, 0x38, 0xb3, 0xa4, 0x89, 0x97, 0x1a, 0x38, 0xe2, 0xd5, 0x2a, 0x40, 0x2b, 0xbb, 0xe9, 0x43,
0xbe, 0x89, 0x22, 0x45, 0x52, 0xce, 0x52, 0x55, 0x91, 0x76, 0xdc, 0x9c, 0xa2, 0x88, 0xf5, 0x24,
0x90, 0xed, 0x63, 0x76, 0x10, 0xc6, 0x72, 0xd6, 0xfa, 0xf8, 0xf5, 0x76, 0xa6, 0x04, 0xc1, 0x2a,
0x80, 0x5a, 0x6c, 0xea, 0x4d, 0x2c, 0x75, 0x14, 0x33, 0x96, 0x6e, 0xe6, 0x89, 0x44, 0x22, 0xeb,
0x38, 0xa2, 0xf2, 0x2e, 0x27, 0x87, 0xf8, 0x96, 0x4a, 0x72, 0xe9, 0xe2, 0xb5, 0x1d, 0xd8, 0xc5,
0x37, 0x5e, 0x17, 0x83, 0xb2, 0x78, 0xc4, 0x82, 0x7b, 0xa2, 0x0c, 0x40, 0x8b, 0x8d, 0xad, 0x8c,
0x1a, 0x2e, 0x33, 0x31, 0x4c, 0x7b, 0x17, 0xec, 0x14, 0x69, 0xd8, 0xa7, 0xdb, 0xc0, 0x3a, 0x36,
0xd1, 0x8d, 0x6c, 0x8f, 0x5f, 0xb2, 0x8d, 0x4a, 0x3e, 0xf6, 0xba, 0x42, 0x3e, 0x95, 0x1f, 0x4a,
0x16, 0x78, 0x3e, 0x30, 0x9c, 0xd0, 0x66, 0x64, 0xdd, 0x4f, 0x3c, 0x85, 0xa6, 0x99, 0x86, 0x6d,
0xe4, 0x50, 0xc6, 0x16, 0x0d, 0xc1, 0x9f, 0x5c, 0x1c, 0x66, 0x25, 0x91, 0xf4, 0xf7, 0x62, 0xd0,
0xf9, 0xcc, 0xcb, 0x82, 0x50, 0x06, 0x73, 0x18, 0x62, 0x52, 0x69, 0x64, 0xc6, 0xc5, 0xbf, 0xb5,
0x55, 0x62, 0x2b, 0x7b, 0x18, 0x44, 0x5f, 0xd3, 0x04, 0x8b, 0xa1, 0x3f, 0x7b, 0x39, 0xa0, 0xc5,
0xc9, 0x91, 0x6a, 0x56, 0xd1, 0x4c, 0xbe, 0x07, 0x6f, 0xc6, 0x30, 0x36, 0x78, 0xdc, 0xc2, 0x6d,
0xe7, 0xfb, 0xcc, 0xb8, 0x60, 0x6c, 0x80, 0x6d, 0x39, 0xca, 0x1f, 0xb5, 0x7e, 0xc5, 0xb5, 0x1c,
0x62, 0xcc, 0xf9, 0xf3, 0x3e, 0x8c, 0x27, 0x95, 0x3c, 0x76, 0x68, 0x0c, 0x60, 0xd7, 0xc4, 0x46,
0x2a, 0x29, 0xe8, 0xe4, 0xde, 0x19, 0x45, 0x05, 0x5f, 0x7b, 0xf0, 0x09, 0xc8, 0xe7, 0x77, 0xaa,
0xfb, 0x7f, 0x37, 0x4e, 0x1c, 0xb4, 0x9c, 0x4f, 0x4e, 0x6c, 0x96, 0xf3, 0x9e, 0x74, 0xf0, 0x7f,
0xcc, 0xd7, 0x3e, 0xef, 0xb5, 0x31, 0x83, 0x67, 0x4d, 0x5c, 0x3b, 0x73, 0x53, 0xc4, 0xa3, 0xac,
0xd2, 0x18, 0x05, 0x30, 0x8a, 0xe9, 0x3c, 0xd1, 0xc9, 0x68, 0xb5, 0x9f, 0x3b, 0x58, 0xdd, 0xe1,
0x6f, 0xa9, 0xfc, 0x37, 0x33, 0x15, 0x4d, 0x6c, 0x5b, 0x71, 0x50, 0xcf, 0x09, 0x4e, 0x70, 0x8a,
0x0a, 0xaa, 0x38, 0xd5, 0x66, 0x79, 0x29, 0x8e, 0x74, 0xd2, 0xe9, 0x4a, 0x26, 0xd9, 0x24, 0x58,
0xc2, 0x9c, 0xd4, 0xca, 0xbf, 0x98, 0x43, 0x99, 0x9e, 0x2c, 0x92, 0x79, 0x89, 0x16, 0x13, 0x2d,
0xd5, 0x2e, 0xd6, 0x72, 0x9d, 0xe6, 0xa9, 0x59, 0x14, 0x3f, 0xa7, 0xb2, 0x43, 0x8e, 0x2d, 0xcc,
0xeb, 0xe0, 0xf3, 0x1b, 0xcb, 0x43, 0x9d, 0xae, 0xea, 0x98, 0x5a, 0xa9, 0x65, 0x17, 0x9f, 0x31,
0x97, 0x1f, 0x32, 0x81, 0x8b, 0xe8, 0xee, 0xa5, 0xbb, 0x08, 0x23, 0x85, 0x7e, 0x5c, 0xcd, 0x6f,
0xf9, 0x9c, 0xe3, 0x38, 0x85, 0x5b, 0xfa, 0x7d, 0xa5, 0x3a, 0x5e, 0x35, 0xe2, 0xcc, 0xf5, 0x3e,
0x2c, 0x32, 0x59, 0xd0, 0xdd, 0xfc, 0x48, 0xf3, 0xde, 0x84, 0x04, 0xfe, 0xd4, 0x69, 0xbb, 0x66,
0x19, 0x77, 0xb5, 0xb1, 0x15, 0x24, 0x71, 0x1f, 0x87, 0x7c, 0x3c, 0xdd, 0x49, 0x25, 0x6b, 0x99,
0xc7, 0x6d, 0x0c, 0x27, 0x45, 0xf1, 0xa0, 0xd7, 0x4e, 0x3a, 0x37, 0x30, 0xdf, 0xaf, 0x62, 0x89,
0x4b, 0xa5, 0x3c, 0x69, 0xd4, 0x29, 0x11, 0xe3, 0x55, 0x47, 0xe8, 0x52, 0x9b, 0xca, 0x78, 0x8a,
0x5e, 0x1a, 0x4d, 0xb4, 0x79, 0x2c, 0xed, 0x94, 0x5f, 0x31, 0xf7, 0xd0, 0x83, 0x08, 0x12, 0x28,
0xe0, 0x19, 0x1f, 0x7b, 0x81, 0x9b, 0xd8, 0xc9, 0x2b, 0xdc, 0x46, 0x5f, 0xa2, 0x35, 0x3d, 0x3d,
0x8d, 0x07, 0xa5, 0xdc, 0x65, 0xed, 0x64, 0x3b, 0x77, 0x19, 0xb7, 0xe1, 0xc7, 0xce, 0x2d, 0x1c,
0x34, 0x59, 0xe4, 0x06, 0x3e, 0x60, 0x82, 0x46, 0x67, 0xcd, 0xef, 0x51, 0xd1, 0x29, 0xbf, 0x53,
0x7c, 0xca, 0x73, 0xbc, 0xc6, 0x56, 0x1c, 0x5e, 0x2b, 0x7f, 0x13, 0x4f, 0x30, 0x92, 0x78, 0x5d,
0x6b, 0x03, 0x91, 0xcc, 0x90, 0xae, 0x15, 0xa8, 0xe7, 0x23, 0xc6, 0x1b, 0x6b, 0xf1, 0x8c, 0xe2,
0xc7, 0x1c, 0x37, 0x59, 0x6c, 0x17, 0xbb, 0x79, 0x84, 0x2c, 0x0d, 0xd5, 0x91, 0xac, 0x3a, 0xf6,
0x9f, 0x93, 0x5d, 0x3c, 0xc1, 0x60, 0x43, 0x06, 0x72, 0x29, 0x2c, 0x14, 0x5e, 0xe5, 0x6d, 0xd3,
0x21, 0x9e, 0x34, 0xa2, 0xe7, 0xef, 0x48, 0x3c, 0xbf, 0x50, 0x1d, 0x56, 0x41, 0x8b, 0xee, 0x7e,
0xce, 0xcd, 0x24, 0xab, 0x96, 0x6e, 0x96, 0xaa, 0xa8, 0x3f, 0xb5, 0xbc, 0xa3, 0xb9, 0xb5, 0xe9,
0x8c, 0x9d, 0x87, 0xa4, 0xd9, 0x66, 0xef, 0x60, 0x39, 0xb7, 0x9a, 0xb5, 0x91, 0x35, 0x81, 0xd9,
0x01, 0x50, 0x01, 0x37, 0xa5, 0xbc, 0xce, 0xe5, 0x2a, 0xfb, 0xaf, 0x89, 0x9c, 0x52, 0x9c, 0x7f,
0x19, 0x8f, 0x93, 0x61, 0xe0, 0x7b, 0xb1, 0x33, 0x47, 0x92, 0xd9, 0x40, 0x25, 0xaf, 0x30, 0xcc,
0x4c, 0xb7, 0xde, 0x04, 0x7e, 0xc1, 0x89, 0x00, 0x14, 0xa4, 0x95, 0x7d, 0xfc, 0x99, 0xcb, 0x55,
0xb4, 0x04, 0x97, 0x2a, 0x8e, 0xfa, 0x53, 0xc6, 0x6c, 0x83, 0x8f, 0xa2, 0x4e, 0x66, 0x81, 0xf0,
0xaa, 0x77, 0xe3, 0x64, 0x07, 0x3f, 0x35, 0xff, 0x6c, 0xb8, 0x04, 0x1e, 0xe2, 0x58, 0x40, 0x0a,
0xd4, 0xc2, 0x21, 0xfe, 0xce, 0xcd, 0x64, 0x2a, 0xd2, 0xe8, 0x3b, 0xa8, 0x53, 0x94, 0x6b, 0x3d,
0x4f, 0x1a, 0x5c, 0xfd, 0x36, 0xa6, 0x51, 0x2e, 0xbc, 0xfa, 0x1b, 0xf8, 0x84, 0x2b, 0x02, 0xb3,
0xdf, 0x29, 0x9e, 0x19, 0xec, 0xd6, 0x19, 0x72, 0x5d, 0xb9, 0x56, 0x97, 0xb3, 0x98, 0x5f, 0x31,
0x96, 0x54, 0x9f, 0x26, 0xd8, 0x2c, 0xc5, 0x8e, 0x9e, 0x4b, 0x0c, 0xf7, 0x79, 0xbe, 0x98, 0xf5,
0xc2, 0xab, 0xff, 0x28, 0x7f, 0xa4, 0x4f, 0xe0, 0xfc, 0x9c, 0xa2, 0xb8, 0x91, 0xd5, 0x01, 0xec,
0xf5, 0x9a, 0xd8, 0xcf, 0xfb, 0x3c, 0xca, 0xd5, 0xe4, 0x92, 0xd4, 0x61, 0x72, 0x63, 0x23, 0x8e,
0x8b, 0x79, 0x5b, 0x61, 0xb8, 0x46, 0x07, 0x8f, 0x1a, 0x3a, 0x39, 0xb2, 0x33, 0x8e, 0xe5, 0x01,
0xfa, 0x18, 0xbc, 0xa5, 0x16, 0x56, 0xf3, 0x5f, 0xfe, 0x1c, 0xf8, 0x8c, 0xd6, 0x8d, 0x70, 0x46,
0xf1, 0x4b, 0xae, 0x0d, 0xe8, 0xda, 0x5a, 0x33, 0x27, 0x29, 0x63, 0x0f, 0xfb, 0x38, 0x4a, 0x15,
0x95, 0x38, 0x08, 0xa7, 0x0b, 0x19, 0x0c, 0x67, 0x3c, 0x7d, 0x14, 0x0e, 0x7c, 0x6a, 0xb8, 0x8f,
0x77, 0x31, 0x2a, 0x1c, 0x63, 0x02, 0x53, 0xf8, 0x05, 0x43, 0x85, 0x7a, 0x18, 0xd6, 0xf0, 0x11,
0x2f, 0xb2, 0x39, 0xf0, 0x11, 0xcc, 0x6d, 0xf4, 0xe1, 0xd9, 0x80, 0xcc, 0x09, 0xda, 0x27, 0x17,
0x2d, 0x34, 0x70, 0x8a, 0x12, 0xf6, 0x71, 0x80, 0x72, 0x1a, 0x55, 0xb5, 0x44, 0x8d, 0xcc, 0x36,
0x68, 0x8c, 0x1c, 0xc1, 0x70, 0x5e, 0x12, 0x50, 0xfe, 0xf6, 0xef, 0x62, 0x3f, 0x0f, 0xd1, 0x3d,
0xd0, 0x55, 0xff, 0x1d, 0x49, 0x4c, 0x67, 0xb5, 0xa9, 0x0b, 0x45, 0xc6, 0xa7, 0x2f, 0x0c, 0xd8,
0x16, 0x1a, 0xc1, 0x10, 0x9e, 0x64, 0xab, 0xe0, 0x92, 0x3b, 0xf8, 0x8a, 0x6b, 0x44, 0xfb, 0x37,
0x84, 0x33, 0x94, 0x17, 0x4c, 0xb7, 0x10, 0x1a, 0x99, 0xea, 0x99, 0xab, 0xcb, 0xbf, 0x21, 0x99,
0x09, 0xfc, 0x8f, 0x0f, 0xf3, 0x72, 0xa0, 0xd2, 0x49, 0x9e, 0xf5, 0x72, 0xcc, 0x76, 0xc0, 0x49,
0x60, 0x0a, 0x9f, 0x05, 0x68, 0x3b, 0x99, 0x11, 0xe9, 0x34, 0xff, 0x60, 0x8c, 0xea, 0x2f, 0xc7,
0x4e, 0x0a, 0x05, 0xfc, 0x84, 0x85, 0x1c, 0x15, 0xde, 0xe6, 0xb9, 0xd8, 0xcc, 0x9d, 0xea, 0xf6,
0x6d, 0x98, 0xab, 0x29, 0x36, 0x7a, 0x72, 0x03, 0xb7, 0x31, 0xca, 0x22, 0xd1, 0x05, 0x9c, 0x1c,
0xe4, 0x73, 0x3e, 0x67, 0x33, 0x55, 0x7e, 0xe2, 0x6c, 0xd9, 0x88, 0x20, 0x96, 0x6e, 0x0c, 0x64,
0x08, 0x05, 0x0c, 0xa6, 0xbb, 0x04, 0x2e, 0xa5, 0x8d, 0x7c, 0xcc, 0x73, 0x6c, 0xf4, 0xba, 0xad,
0xce, 0x4b, 0x41, 0xcc, 0x26, 0x8c, 0x4c, 0xae, 0xe5, 0x7b, 0x14, 0xea, 0x5c, 0x5b, 0x0b, 0x14,
0x2e, 0x4e, 0xb2, 0x8f, 0x0d, 0x6c, 0xe5, 0x30, 0x27, 0xa8, 0xa0, 0x16, 0x17, 0x4e, 0xdc, 0xd8,
0xb1, 0x63, 0x23, 0x89, 0x64, 0x52, 0xe8, 0x4a, 0x26, 0x79, 0xf4, 0x27, 0x9b, 0xae, 0x24, 0x09,
0x88, 0x9b, 0xe0, 0x89, 0x52, 0x5e, 0xe6, 0x55, 0xbf, 0x61, 0xf0, 0x3a, 0x11, 0x98, 0x2a, 0xb1,
0xd3, 0x95, 0x31, 0x5c, 0xcf, 0x25, 0xe4, 0x59, 0xc2, 0x5d, 0xea, 0x4c, 0x68, 0x8a, 0x2a, 0xaa,
0xa9, 0xa3, 0x01, 0x17, 0x95, 0x34, 0x10, 0x4f, 0x32, 0x76, 0x62, 0x88, 0x23, 0x9e, 0x24, 0x62,
0x25, 0xa9, 0xf6, 0x33, 0xb8, 0x58, 0xcb, 0xef, 0x59, 0xa2, 0x25, 0x64, 0x6c, 0x20, 0xbf, 0xc9,
0x68, 0x72, 0x18, 0xc9, 0x78, 0x0a, 0xc8, 0x24, 0xd5, 0xf4, 0x5d, 0x38, 0xad, 0xd4, 0xd2, 0x80,
0x9d, 0x64, 0x8b, 0x74, 0x3f, 0xda, 0x39, 0xcd, 0xbf, 0x78, 0x9e, 0x3d, 0xda, 0x6e, 0x0e, 0x74,
0xa3, 0x6c, 0x23, 0x82, 0x34, 0xf2, 0xc8, 0xa6, 0x0f, 0x39, 0x64, 0x90, 0x46, 0x04, 0x11, 0x44,
0xd1, 0x7a, 0xd6, 0x62, 0xd7, 0x82, 0x9b, 0x74, 0x52, 0x89, 0xd3, 0x21, 0x59, 0x13, 0xfb, 0x59,
0xc9, 0x5a, 0x4a, 0x38, 0x8d, 0x9d, 0x0c, 0x6e, 0x60, 0x8a, 0x86, 0x65, 0x64, 0x6b, 0xe0, 0x66,
0x0f, 0x7f, 0xe2, 0x1d, 0x4e, 0x6b, 0xcd, 0x40, 0x5c, 0xaf, 0x1c, 0x46, 0x24, 0x91, 0x84, 0x63,
0x27, 0x86, 0x44, 0x1a, 0x71, 0x90, 0xca, 0x20, 0x46, 0x33, 0x94, 0x7c, 0x92, 0x35, 0x37, 0xb0,
0x75, 0xac, 0xe6, 0x03, 0xbe, 0xe6, 0x70, 0x1b, 0x8f, 0xdd, 0x78, 0x1e, 0xe0, 0x71, 0x21, 0x21,
0x9d, 0xcd, 0xa6, 0x99, 0xc5, 0x3c, 0xcd, 0x6a, 0x75, 0xc3, 0xbe, 0xf6, 0xc8, 0x30, 0x2c, 0x8b,
0x24, 0x93, 0x51, 0x5c, 0xca, 0x18, 0x72, 0x75, 0x9d, 0x88, 0xd1, 0xc4, 0x4a, 0xde, 0x64, 0x11,
0xe5, 0x74, 0x34, 0xe9, 0xa6, 0xf1, 0x16, 0xd7, 0x78, 0xbc, 0xe3, 0x20, 0x27, 0x48, 0x25, 0xc7,
0x22, 0x03, 0xd4, 0xf6, 0x94, 0xf3, 0x2a, 0x2f, 0x2b, 0xdc, 0x4a, 0x2f, 0x29, 0x36, 0xba, 0x31,
0x85, 0x57, 0xd8, 0xa9, 0x70, 0xc9, 0xd6, 0xd7, 0x0c, 0x78, 0x0f, 0x0f, 0x7b, 0x8d, 0xf2, 0x67,
0xe3, 0x11, 0x0f, 0xf7, 0x14, 0xf3, 0x73, 0xfa, 0xd1, 0x95, 0x6c, 0xae, 0xe3, 0x55, 0x8e, 0x08,
0x5e, 0xba, 0x51, 0x97, 0x9c, 0xac, 0x63, 0x9a, 0x68, 0x6b, 0x9f, 0x3e, 0xec, 0xe4, 0xf0, 0x00,
0x5f, 0x1b, 0x72, 0x38, 0x4d, 0x2d, 0x6f, 0x33, 0xd6, 0x67, 0xb7, 0x71, 0x4b, 0xa7, 0xea, 0x3d,
0xc1, 0x9d, 0x6d, 0xee, 0x88, 0xe5, 0x2a, 0x3e, 0xb6, 0xcc, 0x19, 0xea, 0xb5, 0xbc, 0xc1, 0x60,
0x0b, 0xb6, 0x59, 0x6d, 0xe8, 0xc1, 0x7d, 0xac, 0xd0, 0x78, 0xb2, 0x5e, 0xc7, 0x6f, 0xbf, 0x84,
0x39, 0x7e, 0x8d, 0xb8, 0xff, 0xd5, 0x41, 0x01, 0x5c, 0xcc, 0xef, 0x34, 0x30, 0xec, 0xc9, 0xd3,
0x1e, 0x7c, 0x88, 0x65, 0x4b, 0x2e, 0xf6, 0x31, 0xdb, 0xda, 0xb1, 0x8c, 0x62, 0xb8, 0x8e, 0x8f,
0x15, 0x1f, 0xf4, 0xe8, 0x3b, 0x39, 0x59, 0xc3, 0x4d, 0x7e, 0xfd, 0x5d, 0xec, 0x3c, 0xda, 0xe1,
0xbe, 0x1a, 0x66, 0x7a, 0xb8, 0x2e, 0x81, 0x9f, 0x71, 0x54, 0x78, 0x15, 0xfb, 0x4a, 0x8d, 0x7c,
0xc1, 0x95, 0x16, 0xb1, 0xa5, 0x78, 0x21, 0x8b, 0xa7, 0x38, 0x62, 0xd0, 0xeb, 0x70, 0xf0, 0x29,
0xa3, 0x15, 0x0c, 0x1b, 0x63, 0x78, 0xbb, 0xc3, 0x9d, 0xfb, 0xb9, 0xd8, 0xe3, 0x95, 0x51, 0xdc,
0x2b, 0xb1, 0x0a, 0x9c, 0xe0, 0x4f, 0x81, 0xf4, 0xef, 0x31, 0x9e, 0x30, 0xc6, 0xf2, 0xb1, 0x61,
0xeb, 0x65, 0x0d, 0xfc, 0xc3, 0xef, 0x29, 0x60, 0x67, 0xe8, 0xc3, 0xf6, 0x0e, 0xf7, 0x6e, 0x26,
0xc7, 0xcb, 0xb5, 0x51, 0x3c, 0x28, 0x81, 0x27, 0x5f, 0xe7, 0xd4, 0xca, 0x66, 0xee, 0xb6, 0x76,
0x20, 0xdb, 0x68, 0xa6, 0x19, 0xb8, 0x91, 0xac, 0x81, 0xd7, 0x15, 0x6f, 0x72, 0xf8, 0x41, 0xa7,
0xe1, 0xdd, 0x06, 0x1f, 0xee, 0xdf, 0xf1, 0xfc, 0x56, 0xba, 0x35, 0xcc, 0x1a, 0xde, 0x61, 0xac,
0xb5, 0x63, 0x18, 0x25, 0xf0, 0xa0, 0xcf, 0x8d, 0x98, 0x6a, 0xab, 0xff, 0x35, 0xc5, 0x0e, 0x1c,
0x9e, 0x9c, 0xb3, 0x37, 0xf8, 0x8c, 0x77, 0x98, 0xc6, 0xdf, 0xa4, 0xd9, 0xd0, 0xe1, 0xa6, 0x85,
0xad, 0xcc, 0xb6, 0xfa, 0xd1, 0x3d, 0x49, 0xfc, 0x46, 0xc3, 0xa9, 0xbc, 0xbe, 0xbe, 0x7e, 0xe5,
0xfe, 0x3b, 0x93, 0x3c, 0xec, 0x58, 0xd8, 0xe8, 0xe7, 0x48, 0xbc, 0xfe, 0x1e, 0xb6, 0x95, 0x8a,
0x48, 0x2e, 0x8e, 0xf3, 0x1a, 0x63, 0xad, 0x3d, 0xec, 0x83, 0x44, 0x7e, 0x63, 0xe0, 0x04, 0xab,
0x85, 0x7f, 0xaa, 0xa8, 0xfe, 0x44, 0xde, 0xf4, 0x90, 0xc7, 0x4e, 0xbf, 0xa1, 0xee, 0xae, 0x97,
0x60, 0x30, 0x58, 0xc5, 0x27, 0xdc, 0x4a, 0x8a, 0xe8, 0xea, 0xd3, 0x4b, 0x2c, 0x0f, 0xa9, 0xd8,
0x9e, 0xe5, 0x2f, 0x39, 0x59, 0xc4, 0x40, 0x15, 0x4f, 0xbf, 0xd9, 0xe3, 0xb3, 0x0f, 0xfb, 0x0d,
0x7e, 0x1f, 0xc5, 0x1f, 0x85, 0xba, 0x77, 0x55, 0xf1, 0x39, 0x77, 0x93, 0x69, 0xe5, 0x31, 0xff,
0xb9, 0x17, 0x39, 0xc3, 0xb0, 0x69, 0x9f, 0x1b, 0x37, 0x1b, 0x54, 0x1d, 0x69, 0x9b, 0xc5, 0x57,
0x1e, 0x73, 0xa9, 0xe1, 0x47, 0x7e, 0xef, 0xcd, 0x61, 0x89, 0x2a, 0xc9, 0x1c, 0x06, 0xb9, 0x84,
0x39, 0x29, 0xe7, 0x53, 0x7e, 0x44, 0x4f, 0xcb, 0x45, 0x1d, 0xf2, 0x80, 0x9d, 0xc9, 0xec, 0x31,
0xb0, 0xfa, 0x8f, 0x32, 0x4d, 0xc5, 0x6b, 0x89, 0xe6, 0x09, 0x2f, 0xd6, 0xc6, 0x56, 0x9e, 0x52,
0xb0, 0xe2, 0x38, 0x45, 0xc5, 0x84, 0xd0, 0xc5, 0x71, 0x56, 0xb3, 0x89, 0x2a, 0x5d, 0x6b, 0x0a,
0x4d, 0xec, 0xe1, 0x75, 0xbe, 0x47, 0x86, 0xf5, 0xbf, 0xfc, 0x33, 0x0c, 0x37, 0x74, 0x7f, 0x4c,
0x03, 0xbf, 0x55, 0xe5, 0x7b, 0x77, 0x3d, 0x87, 0xbd, 0xe6, 0xb5, 0x40, 0xc1, 0xe9, 0x20, 0x09,
0xfc, 0x4d, 0x85, 0xf4, 0xad, 0x14, 0xf3, 0x32, 0xbf, 0xe4, 0xef, 0x6c, 0xa3, 0x4e, 0x75, 0xa9,
0x9b, 0x39, 0x76, 0x76, 0xb3, 0x5b, 0x52, 0xb0, 0x54, 0x3e, 0xf4, 0xe0, 0x2d, 0x43, 0x3d, 0x65,
0xff, 0xad, 0x6a, 0xf3, 0x76, 0x7f, 0xbe, 0xf6, 0x91, 0xd7, 0x76, 0x06, 0x29, 0xc8, 0x63, 0x2c,
0x07, 0x54, 0x49, 0x58, 0xc9, 0xdb, 0x5c, 0xcd, 0x28, 0x66, 0xf0, 0x26, 0x5b, 0x14, 0xb5, 0x06,
0x4e, 0xaa, 0xd9, 0xc9, 0x87, 0x3c, 0xca, 0xd5, 0xf4, 0x0c, 0xfc, 0x68, 0xdf, 0x4c, 0xd3, 0x42,
0x14, 0xd3, 0xb9, 0xc9, 0xc0, 0x27, 0x1c, 0xe2, 0x79, 0x3f, 0x47, 0x3e, 0xb4, 0x25, 0x8d, 0xd9,
0x8c, 0xf3, 0xf1, 0x7b, 0x06, 0x43, 0x3d, 0x86, 0x8d, 0x6c, 0xcf, 0x06, 0x3e, 0x64, 0xb6, 0x8a,
0x2f, 0x32, 0x85, 0x5b, 0xc9, 0xe7, 0x45, 0x16, 0xf0, 0x1e, 0xd9, 0x0c, 0x64, 0x10, 0xf9, 0x64,
0x91, 0x46, 0x2c, 0x31, 0x44, 0x12, 0x89, 0x0d, 0x70, 0xe2, 0xc0, 0x41, 0x23, 0xf5, 0x9c, 0xe2,
0x30, 0x3b, 0xd9, 0xc3, 0x3e, 0x0e, 0x51, 0xab, 0x2a, 0x40, 0xb6, 0x61, 0x98, 0xa9, 0x00, 0xe3,
0x98, 0x61, 0xe0, 0xd9, 0x02, 0x2d, 0xbc, 0xc9, 0x4a, 0xc5, 0x57, 0xc7, 0x72, 0x0f, 0xb7, 0xf9,
0xfc, 0x9e, 0x92, 0x18, 0xc9, 0x42, 0xbf, 0x6e, 0x94, 0xcd, 0xbc, 0xc3, 0x8d, 0xaa, 0xc2, 0x48,
0x86, 0x31, 0x98, 0xa7, 0x19, 0xc9, 0xff, 0xb2, 0x83, 0xed, 0x7c, 0x44, 0x3c, 0x09, 0x64, 0x90,
0x4e, 0xf2, 0xf9, 0xd3, 0x86, 0x1d, 0xd4, 0x52, 0x47, 0x05, 0xa7, 0x38, 0x45, 0x3d, 0x75, 0x62,
0x2a, 0xde, 0x7c, 0xb2, 0xf8, 0xc0, 0x50, 0x17, 0x8b, 0xd5, 0xf4, 0x51, 0xfc, 0xec, 0x08, 0x66,
0x52, 0xaa, 0x20, 0x47, 0x25, 0xc1, 0x6e, 0xa3, 0x78, 0x5e, 0x83, 0xb4, 0x2d, 0x7c, 0xcb, 0x35,
0x52, 0x79, 0x0e, 0x07, 0x98, 0x48, 0x1e, 0x36, 0xc4, 0xd5, 0xe3, 0x5c, 0x6a, 0x54, 0xd1, 0x10,
0x87, 0x33, 0x8d, 0x62, 0x05, 0x79, 0x56, 0x71, 0x87, 0xa2, 0xfc, 0xc6, 0x6b, 0x32, 0x09, 0xb9,
0xd8, 0xc5, 0xf4, 0xa0, 0x3a, 0x88, 0x56, 0x15, 0x85, 0x06, 0xc7, 0x0f, 0x5c, 0xa5, 0x38, 0x7c,
0x83, 0x8d, 0xeb, 0xd8, 0xa5, 0x30, 0xd7, 0x37, 0x14, 0xad, 0xae, 0x25, 0xf2, 0x8e, 0x46, 0xa9,
0x0f, 0x73, 0xb7, 0x29, 0x07, 0xdc, 0x49, 0x4f, 0x02, 0x7f, 0xee, 0x14, 0xa3, 0x53, 0x4f, 0x6a,
0xe5, 0xd7, 0x0a, 0x67, 0xff, 0x11, 0x4c, 0x66, 0x83, 0xe2, 0x7c, 0xf7, 0x71, 0xa9, 0xa2, 0x5c,
0x7f, 0xa0, 0xd9, 0x67, 0xf1, 0x08, 0x33, 0x2f, 0xc4, 0x56, 0xe0, 0x2a, 0x83, 0x83, 0x47, 0x1e,
0x66, 0xa4, 0xa2, 0xe7, 0x46, 0x30, 0x8d, 0xdd, 0x2a, 0xf2, 0x6d, 0xe6, 0x8f, 0x8a, 0x1c, 0x2b,
0x7b, 0xb3, 0x56, 0xb3, 0xec, 0x47, 0xb8, 0xcb, 0xda, 0xcb, 0xb8, 0xea, 0xe9, 0xc2, 0x3f, 0x0c,
0xf6, 0xb0, 0xfd, 0x44, 0xd1, 0x82, 0x48, 0x1c, 0xf7, 0x28, 0xea, 0xfb, 0xdb, 0xa6, 0xcd, 0x14,
0x28, 0xc8, 0x39, 0x8a, 0x67, 0x74, 0x04, 0xbe, 0xd9, 0xcb, 0x8d, 0xc1, 0x63, 0xda, 0x51, 0xc2,
0x64, 0x05, 0x23, 0x70, 0x75, 0xe9, 0xb7, 0x0a, 0x3a, 0x80, 0x54, 0x1e, 0xd3, 0x10, 0x97, 0xa3,
0x89, 0xa7, 0x14, 0xb5, 0x01, 0x93, 0x75, 0x05, 0x7d, 0x5d, 0xcd, 0x70, 0xd1, 0x95, 0x12, 0x38,
0x12, 0xf8, 0xab, 0xc1, 0xd5, 0xef, 0xf0, 0x3b, 0x5a, 0xb7, 0x31, 0x80, 0x57, 0x34, 0xce, 0x3a,
0x94, 0xb5, 0x01, 0x7d, 0x54, 0x8c, 0x2c, 0x3a, 0xa7, 0x56, 0xde, 0xbc, 0x70, 0x8e, 0xa4, 0x9b,
0x60, 0x78, 0xf0, 0xe8, 0x3a, 0x6e, 0xf5, 0xf9, 0xc4, 0x68, 0x26, 0xb3, 0x4c, 0xb3, 0xc9, 0xb9,
0x99, 0xa7, 0x15, 0xac, 0x2f, 0xc4, 0xf1, 0xaa, 0xae, 0x32, 0xd4, 0x32, 0x5b, 0x4e, 0xa7, 0x0e,
0xa3, 0x17, 0x1c, 0x63, 0xb8, 0x81, 0x5e, 0x06, 0xe7, 0x19, 0xe6, 0xc3, 0xa0, 0x62, 0xa3, 0x37,
0x8f, 0xf1, 0x17, 0xc6, 0x69, 0x1e, 0x68, 0x45, 0x30, 0x4d, 0xc1, 0x02, 0x73, 0x3d, 0xdb, 0x74,
0x59, 0xec, 0x12, 0xb8, 0x97, 0x42, 0x83, 0xdf, 0x8b, 0x94, 0x0c, 0xd2, 0xd5, 0x54, 0x7a, 0x4b,
0x8f, 0x79, 0x51, 0xd4, 0x54, 0xee, 0xa0, 0xc8, 0x80, 0xe5, 0xa6, 0xf9, 0x0a, 0xa2, 0x03, 0x5d,
0xa5, 0x33, 0xf2, 0x97, 0x93, 0xbf, 0x2b, 0x58, 0x7f, 0xb4, 0x38, 0x61, 0xdc, 0xaf, 0x7b, 0x97,
0x9f, 0xa7, 0xb4, 0x86, 0x01, 0x1d, 0x9e, 0x64, 0xa7, 0x2b, 0x37, 0xf3, 0x3e, 0x55, 0x86, 0xe4,
0x5f, 0xc9, 0x0c, 0xbf, 0x2d, 0x48, 0x7f, 0xf6, 0xea, 0x7c, 0xca, 0x09, 0x6e, 0x0f, 0xf6, 0xd9,
0x40, 0x9a, 0x49, 0xf1, 0xf1, 0x5b, 0x59, 0xc0, 0x70, 0xa2, 0x09, 0xc3, 0x4e, 0x14, 0xc9, 0x8c,
0x62, 0x36, 0x5f, 0x19, 0x7a, 0x18, 0xc3, 0x3a, 0xbf, 0x96, 0x86, 0x1e, 0x14, 0xe9, 0x7e, 0xca,
0x67, 0x7e, 0x5c, 0x51, 0x05, 0x60, 0xac, 0x89, 0x62, 0xa0, 0x42, 0x83, 0x8d, 0x5a, 0xc2, 0xb8,
0x99, 0xa1, 0xac, 0x62, 0x2f, 0x6e, 0xb2, 0xc8, 0xa3, 0x1f, 0x3d, 0x0c, 0x96, 0xbc, 0x80, 0x9f,
0xf1, 0x4b, 0x9f, 0x67, 0x68, 0x35, 0xa9, 0x58, 0x8a, 0xf6, 0xc6, 0x58, 0xae, 0xe2, 0x0d, 0x8c,
0x8a, 0x47, 0x6a, 0x08, 0x46, 0xbe, 0xc6, 0x70, 0x0a, 0x4d, 0xf3, 0x5e, 0xb7, 0xd3, 0xd7, 0xc4,
0x83, 0x2a, 0xc1, 0xce, 0x14, 0x76, 0xf3, 0x3c, 0x0d, 0x5e, 0xaf, 0x70, 0xf9, 0x89, 0x1b, 0xa6,
0x84, 0x14, 0xa6, 0xb2, 0x88, 0xe3, 0x26, 0x96, 0x43, 0x43, 0xc1, 0x8d, 0x23, 0x91, 0xb1, 0x16,
0x5e, 0xfa, 0x88, 0xe7, 0x01, 0xa6, 0xfa, 0xfc, 0x20, 0x8c, 0xe8, 0xbf, 0xc7, 0x78, 0xd9, 0x93,
0x28, 0x0c, 0x23, 0x15, 0xa0, 0x1f, 0x43, 0x45, 0x17, 0x47, 0x17, 0x19, 0x3c, 0xca, 0x44, 0x93,
0x87, 0x69, 0x69, 0x4c, 0x32, 0xd0, 0x49, 0xc6, 0x00, 0x8c, 0x53, 0x00, 0x3b, 0xa3, 0x0c, 0xb7,
0x00, 0x04, 0x9a, 0x7c, 0x9e, 0x60, 0x8c, 0x17, 0x15, 0x88, 0x30, 0xe4, 0x38, 0x09, 0x1b, 0xe3,
0xe8, 0x27, 0xba, 0x98, 0x6d, 0x31, 0x4e, 0x01, 0x92, 0x98, 0x60, 0xe1, 0x0e, 0xe0, 0x1c, 0x17,
0x33, 0x97, 0x4b, 0x3c, 0x1a, 0x9e, 0x92, 0xbd, 0xee, 0x27, 0x56, 0x47, 0x0e, 0xe3, 0x65, 0xf2,
0xf7, 0x37, 0x4e, 0x94, 0x7e, 0x0c, 0x13, 0x5d, 0x18, 0x03, 0xb0, 0x71, 0x29, 0x2f, 0x30, 0xd9,
0xc3, 0x02, 0xd1, 0x08, 0x83, 0xa6, 0x70, 0x31, 0x4c, 0x30, 0xf1, 0xd0, 0x6d, 0xd5, 0x18, 0xa5,
0x00, 0x76, 0x0a, 0xa5, 0xed, 0x00, 0x5c, 0x6d, 0x42, 0xc6, 0xf9, 0xc7, 0xc6, 0x08, 0x9e, 0x63,
0x16, 0xdd, 0xdb, 0x75, 0x05, 0x5d, 0x99, 0x6a, 0x58, 0xac, 0xc1, 0x41, 0x06, 0xb5, 0x25, 0x86,
0x60, 0x94, 0xdb, 0x62, 0x32, 0xb3, 0x18, 0x22, 0xba, 0x30, 0x5e, 0x70, 0x70, 0x58, 0x65, 0x4c,
0x9d, 0x14, 0xc6, 0xd0, 0x17, 0x07, 0x95, 0x38, 0x38, 0x13, 0xcb, 0xec, 0x3e, 0xa6, 0x1b, 0x16,
0x93, 0x2b, 0x8a, 0xed, 0x6c, 0x94, 0xc5, 0x1a, 0x60, 0x94, 0x1d, 0x20, 0x47, 0xe2, 0x15, 0xef,
0x6a, 0x76, 0xab, 0x1e, 0x78, 0x25, 0x72, 0x2b, 0xe3, 0x58, 0xc9, 0x06, 0xca, 0x88, 0x67, 0x1c,
0x93, 0x0c, 0x8c, 0xcd, 0x11, 0xc7, 0x48, 0xde, 0xa2, 0x4e, 0xf4, 0x6b, 0x39, 0x83, 0x31, 0x0a,
0x60, 0x63, 0x94, 0xa1, 0x07, 0x2e, 0x1a, 0xcb, 0x2e, 0x2a, 0x34, 0x95, 0xa9, 0x07, 0xb7, 0x30,
0x99, 0x26, 0xc2, 0x89, 0x31, 0x78, 0x72, 0x38, 0x80, 0x1e, 0xec, 0x13, 0xfd, 0x5a, 0xce, 0x60,
0xcc, 0x18, 0x20, 0x91, 0x4b, 0xa5, 0x0d, 0xc9, 0xec, 0x66, 0x93, 0x8e, 0x50, 0xaa, 0x91, 0x24,
0x12, 0x6b, 0xb8, 0x6d, 0x20, 0xd7, 0x8c, 0x13, 0x7c, 0xb5, 0x61, 0x8c, 0x02, 0x64, 0x4b, 0xbc,
0xd6, 0x5d, 0xa3, 0x2f, 0x96, 0xae, 0x29, 0x24, 0xd3, 0x4f, 0x96, 0x4d, 0x23, 0x46, 0x28, 0x80,
0x8d, 0xd1, 0xd2, 0xce, 0x00, 0xe0, 0x10, 0x5b, 0xa4, 0x5b, 0x84, 0x8d, 0xe2, 0x22, 0x59, 0x6c,
0x26, 0x46, 0x28, 0x40, 0x02, 0xe3, 0xa4, 0xed, 0x00, 0x60, 0x35, 0x27, 0xa5, 0x53, 0x00, 0x3b,
0xbd, 0x65, 0x89, 0x5e, 0x6e, 0x84, 0x02, 0xe4, 0x30, 0x5a, 0x74, 0x31, 0xbc, 0x52, 0xc7, 0xb7,
0x3e, 0x56, 0xf8, 0xc4, 0xd1, 0x4d, 0x16, 0x63, 0x90, 0x7e, 0x05, 0xb0, 0x31, 0xda, 0x80, 0x13,
0xf7, 0xcc, 0xa2, 0x84, 0x35, 0xa2, 0x45, 0xf0, 0x48, 0x5a, 0xf0, 0x28, 0x40, 0x1c, 0x97, 0x49,
0x1c, 0xb6, 0xfc, 0x5b, 0x8e, 0x61, 0x93, 0xae, 0x0b, 0x80, 0x14, 0x59, 0xdc, 0xc4, 0xf5, 0x2b,
0x40, 0x1f, 0x93, 0xbc, 0x80, 0x8c, 0xe0, 0x14, 0x9f, 0xd1, 0x8c, 0xdb, 0x00, 0x57, 0x0e, 0xa3,
0x89, 0x0e, 0x1e, 0x05, 0x18, 0x29, 0xcf, 0x9c, 0xb6, 0x13, 0x2b, 0x59, 0x03, 0xb4, 0x6a, 0x32,
0x04, 0x99, 0x8b, 0x9d, 0x74, 0x39, 0xf6, 0x09, 0xe8, 0x55, 0x80, 0x58, 0xae, 0x94, 0x65, 0x42,
0xd3, 0x89, 0x3a, 0xde, 0xa3, 0x0a, 0x70, 0xfa, 0xf4, 0xf5, 0x13, 0x83, 0x9d, 0x2e, 0x72, 0x6c,
0x19, 0xd5, 0xab, 0x00, 0xd9, 0xd2, 0x2e, 0x01, 0xc1, 0xd7, 0x2c, 0x3e, 0xfb, 0xaf, 0x52, 0x1a,
0x45, 0x0b, 0xd3, 0x01, 0x1b, 0xb1, 0x72, 0x78, 0x05, 0xe8, 0x15, 0xa2, 0x80, 0x5c, 0xd1, 0x45,
0xf0, 0xc2, 0x71, 0x5e, 0xe5, 0xe4, 0xd9, 0x7f, 0x1f, 0x3d, 0xff, 0x2f, 0x59, 0xb0, 0x05, 0x47,
0x0b, 0x10, 0xcd, 0x65, 0x12, 0x9c, 0x99, 0xeb, 0x09, 0x27, 0x0b, 0x58, 0x7a, 0xfe, 0x7f, 0x47,
0x28, 0x17, 0x2d, 0x50, 0x27, 0xec, 0x72, 0xcc, 0x4d, 0xf4, 0x29, 0x40, 0x4f, 0x55, 0x61, 0x5b,
0x03, 0xc9, 0x06, 0x5e, 0x69, 0xb3, 0xe0, 0x5a, 0xad, 0x20, 0x20, 0xdc, 0x05, 0x8a, 0x3e, 0x05,
0x18, 0x2b, 0x93, 0x6f, 0x4b, 0x1b, 0xca, 0x78, 0x96, 0x5d, 0x6d, 0xfe, 0xef, 0x60, 0xa5, 0x2c,
0x0e, 0x18, 0xb2, 0xa1, 0x47, 0x01, 0x62, 0x98, 0x20, 0xe5, 0x1a, 0x40, 0x13, 0x7f, 0xe1, 0x53,
0x5c, 0xed, 0xfe, 0xb6, 0x45, 0xae, 0xed, 0x18, 0xf2, 0xa0, 0x47, 0x01, 0x32, 0x15, 0x86, 0x58,
0x0a, 0x2c, 0x4e, 0xde, 0xe3, 0xe5, 0x4e, 0xa3, 0xfe, 0x3d, 0x6c, 0x16, 0x2d, 0x98, 0x9c, 0xe8,
0x51, 0x80, 0x31, 0x12, 0xae, 0x01, 0xb8, 0xf8, 0x92, 0xa7, 0x3d, 0x0c, 0xf9, 0x6a, 0x58, 0x4c,
0xab, 0x68, 0xe1, 0x64, 0x44, 0xbb, 0x02, 0x44, 0x4b, 0xd8, 0x01, 0xb8, 0x59, 0xc1, 0xe3, 0xed,
0x7a, 0xff, 0xef, 0xf8, 0x86, 0x12, 0xd1, 0xe2, 0xc9, 0x88, 0x76, 0x05, 0xc8, 0x96, 0x6d, 0x97,
0x1b, 0x2e, 0x56, 0xf1, 0x1b, 0x36, 0x7a, 0xf9, 0x75, 0x1f, 0x5f, 0x86, 0x06, 0x82, 0x9d, 0xd1,
0xae, 0x00, 0x23, 0x24, 0x5b, 0x03, 0x68, 0x65, 0x09, 0x0f, 0x53, 0xe4, 0xb5, 0x92, 0x1b, 0xf9,
0x20, 0x34, 0x10, 0xec, 0x8c, 0x56, 0x05, 0x08, 0x97, 0xcc, 0x0b, 0xc8, 0xc1, 0xc7, 0x3c, 0xc2,
0x2a, 0x9f, 0xdf, 0xf8, 0x7a, 0x16, 0x89, 0x16, 0x53, 0x3e, 0xb4, 0x2a, 0x40, 0x26, 0x63, 0x44,
0x8b, 0xde, 0x86, 0x6a, 0x5e, 0xe7, 0x11, 0xb6, 0xf8, 0xb9, 0xaa, 0x96, 0xb7, 0x39, 0x2a, 0x5a,
0x54, 0xd9, 0xd0, 0xaa, 0x00, 0x23, 0x4c, 0x0d, 0xd7, 0xa0, 0x06, 0x37, 0x07, 0xf8, 0x03, 0x8f,
0xb3, 0x5f, 0xc1, 0xb5, 0xab, 0xf9, 0xa0, 0x83, 0x7d, 0xe0, 0x82, 0x47, 0x9b, 0x02, 0x84, 0x73,
0x85, 0x24, 0x4e, 0x8d, 0x0e, 0xfe, 0xc3, 0xcf, 0x78, 0x49, 0xe1, 0x8a, 0x7f, 0x1d, 0xf3, 0xd9,
0x29, 0x5a, 0xe4, 0xb3, 0x48, 0xb1, 0x12, 0xa0, 0x55, 0x01, 0x7a, 0x49, 0xb1, 0x06, 0xe0, 0xe6,
0x28, 0x2f, 0x31, 0x8b, 0xcf, 0x54, 0x2c, 0xf6, 0x6e, 0xe6, 0x6f, 0xd4, 0x8b, 0x16, 0x1c, 0x80,
0x44, 0x39, 0x76, 0x06, 0x68, 0x5b, 0x92, 0x2c, 0x90, 0xa0, 0x03, 0xa8, 0x67, 0x05, 0xaf, 0xf1,
0x25, 0xb5, 0xaa, 0xee, 0x6a, 0x61, 0x01, 0xe3, 0x98, 0x2a, 0x5a, 0x78, 0x20, 0xce, 0xba, 0x0a,
0x10, 0xc1, 0x65, 0x82, 0x3b, 0x80, 0x16, 0x76, 0xf2, 0x36, 0x0b, 0x39, 0xa8, 0xa1, 0x47, 0x3f,
0xca, 0x3c, 0x06, 0x70, 0x91, 0x50, 0xf9, 0x2d, 0x4e, 0x0e, 0x1b, 0x4d, 0x89, 0x06, 0xa8, 0x34,
0x66, 0xe0, 0x5e, 0xe6, 0x32, 0x42, 0x87, 0x23, 0x5a, 0x24, 0xb3, 0x0c, 0x3c, 0xc9, 0x58, 0x6b,
0x5a, 0x41, 0x57, 0xd1, 0x15, 0x09, 0xda, 0x5a, 0x80, 0xc1, 0xc2, 0xbc, 0x80, 0x9a, 0x29, 0xe6,
0x4b, 0xfe, 0xcd, 0x3a, 0x5d, 0x9b, 0x3d, 0x9a, 0x79, 0x87, 0x7e, 0xfc, 0xf8, 0x42, 0x3c, 0xc9,
0xa3, 0x33, 0xea, 0x15, 0x20, 0x82, 0x09, 0x86, 0xc5, 0xca, 0x50, 0x43, 0x1d, 0x3b, 0x59, 0xc4,
0x27, 0xec, 0x30, 0xc0, 0xbf, 0xaf, 0x82, 0x79, 0x64, 0x71, 0xa3, 0x1c, 0x5e, 0x79, 0x62, 0x51,
0xaf, 0x00, 0xdd, 0x02, 0xbe, 0x08, 0xdc, 0xc2, 0x31, 0x36, 0xb0, 0x98, 0xe5, 0xec, 0x37, 0xcc,
0xc3, 0x7f, 0x3f, 0x73, 0xe9, 0x26, 0xc5, 0x5c, 0x46, 0x30, 0xea, 0x15, 0x60, 0x98, 0x8a, 0xf3,
0xfb, 0xf4, 0xd2, 0x42, 0x29, 0x3b, 0x59, 0x41, 0x11, 0x3b, 0xa9, 0x30, 0xd4, 0x84, 0xe3, 0x66,
0x1d, 0xbf, 0x67, 0xae, 0xa2, 0xe3, 0x63, 0x83, 0x1a, 0xb5, 0x0a, 0x60, 0xa7, 0x50, 0xd1, 0xf9,
0x3d, 0x7a, 0x69, 0xa1, 0x94, 0x2d, 0x2c, 0x63, 0x2d, 0xbb, 0xa9, 0x36, 0xe5, 0x6c, 0x4d, 0x27,
0x5f, 0x91, 0xc4, 0xef, 0x15, 0x1f, 0x47, 0x17, 0xa4, 0xa8, 0x55, 0x80, 0x14, 0x46, 0x9b, 0x3c,
0x7f, 0x6d, 0xe6, 0x38, 0x5b, 0x58, 0xc6, 0x6a, 0x76, 0x53, 0x63, 0xaa, 0x13, 0x47, 0x0b, 0x1f,
0x12, 0xc9, 0xe3, 0x17, 0xb6, 0x0a, 0xa8, 0x55, 0x80, 0x0c, 0x13, 0xe3, 0x5c, 0x36, 0x53, 0xc6,
0x46, 0x96, 0xb3, 0x8a, 0x7d, 0x54, 0x05, 0x24, 0xaa, 0x47, 0x13, 0xef, 0xe2, 0xe6, 0x77, 0x17,
0xb2, 0x0a, 0xa8, 0x55, 0x80, 0x7e, 0x06, 0x46, 0xcb, 0xfa, 0x0e, 0x07, 0xc7, 0xd8, 0xc2, 0x4a,
0x56, 0x50, 0x6c, 0x70, 0x5f, 0xef, 0x8f, 0x26, 0xde, 0xc3, 0xcd, 0xe3, 0xaa, 0x8e, 0x87, 0x0e,
0x2a, 0xd4, 0x2a, 0x40, 0x8e, 0xc1, 0x36, 0xc0, 0x16, 0x8e, 0xb2, 0x9e, 0xa5, 0xac, 0xa6, 0x84,
0x2a, 0x21, 0x2b, 0x75, 0x4d, 0xbc, 0x4b, 0x1d, 0x4f, 0x48, 0xbc, 0xc5, 0xcd, 0x54, 0xd4, 0x2a,
0x40, 0xba, 0x61, 0x5b, 0x41, 0x5b, 0x39, 0xc2, 0x46, 0xbe, 0x66, 0x2d, 0xc5, 0xd4, 0x0a, 0x75,
0xd6, 0x6a, 0xe6, 0x63, 0xaa, 0x79, 0xc2, 0x4b, 0x8c, 0xe0, 0x20, 0x47, 0xad, 0x02, 0x18, 0xf1,
0x8d, 0xb6, 0x70, 0x94, 0x4d, 0x7c, 0xc5, 0x5a, 0xf6, 0x52, 0x2f, 0x85, 0x9f, 0x9e, 0x93, 0x6f,
0xf9, 0x09, 0x8f, 0x72, 0x93, 0xa4, 0x1b, 0xdd, 0x4c, 0x44, 0xad, 0x02, 0x94, 0xd2, 0xa4, 0x23,
0x1e, 0x48, 0x33, 0xc7, 0x59, 0xc7, 0x7f, 0x58, 0x49, 0x31, 0x0d, 0x52, 0x54, 0xfd, 0x39, 0xdc,
0x6c, 0x65, 0x36, 0xc5, 0xfc, 0x58, 0x96, 0xd0, 0x2d, 0xb2, 0x32, 0x9e, 0x63, 0x9a, 0x96, 0x3e,
0x1c, 0x94, 0xf0, 0x1e, 0x0f, 0x32, 0x94, 0x44, 0x59, 0x5c, 0x21, 0x3c, 0x10, 0xc3, 0xf7, 0x59,
0x4f, 0xeb, 0x85, 0xb4, 0x18, 0xa4, 0x96, 0x24, 0xe6, 0xab, 0x3c, 0x18, 0xda, 0x41, 0x09, 0xef,
0xf3, 0x53, 0x86, 0x19, 0x72, 0xe0, 0x82, 0xd9, 0xd8, 0x19, 0xce, 0x5b, 0xa6, 0x1c, 0x7d, 0x17,
0x24, 0x0a, 0x00, 0x97, 0xb0, 0x4b, 0x61, 0x11, 0x9b, 0x39, 0xc8, 0xfb, 0xcc, 0x62, 0x38, 0xf1,
0xa2, 0x85, 0x56, 0x45, 0x17, 0x1e, 0xe6, 0x68, 0x48, 0x01, 0xbc, 0x61, 0x67, 0xba, 0xdf, 0x6e,
0xa0, 0x91, 0x5d, 0xcc, 0xe7, 0x1e, 0x86, 0x4b, 0xe2, 0x39, 0xa8, 0x96, 0x08, 0x26, 0xb1, 0x4c,
0xc7, 0x81, 0xf1, 0x41, 0xad, 0x00, 0x10, 0xc1, 0x5d, 0x1c, 0xf2, 0x52, 0xac, 0x7a, 0x76, 0xf3,
0x16, 0x77, 0x93, 0x6f, 0xf9, 0xf1, 0x74, 0x1e, 0xff, 0x67, 0xd0, 0xb9, 0xa4, 0x41, 0xa7, 0x00,
0x10, 0xc1, 0x0d, 0x2c, 0x69, 0xd7, 0x53, 0xb6, 0x52, 0xc9, 0x0e, 0xde, 0xe0, 0x1e, 0x06, 0x59,
0xf4, 0xab, 0xef, 0x4c, 0x22, 0xf7, 0xb3, 0x57, 0xe5, 0x88, 0xc7, 0x72, 0x0a, 0xa0, 0x75, 0x44,
0x6e, 0x23, 0x93, 0x6b, 0x18, 0x4b, 0x0f, 0xec, 0x38, 0xa9, 0xa0, 0x98, 0xad, 0x6c, 0xa7, 0x54,
0x12, 0x8f, 0x5b, 0xa3, 0x08, 0xe7, 0x62, 0x7e, 0xc5, 0x15, 0xa6, 0xc4, 0x41, 0x5b, 0xc9, 0x54,
0x09, 0x03, 0xd7, 0xa8, 0x24, 0x9a, 0x74, 0xba, 0x92, 0x66, 0x42, 0x44, 0x7d, 0x79, 0xc8, 0xe1,
0x19, 0xca, 0x83, 0xb7, 0x05, 0x08, 0xe1, 0x9f, 0x58, 0xee, 0x64, 0xb3, 0xe1, 0xd6, 0x01, 0x49,
0x14, 0xe0, 0x02, 0xb4, 0x7e, 0xab, 0xa6, 0x85, 0xed, 0x6c, 0x20, 0x89, 0x5c, 0x43, 0xbb, 0x82,
0xe3, 0x2c, 0xe4, 0xb4, 0xe8, 0xa2, 0x85, 0x14, 0x40, 0x19, 0x6e, 0x8e, 0xb1, 0x8a, 0x06, 0xf2,
0x0c, 0x5c, 0x0c, 0xaf, 0xe4, 0x53, 0x19, 0xa2, 0x17, 0x86, 0x14, 0x40, 0x29, 0xa7, 0x59, 0x4f,
0x09, 0x3d, 0xe9, 0x6e, 0xd0, 0x3b, 0x3b, 0xc9, 0xfb, 0x21, 0x05, 0xb0, 0x16, 0x2d, 0xec, 0x62,
0x23, 0x31, 0xe4, 0x1a, 0x12, 0x1e, 0xbf, 0x9c, 0x85, 0x21, 0x05, 0xb0, 0x1a, 0x6e, 0xca, 0x58,
0x45, 0x15, 0xb9, 0x74, 0xd1, 0x3d, 0xef, 0x91, 0x44, 0x01, 0x42, 0xa8, 0x27, 0x8a, 0xeb, 0x58,
0x4c, 0x93, 0xce, 0x59, 0xc0, 0x36, 0xf2, 0x45, 0x17, 0x04, 0x42, 0x2d, 0x80, 0x16, 0x9c, 0x14,
0xb3, 0x8e, 0x30, 0x72, 0x75, 0xd9, 0x3c, 0x25, 0x69, 0x01, 0x42, 0x0a, 0xa0, 0x8d, 0x53, 0xac,
0xe1, 0x04, 0xd9, 0xa4, 0x6b, 0xee, 0x0a, 0x42, 0x0a, 0x60, 0x71, 0x1a, 0xd9, 0xc6, 0x76, 0x92,
0xc9, 0xd6, 0x78, 0xf2, 0x87, 0x24, 0x0a, 0x20, 0x45, 0xcc, 0x7a, 0x8b, 0xd2, 0xcc, 0x52, 0x0e,
0xb1, 0x8b, 0xbb, 0xe8, 0xa1, 0xe1, 0x6e, 0x67, 0x28, 0x72, 0x69, 0x70, 0x90, 0xc0, 0x1d, 0xac,
0xd3, 0x60, 0x28, 0x5e, 0xa5, 0x49, 0x6d, 0x42, 0x48, 0x48, 0x38, 0x85, 0xfc, 0x53, 0xb5, 0x1b,
0xd9, 0x32, 0x39, 0xdc, 0x4f, 0x43, 0x63, 0x00, 0xfd, 0xb8, 0xce, 0x1a, 0x8a, 0xfb, 0xa9, 0xf2,
0x7a, 0xdc, 0xc4, 0x87, 0x34, 0x89, 0x16, 0x3d, 0x84, 0x71, 0xc4, 0x70, 0x13, 0x45, 0xb4, 0x28,
0xfc, 0xfe, 0x5d, 0xcc, 0x93, 0x2a, 0xd2, 0x6a, 0x08, 0x03, 0xb0, 0x91, 0xcf, 0x2b, 0x54, 0x2b,
0x52, 0x80, 0x7a, 0x66, 0x04, 0xb1, 0x0f, 0xc5, 0x05, 0x4c, 0x2a, 0xb3, 0x28, 0x56, 0x64, 0x07,
0x2c, 0x10, 0x2d, 0x6a, 0x08, 0x73, 0x88, 0xe0, 0x0a, 0x96, 0xf8, 0xe9, 0x0a, 0x1c, 0x3c, 0x1d,
0xea, 0x00, 0x82, 0x99, 0x5c, 0xfe, 0xe4, 0x23, 0x10, 0x9d, 0x93, 0x8f, 0x4d, 0x8c, 0xb2, 0x10,
0x42, 0x0a, 0xe2, 0xf8, 0x3e, 0xcb, 0x3d, 0xb6, 0x03, 0x8d, 0xbc, 0xcb, 0xe0, 0x50, 0xff, 0x1f,
0xfc, 0xd8, 0xe8, 0xcd, 0x93, 0xec, 0xa1, 0xb9, 0x5d, 0xe5, 0x6f, 0xe4, 0xa7, 0x74, 0x17, 0x2d,
0x5a, 0x88, 0x40, 0x11, 0xc9, 0x28, 0xe6, 0xb2, 0x09, 0x07, 0x6e, 0xea, 0x58, 0xc6, 0x1c, 0x06,
0xca, 0x66, 0x79, 0xf9, 0x7f, 0x2e, 0x03, 0x18, 0xfe, 0x43, 0xbf, 0xeb, 0x10, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
};
#endif

View file

@ -27,17 +27,29 @@
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <inttypes.h>
#include "compile_date.h"
#include "board_api.h"
#include "uf2.h"
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
// ota0 partition size
static uint32_t _flash_size;
#define STATIC_ASSERT(_exp) _Static_assert(_exp, "static assert failed")
#define STR0(x) #x
#define STR(x) STR0(x)
#define UF2_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
#define UF2_DIV_CEIL(_v, _d) ( ((_v) / (_d)) + ((_v) % (_d) ? 1 : 0) )
typedef struct {
uint8_t JumpInstruction[3];
uint8_t OEMInfo[8];
@ -78,11 +90,15 @@ typedef struct {
} __attribute__((packed)) DirEntry;
STATIC_ASSERT(sizeof(DirEntry) == 32);
struct TextFile {
typedef struct FileContent {
char const name[11];
char const *content;
};
void const * content;
uint32_t size; // OK to use uint32_T b/c FAT32 limits filesize to (4GiB - 2)
// computing fields based on index and size
uint16_t cluster_start;
uint16_t cluster_end;
} FileContent_t;
//--------------------------------------------------------------------+
//
@ -97,13 +113,13 @@ struct TextFile {
#define BPB_MEDIA_DESCRIPTOR_BYTE (0xF8)
#define FAT_ENTRY_SIZE (2)
#define FAT_ENTRIES_PER_SECTOR (BPB_SECTOR_SIZE / FAT_ENTRY_SIZE)
#define FAT_END_OF_CHAIN (0xFFFF)
// NOTE: MS specification explicitly allows FAT to be larger than necessary
#define TOTAL_CLUSTERS_ROUND_UP ( (BPB_TOTAL_SECTORS / BPB_SECTORS_PER_CLUSTER) + \
((BPB_TOTAL_SECTORS % BPB_SECTORS_PER_CLUSTER) ? 1 : 0))
#define BPB_SECTORS_PER_FAT ( (TOTAL_CLUSTERS_ROUND_UP / FAT_ENTRIES_PER_SECTOR) + \
((TOTAL_CLUSTERS_ROUND_UP % FAT_ENTRIES_PER_SECTOR) ? 1 : 0))
#define TOTAL_CLUSTERS_ROUND_UP UF2_DIV_CEIL(BPB_TOTAL_SECTORS, BPB_SECTORS_PER_CLUSTER)
#define BPB_SECTORS_PER_FAT UF2_DIV_CEIL(TOTAL_CLUSTERS_ROUND_UP, FAT_ENTRIES_PER_SECTOR)
#define DIRENTRIES_PER_SECTOR (BPB_SECTOR_SIZE/sizeof(DirEntry))
#define ROOT_DIR_SECTOR_COUNT (BPB_ROOT_DIR_ENTRIES/DIRENTRIES_PER_SECTOR)
#define ROOT_DIR_SECTOR_COUNT UF2_DIV_CEIL(BPB_ROOT_DIR_ENTRIES, DIRENTRIES_PER_SECTOR)
#define BPB_BYTES_PER_CLUSTER (BPB_SECTOR_SIZE * BPB_SECTORS_PER_CLUSTER)
STATIC_ASSERT((BPB_SECTORS_PER_CLUSTER & (BPB_SECTORS_PER_CLUSTER-1)) == 0); // sectors per cluster must be power of two
@ -115,12 +131,12 @@ STATIC_ASSERT(BPB_ROOT_DIR_ENTRIES % DIRENTRIES_PER_SECTOR == 0); // FAT
STATIC_ASSERT(BPB_BYTES_PER_CLUSTER <= (32*1024)); // FAT requirement (64k+ has known compatibility problems)
STATIC_ASSERT(FAT_ENTRIES_PER_SECTOR == 256); // FAT requirement
#define STR0(x) #x
#define STR(x) STR0(x)
#define UF2_FIRMWARE_BYTES_PER_SECTOR 256
#define UF2_SECTOR_COUNT (_flash_size / UF2_FIRMWARE_BYTES_PER_SECTOR)
#define UF2_BYTE_COUNT (UF2_SECTOR_COUNT * BPB_SECTOR_SIZE) // always a multiple of sector size, per UF2 spec
#define UF2_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
char infoUf2File[] =
const char infoUf2File[] =
"TinyUF2 Bootloader " UF2_VERSION "\r\n"
"Model: " UF2_PRODUCT_NAME "\r\n"
"Board-ID: " UF2_BOARD_ID "\r\n"
@ -136,23 +152,30 @@ const char indexFile[] =
"</body>"
"</html>\n";
static struct TextFile const info[] = {
{.name = "INFO_UF2TXT", .content = infoUf2File},
{.name = "INDEX HTM", .content = indexFile},
#ifdef TINYUF2_FAVICON_HEADER
#include TINYUF2_FAVICON_HEADER
const char autorunFile[] = "[Autorun]\r\nIcon=FAVICON.ICO\r\n";
#endif
// size of CURRENT.UF2:
static FileContent_t info[] = {
{.name = "INFO_UF2TXT", .content = infoUf2File , .size = sizeof(infoUf2File) - 1},
{.name = "INDEX HTM", .content = indexFile , .size = sizeof(indexFile ) - 1},
#ifdef TINYUF2_FAVICON_HEADER
{.name = "AUTORUN INF", .content = autorunFile , .size = sizeof(autorunFile) - 1},
{.name = "FAVICON ICO", .content = favicon_data, .size = favicon_len },
#endif
// current.uf2 must be the last element and its content must be NULL
{.name = "CURRENT UF2", .content = NULL},
{.name = "CURRENT UF2", .content = NULL , .size = 0 },
};
STATIC_ASSERT(UF2_ARRAY_SIZE(infoUf2File) < BPB_BYTES_PER_CLUSTER); // GhostFAT requires files to fit in one cluster
STATIC_ASSERT(UF2_ARRAY_SIZE(indexFile) < BPB_BYTES_PER_CLUSTER); // GhostFAT requires files to fit in one cluster
#define NUM_FILES (UF2_ARRAY_SIZE(info))
#define NUM_DIRENTRIES (NUM_FILES + 1) // Code adds volume label as first root directory entry
#define REQUIRED_ROOT_DIRECTORY_SECTORS ( ((NUM_DIRENTRIES+1) / DIRENTRIES_PER_SECTOR) + \
(((NUM_DIRENTRIES+1) % DIRENTRIES_PER_SECTOR) ? 1 : 0))
STATIC_ASSERT(ROOT_DIR_SECTOR_COUNT >= REQUIRED_ROOT_DIRECTORY_SECTORS); // FAT requirement -- Ensures BPB reserves sufficient entries for all files
STATIC_ASSERT(NUM_DIRENTRIES < (DIRENTRIES_PER_SECTOR * ROOT_DIR_SECTOR_COUNT)); // FAT requirement -- end directory with unused entry
STATIC_ASSERT(NUM_DIRENTRIES < BPB_ROOT_DIR_ENTRIES); // FAT requirement -- Ensures BPB reserves sufficient entries for all files
enum {
NUM_FILES = sizeof(info) / sizeof(info[0]),
FID_UF2 = NUM_FILES-1,
NUM_DIRENTRIES = NUM_FILES + 1 // including volume label as first root directory entry
};
STATIC_ASSERT(NUM_DIRENTRIES < BPB_ROOT_DIR_ENTRIES); // FAT requirement -- Ensures BPB reserves sufficient entries for all files
STATIC_ASSERT(NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR); // GhostFAT bug workaround -- else, code overflows buffer
#define NUM_SECTORS_IN_DATA_REGION (BPB_TOTAL_SECTORS - BPB_RESERVED_SECTORS - (BPB_NUMBER_OF_FATS * BPB_SECTORS_PER_FAT) - ROOT_DIR_SECTOR_COUNT)
@ -165,18 +188,6 @@ STATIC_ASSERT( CLUSTER_COUNT >= 0x0FF5 && CLUSTER_COUNT < 0xFFF5 );
// So, avoid being within 32 of those limits for even greater compatibility.
STATIC_ASSERT( CLUSTER_COUNT >= 0x1015 && CLUSTER_COUNT < 0xFFD5 );
#define UF2_FIRMWARE_BYTES_PER_SECTOR 256
#define UF2_SECTOR_COUNT (_flash_size / UF2_FIRMWARE_BYTES_PER_SECTOR)
#define UF2_CLUSTER_COUNT ( (UF2_SECTOR_COUNT / BPB_SECTORS_PER_CLUSTER) + \
((UF2_SECTOR_COUNT % BPB_SECTORS_PER_CLUSTER) ? 1 : 0))
#define UF2_BYTE_COUNT (UF2_SECTOR_COUNT * BPB_SECTOR_SIZE) // always a multiple of sector size, per UF2 spec
// NOTE: First cluster number of the UF2 file calculation is:
// Starts with NUM_FILES because each non-UF2 file is limited to a single cluster in size
// -1 because NUM_FILES includes UF2 entry is included in that array, which is zero-indexed
// +2 because FAT decided first data sector would be in cluster number 2, rather than zero
#define UF2_FIRST_CLUSTER_NUMBER ((NUM_FILES -1) + 2)
#define UF2_LAST_CLUSTER_NUMBER (UF2_FIRST_CLUSTER_NUMBER + UF2_CLUSTER_COUNT - 1)
#define FS_START_FAT0_SECTOR BPB_RESERVED_SECTORS
#define FS_START_FAT1_SECTOR (FS_START_FAT0_SECTOR + BPB_SECTORS_PER_FAT)
@ -208,9 +219,6 @@ static FAT_BootBlock const BootBlock = {
.FilesystemIdentifier = "FAT16 ",
};
// ota0 partition size
static uint32_t _flash_size;
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@ -224,10 +232,56 @@ static inline bool is_uf2_block (UF2_Block const *bl)
!(bl->flags & UF2_FLAG_NOFLASH);
}
// cache the cluster start offset for each file
// this allows more flexible algorithms w/o O(n) time
static void init_starting_clusters(void)
{
// +2 because FAT decided first data sector would be in cluster number 2, rather than zero
uint16_t start_cluster = 2;
for (uint16_t i = 0; i < NUM_FILES; i++)
{
info[i].cluster_start = start_cluster;
info[i].cluster_end = start_cluster + UF2_DIV_CEIL(info[i].size, BPB_SECTOR_SIZE*BPB_SECTORS_PER_CLUSTER) - 1;
start_cluster = info[i].cluster_end + 1;
}
return;
}
// get file index for file that uses the cluster
// if cluster is past last file, returns ( NUM_FILES-1 ).
//
// Caller must still check if a particular *sector*
// contains data from the file's contents, as there
// are often padding sectors, including all the unused
// sectors past the end of the media.
static uint32_t info_index_of(uint32_t cluster)
{
// default results for invalid requests is the index of the last file (CURRENT.UF2)
if (cluster >= 0xFFF0) return FID_UF2;
for (uint32_t i = 0; i < NUM_FILES; i++)
{
if ( (info[i].cluster_start <= cluster) && (cluster <= info[i].cluster_end) )
{
return i;
}
}
return FID_UF2;
}
void uf2_init(void)
{
// TODO maybe limit to application size only if possible board_flash_app_size()
_flash_size = board_flash_size();
// update CURRENT.UF2 file size
info[FID_UF2].size = UF2_BYTE_COUNT;
init_starting_clusters();
}
/*------------------------------------------------------------------*/
@ -253,105 +307,136 @@ void uf2_read_block (uint32_t block_no, uint8_t *data)
if ( block_no == 0 )
{
// Requested boot block
// Request was for the Boot block
memcpy(data, &BootBlock, sizeof(BootBlock));
data[510] = 0x55; // Always at offsets 510/511, even when BPB_SECTOR_SIZE is larger
data[511] = 0xaa; // Always at offsets 510/511, even when BPB_SECTOR_SIZE is larger
}
else if ( block_no < FS_START_ROOTDIR_SECTOR )
{
// Requested FAT table sector
// Request was for a FAT table sector
sectionRelativeSector -= FS_START_FAT0_SECTOR;
// second FAT is same as the first...
if ( sectionRelativeSector >= BPB_SECTORS_PER_FAT ) sectionRelativeSector -= BPB_SECTORS_PER_FAT;
if ( sectionRelativeSector == 0 )
// second FAT is same as the first... use sectionRelativeSector to write data
if ( sectionRelativeSector >= BPB_SECTORS_PER_FAT )
{
// first FAT entry must match BPB MediaDescriptor
data[0] = BPB_MEDIA_DESCRIPTOR_BYTE;
// WARNING -- code presumes only one NULL .content for .UF2 file
// and all non-NULL .content fit in one sector
// and requires it be the last element of the array
uint32_t const end = (NUM_FILES * FAT_ENTRY_SIZE) + (2 * FAT_ENTRY_SIZE);
for ( uint32_t i = 1; i < end; ++i ) data[i] = 0xff;
sectionRelativeSector -= BPB_SECTORS_PER_FAT;
}
// Generate the FAT chain for the firmware "file"
for ( uint32_t i = 0; i < FAT_ENTRIES_PER_SECTOR; ++i )
uint16_t* data16 = (uint16_t*) (void*) data;
uint32_t sectorFirstCluster = sectionRelativeSector * FAT_ENTRIES_PER_SECTOR;
uint32_t firstUnusedCluster = info[FID_UF2].cluster_end + 1;
// OPTIMIZATION:
// Because all files are contiguous, the FAT CHAIN entries
// are all set to (cluster+1) to point to the next cluster.
// All clusters past the last used cluster of the last file
// are set to zero.
//
// EXCEPTIONS:
// 1. Clusters 0 and 1 require special handling
// 2. Final cluster of each file must be set to END_OF_CHAIN
//
// Set default FAT values first.
for (uint16_t i = 0; i < FAT_ENTRIES_PER_SECTOR; i++)
{
// `i` here is the sector-relative array index into this sector of the FAT
// `v` here is the overall array index into the FAT, which corresponds to
// where the next cluster in the chain is stored.
uint32_t v = (sectionRelativeSector * FAT_ENTRIES_PER_SECTOR) + i;
if ( UF2_FIRST_CLUSTER_NUMBER <= v && v < UF2_LAST_CLUSTER_NUMBER )
uint32_t cluster = i + sectorFirstCluster;
if (cluster >= firstUnusedCluster)
{
((uint16_t*) (void*) data)[i] = v + 1; // contiguous file, so point to next cluster number
data16[i] = 0;
}
else if ( v == UF2_LAST_CLUSTER_NUMBER)
else
{
((uint16_t*) (void*) data)[i] = 0xffff; // end of file marker in FAT16
data16[i] = cluster + 1;
}
}
// Exception #1: clusters 0 and 1 need special handling
if (sectionRelativeSector == 0)
{
data[0] = BPB_MEDIA_DESCRIPTOR_BYTE;
data[1] = 0xff;
data16[1] = FAT_END_OF_CHAIN; // cluster 1 is reserved
}
// Exception #2: the final cluster of each file must be set to END_OF_CHAIN
for (uint32_t i = 0; i < NUM_FILES; i++)
{
uint32_t lastClusterOfFile = info[i].cluster_end;
if (lastClusterOfFile >= sectorFirstCluster)
{
uint32_t idx = lastClusterOfFile - sectorFirstCluster;
if (idx < FAT_ENTRIES_PER_SECTOR)
{
// that last cluster of the file is in this sector
data16[idx] = FAT_END_OF_CHAIN;
}
}
}
}
else if ( block_no < FS_START_CLUSTERS_SECTOR )
{
// Requested root directory sector
// Request was for a (root) directory sector .. root because not supporting subdirectories (yet)
sectionRelativeSector -= FS_START_ROOTDIR_SECTOR;
DirEntry *d = (void*) data; // pointer to next free DirEntry this sector
int remainingEntries = DIRENTRIES_PER_SECTOR; // remaining count of DirEntries this sector
uint32_t startingFileIndex;
if ( sectionRelativeSector == 0 )
{
// volume label first
// volume label is first directory entry
padded_memcpy(d->name, (char const*) BootBlock.VolumeLabel, 11);
d->attrs = 0x28;
d++;
remainingEntries--;
}
uint32_t startingFileIndex =
(sectionRelativeSector == 0) ?
0 :
(DIRENTRIES_PER_SECTOR * sectionRelativeSector) - 1; // -1 to account for volume label in first sector
startingFileIndex = 0;
}else
{
// -1 to account for volume label in first sector
startingFileIndex = DIRENTRIES_PER_SECTOR * sectionRelativeSector - 1;
}
for ( uint32_t fileIndex = startingFileIndex;
remainingEntries > 0 && fileIndex < NUM_FILES; // while space remains in buffer and more files to add...
fileIndex++, d++ )
{
// WARNING -- code presumes all files take exactly one directory entry (no long file names!)
// WARNING -- code presumes all but last file take exactly one sector
// Using the above two presumptions, can convert from file index to starting cluster number
// by simply adding two (because first data cluster has cluster number of 2 in FAT)
uint32_t startCluster = fileIndex + 2;
uint32_t const startCluster = info[fileIndex].cluster_start;
struct TextFile const *inf = &info[fileIndex];
FileContent_t const *inf = &info[fileIndex];
padded_memcpy(d->name, inf->name, 11);
d->createTimeFine = COMPILE_SECONDS_INT % 2 * 100;
d->createTime = COMPILE_DOS_TIME;
d->createDate = COMPILE_DOS_DATE;
d->lastAccessDate = COMPILE_DOS_DATE;
d->createTimeFine = COMPILE_SECONDS_INT % 2 * 100;
d->createTime = COMPILE_DOS_TIME;
d->createDate = COMPILE_DOS_DATE;
d->lastAccessDate = COMPILE_DOS_DATE;
d->highStartCluster = startCluster >> 16;
d->updateTime = COMPILE_DOS_TIME;
d->updateDate = COMPILE_DOS_DATE;
d->startCluster = startCluster & 0xFFFF;
d->size = (inf->content ? strlen(inf->content) : UF2_BYTE_COUNT);
d->updateTime = COMPILE_DOS_TIME;
d->updateDate = COMPILE_DOS_DATE;
d->startCluster = startCluster & 0xFFFF;
d->size = (inf->content ? inf->size : UF2_BYTE_COUNT);
}
}
else if ( block_no < BPB_TOTAL_SECTORS )
{
// Request was to read from the data area (files, unused space, ...)
sectionRelativeSector -= FS_START_CLUSTERS_SECTOR;
uint32_t sectionRelativeClusterIndex = sectionRelativeSector / BPB_SECTORS_PER_CLUSTER;
if ( sectionRelativeClusterIndex < (NUM_FILES - 1) )
// plus 2 for first data cluster offset
uint32_t fid = info_index_of(2 + sectionRelativeSector / BPB_SECTORS_PER_CLUSTER);
FileContent_t const * inf = &info[fid];
uint32_t fileRelativeSector = sectionRelativeSector - (info[fid].cluster_start-2) * BPB_SECTORS_PER_CLUSTER;
if ( fid != FID_UF2 )
{
// WARNING -- code presumes first data cluster == first file, second data cluster == second file, etc.
struct TextFile const * inf = &info[ sectionRelativeSector / BPB_SECTORS_PER_CLUSTER ];
size_t fileContentStartOffset = (sectionRelativeSector % BPB_SECTORS_PER_CLUSTER) * BPB_SECTOR_SIZE;
size_t fileContentLength = strlen(inf->content);
// Handle all files other than CURRENT.UF2
size_t fileContentStartOffset = fileRelativeSector * BPB_SECTOR_SIZE;
size_t fileContentLength = inf->size;
// nothing to copy if already past the end of the file (only when >1 sector per cluster)
if (fileContentLength > fileContentStartOffset) {
@ -368,16 +453,15 @@ void uf2_read_block (uint32_t block_no, uint8_t *data)
}
else
{
// generate the UF2 file data on-the-fly
sectionRelativeSector -= (NUM_FILES - 1) * BPB_SECTORS_PER_CLUSTER;
uint32_t addr = BOARD_FLASH_APP_START + (sectionRelativeSector * UF2_FIRMWARE_BYTES_PER_SECTOR);
// CURRENT.UF2: generate data on-the-fly
uint32_t addr = BOARD_FLASH_APP_START + (fileRelativeSector * UF2_FIRMWARE_BYTES_PER_SECTOR);
if ( addr < _flash_size ) // TODO abstract this out
{
UF2_Block *bl = (void*) data;
bl->magicStart0 = UF2_MAGIC_START0;
bl->magicStart1 = UF2_MAGIC_START1;
bl->magicEnd = UF2_MAGIC_END;
bl->blockNo = sectionRelativeSector;
bl->blockNo = fileRelativeSector;
bl->numBlocks = UF2_SECTOR_COUNT;
bl->targetAddr = addr;
bl->payloadSize = UF2_FIRMWARE_BYTES_PER_SECTOR;

View file

@ -48,11 +48,13 @@ SOFTWARE.
#ifndef CFG_UF2_FLASH_SIZE
#define CFG_UF2_FLASH_SIZE (4*1024*1024)
#endif
// Number of 512-byte blocks in the exposed filesystem, default is just under 32MB
// The filesystem needs space for the current file, text files, uploaded file, and FAT
#ifndef CFG_UF2_NUM_BLOCKS
#define CFG_UF2_NUM_BLOCKS (0x10109)
#endif
// Sectors per FAT cluster, must be increased proportionally for larger filesystems
#ifndef CFG_UF2_SECTORS_PER_CLUSTER
#define CFG_UF2_SECTORS_PER_CLUSTER (1)