diff --git a/Makefile b/Makefile index 0091c292..e067a3c6 100644 --- a/Makefile +++ b/Makefile @@ -49,12 +49,16 @@ firmware_clean: .PHONY: bootloader_flash bootloader_flash: +ifeq ($(FORCE), '1') rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true +endif $(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) flash .PHONY: firmware_flash firmware_flash: +ifeq ($(FORCE), '1') rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true +endif $(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash .PHONY: flash_radio @@ -73,8 +77,16 @@ flash_radio_fus: @echo "================ JUST DON'T ================" @echo -.PHONY: +.PHONY: flash_radio_fus_please_i_m_not_going_to_complain flash_radio_fus_please_i_m_not_going_to_complain: $(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin $(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin $(PROJECT_ROOT)/scripts/ob.py set + +FORMAT_SOURCES = $(shell find applications bootloader core -iname "*.h" -o -iname "*.c" -o -iname "*.cpp") + +.PHONY: format +format: + @echo "Formatting sources with clang-format" + @clang-format -style=file -i $(FORMAT_SOURCES) + diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index 2ea1599b..aa999e36 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -1,5 +1,6 @@ #include "bt_i.h" #include "battery_service.h" +#include "bt_keys_storage.h" #define BT_SERVICE_TAG "BT" @@ -69,8 +70,8 @@ Bt* bt_alloc() { // Power bt->power = furi_record_open("power"); - PubSub* power_pubsub = power_get_pubsub(bt->power); - subscribe_pubsub(power_pubsub, bt_battery_level_changed_callback, bt); + FuriPubSub* power_pubsub = power_get_pubsub(bt->power); + furi_pubsub_subscribe(power_pubsub, bt_battery_level_changed_callback, bt); // RPC bt->rpc = furi_record_open("rpc"); @@ -161,6 +162,14 @@ static void bt_on_gap_event_callback(BleEvent event, void* context) { } } +static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void* context) { + furi_assert(context); + Bt* bt = context; + FURI_LOG_I(BT_SERVICE_TAG, "Changed addr start: %08lX, size changed: %d", addr, size); + BtMessage message = {.type = BtMessageTypeKeysStorageUpdated}; + furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); +} + static void bt_statusbar_update(Bt* bt) { if(bt->status == BtStatusAdvertising) { view_port_set_width(bt->statusbar_view_port, icon_get_width(&I_Bluetooth_5x8)); @@ -177,7 +186,12 @@ int32_t bt_srv() { Bt* bt = bt_alloc(); furi_record_create("bt", bt); - if(!furi_hal_bt_wait_startup()) { + // Read keys + if(!bt_load_key_storage(bt)) { + FURI_LOG_W(BT_SERVICE_TAG, "Failed to load saved bonding keys"); + } + // Start 2nd core + if(!furi_hal_bt_start_core2()) { FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed"); } else { view_port_enabled_set(bt->statusbar_view_port, true); @@ -190,6 +204,8 @@ int32_t bt_srv() { FURI_LOG_E(BT_SERVICE_TAG, "BT App start failed"); } } + furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); + // Update statusbar bt_statusbar_update(bt); @@ -207,6 +223,8 @@ int32_t bt_srv() { } else if(message.type == BtMessageTypePinCodeShow) { // Display PIN code bt_pin_code_show_event_handler(bt, message.data.pin_code); + } else if(message.type == BtMessageTypeKeysStorageUpdated) { + bt_save_key_storage(bt); } } return 0; diff --git a/applications/bt/bt_service/bt_i.h b/applications/bt/bt_service/bt_i.h index 0588378e..3921a4c5 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/bt/bt_service/bt_i.h @@ -25,6 +25,7 @@ typedef enum { BtMessageTypeUpdateStatusbar, BtMessageTypeUpdateBatteryLevel, BtMessageTypePinCodeShow, + BtMessageTypeKeysStorageUpdated, } BtMessageType; typedef union { @@ -38,6 +39,8 @@ typedef struct { } BtMessage; struct Bt { + uint8_t* bt_keys_addr_start; + uint16_t bt_keys_size; BtSettings bt_settings; BtStatus status; osMessageQueueId_t message_queue; diff --git a/applications/bt/bt_service/bt_keys_storage.c b/applications/bt/bt_service/bt_keys_storage.c new file mode 100644 index 00000000..25c74882 --- /dev/null +++ b/applications/bt/bt_service/bt_keys_storage.c @@ -0,0 +1,41 @@ +#include "bt_keys_storage.h" +#include +#include + +#define BT_KEYS_STORAGE_TAG "bt keys storage" +#define BT_KEYS_STORAGE_PATH "/int/bt.keys" + +bool bt_load_key_storage(Bt* bt) { + furi_assert(bt); + + bool file_loaded = false; + furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size); + + FileWorker* file_worker = file_worker_alloc(true); + if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + furi_hal_bt_nvm_sram_sem_acquire(); + if(file_worker_read(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { + file_loaded = true; + } + furi_hal_bt_nvm_sram_sem_release(); + } + file_worker_free(file_worker); + return file_loaded; +} + +bool bt_save_key_storage(Bt* bt) { + furi_assert(bt); + furi_assert(bt->bt_keys_addr_start); + + bool file_saved = false; + FileWorker* file_worker = file_worker_alloc(true); + if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { + furi_hal_bt_nvm_sram_sem_acquire(); + if(file_worker_write(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { + file_saved = true; + } + furi_hal_bt_nvm_sram_sem_release(); + } + file_worker_free(file_worker); + return file_saved; +} diff --git a/applications/bt/bt_service/bt_keys_storage.h b/applications/bt/bt_service/bt_keys_storage.h new file mode 100644 index 00000000..4b09d7f2 --- /dev/null +++ b/applications/bt/bt_service/bt_keys_storage.h @@ -0,0 +1,7 @@ +#pragma once + +#include "bt_i.h" + +bool bt_load_key_storage(Bt* bt); + +bool bt_save_key_storage(Bt* bt); diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index e4053c4c..1a9f4a6d 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -350,7 +350,7 @@ void cli_command_gpio_set(Cli* cli, string_t args, void* context) { "PA4", "PA6", "PA7", -#ifdef DEBUG +#ifdef FURI_DEBUG "PA0", "PB7", "PB8", @@ -366,7 +366,7 @@ void cli_command_gpio_set(Cli* cli, string_t args, void* context) { {.port = GPIOA, .pin = LL_GPIO_PIN_4}, {.port = GPIOA, .pin = LL_GPIO_PIN_6}, {.port = GPIOA, .pin = LL_GPIO_PIN_7}, -#ifdef DEBUG +#ifdef FURI_DEBUG {.port = GPIOA, .pin = LL_GPIO_PIN_0}, // IR_RX (PA0) {.port = GPIOB, .pin = LL_GPIO_PIN_7}, // UART RX (PB7) {.port = GPIOB, .pin = LL_GPIO_PIN_8}, // SPEAKER (PB8) @@ -411,7 +411,7 @@ void cli_command_gpio_set(Cli* cli, string_t args, void* context) { LL_GPIO_SetPinOutputType(gpio[num].port, gpio[num].pin, LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_ResetOutputPin(gpio[num].port, gpio[num].pin); } else if(!string_cmp(args, "1")) { -#ifdef DEBUG +#ifdef FURI_DEBUG if(num == 8) { // PA0 printf( "Setting PA0 pin HIGH with TSOP connected can damage IR receiver. Are you sure you want to continue? (y/n)?\r\n"); diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index aa9b4ed5..5ae97951 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -1,4 +1,5 @@ #include "desktop_i.h" +#include static void desktop_lock_icon_callback(Canvas* canvas, void* context) { furi_assert(canvas); @@ -117,9 +118,22 @@ static bool desktop_is_first_start() { int32_t desktop_srv(void* p) { Desktop* desktop = desktop_alloc(); + bool loaded = LOAD_DESKTOP_SETTINGS(&desktop->settings); + if(!loaded) { + furi_hal_lock_set(false); + memset(&desktop->settings, 0, sizeof(desktop->settings)); + SAVE_DESKTOP_SETTINGS(&desktop->settings); + } scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); + if(furi_hal_lock_get()) { + furi_hal_usb_disable(); + scene_manager_set_scene_state( + desktop->scene_manager, DesktopSceneLocked, DesktopLockedWithPin); + scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); + } + if(desktop_is_first_start()) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); } diff --git a/applications/desktop/desktop_settings/desktop_settings.c b/applications/desktop/desktop_settings/desktop_settings.c deleted file mode 100644 index 5e170a09..00000000 --- a/applications/desktop/desktop_settings/desktop_settings.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include "desktop_settings.h" - -#define DESKTOP_SETTINGS_TAG "Desktop settings" -#define DESKTOP_SETTINGS_PATH "/int/desktop.settings" - -bool desktop_settings_load(DesktopSettings* desktop_settings) { - furi_assert(desktop_settings); - bool file_loaded = false; - DesktopSettings settings = {}; - - FURI_LOG_I(DESKTOP_SETTINGS_TAG, "Loading settings from \"%s\"", DESKTOP_SETTINGS_PATH); - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open(file_worker, DESKTOP_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - if(file_worker_read(file_worker, &settings, sizeof(settings))) { - file_loaded = true; - } - } - file_worker_free(file_worker); - - if(file_loaded) { - if(settings.version != DESKTOP_SETTINGS_VER) { - FURI_LOG_E(DESKTOP_SETTINGS_TAG, "Settings version mismatch"); - } else { - osKernelLock(); - *desktop_settings = settings; - osKernelUnlock(); - } - } else { - FURI_LOG_E(DESKTOP_SETTINGS_TAG, "Settings load failed"); - } - return file_loaded; -} - -bool desktop_settings_save(DesktopSettings* desktop_settings) { - furi_assert(desktop_settings); - bool result = false; - - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open(file_worker, DESKTOP_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { - if(file_worker_write(file_worker, desktop_settings, sizeof(DesktopSettings))) { - FURI_LOG_I(DESKTOP_SETTINGS_TAG, "Settings saved to \"%s\"", DESKTOP_SETTINGS_PATH); - result = true; - } - } - file_worker_free(file_worker); - return result; -} diff --git a/applications/desktop/desktop_settings/desktop_settings.h b/applications/desktop/desktop_settings/desktop_settings.h index c8f324a1..27ded715 100644 --- a/applications/desktop/desktop_settings/desktop_settings.h +++ b/applications/desktop/desktop_settings/desktop_settings.h @@ -2,23 +2,35 @@ #include #include +#include #define DESKTOP_SETTINGS_VER (1) +#define DESKTOP_SETTINGS_PATH "/int/desktop.settings" +#define DESKTOP_SETTINGS_MAGIC (0x17) #define PIN_MAX_LENGTH 12 +#define SAVE_DESKTOP_SETTINGS(x) \ + saved_struct_save( \ + DESKTOP_SETTINGS_PATH, \ + (x), \ + sizeof(DesktopSettings), \ + DESKTOP_SETTINGS_MAGIC, \ + DESKTOP_SETTINGS_VER) + +#define LOAD_DESKTOP_SETTINGS(x) \ + saved_struct_load( \ + DESKTOP_SETTINGS_PATH, \ + (x), \ + sizeof(DesktopSettings), \ + DESKTOP_SETTINGS_MAGIC, \ + DESKTOP_SETTINGS_VER) + typedef struct { uint8_t length; uint8_t data[PIN_MAX_LENGTH]; } PinCode; typedef struct { - uint8_t version; uint16_t favorite; - PinCode pincode; - bool locked; } DesktopSettings; - -bool desktop_settings_load(DesktopSettings* desktop_settings); - -bool desktop_settings_save(DesktopSettings* desktop_settings); diff --git a/applications/desktop/desktop_settings/desktop_settings_app.c b/applications/desktop/desktop_settings/desktop_settings_app.c index e284ff80..c8a5f2b7 100644 --- a/applications/desktop/desktop_settings/desktop_settings_app.c +++ b/applications/desktop/desktop_settings/desktop_settings_app.c @@ -15,9 +15,6 @@ static bool desktop_settings_back_event_callback(void* context) { DesktopSettingsApp* desktop_settings_app_alloc() { DesktopSettingsApp* app = furi_alloc(sizeof(DesktopSettingsApp)); - app->settings.version = DESKTOP_SETTINGS_VER; - desktop_settings_load(&app->settings); - app->gui = furi_record_open("gui"); app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app); @@ -62,8 +59,8 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { extern int32_t desktop_settings_app(void* p) { DesktopSettingsApp* app = desktop_settings_app_alloc(); + LOAD_DESKTOP_SETTINGS(&app->settings); view_dispatcher_run(app->view_dispatcher); - desktop_settings_save(&app->settings); desktop_settings_app_free(app); return 0; } diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c index 1fead1f7..0b9bb580 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -1,5 +1,6 @@ #include "../desktop_settings_app.h" #include "applications.h" +#include "desktop/desktop_settings/desktop_settings.h" static void desktop_settings_scene_favorite_submenu_callback(void* context, uint32_t index) { DesktopSettingsApp* app = context; @@ -43,5 +44,6 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e void desktop_settings_scene_favorite_on_exit(void* context) { DesktopSettingsApp* app = context; + SAVE_DESKTOP_SETTINGS(&app->settings); submenu_clean(app->submenu); } diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c index d809f999..70b059a4 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c @@ -1,4 +1,5 @@ #include "../desktop_settings_app.h" +#include "desktop/desktop_settings/desktop_settings.h" #define SCENE_EXIT_EVENT (0U) @@ -57,6 +58,7 @@ bool desktop_settings_scene_pincode_input_on_event(void* context, SceneManagerEv void desktop_settings_scene_pincode_input_on_exit(void* context) { DesktopSettingsApp* app = context; + SAVE_DESKTOP_SETTINGS(&app->settings); code_input_set_result_callback(app->code_input, NULL, NULL, NULL, NULL, NULL, 0); code_input_set_header_text(app->code_input, ""); } diff --git a/applications/desktop/scenes/desktop_scene_lock_menu.c b/applications/desktop/scenes/desktop_scene_lock_menu.c index 46561e47..8a73739f 100644 --- a/applications/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/desktop/scenes/desktop_scene_lock_menu.c @@ -1,5 +1,8 @@ #include "../desktop_i.h" #include "../views/desktop_lock_menu.h" +#include +#include +#include void desktop_scene_lock_menu_callback(DesktopLockMenuEvent event, void* context) { Desktop* desktop = (Desktop*)context; @@ -9,7 +12,7 @@ void desktop_scene_lock_menu_callback(DesktopLockMenuEvent event, void* context) void desktop_scene_lock_menu_on_enter(void* context) { Desktop* desktop = (Desktop*)context; - desktop_settings_load(&desktop->settings); + LOAD_DESKTOP_SETTINGS(&desktop->settings); desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pincode.length > 0); @@ -29,10 +32,9 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case DesktopLockMenuEventPinLock: - if(desktop->settings.pincode.length > 0) { - desktop->settings.locked = true; - desktop_settings_save(&desktop->settings); + furi_hal_lock_set(true); + furi_hal_usb_disable(); scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, DesktopLockedWithPin); scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); @@ -43,10 +45,10 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case DesktopLockMenuEventExit: - scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); + scene_manager_search_and_switch_to_previous_scene( + desktop->scene_manager, DesktopSceneMain); consumed = true; break; - default: break; } diff --git a/applications/desktop/scenes/desktop_scene_locked.c b/applications/desktop/scenes/desktop_scene_locked.c index ad436212..b8111ed7 100644 --- a/applications/desktop/scenes/desktop_scene_locked.c +++ b/applications/desktop/scenes/desktop_scene_locked.c @@ -1,5 +1,6 @@ #include "../desktop_i.h" #include "../views/desktop_locked.h" +#include void desktop_scene_locked_callback(DesktopLockedEvent event, void* context) { Desktop* desktop = (Desktop*)context; @@ -40,8 +41,8 @@ static bool desktop_scene_locked_check_pin(Desktop* desktop, DesktopMainEvent ev if(match) { desktop->pincode_buffer.length = 0; - desktop->settings.locked = false; - desktop_settings_save(&desktop->settings); + furi_hal_usb_enable(); + furi_hal_lock_set(false); desktop_main_unlocked(desktop->main_view); } diff --git a/applications/desktop/scenes/desktop_scene_main.c b/applications/desktop/scenes/desktop_scene_main.c index 4065b51c..36c8bdee 100644 --- a/applications/desktop/scenes/desktop_scene_main.c +++ b/applications/desktop/scenes/desktop_scene_main.c @@ -34,8 +34,6 @@ void desktop_scene_main_on_enter(void* context) { desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop); view_port_enabled_set(desktop->lock_viewport, false); - desktop_settings_load(&desktop->settings); - if(scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneMain) == DesktopMainEventUnlocked) { desktop_main_unlocked(desktop->main_view); @@ -72,7 +70,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopMainEventOpenFavorite: - desktop_settings_load(&desktop->settings); + LOAD_DESKTOP_SETTINGS(&desktop->settings); desktop_switch_to_app(desktop, &FLIPPER_APPS[desktop->settings.favorite]); consumed = true; break; diff --git a/applications/desktop/scenes/desktop_scene_pinsetup.c b/applications/desktop/scenes/desktop_scene_pinsetup.c index 78515d7e..6b1c9686 100644 --- a/applications/desktop/scenes/desktop_scene_pinsetup.c +++ b/applications/desktop/scenes/desktop_scene_pinsetup.c @@ -4,7 +4,6 @@ void desktop_scene_ok_callback(void* context) { Desktop* app = context; - desktop_settings_save(&app->settings); view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT); } @@ -45,6 +44,7 @@ bool desktop_scene_pinsetup_on_event(void* context, SceneManagerEvent event) { void desktop_scene_pinsetup_on_exit(void* context) { Desktop* app = context; + SAVE_DESKTOP_SETTINGS(&app->settings); code_input_set_result_callback(app->code_input, NULL, NULL, NULL, NULL, NULL, 0); code_input_set_header_text(app->code_input, ""); } diff --git a/applications/desktop/views/desktop_lock_menu.h b/applications/desktop/views/desktop_lock_menu.h index f86b5d74..73f4f203 100644 --- a/applications/desktop/views/desktop_lock_menu.h +++ b/applications/desktop/views/desktop_lock_menu.h @@ -10,7 +10,6 @@ typedef enum { DesktopLockMenuEventLock, - DesktopLockMenuEventUnlock, DesktopLockMenuEventPinLock, DesktopLockMenuEventExit, } DesktopLockMenuEvent; diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index f1f1e5e5..1415f435 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -81,12 +81,7 @@ static void dolphin_check_butthurt(DolphinState* state) { furi_assert(state); float diff_time = difftime(dolphin_state_get_timestamp(state), dolphin_state_timestamp()); -#if 0 - FURI_LOG_I("dolphin-state", "Butthurt check, time since deed %.0f", fabs(diff_time)); -#endif - if((fabs(diff_time)) > DOLPHIN_TIMEGATE) { - // increase butthurt FURI_LOG_I("dolphin-state", "Increasing butthurt"); dolphin_state_butthurted(state); } diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c index 240b7d95..379908c9 100644 --- a/applications/dolphin/helpers/dolphin_state.c +++ b/applications/dolphin/helpers/dolphin_state.c @@ -2,20 +2,14 @@ #include #include #include +#include -#define DOLPHIN_STORE_KEY "/int/dolphin.state" -#define DOLPHIN_STORE_HEADER_MAGIC 0xD0 -#define DOLPHIN_STORE_HEADER_VERSION 0x01 +#define DOLPHIN_STATE_TAG "DolphinState" +#define DOLPHIN_STATE_PATH "/int/dolphin.state" +#define DOLPHIN_STATE_HEADER_MAGIC 0xD0 +#define DOLPHIN_STATE_HEADER_VERSION 0x01 #define DOLPHIN_LVL_THRESHOLD 20.0f -typedef struct { - uint8_t magic; - uint8_t version; - uint8_t checksum; - uint8_t flags; - uint32_t timestamp; -} DolphinStoreHeader; - typedef struct { uint32_t limit_ibutton; uint32_t limit_nfc; @@ -28,25 +22,16 @@ typedef struct { uint64_t timestamp; } DolphinStoreData; -typedef struct { - DolphinStoreHeader header; - DolphinStoreData data; -} DolphinStore; - struct DolphinState { - Storage* fs_api; DolphinStoreData data; bool dirty; }; DolphinState* dolphin_state_alloc() { - DolphinState* dolphin_state = furi_alloc(sizeof(DolphinState)); - dolphin_state->fs_api = furi_record_open("storage"); - return dolphin_state; + return furi_alloc(sizeof(DolphinState)); } void dolphin_state_free(DolphinState* dolphin_state) { - furi_record_close("storage"); free(dolphin_state); } @@ -55,121 +40,38 @@ bool dolphin_state_save(DolphinState* dolphin_state) { return true; } - FURI_LOG_I("dolphin-state", "State is dirty, saving to \"%s\"", DOLPHIN_STORE_KEY); - DolphinStore store; - // Calculate checksum - uint8_t* source = (uint8_t*)&dolphin_state->data; - uint8_t checksum = 0; - for(size_t i = 0; i < sizeof(DolphinStoreData); i++) { - checksum += source[i]; - } - // Set header - store.header.magic = DOLPHIN_STORE_HEADER_MAGIC; - store.header.version = DOLPHIN_STORE_HEADER_VERSION; - store.header.checksum = checksum; - store.header.flags = 0; - store.header.timestamp = 0; - // Set data - store.data = dolphin_state->data; + bool result = saved_struct_save( + DOLPHIN_STATE_PATH, + &dolphin_state->data, + sizeof(DolphinStoreData), + DOLPHIN_STATE_HEADER_MAGIC, + DOLPHIN_STATE_HEADER_VERSION); - // Store - File* file = storage_file_alloc(dolphin_state->fs_api); - bool save_result = storage_file_open(file, DOLPHIN_STORE_KEY, FSAM_WRITE, FSOM_CREATE_ALWAYS); - - if(save_result) { - uint16_t bytes_count = storage_file_write(file, &store, sizeof(DolphinStore)); - - if(bytes_count != sizeof(DolphinStore)) { - save_result = false; - } + if(result) { + FURI_LOG_I(DOLPHIN_STATE_TAG, "State saved"); + dolphin_state->dirty = false; + } else { + FURI_LOG_E(DOLPHIN_STATE_TAG, "Failed to save state"); } - if(!save_result) { - FURI_LOG_E( - "dolphin-state", - "Save failed. Storage returned: %s", - storage_file_get_error_desc(file)); - } - - storage_file_close(file); - storage_file_free(file); - - dolphin_state->dirty = !save_result; - - FURI_LOG_I("dolphin-state", "Saved"); - - return save_result; + return result; } bool dolphin_state_load(DolphinState* dolphin_state) { - DolphinStore store; - // Read Dolphin State Store - FURI_LOG_I("dolphin-state", "Loading state from \"%s\"", DOLPHIN_STORE_KEY); + bool loaded = saved_struct_load( + DOLPHIN_STATE_PATH, + &dolphin_state->data, + sizeof(DolphinStoreData), + DOLPHIN_STATE_HEADER_MAGIC, + DOLPHIN_STATE_HEADER_VERSION); - File* file = storage_file_alloc(dolphin_state->fs_api); - bool load_result = storage_file_open(file, DOLPHIN_STORE_KEY, FSAM_READ, FSOM_OPEN_EXISTING); - if(!load_result) { - FURI_LOG_E( - "dolphin-state", - "Load failed. Storage returned: %s", - storage_file_get_error_desc(file)); - } else { - uint16_t bytes_count = storage_file_read(file, &store, sizeof(DolphinStore)); - - if(bytes_count != sizeof(DolphinStore)) { - load_result = false; - } + if(!loaded) { + FURI_LOG_W(DOLPHIN_STATE_TAG, "Reset dolphin-state"); + memset(dolphin_state, 0, sizeof(*dolphin_state)); + dolphin_state->dirty = true; } - if(!load_result) { - FURI_LOG_E("dolphin-state", "DolphinStore size mismatch"); - } else { - if(store.header.magic == DOLPHIN_STORE_HEADER_MAGIC && - store.header.version == DOLPHIN_STORE_HEADER_VERSION) { - FURI_LOG_I( - "dolphin-state", - "Magic(%d) and Version(%d) match", - store.header.magic, - store.header.version); - uint8_t checksum = 0; - const uint8_t* source = (const uint8_t*)&store.data; - for(size_t i = 0; i < sizeof(DolphinStoreData); i++) { - checksum += source[i]; - } - - if(store.header.checksum == checksum) { - FURI_LOG_I("dolphin-state", "Checksum(%d) match", store.header.checksum); - dolphin_state->data = store.data; - } else { - FURI_LOG_E( - "dolphin-state", - "Checksum(%d != %d) mismatch", - store.header.checksum, - checksum); - load_result = false; - } - } else { - FURI_LOG_E( - "dolphin-state", - "Magic(%d != %d) or Version(%d != %d) mismatch", - store.header.magic, - DOLPHIN_STORE_HEADER_MAGIC, - store.header.version, - DOLPHIN_STORE_HEADER_VERSION); - load_result = false; - } - } - - storage_file_close(file); - storage_file_free(file); - - dolphin_state->dirty = !load_result; - - return load_result; -} - -void dolphin_state_clear(DolphinState* dolphin_state) { - memset(&dolphin_state->data, 0, sizeof(DolphinStoreData)); + return loaded; } uint64_t dolphin_state_timestamp() { @@ -229,4 +131,4 @@ uint32_t dolphin_state_get_level(uint32_t icounter) { uint32_t dolphin_state_xp_to_levelup(uint32_t icounter, uint32_t level, bool remaining) { return (DOLPHIN_LVL_THRESHOLD * level * (level + 1) / 2) - (remaining ? icounter : 0); -} \ No newline at end of file +} diff --git a/applications/gpio/scenes/gpio_scene_start.c b/applications/gpio/scenes/gpio_scene_start.c index b7d94fe7..df210882 100644 --- a/applications/gpio/scenes/gpio_scene_start.c +++ b/applications/gpio/scenes/gpio_scene_start.c @@ -67,6 +67,9 @@ void gpio_scene_start_on_enter(void* context) { variable_item_list_add(var_item_list, "GPIO tester", 0, NULL, NULL); variable_item_list_add(var_item_list, "USB-UART bridge", 0, NULL, NULL); + variable_item_list_set_selected_item( + var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioSceneStart)); + view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewVarItemList); } @@ -80,8 +83,10 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF) { furi_hal_power_disable_otg(); } else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_TEST) { + scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, 1); scene_manager_next_scene(app->scene_manager, GpioSceneTest); } else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_USB_UART) { + scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, 2); scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart); } consumed = true; diff --git a/applications/gpio/scenes/gpio_scene_usb_uart.c b/applications/gpio/scenes/gpio_scene_usb_uart.c index c8ec0141..b24e4b3e 100644 --- a/applications/gpio/scenes/gpio_scene_usb_uart.c +++ b/applications/gpio/scenes/gpio_scene_usb_uart.c @@ -120,12 +120,19 @@ void gpio_scene_usb_uart_on_enter(void* context) { item = variable_item_list_add(var_item_list, "Enable", 0, NULL, NULL); item = variable_item_list_add(var_item_list, "Disable", 0, NULL, NULL); + variable_item_list_set_selected_item( + var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioSceneUsbUart)); + view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart); } void gpio_scene_usb_uart_on_exit(void* context) { GpioApp* app = context; usb_uart_disable(); + scene_manager_set_scene_state( + app->scene_manager, + GpioSceneUsbUart, + variable_item_list_get_selected_item_index(app->var_item_list)); variable_item_list_clean(app->var_item_list); free(cfg_set); } diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c index b50cc158..ff787ea7 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/applications/gpio/usb_uart_bridge.c @@ -4,23 +4,19 @@ #include #include "usb_cdc.h" -#define USB_PKT_LEN CDC_DATA_SZ -#define USB_UART_RX_BUF_SIZE (USB_PKT_LEN * 3) -#define USB_UART_TX_BUF_SIZE (USB_PKT_LEN * 3) +#define USB_CDC_PKT_LEN CDC_DATA_SZ +#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) typedef enum { WorkerEvtStop = (1 << 0), - WorkerEvtRxReady = (1 << 1), + WorkerEvtRxDone = (1 << 1), WorkerEvtTxStop = (1 << 2), - WorkerEvtTxReady = (1 << 3), - - WorkerEvtSof = (1 << 4), - + WorkerEvtCdcRx = (1 << 3), } WorkerEvtFlags; -#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxReady) -#define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtTxReady) +#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone) +#define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtCdcRx) typedef struct { UsbUartConfig cfg; @@ -28,13 +24,13 @@ typedef struct { FuriThread* thread; FuriThread* tx_thread; - osEventFlagsId_t events; - StreamBufferHandle_t rx_stream; - StreamBufferHandle_t tx_stream; - uint8_t rx_buf[USB_PKT_LEN]; - uint8_t tx_buf[USB_PKT_LEN]; + osMutexId_t usb_mutex; + + osSemaphoreId_t tx_sem; + + uint8_t rx_buf[USB_CDC_PKT_LEN]; bool buf_full; } UsbUartParams; @@ -65,21 +61,18 @@ static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) { if(ev == UartIrqEventRXNE) { xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); - - size_t ret = xStreamBufferBytesAvailable(usb_uart->rx_stream); - if(ret > USB_PKT_LEN) osEventFlagsSet(usb_uart->events, WorkerEvtRxReady); - } else if(ev == UartIrqEventIDLE) { - osEventFlagsSet(usb_uart->events, WorkerEvtRxReady); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtRxDone); } - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } static int32_t usb_uart_worker(void* context) { memcpy(&usb_uart->cfg, context, sizeof(UsbUartConfig)); usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1); - usb_uart->tx_stream = xStreamBufferCreate(USB_UART_TX_BUF_SIZE, 1); + + usb_uart->tx_sem = osSemaphoreNew(1, 1, NULL); + usb_uart->usb_mutex = osMutexNew(NULL); usb_uart->tx_thread = furi_thread_alloc(); furi_thread_set_name(usb_uart->tx_thread, "usb_uart_tx"); @@ -91,10 +84,10 @@ static int32_t usb_uart_worker(void* context) { if(usb_uart->cfg.vcp_ch == 0) { furi_hal_usb_set_config(UsbModeVcpSingle); furi_hal_vcp_disable(); - osEventFlagsSet(usb_uart->events, WorkerEvtSof); } else { furi_hal_usb_set_config(UsbModeVcpDual); } + osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtCdcRx); if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) { furi_hal_console_disable(); @@ -114,26 +107,25 @@ static int32_t usb_uart_worker(void* context) { furi_thread_start(usb_uart->tx_thread); while(1) { - uint32_t events = osEventFlagsWait( - usb_uart->events, WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever); + uint32_t events = osThreadFlagsWait(WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever); furi_check((events & osFlagsError) == 0); if(events & WorkerEvtStop) break; - if(events & WorkerEvtRxReady) { - size_t len = 0; - do { - len = xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_PKT_LEN, 0); - if(len > 0) { - if((osEventFlagsWait(usb_uart->events, WorkerEvtSof, osFlagsWaitAny, 100) & - osFlagsError) == 0) - furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len); - else - xStreamBufferReset(usb_uart->rx_stream); + if(events & WorkerEvtRxDone) { + size_t len = + xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0); + if(len > 0) { + if(osSemaphoreAcquire(usb_uart->tx_sem, 100) == osOK) { + furi_check(osMutexAcquire(usb_uart->usb_mutex, osWaitForever) == osOK); + furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len); + furi_check(osMutexRelease(usb_uart->usb_mutex) == osOK); + } else { + xStreamBufferReset(usb_uart->rx_stream); } - } while(len > 0); + } } } - osEventFlagsSet(usb_uart->events, WorkerEvtTxStop); + osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop); furi_thread_join(usb_uart->tx_thread); furi_thread_free(usb_uart->tx_thread); @@ -147,35 +139,26 @@ static int32_t usb_uart_worker(void* context) { if(usb_uart->cfg.vcp_ch == 0) furi_hal_vcp_enable(); vStreamBufferDelete(usb_uart->rx_stream); - vStreamBufferDelete(usb_uart->tx_stream); + osMutexDelete(usb_uart->usb_mutex); + osSemaphoreDelete(usb_uart->tx_sem); return 0; } static int32_t usb_uart_tx_thread(void* context) { - uint8_t data[USB_PKT_LEN]; + uint8_t data[USB_CDC_PKT_LEN]; while(1) { - uint32_t events = osEventFlagsWait( - usb_uart->events, WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever); + uint32_t events = osThreadFlagsWait(WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever); furi_check((events & osFlagsError) == 0); if(events & WorkerEvtTxStop) break; - if(events & WorkerEvtTxReady) { - size_t len = 0; - do { - len = xStreamBufferReceive(usb_uart->tx_stream, &data, 1, 0); - if(len > 0) { - furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len); - } - if((usb_uart->buf_full == true) && - (xStreamBufferBytesAvailable(usb_uart->tx_stream) == 0)) { - // Stream buffer was overflown, but now is free. Reading USB buffer to resume USB transfers - usb_uart->buf_full = false; - int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, data, USB_PKT_LEN); - if(size > 0) { - furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, size); - } - } - } while(len > 0); + if(events & WorkerEvtCdcRx) { + furi_check(osMutexAcquire(usb_uart->usb_mutex, osWaitForever) == osOK); + int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, data, USB_CDC_PKT_LEN); + furi_check(osMutexRelease(usb_uart->usb_mutex) == osOK); + + if(size > 0) { + furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, size); + } } } return 0; @@ -184,26 +167,11 @@ static int32_t usb_uart_tx_thread(void* context) { /* VCP callbacks */ static void vcp_on_cdc_tx_complete() { - osEventFlagsSet(usb_uart->events, WorkerEvtSof); + osSemaphoreRelease(usb_uart->tx_sem); } static void vcp_on_cdc_rx() { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - uint16_t max_len = xStreamBufferSpacesAvailable(usb_uart->tx_stream); - if(max_len >= USB_PKT_LEN) { - //if(max_len > USB_PKT_LEN) max_len = USB_PKT_LEN; - int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, usb_uart->tx_buf, USB_PKT_LEN); - if(size > 0) { - size_t ret = xStreamBufferSendFromISR( - usb_uart->tx_stream, usb_uart->tx_buf, size, &xHigherPriorityTaskWoken); - furi_check(ret == size); - } - } else { - usb_uart->buf_full = true; - } - osEventFlagsSet(usb_uart->events, WorkerEvtTxReady); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtCdcRx); } static void vcp_state_callback(uint8_t state) { @@ -228,18 +196,15 @@ void usb_uart_enable(UsbUartConfig* cfg) { furi_thread_set_context(usb_uart->thread, cfg); furi_thread_set_callback(usb_uart->thread, usb_uart_worker); - usb_uart->events = osEventFlagsNew(NULL); - furi_thread_start(usb_uart->thread); } } void usb_uart_disable() { if(running == true) { - osEventFlagsSet(usb_uart->events, WorkerEvtStop); + osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtStop); furi_thread_join(usb_uart->thread); furi_thread_free(usb_uart->thread); - osEventFlagsDelete(usb_uart->events); free(usb_uart); running = false; } diff --git a/applications/gui/gui.c b/applications/gui/gui.c index a7e7f295..46a515a0 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -189,7 +189,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { } else if(input_event->type == InputTypePress) { gui->ongoing_input |= key_bit; } else if(!(gui->ongoing_input & key_bit)) { - FURI_LOG_W( + FURI_LOG_D( "Gui", "non-complementary input, discarding key: %s type: %s, sequence: %p", input_get_key_name(input_event->key), @@ -211,7 +211,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { if(view_port && view_port == gui->ongoing_input_view_port) { view_port_input(view_port, input_event); } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { - FURI_LOG_W( + FURI_LOG_D( "Gui", "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", gui->ongoing_input_view_port, @@ -221,7 +221,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { input_event->sequence); view_port_input(gui->ongoing_input_view_port, input_event); } else { - FURI_LOG_W( + FURI_LOG_D( "Gui", "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", gui->ongoing_input_view_port, @@ -258,8 +258,7 @@ void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context) { void gui_cli_screen_stream(Cli* cli, string_t args, void* context) { furi_assert(context); Gui* gui = context; - gui_set_framebuffer_callback_context(gui, gui); - gui_set_framebuffer_callback(gui, gui_cli_screen_stream_callback); + gui_set_framebuffer_callback(gui, gui_cli_screen_stream_callback, gui); gui_redraw(gui); // Wait for control events @@ -279,8 +278,7 @@ void gui_cli_screen_stream(Cli* cli, string_t args, void* context) { } } - gui_set_framebuffer_callback(gui, NULL); - gui_set_framebuffer_callback_context(gui, NULL); + gui_set_framebuffer_callback(gui, NULL, NULL); } void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { @@ -387,14 +385,12 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) { gui_unlock(gui); } -void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback) { +void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { furi_assert(gui); + gui_lock(gui); gui->canvas_callback = callback; -} - -void gui_set_framebuffer_callback_context(Gui* gui, void* context) { - furi_assert(gui); gui->canvas_callback_context = context; + gui_unlock(gui); } Gui* gui_alloc() { @@ -414,7 +410,7 @@ Gui* gui_alloc() { gui->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); gui->input_events = furi_record_open("input_events"); furi_check(gui->input_events); - subscribe_pubsub(gui->input_events, gui_input_events_callback, gui); + furi_pubsub_subscribe(gui->input_events, gui_input_events_callback, gui); // Cli gui->cli = furi_record_open("cli"); cli_add_command( diff --git a/applications/gui/gui.h b/applications/gui/gui.h index eb68f520..acdd2211 100644 --- a/applications/gui/gui.h +++ b/applications/gui/gui.h @@ -73,15 +73,9 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port); * * @param gui Gui instance * @param callback GuiCanvasCommitCallback + * @param context GuiCanvasCommitCallback context */ -void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback); - -/** Set gui canvas commit callback context - * - * @param gui Gui instance - * @param context pointer to context - */ -void gui_set_framebuffer_callback_context(Gui* gui, void* context); +void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context); #ifdef __cplusplus } diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index cfbf604f..5b32f602 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -50,7 +50,7 @@ struct Gui { // Input osMessageQueueId_t input_queue; - PubSub* input_events; + FuriPubSub* input_events; uint8_t ongoing_input; ViewPort* ongoing_input_view_port; diff --git a/applications/gui/icon_animation.c b/applications/gui/icon_animation.c index 22089d63..3ed0973d 100644 --- a/applications/gui/icon_animation.c +++ b/applications/gui/icon_animation.c @@ -2,7 +2,6 @@ #include "icon_i.h" #include -#include IconAnimation* icon_animation_alloc(const Icon* icon) { furi_assert(icon); diff --git a/applications/gui/modules/variable-item-list.c b/applications/gui/modules/variable-item-list.c old mode 100755 new mode 100644 index 800e0602..03f04cb6 --- a/applications/gui/modules/variable-item-list.c +++ b/applications/gui/modules/variable-item-list.c @@ -84,6 +84,40 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) { elements_scrollbar(canvas, model->position, VariableItemArray_size(model->items)); } +void variable_item_list_set_selected_item(VariableItemList* variable_item_list, uint8_t index) { + with_view_model( + variable_item_list->view, (VariableItemListModel * model) { + uint8_t position = index; + if(position >= VariableItemArray_size(model->items)) { + position = 0; + } + + model->position = position; + model->window_position = position; + + if(model->window_position > 0) { + model->window_position -= 1; + } + + if(VariableItemArray_size(model->items) <= 4) { + model->window_position = 0; + } else { + if(model->window_position >= (VariableItemArray_size(model->items) - 4)) { + model->window_position = (VariableItemArray_size(model->items) - 4); + } + } + + return true; + }); +} + +uint8_t variable_item_list_get_selected_item_index(VariableItemList* variable_item_list) { + VariableItemListModel* model = view_get_model(variable_item_list->view); + uint8_t idx = model->position; + view_commit_model(variable_item_list->view, false); + return idx; +} + static bool variable_item_list_input_callback(InputEvent* event, void* context) { VariableItemList* variable_item_list = context; furi_assert(variable_item_list); @@ -323,4 +357,4 @@ uint8_t variable_item_get_current_value_index(VariableItem* item) { void* variable_item_get_context(VariableItem* item) { return item->context; -} \ No newline at end of file +} diff --git a/applications/gui/modules/variable-item-list.h b/applications/gui/modules/variable-item-list.h index e1e3cbf7..b67a02e6 100755 --- a/applications/gui/modules/variable-item-list.h +++ b/applications/gui/modules/variable-item-list.h @@ -70,6 +70,10 @@ void variable_item_list_set_enter_callback( VariableItemListEnterCallback callback, void* context); +void variable_item_list_set_selected_item(VariableItemList* variable_item_list, uint8_t index); + +uint8_t variable_item_list_get_selected_item_index(VariableItemList* variable_item_list); + /** Set item current selected index * * @param item VariableItem* instance diff --git a/applications/gui/view_dispatcher.c b/applications/gui/view_dispatcher.c index c0246d97..e50c1809 100644 --- a/applications/gui/view_dispatcher.c +++ b/applications/gui/view_dispatcher.c @@ -236,7 +236,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e } else if(event->type == InputTypeRelease) { view_dispatcher->ongoing_input &= ~key_bit; } else if(!(view_dispatcher->ongoing_input & key_bit)) { - FURI_LOG_W( + FURI_LOG_D( "ViewDispatcher", "non-complementary input, discarding key: %s, type: %s, sequence: %p", input_get_key_name(event->key), @@ -275,7 +275,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e } } } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) { - FURI_LOG_W( + FURI_LOG_D( "ViewDispatcher", "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", view_dispatcher->ongoing_input_view, diff --git a/applications/ibutton/ibutton-app.cpp b/applications/ibutton/ibutton-app.cpp index 3491c95e..99454cf0 100644 --- a/applications/ibutton/ibutton-app.cpp +++ b/applications/ibutton/ibutton-app.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include const char* iButtonApp::app_folder = "/any/ibutton"; const char* iButtonApp::app_extension = ".ibtn"; @@ -48,8 +48,8 @@ iButtonApp::iButtonApp() iButtonApp::~iButtonApp() { for(std::map::iterator it = scenes.begin(); it != scenes.end(); ++it) { delete it->second; - scenes.erase(it); } + scenes.clear(); delete key_worker; furi_hal_power_insomnia_exit(); @@ -191,7 +191,7 @@ bool iButtonApp::save_key(const char* key_name) { // Create ibutton directory if necessary make_app_folder(); - FlipperFileCpp file(storage); + FlipperFile* file = flipper_file_alloc(storage); string_t key_file_name; bool result = false; string_init(key_file_name); @@ -207,27 +207,30 @@ bool iButtonApp::save_key(const char* key_name) { string_printf(key_file_name, "%s/%s%s", app_folder, key.get_name(), app_extension); // Open file for write - if(!file.new_write(string_get_cstr(key_file_name))) break; + if(!flipper_file_open_always(file, string_get_cstr(key_file_name))) break; // Write header - if(!file.write_header_cstr(iButtonApp::app_filetype, 1)) break; + if(!flipper_file_write_header_cstr(file, iButtonApp::app_filetype, 1)) break; // Write key type - if(!file.write_comment_cstr("Key type can be Cyfral, Dallas or Metakom")) break; + if(!flipper_file_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom")) + break; const char* key_type = key.get_key_type_string_by_type(key.get_key_type()); - if(!file.write_string_cstr("Key type", key_type)) break; + if(!flipper_file_write_string_cstr(file, "Key type", key_type)) break; // Write data - if(!file.write_comment_cstr( - "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8")) + if(!flipper_file_write_comment_cstr( + file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8")) break; - if(!file.write_hex_array("Data", key.get_data(), key.get_type_data_size())) break; + if(!flipper_file_write_hex(file, "Data", key.get_data(), key.get_type_data_size())) break; result = true; } while(false); - file.close(); + flipper_file_close(file); + flipper_file_free(file); + string_clear(key_file_name); if(!result) { @@ -238,28 +241,29 @@ bool iButtonApp::save_key(const char* key_name) { } bool iButtonApp::load_key_data(string_t key_path) { - FlipperFileCpp file(storage); + FlipperFile* file = flipper_file_alloc(storage); bool result = false; string_t data; string_init(data); do { - if(!file.open_read(string_get_cstr(key_path))) break; + if(!flipper_file_open_existing(file, string_get_cstr(key_path))) break; // header uint32_t version; - if(!file.read_header(data, &version)) break; + if(!flipper_file_read_header(file, data, &version)) break; if(string_cmp_str(data, iButtonApp::app_filetype) != 0) break; if(version != 1) break; // key type iButtonKeyType type; - if(!file.read_string("Key type", data)) break; + if(!flipper_file_read_string(file, "Key type", data)) break; if(!key.get_key_type_by_type_string(string_get_cstr(data), &type)) break; // key data uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0}; - if(!file.read_hex_array("Data", key_data, key.get_type_data_size_by_type(type))) break; + if(!flipper_file_read_hex(file, "Data", key_data, key.get_type_data_size_by_type(type))) + break; key.set_type(type); key.set_data(key_data, IBUTTON_KEY_DATA_SIZE); @@ -267,7 +271,8 @@ bool iButtonApp::load_key_data(string_t key_path) { result = true; } while(false); - file.close(); + flipper_file_close(file); + flipper_file_free(file); string_clear(data); if(!result) { diff --git a/applications/input/input.c b/applications/input/input.c index 62be3dba..1d160e55 100644 --- a/applications/input/input.c +++ b/applications/input/input.c @@ -28,11 +28,11 @@ void input_press_timer_callback(void* arg) { input_pin->press_counter++; if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { event.type = InputTypeLong; - notify_pubsub(&input->event_pubsub, &event); + furi_pubsub_publish(input->event_pubsub, &event); } else if(input_pin->press_counter > INPUT_LONG_PRESS_COUNTS) { input_pin->press_counter--; event.type = InputTypeRepeat; - notify_pubsub(&input->event_pubsub, &event); + furi_pubsub_publish(input->event_pubsub, &event); } } @@ -89,7 +89,7 @@ void input_cli_send(Cli* cli, string_t args, void* context) { return; } // Publish input event - notify_pubsub(&input->event_pubsub, &event); + furi_pubsub_publish(input->event_pubsub, &event); } const char* input_get_key_name(InputKey key) { @@ -120,8 +120,8 @@ const char* input_get_type_name(InputType type) { int32_t input_srv() { input = furi_alloc(sizeof(Input)); input->thread = osThreadGetId(); - init_pubsub(&input->event_pubsub); - furi_record_create("input_events", &input->event_pubsub); + input->event_pubsub = furi_pubsub_alloc(); + furi_record_create("input_events", input->event_pubsub); input->cli = furi_record_open("cli"); if(input->cli) { @@ -168,14 +168,14 @@ int32_t input_srv() { input_timer_stop(input->pin_states[i].press_timer); if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { event.type = InputTypeShort; - notify_pubsub(&input->event_pubsub, &event); + furi_pubsub_publish(input->event_pubsub, &event); } input->pin_states[i].press_counter = 0; } // Send Press/Release event event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease; - notify_pubsub(&input->event_pubsub, &event); + furi_pubsub_publish(input->event_pubsub, &event); } } diff --git a/applications/input/input.h b/applications/input/input.h index d848b1c6..08723795 100644 --- a/applications/input/input.h +++ b/applications/input/input.h @@ -18,7 +18,7 @@ typedef enum { InputTypeRepeat, /**< Repeat event, emmited with INPUT_REPEATE_PRESS period after InputTypeLong event */ } InputType; -/** Input Event, dispatches with PubSub */ +/** Input Event, dispatches with FuriPubSub */ typedef struct { uint32_t sequence; InputKey key; diff --git a/applications/input/input_i.h b/applications/input/input_i.h index db314dad..2111de7c 100644 --- a/applications/input/input_i.h +++ b/applications/input/input_i.h @@ -6,8 +6,6 @@ #pragma once #include "input.h" -#include -#include #include #include #include @@ -35,7 +33,7 @@ typedef struct { /** Input state */ typedef struct { osThreadId_t thread; - PubSub event_pubsub; + FuriPubSub* event_pubsub; InputPinState* pin_states; Cli* cli; volatile uint32_t counter; diff --git a/applications/irda/irda-app.cpp b/applications/irda/irda-app.cpp index 042d237c..7c7a5cf3 100644 --- a/applications/irda/irda-app.cpp +++ b/applications/irda/irda-app.cpp @@ -211,10 +211,12 @@ void IrdaApp::notify_red_blink() { notification_message(notification, &sequence_blink_red_10); } -void IrdaApp::notify_space_blink() { +void IrdaApp::notify_sent_just_learnt() { static const NotificationSequence sequence = { &message_green_0, + &message_vibro_on, &message_delay_50, + &message_vibro_off, &message_green_255, &message_do_not_reset, NULL, @@ -261,10 +263,6 @@ void IrdaApp::notify_blink_green() { notification_message(notification, &sequence); } -void IrdaApp::notify_double_vibro() { - notification_message(notification, &sequence_double_vibro); -} - void IrdaApp::notify_green_on() { notification_message(notification, &sequence_set_only_green_255); } diff --git a/applications/irda/irda-app.h b/applications/irda/irda-app.h index 904bead3..adc53b45 100644 --- a/applications/irda/irda-app.h +++ b/applications/irda/irda-app.h @@ -77,8 +77,7 @@ public: void notify_success(); void notify_red_blink(); - void notify_space_blink(); - void notify_double_vibro(); + void notify_sent_just_learnt(); void notify_green_on(); void notify_green_off(); void notify_click(); diff --git a/applications/irda/scene/irda-app-scene-learn-success.cpp b/applications/irda/scene/irda-app-scene-learn-success.cpp index 030ca0e3..59a81727 100644 --- a/applications/irda/scene/irda-app-scene-learn-success.cpp +++ b/applications/irda/scene/irda-app-scene-learn-success.cpp @@ -23,16 +23,24 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { if(!signal.is_raw()) { auto message = &signal.get_message(); + uint8_t adr_digits = ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4); + uint8_t cmd_digits = ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4); + uint8_t max_digits = MAX(adr_digits, cmd_digits); + max_digits = MIN(max_digits, 7); + size_t label_x_offset = 63 + (7 - max_digits) * 3; + app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol)); app->set_text_store( 1, "A: 0x%0*lX\nC: 0x%0*lX\n", - ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4), + adr_digits, message->address, - ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), + cmd_digits, message->command); - dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 10, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, app->get_text_store(1), 75, 23, AlignLeft, AlignTop); + + dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 7, AlignCenter, AlignCenter); + dialog_ex_set_text( + dialog_ex, app->get_text_store(1), label_x_offset, 34, AlignLeft, AlignCenter); } else { dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); app->set_text_store(0, "%d samples", signal.get_raw_signal().timings_cnt); @@ -42,7 +50,7 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "Save"); dialog_ex_set_center_button_text(dialog_ex, "Send"); - dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinExcited_64x63); + dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); dialog_ex_set_context(dialog_ex, app); @@ -62,7 +70,7 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { app->switch_to_next_scene_without_saving(IrdaApp::Scene::Learn); break; case DialogExResultCenter: { - app->notify_space_blink(); + app->notify_sent_just_learnt(); auto signal = app->get_received_signal(); signal.transmit(); break; diff --git a/applications/irda/scene/irda-app-scene-learn.cpp b/applications/irda/scene/irda-app-scene-learn.cpp index cbbbbe7a..b044215f 100644 --- a/applications/irda/scene/irda-app-scene-learn.cpp +++ b/applications/irda/scene/irda-app-scene-learn.cpp @@ -39,10 +39,6 @@ void IrdaAppSceneLearn::on_enter(IrdaApp* app) { popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter); popup_set_callback(popup, NULL); - if(app->get_learn_new_remote()) { - app->notify_double_vibro(); - } - view_manager->switch_to(IrdaAppViewManager::ViewType::Popup); } diff --git a/applications/lfrfid/helpers/rfid-timer-emulator.cpp b/applications/lfrfid/helpers/rfid-timer-emulator.cpp index 05afb146..56c614f6 100644 --- a/applications/lfrfid/helpers/rfid-timer-emulator.cpp +++ b/applications/lfrfid/helpers/rfid-timer-emulator.cpp @@ -10,8 +10,9 @@ RfidTimerEmulator::~RfidTimerEmulator() { for(it = encoders.begin(); it != encoders.end(); ++it) { delete it->second; - encoders.erase(it); } + + encoders.clear(); } void RfidTimerEmulator::start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size) { diff --git a/applications/lfrfid/lfrfid-app.cpp b/applications/lfrfid/lfrfid-app.cpp index 92ddaa63..a64b1380 100644 --- a/applications/lfrfid/lfrfid-app.cpp +++ b/applications/lfrfid/lfrfid-app.cpp @@ -16,8 +16,8 @@ #include "scene/lfrfid-app-scene-delete-confirm.h" #include "scene/lfrfid-app-scene-delete-success.h" -#include -#include +#include +#include const char* LfRfidApp::app_folder = "/any/lfrfid"; const char* LfRfidApp::app_extension = ".rfid"; @@ -119,17 +119,17 @@ bool LfRfidApp::delete_key(RfidKey* key) { } bool LfRfidApp::load_key_data(const char* path, RfidKey* key) { - FlipperFileCpp file(storage); + FlipperFile* file = flipper_file_alloc(storage); bool result = false; string_t str_result; string_init(str_result); do { - if(!file.open_read(path)) break; + if(!flipper_file_open_existing(file, path)) break; // header uint32_t version; - if(!file.read_header(str_result, &version)) break; + if(!flipper_file_read_header(file, str_result, &version)) break; if(string_cmp_str(str_result, app_filetype) != 0) break; if(version != 1) break; @@ -137,13 +137,13 @@ bool LfRfidApp::load_key_data(const char* path, RfidKey* key) { LfrfidKeyType type; RfidKey loaded_key; - if(!file.read_string("Key type", str_result)) break; + if(!flipper_file_read_string(file, "Key type", str_result)) break; if(!lfrfid_key_get_string_type(string_get_cstr(str_result), &type)) break; loaded_key.set_type(type); // key data uint8_t key_data[loaded_key.get_type_data_count()] = {}; - if(!file.read_hex_array("Data", key_data, loaded_key.get_type_data_count())) break; + if(!flipper_file_read_hex(file, "Data", key_data, loaded_key.get_type_data_count())) break; loaded_key.set_data(key_data, loaded_key.get_type_data_count()); path_extract_filename_no_ext(path, str_result); @@ -153,7 +153,8 @@ bool LfRfidApp::load_key_data(const char* path, RfidKey* key) { result = true; } while(0); - file.close(); + flipper_file_close(file); + flipper_file_free(file); string_clear(str_result); if(!result) { @@ -164,21 +165,27 @@ bool LfRfidApp::load_key_data(const char* path, RfidKey* key) { } bool LfRfidApp::save_key_data(const char* path, RfidKey* key) { - FlipperFileCpp file(storage); + FlipperFile* file = flipper_file_alloc(storage); bool result = false; do { - if(!file.new_write(path)) break; - if(!file.write_header_cstr(app_filetype, 1)) break; - if(!file.write_comment_cstr("Key type can be EM4100, H10301 or I40134")) break; - if(!file.write_string_cstr("Key type", lfrfid_key_get_type_string(key->get_type()))) break; - if(!file.write_comment_cstr("Data size for EM4100 is 5, for H10301 is 3, for I40134 is 3")) + if(!flipper_file_open_always(file, path)) break; + if(!flipper_file_write_header_cstr(file, app_filetype, 1)) break; + if(!flipper_file_write_comment_cstr(file, "Key type can be EM4100, H10301 or I40134")) + break; + if(!flipper_file_write_string_cstr( + file, "Key type", lfrfid_key_get_type_string(key->get_type()))) + break; + if(!flipper_file_write_comment_cstr( + file, "Data size for EM4100 is 5, for H10301 is 3, for I40134 is 3")) + break; + if(!flipper_file_write_hex(file, "Data", key->get_data(), key->get_type_data_count())) break; - if(!file.write_hex_array("Data", key->get_data(), key->get_type_data_count())) break; result = true; } while(0); - file.close(); + flipper_file_close(file); + flipper_file_free(file); if(!result) { dialog_message_show_storage_error(dialogs, "Cannot save\nkey file"); diff --git a/applications/loader/loader.c b/applications/loader/loader.c old mode 100755 new mode 100644 index d52eaa18..574db256 --- a/applications/loader/loader.c +++ b/applications/loader/loader.c @@ -140,7 +140,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con Loader* instance = context; if(thread_state == FuriThreadStateRunning) { - instance->free_heap_size = xPortGetFreeHeapSize(); + instance->free_heap_size = memmgr_get_free_heap(); } else if(thread_state == FuriThreadStateStopped) { /* * Current Leak Sanitizer assumes that memory is allocated and freed @@ -153,7 +153,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con * both values should be taken into account. */ delay(20); - int heap_diff = instance->free_heap_size - xPortGetFreeHeapSize(); + int heap_diff = instance->free_heap_size - memmgr_get_free_heap(); FURI_LOG_I( LOADER_LOG_TAG, "Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", diff --git a/applications/notification/notification-app.c b/applications/notification/notification-app.c index 22b6794e..3912cf62 100644 --- a/applications/notification/notification-app.c +++ b/applications/notification/notification-app.c @@ -427,7 +427,7 @@ static NotificationApp* notification_app_alloc() { // display backlight control app->event_record = furi_record_open("input_events"); - subscribe_pubsub(app->event_record, input_event_callback, app); + furi_pubsub_subscribe(app->event_record, input_event_callback, app); notification_message(app, &sequence_display_on); return app; diff --git a/applications/notification/notification-app.h b/applications/notification/notification-app.h index 78c58f6d..f1fe5cef 100644 --- a/applications/notification/notification-app.h +++ b/applications/notification/notification-app.h @@ -44,7 +44,7 @@ typedef struct { struct NotificationApp { osMessageQueueId_t queue; - PubSub* event_record; + FuriPubSub* event_record; osTimerId_t display_timer; NotificationLedLayer display; diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c index de712fd4..94137d73 100755 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -31,7 +31,7 @@ Power* power_alloc() { power->gui = furi_record_open("gui"); // Pubsub - init_pubsub(&power->event_pubsub); + power->event_pubsub = furi_pubsub_alloc(); // State initialization power->state = PowerStateNotCharging; @@ -60,10 +60,6 @@ Power* power_alloc() { void power_free(Power* power) { furi_assert(power); - // Records - furi_record_close("notification"); - furi_record_close("gui"); - // Gui view_dispatcher_remove_view(power->view_dispatcher, PowerViewOff); power_off_free(power->power_off); @@ -73,6 +69,14 @@ void power_free(Power* power) { // State osMutexDelete(power->info_mtx); + + // FuriPubSub + furi_pubsub_free(power->event_pubsub); + + // Records + furi_record_close("notification"); + furi_record_close("gui"); + free(power); } @@ -83,14 +87,14 @@ static void power_check_charging_state(Power* power) { notification_internal_message(power->notification, &sequence_charged); power->state = PowerStateCharged; power->event.type = PowerEventTypeFullyCharged; - notify_pubsub(&power->event_pubsub, &power->event); + furi_pubsub_publish(power->event_pubsub, &power->event); } } else { if(power->state != PowerStateCharging) { notification_internal_message(power->notification, &sequence_charging); power->state = PowerStateCharging; power->event.type = PowerEventTypeStartCharging; - notify_pubsub(&power->event_pubsub, &power->event); + furi_pubsub_publish(power->event_pubsub, &power->event); } } } else { @@ -98,7 +102,7 @@ static void power_check_charging_state(Power* power) { notification_internal_message(power->notification, &sequence_not_charging); power->state = PowerStateNotCharging; power->event.type = PowerEventTypeStopCharging; - notify_pubsub(&power->event_pubsub, &power->event); + furi_pubsub_publish(power->event_pubsub, &power->event); } } } @@ -156,7 +160,7 @@ static void power_check_battery_level_change(Power* power) { power->battery_level = power->info.charge; power->event.type = PowerEventTypeBatteryLevelChanged; power->event.data.battery_level = power->battery_level; - notify_pubsub(&power->event_pubsub, &power->event); + furi_pubsub_publish(power->event_pubsub, &power->event); } } diff --git a/applications/power/power_service/power.h b/applications/power/power_service/power.h index d3dec410..947d917c 100644 --- a/applications/power/power_service/power.h +++ b/applications/power/power_service/power.h @@ -62,4 +62,4 @@ void power_get_info(Power* power, PowerInfo* info); /** Get power event pubsub handler * @param power - Power instance */ -PubSub* power_get_pubsub(Power* power); +FuriPubSub* power_get_pubsub(Power* power); diff --git a/applications/power/power_service/power_api.c b/applications/power/power_service/power_api.c index 46fa21ef..a3278f9b 100644 --- a/applications/power/power_service/power_api.c +++ b/applications/power/power_service/power_api.c @@ -1,4 +1,5 @@ #include "power_i.h" + #include #include "furi-hal-power.h" #include "furi-hal-bootloader.h" @@ -30,7 +31,7 @@ void power_get_info(Power* power, PowerInfo* info) { osMutexRelease(power->info_mtx); } -PubSub* power_get_pubsub(Power* power) { +FuriPubSub* power_get_pubsub(Power* power) { furi_assert(power); - return &power->event_pubsub; + return power->event_pubsub; } diff --git a/applications/power/power_service/power_i.h b/applications/power/power_service/power_i.h index 5bebd8cb..9833df5f 100755 --- a/applications/power/power_service/power_i.h +++ b/applications/power/power_service/power_i.h @@ -25,7 +25,7 @@ struct Power { ViewPort* battery_view_port; Gui* gui; NotificationApp* notification; - PubSub event_pubsub; + FuriPubSub* event_pubsub; PowerEvent event; PowerState state; diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index b8d6a979..80355e5e 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -45,6 +45,10 @@ static RpcSystemCallbacks rpc_systems[] = { .alloc = rpc_system_app_alloc, .free = NULL, }, + { + .alloc = rpc_system_gui_alloc, + .free = rpc_system_gui_free, + }, }; struct RpcSession { @@ -161,10 +165,10 @@ void rpc_print_message(const PB_Main* message) { case PB_Main_stop_session_tag: string_cat_printf(str, "\tstop_session {\r\n"); break; - case PB_Main_app_start_tag: { + case PB_Main_app_start_request_tag: { string_cat_printf(str, "\tapp_start {\r\n"); - const char* name = message->content.app_start.name; - const char* args = message->content.app_start.args; + const char* name = message->content.app_start_request.name; + const char* args = message->content.app_start_request.args; if(name) { string_cat_printf(str, "\t\tname: %s\r\n", name); } @@ -260,6 +264,22 @@ void rpc_print_message(const PB_Main* message) { string_cat_printf(str, "\tlist_response {\r\n"); rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count); } + case PB_Main_gui_start_screen_stream_request_tag: + string_cat_printf(str, "\tstart_screen_stream {\r\n"); + break; + case PB_Main_gui_stop_screen_stream_request_tag: + string_cat_printf(str, "\tstop_screen_stream {\r\n"); + break; + case PB_Main_gui_screen_stream_frame_tag: + string_cat_printf(str, "\tscreen_stream_frame {\r\n"); + break; + case PB_Main_gui_send_input_event_request_tag: + string_cat_printf(str, "\tsend_input_event {\r\n"); + string_cat_printf( + str, "\t\tkey: %d\r\n", message->content.gui_send_input_event_request.key); + string_cat_printf( + str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type); + break; } string_cat_printf(str, "\t}\r\n}\r\n"); printf("%s", string_get_cstr(str)); diff --git a/applications/rpc/rpc_app.c b/applications/rpc/rpc_app.c index d2c0cdc0..79ddee72 100644 --- a/applications/rpc/rpc_app.c +++ b/applications/rpc/rpc_app.c @@ -9,13 +9,13 @@ void rpc_system_app_start_process(const PB_Main* request, void* context) { Rpc* rpc = context; furi_assert(rpc); furi_assert(request); - furi_assert(request->which_content == PB_Main_app_start_tag); + furi_assert(request->which_content == PB_Main_app_start_request_tag); PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START; Loader* loader = furi_record_open("loader"); - const char* app_name = request->content.app_start.name; + const char* app_name = request->content.app_start_request.name; if(app_name) { - const char* app_args = request->content.app_start.args; + const char* app_args = request->content.app_start_request.args; LoaderStatus status = loader_start(loader, app_name, app_args); if(status == LoaderStatusErrorAppStarted) { result = PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED; @@ -70,7 +70,7 @@ void* rpc_system_app_alloc(Rpc* rpc) { }; rpc_handler.message_handler = rpc_system_app_start_process; - rpc_add_handler(rpc, PB_Main_app_start_tag, &rpc_handler); + rpc_add_handler(rpc, PB_Main_app_start_request_tag, &rpc_handler); rpc_handler.message_handler = rpc_system_app_lock_status_process; rpc_add_handler(rpc, PB_Main_app_lock_status_request_tag, &rpc_handler); diff --git a/applications/rpc/rpc_gui.c b/applications/rpc/rpc_gui.c new file mode 100644 index 00000000..10a0afd9 --- /dev/null +++ b/applications/rpc/rpc_gui.c @@ -0,0 +1,155 @@ +#include "flipper.pb.h" +#include "rpc_i.h" +#include "gui.pb.h" +#include + +typedef struct { + Rpc* rpc; + Gui* gui; +} RpcGuiSystem; + +void rpc_system_gui_screen_frame_callback(uint8_t* data, size_t size, void* context) { + furi_assert(data); + furi_assert(size == 1024); + furi_assert(context); + + RpcGuiSystem* rpc_gui = context; + + PB_Main* frame = furi_alloc(sizeof(PB_Main)); + + frame->which_content = PB_Main_gui_screen_stream_frame_tag; + frame->command_status = PB_CommandStatus_OK; + frame->content.gui_screen_stream_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size)); + uint8_t* buffer = frame->content.gui_screen_stream_frame.data->bytes; + uint16_t* frame_size_msg = &frame->content.gui_screen_stream_frame.data->size; + *frame_size_msg = size; + memcpy(buffer, data, size); + + rpc_send_and_release(rpc_gui->rpc, frame); + + free(frame); +} + +void rpc_system_gui_start_screen_stream_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + RpcGuiSystem* rpc_gui = context; + + rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); + + gui_set_framebuffer_callback(rpc_gui->gui, rpc_system_gui_screen_frame_callback, context); +} + +void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + RpcGuiSystem* rpc_gui = context; + + rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); + + gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); +} + +void rpc_system_gui_send_input_event_request_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_gui_send_input_event_request_tag); + furi_assert(context); + RpcGuiSystem* rpc_gui = context; + + InputEvent event; + + bool invalid = false; + + switch(request->content.gui_send_input_event_request.key) { + case PB_Gui_InputKey_UP: + event.key = InputKeyUp; + break; + case PB_Gui_InputKey_DOWN: + event.key = InputKeyDown; + break; + case PB_Gui_InputKey_RIGHT: + event.key = InputKeyRight; + break; + case PB_Gui_InputKey_LEFT: + event.key = InputKeyLeft; + break; + case PB_Gui_InputKey_OK: + event.key = InputKeyOk; + break; + case PB_Gui_InputKey_BACK: + event.key = InputKeyBack; + break; + default: + // Invalid key + invalid = true; + break; + } + + switch(request->content.gui_send_input_event_request.type) { + case PB_Gui_InputType_PRESS: + event.type = InputTypePress; + break; + case PB_Gui_InputType_RELEASE: + event.type = InputTypeRelease; + break; + case PB_Gui_InputType_SHORT: + event.type = InputTypeShort; + break; + case PB_Gui_InputType_LONG: + event.type = InputTypeLong; + break; + case PB_Gui_InputType_REPEAT: + event.type = InputTypeRepeat; + break; + default: + // Invalid type + invalid = true; + break; + } + + if(invalid) { + rpc_send_and_release_empty( + rpc_gui->rpc, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS); + return; + } + + FuriPubSub* input_events = furi_record_open("input_events"); + furi_check(input_events); + furi_pubsub_publish(input_events, &event); + furi_record_close("input_events"); + rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); +} + +void* rpc_system_gui_alloc(Rpc* rpc) { + furi_assert(rpc); + + RpcGuiSystem* rpc_gui = furi_alloc(sizeof(RpcGuiSystem)); + rpc_gui->gui = furi_record_open("gui"); + rpc_gui->rpc = rpc; + + RpcHandler rpc_handler = { + .message_handler = NULL, + .decode_submessage = NULL, + .context = rpc_gui, + }; + + rpc_handler.message_handler = rpc_system_gui_start_screen_stream_process; + rpc_add_handler(rpc, PB_Main_gui_start_screen_stream_request_tag, &rpc_handler); + + rpc_handler.message_handler = rpc_system_gui_stop_screen_stream_process; + rpc_add_handler(rpc, PB_Main_gui_stop_screen_stream_request_tag, &rpc_handler); + + rpc_handler.message_handler = rpc_system_gui_send_input_event_request_process; + rpc_add_handler(rpc, PB_Main_gui_send_input_event_request_tag, &rpc_handler); + + return rpc_gui; +} + +void rpc_system_gui_free(void* ctx) { + furi_assert(ctx); + RpcGuiSystem* rpc_gui = ctx; + furi_assert(rpc_gui->gui); + gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); + furi_record_close("gui"); + free(rpc_gui); +} \ No newline at end of file diff --git a/applications/rpc/rpc_i.h b/applications/rpc/rpc_i.h index 1bcf7c86..76df1e5a 100644 --- a/applications/rpc/rpc_i.h +++ b/applications/rpc/rpc_i.h @@ -1,5 +1,6 @@ #pragma once #include "rpc.h" +#include "storage/filesystem-api-defines.h" #include #include #include @@ -24,6 +25,10 @@ void* rpc_system_status_alloc(Rpc* rpc); void* rpc_system_storage_alloc(Rpc* rpc); void rpc_system_storage_free(void* ctx); void* rpc_system_app_alloc(Rpc* rpc); +void* rpc_system_gui_alloc(Rpc* rpc); +void rpc_system_gui_free(void* ctx); void rpc_print_message(const PB_Main* message); void rpc_cli_command_start_session(Cli* cli, string_t args, void* context); + +PB_CommandStatus rpc_system_storage_get_error(FS_Error fs_error); \ No newline at end of file diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index f8e0a97e..99844e5d 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -51,7 +51,7 @@ static void rpc_system_storage_reset_state(RpcStorageSystem* rpc_storage, bool s } } -static PB_CommandStatus rpc_system_storage_get_error(FS_Error fs_error) { +PB_CommandStatus rpc_system_storage_get_error(FS_Error fs_error) { PB_CommandStatus pb_error; switch(fs_error) { case FSE_OK: @@ -96,6 +96,40 @@ static PB_CommandStatus rpc_system_storage_get_file_error(File* file) { return rpc_system_storage_get_error(storage_file_get_error(file)); } +static void rpc_system_storage_stat_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_storage_stat_request_tag); + + RpcStorageSystem* rpc_storage = context; + rpc_system_storage_reset_state(rpc_storage, true); + + PB_Main* response = furi_alloc(sizeof(PB_Main)); + response->command_id = request->command_id; + + Storage* fs_api = furi_record_open("storage"); + + const char* path = request->content.storage_stat_request.path; + FileInfo fileinfo; + FS_Error error = storage_common_stat(fs_api, path, &fileinfo); + + response->command_status = rpc_system_storage_get_error(error); + response->which_content = PB_Main_empty_tag; + + if(error == FSE_OK) { + response->which_content = PB_Main_storage_stat_response_tag; + response->content.storage_stat_response.has_file = true; + response->content.storage_stat_response.file.type = (fileinfo.flags & FSF_DIRECTORY) ? + PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; + response->content.storage_stat_response.file.size = fileinfo.size; + } + + rpc_send_and_release(rpc_storage->rpc, response); + free(response); + furi_record_close("storage"); +} + static void rpc_system_storage_list_root(const PB_Main* request, void* context) { RpcStorageSystem* rpc_storage = context; const char* hard_coded_dirs[] = {"any", "int", "ext"}; @@ -140,11 +174,10 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex PB_Main response = { .command_id = request->command_id, .has_next = false, - .which_content = PB_Main_storage_list_request_tag, + .which_content = PB_Main_storage_list_response_tag, .command_status = PB_CommandStatus_OK, }; PB_Storage_ListResponse* list = &response.content.storage_list_response; - response.which_content = PB_Main_storage_list_response_tag; bool finish = false; int i = 0; @@ -434,6 +467,9 @@ void* rpc_system_storage_alloc(Rpc* rpc) { .context = rpc_storage, }; + rpc_handler.message_handler = rpc_system_storage_stat_process; + rpc_add_handler(rpc, PB_Main_storage_stat_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_storage_list_process; rpc_add_handler(rpc, PB_Main_storage_list_request_tag, &rpc_handler); diff --git a/applications/storage/storage-external-api.c b/applications/storage/storage-external-api.c index d74cbb77..7f275894 100644 --- a/applications/storage/storage-external-api.c +++ b/applications/storage/storage-external-api.c @@ -324,6 +324,11 @@ FS_Error storage_file_get_error(File* file) { return file->error_id; } +int32_t storage_file_get_internal_error(File* file) { + furi_check(file != NULL); + return file->internal_error_id; +} + const char* storage_file_get_error_desc(File* file) { furi_check(file != NULL); return filesystem_api_error_get_desc(file->error_id); diff --git a/applications/storage/storage-glue.h b/applications/storage/storage-glue.h index 775742cc..3a6cbe5c 100644 --- a/applications/storage/storage-glue.h +++ b/applications/storage/storage-glue.h @@ -1,8 +1,10 @@ #pragma once + #include #include "filesystem-api-internal.h" #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/applications/storage/storage.h b/applications/storage/storage.h index aabe8ddc..9351e155 100644 --- a/applications/storage/storage.h +++ b/applications/storage/storage.h @@ -197,6 +197,12 @@ const char* storage_error_get_desc(FS_Error error_id); */ FS_Error storage_file_get_error(File* file); +/** Retrieves the internal (storage-specific) error id from the file object + * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETREIVE THE INTERNAL ERROR ID IF THE FILE HAS BEEN CLOSED + * @return FS_Error error id + */ +int32_t storage_file_get_internal_error(File* file); + /** Retrieves the error text from the file object * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETREIVE THE ERROR TEXT IF THE FILE HAS BEEN CLOSED * @return const char* error text diff --git a/applications/storage/storages/storage-int.c b/applications/storage/storages/storage-int.c index fb4c07be..4a1dca7c 100644 --- a/applications/storage/storages/storage-int.c +++ b/applications/storage/storages/storage-int.c @@ -119,7 +119,7 @@ static int storage_int_device_erase(const struct lfs_config* c, lfs_block_t bloc LFSData* lfs_data = c->context; size_t page = lfs_data->start_page + block; - FURI_LOG_D(TAG, "Device erase: page %d, translated page: %d", block, page); + FURI_LOG_D(TAG, "Device erase: page %d, translated page: %x", block, page); if(furi_hal_flash_erase(page, 1)) { return 0; diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 63156717..5b497e45 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -188,7 +188,8 @@ SubGhz* subghz_alloc() { string_init(subghz->error_str); subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes"); - subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_floor_s_rx"); + subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes_user"); + subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_flor_s_rx"); subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/came_atomo"); //subghz_parser_enable_dump_text(subghz->protocol, subghz_text_callback, subghz); diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index 94c2cd03..62d070ef 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -3,26 +3,16 @@ #include #include #include + +#include #include +#include #include #include #define SUBGHZ_FREQUENCY_RANGE_STR \ "299999755...348000000 or 386999938...464000000 or 778999847...928000000" -void subghz_cli_init() { - Cli* cli = furi_record_open("cli"); - - cli_add_command( - cli, "subghz_tx_carrier", CliCommandFlagDefault, subghz_cli_command_tx_carrier, NULL); - cli_add_command( - cli, "subghz_rx_carrier", CliCommandFlagDefault, subghz_cli_command_rx_carrier, NULL); - cli_add_command(cli, "subghz_tx", CliCommandFlagDefault, subghz_cli_command_tx, NULL); - cli_add_command(cli, "subghz_rx", CliCommandFlagDefault, subghz_cli_command_rx, NULL); - - furi_record_close("cli"); -} - void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) { uint32_t frequency = 433920000; @@ -222,7 +212,9 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { SubGhzParser* parser = subghz_parser_alloc(); subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes"); - subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/nice_floor_s_rx"); + subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes_user"); + subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/nice_flor_s_rx"); + subghz_parser_load_came_atomo_file(parser, "/ext/subghz/came_atomo"); subghz_parser_enable_dump_text(parser, subghz_cli_command_rx_text_callback, instance); // Configure radio @@ -267,3 +259,131 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { vStreamBufferDelete(instance->stream); free(instance); } + +void subghz_cli_command_print_usage() { + printf("Usage:\r\n"); + printf("subghz \r\n"); + printf("Cmd list:\r\n"); + printf( + "\tencrypt_keeloq \t - Encrypt keeloq manufacture keys\r\n"); + printf( + "\tencrypt_raw \t - Encrypt RAW data\r\n"); +} + +void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) { + uint8_t iv[16]; + + string_t source; + string_t destination; + string_init(source); + string_init(destination); + + SubGhzKeystore* keystore = subghz_keystore_alloc(); + + do { + if(!args_read_string_and_trim(args, source)) { + subghz_cli_command_print_usage(); + break; + } + + if(!args_read_string_and_trim(args, destination)) { + subghz_cli_command_print_usage(); + break; + } + + if(!args_read_hex_bytes(args, iv, 16)) { + subghz_cli_command_print_usage(); + break; + } + + if(!subghz_keystore_load(keystore, string_get_cstr(source))) { + printf("Failed to load Keystore"); + break; + } + + if(!subghz_keystore_save(keystore, string_get_cstr(destination), iv)) { + printf("Failed to save Keystore"); + break; + } + } while(false); + + subghz_keystore_free(keystore); + string_clear(destination); + string_clear(source); +} + +void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) { + uint8_t iv[16]; + + string_t source; + string_t destination; + string_init(source); + string_init(destination); + + do { + if(!args_read_string_and_trim(args, source)) { + subghz_cli_command_print_usage(); + break; + } + + if(!args_read_string_and_trim(args, destination)) { + subghz_cli_command_print_usage(); + break; + } + + if(!args_read_hex_bytes(args, iv, 16)) { + subghz_cli_command_print_usage(); + break; + } + + if(!subghz_keystore_raw_encrypted_save( + string_get_cstr(source), string_get_cstr(destination), iv)) { + printf("Failed to save Keystore"); + break; + } + + } while(false); + + string_clear(destination); + string_clear(source); +} + +void subghz_cli_command(Cli* cli, string_t args, void* context) { + string_t cmd; + string_init(cmd); + + do { + if(!args_read_string_and_trim(args, cmd)) { + subghz_cli_command_print_usage(); + break; + } + + if(string_cmp_str(cmd, "encrypt_keeloq") == 0) { + subghz_cli_command_encrypt_keeloq(cli, args); + break; + } + + if(string_cmp_str(cmd, "encrypt_raw") == 0) { + subghz_cli_command_encrypt_raw(cli, args); + break; + } + + subghz_cli_command_print_usage(); + } while(false); + + string_clear(cmd); +} + +void subghz_cli_init() { + Cli* cli = furi_record_open("cli"); + + cli_add_command( + cli, "subghz_tx_carrier", CliCommandFlagDefault, subghz_cli_command_tx_carrier, NULL); + cli_add_command( + cli, "subghz_rx_carrier", CliCommandFlagDefault, subghz_cli_command_rx_carrier, NULL); + cli_add_command(cli, "subghz_tx", CliCommandFlagDefault, subghz_cli_command_tx, NULL); + cli_add_command(cli, "subghz_rx", CliCommandFlagDefault, subghz_cli_command_rx, NULL); + cli_add_command(cli, "subghz", CliCommandFlagDefault, subghz_cli_command, NULL); + + furi_record_close("cli"); +} diff --git a/applications/subghz/subghz_cli.h b/applications/subghz/subghz_cli.h index e6dc16a5..c70cbd21 100644 --- a/applications/subghz/subghz_cli.h +++ b/applications/subghz/subghz_cli.h @@ -3,15 +3,3 @@ #include void subghz_cli_init(); - -void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context); - -void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context); - -void subghz_cli_command_tx_pt(Cli* cli, string_t args, void* context); - -void subghz_cli_command_rx_pt(Cli* cli, string_t args, void* context); - -void subghz_cli_command_tx(Cli* cli, string_t args, void* context); - -void subghz_cli_command_rx(Cli* cli, string_t args, void* context); diff --git a/applications/tests/flipper_file/flipper_file_test.c b/applications/tests/flipper_file/flipper_file_test.c new file mode 100644 index 00000000..8d21bb42 --- /dev/null +++ b/applications/tests/flipper_file/flipper_file_test.c @@ -0,0 +1,500 @@ +#include +#include +#include "../minunit.h" + +#define TEST_DIR TEST_DIR_NAME "/" +#define TEST_DIR_NAME "/ext/unit_tests_tmp" + +static const char* test_filetype = "Flipper File test"; +static const uint32_t test_version = 666; + +static const char* test_string_key = "String data"; +static const char* test_string_data = "String"; +static const char* test_string_updated_data = "New string"; + +static const char* test_int_key = "Int32 data"; +static const int32_t test_int_data[] = {1234, -6345, 7813, 0}; +static const int32_t test_int_updated_data[] = {-1337, 69}; + +static const char* test_uint_key = "Uint32 data"; +static const uint32_t test_uint_data[] = {1234, 0, 5678, 9098, 7654321}; +static const uint32_t test_uint_updated_data[] = {8, 800, 555, 35, 35}; + +static const char* test_float_key = "Float data"; +static const float test_float_data[] = {1.5f, 1000.0f}; +static const float test_float_updated_data[] = {1.2f}; + +static const char* test_hex_key = "Hex data"; +static const uint8_t test_hex_data[] = {0xDE, 0xAD, 0xBE}; +static const uint8_t test_hex_updated_data[] = {0xFE, 0xCA}; + +#define READ_TEST_WIN "ff_win.test" +static const char* test_data_win = "Filetype: Flipper File test\n" + "Version: 666\n" + "# This is comment\n" + "String data: String\n" + "Int32 data: 1234 -6345 7813 0\n" + "Uint32 data: 1234 0 5678 9098 7654321\n" + "Float data: 1.5 1000.0\n" + "Hex data: DE AD BE"; + +#define READ_TEST_NIX "ff_nix.test" +static const char* test_data_nix = "Filetype: Flipper File test\r\n" + "Version: 666\r\n" + "# This is comment\r\n" + "String data: String\r\n" + "Int32 data: 1234 -6345 7813 0\r\n" + "Uint32 data: 1234 0 5678 9098 7654321\r\n" + "Float data: 1.5 1000.0\r\n" + "Hex data: DE AD BE"; + +#define READ_TEST_FLP "ff_flp.test" + +// data created by user on linux machine +const char* test_file_linux = TEST_DIR READ_TEST_WIN; +// data created by user on windows machine +const char* test_file_windows = TEST_DIR READ_TEST_NIX; +// data created by flipper itself +const char* test_file_flipper = TEST_DIR READ_TEST_FLP; + +static bool storage_write_string(const char* path, const char* data) { + Storage* storage = furi_record_open("storage"); + File* file = storage_file_alloc(storage); + bool result = false; + + do { + if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break; + if(storage_file_write(file, data, strlen(data)) != strlen(data)) break; + + result = true; + } while(false); + + storage_file_close(file); + storage_file_free(file); + furi_record_close("storage"); + + return result; +} + +static void tests_setup() { + Storage* storage = furi_record_open("storage"); + mu_assert(storage_simply_remove_recursive(storage, TEST_DIR_NAME), "Cannot clean data"); + mu_assert(storage_simply_mkdir(storage, TEST_DIR_NAME), "Cannot create dir"); + furi_record_close("storage"); +} + +static void tests_teardown() { + Storage* storage = furi_record_open("storage"); + mu_assert(storage_simply_remove_recursive(storage, TEST_DIR_NAME), "Cannot clean data"); + furi_record_close("storage"); +} + +static bool test_read(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + + FlipperFile* file = flipper_file_alloc(storage); + string_t string_value; + string_init(string_value); + uint32_t uint32_value; + void* scratchpad = malloc(512); + + do { + if(!flipper_file_open_existing(file, file_name)) break; + + if(!flipper_file_read_header(file, string_value, &uint32_value)) break; + if(string_cmp_str(string_value, test_filetype) != 0) break; + if(uint32_value != test_version) break; + + if(!flipper_file_read_string(file, test_string_key, string_value)) break; + if(string_cmp_str(string_value, test_string_data) != 0) break; + + if(!flipper_file_get_value_count(file, test_int_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_int_data)) break; + if(!flipper_file_read_int32(file, test_int_key, scratchpad, uint32_value)) break; + if(memcmp(scratchpad, test_int_data, sizeof(int32_t) * COUNT_OF(test_int_data)) != 0) + break; + + if(!flipper_file_get_value_count(file, test_uint_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_uint_data)) break; + if(!flipper_file_read_uint32(file, test_uint_key, scratchpad, uint32_value)) break; + if(memcmp(scratchpad, test_uint_data, sizeof(uint32_t) * COUNT_OF(test_uint_data)) != 0) + break; + + if(!flipper_file_get_value_count(file, test_float_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_float_data)) break; + if(!flipper_file_read_float(file, test_float_key, scratchpad, uint32_value)) break; + if(memcmp(scratchpad, test_float_data, sizeof(float) * COUNT_OF(test_float_data)) != 0) + break; + + if(!flipper_file_get_value_count(file, test_hex_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_hex_data)) break; + if(!flipper_file_read_hex(file, test_hex_key, scratchpad, uint32_value)) break; + if(memcmp(scratchpad, test_hex_data, sizeof(uint8_t) * COUNT_OF(test_hex_data)) != 0) + break; + + result = true; + } while(false); + + free(scratchpad); + string_clear(string_value); + flipper_file_close(file); + flipper_file_free(file); + + furi_record_close("storage"); + + return result; +} + +static bool test_read_updated(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + + FlipperFile* file = flipper_file_alloc(storage); + string_t string_value; + string_init(string_value); + uint32_t uint32_value; + void* scratchpad = malloc(512); + + do { + if(!flipper_file_open_existing(file, file_name)) break; + + if(!flipper_file_read_header(file, string_value, &uint32_value)) break; + if(string_cmp_str(string_value, test_filetype) != 0) break; + if(uint32_value != test_version) break; + + if(!flipper_file_read_string(file, test_string_key, string_value)) break; + if(string_cmp_str(string_value, test_string_updated_data) != 0) break; + + if(!flipper_file_get_value_count(file, test_int_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_int_updated_data)) break; + if(!flipper_file_read_int32(file, test_int_key, scratchpad, uint32_value)) break; + if(memcmp( + scratchpad, + test_int_updated_data, + sizeof(int32_t) * COUNT_OF(test_int_updated_data)) != 0) + break; + + if(!flipper_file_get_value_count(file, test_uint_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_uint_updated_data)) break; + if(!flipper_file_read_uint32(file, test_uint_key, scratchpad, uint32_value)) break; + if(memcmp( + scratchpad, + test_uint_updated_data, + sizeof(uint32_t) * COUNT_OF(test_uint_updated_data)) != 0) + break; + + if(!flipper_file_get_value_count(file, test_float_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_float_updated_data)) break; + if(!flipper_file_read_float(file, test_float_key, scratchpad, uint32_value)) break; + if(memcmp( + scratchpad, + test_float_updated_data, + sizeof(float) * COUNT_OF(test_float_updated_data)) != 0) + break; + + if(!flipper_file_get_value_count(file, test_hex_key, &uint32_value)) break; + if(uint32_value != COUNT_OF(test_hex_updated_data)) break; + if(!flipper_file_read_hex(file, test_hex_key, scratchpad, uint32_value)) break; + if(memcmp( + scratchpad, + test_hex_updated_data, + sizeof(uint8_t) * COUNT_OF(test_hex_updated_data)) != 0) + break; + + result = true; + } while(false); + + free(scratchpad); + string_clear(string_value); + flipper_file_close(file); + flipper_file_free(file); + + furi_record_close("storage"); + + return result; +} + +static bool test_write(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + do { + if(!flipper_file_open_always(file, file_name)) break; + if(!flipper_file_write_header_cstr(file, test_filetype, test_version)) break; + if(!flipper_file_write_comment_cstr(file, "This is comment")) break; + if(!flipper_file_write_string_cstr(file, test_string_key, test_string_data)) break; + if(!flipper_file_write_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data))) + break; + if(!flipper_file_write_uint32( + file, test_uint_key, test_uint_data, COUNT_OF(test_uint_data))) + break; + if(!flipper_file_write_float( + file, test_float_key, test_float_data, COUNT_OF(test_float_data))) + break; + if(!flipper_file_write_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data))) + break; + result = true; + } while(false); + + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +static bool test_delete_last_key(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + do { + if(!flipper_file_open_existing(file, file_name)) break; + if(!flipper_file_delete_key(file, test_hex_key)) break; + result = true; + } while(false); + + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +static bool test_append_key(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + do { + if(!flipper_file_open_append(file, file_name)) break; + if(!flipper_file_write_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data))) + break; + result = true; + } while(false); + + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +static bool test_update(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + do { + if(!flipper_file_open_existing(file, file_name)) break; + if(!flipper_file_update_string_cstr(file, test_string_key, test_string_updated_data)) + break; + if(!flipper_file_update_int32( + file, test_int_key, test_int_updated_data, COUNT_OF(test_int_updated_data))) + break; + if(!flipper_file_update_uint32( + file, test_uint_key, test_uint_updated_data, COUNT_OF(test_uint_updated_data))) + break; + if(!flipper_file_update_float( + file, test_float_key, test_float_updated_data, COUNT_OF(test_float_updated_data))) + break; + if(!flipper_file_update_hex( + file, test_hex_key, test_hex_updated_data, COUNT_OF(test_hex_updated_data))) + break; + + result = true; + } while(false); + + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +static bool test_update_backward(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + do { + if(!flipper_file_open_existing(file, file_name)) break; + if(!flipper_file_update_string_cstr(file, test_string_key, test_string_data)) break; + if(!flipper_file_update_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data))) + break; + if(!flipper_file_update_uint32( + file, test_uint_key, test_uint_data, COUNT_OF(test_uint_data))) + break; + if(!flipper_file_update_float( + file, test_float_key, test_float_data, COUNT_OF(test_float_data))) + break; + if(!flipper_file_update_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data))) + break; + + result = true; + } while(false); + + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +static bool test_write_multikey(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + do { + if(!flipper_file_open_always(file, file_name)) break; + if(!flipper_file_write_header_cstr(file, test_filetype, test_version)) break; + + bool error = false; + for(uint8_t index = 0; index < 100; index++) { + if(!flipper_file_write_hex(file, test_hex_key, &index, 1)) { + error = true; + break; + } + } + if(error) break; + + result = true; + } while(false); + + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +static bool test_read_multikey(const char* file_name) { + Storage* storage = furi_record_open("storage"); + bool result = false; + FlipperFile* file = flipper_file_alloc(storage); + + string_t string_value; + string_init(string_value); + uint32_t uint32_value; + + do { + if(!flipper_file_open_existing(file, file_name)) break; + if(!flipper_file_read_header(file, string_value, &uint32_value)) break; + if(string_cmp_str(string_value, test_filetype) != 0) break; + if(uint32_value != test_version) break; + + bool error = false; + uint8_t uint8_value; + for(uint8_t index = 0; index < 100; index++) { + if(!flipper_file_read_hex(file, test_hex_key, &uint8_value, 1)) { + error = true; + break; + } + + if(uint8_value != index) { + error = true; + break; + } + } + if(error) break; + + result = true; + } while(false); + + string_clear(string_value); + flipper_file_close(file); + flipper_file_free(file); + furi_record_close("storage"); + + return result; +} + +MU_TEST(flipper_file_write_test) { + mu_assert(storage_write_string(test_file_linux, test_data_nix), "Write test error [Linux]"); + mu_assert( + storage_write_string(test_file_windows, test_data_win), "Write test error [Windows]"); + mu_assert(test_write(test_file_flipper), "Write test error [Flipper]"); +} + +MU_TEST(flipper_file_read_test) { + mu_assert(test_read(test_file_linux), "Read test error [Linux]"); + mu_assert(test_read(test_file_windows), "Read test error [Windows]"); + mu_assert(test_read(test_file_flipper), "Read test error [Flipper]"); +} + +MU_TEST(flipper_file_delete_test) { + mu_assert(test_delete_last_key(test_file_linux), "Cannot delete key [Linux]"); + mu_assert(test_delete_last_key(test_file_windows), "Cannot delete key [Windows]"); + mu_assert(test_delete_last_key(test_file_flipper), "Cannot delete key [Flipper]"); +} + +MU_TEST(flipper_file_delete_result_test) { + mu_assert(!test_read(test_file_linux), "Key deleted incorrectly [Linux]"); + mu_assert(!test_read(test_file_windows), "Key deleted incorrectly [Windows]"); + mu_assert(!test_read(test_file_flipper), "Key deleted incorrectly [Flipper]"); +} + +MU_TEST(flipper_file_append_test) { + mu_assert(test_append_key(test_file_linux), "Cannot append data [Linux]"); + mu_assert(test_append_key(test_file_windows), "Cannot append data [Windows]"); + mu_assert(test_append_key(test_file_flipper), "Cannot append data [Flipper]"); +} + +MU_TEST(flipper_file_append_result_test) { + mu_assert(test_read(test_file_linux), "Data appended incorrectly [Linux]"); + mu_assert(test_read(test_file_windows), "Data appended incorrectly [Windows]"); + mu_assert(test_read(test_file_flipper), "Data appended incorrectly [Flipper]"); +} + +MU_TEST(flipper_file_update_1_test) { + mu_assert(test_update(test_file_linux), "Cannot update data #1 [Linux]"); + mu_assert(test_update(test_file_windows), "Cannot update data #1 [Windows]"); + mu_assert(test_update(test_file_flipper), "Cannot update data #1 [Flipper]"); +} + +MU_TEST(flipper_file_update_1_result_test) { + mu_assert(test_read_updated(test_file_linux), "Data #1 updated incorrectly [Linux]"); + mu_assert(test_read_updated(test_file_windows), "Data #1 updated incorrectly [Windows]"); + mu_assert(test_read_updated(test_file_flipper), "Data #1 updated incorrectly [Flipper]"); +} + +MU_TEST(flipper_file_update_2_test) { + mu_assert(test_update_backward(test_file_linux), "Cannot update data #2 [Linux]"); + mu_assert(test_update_backward(test_file_windows), "Cannot update data #2 [Windows]"); + mu_assert(test_update_backward(test_file_flipper), "Cannot update data #2 [Flipper]"); +} + +MU_TEST(flipper_file_update_2_result_test) { + mu_assert(test_read(test_file_linux), "Data #2 updated incorrectly [Linux]"); + mu_assert(test_read(test_file_windows), "Data #2 updated incorrectly [Windows]"); + mu_assert(test_read(test_file_flipper), "Data #2 updated incorrectly [Flipper]"); +} + +MU_TEST(flipper_file_multikey_test) { + mu_assert(test_write_multikey(TEST_DIR "ff_multiline.test"), "Multikey write test error"); + mu_assert(test_read_multikey(TEST_DIR "ff_multiline.test"), "Multikey read test error"); +} + +MU_TEST_SUITE(flipper_file) { + tests_setup(); + MU_RUN_TEST(flipper_file_write_test); + MU_RUN_TEST(flipper_file_read_test); + MU_RUN_TEST(flipper_file_delete_test); + MU_RUN_TEST(flipper_file_delete_result_test); + MU_RUN_TEST(flipper_file_append_test); + MU_RUN_TEST(flipper_file_append_result_test); + MU_RUN_TEST(flipper_file_update_1_test); + MU_RUN_TEST(flipper_file_update_1_result_test); + MU_RUN_TEST(flipper_file_update_2_test); + MU_RUN_TEST(flipper_file_update_2_result_test); + MU_RUN_TEST(flipper_file_multikey_test); + tests_teardown(); +} + +int run_minunit_test_flipper_file() { + MU_RUN_SUITE(flipper_file); + return MU_EXIT_CODE; +} \ No newline at end of file diff --git a/applications/tests/furi_pubsub_test.c b/applications/tests/furi_pubsub_test.c index d52b6bd3..010a00ab 100644 --- a/applications/tests/furi_pubsub_test.c +++ b/applications/tests/furi_pubsub_test.c @@ -16,39 +16,30 @@ void test_pubsub_handler(const void* arg, void* ctx) { } void test_furi_pubsub() { - bool result; - PubSub test_pubsub; - PubSubItem* test_pubsub_item; + FuriPubSub* test_pubsub = NULL; + FuriPubSubSubscription* test_pubsub_subscription = NULL; // init pubsub case - result = init_pubsub(&test_pubsub); - mu_assert(result, "init pubsub failed"); + test_pubsub = furi_pubsub_alloc(); + mu_assert_pointers_not_eq(test_pubsub, NULL); // subscribe pubsub case - test_pubsub_item = subscribe_pubsub(&test_pubsub, test_pubsub_handler, (void*)&context_value); - mu_assert_pointers_not_eq(test_pubsub_item, NULL); + test_pubsub_subscription = + furi_pubsub_subscribe(test_pubsub, test_pubsub_handler, (void*)&context_value); + mu_assert_pointers_not_eq(test_pubsub_subscription, NULL); /// notify pubsub case - result = notify_pubsub(&test_pubsub, (void*)¬ify_value_0); - mu_assert(result, "notify pubsub failed"); + furi_pubsub_publish(test_pubsub, (void*)¬ify_value_0); mu_assert_int_eq(pubsub_value, notify_value_0); mu_assert_int_eq(pubsub_context_value, context_value); // unsubscribe pubsub case - result = unsubscribe_pubsub(test_pubsub_item); - mu_assert(result, "unsubscribe pubsub failed"); - - result = unsubscribe_pubsub(test_pubsub_item); - mu_assert(!result, "unsubscribe pubsub not failed"); + furi_pubsub_unsubscribe(test_pubsub, test_pubsub_subscription); /// notify unsubscribed pubsub case - result = notify_pubsub(&test_pubsub, (void*)¬ify_value_1); - mu_assert(result, "notify pubsub failed"); + furi_pubsub_publish(test_pubsub, (void*)¬ify_value_1); mu_assert_int_not_eq(pubsub_value, notify_value_1); // delete pubsub case - result = delete_pubsub(&test_pubsub); - mu_assert(result, "unsubscribe pubsub failed"); - - // TODO test case that the pubsub_delete will remove pubsub from heap + furi_pubsub_free(test_pubsub); } \ No newline at end of file diff --git a/applications/tests/rpc/rpc_test.c b/applications/tests/rpc/rpc_test.c index 3f59cebf..51ed30cf 100644 --- a/applications/tests/rpc/rpc_test.c +++ b/applications/tests/rpc/rpc_test.c @@ -218,6 +218,9 @@ static void test_rpc_create_simple_message( message->which_content = tag; message->has_next = false; switch(tag) { + case PB_Main_storage_stat_request_tag: + message->content.storage_stat_request.path = str_copy; + break; case PB_Main_storage_list_request_tag: message->content.storage_list_request.path = str_copy; break; @@ -369,6 +372,19 @@ static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) { mu_check(result_locked == expected_locked); break; } + case PB_Main_storage_stat_response_tag: { + bool result_has_msg_file = result->content.storage_stat_response.has_file; + bool expected_has_msg_file = expected->content.storage_stat_response.has_file; + mu_check(result_has_msg_file == expected_has_msg_file); + + if(result_has_msg_file) { + PB_Storage_File* result_msg_file = &result->content.storage_stat_response.file; + PB_Storage_File* expected_msg_file = &expected->content.storage_stat_response.file; + test_rpc_compare_file(result_msg_file, expected_msg_file); + } else { + mu_check(0); + } + } break; case PB_Main_storage_read_response_tag: { bool result_has_msg_file = result->content.storage_read_response.has_file; bool expected_has_msg_file = expected->content.storage_read_response.has_file; @@ -455,11 +471,10 @@ static void test_rpc_storage_list_create_expected_list( PB_Main response = { .command_id = command_id, .has_next = false, - .which_content = PB_Main_storage_list_request_tag, + .which_content = PB_Main_storage_list_response_tag, /* other fields (e.g. msg_files ptrs) explicitly initialized by 0 */ }; PB_Storage_ListResponse* list = &response.content.storage_list_response; - response.which_content = PB_Main_storage_list_response_tag; bool finish = false; int i = 0; @@ -649,9 +664,8 @@ static bool test_is_exists(const char* path) { Storage* fs_api = furi_record_open("storage"); FileInfo fileinfo; FS_Error result = storage_common_stat(fs_api, path, &fileinfo); - furi_check((result == FSE_OK) || (result == FSE_NOT_EXIST)); - + furi_record_close("storage"); return result == FSE_OK; } @@ -687,6 +701,59 @@ static void test_create_file(const char* path, size_t size) { furi_check(test_is_exists(path)); } +static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) { + PB_Main request; + MsgList_t expected_msg_list; + MsgList_init(expected_msg_list); + + test_rpc_create_simple_message(&request, PB_Main_storage_stat_request_tag, path, command_id); + + Storage* fs_api = furi_record_open("storage"); + FileInfo fileinfo; + FS_Error error = storage_common_stat(fs_api, path, &fileinfo); + furi_record_close("storage"); + + PB_Main* response = MsgList_push_new(expected_msg_list); + response->command_id = command_id; + response->command_status = rpc_system_storage_get_error(error); + response->has_next = false; + response->which_content = PB_Main_empty_tag; + + if(error == FSE_OK) { + response->which_content = PB_Main_storage_stat_response_tag; + response->content.storage_stat_response.has_file = true; + response->content.storage_stat_response.file.type = (fileinfo.flags & FSF_DIRECTORY) ? + PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; + response->content.storage_stat_response.file.size = fileinfo.size; + } + + test_rpc_encode_and_feed_one(&request); + test_rpc_decode_and_compare(expected_msg_list); + + pb_release(&PB_Main_msg, &request); + test_rpc_free_msg_list(expected_msg_list); +} + +#define TEST_DIR_STAT_NAME TEST_DIR "stat_dir" +#define TEST_DIR_STAT TEST_DIR_STAT_NAME "/" +MU_TEST(test_storage_stat) { + test_create_dir(TEST_DIR_STAT_NAME); + test_create_file(TEST_DIR_STAT "empty.txt", 0); + test_create_file(TEST_DIR_STAT "l33t.txt", 1337); + + test_rpc_storage_stat_run("/", ++command_id); + test_rpc_storage_stat_run("/int", ++command_id); + test_rpc_storage_stat_run("/ext", ++command_id); + + test_rpc_storage_stat_run(TEST_DIR_STAT "empty.txt", ++command_id); + test_rpc_storage_stat_run(TEST_DIR_STAT "l33t.txt", ++command_id); + test_rpc_storage_stat_run(TEST_DIR_STAT "missing", ++command_id); + test_rpc_storage_stat_run(TEST_DIR_STAT_NAME, ++command_id); + + test_rpc_storage_stat_run(TEST_DIR_STAT, ++command_id); +} + MU_TEST(test_storage_read) { test_create_file(TEST_DIR "empty.txt", 0); test_create_file(TEST_DIR "file1.txt", 1); @@ -1138,6 +1205,7 @@ MU_TEST_SUITE(test_rpc_status) { MU_TEST_SUITE(test_rpc_storage) { MU_SUITE_CONFIGURE(&test_rpc_storage_setup, &test_rpc_storage_teardown); + MU_RUN_TEST(test_storage_stat); MU_RUN_TEST(test_storage_list); MU_RUN_TEST(test_storage_read); MU_RUN_TEST(test_storage_write_read); @@ -1158,23 +1226,23 @@ static void test_app_create_request( request->command_id = command_id; request->command_status = PB_CommandStatus_OK; request->cb_content.funcs.encode = NULL; - request->which_content = PB_Main_app_start_tag; + request->which_content = PB_Main_app_start_request_tag; request->has_next = false; if(app_name) { char* msg_app_name = furi_alloc(strlen(app_name) + 1); strcpy(msg_app_name, app_name); - request->content.app_start.name = msg_app_name; + request->content.app_start_request.name = msg_app_name; } else { - request->content.app_start.name = NULL; + request->content.app_start_request.name = NULL; } if(app_args) { char* msg_app_args = furi_alloc(strlen(app_args) + 1); strcpy(msg_app_args, app_args); - request->content.app_start.args = msg_app_args; + request->content.app_start_request.args = msg_app_args; } else { - request->content.app_start.args = NULL; + request->content.app_start_request.args = NULL; } } diff --git a/applications/tests/test_index.c b/applications/tests/test_index.c index d55a1e45..f436c0ef 100644 --- a/applications/tests/test_index.c +++ b/applications/tests/test_index.c @@ -1,4 +1,5 @@ #include "m-string.h" + #include #include #include @@ -12,6 +13,7 @@ int run_minunit(); int run_minunit_test_irda_decoder_encoder(); int run_minunit_test_rpc(); +int run_minunit_test_flipper_file(); void minunit_print_progress(void) { static char progress[] = {'\\', '|', '/', '-'}; @@ -36,11 +38,9 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { minunit_status = 0; Loader* loader = furi_record_open("loader"); - furi_record_close("loader"); - NotificationApp* notification = furi_record_open("notification"); - furi_record_close("notification"); + // TODO: lock device while test running if(loader_is_locked(loader)) { FURI_LOG_E(TESTS_TAG, "RPC: stop all applications to run tests"); notification_message(notification, &sequence_blink_magenta_100); @@ -48,10 +48,15 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { notification_message_block(notification, &sequence_set_only_blue_255); uint32_t heap_before = memmgr_get_free_heap(); + uint32_t cycle_counter = DWT->CYCCNT; test_result |= run_minunit(); test_result |= run_minunit_test_irda_decoder_encoder(); test_result |= run_minunit_test_rpc(); + test_result |= run_minunit_test_flipper_file(); + cycle_counter = (DWT->CYCCNT - cycle_counter); + + FURI_LOG_I(TESTS_TAG, "Consumed: %0.2fs", (float)cycle_counter / (SystemCoreClock)); if(test_result == 0) { delay(200); /* wait for tested services and apps to deallocate */ @@ -68,10 +73,15 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { FURI_LOG_E(TESTS_TAG, "FAILED"); } } + + furi_record_close("notification"); + furi_record_close("loader"); } void unit_tests_cli_init() { Cli* cli = furi_record_open("cli"); + + // We need to launch apps from tests, so we cannot lock loader cli_add_command(cli, "unit_tests", CliCommandFlagParallelSafe, unit_tests_cli, NULL); furi_record_close("cli"); } diff --git a/assets/compiled/application.pb.c b/assets/compiled/application.pb.c index 097a57b0..a50850b2 100644 --- a/assets/compiled/application.pb.c +++ b/assets/compiled/application.pb.c @@ -6,7 +6,7 @@ #error Regenerate this file with the current version of nanopb generator. #endif -PB_BIND(PB_App_Start, PB_App_Start, AUTO) +PB_BIND(PB_App_StartRequest, PB_App_StartRequest, AUTO) PB_BIND(PB_App_LockStatusRequest, PB_App_LockStatusRequest, AUTO) diff --git a/assets/compiled/application.pb.h b/assets/compiled/application.pb.h index b7a053f3..4b05c46b 100644 --- a/assets/compiled/application.pb.h +++ b/assets/compiled/application.pb.h @@ -14,10 +14,10 @@ typedef struct _PB_App_LockStatusRequest { char dummy_field; } PB_App_LockStatusRequest; -typedef struct _PB_App_Start { +typedef struct _PB_App_StartRequest { char *name; char *args; -} PB_App_Start; +} PB_App_StartRequest; typedef struct _PB_App_LockStatusResponse { bool locked; @@ -29,24 +29,24 @@ extern "C" { #endif /* Initializer values for message structs */ -#define PB_App_Start_init_default {NULL, NULL} +#define PB_App_StartRequest_init_default {NULL, NULL} #define PB_App_LockStatusRequest_init_default {0} #define PB_App_LockStatusResponse_init_default {0} -#define PB_App_Start_init_zero {NULL, NULL} +#define PB_App_StartRequest_init_zero {NULL, NULL} #define PB_App_LockStatusRequest_init_zero {0} #define PB_App_LockStatusResponse_init_zero {0} /* Field tags (for use in manual encoding/decoding) */ -#define PB_App_Start_name_tag 1 -#define PB_App_Start_args_tag 2 +#define PB_App_StartRequest_name_tag 1 +#define PB_App_StartRequest_args_tag 2 #define PB_App_LockStatusResponse_locked_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_App_Start_FIELDLIST(X, a) \ +#define PB_App_StartRequest_FIELDLIST(X, a) \ X(a, POINTER, SINGULAR, STRING, name, 1) \ X(a, POINTER, SINGULAR, STRING, args, 2) -#define PB_App_Start_CALLBACK NULL -#define PB_App_Start_DEFAULT NULL +#define PB_App_StartRequest_CALLBACK NULL +#define PB_App_StartRequest_DEFAULT NULL #define PB_App_LockStatusRequest_FIELDLIST(X, a) \ @@ -58,17 +58,17 @@ X(a, STATIC, SINGULAR, BOOL, locked, 1) #define PB_App_LockStatusResponse_CALLBACK NULL #define PB_App_LockStatusResponse_DEFAULT NULL -extern const pb_msgdesc_t PB_App_Start_msg; +extern const pb_msgdesc_t PB_App_StartRequest_msg; extern const pb_msgdesc_t PB_App_LockStatusRequest_msg; extern const pb_msgdesc_t PB_App_LockStatusResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define PB_App_Start_fields &PB_App_Start_msg +#define PB_App_StartRequest_fields &PB_App_StartRequest_msg #define PB_App_LockStatusRequest_fields &PB_App_LockStatusRequest_msg #define PB_App_LockStatusResponse_fields &PB_App_LockStatusResponse_msg /* Maximum encoded size of messages (where known) */ -/* PB_App_Start_size depends on runtime parameters */ +/* PB_App_StartRequest_size depends on runtime parameters */ #define PB_App_LockStatusRequest_size 0 #define PB_App_LockStatusResponse_size 2 diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index a94686f4..a9fe403d 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -2,12 +2,12 @@ #include -const uint8_t _I_Certification1_103x23_0[] = {0x01,0x00,0x98,0x00,0x9f,0xff,0xbe,0x30,0x38,0x04,0xf2,0x01,0xe0,0x80,0x82,0x87,0xf9,0x01,0x06,0x24,0xfe,0x01,0xf8,0x80,0xfe,0x21,0xff,0xf8,0x3c,0xff,0x9c,0x0c,0x1e,0x00,0x30,0x7f,0xc0,0xc1,0xe3,0xc0,0xe3,0xd0,0x7e,0x75,0xc4,0x46,0x30,0x70,0xd9,0x46,0x3c,0x10,0x09,0xc0,0x30,0xfe,0x10,0x1c,0x04,0x3c,0x18,0x37,0x08,0x05,0xc0,0x18,0x77,0x88,0x07,0x00,0x6e,0x31,0x89,0x87,0xe2,0x00,0x0c,0x39,0xc0,0x30,0x49,0x83,0x18,0x8c,0x7f,0xa0,0x60,0xc3,0x2c,0xa0,0x30,0x60,0xe0,0x01,0x06,0x14,0x70,0x18,0x26,0x51,0x8c,0x43,0x20,0x70,0x20,0x64,0xe3,0x03,0xa2,0x74,0x10,0x62,0x5f,0xce,0xc3,0x8f,0x06,0x78,0x31,0xc4,0xc6,0x33,0xc2,0x6f,0x99,0xf5,0x03,0x89,0xb7,0xb0,0x2d,0x7d,0x9f,0x2e,0x98,0x8c,0x0a,0x86,0x3c,0x0c,0x30,0xb9,0x7e,0x20,0x30,0x88,0x07,0xfe,0x0e,0x0c,0x42,0xda,0x40,0x3f,0x90,0x10,}; -const uint8_t *_I_Certification1_103x23[] = {_I_Certification1_103x23_0}; - const uint8_t _I_Certification2_119x30_0[] = {0x01,0x00,0x3c,0x01,0x00,0x5c,0x06,0x01,0x40,0x07,0x5e,0x0b,0xff,0x20,0x07,0x5d,0x92,0x01,0x13,0x03,0xa4,0x70,0x06,0x5f,0xe0,0x10,0xc6,0x20,0x10,0xc8,0x1c,0xce,0x70,0x07,0x19,0xf0,0x08,0x70,0x10,0x18,0x1c,0x03,0xe1,0xff,0x83,0x83,0x84,0x34,0x57,0xf0,0x10,0xd8,0x03,0x23,0x00,0x1c,0x8c,0x08,0x1c,0x30,0xf0,0xc8,0xf8,0xc1,0xc3,0x10,0x00,0x90,0x48,0x60,0x70,0x3d,0x98,0x90,0x70,0x1c,0x10,0x70,0xc2,0x03,0x65,0xa0,0xc0,0x07,0x47,0xe6,0x6d,0x1e,0x07,0x04,0x06,0x20,0xe3,0x90,0x5f,0x41,0xc9,0xe0,0xc0,0x08,0x46,0x09,0x18,0x41,0x0c,0x82,0x44,0x0e,0x11,0x61,0x5c,0x27,0xd0,0x70,0x70,0xc5,0xc1,0xc3,0x40,0x8a,0x17,0x84,0x94,0x53,0x0a,0x0c,0x1a,0x01,0xe2,0x88,0x7e,0x01,0xc3,0x08,0x80,0xff,0xcd,0x05,0xb8,0x80,0x43,0xa0,0x11,0xe8,0x80,0x84,0x43,0xa5,0xfe,0x98,0xa1,0x86,0xb9,0x00,0x8e,0x9c,0x47,0xe0,0x5d,0x1a,0x04,0x88,0x8e,0x20,0x02,0x97,0x60,0x27,0x40,0xe1,0x03,0x95,0x02,0x82,0x0e,0x49,0x35,0x0a,0x65,0x00,0xe1,0x28,0x04,0xfe,0x38,0x05,0xc8,0xf8,0xe3,0xf0,0x09,0x3c,0x8a,0xe4,0x0e,0x4e,0x02,0xe0,0x7f,0xff,0x39,0xfe,0x02,0x47,0x14,0xf1,0x0b,0x13,0x41,0xc0,0x52,0x0c,0xc2,0x61,0xc0,0x90,0xc3,0x38,0x50,0x1e,0x27,0xfe,0x8f,0x00,0xc8,0x48,0x20,0xc0,0xe3,0x40,0x0e,0x04,0x1c,0x98,0x8d,0x04,0x28,0x1c,0x4a,0x31,0x00,0x0c,0x0e,0x11,0x38,0x59,0x8c,0x12,0x7f,0x12,0x81,0xfc,0x27,0xf7,0x08,0x05,0x06,0x01,0x07,0x07,0x1c,0x08,0x6c,0x20,0xe2,0x98,0x40,0x27,0xd0,0x08,0x34,0x42,0x70,0xef,0x13,0xa8,0xd0,0x05,0x84,0x1d,0x10,0x00,0xc1,0xdf,0x43,0x0c,0x41,0x1a,0xcc,0x47,0x63,0xff,0x00,0x0c,0x0c,0xe4,0x2d,0x91,0x00,0x17,0xf8,0x1c,0x3c,0x00,0x71,0x09,0xc7,0xfc,0x0d,0x30,0x06,0x7f,0x3f,0xea,0x11,0x07,0x78,0x3b,0xc1,0xd6,}; const uint8_t *_I_Certification2_119x30[] = {_I_Certification2_119x30_0}; +const uint8_t _I_Certification1_103x23_0[] = {0x01,0x00,0x98,0x00,0x9f,0xff,0xbe,0x30,0x38,0x04,0xf2,0x01,0xe0,0x80,0x82,0x87,0xf9,0x01,0x06,0x24,0xfe,0x01,0xf8,0x80,0xfe,0x21,0xff,0xf8,0x3c,0xff,0x9c,0x0c,0x1e,0x00,0x30,0x7f,0xc0,0xc1,0xe3,0xc0,0xe3,0xd0,0x7e,0x75,0xc4,0x46,0x30,0x70,0xd9,0x46,0x3c,0x10,0x09,0xc0,0x30,0xfe,0x10,0x1c,0x04,0x3c,0x18,0x37,0x08,0x05,0xc0,0x18,0x77,0x88,0x07,0x00,0x6e,0x31,0x89,0x87,0xe2,0x00,0x0c,0x39,0xc0,0x30,0x49,0x83,0x18,0x8c,0x7f,0xa0,0x60,0xc3,0x2c,0xa0,0x30,0x60,0xe0,0x01,0x06,0x14,0x70,0x18,0x26,0x51,0x8c,0x43,0x20,0x70,0x20,0x64,0xe3,0x03,0xa2,0x74,0x10,0x62,0x5f,0xce,0xc3,0x8f,0x06,0x78,0x31,0xc4,0xc6,0x33,0xc2,0x6f,0x99,0xf5,0x03,0x89,0xb7,0xb0,0x2d,0x7d,0x9f,0x2e,0x98,0x8c,0x0a,0x86,0x3c,0x0c,0x30,0xb9,0x7e,0x20,0x30,0x88,0x07,0xfe,0x0e,0x0c,0x42,0xda,0x40,0x3f,0x90,0x10,}; +const uint8_t *_I_Certification1_103x23[] = {_I_Certification1_103x23_0}; + const uint8_t _A_WatchingTV_128x64_0[] = {0x01,0x00,0x32,0x02,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0x80,0x01,0x15,0x04,0x21,0x70,0x18,0x05,0x02,0x42,0x09,0x5f,0xfc,0x7c,0x0a,0x70,0x20,0x78,0xc4,0x41,0xc9,0xc0,0x80,0x58,0x01,0xf9,0x20,0x1d,0x98,0x00,0x60,0x80,0x81,0x84,0x83,0xd2,0x20,0x3b,0x30,0x00,0xc2,0x01,0xe3,0x06,0x07,0xa0,0x20,0x45,0x64,0x16,0x30,0x7b,0x0a,0x04,0x04,0x60,0xf3,0x85,0x03,0xd0,0x38,0x42,0x22,0x23,0x14,0x80,0x9e,0xa0,0xf2,0x21,0x11,0x74,0x60,0x1a,0x00,0x90,0xa2,0x14,0x1e,0x86,0x41,0xa8,0x04,0x84,0x1e,0xc1,0x83,0x07,0x8c,0xc0,0xee,0x80,0xf7,0x03,0x88,0x3c,0x6f,0xfe,0x00,0xb9,0x40,0xf0,0x10,0xf0,0x7a,0x40,0x86,0xa3,0x80,0xcf,0x83,0xcc,0x06,0x2b,0x04,0x82,0x46,0x1c,0xaa,0x0f,0x22,0x42,0x41,0x22,0x80,0x84,0x07,0x8f,0x82,0x7e,0x1f,0x48,0x44,0x90,0x1e,0x9c,0x08,0x0c,0x82,0xce,0x1f,0x48,0x84,0x88,0x06,0x33,0x01,0xd9,0xd8,0x34,0xfa,0x00,0x79,0xfe,0x28,0xe0,0x31,0x86,0x00,0x84,0x8a,0x3c,0x0a,0x9f,0x04,0x1e,0x70,0x6a,0xc0,0x0c,0x49,0x64,0x12,0x1c,0x06,0xbc,0x3e,0x90,0x11,0x48,0xfc,0x02,0xc6,0x02,0x1a,0x87,0x41,0x3e,0x94,0x0f,0xc4,0x3c,0x0e,0x42,0x22,0x64,0x8b,0x3d,0x30,0x0f,0x63,0x57,0x1c,0x00,0x3e,0x5f,0xff,0xfc,0x3c,0x1e,0x83,0x22,0x40,0x8e,0xa0,0x08,0x35,0x5a,0xaf,0xd4,0x24,0x21,0x31,0x80,0x6b,0x8e,0x25,0x04,0xea,0x01,0xc7,0x54,0x00,0x48,0x76,0x03,0xaa,0x0f,0x18,0xe4,0x02,0xf1,0x35,0x0f,0x90,0x00,0xe1,0xfc,0x0d,0x57,0xff,0xc2,0x51,0x18,0x65,0xa8,0x3e,0xbe,0xa8,0x55,0x83,0x03,0x01,0x8f,0x1d,0xc6,0x0d,0xd4,0x0f,0xad,0xd6,0x1a,0xf9,0x10,0xe8,0xbd,0xc4,0xa0,0x30,0x10,0xfa,0x6b,0xa1,0x40,0xf1,0x25,0x0c,0xbb,0x01,0x01,0xa8,0x40,0xc3,0xe9,0x57,0x9e,0xcf,0xb0,0x06,0x61,0x82,0xd0,0x20,0x3a,0x88,0x10,0xf9,0x35,0x5c,0xa9,0x0e,0x00,0x0c,0x30,0x24,0xf0,0x87,0xc4,0xf8,0x5f,0xfb,0xfd,0x54,0x7e,0x38,0x01,0x28,0xc0,0x53,0xc3,0xe8,0x83,0xe2,0x00,0x05,0xb8,0xd5,0x0f,0xc6,0x80,0x1e,0x13,0x58,0xbd,0x06,0x30,0x3e,0x40,0xf9,0x31,0x85,0x56,0x50,0x08,0x24,0x82,0x44,0x00,0x1d,0x16,0xcc,0x3e,0x34,0x00,0x79,0x60,0x11,0xa3,0x02,0x90,0x1f,0x4c,0x04,0x30,0xdc,0x00,0x3c,0xa8,0x17,0xd7,0x20,0xd0,0x07,0xc5,0x98,0x1f,0x94,0x02,0x42,0xfd,0x2a,0x3e,0x00,0x26,0x23,0xe4,0x0f,0x8c,0x02,0x7c,0xfd,0x2a,0x00,0x3c,0x8d,0xc5,0x23,0xd9,0x07,0xc8,0x00,0x56,0xa2,0x21,0x28,0x84,0x04,0x22,0x22,0x0f,0x88,0xf8,0xa6,0xa0,0xf6,0x3f,0x98,0x3c,0xb4,0x11,0xaa,0x03,0x14,0x43,0xf5,0x54,0x8a,0x83,0xce,0x63,0xfc,0xc7,0xc8,0x87,0xe8,0xc0,0x14,0x20,0xbc,0x47,0x01,0x49,0x81,0x64,0x03,0xeb,0x50,0x42,0x10,0x3d,0x47,0xe5,0x2a,0x0f,0x16,0xaa,0x1d,0x80,0x84,0x0b,0xc8,0x3e,0x95,0xd6,0x31,0x92,0x86,0x0e,0x4f,0x20,0x78,0x8f,0xcb,0xed,0xaa,0xf5,0x21,0xc4,0x1e,0x30,0x43,0xa0,0xc4,0x49,0xe2,0x1a,0x2c,0x2f,0x5e,0x3e,0x41,0x18,0xf0,0x3c,0xe5,0x27,0xf4,0x83,0x5b,0x0e,0x04,0x6d,0x10,0x78,0xc8,0x01,0xe4,0x1f,0x28,0x2c,0xe1,0x40,0x60,0xf3,0x8a,0x83,0xc4,0x7e,0x50,0x63,0x48,0xa0,0x48,0x1e,0x70,0xb0,0xfa,0x83,0xce,0x01,0x03,0x07,0x8c,0x40,}; const uint8_t _A_WatchingTV_128x64_1[] = {0x01,0x00,0x4a,0x02,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0x80,0x01,0x0f,0x02,0x80,0x10,0xb8,0x0c,0x03,0x41,0x20,0x04,0xaf,0xfe,0x3e,0x05,0x38,0x14,0x03,0xc1,0x10,0x07,0x27,0x02,0xab,0x75,0x07,0xae,0x80,0x1e,0xba,0x0d,0x56,0xa8,0x0c,0x70,0x48,0x05,0x42,0x12,0x0f,0x40,0xa8,0xd4,0x07,0x62,0x00,0x18,0x44,0x03,0x61,0x05,0x07,0xa0,0x20,0x74,0x02,0xb1,0x0b,0x20,0x18,0xc5,0x07,0x40,0x0c,0x18,0x3c,0x76,0x10,0x70,0x7a,0x05,0x47,0x01,0x0a,0x03,0x11,0xb0,0x47,0xec,0x25,0x28,0xa8,0x18,0x91,0x83,0xb0,0x2f,0xa9,0x30,0xa3,0x4a,0x04,0xac,0x23,0xd4,0x1e,0x53,0x40,0x7a,0x4a,0x38,0x1f,0xf0,0x7b,0x4a,0x00,0xe9,0x38,0x01,0x8e,0x0e,0x06,0x17,0x18,0x1e,0x02,0x1f,0x30,0x23,0xa4,0x60,0x06,0x3f,0xc2,0xe1,0x04,0x86,0x01,0x60,0x3b,0xa0,0x3c,0x8d,0x86,0x0f,0x2a,0x80,0x3d,0x22,0x83,0xc4,0x07,0x8f,0x83,0x7e,0x1f,0x48,0x44,0x90,0xa8,0x6d,0xe1,0x80,0xf8,0x2c,0xf5,0x16,0x3a,0x48,0x90,0x86,0x3b,0x2b,0x06,0x9f,0x40,0x0f,0x3f,0xc5,0x1c,0x06,0x25,0x82,0x22,0x8f,0x02,0xa7,0xd1,0x07,0x9c,0x1a,0xb0,0x03,0x18,0x60,0x08,0xf0,0x1a,0xf0,0xfa,0x40,0x6c,0x1f,0x0f,0xf9,0x6c,0xa0,0xc5,0xe2,0xe8,0x27,0xd2,0x80,0xf9,0x10,0x01,0x04,0x8a,0x01,0xa8,0x67,0xa6,0x01,0xf2,0x2a,0xe5,0x80,0x75,0x00,0x43,0xff,0xff,0xc3,0xc1,0xe9,0xf0,0x14,0x94,0x0f,0x54,0x04,0x1a,0xad,0x57,0xea,0x12,0x10,0x98,0xc0,0x35,0xc7,0x12,0x82,0x75,0x00,0xe3,0xaa,0x00,0x24,0x3b,0x01,0xd5,0x07,0x8c,0x72,0x01,0x7a,0x9a,0x87,0xc8,0x00,0x70,0xfe,0x06,0xab,0xff,0xe1,0x28,0x8e,0xb6,0xd4,0x1f,0x5f,0x54,0x2a,0xc1,0xd5,0x80,0xc7,0xac,0x18,0x0a,0xb0,0x94,0x43,0xc9,0x75,0x86,0xe8,0x35,0x41,0xd1,0xa8,0x50,0x30,0x7a,0xa8,0x08,0x7d,0x35,0xc1,0xf1,0xa0,0x12,0x86,0x5d,0xa0,0x80,0xd5,0x60,0x61,0xf4,0xab,0xcf,0x67,0xd8,0x03,0x30,0xc5,0x6a,0x01,0xd1,0x81,0x0f,0x93,0x55,0xca,0x90,0xe0,0x00,0xc3,0x0a,0x4f,0x08,0x7c,0x4f,0x85,0xff,0xbf,0xd5,0x61,0xb2,0x0c,0x00,0x94,0x60,0xa4,0xd1,0xf5,0x41,0xf1,0x00,0x02,0xdc,0x06,0x86,0x40,0x70,0x1d,0x56,0x09,0x3c,0x31,0xd8,0xc0,0xf9,0x03,0xe5,0x40,0x0f,0x08,0x08,0x5c,0x83,0x20,0x91,0x00,0x07,0x45,0xb3,0x0f,0x8d,0x01,0xac,0x30,0x0d,0x02,0x34,0x60,0x72,0x03,0xe9,0x80,0x86,0x1b,0x80,0x07,0x95,0x42,0xfa,0xe4,0x1a,0x00,0xf8,0xb3,0x03,0xf2,0x80,0x48,0x5f,0xa5,0x47,0xc0,0x3f,0x44,0x7c,0x81,0xf1,0x80,0x4f,0x81,0xe3,0xd5,0xa0,0x03,0xc8,0xdc,0x52,0x3d,0x90,0x7c,0x87,0xc6,0x44,0x2c,0x04,0x04,0x04,0x22,0x22,0x0f,0x88,0xf8,0xa6,0xa0,0xf6,0x3f,0x98,0x3c,0xb5,0x51,0xaa,0x04,0x80,0x3f,0x44,0x91,0x8a,0x83,0xce,0x63,0xfc,0xc7,0xc8,0x87,0xe9,0xa8,0x42,0x14,0x40,0x1e,0x34,0x98,0x16,0x40,0x3e,0x51,0xd3,0x41,0xa1,0x04,0x1e,0xa3,0xf2,0x00,0x24,0x3b,0x01,0x08,0x17,0x90,0x7d,0x2b,0xac,0x63,0x25,0x0c,0x1c,0x9e,0x40,0xf1,0x1f,0x97,0xdb,0x55,0xea,0x43,0x88,0x3c,0x60,0x83,0x61,0x88,0x93,0xc4,0x34,0x58,0x5e,0xbc,0x7c,0xa2,0x31,0xe0,0x79,0xca,0x4f,0xe9,0x06,0xb6,0x20,0x08,0xda,0x20,0xf1,0x90,0x03,0xc8,0x3e,0x50,0x59,0xc0,0x3c,0x93,0xa2,0x0f,0x28,0xa8,0x3c,0x47,0xe5,0x06,0x34,0x88,0x00,0x59,0xa2,0x0f,0x28,0x58,0x7d,0x41,0xe7,0x00,0x81,0x83,0xc6,0x20,}; const uint8_t _A_WatchingTV_128x64_2[] = {0x01,0x00,0x37,0x02,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0x80,0x01,0x0c,0x62,0x80,0x10,0xb8,0x0c,0x02,0x29,0x20,0x04,0xaf,0xfe,0x3e,0x05,0x38,0x14,0x02,0x39,0x10,0x07,0x27,0x02,0x01,0x60,0x07,0xac,0x58,0x1e,0xa2,0x51,0x1d,0x90,0x00,0x60,0x90,0x09,0x54,0x20,0x1e,0x81,0x52,0x1d,0x88,0x00,0x41,0x83,0x36,0x09,0x08,0x00,0xc2,0xa4,0x2b,0x10,0xb1,0xd8,0x80,0xc6,0x28,0x30,0x11,0x83,0xcb,0x8d,0x03,0x07,0xa0,0x54,0x87,0x06,0x46,0x18,0x54,0x1c,0x1e,0xe5,0x83,0x46,0x0e,0x18,0x9e,0xa4,0xc2,0x07,0x99,0x90,0x69,0x40,0xf8,0x4c,0x18,0x3c,0x64,0x80,0xfc,0x03,0x8c,0xf3,0xe1,0x3f,0xc0,0x03,0x07,0x01,0x03,0xc0,0x43,0xc1,0xe9,0x02,0x8c,0x2a,0x86,0xc0,0x0f,0x30,0x50,0xac,0x12,0x09,0x38,0x01,0x8c,0x7c,0x1e,0xae,0x84,0x82,0x45,0x1e,0xa8,0x0f,0x1f,0x04,0xfc,0x3e,0x90,0x80,0x79,0x06,0x0b,0x81,0x01,0x90,0x59,0xc3,0xe9,0x10,0x91,0x16,0x10,0x36,0x36,0x0d,0x3e,0x80,0x1e,0x7f,0x89,0x38,0x0c,0x4a,0x42,0x02,0x2e,0x05,0x4f,0x82,0x0f,0x38,0x35,0x60,0x06,0x40,0x21,0x86,0x10,0x47,0x5e,0x1f,0x48,0x0d,0x83,0x01,0xff,0x45,0x90,0x48,0xaa,0x1d,0x04,0xfa,0x50,0x2f,0x01,0x63,0x72,0x18,0x7c,0xca,0x63,0x80,0x7b,0x1a,0xb8,0xe0,0x01,0xf2,0xff,0xff,0xe1,0xe0,0xf4,0xf8,0x20,0x4f,0x50,0x04,0x1a,0xad,0x57,0xea,0x12,0x10,0x98,0xc0,0x35,0xc7,0x12,0x82,0x75,0x00,0xe3,0xaa,0x00,0x24,0x3b,0x01,0xd5,0x07,0x8c,0x72,0x01,0x78,0x9a,0x87,0xc8,0x00,0x70,0xfe,0x06,0xab,0xff,0xe1,0x28,0x8c,0x32,0xd4,0x1f,0x5f,0x54,0x2a,0xc1,0x81,0x80,0xc7,0x94,0x23,0x06,0xea,0x07,0xd6,0xeb,0x0d,0x58,0x08,0x74,0x62,0x00,0x31,0xd4,0x40,0x43,0xe9,0xae,0x85,0x03,0xc4,0x94,0x32,0xec,0x04,0x06,0xa1,0x03,0x0f,0xa5,0x5e,0x7b,0x3e,0xc0,0x19,0x86,0x0b,0x40,0x80,0xea,0x20,0x43,0xe4,0xd5,0x72,0xa4,0x38,0x00,0x30,0xc0,0x93,0xc2,0x1f,0x13,0xe1,0x7f,0xef,0xf5,0x51,0xf8,0xe0,0x04,0xa3,0x01,0x4f,0x0f,0xa2,0x0f,0x88,0x00,0x16,0xe3,0x54,0x3f,0x1a,0x00,0x78,0x4d,0x62,0xf4,0x18,0xc0,0xf9,0x03,0xe4,0xc6,0x15,0x59,0x40,0x20,0x92,0x09,0x10,0x00,0x74,0x5b,0x30,0xf8,0xd0,0x01,0xe5,0x80,0x46,0x8c,0x0a,0x40,0x7d,0x30,0x10,0xc3,0x70,0x00,0xf2,0xa0,0x5f,0x5c,0x83,0x40,0x1f,0x16,0x60,0x7e,0x50,0x09,0x0b,0xf4,0xa8,0xf8,0x00,0x98,0x8f,0x90,0x3e,0x30,0x09,0xf3,0xf4,0xa8,0x00,0xf2,0x37,0x14,0x8f,0x64,0x1f,0x20,0x01,0x5a,0x88,0x84,0xa2,0x10,0x10,0x88,0x88,0x3e,0x23,0xe2,0x9a,0x83,0xd8,0xfe,0x60,0xf2,0xd0,0x46,0xa8,0x0c,0x51,0x0f,0xd5,0x52,0x2a,0x0f,0x39,0x8f,0xf3,0x1f,0x22,0x1f,0xa3,0x00,0x50,0x82,0xf1,0x1c,0x05,0x26,0x05,0x90,0x0f,0xad,0x41,0x08,0x40,0xf5,0x1f,0x94,0xa8,0x3c,0x5a,0xa8,0x76,0x02,0x10,0x2f,0x20,0xfa,0x57,0x58,0xc6,0x4a,0x18,0x39,0x3c,0x81,0xe2,0x3f,0x2f,0xb6,0xab,0xd4,0x87,0x10,0x78,0xc1,0x0e,0x83,0x11,0x27,0x88,0x68,0xb0,0xbd,0x78,0xf9,0x04,0x63,0xc0,0xf3,0x94,0x9f,0xd2,0x0d,0x6c,0x38,0x11,0xb4,0x41,0xe3,0x20,0x07,0x90,0x7c,0xa0,0xb3,0x85,0x01,0x83,0xce,0x2a,0x0f,0x11,0xf9,0x41,0x8d,0x22,0x81,0x20,0x79,0xc2,0xc3,0xea,0x0f,0x38,0x04,0x0c,0x1e,0x31,0x00,}; @@ -25,23 +25,20 @@ const uint8_t _A_Wink_128x64_7[] = {0x01,0x00,0x9a,0x01,0x00,0x78,0x03,0xc0,0x1e const uint8_t _A_Wink_128x64_8[] = {0x01,0x00,0x95,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x00,0xf8,0x3f,0xf1,0xf0,0x7e,0x4e,0x02,0x23,0x01,0x07,0xdc,0x1e,0x01,0xf0,0x87,0x03,0xab,0x81,0xff,0xdf,0xc7,0xae,0x00,0xfa,0x98,0x40,0x2a,0x90,0x7e,0xc0,0xc2,0xa3,0x10,0x0d,0x54,0x0f,0x1d,0x03,0x07,0xcc,0x12,0x01,0x55,0x81,0xc4,0xc8,0x16,0x1f,0x1e,0x0d,0x86,0x10,0x0f,0xbe,0xad,0xc3,0x08,0x34,0x10,0x03,0xe0,0x00,0x43,0xea,0x8c,0x42,0x22,0x3e,0x08,0x78,0x3d,0xa8,0x00,0x21,0xaa,0xe3,0x22,0x13,0x88,0xe5,0xe0,0x1e,0xd2,0x00,0x10,0xda,0xa0,0x92,0x19,0x64,0x1f,0x80,0x7e,0x7c,0x07,0xfe,0x7f,0x0c,0x81,0x79,0xa0,0x38,0x04,0x13,0x44,0x03,0x03,0x18,0x8c,0x61,0x24,0x6b,0x31,0x07,0xb4,0x22,0xc1,0xfe,0x99,0xcc,0x3c,0x11,0x08,0x07,0xe0,0x1e,0xd0,0x49,0x84,0x06,0xc9,0x20,0x9c,0x43,0x20,0x1f,0xe1,0xfb,0x40,0xb2,0x10,0x0e,0x41,0xb0,0x60,0x58,0x0b,0xf8,0x3d,0xa0,0x34,0x8f,0xe6,0x44,0x0a,0x5e,0x09,0xfa,0x41,0xe5,0x1f,0xed,0x1c,0x04,0xa6,0x3f,0x08,0xf8,0x3d,0xe4,0x9f,0xf9,0x3c,0x05,0xe6,0x3f,0xc4,0xfb,0xc0,0x22,0x9f,0xfa,0x3c,0x05,0x9c,0x3f,0xe8,0x38,0x3d,0xf2,0x9e,0x7a,0x7c,0x06,0x0c,0x94,0x18,0x18,0x3e,0xb0,0x24,0x01,0xff,0x9f,0x98,0x1e,0x5f,0xfa,0x7d,0xc6,0x01,0xe0,0xff,0xbc,0x20,0x1e,0x51,0xd2,0xf0,0x9f,0x9c,0x1e,0x84,0xb1,0xfc,0x1f,0xa3,0x01,0x96,0xff,0x86,0xcb,0xf8,0x7e,0x8a,0x04,0x97,0xff,0x41,0x02,0x8f,0xf8,0xfd,0x1a,0x09,0x55,0xf8,0x0a,0x5f,0xf3,0xf4,0x54,0x29,0xb1,0xe1,0xa1,0x1f,0xa7,0x51,0x9a,0x81,0x01,0x04,0xfc,0x58,0x01,0x0b,0x54,0x32,0xa8,0x92,0xf8,0x7f,0xca,0x83,0x0e,0x0f,0xb7,0xa8,0x08,0x5f,0x88,0x09,0x7c,0x61,0x21,0xf6,0xaa,0x81,0x0b,0xf9,0x00,0xb8,0x70,0x1a,0x62,0x1f,0x59,0x50,0x10,0xa7,0xcb,0x01,0x9c,0x83,0xda,0xa1,0x15,0x80,0x58,0x30,0x02,0xd1,0xc0,0x43,0xe0,0x81,0xf6,0x85,0x17,0x47,0xe0,0xad,0x1f,0x84,0x00,0x1e,0xd5,0x08,0x2a,0x34,0x80,0x02,0x21,0x13,0xb1,0x07,0xd8,0x00,0xa7,0x62,0x0f,0xbb,0x5d,0x17,0xee,0x1f,0x6a,0x02,0xc1,0xc0,0x0d,0x3c,0x07,0x6f,0x01,0xa1,0x00,0x05,0x98,0x03,0xb5,0x1c,0x20,0xfd,0xb8,0x13,0x79,0xd8,0xc0,0xff,0x1f,0x78,0x01,0xfe,0x10,0x70,0x7e,0xff,0x0f,0xbd,0xfe,0x07,0xc8,}; const uint8_t *_A_Wink_128x64[] = {_A_Wink_128x64_0,_A_Wink_128x64_1,_A_Wink_128x64_2,_A_Wink_128x64_3,_A_Wink_128x64_4,_A_Wink_128x64_5,_A_Wink_128x64_6,_A_Wink_128x64_7,_A_Wink_128x64_8}; -const uint8_t _I_dir_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0c,0xfe,0x01,0x41,0x80,0x7f,0xe0,0x70,0x18,0x10,0x05,0x7f,0xd0,0x10,0x88,0x80,}; -const uint8_t *_I_dir_10px[] = {_I_dir_10px_0}; - -const uint8_t _I_Nfc_10px_0[] = {0x00,0x80,0x00,0x00,0x01,0x22,0x02,0x43,0x02,0x45,0x02,0x49,0x02,0x31,0x02,0x22,0x02,0x00,0x01,0x80,0x00,}; -const uint8_t *_I_Nfc_10px[] = {_I_Nfc_10px_0}; - const uint8_t _I_sub1_10px_0[] = {0x01,0x00,0x12,0x00,0x81,0x40,0x69,0x30,0x2c,0x2c,0x0b,0x6a,0x01,0x28,0x0c,0x0a,0x65,0x01,0x98,0x40,0x00,0x26,}; const uint8_t *_I_sub1_10px[] = {_I_sub1_10px_0}; const uint8_t _I_ir_10px_0[] = {0x00,0xFC,0x00,0x02,0x01,0x79,0x02,0x84,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x58,0x00,0x78,0x00,0xFF,0x03,}; const uint8_t *_I_ir_10px[] = {_I_ir_10px_0}; +const uint8_t _I_unknown_10px_0[] = {0x01,0x00,0x12,0x00,0xbc,0x40,0x39,0x90,0x0c,0x24,0x03,0x81,0x00,0xb0,0x40,0x26,0x00,0x12,0x00,0x08,0x14,0xc0,}; +const uint8_t *_I_unknown_10px[] = {_I_unknown_10px_0}; + const uint8_t _I_ibutt_10px_0[] = {0x00,0x80,0x03,0x40,0x02,0x20,0x02,0x10,0x01,0x8E,0x00,0x41,0x00,0x2D,0x00,0x2D,0x00,0x21,0x00,0x1E,0x00,}; const uint8_t *_I_ibutt_10px[] = {_I_ibutt_10px_0}; -const uint8_t _I_unknown_10px_0[] = {0x01,0x00,0x12,0x00,0xbc,0x40,0x39,0x90,0x0c,0x24,0x03,0x81,0x00,0xb0,0x40,0x26,0x00,0x12,0x00,0x08,0x14,0xc0,}; -const uint8_t *_I_unknown_10px[] = {_I_unknown_10px_0}; +const uint8_t _I_Nfc_10px_0[] = {0x00,0x80,0x00,0x00,0x01,0x22,0x02,0x43,0x02,0x45,0x02,0x49,0x02,0x31,0x02,0x22,0x02,0x00,0x01,0x80,0x00,}; +const uint8_t *_I_Nfc_10px[] = {_I_Nfc_10px_0}; const uint8_t _I_ble_10px_0[] = {0x00,0x04,0x00,0x8C,0x00,0x15,0x01,0x56,0x02,0x8C,0x02,0x8C,0x02,0x56,0x02,0x15,0x01,0x8C,0x00,0x04,0x00,}; const uint8_t *_I_ble_10px[] = {_I_ble_10px_0}; @@ -49,41 +46,38 @@ const uint8_t *_I_ble_10px[] = {_I_ble_10px_0}; const uint8_t _I_125_10px_0[] = {0x00,0xE0,0x00,0x00,0x01,0x0E,0x02,0x31,0x02,0x45,0x02,0x91,0x00,0xAA,0x00,0x92,0x00,0x44,0x00,0x38,0x00,}; const uint8_t *_I_125_10px[] = {_I_125_10px_0}; +const uint8_t _I_dir_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0c,0xfe,0x01,0x41,0x80,0x7f,0xe0,0x70,0x18,0x10,0x05,0x7f,0xd0,0x10,0x88,0x80,}; +const uint8_t *_I_dir_10px[] = {_I_dir_10px_0}; + const uint8_t _I_BLE_Pairing_128x64_0[] = {0x01,0x00,0xb7,0x01,0x00,0x6c,0x38,0x1f,0xd0,0x10,0x76,0xe0,0x03,0xdd,0x40,0x07,0xf4,0x82,0x01,0x08,0x07,0xf4,0xc0,0x1f,0x91,0x08,0x07,0x00,0x1f,0xc0,0x0d,0x1e,0xe8,0x3f,0xc0,0x03,0x58,0x80,0xcf,0x11,0xd9,0xaf,0x85,0x77,0x01,0xf7,0x60,0xf8,0x45,0xff,0x05,0xed,0x9e,0x7c,0x09,0xdb,0xe0,0x2f,0x78,0x03,0x3c,0x8e,0xee,0x8a,0x43,0x81,0xfb,0x0c,0x66,0xe8,0xfc,0x59,0xba,0x6f,0x28,0x1b,0xfb,0xa3,0x80,0xfc,0xa0,0x1f,0xc6,0x86,0xbf,0xc3,0x78,0xce,0x04,0x19,0x26,0x77,0xfa,0x43,0xbe,0x12,0xa0,0x7e,0xf8,0x2a,0xa2,0x02,0xff,0x89,0x27,0x01,0xbf,0x99,0x38,0x8a,0xfc,0x0f,0x8e,0x07,0xfe,0x0e,0x94,0x2c,0x07,0xfc,0x7f,0x1f,0xf5,0x00,0xc3,0x00,0xe4,0x31,0x13,0xd1,0x00,0x0a,0xb8,0x19,0x25,0x91,0xc0,0x81,0xe2,0xb9,0x4d,0x5d,0x78,0x64,0x2e,0x84,0x80,0x61,0x07,0x02,0x3e,0x2a,0xa4,0xa2,0x00,0xf2,0x40,0x20,0xe3,0x21,0xa0,0x62,0x9f,0x60,0x05,0x02,0x3e,0x36,0x41,0x66,0x23,0x20,0x51,0xfc,0x40,0x68,0x0f,0x15,0x90,0x60,0x20,0x1b,0x09,0x89,0x70,0x46,0x42,0x07,0x14,0x99,0x41,0xe8,0x1f,0x18,0x0c,0x07,0xc1,0x19,0xff,0xc3,0xce,0x6b,0x54,0x8f,0xe0,0x3f,0x90,0x78,0x17,0x02,0x1a,0x70,0x39,0x01,0xa0,0xb1,0x53,0xb5,0x88,0xc7,0xe0,0x98,0x08,0x3a,0xd5,0xe8,0x97,0xd0,0x78,0xcf,0xe1,0x07,0xf1,0x0d,0x08,0x00,0x74,0x10,0x80,0x18,0xe8,0x97,0xc3,0xf2,0xff,0xc4,0x03,0xe3,0x04,0x8c,0x19,0xcc,0x00,0x35,0x0c,0x3c,0x03,0xf9,0x3f,0xb0,0x8f,0xc6,0x31,0x0e,0x0f,0x90,0x90,0xb5,0x45,0xc1,0xf8,0x4f,0xf0,0xde,0x18,0xcc,0x82,0x08,0x1f,0x22,0x20,0xd0,0x3a,0xab,0xd1,0xe0,0x5f,0xa1,0x1b,0x19,0x8d,0x02,0x04,0x9a,0x1d,0x04,0x28,0x26,0x36,0xa8,0x05,0xf0,0xe0,0x3f,0x04,0xf8,0xd0,0x30,0x55,0xfa,0xad,0x54,0x3e,0x35,0x09,0xab,0xac,0xbf,0x2b,0xf2,0x0a,0x0e,0xfb,0x55,0xaa,0x0f,0x94,0x68,0x04,0x30,0x6f,0xd3,0x7c,0xb0,0x15,0x0f,0xfd,0x7f,0xeb,0x05,0x4f,0x0b,0x60,0xa3,0x1f,0x28,0x0b,0xfc,0xbc,0x30,0x1f,0xf7,0xfe,0x54,0x2c,0x18,0x30,0x3c,0x6f,0x00,0xf2,0x1c,0x8c,0xf8,0x10,0x3c,0x00,0xf8,0xd5,0x5c,0x05,0xb8,0xb0,0xaa,0xdb,0x01,0x2b,0x31,0x0a,0xdc,0xa7,0x00,0xe6,0x00,0x0c,0x56,0x00,0x7e,0x10,0x00,0xcc,0x01,0xf0,0x1f,0x1b,0x40,0x2e,0x00,0x07,0x16,0x10,0x90,0x02,0xe5,0x90,0x06,0x29,0x00,0x2a,0xa9,0x00,0x2f,0x10,0x02,0xa5,0x10,0x02,0xf1,0x00,0x2a,0xa0,0x0d,0xc0,0x00,0xec,0x01,0xfd,0x60,0x17,0x6a,0xc0,0x60,0x40,0xfd,0xc0,0x30,0x04,0x01,0xb0,0xb0,0x7f,0x45,0x80,}; const uint8_t *_I_BLE_Pairing_128x64[] = {_I_BLE_Pairing_128x64_0}; -const uint8_t _I_ButtonRightSmall_3x5_0[] = {0x00,0x01,0x03,0x07,0x03,0x01,}; -const uint8_t *_I_ButtonRightSmall_3x5[] = {_I_ButtonRightSmall_3x5_0}; - -const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,}; -const uint8_t *_I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; - -const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x00,0x04,0x06,0x07,0x06,0x04,}; -const uint8_t *_I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_0}; - -const uint8_t _I_DFU_128x50_0[] = {0x01,0x00,0x2e,0x02,0x00,0x57,0xfe,0x0e,0x0e,0xcf,0x84,0x02,0x70,0x0f,0xc8,0x74,0x03,0x80,0x0e,0xbc,0x7c,0x04,0x06,0x30,0x30,0x74,0xe0,0x2f,0xe0,0x42,0x82,0x03,0xe7,0x81,0xff,0x02,0x14,0x20,0x1f,0x3e,0x00,0x79,0xc4,0x01,0xfd,0x20,0x07,0xd5,0xd4,0xe2,0x53,0xf2,0x74,0xff,0xe1,0x40,0x41,0x87,0xd8,0x01,0xf1,0x60,0xf0,0x43,0xca,0x43,0xe0,0xa7,0x83,0xe2,0x30,0x01,0x29,0x84,0x7b,0x20,0x0f,0x88,0x30,0x3c,0xb1,0x90,0x1d,0x00,0xfa,0x30,0x3f,0xf8,0xcc,0x02,0xc6,0x31,0x1f,0x83,0x49,0xa8,0x16,0x0a,0xf4,0x7f,0x00,0x21,0x1f,0x04,0x38,0x06,0x20,0x04,0x90,0x46,0x35,0xf0,0xfa,0x00,0xcc,0x7f,0x10,0x14,0x0b,0x46,0x20,0xd5,0x70,0x50,0xb4,0x06,0xf1,0x00,0x9f,0x03,0xd7,0x09,0x81,0xd7,0xc0,0x8b,0x85,0x38,0xc0,0x50,0x41,0xeb,0x63,0xc0,0x07,0xc6,0x90,0xbf,0x2b,0x05,0x01,0xb8,0xb1,0x0c,0x06,0xae,0x01,0x24,0x6f,0x94,0x42,0x80,0xb2,0x49,0xc4,0x33,0x80,0x1f,0x18,0x93,0xfc,0xa1,0x14,0x0e,0x02,0x9c,0x43,0xc3,0x07,0x81,0xfc,0x03,0xe2,0xc0,0x28,0x14,0x10,0x5e,0x3f,0x03,0xc0,0xcf,0xf8,0x10,0x0f,0xe5,0x56,0x03,0x05,0xf0,0x40,0x20,0x20,0xf2,0x42,0x0d,0xfd,0x72,0x30,0x0f,0xf8,0x7c,0x41,0xe3,0x80,0x10,0x0d,0x00,0x5c,0x4a,0xd1,0x87,0xf8,0x39,0xf5,0x5c,0x0c,0x0b,0xe0,0x1c,0x10,0x78,0xfc,0x02,0x04,0x20,0x1f,0xf7,0x0f,0x57,0x80,0x81,0x5e,0x13,0x83,0x01,0x1f,0x97,0xff,0xfe,0x03,0x2e,0x07,0x57,0x03,0x01,0xbf,0x1d,0x45,0x70,0x27,0xe4,0xff,0x8c,0x07,0xf5,0x83,0xe0,0xcf,0xe1,0x00,0xf6,0x10,0x8c,0x07,0xb1,0x07,0xc1,0xfc,0x63,0xe5,0xd2,0x07,0x8f,0x80,0x1a,0x21,0xe1,0xc0,0x71,0xe0,0x20,0xf1,0x24,0x88,0x34,0x62,0x00,0xe3,0x3f,0x8d,0xfe,0x81,0x80,0xc1,0xf8,0x5b,0xe2,0x0f,0x18,0xc7,0xf0,0x1e,0x50,0x35,0xa0,0xc8,0x3f,0x98,0x30,0x70,0x87,0x44,0x1e,0x21,0xe3,0xf8,0x02,0x4b,0xaf,0x01,0x81,0xb3,0xca,0x01,0x1c,0x25,0x94,0x01,0x04,0x58,0x8d,0x5c,0x0b,0xc6,0x08,0x10,0x78,0xc3,0x3f,0xf0,0x72,0x88,0x98,0x8b,0x89,0x55,0x82,0xc7,0x9b,0xe5,0x00,0x87,0x26,0xc4,0x46,0x20,0xf2,0xd1,0x87,0xc6,0x0c,0xdf,0x21,0x50,0x8a,0xc7,0x00,0x38,0x2e,0x04,0x42,0xaf,0x05,0x06,0x0a,0xb8,0x70,0x0f,0x91,0x80,0x5c,0x03,0xc5,0x30,0x84,0x6a,0xe1,0x40,0xf1,0x7b,0x0f,0x00,0x7a,0x24,0x21,0x07,0x94,0x33,0x09,0x57,0x8a,0x93,0x85,0xec,0x3e,0x00,0x79,0x0b,0x88,0x06,0x3c,0x3f,0xfc,0xa8,0x1e,0x21,0x91,0x76,0x90,0x90,0x40,0x03,0xe0,0xe0,0x78,0x3f,0xd5,0x58,0x0e,0x08,0x32,0x3f,0x88,0xa8,0x90,0x8c,0x25,0x30,0xbc,0x7f,0xb5,0x50,0x1b,0xe0,0x20,0x7f,0x92,0x33,0x88,0x97,0x4a,0x07,0x0c,0x9e,0x5f,0xeb,0xaa,0xf2,0x74,0x8d,0x17,0x80,0x06,0x29,0xf1,0xe0,0x71,0xfb,0xfd,0x71,0xd8,0xff,0xf8,0x21,0x71,0x04,0x87,0x01,0xc1,0xa1,0xff,0x83,0xe7,0xf0,0xff,0xc1,0x51,0xe4,0xdd,0x1b,0x07,0xc2,0x63,0xf6,0x0f,0x9f,0xeb,0x5f,0x02,0x77,0x8a,0xc4,0xa3,0x17,0xc8,0x44,0x8c,0x34,0x20,0x71,0xfe,0x99,0x04,0x88,0x40,0x01,0xc3,0x47,0xf0,0x93,0x0f,0xf4,0x28,0x0e,0x3a,0xad,0x50,0x39,0x30,0x1f,0x18,0x3d,0x0e,0x31,0xff,0x3d,0x0c,0x02,0xa8,0x03,0x20,0x01,0x7e,0x3f,0xf8,0x09,0x06,0x33,0xfe,0x1b,0x50,}; -const uint8_t *_I_DFU_128x50[] = {_I_DFU_128x50_0}; - -const uint8_t _I_Warning_30x23_0[] = {0x01,0x00,0x47,0x00,0x80,0x70,0x00,0x65,0xe0,0x80,0x80,0xc7,0xe1,0x03,0x01,0xaf,0xe2,0x0e,0x03,0x19,0xe4,0x3c,0x06,0xb3,0xe8,0xf8,0x0c,0x67,0xf3,0xf0,0x1a,0x60,0x27,0xf7,0xf1,0x50,0xcf,0xff,0xe0,0x34,0xf0,0x00,0xc6,0x03,0xf0,0x01,0x8c,0x0c,0x06,0x7f,0x80,0x18,0xc1,0xff,0x9f,0xff,0xfc,0x3c,0x06,0x7f,0xe0,0x58,0xc7,0xff,0xe0,0x31,0x00,0x88,0x00,0x67,0xff,0xe0,0x18,0xc7,0xc0,}; -const uint8_t *_I_Warning_30x23[] = {_I_Warning_30x23_0}; - const uint8_t _I_ButtonDown_7x4_0[] = {0x00,0x7F,0x3E,0x1C,0x08,}; const uint8_t *_I_ButtonDown_7x4[] = {_I_ButtonDown_7x4_0}; -const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0F,0x07,0x03,0x01,}; -const uint8_t *_I_ButtonRight_4x7[] = {_I_ButtonRight_4x7_0}; - const uint8_t _I_ButtonCenter_7x7_0[] = {0x00,0x1C,0x22,0x5D,0x5D,0x5D,0x22,0x1C,}; const uint8_t *_I_ButtonCenter_7x7[] = {_I_ButtonCenter_7x7_0}; +const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,}; +const uint8_t *_I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; + const uint8_t _I_ButtonUp_7x4_0[] = {0x00,0x08,0x1C,0x3E,0x7F,}; const uint8_t *_I_ButtonUp_7x4[] = {_I_ButtonUp_7x4_0}; -const uint8_t _I_DolphinOkay_41x43_0[] = {0x01,0x00,0xa0,0x00,0x00,0x0f,0x82,0x3e,0x05,0x38,0xf7,0x80,0x08,0x58,0x08,0x0c,0x02,0x0e,0x05,0x1b,0x00,0x08,0x63,0x00,0x21,0x88,0x00,0x86,0x40,0x02,0x18,0x40,0x08,0x68,0x00,0x21,0x82,0x06,0x88,0x0a,0xf0,0x21,0x39,0x09,0x84,0x02,0x20,0x57,0x09,0x98,0x15,0x67,0xc0,0x54,0xbe,0x81,0x4f,0x01,0xfe,0x02,0x9d,0x03,0xc4,0x20,0x10,0x29,0x7c,0x80,0xa9,0xfe,0x02,0xac,0x14,0x0a,0x77,0xc8,0x58,0x8c,0xf0,0x11,0x51,0x79,0xff,0x61,0x44,0x93,0x81,0x02,0xc4,0x9e,0x60,0xb2,0xf0,0xa0,0x46,0x0c,0x17,0x14,0x99,0x1a,0x07,0x80,0x59,0x49,0x82,0x21,0xc0,0xa4,0x82,0x24,0xb9,0x20,0x88,0x1c,0x47,0xc2,0x07,0x11,0x54,0xa0,0x60,0x53,0xb8,0x0a,0x4b,0xf3,0x03,0x87,0x81,0x4a,0x0d,0xfc,0x1a,0x98,0x68,0xb8,0x01,0x51,0x13,0x15,0xe0,0x82,0x7f,0x8d,0x78,0x38,0xbf,0xff,0xfa,0xb8,0x60,0xbf,0x1b,0xf9,0x50,0x14,0xea,0xe7,0x02,0x02,0x8e,0xac,0x94,0x40,}; -const uint8_t *_I_DolphinOkay_41x43[] = {_I_DolphinOkay_41x43_0}; +const uint8_t _I_DFU_128x50_0[] = {0x01,0x00,0x2e,0x02,0x00,0x57,0xfe,0x0e,0x0e,0xcf,0x84,0x02,0x70,0x0f,0xc8,0x74,0x03,0x80,0x0e,0xbc,0x7c,0x04,0x06,0x30,0x30,0x74,0xe0,0x2f,0xe0,0x42,0x82,0x03,0xe7,0x81,0xff,0x02,0x14,0x20,0x1f,0x3e,0x00,0x79,0xc4,0x01,0xfd,0x20,0x07,0xd5,0xd4,0xe2,0x53,0xf2,0x74,0xff,0xe1,0x40,0x41,0x87,0xd8,0x01,0xf1,0x60,0xf0,0x43,0xca,0x43,0xe0,0xa7,0x83,0xe2,0x30,0x01,0x29,0x84,0x7b,0x20,0x0f,0x88,0x30,0x3c,0xb1,0x90,0x1d,0x00,0xfa,0x30,0x3f,0xf8,0xcc,0x02,0xc6,0x31,0x1f,0x83,0x49,0xa8,0x16,0x0a,0xf4,0x7f,0x00,0x21,0x1f,0x04,0x38,0x06,0x20,0x04,0x90,0x46,0x35,0xf0,0xfa,0x00,0xcc,0x7f,0x10,0x14,0x0b,0x46,0x20,0xd5,0x70,0x50,0xb4,0x06,0xf1,0x00,0x9f,0x03,0xd7,0x09,0x81,0xd7,0xc0,0x8b,0x85,0x38,0xc0,0x50,0x41,0xeb,0x63,0xc0,0x07,0xc6,0x90,0xbf,0x2b,0x05,0x01,0xb8,0xb1,0x0c,0x06,0xae,0x01,0x24,0x6f,0x94,0x42,0x80,0xb2,0x49,0xc4,0x33,0x80,0x1f,0x18,0x93,0xfc,0xa1,0x14,0x0e,0x02,0x9c,0x43,0xc3,0x07,0x81,0xfc,0x03,0xe2,0xc0,0x28,0x14,0x10,0x5e,0x3f,0x03,0xc0,0xcf,0xf8,0x10,0x0f,0xe5,0x56,0x03,0x05,0xf0,0x40,0x20,0x20,0xf2,0x42,0x0d,0xfd,0x72,0x30,0x0f,0xf8,0x7c,0x41,0xe3,0x80,0x10,0x0d,0x00,0x5c,0x4a,0xd1,0x87,0xf8,0x39,0xf5,0x5c,0x0c,0x0b,0xe0,0x1c,0x10,0x78,0xfc,0x02,0x04,0x20,0x1f,0xf7,0x0f,0x57,0x80,0x81,0x5e,0x13,0x83,0x01,0x1f,0x97,0xff,0xfe,0x03,0x2e,0x07,0x57,0x03,0x01,0xbf,0x1d,0x45,0x70,0x27,0xe4,0xff,0x8c,0x07,0xf5,0x83,0xe0,0xcf,0xe1,0x00,0xf6,0x10,0x8c,0x07,0xb1,0x07,0xc1,0xfc,0x63,0xe5,0xd2,0x07,0x8f,0x80,0x1a,0x21,0xe1,0xc0,0x71,0xe0,0x20,0xf1,0x24,0x88,0x34,0x62,0x00,0xe3,0x3f,0x8d,0xfe,0x81,0x80,0xc1,0xf8,0x5b,0xe2,0x0f,0x18,0xc7,0xf0,0x1e,0x50,0x35,0xa0,0xc8,0x3f,0x98,0x30,0x70,0x87,0x44,0x1e,0x21,0xe3,0xf8,0x02,0x4b,0xaf,0x01,0x81,0xb3,0xca,0x01,0x1c,0x25,0x94,0x01,0x04,0x58,0x8d,0x5c,0x0b,0xc6,0x08,0x10,0x78,0xc3,0x3f,0xf0,0x72,0x88,0x98,0x8b,0x89,0x55,0x82,0xc7,0x9b,0xe5,0x00,0x87,0x26,0xc4,0x46,0x20,0xf2,0xd1,0x87,0xc6,0x0c,0xdf,0x21,0x50,0x8a,0xc7,0x00,0x38,0x2e,0x04,0x42,0xaf,0x05,0x06,0x0a,0xb8,0x70,0x0f,0x91,0x80,0x5c,0x03,0xc5,0x30,0x84,0x6a,0xe1,0x40,0xf1,0x7b,0x0f,0x00,0x7a,0x24,0x21,0x07,0x94,0x33,0x09,0x57,0x8a,0x93,0x85,0xec,0x3e,0x00,0x79,0x0b,0x88,0x06,0x3c,0x3f,0xfc,0xa8,0x1e,0x21,0x91,0x76,0x90,0x90,0x40,0x03,0xe0,0xe0,0x78,0x3f,0xd5,0x58,0x0e,0x08,0x32,0x3f,0x88,0xa8,0x90,0x8c,0x25,0x30,0xbc,0x7f,0xb5,0x50,0x1b,0xe0,0x20,0x7f,0x92,0x33,0x88,0x97,0x4a,0x07,0x0c,0x9e,0x5f,0xeb,0xaa,0xf2,0x74,0x8d,0x17,0x80,0x06,0x29,0xf1,0xe0,0x71,0xfb,0xfd,0x71,0xd8,0xff,0xf8,0x21,0x71,0x04,0x87,0x01,0xc1,0xa1,0xff,0x83,0xe7,0xf0,0xff,0xc1,0x51,0xe4,0xdd,0x1b,0x07,0xc2,0x63,0xf6,0x0f,0x9f,0xeb,0x5f,0x02,0x77,0x8a,0xc4,0xa3,0x17,0xc8,0x44,0x8c,0x34,0x20,0x71,0xfe,0x99,0x04,0x88,0x40,0x01,0xc3,0x47,0xf0,0x93,0x0f,0xf4,0x28,0x0e,0x3a,0xad,0x50,0x39,0x30,0x1f,0x18,0x3d,0x0e,0x31,0xff,0x3d,0x0c,0x02,0xa8,0x03,0x20,0x01,0x7e,0x3f,0xf8,0x09,0x06,0x33,0xfe,0x1b,0x50,}; +const uint8_t *_I_DFU_128x50[] = {_I_DFU_128x50_0}; -const uint8_t _I_DolphinFirstStart4_67x53_0[] = {0x01,0x00,0x1f,0x01,0x00,0x17,0xc3,0xfe,0x08,0x68,0x74,0x02,0x0e,0x07,0x4c,0x04,0x06,0x01,0x18,0x04,0x25,0x00,0x04,0x36,0x00,0x42,0x48,0x02,0x88,0x00,0x28,0x80,0x0c,0xa0,0x40,0x83,0x84,0x00,0xca,0x08,0x08,0x30,0x21,0x83,0x0c,0x2c,0x81,0xe3,0x04,0x20,0xc0,0x80,0x02,0x31,0x32,0x11,0x02,0x27,0x00,0x5d,0x40,0x45,0x87,0x90,0x3e,0x7c,0x00,0x43,0x84,0x4e,0x60,0x43,0x30,0x89,0x82,0x12,0x80,0x15,0x20,0x40,0x99,0xc8,0x22,0x7b,0x88,0x10,0x20,0x82,0x27,0x7c,0x82,0x9d,0x48,0x22,0x5f,0x0d,0xfc,0x08,0x10,0x41,0x12,0xf8,0x57,0xc2,0x28,0x30,0x1e,0x07,0x9e,0x06,0x87,0x25,0x79,0xc4,0x20,0x40,0x83,0x21,0x14,0x22,0x08,0x08,0x38,0x2a,0xb8,0xd9,0x47,0x0a,0x14,0x09,0xf0,0x54,0x47,0x1f,0x81,0x82,0x1a,0xde,0x8e,0x33,0xd1,0xc7,0x81,0x0f,0x0e,0x45,0x18,0x20,0xa1,0xe6,0xf2,0x10,0x89,0xa0,0x70,0x11,0x00,0x41,0x46,0x03,0x86,0x55,0x10,0x40,0xc1,0x82,0x25,0x20,0x04,0x11,0x94,0x80,0x43,0x10,0x84,0x01,0x46,0xc0,0xbd,0x38,0x40,0x20,0x8f,0x49,0x08,0xc4,0x1c,0xc8,0x22,0x50,0x38,0x20,0x20,0x86,0xe4,0x83,0x10,0x41,0x8b,0x87,0xf9,0x03,0x81,0xc0,0x81,0x05,0x81,0xc0,0x40,0xf3,0x90,0x60,0x41,0x70,0x2c,0x17,0x01,0xc0,0xc1,0x41,0x05,0x30,0x98,0x43,0x04,0x65,0x01,0x04,0x0c,0x32,0x38,0x91,0x18,0x04,0x14,0x10,0x38,0x18,0x1e,0xac,0x7c,0x41,0x11,0x88,0x5f,0xfc,0x17,0x55,0xa9,0x82,0x06,0x05,0xbc,0x85,0x02,0x08,0xc6,0x32,0x0f,0xe5,0x5e,0x1a,0x08,0x5c,0x06,0xaa,0x34,0x08,0x4a,0x06,0x02,0xab,0x75,0xf0,0x4f,0xc1,0x05,0x80,0x08,0x8e,0xab,0x7f,0xea,0x04,0x11,0x80,0x6a,0xa0,0x02,0x03,0x08,}; -const uint8_t *_I_DolphinFirstStart4_67x53[] = {_I_DolphinFirstStart4_67x53_0}; +const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x00,0x04,0x06,0x07,0x06,0x04,}; +const uint8_t *_I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_0}; + +const uint8_t _I_ButtonRightSmall_3x5_0[] = {0x00,0x01,0x03,0x07,0x03,0x01,}; +const uint8_t *_I_ButtonRightSmall_3x5[] = {_I_ButtonRightSmall_3x5_0}; + +const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0F,0x07,0x03,0x01,}; +const uint8_t *_I_ButtonRight_4x7[] = {_I_ButtonRight_4x7_0}; + +const uint8_t _I_Warning_30x23_0[] = {0x01,0x00,0x47,0x00,0x80,0x70,0x00,0x65,0xe0,0x80,0x80,0xc7,0xe1,0x03,0x01,0xaf,0xe2,0x0e,0x03,0x19,0xe4,0x3c,0x06,0xb3,0xe8,0xf8,0x0c,0x67,0xf3,0xf0,0x1a,0x60,0x27,0xf7,0xf1,0x50,0xcf,0xff,0xe0,0x34,0xf0,0x00,0xc6,0x03,0xf0,0x01,0x8c,0x0c,0x06,0x7f,0x80,0x18,0xc1,0xff,0x9f,0xff,0xfc,0x3c,0x06,0x7f,0xe0,0x58,0xc7,0xff,0xe0,0x31,0x00,0x88,0x00,0x67,0xff,0xe0,0x18,0xc7,0xc0,}; +const uint8_t *_I_Warning_30x23[] = {_I_Warning_30x23_0}; const uint8_t _I_DolphinFirstStart2_59x51_0[] = {0x01,0x00,0x2e,0x01,0x00,0x1f,0xfe,0x06,0x05,0x3f,0xc7,0xfe,0x01,0x1c,0x03,0x16,0x02,0xaf,0x0f,0x80,0x58,0x01,0xc7,0xaa,0x80,0x82,0xc4,0x0e,0x55,0x6b,0x28,0x10,0x81,0x45,0xab,0x8d,0x01,0xca,0x04,0x1a,0x1a,0xac,0x1c,0x0e,0x50,0x48,0x06,0xc0,0x3c,0x40,0x01,0x84,0x40,0x2b,0x15,0x51,0xd9,0xc4,0x20,0x1a,0xc9,0x50,0x1c,0xe4,0x02,0xe1,0x8a,0x81,0xd7,0x55,0x0a,0x03,0x9d,0x02,0x01,0x5c,0x82,0x81,0xd7,0xc0,0x3a,0x10,0x3a,0x12,0x88,0xc8,0x60,0x11,0x07,0xa0,0x1c,0x68,0x00,0xf6,0xe0,0x22,0x50,0x0e,0x36,0x00,0x7b,0x68,0x00,0x83,0xa0,0x11,0x08,0x1c,0x6a,0x03,0x42,0x44,0x1e,0xc0,0x28,0x50,0x61,0xf9,0x56,0x00,0xe3,0x60,0x40,0x88,0x1c,0x75,0x01,0x42,0x07,0x9d,0x50,0x5e,0x4b,0x01,0x37,0x8e,0xb0,0x0e,0x51,0xd8,0x04,0xc2,0x01,0xd4,0x5d,0x1c,0x02,0x30,0x7f,0x14,0x99,0x5c,0x20,0x11,0x48,0x07,0x58,0x0e,0x20,0x81,0xd0,0x23,0x04,0x1e,0x30,0x80,0x38,0xd4,0x11,0x82,0x0f,0x18,0x40,0xb0,0xb0,0x50,0x3d,0x58,0x1c,0x52,0x85,0xf1,0x83,0x75,0x58,0x64,0x49,0x1a,0xfc,0x17,0x57,0x01,0x88,0x25,0x0b,0x55,0x02,0xaa,0xc0,0x64,0x14,0x08,0x1e,0x02,0xaa,0x1f,0x18,0x0f,0x00,0xbe,0x20,0xf1,0x80,0x82,0x46,0x01,0x03,0x82,0xe0,0x04,0xa3,0xab,0x46,0x0e,0x32,0x15,0x80,0xb5,0x40,0x2a,0xa4,0x21,0x98,0x43,0x70,0x13,0x58,0x04,0xac,0xa4,0x3c,0x08,0xd6,0x02,0x35,0x00,0x8a,0xcd,0x06,0xa3,0x1d,0xa0,0x24,0x46,0x57,0xe8,0x26,0x8c,0xdb,0x80,0x84,0x18,0xad,0x42,0x07,0x5f,0xbf,0xb9,0x8a,0x17,0x80,0xff,0x6a,0xb0,0x46,0x91,0x07,0x88,0xc4,0x4a,0x43,0x1f,0x07,0x92,0xc4,0x49,0x82,0x9b,0x25,0x98,0xc0,0x28,0xa0,0x73,0x1f,0x0b,0x50,0x81,0xea,0x07,0x40,0x7b,0xac,0x44,0x0e,0xa0,}; const uint8_t *_I_DolphinFirstStart2_59x51[] = {_I_DolphinFirstStart2_59x51_0}; @@ -91,110 +85,113 @@ const uint8_t *_I_DolphinFirstStart2_59x51[] = {_I_DolphinFirstStart2_59x51_0}; const uint8_t _I_DolphinFirstStart5_54x49_0[] = {0x01,0x00,0x0b,0x01,0x00,0x0f,0xf2,0xfe,0x06,0x48,0x1e,0x02,0x06,0x05,0x2e,0x00,0x08,0x61,0x80,0x62,0x98,0x00,0x86,0x20,0x06,0x28,0x40,0x08,0x64,0x00,0x62,0x82,0x00,0x86,0x80,0x06,0x28,0x14,0x72,0x01,0x80,0x03,0x14,0x06,0x44,0x03,0x20,0x49,0x00,0xc4,0x0c,0x61,0x13,0x81,0x07,0x90,0x0c,0xff,0xa8,0x18,0xcc,0xe0,0x10,0x78,0x60,0x18,0xc9,0xe3,0x10,0x03,0x0e,0x02,0x02,0x4f,0x19,0x00,0x18,0x78,0x10,0x12,0x78,0xc8,0x0a,0xc3,0xf8,0x80,0xc1,0x80,0xc5,0xe0,0xff,0x8f,0x47,0xe1,0x27,0x03,0x0d,0xfc,0x80,0x3b,0xc9,0x74,0x43,0x81,0x0f,0xb0,0x40,0x2b,0xd2,0xd3,0x71,0x07,0x87,0x5f,0x16,0x84,0x54,0x23,0xe3,0x21,0xab,0xc5,0x61,0x1a,0x82,0xf0,0xf0,0x35,0x70,0xa8,0x45,0x50,0x2a,0x3e,0x0a,0xac,0x1e,0x11,0x28,0x03,0x0f,0xc3,0xfe,0x06,0x19,0xa0,0x18,0x6f,0x9f,0x08,0x7c,0x22,0x30,0x06,0x1d,0xfc,0x3e,0x21,0x08,0x00,0x8f,0x01,0x7a,0x31,0x08,0x24,0x42,0x21,0xf0,0x5e,0x08,0x18,0x44,0xe3,0x0f,0x59,0x92,0xb4,0x96,0x66,0x06,0x58,0x10,0x19,0x60,0x20,0x64,0x46,0x08,0x19,0x27,0x00,0x65,0x9f,0x81,0x93,0xd1,0x2b,0x03,0x17,0x82,0x3f,0x50,0x9a,0x81,0x87,0x51,0x1e,0xf0,0x68,0x69,0x40,0x61,0xea,0x9d,0x86,0x1d,0x45,0x80,0x61,0x2d,0x48,0xc2,0x67,0x8d,0x12,0x3a,0x06,0x19,0x02,0x88,0x74,0x4b,0x21,0x03,0x1d,0x08,0xca,0x21,0x41,0x06,0x93,0xe8,0xa1,0x85,0x31,0xe9,0x24,0x48,0x20,0x30,0x1b,0x10,0x18,0x77,0x8f,0xa1,0x80,0xcc,0x40,0xc3,0x56,0x0b,0x8c,0x0a,0x22,0xba,0x12,0x88,0x81,0x84,}; const uint8_t *_I_DolphinFirstStart5_54x49[] = {_I_DolphinFirstStart5_54x49_0}; -const uint8_t _I_DolphinFirstStart0_70x53_0[] = {0x01,0x00,0x5a,0x01,0x80,0x60,0x3f,0xf7,0xf0,0x42,0xf8,0x01,0x43,0x07,0x04,0x24,0x72,0x01,0xc0,0x9d,0x82,0x13,0xff,0xff,0xbd,0x70,0x20,0x20,0x72,0xe0,0x40,0x2a,0x11,0xdb,0x00,0x6c,0xec,0x10,0x0d,0x44,0x3a,0x71,0x0e,0x04,0x14,0x42,0x01,0x54,0x86,0xd3,0x27,0x02,0x44,0xd4,0x41,0xb0,0xf2,0x10,0x42,0x55,0x38,0x71,0x1b,0x10,0x18,0xa0,0x41,0x11,0xb1,0xc8,0x28,0x98,0x09,0xfc,0x00,0x72,0x35,0x49,0x8d,0x0b,0xc1,0x70,0xf0,0x10,0x4b,0x51,0x11,0xc2,0x6c,0x0a,0xa3,0x03,0x80,0x7f,0xbf,0xf3,0x08,0x46,0x60,0x90,0x30,0x60,0x50,0xd8,0x2c,0x11,0x0c,0x71,0x5c,0x60,0xf8,0x0f,0xcf,0x3f,0x81,0x80,0xa1,0x9e,0x86,0x0f,0xc0,0x82,0x64,0x30,0x3e,0x09,0x84,0x03,0xf1,0x03,0xa0,0x40,0xa4,0x18,0x39,0xfc,0x20,0x52,0x30,0x19,0x07,0xc6,0x8e,0x4a,0x18,0x22,0x74,0x60,0x1a,0x0f,0xc6,0x3c,0x60,0x5c,0x05,0x28,0xe4,0x3f,0x99,0xf8,0x22,0x28,0x7e,0x05,0x91,0xa8,0x7f,0x23,0xf0,0x59,0x00,0xac,0x63,0xe0,0x81,0xcf,0x4f,0xe0,0xb1,0x81,0x58,0xc3,0xc1,0x08,0x24,0x1f,0xf9,0x68,0x6a,0x1f,0xe9,0xff,0x16,0x02,0x34,0x13,0x50,0x82,0x0a,0xea,0x60,0x1f,0xf9,0xf0,0x41,0x05,0x1d,0x30,0x09,0x18,0x60,0x15,0xa3,0xe8,0x83,0x47,0xe0,0xec,0x2c,0xaf,0xf2,0x0e,0x08,0x1f,0xc1,0x18,0x60,0x1a,0xaf,0xc2,0x6c,0x89,0x62,0x03,0x19,0xad,0xe5,0x70,0x44,0x62,0x80,0x5a,0xa1,0x4f,0x63,0x23,0x0c,0x7a,0xaa,0x4d,0x11,0xe9,0x00,0x06,0x73,0xaa,0x25,0x0a,0x78,0xaf,0x90,0x09,0x25,0x54,0x56,0x5f,0x04,0x30,0xc0,0x64,0x7a,0xa1,0x11,0x7e,0x20,0x18,0x0f,0x3c,0x82,0xaa,0x04,0x18,0x0d,0xf8,0x16,0x33,0xe8,0x84,0xa8,0x08,0x3c,0x33,0x00,0xf0,0x20,0x71,0x08,0xa9,0x38,0x86,0x62,0x62,0x18,0x40,0x44,0x80,0x09,0x04,0x08,0x90,0x01,0x20,0x41,0x17,0x22,0x90,0x01,0x3e,0x00,0x76,0x80,0x1d,0x48,0x00,0x8d,0x91,0x00,0x34,0xf8,0x20,0xe2,0xa7,0x9c,0x06,0x5c,0x11,0x02,0x28,0x5d,0x91,0x35,0x48,0xaf,0xf8,0x04,0x3f,0xf9,0x88,0x20,0x01,}; -const uint8_t *_I_DolphinFirstStart0_70x53[] = {_I_DolphinFirstStart0_70x53_0}; - const uint8_t _I_DolphinFirstStart6_58x54_0[] = {0x01,0x00,0x21,0x01,0x00,0x0f,0xf2,0x7e,0x06,0x4c,0x04,0x0f,0x81,0x03,0x03,0x9d,0x80,0x04,0x30,0xc0,0x39,0xc6,0x00,0x43,0x30,0x03,0x9c,0x10,0x04,0x34,0x00,0x39,0xc0,0x84,0x44,0x07,0x38,0x08,0x0d,0x41,0x68,0x13,0x70,0x39,0x08,0xd0,0x56,0xa1,0xd1,0x03,0x94,0x80,0x04,0x30,0x68,0x04,0x20,0x0e,0x84,0x91,0x03,0xa9,0x64,0x62,0x80,0x41,0x88,0x40,0x3f,0xc6,0xf1,0xfe,0x43,0xc0,0xe3,0x80,0xff,0xff,0xe0,0x3f,0xf8,0xf8,0x1c,0x78,0x18,0x1f,0xfe,0x0f,0x02,0x12,0x18,0x47,0x03,0x82,0x10,0x1e,0x08,0x1c,0xf5,0x60,0x71,0xd4,0x81,0xcf,0xab,0xff,0xd5,0xf5,0xc0,0xe3,0x04,0xe0,0x03,0x86,0xae,0x27,0x28,0x27,0x40,0x0e,0x21,0x91,0x03,0x96,0x80,0x0e,0x34,0x18,0x79,0x28,0x60,0x95,0x00,0x38,0xf8,0x20,0x27,0xd1,0x82,0x6a,0x03,0xc3,0x1c,0x39,0x94,0x0a,0xa1,0xc0,0xc5,0x2f,0xca,0x05,0x02,0x90,0x24,0x56,0x04,0x68,0x10,0x01,0x4f,0x80,0xea,0x5b,0x10,0x38,0x83,0x8d,0xa0,0x30,0x30,0x38,0xa3,0x09,0xc0,0x20,0xf2,0x03,0x90,0xc0,0x46,0xe2,0x91,0x2f,0x80,0xfc,0xe0,0x1e,0x08,0x02,0x54,0x47,0x62,0x27,0x2f,0xfb,0x14,0xdc,0xc6,0xb5,0x30,0x38,0x8b,0x05,0x6a,0x60,0x01,0x89,0x00,0xc8,0x16,0x50,0x29,0x10,0x1c,0x8d,0x25,0x05,0xa1,0x15,0xc9,0xfe,0x50,0xaa,0x08,0x10,0x67,0x01,0x22,0x8a,0xe0,0x60,0xe5,0xf2,0x07,0x8e,0xa8,0xb0,0x49,0xe1,0x00,0x0d,0xd4,0x68,0x5a,0x00,0x39,0x46,0x88,0x84,0x07,0x30,0xe8,0x81,0xc6,0x40,0x4d,0x11,0x91,0x17,0x06,0x40,0x65,0x11,0x51,0x01,0xc6,0x81,0x04,0x32,0x18,0x1e,0x92,0x64,0x00,0x11,0x68,0x81,0xd6,0xa0,0x07,0x16,0x22,0x6b,0x0a,0x82,0x07,0x3f,0x05,0x4d,0xdc,0x24,0x21,}; const uint8_t *_I_DolphinFirstStart6_58x54[] = {_I_DolphinFirstStart6_58x54_0}; -const uint8_t _I_DolphinFirstStart1_59x53_0[] = {0x01,0x00,0x1e,0x01,0x00,0x0e,0x03,0xfe,0x07,0x5b,0x84,0x02,0x06,0x07,0x48,0x64,0x02,0x08,0x07,0x48,0x14,0x02,0x10,0x07,0x48,0x0c,0x03,0x21,0x3f,0x13,0x18,0x84,0xa8,0x00,0x75,0x8c,0x00,0xca,0x00,0x0b,0x28,0x20,0x1d,0xa0,0x59,0xe0,0x39,0x48,0x07,0x03,0x81,0xd5,0x81,0xd6,0x81,0x55,0x8c,0x01,0xc6,0x21,0x00,0x87,0x68,0x25,0x52,0x40,0x39,0x7c,0x21,0xf5,0x08,0xa8,0x1d,0x20,0xfa,0x88,0x70,0x1c,0xfd,0x10,0x3a,0xa4,0x1f,0x88,0x54,0x18,0x85,0x52,0x09,0xbe,0x81,0xc1,0x0c,0x83,0x10,0x94,0x40,0x39,0xf0,0x19,0x21,0xc8,0x62,0x12,0x0c,0x04,0x0e,0x0c,0x07,0x38,0x07,0x86,0x07,0x18,0x03,0x94,0xc2,0x01,0x9e,0x81,0xca,0x38,0x89,0x21,0x0f,0x0c,0x03,0xf9,0x27,0x13,0x94,0xd0,0xb6,0x70,0x20,0x38,0xda,0x80,0xe5,0x10,0x03,0x95,0x59,0x54,0x70,0x10,0x38,0xda,0xc0,0xc3,0xfe,0xc1,0xab,0x0b,0xaa,0x2a,0x1c,0x05,0x81,0x58,0x38,0x09,0xd0,0x5c,0xa3,0xe0,0x72,0x86,0xae,0x8d,0x40,0x34,0x06,0xa1,0xc0,0xc0,0xe3,0xc0,0x65,0x1c,0x19,0x58,0x29,0xe1,0x00,0x14,0x28,0x0a,0x26,0x61,0x00,0x15,0x58,0x0a,0x2e,0x34,0xd6,0x42,0x9e,0x6b,0x54,0x82,0x92,0x08,0x1e,0x63,0x41,0x1d,0x0a,0x88,0x60,0x1d,0x42,0x11,0x5c,0x01,0xe5,0x3c,0x03,0x97,0x30,0x0e,0x42,0x42,0x80,0xd0,0x82,0xe4,0x07,0x28,0x17,0x10,0x1e,0xb0,0x4a,0x20,0x3d,0x61,0x1a,0x80,0x79,0x0f,0x0a,0x21,0x70,0x07,0x90,0x1c,0xa4,0x1a,0x00,0x7a,0xd0,0x0e,0x42,0x34,0x20,0x10,0xe0,0x00,0xed,0x00,0xa1,0x82,0xc8,0xc6,0x74,0x40,0xd9,0x01,0xce,0x84,0x07,0x69,0x10,0xcc,0x80,0xe7,0x5c,0x03,0xb4,0xa8,0x96,0x40,0x73,0x8a,0x96,0xc8,0x0c,0x40,}; -const uint8_t *_I_DolphinFirstStart1_59x53[] = {_I_DolphinFirstStart1_59x53_0}; - -const uint8_t _I_DolphinFirstStart8_56x51_0[] = {0x01,0x00,0xfd,0x00,0x00,0x17,0x83,0xff,0x01,0x03,0x1c,0x72,0x01,0x06,0x03,0x1c,0x0e,0x01,0x18,0x02,0x96,0x00,0x04,0x36,0x00,0x31,0x50,0x01,0x24,0x1c,0x29,0x00,0x28,0xa0,0x40,0x21,0x88,0x01,0x8a,0x08,0x02,0x18,0x40,0x18,0x80,0x64,0x09,0x20,0x89,0x81,0x98,0x3c,0x42,0x63,0x03,0x30,0xcc,0x70,0x10,0x71,0xd9,0x01,0x86,0xc1,0x1c,0x03,0x24,0x42,0x7e,0x50,0x12,0x91,0x62,0x2f,0xf8,0x0e,0x00,0x18,0xb9,0x17,0x1c,0x04,0x83,0x02,0x06,0x1e,0x27,0xc4,0x54,0x20,0x62,0xf2,0x7c,0xe0,0x52,0x0c,0x10,0x88,0x7c,0x9f,0xf8,0x28,0x18,0x41,0xa5,0xff,0x85,0x48,0x30,0x80,0xd1,0xe4,0x5f,0xc1,0xa3,0x84,0x26,0x0f,0x23,0xfe,0x1b,0x18,0x44,0x16,0x01,0x90,0x81,0xc1,0x62,0x10,0x84,0xc0,0xf8,0x20,0x30,0x28,0x84,0x40,0x1a,0x25,0x11,0x82,0x42,0x22,0x11,0xf4,0xd9,0xc1,0x02,0x22,0xb2,0x38,0x14,0xc1,0x8e,0x90,0x14,0xc1,0xa2,0x86,0x02,0xc6,0x30,0x31,0x06,0x8c,0x0c,0x26,0x02,0x56,0x9d,0x04,0x0c,0x6a,0xa1,0x03,0x21,0x20,0x68,0x5f,0xe7,0xa9,0x00,0x86,0x85,0x01,0x8f,0xe0,0x08,0xe3,0x00,0xe1,0x02,0xc6,0xfe,0x16,0x23,0xe1,0x13,0x10,0xa4,0x82,0xb1,0x12,0x88,0x00,0xf0,0x91,0xe0,0x6a,0xfd,0x63,0xfc,0x08,0x78,0x18,0xb5,0x5e,0xad,0xfb,0x84,0xa0,0x95,0x48,0xad,0x54,0x4a,0x50,0x4d,0x44,0x6b,0x56,0x0d,0x28,0x45,0x42,0x6a,0x0d,0x38,0x46,0x02,0x55,0xaa,0x35,0x25,0x52,0xac,0x06,0x4b,0x04,0xa8,0x0c,0x94,0x03,0xa0,0x80,0x04,}; -const uint8_t *_I_DolphinFirstStart8_56x51[] = {_I_DolphinFirstStart8_56x51_0}; - -const uint8_t _I_DolphinFirstStart7_61x51_0[] = {0x01,0x00,0x13,0x01,0x00,0x17,0x03,0xff,0x01,0x03,0xa4,0xe2,0x01,0x0e,0x03,0xa4,0x1a,0x01,0x30,0x03,0x1e,0x00,0x2a,0x3c,0x00,0x39,0xd0,0x00,0x65,0x03,0x01,0x94,0x80,0x06,0x50,0x40,0x19,0x44,0x00,0x65,0x08,0x01,0xb0,0x2c,0xe2,0x81,0xb6,0x86,0x0a,0xd8,0x7c,0x20,0x75,0x85,0x10,0xcc,0x06,0x50,0x50,0x3b,0x10,0xce,0x00,0x69,0x20,0x79,0x7c,0x20,0x20,0x71,0xc0,0x07,0xca,0xf1,0x02,0x81,0x01,0xc6,0x3a,0x07,0x1f,0xe4,0x10,0x0e,0x53,0xe0,0x38,0xe7,0xa0,0xa0,0x72,0xbb,0x81,0xca,0x12,0x68,0x1c,0x05,0x5c,0x0e,0x3f,0xe8,0xc8,0x1c,0xab,0xe0,0x72,0x94,0x81,0xda,0xb2,0x07,0x5f,0xe0,0x3d,0xbf,0x95,0x44,0x20,0x81,0xce,0xf1,0x2f,0x03,0x94,0xb8,0xae,0x51,0x00,0x39,0x47,0x60,0xd0,0x84,0x70,0x81,0xcb,0x44,0x9d,0x10,0x3a,0x58,0xce,0xe6,0x07,0x29,0x10,0x18,0xa0,0x50,0x88,0x76,0x02,0x22,0x07,0x49,0x8e,0x02,0x24,0x07,0x4e,0x0e,0x02,0x12,0x96,0x38,0x44,0x07,0x02,0x8f,0x1c,0x07,0x1c,0x4e,0x30,0x1c,0x10,0x3c,0x6c,0x13,0x80,0x38,0xc0,0xb0,0x80,0xf1,0x6e,0x90,0x1c,0x71,0x10,0xd7,0x49,0x81,0xc7,0x20,0x0f,0x17,0xe9,0x42,0x20,0x91,0x09,0xeb,0x24,0xe2,0x10,0x49,0x07,0x6f,0xff,0x80,0x56,0x88,0x1c,0xa2,0xae,0xd1,0x66,0x89,0xe0,0x68,0x11,0xb8,0x06,0xc0,0x2e,0x40,0x71,0x9a,0xc0,0x2b,0x00,0x73,0xc0,0x7a,0xe0,0x09,0x12,0x03,0x95,0x57,0xff,0x17,0x03,0x9c,0x03,0x57,0xaa,0x78,0x94,0x40,0xa6,0x35,0x5a,0xac,0x14,0x0e,0x9a,0xad,0x50,0xf8,0x41,0x05,0x00,0x83,0x55,0x14,0x06,0x07,0x18,0x54,0xa0,0x0e,0xb0,0x60,0x31,0xc0,0x00,}; -const uint8_t *_I_DolphinFirstStart7_61x51[] = {_I_DolphinFirstStart7_61x51_0}; - const uint8_t _I_Flipper_young_80x60_0[] = {0x01,0x00,0xa3,0x01,0x00,0x1e,0x03,0xff,0xff,0x87,0x82,0x57,0xf1,0x83,0x90,0xde,0x01,0x2b,0x0e,0x83,0x70,0xfb,0x10,0x10,0x41,0xf8,0x27,0x70,0xcc,0x34,0xc6,0x0e,0x09,0x3e,0x04,0x86,0x21,0x0c,0x90,0xc3,0x03,0xa9,0xe7,0xb0,0x46,0x2c,0x51,0x40,0x4a,0x63,0x38,0x31,0x0a,0x34,0x90,0x12,0x91,0x8e,0x3c,0xff,0x89,0x4c,0x04,0xa4,0x43,0xfd,0xf3,0xc3,0xf2,0x01,0x29,0xe0,0x2b,0x8e,0x72,0xa0,0x46,0x4b,0xe0,0x30,0xba,0x10,0x22,0xca,0x1c,0x0b,0x26,0x09,0x3c,0x04,0x0c,0x08,0x59,0xc8,0x21,0x64,0xc4,0x47,0x98,0x82,0x81,0x0a,0xe0,0x21,0x39,0x04,0x34,0x88,0x60,0x93,0xa0,0x45,0x4b,0x06,0xa3,0x40,0x48,0xfc,0x20,0xf0,0x82,0xa2,0x4d,0x60,0x11,0xe9,0xc2,0x19,0x64,0xd0,0x08,0x1f,0x80,0x7e,0x60,0x01,0x92,0x60,0x20,0x38,0x05,0x21,0x7c,0x3f,0xf0,0x1a,0xe6,0x00,0xe6,0x21,0x32,0x1a,0x0c,0x0e,0x91,0x80,0x8f,0xc0,0x06,0x25,0xcc,0xbf,0xc1,0xaa,0x10,0x0b,0xfc,0x02,0x60,0x2e,0x2c,0x04,0x32,0xc1,0x00,0xff,0x40,0x68,0x00,0x91,0x89,0xc0,0x21,0x20,0x51,0xfe,0x41,0xf0,0x00,0x91,0xc4,0xcf,0xe2,0x40,0x51,0xfc,0x0c,0x86,0x07,0x80,0xe2,0xdf,0xda,0x25,0xf0,0x9f,0xc0,0x21,0x98,0x0f,0x27,0xfd,0xa2,0x5e,0x01,0x90,0xc4,0x30,0x1e,0x2f,0xfc,0xa1,0x3a,0x45,0x41,0xb0,0x60,0x3e,0x5e,0x79,0x4a,0x10,0xbf,0xe2,0x61,0xc0,0x82,0x52,0x01,0xff,0x36,0x8e,0x3b,0xe5,0xff,0x04,0x9f,0xf8,0x78,0x3b,0x8f,0x97,0xf8,0x12,0x7f,0xc3,0x78,0xf8,0x3e,0x5f,0xc0,0x49,0xfe,0x08,0xc2,0x17,0x1f,0xcd,0xa5,0xac,0x5f,0x02,0x30,0xc0,0x30,0x5f,0xfd,0x23,0xbc,0xbc,0x1f,0xf0,0xc1,0x5f,0xaa,0x8e,0x52,0x28,0x10,0x10,0x6f,0x1b,0x28,0x57,0x81,0x66,0x25,0x01,0x80,0x4e,0x28,0x15,0x98,0xad,0xc3,0xfd,0xff,0xff,0x91,0x87,0xc1,0x80,0xd4,0xc2,0xb2,0x03,0xb1,0x5b,0x13,0x34,0x6a,0xf1,0x58,0x84,0x0e,0x1d,0x00,0x23,0x14,0x0f,0x55,0x0a,0x88,0x67,0x0d,0x83,0x7c,0x04,0x8c,0x0a,0xa9,0x15,0x90,0x7c,0x07,0x23,0xf8,0x80,0xc1,0xa0,0xda,0x88,0x54,0x82,0x00,0x2f,0x1f,0xe4,0x3c,0x7a,0x35,0x08,0xab,0x20,0x7f,0x03,0xc1,0x2d,0x96,0x82,0x14,0xce,0x20,0x02,0x04,0xc6,0x00,0x60,0x20,0x01,0x84,0xc4,0x6a,0x21,0x36,0x3b,0x8c,0xf0,0x3c,0xc8,0x02,0x1b,0x88,0x01,0xe1,0x80,0x98,0x2d,0x10,0x01,0xb0,0x05,0xa1,0x00,0x3d,0xf8,0x13,0x17,0x81,0x47,0x80,0x0b,0xc0,0x28,0x8e,0x02,0xa4,0x81,0x2c,0xf0,0x20,0x01,0x00,}; const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_0}; +const uint8_t _I_DolphinFirstStart8_56x51_0[] = {0x01,0x00,0xfd,0x00,0x00,0x17,0x83,0xff,0x01,0x03,0x1c,0x72,0x01,0x06,0x03,0x1c,0x0e,0x01,0x18,0x02,0x96,0x00,0x04,0x36,0x00,0x31,0x50,0x01,0x24,0x1c,0x29,0x00,0x28,0xa0,0x40,0x21,0x88,0x01,0x8a,0x08,0x02,0x18,0x40,0x18,0x80,0x64,0x09,0x20,0x89,0x81,0x98,0x3c,0x42,0x63,0x03,0x30,0xcc,0x70,0x10,0x71,0xd9,0x01,0x86,0xc1,0x1c,0x03,0x24,0x42,0x7e,0x50,0x12,0x91,0x62,0x2f,0xf8,0x0e,0x00,0x18,0xb9,0x17,0x1c,0x04,0x83,0x02,0x06,0x1e,0x27,0xc4,0x54,0x20,0x62,0xf2,0x7c,0xe0,0x52,0x0c,0x10,0x88,0x7c,0x9f,0xf8,0x28,0x18,0x41,0xa5,0xff,0x85,0x48,0x30,0x80,0xd1,0xe4,0x5f,0xc1,0xa3,0x84,0x26,0x0f,0x23,0xfe,0x1b,0x18,0x44,0x16,0x01,0x90,0x81,0xc1,0x62,0x10,0x84,0xc0,0xf8,0x20,0x30,0x28,0x84,0x40,0x1a,0x25,0x11,0x82,0x42,0x22,0x11,0xf4,0xd9,0xc1,0x02,0x22,0xb2,0x38,0x14,0xc1,0x8e,0x90,0x14,0xc1,0xa2,0x86,0x02,0xc6,0x30,0x31,0x06,0x8c,0x0c,0x26,0x02,0x56,0x9d,0x04,0x0c,0x6a,0xa1,0x03,0x21,0x20,0x68,0x5f,0xe7,0xa9,0x00,0x86,0x85,0x01,0x8f,0xe0,0x08,0xe3,0x00,0xe1,0x02,0xc6,0xfe,0x16,0x23,0xe1,0x13,0x10,0xa4,0x82,0xb1,0x12,0x88,0x00,0xf0,0x91,0xe0,0x6a,0xfd,0x63,0xfc,0x08,0x78,0x18,0xb5,0x5e,0xad,0xfb,0x84,0xa0,0x95,0x48,0xad,0x54,0x4a,0x50,0x4d,0x44,0x6b,0x56,0x0d,0x28,0x45,0x42,0x6a,0x0d,0x38,0x46,0x02,0x55,0xaa,0x35,0x25,0x52,0xac,0x06,0x4b,0x04,0xa8,0x0c,0x94,0x03,0xa0,0x80,0x04,}; +const uint8_t *_I_DolphinFirstStart8_56x51[] = {_I_DolphinFirstStart8_56x51_0}; + +const uint8_t _I_DolphinFirstStart1_59x53_0[] = {0x01,0x00,0x1e,0x01,0x00,0x0e,0x03,0xfe,0x07,0x5b,0x84,0x02,0x06,0x07,0x48,0x64,0x02,0x08,0x07,0x48,0x14,0x02,0x10,0x07,0x48,0x0c,0x03,0x21,0x3f,0x13,0x18,0x84,0xa8,0x00,0x75,0x8c,0x00,0xca,0x00,0x0b,0x28,0x20,0x1d,0xa0,0x59,0xe0,0x39,0x48,0x07,0x03,0x81,0xd5,0x81,0xd6,0x81,0x55,0x8c,0x01,0xc6,0x21,0x00,0x87,0x68,0x25,0x52,0x40,0x39,0x7c,0x21,0xf5,0x08,0xa8,0x1d,0x20,0xfa,0x88,0x70,0x1c,0xfd,0x10,0x3a,0xa4,0x1f,0x88,0x54,0x18,0x85,0x52,0x09,0xbe,0x81,0xc1,0x0c,0x83,0x10,0x94,0x40,0x39,0xf0,0x19,0x21,0xc8,0x62,0x12,0x0c,0x04,0x0e,0x0c,0x07,0x38,0x07,0x86,0x07,0x18,0x03,0x94,0xc2,0x01,0x9e,0x81,0xca,0x38,0x89,0x21,0x0f,0x0c,0x03,0xf9,0x27,0x13,0x94,0xd0,0xb6,0x70,0x20,0x38,0xda,0x80,0xe5,0x10,0x03,0x95,0x59,0x54,0x70,0x10,0x38,0xda,0xc0,0xc3,0xfe,0xc1,0xab,0x0b,0xaa,0x2a,0x1c,0x05,0x81,0x58,0x38,0x09,0xd0,0x5c,0xa3,0xe0,0x72,0x86,0xae,0x8d,0x40,0x34,0x06,0xa1,0xc0,0xc0,0xe3,0xc0,0x65,0x1c,0x19,0x58,0x29,0xe1,0x00,0x14,0x28,0x0a,0x26,0x61,0x00,0x15,0x58,0x0a,0x2e,0x34,0xd6,0x42,0x9e,0x6b,0x54,0x82,0x92,0x08,0x1e,0x63,0x41,0x1d,0x0a,0x88,0x60,0x1d,0x42,0x11,0x5c,0x01,0xe5,0x3c,0x03,0x97,0x30,0x0e,0x42,0x42,0x80,0xd0,0x82,0xe4,0x07,0x28,0x17,0x10,0x1e,0xb0,0x4a,0x20,0x3d,0x61,0x1a,0x80,0x79,0x0f,0x0a,0x21,0x70,0x07,0x90,0x1c,0xa4,0x1a,0x00,0x7a,0xd0,0x0e,0x42,0x34,0x20,0x10,0xe0,0x00,0xed,0x00,0xa1,0x82,0xc8,0xc6,0x74,0x40,0xd9,0x01,0xce,0x84,0x07,0x69,0x10,0xcc,0x80,0xe7,0x5c,0x03,0xb4,0xa8,0x96,0x40,0x73,0x8a,0x96,0xc8,0x0c,0x40,}; +const uint8_t *_I_DolphinFirstStart1_59x53[] = {_I_DolphinFirstStart1_59x53_0}; + +const uint8_t _I_DolphinOkay_41x43_0[] = {0x01,0x00,0xa0,0x00,0x00,0x0f,0x82,0x3e,0x05,0x38,0xf7,0x80,0x08,0x58,0x08,0x0c,0x02,0x0e,0x05,0x1b,0x00,0x08,0x63,0x00,0x21,0x88,0x00,0x86,0x40,0x02,0x18,0x40,0x08,0x68,0x00,0x21,0x82,0x06,0x88,0x0a,0xf0,0x21,0x39,0x09,0x84,0x02,0x20,0x57,0x09,0x98,0x15,0x67,0xc0,0x54,0xbe,0x81,0x4f,0x01,0xfe,0x02,0x9d,0x03,0xc4,0x20,0x10,0x29,0x7c,0x80,0xa9,0xfe,0x02,0xac,0x14,0x0a,0x77,0xc8,0x58,0x8c,0xf0,0x11,0x51,0x79,0xff,0x61,0x44,0x93,0x81,0x02,0xc4,0x9e,0x60,0xb2,0xf0,0xa0,0x46,0x0c,0x17,0x14,0x99,0x1a,0x07,0x80,0x59,0x49,0x82,0x21,0xc0,0xa4,0x82,0x24,0xb9,0x20,0x88,0x1c,0x47,0xc2,0x07,0x11,0x54,0xa0,0x60,0x53,0xb8,0x0a,0x4b,0xf3,0x03,0x87,0x81,0x4a,0x0d,0xfc,0x1a,0x98,0x68,0xb8,0x01,0x51,0x13,0x15,0xe0,0x82,0x7f,0x8d,0x78,0x38,0xbf,0xff,0xfa,0xb8,0x60,0xbf,0x1b,0xf9,0x50,0x14,0xea,0xe7,0x02,0x02,0x8e,0xac,0x94,0x40,}; +const uint8_t *_I_DolphinOkay_41x43[] = {_I_DolphinOkay_41x43_0}; + const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x01,0x00,0x12,0x01,0x00,0x16,0x03,0xff,0x07,0x03,0xa5,0x82,0x01,0x38,0x03,0xa4,0x62,0x01,0xc0,0x03,0xa4,0x10,0x04,0x30,0x10,0x39,0xc0,0x80,0x48,0x0c,0x40,0x91,0x7e,0x20,0x60,0x72,0x84,0x02,0x8b,0x78,0x12,0x28,0x80,0x68,0x85,0x87,0x20,0x11,0x18,0x5c,0x80,0xe8,0x01,0x19,0xc5,0x00,0x0e,0x62,0xc1,0x9f,0x01,0xcb,0xe9,0x03,0x84,0x60,0x20,0xf8,0x00,0x38,0xd7,0x21,0xb1,0x0f,0x04,0x04,0x0e,0x5a,0x89,0xd4,0x83,0xc0,0x4b,0x3a,0xc5,0x54,0xcc,0x20,0x51,0x00,0x8e,0xc3,0x54,0x80,0x13,0xf8,0x81,0xc6,0xc1,0x55,0x01,0x8c,0x78,0x0e,0x30,0xee,0x06,0xaa,0x05,0xe0,0xae,0x01,0xc6,0x23,0x80,0xaa,0xc1,0x60,0x1a,0x90,0x38,0xc8,0x60,0x1a,0xb8,0x54,0x02,0xad,0x07,0x80,0xd0,0x40,0x83,0x15,0x80,0x7b,0x21,0x10,0x1c,0x0c,0x03,0x7f,0x2a,0x80,0x4d,0x00,0xe3,0x01,0xf8,0xf0,0x2a,0xf0,0x08,0x60,0x1c,0x60,0x41,0xd1,0xdf,0x1a,0x44,0x0e,0x50,0x68,0x05,0xe3,0x07,0x02,0x82,0x01,0xc6,0x19,0x00,0xf8,0x5f,0xe0,0x20,0x72,0xfa,0x40,0x7f,0xc2,0xb1,0x03,0x88,0x68,0x7f,0xf6,0xb4,0x28,0xc0,0x80,0xe3,0x88,0xaa,0xc7,0x40,0xe9,0x50,0xd5,0x41,0x94,0xa2,0x07,0x29,0x87,0x52,0x02,0x07,0x12,0x30,0xc1,0x22,0x16,0x86,0x29,0x01,0xca,0x30,0xf6,0x10,0x39,0xc2,0x23,0x10,0x6c,0x00,0x1d,0x3d,0x10,0x1b,0x02,0xe0,0x41,0x03,0x08,0x75,0x0c,0x60,0x0e,0x4f,0x11,0x0a,0x0c,0x18,0x0e,0x96,0x06,0x28,0x81,0xd3,0x01,0x1f,0x01,0x90,0x1c,0xdc,0xc2,0x01,0x15,0xd0,0x81,0xdc,0x4c,0x30,0x30,0x3f,0x00,0xc4,0x0e,0x30,0x20,0x3c,0x8c,0xc8,0x0f,0x2b,0x41,}; const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; +const uint8_t _I_DolphinFirstStart7_61x51_0[] = {0x01,0x00,0x13,0x01,0x00,0x17,0x03,0xff,0x01,0x03,0xa4,0xe2,0x01,0x0e,0x03,0xa4,0x1a,0x01,0x30,0x03,0x1e,0x00,0x2a,0x3c,0x00,0x39,0xd0,0x00,0x65,0x03,0x01,0x94,0x80,0x06,0x50,0x40,0x19,0x44,0x00,0x65,0x08,0x01,0xb0,0x2c,0xe2,0x81,0xb6,0x86,0x0a,0xd8,0x7c,0x20,0x75,0x85,0x10,0xcc,0x06,0x50,0x50,0x3b,0x10,0xce,0x00,0x69,0x20,0x79,0x7c,0x20,0x20,0x71,0xc0,0x07,0xca,0xf1,0x02,0x81,0x01,0xc6,0x3a,0x07,0x1f,0xe4,0x10,0x0e,0x53,0xe0,0x38,0xe7,0xa0,0xa0,0x72,0xbb,0x81,0xca,0x12,0x68,0x1c,0x05,0x5c,0x0e,0x3f,0xe8,0xc8,0x1c,0xab,0xe0,0x72,0x94,0x81,0xda,0xb2,0x07,0x5f,0xe0,0x3d,0xbf,0x95,0x44,0x20,0x81,0xce,0xf1,0x2f,0x03,0x94,0xb8,0xae,0x51,0x00,0x39,0x47,0x60,0xd0,0x84,0x70,0x81,0xcb,0x44,0x9d,0x10,0x3a,0x58,0xce,0xe6,0x07,0x29,0x10,0x18,0xa0,0x50,0x88,0x76,0x02,0x22,0x07,0x49,0x8e,0x02,0x24,0x07,0x4e,0x0e,0x02,0x12,0x96,0x38,0x44,0x07,0x02,0x8f,0x1c,0x07,0x1c,0x4e,0x30,0x1c,0x10,0x3c,0x6c,0x13,0x80,0x38,0xc0,0xb0,0x80,0xf1,0x6e,0x90,0x1c,0x71,0x10,0xd7,0x49,0x81,0xc7,0x20,0x0f,0x17,0xe9,0x42,0x20,0x91,0x09,0xeb,0x24,0xe2,0x10,0x49,0x07,0x6f,0xff,0x80,0x56,0x88,0x1c,0xa2,0xae,0xd1,0x66,0x89,0xe0,0x68,0x11,0xb8,0x06,0xc0,0x2e,0x40,0x71,0x9a,0xc0,0x2b,0x00,0x73,0xc0,0x7a,0xe0,0x09,0x12,0x03,0x95,0x57,0xff,0x17,0x03,0x9c,0x03,0x57,0xaa,0x78,0x94,0x40,0xa6,0x35,0x5a,0xac,0x14,0x0e,0x9a,0xad,0x50,0xf8,0x41,0x05,0x00,0x83,0x55,0x14,0x06,0x07,0x18,0x54,0xa0,0x0e,0xb0,0x60,0x31,0xc0,0x00,}; +const uint8_t *_I_DolphinFirstStart7_61x51[] = {_I_DolphinFirstStart7_61x51_0}; + +const uint8_t _I_DolphinFirstStart0_70x53_0[] = {0x01,0x00,0x5a,0x01,0x80,0x60,0x3f,0xf7,0xf0,0x42,0xf8,0x01,0x43,0x07,0x04,0x24,0x72,0x01,0xc0,0x9d,0x82,0x13,0xff,0xff,0xbd,0x70,0x20,0x20,0x72,0xe0,0x40,0x2a,0x11,0xdb,0x00,0x6c,0xec,0x10,0x0d,0x44,0x3a,0x71,0x0e,0x04,0x14,0x42,0x01,0x54,0x86,0xd3,0x27,0x02,0x44,0xd4,0x41,0xb0,0xf2,0x10,0x42,0x55,0x38,0x71,0x1b,0x10,0x18,0xa0,0x41,0x11,0xb1,0xc8,0x28,0x98,0x09,0xfc,0x00,0x72,0x35,0x49,0x8d,0x0b,0xc1,0x70,0xf0,0x10,0x4b,0x51,0x11,0xc2,0x6c,0x0a,0xa3,0x03,0x80,0x7f,0xbf,0xf3,0x08,0x46,0x60,0x90,0x30,0x60,0x50,0xd8,0x2c,0x11,0x0c,0x71,0x5c,0x60,0xf8,0x0f,0xcf,0x3f,0x81,0x80,0xa1,0x9e,0x86,0x0f,0xc0,0x82,0x64,0x30,0x3e,0x09,0x84,0x03,0xf1,0x03,0xa0,0x40,0xa4,0x18,0x39,0xfc,0x20,0x52,0x30,0x19,0x07,0xc6,0x8e,0x4a,0x18,0x22,0x74,0x60,0x1a,0x0f,0xc6,0x3c,0x60,0x5c,0x05,0x28,0xe4,0x3f,0x99,0xf8,0x22,0x28,0x7e,0x05,0x91,0xa8,0x7f,0x23,0xf0,0x59,0x00,0xac,0x63,0xe0,0x81,0xcf,0x4f,0xe0,0xb1,0x81,0x58,0xc3,0xc1,0x08,0x24,0x1f,0xf9,0x68,0x6a,0x1f,0xe9,0xff,0x16,0x02,0x34,0x13,0x50,0x82,0x0a,0xea,0x60,0x1f,0xf9,0xf0,0x41,0x05,0x1d,0x30,0x09,0x18,0x60,0x15,0xa3,0xe8,0x83,0x47,0xe0,0xec,0x2c,0xaf,0xf2,0x0e,0x08,0x1f,0xc1,0x18,0x60,0x1a,0xaf,0xc2,0x6c,0x89,0x62,0x03,0x19,0xad,0xe5,0x70,0x44,0x62,0x80,0x5a,0xa1,0x4f,0x63,0x23,0x0c,0x7a,0xaa,0x4d,0x11,0xe9,0x00,0x06,0x73,0xaa,0x25,0x0a,0x78,0xaf,0x90,0x09,0x25,0x54,0x56,0x5f,0x04,0x30,0xc0,0x64,0x7a,0xa1,0x11,0x7e,0x20,0x18,0x0f,0x3c,0x82,0xaa,0x04,0x18,0x0d,0xf8,0x16,0x33,0xe8,0x84,0xa8,0x08,0x3c,0x33,0x00,0xf0,0x20,0x71,0x08,0xa9,0x38,0x86,0x62,0x62,0x18,0x40,0x44,0x80,0x09,0x04,0x08,0x90,0x01,0x20,0x41,0x17,0x22,0x90,0x01,0x3e,0x00,0x76,0x80,0x1d,0x48,0x00,0x8d,0x91,0x00,0x34,0xf8,0x20,0xe2,0xa7,0x9c,0x06,0x5c,0x11,0x02,0x28,0x5d,0x91,0x35,0x48,0xaf,0xf8,0x04,0x3f,0xf9,0x88,0x20,0x01,}; +const uint8_t *_I_DolphinFirstStart0_70x53[] = {_I_DolphinFirstStart0_70x53_0}; + +const uint8_t _I_DolphinFirstStart4_67x53_0[] = {0x01,0x00,0x1f,0x01,0x00,0x17,0xc3,0xfe,0x08,0x68,0x74,0x02,0x0e,0x07,0x4c,0x04,0x06,0x01,0x18,0x04,0x25,0x00,0x04,0x36,0x00,0x42,0x48,0x02,0x88,0x00,0x28,0x80,0x0c,0xa0,0x40,0x83,0x84,0x00,0xca,0x08,0x08,0x30,0x21,0x83,0x0c,0x2c,0x81,0xe3,0x04,0x20,0xc0,0x80,0x02,0x31,0x32,0x11,0x02,0x27,0x00,0x5d,0x40,0x45,0x87,0x90,0x3e,0x7c,0x00,0x43,0x84,0x4e,0x60,0x43,0x30,0x89,0x82,0x12,0x80,0x15,0x20,0x40,0x99,0xc8,0x22,0x7b,0x88,0x10,0x20,0x82,0x27,0x7c,0x82,0x9d,0x48,0x22,0x5f,0x0d,0xfc,0x08,0x10,0x41,0x12,0xf8,0x57,0xc2,0x28,0x30,0x1e,0x07,0x9e,0x06,0x87,0x25,0x79,0xc4,0x20,0x40,0x83,0x21,0x14,0x22,0x08,0x08,0x38,0x2a,0xb8,0xd9,0x47,0x0a,0x14,0x09,0xf0,0x54,0x47,0x1f,0x81,0x82,0x1a,0xde,0x8e,0x33,0xd1,0xc7,0x81,0x0f,0x0e,0x45,0x18,0x20,0xa1,0xe6,0xf2,0x10,0x89,0xa0,0x70,0x11,0x00,0x41,0x46,0x03,0x86,0x55,0x10,0x40,0xc1,0x82,0x25,0x20,0x04,0x11,0x94,0x80,0x43,0x10,0x84,0x01,0x46,0xc0,0xbd,0x38,0x40,0x20,0x8f,0x49,0x08,0xc4,0x1c,0xc8,0x22,0x50,0x38,0x20,0x20,0x86,0xe4,0x83,0x10,0x41,0x8b,0x87,0xf9,0x03,0x81,0xc0,0x81,0x05,0x81,0xc0,0x40,0xf3,0x90,0x60,0x41,0x70,0x2c,0x17,0x01,0xc0,0xc1,0x41,0x05,0x30,0x98,0x43,0x04,0x65,0x01,0x04,0x0c,0x32,0x38,0x91,0x18,0x04,0x14,0x10,0x38,0x18,0x1e,0xac,0x7c,0x41,0x11,0x88,0x5f,0xfc,0x17,0x55,0xa9,0x82,0x06,0x05,0xbc,0x85,0x02,0x08,0xc6,0x32,0x0f,0xe5,0x5e,0x1a,0x08,0x5c,0x06,0xaa,0x34,0x08,0x4a,0x06,0x02,0xab,0x75,0xf0,0x4f,0xc1,0x05,0x80,0x08,0x8e,0xab,0x7f,0xea,0x04,0x11,0x80,0x6a,0xa0,0x02,0x03,0x08,}; +const uint8_t *_I_DolphinFirstStart4_67x53[] = {_I_DolphinFirstStart4_67x53_0}; + const uint8_t _I_PassportBottom_128x17_0[] = {0x01,0x00,0x5e,0x00,0x96,0x01,0x97,0xe1,0xff,0x00,0x2e,0x3e,0x68,0x0f,0x5a,0xc5,0x54,0x00,0xb9,0x50,0xfb,0x6a,0x35,0x40,0x05,0xcd,0x4e,0x03,0xfd,0x30,0x0f,0xf8,0x7f,0xa0,0x81,0xfe,0xf9,0x1b,0xfb,0xf3,0x01,0x47,0x66,0x02,0x1b,0x03,0x07,0xe7,0x02,0x0b,0x02,0x07,0xe5,0x82,0x0b,0xf2,0x1c,0xb0,0x01,0x67,0xf0,0x5f,0xd0,0x3f,0x23,0xf0,0x9b,0xc9,0xe5,0x80,0x03,0xd5,0xc0,0x00,0x86,0x01,0xf3,0xe6,0x1e,0x58,0x00,0x36,0xa8,0x06,0xac,0x04,0x30,0x6c,0x30,0xee,0x60,0x1f,0xe0,0x10,0xff,0x0d,0xfb,0x00,}; const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; -const uint8_t _I_DoorLocked_10x56_0[] = {0x01,0x00,0x4e,0x00,0x86,0x40,0x25,0xb0,0x0b,0x6c,0x03,0x9b,0x00,0xc6,0xc0,0x65,0x90,0x10,0x3a,0xc3,0x20,0x31,0xc8,0x04,0xe2,0x01,0x70,0x80,0x78,0x20,0x1c,0x48,0x07,0x22,0x01,0xd0,0x00,0xf0,0x44,0x68,0x90,0x09,0x04,0x02,0x21,0x00,0x84,0x40,0x25,0x80,0x12,0x1e,0x88,0x14,0xc0,0x2e,0x0d,0x11,0xca,0xf8,0x60,0x1c,0x38,0x07,0x1a,0x05,0xcc,0x80,0x72,0x60,0x5c,0x38,0x10,0x1c,0xf9,0x10,0x2e,0x00,0x05,0x60,0x00,0x11,}; -const uint8_t *_I_DoorLocked_10x56[] = {_I_DoorLocked_10x56_0}; - const uint8_t _I_DoorLeft_70x55_0[] = {0x01,0x00,0x19,0x01,0x00,0x2c,0x32,0x01,0x03,0x04,0x2c,0x18,0x10,0xf0,0x40,0x47,0x82,0x06,0x81,0x03,0xff,0x80,0x08,0x1a,0x20,0x82,0x15,0x28,0x21,0x87,0x82,0x08,0x6f,0xc0,0xb1,0xe6,0x10,0x10,0x8b,0x46,0x20,0x43,0x55,0x8f,0x82,0x10,0x32,0x73,0x0a,0x09,0x89,0x6c,0x1e,0x09,0x00,0x18,0x60,0xf0,0x0c,0x84,0x93,0x82,0x03,0x18,0x0c,0x02,0x1d,0x00,0x90,0x52,0x70,0x50,0x1e,0x00,0x58,0x63,0x90,0x0a,0x06,0x4a,0x09,0x03,0xb0,0x02,0x06,0x70,0x62,0x49,0xf8,0x0c,0x66,0x3f,0xf0,0x41,0x63,0x04,0x43,0x00,0x99,0x60,0x00,0x85,0xc8,0x06,0x14,0xd0,0x80,0x3f,0xc8,0x0d,0xb8,0x10,0x70,0xf8,0x34,0x13,0x03,0x39,0x04,0x1c,0x42,0x19,0xf8,0xa0,0xc2,0x01,0x07,0xef,0x02,0x8c,0x80,0x10,0x9d,0x00,0x43,0xec,0x00,0xa3,0x10,0x04,0x25,0xce,0x19,0xfc,0x88,0x82,0x12,0x0c,0x35,0x10,0x42,0x4c,0xa1,0x90,0x3f,0xc0,0x21,0x22,0x39,0x82,0xc8,0x88,0xd2,0x11,0xf0,0x01,0x88,0xd5,0x18,0xe2,0x08,0x68,0x10,0x0c,0xa8,0x00,0x83,0x81,0xcc,0xd5,0xc3,0x80,0x84,0x82,0x0e,0xcc,0xc0,0x15,0x79,0x02,0x0b,0x98,0xf8,0x11,0x88,0x82,0x0f,0x31,0x19,0x02,0x08,0x2c,0x9f,0x6a,0x1d,0x20,0x41,0x31,0x4c,0x10,0x8d,0x73,0x04,0x23,0xa4,0xc4,0x6c,0xde,0x20,0x42,0xcc,0x01,0x07,0x07,0xff,0x80,0x06,0x3e,0x08,0x38,0x70,0x20,0xa1,0xe0,0x83,0x8e,0x01,0x0c,0xf0,0x73,0x80,0x43,0x70,0x05,0x08,0x00,0x2c,0x04,0xc4,0x46,0x53,0x09,0x98,0x24,0x80,0x65,0x80,0xb0,0xd9,0x84,0x65,0x32,0x06,0x17,0x0f,0x98,0x23,0x63,0xe1,0x88,0xc4,0x08,0x5f,0xc1,0x30,0x9d,0x84,0x4e,0x66,0x94,0x11,0x98,0x75,0x26,0x00,}; const uint8_t *_I_DoorLeft_70x55[] = {_I_DoorLeft_70x55_0}; -const uint8_t _I_PassportLeft_6x47_0[] = {0x01,0x00,0x1c,0x00,0x9e,0x40,0xa3,0x32,0x59,0x2c,0x66,0x03,0x01,0x82,0xc2,0x62,0x32,0x50,0x16,0xc8,0x60,0x30,0x28,0x24,0x32,0x39,0x3c,0x9e,0x4d,0x25,0x80,0x1a,}; -const uint8_t *_I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; - const uint8_t _I_DoorRight_70x55_0[] = {0x01,0x00,0x16,0x01,0x81,0xcc,0x01,0x0f,0x60,0x04,0x3f,0x00,0x10,0xf8,0x08,0x0c,0x02,0x05,0x01,0x84,0x02,0x06,0x26,0x0a,0x10,0x8a,0xcc,0xe0,0x1d,0x68,0xe0,0x18,0xab,0xd0,0x0b,0x18,0x10,0x46,0xe6,0x16,0x1e,0x18,0x10,0x46,0xe4,0x28,0x2c,0x98,0x14,0x68,0x00,0x21,0x1d,0x10,0x8c,0x40,0x02,0x0e,0x10,0xa1,0x08,0xc8,0x40,0x42,0x62,0x11,0x94,0x03,0xfd,0xff,0x00,0x0c,0xff,0x0c,0x08,0x28,0x60,0xe4,0xc0,0x85,0x00,0x83,0x00,0x87,0xf1,0x00,0x8c,0x02,0x0b,0x07,0x24,0x84,0xff,0x04,0xc7,0x80,0xa0,0xe4,0xa0,0x81,0x41,0x04,0x17,0x02,0x41,0x49,0x81,0x0e,0x10,0xb2,0xa0,0x82,0x0e,0x9f,0xfc,0x0a,0x62,0xf2,0xc0,0x03,0x92,0xf0,0x08,0x2d,0x78,0x20,0xff,0x02,0x01,0x08,0xae,0x60,0x64,0x38,0x0d,0xb0,0x8d,0x08,0x82,0x11,0x58,0xc4,0x13,0xc0,0x35,0x68,0x62,0x68,0x81,0x09,0x08,0x84,0x40,0x81,0x0d,0x18,0x69,0x10,0x47,0x44,0x66,0x5f,0x21,0xa9,0x29,0x94,0x10,0x2f,0x23,0x53,0x14,0x60,0x42,0x3c,0x08,0xfc,0x02,0x2c,0x62,0x23,0x58,0xd0,0x22,0x00,0x83,0x3e,0x98,0x44,0x43,0x46,0x22,0x30,0x89,0xce,0x01,0x0f,0x70,0x04,0x3f,0x81,0x8a,0x3c,0x21,0xaa,0x70,0x1a,0xe3,0x44,0x1a,0xa6,0x01,0xd2,0x38,0x90,0x8a,0x40,0x20,0xe5,0x96,0x80,0x43,0x81,0x06,0x6b,0x28,0x07,0xf3,0xfe,0x00,0x19,0xf9,0x34,0xc1,0x08,0x8f,0x20,0xf1,0x3e,0x16,0x00,0xa8,0x19,0x00,0x10,0x76,0x03,0xe2,0x3e,0x90,0x45,0x38,0x01,0x42,0x05,0x88,0x44,0x67,0x15,0x70,0x41,0x38,0x04,0x10,0x24,0x03,0x00,0x10,0x20,0x4a,0x46,0xe9,0x46,0xe1,0x04,0x50,0x66,0x40,0x85,0x19,0x98,0x00,0xc0,}; const uint8_t *_I_DoorRight_70x55[] = {_I_DoorRight_70x55_0}; +const uint8_t _I_DoorLocked_10x56_0[] = {0x01,0x00,0x4e,0x00,0x86,0x40,0x25,0xb0,0x0b,0x6c,0x03,0x9b,0x00,0xc6,0xc0,0x65,0x90,0x10,0x3a,0xc3,0x20,0x31,0xc8,0x04,0xe2,0x01,0x70,0x80,0x78,0x20,0x1c,0x48,0x07,0x22,0x01,0xd0,0x00,0xf0,0x44,0x68,0x90,0x09,0x04,0x02,0x21,0x00,0x84,0x40,0x25,0x80,0x12,0x1e,0x88,0x14,0xc0,0x2e,0x0d,0x11,0xca,0xf8,0x60,0x1c,0x38,0x07,0x1a,0x05,0xcc,0x80,0x72,0x60,0x5c,0x38,0x10,0x1c,0xf9,0x10,0x2e,0x00,0x05,0x60,0x00,0x11,}; +const uint8_t *_I_DoorLocked_10x56[] = {_I_DoorLocked_10x56_0}; + +const uint8_t _I_PassportLeft_6x47_0[] = {0x01,0x00,0x1c,0x00,0x9e,0x40,0xa3,0x32,0x59,0x2c,0x66,0x03,0x01,0x82,0xc2,0x62,0x32,0x50,0x16,0xc8,0x60,0x30,0x28,0x24,0x32,0x39,0x3c,0x9e,0x4d,0x25,0x80,0x1a,}; +const uint8_t *_I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; + const uint8_t _I_LockPopup_100x49_0[] = {0x01,0x00,0x37,0x01,0xfc,0x7f,0xc0,0x13,0x01,0xfe,0x03,0x2a,0x07,0x06,0x12,0xd4,0x1a,0x06,0x0c,0xa8,0x60,0x33,0xe0,0x12,0x08,0x40,0x32,0x3f,0xd0,0x70,0x64,0xe0,0x20,0x31,0x8a,0x00,0x32,0x2c,0x10,0x0b,0x00,0x32,0x62,0x10,0x0c,0x06,0x00,0x19,0x00,0x82,0xc0,0x83,0x22,0x08,0x04,0x18,0x11,0x6a,0x01,0x25,0x02,0x84,0x83,0x1e,0x02,0x04,0x10,0xe1,0x03,0x1e,0x3c,0x0c,0x9c,0x1c,0x02,0x43,0x00,0x84,0x4f,0xc1,0x8f,0x80,0xaf,0x40,0x39,0x14,0x00,0x63,0xd0,0x36,0xf0,0x09,0xc6,0x00,0x18,0xd4,0x3a,0x06,0x9c,0x08,0x20,0xc9,0xdf,0xc0,0x20,0x7f,0x00,0x65,0x40,0x3f,0x80,0xc7,0xd0,0x10,0x06,0x01,0x7f,0x06,0x34,0x8e,0xa1,0x3d,0x80,0x70,0x0b,0x4f,0x23,0xd0,0x50,0xa0,0x1f,0x08,0x78,0x66,0x11,0xe3,0xfc,0x83,0x83,0x1e,0x40,0x0c,0x1f,0xfb,0xec,0x41,0x8c,0x03,0x1e,0x07,0x00,0x4d,0x10,0x0a,0x04,0xc0,0x9b,0x30,0x0c,0x1f,0xff,0xff,0x9f,0x06,0x3e,0x01,0x80,0x48,0xe7,0x99,0x83,0x0d,0x6a,0xe0,0xc4,0x90,0x03,0x1a,0x76,0x0c,0x38,0xe0,0x34,0x45,0x25,0x02,0x06,0x0d,0xe0,0x18,0x3c,0x08,0x19,0x40,0x78,0x00,0xc1,0x81,0xc3,0x27,0xf8,0x48,0x26,0x82,0x7d,0x00,0xfc,0x40,0xfc,0x10,0xfc,0x04,0xfc,0x18,0x30,0x28,0x7d,0x02,0x3f,0x00,0x98,0x41,0x38,0x31,0x08,0x25,0x0e,0x19,0x1f,0x81,0x42,0x70,0x11,0xa2,0x08,0xe2,0x30,0x72,0x08,0x76,0x0a,0x19,0x0f,0x85,0x42,0x60,0x11,0x51,0x78,0xc2,0x20,0x32,0x08,0x26,0x00,0x18,0x91,0x00,0x60,0x91,0x44,0x08,0x34,0x08,0x64,0x1f,0xe4,0x07,0x3f,0x84,0x0d,0x58,0x44,0x01,0x83,0xdc,0x60,0x43,0xe1,0x39,0xa9,0xd0,0x60,0x70,0x16,0x78,0xca,0x01,0x8f,0x83,0x3d,0x10,0x33,0x29,0x00,0xc7,0xa1,0x83,0x3f,0x10,0x0c,0x79,0x30,0x32,0xa0,0xdf,0xc7,0xa0,0x80,0x22,0x07,0xf8,0x06,0x54,0x04,}; const uint8_t *_I_LockPopup_100x49[] = {_I_LockPopup_100x49_0}; -const uint8_t _I_Mute_25x27_0[] = {0x01,0x00,0x51,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x31,0x81,0xc0,0x64,0x38,0x08,0xa4,0x06,0x83,0x40,0x86,0x40,0x70,0x32,0x08,0x20,0x3c,0x63,0xf0,0x60,0x38,0xc0,0xa0,0xa0,0x31,0xc2,0x02,0xc7,0x03,0x48,0x01,0x94,0xc0,0x06,0xc0,0xb3,0x09,0x98,0x6c,0x84,0x68,0x2b,0x21,0x99,0x8e,0xcc,0x86,0x64,0xb3,0x81,0x94,0xc6,0x03,0x06,0x80,0x70,0x20,0x1f,0xcf,0xfd,0xfc,0xce,0x80,}; -const uint8_t *_I_Mute_25x27[] = {_I_Mute_25x27_0}; - -const uint8_t _I_IrdaArrowUp_4x8_0[] = {0x00,0x18,0x3C,0x7E,0xFF,}; -const uint8_t *_I_IrdaArrowUp_4x8[] = {_I_IrdaArrowUp_4x8_0}; - -const uint8_t _I_Up_hvr_25x27_0[] = {0x01,0x00,0x39,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3c,0xf7,0x80,0xcb,0x8e,0x03,0x2c,0x18,0x0c,0x80,0x26,0x25,0x18,0x08,0xa4,0x7f,0x90,0x11,0x88,0xfe,0x20,0x31,0xf8,0x07,0xc2,0x03,0x0f,0x80,0x78,0x00,0x68,0x37,0xf0,0x1d,0x95,0xcc,0xbe,0x66,0x73,}; -const uint8_t *_I_Up_hvr_25x27[] = {_I_Up_hvr_25x27_0}; - -const uint8_t _I_Mute_hvr_25x27_0[] = {0x01,0x00,0x4a,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x21,0xfe,0x40,0x7b,0xf7,0xff,0x5c,0x07,0x7f,0xbf,0xf9,0xc0,0x6f,0xfd,0xff,0xd8,0x3c,0x7c,0x1f,0x90,0x38,0xff,0x7f,0x40,0x31,0xbd,0x82,0xc6,0xff,0xb7,0x01,0x97,0x3c,0x06,0xc0,0xb3,0x09,0x98,0x6c,0x84,0x68,0x2b,0x21,0x99,0x8e,0xcc,0x86,0x64,0xb5,0x01,0x89,0x5c,0xcb,0xe6,0x67,0x30,}; -const uint8_t *_I_Mute_hvr_25x27[] = {_I_Mute_hvr_25x27_0}; - -const uint8_t _I_Vol_down_25x27_0[] = {0x01,0x00,0x2c,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3f,0x01,0xff,0x07,0xff,0x07,0x01,0xa0,0x5f,0xc0,0x7e,0x03,0x38,0x19,0x4c,0x60,0x30,0x68,0x07,0x02,0x01,0xfc,0xff,0xdf,0xcc,0xe8,}; -const uint8_t *_I_Vol_down_25x27[] = {_I_Vol_down_25x27_0}; - -const uint8_t _I_Down_25x27_0[] = {0x01,0x00,0x46,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3f,0x01,0x9f,0xc7,0xff,0x1f,0x01,0xa7,0x87,0xff,0x0f,0x80,0xf0,0x7f,0xf0,0x78,0x0e,0x07,0xff,0x03,0x0b,0x8f,0xfc,0x04,0x30,0x1f,0xf0,0x7c,0xaf,0x80,0x32,0x9c,0x00,0xca,0x20,0x37,0xf0,0x18,0xc0,0xca,0x63,0x01,0x83,0x40,0x38,0x10,0x0f,0xe7,0xfe,0xfe,0x67,0x40,}; -const uint8_t *_I_Down_25x27[] = {_I_Down_25x27_0}; - -const uint8_t _I_Power_hvr_25x27_0[] = {0x01,0x00,0x4b,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x3f,0xff,0x78,0x0c,0xb8,0xe0,0x35,0xbf,0xf1,0xbf,0x90,0x19,0xff,0x1b,0xf1,0x01,0x8f,0xf1,0xfe,0x30,0x1c,0xff,0x1f,0xe6,0x03,0x5f,0x78,0x0c,0xbf,0xe0,0x39,0x8f,0xff,0xc3,0x63,0x3f,0xff,0x08,0xc6,0xff,0x7c,0x15,0x89,0x04,0x7f,0xc0,0x31,0xc1,0x8e,0xc8,0x8e,0x60,0x36,0x2b,0x99,0x7c,0xcc,0xe6,}; -const uint8_t *_I_Power_hvr_25x27[] = {_I_Power_hvr_25x27_0}; - -const uint8_t _I_IrdaLearnShort_128x31_0[] = {0x01,0x00,0x10,0x01,0x00,0x47,0xfb,0xfe,0x00,0x38,0x38,0x3e,0x20,0x20,0x54,0x84,0x03,0x9f,0xc0,0x06,0x58,0x80,0x3d,0xf2,0x00,0x65,0x90,0x03,0xde,0x90,0x06,0x5a,0x07,0xc0,0x8a,0x70,0x1a,0x04,0x02,0x51,0x80,0x03,0x94,0x02,0x3f,0x40,0x20,0x24,0x0b,0x01,0x00,0x92,0x70,0x35,0x40,0x01,0xe0,0xdf,0xf0,0x10,0x40,0x71,0x58,0x20,0x90,0x88,0x0c,0x4a,0x81,0x55,0x00,0x0f,0x87,0xf7,0x00,0x82,0x43,0x36,0x16,0xdc,0x9c,0x12,0x21,0x01,0x85,0x70,0x3f,0xc1,0xf1,0xf8,0xfc,0x60,0x20,0xf5,0x90,0x40,0xa1,0x34,0x08,0x18,0x7c,0x7e,0x24,0x91,0x07,0x8c,0xc0,0x5e,0x52,0x28,0x14,0x17,0x81,0x01,0x0f,0x8f,0xe7,0xe3,0x03,0x1f,0x8e,0x02,0xdb,0x03,0x8e,0x49,0x20,0x50,0x2e,0x04,0x72,0xbd,0x55,0xdc,0xeb,0xa0,0x7c,0x4f,0x68,0xbc,0x60,0x72,0x40,0x79,0x50,0x23,0x9a,0x6d,0x56,0x66,0x5c,0x0f,0x21,0x78,0x9b,0x04,0x1e,0x28,0x21,0x8e,0x5c,0x43,0xe6,0x2f,0x10,0xf9,0x0b,0xc7,0x04,0x99,0x18,0x06,0xe0,0x7e,0x56,0x32,0x78,0x8f,0xc4,0x08,0x32,0x20,0x79,0x48,0x2b,0x85,0xf2,0xf8,0x83,0xc4,0x5c,0x3f,0x03,0x78,0xd0,0x81,0xe3,0xc0,0xdf,0x9f,0xcb,0xf3,0x04,0xc6,0x7d,0xfb,0xdf,0x34,0x78,0xd0,0x45,0xe5,0x7e,0x4f,0x97,0xe2,0x09,0x80,0x07,0x88,0xbc,0x61,0x00,0xf3,0xd8,0x2f,0xcb,0xe0,0xcf,0x60,0x68,0xd0,0x30,0x15,0xfa,0xac,0x36,0x3f,0x60,0x77,0xb3,0x80,0x5d,0xe6,0x4b,0x20,0x03,0x03,0xc4,0x01,0xd0,0x10,0x7f,0x40,0x81,0xfc,0xa7,0x10,0x06,0x99,0xd0,0x01,0x51,0x00,0x7f,0x48,0x01,0xfd,0xc0,0x43,0x98,0x00,0x8e,0xfe,0x00,0xf0,}; -const uint8_t *_I_IrdaLearnShort_128x31[] = {_I_IrdaLearnShort_128x31_0}; - -const uint8_t _I_IrdaArrowDown_4x8_0[] = {0x00,0xFF,0x7E,0x3C,0x18,}; -const uint8_t *_I_IrdaArrowDown_4x8[] = {_I_IrdaArrowDown_4x8_0}; - -const uint8_t _I_Vol_down_hvr_25x27_0[] = {0x01,0x00,0x23,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3f,0x01,0xf8,0xb4,0x7f,0x00,0x34,0x0b,0xf8,0x0f,0xc0,0x6e,0x57,0x32,0xf9,0x99,0xcc,}; -const uint8_t *_I_Vol_down_hvr_25x27[] = {_I_Vol_down_hvr_25x27_0}; - -const uint8_t _I_IrdaLearn_128x64_0[] = {0x01,0x00,0xcc,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3f,0x01,0x07,0x82,0x41,0x21,0x20,0x73,0x00,0x8e,0x82,0x0f,0x00,0xa0,0x01,0x46,0x11,0x00,0x07,0xc0,0x28,0x41,0xe5,0xc8,0xba,0x63,0xa7,0x70,0x6b,0x3d,0xbb,0x99,0x19,0xee,0x68,0x71,0x16,0x3f,0x70,0x3c,0x64,0xf9,0x58,0x25,0x26,0x13,0x91,0xc9,0x64,0xa4,0x99,0x2d,0x06,0x1f,0x29,0x42,0x07,0x8c,0x80,0x1e,0x50,0xff,0x88,0x3c,0x67,0x80,0xf1,0xc1,0x03,0xde,0x03,0x11,0x07,0x8c,0x10,0x1e,0x38,0x40,0x79,0xf0,0x32,0x80,0xf1,0x83,0x58,0x72,0x58,0xc8,0xc6,0x73,0x40,0x3f,0x10,0x78,0x9e,0xf1,0x17,0xe9,0xcf,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x02,0x44,0x18,0xa3,0x80,0x82,0x32,0x06,0x44,0x0f,0xf0,0x73,0x5d,0xe3,0x92,0x7e,0xcf,0x06,0x3b,0xc3,0xa4,0xdd,0xfc,0xc8,0x35,0xca,0x44,0xa5,0x34,0x5c,0x16,0x92,0x89,0x4a,0x91,0x4a,0x60,0x20,0xf7,0xa4,0x83,0xc6,0x8e,0x0f,0xba,0x88,0x3c,0x68,0x00,0xf7,0x80,0x65,0xe3,0x9c,0x7a,0x6e,0x0a,0x49,0xc3,0xb8,0xc8,0xa4,0xc0,0xf5,0x00,0x08,0x1d,0xc0,0x0e,0x0f,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xfb,0xfe,0x00,0x38,0x39,0x97,0xa1,0x00,0xe7,0xf0,0x3b,0x1c,0x00,0xd9,0x00,0x32,0xc8,0x01,0xef,0x48,0x03,0x2d,0x03,0xe0,0x45,0x38,0x0d,0x02,0x01,0x28,0xc0,0x01,0xca,0x01,0x1f,0xa0,0x10,0x12,0x05,0x80,0x80,0x49,0x38,0x1a,0xa0,0x00,0xf0,0x6f,0xf8,0x08,0x20,0x38,0xac,0x10,0x48,0x44,0x06,0x25,0x40,0xaa,0x80,0x07,0xc3,0xfb,0x80,0x41,0x21,0x9b,0x0b,0x6e,0x4e,0x09,0x10,0x80,0xc2,0xb8,0x1f,0xe0,0xf8,0xfc,0x7e,0x30,0x10,0x7a,0xc8,0x20,0x50,0x9a,0x04,0x0c,0x3e,0x3f,0x12,0x48,0x83,0xc6,0x60,0x2f,0x29,0x14,0x0a,0x0b,0xc0,0x80,0x87,0xc7,0xf3,0xf1,0x81,0x8f,0xc7,0x01,0x6d,0x81,0xc7,0x24,0x90,0x28,0x17,0x02,0x39,0x5e,0xaa,0xee,0x75,0xd0,0x3e,0x27,0xb4,0x5e,0x30,0x39,0x20,0x3c,0xa8,0x11,0xcd,0x36,0xab,0x33,0x2e,0x07,0x90,0xbc,0x4d,0x82,0x0f,0x14,0x10,0xc7,0x2e,0x21,0xf3,0x17,0x88,0x7c,0x85,0xe3,0x82,0x4c,0x8c,0x03,0x70,0x3f,0x2b,0x19,0x3c,0x47,0xe2,0x04,0x19,0x10,0x3c,0xa4,0x15,0xc2,0xf9,0x7c,0x41,0xe2,0x2e,0x1f,0x81,0xbc,0x68,0x40,0xf1,0xe0,0x6f,0xcf,0xe5,0xf9,0x82,0x63,0x3e,0xfd,0xef,0x9a,0x3c,0x68,0x22,0xf2,0xbf,0x27,0xcb,0xf1,0x04,0xc0,0x03,0xc4,0x5e,0x30,0x80,0x79,0xec,0x17,0xe5,0xf0,0x67,0xb0,0x34,0x68,0x18,0x0a,0xfd,0x56,0x1b,0x1f,0xb0,0x3b,0xd9,0xc0,0x2e,0xf3,0x25,0x90,0x01,0x81,0xe2,0x00,0xe8,0x08,0x3f,0xa0,0x40,0xfe,0x53,0x88,0x03,0x4c,0xe8,0x00,0xa8,0x80,0x3f,0xa4,0x00,0xfe,0xe0,0x21,0xcc,0x00,0x47,0x7f,0x00,0x78,}; -const uint8_t *_I_IrdaLearn_128x64[] = {_I_IrdaLearn_128x64_0}; - const uint8_t _I_Down_hvr_25x27_0[] = {0x01,0x00,0x3a,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3f,0x01,0x9c,0x3e,0x01,0xe0,0x01,0xa4,0x7e,0x01,0xf0,0x80,0x8b,0x47,0xf1,0x01,0x16,0x8f,0xf0,0x2e,0x23,0x11,0x01,0x88,0x04,0xf0,0x60,0x32,0xe3,0x80,0xcb,0xde,0x37,0xf0,0x1a,0x95,0xcc,0xbe,0x66,0x73,}; const uint8_t *_I_Down_hvr_25x27[] = {_I_Down_hvr_25x27_0}; +const uint8_t _I_Vol_down_hvr_25x27_0[] = {0x01,0x00,0x23,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3f,0x01,0xf8,0xb4,0x7f,0x00,0x34,0x0b,0xf8,0x0f,0xc0,0x6e,0x57,0x32,0xf9,0x99,0xcc,}; +const uint8_t *_I_Vol_down_hvr_25x27[] = {_I_Vol_down_hvr_25x27_0}; + +const uint8_t _I_Down_25x27_0[] = {0x01,0x00,0x46,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3f,0x01,0x9f,0xc7,0xff,0x1f,0x01,0xa7,0x87,0xff,0x0f,0x80,0xf0,0x7f,0xf0,0x78,0x0e,0x07,0xff,0x03,0x0b,0x8f,0xfc,0x04,0x30,0x1f,0xf0,0x7c,0xaf,0x80,0x32,0x9c,0x00,0xca,0x20,0x37,0xf0,0x18,0xc0,0xca,0x63,0x01,0x83,0x40,0x38,0x10,0x0f,0xe7,0xfe,0xfe,0x67,0x40,}; +const uint8_t *_I_Down_25x27[] = {_I_Down_25x27_0}; + const uint8_t _I_Fill_marker_7x7_0[] = {0x00,0x1C,0x32,0x6F,0x5F,0x7F,0x3E,0x1C,}; const uint8_t *_I_Fill_marker_7x7[] = {_I_Fill_marker_7x7_0}; -const uint8_t _I_Power_25x27_0[] = {0x01,0x00,0x54,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x30,0x18,0x80,0x0c,0xa7,0x00,0x35,0xc0,0xce,0x60,0x70,0x1e,0x0c,0xe6,0x0f,0x01,0xf0,0xce,0x21,0xd0,0x1b,0x0c,0xe2,0x18,0x03,0x58,0x80,0x0c,0xa0,0x00,0x39,0xf0,0xc0,0x03,0x63,0xc1,0x80,0x88,0xc7,0x03,0x83,0x15,0x8c,0x07,0xfe,0x02,0x18,0x0d,0xf0,0x76,0x44,0x73,0x01,0x94,0x0c,0xa6,0x30,0x18,0x34,0x03,0x81,0x00,0xfe,0x7f,0xef,0xe6,0x74,}; -const uint8_t *_I_Power_25x27[] = {_I_Power_25x27_0}; +const uint8_t _I_Vol_down_25x27_0[] = {0x01,0x00,0x2c,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3f,0x01,0xff,0x07,0xff,0x07,0x01,0xa0,0x5f,0xc0,0x7e,0x03,0x38,0x19,0x4c,0x60,0x30,0x68,0x07,0x02,0x01,0xfc,0xff,0xdf,0xcc,0xe8,}; +const uint8_t *_I_Vol_down_25x27[] = {_I_Vol_down_25x27_0}; const uint8_t _I_Vol_up_25x27_0[] = {0x01,0x00,0x2f,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x38,0x88,0x00,0xfc,0x06,0xbc,0x1f,0xfc,0x1c,0x06,0x81,0x7f,0x01,0xc1,0x0e,0xa0,0x65,0x31,0x80,0xc1,0xa0,0x1c,0x08,0x07,0xf3,0xff,0x7f,0x33,0xa0,}; const uint8_t *_I_Vol_up_25x27[] = {_I_Vol_up_25x27_0}; -const uint8_t _I_Up_25x27_0[] = {0x01,0x00,0x44,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3c,0x88,0x00,0xca,0x70,0x03,0x2b,0xe0,0x0c,0xbf,0xc0,0x32,0xff,0x80,0x87,0x03,0xff,0x81,0xc0,0x78,0x3f,0xf8,0x3c,0x07,0xc3,0xff,0x87,0xc0,0x7e,0x3f,0xf8,0xf8,0x0d,0x06,0xfe,0x03,0x78,0x19,0x4c,0x60,0x30,0x68,0x07,0x02,0x01,0xfc,0xff,0xdf,0xcc,0xe8,}; -const uint8_t *_I_Up_25x27[] = {_I_Up_25x27_0}; - -const uint8_t _I_Back_15x10_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x0F,0x06,0x10,0x04,0x20,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x10,0xFE,0x0F,}; -const uint8_t *_I_Back_15x10[] = {_I_Back_15x10_0}; - -const uint8_t _I_IrdaSend_128x64_0[] = {0x01,0x00,0xe2,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xfe,0x04,0x0e,0x05,0x82,0xd7,0x81,0xca,0x21,0x08,0x01,0x8c,0x10,0x0e,0x54,0x00,0x20,0xe0,0xa4,0x00,0xfb,0xb2,0x4e,0xb0,0xfa,0x0e,0x74,0xc7,0x0f,0x3b,0xce,0x4e,0xec,0xf0,0xe1,0x79,0xe4,0xe9,0x58,0x2d,0x3d,0x4a,0x95,0x41,0x89,0x52,0x31,0x59,0x40,0xfa,0x64,0x01,0xe3,0xa0,0xa9,0x5e,0x81,0xe7,0xf4,0x07,0xcc,0x28,0x1e,0x71,0x40,0x7a,0x58,0x01,0xe4,0x3f,0x1c,0x0c,0x4f,0x11,0x0b,0xb3,0x83,0xcc,0x00,0x94,0x20,0x2a,0x03,0xa0,0x1e,0xd0,0x34,0xdf,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x4c,0xf0,0x17,0x4c,0x81,0xa0,0x18,0x18,0x1f,0x39,0x90,0x6c,0x60,0x27,0x70,0xe9,0x3f,0x67,0x03,0x3c,0x80,0x83,0xde,0x81,0x4a,0x84,0xca,0x68,0xb8,0x2b,0xf0,0x3f,0x29,0x20,0xfe,0xa8,0xe0,0x85,0xf3,0x80,0xa5,0xc3,0xb8,0xf4,0xd8,0x11,0x3e,0x40,0x04,0x1b,0x23,0x7d,0x83,0xcd,0x1f,0x60,0x0f,0x00,0x78,0x03,0x7f,0x9f,0xf0,0x01,0xc0,0xc1,0xf1,0x04,0x02,0xa4,0x08,0x1f,0xe0,0xff,0x01,0x0f,0x00,0x70,0x9f,0xfe,0x20,0x10,0xe7,0xe0,0xf2,0x90,0x07,0xd7,0x89,0xdf,0xaa,0xd5,0x7b,0xa0,0xf3,0x8e,0x03,0xdb,0x54,0x00,0x29,0x70,0x3c,0xa2,0x40,0xf6,0xbf,0x87,0xc7,0xea,0x1f,0x12,0x30,0xc2,0x41,0xed,0xab,0x95,0x07,0xc6,0x75,0x02,0x10,0x0c,0x17,0xe0,0x47,0x18,0xff,0x82,0x07,0xc4,0xaf,0x8f,0xd2,0x43,0x80,0x82,0x56,0x01,0x03,0x35,0xfc,0x43,0xc7,0xe3,0x8a,0xc4,0x6a,0xa5,0x50,0x28,0x8d,0x02,0x05,0xa8,0x13,0x8c,0xaa,0xf9,0x1f,0xe2,0x5d,0xc2,0xc3,0x75,0x9f,0xe0,0xa1,0x14,0x08,0x0f,0x60,0x52,0x33,0x59,0xf4,0xf8,0x7e,0x32,0x2d,0x10,0xfc,0x70,0x58,0x89,0x04,0x06,0xd1,0xa0,0x0f,0x8f,0xfa,0x7e,0x3f,0x3e,0xa8,0x7c,0x69,0x1a,0x08,0x04,0xe2,0x80,0x1f,0x19,0xfd,0xf8,0xfe,0x92,0xa0,0x78,0xd0,0x20,0x19,0x8e,0x19,0xa8,0x7a,0xf7,0x51,0xfb,0x03,0xcb,0x11,0xc3,0xaa,0x4d,0x7a,0x76,0x51,0xf8,0x87,0xc8,0x7e,0x34,0x85,0xf0,0xe2,0x24,0x7a,0xe0,0xf9,0xaf,0xd0,0x9e,0x31,0x08,0x04,0x22,0x01,0x57,0x1f,0x9e,0xb8,0x7e,0x90,0x80,0x79,0x61,0x07,0xe2,0x5f,0x2f,0xfd,0xde,0xeb,0xf7,0x4f,0x8c,0x44,0x3a,0x30,0x8f,0xc0,0x7c,0x4f,0xe6,0x1f,0x29,0xda,0xbc,0x41,0xe5,0xc0,0xd7,0xa7,0xcd,0x8a,0x3d,0xdf,0xe8,0x7c,0x60,0x40,0xf2,0x80,0x55,0x97,0xe7,0xee,0x0f,0x0f,0xa9,0xfe,0x30,0x40,0x79,0x7c,0x05,0x43,0xe1,0x6f,0x88,0x7c,0x40,0x02,0x1f,0x18,0x01,0x3c,0x5d,0xe5,0x9f,0x80,0xbf,0xc4,0x1f,0x00,0x05,0x82,0x01,0x50,0x1e,0x28,0xf1,0x00,0x2c,0x90,0x1e,0xca,0xf1,0x00,0x2d,0x52,0x1e,0x0f,0x5c,0x00,0x7d,0xc1,0xed,0x00,0x25,0x08,0xff,0x00,0x46,0x00,0x3f,0xe1,0x7c,0xff,0xf0,0x30,0xc3,0xc0,0x3c,0x02,0x73,0xbc,0x00,0xcb,0xf0,0x18,0x4f,0xf8,0x3e,0x00,0x0c,0x0f,0xf0,}; -const uint8_t *_I_IrdaSend_128x64[] = {_I_IrdaSend_128x64_0}; - -const uint8_t _I_IrdaSendShort_128x34_0[] = {0x01,0x00,0x42,0x01,0xfe,0x7f,0xc0,0x07,0x03,0x07,0xc4,0x10,0x0a,0x90,0x20,0x7f,0x83,0xfc,0x04,0x3c,0x01,0xc2,0x7f,0xf8,0x80,0x43,0x9f,0x83,0xca,0x40,0x1f,0x5e,0x27,0x7e,0xab,0x55,0xee,0x83,0xce,0x38,0x0f,0x6d,0x50,0x00,0xa5,0xc0,0xf2,0x89,0x03,0xda,0xfe,0x1f,0x1f,0xa8,0x7c,0x48,0xc3,0x09,0x07,0xb6,0xae,0x54,0x1f,0x19,0xd4,0x08,0x40,0x30,0x5f,0x81,0x1c,0x63,0xfe,0x08,0x1f,0x12,0xbe,0x3f,0x49,0x0e,0x02,0x09,0x58,0x04,0x0c,0xd7,0xf1,0x0f,0x1f,0x8e,0x2b,0x11,0xaa,0x95,0x40,0xa2,0x34,0x08,0x16,0xa0,0x4e,0x32,0xab,0xe4,0x7f,0x89,0x77,0x0b,0x0d,0xd6,0x7f,0x82,0x84,0x50,0x20,0x3d,0x81,0x48,0xcd,0x67,0xd3,0xe1,0xf8,0xc8,0xb4,0x43,0xf1,0xc1,0x62,0x24,0x10,0x1b,0x46,0x80,0x3e,0x3f,0xe9,0xf8,0xfc,0xfa,0xa1,0xf1,0xa4,0x68,0x20,0x13,0x8a,0x00,0x7c,0x67,0xf7,0xe3,0xfa,0x4a,0x81,0xe3,0x40,0x80,0x66,0x38,0x66,0xa1,0xeb,0xdd,0x47,0xec,0x0f,0x2c,0x47,0x0e,0xa9,0x35,0xe9,0xd9,0x47,0xe2,0x1f,0x21,0xf8,0xd2,0x17,0xc3,0x88,0x91,0xeb,0x83,0xe6,0xbf,0x42,0x78,0xc4,0x20,0x10,0x88,0x05,0x5c,0x7e,0x7a,0xe1,0xfa,0x42,0x01,0xe5,0x84,0x1f,0x89,0x7c,0xbf,0xf7,0x7b,0xaf,0xdd,0x3e,0x31,0x10,0xe8,0xc2,0x3f,0x01,0xf1,0x3f,0x98,0x7c,0xa7,0x6a,0xf1,0x07,0x97,0x03,0x5e,0x9f,0x36,0x28,0xf7,0x7f,0xa1,0xf1,0x81,0x03,0xca,0x01,0x56,0x5f,0x9f,0xb8,0x3c,0x3e,0xa7,0xf8,0xc1,0x01,0xe5,0xf0,0x15,0x0f,0x85,0xbe,0x21,0xf1,0x00,0x08,0x7c,0x60,0x04,0xf1,0x77,0x96,0x7e,0x02,0xff,0x10,0x7c,0x00,0x16,0x08,0x05,0x40,0x78,0xa3,0xc4,0x00,0xb2,0x40,0x7b,0x2b,0xc4,0x00,0xb5,0x48,0x78,0x3d,0x70,0x01,0xf7,0x07,0xb4,0x00,0x94,0x23,0xfc,0x01,0x18,0x00,0xff,0x85,0xf3,0xff,0xc0,0xc3,0x0f,0x00,0xf0,0x09,0xce,0xf0,0x03,0x2f,0xc0,0x61,0x3f,0xe0,0xf8,0x00,0x30,0x3f,0xc0,}; -const uint8_t *_I_IrdaSendShort_128x34[] = {_I_IrdaSendShort_128x34_0}; +const uint8_t _I_Up_hvr_25x27_0[] = {0x01,0x00,0x39,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3c,0xf7,0x80,0xcb,0x8e,0x03,0x2c,0x18,0x0c,0x80,0x26,0x25,0x18,0x08,0xa4,0x7f,0x90,0x11,0x88,0xfe,0x20,0x31,0xf8,0x07,0xc2,0x03,0x0f,0x80,0x78,0x00,0x68,0x37,0xf0,0x1d,0x95,0xcc,0xbe,0x66,0x73,}; +const uint8_t *_I_Up_hvr_25x27[] = {_I_Up_hvr_25x27_0}; const uint8_t _I_Vol_up_hvr_25x27_0[] = {0x01,0x00,0x28,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x38,0xf7,0x80,0xfc,0x06,0xa2,0xd1,0xfc,0x00,0xd0,0x2f,0xe0,0x38,0x21,0xd8,0x0c,0x8a,0xe6,0x5f,0x33,0x39,0x80,}; const uint8_t *_I_Vol_up_hvr_25x27[] = {_I_Vol_up_hvr_25x27_0}; -const uint8_t _I_KeySave_24x11_0[] = {0x01,0x00,0x1e,0x00,0xff,0x7f,0xff,0xf0,0x18,0x06,0x00,0x04,0x53,0x1c,0xbe,0x33,0x13,0x94,0xc9,0x64,0x72,0x99,0xed,0x0e,0x53,0x05,0x19,0xb3,0xe3,0x02,0x8a,0x1d,0x1b,0xf8,}; -const uint8_t *_I_KeySave_24x11[] = {_I_KeySave_24x11_0}; +const uint8_t _I_IrdaLearnShort_128x31_0[] = {0x01,0x00,0x10,0x01,0x00,0x47,0xfb,0xfe,0x00,0x38,0x38,0x3e,0x20,0x20,0x54,0x84,0x03,0x9f,0xc0,0x06,0x58,0x80,0x3d,0xf2,0x00,0x65,0x90,0x03,0xde,0x90,0x06,0x5a,0x07,0xc0,0x8a,0x70,0x1a,0x04,0x02,0x51,0x80,0x03,0x94,0x02,0x3f,0x40,0x20,0x24,0x0b,0x01,0x00,0x92,0x70,0x35,0x40,0x01,0xe0,0xdf,0xf0,0x10,0x40,0x71,0x58,0x20,0x90,0x88,0x0c,0x4a,0x81,0x55,0x00,0x0f,0x87,0xf7,0x00,0x82,0x43,0x36,0x16,0xdc,0x9c,0x12,0x21,0x01,0x85,0x70,0x3f,0xc1,0xf1,0xf8,0xfc,0x60,0x20,0xf5,0x90,0x40,0xa1,0x34,0x08,0x18,0x7c,0x7e,0x24,0x91,0x07,0x8c,0xc0,0x5e,0x52,0x28,0x14,0x17,0x81,0x01,0x0f,0x8f,0xe7,0xe3,0x03,0x1f,0x8e,0x02,0xdb,0x03,0x8e,0x49,0x20,0x50,0x2e,0x04,0x72,0xbd,0x55,0xdc,0xeb,0xa0,0x7c,0x4f,0x68,0xbc,0x60,0x72,0x40,0x79,0x50,0x23,0x9a,0x6d,0x56,0x66,0x5c,0x0f,0x21,0x78,0x9b,0x04,0x1e,0x28,0x21,0x8e,0x5c,0x43,0xe6,0x2f,0x10,0xf9,0x0b,0xc7,0x04,0x99,0x18,0x06,0xe0,0x7e,0x56,0x32,0x78,0x8f,0xc4,0x08,0x32,0x20,0x79,0x48,0x2b,0x85,0xf2,0xf8,0x83,0xc4,0x5c,0x3f,0x03,0x78,0xd0,0x81,0xe3,0xc0,0xdf,0x9f,0xcb,0xf3,0x04,0xc6,0x7d,0xfb,0xdf,0x34,0x78,0xd0,0x45,0xe5,0x7e,0x4f,0x97,0xe2,0x09,0x80,0x07,0x88,0xbc,0x61,0x00,0xf3,0xd8,0x2f,0xcb,0xe0,0xcf,0x60,0x68,0xd0,0x30,0x15,0xfa,0xac,0x36,0x3f,0x60,0x77,0xb3,0x80,0x5d,0xe6,0x4b,0x20,0x03,0x03,0xc4,0x01,0xd0,0x10,0x7f,0x40,0x81,0xfc,0xa7,0x10,0x06,0x99,0xd0,0x01,0x51,0x00,0x7f,0x48,0x01,0xfd,0xc0,0x43,0x98,0x00,0x8e,0xfe,0x00,0xf0,}; +const uint8_t *_I_IrdaLearnShort_128x31[] = {_I_IrdaLearnShort_128x31_0}; -const uint8_t _I_KeyBackspaceSelected_16x9_0[] = {0x00,0xFE,0x7F,0xFF,0xFF,0xEF,0xFF,0xE7,0xFF,0x03,0xC0,0xE7,0xFF,0xEF,0xFF,0xFF,0xFF,0xFE,0x7F,}; -const uint8_t *_I_KeyBackspaceSelected_16x9[] = {_I_KeyBackspaceSelected_16x9_0}; +const uint8_t _I_IrdaSend_128x64_0[] = {0x01,0x00,0xe2,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xfe,0x04,0x0e,0x05,0x82,0xd7,0x81,0xca,0x21,0x08,0x01,0x8c,0x10,0x0e,0x54,0x00,0x20,0xe0,0xa4,0x00,0xfb,0xb2,0x4e,0xb0,0xfa,0x0e,0x74,0xc7,0x0f,0x3b,0xce,0x4e,0xec,0xf0,0xe1,0x79,0xe4,0xe9,0x58,0x2d,0x3d,0x4a,0x95,0x41,0x89,0x52,0x31,0x59,0x40,0xfa,0x64,0x01,0xe3,0xa0,0xa9,0x5e,0x81,0xe7,0xf4,0x07,0xcc,0x28,0x1e,0x71,0x40,0x7a,0x58,0x01,0xe4,0x3f,0x1c,0x0c,0x4f,0x11,0x0b,0xb3,0x83,0xcc,0x00,0x94,0x20,0x2a,0x03,0xa0,0x1e,0xd0,0x34,0xdf,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x4c,0xf0,0x17,0x4c,0x81,0xa0,0x18,0x18,0x1f,0x39,0x90,0x6c,0x60,0x27,0x70,0xe9,0x3f,0x67,0x03,0x3c,0x80,0x83,0xde,0x81,0x4a,0x84,0xca,0x68,0xb8,0x2b,0xf0,0x3f,0x29,0x20,0xfe,0xa8,0xe0,0x85,0xf3,0x80,0xa5,0xc3,0xb8,0xf4,0xd8,0x11,0x3e,0x40,0x04,0x1b,0x23,0x7d,0x83,0xcd,0x1f,0x60,0x0f,0x00,0x78,0x03,0x7f,0x9f,0xf0,0x01,0xc0,0xc1,0xf1,0x04,0x02,0xa4,0x08,0x1f,0xe0,0xff,0x01,0x0f,0x00,0x70,0x9f,0xfe,0x20,0x10,0xe7,0xe0,0xf2,0x90,0x07,0xd7,0x89,0xdf,0xaa,0xd5,0x7b,0xa0,0xf3,0x8e,0x03,0xdb,0x54,0x00,0x29,0x70,0x3c,0xa2,0x40,0xf6,0xbf,0x87,0xc7,0xea,0x1f,0x12,0x30,0xc2,0x41,0xed,0xab,0x95,0x07,0xc6,0x75,0x02,0x10,0x0c,0x17,0xe0,0x47,0x18,0xff,0x82,0x07,0xc4,0xaf,0x8f,0xd2,0x43,0x80,0x82,0x56,0x01,0x03,0x35,0xfc,0x43,0xc7,0xe3,0x8a,0xc4,0x6a,0xa5,0x50,0x28,0x8d,0x02,0x05,0xa8,0x13,0x8c,0xaa,0xf9,0x1f,0xe2,0x5d,0xc2,0xc3,0x75,0x9f,0xe0,0xa1,0x14,0x08,0x0f,0x60,0x52,0x33,0x59,0xf4,0xf8,0x7e,0x32,0x2d,0x10,0xfc,0x70,0x58,0x89,0x04,0x06,0xd1,0xa0,0x0f,0x8f,0xfa,0x7e,0x3f,0x3e,0xa8,0x7c,0x69,0x1a,0x08,0x04,0xe2,0x80,0x1f,0x19,0xfd,0xf8,0xfe,0x92,0xa0,0x78,0xd0,0x20,0x19,0x8e,0x19,0xa8,0x7a,0xf7,0x51,0xfb,0x03,0xcb,0x11,0xc3,0xaa,0x4d,0x7a,0x76,0x51,0xf8,0x87,0xc8,0x7e,0x34,0x85,0xf0,0xe2,0x24,0x7a,0xe0,0xf9,0xaf,0xd0,0x9e,0x31,0x08,0x04,0x22,0x01,0x57,0x1f,0x9e,0xb8,0x7e,0x90,0x80,0x79,0x61,0x07,0xe2,0x5f,0x2f,0xfd,0xde,0xeb,0xf7,0x4f,0x8c,0x44,0x3a,0x30,0x8f,0xc0,0x7c,0x4f,0xe6,0x1f,0x29,0xda,0xbc,0x41,0xe5,0xc0,0xd7,0xa7,0xcd,0x8a,0x3d,0xdf,0xe8,0x7c,0x60,0x40,0xf2,0x80,0x55,0x97,0xe7,0xee,0x0f,0x0f,0xa9,0xfe,0x30,0x40,0x79,0x7c,0x05,0x43,0xe1,0x6f,0x88,0x7c,0x40,0x02,0x1f,0x18,0x01,0x3c,0x5d,0xe5,0x9f,0x80,0xbf,0xc4,0x1f,0x00,0x05,0x82,0x01,0x50,0x1e,0x28,0xf1,0x00,0x2c,0x90,0x1e,0xca,0xf1,0x00,0x2d,0x52,0x1e,0x0f,0x5c,0x00,0x7d,0xc1,0xed,0x00,0x25,0x08,0xff,0x00,0x46,0x00,0x3f,0xe1,0x7c,0xff,0xf0,0x30,0xc3,0xc0,0x3c,0x02,0x73,0xbc,0x00,0xcb,0xf0,0x18,0x4f,0xf8,0x3e,0x00,0x0c,0x0f,0xf0,}; +const uint8_t *_I_IrdaSend_128x64[] = {_I_IrdaSend_128x64_0}; + +const uint8_t _I_DolphinReadingSuccess_59x63_0[] = {0x01,0x00,0x19,0x01,0x00,0x1d,0x00,0x0f,0xd2,0x00,0x21,0xe0,0x3f,0xf0,0xf9,0x00,0x40,0xee,0x00,0x11,0x88,0x04,0x0e,0x18,0x11,0x18,0x8c,0x40,0x0e,0x50,0x30,0x10,0xc0,0xa1,0x01,0xe2,0x05,0x14,0x12,0x08,0x33,0x58,0x44,0x08,0x66,0xa1,0xe3,0x01,0x9c,0x83,0x00,0x24,0x11,0x11,0x06,0xc4,0x76,0x20,0x75,0x15,0x99,0x48,0xc0,0xe9,0x0f,0x03,0x95,0xfc,0x86,0x3c,0x09,0x80,0x1c,0x7c,0x00,0x91,0x81,0x48,0x2f,0xc1,0x41,0x8c,0xc0,0x20,0x30,0x1c,0x87,0xfc,0x0e,0x30,0x70,0x70,0x81,0xc7,0xe6,0x07,0x18,0x08,0x1c,0xb9,0x1e,0x38,0x0f,0x02,0x01,0xf0,0x03,0xa0,0xa4,0x7f,0x90,0x30,0x38,0xff,0xe0,0x28,0x21,0xff,0x06,0x44,0x0e,0x46,0xe1,0x01,0x8c,0x03,0x34,0x2f,0x25,0x18,0x80,0xc7,0x2a,0x03,0x2e,0x01,0x3c,0x70,0x12,0xa2,0x39,0x78,0x27,0xe0,0x31,0xea,0x82,0xc4,0x6c,0x31,0xf0,0x78,0xea,0xb0,0x22,0x31,0xfc,0x1a,0xc6,0x01,0x55,0x25,0x88,0xf8,0x4b,0x02,0x1f,0x13,0xe1,0x7f,0x97,0x85,0x15,0x03,0x90,0xf8,0xa0,0x10,0xa1,0xb1,0x0e,0x88,0x00,0x7f,0x0f,0xc0,0x7c,0x57,0x27,0x3c,0xb0,0x7f,0x5f,0xa9,0x1f,0xc0,0x6a,0xc5,0x05,0xc0,0xf0,0x11,0x46,0xac,0x18,0x3f,0xf9,0x54,0x75,0x00,0x73,0x1f,0x0f,0xfe,0xfe,0xc6,0x30,0x01,0xbc,0x48,0x00,0x84,0x82,0x00,0x1b,0x64,0xc0,0x07,0x60,0x03,0xb4,0x70,0x0c,0xbf,0x82,0x31,0x01,0x8d,0x0c,0x40,0x02,0x37,0x08,0x1d,0x74,0x00,0x76,0xa0,0x01,0xdb,0x01,0xfe,0x85,0x8b,0x96,0xaa,0x9b,0x30,0x01,0x6a,0xa3,0x40,0x75,0xaa,0x03,0xdb,0x50,0xbb,0x30,0x01,0x54,0x24,0x25,0xe6,0x51,0x08,0x1f,0x68,0x00,0x7f,0x03,0xf2,0x79,0xc0,0xf4,}; +const uint8_t *_I_DolphinReadingSuccess_59x63[] = {_I_DolphinReadingSuccess_59x63_0}; + +const uint8_t _I_Mute_hvr_25x27_0[] = {0x01,0x00,0x4a,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x21,0xfe,0x40,0x7b,0xf7,0xff,0x5c,0x07,0x7f,0xbf,0xf9,0xc0,0x6f,0xfd,0xff,0xd8,0x3c,0x7c,0x1f,0x90,0x38,0xff,0x7f,0x40,0x31,0xbd,0x82,0xc6,0xff,0xb7,0x01,0x97,0x3c,0x06,0xc0,0xb3,0x09,0x98,0x6c,0x84,0x68,0x2b,0x21,0x99,0x8e,0xcc,0x86,0x64,0xb5,0x01,0x89,0x5c,0xcb,0xe6,0x67,0x30,}; +const uint8_t *_I_Mute_hvr_25x27[] = {_I_Mute_hvr_25x27_0}; + +const uint8_t _I_Back_15x10_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x0F,0x06,0x10,0x04,0x20,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x10,0xFE,0x0F,}; +const uint8_t *_I_Back_15x10[] = {_I_Back_15x10_0}; + +const uint8_t _I_Up_25x27_0[] = {0x01,0x00,0x44,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3c,0x88,0x00,0xca,0x70,0x03,0x2b,0xe0,0x0c,0xbf,0xc0,0x32,0xff,0x80,0x87,0x03,0xff,0x81,0xc0,0x78,0x3f,0xf8,0x3c,0x07,0xc3,0xff,0x87,0xc0,0x7e,0x3f,0xf8,0xf8,0x0d,0x06,0xfe,0x03,0x78,0x19,0x4c,0x60,0x30,0x68,0x07,0x02,0x01,0xfc,0xff,0xdf,0xcc,0xe8,}; +const uint8_t *_I_Up_25x27[] = {_I_Up_25x27_0}; + +const uint8_t _I_IrdaArrowUp_4x8_0[] = {0x00,0x18,0x3C,0x7E,0xFF,}; +const uint8_t *_I_IrdaArrowUp_4x8[] = {_I_IrdaArrowUp_4x8_0}; + +const uint8_t _I_Mute_25x27_0[] = {0x01,0x00,0x51,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x31,0x81,0xc0,0x64,0x38,0x08,0xa4,0x06,0x83,0x40,0x86,0x40,0x70,0x32,0x08,0x20,0x3c,0x63,0xf0,0x60,0x38,0xc0,0xa0,0xa0,0x31,0xc2,0x02,0xc7,0x03,0x48,0x01,0x94,0xc0,0x06,0xc0,0xb3,0x09,0x98,0x6c,0x84,0x68,0x2b,0x21,0x99,0x8e,0xcc,0x86,0x64,0xb3,0x81,0x94,0xc6,0x03,0x06,0x80,0x70,0x20,0x1f,0xcf,0xfd,0xfc,0xce,0x80,}; +const uint8_t *_I_Mute_25x27[] = {_I_Mute_25x27_0}; + +const uint8_t _I_Power_25x27_0[] = {0x01,0x00,0x54,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x30,0x18,0x80,0x0c,0xa7,0x00,0x35,0xc0,0xce,0x60,0x70,0x1e,0x0c,0xe6,0x0f,0x01,0xf0,0xce,0x21,0xd0,0x1b,0x0c,0xe2,0x18,0x03,0x58,0x80,0x0c,0xa0,0x00,0x39,0xf0,0xc0,0x03,0x63,0xc1,0x80,0x88,0xc7,0x03,0x83,0x15,0x8c,0x07,0xfe,0x02,0x18,0x0d,0xf0,0x76,0x44,0x73,0x01,0x94,0x0c,0xa6,0x30,0x18,0x34,0x03,0x81,0x00,0xfe,0x7f,0xef,0xe6,0x74,}; +const uint8_t *_I_Power_25x27[] = {_I_Power_25x27_0}; + +const uint8_t _I_IrdaSendShort_128x34_0[] = {0x01,0x00,0x42,0x01,0xfe,0x7f,0xc0,0x07,0x03,0x07,0xc4,0x10,0x0a,0x90,0x20,0x7f,0x83,0xfc,0x04,0x3c,0x01,0xc2,0x7f,0xf8,0x80,0x43,0x9f,0x83,0xca,0x40,0x1f,0x5e,0x27,0x7e,0xab,0x55,0xee,0x83,0xce,0x38,0x0f,0x6d,0x50,0x00,0xa5,0xc0,0xf2,0x89,0x03,0xda,0xfe,0x1f,0x1f,0xa8,0x7c,0x48,0xc3,0x09,0x07,0xb6,0xae,0x54,0x1f,0x19,0xd4,0x08,0x40,0x30,0x5f,0x81,0x1c,0x63,0xfe,0x08,0x1f,0x12,0xbe,0x3f,0x49,0x0e,0x02,0x09,0x58,0x04,0x0c,0xd7,0xf1,0x0f,0x1f,0x8e,0x2b,0x11,0xaa,0x95,0x40,0xa2,0x34,0x08,0x16,0xa0,0x4e,0x32,0xab,0xe4,0x7f,0x89,0x77,0x0b,0x0d,0xd6,0x7f,0x82,0x84,0x50,0x20,0x3d,0x81,0x48,0xcd,0x67,0xd3,0xe1,0xf8,0xc8,0xb4,0x43,0xf1,0xc1,0x62,0x24,0x10,0x1b,0x46,0x80,0x3e,0x3f,0xe9,0xf8,0xfc,0xfa,0xa1,0xf1,0xa4,0x68,0x20,0x13,0x8a,0x00,0x7c,0x67,0xf7,0xe3,0xfa,0x4a,0x81,0xe3,0x40,0x80,0x66,0x38,0x66,0xa1,0xeb,0xdd,0x47,0xec,0x0f,0x2c,0x47,0x0e,0xa9,0x35,0xe9,0xd9,0x47,0xe2,0x1f,0x21,0xf8,0xd2,0x17,0xc3,0x88,0x91,0xeb,0x83,0xe6,0xbf,0x42,0x78,0xc4,0x20,0x10,0x88,0x05,0x5c,0x7e,0x7a,0xe1,0xfa,0x42,0x01,0xe5,0x84,0x1f,0x89,0x7c,0xbf,0xf7,0x7b,0xaf,0xdd,0x3e,0x31,0x10,0xe8,0xc2,0x3f,0x01,0xf1,0x3f,0x98,0x7c,0xa7,0x6a,0xf1,0x07,0x97,0x03,0x5e,0x9f,0x36,0x28,0xf7,0x7f,0xa1,0xf1,0x81,0x03,0xca,0x01,0x56,0x5f,0x9f,0xb8,0x3c,0x3e,0xa7,0xf8,0xc1,0x01,0xe5,0xf0,0x15,0x0f,0x85,0xbe,0x21,0xf1,0x00,0x08,0x7c,0x60,0x04,0xf1,0x77,0x96,0x7e,0x02,0xff,0x10,0x7c,0x00,0x16,0x08,0x05,0x40,0x78,0xa3,0xc4,0x00,0xb2,0x40,0x7b,0x2b,0xc4,0x00,0xb5,0x48,0x78,0x3d,0x70,0x01,0xf7,0x07,0xb4,0x00,0x94,0x23,0xfc,0x01,0x18,0x00,0xff,0x85,0xf3,0xff,0xc0,0xc3,0x0f,0x00,0xf0,0x09,0xce,0xf0,0x03,0x2f,0xc0,0x61,0x3f,0xe0,0xf8,0x00,0x30,0x3f,0xc0,}; +const uint8_t *_I_IrdaSendShort_128x34[] = {_I_IrdaSendShort_128x34_0}; + +const uint8_t _I_IrdaArrowDown_4x8_0[] = {0x00,0xFF,0x7E,0x3C,0x18,}; +const uint8_t *_I_IrdaArrowDown_4x8[] = {_I_IrdaArrowDown_4x8_0}; + +const uint8_t _I_IrdaLearn_128x64_0[] = {0x01,0x00,0xcc,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3f,0x01,0x07,0x82,0x41,0x21,0x20,0x73,0x00,0x8e,0x82,0x0f,0x00,0xa0,0x01,0x46,0x11,0x00,0x07,0xc0,0x28,0x41,0xe5,0xc8,0xba,0x63,0xa7,0x70,0x6b,0x3d,0xbb,0x99,0x19,0xee,0x68,0x71,0x16,0x3f,0x70,0x3c,0x64,0xf9,0x58,0x25,0x26,0x13,0x91,0xc9,0x64,0xa4,0x99,0x2d,0x06,0x1f,0x29,0x42,0x07,0x8c,0x80,0x1e,0x50,0xff,0x88,0x3c,0x67,0x80,0xf1,0xc1,0x03,0xde,0x03,0x11,0x07,0x8c,0x10,0x1e,0x38,0x40,0x79,0xf0,0x32,0x80,0xf1,0x83,0x58,0x72,0x58,0xc8,0xc6,0x73,0x40,0x3f,0x10,0x78,0x9e,0xf1,0x17,0xe9,0xcf,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x02,0x44,0x18,0xa3,0x80,0x82,0x32,0x06,0x44,0x0f,0xf0,0x73,0x5d,0xe3,0x92,0x7e,0xcf,0x06,0x3b,0xc3,0xa4,0xdd,0xfc,0xc8,0x35,0xca,0x44,0xa5,0x34,0x5c,0x16,0x92,0x89,0x4a,0x91,0x4a,0x60,0x20,0xf7,0xa4,0x83,0xc6,0x8e,0x0f,0xba,0x88,0x3c,0x68,0x00,0xf7,0x80,0x65,0xe3,0x9c,0x7a,0x6e,0x0a,0x49,0xc3,0xb8,0xc8,0xa4,0xc0,0xf5,0x00,0x08,0x1d,0xc0,0x0e,0x0f,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xfb,0xfe,0x00,0x38,0x39,0x97,0xa1,0x00,0xe7,0xf0,0x3b,0x1c,0x00,0xd9,0x00,0x32,0xc8,0x01,0xef,0x48,0x03,0x2d,0x03,0xe0,0x45,0x38,0x0d,0x02,0x01,0x28,0xc0,0x01,0xca,0x01,0x1f,0xa0,0x10,0x12,0x05,0x80,0x80,0x49,0x38,0x1a,0xa0,0x00,0xf0,0x6f,0xf8,0x08,0x20,0x38,0xac,0x10,0x48,0x44,0x06,0x25,0x40,0xaa,0x80,0x07,0xc3,0xfb,0x80,0x41,0x21,0x9b,0x0b,0x6e,0x4e,0x09,0x10,0x80,0xc2,0xb8,0x1f,0xe0,0xf8,0xfc,0x7e,0x30,0x10,0x7a,0xc8,0x20,0x50,0x9a,0x04,0x0c,0x3e,0x3f,0x12,0x48,0x83,0xc6,0x60,0x2f,0x29,0x14,0x0a,0x0b,0xc0,0x80,0x87,0xc7,0xf3,0xf1,0x81,0x8f,0xc7,0x01,0x6d,0x81,0xc7,0x24,0x90,0x28,0x17,0x02,0x39,0x5e,0xaa,0xee,0x75,0xd0,0x3e,0x27,0xb4,0x5e,0x30,0x39,0x20,0x3c,0xa8,0x11,0xcd,0x36,0xab,0x33,0x2e,0x07,0x90,0xbc,0x4d,0x82,0x0f,0x14,0x10,0xc7,0x2e,0x21,0xf3,0x17,0x88,0x7c,0x85,0xe3,0x82,0x4c,0x8c,0x03,0x70,0x3f,0x2b,0x19,0x3c,0x47,0xe2,0x04,0x19,0x10,0x3c,0xa4,0x15,0xc2,0xf9,0x7c,0x41,0xe2,0x2e,0x1f,0x81,0xbc,0x68,0x40,0xf1,0xe0,0x6f,0xcf,0xe5,0xf9,0x82,0x63,0x3e,0xfd,0xef,0x9a,0x3c,0x68,0x22,0xf2,0xbf,0x27,0xcb,0xf1,0x04,0xc0,0x03,0xc4,0x5e,0x30,0x80,0x79,0xec,0x17,0xe5,0xf0,0x67,0xb0,0x34,0x68,0x18,0x0a,0xfd,0x56,0x1b,0x1f,0xb0,0x3b,0xd9,0xc0,0x2e,0xf3,0x25,0x90,0x01,0x81,0xe2,0x00,0xe8,0x08,0x3f,0xa0,0x40,0xfe,0x53,0x88,0x03,0x4c,0xe8,0x00,0xa8,0x80,0x3f,0xa4,0x00,0xfe,0xe0,0x21,0xcc,0x00,0x47,0x7f,0x00,0x78,}; +const uint8_t *_I_IrdaLearn_128x64[] = {_I_IrdaLearn_128x64_0}; + +const uint8_t _I_Power_hvr_25x27_0[] = {0x01,0x00,0x4b,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x3f,0xff,0x78,0x0c,0xb8,0xe0,0x35,0xbf,0xf1,0xbf,0x90,0x19,0xff,0x1b,0xf1,0x01,0x8f,0xf1,0xfe,0x30,0x1c,0xff,0x1f,0xe6,0x03,0x5f,0x78,0x0c,0xbf,0xe0,0x39,0x8f,0xff,0xc3,0x63,0x3f,0xff,0x08,0xc6,0xff,0x7c,0x15,0x89,0x04,0x7f,0xc0,0x31,0xc1,0x8e,0xc8,0x8e,0x60,0x36,0x2b,0x99,0x7c,0xcc,0xe6,}; +const uint8_t *_I_Power_hvr_25x27[] = {_I_Power_hvr_25x27_0}; const uint8_t _I_KeySaveSelected_24x11_0[] = {0x01,0x00,0x1a,0x00,0xff,0x7f,0xc0,0x0d,0xcf,0xb4,0x7c,0xee,0xf6,0xbf,0x6d,0xbe,0xd7,0xe1,0xaf,0xda,0xff,0xbe,0x7c,0xc7,0xcc,0x28,0xa1,0xd1,0xbf,0x80,}; const uint8_t *_I_KeySaveSelected_24x11[] = {_I_KeySaveSelected_24x11_0}; @@ -202,6 +199,12 @@ const uint8_t *_I_KeySaveSelected_24x11[] = {_I_KeySaveSelected_24x11_0}; const uint8_t _I_KeyBackspace_16x9_0[] = {0x00,0xFE,0x7F,0x01,0x80,0x11,0x80,0x19,0x80,0xFD,0xBF,0x19,0x80,0x11,0x80,0x01,0x80,0xFE,0x7F,}; const uint8_t *_I_KeyBackspace_16x9[] = {_I_KeyBackspace_16x9_0}; +const uint8_t _I_KeyBackspaceSelected_16x9_0[] = {0x00,0xFE,0x7F,0xFF,0xFF,0xEF,0xFF,0xE7,0xFF,0x03,0xC0,0xE7,0xFF,0xEF,0xFF,0xFF,0xFF,0xFE,0x7F,}; +const uint8_t *_I_KeyBackspaceSelected_16x9[] = {_I_KeyBackspaceSelected_16x9_0}; + +const uint8_t _I_KeySave_24x11_0[] = {0x01,0x00,0x1e,0x00,0xff,0x7f,0xff,0xf0,0x18,0x06,0x00,0x04,0x53,0x1c,0xbe,0x33,0x13,0x94,0xc9,0x64,0x72,0x99,0xed,0x0e,0x53,0x05,0x19,0xb3,0xe3,0x02,0x8a,0x1d,0x1b,0xf8,}; +const uint8_t *_I_KeySave_24x11[] = {_I_KeySave_24x11_0}; + const uint8_t _A_125khz_14_0[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x13,0x00,0x24,0x0E,0x28,0x71,0x28,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xF8,0x00,}; const uint8_t _A_125khz_14_1[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x10,0x00,0x20,0x0E,0x20,0x71,0x20,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xF8,0x00,}; const uint8_t _A_125khz_14_2[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3a,0x01,0x71,0x80,0x61,0x60,0x30,0x18,0x15,0x8a,0x05,0x92,0x00,0x95,0x92,0x05,0x04,0x80,0xfe,0x20,0x00,}; @@ -344,45 +347,45 @@ const uint8_t *_I_Detailed_chip_17x13[] = {_I_Detailed_chip_17x13_0}; const uint8_t _I_Medium_chip_22x21_0[] = {0x01,0x00,0x35,0x00,0xfe,0x7f,0xe1,0xf0,0x28,0x04,0x43,0xf3,0xff,0x93,0xe1,0x6a,0x52,0x8e,0x2f,0xfe,0x51,0x25,0x80,0x4a,0x72,0xb6,0x79,0x55,0x76,0xc1,0x2e,0xaa,0xc0,0x25,0x51,0xdc,0x00,0x14,0x70,0x00,0x56,0xae,0x81,0x47,0x2b,0x7d,0x95,0x07,0x48,0x46,0x42,0x92,0x17,0x90,0xd4,0x87,0x64,}; const uint8_t *_I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; -const uint8_t _I_Health_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x2f,0x02,0x03,0x40,0x00,0x95,0xe2,0x1f,0x08,0x84,0x00,0xc4,0x12,0x60,0xf1,0x0c,0xb8,}; -const uint8_t *_I_Health_16x16[] = {_I_Health_16x16_0}; +const uint8_t _I_BatteryBody_52x28_0[] = {0x01,0x00,0x45,0x00,0xe0,0x7f,0x3f,0xe0,0x02,0x87,0xf0,0x21,0xe0,0xc3,0x84,0x50,0x39,0xbf,0xff,0x27,0xfe,0xf3,0x09,0xe0,0x42,0x81,0xab,0x0d,0x03,0x1c,0x2b,0xfc,0x0d,0x48,0x55,0xdc,0x1a,0x90,0x8f,0x18,0x6d,0x41,0xaa,0x1b,0x71,0x4b,0x0d,0xd4,0x1b,0xe0,0xdf,0x1b,0xd5,0xfc,0x1a,0xa5,0x36,0x06,0xac,0x20,0xa7,0xe0,0xdc,0xa5,0x7c,0x7c,0xb7,0xff,0xb4,0x21,0x5c,0xcb,0xc6,}; +const uint8_t *_I_BatteryBody_52x28[] = {_I_BatteryBody_52x28_0}; const uint8_t _I_FaceCharging_29x14_0[] = {0x01,0x00,0x28,0x00,0xa0,0x00,0x86,0x05,0x60,0x01,0x8c,0x0e,0x61,0x00,0xc0,0x40,0x63,0x10,0x0e,0x04,0x03,0xf9,0x00,0xf0,0x41,0xc0,0x66,0x13,0xb8,0x40,0x94,0xc0,0x07,0x04,0x82,0x00,0xc6,0x11,0x02,0x01,0x8f,0xc2,0x03,0x00,}; const uint8_t *_I_FaceCharging_29x14[] = {_I_FaceCharging_29x14_0}; -const uint8_t _I_BatteryBody_52x28_0[] = {0x01,0x00,0x45,0x00,0xe0,0x7f,0x3f,0xe0,0x02,0x87,0xf0,0x21,0xe0,0xc3,0x84,0x50,0x39,0xbf,0xff,0x27,0xfe,0xf3,0x09,0xe0,0x42,0x81,0xab,0x0d,0x03,0x1c,0x2b,0xfc,0x0d,0x48,0x55,0xdc,0x1a,0x90,0x8f,0x18,0x6d,0x41,0xaa,0x1b,0x71,0x4b,0x0d,0xd4,0x1b,0xe0,0xdf,0x1b,0xd5,0xfc,0x1a,0xa5,0x36,0x06,0xac,0x20,0xa7,0xe0,0xdc,0xa5,0x7c,0x7c,0xb7,0xff,0xb4,0x21,0x5c,0xcb,0xc6,}; -const uint8_t *_I_BatteryBody_52x28[] = {_I_BatteryBody_52x28_0}; - -const uint8_t _I_Voltage_16x16_0[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0x0a,0x01,0x03,0xc0,0x40,0x78,0x10,0x1f,0x04,0x03,0xe1,0x07,0xc0,0x40,0xc0,0xe3,0xc0,0x80,0x58,0x20,0x12,0x00,0xd3,0x00,}; -const uint8_t *_I_Voltage_16x16[] = {_I_Voltage_16x16_0}; +const uint8_t _I_Health_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x2f,0x02,0x03,0x40,0x00,0x95,0xe2,0x1f,0x08,0x84,0x00,0xc4,0x12,0x60,0xf1,0x0c,0xb8,}; +const uint8_t *_I_Health_16x16[] = {_I_Health_16x16_0}; const uint8_t _I_Temperature_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x1e,0x02,0x01,0x40,0x80,0x80,0x66,0x41,0x02,0xf0,0x40,0xc0,0x23,0xc0,0x80,0x86,0xd4,}; const uint8_t *_I_Temperature_16x16[] = {_I_Temperature_16x16_0}; -const uint8_t _I_FaceNopower_29x14_0[] = {0x01,0x00,0x24,0x00,0x00,0x1f,0x02,0x01,0x60,0x01,0xa7,0x80,0x02,0x57,0xe0,0x48,0xc3,0xe7,0xd0,0x0c,0x04,0x3c,0x39,0x1f,0x88,0x18,0x0c,0x61,0x90,0x60,0x18,0xff,0x82,0x44,0x03,0x38,0x74,0x38,0x2c,0x80,}; -const uint8_t *_I_FaceNopower_29x14[] = {_I_FaceNopower_29x14_0}; - -const uint8_t _I_FaceNormal_29x14_0[] = {0x01,0x00,0x1e,0x00,0x00,0x1c,0xf2,0x01,0x80,0x83,0xd7,0xa0,0x1c,0x08,0x5d,0xf8,0x06,0x30,0xf0,0x1b,0x84,0xcc,0x41,0x10,0x88,0x10,0x0e,0x62,0x10,0x10,0x18,0xf8,0x00,0x42,}; -const uint8_t *_I_FaceNormal_29x14[] = {_I_FaceNormal_29x14_0}; - const uint8_t _I_Battery_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x1e,0x02,0x03,0xc0,0x81,0xc8,0x20,0x80,0x11,0xd0,0x41,0x40,0x72,0x11,0x10,0xda,0x80,}; const uint8_t *_I_Battery_16x16[] = {_I_Battery_16x16_0}; const uint8_t _I_FaceConfused_29x14_0[] = {0x01,0x00,0x30,0x00,0xc0,0x00,0x46,0x1f,0x38,0x80,0xd0,0x22,0x14,0x48,0x0c,0x82,0x0f,0x52,0x80,0xe8,0x21,0x14,0xa0,0x18,0xc2,0xa6,0x59,0x19,0x24,0x27,0x09,0x48,0xa1,0x41,0x2f,0x12,0x4c,0x0c,0x0c,0x51,0x1f,0xc8,0x78,0x0c,0x7f,0xd1,0xf0,0x18,0xc3,0xa3,0x00,0x74,}; const uint8_t *_I_FaceConfused_29x14[] = {_I_FaceConfused_29x14_0}; -const uint8_t _I_RFIDDolphinSuccess_108x57_0[] = {0x01,0x00,0xe7,0x01,0x00,0x0f,0x03,0xff,0x1f,0x06,0xd4,0xe2,0x01,0xe0,0x06,0xd4,0x18,0x04,0x30,0x30,0x64,0x60,0x20,0x20,0x31,0x86,0x03,0x62,0x80,0x03,0x28,0x80,0x36,0x24,0x00,0x36,0x00,0x28,0x5c,0xc3,0xe6,0x00,0x58,0x40,0xec,0xc1,0xb1,0x04,0x02,0x19,0x24,0x80,0x0b,0x02,0x02,0x40,0x37,0xc4,0x8c,0x2e,0x40,0x6f,0x93,0x8b,0x81,0x07,0x06,0xdc,0xc2,0x38,0x66,0x50,0x6a,0xe2,0x27,0xe0,0xd2,0xfc,0x08,0x09,0x0c,0x9c,0x4b,0x98,0x34,0xa0,0xe1,0xd5,0x06,0x8f,0x92,0xc2,0x05,0x1e,0x42,0xe1,0x81,0xa3,0xe2,0xf0,0xbc,0x4c,0x1a,0xff,0x2f,0x9b,0x80,0xd8,0xca,0x05,0x1f,0x97,0xfd,0xf8,0x60,0xd2,0x01,0x1e,0x00,0x1a,0x5c,0x00,0x08,0xc9,0xc1,0xab,0x40,0xf9,0x83,0x46,0x61,0x00,0xd8,0x4a,0x81,0xab,0xa0,0xf3,0x5f,0xc6,0x05,0x58,0x8a,0xa4,0x09,0x76,0x21,0xb1,0xf2,0x83,0x4f,0x5d,0x1a,0x01,0x8c,0x90,0x1a,0x31,0x0d,0x07,0xa9,0x16,0x50,0x0a,0xac,0x34,0xba,0x42,0xa1,0x88,0x50,0x23,0xaa,0x72,0xe0,0x6a,0xa1,0x4a,0x32,0x39,0x88,0x6c,0x60,0xc7,0x82,0xb0,0x55,0x60,0xa2,0x92,0x80,0xc0,0x43,0x63,0x03,0x25,0x96,0xe3,0x54,0x33,0x18,0xc4,0x90,0x22,0x21,0x81,0x81,0x03,0x4a,0xa9,0x55,0x7a,0x17,0xf3,0x82,0x9f,0x6d,0x5e,0xa9,0xb6,0x50,0x38,0x70,0x35,0x70,0x15,0x5a,0xa9,0xb8,0xa3,0x46,0x12,0x06,0x9f,0x83,0x54,0x8a,0x28,0x80,0x34,0xfc,0x08,0x93,0xaa,0xc7,0x40,0x83,0x83,0x81,0xd3,0xa1,0xd1,0x08,0x84,0x0c,0x24,0x3f,0xed,0x54,0x18,0x26,0x50,0x20,0xd9,0x42,0x21,0x90,0x4c,0x07,0xff,0xae,0x52,0x20,0x6a,0xc4,0x23,0x1f,0x88,0x3f,0xf0,0x1a,0x45,0x31,0xe7,0x03,0x4a,0x41,0xe0,0x69,0x0f,0xc2,0x1e,0x0d,0x19,0x80,0x48,0xa2,0x10,0xc5,0x68,0xdf,0x0a,0x82,0xb9,0x28,0x22,0x2c,0xe3,0x0a,0xd1,0x2b,0x0f,0x00,0x3c,0x22,0x91,0x53,0x9c,0x50,0x1a,0x30,0x08,0x39,0x1c,0x60,0x6d,0x12,0x3d,0x8c,0xc2,0x51,0x00,0x17,0x0c,0xe2,0x01,0xff,0x83,0x84,0xc6,0x40,0xb0,0x19,0x84,0xd0,0x1a,0x5c,0x08,0x1f,0xf8,0x8c,0x50,0x43,0x08,0xce,0x2d,0x06,0x71,0x5f,0x17,0xfe,0x12,0xdf,0x20,0x69,0x55,0x01,0xa6,0x00,0x18,0x40,0xa4,0x80,0x63,0x3c,0xb5,0x03,0x56,0x08,0x8b,0x20,0x10,0xcf,0x03,0x62,0x08,0x20,0x00,0x94,0xc6,0x01,0x70,0x01,0x0c,0xe8,0x36,0x20,0xd3,0xe0,0x00,0xcb,0x10,0x02,0x19,0xf3,0x9c,0x41,0xa3,0x15,0x31,0x90,0x00,0x70,0xc0,0x21,0xdd,0x86,0xc4,0x78,0x3e,0xa3,0x71,0xe0,0x30,0x20,0x31,0xbe,0x86,0xc4,0x1a,0x35,0x40,0x20,0x8d,0x89,0x28,0x5b,0xa0,0xd9,0xea,0x3d,0x44,0x42,0x87,0x83,0x48,0x36,0x49,0xe1,0xa0,0x75,0x67,0x8d,0x41,0x54,0x14,0x03,0xf5,0x2a,0x06,0x96,0x03,0x54,0xc4,0x14,0xd0,0x83,0x4a,0xfb,0x35,0x06,0x90,0x38,0x4e,0x46,0xb4,0x10,0xd9,0x81,0x49,0x72,0x40,0x01,0x0a,0x95,0xd4,0x36,0x20,0xd7,0x55,0x10,}; -const uint8_t *_I_RFIDDolphinSuccess_108x57[] = {_I_RFIDDolphinSuccess_108x57_0}; +const uint8_t _I_FaceNormal_29x14_0[] = {0x01,0x00,0x1e,0x00,0x00,0x1c,0xf2,0x01,0x80,0x83,0xd7,0xa0,0x1c,0x08,0x5d,0xf8,0x06,0x30,0xf0,0x1b,0x84,0xcc,0x41,0x10,0x88,0x10,0x0e,0x62,0x10,0x10,0x18,0xf8,0x00,0x42,}; +const uint8_t *_I_FaceNormal_29x14[] = {_I_FaceNormal_29x14_0}; -const uint8_t _I_RFIDBigChip_37x36_0[] = {0x01,0x00,0x6e,0x00,0x83,0x01,0x0f,0xcd,0xff,0x00,0x0c,0x1e,0x24,0x08,0x28,0x47,0x24,0x12,0x51,0x39,0x28,0x24,0xa2,0x91,0x5e,0x07,0xab,0xfe,0x04,0x1c,0x04,0xaa,0x01,0x15,0x02,0x28,0x4c,0x81,0x2c,0x04,0x4e,0x05,0xfc,0x08,0x35,0x59,0x06,0x02,0x81,0x15,0xca,0xe4,0x26,0xf2,0x10,0x70,0xd7,0x66,0x11,0x70,0x70,0xd4,0x20,0x14,0x10,0x70,0xc7,0x68,0x13,0x70,0x70,0xd4,0x28,0x10,0x10,0x4a,0x84,0xc6,0x80,0x13,0x10,0xe8,0xd0,0x03,0xa2,0x27,0x19,0xf0,0x9c,0x46,0x28,0x3b,0x42,0xcf,0x96,0x6a,0xd4,0x13,0x6f,0x2a,0x2c,0xa2,0x90,0x54,0x59,0xfe,0x52,0xa7,0x02,0x4f,0x9f,0xf1,0x52,0x60,}; -const uint8_t *_I_RFIDBigChip_37x36[] = {_I_RFIDBigChip_37x36_0}; +const uint8_t _I_Voltage_16x16_0[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0x0a,0x01,0x03,0xc0,0x40,0x78,0x10,0x1f,0x04,0x03,0xe1,0x07,0xc0,0x40,0xc0,0xe3,0xc0,0x80,0x58,0x20,0x12,0x00,0xd3,0x00,}; +const uint8_t *_I_Voltage_16x16[] = {_I_Voltage_16x16_0}; + +const uint8_t _I_FaceNopower_29x14_0[] = {0x01,0x00,0x24,0x00,0x00,0x1f,0x02,0x01,0x60,0x01,0xa7,0x80,0x02,0x57,0xe0,0x48,0xc3,0xe7,0xd0,0x0c,0x04,0x3c,0x39,0x1f,0x88,0x18,0x0c,0x61,0x90,0x60,0x18,0xff,0x82,0x44,0x03,0x38,0x74,0x38,0x2c,0x80,}; +const uint8_t *_I_FaceNopower_29x14[] = {_I_FaceNopower_29x14_0}; const uint8_t _I_RFIDDolphinSend_97x61_0[] = {0x01,0x00,0x8d,0x01,0x00,0x0f,0xfa,0x3e,0x04,0x2a,0x00,0x2d,0x78,0x10,0x1f,0x04,0x04,0x0a,0x38,0x00,0x62,0xcc,0x00,0x43,0x06,0x06,0x44,0x30,0x04,0x31,0x80,0x31,0x07,0x48,0x00,0x50,0x20,0x10,0xc8,0x01,0x64,0x0c,0x1d,0x04,0x28,0x24,0x83,0xd2,0x81,0x04,0xc4,0x18,0x42,0xc3,0x01,0x90,0x30,0xbe,0x05,0x51,0x29,0xa0,0x74,0x60,0x80,0xc1,0x84,0x0b,0x44,0x5e,0x43,0x73,0x82,0x41,0x20,0x1e,0x4a,0x68,0x31,0x27,0x90,0x48,0x84,0x20,0x18,0x31,0x7e,0x64,0x06,0x20,0x0c,0x2a,0x14,0x12,0x40,0x0c,0x28,0xa0,0xc4,0x41,0x87,0x81,0x17,0x08,0x30,0xa0,0xfd,0x08,0x0c,0x20,0xfc,0x38,0x08,0xc4,0x24,0x32,0x95,0x02,0x18,0xc2,0x61,0x18,0x09,0x20,0x31,0x03,0x25,0x84,0x1d,0x88,0x30,0x62,0x21,0x96,0xe2,0x44,0x22,0x00,0xc2,0x26,0xa0,0x64,0x68,0x80,0xc4,0x33,0x9e,0x92,0x9f,0x00,0xa3,0x48,0x24,0x00,0xc4,0x40,0xa4,0xa8,0x18,0xa9,0xb5,0x9b,0x48,0x28,0x05,0xa1,0x06,0x22,0xd4,0xa3,0x7e,0x05,0x98,0xe0,0x4f,0x22,0xcf,0x58,0x6f,0x80,0x10,0x34,0x24,0x31,0x3a,0x52,0x0f,0xe0,0x03,0x0c,0xf1,0xee,0x2d,0x63,0x00,0x0c,0x0f,0xe0,0x13,0x28,0xa0,0x31,0xa0,0x3f,0x08,0x18,0x10,0x45,0xa2,0xe3,0x40,0x00,0xf4,0x3f,0xe1,0xa1,0x84,0x02,0x94,0x18,0xb0,0xc0,0x63,0xc6,0x3f,0xe0,0x31,0x87,0x03,0x1e,0x11,0x3c,0x80,0x47,0xc1,0x90,0x56,0x1b,0x06,0x01,0xc0,0x20,0x06,0x17,0x88,0xf8,0x60,0xa0,0xc7,0x31,0x8a,0x58,0x60,0xe1,0x99,0x00,0x08,0x9a,0x01,0x06,0xd9,0x10,0x03,0x1f,0x44,0x19,0x43,0xc3,0x40,0xc4,0x2c,0x19,0x58,0x08,0x29,0xa0,0x60,0x0c,0xf2,0x00,0x27,0x02,0x05,0x20,0x06,0x4d,0x02,0x0b,0xc0,0x02,0x08,0x3c,0x80,0x09,0xa0,0x39,0x0a,0xd4,0x41,0x8f,0x50,0x05,0x09,0xa4,0x5b,0x4d,0x00,0xd8,0x23,0xc4,0x96,0x20,0xc7,0xac,0x40,0x2d,0x53,0x00,0x64,0x6b,0x20,0x1d,0x4a,0x08,0x32,0x2a,0x90,0x0d,0x46,0x0e,0x02,0x0c,0x79,0x51,0x08,0x61,0xf0,0x20,0x63,0xc5,0x4b,0x83,0x1e,0xfe,0x57,0xd3,0x51,0x40,0xbe,0xc0,0x08,0x42,0x00,0x53,0x30,0xe8,0x3f,0x50,0x14,0x73,0x80,0x0b,0xeb,0x07,0x61,0x40,0x00,0x7d,0x5f,0xf8,0x38,0x32,0x7a,0x03,0xf7,0x55,0xa6,0x78,0x19,0x54,0x0c,0xa8,0x32,0xa0,0x19,0xa0,0x65,0xc4,0x0b,0xe2,0x00,0x98,0x40,0x33,0xc1,0x92,0xfa,0x10,0x67,0x80,0x08,}; const uint8_t *_I_RFIDDolphinSend_97x61[] = {_I_RFIDDolphinSend_97x61_0}; +const uint8_t _I_RFIDDolphinSuccess_108x57_0[] = {0x01,0x00,0xe7,0x01,0x00,0x0f,0x03,0xff,0x1f,0x06,0xd4,0xe2,0x01,0xe0,0x06,0xd4,0x18,0x04,0x30,0x30,0x64,0x60,0x20,0x20,0x31,0x86,0x03,0x62,0x80,0x03,0x28,0x80,0x36,0x24,0x00,0x36,0x00,0x28,0x5c,0xc3,0xe6,0x00,0x58,0x40,0xec,0xc1,0xb1,0x04,0x02,0x19,0x24,0x80,0x0b,0x02,0x02,0x40,0x37,0xc4,0x8c,0x2e,0x40,0x6f,0x93,0x8b,0x81,0x07,0x06,0xdc,0xc2,0x38,0x66,0x50,0x6a,0xe2,0x27,0xe0,0xd2,0xfc,0x08,0x09,0x0c,0x9c,0x4b,0x98,0x34,0xa0,0xe1,0xd5,0x06,0x8f,0x92,0xc2,0x05,0x1e,0x42,0xe1,0x81,0xa3,0xe2,0xf0,0xbc,0x4c,0x1a,0xff,0x2f,0x9b,0x80,0xd8,0xca,0x05,0x1f,0x97,0xfd,0xf8,0x60,0xd2,0x01,0x1e,0x00,0x1a,0x5c,0x00,0x08,0xc9,0xc1,0xab,0x40,0xf9,0x83,0x46,0x61,0x00,0xd8,0x4a,0x81,0xab,0xa0,0xf3,0x5f,0xc6,0x05,0x58,0x8a,0xa4,0x09,0x76,0x21,0xb1,0xf2,0x83,0x4f,0x5d,0x1a,0x01,0x8c,0x90,0x1a,0x31,0x0d,0x07,0xa9,0x16,0x50,0x0a,0xac,0x34,0xba,0x42,0xa1,0x88,0x50,0x23,0xaa,0x72,0xe0,0x6a,0xa1,0x4a,0x32,0x39,0x88,0x6c,0x60,0xc7,0x82,0xb0,0x55,0x60,0xa2,0x92,0x80,0xc0,0x43,0x63,0x03,0x25,0x96,0xe3,0x54,0x33,0x18,0xc4,0x90,0x22,0x21,0x81,0x81,0x03,0x4a,0xa9,0x55,0x7a,0x17,0xf3,0x82,0x9f,0x6d,0x5e,0xa9,0xb6,0x50,0x38,0x70,0x35,0x70,0x15,0x5a,0xa9,0xb8,0xa3,0x46,0x12,0x06,0x9f,0x83,0x54,0x8a,0x28,0x80,0x34,0xfc,0x08,0x93,0xaa,0xc7,0x40,0x83,0x83,0x81,0xd3,0xa1,0xd1,0x08,0x84,0x0c,0x24,0x3f,0xed,0x54,0x18,0x26,0x50,0x20,0xd9,0x42,0x21,0x90,0x4c,0x07,0xff,0xae,0x52,0x20,0x6a,0xc4,0x23,0x1f,0x88,0x3f,0xf0,0x1a,0x45,0x31,0xe7,0x03,0x4a,0x41,0xe0,0x69,0x0f,0xc2,0x1e,0x0d,0x19,0x80,0x48,0xa2,0x10,0xc5,0x68,0xdf,0x0a,0x82,0xb9,0x28,0x22,0x2c,0xe3,0x0a,0xd1,0x2b,0x0f,0x00,0x3c,0x22,0x91,0x53,0x9c,0x50,0x1a,0x30,0x08,0x39,0x1c,0x60,0x6d,0x12,0x3d,0x8c,0xc2,0x51,0x00,0x17,0x0c,0xe2,0x01,0xff,0x83,0x84,0xc6,0x40,0xb0,0x19,0x84,0xd0,0x1a,0x5c,0x08,0x1f,0xf8,0x8c,0x50,0x43,0x08,0xce,0x2d,0x06,0x71,0x5f,0x17,0xfe,0x12,0xdf,0x20,0x69,0x55,0x01,0xa6,0x00,0x18,0x40,0xa4,0x80,0x63,0x3c,0xb5,0x03,0x56,0x08,0x8b,0x20,0x10,0xcf,0x03,0x62,0x08,0x20,0x00,0x94,0xc6,0x01,0x70,0x01,0x0c,0xe8,0x36,0x20,0xd3,0xe0,0x00,0xcb,0x10,0x02,0x19,0xf3,0x9c,0x41,0xa3,0x15,0x31,0x90,0x00,0x70,0xc0,0x21,0xdd,0x86,0xc4,0x78,0x3e,0xa3,0x71,0xe0,0x30,0x20,0x31,0xbe,0x86,0xc4,0x1a,0x35,0x40,0x20,0x8d,0x89,0x28,0x5b,0xa0,0xd9,0xea,0x3d,0x44,0x42,0x87,0x83,0x48,0x36,0x49,0xe1,0xa0,0x75,0x67,0x8d,0x41,0x54,0x14,0x03,0xf5,0x2a,0x06,0x96,0x03,0x54,0xc4,0x14,0xd0,0x83,0x4a,0xfb,0x35,0x06,0x90,0x38,0x4e,0x46,0xb4,0x10,0xd9,0x81,0x49,0x72,0x40,0x01,0x0a,0x95,0xd4,0x36,0x20,0xd7,0x55,0x10,}; +const uint8_t *_I_RFIDDolphinSuccess_108x57[] = {_I_RFIDDolphinSuccess_108x57_0}; + const uint8_t _I_RFIDDolphinReceive_97x61_0[] = {0x01,0x00,0x87,0x01,0x00,0x0f,0xfa,0x3e,0x04,0x28,0x08,0x2d,0x78,0x10,0x1f,0x00,0x24,0x70,0x01,0x86,0x98,0x00,0x86,0x0c,0x0c,0x88,0x60,0x08,0x63,0x10,0x0a,0x00,0x31,0xa0,0x40,0x21,0x90,0x03,0x04,0x1a,0x5a,0x08,0x50,0xe9,0x01,0x23,0x20,0x07,0x88,0x30,0xc5,0xa6,0x03,0x10,0x61,0xfc,0x0a,0xa2,0x2d,0x48,0x0c,0x82,0x20,0x04,0x18,0x40,0x40,0x42,0x44,0x37,0x28,0x80,0x30,0xbc,0x94,0xd0,0x62,0x4f,0x20,0x91,0x08,0x44,0x12,0x01,0x17,0xe6,0x40,0x42,0x45,0x00,0xa1,0x03,0x08,0xa8,0x31,0x41,0x88,0x83,0x0f,0x03,0x08,0x06,0x1c,0x1f,0xa1,0x01,0x84,0x1f,0x8a,0x31,0x09,0x0c,0xa5,0x40,0x86,0x30,0x98,0x46,0x02,0x48,0x0c,0x40,0xc9,0x61,0x00,0xe2,0x0c,0x18,0x88,0x65,0xb8,0x85,0x51,0x06,0x21,0x34,0x83,0x23,0x44,0x06,0x29,0x1c,0xb4,0x94,0xf8,0x05,0x19,0x12,0x20,0xc2,0x40,0xb4,0xa8,0x18,0xa9,0xb5,0x9b,0x48,0x28,0x05,0xa1,0x06,0x22,0xd4,0xa3,0x7e,0x05,0x98,0xe0,0x62,0x0c,0xf6,0x86,0xf8,0x16,0x63,0x42,0x06,0x0b,0xa1,0x60,0xfe,0x06,0xe8,0xcf,0x23,0x0d,0x53,0x00,0x14,0x0f,0xe0,0xea,0x28,0xa0,0x31,0xa0,0x3f,0x08,0x18,0x10,0x45,0xa2,0x11,0x20,0x01,0xf4,0x3f,0xe0,0x81,0x84,0x02,0x94,0x18,0xb0,0xc0,0x63,0xc6,0x3f,0xe0,0x31,0x87,0x03,0x1e,0x11,0x3c,0x80,0x47,0xc1,0x91,0x18,0x80,0x58,0x30,0x0e,0x01,0x00,0x30,0xbc,0x47,0xc3,0x05,0x06,0x3c,0x52,0x00,0xe4,0x20,0xcc,0x80,0x04,0x4d,0x00,0x83,0x73,0x08,0x01,0x8f,0xa2,0x0c,0xa1,0xe1,0xa0,0x62,0x16,0x0c,0xac,0x04,0x14,0xd0,0x30,0x08,0x80,0x31,0xb8,0x10,0x27,0x89,0x03,0x1e,0x81,0x05,0xe0,0x01,0x04,0x1e,0x40,0x04,0xd0,0x1c,0x85,0x6a,0x20,0xc7,0xa8,0x02,0x84,0xd2,0x34,0x00,0x63,0x6c,0x11,0xe2,0x4b,0x10,0x63,0xd6,0x20,0x16,0xa9,0x80,0x32,0x35,0x90,0x0e,0xa5,0x04,0x19,0x15,0x48,0x06,0xa3,0x07,0x01,0x06,0x3c,0xa8,0x84,0x30,0xf8,0x10,0x31,0xe2,0xa5,0xc1,0x8f,0x7f,0x2b,0xe9,0xa8,0xa0,0x5f,0x60,0x04,0x21,0x00,0x29,0x98,0x74,0x1f,0xa8,0x0a,0x39,0xc0,0x05,0xf5,0x83,0xb0,0xa0,0x00,0x3e,0xaf,0xfc,0x1c,0x19,0x3d,0x01,0xfb,0xaa,0xd3,0x3c,0x0c,0xaa,0x06,0x54,0x19,0x50,0x0c,0xd0,0x32,0xe2,0x05,0xf1,0x00,0x4c,0x20,0x19,0xe0,0xc9,0x7d,0x08,0x33,0xc0,0x04,}; const uint8_t *_I_RFIDDolphinReceive_97x61[] = {_I_RFIDDolphinReceive_97x61_0}; +const uint8_t _I_RFIDBigChip_37x36_0[] = {0x01,0x00,0x6e,0x00,0x83,0x01,0x0f,0xcd,0xff,0x00,0x0c,0x1e,0x24,0x08,0x28,0x47,0x24,0x12,0x51,0x39,0x28,0x24,0xa2,0x91,0x5e,0x07,0xab,0xfe,0x04,0x1c,0x04,0xaa,0x01,0x15,0x02,0x28,0x4c,0x81,0x2c,0x04,0x4e,0x05,0xfc,0x08,0x35,0x59,0x06,0x02,0x81,0x15,0xca,0xe4,0x26,0xf2,0x10,0x70,0xd7,0x66,0x11,0x70,0x70,0xd4,0x20,0x14,0x10,0x70,0xc7,0x68,0x13,0x70,0x70,0xd4,0x28,0x10,0x10,0x4a,0x84,0xc6,0x80,0x13,0x10,0xe8,0xd0,0x03,0xa2,0x27,0x19,0xf0,0x9c,0x46,0x28,0x3b,0x42,0xcf,0x96,0x6a,0xd4,0x13,0x6f,0x2a,0x2c,0xa2,0x90,0x54,0x59,0xfe,0x52,0xa7,0x02,0x4f,0x9f,0xf1,0x52,0x60,}; +const uint8_t *_I_RFIDBigChip_37x36[] = {_I_RFIDBigChip_37x36_0}; + const uint8_t _I_SDQuestion_35x43_0[] = {0x01,0x00,0x67,0x00,0xf8,0x7f,0xc0,0x03,0x03,0xfc,0x01,0x0a,0x0f,0x38,0xa4,0xe4,0xa4,0x80,0x4f,0x0c,0x20,0x13,0xc0,0x9f,0x80,0x02,0x15,0xfe,0x00,0x04,0x29,0xfc,0x03,0xfd,0x07,0xfa,0x47,0xe7,0xdf,0xc8,0x3f,0xea,0x1f,0x7f,0xfc,0x41,0xff,0xb8,0xff,0xf8,0x10,0x7f,0xe0,0x4e,0xef,0x86,0x08,0x68,0x33,0xf1,0x10,0xff,0x3f,0xf1,0xf1,0x60,0x81,0x06,0x1e,0x36,0x10,0x20,0xe1,0xc0,0x87,0xc7,0x02,0x0f,0xd3,0xff,0xe3,0x02,0x0f,0xe8,0x08,0x7f,0xd0,0x21,0x89,0xc4,0x08,0x9f,0x70,0x21,0x9a,0x08,0x08,0xc1,0x89,0x02,0x20,0x62,0x40,0x8f,0xfe,0x68,0x98,}; const uint8_t *_I_SDQuestion_35x43[] = {_I_SDQuestion_35x43_0}; @@ -392,14 +395,8 @@ const uint8_t *_I_SDError_43x35[] = {_I_SDError_43x35_0}; const uint8_t _I_Cry_dolph_55x52_0[] = {0x01,0x00,0xe8,0x00,0x00,0x0f,0xe3,0xff,0x01,0x03,0x1f,0xfb,0xff,0x0f,0x02,0x96,0x02,0x0f,0x00,0x9f,0x01,0x8b,0xc0,0x12,0x1f,0x80,0x18,0xae,0x00,0x21,0xe0,0x07,0x0a,0x30,0x0a,0x28,0x18,0x08,0x61,0x80,0x62,0x83,0x00,0x90,0x14,0x61,0x02,0x0c,0x16,0x00,0x76,0x60,0x66,0x98,0x0b,0x04,0x90,0x60,0x66,0xb0,0x00,0x48,0x0d,0x21,0x21,0x03,0x30,0x74,0x40,0xd3,0x80,0x03,0x34,0x04,0xc0,0x52,0x00,0x32,0xc7,0xa0,0x18,0x80,0x31,0x80,0x07,0xe1,0x01,0x37,0x18,0x50,0x80,0xc2,0x92,0x10,0x31,0xe8,0x23,0xe9,0x63,0x86,0x54,0x3f,0xe0,0xe1,0x0d,0x96,0x83,0xfc,0x06,0x40,0x69,0x6c,0x3c,0x60,0xd2,0xfc,0xc0,0x60,0x58,0x48,0x0c,0x1b,0x81,0x08,0x14,0x9c,0x1a,0x81,0x04,0x03,0x46,0x80,0x0c,0x50,0x26,0x21,0xc1,0x94,0x26,0x14,0x27,0x8a,0x40,0xc0,0xc2,0xe7,0x26,0x40,0x81,0x86,0xc0,0x6b,0x28,0x64,0x0f,0x01,0x10,0x4e,0x14,0x60,0x0c,0x29,0x02,0x48,0x8b,0x5c,0x45,0x22,0x01,0x10,0x31,0x3a,0x4c,0x0c,0x34,0x06,0xf1,0xd8,0x00,0xc5,0x1a,0x64,0x94,0x0c,0xc0,0x37,0x52,0x20,0x81,0x84,0x26,0x3e,0x88,0x0c,0x38,0x28,0x54,0x0e,0xac,0x1f,0xe1,0x3f,0x06,0x96,0x82,0x7e,0x29,0x4a,0xaf,0xfd,0x76,0x30,0x3a,0x41,0x14,0x7f,0xd0,0xf8,0x78,0x18,0xaa,0x9f,0xd4,0xe0,0x83,0x4f,0xf5,0xf7,0x38,0x0b,0x9c,0x6a,0x1f,0x5b,0x5c,0x00,}; const uint8_t *_I_Cry_dolph_55x52[] = {_I_Cry_dolph_55x52_0}; -const uint8_t _I_BadUsb_9x8_0[] = {0x00,0x01,0x01,0xBB,0x01,0xFE,0x00,0xFE,0x00,0xD6,0x00,0xD6,0x00,0x7C,0x00,0x38,0x00,}; -const uint8_t *_I_BadUsb_9x8[] = {_I_BadUsb_9x8_0}; - -const uint8_t _I_PlaceholderR_30x13_0[] = {0x01,0x00,0x19,0x00,0xfe,0x7f,0xff,0xf0,0xf8,0x10,0x18,0x62,0x10,0x10,0x18,0xc8,0x00,0x7e,0x03,0xb8,0x18,0x0c,0x66,0x1f,0xe1,0x58,0xc7,0xc5,0xe6,}; -const uint8_t *_I_PlaceholderR_30x13[] = {_I_PlaceholderR_30x13_0}; - -const uint8_t _I_Background_128x8_0[] = {0x01,0x00,0x43,0x00,0xff,0x7f,0xc0,0x19,0x7f,0x80,0x87,0xb7,0x01,0x3d,0xfd,0xff,0x74,0xff,0xdf,0x7f,0x87,0x87,0xfd,0xfb,0xd3,0xe7,0xf7,0x9d,0xbf,0xff,0x35,0x41,0x09,0x8c,0x20,0x04,0x31,0xc8,0xe0,0x0c,0x62,0x18,0x08,0x10,0x10,0x70,0x99,0xde,0xfe,0xde,0xe7,0xf7,0xff,0x70,0xfc,0x3f,0x6d,0x7f,0x9e,0x6f,0xd9,0xfd,0xd9,0xf3,0x43,0xff,0x2f,0x68,0x00,0x4d,0xfe,}; -const uint8_t *_I_Background_128x8[] = {_I_Background_128x8_0}; +const uint8_t _I_Background_128x11_0[] = {0x01,0x00,0x70,0x00,0xff,0x40,0x40,0xc9,0xe0,0xff,0x80,0x06,0x1e,0x08,0x38,0x0c,0x0c,0x1e,0x93,0x00,0x19,0x46,0x01,0x07,0x7d,0x83,0x03,0xd2,0x31,0xff,0xdb,0xd5,0x66,0x20,0x83,0xc0,0xff,0x05,0x24,0x00,0x1c,0x78,0x28,0xbc,0x40,0x72,0xbf,0xcf,0x47,0xeb,0x40,0xdb,0x7a,0xbf,0xf0,0x40,0x39,0x60,0x28,0x3f,0xe0,0xa0,0xea,0x80,0x63,0x3f,0x0b,0x17,0xe4,0x3e,0x5a,0xbc,0xf9,0x99,0x70,0x1f,0x81,0x50,0xc0,0x80,0xe7,0x3e,0x1e,0x9d,0x57,0xfb,0x7f,0x23,0x15,0xb0,0x12,0x5b,0x5b,0x02,0x1d,0x8c,0xc3,0x80,0x24,0x9e,0x03,0x80,0x5e,0x40,0x00,0xa1,0x88,0x0e,0x98,0x00,0x7b,0x07,0x08,0xb2,0x44,0x41,}; +const uint8_t *_I_Background_128x11[] = {_I_Background_128x11_0}; const uint8_t _I_Lock_8x8_0[] = {0x00,0x3C,0x42,0x42,0xFF,0xFF,0xE7,0xFF,0xFF,}; const uint8_t *_I_Lock_8x8[] = {_I_Lock_8x8_0}; @@ -407,129 +404,136 @@ const uint8_t *_I_Lock_8x8[] = {_I_Lock_8x8_0}; const uint8_t _I_Battery_26x8_0[] = {0x01,0x00,0x13,0x00,0xff,0x7f,0xef,0xf0,0x08,0x0c,0x03,0x00,0x03,0x38,0x18,0x0c,0xa0,0x40,0x36,0x05,0x98,0x6d,0x00,}; const uint8_t *_I_Battery_26x8[] = {_I_Battery_26x8_0}; -const uint8_t _I_PlaceholderL_11x13_0[] = {0x01,0x00,0x10,0x00,0xfe,0x40,0x60,0x50,0x28,0x0c,0x10,0x03,0xb0,0x38,0x37,0xfe,0x07,0xfe,0x80,0x80,}; -const uint8_t *_I_PlaceholderL_11x13[] = {_I_PlaceholderL_11x13_0}; - const uint8_t _I_Battery_19x8_0[] = {0x01,0x00,0x0f,0x00,0xff,0x7f,0xe0,0x30,0x18,0x04,0x08,0x04,0x90,0x60,0x12,0x02,0xcc,0x28,0x40,}; const uint8_t *_I_Battery_19x8[] = {_I_Battery_19x8_0}; -const uint8_t _I_SDcardMounted_11x8_0[] = {0x01,0x00,0x09,0x00,0xff,0xc1,0xff,0xf0,0x40,0x1c,0xd9,0xe0,0x00,}; -const uint8_t *_I_SDcardMounted_11x8[] = {_I_SDcardMounted_11x8_0}; - -const uint8_t _I_SDcardFail_11x8_0[] = {0x00,0xFF,0x07,0xB7,0x07,0xFF,0x07,0x87,0x07,0x7B,0x07,0xFF,0x07,0xFF,0x07,0x67,0x00,}; -const uint8_t *_I_SDcardFail_11x8[] = {_I_SDcardFail_11x8_0}; - const uint8_t _I_USBConnected_15x8_0[] = {0x00,0xF0,0x07,0x08,0x7C,0x04,0x44,0x07,0x54,0x07,0x54,0x04,0x44,0x08,0x7C,0xF0,0x07,}; const uint8_t *_I_USBConnected_15x8[] = {_I_USBConnected_15x8_0}; -const uint8_t _I_Bluetooth_5x8_0[] = {0x00,0x04,0x0D,0x16,0x0C,0x0C,0x16,0x0D,0x04,}; -const uint8_t *_I_Bluetooth_5x8[] = {_I_Bluetooth_5x8_0}; +const uint8_t _I_Background_128x8_0[] = {0x01,0x00,0x43,0x00,0xff,0x7f,0xc0,0x19,0x7f,0x80,0x87,0xb7,0x01,0x3d,0xfd,0xff,0x74,0xff,0xdf,0x7f,0x87,0x87,0xfd,0xfb,0xd3,0xe7,0xf7,0x9d,0xbf,0xff,0x35,0x41,0x09,0x8c,0x20,0x04,0x31,0xc8,0xe0,0x0c,0x62,0x18,0x08,0x10,0x10,0x70,0x99,0xde,0xfe,0xde,0xe7,0xf7,0xff,0x70,0xfc,0x3f,0x6d,0x7f,0x9e,0x6f,0xd9,0xfd,0xd9,0xf3,0x43,0xff,0x2f,0x68,0x00,0x4d,0xfe,}; +const uint8_t *_I_Background_128x8[] = {_I_Background_128x8_0}; + +const uint8_t _I_BadUsb_9x8_0[] = {0x00,0x01,0x01,0xBB,0x01,0xFE,0x00,0xFE,0x00,0xD6,0x00,0xD6,0x00,0x7C,0x00,0x38,0x00,}; +const uint8_t *_I_BadUsb_9x8[] = {_I_BadUsb_9x8_0}; const uint8_t _I_BT_Pair_9x8_0[] = {0x00,0x11,0x01,0x35,0x00,0x58,0x01,0x31,0x00,0x30,0x01,0x59,0x00,0x34,0x01,0x11,0x01,}; const uint8_t *_I_BT_Pair_9x8[] = {_I_BT_Pair_9x8_0}; -const uint8_t _I_Background_128x11_0[] = {0x01,0x00,0x70,0x00,0xff,0x40,0x40,0xc9,0xe0,0xff,0x80,0x06,0x1e,0x08,0x38,0x0c,0x0c,0x1e,0x93,0x00,0x19,0x46,0x01,0x07,0x7d,0x83,0x03,0xd2,0x31,0xff,0xdb,0xd5,0x66,0x20,0x83,0xc0,0xff,0x05,0x24,0x00,0x1c,0x78,0x28,0xbc,0x40,0x72,0xbf,0xcf,0x47,0xeb,0x40,0xdb,0x7a,0xbf,0xf0,0x40,0x39,0x60,0x28,0x3f,0xe0,0xa0,0xea,0x80,0x63,0x3f,0x0b,0x17,0xe4,0x3e,0x5a,0xbc,0xf9,0x99,0x70,0x1f,0x81,0x50,0xc0,0x80,0xe7,0x3e,0x1e,0x9d,0x57,0xfb,0x7f,0x23,0x15,0xb0,0x12,0x5b,0x5b,0x02,0x1d,0x8c,0xc3,0x80,0x24,0x9e,0x03,0x80,0x5e,0x40,0x00,0xa1,0x88,0x0e,0x98,0x00,0x7b,0x07,0x08,0xb2,0x44,0x41,}; -const uint8_t *_I_Background_128x11[] = {_I_Background_128x11_0}; +const uint8_t _I_PlaceholderL_11x13_0[] = {0x01,0x00,0x10,0x00,0xfe,0x40,0x60,0x50,0x28,0x0c,0x10,0x03,0xb0,0x38,0x37,0xfe,0x07,0xfe,0x80,0x80,}; +const uint8_t *_I_PlaceholderL_11x13[] = {_I_PlaceholderL_11x13_0}; -const uint8_t _I_Scanning_123x52_0[] = {0x01,0x00,0xd3,0x01,0x00,0x78,0x03,0xc0,0x1f,0x00,0xe0,0x7f,0xc1,0xfb,0xf0,0x80,0x41,0xc0,0xc7,0x03,0x07,0xbe,0xb2,0x07,0x18,0x07,0xc4,0x40,0x06,0x55,0x68,0x2d,0x80,0x0a,0x58,0x08,0x10,0x3c,0xe1,0x00,0x32,0xc0,0xc2,0xb0,0x00,0xf8,0x82,0x02,0x0a,0x01,0x15,0x80,0x40,0x40,0xc3,0x40,0x07,0xa0,0x10,0xa8,0x10,0x09,0xc0,0x19,0x01,0xe9,0x82,0x01,0x0c,0x82,0x01,0x74,0x13,0x1d,0x03,0x04,0x24,0x28,0x05,0x04,0x1e,0x76,0x80,0x79,0xc8,0x30,0x50,0x28,0x30,0x14,0x64,0x26,0x23,0xe8,0x78,0x21,0xe0,0xf4,0x85,0x43,0x30,0x12,0x03,0x00,0x83,0xc7,0x41,0x1c,0x3b,0x10,0x3c,0xe2,0x98,0x08,0x80,0xa4,0x61,0x1e,0x0e,0x9c,0x0c,0x1e,0x51,0x00,0x7a,0x95,0x46,0x11,0x90,0xd3,0xd0,0x24,0x80,0xfb,0xe4,0x5f,0xf0,0x92,0x80,0x79,0x61,0x01,0xe3,0xff,0x07,0x9e,0x22,0xcf,0x3e,0xc4,0x03,0xd3,0xf5,0xff,0x07,0xa5,0x12,0xc9,0x2e,0x07,0xa7,0xf3,0x5f,0xff,0x8a,0x93,0xce,0x89,0xe4,0x97,0xe2,0x25,0x40,0xf1,0x8c,0x75,0x3b,0xf1,0xf1,0xf8,0x9b,0xc8,0x1e,0x55,0x0f,0xfc,0x03,0xfd,0x1f,0xf6,0x4f,0xc9,0xe2,0x8f,0x3a,0x27,0x12,0x5f,0xea,0x68,0x0c,0x06,0x35,0xfc,0x2f,0x92,0xbc,0xf0,0x98,0x89,0x7c,0x75,0x8e,0x37,0xd8,0xf1,0x7c,0xa3,0x0c,0xf3,0xc3,0x47,0xf8,0xcb,0x81,0xc2,0x5f,0x62,0xc0,0xf2,0x77,0xa5,0x1b,0xeb,0xc3,0x6c,0x8d,0x12,0x03,0x22,0x07,0x8c,0x30,0x18,0x2d,0x82,0xc3,0xc2,0xaf,0x84,0x42,0x81,0xc8,0xb1,0x01,0xb2,0x4e,0x08,0x08,0x68,0xb0,0x50,0x20,0xdf,0xb4,0x90,0x3a,0x10,0x3d,0x19,0x05,0x86,0x1e,0x8f,0x03,0x03,0xa5,0x83,0xd0,0xa1,0x10,0x30,0x79,0x00,0x0a,0x0a,0x02,0x19,0x84,0x03,0xa5,0xff,0xc0,0x8a,0x88,0x00,0x81,0xe1,0x80,0x12,0x07,0xa5,0x1f,0xc0,0x03,0xde,0x0b,0x80,0x80,0x0a,0x47,0xa3,0x1f,0x80,0x42,0x43,0xf1,0xe1,0x80,0x60,0x3d,0x30,0xf8,0x04,0x48,0x3e,0xf0,0x08,0xf1,0x40,0x7d,0x00,0xf1,0x56,0x08,0xfe,0x20,0x17,0x0f,0x70,0x3c,0x55,0x82,0x00,0x58,0x38,0x0c,0xa7,0x9f,0x90,0x78,0x80,0x1c,0xec,0x5a,0xac,0xff,0xc0,0x1f,0x30,0x1a,0x05,0x57,0xfb,0x5f,0xf8,0x45,0xc3,0xf3,0x80,0xf5,0x7f,0xe7,0xfe,0x00,0x7c,0x87,0xc7,0xab,0xff,0x8f,0x83,0xea,0x05,0x80,0xd5,0x7f,0xe1,0xfe,0x08,0x98,0x7e,0x60,0x15,0x5a,0xac,0x0f,0xe1,0x15,0x0f,0xc9,0x78,0x75,0x50,0x0d,0x84,0x28,0x3f,0x55,0x4b,0xac,0x02,0xb1,0x0d,0x0f,0xd6,0xa0,0xf8,0x3a,0x85,0x29,0xaf,0xde,0xf8,0x04,0x1a,0xe2,0x54,0x83,0xf0,0x00,0x2d,0x70,0xd4,0x43,0xf2,0x00,0x2e,0xb8,0x3a,0x20,0x05,0x93,0xc0,0x5e,0xc1,0xf2,0x79,0x3e,0x04,0x7c,0x1f,0x32,0xa0,0x19,0x7c,0x1e,0x86,0x00,0x6a,0xa8,0x0c,0xbf,0x84,0xe9,0x4e,0x88,0x0c,0x85,0xd5,0x00,}; -const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; +const uint8_t _I_SDcardFail_11x8_0[] = {0x00,0xFF,0x07,0xB7,0x07,0xFF,0x07,0x87,0x07,0x7B,0x07,0xFF,0x07,0xFF,0x07,0x67,0x00,}; +const uint8_t *_I_SDcardFail_11x8[] = {_I_SDcardFail_11x8_0}; + +const uint8_t _I_Bluetooth_5x8_0[] = {0x00,0x04,0x0D,0x16,0x0C,0x0C,0x16,0x0D,0x04,}; +const uint8_t *_I_Bluetooth_5x8[] = {_I_Bluetooth_5x8_0}; + +const uint8_t _I_PlaceholderR_30x13_0[] = {0x01,0x00,0x19,0x00,0xfe,0x7f,0xff,0xf0,0xf8,0x10,0x18,0x62,0x10,0x10,0x18,0xc8,0x00,0x7e,0x03,0xb8,0x18,0x0c,0x66,0x1f,0xe1,0x58,0xc7,0xc5,0xe6,}; +const uint8_t *_I_PlaceholderR_30x13[] = {_I_PlaceholderR_30x13_0}; + +const uint8_t _I_SDcardMounted_11x8_0[] = {0x01,0x00,0x09,0x00,0xff,0xc1,0xff,0xf0,0x40,0x1c,0xd9,0xe0,0x00,}; +const uint8_t *_I_SDcardMounted_11x8[] = {_I_SDcardMounted_11x8_0}; const uint8_t _I_Quest_7x8_0[] = {0x00,0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0}; -const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; -const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0}; +const uint8_t _I_Lock_7x8_0[] = {0x00,0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; +const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0}; + +const uint8_t _I_Scanning_123x52_0[] = {0x01,0x00,0xd3,0x01,0x00,0x78,0x03,0xc0,0x1f,0x00,0xe0,0x7f,0xc1,0xfb,0xf0,0x80,0x41,0xc0,0xc7,0x03,0x07,0xbe,0xb2,0x07,0x18,0x07,0xc4,0x40,0x06,0x55,0x68,0x2d,0x80,0x0a,0x58,0x08,0x10,0x3c,0xe1,0x00,0x32,0xc0,0xc2,0xb0,0x00,0xf8,0x82,0x02,0x0a,0x01,0x15,0x80,0x40,0x40,0xc3,0x40,0x07,0xa0,0x10,0xa8,0x10,0x09,0xc0,0x19,0x01,0xe9,0x82,0x01,0x0c,0x82,0x01,0x74,0x13,0x1d,0x03,0x04,0x24,0x28,0x05,0x04,0x1e,0x76,0x80,0x79,0xc8,0x30,0x50,0x28,0x30,0x14,0x64,0x26,0x23,0xe8,0x78,0x21,0xe0,0xf4,0x85,0x43,0x30,0x12,0x03,0x00,0x83,0xc7,0x41,0x1c,0x3b,0x10,0x3c,0xe2,0x98,0x08,0x80,0xa4,0x61,0x1e,0x0e,0x9c,0x0c,0x1e,0x51,0x00,0x7a,0x95,0x46,0x11,0x90,0xd3,0xd0,0x24,0x80,0xfb,0xe4,0x5f,0xf0,0x92,0x80,0x79,0x61,0x01,0xe3,0xff,0x07,0x9e,0x22,0xcf,0x3e,0xc4,0x03,0xd3,0xf5,0xff,0x07,0xa5,0x12,0xc9,0x2e,0x07,0xa7,0xf3,0x5f,0xff,0x8a,0x93,0xce,0x89,0xe4,0x97,0xe2,0x25,0x40,0xf1,0x8c,0x75,0x3b,0xf1,0xf1,0xf8,0x9b,0xc8,0x1e,0x55,0x0f,0xfc,0x03,0xfd,0x1f,0xf6,0x4f,0xc9,0xe2,0x8f,0x3a,0x27,0x12,0x5f,0xea,0x68,0x0c,0x06,0x35,0xfc,0x2f,0x92,0xbc,0xf0,0x98,0x89,0x7c,0x75,0x8e,0x37,0xd8,0xf1,0x7c,0xa3,0x0c,0xf3,0xc3,0x47,0xf8,0xcb,0x81,0xc2,0x5f,0x62,0xc0,0xf2,0x77,0xa5,0x1b,0xeb,0xc3,0x6c,0x8d,0x12,0x03,0x22,0x07,0x8c,0x30,0x18,0x2d,0x82,0xc3,0xc2,0xaf,0x84,0x42,0x81,0xc8,0xb1,0x01,0xb2,0x4e,0x08,0x08,0x68,0xb0,0x50,0x20,0xdf,0xb4,0x90,0x3a,0x10,0x3d,0x19,0x05,0x86,0x1e,0x8f,0x03,0x03,0xa5,0x83,0xd0,0xa1,0x10,0x30,0x79,0x00,0x0a,0x0a,0x02,0x19,0x84,0x03,0xa5,0xff,0xc0,0x8a,0x88,0x00,0x81,0xe1,0x80,0x12,0x07,0xa5,0x1f,0xc0,0x03,0xde,0x0b,0x80,0x80,0x0a,0x47,0xa3,0x1f,0x80,0x42,0x43,0xf1,0xe1,0x80,0x60,0x3d,0x30,0xf8,0x04,0x48,0x3e,0xf0,0x08,0xf1,0x40,0x7d,0x00,0xf1,0x56,0x08,0xfe,0x20,0x17,0x0f,0x70,0x3c,0x55,0x82,0x00,0x58,0x38,0x0c,0xa7,0x9f,0x90,0x78,0x80,0x1c,0xec,0x5a,0xac,0xff,0xc0,0x1f,0x30,0x1a,0x05,0x57,0xfb,0x5f,0xf8,0x45,0xc3,0xf3,0x80,0xf5,0x7f,0xe7,0xfe,0x00,0x7c,0x87,0xc7,0xab,0xff,0x8f,0x83,0xea,0x05,0x80,0xd5,0x7f,0xe1,0xfe,0x08,0x98,0x7e,0x60,0x15,0x5a,0xac,0x0f,0xe1,0x15,0x0f,0xc9,0x78,0x75,0x50,0x0d,0x84,0x28,0x3f,0x55,0x4b,0xac,0x02,0xb1,0x0d,0x0f,0xd6,0xa0,0xf8,0x3a,0x85,0x29,0xaf,0xde,0xf8,0x04,0x1a,0xe2,0x54,0x83,0xf0,0x00,0x2d,0x70,0xd4,0x43,0xf2,0x00,0x2e,0xb8,0x3a,0x20,0x05,0x93,0xc0,0x5e,0xc1,0xf2,0x79,0x3e,0x04,0x7c,0x1f,0x32,0xa0,0x19,0x7c,0x1e,0x86,0x00,0x6a,0xa8,0x0c,0xbf,0x84,0xe9,0x4e,0x88,0x0c,0x85,0xd5,0x00,}; +const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; const uint8_t _I_MHz_25x11_0[] = {0x01,0x00,0x21,0x00,0xe1,0xe1,0xa0,0x30,0x0f,0x38,0x0c,0xbf,0xe0,0x34,0xfe,0xc0,0x7b,0x7f,0xe0,0x19,0xf0,0x60,0x1d,0xbc,0x35,0x84,0x36,0x53,0x10,0x19,0x46,0x40,0x64,0x13,0x10,0x19,0x80,}; const uint8_t *_I_MHz_25x11[] = {_I_MHz_25x11_0}; -const uint8_t _I_Lock_7x8_0[] = {0x00,0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; -const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0}; - -const uint8_t _I_DolphinMafia_115x62_0[] = {0x01,0x00,0x21,0x02,0x00,0x1e,0x02,0x06,0x0e,0xcb,0x04,0x10,0x1d,0x91,0x88,0x40,0x3b,0x20,0xc0,0xec,0xc0,0x40,0x62,0x03,0xac,0x80,0x03,0xb2,0x31,0x00,0x90,0x03,0xae,0x5e,0x0e,0xcf,0xc4,0x56,0x01,0x40,0x07,0x56,0xbe,0x14,0x0e,0x2f,0xf1,0x5e,0x2a,0xa1,0xd1,0xc0,0x7c,0x3f,0xf0,0x70,0x73,0x70,0x35,0x41,0xd1,0xc0,0x7f,0xff,0xf0,0xf0,0x73,0x50,0x03,0xa4,0x0d,0x10,0x74,0x07,0x46,0x55,0xe0,0x07,0x10,0xb1,0xc3,0xa3,0x55,0xfe,0x03,0x88,0x94,0xe1,0xd1,0xd5,0x03,0x4a,0x3e,0x59,0x9e,0xaf,0xfe,0xff,0x05,0x60,0x4e,0xab,0xf5,0xff,0x95,0xb4,0xa4,0x3a,0x3f,0xd0,0xe0,0xfa,0x20,0x20,0xf8,0xd5,0xff,0xb5,0xf0,0x0f,0x88,0x3a,0x6a,0xbf,0xf8,0xaf,0x82,0x6f,0x03,0x07,0x47,0xaf,0xff,0x0a,0xfe,0x5f,0xc1,0xd3,0xf6,0xbf,0xe0,0x7f,0xfe,0xf0,0x73,0x41,0x00,0x43,0xfa,0xd7,0xf8,0x27,0xfe,0xe0,0x73,0x40,0x80,0x43,0xfe,0xab,0xfe,0x21,0xfc,0xe5,0x9b,0x05,0x48,0xea,0x3f,0xc8,0xfa,0xc4,0x66,0x07,0x44,0x0e,0x8f,0x00,0xb0,0x2b,0x31,0x07,0x0f,0x00,0x1c,0x72,0x00,0x70,0xf8,0x37,0xe5,0x81,0xff,0x89,0x08,0xf2,0x71,0x80,0x20,0xfe,0x2b,0xf0,0x5f,0xc0,0x38,0xc8,0xa5,0x60,0xc3,0x00,0xc7,0xf9,0xaf,0x81,0x2d,0x04,0x34,0x40,0xe1,0x98,0x47,0x68,0x04,0x92,0xab,0xc0,0x7e,0xb7,0xf7,0x39,0x03,0x85,0x8e,0x24,0xf1,0xc0,0x7f,0xf5,0x78,0x0f,0x53,0xb4,0xbc,0x1f,0xb8,0x1a,0x0c,0x61,0xc5,0x82,0xab,0xc0,0x3e,0xa3,0xa2,0xfc,0x07,0x46,0x09,0x60,0x19,0x8f,0x80,0xec,0x38,0x08,0x52,0x6c,0xb8,0xdc,0x28,0x7c,0x10,0x2a,0x5f,0x0f,0xfc,0x5a,0x01,0x05,0x1a,0x8e,0x02,0x02,0x1d,0x1f,0x81,0xa8,0xbe,0x13,0xf8,0x52,0x2c,0x8c,0x62,0x77,0x42,0x11,0x40,0xe0,0xca,0x93,0x8e,0x03,0x8a,0x30,0x10,0x48,0x54,0x03,0x04,0xbb,0x2c,0x00,0x0c,0x64,0x80,0xe4,0x0e,0x88,0x38,0x7c,0x10,0x04,0x09,0x48,0x83,0xac,0x1b,0x18,0xf3,0x44,0xc1,0xca,0x1d,0x15,0x40,0x8e,0x05,0x02,0x20,0xe6,0x24,0x12,0x8c,0x8b,0x05,0x21,0x07,0x24,0x14,0x08,0x73,0x80,0x19,0x78,0x43,0xb2,0xff,0x15,0x30,0xc4,0x01,0x26,0x8f,0x14,0x61,0xa9,0x8a,0x09,0x10,0x02,0x12,0x1c,0x80,0x84,0xaf,0x10,0x71,0xaa,0xc4,0x00,0x3b,0x04,0xea,0x24,0x48,0x1c,0xbd,0x8f,0xf8,0x00,0x67,0xf0,0x09,0x40,0x20,0x61,0x00,0xe4,0xf6,0x07,0x4b,0xc1,0x1f,0x07,0x14,0x40,0x1c,0x9d,0x66,0x79,0x24,0xc6,0xa0,0x0e,0x32,0x51,0xfa,0xce,0xe7,0x50,0x07,0x1c,0x80,0x30,0x58,0x0e,0xa2,0xcc,0xa0,0x19,0x00,0x71,0x42,0x13,0x27,0x40,0xf5,0x45,0x41,0xc5,0x08,0xb0,0x80,0xc6,0x18,0xf2,0x28,0x04,0x83,0xe8,0x58,0x10,0x30,0xc2,0x2c,0x40,0x91,0x89,0x3c,0x88,0x62,0x21,0xd2,0xff,0x03,0x87,0xc8,0x12,0x19,0x08,0x39,0x3e,0x83,0xb2,0x4a,0x0e,0xa2,0x0d,0xc0,0xe0,0x50,0x06,0xa7,0xe8,0x2c,0x94,0xc2,0x09,0x50,0x8c,0xce,0x20,0x34,0x70,0x71,0x41,0x3e,0x85,0xe2,0xe0,0x41,0x38,0x1e,0x28,0x3c,0x19,0xc8,0x70,0x4f,0xc1,0xdc,0xe0,0x74,0x01,0xd8,0xc6,0x24,0x00,0x82,0x81,0x7c,0x12,0xa6,0x7e,0x10,0x28,0xd8,0x22,0x00,0xe3,0xfc,0x34,0x53,0x00,0x23,0x1c,0x04,0x44,0x0e,0x50,0x10,0xeb,0x17,0xca,0x1c,0x07,0x20,}; -const uint8_t *_I_DolphinMafia_115x62[] = {_I_DolphinMafia_115x62_0}; - -const uint8_t _I_DolphinExcited_64x63_0[] = {0x01,0x00,0x36,0x01,0x00,0x25,0x00,0x0f,0xd2,0x00,0x3b,0xe0,0x00,0xeb,0x10,0x0c,0x34,0x40,0x30,0xd0,0x88,0x80,0x1d,0xa1,0x00,0x42,0xfc,0x7f,0xc0,0x63,0x04,0x01,0x0e,0x02,0x0f,0x00,0x00,0x8c,0x08,0x0e,0x37,0x00,0x10,0xc6,0x20,0x10,0x10,0xd9,0x11,0x92,0x1c,0x1a,0x3e,0x00,0x04,0x42,0x02,0x1a,0x20,0xb0,0xce,0x00,0x64,0x07,0x20,0x59,0x16,0x50,0x36,0x45,0x94,0x84,0x78,0x20,0x60,0x75,0x8e,0x43,0x06,0x63,0x3c,0x33,0x94,0x0c,0xd2,0x5c,0x30,0x38,0xe4,0x08,0x43,0x10,0xc0,0x5e,0x06,0x22,0x53,0x1a,0x02,0x08,0x7f,0xd0,0x32,0xc1,0x50,0x21,0x14,0x0e,0x70,0x1c,0x46,0xe2,0x07,0x19,0x06,0x3c,0xdc,0x20,0x91,0xae,0x01,0xcc,0xbe,0x30,0x09,0xfc,0x12,0x41,0xff,0x83,0xcc,0x0a,0xa3,0x1f,0x03,0x99,0xe8,0x7c,0x10,0xf8,0x25,0xa0,0x5e,0x50,0x0f,0x84,0x1e,0x09,0x54,0x03,0x9f,0xf2,0x07,0x02,0xd5,0x11,0xca,0x01,0xfe,0x80,0xc0,0xaa,0x9f,0xf0,0x39,0x5f,0xd0,0x43,0xaa,0x83,0x41,0x92,0xc3,0x1f,0x03,0x8d,0x52,0x02,0x2e,0x25,0xc9,0x6a,0x99,0x46,0xa6,0x2a,0xa0,0x1c,0xaf,0xca,0x62,0x94,0x28,0xcb,0x7e,0x0f,0x15,0x71,0xf8,0x3c,0x22,0x71,0x03,0x8a,0x84,0x67,0x18,0x0f,0xac,0x1c,0x0e,0x38,0x08,0x0c,0x3e,0x01,0xae,0xbd,0x13,0x0c,0x0e,0x35,0x8e,0xa8,0x1c,0xb0,0x1f,0xf8,0x06,0x83,0xf4,0x27,0x38,0x07,0xff,0xff,0x8f,0x03,0xa0,0x4c,0x80,0xed,0x60,0x03,0xb4,0x60,0x0e,0xd0,0x60,0x3a,0x87,0x84,0x0e,0xb7,0xc2,0xfa,0x18,0x05,0x44,0x20,0x73,0xff,0xf7,0xce,0xe4,0x07,0x2d,0x52,0x2c,0x80,0xe7,0x54,0xea,0x81,0xd7,0x50,0x0f,0x7a,0xaa,0x3d,0x41,0xe2,0x07,0x5a,0x80,0x3c,0xa0,0x40,0x72,0xd0,0x6a,0x80,0xa2,0x07,0x3a,0x05,0x54,0x8e,0x20,0x73,0xc0,0x03,0xd8,0x60,0x30,0x40,0x3a,0xc0,0x00,0xee,0xea,0x10,0x3b,0x80,}; -const uint8_t *_I_DolphinExcited_64x63[] = {_I_DolphinExcited_64x63_0}; - -const uint8_t _I_iButtonDolphinSuccess_109x60_0[] = {0x01,0x00,0xac,0x01,0x00,0x17,0xfe,0x1e,0x0c,0xaf,0x04,0x02,0xe0,0x0d,0xa8,0xf4,0x03,0x01,0x03,0x06,0x46,0x02,0x02,0x03,0x18,0xe0,0x36,0x2c,0x00,0x36,0x00,0x2c,0x40,0x3e,0x60,0xd8,0x84,0x01,0x0c,0x5a,0x40,0x05,0x82,0x01,0x0e,0x04,0x0d,0x70,0x42,0x04,0x90,0x49,0x02,0xe4,0x20,0x41,0x28,0xc0,0x07,0x40,0x06,0xf8,0x00,0xa4,0x00,0xd6,0x03,0xa8,0x37,0x44,0x2a,0x31,0x74,0xd3,0x83,0x57,0x80,0x0d,0xc7,0x18,0xa9,0xa8,0x36,0x2a,0x86,0x06,0x8d,0xfc,0x36,0x60,0xd7,0xc0,0x3b,0x8c,0x36,0xf0,0x4a,0x05,0xf9,0x6e,0x5e,0x06,0x23,0x41,0x24,0x1f,0xf6,0x01,0x74,0x01,0xb1,0xe3,0x82,0x81,0x47,0x40,0x0d,0x7c,0x87,0x8e,0x12,0x05,0x1a,0x84,0x0d,0xb6,0xa0,0xd2,0x85,0x86,0xc8,0x1a,0x50,0x40,0x69,0x40,0xb2,0x1f,0xf0,0x69,0x50,0x01,0xa5,0x08,0xfc,0x03,0x5f,0x60,0x0d,0x28,0x84,0x1a,0x07,0x18,0x06,0xaf,0x00,0x1a,0x3c,0x03,0xb8,0xc3,0x20,0xd0,0x28,0x87,0xfc,0x8a,0x50,0x08,0x78,0x08,0x70,0x77,0x0c,0x44,0x06,0x05,0x30,0xff,0x18,0x4a,0x01,0x30,0x01,0x0d,0x33,0x19,0x11,0x1b,0x8c,0xa2,0xf8,0x7d,0x27,0x71,0xd0,0x20,0x51,0x20,0x68,0xd5,0x00,0x42,0x0d,0x2c,0x00,0x08,0x64,0x10,0x19,0x20,0x28,0x75,0x07,0x53,0x3d,0x18,0x35,0x2a,0x9f,0xf4,0x9a,0x41,0x90,0x23,0x00,0x94,0x43,0xe0,0x5e,0xae,0x03,0x9d,0xb4,0xe0,0xd1,0x0d,0x8c,0xd0,0x52,0xb1,0x00,0xd9,0x83,0x46,0x34,0x45,0x41,0xa8,0x9f,0x86,0x01,0x14,0x05,0x08,0x08,0x81,0xa6,0x62,0x10,0x68,0xe5,0x20,0x70,0x41,0x80,0x80,0x10,0xc4,0x34,0x48,0x04,0x2a,0x38,0x0d,0x99,0x16,0x02,0x1a,0xd5,0x10,0x6c,0x5e,0x2e,0x0b,0xa1,0x4b,0x0a,0x60,0xc1,0xa7,0x84,0xfc,0x58,0x01,0xb5,0x02,0x82,0xb4,0xc4,0x16,0x22,0xa5,0x06,0x96,0x19,0x20,0x20,0xd7,0x30,0x8c,0x0f,0x08,0x05,0x10,0x68,0xa1,0x44,0x1a,0x98,0x08,0x14,0x11,0x28,0x21,0x91,0x1d,0x8f,0x83,0xfe,0x07,0x1b,0x00,0x34,0x61,0x00,0xd3,0x1d,0x8c,0x7a,0x01,0x7e,0x80,0x56,0x30,0x06,0xb1,0x4a,0x08,0xd4,0xbf,0xc1,0x31,0xc0,0x7f,0xe8,0xf0,0x08,0x3c,0x40,0x1a,0x80,0x04,0x5a,0x8c,0x10,0x80,0x40,0xd7,0x05,0x08,0x36,0xc0,0xe2,0x0d,0xb8,0x30,0x34,0x45,0x82,0x0d,0x72,0x49,0x03,0x5a,0x41,0x55,0xf8,0x7f,0xff,0xe8,0x72,0x06,0xae,0x03,0xf4,0x0c,0x1d,0xf8,0x18,0x60,0x40,0xd2,0x4b,0x9f,0xd0,0x1a,0x35,0x71,0x48,0xc0,0x95,0x42,0x0d,0x4d,0x50,0x70,0x75,0x40,0xd1,0x80,0x83,0x5a,0xa1,0x55,0x00,0x0c,0x05,0xa4,0x20,0xd2,}; -const uint8_t *_I_iButtonDolphinSuccess_109x60[] = {_I_iButtonDolphinSuccess_109x60_0}; - -const uint8_t _I_iButtonDolphinVerySuccess_108x52_0[] = {0x01,0x00,0xc2,0x01,0x00,0x0f,0xe2,0xfe,0x0d,0xb8,0x3e,0x02,0x06,0x0c,0x9f,0x00,0x08,0x61,0x80,0xd9,0x8c,0x00,0x86,0x60,0x0d,0x98,0x30,0x08,0x6a,0x00,0xd9,0x80,0x80,0x87,0x40,0x0c,0x8c,0x00,0x0c,0xa8,0x01,0x12,0x00,0x2d,0x00,0x22,0x70,0x20,0x6b,0xc8,0x02,0x26,0x62,0x88,0x80,0x6c,0xc9,0x24,0x0d,0x9a,0x07,0x17,0xfe,0x1d,0x68,0x40,0x6c,0xe7,0x48,0x04,0x28,0x10,0x34,0xe8,0x10,0xd1,0x11,0xc4,0x01,0xa5,0x04,0x06,0x96,0xa0,0xa6,0x24,0xc2,0x88,0x17,0x88,0x1a,0x7d,0x43,0x78,0x82,0x4a,0x40,0x03,0x20,0xb0,0xff,0x20,0x16,0xa3,0xb2,0x48,0x03,0xe4,0x0d,0x1f,0xfc,0x06,0x3a,0x0d,0x4a,0x00,0x34,0xf8,0x00,0xd1,0x37,0x0f,0x82,0x9e,0x95,0x58,0x17,0x83,0xff,0x81,0x1b,0x0f,0xf1,0xfe,0x71,0xe0,0x69,0x7c,0x3f,0xe0,0x82,0xff,0xcf,0xc0,0x85,0x61,0x80,0x43,0xb0,0x5f,0xa8,0x79,0xdc,0x81,0xa5,0x70,0xc0,0x68,0x3c,0x10,0x1a,0x17,0xd5,0x28,0x42,0xd1,0x8f,0x84,0x46,0x83,0xb0,0x8e,0x40,0x34,0x5f,0xa8,0x38,0x34,0x45,0xa2,0x0d,0x18,0x04,0x9b,0x50,0x03,0x1a,0x14,0x35,0x36,0x5f,0x8f,0xf8,0xb8,0xa4,0x19,0x40,0x18,0xe8,0xa0,0xca,0x22,0xfe,0x7f,0xc4,0x05,0x20,0xa5,0x80,0xc6,0x82,0xcb,0x3f,0xf3,0x44,0xfc,0x12,0x40,0x18,0xe8,0x51,0x82,0x52,0x28,0xfc,0x38,0x0a,0x3e,0x48,0x98,0x6c,0x8f,0x43,0x00,0xe0,0x63,0xe0,0x62,0xe2,0x91,0x90,0x0a,0x02,0x0d,0x2f,0x82,0x50,0x41,0xa3,0x80,0x90,0x41,0x04,0xc3,0x01,0xc0,0x83,0x46,0x71,0x30,0x06,0x95,0x82,0x21,0x02,0x6e,0x88,0x6c,0x43,0x83,0x1f,0x2f,0x88,0x34,0x62,0x00,0xd1,0x15,0x08,0x2c,0x60,0xcc,0x51,0x0f,0x08,0xcc,0x81,0xa2,0x12,0x10,0x68,0xc6,0x3f,0x06,0xc2,0x06,0x8e,0x02,0x16,0x41,0x20,0x10,0xf8,0x01,0x85,0x00,0x19,0x0d,0x82,0x18,0x07,0x20,0x81,0x00,0x0c,0x9c,0x31,0x08,0x42,0x74,0x81,0xab,0x80,0x03,0x0c,0x32,0x11,0x0b,0x06,0xb9,0xc0,0x43,0xa3,0x10,0x8b,0x83,0x5c,0xe0,0x20,0x81,0xc8,0x26,0x49,0x4c,0x40,0x02,0x86,0x0a,0xc5,0x22,0x32,0x50,0x6b,0x93,0x86,0xc0,0x0d,0x19,0x18,0x35,0x8c,0x84,0x79,0x1a,0x84,0x84,0x1a,0xdf,0xc2,0xe0,0x8a,0xc7,0x51,0x22,0x06,0xb5,0x5e,0x3f,0x00,0x77,0x0d,0x60,0x36,0xfa,0xa9,0xd7,0x00,0x08,0x3a,0xc9,0x02,0x48,0xc0,0x05,0x54,0xba,0x98,0x8a,0xa8,0xf1,0x20,0x6a,0x6a,0x3d,0x43,0x61,0x80,0x4a,0x81,0xaf,0x40,0xea,0x8d,0x86,0x01,0x56,0x06,0x93,0x60,0x80,0x05,0xea,0x01,0x94,0xac,0x1b,0x11,0x80,0x19,0x45,0x41,0x44,0x0d,0x58,0x33,0x18,0xa1,0x4f,0xf3,0x06,0x1f,0x01,0x76,0x58,0x00,0xd9,0x83,0x52,0x7c,0x11,0x38,0x51,0x40,0x80,}; -const uint8_t *_I_iButtonDolphinVerySuccess_108x52[] = {_I_iButtonDolphinVerySuccess_108x52_0}; +const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; +const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0}; const uint8_t _I_iButtonKey_49x44_0[] = {0x01,0x00,0xb4,0x00,0x00,0x24,0xfc,0x0a,0x9c,0x0e,0x00,0x19,0x26,0x18,0x00,0x32,0x43,0x20,0x10,0x10,0x31,0xc0,0x80,0xc9,0x80,0x02,0x08,0x18,0xec,0x00,0x21,0x03,0x1c,0x40,0x1e,0x22,0x15,0xa0,0x08,0x56,0x40,0x06,0x30,0xc0,0x85,0x84,0x86,0x40,0x21,0x84,0x10,0xcc,0x04,0x30,0x40,0x31,0x02,0x88,0x3a,0x20,0x01,0x83,0x0d,0x94,0x06,0x26,0x03,0xf8,0x43,0xc5,0xe9,0x0c,0x11,0x08,0xbc,0xe0,0x64,0x21,0x23,0x09,0x38,0x80,0x22,0x28,0x20,0x58,0x99,0xc4,0x50,0x41,0xe1,0xc0,0x60,0xcc,0xab,0x47,0x21,0xa6,0x02,0x9e,0x06,0x22,0x70,0xf0,0x00,0xcb,0x40,0x03,0x18,0xb0,0x78,0x14,0xe0,0x32,0x58,0x28,0xa5,0x84,0xd0,0x51,0x80,0xc9,0x30,0x06,0xae,0x62,0x84,0x06,0x48,0x64,0x88,0x0c,0x90,0x29,0x08,0x19,0x30,0x31,0x13,0x71,0xb8,0xc4,0xea,0x70,0x6b,0xc5,0x01,0x4a,0x7f,0xc8,0x7c,0x81,0x4a,0x77,0x8a,0xac,0x45,0x4a,0x7f,0x08,0x54,0x39,0x4a,0x7e,0x0e,0xa9,0xf0,0xcb,0xe3,0x7f,0x6e,0x22,0x5c,0x59,0x44,0x00,0x28,0x7a,0xd4,0x40,0x07,0xf0,0x02,0xa0,}; const uint8_t *_I_iButtonKey_49x44[] = {_I_iButtonKey_49x44_0}; -const uint8_t _I_DolphinNice_96x59_0[] = {0x01,0x00,0x8a,0x01,0x00,0x37,0xfa,0x3e,0x0a,0x8f,0x04,0x04,0x02,0x20,0xb7,0x8c,0x00,0x86,0x1c,0x0b,0x78,0x20,0x08,0x66,0x00,0xb7,0x81,0x00,0x86,0x80,0x0b,0x71,0x61,0x60,0x01,0x4c,0x07,0x41,0xe3,0x07,0xd0,0x4e,0x40,0xb8,0x1f,0x90,0x00,0xe4,0x00,0xba,0x88,0x01,0x0e,0x10,0x0a,0x48,0xf9,0x6c,0xbe,0x10,0x70,0x82,0x78,0x3c,0x15,0x82,0x18,0xc2,0x21,0x00,0xb4,0x02,0x0e,0xbc,0x86,0x30,0x48,0x80,0xd1,0x05,0x03,0x78,0x82,0xc0,0x3e,0x52,0x32,0x63,0x70,0x20,0x70,0x09,0xd4,0x98,0xb0,0xf0,0x60,0x58,0xc9,0xce,0x12,0x0b,0xbf,0xd4,0x9d,0x28,0x9e,0x24,0xa9,0x82,0xda,0x24,0x2d,0x10,0x00,0xfd,0x2a,0x60,0xb4,0x85,0x4e,0x00,0x85,0xf8,0xd4,0x82,0xd2,0x09,0xc0,0x12,0x14,0x12,0xad,0x81,0x29,0xa8,0x90,0xf5,0x01,0x75,0x80,0x46,0x00,0xa5,0x50,0x0b,0x90,0x1c,0x41,0x63,0x60,0x05,0x96,0xc0,0x2e,0x52,0x44,0x79,0x60,0x06,0x05,0x50,0x05,0x94,0x89,0x88,0x63,0x02,0x98,0x02,0xc7,0xc1,0x21,0x6a,0x98,0xa0,0x62,0x11,0x00,0x58,0xc6,0x02,0xe2,0xb8,0x21,0x80,0xc3,0x05,0x02,0x38,0x11,0x78,0xa5,0x0b,0x01,0x81,0x5a,0x88,0x2c,0x60,0x40,0xb1,0xc0,0x27,0x0a,0xfc,0x0f,0x28,0x04,0x06,0x50,0x05,0x18,0xa9,0x94,0xc1,0x67,0x48,0x02,0x8c,0xb8,0x16,0xf8,0x80,0x28,0xd6,0x16,0x86,0x0b,0x38,0x40,0xd4,0x76,0x0c,0xd4,0x05,0x94,0x10,0x9a,0x34,0x01,0x82,0x1f,0x06,0x05,0x02,0x98,0x01,0x47,0x54,0x18,0x35,0xc8,0xff,0x20,0x3c,0x00,0x58,0xd5,0x6a,0xa0,0xb3,0x81,0xa3,0x0a,0x0f,0x80,0xd5,0xea,0x81,0x67,0x07,0x46,0x14,0xe3,0xe1,0x55,0x18,0x18,0x2c,0x51,0x85,0xc0,0xef,0x85,0x8c,0x0c,0x30,0xf4,0x61,0x40,0x2d,0x46,0xb4,0x05,0x8b,0x04,0xb0,0x15,0x40,0x5a,0x50,0x23,0xe6,0x01,0x02,0x8c,0xa8,0x2e,0xb1,0xe5,0x40,0x81,0x46,0x6a,0x17,0x59,0xeb,0xe4,0xa8,0x11,0xa0,0x5a,0x68,0x27,0x4e,0xd3,0x59,0xad,0x82,0xfa,0xed,0x2a,0x04,0x28,0x2e,0xb7,0xa7,0x69,0xc3,0x42,0xeb,0xf5,0x1f,0x09,0x4c,0x42,0xed,0xea,0x01,0x8c,0x06,0x41,0x05,0x0b,0xbc,0x02,0x0d,0x80,0x83,0x05,0xe2,0x11,0x40,0x0b,0xb7,0x14,0x06,0x33,0x0c,0x83,0x89,0x02,0xe3,0xca,0x3d,0x95,0x01,0xe2,0x21,0x74,0xc2,0x81,0x0b,0x0e,0x17,0x6c,0x10,0x10,0xaf,0x09,0xe2,0x0b,0xbb,0xd0,0x42,0xeb,0x02,}; -const uint8_t *_I_DolphinNice_96x59[] = {_I_DolphinNice_96x59_0}; +const uint8_t _I_DolphinExcited_64x63_0[] = {0x01,0x00,0x36,0x01,0x00,0x25,0x00,0x0f,0xd2,0x00,0x3b,0xe0,0x00,0xeb,0x10,0x0c,0x34,0x40,0x30,0xd0,0x88,0x80,0x1d,0xa1,0x00,0x42,0xfc,0x7f,0xc0,0x63,0x04,0x01,0x0e,0x02,0x0f,0x00,0x00,0x8c,0x08,0x0e,0x37,0x00,0x10,0xc6,0x20,0x10,0x10,0xd9,0x11,0x92,0x1c,0x1a,0x3e,0x00,0x04,0x42,0x02,0x1a,0x20,0xb0,0xce,0x00,0x64,0x07,0x20,0x59,0x16,0x50,0x36,0x45,0x94,0x84,0x78,0x20,0x60,0x75,0x8e,0x43,0x06,0x63,0x3c,0x33,0x94,0x0c,0xd2,0x5c,0x30,0x38,0xe4,0x08,0x43,0x10,0xc0,0x5e,0x06,0x22,0x53,0x1a,0x02,0x08,0x7f,0xd0,0x32,0xc1,0x50,0x21,0x14,0x0e,0x70,0x1c,0x46,0xe2,0x07,0x19,0x06,0x3c,0xdc,0x20,0x91,0xae,0x01,0xcc,0xbe,0x30,0x09,0xfc,0x12,0x41,0xff,0x83,0xcc,0x0a,0xa3,0x1f,0x03,0x99,0xe8,0x7c,0x10,0xf8,0x25,0xa0,0x5e,0x50,0x0f,0x84,0x1e,0x09,0x54,0x03,0x9f,0xf2,0x07,0x02,0xd5,0x11,0xca,0x01,0xfe,0x80,0xc0,0xaa,0x9f,0xf0,0x39,0x5f,0xd0,0x43,0xaa,0x83,0x41,0x92,0xc3,0x1f,0x03,0x8d,0x52,0x02,0x2e,0x25,0xc9,0x6a,0x99,0x46,0xa6,0x2a,0xa0,0x1c,0xaf,0xca,0x62,0x94,0x28,0xcb,0x7e,0x0f,0x15,0x71,0xf8,0x3c,0x22,0x71,0x03,0x8a,0x84,0x67,0x18,0x0f,0xac,0x1c,0x0e,0x38,0x08,0x0c,0x3e,0x01,0xae,0xbd,0x13,0x0c,0x0e,0x35,0x8e,0xa8,0x1c,0xb0,0x1f,0xf8,0x06,0x83,0xf4,0x27,0x38,0x07,0xff,0xff,0x8f,0x03,0xa0,0x4c,0x80,0xed,0x60,0x03,0xb4,0x60,0x0e,0xd0,0x60,0x3a,0x87,0x84,0x0e,0xb7,0xc2,0xfa,0x18,0x05,0x44,0x20,0x73,0xff,0xf7,0xce,0xe4,0x07,0x2d,0x52,0x2c,0x80,0xe7,0x54,0xea,0x81,0xd7,0x50,0x0f,0x7a,0xaa,0x3d,0x41,0xe2,0x07,0x5a,0x80,0x3c,0xa0,0x40,0x72,0xd0,0x6a,0x80,0xa2,0x07,0x3a,0x05,0x54,0x8e,0x20,0x73,0xc0,0x03,0xd8,0x60,0x30,0x40,0x3a,0xc0,0x00,0xee,0xea,0x10,0x3b,0x80,}; +const uint8_t *_I_DolphinExcited_64x63[] = {_I_DolphinExcited_64x63_0}; const uint8_t _I_DolphinWait_61x59_0[] = {0x01,0x00,0x56,0x01,0x00,0x17,0xfa,0x1e,0x06,0x4f,0x84,0x06,0xe0,0x07,0x48,0x64,0x03,0x01,0x01,0x03,0x9c,0x0c,0x04,0x30,0x60,0x31,0x70,0x00,0x65,0x08,0x01,0x94,0xc0,0x06,0x51,0x00,0x5b,0x48,0x00,0x65,0x04,0x01,0x95,0x00,0x82,0xd8,0x00,0x19,0x40,0x7e,0x00,0x75,0x1f,0x88,0xe0,0x88,0x02,0x1a,0x1f,0x94,0x14,0x0e,0xbf,0x98,0x58,0x5c,0x42,0x45,0x00,0x9e,0x99,0x87,0x01,0x02,0x11,0x94,0xf2,0x2e,0x03,0x18,0x39,0x28,0x70,0x1f,0xc0,0x3e,0x42,0x00,0xe5,0x80,0xff,0xdf,0xc0,0xe5,0xf8,0x85,0xd8,0x10,0x27,0x40,0xf9,0xc2,0x63,0x88,0x12,0x82,0x6a,0x20,0x50,0x41,0xe9,0x42,0x20,0x95,0x48,0x6e,0x0c,0xfa,0x9a,0xaf,0xf9,0x90,0xe2,0x10,0x2e,0xac,0xe0,0x0e,0x98,0x29,0x52,0x11,0x13,0x23,0x15,0x3e,0x20,0x3c,0x61,0x40,0x52,0xfc,0x4f,0xe2,0x10,0x38,0x68,0x1c,0xa0,0xfc,0x08,0xbe,0x04,0x1e,0x5e,0x01,0xb9,0x03,0xc5,0x60,0x24,0xf2,0x84,0x60,0x63,0x40,0x71,0x27,0x9c,0x0e,0x2b,0x04,0x6c,0xa4,0x06,0x15,0x08,0x6c,0x99,0x8c,0xa6,0x0f,0x81,0x00,0x0c,0x08,0xf0,0x3c,0x05,0x61,0xc0,0x40,0x86,0xd0,0x30,0x78,0x80,0x0c,0xc6,0x2b,0x92,0x00,0x0d,0x51,0xf0,0x2d,0x42,0x0a,0x8e,0xaa,0x34,0x0f,0x4a,0x85,0x55,0x6e,0x20,0xf3,0xd5,0x6a,0x84,0xa2,0x66,0x2a,0x05,0xf7,0xaa,0x07,0x18,0xaf,0xfb,0x7f,0xea,0xc1,0xef,0xc0,0xe3,0xea,0x80,0xf8,0x27,0xf0,0x0a,0xc0,0x1c,0x67,0xa2,0xd1,0xb1,0xc0,0x34,0x00,0x71,0x14,0x8f,0x00,0x98,0x34,0x02,0x69,0xd0,0x37,0x90,0x16,0xf1,0x00,0x06,0xe1,0x84,0x31,0x89,0x14,0xe9,0xdc,0x40,0x38,0xa4,0xc4,0x4c,0x3c,0x1f,0x88,0x8c,0x5b,0xc3,0x01,0xbc,0x40,0x3f,0xf0,0xf6,0x71,0x0c,0x0b,0xe0,0x07,0x3c,0x0a,0xf8,0xa3,0xf0,0x03,0xb8,0xd8,0x80,0xe8,0x87,0x1b,0xa8,0x1c,0x78,0x1f,0xf8,0x0e,0x7e,0x01,0x6a,0x03,0x94,0x0f,0xfd,0xa0,0x80,0x7d,0x49,0x04,0x4d,0x12,0xc0,0xfa,0x83,0x83,0xbe,0x26,0x8d,0x02,0x05,0xd5,0xff,0xff,0xeb,0xe9,0x31,0x90,0x40,0x80,}; const uint8_t *_I_DolphinWait_61x59[] = {_I_DolphinWait_61x59_0}; -const Icon I_Certification1_103x23 = {.width=103,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Certification1_103x23}; +const uint8_t _I_iButtonDolphinVerySuccess_108x52_0[] = {0x01,0x00,0xc2,0x01,0x00,0x0f,0xe2,0xfe,0x0d,0xb8,0x3e,0x02,0x06,0x0c,0x9f,0x00,0x08,0x61,0x80,0xd9,0x8c,0x00,0x86,0x60,0x0d,0x98,0x30,0x08,0x6a,0x00,0xd9,0x80,0x80,0x87,0x40,0x0c,0x8c,0x00,0x0c,0xa8,0x01,0x12,0x00,0x2d,0x00,0x22,0x70,0x20,0x6b,0xc8,0x02,0x26,0x62,0x88,0x80,0x6c,0xc9,0x24,0x0d,0x9a,0x07,0x17,0xfe,0x1d,0x68,0x40,0x6c,0xe7,0x48,0x04,0x28,0x10,0x34,0xe8,0x10,0xd1,0x11,0xc4,0x01,0xa5,0x04,0x06,0x96,0xa0,0xa6,0x24,0xc2,0x88,0x17,0x88,0x1a,0x7d,0x43,0x78,0x82,0x4a,0x40,0x03,0x20,0xb0,0xff,0x20,0x16,0xa3,0xb2,0x48,0x03,0xe4,0x0d,0x1f,0xfc,0x06,0x3a,0x0d,0x4a,0x00,0x34,0xf8,0x00,0xd1,0x37,0x0f,0x82,0x9e,0x95,0x58,0x17,0x83,0xff,0x81,0x1b,0x0f,0xf1,0xfe,0x71,0xe0,0x69,0x7c,0x3f,0xe0,0x82,0xff,0xcf,0xc0,0x85,0x61,0x80,0x43,0xb0,0x5f,0xa8,0x79,0xdc,0x81,0xa5,0x70,0xc0,0x68,0x3c,0x10,0x1a,0x17,0xd5,0x28,0x42,0xd1,0x8f,0x84,0x46,0x83,0xb0,0x8e,0x40,0x34,0x5f,0xa8,0x38,0x34,0x45,0xa2,0x0d,0x18,0x04,0x9b,0x50,0x03,0x1a,0x14,0x35,0x36,0x5f,0x8f,0xf8,0xb8,0xa4,0x19,0x40,0x18,0xe8,0xa0,0xca,0x22,0xfe,0x7f,0xc4,0x05,0x20,0xa5,0x80,0xc6,0x82,0xcb,0x3f,0xf3,0x44,0xfc,0x12,0x40,0x18,0xe8,0x51,0x82,0x52,0x28,0xfc,0x38,0x0a,0x3e,0x48,0x98,0x6c,0x8f,0x43,0x00,0xe0,0x63,0xe0,0x62,0xe2,0x91,0x90,0x0a,0x02,0x0d,0x2f,0x82,0x50,0x41,0xa3,0x80,0x90,0x41,0x04,0xc3,0x01,0xc0,0x83,0x46,0x71,0x30,0x06,0x95,0x82,0x21,0x02,0x6e,0x88,0x6c,0x43,0x83,0x1f,0x2f,0x88,0x34,0x62,0x00,0xd1,0x15,0x08,0x2c,0x60,0xcc,0x51,0x0f,0x08,0xcc,0x81,0xa2,0x12,0x10,0x68,0xc6,0x3f,0x06,0xc2,0x06,0x8e,0x02,0x16,0x41,0x20,0x10,0xf8,0x01,0x85,0x00,0x19,0x0d,0x82,0x18,0x07,0x20,0x81,0x00,0x0c,0x9c,0x31,0x08,0x42,0x74,0x81,0xab,0x80,0x03,0x0c,0x32,0x11,0x0b,0x06,0xb9,0xc0,0x43,0xa3,0x10,0x8b,0x83,0x5c,0xe0,0x20,0x81,0xc8,0x26,0x49,0x4c,0x40,0x02,0x86,0x0a,0xc5,0x22,0x32,0x50,0x6b,0x93,0x86,0xc0,0x0d,0x19,0x18,0x35,0x8c,0x84,0x79,0x1a,0x84,0x84,0x1a,0xdf,0xc2,0xe0,0x8a,0xc7,0x51,0x22,0x06,0xb5,0x5e,0x3f,0x00,0x77,0x0d,0x60,0x36,0xfa,0xa9,0xd7,0x00,0x08,0x3a,0xc9,0x02,0x48,0xc0,0x05,0x54,0xba,0x98,0x8a,0xa8,0xf1,0x20,0x6a,0x6a,0x3d,0x43,0x61,0x80,0x4a,0x81,0xaf,0x40,0xea,0x8d,0x86,0x01,0x56,0x06,0x93,0x60,0x80,0x05,0xea,0x01,0x94,0xac,0x1b,0x11,0x80,0x19,0x45,0x41,0x44,0x0d,0x58,0x33,0x18,0xa1,0x4f,0xf3,0x06,0x1f,0x01,0x76,0x58,0x00,0xd9,0x83,0x52,0x7c,0x11,0x38,0x51,0x40,0x80,}; +const uint8_t *_I_iButtonDolphinVerySuccess_108x52[] = {_I_iButtonDolphinVerySuccess_108x52_0}; + +const uint8_t _I_DolphinMafia_115x62_0[] = {0x01,0x00,0x21,0x02,0x00,0x1e,0x02,0x06,0x0e,0xcb,0x04,0x10,0x1d,0x91,0x88,0x40,0x3b,0x20,0xc0,0xec,0xc0,0x40,0x62,0x03,0xac,0x80,0x03,0xb2,0x31,0x00,0x90,0x03,0xae,0x5e,0x0e,0xcf,0xc4,0x56,0x01,0x40,0x07,0x56,0xbe,0x14,0x0e,0x2f,0xf1,0x5e,0x2a,0xa1,0xd1,0xc0,0x7c,0x3f,0xf0,0x70,0x73,0x70,0x35,0x41,0xd1,0xc0,0x7f,0xff,0xf0,0xf0,0x73,0x50,0x03,0xa4,0x0d,0x10,0x74,0x07,0x46,0x55,0xe0,0x07,0x10,0xb1,0xc3,0xa3,0x55,0xfe,0x03,0x88,0x94,0xe1,0xd1,0xd5,0x03,0x4a,0x3e,0x59,0x9e,0xaf,0xfe,0xff,0x05,0x60,0x4e,0xab,0xf5,0xff,0x95,0xb4,0xa4,0x3a,0x3f,0xd0,0xe0,0xfa,0x20,0x20,0xf8,0xd5,0xff,0xb5,0xf0,0x0f,0x88,0x3a,0x6a,0xbf,0xf8,0xaf,0x82,0x6f,0x03,0x07,0x47,0xaf,0xff,0x0a,0xfe,0x5f,0xc1,0xd3,0xf6,0xbf,0xe0,0x7f,0xfe,0xf0,0x73,0x41,0x00,0x43,0xfa,0xd7,0xf8,0x27,0xfe,0xe0,0x73,0x40,0x80,0x43,0xfe,0xab,0xfe,0x21,0xfc,0xe5,0x9b,0x05,0x48,0xea,0x3f,0xc8,0xfa,0xc4,0x66,0x07,0x44,0x0e,0x8f,0x00,0xb0,0x2b,0x31,0x07,0x0f,0x00,0x1c,0x72,0x00,0x70,0xf8,0x37,0xe5,0x81,0xff,0x89,0x08,0xf2,0x71,0x80,0x20,0xfe,0x2b,0xf0,0x5f,0xc0,0x38,0xc8,0xa5,0x60,0xc3,0x00,0xc7,0xf9,0xaf,0x81,0x2d,0x04,0x34,0x40,0xe1,0x98,0x47,0x68,0x04,0x92,0xab,0xc0,0x7e,0xb7,0xf7,0x39,0x03,0x85,0x8e,0x24,0xf1,0xc0,0x7f,0xf5,0x78,0x0f,0x53,0xb4,0xbc,0x1f,0xb8,0x1a,0x0c,0x61,0xc5,0x82,0xab,0xc0,0x3e,0xa3,0xa2,0xfc,0x07,0x46,0x09,0x60,0x19,0x8f,0x80,0xec,0x38,0x08,0x52,0x6c,0xb8,0xdc,0x28,0x7c,0x10,0x2a,0x5f,0x0f,0xfc,0x5a,0x01,0x05,0x1a,0x8e,0x02,0x02,0x1d,0x1f,0x81,0xa8,0xbe,0x13,0xf8,0x52,0x2c,0x8c,0x62,0x77,0x42,0x11,0x40,0xe0,0xca,0x93,0x8e,0x03,0x8a,0x30,0x10,0x48,0x54,0x03,0x04,0xbb,0x2c,0x00,0x0c,0x64,0x80,0xe4,0x0e,0x88,0x38,0x7c,0x10,0x04,0x09,0x48,0x83,0xac,0x1b,0x18,0xf3,0x44,0xc1,0xca,0x1d,0x15,0x40,0x8e,0x05,0x02,0x20,0xe6,0x24,0x12,0x8c,0x8b,0x05,0x21,0x07,0x24,0x14,0x08,0x73,0x80,0x19,0x78,0x43,0xb2,0xff,0x15,0x30,0xc4,0x01,0x26,0x8f,0x14,0x61,0xa9,0x8a,0x09,0x10,0x02,0x12,0x1c,0x80,0x84,0xaf,0x10,0x71,0xaa,0xc4,0x00,0x3b,0x04,0xea,0x24,0x48,0x1c,0xbd,0x8f,0xf8,0x00,0x67,0xf0,0x09,0x40,0x20,0x61,0x00,0xe4,0xf6,0x07,0x4b,0xc1,0x1f,0x07,0x14,0x40,0x1c,0x9d,0x66,0x79,0x24,0xc6,0xa0,0x0e,0x32,0x51,0xfa,0xce,0xe7,0x50,0x07,0x1c,0x80,0x30,0x58,0x0e,0xa2,0xcc,0xa0,0x19,0x00,0x71,0x42,0x13,0x27,0x40,0xf5,0x45,0x41,0xc5,0x08,0xb0,0x80,0xc6,0x18,0xf2,0x28,0x04,0x83,0xe8,0x58,0x10,0x30,0xc2,0x2c,0x40,0x91,0x89,0x3c,0x88,0x62,0x21,0xd2,0xff,0x03,0x87,0xc8,0x12,0x19,0x08,0x39,0x3e,0x83,0xb2,0x4a,0x0e,0xa2,0x0d,0xc0,0xe0,0x50,0x06,0xa7,0xe8,0x2c,0x94,0xc2,0x09,0x50,0x8c,0xce,0x20,0x34,0x70,0x71,0x41,0x3e,0x85,0xe2,0xe0,0x41,0x38,0x1e,0x28,0x3c,0x19,0xc8,0x70,0x4f,0xc1,0xdc,0xe0,0x74,0x01,0xd8,0xc6,0x24,0x00,0x82,0x81,0x7c,0x12,0xa6,0x7e,0x10,0x28,0xd8,0x22,0x00,0xe3,0xfc,0x34,0x53,0x00,0x23,0x1c,0x04,0x44,0x0e,0x50,0x10,0xeb,0x17,0xca,0x1c,0x07,0x20,}; +const uint8_t *_I_DolphinMafia_115x62[] = {_I_DolphinMafia_115x62_0}; + +const uint8_t _I_DolphinNice_96x59_0[] = {0x01,0x00,0x8a,0x01,0x00,0x37,0xfa,0x3e,0x0a,0x8f,0x04,0x04,0x02,0x20,0xb7,0x8c,0x00,0x86,0x1c,0x0b,0x78,0x20,0x08,0x66,0x00,0xb7,0x81,0x00,0x86,0x80,0x0b,0x71,0x61,0x60,0x01,0x4c,0x07,0x41,0xe3,0x07,0xd0,0x4e,0x40,0xb8,0x1f,0x90,0x00,0xe4,0x00,0xba,0x88,0x01,0x0e,0x10,0x0a,0x48,0xf9,0x6c,0xbe,0x10,0x70,0x82,0x78,0x3c,0x15,0x82,0x18,0xc2,0x21,0x00,0xb4,0x02,0x0e,0xbc,0x86,0x30,0x48,0x80,0xd1,0x05,0x03,0x78,0x82,0xc0,0x3e,0x52,0x32,0x63,0x70,0x20,0x70,0x09,0xd4,0x98,0xb0,0xf0,0x60,0x58,0xc9,0xce,0x12,0x0b,0xbf,0xd4,0x9d,0x28,0x9e,0x24,0xa9,0x82,0xda,0x24,0x2d,0x10,0x00,0xfd,0x2a,0x60,0xb4,0x85,0x4e,0x00,0x85,0xf8,0xd4,0x82,0xd2,0x09,0xc0,0x12,0x14,0x12,0xad,0x81,0x29,0xa8,0x90,0xf5,0x01,0x75,0x80,0x46,0x00,0xa5,0x50,0x0b,0x90,0x1c,0x41,0x63,0x60,0x05,0x96,0xc0,0x2e,0x52,0x44,0x79,0x60,0x06,0x05,0x50,0x05,0x94,0x89,0x88,0x63,0x02,0x98,0x02,0xc7,0xc1,0x21,0x6a,0x98,0xa0,0x62,0x11,0x00,0x58,0xc6,0x02,0xe2,0xb8,0x21,0x80,0xc3,0x05,0x02,0x38,0x11,0x78,0xa5,0x0b,0x01,0x81,0x5a,0x88,0x2c,0x60,0x40,0xb1,0xc0,0x27,0x0a,0xfc,0x0f,0x28,0x04,0x06,0x50,0x05,0x18,0xa9,0x94,0xc1,0x67,0x48,0x02,0x8c,0xb8,0x16,0xf8,0x80,0x28,0xd6,0x16,0x86,0x0b,0x38,0x40,0xd4,0x76,0x0c,0xd4,0x05,0x94,0x10,0x9a,0x34,0x01,0x82,0x1f,0x06,0x05,0x02,0x98,0x01,0x47,0x54,0x18,0x35,0xc8,0xff,0x20,0x3c,0x00,0x58,0xd5,0x6a,0xa0,0xb3,0x81,0xa3,0x0a,0x0f,0x80,0xd5,0xea,0x81,0x67,0x07,0x46,0x14,0xe3,0xe1,0x55,0x18,0x18,0x2c,0x51,0x85,0xc0,0xef,0x85,0x8c,0x0c,0x30,0xf4,0x61,0x40,0x2d,0x46,0xb4,0x05,0x8b,0x04,0xb0,0x15,0x40,0x5a,0x50,0x23,0xe6,0x01,0x02,0x8c,0xa8,0x2e,0xb1,0xe5,0x40,0x81,0x46,0x6a,0x17,0x59,0xeb,0xe4,0xa8,0x11,0xa0,0x5a,0x68,0x27,0x4e,0xd3,0x59,0xad,0x82,0xfa,0xed,0x2a,0x04,0x28,0x2e,0xb7,0xa7,0x69,0xc3,0x42,0xeb,0xf5,0x1f,0x09,0x4c,0x42,0xed,0xea,0x01,0x8c,0x06,0x41,0x05,0x0b,0xbc,0x02,0x0d,0x80,0x83,0x05,0xe2,0x11,0x40,0x0b,0xb7,0x14,0x06,0x33,0x0c,0x83,0x89,0x02,0xe3,0xca,0x3d,0x95,0x01,0xe2,0x21,0x74,0xc2,0x81,0x0b,0x0e,0x17,0x6c,0x10,0x10,0xaf,0x09,0xe2,0x0b,0xbb,0xd0,0x42,0xeb,0x02,}; +const uint8_t *_I_DolphinNice_96x59[] = {_I_DolphinNice_96x59_0}; + +const uint8_t _I_iButtonDolphinSuccess_109x60_0[] = {0x01,0x00,0xac,0x01,0x00,0x17,0xfe,0x1e,0x0c,0xaf,0x04,0x02,0xe0,0x0d,0xa8,0xf4,0x03,0x01,0x03,0x06,0x46,0x02,0x02,0x03,0x18,0xe0,0x36,0x2c,0x00,0x36,0x00,0x2c,0x40,0x3e,0x60,0xd8,0x84,0x01,0x0c,0x5a,0x40,0x05,0x82,0x01,0x0e,0x04,0x0d,0x70,0x42,0x04,0x90,0x49,0x02,0xe4,0x20,0x41,0x28,0xc0,0x07,0x40,0x06,0xf8,0x00,0xa4,0x00,0xd6,0x03,0xa8,0x37,0x44,0x2a,0x31,0x74,0xd3,0x83,0x57,0x80,0x0d,0xc7,0x18,0xa9,0xa8,0x36,0x2a,0x86,0x06,0x8d,0xfc,0x36,0x60,0xd7,0xc0,0x3b,0x8c,0x36,0xf0,0x4a,0x05,0xf9,0x6e,0x5e,0x06,0x23,0x41,0x24,0x1f,0xf6,0x01,0x74,0x01,0xb1,0xe3,0x82,0x81,0x47,0x40,0x0d,0x7c,0x87,0x8e,0x12,0x05,0x1a,0x84,0x0d,0xb6,0xa0,0xd2,0x85,0x86,0xc8,0x1a,0x50,0x40,0x69,0x40,0xb2,0x1f,0xf0,0x69,0x50,0x01,0xa5,0x08,0xfc,0x03,0x5f,0x60,0x0d,0x28,0x84,0x1a,0x07,0x18,0x06,0xaf,0x00,0x1a,0x3c,0x03,0xb8,0xc3,0x20,0xd0,0x28,0x87,0xfc,0x8a,0x50,0x08,0x78,0x08,0x70,0x77,0x0c,0x44,0x06,0x05,0x30,0xff,0x18,0x4a,0x01,0x30,0x01,0x0d,0x33,0x19,0x11,0x1b,0x8c,0xa2,0xf8,0x7d,0x27,0x71,0xd0,0x20,0x51,0x20,0x68,0xd5,0x00,0x42,0x0d,0x2c,0x00,0x08,0x64,0x10,0x19,0x20,0x28,0x75,0x07,0x53,0x3d,0x18,0x35,0x2a,0x9f,0xf4,0x9a,0x41,0x90,0x23,0x00,0x94,0x43,0xe0,0x5e,0xae,0x03,0x9d,0xb4,0xe0,0xd1,0x0d,0x8c,0xd0,0x52,0xb1,0x00,0xd9,0x83,0x46,0x34,0x45,0x41,0xa8,0x9f,0x86,0x01,0x14,0x05,0x08,0x08,0x81,0xa6,0x62,0x10,0x68,0xe5,0x20,0x70,0x41,0x80,0x80,0x10,0xc4,0x34,0x48,0x04,0x2a,0x38,0x0d,0x99,0x16,0x02,0x1a,0xd5,0x10,0x6c,0x5e,0x2e,0x0b,0xa1,0x4b,0x0a,0x60,0xc1,0xa7,0x84,0xfc,0x58,0x01,0xb5,0x02,0x82,0xb4,0xc4,0x16,0x22,0xa5,0x06,0x96,0x19,0x20,0x20,0xd7,0x30,0x8c,0x0f,0x08,0x05,0x10,0x68,0xa1,0x44,0x1a,0x98,0x08,0x14,0x11,0x28,0x21,0x91,0x1d,0x8f,0x83,0xfe,0x07,0x1b,0x00,0x34,0x61,0x00,0xd3,0x1d,0x8c,0x7a,0x01,0x7e,0x80,0x56,0x30,0x06,0xb1,0x4a,0x08,0xd4,0xbf,0xc1,0x31,0xc0,0x7f,0xe8,0xf0,0x08,0x3c,0x40,0x1a,0x80,0x04,0x5a,0x8c,0x10,0x80,0x40,0xd7,0x05,0x08,0x36,0xc0,0xe2,0x0d,0xb8,0x30,0x34,0x45,0x82,0x0d,0x72,0x49,0x03,0x5a,0x41,0x55,0xf8,0x7f,0xff,0xe8,0x72,0x06,0xae,0x03,0xf4,0x0c,0x1d,0xf8,0x18,0x60,0x40,0xd2,0x4b,0x9f,0xd0,0x1a,0x35,0x71,0x48,0xc0,0x95,0x42,0x0d,0x4d,0x50,0x70,0x75,0x40,0xd1,0x80,0x83,0x5a,0xa1,0x55,0x00,0x0c,0x05,0xa4,0x20,0xd2,}; +const uint8_t *_I_iButtonDolphinSuccess_109x60[] = {_I_iButtonDolphinSuccess_109x60_0}; + const Icon I_Certification2_119x30 = {.width=119,.height=30,.frame_count=1,.frame_rate=0,.frames=_I_Certification2_119x30}; +const Icon I_Certification1_103x23 = {.width=103,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Certification1_103x23}; const Icon A_WatchingTV_128x64 = {.width=128,.height=64,.frame_count=4,.frame_rate=1,.frames=_A_WatchingTV_128x64}; const Icon A_Wink_128x64 = {.width=128,.height=64,.frame_count=9,.frame_rate=1,.frames=_A_Wink_128x64}; -const Icon I_dir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_dir_10px}; -const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; const Icon I_sub1_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_sub1_10px}; const Icon I_ir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ir_10px}; -const Icon I_ibutt_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ibutt_10px}; const Icon I_unknown_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_unknown_10px}; +const Icon I_ibutt_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ibutt_10px}; +const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; const Icon I_ble_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ble_10px}; const Icon I_125_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_125_10px}; +const Icon I_dir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_dir_10px}; const Icon I_BLE_Pairing_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_BLE_Pairing_128x64}; -const Icon I_ButtonRightSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRightSmall_3x5}; -const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_4x7}; -const Icon I_ButtonLeftSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeftSmall_3x5}; -const Icon I_DFU_128x50 = {.width=128,.height=50,.frame_count=1,.frame_rate=0,.frames=_I_DFU_128x50}; -const Icon I_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; const Icon I_ButtonDown_7x4 = {.width=7,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_ButtonDown_7x4}; -const Icon I_ButtonRight_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRight_4x7}; const Icon I_ButtonCenter_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonCenter_7x7}; +const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_4x7}; const Icon I_ButtonUp_7x4 = {.width=7,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_ButtonUp_7x4}; -const Icon I_DolphinOkay_41x43 = {.width=41,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_DolphinOkay_41x43}; -const Icon I_DolphinFirstStart4_67x53 = {.width=67,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart4_67x53}; +const Icon I_DFU_128x50 = {.width=128,.height=50,.frame_count=1,.frame_rate=0,.frames=_I_DFU_128x50}; +const Icon I_ButtonLeftSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeftSmall_3x5}; +const Icon I_ButtonRightSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRightSmall_3x5}; +const Icon I_ButtonRight_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRight_4x7}; +const Icon I_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; const Icon I_DolphinFirstStart2_59x51 = {.width=59,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart2_59x51}; const Icon I_DolphinFirstStart5_54x49 = {.width=54,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart5_54x49}; -const Icon I_DolphinFirstStart0_70x53 = {.width=70,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart0_70x53}; const Icon I_DolphinFirstStart6_58x54 = {.width=58,.height=54,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart6_58x54}; -const Icon I_DolphinFirstStart1_59x53 = {.width=59,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart1_59x53}; -const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart8_56x51}; -const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; +const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart8_56x51}; +const Icon I_DolphinFirstStart1_59x53 = {.width=59,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart1_59x53}; +const Icon I_DolphinOkay_41x43 = {.width=41,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_DolphinOkay_41x43}; const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; +const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; +const Icon I_DolphinFirstStart0_70x53 = {.width=70,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart0_70x53}; +const Icon I_DolphinFirstStart4_67x53 = {.width=67,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart4_67x53}; const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; -const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; -const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; const Icon I_DoorRight_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorRight_70x55}; +const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; +const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; const Icon I_LockPopup_100x49 = {.width=100,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_LockPopup_100x49}; -const Icon I_Mute_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_25x27}; -const Icon I_IrdaArrowUp_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowUp_4x8}; -const Icon I_Up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_hvr_25x27}; -const Icon I_Mute_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_hvr_25x27}; -const Icon I_Vol_down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_down_25x27}; -const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; -const Icon I_Power_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_hvr_25x27}; -const Icon I_IrdaLearnShort_128x31 = {.width=128,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearnShort_128x31}; -const Icon I_IrdaArrowDown_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowDown_4x8}; -const Icon I_Vol_down_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_down_hvr_25x27}; -const Icon I_IrdaLearn_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearn_128x64}; const Icon I_Down_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_hvr_25x27}; +const Icon I_Vol_down_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_down_hvr_25x27}; +const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; const Icon I_Fill_marker_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Fill_marker_7x7}; -const Icon I_Power_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_25x27}; +const Icon I_Vol_down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_down_25x27}; const Icon I_Vol_up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_up_25x27}; -const Icon I_Up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_25x27}; -const Icon I_Back_15x10 = {.width=15,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Back_15x10}; -const Icon I_IrdaSend_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSend_128x64}; -const Icon I_IrdaSendShort_128x34 = {.width=128,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSendShort_128x34}; +const Icon I_Up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_hvr_25x27}; const Icon I_Vol_up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_up_hvr_25x27}; -const Icon I_KeySave_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySave_24x11}; -const Icon I_KeyBackspaceSelected_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspaceSelected_16x9}; +const Icon I_IrdaLearnShort_128x31 = {.width=128,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearnShort_128x31}; +const Icon I_IrdaSend_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSend_128x64}; +const Icon I_DolphinReadingSuccess_59x63 = {.width=59,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinReadingSuccess_59x63}; +const Icon I_Mute_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_hvr_25x27}; +const Icon I_Back_15x10 = {.width=15,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Back_15x10}; +const Icon I_Up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_25x27}; +const Icon I_IrdaArrowUp_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowUp_4x8}; +const Icon I_Mute_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_25x27}; +const Icon I_Power_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_25x27}; +const Icon I_IrdaSendShort_128x34 = {.width=128,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSendShort_128x34}; +const Icon I_IrdaArrowDown_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowDown_4x8}; +const Icon I_IrdaLearn_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearn_128x64}; +const Icon I_Power_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_hvr_25x27}; const Icon I_KeySaveSelected_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySaveSelected_24x11}; const Icon I_KeyBackspace_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspace_16x9}; +const Icon I_KeyBackspaceSelected_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspaceSelected_16x9}; +const Icon I_KeySave_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySave_24x11}; const Icon A_125khz_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_125khz_14}; const Icon A_Bluetooth_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Bluetooth_14}; const Icon A_Debug_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_Debug_14}; @@ -548,45 +552,45 @@ const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14}; const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13}; const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; -const Icon I_Health_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Health_16x16}; -const Icon I_FaceCharging_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceCharging_29x14}; const Icon I_BatteryBody_52x28 = {.width=52,.height=28,.frame_count=1,.frame_rate=0,.frames=_I_BatteryBody_52x28}; -const Icon I_Voltage_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Voltage_16x16}; +const Icon I_FaceCharging_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceCharging_29x14}; +const Icon I_Health_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Health_16x16}; const Icon I_Temperature_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Temperature_16x16}; -const Icon I_FaceNopower_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNopower_29x14}; -const Icon I_FaceNormal_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNormal_29x14}; const Icon I_Battery_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Battery_16x16}; const Icon I_FaceConfused_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceConfused_29x14}; -const Icon I_RFIDDolphinSuccess_108x57 = {.width=108,.height=57,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSuccess_108x57}; -const Icon I_RFIDBigChip_37x36 = {.width=37,.height=36,.frame_count=1,.frame_rate=0,.frames=_I_RFIDBigChip_37x36}; +const Icon I_FaceNormal_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNormal_29x14}; +const Icon I_Voltage_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Voltage_16x16}; +const Icon I_FaceNopower_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNopower_29x14}; const Icon I_RFIDDolphinSend_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSend_97x61}; +const Icon I_RFIDDolphinSuccess_108x57 = {.width=108,.height=57,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSuccess_108x57}; const Icon I_RFIDDolphinReceive_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinReceive_97x61}; +const Icon I_RFIDBigChip_37x36 = {.width=37,.height=36,.frame_count=1,.frame_rate=0,.frames=_I_RFIDBigChip_37x36}; const Icon I_SDQuestion_35x43 = {.width=35,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_SDQuestion_35x43}; const Icon I_SDError_43x35 = {.width=43,.height=35,.frame_count=1,.frame_rate=0,.frames=_I_SDError_43x35}; const Icon I_Cry_dolph_55x52 = {.width=55,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Cry_dolph_55x52}; -const Icon I_BadUsb_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BadUsb_9x8}; -const Icon I_PlaceholderR_30x13 = {.width=30,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderR_30x13}; -const Icon I_Background_128x8 = {.width=128,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x8}; +const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11}; const Icon I_Lock_8x8 = {.width=8,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_8x8}; const Icon I_Battery_26x8 = {.width=26,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_26x8}; -const Icon I_PlaceholderL_11x13 = {.width=11,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderL_11x13}; const Icon I_Battery_19x8 = {.width=19,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_19x8}; -const Icon I_SDcardMounted_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardMounted_11x8}; -const Icon I_SDcardFail_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardFail_11x8}; const Icon I_USBConnected_15x8 = {.width=15,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_USBConnected_15x8}; -const Icon I_Bluetooth_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_5x8}; +const Icon I_Background_128x8 = {.width=128,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x8}; +const Icon I_BadUsb_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BadUsb_9x8}; const Icon I_BT_Pair_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BT_Pair_9x8}; -const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11}; -const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; +const Icon I_PlaceholderL_11x13 = {.width=11,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderL_11x13}; +const Icon I_SDcardFail_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardFail_11x8}; +const Icon I_Bluetooth_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_5x8}; +const Icon I_PlaceholderR_30x13 = {.width=30,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderR_30x13}; +const Icon I_SDcardMounted_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardMounted_11x8}; const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; -const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; -const Icon I_MHz_25x11 = {.width=25,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_MHz_25x11}; const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; -const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62}; -const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63}; -const Icon I_iButtonDolphinSuccess_109x60 = {.width=109,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinSuccess_109x60}; -const Icon I_iButtonDolphinVerySuccess_108x52 = {.width=108,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinVerySuccess_108x52}; +const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; +const Icon I_MHz_25x11 = {.width=25,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_MHz_25x11}; +const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; const Icon I_iButtonKey_49x44 = {.width=49,.height=44,.frame_count=1,.frame_rate=0,.frames=_I_iButtonKey_49x44}; -const Icon I_DolphinNice_96x59 = {.width=96,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinNice_96x59}; +const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63}; const Icon I_DolphinWait_61x59 = {.width=61,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinWait_61x59}; +const Icon I_iButtonDolphinVerySuccess_108x52 = {.width=108,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinVerySuccess_108x52}; +const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62}; +const Icon I_DolphinNice_96x59 = {.width=96,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinNice_96x59}; +const Icon I_iButtonDolphinSuccess_109x60 = {.width=109,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinSuccess_109x60}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index cad95865..e0c18aff 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -1,69 +1,70 @@ #pragma once #include -extern const Icon I_Certification1_103x23; extern const Icon I_Certification2_119x30; +extern const Icon I_Certification1_103x23; extern const Icon A_WatchingTV_128x64; extern const Icon A_Wink_128x64; -extern const Icon I_dir_10px; -extern const Icon I_Nfc_10px; extern const Icon I_sub1_10px; extern const Icon I_ir_10px; -extern const Icon I_ibutt_10px; extern const Icon I_unknown_10px; +extern const Icon I_ibutt_10px; +extern const Icon I_Nfc_10px; extern const Icon I_ble_10px; extern const Icon I_125_10px; +extern const Icon I_dir_10px; extern const Icon I_BLE_Pairing_128x64; -extern const Icon I_ButtonRightSmall_3x5; -extern const Icon I_ButtonLeft_4x7; -extern const Icon I_ButtonLeftSmall_3x5; -extern const Icon I_DFU_128x50; -extern const Icon I_Warning_30x23; extern const Icon I_ButtonDown_7x4; -extern const Icon I_ButtonRight_4x7; extern const Icon I_ButtonCenter_7x7; +extern const Icon I_ButtonLeft_4x7; extern const Icon I_ButtonUp_7x4; -extern const Icon I_DolphinOkay_41x43; -extern const Icon I_DolphinFirstStart4_67x53; +extern const Icon I_DFU_128x50; +extern const Icon I_ButtonLeftSmall_3x5; +extern const Icon I_ButtonRightSmall_3x5; +extern const Icon I_ButtonRight_4x7; +extern const Icon I_Warning_30x23; extern const Icon I_DolphinFirstStart2_59x51; extern const Icon I_DolphinFirstStart5_54x49; -extern const Icon I_DolphinFirstStart0_70x53; extern const Icon I_DolphinFirstStart6_58x54; -extern const Icon I_DolphinFirstStart1_59x53; -extern const Icon I_DolphinFirstStart8_56x51; -extern const Icon I_DolphinFirstStart7_61x51; extern const Icon I_Flipper_young_80x60; +extern const Icon I_DolphinFirstStart8_56x51; +extern const Icon I_DolphinFirstStart1_59x53; +extern const Icon I_DolphinOkay_41x43; extern const Icon I_DolphinFirstStart3_57x48; +extern const Icon I_DolphinFirstStart7_61x51; +extern const Icon I_DolphinFirstStart0_70x53; +extern const Icon I_DolphinFirstStart4_67x53; extern const Icon I_PassportBottom_128x17; -extern const Icon I_DoorLocked_10x56; extern const Icon I_DoorLeft_70x55; -extern const Icon I_PassportLeft_6x47; extern const Icon I_DoorRight_70x55; +extern const Icon I_DoorLocked_10x56; +extern const Icon I_PassportLeft_6x47; extern const Icon I_LockPopup_100x49; -extern const Icon I_Mute_25x27; -extern const Icon I_IrdaArrowUp_4x8; -extern const Icon I_Up_hvr_25x27; -extern const Icon I_Mute_hvr_25x27; -extern const Icon I_Vol_down_25x27; -extern const Icon I_Down_25x27; -extern const Icon I_Power_hvr_25x27; -extern const Icon I_IrdaLearnShort_128x31; -extern const Icon I_IrdaArrowDown_4x8; -extern const Icon I_Vol_down_hvr_25x27; -extern const Icon I_IrdaLearn_128x64; extern const Icon I_Down_hvr_25x27; +extern const Icon I_Vol_down_hvr_25x27; +extern const Icon I_Down_25x27; extern const Icon I_Fill_marker_7x7; -extern const Icon I_Power_25x27; +extern const Icon I_Vol_down_25x27; extern const Icon I_Vol_up_25x27; -extern const Icon I_Up_25x27; -extern const Icon I_Back_15x10; -extern const Icon I_IrdaSend_128x64; -extern const Icon I_IrdaSendShort_128x34; +extern const Icon I_Up_hvr_25x27; extern const Icon I_Vol_up_hvr_25x27; -extern const Icon I_KeySave_24x11; -extern const Icon I_KeyBackspaceSelected_16x9; +extern const Icon I_IrdaLearnShort_128x31; +extern const Icon I_IrdaSend_128x64; +extern const Icon I_DolphinReadingSuccess_59x63; +extern const Icon I_Mute_hvr_25x27; +extern const Icon I_Back_15x10; +extern const Icon I_Up_25x27; +extern const Icon I_IrdaArrowUp_4x8; +extern const Icon I_Mute_25x27; +extern const Icon I_Power_25x27; +extern const Icon I_IrdaSendShort_128x34; +extern const Icon I_IrdaArrowDown_4x8; +extern const Icon I_IrdaLearn_128x64; +extern const Icon I_Power_hvr_25x27; extern const Icon I_KeySaveSelected_24x11; extern const Icon I_KeyBackspace_16x9; +extern const Icon I_KeyBackspaceSelected_16x9; +extern const Icon I_KeySave_24x11; extern const Icon A_125khz_14; extern const Icon A_Bluetooth_14; extern const Icon A_Debug_14; @@ -82,44 +83,44 @@ extern const Icon A_U2F_14; extern const Icon A_iButton_14; extern const Icon I_Detailed_chip_17x13; extern const Icon I_Medium_chip_22x21; -extern const Icon I_Health_16x16; -extern const Icon I_FaceCharging_29x14; extern const Icon I_BatteryBody_52x28; -extern const Icon I_Voltage_16x16; +extern const Icon I_FaceCharging_29x14; +extern const Icon I_Health_16x16; extern const Icon I_Temperature_16x16; -extern const Icon I_FaceNopower_29x14; -extern const Icon I_FaceNormal_29x14; extern const Icon I_Battery_16x16; extern const Icon I_FaceConfused_29x14; -extern const Icon I_RFIDDolphinSuccess_108x57; -extern const Icon I_RFIDBigChip_37x36; +extern const Icon I_FaceNormal_29x14; +extern const Icon I_Voltage_16x16; +extern const Icon I_FaceNopower_29x14; extern const Icon I_RFIDDolphinSend_97x61; +extern const Icon I_RFIDDolphinSuccess_108x57; extern const Icon I_RFIDDolphinReceive_97x61; +extern const Icon I_RFIDBigChip_37x36; extern const Icon I_SDQuestion_35x43; extern const Icon I_SDError_43x35; extern const Icon I_Cry_dolph_55x52; -extern const Icon I_BadUsb_9x8; -extern const Icon I_PlaceholderR_30x13; -extern const Icon I_Background_128x8; +extern const Icon I_Background_128x11; extern const Icon I_Lock_8x8; extern const Icon I_Battery_26x8; -extern const Icon I_PlaceholderL_11x13; extern const Icon I_Battery_19x8; -extern const Icon I_SDcardMounted_11x8; -extern const Icon I_SDcardFail_11x8; extern const Icon I_USBConnected_15x8; -extern const Icon I_Bluetooth_5x8; +extern const Icon I_Background_128x8; +extern const Icon I_BadUsb_9x8; extern const Icon I_BT_Pair_9x8; -extern const Icon I_Background_128x11; -extern const Icon I_Scanning_123x52; +extern const Icon I_PlaceholderL_11x13; +extern const Icon I_SDcardFail_11x8; +extern const Icon I_Bluetooth_5x8; +extern const Icon I_PlaceholderR_30x13; +extern const Icon I_SDcardMounted_11x8; extern const Icon I_Quest_7x8; -extern const Icon I_Unlock_7x8; -extern const Icon I_MHz_25x11; extern const Icon I_Lock_7x8; -extern const Icon I_DolphinMafia_115x62; -extern const Icon I_DolphinExcited_64x63; -extern const Icon I_iButtonDolphinSuccess_109x60; -extern const Icon I_iButtonDolphinVerySuccess_108x52; +extern const Icon I_Scanning_123x52; +extern const Icon I_MHz_25x11; +extern const Icon I_Unlock_7x8; extern const Icon I_iButtonKey_49x44; -extern const Icon I_DolphinNice_96x59; +extern const Icon I_DolphinExcited_64x63; extern const Icon I_DolphinWait_61x59; +extern const Icon I_iButtonDolphinVerySuccess_108x52; +extern const Icon I_DolphinMafia_115x62; +extern const Icon I_DolphinNice_96x59; +extern const Icon I_iButtonDolphinSuccess_109x60; diff --git a/assets/compiled/flipper.pb.h b/assets/compiled/flipper.pb.h index bb2a3535..161b969d 100644 --- a/assets/compiled/flipper.pb.h +++ b/assets/compiled/flipper.pb.h @@ -7,6 +7,7 @@ #include "storage.pb.h" #include "status.pb.h" #include "application.pb.h" +#include "gui.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. @@ -15,12 +16,14 @@ /* Enum definitions */ typedef enum _PB_CommandStatus { PB_CommandStatus_OK = 0, + /* *< Common Errors */ PB_CommandStatus_ERROR = 1, /* *< Unknown error */ PB_CommandStatus_ERROR_DECODE = 2, /* *< Command can't be decoded successfully - command_id in response may be wrong! */ PB_CommandStatus_ERROR_NOT_IMPLEMENTED = 3, /* *< Command succesfully decoded, but not implemented (deprecated or not yet implemented) */ PB_CommandStatus_ERROR_BUSY = 4, /* *< Somebody took global lock, so not all commands are available */ PB_CommandStatus_ERROR_CONTINUOUS_COMMAND_INTERRUPTED = 14, /* *< Not received has_next == 0 */ PB_CommandStatus_ERROR_INVALID_PARAMETERS = 15, /* *< not provided (or provided invalid) crucial parameters to perform rpc */ + /* *< Storage Errors */ PB_CommandStatus_ERROR_STORAGE_NOT_READY = 5, /* *< FS not ready */ PB_CommandStatus_ERROR_STORAGE_EXIST = 6, /* *< File/Dir alrady exist */ PB_CommandStatus_ERROR_STORAGE_NOT_EXIST = 7, /* *< File/Dir does not exist */ @@ -31,6 +34,7 @@ typedef enum _PB_CommandStatus { PB_CommandStatus_ERROR_STORAGE_NOT_IMPLEMENTED = 12, /* *< Functon not implemented */ PB_CommandStatus_ERROR_STORAGE_ALREADY_OPEN = 13, /* *< File/Dir already opened */ PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY = 18, /* *< Directory, you're going to remove is not empty */ + /* *< Application Errors */ PB_CommandStatus_ERROR_APP_CANT_START = 16, /* *< Can't start app - internal error */ PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED = 17 /* *< Another app is running */ } PB_CommandStatus; @@ -66,10 +70,16 @@ typedef struct _PB_Main { PB_Storage_MkdirRequest storage_mkdir_request; PB_Storage_Md5sumRequest storage_md5sum_request; PB_Storage_Md5sumResponse storage_md5sum_response; - PB_App_Start app_start; + PB_App_StartRequest app_start_request; PB_App_LockStatusRequest app_lock_status_request; PB_App_LockStatusResponse app_lock_status_response; PB_StopSession stop_session; + PB_Gui_StartScreenStreamRequest gui_start_screen_stream_request; + PB_Gui_StopScreenStreamRequest gui_stop_screen_stream_request; + PB_Gui_ScreenStreamFrame gui_screen_stream_frame; + PB_Gui_SendInputEventRequest gui_send_input_event_request; + PB_Storage_StatRequest storage_stat_request; + PB_Storage_StatResponse storage_stat_response; } content; } PB_Main; @@ -108,10 +118,16 @@ extern "C" { #define PB_Main_storage_mkdir_request_tag 13 #define PB_Main_storage_md5sum_request_tag 14 #define PB_Main_storage_md5sum_response_tag 15 -#define PB_Main_app_start_tag 16 +#define PB_Main_app_start_request_tag 16 #define PB_Main_app_lock_status_request_tag 17 #define PB_Main_app_lock_status_response_tag 18 #define PB_Main_stop_session_tag 19 +#define PB_Main_gui_start_screen_stream_request_tag 20 +#define PB_Main_gui_stop_screen_stream_request_tag 21 +#define PB_Main_gui_screen_stream_frame_tag 22 +#define PB_Main_gui_send_input_event_request_tag 23 +#define PB_Main_storage_stat_request_tag 24 +#define PB_Main_storage_stat_response_tag 25 /* Struct field encoding specification for nanopb */ #define PB_Empty_FIELDLIST(X, a) \ @@ -140,10 +156,16 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_delete_request,content.stora X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_mkdir_request,content.storage_mkdir_request), 13) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_md5sum_request,content.storage_md5sum_request), 14) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_md5sum_response,content.storage_md5sum_response), 15) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,app_start,content.app_start), 16) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,app_start_request,content.app_start_request), 16) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,app_lock_status_request,content.app_lock_status_request), 17) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,app_lock_status_response,content.app_lock_status_response), 18) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,stop_session,content.stop_session), 19) +X(a, STATIC, ONEOF, MSG_W_CB, (content,stop_session,content.stop_session), 19) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_start_screen_stream_request,content.gui_start_screen_stream_request), 20) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_stop_screen_stream_request,content.gui_stop_screen_stream_request), 21) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_screen_stream_frame,content.gui_screen_stream_frame), 22) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_send_input_event_request,content.gui_send_input_event_request), 23) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_stat_request,content.storage_stat_request), 24) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_stat_response,content.storage_stat_response), 25) #define PB_Main_CALLBACK NULL #define PB_Main_DEFAULT NULL #define PB_Main_content_empty_MSGTYPE PB_Empty @@ -158,10 +180,16 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,stop_session,content.stop_session), #define PB_Main_content_storage_mkdir_request_MSGTYPE PB_Storage_MkdirRequest #define PB_Main_content_storage_md5sum_request_MSGTYPE PB_Storage_Md5sumRequest #define PB_Main_content_storage_md5sum_response_MSGTYPE PB_Storage_Md5sumResponse -#define PB_Main_content_app_start_MSGTYPE PB_App_Start +#define PB_Main_content_app_start_request_MSGTYPE PB_App_StartRequest #define PB_Main_content_app_lock_status_request_MSGTYPE PB_App_LockStatusRequest #define PB_Main_content_app_lock_status_response_MSGTYPE PB_App_LockStatusResponse #define PB_Main_content_stop_session_MSGTYPE PB_StopSession +#define PB_Main_content_gui_start_screen_stream_request_MSGTYPE PB_Gui_StartScreenStreamRequest +#define PB_Main_content_gui_stop_screen_stream_request_MSGTYPE PB_Gui_StopScreenStreamRequest +#define PB_Main_content_gui_screen_stream_frame_MSGTYPE PB_Gui_ScreenStreamFrame +#define PB_Main_content_gui_send_input_event_request_MSGTYPE PB_Gui_SendInputEventRequest +#define PB_Main_content_storage_stat_request_MSGTYPE PB_Storage_StatRequest +#define PB_Main_content_storage_stat_response_MSGTYPE PB_Storage_StatResponse extern const pb_msgdesc_t PB_Empty_msg; extern const pb_msgdesc_t PB_StopSession_msg; @@ -175,9 +203,9 @@ extern const pb_msgdesc_t PB_Main_msg; /* Maximum encoded size of messages (where known) */ #define PB_Empty_size 0 #define PB_StopSession_size 0 -#if defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_Start_size) +#if defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenStreamFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) #define PB_Main_size (10 + sizeof(union PB_Main_content_size_union)) -union PB_Main_content_size_union {char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_Start_size)]; char f0[36];}; +union PB_Main_content_size_union {char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenStreamFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f0[36];}; #endif #ifdef __cplusplus diff --git a/assets/compiled/gui.pb.c b/assets/compiled/gui.pb.c new file mode 100644 index 00000000..ecc8a647 --- /dev/null +++ b/assets/compiled/gui.pb.c @@ -0,0 +1,23 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "gui.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(PB_Gui_StartScreenStreamRequest, PB_Gui_StartScreenStreamRequest, AUTO) + + +PB_BIND(PB_Gui_StopScreenStreamRequest, PB_Gui_StopScreenStreamRequest, AUTO) + + +PB_BIND(PB_Gui_ScreenStreamFrame, PB_Gui_ScreenStreamFrame, AUTO) + + +PB_BIND(PB_Gui_SendInputEventRequest, PB_Gui_SendInputEventRequest, AUTO) + + + + + diff --git a/assets/compiled/gui.pb.h b/assets/compiled/gui.pb.h new file mode 100644 index 00000000..abb702fb --- /dev/null +++ b/assets/compiled/gui.pb.h @@ -0,0 +1,121 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_PB_GUI_GUI_PB_H_INCLUDED +#define PB_PB_GUI_GUI_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _PB_Gui_InputKey { + PB_Gui_InputKey_UP = 0, + PB_Gui_InputKey_DOWN = 1, + PB_Gui_InputKey_RIGHT = 2, + PB_Gui_InputKey_LEFT = 3, + PB_Gui_InputKey_OK = 4, + PB_Gui_InputKey_BACK = 5 +} PB_Gui_InputKey; + +typedef enum _PB_Gui_InputType { + PB_Gui_InputType_PRESS = 0, /* *< Press event, emitted after debounce */ + PB_Gui_InputType_RELEASE = 1, /* *< Release event, emitted after debounce */ + PB_Gui_InputType_SHORT = 2, /* *< Short event, emitted after InputTypeRelease done withing INPUT_LONG_PRESS interval */ + PB_Gui_InputType_LONG = 3, /* *< Long event, emmited after INPUT_LONG_PRESS interval, asynchronouse to InputTypeRelease */ + PB_Gui_InputType_REPEAT = 4 /* *< Repeat event, emmited with INPUT_REPEATE_PRESS period after InputTypeLong event */ +} PB_Gui_InputType; + +/* Struct definitions */ +typedef struct _PB_Gui_ScreenStreamFrame { + pb_bytes_array_t *data; +} PB_Gui_ScreenStreamFrame; + +typedef struct _PB_Gui_StartScreenStreamRequest { + char dummy_field; +} PB_Gui_StartScreenStreamRequest; + +typedef struct _PB_Gui_StopScreenStreamRequest { + char dummy_field; +} PB_Gui_StopScreenStreamRequest; + +typedef struct _PB_Gui_SendInputEventRequest { + PB_Gui_InputKey key; + PB_Gui_InputType type; +} PB_Gui_SendInputEventRequest; + + +/* Helper constants for enums */ +#define _PB_Gui_InputKey_MIN PB_Gui_InputKey_UP +#define _PB_Gui_InputKey_MAX PB_Gui_InputKey_BACK +#define _PB_Gui_InputKey_ARRAYSIZE ((PB_Gui_InputKey)(PB_Gui_InputKey_BACK+1)) + +#define _PB_Gui_InputType_MIN PB_Gui_InputType_PRESS +#define _PB_Gui_InputType_MAX PB_Gui_InputType_REPEAT +#define _PB_Gui_InputType_ARRAYSIZE ((PB_Gui_InputType)(PB_Gui_InputType_REPEAT+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define PB_Gui_StartScreenStreamRequest_init_default {0} +#define PB_Gui_StopScreenStreamRequest_init_default {0} +#define PB_Gui_ScreenStreamFrame_init_default {NULL} +#define PB_Gui_SendInputEventRequest_init_default {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} +#define PB_Gui_StartScreenStreamRequest_init_zero {0} +#define PB_Gui_StopScreenStreamRequest_init_zero {0} +#define PB_Gui_ScreenStreamFrame_init_zero {NULL} +#define PB_Gui_SendInputEventRequest_init_zero {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define PB_Gui_ScreenStreamFrame_data_tag 1 +#define PB_Gui_SendInputEventRequest_key_tag 1 +#define PB_Gui_SendInputEventRequest_type_tag 2 + +/* Struct field encoding specification for nanopb */ +#define PB_Gui_StartScreenStreamRequest_FIELDLIST(X, a) \ + +#define PB_Gui_StartScreenStreamRequest_CALLBACK NULL +#define PB_Gui_StartScreenStreamRequest_DEFAULT NULL + +#define PB_Gui_StopScreenStreamRequest_FIELDLIST(X, a) \ + +#define PB_Gui_StopScreenStreamRequest_CALLBACK NULL +#define PB_Gui_StopScreenStreamRequest_DEFAULT NULL + +#define PB_Gui_ScreenStreamFrame_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, BYTES, data, 1) +#define PB_Gui_ScreenStreamFrame_CALLBACK NULL +#define PB_Gui_ScreenStreamFrame_DEFAULT NULL + +#define PB_Gui_SendInputEventRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, key, 1) \ +X(a, STATIC, SINGULAR, UENUM, type, 2) +#define PB_Gui_SendInputEventRequest_CALLBACK NULL +#define PB_Gui_SendInputEventRequest_DEFAULT NULL + +extern const pb_msgdesc_t PB_Gui_StartScreenStreamRequest_msg; +extern const pb_msgdesc_t PB_Gui_StopScreenStreamRequest_msg; +extern const pb_msgdesc_t PB_Gui_ScreenStreamFrame_msg; +extern const pb_msgdesc_t PB_Gui_SendInputEventRequest_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define PB_Gui_StartScreenStreamRequest_fields &PB_Gui_StartScreenStreamRequest_msg +#define PB_Gui_StopScreenStreamRequest_fields &PB_Gui_StopScreenStreamRequest_msg +#define PB_Gui_ScreenStreamFrame_fields &PB_Gui_ScreenStreamFrame_msg +#define PB_Gui_SendInputEventRequest_fields &PB_Gui_SendInputEventRequest_msg + +/* Maximum encoded size of messages (where known) */ +/* PB_Gui_ScreenStreamFrame_size depends on runtime parameters */ +#define PB_Gui_SendInputEventRequest_size 4 +#define PB_Gui_StartScreenStreamRequest_size 0 +#define PB_Gui_StopScreenStreamRequest_size 0 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/assets/compiled/input.pb.c b/assets/compiled/input.pb.c new file mode 100644 index 00000000..6ce50704 --- /dev/null +++ b/assets/compiled/input.pb.c @@ -0,0 +1,14 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "input.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(PB_Input_SendEventRequest, PB_Input_SendEventRequest, AUTO) + + + + + diff --git a/assets/compiled/input.pb.h b/assets/compiled/input.pb.h new file mode 100644 index 00000000..46f78113 --- /dev/null +++ b/assets/compiled/input.pb.h @@ -0,0 +1,78 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_PB_INPUT_INPUT_PB_H_INCLUDED +#define PB_PB_INPUT_INPUT_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _PB_Input_Key { + PB_Input_Key_UP = 0, + PB_Input_Key_DOWN = 1, + PB_Input_Key_RIGHT = 2, + PB_Input_Key_LEFT = 3, + PB_Input_Key_OK = 4, + PB_Input_Key_BACK = 5 +} PB_Input_Key; + +typedef enum _PB_Input_Type { + PB_Input_Type_PRESS = 0, /* *< Press event, emitted after debounce */ + PB_Input_Type_RELEASE = 1, /* *< Release event, emitted after debounce */ + PB_Input_Type_SHORT = 2, /* *< Short event, emitted after InputTypeRelease done withing INPUT_LONG_PRESS interval */ + PB_Input_Type_LONG = 3, /* *< Long event, emmited after INPUT_LONG_PRESS interval, asynchronouse to InputTypeRelease */ + PB_Input_Type_REPEAT = 4 /* *< Repeat event, emmited with INPUT_REPEATE_PRESS period after InputTypeLong event */ +} PB_Input_Type; + +/* Struct definitions */ +typedef struct _PB_Input_SendEventRequest { + PB_Input_Key key; + PB_Input_Type type; +} PB_Input_SendEventRequest; + + +/* Helper constants for enums */ +#define _PB_Input_Key_MIN PB_Input_Key_UP +#define _PB_Input_Key_MAX PB_Input_Key_BACK +#define _PB_Input_Key_ARRAYSIZE ((PB_Input_Key)(PB_Input_Key_BACK+1)) + +#define _PB_Input_Type_MIN PB_Input_Type_PRESS +#define _PB_Input_Type_MAX PB_Input_Type_REPEAT +#define _PB_Input_Type_ARRAYSIZE ((PB_Input_Type)(PB_Input_Type_REPEAT+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define PB_Input_SendEventRequest_init_default {_PB_Input_Key_MIN, _PB_Input_Type_MIN} +#define PB_Input_SendEventRequest_init_zero {_PB_Input_Key_MIN, _PB_Input_Type_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define PB_Input_SendEventRequest_key_tag 1 +#define PB_Input_SendEventRequest_type_tag 2 + +/* Struct field encoding specification for nanopb */ +#define PB_Input_SendEventRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, key, 1) \ +X(a, STATIC, SINGULAR, UENUM, type, 2) +#define PB_Input_SendEventRequest_CALLBACK NULL +#define PB_Input_SendEventRequest_DEFAULT NULL + +extern const pb_msgdesc_t PB_Input_SendEventRequest_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define PB_Input_SendEventRequest_fields &PB_Input_SendEventRequest_msg + +/* Maximum encoded size of messages (where known) */ +#define PB_Input_SendEventRequest_size 4 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/assets/compiled/screen.pb.c b/assets/compiled/screen.pb.c new file mode 100644 index 00000000..a87a3dd6 --- /dev/null +++ b/assets/compiled/screen.pb.c @@ -0,0 +1,18 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "screen.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(PB_Screen_StartStreamRequest, PB_Screen_StartStreamRequest, AUTO) + + +PB_BIND(PB_Screen_StopStreamRequest, PB_Screen_StopStreamRequest, AUTO) + + +PB_BIND(PB_Screen_StreamFrame, PB_Screen_StreamFrame, AUTO) + + + diff --git a/assets/compiled/screen.pb.h b/assets/compiled/screen.pb.h new file mode 100644 index 00000000..1c409a6f --- /dev/null +++ b/assets/compiled/screen.pb.h @@ -0,0 +1,75 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_PB_SCREEN_SCREEN_PB_H_INCLUDED +#define PB_PB_SCREEN_SCREEN_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +typedef struct _PB_Screen_StartStreamRequest { + char dummy_field; +} PB_Screen_StartStreamRequest; + +typedef struct _PB_Screen_StopStreamRequest { + char dummy_field; +} PB_Screen_StopStreamRequest; + +typedef struct _PB_Screen_StreamFrame { + pb_bytes_array_t *data; +} PB_Screen_StreamFrame; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define PB_Screen_StartStreamRequest_init_default {0} +#define PB_Screen_StopStreamRequest_init_default {0} +#define PB_Screen_StreamFrame_init_default {NULL} +#define PB_Screen_StartStreamRequest_init_zero {0} +#define PB_Screen_StopStreamRequest_init_zero {0} +#define PB_Screen_StreamFrame_init_zero {NULL} + +/* Field tags (for use in manual encoding/decoding) */ +#define PB_Screen_StreamFrame_data_tag 1 + +/* Struct field encoding specification for nanopb */ +#define PB_Screen_StartStreamRequest_FIELDLIST(X, a) \ + +#define PB_Screen_StartStreamRequest_CALLBACK NULL +#define PB_Screen_StartStreamRequest_DEFAULT NULL + +#define PB_Screen_StopStreamRequest_FIELDLIST(X, a) \ + +#define PB_Screen_StopStreamRequest_CALLBACK NULL +#define PB_Screen_StopStreamRequest_DEFAULT NULL + +#define PB_Screen_StreamFrame_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, BYTES, data, 1) +#define PB_Screen_StreamFrame_CALLBACK NULL +#define PB_Screen_StreamFrame_DEFAULT NULL + +extern const pb_msgdesc_t PB_Screen_StartStreamRequest_msg; +extern const pb_msgdesc_t PB_Screen_StopStreamRequest_msg; +extern const pb_msgdesc_t PB_Screen_StreamFrame_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define PB_Screen_StartStreamRequest_fields &PB_Screen_StartStreamRequest_msg +#define PB_Screen_StopStreamRequest_fields &PB_Screen_StopStreamRequest_msg +#define PB_Screen_StreamFrame_fields &PB_Screen_StreamFrame_msg + +/* Maximum encoded size of messages (where known) */ +/* PB_Screen_StreamFrame_size depends on runtime parameters */ +#define PB_Screen_StartStreamRequest_size 0 +#define PB_Screen_StopStreamRequest_size 0 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/assets/compiled/storage.pb.c b/assets/compiled/storage.pb.c index a74477e1..24577c23 100644 --- a/assets/compiled/storage.pb.c +++ b/assets/compiled/storage.pb.c @@ -9,6 +9,12 @@ PB_BIND(PB_Storage_File, PB_Storage_File, AUTO) +PB_BIND(PB_Storage_StatRequest, PB_Storage_StatRequest, AUTO) + + +PB_BIND(PB_Storage_StatResponse, PB_Storage_StatResponse, AUTO) + + PB_BIND(PB_Storage_ListRequest, PB_Storage_ListRequest, AUTO) diff --git a/assets/compiled/storage.pb.h b/assets/compiled/storage.pb.h index ea6291b9..2e82a8de 100644 --- a/assets/compiled/storage.pb.h +++ b/assets/compiled/storage.pb.h @@ -32,6 +32,10 @@ typedef struct _PB_Storage_ReadRequest { char *path; } PB_Storage_ReadRequest; +typedef struct _PB_Storage_StatRequest { + char *path; +} PB_Storage_StatRequest; + typedef struct _PB_Storage_DeleteRequest { char *path; bool recursive; @@ -58,6 +62,11 @@ typedef struct _PB_Storage_ReadResponse { PB_Storage_File file; } PB_Storage_ReadResponse; +typedef struct _PB_Storage_StatResponse { + bool has_file; + PB_Storage_File file; +} PB_Storage_StatResponse; + typedef struct _PB_Storage_WriteRequest { char *path; bool has_file; @@ -77,6 +86,8 @@ extern "C" { /* Initializer values for message structs */ #define PB_Storage_File_init_default {_PB_Storage_File_FileType_MIN, NULL, 0, NULL} +#define PB_Storage_StatRequest_init_default {NULL} +#define PB_Storage_StatResponse_init_default {false, PB_Storage_File_init_default} #define PB_Storage_ListRequest_init_default {NULL} #define PB_Storage_ListResponse_init_default {0, {PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default}} #define PB_Storage_ReadRequest_init_default {NULL} @@ -87,6 +98,8 @@ extern "C" { #define PB_Storage_Md5sumRequest_init_default {NULL} #define PB_Storage_Md5sumResponse_init_default {""} #define PB_Storage_File_init_zero {_PB_Storage_File_FileType_MIN, NULL, 0, NULL} +#define PB_Storage_StatRequest_init_zero {NULL} +#define PB_Storage_StatResponse_init_zero {false, PB_Storage_File_init_zero} #define PB_Storage_ListRequest_init_zero {NULL} #define PB_Storage_ListResponse_init_zero {0, {PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero}} #define PB_Storage_ReadRequest_init_zero {NULL} @@ -102,6 +115,7 @@ extern "C" { #define PB_Storage_Md5sumRequest_path_tag 1 #define PB_Storage_MkdirRequest_path_tag 1 #define PB_Storage_ReadRequest_path_tag 1 +#define PB_Storage_StatRequest_path_tag 1 #define PB_Storage_DeleteRequest_path_tag 1 #define PB_Storage_DeleteRequest_recursive_tag 2 #define PB_Storage_File_type_tag 1 @@ -111,6 +125,7 @@ extern "C" { #define PB_Storage_Md5sumResponse_md5sum_tag 1 #define PB_Storage_ListResponse_file_tag 1 #define PB_Storage_ReadResponse_file_tag 1 +#define PB_Storage_StatResponse_file_tag 1 #define PB_Storage_WriteRequest_path_tag 1 #define PB_Storage_WriteRequest_file_tag 2 @@ -123,6 +138,17 @@ X(a, POINTER, SINGULAR, BYTES, data, 4) #define PB_Storage_File_CALLBACK NULL #define PB_Storage_File_DEFAULT NULL +#define PB_Storage_StatRequest_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, STRING, path, 1) +#define PB_Storage_StatRequest_CALLBACK NULL +#define PB_Storage_StatRequest_DEFAULT NULL + +#define PB_Storage_StatResponse_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, file, 1) +#define PB_Storage_StatResponse_CALLBACK NULL +#define PB_Storage_StatResponse_DEFAULT NULL +#define PB_Storage_StatResponse_file_MSGTYPE PB_Storage_File + #define PB_Storage_ListRequest_FIELDLIST(X, a) \ X(a, POINTER, SINGULAR, STRING, path, 1) #define PB_Storage_ListRequest_CALLBACK NULL @@ -174,6 +200,8 @@ X(a, STATIC, SINGULAR, STRING, md5sum, 1) #define PB_Storage_Md5sumResponse_DEFAULT NULL extern const pb_msgdesc_t PB_Storage_File_msg; +extern const pb_msgdesc_t PB_Storage_StatRequest_msg; +extern const pb_msgdesc_t PB_Storage_StatResponse_msg; extern const pb_msgdesc_t PB_Storage_ListRequest_msg; extern const pb_msgdesc_t PB_Storage_ListResponse_msg; extern const pb_msgdesc_t PB_Storage_ReadRequest_msg; @@ -186,6 +214,8 @@ extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_Storage_File_fields &PB_Storage_File_msg +#define PB_Storage_StatRequest_fields &PB_Storage_StatRequest_msg +#define PB_Storage_StatResponse_fields &PB_Storage_StatResponse_msg #define PB_Storage_ListRequest_fields &PB_Storage_ListRequest_msg #define PB_Storage_ListResponse_fields &PB_Storage_ListResponse_msg #define PB_Storage_ReadRequest_fields &PB_Storage_ReadRequest_msg @@ -198,6 +228,8 @@ extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg; /* Maximum encoded size of messages (where known) */ /* PB_Storage_File_size depends on runtime parameters */ +/* PB_Storage_StatRequest_size depends on runtime parameters */ +/* PB_Storage_StatResponse_size depends on runtime parameters */ /* PB_Storage_ListRequest_size depends on runtime parameters */ /* PB_Storage_ListResponse_size depends on runtime parameters */ /* PB_Storage_ReadRequest_size depends on runtime parameters */ diff --git a/assets/icons/Irda/DolphinReadingSuccess_59x63.png b/assets/icons/Irda/DolphinReadingSuccess_59x63.png new file mode 100644 index 00000000..46f559f6 Binary files /dev/null and b/assets/icons/Irda/DolphinReadingSuccess_59x63.png differ diff --git a/assets/protobuf b/assets/protobuf index 021ba48a..0e6d374a 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 021ba48abb64d25c7094da13b752fe37d4bf6007 +Subproject commit 0e6d374ab1a12f95a3cd04444376a261e7252db4 diff --git a/assets/resources/subghz/came_atomo b/assets/resources/subghz/came_atomo new file mode 100644 index 00000000..0952f3f2 --- /dev/null +++ b/assets/resources/subghz/came_atomo @@ -0,0 +1,6 @@ +Filetype: Flipper SubGhz Keystore RAW File +Version: 0 +Encryption: 1 +IV: 47 69 6D 6D 65 20 74 68 65 63 6F 6F 6B 69 65 73 +Encrypt_data: RAW +E0BDF15D68F29AE787E7FCEE6C3611C90A92305D677B8FFFBE225196F5DC04CAEAE1102B4AB830E76C9C14DBA7FA5BD1F30864ABAF51387222FDCC0BA87E4FF709812D5C59DD953859AFD698A0EA2ECEFA0DC49652861EF4CF1864843F135DB8680E0C5C9EEC3BC548E2EB696DC8CA1B0F627347D2C476B410CF03A0F4D1EFB36DFB0574FE8F48FB61910CA539EC04583CA170A51822225A1D3E86C07219FE92E5DE9F557A45E611D74028BAF56E7F2C53DBA8DC53DA89B642FAC0A9A0BAC1756BDA0833ACB09F56E0FA3080CBE9E6A04B235F3AC82BB955FBFD779C59725E6D1875E04E0E84ABD0C3C1C8FAB247EC2755ACEC9961244E0D79AE710E4C7D33E9 \ No newline at end of file diff --git a/assets/resources/subghz/keeloq_mfcodes b/assets/resources/subghz/keeloq_mfcodes new file mode 100644 index 00000000..9f5ff755 --- /dev/null +++ b/assets/resources/subghz/keeloq_mfcodes @@ -0,0 +1,27 @@ +Filetype: Flipper SubGhz Keystore File +Version: 0 +Encryption: 1 +IV: 7A 44 FE 5D C3 B3 65 13 73 A6 F4 2D 1E B6 7D F0 +89153B35033574AAA06D7E792CB92A486B37A2CCDF0B0152BF1A563E321518C8 +F6583A3E4148439E8A8D7ED6A095ACC0C3E22A48F1637E78DF023CAC9272934E +AA0439E6B76CD43F3FCC27CF69C5F3B6508E8103B164E4ECDDF8B2FB222D46FF +A9826C663033D25AE21CB8790406997ADCE84360B258F2B989D967009659859C +3474E7BBFA0173928F414CFD5EE19B27A558D9C171D96FE7B7840A01323A7E7446FAE3E98EA9A8C69B4A6B781BD7906A +2873939A8E0EAC16D748967E987BB0F1079C106E4235B7D35B4BF37F54B21F8E +EF6F1DC0201FCB8CEBC5642A5194A1FDCFBE1FA772A79CEAD54D2F0DA3AC4F6C +3F595EAA0E81E96C5D6DB41799D314E3E81E7F4197E19A3341C55592B1B6C4B0 +7B2D75FE11B27E99CA7610E47D712C8CFB619EC69EBC976A70CFD9574C9F4FF8 +39735CF1D009D132A33B9C546D95FA6D3E69BF3A57EF219392E57C9560E7B037 +D56FDDFB0C4E808143D3ED5F15D6FF47F6EDEBD01192FC7ACF3ACCE9FD5162FC297D0089D65ED2CBE3CE05DDA7B96446 +2750D4F0650061C3AF72C88FD080BE241F2BDD8D8C1B0EFE781120EBEFFE2C72D0EECC42CDDED50CFE4AC51C48AE68C6 +F8CE64921CB73015F2672A9EF0A8359269CAE0E515D6DBB3130CFC9E5E1A98AD +ACF6ADB9E02D67B44EB6C6F126BF64BDAB37926B8BE39E27F323E8F5A0F8FC38 +FBB1302D697F94ECED681CE047819001EDE6E013850258F61E97091DD37D24F2 +D8CD53AB5A94898EB53D4FF46546ADBAA24691181A396052A58AAC657D6817AB +43200E08C21747CABC59538888A259238E782545732A1A6EEE00A6929EC9DD97A8BA9812372374046AC66652CC561D60 +C38CBE29F22D0E83E58A52E94AA2485DA8E702FBDB89D27249473CB8A19AEF61 +9F0EB580F7474985E8460E1682451E213778B77A9CAB4734B75C5386851050BF +2364EBB8237363B21226565675B9F478482CADAE41E795C27287E26137797C10 +775C9A28BA50D759FB438D0200121F01F7DB11986D44D3960F745EAA1E7A2CE2AD92AD718AFCD98BC3269C39F65ADC53 +6911E7EAFFAC15B4E3ABDAD271E92EAEFE1F2E288789EC7599AAA32986273306 +5387D67534234AFD8BAB90DC74BA39598B938526CBFAF14F75AA36A29C13836A31897A86D2E1178AE66191E771A7FEA4 diff --git a/assets/resources/subghz/keeloq_mfcodes_user b/assets/resources/subghz/keeloq_mfcodes_user new file mode 100644 index 00000000..6361d85e --- /dev/null +++ b/assets/resources/subghz/keeloq_mfcodes_user @@ -0,0 +1,11 @@ +# for adding manufacture keys +# AABBCCDDEEFFAABB:X:NAME\r\n +# AABBCCDDEEFFAABB - man 64 bit +# X - encryption method 1 - Simple Learning, 2 - Normal_Learning, +# 0 - iterates over both previous and man in direct and reverse byte sequence +# NAME - name (string without spaces) max 64 characters long +Filetype: Flipper SubGhz Keystore File +Version: 0 +Encryption: 0 +AABBCCDDEEFFAABB:1:Test1 +AABBCCDDEEFFAABB:1:Test2 diff --git a/assets/resources/subghz/nice_flor_s_rx b/assets/resources/subghz/nice_flor_s_rx new file mode 100644 index 00000000..e63e47b0 --- /dev/null +++ b/assets/resources/subghz/nice_flor_s_rx @@ -0,0 +1,6 @@ +Filetype: Flipper SubGhz Keystore RAW File +Version: 0 +Encryption: 1 +IV: 47 69 6D 6D 65 20 74 68 65 63 6F 6F 6B 69 65 73 +Encrypt_data: RAW +7AE3DA5A4EBC89793AEFA8357F83A8577E08EBFE9312BAB9DDA0AF36A85569296DA4AA955D97B2489F84A4AA075ABEFF2A94A5AA315D15778FC003A224096B58AF8FC76FA5B4AFAD1EFA5484CA13835045FE9C1AA0678E690FC61806D731E968637CB7FF2C4D643971B06676B3C9E6CD0D49C4CCB6E4E61BFA1D314297BB8517D8773E0EECF090933AD78DB444BB210388DEEB464034D21DA08248C79A2E39B4472FCE441FB257B574CAEE240E3345F6E11FD4BCD91FD8D8E173DD2E60E545A9991659D551D95FE027561AA5DDE8B3F114DDB00F2D1B97257851D43CE6C2174A11CFF15146F30F82F6DD3E40379B7F33852C78206A521A209B5211471E75A0CA7B49765EDB88F18305D5F511ADFD3471811E71C8681F90C7DF3FD0C787A8226828D54C6F64895DD6E777A7B904406BBB80A05DEA9C7CF0D491F033446808CE4214F4B31C03CC6B7DD6ADF02CD0F9BC1690C9B098720DF786186C9EDE8AE318D2EDD0D2BBFDE2CBEC9FD65C612CAFEEE97CD137AF3B5074FF0B0D134A8A14EE54FCDE569203E3936D7B51B0580FF041676AAB46FBF7F15462BB5DC2ECC323D2E781053DFADC59174784BCD5D34A56E92A8A5C1F2A849FB620024EC0434FCE1D465AFE92440004ED48CD2FF97041803C5E077EAB823BA0A98A3853CD1C6C7AC33A502D69B5B7119EB4AA486B6BEB30470730F8D6B058527FE4DA45287A8E6F076D6AA32DBCE9E127D8E32269ABA1B26E70DF64F3B34E64C92C09E62EB25AB92843D0230F95F9703CA2CFD3E2B3CAAB2E77467D594E9BBCB1CE0E2FE5575AD98E75AA3AE58145F14A90B99B6B70BBAF46162A6774C550722B2A08B8007F6DB4EBE103984996EFC6534AADD0C354881FEB0DD06BEE6547175D4BDE128DFDD2FFFDEF3143F35F282F2B05B3763ABFA2B6E40C109764084DA53469FED9E7354C4DD87090205C4684209755BCCDC75F492D31C47748A18CF9EE60D1A7989918C3095090280283C414BEA5D06D08D25C3B3DCFF283C2936F81DA639BF314D8B0018D62C7AC35E6DA8379754965A72AC81A46AACE8B1C8BF44875EBDB325241760E510AFC5C56860547678F215DC082A099B7202ABE4F2D1F7D78CE89C0463EE4BD6F08BBD79AA1D06B7F76CCFA536E2D0BCD864ADA11F2923A194D679AC5C9B6B4A545EBF352DE4AB9F4758C22687FCA49BE8DAB772010530B389AAAED883D15A8B639930C3B667CF20098ECF8AC695520AA29A2484CEE93C8357B062CE1732A63BF47774397C52503E4B93E33BB2B77F45366A9FD2D9B6F0AD63912BC4881F7D6209B4F0AF10D65293B8CDCCA4FF7DC50F4589D1EB3146D239F4497141C711EAD7CF5DC276864743853E0D54CB535AB26C90819B49B500D04D64E9741527F3CD09D4E5B8E0AFB9F8A92772378D0C16D2E904F2912C3E5C06E8AA73139314595CFB9B331370ED015543F3E2855C8539CF938EA7C68DBE2C8DC3E0DF0CAA6396422A0179FA88F6872048A98BBAB3961A5039162AE3B84BF7316C72F1572FE09951EA35560F7BA164BC43CACF385D58DBAA240E9D260CC167EDE2821A581B6D699B0C6CB54BD69FC6EF2519811B50E01C33CF58FC2D625B8960E5E4A9C8FF7D306EE887F18A8EEE95D94B839BFADE4781860EA8A6A34ACF77BF12EF31993109CF25490D84B0488F35289A253C1EAE00DCB6F006223E4CE22389C6EB0FE540542E57A53E6EB6572CA93FD6BDA47D1CED573D2E2BB58BA2E04FD0D4B1BBC82A2E5CE309039968B3FA1492DBFEA86AAA64C7B3109A8B3BB7124A9C695C797067A78876157AC1AAF27632D036E7D65DE1F6C3B51D9DF7DEB21FD40DE6BA8CEFCC1B082E7FE829451E435F867173944F90D08C0B3B2DD59EDF530F3403B8B676A1738F1DCD0F3DDDEBE0E9E9057ADD974FF293130F0BD896991473E181C63311C6CDDCE75031FC9295BFB5781D28D22A0A17F3BB5A6512E6FB677539DE689E6B709B11470E77616FF61495B67A9BB7B4AE47A610B790DB276F69458D442AD6EA43F2F04819DEFF8B24E1488928F668EBA541E91A02701E375D757708D0E35ACD33C3B89A4D776EDB3962194AB3E2A6521A9A8EFAA7783083FC83BEB586A073A3CE424790B812EB6AC5E0B2E2B153C34352F41A89078BC7E9B976C2520F23E6398EFABB2C13A24113482E178A9BE1CDFD85D3CBC535AAC99D03B9ED324CD9FE5A4922061DCA2257DBABAC80AF9178163661FD11F1BA1D37FDEE95453F3C283B8EAFA22ABC72EE5EBAD0769B31B0FF7234147CDE12AE39DDD203EF172FA9983CDEF145FEFAA90AAB3F1E2F3233D54686A47DCEF2FF1EE98C5E261AB84E3BB9A16026B456B68A1097488A3C929BF99F68B93AEC2479E7C2EEF700AB484811568E8BC5ABA36873D90D9349A613608D028E82DAD79522FB2F60533607F668754F6CE08099173C9BE045BD46DC6D0AAFCEE48C902134579CB12E136FE6136981DD9200F418DF72169291645B5CC03B3C581840F5252F884A6C089BAA9228EA070F94DD9BA6606B1641BD5B9621945A5F9C39C2C107B2FEA1CD1796FB256A5CCAA3A8E86064FA7E9F56C32670F137AE73461A45E4911E17FFFF4C1B4E78043C31B9BA9C69CC8AF54D7F7076C41D0826066B075BA6EFC141520C00AE7F05743DBCB9A9319466641660BAC7E0C591DA133E5A4C778D4169E50A6757DC2B69168698F9A1824DA571C71E28A4141B6B664222FE3D88FF16487A18C3D738AF0DBDDDF66DB9F0A55F55A067D93F4C8C5BFC78E47ED5290BEDA49BFF40E0517AA4334CE36011A22118073E61F94AE34FFB9355625510DE74A2223F0B75CA9236BB514582A00E3A1F00B201CA0107C0D39C91B7AD507FEDDB346F815EEFAC4C807DD0D5DBF11953183BDC8BB77AEF2F580BE1B4C9124938981426B36EF811B21398C34158EA6C7D528BA113DA970818DAB0A0D0187D07A407C5A5D121637896EAB8F14787368C1A4A5FAD2167F804600805D6C8AAC502A1813258B296F508381A18DB2962C8CF8DD32A5E7859A27ED57C2F816C48F944A748B8EA19DC83D467B1A22736F3E1BA2C979371861B945075F464973E50F7AE892411A4C1D2104E3A71F3E9F180B89AA2597F0DE3FE00815DAE9450F385F7C4D3829D85BCC3D71F7CB77D1E0D2DBD69DEEBC92160F67AC82DF50B4DE7D8C7D5E09A01CFB331847951C3F999B8DC667AE358A5DFFE1EE21B42AF0450305FB8F9B2E16E82E169F61E1EBF70262DBD78D1FCD01244B704D65F340124464E51EF8613A6B2FEBA5CF468EDABB72FC652EA9427E849440284CD5885D52387B2829EA7FB073D44AAF4BCF4FBD0E2612195FA4DCF7F73AFFE7743869542108B10E64869B3F486398BB58D5392C74E11FEAB3DD64A7A0FB68ECB628847F26370D49EFAD48D1DA35E2823BA757DF7D165EFE6F883BAFA9244FB0ACD3EC9802FC75841F1A18374644A948ED604AA368829F8A36BCA83AE290211D450CA2D3AE8B41D7EB928666E19C1E7F9EB6D4535A2CE430D40F7F8EF0AF1D9017405BC923AF2CE8E128DB74C9A58458BA706FF4B2FA8BC5E472C4C41DA8393A982AF025AE6F95872042636F540F564BD8831AC4B4F71242F3ED30EBD90ABBC69373A23BE8B6B652D02E2D626269790D95BBCADDBCAB98C1468F441DF98BEA46186B427EF50BFB13CA6491778E1F9DDBB561172D109A6EF7D6D4BFC3DB86EDDCEAEE5DDA7D3EBCD4FAA40B35F5E28CE082576168ECB994879F0F6BB196AE3F9DA56EF04BC6EA659409DFF99045966FCEBE683830C12B8ADF76D55526FC748D8F572686110646EFDBC0217D3E530F56C192D668F2592EC9B28579BC18A7678A7AB28BCEEAB2ECD54FFD6F90C48FE57C230501792065FC7F5CA0333F5BB2173A8BD3A37BF0D236B134F249B983907339F06C81CB8B64338E35429F02FE51DFAD1CE4EC360E855FEEE48A6A7FFA31F0C9B157486D4F313E724CA4B72A14D36CDF1E99CBD72F4153B7C38790E49DDADCD3667865F9DF28B45AB6E29A2C5FDB4A5FA041443C54BB8A0A49DCB8788BC352B59B616AC28E5EBF090B1C1527E2B2EE8026D391BD62C22DA8357A36AC1D95E09CC34C8DA923311D9AC70AF55310638406C072CAC80EFF82D305A91EE3CDE8E95C4B936B2A46E4ADF630B47E40C4FCCDCD54261152B9A7DB0E7444D234228117558968AECB5DD06F16A3C4D00EA52309B1F76789678961B9577CB7AAF81739C9E11F163BD0625568D0C482C64F8F90CA9A1FA9CF4E9010E843142B93650D72ADAF15E3EAB1C4DFE32EC4552112B0EF009D0E85A155BD0CD814388188CC96607379FF5ACA85DF3CB39A11A54A48D95DBA6CCDF145C99E2592E8E4F07EF1BA580654065B7FB0FD79F00A21A32E6E8DA1C475590E86D55F3995FF205DEA925DABE5E28D69411D5C153B3A6271DDAA29B6A9E77812A25FBE56333A28F10309A7F4091CAC0976FCC852BBE51AC30D1227800C8AE15F51CDFCA82488DCB9DA168D8D5868914DA71219A132E9F8FA8E9AB610AA57FB2D52BACA84752D9C856C2BDA2625F5F1FF57FC7341F3088AD4A681B22A50D2A20A5CA6C7471550F99F6A7024404ECECD9CB0FE293A4137A78EDA92C5A8B5F4A7B7643237354D151A0836B7CC5FE79EF5A89C8917BF82FE8AB68A9E74E148D096594ADFBBAE055D6B9CBB6D6BE0A2DDB45247F463AE1A00D247D95A6339B749F4DD4366728DAFD4DFD8DDCE66B79000CCDFB89F9BA9E0372DD81EB2F08B05CCEBC79197E1166C08E8B8F006665464AB7FCCDD35A5885F604D05988E2325D89FEDF7B4411AE4E25FB3F8CADEB82021F79C74FE859783FE5FC140A652420F63B0749240E5070783F1C67642F03989AD87A1465B1D2506DDB7717C619320692A71FEBC9F513622EEF0D9A566E8E0E5E017AEBD6DFE04D912F6707912071843D193BD8E38119181CC092E45D1B8DC7638C7347CD02F6F011F5D6A0CDD4B79C0BB06CE25101EF88E7BDD337FCFEAE0C7DCC15474CB3F000A701D7B78D7108CEB4C1739A0A102E278E0E652C31B605703B73C486BD22FBEB339BD94C758C1D4340A31CB4EA0A5919A10FE2E9103A4971B0A56ED280AE891D14A2E6B51B1D4BB69F0ACFE5EFC70CFD27BF9498901113DE780FE7510A178CA9FC067E5ED3BFBF1A049D3001CCBE64844E5AD043F31FF47F63477ADDABEECCF5ACC3C8316630346172006953A1018C3F8FF707DD39A2A9ED4D696360340C69C6C6FB746E4ADA1AD6373FF20BF000B4FC8E7AF8D75666A590E2C7A66CE6982E5600F5608817A7EAE2331882E9B474B26635784B94AB30252FB2210DD730C3103985B8EDB7D8D39B300C23D019244D962FB2DB46B2048599CF272F45464AF7A26DBC1B4086B6B535F7258F7D9122A593EF0FA781FEF1EAC215AAE3BFC71EA6B4CBD70B4F076AE63D6106D2EBB812E3187CFCD5C9F313F9867E93C7E1455903DB84EE62D489D1281EE7215584E371CC7387C9A41192178927F23597E113DE1D3243E91906681BF5F5AD1B4F36B06610BA17D260B4B0F621FC196CCD7C071088582E7C4DF0D5FCC0FAECF839302BC6F07990A5F504330D77C88B3A1A5CB17813A5088828D17BD91E6D787EC93795EC6E93F1D9F5065BA2271A014692A3A23CAA9A1B7E9DA0A4E881D83F1F06C3E202993D197EB5D10397B77915B7C93DFA289F0E53D6381164B368FAE599BFB212365C00C526F21C76C9F72823ACEB5C78A60754C533E65D4540F29D3F659FD0E43DD59B48CFCE64E5097C08888FBE61A9B0C282D0F4062DE068B9A998B4B8A7BC3635C812EDB569DBFC0D4FEE0EF400F07B6C1021A9DA7A56C9558AC88A675FA3BD2567C6940162955E5D51057973919E01EB9FA5B688A10578F93D07164FB74ED47A38C1179AF60BD0272C074C7718C3C3AB42E707A2EFDF3580109CB246A60F4E120F86C1AB2B2EDCA5D0278A0E4C2CD52F33A3DABBAF8AA81299ECD6CA46F8A60396D17F417D974B277952F95EA8CEBD3D9C57519B95D8C8EEFE9768D3F28E67085B9D447C2E2182F6AC9904ADD970FD387E662A216F8C79E24E9AF3283DBD36ED0363E864DC1BF18BBF40FA38234544C2AB58E32F5D98499F1564298F54C33BF0DCB06E8403F9B6E73DBAFEB10A63CD3BB713C694AF012A28353675C07838103900EC879BEF17EEAC3812EDB26432C71E9F102D83F3ABACDF651923403B0710AA65CF1FB5ED6E8E67464F8307CB8ECBFCCB9EC363D5E76321786027888690A96F44AAF6E1C9D2806B523197523B38818E73777A184375FCD7736E3BBF3549D2921FACA812815E9396AF05F83E1BD7CF2449094253DD0569196E1C18F79036B7355537D3C892A9E926FDF7B19F74A1864F42D26669152874093C8C34390B90CF2C87FA14F7CC7E3E21A1316F024A4622CACE2C93ED20E82DDDC17D82D58B55CF18141B8A18B289ADCFF7D83C72A2073A0CA3919116A38C642DFB9585D85BCF27147B3560A3AD0AEE203CF0E55D59998EE2F212DBFE39158EC3D1372B39B50B9E5766667EED390C9F61CF6F422961F8FA0D39D10A204729F9ADC3B7B792EB7C3950F65C333326C743F264B90AC990217FD3DA95727593363AB0B90128F9FE09F444E3389419EAAFE5D04DFEAA89E7A5B83B832F82C914CC14C1D989CCB728853520270ED3332A9F8F0054CEE80743B98AE309143F5A1CBCFD38FA5889D18011AC05AEB01D82C1966751FAE6734D93FE684878210323ED4C8DE17B61DF69C2EB8655630B19A1F178A330418756E48EFB0FB6E50AF2C202ECDC943E789142A05C63942B79800592F77CC4C4E255BADFB0D330BAB9C96D3EA93204101617319DDA24A7C4BED5F3A427B2DBF2EEC25FBE23147ABCA885D7EC951D69A35B9EF871DD0ADC706FB2E73D90DF21DA05A4CEFBC9F16F4A2C73F151D9F04E45EAA11A1E53C8F8DF5DB4103E9CC99B9EE962E7CB7339082EDAA96FA2673599080FA9334DF3955E631E234603C2B63637E082DEDE1A1BF729302C675FC64A15BAA5DE0AC3CD978E868D495DB72BBF07E2BF99594FFB69D8E8566EAED512229E8059C3620AFD0A4E6C9C004EBE2C9E2502D2B1D9371BFFF9AFE966B153ABEBBCB4144F0C17CDD01AFC53784DE27AE1D51830B79283D1ABAC7A11F512AC56015A6E26B66D271FE912A51D9DCE4FD4B903923C9791895C87272875504875FB2732AF262A6EF7499DD5B9FCD259AF028CC2A5AEE5E263DBA66D348654F5CB9C831F5C09DF42BCE994123E7440FCF2D6DEC509573474B424E91ACE7528470F2FF540271D98D8B8ECA22E7E78A18D57CC766C66D17F77D614C69807606DF06CF489EE3A9EBDD5D4D86C40B76136CDE362304F0814EDB84BFF1F046AD1CEEB7D81923B52A1B7EB759331B09EE1B9860D951FD25C33C88B3FB57C90CE131F27C648A54BCD5208BEA37A25A7BFBC59C4F26EB3975F776EB6428B575CB3EF4EB41F652CC6B3458949C486AB1879C0BF67400232DD9D8A2239C1DF3F895427D827E4F5CBEA8759059D32A4CC993B294649E830DA7F0F760894CD696E2DCD2A72582A5B01768F823C6668666F179007CA11B6E6D5029113413280BE26EBB3F9017A04F2F6EA959AEC1F3A58215464CDDEC51A2C46BAD4FFDF9AB61A58ACC2269D530ECF26243F1103DC40B5FC2F494DE7F1C96A058CA7E819866BFAA89F38BC11DC7995023153EB8144D24A62DA2A54E4090E44FCDCF10FDEBD38E04E211436F0DB22CB3DD532D885ACEBED368B141195D0B34CDA4A139BB26EACDD7E7AF6CC9B55B26EC3680DDD0C325EAB94183387ADA490099D6FA038B364EBD7E3375AE10F36BC99853450207D3416B5AC2313FE0CEBD9A8383D7707991FCD1BE08A9062225036053F9301C5C74650023D6422A5F665C3EA35F8CA67B7487AFFFF2FFECAF3E91AC567D398807F6DA9AC283FBA430171292E958D445CE136FD37B367076806C5B92306165D1B364BBE8DEB1DC75B1563693FF8223622DCBA20B0271996B81317C3070804D23229D9186D61A91D55864AB4D2CD60F7F6DCE1843567172B0BD4DD038A875B99616EA79A5788F371F408BF9DE371D929D16DF0D70FC4893E31D7D4BA86ED5EF897302B7680C2FF8746497A2E4C6C7E1448B1034475E7A43EFE7FD5F9CA16D14E0CD867FEB4DEA7ABAD9E59B2ABDB13158376533CE68F549D4572241CCAEC234887A56517623264F4C0012876EC3F0A7B9F59F3197535A84D608A831ACED8E91F722D18BA9AFA8C4BA70B1E2760C4FFE04D38C9FC6B77CA811E8775D253002E2655BBE162FA9E401CF28BC58017B8993F2C3DD8A57A27CCAFD45C4FDF11EDDFF5B2181817105C7EF4A4A889D2B48B18E0E0910D198737A1400E289F33BF0935D6230C948281B603726A42CE7304181E6C7A3741800680F600D5FDDB6B92D42A273746EABF57E008FD55ACD2F6512CA96117EA583F5D35FFD9E7771C7D1734A684C5D2C3209205C51A6BEA38829A2DA579F9AD4EFCD86534209AC50A0D7C0F85FA93475989ED4CC090FD1DBD00603CCA0F946912A4F773840AA2A78D765FC353A6D1BF5EF11F5F3A6AA2EEFD472FAA20FA33D409E8457ADD5DBD6F24271651719DBF84B2BF8CAC864AF326FBACEA138391FD57B49470837F0932AF6786EF082C9EB202FE7F58D8AB5A6D6C92546D859022B4BDD96D4260AEC0DF1B444A0868F3D5DBA4B5C4B94E34FB3E3E961B0A3E31BF4483D9356B2057E1D6A589A29CCC845BD9E57228EFBCB5D3FB075E5E461D23A73040B7F1BCB356478C53BD54B7354577611916DD0B2DD66450DE53B31AAE9B3D95D75D716D40BBD39EA6B9363BFD3925ACE2F4C9429C7544CC5E7CE23D4CE7CBCB0979C941523311E1DD8D0C3110DB31AA789192FE81F0399527CBC899296A15FA3AB61CC5E4BEF8A02C6612EC405520C0D6740F386A9609F46FD3FCEC5BD7A6D7D415CE21B4EEA36B6604232193EF2D0EF2D9CFFA513FC736A4AD75138C7B514E75BF465584A9F941F39E89787DADF89B402B54E76636F6B469398A6BF21C16D6133BC657332E07F9B6250E8D4A4DA64F132BA807791A46BA11E9BF45C82F974BF4DA871E5ADB7DC34D76DF552831EC995AE0319CC166A1859569FFD87E94F15C66ED0CEA9DB8B451A7D54AD7A1A93D8F42250020CF4E0365AD3733CEB624F6281D182D3E9F4DEE8DF7867D1BDDE756EA75279EA36864F0A442E4CF4063118F524535697F685EDCB17CA294057F9B8BB9443C017230F720302FAF52F72957D4D479BE48D4DC87B9E7F6E2CBEF2555F1E61456781E82744D70CF6DD3897115CCB206232B09349395CAF5BF3600F497FDA857B7ECD122355FB8A5805B452C1D4A5AB01B0609B26C14BFEBD14BCED9F20E618C4299AC5268CC6C8327FDDF02793D060A43505187B10519DCB1CFA05CECCE4CBDAA521C94B5610B9E03FDC3993FC4DC08F11514BEA5D207E2F4D8C57FE671CB40D79FD7205FCD10853E2C4312C4F66AD3F320CAEC301C26E4211277E4FCE0E7C28543D2930AAF7D0AD3B6FB923EC8D8E17734A364C61051448AB12811D34AE982264FC41ED52CDE2662E727EFD77A1CEDC07EA738B9430ED87B19C5A0BEDD3AE992AAF5D70FB9FAF44310C36B1448DC7E38BA87B9A4DC4E7A3A382EED2FFA19B517064DD85A92C7421A62A26190BBB2CF980BAB71FBB1903B904964010A2B70950C7986FED694B01C75DA1A63F4E30692D2A926A0CC19BF954F9792607FE01BEE9522D7DCC8C5FD199FE4F3C33E6D81510B578185EFF75F3D27195C2167AD75A31F12B17F352760514A4827CC5F2AF216054F2CC859C0E8AF2BAB883A49383AAEC370A995FA678AE617D28E66AA482C48C365EF81BB002A0F6EFCF9EBC24BFE9732503F41C18F582C3CAB432216C9D1C12D0F5DF3BD66AF94AAA46C2AA12572FE1599DDD6573DC60E6EE1FAECBF4674B3CB9F1AF1ECFC5F97826EDF4F041E3EF2DDBCCAFCB1310056BDE7C3913979A9A3FE71DD1816D8E1A6EBCAD6498A83C45AAB6196E325ED612C5A686E9051F16CC05BBDD8C0EF5817A1DB22B16EC64726A009474ECDC4F1BBA6F91EDDE117E3BFAC5D7A1ABC70F30CDF25893998AC579CEE2AC652EE97F1D89B021C6714C3F0D712210EB2A1A3C32ED424EDBE3DE6FB2EF3E1FE018A234FEAAF1BEF85FA2112821DDA3D5CA7C010A5BAE6721F7D77D9C96EBE4A09CF6AEB05EBF5637465A5A82BA84EAD67B185F4F1941F123B52C814B8512405912E7269381C005159A4B94C17131C2E782C76183113C8AA5EBFA5A8A861B9B1D30E838DDCD42619A7726624040F3D86A48E1C5F81921D3F17E05643CA01F44E34B0DA33A1F1EB38C15C88B1DBF73304EE2E7ABA959AA35EBC23211ACFC0BB45343B3135671615ED1BC5C3731208DEED4BCB74A5F33EED3C19C0CACA7D44E1EF76861F84A265A4B5C3CB970FB9BB3E4CA2E5DF7396CF0F6E18BFB54D79F718CCD7C841D953224660906FF1B94E102A5B7C3E3F14A6A7FBA5BC14196ECD0AF8BA32B736B3AF63FEEC62DFFB3E3D8AE1ADC30600FDEEAD752197D857356FB4BCBC77A54C515299E801517D1C5EB2C02131F8662311953BB54238329D32A43182372E3BBDF9AE69A79219165E5325819F65DF78FFE77C2C0787172E9CDA91CAA2B721E42E49AE8843722E2881C076CEA985835A347C522223463E0E07F27B5CC040C82A0BE76BFCE78DF1C6A98709C6D8B7338935A55EEA7AF9357CC6E34CEC4A74E06C4E677C5C27C7126B59A808BB5F9DDE67C18A913574786187BE4555EFF887E893A8765347A00C78533AA3921DA02EBAE088380E13102ED71628A14D1BC8C822F1E31906BC227BE636D327D1C9A8F9CC05FD26B282BE514064D27C13C160978A1752957329BF589B6D63565AF5B0BE594555E5609FC5D05FCA5A1F56C319DAF767B7E5D14D5386467F8B20702A64F6D19447E4A4DA52A0887D31FD4678380F7532B6ADF168C6CAA22050331982EE3E1134C7E8BBC6359D5E877DA1272EA26718A70FACE209EA412383E20EEB83AA3DCC3F0BDCF6A78528EA81938E967A6A526D5F138D639B91E53B8B74482A80381A87DC3E0AB19B155167F97DC18968CCE4F99FD5AE63E50DFAED851B7DB48479B091753535B84202E082BC5C72463493357AEFAEC35E164E82BFF534733CD7C924FEEA56A76A4FCD3C2DE3C055AF798685CFC8423470BB871A637B2A1B8501FE72B7D78C397B5E4A8AD197E2AECE1E5B14BB61DAD94C979CD46A8766E41CA02447BC2A7E48EF3ED68B19C3526C6E8BFC17F83668FB698430A74752A2AA29C83AE019A1145208DC0A3AF76FE964C16A3589009EA0C5E32EFF40BD3B8414D1685E20456023C16C8E6DAF4193F8CDB1DF5BF2BC95EF5C98552A18B2DC4FEA9A6C6B99C712A343573210E1B42C9019AF082F34971511BF0E7700BCAEEA3F7D24241A0B598B9B6703697980CD82F244211B58A3C616FFDEB8E8D946C8418B94AFE1F46CB950727F456749AD6982EBA93ADE229A81D01D31CE22725AA1565C608DF9C1ED1BAEB4F1FD1AA8625A921ED6C9DD019B6451433A4FD335841CD36882955642B3344F306E8473A6742C01362F41A7E1978E43FB5AE7529D05859CFCDA665F2B53BCB19CA277CFB8B78639A6D9848FD903D00667E7BBD537939FB908DA8E60331B6F283D9D7BD64908780CF74038837108DD4A9BF095718219BBDB22AA9F6211617031E169ADAB1B0B24A96C3D6C4C2CEEE273A36106F4F1E473CC552697C1B65BAFA5ABFD2C35A0B0D5C410A72BD6D9B177285C9703B235C5E8E9C63DA66B9CF5A543B1B463748D01E873CC3B6CF4A57A6CBAE554138FEE27F7B852F0E6275CD699AE4965F32ABBAE300FBF7591F52E96EF29589711685D71D5401EB0C60F66E6AECBB82ABA67B6063DC060BC4C05841BCA8ACF231AF0D242AE4EFAF0B5D32FABC10F6F33DF3B84F895940643240C80FC826344E93F29FEBB0B62B667A1B13D489E35AA9F1D741C3FCD509D11E0C3E33ABE100066690B2A62769C5C95A2FE1985AC5C7BD53F06716BB58823971118DA6BECD9B5B53471854215FE09CE7A4D9E39A588E32CB734A3E942318E7D35D67C103E311F11ADD4E276793C99ED05EBBC295FFC664C015F604B77DC51D2C64BAA9FF11E0291A4730F65EA1A29898A6585645109D8B6AA2214439ABB3012E5CC46645EE89D454460944FB0761C7E44230CF3BE6D7D61E948674189BE5C46D2E4FA2E4FF92F7A9F2000C9FFDE840B5C54472FEF1043701B05E67D8DF1D63AC5B0AC1F578728D4E788B2E6EBDADCD8DBFF6F084275AF8BBBDE9F80CE0C6C9077CB72577D8DCB3EAAD619AD93EF53837EDE645B192936AC6A4097DC390402B535134CD25D57182FF3572AD82EAB6E5C17DF6D22AB29D58CC6BA486F74ED0B401BB39BFF87B7234FF23BEF469210F3E07D720131A17AEEA05FE15FE4FFC0A4DAAD89A6910187B91BE0CEEC72B5AAD8E7013E6F3C80B4E24591A8A4C91F0784496F12E3F2FE26799244295F6F9BCAC65316B303B66E347BF73ADBCFDB340F63C8B89E0890A45BBF935FC2D11709C91C237C0F70652179AECC95EFC63E35673DC22B4BF64AD8658C9FB44F05F994719CAB283B3BE28010B74406B6042DB0E798F6949D7E657E1B29FE950131CE30517994C09881A6F298081C5C58CA514104595DACACB48B7BF17535B529B465190CA22081DF455E1442BD9B9AE61FBF7B4885BDACDBE4E6998AD6D316334BF405BA773553B69AE6A4F6DCE0CD14E1B07FCB4E6896A09177D97A92BDB7EFCD6CD08856C66A8194629FD03D9A3AD4234DBD9876864CEBDC749A8897F6106CE9849F1951FDFB751243CDCCD87B36F0BD4FFDF985348A976B6F52F03ADB3399282F4C87FE45226880BFF42ADCEAF677079D02E30575561830B3C8670B73B174FBACC0BE4FC174FD2D8EF6883D208FF925571777E1B5A976D3A55336E417F82090F01132C73F7BD6B2D30526244C790B5056B8E48ED08BA9EB604D034836D72D03CE069F75044AA2E20B547B84E5DD2231D44DAAEF82EB8BA1173BBB60D1827A30BC21E088ADFBBE1D0FC10E87C9D4CC4F3FC001CCC08172B1416A20437790EFED4ADBA1A8AB44A9245AEF7BDA762C77B44FC08BF9326B05ACA1D5AF69BF4BF2B955FA36CD15F2053A92801E0445CC0ED524F4EB57F55EA0902B418F24E58622430AF2E6C1DCC75CD1194ACF10F812B2F2B6CF772294E875B27E3573A362FFD392352CDEEB9777805A78927C9BCC97BDE175BF8C411F4734A84CB1EAB7509944ABF896BF080DAC1FB7BA824F2E230B958D935C6BC98A15CBD50F207A83D2181BD950AA005EB82D59283D1CC7DA77292B632A7654BAACD320E4C8A4B6C29CE0FDC5AF141A576920AB6A341186DD142E0C5431DDAED456F9519FD0F451386B5BCA830D1E588A436A713DB4CB71635AA4919D734F04A6719807D01BC591FF00733607E6160799C6406AC7E14AC78BC43B3822674D4944E095881810B637A1FC7335FEA7370DAFFC3B82F8AB6CCE399598F97718BC9C1D6408FBDC90DE30D1C61F45B8B0821C123B37D08334C5B607857197953B566F165E71B22AD9AD206D08564E2E5C60B64AB6619CA933A439BBB0F7C7A8982D776BE2A5391F91EA155F0A3198EADC1A68FB64E94F42F406DFE50C3AF4E8435A1C38578FFACABD56174CD1B35072482D728A69228EE6EF661F4DBE878B51C5BD9579DFA1D787DACB7A64E3ABB0015E46CDAC0885BA4A2B8F58CDF5555EE35AA51E5C6E4504D853905ABBDB0377DF380580B9B3FADEA6D592CF6D24240B29A70DBF5CDCB67F3EDE9C8B1324EAD0557B33485D64BA0A9755A64043156E39882B941CCE406D8977BB2052B4D6D3CBCDAFF6B1C2EC84AB80DBFE6F4C5A4ACA0C9D7D9C89C20C1EC6067AB08D34526A5FC73BA3A127A0DC4726E924E669EA67DA2023FE166540A6F9AEA9F569F136DCF69C5C44E0FDCFD87A08F69B3EC0365116C13AE5F704808BB637ACD9283C303E4D814C331FA6843787937FA49FCD1BA4D697E70FED790E8B2459C4259D94432BEBDD43F5508C072CB887F9BD7A6AED8A6066E18A85DDB7A9161F8F70887022CF1CBA653DF931D3BBD69D86DD846D9D140D97FF49F5B80D5F8CFE394D1E8A8DE1C05C0E2AB2DC043461A352F0DB1FF14DBA1BDBF5A9C6AADCB51127D7AA873C82BF01BADFEB360877689768CF9EBEC66F213E1F7A43C3809450E8854B30EFF5506809468E3543B029FF2A581A5950F6F360D1A82665BB8091369B9E2C5BE93A71DCB6995A527F47E52D1EA66F60297EF3B5D7B19F1E2C27FF2853D28CEF90A01D3242CE097D738E513CEC849B906AE1BEACDA221336C140255864E360E059E660212C7612F84AFC2A1CF44DD8C47AA8E60E083EFFA94731EED8C42AD9AD460530B8FE36C21355130B9D014150681BA2261EE4157208B982AAD7A36EF2643B5476DB89F1B83CFD65EDC7996740F2003C4D33153429A5C5E47AECC59268E45D44A2638269340126E11201D58BB7BCBC8F861CF7B237075DDD4682880CBE439200C8CADDB4F96BF4BDE6B844C0D28859666DAE0479B4CAB05D43E5C1B06FFB29351232B420655F80B38BBA2C555994C7B2A1D953178131AA6A9677B04350861F157016D771E582F8400F3793A38C8D4F7F610904E95CC331563323E2A501F93EA0902A11D806E4A74CCF4B9A98C533C170E36247B99DFF790648B29DF4799E86BFCDB68268BAAD292DA29BB4F8238C00FDC8E4A69A447BB82958E1DB3AAB8EC88D4BBF67762398D3D6579D7B2AACA4FEEB6BF56C4C9ED52E5B63A7EE8D25134209BAAB61D17AF0C1B0277C9FDF42EFF65D0FCFDBC2033B40D401C2D3697F1492F19249514B8049EC585BCBB30CA3AC6B8FA946D235271A7EF5687424F4286515A4E162681FDA9AD2CFE29E62539F514FBE001DA93436B823EE8CC28534DB9FC84A55DF11231449900A4B6ED9C0AEEFB545C4E0EE13022ED517CCA6AC23BBB5699E42B4CAC45085C067141BA066CAD4954C4C96FADA9A3FF0FF90767D4BFB58326ABCC3CE2316B1415E1AB663753D1709F92DF00E64B7CC20B0803E81569FF1B377A929ECE8B8C80E81FCC89CB435CFDB199227162CE307A5B148698D9BC0463D15DE7A668284BED8A719563B1BD2D3127F11BD72B173D5F5756B82F16337F5E34DA73236F6FCE9397B054AC51DCA8D9DB3AB9E44900FF6921873D937F8CAF90BC743DA5347218788887EBF90344E4B2B82A738BA937FFAADA49C4F963F2875984B3734A5D475DE56F22A1BE3E3DC097DFAE0B657561BB0ACCDB16C0A0F4E6C0C99DE6C21AFB6BDEFAD4E0950151BF32E3FCD758CC4ED94AD18988A9F02B90EF8BC7B8CE83115FB930312062349397E7DC4DDD9BA7304A442F10EA4AC000A0EE8F703175A6E7127F08289030930462FA723C53762F2A914A987A76916B399D42E7FE4568C51D230F539BF3574FE573E2C6A317FBC25219996092A2518CB25A7A9C0D7C4C39D73F7395823C24188919F919449A940CC37AB07CA6D1B5B6983D47872E665B1C1553E6709EA273ED109B4565EDFEF99AC1A618DD5D96CD4403BD6676CDA19BAD86342F7029375B5F772860ABAF5A00916D2DD5C967B457248A4B1E0357AAC592100468DA42AE53B3B1A9B6185AF1533A187A1EC66D5CCFAE033BA4C00B7257A5D5C6C22769C1F2B7CF4F8EA9E774DF6338C968CF7B3EB704041A61FCB08A29D2BC6F2DFA17D8D519D69CDA4C843873278655FBAD0916947878E00E85F5A78DC5C0CAC181208162605659BEEF616E9DA189FC1D7250D4E873093F6325062823D383A42397F87E3B52B9876331F4A4F88CB78DC003F29B823DC697682E69C4ED6CA41D45CBB929FC19481F4B80B0D4EC5D2BBC4FBF93515C97B01210A39E69E47F9CD9CCAA8419A7B62DA8F9C823966B9E5E6FD838C61E6DFC4E28ECB5EF646DB450A4F211349333A70575C4CC3F2B7BACC74D3D1475FBE2AF1E3C4E9B03328CEC1371A451F65499C8D2DABF86050543D379363335CBC6E7C5448D2D39B1EEC0302FD3B719E6AE95914284F43BB4B4BBB6467B0C26F7CF39369BDF79D9F14B919136EF8345A4225E5C7D3EC22B1B55232E1E983D8CECFFF420DEAD90D9381C2DE688D5C853BC02E49338CE8B40DCA9518CAAFA071C5A0C02E21F2818D660AF4863859BC32EE01E707DDA4BE9D6DCD3DC565D4ED09386BF9FF2168B89EFBD5BA1AD638CA0F13A3EF40AF2D4FBC7016174E6FC39D94D4AB9BFA109D764E9229E7CA26F09796A8512BAD353F1EF27F4AB3A982780A0CFBA4F307F9BEFA47249619A1CC2D7690BDF4315D236BFDFA08D493F24CB4C78BCAEA1D7654367D94866C0703715D3B1F427F4AD13F88B5EC34F9513D786850720A7CE4363FC31F2D5F7F76E707A0BC873A6314D44A8667AB7C9235A9F8819342621A974D156BD39BB54CD36822F616EAD364F05952154DCE6C2938AED116F198BDC207770576845DD3879EDBD579CE6E04864465F282AB8C2492A6BE15C740690A170EE736D8CDD3464DDD8E55E995A77C90ED2252AAB9AFC9A7B418D986AEE4933DD29DA7938009B4E9C402B657B0495512FEA68D3F1B0911CBB9E2259669E647623CE7A13D02D144E8E8AA28396C467DB6020ECD6C5806E196329CEF6D14F52D6BB5AAA04A6E982C80072430F6C9267CA42E54DE5BFD573D2AEBD0DF65EE07CFE80A2AB8BE771D58EA2FE6B6193E8FB5E40811528BB5E7FFD095AB0A860E61C1C5DD3CA4839CF29F3E60472EB197FEEBF43851F42553CA87F24DC342164329E7A4AD5EB11D5BD2E9801C0A8C5C4B46315D84A4D813E9B5602D19FAF7715092C7F148DB6C12A6A7CFA9C305665F7AA0A05B0C944CDF12D1DA0353FFC76108DB2E2D38B50835C4DA938348708E2283D86D9FDDDED96B89DA04367662726CB58C0E67FC45A594A5041035CA7EDFC24CCCC2CDABC8492D48D8F735CFA198C07229AC2FD8DC6104DB982C3330C8A9DAB224FABD8AD798052A903A1AF6E362402EACD49E1104B903FEF4C8C492E1FCBFD03AFB462C9AE8293D50AE7B36F08E974B91BA1B9FEC9B427A20CDA21332091B1EAEE6614E88E240F6697AEB9EE0AE6CCA1EE902B446DC4D61D2CFF21D7C69BEB248CBD33ADEE0B6E78C2D230CFA28941D1BDEDD7CC6B1F813287F2A0C006C59FBFE8A4FD256250B558AF31CB0FE587B92441BB25100CFF11CE9EE0073280EA6DD1EE63897FDA4829E6202735B6071F2711E1994E8D040E5A9D3D337AEC3DBB6EC3CDCE22216BA137F6FD56CE0DA2EAEAC2907646D1DCFD7AE95D8CD879ABBFD23A1F1942B0F92548ACB1FF6FC15AAAA5CF36CB8D6A7FE505D7AC2E178CA29396CCDF5ECAA2E9FF9AFFDD2CD470B3671840553DE151768D9DDA605E4E81EB72FB155C8BFBEDA1A026C4CBA7F74616AB34E4B385B5921511B0A18B736C3AA05BDEB5FDE0BB84D061B0D039402DAAEA2B5F315E5FC8F4D10F8F2F3C11E7F5D672046A56FCB113761139240D64A8B3E0ADC83793B306F778988B3224A2492AB2764B74140BCD0F78C8EED86118B3C11B89CEAD23C4AEE21D62E4CB1BD03E0B8697A5EA9031FCB2F1036ED4EC61E224B43E1A4EC7AB71E6C4951D90A14F352204DA0043DB745FC8CBD34BF892AB2AE6380AE7086F2904525D70493C317529D206816D61ABE59F240366FD86DAF23E40EE8749A84FCDCB58F3A23251D09397160DA491768698B19DAFB78AAE1C446DF78AAB7A90E3310DE69045CE5DF8429F052D348ACD185B6ED93EFEAE68A5A2F0CC2E537DFABD033F157BA74DB1E2BAF2509128520037BE694E1DA590A160ECA3CC6B5B96F7723A344F758B4856C44B46BD15B8414D4DF40880B55C8AED8DB07067465E86F95790C091F1A6DE411D602AC28BF9FEB96258634C6568B1AAFED19574C535CD7A16A69876EDBFB0AE06DEB4426B0C40650A374E272E82BE33198EF95B5582353BE8431701D3B382FA9590C650718C9D415E92C555B9708A52DBF0AE414911C8C6E10624E55C531BBCB6B8B1CD1BD7FB7B567088EF5AB0B430F36157A1AD3E5AA0044723AC4D7E575BFAF417882FC7276FC3B082AD00BF14A7884A6D45651BE8CB8DFFEECA0C7CD13602CBBBA545E2F6E3A895B005FDDF58F31A6A46C016CDA306D8C3E8403BF6AE608A3AE56C368E9CD8B99E824D1822C7DB086D71BC610B9FBC9FB5F75546DA16C4E90DBAF13EE7FABCD775864F90E1F04B75B1A7AE62E6A0AEADBC66D0BBAB605F162448B3A70D512B235D639BC19770A6E407346E6871E62BA586DE60ADD6DAE6FB2A2BB510D833B6E7DB77E86CCC31EBECB32072A96EEE867A1B8B391D88E7E55A52C5B60558F0D075B11995241571B77EBECB2C66AF66B0F9C207B8A90F23FB01D3A5DABCDB3BD295836F97DAB2AD2DA8C372027440EB40CD24C683AB95C50CB452FE5B2755E614896FAD8BFDF1DFBCF5BEAB745DF61C21FD69A8BA8D54EA600B1954DC7341DF64809EEC0D2CB1FA7EB68EEB3A44B9320CFEEBC7E4A63C1CB96F33CD898FD410ED179D202470A867453F4BA9B655207520C4E2F75240B2AD22B82165F73C5D9BB098F9F8197337691641AA42AD5C17B6691DD637E77F8297BB3A50672FAC99607D05DFF6307A2271605AB4740A2A22B7EEC1A375EE0ACAA28061B08880E6957E2689D4EA16260528644CE17BBD13FF6E6B1D4CC02612105E9633CAFC2A05C366C1F44F564863E4773983C993BD8F6644C897B54935CC06A699D8579C9FF31AFBAE1A35E6698DB1FD59F60F457FCAEF3038CC4F1862AEF538EA41EBA4BEED9FC2D1D23DFDEB1ABDB44530A120A9D9F0C79D4E039C39DA04F36DF3B634B0C9547B55561D62FF039FCF31AE5088ED61B2412D80155EEE779A369A91E24CAAEE50638A2AB8607093D20C8CD705A97E3C0BB0B1DB01EE5C33A501B89826072B6BDF5AE9BE52AABA6B44FFF673F747F4D929D6580D4F9E4BDFCBF3FAE406B05A99D3D77F653C671E8B64174B8AFD53174EDF0C2E3B37CC7102441DF770076AED0929573308F8E03FD4AD8726FE3CA6AF653105C0B8F3C31DD1FCAAB2F437D35E4B75D16C9173A4A00D46DC2FC2E904D82E7D102DFC07E882C9805B7346590D9004908394E8CBFAB5F3CC1780113203E8F3ED33BBCF60D46F673955931F4D29F7576D6C84E36D4E56BC3390736D3B067CD2D840FA7D07EA8918D58831EFA8FD4A014994619B7319B291705681135368103BE3C05D572C6683C0C085EEDE98110FD5FBDD7FCAC46D296B059FEAC9F7AA7AB6AB7C31C965553370DA955D6A1D5A3A233931AB3F11EAE83483BB5BA96522ABA5801B8FD7CE4B35FF63A9083CAE094D0255A8B40CF19FE5F77E4044397C22BE7AA10DE601D5F326F470434DA9296C15A647632B41D829A50830B1EFDB755E0052AD79A6F122A38E6EB148C3D1221B491514554C537B7DDA5A7B7DEC9A23A70AA06DACDCA6633418B83913FBAD809B064432B683FD05153ED878637AA74C118DED9969612E8F42A12E4C8FE3484D7724A069092A2E90E30DE75E1E90620D389946A145BA8563C5AEC27CD1AD29C7C0040DD037717A1E4119D430699BF318A19DE4246A9F62502BB04C78B2533F226E08712A99307A50B0380F1075F4A0E4B28C7EBCDBA7BE154357ECDBAC9F5E375EC8D816FEAEFCB6584AFAF35FA1C8D0C13E6FC6788C81282E7D9FF322FE380826C8F90065D0F7B7BBECAA8DCFFEC30014143F645281825915C35CEE858E4D1100BE84B829B9D6386ECDBA5B197DB4BDF66834AA6C7EC5535ADB8C52D95532F982A17033CCB51957E82C1B2F9342E8AA418B483C48BE6C2296D468EE0964B75D483D942E32F743C5CFD1C4D8B1454A98A2BA70F6E67FE3117E0C81940A2125EEB0F4F89C92B70FD93707195D5A669DF2CF3B5BEFB3CFCB6511EBDD957170CD32C7F5C4C60CB3B63C697654A4BF6E0F8A93DF789A1311660B52D5EB6F163AC250CBD905A478D22F3DF7E82FD2810A07AD2F9092A0E362B35DFB9C09AC6749F87E995110F8F32F800BD30BF68E5C44F78D1E479A2A242A52513A2BD7722973784004CD32533E47340D69E7E2881808A3C019CCDDC1ED1E694D6477691A9052BC59DA79324E456411304B3F3C47E2FA7BF76DBA691E5C01C5EDD3CC7AD8B118078CA4D789891C9C1BABF1B8047D4CC68986B75CB01788848FA1E3D5A5521AE44F39F015F2B1E2226383102803155E6159479FB51875B809809D399B4482C29AD3CA8EFE0D8F3F236C2D7353D3832F00C23990BADDF1C0AF89E9841CD1D3ED5A45A99EB0ED970AABD5A4545A4F1E593ECE3D2C12348291748CF0C7576BF6D0EE530473CF46F4A43854A791FA59CA195F9D11F4F962AA7BC86C37D1C1CA524EA8C5C9C82757346CA4F61AA17064C327DC37CB025BB59234A3B2C7D3DBE71D4B27783E733A9576701E47864311A207EA8924DA15206D9C4A6D06BB762F0065BB8E98D4F7AF0E162AC9B7B08ADB314E2B68D4555653E3557B9BA8F14F2BC314A395F3DA7EF38DE9245C8B98FD22F2918120A7C634D52159A670FFBDDD03142734AB61BEC165566DA67F5F0E0490977868330A5FAC65A78CF7B0BB2DEAE5F2386F90507A3E1BE10DDEAFFFC16A4484838ABED210B1832E93108BA63BBCB690E4BDAC093C92D5CA3D4CE791359C7214B33CCF5F2E47B9F61A732E6BF819F66B5B81DCB647E0E6D47EC0098AD831EC83081C2BA29CA60E03BD26D4E04BB58CA4C36BA4AA9B048B8F6F9C7D6AE980C15D85F78848058CB1D2680598B50DAAE8A47932113BA3F4F8480373864C0475EDA357F7CA005C53154056FE989605F7565DD7049FC090620090282C17B8349D18B8F1B0BBA96182DF36BC4DC381BDA681AA569EBCCF2A2FB6872EF5A58683E4BE6E487854CA7387F0D8DD358E5129AF174FDD19C5E0348743A8CE4911F63E78D58E0CCA713443BA80F793CCEF49FEE424CE309E60F681F7C3E1402E762E6EC15260EEB6CD362F1B16B4CB3D1189EB4AB6220B4623AA02B80BB3BF2BFB64E9AF881B5170B841B1AF36B68BEAB3F86780BF1745715EC0C8B2F0677702A44C7CF25CA15F310BFE8F122889633BBC43A92169B3E5DE969A19630B48F2707010EC0BBA15D65B69585FBF91C4F1A17552BA6F84359002486BBB75A5F3C5B235E51C49804C2F89683515AFFC6FC454D7AE9BB045C263F8F27FA60BD21BED9DDB9612FD22A07FBB694EC444ED5F66167B1EEBD82E28CF06C02535FEEE2870FFB4A4099017735026861CE229558EBD103E836ABD5BA9BDF51E050A4BBA60A2E2E7F7E8FC99B120947327BDCD3924E5FEEC5A0CE1FB757DCD4A75B41422BAFBE55A0DD1AC033651C1FF20D5EAF78575A5DE3D3B693D33627716F07AE901D644B61DF6C2568829CB622AECE310ACAFA6AE2E1CAABD3FA918B14446D5EF82307F317CEB1ADEC56647451A24BAE277F947D964371B0D83B5A4F634CCB859BC71A1539D0323C029BE26A4A00789EC51FD185244B371D9FB655D57DF603367B5680E57217AEA791DD1A82C6B7118E9E5D418CF6448412E13504E60197F5D5FE159488FA8DF8B8AF6D736489992CE16AD52C1B4BBD8691C61D88A3758EDEB4C3B80FFBCD000CFA99B94102211CD985CF4DF6679816BA38AE285EEBCF42BC800104113A5F9536F428404668A9A1B0A19C036C2CECC27204B1E3E0E0373F5F98CC0D29DD04252EF6956F24A70C8D671DCB10452881FD0B4C65A0C6160C0EA073E9ADDF4930196D14CE3CA9692541EAC625F809D42FBE533356963E6CC274E6073AF9BB9C7719F053A60BB44ABC2040890671511E69FF76D9956C3781FE9AB32418476139A0D1F73B0D817BA7318AA84F38C0BA4BCBB3AF378AD98B12338B7920CE5789F4FC6FF029C90F891858321A47B57B0C90A4365EA71DD69F2385F6A9523BEEEE8ADFA594E8EC4C15DE3A1FF837BDB3667E64FC9ABBAB8FB4258510009F413809DC52EE3831D511906906CB8A54E1117330A458D0FC8A52BA5661A0258F62C3DF4C11D4B6EC76F74770334CA0723FAE02C689A93510278C2738002574F13A60834B51FA617F9A41DBB75B6811BA25D4EBFCAB00C297ACBD1D29503731F9AB191AC8FB7C9BCE80F9135DAB7C94FB0E4E261144DAA71A1B940E0233B24306FABDCF1681BDB3F1536459751CB5BD326132F6685FD74C5A8B257BC4E7E632785DDE6CC3C657300A1A7BFD1D0004B1B85891D0F47F24E45D780CAECDBA2EB3AD446CA949BE01B4B28F44D9174ECFC7F42B70B73CAE3FC5BC3FF36DA9982509CE717CE4E35ED4297FBB820AEBC5FD07C2469C21B42A9FA77F53DA6128DE22B5D8EB98E5F6C63601BB6A0A47286653175BD18A71DA3759E94639F1EBD97276F6A6B4228D84A458C56D0157B76CF573A1E8442B2A8BA6582FD0CD8B0C617D387F77E2627D4016F9A71E3082FC6E2DAFF1EA2326DD1E8D09C18C0C286111E67E922024AEBE81BC97371CDA78D978035EED4037D774784AD2296F71B3F53BAF74AC6028F7CA9BC02A50EA8DE22FAE4B0ED2A844D463523D74737BC15711A23C83D8A8BD16BEFCC91C6F37551FC97BDD233A3A0967EB6EAE0183F23F3D8DE25DAA4D8E9306FB695E86D7016E895B31C4186F11D9BA4BA35234F7DF4E1864814E45943FD05D78EF05F024D43B5545CA95E60E001D78438181539716F471A78BA7E53D9F01DB4BB28EFE58EE4C15869E0E1673D0486E1657C6753519BE248FAD7944EFC464905875F0E55E4CB501E459C66F844A9449073B593E972BD9F5D9C0C0214C4D7A16A818E349AFFF9CA0AFB7A5B86FE425ED3E07AB89B475A94CDC06781CC2CBD7E2C09D971DDAF937DCA2061BDDF24F16DDFF045AC7A82E70AD7155E6F90B1769BC67254BEF12333AE2C6FDC732A70760417D7D3955EC5EA0E8F917C853699D244B4EC7B3E02B33CC1159ECDDB2972358447705522E35C4A6F37FBA3FE37E1F40AB350F395CA26543FF5314B8371CC4FC1F470AACE33D188B06D898A511FC9CCB43BBE6A033FCAA1DD7E4564BC5257C2712011D7EA37018910F1E30FCB7696749BADA2A66BE7ACC9EA30E07D755F8E32024FDC1D29F8A997BFB370F2BC223B7C870A75EBD75DE3FE0FE08971D275EB7D55DA86B803615DD59D475E0E75C586D1A6BFE1A8423EA77DBAEA4854D5169846DDEFF74C8AC91991816D0862386D9C7D38DDE7F50CAC64B79D7E415076A475F40DC94D79F1CB95FCAA479A07A051D5E744A01699CAE94D82556A1020597BB8C956591A5432C6FC2EA5E4DFAEC1A8EF1EBCAE01A5D83307E9E16C6743AB41D56C1F923FFB94448709E344AF69D302857813388FD72D99D3A596638EAAAA1DCAE05A8F8214AAAEE5937299493C5B114C5C8BA6389E1AB5543432179D6A9C1A457FAA25197B18780415454907F43F8C634E264FD10D8DA172ABC4CE49D5B78BF00E22813A5C385EBC9CAD39057C26D795C5960E0BC725975C0BAC80CCA59E6B05AD861C887001AB1CE1634196135A3289C4924747242DFD0BB95D8A58B3B13C9C91F9EB285368734CCAEB3E0FB7EA94EC928CE5907F26BA5A44BE9D8AD9F839CE251B3C2C9F145A7B1975C36266A287B2C660061763A58410BA215EB8790477441169CC48B44D0E6E0FF66DF1E03B2977CC87B9C2202DEA89294F56E720F569A7D5EF5A9C804481006B886D4660325B53725DC5C1404BE3161DD84A5888F78A74FBE0CE3557D07A65DEE5647B9862E89C849ACE64089BF7ABA08A971A1C7D6829F9868A78CAD90232849EA5E2F70BFAAD769892B40B662D3493B33CF5FE3D40877B4CD4105BF54AFF3CAEEF9130ECC47CBFF5F9F026D8BBFA16ADFA79A718023CDFCD8CFA081AEC5D37620A3810B9BC55C0A13BFF632AB5816059D6A569F57F408ED883994F2C105E045458390A6ADF24090414A45138E72D90C209A8FCF3DE54189D5234649482C575BF2E570BD4088C8B737C1776613A76CF477F073E1D2F8F9A5F24D76F7E368DD0D513B852F492D5A327A2D9BCCD6BF9966A2BA1D956FDEB3E452B3D91B68E29DBC14DA5E8E2EC139FA23133EEA5942F17ADC3B93F052A28F5DF7C1E956FD190C5A986450E4A131029D8A5DA75B329824C62369F5C6BCC1478A1EFE28E8DF0A5F7A1272FA4D8FB4B0C3FDEB8C33BD5D28C9676CD7F8812F37F1F9052E1681BB36012EB36CC01F5F1BCE36B6C2295A8DF4F4C9673B06549CCC3264A0177529D21C627695D4480737AA281791BE727803616BCCFC04B00AD3E316EEC2BB5D61BF8E4EC4BED2C31370ACA1CEC038A9764F5DCF8CE9E1C013DB3846CACFD28AE21363FED8CDCF280FBFAA754E7A00BAA18EEDB5D94EB6465C16E00CFC78F0517C93E7E4E1DBC993EC206EF0B9D37B4405370AABF7F859380A542C85AA61D3E433F3453F625CA2111F00B48884CAD5BDF64BB5E2A1B4BB2D74BEEACC06FECC461010F94B73D6744E5A5F3B1F39F0DC3CB0BDDE4230643EF9EB50BF1417D899D862D310837BEA1D81EBF7BCB3F0DF67A4799527FBBB74B48C06316BA66ADABEF1A4B16D27192C0E2D4E666FAEF9B58A74EE762FF12CE76A197DE2F85FFE55EA8C2DFCCBC58D0C83F22F718CF0621D9A1CD7CB6B27E8A06DC6B6DFB48521EC8D8B7DEC2C3117AC0C59CBCCF52E32A1644185DE558254DAFCBCB67AC8C5C2EF9430299225CCBC2430F64C434912FABC40325CD87A9B5D296191B9BD75FF189213EA13B7079200524DC4BD7154D1BA5FBF8D2797BE23CCA47CD546A248C55CB934B025E364760CB60E457391D23149F6776E0E985F2EA8F595FE1D20ADFBB1CD4D803DB20FD66B4F57D208FCCB1A06C494F0952DCBFB503276B75D2807D0F2BAD54F15F1099FF802FB390238A13DA807B061B749046787ACC049FC0FE3E8718A95E7870E2A36DEDF395D71581F854C29870FB63B3B5F770DAF7326A5997FD482D62635904E85BDD3022F727B6BAD6A5943BE8591B7D57AE5E0248BB56870D662F9C57375D0F69DCDF43F46E64164AAC3FFC691C01B586238FD96B826A24AAD1D75F8EBF791998FA7BEDE1C119906974DF100E1F6AFA1F6B4FD1D41F60A61A3CA5F52A70F05662F083CBFACF6ACB61985898F666202805AEEDBA481DD25E1E819B710887E345D5B8941F47322D8EDD1EC5EAAD551A8ED5884F9A2C000D93D28BBC1D0CE2D1851D914552DD329CFB4404391C3155AB35EF66DA241C85E6EA29C8A9376171B2F877421A641AF13AFB7B754938FCF442C2A62428CFEF71075410B8610AB6C5E1921879A5D4C5B6F54F38589850092C5354734881F0731EC1D01D8D7DFE36DC706133ADCB3EBF07B7B5F6F4E9A436FDCD80E8CD531AF9B24F4B476EFFE1D7ABB98E18BAEBA491908FBC84BCFF6F65DE0371AE9641FF498449777C0D24262F65C1395BC1C1B3849B14F7F354FCA47CBEEA7E5E7CDFD4CBAE0F237F37FE1CF1345B0041F7091028DCEC1010D3D23E035F100AD9FEEBAF530996E471BEBFE9F1B1D04C84AD3C3512FF468E04AA7322D7662EB116F74E90A265C72990F2601702610710BBD0B9511E2BBB4BFAFB3C82B34FC5EBFE790DC55CC6DC7DDCD17AF38F6BB225A755BE34976C0BFFDDBD5AD36F59BCAECFCFC3D529E99EDD36EDB2B269229FD30C505A333679F79DDCDB4C6BAF54F7C55AE6831ACBCE8147E549FBDC0C605794E1B4EC6C9E489CED94AB53831D262AADEAC53E5935446AB5482A90794E0865196524B4F650AFBF93FAA5E78231BA801F7593AA1A471DD1612F24E3EE917A282D461B8A5403FF2AE6F087CE8E6E346E41E76C03A5CFC03DDB8220E78EEEAD51CF71B79E47E2161936ABB6EC5B552DEB57FC3FB13602E1884143F834F89B372CFB21A093F5BF146E036DE4B46D327195267684D046DB42D1133E59596DC4FDC2B6A0C036B7453F297A293D000CCA258A0E2A278B3ED183EDE0DE785BB2F3B5F97378817BA7020ACCA6B191144710ABFFDE29F66AE03348DA1470EB20338C572386B56E67074B9E64A0E52EEE522491C3FA14B7E751E07EF5C3906396C71B6BAA6C55E2819D3F1557F050F8C41F851D8D43167AD703972AAED427A8E0FB750F7A98CE663C69CB77B016A9EB77DBD2F97233403AFC3EEB6AACB3262D69FFE84F112BAF7A78D0C31B830DE27C6FDFDE869BB3F69BAEB1DBC3982BA410848C7788A9A43A2BCABD434E93C80AB4A24EBA5A8497D28C85E93C69243E20015EF7941F59CB2A3E1A69985511A16E4E82AF2DE027F91F9DC000AD4A27036373B1633AF1D3F21C3D2DB28DB3783C97905B6E73B734ACEFC2CFC0650EA3EA4CA99557649359AE05BF3C0C190CD8E74F5062F20638F77536DFDB3EE7439842341B4F11B74436338F0CF004B1FE0D100207D97F90B58125D151BA8799E8C8BB48958AF17E27B983CD11FEB8380D82C4A8EA0E4C8AC528E01E4C87737D7BBC84A694E95BE782F6B70884227929EDCC2AE21A0D3AFCAE60669EA4FB79B95AEDDD12038E867A1C1EBF386B62916B1FF180469C308CB275488CEAC739CBA11161C72B771A7846FE95478DE8235BB3378F45F77AC26A61C7A8BF889F3F78C270C5FB47D4E6F2F946DF1828BD9F94495C4BB406C6E8DC6E0D2A0B3D7400E3E90668E90E3DD55AC2556C8EE13B7F77E6B0C4E05031F01D73ED870D0F6CE6F26891F3D94EED97B2D5F66C67C7E101F0E9E6DAAA1DE7C0428CB9FBD2F0E88E0ECBB38F6F0A9B744F97168BDDC18E45CD34D201662E65FF7F22AE39FC598B4C1359D37C396E526BC8F80A4CBAAE811255EED1D7D8958FEE2DD3277FCA830E5EE0E4660ADFC926948750118CBD441F7448C9FF355A53CDA8210818F27A2D8B0EF8F6497BD7675739C11ABC3F8631415DA5A9A9DE0704B9242DA5E32827E7E042DCD933B6745F91736231E5306D1EE112D4B707FCF80C8304685808ED08D9EB21489932A7C6C635017C00EAB8A6CEEB83FECD722FFFABCAE7D4CD25B1D3FCD0FEAD728C7BDECEBB111EE80BAF1FA7D512564F5AF1F89379D82DB037C5B9191686CF8EABD9D674317EFA9A28B3A3B292D12B666AF3F00161625156D9FD2DFAB42A5AFD7D9717A3F6457892081CD9031BA28C331CD155FA34FE981A89295FC69861E9EC921BCD3C8AF1CBAAD9EBF4FFC7EA628A467AE5CBB9546C009412FFFD3834376D0C525952CD846E572EBE4490D809EB2784EDE4FC478AFC304BF68167DC1A9B7C686BAC400D6F79903D0FCA521C79E9C94A927B2E129718F84F65EFC5C3EC486530EADEA2EB797613E11DF0E1E114864031DE0273CBE6B85F2CDF778BE559959A7C3954879445B7805DC51BF38EA0068875680E99E94E61801AA1442CE5E7C9E56603FE82E5D88F59E39A81C97E2C5A45E47E8160953F0E57B8735F4B4F1F1A8EB875E8CED1B3B844B37031E815AAEDB1F502E0CC77594C5C73B10414EB40E9C74EAB006A7D5920E88EA5696C7258D583A73030A444020E4D80B38FE35DCFA3EB280BED403C967995E6D5B541F1374DE72900892AC655C58F52716006A42389E58BC0F6F25095C1409CDBD41F1DE27EF3A33D930FEC06AE8DB18A3D83CC0DDF8A63973743AD76E55B44735BCC5F01F17C3B7E1463AEDA920C166F73CC811FAC80D87C405FF3108E856F9F66E228789112C045B35308205B4B7C576CED73B78614EBACB8B50B18571A0B70887DBE53BC80CD1C98D7F087CA0F41791A619D6886A449069CDDD1D20792931CD5ABB085764C7610B6C7BE303FB63A14229A34829A2B80ACF1449CA883B6B4EE58DC095E5264FB470E12529AC39D66EE66E2F03A3AA9C30C4F00B99BA55C79D972F5D0E87AB70647C2F78735E70CFF8EBDD280A5630B4F7C75A4FACD44459EB9C0524DDDC4769E2FC34CC1B4220CF6EC9BF1B490C959183E55D769A905B9E026F7C049735D34CEE062E6BD886980AC673AE25C5C68DAD2ED3D80402866DECFAD1AD088D2C782BED205684848E0AD9FAE58C9BAFD4534FA15C2E9FBFBE334799CC979F44A1020BBA43120DC06952F90982EC8E5FADA21FA06B9404F50A9F29EBCAAF20AE716FD357D79649D484BC24DDA536162FC20A2CD7605F27C8649F895A8BEC53A67C7C5189AAB9473423769B685FAC9B8D876A1A1336D5A757DA7B3547DFD6ED0AB8E8EB79A4A5836B5A00A17A60EA315747D3F702851BACAF6A596FAADA3776E61051F5815286B7CF2D2F5EA32EA8A57E21791DAE025B90CE5C16E4CC6068A1EAA53560F76EFA52026A45AC30669962171D15681AD3BBB59DE704D16700041D38B0287AE4A033AE28A1FDE30BFA4A325FCEB00C664263FEEE7430137359463DE3132F553AFD5296C5E81A6E2D40F35A06E6F46FAAC3DA3E6D7D8AC6DD09F2D0270E6E97374DD2466F168363471DFE26BA426F18D5510F69E9D6B972A30C520013669828DEF096969FBF67CC86110A5F1E1DA556CBCC79EC670B7BFDEB2F6D00B5CF62F03608BEB65BF8F058C4991877C7F78321276230CB832010C577A80A102C8BA08AB2A19B29BAB88B22EF51CAF112EB28BA198424B818AF5F598786B50AFEF0B6F63F906E0C20CA5438207DC416C571BE97D9DBB874512BD2B200D6173C1C5CD5D3548D88487F0FE37BEE3F1415B937389EECABE889ED0E062A0C4472F91229699EAD02A0303900D8DD343291168A96C68FAA165CB635CB61AFA3A7DA9D142025BA536A4EC9A925CBF27AF572D22D04BBD5E0875B2051C9ED89A6978EEA01B317E9531AA82CBFF19EEE3942FEE9C21BC9E045B108D596CEE0A070E7F3ABFB838A635300D161689B136AA27877F81B8358E6C7FC78EEB11B890E73A21D6D7D075F87070DF761DBEAD7E022CCFFD93FC33937F8221DC9DD916ECD40A9DD6F952469274939CDE4C4C7D0AD4BAD782E63FB5DE6C2B4E5DFD68C0C11BCF8C64BFD6B9062303FAADDA3C2C3E5C275069AE3A70ED6859AD0F4B66F13538FF3A3D47851A03CE9E956EE20C8ADE99DBB12AA2B7610C58E7EF9E0330ABFEA16089CF01650E42ACE98ED0941DAB1FD9D7C6815FD22179BCC5EAF5E88A2FF0AA349B745CCAED0BAD16D1C9B8FDCA37E115DBC858434D3ADD8E44FDD9077E201DF9817B653406E33338B37103DEBA68097DA0EFFDE985C872C86E0E3101759A711247E044B21D8607D9FBAF15C1FB53C8B0E8C0747356C2F96C38BE2293C3A47C99E8014C719EB4BC342F685A591DFF88FBF0E746E6187B253A7F3A824DBCC6ACC76484C268ACA22DF6670F265DFA39759BAEFC3AF5ED0ADCE50C9B6BC5213F8A54C1070B26DE7FD95E3687ADC1924957F7A135CA0582AB08031CC6C43C8A8623EB8A6D2C111F732F78EE1480560A66481DC9B8A919D453518153F4CEA84A1DB6A5717902E098A0380FEBE06C3F37ECE7B4C095986ED5BDB4EA038D1D2C27CC72E56F5576AE14A1760935F14F1915AC41B6B93D5660D2F240466DAC6F9D6B2341FFE1955E5ED32B9384F5F5C2644BF3A34DA144DEB7E111C3EC5994A2173E50B2A5C3BF71A83327A7CFFE836C54C22D99D8EF11A130EEC439C51DC2DB558479FC5FE9E8B6B547CB8278E15A3FDFD1AE771E6CB44CBF728A0BF0D6F32E813FD93AFC2509F99337F565525A5805144918CABDBE8AE5AD93F66918E2A881FBD538246A1362A1013DE4B09CC85FEAC1D725F62EA51E43ADDFAE5D874017107EED53F1699CFEBD8CBBAD9548420DEBC8F2D1A6EEFC0F830BB2F716F091581EB4C65C93E93C86F7A3D550119E494C0F41EF80D805716228C8E61E6A1FD14F421AFEB39077A6EB54F1E51BC5234B4EEFDA822A57009F3A709D8705013107C2E1F4E1D157C8A9A5E0CD3C15A968E7FF0B3462C4A5D784347F5F342E1F3F5A4C973372959974998EC3E7B0EAE56049DC2CD96700897E7BD58DF85FA3092B97542EAF1797A021EB2C644794362D1FE2C7DD25794115F9C23A33A01F011B4A95868653D8FE1A73FCA7A12BA15143F16C35424B6831A4A397F8F6F3A1EEC26F038811EE41C1EBCB633CD46985199C8C3BDB0F6C03E5682B65AF011769E48198752891D287C677A41AE1B638AE5BC0D0504848C9784D8A693F081D0F09CA14A7D567E25500B5AD97D0214D7D52F08FBAEC21DA33D801BD60A9EA5C7B60C6E2C967270CAF36970AF351122C74DBB56857A1E952EC9444A5FB0B0F5A56D9E17671135A38682367381E9DDC8A4F23378EAD5DBA9C2DFA5A5952A7B97920B38460BBB9305A4C20365E420FB7DD8697C266B78130561241ED23CAD7A32E6B928F49ECA640A790DD0728F33E751E9AF2113AE250CCB1D17174FB6734EA354ED8FF2D2F62DE648D52E6A113F9BFE58A6C5BECAF406DF3F0D28F221D29E40F93CBE08AFEFF3F960258BFA7B35E65357FEB86EE6ACFDB2D0ADD23DD4F138EF854B61C7EC36B112E6DD4AC8890F6F5CBF449B09CA762CD28019AD0DFE1466C11CEE53678ACD75234800DB30A0703304AAEB3CF7CD3DA34B5CC84DE8922F7AFB774A931335232963803E266486C34AAF56FD2FA20263456EC17D17E57DA3D5282EB7C7307D6A70E3591A2C0CA68A0BF0BFDFE4E0EE7A98F3DEC391E519F5700A0CC32024AC3CFA737A1C102412912D6EDE69B1D0A45057DC280BA17435A1CF7E16F3687A6A4DCDADE4370DEC954DAECD1B03896BBBDFC2CCDBDB598A945EE09821E9007D92EEF159509E345750C0214BAD6A5D7E811EC12D8E558C9A154CF74AEA8070F1620FF2D2E588DBDFDB8CADF907CC0C96B831C4ABE7A431A7D580CB63967880A9C1CFE912F8D881C611FFD434A8514D9D592873FDAE5C8E8556A563B9D7AF48EC09DFA5A1CF0F3A785F0FE6BB1BD4EC8AB712931126F1D34D7ABE00887E36EF73D28F3B87A0BD092D3D4194E39EE9A586E8318807B716DBFEA88243165BAE25D9EC74989A21971C7672525DFE820A39560C5D913A28A0BBE495F0CAC4F07585AC43CF5BF54A842FF6BC8592024D521B5CC748C296E4C3B645289228013B90A9275632C5482E066FF5BB69919D7CF3B51B6B8AFF18A0AF215699C6252EDABCA8723EC0BF2A8B5B45DC6F8099A8176D1F697E9751F27BD38FA7FA7E4AAD1FAB4B1715072E4641CE6074F674ADC81E39B0CEDB2A02D12B923F679FC55512D961ABA440F735DC756720E0256AE3A5B7FE6F3A56FB2BB618705F2A5FEBB4F8391A72024ECFACBA73F5C7091964FC3E88B0FADC6E92D4272ACADC7C693289EF8A41B45B4D77CCC27FAE58B18267EAC08C562450D728D7E8554F56171872E9E11CB2272A1E6C05F70BA07C270EC9C0F2C2031DF8E4BA9FA6F68A6D9CD35CE88D23D2C564231A80173EBDD3AB377E9BEA53FDC909994DAD76E388CB0491D01A64E7038BF19F9A6BEBD146B1C3369C6F7643364400D2BE7A43F367CDD8F0880123E981B0B387461B401C50D18CDC6D46A2E7233D7C6D41EF7F294E75338D749378C4AE87E5E64064834451E39B2FEEBA7DBB7E21670A6A05E8853CA31686DF03D9E0C09BB922A53E7A4567D645E57D9C6D3BA18EC36113E6316135A30CC2738AC772FBBA734D1448028B0A2120DB9516F05C3DA1358A8FD587B21A1E12930B8004F63AC8A9A1484E3BB7EC313D287CBE35ADEBB054E704816D7EB4378FE5D968DC244F8369CB1A6C31F3F106C87B476D2C6C14A4E308845C2564CD70FDC1AFC59A7803475DFE2C63791EC7D447092AFB5FBB489734EE12DB7C37B3AA0F45A04FCD5B50E62CD71037B73672545C8420DD67968C9EA56D6D490741D534D9C29F90BFDF37F6C669A3FA38535DFF1D06566076E6CCF91E060960DE939B0B62D61DF30ABCD70B6C5843982A60CA36BDD5A73FB6C50CB2C57384903A77A8EC1AE3E6FF90B105432E45713A2F4B09B11E2857D767025109A5045E808ADAEFC74770F3E0C20A724398796421B31A952742533A8EED5270E97C9B992DFEF48ADF73D3A591F7FFD65A11FA93F0B87F1ED93389B29B6F9242B05F26639A871275AB6194A14FA7FD2C00BF57C3ABF9DD2897183A29F7BC80D8FC018D11FF26AF3754139B66053062DE085631398992E279D9CF0590508EA275F2B44B4B30127BCC633A33792B83F3A5F12E14292B79903B2A5A0C7852B54FC4416AD38FB589D5C167DE556594693C72AC4E024215FE4967FECA9BD6BCD46E33C379E30C1780CF066A8CD8666D38A6F750F46BE5161EF7FF80EFA1EF706FF70DB2BA6ED829456E81B85B559FB785D8124983D1551C01FCD5B00EF899A8ED65191D8E7614F5EF2ADCA91BFA55E0B7F5929E9254069440D5E31B290491C20CDBE01676EF6C21F7911BAA6A689BA8F4B845A40ED76D2D50ABE4B47B03F73B678E363C971D86865D052539D64D3E762B6A0F5A0D1A917EBA6481E8A5EF78FDA2CEEDB3D8723DC7E492888EA4AB80DE20B8A7DDE86463047473E56564FF3D6DB4323E4C25176E3AD762504EEAE092E6A380CED61D8A26B4336D3FF1C4E1A010EECA9D1796D7850CE63F17BAC3404E3DA0072C0D337BCBF335D64A25165BEDE02F82FF11961347B253CFFC857BDA3766DA2A52C5C9340FC0925A4850AEB0EF9FC711954A117607CB586E2760FB0C425E719886A202DA56D3F60D95C085B449ACFB01C8D5648974F93603B5D04E327C52BE05CC03F05C52DE28EBEB705A0EE8A74B75A5B06D3BADACDD053F061D7163541242FEB8F1EEE604F224BA3F82B9FB88BF4944B6FC8E69A984C94FD07F27D5ED6DACB981702BDF6870DD8DA558B77529CB57B66F20A8D8401E993C5CB39B84D1C679F359063CE78BFEC344A0F2E8A3B25891C69B66B9417FD781838E42DD49D590EDCE6C2534311ADB4117CCBAB29D407DC64002622A86E1C0B3B088FB1598A74F2B04378A4A700829F371FA6F0F1DD2E8754E13152972C5FFCED19FE5BCABD839D0AEEB037534B4F687F219CFCE8F25AA26A381D380B2D20EB30F02E8344DDC74E76DC6FA9B802398A47E0B425E717D5F6CD2A356078F75F532D50E6864C774B3BA0B98E4E16743D106E9F3D2E5FCE3B97C5F5341D481D2C02B91223C33ED4F7F836D3AD9F4F7A45DB44CCCF394CFE4B6C943516C5D80AA8DD19008137FF515C24C7923D18A1872918870C43F45F7FBF512EC8B4D933F9EED0CE1702228EC3C40F1DC58746438A644DFB9FEA4D1D4D85186B9BF7C487371CA54CE4F4A7B0D562519BBE44FAA5F1E53C59D0ACB6514A8FB02A081AA209A0127F774E7C4A99CB8299248C160765E4CC82F564B8B490EB36101E25A8C41F5686F280CBCB04721C92A8C01235C4C8FEA6C4305E1FA9C72FA7759C88E7A4507B931EB1219831D4D740928EAAE9DE16623A88DA2F5F7B99C1F760AB86FBA586D1703E77CB351228DA8A424671AFF47D9485080A6200512931634375D98C2DD04A124D617C2C7F6285772AB20A205EA6BDDA3638E4EBE171D1C0C77246535D2D4CC921CE27CF1B3A54C80CAA5551130E4C1D061088FC2C20D51B206BFF437C5137E77B4FA9F55EDA51C37A178F4AF8D4EA3547F10F3A0322E6F9AC67F5D552C020D84CC6D32F7A68203FE2BA9A2EDB5B065D87B0ADD1EF8F3DC26DB8130891CA39D01AA6992727C8C5C2A5C438FFDFDCD38298D886D0BBED2081D1641FB09443E0E1AF3E6EDF9E131BC0CFBB0182DBD237303267C5C5C2285C09F30654558141FBD09EB0CF608443C09ABE5D9514603F6ADB9A5203C33BC4D1FED82C3B70D4EC9A26F9DEEE3A9363EBBBD87D8F01B4D8B0E6181197D90F78ADCA38FDED2465B5F3536136A6CEC397C520ABE3A9FF658445BC265A543021DB698BC7232C535DD13352BE3501D0700010A60A9F99C301AFB7C26C5CAB29CBB2CAD106C46AD6C0D4B528614DD9861210978F22A10A2E98299184D818D7BF479110F5A1D01B15FFA13CC5712031CD2DE65E5293D40933B06D35DFE7A0B5E4AD757EB8537A05FAD369F7CF968F98F011FCD0C9E9BECC44A99BFC6D577AE0A63212125C0A9A77432ED27E5275B86A0A632161D22AA9685C582826140F9ED3C86BAAC0AD554C39BDA53F77CF33D23C73E2CABC69CE53BAE2285E33BF251377A8EDA7F03832891146DFAF8BEAF898A269B90471C68249EC2441BA1842EA615D3FEC750F0887D58DA0A96238E437EAF7C857FC10E421B885635AEEE75ACFFFE18E828B850715DEAD14FA89ABEA095653323704E2032EC97CDB2AC0BFF98A0AFB74344EE2001C2FED78428D3D0FCB09EBF896EC678A29EFC5C5FF9A06AE0B14629C5F6D5D42490E2DD1D8E2F06D3264D1830CEB95CCE7AABFC787E60283F930C1F5E2B78F7EC81AC52C4004F80EA814CCCD8547E6ABC4BD8239DA70AE74F46A06368CEF88876BF9F29910EB3F910B76396BC12F1929CAEF4013EE0CA9587B250405D904B96353C73D4A15E21BD82910F4AAC9DD348AAA9A98B3319E7D659DE266C4C10DB580EC474611DA71312C38F94A48F2226CDC6C4B63338643814F185DE5018727672C8AF794B8CEF5B6BBD64D12EDB3D05BBC49B9EC7706D525DD5A8C3B7E6088D10B44BDD9B9381A1301473FB651B0569EFF1F435574AC5A6C36C4F2828BFA87C9ED1FBDE71966536F1C64F34069AF3B933E6C2489AFE7C72A96729B1359EB8432D3C87E17AD8209CAEEACE324563BE26B4940AE017F1BFC089E39D5B05C782D9B08BD60E9E74A5BD8F2439A8E68C068C275B4BA5D2E4F2490BCEC9EF698EBD9A48B84CF3178AC3D0BE797E74E8C1DCA6C068CBC4FF94A81689B3C23046C69A5C34B6F5AA19B79AA79C8CB629E1052D58D003D54AF5F7AED5CC4382CB4C1512F7687D97AE9FDAF5F89AE7B6C7E30A50591C516888732C94EB4837DF7D3CA10D6298B72356E26DD4B3361732416D838FF16F7E5FC9E87441C773FF273B8F75E70CFC4FEFED9E12584AD7D501C8D6B69FC119DD8789E93DFF80DBC2F5586407DB14ECD76FAE8848B62168702C5AE1259475E2AE4744CBCD3D2B8502D11555737C7E1C8FAFEA3333687BC335472E3B20D63A8AE74A338722AE395F823962AE17EFC748A1191EB694391C79AA5970AFC0B5B21B8BB6BB3101D5B95C300E7F26AB39F1A1BB279203411E5BD7B4AF422084C158D3E633A964E6E470DC17A5EFF9867D67246E3DF584CF78EAF0F06D67A69A9DD22165E5619A5BCE317295879CDCFDD919B70A234404718A1CF9B2D3C279551DBBDBAD011D42A7E198DA38DB084A33EEC81C0910508897D4E3D61FC6C1D4D71DC3C8B92DCC46C8EF6B41AF192A13188A3C3766C27C098DD2D0EBF0F3D1CBBF8C8FB8824CA708DF8CCD4BCDB8620A87174349F57663212F443C8DE0C8BEBD26A90560B4EA1F159968B5F0B983F6C74E6CF2511D9557B36F95B460FBB0E50D51A7D06539AD3203C0C5C15B57E9BB1FBCA4E5959F1860AE92CEAA97FFD47D9C2B211DA5292113EC546558FF229669CC9C09BD8B1381EAEB9D9B98661618D5E81F6A73DB6FF539549DA02206A9E2DC626D3505D0B2F08DEC90BAF49E10A942653A7847F85BF891EF81CB02219A8258B737607DB73EA91A5E84D69950E33FF5A96844D4E8A55E7B18DFD45FF4E0AE4BF631F422E1A6678D386B7CBDC8911861A163FB7BDB9B627A569C91A566CCEA8FCE3770F8704BCA049B5778DD9AD23A0D0BD54E07C44CBD67BB8A96733988BF2215E3CC339B392C58D89797888784E84E57302B3A4855781118E16FFB83B44CF8B9B99320F22C74652E4401828D4A082BFADD82FB4BB00FFB14B0E8752D707A9BF2FB5A719EC6968E5C6CC19F0B14D4C1611FC44795A0EAB7EE95F68ADD5D25228B113642CF0718875A20FBD7059F83521504F095FB3DFC20A01FC3D668E0C79B67F5EEBC57760EE2355A01F65BB0000293672118C9E28C215B6BBE30000289CAB8E6447BB5695E8D80BD2467E69E2F18B0BEBDD938022DB19D1F4DDC83D800A27668EE78FA5A24F1EAD457A2340B9CE91B9961046E7AA5C690EE6B26EB19B35248753F991A157CB65EE5CE9BD9752AA8E2B9F7212FA4687A6839EF8AE3E44B77C4F930841E3EF313A413DE12204D376FC53B0DCFA305027B302AA6429FFB39DDA1E7097E8E2649C8C3A1739106DF7C095512CD0D9084333685A266274A222F412CDB80DB4505F219C187C554A33FC319AAF4675684A7836A09C2116BD0BAA6684C3B37052C2E8F7B3AE878F8184BF04E2F085FC3EDC4709172B778B1D1C7219B993508615F03A9FC340E1A9E24588EDA8D1E202C43D96EDA28688283CB5A9B43A3308E776B72CA8BC1F252DFD9D38EFDFBDF6F727CF994DA73AD88F32789EA709A8F4D1427926C60E6E0FBE79EA4559F1FA0B9721BC536D3EECBE6275268A8647B35FC77F10E76E4DC2527E92983CDBB206F92B3F49BFC66B92B61760A6799B98317947D2171225F0127186CAF2C0EB7AB52B3BC95D680C220C13C9DE3F2D61E2D97F0C9167833F69CD964EC4580CD3BC6FB92A928C77D013BF07AE1B4123903F7980B610437038549F2D85B82AD1E7D1F2BA9252E7BB1A352845B67B3617F87D86F5E154A209C2D3FF774638EAF88960C03538DD0E86577CD09BBCD548F2AD07B2D10DA4F6882C7AA9A72FDB5517B08CF74A530B04ADE4E8701B770EDC3131D71342EAD27B2ED085B1C98B9776E32E7F6C44FECF7B04930F122A3C16E336078333AD8558FD71696D5B5D777D9C3F92D009156AECF14AE7DBF9A8F9A5E087FBCCDAB9CD2A2C7EA6C29480C99A93F66A87A964C37188ECDAE3DFD8025B362D22EA84A6D97AC32E284648C01B7EF9F07C6B8512B77F23A9BF121F7CD5B285634332FE797274783132233F7695FA5C67D94003DD0DCBF57CFDFF993E6D4080ED2FB52FEA0E04E57334DEF416EF1CB59005154D54D57F8B629B1B550450C3AF4BEA617A65803DF4CC6EE79B136A6DA4B71068A9B848B3B009BEB9BF9C5508778072B7F8FE8C8F3408D3F285128363E3C9B7C8B9D54C35C8EDB68E45C2FAD1500E5AE382A387D9B12F57044088DADC2CF9935E064BAE2C93120C4E63796E835E643D69D55CF4D10E9609F38A679F9FB3CA698C1530513A548116EEA52D1D609726149C22DA8D327F36898E427226D0DA205BC2920D81F086F77B7AC08862C30E7F8BCF7C510D7D82B122A79ACE6E29EC1181D59EE0260CFC6A1090AFE7D48FA29C50C408E6155EAC3A793A86B30E8F6352C3F25228BBC09FC34A4FDF1B36C62B9873EE271648D4B1DF718206DA07293C7879EFD6AC0110BE96C0C18F4A555AD6B6B1971310BA863E38B457E7A72D05257C53ADB1A2847C217464B9FFA8AAB3B75B59EDCE3341C851555837E645F002F9C91EFFCADF5EAFF053153F5B6DEFDD2BB960C8BBDC85D7F716B15F21CD52C1A9AE8BCDBF758FAE6CCB3F6C74EDFC2381F3404A8C7E666E8FA382D9C0AD67DF1D3A108DD6883A3C4333950276519BE6F39DEF23261268866234A1F65CF374291CF70C9D1B4580563C6BD29FCC6C625516879D9182454456655728E4E78FC220EB0935FA5073DE701887D3C025D4A76210CDB2FDE2F5645B42B393DBC743B69E3AA79A125102466782CBC55A0BF434D7E6220AAF54C6F018BC3DD58E84F5C72238DA645E87EA0442F8B0C4117D475395961272A1F0C5FC6CC75A23603201CEE4D735F27C4CC7CB8CA2852F986A691CECA426E823B1E33043593BE4E3F53B761FDEA06A61770F747CC94A7DE06F9103C0BD1544DCE777ECF7D319B51F60BAC0A2F3369D6B01303A2F6113760A677496DD312A5D7B40C9BA470333CB5B01254C702FB8217C0BF6F45139D9BB8B03EB08899B84C53C82950F1FC105D1F89FB141E3A04DC1895297C813CDEB39BD3F725CD7B00874E7D29B648D3E963B82C2211C9B60688A8281C8A3BFF6240AF77F7B75C87B6D7FBB6096DC8E5FDAF2048EB95C5C2C08CF83A366701757017CCF9D59B83198C5CC2C99B073DDC85D5158E4B85AD4E6977CA0E19ED16674CB72B4855F5E42DF31F9984BFD1F8042C4B5D615F7A932FD2C47D8C485A8277E607F4F9500E496733A014B5D5F87B1A7AC2047FC868DB14394C85ECEECFE4004B4EF0D00C8BD57E86B97179619D297FB881396326926788D89E811F240A0D484F605BC9D0CE66CADBCDDEAB4787F2351D4D7886EE1F84EFE4141C2576910DF77400D964FBD3583CED6E6D0B3D92E42960BCF50125B25547F59ED6AC86E45D9999E7DC100EA13FB78F815AD5EB1AFDA08D2086285734EC4431A71D4C8AE35A53C8CE1DAD8B3BAEFC2EFF1D5645071755C3A41B852C47B1842FD7DBA9D31EC3C93476E497196A02CB8CE0C757C7AB1F87E8820E9C4C8BD4A9023865029DA17AF601EAA4A86628AB861F41B9F5B7050B5EE00B26E4AA71CAC84653997793CF1A9A16131B5019042ECBD70FD801E46EC3F18CE6378919B77D09A948510840764070D9CC30A6DBC4F65D48FD0C3A3826E261E9C51995181C98234077DCADB7561252D9714CD80558877079A27DDA604CC34DCC1BA52E598DA8F41F60A80A37102F1584173F523284D51F1CA5E704FB02B791A90434EA3A1F97A2D13AF9B958167539777C937A1A15A6F0C50BA740C0B4019C81AF4E98BE0031878533AB543DC5E3290A8FB9662648FACBCBBA5AFCFA4FE590C3134F003BAF2D9FCD44A17EEC867F11EA936345D76E8F48F64D4DA15533F5B924E240E7012796AFB2D1FFE0A5A3970AAC4FCD591A017C6A996A958F3D93EAD40DEF3F2D869E52615345E06F77DB53F9D508A53D3ED650C0D0BECE34002B6A83E566E4A067FFE4E66BE86E754DD149F68CF0D8C9A7281574407AB119BA4947FAA134DB253C5AAF35C4F17F4C0C041EDCC6D0B2A24D7177295E2E86C9912EECFF73E70CBC643B775CEA4C9C6345B07BB431568E28046E2E111A76F202C891F63FC5E8100509CB9528E25856957DCB69F06105D94A4D67BDD43D679422BC27BDEEECC4A4EB7F39320B8B521164EA421FBFA82E067AC08565C812810602FD0D3F98CF13A87161118C2088B1090471B59EAFE87BE767458AB24ADBFF30CBBBF7315F0AD116AD627050830392BEBA9519026098EEF33C4B020725D288FBA7FC6B25F1F976047AA6D90019715448781381A58AD60358843F1329E278341CF67C996CFFA10DA30444788866AD35D80D1CFD199E39D04AA89E1E2613B2C9FAAB537AB9CA264BAF220A0EC9E64404A242193D2F1B8AD2A070A7FA75DD2912FBE381CADC1949BB443A22ACD6C7A8EDDF05871E6C4E6ABE9656A9B9986442711CED0883030F96DDF8242C44FFF60E154D8015DE2AE248192AF7ED0BD0C567A5F0F8ACEC1C6A48D39CCA3ACEE70F394FB8882255A4AA91516B4FC46E8634E1EC354844770EAEA8A0F429D13F24A512225FF479175400D7963333B685285FA10F383BDE96025E691FF737B574C612EF98A9F6D54A9A6B7F1C7FDCED64F5C2F882CAD58A1A673104C180A1ADC27EB6CB75A4464723E37D65C8BE3B38B02C1E5C716A98EE6C6B94A3B199C2256933F257EE51BC54298810C152C0B8DF126C7A249908A5AC0CE41B382F06A3229C2B58A4722861D78B30DE549337C9540FAB5BEE07F064D48D79853AED8591645438FC3D4F014423F26EDD7FE13961A7B95624A80045F3A49A6AC4B014F7A97984F7DDB86FD338BDE354DA453F70F64AF63A1A387A40DC1727D2CABBDF2D42E4C27BB655B62620B892EBBCB4E86658DE44E80753AF0A74AEEBD7A9FF1A5A44A9F53937A67D4CF4A602CFA93521C67845462D900F19AEACA33400ABF813F005136FD87C79DCB6DD1A622CED3CF94520FC942A1B3610ADD54807D0D2485EACE46516E76495CFC2E5D42E5361D919419F782FCA92AA72B40FEC0E7EA3D6F11724DB541D1F10C2AD908FC3EA89C17975C486D1DB89EC1EC8C8BD13BC7DC5780FA2B285053CE1294DD2747AEFF547FC0ACE18932320ED2DCFE3441C943E7173483AF26C2E0AC7B1534BE78BBB71688D4DBED3FA6131CE8A8D6173CE16EB4EC1A039D92D3275183D488A23C326D43FF684D9F146C6A31BC12E9A87F694AC60BC58046C7B46347F7C2C2C41A50829CA883A25D55A7D89F7DC7266E66DF38BE8DAE0537CF0DE3F3E438A2C2146355BB39A944EAD69D613F2C35B455EFFF30978FE75369BAB9244A6D09788E4E23C9B7F6002C3144F20B136F715FD906A8D08A62909D80504DBFE37611CE8238B385F98186697B3B03CC0C9C1D35A47AB2D9E90DBD0DF570CE95CBA5499A990F5FF3D3B214862E6CE8A9977A4C8859F1DEF7E5C0004346CD195EBE3E306A75129C00A14EE3B44156157BBE08A7758BEB6418727CE4F9C4397C59240FAB9905584FC2316F5E500CF8D9AA3A98225EFE7E2D740222EA39E5C9229FB746D9C1E0CF262FF824041738A3BC56616941A5A69CA111D74E72AFAA6AF6825EAC1D78AB50E3F96377FFE60D3929744BF5EC7FEB1A9DEE92B911AB39B68145FA451AC231446CAF8A561F7277338A52FD835584969E62FA28F56474BCA9D84EF5C2A232A39A2F6E291B3C11FCDD1888F1CFC38B74B0397DA3E4BF5DB9D9C44C7CB226E0D4179569BFFB10C3DE144F19FC38D81D22ED3A8778E13D110D74C976C54737C9A5753223592068F097E03B2EACFD38243B847A5D28EBA874371BD4B00EA648E3EF770B575FE57247EEE46C5BF912A2CFEA8590AD47A71520FC3E0491F26EBE196C6AD322EDA80A448DF8AD6276F3F33F8247D9BA504C289B6D8F2868924AA69EA2278CA1DF05FCD50CF820CD7EB24960C8F75683356A1238117468F9EA602EEFDAB7382AC59BB16589ECD2886F7E3EA249A6A9972BD8AE6DBF6DB8222A00FDE790080120AF36230907B1F3150D7A6890116DF862D74847F491355A1925524296EDD7EBC65C9078445EE0CDC398D5833731DD61A2DE62A2313021B718626DACA00F53DA0A824F692A46A8CE182AEADA54B44F4F856C29A2A0B59EA0932D32B44ACDA922F5BCB47C7F17A9D457187487F0F4DA56A84E6D1ED438FD6EF7C7AB74DCC0208DDA70E264085AFDF8B60F6F49006ECCB753AFE5C5FAE1BB6DAA1C7626EFA1BA68DE03A7D8F78F2C13F8D407A6749C29DA9875FCB1680FD81078D7BA9BBDFAFB3565A275BC17816E2637DB5325BFE290E48D6FD230F4658F41D885E82383D43392BCECB03A990F14149304F001FBC81494366CABFDF8689086F1967A25DD53D2CB8991B5B99C4CDC80E004E789F226C55FC63455DBB895984142F6A65F0E3956B43CDCC7ADE92E9567C88824DFAE66F7E5B186B3BD28DC8CF15E67F6ED61E40924DDB2F643B186AA11C859DA950D10F7FBE3B9163A80C9B76D7A72C09FAD355BD28778C0AAC14AC8E7121086B36AABEE7CAC8262B2DD54D0D865975ED901A6354DDF9EC3BBA541F602D429A569B4908983B4B86C01A331EBF26242F8344B8B8481FA94E26C28BF596A0BED6BF770BCD63413DCDBD2FD83188ED047E747EF3AD052AC23B3B112BA241541D62FF2AC34E34ED65F4638D99B9DF543BC12382BC8453106A3DE9CF44BDC9CFA77D6C9CB58B5A4E9BCF31283CA6F4364656876EB67831326C6D8023A5F49EE2D3B0CB31414C75A878879B4D65D7098A013637D7922AF6CD348DF584CAC496C917D88B320B433A685542F4D0D8D78D96B548493B5B39557268A28EB19C16A0896D50BE7BF917B68E3A6F7A0374DFF12877CF3BF2805BA3637A0244CB8AAFA9A66AE797FD5D9E1464E0544B1CACA08492B62D41463D854F5314F496D8D8DEF5A54BAAE38379D28C9C21539B0AFA22778FE9A975B7F18277D4ED8A3735EBF25783DDFE19793EC2BB5B3F4A89C4F10B01BFA5D829F473D233EB1CAA2371A4CD9D605D172D969947C0ADDD0FDBCD14270D5A083484B65BA7CBC81C58D7A117F11DFDE13F87926DE078BA4C0CF5A13208BD5FF9FA0A29C5BD29A8829EBBCD2779B33D7B7445772BA3BFA6B63C7FA7D76CC49A34C9E1506255D1A8E9B874200424BA0BF0971E2F482C25E7A58CB2086C04DE629AC91D971B8496912C1A1FEF6DEC4019109E9328B1163B6556FA0431D252C34CA939576E80D56012902A63A6332D2D28289DD69D1B51A431876F75A03A7AD91863E7DBC453FAA480AF867B646AAE61121F374D3B7AA0CCCEF26C83218C0A8EF515C81C238B9D0E34B30A527BADB3F8A05E40640632A4F5A9A96E0998485D132B5D81A5AC135BFEB4C283042DBA37823D160D056EC89268F66EE8F48F6212F8BCD6227C9315582074B4BC70D5D6039A0222646B821CFA3C73C6243FC141054C80F253FD58673729E5F5A1E95CED50857129D990DAB1F51DA043028D73D978E45B5E0B0ABB6BB95F3F1E54511999E9A862B5943AF05A8D24B35BE132F682B5246032FA73C60B4906A3FD68FB2670C1BA8ED389B26ADECADD7B8C0666400668157744D55B316A3EADF0FE6A7B67DEAFA0F52123AFFA59A204C764298FB5EEB43A0430CF1BAF48DE174A12B94E5544ECE92DFE923AFA4A190FC901FC715900AD67BE223CA834BF0B6D52D04C6DDDB0284D6F113B175C9C1F7AE53ACA3224079F32DDF2D8C9D6C213D73A6CFAE889C238D0E817582BC9B153FCE9281CC045748D7CEE32D9FFECF9412C75E0EC9399176AFCCAC40FB5E80073DD2AFF99393F7212D49918EF124D39E1A7EEA9E393C66FDFE0BA0D03EC62ED40B3BAF3A549FAF43600C4B9F65B46C70F0A3B798B5F6F30C47BCF6ADA45D88B7CA386587CE37E347D131EAAFFA4A902C63505820D9FA81BC572A4EABDBA49926C73F7883EDE22FBA8CE0F56A024056809F4D3AADC5AAF4CF4F559BC17F408509A2D79E8204232AB7CD23766D5473C93EBEE639056FA943E0776DB28931E43330649B7889E4BD8DD9E088D40D56F279E6744EF099C97528B1CB65E1E7DD8BFE0315760EA66F86DFCFBBEFE123594AA138E047F41E5CC0D6992566046BA399AD6B5510AE23044856CA7B9880FE0A9A190E0D6C5A3FB45E048B185A86D7B06B23F531F69C535D2B4AFA68C4E28EACB8B0D274AF2D7218606506D3240B6B07F58ADC31C62A09A3667051DBC826729D4EAB41226B5B867ADDECC4C92364A6AFF0F3DAC6E7865F25B40782735A5C8E355EA48AD21537543DDC7CF5A1BA98EE74AABD9C732B0BCDAE3C4EC962CBD3E9DA6E6D30BE157026D1E44C2AEB9ED7A71861872E7FABC25B7DB07FA5E48BFBAED9289D70D40459E159183A2739C9D4A84DCE46930C23B1D898ADFA23D7F7DEACA07D4013DCC499B2E22947EC9061ED103D62D1570A43CD6AF7814D977291679F6062831B5E9E3CD80F41481D51334C384BA5B1110F2E655154609A0F25F6E4475F49E28F3C45222BA8DABE0F33FD736B376F3F526AA2F4D1EEFF55CD6A48AB7DF93EC1F0BA52390780323FD8559377135E1EC229380C4754B9ED95D9EB37A2E62C42B00E8280C56B271139E68E39B3990F439D64ABCE94FE9F834CAC5CAA9E1304B03CE71FD2814FA21EEAF619CDF06A8C02D9F496FA36314D278099DB3C2938213C57A4DF167BAB97800680B452750DD31F025063C1DCA737769DA11F15E4A4A0F42FC1DAB26D8B124FDE946850AF8373EA3BEA4CF059C9EBE5106175D2C5DA8A3D1DE85189CD662247FFDD1D1EFAB717DA5F9CDC5C9DB6853019D31A462ECE81F783369220E9536BC667E28B4FAAFC84EFEF8590554DF1D0FD260D7A59547070DD1742A73B28EC174A7DE07FA043E1D8BD6AC6C3EAD1DF29A8F31E72CFEEF4889FD7093721B70399F5F3B709246E9E9FC7915C24A7A65102CEBA3AC3B2AD47E88B79CE3D1886793E529398441B62D941D0DEEBBCBEE34B52A7A9D7387425C959B8C63F06A000841C02FEB7FA39D9555D285BE3B00B31BE3AB10B8EDB6425032F516C2F7DFF1FDA15A34238E293B95495C6875DC50D4E08DAFD250DFE4FC69845D2655A7F4E2ECD406544B9C6455660C95316B4A3F08D6AACAD4CC9D6A9A6B9626AEA04CE21BC5F769768ED1E33BB4AAD1172B34E6CA0A02460ACDD430ABF1A5FE0337DDC0D96E8AF5660096E1FC1CFA47EC2E0146B8C9E69D9FF03349BB8A79734BECADD3A064F61FBEC0A60DD6F40DF2D3040154E858E871E8BFB365CBE32B15DDBE04B39E34859B2CB8272206C24EA20E191A100FD547040444074C96A6486884B12BE3CC92D1CF3BA974BE608FEDE315440317BD6294FC3768BEF25B9A1BD9B97EAA0654D6F7C45D61A412E4F92E99388B76B58021494A6AF1DC3789DB322429A63E8F0801F23DFADE6955D2AD608CCC2FECF551DC5084565C1B1DDB723D029B2F8DB7719CF36A11AE017F6114563D33EFDE306A0FA91F0A61206410CE3B0E85D5D4E81B1E599CA7394E590559519FB1802207A61884FFC1A567503B10E46ED742E75A0F5ECE8B8932B1B2EEE93910D9C0713E14B0DCFE0F8C8A9428DF19BF33C15C9942D0BE7AB22849DFD8E518E67919F36825724F07684BAE1BECB401BA5C5ACAC40E49FFD472F3BF62840982A7FFD63DA1C144ED79499596D8453BB2117551CB668C89313461110589D6BFAFF2F1A5410EFC7140ECDCBD291269E0BB88538C5A62AF2B662E192A699FE40D248D96558704E1679FA41B473820DFDC24967479738E92A0899BB20CD80963CE5377E27E0B65DB1FD557C9C851B69392337DC0D2276C7C5D6C04406296A6B5C1115BF1C5B017CF60F6DDF955C14803A42095D195238159A4783A6BE2EC9C363B1FB4E7D6C1B89A8788862021E8B51FC1A6E6B420DF60756C3BEC7C3768B3249B2CFB7764CA4E19A2D80FC563606C18DF6D37BD272D5E79DB7A4FF4D4992FDBF0A122A402DF74AD20A0BEFCA5747A765738D760C1728BBC8C24717EE81947B5FF1A0840B5657E04F92EC6596576B4E4522D26222709646C60A1C32D110880E4ABF574608BBF9B70FA1FA234DAEEAA6C0EACEDD5522EFC8EA67A640ADE760120D5FDE8B79F8A9AEC7BC59E567CA209444433B6ADA537A9344D2731C359A66BDDC508F41EE60DCC1217C227E555873427241E94E0B510C7751ECB430AAFAD3E1D170BFDF0F225E2A3B8ED8E6045AF05FF7EB6C690E48AD173FCE29B510129BA51A43931B5A85CC1F96D77D77828D69E468CEF98D7A6293C0C71DB10DB4E655082ACC335316ADE63690CC84EFB350A955EBC320D43959C7EBA3ECAC255E46F5435660DA6ABD8BE590304232CE0B71687F7080B82C68DAAA18D98B7EB443C91FCBACFEC54D8FCE9F42A7B6D028B36484D3D7D1A60792DDA18A8020F2F855032FDE5C64197AA468528034CDC56F51CAA4F92CFCC4E37554FD6687A61F2CE21C9B9F4199B329B138564B24AC7AEB3D8C4C643690EABD33C1B3ECFCBB4F8FE0A9A75D24D1041B946542679576C8AF6792FE8942F5C1D8E4B2AF21D851735B6BFB85750A30800A0E1B4AF0AE034083132A0F9B7CCAE52AA61124D46A8395422882B9589C7F0F274B66AE509F37099B15D5959ED9CA7580E3C42214A12B3626501B0A4C6A1212188B21E347439CF4621C51635A5E3E6CB54F3D65F1B4510392560E35A97D288AC7EE906AC6BF86D5DA143A651A2B88CA915F881A5032B041A689B1D87CC961180BB33B6FABAF963E683EC6898E88A933EFF2ED468E597CE6C9F8F568C36D07F1ED9EFBF28A132E7DBC143A497E23FEE76044A38ABA1B1E00790CA90D2231A0D54FFA96E22BF9FF90B86E7B0A03FB5675A42E3E0BDEC25D5C8332D589664D35698445A11D6A55E80F750D7C9E2FCD01F7AC84CD09609C54BFDB6E2884F10F87DB4EC21E8C4B026E80A6AC41C79A9162902FA4465F6B4AB1EB90F69276D3EF233DB733E32C919982E6159034AA841EE46A5300CD132405AC7D4DC9215CFE7496086873A46BF614CFF64DD4845C7EDED92EDFD6EC9DAA6BC259775AB24CF26C44CD0B94367D5B569AC084D62FF9542DE2211D9416EE14A4922528F9CC3B390A916C42826227512CDCCFC990B93B597C106A5108145E3C40C4EE6DAD094DD220B27FA6AA47D8534203E26365D87AB539D6F639F7292953BA805D450C54E6C24ECA247FE5FCEE8E0831966BD1F1C1169C0FB0A1015FA28ABF1CF70638A4D7FC7E753CF23E45A08BE4C7624DBF627AD1E859793577C2E76988697201DAD7EBA3F2CBE9FD9C61ACCEB88FA081672CE05E8E68D2AF1C76E5B3C7E1091D668ADBC8E87E1E635A688A797BC53C36FFE8AD384BE9FA89328BC9FC94B4F90D4C50A67D42BCA19B0F363B172C5E1CA1D06427610E2BB6C6443F7C9CD7704FDEAA00A0B61405F2E740189CCA8DA8AEF585DF7F1ED83856AF67799D57F065CC33B2353E9AF4192B08460D8CA9E555C12DF8D1F3B8C0F58D12BF7ACB5EF1299EE0356AD967B073A247612597228DE818D5941C84CB0023AE8ECD227F5D67BAA96DC0604C34ED0C3A48A7999FAF18351E7774DECABE091D88453CA048EB0F6CC472B27EBBE12552D2D52F30DFFF4F16D8D5170DB569EFDA0BC0C8C60F5110C67A99F15B46908A5EF70FA835B544049F161C7B69B44F198E46FFD928DE85B89F3E523A2ACCA0E8D5DA476C189FCF86F96947E3B39FE908179967BAF002797861EB09261BE629485C50C6D454ECD5E4D63041DC8DC8515503D1A6F3FB7D5DB680CE8350D88BE2A6507F49FB97C4C44E81F7A217DA5B31C3029C6E15C5B3F7C1C6149CCE0756C4130705ACE06892DB451D37949540B4C0B54712904CF81C59FF0D81DAE2AA8920AB3DC087FBB1056735DDFAD592FD4C000CA1E91C39DD0FB2ED42727F680DF5973DA42E22045952CF0A91864642E4AD9865FAC0D4F95D4EB1D77E05FA31093F5DD51AEF75C111F55BB20ADCB2B0B291BB61E2A571A9FCC12909E8A7C74F9FF6D176CB8067D77248EDCD4E9F4E66D0815334BA1062A60542B8F52C4CF98B51FFBC861B293680F4D3C00F466BEF774ED27944BED76D368EF6511CDD0CCC3399F81486B85C4804BA2FCAFF0581A9BA14F40E3933F4B10477136C8B9AB935B5A6BE14ACC2C90156B9FCCC996D843CBCD714B5D5F5230EF58AE9BACB5BE9C2A38D09574E07747CB592A02C53CF5C63924A60A1669D7482C8D1CB9D2A848675E813C41862C25B649B1AE18DDD5C70D9C99A1918C9624FA55CBA82EFA382E3E4AB72B272A59290494A795A1B9ADC12C6AD7E5DC1B4923578D27A5E625C73D014B7064AD4DB50D8DFEF431A4F92AC35AD45B71831A058E3647451C7F68C1CB06970578B002433A8B59DE98766A7ABC9A8380A12E687D76B83839E620CCD34A9D672485DF81E97D20C2814403BEE32684B943001C76B43A9E7F755731F833CC34C2D6A3F7FC8ADEF894B24915AB3F8A867873168A8478ADCD48C135B00DEDEF299BD3FE55D71558BC1180B6B243D15D24BE76DFE58195B843C4D020D6117A9031C0863767578A51CE32F409A16D2C633A946CEC698951AAF392A5C1C405122B86D48BF518945754EE3CAAF8CE1871C12F5E410789FFC710E713C1DBB5650C0F035C3B4455D2DBEA8EFC9937E5F1FDA6FD73E87EB850E25AE2814FD7A63F309646825B98E348A73F088B179192B24E1B47976E4E01782290BF7153087BC92DDC3DC50A5D639027B5E9853B24A6892E54516C4EB189EFA19FA81E01EE6DA588887ECF36CB8F62A33FA4C03E0E56620EDFF6A8A9C0A18C4AA7C36DC1AF82E8F472EA396596BB06299B525AD95C3090259DDEA8C6DFF9AB266F6295E30EAFEFE20C612FA2887CAFDE136D25E241354F4CA0CAB6F08611184551EA1699FFDD0D1B97C7BC45A828C4278CE720A67233D96D3ED5555BF18E38950FF61B01E3C61806C770925E157E6BAA6E60EA3E9FE576083EEE3187D053040494BFC50C2BF6FE5454C2CC809746156FD1A66BD5693F78526E0E3FFE8680C986903E42AD2D22F5B4ECD9A2EE2F662421AE44C82139B4C99DBE6C0D83C2552E125EDED45EE4C8AB468DBDD28C351958977CAFC72F56B2A2DF920D956F92800D97D68B4B40A9EA90E089132DF96C81B4BD9025B7930029148BD4BDCABDB760876E4C2497896A88ED4FC1CCEC183AAA8FDB9766C9095E3895B43ED866213DBBCABA86BD9F8BD8DAAE6E65F9D6A00121122763072500E3DECA07C39AFB15DC14E3DF4B78F86219244C2A59B19BE43871C0823C1A6DEE8DFD104036F78B8FFB278C70D5090986C5F3A4DAA3BF9B80239F1CBFD08A155DD37277667647F4EDE2F33ADB78845F1F2CA41241F931EC6CA9D39BE701AC80CD58774681F351ACACF55163339E706C80051AF153806074388EEA1BA0F6DF9D61E1734E5BC96B20B2A03EADE9F5D34341ED0AF7D1C3A03A0436933E0ABA490C8B18755C09AB09B9BFBC127A9BA07BDD8B64C5F19239468E34BA64F8A73377E382CAB133B40AFA57286BD7C990574ACFD81F879F6B5DE8209F5FEF2C0B0410D351DB5E7937E233744FC8F1DCB4E34B023B8B0616D7377CBF6506BA485966C78C975C7E9A5A57479612676561A1A81EE31899661620A999D385C83C5BE3D7C094B883052D3E51350AE2AEFF3B70CD79788BA2A10AC680C86403DF5187133F1CAA730A6FD8FC5D825FC842EC6F3178A9CB8D378C779D94CB5722929F598E7122C4ACB9C815DE1D9D3FB012A4429A4135FFE30DE26E6E6CE348A28552CD02F3BD76890E42B24CCE80551B57E10F3343CB1E22740D5DAB48D63D7EC310441C3A03EF2D068B89411D02F795B6161E05963C350B4437F7936C4A3886BD1BFD547382971F83FC64FE405DE43E97B47FC3E6A319B5BFC8C3462D327D9C017867AF4B4AD860E5149B67738008A16EEF46168753DA6B87736B279E6AD772829F074698A523F3C28444C4BD75C66BF385A78A58A2ED8FADBBA80E8F03B391A00FB6C53666D46EBF490394A2667A6E0F611EA20FC6D35DB53C07FC947D7C9975F141702C922CB92807D137A082C21AB23A53D3BBE7752057A77129AA70A6AABCD20C8C6865C2718FBAA92C25A5B09C12B5078657EA83F71F9A5F7F30305B07E20E71BAF024F174EDD64CD556917C663CB4596C05FF4A952854004F5E29BFC45DB30218CE050EE07EBEE4DB68B6ED2058B2E7A84607018689C8750F7D69B6FB50D0A1141785F88B91B9A465045C87438537715A9CB6A3CA91A2D8A097B13B883ABE281044487E42205DAB197D526A00E3D0B10F04E8E42D7DABEF50F8DB330F93EEAA513AC6C649F7392256A1F980CA0C3BB252EE86DA581D895D992D419C24F2BB9B3E8F55AF2C2E47ABCCA94D6DDCC7C774123687147732B661AAC17CD7F347CDD0753D1C074A4329D98000F648528BFD8E0B010BA56D7FC3A6A16975BEDC90CBAFAE757DC5626C6F0E25F04D762C22B3C9934A09E4BEC3E320E3ECBE8A9535319174F764FE1347DD0C5434F5E4516FBD1A548225A2568C8B97BD84E0A8EF1D1FE3A9541AE5F1973EE86FD8CE7BB7752214EABA4B75BC4811AAD5C1C561391F9CE6536F2C63EF8824EF245B57F40F9EE94376AF6B41B000B3E60138F40FFD8CE8AF624E763B409A210FC5416A95A0242494DC1D6B76A0E3040054453ECFC2018DC4BB4603DE162E1DE55FE1C4F2E99FDBA9F859FA74FB0989840746AA18A07C25C5983B7A2231E7C4EC4DA4D5C190975460754D51109453DABB1B2D71EE6F7453E55D961AC865FE18CB1D9AFCFDA327CDC529045BDE94930AC634A6F9CA9FFB6DB8DD430631B48F499B75FB2AF66D7C9C59DBF45E3C24F61178B5D8802A285A93335561D51FECC572011F3FD4FEDB73DAD314AF3E62AED3F43EC53E3DAC3C41829231A5AC37788A8C41E6E168998BE3AC0B57228F2F37E52DA96518D989FF1552222E29C1DAC74DF9EFA0B5282FD5CA0BBFC34B224F6DEB870EE2DF71592DA2762316D5C681A56052295DA7CF89E01AEE534792FD671699DF819498AB00359417A4F95A259DF094161712DD3B5DA16EC9D9E71E9E5BB4DE045EB61077233B6755C5CCA04578D679C765F6D7B090D83003C56663C30BEF964DF8E5952730201C929251CFA37A7455E80D72D19D0E22C52F8A7D1C5A7632A1324A44634C9EB5A2D41F09F336916514BBC061091206A19FD9DD831042509D6DA9BE7BADC099F84B27A8970BB62930366D1B682001E9708C4F819FBB5824C45FB7C90113636EE0BBCAB66F4653B9DE72459727A4A78B503B57C5EEA7463D40E42EE3F7DCCE12C9333F290F114A20153A1D977A0A108C9968418E1DB71DEDECB7AB965C485BE29294F59CE804782D91AD71BBB3284F15BF4F012BA9451A08EB7A75A1E266303BA4D71BD85E3132390D42616212D3ED6BADBAFDD348922A616E3D49602F09A965A1411AF93EE668EA1C271B2DCF9BF8E46DCF252B40A814A7F3C04308D1C1528D7DFB555CE1717A6A29E63FBDEAC3B468B5F1EE2E10A2281B01FAAD3DEF9189C585EC2DB74C516F2A9D7FA9DB52E573A6F4D337546A6375A10C9A0306BBC4C6F2BB16BF65A87A0DD8DD5BFC8D3FF13774A2055E5D112273F12A21B5FA1850B932884152BA2F4C8B8A51B7F6E69A4069D09739302D1F03B6E9C2411A2639B85F3D676C28C480DBB3117F94A0117E795EB14390231A9F0300536A6D8E454846894D30282735A17676688CB18709D632D3B8676C7FB96887BDF276A2D578D6CCEF5ED099849D384286EBC9B66414125E561CEA6A234835E2CBB890C75BE0B56DB35D6ECC618EB4A4E71C0F20AEF5F414843C0F8ABE9B7ABAF51A962E352A19A2FDCA53A31D7D3D9B5AFDEC3CF6051143C53C7C5C8E2C74E9C00D2AD6BB0513C73155E6B8EB93C3E95B30EDBC07608486905D210D60CF32B82B26F211A44B81240A63292271A9EA581AB3AA63A9744E5AF880AD54DFDC292AAF8FA83920D02C0CE1689E3517E5498D694AA91125F7C39BED0C175B5ED9DC2680A4AA97A8BD86DD544AD94FD50FEEC9B1B30EE72D155F573CA41D7E3C1D6D954E23AF8468C2AD9303C4B36760DE418F2490D4D4BDC3E7FD98D9865D728702F9B0A74EBFDFC69EA3AA0E67CC7CF7D12CB3DB7E733615523AFDD4C23C4BBB045116680876FF2BAD5DDF239B9E6F32412A9D0FD918BAC55FC2745CB8A4A2AB4A4B663C6A941683478D79EF66E471A4B30296FE8F888C6F2FD42E73B071153BD93AD9BE51CD6C9588D32F8BAA5F1C61AE856D57384CB498BB5A98610C2750791CA63C1AA23F3007F6C4717ADF629E84DB16B96F3FEE7E7EAF8ECCD886DDF7396EB60D4F6584DEC21B6A2156A1AE23F20111B74A9D6A45666727464DE37BA0FA409E9F4493E4BB02072EA02E8FA86FAA943E349DE25847DD69EF75C54BFEFEC6AA276840B7F5812BA98FD71F5DBB0680FA9B9C97E84570A380F674F025EA4684FD6360E35DCC7A1E71E822BB585C0486AE26C313B7898112F33026A6B11B04472321E05961203FB1CB68028875120C072F4C3CEEE18D156D0253BFA782D8D6E85C5A3110C9BCF5C72D45AEB42580637F78323687D95D528474E44A731DA9F385ADB3C7451A97BE5AD9D267BFA1D3F4114943E4E28B649F9E48E66F1CB91D67D3CAFD87DA4317DC7A49AA4494E26751F0366FBEE3B26F6AC04A5DB9C0674520D8BA30EE574742E4E8829FB11CB1E920BEC31E72855B9FE2D021FBE3B6500E7B7C567037CEBBDC3F92CAAC3146E48482E595B0CC66E978BF153EA59D642EEB1D9CAF0EAF1899D1A32F1FD4266A5120D7E87B0FE804843E3EDBEF4C1A74D394F8BA9E10CC50F69445D97DC723CC4477C699BB29D27BA3B96CFA57CD9F7DA86D92B92D871D0875969D3BE45755997C3412A46E3DDAC71960DD60F9EF1AE2BC0690DDA4AD21721322812136C5D8FCA1A9AAA0DFA5D1B397B8AD87BE85D3274E973D8EDC7086C93E0030AE2F2B70D61EAC6739CE026AC4DBCAF979CC104F547814EACB7B91ADD6C889FE35FB2EDF57F364CE26745888D1F10FFAD156B7CB324140DAC5F716F1D8FDDFF18159B4A1FC7FE1525126503CC3831EA94D7FD1E092FC52A1A102C3408E0905C8375138C6E8CE8E88E544F546A33369FDCE1BFF151C96F6867782458799F545236BE234F93C4C12B1BC0D7A148F06687256E05501D12D6BB1E11E0393AFA24A87DF5D0A9F8FB065984EF0BD2E8A25F3C7164A08A490069BB0AAF61D75EF542FF54DC8750EF16F9D60BCFEC19FB2F15314054B3F06724E5EBAB6ECD2E703EFE24839855509DB9865CD0B18C37A5A87C33D4A1DCDBECEA0BD3FF00A6111F5D9A72B56525EB80CE4A6B17A39D1A4B1CF96D7556AC97D5450A804B0E063ECDB03F63C8AB181FA5C657AE4F74E24C02B27F6F7E709B6338F226CE690604C633FA322653EB8CBF193BC5D86316F10AF9E5048BE625805154950234F8FA657ED20393787682717C0A772FCE694F32386C2FA35AB980477B9B97C0462F3FB05F645C2F0B287F183B720E3D94C1A1AC11F79A42C52A319C25D6088E68527073C36B70AB9DFD512F9E8C4BC278A127FBE4733676090E072A2A384E446DF352FE1053AFB564CA65CB44743BB4DE8FB2A164763CAA6D6616F0F264A7C7ABC4A6F64CFBEACBD07C7DEA63B2CE5F31CD608AB38C1E10A0E081636C618C88370759EA668DBBAF53D70A36455EABEA6D11030341DD085FBB9CCBEC6D502011D8887261A58B6201118FFD45A935336BC54D75A8797B9239280C0059F6749DD4B2A6410FBD19C3CCC04A47E92921A12F02BA85F5DFA15626BC0C58DACAD004BEFFE2754E7595B008793B13319F4EF1228C97248B1B12F089839FFBC1E6F55DAB9F5FC3A9A36E19208CA7C98855D7BBA14EE8D1A6AAADB559AF3ED28B7C43DF7DD94948923B3D24B6A67D6FE28F512176AEB54584FA519B2DEB358091A9878E0D76B1BBB42B471542926519B33DE96E9738C7402B2C8159F017A0A69946F06E546E668B653114AF273B1430289225694EC60E0E90064D82B2D2A0071143CAC21D09FD7CCC72D33377D2FA6EE7E1F449AF6A64B857FCB173106B84702B998AE82703E2854CAE71A3BCC2272F383265B944F243CE6178D755455CE5977E08D870F35E018CE5598797BA89AE1E04EBA95A6769026B9E72A26AAB518A6C06BF04378DAF29E05765841B4795D34B9923360333C5BDCF95BBE472078560E059846EB94CB29CB7F1F4F03F0ED1C7AFB4EA0F85863F93CC2B9709EBF8200F93BB0C217E9313E5F0EA6CC7E085AD740040BB2BC45DF2486B9AEA8B4ACBBD4D611578512903B8F5E1A269A0586419CA500E5911BFB3B04FC605CAB9D30103DE52E3320E52044E2C049FBC99DF4B43407CDA75438C5C24EB92B8FE96F6805AC674BA0B0979A7D1D50018E241DD86350C713D670A837A2D4BBACB90BD87861EF4E86448F1A55CA2EB752907038246F65B776D278135697E36506169927FCEE37FD02B66D9C662F49C12A078271123B4F834410356E24213F089B36288518F31164207A7E56997880BB7D4903571EE0CE992F862FA111C7358766944864C5DE335D03A1F591180407A7E6F241BECBB8B2964E620AC692E38FDAAB63655D99D30773C9AFF94AFDCDE5B185E51DF54A5DA08A5C7ACF115B3E14E5B029D1EB31BD2179409F6A014AD23DABC7BB7842FE23C53F815AA142685F867DCEFBB136BA816F885F4BEEB1C5A7AAD561BC83B642549A92D6631B3212219376B8A3D6C4237B4DF32EDDE266F7B98DC373129CB61ABF728862EE223A3BE85D92BD816F029664FCEC16706C473E1FBA8FB11D64F5FA3192EF06EEF1A05C7FD8BB8534FB49E22C55B8B6E929ED7A9F25B7C0674B39970E3E5A2BFA32764ABA1B85D83D2660598854BE1AB2C49025293A162BD64BE77FC924516A7E8FDC3F12ABB70E979EA2428648FBFB24B222CE8B10D8D6F659A17D0EA97426DD2FC9F6B7E91182941389CA001AEE443F6ACDCD36A00DE56B960FDABC882146378911D1589C09E41A520AD005A9879F4D2EF1522EBFAAF66831EDFB3AD76409D0A6380A18744C7D2FF5E718826075C2D6C8F78F52A29DDAAAC5901770583338FE4CF0F155CC30B62D81FE55845B224CA0AACE7BA7F2EE12E06731B5DC238B41628C14567DC29AE4E05E160D89A0E9B2D720D6F4BC0CC0C81C8EBE5CBC4ECAC219E4CD924826F0E64C72AF8A197E8AD4F48C66AF2EABADDA1B56A55B01840598AD979D824FD9A2E2640CEE7785395E1A9A9EBE54128CBA87768C8883A89F3668556E4D252097ECEA8F2FEAC4541D7AF8AEC7EB59D504E3D7FE360B468014F1C355BE8382AAFC2E6EF8E626DD8C385C7B7FA9CA56A73344C2841ED9B21338D3ED485FD9D46B3FB6981A3DD8BDFBB6854FB019BD3181EC5494E0F482385B9DA1C8EC8EC4A2D8221A32F098A784F4B24D810174029519DC676C1333AFC2074F9F94E13EDFAB391EFFF9F36A4C5A58CB6916D51A7401A0E09ED36713E62AACE1664CC3D99A44E40404A5523EBCE2358D087256C3F6E06E5A74B138CA6C94421E96F35806C160FA0C05C3F3A66BBDE71E28C5E4000F12A641683DA590F8AB914963EAA2FCB3AE6C0D787FADF448C06FE41DEEEFC3D207084AAE2E4D39E110F8294A9AA3C537482265168B968EAF40AAAD979657153C2020B3E37859E2F7B9ACCC2BB623286F74631ECED132DD6540C364B84572355B32AB596B38F6620EA2365348607BB0D3F76D5DCE048AD28434A79F8A4DD2FFD5FB23BCE4FBBF19DF8417B9F339EED060048413D21184BC00C2AC9DB38E7F9DE110A505C368243FBF6802932D463DBDDDF43F359CF4408BAF8C72FB549BD43FCEF0B4D83C0C18BBEA91835A2735333F4CB18E242D0848A098D125DD8EF095472D0254C7448423A2EC7CC95DB31DD05EE152DA321362ECDD1A15EEFB8DB0712E4F616C38105601185EA2471E379048473FB3C0EEA601EE2B7854C27FF2F6641ECEA55F86A2530564DE456A67163239B9887EEBD7C4E5E8D77666B6DF757D0DE1AC594B38C793DB57A79F172A02F456D184AAADD14FF4112331F975AF94490783AF38B63BF3B77D21014D8706B0B3FDB1112503BF2EE61EFF6BB38EF0676B93D2CC22D4DC5FF10BDA94EC00F64EE473EBF2BF1D58CD2AE9399B0F40A2128A9AE3C984621919D5CC6A3A0CBE615DA8D6485CD91D943B610425B3D01CC1705DACA66A6678AEE6E4274ED27773C2251B85ED44611C332CBFFAE6F50F530A81112BB2CAE2524187B1B27930629A979695C6497FE68C8F33A88F420DD6170F526FA6168C2BF777E06B9CBBDA2871070EB196C31AC6A6EDE4C23E85C40221BA64C49AD80C35E71E8697A2AF201C88316E0B38AD1FA7E432C358C7C49A79D7EC725E00FD73C3E8DDFD83BECBD838F74055A6088ED9E4E4BDD5DC54CEBFA425A5AEC62FE0221F36DE9CB188BE2DA01D99C908C0AB37B186A9D71964E578EA4A40DFA3650F83CBAE198CA601C0ED8C1F00A59E419196D6E76FC2C88C0B037C1B88A8624610E167FD9551A1AB0DD15EB51B67BF3259AF9043409903EAE5EF4AA9F43126CCEC884463BC92D25D6BB89F62D0ED28C73C41C9AC0B9D0812B369876F2024B60A56FEA2C9FD6D172359247FC0E3CC33E3FDC0A58FF9DCADBA4929AAA5344363FE60262C292D3CD55FF8CF4B713038D77A4785C25B24879A798BE5BDBE4EAE96BD184396C0D3CDD5F49F90CA6FA79BF02F589E68D2DA09EA6DE612DEC4CB1DFD25E3FC12B4C7D2A31D18DA04DF7E31189C526A063AAB479385BDE172CBCD1C8740670B1C2039809B44F601846B7331A158CD1B7FE7783CCE1ADA31D50AC296A3BAF44F2E53A19858B1F4D55A9BD96D5C9B62CDA1432BC06A50E44FE76C84FED8CBD8388AD3648A17D1A5848E49237A79F30A4B585433F0F41904361AFA046AB55624AE34A03D89DA786BF7BAD5548C402A9C0CFD90E2B0DFF8C3224BF564E58B6D20CC2B6B1C98649C919E96F72BC2A8AB0810F27FB25F673B1EAD0CF69AA47021743FC06179E0AEEF925279BD0784941E2E8B52B35C50621AD307E16B416457769B49DEB15226F81C2D2BBD48151CDC46BD234B3A883C501D3ED69D344FBB202237A6CF194BC13F6384D0BCA9B75BFA7C392FE755AC7581263DA8B147431E5391084BD48533ED696EE35D1B834DE02DEC88711B87AF1C5AF621578CD417964AE97CBECCCC7478E851945E9C9494877A08CB0E39655EB17B400F347FE21E107F30B3BEDAF542249E0B11C96EF7E571CC62C4DABB1C754E6A327C628634F697049EAAC4027EC6095789E608D2EA41020522F09327338DDFB1B6C4989EBAF15E390C62E8A7DCF20A9DAF8B010C9C8C3FA48CBDA9B04D264EF7301BD66ABBB44353EFA90153853626D66A52C69659F38C984B8A7176087085F2C9F2A369E84EDF4B587F45B371B35EADF944CBD4BDA42486720E94C7520564AFCCA9A4D621D2EE9447CBBE5FB0AD4B0734682ABC642679D21541E1F127B74FAA9910531E0205D7935A8F992C732DB096D097E7B74B2B7D6CB6E856E9B849B6B1DABB81B86EC25F8448F7198A87B371A00AA8F39A24A2DC8E4C4CDA086797DB9C1AEEB93193AA3608B773C9F828252AEF5A21E741CBE9BA9DAFBEB08EA70E4026EB2294E3FEA573A622C8E9181BF21AAA816D701F79A729D5C6187C3FBD68E4A3D3EDC234A3F4EDC7444FC164596C99FA2F6DBA47AB78A7C0CAB00AC41C5312EAC472D8C12A3013FF2F22BDB982896AC042A460A11ECEC68794D9921305BE1D558DCD2DAA85326F986B1623A1BC527BAE3C2F75DF0B3B01BE1DEFD3B4B403B8E738ABAC28429B5B4B056BBA39C052B799147DFD972E5308A14100DAD9EF3BD59D9420CA78F164BEBA4E4936AD70D05E6389A5210C7793160FB98CC74459450E8FDFA73DF636933FB3CD2FAEE282379ECEFBE217BD9FFF0EA9542C0A82D8A1B18DAE6EF65CA3D64A3C22B014434C569D6078DEAAC9760526BD9CC581304C9B6EE36AB0D268DE61E4742539EDCBC0BF6949A4D6280867D3273DBD6C2ED687A3BA126799E42A4E09A943713AF258B3DBB0260594FFA00CC6B91ED60F6DB0572FC8FC49EE3F536728324540DA237CB1C605B47CB4AD1F3FF3769851DBD19F3D2BB19E4CCA90093805D38B69E487DE2065CFE7D8F7DD47354D45E3C24D124532B040A6C9DE9E97341BCA68F37008A2899D157AB935039E73C90B696ABB0A1141B539BF1B1EE6231B04DC868D905B3B127B79740A03B5626EDDD5E23881EB51B93E6A8B3405700327B1A2A43EE5C06D44314E9185A47F88CCF7049B429A1C080A33C587CFC7475A221B69D7CFCDCC01BEF4C2D06F2FB62C754A6D7E6335DA5728C3FBA9E5BA1A2C6A03CED031EEA549CBF9E6D1BF89815C3F1C6FA1A7B2CB79396F41B1F3C95E1F6BA9051D8864238DDF8106C40161EE9E3EF02A6F709996D27E6289C7654F18AFC44E29D393C72C77F1CA54A9EB6C819148845F2D9FF53B2432A49F23B4B787527C8BD06E98EE5CC1E497CE864865B3B778ECE97E1E7BB61F4F226AB124E7FC3614F8983768257120338DAADD65E1E883B33AF9354753BD3C8092ECC827EBE48DF0E881ECDFB3CF672C61FAD79C237EF9D951D24CA9A1536E9149E38377A077D7C8EEDB7066D3318EB9873B5227E5CEF60B363F1B0990337138C44697A3AF9A820E7E61F1B5B70DD6636DB7CE969253681E97403CF3FA4458D050EADBF53CD4AFA340F951BF0F427033ED32FC972D79EAA9CB2E70E3B301D1B02D9BB62FCE77045956B1EA78EA9AD337CCC738F55BA528C15F52CCC396BA7283640CCF3DDC7B6EE0E7AE92EF7863DDC68F9A53E53737C478015949B7F4309321E8A611F43938B8A003EE34487CF3FE4B18929444E51EF0535E75B8FE0A3ECCF51753452FD50BEAAF04B573686258AC13B5592560E4C8719A7D728AB2164F9C05A3FE98C2CAE61D28124EC8BFD77696742F2E206AF00FC73C362E5832B994C4892BBD66E4D7D821B6056406F2703E6BA304658476BEC26DE30E5C7290E68A6CC1FFD72DE8F70D478A475E2F2561492BF1DAE9B936B1FD2887CD305B9DEC5DE0B0CE1DD8AB237D0A43E49E20719967E985A6498481EDB615C536E842B27238704BDF5146692B85C05813A960074D73C23FA118C00D7C4F322CFDCD6E87B42CC1FBEA04454748DF25F621206BA7717932701CE3AF61E1F8F899B89CB2DB63C76FCC8757AB71CEC6430F8598DD612ED24BCBECD337CB815C1B60E95478754224E45DE66CB09F073375F95025EFDBC1521BC229ED214C311460B801DF09356CDC3B4ECF70B9A9BE4D4E177D294AA11DC18A6EC10BED7DE96B20CC4296F74B28C6D79750CF439DD24C0965E557A2DCD447A4BC39AEC13CE4824E7023551C80755BDD9CB95459280497F7D36AD9E64ADDE98617107E1800D01A6DA9D3004CD4C0A6472D9F4DC9EB59B324525EE27FC8AB92732C65FC425812874A9EDE27781958B18CCDA9A9631531EB603E43FFF6CCBE442661901614658FAB1A32A0A4B6FB6FAE927A2DBC187741589E339EB259324BAF8EB23F5D8F57385D0E76FF1AB882C9C444A8B19FB5614A0AC2E7238B70FC6A01C7FDEEB1178FBC4B91803C644E0C732B83F0E2C8A68441AD0E6431FA38F09397E7C0E4C88041DE808B588FC2DC46384F720FAE1413DF6FD8387EECE2D19BDD816713D93FB37F0C17B1BB4DF99FF9193BEAAA6A64D59A156375DE808D0E571B312129AF96D4772F66356019AFCE14BE3ACB6F8057740781AEC92DDFACF1978C3D97DC2D3C61F8CE5B1F8DC283990A2887807C6B667C45C3D41161CF392AE58D6BC555E1CF714C5E010FEED160E52AE3E36D67CDCFEED00BE1D01D4DC7A87C8E725250AF38A5BD29B2DF62FF46B582C1A21EC08056526AA08555387E2DE9F599FDA07F34ACB437ADADC2C3DBC1054AA7FD6C24818C88C1E154C3F74315C7D58374199C7CB7FA945A8C6A4D499A91F5C78DA349325DD65C5162CE092ABCF4072BB48197AC1FCB5386CC74CE394DCCA72912FDDC66B5C3359D898A86C338E6590A53353B6AC7D136AD8C8AD5ABEA78DAAA702CC8666CAB857D0495A2CB86DE777F92E944C3670CB265DA429F3C256447F75C45728E34392E9F767A2593000FCE63DE65E9F457DFDDB37EA3852E790AAA01CE7D1A3330C7B4AAC9111AD9CA8F60C43468DBBD7BD697694C074A11B5D855210AF868D1F546DA03342F8B7215EFDCDB1209EF3A2877AF85BBC59AACB4ED0943DC3F65379EB573B5FEA9295DEBB9B4C80C10BD1E0E8033E9327F22C7363F48EF59AA7BEB6E4DAEC0C4131D7B3AA5068E5C513A5FBC8BECD96C4A9595EE4CBD6FE5BF8A35CD37782888F34C128940C1BC058374493575A8323EEA9E8D94BD9C39AFA20AA43D1064270CB88C3F4657D2D4A5342C97FBD53EDDB67AE45C429BBEDE713DCE11D05849233CEB3893DA21C26706C636F5D79FA124B10C8F1BAFC87C10AD2CEC4FED3CD3060C3E64FA6AC1AE19A9A1F6B932011A72D54B2E5FDA46866A35FCC887A72B8BFA60029B79FC5CE497596E7667E9A50B13968B1378DA60C40020D2EB3550DF1A31DE6F2F6DF7EAD769EAEF838371EC4FE3D4E011F3AC68DC09FD951FB458E6D3624AB4F61FA17E3CC62642690CF9A3481A495F32CD8DBA3CC07A93983801B2157306A247A6B274214506A9D5CAE0682DC5B4B41912C36D2840C92BE6B0B45E2A30C7967291E939C61374E0FBA8D2D3C80A1746D758D609D88EC42037E01F95A74708A2CE74C260A1DDD632FD1EB28FE4AA9B97CA30AA9DA645AAB330D38D25BCD6EE669D435206603EE70CB9C9A1668A81C486511F273B2430C335CB5D8B2735F6F57B7B14A6422A819F5BF7FAA4E7EF8119AA4C40F6349899B86CAA55CB7AFE3CE07BA4D766A8BE0DE7A17809DF133C1B7B4A5C08AACC329DE1C58DF162827712CD4FF5B6CCF2EFE81A8E9C741949BED62F26C433382FEAC9FCB999C6A816DDC6858B3F97CBD78F61BDB4CD68097CBBD52BD8FF01D02753044F7FCEE91268C161C8B75203AEA18AA288733458FAF03799800977007260F59DEC3B33D0DB439D5E3EE26D466FB526CD9C445E9CD15386E5F0C290F094902F7E5632B2491584B4C7992304E6626EE0A13EE1DE47AC39C4D87C0C1AF327FFFBDC0D2C7013D6551E0B6DC8B2E7BD71377E9B9F989A45E446B50B3E9E7712434AF8A717E9314C15BC08E4BE9DFA09E2580AE225BEFA4FEB4B3298D0BB34EBE72D7BA20187F438180A152A5E762BC59B78CF84C56E2798CDA1FF2DFC4B9F3838FFFD517F186A7E82DA7D39664CD92095FF3283D0D878E869E57CB7EE8729541F32ED4D420DAB8FE17A605D419FF85AF9A447ACB15F4146412CB60E851793912BF4E791CB3A854EF9DEF896F74790157742FABD93413358A79EA573CE293544ECFA2F96A0213B361B60450A385415995A329ABE0D67A9DF49D53678BA449E9646B1C2118EC84609D427BB8C849B3E4CD8FF0E66476B34CE34C9F28ED13D166ADA3A21F03E27499C48F856D50E98E4AEBCE5C2FC311873FA111791D36E5014E6D65726B5A345F5122374F6892650AD2A16D080D76FFACAF91F534E71FB2378835935FBF19BB68C9617A3CB9D3053B3796CD247A8DF7CD9CE38644B71BA246A20006C13632BF1D17FC82FFF64E9C52BB71DC8ACFC4065FF4B6822B13BA324C28D2B036C2410FEA254D8B29DE05DAF8F059A1856470A0567A16052AA4FDF8BB89364874707604237D1F305F5215E9C338D9812819D4D227579821ACE8E41020BCDD371ABAD3E694BD0B7EDEA22B763D69A1665EBED0A79213FE462BF15001F75D1D6E2D9EA2FF1E39F8EED634C30D881762F5450C2A5DCA4937D19290E76AD9949448729E495CD874D3516EBAC782E16BA180D7E222F65CB9F33F2E5248FD7D6613C7BF2ACA22EA01C7275C52BF00F07D520E06B8D4DAF072FC6AF22D62DCB9DE955CAA48A46AACBEC315B9AE66E016C284799B5E242ADE11C82F321CBD91B6B938D277F334500F82B3A0A17A0E441425C2F3E85EBE9F4F30A71833B0EA42DDED0AABA73208882F36B009B8B37F23FAF52DB3DEDAA9011B52786E56B5D8EEE8D2092E1086EE3CF2FADE2493A913C6EF41C65A40D277AAB61A1DA7E63FFD704238F2E81A24C9FAE0B5841B21EFDFB3544F40AF683DBD40BC12942D4064303D16F6E5E5D4323371D6E52A30BA043005022FDDF2CBC6A6147FDCC3416004FF247FCD273E65582ADB8ECB8C8B85B28BCDA13798993C7917E201275D0ABC3FF382948606BA79DDEBE42FC76730A1D0915D18BC7A4DCD5352C390A76AF260E6F2857E5880E0C996F0379F584FC147F495E576E60CF75D818D1C174C6CF38DE21EAE0C155938473CE4E811C5BD3F7ED8ACECE43EF303266044DFB409E33D3A343CFE16B97F9788C6FBFADB6921D583A977BF6F08CED993C506B62B0C2880B13ABB79D557E78842E7834AC67D38F761E3FB5D7E18845A7522FA0123C5BD5CC81D31525E099050181BF7D8C7672E5823A02E948EE6F7427309570B944C717F1CCC214AF63CDB0D827D58423AEBF63B847DBE51CE4E7C97D1FAEE901F73768F2AB7097911C1B8DE862E5D4F39F7E86051C9736920EE03152C4EA1AB4C7B90D9DAD5B1F313BFC5EAFDA4FCEEA7CF0E5DD68551EA75655CF8C89EB11C5285C7CE3B7E612A44CE273FD1F7538AD9AF541D3F859EF19F51159216F110075D03443DE957B622502AAD0C7678C41CB70D5686DF1338CA98F69B95C61C91F7CCCB4136F0A6E47CB799116C92600F4F1F3243DA8BF83DD432EC84A31D8F7A9C590A11985A329B17D0A221C4D4A72E6C3E2EA6CA28414717CD10A7E97F98F525D427E68A6B2AF96A93B995DB64CCA7A96CBD8E64F7002026B4C6D9C256F6214565EE8EADA590EA7733558DA1403F35424D6E76EC4E6FACC110FD53267E939849C6A42DD904E4F7FA2894FA23CF833B244B46BD9CC0F635D9A0A11F76669E9EF75F8FA9B925930C11E1E55AFD36B3546D13D225259F49E18B632925591EEEF0DEAE475888C59DF76EAC3DE040762D300EFAEE846F9BE5754268C766BB1FA1A2F064D8F353E9E31BADAFA391038FF1D9EAD1A46E6ED7CE6D26E375E9C9E3783085857B2EF1E7D4A3453EEE66E721DA569C0336CEA8389FE0C72FCB2A84698A935F9BDD8663C9E2453508FAD70E953ACC58A525255B6B0D6215771FF5C6288E3182CF4E69AF9D930EFF91517781AE31E9CF0E69CE81C7FD388A12EC5E46DB71734AC1AF5B6DEAAD47588786F5506D5A600E3FBBFA58924EF3172E8CDE63A12C3FF2DFA2AC6F6E5A4BC9799BE88CA1D26B1B775C3D36055FEA4F24D8A977098C33C582E782E4107AA8BC6F3C0BCD218353A9D9CA6489CBCDF2EF6DFAE91ECB81B6F642ED6B60DE9B29E8AEB22944C039F3ACE48F92C40EB049629744709EA63D246017860D52A69D7D7AD2563DD0CE94DB3529D51C1ED7DDB3DE7643B7CE20A5912BCB48DA36895B6DDABB7B28D7E4AF1819236F3C3DE772FB49C5CEBC211442B3ACCBFB9B0B4D2BD499DC4F7E9137409D3B012444D774F952A7F2D9EF9A4198D04005E6B16B3D546948B28524677D58CD1032E8429146C848EA47CC4F91AFBA53389FA2BA6A357424895CF618515E4056570BDD4D23E12C26B20570DAD598D318E43C2D26AB4D4B1E3461C6B4E1AADD1D71C52DB1F24464C97828BFE7A290DA6A7ED8AB88055FD8ADD23ABF99ED142D2659F2180D1545AB8D4B49E1E189B4CAC1DC635F82F32B332E71E865159769CD9341A1FCF732D5614B1ACA53DE3CD6FE5C5E3A82E0149950F97D651C15FF17622E90DDAF998E17FBBD796E81C2835C8A65EAFBFD27CCF36E0B6DF32234FBD84846E71705CB2C72634BD4BA5E1F034ED6E8A316194DBE85C437D9938A47E73822B2C21E8C30DDFAAE6967DF0724E320A8FB09109402826CE9880004ECD1BBC767A23C4E129AB61CA241993C4167C53AD9F5BCED6827E8FBE38D59A3AEA0CD135295DB8D4996F0C7740D64D8BC615FD9B3A6368AB137C4C36B30AF65EBC1210D977EB83B570D913D1C56935116E7816E8C50C28CB873CFC5E8C2894174E5266166CA6C3D5D894A8296D2C842CC83A8AE620046EFD421B3EB2635C1DE4E05BE6734E41BF5D1FF5A4F76F287799A70F99E2F4818F3C32BA619C49B477571D7A62E76F44B01EDBDC8F488C6FBAA08162C9C5C420EAAC34701FB21FD7AC1AD6EEB2BDF368364B5C74DEA4133463A2BF45ECA26F2F6EDC6E2DF0F6A6BF06D8140D35E580BEE569BAEEE972C8B9A1CC7EE65A36C93FC77D15D5C22C697DB3AFDAD7E73FA59D25F151F6BE68AAD520E22CB385A5C25EECB40F34B793B46AFE94B69E0588D691547545E7BBFE9A8CBD8F685D488A53274904A54514FF3715C611E0805CF157D1C22D2830EDCAE7BEE4F0A95E833CF07E36CD2897CBC0EC6ADEACA13291E484583D7082D3AB3C348624ACCDAC09DC05781C36A66D4C3727B787CA04E13E8FD51178E15C9CC0189D174141AF27DC80BB372A83AF1C5ADCFE9AA10410F29EE3C9D8F35E98019B6ECE3D756337A6DFEF5F26E0981680C0F5DCF45B19C355207BE2777C2085B9678CDE2F721A7368E96E04BCEC0E79F977F818A2DCCA1F1F0D8C2899669170074C5AD35F7661757DF0F9F1A545A14ACF6560939EC1698ECF26C8D9DB7ECA2B74250847EFDC54E15C99D9F8877F6A79E6C0DA28397C9CD7AF65307A03387730B84C16CC2AC0829867E89BFAE1F747E549563D99296846C8CAC7C45DCB092A2E53172E32C13D2216133E439B285299610863BAB12D135B46E95C9A1B2F88943C1EF5345943874A19EA6B8007C895A9A6DBD7E72E8604BACC067460CD621A5A25DACBE049172B9CFDC4227C0B79A7012D4E817267ECB62B3DB2D4A9DDC7B55E88DB422172F7728F201706C543FAD35C4FD788A3CD18077E7B8694D443D50BADE1FB93DC354E509BFC3656EB78890966543D8CE718F06CA2FDB36200EBA839086605CF58896B6271F9CFA405D8C9295286FB8EE744A7CD4B73278E40A51EC3D4629D8FBB8BF8678170D02468DE4B3A3F3EFB7275112E157580ADE3FDF3F0385F943BED35E29B1D902D9A553A8C950A40F8818CBA17D7B031AFEBE49BC9A72F3D03B292C769A851B27D7477D3384C748788E980E2CAA62A026E5C7B9240CBC45392DC60D562FFD2173660199B88898DB1E181CAFF9C396D630485FC1E107123FF6DBD7CD66064846144F02BA5941FF587E0B7594D83FEC866C92DF232533FFC430B6E7780E413F37E3FEFBF28793323E2A690FEDFEE39DFE827C0767E9918F0D06D1620F9EBFADDD7655DAB8EB4C305E34F31890CF8392A0B09D46329F9F1E33D3F8F8C3BA8CE73A8C5975226ECEA50842EF603DFA21D3608315861059514891ECE26A3133CD6070BA67ECAC437617AEADF751FBCE5869AD63D051563567D62065F547081DF64D3535A9C08AEB3BA2B0A8C23343DA0EABF1AAFF7513C36E14246081F938B131FDCEB19D39121906E651B9BCB29976C1D5C35444ACEBFAEAA698CB74575E4D75F350EC7553EE515F817080A1139137A8037BCE378C76744B1E8069147D964EE3ED8042ED240980B609D1432129AAB1C982CF028B6C86515F3371A8B0460E8E2FCAED90EDEC9BBB43B098E99696368DC185B757ABCA6C2F5C845938499666372893A9E00A4EDBC90224CE56866C06A5B7F283C2269D1479210F000BAEA547FB9BE79ED121715D671B8C20405AA40E0C084A50814AC8576103B8FE95C99C4CE2B20ED5D728AF7028762FDF8C5DA5ECD6B850797A4B77C30FE2BE27A6BAE2AA3AD133834DABC72B7C71528F1118DD4431D7E64CCB5BAF7CFBCC2885E55AF6879EED80C107605D413A66CD155FB0B3B27DD0D30222F2505251F28F379F9AA8AAE02C4C82481BEC59531A845661507EA0B081E571BC479EC9D87AFD8E27EAA8C1656F5DBE626F23271CA9BFE4BB2DE5D2398D187E08E2E3C537B1FD511CBF615B47CD4035BEA9E0EB1185F2ADBC23F1A834E7C282201144068E691B5B087ADC75BB8B92913653A362B339B8B13F3C9B7FE383C5B93B11D27DC50197C74A39086C5E2CBE83DC2B0E6D07AAE8D52DEA43BE3803A1F5C856DF1A0711240C746FA270295B9F09AC632D5D79CA410780D4E909DF079D31D237394E0A88756506D696574DF169275A37976E371F1A3F132667C4A9492E11C94EA00191BCC9A12258E238C7760C33F9B4146D5099D704D5E0209732E7E625379F2073698C932166F4B3B3FDF1AF4F84C787DF54A4C998B90E05F82B14A46C2C036CC38FE07E68F117BFC93E84F67ED2C7AE1D3486293E723B8635913E1D033A5E0D30ED3DD9C9316A1EBD684B17B99C26270510B9F74ECE66163F009C5E9914DEE7035527CA7AEE3A0EE286A6C631AAA37CEA787C71B38A925F47DCECA1E40AB64E3FC06F7AE0897093E26A03FC0936A1455B6D1DAF6A40A75387D3DE62BDDB071955F889AD177D7BB19BFB025C6455B110025AC53CC5174C2B7EC5B06A010C2974879C1BCA72342A1FB027BD5D2FBDF4A7D0959F76008A492DB9DFFDDFEBEBC189B3BD9B3D7F413B2335500363193C6B9139C4596EBAE3B3D868E7BF02F5E704765556B7372856CAD265D8F76159820AAF7025E6170F3725100EE5329BD458D50B692F192B36FE8F13D66C4B08F5386B719A4676FBABC7F2A2EDC116976449C1C68CC7DB592C9AE86B6DEDB589CE4512734710853DFE14501426C06F0764C3EA9C77B9269413A6E9D5261D3402E30D8FE7C86187A094BECF024290EEF98D880B85DE011F29AC8A89C77252D108C15B19FC6B4D5FFF87BA18DFFBE33CEC72F3B0A6370B45EDEF38E4DC4193F31F523CAAC381BAE0DCAA7D733B792687FD767C3E2DC52E18414E2FFDBDDE32949FC1C0968FF7C981F4CA57D382B61F5B16ABF3D568BBF1F12BC03B5DD012755A845F6508DC93AAD7AFC14E03DC5B7C78D3E62603E824AE57CBFC11E5DF3CF1D25AF682075FF1897BD37643379A79D2F727AEE56BD3E004F25A5333FF4707D0469DB290B57F16AA2D419EBCD94ED953ABB22B42D5DA901E42B41B787C365B475E6CA3E278C62D53B3A3CAEBDFCAC9AF9C84A39768FA9FFB1C0688670244314C67432134CC2FF023464411D6DEE2E344A9B0CFFEEF18AA46057FD017EC4EC23477FA2F7BB64C788BB0FDC9F79D67D636AFA135399F652B12EDA20E61D1EE5DCA82A29993E183A6DEF314001B19088B5A7A857465E68AD569C8DDF21789F4A972353214A44AEBC84769FEA20689A87F1CDBA25E380E54E2D177D077970BBFDD7EEC68C6D716A4E1D62983334A53969C8F189EB6D00E5202CD6EA0511B9076829632A88B328D7B90089680001D71329590938174E3E648A16896D5D2B3B74C3C99066AFE38DE764A08CE3D24D1E2D6A2BB407F6F0BBC59ECB5B745E6BA1C09084741A1FEFA7ED59F719EE95863BF5431463463DA5D554BA96D9DEADD93C142F95D9F5632AC5B6875C4E2462FAB652B75A6AEC7B2CFDE1BB6D59F667BD8481CACD4710D07BFBB4D4B0178F256F2A9220A0445D09D5F39BA83ADD7B1DE1652A6A7F2654ABB704C0FA8DDD268F83F475D6ECBA2825BE191610E7C75C9D4E2CC354988343D1B44661F8A3A90EE38FD9FC2ED6F7B9217584AD74D85EC2837AA8B7863F03EE452EB0D586CDF70B21525D13C41FCCC281340442D12E9D593D64CCB3FA920D158E94CABD9E72C047DB35BC3848F8553C41113032B60F2A2DA2A9C1476A9E141E29689B2371D815B43048AC0BE2D09B20A7D4B9C413BE135541D88DA756ACBDC1F44C6571F5B5182AD00E26593997F35B9583B67AC562467C59319CCC37F58E8A9EBA28678A728664D755E9B667AB8EDD4218EB5A79C4F81F8A64B96282753C62D203D9865FA83763F4C636D30F97E36DA28FEFBA6A257D99B54E7BD61E4B4321E5B963EFB9BE28B76A09BC2DA9C4433E1415BAD7BFC1E9DC099514AA34D743FA6D688DCD9A22D7C92E198EA5D5F1412B9AD42325D9973751D7AD6054E13DB2E088147A050226A5914D0EAFF9FA3E354535DC7B74EA8CD2D5F2D021A7B65BF7C401D197D5EB8A4D62B5E350FDEC5BF355F52ED6A5A56E9393DFF345B4AFB22A9949F9D60A36B45EF066613ABAC517A20CFFD434CCEAC764AE745871C2665E912AE996FF18DD697312B3EC2990A6288A41BF50377695118AECC5AD35537F58A354A74838B53D765B13F7F0F9DC24AB6B31AE0C9BCD11A9662D635BB3C923D83EE04727D95CD4916C9F0C50781455C148BD8988306319B45DD747FF73851BF423792E6C8984F455C4D88B851BE801B0F1E942ACC4793371B125CB15D230B018AC939118262BA9836DC3E7A50E207EEA85DE379201C24A034217B1FC23EA213430AF8DE721BCD929DB9F1BB1A2D2DC26E1747EC54C070AA85590B85EAD977EDC8E3A2C5E93FF717B5931746D173BAE2EF3D3191352A9EC2EF6A2261894B09A1CAEA45182B900111EB1DBE6C50F3A9ECB185394D29E760203C1435961B5242DCE1CFA5189F60810740A235B840292179C9C7210DD4A99FD637942F294435F15D5F3DDA5DF5B680E69D6BD7FFD10137EC125DA63D137B312974800642FE1DDEF0FB7E46C80E8894F2C216C40C353804BEBFA96D49E1FF9C106D424F4842A967DEBB2C77D4351509CE662C8EDCC307E95B94FE67975BA12547CA00634F5266CA4A7929C08D7A1F9C70346D642784390C9439597DCF251893D4F6C726A7B8BCE1FAA4AEB7003160423293953B1FC9F8C0C872AD1FD4CEDDD6F2F6EB0733ED51A3F7D04950E4BA7D6E90F9DA63EE7620AA449D22F17F5B4797A1B31EF6A459EEB30613237D80D267044AC9B859512719E4D6A1C00C9A4318880F794D2DFA9C6986B720886526A55992A546B775A08B8FC6F03A6371D91CDF440AFA391D1FC3A4F38747DF67A9366DAD15EFA678E61F800D136EB0B3B5939E76E90051E2E97EE1A0F4C40BF0BA87DE520AF251867893AE54574DA44A82D2F52AAB35E9969265CE1EDB00BC55CA42F3A01CFD113902C19EB107BB3FFB8BA8FEC4C1D01B334A7C759A82859E5846788DBAC6C134E505BA0D423A7C4AF695EA069ABC2C4B59954C07396B62B8C5CAC540B093728A0E1F42612D781D21C140BC3B9B2BCBAD0CF7DB12A270949A675EE85D6D4F2E741A9437F86A6A12A9324EA5AE84F1562B1750BFE51003C6B9FB2C611F2B247B6D8CBCBF658113584141639EBD53D3876C6B190BC6AD3E35412F60FB121D591F7A415B1CA064D1B394E9FB4D5A1CF747D698228E3F6590380A7DB88A7F66DB8C0417F6DB2C7F17C902258D4B747BF4E7274887B7575D6BC5EB71D570825A8283E879F6CEDE9F9C10D1C0D65580ADBA627706942E4F1F33591E49454BBC699FF393403B666E9FC51A4BE1236F25D71012B19D3B97D6BACB780800CD42072B934408A2F6621E84CC5BBD1E5EE26FE6C26519246C3576DB12B19CD55983E354FAE632D1F3F709D71A61E41AF206B3E0768A75F651B5BC478EDD0796AAEB9CB2EC945230FCECC6C28F410E8B926125CFD499C2093043FA0A3CE3BD7EC53D7786F1EE23830D113609CC3557A78A820551D7F8638025BB4BB0EBAF5EF9D03552C22F71567FFC430F8E2312782E83D6EC243A65133826719FAE961A861199BDEF57F2145EDA46AC4A7CCB458CDB73C871CEF7CF40ADE9C71A88892B73EF0E7EF6C53A4A41B763871B49070AE9B6249E9E8297C3899A06117DC42521EC905D7259C4F58CC111C98D891A74947D509D61C48E84C7750E72AB129010C4B16F5E80244E85FF1CD09F3E6F0F768D2CB6682901B7626601B2397D05FDB5F35FC2C6227D82AF29EEC4D9338006024F919DAA869270F7AD4C79BBD4B3BA2C64D2F53B002421FC5210463D1C9F8C0124EF803F6B8E3C343D8D7247FC4AF9BFFFEABF711549CC204C93D4BDC48DB7D79BD680BA0FCA53666EF5EEC72391411E47D7750934AB2CE67FD4745DABDB5A421FC5B5340BC1C97511CF0A7CD08B19CC73523A87B899C7D55D15C503335F4CB1F5DF92D4A42373B385A5709990F5B91CDF5D4068E17EA62650786A78020BF8E6EBA3DD6EE030FEB3CA221B4EFE1FE937FBD1C23297274130AE6EF0A8C10318CAC796395A93B3F04523ABF2873CFD837ADC68C17B8DD96ED9018ED05409CBC33C740051DF8E2C22557EFC3AF5B38558F11150A81DF5D9ACA9DFC1ABF72C047C735448D68D899828AA29A13714E55D4EE6B62906F9C25D15319789D0882E5C0172A6C7B35761D197C21AB6B65D5BDDEAEB6BFF30943E6E04CC40CD0BE76BAE8EE1C3CCD868DEEC10133B9284D72A60BEDA88E4C76F72D4E53D8621CF63B48C4E0DD7C6D3D705CE38BD6016AF2399601727A538243985D2E7817A07E26EEB5794DC6760214FAF23A5B09A1131FCFE0DA12568F950FD3858B3AE46D5F323E0B62E6F87C17A0FC51DC914D08CC699EF162AF976484418769E0BCA6BC4040FE877EAB24274FB265E4CD6589AE0A3263C11136C74E89A5491798A57AF7B7FC33F3C73795F8C63FEAF0BC51CE83083423642A4D2A549C5C135DDD32A19ABC13FE3EC11127D61740D7AB89002847CD54D8C82ADA3A89EE3062A498BC7D6ABD6B9761904A912A4A4D1B1A8EFF108F8F40D9D917D59E95DB71C543180903E91B204A41F1AA0CCF42AE6D6D99B39DA974F707B738195D0FDC5CF270F4685CD50713679CC78E53B56098A90EE803507317104828D192F2076A2CB794393E05110E63068BFC2DC42B6A3402D51964C459BAE76A7497A08029D7225A47193E64316DE0B56055001C36DE8CBCCD7C79D58AE762DF431A8C4F41C0C743DB8E01C2656268BE0B4F20AB1935210B0DAC31A8C5206FD9740BA72766784E8A15CF38CAEC70739832F5F25A72C8F36375B649A6C01FC3D01065ED855A0D404EF881DC4AB1AE5836E69D4CD4359EAE48D975EAFEBB3065AF382A59EF0DBD002D14E87452B6633688173A7D6FAED64CCAA3341E67FB06594306AE9CCF822C8843B24EDE78145F55C3A954C630EC03B0FD04229FD461E865241AA3CFC598A6DC94FBD83D5C3B7905E4095EA9B40BBFB3C64478F404961C314A5C0164FB2D9EF5B58E7BF613D8A6E559EEE62057FC246A0175D7818A9AAC929FF1A0D14942F4517A83DB9C4EE9DC8A2054F1E9807B8869D1E7AFC516987F3114E3DABED71BA3DFD3924FA1CF4726A8BB5DE628F1E6323BC2749CA18D3820A1ABA5238096FC6881AA52F8AD3CD023097FE5C7C18861B1DDC5DCBE5421EA2700CDFE1FC77D4C0640C69F71FAA49F4579BA3F64D4BDDB91E2C385002A85527748E998495A52A8024A4807D9AD0234F3DA52EE90B783578BFAAA1FD174F0F55951A093124CA3751EC29BD28A6E7A7D51826F984F9F581D844854DEBFBEDC74C791BEBEDDF99CCD60EC66A12FF9D0BB80A635043D649127C04C6F94BA0DB09185EA7B2C6800E6E689968E757797CABCE450EAF1D57420A49998AB00D2CC970E88D9181C4CCC5C88F813E9C8654D19D4DDA4BC8E5A4D11F78E54A3D9265CECDE4E0F243E6A689904D5BCA07052044D1A83428F8AF729061D2B7033AC4E4AA2E755FBE0529645477070A7A891AD9424BDBB72B40D376F781EE89738FA7B109B288D87D93FF6118127A9BDC6D35C229C144C68CB2E8F7399458D8794509A023ED80A3B2047A6BFCBE5B500C48CBB9EF806541417171BAA335247A95E224BD59F8599683D1EB56A26033C2E88F3A3BB58B054ADD4603D399BA046BC576625AFD59C2A239A5C80556848365B69CA308A3114040B7BF6A76475F401EF92E18E706FA25D2C92DE646A52A115ED1D2E87A4EABEB343C7688CC1AAEA36DAAEC46AB026576F25986A0E89D092557DE8B7AD8768054516553D035784E9EC04C8C79B9B5AB59A268DA72A8F4E28583B306E56AD1D86B09F7671FA1C97791A96F8D5A38D107E79B5549B4A31540B66504B035E65FB5D936A87AA78DB3A9C29531542EBF7884826ECA3DFC8D1AE03D97D2819A2ED3F08B7557FE92DC311B7C82BDAC55928D37213EBC65A901278F480790EB90677F434C89401701794B73751D37668AF3BCAED6AA04240C62F3BD9F5B73F28EBEDDD6A1DE2DDD59F2027A74254BCABEDCEBA438967714759D806641EF76E1919BEC0B9F6753BE966CDA80ED2B70A34CA676D37C1824E23719B86952C97CFEF4B6BE28776450AB006E2AE5CF1D1A2E0F3B28B8DC47C45AF94A70E6E01E2595B197EC5FD42C71EBBFD4A9954AEAF88527A49FA4D66C4079F7E72A07A7AAC40D550906B83F4451F11F57C21864664D6561A1179639157AAE8FD7D1FF288E86ABE05CA6BCA4A7014287649D330A9249637319249111A273BE568C77264C88240FB72C6AA2B9A8118FAD8EBE72F3A873B61F099BE8DEE16CB4F8F7D2F7877CEF538D8A6E06CDB254E81B853B62D93E2A7C81A244C6E7AED40DF47106A8EB3BA1302BA716BD41805C5B7813C0E8025CD7B7D6E8B819068177986967D47231CB119E40D706C55A6496218A43B1BC4F109D2B6F62DC90099D42A50C5E033449963A586C1847BB3822A3247C400607212E85E39C8A30B88372AFC7174B89DA15AF543C1C77159FA95D582659EA4723200C3EF8100A07FAA9EB95F5E8D3E51236BF0BBC41D2F3DD11B96B73F18C089ACE5FD01F79D60691E6179E46D9B5C2227126B892C36784E5F447E806DBE77796F02D4D180E53DFC34467E5245B11372EDFDB979FBA3415F4FC1C9F1ACCF40E27748E25C1F876401A30260533EE8BE06F9B19598E8AA849B7566B590911AF48C339A9F490FF7621FD2833F412A7CD2A36B8E632AB7B3C9E7C848A9651BD38B1A3AAB343913DBF4A8B090792A6612721655DC5145623D57F2C89EC0630D9CFECDFEFB3797DB16FD1D80948E0998F36533D14E07A910571D9E5B9377A211A057EC02D32AD4F3E371AB56A2F7C6747853345CA314CF5A5632D8C85E5503F918ADB72FE5871F584E64651415FAF07E814BC07A3C47C72BAB43773AE3E0E0EAA9023D6DCE539A5E0597F1243F4622E1DC559F7C453732E14992EA9D296CD7E597FA1C793A395FB5F6641DC7A258C00234D380F88CCE074198DACD319A5DD75C4474347396B6F8AC9E19D5074ACB3D921F11094C4B6C2332F07463C92032BEE6A053227B5243F313A662CDAC0D68BCB7593915349BEF0D9CAC21F37078846B8D4DB539707F3D733A88E777F811C9427696D5C229F6D19E46AA385D03DF0276BD39DCDFDAF6C674C296F88DBA559222E9D6EA5C29F3CD82D34BAFFA594F2C83831355F87ED32EF7FAB1B053FBD40F8412644D45C113FFCE6EDBC08869AFBB4AAB497B329B8B58B38F98C117F10EEC8C2E038C469DB8139DD917BE0A2B750CBC46AE808C4C0D9919D0CA56C967651145783EF4566E040430F8435A93C28AD37D506667930F78C8962CC3A92E012C8DA5D6B6D88692D3C4DC87B779B4BB654E043A11B853E758907A47B7415495B347EF85155F21F84B72BCDEEF56B27AB6FB6E0D025FFBAB1C5839D15E918F481BF4B843545D8719A723BFE52BC3DBE5EE1AEF0013CD2DD1AB9B31E0D981F0540ED84A6057D8AEC179DC81643913355F470F4982B77CD89FAF228C29FE1720F54144772F08797810D9503A3613FB6642B50F225FA0DBACB91BB501E42181046722A166D547594D2CD4CD3728320A1B85A88F0DB0A69BC9ECA65BEAFE17B783596E8FCC4B5E13D4309F135D011DA254DF9A64E35D4751D5EA77AD6195721878A6FDE8FD445368F2840E3CAD1DA921ECCCBEAF831DDCD859F146B1218756374037B15C22FED7AC3CD92EFD94AC7843868A8F47A0EFCD6E8DC270511330D9FF045717E862B4AABC93653F731C6D542C0BA930D69FC574076DD569DCE8EB8E75332FAA55CECE78C3C05ACBB5C5442C98BE1865B43A367DEB92DF8C5F8D623C2FAC5563AE4BDFB185E0B5E7EC75168ECC33E0D32B6DE1AD9CA6C8CBDEEDB72F90CE6514ACCEC7DD7DC32F73AD80A6704D119049F537F03D56AF42F6B9E5269DA20ABCF0B4747218D3BC5F5DC47339E78821921499A41CF31B08A73B194DA790899AB2A7183C63CE48B700A4A41D18052D640A1BCEDA72383B090D8D56385F3B9098BB6CBBDD62C96662CE69CE7CAA6094B71262D7665D049D7726016ABD28A7A4BDC9A92F9D1153EC629AC00D5AC2E174AE986E38C8634BBCBA111549AD16F8AFEDDCE1DC9C6B9AD85EBA52619D1AAF5B6DD4FB86DA5BFCDFC9392B3F929457031D41B84E2C81B068623E5D21A5734B196C199DAC3BF4DFEDC3AD0E9F95345E4B437C068F58A4C204D77638A1F59B48FF9174A1EEE74C94211C2450E2F90A348D6B26B163418C3898DEFE3EBC4EDB7B929A1F17058BAB722C8BCE577C6E41DC587A51858BEB3F3332A00943CAB2ABA8A66B45E8A33D743AF0173BF439C8B5D3B79E5C32323E35DDEF66F08B3CEF8FB4CD13BB14BFBE39C857F1B7D62217F33B4C5E0EB3134133FF516442DCB3EF89481D971E1904A9E0373E33EF317F3119CF08AEB4277F1EDB64536F62D05D9609B2AD0BA12D0FDB7D03238CA42AD4F094968E5F33A422E44824A0D4F68341EBD06B3211EFF561F4FB8C1E220B7BAA150EC4C714AC6647CCED0554C5E6252BDA66E45011979653B0506B59C30EC16450D673106ABFC33BDA58F5491D804164C818700E3E587CE0C7682C4B0B0A7BED90B7230557A23F31C890294981B41AF506BE03C74BA8CC8426782D3EFC6DA4BEE7877B4EDBC190FC23C56A849DC62307CF8CC5E4E05FA64BEB146A92416E1C4CD2FD269503411286706B671E6565E7A7B161FC3D429EFAD012EB0B7E6C6765C606E0115C5EF64C2092D7A35FB7C4C3B2F07ED8925449F7B517CB164AD208F2EDB390BA10D424E5FE90FA0BA08F5210394CC1AB861BF21291BEDC818201F50E9213E6BB48B18D7AFD92FF9F8F54988953841FAC0F55FDB68B495A327A8B8F8786239A4FE3426235451714DAB496A1825AD66D8FE9A7F831BFF4283C48F90A28571A4633C7F74D22A6446141B3684F9D92ABC03B1029A0A2428495B9F2774D5C169C3FD4E6886322FEBBEC383070AD08CF7571FAD9C9567A769BD43003F6704A6041F9C8C3AEAAEAC1CCC4981961EB55D6449A353B6D08EF78806A967C23762005034D19BE40C6D8625004A478A7B35CA4D29DEEB9F904A905B50268A9B69F48A1EDA29D702DA46A0E0F84CBA63D8BFB4D82FEA132CFC1B1E8EDB3C16780E2B9EA6CB0B8119A02A1FF7354B265F797844B3B735FDFBC9AAAB4379C0E32434B2F12407A212EBD50575EF33389701B8728F0C170C8DD9FC9FBDFAC2D48D45A03E19D3A0170CB435BB0C607A0F77AA913ACDC718D67EAA307B53F8338E846787B2A2D360FC0AAF4ED8DA9EA2D2A77411BF0FCACF8989B3EB0351BEE0F4EF2119C4AC51437D0823EDB1DAF1A8581C92AA32D17BBCEA80DE2C4097B3993BE16E08E9EA37EB17F1137B82D6D77F42FAE8521CC6B8420682B4227025395F6CF41F3C04490D09219D2EEAA86BE2C8C93CF59EC2C93B694FB60D422581BBCC823CA69C7CC5D75406C4365E6318DD935306B8739317C578D0FCC15E1D0E83683200428D9C466D1E8BCA23BB0C5F689E5C00B3315DC24C08AED06A5A975D8087AF42814CFD115A670F98DF15AD494895482B88876AA1BB6D9F805AF4401D747C45426E81F1A9E9B26541CF246C5813F4D0236D9A94306BDAFFDC04625719FC3FB868819DF558774D63D133C1C9E152A75693DD180621056A5B32CEEEE0D179865F2664F190B4DD927A13921796CEED93662AF73EFF0020F261F7218C5243B8305FF1B8D600E911757345B67A72F6F0F2FF3B51CAB4FEE910CD9F7400A07028A528B4FB4DDDD43303A1D48EDE78A46D62CFA74AFF9EA5DACE434ACE6D58E013A377A28A6CA82CA2E4B7BC911912BDDA0928E25DA052AC4A14C54DB1369BCFA9F764C8E49F687C631F0C1DDFAD98F62EF6A0A43359F036BD76FC07E43AEDB353D057F9A4358A735C957CE4FB97BA2F2D33E7E6425DC6CE4F49ECDCCC934DAD214563E24C318DC5430482388ED53E390BEB4FCA0B600E79BD705F481D395CA0A1D3675D573817DD8093BD5CA23CF2290DF9003DC82C844554D15F43AC605E5C05F049FC621B4D6B518F586EDFFC66C4C90713DB7F559AB4350C74AC25738DB271D060D8A24DCCEEA9CBE2727D54CE0E626D92B1557DF8814EB54F7C3357F5A74AB8CB7D3C3DADD8CE4488BB88043B2944D8C15F86DA6C0D2528864104A55275298C6B1F26CE24C02068EA07DC91FA16F9ADEE55EECC3F1455418E632B3F51E394C8B0D94A6361A8FE6C1D6BF4CB5630ECA64E1C8E10D0C7AF558AD7E4C409C4E3BB75723650336F0F12B7607267A9AA7B26CD66E34DA287DE27E35B52F92AD22A87C061D829E5DC07978181846B848471397AEFF2BE613C0B146973AB787D2775D9170070A02C2DD403D68745ECF4E5BCF95BE388D16680AEBB405BB73AFCF5E3DE1278D53A5FEAA127E57BB418FDD481E7373DFDC68CD926FD32EB30563ECCAA42D232FD3DC4B04CB2B9E5501CAF557E510601B99F41CF833898C460E29DF4EB5D1237BD054362E8F33FDDC6539486C32B17CF1FA2DEFD7DC1A3FBA683F556255D722A9FF60BC49E2DD4BB504160A96862228C5AA1B130253BC16B77F6F4CE27A10AE6B04C1FE88628AD41885073C25245B69648FE75F85B9D0B1767A6997415F146F2EFC12879D0A2807BB654BD0CFB55B19122FF1CA17E9FB2E21C3AAEBAAF7C9CA5F36E13C574F8CF051D6CD458F208CDD86CB43E4A2E559BCE3B5A8346382CF2362B84A33FA8D06204D58B010C2FFC4EC78FF2B12504870105BCE06A562EA481253BAA5E601DCAC3C38A228FACFD93E55F3EBFD24A49EAD6164058805671D5683A6A7A467112F1FC12E73B73076B077A2E860DA0ECD032FCFB42DED0DC7AF628178C37507B342BCA2F54487D4E4BF071F2AA719493AAEEB25E45C72B2A8C4B7A354A57C894E945442E102374D9AE86B2AD9011DF7E9B3A30754D9872E175214EACE4D9C65405541C302ADE383D82837F7BC074ED389B0786084E0BBFF6B17B6859A14B10E52BAD87AF069145621F9B04CAA2CC2EEE3341076D8CA75AE5F8D685E18B1659667FD243605C2A7517724603550343AD606F459569F88EEB68231A2262BA550FF1A2BDEE8719824B749582D82ACB2A1489E2D59C6714B6DFB4C08ACFEDAB8AD3F14E800F9067FE418E015938DA07CF214DF810DB530509252368782DE6B40BE425C6E9BC0266F4288544929BA8C3154DC8F014E70C7F716F0AF040C99EABB252EE2F630EEDE29CAA226B3351148A2E684C02143B74D0C17744630838ECD3DB1C3E08CA7EDBDCDDACE8F024DA0D8DF865A5DBF76B5BB663180084397B3E7CBDF28DDD78491078A191B6B73B56C656BB3EBC393B350A082DE4FB4F301C7DE8D603EC733443409E7DB02DA7C3A43CBC2B10F5F0B4EDAC421F2BA2FD17D178CC66645811FD1E2BAEA62AB91E09567A5621E06F1CBD12632EEC3E21F493B3A98CA58FDCC14324D692A9C4FCF949F2D3D01BCC25A1F8BC1D1A03F31E997A148A520B0FF604C65F3ABE32C4B311F46010450993480F3CA9BE32599E509BA68E7747BBA0B6481F9BF5738D94B85FC10CF7F58E14B1AA46C6E20E7A09157296C859DD22D38F9D58DEBC418519344E30CBE392EAACC7EE58E39AB336AEA2095F62943D2AF22C785EB281F45667C95006432774088DB18419F7A52430470E3260C709604BDD2BA55ADEC2736F3735EE4EFE96586259AEDB15DC5289020D7DE76F76ADC51A5B98195A2B742FFE0C8C77BD26438D948551E1AA1815B84D15141B90DC8CC78EC332188E97D7DA603A108D67312A663D39B22F72145E36A519BAB6CCCC8E1BDE17ED4F9E19473B05FB665DF3851A436690BD5479BCD913A20FFC83F43580E0A7B0A73604FF74E8AC8400EBD266571BA2AEE7A95B33C1082BD9A39330E62CFFE29B629473F966BC57E0CEF1BBBBA1FB36628138761F957F2AADB2A0132CAD8A6EF2F0AD4BB7E62D9FEE72C00FD095DB479BD3833532475F8C5A90719274ED3E2B15D13D73C21D1107167140B65661439BDED15F95FDA97456EC3EF7BA97226D12D775BF6109B5B6DD5725A325A7F95A9D5E2BF4AFBACE6698493CB66362430C54FC286A60DA95536E4F484E8CBB20EA10F334E1F025C6F279B69F623EA6810848D00FAF1EE61C0C592BA60D32CF10FD66E8B12B4699C9E816B801B503F02CF6D833D5A66A56D6853EFC6804333B0F9A03B4800505CD2A89DFFCA807981638B171BBCF1FCECE72760FD2C55CFEDA4B9FF8845A21A0F5D4910461291AE5EE24879232862EAF52DB7AA525261B3F1A43A518DBE72EC6DE26EB8780E43982AEC18B74E958AD95C45322E41D2E6A6B0216B0465326CF7EF760932A5224FC87B86C5708C8F3500F854D4B62985EA1B231A6AA7B5D7BCF83A184B063CD1272F72F266B2A384852E387FD3073CCDC6256719286C50D476AF246BC028A15BD4F8AEB4524A3924B99D8E2B9D4B9FC98DAC1325F49F5FDB5C32EE7EDC136ECAAE1027096728FD985970C59FD45F1328CA1AA2C6EE57A9F4D551232AC7A2029E4D25151363B6320EBBEE4D3D58A610B5B21EEF85976B86467FBF0544ADA2D5F02CBE2399E83CB3F1910573A7F078265B9BEED00C56BB315283C19A5A08D8DA3C5C779B8C94F80CCE4198ECDB1FB86B7CED2CCCA4C937E360EF0BD0B5939A2309D6210D80BE0D166F07C877F9B9C74DF1CB254A0AA46F395C3EFA3CD920FE6C007237CB11FC8E82043F184548F7E46FD50EFEF7B7650CECCBA472E00157FD7B65068BF20FB839A9D0CB6E8D06F810FE969A91EC120A7DD507FBB996A5C8E53E48C6586CC59090D6E44900342EB47684B67EAADADD6B5FD2E677811F66D90CBE745A01BF0D43F91DC517BA283CFFA1A9365DB7C3377CFB8D54DA1034462BD2E4A4D4109D6A080F7164A5AD95B507109D063A5AFE47BE2F28C8849591CFB444D8349F454B719B674040048D15DAB67538EA27EC8842A84B19F55A9CED4C8FFFF0AC754939DD9BDCFE1E5FA04B8294BEC99A995EA90F0CC2ED4DCE5B0B4750153185E512A2E5DB03CC0DFA5778A663546F0E7F8B14873C7A13FD88DAC111198E0792D396602EBEDF82896C40712924960E2EC123E131EA4F44187D2608CAE03E2CF3E496C387FFB372A3FC6067ABD0CB5B335B5ABC17D4FD9E3ACAFD82C6C5C362E78B21B177BE804E5E5D54AD7E3402C17558F63C866504D5380D44F7D5C47E70E40C7E74AA1D890C963A9549F7A0F78AF2EEFA7D8427B0BA60EBF2FD4CE30A7AAD207F861CAC1FF534D17A1115B664BE2B30ABE89138537205D115BC5EFCD0308FE677F2C3F1E1694B0665963235A41536C71E517FD2CB5393165A75F565F7CBEF0230718E0297C58161B8098BB0AAB9A5FBDB4A572E17E78082D16E27C6996A5118E0AB330ADF01C9AC225E352ED803BB9BAAE039990554D25CA179AA7FB3D9A8B547039A22F747C5B3113E92E9BA343D0ED3B79B26D2C22EE4E81143A349909142290C17947BDBB5FED6736E56B52FF8C20649EBF8903F1364D9C149473566F5EEF0D3BE894B98D744AAADFF9A2E9C3BB91C7362FC9C975D8B328872EFC961A7305AF1A1DE12A9586AF67473B5A82165D11DA20094102C2DE65EDFA2CF88CF4ABF1DF42C6E3DBD9A50ADEEED4443C2D30373B7E4AF1D3E38A3B4E8C9DCE9DACE7C9EC0DC256C9CC1F02CE91850C63542F79BDEE56B03D0272D57C2A620D1F52DD4BCA6AF7709FC394B1C25454CE3D7DA0D277D021BB3B16B97BE06C845E65142B84EAB9C70FAF52B0C5F0D265FA2B168BA09BC0B7F3CADA7DCE4E9EA9D88DDD9423B449618A07E59306A57D26649125C2251ABC7440619BEC0AD666DF4BBD59ABBDD0D1956F4A484F1C6F9140E966397A218969B6EC0F508562B1C14B7AAABF0B88FF887CC736F5A95F0AA7B130A12EFA5AF46089C0B9C408671E29320F2C6D339B446248F011A288B84D9EB97D70BDD3486E9759EA3D4A1519FF1B6D00B1EC1CD8631B1BF8C10E1CB6A0132F46377FC1AE489B041866BE4AD4218984868201DE09EE13971F90A334D3F90505409B5EFB5D125DADCF59B58604147C49BFF5B40A43A50902677F05DF541161217C9F12ED15C327666A70C3E8F794D295D2783658377644D298BC4D693D310A2630F4FD65504AB8A7B0B039B37F291660AB629C75896247C50037ADF9222773FF96A4D75B9548F05D9DD943FC3E245AC2ACE42FA66FFCCD81B40889B25F9E439DD4C8FB7588625F0B6B6E1523BF2AB03C32243722BD59F0484B8C8EFBD56671D63613F84E266E63B25A384FB93CDA047D26F616BD2D419C057B4625410D2BA04BA3E91043590FDB526118B686D183F802420E2F7808A77AA0604EEE4B83437D9399C734510E37A5100C3E0B59BC77D0835AB58EC510B63591D26EBF5DE919C02AEDBE50C9C9C36FA52B0EA2ECBA1853D310440D52D81754D521C67221BC88A1E58BFB84F339F7AAC1B5BC196A4FBF59154FD1B83B0B9108FAC88C69DA4F4E3B1B7865526E2A17BB1A2350E6C5F2458F1CE139E0249992A6F456D35942521AF4D64C0F9A2820A16BBE18E4A2DE934AD25F56E101579F493776808A3AA327E7B0B0AC34647FD53697BBA90D5F463358E14FF50427742F079E4498655A1052209C7E7817ADCE815284CE7D59A11395677A7E7F920C01C697E3FC09D852EBAF1F5535D587D4BAB4EB3EC6490A42312CF37AA665878447BCD78AC93F6B78F0D27C9E2572DE6DC81A957E32DC307E6071C1A8CF33045E0E985D4C804DC7147AF9B9FCA6537E7A889EE3F0356EFE0D68C8FD01B1F0BCBA14C179E46C26A43401151F77E438F730C1A0823A32B8573DFF6D89926958BFD2678D59B0E51A569AB697510F040D94A17C3EC3520DA19BE5E896D26A792C2B15030C6B5068292A9B8F431C2DE8093253781FD90A7050719B0EA417EBEF88A3BDCC53DC93EA74C28376103EB5C4C65EED6623525CF47227E0DBC7A019EED70045298A680AF937AEAE895B31C2EF665952E8759A9932211F68FF77EDCC092DE3786950FF940176C8146CBEE634616A643BFFC583E66214E15EF5B22BF45F2FB4CA2D25D76AAF3C721D5B51F9CE4D94C425629ADA9082E976777BC632A2FF09D86F8F2EDEF2C4EE30A0BF8C9341DC2DC8BCCE06B2060C664C48367815F66FBC6E7286535CBC5EAD3F8565ECEF308E4FC3582E2F088102BEAB0887775D003E9531575D3D099C96FD529AAB736130D2F41D42841F3DA14AAD54EA0FAFAABCC848DCFFE07D94EC87A2C3BDF30287286C07A74A17F07DF51384D27552CF328948C620138395903BF4D1365441EA6AF10A9626EE6FFD8920A1D80E2EDE718749A7B7A7A95DD88AAED38D524D8DA08996AD148C0B40337DE28BB383FCBFC5680928F249C6753BA5059215990459CF4D401AD8C52A34A5733BDD6BC5838863F90A578C01A20A8F1DD603A5F1DA69B87D487899E9006F1C2BD45A4DD9A31E3EF30FECBC3370A815480AE04A2817A73154664F4A0ED412DB88E95DB99C15B9D93682D9AC414E325D771180E1115D11FC321B452FACF10DC1B5DC128E0B5BE16FF7608831FF4FC64390C1F2D3B9DDCB5645D404749C991DFD4EBBAE566C0FFE3D179CA897536941CCE9DA5D404F3890570238F286C6BEC1ECD2799AD6F5BCED4C628F32E1977852649941552C23B116FB766364705F0C99E04CEB459E52505C825BA2F46BE55B3DF979955C56F02527F9304C76E3074F451DBB3A563AFB7A138A78D3937E4F7B572D94A4DC357278C42240711E10ED955DC7322AC7A9F87B7B13C2B63EEAB9958D4E213C8D8D02EC7A34C07AEB20734B7E65C294694070352CF0828724951FC0F0D25579C4DA5FDC635B1B9E388D2115D11D42509C7508934E498A6041351520CBE7C43532948EB351AE3E6EDFAF1433480BF727096A37CF1B7C49D2B45C10C93246C15497A6C4847CEB664A92EAE5DFDE2FDF87BADC4C15225389A77B31EB79E5972DE910FAC113C8D7F1FCF71CA6D1D86740A2F3C95667672A8BC33FCDD2D2F6146B58ADD55C8C976B2E4CCF73B29C70D6DDA36FAC456702C2F5CCC47549611AD629A201D64A6469F590F08886EAB226B9114E4FCE4DF19E69EFDD7DEB534B17C3C1836428427E2CA0A06F40F343BB4A5DC96CABE5EFD1DACDE25CABF96E0A9779DCD63317390D8ED2E3F875AB099DAA87BBBFCB5EC4B9C9D7F6EB6BA68933AC589BF3E6B92AACE1F6B02ECC1CF9D1F98AD1FF1281777CD7E397C696A1515CB11AFF0071F51BF2BF2F18109505425ADF4B8464E1AA90FC6573333E9F247096C9413E92D0AE0B7D018CF66D825F1BF8CEC075623D725BCBD64D1087190579D7A726E99C6C184F8EEC82FB53A041187537AA18FBD44DE326EEE6FE63A4CF22BADAEFCA9C683AFB5C6CBF062F72224AAA58F18DFEC506FBBCA1040FD26B5C8BABB3B1DA1A93954320115E3D37EDB70B978B9FDFF8070C8AE29EE114F6345C4374A46DADE2D74A4DEDFC50814630248638F28BD8ED5C26BE4C2D9017F524A0F2B67C77F562A7A49F6CEE586B8433FAF923CE3E706ED46E8306B8A9342E17743A3161FAA991E6C2AC05F562819F099B661E5DFE9B8D72FFFEC6D42DDD1B25D5AEBD34999EE53814B862EF4BA0C0FE6705E81CD4B45C1E9522E0B30BF7A6673A1ED84C76629057CC8E935E3ECF7BCBC5915EA089963AB7EEDAAFAD979D345943276DE6E0D2829A3FBE4CA2030ADCB6FE71FEEA190B6D0BEDA206354397CB64F90FB507B4C3467121E713B08C107A2C885C44971C4A3CD2F9EB93302B4177AB84876E93AE1A1241B436B52EFB7F00342A5F06FC422E402ED583D8506C432D43F116FDF36705E7B7C1985579B4765E31347CBF58458D6EDBFA03B735DDCBC66F35F2382CC6610785EE2EB5EBF988B36CCF2FCBD669C9F1F52E038AF740DB138C79C6B2364CA7B4460BC9FACB2B6C6326EB5D1379235F2028E129629E6265C65FC21DFD20CD887E286399ADB43D680D6526F01ED4DDABB85C4C86D2929C0926D7BFEBF7AAED93C25CCAED86119E3CBFF9FF033E698E5119DD5FED5EB87343F34B170DC5BBB21F2163D0FB3FB04A092BF1B1AACEAC670E3B057955E83473250EC679A24DCEC9CBD8DF37BE84AAC6AED9697B60899E20546CB26A2FF2AA785516151571322E8A36654E9C9C73F9384630E9CB000693743996CEBFCC2A447D60D3DC56CFE4DBCED0F1837F2D1798A2008A15E02FC280CFDEEDEF66E5BBFAA4F9374BB11A4FE4C789A0970CA5317B6CE01FADDB95376120BABB6674AC889C57ACCB43FC5E556D48195E82657503EE3DC354898DC32B4D5F9664CFF3399C8C4604EC7D1571E4677985B3F2C06A9EDD25DEA372A521A106A3F09F27211062B75D76D6D2ADC8BA2E8C8F2DAE7FEB9DAD8561017C3194658F3C43AA4A9ED6E00B5CA3B7375E5CDDD605223EA9E69C9DCD92E811F00FC7F04D92EBB5E58089DA09C8B03684C918DD50681D30BB4EF6A4F7882FD7E8B22C422202A1CF4F2CBD992D663ECC3FA3F02CCC539599D3A8DAEAF3FC4F313E0313F2544103E10FDD69EE9A30A9159BA44EC2EB0A890DB1EBA0C70AAFB65CEA29B9DEB4242FA42ECED0BB7C287D69ACFA74011656A0F75AF93C58F42C15CAC1E7E21AAC2CBF2E0626C61644DA39FBEBF9DF2A89BCBE16E9DFD4680BB2D466FD1D9BFDFF9F1FC8F77B502818B93ED9DDDA0CECFB2A4B89AF6D319ED4B89B91A5856602D62A7206E67AAE8C58FD3B4A2361943F885851160D2C25821172A8E5CA9512E13D63C389875ECD16E9CDD60934893C97FC45C5930DA5D00091002C9A9519B7410C6F8988C49AF36C95CDAE40BE356E557FF3E96CAC4B75BB7EA80CD1B686253F4B90C5DCAEA45E2D55DC9425762DAA25146D74D25AF5F329E67882976C93D2149B50FDAF69A068E5082A4EAC3F63974168CE626D33A8A645012EA83E36FAC41632348C6CEBAC7A436E7B34C70F5E7D5F36414CA15B1C8564F302F09C68ECD5BE50804BDED712B35024BCBE790B0D8C07C8DD3FAD772969A7E244D0938D0B5E8D24753BE1D4F72329998E66ED9673A61901332D2E9779DF65F03AD67C1B56710D37D15479BF5F7184E25A27FA5B0CF5934BD26684D8C604C8D1BB89B4A1B1767E7BF67718B88CA874331920990109CE2DB29288B4162151B86FD5770192B96E2DF5CDD6A65BB01D369077E07ADFEE45EEA5649EC29C6CBCB26BD7669B35AF6F023F7C6D2BD44F1612525C17462B166376D3F8AA62AB0F6A3A45B7B47D6BBC06873CDEC2F7016DC5B2768A7A68E343B7A0FA12EDB77C2962594B4A11D175F1D7C6BA10C8115A175E56A038FB80CD53427E4A485BBDE60F5E54347381BBD665D84E04EA747F4524BA6B35425CC49A6CD2D8AF075D4621AB40C075B33376DA5869B0E3525843132706A4C7D1BD4454CF88D16EC560F5E0F02DE5C13691C3C1FCCECE19979CE0859E97CC029694B4EE0138A3E7790F764596E82E6B9FA5009FAC1ADF24E35AB20BC37795615D4BE1DA62A53969F23DBC8726A4DF6CFBC7AA6CC700046A8F38D75E23D2AE0455209AC9ED54B02DFFC598810CC1716EE37CB2528A82963888F6AF742A6827005845488B93C6FF3F48BBBE9DDC9AF675540753C73BF86E612789EB490F788DAC223E18015DE8131524E555E685EE6A967297A683E7142D0E5664183A26FAE5105FE929C06CB260D6E13402FE7FF24FFD832C6E83EC88AB253DD703CBA0DC8FD9DA16F62A01E000527A18F0DEF014CF8586E353ECD95C192A17A2BF654A50FAB4C290CF91DD80E4825D70959588D9EA565D6D194B1034CC4CA98E430A41454A4A83B85CEFDB0BB3A748ED85FBAB77FD48786D4C069ABDACF408E4AC7D8375F0B87A2940F99E065C2F9E0A849C7FDFD235222CB5AB4E58B2570024B0A627E1B8FB46C4BBCBDE33B1F328E7E5F413FD4FF4DE3B1D428416F001D140F968096FDA26E0157CF1DB42E65B9103123D0CBD00D8DE0DBE17A80B55329E80820DCF3418A75F7BDA5A33ECA2C8574865A1D958A225334626F669FD2965145357BEFEBF558CF3A932FF7287CF8625CAEEECA52A526A2C39369A4C6667FB131B1A3EC0DE319F33CD7E4C751D7A86337540806EA0B2D033F782671FB48B047B6DC54592F529D52C7F081AA8CC4F09C2106004F802D31B02B8958EB6038C34CD934BE1873E5A0F2196FD58D1B4A6350174F77016DEA4301C395F71B6D7AB299DC71ADDA5C34FCFD053EE8914EEF35D15B3CBFF687487E70EBC50B0D34E831667D6ED65FC5474B22B79DC59E9EC5E837ED9B05C1BCCF845D10FB40E77FC58A6E0D9488371D938E9CCB6A3709AC82B77F2CCEB7B448A3132ED035C231E114963B738E48A3E48BBB7DB0536F591210383D7A8475EA0A9E8D4C64DBC3D710BB0578E47B35E4D6DC5B2D1121BC2540A2BB46F4F1EB6F5EEFA33B620A15A674FD7B9B7602E561D95178D6148FB67483A79FEADCE6CF2E854C3C7ABF2C35B769EE5552E55A0D14D0C984473C41644A08D43344F43436680615C1FF96955B1B2699CEDFA2A6CADA455BE94D5AD1513B67A1162CD3847E1CDB611C37566C66A9FBE477C63DDB9A25A7B29C1F20369EAEE682E4E8BFA0D7F3789A055E8FE7BBECD014D72C7ED43996A78101FC750FF1595DC43686FFB46498C91314A5B0C4D53509BF315417CD85510CC20FEAD1B35564D265D4D7E9BF6DB74B43BE18F4F0E3AC8F2721B1BE322EAAE018CE7561EDC7814B4E9314C452EDDF4884E61C4398D11D59F777690688928AFD03DB9DFEC3D61B676DF7D3F857BD2D15012F6BB9ECB3AF90A49A2621EB40B7B7611CE0AB66842999240FE891DC72C0F9B245D6A456C511A2F6E17CA7BA2137F92311584CE908634E3E39D72031285360B33E9D60AE601074C9F3168657F13D4008AB825D5F5FF0A21BDEEABFF56A5C78F7DBB56B89F40861E0947D7AA2867A79C9430C1BFB6FD18AE66C622D93EB115374EB2507FDCEB2ACE366074745A37CA6C7E3B0F7C6E850BE74A02C733F6A0D049EE9A5E26FC67F0BDB21267D67C8C30C8AB9ACC591B867EDD9C34092C5B84463838C0998940F5EEF53F8AE479620AF12EC0D43A8FAF4C0B0A422D8A8B6FFC5A6555187CD3C831A570CC2CAC2058A18C9565D485D4D437886A9B27AD4CD14ECFD799C423B2C845BFF4A6F8E98B6B2F42FD26B625C15BD356F57EFACA6DDCA96B9BF442CFF0CCC382B28106E1DC62A18E7039B1F70DD16400B494AC764A919AA30C7AEFB947E45306B8DEC969BDBEB7474AE20EB7E08363CC21427E27E5CA753E81363970D7B0DAEF34AC1025C9A22B8345D91046346DCE62CE6904CE2931E86EA026787564947026AA842444DDABF156ECB338597268E6466E17D9458A258A0765FE05BF89386B3C2BD19BE06274E05189DFF9192F051614E860F2A500F9982B158EB2987C45DF24BFFBEFD56B62D36EE2F29257C400018386328FE3C708987BFAE42014D88D3E094B9179AFC7961472296DD21DA96FED02A7517F7A314949959BE06100F88769F458CED65E2D2384305D563FE8A94E9A2C15E9B44B17C7BC4DD1E946F3C584D34BBCC6D975DCE7B1FF99BDE0951AB1111113D2B3A61AA06793A3667C7D490D4FA7EECA0771F7499D4029339B73CE6983FB8E56757F6F06A830FA67207EB19380C1984A3DAFD44F0AB559139316AE0AC01EB80CE2E9829C3A1C742B27631C5E309607A92EDC2327F8EF8A7F5A7BD45758494A3B01F05A7F8CABD44C1D27E8D2071F20F7E41E4051FB65DA5D63D4E7DED97F05678B0073042535BA30ADE54D1D6973895552D644AE216C5AB6155F1E1BFECB69573668EC9B08877742B1A5E37E9A49BDEF019A213F711C3977F0BAED8ACBD2345D750B42900BAB07F0A780612958D274B26C0E24FF9791F7349B89BA63925ECC01082C25027BD9DC69BA52CB709544566FADB4B64E435E9DEA837BC531DA332DB2BAEA774FF0D153745BDC9ECFC3968374E81DAED1D7A6D9E72DE61E7C944ED76D03A0FDE3AB3C97C0383BB1B72D8438AB8EC4F420EFFC70365957C27595404F04B17B2130150443CA3E7EDC54CD2AFA0DEFCA665D7F9C2C16A95059D5C4694A5E72598BD0EDED2B2C8666489732CDD930556D5835412AA8132D9EC17819524A3E5074FE79422A3641EADC4FE4B543A89790E451DCFE1A74ADB7226C4354FB83558127E947164FFC3CB4794C98B1A193F7D76550C1D1BF23D1FF6A8AC85BB0685660A180A26184FDEA677F8C5AFC04CBA1D196EFDAC86E551DC0342EA939794EDF537DFFC2913035DF199828E47C9BF49A98A9D6BE35A7FEB1312A3D5808043DB9F1031A1770270BEA71B3597E94DD23237064B9FDF8D0151492D455E1074A334BCE8B2AD5D052951C8208971D9082E88862EDE46D969D363DB7D674EF981A09E217FF82FBFD0B5180F2861EA2A5C31EA6F640EE6A6C076868672923090DCF78384FD4E8071E66C3E6B2591E2E50DE27769419061250145F821498E074A923FA5A8975DC081BE3C46D66A303B323819B0D4F4201A3B7F433C670E28668CF9D5A8F2B35729F961C32CA7264FD5DDB3E38A36E537D214CEFEFC068B8CD273D487D55FE0595C2D3FD891023F59F974BD92A1372982F773BE461B865B37D8DC09EB40549C9842FF4A333DDF6BD963A7D9BD56CAD45D6926479E045B68AAEC9EB6EA561117D1F6B8ADB83E1BA08D2DC49BC17BB14EA92A5A7EC3BF1D5A4842933194806EE54BABDB5F21CB6499A9FF6E9A96059E51F99A420A7F032DEAAC4CC8A376E89BB2E3B0BE77B330B850B349643DCCAD94C31AE9B80EDAB9A56283FE0572371B37493949B987E965D9995DD2D66F2E15897519C62AB5A6FC617B3F054F6867B88E9FA404074972F312C2F342F749567702E39CC2AD4E34D8320882F835D0ECDEA515140D798259DC483D93382AE6FC358D4DDA18BCAFECBB234B379FCFD34BC101DD0A9D8D0C5F63580EF323D2D3936B3784044F0BCC9842CC980A723BFA9E1D92C5FFFAB508800CE7EBC8B99623D21268981B4EC359448C9A2F539EB19855164B18722E1F902ACCE64626072776F9030B6CE7335ECF150924F78AC7DAB973FDE1BE4B1A726C908D3A291DFFF0FE37110ED95BDC53EC35ADC1AAFD9844F138E3C93CBD963954AB2CACF358C37B714B42AD5A3F148B56EFEDF933D6D87AAB3866B05E78DA3ECD98427B9C2691BA6AB46193597BCAEC5133F15F7EF4BE61B2F06D01000D940B659CE951367D21474C004A14DA14B921FD9F0ACFE2875468B6AD87EDD66784D15E7B058E310EB3C247C6E8AF7B25699E30733269CA247B25173FF9DFDFA816E9D3C051A33C73134B691CF0AF47FCCB1B7B989397A536C93FD1D9E0D6D3C44367A320DFA2B0E1166231CAFB6AA05DD4C5134142731B2AA06394BD3672948F399878AA19AE8CC2DA8BBF290D0F75184932494068276B54453DE3347867D090D5720D70304E1A021C3B899DE4016B5D6F4F5E0BA223A0BDEF79ABD9D1A6E7488C2AB25671F5ACD1D3B63FAE5D06F0E91242938925BB551CC56D751FD18E9BEE669BAA75F319F1F26DC3777F9D0BED4EF8F96D913EEED5D639E46149242E13A331905EF97C5CC546B1A23E5E7CD38036BFF36F975BA4F2A3C59A8548BCBB1140155434056DCB50DC28744CD67C2CDD649541962B30122BA3826423AEA4A2D7B0C411CEB02A4C517A6B53FBAB73765E3D0D820A2FAFB3C6A71AF69D9B140EE89067218063B4AC8B9D860F516CA551F079635323E0B0040B9F6039DD20CFC58D18FA74BC74B02DE73BEB37C7D15D5D0122D1DB15AEE8449089F994D55100D65546B50B3F11DB66E47462833AD13EF76F83FF96671C901CCAB2DDBC70E2FF47EDBE63D29CE76F4BA6A24F3E82C604CD7B66AED6DB16AAA0DD485E399BCCC05341C4FE64D98EFCDDA9908061BB89E36AF136FC5E5B6BD6F757F2036A1D1743B95C456F5F25B81D981B0477B2BAD0AC359C5344E170103C99FB162ADB7289399BB4F223C8660EF4CCEC8FC47BDE2E2D856BF43F72AE4E55E72DE12AFF0AE494113602A1C390F321F773575FBB9D0239DE0C63DEC165D420111E8D616B85B71641EF7EAFA1D88347EE7B8C964143F1C3DF4E6D38101026230298917CE390C10075BAC6B1E8367DF91EC7CE42486140AF3F6D51639C54A61E97E4AE5445D2E6F07DCFB9E7190FEBDA058401B9CD1BAE0636FD0C59DBBE71795A58834E885883ED000EB160209C274AE82A732E22A447E271D6D5C832B3A282ABB820F8DCF1A1975B2E92F3C66B55DB54607D3AB21EBFC7AFB42A3D7E19F73BC8D53B99CAB20AF95E3E669E980E6154478020A5AE6DE70E0DC5A331E4443061AFD5C868F2F9EF9AF5F89EE31205CF1DEB9E6165C916594E1D6F4D467788AD5203069DE2EC2EF0529C550F8B42E4D05FC94FA14DD87C9D869633CF14C8CB0085DB6D3238266B374C9C77F3FB6C28E133FF3CCF559F7018D1361656A7A9A108769E828A8AFB4AE45A8957D7C03668C93E646AF6BA245ABB4A27A2C7171A1BA69F340B428171AF837F33A02D7AB3A963179D3000E79D525FD17723CBBB4665D38A4BDC524FAEA02F595E3705789F77EC57C0B7B8B6024348C1C763975633D9EDFF002614593AD210190C1D73FFF978AD1DAAFD32A60C475680321AD411E91BEC94438ED9E818C4A63F7997B1FF1BD12135B7B405A10F1575D874E47F007DC14A4AD2B0AF863818A2064EAD55E5743776516C92B3907973B8836E5FF1070098873C0B2A616C93B84CDE4C5D2C9D91BD2275A1B83F65F3E671C8F6FD718A08EA4B583B9882E37B2ED3AFB20E5DEF50AE84480E28EC33A43A302C9730EC644C32FB3F0C9E211E5D70965EE05D424E415898B3C835F83C9B2A210B6C3698BB9DB0A7379C6D954DFB2269C8BD1C09FAB9131F53E58ABB0DCDB86CE588D56A5D3B5C723F84D8698BC2DB8BFD1A317C91B11A22D6CE2E67C9CD347A979C5416EC2C3E29E87E6FA079B97A58CE3D339F1BA8D62F3EB3DD5E11E1700D1C66001A3FDDAFCA6E89DA83065946CBEA15D583C38A67C8BCDF92BFD877C03888804DA9ED7D5BFFF024FD519E2ECDFF67327FEE749E51D82F0CCFBA83D99EEE253C6DE68C89F7C59F7C4515821BB764DD435D03BB471075022EC7BF7D042AA14282AB0AF86909A13E81CC0AB6F0B7FA31FB931BF5723FFFBE711EC8FB64B04F603BD79E162F9ED7F76ED87012F76928E43B2B998D307D2C61DA463C60A443544D1B0282022F100241993781E8C5C21FE91C13962743F6289B9321E86EBB94023BBCEF22455EFD429A920547F022E570949A894AED405ABED4B3F34D534BE3B701E41D330A2F6FCA9EA55CDE6097E22E178863D16CE4EC234DDD464035803F20A02E0E41F0F1C809B1CAF6640D2B1524E4FB37AEC470F46280948E730EFB7B97CF8DE1F1CAF96AA99988CCD314EDFAD066B9F09BEEEC93563E0ABE3E32D5420027E7AC60940874AE686F15F2B0F02546ED93D2B885563600A5EFEA18760EC53AF4F3806A1367BD11A48DBADCD07FF97E3A4A3AA643B3BDB9378A2F7B7E144F6224FBC71536793F2CEF2672636CC53D5D68587C6F1349CD3E8BC459B80DE3280F198976B3675B37B80392F7E646A38591686D9C82941CDEF69049F5F2ADDD9AECAFEC1581985B0575D072D7EA6AD907BAD894DC2954634E308B762592304F78FDC1DDCECFCB78EABE89AC66CAF7A439051885A7F6ECE849A43AF3C476019F479B5F3EAE1497E1A0A7FDD409D67F0C077E1D4F1FC8C79A1BC0FC9203C939054806C4B0DCA7A8E12567A5E73BD7CCDE8E7C09D31AEBA2F816DBF32B0E03995C1D99A088D3743E018C0231DAB5DC164BABEE3CE9D965A5C3711CA975BE6F7E809CFA92F83B1B4B7664566E85A278837ADA734DC1F2847A4FFC92C08BC32AF1E53882012CB25BDA4B378671E06592E1C9B3885D9F8296569DB4699761E491676B51B7F7597701FA9E26BBA878BAB97CBDF18520A53E5EC6D5F80BA9BE50BB1CB702581BEF9C76F3D4FEDEBAB5B076B6168D60FCF2DDFD8D15F104EA242619DB629D80F7ACB337DC77A47B8957D84F6843B1ADF829887B1A94FA8FBE2CC2C7F362CF44812D1CC84FECFBF0D30548FEFE61CDA5C705607F5964631244FCAC28A1669DFBDA8D58E80D8C3DE321E644C22525D4EFA6D242A28EDC339C016BF990202C98819BF4BFC4DA8BA4B0C98FEEBBB0DA346670517BA76E787678840F419547C7F119186FB9DB6D880D23B4571C8A0104A3B57132B21DC2919EF48B88A84E7ECA7C224F9FA65B3FA258B5C15E9860ED076B588D73A14ED64B3D7F810023033DBF994DFA96872844888C0535C08950D99F1199C5B59AAD95B99810BF56D194BF5D20B4684BDCE4809049200A55669D120F9496CE8FEA81B8AAABD49752A426A6D0BDCB8CB8D4666F7042C15C0AA3A2DF4342FD5588BFB741EC03BA41036C2209A5DEA80F4123CE4FC397B440A242E1E7E6E5CF74648DF2799C6841E1E0FF6A56FBFE2E949C32B4F6188F3046325C73F4BBBF916CD79EC2EE11C01B62642DE5FCC314FB8FDB7AD61AC41FA3139A89506FE669BCFAB7DFDF1E12DC0EEB833AC3E2DE79FEC75FB57FDE63C87504CFA0A254F4B3CB7D22348A92F8F3D0B146FCFA05E1B2ED2ADEA592DEAECE1BA78D812B629431EC67723A79968597A024FC89A558A12E4A0B165498769B93083FC6A411AC06D505F0525D1EC1983F2256502E453E40D12B3B4DA4C42539DCCCB5D91007AEADE43897494059A061F77EB67A0363DA5C44D20D33BA0C8A3B44DF69CE87CF7143B80D0870F454993B7B45D16A4E6E531BFBAE714C393B09028B92EE3A6808529B80D163164CD98709EDF5AD8D7B1C479522855B4C078590EE5A5C342A7A8C01C1F54FC914500483833B41910799F07844860E69B16652F19B7A01F1790FDC7127B8D098553FD16640B78E9C78E663A396E49B9AC6E590141CD155E6B111CC589FB0A632171D9D2F094E98D5FE377CC13BD6E945288E399D7E39D78C80193A2A2BB37E3483A3CB96616B32BFF546B9E70D3F91D3F7F796B0D70F7F9914CEB013AF4E95D2F7F31115ABAD5D362C27E50999A1565A26F7B0457766E91F22440DE0A7715DCF11A2897FAA05930A960F9937F44A3301847C7A10AF9BE3D375397A76711786403BD4132B2791926F7D9E86316ED33CB50F6BC7556C04FA8FF57D19EDD7F3AD7F1FAAEDF3186E4DEDA8D7FC825F7E57E7941C6CABBF093A6E88E0235C2A110B83793064F6A5BCBFAA5C3059D7B243CF1D0AED8F29B8EE3340D438CE8DFB9AD7606D94F24ED741B244ED40925F9860F27FF5C3341273B85285F8FFAB875FE75D4D53F1C6D1CD081FBD19642424A87C650FB6DDFAE397FF15F5A97B61826A27B1E150C109074344520A72D232F0C89AAE1021A76F8499C31501B4509AF79E4048B15F0C223C08550EF9D4D0845A68C7B09B466AD53F2636631BF063397C51424F57E342890E949E4CBC28A6EC3B68C59C0335815E5D29D4E7DF880B86E5A38399E865A5A29187BB0BE90B822F6812D36DCBCEDDAF257E48DC8D8B53C6D1A0DB173C110294E6D92EBF0B0C92DB80EAB7B23F1B73A4E221F80BDFF63F591C7C214DCB90EDABE729140884597EAE3F28BA2D7300A308D468C4AC60CA4CC469C4CB78F8060BF80EDE45E496312469553E53FDA8691E4741FDFBF22BCEDA2D9A1DE0B7DE77ECA913F1131CC494DB40BBC24D7C37D996CB6739FC2CA123EC6DDC02CC0A83348669A1EEAE2A88ABCD72CBCF3D653ECC78EBD340BE6A3557BEDDD15B618CC0DAAC10D6D247776C59C4DB9CF19A446F7F2ACE3155C5021176DB40F5E99A7496AC75BCF15E4A7393DF25A02A053F4AFF10B546E12BF5B94B1980A933558CF180ECE63AD7356CE0030D8795CA0D2819C88C921377850163EA5E3F06461EA15ACEA48AC2AE344D0C09F7550EF4991C53905EF891CCA5CA2230E3FDC2873D4FBD30EB312E31C1B391136EA093233665C47D1D1CB148A0DC77926EDB51811EB31E97D0235E551F3E9DD48C5A804BD4129A4BE15F81A13DA8121C368B35FA3F4D0E44DA321CE977F855AD45E1A2044B45894336645C675B8BF2A7190B5B5BDA4465FF624E6C6BE802993F3A72D5A65FA2851CF3AE35AEF407791BD598A33BB09D35BC6A34AB487AC4BD512670AAC5E492DAD2FC373A6064E4F256AE4EB61CB5571960DEB0EB681C4E5DF614C93F823B08B079C307883416002952876193CEE214238855F59C64F2D3F5199060BD660D38A6D6B4174453C9B87CC42D12465114E9F723059A09DC899282FDB99B3DB65CCF8E0761ED01C77890D424BA744F01C2CE675D5AE3CEE89F9A8F83A9BA8972C54C12478BB1197BAE904C7D2DDBE6BA6069CD481FEB756CF461027E0FF677D65109932C4D66B2F0A3F1771DCA28C1BD232F99F4AFF9BDFF6E040EB064286A8067323784C92F6561A56B2A0108FAD2D1D12D87D264B2D36B8534A1EB1B64C013DA46CE438A51555A5889F0BBD4ED62BFA1477CD29CBED58C704430F09C99BF001CD8351326C1D20A0B9198373C1D824F48EFC423D6748DBA7C9326B5C33CC57AE2BB439E7B2064E394FD758F69C544C4AC7B3B83D724FFDA48D6A8F1CC1235B7DF9C404E4EAD0091D747310DE614CD2DD01F9CEFE942F776871FCD93C8FBCDC8AECA6A7986DA4406DE82FAD220D91EE00E57373D586E5F417F0CC371E1A1A584381F4AAF6A45CA9E0EFE1DA203E8FFA36399F1574142275E3FD2DE5211295F183D1C60DF0DFE6A93868642FC72A54F51351C83CE7218F257871870574B7E73233A7FD85166C0E0EF1532617896E634626E25ABA114DD75C80CEE426DA53BE011738C63B48B7BF6744AB19FCA46517AB75784EA03752F0741308584E04560A5FA0BA8DF7313DF7EFB13C709C50FDABDB84E8274E11DF08D7BCAC4361C7C8707E0A49E75EFFA78DD00859C03B83990C3F57EB19822A7E85D3FAB225693B0DA925EA5354A12A38287598771166CDA7ACAAF0210F923C0D1027CF2D13E154F311BDE4820F293CC6E1638D706883BA32FD8E8923AA6E76A2F0C8E96E3AA1842B467B46C78BF8D9DD683B7C3824DB2FFAEEFD484319921B217DCDB0536238D7F0A96E6E19E2284DCB3A4D275880F16D05942127DCDF6047E5C3997692E5A385B4B1959A7B22853542C39B462F2C1B9C7B491B683C16BC68EA41029C749D62226097AA28573F2657D83387EC6522F8F250150445ACA03722EC62DFBCF43AFA4F3F6ECEC089103218A876233811592B23C6A6E4597BAC84857FF50141E8C2AE3AF48FA7338F479A5CA37B6C16AEDF520C724458E0C06CB1BE3273691EEB9FCFEC06EFEAE35B60ABFECEFC097DF96A27C62E057E51C35D02A03CA171E5FA43139C28A827D4D23C61CA083D75B63BA84782E66EE765388585A1098F53C75A5D60E8A9FD5D59DB855519A4625E0B5904EBA6A201FBB76E12B31EF0BF69DFF5581FFA0048588C2F64625854CA2286A6B19448552627BA4D658AED49E45724B37F1EA14C020ED53B9B00BF71319560EDB4341BFAC783885410AF54C182FEEDF2CCD793EE06D68D29F5CA3005C3C1031A4877543CC7E60151992F8B6D2C4F7ABCF4FC9A9234EEB830802417AF210F3300A64B511523D1A7A07C3363B44670B96AD019AD60E24413738B23018044A54E3639F26FEF032A79F3A0738B0B219DD72504AF010EFCEB8C7B81D7C706DD09F0AD3E3E48E1544E6CFAF5777EE420ED7F6C47F7E70386F0D67055B938EE58C5FBE7C1FC75510EAF91F4155E09CC82FD8F5797D5FF160AE9C7501A73EBB329412BAFA2079356C37325C1DD7438BB44FBC9AA050FF418332B3689FC25CE5CE034F58344E845BA4000B7E84A7CE2973ADEF4A1CA633B24143CAD8B8ABDDC69730B1EFDCC7BCB5DA9DE6ACE5E805B5B6C53BD15D8456E0859736D714C198F1CF63219C2884631310B092724126E56BAA394AF1DE0A6155E9B1BD627286D4891C730E97BA186152DD1BC2D4FE99CB73417A13F89C1F534ECF7D9CAC389CEB8239C04BB17D7E597DF1F2EFC9B12D2CF942E642357135B0C4A9B6FA592ABB2C43BD163A1CBA3ABBB6EB2005FAAB70E5008D0C94A33B5D6A2DC665FBD613AD23EE6632AE7CAC93258D73A0CBAE390BEB55D3C56FB898593A00221DE9A68EE2873EB83C600F49D38B7B2E6C90CCF7A07F9D6F20494E6E88E42A7BC0F0C5B81A3F25168D90EB740CB0C9AB105B893FCB9CF43C7946563B9F2CCA419EB49093211D2326A9F3E61FA5486F927C98B53C80FD8C0EE43929C00F65ED8AFA7BC3786900A54E35440C2676BE89E2CDE6189EDCCAC860DE6696F56463EAF426B96CE29DC5321B87906AA9E247709351E8E6AF41EA1E9E01AD559BFAA41F3795863156795AA1331558D25A5956A2BD6D892189BBBC62467F60ABB061DD9816A48138E9B61C3F1870795697D3B4FEA00F863F2AA1CA995909950A8896F238E3D2B2890E181B666C44B311BDC6F91A61D1ED86267626E2B6EEBC74E84FBB4C63E16544046CF223EE68150CA20E51530448A01A660E1AFDD27CF0136F284443BF92745FADB81AC69A0B8BE91A9C4ACDB12B92FF48A2FEB249F82F5D9147481B35B0DC36DFBAA2E0D6D2BDE7FC46D5ED9D0E2DFA033C76E3257C9B832993EDF5121F4CEFADF83061C5F9D137634AE2E2B794B058DBA79E95B6EBCB3537C71469A62DA13392079160472782A34771045CA49B69695DFB17AB25BD306ED094ABF6F2A492C3CB2343DF3CC6CC5E796C012698F40208C2B8C4215A0D48551AEF591C1F688EF21751E2774C46F4B91FA45136DE40119E4AF0E2672EB36C66C89F180E78FD5A06999084DF31BDD0D57D199E2A421FE50954C63D968E27F3DCC0776741B8D6E835547E9E8B4809CB98CC781B4C5A5CB9B711EE31134CDE18739AAE35B2BE6812FC92F7EBF5041C236A89B803213BB76CA7B68F4D233E797A9CFF73446E1F67AABCA545E219E8767B37AB1AA31049740DF2F045A9F20084D300E3C40881E3C81AAF30328D51774114C73150DEDA32FCB4005065CDFD7AA31190B2A72EF3CDF9581EC725A90B7DEFAF32AD527F5DAB8C7A271BDB3DA3457A0ED35B43143AD82423D280C422A091F1883034D13A5DF87046FC7DC87F830D6933B73E0544352CE6CDE981737C3B61542BC240E2CDDB028AC219543C57401A81EFE0358E08BBF6D9CD5981AEBAA54DFD3695C351CD702071595F91FF2A1A6FD7660949DCED824C3F4942A8693D76592B15887BD4473B045AD4D0015BB3A581F96D7F515253451BAF6242EFA6EA3829CB0F02B18206D133134743B9D1805993A6F194DA42E225AC0793C16DF80DE043C49F5CDD9635996181DB76F3404F25B3B9E2E22316C9287ABDD2C743B04CFC8F7269D94F3B8E0DE177F8DB80F7FEA0B411078AC7D351E62B0CEA3DFFB54711166F9CE6512FD2600272B583F305289F6722280933E95208AB513129B1107A5B511A18DF542FCBC85772E6747FE11D79B722877D45175DD56A9C2293C8E1FD1B3334F59C0E0571049B2847CC3E02EE2C98CCD1555420E5E38D506DF3D08F70CCF82A022124CBA797792528139E1FBA1D325681D1EC8A28184DC3C157E89757196CA201E1A61BF1CC1EB7B6DA3AA89F7383F1ABD8DA13696F4983C4EEB5BD770CA906C7D1BCD580FDCD4D71E183A060F83F1F0AE26E7852B8A588159D8FD14E6854E251478AE68E0D1DBB46BC339D2AA6270CF76DA98D076297B4E944491770E361888556264C0D7755300C3D7B4C6BE590C719C1B71764B9C59B19949D2527C0E780249ECE82535C306008E4AAF3049C0150E160170DC0433CB0CC9432C8D6AF52FD0532B69748BDFCA5CC696D9854143DE930A0349E314DD194A7853AF2CD58E60462427F3F221857C482528174D3794B038ACB955EC0764FE3CB927FEC2E9BF998C270EC67712EA495C2BF57B0730FD21F0C2344C1652BC172A7B6C140F0DCF5AB0D13A13319F294200A389F9613B28BE59C34A7007A23E13837CCCC83859A518A852ACAE33D2309D2329CDC5CBCEF8406D218163A1CBDBECD57E72DB4B5B39CC0462F518A532DD3BD285F460257349F27A7D32B7CDAB21A7ADEA77DDE09723CFD6B1B06DEEB4F4B024EE7C5E88161EB8ED92D77E25D023B095128E31DF97F4A2A8F0F31254BA9BB75EF76D8CCBCA40C05EC6A1C38C6882F0F394E6A69ECA05EB9531B268F3289AE54CD1F5A35875A0D6E183FB496A8239954431515205F83194B8CA05C2637E6AA2F15182E2CA29F17500A9FA10EA5AA25A325C681C2CC33B28909D8FC6ACFCAA3DB76A8E41FCC4F0C882EE881F2547CFF1EA710EB35395C0A6A4A347EB260A29AAA389323CC8DF5B58C211B703FD630DC60596B9031001913F7E00C088BFA95D47B39CA825E92888B973AE26375952245227CFA8B29D367AF69AB7B0669314420EE791D9452ECFE248ABFB0BCD54DAAE50B5652689229D9F9A781EDDEF8BBCDFE3ABD69D67DBDE80F71153F291925CAACDC393C9F0A7B4C9E5E670F87FACB5E374074CE36B10CD369C407F0B63986B163AC9E32DC2F4B3A52EE1C56AA7810A2A8CEDBA50560436C35E71D219FC7D1BEA2E84A38B3BF56E3715C9D52933C60ED354D35EF3DD9FD6061B6EAD24387F41073C3349816B11F91DF7E5CCCBD5E92A9F88B587EAC22E3D2CA4855F4C641BC4DD24E31AB72AE73FDB5C5862A180ED944F70CFB0D61E5499F744B7BF048E940CB63D5DEA8E4989E867DD20D4DCC51B9C5D66A65C0C4EA5189E4C7A79CBB9E204E0AB20C98EC64D3CFC14AC0F9F5F8923BA96F1A48950DA177DE445734979E0F1BB56FDD85E75D366A132E5F6F8DC76382E9F789A26BD5976FBB6F3475D0B351FA90E00ED93DF7D55B6BFC8756E249BCB6255F376DFCCBDCFB5087EB92187A6976F78436AFE3590DB5215E20E2885A218CBAE7287E2A80F60F84E11099B4F618F8F2DDBA0D69AE5B8E360CC298F01E8423275376CD4C89B5D3D554C0DCE46F18ECE07711877BBF44837DA0CDD0978C817807CABC0CA545BBC011282D7B81F56CEA0584846BA885A64F701C5F1325CF969BFE0589AE42FFC18EA6007D480D0A70D08DDB96E366F0D838DF065EEFCD3A9CA7DC36CDF52BE150D478B2A28BCCA9E41707CA5E720A4012DEF416D350EB470FC3A9F0082ECFBBC8083B2D3068293ABB38A5634CE65047A3986BD754EC96C31ADB6C4359538DF0CDF6F82C4BF0A8EA02658F6CB89509D48FE2383A0A82C091221D14D19ED233E539C17FDD6C77409F0FD0A2973368345E3895A7A541A5054D794BC27124973D07D718545EDA8936FB07D9C2B8605C1846A3E97451109DECBC4242CF2B8CE70252C6503C5AA5FDCE912CBF728847B4E4C500CFEDE000B95C98CA02B5C229631EC2C0F1A72B1EFFFF28DAC3DB060B6E028A51CE8953BBCC926208E454BB76F26F87025B41EF8F00B135AA9FEFF1C0BC50EEDFE8C1DC645538D3431B76EC64C649E198F7679D5FBBD5E14648D0CAE5A3E75D2967BC0F9C57EDBA3FA8D79CEA4521B9D1EAC0034ECDAF1571E352BEB68B2273FC74E0CD6EB320F17A3BDC77425BCF41CDF17644E9DEA08AEFCB5E2AB9803799FCF92FCA4BC21AF5ACBF3FBBC1F73B184BE00CB6551DC4A79F5F688B02F2D56159E2E8C31915FD0F69ED87D3BF1399B877BE8E276E8992D327B45231EE99A18121A918A7B561A91B9786AA858FDB29C4E02D522BEB09B59F07BC812F3FE4C9078E2CD7CB81A51041E30B42FE1C93E283B4EC8F7B51FC8E64CB4DBB014C4737466B592C3770653DD799841401D4400054D7E9B97418B1F15F6C8F225FDAACC6DC1C101F7DC1E0AED4ADEF4DD96D456129A3483B6D846C9637153DBEAD0180C7D463F8654C2D75523A6D3D0D450ACAC7EE80BFB32AD0FF901E4763F87A9AC926A06A34FD2085026E56EEC05E8E31392C99A4C5EE2505FF14E54A832D061507A8FCC80172ED58C9AE75F19A282C05C4F100721024ACAA2B43002866390C1E97DDF1A72A87882DBB1BAADF35E41C8E98F62DD1E33D96352AB17D906A4EE1B885CB9D47F9B7A24C7CD88E1B5084F9C301BEBCB068051D77E2D1E0E3A07639472874E6F260156A0F17417310F08B418CC6E7AF47B1825D3C045293B57FD696EE5485995C00E0F9D87F34FA2A140F165B3A49084863F4E2515CC0222974FB7E3486E7DF3E362E7CAB2F3EC67ACA16C94CAF6A6EDC9C17A2836F60442061FF0E8F1C8D6E505421E50E785958A4D78931691E79315CEA72D2E9C31480C40E02BA76385BB78D8AFC875EA8AFD516E7BC75A58B01636D6994369738542B19CBBF463F2E38A6F3551F2B93697425161D993F61CA2D55BF45B6BEF9905FF1DC1A45CCA04C96721CFB50C04FCC23DA2B7A4D746FAE8B946846058B977A86E132546A2C19AC1C97A690808766997E000F21DB294338CDA9D47DA1A971E03D534D9FC9C133F42C9543EB80207245FA525696D7CAC223BD21B4A3686F8010A9CC52847EB5E9229115BCC29B2F8FFCAAA4A1B7A7192A84F969258F8E96D27DFA9315629A704E328DF9706046AE3D438462382E2BE6F518A122ED8492342ACC67682239FC3530858BA34F19E6BB7C115ACB3FA69A17C0A9A9240719C33F1AE7290A9165D5376B209FF0D2D242A83587553D7EEBAC9024FCEF413D924A2F48F0A37873753898C8AE75E3A95EDDED0E05A3EACE648CDFD5396D71FA80204BA96708564B147CB0A7703AE1C73A7DD762F263D6929989FA361343EDC28AD1160781ADD18D2F5A7628CD8F44D1A03319B9783E848CA98A5A9172377DFFC5FA037D16797648630D3EEBD4AAD647934CAF4541C3EFDDFE4FDFB94AC1D715CE764944C36731AE1A82D0DF664CCD7AA73C84C11517024769D04AB5665CBD97F9376DD88BB902B0C567435937521A35AE658F091A45B63435EC024E3CD204F40044A181DF6E244E153D166FDA23C4632A7D504AA0A3BE31EE41CA68B1B13C5BF32EE882E48FD5632EE804EBC6872FBBF3070B1C7E085E3BF0D18951B9E5E7C54543535E36F9503CBEB5443280FC9B7D506C45FFEBE2E31A8175779B18966B67D4011D5CF5050B2448FDE0C2F80CBC5AC29D09B830B8BCB48BBBA5330FA8579528B9730EEECD7EF26EB63FD398BF68B0D5F94A4E931F56F53B2592DB3BD2843F124A7F8B4A9219159D738A6863F5D16B69CA0673464497C830DD7B994DA4852639B90F21620BE79186419ACD4C0DACC556DA01217F95AE384547838FAA33D501FED0403D9360B02BA6835AB4791C215D12091B2237EEAD29E09E22D18C4CFBE924A8E84DF4AF42F87761A6A13C1985B06A11BBD0FF68823F6B021E9A2F9E0D477544D69323187FDA32B5E522327C4AD4B86EEC551C52E0D221F3AC830A1BB0F8F13C287C91234C4ACA23A15916C2B68D55192347BEAB141D9FD38D2616EBC4482343D6AE213BA9C225F093643AC3B33E0C8FB719A30C6B8436E6C5A77E0E6171047435642FA7309EA9ECF9D41EB5658687C4563C9B1AF01685BE5EFB6B511C186331AFBFCF661975DED7A850260C0377B7774080F5BECECBB5D5AA89ABB80D197C1A6A58581F1EE03C135FB46E2F3422A9145599C600FA6ED05A55D69FAA839B40A3DAD2B316F55875699293ED546243D60A5FE589045B9DBBED98455BC85FDA4B58209CB9A8EB368F1DEAC6521C0B8CE9A5BEF7BA9197F6C39D439CAF4ADB960B8FB29D3CE1E1415872682540980BBE7D1A018268917C57B256E87718E777E13BBDB350EE25181A5EB7E4B12FFB8624D575737CF2973C99BE8A2427E063438E750F42B4444D6BB2A51827D520BB93F6862B3117D8A3A79066E90DBE5AEB6BECE99E277D78382780D066FAE50F0F4075B6F92A3B6A19B10AFF22BC9E715DEF54F752C1473532A0DE8830C4A71640DC7A2875EE4F3031C9F412F316B40281F0D49DB9FA5BB06E4BCCA9C7871274F7C9160C3735DC6E0D20A8299DD87555554EBF9C02E4EAF9DFD56E53CAE3B56E78015FEDF79748DFB46E25C11D36A3FA4A3C6ADEE43530D7F6869734FF3663A4236706C8EC71835B7A8D495AAE5F050B87473E1D4DF591B90BEF85607F5006349250534BF06261F09B4ED6337B2A0A1BB45D2E59A461197E8CAE098406E4C51F9DE8BDD041A925EF5AFB7832D3E4C816F4D13FB6E2238B387EB27E28E7DFE7343D29A717FF0A07D35CBBB375179B437740DDBC878F2459E97C2C3941CF2B051ECCDD0BDAA82BF13DB91B760F709003561B1CE1144F2B66D048ECAF510174F992BA5FAB55E79613E1A1107BAEB84FC695CBD1DF85CACC4F4B02A0DBA7F88828F385A9B3836D59CD1D317E1A1A3487BC4A27920C1136159D4E02142091D7B1DDBAFF8DC3C89577AC55AB026BA14617601BCF5602F488AF88FF88220A485BFA616E86E6D2D05B5031088313753BA6E6B3528640EADD7811E3013CF1A547AD96589824F848F1A761D13C794D21FA25443A34E61933CAEA8388FD23A48434E9F333C56979F5A0931A46C215C01532528906C3131DA314582DC6C5FF15C1B621483F6B13CD9A84E3D994462F4F168E2D589FBEDE0F0574B15E59490C75C5FD8775B86072523BE8D31790A8AC41DEC428711823A0B9BE5C11AE55B30122178D5EF7E215767D49F9457A2EBF250ECA5191B1824C88549388ECEC8D4A46174C45AE682DF4D34595E811176B567CA445BDD3E73CA57FB08639E18EFF5E5FC462D1D0F9E244B2885E348B3CB664E2EC8FEE241F0E7707A57E9F3730563E1E9A3EEEFCF84469FD7335A4AEF5FDEC67AD0C7E425AF3734D435BB7AE585BC012BA42E4775EF637F2CE2C68181254F318E36E03207B0B7E035F8E35B8B6F8E7AF352126F41836E2623E62BE2E4E89BB32D892E8AF5D8F294D149AD68AF00785AA007D030F7E1DBC9A5265624065A74DF27F1F2AEDCB756A4078F72D3A22DC0EE4CA11AF357CC1D87D2E9BCB61CD98736C9EB5902982D69934AAE3398EC705C1165710C392E3219883A1EBD1C1046103F2229B7315D1D8C3B9D00C0AB72E319C8047B1305BD64909F1B16FD5D61D7AE7FEBC81A2AC1005F1A228D87392EBBDE01D0386C338DF659D5C713CB02BF4A069B5662E203D2900CE27A15FC535B0EBB4BBC3AC19E8E9D849030DAEDA50E8061E55CB71205EDB08084C6D98E37F65913AFB294B7404A5F80D49736D01784C588DD056CAAC70D88C78AE400A490A8EC7B3AFA2AE39C83162A6A4CAB065B97FA7AD98B8038EC5982A0541C14D4465B2A941B4B6B35AE39CD3A9F2B1463A804E2F25657746DDBCC8FCEE243AAE00CD96F557DB7705E6F8D6EA56116459B161300FC75CD49BFFF6416474D684B22B16A1E5B6A13A250894DB181D51EF45839116ABB1CD3789F0013C4D73EEB2E5FB4511E45C934CD8DD61E1385DD52DB8C85AA6BB1AA1E215094D70B92631A339ABDB39320A32C8A9BF409826EC0A1AEFDB3B48416A88F1ACF3C4956D7B4E4B0729DD84E0F1D54AE1E11D794631840CB9D3884ACAACE38ECFC991EAF38D50C734E6AD46D4F12FCAA20B3C978977C7EA54583F53C7B6C95B82F94117E5698C2DB9BDDE03716833A570AAB0C73DB976D0B19299DE2CEF8725D6E4272238115B5C8BB4CBF4B0728DF47F378FDB565468CB12D25B4B005268D9FCE8667E9E54F5781BC901A92733DE9270E9135580DC91340AF15CD5CA2D2DA8B2C47504678DB66F4C457B649E0B0340B9A384BEA52243D9C492EDC58C94E0618DB84AE916E54238DE31879964F34B6409ECA022E4C90005DA3D3C65D71E76933D528A83F2A2129AC5BCF3543A1D314F93FFF3F003FF47B74D6132BA9A331F7B20BDEC7FB69326935C1C89195F11B9A2BE6F511E668323D1258AC95FAA87C069FB511201F97CB15487D3488608EADAF436A5AAAC611211CE792F343991BC736E2AF5F9F12C20148DDE4D43758888DEB4633AD5C035D2AD86E8F5A0D78F331993744933F4D9DF00688B75FE50E76155B3C1E19E1C12A23220CA82E8FB2A73E815D8CA38933BE1C5D790D175CD85318B1C2A5C30099EB94365B8E6C40FF4636E52DEEC2A1BF5ECB14D08C5794AEBC227D32470EF7B2A02EA7221A8999235AAEBC90025527AF51E96F6684C1856BA4FF3DA234E3D2711D17FE4F6AAAA25D137DAD1E8B0446F004AC3D092D3431F6254FAD1F9B22BD26EC86B9BDEC7B6996B61676E5137376072B4E1C7E7304ECF3331F20C9A3C714BB07A46C09F521A2215F7A7C4AD5FCD9E9911617EF8596D8D60BD70DC16964F972F4F4FBB83B51EAB949C5553563DD4F37FA1DADEE67F8B96B66D2BBD200745A052EA21EB7D90533ABBC7D951933D267D34C8E757BFD50EFDBC856C64B811DCD5C8DD18D7474E04E876807531E1380F6A48BC46869806C7DF9A16DCA26E595B2CA6835AB5E6383B1CAFDD11AEDB61FE7E1E57D43C0FB7779DE02DE6BB4D3B86A07B59A233EB5A339A65D7A674A084E368E38BC13C38FE3D3CD58026A16F48EC513332B49A13A09DAC34ED41FAEB88C00E855C481A422D2D95B5890CB889741B77EC1447D799EFA9492BA5F3BA6CF22B86CED01600F661222B6648D8EF522C6E6A0FB2862FDE641D325C4717B024F8C20166E24BE4C6970F914B9BE78B4481C312C226CCA82DCC6EDB367C955C590AADFB1A2520C8E6941A9B5B0AC2499FC1CE2A911C4BEBD59F99F627B69767E920B121DA2F8F2CB45E434678283A1C2A777C6DE2A2ABC6A0709480956C719D13D1202824F6F6324160FC728A2DC449E1CDE8A58A4F385F315B12C701D144FA8797F455EAA4F8C843C95E2963E26BCF590992DD0245C645A65748EA727FF189B3728E0A3A2BA21FB4D877FCEC369C0228C5964DD64F5D2C786D4EB433EC4ED484CD3FA09B6A008634CEA40A147BD51B2A7B47901F05A31C360B0286DA46AD41CC7C1C646B43AF8B77EDF78CB501FC1091D6D59470C6EED6F78EA8B905A9A3756319DFE9F2880602E3D2AF4476126968888A17844BBD8BBB001ED2B2FE8F152B71C73F2EB63B9F24FEA013E45FB711FD7617EBDDDF701236F8C0FE10AEA5C1337BFD618550B95ACEE3E563033E72B1ED80B353A2CB7854B6AE5D26CE46602826E32B5B8E6652B52939E6C75A551379AC1B43D1CDB5509C8341AE1F048C44A262D9DA8412F091DD9A0E79C00DD6FD71BBC15F9AE7B058C22757C383F1D68C1F4E9F0D2E0DDC7083DE361D3D1326976D724C797368B7BF585BEE60B8F588F443334B0231E732E45275F2CE440302C130979D38E345AAB0CC745E9318988044E973E4A884EAF9D823285B117CBAE4576FEFB884F338CAD2ED9DE77A871365D1D9E750AD6E1A5D1F5A7D7758D3ECDC69FECCD2EA0E440E4E174183586EA8BF5BCAABEE5526CDA365792466C974E8BA04646D759751A4E2D6C78728785BFBCF309A33733A077A5F6D81677067CCDC48F3F4E945434FE278BB934B6A7F1FB20881D47D058284079E5BF470E7FE947446B5D1E16CA64334C6D845B973E9DF39E5EF4F46A27B49DE00E4C92909CDC47881A05C5E61DC179F2DBDAE914D1E322976CA8F7449572EBAA7C07E520EF2E500F42B903870EA1014FEF18537935A82DD1B094124DDA01E278BF8040A9D13E4FE0C41D97CBD05396EFA37BA02123F668FA1FCED4860F74E5DC8B73B79325E1AD25A8867D9662BE2F091F2B195EECFF67BDA1E0139E26C4E923F0905BF3413B4EA76AA9F645576925A22AE7120F68F05B0A5524163BEB222FCF9691941452A122E5658FD1065EB6D53A9D6BD9936FC6F786A79F4739ED0D0FCB4A466027386A2EAAB1418B49A392CED40C7DBCA95986C7A3ACEB0110F004326FE1F8B019916B84BE7BFDED763960F710E81E3C0247AEDF2715B18A6406AE424326396A8AD20310102F0730F4F308612341B53A09FAC17923879238A3D3B0A890E416837678D4D01480C5B0D728EE70BC40D4368AEDB502B562D44C018417F3534E2526F020E15E5D18292FF08D2E26DD895F9596E198C2215BE8C8A2A8F9F4C86C9B707536139EA2060F5717AC84B4DF30DC93ADE4ADF1987D74C413E01783C5ABCFD6E5676712E0D0B26BB29E2476F7796D6EF80B5489628599758319D1C18A1E938FC8B01F172DE9BEF5416E2BFBC1407FF093BBAD58534672736B138BC7847D4B05B247CFEB527A2E1A42ED691DE25D91B2FF797B3CC43E74E1D51FEAD0BE893F264AF28C6F24435BF6AE1E564B8D2014E8C77477BBCB53239E2022268EEF8750867568DFC2DFD2D8876ECC1ACB18C18CBE5998BBBB8FF475F743818AABA1D0BFC4C7C6A0F6E7CB66F9728DB659640DB0E399FB501D76910B3AB89BE8AA13F67270F6A9BCBB909309FB70DC3EC407AF1937DEACB5069D4CA67A0EE553B0005ACDB8E0AD22E5BBB24F4E55C86660CB19D4B95EF29B959BCC2A7FC54B7EEBB8DD16FE31A35CECAA12933D482B07452F1AD4A7F0CB13DA5785A4C2FFE5F33EADC28B1FB027BAFFA2E84E142797E4A072CC748A7257B1CB057C884DEF770B53558933C0B93A026F32596800A844C19AE2D265D86F50AF2C2FC39540A32C19655E88F26972D3A62A24D6316DF8B7C6EE9586C9EAEB112BF29E94B52082CC11A8E9788753267EC3787BDFBFBF87F16D1407F13404B0175D349868601412F03669BBD2252DEF95C4435B834FFC16EBA6F4EF949568A0DE1C6013EA6978B2A6FCE09E17FDE8E4CF33BE61F14FA9F32878A160995A5FA3CB8C052492ABAC760D4BFAF47B5E0910277E6755473CB708C0D4DA8CE02C6FECA61267DC69F0AF54A6F79399E492E85437176FA2018BFE937568D166C36924795088EA7CD1FA108147FDF82A0E61C22BF618CCB78484E7272184493C8770816EAC6155585CA1B77598B6B910C872D99F591943D38D957B74867439207AB5A10BF64D76DECA3AE50CED3CCAF697E8D95CF52C61BF398E00C63D72192D0EE7105C0029AC76C32AD05150F77A51B042B4120B77E4D4779F9626539138406E616A44AEDB47800E2C23546CEF5583C0127174195099C9EE126CB627452F9EA16B6C5EBBBB31233EB283427F7CE2B7F84F6801BCAD47C1B0D4F46EB92B44E5846C5B7C3460EE3EBFBB28DF363476F08AB4F57283D26C5563CFAF01730EEE4B1EF34B94F8CB90BB1013029DEAC6F6E132C65B81BFBD95164FBFC7AFC44695E82B443565A5AF0BE322E01F87A35AE981B53659D2AABFF7872F72B21130622645401FB08C5CD53CAB0A0DE21DFA35579871480DAC90345D1E02F7E957071A320FFEB055A27CEA83B1053D27299B3F33D721DAE476D227E434287587D3ADFD5983DAC894CD7C133E0AB27FFE3044F45808D8C705CBD1620E3D7CB5B6FC0E8646A3C72007DC86A1D8AC82910B73F4AD1D4007967F5D65F795BB88B34C79C0081538C34BCC7E40E30E7F56D4A69CBD10FD9AF26C6345F00655DCD23F6B69D317994C0AD5593954655C96C9F3C22CD9D3AB3DA94E8E711DE10F3D2282AB4AD6040CBAC477BF4C598538A6FC81A01C14383515115C4FBD5020D5F1228E2384EAAC746358ABE7B0C3B7106AE9504C3B6ABEBCABD79707E41C0204115D00EB80016BF8DE55DEB4E1A43B4B869552DBE36A0C73E41515B8FD87331B582E9D8C9A28F7F1AE49C2DEDB08141F5F7F6ECECC5AC28C5828E5543F8176FC2317EC5F822A8A2F3742EC7034C804AB41F445E654594C7AA6EAA520F1BD5EEE6809C2A1D60BAFC6997699F218E99A8E583C0C28B48EA303A72FDDA79FE9D1082274395E31EF118B6E3CB64E7E59A48120648D6D3E5EDB3923301B2E98B8980982BC2EE38B733D0F44E88ABC22F469AA06EF195CA170216F1901E7825FC708556829C46F5AA2272AD88C755FADB9822D750EE4A9F28C0C481FED560222DF0B8ECF0F2F472E338FDA1F9BFEC25733C9BCF8D4E6D18F886E796CDCF0A68C135708CBD4022516C79582FCDF4AE096E965B7CFF886ADCD739543BB501B27F0B92221CE72B2617C82AF62F46D58B1018B1F7AB2B06D89FC821EFCD3867BE0F15E90EFB2C016698B4F91E558978DCCC233A70E4B341CC9776570C3DCBDEC3B90A42C01096DC05E7AC230753F0462A0CF34D2B1DEEA89237744959EE6AF3C4A3898EF153BED4C3CF7C5BF7C0E0CEE9652CE3B7A0693E11586AE28ED6D0F375A318FA919C023EDBA583E49974B2B57D81857B43B423C31F1467D0CC1B6438C6EDC251B3A6E148A92C9E08C1B263D66878F42755F447CABC15CFB74E6BAFBC53AB650F8006ED540E91C63F2109224D2BF365FEF30D4623C9C9EB80117D5434C0A9077EBCDB8EB729CD7D98E58982CB151DEE96B0E122310E922FD54708367DD6AA8110DCC17CAC9CBCF30B781D61E2D9A1A367AA71A0B6DB0AD065049A9729AD2C0D351BB7394AF9C23F8E59BA14D9564DA786722E05CBB7723F697C5540196CEB07EB59593D9DA54F7E8221C70C9E98A02F74898F1F17E648B6CB415E7BDCDB2F74D3CCC8E05477A66FB65444B479DF3A9A949D854A6B530D6D5555D3B0DF29FEBC34C7778A9871C397DD24026502B0F936B1FFC80026440C4F9715BF761F8C661DD06097E55A411B9783F2F5C332AA7E756A095AE139C5D56EF634B2809632780F584A9CCCDC67590402B9B6F1CD219284F896208A66D92164A08482FF8DBD4D2882E63108707A08D3C090B5E30655B69A253C2A9EC81553EB2FB11A813C1B101AB6FB5D82A95AFC587A2C9651DA8353803FBFDF043EC86C0338D0217C46DB2552B196794171A266E8FAA003D6B8088A2E0AA69D12AA1C28E80E140BD5B73D4A1A7CE534DDF79B35D6870F6227DEB2E2EF72B869FF7D6C898DBBD92221A253A90CFF8F0247C03626E2AEF0CD4EC1E511B054C06DD172A5DA32E241BBBB73D13593B83F4E7F3900A8144F9C79A7A98F1483DE501305CAED2C7321D58FDDDC077ABE644B5676BB12F0FB24BED16AFB0DF7D930D83740C2AA10C36BD2AE04234BD9E46029930228975B0D07FED6535F1955FC5AF3C8203589D32C4E104AA98243E4B0A4681958ACF4F7FF0842AD56D978E19BDC37D46E74C2125B719452DE664C53B1DE7D516676AAFCE821FBB9050ECBDC4325FA1B78EB5CF0046B5945474E5720605E233BBE51B8A5B627630E0A9D6B0EF20B16015164A69B1D826DFFE85E48DDB74BFE910297BA5B9B685ECD88FDFA480A30BA70E1F20A676457DDD26B7E553CEBD01D96E8C518C50D000D3B11DF188D48A9CB9BAE44FA5DFD1F80A77AAB8862EC8E04C34D2D2F4D39A174B9262D236FFDB6A89F083AAEDB82B1746868B77F7B5A4150511F0F7D5755210D3C3DDB32DDA892456EAC5F6F86D5008FD20C46400CF78F5B1176842DEBB1BD5515C6E141ABE519FCB6D29FF244D305AC68A742F01BC078443FC87B8DF698938B093A94F79A670234C14097DCE86ED1B7056F87DF009ADCFB453CEF7AB1F5E74C0664A8CBDCEF1D6DDD674D5CABAD29C39A766BB4C620F35F5002BD461C6DAE74C67DFBB7FEC001F7F82DE3531C856D791442F2E0569E36A5D92FD9869F6F0A085B89D37709C61863108172FC7E22ABFD21491E0F5A384CB8DD0B97496BBE7F1E6ED9A08B511A1912A33D243CFEF1E2AF2349226BEC5A8AABB18292D350F5214BC770B9B1E81F1277DD54AFCFEAB009AE5BA5AF31D18FB5F5E1AF43D4D93B06B9C129DE0579568E82B0E9022B8638C7804761D8218A8F3B79B0DBACA60E24BB6EEA8C75A4683236A88FC6EF5D9AA57FD0F76690BB9F8636F96298ECBE43B9B086B3BF8CEEDCE2D5A34A4C5B9B40975C0181A738EB67E6F2E15C3FE937C9F29A17FC96CBDF8E45F0156DD97350B1D4C36FDBF751E375CD456F14E9E46532CD017BD7D15E6C6B6F58D4355EF93633E174A40D3854A9412FA608218448094EC7BE8D8C524D821821960F2894BB8CD36B2111FB5B2F660F44A48D439C4BCD4A01FCA4E5B6DEE45EBF043D9D0622CEBEDFCC6BEBBE186045099F558E51E966EC11FA2178E1DDBE46D54CC04D1AA0EA7283C63FDF4923A6CFEC115490F6B20E7CC56D7C9A5FEDDAD11E808B8711711006CD1A137C2B379C5CF677645024BE99BE5CAB4AD414F46D027986A0416CEC28BD2D40024E5C16C2F96E35EA089D2844E483FD7FFDBB15EEC3179870765CE73FBF8D801B4B9D3E6EBAC9B9723796691BAFCA62A95F0C391A1173C7F6F97CC33F7421952CAC970A81627D84246E03D376FDF666A19574ED9E2091A8B9ADA0DC02ECEBC68BB2E4A8161B5A73E690A07E26EF54548D7E78998F4E03BA5E728540FE19D01C3A8F324F08292EC316C0623421E8BAF3CD0708B5F2835303B2D07F9083B2298D12DF61F814526353E4133C45BA09889E9F316B1EB490607B1F957DFEEFE54E84E6B5407CF136F23B1ECDD2A5FEBB40E2232158556920E120C17849E912A6326AE385AE765D6E5CB191A4FF0D6BBD9FCA198C048302FC2CDB8A26FDF548F59ED54FB28307603B9A13AFD41A7A7E2DE754E915FD2778F420ED071EEFC48CE27CA2F4A198F96C15AAF1A1817887715055356E2FE8D6265DB32D20BD12F83DFB1B147BB04C3BAED98E83136C14EA64A437F06EFA82F29DE9A2B3F51E7989B17F122B9412AFB1E7A0BC8709A44BF2CD02D03572194AB2DB9F89193F75C2B8DCA8FB9371575D967F6157E03EA1BDC0F8B77F12169DFD80D49DDAC27A45B16E16408B05ABF97534A15B3ED61F7EF4F1335AC771AD2688415B705E04D3A8335CC4DA2EB4877894C549837825FF69F9A02ECD4E3D2AD15A04755A16B01A7677B82F9C74B6950D51CF14163B7F0ED98F229919DCFA42A59C1D930AD59511B0D6892DD05D94808420E9DFF99F00190C9A0A0917D7DACD352EC34ACBE891674AD06332CD6930086132B5C2A2E68C546B079E810B55C05D7969BE65D97A18A11CC438CF655B60C7F65FF3806F4794219E66EA2227C72ECA1A73ADB823F68E855C8B1D990CE1AD989A47E6F119EB6E07198A9B57CFDBE47E37E79F657F5CF73BC39FC2FC5C8996DA2528BF579B882E637D37FB1E3E88E87039EC3B3117637E691264A628939AB32476A24CF23EC1171E1504CE04351F1F8A74EC2617F8F668D62637EDB8637678F50E0D40F707906B979B07979371A9BEE717DE98835EC413CD2AFE22B05D548D84290F12628AE51CA9E03901C0696937BADC32DCF06559648F29ADF3CA0A76171B64ABB3A5B52160F621FB9E03146F6FB931B83E16CDAD21CFB256AFDC0B77ACDC0EBBB14979FEEB3FDC9A62C0C998F988094E9481FA968FEC2403BB85074253EDAD2C24E7C40C5E3617B3B0E480BEF5CC2F0C542AC57FA660B5CEB83754E83689E5D8774446D4A2C9370AB716CD7D0A1D6EAD35261DEF5FFE50565DB183465FB571FE4DB998DC8A9858D71ECFDAE54FD7D510C601F9F3012394250EC252EBDCA657A8599EE8D714B97A36466C19B5575F8F22C39B72994D2FDCE2BE48481A93972AF0301A3B737D2C86E3124F05F39A76B065674427A1B168F902FF9BDE19CDFCEE957244A7CA7F09732FABFF4E9A6D511895769A282061EE64EE39BBBD624B819C463758E0E941A3F7E9A172E00D3AD53B0489FC2DB84CB0BB29DD866C43B70CDC4027AA93CDF5A94B090FFBCF27D10E7DA3997AC4F1E86A67A6AB59D4E23193EB6DB3D06D47F78FF2C80BD4B06A5C910B90F21C5B3C0507F8C17D3D4AE7619D0E3485B3A6B3536AB3790CCD842E0E248D55A53D14E8D2AB91129CEDC7DA859FD02ED919CF79F23FFC078208FA234AA634FCB7300E58E3503FBAA21ED9D6E7CBC12A0B9DA390E44E7036355521B369A935FB6A3561170CEAEC879EC97C7B4ADE71776134F952BB64B60D45370364F67CFF693C142C9275AFB89816ACC3923B846594467031DD12876A6CC6622343B422EDAFCF905AC6CA2CCF648A9ED401C3830854A4E1C299D89D27AF51E3E7EDB28FF9FE25003442C459385ED67C4B5BA468189A42BDC6F999613EEC8F8224E4803A6CBD2DA308B88BF8878EE8AC8DBF76286A5DD78009D8BD15E4D88A7D6A081A9CE90142308768B230BFAFC02051BDC90AD6F075B04544947DE044733EF5EEBC3F8B1488157346550A7610B17AA1631E5FCC070EB6EC196230EE79F54F1A2BFD6F5622E611125E43CB36C713842D897BCD93EF1584349F728EC7732B188B93F02D178F620351D3C10F340CF648FACA0396CD06608C24CE87E39A35CFB27850001EB95268F540491E2F6A15A86D5BB72EC86B625BB4A39E75961BB08C288BFF0135A9B31111B3AD3F4690B7CF06D76512720C25F62AFF2BACCAC0CAEADF2F0042B2E149D8F7CCEA3B51072316D681ED1F05F437B530E6DF7FD0A2A3B664BC3D6A7BDFF8AA8DEC1891AAED55ACFB47148D8B992C2F9D644753AE7A1705557DDD9B4F0E51AE064A553783312E82406AE0184AD83834C2AE382BF6FCF4FE2EA558C3965CF6EF6DC8706BA627791B8FD43D84231C595E67B431B625A6FFA8679D5107A88E4439E74F8FBE024FE20456CCF2B18171C9789B5903288542100E4B699FBAC6BD00B750A91E4A7D44A14295DAB2FB67B55290FFE998CF943C851369406EB0A7003BCE1E8FE840D33BB54CEC5031DEFB8B9A6FAE0E5B71C8E263622CDE81029C3DBC1203960BA51D270ADCC575412298BC85A8A20BF2EC7C1FF4B8E9B1C014305FA0BEF5371CBF1B3AD7EA804FB83AC8F78930FAB8E07E2AA2FF20B8405AE4106873F1DACB1C6C26B8CE2370FE20D065E309D225597AD6B2E85012FA4537AE8380A55AAF5D4DCAF59E621385CD997AB2B04797D47CD2A8C6105AA0FFF9B50F6060971CECD9E081244ED35543CE95221ADA29CB424859CA71D1E2E056A96C8827386886C7C5057FEEAF1A8865F016AFB6CE66F8D29B26E34C10981A3572F06E8741EDF20DE2677ED6D7B1FE199DF693D090A06B4866F05D276D8BF454609DEE9E4C48975174548FA0E1853B93202DF912644ACFCB7924193EF8FB8807154629220F264269652A347EC9ACADDEF0DBA78948EF0F7896098331692611B81FB63DD79780A3140D60EAA23515D2359DBC4BD1B7B728183C49F28BA144B0F6D01C82E03F7B3A040F0B85B210CC1352D2C3C58ABD12AAD610A0C26E81BA2E1D7030BE72EE64EE140CC34149032DAAF57CC5A476B567CDE48032602B3D6759E56DCC504F612E8D1BEBE9FE7000B61896668503A2E7B2076C470BC549F92AEA06F8F65F9A7798A99D7658348D3032E9101C8E900845C43F855AC05063B5253BE037A63C2EE76B756162E113A903CD475D1DB149BDC533C653196C5566AB1ADAB259A5D0D22C4B39853F9DB270D69C93110E4324D4E93EC8F58332887AA351CFBFDF954503225D5CBFF4A65ACFDBA34BE720B15112ABFFAF12807DDF84EB655C8CEBEB13D3375D3ED4999F56F576F00D89D3434ACE8897F36D8E78A8B019FBAE22952BCE6DBB3EBE755F492769D3B2672506E981A4DC72C94C8E137C261EC34C7EF19DC551BD7D8B8F540B2188E6F1A1EA4094BF7340D67CFABFA810C6F8D2203E3765C068C7C31247C70B3AF3590B8DEBCD86B2C9DDD5A6200C92A37267037AB31118F518432D4D071955E680A3ED49234312B5DF396F9802DA1A1B8349C95F969BC9AF610229E9D15DF28E2C431F9B5DF30EC743F0A563097F1490D0DADFB8028582151B39A1F488DEBE9A490976B3A02FA1BB3D86202597E36368EA10DFF6A0370B4950B675869C61E947E514B0173CA050CC90D4E52AED9E47B77A19B7D88A661FE8FA8985E5FC1548CD542F8ECDBD858E804E5BB95239C8AC750F09EC6800F97706A841861BBC05A5816D2E47D2F52E0DA4BBBC479FCA1C64085C1B7EEDFB0D0196097C3A696454B6DAAE1192FC434BEEA8792C28C9B654772994C3369B8E7FB100A8296F68E9B0FF0B1F12C688D21F3633C09F04742AD4D6BDDEF65E8FCD7331D27B1F883A5410C5AC633F0643EFBEB025C19035AA7C3249DA81F7543731FCF47772FD04819CE601F10E9C27A9C1DE7E3968E04C70E7D5F4B7122A91A6588EBC9AFF49A74DBFAEE4CFB6B0658CFD8E0B9221F44CB5D4B21FD7E9B6C62F04977EEF856C2F4C4DD606C276C718770417DAA7D4B4F9AD6478EFDFF177327899D30D53EFE7BA0392191E9032174FEB694A424562A943E29C0754D33835C38617C53DE6E0F8D6026187E085BFC06EA236FE5C4502E4EC133027092EA06CA5DA63A64F244BB2617DEE3CAF1C1FDCB61E6E409F32305A38F5FAAC0A20352ED822C86D09D7F39110D662B937768DDA2A90B5DE39ABDA8DD10AE0978777F495B9824AEA21C0322996EED5090CF67A66263D48B1AF3D804E3BE0D963712670081E3AE5306153B93074581BEEED04A1FA360F75E850288579A9E372D81E2DDE8B7962F40FC97D9DC1D7E4A267ED4D2AD9B7E3231EFC28060DB90CBDF0BBEBE46827BCEE9905724D468E64E4478152153C408AC4BEA434AB5934C6A07267D47B9BA88C7BCA485B18AAC8E85E6C979ECDE1976AA67DE578406EAB3B5E721A68ABFBCB2CFAED660E719C559ED45137047295BD5FC0792F7EE4D0F51A45440B0C47BA7C1F3F4B6945B431E761343F826715C7198F4CA514C1537AB48D61972EA531D9D65B6A7F4DDF0F83A6D01751F8D13193907C82E7F2A61A3F2D46EE665B2942D39FA93A46166EC2F327E8F335C1AB0A7127DB2F62580816F022ECD48AD37D34020B44DD74B3E0F89039304FCBAD59A51E8015916DB56E6E970FA7226483AFFF9308A47D2969381C363ED6579C028BC89257AA19860DC14B7452F8C2A0C95EA37D052F00FECAEAF210159D4F54C5505540B38E9D6C2A3E99C1BC77B5CCB2C27317F5083DF9A010AA73760017F909B9A1C124C5017F55BCA30A787C629194D3B1F8DA7516BBBA7BD3A8ACEA6E121E78C57603315FF4251294DD356876E457B65B921F21AD58CEA6313C4AB3DFD4E50EBC6FAC7C5D01B4603DC4FEFB5389DB92A91A326B8DAD2A00BEAD397BC44594C7E749F9A13CB34DF805097FC4B3E494CE3E98C3E88EB2980776D6229F86B5579BA56CA62918705F086A705FCE6F50AB5823C26B5881654A174EB64D6816AD9FEBACBD3D5CBD0311B51FDAB1C432FB55C69A8BFF0A28AC419268BAE812FB216A16E3C1070452652EFE101A980FEC0600C767543171D8BB5A0C57BE1A022293A8F9EEE5CCA45D9F6B607B04FB72F408DB1771F8452737CC552A6EDB3244E1E1A210511A0F6326A7E3B91C1E1676C523AE78957B83FBCA3A5C99DD3B2ADD7F1BEA562D98787A32798BCE04851B112052173653B25202825DB5E45DBCAE61B9D2127EA14F47F83328E65A30CD73252597F1C802B9C246AA1B949364F69AAECE4FE399AA02DD97925724DD049C73B977DE1B0858E4C8C702D8BBDF9DB2364E856B9C6114B25C9FAD3582F0CCAD92C6D650CBC032DF3FB4C210A105128F53BB1C92F3E248BEF5BA2AA26DE907A5FC47F6B7303DEE805295179C24CBBBCDBCDF107DC626E0130113D15637F529C7302CB9CA679C105F45CACF8C7C289E49EC2ECCED1A26D3495105A91EB7A3241625724B5A82339EA2682A15978EC75F4800FD03331EABD4B561D2BD957DBB37A42C6CF44AC2AE033FB61CF9FF207181B51276B0A65AA394A8AF53B8D6814F94BB1E67A37C0EAABAA3D57A010F8F0A2AE9AC90946EB3FD9AA1B5DBD45B1653F0DF1412A9383147CB8C90497ABE52E5AC65161B38E52FED20E15D79E15811F60055E3B3C6EE7BBF80542346146B79EDE28B80310940A426EC3E5D57AB0E5EF25EE9975469112FD56126D02BC047ED81AC1DBB08ADF206FE9792CC575ED9EDF9102B0BEBBD63391C9DCAE2E522AB20E13CFED55ABE06C5B9865FD3BBBD63173D26A3CBE48DA16399525B2C028BEBEC88745A56A30B5795CFD69AD5B3E1385C87847C53BE7D8B09FFB21D57ECEBA5D1865B34ADA3523D6D1C39CE3BEDA8D81208EB4AF4DC137FBE78A330C31F4F89E04F47F424490AA7A6180DB6B1B6BD8224803CA28B7E331FA3978073E20FF1F5D8F826595EFE1C5C40783491AA0181EA41709C47B30553E57571A132629E04C9AD4EE698CD45B9DD9A42747CC3E80800B3F01539FE7133E600266B53E52B82E9048251ED5A047F71FFB72B04F7AB29773DFBEC3695222B5CE8B89F901267508089C485E6DD714FCCB82EA2A9305A6698C940C9D2D1A2E53A0919366E013D14706DBFFFC4C0C1AB0BAA9F7983686F7709CDE9728BF899B9DCD4F0986354090F04BA5F1EB45975C0648D048952C71B471D396275A99AD4521E77C25669EC73C4C031E9737729416D5C2F8D13D9F7886D15921F67DCB652A3428B9B816D95F9F3FCAD65B02795D63CFADC663BAF979B8305B7AD3D655626ED8E81678B817910768297698E94234E6A9AC2B7851E55B2EE917D9492AED13D4580EC24D073861E003E38919108245C53B9AE3AD31F71A6F027038714F1FA1F4E4FC70492FED2EBE3B1C49FCE3297C8C86CAF5CDDDEE506467E6B36D2433A62CF2EBD88E5571F4114EE655AF7096CDD885A0CB70E5599FF852B3A3FACCC85C2CF27C30A97544562C8674C0C8DD5D44060913DD9465F8899A0178C29F7B1B07046FBB338BE9CEEB8B97D14D97AF6EC211CE04815AF04F9964807F2F0665A96E4A628DBB076ACCF8C32BEE3A353FDFC79929C86E03A8ECBFFCED7C3E5BE4107A1933EB542C782177BDB04F2985752B054ACE9BE1114D9F996475383BABDAAED90E9B24839C97BDFAB5658B9E9C00A772298CB4BADB723BC2CB73FBC4518B0D9799CCD26DE8E0A70086128A76FD7E3DA06B56E35FC5C3B2399A16C49808D2881110FC4ADFCCBFCE3331F780C45B8D5A7F94524FCB6C214EB283033C016F2DB9CC3C15C1D067AE17D9458F032D542646284E707273742115CC610AC131BE5AA21D80C171A2ABFF27BF484FE2F9AC31AB188EF03509A8319B46D62C5E4C4048B3451B4B6D9BC09AE89B94024FD42213BCAECDBAD42AC4B07A5BD0677843685451CFD582797F68CB63746C5D85B90117D35C7B3C9FEEBBBB678B9884A9774CFE8D8E538815DF6700E701118CF6107B7D68584C5422367CDFE8FA97FA95DA24C8AE2905F5E1FBC5DB62F88D7BB266260B859A086EF802E9A0846EEC0A52363E7D5A6565A75A765300120FABD216B0EF758FCE01E438224FFBE7CBA76D57F327A3E0D45122270A81BD2C6AA3BE530F9C4E374F134D29444EFB076EF53F11F3DAB33EFB0F0F05C03DF46AA017278C713DA694E2A47F996EAC915649A84FCCFD07F2EBEBD947AA731A46B4F1BBE869007A5311E361EFA1838A53DF473A916B90E9E2642156ACC2034ACE2D17DADC66D66758315AA90CAB8B69A749EA408EE9F544F5811CCECC371B2B8AA28430D516B80C407962829FF24F0CE6A45F8462B41FF880D492AF8A2EEEA5BDDEC8DBBA86875563149E0B0451D067022C30D6FCBF14D4B28E33D4A749B31DE6E5D003F118954B3EA9986EE2522E52D2EB8524F3C8719296C43469A1940ED2D8BA99D740A80871615E6D50F302B4A04339A9EC36D67EB645C82DB4BDABB37EA4B3B1204C516A96EC4FA5928ADD9E81C4CFE1675A7A6ED03D1EF774FF55EEEC54865E172BE2B89538E87CD9EDA4BCCD26717E7CE0AAF285438E6F44F8A4C63DAAE241610E03BBB711531E15204648A4DBE902B904D84044B023D84F61933143F2EF1EA1CFF3AA84BC5E46E0FF8CB1A5F7354FE6FC45011C3209CEF305245710953D32E78A87DE9773014E2A5A9795DEC18081068CA6C79B2A661E401F1F22C4FF394984F5C8044B6775D3763F58422819A9D467B72D0D54A431D73D678F431D7B62FE854BEB39802AE7170769D76F24598D88691210EDCAA0205AB7919905A48FD84292B9CFB34B8457A4CD4A28192BC8B8C282D9F860D218CCE7FEFE0F0FC9E92DF31871CCED383595144F8B2C62BDF3D9AEBAC083857EDBED50DD6AA0CBC4DAB89B938D13C024F7201866B4C4F5486ACECFD01D6550BCA9B9A9567D9B454F18D9F6A07A11D8AC8D036DCB7DB55617124D7307E4DCDC62F166C8D775AC156380CB2D693A39C0C7EB875E3B7B7A4E7D771C586B56D6E77D7317891364FEF9BCB2A0A1F7E2D98DAC242D90C878A916ADC1B13C1232A7A36296B5DE94FDDA968048705CDDC05FC968B7374C6FA0DB3F18CF2027EDBE8A1E19723BF99A1D4D43E1300DC47DA86F2ADB58F9409C9407C8D68D2AADCA037A920BFC4444A5B4CE463B43AB13F0CC0E25FE49CD370CFD735EF496B45332E2B5529853E7608BC68EE9427C2189B92DC65CFEC027A313AD65A43082F466E6D5F6D407FBD7E62245D8965D2726608E0B322CE73594CB59B61FFB5FD3C1C2724C032F3F15718278AADE681BE0AF6463C9B9DF685AA8A4594A4EA78929B074057FE4A8191E1F9F41AAABC716116B3B9AEC35FE690DBDF8081AB351369EB03E1527CF40CAC7CB0000B9FA833775DF441AF2E936C2456393A40FB970D4EF81CB014F7118D81807C6F5A6CBF3CEBA29A67D22312D2C0B54A59CB4C21AEA9F4E88DFFC28EAF5F48433D0BD23822897160E86D5C7DBD0232E4199714DC86E7E6CB37076F921093E5CDC84C3FB761FD62DEC946C71E74D654F66AD998FBF5D9F0854677E9E1809FCF5C58B9A41BCB71B56C11207F9C0898FB3DE8FF47458BE013CCD8C5D192F16AF71DBC58223B29BE26AB6D3D1E497A77D0A3202E6AB99725F5AC3CBFC9512F5CA832292430C42C625A71F6A23AEDDC045027C0D0BFCB1F14801A0F6066B0305F66ADBEB6022BAA28D03D83EC2C023A224E9888F51B0A02239CAB2B60AF5B2C4C4255F7C2191F0E9DCADC8E0D2143B52CDE09D96B741524690CF42C8E3044463C70D2CFB3D6332964FD790163B998CF9A4F6ED11BD1ADA2705CB7091AF9B359B75D18FDDBC9E09170ADAE7CFD9C4150CC70033862CD8D5A6F97A142B13BA37B633FCA6A534CB91852DA22D1C4A2964512869364BF8B431126AFEC51E3619718B06FCB308320AF76A3D90479F050313E13F4D48BD1F6BBFB6DE844DA5AD42E7738FCA9EC4AD8D9DE63595EB63E8D224392722C75B1F42A023D04FA75F59CB30FFA88F2D81ED0A59E02E1C153549CB58771DA6BAEEE5729D46C5A9F2CDEF3EC6507D55E8AFE4D3478928808B3E01AAFEF04DF3C4F6112A3B4902D2A127BE8254C423045138333891789D9218383C017E8C1C88D7B7B4C774A267DE11B4C7B5400CB42D753629F7A1B74B7C33BDAEE5425265B0A49F60F8432AC038CB5A7539CC907CB5080695934A69ECC20C41FDA2089B6EC73037221D666ACCCE38C1B7C58CDC267F5AF1CB0E56D65DD4B019FAD5255B2E50FDF7FADB37C1D63E951B20A430530C95F48268707F57E632ECFB2646D1FDBD13BB4FD32B4192593829F42954D52DF775EE931AFBB4FF8D5D18A3EE0ADC0EBCDE0473A4BF25E23134F6E3EF9A4EF7CB25E8F2262910265E94572943B247E44AFE113236E71A7D15C94A0ED7D5E5291B6E48CCF91779AEDCAF8325D23C0057E3C4B81E5213F21433207CEC6DB2E189CBA80A08400E23DA03858D1D49EB677873F5EFC29F67DDA75E37BB273740A9B20E48F41259B31ABF3224A7E814965ABCBB0A71F81E64D2DA471C1FD3329999E6E104D48B549395D7911E25C388042846DF8DF47DD3FAC0927A5D51D2E6375532D34CCE0492B981AFFAC5AA0312953B228229A902FCBE6CCE72B8C77DC518E7A5070AEDEA115899CB12B4D2AA28390D5301926EDC7A53AD1E99BDC717A6704DCCE8464757259D55A22287CBE1045ED3996D0855BDFF451173280BCA6F27E6074BDEC82957AF9D99EF2228496A69121ED333E16EDD5055816E5817FB48E2ED20A612E361B39019E7DF343E23D5A885D14F01BA6F2C9AB4851C45025A6A2FC74CF7A936FED465051BC2E4FF92461E28A1A06E0071F0702623743AC6213D2B95DA8B9DE25F16C37BD2ADA692765EC8F061208ED985DDD2F05258C084DBF87D607BE888625D592684CABC812F5548247E8CC519C75ECB347F8718A71C02D5FF22C888270CF7A52580398D9F2A1257305ADCCC521C6C3EFCF3EBDBE5F164C6A0D5538EC79706D9ED12CA9C1B9594C1154BD61A9EFAE859C0628C07D9C9AE7D6613697404B5E941EDB16A330D43BD0713BD691C7E2BC72E4FFECE6AB72A70E8AB42CC7EE3156C27FD6BAB963381A36527BB756C1716B5BEEBD1D8501C0D03C1A7100AC44558D9FFA02130E6C8F913461E9AFCB620CD12AFB466C8285B81CD81E24459B7240D68DED92093F8E145A541D59B436419F679BB36470610A25BC9629D17493E688D53A4ABBE43AE51AC9512FFDF57736BF2DB25304024771F412B0BFB881DDDC38DA46BDD15D6E6451524C21D0DEF763AE08B46DF5AFB05395F12FCFA69220112A80AA8A704E3587C721D882E6F64AEB2E1612FCA54310F51E8040D957653D112A5DE9BA13961F77C8D76FA619E6A9AABC562A959F39841F13122F0889B443522AEEA04A705362168EE412212A5BBB1E8F552B581D2B14EF6D4571DB6231CCCEAC4FE115436899184EA13EBBCBEDA909CADF42BD23453D9A5DB55A697AE8C848859AD3EFA2A49C627286432CD34475261AD80F6CAAF9A106E6ACB7E042C9F27E53DB6926D28FEF1187E11C5EE94D214ECEAD5438E0016D52979E338F22B9CE2E0CFA4B16FFEAEEEF724FDF9634A5051FF38B6620F06F8FE2F67F23483365A0ECD82F6BDE81DFBB770EE53E5E0E0C7986ACDD36F8E902D09565D26659FFDAB8F70CB70FB1CE3A30737A5DE69085F8999AB074E17E25447B02C7E0223B319E58F896F8DB9CC5AA231EF137C2558B6D6DD49396D1F5820D85B5543F5F137294BEE1E8AB364904D49554F670169F674E02ACDF36633C98B2B307B4C60D1D138570EBCC29465F0ACB59C2DD3EEFC7B1E37E2D0F315C76FB128C344F17770F1AB2D1C9D73E9A2E4D49943B701FC9163CE3B03E85D03E8408030BA7D1E16EE11B8550AFE6409D31EE89E804BE399B02C243233BAB98293700DE27BA9F2DF66E734F449B4D99CB01353C5AB44D348C705809F4EDF15C578A666DDCE2632706CFC2E2343F24821539C34A19F530AA89E2B26CF45FD96557F913BBD8F5B7DFFC145D5606E5180AE1534EDAC4AE2D4F3D0C08E571E747DE72EC3BB1179CD3AFB75A8E18D5320727854507278273BB49D5E87D0E578CD01BEEE5E9A598F2A09BA623890E0B3E2E86E6D9B1729D685B3AF5AC8E4ABB6B1841CD1CE6F4D9A4909039349BA7E23AB37257ED65520DED2B1DC351AD2B05AA238C0BC5DD80B1F9144712E0DB3CC312CD7972803DB2052556B26AB3DE3C36BCB12FB071A9ACC476DE381AFCC2971C6FAC7B363841CCD8F05C1364C9527AA3BD0E9354E9A648527FDE78267AFC1ECBAD5AED65065148B5DD6B6AE1AF489317DBFBE9AAC603D902B725F9AD5A7FCF524C087E7BEA2B2F9A3A1D2C8D4EA79362DA4AB245528180DDD93E4427CF7ECEFB771EAA5A3208BD348694F069E6BED242FC086828726A98FB2C0CDF3A49C0FEFDEBE83B4EBC077D48DFF40441BC090F7AC65E5121631A728336D5189D07A710CA2A29B855B897B4C36D01E79B32F37738F013EBCEBE67B8C9532015B744500BE5E23126738CD28CE34BF22E881FC50DC905CDC88B19985B5CD62946F09681648B08C5D2E7C29F6E31460EED6F4DC9F7EA646B84DAEED064F46F624AB0C7EA09CEA73708EB4575514D25487310468D419402E87DF65E6598F467136A8FBA8F0C89EF2C09A90160A9174C354EDC15C2297E91FD7175E5916B90067C87EC13E62EB6CCF1CCAAC97DD05388589E9EEBD67AAB3474FA7F682A757E862062D0421AEC7638B2D17F2D54B2138067162EFDC9A96BCE23AF5E32930886345352E869D3E2CC6FEB1847C6464091C5258B067F1AD098CF0B4664CD85EB9F400E201A39CE05465AD42307B9C27825EF366C9A46955D70D40410E5173AE9056B43FC0AAB422C0FE136951436AC6F46A73C22BBD82DC4D8C7FC51E1100889DC380A585F3B4A33422621404B5273EC6742DE1F0610C91168AA343101BCEE4C1D0DFA784091E60E7E50047A6712D8503B58C9B0F529C3C1AFBD35688647403538DDEFD267761843FC05856AE1F3CED51972B775D8DD5E531DC9EED23BE0CACBE68D6E5E90E003A4BBC51CD71650541534C80E93EEBAEA3AE578D4AE9A3E1EA051D80A25C9A53D48B7FDE8CC7270E87A7867643B394006D2EBC09295FE1E244E7824DB260087357E9655232305F2A21D5FD91519DD85BE3AF3628C7A077069961C875564F72446288F38EDA51E1F82D8DEDCC5A9B3D085CE540CA2D28F0743F199B10B7BE6998B1B5879719045C1183FEF95421116C0A501C802860038507026531644238974AFFFF22EAA192E41EEEF5E9001106A5F74B659515AD030B493D32810C5B805A9D829B7D731BAE9445CCD0E3762AD4FCA84B071B1863920112613FC17F8A7F8370B3882405DF2B4BA067902BA2CEDA53AA53C084F93ACDDAB024BC5F614938CD4D9C380175B08355EFC86B385945942418AE15ADB79B96429D3BD35778B0299349CEA18C1DB65BBBF427D9BC5B3C8E41C01824ACDCDBC83C588F7BFBDABDB684E6B6EB850911D9597D17F4EA8D8E50C41A96F2C0857605193158F574D900E9B1139A6E67B62495B87039840FED4829EEB5D25A255DC8CB9BFF3EA7F38FC22D90C66E87661713E61D4D199D1E356C117F8F6481F9DDA59BA86CE331816A68102AEF19502E2F1E458D099F35BA66FBB330607D741A6877CCD66434C096F7E439E1FFB8A799C1B013BC30F9A16D4616A224E8FFD36482BA5A826C3756A3A4C5D54618E4EA8280F925983EE970851DAD6DBAC8F7557BD3427A1F56A2543E18ADCB5A1B3ACD34687881B174F50C4F81D0C1171993BB629C32871D1DE5B42411F985E5E48C04A68213FA0B2757BD3876211A27A83234B88600BFC69F57A25CB4B4FDA33A42BA89F45A562CC0CA60681B15F87EDB622CD92494A803A57F7AB272FEC8171001F545B5196C7EE5158515A94444201359C7FE617243CE95E307F4AD87012BE89AFA23E4248A32FD60078236F824EC735A0CA7269D0CDE142E71C9754998D6D2041F5F4A5B7A261D9E9C857A04818315A53933D9AE07A648B77C2C1866CA7294539CA6528A71BD1D9AB951C60D8BA884ED1A7AADFACE8E389E20B7DEE72544657CFE55127EEE5440643380C6DC97CBD5308E0FB5A6B2EE10A0444CD70F468BC0C7F13798F0277C10DF16A8990161DDF7AAC38C388476CDF9D8D1BE72A28BE1BF9354D01B496A17CA4818F3889EEFA083D7E4DDF894393E0D67AC75BD34857647A238D91AB0FE1381315182C8EC838FD85F2000525656181A36ECFA7FDD385901866D223FA10D68B3776D3A4F333D58DBE824E31B5541B2B2483868C473AE9E6ABCFA2B7EEEAEF988BBD06FC63511E030370A88CE9010DB27F766882DBE69B5C3C7C094E2D8064C2C95FBBB2CC3F120800F2C5D772C852D3BFAFA7DDB394943FC92D31E23D3847E6933F265951FBEEA1182926C0F99B27052925075ECC50F01B6654D66D1C6982A27064670BB2BF8855FC0CBA78F5B6149C9EA583253F773EEE03EE28FF738F21F048DC3076D5847309237EEBDFE03D4561E4972A033048C39A8D4FEA0745C1E5E1D36E92D0EA0ADA3E025B6909C86065F5CA944D650533A8518AD02345967C53E2A14129944E101DF2A37F03E986DFD62D45FACD4D71D018460CC2D038E7ACA4F1D8BBE57BB92E1053D3ABDE11E41A440405FD1B99A983B1281ED56A0A7596BA6C6DF2C5CA31FEEFDFB72F1DAB3ED65C6DF169EB50E031492755F9ED2B2E984E527B2BA3C95C5D240A2A1A9020366D2A25CBD50DDD1D673B4B5C8861D47221A0DBB56F8C6E4329869C1526B21A795A27F068575F2E5A6970D121F1007D0EDAAC4953E56FE7C252E46AF5278CA77E3F4D044A6A8E64AF07E72784CE500F2C742086655045952D215632EE3526E63FCCDB3240A686C49CD950F83F78A12323E31FD497CEA2EB7563C9EB5BB4CF0C97062E415BAC50FC883E00CA75F9A0F4513A1591CAE9BC41201A0BD1575FD4E16818E56BF0D414626E331E4B2FBB81DA7B41C32ED6CD8FC900CB517C59076D8F41360A5BC623B05A9607B21E5319603FD89E64BEDC8010C16DF6CE775595848956824BC0A0A3E239C9A388FB875B69AA746F5E9C5694B035F6A5152E10B77476F5748DB8B838774AE25060B99B57C1D1CAF0BA7B0DB892FC3359601CD172FC656F4E9D92651E750A5364B1C40E2BE00263B0BC50EE8D5777205501C8A196B73E7CF9E763ABE03383313C89796B8D0504754F71FD282171EEC1AADAD79235C95244F3BA8299421BDFCEF0540925EC7F13ACE7BB6DC38345CEE29C6FF8CB5561DA38BECAD8D8257120EE4EB7C2332B92C22E3C997AB32DB789854985AD987163A9860C35237EEFEEB7509108FACA9342623D1FAF687D8F3922E7523B08600D3B2EE9CFA2B5612C74147C07149EBECF49837435ECF2D5C8F5711A5C8637E76160AC282931324C05689032AC1EA5B3901976AEB165F94B9E366D0FB7D48A31EA13F89E7EF3504270C47DD7FD2F004E69E782D3F0C63E429B2CF198AC5201A1B760D7018C5F76F1AD34C11ED1E18BDCBDBE7780F3ED8C620D53ED330B0946B66F5D46CC381B8B71A35CFE8D7D0FB6B6CE894484CE7427D2C7B1F7A908097209DC37ED69C2483846118AC8EFFAEFCD937A6B82282BC9E976DE6DBAFBA3BBA0F4DDBEA4E1A9090AE90922909674A38E7DE620B036C79AC06A865A860F36380D37DB802C042121BDDCEACF58EF3707566084AF6DC8CA2999A12AE386E891B8D6143F9662061E6B9B0E54890FF03989EAB0846EE6D483494D3FC13FEFCB9CDAE9D273D05F5007765453F6E4366A7BDA9A6700E00FE25304AAA82A1A1BDF10B8448E4BFDED076088E301C6895A89536FF8938F3C7A43C481444F1AF4A34A5B74B8D2507B34989511ED641E30BD4A2FAD38FC65DEA223523A92D386AC592047333BF2A956C94DF0592E08A4DFF7BCF238AEAE045A17CCD24838FA14851202C95CCB79585D865B862EAF0C6E156501755DBCE0B4C82CC6AC46ED2D9549BDC116E3C8B7C6EC62A67CACDEA6621951E2B40DD45DAF85C90BAD0F7F6F17A1148639C42150AB999A8822131106867A96B62AE25D9503BB02AE1D5B2E6211FE9601B1FAE84D477D41EE69DFDA748DEC02FF40E5433A9980F13662B1C470269A735BB218AF4642C1CC968C86BC7D3FE4D70F2CEBC5BF382D5B1E8FC4DD05217DF7D4FD8FFD2AAFBF025D99A55C38F01840F1EFBF7EDE154683EF2528D86CCFC7B409AF3E55C5D804E93EA040E86C08803D42BF6F0EBF2FE1FF37C9461D4D498A6B9020250FEBEE8359098BFC189C825356993DB4D4DB8883AEB466EB21DADE339794374AC4C1E49728DC68FD525308B022BCD17EB3AD62B379F00C9BDCED89BAFB458245692DE755331E7F400ADB65A4DBEA816F394E08BA8A2B400C85C1BA66F54A94034E5CFEDFFE948D368EFC6801D551755B1E6707FBEB1227F9A677BC28EEFF7F889AB116AD93B080D36242B5799B6CFAC2ABE4849DF1EAACAC2D3163992D569B15A82EA344C959FC78167EF30990BDB865C57BF8285117CDB83FCEAE50DEAFBB3A05BC7D2D2B438B75A58EE22800A8B27E5E4497834B11C3924367E3B8E06F3AC7C5A15A17ED2A17C07814FF8AD3A4F29D567BD12A960337EB4618D7E8FE9F15B2E474C97D79D62A0D9206016D306B794A000DD545E3662D956FC2FE263805B15057DFC0AB10985B1857E2A1FBE29F5043B2C50FA509CD707582266552CFD3F5578769DB419A4AC0CCC42F04745B5D976C0DE8472E3FB92EC35483B8F1B8CE367D74677AA56AF8775064331085ED10F078B8F009A31504339B98431212BEEA353CF0523B62003CB8FD03E60A1A5D2C042B97128287C4552CFA766851EF79263775F3F1B12A243B604A49AD74DD6F7E8F24F51B5917CF29BE4041EA4B04B78578B775E06BAD1A47D540B3CF42A0BC82664DF4CD4F5AE387DDD13263058291032F8D547CFEB00B869ABEF6CE5F5FF09BDC7F986D6DCA908D49E5FB7C60F6769589CC8A3BAB7EF6DA73F43A3113C7639BF48E41514D3842291CA3F7ABBF70D6E28AC50F7211D779017BD4B9235D6FCEACDF0E1E73F3454A852F96702FAEB3F51AE82299295A2778A254B3EB532D6087A5B01E2528D3719860444A76A4936229412553203C11D1395E23E93ED127719C479B270407835E13351B387B00771B982B05F1B68FBC15B1F1D65E67B7750B1D057B2F94DF4D3D8610E3E228744FE83BE81A3F6A0F915E040ADDFA9BDFDF541BF578B94549E5098BC44E5979A9F74396830F9E06321686BA2A601718E515ACD56BFA87BBE62944895A18F01D0D76365153C85B78840661ADADAAB9AA008E9401FEFF2799ADAC7BF20E5FA5C11D34B2DA6E89B88A46F7E996EAF27C14E3D42BA17CF2774F6BFB2A53B17C79CA8C58346F2BFE7EBBE75BBC5FE2F14231A8E66B689594ADC222B31D353149676054D90B91E32551F2F086CA4490749A133F1F3A805EE0A7EE93B5EACBAECA99464F0218A54F293CFA60A8399E2F4DBBF9A06BC34555EB535CE15B837524AEEA098DCC5C6DD923679A12EBB9E068473A1554122B0CDC37A14DDF31DF6CA9B24B2156C8C55505C9C32484DC878BFA34B68756140C83337EA818A6AF3EEB7C639F12C29F239B9F924555B6A7C1210DEF1667685F340DCB4F9703D509C557AD8A68B6B5B7BB5456776FB156B995ED706550D16206725DFB50D44C25C68EA13479BEAE2EEA5519F7D48BD0FF73214D35B803930F57F087A06155E4DD3475737CA0C132E16882199C667DE99C6A64B6D01427610C70BC246C08FD72314DB032597C890A54F1D3EC9A49ECE4FD959D4DBCB543B82762F177CE4AB5CDB3235DF9AC8F63935E720D4F1867A26F891B13D5AE71A824AA02A8BA6833A4F2C665B024637DB9EED305BEA1ADB089927B5C4D21A70DEEC17142477A02FD1DA31FC39AD51217770A68591C25FCEF0347B06A6FB002E5A82E3992ADA8A4B94829F5E1A4915CAF7B7372F734B159BC1DF85E1A6557617FF7809A4F200B379472FDD6798E3F0D0AD6A5DEE80AE4A678E3DEAB44981445742DD857DB5795A5C81A0D0E62AE92EDE89413B946C2C4CF14B1E2110FF5B2159B96F1516C9C8D4778D1F0BF307B8D27A4AAC3AD415143BC20D20FD58A44D2A7EBF609C99919B3B50629D9477465A11A50C58C806986E66C09392940461197B5BF93662526EAA48A821C83A6A8E2E01838B5A057636193196C9CD7EEC203A453B235524A1E4D3787B744FC341941EFD74C1CF1CDC671CADC97F6012B2F046990BF920EA30DFDDF3D6E7A66617CF370E669998164B61CA9C290F6BDDB761814A981C7A9B3D35341FB318CC6BF0B9689CA7075B33CC2DB02BA0DD932BFF9887458ACDE5B4B39E6596113731D40C2F2545B3C7F4BFA7888EC58FEECE43975B667734BDDF833B7279C6E939596E12696860DCCE0782A0479B224CC92376A320E4E2ABF4914A3C02D18824B036F18DC4AF5731AF62D6AD1DEF36A9FFF4CED55450ABD5DB1E4754B79C6E8EE17B55ADA0BC71CB2DCA58C7E3466B95EABB4D218495025F58EDBE89F93C3838A7B8EDF9E6130CBF2D6EC7670F002E894D6595ED52FD791277FA79C781CB36BD8F44EBF89C27C687C0B4E7ED33A76961BA04B6535A02748CDCDDAF8B08698FA0A23D1164277E0EB295244E23BA36FBD1437ED333A55B8AC14A8E24358CBCE75898E1B4EAB8419C22EB5D5C003D930526B5FB0A364A4293FAF48D877C051997BAE8DAB853D37F2ACBDE8E5BE582986C81799B689F54662BF7631ADFDA14EBDC4527C2E618ED52793677ED2C30E24FD4769C82A4754AC716CF55BD88F42BDC445CB8FAB03BC2B56F322027CEE9E28D02719FADC82EF4E0FE40CF760AA55D54A1484C542A1604E334D12FE97D78631A3AA21CA102B66EC31049E0EA4B06CFCF9965008890CD7B6BE9315C99205521A3E384FB0A815219D0DA400377D002C3D2B354D3C0E96D1F25AA89FD8DB87922F2BC2551C83609D98808A1FD7E2497F7256F670467194DB802DCC57F993E701FC2CD8B4838A96E2156984FC74399DFC4ADC0A83835325D9FE65904BEABB81940A4DD89BEC4FC81C20BE9AC8369FB993F2EBE821C6906A5E9964F5A783793E41A0F91E566DA4E80E6AEFF3357B76444A1321BB3861343CC1571172E2D703647B97C33191518CF0D4B8585FFAA4670C9B2922B44707AFED7455352F35663B838D846ED3327CBF5149F6B47026CD810D682F64B71FE90FB015B0228EE0B4C4A609254F84E26CB3AFA7105894B84BA35FE1EEFF20C168E336F35CEEA00406CD71016B084C7D295E187C8B76999A513B5C0FB77B727C45808A64685F7CCD135B0B86EED8741D1922900205CBA3E23DEFD9F98F468CEF5F71254745EB7F5D02412E74F90213EFD38A2EE4C42132E637AA0D202038ADDA79E0B77E3E0E7C65A4D51A7F334D714B0DEE9721F23EB552D78700C16AE4BBD1EF88B4E3914D01F454BA344D872455000B4C534C4D5F9B5D1E2744C32C848DFD0709544EBA578841069B5F2BF354096302357679879E96CD32D9ECB63E3AADF00221A7833F57677EA1949E16B5CB1F8EBB6A7C0FB480B2F15801448BD858744113FDD3414242C0AD8D5287E05ACB70FE34A5B83D19A53F655C5C301799AE3323B21FC293D121D0A5FCF2056A57083415BE01E9DFF0D553DB70F4DFD1776AB5FB02C6EDC79A868B4BB484BC5AB50A8CF98B1D3EF5ABF85E797A29C31545C809B076DE66ADC704665574C818211780487D99F70A800598B53544AC486736A748E7296E9CC5F13B5E9A8107F3B7422680793365698BE635C948880C34127D49E64A5CA1718137B6EB13BA9AF8512A1EF155C20DD012B91595BFDBF9C7ECEBA72596CB0F2C390ED266BBFB60B39F4B0AB20C28D16D89173430D949E10F73E61FCC55B7AAE49EEDCA2EE53AC9B96C2CC742C7C5843DCE5AF1192778B6E6CF4E12A5A33D09002CCDDB4F223DB5E680EDFF31704A5DCE00D8819BBBB04DE2BFCC6746E100C9345E19E71CCD3A36607AC82B3F3269072E067F7FB110D8595B7FC4FDC067AE87E7E971E00FE492F1E01371B0AAEC88DA8E952B27BB5F162B91BA23D1BAD3A9F3CAD308551976B2B457622AD4504C34B5E1079DE149FC52D9E2487D9AE9435C252A203F1E3F5B32F0C43A648A6FA6EF000A4FA03D866192DF5F4496B058BC23F79E1E617364AD41E4524780DA0827497E4BCA2A4A878C1B0AB89DC632F34128E9698C5EB62C3141B654283D5D75E1D1BF410C70F109181FB82DEB2639A5A38991C1260BEBF6E01AE4E314B09BE2AF627ABC0042C30F397E78D7D3645E656EB3CD8DDAA4472A6DF7EE68A56128257E8C392EFB942967A76404F662C82D6CBBAC4D443607BA89B187FB7390B7911D8A8B1723C9BE484F12B76AC64173478B21B3AFACB6091142BD81E32C80C25249A69AFC9CFF0BB4574F639BF35ECCA9A09549213E4309B450885756A57AA5DB400A496DA72BEA92432A6EF5CDE500500AA2A1BABE239051034933A7E082B95D362E9A6A8BEA2A1FA642AAF2B0540E94E3F8648E13BEDDBA77BF58E83971762083278418873FDEFFC96400B55AEDA8638194A36F41BBA799A92A52D3FA2F94158F6B07C2D65345F3241246ABA5AD872EDC0DB8F8782AAFDA218FEF129073755A87D99B48707E290020DA599FE3A49125EC3CFCCBB396EEFF9391C56B8ABB620805DAA9EFF7CF5F03EA4297AD375629927EECBBC8880B75BCAAE75CBEC5F7331576BE448D7875F6A2CD516D3D0A7E7CB6B17EA1AED416D2EEC03708BEE5525D6AFFDA5A460109D1142AB87BDFCB5850537E8A6D07D9F8818F578FC7700CE508D93A10CC90DA7A0FFC6F8DFB08257513C9C2BB43349FE9A33F95A482C40323689C7109DCA035F3E23E349CE2905C8DBA4EAABC787E2EA396DCB5DA4E8027D91C64CD70C7FD68E3371F6FD3298A0E14A6F5055EDCF75D911A817DBEE2FC417BDE71760C74D9E4FE1D9AD283D7AC217EE9929A5037ED7E9717D6E345ECC246CCE3EDFDACB3D0948A36CB41059420158A94F24FC048DF3CF80BF6F9806E4760C3DCC095EDB7F1A17941BD6B88D8AD23A92B122D1B86A2F5A674CAE107966303C6061AC3031321DDE1363EFEFC51A071C57C3852F4CFC232B177E886969D5CD2CD79A2A3EE7456FC3830BB79E528305AA73016F0D10B94A1D824E57CC6CBD8571952FA684DD2635FACC38E4F335D1EC824FF47CA457366DCB1FE5FACCC9ECB00225A5C4E447B410D4E02EF2BCEB933D7DCB92381777F50673368DEB74E88C4CB306C05E1A57056165D3C6BAD534BA1E0C58CC6B0B3DF87C4B3F4E679E98AD81907F3C32389A477181ABD2710593C36DA28C6441B0364130DB577FEEE58E6C5FD94264A620ADDFD030FF624341AA37D501E7B46216B4D90EC4A375FF8C46435AB26CE15E1C2856825DA4E62AD9E295B4FCEAE7920F44A4F3BAFC4D320DBE286138A071D0882CEAAB40847C03346404EAF19A4537D1E2DDD82D7645779C01FA2C8569CDA84F0181DA953C5E33746E3E8B0BFED3D42CBFE75F0DEBC33C6CB5CAED1A0495721EE9F4C692E8E0042A8B79B6A6B6A9C3390B30C5B12F493741547AA43D5B5D5B8A6F28D9CB31CB0F0F2C57FE57F80089F9439D79B6769C399FED6A0AFF98A5A4D1EB8901F9AD0F9223E071C999A3AC4D1E20C5E9A419DC2A3670312B8DF7D3DF9DB8CBA483D62C6DB2EC2F82B8B37DF482ABD89BF510AEB5295A8CE22A88AE7620BAEDAFB165E58884C6099BCEDC33522EEC1F316807A99EC7113662BDF334D1527A0AFE2173DCD4C92CF9FD3ECCB0C0CD71DDDAA5120B2845C56B6D699DEB113DBB026944811235945E72BA01931926635D498A6F15E9994208705BF6019BC3DD31B70CAF5B5F1FEF475FA61AB8D6316FB3C4880E10A745B4D4311AACA934A014091190AF86D8DE01B8D6EE0831711EEE6963E1D2F09DCFC0BFB88007B34AE8390D4E64C7E673AAD35600856E42CAC986F3D60E4CB83A08BF71946BF408F99A952DD49C900675C4484FD9FF8605182659F6B821E1AE77FD812FD465D2947812D3A1D757582549C6ADE50A2AEA6D5255A7DD86D4DDDA5FA41847CD97DD0AFFB943025ACA75014B90B90E32D62FBF60799E0C2CB18C7CEF696C92F6F291AE30F8CF261C8FF3DD000C9BC3BE180D0BDAD52DDD0F234DE7B95097D2965CC69CF8D23FE465E6C3402DBCF28BCB8C20D5B18C446F74A3F82C3629F9D85776902023E379E74B9F6EDBCB47CFA125CC8FCB6C6786BD4363988A4814AF60D59D1678ED93B062D213899B99A3A2497DF70F2B6A2D3DFEA3601DB477487F28BBB73BD2E2EB5D849DE2180D8A8C479CED874926D0DE4AF4CE11DADF94C0CFB686B630A2D57171A0887641C59F094713E6AA3A60394C4556AE58BC91E808A7A93F071538D38A74D0BAB55D8A0524817EE2066E6508B1C759F56A4B6CD257EF2C243CE2B5E0EC2715B9744E17206E54D4ABCB1CF81280DD22DEC4BFB649F2DAB66A7F3EF00E1A31157F815DF1404F6110E919C9813D785A5BE2556803C6DA2E7FDB791873F5EDF9E839A0670560ABE283D89DD8FDFE9D4AA5AE53D44141A9EB0353AE0860E526F871461B490853D9B8A2EB63D191257C3DA7D1FD878AA513C340F2993374BF65B2DCA33BB1F4A2A571B30CA75F76F6901E24137EEB467C3A89A69AF65F67A2ED8F136C831D59AEC27380B249F48C5E771873E9A6339D0FD6407F04E43863384324A03983FB25C55231B7ED8E097483D0784BEC37819620827C5D08E143BB468A5DB636E413E74DC49D27ABC1D9600747DFB8A645DC0BD92ECC75689735058CEBE7FF3105BBD3EB5D9795AD0A963F43EC60B2E559D08EFB990CC594F78CAA5ACA888828EAF46E80D4EB1143116EDFD5F32794AF7A2017A6C0BF66A65DD1880EE56E9593ED411880F8ABF7D435FF7265260D55E774B4C75C96805E40D5E13DCAC66C416C9732975D1EFA02C170634A7DF3E4DAC3F9D26B2118E1C33282B9C2737D3DF6103390137C358B0CC1EB572AD9CD4B5317DCA5456B07D8CB36CE37619B1F053CF813AA11D55967B551ACF49DEBE5498F6F62EEE724D088D9714DA656F378379E4C76693F271A36AB04D2408DFCDADCA1B6C69FD220A074D7F0589DBE1E84E4CC23D812A1A8E3973DA3F3219B6E812005E4F66FD2F73F238B6A1CEF3A7BEAA280A29814C927C0730AB0808CD15F65C9816C243C719CCFFC3434EE8DF597DAE714B47B73710C78A1965E3B393E513AA99643F9DB4E63EB6D7AB08F48CB64BCF4AFBCAE38625472997224A1BBC664F4122AC531CEC35628EE4BC157BC3858B0D8FF2BF6852F2F6521EA33F4DCBCB8BCFD20719D5248CFD858E1FDBEFC5070C8301C917672CA6F16FE55BBA1385FD019E29345852BBD1F82AD85BC7DBE5ADEBEE964C298F746105386D97FDA7B0CFF14D8316F72F256547114E2126DC75D97A35E122625AB965E37B906769C4381FB57B8629670DF8D6B4717719076381CBD5AEB893A5F04D469D2DF014665B98A0B3963A32D7C2D29D34A8843DF949F7DA473911A8955A9253B3957D3521FB72159378564CBC58A2AD9D2F50C71D582A50D3AD5B739F8002983780A0EE0C7CF28F762115AF83EACC5B654F5EC5AD2AED1ECA1C03ABBA79146AC21C7B7B668BA96883FC3A4BCD8AD43B6F771FF89F31502FAFEDFE2EE6139D943CFFA74AC19536FD4C723C2E0536AE1565C36011EF76824216F3C82CCEAB0C23BDD9BCE7EBD136ED9A39BB93246E9CE2B4D8F0DFDE3E42B36E6C98CAC5D1C5E7D35F1F694D4E4D73C3A355D1C558AD1639CF6A9C44877F82B34CA0BDD7B369244728C3BD3265D2E988375A91E836252FCABC4940182545B5178733C112274A5DA9ACF96E687ECD1D7888EE75682412676D00C5BA616ABB992E21D3BC88AA4F674977F77BB38EF08AB7C0650A3364AB598619F1895C03F14B02166D553069484AF41D1A5366AED5CF6053025745D1146231F708099CD1232DF77C57BE0DAEA271F2BA04D15BCD9388CD31FF7048D59F229F7FC8E362C989516D3A21366AF5B0884830096DEDB40A4FD46EA420047F6560A6CF6D0ED9364978A046DA01198194C774EA3CFE21E47A22C93D56E393F88EAF327DC5F1230693684B1DAD141354A54E00424E4590B0862D53D4CEEE267ABF9F14FD9D37540522CA3EE4D56ACE2B8F285D414F5FB76EF473E7ABAF5D23A503FAED1A9AC86136351DF11426ABA639D1918C0239B9441B7B2A0C1FA2BF818588FDA974C35D2D3D6B1C6A76FFA6CA6FEC2BC0A17C070C1C434F62A707EF21A5A9AE2EA4EFC7668788C7A5BA01B707A38C5914651619FE2028B0BDFC0D343019014527236415D02B83BFE10BF1896E18941FB060A0678B0CB39D47B3DB8DA89995D229B73B759B51B62E3431847D7D0F2D866B121E8814D1B9A9751E4E245DAC6357AC1135EF7AA7C1495E7F413E671A1EEB41D9CC020C7D1CC4AAB412218DD23A8F71DA398CFC1D08B3A6CC4FDEDDB21B1AAB25E54CB9B7B11BC48453DAFFC8C00ACBA1B44D673890CEF475C2FE244C9D4866AA10A77C775BA6F2C2076BDBD576D9864F5679FEC4BCA1EC4AD297E0724FCE07A535945AE4060BDCBEF1B15B967BF00F80505CB0FD4BD842FFDECB07899FCDDEF63B7FC451A5BF1ED6BD28A30156FEE36AE47D704882019A9BF2C8F8C77083E3F7AE84393C299569CD02D1596B76D26A857269DBDA0B2897D72571DC66B198E01E4B558344BF60AD264B1EFAF5A1248EA5B3246B0CEFDD14EF2CE576575A3C16A921387D795813DC04E02FC80978404968E12B862D0ECF0538AB77645D9106C3863D6419CB3B55006B03B1352D06399416D5F9629E66A9D3C60FA736F68DEC984B60FF7962111E05B919EC66726096264D64B03559FA504751216772254CE474EFAF3C44324EFA10BB6A5B4A52DBFD3BF3FA2AF9251C97F185AC6A14B4D155480A0FE219F683B940921CCC54967C1C0F9EA7271729354EEB72F57882DDB1C3640A699AE55A6DC15F2019351CB194C6083FF039E2D3741E137D7954805829E114ABA2FD008EE6EBD43AF6DD0D00A33A234B3E19175ECF68A53A6861EA2F73194F140C461EE6FF96DABFFAD93EF21E89E16867CD5BF37085B421FBE0E800BE3884B4D7770F54F0DAB4B5CE23C4408C1CCF1E87458FC9FAEE48FC0244C08948A19DC2BC7B2A5DB02D289BCB56B03FDE184B71C3D4637E6C04F31DACCE8CFDF295CBF25340AB1592E24B174E508AE66D96B230E1A9B416319AE9561A2902CE82D322671E6387C1F263F3240B11F5D4DF16EA77A28A45F7C549D0A1AEADBB37F099F96507DD67B7B43E2B42613916557919462E15E1B3572A6DE09F01518C7C384AF9F6740B9DB2CDE2D86E152989F4322180A3871603FCBAD26E86C00137E871FBA1EFF0F1D6C6D97A0F77939434DEFA81AF63272B115285A32C99E113A9E3B33325A01F7DB5DCED56628BFFD292A53E7157EBFF12D7C97F5F972AC37EED8889C27C98B245AB34B49F50B20D29F6CA6901EFA0ACBF3C077783D9377DCC80F8DC20B08DD36AECD4E8E288F406CD8445765F5B33FA61E17A1CE0EC321A6527273D5AE5D651471188DB88D51940EBFB79608C4C1592276E5BF69A82D85EE42C9230490268756041003129368F6960C1920D7EE1F4978BC9F01ADED7B79E24F9CDBD9C488DF464025655DB7909EC3BC16EF5BF3FB64D012AA4C576ADDA24D9915B2CCC741B491FDB7E1FBDADF7C0BA2AA8139BA5B890308420D1E793F5620F0C8C85E3494E1735E849024240E7CC933FC960693766B2462840851B12A6ADED5A1858A7AD30B1382926FB65346BE6505BA37E2EA0D83F17ADD64EFBB57AF8A3539606ABCA7624CEEEF46366305D9CA67353B5F5CD92FC657870A4AB95731D45E45C96050A0C8346DCEE881284B34BB051A3AC54C8AEAE1A57EBEB728FB2D5184410D09B899CBA22EE9209E48448C535A48E5CEBED3523D5A138FD48AEFD0B42563F9AEE40E1D3C7503AF3AEC70B0F457F4B3FC299E08A049174996F6E787294817686C6DEBF42D69BB8547ECF009576CAE664EED1E30A65487153BD93A3E77F2AAE465AEF5F9F0D9282D1EB6A974FCE203A92E4E1B5FB6FD099EEE185DBBF5ADEC147E2BCFC2277AAD7E7905BDF0A328585704A65290E4397D08C6CFCB1D8A95950D1FC4E03A3833886DED8EA6B9D7B2C340CF04A8C5AE008D750C40FE4490A879E04344433CBEBD399E881F4773A9BBAD42ABC4720152575E692C3E397143CCD3B6994C360EF92E037DEA19095B64D367E476CAA57BFF5D58574C45A789666DB4C645E94C735D218DEBBDFE60CFB16CC925FE5A226E0238828EECA1047BE1B403E97EF5E5CD4C637C43C33A2FB05C45436CC84D76781E5CEF8092CBC440C2703BE6AE651BC65C76E4B7327B4FD4A53DE341E3C7E03893C6BBCF57D7E197A6B926EECB68ECAB648BB879DDFE3DB31A01439778507D01B3B3EA279C49D0DA28083D2AE9D4C27648970372421098254F4B83EC11535F6D7EC489F2BD2908DCF9165DEF03678B0E4D8C80D3E65ED9E096525A24F0B00C6A8DD5661FA6B097653FA2EC41EC886B7C283B48CADC4D4E027640B3259B71298C02E0694D3660EB2C22719E1813F065D6B76C172C2706E29A19FAFB55D515230A369775CE4172FFF57F4DFA5D7E90DC34393FA6A6156913C86A6641BD5A0807C114792DD656E0720621669333A53124137EC4127B55EAD307EF28282BFB33A10D5BD326CE865C7BBFB60FB5CE5E5EE9DB430BE7A44BDFCF2AAE550CD7728B2806DB21B329608260DEC763481B2E75BA6E818EC237CC57B4885384941DA4B73A778588973D78C98CFE48BA0D84E9C2B7DE48D8DE1829250C1CE4854BF57D339727739DECF075DF3945A59845E112DAB123B84FC19FFBE2E2116AF14D096F1B1D32CB720F40BCD9DC5F2B06026792EE6E4FF30E3BD2CCD51094B57F6C33A790235B07889983713E51FB40EF447073AB1B4DE407933264E6DE5B5716082A71493B6DDC95DD07945391E38DA945CAB6B8D5BA19B31E2FB0BC4CAA5CDD17E9998F346A2F400CAD6D981D62D3555540A9F43049B0F2259B70D11375E503576E86460F0011B0448DB097C0FDA0362E4754A4D3FCBFA54425106B7984889DB659D49229F1ABCD7CDF06D3C15212A5D0EED7F71A5C7925B1B60F7534030529A859C98C3493D5AEDD728CE7BCE19B86E0CB33AFBCF8BF369E1388541B840AD1630C05C6A3AD4B6F1350ED69CCB00552D62C7D98EAD96752F3ECCF785269A3496987D31FAF74B11B057A0CEBAF2B95C186B97409DF8C865E0CC6FF36925ED2BF14EDE41C4DF045EF0AD28C5746871AAF99619DAFFC8C8C77BBC0D48A2B32678D2D53F35482D34C55AC9819AD86D00BB886631C463146C28B69085031B7E0049E378FFEBFC0CE8810448FC796871D2C8C521D6E4D9608F43887DE5ACC106A06D0652D67C5FD177562D7CA4E2DF52B819F4AEAB94FBC4BA3A38F3143915FDD61E27DC5BD648E993211852ECB45C69619ECB2E2379D0928259AF5D5604601297E652FEDF084F15CF666FB89EF0EF78D4C7B4CCD07F8F474F657D92E318B41CC811257C454C30E8A86C03B8139A256B6044B7CCBBF5977E4ED5AEEC1A86C89BBD76092912705BAABF7AAB98BF8CDBE81506E931ED8DF0928AE16A6455A7D81C719AC0375295F1703C4BC6C0AF44416164EFA2B46F63CF20C7563109D4CE8C5314115861B9EEBF35423B23A3185A9655413DAA08BDA6ECFB867BA5F982EF70E25AEDE6C0959FC573E636113DB30101B4AB5C2DA4094C4C70B12D05B6CDB4BD9E31B0ED7B57235E2392EF1321CC9DBF89ADEE7A2038A5DC5D5477C4648FFC3B89E00257EF73E20389A041E167C2A2C6A81E6D0C319F47851D2ED0EF3074459778BB69C3374888366C82FFDF19601D32E692074891CA5847C3EA6AB5BC41380BE3ADDBEA8EFEA506A7FED0A5C46532FF69BFF498F6006874E39F8815F3A1CDD6A1079D0A75DEDF6D20840EA0F630FE450A1BF9133A2CF030AC784CAB0DFC2F567C5A78258EF7E9B2BB49B0AE3DEAD886E4B6456758D85E35DAD0617ABDE59F47157BA427839EB705ADDF869694BCCCA571B392CE5A640A93B347DA83F42613BFF3AAC1E231318E74025199EF6764F55727C525BD13219DDBEF335BE3E084018C610088CA93987627059B3ADAB8616F9974094F3DDF5B2E952B324259D1B4198C059E1FA7E7345CFE100F6BDE173606CE2E939DC8DB28BBFAC6ADDB06FF0FBF2CC9FF3DC4953577AA4A00A3F265ABF9E51F55FEDA9FD4B3EF8D6D5019837BC749DBE60DADED9C0D9CC38790AC5955D1C3C7A4AFC7469C694C0AC63871DC801086C3801F7C12E37B63AC8C988BAC5F88DEB2B27D62B80DABA75A5ADEC94B2985E14D623B5DABD809CF61F8C3F3E640A24805260E82DF6FA7CC5BAB771C12E5F72F47854D3EFCC62E0B316B7C980D3961AD9B054B7071980CC70AA0699A7AE9F3FCB90DF0EAC8C8972D1D445E88258E6EEEE0DA9FF878F743A4DC396F41CAEFCC44A4ACA665CBB4FF6FCB201E40CB22B9ACF31F88DB6B8E803805F0A72EB4523C4696611492EBD6A9F21953E90399781DC36D3575563FA3CC525279D3A3B7AF33D608B4BDF299ADC9A34849B7BB6F17339FF91659310F5EE27BE12598A42A2BA9496ADB6DA700FC3088A0910E490D6CBCA19DEA091B021AF94C9A452D9FBCDDA9C5F4E12D8977BB93965A9A931F1B81DC49EE999B217A3E138A1CFD9B3B795638735E6B775011D4008C89DF4E831046DA90D78D9FAAAC2D1BF2AE6D5BB51FB61854BD17F0234F34EFB5B6CB7424461E2220A21EC4B38D3DBDD3018BDDCD236376070542A4B0C2AF949D58C50B866CE76B6DD7C365D92B716286B5FA95E9F1D25625AA9EFC4227F29381480452578B6FE27D7AB21778F02B8CCCE283E30470A2D38DA311B66DFAEBEBFF16257D8BA135E6AAB4E26E0390A1D700BC2D5C28A458E083B63EE98A01A0CB1BE2438AA4099BB5D79414FDFB002572CFB3A5ECFD8456FA621FBF02663E5F41F703E18BC5775217829019504852311E3D557E9C4F3D98ED6CCCEBA09507B5433225C5F52DFCC1C5455DC552E5945FF660A855FABC88C6E306EDE7F166AA6AF42EBDB04B79297712026FE79963318550A19100E222CBC641B55E50784F5B049A835601C7839F29FB0FA8649EEF1F206125FEECDD0ABE160247810E80DCE2DB84BFC1535E622169BA237703B04EC6DA9970E9BE1B99902D07074CD7B13B8BED195753CBA10F9F64174AB491CEBC5C374751F919F3119BE7DE007A7E651609DAC06E8898404326F53AE8D714C32144D6D7E79E4F5DD19B6B498F609FB76E45E228CD4B3D8C7221F96BC221442873A0EBBDFF240B72DD22DF75A02D25047980ACCE46462B858FC1671FB49A8ECAAAAAFFED609E1489CC6D9465BD1E03EA3ED40D4A31E988AEED501944827AED4B054D27B0A6E8AD722B471E398EC66FB401015BBF2CE5B3B8702C617AD558C7384CEE65EF3DDC53A03E558D5543B5BD51C8D28646A3221B6258406AD40298919474B30825023A31144652622AC6ED30B35D461338E1F5B69A1CE004888EF78F693A9AB4ED3668963948F7C009B4A0F48C8B25A6CC62F234ED6A429204C5FECB9700E2904E4D5F340F90FE4B6D80F0788850B4D74F128C3547D9AE72B3EEBAEF004B23072A88B39DDD0F1F16DE7232D9FD450667BB38BCBC7CC06D92D04997B9971E044B5524BB6088181BE89341ECC9270699FA86087AD96739D960AB6B3CB924BFF4D68AC25D5B5EE1286D5E97EEBB5E58BE22D575CBCE7F5E7B5D09A413F1A186CA4D4E6E790EE1641B468859C8DD3FE2634BAFA9FF4CDD017F328E070E7551B43C6F5CB2583E227BAE550526B0FE9570B4A566B1D7A0FBAE448690EC9C575BDA53D75CCBFD4743CD68CAFFADC1A5A7F580F033C899FEC78A5C69826EC49FB732EC27542BAE53DFC4631111B2E14C50DE649F3DBB55138A0F72D94BA5D9787EF5FA2D834F1DAE5FD674710967EF81EB9EDA14DE89962897CD75EDBE5D7D45A05FC74ED00B10776A67A1DA4F7249535A013C3D9B0E2B72F819B22F594C524F6A7FF3BF325722831DCF961BC35D58E87BBE86126F7B122ADE6B66F1D685C0F415695EE36BFF4BD421E0D1EB0CEE4C9DE448413BF28CB16C001DB5E73D2FA4F761ABA4B79CA7D1E47CBCECD3C6ACA012D030DE1A111FA0925EEE1AB5E582E3226B1189AF241AEA0F75633CA33CFD87519213CF2271453B353F1B5EB2DD03C220AABE7E9A0EC3969BDB0452798BDC7F6BB189775D77501BE57CC26AD02B8DB1157A838B0ABE873B2C77C22256740785648617747AA88E0A2A69021B479FEE1288C2482E3A2CC147ECC0D45B9A4DA2A3AE4767D278A33A0DC86ABABD7EA7AA0B800A84CE7A3B32D72D1FC30C8F6718BB2BB995813C5E7CD840E501E059DD0403391000A03E7133727871AE59E1A210142788FA7369B6FD583D117C9449FB9EBB07CCE941CC3FB449EB08D392EE1FAD3BD7CFA6B08D0E79814D06B6679364E486D13A42716D8A19D987189431B69214C9533D42270DE54760661FB966686DA75FB9A3C2085A201AED2499F27B0E0245B68619F15475A865E0FDA86D87CEC70387F417E20F4E82329F79A1750EB978F8CE46CF0495DA75F34C2D52CB58C26A5A5CCEE35E5FB8FF23A2B127BFF1F6E97BE1A8034AA639CF496417C04E55E28420B94A12389AD80ACCD107BBE3F107CBE01092362CB4B08330A99F0C33EA1E95C446E5735B33E8EA574D36F59765BF7B9A28A1127833D2957E46DA2F833DC6B29B083C11AB860298394467F88C341C58B62B0E33A09E9F8D8D65E25C04CBD3A9DA653E0E7E3612B56DBB700E26BE0793A6BCCC8A12B470CF4A06FA349786F1AFFB14DF21EED0690BC8DF284E2F485BACD4364F42FE3BB88635E007F6CB68F974E180737D77FA0766D6A1DBF826FAA73DC77026B55E234CF107D30489FEB2D509200A9112181B27E4E110E7F4FE974D926F416F5C7A301BA76C4D89C215D5689A2B07D5D1F7465F44B4E4DA4B5DC7784FFA478079765E470B4D6AF612BF32D58A1A2F564D40B9FBFEFDD6E6018383CBBF49E5AFC9125E6DE6CD81B78396E2E539F5C66CFBF23DE0AE6AF162D8E5B2DB974380CB15EBF09CD325DB03A8C2838AA7E130916CE2AC67C0DC59945316E46945C6F84B5845D649BE67E63ACFB2A8E8488DEEBB09E84A7F29301457A038EC7F3CCC8A3E53CDAA4ADD188C6AD77243DAEB707E67F07FE643124117F4FCE4837CBE49239F1628AA49AF720C9EF53622B97FE90AF125E54B3DE5D53E84FDA84AABFDB1E889DC2787463E4DCE8D04CB58FB6BE38FCE87011974876C9139AFB171907F0F8B89210D94DE9409FCB4D4FAE11AC680B31E3B39332458BEB69853AC7920951F51FA3DAC6378D4A6117EDD0B3D7404903BD8E20B67F1E4B5290AD76ACE53023E8BC81B9CBB776BC1D5A0BCF67EA946BF3CCF26AC276DCF24C380C5A5BFE46A2FE85CC0F3449DF921ECF295C0ABA966C4193553ACB3C1C1B8F68A60658DC9769E79F766122F96118ED99582EBB03922B2E922CF3DC3A2FCF8C4CDE8B7977EBAFC5C62304C2593570F6EE79CDFEA3209B23C7881C5F10A55E3E18F1420A8B618A1646564FC5972E965554616857C079CC1384407F70A7A575CC8269349AD8F78D61B4CCB5A57D88F3A8872FF4905BEDE464624A336BEEF2FF94AEC5BAF3EB695E5A85E2E3684476B77277971BB86F44CE88C9061F1A86D35011BB4CDEAA0CE67455150EF696DE4C8D3A5F8ACA8746215B2A59EAC9AA4581FF91D6B2A3E434B834928F8F1E4B3673B02D12EBE3DD125F04FDB03A22F6168057BA603EB2ECA50208BAC9AED056F7CC270A8B9290F934CF7D398F7E935A8BE2CEA8A953FA4069D6351DC8CD2FDE73D63F62971E7BFE4CD9EDD46AC1A2B7BD82151851A5FA045E907D54516F1383CE868E9147949BDF73C72CDCE1D8884FA674EF376BC37A44F7C3EBCC35AE0591ED54C0576266F0A18268B1EBAA3A6DD44BC5D2A5771C4D1B2FDA82A015D1FFFE8CE4454806965E99BB3F2735018572D795302AAB1156DF38591A74DD80053CBBFBFA102ED94606B6B8D0D764C74AE691FFE1E26F9774AB90910162D83D796D30753A5C37974597EA6D55E706A2B0F5311A0551F05A13DB96D1E99D9FE22C81623C48D82646B90F17E3C725B63D91721BD2D2A1008E35410962FBC3598F53B7FC96D5BDD8B85FBDF4576A0C7EFFD652E2F83776EBB3890F4C4D30304161A13F00AD3D2A64662794DD6DAA40BB9E982C74EB35FDCCEBF1905E62D3B20D5E440CBC5C582C40E506EC353E9402D558DE2622C7F22BA9C9B047699E186FD87F18AEDB875B76814FB350158BE3FE0D1C73C43CFE0CCD718C7673AE64C976159396384AD559776A7F6CB7B4A70E20DC586C8AA5592B1D758F97E2A4C9057731FBFDCEDE8D93F937F1D6AA636DB2CABCFC584A7B70357683FCE7588AC82D4664C6F0131F30DF726F1389FABF920091A3FAD9E06696B174BB0EA2982173CD0A5D746E878423A8F68F1F5580D75AF85634A63EC1C27B1F82927C8F8AD8BC7B4D9B231905967E71CAC273E0CE7721B1095F620D5731B441E4B4750CDE63A2A6F39343AB887684E027ECDB9C73AC47DAF5BFD5EF9920B54A32A7F6EEDB8C742933F08BD975C1037439629B0DBDC29B782145BE86195F39F1023EDD3DCDEFED0B84E4B1DB606664437600D52AA97FBCE3B18EF1E303E621D43A7939434B00BBF8340AD84DAB02F3DC479ED202CF362FAE752EC57E44F4FE41DEE9F60D7713E1C152BFB808FDE530629077B1376534D7A9BDE0D99B026A8E183512323C1185E0EFADAEE2B989AA9295285631499EDB37B5376BDA17F8D916131034D9498A21C1BD3EC1EBCA032778230C532A3BBDE65AC56BB0F405F211E8CFC6C5D0B3AA4978FF6C892B8A36DA80D23670AD1005D2B97069E4EE4CBC6813D318CF89276205398E8EE7F9B0C194F42B6F938836DABEF6861844AABD6882EA2AB5B010F954E7088EBE97E2008077DD347C12C0F9C297C5714B793D1FFE335F23C82F611B1ED0B2D01904AAE8046A1BA26AE5FC2B80F6E1C6B5253FFAFFC008C12EC465D6F212269957B628486398696BFDFA99513AB3FB254F0CFE9CCE70B03162F11BA935199A71CFCED6186B5E93B8F13FDE38B906248CE135EF9DFA501704847994E24927047E43F671A52FC3AC8F70F2FB74556DACC8F266D196D32E3E821C8B3A12F599A4D92938B0566F4318F88CC636BAA8FF0ADB575881537AE9EA400A0604CB90075D29F91863987D6404FB0ACC622887515073EC45169D85BB2D2742053A4791E9C6F12274E0C0C24C98DA82AB77FDCE39A6D110450965C69021DC7A49B58A07D4F167330BFE59E981E27AFB9DEF9CA7601D21AD463EE251C673AD261BE5BFCC7969E75D2481BD7A00C18EBAE25989F11195D3DAF665961D6B42B70FBE195A32BA082F4A35DFF4BC266C9FF119AF9C1B3240766B9415848F9B0E26F20BF2D0B023E53235B512841C7CC0E8FEB58C3E1E099E1CE99FD6DDD26309300FC116F730120307413EE3D84EB0530B13E7E4E34EED5BC9A1C21EF35F239BEA8168491DDF0076FF9209B8920900FA1A2F502033CBB99E3D3DEA72CEF72E54C834510FD59C08747F03810BA02DD94B6A7A6256850B7129964761E323C53CD39D26E69BF146885E8C0143F2A61926F5DE83A5561A30B2C651A025047C2DFBE9525DF3F2EE10742BFA6E8403F86862CA1988ABB5A53C71412E2DF9F05C5B4888F6119276AEE0A5907222850F7D825F015D6667498D1A0E9E53D0A39C390E8367DEA3A4FD86FEB861954F0220FB2EC04E2ABA5C75BF4924DD9B4754CDB38368C2D432B09FEDFBA918CC97F6979C974D8C5A5770BD988A2F40768FC49F2B56C7507A9EABDB5B4E723BB5B06E96C57464C3A64FE09C62D5783B0492F2F2891C4098638274CFE24CE0B0DC45FEE79AB32BE8C3B5049C782F11ACAC0106FE4EB0361E1404582EE0FC8A80251D3F58288075A4C35EFC0A06C653C86DF92F7479C8CE2349978EFEE82DCA36B0401CB61DEC15E4954D09417997E928AB64BDB1B1625030B02BC3210EA0A097430ADCCD589129966F20CF392E246575931CC6B7258158A1356CF350A2734BBC88C8F3EEE1EB6FC9B66B1E6DA353131FA24C48D4F6F25313417F665F52C91B9098E5475B9BF2BA7ABE51AADEEF0557EB1561C85D8230DE1B9E8F57C6634FD1EF297A861EC842BD0852ED69F8D71F7C9B749E1B20595A53861B97C9D7B382C08C4CBD93280337EE7001BD33944E851C8704F3A294D8F7130401E4B823DA1E5187E294C15488E34E7086269EC530EDD11D9D9D89F56645E6163E6A249AB16E342C10452DDB7A1E27ACE8F3478A45879929F0EE81A467EF09655686D40270C2CD3BAB943F11A8E85BBE2A45722D9CF80AADA6E2937E7AC199D5F948F3DD06ABA7B3297C302C723A08712440CEF5ADD74404C1FC085C2A54125B4524226113D6D69A013F21337B745B8F9EFC4CE444146875CA6B65A50B45D3537A0845C3715C06A07658D56B17BE47E790428076B1E98495D3009B9B3227FB3F4E80F27C5725813E59E4AEC4E2B97522284AEAC3D78DDA2214F6C26664E6C203D19E89BF2A7B1EF7EB746B6ABF4A74BD8B8267EA9676141DEB6CEA78CC0A6C39F5821A6250A9DE31046B4CF6E120FF5F1653ED50025A84041A2A65BCA29ABF5621AEAF8ED17D2D2FC4CF2FA628B324914E2BC5A5EDDAC38E7486B8FAA1A2F6D332E8A97CD0C2B8556B76B7E18BAD50678530AAFB27DADFAE80EA51B8F23C25D28495DA11C46A9541D154912524DB2BB1168D3D21FC6016E8AA40753FE478FD397418B9E7A4DF5E69225D2D029826CF9D01CAF6F3F8332948F45B9B936C82108FF8319F8AD457DF7A7F1C2D31C6404695030B97DC26343E899BFD359A576179886B882130991A9C8C88D886CD52D5E39C3B48FE2F70A320FB383AD37CFAEB263B4545D92F9807AAC56F439A6BEEE746D9B7B240B1C9BD7B8655D6BBF2287B5585F68B5C387FF2151063D0E05D18866B989CCFCEF772CD097C138511F1C47C3B0CA35716B142265B237B75203687970FF4A8A84D7FCB880C8C3CD673353EF2FE799A6298C83E4116A2AC967007BDB3C4E6E024103574E6987081600057297802303454816305CF969A9889F991429B10354B049AE367DCB519DA60BBAFB84CE9D75710D1F6444062511ADE167A41E3A67324B7687687D47F20EF9764973E5B4278FD054F40BB21D563181B2E6145E2D23E38E7CE6E5FFD65F9CB2B6BD59A123683C287ACB3A817E89DFE78D2CC1A468D36CD39200C16E69B2D7463D0D6FAD072975791B325EAA38CFBEE031CC3ABD550C1F57349ED897F719AA3A13E48C26D92C4E4613F4FABB9C9C003B63F40CA58F0DEA32B6D4F1697B01C7F3B8B4F1ABBE8AB1C346D3AC8BD5BA0E37AE5D7D5EA8AD9E800A2DFEF7EA08AA1FD67D4E2CBE737955DD8894AC9EB5A316AE88106F26D94A740558DCBEF7D25C9A107C0359B4F771E83061F4013810B2FF8B1FA64F8ECF589DA73282E4AC5BD6962F935D5C6911430268B12F30A05C9B1866B4677DB2737199E013755023B34C874BB32D70E67A1542CFD32A1C393747394CD27AA854F1E2F0D72254F3B6244CE9A67D29B772BE10C482CF5E57ACF2BCB299A11504D23BF34E02CABC8C5906DB700FEBA3E282BBCCD9B0FDFCD77C2AE339F9341457BEDC79D132A1F15B95A7A3D67FAF4DBE78BE0871C4236DE1AD33511BD1343077F3FD04820BC9298655948D554343B8DC7AF0B2CEA808B4C577987A9F608D85370DACDCE6AB5924B7683110E5946361A172B7BF11546F4F70E2BC5CE7012EBF44178C292A876D62A5651E7E31A15B8721BCAFCCAEC4AAB73836B9DA4998F0CCC6D2FFD20C70AABFB7FDB508FF9ADB8057B70A72796729EE60141151E1DF2EA2D8C5C6F82E2CF58B9247D398E83539B998EBCFDE82C04848F8E0D04CF0630416424ADE49E934229E420102BB49C1ABA40F3DB80EA27DC0CF5F649F47B22761D76AF3B6F2EBB61719C324AF5EB73941557653A4E01544F051DFFD0961C85965F264CA6641D9C7F0412806DC625382D7BFEA06D70D17FE56AD6AC185EBAD78A86B6B0654362ABEFEF3E90E8352273012E750CB69BC7C5771A2A65EC54C6DCD9CCF0B2DAB13339A60C20261D01B4EFB71768CDD2673F3629D4616B1A4645E5FD02F6F8A77DDF734C660774F7B203C5A3538F103CD920D4FD871D5D95D5C763A80B8C54978A90A941AA240E5A8B88BB0CF26768E9A0F72F67EE07E425DA838B3B61B9D2083E75406BD72B33B3CC0C463CF194E3ABC9B7D3024644D84B70A4F01CD8CC3FE36F8D8929D4A1E65BFA2DF84DDFE8AE66DC21A94D4B3D6344850C516DD177190BD384E259C14BCCD5696A9022D8E2FD1BC38A59A45ED48CECB6E4E6874C2D0650C59B0CEFBA5375583EEE5054097BB670E753288264629111AE732AAAE6D75323362136EE1B7A0BB9605924F556CCFC5E8AFF8CAC7A31A87AA35962E7805C4ACE289644A7084EF1D3E290913211D9496D997F0DFE70CA7BFD014A27E6E506CFA63CE137EC387594AF52C1E86B04A106B0A6F47137393B486A865BEE8DF4856316CD559D50A0D495B106B48832F2124C4EC9DFBFB9C406C76F86272A57F395C7D1BDF388DD51C0224B16B350E369ECA6E6A4F9B84BD41F272977A325192B6664889C6755865502AFBCFBBE41F507AE45D6029C5736B600C31FA84063528840976FE40EECFC9F8041D85B7B6C6E2E7F1BF638EDC0ACB6121A5BFA4249D0B63922D3B887939239D007B79AF60CD79771E1CDA1F46B4250FEF863ED21E33739F4713B5CE62AD77E67FDA0E4CD5CC6795594930B6F5A1B52526428A48389C928D52D452301B867D0571322F5DFBE5A4E46D5F22D3DEBE04384DE0B4CEC91A2A54DB9351D6F67CC536C6F1371F3859836D0539F73020F9C7509C39E9BA5271DD627E723953C6F885FCFFB7476490C33135672CC1C1221C2D6698918C4BC1DD4D0675BC1E246C915134B16DA036B63E7289596B65A73FAA873C6E3F79C05F68EA3F93D8B0CEE45C82C81C6C5C2C894D3808B9538B63B2CC13F4447D429295FDEE457CBE10F804E29BF316D2FA12A9A46E170C07DC2AB09190112DB80E6EE5136A8C82C27DA6EB1C4283C669B5F544AE1601865DDD6D22065EEC9CC1CF8E0F2610A78062E87B8CCC17E21D3C18D722E2EB7B2F128CB791342C26B47BF6D7C40635C2A2974157B4344C076F31CC29BBC77E725E4D96EBAEF12333A411DAA2A1251B40EEF8D66E108EE7D9CDAEC01C22154F76E9B670EF4A5124A4CCA991DC7B14093918E057E8D6D0B79FA7043DF88AE4AD36B3DF478CA078E48382201D7DE38ECFCC4513028EC7D7A8EAC56D8F8BB3C4BBBC3421D27CCDCBF5BF423D5DA9A3AB605FF61BAC171D02F4CB363DFC12708338DBC841D47969B0850E7C0F94617B4E50AB040289DDC9565AE0590BA9C0BC4699F351D11E232DF64A5C6345AF908FA962E2725DDD0F5F9A3E3A0C85D91C376AF27E18959387EFD548B41AAFE4F56E0D029BD408C3F0CD208C09D82ABB385EB54C0E0217A11E7D345072D2A60DE4A28417B0B7B778A4C87220821167B05B6D0F738CEC59613590270AA1C3B8400E5E596B49F7316892B775B568DF74EFDD60694FAF23BB9A088916EE2D05022420A4E64380574825945285D93AD6EE50FC6AB5D7063A182DAFF74B8E66846E69528F894D18A275B3B31762F9654E1DBDB2602D473BC7A82FB65D32726B8B953EF1BD7A7AA3AD8FDD8892F2AF15969539566EBAE00DC5C20CD40DF9A9A48EE65088C98F0AA00BF528721F1723629260B84E80D3A08616EF199172F80F24326A16215C755B614E6DC88818B3B5A034E8DF3B1519B8C54FD5D298149524E39B2DB50453296D988F020602A4CD2DE8D4939CFA41B98F334029C536AD4BAF929DEF5650E8810073F0B07A503FE408B93D09D3F7703E4F24C7848891D21241531846F4F222BCDDBAC468589A475CB835624C57FD770F63188068C373CB2FB951D6FA86C47BB0D3DC4D4C64DADCADB568EBD67C08F168155900E8E512593EC5998A131FB9667346AE644E27BCEEABEF63136A211FB3BB702FAE719399B48131B4814E246E3BD0F80EA77F9CBA5475C0166C79BE91F0B1C1F991008B962B4006635A214E82AE256452589BD2E4270C3BCB03048AE797BC87A638421F07EF863A19E04A4DF66A5683386330C0AAE967610D332EAA750279C1110B20CE2E8C50E37110153108B9B8B56599C04762B2B40A03F64BDA6F8567E4DED894BE2F75BF7F365F9D766AD98736F8EBA292612790814CCF53E71CE7CC7D5EED5573D260CC9AADA37CC992930ABF65EC590BDB26407C19B08E3CD273E507F8D76B9FBA96269907AA5E549872C73A4C1D2C16AE8D533EA5A18349190F5567572FC5B580A71D11D84D2D1B463373B3AFA4C33B91241D1E5715763B69EE168C1C1CA372EFBD21528E9784E9819FE31FB6C772EEC264BE5E2FB5A61ED712AAD29CE09C2A69A9E774FF35982DB902DAFF136B285414681AB6D77CCEAB01FA71161239254D95F0382BB1351A6108BF681BE4130788AF311E234C93159E6537B1FFA72751BA8B39E0302B1B0749C139A5C54DAB4B16317F651F54FDBFD8CA0AB9037212CF770B6DAFAC4B1AFE8E6753CA6AEADBAD01CEEDD4CB4986129FB5D41460C6A3FEBFECFD175DDADB20C2DA3823E45D5F34D68AF1665D369411B9400E8D55F03A7EF88D7D38D2AEB45A93D5A37C10EF4DCD221F5EBEB01B80B8060F3A740F601BEA5D00979FE702A51D29F6E64B49C779847994476DF60792F37D44A6488A315995100584981B7F432FC6B4C9E1EE95374443DA8EA2C6A1DAE03334062665392596F3215F339FD5C02115D31287EA48BB8CEB60E514D93CC4D661B29812E94FDA8BEE8EC6C130C51BC887E55152A5BCC840EEE7F5723BED13C653F4A5EBF3DDC0900EB2F468284CE49554AA880F5E4557F46C38A4A373CFB993D8EA046186EF37DCFDD905DE17B66994619EBC0ACAD9D42172C6C46917A16117A28C9DC0E2F9C330AE135F1858218CB8150F79305D5D77E4F0A0BE2672849378E26BDC9EC0A21CF1FF808D6E4AFDFF00A3528153E1FC564DAFC505792C7481195C1FB80A584E4907757E93A7DAE231C517698A4206C5508946D2C4A1BB64E6CABBBED6402D683D74C04133A5FD0B09194F2146EC8F91F4892E896F2B0C5525D605E2CEF960257C7CE524727A95ACDD3FABCCB71B8F25E1F8D67D71BFDD55EEC562BB1218E20487C75A8590FD82815CEDC797D3DA2D7CB00CD886CF8227D28530358D264903873BA74D4998E0EC47441A5E0C945E1F0C6B2585997A2201BB1BB2D47BFDA38F84465567A525A2341F95727D2552FC7CE938F7B238EA73C35B9BAF8462BFD65CDA8FFC91A9FAD46DCC6E84F81A1C6AC033B73627A7189390FD0CF06AC26B370BE756BECC5BB3AF2941445B407AD71BDB901B30A9B22B979C170D2DEF1FCA3AFFB265528D59585D34FF60F4C8DEC94D1B68F1F583C8E920D1C12690116D1E34DC90A616B8501B6E0C5469A848EBE69A9A0098BD214DAF119C8BBC9896093C30F80E955B9A540A6B863C5076D4D954E1AF8BC8C8CA75AC197A41C514E64F29FAE91A994FE38B6AAC75D945CD9821AF2DE46F2E96627D814A41C35F9FEE78CA62E5797B908B9D4305A30BD8BAFD3D7DAB93246E1418CED0437C17488B8C4C83EC62D20007D2B84A49C809E0B69A121DED6CF0C3A0AD314E67E07BA371BCBAFD0063D5C2A767CF9717028E0A5925676D576A3BEE4238EFF229B2DECD37A77EAB6C8A03FB9D6A6A0784084B0992E458AA4BCF2A652B9202DB324B8BDDD26DB98331D255121228A0BF9FDB4B7D30B1A9C3292FAF93D94B2668A7A29D44FF9C29EE09ACC98671F84318D1D5BE93001DA68FA672C31DFFE12D43E26582A6A8603A551264326B27B5A933F7F9F65559E52F2ECD9C66A7832CEED83A7750B32174F9CFD5AF8676FB2E147D384051B6114EAB20D3EBE21511459EFAB1FA94CBF6021B271BBA7F1EEC19C8401F8B0BEC897308C80BC33FD65D5F69B05096A4A3C17A0963C9202F194F23B0544933D067F5F7C26657D888CCA4B0C0E84A65E1CBC3741686F3EB9A5054F312C545FB48362CB33D3E9BBFC5AA59EDC57552FBC169EF4F8D4CCB6048AF4FC3387470021DDD08056F8BC1C9C70312121D14A108032D0CF88010304F1642517EE9CCEEADA4298DD20EA672F774C45DEE7E149BD1F6C95976E44D9660F8CFD735AE03312852B9B0C26DE77F4608AFFF20A2E0884A737C07A242B7F1D825A94DBD0171A770A1ACBD094033978C4EBDDDB4BF4B2E16B597F990A000454791CD07CF27650643A2162EF94E5139E8C4E22AC3A7A29C429DD8AC820AEF7502C5BFF1F97266B2956B04D3324A4872A678E0CF63F29339562556E0A51B52435BCBF7C5CFABAB34DAE30386D40E68557C5B3444901E11542B1A17CCD5A99B403DCD7F13DFC24C2D9B3AD68B2CD275CEC7E9A593F7824F3644E5FE9CB6FFDB4780C5E83DC116944219A78AC21DB98FB72DC8C003DA7E3C5CB03CE119962686C15D2DF1E79BE8815AC2DC34B35DEE7F483F232CAD42C9F7E2A2D739A628EDB637D0D7FF91F5AE52AA02EBE02A686D7FD88453B7C5507DF5691A2AB852C9411876941D5B8C6BCFF9821EC143BAFB2E2E90341D2535C5AFFE6A8B7E5A8A5B28E33424DE8F25E963243F7B9C1DC31365860F30FD37ABB2B938FC77D97AB9B5E4834625FB3FDF8C1BF85999EA61C1CA5B4658E5DD6D180D5E5FF0DD11652E7550F474C003A4723448C06BB2CB1A8CC9CA6590BA00C8205FE1F17E5E629A1071C90ECA731B88DA992C46A7DEEFBAD86F99306E3CB481DEAAEED2F6CFBB9BCFCAECDBBE5B36D579780461888C775A9897FDCBE1A24D1ADF7DD8170F0C5D8A027E2195326E846A0D1C2D2EFE09ABF1110792923BB488993648E7C57F53CEC00A7B49697B04DDCF635CB643204DBADB85E25E170BA74FD05C341DDD128233FAF3B0F9D812D47E4F4411A148834F245410127E1593D1D04B9E359526A314E8766C3BBA61A8A60E537ABF3041083B0D6EDBA6CC46728D9C30B273CDC527133F973394EFF13E1E65647DAE218C7689A74199E8F5731FD752963B7426970E928429509C747462BA4E1314E36B0E36663E4A797E1C0D02ED5DB30C1BDE4CFD3E61D14A872AB5B852DE9B0A05DBEDA9CE209ED2D6607C8E1C0E2ED649D61D5C58845CA8B169C127F55164B2C8616CC3D5716B0EDABD3A88602EEF1B190FCCE6B29708FB40956B3E3653EE2E0BA08F33136A7CC7FF945B21F79757EDC14263A2FF1AED51153EB77CB63ADDA601EF88C261B3395C833A2A982485070D5799E0A5B015EE54E9D1FCC2A4844A731711575503E10664C58032DA5E1A2F37809C9E35C3F7A33584FB895CB03702A20B8BDBEF68FA173F10E5A4DA29AA214BE90BDBDEF88772D54C15A7D2779B34777E11616A7B56F5A8763C4C7521370A3F37A2D865628966DCF329404BD02C6BEC5D046B154914F4E442B13DDA575EC71A23332347EED914DFC5B8085DF2C1F8064D304A846A143AAE3EF67CA64BB6B49EBF0EA55769DB5BCAA1931B46F9F2D40330F0EAD64E5FA0DF85CA207F15AE697D6E44C363FF0828ADC475508A993488BD26BB3D5879FDD05C803DB0F46B66F2B841648E465B26E9ABF7357E370F1F72C93970D68F86690782C5FEF8579DB45574D350E66D819DF1B5250C80B49B362923A5C14F6C4B1B48F9090ECB5AE03CC27C70443156D8EE3D4815217C7D5F8ECFBCFA174454F623E22ECD80DCF7E43C5DDC56D9C27DB2638117C1493CA79A25EB2A8E146B273B29DA0107E007F9D44F08A480DBC2FBC721D55330E2FE218D5253730847107DCC32ACBFCE8E312FA1A4F680C646B736F93025F0DEB5DAB8F286A4C3BDAC8DED0F203455E3696185981A29582DF5D1BFAEBC34A73DBEA6EB85811BF05F1F277096711043E91FB36D45B066493D8AA2E8FAEA33A06989F31BCF52E97C05B97CC470DC8321FBDCC644E0887EBDE8136E38434ACEAB0D7B9ABB7C6B0740CD54DF646C7977595BED83F8E29FFC2F788478E96DF4BC3BAD1D293FADFD516A9004519CF0E57BE935C3E3C0D559D54653FD8D741170F3BF68B212D9148DFFF85B4A0A8A04F4EFBA3422B1D5538B1D9991C35292967EDAD35FAC47336458B7D5C82A96F26D6D8B58D111CCBA962FFD1806E74B994444E92AF6CBC5E49F58B80A1DF6176D7FE403AB37B4AEC4E2059B271B7BCD30E3A046C4CDAEFCC559C3D92485CBD904A7F8AA41B17B3AACA4AFECF46B3704428CC3A48D619FF7FD6A2763FB24B1CB74ED4FFFCC84F809C7CA952FDD243447DE1034B807DEE5F30A9ED1C29DF78CB33D73A66D0963FEDD36219D93F9C9C3C7BB1695026D14B403B100F9D9036C3DB1B5E5946594B8DEF8D1B60249ECD884BCCEA22C26BF4E2C855806EF75CA8D358EFAF80AF5D050E44E085050B12634C4800D43824FD8998D5636CCC727962639457692F3B2F4B28BA22E5FFC7994F750999AB7A304BD5CD722E1E3914DA106DFCA85DF70C4891E335837F27322EA109FD74CEE44B6766F13DABA0150E0578407F350703D01E3650DB6C93EE92E30F79C820A5302B0162219A6D1723EB96C31DA0D05707C0B6DB3507643EDCB7F64037C8EC4D757260C312547AFF5CB77FEC48CA7124D750EEE27E20BB536EC1A2FDAC872BC51B74E1FB69E5732E896A6D573AA6BF3F75A07EDF5CC22A008FB0FA3BAEFFC52C2E7B611560BD2173EE5562A9B6F70186BCB8D6DBC524FCA512B444D6D64D678E523CE98BF0BB39E64B6ECCCB6D33556BA95176F2E70506A8B247066C963AA12F26B042DCFC21DE2568F6BA6B8B4DAF989F538112A67B003D410023F7C102CACE81CF7FC0846D3B2F2E4122818235478C48FC24D6546F69D080D2D7C54FEBECCD08184B1B0C408844390FA826DD551547386392E79CDA6452A2541D74360BCF75DED36D5C99820FB65A15B4615A0E8643A23B4BEEFEE54AFE1DC1CCA446DB6B064ECEB7AB13BB9D2458A71E39727715390237FDA3696BF815FC900DA7303C24712EAE51DC2FC71C406E431A51EC36ACC52E6B6BFA3E06DA7A46086421538C0B8C1EBE9710FA2E2E5B75DA0A284E133BFC7BCBD49965E67D758F080F42004A049BB9102FAF3A06B9A4193F1D35BB2661CCA043E18392C381312DB94DDD3977DBEED9D9686CEBE479053C4B3CD93CA1CEA4D5345B4BBFB953F27259D5978433F6CA70B26B110218DFE2D2E6467699A8AFABE6A23BD55088E5B489F42D240A06A4D0E3830B3D0E87C5043EF9CD097E52186335ADF3C9A5080A0F9CC9E3611FCDFD04C38A76F3C9734647157BC38D4B63968D888BA2D13E364EE42AE3AE739771C98DDEA0B455BA659FD7793AD6E1B860A9FDAF48243B2B54C6573268C466ECCDAC6EAB2B2EADCE5CBBAE0CEC14EE9EC6137318DC114031FFBCF20CA9A5AA5E0F6012860FC5761BCF4BA13A2393F91D3D04677EA349AA8318B8F77DD791F42E9078F123782ABD259CDEAEA31E459CFB2ACE7101FE45942A45838A7603DB82ADA8AEAE7539C43ED92B4D466ACEDEC4E4822B2C3D78D70BB2CEC071AC73092240570BA8FEF5D9DAA63406AD6DDEA1D33C68796F4277AA6D454BCB8D10AD3E50FE685B63A3B932949E8D4C029E4C74115C6DF563B6D712E4E4DF1563145B8FACB562F2E7967191E6707FE18D07DF2EF3A6B430E6518F9184606F76207BB94AC2B30F50D996433BD7AB5CAD1A9613284DC0D30299DC638B2FAAE5C8D3479001A1596B17DEFC49B12F486B9415D0C18E6CB4A271FE8599B38FA0909F38CED058D27C30E75B1402702B2B94FA4CC19F35B4D08E9C5E09EED8CCF869B34577908BAF59B0148FE0CA4E325D73DCCF63E68C2A7DC0F5B3394E45E9964649A2A60C335CEE83AA58E1D44C7A6882766980C52122B7D3AF2D8E9530570B5DD870A6F30C482F7CA0C59A6CCA57E0EC02AB4969B9B579F4AC0DAAB1EE2DB00DAA69724D42822CF649BC8A71209177ACAB5105374759B0F5393AA32E5C9AE5F51E0C9E5321ED9CB46C78040DE5F185E80C50D9466CE92AECC34DF73617AE723AE57427FF0E20DED2F13B3AF57E75CD2069E94CAC6885FC6AB098D6E005A5942E3A5D142AB8807BB99C1FE0F22EA2192775031D2ACB2151C3C8EA95FFA864816381F5B2F5A2942BDE696853A6D24F6B6FDC08C95802CE133D7D5A46A310FCC73B27EFD0ECD846D00FD8E7003217AA962EE4BB4CE60136C5BF59EBC558762CB3F3F4DA36239967B27877685763CDD6EBC061FAADB8436C7B8BAD21FA83BF1378376B702A3147305F6E6A100782F386BA175C81B363AECE8F16D555B23ECA7D2706092B0D200956611A7FAADCB2A30FBAEAE297F5E0F11114A304E0DDBF3D1A41631CEFE4B55ABC4D3D93118BC1759301E0F554B04CEF8BB23CE878D5B28E29E44C7FC850D9FB46D5ED80CF5D3AE9B0CB5EE2CDEE9194639938D329085074C7818040EC179F3FF9A997B664629AC4E73FBEF05DFAACD9C224EF168E75D3F20E35A3D628385382D6271E725186A77E597D18F9236DCA9429B82E41CF03211830708FD61EED812305337F92A8AE99A79F8DD8AF0F5D77CAB2C8B778D3D2584315430A8D32B2400DC9E65FC41D5A122F735B75BFA5FE1C2E220498D095CAAC899AA441C805B39F88D5B861B5A6CE3FC6404447B080F31C44A6F40E10369CE13441C4E3FAF4B4B00EA245EFB8B80D6C7738EDF4D33AA1B3C8512C89230AAB2F40DFAA9823BA490424D3933F6612016F73F53245BEBD4F9FE7AB3F2C7B55B5F661D9B25F063D9255F515482BA9B35665D4AE09252DA8F305CB3A162A1C06B1E1AE466A68EB3F852B34C182A17343371AC33B270EEA5B8C1AD842CC674F3103786C419018C9654975ADFC272FB24713EB97652523B94269876F5D6E347D9211E3ADD3049F349E11FA7FDCAC742175D08962FAB59EB731333A506ACB3FE7A7AE6285BD02A14AD3A4E1070384001C225D9203A813FF43C8DE619D3B82903D327C3034AE3BE37D2C222EAFC50486FD2D067DFFA7387D546E48A0B21E3675F8AEA197F6F72FFF1B0AE2AD92503AD4379075227192EBC62D23D0459DE1690D605D380BB13309DFD1C42AF8CFCD58BABED0BBECEF9202ADBFF1B68429ABEB03092A17D4034ABF7382F23C1750B221AF80158FAC7C656663CF24CD4F5C52CEF7F95F927F3975498F50AA7935A845B63E94DA1FD53653BA0ABABD7E9AF43FD0B084ED07F7AEA61EB6AAFD9DE548ED6A2928E6CE28D1BE842446395F6C09F323663366E00C2734FB68AD812A5E19EC8A4B003E6F53CA46B53AE4059510A7F3D712ABF39A38724AA2DC1B8627FC027154B567065C447EB95AF39A68A10CC15C48890EDA1593B711D94F141811BAA425DFC6F0AB64FA1CE75F4A8C9662ED1EC91C390AEB8617FDE357D14B2D81C8A9D23FB00A52C5008F845CA05EADF588E01A79888FBEE1E05A819664B6BCFE44B4D6C0F27C37D17134740AA3C96EE99CB4AC0348676EC529FCD6443ACEB04EE43FB173651DB02E94010CE22746CCEB50BCCCAC5F7B9C09C507B6DF6B32C28D8E34F11BF40BD8F1E1163EA6C9FA07F344E3CC09E8042F9254879773C8594B72F7D990B6D7EAA5BFB3C9D95A6953D267D3D3F55169A200CE4CB7979117848EE34434D376F94CD5BABA75AB0C82618A31DB337F437FACDAE4DFCD76D2F60498641520E6E103B4A1FE2470D1EE273786731D061F78420D4E2AFB3AC66AEF41472016FD08F270AEBDA0E7F5200B54F82BAF33AA3D81EFF4DFE7A964479B4660606EFEA07DC70DB7BA838EABA5A6D5E5C5226B48795EC453B915388A3749C4FB343F299EA2D542E449260BBABDB068FC9D86D3AC007C4A68963C947A61392606A6D475A7D17B3A845C8C499B5FA607C400318CE8D53854A9A6E0F6125798085AB5123CDBE9853185275CD57FA9769D3BE038342D2A2B34F0CDD4355EAA1E60AE534F8CAD453933DFB48A766510AEC054486CA9D71EE1B6B101B3A857033C2A4CE13B10139849BA89609137742A083011CB719419DE32C991D331B719D1A8B35A144DA8FD75F22CA923E7C3DBD8842E95AD3C5F66856416EE7D8B804D493061B432278A02A970D456C31A99BAB9E7BB735BE4CEC63FC8E4EF56D1ECED809DB097396DAACD63848B0EDFCFC9BE842DAAF283C94929FE32B10CFA6D4305939E1D435D649CDBF17180A3782E903232546F6DEDF3BF0B2565D260D4853D8C9A55B51AA11A23807DEA281A2CC965B83AEF6F6532448DC1C511EA27B420AC43A63E639E7278ACE1FC8D522566BA5183BE4F51045F15C79E723F5FF9D9E9EE16C70A00F01BA6A4AA71B7A9B8C912EC85D3DB2C4266F9986D8190F3C0ACCCBAF8DB1BF34DC8ABB4890A27100A59D74186C90DFB427AB2B8885E28318C29DF313187FC13E6245406BE4469905857CED13E6EE742E0ABC5535C484EB3A05BDEE17B609DB0ECA84968D1FD84F23D25A3272C0C8E8D36C442E8BD73D22A6A37D843DB6D27E66F7DEFDB17E2AD682605913032D4E0A7D2B1C16A138188BF4E6C664E39B44E21E7137D3A592493FBB52AF041A78B03685ED96F3B70F3ABB365156ADDD0C803455B0038CB78C3F2539C5F3C4469652F2DE704970376BF5E0F7D33741CB9F0C951A9A2D1E5E389229407A507FB6DECEF321E7445A6411665E15B55AA9CA302477BF654C542BDBBFEE658CCFB1280B31B3001602F83496A36ACC588F8D30BBC42830FCB839C4EB37F6991D7388A36056693AA705967631A5B31C9E32C3F5487EB851D22BC1AE7C52015E52D9A8564FA2A4CF95B1BC396BA2683EA7BC966D46EAC60586D70EA846223F598069F5114CE19E66CFE5E0C914398F6568046A754FF7808AE1260E88716C37591F86EBB11B5C4781DC2AF8CC5E7A69CAA2C95757A6E3FDE44B1EC3BF2828FB141ECC6D818E4B3AAB5DF7370B80AC9B6CD31B641C78C939673247CF15EFE409AF385161F6826247E04C41B570714514D77A339E0E5181BBD10DE589CEB9C0D8DEBF11BBFCD8470B7F1643EAA8E5B1F03DC8D1004A5B15398CA4DF0CC7E1D21CA6505C63E97B1D1BC6BA15A79639C53B27580861C6F05C3C27DD0C49CE89FA9E06D91D4B70EA56BA261C7640B77F01DD032264FDD7441621D641F59593A688883D0F73D0611ED90A094E540B55DE0EA852231F89D66E7601C5B489F46C03BA59821DE26A77893509D4022BE166E67F4988F908098BF4F7CD56FA91970116B50FB9144862190A4509A21F9FE2935104751C398EAC656CF3DFBF08B7019ECAB72971D196A05127DE5508FA829E729607E122436D5516DE6AC989FD09C610872A4ED75C0970066910ADC3B1243B5B7AACB5B0078C30C02F7FD4F1DD1F59213205375288CC068387204402790A4F503F7A6F95021BA04425639BE00249CFB48BBA39D2BCBC56665ED7FB172A7340DF6D2CF2DA98B5AACC0E7BA952AC21E636D69E211AA73D48B750AC43152097713A5C94B75086754353566C3FE5740A8E9A1A9E7A50F1B32F234F7C33428A5ECF1A7DC08F84FD232B23A7EA9AA8474747A731205D61CE8E868982127FA52F2DB26AF432B82D9BD0F404DD758AF127DD6E37A10DB3F33B6BF7E68F185144389BFF3A108E46BA5C78A8744C3AFA23E4AEDB480868CC863EC2DCAB906B2CA71575BDA2CF92EE7CF7D0446ACC2BB615BD1C22E6DC861DB83CD7F6CCDCCD52A7E2407D787913F9A7F682A6D3C9CF67176FEF10FB8911C8B097A5BFB76778F7A112606730F2BD723291D061C43F032862C0CB8D24B9F2A607D61A14978E81EAFF79DC316A2BE5D3505C407CEF26771A1B5712601036559811C0BDAE4D1E690528D37EAA9934D6E3B947446BB3DF1D2A203CCAD9D28616C08FDD0DDFA93C6A9F9A4203D883EE17694F4386BB677A2E87BDFF50C2FD65E5D3FD3EB0B640A64241F1DDC08AACBD6BD3B6C10210A22F188596A985584DC1F4CF5A9FB95E8396A59008CB936FF220CBBBC951016CEFB66D5575BEDDFFDD24B3B1584C78BE23785D155763CCC407544FDB0ADBCDBDDE8AE7311A7A0B74FCCBAFC77853263394021720A4818FFF81ADB8FA6FC566E13D208D0EC952D7E5770C51D2E7BEE3DD88CA5C86BB86C70AEBC23471FA7AFF35F4A9CA336DD605692F5F514A251E694D353564564CA07351EA56D6B7EEFD2A91F42903E728F4E28B4E4F8E179119A6F7AE7DE29CA858341D67B4BD3390497184C3D6B5E314CA4A672CD9A6433162F1CAA8F99B951F8A96BF9FFC9AF868EFEFB80C462899F5BDA20D6D0FABBD430DF3A406D033065D54840301508CE9C1556DBE9C0569A048B07E7FBBF2C713669436721A0905A1F2458558AEF2D742389DD553A0B24B44870984F6CFC3EF702C9B334ADACA31058C2848B1973E8C3B016313FF479563FB83D98709127187C5D9F1B8784DED7BD71EDC37E56C673DD886013767057F1A0828F52A1245DCE5A2CCF9DF4BD3B3F7D48D3DDAA405AB338118C22401D1F89C3E880189165682D263E5489C2F3B5B49C7876C086D5B949B9FCAE5E8F45A70015A9D2816CD6E2D8930FB91A2777D82ACAD1745EA5AF57753C94027AD2FF7C5B6B78923A4DB3A90614D45DCCA6972D26257C4A56D8EF49818A857C782B8C70249437F16582AE3F75815143664C3C86A0B5C1D535D49EDDE0D24E1628702F8AD1CDF4F93B5001971E4E44040D84876D4F4ADAA08122945D51D10E97D8CE9265D6FB77EA9FEF4F3D4318537FFACC6F27AEB6D776571A409F10DCD8E7891C87D1B6578F49BFE193E237111883F8CB3E53211D9942435E68994D1518C76AD6E743D63AA7AE0CDA06427BE8CCB76A24613788E445C95ABC17440AAF2664087D5F858A13B540A990A9B1EABA84B8CB07309B4ECA20661EA1A1DCB6D8AD898E9CCF5D15EF4DFBBD8FF053EF10BA5C3001C24535DED2AE9672D22BD22A60807B0A1C894C6413D6EBCB93A6581AAF564938EC7D22271E265D033FD5CF29688AF3538C3C8E26F089247BB34FED26ABDE4431FD9A546F6377BD34138D9D79986D798CE69188907978E02D2F323A32FA672C4990B0D8D8AAECA0BED60AA833FCE874FCE8442030EAF5E27D4027801866B7E814A0559E34EAC2589DA1A41959CA3A59470045B26C8C936B9C1A73318CA6274F66982108EE3C02DD2A60F0173E7AA852C5C2653234C0FBB1280361EA0DA98C49A6796B47E304DD444AD4C6F16C0F41D79BF2497FCA7AB3A0C0E21924542BB631913F6D20CBE5623FE0E454203D084710235AFB00607287F0D80002909E39422650FA4EB3FE8CF08591CA2401200C6C582B0D9EFEF242785FA45A5AD794B4B48123A7BC79E5B0A93824707EE94D8A3B47E3B3264465DD6FDA6E9ED08B80B229B8F621D0416751725CA512879D5BCFA96BA3B7769832010D652EEB4618798557AB93263418CEE75C21207D010CD89D233F2BAC24F7DF5F2B81C2FE10EDB7E36DF226A2F3AA26AF5AFFC401ED3970AB9B2CA8C6391BB52E6982405841879EC2FB73BBBB9A8C11B7963C44ED198D593E13797A3DCAD1665F1C8C264DCE598E743DEA5C2B27FB27A4D9D4DD6D7C36B1C28F7DCF2507E73E7AD755E455ED2FA21ABD55AC993C7A6FB9190A9973C6374BEF1E90C258643C6E24BA0489541A84B95EA8B7FA408DE51451D2B642067D818A0E96118CA26CAB27F5364A01C40B2E7D8EF4C37EBE22BC63D92CA6D9B0347C9B1846233B49E8353CF271FCE80C1A02312BAEF90ADF96623BF29C853BE88C1E41F8C4FB35B20E49CAE3250E13D5101A7208C8AC08E533B238F4FEE97EC21AC77E27BAE3BDFEC44B86822A07B3FDB4A42CB74C99DF12F20B1847DFE782DD8768CBF0E46C77E8FC00E97ED88C070AF002DB58C633A5A2AF9D687171BD281A57388F1748E4AA6491FAB301D34489785B969F1D5F9C2781CD14663FAFCAB26B94386B4A45C78AD0FF7198118ABCF847A147EF4BAC12BA09F64A76BF9E6C332AC71D2E8083B75724CF250EC74EDDA014F529D73BDEF0916556F71917F437A3C8ED543ADEEB3C56C57A4D3D57D1A43349B398CE66DEDEC224E3421316EAF431753F42426201415A9341C384618CCC7ED6C62885148306AA3AA6478EC5345A6E3882FDCD2FB079C0D996D63131FA8E2878C9CD64E1E6A1CD39E90A21CCE4F3F490ADC4FB7D9A5B5A26CED5A724CB85BC3E96E076AD20EDBDEBF6643E215310A9DD7268CA385A0396BDDC5A30ED06B99CC4AF44181C2FCCFA0F5DDEBA6FD1407723B9630D04D8AD5890F010D004ADD683D9131ED100F67157B4729A135CF18E7811C94CDC8351563B02E0A75B24C3F7FC30A0F823E2C2219B0C83AAE9253E4DDD56FF3A825192B2632D8A4CEE5EC7A5C26026967630FC3A06053774E41BF7EAEF1172BA29A0EA2A978571FE26753D813F97EED592C37095ABBD67F5CBD3022B28891DC603359E1D059B118D136120880C1B81E0B83E52421992E267364E6C195AC1FC65E08F101C8B1764DD8BBA2A190E5E4A2086530185AC74360D3B57C72CB81440E54FA3FD31693522DF080BB252B8DB5B4D0BFBFBD7378D7BCF66ED2B6C2DF3EE7BF36CEEF9B6F17E4BFD537B7B606DB7F38E85129D79C1F7A0487FA282E32F24138966E0C57DB8FD583C5A70FEFEF3D7124E12B5B66EEA3C6DE23F548AD14C7AB3042FEBCCBDEA4D9FBBD64D1D42AADD570852B2D7292BBC57334889EAE6A4B7289369AE1284A7150B3605A664BEE34A703170764C22604ECD63245A70E3C462F80871DB42514BF4786E331B84A7B314FC10C11376680945034DFE6CF8DD722FF35DCC49D47F95E137CF80093CFBF36643B4DBD3743528E8B005DF3D5C0B4C6FF67A945CB912045106F35B4171EC21D8C8660F336B812B1623A45FB8E633E4CD72ACB92106AB885E08222F5268B998D870F0C2FDB851D2944DD0111AEC8B8872DFA8F8898278DC93EAC5C4890E150214FAACC657E1BD1409C4F51D7E024028CB353792E255C805A699092741B18BEB7B5CA9C1E97E89789131DA56432285225B1FE9BAE88232BC6C6555AD9B8DF26C51F3E12E6FD7639FDD2179BA5232601BF85F3A029424A1573D64C666B09D7E2D1AEE3D3F2C9D5FDB836105461825514DF2F9D4F5C085A4F250076B67CF58974F2B4E09D3924D73EE3B45BA4696D0E858106872F119668FD6E83CB36D4921DF89D517E33F8238EEAD273D6610BA1AC1ACCCA7AF876F29ABD43943BFB4B8F44C3181E0E4835B80C6DEAA8660474A95F13736243F71FD2D015F85742687F03C9CC6F2CD71DFA3899A04CA1789EFAF251FFEB90A4404178E2B699A970C17BB3E57015D670F604478BA4203EFCC737B71516C0BA651B200876686631AE34E49E5449B507224207EFAE2A1D49E33E488DEEEA85F0DAD79C96E26D6C224F50F63A6A7887B998AEB415F69AC5D93D5CB774950DF8DFB6F30753B1B8BA3A23308BACC40604ECC02A9AF101FA2A907D78D8D3E57D6DB67AA4EDB30815AED62F747AC15B43D21B66DA744CD19A4D03945BEBC3482BAD072BEBC88D6FEA009EB500DDE67E9CE31FDF35C5542227F3D9A479BF3E71D8B3844F88D7D0D80BFEAE6B06A260CD39A44C0E91A2951DAF74BBAA3A48089BDF0C327146F848B40AFEAF9801D9C06C302C4C9C138FBF38DF94367B55CD1AE5DF5F05FC8B9574C2DF59FAD674A85E47FF0D31DA6D2138D40A51ABDE36FF604BCFEBBFD641E1A7CD34C70AAF158C0A1EF483ED9AEE620FFBA7F49E4DC84AC3177937072BF4DE343FBE729C5D98BFD0E33790D33B4970EF27110A362EA5783A2588D8911C5EF2F2A83F3A2DD1A4EBF78A3ACF1A2D9FDC6C45DF9F99BB39D736D2EFF527A2B49B3D71357D9AE66BF3F6298372AA35142F266C83BE0266B4BB187BB82B6AD5C6CDDEFF110DDB21D4CFB77F86F81D05BE23D2A8616019B9D6B7624DA3B9E64AEB1516027CE66915BA644634C43698D89289FCED481AD3855402BA13B3AC37B6A627AF982FA1B49D62A86393D655B138F2B4C61024E5C920FD896945B53F5B96193EB6B49F78F4AF696F21765A2DDCB797420391221983178558D57DE56E35839060ED1113CE8AB9BFF7573586E7DB3A47173FA3069F9DC1A1DD5C0BB4859708B318D8AC668E99B6B9D2612F6222E69EE14A0E8B1297D81632A9F27E18CEC882DFDC3712E01785585D65DF71210B2811EF369E070DD2678B0F15978CEA1409E274958E4D0BAE4AEB18418C30F765017B94FF403AE55BF26D77FCD2996DACEB675F742ABD3274A1EA1F5F00A69834D59F1C6CB849B3B788FE09F69AE0FD91ADC800DC4C4FE70803437950C4495AD07E4905BAA5D732964EF98E787F0B33AFFABE113EB21C2EDD2D964AB009BBC707D2E47ED4891E8CC8E9AFB2D3AA62C7CB721F6B6FC0D2F910BEEEED9C17D5BB765EDEFE04A79CE453B591BCCF1B2EBE9AC08430A2AAE157B27DDB66E5E1B6FA7BBDD38748342429B563F88F6B8F56A48DC9AA578F1F35DB6A5778C8F7FBBD39DA4CAB1D0DCD4125C93F375B2000A03077431CCBA5442ED64B9C567155B99B3E40ABC052A19E7AEF368E9423CEB6DE339FEE0301F8E36544EB482815DF16B7B08446F8FA1CC8081461079BD67672D0B8E1B92EB83497C48153C37680263FCB41A344F4FDE9297782FA5A14CB1E2FA5132E27A36067C3F443B41BE2C21229E91AEBA0E961C7339D4D0C7D3E5F089CFB28EC88062A7F6F157C040DC9258F5449ECFEDBB97F9F0E05A5A35052BCCB6FA886F539A5E9746CC1D3F3BF739B224DD478876A13B15D22CB85F45CA7935A733B1AE92DDE42205EAD6C84397D5EC8C082B5349270BEE2AC661EF14340C50909D9BCA40FE7C939627310E35168C8BCCD1EA82B383AF777528E3BD88B71287893E32B1FDB6803E12156DA7F2A01A557B8D44FAA467F5402A9951E74CDA47D0571776C9284F537FF733E2FDD86DD64C93B64CB331599ED9ACA76F1B29FBE5DD92B01C817B6D21388EEC75B5000C1D827B7B42D9C6FF20BE88AA5DD344E2514312DD93CB91E2A07EA1E7B4461D1BDF084C8A5F64ECBA21AC5D33E59B2AE9E6A12775191DD200182CBEEC396356C7C2389AA41E29DF0DA30163992D3EF814726E6174E4DB2037F836ADBE99F16D136239584F4E50D018EA3FCAAE1DD329857DC49AD2AC6CB33AD426A7EFAF972FF9CCD2728E2AF599BEAF35052FBA7F8FB147FE44ABE88695150FBAB7004A64238F62CF8AC9573699BFED15516384A9C9D7E2512C22D4997B8515D4AFDD1201A5E67150F6F0C8D55D0B4487C8665662E6D79882DE700B9A8AAC2BE98CF0CB83717090A1A2DCA61577AC1D470E02E44297724E08A3E35AE125411F72C334C3A3ED621C2870B222D4CFD6A77EB638DB20BBD290D86B7212E04315F716CED87D4822B246669AA69DCBD0548604EB5B9B61C335B797A53ABBF3789B579C8676BE758B30636C661F0BF8D5A9FC44B259B3FC488361F7D106F87AC72450727172C252BE6C87B07B774FE5E28398C19E77622A515D3E0E3D755C172B2B4A817DCB6BD21FA6803590C06C83CEAC0B48D2D96D2FED23D33A4862658D1BCAC7C5C3C688395A2205403948E42BE5B444E3190219099910CA1DEB71DEF3CA110E744A5770F072DC790BB0BE13A90A16734BEE066C76C9FA07240468314F2723234D4831CCE4065B36275AFA798C1BFB192029382A923CC45C24B40D5AE9E3F96C222B244776072D2999AC7C9870C42F04D0B8CEE1DA96D29A2797BD65C6C9B96D7A6F6B6447B781E769C64F1CB515503BBE8EC7C7E6E1E36D5BC269E345EB52BEC8889C9A5200D708BEC5AE859DF42070EC0DF3E226B41820F1E4E9601289B65C02951F2BC9D2E880C374780D8B793986495EDF6E45FBB3115C9494CE7BBCA00E9CB4756E39DABE13AEDDF629F75C59310E2F7C7931F76D761122CA38D50AAD4F51C1E769606D1E130A5F26C61C3C4803723A6C39923939D30893480A434331C825160D584BF0389667517A81F5C45C5F5AC72445ADF646E25163BB0EACC8DADB3859486EEE68F5FB9B8144DE95B32242E9F943DB57DF6CC24BB3C406116711893CC173E6D5C4D76CF9A7CF5CD9BE4E33D8816E8A7C67E726C9E9F97AF9382C92D38A25776A359A600CDF7496ADCBB0EB6DCF3E87B9010C9D19ABB6A511ECF8A8A240F0CDD8977CEF58B75EC74BB1402F4465DD9EA0EF51DDECC6326CB4018008440737A578B078BFFD83840769139A748483600E590AE984BE0B9484A9B42DF9500971DC5C01CDF75614861BB8C6E5220F69D20EC505AE1F273054A37C177A2D68CFCE1C20F0E65E821CCDD7DC230A57B86E42086A9ED4F6791E03B058ABCE99929021B975F44D339A59404730F8A6F02DE07E9025C62A4AB12436C07EC50EB2B1DD22BE6C00F9B5720DC481006BAD76E73DB21F6B72FDBC6270C0BAC53477AD4561A0CEFC35EEB24775B80A10B80365C17CBEF3B7961EF109E0923C037A5D90AD7290FE21F760C315F18DF26D92145FA45153EE6A6C7A4E815B53A62205207509027CD9DDD484E2CB072FBF450C2B32990FFCD49ACC757830DE6B377B435B77BD406CEBB0051F4C45B02227AD797576E8489F6A95E705086BB9B53E0885C62A519078517E8E558FB322096786389DAB7F3DC873ED91F44F90062DA89DBAAFA2415435E22CE08A7138C7BA39B681321BAB11D144FB95267A8DFB6686139B4DAB4D322C3626562FD01C48E1E0B840549BB8A23DE0FB200A29611CE24CF1EEA19A85F8AFA26284736D7951509E036CED2418627A89352680A83B360EC6DC68F99A9EAA4C0DF5C715DD18E80C321FB76104804A9453CFC69F30D8C7B3354DF690735FD56422462D01240D73C0F4328F964B15C08A1342F4541142DCCA57058980E0D1AECF865A25A9CE3C6D6BA3C9E4F921CB62089AF780E1E923652374DEBD8DC6DA9B8A669848CB1843EC9E961FA0B2BB444145EDB33D1450E9798B09D09D110B4CE5B01A1EA5AB0A626968BEA0FA77DF6CE3227D8B862FF2FF08F49A8C67E5CBDD00CB208111F4B64620DC8B6E55EAD3C7A9B7BE02C835C3F2E5169F054759950CD9C6E922540C75223BB066F49196073E6773F154041CFD35C6AB5B368173EB72D62A401C597C5A5BDC65F034CDFDFDB7343E570527B2316BE395D35F6348D9FF65F2C39079082886339F5C338621F582AB1249479E557306FB2A9EE80ABA15BA600DEB3206A5148DDA514800FFF9E5FA5C8D3742C398C7DFC46BBCE913084C867737EA2629BB7F6E6C44512BE17BCC1C7083B5314CCE72C63B78A9EDD473A41B2A68C2CD585F36BAD9680ED5D92BF056C4542A63DA49B42081B3585E42EDFFA1BC5AB3EA4BE5E7CFDEDC3C86D2E73F2B96D2CB9A219624B6DD14F6C9E8B4F95AD9B4ABB98CF4DEDE07DC38377B730DE58038CC137B248CFC77753641F62F7347F9243E31D5B03312D33381691A5CF9CA26BEA019168F749558FD3D4C4DF0030813D8D4C2BFE3DE0641086760BB0910717D6C084FBE3FE9BFC806E96B7DDA17A1976CA0043C989525C7D3B36E2A4479742BE8D6285E88C4F6124A7CDB31CE9C1BC8E472F71F9B9C06F2A1E17DE105C6B696DBD21147AE06E06BFD9885E075A26668C3734C059A893EF0A980367564AED32702F6FC709B9455A99036A8B86C1183E160BF6C68975F1F60B7A62806C38AF4ED72B07C28CB3DF76289DD3D895C9B8838E80DCB15AF422E295E4F50135E7542D97B3BAED2B543BD645F38B18DCD508D518775F9263C7CCCA963ADEAD1E4DC04D1184AE04B64B37A9DFCDCC3E87493B4FD051D89798CB6C60FF9FF3B3D0A3A14F7E3AE7F785EEAE16C54C1EFCD9A2BCFCD5D61315F39CB3342FEA236E131735A70AE200A45121E12625520961757F4F6D4095F4C72FC003D2E0C25B3CD3B0D67ABD4662E7C7629E3A69FFB4E374436296FAF1DFDB2270D3D41765A3E26A7F4A70B079589C76288637E8628DEE7F24C27ACB94BE16EFD644B8CCE8E4E3435CC734CC72B61E20860A425BDA10510C4B42A7D0917B79FB82175EC09B2BB460788F885C7D1D9CFBB34704002B0416F32FD8AD4D6D3D1D4888140258745FFAED3330B415BB97B0638B2342A1DFFF200E994E3CAFB7169BD07B55949393DBD3AF76C1A7DC445A9FCC1228DD1BF6AA4DE332A4BAAF274C9E34D0CD296666D3D2EC61AD5EFC06548D8A3ED75E4443FB10383B2A2A0CC9BFE6AD785E5567FCE0D25E009C36F77918E28366712E3A74E71DB439E5016EA307EA7AB9E9295404F8121981FC5197D0F5F49D9622862CA3963DF5E417E5AC799BF36CF735BD13986D0C986F684642D654CE0E12C37EF4FA8436122162482B0250D7AC8D4153310C60F5DB0D8409DAFB7ABEA33AD0BBCACAA4245B95657F004186DD23C26DAEF0F19BF04BAAAD738FE8CDCA200E26B56CD2726D3E234B885A5898580082EF73C34111C4E938E324850B468CE55CEF70626815B45F28F8F46762478FE10AE3507A43BB12067560B111D334C13991F5D76FB776DFE554D11A75C2264373F1F4620741D03704A15CDCD41AD71B99DD95860A580F2584216F16297EC9EEE982F0DA563AA850F8A52B68247F0BA41698B64D4E0B45EA877D38CF022C3B123DBC38CD8A57B049726B2D36B4F070BEBD4ED574E594742A02BF32AB3C3F7F93A9FB7B4FDA28B7EC6524A5D3B7558F61443327EB0234F514589C4B2A72F6ADA5C23792C64203AF575A0122D540AB8842AF70712EA1799841382E0E1C1BF1F3F6025A0D011A3FC5B3FFDB6EAAE68C2DABFA6F7AFF53F392EA2A443382F8056A1DC5101A63E92D839A3C4DD2DFB96F920797D54D4E76EF3895162BF1098F844621CB479B0C84F2141B8C15C5C869397DF5C3402DC4DE00999BDA394295C8C4C0E48DB31F8C6056CABAE26DD64458C484A5E3A14761EA826117CE40E000CC557B7E3C898FF866CCB23617C8046051B6161392629D3BEBE0F087D77F13FE42192C3D8EBDECFA0FABC2B8D6D9CD06795C931CCD8448B8E62CD6FD77CA73A3D778EA4D900A6B5E838B63A3FDBE0151D2E2DDF4396EB39A319C6DD136FF0BB05D911670557635D8ECCB4120F16347528E9936985EB03172ABFA8198E3BF9B0B25060C7F98D8CF1D0135607F21C0142720A60C60B0E17E91938856F3E6D64230EEF4FD2077381D1C31F0D3468861571529221E618B70DBD8571BD8F912764C665EF6F35D9E63D7F0627CEFBC4C049FB37AF254908602A84E944AB5316C43CA9B0B8377CB970B251D49B40D37567E48A9E43E84DBBB9CF82ADA6D36261B609A2A9C74C9AEF89E53C1D7665087DC1B7E49F4BEBA874168BDDD4925EBD2AF9757F2D1AB78B5B1D0D4D8678C7C2CA3D373CA2EDE05B099362B0BC0844566325F5A23DA20E5091CB0F6BCC830DD439658933794D748B9444D0181318EECB07A95072C297C1B2D89B89A5BDE1E758087BD6915A7F6CFEEC92916B629D9AEF2462C0F221D0CF50B960346142C05D1699517C8B690B612BDBACD899BFCFC5F93853267726FBDE4780D76EDB01D945C06E68C36C25793247AE0E467D2DEEA330368E3D217C4310A9E95496A68E8C26DFD3C46B91B192BFF168A69DCD01E9C69080638D62A95B3D61328A92C823C7EA3B24B153D7E98130B68A911FE506E55EA8D13B9BE43DF272AD2413A108FFC1582831CE6AC0F5323B7E4B4DB02EF5316D5377C0784B27FADCEE462D6EC8C2F7DE9ECB42579B4CC73911FF9738B1943ECF4D60D2ABF1D6B947400AFA95D3F390E43263AEB32FA20AE7A681263A92E532D9853FE8BB484193654D85469686619FDD3D1F3EFD8BB5CCF83C7BDE45D1F3E22E889AF6983BAC80737376C6E8168175D08DF42B71A972D3E71D1DD677986045C14C2CDEC9EE0A34E1D3A0865244F471C58225220290C81A8115B6013138E7277B1C0C660A3946ADA8596C397318B9BDFCB8C6AC25DCF88D87389F7C192BAD7F9CD32EF5B6077C10DE212E9049C21CE53D3B7CB572C8F222EF7950EA5882C1D5CFFC2909160D3C812E20352FCBB2CBA3DACC01F1818B5AA9C87802160AA171052BC8EB0B2C3402560E182D1D6E81FB967C980C69D761C8A0E9B17C24283CCCD0EF3BBA1FDF33A5DD1D2B650C79B7624C720BEB9D1A4E840B7BF0ACD99A7791D02160A0C85EB2689156E1DB676A10B12DB76390C214F7F404C2060EB2B5AC8C8B90645A4DD28E883EE31BA1360E9423BD642A6C385D1210922AD77A645E0342562552274785F8C14C3459D08B5180E2608AEAA6F6C65111841EBBA66E65B232254FAEFFDD26AFF711446C81526F28D9D7A678F178AF227C2BBC814B1DC11901DF09F1E06B74C072E824DC9605211BDFB3724B55E265793D2F98DDD1D5DBCD4EB3F2B77DE1C964024848A744528CD8A1901E723B3076A75543A3BC27CFFFDD1E4AF13EB15ADF515BB4F9C5617F5B825109FF940A0C9B2D13F61A423B96414CCE06939E56F27F9AED3BB70F7EDED859A03C39F1DC09831CF036303EBC24C0EC4B6D27A9779257AC1AE137CFA2D2913855DC03F4B13FE7FFAFC4D8577C99A8663333228A8C34D6117F4DE65685FA59B4F29069448DBDAF1B655733869DF19D06A098B452EFC875DC7899DD70595C56B472B0DC2F6241AA21C6A7404296BEF57826CB6144DE8E9BE79A35ACDFF638ABA42352E7380EBDBA36A4D623BA598FD374355BCCAA3D331D7D18FFB0FA7C5BD25FFFA863B6792688716FBAE4900C5335AE3B631E707ABDAD87C433E5F6851813AECF3C65256422C09576F7BE4FD04D359E98E7A97886AA27FA0B75446E4500C1E73E46FE74D1ED7FFA99C4E0EC5FFC52D1A85AE6B53D10C7D153D96710439BE0241E483D5D1A3D082CA085AE5521F46CC17F816AB02F3D2D6B5166963E5AFE9CC8EA00D44A139C4410BBA8056D9A4D5DED2641E87A4DA06EFC4F8F7642F88B63B7913206889DAC49576681E704889BDF5DD87154C939B7AFC0E9F542B8CD331432A9388704193A028A24FB6903D28A02F6AF5F3164C2F1FCE92BD35A7BD444D4E1EE7F66153B3500484D80E9A5348375B81ACA4BEC440E7C08F142F494769D21CD2F94F3D9FF42BE3E7B2F0B901E26D9EC9AFCF90726E1FC73DB68A8F10799EA8F6F2A2E076E5BFF97178E1B7A0DA6D687AEAAAD7E73476AED9C557F126B12A965EC07EF78B18BFB02D3806593640F458B243B2EB37F56ADFE585475EB56DFE8EA962A99B18DCC50243F6B802B060EB6972EF33F726507AB3B4713F0E53025179714589845D286B0C767EEFE9533C5613805F4CE848816BE0669815FC2A08E342BF64F26B110A17F875750F84F4152D9EF4EE4A6823A7A5FEC0AEE9FE3E71E532E4084000EBFDEE4D62CF7E64D97E3BB5F0AE6A90E68275B493B17BD645EF6F93E602FCDCEB42F59A36030AE8D25C031DA78A1F40D397FF31CA63945F9815494B45F68410F57FE737A29D4662C81C5953D5C8110A312892D797F04A473BFD2F49E444E1E1D34CE49B56B4F84EFAB03A4EA77F3BDAF507A039269F234D9E74EC49BAEC210AD1935981652DDA1FA59EB5D1806C870175488FB018C9C6F13168B97029B567B9A12AA3134363D506C2E60F4923CA7139BB966DB1A488CC5E5C293C9C29BCB961A897D14E0F2618A02D2A858845FCC1CAA5F7D5A4C175DCEFBAC5B0B34246A5B0C0874FE0CDA82CC29AB6F3E5C8C313A6C618F8A74916DC64BA880A42F573B03BDE96C2B2283271F1E131F30E026BE3ED3480F409A9A3888A5A199EE41519C0D8122E18EF680E9D4038FE22E495FDD4E29B010C52C6E38F8C5EB36BF9AC5D356672B845EEB68100DF4B25227AF6265C42BF54190CCA0483CF2681985F626AAD2F37C983814BFDD6A56028CC041A9FF23DF2D5339D6B654F52AD26C049D6EDBE2A1C01DE2FE9938A7A53A87018006844A2E71BCDC551F667E3CA387177F8BECC097612F3E36B859D07BA09E7AB9BDCFFBB25C357DBAE196B2487336BF97C926B6E5DB7F8F92BD71D5B7C880119CA09266BAE6FB1FBC2EFA9D68503418CDE58DB14C61682362D987784B0E5E53B9F4209D3BF6CEC66500FCEBB84C5E79E3625453EFD18AED6CC0637C8CE79769ED60CDE0E48ECFBE9063A2F99A0C34750A06149E6BEEF04E7BC69C13DD94FC861F7286C7EDFBAC36BD012C1676D4C7DB86EF1FBEA05E9BE6913AA2C2C220A2198C7D110A795862E532C66E71819A1C5EE75C0FD4AFD223FC70F30D389D2715591284CD5E938951BE767F219016D902225DF4930B7D95019B200EE4F315C1252CBF9D0D7E7FF6749A331D7517BE98266389A3F36CCF224FBDDF19CBE92E3F1CA35E51894F51BAE7F18782AC64425033EDD15538B8B83B1666D22096B3268C38C6A52D923EED96526D02D8AC0F872109CD5B5C045ACA82732FD9CEEBB719EFD64D179735F4588105E98FFB8C2228E86E23D8BA96B7EA96F29306CE00F731CB985650277BD57E4F7B3D3928A93F68F5E7F57FB2F8CB5C72C48C705942DAB5932AB9AC63F0BBC666157BDD331B2032C31EE6B7F6DA382A1B21F5B1D6D8BF4BA31564FFBE08E9604F437D27C57C158BA0BFC47F7E9FFEC086A4CDF3D0340954C66D63DC4B4F56C5C58331C4BA04AB67E7D6285E7F8A0E00F6CF7A78CF1B5B45C0FC1AED07C22427313E9B2D92FD43BC12588871447F670ACBD26C219F9CDE40E37DBBBF8016BE4AD962A3548ABAB36C4FF22BC52DC18FD9EFD5B583490031D7BECEA8B83C3BD7D2B31C8313D415686EF791ACB2E42C5841E797837D9AA8B7741DC9CD0992FB27107900ECC50D9424BDDFDB44AB77B69504847E95D725D1DC4A59A9BF92D7C9606C4E75D741557B76AB8A2B1724AD4B355FE031959777BC058562AAE6FA310B9F6C5C5FE4E85D25B73BAD139C6240B38E2A4086EE575FC98AAE4784569DDF5065A080110E3842A2CB5B952D7A797C4B5C5833970AF6F417440B08B5C7F53A7ADA37C114E8C9BEA943D8116079399DDD50DA6FC53BE34340E6323154D1527A7941A393686028BFFDC64E891AE3D50B58D62F8183D230F8D17FD3F3FE6BC255329D0F2F6FCC880BD1845E06E26B9580A9FF2D48C244C6F6419E33A577933CBD111A37628E86419DC220E93A94DD1406D1957664105D9AA7C1E3CE1F47BE0737005E5C0ECAC76D836789E2557A4730FDA832E23ADF9FD2FF9A4831A7F28FB560D47A2E0DAA65E9F5BC491C5C35D606B4AC6F1B13648A2FDF6F13AD9B7DFFB885B782D91D2F9F962DEC07FB917626988568CD8E6959ED7721B38B9B16AB39A3AFC0E6ED6BD44AB1352DBF32E369BA8053BF0BE10CA8B7B7F1844F976B094BE340A12C67585F42E22289D50E83774B125618EC7A85546FA25A09EF305AC4F2EFF291810521A5F08963878BC03251DE97D0E132FF545BA25A5F0486F9E0D65C6DD1260B480F96BCF4E312A2465E38280E7353D7B9F9AFF50ECE83F2DC842A71972A9193C2FCDF79A621C1F95891E4626FBAA0A6BF488DB9429DCEE4E404E043B4F5D62B4CC741E006C597D09D80603C06D0DD5FE390F64797B18E7840B717AFECCA83FD19C44A6C3306391FFEA84058AB2EC8A40C1059C10F85731F45D7A4AAA70EBC34ECE02E8FC2E7F80D496E3A3B472CA6F4D7079BB1386BD88691E9FEBEE3B8653298C6376FEE0D77D55529EDDE44AAF34E96F61836AD4C6EFAD6ECDE9ACBA8E904B9508519D2A7221ACC3297B4C1B02C8495EE86BB3A3648F35796644043B2A157482FFFC5A318AB1B64C59A2D1D28079006BAB8911AB8034C0306B8E2E50AC12FFE492D8EBF62F31D5AFA84830C61AA9B5E26D8211D4CC105405B3C36951024081CA8701DEFBA7F995D31E2403AC87E5B86A319ADE88463D259550D44C4C6BA29866DBF05BD62E88B33401871E2CA3460EF87E7C17457E0278452A30FD8483C79D6158AF1ED06E6FAD27D64CB5BEF20F1EA86BEFB443C2D0B5A3DB428B0FFA20FB808DF245DFB3244A06C27E61801205040A75BC525135D1C327713454FFF2CD654F4AD60E600A467ADA304596E6C427BFCABC992038E1283BC7879D9D9EEDBE8DB70A234782DA230E4A9D80170F0FA85216CB49253D5E8F8C774EB8AEB8D003408F723EDFB29DD82B53249DB16CE7777C4ACCFF7EB8A65C26F2D4C3DE9DCE9E1EB791792B818A949616E57194C3A4513D386CE09D94431078BBD274B45EA9EBFAF7C6125FCB66E74A4C27DB6EDCABDE70F72A1CEBFC110B2A12FEE158D168BBDE90EEF668629B6FE8D0CBE2E7DDB3F4A999A7A477F4BE756D818CD8D0963D3ADBCD3CA5F3493BA6CD3C0F3F161ED7B7B1A43E98D9E2D4C1CA09CB626CC26593F537341D09F1A6B28831567D54220267B364ADF9143DCD9D6AF0BDEA1EA43C4AA098D6A415DAE5B769F996951F1CC57C108952693B3D006FA4923BDE4CF0A9D8EF62FF3D3E2248115CCFA5A56092C46EAE3B7F17505D85375804B207419AFE0C2B0AA40A09004EFAD7D68EF22BF90195D2DB5D96989E05B638E2DCB272078681851E3962B19565EA3F3773DB4CB7DD1CEA9E14B2124D44B298C19FB873C6B4AC91D77FDD3717A7153BC697A5076D08D313A12D2229AA3679F62168031835190272A1F0F04851468180E622A08782B392DAC570BB67F8000204952610232310E8A0B50D2FC2548905AF4EEA79BCE69F32F52F453953D5D8A8356F5E8CBFB54B4FDA8EAB710C8BA6C812633630679D42F5E824421A79E99539E908907CDC1FA5BD3BD20275221A0CCE5C552E2C30D6DC51B45F2C7FD6BABF95D7ADF5F792EC7825AB71F3764A9C40A9FF9F6BE00239A6554728CEEB74ACDC0ABFA7E368F1A4B335618DF4798997D24E0C98D7D4A6A82223C8F5EF33B6A1041FFD4C1C089B2054A6AC3C3F59A67DF349D03F7936225CBC622D7EDB7B1064C56D9FBA674FDF9534D1474B99DCB83951CA4568FEB174022F9B5A78E1C649424443B3ED0E0D9D0D67F285B83BEE459C8133EBC117607F0FA7913A61881919C3963ED1DF3CE24CB1D380EDF2A6606B3F34B1C9B765F6C1796295DE29644A8B37D06953BA629780DCDBD22953C368D112B35D9D7358891D238048EBED62448ED12B7ED672E2231BCE3F23DF85682BE2B10707B0838002FDA683C2B18C6488C7ACD1CA4E227D6F86FC47BA0CC108F1282C64E905964A78940101D40114C81DB93FEE068921E32275D5964E71B5ABE5C1F8C3F70DE7A30C9B14FE857000AA5CC190782D85E2EE110FE2712E09E5EA1530C52EADD8499BC5A010A4CB9EC57547C9F943EE48D48ABE5A59D1D5783B97A44579C181A21FE6E5BABDF61401CBF1ADAB35D42A9A17BCFAE8B759D300D4A9FE80DA497E23AC47E0E6100CC6271B464D82CAC7F6BE316C2614AA883BADA2B360127820229F7890642C11A3FE10307B5C9C63FF0293478AE2EBD9411DB873E56C19973F1E2EB295E13216169056AC3C159905CEBEB3438F6B45821DBB3B9EFD03FBB26D11498ACEE2424A2143860A5F45C5AE2BF7E2FF8C8F414D61B8AA1626CC11A1DD709BEE41A98C8336D4314F03CF10794DAE3F71F51A523F6A15011DC186580A464DB9D1CAA5CAE50A2CDEE55B68F6B353446B9111DBCE635AE253313346A1268DB023EB7E29542EFFCB346E5F58DDBF13FC6BE1AED1A5F19882B3EF60AE0C672BE916FDD97A07B8924481155EEF0F1B5315AFB4221808BB1874FE449E8F005287D095AD2C8E11E1DE5E8B7B91B3541E9078E91949E829C82ABCF05907215359459A089B4D966A7DB056A39E81F5B0C70FF9037C784D74D0D7F7D4097CAD0F303781550300629CE57F4404CE34378672903750F0037AE3182A9529021159103E9D2E009431801DFF5DE94A4CF041495C9D7B8E0A779832875DB149DDE1E1B6FF3204EF75191AE27AC2A5E6A62E1E4131E1A3D633F54290284057131A301CB1661F34AD1C7125CB6DC6D2B35E0E6D8204C82D7A0836FD485F1681DACCEBFBB7CC897FE026DF36FFB39CC344714D64BAA42B4DEA16FCA84EF319948A011DC4D4D8D1EA5DA5B9462B303820D6F5AA6835172B3D0EE0B9B3808ED237C50CC6B8B199E0F8270EE06273F52EA0C539E08508A1F4620932CDD069C20F1577D80EC9F3A15C668E47CAE90A233555B657EE6F0EBA1BFBC72A1C1605166B6FC2D616956A533A886F3F8118FF841A9482A09D26F9F30FCA4B88A724F3466FDE338B442BF1594CB5AE299594FA21E67464EEC4CB85885883018CA735F22B72C18CF2EBB1F64A0D868FDFFC4D698B429147ADDE872EA58D5DDD5670DC83B4135260FB0D5E65C325FA60DED80EE1543C63A3DABFFFD6B7A68D4BF5E4F53A0A728109FEA5B84B9C9BFBA9F2621DB1A874CC956604F73767D75F742DA2D6A9F46274664A9B7911518280C0ED51CB50AA5524E0EBFA328D1A82D217534128CA22366C652D7481D6B61C455F896FE48B562E92F0BE201E498E14556C6657B309FFADD78F414093D43B1675D75EFAE0B900065F0A213D3FF719EC15A39D8988C5566212719A3E7BC3C9BE2DEF872F1082282B64ED4857895A620655E0625C29C43AE2FCE59A31043908A2692110C45ABEB76ABEE451B5DB24A6AD108A75331F29D7B18158E8FDAAF880055BBD3AEC9D0CE5FB1F3F3DC6B0710F67B4CF11DA11084518425A0611A492774BA5C28558B5A16DF308F44CDE9C7BEB34985A8CA90A83F4FD5F6A915D12511BCDD0A307D894A0F360AC316618F61E5ADDA075A46BACA18D64276962D085062BBF1F8FABE31EADD990858317F1DC351ED79772DA1C5788C00DA3BCB8C08EE4A82B3ACEC33B214CD526AE6BF5EFE5E1F4DB818D93298F667BBCCF8B03ED4BBA5CD6FFE764D411F3E4F5DD95FD7109D953E3570E9AC863903D093B8FEFB0E29E0F0FF0C3F88637DAC14DE57A78DF4EFDFA8F8BB9CC3FA46AE9E348C3E075A6263A59CC11E94D08A6F9814CA5AAFAD27F171668C2E79AF11F6F71205756B80B7C896FF2416483A24F86E6625D3D036A1BC391C62443C6E4C833B1814265418BD8D06C4F368A24125906DDE9865A50217E0E2B3D5959742E7A2C7EB1512A9B50C90D11EAA85E3FFCA9A4D90EFB8C090FBF02BE04C8E53319395A538AB4E0B7672B7F92057D033AE21C2BB694B907746A8E0E4D35B6AB8422BB1FB9A05F98C4B81BD6456D68EB9CAD25D94BF597F7AB03ED3844F40CDC47A89B0D6D6C5ABFE313A6864B4C5550787A866B3EB5D199CD9A06754BAF6CF1BDBB2D7ED2B2CD112A28832552ED648F73FD582DA13720B20E4564595C8105907FE7911D8CE26409BA5B1E3C0598B7137056500E833F6B2C9C9CE5F6BA972BD6BF65319DC293405142146D2819D641ABB98E1B3D1B41366D7BFAD7F59200CB2C8969846D80646ADE746EC77D7D900F4BDE69A01634C2522AB0279DFA62C08CD813C4E1AB8C78E95CCFE369B77E031DB96B2E3E49A195F819A8DCA0F6D0C63DDD2BF3AAF104683819CDDE8EEF1203606B16DB5A564974AC4A144B0B24B3DF83838C015BED509636F74A789FDCF572FDCCE906AC3A59508AB012196B0882CB64EA945515C79BD55797159D22101E8968858EFBCCDF961A75BF13AD73D5EBD97B5ACC05FB374FA44030E457E945DA373C4BD066EDC52DD33B603DAAFCBF3C1FCAC26E92DBC27DAF25762F5FEA8BC0042340B4F0817A1A7E0AA353019546DD9487DA133F90658B1A8C711568270457EBC833223DDECF5BA3A517470EB0A7A7ADD9CF29E0E2D29C0D39825F982B80CD471394A67AC1DE9C47A925475578A23B732FFF7A4A8349F6B81315DF089CCBACDCFEF1B395DDCA82A21DF26425E1694E93189480614AAEBAA94A903A1A9BEFD198FE89331BBCDED4FA9B0D85062C0D42BF24D8F307C73FDD467D2C3626E09A249CC2A95604DB8F53FAC2A90092D1BB1B618882DA4F06643FF15C2B3BE6D8598F6935F4181EF7B30FED0471B8CA9DD7A8B606129E1D2DD1FC6E5BB9FAA693318F7E627C2AF80CF24F67A11F27E851D4623992F7099E075582CD13DBD29DA81CE808167E4F5EEE781FD041F369DDE1C847D9911A289A1C0C81BB38C279FCDC75434563D613A186E05676E067BB51072AE1070377BC1A8E54634876B1A87EAE57B6E54EFDABA465B5BC8F3B08F62D05E0AC7CDED8E25CFF920684729961961673D44D4CFD8CC3E4EAA650FAD81F0FA41695B666E782299C8951D98D40ADBFE0B2ABB20506E3B11C8FE1BDAFF12C0EAC70E754232A0753D69B155494233EAA01FB222F35AD6004A824D4B8E673183E70DA8C6593B353FEA535F6C22AAF3ED97054A74298B7430520982E646F8ECB1307BC81F600C367A86373AD1CEAEAFDE4DDA3721DB5AD4A53BBD38F54B42CD03D5B34589C31FE146CA5674BD839FC37117AE32277DD726428630601C0380250EE1825E85A7529B19744A2BC617C3B51EC368728AFD37ED24D709E0CCDE7F45E9DC2A8D67BE0D6285DB75739DBA70C865FE92F9B9E38A4650B09F19FBE544BBF85738715E3AB1DD50F371768EE8FF7D48794936F0FA1ACED34F93068200FBC4ED2889B83130A0569EBFBD079A2A30C16C304AAD442914BAAFFA1B4ED1F215F2101C6E64B562C1B90F3EAA584433566B15F85FFCF7FB2E9BC18EB65C897B9B08B99F560B18884D4A4B5050E5CA6B44E0F1370830C6BFD28A9BE22A1BA13E5929E08625E4D1C1E03DC74265F8ED076F157FECB5FC74749832CC8F62BEE905111A0E58B693DDA4CEB8DEB82092A4E818FBD8911F9113F546F188A5BD4E603AFA5021EAC8E96B7EF0FB20EAD383565D377B0F95E67B34BBE1E120F3FD15FAA344124AF1644D381F0CD829BD965DFEA6EAEB18658101C7592F7AE67F1FC39DD7A0F0A6448847180FB540E40697162A91947287A3139A1D662EBD1D6D84B31D7A8CFFF99433957F4254A6598A5FF01671EE68DCD2924A64108769F7236FEC67369172D990E17261ABA4660A46B99CDCACB88169F4AED8B2EECD6B570651B5F2D52E98CC3B644B5CEC7348A5D5CFAD56F20F50D56B0B9BBC5ED67C9742463CA2F67EDB4DE11AAF86DC593C1800E5A928BD9ABB663B3B1FCC298481AB610468BE28782E4E99B35B1DFE654776A33B101ED42D220FDF46A1ACDB9BA6F1012A3C904D194FD68429D8E8DC8C6AF2652D0AE41CF31B979D8B428EE5878F190694245F8944253B0C7F9B95299AA497CDEAC6A7BAB2B62B73D9CDD335918B88B5E635110DE1998FA87347AD37A8CB90742975D095720F7BCAFE077FBEE941A805F65CC1D2993A81BD08B435E07279EF874EC71A9E0EB1C223D1FD8CE188B188A0BC97F18F6F612198767AF3E492B8511A669AEBC5ACEF5CA697B600793348EBE124F3C4E563C651E216B6BD594E3954F1CFC2938A0DA83708709B371F067EBE0698623E116C6AD2A6E92B76D892A78BB2B945B3D9644770C3E8B2F4288E39E23E897116DC7B02B29FCF1767A07666AC16A59D96E932F45A3737C3B4E34DC711C226507336341A699F220794BBCF43F2F85CA157688F3A857E277C049CDEE2019C20302DB5CF510A2B16FE9657DDA3A731E2F9A7F9EA906F37322391814A404DCB4F22E786A8B9291EB27387934A0E42C2C0E8B16E19F09773148383890082627C58CFD6117776318B451A4937B109FE2A99F6963A4EE4FB1C0756C77A65BF90568A684E864760C5D83335928C32C52B18D353014C60E628FAD479E3C7BFE609F52C75DA0577FE07822DD316E71E36BCBC2A9190BB376CAD8DC0ADDECD19A4F00B1266B5D9A0577FCCBE8B2A291024B841EEC1D557D8D132623E065AEF2F345A8637B98B829C3C829CC366EC203F178BAB620E50D385D5B6A166E2423D694B199D80F6305A0F774A028A2787FBA1545350BDF3741D1A93A9E5FEE3F75C36C84CC876145FB50729A714FD9CAE1D3728A730A7E503B14EFD7C8D0327E4889361E5AFB112B2A6F37AB767CD672667277F7D9A5FFD1602CDDE4BB3EDA0C2EE1025FF20283DFBF9E9270E78D587AF84E03D3E3F664CAF3AD7CBE341357E8AE55D253A2BC206D256E75D531BB39E0FB44FDDD420857EA121A0F564AB2B0B09F0ED03CCD7E5AA28C5E1F92BC7E5B5628EECE630B3E97EBF8121E6B528349CFBA473AC04499F89F551D7CFAFD8EAD067EDC3F281C19A40CD68412E75E63E184856A3EB392A684BFE54205D8D83BDE77393DA4F7085DA165C2754522C8EE05B5193DB3A0F72C39C4B68D2192C7A4679E934D82B9319C988261240F1AE1BA97072037A780BD0FEB31E69351146120A8F583183FAA098D12CBB4A554E185F1C57D90A54C2C09339D332D9F95289D3B7EACE9D435382D7C2D0ED9B8CD7C7FE82B1D28C370B5CBB3D9A4B4E3AF5959BC765ABBDCF2B7DD99D8DE794C07647539D5DF44D1F773DAE156B11CA683FE91D114C0A2D9065EBD5907D4C4F34ADF62098BD69A341A3A546F55FCC8CBB9307BE2A64DFF770AA093E14EB7F3E87E5620DEA6C5435F14C8B583A9749598A1CF4867689EC485C61FD220ABB513774C62AF2830648DB0544DF1196FB682681C8D09B43C590EECA202D442EBCFC328733AD37D772325F7F72BF7B18D38A90913BB616E12021850C296184E7267F5DB6E1DDBCF922BD480135E4FAEE80476641C2FA4C4F6DCFFA2852DB2AC84B70EEF1A520F2EBB1A6388686D5A1C1A9EFAFF2ED3D7B3F7202782B1B0A85C45EF18F40C448190EF9C366ED7B11D5ECCD62690F3328A5B8A45C13B96DC35A98752D50D2910E63DA52590236B80FDEF88564CA51D9FFB86900F78CFB5AF253B5A3E4F6062A50F22103FCD12AD6481AD95AAE97A988BC47EAA196D9C16E0A12D1607D6EAED62A7E0C3EE497A180E54C39F8DE674AC701D35B987ADD0409EAEBB63665F08A8E340C29EE6ED08ACC650FCC26181E337B659B0A56118DF83F4345CDE8E7A900170A46AB2C4340A8D1640E7D545B2F3B338D58012204EE9780AB36EAF2B6A9FFD39B05C93751974C3FD88501543D9E3ED0C7A2F43B5B9B6C6725DECE03BC4119A24A0F9850615B447DD998D1D25705E4D54C287DDF09D0ED27ED52EF7836133886D0840AB7AF9BE58C1E1A72AE6375E9437665E2CE60FBA6B11089D2D9F471EEBE7558C8E312F43D0653AF80D9B565DD29AE7AF73C4DE4F252D8C330E7D2A9A4C34FE011EDBD09328A8F5712B800A53F2DE878DB88EA09349200B3A044C655B1FA375F3EE1D1D0374B3D67970BFEB6738B55AEF9EF4F8CD2D314B64C323C582CECF0D3F1FFFA49F8A3A3355A9BC2ADC132DD9EA23ACCDCB5528195AA61808A2459B20AFB5E22D129BE9B5AB8AC5C0334557ECE0324279234B54D49D93255B4B778FE88E7A0FF4F3509E4EC692A65FAA55B8B309009BA8DC2E654EAA594C39087A6DA9B29D3A82A8E3E9C9D97425615014FB354CC519B1E5DEF86162A29C835BFBA1AFFA06958C2037A0441F9D6E318F46CB0078717B701ED6A88DD405F3EAD0371AE511CC64F28AE3985B76F4357A04B92576F848B65A600F91830241609DC59B689F086A08350CF2EB0C4AEF65FBB82E1432901C009C648003DD64A8413B61D73AF1ED713FAF06B7315272A6246672D665FDF90008C29CF18CEDA72B82F60E52F37D3161C0D051BCF2FEC64F0EBAF710374AC5336934BBC8531AF774E42D341E59437F0E3AF68039941034C71A6576D86AFB6429E83277561DE5E99AEFF577D8740A953887610F696D581C49413BA0D6C3056CB2B3C3A0C1888A47451CC57BD1479C86C7EFF837C73973380AB91094EB94A7FA8BE68CE28254DACA765644EFFCCF8C8FB031620A2130CB650F29EBF34149CD44CDC8A61E28ED887D10C0C7E75DF9F588022AC2C4C40A8AA404FCFBDE3E5547193FA0D128174D0562001E6E34C31AB5F74C4FA187B09DD71035EBCDC01244B29E25AA996931536C643805D6532414EB295D6D8317DB6BEDC3A135D066AE4E16EBDD81B97858BBE297D99207FEFA2D3BAF6E9030E4A0D6C141909F140FD357BDE5FF781B8BBB7F2D608164724592FDA0F6374A3431F4BA0AAECA0E1EC1956BA4947A0A4475D4CBBAEB7717CD0B8541EB570962588F78C30311211E962E13388C66F3E8945F5DCC9D7CC2A7519E4B1C806342A236BAF6FFAE724B9D0D4C82E4BF877BF9AE8FA68A20DD757FB1CA545CC61B668F396A0B98B3FA1DBCCDCB64D6047D53CCC2303A2B1E1C14D9B76A1764962B49AA482A9C5A7C505201DEA3CDFAF63C69904510547AC0F75B5C7668E3A29C5ECD2D2F44BB8564C60305661B7EDD96B99EB4978E4AEE706B3F70232A6F55331F48FA5E28053B74DCEECF6B446E08DD7B62AFEB53901FAB52D9BE4B19ABC2E9CB2F3D84FC4EC6983E0D68AEC479DD0545B59BF8AFF23DFEFCE1481F2227B848D71F590C0298ADD20F82F9589106D879725B51404A9E6280D7896E767F420F721F98190921C3A690FC2CF60EC66498747F49027F50923236A401D0CAE120BB581C11D5FD2A711F6B7A3E19B0BFDC8813260827C72FB6985E066B3C29AD6B4F2EF0EAE34CDE4499B952FF15916BBE95DD424360EA1F9BF55C72A126C236569AE7B480CC58E20B695052B647946C4F0A98985589EA6EF566451409D7E80D9DA23ED7401E478A4BCF915353B33EF8E1BD54787898E17185B99EA43E5624184993190F14545727C32D8F96BD6BB3D4C9C46A7EDFACFE496B53549C05D421D27E008D17114C146B25E7B4A9DF6A2BEFBAC5C91D7E89DB5C3AA8A7B02AD00F6F6819FFCCFF14671E59530E37821BF81AC4A704EA019A77C88F043C1E2E74BFA5BD5EF85F01DFA9B0D165127F6D079216F8228F2CCFBEF746A7905D1D6E69C5D8204EB0F194118ED5AF1740630275408BB57B2B82C49706DF6C9D6EEDFA1F18A1F89F72DE5E7094E46A150A591DFA414D76ACBF776737D29FC5F358491FC3C1509EEF71663BC7C16C30D722D20063B2E6111686F3FA2D69CFFD6447E943E962EFBC8F8B080CFB01F96F1D5C18D6B2CFE6287A674850821CBADE11EFF785AAAD62AFD0CFC7B79A1CC3A035BD4AB8CE4FD75CF3B353B859C967B7DCD97D095E42374F96AEA82B51D00870010B00A0D0E919618EACAACF962196E167810C57F7C4CE92E0AC43E8170529E807DE4CBAFD6DF08C532511C02BEE687A75E7F51DF2AEDE100EB403D037C444153D0F50CFFF508E327D64364A8A0F14C2930429F59F940326A9D6600E73803B165CD080A4DF4458F0CEC66AB741DDB4153EBA18BB4EA5B16166BCA46B05B32EFB762077BF553A1AFC5CA0E17EB2DD236187D49285A464789CB61C8E4E1E532F10E77413500FDB79CC422E8CF1DF776C25FA71E2CF3CF33CBA4016B514EF49EC25DCB7D80F05BC8FF9F7F8CF177125190112C8BE7CC4BD36ACDB76557F4C5DD890D5CF1ADB2A0CEAA2CA33BF6C32975E50797BC6EBD126A20B18846FE1E66C00EA5877C3143007C2EC0402E4F9AC0412488F558CC4A66517AB74B5510141EAADE879F4DCEAAF7A5F8D1D6BE4AE9C0A0268F88CE8D74938AFC56A8983936FDFC704113CF7C03FB601D09235971E56EB8E3E7EAD2C14F53BDB22962F5669C27E3A057FD3C87417688D46BF0A651225D4C97BF6094B825B6D5C9F50699F62B9C6C093AEB9B4925F405D8C1FC19024ED2FE8CD37772351C4A52E957F72242B2A796BBD84DB07C3F29EE0BBAF04D4F03D81C797938CB6C1260828494AD5C497F19C6743C0A07500DFB95B25B1195D0386415F9D031DD870331ECADA3FAA26F33E5478C8DB7C38C931741E99204A54040A44270ED5ACB80107E057B4839D8E16036A22D3EAC33E64E091797CE5DA38C66F3BE19A8FC21492C5AFE572DBAD06BC32B7E3204C1170321A819DD8839FB73FFF7EBAD409F5FEADC8770B619D6E603E7C6BE7F5D094C4FF458CFFA9BCA3BA6A2AD4E8219DEE371F425A58ADD2A606CF3123FC7FBCA54407D64464B10707A35EB9D42E3C9E5FFDBC6D300A8BF47077944CC9906A6D66A0C342F9B113430467B9E3D5779CAEBB5F21BB221EDD8C61D7E91F54AD88065B5117A066C331CDE3FAE38DB490480F607E55E68F567946C06EBBF0DF5CAEB518681A5823B58C8A11708FB923EAD7620041B944017A2BBF8FB04884F6A68D177E981C6DD10F7BE426122E93CABC0F16CD1BCD0D4768F2355883BE3D98CBFB3E9F933E91229812D77AC624FECF9F9DA7FE2FF1F30B28EBCAFBE6A811ACF934D30CC1F1C8E2762D46AD4FF1CD152A3B18D7F09BB75A5AB31976AF8EBCF0C35811C488C62A93AEC349397F888129A4646431B3B1A1A5B543B7BDBC457362EBA1C4527FBF9DDAFFE689129E21D8D47304D3A2DE38B76CBB2466259EC04BD9B72CFA38A43A5A1D0580310A95DEDCE7CD2C8C573A0F7A0C6F1562F115641674B2CDD348A4EAA1055CA05C4ECE547A12805D7F8F2CDCAA9B97F9792C13FCBAE2C2E939C69EA93A92A90E725F0E4D40E0F49073BBFC02FCB5193AD00180FE0D5B9D885F19E431049D985B4AC5921E337E528E472B72051D8754B7EEC6121CA509D3C7FED00D836B083952A836FB56B3CE1CFF1D5B4AF84C4D68C248F7FCCAE187D5D6453EDACBC1E4C971B911C7D98D0A951138E03A3B2B5F949FEB674BF033A3AC6C5814C30A33966166DB0589D7392E421C8020E10B4C2E506F3B3CF6D0095AEF3CEFAC595B12A7557B711D8BD2B79968A4838D581F84BDFFC21B850487D5C461CB8843D3EDA3EC2C7F100A3D12608BAA293AF4FE1C4AE8EDBC92E9C3634B3688C2AF5BEC9E7C3D8FC1CFC13B863F6E67D406200C7FFC6633ABFB03B43FFEC31607B053B5EBA94E797EB56173D4D5D28C68947ABE203B584E7038D7F01A8DE6A31EFB27AE87D21B222758201BBF6D4D0D20916E89CB793FDA83582BC16E211D638C2EF54B9B9746CB4C0A7A0C48AE38629D5EE07207556AE82C7C3708A5786319FD0CB0F3D0603768FC8D2B1E8A4711AFE851C8F51F8C33CC7E558C91724EDB2D7CE0CEDA750591F9C230F1FCB7B4D5CD7BAF0C74E4059A61D8BFC7010BBB161D70935D0F063D01041FBF0EE90C283A78B99B6E05795ECE31583C666F7756C3FC374F7AF283762740A7B0B1F063B89D84BC7E4E01869039AC4EA83173DD992DB861115FC35AF9D6D2A7D3D978EBA765FD43EF857CDB2E65CB51EF90717AB704AD58F17D9ECF954818657A70B6430C8BFBD20EF27FC567274DAACFA0237E7DBA1455692B61751D520930813CEFDFFB9A8C59A2AA9287D237ECDF1FBAF77FD199178EC90C5D0EAE60A9F88D7AB72F738868405AE288BCD8BF5404A73EF6AF08142F8263FD4895251BC0914177647CBCB31E9A4F92C2F19D2EC381E0E5B40573E058B09F04BDC3FEB3395A2B82E9D45D7673F932D3600FFB38191A39B49F80D9EC5BAEFC1C829060C76AB125A5F1099000BBA83A9E933754A4136039D7D56388B7105834B3060C4AA4ABA5F05BF4068E3C3E6268AEF47F52AFD77A1F38BD7F72C1DB1856CEF2FCD9E4482AD573F8BA0F2725FA6CC6A571474B58F4168CB48B2CEE1DBB60AE246D8A17046F5DA4BC430A913FB5FD11947F0573FD970CAF8AE6126690F1E9FBACB49EF0EC1F15CC688FEF09ED34FF257A71EBDD19C11E1843703479B60622CB31EC77629A2A0048C01357FE732E751DB5BCBAA02AB372868FF45E6BD84B7FAD0B3A02720F6A9DA560BB9DAE05018D47B016A6265C25EC1BB39CF94B071F769D5846BB5BA6E7C755763160115E4CB543FD2AFAB507C22B537B131D93612E248B973BE5FCE8E6DAB365EA013AD4B42474F512E06BA7EDBB4210B624B3F7AA73C7CBF9AAA45247F94239F132D0DC39718F0FA640952B8B19D154559181A0E8E8F9022FFFBC4253F1420000892B297E0AFAE7713B0F7A2A8EC077A3CE842C7D93A7A70C389FE9FC9375CB0A9F30469195706999B9EF5CC802419B54435E275E46EC4442E7ADC4ADC5F4C12CB7F5D2685ACF07C30DD1F7E54014458BB6589B2682428E37B667AA59B9D26B33EFDB0DC9994DA9D9450512974FF55EEE040A243FB926C39B39C731DF15B728FF6359FCE45E0CB756C8CF659705059102AC1688A4A8FA164B371B1E77691C3956732DB4C328BD38F59E466C0675F684694B51E11B9A565764BF2AFD0AF856977CF9DAB9FA90232EFC455A66D4C663B28FED0B2FAC76C047D7D2EECC71376979143B666CE6027368FBA5603F745AF75565F8C050BC87651B22939A65A4AB460379688FC6FFDFA9A2D608A54CFDD2771CF2BD740A245A6C80CC6FB086A80906748F45FE4E1BCA95E35F3FEDA84D9212B481FE27BE07719936AB4968C25C1FE29C3CC683E15B00EC7E0A196C1AC7592C73D15D3CA4DE2ECD61C928DA6EBB2F8DEF6B65F4AAAF1DE36695B8E29245A1AB239D1F637C584E0B37FAB4FB14D7A4675BAD72B8E71467259464B6D4B64F4F3F2A215D6FB62203160B6DD7094351DCFFDD97B00BD8932C808B14F699AF0B795F1877F34FBE1B5449A644243B811B215E3F304752DD14786812243DD033CEF222AEB72CDC249FBA2AB109DDAA9FB25E8B425F1B72D67D7581DE6D70FC6CE7194DCDE5835134A8066BD5341C0D1583E1AA555B05BFCA3A6F16AF6A5E7E1C192748249944B504D0E9197E1DF3BB1433CF8D3BA4F3051E159BA9C25A5A3AA6B7F39B014A4E079C465A97071D756F9D510BB01627662EDCA146BD09799D1AF1916934D18A0DC76A059C4A13F0301355F192D38297C3DCE603817AAC28A9142A511CCEA0D44E3BD73ADFF265243440E47B41064AFF1C02A4A9DAB87DAA1DA5FDA29AF91A0965F94199A1742982B9BD3771E6F7272C84A42F5DDACD0BE67494F9F03B431FD2D12C7CB0DC62B787213CAA671FD65E04FA96F48D95A82BC7E09D54E3E4C2970731B4B8FFCE44DDF4B77CC51CA5E9F5AC1ECD70DC44886EFDF12DBCB59376D634F2D31B137EF5FE83840949E88F79C8E7D56C8BBA8556B3DEFF4596A9ECC3A646B166504DCAA3DC36988B8973118FCC47B70B7D60449F3F989D49B01DA8D7963881B716131508D152C19FE499BB5120DBAF23B6B575BD808BA2D31B026BE0472906104FCF64F0180A78BC9B54CF8D2C142E36B6EB453CBF7BFE73BF8E61754D901637F05AE05E4A8BA7D14A07467A28F35C4DEDFB08877860304A3FF5A4D14AD42521D137CF75E8CAC5D9240AA87685C67EB1FD44684B018DA1DF6DF553ED1B61582D9BDDC3273E3110AEF3084D34960CE507D8583EA41EDACF2C7026D2342CAF6165874C1D4E0668F91EC0DA71A641786B542A85E274C16BBAF346A0B1E95D2F0FDC8B650E819828DB3C056A6E1D76D143417B78E88FD25DBFA0C7007371D860A75A922A31EABB28363FD03B126DB21274DEF53CBB348C53BBCE3352C33941CC015FD594C2BA2E412B074ECAB36F74E0B8C7888657748228CE7E4237862BF1052BF8E06EB7057995B2F4E8A93BA4961014E1B68F182DE2D9DF2C58FA9BDE52B421687C0DAFD21459D8FC36FCE4503C0CD4912B425EEE90BC2F8BD3E3D77E01955A6BDF29FBDD2C401856D8D2A7E94CD4E0061297B70AF0E9AE5C6DB7A1BC9E59D6455D259703AB1B71EDAFAF2C696E708DCC341CBAEB63F55F74112F379C78A8CFA17CB67973674D7CCA5B2F5C400B6CE58C9138AAE64EBF627AF6AD71A48F06F5FB90F21489526BF5BE4E894599ACA3F7E71549F32125DA19C8D822A7F05DD34C88A99135475943C6F9B07F00EA521F0292F87B6C43C50EA9252A077F482CBDED9BDB76F4BDD5B602CFA026BDC9649A06996DE68528F89F2787A6426106A8CED4FA033A376D12CB3E34D8AE844C3F7689F60D9DC5FC3E402F70ACD5758EB6EDED67905CABB5D56F01CA0274F221A21DDD30557CB7F072DC253EFF9762829483C2AA91D407E97B0CF1D4429772F55F7FAC04928DAED535D96236749108B7EFDBAAF4B583F4B1425E86F5F9FC3089B762B606ECE777E8C17C83F3FABECAD089F5021117CF54DEB8B6945CB524B508CA7A3AE957E7FC494A0206845BEE1DD19A5069325FE48901769C6F5F29694C14B897FDED96A4FDB461B330A490F2791DC68D8B1D10237CC94043713757AD3337731E6575432A995B6761123D78959ACF77DFF293D3F9564A559D70A9BC0FB57D133884EF4F79F3AB8D517566D34A480D0BF6197A7E6D506EBF8E522B4F33599429C08A6A29400493B0DC39FCDBB1B3282A601E89419C1F937B6DAD0D3384C7CB5E34935E1FD8492BBDAFE94B9FF771C597265C17A2F3377914485E9CEEE7206BAA4184100BACBDA599877FB50B77E065E4D603AA40AA34306D3664BB1A71CEFBE1D75F23BDD081E5A2039FAB6FFA15DA0D012EE105CED14BB1A69EBAA1F9747AD507B1B0B85D17935C629CFB17648E1A45F813D727ADC238F5D1590210A77F946EB3D008C941A9C1CD3AABE2BAE6A4D1D4ED92603A3BC6276D2A90758A9BFC0F15FB1C036173CECC142357B857EF33025B2A4F418159DFFB73733E8A2D54209037F1217228886996C290FCFE144142B1A806F4F9AB6A0F7D56F20686551FD44F60267A27F827E46A9D7C2CBFE9470D35B4897C89FB37DE93D862B0F4F4EEDECBE0C11529ECF74A22E89F70EBEA88E4C9A58DFB34AB2C4D97B76F7651BB69BBCFF91CDA6F6D1E169BA5348BC70F0255E422D6ED99A293163970E42BD8264BE8DBBFC79798F9EB49E5A7EF96A5F1C9DECD7BDDE7429AE8F98B496D4BE2E8D36C274091150977375EDB46707E1A7713ABA629E8D31CFE07E3ADEA89EBD7F95B0E5B8DBEF70B4A8C47C2395DF5347AE04FD8467F7B7ED1B80AC8A12B2D31FE69DAE4C076BE36E42C4FF30608F70EB09BDE40315D98317451F25162CFEB495A611D8EA21FAEBDF0405D836FDEADB7735792BE694D77E42923682120292D9479E0160280EA3CA4CCA55FDE88D5B04B040892FECD5EFE566604A0E639E6E61A1CF3EDB762748686FBBB469665AEDDA6A63308876E760F55C557F412D78AAA31445AD5D6BCD96A4FE37E44DA85CB3D4FE854B1F0C31765A85FCADDDD4478614154C36AC532BFDA4BE5DDEED5E96F811A7CE6CFE03CAA65DF029C13C9406ED920B35357E4DC9C9F61F2B35D6F2A564869B1C3DA8C63BD11D18EFCB264B271746D69DA243F6B71BD16CA8F246451A76E9BE2A784FDCAA714E5830DADDC65DCF1090A710E505E0CC99C0F5149A2CEA7B6F78965FDBAAEDCF5D6AF0E5F120CC015E6B84319C703D990A3D2B959E1810B1EFD49B7F3EDFBB10B3E0C0DC605E5C81D37127E77B6C459179E290BD2E36613F11221AD931CFD79CEA61B4BA7DAD13E2C2B686847ECA6FD2C1F967C51CDE8E08EE9713BAC97EDD2CA8C682178F5455D3D580316EDF348A39591692A0D17F461EC52FA6329EB27BE3C084A010543DD6F82FE9CC42E42E35ECC0249FB2015ED271D2CC4E91032EA45626FEF9682C079D532D780962F583AB39BFC4B7DB5C188056A1503C9B8D077F0CBD7579B0CDECA0AA1A1FFC2C87657F8C863C3E2A4BEFA18AA124CC869427F765C0062359E3287B264DD321DB36F43BA3E664296A9D5B46F1D01E1CAE5DF7B6071483F398D6620518648ECA21554B1CDD146B4C7E75FFB507A38B15AACB2E425DA0CA5D13FE567FBED003B35DAAAC003F58AB8B2E05FE6CCD7BE2063E9D11F3DDF5F881DCADF08D439446450DF2B89FA10401FA05F8A7FC56D09E5DF970216C7FAA33CC10BBF66C703BA32A63B6B9325B81CBE74B767B5C1E703BED90AA634CCB77684D8AF612C0EEA3D12352800C3991E36C55C3CBB3976BCA05B3DC96CBE540E8AD7C3DAE9617B55456077BCF9710FFE290801290188C7F3E74157EAA39C3ED132620F456531362A9AC6AFAE9D4F8CE51AB8E05649C73BB94F2965D2520B23048BD8B001B786CB3E24FAC42274DA19EC94BCEBF479E7B43040D45A8EB97C0FFCD6DBD9260D252D27C6A9E6A21BF36CC1544C1930548AEA897940AF87836596AAFA827549ED196B935C287DB3BF8ABF985CBDB55367F0470E301F40279BE1214975969C9FBB483F7C2B20C35E6A1B3289F0FF701DFC506686392E2ACCB589295822E0D679E297D6D0AD40C8C80E93F235AD239B1A7C5690F717ECE9717B7761F293C823BD92ED4586112BB0E7B83BEF70C76D75A7781FD824FD398106224E8CBC27FBD88EE0FB244D00B7F66F6AC7037D60E9865E22BB923744D459A024CE15C2B444A18D591993E44E7CD9DAC248002CBA49B2F435E34160BE773440301F9FE448C52C1C860D198ACFF6DB83AE2660E2714BFA70C97377B926C75621310C28BCC84EC80BF62A4A05B6072E13894504A712ADD85699DAFB157B7C322EBF8A304A4096A6DFA33CFF316E91E5E28C55E548AA3F428C7881EC9F44702F4946443A31FD681E919259FF756EE487573356AB0A71EC553F9C03BE9089EA9FDC6C0AE5B2AF029C0FA6E7315B00B1B39F484D125234103E533A58459BB84E9FBF7EF7B0BA0743116AF7DA405A49074C2D18D2DDE6184C913014F8B1C887175A638637CF85C70F68D5FCE686F6B3ADC73F370138200868E2DE29ED4C21B4A41AA6F9A0CA892B5F25B6B7CA9746289A86FA6A0E3E2879D3388689042057B9EBF5373F5001B950EB3DA866AE959A4D60518FE478570E7AC0D974DC6EA9BCF538960D276D72F8FAB3B037C9EA8C78E1F8576A9B0C41F41112B8327140A712346FD43C66E89C8B4EF6B13043A99747F16FE0C81720CD3EEEDB2D8F32CEE22E2FD389495CE3A4D93D48EE1EF4CAD73C27E2C8CD6A345E53B6E61C91387AE10 \ No newline at end of file diff --git a/assets/resources/subghz/nice_flor_s_tx b/assets/resources/subghz/nice_flor_s_tx new file mode 100644 index 00000000..a98dcb07 --- /dev/null +++ b/assets/resources/subghz/nice_flor_s_tx @@ -0,0 +1,6 @@ +Filetype: Flipper SubGhz Keystore RAW File +Version: 0 +Encryption: 1 +IV: 47 69 6D 6D 65 20 74 68 65 63 6F 6F 6B 69 65 73 +Encrypt_data: RAW +E3F630A0B38CFFF2282A106DE0BE1052A6A289D3504D92973305D5585B89F2266C3C65900856482523D7F43BF7EA8F0A343E09A4AAD2AD07729F82EC4568B8C8C93A7ADA287B34680AC809A2CEDABC0E5D6E2C45329B479D8534DF7FE06413892F5CCE0848B287FB1A86B11C067F696D49FA92877E75AEB699C176E60571DF927AB75E26AB2A70BC81FB79DB6FF766737C204EB7F836125801F97908E4DEFAADAFC7264B7AC66A4E3B83C17CAAFE1F25F40172A40E20501DBAC45EB588E31C53BF52F0E56DD9035D8DAA423A96EB3F475500BCF42E23E1872A57FEC2756B276F6323D27F3C5670E3B31A399599828CB9AF50CB9EF8453A9D9B2755127197E16BDCA32FF706B6FF899AA4C7E0DBD6E40B0940B59E1BC94E26536565B2034C3D6DB3BE9C2AFA9A88755D69FEAD528288893048395F2048C8C9A126BC4613B357DAE3BA68EB6C0329906026F2C4E751BB449C7320ACE61F018FF12112E0DB70B5C38C84951064D2327B93B30AF30D0C5CFC58D2CFD0726D3B8C4DF929911B0AA16C661B020309E0C6FCDAC520891769C4F52F33238ED9100513DE8735AFA1D60595175D8FB25BFC296C71B4A7F07DDD866E1F1CE498DF31F2B2832B3A885E379592AE5DABD32786DB2938741C3A669787A5F5BC6D1BF5AE8BA4B90353C8A4C29400CB14A0852DA6B84A1B70A8C0DF6D0DD9826771ECEFBF3D7F0F5273A809AEAD79D004DCA60922ACEF9ACC2DA690CF1E2BDA496AF9E93283B2B8610FDEB48402F29C29C6013E23108191D32CD26F9A1143DC2EA97CE731A290E1E0C9801130C37EBAF8C72F286DC1462714A1F8B9B62C3F8BE9C9B75471971337BF0AA09DC21B06F6C905000FDFBB9CB4FF64E86DCB9C08343F20196EEF9227995F9BB94B081852F00E769B1E0437D9DA3E12B720E703748D6461198CF84D28C3DA24C8285AB1283451359621F10E355C2FC563E8FA6C9609A0197A89D27BA97BA0C19188A86013EC800FF2D32282C7A4C88C61F1D0A1C84E33E5CB04F47518311DF5A75A600FC2FADD5BB2FAFA53E48EC68FB703021F19EAED761E55604ED46C99D2AF5D73D7998DB54819219BE5ED4882B04FC7939332F5D9DE78FD4CEAC40329B93AA2F3E2936FA7442AC61CB53C6436E67A965EB6287DDC9FA574A9A808F836191B6C2C1012CA8AF1DB3A901161714955470F9472622AEEA3C74FA22168C0D6888E36E96CE4D8BD215C0DAB748634D69BEB642305B33D070CB0D68D909B174F18B1EA9A957646342DDB48110CCE5BC3C7F175D2BAB25360C9F20E4706188703290FFD3631EFCBC67763A3F209C5931EA6D6C852B970705F066B5A5987F850AE8CB2E362679BB77FF319ACAF90DC6E1783E53E1A2086CA4EFFC86B020D348F36B0A348956C86F9B835293F0F59436A7833F5A4EFA61E914962A77B64A8EBFA2511870F475C4415BDEF63C961424B3628E3A537AA6528C8DCE65850FD57384F0211310D8C367247239E1DB35E54DCE6EA9E9357146017A592DD22C923A817F52B130201B69918EDA06FF5B073445208C940BD6111D3CF8730F4A9EDEC97089005BB51DA32B1A9E70CFD5F29FB03E4B0AC3D5C7C954BAF2391A318B942DFFF9243E32395F7594E9C8AE374AFCD8BC2C3837DC389BE916FBFA610B7DDB2045C3650CC321E8F9EA06B2E9C1536E2AE684D765A693C11169B795043BE07533E6D36AFD693F54F281425F00DC84B14169F82582941731309B1F4321BF365999F5479671066CCB75F65417148E0D45077178A239CC29E7DCC379025EFDE72C313FF693E5BFBF9491F138631A29A2A1EEBF51E842F534A18B955C4D1E284EDC9D59A723709D4C1B73A46D032994309BEB7126602180794EE75178313016EE6162EC196FEFB6F8F87DE4D8781DEDEB719846C6063D1DD2DEC26D8331C3623D1D96565994D96A4F453200E96F7CE0AB7D1BB17319B75F64E3AE9DFCD0A734AA6590094282695E5BF5E8A1E556D2F21AB12E8A16274FE6F1842788DBD33233A0D12B3C5BE416BB1B012F3AA8EB737F94B3B5DB347952202B86BB25ED3601C300172788347F749C183473B21007CCB131CE57BCA30426C56D82DEEF5FFEBC7E941E432C8BB56B1BD9057ECF2F08E702267EEEC408848455F30D7447F0C020CD273B2DDE8E8750FC2313B3CC41125BD44AE125BD53B48C731C0CC4AFBD391574F8AF4CC74B4BFD26635DAB915DACB78534ADDE515B1555D5979007C896AFEB5F9FDA645B64974B715DC6A015162A178AF37AB2755B4CF4A2C3BD7F73D6462C737EE6F4224179853CF7BB62A0A773A4952CF091BA1D5803887EFDDABD777065D2E1FC923E86FA43E1F367FEC620E2EF86B0EDC6016DCB2E0412B09CC8503B996E072566CCE06BD072209C21AEDBC74EF92E4E504C0B36F2F481F484C4FBDBAEFEF0E5157CEF59007B6867E10BA0DCEFF62DCA4A46034B2646156041DCAE4090A6A77C8202709589EF6D26B228FBA9841ED8EC3A154A84974A2BBACB3A9E62600F23E59E8AF9C68B448142BD02F2A0F221EED4BDECE73BBCD744187E6245DF45C43D5C072E848FC529B477E31D686247987CA8DD543C855637E1AC2DEE18DEDEFEDCA0C0E20A62982CCD7182E91BDB2BF2F30E27E0EF71EE6E7C13B03E9FA69567454E4668966BB6AE3F802CCC86C818D4A845CBE16E9199BB7ED08277FD47A3F8CD3474024AD642625C17FF56A51E9C3CD389A048DAAAE8CD65641D530F7C9AFC0B04407172FD1201F22EEE4299EFD1C60CE19EAC7B77D0AF49B823FBF877E53BF8F96916DB4F804F33D3E9EBD7D7459DEC96F1C96BC9D21B1FF8A2B8CA394B809B42C272EDE38C410EF38707CDA8B0857B28E094E4FEF1C227EA2E0659C2E69CC4326D41B62ADC48A22765E6429B28113D1837E2FB8FDAC806FE82F24DBA29FA7D37D1A08B7A11E8A63FA1B46753076B4DFAD0782B39AEF5993C57C4A4F9F484B2BD9B25BACE838251537A02F16FF721CC115B53637758726EE9F1D53E21AB0251B4EBE7C730BB0DF2ACABCD4083AF3FB1D8949DA6E6F835B225B92FF470A9B56BA0BE7AD37699A41CB05075027C272970E05F8EB885FF507909C52466CA80C6A922AFCE16D6B046624BB11F6300608D1D07F722251670743911C4EBA07BEFCA587B09E795FC9014E045325B3717CAF8C5BCC2DBA811DA624BF72267B9795337CFC23BEFB2BD57B4972EF5F4B2AA2AEB5DE5F20A1972D0B06814C78F0FCC8D63AFC4055694625CAA17815A41ADDD5D8F11C155524FE12C9DAFC34912B43B2F83FCD6E103CAAB8CD31D05094245C51D1830F071AF426ACA76D8834DC1466DF3422B1D4008708904372402FD8098FDCDD2145D2E46A3B4FB4C79C0FB5B6535AE888DA607B8EB54B9CD752B4274375FF6F2FEBF66EEC7D1CB3D7BC95BAC1534B81E864C14F9D32D216796ED84510B09F630B7055E83D262C8E7AAC9ABA8955DCBAAF60C191A23405623E82916E49A31423F8523B5CB270E4E0E5461CA333F9389650976E3C37B7BFD1D88D79E38F83063A5C3EA57DC55D08551E9733F438CE5002FF5256CC44D1B235A99E399A8B688207710A8D4CF726EB20DD833BA5DF5B079DEA644DC9164B945218F214F71EBD4EBD46016CC0377EB511E257383D0AD88171C2C5714601E0048E7755F7B9CB9F534FDBDAD52AD9BF8094F2F020B4EA568FE49007C7D4AE576A3DD46C3C7970BC07A2B2C6A908C2D4ACC7795BA7B4357B854D5B5CD7F38288934A79A7BA6CFDC5F3EEA2B765349B8EF5FE52E15893A796D9D3D0543FB9216293808C08FAA921142697AE55A3637404D7185E1116D4673097CF187AAB8B9C42D56584F47760DA41AB0B5579C67D8E014EF55B7DA318430D0C2B62EEEB4697E507860EB1EA05C7A287BA27AE06AC23CD0BD8C596DAB1CAB40B4B6E665C9624A7DA04BE7987F6BC691DEFD7E4C1E9C269A4B34F1FECCD92B7F4B4391D6055AD5AAE308E379787FE9ABB23A655AC8FEBE706C4977425D6A30CE65AEB13A85BDC45AFAC0296B2D5EA388ED2A3D74227E7DE68639441B40B376FC083798F1B26EDF19697300D8AE2DF082F2869344D6E0881B69A6353CA1196DA341E7A8935B68DC729318EE290AB4FAD33BA01EEC7B840A4978B9900B4DB7A7B828FFFB1CA1BD01E881474B0A1EF6A37C7FB7FE2403F133F20C4F7606CB3AA0172CC1024F1945D671433623254B5AC2469923043F3A28D4830BC898B77C6D2A6C412F8AB5AF708AA999E1C852FEB85F60F897EE01077314077345DD017A95CADD4F978A731FA9779748E0EB9B6B2CD6A9F35076A34207F2989FA33F18F04D9F15DB8986907900372C363F0CF73FF217B6FB82D226B15F1446EEA2C7EDD358CAFF2481A31D162EBC659FFC55F55E4A3F1141D6F735696B7322F238AC3DC009C2EF7EBD419BBAD2255DE498904527406E99B60C43B85B7B405CBEA0F7B0FE34E567F49BCC8AD4E1E10771320ED91F278A191AC771AF19DD0BEE3C2200877E2FDCB38EEEE6BFDC723A81BB478E3FFD1D12D6205CC7DA553CCA16C0B857E372C5B765416C303E68326B2B9B727A356DAE6C5713ECA2A483628A99B52269E673597C4F8A01272EDC6971EEA19B13B96F3E843B82FCFD2C95FA154882CCD0EFE2E35DBB5C2BE6B75D12D2988497A2FE762772905E65EADDBE9271665DC730214324EC823994369F97C2FE4EBE266095DCB310D21D73EDE56332D459F5A110C1C55EC9A4A77A9045416E618AB0538162D095D024DF0738A5CFE9FDD023910D6D8F9CF526AC5FBACED4B43362F08B1928A53D12581133D1F9D2D2B9ABC19209A6764D37A559D246588C45941039757A984BCE9D86F2407876EFD6B72C9DC896592A59342ECFCE526152B5DA6F41E4232BBB27668505821FC499D935AB4A4C7FE678C0E4BA8421996021647FF1EE268DEF4DC1715895D8478F9B7B305541824D3996F3B4763A809822350966A3467EF5DC0FA0247F413CE94DD0DECC4603DD171182CE621DD35A8326D5A7E80CA6A6CAEEFF529BD83A380B7CDAD100AC6587A11DB36E4EF1F2F102C5B2F52072E062A8D72334094812A8DF61A614A650E0BE652C155DDAE3E7CD943F13350A95256AE206C94C9E7D5240E537943A772909D2966A541F5C8B7E08FE90BEC85D11B9988E931B181CFD4257951AB9E54DF8643DD9DC2E786B7B9745B3BE89D4EFC291DAB338ADA0BEFD8D0EBBF23ADB320A8260F5932B5E95F00770F742AF457567F7409C49BD5E81D5308E4A5188E2EB67C15A7F6B597DC46DF0C14B60724B25328B819DA68C37B94A06C1A7EB1A03660D56BB12FA5E43C16FEB4E4DBA3567A27A1D9A2FA0D3F88168A04B958197DC7A42B0A812485A59FE7837AA1DE994F879959532DC6A32861C954D72856C690BEF48E8C8C6B637E6803299AAA27C75809A9597EF07A352ED106C33AF6EBD12797D9DE076180A78EAF5330E9C475E6D9D07A2EED757B87898EF5B51FBDAA9ED1E8B5EFD765997F1B4A80E6178FD72933E9B8923F7A2DA4053E5A297F7EAD938C5CE46FA0AD5524576A35A876FD19BBBF18E80456C2F058D4215D16C7AA6AFAC6D57F82B43B067E7A268B6CE62836045ABD62EB8DD0C6CF1CE8D5ACC566FC4A4E4C3839E247439DA30281500FE146EA3024941B10417DDCDD2CF7A57184A81F2898C34EA0CD556601C661DDE85BE1F7A1D88A9CA73DAB343B05022FF5DA41728738E29AFB6412C0B1F9AB78BE9CE81CC0491C07A7B349FA47CC5E2D447E43BEA81671369B0B5305C954782C70B03536553E40300A4D558B21536907B5501F53FC3F2866C9F07F6629FD623FE92A0008F85E0218320FBD71BA710ABDD9B9DF16584F2A5013264F26DC693F106D2E7BFDA98855C9DA648542407A56078C93155E13F6CDF32CF281A24BC2E03011BE8CCA0E9ECC675D3279C29855612AC21D1E040EBEAE074FADDD95AE127590377042AFC716E085C1A19B80723F7C3209C1C8EC7381733879B56E72A304C11EA0287BCC619F82D8CC53604C37C2645DD7FDAC6763EE8F164B43C73D4C397F7F46EBA5DCC24F39A149BCE336659327DEEE063C88915104758E78794E5A5CCF589A5E2EF52C0EF7D64D12CF7F837BCF88E7A188D104FDD44186D55135C7A6E1503301F6F28728C40DDDC9E90537BA9531A807B8C5BDB1E0FBA630BAF8F94216DBBBBC6E7DE713B8D40A6DC25087345810D57A594D663318756645983D55F681FAC95AA1689D2629D785BE3692872A6078962ABF16B51478A5E329B9C2C3BD149B741DD9AD64928CAFC432D40562F713E94AEBA04692414C76C9EC07773FC69A77D9551722A4F2B7683FC09F04607A40D234C80F563A4117710026E467FF87256CD8F4290CFE4F0825B96375827297BA33CB2C229CBB9B71A78F930C251039815D8D65C341134335478F351C8FBDB1B4D9731093FEFA973982CC51DB07BB3EA226036A6037A7C412A86E546034945C8BB3ADDE5333DDDA5296A99A554AA0190D0C49CAA1C9A659DB30AFB28EB54C8273F9D4DDFD8D2BB89E30DCC4508341A1857C43977BA76CA51D14F89167C5C38CFC827A017EBF833C41DEC47D8FADBA44B9A934A4090071305E3D6BBBDA767FD7C218286795D60E68833C3C48B0555DF14AD3868166B6808FAEC59EA59610ED6A7F44B53D3583CD83C0AE2DAF2333DFEF3C8B13565C1A5A32C51CBBC007B6ADC919EAB3D2C35872EB7F51C736AD16F568FA1967136FEFC492346A192FA78C8288A0A8902410C21AC973BD70F12BDC9E4D743D51AE46AF5EE4FBB3558C4D9A2D114D0BC5276963566D45A6FE7204C120FC4F91710E96BE5680F92B4AA29621127B1313647186547FB685969650165256E254F972240C0CEECA1AA74BF55C2416E703730D04C6C7B4691AACA78F9796705F68BE2A35BDBAA07A9B2F72FDB6D39283AB0FFB7FEFEDD153F4B4A32BD48B56594CCC2F8D8121979B4D01D67CA75DE74940538D48BCC1BBAA6BE7B4B767C1728F8E593FE425B6518CA7BA0FA5CB1DB7E0A7B83ED5DC1F0656DB49CB81ACC6375F287CF456C9D905146472B55D0547C856E897C068331D6809BCD3C6680AD27C50E1E4AA28319CDEE6E333549E474B6DAF27772501A8E6466724C8663C353DC6ADA196A60ABFD65AB4F954A0E36DAD3F9986025B2981432326F95E7242246BB08DC8DCEDA683E5AE1D934A7735A79E23E9C56B1C28D43EB33C134A892D1C722A7C6A006EF898F903BEFEFF617D0F0D634D832D6EEE9917979FCECD43FE293F5A1EF4C6937B63C227300882E8776A67435C148BF16358EA9FFDC9C97043293DEEE0FD61F7C971B2456361064CE23046C3EECAD7DCBEE3A4E8120F7BF7CF84F8798B9F498EA352FA467BB0A38672F92C95F22458ADCA319B9CC2D1C01631F6FC2962F6FEEA8D0DF95D40289DBC6E4738C58C98CA57CA2E9D400D19660922CCA2CD8FD7E438AE92F0D26B0F7B25A9E46555D7D2933E1694166F35A4D2733D3985BB46BAFC3169E178276EE7C05E4FA26C41C2F868E10B0C66B33327A81DBABA4130EF066CF889061DCF97736C8DD6F5B7915123B45B9FB7A89A7867C334D957F5B9A8BE8ACFC3BE057A503FBFDB7A47DFF452E57347B66B3ED599D62C1969020244B786175A0D7AD7A35827AA7049AD116318AE25EE56503FD62626F17693C2913F4E85340592A8B83D0752D5CD1EC9E0BC25C60211AE1F49138E457C4FB6B231C2833541A12B368BDB103695F7DAA7A4B2EE6ACD31DA878C20E758011C1068EF4FAD172D82703C2FB8F2D157DA335CC327EE19652E1DF95FA9A0013F912E204EBD9BE01D2DFA5DD3591C532B33247C6394B7EDD6F6F113FA63F1FD3047F954C4EFEA01E2C6A896A26BC85B0383594F214F51BFED361A09BDFA4458BE90006B9097BFF4EA08E96B2D607F78C08C3C744AB778C06500BAA8D598613B92F86A0243F70F5E72B7B3F2823BB837B341C1DCDAD0689CA01826CAB784F75E191BFAF54DA67AC04BBAD3F2E6FC61F80B4A781C515B8E551106E2F64A17FD5B1EE1B235AE53E45D59C0383DDD9453F2E6B9FEDFF33FEBABA134F26474B28F263225359C2DCAAD6200A2708490F5CFA38241626F2D7E2FE82E1D2C933A6F250F2AC4FBF5F54F6A6B863DE8F8ADD79EFC112DFD76A280F83E2F17D6CCEC71D944E324AABD43FF7AAAF75585273877233F1563BCEABD677BAB8C714E8CAC5295B023F0BBC3C4032E7CDDB0276420C0C03DCF3EBA72804E1EF422BC5E91B507851B2AB6096D682424B516CF5114A908AC0FD5E291CD846C98CF180E1E46ACDD71EFA6D2C9230DF51DEAF9BD79F759CC97C06ACB6D22311CFD1133373D1E31B3B5F7EEAA50AFCFBC6112F873F9D253477B12A5D6236C32534B7F2BD46D0B660B5DB45359B5BC3BEB62F88A6BD6D187AF38AFA9204E78D4FEA0A469DBE5AB8F502901D04577A5126C2746B6641517537822261A90B8403A83550542D40625D58B9262CE9747912F18C88550BAD545BF1381BADD0DED9605214A5CA4A137B25A045449A4256F70D3C37A66658888015B7D68818BFB35DECB58E1AD3A1C35E190871E6EBB5523CA91FB6EF61C83C33DA99D36E9E17B1B64C58639763A6024121EDD90F42EDD8B833A9676CBA7A6C0C20A356E9E29125D3E17545EA0BF8F05179FF901CEE11BA2577B9365CD00665A5317FF9DAD1150D361132148F4E0B7B4CA2644B1C382FEEA9831E0A296AE7C73413885E7B751CEB5F541E540A69B0207730CAE4F275985436811563B73C3BA93ED0A40A726C43C2A4A0B9AF05C025DF0FDE3758235DBFFB1801378557466B613C411A33FCB325243E814E964BB9165C04E40FB1F03E40A86A20DB9D33F0A533423E51CF273A789AA80828DADD5FA3FC4EB527A80E941E84D05E22C3EC461B82A360472A674D035D82CC0ED279229F45A098FC993128540BC420506CD628B1E5732703301FBF4E871696D524B5A8CDA9F4A70117711688455C54472D5FD3360D3B5C7DB7324F05B897CD1DF721744490D2878F4613E643C0015F0C870F325EE821FA13E3F08D42B26F51C56D19953053E7287E5A6F41BBDEAF70D06C31DC80CF9739568B0A6B938203601D28C102EF82B651422D1475139669E2E06ECEAFF94EB494C156FBFBC9AD7C7F9427BEF95C101BC2D9EF04F45BFC7870B0386792FD7AE551E4C7642F425DA82473007421F8557369F0BD647E4D47226F51A4C280D0A6640A5D87943D14E5C744CEB7305E86A84339554EE0D10F22EF015CEEB24CA368F34F4950BC8B2496C66C47FD36235D4853859D0246B371430FAF2BEC053BD1A4116003FFC053118CF2C19809EBE6E54D95468CA049815F2B550402D0B1B3ED0595B6D3BB30DDD1DFD4611E1339CDB37BBC263499C0CD45069C4964F951639E1B3D483C8A93A12EDC57ACFEA7738B2A37C7850FF387DB411AB3DFCAB701616CD2AFE95D9A94F85B3F57F8D8731FFA2210CBA4A26B37C05AD28DE368DEA70F7D21F0E187E4E0650BA4CB0EA13EF34FCFFC5283E2417533A781CE3FCF62B5484CA16EEC6D452E7D4D933490AB0F994BCDA468B435E10D4CA68CB8FD6B7A440655F55F6B3E9F737D6BE8E7987C7B02B5388187B07A43C1BF96161524B5D8DB37B766BC638A918DC0F2E2C824FAFCADD43A1007EDA49C6FBC0BC0D0AC73CD7E1058B804028ED3E4B33606E7BC8B2B330CA9E1919E08E1FAF011E2EBBF7674BCABE4E4CA599EB00EA33640EBFF823E6B051AF46CF6296B14D9770D129BA32AA14827A3FED7EE8B6513A7CBD3F5A441234A9A03425B75383801C0F9D62F649B69D13A860E98290488148DE91329CBE31219B19A1A56E0FD59D74879AFC30442FABF8AF40D73A0EFEEFEE41F995ECB715C6B69AEDA0D1ECD29C35DEA7550CE0BCBC52FD87279A24ECFBF2DE0F1162B7E524FF86CE35BA2A4652ED53E29D54A63A5D72DC62A88F611E5056E2481169410EE612F81F82DA5F9EBC54B7E3BBCF0E7055C83E14DE102E7DCE29D873EA6ECA825D8513F45BE3A092A9C0D23BE3DCC6CA70FF0494DEEBCFA3B122D3A3A95906B4CD70E6C051D8CB2A0AEC67387BC8D6EBA28887EC2CBC89D0177F8FC78CDE7EF48413B956EC170F5E7BB8D6F4E115556FBBEEFB258037920FAC8400BCD497F82B02A637C1E56BF7AD9CF9F6FEA23BFC88E72CADD97F76F01C0169B50F682695D1F0C981A970B092B24CDBAA8BC3BD7CC4E389FDDAE573F82D8A4A50FCCE425024B148D179DB2D2BA032A91847C3D30D32E5F87BCA478CB7F4158F1ABFD6735EEB036D9518896DA47D04AB0B692E892DBEB5E6DF71BF6199C91359A6618040A1BD5D318AD005D58B25437637802B3FA21ED33EE80A7D1742C7EFBC8A10CB8B27894C200105353E463F44A5A3F22EFEA2067DF16AADE72142CC427065439768F2BD0522B1B2FB3B6E84DD720ACDA2907E25FCEAFE677DE94B9B9482128D3A9C9BAEB6E626808E0ED68793E7D9F7B9939FF53544A64D3B64738BB3F49CECEDF80839437A10D401A77EF936BA2AAA365B98604321C591D0775AB95622DA3F9CE45B2AAEA1E309F027FFEE9A7D29502F2B00FBAF8FD429B3A619504F781FB8D3F138BD95FAE157D8B9A72F74FBDA2BCE38E27091B4C96E445BCA2873025FDFF5EBCA57F6A706106B5D5AFB873A3936E28BDE378353183FFB2878E27AC7701C3DE744D5D5E14C5B178A96ED15987599DC47B2A5AEEA40B470207D234A6C1B4647A7903E77487F94A4FC9C06FCDECF3F89CD0F61BF7F6E268C797597685DFB6EAF83340ACBE453F1D023BD6A9C6BECDB1D78D5D7BDAD5578DA4259AD83D0C180ACAB00963D58CA856B22B4B4921D11DF4B39F7EF26236083F8949A4CCF81B3E63EA0F4F7C5F585C41131027B60EA777BB5FC2391633D7425A4589E5DA514F4481CA86EEB466E4DCDCE486CA94655842B64546BA41DCD4F5ACE93ABE0AD27EB54D980A9C9FCDAB905F360CF9EE695E56942934B71F0227EABAEA423D4ED7D5FB731574BC4CA6448BBE1B6E311A119977E04F4BBE3411256159A7E9A42DAB737E0C06FCD46484A3B9DA9617EAA7AAE1F2218D630C8CC0F82AA4E418ADD1D1D6655957C16B83AC181B5E83B3D2415F13CD266E7CF8A1F47B010EC1D659E2DF891A1A4E78E3A58F3B4483FEC4C61312985E42AB83FA4DB3777E2670AADAED60C043BC6FF2034590309F9EC2252DC672FCFAD05DD9D7D796EDB7DBED69AC13B595B0F5993976A941C608CAEFF7837884D0D0C359A56A8A0EC407FF59C7F40DE9F8866264598269A724B0C576BEFDF0C57CB3DCD82F37F4CAF9FDE3FF29C26C15F9C0BA9FAAFC8CA5EC77224394523A2779BA6501D74CAE46C18129623929133DB7F773E3AB498A9EFE8C33AEA19B9874E6A0EB9E6E53F09730C54E688D94D0B7399BA105AA2AD9324924CF02F286A39319326689665A46EA16D64A544D6351CB98B7CA7EB518B64007D87EA14CAFF5F01C06C939DB2390394AA9BCDD417572EFE8B7F85CAF472C7AE2BCB623AE19DBCA6E3797F1CE5A2BCEF6AF02EF3365326FE0EB500F4821948E548EC6F53067C0729501260F6DA7F778A0D6CC4E47F7C6536AA5826B928405A491B9D47C1C83EF2B8B22E759BCEC610133CD9F95AD35737FAD9204CA46818FB12CF409584670035F6273970DC91DD68A1A2AD68ABF968EA84F0E0360572F1182D50DE7B462D7B833E259E2D5E96F95B2D64A74E46E00F54515C4EA3115088D7E42995D2F1C1A7ABE8C4629F1B3872230F464F002BACF2971FD1386DE2DF94C58C0C57B29AE0032FF8746DE14A3B8ED4EA1E49F6A57DF08032C9A92DFD0B6067510379A12919D3D203DF034B122C6F44591290FFCDAD0E4FC2B3A162119A5F20FAB27C49F025714BA41522462F8EB94CF5CC8489645A7617FF8D71A7CF0F40005AC24EE25E6B71CD56FB4CBFE776ECBFBE8A93891D071A760EF8BB9091539AEBB91DBBE797A1C061B3A93AF45CE6315B5628F677BD6823D2DC0E62E11FB39736D601F1C4DBAABFC08925DC7B407412F4907D675B0C0DEB6466E1F184E53DE9C6F5B76E89C6DE606F75FA6B3672E594B4F1E2B5964C730430C1BA8DEA040F18A43865F845EA34DC5C8E04B9DD30AAA67F11C6B7D5025D38061192D8F8C1C3A9E9681B360DD390518E5F21A6C8B9CE042799908CF6927071B328DC535841BAD1F003CDF7B36F9CE6B9CFB2A95F6468F38C57F5DA4159493C32CAEA4E85933279CE2ED6279E61493D75D69209E02F44F25D0F8A1E5EBBA896AB306D1C18407D1FF4B7CE9296566D09ED280FEE33F558829E442E07370774BFE75C69AAE2E1B37B2D93CB4BEE21F5D857591972606EBB6CAE03C0A23AB14593DDE050839A95263B7C405ADC4DAE730E95B41D6E26D84BBCBFC042947C50794783F596787126D173106FE11F39AC11C852027F8E027BC58B7B3A4A493308874AE368C69A892093A9267E3662FAC1E74D1261C4D05DBA63AE3537770B6C6FA701952F9F6AD2F4BAF4322E2EA051F3B34FBA93F68D690621E717EEDF4E3088639DE7C2B2E196CE1E635B90DD4A7FB71151E9451F8CD8E9D0D76F5B6DE0E6FAF28BC6A9917FD83B0883C0AF2EE0EF582CB6975FEBF76743F84A2F7522EB2243647166427C84EA85194B526B0BD7599B61CB8D5211619DBB9DDCEB9221567E86116FB913024F58704B76394E738223C72F65469C15CB7600CD14F3788728B093AA50C15E0EEF34D85CEC9BFE99E61FFDDE792E3C9C271C562DEE4DFAA38E21AE86F656D3EDBEA4D4C9B8E2FEC190761FBBBA699804E62E31D8971399B111F1CCCC1C6E7EBC490E2A51C6DC9B32F661935472B9FE7BF0271B2FED155B6682352D3FC2052891D2E8217928AA4B55F8B8B1065C6ED2269F5FC88B7EC826BD6973770085EAA6051F5D49C606DA4363ABE963B549F8A1B89380B0977970E42EF56459163747A95920F14CD52F2D0FF4FF397FB68E6AF6E6349C9355CA9EBBE24F333BA46031FF06865B8837D924007FC52731C88AAB98A2C065BAC7267CDBC192CE118E17D0C25475C64961311E31F77F4955AED1A1581C6FD695D9B27B107E2D82CEC6A9B590D51468BBED29EDDD1BBC106B0C9BBE5369A7D4A476D6947DF9C1BF7B078B618E147FFF55937A1F6ECCC6C710620D5F73AD6E9F5DEF92BC20F43B111999093F09C57DC430F3B897E6574E3819F6A59E7551BA44702CA887A8B429CA12F3D4D1DBD1D18AF9EE6CE52128DAC7914DEE2579E2608FFCBA78DC11B242B2105396195E51A8350590EF1BF65CCE4E1C91B10AF6A35F80E695C95651BC83651BA29B4BE24A59DF2D863820A1ABD2D55327C548FB0A0358C1855F18D28A8A75A136D08BEE67370B5485179EB489CF61BADE151C93695F9754913318D2DB7F103AC3DC86FACA8309DFFDB0C3BDB7702DBD60B965DA897E8C0E7A4F8366BA68FD72DA32487EEE0840D5BAD38A70941D8F4C5347355E76F09977E3303A2D5F2F6E7FC7D0EF69F2F050D633E28A50328AF1E84CC7623669B789BC56C5DF8E221B4F8AC93D7CF9269A95298EEA4A20AADA437EF4901EDC26D076E94F92CB808F6076EB8DCAEAB7E1CFA52EB44F5F5E285409589F06190E88A5E0767BED60B0D9C426D4619FE8016051EC3AE8548CDF7B6ABCB543A6DA02525957E9F16D27AE7306EDE54ADBA8E4A0BCC9524D0A1FC90870AAFC503B837136226C88D03670EAFE4E9C3449D7C14C8272485DDB16846A5809C0E4081765262F75E80787CE2C81DF940FF686ABEFE94E72EB39DB286D9C0830D5AC12B4ED49CB6FD96A494BA2BFB6C7D3C092918195496AAA3C37E908ED970CD91763EE03A88D4A968AB3955148A38C1345CD117D732247663E79706BEA65DA27DBB503C54AA14638D4C5BA92C8330B66EA40C5FF38F6E5EF99292C9019D915707C4C679D17BD35AA40A50E4F837DF9A1ED4F824DF80E3F01B4AC8C1E7E4D1EB0C1DB3F0A748D37AF639FACD6BC6D37EC57719BD0E841A3AF20833D2113119DF327155E28C5961C65FB6B2020F88CADE4047F0682BD70E0CD2BC9D18BD2C62111AC0C240C9E9A64DEA37FBEFA230CAA0B3A87977710FD9356F0B9D03DE2F412329E105CD8A50C1E67CFE0A9CEFE37C681F00D4D1043088A386D810CE619EE0F96C84104F5B21A71D4DB1C45DDBCDC08980C9D881B8A8E77D615B818314E9EFEB5FA10206E2A9EF7680470ECBB969401A30FD6792ADCEE916411EFBA6D8E9D0E584EFC1055523AB115B156003DE1946122488D9CA72124307A273ADD9877F76B7343C877A0435730AD98FC5611E6179DAB485D3522710F08BDDF3069DB67EAA187D9D4D501DED8B20E08A830EF6F62FCA86B588CF4E723D5996EC6A44C8723F293F264BC58AF1A2A076A1760F9B9A2E10CBA89CF8EC72AF7E4D0C0B462AF56F4A187C40CFE68A00113B5156217A335522E64C4BAB084ECAB1D81CE95F7D732AA225FC1B48E1C6973E6E4BC935FEA9BFAD64B6E1E17B908636F7F647AA9C942D13C4502E64E4A03305F3755E69C06608E57DA0D1C15BAB156E53C519E8616729617D17FA83DF9ECC1CA16D5A962A71950EC544823F221BD2807971A94B6B98F50F7AD5311BCDE176A99D30A5422837ABEBF16276B0A1A1A53B9A9BD5AFA07904D06C7AB5006C49F0A5CA9EEFA928059110D232DBB2463D8E13983807342C34E093B28D2EC9648B20BC8EA97DE15A75C3D23F2625E8A4291C921E1D88453EBBDED345B2075E39EF3600BD02D13E91CDA66020015DCBDD78621AFE6E0E68DA4A087CBECA4DA7D869AF566B8F6BBF7F676341E392111BB91439E4F3D0E2EA47D5EECB0EB079A909CCA29BE495D2D42C60E67DBD6C2602306609F9F22F58F0A9496B7581CBF0273578D62B2C9FA1AF14C1EFDC9508C077E547760AC635780981A2F7501E41717880A6D6AADF43D0C2F4D3F506E0E68990354924A0CE2BDF58E301102E9D7C87AEF8867F39A8B6D13F7AE75EDB040B0D56843ED305D7DD3B961E485C53DC07620E21639A90DC707FF413A932BEE2F18A0ABCB9AA2B262E8B32A5D3FF12BDCBB164E518A43C775E219D32389A0921C7C16027F5B9F3F76E274B9847FEEFC8A815B37345254242AD0318A79D0F25ABD2C92C909597A01FB606C71B1605ACAE8B3C9FB23C5759A422F7D14026CD8EE515CDD59F305E1E1E0A4D3DB5E7253FAB5AE2D2A8A8283C9F589F62E5F2FE1E930B97945D38252DCDE3C0217294470492CF7A732715CE37104233B172827261EE0AD499876545BD7FB192F16505A2B3E4C3B6E1DA9DC454DF8C81217C4EEF6338D89640126064935FF05FAC6B834AA0924E00B521066FF148B322230D4C622F6FE0825CD5C81B4EA12705831E6051160FF2F77A2342A13063A4799955AE05F4C8BA8486DFE9EAB459FFF25EBA15DA88B798E604D62B1C409C8EA95753A9CD2A9AFE9B123852E78A9AD58D522D1F7B0FB4BD47E284294EFD7CBBC261B0A9957EDEC2EA26E5ADB7C7D36D7D0B9AEC217FB229CB9D08130D97B3C4760E2838E03BF3DA6BEC98956B88DEB827BA2A9F47941120823CFE80E7ED4CD1AAC4BC8788D3CB8848F38D32A694E4F4A9EA5F492F2DC4A97FC45E6F93D303545B5A96588B20C3B67F84CEE4E51BCF0FD5F646A88801F1C291863E9A4AAB80C0698A0D7D954C4C843BD3C2BCBF722BBE15A6058184CCAEF04693C71F23729DD4F274B63F955F8D14EB4E63D5EE671CFCBBB06531A5EE8C0093D203405ACDEC91E6544A2629AE616694286C7AEABDCA3430733D871AE1C53DB1BFC09574BE1A84E14FFD970CD92BF6839F961B42739EFC0205538E27DDD969D485B04201AA9B9B2DD3CEA9594D1D9C0B4DACF86C23B2CB27C368FCCCF14DEEAF6184F2670EFC8D22600C7B39A705B648089CF3DC2ABD85FDEC35CC6FC131D32CF2EF6BCBF66B90E15062E04CF0E137AEBF128093692528D6846FE482FC8FF9E71FDAE5A9C40EB5E7E0CF1088E8BB20145293FE6F5E67EB24EE3E711CABB65FD09EA323A6F8F54D269D8D5AEE36502F2ABC1785475B860DF8DBA5C1B99F98C114E42F1825ED57A8D34F45BC32A725B14693E5298715B87A35732D4061042724842C897AF5EAE452416DBE282A5378A7729EFF183C64DC987651849323588E2FFCFEE7B871A9C3F4BF9CFB783042B00F069E666729D7C5CAE86534F6CB861ACF8FD65B2207879329DE1C7843E05BC6498C32759AEFBD3EC83D95CA435ACD1D649E8DBCB1EEB25A959FAEC7014B5E25F676B3F9411F9377DBD7FE40816F90B70C42A061996F3B7D3138AD543A0D5283E59BE32A32AFED98889DD5C53399883E2252EAB0A4849158EF07841CC3D628010B2E3E6D18D198FCA7D6F64782DF89D88CD33BBB01C1E437C70F945B385B72EA1B3367AA28160B905F44C0CCED8FEDBD0F806216F4818FC2AF9297F2CBA12EC0F60ABCB6F82D54129F0E43DC8A773A08814784CD01C10CF9A0F4054BFC7D739217476957F467C5B533C15F14C657D8B410DA43C42AFF55AD4CEB7B90CEF86EB8DC8727BF58D861C3C55D9D4CB131CC710D59A6906B734D1CA000EF19E117F2FEEBECD517D782014DA621BE7C96A03C190CDAD22846E0A2538F1FFC0ED22E98A714B8576A91009B00E04CAF803D7B027B01D865D1B464B3740D95CE9601858C9ADD5801B12F89BCF1BE5E93EA03B44025136E174104A0B87FC15C379F2CD9150B6CD1A3CD87E9D85F4D8A4F0B38ABD2317DD37D1B520FCCAFF33B089DAFD4955148D5CF0787AA71EA660D8C89B0C22CDA21E2AF94C1B1075B6D6507AD7694BC2A94F0E76693D5FC2752A77505EE58BA4EAD0C3E25FB0AAE2D1C35D601874447AE78EE1CFBE568C35BBDC9FF31442A3CD52C308E3F6AD641320A4800C40A82B9951E401D1A536F49DFD29206BF5D7862ECF25684E706A6F07E2A248D3C3E4406E01BACC7CF3E526E63AEC00022B9D90B25E80710737675BF0A51D8CA0ED561DF1349761EAD4D70DF80FF5A127D39CF83DB94B0E562340EC4B714A61094CAFAFD84A90457BE68DCD9420408261DE1AB7A00014AA137A12246A7D4142506F44E621882BF3472A7EA61AE82EF9468BFB4D9A61CF9883007D4161BCDC85BE709F6326C03F0998E6DFAC59E89CC439ABC06FA4321DC0DA46A19F4530FC0D9D0BEE089381DAFE688870985ED291760DBEFBED70DEEB573F004966B176F7B361EE01EBA1378FC37CE09D360FBE9089F4C9CA85EA36F363C2C7197D952665DBCF40F07AB9CC2D12FE28C5ECE7A107D4F5A830436F52015DED2D1B39204CA935C68D5C34D746AE59A6D9B9A7B5E46B91EFA0323D33E5B397613842A7D4DBE47F2624BB400DFE28C35D322B5A5F97653F38AB0955959BA501B429CAD33FDDBECA17BCBF26980D2A4269CA68BC4FA5AD6DF00C5D3E7F2653C72922B0ACA3454C564A89BC528D01011A74C27B606DFD5AD051166B5C1EACCE5306F92418A9A4BA170D8279676CFC4D3B33B7611F76A14C46E300961B47A798803B72E1E1318EBF9F2DAE26AEAA137C7FBA35A3EA23051EA5FDFD0D734A391D120B84F7BCB8A9CC1BC7BB5EC08BC9DE4CCC894CB47DD2463D2F47BD6CA7B2F5D7FED2184C22D2D858000A6F19AB4A9391770114EB4291B116E3B0B39B5E0C2475863CD5E0A5E8F2DC386FE2E7309EDE5D067A1053685A9C08B992203F5F10B39868561E22C76725BAA96586E104B68E041E00699DFAB585998622CBE7E27F278F5949467C3641B3EA1E3EB009873E92C772E604F07305CDC1C679754523F2E076718463883B2D1917F2250BB577CEEDAA3759DD4D0D199AA1B95C3C6839429E5CA827A29046CDE520B2C6F0FB8BD68059845BF3C44249DAB022B4479DE1D062C27452854038922A6F12901C14A8431628DBFD90EC9E29D5DCBEBC176897E1A57753B5CE61A86D4AD3B18AF428B2BCF50BC78DFAFEA37967C207AB6103F0FBD39A167AFF1A10948BA3B8A428B91530DE9BCA0E150F0ABD23BCA674D9B81E6C30216D6F11C27BDC3BB7C1AC156779A2EF331726BA0F3873C86F9580113DA445115582FBB07209E9ADC1AA57B972AAF1EA6E15581A44F8932A13E7FA4D4A545B0D13AF47560AD8CB2A792FE4EA3144CDA4DECEC6610E05BDE90AFF5EA403CE9D283A70F15D09A33FBCFEF371D1BAB43B92FF3A8C31B05BE368E97595054AC320F72298CD157B7CBB38E199511787B5273D9A230214DEC60D1A8495AC7BD3604062B4EAB9C4D2F88E95547124175843DFD5BC66B489CAB9B7EB30A4D5F7E2432EA25CA2669D1B65926A0D2CF2DAE0D535B0380619D4422145293A492F4E3282CDA6232914CA7D13AA6B4BE529576325DEF67237BB33F0DF704E02B436B7EB7044F0A76CE4E7A494E071016130F2CA133A2E2F1F9B3FEE4A0939C48BDE1C36DD4FD792F8E7369FCBB6D94C96A6B9DECF5A2B618A23CE22803CCBAA63CA6E32EE0904B3EC820CF84B5744E3526484CB0312A622856DB41D969C779AEC27D257AB57E828ED4CB40E5A917722BBEEA4CA441E5AB0FEB64CD2DE9BCDDB61A270F26B94DEDA3E987A56C6F8CCFC1A43C7D0F31BB94B38B1630F3583B08BAAB4AB4E94A78212FD367ED8B6C499BD88B0A21447414FB0B4ADD0AC63BE6497439FD724449ADE3953DD7FF7A1B364F38D4DDCC1C6B0BD1F65E17A1DA03B02D51E97B987DC1E31927D3497708085C64902888F3CD851155D6E301952304FC7F1EAA17003BA7B86DFE9988BD695A87670961120A30F3A6D82BC843B25475EC1CD296137C6F72449548A058191433BC884E9B5EF874EB55B9E18D5DD78E07D2AD8BAFBB9050FAD4015E9825171CA3BCF9A9F0EC6619B2DDBFDC7DD29ED7659BB623447D2C1AC1366C9833010975EE7C399A006CC1CF8C254757CF1994240D3BEE84ABC11EC9F7CCF40943065068ED7F9DB9A98771747ABE97612F66E946507E527658A487BFB0E8A582E8521C10F2EB3C0F2CC48A04DB4A243935DA642C5F3D4E8DBB2B833B535E76C2AC4E093E766A5E031F3F074015FFD12501063C0C9D76C0B64C14D70B8E561FB8DF19D119562C0FA5783613AB47282E2027F883204E0E6577C5B5F8A919E9F73F739FAF8F0857B77185CBA0C5B67ED95EA153E7F9FF033F289D86D9DC2386DD04D2B2A91345D4F15C9A81D1D1E9B9BBDFFD5EB3364C27AEBEF1C8C1E3746D373779D047729B1736124788A097A13C4E278A08518412B5877902505329F86BDBE5D6C612E924A88E3EC8471F08726765C849A9446D9F196EE26D342608610E2095CFBF02AAC2B7CFB881F3CD3594D35B3A10BDF0CF4EF6B3D050D8D1B81350455210D89D6E557D2BFCBE8D02DD7AEF405DA3374A0720A3EBFD484569436205EDD705897ACA2DEC2CEB5D865371C1CC63D7FBDF0E435163B3CED3DBC709D8803BEC24437C25F5AE07A6C30CB7D11457BD930EB8FAA601256FE74954FF51A5A8EDE76C9C4DF0BC816D03C7BCFEC30E235AD89E7645001649B87ABCED7FC426ADB8475451A4BDE88F5C770F468866B9BC80C5906E2910F0F52CD9A6EF3A8B22CF4F00582814937A00A6756EFE0985CC9F1E2F86241BFDA7BD29336F7B318F44787575CF6DF0DAE8A9878156501ADCDD36CF01EC5E4A23657C71EF7AE481A87E6EF1EE97E8F558A5D6BA5A5BD45163A3709F9021BCB7B9C75ECB05CEF65F1B76E032B1EF140F50226F6AAFA482F9FEE87D77FEBCC6443FB8BB5AEF06A0520ADF6688BE16075593E5CD1A01B636DB9D553D82BDAC25DF923D7DEFA2AC452BBCF74A1108EFA28E9461AE96AC6C58AEABC04BCE6570EA3CA4957A9F58B5E943D4AC2030C72538D4994379216F40949D23D06497DAAC54BE266E4BE315E129B3169D945D08E04C4DDEA9C81F00B0E4490C3238C7B3CF256A06CD188D32C7DA5E885DE5992EA726A618CD1A25A6D9B2AFBD4567CBCFF076C99325BCDCD49BC1E8AF57E172324D8A4A4094E798CEAC864AD2CC62867EEA1A69F40A39D80F431859908DB40EF68DE599B63D852DC2F7E0C1B0B4B8B486D78679E0C51B9DD12C9D764647CDB0DE323A505990F36A9692B9E5EA4171DD2AC9723FB91E0B5678ADDD6B0839847CCD8798E3B6F7E76B01B0D5FCF80804E630303D389105A3AB2FF472CCBE6AA42F2A40C16DA9726B85982FC81DABDBC7D9E267CBA036E443E5B4C601D1B7A44C6FB14E78A44033AD5469000B66945EDB9C9625CFF19A67D5B39E2B02329FEB6004B1BDB9386344E19194B2EA4613506C2E48BAC08CA8E32856C3208C3BD15B1C8A0698484EFD25B7C0A22640E4E8F3CC19B2D6A47463BEE7885E9602B3BE2D93A782C400CC765B7043431ABC5FB7121051EE726AC87D09510F017D64A91941C706384B6B98D2F6E031652FFC3DD99A558BA40AE152833025E1111BCE82FB66AA9F374EF815740151F778872B61B6C43542F01A59FE8887732700CEDBE5851A95137FD722217EF35A3860A7F3E55670959F5B43B95DA10E8BB7BFDC58D911B0E4BCBEC54172B1C63E739E64BDD9861E29E13097CC81D7063DEBA32980102F1A640D279D4DF0EABC4992111BFE5B8360DA61FC476291FDF4F6549B2CAF55FDA2066AEB38ED4EED347F268AFE17BEEDBBBFD5293F22D1F2254250B3C702AF84E468274B30A1B429158ABED08EF10E691C3E9834FFE8CD3FF56DB9B8060800A0E5EB8FF7BF26AFC35EFD8F51108509F8A74B00A5E8B0FC0B49D016CE675BAF98E4837569D8A36E3EF4BFD187D32B79068E8B71BD64CA24212C272331EB31FD4727DDD9D73B0F4ACB440621F94DFCF8698160ED112FA06C2B4B2F56365EE8FDBCCA9594B19CBE71F05B999175F5B6D604FEB47634F35E4795837346782E60067C42C4AE413657D01C3D401261C4CA91D456FDFD20CC719C09514AD3930A24DDC3B14ECFA305FB48D7780866D4F1C517FBA69222B8713EFA46CBEC70EC87E6861E7012D9DE24C7F6F91617E4BCC8CF07C9465B0020EABCA3B049AFB5B75F2EFA7D8881AFE4B60A47675F345642BA1CE5E0019F2E34FAA2C38305D39DE10C256343BF456FAB62913F727D1A0E41585FB52A46EE4E154BC4B8E9EB983D6BF63CA77F66725EE43EA782FF1549E014ADF0A513144A55A5B991B456C2605D2221520AC4D0FB5E86A843408EAAF0669B1CE8BC9111AB0E915F852507440CEA28B94C1F19196B466CDEBD345B61ACE9B963E3E2668CD4B7A5BF4957512EC29C5096C8DF54A8E392173A4FA678D3153A3531E212578F0FF46D33C9BF6FAC36F28BE55E85A8F5999B8F9523C63B4469BD252CDA351F2909AF580D769B64877F4601FBF08DA4B253E174E10BE895A6DE95530F84E2D021EDABC417BBF53E9995C489BD991C71C9DF1D5EDE51434CABCE3C3F7B78DE7F59074F827040508492EC28F41B6F3F502EDCC26281E26DB86F0F55E6808C597DBB6AB4DCDB0BDF8107D85323AAAF5A4A0F22D5738D464684F30D12E9CF8C7384C3EDAEC3AC9701208631696E71718A7A8F57101656392B51FA005774FFF605074734A129571BB17BA6723D0E7B89954A0B598C1799F602C3E94896125FB9C32D07EF89C7457DAAF938B3B378444CF75FDD39F22225B34A1C92A35A2EA54787D301F4E5830EA02B82BBA86EA0343AC37B3E522BBC9DA6634537531D8ED3246B204E67F513ACC93D05EC8C35CE5ED7E970BD585032CFC622C8EF656ABE7EB0495C081680AE32C70209850E4E9FF72F0ECCBF4C949BEDC5C4CB8AAAC3A6CDD0ADE08FDC0D32F307307F65AD89320472B557E18288E79E98AEA234F159006A5CE94BA8F29E7D45F41D2BCACE3601544D26B61054360D145871461AD8F5FAE0E9200364D32AE0CC3F77DBE08A6DBCA210C0F9EC04BE273EC3CFDF3F2D19549B40E80C67C925D92EEC18B654A8FF68DD1E97009506776E080E83998B0AEA5FABFA1942BD7D49C816B91B5AF2C5B7CBF577711D0044AE51BFDE08E8F1302FBCD335BDBF0548736497841D315E384E578948FA6A34E91B72CF14941ED6BDBE47AA5D0A7CEBEE6FB9156B8BE78EAB052AC6063C8882B18A56D3C1BADA35D6C5144FD76D16A134B46D989CB09B18520CC32465FE71B5EF7C503550F0792DDCCB25BC792D968FEF95C95AF14702885BC300E564BBD8198EBADD62ABA5F4DB6DF05CF2ABC5A19DFC1A7574B55AC836424E8B6F433703F735430B1B74B26C7B825AD331F92E0E16780B4C124441EC940905A422C0E719576F7FF6A1151E05D0C0D82A274A7DB8CE37E0473CD1A91DC73AF502162A2663D12F50304869AF0CAC991ED398712326BA2817949E2841F833D1CCBCF84E5E1B72F952F7F586109E4C61B237CABF0D71B759B970AB345CFD10856DEA7B59883060535318F4BDB14C66B3C8EF97275CE8BF1201B69D9212DBD9597B0E3D01D9B060370C3ED15E1B68E5D4E837144DDA9C2A22455D7D9A72AA299C7F23BAA921EE6E175C1A1625146DEBC0D0E1835D1311B3ED724D057F7932DA2D76E3B35BCC88E3355C9B508916A3C1663FECDBBBB9285E9BEA1BFA3102377A0747D9BCB05465E3DB5CAC183CE23AC7AE30E4A538DCEC3636BB4E55417E3C8EAB818E393C2BFE9D9AE4AF24D7A3929B3480FD850D5C443F3DDFA3E24FAD8AE01AAE4D51ADEF1262FB616CD1953B8F58AEB47890DC2188B725705F81D02480E0F07FAF6DB250926414D74837BC5E17035F8279A54990CFCE3C0F923A262002DF7187E5CD4D1690ACA890CE41F8BB7CC541197F3F083BD3DFBFA73FA6F480028F296FA791D60B870AD4F794D9844A2432B6610CE349EA102B5211C93B99B163BCC53770C69248AEA24644495266EF1B86D71542A1B98B3E6CAB02D117BDFDE893D1D0AD3BD22CB874DE3A2E94181A9B582FBD83367919730A0CA53758D46FEA9B9D07E83E5703C2F7C3B583F9F9B4BAC169C5DAF9FD4DE31806A62C202936D83DE25C00F9F226A24CFBB10A05060D7B07609B1D4C21C3739E1DEF73F3A02F19CC4A217BE57803A755ACCFB6F184B13BE3641B1FFAC9D5528A69EF55B250F8B18D9700A06246B115A32FD791CFF6835BE25BA35A9866962E486DB5EFF51AEDFF57A3A671E166B2E8A5DABCC5D67E9ED21C405F0C24D3B86269A33FD4AA9C7D1175BF70B158D975FFDCA790CFD51CCA4699C15A1AF364606455DB23E8A8F84B6C6A12400DADDEF43EA7D72316B8D49AEAF895A507CC8AD5EC8E08C764F697B4F6EB3BEF81F64474770557044D3179313568E7DDB7DEC552307F28898729ED5CBE70FAB442E7B9130E48F4BDB9CF4FF5FB4FADCA3DD7B0CBC8778FE3A2FBA9DE3FE3B6E951931D60854C04FDA7CE43B600E4A10A648B748CD9921E0D808A5AC13A361E48C42C3ACFC17D808A9BC12376BCD7A7E55FBEC6A2D938AE378C3F7CF8A5CF02AD49009D0FE5496F6D27F8E4E501067603CB18D48F0E7F23B3A09AD652A6939066E2BC539F560BFA836E65B19047429F71731B41BF2C08391D59910FCB9935BD115D79245FFC873976A8402BA445C9555CFC8AF05944B817809C4151520C228D7454F83978CCF0BF207D7092B737DB7EB0AEADA61F65C05B1549A40FA65F89D05E11A7AB0E39BFE31FA31CD1ECB77B73B945516B78F17487A73BF9EB434940016EBF39E3D630BE0D383F61388449394EBFC467F7E9A191BFDA7BC2BE8F86553E884708BAD508776CA041EA32FC8BF6CA5E979C5ECE7FDD3BADCBC5425DB4706B68F5CF960B6F03A3F4E62D75A613A943E26B6AB3C40C868E77F982D5FBE9FF35FDD07C0A051E9CBAFC57AAB79D8AFDEC73992F0C1C2C2D9BAD4C2A6CFE1FBFD861BFBB99F345964B6B262722A5507083648D803178A633FAEBE38D03DFA5DFCD2D54CD9422200CA078435AB33773FA8DDA49A5DDA920C2A5C9494CF8089235F2FC1A15BE2CF24BA9D166AB7F04E5EC94B81CF4E400FA454482F9EB1018A5DCF1B56C10B5308B9DA47CF98A76D53314258C7F55126756C3618372AE5BE56E762EA01C6CE41FD7D749DB13FEAF135E33CBB7843529E90130873A6E295E1D0AC26816E5A0E38421711F1F844C03DFF5E7BB2BC2E3B225F66B797160AAFC8B5F7EC7775F0007FAC2E3DCB90EEC2A1529394E8D0239DF80C98D63925FB1FDD69B7BB83EA5166F8E7A1ABD4DE86291B75AC0106E88F15F252FD757E147D5B870C1A4671977375B5FE0AE356431115C17737F1980AFB4084114D1D34B9C2EC8B28F4D489CC388BD95E89E87131FE44DD9A0029E48695866763FABF6FF32BDFAF5784C04F9B76F69695542B410BFC8D76A98E140C7103D6E4C18859F7B56FD98D6B1101E7378CD27E91D7BC26B78FE811FAD8B1C10DB26D3D5798100220269A0ADC48DFBD9E407708140014A04BEC657C11F594F1A0F832A549FEFBD21767721F5A35766621FE14677421EE76FF5F3EF7A89C8804DD3784AA9E5CEF45F62AA12E3B76C030752AEADBE3BD1113349DCD0DA873AA13B9C43089ABAF270D7CBB7D790409DB4681F0555F8707641DC77FD2CE1AC4ADFCE94DA15EA58A323D6B444BFD5202E44AF13C90F433991AD4F76F0078A9F5FAA676EE39B2810C05733951086CA3C4238DE274FBBFFDBEA435265A6F73506CBBB0C1366F7DF082B317AD559B0A620D91AF4A9C758B810D4D80D866B84C1B72125FBAE56300B480EC69EE375687CBD24D516616F8E97C0490632C0B42974F43426C2F73FF340A7A2A9B6135A46338AAB496BB50EF9164E1F3FB216075D321A91516DE37C5C36245C57EEADB88E349E5F09D6125ED98DB3105C3F17100DE03F8706D22C9FAD2A708A2C29220569632CC3ED0E29AA0608D876454A4DF71D70D9F281EF954DAEADCA51C314BC2AF90F1059E22C5DF5DDA7C5CEA385573278A272A08FA832F2C094BED35B387566FDEA1D01EC9D316FF8701A0A13B677F64ABACA4E6F5418D20D78616669EE7EC5AF092982C8301333CDC34F7D11BAF0CA1D459A766C53E800FF06D79A07A243216630747449F7B990C012656C54500E135EBB74E65DAB5DFAD827272AB2C430F05B2ECED1D1BF3C5672AD80DE5C1746D8DFC7D7C49D0D788FE00774588DFB6D744704447BDCC82335C169A514405AE81CCB6D89D994FCA5B8F945C083FA5A7D113EB757E081CE4A24768E3421B3C23EEEC9193F61766099913F9E4346CCC7C04211540B523A278C154473F2E87CF8CCB30A882653B9D0107CED561B5B515A7C72F67BBD682B0BAE0B7E4B16211B68842288FF508D87F95B4DEC506D7E99A75DA21C9EF4523E4D9DA01BF0FCFAE36EE288A0763A06901B370E2C325FFF74F4464E0705F108D885DB859B05919145C0BA24A654CE45D77CE7157D7F764CF9C59C7678C8C639DC5F30FB6CCF227D7F0226C643E7B4B4AFA76F24C9C1BDDD66AC46CF9C3A2DC629E8836D22A6A9FC224C9785E61298D6DF7A33A697BFE07878F373E4C97B95B884F9C15B2D573448C5B56C2DA6002EE494F300857DE4843B2B1BD7DF3A12D6E1715619B0D6D3C687CFD367D6112D9D606AA25E12C61E523D264F9DEDE3D529EF64FC7136FB81E0765CB08228465879AE9B1AD77794EE5BD333373C82B7B85EBB16E49FDC34C5D3960F7AF4B1610D23E6CDC71007CAE1FA7FFCF1CD7E03AB43134D927CBB1BC4882BFEF234FF1815A4F749A09A2E198CF3DDD5A8BB46BC16194666A1715AD8A7A876146CF6E9BF410049643699FCDFE67EA46225219F913ADC2585DAF52C6F8B9CF143627BDC957937D39D362DF89CAB25D9894CF1B5C89FBA8206302AC13A8650274C0AACA8B56A5395A454BCB98D02E0D4061F4CDFD0E03820440B0778FB9534EC77E401E122A449AAEF9A01AD03C02075143947FB99C2E38A5B99ED66C15D3621109B2673208B1F854957BAC81AACF3A67EE0B7F06F67BACD540D138F9C60576C47E2FE6A8554A2A5930804E743214156FE8C894321F7114CF8B8C261C1BBAA5E0534AF37E08E5D4999F86D930A24B2CFE87E79BBA69875F5E240B4F445C48C36274A4142615D6D2869E64D3EFDE166C7D06528976C7E3AEB13C20BE768A91B19689D0D7F1BDAE2E005574E1F8A332D4992FFBAE29F049A905FF6E00F1D4E6C372F70CE2224546CEBF9D12A68B70688C7A8F2E65F287F58EA7D37F83736CAA0773FAD6DA04605F73F05E324A2414170BBB0CB37661AC8DA279131571EC8E36288418A349D3A632C0A7E482441FE2841EDAE6C4314363F7E104B18D81DCB62F347FC49EF48A92B347F0625D47194506A4AE8157189AF903967614FC3C4348F1106EFF2693D91BB899368FBD81553E5044F90AAA34F9E5359C7134AF75057709E62E4E4F0E3ABA7F3AF3BD9C42BD8A76B4FDB577B07E491FB4BC90E071826F9A3205FC6D727E3F42D19943E29C8CB03B573CD3CA54D31E86E156CCB1C050443CB8526E95B4F677C65D6A7FA886031B2A9409085B6B5B901D247472D06868A7304ACB5479E3F55737AE58B9A1E2A0F055B9ACE1F6EC35463C629AE54320168A8065F5D2DE894860F85FAE34BFC6D26F50F8354DBF282F2D032414076B88532D1FFAF263A321AE770EB082921AD96EA2866ED3D90182DAF023F557D2EC113C2412EBBA2BB811B7AA94AFBE1FF66781636986A09A81049B98BDF5F8EA723085260C60DD2524A0497EFD02F5BFAC6E079B9FC699DE7B8BCF6D24D9AF86C591CF2FDD6737A08A094FA82DB334AE070B70BF66CD189C0E42F759497A988599D905EFE5CADB1EF5DCC5F6FA69B1024E1EE94583C53D51787AEB2AF23BD530564EA291A5729A499E1506E58898BDCE7943AAAF9C7ECE7878F56A31774AB918592247940EA9A6E62EE91372B1D17582C9B57D7562EF24F0321C5B8947F56B620E56E3B87C2A8D1121D86C44B55A57D3B88847FA7766A5B0CADFA4AEE047D8A97B11D6A312E9C2440D6A2BC2DAF918AEDE944A98E6C689040A1EF2B0500F94793C8615A1E869CA1F3250A10A468D4E086A13E0159E0B1C8107F3324E31E05AD09E151082AB5B532658B73A910898DE50FD646FFB6B5EBF10E57AF3BDE9B098B5ABEC9BB8B409A4A76FC4A9BCD6D21E287BE869A69E4FDE4859A79EBECC1BF2B0BB38A783179993548088394CA4AB26FA71C9360818A31867989A9E53DAECE67614E3C5EB4B9C1BB68F44FA4A069E3D62FE576BD098BE53689CEC5BB43DFEB64CF3D3E0145BD7FAC2D60AAEC79B14BEC58EF4BF75D122CE03699B1F6A3C1B28F927E59090037FBE211923BD346B8C714F980D3C949D3CCD6781F9D354B2C48A6442F40A8363996F3C390668B012A425F7C10E27BC2636DE54330A72DFFDCF61FC2465789F9E73A00821A13A8465D5D3D6974E66FB7218D2AE2F619116C6F69B8555A77BBF872A96B511D3AA4A91A6DE466FA4DA0A056FF0BE1AD2E7EAD17F0C400EEFF5505822DC3B8D10ADB25A18AED9078C3123B10ECBD8D6CF030BA5AB4516AA0EF6F71A053A631B303B14AA5D89C36ED3B5BA9375C46BF1D5E69E7EC2D076E281D999EB70FC309421450F4B64DF45FBC97B981D857942FF566269971F74C6EA9C2B3AE4E57C9E0CA8850293444248454909C612FA5EF02351172A3B0DF5EAA01F1E97BD6F388E8A61F126E0B1A2022144C216794187DBE7DB6F4C7E3F6552C3DE878D80EFEA29AFE75C9C768715C5F082D788C28C9FDB059E8E14AEE10A1F0A47E801E92F0F59D84D74DB51E7452C4C3D70B73F299DCFB106CF88E3A53350FE1226AF96CD5B23DF7AA78D79D126C4A3514B1DC6BAC59F41D9D14E6818CC6827D974530862D1BD201B425F633EF9602EED5AF469A275730ED57E14442983C0D567B67F2D01C6C9321C8CA14A397D2D1C32A55F964A9AEDAF8B5D5832F177078991CD43B5C788669203A10EDEA38E8AFB39E8D6B386EFAEBCBC272EC42A42CD411F0E9DBDC5AD0669853FC572CA9AF999CB6368EDC285E340DDF5F8E2784A0135FF6FB9E7D134C927C984C5F46FA6EEAF51881BEAB12864B4782967FAE5539335A810F128317127A6F423D17D6876CF5AE31B8D8BC2069390CE2E88648A5E754BB5A2C6E5AAD38514718370B12C5D922517ABF3F65BC845EE79CA51211A89F8EB2915CA98D32069C66FAD4324CFE1E697593F9555E27EA5CF72615E4E4C44750D6B775E7C9B8A0B3728A961EBB27251EE032C023601639D0BB0C6244B445694A2002F594019305DB87C740C2A5ABF960405E4D7FC6FD8CB9A8A1CE59A893F84DB92E19DA5EBBD57797C7D9386B3688F0692E44F2691C220603A88E603F3DAC4AF0EC2E44F746268786B65BFE45B359F43A050E58076BF759B7A946202F94B4F5E234288090875F92FDF006A9517D204E55B8BD33E6EC47DCB8B9DEF7B9D5ED37462C8D77A1D094AE5E9BDBEC5D18CB0C5FE6EA9325A9F213F35038C44BCD0615FCF54322C0070E1F46F05CD359117C0803B63DA34B4B4C824B9580D4FF765A2C56616F132E18895AAF54A8AB64F0DFC6B85CF323FF1E4B15808A8B65A171ECDCE97DEF9B4C4DF771C035EAB87A4BC2A2F5C4EF11E8F3CC84CB4E0115F1A5007453ECD8C9C41B7D3CC43C8F561136429C19AB6162F1F3AD0A06837B05C642E4DBEFB3E24E9601BA4CAC8EF666724D906260A62D6A94E5F648F7B79F3CAE2CA0B81E2C726CC345F046A864BB6F4E9400CC1ACFD3A99BC1C346A4BE9928A676CB9DCA7C20E836CE27A08C6D03E502FD359D2A85ABD2B6A6AF4CA17157D0FF7BBA37DF084DD3A724C25E1FD69B7DD8E77511C011EEDFDB49326DADE3C3EC4ABAE3FB58E1F0E27A733066323AA3FD9CAFEFF0AE3EF977E8EF53F7322C692B7E94D85AE2CACB66409A7D21886F4ACB9DA73671E15CD7999E83D1261D1D278D6DEDFD513159324EE79B8F8123B097C323A702332CCAB34F23B70BBF94F7795B0ADC01A2E8B895522ABDCE0F6EEAE487D14FFBC74D3420130A2B96F005914B07F3E2A0A4E94BAB38BB469AAC8C18D27441F95456FAFB539C895BAC7F7E72DEF1E28715DD3E84E86741D696A15F66226F0AE2573C27F931E0EF30AA8A3497F24F4AAE8DF5E3C8B97EB81523901431E40A837EFEB9B5025C37F6D8E6C0AB701E3A17CEC81A7D7B7C46C33B66BF9BBB7C5B70C7A2F0D1D23FCAAD88F7ABE92ADEC1F1FC1C652F442903EBDC2E1AA0BE4A40A56DB14490DFA087E7D8733EC46F287F07710924AE1C420ABF710223D68BB192B7E0DE96317B9A09FFADF5499903B2D5386EE274B86703FE9712E0EFF66E8479EEE8FA39162ED0CF0D705B0D903D3CC3296B1303C6CF7E36992AEB5455A737C70F73BAA9C864C281A52F870015B9E166747C2AABE39F4469A58DEF7F269A25C3482455460D1834407DD7C42A36F639E3AA4529392F682F795E51E9A6451CCA809603711F3DFAEC01ABE5DDF3EB6121B66BDC78727D71CE8B605853FDDE2F9E842F1117BE83925AAEC279BAC6F33CB59EDB221FD2B507B4A36905B1E3047A1A0A31D03C338B1CCB37AFBD1CA79A48968243DFEB3F3E51EE55D9909CB5052CEE3E3227E199C20681E1B365B9A0B4CFF51A0CDAE9F10B0B083D1CA6B3B786BBB9332A9A45AF5A0FA7DBF2E5B1C9B8C1563017EADB54F5894E3E35885FEFB43199EE8B2479B0E7813F3CF7A027D4AB45D1EDE54AFDB421934735015E6E67AA32BA10DDA5A29D42D5BA3FB5AC71127D0B52DE2B39C5BBC1554E3AEA0EA99ABA4B0855F9B9ACD2D30AA38225FE8E2818FA2D060F9D07B85C40DE0CB259C072552FCCE5633C037AB826C3F70B482A9DBC1162F3869200B3B840AB9B3E6ADF4F68A36D9B041D817FED980F908BF70CA24E5A1A4F34DD3BA295B0AFA7359E31E4279DA397822CB92EECC513307A7D56CA961A50CCBDC8639461F4E8EDDBBA365704DB61DFA6755765E1F062810450430AC69CEE11775E08DA8A4E3480F4E8E53A85AECA66FAE351ECBFB6EA6D7EBE33BE9F763CC30A8626CEDFBDE29383770BF4DE791EEEBE9625AA69F580A5EA3FEF80CBB556983AC2074B0DCEDEA25D442445E5B1A7835164CD76FE59141C0A34DDF6E61119908C524AD6C3CF519A7ED088C71FFD17AF72696D3455C8D8E491C576F90EA6E2CE6140CAFD834AF5E364F0FE3325F4EC64C1B9FA748DE6C3617E262681CEF67E226261B42D409F366194D44C598452AECB9ED1A70E661367EA299AE30DA6374304FD3F032C13A9E0E581AC7C7BE8E8621F6B3259808C60387E4AEEC033D3FE9C78C82F80B98B4F9024E6869E3D47C10527933C940CD7EA47F35DE2EFB85328D2ED64A25B273768DC9ECA8DB40065FF3C42E7032E55221184C0DB4232A096B3DADCE9362CDF3A69E5B84DE12FE8F7905F07076275D148F0C23C353AFF29683A7F8C4C4EF4E1CF27ACA4866A0C9DC3675A8245AD840C0D9AF154BCF94EBA76CE083DDBF42F4B87230D6DB2B94DAB2820083F39B5E27EFCF3A2E25C0A9031492491D3FF17AF00C29842F3C691E5C574C2A89C7C36B5326DC5E5A06993F3147516F79F6C0E9F586B72AE900EE33A1D1EB1FAF30BA9D062CEA4C5088B653FA4637040182AFD8A4CBEBED1E506577C2A0A6A6AB3BE164E99161AD8E1DBEF87A006BA272C09D0D3A5FB35680A5082B76959833E2E9C2C9596A7F83759B22275745B58FF1A5AC826AD3C5FA2D08B520A2B2E7CC9C1B180D09ABD6A0CC2BC633C56B43D6400932C0474EEB245CC0260D1B8C41E8679825E2BF6DECB3CFEFFA3E4E9E1A0E2461CEBCEF21129546845BC7CF51E7717DB9F400E9989AABB44FCF1315BC0C3CCBC003FBF21C3AC9E78EC1F20BD6F12D68F6A9A784451E57D8DEC9989F351173C9D2169E64112CC0854A191784B54DBE6C9AE281D2D6A7A0526258B49FD9073DC195ACB4060EF5DED195CF9BAEAAFFADBC067F2EA4317D98DF5E3E0E69B5045BF52A0EF7F0FDDDDD44BEACAE8DD4A98952356A23C580167EC51DF773C220896000DFAD136C120410530A0E3CA43F64AFE68F54AE6B1832391BD9CD2C9AF60C803FD3287FB461BE0D03441F187B86A23146A1FD7D3C812EB5733C5D104619420D05A5D0BB6AE5C3E321D251195E811CF7558D26E0BED7CBE90161F83743C28B54EEFCF933FAB522EB16D78E65E72BCEDECE333ACBA305AC9AED65D3AC697DC9324CF187E2C50FBB2871C74A7F8127627375BEC0FE9D24498C412843D62F38F958CC4A06A845C37924A1AD6575C23D810E0C3B227375BDD29A61D771D5F1D9567147CE36AD6C6D2A96805321B8E2122EF6CFD6CA5729D007FE30B3F6510A5000110422D5D4583929821BE34AF5DBC9221D272F7FE001CCDD1015D7D720242C07D3D002C7F2D83FF77A8B3A5D93B9435620CBC34830F67D31C81CE380884DD9DBC94EDD83CF13B23ACA30E6ACAB64BA762980F48EE17CE74A5225A4D5819D6D268CF75FDB1BE62740F6141FE952AF27BBF2C9E7092EDEAB04C57E62915EC5DC595DF9BCC276F995E8F9C5FB31888DF9061BB48DACFD95E002785DA77D3104E3727F6DB94D783A0F982A14FA3E410DECEC32593C0008C6097A633BF8CE1A3DCAD3C5A989D958D1BF4ACBD44328E82738E9389F23DCD4A9B4A56CD42D5347C17FED43029708CCEEF7F8F2ABDF03FC61C72B09F75239FEEAB9A462B85617407F26AFCADB9E796E361193A547386B3703EDE92690055627546040A5675F54FED152031ADEF4BB52F2168A3A6661E4BE609091253456971B255B48C1B35FF8B928772BA03CD0BBC7D66EBC56246D849205D79D854E5F522612E7DB7FC18E58C323C270D1EFEF1C9A244179A711E0F1D3C24419225D3E56C555F2725F56414DB70CD42A170A661950D991049E1C93C7701B02FE321E307E42E074A87EC62EFF98E243CE546F0A29094DD97D5BD5A71F01EA3EC8B7D19AE5EA1F56144DB628A30CA9EF0B272FB27C3C9F1145B6862C890E884D12E8C1D2018BCBA2D76F673D231C4D50B63FA38812685902CB83A10464C9A11D9D1C2F92BAED94D6A5022900EC936B11DF06B94B2E939C77411DF044812F4B08B75A8054C512FA8AECBCDDA6747D534D0DE89E83BFCC20F4E98C780AFEE5C5F9114121A0817ECBAA842759A70126A3BF77B0383CF3CDA623FAB232B4E3178FBC41045E18DB81451C27BCEFD5F244D9206EB1E15A2EEC4789BCBDE53F08784F1B0EBB778763E9486CF3F5DAC3306F4D6292F2CB221E403339A6AD8763CEC7E89F93776FBE99853C57BB279C0E485DCB3D93622C2022D59FB52BA96ACF4FB2D8F386673CA4AD1E9FDE705F59F46F4360765133A845D9F5AEDED31EB811DC2B584DEB9A4F37BEAFD21215A2E204902881B821499110719817D7D366F0BBFFFFF4A19FA702931AECD1B887A885D2883CECE987C8012B7B37809AB9299589A7F530293DB6C8D97FA60DE06A35D27BF905EE318614146F2BF9A335C19D601028D464E3D43D9AA2350B36BD2D6CF9FA0441E42324544BD26CAAB818D6D001ECA9AA3882C9778FA0B8E6F3969653944FBC6CDD484749B9C0D801F9A495E97A81CC667B6917100C0BCFE2FEEF433BB44D45CF5E1C6DBF0FB563FEC64B9C5F274FB6714B5E30D10FEC3E753176BD7399580392BDC5C6DCDA15FA2B80FE9050F1FB7E8EDF20F988CCEAEA535C2AE73C0385D1EA52EC8E1B9319E7D375D80F401F9466EB12B01CD89CD6DAE79048CDA40961A6959FC6CBF2B6018D398B5D5AB4A5870919F88AFC2A4D5F8155B5025190ED8581DDC2D91D2D611CBD501D3366042BC45F11BAC961F1B971F27E02651F85D24BD9AC285B66CD8BC985B5D5F8DAB4D51E1415B19BCDB3515F4C568ABF54EF5FFDB87D67F6B0601080A81D329E29A67BD65C4468B7E303F9DAD759B13C8720767A926C980A59E047CF1699FA6ECFF62454B26012E3422397163ADCD15A2890DEC6F662237F9FE06025DCE3616A53E88105AACDE6B2156A9471593943217F2552BC2A9FDE3392451F163D83A90A58A3966111495B39E9EDB84405B08C78E71BB3D46C6262FA9DADE749A63A96D8B8D9AA1976C592F4D0445F078E38A1B9C786AF7CA54942837B8B65B821E98A692F26808EBFB9B6FCDF1541BB74E415AE2F0B6C32627B560C094B5998F986DB9B02435E96B07EAA44D038DE57CDCA07AFDF90763846045C00BBBDAE33D548C935B7AA29C7E11F13375F47DE44BBA180672740C525B960EDAB1F11FE2DDB8249370D3CFFCA2975A6174D2A515F458F24470F1734A5FC9AF1B2A3B15718F88B68F58DE9CFE3512FE9A273FCAEC7383576D250994D3EFD0F8F747D06D683733234B905D4B0BABB6BD2C97245E81F272320ACF71C7437778BC37E6B83DD78B0F9799A5E2B4D87A1A5B0CE8C696F192EB559BC9CF745D46BB0F589B1D40A80C985ABD03875A305A4CA07EE07CC3B51F9997506C0652F23ADA1D62706F2744726A8321C6EF487B2E365136605857CCDD5AEA9A8792A8AC697449742A27D584C849B40876A16A2705F1B8CD82548E64FDDED6F42AE1BBE2CD374FABB060D5CC2C0D7D9FBE35EDBCDEECC38CC9DBE49DE05862CD99E9C2270EF057A550C1BC984171D4B333EFAD098DE8B4D929BF82F7C412987977B9EF354E8258958041DC1913379CB5C0384B873C5467E9B21DEC48AF2084B49E2D204F890B0D4E54A576902858F655E8FC7D938FFD96BEE07EC838CC4CE53FD6A72A686A6ED325F13539698B9E447D08455997059DBEC0E08E5016302DC2127CE24ED7F2D5456EEBA8EABDBCF63FFF492BBFDD475705D62F4F129B3316FCA531B92C3E4D219F9ECDFB121010D69B48897B608E42CF342D5E7C97ED3D39058B841766DCC2013BAC4AF3548D1F2765153A74CAB335D5D48A78ADB41498C0B8C04D50BC664F2B3B2D5CC4CDE036E7F2B32AAB25FC5EE93E1E84A58EBFC41CC51CF7F427096C6A3F54FE1889A59C88E58FB75CAF45BD8809A7C394E5499E233FA1380691E11A43EA50E37EA48D6BB678DC5BE07987C0424DB14D934141C8503DC05DBAA48B9BE2D6CD95B6E8231D708A0D6761E6F83F445EDB1F52D01168B745B6C08C6BBFE0039F9B76DAAFCD7DFFDFB032979EC774CC7C89C992610F30E08543D1BFDFF032C8C07527AF7EA463AB3C54C7A76A8907032204025AF24173CE8F71FF2C2D3B7E306CBD5D1C6BCFB182C49C64325D0F1DFCAE1AE8AC903C5AC735C0A39C2B809BE5386CDB98A74C714D3935ECBF6D148485FB356426382F5E978679FF6A7A742CC661C1E0AAB00CB71D096F835776D3E8EAFE499A7F3A2B0381A0D1C848C6C9C9BE588274AF8ED2B3107B42130EA4A0009682F0E1A11263EA03FA07952E62D4817E9F315D50B949509885235CA5D6E0E5EFED006F17C6DBE788E4CD9A2E536F798F5C5B7764313DFADAE9E080B5EE1AD82F7DAE3912C33D3AB458810A187D7CCD4AEB6A3A65B2BA83620AA6DA5F103B502F1ED9070BAA465C46152DB48448D0D48E0D23DAD145DB4460DCEC6B7A7204C2502BC6D792225FEE4E74118D7C2F3BFF274FB36BB80BF8C505EB38299065C609857E7A7396D712773499CCBF2AE6D40C02C50D7C0364A3F855AB90E8425CAAAF199ACDA1B1944BAB6FF8BBF3CA80F08A16A0BA23446766E33E00B72ECB66F5639C7D44ED11F9EECD1B3C2546CFDF208EC0DBD277083B9DBC01DC8F839B7F41600B998E9372AAD792CBCA5E88BF08FF991AEE7CAD0509C22F1EA51A708949EE5F9815359199263131885FF243FD2456776F43EB69FFBB64B0CB916FB244B2A3A706D57F93C453AF7C2B05AC3931D6A6D1A43427214D45B5FAE16F7DD57C23ACFBF8F92D4BEA7F5F16D82AA0D72438E63CF240ECEF964977AD3F480AE27F178F585E926828642D110B4B69F9D791910409ED8B3408E451ADFA8421E184111FEF558282CB2CC9237F6CB6C45060F54A4BE7A7E4523252B65C91CA41B6E42A6F4BC687A2662EDEE3FA615EA0FABC4CF6825946ED899DEE17753A22D3CD0DA7F9919C0F868F152DE1B8AFA2DEC36F0F05BB35E20C51A9024C86269A916DAD6642AACE2A94C0850845B2A75490B3ADC89E5C017BD2AB8BA738E0DCC966064BA358E1F9498F789CBA5AC590173FC35584FCB95E5A542AD2C54B217C139D677C7E27648729B3D7AE9B724ED7574076A43F5873AC56A34CFB43EACDAEF81E5C3D7E21D28884AFC4BE8B2C522C9D8AC3CA488E3750A780A6850C89F2C6B440306791FC7A596C101311EEA1EE8C2A679E75D69F188D993BC4A458850E88B7EA65BB83B12A0ED1509D9026C5BB10D1D4F11354FADE05DA7330E65A3B811CD2E99F3B2F6CC1715F31064EFDC208543644462FA3C4FE14FCCF4C9829F8768C908056150E293E0521CD003803362C98466B5C98002218A86E1BEB09D7AFA1962A1E75465F8D09F02C62FA11333B4E4216247847B9CBDD0829286A1A0757F01518CEEC4AC2163CD206C8A234E53C3F293B563CF55DA09392AE76FF5035D534F575AA5D8DA98C416102FF72B053EF86934350B8A6764912CD41724AAAB694365EEC55A9C90899A557C1E1C32720BE2358AB3E0B5FEBC58C557D8211D60A0A32CC9FC1C0943BC5BF08C198D722242A1CF81BB8D21E845B555A022E11AEC02F624A3760B3416EF988FDDAA2D01831CC23C7130C4DCAF267F49781F2133C11CFB54C8503FE566D674E8FF62CB5DE08D5AE686DAD11024AD2D0B8CCBCE4EDFC5477A5E0B12F997C71E93816302B4DA63FCEA3B8628D3D397C19C4B26A7471894E96AA59A55A4E16768919BCA85D60CA3119DF00E95C8273B2F6CF9877208736F92471F939F42454F559406887227FEC7489F893A3B6D157C73EF49C07390B131F2F028BCBBBE70BE2475894686BE1524132CCBD233EBC2D24625630404124DB333B7BDF832F4CD2A24604DB39BEA8FC438A03B49A49285863197549524CA06E69F73036A29C977BD765BAC06432E328BA98A6AAC233830BBDA367CC16F806A64B591D0D3B4E4C4D41805848021713C052495F10578BABE03FFCBAFCEB63697D6A570A820C34E2267400E53B879081A29ADEC66B98F1B1D25FBCF45C380C75028A23D58C9225F46036CE8148C1632AF6E64021F8AE0091CDD9794025F399F811BF4F8FFFEC9E1095FAB0A9E271A9A9E35A7C3E003BB696F52FC9CCE87905B16D16A16183FF2BAC1C801B134D7E656AC43C659BB166D8C897B2BE3F30CCDD1D7E66B9DBB26FF4A7FAB3DD6DF4139B3B34AE3670CDE88616CDAF33B42E581761A565BB399C015C7F8D8A0A5B0714A139F0267B612CCA8CA87AEB4F087B4D1C79B8AB2F18EDB347F46CF1E98AD079F6CC2E3930D57A9A86CFF37B51014BA8A6E3364A20F4475A5E0D32605C5517C27885DBAA008D588432CB2062F69D0FCD97ACA849BB41CDBB34951E659A29E1B49343ACF49CB6B3323F0F0D19B75931DD102CE466FFDF5A70DE568F38E120E3B80239E088D8AD69207AE03566EA69F0A24225A75C24D90052C3E485476B2CFD3A103DD123695E70570879B29E36FB2C61D15542EB41921E1BB3D9A4068E8CE0235C6B13D390D85DBA63C6156D1B5FAE83A0891E08321B6B0A4B1CFF51276BADAC4C06FFD3F71F3FEA5679FD2E927217C93200D395EA6B8FC5B2772F3A0D33FE6E5965B37DE87546CE9E38C9DD9493526F3D0B690AB992FE294E3E34C4B21E1890C7F4ECC4B0D7D59F5C57C98D13932647DAEBB04B0556460C9E342592CA60049517DE60F09ADBC7CB57DB890CC8CBC90BF2B1CB4F8723A30307B27FA2FA67BB4912DAE843F42FF07A84C46FE197C24F2EE7EF82D7EC6606E0BC7DE2B534E8D214BA4A76C7A614ABC533625FEFB2E2D8FFEF1C4A166B0B85CCAC963DCECDC2D45DCBE22CB942BFCD452F3881F2248FDEC4EB7468ECE80239D720731108E94B2FAD59310C7411509AC085EFE47D8C05C5F69D5B53858021F06289F22D68B422C4AF328634C5D87F9979617C11A883FD8DEB0C1D4C1D88EE03E2A67574FD4529F1F94BE072CB1E549F26ABAC8D02E9D17B47FFBF9D381996B3D630610F52772FFA471F9F204F33CA07935A2F9549F1FC4C08E9A1EE662B71E91FB23933E4DDC0F66C793BB1DD39A8F103AFFE2EC0AE6641A03DF236CE31F4000AEED208FB2805069F1D0728E35346372F946A99ABB0D6D2062B5690D769C8EAE006C9BE83D8B5FA57ED7DA21BC808CE210E995786B0E5B955C839BB728AE3D6AE6C10A2BD5C4D1E47E7B69F79066F768D63BD988AB7277AEFF9AA2ECE1DCE4C5588E4714A4CFA929A324D2ABEC3BFC58DCADB547E5FDA375678632CBE9B60DCBCF5518B46F3FA9EB8B25857B9961F02B2C8ECE27137E2956CC6C258FFACFABE88DBB0863DEB5BC746E5F0CA1366025BF0083DC5C6CAA1D17E86BEF0215D38C4469342E4CB8F2C002B579B94A2522A9773200BD97D6E2813325DF921D0CCABB7BD06995918DEAA937DC7C3341EF7C5B8E63D9B04A398D65C1C8F21654BA44F6552C1E9F33900C6C189E9F7B32776AF1AC795B48884D5999366231240EB12F81DCFB3B4741CBBE4081955AAAAA600EA68D22E5655184EC28932A31252C5F860635B041A2C6A87E110813D1DF1D3A36D779CEB62A13CE9759EC0EE11D17C78E1EDEA5E053BAFC623B4534BC656882CC87D87FEA55A3BED5DB62E624713EF4702DCC3EA6ADF07F69D0A6E22B76B84D8DDC961A17697152B19095EBBC9E7136DE4EC5E142B3CBD75762F5A72FD9E08F217FFD383546A889680B69D6459C3A5711FEE2173A226636BAD6454F454AF8528808FA2CB5A55B3FF552D9F9C2707313C821A452E48EB724BD4D880F38008B455D66B99347769FF5A55997EE9AE2137F7A2FB48933920D0CA416A16F980E6B7D714282ADDCDC6F13DD4618B8120569602C46A3CE7B25057FDC0754A214AF9CD7949C3775CFF3F9857E93D6B62D00BF10480D67076DE98C759CA659315B679B145B3330B9B2879947BEA0B9C1F4ABA9744DDEF677C3FA2F027008ED0671AE2AF607E65462B80A026D1C0EA5674AFAF8BA2EF1EE52E368C907D0027864D260964D411B957B6905E5BFC12D01DB6461459D99168B22C3370F16214A6AB4D044EBD55C5E2B6FF9B43761FA210FB992203053D2DA392CAC12D08C29FBD7238EC0551EFF37E3E39BF26C06950205FD5E04A52D707191530C1276028706ACB5939F1964B1991A15F428A9DE9DD19CD0A90BBBEA58FC3055D612384859A6DABBE4762466A05C1C7C386E9366BCAD00470D08A855178CF37827DAF63E34D8B26D377AD88F8CB0840361A94BB1A92D2DBB4001FDD64ACD5FD944D02C22BAD14A29AEABC7D7BC8A97F2F938E24969BE30A8DB1636ECADCA6AF45184467C4C5715E2505F0FDED735CF94BC4FBD23031855688B4F1CCD69FC486AC899E8D97608B410CDEC222B2D127C474611C4210DF59CB4993A89437A05B114DAF0EC232C76A5376C10F10917F490F6ECE01E6236561F1F7E77F1B3AACE76E52521F135B87DD84B49A7017CE23ADA63493D10DF64B434D0D72589427DCEDAA0D8CBF73B0E54C674ABF6772944C4BB4FCC261FA0CAFF055D8C5246614CE56BFAE69297D1B2FF223D5359B23B7A3384FCCF186FB6B2EBD99E4716F73BD8D6A1293F7C7A44D27E952F3EA5BE20D079AF821F9EEF3F60830CEA8C2CE82912212E481FC6D64D583E08176811C4469BB96EA127D13C9CDFDDBF94FA3AB99256FA52C9A82F624B9FC94FB41235322C98D6239B4254E5930A17A58036221E1F5E26191825C06274C21E311C0B4585CE26A1E6640535E6CD9E71FAA020AB504CA806FDFB2A72C72FC73B3D9767012965B222BE1F9015BD45CDE22D737BC9494CA5ACCA700EE41891BECA333024D3C8B5D8CB8BD79739FF4B6F10FD75BF95F5F265951D1736D84A4379C2A29B7BD802E2D2DB5F48E905C0BC75C5EF9D4EF4AA7FEE7B920AE953632A0718D775AD4481E1F77E8B7F61A2B5291E486CFB272EB79F49BF2389EFA4749703A0FBB95E398917A1C7EF5B89F96007B5B7091BD92559A0DE45FF1531348918EEC1E12EAD0F7E3D0BF0710B5FE7DD270E715965884C84CD97295C69C0888F553F527D8DB77A2D5EBB111282CF642342D5A02DB46BC9B0525BFF4E37BB641A658FBE39617FE1F408CFD97896C02B33DDF48A2ECECAE8F6DFE102DA10318F8FDBB9E9956834FEFFA0015F062A3F153D368F94772208859CC86D36F0D31B5018E4EFB2E953669632491833002F9C0969198D3ED992F6A47F7A54087D68E1BD9BD4D6634692136DEA7D00112A419DF4701055A1EBDEBB29C9BDF67111486A1CC9AFFEA8340D6D254147C449DCA66E4A6CDEBA3CFB199AE8ED051AB4225E53D7A64793AA1A621210F85D57E41A21D69A35AA51FC968CD45E632C8C413C60CA9A4E2CCA08BB2CF99401A727554DB72D103F14BE199709A014BD2E1B9FDA80FEDD2A2EC2D10AE0B3C384497EFD9443F13C952E10083544E513C4BF3D910FAC6BAEEE020DBE07C69FAB997917CE44D678352738B9EF8ADAC1A875CAD0FAF8ADD9328F2BDE0ACC8AC1D2D6C62D308BC9FB4662D9B72771658E92857456D3F4CBD971D94F5810A0CD5B0F495D2C18BD25974B9E0A26A46CADD37BBCE6F8141F3D28877154BD77FACAAC09125FD926BC3F0D1AF9716455E49BA0E94863140101F1468221CDE3D656958810DF10F9DA4BB79184D614A87CA9D7060289A603BCC664F2F974D5D19593BEBC5B53CBF03A14F7ACBBF0ABADF2B6DA977B9F002CA798F90932C0B76EACE0E97F3A75E7F6FECE2900DDCDD290CB8384BBEB00789C337EA19FCFAAFC5C5F27974A79E61C0D8311FB3825F1471A30AEA2AFED26C02DFEB288C759E5AE5DCBDE09F2BF4038EBBA4C4FF9F7C56361FAB62D9556E8B69D6AC6AF60FB28266A131E6324E1ABF8E9A179AE0612DFE0AF43E8EA34CC6963C00F1517ADA2891ECE0CA12A1E7AE1D4AC0B7A742A72D9C74F307335CD369926D9EB9D6DE881BA63B20FB72BB594D1B33305A7F13C90F4786131EF6657F6CE2AEA99312B443D5060A2F2433BD913428F38BDEA661731C32F30670ACD172157C6C3FF4D23FB924B7338B42BC47B8596CA9A0BCED7A5397531B78372D5746F5E8D48FDDED913DB9EC5491C09A123FB7E8DE770D4EE0AADEBE3F616EE04AE367F1698D3791DCBFE03D797D7D63891FA9F05A9F0B39101D747C1C9270AA9C8C5F17DF9B5AA0D05145DE455F1071620478E17F0ED3C804314B2FF17C8CC4AFD77CC166E74B58DA0F040A7DE9850EC242BFE9644B15FD071C582A8DF5CCF3006FAD382505CFE12CAC60154000E828F533B7A7E72EB1A73113B03E987D99FFA5E3A715E574C627DF53A00402FD8D14E4E2E2661F7AAF3AB17C5430282C1DE3AB46D8E526C36748E5029795AA1623B66B32FCB1EB3B0614E0895C222FAAF6E0D3B540A66DCEA5F1FB189BDBDBECAADE593084FE4BD523EAA3AD9FAFB0E7629CE0DF910C45BBA99EE3461A8C3CBE029058DD5E66BF8D41B53590AAAAA274693CA257C924590117EE92FCBD15FE0C1395EBE333947BFCEBC76DDB1EF7FD13B52016BC61CC35F588B541EACB98CD30ED1D65E06BB5A1A723358EC4E3906BE05051513AFA4CFB5E8F9B6846808901745D9EFA7538256DF3297DF1909E5A16C724194129B2DF4FDAA5831C9A3B27484617787088E448158ACDC4B6ABA4968E24B384BB7DE602AC13CF810AED3D49192B83AC37581933E2E7505CD61BBDEFC7D3DE31C23B85798F8D1409C06596EC74DABF89103472A4E5BE88D92303516DA89684DDBC813ABC9897292CF17889FAF331F4407DCB1CBF6ADA3387ACA19C837FF24CF3FEF3FCD1A0A965F7D0DD0C0991B578C84D7EA956774BA217C9B0C5F047DA699F5422D72EC23F59A70503195F5F24E7349A5F6BFA812F0503E9C7A1836C57B42AF8A26113FB377C295EF3F30F135BEEFAAE344B7A572BE2022467121A58B1C1AFF6B7DC7A51032810B578DC3147A5D8BF005C5F5C90D1992F83AC3B8DC10C818A7CA6DED6139F50BD9E9FB331C1D2EAD9B5FA35B1641572C4802DA56A9A3B98F8DF48EF44FECDFA0DB7A0DD2A0A944F81BD46F3168F8B9AF3F598CC4FF2CF9959BA9B79473CA4356276FB6A547A58CE396B68E622547FD16EB44D11065E57DD941F60D09163D84221190D568C5C998977D34B67B8C83B899B9E6E5890167F8D4748E667B42A4AFBCF495291B7909ED1B3F7DA1DB5F9C9A8C4854CFBDBC8E1782E585B0EF05661081A3C26E8A075AD21CD34E769253CE5765063A476203D0693F1CE74C6AFF791C6129C1DE221C42BA089820F1B5C7E03F9B492A41483DCCF1D6F71D45992241C0800732A66408F72A4D3A75A17AA7B5961EF0EEC7E36B1B21E759DC276C549D748DF22EC6D8641D447B82891077F9C163E7D668719FF3E02A098B7A11EB2C1E591264BBA7AA4D64E93988AFB8FDE0F976E11E21D4AC425655E5714078E208832A635EE1C28EA7A919A48A437DA36354B2E9D6434BEDC7E39636BDB3FE055A92503C9E6D5DBABC3EEAC67C584AD466BF7FB93A2493D19D0569C4A69F893DF481C54015C1E5A8E52FDD4FE3BD8C527856DA4E436AF1414B3625660BEE8E1392108FE295F9D4B2E789C1071FA7ED46ED79399CC4AF09A13E8CDFE0F7561F62B61CA8387A3CCE8570E491054B5516930E603E10E1B2645D2BF32E100801AA997E95DD285DFE07BADD392AB2045893A95D02BAC20444BE5D954F4CEC5C5C3379D02F523CE8329C37D0083583ED43E75FB38812C4C3D1E3D57DEC4132120517BE68C71DFD90E92AD0C2BC60CEDB3483651208E7B1B2A3CB8CA3EDFE28FB693FC06A3EFA56AF3B9FB27DE24E85AE8DA4CB1DECAB79EEC93F09CAB0EE8E922F1AA2074891BDD1677786F82EDFB888D96DA26E3243AA7219C65678965E36AB3CFA0A6D894652E91865F03A1F56CBC5319E5A8E5957B1ECDFC0D68004C8C761F2E0CD8ED874AA608FD992B42B320166461D08EA0BB9218A2FC4CA20BD81C6231DDCFCA72E0194611D121CAA760FA16BDA489ADECA8C681AD0ADA37840D0F6B99EC5B474B011DA8E7FB6485CFE7336531BC748D147755149B568AAF8E263D57EA1B0ECAD1BB4FB3EB7BB88B4342EDD34CAAC45125B948581C2DD7BD079E17320C698299CE09ACC6AA2C7FCBB0645F6806696E66D554F0DD4DD59D1BE2F0C6DCDF33AD311EA94C23D6C3EF5E468C12A5BD98BDCFC8EDAFDDBB373492532F1107E05AD091800A6948C84E904B54D39571DDD1F711F381B4C6221C443D2BEC15D8C40DA089BEFBD3D53E4C98E41FD13CA879513FC90B5BB454713A1426D094D537730A7562FC23AFEE8D304623B9A70352449AFFB12F2BD08DD607E7328E4683D59C049CC19A3E315BE4AF1C6E77171C89CE5E8434011EFD1E340BD4FB24EA49361D026D1D35AF589D9E5B6EBC225878B3D7C466B3C5B27EA2688B9E02B704BF44394966E08D18ED10FB6FC4AFDEDB265B5FB0B5F9778E475D7F8F07EF1469D0C66657B96B3173CA0010766D6E40DEC399E55E0BBB75F2DC56D4AF7A90EC5C6007451AB4EFB91777BC610832423552D3B7864CD077A5399452B9E0F3F45D0C32B536AFF0BD2468FECB7D1FA00072CF87E9541B0574F2F4682B06BE508FC53B9898437FCA44DD94B56E80555F33B0C171A334EA968F2373BD54AA1650A73B8175A6F9C0E3130660228C16E29A139675889FDAE0B217D9AE9E1AA71D9452839BAE261C6412F94A3B1B4BA72C25E33B9D452B7D53214DA424B588AAC642EC31386BA7C194BDBFF806E40548A63F55326842A92CE94D4A97652681644B61300AE56582F68081C5D2398DD2025A40709D960793DF203F5501A5F702FAB0AAD3BBA868FC8E3EC8B0620A05C886513F4F1FA5F36EB25F5555F928069746E2AA21032EE498AAD9A14CB2AEFCD18B5E675B516D5607F49107EDE10AF538D7088452E65B919868DA5EC054107BD65462F1A955C6706F717C821D031EA3CF86991219C5E6958EE3EA18872155EE6DCC5C8751A8E5D51D58E70F51A2F8D1F131AC0F6C2C84DF9C65EECB524D5C6B0A3AE164769F9E009FB410A6639769DD81F9D4239D909BBAC85B34E5907DB37915BB486400B1F7B50C4B68E074B45F0542DFADE9D9068F10A815705A5E2369938A762C5CA2B2B1DFCAF01AFFA4E3336A345E18BE0479C0D162502910F7A84182B6CA4AA63BFD6D134E1133DF83F986EA0A8EC693F071F6EAE6154E8BA3063D3317B4EFC06271FFC5A93A9E1275DCA926BC345908DA05D17021A76DBAB286DFB4BB91FF7773449288E648EE7130EAE110714DE15FCE80E85697E6D9E603B3AC3C0BABBF967DD4D8B76DCC579310721CF829FDAEC506A61476AC5042EF3A3F77AA172AFD9C2AC7AEAAFFD35C13C4D4CABAA3B9DDD23E8F354050A165ED57615B9B851F4B3E14EBCB9DC26C81D321BC6B27CBC51EEB2D80B365F9B85EEECA96DCB6EF1C1264460C4D2035C083110CBF32328D17C3CBCC2628250B8781BEFCF7D469864023314C5CC44CF64BE827F13C38D93C94601A36C126C55288D661B30C791E0BCDBEBB76EFFD76DAC459DA4F47524CF247D322F5F1FC5D00FE75503E1B14E896D8DB144B5FE9B43CF0FFE2A80E1269A54D760972C1C7D587FCD10FAAF439F4FBE7230D59138046622E2F67A38EBCC9E3ECECFDE8C14D3217B62AB41A5D1E4CFBC529B79C08C39849A67029820F325710880C5EF05D387489476A506747CCA90EABC7ECE7E5857DB5D27AFA826D4B12B5A4B67E0634BE356586BE9E03D3137171AB119A06FB8C32CC5F05F04954CDB6AD8F3A08FB557BE135DA21DC8EEB06262101CC06424839638AC5D494D6714E6DD15EC107B8A7C352F5E7CE49843D3AB799D25F35EED7B72566C04C4EE4BD842403785E937A65D9F336076BC80BBD616D3A3E45B5E3BFF9BD9E2B06A140DF852C79170C26F290A7DAD53BFBDEF990EE99AE83C1618E72854A0972A5586465870702F514362CD939A1830D32AF7CDB899BFA5DAC9BB2B2671674B05EF36A98F282A304D22047886026012596A982B2549B64EE617D28E361B7318083405884342E8350CA643089484BFCA519A22D7B2E98CDA5DE70D9BD3501F2C9956BE7758B9D80F1E8E6455F1383560355642D45CC5ECB0DE099048D3B1DD9D1C9564B1B12D899EB69B1857123D5CC45A5BA15AEDA463D774E0B509383C3C07191A8028C68B0ABD677FF68F69C17B13BA77900CF2D9C4C51BE6E96F57333614153D7199177286E971DFCE60F8D26FFC71290D475B5C629C8012DD1ECA55B9329144C5993D2EDB6ADAE9054CF040541B7C84EB27A06A51B83B74006727D5058C163E58B6F886DADDF21473CF1763E70A007512E327DCA02271986F1DDA2A419345A915F1934FEA91E05CD2D8548165384A330F6FCEF8BE7912299BFF7F773C99055FD951550F7A1D43DDDB36C55CD289047EEFB02874E91D5E15E14DD051C43406FF4DBCC038D37CBCA2B1D81A39364CE7C88D33D98B8983EE339DDE5240FA71411259055A7B2F5A9DCE743A13D55A26C62319454BB1390483712129BE75C977DE0CD8D23B5B9EEAB0D2A3A634BA958E6FDD6ADF05B8457F09400B15E9149BEB00C2A2ADAF57ECEC01DB54C6E00F3F4A975C1CA747707750319018BFE2F92CC424A71C918D1EF10DBA889F9B05105A3173ECCDDBF3348C8E67311335D2DE5205FA55A36A4CDD01E456E2CD3E210F6E47F75B067701C2FDC1494EB556196C3F72BF71B82D972F095AF9AE311C8FE5D09B580A67467408AE7E06993FC27FD90972FB8C1E2F39A201398A3CA0B04417F7AE425B616B118D4209DD4D39304639D2097959798F21C023A96A629470E60A3DE138E2AE52C4AC095F8DC1E031450FCA7E2B44A921FCD65F8FFAEED77D0DA218CE3CB729D11D6355535ED32295F73FFD35ACD56B64F5015F6FC1C75195B9B0CAFF002EE7701CD6158115E66F2251C0AFC56AF1C0FDF6F77D15C529B9FEAE3EB32A13814800F445497E486DA36FD585B511C557DE9080C967CD73FFC8DB94BEB5B7CF952F37D406758CDE79F52902CE11A004AE079CD062859B5B5135B93CF08649EC5DF33B0CB550CA484C9C20F8134D26C71EE5DAC3ED263107E278F973F5602C833A6A1010CBF1076327F421AB182462592F63E86651581749646EEF2DF7464F3EE8867CD00E997DA4785F721C6D37439EA13F3F3FE0CB09C14D85F07C2C57B57050B888A38B8E4BED0238A0A1AB1AE058EEE9DC845E7F70DCB3D9B5E5599C82981758B96F61CB2044D6BB382D9BEE530DA0D93FC1B46A882FBE5EE7CE0415149933390E14CC0E42ED5B54B694B2A7B272F6748930BF8AFAD4183EBBD9695F0F9BB259DC906CA085326E106725A2171904BF31153B37EE6F851C72F347C2DEB5A3CE043FDA09344B162BC01CDF98A2E7B6C1D8FAD06B4BC626ED1A85445A15E38B2DC633B647622551C1415F4D9FDD840D43219FB14804565C61EB72F57757FEC96F602E2A7EB65FB1A52FDF6575AB53C750AE0D8A84CA73D1B28C5353204E772E3535A8E454A65D1D3419AC6369905DB5DBA9D092329696026970C270827DE388FAF4A07174199B93B1764FD44500476CA5090D693E1CED742E0BF0732F0DA402DF0F32113716C855E10A5178C35B2EE6C0AA9CF040905BCC4CD822515EC4B575A335A7B1D178419A2E957D8E7A3D48D593B57B656D2CB530740D88E608ACFEC6A2C9EC7D539F6392F0A00D93F08530BC5EE357B76DB3E80F7DDF7546D5C94701AC299600614B58FFE484D48B3D6D2D08F2498B1CA5B42FD3E9A0C06AD9F1A14E39A704D9C5D33B982953CFA0E645DEEB1218A52D25A312FDC0957A6F7DEDF2172FC1E1CA5DDDF47149E65D170943AB705383A33B8E35F04E901019020DEC910926B98F35706F4B98E5192007FC5416076171D42787578F49A6E4E705D21B3580434D490CFC925EF9DE975E144E5DF8BB72CD8D735AE6E726DA30688A0DF3B6F96C5AB0D61703CB25758DEA132E3BF92AE3428284C0EE32D32808C9C2C537B3998E4F7719F0412A54FBA090435E7724B7D944BB26EC545957F0539A20826C38A61CDC6DFA253FF37748D633F0F36CEF058ED13D8BF4045CED815E227D96FC3875185A9412279CA340CCFCE77510702E4B87ACF05B5E5ED8C28A2679456183F9CBF9A2AC841DE9434E3D6F2AD44BE79BE013EAFFEFB9142B1748B412DCF4F802C5F5B8D001A55E20AAB24BCF807C142E930ADBE874C65129D615169F4FB669DD9ABE12846339718E1B57355833247D020CFA8314ED0BD8CB2CBB48633775F5AAE6EA813F0EB01227744C8F396E3BA10E0A8100391D5B9996B6BD003A301A77E6049ADB85F211F2446F4226C82A1CA4FC12BBC7BF252627A85227E7C2D86E542C7F9ED4BE504F67FD7DC10C04712B364E98334615F300335D057FB0E5076146A12DF285615340805300A799528D0C1A08E4803B08A2DE67ED40BAE18B53F0510D393FD374B84898D3BF2DE716E4C801EDBEC6A188C14A1B30C07B9E9F0AB2D90A65CDA455357A1FA489BB1F9F1300799FCFEECD32824282E712785B47FC2BCE539F66F3A5DDFD29B69A9E6D2192B149FCC7C356095D8FBBC78BC051B025211BA0CE4E262DE40D060E5EF7EC50726944CFE821E78BB93A955F982D6AE9B0D50AFEC40E7AB35E13B507B6CD0DCDEEE0A9405FF2FC59057D54929EF811CF49844D979D7642EFBD82F346B7240A8B6B1694D62DE877F12B82901A77867AC424FB6954338B10C0AD5C1CEB53DAE5659BE765965A39359CA3ECEB12E2575ABDA4342E5E1D9F7B55418DFE30B5DA396703970790FA8650E9E7B37266148636AB806C37DBF13A7A52789E26C68E9D7C5FADA232734D99187F27272F1F4FA6DCD56EC5D02B939BAE96777343512323F063F0AB88E7D7066AE00D9279D0ED64472883EAAD81AE60543290F0654A46B45BA9B1863305CABAE8292B6C564DFEA62F7310232A47F9CFC6AA8B91F2945F65954D2086D17D53FA9FC9ECC8C41F22D97891D215F0151DCEB17EFC07F4C63B9467A3483D4DD68CD5F2DF2E9D378CEDB48EF03B00B81020E2228CD4D45AA62C5F97661FA5B4E916F54A666DA44AA1576DE1D7C89A748824015BDF74A12734B244EA02935497839C52E5BBEF73789A07C7F2C8382BF603C81E7DECCB13E68236ECD57F5EF7E7BB0DAC2F0F599ECFFF849557E810BCC805BCD75AF90FBF9EE35D7FE3A9DF4DE8494ECD5A024B88F97BCFF9AADBD5BE6415F027CFA5A95B96D2591E5DE28E232CC684D6F84424FC7A2A98AC83257EF71CB8B66193180E42EC526D0DBEA3A09AC5347AFDF8D8CB4EA2CDF6534F3173638942523DDA5CF131F16D6C10AADA281A9433A8587630689B8C99EE2639F7500663318205B629B387F34A597F155DC5F4CE37D69CC15E16C5A52D5928ACC20DE10B4218AE58147837DCD502326DF7F54580A781A4E3DDA8421C52028B40B8CB6FC841BE9B658CD8D8AC78B5BA6E1038203105A604BBAD99EB99E87A6856B87A988BF999E62A1F621ECA48E1846F9FAD4DDD02C45D949215F2E5CB5C22C087C9BB76A1B3AF2829FA4DF12651AB40C537074AC559FC7726142D6B393C2C84E90FDAA4B237FDA37BA6E907477252C08AD2BE42DD662776F4AE6394EA84586F2FEAE8B408690A3011BEAC8F18EFF2123155D5901D16414AD9EFAC9D7C3055E1F788489BCCAFA7E4A50AF501006C57EA1507865DE034F1EA384DE714C7C605987B204DA4F4D6FA5B9A86C7787816C85F96101BB750E8B972C29BC56C66C6B114D95DCC75CB1BD96F4FDD810238528173C69D3CE02FC7DB1DD7EC783A909BA8454076BD664788900499BDAD2DC6DD82C5B78E0BFEFC5672C1B011EB576F952B7CB5B4D6D4CBCDC535EDFD3813B453037D1FA1CF1B2B13AE5425D33612B0DE26C06D8C92A1BBBBF58405340DCFA1749126B570C2B9A4B3674D9F3D93FB6698BE86E8DD15A65548DC08575E55CBE5C1186BB8A980FDB81DE7D3F5D0ABA4EF0BEF7635147EAF1F4F4D19ABA3F351AB3E9AC9A3AE83F82F97F3D503F14D97A0AA3A96A442E2B5AF96BE3EF0114A52BE6EE75D17E6D7742B6E34DD2A4FFFF0242E8CE2EFCE6C0E37BD003C75097F074D1D6288561A9D6CEAFEE82A3A46D7D708B5E482C6DCF6AE8EADC5FEF1ADCF536ECE54F633B3614ECB8B9FF7504802A96B59326AAC7C53C7F2116642EB2019340E19E6D05E79476667A52BB41DB42B2D931AA4B31F8BA83239F7F9DC659A6BC9D473D519213784367F8570E0B10958D789AE0BDB76A5FBB83A5B6DC76481A7CA594D1E1B358CD2E611B206A3EBD1B40D9C4FC75F48A5ACCA7ABCFAAEE8D6F38FB79FBA985E9149F9E08058603575B7B0A9E165A406B7A8A91822E897E823DCC742154CE8862322D53736D3CEED2F9131C0B221B5E57BB4F189BA89EAE2D017D9C4A5A2F164A2FF5727AB7477BF944164593765700F4D5343359B33D40732C3FE6101D6CFCE2BF449A10EDE35535DCE08147554FECBC5ECEEE440AC4CD5B6E0AEC1D4ADED71194147152E12981699C74A4A015E83BC0E046610331F0428703179150492B6E0938F35C25C14A01005D232E830D2412B5FA00AA94E15128F2EF837B0FDA1B97F5ABCA2C7F50BE1AFAA607C6FFE421C39C7CF579058E0F552EDF29B238E16AE16B79963A9CC79C0E220468FCABBF396486FD8D1665F708769E4EC29DAF2C0EED3A84B71BF5E9BC295240534CFFD57F68EC675589A746D7A690A26A3EE3D5F171D1E7E6014CD18FAD97D18E25C2A00F405704C7DB6D629E37D86AFE453DC7C331D6F75B56FBDD7CB12BD96BBFAB32B2B8223CF91E77382C997A79C087E0767432EDB331C49CE0437CF7E11354EE1CE887D7A3F7A5F5E039CC34094391A90535F996B8814092817CF4C4C57077626389CEE7BBC84179DEC56BEF93819E052BC31FC6B64E106A799F3FB9E313E1C334C1B49C8AF90FBADA0026C60AE137126A77EDB8EA1B45D7C3E7CF0CB1781B1D61EC15A8344E4CD077C3F12F04893836D8D7AF8206C99F55E9CF4DA24C0E19343CE6C25298A1B530906AC2DA839A35E59A2577CA2A40B100F3E8BCB9CC951D642ACD9A15111AB4F47D2B3632457708208153DC6BE4FCC4189D4B1C68EBDA663865744B66FD536453881B30B841E4DEE5DB9A0CA076640AD291E3204A9931233B3E8B68A9A3216B1F360A45F368E417D78FC5BA8F12E8AD18E2C93ED985D6311B372F6391906A0727C22CBCA5F82FB081F9573FFD41420BDD30F0E0C6CB0ABFA0BF7B44BC0EE55815DFE3BE4F94A761CB57E8D00D033AE4C7027A8DD7B01F690D772B76B1FD82A8DCE3FB7A19ED645AAF9DE26B16FDA08980684D26BB834914E1EE00944EEC991F9A6B31FEA33C0F1C1660A94625048E82F9EF513A79F551AD07C54B1FDF6D467D1535FBDB00E3CC5E62DE622FEEC2BAEEFF6F0B4B14146563CEB8303BAC0FC184E0711A9BD76F9B18B85EAAE13DDBFD1AC0B42983C16B157D6BDD06ED7E1CA63ED26C927C9C68B4E4208B50A35AA9AAABF3724DEDEBD0191BD2663FDC93F3190B59884DE71ED430E3B15DB9C23C91B52C1B6AF236E09898D7FDAFB97E0E3D0C3D108E1F4D04BFAFFCEE4D0824B6205C16F8194E6690328314DF3D0D362C9F33DE455D263ACD83DE83EF6270BF116BB5B3C5C219469BD3B37B3F69F829386F0FA35DF3246A2E5744BF83DEAEBFBE3CB941691F5EC9EF4843883296BA812D28D57D72C658642C3F66F40E1E37DFC87B995524253631E3281295B2AE89B9E15A47D3B764361686B885F478FBC24DD00B251DDB36E4114C0760E0C31494C8BEB7E31F40FF8B2C259D4395881F93F7523851D05892DAF86D3E7CE9FBB634E8AA6C466E9540FC55AECD082A979052FC3D985AC25B2D305E3609BA0C46192E8D8F42E84220A72C4F1DF7BA67D88613B954817489F555DEC826DB18A23808A2202B104B95ABC12245A674AB449DAE47A37FB79C988C4F4B1D6851F85F336FB617CBF48DD2500979F69A2DBB48476D157266C4386BDA4AAAF9CFBB2A8EF445FD8399D802F09B6A716B5A4535207C22E7BB2552096A9423C01FD04568B8E1017FECDD75FD259B0653684426374D37685FD5BB5D5816A5E3A6ABD9C649B1928E7A1EBB142129C4D810823B12A37EBDDC5A9F9C4401C98E1EE25B79E2A364E025D0F9F5402EACF58185037D19374F03D9FD8A7F108B37062D5C5449C956C1FEF12C7D25C89517E8C6D84772D2FFDAB3832E88C814A8BBA462FE3FAFDD4ACFD2FAE46BF995892A2782906066425BD508BA0E1DCEEE0A570235CC5C4131D7FCE025F2A3DE91387EA0B5C64813DFB37B03861090F48CE4B2013AD2CE79B48710A9201C6DBFDAB71957077CEB9A40FC445F42431CC8D7B98FF415DE916EF46BA88E1AB3D165CB5B9D6D163EEAF1BAF63C20C635FBD82A8ED252F3710FA0EBC59A68F81D4AFE3605176F47785CE8B156AF7FAD052A9645997BE5CE78313A33CC55E646A583AE9DFEB5D7B0BF90FFA49A79D8B1CC25D2808E4FB778EB9FF19E1AC700135BE60B6CD92DFD6845D9D6952C76CD651F9332984C98E98FDB0055F8AC2474D1EC2C73B04B38CFC1893D45AF50DC8FB5A164528F62664F82BE323D8257B28A84142410AD3C51846C99F48F516ADE0774B5ADE6F92FE487CB0A06E44863D1FCFF58C4072C80A816781287145B2C71E603856FF606D5B171375DCA2AD7F8C111563DACFA40F09697CB7AD9D3B22250F846F89D99BCD11B26A23061290E9EC9838C25606DF5917E2FE1C36B1FCAA08F9AC98723BECE4129BEE1B241C19667CFB1D73A3A33D67024F66821C3973DB80187CD56E71029AF76A0EEDB4320317844A2E83B6CC319CD6A85EDA3D44F7D2C78BED76618D393A42FB2ECB3961A78ED0F2ECCD35D7AE092DCC323DC52640A6B39A3D70EC8F1E8A49BC1C0AF8DD81F00AE5B0FAFA35ACA30EB724B1B51199CCB015ECED5F417DBF97C0B3CF8AFF1B79AA0CB23A051CA1FBFD8EBC67A039E6140B90233FEF308C1F9C4C00029DA1E36214582D75337A06FD49B33ED3DD66F7058EC421F00147E3E75A048F2249EA41FEFDC710AC23A5E76FFB7B5294B347AC2C13655EAC969F8A945C504E6943CC732B49B9B6660CFFF9B1AA45CA7B896C1B0B3B47EAE74EC17D2E34D82AFCA08899C0BD9C3FBF647092AF5AF64833DEC09459AD9988B7BD9EC0F38FE14B21AEAE767621B5A9F327371B4121FA2F2FB56E65B392D09AB8074AB7ACC1EFF3D3022746D8119233A14E9A6A107D16E6B86A636C96FEDFC3184D7153077A82E5E04F61A42B4A634E17DEB0A05B5007B60290DA72E791BFEF276617FB144FEA6C2CA666E36C83445077DE4EB788A0CD6064A0C6C7B79049273CCF04C44B373501064CFAF7C0FAAD850C81F064AD0938AD87074A68E16271B35F4B36C8189E9FFF8734B1F2C1A2BF1FCE4B33558A9A778FC709790CD710DDB6B8E5A0E0F5BC539FA0FF1E5C83FF19DBE6C49D6DFC3FE5B7121FC2EBC90419D29F2E29CD0C72F655CF2D12E1B9DC3F0751887CA0ADB956D6280495B88849AB8915E327CE56B46AD9DAFB678D34C193A2AB2736DEE6AF8AA975BDA6D5D6693952056B23512ADAE9BEEAC4BAA093386D930742D37785C79A5DE14ACD5F4A90C41C3F488FCDE1A4D3BA18EA023B27B2226C89792832F6D7C88129BEF1A7E8FA378E413085F57409FD22BEAB2653F298FFC01F7FC4F602B4F9D49D45B9471A7DDB7003898B8E3543588EB52304BCB509565CB2A48FC36DE8249CB1089F7115C892FBCB8FB6924425F1CF2C30B8B38509E99AE30C4213E11AC32B2CA5AC5AA1881B9F042714C043247F77C545E4B773C97805274B0CB5EB473953EEF2BD3D4CC21DF9AC49C89FE4B7D6A16DE358FA505DF9C0F31D8BEC1F50FA54404AB14AF30B2D25D890D14A4FD32F439E0CC174D58513AB263201525F13D1AF8DCFC39D9D6DC4903E54BE3491A95B174A6DDF493A4022C732FE06061A64731AAE936BCFF6B3AAD39068CCC7323FAD9695C181241EAC222B99F6FAC52A4183E5DBB99F189BDCA7266DFB6EB7E240B4CF6EF419218A0BD40B941F6F6F1B2028DE5CDB7A4DA2458A0A0AEA9CA3C0F2D95966F32F611890561A14E12F4509B0B38451CB5B16F9B4743FA750212FD1296103E050BB20E54ED0DF4FD081B21B3F6E4A27B059FFA448B47D724888430C7251244FB6AEA4F55E264491C3BDF85F5173B977219A4B4EE4F10539A242C36349AE2DEFCEE0E680E52937E1AA41463537A439BBA79C37019A3889DE8BF98939FEACD19BF80995730EC0C4E6266B71919F4A31B4FC93C339FDF9634CD40F04E4712C468CAB88F3D230AC2D2EDAF3E5A89A4CA8254BD7FEA6BD974A8A397C8B4F4B485AFCD745B7FB64A1615BA13229F90C4994D42556432BEC27185252BE2A06CB3142440EB751B478E1CC33AE907F24D8202AC638065A55A1B0EBA2706804AD349329A19B2A1AD7B7399887DA77377CCAA0D3E4FFDE54DF4BB54BA7A5C4C334DE181CBD788238C39C54D83ABD4680CD1A26B97168DD86F628E5BEB9328906D23D682A59A02B3A6D78A79835AB1320B0D8C80361CBDB0C4191FAE821CBC4D1B06235BEE2312B64E45B5332A26CCDF314FDC8FB3DA54B6561FB685188C9183A3B911924863F9C7DED5562BE104D271C55910D106A7E0BFC1BB0BBBC780B98BFC6D2F8307A66712EA8C460B812DCDDB3ABF6329BFC9817FC18502EA58ECA4B8F0742CE343E3BCFE11F856AB0DE73F0CAD00474D91A3818A14F08F2479A81B7CDE3A5C4926D7A95BBE40AD9839F2B2735464FBB78CF3811509D327E53D1CE14189FF6160C43C4108233B6AAD7D50ABDA2C1F8C76D35ACD5C8B830BBEE240C0828C0E0033B924DA6AC5E4AF4C6AB40B1CC6C790962C04778058F8284905B48FCF447983238F804267C547F9C74DD88418F3FECB6F3C310915DDF02FFC4ABABB52B0D7905296D5A459925E41B4A171ED43C115B2E1142374A2D7CA895726D8C9BCA9CE0C1C383C98EF9F27FF9DA34A514FDB356ADDDAA45B63EC282D2D9B285A7B437DBF01EDAF492FD61A69FE533D7D7EA68739FBBD3A15EE5E703FA32866793FBA4A574864AD99F2F51D67CA239B6562A36935AA5C3F250DDB3AD2A9B260B0C744D1BB318AC82A52F08C859D323FEF4C486789C7ECFC4E1F4512E4094083D0D373352A1AE8D76791CC68A04F83266DA849AE58FB84B44DCFF05EDFBAD397CE613991FA4AD7D232B77E0C5D1613EF49286FBB49EACB121ABD5E0DA5D0351F9FCAD64E695DB8B6C3F42B0D2A28A76D7593C3070756FE0783201C2F82B1EEDFF54A6E3C53BFCDEE402DD64BED18CB9C6AED0DB17955DF7E254E79FF686BBD89A1FBEC45036914705C93640A75C2CE2345A43D66AFF52FFABE340924AEC0E410C61EE452B2CA051078A836617D2F397CD2E905C0EC9C4EF7E333F1BCE5EAD063188805023947E70B5CDA4C7EFCA9CEDE464B597568DC2FFE45219834C90B77086038EF687BCFF43796F7994F429A703063CE5D147F0F01E2A98654F454E3DA99D715875D6686BCA0EDC907A14C41B6D57ACFA6A6E05C9E3BE7AC9BAF68189C7F486B26D9713298E3A433CF6BA01B8387EAB7B1E04F1091A9DB1BD8C3BE9033826A686C5DF11E8DC5A351989B636F4D1A3F0E4E2AEBD3FEDC2CAE7AFF884984189BDAED23B1C18066BFA2B49D6B4A22C849B47C1FCF49927B213613F9A4EF377AF7C8B6552A8026CD287CF1BCDB18A983E47DBE482A74E5F6767D6AD8FAB9CD06EA154268B862DC240A35233753690577B96AE535784D9692FB254501BDA9D3D9A6328F0B4B2ED872D51969FAD1AC8DA5B7105DF50C62A0829819996308E3348AD08A88170E255D50F44FE3761BC6E2B210EBD90DAF05495CDBE4BEC6460653BB98B9A49B9C872EBE15F97BD5E42DCF41B1160B406295678B7964564CE748DF5015754908CFAD318C3BBA3FD41DDA248D7B0DB1C071F705E9D80D5EFAEF33AB972ACE9891DE6CBCF6FE75825C0B99791C0DF6A1FB86C68EB6940B0D2A0DA6E710A39410458DEE30028FEBC78CCE4494C374BA8F2A118B1881F353EFC94B847AE45B23129DAFD03435311A3B93771D48A9ED15416BECE91E9A46515B076621A8A371439F428E5239CB744B4CFC001B1DAEBC378C7FAEDBCA28573FCB5C16FDCDD65C1D7B6B31DA4D4EA4DAADCBD553ED7755F2CBEC29745C6FC274103AF25F514BA8ADF2AFF5841F8D4F37BF53674D67EDA2BC467BAD5788E614BDAD04001544A5E3AEB1EFA1C182175A7300C92FBE948EA931548E9894A76FF5119552FC225AF2C771A5BB321C5BA50DCBFB40A505785EC7801B14BC560BC7AE02EFEA4B9967F3EE3DE4A9972970B22A7E8AEAF5F9A39BCE663F298FBDB3F17C444B04D87F9E1D0F553AF41A13E1EE4C465199E0C41DE48B23236D28F74F40EE065301869EEBEE5746E2DEFF05F940A2A1534FDCC5528C59E743EF02983A47F80A5BB28E521BC7C6AD99247177289B178690BAD4D25BF448EF3E4A27E98525DBB498FE0AD31E58E2B4110401FFC63239852092BD1E2303172877723D57C124B0F007980FC0BFE6F9391BEA5BC53DC76179A59E5963C213AE87075E9BCD501F36A02B31C97A35C3E9133A7CE08B5CA57D8BA980E8F7903F2BC04BA65FB4F2C00A35FAE5682A1A32F95773DBFD5789469BB8DC22D30B0ADDDF68B0682A2D9E9A8D228A96FA6A5A6EB4D23164E688994D09816136000DB79B68D46C38EB382BD9E9BBA2A81FB20A63CD4799DCBB0E6B85DDEC9096788BE73DDF50494E9CCD515CCD753ABA2CDB69972A276FC6A405F85A51CDD17F2E7D535DEC8C0C0B34147875EDEB94F0653D35BDFD7EE91108E983A943D4668C0FA3BC01E5581FBC9572D776752E65D8989FFDA22A9AA502981A4CB791EA2F40616CB4A4042581CE829074A53DDC5FA681DC793A78572E941CB2408554674FC775728DC5ACEEB858FAF01C57B303E9AE3F39C66034D21B33BB613AD53525B1D6ED3A46501E4D1B271A5A1D240DA2B94ABD1157B141C65BC4ED6B426FF6D260BD335D2F4ED3593250D449A21562609CDE59FC8C791F169920BA4E8FD62D0A12BBA174359D5B5C269439FB0589573298C234C45D82A87F390297407486543D1827A10DEC0CFD9851980F495B185DEAF648475EC171F57987AC2021B46E551D5E1FFF01DA50A493579FAF69FFBF5F2B3C62566BA395F85FF4436E64E22102692AE7FEAF05E532F49CCF598069CDD56863FCA3AA1851836BAC9C57BF1B251A940AA03DC6533540C0A381975B165B792BAA197D765ECDAC596D6102486FC1B305380E2FDA2D4EE23A0EA4F499EAE94E1A0831DDA80002674E571D7C335C47DD75E1E47616126A5F1D8A407B0325C43A531B9D8006344215C6191B785B706F630513DB1780364576C7915A892CFE9ABE9FE4BC397F04CBFA457B67DF8074AE3BF571C6298527DD0B564E6E3BDBC7969E2C2E35D5AA34145DAAD9B61F3402DF7FD96EBC8C7556E1E6C4B292E1516EE9B2E0AC3CC239F2B1AFC4FD9DCAD2E940C878CCB3276BF4D89C8925EE3D2C9FC737FEC2AADD349C23BE4BFDDF0C4C4BFA6A602D6C0C6C42F2351FD980410ADB5B3F94D88783C192F0E7F128D6665A7EC03485CF4EF91F4BAB231886E7DBC1B2E04135043A84BB364173909F395161E78594D0E7B73E7E3C014D917FEDDA0F21F68DD0F648BE83F118EE2A72D0087AA3ADC5FA39377EC559D1C15884036CDA256C0B79E735896F84EE8A99665B1A6757E07876C77FDB99D5C1679467BDE25C0368CF7EE54CC5FC250C1082B8074000B42FC5D59B3FB8345C72EFFB778C840CC3339561E6018E25B63E01EB72716D4C4034AB18A958D31D75864271C144B236CFEA88A2B8E01E5B8AF1BA856B1A07D2D236794315CD5811A8BD5D2F9605D0D6FDBB66332F84AA07CAF38F053D65A270C362D83754D2A8519274E46765D138E8FDF4BC5F709F54E89AC6191677C7A99480588FF4F049BC44AE020E07D60062AFDF9AFEB1C5A9B08B6AC31E7C896F89E2503BE2275D97A26BC98FB9DD9A5FFAFE23891ABDEB3F0A45DDA486B07F1500779FD5DD8DCB29B2C2A6D96430ACE44471489490B3E26662641D967DB8C324D1E2EE4874B9B523F17DE5C6C949A7B73AC7D440C2DE801A30043D060CA4C279EB66DE7E11659A83AF0A11109EEF252D07D188238835E594FF2E590D55BD7125B65BC74DAF681A4BC3EC09D2F9929C7BCB58E78CBDBB5000AB1B88A4E1B3B501BD07A828D0AA64236DBF1A9C6E8C22F891B568FC35874B8771A83879FCF411F3B030946048F4F1342C0F671DF20041E4C752B6875E248ED46F36FDE641234A04978CB47841130C6C565943F72C575F725D82C147909625AD656036F90BFCB184B865ACF52FF83BFB2AE91416973598D8871A691ABFDD7407142D71AC437497CC4EE0580A2C1615EA2C0C6F14A1EFEAF7459E39DB5B7EAAD55ECC65D941E21E890D9E60E9AD3C4F76F9FAB1959F9D4665EE6A2F06BA95E1C7FF4202C994F35533947F27E30A121C5A1FA4B4192BDE9CDA5AD8839C0E63CA41D7CA16AD66F34C5CFB93FF3410AFAC530CC48628DBD0AF440033EC6F10043BF46564187DD01E8173D5B8596A3B4EA074B5B8DC3F4A3609CBE99315D2499C63E61E8A3B36E7B38E7C665014AFCEF5DAC9316DCA695539572512D44050B577D38E4AA54FA31EA9241A1545C357B38333F73AAA75ED8F348D120232BAA4C808351B22D3D26C7BE243A1F7511160C1AD2C2D4FB2F0C09EEA20BD2C255BBED2C570BD8EAF77E3C3417678B676B5439434D00B7260E577C9E6C5A068AD82504CF4C91FB372100DDF0484BABA5329B93CA4764A025D2031B55B573B0153C765A86CE8F7D5BFA1BF40FE177729D48E7689DFF7AAF38F336FD542071FABEB7156EFF05C31F4AF9ADEA3C28123C10D89E1B9E5F2726E6D4733C7A04070E4A928CD40F499E5C8C7A8BBA1BB9C821640FEC16E4D4745257D2C27276EFB89AB8BEF8D0868ACA957937FB337BE808558408B8F9A84886CF96E2F369A251E634F9073F27DBC86FACB8F008A57200831F6B18050329C392A378B325B0EC6C584584DC3C8E2C6277EC86B0434B745BBC5826B62051953A8BC100D75441944F430EB6E0B4ECBFF2F3E452C615C452C0F777E8FFA308EB3FC3CAF4F910B029A8832AD59C38EE7FA77E32D2713C1490A88DE4EC81E8DFDCF014D6AEB26E6B5134FAAF43023827A118E81B6C9DF1FA3EB313A3A8582D9C62325979434DC953B343DCE224415DE23CE24886271724FCBC1A30C8EE2E4D690D3CEF53DAE228579A1DDF8A5561808C530853246C8A9F0E486FD9F2BA98064E4203DC6EBC12CCA9381774CFC51773D9C3B51FED3D89EACE310C481FE236D6098E8D6B270491A31E15C902AFF30D6F948047D4A5FA0A9A4DA35B00814A5DAB1390E828AC510B56C6B5A7F9A8CD11D32384E238DAF7C45F2A5624ED77076796D48ABCA477D33462A8B61B03C64168D7473C05D162520D0FC101CC9F0826A0A663F7C6EAA98DBF29A8559395FFB55334898BF1CFD25F75A5664B4115ABFF11CCE4CFC643D16254DDCBF34E8BD627B4F3F9EFBE048300A3C656CB9CA12639286642E6D5F2079C2D72EDC4DD1FE95CC15B6A0D53D02314E87E9126BA0BAB17C6D3B2F104492D705AC119830AAEAC5BC7859DA8472C3D29AE7FA1995EAF93F1C92FA172A44D4FB1792B620CF4A69AD9FB58570774CDF8A915FA7ECB8C3CD3A83FDE7EDEDB5FE6A9F404E44DDE4185E418D6104ED34EEF2F818F0B46D46AA34AC60AE6A96003E9082E9A9B15A93E0E2FD3B6C4A8E58C01F4423B7983E83722C213D3D776982970B528ADA7F97C80AD06174982B61F9A5791CAFC16ABBD66FA3CDA59043E4634F6CC8FCF15D91FB1D6FB3AA8BFD0088E5375EC55DFFDABD4E61A917B3CA939DD19680031C11F5DA35EA4EFE6A1608AFCA2C7059CE245789EFEB3A50E65D4DF3F0DA4174DA061333DFFD19FEDB5915B337739C46C81AFCFE69EE08BE70D2B3F01949C78E24373B941BC568F62CDD2397480A5E87C0E4E1C2F15B635429C21F414B3CBB2F4B126B3B0111310D63655C3035BC4B85B2DEB44C88EEF0658E19477C531FE0DAB759A4996DAA0520E7FB444B0CD6C1A647A9C3656F41E98A854EC2F737658BFFFE1532E6193F1E6730F08D56F34210DCAA8010DEA239AB21622C8DCEC42D35779FA7A3A499940C0DC3F8A04B3811EAA9E34735DE2B0AC3D7982F276AA2C1AE360AE46B762700EE9D057599CA8CFB91A7A1AD248B5B26BE59529E9DDC349793444A598810172F8860FFDBA9255FADC93C508E021E2BF38E32E43F26E5887E1811941680E2A04A4275AF58556E56CF091D2236F614AF3C2D5EB568FD6E4F9BADC4682CC1D98092E5F99CB7A89F95BC80BE961C341E5BC854943B70A1DC3FB9CDC9F79C676457FF24BC749D797A21ACE5C1622BF1730DD5E47897BD9D973D9F30C354446A37C2A23F7D55899850E131B8A44C8D08F6C6C62EF243E72013CD8A266636778CDDEC6D2213679B59B9781BC3DDF52CB845A1AF053A3817FA4ADB057DF765D76BABC001528C108BB251F397213200D291D59789081F0E06E6AE823F5140DCEB86D9DFCBC163FF330355164C737ADBED5B798FCE81D23CFCEC03015DDC74E6CFC0051C7AC8B3C4D610324AE81C6EE6FD9AF0B8079E1653FBE5CDFF7A76CAEF3EA08F3981A7A64A235DF2832E718E0076E7C3D133496BA454A2C0FF590FF3DF929FA7751345170FF4C1C4E1635876529977526FE7294CD44903996B7B7673EED5950D200C89A0073759F14558E56C14FBB93890FBDE01C41161B7B9683D8D9FCB8D5FB9FDEBB3E3B017F8FE6995C34D9ADD61C10CC91BAC94FF73CAD9D2DB22720367A27FF4E1C3DF9CDD4E5483019CA7259E86DC1E60048AF282BF9322BD5A5A5E4FA6F46E785039A92F48983E889C444BF92FE96C7FC71B15A2B50E81EA924702B4D0D7B77A78843715DCB127BF55FDD6703AD72A996D83B87D23D0508B23F3E600F0676DCC64603E970CC55D99E1657B60272C5944B5B39148B539BD41895B02265525520C19241DC77A1216426B5ECCE93779A8B8F799916CA4347374239E5781DB4FEC47D94B7DA42D3CE1BA516F8BCD0CE41A00446CA16491E544871BA32B7451C95EFD7657B00DA82565F5B03F3A825DD4479916FC6E7A378B37C77DA089B09D0333F719B9FB0C0697E8575D93D10302D2FCBE6183A5BFDB7FB38143BE74017A8398C0209BA5805F8C84062D49BA2495FA2A4409CCAD2E67973C0A8D086197D1A74C55CAE0B315F8A315BD26106FA85C0E56C20DDFC243DEFD20DD635114CAF239E3CAFB5F720D44120E32FC70B2DB14797A47640F3CB9B05095B8D5A8340B5F46E91C0210B55C3B87FB4E96740EFEDA6503365DF8EE902CB8B18747706B7422A5A292F909C1340EBD5BB5BAC5CACCE6C68BDB2E213CC04D7DC0A029DB881E2CF41CBA9354133DEF1DE7ACA7ADF9CB75CFC0F4957F791C45F0CEDF5D738609CB11385A3A2CCAB12D3BC371583BBB0D350062C6B8D027014E9D867A88034A58835638EF0D812FF353094F0EF4FC20CF4E65D03F62CF92F9A5C2129D67EC3783108C08EF566440B45E9ECC9CA3A6B21352462906B4274013A5E43E577A0CE746C3724C7D7819AFAAA384344020C9445DCB7651F9FF1EAB2DBD8C41EEC4E8425B51372C30518ECC02EB1599C6FF015BFDEB95B4E8168093DA38D3EB9B128B03EB7C5C1339E3128FF8399D72A52D908DFB49BD671AEC97D62A99DB6747E1B15D27AAA81CF76CAEABA7730C31E13821AD3A4BE0F052B2F858A86DE81DBBF04623AFB5DBFE6D1DAB8A62402DC2C496BC63063EC9F2483D7B9A64319247B1E77CDB49D24AC42571F6883AB921CCE0DDA2333D56F991042CC9A6AA8634D15EA20C730CDDA9F758E1E85EA2C9D8698DDF70DD791E184C400B2217089BB72371489D315B22D7B5CDF845E2B1933CC79E278B0A96750C1B1A32123EA7F39F1C86354A59FE0069DC84051464729C08BA719A3B2B18E734A377874CD95AA862870899C7B8358F06D7F924756624B5FA3526B1A6531AE039553760E93C9859343B2083EBD77E886953C37DE03884728344854DF96B996BAFC6FD14D24CDAD05E56CCE42C356D63C413C805A4CF394E9C72C263E1EAB19593351C6CD4F2F249BAE08AF6DB409C6ACA22BDB034E577578A56F69CFFCDE9CF8EF2649085E5BF6EF68D90733EF246BFF6D14E43E86A7A5AE7A09643E0D3CFDFBFEE37A404D86256835EA63C71B2B8FDE1C8B729C3970234D6E179AACD662A85D1A5F64C7936561B8BE993E57CAACDD558EE0C69452093FB12660DF2DC2491C1D1CA243D005010A4B6EC286601D3C999249F2C3DA825F693306856BF04549E600D26514D20CBB2B05219974F697D09112FA3810CD74C08551CB50D3D546C511C59D10B648702FD2458D7236FB9375EBBF5DA47B2020F85289C2EDEA392F573BBE4F29CDBD3612D5893BBE502D9B9D937A022667DE8D6FD57DA85D5D912A06CAD105E8A95DAAA8EC3CE228648AB0F80B5690ED09BE9E0F76E5CBC502F04F7DF981C1666220FA0646DE75B56CF67F43423586ED9F7A922F2FF062BE0470B2E9B2CFE4042EAECEF0948780CF344D80C91375D1186D224C94595EA8FDB885826D762CD0DE24EAACD3C3503980EED4E978DE85B45D9572DC6568CEEEF445FB627464528571A80A961EA39BCBF6DFC70DDF320192C730D1C48F19A203DA648170B60323DB088B7640EC0382A72287D8FB1241011197DB12564527BBD501AC000C1835DEAB9D1D84059F8898E9B8D1C5861F6EFB89B1B96D015B42B7208E9E39E1C4A90CC86A93160F65163A485C34B385CAA6423A212DB92083446759D1DBC1653DA3BD2E0CF730A601C7F7EA06027D117A71C533A38316F1507277DE38DF954EE88683BFC803439311F1BA414E596471D4B020E0BEA0A4F5F0DD3057CF2A7DFA213BF68D0E54FE7193334F70EA4B26F079FB01B442FD2EA4D57F7816CD099B15B1BF8328FFB9FDB6F7AF97153E37CBDF26B4621E21E5D9D3886C80872308CFA86FF130703A65B541AA3AB1DFCEB960885D54E81A7082C4641261FC69F343C763FEC4713D0AC11492090581CCDFE78B9C8CCB12E30DFA95BA6585073944F94D4966B1C0759955F84C10E654098422EABFA60114871DEA2ED82F3F9FD1E79EA04BC2FBD95CE3F882239100CB6F1B4C5E7B994D7303FDB4D283F8FF93D87A05218BB040914CC87C89A1A7F25FC62FBB1B6CD3DF2A9688C47059FAF07CE7881622F39CA42BB9ACE8CED335FA675B83F179C3EB109190983D9F1201EBD4F6FFBBC1308B8C44D8D7828444CC51E253BBF0A237ACE38F6E50D691CF506292646641AF4AAA373CA86A149AAEF58A514D9FA988E6FBA911BCC510898F1DB176988B3378BE633E90475A909FC690E8BFF3A1B9FD8744353512C8DC2DEB167AF1781F0880BBA8BDC2C15F67C932C1390A776B3188A0BBF3DC97AB0761CE70E563B97E64F392EA70168ED91708B0428C3B568786FD44AC054678598C9196CBAB664DCC855A0A485AAAF2120A64DA143D8179F74413D1A0B47DF9EA29FC90C7D03BABF8D6534EAE6754F45F144BCF5F41D229207CAC8E24A9C2B447CE218D3EE0F469E2E2C100291E1480C3BEB60414715051CEE1FE291F9297771B1F029ACF5AAF6DE36AE3877FA8483FA678152069C549F8E20704A5D81F9FC25DBFA493745FDBB675F8245E83D8B1ED04962A6AEB88013632F64853953DFAC8D47A7A2B1050EBA9E05E105F60364AD613030916D1572A1928186AFFB9A8ABBCE2B276A8CD06720A56601FDA15E495F45DF761BA71B4B703E2962D379EE6610C2FD74E2EB5A84BB2395200A61CD2C4B907031C34BE6C583123C531F8E1C672754633510FB4110638B8547776BBA62E2E1CC20FEB1DBD33542DCD483D43CD61FB6F6109D19C3896C16353004A2A0EBC4F25BF2CDB63E3AFE98CA0F8BCCA674A36E4BE20ECF14187A1C70557604E4157B10BE63FC0CAC88CF452F09C867A28D52504AD5F74EFB434D15DB4E27BB04973F89346BD2B534D4C30D94FACBA022A63AFFF30F785FB3F116AAA7B6E25C53C5CCA3C1D8B3969D33CDC8886D2B2EA77438829F6F2D67375E81310202C3FE06783349B621BCADB6D012F8A19637CB1B606597721CA530734907BF6E46A02F68202EE06FAA60AF51A89A3A2F281DB7F35649A975ABD2C2C52F5B5D3BA363BC3ED5AD6944E93F8409F9B372601EF7869390CF8B9EE11EE16200CBD81EC7EA9D289AF15AB7E299238EF887A266C3067DB99829F4BD1A0264D7EEA6A60710131A29DE8B5073FACD14C7EDF4F5A50F07AFBAB762151D53F5E4E2E1E1F6DED490F9E0FFD687BD042822064972D85960E0E8C19845819F3ADA143625B85630B4429379DE033F929852EE3B3F5441D663DF3B0A28F07E8583F8FAFB70D94BE5C51F0DB8C74BC181865509F6E20A71AE316155EA06978F821E8C0A8313C8BDEEDFE4ABA080CA49675BDA0A2C7FF7BC6C32923C5122A19BE99C9BD4DF2DB15659D98001918F6B175028247516502A931D1E818DBFA24E3447C64E538A3FCDFF392C802503F1F56168E4A505EF42C5FE0E99E8A2A74D97CF6FF8F590BCB39D1783489013BD4FB75D94D27FCECB987BC96AFF6870FBFD53563A536C4607C541747F7AC61F2E1557362FCDC235F80E212BCB7E5AE8ABB18E83A4BA0EEC48567208A043AB2860F1CA773AD0AC50C53395280B48EB3E5FE6B27B61370D0943A522583EF87139F2542AF3AC4CAF7AC5858108F399BDACDD9190B1263938F254E969C36D8470918663554C3EC46154587AE7D301DEFF6BC9F9FA16F50FFD1D258E05DD102CCE2C508AE8538C64851CA6169B11BA21DCEB06667162F42B16750125647DD73BA9241E181E8B7F2C4F9622847148A020B701119E4327DBDE9E4942C690C83EE2FB97FDF6BD5388FF2FAACDCFA3950D4E9D1FFD06204804EEBB0C2DF8D7A8135339A36D02DB0491C19ECBBA6516B6B8C0A2BC64C1ED62AFD49D989BC004752992B6E477A68F12CB0AF6B9C96FB955DF3D2E41CCE221BE48BE424A1B05EDE38CE1F374EBBA4B24769EEE2ADA2717FD48059D7E1A19E1C588B8DF7A7C756672DF0DE7905273E194AE1ACA6DA06627D059B695342BCE49C348111E28D62828C5BC1552A2DE0CE2592EE355FBE22B5478085D6B0E5A2A1C28844CC2A44F83E15FD5F6B65FB8684072A2EB251F2ABA5A9C249538384C6B6F7971B38E8302D960EFD9061481F1D24776C1EE1FB5733DDC961AAB48EAA3A68FC14318519DBE7D07A4A1D7AB041246E1104195602141AEA2FA44D0D74FB3CB3990D2707EBCCED86354E188694D3F9EBD1DD8D8E9A562ECE866C71CED3532F12B8097612987986731200C4E76138B12ABEA00F23FD23CF02016880CCF9EF23139CAE7F29BE0106CA0ABEC03A79BA26E1D779C062FE8ABFEC95ACE73DA3B65D4A8DA05E51D2DFBEFE09CFBA23E76B18305181A9F957C6689F1D6B27D967795EC97F1889E4C59417D40B4D095429EB781E8AA497A51119D22C80B84ACD5D42C2CB71C06755CBB5757A39AFD38F9B6EAF8FDA163CBA5ECA0A7DCEF1FE1181AF4BEDC22FC53B4057FDFCEAB299ACF4D04B48BABF6AAB1FB9269835ACDF3C826C368EA63D916064D829547084E3A1733AE053B339F7BE5EEECBD3C30BD852A946B2CEFD8AAC2D97B6F95635AE94C1D168F1D3D51977F391BE92670D15D2B60AF3084CE24BA64D5ED42CCD907E41C3AFF52E89392BEA7AB539E5D3781F6F41E87CCE0682132BF1E4AA72A18B9905E67C98FFB1921649B6AF171E301D321227B8814AE30C93311057E39D041A1DF3FFF5E9941D1741754514E34000E4477E0F32AB2500F175C7A9F6CB9F84501D4D1DD98C86AB3ADDD083FB5E79546509E85D23A9464A6526A4FED0D947584F321CD551E9B3E29D49235ABD554D3793F2C668A03462B9BBAB54FDBD6BABE039F47BAC01CD5258084E94D9DC8E72B5812B08BE80AE7EAACCCACB67996D0C3A0ED892B78BABFFC321121DABFF0F96C6F6F13C2C1E0FE6262962B13AE19288E2CB4323E349475BAFE329CA32C9FF37902445D8557B085A2697223366247397EAE9092991312E78C9C1AEAC9D6FCD2ECF9979C1DBB559CE0780CC038BA5B85D53ECCE42A32A19674EB1D1DE62CF33DEBAEBC8B31309061AFBB00E698ED5701A2F08568B122D6098A864C27F45E62F103AA22E874E8633CF75565456F9A6725599AF53690C9315198B314E05B76F7AB6E0506899D1F908D0370175719CE452290020EDF28AF27EB6BA1A7242D4987242886F82ED775616A832996BBCE72222EED462537BDF770E6DF27E5A9D67F138BFE0116D7EFBF848C154AA4F43596735C95A6CAC273971FC464FE647B32746891A54522873F02400AF7FF821B8A90E9B2FD7859DBF3DCBA95469237E88FB8A4AA5FBF9BD58F27D0B2A22E801E447D3C2979F062A3A2BA09081980CB596567DFB3578AD706D451D725A2DB4920C1693A8D89180726C2F7E402C6084FD083CC679B0847D0AD9CC8EF9E90096052A2FE127075375FF5B1087B883C3F3DCFBDF30795A97D289E6CCC6A8E7831D2A11881252B468515ACC5F7F736D798CCB6EABD20DBA2110550783F00A798B167AEC30AA9B1B840A51FE439A6FFC952C3E9353614BCFAE6926FF73FB442A2555F1C5F13BDC61E49F5EC945849F5B96D877ED090977BE3EE47F19CD31029EEFB3A6DD6EEA5EC733A30E20640DCAEF1466EB6E2A80A3583FD53DEF29E5842B24346D3A5C0A3F8A1CABB6D25CF94F79FD94F76F0CCC4810243A09812C57ADE6F304D36C261E03250B7CBE641CBE1371A947E01CC9AD9CFB22F7E281218514C363D352A4776BF9C842C98A55317A64776383FF50AAB566FC43581BAC0C78466AEE9F17931C925F19BB9A70347114249197E109B906AA3859AD3AFB9EBA65CD80380FCD0375BAEDD8C75F506BEEF5FB69214B85C581A3EA37CA049D2CF41FA9D197C8EA5A173A335D6F7CEC8034906446134DF9CD5DF48C569D401511FCE3AF18737CBBBFB58D2FFDDA2E6DDC126CCB6792BA0F3A973A57E1C467B0C56433CDEF37BB3BAC0CD8A19FAF112179F7425C00244F569BC3187A7051AE3C0C7264AE3D16B244AE3B6F7F5B52C5175D927D79D89C87890F070B6C4A951385856A2E5247CD968054F8FC600F414019669886F8D918D6E1108EE12F5C81D19C9D619E14EEFE03433C27B79E7566D4B348BFC90394BA386A408445520AD01FE6094BB9DC60B25A8C67E727B0D83FB2E94DC611E9F9E53955D96F5AEDD37FB0938ABA88178B268CCC45EF47187B31339D22FA0E8B7C17DDCF07E9DCAEA173C5965D67E69A5C4A6C50353C9618135E04F4F4E430EA559138C066267EE075B92399355F1DEAEC1767A20CD5F2631FFFBD27C93787A5C4CBCD55F75173FF5984F5DFAFEE1D5CB99243D6CBDB53A8186E590722B51FEF25361D92F98EA9663CE9E48CDFB0890FBEF43528368CAEA710655E5621C074AFD98FBDA62C6E51EF4E89DA400C7800B505B2D28E3C0EB6C601DA519D8667407583E05296FD4C5EC47322F632BD1A82EA8BF656A58553B1170D2A5408F1AED17CCC5505B19C6ABB359EC2FB5B6C117D8A2F777AF3BCA77F44B8152DA31D9C13626A9CCF51D6DA226762381B5DB53F48A8FEA0DE8BA163B27EAA56AF440E42891EB46DFE75DA771222990692B9600F2F0BB3079347594E4630410C44092735183BA9486650C7827579FD44C714B30C4061D9DA324A0EE66E4EFEC0EE06FCEBFA1D5363E14B43D4F1AA3BC6134DC408036B03A5CC26ED54A4BA992BF595E27950CE1503709734EFD6B44969F8EB5346C281A0C5CAD5DE5343580EBC713025DF6F827EBA23E7D08D958BF8D0B24D4562FEFC2A0B3A9DDC40C73EB3D0F7BA93A98296102E6AC4B67C331EF6C9D0622D18F72AFBBD9A84B3FC32DC350B17D5A85CECC441881129F85AEA72CB7EB88CC4F0B63E7D4DAFC9DC01E1A09BF6B095F9D04CB0ACB3A7D175C7E5DAA908D46D7BDEB41395B128D1ACADE5F07EDAAC17C25885EB05111678984FA18C34991D912F8E8ABE2753358DAFF4D4B24A63FB4713F61628E35E34FFBB9CDAF71C1BBCB559F2752C31A927E245F47F2AA852A9C7A376CE8F23C5F64B11320FD0A4F26758F7B39880FE54FB8E4F354578D7067713DE3A7048907EB635C7106E53A8F5CC07873E741F288C36B2588B76832875F9BB2083462BED1842909E4E08E0C05F32D69F556940797D2906BE65DEF3363399F27D8E8DE6500671545DD1DD7032A223B6A2CC13AE1D641B68A3911E5138775DC5CD5E2CB2FF53BD38D376E6CD707DC75A5A479DDA1F42D8428FA6B2DEA527289E61C5DEE1B54C73273C311143BD6788A5DE4E97F9A9DCF5CFA8CCA3E6B71B1916128DE6670043C4FEFF372EBC78B0F6557D517382F7BFE770396C54BD8B89A351327A7827165D5F77E339B9548E0C0D863F5F8162E9C32D4251CDEBEBF9EA5D3B1B9BE0208C04B12CBDCA2ED47DB86526A6A5CBCFA712F10A915207F1C575FFA247B6961147659BD02B7D004C0D1578036E7BA7AE5A038A59752853B0AEFAB7B0A31411407A1186A074429C2DACC5238E4CF4CF2ABAF3C7CCDEFFD640C1E4721ADB22FD890313C37EE75FA4BBEE7DAE359C428984886EB5518E6429F5FB5E4CD6AD55AAA2DE27CD23C29F621DC8EA03BFD69BD7EEECB38989F853565BE4374A40F5635DD0943FDC00741C5E0705B2C859E5401137F7ED30872F1BD0405448A5DD3D52787810F6F3B779827DA4BD724805721676933C4A4F8A4EC9AB2114DD3F7DECA1966575DBA784FF4FCE97EB8A43340B1F66911FD4AC5A4C7566F0DE74CB88E6C5D353C72BFE24403F2FC2761D8AFC31A5AB23399EA62C4A9E68CD923E27A6C9CD4A165BA2B872CEBA0945FCF7118C8005D261CA81C07DF59928445499C612BF4530F5E9DBEBE75751E72E38A93B1D7A2288BCC32785DD944DE596B080F57B05B8AB7A5CA6CF7C7FC10F82A238A944DD961A487F1B9B0BF7E03F44D5134B7A084873F018FA466F501DF10919F963886F9075D7CD80E6736E3FFDDB8A80750F7168553F45A4285641F21625A365A479882C0D11F92C5E8F28B5CD199E1F3F3325844C1FA3AE52861583C194C3416BCE62B8F126FD6E3BB81E8A531473F7CDCD6B792B7782BB382968A467B5BB232AEB49B25BD9C53627B34890C8F631C18BAE707044D807E45D2AAA833BE32737FEE16F36B7D218772EAA78D56040362DB201FFB93ADC492E2E339F7377FD2F4070D20FFA547FE127298E04E7A192E0C774098F7C03A813A15524F2A3EC3C446818671BE3F7664A0E428E6A311FC6E687072827FDAF3BB5211409897F50698072C3F616085ECB1015099EC20EA104CB44470C940FB2DFC12CAA34EB36D7200BF8A04FFB6E59C6BC9714127C2C011D4E36EB3637028A652C403D77ACED0EC870D8AED6C4A4B2229B300B319FF3FE2DD19C6DEA43862D65A31AA92634F0B7C53B13E62ED48A95CB5396F28BB74590F1239F9DAF3CCF6C516355FFF4F39C0B0F173A7ABE088E67BA247906EC73EFF205A254C38C995E498C129556240479544A7CF1AD59D6181399B018C5E456490C006B8EB387B183ADCD66C1E9B1EA06FF0D48619787D8DFEFFE36706FE5538006B79D68C5FE848C3410F74D0A1120B8B9C1006B91058A6871FDC8AE4D68A0A7A1026C3A1D64274733E1301AC740E530F81E91B95DB867AA090B39A8617343D344771BF28E1F52B42ACB7462BF9A9DFFB0CA000EA2498610552F3E028C7C4AE8B33126764D780BCC3FF0BBA14A1170934A2F2527DC3370AB0AFEDDEE8D20CEADFFA8266043AB73B50492BC9C0E73A1E50A00391D4B36BF7905300EEF903EE6E7ED1B174F7E7DEABB31B8A0C7A1C6564AA28ED3F6C152D13F24BE5BFC16967A9311D96BA5F99287659B92D6E23E2CB3EB2C010919A8C907A8DFCCF4F8F501290D92FAE8879835290F51304CF754FFCB9AB510AB18FD89CD1492870983033113F62ED37B1A0451440C66C29391B2289B908802F1E061F90440F732440DEC55992FA1A4B64E36579FCD4103B6FF3E14FF51B164AFFD7D9235E08B3640E6FA82495E72339513D30EE71AC9C596E0E65576AE850A07A9CFC6B64DC02C5E2DEBF961AEB2F677B1B789D738C07CC63F6F8310BFF257CD7DC8519CF9B0F0636780237913697ABA478DA2600B593F16BD946366114D0DB1CAFC50CB80FB3D9E4A74444E38ADD99FAE394EF4A2F49B2D8A44F0DA1C52666F639B73BAFFAA4E355722F6F4A0D12C0FEDC8AC487C202FE771C5D3A092159C1211D6D6F9A294FCF52994DC8DD7D7A7676CE9AD3B2EFB90359D527038F1ABF13ACD979D576A8C1964819C8217D84A6A632EDC4288129A191253476B0F674761A369F2096B90E7B4E007A42B8833AFE596B99153786B16707B826F80D20188281F3EC843038B6BAFBD6CE7A219BC59A091B8E77A45F2539650DA1790E7D1CC0EF4D6C4DAAA0EB371EA8BB390180FBB2721D1D33885C52F1DE3D05F746956AEDA7B6D6E66B29919F678EA54CB7DF393F962E5C3A0AEC426395EE1FA31CFE7D904A013A630835B13C49C8BFCA5CF09DF569456FB1F49B241D6159CD698BDE34F0C76AFFDA1C718821AD1325EEB444FBDD6958B4085A7606A0DEDE3BE38096F531F4E55A106C64427E20EF0CE6FDB81DD60B1DDA74AB713BD902FE4928BAA48FFD40A1CC12293F1118B14F2208FF7EFF74D3D55911AC2AFACF98C16F9EF9BABF1BE26C3EDEA250797DC046C6290AC8014DB499533BD2E58266C661D96AF12FC2681E40435C6B45AEBB1260F0CCBEA4AB94D927C75C101EEAF24CC8FDE92B7DD285D099E496DDE0229815DF89F887017C4B095966A00761BB2A81C5BB2B4ACF108AB6EDDEF0635E9E4730EC66B6873DE4D449D4A25DF3D027DC2423A11C3FDCF474F9792B0D1376D2B2C49075D6BFE2BC6343EB0E26BA35BCCF89CAED733D21B7384DD6E62FD505F4E6211A096DF05A9E8ABAD0C54A669DFDD687C502AACAC3CBE79648243273BA80438D9CD6686E4A3F5069FD46961BFFEA699EE0A4D65509E185FD5E5127BE0CA333863763F9A17831D92496F59DF5308B42325672149C398F0FD64E7AEA186302B1F91968A6A475E7211A65041F0116672E0FB7EC51548763B71D69CBCC2765A78A3A467FD6D777B5AE5808F8D6DDD65870930FF389304D7341D242827B43B1427AF010F149E6D28A0351202CB3B356A055DB327CF4680CA8214BD038A01B945DB98E463DEB27A4F36125C57F084BFF8A7570BC09603626B6399B2F61FF057FC5D8D522F156F0D4CC2A69102D886E1C906C9D9D72BB8C3FC00C3A91348762743B7342BAA03E32007A6F985D350012F9B894CFEF29A31ECCA4243E422D013AF1C26DC95E0243753EFE4178B4ADEF0132CE71A9D872C0193C761690D095DC81ACEF563AC81F22A4CEE4F71EE6917F3E880B9FF75157F135FC6751E7BBCA06CC5A4D8FDE70A2310B437A02F413F06936EB7376DDB29CF2B15110E80BC6F6EC940C97C12D3544AD308F3C5ED81276FF707BFADC7F672ABD6B20B82098CD720E253432126DB58B9FFAF90E13749ACBCF9E91A8D56DDE24EDF3B6AA79C5E248457F4AB76D037BA826531F01EBFA32D86E1242D3BAF5709B6C664CCC2F08AA2A6405E723470CA0BE9F9F22E14773D29D5C7605D8F7BF1AAE3F7CEDEB4E211054D2E36919DB2AB03AC15B455371A23FC732AB212032F8E1D87A6CA5CCDF3DB5CDE8B657B13AA1CDDEE9772C83EF1F8DDF8E88C254E7F5CA8921EE09A7FC2BCD638F5299D6D5A07F7AAAE1E250EC73EE7495C65A95F45FDA9C06BA0212E9CCC913BFC26C62823DD8FAAFCF1AA16A8F2347B036AB9BB05952F81916517DF199CCCCADD9144C7A045BC26FA26F824366F24A2611024A1E582DE9C6A381FD8D980576C8523E7D5AF52E13205A6D2E42977667775D6C1D5187654150178EE827E59E81061B90A423A00BE6351E9E6FE1BEB38C1F3DBA4304D3716EB43E2D993EAAB5415E1A0529F6B81D8DEB957F4015857F140A85A847EA9CEB537DC1E9449B285FD69702BDA26222480E6F8084803B5035983483B53A0F4B9A5BEDC4DE5292900CCA65A1A02B2502DC0D8544DF0B29D1532935F278432D2B9ED7FFAF6DD2E4AC9B42F77064C3E673D120AD5459F51E7C0110EFED58D736CD9A037FEAFB0C3006C970F693C90499E5E3895D60BC0921D6935C45301F7B97D08F77B9D4930E1FB2369ACF7238DC64220D1CE64AFBC3898D72372D069F210C14C0F22A445C6C9951B79C62643890EC5CF5987CF56061009B527CD380FAF6FBFD70D4EA708C6418B23F6A8CA1E4C7A22C6C73BEFCB96CE7A1E976C208F5DAE6651969619A3CCBB657BE5C23F71457D27C994E434FAF38E7D9814D8041954E4A878AEFBC23B7FBB6E989EE2293C660EB7DD7B4790C8612BF799876CC6E81C9459ED5E551E10B9B5A4C7D5A01152BFB1BD6C7785DD4951F96C2C73DD06AAA859B8C4F7B88000A615C68D31ED7BA85C418D88B0769E32716ECA901D8A36ABCD5A244FA9ADB87E78A353FEAD3CCCAFEA663503AAE023307F9075B1758515D4EB5C384EF1E34988D729E41A0FBB075800EC1699754EA17335506ADBFB7263DD3E38FD47D0A328059A075D9EA14B145341D6B83D85FDD74F6B5F781244AAA0C7F1F103171E89B440E0FDF2336997AFA6711F82B044261A757772E6CECFF0EFEBED6E83ECFD7E5A61B4AD91CCC506676FD423519B2078F0BA3836537D1C8290ECBC4EC416FB40E37AADC5B75D4D307945C64B6FD2FBFE39CD26C3C5D13FE7A7EAFCB25B51601CE823AF1130248663B5273A1B2EB06BC509092949D8D878F8DBF35FE805F421EFF78B1335971DB6B5FA43F7C94F5050E96CDB7488764E64CDA9EF5C7FCDC0722808F7329F7F855CBD3A8F26F8DC2F6153D6F5DA6DDE93192295BB0DB81B9636BA2B7C7A583BF056032133E1A4C1F1F3D502499BDF4CA6343AA2F06DFA39DB6226FED21F17C6D19976BCA10D96BA902625E03080CC8AEE1980DD1AB484D66F5FBD8BC6550B83457D75B3217E518BF5A2D607CAEF334545B4D69DA7791B95E2DE9AB163A5C825EEE411D4F5B5D2766CA4A3D509188546EF7696E9EEF751A6F6E598FA0E43D137A11E361AD4E2D13CBC92ADD5A15258D45DB11DD190826B932ADAFA4756AAA271F5757EF0811220DDF1BDC2E5C67AECD3B17CC1058CF0B4157F5B47EE34ADF8B021D75090CA5521436BDFA5194FC7D119C6F2108DF1F996AD45C4F856A1648E80439170183C5F43E6880CE2F7F7FB73E86FFCB441720C4115116A4515D1D4555861D6B8B698C208A45583414A1088FE41C6FA54FCB7945011D7B8659AE1BBB9080E1B84BE13E8E53704656AB576A0DA312360D2D2D87BF8B9E3F474CCD96BBB701F3045761C78DB0D795695935BBAD2D8DC62B4E8F5BECF809E091518192C76029FB7CE9E5B8DD2DDBD7C3856B3DE4402181D1139F083E377F728D654D710D914974F8706785AA399E780D9666595A6E9F23E79CA7C766540B28EA039FE788FC13F2865E911C62DC4D46BDECF0D9F04C863146141B3A6BE9BCEDC5C109F7F2C9BD4F2A095127132576C734CAD4C6FB9FDD8D734A5277065ABBE64B9DF07EB4BCA1ECED7C8D9D7B32348462DA0F9B55EDD57F69F82D8DBADD4DDAC8298AD653E30C3C33460BE09FD2574BBC3853F4049BA5C4CC6D4A290F444BCF7F9179F143E2B62CA39E8B0187BA25E143A3109B6EB3FBEE7267CD9CEE749DB03E38430B2AC6E29E9E55566CD4AEBE83089300EB8E36F40CD157CBA12154D95EB26108494B6F0A976F9BE224893D8C59C2DED39341B83DD6A78F709E7563C7D4C790D9F268AD85B8C3CDA6B978989DF9B9C6D7AE7A131F211DEE2B05C5A2272EAAF32DFB8D888E7B84C2AF6775B0229716C51A7E3092F19863EA2A50DB6B72DB08B556E97FBEE5614BFB823071D04A9CD8085200CA35D64D65E930EB811E3F8D01CF4E17CC7CC47EB15E095F662238B9F543BC5E979EDACAA1E1BA900DFC8287E62310E154F81715609ECBF8640A6D3B66DDB3730E83DE3193C54C700A7BF5D277348B3D3D9B3983C7791EAB98958EFA52AEEA6655B689044AFC5E5DE99EE6708398C54742037E48536B0E1637B1B2087379AD928F295B22F1D18A6FBDFD30ACC442F6FF65A068DBAB08297F2ACC04424E1376E9D0C278A43B7CF4FAD910CC2E48A26D6F69E8B09010D2DBDD45DAC88C2538811C594AFDF4C6EEF87AF334B959A82D1D7FE053E1AD9E5BF8925D637BE4B5DE6F187B49A76CC8E2E188F158DCC578F4F204767ECB7894E9F6E7E1D99C586B15F3DFA197E2F7ED84AC92FFDC7B507F779F8A433674F482FEBE088F5D23362E5AC08AF0A5DA9B721E722B33100806EF453E3B6FE1BC739EE626B47E2AD122A49D57DC24CBDABB3A739F39CAF6CDE6DC60305956B6E6077EC51AA3710BF729CCBB8788228409405AA7323E70D4158C0166FABC78B13F369B4D547D3D9F508530C78DC6ED880377A4D850E6B6ABA9C9F877457BC21267036748C4076B37FFDAF56C4DE05B887E296C2A1E3F11C59BBBFC0AE439FB2D1EED012D40FFE36BB40100BE422D9295DB1EB85C42FCA2A640A6E8FECBAB3DB65BE74DC181C6AD2F39F2E34747A659CFF62EB50DF9A119408E562D7E4B6AB39872DA357B2314D5E1D3E67A93E9846EFBA62E1A65440B216F7C44ABB93E8928012926AEE2A158E4DB2EDD2001E171512A353484A45729481A7FAF27C5EEC25F61D5292DBE8498280A82F70D7302A6DD9CF6F9625C6594EA3491D4C2267547E5CB5BE26ABAAF50E146D5BC50CE30A2291403E9B84D42A6296356A3025877683009F0DFD76F90EC7221247D3F95FF8F6ECBAEFCDED45493E74781F164E2FBA5897D5BFADACE92BC3E26320F2055415F45CFC5D22DAFA42BCD9E101EAE33A315E302CA3739EF4E2B0D9CACDEA941FC433D64D1704DFE93D089F2265F024315E9C7D59A4CAFB061299858F50F4ABA592DE8E99798534612E8DCC2782287C58BCF6C01240F4DB84E4EA5241CBC141E1F3705E7283587036FB6FAF407873A4EA0610553E23DD509E73D1C11C81B11F8B582E99428851FDF4868929969D499ABF1407515CBC2B929B342123D78239BE16B7FA88369A466A4DEDD3AF12B38E538D05B49C67FB0171AFBD120F1227D4EAF4EC122A8E2DE8DEE5CECFA3B6C1482AD5F0A9A1112D60143B4CA5A9EEFC8408070D39BAB801FBAB9E300ABC42FC1B97BF5BF6324915B813E730FC9C38684DE960E8E1C42306A5C7C0E3451729EF0BB67E378269E87EAC13E516C7B7934855BB4A5A6DE8E684E1EDFC5673874BB8CED951D2BEBE73E11C678648A9F328DBED757F3C4D58951045B7473BD4051963CFB7A46C9CD8FD0CB6DFCD13613D702928F3B4362A8AD43DB5C65AE03ABB297E611641CF8CBADF854B616E681ADB44D6F51268AA7B74D495A0FC2CE0020DF358B35C50FB280CB3589CCE9BE91CAD66BA631251869AA0291F059A1800599EDAF0C7F17E0EF4B9E5EBFCE91722AD8639B87710EF573A461E920D1FDBA97DAB8A0ED396D204500E00A031120E832D7B119F9F002B598E12DEA051E16BA6B879CE4122730CFCBA4CF804D818E043A6C8D6C7AEE116CA39F5CF832DC292F4997E15EE377C47B0FE38307B208C2C02184FCC435A38C92BACE16D2418FD55158C38FBD04041B9BCFD9D255DE32CB431A92A9A2481E1E21B4E943D63FC15F3B14C773471DDBA25C28CCDF930E5EED16AECC4AF70130741B10F6AC3CE4569D00190F59ADA1B35C4ABF28C7891219C2206702DC8E3D0E5EBBDB4272290AB08AA4E785A83CB939FA25942D8C9FD4A796E5EB4038F195C81DBE4E0DA9CDF58CE2A668B0A0156800C5716F7032A3E1B20C0CD1820EA6B6C2234577BF19DDDC52F7F15E6BF619F13B6E230D2FF6CB000E179402AF92F81E9859DED88B4D128F91B16B59B51DAB7458B312355FF89500C449A90CAE050568EDB5B4399647F6E1C231D11E2157ACB2D2D7A711EF4AA4DC58B72D88DB2D08546276F9C379125B0E3D12B0FA70CFC469AA2BE1147E0A895F07D65F08D6BF1C8CA29B9380FC136A084553B637133DADEB675B60ABFCACF1A721599C19BC5B54E19058BC5004CE7F2EC0F603EA327EBE8C6DC731C77F7FF123555E7690CDDEEEBA2EB3ABDFB0D4F17615840B4D4B3DCDF475D3B103AD3441FCF8DD199AACDE0773594844C997B76947154F839A2874BBBB6FC4C0B7BC2975F78A65F3CA071140D330F785E3551ED99FD9F62B2CAF047885DDC237ABB99DBBDF4DAC098067C85D4E41214B28252E6BD4FA331A77E116BBFE7B7B022335CE56AD6B908C37CDE407751FC7CA044872FBEEDD4DC792AA52D99D567835B8DC1F8664D88A87F83B4A81CD38043A87C006089E6B0FE5DB964C9F1ED24BB42A9FB9BDEB8AAB901953D1AB095537A850CDDBF0ACDECF30BEE2DDE290030848C16227F9A358DC710428865D4AD659239EDEE56740ABDFFB9FE02406DEB6D64152FF2BE1943C9C6217D9308FE768E20CC7FA0D3F818F2387449FEBB8F4788A4648B63BB65BD77780A542D53F0ED8B668963BADD90E7540CD351E9A34BA5C795292DE2C25E7653767E70596C7D99EEF7B223438512BE43EC91CA1F3EDF321BD499F30F6D4B79A66AF8634CCF72A58397C1C5A03DAFD9851A2D716474B06CEC9BA35FC4F8EC688CF6B0CDE85B6CE6ECD2089167669E9D8C2C13C7DBEB17834D0368E3C06BCDAA1F0F739891721F338DE3F087F491712A6872E3397A0E74C778868E3FA3A4614692B0C0E79F0087942BDC3B3BCAE38BAC82C5A640D14BEFF8F0954417ACEA114AEC7FC6C13C1C92548C2989C0FCA4482EB14F8DBA2E529CB425EAC59ECD4025CB633C824C167E1755966DC56D27752F259B0C5F38A2826B2C3A3B99DCDAB688735108B310D024DB2CAF7AE993983BDF9F32101F568224149F842CF60123D66A318DB281B2D5FCE955C0F69F51CF19C9F07E996E4D8899C7BAD12C712F88B955F5BCB6A8A8B2316416BDD4A235D8E2FA31065B15A8B238FCE1CC6F9F108DA9474E349892B1A80CB48BDD7459FE942680454A8F84FE99C2436CD1DAE505094EF1C9D054B7F8959C2E80C6794BEDE58F4FD6A807B2B79F56BE9E429E97E4720484CAC064D9619950DA77871FAB4E392EB58507C6943D6D85ADD3A03C6AF58EB1C401D65AFCC514D992B89910000FA2ECF8EE9AC5EE7D625547C6441126B3E568A612807A635C18E47C0634697233FE1B23ACC4C7151755AC308E72D4FDB1C9293CDB875DF3C98B4E3B102E5DED1D0DA3041C55CF190B538A63529AEE999A4E5D746F7210C3BAF061763CA52D78922C9B36DBC22C84EED49D0D5BE942779E7B34722E1625A7639355442FB1BB251B94672C9264E13668946C01AA95DF8D1E63CB6D9D7EBC18D94BA1284AB8C37D85334F359FA02C558777CC50769F04E979FF7DAA20E4AC64764AADB97DE8A599559E0E5D526817EF4909313E79FBCF05649F364934FD958BC4F7D11726C61F5B74F92CBA6F4AC7F2E32495EF017F2336C001EEABCD11ED24115968E73A7FFB3D6B69C11C16C0434C3EC5B425F5C3BB30BC689E6EFD95349AF6AE0980ADAE4DB46E2BE4CBF3CE42DD1A06AEB096B470240B4103230CDAF9E5F1CB0347355AE8A040B1111D9A27BD4647B894550EB727132E298B12554B314D679365BAA867CC8D048663B650CB0EA8AC4211B488A1EF45076399BFCC6AEBECF4549D1F2C86FCE6A97AE8C48969165DE3718D164C62CA4FF24501F1BBA1655B93BA47D325A6ECFF527AFA4C559FAAE9F9398749E3CA3067637FFA59AAC51B32B0A29ACBC0DB912136CE10581C52B6DECD98C6D1171976DD8379EC4BFAE1B6475AED2AAEAB8A8838141CB79509268FCA4AF2B7AE8EF235840FAB8F7A7C615A451264D399BD5B05E69B9967FB180C69DAFDF590A2C0115160B5E4946ACDF0FE1CA0F5B5F4F645A149149BEEE704197D32AF00CC6DE723FEF85890F6C857E9DDB5599E0CAAED63BAFDC7BF11C79FE5ECAAA2B56959BBE9768D58537C13E955C79CFED80A806ADFD3510E83809BEA2252EB36AE4260796D0F1CC4AE5DC5EA659883142A8621D59C689FE004A68D60FC45EFF48E61F21D03CC15F8A3C9A100950781D93A28E001E41486476A3726655993D3AE2986D83FE3BE17B97FA0F6981CF90774F1161450C06FB5FDE79B058E75123A215FD4D47293D1A701BF51E086B24CE0C44B1EEFDAEF48EF7F4FE4CC89B5804147115FD40969E618DD4C6FA0C5B139232018C5C50267F653D33C4D4302F8312C80397615A8461419E7DE98EDAEDE7EA3D94232B55BACB5092110FCFF80DB143EF9F02865917DC0D6EBDD72BC975913C86C5ADFA85FC9B358E3B249A645AD013BDBB2A83D71791F85371A214BEBA9D68934CCCD3105FBF7F4E2BD9CFB863583069D037D3B6C0FC2BF48D8AA10D47935AE665231723A90909C9F08F42225F2CE26998233431E7DBB1BBDA7BA20E282BDA160AA1D2ED48443A086E5F05328A60513597615D23223BDC74396CFECE66D04F5E4B3A1BBE8492F4753AB2A906AD2D5D05A82F63AB4493B406B5163AC0B1BAA19CE1E565132A485EEAA5332769FFB7483A53AD108355E0327BD7E5F3DD1DFF0E7953262E4CB91B51F3C25B0F058B128E211C1E2E932DE6414C3DA1902CF98B30049CF84B3C9FAF026257349D10EFDA208F0AF2F7D9494C0C55B30F868C282147B0C50DC04646C6F7EE35CBAC39FE87485469E13588967E66E564B01231002DCE0BAFE2DC52D0FBF27726591B3ABE8B99F59AE7498352A7028D5930CF2284BD11797B3E1091C36A690EA6AB2FB6D415C814EDDC86AF5CEB83E78E37ABDEDA6AE61443CAD69A9487C43613F5B3D1C725CEBE38F9A153EC0B8AC06903CC459AD69CD21E28088D0D8E5983361E7B15204DF21F903C4C16A4603887AD4EF2415970BA60BB1EF8BDD8C3A704EF1637AE34C9475BA62BADA4A50F73C80EFF8723DCE05F829FEECD6642621F46C052870EF6F9B41C761A744817EAB8833EDDB48AC05A111500AE9382346740BA95774C55D239C9BA02D16DC0081E30D9139F7562A6E5CC10FC0E0082A67881460E2A9CAFA9460E6E610029446B8174E08F976A6E258BFB1EBE3D3DA477A8CAD5EB86DF8D4453B2ACD115D005AC35F2AB3D27D84F0B5CDF1D134D9E34F347D72D3836A8062BDD08AC329DF1A041C93B55D432B7DF316F1C87D305A50FDBDBE64D9AB4BD931AF51B250458BC8D59C959F3FED85BB32C1A0F2F1433E32798AA48071862E56EF1B003B35BCD91A01D96D842E472EE9E589ADFB43D31B2C2AB5804426A4CE136C6E2A987563DBEF3093BC65BB19B085E8C9532DB46505CC415C5878863C596B202426FB6B3C8520C3C097ED96F84265809725E1C011A31F67F7EFF8D86A12C55272ABD63D7CAFB5DBEEEB19422C202C1C978A6D7EEB06E979EB32854BFD8582170404D4A7B96C8912E2F176F9DBD6245A5760A11EB7C1B41D604BE646E252067F287A74B84F040C465F9F90ED692C17AD2B3879DB1A41ABE04437A691736A4A3E5BEDEFC947BFE1743C1207760805F743E073F61C002DE075BA983A98C8478413D4674AF88C1A8A90CEA7C38D9605DEE15B4E48983605C26AF5E6F74001A4AD0787FEFA5DCA1DF0DF353312B5E0D8CA7F7B9FE1F42BA442335599F9DE1B943EB8CA3154DC3D2DDC966910F7BEADCB66BBE12B9ECDB7D2EA86B8E359DF6E13E90C6B81D2A39B4D858BFDE3A506518651D4A2E3CCEADF52E367655331408159F8DCAAAB592632BEF05F43F0AE57D9DA020064057F56740C2F48DDB3E3F93172242891E7BDC205F5820BF8D0F69706C94DD7D7F03C56589133E59AF1FB09B160ED2F6E9EF52182AE49000201E8F63E81B712EBF1B0D67FA491E4D5F8FC5922A01B0454DE8E8DD732BE4ADFE29D36BE55808AF20EE14C5C36A347B0C4532BCC29A115187FAAD71F8C87C441576AC07A57AFF0C81A800B3125EAF7B33C8FA75FCEB152B589FA76FF6873800D99A6A88636F8015A42D4032CBE321D5885962D9EC9E30D30785E18F9D40A6E593CB15F0E4122D0AE7F4CEFD5737BFBAF72459ED9DE4E9E04E78AD9E932E041BB22305D19E3820A2D5C96ADE8B00E998C8669609982447CF5F23C3B81CCEAE89876E3379A3A7A87D097DA27B654A80926756A73088DC52716BCFAF4FA33486268CAD524EF1BDC225BB95C3EE4BCF05C2DF22DAC479F0F7FEE5DADFD7D00F7C06A8A4DEA6AE49386DF2B28AE5ED9186352639E439BDAB4FC5B0DAD4706FCF925DC42AA8D98617FE6B1DE4BDB8BE21F9E7E2DF6695542BC709171CCD8699D68DE73A05D8CBE35A8D968A647D8B468B45D54116E66664296684B9DAA87D982E4FB5FCFA5A5547752B26A7788BFFB721CA12F219243C03925213A0EF42C6FFFF2067891103EE56B45B183EA5C830E167F0C35CFF518E7993268DFFDA078008F80C3E1E4A01A59DF88C87837CB6A9B5324BCA973C79B432F78A04B9955519AE42E0A129CA6709ACCCDE6BF2DA8B016C4BADD1E64BCE783D94FBDEA5C6634B0F9F7D6271708325E8438CC1B8F6ED597727B3EA59CBD2933C4340E601217BD1B7206C9E524E24D4EC6F4C9A97B8B5945C975BC09FD21F4C68E84532E4B13E2A0B4C018BE4A1A4A15F99DB5314D7EF1925CE85BC0BDC8F2768019DBD87A6C240C35F9195516F219CC609D479DE5243BA10127B03F00EE993567A954DB41CE3BA28FEAE2077F7BBEEFAFC0A836B630A7DF80CD900228C027565AE960C13C3FCF4C32B53CD0E760DF1A8AD5BAAB66DF76F32BBE0A2720C37697920ADB8A14320C17C9F10336CC8AFF68655BDD933F29DB96FCDD7CF4A6908A967C4FCF6C721F85E998C5F31A4AE581744725D15D6D6690F819F8EB1B90DE0953F20CE4FC497E64D879A79E883AA6CC7821990FA159209FD80FD61B6C892F0F4AEA0C6A0ED6BCC5F37183FA119EC45266ED68D923CDB5DD80132C4310AA3F4290FE0F5334C079DE7E3DCABBAE8BBD6150C339864C3425522344CD82AAF8B8B9260BBE3DE5A5675FBE36FC2FE8A8A7CBC8E3E1F1335E33D581BC58AFB3B3B4F84E8CBD3EED40BB4EDF10C509E065D723BC45C8A524AE66C06FBEFD4149BFD3F3C6D27F86EC3AFFB4A46CA080821EBC66CE9E428CB63154F30F8877CEF8FA995D6F3915C8498674E81026F64EDC299EDDCFCC0F95458860AB0DB4AEB790715AD22719C1563CAD6A8AC90A6564A4D7D4898A59A417E3D1B411CC602BA8AFFFF189167E31A2E8630E5D768660302358D80001A0D76FF3B2955ED5E6717DCC16F154F6BC9F9314D910FACF78FE583B57A22FB533C83235BBA73C777A9ADBCAAD3F42DAE84F083204956E34B676FD68FF8893EAF85BAE1A0A87ADB4CF07F3AA2AF48476A2D36E3DC8E034D5FA1462E7A773720EFEB8E34DB6C814AE4DE513BA3BEDA35DC2244705037180D618549312101EA51A54A152C594AD866EA74089F3B88CF1ADB1676070AE1820EA0C56070216F42B9CDD92228F69ADCB42FAAE3693EBBAAF67C4FCDBFB57E04CC16471C2FBEAC4BB355C588112C5C72A7FD016A61ABA124245C4EF0611E848497FEE0E5B0D37265943356F13AC4B98404B4D237D26CAE4C36A629CEB7ED088338D9D2B1315937E0B646D7E7576E8001ACBF005E2C48540CD159F0A2E9DA10D235956C7F6F386A4D17CADB41A818FD3787321CAD8AA86BFDEB9722028EEBF6129EA44BF5B088428B8FAD2302039090EFA919B411C85902682D18611A351290D6D44713A668AC99A71B40B09A9E411564F35260C222B91010E16B4F296B6EFE8966C2A26F901C1590DA8D9B1E405AC3C0E802AF555AE8A1C7A0AAEF38D1023A3EFBA3F56446DABFE1E9D7B9CF905CE1E41CA86617A1ED2E7FBD934FCC52C9FE4F765F84CA5BA0F8D39C56118859831DC6C6C6F822B17B0D8D227E390B69F49BBF4F3A1062A6CBE1D4B58AA12A0C4B93AE9DB2AA0BC5F39C13855C1318487B116C40F99CD51328F3370EF3A4305509233AE305D7D1D2A482B87A7866AE222C9A8152B037E754323A207AC08DC3FBB7EA4B83D1C6254465EBB16BCEEE44FEBBFE8D6EA736DA5ACB069694FAF01B517FEB6F4B9488D3730E07BF8362B9055535824BD3059FE9D49C1995FCA4CFE4D75EF81F9B813C988F764B6EB03DDE78109BC732EDB8AB98883B16EAD06FD84F50EFE251E6DA45F5123406BEE9BD52DBF73EC3F932D120A1FB7A76ABA609CB40918D2F94364926B071AD0742F598CD38443486FD0426BB5BC869BBEBD232EAFB4F07A2F83663652D44E426438EC63455583E5F50558B4D8082BAED59AF2A7903BF614630A39A106D50A708856E87579793A611F9D129FA41CC2BBD38DC7365F44AB276843DE2F1FF88A3C1969EF1154FB03170CF6DDC65C3E999828FE94FF738BD002D05963AEAAB2B3C66C306DD27E558D67F831BD0EB6670AD51CA57562688EF0F38D4FAC0FE4E7218BAB4FEA1BACBAD9912FFB48D7E962F1378B0FEB19E431A0E82A22DD1A396E97D78A94537EABDB7B35FB364AC8B0613C20ABB4BAF7ACA006337A4551A066EDBFA2600BEAB350107AB2EA00D49C6AD459DADD1DAD67F611E442BE8A9826B90CB50D6A14E45E49BFBFC05CB1B8CB5006992C9FCEE5E46E9F7ADFD446E3F673D1E335C3209A1BE0364D3F18E5D4C6EA95F103585EDC74BF9DA3BB87AB5BB7BE0A7E5B7074C633FD33F2907C6E762755AC36F413075C505912DBBD2FE4A2E63C2EB848A173A0D32CFC8690A0C84FF45247DD0098BD57027119975B6BA41F0AFB8DDD4975FE4A0EDCFB62876883B29A0DD978133E38E8A51B8D9605955CA3BA553F123A202EEAD809EC44FA5C0B415A1E073B6E2584B91E4EAE6AEB3B255DB0FADCBA87FF12866DA17E1EE37DE4323A13223408C8052F3823BFEA983F0200FEE8DDCE65B93E3F4424842ABEE42A9CF30558EBEB31859E907A215748C3C77BAC991A11D64BB993ECFCEDD82C5204CC014AF342275E99CF82B20A8CD1C40966CE8654396E924BF5ED5E9EE6A10287D959AE73A02749AC3655770D6C1CBF0A5FFA85E423D2FAA6FEA41B45695A696513731198F0F5B7451285366844302AEE30568E8CADA878319C961DA5FD926F609C679E8E76DA060A282F812A9DFDA4DE42AFAA65CCB6C5887C08D92EDFA5E5729D95987124D7713CBC02510FD388F853DA2ADDE3FF1BA5A9959FA21FD4F59D4FE4E6F98FA0A7C877BEA3FA2E3DFD71E18DB6037318A2700A7E636158234CB144BA6FD7168B24071FA5483A0D14E209244A59AB6B8C52B4FCF430AC339D7852C8E2DD91329ADBBC2CB44F450E54F65C0079079BD71FB6EB59E543B3AED230B314873620F8BAC909D41873CF99E2A8649D53CDCC1DE15FE108EFE94201153994A07F9F7A3B10BF62F9E02CCFB734A774E2C8FD46E335E2253D3F283611543C534F4BA0976C566D1CC738C568B2159FD7A74D7D87AC2706AEB5B097FD7FF11FD01E29761971C6282E85D8864140A9CC7B144B8A64F5C3FD33ACBB4B66F67D49C5F707DFE3CADC1368DA92B7EBDA435EAF877F03A094F0397CC54A73C9D5979F45F0CACEA3D0CEA24F8E86642F4271C8CD3FA993417080BAB03D913E4FF7C7210B44B02EA4EB8D262A567D714D3C0E50F4AE4D7A0D111B568E81EC476015F2850C1B5503D61D5602EFC4E8BCC71D8A122CC1A7C4033CE25A5D28BB887D571A247B98926A78854178FE513594D8F412F2C13FAE437EB21469AD20364D178BDE3325DF424AF135B59FED9C63C845F0FA146F0B490E4A52CAF65FA49D201A9F783FD93042E921A1B584F5D41E5DD99A443237AE0D245A0B107F8D1286AFAC87225A40DAA260AF067C13D921620F8F2429A72C8BA7D0D3C02BC7D03587FE9EA8A74E901164EA631190726549B4F46249F250E6C48E645773DD94ED1DCD12E3F0124B8E5950891893EF2A0099F62CFABB20D6A6D8F322C960F92933598A8E30AC0E79EA43711FC3A770DAC21ED32DB3ADAC6FE3F055B0EE20B8C08B779DA056738ED2C1D867E3D5A5A8331BD4C751574D75A7F1064ACCD950D4C74A68A271A0F8878B5507EB0C477AE9110AB61DF4D27324663041DF44B85801E52580A5F4AEEF55DCEA366A299B5DDE0B307A108885183F84C729B97C7BCD764B7D15EDAA736266894336F6460CD3CD33EE58266C0673554126E88A783B11977E5906BCE30F27F2BDE228035894D8210B6E1466A6673FE8F5C9553C923958373D84926E97107B43926412695581DBD2073DFFB143ED6A03786BDB8EEF29DD14C6B98EBFCB7BBD8B74FE6E85E7807567B3B11105BF84140370789946610ED24676B79D74A19372F94CF1B69C4C793CBAC5137C7230A41E2B183AA7954A747BDECC7DE0D453D8FD383B17C529D65ABF03B1B72A7F6F47F46AF94CD1A668AF361A0C3314C36037368749977F523A667B652ADFEA77D2DC89DCB6920277F5E6AD0DB107AF69ED7AD956419BA7D5366EC4405B658E3ACE0CBB74C8DC0CF7570A77B634EEC17F1FA1823740BF234BE46406463A1296886610152E73D3C48E7EA15E65D8E0FCA6598B8667B4D49877FF8C43EF69DF944F4B50406259F84F76361DBE4E2CF0C249FEBDD0B2C8E0321917448A3597FC5849ED6111BB877863491F6CBFF955D72ACE8E26B90204D5B7D49F509D09BA5380750ACB06E99C3C681801F641BA7F9FD185DE9166B15202A03AA98B5F25B1B55E3E043CDF620BF8E78C49DBB6D9CC87013F1BE73F660B89835E07454C2509074297018DD4A3593536EA602A428D443BB2FB2FDD20BB021940FFB12BF6E45AB8D6D6837B6945C98A9DD6BFFA1A33307FA8E7BEB59868E96D9F2FE3A2271D597165DB20C116F5D9D2839BE394E525D2458CECC8424CC68F8B14008E4547413A1A317F48411CE1D126C3B67F9AAF84A618E62F57E6A15E41B3084FF8E43E1E0EF608913CF7BED24D3CEDE5F2B680E2546BCB3CE516E8E9C777188C4A3A5B472BB58A769557095C1CCF7390DF55F4A5DC4429B3F7BD0A0DD9E2E63EDF761AB59A7CA566259FD3243AC7FCA788D958AF9C49ADF27DC855422B34750C706F4880DC21CFF9B849C4ECA72613E6FE6FF1E77BE7C1DFDDAF9B500BEDB53445A9AE5D95EC06F0540DF351A2DD6BCE3499C99193D1AAF51F6EE9AB77123755D466BC5882DF9D3CBE6E899C91F7ACAAAA55779250E6E223BE987A1572CE8EB472CADB0FFC0B2D26575D530D602B826DCF6F4AF45CD8FED56650B95551A19C22AD0508ECD2295BE6937B6D84DC7CD9B2186786CBF05CC9E3974235C9DED280CD308B970BCE2C7A3B184CB271A83F706348DD83680F576D99B410CEC5AEA807A175905972A5E02EBA1B9DD1A2769BDB671088D619693FD304247A2A8C80FDE5F00EF68437A6A0221343FC3A4CA900A81DA92008805887A7807D0A74248261BCDDBCF69D5EE325D62CB494AB7588F37DFE1C59CE29EC82BC4283A7992D9E7B26F8C2F81D72DE0AB8ABA93BE2D4A2BBFA80D7CC72AB9C1534282745F021292DEEA6072A81148DAF0283CBC9E540863B9552A42F5B4245C3D38C2968166448603BD0529F19D0E7C3258EFFA33651FC670DE044A654FB0A4DD37890E5E6600B6D430F7A9F35B856F2B4B1976CA5C4D43DBE41D0398EF905BA803D1CEE1822DB3EEFA22222BA00D554D2454FD87317FF04344DB00A30192780869B3FF19EBBF68EF34F301AC078354426E1B9A36CBEC8E73CA0847039ED6010C2BE5017FC9421CD401660B2A6C0005C233C319CEBFD6CAB5880BE7686A9ADDDA225A5590B1394C0545E41788B9979B6B96267EE20B2AEEE3DB2BC9AC00DB8CD0D864A07E4CC117B393606C46C4C209C5D45CA4B799FB267C890854BFEEAAFD2160B1C1EDB4727BAF35B75D84F0F232C7348B6561A6BEA7847748EFDA5036C1E6B3E24598AEC839474C15BFD2715F20E9283E38F8668D1B202445BAB4C8D54561429F5BFD21ECAA6A2B5AAF4951DED331A5E5DD9F7D7D743C06D4867A88D562B9CF90E906A4C218D92B4197A63478155C66CA05B2943B8D2D8894FA9194338E1B7BAE72A6284169FC1F5410B7E26BE1B8880FDC59C19CC4270EF475DCFE4F2A73794522DFDE70887D75B1F9864071042C98BB310BD3BA4225B469F93EA118210FF3D423D684413D247BF617BE0B0E92FFE2FBA38C9E2DF36859A109BBE85AC5AB863166487BB8E6C50B030E33D200A8BF20BF085581FEDB5B8543348C5E5AE52794F98723F1DE7635175285F0500206595920EDBA3850DA137E30B172439E301B30B977B9A07A4F189CB9D4C5D31EAF5669363144F83CD9C002D4F7E2F6793B451F58C0465FC9A3E7821CA7EB141729F6B36AFE77962DE9CE2EDD271041AE99543BB4B5FE116FB2DAAB60C3C5294098310BC947252788106F23B68EE2C25B0004682543D664B22D1E765C35D9E134667C0B7E287E8B8FEE0A2B29DF64601AE35A2BAF5D70A7037BC4868F18D9C1F3B4286CDE5E7176BF1A4AB7908AAD2FC8F5303206A015A36868DC0907092EA06B5617261761BE75C8453FED13CC49A924A902C84AB2AD76D4223F01D071AD0CFAA0A135D20900B4500302385407D6020843B6F3CD816D0333EA6C2622A332E69FBE3B62ADADDBCDFE84C9A0A6C9BDD419CEC4E4DC31523D09754CA73512569D08B2BB170386D7C63E6FA3D1E5499C80F4DC28BB74B686D17932874874ED2F71698637641D5843774508D7801DAD38F776B1F0F10EFC4F591A2BA27636426FFD73E97B66460130241E3D1482D240D2A95F54301A43BF2645DDB64649BD8BDC6C3C5BC51DC50DB60FAEF7A77992380288C138E448B109A8B52F027A5220434D0D20750C7CE00C382B1A96534751CA4EA5A48DCBF79BFB1E66A194EB1D8D5DF8AB485623B47CC0E385F1DD419FA5E46F4764A5BEDF7D448BA1CB5CC3E670A539A9F4F81974E9256A818945657A709A6D394E2C499F410B5B754E0B1841EFC282AE3348601757920C1D6479BF2755FD2AE071ED5D052601A907D902A6A188CB3226D78D7B84DC11671CD600E0A2643C86241B76B9F5CB5063A59DE9F02D36F33B482ED3696B2C85817943ADA11F1E2CE598A9B69F5A3C02B9297DA70720A293004866170917F9E7185C4A9A115901A52A93F6E6B7EB379EB1021A05E776AD5D7A9AEA8E6C1D961EEC1EF419A4EB50C96652CD26F8870A2FB690EF022B8EADFFB3D8280995EB64B235D2A398E868560FB11B5F8CC6299F017B1B9E1B022E1E3FC009503A3EF38293D752EFCFC5E274F31E3E04857D85BFB6416EF4A6EBE1016E483BB0A558D4AD23F8BC6794C47AE5DEE89D2163F87571589C35A9A45C6EC34E512C118F05CF7455C9F6AAB10E639A1D8155E49C74F1F5F78356337570F53333C41E26AD166B36CA84B9B9148B644ADE0EF0994D0D3B2C79E20E71D70C7B354245BAAB85F7D6036B5BFFFA35DF3672B0C76D05DBAA1A5E7DDEE94613F41302E63A8566FFA9EB798969F6852F0EFA95323B96C44A485ED0F895D00D20518A7427D53FC7C70088BBCAB3AC98D33455CAE6871296CF4D74F6CC47E7F945DA28F10A43AE1FD5235786871D77E0F96E26978CFE5D6DB5727407CB71FA9EC9732E2CE625E7F87B5D7C1DA41DD9EBB8B585924815CAAB90EC840B932E296053465AB8CA162C3C3864951770C26CB3C409FC3493C9A52F4CC33259CC70A3701CD7A3757BEA0F23AF3AFEC9A4BCC6BEE29A093F045341EBFD72E76DB780AB9D1F5491AA483A0473E5D967C86CAF2EA3618FE24514950EC11E1BD2DEA2C9E8100726E808BA35805F5926E54EB553973885E52349B3D3FFC0FA3C2134CF292515CD9157919D565B5C68B4A49D364119E082D31B4FBF15C80D28ACA22DFF29416D111929E726CFB3D2BD3646D94270F60D9495E00552BB997C17E58EBBFC1F5B57FA308D1B7859AD9261CB319A54828E29EA8557CB3A8A619ECCEA0B46C798F7C6E3B28338BB894E6ED7120BBD9DE48C4CCAB0D69C0F89018FF80B6B3C028C939D7255D8581C6FEEB04CA3526FFBFA09BAFD26B70A83C58DF674399205182D0484E266B9FCDD5C33672A7059CF32018E7EBB9000198D7E806E38161BBBFDC98F1C8BE64484B3FB9F14B398514ED6EFB491982FDF972518689587224C82C2BED210C88D3B6EE3C629BBA938EC083D1985798461ABD0982D0578CD03E8F2ECFC80448EA7BF28EE688979E972E6F2DFD36A89372FFA777933E48312949E1BAB8560EDCA99CBCF6493AD0782CE8BC16BF6E56D301822AC3B01777F1CF4673480AC6071FA18D0CB2F67E56D21D54E57AF22B7C45376EFF1E5F0E913D0B9E95186389AD79486C939B7D30EBEC9369834F26E56C712F01FC2930FFD288F4A1E7EC7E280A971BADB27BF77BAFCFC222C8BEC8AEA50A5E4E2FD0F094C106574821FEF0D0C58F020FAE90B3A493E35DE39EE919AA1DD8F0DAD920989408AAD667856862076E58A700FF5FF48A28FF9C1B26F50AAC13475A1795119743F3E9FC926B6BF19515D946DCAB103BA1481EE8B9D1ACF9A9235E5CEA07D471FD12D0C23F15A5673CECA49E2653F2E984AF0E24D988BB5D13BA6E0BF91A8DE7C22550391B8566F24D134D5D736A9567487FB674599EEB7027E02B1C8333A3A242F2FD5DC788013E5ABEF0BEB2304E8F67473CDECE6A90C1C41EB4A14FAF8EC7E242C9DB4E9E367B16DD531294671C94F52441F2CE7B396B653E783224D056EF4BF98012F964395E903CE2642E388EB20606D00530291EF1DA1FBDF96F72641C69056F85EEB600C38140D17046E993C822CB606ECE2B1F5961C844B23B6BA2FFC8E2964EF439A65F041EA1E78C26962ED8157F8AFFB7C66BCE1AA81EA2B0CC26E6EC7D0B6F08BA36ADDD9F4E8FA5CCC6233D6F1B6C1773FE98E630623A7DABD79ECEF5392FE892B97760378999C31E194DAC3C57D8786A51B57DE29432CA58C8752DF6351A7EB5853B5EDAB9F76D1E3EC118F79BA504EE8503C8399BE5D4613A615DFAA71C495C5006D9F3FD521183404E9D8D60D5680664A8A6309AA0927F8C82400F47413ACCF34DEACE2566CE8CA482C975BFA5900B437C4481AADBB36E3B933C63EF1A56E381C3751114867D9E6116BF22122522DFF2AACEFD0CCBAC99021D2D71B8E37350C0DFEB6405EACB31F9182591EE6E0E3DC2EC311EC7FB8EEA4B05CAE1CC6D20203D81C56C9DEF94780881BAB8E30FC9B6ED9E7D95E3A928331342E206FF31F14286F5FA3B5AC5D43306F939AAD1F15DAD8E090686770263408F9588EEAB771D4A2DD937B931D60E9E4BF3F4F1D0D37E3259102BC410D63A0A0DD65B25861F408DC8F9D4CC908B40A5108ECACA314B45B6F7EED069051B3F7D001D52927273B90054D042E783B10F7AA7028EF2985C881C2C06AEDD160FF55D11F392E05734BD9BB58343926BFA1435AF9E2889889A1891A134B1561F9A85750819BB9CA5E48EA9BD31716A60EFE21E3A6B46E3BED5D778227A114FC4331D3DCDDC43BDDD20DC572D785E59CF545747D21800DF34B6DC3051921CDAE7BEA0B7CE2FD6BC4CBF37DE1D8C7887D6CD35F5D54E7415AEB228BD0C2A6B0CE053CA37DDB2C60ACE739C3D44602C6A0AA463DDFE88890F15FB3D973EB3433E74AEA86632DC644F53E5D832BAB13D66C8BDBDAA4C2E88A667412CCF592A96C94107BFEA2555FBADCEE64D03B0248B51054E30F71794CAEBA18D052EDC8BCA2F9A5BF929ABE8CE00075A4235E591650F7E343B40EC72C7204AD8AF5E8FFAD9C379B2ABD48CCEC7D953339B49FF5269361A94794A0229E6A91D2B68865B90540897E8A129E42D030456A1107665092BEFC9CCE3A6DFC8C27FB9B6BAF5C8ECA377C602C4FE79C898BD7E7E57BB96F3A84DBAFB682B5B5D99CBDF13192D0849E444E9202E662A63EA8997A59A33C0B5A789870EE64C07CEB39FB3307572331F0F0C656D1D05478D937C41E9C8D5F5A2627450B5F5F68070D3D68A5C8FB033B1899C4360D13E8CB06844E85CA94A4C5A7280E07F010C8745248A53D32E110D19088BA3D6B05C0D35115307732C35D6718BC64E983E3CE2EB36FEA533867AD1B673598D2620186EB6ADC95958ABB2EC37CB056628E783FDB3696FE72E7382A4316D57E75DB3B9A864CA1351AFA32D2923D7876A4BA62194C03FDE52BEC69A6511A60093FDED403A23C00EF8004100B4A41C983FAE761C60A2E56CEBE8E822F0992CC5120F4D4105B9F80963CC58E3B53A308B66D0C6C32203EA4D1271D3DE78F6B33C6E0F0E1ED5CCE9681FA2DC048565B74AE707F69456B79DBEFF21FF4B0BE60AE72A34A44AD179691DBBC7E405A8736095D199CA263BB91253B33AA2832D7E3D1E3B3DBA54AE53BCB2996D13C0AC9BB1E8ECAAE4FC5D5302F53D42A299B7FDEC5EC34D8AFE4A6851E6A85AF4DBEAB0809553A5A31A7874A3C5E1CF3DC596D4C364303AC02819DD31E9DC7419D81EF677BAAB0A791FAD8550C738E929B17CB97A00A2BFE94F187C6D69E510AEE746624A984B286A263A11AB6B6A37D2B796EDEDFC6B8CC970966B66C64800A295FEAA5345D0E4EFE82CE50B80139FF5E51E9E6DDE7F2012A028EE5C02EB08D6F24EF6468BC59E1C26398B2F0FD18A84CC2B6CFDF9C6C36BA7893D3442E302314529A029ABD357B540B0CA33EAC19EA7BEFB8CC498EA4808695F1324A1C29E64F9EF87BCAA5DAFFCAAC6BAE496BBAACFE4204087D706956EE2E4FDF9C43B5A6DB1F6005C7AA39052C2CD0E143F0CE628C5FB2C180F1CA149F51AFDC63E4231DBC781FEC66E5575A6DD2CEADA06285AC6140642F3F5B666F490A6C8E799841B26DC4F479D712EC4E6B8A3C9786F196F03B5F5DC4D76B65CFF292EF1F634272FCF9BDA6C30A1865458EB79D2D4A8B48727B3D8358F338A0B04651F45E6174957AA595EFE1A1753E164395713EAE2499E52D1F706EA11785CD0429FB3BD6B438CB4263F87B601A548AEE0E5BF572C0FFA40F52F09013A0715D3EEC0F99FA72F5B6C99D0D70BCB0F43ABE3D42C97AC6C9040563E3C77ED1A5186B51DF1FC31EDA51242EC71F993CD3864062A2230AA05D91E726A8BA9AEB43E823C00982262F2769CEA9130E85F277D6218027C90E1627939FFD08305121CA3DB66507F5EF93802A3C1A501B0851CCADBEABE773201D31B8D15B70FE936179D750B232E4B762DE72051F1F5A58D593B0B314456342EE1E6CCB89E68EF240F2AC47F8AF27B85448443037181EA8FF92C18869FDDEBA3B778E1413AF5E68E3BF80DBDC51B0B0110430087B9E64A7EEFA79D0EDFB00FF97DC0C7A572E4E17988D3ED0D44F90B33AE5B5E0D4603AB05056CE9729DA007913A1022739CFB3BE3589CD4B29ABC54E97B8FF40D3E87E24F3017394BBC42E68B64747994F1D8B3A76EFFEC6AE1694DA52FC74260E52AAFF579A1000E3B591E7DEBB979F6E78F2A460653809106FA94EEDDB56CEBAE6B70BE72508191209D87E776496F92DA3339751FB45F7EFF59448181358FAF8588CAE536F1FD3FACB97504EEC77394D748C0182EDB298F4E590A75D20C12AA603D28880A5DEBB02BAF3E2EA8DE7658A2E28FB4DA4993A52E88839A3BD0C320B2965340FB23F8767971091CE8FC3ACB7992800749D5C4C7F43111EAA752C635B66AAAA170A6ECE415357E7C20F9AA6A650215106ED8B6743AABE9FC60BACD4FBC4FA6E9A67CE1BA9AB863CA325669EF46DDE3AF7F4D4D31740E087FA0425592ADEBFEEAD1EE4A72E69DF80AEF683BA7635E2DF6DE050437CFB2A8B27B9A1B252355D614CD0378B41E95D0323A8A4042C0B23FD2C7743BBC6FC53F3E72B6566CE615466C14B14A2B209F7363327C735E8306019B482859A240E4D8AB63660179D51B8C025A38FAC684A1143C13C294EAD49CAA93AD60F2CBE539C70F26060D726900D09BF42F0E6DB13303423DA1736E072E02F83C2D38F02F39ED3BF7EDBCAD70FABDE83FFC48D9B5799D6C0C800CB10A39BC0D27855B4042F1B68101C335F14924AA5A965CFE97B674DFC3BEBB39F70030F7FBA6B537ECAB136D07F77F703D1463669184D953A0423FC51A0B38659D0FAB558B8A1E3BEDC32EFE5852155E2FC227C12B458D38695E43978F6AFFF8FB93700B3C116FFCC4258AAAC86FA56ECA010B3B5DEB32797D4BC8589B3893F96175EFBCE7D78E5CCA8E13FB8034392AADE87603990095506612B4657341AE50F82C8FEA6AF2904DD72609785A1A44B01C17FA959D2DADED39D6B0F055123DB7F660E9D51C73F3A7B6B456A5F12B16AA084632CD40DE50D4D2AE82D1CED0607793BF4A962C623D97F1122D95C65418F0A9314D552690D59DF6B669AF27D0789C88D2DF3029E82E40DC840524CDE85424756A3D94F582E4B4A787C159A0C41DAA9278615F41ECE913E248CCBA4CCCCF43417DC09F8F86AB32D980E9683AE7729848E14DF5B90B39DA6E4BF6FA41D9F6A902440235D7381358ABA24740106F96874FABFBF6006897CC7C33E28C8792A267AF55E21ADBC4F111AF6E89162A683EC30AE1ADB08CA7B0A06D852673131882094454F7034BED4873383780DD78A0115CA1BD39F1A65514E5E7B1D29C1C2BD6BF50F0001372471D4D755350B57F0D9C48F0A679E78EAB9420F5C222911F16319621B8FA71E8CB082C4BCCAAF31AA3F032E32D8A1CE4B524CDBF920FEC54792AA35C9F1700F0D6DA6EBBC06F6657399AE80104A2338A9FB052385B322EC6F8A99043F27B3F20D00C53E3EE33BEE07705DAEE9A09A692874A52EC91A68B5C090233D4F7C5669ED00137A128D20B8417747174E73076A74B5DDB59B4B5B9700C48974DAD696D6ABD78DE94263A5BF913460DBBC138BCE6F7E28CDE4473CB26DB8D59C6E0F4E9274BABE0C7B5A5488A1C0916841DC26A5129712CA8D159AF567596CEF8704511465A831BA8F2BC75D007DB0A6DF3A675745373A2911325057B4F5F5B8D78365486CA65E40BEC8C72805C99AF4856648C0BB09E42C79557CD946948AE7AE6867F1ABD606A6A57610684F3EDF7109BAC8B0B7369F7BB8250F3F90E509F3275C9E1377105AE54BD0D1B14898C73FBB6C80C52A92B3FCCAF0E46AA684CB4997F873B03AA4047F92DEAD9EA3DE24621D32BFD59C4F7D443BDBBFC6CA4FF0B167DCFB8969B582978437053FB1D29BD45821109BEA28F54D880A8EAA78D93A4A4DF3FA7CDB0BCA64F79EBA01BFD8FE9B076D5168F1A79110D8D0B9C67EB4B87275C56F1ED32832863FA36AD717DBC5F32E266CDE2A310ABCA520A82113FC455625CB579F549123AA42F1201CDF027329452A3244845452CCF9D1094FDA515FA7401A25B1652A62BA33E031FE07E93AEF56015210F7C3ADE2F252BD6006D9FB92CD2BE729FC85468CFC5AFF22184B5BB1A8ED4837FAB00413BC752DDD31EAB3D5C24172CE2ECD024503F4A7A32441D5268681ED3E2DF7312A8A17A20929E9963F2CA5F47A1E26E59166349D40032E018F1AB491003CC0A777EFC5B8316CE71C261A14AA7CFF20E3AB9760591D982F2D725774D1A30B2A4E20FD0AC955A93400F4533B2B3C8434B00CEC7C3C7C71C21BAC6AC8346F49BCEB91295352E42B52CE86855D6D64CE2DC0EB010F206767ABE7639409D49F03622275317BC0F5EC84951E562C15977DB498381C1A940FD0A7A8AAA81F89C3CD2904668BED8782A8EBC284D050A9CD887B98C41F3D783C72A0EAA2283ADDEBC5ECD7A79BA3BFB37DAF1CAD1FC65CB25AF4ABFD4E710E28B540458807CB18E75B6F5AC6F3179CD7403CB15DFFAD4D23316C632C85A39C01C0254ED502C93D2FEF92B08F10D3CD5B5790859298925105290E627783EAE0848D60F66D3C9932F194189D1FE5425F39B3C8C93E7C14BC41367B89A920A7E3F04E6BA63C08A8D560EBDE04F78D2E2E0F89A286DE32E4F42C4A9FA4330097D4EF90DE138467729B746BED8FD5784ECC1363953D2D63AFB5A6EA7ABB68991ABE045E4B9F5036DEECE6D489D9034F10250688EAB49809605C50676F3F3FFE3BA165FED1B8395375F63713DB2E525126E19B7BB0144ACCA34A27A95005A349B468FD1B21560EE6704E09EA6579A3E62A1CD78A46163DA750D305AF119DDBC2C62FD69EF58301F74D5915F353BC143E00EA78EB8E81FC3826546331F79CDAEDAE4C996EE95EF17F88ABCF5FE562E50812B0CBE192AB39A40495279697DB630C282DB3505DC6E82B99263AB42257854C84942AFDFD46BD1A0ED10778519D634B743F09BBC4BDFC9DD7B55F61747044FC6B16380F036284C5292BA13D964AAE99BBF1ECDD6879F2C76C3E0540F8B8E64F6FB43D1058BA3E44B393A67339193C62B77B979C10EE0CF30EB248AD0FD93AA2F1011456718D6F3F5DA63575062B5A578D71BD2B542F25B8803D7230358E26570D3ACD00CE6DF3BDF4131AD104C3079389A83B3814BD6EDEC17B9598D10C40D445169F23E7307DF26B5A599B70475B8C1EE22BC0DE499DF0D191AE3A322AC639F48057C6A58A5A891633B4A265A1E926ACDF10CB48CFA3C424C7EFC9F7EA3FF02D5EB15FF023300B3B449E64024FF34270DF8371F984236A93EFFF913EACA3F6FECC96868A6611EA194C791E1A2A1A1EA1432710BA4223825623047F07D60BF756E0B6F4A02D9294240503D61A6392E76275E32DC1CD079F3E9D5D4B6D0BA84BF31242B73F4A4DF0E55B6D66BE4BD662034976998408C9AAD7EF5DB95D98B92ED58BB5A8FB49DD176B800E44211AB14C172345A9F81860B7A20651FB3DD3EAB8D0B2790649F13B92E67A3E30C0F1EE4DCAA9FFBB8FBE4F8056BD216CEA155978E82307DF8B5E3D46701812B8E73A8B88832FE219D9EC1C400A190CE21F4362C0356BC93B27881B406609AF580BB03DEC052E9CA3C097E042CF67335BF0BA80F7D327D6345C6235039EE917EFFF1CEB6820CD308C57EBEABC36F74ED675CE9B3EA2AD7141941CCD4B3321CBB4CEAAA9F45C874DC333BD840D0AE7338B0A4B1BD1D6741BA95CE2553E93F4DBB03BB93B216A506988CF85F3B365B46174788591715F268A787D2E1B3A158679FA1306C60B834EFC461B87EA968DE566BD37B4CBDF0927A32424A500D8F039ABD29127459448E3A303B94EBEB140991E47C27A89E3EE7B64F865605A2EAF2E4179054E1D07D73568162C298427CF785062D17148E5E458A1EF684A26153A14CD3E0F23781F539736EB3F19847CF581A641B1B96C4E6351C26A35AD730D7C62C29C5B5D978DCE427924C41C6812F1F1004E99F1325F67E0A4946415F84FA0BB7A4D7642649C812707315D3D02142DDD5E40B44095C68DDEEAA3E462C470E81007C5D905ECFDF7F702261C16B59841C98D55F572D2482571E77D44942F53429BC0333E5C07823C6C7E4B8C5D92241B8494266D0497D58F4932F55A97C3584A87E132F9313B5A68B039ED58A6B9619BE284132DE5F55F6C7FA9E5B317201EEC2C22EFF849CAEDFCBCD2029D67F92D79D8FEA9FAE7FF4ECD269F90B4FC0F6D35E3CA353CF2418D6514FD4C3F5AC86ABD0E03A00F803A00D7ED3CC8D9140254D902B7164B53E13BAAB2BC66E31827EF29D56D1BADEE2D557E0E9C14BDCC5E09BF60E845176E5E0FD2A1406D6B8BE6AEFAAF6F8B7B5DCEFC3617A05E8409A730A3BB0F79062F95F482C4718A80134308ACA9A9A2FAE2C50C16AE3EE82CDCD92491D807D2BA530525124BEA845D91798D663DBD94C651FF51A05BE6DE43649D7BAF8FE1EFD8A1C07AF304E73DA726BEAA43742E07AB87E07B97F739CB279EEAC916B9C0203926314EA853C7AB533E5C20694832C203DCC7DD7D3E2CBFB112CEFC9F3BE3DE44462BADC4A11833BA240D5E2910C4ED3F7270C3568F6DD6447F986BD1B0CBB49AFCE294D3E1B5DFD25944978EB4F39406BA464AAB0CC8BEC947CC1739F3DB6B3D36941AEB768466303AF7DE0B155F7C4888DB7DF5528CF8C60F72A35F393CA65BA2D6B9A3D55477AC8B227612394180237A0ABB96821492F5EFB69452600B942C1E2B2690765A644B3B5EDBC90403A5099CC0C707060AB61FA0AF539D13F112D69900932291BBE2D5E3AFF67C2F87E091B7A010CBB78EFCE0780E0AA9E389316B82B1228588F9CA48BED8F18A4CC5969DA7E7FF4487C9028BAD694AA758B91D44902358E5672CE3268F18776D64CF7FB47C825212CA61D484810B0C918245741722933B1B4B043624E23C57FE52421D91421F88CAD45EF3ADDA758DD4BEA19F3E653EDDF76498F411CA0603BA83028DE5170A4E4655E5182F6D71771069949928DD8119F88BFD3CAD792B8481DE511136B4E04B8815DE46C3CECE493C645AA5B9E05E711C3B77F2B45880A14A1E49FFCBC1D3C58A94D4EE1C9E23577F4DF619D5E5CB46885640579C9867B39AEAEAEB9B1BA4E9DE79B0EE8B1A71F2EEA78633ED2558BE7D620D3349B39CCD5C3306AD4C4D51BFF638FD48370D7A11865ADFFFAB91A6BA60C39A77DBC19623B4528B984429AB89C2DAC24DDDEDC576A8B36C9C58903FFEEB49251D92710736F01A78C6AFF08585956E6511CEF93E994A468EEB01D1C000913A1965C3F849C239617BBD05177C7633A7D0031DD491F1B3CA3895868FBCDAD9DA1514451520BDE1ABEB875ED29E4DBAB43E86F31B5FA9FF00266044C78E9896DA0A7026761CBE35578E5606D04E8A883B39845069223F8B90923D477D3F5077A10FB8AF0AF686D0565C080AD722DA74DB90B292DEC7AF43B70F1C645EB7626FAC5DDC94C0D4A44B5F653657E7EB4220145B3FE177C57D7C92F9E3D39EF6AC2AD46A75C463DD182F53B441BE3FE976654E1D3FFA82BE7BF5328F3675CF7C0D91C0CAA087E92CDCE15F328FCD3A4EAC7B4CC3F20E4D49BF41E698DF7EA2858B05A114EF570E4C76E29A849A00698687616BE1B20B185BBA0CEAA1AD4E68CF8D1BB3401FF2653601553FA3773ADB082508E15A2B27D4322B0F3A314CA52A8C72A8B869CF2778B25C91B4F9B1DAAA190EC123F6CDA5F5C12DA2746ACA472ADBBF53D209A5E5ADC174B2A64505467F43174A0EA7E16F9F282A4F1E86B8D8F2E3BE26A3DA0444D35632DB2C77E490A80221300C5F01404262BC5A0565AC529A4E70D4B6CE557DD520555199EDCEA5DC80A85C0C11503449E922789EA45515A35160841E118387926672ABA7027D40F766953E83114C13633ED5DA3AE5981B39EAEDA23A4A5C41E03122FDD53828E8F5A0CF464DAEBB0B5E676A628F0FC3FA3A272C24DA70260FADA81CEE7409048C1242AC9F041A2A7F119E2F784AA9BEAFBC86D5E62712F897865810C89C51292F32C7804CDBFA1096D0BBABCDA2BFBBCE0E0659B7751B95E7D35F04F94024B087C08EF9E2A0D8114495305110F7EC1F1D67111293347E3678E8A0DC7EBF220AA4EA4F1581131E97955EDE51A1385B6A23AF4E4CB984AF24B8625627110698F69571917D836FE2C7E549FAD507514CEA6300FB2B02B71FE45EEF1641558A5E9BD490947FB3A39FF7DB6A4757BF3B7FBA28D2FB4EB1797450F7835ED5ECEBEE8B7471CDFBDEF26F6049F448CBACA32F8C13A3483BCCA4CBCB2CC861FB83283D225A2982E92A10A1D8F98E9B3DE0CD6EF0EED07384969994F382B3464626397D2F218079CC1D83529F20BBB1DA97BF82146C82AEC37CE8E1BB6A39B1198B38E04D778023710487BC9312619C5E67CED9CF7E4A3BE702C46EF73AD861D8969A833F0F9A5F308E432945CFBC7732E04680AF20730D170F71FF880599035FEDD98DDDC999D6E71475927A293309BE96BF223966A3B955638CEAFAB38F25FD887F92D2466AEAB9510B954A68EA446115CBFC7ADF9B3363CD90A92D273CDFD93BAD1F7C52B6CFCD4F66838CA244288495883776ECA52316C8FEABB91AE275227C7151F5B2E14BC5358AF4EA3673EFA8AE3D9EAF6ABAEB35372F67BFF85795EC8FEBBE3E6D8A53EA883B0B2A05505EEE201E408C452B3E18EF2F1441BB73CDDE7A08050F0361B0FFA8FA4A3C37DBC7D8B316C6D8776C1A1A5DE4BAE46EA513A0D6819E2804BE107A6FE1689EDA185E09228B709825551CFD063D1E249B8CC99219AB7091AC18BD9A0E13E970B48F8813546EF6CCDCDA89F846F8482D3CB22485CC13E9FC570DC94A1B6277C4CC9935B0E9F11A91FBFDD257DF0C774D003B818679AF46347DD36F2BE3E5E9FE63870B88DC9BF0EA9D9DA2E5CF45C3A64C9C081A84E423CD3A42ADF452230B7BB4DB01CED5C18931FE14FC02CDBBED40F9DAFA0B1285C0809014FB51F96F37BA376EF99E1202F9AD96545D023FEC3B99F52BB121791EEA7A4AA2B4E51DDDCF323256BC5369D8AFB1B20044149BAF293A3B2486DCB89E259C89F2048E3A506C68E399B586D1738EAAE1290E3ECAB43F6BD37AFF0F426BB2A4803E21EF0310554399256ADFDBA84E0130C134F1604DC14FF29AD84F38F97400959576869256F049D9895DCD0075E99ECF379C173369423EE492463298A3E61723CCBFAE87519EA59DFF42C4B0AABABD6BEF6B3CE2F726EF337D18AB7B0B48631EE896263598AC1D8B05D3E90538A763BB01CD5159B7D7E78D8DFAD2A208FF66408B9737E407AE8BCD6A06D6C7BCB7685F72CF6F9DC0D91B5A4FB5EE0274609AAC0190C9B9CECB4CF68BEE083C900234DFC756EC1A89121B1DF5503A82BD6E622F65BC9E5AC775C02AC5042BC00F683C8B052E7B4C3C27D52F1239A52A596AFFA9DA252E12A1146BD51912E61BB17934460B37CBE7DECF4012E8034B741C556C7721376FEF8B55112FC75D14A4748B0F8A8E88B2BF8C0DB64E9EBBD77ED21870EEA84B28388F0D321D23B987AB0E1A5A631B7A383A1548C39B9061BFB5E8826EDA41943A63C68BD38142F9DCEB55091BA3966BBDD41B93E34D567E129CC3ECFF8673E93A14E1AAF905C30C50992C54E2AF379BF03A7C3D925F6458483511DE35EB109CDD008DC5BBAE84F10C066D685B89258FB92DA5F451069F84AA6BCFB4EBF6A7986B28A7B97754FEE18F20D21C1CC992982BB5708A80D70FDF336CBC020A8641C5CDCCCC6303CAFCA24B2495CB3A4EB11CE141911D5B3ECF82FCB2227B59D942A6CB08C1F022239917A1BEB43FD3E6A62ED7180725AB8DA75A1068E7BF5ED65D78D2C671ADAF02F0943C7A7F93AF34E618D10EC4849AE7424F03E902E511B1E2518C6C5A7216E3470CD481FCF56A6162D95BE4875692BF5C74F9DC743CD9BE123871AB725A8FEB238182F8A6FFCD898F13A354837D4828D8AE552D6539CD48819F962CC09CD816B645153A1D73BA6B3F624C4D67FA23919351FEC81644183042D7C11091EA7E9D27B180C7457FEB7BB2DF7615F61744F46730FD916B1D32A361347E81A8C83D1D3DFE321C2CA43B9F6C0E2180FFDE89D8AC255BDEA03720DD93C9327CA2D0C7B8FED05180B960FE27182C32F248931AC219CE74A4CF5798A4134396506A7296043601150302DB1A49B86F7E89C1023A50533814EFBBE542DF6BB9551376C6AEF08653EF8BA59C960157CE1C07C9D9F87E773C4EAF6C4620ADB5BE0BB09D8D84DBB49118DA872FFD93F4DF50832CC78FE496E7D71A8D946B6AFE06E5A9AEEDDB4E10C851C5986EE8D73A460BC531F530FC337F07730EF287F83647137ABEBC04157C3FD843E2267203CCBBA7D5CA401C4E225B6D91BF850ACB24A08C6EDD987F09CE8F3EA54D2FD64CC89DC1FD5248FA40C9507DA9AE39818B57DE299A11A3C09AB6F07A330DE3F6C1A05E39032A5EB1060742CD06F118D094385A41B4A5661C3DF14966F531B313925482C1834B54DFC0D09676B25B3E212CEFD25B97FFA62A20B4361D99F93CE94521F94D6A77B989D04A9FFD990429A88015727B475F901D37C7C094F08FC9727832B57A11BAF1E45A08EF175EF4A1816CDDDD909430FA740D1B1F713BFB7F4A3ECCAE6871D1A7C6E271CF3BE708475423653B29C1448E137226BC2691470101ECB55D2A6AF289549803D151B27F1008B596010EBE749E8DED6E0EA4196C3463956939401346657FF46DAE813AA28B6F232C360E7C0C3891B3121CCF1B90D66ABFD946BC67BADE6DD8A83D67D97522B878D1CA026264872D91D2A9810F472320C323F6AEEBB5739DEDE13C15A4921F1DB5ED1911653CB27B2CB7493B759A1F49D981C51CD08AC362DBE55E998B3B85751F616A5CABD7AF9D25828AA3259CE226562C755CB765558AE0CA3CDDFCAF2BD4B73A6C13AAAEA82335E8B0751C62CF61F54D5D78CF1BC3444935AF82A062EA96806DD81D4487FB0675B1FF77853BED33641BC0FB6AACD1BE0E210D609AF643D12B784D26A801FDAF0F26E3BBC4FD6F597611AE02D7EBFC7ED3CEEEFD125B2C9908B603A7AA5002E8EAA2E16972705CB222695A7FB0AC1BDCB8037604D117D7900F84B822BD2C7AD62D351781ACA3DEA80D5F19D54851BF716A900263971F6DEA65113BAE2BCFFC8ED9C583FA4F38A43BED7A619F5D1CDEA881D7625181C224053944A19E8168C717B461B131471A317C8D30120BEF342EFBE78DAFB3078EBD5A58D733D606CA35FA365A773FC1805A0727590B3D9B6862DFCAF59B7ED75DF49F592ABE91C7289AF60DCCE823C380EBDA7B5502A3A7CFC4C2E071970C03DC4F578F6014656011A6E6249A5205CCBF000642F8E64F20C1ABCC02FB36097AE24A630DA71EA9BA519031F522ED1B86BC787C5FBA145B1E739819A7B0F5E62F872140406222B1FC8DCA2006F38DEE7D6AFF80F5A15E83B72949DB19A0DDCCE3335370751E22B6583CD6AD0D31FA104DCEC4F60CC38B69FFE12F26CA67483BF08B3CE8DC0315AD0C15B498399A4EE96583803670E6BA3BC9DDAF8C85FD3127AD760ADE520FA34E34E510A9D73EDC4D0436489080B1C46DF32AF58553033794CB1ECCF62B9079DF10D33B8F070F3BD2EEAF4B23F6F440A4CAB1AC571FE420CE54B92931ACBA8BE0006C334202EF0397E412B70B00FEB587C4CB51321AB49E73F9BC5C2F916780672A3088F6A7B91E26A01BFC0CF4C9191780779B132B02E688FE009048C68BD2E1119C8DB51B1724C1503E8B8647B86C522004E2CA10E78C44FECD4D159A7D292E7E1305D0887F0C50649AF808A861FF07E3854103962189C9CDFADD09DA53B5BF7A154776DE4BD16B1939007D72B032D9D4215CF972D4DD628CBB9651440259D88A9F5385C8DACC1C2312BFC158373029FD317EB8B8305A63C3BC35DCAF8EC0DE794704EFCDCB500035B1930C15887C6C2B7FC184D608663B8C0A8AF963B926CED66A530AFBCE4D45D919A65E46ADD2662563E3A31A65A7C73D77FE2C1AD33EC85345684591F3BD035C8DE6ACA760BD3C9F3BC9B74E5A74113D1DA8B7662AAED841BD0E0443F684EEC8E857D4BC2B07D8B0767D82AE372206566ADFE4685DD560ACE117966BA17D8E09A9EC61A1106E7B9B84978E439DB71C62C9880F26F6666CC82FCE218B37F841F3B30E212CA75B02BAC652A02954EE9A9F89CED3F7DE0289D8AF0A0A04450BF082E5311DD32A02DFDDD160D5155B5D23AC5C207A03DD7B4E82BB4EF9560A7478C3627E4826D268FE64873E1981D68932AB8ECB1BBE7FD1521BB9A23DEC7AA93AF1B94674234034707DC44EDF6C2C2C9207DCD7C0855AAABDCEED58C3671384FC99994D319C1CEE48BA58470156CCDBAB8E94516F0E50E19A7A0D4A14A597572893A18F0CDD5CC2C5856D0ABD6D90F345644A280425FBF9436C330701AEB6867CFD771A4FFCEA844C9B8B1ED59358528234BA413B3EA68D568226FCCC3C25847E0599391C19121ED422DB3F7BBB06E36AA87450025BC1CFF41975E0DBAA6F1E6EAF99F457C03D47F19A5167EE9EF60D9D8412353B07E3B604C170C13D1EE648C34D054CCFE1522690F2CE0AAD0C936E1EB065AA0D9D6D24C782184DDB6A48FC7B9040CA4459A5C1751EBFBB922EEEB9E304252D2BBD660A02E084D338058451DD2D85EB643C39C89E0DAC4C3DEF188379E56F7B7FE6C5D47806FEF4E96A232813D539C5A3FC29E79C690B1946833C4E5ADFEAA0E6109686E99ECB2E9AE4D092115530B8B767BD157406FA785B84C605FD6404E9A1C3A7EB4E28FAD8F0C0C36F7F93F766455EEE8CF82C5B988BF0AE0B4FAB17BA6F3642FF17291B47304D7736944D896F6272E53E2CC0468853F5105584418B38DCD4AA0B8A7FD88FC9A4A17CA4C9284DA3F46CAEAA5F83FF058663AD064F1A4BD39E54A199A99271AC73EDE90EE6747DB2F4F7FEA8BF0C621A075C3755741188206CC8B2B602A71E65F3613CEB82892783F185488A2924BA27DB5BA00E630510C897CCF71E2BDF48C09D38FF730418F4D42B12AEABE2915E83BBABCA5EF69EF4FA6540BE2AF106DB53839F73EAFEFCE72C0508BDD1B0B9C050BAC9BE1FE104DAE4568DF26EA89983B42C0584CAA7C9136B580236799273689E5BDD0C2C74CE862B9F847E6FA32F629E806F6748523066B094CC76D9EADB17C6FA1ED29EDD466A82A95B702BD31DE325933861C9C3607341E6CBC6350CC0852769D235B413477F05EA9EEDD61CE205763334391393A83B809DC8C32797686FDEA23EF13D4D456FE31900EFE89BD835176E6B55E94586242655D150106E603C44D705A3FF26976208FAAA3EDE053EEDA35B17DEB86683327E67A77807AA90AC281A2A8514477B90050113C3A9526F0EC0CBCF4D8794BC19DC904FA1A954E0A5148FA58930C88F1D54AF162ED4543E6708182CFCEA9314464C99ADB780EE1C9A593A222C5C00962D54E0AC662D253F2053DA12AFD93C219D28361C4548416E432A6964509607115227089C1CE24480E3CA9C6226F508EB56B90F25D79C3DFBAE9D6581CE560C6BE91FB0788931C1367990BB2F3DC5F0C6E68A6F8E55CCB94D9DDB0295FCF6FCC14D45FE181E9B31DD8CBA7BE7B580D4D3D59866B4F2F597C76158B8C90AE52594DF4109359BD2D2FDBC9E71F25B360965074A4C91DC8D1DA72228AD98E9B00593C653DBD978043D90C4E38CFBEC931BF0AE30E8C8AAE7B36FCB58E8789003DB4215C9B1B8D424E00E74D6C4E5F29A0CAA01A0BC23C5F36BE75B35371311EA9EDADBA2B7383D68254504A8657B560511EC64395A9032E9A175F583685A54AE81A97A92DC0D5BAC0A5F73FD809E7AE820E12452C69982D962D39730F6F6A4D140FD74A6B362B4D8079E0A1FEA27C3D99B98291B41ACE435F4FE93E483C93E89EDFB66438F33F60CB119DDE6DFB2CAA33A5B3BF5920623ABFF3CB09C03853100394529EBC2ADB18CE342600DD61FE73FA2172CDA554867D1D37C253FA3E1612D93837AA9FD2362092C249D74C088629F4E62F0977FC469589ACD0CAB9946277D688AFD1E799BA8924093543300AA75F04757F75BCB719CD1DD150E96FF0279AF85F7E3A23FE50EF4E4143B75F1A989494C68F63B0AAA37528C96E35E8A24C2BA873CA6DB3D5489C11621379AADA3FC0EB2628DE65B918F7416AF6720738B80BCB552F7941DCDB83AA76F7686135CEC70C2712122FA734C1B7687E693D86616F1FE3C0D873F4B71BDFD35F0470756EDB5561F630DD5872460640152DB7F0504E7AA1F89076262E1CBBD56CCA1141CAA2ED412B153D88A72ED8F390AA215B4671629A4F312EF23275C68DC60D011E891D259736B78D20B6921CBDA4BDCC43837C2E0AD1FC73C27EDA74CEA79EA6EF418E112741819F41B16B535EDB4863FFA51E3EDE5B4A82B8CF58AE720EF170D00C2A7FAF71E3852AF65A7DA0F83419708EDF95236B064EE5A09F8D93F6F7048EA13C77F92E3726B45812D4D7031F6621465FB384EE255DFF193EB09CF2617AC3280BEB52BD4B2CE89BFCCDC90A4C7722350123D55A4C30A6AB4690993ADAA65D66E2AEB11243A4E175EE6183067BDD60A01BDCDC3B7F9C17D3B5EC6205129DFE10320CA797014B91E96E6C5D6B4BA4CC1792D940108576309826F53F7EB14AA43C2B9194949A8660B87239563C8A24D70339A058EAB8E7FED429D50481AE05BD153907CBC957C5161FC9C0E32AB83D7AC12FA3A846B74273929CF90FF9F1EB3F7458387D394C15A3B5FE9D7135B6F21B754F13112901D18888DDAE48C3346288E7A628D4A9C60C1A829280FCF1ED0BA78F25C886C994624C56201DA565D371083C653A649216E870F0724409FB0EAC384BBB0EE6851E01D95E937396B004AD409278E5F1F364803687E88CD8287F5C8F0107088BFB4C88972A63F31EC0A3DB641A2C4F8E43DF486A9AD65EE0DABF50144F5FDF7C2339DE99AC7C23E92D83B921CCFD66AABFE8EB2AD4AF20E63AAAB9330EB3A18F64D6A438108C64D9B2C77C896AB2AAD68481841345C1E57A7E5D20B70160BAB46B1A6A59E0A02DF755C9CBEEEFACB1DB37A4AEA19CDDD71ABBB6E7CF2CBD628C70B8C7404A689D51DADB16C8CA0C510DCC1436DD1A3D0097B484C9946ED102D3E75D76ED553D73B30D75751D0F28D78BD26B49130AF66A7E8A47CCDFDD847FF75AEF1FAA9B71C88E5469350E7907E562C9603AB39C392910776B9306458F70EF9DA3E2C0F964BEFB022749D9EB679F1FA187D9BD206615D08773A685271D97D01936FB1EA71B3B44BEC0499D9827A4895132A495E72672189A2A5F68833988203C689E039D71B60B70B4E6CD95F6F6898AEC4E13365F396CFA8DA83EAE7AA0BC0B0EBF1F92CDDC8B61760B117329E36BC8F64E441C345CE2D3F55AF0C360CB0ED7F8241301A9D82379F790E535D16A61A07DCBE9EFEBDDB037EFDF4DADDFCFBFF497990CC2DBD3AEFA1C4B221E48CC29350C443D4614215A5F121D948377B5E4C4F6B11010A1C2356925CA24E8D2C6A786CF2EBDE3E38188C39C4EAF4D779F7A2067F6794B8A0C5EC6598F2C25837DC24FF1ADA190A4F7A1ACA13036BD310377056E952E4E2DC342FD604219689550A1EA94134748537A959BAB043534C15BD320C3E76883F515D2868FFA6993222443D1723E1B85A95433A88DA5C3591F22CF90843FC39CF8CFA3DC373340328E6C0AE2BBB06FF023890A1F72E80E6C9822BA19AF6A479934D904A07DCDDFAF5B3C5794EB4FBBB3E4982FF918FD1010224D0C9A83E27382913C68A655C17EEAEFFBCB1B61EEFDE8C4C36D773F665BE5BAC763E1CE61620B7281E268C635C9CE57F7C357A3DA89A4E298B5DCAE510CE7812CA5F60E5B3891B2FDA507A9C7198D6AEB8BA49151BF66F9F2B027630F9A6505DB0DE52CCCE2F5F38C71127561B1B962F859CD5174D923F67C3DE2CB9D73CA2B90BED7046999D7343973B067561001522957C2FA2D80DA2671EC7434E873296A1A889F59386C42B24C24CD17B48F22B5620693102F6163A4F4734F1AC0C875037D8AEC12E45680F9CFD6DEF5C1A0F5B0D6620DE7F319CC16ADBFC84264605BA4BFBBE1C63886AD07532FEF718EBE7C2E060EE772481011EA148B868D396BC2042BA824BF890669AC005E2162C43E838FB4CD9B6071195D54832FD3BDC6509E9AED7EB59F94E2A2075335510AC89DD268DBD09A3F2493BECF270F599F542FD5B8C32643EE19D54D1E8C037AEA837FD1DAEB80622DBBD0816CC91763AF690C2E04922D531B5F7BB94A686DB02BAAEE040D513A680AE16AA96C845367A7E7BF48E29BA06AA8B0B9B7311269B42B3DA3E13E666A160AB82E083E6D5CE49749DC5E2F4DE145FA804BB797AA45B38F4C1DFAEBC5B1D71DE146364C196A3690A0A6AB47B65DE50BA28291DD2AB903FF1C84A18E5395CFAF45317EABFEC097321882342D38CA6AD274978E2B88A3CF13DB852915C58960E2DCEF62A82D38F240DFD28D8D92BE57C6FC8B58A113CBECDAB08E575DA49FD336C95B4F553A43CD9AE2B8E7FAE0496BA1565B6C09C50F46427AF41B8FC39D67593B3B0C85362084B68A3644B4A59B373DC81DA8A1B6548149B1D319A61745716E687EA030A70F1A286D1E387E7290C18F90D8F9FC57E595C26764ABDEAA3B2EF24CFED891EA343A9127B59D576998A63845AAAC5D36769ABF8AF9CC09DB8EBB238A4E0BDA2F9B309114D86814A83E50A9F4D1A42A956780DF5C6A3BF415B9CC38E9A20CC14F173A74078D9C2A34C810D345D8A68192E62FC693397C60CBB106486BCE3572726F8CB7477E54BBA5B97BA2A4750D76F430C3B16A4BB1C27D867DACC8DDB18FC099900698D2827C957A327F79FD0A157A91D76C79241C2DE0ADF422DA9A42DA256090A8B1A8836107F7FB0F576DF72EDF46F7EE5BF690E6AE69C1657AFB83D486E676AAF30B1F486E79600C7311A045364B5077D318D47A5A29FB8FC24A2DBAEDB4AEFD130E68BCA1D753432230852660D49BCA679993699479532914105EC0DE518F2B982D434C59FCF491BAE761920D7350CCA7D4139807BBF0E4FD1FAB33D62D6D8C264C9EA508D3A4E9221A4220A4F3DA2D4FE5DA9640B4A8FA7150B5595B225B04D375B6123B9301335B2FB01891216BAA37F8385A700F7F20A0EBAC9DD1AE3586C270E1CDE363E928689A98E7AE8F70289823881A1EC0D31ED9B9CBBF64FE8CB5DADDFCEFB7BD063F5B009B864DB8F4EDF08356864C79E3FEF8BC6B66EBDE5B0443A032F82708555BA25873D9F8808EF4E771944A7249BE605E3FC0282EC28E6A75B90EBE12DE53914A19DF57F1E6714F86AB16F542F8AFE85C341567FBE778C52E06C6F85789A7E594AAA034998C0FCD5F662DD9478074E29E26318D6E9ACC9D66A0CA12AC1ED73F01901249020A353133729D990BF255659AA6F6FBD84DB2D8F41E721F4B039F26A304963BA2EFE82A4D949ED8210CA89F25043F6C3E2FF76C587E81E832949F6FA2BD1508CDA1D1910078B934CA82592294765013214501DCC9D3C6FB215C0E03AD835A0D92360DA22FA0FC555011621BEC293BDCA7CC9CD0E979202854C198884BFFA80B762930264DA40F96DBCAC2BB08F8B7D3ADAA45EA04D685FF73C89093A36C942D09365E93FF599C6D4397299352D9BB8C17F6D32FAE5161C664214C6F84E7A3CB937D728C4B55B15A0EB52C702E0C4DA60D72E4E8DD63BE64C04658D1A638D6B49FCA741F4B1A5CA127AD011A9D7E2D96BA75A4B9A8E14AC107E01FAC73A915C79B65AB798AE25F651CACAF00F132313A8A402404915D965B0DDBD1954CB5C8E7A0B0AD470B1FFBB0C089EB94E05CAB2729C31F7BF98582FA79161D942F4373A09A576BFBBA962F81653651D1473EA9E04673E07B432393B3EE8E178BF67526DB19310BCF9F9A5BEB2B58DFA08D0CA899B3A58716117EFE249EB528466DB753D7444FD6124BE154DAD6F60F3FB50B0E7E104EA2666A9D8FCDEA3494C40B95BDEF872EB47FFF400B53F1D6239BFFDCF0330D7BEDDCEE6F0551D3E08142BF733F6F332B6CA7F5DFAD6AAB07BFC45C3977282047ECA7AF6B33C893BD60D25CC87393F25E709C193D7C088E7D94C2109CB494BDFBE617DD7E94903FAE2DBC51824E5ED88D4E5072AF9C5299CE575E003C6E0C678D9A853AF29F6DF8DCC14B6DFA44F328802BE7DE5B171FAE27635D71A398B8667FEFE3A508A8B79C537727AFC920769892E86406ADA942E8988C0A99689204550612FFE2FF0F74506131D1BFD9A8A24861F92F0D77453AD504169758D6328A9A7DE22189F0031016C9C09EF0248A6F1908C03540C94B2134AE08F098B51DB54685EF8421F844A379D6F870E9A039ABADBE55A062944E5142529FF54DE01DDF86BE605C840325FF24FB21C84A1652658836EA029EFB8C5B916D5A0DBB05602517270C2BA16A97E2D671CE88F1219DE986552D4DAEC4CCB7E8CE785F4CA4556B2B809856290C164BDA001C1DFEDE49DB61800843374EBEDB7511C71B6801A6BFBE29C9BF6A023D9D30696C7BF95BA04C462C55B7B0A2E765DC4505E9C953B8C9C249DD3D3A3F0D62404DDE45242FF9420E19C95771E6D34DA21633E349AA91A64E25595A03464B6781B406A89D7863C93E662BF95F290CF95FDF98CC92F083ABC89BA331384063A49BDDE8EE0962069DDBCB8236CBF3D580A11E5FF4B6A82ACF5D9E04E7D0BE039B168C8DA3F357270EFF6B5B5917080A0E27F88C08F707581E6C3D52D5163361F18D3CFA32B9253F94BAC2BCEC69DE4369E930477843C14FA9C752F56C721EB3C222358AA4FA6B57B09DE917146D739C1B5F22D82A6733F1D04380F1077D1D7EFEEB84BCE544859235EE12783CB058409B0169009FE89763BF1307843682633832CA7E52EB6FDD663460E671496D8A6F2F12F4C6F80DD0C3494432E9AEBF329D5E7E0D773856E9E249318BA469B301948D7ECEA6F49DB20641EAA4D57E49E2507903CDBA2E09714834650F8B7A6CBF90E0CCBE643748205E78E10E93C4646A6F5188E83AFC017DABA5495DBD6AF31969C3C2B0EEBBCADD81C0BA5D9CEC8F51950A24C0FB732A3AFEE047848AE2776B5AD4672C8223468DE0DB6C3E65A534E69505D0B9C934254661A5202B0DDC421A4150342F3635B9701A2F11E9D169800B72C8E47B1012CF547481ED7184D16D2EAD91225C02E839594B5D152310B259444CF68DE5502BF9A80A90E97226258B74A37AC5ABF527024738CF985E961A21CE5420A8059FAF80D914EB86C2A2428D5FC579EC0CC2F92949D7AF10921FE6373CFDDB73AF3778C287E57292353F7ACE0271D6DE9239B245D2F139C9CF9BC2D4C66F76A115757C1FA96B918E3719139E42758E344761428A8426E2592215020BE6F893B0142C7A43C77392B15E6B2EAC200EB69FDBCF5800E2C1ECB7697D48A2B6A03C1E79764E8C556FCEC024659C4B00D7594400FC0472DC3E3F2DC07370D76220BA24DF5EDFFE9830D18D9F1A820549F02012E367CA709B9EAA063A69360AC9D6C4608D64E9B2857AB6F23B08F099CE6750477F1BE5CAF79CCE6DBB827A6EFC8DB8E7A19D186916F0FCBFE186C0D56EAA9284A504EAD4FB15438E2341DB3E4C15EF995D345BC42272713D3B252F8A4224D8382C4A1BBDE5E4E61FCA66DF40677A8A26FC5B4765C4B1A950C1F246F60A4F5ADE62BAB44004B5092E2B76D9C74312747328F6A47A84296A2CA11CD066264521674CCEE322741BC6CAC643EF71B62A11FEC5A9247D3FB259552C2E7B5CECC03BAD3C1ECC25959E0A0A19C6D3975EAC31C39BFC9CAA1FEDD719B2D0FB27CF3F24CDB2AB372753972A9F13E04B1A21E10FB82240815210CE3D827911BFA3819E1FDA1ABD4C00D6D886DC708482BFC0A46EAB88896A0D4BF832B381CF25C89467218A63A601944E4FBDA68466913ABE3F41A503A3B36067BCD6212EB5FE508FE950DD26054C11488DB53D648B63ACC6BF17CAC5B3A4AFF86CB9F53591EF061844110D372D0AE97CD333413207F94BAD3E4CFB51AC2D2F86A2E08B28AB731B9D6F9C967E71E9040988016387EC0DF502D77AB45F47C561199B9C37912EF1021578D43C376DDFA985FD1E2851D7D691D908239BEEE604171E87E0ADA6B79E7C366B83EB690DC680688961D0082BA497B56F16A1E000B5A258F4DAA7360AEDD458385FEE93FF5C486A538DA000985BD541129430BAF71785AAF6B8703F366FE99CAC55A2E353AC61793EAFF220E52FF72E343E04B33535734E52B936D04D0B9E6CBB0C06FD47FC5910E1237F6151896C7B12E051FD0974B5D9D708E0D57A92CA6C69D43191E52107C3EEBCEF4A2516445C48C58F6ACAE98A69BADD491DCAA41B2D51101E89C572C2CD624E9E2A7A58231112E4EBB6F92C6E09F9BB45B24D804FFA1E06FF7162C3A002D730AAEF39D5E2ACB3076BFE4EAD212455ED97FE04CDF502A74B3673245B7B948EA49479403CD1DCAB26A2FCCAD2EA6F2C4EA09988D95E9B487F3CCFCC444FE9478CF70A6EFFC806D417FA04269D568C1C6C6211D606544D887E3D4E0426ACA3E972D484EF972696AA4FA3D520DF6E4DD868333CB946CE2558143E03225B6C21A6D30129268D1994ADAEBCDD702C1D31E5CCE9CE76A990F91290C3119452DE85CF7A683959A7CB29FFA9020D07AD06CA870BD0A82E8AC138BD5A0320D565678641ABA9015007432E70B7089743A8309AE6C1CAB93E869DFC2DA15025DACB786C594F25100516DB601342103E2478C65AD0AACC76CEBEE4C6BEFA200FBBCAFC00C2513C5B8502E74A21EBCBF34A0739665385C2A1574BE8DED96DC8E04D62315A0FCF676325AC76B926FDEE8B238900AC31070859C3095F9CBCF61BD0AE71B1A2B80D77B97D526DEBC342C578CCE43760F45B1327F81FD5C20DFE5C8AD9E4C248E0D3CAAFF8436FD1142569AE8095974876937358AC5C85390B4446322FB0D9E17E3358C66AF7798F05E893268A64B0B8ED3332B98AB50BA6D7772865A53A71719E8396CA2AD6392251ED5BB60EFC34FC8B5F9BDD797250FC687AC09000FAA66AE264DB3B9962127C2DE21C103446D9E447074DB737F0D0DB8E8297292B086215935934856B4E163ACBCF3AB01D9B082EB4B9A9ED6223C860217EFEFBED303AC9FC91496C6CDA4DC594324ADBB23FBDCF55E187BA52ADA465729295CE22DDE059AB3F20FFF215180C508E93FFEDD6522122EA2BC5EB63FA0C292D62088F973F43C8DBBE6CED12495CE3B195AEEE549A718DBBE29E92D33916EAB6E50CC2C6F123C8870D86A9309E281A89DED9A0AD62B3F83672617D6AD75B8EF72840F80EE16ECF9429E62FBC419E938BCFD6509B12A5C6C34B78E7AE2E985288FC28A9DC57E7CABA4AB7212BB49DF6879762753E76267118E8EA5C889A8A29AD83F73B9E6B5FDEB7F07FF215E2790CD998331BDEBB5E2F0F792AFE38FEE0894676ED6C65AD0954DA1636D1D3AF53C29744987A13CA6E08B5D5E010706BBAA0D4A27F34CA5CC7CA67EBF7281B4811447D0A819A48CC36C665EFE7BFF4785CA3453AA9687222923D8A7B1B7FF6AAAB7DA23F3CD9BDAE5C978DD0E8771D97D05704D866BC9290CF856CD7E50E1A38572A1BE7D420655041AC1EE6D96510761BCA61500809536F76DFC3013A5ED9FFB3E64A5E954829F7A5758023D2AB61D1E49183A6D6ED117BBA1882C7C7244E9152AA791AB61C400AC518A9446AB4BC09B20F394F8200ED8E3D438178B41800105FB88A01CBD9220C1A4189FC3221B55E5164ABBD09E0ECEC00FF57E8B00D1C6AB29A2679DEFD4BB7435672F5EC1E1DFF4178D53DA9DE5A4F18BF201BB726C6DE2E1C4620D9DE665FEFB8B04E6345EB1621C866581566635AE248336A9343511047B707166A904E32DCEDB6D8534167E8F261FE090D3D8AE63C693B3E60E7C72F523DC68EA700C9AD3ABF706CCD5B21037AC8C4BE1221D519593020065281C68FC93D8EC5962E365AF7CC8B65F9F428424FB017329F06458312C922B932A48D5CFAE96D7DDAED877779A267B36B13F7BB0CBEE942961755C723D7F03FE124C6254EE8794B9CEBAD2A3DE7B4D5B8E899E2B580B71D15E7925DD20D16763716ACE6C1B18669B6604305AC9C8DA502AD4F1BD3F78B88E5B95CBF919972FA3E5EA7E4CD4F178901BA6EE6F256E88AB8D3D2F90CBE855606198BD4DFD3CC5817C276734D2603B0D145936801D6497470D76B954686A5E2ABB5C0A078BEF1AE6014177EFEAA3FEC09FBED950C8848DC63C436C3855F2598DD993A48B01F5C8A190BCFA47141DEA6D56FF1724BFBEDE18035C7ABC602DDA76F9EFD0B44A9BE83EB8258FB749BA8418357E7C3D17CE9E4C3D5E74E055D0F2F8DF5C31D8321A9104A45D6BA88BE9ACAECD1E669A96B101C9D165BBCA23D2E226FB1BF4FDAE8EFDACDC3D542EF978E6AACB2F91DE19D0907C91A832C7A1604BCEEA2313B5BD87324C5BD48EF222ABB8E3501A12217737F152F5562D912307DBC3FDE0C8E0C75FE4B33D99C71B1F618E847FC913D7F1E077B384358AE877E7774067096CD6FF14B744014C2D888B094A2CE28F322B6D815FFAE8589B28A89695150A1F0EF1B9172535BB96B178F1F7B0914272A23ADCB31E0CA80A8952B239B075F8E623E660DD061A7C7C3A54F90E4F2AC29C6714A5CDEAFB54621014A148A70908B367B3FDEFD803628EC36B42367D873F0224407C053A00E8C1682BEA1B47494B7214EA41344B8DA65240E9C724F617403274AB1DAAABB72B66D998E47AFFA973D6821498A89ACD6A2A4C7D6662F25E873D3FEB1B63419C9AEFC1D13114E7388ADAF8F76FF601C02A3036B34CA26F1F9BAABC1B2A5AB79269B84BE65880683EBAB10E4C59C2DA77C70F16FAE93A0010B9379A1EDEBAF55D174B76A84A9C01C0F922FC781D7B60B830F6FCEF9545226578FFA4A3080DFE992317C0CDF989D8843F210EB0C7DE8A44928154E78883A4A570A045099EB773D102690F118F36A2B9B1887881D7950B771FAF915A63A51C95DBEBBE175508DB74D8DC6CCB09EBAA089FD2A790905472270B4CC397D860A5C0D146F3E64B1CC70AA4181D1B35CBFD9D016627BE9A1A4BC25A166AF206950E9FB399F4A07467421B4A44AB446752C78090557E613E0AC8ED9D11F751A65EF7BF37D8E0F8122F0ED6B81C14687CC1A53EE0D03289B20E4E3B50ABB4D85E7569CB353A0871FC8E7A4E9F83D88FC8FF03A467D0BAAE134010BFFD85D0461002B013822A293C6BF11C2E4CBC6316B92E5B96672B71D494AD5D5CD8A0418C7E8348F1642E92F12359B1C37C1740A732A0A974690CE2D6018EFDE02E07EB0C7FE3178C9D7BCF806F4C58C722C6EF9CBEAE73AB4FB6B60C8B5308A22B647B3A6C86F873443784C35B913AEFB1B328B0A230036A912FF0CA02E95C2C371F66DDED9B59804A9F3C4BBAE494BDD412A26E35A4B1145BE73461DAC029A18275544C9454ED6A074611DD4EAEE5F299738316D829937914CBEF3CB74E33D80EDC2B216D3E4C5E5C7055AD0E4FD4C1D0E25C51A9156E336FB10C715812EF1F741C3C31C8B6F8B6CF0EBFD7D7ABCF91CA374E76702A844A9AC0059FD656B50E43FEA48C4939A2D74A669C1A37E2B847F028ABC7D55BADEA591CF717420AF143A0758D5CC189024C4A64A4E029B5BDE09B7B1C3ACFA4E1EB026F190634EF3E5F4AE9A560090DDA87668EF19EC2EB34DD97EB744A3357308A30AE4FEC40C656E85828592A6A462FFBBB98E1F3B9798F378B27404F9D8BC10378B9560777CD22074A269FAF8218E6A9F4C95BBEDCA95C5CC2537C80FFC8767651555BB6664DA5F1448E3DC29FA5600B4505C7A02526D34C567076156FC848BDE68E58C31EC97223127F65E4BC854D65A1CC2A2CFABE51324D160057C890C0277E400099196FFB24CE8D68443841D609FCE284A2B2BCCB3CD7FAAA916F24A596E356E8CEB16EEA5C1A2E176771D28424CD62D1F16F4AF348C2C8EA40AB62B24118BB952109AB9EFA8F1320A46A42036167780FA828D270FE7176A850D3966894C78AEEA9597C36F819D38F33FB02CAA0B4AF7D73E2E205B59B8EB666A566195541D74B1A707DFA2683D87DCEE885F4E390A70846E1072424EFF38F643141B9C2DE1F8771E71F1EE36CBDA1C20675B25F86C4EABDD334900533457210ED54E9FA97DBEC4BE4F641D1C0FD8B4BFDE0D0902E4F16FA9DE8B54CC2442F2A94E7F07F0506271990B4E389473B7E44E02A48A30C3F81D640F957951338ED0723F90A49DAD09DF93A080EF28164C71EA95AC114A3CAEDE3C7160AF0395B015BB1B5FB5F66CF30ADB898F8EA1D89D3DEF05B2EA465DD2549ECD0BF08CC23C450A36F5359CD1269DFBD5F4F69CE2C67CD3C2581AF0EA3EA1B25FD1E73F7AF61552FCDDE19843C33C2069CE27D893C2EBC28DC00DDB2EACF3B2B5A683CF73AA938EB51316AA896AC1905905AD3CE9AB8F41770EAB4ECBE3670A8695EF88F838DD272A4F42300584FFE33AEE2103871E0AD930EFFD78D47A119BAABDF4B546A31AEADBFBD8FA89B3FEB21B9AF97E4D50257953C98391A70B0E1B11F0B5A828406B2B44FCBA3E5AF14CC666CD1FBE0D6AD33AA43ADA0050EE4F49203ADF8484FAE290A919D3BF69B2E37B7B643DA1EB96E94A28ADCAC7754EF86DF4491CFEE1C55D5DE6E2E5147C3EAB4B0314D715C4920C618B5C30BD07BC025DD2541ADD74F516A5D76CD8B2E763CA023C47833B1CE18BC70570E0839A55E1736ADCC1D1D8242CC40A01C3656B436B4D39715656E121ED57CD8FC4EBBFB8F03464ACF957D103F5CB041FF85022B8BA7EB43AD017A2ADC8C587519CD30630FF59EF8596FC6CAE80B421B2B513D70379FB619F19F0253A48BDFCE0F7E44DAFF914BDC8C0A99EDC60B566AB9ADC698AE79FB5AC14701F455B1EC881B7DB23A330644441FF0C746924E7B55B93F3735133350E5FD19CB0B344F5BA251247607627A49FADB1AA1BA177125F184CFD70FEE5120855F4600B54C2A33E1A0788E5136DA11AD9AFDEC6D111406C67D6FD0C79FA6AC023EACF01FAC5FF45C1A932A933547FAAE9058014914B9B8C46845F508E90F378D3EF6E50AA0697279FB677E46C613D0FE7B2C79F5879199911C685A3A55E24F416E823B48E6107C971397B54C5A0E4A581627DC4B3C6BC80C3AED7FCA66290B48BC7E42BB1ACF6DC7EC6194B12CE7FC887DE65DA926414F7F34CD478D914614BC368F88321365D70C1A4DB57A874AC1552A47231EE97C3C2B11EDAD2721170E744CC192303E7E210991A2289EE2A420399F9E0BB119840AFF2745F09D8746437CF968496D2A4EC6D6EEF338B8587EE238E756C4D2538D1C89C40807C6A1B1F8A96A4F3F2715877C75928274F28502F50154362FAA3A4D1F4289BFCE4AECF7DB3CB52B9D040EDF18B410CDB9A9AD0A2BE58E59A4FB9A15822FE3349FAC9C1B33E8ABEEAED32137833A6759D3BF794BEBA6BD92A756B65131C7F14D737AFCED330B63E45E55410E7813A517DB7F4A2165A54436C83451A03ABF77DE2FFF05A7766A60E17FA9561DA5B5B6E1BF372D47816A118BF3F9987F8BDE69D667B62C8C5AF82C122FB0C6F7C2EA81955DD900F6EB81945EE141828CB89A2764A53505C890AEE163D374A45042D7627F6CA7F184C5892D0D117BC48E9BE68E17F920E29779E95E538ED217B1E90E81AEA9C08A377D72CF7AFE96C5F7E08F0D63F8D74E0DEE2425D47C713EB6A6BCBADC0F307BA3F719926658E114665095CD30AA647D9DE8F4EA221341A56146976748A801D17390470D878F5B864C8B753FE6398FB369E91C7443F88670F7FBCC673C174B6559DB22C1CF5FB3FFB76B1CA41D53FCEB71BDC76CCB7B115B485808E0CADC475A30AD8FE0D29C884B6BCCA1272BDBD65D5B6175F3B09AEFE4CF65AF31298DBD107D9DE371DF2B061CB5F20951DD90E083DAF577660B8AEDC4B1B7464E12FC0C89D2865418B2FB595D39F2CBA1B575309028242DBB94521B22BA2196684B93F197BCC2FC6A241A362C80AB46AA21613D9FE15056EE0B37383FE71C153D74D3B3F0AA0712D743F3A7888AEEDAB43A1949ED1EFB527A766B847C5AB20ACE184FB52760CCC6BAD7599ACE9DC9E3E1265105075E72CF52B6F0813D13506CF54D27DE48693C9CAE21CF7A2FB89EDFB9F58162569DFB1D4BB89F43FF3739B896853C560F5390D3812C83DF974C3CC9A47C7964773B8A2B842776110F08FD9E28181433A77227051763EFC2480FE4F03671E8339384D9D0875C2765E4B50EC3293C0F742AA4B3481A7EA8CE97DDB9F3B8ADB9F9ADE788883BA9241BEA97496EA864F5B54ED0AC35EB7705B655B8B2A691F89F1355E5588D9762C1B82E21A4E4D447C6617656AFFA7B3E20CC8670DDD92FC79BB8AF216126699083C3B10204FD852F27BC0CFC57FDDE077429EBB7F7F618BC0689FDA23B71D3EA04587C0067B2BF6B810EFC5D95143DFF747D92EC168B7C9B89D43E607A2B6DCF82F5D6C981D3DC8B1F45591101F88557389593FE7E4B37A4056872505B58248CC666AB1DEEF84BCE4F61C8A7D831563639F041F8D2BDBD55D9F3AACA6BBE99DA68F7B127162FAED064E7E1F6D9EA39FD21BCB011FD6D34A5C1EFAAB57173249A61B6958C09DAB26037DE9329F978F22C632C96E3D163E77CE4FEEC275D2A49C4A62E7BDF5EC75D17140978E07CA9DB4BCFF4D525DD4F3468188A2C8D17D1A29D74698569AB4D842D23B0117873A9466C620886346D8754D40C3607E185A4E81A58DFA31B2EEB6FDAD5B63740319789D6A4CEE1812808F86F31640BDD0A5CF6CE8C9E20D162E6D5DF4E80E4BB2A21F4B07DE165541C11BCA14D308819C37BEC138BCB0F5CFD6158FD86D9DE2827F7756450B3081A3F3DF94D5FA476C197CD96E2ACEF1F9E57B5BDB2AE590026EDE01FB196A2FCFEB558110FFAABC9D4353F963E42A18653A53442FEE4534C76C8216C11281CD7505C01889395EA8C41017616E68666B1648545BF29EEEE1FB546BE570799862791A133A77AE546F93AE429D77F3B38CC5C8B5CAF9492060F0B9DF90CCB44028F711FE46EA8528B03F80670EE7C4DBFCA1D35A4F277CAE112C6A58FA0F98FC7C9B9CFB691809ABA7956B5E2BCC7F0471310AD13B68105AC43C549E248B12F3409FE371158C354BEDAF4698F388472879A4FC7E7ED5DB54E076D315E250EFF88DDCC74F0D55556765890E1F85970D4ED33580476E27F78C44C676AB7B79081F15CA92AABAA9B8116C6621B280AD1DE6FE4AE9D72439825617BBCF580E6D36F1BDE24A64BAC4E66B55F3B4896B030FE707F253E9054E593CB32D8638851B724E56033E615B5A976CCAB49152B9C884AC08BA1FDA07461D2D468BBC795E4B5F858D03424CBF760A2CC5C9EA5329D663A829A8E4260F6D657704209F3F29C092DD4228357177A3EDC120736B7B4B6C7C60488D586754A3ABB276C8981877F14FDA2FB5AAA08102FCAC33FE9ACDAD913971481190A4B634545A9682248BED170B49E5E4C8912C3DC4FBBF8C94C6C21A0D259925A42D08819E8B4E182C9B1A022ECDDA1BD535093CB57478D89C61EE542B8798B312A198E30A7ABE15043BD9C144605A5FF979B0DF8A403E58F1ADE788607792B93406401578045DE9CF3623EEB8AF24CCCCF63A21249D59B540A8B50276B6EF5D05D1F53CE277D765A8B1F4E4C4A913FBD9CDB932FE90DCE0DC64D94275341BFEE8D8F09571385AF4D34BAA2EA93E521E124CB948E730E57B416784CA7C9B59ED3B7302A5AD575CD117DF410DF73EC6C0B93DD7860C6D769D948E4E99C53A436CC384D60EC60B92D4754CFAC30CB9D3BC915BEE831A79994BFC23D0C033B65C2AAF916E0B348F22AD8FE7FBF96B28BED0D214EB53F2928CD0BE748A462E10B3437180C01F4782AC332D95FF3F3CAE08875C71C3A142A649B2F651CD4CBD3DF19E653AA36BD1FA7A31F5C56D8A0F24068861BAC24A570E27DD5177A5A90D3169D4B67EE69ADD4C7CBD67CAD415D57A10F6474EF0EE298903B6526E15B6E24366CD1DEB244E01A500236F1D0B0F4A2B8216D54F29DA8F5E66F01CF04C991B37BD4A4C1323446205110B6393F50D96F993DB5A33A72A8D783B27B912CDB40344AD8DAD9A5D10307AF822315FBE349E551B2E55F05824E391F261AD0C06F2AD3D42C7229526E7E42156619A1BE22007450BAFE5D470694D8EAA42B09B9FE7A49BFA9839BD770D736D375B7266022A5B55FE1412AF502B6EB64B5D99B929B7086C1EB3C76ED17F9A06299E40FFBE1E4C12E2BFDEB217DCEE7B186E727E447AFEF7FD523E9B05A409DB784677BDF68C77A9C9BFCDA5A2A310D66E3915EFD5C1CD0D0886D590B7D923246459707479D79B8535F0D6047315CE996BDCC759C807CE01298CABA2F38FBD3939BA2047A15395FE47CE9BFF59C3C245D858D928206B41E95853A46144F3B0358887E786EAF4A42A6FD1B4D4A3023C813DBDE7A72F2B8B41DB17AA8BA2F75D00D9B92577EC3090CA5890DA76BE5B4B9C16883A02B67C9926851791B9023B8A45E279AAA25BB1BD77ABE1D3A578AB6CEC2DA1929569753F9F07B48003C59E9B561F10DE322DAD922DB097764A53C382F59E382E0EFC7BB06AA3081F7998CC171E1A6905AB4272131EA0CC370161B248AD8848D62C6E0B1781CA571457E45F6F3469741F5F299C096B37B6A22C5D2A8CE7AB08E1964AD65FACDE9FC32CDADBD218A029C86AD47064775C19390FFC9D2D538A1DA74B87A62779B90C99FBBC430E4DFFEEE4704D061A753794DF77D34ACCABF46C2C3BA7410DF2CA4A2CE17D3B4CE5C7F8F829702B8A4C82521ADFA397D95CB82D390B8ADF0D76B4F15096F259890B67E7AB8D06C0D2CED0BD6AE2FA9B28CFE126D06CB7EBB4B645A42397934771EB09DA7FF3837FB8225860C0880F2A6F7CAA409F6DA9C5A4C95864CB7184DECBC2F5A1E9C3AC5956DCE6295FB438FDCB4E93337546F76AC9C64E57CF8AC0D40DB65B8818F917314A25DBC8E976934E8E0B1F1E7ED79D3153CEE2B853F777577CCD79CB59BE22F9AFEBB0B4B181F71A4239BD30B1B0E49DD8DB865A6C17D43D690D39343A4EED46337ACE8169342E6A8ACBD59A0D36DC823C787C509BF92933D93C2D0F2551433625B6BB03A07CA1EEB9C4F221F33A1C8733B3F2EA6EF2FC8AFB16FE6BCF8903F251EC55F260708ABB55A9CB708CE2E6CBB10CC1E0DCFF23E688D0802297B4FD8D977C57A58146667AA2F1FDE671052D5ADD348DC3F43279C843229CC021A5536C4D9C62BD83A36CE8397B2A76A0D6AB3AD5395B4C0D1D9D32BCB5C83EB078638172212DE456CC0D491207537551C1B4F541085AA76BA2D707AD97F65A447AD1BA141FAE3A937576FD3FE0C633744A8F9CB5D1339FD77906BB319B07316DDF29676961689BBD6933D8A33EC04117DF879420B68C2B9073DBFE35B03B3F91AE216E74048B8009EE6656B9D1F0CD835F0409A84C8859E5B460E8D84A520122B1F6252894F0B45E935BD5EA8B8DF44D6472C2BC8F0F9936680DA98C80504CAFBE764CF4EF253C0EDCB5BB8A9EA3FE9357CED92E1503927BC626A688157C879C012E710A11CB14B10BF8A34DDE710A99B1049631F370DE07F781ECDE34EA98CDD067CCC33E9E97AE404CF6A20F188A61382EB637D2B5D87D7B8AFE47DBDEBA9A17AFD7AD29AA93D7EE7A47D1A8BAE204B6BDCC1D7868BC6265280BDAB12439A3B66D677FFB8C15B9A958E16B3F82DD61B2B16FB9CD08CD2C1131BB384966FC75734F1E9F3C157A6074BAAD9770024880D228B8B01C1D14CF1B4F42A20ADDA86C792DCFE15D4155DF9D1CEEB23F2C165E16858217C770077E492DD5D067C3B56989D61EB645324261A24EB9ECC486BF45B2B793FCA8208A9946CFDDF2E31C23509DF9ECAD0A4B91F2CDFF4F2ED0B46FADA856987895FD6C126F02E24D292DA2EBB30CD6BA5F7C9FD9DF203D927219F5CF569CA7B1A896F598B0524002E613448DAC8A2EEB278B101F0AFF1FD458B8A116DE9D9922808855071859A2EA1F1579E6E4A61AC5285CD6B0F9B190FD97F83137DA22E36B393F04EA28FD26032523C44503217832D60746621E312F6A1C12E096706F36D124A9AF9DA2AE25D552E96DD4239C128DA5491E3D45ECF23E1BA82B3EF44155A7A867B032D1CB9BB17CC68096827EE50F200D9270CEA7A8FCE816410E0B8DB0D68587630354EAAE6215F79CF5AF6D29624ED4A8E2BCFF35D41E283E0AF42BA5C05465F5D3B779938B425BD4AA7AA6A636B1C947B5B1CB0C7732C50CD5FA876A6007388902E7640F4E00A9E75C9BCCD6D720075514C119B28042214A2107B7AFAFEAC70B1BF1D7BD0CF355CF47068F4F784622B73E65DC2EA217FBEAC0A8A99B08226D40C8F6A7082EB22A06A580A5D6B667482DC80786195A84C906FC37E0F7988F74E5DFDDA99A8F7323017AB6E87852A29F83984BD791781C576E8A1362DF1D38E51E117B379EA4BB970374CCDC1C17D9BE96CB7BA4A3FD9E0B920BC3D70F7DAA98CD2C316C6D3459EBF9C6479496DEE2A869D4AA6CFD759EBCFEBD3AD27B97A5954CAB9F188264B380F58DA08F249B88CC67767E5B0BBCA3B5591217DDFE810DDA3F0805691A1A4C5F1B8839C12D8532464DF9C1F1D0B19CCD590DEDF904D3A7AE4DF0EB32972A4BD1B78974B6EDE032E211DC16A83A99108DEFD31191E6CD0AE6F52C34D2079E9E4F7101592FE5249E4E9E74CF4E2B11A9CD9DC71F05DC20C5409B4805EC03753A11EF1E5E2EEC70603E5740A435407F09ECDCAEFB56C510E28C51B4D9B3A50079FB214066AE88F8EE202BAFE22C04E9339BFF864FCB3227D4D897647C6764F9DD81960ABC5B02828F810E76C4E6815F03813263A4DEC748830279770B881DED99890E912CFBF6251AE4799987F3F0731C2ADC12A9F4564E3ED4CD7BC057F4C36699E3FD2E905CA9AD7372EABA90B8F962FEB8A4659A3B897E788FB34E69AACDF80BE171479AA57C508B2D48A74D77488493D92B7B2A8B8A3D628455DD988378FD723299D7D8448712B3A5BD6E7A40605D28A70B525A4B2D6D30E7CD2BB62F1948F8841FDE96037D622CED77A37DB40F5E853CBC073F880CFFDC1F01E70AFCE990EBFBAAA7E4624CD89BE5EDCA004C064E7629A356880A6BE49214E296A92DD3BBF7F88EF3AFF01F5A6CB0573FEDC19E60637C13A527CB6D8BE7F440B551E6897DCB9F0F01B691F5D728B982C75161079B3EB499F4B826CDC150D6F7AE2F86808C57BB281AD0C82D5EBB8531E22492E5F71123465AC4842EE2B6DD12DE834AA0ADD8CF22BDEF4A0EAF56A7CFF1FB0716989CD07B45CBEC5BF3CA632E3FBCBA2C9C2C893672E4BBD2750CB5C5902A39CD7DBB6839B077B19D25E8A45A3718CEBD7B5A656667E3FEB4EAEE5362F83F4A08E6F5F51E72FF957532514595EBB8DB2787F08B0E3D3D1EEB0B4A6349FA709DAF814FF575C70D5BFB98A2166CF77B57F9ED200229DC7650539526AC2660B5B8959B5A2AA71199BA6E01F64CB6E61A323EAB355A02E5EAE110E3DD35F8F1AF1C34EF119F72EDC14A414CAD6DC27C0CE93244E5EA66A76D6A4D7853D0F49D3BBDA398608F6695BC1D55B622F0275B8302DEB163DE2273D4135E727B79031359A9B0E04940DC0BA04C9A903C9BFE00DC2375E9B56F799B47D03A30C95F7C056B8D22A7BC61D54EF1697A4555DFE9EDC5C7657B3D582C0A245BCF095587BF112A2D65B4235CCB4241BE093F42F83E21C57C2A3B851E7B091E01BE8469FC5AD47F0000F83FAED1946F1D1D64BF1ED57C27FE66A0994CFD2D7E9A628CB3ADAB67DB0046C5430186F93228D5AD08BFB465A75EA6AC027F48941474F68E0575E5DB4C8AE29637E65CA9CF41F4404B27EAC6C5D1761CD828B3D89273BBE5BB49455EC933969D0A34D622D66CE714E632809FD6A86BEAE7C9B7970D22C16FAE4E179D88890A04A9C75B499CEE693638D306FE4262C7672AEC4A657A96A8C6E8B689B8085AE24D89781381A645C3E24FEE9DE0BC5687A8A0DCAE48217537807D0AC338F343DBF7ADEF7799F8F88C587E6119B86E7660643F3D2FE38E18494CB2734D0E6CE392E6AFFB445A5E1EC562222EB97E61C5FB1F0821542B9C18F97C705030082D1691AF03ADB8AD01CF38845B579AD491F26350E7B6FB50DE97028D98281BEC611C16C0C3F372AF5E7C3CD682A2DE0415F396BE9178CC47A9967C68994B21C3B6F1236CFDD8EBACBF7FE01FBE5191E60B6D751DCCF45D22C07B6265CE422688D43D8B97D3D7C43BB5F1473D2B5DA273ED97DEC4C1E9278CB36897DAAB6E76399AD39B50D2727531C092E94A889525F5BF212BE00ABA878EAF190DD8314AC22E1DFFF087196FF2955594E4F0E4FB888FBF4FEB36F7EB43BAE1E7A988B204B8CC497306FCAF2AE7549261D4E881A6DE99F238094E44C95EB3BC3AD9FFFA7A301E5B808BB4B221291023410A997EC25D0C87E12C2F7EE57472299A83596E7A067837BE07F656336E5BCB7F59ABA4E80AE73B0F2C6B16B5D1684F08DC66D56B9C528CCD25D524721D2FF17D594E4891E64EB5B31A93F13C0004B3A290D96B2994919FFACE7856DFF707E259C026B746B0C33B0428520656430609A1BBCC04DA0631AD16F916E643F0B06AAFFBAFD77721125DE11E6D29D7ADBB043C344C74BC26B51C6DE61084E72B72ADDBC7B601E1FE0D2637A83F07AEE735E51769457814432D7DF695D8FAD72F29F4A879D26D0906351719D50412ACD968890E7EA1CDF899CC633A0444BFFF93C604258D79C84591539D83C5FF43340190AB64A77BF311B5BF5D73B51D1C0767CAEDEF9CE0EA410EA6116136247BF8D4535FD2CE151BEFB2DD7D6370F7A97CB2CCFEE3D9D85DDDFD3B6DB6DCC624CA88D1414AF7438B796377D0F3449C3A39501E024F0920AAC28EDCB597E096840C015BD78D1971F28C769422F2C6A74A6B8C1A0AB747386B93AD82AAEEC0AC64E7EC401AEBC1E12666BA628B2F48B17A790D49E9DA9C9DEACEF49A0BBA8094BF85B49D32204979D0BF7F5622F543A217523CEAA01E366F00256834FFC36D038AEBDB9E690AF4638F13D65FD55087B73B4BA018C45562AABCA7C29CF399D94F77CD24BF318461DB36368E6154959E28FDCB66872485A3FED5F6A0CD8C429D43A0937C045A8D645A49C7EB9175C9F8D4DA484F6281EAE2AC835A4F38B5F3EAA8C786FC10B1ECB8093512389A29E45D6E9E3D2747279334933DFA930194D3F732B318A17AC10D1C6404C7B991463795B1BD0BF2E556087EA80CAB1A04CC4D007BF6D3D7805821873FFE7FCB22FBCB0C4C166B04FFB8A4AF82F4E94DC7A987728390F52EE0D557DCABC28FD6747C145BCB66F15D5886788A386BEA17A2BFE05EF87EE7C508B14F5861015B09CCBC466326395488452C90FD6DC06B9376AAA07CFE3DE8719FF61A2AC33B03A3FCF5C42897CAA451081618BE80DA42FDA7A732E7F1753F0AF9677DA03073388D3D697E870DF681131CBBD4348555551CD9709466368B2553FC6D47FDEA7DD5B88F4DCEEDBFE43125BF95C6B2E81CEF6F5D6EA8D89051B32EF7F3C0399538C3B487A48FA0D59314B1BCDC0417689EDF3557A7C16AB00CD5CABD8D52189107F12D67D05E13EF4190C1F5465A1EE99745A461481B085EB237A24F4F1D30FF16F8C53832231903E1ABBF691185C94CF6D5B2AD5D93D31C2D57B3F1AE97452EFAA3A54482A8B90761301E4F6756B5598AD82C7C48B7411EA0CB47F61C14FF38C832796E035730735AEBAAE4E753175DD39F20AB6CD08CBF85ACF4D35C0EE442A1D893DA38D7A448F2CC6DC7B52E5AC251BD6C03CD5833ADB92157E33A07C70E504528A723FCF17CF8E63747A2C908FA91FA00B2C8DFAE00F0BCFCA3BB477A798EE921DA8DF41403A2F2BCCFC1B26D9FD746701F32D6B4839545F74FA4DAD2A18617B207E9EC6D1D76C593FAD784093F066E4094D73C20B524ECDF098747858DC103AE7661A25F8B3867BC9413FE4BF12615AA59FA5D6FAC2E323AE8E0F6F22ACE8F9CFD23E1FEE21EAB2AD54A3ADD15C9811AB5C2B5FB6E7E56584625D9FB762E45B7926CF8E72EC93CC211C8DC2F4A28CE2C6D38029B163235923EC62F3A322036C5C883364D02627B4AB4BEE86629A0678A641384D944B58229C1364161DCA1126C87D47EB93B29DB9C65E0F105211272D15DADB603C3CFF7F746A299EDCF1A63574DD5932614250CE7D85B5E112CE5895B2D1C1B534512F99EFE9E0E22BF3A9B813B55E2399C39527B992A7524DA3414697EE8807D854BC53DCC889DAE5D527673F5994E91036A4DF2EC1BC056C12DB966DAF5F1902A160F41CA5BE0B78E4E5D175A72A3F9BF10A6147CDC8CE5BD50BAC2BC2EB3048680E02231AFA3A348B64DB98F8596BA49CC88224D0726E7B4C6D07DA3F55CC8B6F36E5A3AE4E8BC142E5DD388EFAD17A0D2F6C9B67A82A5C78546787436751ABE9F7C924846BCBC6AAA62EEA06F0C28704944E3A3468BF04154CB9240D8719CDE1360048154B0A4A1ED19C0489B4B33ACE3D08E7534F85884E5BE0F6F4B57A9EFBEF2D5B4FA36166746993DD9AE2B5F68EF76FBC7A1EBE0A174C76D77382954211D9CCB7D24C2857256EBD4CDD2B91FFDEAC4668CD51187F24740C1004323CC932EAD329E05FAA940CE1ED6CF778B0FC7CAA88331FB8611254521CA29140FBD09D1D8EDBD4F5723BB237FB8EB56B1C9882D678644F1F7A46DBF14537C63BB0BC4E05CF97065EFEB5EC79D9FDE22D2D8BFC28F4732EF94FB415E771FCF85446301EB25D3F9B0A8C9747FB933D70D4CA16177A2D883BD6AFF3BCCDF2D5E40F7594AE2A9CE40F958175D450896733764E17FD2935C70DBFC3B097FDE66AB8B269ADC1F3A8A6DE49254EDC5BB90F20A4614D3413113FB75D028E9E0A793BDFB64829DBA3D03EF02735EF1FDE45B26F9B76E83AFEE61C4535123BF409E131A52EDE599B844A086B55962BDAA9C277B95C79E90B3999502C28B60796F98EEC4784D183DD57CC86C79F15BBD90B96131EE0547562500C419559DE31EDA7EDE89FDDF781B38E0F7095592B9B7B9671152202D2BDB73A4B9C1F32BD6A7F614D0F2A8EC5134FF6B409B786C517362FCF8F7B475AC73DE6508ADB4C4B3EF8970838C746956F1BF31CB96C109D31B113374ED1135F6AFCF4FE2324A247E55A502D635BC2B109C2C8E2815473C3CA389115FAE82F26976C7911C2673D833113D027EE9C13AAF87A010E5453B97E1399A65A56448E7D32E84F617960A3C733D88F8AFAF604F20F76A6A1A036FA3E1A92A35AFAAADDB2F98A92BB93BC8DF10523E9D25F372A8703368E45F6E110362E6D611E7D1A272E6DCAC4FF0238EA489920E2D5D190BAF394C371D2E65A6421F3E67E1449ED7D9ADF33EC73A2398185757FAA2565D39D489928EC10A531822EEDCADE8DCC5A2124F4BCC2485C97D0C71E83D21408FA957BAD9E184BDC687069AAFE52EA2F3989144707D80087A6C8C29B706E2EDF39A713022BEE281C1FB86F27B64C0BACD2361AAB05F640EB27DE192D8585138C079CF32D6848767C87694300B7BB20941CAEBD483C8E56A72FF628BE420E12A44123DDE85F6173E49B0B05A2FE0DA79D56B3B5ACDE24CED66BA191F099E689D9CEC2CBDCB741876CD7DEA5FF7E3BDF6B46E0435508306F0D14B557B3DA5F532B7043D6946A196086C25AEE2CEC575FFB656CD6743FA78F1743314D4D75B64C0EC7C2AEDB0EFB3B07BD86E59A2B2E6036680824012D232652FE6895D43239872AE174D244DDF6EAB089961985E59C207D1917482BF3F2E520769296EE3A133F898F0B753B3E5DC560A7C64494BB323C0583FE4FF2E3D607B69CBF13E90C694384A9DAC6548652F6B03926187DF7FA1926D3BC64C0C11103851FD318A1AD023C8BC04880179199C05EE9024F906DBE9FAFC5E31265364EF8820E5C28D0DC1556A90329176C098C2CBF7AB983EF1A1E84CC537B381A346506525CBFE992589FFFB293CB47BFCDBD685246BDB50CA3FA847839121130C3A67AEC32D13083C0A7F0FF46C26E776983376212DCE17A017CEF1BB09E7DC01ABED85268170C395125408AA988F48BDE4B800E6C944BC851E83CEF9DAC06FEA9FAFD1224C61E9CC5301BE19BB868866E2337368E8B7B8E72EFF3489200C7F943BB503D92404B1AE2467EB1B49D135BED031558B639BE31E163C99A577E756513EB06CF4A0016FF31A2A17F77C1BBF46F9FB590F5C9CBBA58994B35282A9EA8F6055179A94BB47A24C8266179D4E1A60390B50C2F9F499FD54432AAE6DE8FD6B8955A581C2BC3D06EB1EEDDC2AA0D50A652A42267B2ACF328E1CB8863607B1D8896CE8BB6C5D14404454797E6B2790F4C1EFEB12C5FBC281E52EC3037E63BC5E277BE9DF2F5D537D44CE1CD4BB45EBE4C60FA2F960D70F7A1A8683DB50B92ADD4A758BB7B574C8DFCCC761793F9948E6600D530ED75D001304718992E474DD9861BD4AD9C85AA89FAB4515C5532854ED8234608012CAE2652D64CB56C9D700476FBDEE693ACDE3369046BE5183720200D81F579F6C1BC8A6094AA5CEC1B2FD426EA7BF50B6540F43A1C0E656AFE71E830A1C728B52D4C5BC7ECB36F9EC70963809BCD2025D92D9F7828B6C62F015E1435B85B0416FB87FB18DB10470063DD6611A28148F1D9B5E3D66550E2BBE143FF436A0D48BC4D68369A72E56A8165643D2288C57A1FCBA856D250A41A7CCB8D35621ECC64D7A71FCA22F69EBF5E1EBA73BB0F19394AC5E5085E6CB0E25B7FCCE6B832470A80220AEE721BC4A119F1EBE9DB7DF4FFCCA1FBE8DB499E2B01C7B99629B4D783828D1006AF9D7DF683ABDB3D173B8367AE918AE84A408ACF84714C3A9CD4F4D78C9AECEDA4D22E262C40E588AAF9EE004440FD102C6B616A6D9D77688E49407A6278BA19F2294252F172A12A8351FDF79277487E2793BB3CBB6ADB476D72EC1C2D9B5F472EFA1DAC7C199C3D56362B526525B3537FB67E924E9375825B9F5AE5D866865C16F943DC50AC8A00D980D8025ACA2FCF488FA3587B17EB18E091892789BF72B1899AC0EF4079AA8D59DFC746166245DAB196801429B8B8281931B796FDAD0B75E5D113D817C35CB13D29BE4B8E75C369AD981E02B7CE8278DFBDDD8099FB4F6F7BFE95F6FA645BF841C4F40650EE4511CF1DA7F764F32FEE0A4FF11B42BAF406A61F6564F20C1A32915281BE3FD897D82837E084AECEBC94D676202BEB858A9D7824D7660590B2DE332110F2A83A2377AC35672154D60E1D78A0E511374AB0D91463EC3FCCC52B593A9B04F29EFC7EDBB29D79E052FA8AD33AF1EFB1D4E17EF94E8EBF654798A6B5366060231CDE9208B5656A80FCB3E703F2C5D5445C7FDCBAF36A4CCCAC24482DAC4F02AD64A5C01D16E222BC0D23C4CEC3C2AF2FB8CECF5970F55AEA96E6683A77F371FA73CC8627ED28843A201008AB8F50FCD79AF31064E6AD53A8784B8B3E6ACB3040642706FAFCE0FA3981852E521B860A62459F7DE932BC70817EE3DF5F863D32D3463225CFAD7BBECD19BC0284EF3BFCBB1C13A64D1B86CEFA3A66A9F0A4F6A799878036C41AFD7087BB06FD3ADC0BBB0C55FCAA25488F10DAAD7F0BA883028FCE814A0F3CC05AF531CCBA0948A4BC63800C5E1EA25A62F656C9354ED90CB88AB4CF83283154EF6751DCAF3F19632BF5E39A2751CA680305D442334DDA551B47CEC4EB312DF3F4E3C186B5B2C0B8A58F1F7C492D0FA7D2D3D17AFFEE5F88679D756E2924B165329D89690C7238747F07D320F9D3CF66D93D36244370414600C7B2AC08EFA749F8D7CBCB7A519A5B6AB6AF4FC749F0B4398A8703EA5CB865D997E28B3D0E9F59C99607791A0232C542E459F3109590D051C6DA9C17DF0CAA8EB755E5390FE9DCE569258F48C51A9E658398F1E1481410FF9CB3F521CB75B5BCDEFEE1E1B2A143726CE04C55D51229A6A3E52A1F4C133BD0B5F42BF856A8C6693F207DD148C48FA7453E6E1F708CDB7C3852248A9BA8332BD5778C20250895321BA78DA451A4B467AC3D0B01D2F8269E89C8EAC90A2C22D326B3DBE3139196BAEF87D781E31B218376FF41955CF2CDDA67A0FBBAE6B4B8FFEBE73D271B85787264C86578B7720F0D441ACE26843247E63C33B785CAFE1AEA05EEC774DED38A9629DE39DBC7C48A429B4BEED0255052597F29169DC01DC5DA133A81A344C779F4C8923317DC5980084FD768ECB9D6E71D88DA3CFFED2927146B82EE0D4577C99ADA44664CBFD4B84219FC5F8451559075761BDDD0A87BFE4C6B3A29D389BD493FCF8A60B64260008532920DE8FA0652189908FF80FD5F81C9CE4A8A767D67A38475F04F45286CDAE020164E46D5A1BBBBD09FB6C9F6E6CB222D237534551B04B3AEAEE097ED77F62078102489BD6E9276AE562615FC85EEA16323A6EBC4B14404F2C8B6DE20991FFC0CA0860B955349F09D48C13345BDCF6755DDDBB1DE156BA6ED3FE6A3E89259DDED0005B283F0C04BA4ACF3C7BFC3AB407F87074025CD17074D064E2DA0FE958863ADFB7F9F65B54240C3A69B2EBEA1682F200BB5DD25230AF64C60858207767ECEE3110E841407CA80E06BFC9D27F5B664E1CEA9DEB8F22DCD180069926A772366B083D896BED131BCDAF3C15962F5EBCED6E29E0F0E40BA2C1B0340AE1926F9CDF7F9DDB4C0B8AA6CEBD280ADEE287112E212FC8B7683443D06EBCE7174B217EF775237641413305E301405BB7E057C16320A05A1909760177F431CFB0B0C6843AE58E2F9F0108068E15C279BAFD2EDFC0AD8AD9D62F813387B47E50C798D952D926B3FC99007CB30E0BB39046091EF7ED3010ED43CCC8DCEC1556957936ACA48E54196797002B81E6CE2D9C48934ADC690420745BA82F6C3E5352DFF979916381C6A336DEC44B7EAFCE532EFE83D8A2967CF9501B08BC10C37A75C3942037368A58E0F3FC0772146D97E104C6D732A9E66F3F13FA4290B6DB1985FA77C45C95A8CB1BE391CAFDC50FAB6DE18A59A6010AD93AD593A0E0C41736DD1D52F8A7FFD457B40EE518C128894958394C7A91F26D191208454BC6462D47926786ED79C0D770FF4BF8A9341FF63D22DF458FFD7FEF73EB13CA33AD323C392125E3AAF20C9F27F15E11D284C2197005C053FE8E2C7EF9D7C5537ED732B03EA0CC482FB0370A137617CA522B8A8B3831C97AD5A5E641E358B9B824D7405E557BC48BB62BB54F5B906C16D2FCA0A435B87EEFC9CB550321D7900C2B4C43E8331BA03F25ADA3E9D4F4173D8492F6B0D533D7F298CAF5D2D510584725E5236C572B758B3F4AB28F5D6754F26C04A58B74A4B33E94FA3F583ED5BD97BB5B2472ED8E7674467841FF2C0BCE52AD67CB5236AB2EB8207A5B1BBD9645ACC54170C36FA4D72118DD300FF2FDD715F986F47D38723FF2485A88B377BFF67895C1EFE5A603EE6BA2B43257A8C568779B72F9E6F9083EBED9E4D4EC3E8956981929F53F63024289FFC0EF28E87E68932F1A95CB8221577E2D718A50871DB574B9B1C2004FDC04A265DD74D0F8F3E2971FA7976241ADFE7A1B20B55E47E7072301F33002A47358DC6069252433AED683820F2AC7BDBC3B08EDDFBF17D49334F34406C95C7C0F4EDBF0714B54177CC559E5D81DDFC58C8F037175EF2328D04B5CB36128679852C2673F6A111A1746925D3BC398A7A029260DB36274AF9A17307A4EA360E7DBF5A26EDDA512E48E2254EEBB584C29A7AFE2CCB8FA85ED83D29B11D7A8E5D2A850CA51384C3C499967B169FDDE2351BDB1DB271469ED8CD782A1D4B7AFB114A662A8898D43B1B522E91145660A008DCF59490BB582FCEA1B4CD19B6D0B317F4AE647E253C4F2EF1F78A7AE2DDE663622FFA08817795CB3FAE8828EE39F9E65493924E92B441E06FC351C9ED537C79AA89A1B20BF8E7798DEF7B553157288D4F0A25B869655E16A56C30BA570BE30BF551F2BF1E90971BAB66B148609680A211C20305056F9E853FAE7A603C27ECE20D2B2FF5ACB189D30A87F2FB33B6151517137ECB07D0E443A04FB6E47B58C86120C9B6E61FB00975A32F20F2D6E0235A14DD936F967CCD2A9E3A7BA0FE7937F862AC8BABDDBC9D5EA049366E2405976BEC0F115784E322F8F59E20B6F0546B578276166A31552E910053D935D487F3253DB2DF57D7645DF1F0268AD735FBFB9AF4A643976E9F67DA3F2F5D359C136DC1285CDA4D02EF8DF5DBFB8F06C2785201935773F9E1A0AEFA89844185EED6C96FC152BF8209375A471BBE9FE001CD4078602C5E40B70A7658EC25864CC6A24E2AD3121B27D7352FC482CA306D787A95046EA0E1EF6471CBCD0860917D1D823A4534674DADC5CDC63160091ED1182AE16B03018DE0B920F9855354E215F3AA10A69A4A2BF2B9BA54834EB410DF6833176661535E4868900D5804D34D8DEB7976E43D08EFDDD505D3E6AF1F0D6B4C6C5EDF1FAB5C31476379F8970453308D974089FF1F6C6089CEAB99ED4AC05C292AC39C612BE560578ACCB92CD10B54D14A1A8665C567DB0430EB1ED46597FF45B8412988BEEF9EA514A6E27B68E2CD29468DCDB16C29A54879F568C493A7576041254770031B0A3732BFC581604C3663312DF4B77F0C45D2F09F9628ED162DC8C466E03377427E1323432FA0595AC87D4B202C702DADE8BF20FA88B0996B03CB87FAAB39327C51D84E845D40B74BB1FEFE8AA2708C2BB8E8CF47C17028466D833734C19B23B64C51B2A1B6C440510F773F2D3C25711F73A9DA486F384D244180D84761A47B79C92C04BFD7D8AAC3688D29400902FD22C1E607F05905F898E5349D5308E684885D1833BAB0D0569DD7BFDBAB1595877B3388ADD05753CE27EE6F44742A6127863756FCBF301F9D6E1CF6E7E346AE7592BF16FBFC7CE44253A9ED2FA7D8C1E480CCC3DC786E377418ABA2105D83FEF314B6A4160A8F34CFE80F789F24487C59D8C9EDB21652DA04BA800D735D7AA2681616606F48A01C9CCB6C499D5B7490A5D80622D708E0BAD6A20233235A15F871E9551F4CAB7E45F0A9DBA312F2C1FFA8A698184196F22A920BBD478A773E463AFB82F2F323B3727A78AB9277EFD530C65EEDD707CD491A9AA7D0B8D362AE004591B112D0E0AD48B0B6435680560EA34B38800517193B6EBB5CD0EED4CF9D70721E4E2B29D139EE7A9FB931250CD6993F5FB4A87A2C5AC88FF4F5114C5694B1D792716B79DBC9A7C9DE0B9B7493EB273230FEB000F069C02C7D9972793F34D02B22274B5552F7DD5167D187DDD2A865C21D560BCCDEFD764D253769BD132AEC97CE80C8B0A935F0F2D4CFB5CC8222CCAA2A7243D1C4509804DA8FC3D98D957C7602E4388D63C8E10EB065CDB51D98278E6358155AD936F7972048204643A14A4882E9241A28E35CBECA9772EEB5FA9A7CA6F0DB3A04B51B920617869CC565AD992FFFC53022DE93CD6E844BAA5E7883E73123B371309F3F066C61C916F9A3DA033AF3C16B28614131F5827286259A1307FD55AE15FA47C5B8C9C4165DEADA98DEDE7869234E4D7A22482F06B2290632A136CA677A7BB4E53AA3E1170D66BEAB2916D6BB2C6A731089A3ADB01346F45A940BB9A392B14E5BF47B749F74A19396116DA6FCE5CA331D990CBB9532D64B9D79743F866479515F5043BEEBCB59C45BE3C4C833CCC07070E5BFD410B21087F3E9D67716CC5BD10EBCBA6D9A4D88CA32347B8D0111EDF3CDCBEA7D27EF0325E904FDC315BF7EBFA91FE999739D5C8C12C3D569BCECA56EC72051356799CE350B29168142C18B2387B3B344E086077B1D4AA0D1EAE77972A1C55F2E91A6DDF8D5B0BF9E3DDE3F9ECA9A4EFF5141F8433D94F0C455C3750BAC7514B46EC799E167283FDF8AD7BF7DF67ED10DB1478D69507515D6446D511DD6EB7A27AA2B6A7EEC99BA3A44A8AE75E0D6CAF10AB8B7DE5E330ADB9FE2A940BF367201A2BD906294AAA1B83B0BD181CEDA5EFCB146A890993F4EBD128CD3C6C9E56C28C4605D9B67F553BEAFD69AEAF7649C5CD8602E1653E3CF535308ECB2C31E5E573493158C994DAE7FB26D28A2B1EBAA3EA4AACBC1D7528E282CE2EEEE61D7B2EFBCE6754C111E44C911A4C9D004C6DEE252802FD8A6CAD98EE9DB53F750141A16BDA564E4A38722907ECC22DE53A8A92AD167FADF2253B684915A048A80E71FD56CBC73BE118FBCEC86C0772A86C05D6ACA1AA01F685692CD8892F20536F9E546E4E01BDA7EFA722DD441EB1089B9FF916BE0EEB3D177DC80598B9C67C810E361F94180B0EE81052CAE9812E95B00175CD9DE8E70AE6D614CA26A9F7D4F08CB8C8AB1939ACF0DF5B0DE6E58DB4A09470AD343A1EC0022620EE9A6D3515A9AFB875C41229AA32CD3994D00A92A769E6CBA0BC3A4E9933968BCE3DDA58EB3016875A6FA469863734C52569C62168E157FF1228EB62CB189D63A6FD9713351FB191FCF71EB2B65C2D8C645DE6C95A1BFCBA9D90F6E3CC4A0C120FCA728FC3E1696A12D106BFB5D9AB3AFAC77698C08913C72DCB3944CF83909AD02910992D3EDEF6D6249785FF3600FF89C1EDE6EC0BC4B93A8788B4176A198097D50D95D3C3B73E9510B0E5F656A8CFBC067FB701FE2C8E39BF3530BA40849D584EA51B684E210F0C188134D7801DB92310147B20898528A510E84FE5B65FDBF0B711A8474D29C8C1FB0125F6FE939526AE1C89D4E0E388BD33531142FB6700C3ECA865F974719E57A7A744271FE16C54AAB3D4865D449781CCFFDC1EBEF1B6A8DE215A0C99E87444069C4B5170A7CB3CAB6F0D7150BB67FDC1C90930FB697989DDA3609230CD06DFADAC75D6E09D83EAC8C7C16E4DBCF9BD5556D9625B5EC927C275B68A973E6E131B49F8B16913949C290E5DB45DFCDCA7CC9094C6F0E0EF228BFA569AFA102AA02D44F3CDB673079E00EAAE195CBEED936D7624A140DEAE0EED002F3B751378989CDC6EE892CEDB15F823830E88D56FFE9B92884E3A5B871B09080392DF46047008A49DFFF10D9D64DA0608977B6A409DC365AF23294D7D95343F9E77834EB663FA6BF6F1F6ECB40E1F535412B02B841DF42FD65642FC23DFFCD427763085471F7E185306CE5A0D0E5FAFF30F0CCCA9E8DC1788D895989DCBB45F4AF8ED2EE9AD1E8E230CB9D77A36BB1D25BF54194E9AFE951D935D38D783BA66F75953E29A65A44AD8D158567D8F791D6FFC16BFC5F760458BE1444601F2793CAACCA925674B30166B801954003A0706B7EA05FCCD797F68CFAFF1B7E6FD85230B6F33FF2DEB39D27AD3B4787FA378A3118E2765442278EBA561040CD4EC39107D639C98DE5B4796A504EDDD6ACC6885F02347AE5FCF28B92A1EA1D3AF83DF9E7511201F5FBEE65746E3298A4502B9448E243960B5AA7D19D3A529DF9DC550E226161E2DF5E071434D51EF2F45DDF3C1004F180A152ED6243D3543717B4B8B72029C19C7AC9BECC4F273AC8AE3E57E3874A1D7449A27ED5EEFEFDED522C00233A95C58D75FC9E083D3FFF77E3DF86F6C8EC4E4B77990A8F6E8D3AB85876EE8311569AF28EEDA2F2733CF90AC2788CEB8979B4AB57B3D69DC01E08519AF3F8DBA56CD7166955A7A805D32F510BE61A84658CCBF8FC81906A2592F6470D80AC834954013D8C37C3CC9BA46CA24F8266FD2667034AB9FAA44271E37AEAF917AF2FCEF520F2A676B557B0DB8A9880069FA0FC6A786C9E2B699CA6E02B803D26CF4DD6BE519C4AB642FC00C0356CA0EEC076311361125B685BF019D9C2C1A0C21A5C5664FD851731F7D49100ECAA9C0207C99FA27E0DC56ED22D81C11972C54A89FF19F1C1A7C4181C0524782741A2B308C89A4853340082F0722C887BA3780623E4004BB3ECB74F7C3F8F92D20DD95F6F2A562B5B106C4AE8BD085BCE15D9CD78A093CAFE8B79F9385DECD050505466FF634C1CDE74A03F6B0B903FC33FDAEECC6C2FAE9D7B26D33EB41CB382328A083F954664508D5F9D176EECF5C93BC635A14726C379E5D887DF0832BD5459E13299E559AB030D14AD0DA5AD7FF42DE9AE68A4730CB5C7AFAE19D7549BE31E70DCC2811EE62B1734CF877D3307BFF3D5B3D70D0203DE2B7F7F4C4853BF9935F4F96B96E3E93667E0EEE4DCE6B9F0111F09D82322DAAD7493DFED4660A7E989148079A47C80E0ECE3DC7F5465B550AD0C7FE850ACD88B1EB0DB40F87FD9E18D9624994930B5BE9361953DBE68B58AB2A40919F3C9D709CB60160E1FA866EC884F86E0C143DCE2F103AA43DD3442E0F46850501E20EEEC253C113B7CB784B1233600C53DEB4854335102DAF9AC45F5C07D038B814B83AF1F2249FA59D11EAD2AD84A772C5E1779ECAA0B68C1900E4BE313A569D94CF45A52D3083215A060D3CB01F66F2F753E1FAA8521C3C51599AD0AA2D2EA061281AD512703C8FE17645B7047C1D828CEC8816B6248AF2BFA43235A43FEC1FAA7B91B55742BCFA4948BD75347882BA2E13B5682135F31382C1AD460F4FEC5ED19961B7CF402168A14FA0BFE09DFA01172BA11FF730912E033F98E3C34EF64499E1FCE8E5160153807962320BF3ED08DAEE43F4C5D5A38BF86CB7899B83CC2DDBA641EAFB0C2F37A484886A6A078D7051AD3BCF91D8D0FC4D565BEC2E484E3B31229007475936F49D9C4229709CA606192C1ECE9B966664AD520E04F880207E60F378A039B51A2126FAEB82AF316907BF9AA106D61C71E4E027F7C5C3CEE6C422FD107CD49199AFF0C325D5AAEFFFC3CD03018304C95136812A007BA46CF9C7091B058A5E6C28EE314E6E08A461239BB4F9E89C139861F7FFE603138A4179ADFD58714D899D19A037866D3C9CE45F9EB51E2A77CCA4C73097A9DD277BCCA5C89D136BD860CDC8BBBAAFD8276F4639E7B11E1E229F1AA7BEF83E725CC3210926FA1C5E9FA952B06C266D40689FF9EFB9CE246FBCC342C91CA57F4CEB9D7CB11B2818838C89D7BD5A23536382305BB0E478788B81E25EBBC0E07422B495A2E089C73306BD0EBF10A32D5EBB06CF5255C8A844D0572EF40C38059655150D77E29BB3A205E4EAB2B7E0B8CA40FBE093956BF549411858A93A3048ECF8EBA1377E6E3A88A90989FDEB8C62025255FEA0F46B15D41788BA590E9FEC5C9F28068432A16601744696173F7382E9B63CF06DC8C3093644A1C63F8D8678CF3940D0E57F1D91B73F1728DF738092EF497E5914008D00E532F3B4E1C817745854F007E397B5F5CB88E420D35705428A2B3035ECE3324BBC4777A27C91026CD27B47917D34AB8B48D4E76BB2F2F97CE0C59B923049E1935EC4373A0999F607A7AFAA678A38460F6F36D019D3303E593DF444D190548FCA0DC0F9B60586DEA93745B1E4B7C51AD270D49DCA9750E1F5793387399A006BC57EBD3C6D972FDC95B5E4AB6AD68E1A9E5839C28BE097395F6507FBE2BA06D7CE9DAF256EEA82D2FB94C4BB0079347724CA24C1D3173A211E0C3C0BCBE2CB5A3E5E0B5827B29251C7E0F542C8BA11C0AFE604D9E817040C5E1402527F42204DB1C06861A3697D60992A457AB88E167F80A418273A91CA97FD0BFF9901DDC7E0CB36C9473ECDEE185F96CA59CFA710999ABC92740D8E87D29373B081118B7CCA4090C97B4D7D7DC208A54F24B1EBBDE3790473363AD94737CBF4C1A64E96138441EAEB43206761DA8CB1FD1131CD0B73D92E0A65E812D57723DC56EA49CCE66B07232BA539CDABD5EEFC1275EFF071A59FD3AD71288686D95D1744E9344003CBB7E8A772B4C12BD5657C4BF7DDDA6C4E4C235C27CFB5AFD8842E1DD72F4D98489A5EF7FEEEDCABDE0DEA07A7113C0683D147E7E6AC626556DC0E066E9BA5CFF9AED35ABCEA968EBF643D118DE57E4E486551E7A5BE3D47908F923F58BB9F1E68AEDFC6156FFE90075C56D563D197A1D39BD167E431D103270735A1B0F70A84E8AE51DD86693A0A22736F98D01D4A0D6B0709B30FDBA4BA45A88EC2749739F947632C4B3B0888D35E963C26F37C16E6A2EC8A76B4D7B9AB75F386D6F968964D84536CFD706A2E1374A1BCF773D0D276EBD1617291049D46742B1111588C7C8063E859E7C295A5C047CD669CE56E7FE9AD8CBC0361C9DC68ADC727F3264D453133CD54BDD415F439DABB2746EC265BA8581C0E30D73D0409AE52766B3E0604DEC7814C9F5348A719B8716213C62CFCD3A5B6F11406ED1DBFBBAFBF2AC77751ED00BD18B8B7B811AF671CC7ADBFE3D141787BAD1FD6E03BAAACCB3A9A9E72A5B04C702E74413CB29C7BC71F87531955E9C31A81D2C65EF68740BF66D0453AFEDF2DD81FBCA8F55CE7C9D1967964D752D3E9E17F1256C5DF94A16019F4772980458FAD076E94CE4056BA11641752D7AA87B68089FD28D53ED774EA108028291889E544A8636C41E69CB20987843B3E94530E3310DCC7AF99D533CDE0F4573A14DC077E0F26BDD1C6DB3D7770170289A2E2B4857BFAC37EBB8B82528933244E64BCD3A9F530B3177D69611E3C4B222F302B1846CD810A09CACD0E5AFC0E5DD539BE9B003A0365E47C13558776D050441392152BA7F4E45438E6D8E9B52E013528C99C09F885258E5EC830CA9AB2EEF54D3497915445E993982012E1A56FC4D52C67463E836FFE5A0AFCC137F72FF87A11624AE4B81081FBA5A47E7F7C1F6D4038F50663DF63F08A7D3F812850F7E634FF7930A15BB4788E4C99844DACCC113F7940C661F04D2BE396E5DBBD9416F8B7ED1FCA798DAD4E0808AB09B152ECD5528E72631497B48C36751BC36332E2814B7E132B241D3CDD6512CBD041E5F571D65773E1A1D9B08308118CB6692409F5D4A7A2D04E42E404EE0CBB1DEC95083FAEEF9FBB3E358680B25106AFE63A2146F5708D99022DEB6955B99F815052B87D7CC7D4F7C3C2D49916247CA5244222A566D578C53A2D775175AD114E8001E1FC9659A4E2F3FCED4A0ACFE8A217BF73AA0D16E11B8E07DF3D7EFDC679D58A8154E0E1F9F41411E01C8E0C910455AB6AAD4E3A44BCF94233A7E0AEC8B195056FE71FCA523E7FD84D915D5ECA8EAC3A0910E514F1EA4F30EF9D6BA772C863B01DAED0CFEC604894F0F9E1A9B7544B60A2E6C661C7D9C571F7848CE4E1BBEBD8C708119EBD66E806C52677840A012ACAE5D13F08ABE2EE61D4EACFB2312C0E5F8671828D7BB6A9AA4C1B5342F38D5437772AAA9FBA6EA7E1D108A971F6C27D86E8F4B006EB5C1A396F1CA351FFA34896CE137365EA4919034F445631E2A86BA0FE9EFF4A6750F81963062DEACA51D665FE85B50D82B0C2EF9199A7F6A3D6324346EF7494F434D6782C7A7F0385347D52B1EEC4F59150BC909161B28D674B25DEEBB8F47910657D25D3BDC52FABEA2D0AA3EA34F3E1225F472156B39332E60A5D6F4AA096A1EE3D06B0905C344895243A01C6F1233A939A54374B077F71B4A901EF2E3446627113C22D9B9F56DBEA4BDFB8665676B952625E9964128A4A5897EC9E37D37644B2324CF322038F322F7B276D07D4638F1FF662290F8CF12BA28F41E64FB2B4E70B8D5981248D826D85E57FE0510D7EA33A99584DD8EE33F00E52F708C379CDD6C2C1D39420DD1937CDA43AC174DC5F1C7FAF5D40C44C7741A98897A258C5F54B8818E740D9026E5130849A5F47EFD517BED1D346F7860FFCD839D42EF59E9EB3BCFE24B378D5CEC0C479D41A121A13D4202A52BA686008CBA9E13FB36357F0BFBA2761D594A36A3BCD200C47B2CD43A0120D1EBAED813C6729BB9296A83F38E4406FA9E0248DA6C475F4A497DDCECED02655755C53FAF87A39E31899C17FDE0A7C31655178FE7D90B5C07911D7F6BDC37265880E3261DD2EC43B04EB558D54E187DDE06F46CACC37BC1476379EDC09E339F3336EAE058FA794575D134AFC37D76C27844B0F530EF06DA96A067CA8B7DABF94BC331C4783741F9DEE5AD6CC3C8F6E2BA34130252CB6698A3F9E0D9209235CEE13D61DD78174BAC3B93C7BB5807A4D6AC4718EAF8BACA7938302201E67C7A77C8DCD6ABE2E57170B44D83DF67551A6AC4236951F1EA51426C9B152B9529C7AD007B97FC3A9902FBE8388C23D06D12ED8FC2CAD8CFF5A1CB5AE29229E7AB060F86A03CDFFB48E5AA98AC748BDB3C7276BF3C9673C90CD95AFAD114D585665B7579E26D6FD106879CE06A2D0215FBF222283D5944F146EA1A63BD1124327F4C9E95C4EB370EB047D60D8913C8A8AAC945815AB159A362C176EAF945A96089D26D1245B490E0B1549033A122CFA3201CC575EC2890BC9EC864BAF9FFB78DF1EF7DE543BAE8D81CE32F78CB419DFB7DD395429375A9D02F3FE6024863D3B1C957F40BE30A9915271931FCB6B17E585317F1D3CC020113D72CD8595F47194CB9C7F9CE96294295F04DCB70B377314CC4773A1CCBDAEAFD58CEB127FE758EE3B5DCBD718BA5C4023AC5AA99960387473CB11131BB488BBDB9876920D88C1F31EF115AA60221BD74E7615EDDCCD44EF44B46BD7D35DFEB5B618EE51E2E9201AF4A313060EB3F4A2DEAD29E1D05F30D91C418BB1AABFDBBDAE414468B44F3DAE500E14450A0090FCC8394373BDF12E1019B107C261661197CE726EF933F6D5C81560766CAAD84B195E5652BC4D597561A9FF6B42B85357B710714EA034A0A8373876AB6479433C3478679E16A3F9B8774A8BEA5C3352CED87CC8D7CA50D858442FE9747B469E9721C76DE6CF55E5EEFE2E318BF4BC51988E7313EEF1A70A754E7AEBAE2FDC2B978C307CF3A40EDC1C2FF92FD3E3A8544FC6BC9FF8F5A60E27AE63E74EDF72A7EEF3D665CC96C792E2867D155E46FE3AA51709850023B4C76592B765CADA3F20B82B6F0DDB9F90960B67E0A968FB9F16141B8F6B322BF24B4637188B985BE15588E25A59583CC43A14A1BFB4FD97909B6A76419AB30B8ADE8A3D25C940D28A4C88F7648D32C6A9D9198F71C8E76895A3411C7531F1FA6F01C6794CBB3D4E7DF4035C33E83D377140F55DE65E26DA0BD14A55C7568A98F3C79F643CC09D609C212D155368DA2D45CB3A268E0EBE902D60C88D9CC7D5BFE3A5C678A33A426F7799DFFC07A2D39D76BD26FAA1FD70C2DC2AE901D3D0D2CEBB132A8C90FBB802DD0D062F6B623FB0A259998E3A959D298A057C6C944BF46AB61038F147AC2A9E1C05B2A6F1D2B790771D5CF439B69481E568724DC31D7240D48A1F155BB7FAC3B1348E959F91B44098415DCFD06049CA282D899A644F61492220BF1FD9852F02624131251DB0FECF030C394C49B9C5D4EDB77793FE444206D378A4DBAEDE173691ED42D1C3689EE251E26A1B91945E66273A9103E741554E509FFFC486F124B68FB1546BEFCBA3A9CD226AD48CA595C8C9F1F929C6E26D9348F51B8C43AB8B10924F17A1B2DDB38842440ED2CF259B25D70D41114DB5CE2DB48F0661B45AFDE24F6F9DD043E5C5F148D09304F687F54D024403BDC2323303549CC5C2DB5F5003DB029D278AC1B05AB2D2DC58D0A45733856711DAE8FEE9BFCF2E19DF4E5CFD84BB0DDE1B5ECD330CB2CE253851F6E3C0631ABE9AF5263E84A6145FB28D0651907E5360254D6B53F8D6E402129D57EAC6D23E2201CF3B157D5B18B0AACF2F433BCCAEE2829C2729A99470EE7B0757480B0D91780541987EB08C27EA0CDC9BD0145AC606327EEB316472D1C70BE708285E87BB6CD8F41DFF539A95F159E7DF44C7CD190DC60F872CD2CC45C945FC8A127E0A31E1C464FEA1A35C0F99209FAA544247A6016C2451EE1097A7BC1C61B2030F9060506F951718B20C600BDFA9B60E53D506B6A43BB8A66EDECC6AF44E936DD2142C5EC2611D81D06EBA82165A3517D5B795DA83E02B262E36CFF1846890F4051085EB9CBCF34E2A2A8FB564EB1A7A49DCDA3C2DC2A7FD65B9C07E534FB8F72183D6F97259BFC861D74D34A03E704002D7EFB6CC7D5BE64FC45628FFE56D8AF3D081F2E825324A34C15FEF22F49B96CF38DD6CFBC39F8B34C590D89E7EE0E07F3E53D9C5FFC9285DE96860365908B15C1E6C6ACF925E7F4E2A4D3FD7EAFC680A1E88D4C5A3F2DF573EB071E03F18D2D3BCBF6C11FEBD3EAC4DF834A539BF2AD5B4DA2B33B56072C51A9432121188FC0744FE6DC148213E7444C9535C12C89FFBC7A3E0A2FD759DACDBD9B16B720ED7DA0B726A242B857C3E9769249F2C35BDAB4E25A09191DF588100D4357E20EC3C897E7E62E6E7662E1D1D0543AEE5AC14E5EFF2C7A272FC251BCDF56C443D21CA2447AB09780C25318136E100168A5D8889A69EBF5B996AABB71A0433F20404EEEC4D9C57E7DC8CF55C44546EA4EA39FB393F1C3156AF63F4D200D9A9954F724E50F8756EFC8B839C25BAA9E10B858FCC266B1216273A4015E77F53B1418C29F1D0406920FC791BCC7F8FABB891130B74226D8B4B00F52B7BC4587F838BB5DAFA137646A53F89755BC3D921AD4F46139F676EE29D5BF871560DE67EEDDFE81354288E73AF6895BD2D8E66B7945E2C44A25DEE23303662D61B908613104C18D2C83081A4AAE13BED21F7395E792477BEAD999F0CDC37A095F5B51BB0DBCA5EA2653477EF35DB7A3198B2BDEFEAD01DE91CE0C27086882C1078D24F4F33AF37FCA2E921DE72EFE9BFC940129819C5DE58F32AE2F5050690A2EB4624FDB5B46016691AA15688CC280E0575038CD25E055C469B3EA41DEADA4BE24A8ACA85BCB0B827D1F234D4E07C1FA64FBC9957841B381C9B1D1675F18748674888F8B30755B6A7968F93A24837C988AC049F51D070D20CC930E26749984B1F5884C5A6F818A3E95CBFB5B7DC9C0F033030C01CABEE970126EC73B19468E7BAF87D9086614018D309F72DAA3A7CC085F29366B5D5FE1174CFA0F6792C718F994B15B9C24F90F74ABB60B59015D049067B66BCDF7E933AE2C7A10DE45496EB55182208D0F4B63B46916F82E85F635E99969AD48E0B4B38B583CFEFFEE26332319E5AF37B97E5E6AEB791D0F8782727F23C0C40610EBD443F9EB5B3EF05C6F4275E72E60A183D432611DAEA4BF9B43CDDEFBAE3DBB4F7CE64E1AE718213C3346ACCC4FCFC183EFD20E6A6D71066B8A1A266A179FB2BC5D40F569400F067B1AD65322499E5C4867A1FB1A8F7F0B46C3AD6B7C27055B7168F7CA5D3FECCDA165540B59159FDD84D71A9543617F3771F8F48BB4FB4DCA2F4CC149B7BF9C552499F8A65530C493C3DA0F0DA3A9B58A6221E546A8FC64F4719430E3F6F32B810FD981C68057F796798E940A75FC7A9513E79B32D09FBB37B1F99287246395D18D3546E09E754BEC0DB625CFF589194D350F29225439145E520CF7799A971681F36773332DEFC4ED869AF523A9606C6D55AAA41253D233F1E79FEA803317039184B2A6E899A1E246D0F357D7C709DC2F37993478D189C79220C3D296A3E84ED5A58876CA0E8F4FCE022F7E606C4DC6388EEA2AD97A52A753479DE262105647D0896F584E2895A54DDF1B99C0D64B5C6EDC36005BC37C663A2D5CBF25CF7AFE8C022A83C173A95AAFEEFD9437C178555FDAFD1BAE801BD6C9D244F529F0D5B47B18DCBA1D29E668EA384B152739995CEA0379C4E12B68E03A29B1F4951164A656B9E68FD3B5F7CFE86701DE6DD04BE7E0249891D9FF557E730C69BFAB3F53649667D6EE34391CBC5BF94BF16EFE07EA100C7E44143E603F4035FA8E995B8088724EA3F022DC23B33EAC9A786BFE1175B2F1D0F1AB24C3FB731342E699787AA1B72F98DA6335894AD731AB7FD014EF620D36A486CED1016CF3940666EC82226609FC386006350DE71E40A5A598BA20070A70B9BB444E1FF63A96B919594B6A3A15B050BC40E3F5D78C7FB063C7B63A375908D6B6FEEA0D610F85020C6394EB152F1FCA2F8DF6EF69EC558A3CAE308476FA9F04A5B944D82EB8961F91838D01D46716653ABF436FBC4142F8537E47D10C50E56088FB8E1AA351A71B4A37DB230C8114A0B4EEA4FAB0B948170EF82A3CD33492E23D33E5051D81AE24C2E64521371550D70B466F91565EDD7EEA4BBE5EB840F2CABEC35BC77B1747BEDD95BCCDA0D8E746475AFB8AA21B851AE18E2574C85CB1A399852ED6CA6D4149DC98D38D691191264D06A5B61541EB6953F385DF9EA0821FC1CD4939C561FAD822F3064DF63F726B1AD8DB2EF0CAE44110464932F1BF83598AE43E1CD6B22127069EFFC525BE8B96F4E36EA645DFBDFE516959694463CF33504D222C8B41DA830D56505D30E4BADC98B1638F64B2C5E4E4349659DE4484AE8AF0EC68D44374CD6FC19AB1B478F291CDC552A787E87EDB90CE72C2B528E98F18BE9F60CBA492A4B0545A7F5AC9C3852EAF80BDEDFBA27DCB495E3D06D47D3F749460B14E46EF59496162BBFF400161DBBE2048D568517FEDB4A29172E16C65F338949AF92A3A444C16AEBC5A617759669F190853D3D494C4C5B7F4CC76E78C22AA15B653FBC09703F4EC2235C64297BADD0B0FCF21AD5CEB90BD5194DA1E8786BB1692D224F701157D28467EDEB70D8A5B6DEDCB9B48C8160B51F0CEE42F64416B58E5FA7B5D650B00029D4FF78436C63677BFB2432E245C7F9872A470ECDE9D8D201BEB95BA77F4CD3A6A2A7155A314684DC31DEC36F69C687E18202465BED6645C8D4CF2014B852A2A012B9C3B5E930693FA14A67EB54F6200AF156F0E09320FCABE98FC588523D18FD47439E437F108FC9C90CE1701A2D9FF2D06A5D4A126CEFBBD076F56254312FF5A85DFD4399F220494051B84CB601C710BA80098ECA704C7F4AA2BEA81557F3D7E8593010535A0EC2A9593B6BB6BA0EC76E64F6228C85CD21CE3B3E6139E4E8FD39FA8B8A2D01963265527C8D70E83CD59E74C4A4B1209927013E2A6989A94507B20A837792EEE5B8CC6D577AFFE67EAFEAB78729E96A388F9097BB58040C734C376E4B10D05E50D5DFB4BFC5F9E0D796726709EF3939DAF3EFEBD5A9CF455748C88C4EB6E4EAC33D732F72630BCA56BFB30CDC94E8F0456833BD1B505711E3BBA836E84E8FCC51E401F8B6A846F44193EC32857FA485CE2C5D9356EB47C53A176230E7A6CCA13BCAB8BC0B0EC1ABCDDAAAB61E5748A93140E2C553E99646252FB1C67A4587F84DFCA6114DBA080E5C6B71B8F7A1954AAF85A8028063DA237300A161F0FDA6372AAB3017B3942A7DA3D5EA1248392927D1524635CA06797F3F05AC72972EB2DE7E7E3504A9670767F2C6661E956ABC8C0AB0338C3DD105E88DB51193AC159A83D09DFA7DBDAD0B7777A96BBA8E2C060003E56CC5137E1533883E29715D41EF6A86236A3DD3A5C0420C19476543969D2C8522AA4F55CF61C3C17B68DD12201E449977662A00D21D7CF682D48706939A58DCC670E6BB94400979175C97A7D021EB25CF22E75F4DC5D9D12F578EEA76E08C3433779A58B24A7818485F68E100A2ADCD40950650A1812B3552B4940482B5A2F8C090DA78A75FFAAE38BF379E601A38F7FCEC5BF63C3F1EA5270577703C6C1BFEC2D4B7DC22FFA3F5C99529113808C71F695B0C387BE7857D1A2A59249990CE182ACAAC220FA983CA489344523A6D8CFCDBAA5D4F5DD920170759DAC677193E4FFA56D0A6FFAFEB9EB53C85FB40CF37AF30E940CCEB6F54FB308AFDCFB92C4AD7EDF78D14C19B2417AFA51D8A6BEC7A9A44E31FC1C76E24B505D409FBAD2483DCA751B6BCA24175EC63FC766D307E1CF38A862E8C2CE7FC4E5862A73C709C1B37D8DC006C4E3181D06149B7ADF8FB5E5CF9ECD6F566B1AEC005C37ADE0302ED9F0A810A256A4A5CFD0750F162918F9F486315FDD3058A68502B71B77BA8B2006B5CBFB1EA1FBDE3EDCC896A970581237E35213F23A901269908C325A5E740E0967E5561C14C1CEC2F99E368E0996822BCFFB58A0F99A95D24D13BFECE82FAD84B50ADED6899C9DA436554CD40D4F32278D48736A9B4A3E2C6317D533FB026EF7E0AD8345CCE92E2F5B2E330619ED3E8594BA0445A7BBE055EC539CF15A669FDD6D1F9370176EB6274B1B58D89E3BFD5F82A8671D558FDCBDCA2A7E28912EC2373A8E612FDF9B5D0DAB9843F3E0F2072107DEB44AC3EF7F02F58D5335B233B95909BCE78131F0CBD4D4406518D9E95A9DA3CC29EB095CF32CD958BD8A76634D6D66A2B5B64212843B914BFC83F1DB81BEB4CF56A464B20B572C871DBA22C9F4BE66631F8A49F57B5DB191DAE116E49977FF6ADAFA8E5025E3617AC80ABD453FDFFBEAE1AAE31396B21929B7B9033697341923DF51F67E5B74081FE0A046C18F2B48511302288659E86484036C1978A5DA21CDB2E64F68F65339BCFD08F0796FC18BF3350FF16D7E3FFD53695F44358A7DDF63B56D1D724CF414797A38F45AF2B434E1F553808D20EF914F8693D8AB4EC5D0BCBBD3824DD58121B19D3849273632A6E195ABAC09D66422161F1DB9D6A504552775EA1D929B0DC8F064950DF592822A143CDEEC97D726A3A65D0C5E1008D7CAE0528261B28738EE2202FC9F74FE00408EB779F9BA84E13CEBC4EFA00994E2688C76440ED9A47F4A64F297D69879A85F55689FA71A4380FE3776F7C2C11F68F7724F8697E88B67724CC238E5BB1AE8A010CE7E4743EBEE1CB7EAE53E018A822D88C4592272B3476CB3B974CDAC8388E472B29C5DD6BDEC9C8FEA7A9D6B8AF9D3371BCCC43C00F3E4F71DF1122BDC4530E73894944AA8C4FC7C0EB31FB0D24BF011F7F50F1552D50E2BA035A6B121F61EBB62D4AE3686C98A842E854BF4B8055BD9F18434A6A9CF13BE8623C0F066FC40D4CFF304258B34BC7AC97BBEEA0766910929643CFEE1A850C6A057DE7AD3F5C10B943BB59210046B3D7613397948D86E5FDD3F37C926450F836E1ECA5BDE6AFFFC71C8A4A4173ED826378356C8D83832CA0099959402EB863AD6D7FB847D04767E1A436257DF1D396143EB0EE3C7F5B02443C3DD85B94A035D1E613E1EAE53BE0113DB33EFDA75554937B31E193AD697C54D927C67CF9340FE25950433D090A9EE1BA1F8C5F7F20563A168DD24998D404EB6E8C8E178BB1EA202E313A43AB5345EF288347FD4A19C3123483D68B5D6D9267D2D50B9230CDE2EFEA28724B78A609A47B02CD015B42144CEB7688C3267530F5810CDCF4744B65D6A369B0658BA8DD96645DD4C390844CBDECA8C5DB1EDFC40BF401BE422C93C7F552D321A3DBBCFA1DA8DE98B2A3EB85B04A258E47F55621904D302C3C3DB1270A0ADF363C525C1C87B7A43D8FC3AEF52501ED70F30A841F205104D4C2A2B1544AF1B475D7B1049B5556C6A3CF8B0A1C82A09A163CEA7C45602B149BBB1DA8936326E6ACF23163DC77129F38C226132A1710702A29F3E371497748D29F4E640B5DB5BB5715B29A943E8ABC1AA9BDB916807C7719201D18BE3CFFDDBD303170CACE471EA5C278A64B8BC47BEA5A8275A51F299643A42E046986CCE55185EAB04146A39D1F6020A681E5191081E97A204B1BB449468523FCB5B825760C7617127434BC818E5A8EACBC69F50D0CC46ADC1B418771BAEB6F6C46697F1DAD56F9812BCFBBC2288C75F17E412D7A68D308E5BF445397A9CC768E397E8973E010319427F0F6BA8B53843B0024CCE620E96E3906B45A17BF09702232C140A000368A76B147823D0F7F19D1372CBED4CB2312264BE12B0021C167FEC6ECE3E4057919725DFE7CA2436476C3B959C4AC5CB6FDC3311576CFEC09F48FB8A79DCC3BFFD192647885C9E80ED45E5A7CF77E1DF54932EC1D3343B60639ADE2EE11266B7FB20EF1BBEDBC518CC6F168851D40D113C6CDDA104566E448257325DB0387D5F34AF13C85D5E617A18412E4269E456F5F2E2D5FE0BAA34CBBFCD5F6F6AFD43B750E7B8F5DAAC40564725E669CFCBB1390111BB3FDF62558EAC9D27AADFF5E2C915B5626E5137E382F8B238EDDE049AD03D20F2CA4F0FFC66D32977B6B0DA96660CEA09EBDE4CA81D4B1E9A8073C312B90E29EBF0FF40832021081FE774BDAFA5B060B8B211C7BF8D6148819475AF5FC91721F8E056973DADAFB00A293554CC9C867E1C77591F8205BCD86B7EF419E746824F837B8DB0986718B4584195C2F850BF0916B646C638D87327B27FBEA1F35B45BE190F86294CE49C65C17389DD9C5DC39ED149536E759CB4CFAC12DF5DEE310A84C93874EA31E0A9FF8FB61FBF109C4647B38CE347C6FB94DE05618D76ED4F9C58C88783A5D9191DC6B174149BB05F045DCD76D11EFAA6FE525EF98CE5C5BA00A93179995AF120ACC1891A95F187B718E7B61E97A5163643EE64949525BC0E4C3661F44A8105477898AD9E312FE3AFA8197912802899AC2CE632FAD83B4758848E92FAA081DF0BA3B95189B6EA2C02CBEE9D3FBC42DA92D54B26B854D4C4FD79F8D1CB553DC9920CF7F36A86A48B703FF0D1C2EC51F8BEE9E063F264DF70203CF8DFFF5BD2E30BC3BE5711C2BBDEA1CD4314FE7018BC38E74CAB2B9E9E4D0C99F4B3DE4D65A71BB89E68D95BD865E37AF94CE52A3E68641BE1B145000B2B026D8C670483DD0DBAB4EAD3795FEDFF78601BA4474D6B5ED0956FACB3014651EFA16862812E3480F05E6FEF4B5A7BCDF1EC243E7117DA70651C0306831C718B5020A160021AF5F8BD7C4F85F6ADF12CC7F429076EB94B3FD1A2025A6B557781E53FE6DD12148638EBDA86FE3760EA4F76A90F0C2A23F2BF4A14CE2C84CDAC5640C5097017B33E080E047956CEE10F1AA15D99A92A0168DC5427F5B066A456F81E6631DEF57E9555AF7878AAB50EE0BAF0AADF6F05F4267DB20CC7DD4ADBAAAAED3BA374F591BBF962515AD935CCB43B27EBF766DBCCB36206F1CBD395F81B53004A83E6E9F257209EAE0B615D3B66217411A86E0EB8FE55A5EC8003BE95B3AD8139C5B63304DAFCC512CE186B5AE192253F48F5728E3C0E722E62A68E0D6699BE46A50CC6AA063DC9CE08590D72816C5811A4FC88477B227AFB594A3E9D4E4AB9D1AF9949A2FF6DE9ABD7A7E488B1B1D02C0CE04FFB14FCF2BDA3D531898BE9B9017DE2AE3A10C034A9EA932418B9ADD2B59207EE7DB666DE7428BDC843EC46BDF4DD4892B07792A4B48ED032D77666BEA648784458023DF11226FFCD022C753109AB48F83B3B30ED3422F59AD14AC53581AD22F87FDF1A9BF7720CB60D16FAA37C2C382E77AB9460784504CF9CECF45B658092BE8DC1A3B6B8E5B1B95B757A725F7D46A5CF443D9A9563334E581E8E9715FC9593A65889CFC966E1252664DEE0DC14D2A4EF766329CCFDAD3E4FA8CA892CFDB34A8E914E2720D838713A188C0C1948150E97FC8EA392C4F546F26ADF1DADB3FB33D8926145F073C9EA3943BCD5748611F5937D2D766EDBBEB00E7CCA466B99C8DD181490CBDB1AB561417DF41AB2A00A6DE7579E9D6373191014DAE8EE726737C138221CC3592245165A069F44A1F5F1E88993EB44E9D0D979C543A27E7FE3930FF592872558CE5248D2D1EF7E445332CCBF88878AE4D23E745B8A4E6B5495A0B5D359AE86A1A670EA5C0A279E33FFDD03960AB3E341FCFBDB7E7CFD24C6C8EE504593FDE284026ADFD087E01FCFA06CBA30D1726EC528AC041B658815A8EA5C852F07BE4978B797839DEDD65736CEBC0E52C44846B7139D20C9600F8E23FB2D6DAE8453F6942A577E418E41BCAC912EBE7F122F97FE6F5427B74C8FE7A046BCD5621D2E7898ABF31691DBBCC8F9F43C3404CB4C2DC0E968B2077A622058C822CF73C753A4E9F7F86B84F3F8F6CEAE83B1DBDE51792A5DFC9F23532709E2FEF5A1C3BD01DD8F5B4FC2B24CE0F828B4CE66A4325770144EF55C5FBB8EE2D682AEEFC9E85DF34CF7305FCB4F105D2196AA7226D700D42EBAF1831FBB314968E91CCF19661C4BFE3E2D8F8F15B127AAB9AAA388C766ACFE72200E2D5557478364C2D774BE546042D90AE378DA7397A438F72EA98B8F769046C9010DCD4CF53ACBFEF4B65F084B19A97C8931AA5A99E3E9BF4EEE3A198CDF69E884948AF3BA8DA2DF03AAC038B4246B4948EEB40E45CEE3F3540C87C8D06C2FC0933B194FF7C49466E0E6979DFBFCC195C914292CD63EAE96D069DD7438B9D419836EB99D8DD3D7D45761A017AFDFB4516C0DBEE76FDA0C0BD8509B81C54532EDA94921879E4AB15455F7A5DF9C4D3F5D4F87D3CF68EFA8A475E119BE132CF10372A9595142DEA4680837D11A7DC0F48D68D56A5B1563A314968BFC13789D0435FD758476BCA18A83AF885B18F4CA17FAA0ED95E7E39FDD8155F158608A1C9AFDD66015255F5F8DB2C0C14D9D96F81797F395474E965ED8C0F8A638B025758982E73B9C6E795B68B41FBD9770336F43436C141423CE78BDADC66931FBD1F938B1C095022FDAE6C6A56195A1FBC8C51C4449ABBCA2537AB2278C37D6FF7FD024D54105B8B19042A818A0760853F947383AA2D0D1042398C42ADE6C277F8B9270417A81FF7DB5506ACFD0059271B334B224DB60A2D690EFD6C8E3EB9FF4F9EB7FA80ED98CE2E018726D159990D2D47A164416CE3D4C790DBA26F6C42045B06701DE9A650FB72E9D9DC5F6903B236E04FC47F628C3BA7A71ACE58B268D639AB6244A225C6BBA0310D6F64B7B48B3412A29CC5C98925580824D32DB796A0E1126DD9CDD4E3140852A06A8570FAEEE5E1FD1B97A7007BEC24E4E393A0AE0621F6FEC60E3181416F5F729D2309F7A205D5FD7DC281FF2C792D0F78C1D8CDB947F793A28EE35B7F03B6879F57B11FA8AD5E8F6FCDA05CE68BD33251069B8F6C396BE4E3DF64FBCA34407A8176B078CFF3EC8221202EAB836D86117B8FC9F0845AD7B5A7204D01720EB13DA52C01B3DA723D3DA3D91A36C9F6CB72C21487CE4C61525A98714E9F3E2C1EF4D0125A95983E2B7F3C2F761F5D09B10A2F789C047423D9DD835A15636A8FDE7309927971F9E796EA46755FA6A14C161B3567CA2A183A89211BF133452F635AAF5D2D3290820572A94E4C0626B0E24CCF76243B937111FEBAA2A9F662E93AF966E9FDDDE5FC4498B1350B5C6509F1A228446AAA713EECAF56E98F7295FCBC92616456C479225925E82F55D090C4F992AF18AC11F9864D1E6D95059943F1718B850BC05C106F4080B970AD9F34CDB30D1C7DC281360CC853F5DB011A5A068FFC2D2E6CACA9F79AB4D58462EDDFB27127900CD9377A7E87FA7FD553562939189B62FA5CDD084EEB01D3522E59144E6400B36FE218F979D1CAC88D886184E7EF526451DBF4749DD49991493A4855F380B362359D0C424D5BCB828B30B47EBBF24C1745E745FF4DCF4CCAC787031608ECAD24220E99900F76D86C4963380F2899D5CD639295E867E9E75C7FC01EBF257E516F400470270AE9272CE1AE1106C0A33F26723CBDB9FEAB50455D844FFD48605CB79D4A97A5A5F601416C0B22C712431704B9364E3A10486C0243853E1D5DC273FF7A01B47F87AF9F31C5614949E9604B7B5240643CC9E046F2C80156BDC4DA0D2A89A229B42EA29B904C93791AADDA156C4223C9B4867E37C6AB80955026C3359C692A80939E3D6E5481E53C9BB310856923F44A18609DC27E313F7F86FE3DB2602D0BB8891CC976A3459FE79AA4A71F506020DF5D3ADA8794890CD8AA360926F0E2357DCDEF48F1BE072A82F7876779558CE023B3E3AD7E6F71EE9058098CDEB995E251B775D18646E6F84A3B2C5E0E46353AF7D9E997B571945783A9C37C37A5D35238566AC8C07875B91AE2C9692E705C828D0467EE8DCFECC174539DDC998A82264E2758C774F668598A0FC0228AE19C33ED6092702576ABA14959C8DF3FDF2A0990F9CCE6F32A47F428213AF44A864FE2CA34E92201619DF6BABAA63BED5B92C8D1A0AD8863C0F669F4906CFBB3998DD5121AFB763DE2F79256B923C2AF81EDF3CB93B6622C46631E30B455052962231917057E4B63BE9A1D039325357DC1F299FA8E510F3417B1A5A6EE65BB9CB9944D56E8C2F5570642BE6FCA22AA743572727CEB225DADF2265FB14D23C273045FA9288443965EC6A89902F110ED8758C5A4B50DCEC14EF80541C267B265B222840BD9548340FA76DCEDD66D921D198F4AC23F216173232285B464EF897472F79B9C3A711CC3F1790B7FEECDDED154059D9ACAD8FF97639FEA2F4C5C037F48EE2774BE8112C95E355BB758D183C28289C34EFFD4A1F24F1CEE3669BC0447B4EDB23D8EA1DEEA853C60D490A3090B472F693BC82B5655CEE2C55809C50FE2D765A9005FC502D491B1F8CBB0AD41683919F00BE93D71F47F64DC78FE308556C41357D558CB3716CFD8D35B2E3CF3B6D92191BB4A39D7960F286531D886740A5F29A1075CFF4799EFA8CD16A4EB34C4C86580BF7ECAF72B84E53A10E65DB3264D18E346720B66A6A4E5CE38897E1FCACBBD20845B1C9ADE2EC0315A4AEAEF36F9D80E091E3F81D37CF18041A345FEBBF678B3809E4A71A449713772FE15A4FDED98A92EC920CC91997C256999E02690C9DBBD3F77013E30E8090B679F645E1394B79FAB664927FDC61C29C4F9D5D9F7C2333CC32ABF61120C2BFE8AFA5E1DE63B0DB7E9B80220FFA2C253400536E0FBEF0CCF463161B70593C061CE106B17C4A0F6664CD87E899200662EEEB68763BD9602A2DF85594F49CC5610D9E50B5678331D4B4C942B8C401DF7C202CFAE5DBCED73409B8921BDBD5493FDC5772BDC8DFDC9F685B7E5E733E13F5D271EE22CE6BBAD9EF8C6220D96F21D6E4374AAF4C9C6242BDC2C485FBFC9DC094CF762C695E6BD6421C80D89A9C8F5F21A986A48DC8EB89C8FE9DB218EC1639E3557BFC195C6CF9AF32AF66210EF8AF224D0E8FB2CCE501A65FA716D2955DDABABEFA38B1C613C6F211A088AE42BA2A69C4DCB007E4FC324D5414518C53B10EA4D33A4B5C264F0601A7D09928C97FB95122AB7134E9E42598AF4E9F135439B29CC09159A0DF635B09BD81C248DF1833029E554158972B042A391BF648B7F792A147505F5CB868A42E541A71C5388EB8B22D2D1172B9DC255364815A17CE8B521DEAF3B0CF16A9C4C220AC090324D5001A1DCABF5ECF424A1B5D9ABD04CB29DE1498959399BEC6E95F80E9B0E6503D43C9D62FA5FA5EF0809521E6EDED3FE11B8065E8BC4B9C92D68C72F6800B9E331AD7693E0F92AD2F4FA482930C84F110C1F4E83069C38FAF9C568BB9FA8E0F6693A91343B5A6AF46C22BBD87A7DD1A09690E6C3CC9FBC335B265C435830D23E0AC1968598163EB73CB7A8DDA3E314A2D5EDF65A23673E893168424645DB6A9909F6929BB1162CCDE446444C557052EA392EF0569F84C0CF53C385BC20320040A86FD32A54BBEAFA1C67B22E2F8E42264D611AEC68A383AE4EC306830BE70ECADD96A9FFCC72D8F6C58F806B1763065DF14B230B36EDF5F4EC3BDE57547701AD25254756852CF6956E70C9002F464B0B86C8CA9F9D175091E9A7878B735E780F3621E801B3C8D4BEA445DF22AB2D4053E5833838DCD2E3A579D76CA7FE258FCBADCAAB946A4E694627AB8C46C4AC775B3FEAFF9C7F555184668D1BFFF59C0BC818FB053B87D22B1081D6765EB39F0BC79A04ECD87A948C0A733002BBFA741380B6C5EC6CF639FCD6F3F038492D34E30C62AB7203A77AF846988DC27DE720BBCEC5FA7500F2D682AF9B280757A3CF4EAC030F23E98977E64C268B4168A32D0CFDBE6CBAA03CBE18E0BA6EB063B221CC7BFA35747579DB00F54027844028981D3DBC31A0C75B0AF5C70DA961FD8D7BD6A2196C4E983D833F47AA1D706145D490EED5F195489084FC6F336F7F849735C50F91951E5EC761C9423381CB8F85CC137D5AEC2C7641945A112030BBA4E326DC3F92312D3C5458FF7EFE760715E887645AADECD2476025BB0B0A91FF321E44C59F2120E91517305B491462DD4B19E695A49847F13D71B01A62AB7D77ED2F3D57E18A707DEAB7DB8F7D40F7FEB74901D13E3F4446946C24D6E3256692C9D9C5CC728F69CB023187353E9A888243E37AFADC1D893808715D6338D8EE0025B9961AA2F1F34577FC3F6D0D41BFFF6C045901CD29D1AD0002F6744E662E2F1A9287D49C52F1C8FB788495A71962CD55F5C20C1C65249D640FC96F2B6621115249479E68014B5823D721F54C18B2CA29C8D09316603430B87FD86849D59D361944A67B01B113CA6D192915E8BDE0AF94CA4978B2CEDA41132F2ADDB36B41E1CF32041DF56ABBDFD83354AC63E08315BC103ACDC27196AB86675D4AF549A4BD24F615171703968596CA08334BE94343111BE2A3ABB9A2F201D1FC731CE8674CA90D5CD55B39AFEF13578A198EC47663F46C59943027895B70126942CB44B4D61BAC38CBD3CC70C69466D6BBECFB38D93A03348F16757EE8825AD3AD1E2BCA21705495294C62A3D63A1B253D2329739DE884A751E3F7BE6AAC2DBD8DDD41F929A3856E611CB4F51B8193EEF9656EF84E6F038FA6414F1A1B50961D943B454761BF1E6AC1F297A7531B6E9F168A93E27A85D9D74D2A2CFF89B760159E93C3FA33B146E74A2945EBDBFD3E8C67A9DA1408D13842F133C95AD549C789B6105D17D6DFF7033D28BD6734F5BBB91A483E244EDA83DD78410AAEDDD72F616E775708AFE042AEB918CFCA615C489A68C399CD5B7066D2895BF83B36D4DAE0E6AD5349D449670B6B666211A99AA2C4578D66BA26E29025D0297CCA835F0930FA6B94C82317FA58269CF868A27ACE44D8E06C2C7C83F4B37ED3F104754B5C1220E6A882CC94D4CC0EE0F7903E534F5A9013D10B6B9D2DC04701F915DCE3827ECF3C0F1337BCC382663F3D0FF060C6D7B377135A55CD64854A330461ABE169046BA689824E911E0AC6CC2E5A9EF4D2F12C77C8FF0A7ED63A1046857FA43C16B46CDD4A9197186516E44CCDEC4B0A507D2649CA08D9C5EA9A65818A8571B975D7E45BB2F0EACE228D87A3A92066C5C52DBCA0B7F0737D997CAD5DB4DE59EB9A2185C9B35276B1CC142A62DACFF3BC0411F567B9796E5E20A9E10575478CBB2D34F0EAE42E720B8E9D36568BD774C0E2FCE7F2A75C7FE1F2A7B66DE8248D6426DFE9A57D25A16549BB53FB0FD2E8B3C0D1D11C597545446237A322CB0D93C0141981260CED6B49457DFE70CADC9B9E1B1A3F503AEBC55704B7A72676515C29B5AC9F82B16C6F9EF639C293B4F827A2DC5C8503A500DD8709DC59AE2884936EA4DE7DD70169DCCACC9766B09E294103D77F27CC179B00A34599BBB06DA3BCD6BDE1C40E66B80824E26D0337C64819AEFC96263E6540F95A622D5FBC19497CC2B325842452622968B71C42254814D88D14F26B20CC59E576757D56F19397501D4BABD8474137168C650A38577C49EC4C7127A189A2C2BF9B5593A0F5E6460E4FCAAB49F2152B750DCC433CBC35445232882E34500FC55A945CF551B82C0C2299EC10F586072B7912DF262AF317CE729330437C1A4AFF6CFB434688D51F80BC027463F9BA563453D17D2D1B822036EFC7DB2CB90B4D75273A93022ABD4E4B98AA74AFC6C47C7FD3304F44C468F47DB5C46CCDC3E4907262D373583FA706F959A6823721B95F26AAC9AD213841193B4C4E0A3E8F6F91EBC08D24465D44635DBBE33488BAD4887DBBAA9CBF44994CEE5FF4E347342CEAC981E2432815C36E613EEA363DB3A4F3804CCE428D8892E7087A8294F3E200BEC0213C97FC584F3CF99A83311CD87EA59812AAC9865CC0C75D437B5ED086ECC60BD9B77BAC23F64525F368B12D3FF14D27C2BD4A1E8C31FDEBAE2ECA7C2755A09363284DE60BB53779767B6A345EAEF9E19D9C78B2714FFD962E3C7B092B9B62FCCF358C011E1102650196B434D89217BD048ED654167A46DBD6233557399E40A8964E8C066F05262CED4FC3F902FFE6E52AC6FDE4F8FD44078EF7C154F47F5203032E807753B48B853719F2FDC471B7DD43402D91029DC859BABB9349D09A9F7332F4F5B9241D73E1DFF9662E943F859B20F50A99F44540B6D619240136BD0E979EE054996D48D95394456AB0601D3E70FB4DF15F484B1DD9EB0D3EE4A89033D1325B3A1FE62DBD1C52B7740D27A1CD52C019B592ABF575B0D324AB40EF8CE91F9FB58A1E3201CD57EC156F62C96D77A33BBFD623C56B43028E8BD107C6417A90B4B91623A669BC5621B649E9AC04B78502756A9E66E53DFD753F2FB11509F068378B1086258AB50CC3CA277F3C61D32DF85219348B664439BD6F3602A77EABD32ACA69D36F72EEA07C2F4FE64AB2CC723E108FF048996854E79CB607C773589B0AEB277886BCB92AF860ED214567A150B92EBDE2903563AA81DB07884C22722E213350F713B04977C0F53626B31C8D5E1A98349E7F75981A45E20B1626E76DE1E1B7383D6C180E3D1DB9C5575FC1CEC4BEBE0AC665CB0615D8D3F6D70AAC7331DBFDC1F3D12EB4D5BDA494E6414FFC5E2ECF7BF8289834EEA392982C380461585E6DCDA6327601EA92817AC138141E671592AB06DC0DDF45D168C4F87F9E0AB3545ADF0984BF9F2DCC28EDD3ECB8B05C0CE3E20720027898B749A7B192CFA8AE63F50EA19FB48E6742B13F93EEE6AB29CB2243760CD997EA0511829CBFFC930EA6ABBE971A8FF3CF94864C477FF9D14A6ED81CAD998AB0BCD95CED88C9AAF4C13008E11916B5836C48A4CE85825FAAE257F3E95B4C6217253E99E0A44CDAAC804BC3D4B43CA6166A08394E84865BB89EDF2F7DE1F9548BB65A4AFC6EA58B691D6B0CCDF4AA3EEBC68BB6FF1824ED74A942BCBB0758E8BF49804A5359D74CEE5DC5FC40E2325846C02C4BE136EA951D40CC78691867CFCE2495E261EB6F667E440BA8D4FEC506E68C05F0604DF3D751AEB398501B31ABC353D8C90DA4EFF5432A2B997373827D98D822014825B9D9AABAEF5ED4CD2C48D3C07E2046B7EF2243077083FB73641E3DEA4E65F14A3931A5AF7654AA7684A279D13C9B79642525EA99E05EC65A8E2CA64BC5966F2C5C7DDED2A7C8A948B87494A9C6D034E50DE30473D2F558E8A51F5FB2DFB788F05C34082180F4F85FC1366F3F60BE4AE4E5605B3819B5655E5E47414735B4EA1E7DAF1F14EC3736716B591BA7444C1412823E63794CFA009F42ACC012D4F789AA4F7EE07A5255C4D17A991D61E35D57E7C3B72C4BAF4E8BB8F669F9B70F0B72052235BA66DD65589EC37ACE7C545DCDA2D18679B37F7C4DD53041B9805D800634E700315A8E971D4E0A1CAE51AB899ED55526EDAF7DB5FC1A9AF234B47A7A880288DA3DEB8C3C6DE9C1268672313EE6A99A50D85A24C6BD850A7E23FE194A734E9AE3186445B6C93CC776D7E13E47F91E652D28FBED0928DF6352D83E01B7681937A297B7D121AA9793F1D108D490C9529E70EEFD23F0ED7686B33D024FC4F27DCE7FB7608DEBF6F2DA0D06E3AF4A8F0B57670CFB7BBC6CFB78377067ACA4EA210F33469292322503B0BAD6385C9624FACB8681445D3C93B0A483B902C44D41AAED1392DA396B2D8570F60AB90E8876F1772974D4FD359A731C456CC9484D232D74F45D4DCADC44F560773A7396D2C4FE7397D2EF7C5ED6745263FAE1FD121F99960011F17CB224D477DF864C40769783A1DA42BB33ECDDC60E1DA5FF1101AC1031A9A2A7B396F05F9DE7C234D0E656514B8826E8BA8DDB08A3F3B839032E28F044D3EDB7A12C606896A3963593E346D4D367E954DE0CCC2D2C8087AF7BF17BDD301B1FF81154DD7E3EBD3AA5332E40E4E3801972D9A262E2BFF68819C63E4FCAA254D88ABF4D4A3F766315EEE1B2524DD89CAFB2788EA145BADFFFEC094054D3B0D50D80D35401CFFCFF93FFE0AE72B9177C21EF28FC590D81E053240DE801FBA2D0A923B5964EF10BCB8A309D36D0B16010B9CBC15FF8F86174DA1A80A0AC75DBE27D063F0F651934D75B818457B3118C9325A49A99726D0247CE54A836C39611F8335750101FF5948B0CDBA2F3BEB177F082C25C59E930EEC1F627E0283C617B82FBA5BEFE622752BE6D755943457CC21D06C65D90A3C8F3CDD783DAC8EE42EBC4C921667436A28C8DA75E843398EC1C9E0FD57B887F9D735EF3E94CD3912C1A710F041D739C5A3F9BD2E2D276FC62457BAA098FBF0DEECE425C919AF257CC5B04920CB309064E75A08E22D7A59F6D2863A2701ABE712568FD4575FAA4C0E74B2FC93CE444ABADF3CCA7730E7E8E9FE4E3F2F9517743FA93FF3C469AE412084A3DE546AAE0A3F298179BFDC00482252D52802870A1BFBC89087A6FABDBC422FAD557C129555F4CA54BF04DC20050379D01DE7B38D0AA276D9DDA6EB0A238A3EA7C30D47DCA6A9A7576DA62FAFA4EE400913DBC8E85F27558B58B48334450BFD652D28550E9D8D1646318AF63D72B61DD7B37502CFD5FC64D7505A763E2B414F84A1EA59902E5027C054A41194A05498222642DE7BB189AB9ABE0E24446E686AFC226E30586C7ABF87F7E97A4DE80F84DC0CE739C481C41834474382070DC588B6A73122AF2140C14BC374E4E74CE3D5CE1737575E2AAB70B7B03CA5A0610D42C77CBAF27C2E5D5891ABB2CB4A9086B25745A9C67247765C2C6DD2465533768326F7A231FE996EEABB92B4D1258CC72D6C50311B3E8A943B512BC7CCBE571BDB2D4CAF4F97A31D44D9BFA2EF5EE4212CA7BB28EAEE40DF9799CDD2459F3D33D00792AEBEA55562E44732F3C71AD4BFC4D0BCD1CC8CED44B97F18B0D424373DA08A108DF6E4A1FFB8E8D58E35F4D25335FBD964C9E833AA82BAB75D94610D4C97BA29137B191EDA5CB50332CE2A885B60C2D09E1462E96448873B09A7473E2D91076044106957FC454B4A00A1AA52CF4634D32FA09B0C77820EFE5D6768D0B19F749A3AC34B39226F2600ED3EDD74B60294F7E6F81C123D6F66835E0D35C3A7715F7AB5B8F5A7CCC75353B6F8783CC1B1EB0F42F40201A1C81AEE484B9FC1096298A37CBBCA7764818C22F47A4C552BF0B9BAA63C11A4AF978BB91254345B00CF278E024BACE2D9D426AD1F00A8C59677F98938E3846EC5CEC0FECF856A7C3ABFB421F302A91B191490520E0F3771706EAE30EE419DF4AC9FE5554D96068EBEDCF8414F8A6876103B74071BCEEF5A1C1B4B9BD809259315C59A51EFD59E2BB204F0440F63C4FFB01B6578FC70434F8645E3141AEF6A76C96D4DE64A25678BCC85AB23A458168770075A8156ED3BEF0962D0AD5EDB31858076D77E8CF082265AE0026F323536D8246D29EC9B2BF5193A395D73D4A5CB1E953B247BA4C7EE262230F115A1F824526C03F100416B24F811C7F9FE8D2D1FEDBDB63AA4E5FE6903D1147DB6D9D40365F36811BE82766606744F004545858466D7FE91BBEB1A786F155C01FB5B35A5EFA8C4B9C34E61571927EF8E14CABC77D0CCDFBB1AAAAB08B20E274E2759C939614D437BDB663B6830418D5AD3205667151324DFCC07A256A9048A316217BA425796A2247558B4A3F80467FFBDFD116567AC07D4347E1962A61744942070754658C1E4AFCB61389E2E83C4D799C3F7C775C68433AEDC0C5E0595B707B6979C82ADA0CA6A5D6554544E1551CE392EDAE38099D0309210CEF341C2D28E865C6108178F4E73F5A90E55B31A2A56AAC60AF519CBF0DED830CCDE9A16A4C83669EBFEF9D6F7EC508DB6AC5E0DCC37D40C4CE21701EB86C9E32F616DD505739EF1499FD7F84241F7C42024B6030BD534D00071EA9A92E49DF20B7A1E3F2D746B6532DA8D3C4B9D4C878310F754305F54E65FFE92753EC8B0169BAC36BEB45D197D5416C39774B5F521BED0A36A03CE01A45842CD2B01D710C1A57BE6507C88E688EDDEED5F6CA6E300401E7C3503DA3D2E8B38088B50A63870C2E570DD80894DD8C0345F119FE28D15E86AA1F66855ABC96523D854F26AE8001F93CF53C2DF753251DB872DE4F90FAD8F67158F617CB79FC10EC1D7277C9B4096A9286977DEE34C0AE120397AE1DF7AAC6A25F093C5F15F03900A4EDB3C906E23FB941A5688A3C7F8E12219685A94BD6F8EBC0E07353D44F94AD37CCB0857A4E9EA337FB2F6274750E9D5EE6CDCFA35630F5B244747F84D487D976857486352167283C5A56127CEA6257D42459B9149F8FDEBF950242AE7E848C580B59C979562CBAFEC468BAFB7DC08E81A82C6C77E6AD56BDE3913088EFC491C015D29DE12977000053ABB4512C695807E6004FF8C44543905BA4F4CEA5FBAC21CF647E488E23F3083B69B1C983DB4F14D1A8BCE5E8216801B8F7EE1BA82BEF79A9E6B74C5CAE04C07FC81973634B9406EEA0E625CF0AEAFA4BABF61D986B3AAFEA2ABD253A6326581A87318B57CFEECBC6117955FD7E606E7FC6DE9C2664866D91A81DC32EF3023693DD27847D2D5541FBA9DAE10C5D23D1AD7AB865E0A5C07B0901EE75173D2E82653A430A62B2D72EE7244C49AFD94C450D0D647F512C48196D6C435449A839A7C2F9DCE02A260414FAC688998BA0116BCDFBD4CE75683E8E47DD49A7FC6335AA1BFF34D6B2433908C49DD58229006D08978BDD1599D366664620096816A8C7F35F5F13CA22A44087DC1EDCBF4DF11839893CDDF45598D56D62DED55D893F18990F2DDF2DF8A425B1B0C5538A624F1383D91A6632F43F60DAAC62FCFED6858D20EC63BB9521B6D2A2C9E06B53888C06512E4AA1C06638A525C0C857A3F8A0F5CAF3702C46B4566D48971A59304EC864F5F14B71EC305A9B98626B76D54ED9D4029225732C379170438B6D85369362422FF8E83E8EE88699C465C3C431CC85C9170713DDF39D8E35269A7D2867B9930937580C0617DA1459FB0AC6DA2F4C3EA98FEDCD5449CE45B72D303486423FEF64FC984FF89D5285EA23A7449EB3D3F9DB077AF62A1B006798D495CA306D0ADA4AE2BBA33DC626D3E4E203223B7CFBF8C484A34B0E3D5EBFA666CFB7028A394B1A0C94707DC0770A864534E974FCDA31C2D0688E3E32AAE09484CEF9022F881D99FD7C06C91FA5501FEA637295A7326C97D1175C5C199400757E9D433BDA3E0146ACC21B3B6EDD3F4CEDC60146EF5837575BBA0C4E6240AEAA5DDC91ADA04CAA97D679B429D74B4BF5BA7B582177E68C8E972763CFB698CCC51EE592A5C8F192DB4A32399021113E3ECD7D57F6168DEE6C9119ACF4756694953923CA5C24A78B5B0CA1D5D36D1745267AE8EE1C0AA61A1461B7E4AC8608F2D0047230D355AA50FA0C0FBE364553F966FC732C1912B844DC6AB9AA983DF1DF6D7298131120A6DA226FD560D28325543B63A4278559016716CAD26D9B6A2E22F50D015EAC948EA27946C46B81C58B408A543E2D336A64BF94EE1609BB9D37D55F2BFAA31F30E03C1E9E739D2DC3AFEC1D5797A6A539FC86B03A5D4925A91D88961AA980F3F3DBF6CDE447C818B3C84CF6AEADB14956018AA463CDD260F7DBB268573E5EED8D9B0EB0075B5889A7447A31664A7394ED5000835939E5F9B2BB6CE447279B78FB800545984D8D264CD7E7C167A2CC79DA84E0B84C139D18C2B2AA518E6553D3698110DC4C946E9E457CD4EBFAB9313F7080D893DEAD32B0D1130F0181BB31BB5D53E14363409C417EEAA1C8D3247109E48F81F08040CD573D77CFC9F7EB0397E3F48316BE862B35673C7E12A9A3F70D23EBED6950C85B15E53597FCAA99B745A0297E49B6BE7814924DC706C87843FDF2FCAB9231D9CCB0B9916CF7F7684DE60B200168AA7F2067404CBF4BFCA0757951D983B81AF8A2EE3389C809B55B7E77E79021FF0732D25ACF44068D16B30FC63F71664E9169C83D54EAF175991C8908F604D9E7A815686A4A22CB962A0A0BE0DD2B61BCC47CFC6C36E40DC0A89314B65EA4F8916CFAC052C00D076FC796DDF9FC8A668F03AA7E722F55E9C67D28D7529D797CC0E2F44E5E928350F15D26BE79C2AB0606305EF3B588B8662A6C77F94689AE9DFCFC2BF3A4005B925D55F3CBA89022DF045BE35BF697EFDC94028BFD05FEFD255AF550C04F1BCDCDD7AFCF49482867E2E1BB29C2C13F1DD2FC0F3AD5D49C0432D777FFA8515EEB86C42D0E4691634D097757CF5B353A5046DF458F2D0EF7160079C1D695E6B26BB41DA1CFA94AE6CF54711F98D4F954F58A151AF721714C5F0B99BE03607E4797D89B21405CF013EB7A49C9EC6F47C2944F3F0F38D4ACE2BE99E2A7CD2D278CBE0020CF9A35028624476FC422E1ED39EADA1D20B552BF190E84CD67BCBD426486987E987F006CCAB3302BC96B26DDB0A999562CDA06F10CF1B1EC97D949C5E7FE71DC079764C91455440767A2DD3D7547DCB60D479E57BC514CF22B15031CB59BB6D7FD868230D9C15C82A34E410F75096D144CC2E74BA2740FDCDDA752518200C56B129CD32A768AA7CD1FE2ABF203DCA490DB445E689284E2DBDBB23F9758D5E98A825FF2AF6048EAC1249FFBBC9DB6C895A94331924073635DE517928AA624B53250D0DAC2C551ABE0CE660E782B537BDA2C1869FEDBAABAA8CF56F33C51249ACE674371D3445E606C84D2BEDA85540E96D2BF1677C4171B00DC9EBAEF1FF60D5F91D140A0E0D4FA9B4421C4DBA2D89D48481CE78AA5CA546E27E4C70688D9BEE2E6FD34959088F4D67FF002BB961AF3118E4CB9D3F2126D102358A488DB8A843656D048B4B59D229F60FE094D434CCB4E827A599741DE1B34C1818B390A6A839055D69D0B1917197060854A64AE1B97F10CCD33FBE564EE0667A7B6FB87610437F08E5B34C1FA55B960E0EFB1359F4C16559CD56F06A75AD0FEB6FFCC538B230A6C9A281CE7D0F43B36C22AE247D08D7D591F3AA8DE1F6DCBD3978E5199D5597CFC209DFD4B9B6C7338F893852A7A01CA24E661F67C72FB4090333F39F42B94386F16B5651110169A4CFA1986948DD8B0C829A61913E4AEF90F4CC957CCEC21095C907F22D72042301319D8CECF69D42D5048661CC42E571A314E2877C4BB98B5CCBCB69664DD6B71F77D19E5373185F3F0116D6C6DAF6CF23B772AD40075A3DF12E19FD34772FCECCE5930B1219921A339B7218719F16D6A7C624D163D407F10C475C95804E34EFD83CAA01E2A1AC18B5C0EC280BACE46D302042E3BA6D987C93D13F73B7CB140BC7360B950232BC38428608FA40D063175425F121FDED9D3C3C5B52CEF74905375FB6C500B3C9E1F245C83F28C3F0E9A2C9F0F86AF14D763DA4702157957FFE120BE05D13268AC9A483B2B0CCE24A0248D99F18ADDC351098FBCEB029AC7175A854915EC949E17D7736C56AB6AC036BE37A7AF57CA68D64EAF90F51FE4E6678E57A648ACFBB6C2F2F254943B7E9657DCF266EB9EEF04F41CFCDE0B4F90874003DA7273BAAEE45452EBAB442C24B52007E0B43776D8B308C490249BDAEF439AE7F67267C0F15D327B75D6918E0FC38524BB7E1F4DA0B77398BFBF6A9E8ABDBE1025150DC8BC4B01735E549EC2B9A4ED8B81FEB9C983A71F71510D50DA2658DBEB6B3BDEA602CB8A4BF4F642311CA4C43C690F5FF079906DD4413323F1E56C85A8E685BFF8814F4A79C479B28BCAD67714D383905E6E60935CCF6DDDFC1279A5546F6318FC8256BC39C5E314E372FDE245DD8CC7C477E7647EDC65DDBB45142918AF3463EA63A61383C030A8CA62E45777D60999DAA294CF9BDC2B6D50E8B3EA82543C0E8178491D9E2A869F0E6527E7DC61294C7732C81B39B98C9803E0EAD18EC555E494B36E8AF4461F29DCC36577B0369FFD23221C748546972AD721A04DFC125CA8200A503F88EE5B5DFF3DB335E4E95A11098CB0D3EBDD255313CF2EC1CDDB6790CDDF0C58BF7DE53854927B325E87018330DC3F168156DE8159949B9D09DD801ED5F8FC11807B9173705B9B98FAA1D79EB25E5676478F245DC9C554AA2F45EA29FD87B48CAF915C5EED81AA629BAB65DA7D9FB4DCE27E76A355C7CC4DB87DE76892204732A02CA0A5FD4B59275222A7C5A60CFBFD56971B571AF4DCD1636585628EDE1F9331B64879AF8DA080425ADD2EA51540A1A9152F9F30752D6B7682AF1A12FB627F4EF7455286773EAD3461F65F272D005F386E9B4644D32658AB92247B29F4A58E65DEBD9367ACF082537832D72730BCEE5C4C0CE3748A9B66A6A31D8794743263FCA66D5228C1983842E25132CC75A9A6FD9EA2A109FF316699CF4E3A1225824A040268D84D625F197CD33F5DEFD21EC854D983E477BB679A1CD34A310F9AA56F2892AB707DB827CD2226E8E6D75FBF46B3EC2C722A1E7C3F0B3DA5DFC055C7BAD5E5F704666953521231C6E4BAAB1BCCF91DFCF54FE88B1B69BBC477046312A219D1EE09ACAE7A6B039F546BBBAE621513CAB21AAF8F032FD25569BE4624D1178C898AF14FEFD3917899C5D12090C7F9DC0A799DB1B6D9BDF67859805CAB54A1D4831C8CD0E4BE09FD90D9F9D6E855E78E86A3918750E27C8D0CAD281768FFF3C30952E8D91975E4F5F639D625C91EDB72ECEF28E635F53216841299630DEB55072ECCC8EEC999D72D3AE7CCD4B0538B56852D791081B2FE6EC8A2CF65E8E5142D91641227FE89F096D0B5E52CC8D818E3FDC13BBD8CC734F7020C53BBAAC686A0867A4B7988A27C6B4FF9B61E55317928E0390A245C4624FDCF211125DA1CC1D3AD219F9FCCCB9EA4751C3262C42D11DB1E220758A7C84973E49956B0265F3ABFBD5FD72C49759228CE48E8A2B3FA794C662EFDA7EA130B67CFD27A10937F81AF4FCD9C20F886CC8EA328C535CD96CCA29CFA3D7D54EEC5B8B2E1DBC186FC9B1A2E7A93ADA06C05732650E67ED980254EF7E61AE6A89847BB4EBD48ABFFA09B9986A87ABF4DFFF2C8D5F735EB2292F742D7208C672F70979D85D524B723B7DFE6002257B0984F0C80C02CB9F113B10BFC25B05B9ED0185CE9541D8E40B829BAE192125A6E513814BF2D018039F47B589869DF0EF1DEE1BB39FDFA7B64B713ABD2D3DB1DD7FC2A83C0A525C06193252C1F8ED4A50692287C1669C1AAB51F21E209A83984C74A95774FC18C21E1F2555FBA1E0BB38569B14C3752322BD827B5011E451BC146BEB0BB96C7E2DFA23351D9BB0F638FE483CC9A72C46DF8144E058B1C4E6F4E03AECD098B9CC9AC19BA095E3B5ACDF855B3CAF4CC87478A4AE113DC0043442E7D068A236330FDEB540B8A9FE116480F000BF05DE94263017CEB9391C27E50CEF233CD4F1E66D2AF205BD878957E580899B90C150D072915A6FAA270CDCE68483AD7116747FA139A3644B481C65BDA5D8A0B6C7F1D98A677A713960A84A7932B317004C6AA647CD814DF96246036BA4666E7663F14D438F8F3D8D8CE9A022D4FDF29374554BCEA2189A4D1F2CF4836A0C6B5775E9A9CF6C55EAD48DD64D1767D7AE08C5B039FD91F405067B842001ECA2F8538BD480516FF26EB76AAC39839478B36FD569E38E5225CD62E7BA76BD5D6ED5BFF74DFF72EB65A30E31018DB93DB2D8D9C87E6912675BB952AE193C0695BFFEAEF2D28B0DEFFCB0F8474DAE117FBAC8C2B4911239649FDFC020CD4D7B71D23A8DF5D5A52B16B9DB33C8CF7C68EBFAB99311F71ACAFBC0557552B209949FD304E916205AB556C2BEFC677B8E471E3324FB891D23F441ADAF156FE4E6D2170FD05D57E900FA93B30E15E66BA90FCC9B71C447DCC7368ED2B52C4331F5223A7EFC6F055744A5DB216108D00D5F6C27C77375D70D6ACC17E972ED9141A54184E75013B4E11BD3E4B50602EE103BE6B5E4688F0940C3585525C806BD8CE50017981AEF539B7FE8F40094479F7483A09F2B6E3C4AF1B2A0CBA2570063C145B5A44301E732FFDFDBC32A49B180C02AC10677FE6AAD5FAF138894CAE52FCE73DBDD643C9A34974360BC4B63F90FF5BF35FC72F006CC6C22A9FED19AD68C1F5CBA56DCFCF0D2A3EE8E9F531704AB53354988D1F6807183DAF84B78636B48291378410EAE72477A7B03D033887DB846BDB44451ABE5EEF369F0DC7E1D35F35DF8D8549E093B321E37FC87BC8A713DCF2EA256B1C7BC76E19791A61B59F40AD76E332AC3D5C80B4B1A49C86E5AAD12578904B91C196F65C95065428C3330F5391A4D5A368B52C9EEE5E2EC8A4418834DA501A1AE2B63F3A294BF68B1AA8EFD1C98DCF287F26EDAA6D311B1824B2EBCEBD54062792CBEECDEB38E9F5630C8572ACC14828B29C377AEA4C68D71AB243D4B5415772396D142757BC68BEA053BE9B4E667545D7ADA372E511AC81D1B125D0434E0FAE1BA3B8704207BAF984F6C82700C29026003A34BF314F6AD485D0CBEEAA237089C34568F33D822A2EC1A297B8716E5D5E13FE209B07D071083407E52CC13987A81876602D74E7FF962392508B8AF6080CA1F95E59174372949D849FE706C2E4B0B9E1AECE4F876AEAC168FB4AC548E74778DFE247CFDED187EDDD9A40C42FC87809CC0AB8FEAACB3665F1A8E427AFF0D32B2F53E83E19C41CDCBEC41B5E40CBD613BA6D628A9B327425C4FC463B51CFE4D016795169B5F48FE287205099928F1E767804FB2315906BACE18A27E5241E4D267CD79BE82B24F5C7CDE76B0FA919662D4C7481614C61558CCB96EEBBEFA0025D26177360DF64E219A8AE93AC8BF63D154068038F4553E1F1EB8E5FDDBB9DFD9DFBD34C1347DD3E47CB7BC043535350D55D43057B77CC58DB9FEF658E839F5BA5B7687B198F75063C58EFEF2CAC01FE3581C0C644693206BE84EF41495BCEC3E5DD27700587FECF36CD92821E0E2A7799C94503571A62CB0657D94A483E4500C60E3DE494E34B5012C550D6CC9794134635EBDB9D6D9352318CA1B84C36D792134936A88C6F2AA5BB675791E6AAD18391E68086A27E19E1AB900601445F00EAEBA1A1727AA496D655C46F7C52FEEFB574286465C4EE858BD84A286B1C91C8D078D3B4E850260FF8C54D3BE001768D7533C65CB708EE39F44E8E387890DD9164D66EE3D7BA51243615730D4C3B8EFAADCEC8B76D54AFF2BF1EFFBEEA4143A741FFC4C6D04B9C82ED71890EA9532C4EE10A8319F651AF75F9CD029003AA75B224003137BD53866FDF2664C83D1DA497C41BEF9E03E44BD0F056D25733005B12A414E17660DFD3281ABBD5135C914807713EC3E0A0EE87098914ECC4BE7252B34A05505463FAB1085409591B8CCF2C7E58F5AE8CDE06A8CB010A9154D0A224CBE0ECA525222CEF71656A63A06B6E47FC5636695B12180702C36E3BA943E5DF308D933C8426D63AB0686C0D01DCAC6AA2148359065B8E77E1F0392799B5F6C6BDA6B78D4E5D3894050DDCE23FE35ECBF3AAFBFF373A6C8310DA419C83987F11C79EB3C2A3242D45D2094B3C153113C1131006E61DB06823C940CD32918F246BA7A0D4BC7165D19992A2E6D750E79C3CBBB84935A6E8B5BA1EF596DB1DEFAD272F20EF26A0B47B2D37C8C56A010FA31F381D60310377534970D8B320841E5F86EABBDC970D0127531C88A58A1035D4EBEDBFBB4ADB3AFACB6C1929D55AA61BE34157634BCCB7C5F7D212CDB0B8055771056D65ED593B769C8FE91D30A011BFE4CABCD5B19DC1446EB032A8728F3CA4FB8A07D49109EE6C6E37925A1C577B211DB4231B7FFF9CBCD47E3EBBAB07890E9B40855C225D2413A009ACFF8C988B2B89655F500D6E171655542226419134FE6B636337FCB0389AD623EFA6C41B7ADBD01934354C4C5289927E637DEF00BFF6587B6D520E6B7975CEC897012E415DB69D80001D3435FB6417B6609CDCE98521F032EAE00B1551D2134CB6C9FE2215FBF14171C7F944243902A7293DC2047296C603771E6F63C0EA0633BCB46A1A6EA05DF0BE4A86EBB826FEE0598C304CF6AAD88CB88599F069D099DECF3D23923EBBAF15679211D97EFD5F2E2AAE19A721FA406BC38EB32194B8C466DC7CB3C8C559DF6C3E53729439C855D7FE29BEBF8B5D3830469403B77316C2D498B4437BDDFE47508E142B7148CA84DC12AB9AED7D9EF4A5ECE7F244F4C9B9C82D89F025F60BAB119A67FD82BBCD09BA6C00E288C5564D3E265F761414DB7F0DA4D030FC32C586361E4D6E0D1D2F2207C887E60D7B569B12EE084C440F41E8C1D29F7BFDE1E678AC3448B9F5CCD4310C5FCFB7324806CB0E55FC12E95DCB1BD86E2548DB8DC9FF858E7B7B1FF1A00E5A6DFE7ACB74A0A4C96537F7889EF4CFA37115529CB677256F6F7BBF11AF8636D3188D8C9AEA894B1FCB2CF7F375CD6B27C573859D697E487EC44F5F0E5A840C777DD23AEECD31A2FBFC56C5BDA7331443B7B7DD0F32FDE1F4D8F2A0B27E23FBAB0159614A911E4FCCC2F8D500A1356233C3CDD4F08F6A4B2DC7BDA2039C6F365B3E16057B0EC54FE55B832DA676983DE355D34CAB52C94381FCD3EBA37C8D10B12E376B1BEC5FF56EFF79C590720F39D63BEA9F826350183716BD8F1ACCB9CDEA6E6FC4344F5D2012E2DB86F5C4ED0AC21FEA42EA464995F0F24DDA662E0D35D16215A97C6AAFCCE9D53FA9110FB84B371461A26C3B4B74B8E83F3C21F253B06490F34FA77B2F943FD373F2677C794CCE389D385D229503A44BE6C86FE5F3AD9E8105A73C809273462B423272BE53062A2685DC0E65FEFB6F2A2DB5F4443E22295DCAAEC1E5348FC70E4A09FE187A0C99CCB779AB6E61C035098E3E85FE9BB9CC879B79CCA0DC3D7E3D1772AA0DE400AD58ED5B01D9F7A6563F4C02BF282FD56C730B326ADBA145BE901D8F5EC2370716709A451E5C2F22B1F5B3EC6B669E193990A5B96B7CFB61EC0D780D903AE72C1D53828B895ED9441ED97D5C7F2478B8A30ED70D3C79D0C07248E11AEDF13728424B7463B0A8237649431C140122C575EBD4D005FBE172DC7D501224E1D75E8BB12A9F99AB9D3C7AA13E2C547B9D3075ACA6FD4F9F718C3FBC627CF024BA61193DEC4C9AFA3CD802B592472689A39FF72505AD0B0F93B45893E5AA7D63BAB56232426ACF7CCA2C9209290F55C0807E58AC09B373707F656EE8FEF5CFFC88BD382318AEB977E70DF3EEAD8326ADCD956A2901E701475801B203D5B1001F0F391C815872F373FAED743FD19734B7FA8BD1E02D529FDF2444DCC8D14DE0CC5B6566CF98538788314B020480E6866EAA9D27788F22B4A3BFFCA8C6E656C530C52F513C98D7D983F419BE96E4FF4F018E0A393F6D03B288F77A25E8DD57CFA112C11FF7C60655931409C7D15C0701E222BAF5A3A47D0A39515A5EC283823ABD2AE7BC93D654B8B2244F061C20804A6BEFA05127B4BC4F06B7B5A8999C4E8305AF731D080BAC2F517C13A98FE71B282AFD986B60B0759BA49D669A846D8D5FC567FE48E38E09081D5415D5D850282D6BC9D5CE1478085E6612DD36F28E3F6D084ADA4D2B360BBA38AE5CA1ED5FA8303EE57F5BB67C5006B888765FDBFEA950D903A4B2375207E1D39C254BF6C879AAEFF0C5C182663075EE3E52FF95DF7EF8F28FA90992E44C1295D98E0C45AD7A13E0FA7A515DF1569FC499E0BA3AC9E86F7DF1C330F9F6049EEE79F5E96D39547D315CD33D213D98EE161CE741F4B712A1823E584392B580717649C1B8DC9F8E3717C816DB6233CFF8B2E35ED97999A534B288AC6C0410D0B4D5C37DFF7DAAE8FA43A1CB027A14A37A3B0AB65AFF3385CA05E83FD7DE65C300E044F43A81052B7FA33CC6D339BAF4818F0D1396EE275F56447AB6167CB20078D01CEFA8DE3AC8FB69D3D2857D4BC52C708BB65A1E4AD33E1B0F4B8E0F099F58CA642ABA9DE2172A978219FFAF1CADEE4AA5C8735BFDD277C829F28832F9419942F46D67B455FBD6885726AF6D67DB5C8306D5158B92FB353B764D79931A9696CC5926548E6A3F548DB5569C617EF2E17125D2C20AC07A5D498F588E2CFB00227DB91BC5AF59BCBF2CD733D098F61715178F05E03B1D9E6A6513FC1E4B6B7D7336030E7DE7C6585620F69DE08E53402826C9178E1423484BAE2D36ED3B919A1095DDAF45F76ADE2B700D71772F250EE41A41CB92933D2FAD81321473852E13F711569A5141EA1F88B7AA46E9E2F38C9AF904C9DE1B17B8A30931014A42EF05F31CB5FB2FD33D333913312AEA1C90A69BF1AB3F71E255DFD858DAC0DCC3EF107781596D8C6E0F764F6677A746D08A6548B616AB0AA1C1B696E4A8F55554D5438DAEFCFDC3DBA17C66D59E399B8DD0382C9CEB7E74820D876F96B7E7CA5DF556C9FB3D9387FD6B91C1C2C49E19FEE5486A7C327AAA808804BADBA153549618560CE1EA14CB5CB3986BC0D2FC9201258174B9216B497466F26F8940F935C73B5E9C5A2BE8A978120CE2A56D2D292BF53FDF3E117EEECD631AD97A67ACF25AC7123848B96FB851611DD9C8F3948B89623B2D2F64BD1868098650EC702745763E7C320642AB48E854BC144AC279672B5F56FCB430BFFF5D7203CFBF7732ACB1B1E0B763F00FC09582682EDDD2080678A8308F4D10CF8E20DC8657143D79130C3E99CDFCD07F5E714E940D421D9C78E79226726649BE3C8ECCB08BAC9E4C221AE1E16CE9E7F583910B7AEAC4ED43DEF7276823099D2ACED856288A43EB239BE8E4B6EE907C9198383268673990082EFCF45335C1746450B4E9FF0BDD6EA7FE91F2AEF93DFC9D2FEE725B94D2C9B3F69BEB3815787B989E3920B0CF68EC31E0FEB3777B6E58425E915AE753E52076D359FF02D239B7CD91CF684E1C823171F7C700FDF74379BB4FB62DCF4D8F53A52A4E456F4938439CD3299A720C16AE993F4411C8849B06DDE0102E6A304D52893E7E6DB3CD445B2894506AB95E0B843645204FFF9FD3AD4C365E055CD88677A718C4838E3DA76067685C4B7B87FD88456E95633F00EF8AE13FFAE778F6515292820C924A287E00640B74361364D4BF324AB10A1EA76140D97FE8C75927B48E2F776A4A69B37FCCB9E469DB599C5B194F7D37B359EB6A0CA52090997CF714254F4236AF93FA0950EFC0EA83B8704D466061E34E2CEEA106D872649FE3E6B9D2996FAB04B21585F4FA3B843BF350C9174F3F31AE851A0F4D99B28EB483C46BCF7F5890B4A59B15826A647BD24B766711234FF0E8218471BEAEF9F9EF714EB638BFD68B38C94095E69B59D0B0BA47AF19C19A8C70F1066DAFF7631E2E6CABD8B214A622A46B4AC2250B1F214F701284E860744387DE67B3896D7A442AEE7DE49F1AB1D501771A4486846D4D8B6A7C3D285E2B090085C5984B55545DCCDDBE5506DF6622600BFFE7D1D771E1B166D57A8D8555760DD7436BE8F96328EE2C6EE1225BD5849C5DB8E17A4E8AC72E1A7D33C30D38ED109243390A96E5535EC5338D6F2AD54A156C2B144980BBB7A3A514A0562195F27578DFA3F98E2AE3305DE82CC880AC90D731F937876548625E9A13B4C7E9F0E7E8FFD3ADFD782AB0E87A195CA1A6C93F7720A793EEA9FC03EE035FA2B6B84E033F3EC07C20829BC8F2B89A08E923FA31A8F6E2561CFE154B324C06A7F7C81AABE98F6EA7A2A4E7BDA7A132D5EB1225751DB370DE588ED7BB09C66C30144ED16B0FCBAB347C9018AD95B80353E67F8EBE6EFD0652F3EAB81A9510274EE528D12D18E85D5BE37D913BFA495FA07F83CD1FFCC965C1D82C5B34FB638D9C2E84A1DE4592A91BEE3A10C6EF0538ABC90516D72B9C116E68A8EA65F8568DBB7106B897DFD2788891F43BC031FFB391BCF53C3A57086C3D2A0820857035D792AF14AC5EE369720037762617D8D3A40392549132D604BB5A0C7EE5AFDDE5BAF92960863052F0F61DB02DCC3729FD6EAF30C149CB686DBB9EB82A3D48CE461778CE665A41CA98BBB75F97D5CC79D19B6FB835106AA648ACAA2A682443F74594D108565E72378F83D070109A0F7326C79D4F2B60437BE746CA64571A5DCDCFC4BA14C56F4687A99E8CC2D24507FF5FE785B047318C1283BD82AEC86D8C7B64530348674BBF54A94D0286D051F7F78457DEC0613BDA1CC48AD17573176A19DCC190D9C7E65FE360AF99FE7B08E3239F4BE44BB0CE1BA9E91876176BFEADA9CB5647F4EE40574AD4B50536745BC2901A980A533C9662C21578772324CE991271283C322B856A258886D9A31C2A4D0D11E981268977BF3DCDA0E849138E60A902FE2F488660BA89E79B1479A711F69DAE36DA825177B82C91B9F1A738E47BAAC005382B76E13F4CAF06507CD732E4F0882BA2A39CBE5D0F44CE8980857353D18C9FF1C467ABFA32B5FA97925B7EAB356D7BCF7242E8A3D5CA3A9EC2C99D78DBE65F38BCD7D9E9C8406FA951667A18295E6C9CF18A8D1B67E600AFA48C1F6E39828E2EE2BCD1B82CCBBF2EF68C3EE3778F05180FAAA55757492F5EA6E456C69089C41DC07A5A63407F002CED899145DCE6299E0ABE0C264D7BCB0130AFF8183EF06FC1C47793150F91EA1048DBA18C13F77E66F09FA5D09FEDB29D90862D63877365BCCF7F7835003060F34CC223983CA4EDBA1DF263B9E368553416A084E592E0474C8F499BA349F1A89261385006EE8A8C5D85EDB0A0A3BA4A49715126FE4C9C1DE9C8A9FDA9416726B771963A119A066805B6B1B3143D49AFF8A5F4391C1D583A49BE962F71146093E3C3C4F4A5671762693FE680FCEFD710353B2A619BD86C2E849D5E57CAEDC9EEFD9A6FD386F9C9C242AF57928C6504D37F905C6C3EA5FDDFF43ED8250B3A2F01DB256D1D625A7DF5A76109EB3E040F15A255BE32EF76D07F02557E44C317F754487E26983039AE29D3BFC178E9E7391672130478E719218C364A4DB06CC058F724709459C6CBFB70B9BB8AC139841E241303C1B2F8C4F4CDE02D2C933A7CB563564707634ADCB04F8836E02208A62DF2C9B5BEBC8CAE819BA5E93EA3D3D9519306ADC3EDAD6532D76A397F72E531C9555CC98E3F3D96C0A611DC86A4364DC894E539B1298F327B95E643467C85785A41067EEB3E782117515AD99CFD8F53DA4A48B5E28C0D4097A1DADD3DC0C5FAD81EB71C7D9E51D083482A02B51E9ED2D0665A85C0A8A525D78FD60089DCAA10ACA3D617AB07BF2611943DD9C4F83749130FE5D90BCD1AE39E1C187EBECF8C9883FE5C529B5CC3D3840C776D090CC6E534AFCCC019FF477AFBF3ADB6F3C88135B89C35D8CDB9250BD5951CE412FE45BA7961865A872DCCBC62A52BD3237C1802D25B223C177096E9737CC25C15ECBDF51E1E22310DE3B28BB90FEE7281042781E1C34B75681DB7FFDE6B4E8E4EB07BAF847A4393656F3A999648980CA27B75B307C2171CEDBFB0B74768DEBEA0DEE6DA35F065FC6CB2761D6053EDD8194C43D70665078F45D183124C1E3CCA2C70AB38235992E7FC26A1CF33011E35C4BF027B71DCC8779A236746302FA323668AF39A6FF5EC46894BB2659B0B0083CDD5D27E96BA480A643F361541815B55175123A370560583F7977271F94136D19CA52547FA353D5C0DFEB0F20B22590AF375B3A990892C3EBA0634C2FD3E3F1BEAEFA0416B473321A1A888FC880D390F4CD16AA531C0E07AEAE5ACB86F88CD1D708DCA145C89142DFD66E940117D176DF8C7E69A499B9DE2C7B8B26A8D76C121C7BA8313EF1623AED855A78DFE41DACD81E74A104B332651931430574710ABC508A7CC9645574DB4064174565F8DC6EB5046F303A44AFAB2E17026F4E1721B49D48E5A9BED5BE8D7B2B40CBC081312AA5A95C28A2B81008FF5E1792A3E9EECE9074E65221B1DB3F9B5BC01F0C509FF5734300860F5951C2CC926BB6FF70B57B43E45B446AE6FDCAB8FD187E1208849ACB075013A3B8216F8D1A99D0A0054C40578F1B0CE747C1B3D01BA416E161E3EB5468BEB873FABD96DD26D0CE5661A11D1ED9A21299818B02642AA4C5D63C39500AF59A558365DF0F13E30A02C723CD6520C42FB1416102A479688BB4426E360F6479CEADE6AA7C867B593542D772B465CC47BAF8242524EE10F202498F7D1E2525A47AEF803DDA745637D834C83DA2F4EBB40883372716B2B2B19AA5718B1BD0926192B8388DAF503ABE6FF2E4D9CDA68CED764554F05B81D239C0E9843E4D672872491452784AE9936335AAA318B42EFBD19AC6B6869B93161842DEEB268C9657EA2D1C5C498E26629A4E638DEC294A109166C1A50E5604750006FEB1E44B971FC43205487B321E074B90FDE7B1729453EB5610484A490932142CABF933B8F63B69849509E4E8018D0D1572F6BBBE17E41201BF40008D8E5273479975ADF24A26BD781B875C6E30D0749054982E652F955CCF62FF5B2941804FB8137CAC9EA7E3A3AA33A1852D09C206FCE40AD6E04D892976188D37393DE2FD8409317D277DB85762A55CC6A900C0C836626C47C808EB274EDBAFA3D0AC0989C725AF06421B216CCE2923A9A7B660093760FACA20D9520449A237FEBC06982FE68E58A3AFC91C4B2328501352982B2AD532F48EC100A80914A73F92362743AD4134E66A9A0ECA0DC6F6FF2F9C7BF2A00A015FFB8E65320DA600C4C4802E740EB19B0C1B4184DC12272FAFEB1CB68B8CFC20CE17D541A092DCC6EEA3C019C2B26BACCA7F67C0295677DB08A5326EFB66E22225084D0A2CCE8C7C865731DE18F14418DFB12AE4C27D19549ABD49813B419E2CB787E7742DA32BF886AFD144069A7F3DE47128A263FE363F8DDB014176237D78294ED0D681A7A726ACE9E5445E1C946667C55FA323D4A0663C3B3D151A162E4CC2C66C4601DA654C3F53B2C4C586FA7728A46A753883772F47F3BBF9EF19A9ACCCEFBB45E53232ABAF10F258C41E4CD1FEA3E52D7C1059D81DB704D26A2DEB0B4788033F70AAA3785CBAE0DD486D87A39380B2C4319F35534892AB9748443CE5A2C783C79945FE7ED225E1069BE87504FE4504F0D99941646146FAD22338335D0013039FF848942CE513BA630D9AAB006D835167AFA89C2D51B22CD446DDAEDE42A59C7D1D9A84AACD6336E5373AE47CAE957B6F24F3D15D9311A393DFA0A99EFC9291B21E21CEBBFAE0722969ABDA31D0DA2BD0C3DC84AA24BBA13C13A3CF20BE620BA28832BD4A59527F134FBB4BEEB1F6DCBFA6284B66A167993F3CD5317236C4BCA396DB547B2DFA536876D7EC84E8CA6AF6DCD717588775CF9133110B9789A07D6ABD3182C7DFE12C609B34439DC2FFEECA68F505503A57AFC2C9B4AEE5168EA940613611D8CA642CEB022506ADBE3018BB7A6B53195BBECD649318D9EBC8E96F03280871106DBE61B95AE5C73EB0FAFB47EB3BCD6D81CAC7DAC430382B8E536EC65D4BBD54E93A875C066479B05079C1CB45ECB4BD7B328BFFDF4CE60F2184A9CFD9BE8D9117C972DC2D0342820762D0464BE4FAFA814976B22FCEC0E1752E9527DDF1C6E57C469E41B8EDC47177AB2EDC94A9B71C464E335BE5F741F70BE9102B9623438D04F175A358170057F11BE67119152458638495B7CAA857985AEC77ED77909A9356C1F27B672F3FD60DA1A24E619086DB7A1E7C834BAD78F937B19700C7CEC7F38AF9AF3761C34D313F07937CB11975BF30AFEE6350D2DB5C9E99E8FFEDEAA1D7EFAEBBF114BC0709A2FD5739A4B61A793A54DF253156FA089387C2F9397A9BC02460A7091C9F2B80D503B11911696ABF9EF9FEB54383C7E05553D418466BD895917CA9891B37376A3EB80EEC8C816506AB888AF00FD56E25AE2A856C9B7AA1598F65981CE483FD7D32CB9F689394B297D107AAC6740245019BC5C692FBF12547FED4711103D931D8E958B65AE4C51735879D3AE8DB4F73EE5D77FC5DB41EEC6162A0D83ACCD6DCAF1A4D752CB0B26903C2063DCC606C29D58333BD1C8D8B3FA2499C3316D36DC64DF455F03D1EE363EF3D74CE94972C3A464BEBA2615BEA481F3087C93237CC9542A8F84EA94A12E1ECAF6301ED1242F0BF1C1E976E501B8101F8B6CAC1CAD6C8E17C70942DB8D2890A339EA56DB4696596847DFB4ACD8AB26CA9EF206C794BC830BA5F47C98EF1F0F1252BF7F51C9C37D88365FAA2AF0539A254366D52E1F460A490B46CEF1E70B679C0C8191BD9BDC3DA597DAD66EA6B12D68BAFC3958F2DB8B3702685AEF62EFDE71116AF13F0045D36829D306B7D6A5117C538106E0BC97CFB07DDFB3CDF041B4B636247F8EAA74BF9B51241F0C847564EC677E5C4934570EE88E166C9CA18F67550F9E34776267EACD15CFB809DF20A9343A84FE970530F1F5B694A3F20FED045CAAC2ED108CE251B6DE6BA97CBE456B11A33B9BED3D915AB9D290D7F0B37AF2DCB6DB6F6F7A2A2DB38F50906C0988964FD1DE90AFF7CCFF335B3AA5468FCCE9197429BD09CD32BEC78FC63B21B4233E67F985FBC596B62BEE4FDD9582C82EF684B67DB538F22E83F66AD54A2268E86AE283D0233DD7F784B63B75A817DF3438234AC2B20C44308DFD4DD0EF157DCFBBE66F0B6CAFCFF5C394125E09CBFC0FAE9E4EF1C1B183E0620319DE7BD4234DE7F1AEC9976DE9106B05BD4F81431554CF074642021769CC5A3F242E7AAE5AEF7CCFCC7FB3D2AAE162E1C81D62FBB2B84E86E3FFB11757108EFE4B1F5AF447BB3C01F1CA199D71FBB597C241CF5DD80CE95CD45AED9AC39211E004CA19EDFC175843D568AB3AA37CF1A3211E1A4741DAE5053D26A227CAF5DD622B764002878050F8579EA97B3C8B706F6CDCE0DB2DBDC2C5F006DC35D79C1FECCA604EDE199071A659E3ADA5612F1AB680D16A94EFA58D00A39B2C12797F3BDD3B1C5A99FC4675841D0975ED48F237A9B09E14A0096579753A74CB38F8DA9FC6845D08764FF0FCD1482D10A8FAED9E4C4B901568196FC2D822A99EC9A9B19352E4D968043B6CA72D51233F512BBEACEE372CB229FA9DC828DD9A76BAFAD9B818567C608524D59448C658EE3AAA94467011EEC589A87D0B86397CCF979F5870247C950CB89BA34DFA35DFF8FFFB2D7A8DFA76AE022D828836F0191DB883E7F35FC1CDC6F39F3AA9770595BE6619132AB774A41F22F366F9356BB60B89CD0EBE5B676393BC0E6C1660BD173B12443E93B75A8DAC24F6DA06CB0B9EE79C06BC785279D823A54B0029B1A1C423E7DEA94312407443C318C81EF74D3C039DFE74F7DD98108A633FD535C336A15DB3FDDAE84952CD557FB6646289CDDD399157E3B46D27E605839FB841E5440B61F049D84D6745A92F22F9B0657C185BAA08B4561786207CF245497360D201CB63A7EE713F4CC2DDB095ED2C54ECA12F915E82873BEC43102D3D13BDE31B8F015E4EA536699A02E74FBBA684689C951214AD280A700C449072702C34F854C00CC34DB8F8AD24358A0C1773B0C4CBD0B32B0ECE2F8DA167033973A53BB8880D0E668AEE2D9A9FC7BECD9A511852C02502D20BC4359259C7054526B4AF27DC692392771EC68AD3154F8F6B752FD569002F00AA4B1E664783274DD17E0BB4E75827078926C23E4F51CD6190F89ED41ED9012BEB44F251FF49E2AFF95505A5274E110C5907FBCB8BFACF896146C8CBF8D363089B4FAD3A9CBD875E6F89905C86E533A9E2782B10DDBCE311420CB7521D3009578C3ABC4CDF63382508FBE6525C8F063BC4500AD441ECFDB63735DB30F2CEE6C3E145D8E2F808D2B91D10F7703977CBE97071EBC97415CAB34AB5A8952CC4398ECBEF766AA3D7533796086E465AB8B762FF042415B46B623AA44CC165007F4998C3B899A1131029EFA133E454019EDF44362870C9B444E94C8469A67C956D7C3D3E9FD8399559120652ECA8BA20EC859D0336BED6B0B8E971BBA0BD400FFFB4B1FB86E3FE5CA55D52C2DAE24CD81AF13BB413D6D65E57BC033AEAF43BDE17B5C212F5E2C362A6F7EC455AEDB7CFD3C28B63F15B9E1E212E55E9355595799FAC1E4465B5FF65C337E5A3990659A504F9B59F472D49DBB891A388D744D42F8E24980FA493578B93484F275B50B7F28FA9DB39F0EA766DF7D08E104C6E15065CF24C055C585D6A57606537BD7C49B19810816392DBF7FFAFE0AA1BAB364C441F38E3234A0163C87A9F91F6B9704F7FAE710582F2321F333368CA502287B4C297025D6AF5003598FCC38DE509B5A94231B9AE0323B1EB40E5B33C33D8047AE6FADFB594AAFED86D1E1862871FEC42CF63DEBB28BCA762E20609175726649D5E15E9B78D9D7A652B8C18C75C1CE5C8B71C2B454324F76A2393CAB59018AD9DC5CF475E1F64086E5BB30EDA2ABA4ED5342F2B14E9EE3645B1A81554E1056E509684935F31736D2999060C79111FC5BFCCD4C883A88B00B1ED866FA79559CF0F26C2FF2A785FA1DA400F984D1BCD0C4E2108E9BBE84A11C8763C7E41688FFC6A0D4E6E1FB49166B3E5119E15B0A8075F4D057E215EB73C2DC28DBDD27E156609ECF9B1680A60B051E8C8A3D1DBAA60327F9774F10B11A1047C2894463DD91D4684FFAC4FDFBD7962B899E6767F8BF0053DDF70C230BB6492AA5685C9B564E762893BF1728FDCBF565D4D060901C221220855D8BA9573EE7618D57795121DB4CC36FCC08BB0F16CED331C7107562C3191308FB3D24C2F2A9057F0E20AC5AE0B965105CEDC4B8F938880352A0206B8AADE2301900EF8D57E3982D671C75BD92EFAC36943DC5B5CE0BB57AA4E30F5FAE3CA4DD9F7640F0BCE55909FD8892AB7E685346A6131CCD485E55A2B13E358F327E67AA40B1AAA06D0C543915B6D8759CE948689613EC81F5427F66E78F954EDE3F35E90EC4621F97E1262FDADCAB0533801BAE543E3877A3139313DFF9BEB62331B2B83DEC963ADF2C7A41EF04A9AA44EF27F0104D738F240E4FF069775B59FCDCC9E5ED5736449D01A21A95A00932FC6A1C8F956C51AC0E54BD1C3BD17D6A0BA8E20D2A77953D9843384C432A6261391CA32DFB43DBE911863BB048A0050233720F394AE88B31FEB8DF594F51B1FC901CD7B5EA76D2E74B731C9702F4760D4E9B20E5E64F142FC67B9392EE4E25F9507DD7CEBA453A60A79A3AE650567F28CC7FB3925B50BD0FDD0D09463417F8C1F366702EA99D8B11DB87DE44CF01435C0881A034EED6323CB2F412B10EA64CF5C4874D021B83231A724A52FFB9ECD799484C6D0CB5AAEFB9BA922E0B105123EB107AD4A5C0722F87C5DB2AF3FE0909ED5CAA2161C37D63E41374966399E6B49FDFAD5CA4C6FEF37F5E604F170451B58659A9CCE3869F6A0D7AC6C646468A6E191FF15AD3B358CDE7FCAEFD82D029E2EFBE25CFD4673F27FA50C91A174D6587E8DF8C292CD3793E12864E8C58DAFEAC9DB16AD1A4F4824CF3F1C8946DDC6652FF9A06A6B52B8C5E8F19EEB3AC24CF44F203C348A0CB5CDA091334FF56C70A9A3F525ECFF9F7038083FF16EDBFF0D15CCCD68C4687B8D8F4FAC06D26DFE04582D3D6F492D1D70BD5F82D186DF4D388DFFFE3C324B5B889B27BCFAB3B62DB3CD36AE6688A5B7D4CB72F97A3270CA3E6B1D409DAAB4F5A5DCC22F635ED80357054EDE1584AB2C075A7308ECB9DBDD6C9CAA98BACB022F38539962498664A887A4B339243A272C3A67DDED6E53F7D9518FDE264CC9601D4C09CB664FAAC6ADD3FDA94BDEA7F576173C5E459A2A82B7CE0F94875DE458BA5B7552800D097BB6C7BBA09C8EC501A9321E653BD089A67E0DD17A5E5A5D8B310D5AB524C1510683E0A319782CD982E2FFA2A42F1A3C426422FD790827474EE0CB3B8AE951F820056291323500DB2D4A235F4CA5383EE1858D65285CE76A844424D5C66FAFC1CBA30C0FC8596C1B7F33E35320BD6B05EC63AACEF7D9F5889AD2BFE078A51BA87B3EFFC8C577F50C7C63F0E9D9AA63DF49FBCA71E3A240F8C77778660FE7A7346EB6F1408F7C5308C38EA4274D615DAF07E0CE8C792D02B99C042D9CB32F2518C724A8FA0936DF6FC280DDA2410227E96EF4254092D227B76E4E7D8A295830C6BD34C747E89A1B0E83BEA029B8F0287B52713D23CC2457B572C7602AB7FDB33D07EBE6F3136A70B9E2FC710937FF54D4E7A91617C82B2B542114D93060FCB53EEE5050C796AFE050FAECF2272C0AAB1A3D3664DE2792F6683385774052D56D0114C92AF4302E828501876A0835589B093B365DB65E0AA1DB6C4134E9D66CB16E1B5E6CF03ECA562BFDE45D2245BB262DADA06298A408BA6452F3662CE7548E858EBC79BBC7C602C48C6816235B6C0643F5BF76D60F3710C4F677A7EA3CB2397F8AE74B960FDEA0995B3E531C3229558D9F15988EA4EC950F6F6A939B76F74C4E82DD549E93625B4F5F77DC079158C53B98F44A7E2008770E695F395B28182F939BCEF87E5625A4FB2CF90E7EF16549378F23B4845008E70F8D8047B39B20B8F3E52DAB497DAE626237F1419BF55CF5C7E79636DE7568DC9C8386020718B3B867107D58E4D25DF65C590F2083A06F0A09A04E3DD44ED3413E1C819225AD68CA16F3B62A10761F61D6B7CE345980706578CE3DE4357BE7C8C266EDA674243ADDD65358A1A1FE0A1D99A8A2201BEFF68DED00FDD694F5EF45A833A1BFB4F40C5C1D061C81540FE78B3C09BE25BD088934EA947EBFCC2AB5FBB5A15173B5609D2E6279DCD2086D9E367F4C8DC45F14C511C72C29E940B6E54741E9A864F6B3D802D9E0E5C11C57D106B64D4D9FDCD6083A30E97AB7E6A5280E12FF95F10B7E8F187EF37DAA881F94ACCBD8E226181417AD93D2DEE5542E1EC3B015C0365ABE3DEE46EFBFCC4AE176A8442B844AFC03A8867846F2B56F9EED963850B4A6B9821C362BF07C38FB9EEBB9D7B5EEFE1C0F145196F82E83FCEED7CF0643DE6C115404F7A037CD43B0794593739C3609056C3771E1B07228743AAF3BF2FAC2809B1E64B72D07F93D705CAB483D750F72C2A0183AB03610E17C17594E51298E7F773308D041B5B619AC8B0E03E38968C3B079E82CB983BD86DF4AB1FDBFB6DC05B5FFE4C486D9C1351E5C428557C5D976DE18046C1E770DDED81584EF284346EFDAED440B609B1B78BCCB72C9B5F1C2C2C075DED249207B575A13EA907C0DE0F808C39D626259051D9FDF950218B5C4622F7C0673B9EA9E81041C5D5DB0636B5331F3F1388F40A98F50FA523D0033249F41317FB769D42097BD68EE2DFE9FD0D87CDB508E8FA8DDBB99D54E11D07F8C097B4DE7389B0D560EE9E5A5D722C6A82BAE5B285AE6E31962ABCDE821F82601535A778E955E211C8F9C0F00A61434DA177A6DF7FDEA8957EFA2B14F8C3A2067E3CE6D364F3D31B0DA16B447717DA5C3E8602A7DF0B5B45394605A713297B6FD281DCE032CE595B02CE74981F79C26093767ED0663498A1B670DB31681CA0950E7B2FEC7F9472802A4486942A3B98903CF078095957A13C8CC7BA989E77B0EC7D35A982E31B30DC5E94FE4E8809E3972AC5392AAEC15CFE41BF6A884E5D8F826AFBFC4CFBF88F853E512F3EAA7B61505F3E2FDF934C39428534317718397C515085969A9EAE816ABCE967C8A6375DEF19D88810F507078AE82257699AAAE7C7374EF36683AE333CCB5DCDC26D84C9A8A9FE033AE9E4FFEF340262A3CCF266E1F654C2D626E3EE8441B2484BEAAA7F3BC65DF634A28496AC94A16CCFE6D9104FE8F01CF653380759AC4FB03A6D353FAFC36677D04D8AF3BD2A9E29D2446DDC52974202067F97C68C509643319DE0B72615695128EBF371D4CBE06AA975E9E0FA8C38D9B99C83E26A47D5709D12B9C680928B6964E2ED7CF45E67251704BFBEC6C9F860A9CA918F73F64B4D06AAFA75B3DFF9A560BED6D2429E0900E9498B0335ABABA7CF083F1C2B0194951E690FD56AF2A265E2226AFF70AE89979B413A88FF20499F2E07ECA7BD2191F7904C1AE238422B48B4509C5F2120A23FF31A6DC12835C3BE4505EA2FD282F11427D149FDF87A36DB30E93B39AA313541C443D1CB55A8AE0FAAB74107041B769E98D817E244D5951366776E0F8DFC8A542E114E74353D1CE8876A75F096ACE6F41196CFCEDEE3E3B7D01C91CA94203C0433BE725F0195CBF04D6B47A569D65E722B63EE355AB2462743C4126E8630DCD7B730D5548F1392524AF4621BDFCEB6E142A90A0B5F300212C9D75FEA9967E35E5F8DB2EC6B63B4F91EADABB2BD4E2715D037B74352BC0DC8A9416C57BF563FC53DECE2A3F31D00EA9E024B19A53CC318FA53D8D24120CB86881A454410E2A346C8EF0309F787776E49756416A0BF8B0C2107A2E091BA899C07D596BBBCBFABD71C9C7F94D703B028BDD246BA8565239271B776FDC59605495F23E948D4F1D0CA1A499453800D45701674088BB1E0675D4F0C991C3E2CF3806BF50813AF6F56833FE199EC6F40126BD2C2A912CCDD9E0FB6EEE054BFE088DC6F89945E15D37459D6426632FFD52455AA908461ED4F5096F45059DBDA4F328272B8D533EEE3CEA5354E7B1416F5C1F85CDC4305A4A54E8F9B140E7631C63EA98F8B04C023080A8E2E3A86524419BCABA4340740F73B647B5C168BBE821190FE4411D91AA5A20DBC665BCD24CB63205A714F1F8FD1E3530052EA08B333A7E2757B80857C0F6C01728119B4D764D4800C889FDA2B3B9AAEB4C587DB3F93398A19C7B8409F0D7B98B40450DAA5FD5A0D108090FC27146CD68528204F8CFA80D2030926BA36D3AD1D7A239B9C7976CE466D65AE947DB91CE89A1BCBC4CA81EDD23A25CA33843D0E596BE0438BD7899B148350416B8D752C2F7A5CBDF1E57970C0DB6C8C8470455674A0D7AD880489D9F29773FA7F497C5F29ECE4B10F425A623C7BB4D12EA3BC3F75FC83C094D706281FADFA7C3C88082F6DBF66F6AAD75C5571BE21A30C1DE05F7F8145FC3E9606C60C0B1672EFAE3878D5B738F8C203F43FBBED0DDECBD7BCA5F6E657D878F6B020EC06466080FF9C56A71052CE4B4BC24198E8FFC0B10FF445FE7784D45E2E07CB7DD4B982397051929E8FCB2F327F917410D097D69A3DEC3323752D1C5AE55845F122F3250ACE19E158B15B672FEE5B27DE459F7DFAF7D46A1E20A680818D641335DFB2DAEB85B9F5CD8A74E22025715D6A79DF312FABE2824D2263884118C2651BE716C79CB455DD41C3F55E3BD27CBE9789E2D7845CD351B43C13652E3AE1C33069FB5EA2D4C3410963235463E36E682952C85204F913937132328DBDC84E479D2106337677173C9BF4AED7A62D2E450D982E33DADDB02931459FF7C96FE0CA4722BFBF2477357040BB0413AC401D6548F7691FD528BEBF08C120419845C622A4EAC33E441C080F97E6DA5F0409FA9BAC760FBC1A3919206A98DE42A4269D0F7A58E709A921BF420D3D47E1D1911A7117E74181BEBFD09B9B81F026DAFF19BAD0A8F45B9DAC3D67A727310191D0AA7C8AA0C0A79D7DB225CCF4C1F0C3685CF76E504831B505275B6868B85D8DF0797D15AA6D533A928D9E375835B72CB9923846958AF834464ED9701B13835E03C4B27C5F6A8BA37D530CDFA93B5DE4825A69E5C919E2E29105EC47EBAE88243F496BDF91A72D119F26E5228639C932266126717205C890B96FAF31CC909AFB349AB5A923B31F7B97DB79BE2EC6569C3E92E6F979FC7269E7FE9A3463BD0CAFCA662716F2AAC1002225556215F419CFF504C8F658F640E5A87987962AFFF5BF59A2D62AB24C4F35E8B24E7115C19BEA2871851FDC92CEF661FA3AD29273D13C6AA4163D7346A29FA6468183B9DA5CE6279F5D6B7BB815B41FD3BC782B35B7EC2D03A75B36640F6565434BA9BC144A1EB24937DD5DDCEF8EC5495046E949018FCA240FE51ACEFFEDC268905BC80278A0D1F5409E605CCF90818E63F32DB02ABFDA174F36F7FD4249C4C7006D10BBAE571F3A656DB0E01F1285E59664A6637457826E359DCF3158D30D52762F30EB0E4A94F3A2283C61A9854435C48080A9E8D96021D3B92986FE8DB113FF666C8CE7FF4F78DFB4126C71359EFC232FD749D00A68BDE31F8B0F64F4C28EC627E32CC2583BF771C2C4C99B04EF9CBE453B9BE088212BA446A4935870A83A1702B37437A666180EC915A8E7711FA16897EF5B91837B59EE598D38D4CDC94E27FF0679864F064D3199113FFE0D121CC49734DB7EFDA3A3C368FE32D685B202FBCA5081B854A618C730225D6C2144A343DCC2B1BC31CEF8EF0ABE5BEF44CBC8D4788A2F4F71533B8BD9D01C1A76193AD3DADCDE897D894F39C666B11D085B6D27DA7DCDC1F2CE7DE93C63A9E1D56704772F2417123EE095485B39FEB8D48D6FE7948662A877C52DE9A1BD33F733392F035B7017189941920761ED922006C211D66A25BB6B2788492C4C7EF388955AC3A52C9D946A0A37971386ECB5B383C8E5EC8F5E2BD5F6B4A29E7F63F1DBF4E79C442A202FD406BDEB495892CF2A9A9BB3BE5F45571510DDA05F7DC93A14312D774B1DE2E40969ED959E8D89441FB593007B52D1C97215A66BC6DC6788B527A339298FB4D14896C20EE15740B6C996A37BF8BD71FFDC1301A052A96C9741C268133DBEFF05E9E7E114B186A801F5D4CB4C3580F180115F117D872B8D1A365AEA409557BB13D036A3F1D18CFA4AE3B538EC3943EBF64C8C43104C1CFAC83D0E4A983265659B1727BC2641C4C1A4325553830FA0197D867F6EAE646F699FCB62C984E63951B007534C04A692C0BCCEA335391EF5511B49FBA2DE4FFEBAA29F105D9A9888C06DDD3EB4BCC9C15F5A4CD5D178996B18B9E451F275560BF1C5D071540D4FAD7166A51FFDF1E01BF28BE295A1CC244A01E8EE0189A6298A82C4B93B43CD9059F819AD62095FA4DC190288A778EF5695AE0E14C0B647FDD8ECCD6BC386AFA828C5EB8BF8C26E37F30C115C7F527382C19BF2C731E8405100631FEB104BF00E0F4AA0B10BFBB0CB302193AB3C033388A2D100E220A50A08A6AF272ABC3DC426D88C7EA5E2A986DB35650D807D830E5DC515A6B3780280CBFB83C1C60DD9300F00C25BF5774DFA657285AE1748A9840ED993262CA5A62B2B29FCDDCF46911B80DA06BEFE7AE2C9B2225BAE78E8DAB27175D78A96A5AC7AB4C851343C3B103D0126FD6FCBF736A0D62F1B0E2CD059B7ECE554368F104E76DA6839C036251965522D3B421FF34D09A1566678B8B0A68031A22373103D63D1E7E34406E968E29226B6BAA6DF6EC027399E8C7ED179693A7BA7C52B73869436E14F83548A65A901003FBBD59F7E55BAA38809E06B612F05B21FBE96C2BBFA824AF4819686F8BB97846A12F312144A10E388C7123E396C0F107F55B88105CD7323D353FC1A64528AE57FC7FF6958A25DA869E8F552A3F247170A4B2CBE093770280371D26D120E4CD99D42D5FEFBFA7BFE2E372181E73C90FEDDCB7E6A66FF9882D6F5EB9D2003E3F16FE9A22076E92DC5047706F6198D419E8F4FDAF7E84F2CB2CF98B342E74B8E6A605F3F5D3504B2EE59A73E516D3FB4CBA40B9D165682A95A5643CE5EE949041E320CD96852DD37573395AADA4A644D500A70BBC565236637D293BC21927F786BCECC961D0946B02660F7C3BD2BCE0398F3A05456C9D7B698FABB0A0C9FB75D830EA74513030ED001AA6657083E7AA02043CA88BF244D8997A9A51759AD10380719EB1506F8214AAF4126D031AFE2444A8622C80F9BC0CA1798F06B557A9CB0613934A6B6E9F6334004959C44758B68BF067959A78ED20BB90FA4874DD405AACA5991AC496A35E5B6B64DC54D17C743F820F96EF14BA3EE8ADC6DC36DAF14D3B49E9C9940C5CEF190F90D7C7298F1586942F190DB541216F34F2AC06B304873E3F82BA907BB85D646DDD99BC004278E78FF60E032EC82058A3A7DE2C64A55CB4B10C89C6D5C11C9B3E342EC8920DBD0A38A830CA2FA8517FEF6051D21C7284FA56BC53B67761A021D51C78A38B66873DD0C0F5029017BE6B823382C8E68555DF30E5ADC0D46F65B99014863CAE4D92DF3D17EC97DE17EE486A262A2F50348F6975E46006C6CF4233C1142792B8FBC74F1705135E092AB022AE44114B298BF5B5C95B597909482EB32CC79AE2477FC12E2BB6858240994A5015C67129BC5CAAA35C368D854285D39F9EF873374A70EBD302DE85871A5C9AB7B8348533D5857B01CD45AB1912BD34992C255E4F48EE35BCD4B9214B4E087CAEA03A6CE4E67124A5DDFAFCC47307F127839D9969E46A32B9EB76449C7406C25857CA0D332D0082EF24B2C58B8AEEAA935161D0EC4735174DA1E5ADE682084E3DC61EA3F0747E4570520AED3640DE434AFE4075C6900801EF1330808F35937CA7E089134134A206FAD5DA95542DB57D1ADF8293020A6DC11A2AED289976214DC1D7BDD07016ADCC3E62D9D630C0DBD7EEA8EBDC5A40E20B47762D14213DF9B6FF690C3655A7DC399D80FA81DFB22730AFCD03544C0A3ACE1210BC044B0B35B6D630630BF13F2FAC2B9294660C95A3678199B8C681B0BC38A53B5322864717BF2023FAC93B207DC6B2D7E2229D3D1FE5FDBA576C3DD1F2AC94A7AE50B2214DDD00745A33AF4C87EE1A4D1285853AB0788B50C7DFBFC63AFE9B1A09932D309FDD80E563DC69E75674DE56D6F1A09E9CE973AC5A65C394193EA2B563A7856382837C4110EE9B39CE38F61FCE965804E43EF191422A270517501146ED4DE717F93703CEC3C6F2508008CF2935E57A5D1894CA6B5FEE5AFA46EA10A4BB3A88D3BCADF01FC22264754876E3FB0D4AE47F611061DD1BD4D4B8DD324D6FFDF376BA43EC3D735CA6912066DDFD53B619E4D7EAC5F24AC6D1667FBF1220D132FA0B1D45F5753B6495EE702CD80206E1AE3228B76F054234A129E19253A799527DA5444B796F907614AFB46BC4A3EFBE6309BCD109D0BC7FB13CF14477C9DFDA7F9F06C03F346616FF89B792DB6D624B8560456FEF03648014DEC140926580460A20005F68534CFCBC60AAB3E70049BDEA9BE72ED6D77899D0948593BFE9E86F515FA385DD0100BC5311050AFC28D650A2367BAFED9B46CCECDBC3686E2E2A68C7819E92FA95B4C35466EDFD42E387768325C5D069B5561F6DE56F167160A747795613A310CDCF11B0F20DC97E79BEB0B85608D4A4DD1F9A763179D7C6754805101268962F163607F4AD655419A9F83C0C7F952351C4F958958B02C8F89930BD04A823B455E5389A6E7E42D3C88651B07F39C893851E0020B3E29193513AF26D0E713E721E7F228BEA6F5359FBCFBEE7305D13A13E70433EAA0914F67232971484B6F71EC8011D59E5584F66AF1E4BDE497F6B0823108E1F2FE6E3AFA96BBC477898E66223F4D9C2D147C2CE1ADE7F89AE237FBA73EAF34BAC66A6200BDF2A5374C965E0949136865F3DC7997C5A56A0CC11D5839534CB38B19359672F87F38B436AF8330CF5140BF2CD791231C00BB6837A636ED6D1A84FCA4379A4A3D428B4601B2DB2E7DA7FDA0B5C89E2F5EBA9AFBD2A79DAFCC4BC923F792D7B89B947EE754F2ACBF56C7FD5F3E1C12E57838991E42E7696763BE2345FEC4BAE2929B340BB9D7324706FA9045A1A5926ECF6C28961FD6B0E47FAC5B30001FA5174444B88705F26B7434DFF57FD455F8FB5DBC03AF47480FEFBFC618BA636565694B0BBDFA4972388A7C2361EB3E60F1409FE6FB7789D4737E192B20ABEAD4C47CEA3C4F1CF1D6234099EF1000A0466626814625091E04430BD5975400809A2B32FDBD9709A720BC3E98F43D34A0B21B48B19F2F2360D6FC63CCFCD75E4BC92BEC930ABD4695D77BC4E3AB5BFC728F6622C6B884E104B223BD755B9463C73CE758C2803780864661B6AE8896B837B1742E691EB7D849039DFF1DB4DD94A5F4CA329442D0C88C82FA757E6A5B59B50D350300A05D1B1080952B4B592F6BEE7ED6E00CCD708FB9B00CB82715466385A68F736AF5E8851794ED1B15F010F5BABD580BEA08575B477D0C2ED9720F7B9DB1C0A36346230E4A7F60FABB90E078AFAC520994D0A3246E23DC956A1693C14FA53FBC8F6F4A32DC368D737600346D541626E53A70FCD6C7241FF72F704B56E00FE7CDE1FA0BC661C06E0BA8E53526316CCD4D95B5B1A7963843D3E770886153A9F07878513556D96B9A9975BD3FEB9AF8B590A0D694A2B8A05C472E710AD0BD3CE0D5A486171FB6EBC86881DF263030B93872B8FFFFC25AE2183D36B745FBF77AE3A4AE1E20CC0161D6D25E0073194875EB63037D090D24814B7C216AF36C730C3511E7CD078E6DFA2413CAF021519EEDD84BF080FC2855C56DFA417B1BC780BFB493D4E188DAC1F5AC22B10086FB25C6CB36B063389FE23967ED7DB0216B324BEA5E3BBB681199DDC3E20EC52AB4BEC2BFA30771A1DC93FB9FBFD3012654E2659B2BA50CB4576C0E5FD754802D6EED142641015E2F8611FC086FE07B0EFBBB558DFA00EA6CFA4A88B10F622AC9F88601C7F9154D96A7ECA64AC94BA8447ABC3BE3CE52FFD7E4AA099DA0E8F94FDE925E1531407DCF6B424BCE09C50A32A5A28FA918D55F9034A17E4D960B33F5F12D913217AD71A2AF22D11470EA8CCB1BE9BFB2136FE7CD27A0E1018EF3EADDFDA3364660812C3F6FDE5CA5693422EF482AE1FFA3203E8A484508DFDB05B9B09A59C6127A61C2E0741B197FD5B0953263E6104F97432742B0B961540AD913607B47C19AB724349E137021AFB4E7165048177FF0EC91B3D97702606359FD7ED8F462FCAB76588737D608B39F8929ACB8E75986E7AA9B3F9E247B8BAE1C20EC718E8029DC04ACEB173FBDDEADC7D8832DA4A706E9AC3E0FB3AEFEEEDC929275DB6C87E808A9D767D5B2410C1F4703A7332B462026925C109DF008BCB88D4B8E00FD48B9F4D9A9ECF183B86B1E4E92A0B0800FFB5D9B952F2DB2E1A7919249365071A9EF92643FCC42DB8D2238CE448CAA2554649C54169F0CE03B954D0AB967C6221289A1C87BC6AF70D1E72B8317DAE35C090E745334F1CD614D4C5EE39DD1E51FF620E5B1D39A7C037B2C9167470341F11A16C090F6AF93DC74CDAA9AF7A127A32474836ACEE3C1DFB02715198C8ECA874E28AEC8AE59DB426122BE9FF1F5216FE65183873249A5C19F79E61AF2E333616BA950B2056D1DAE4A87527499009435C0D8323DDE5A27F4248FA58FB8A8396E1EC18CBBAF1C5C01BBEDC96E932F4498A4F12213732D8DC521AB56BB995F07C393298231EFE664245ED02FC19FF139D47FA550E47A3A884916958434733101844FFDA1037E7F4A85905EB7D8DCBA2B3589202678AFB4607C5FB482DC96B6153F024ACB774C7426A088720CAB5E509479EB6AE309C25837911D321FFFAF6B5F5D746C2D1CA870F9733313EFA6349169810376D73C9EE0477CCBD3D31AFB111B28D47BB1569D0B1F174493A4B5244E22391D7F15C7DBB9AE01459329D5F58A4DF2393AC208362E50489B87E3E9A7D5473F9AF417E366F4037AE71B7CCCD0CEF85A581B9EE38FC45510A48403E12564288C0BECD1BBB67C4318F52A88867E58220FA43D88004B4FADAC785C6C85B79FFC6FEF97F75989A665ED93D77A78638B1C214EADAFC24B007B2429FFA1E9ABDA087D0911DED012DE1D7366507CA44BC5CFDF805BEED4CDF2BB8E1DA6F4EB154B7E503F9A7DD9B31B7612A38118567951D184AA6829D69B7089A559DDD8C4B21E9535199A0479B1B7085072505161CD528BD82BAE9ED2C30665317280BAE1BEF3ED3434C7A02B243FD9E3DE7671CA7D7A907D3D23E2EAD56A74B1A047AEEBDE58CCC9F09301F87C8C24B9B3AC129984A6EC4D0EC7541B96759FD8764CD9BAE4FBF0E2166389446A41AF86187DCD54CE274E346397EABD20B1076C242FF2B5D9BD7173B22CFE852BF092E19D850575304710EB1A91AEA36AF3D4E57BBE9FE0134E8FD7D5C35BFD06A8920F109CE7C2DC3A32720081542DA5CF2D7A72514526CB428319C1A974B88C848080058B7C9F5EA80F68073B57FFDE037CB04162537460FFB630B53E1BEDF303DE5A137654D7386C62B44C8F98914B0F27EF7EB55FE726656C8BC9A4B93E09C224699F340183C25D5C2F8A11153255DF5E749805A9BB0BF253F846ED4E87D12D517C508059F6B0790B8850A462BAC89BE0CF6DAEAB971DB73E93B940CDDA05740C4E2F7AC115A75F280BA7ACE6B237D84991CC5C1E0C45AFE44EEFDF3F119CE0022EDEA602254626A5A7CFA7AA83BB12A6B57A989344F5D3CDF41224A41F6217BD52B8E587E1314228C8DDF84C67A02A54D46B5AB5DED1DEC3D0438F2B3953B8E620D0DEE39914242B4569648D8CD7C42896589B014C80EBBA772A0F0F32F559445EFEAFDF2DBC0DBC9FF1F4F0DE478F64729DCEFACD9864591C18FF8D0E7BF049BED035D42C6E00AB3AE5362CDA40FC5F0A8243068F9B910ED5611CCF037889C81147FDE7E717DDAB3B49D1FA18BFA025357C2AFA9D2DEDF7D5D86ACF06CA5BA7D40C7E8431B6E7E4EECD9F2361D726A26BC2382011A3CD1F7CCB625C0E3ED17E54545C424AF277A1FA03C1974DA63107F58D8ECEA6A5C468F249A5AD50D222529C79C25214508A1A0C6D5F48BBDD19A467D005E7599CDC0879F0BEF76020F88360410C2D87FD0855D4019C0D80BF68237F07D31A126C12C130C78883D6E958E272D2D3E6AA26F7F83838DA49563E8C21289F554AE7A10E214C299573104D0185BF7C27FD5708FC278506C0C5B458B7F369128F8FC93D625A74C3D47F2480BBDE060816057090E5BA46C4E316F7D8EA80C496EE046D7511499DF23D7ADBC69F722A48A90CF2F3A7C84ABF3AD8DBA94058F7C492C4D619462AE241F99F3B121D0890997FE43B087AD8B60C3BA1BA9DBE8C79B42A143C47181335BA92CF4701CB07D5F9537A1C7338E9B12D9C0664C8A2F2E4720AFA5047CE290D39DA6938388E9A05982FB83BDE723E4444A78ED7B4F22F25FDAF70C814C0ED5246AB643E183A34E33ED050AAD6D9F5128ED66CBF378F24D85C00DFC6E2E10588FA635D57F0E4D98EC84F690E556B8BB5AA9D71AB2C01F5B6EAD743A165DD151D591FD2881B83CA1563AD72D439D9FAAC1358B39E1F3BF05D67ED69023C843799BE6C5301D921A633A70CA87CB1A1C5F8BC931D37ADE608F52633EC11452352ACCE6605527D5123DFDECC2CD2A78E21BBA233F1A378F98DF25 \ No newline at end of file diff --git a/core/furi.h b/core/furi.h index 681855d0..80aea70c 100644 --- a/core/furi.h +++ b/core/furi.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + #include #include diff --git a/core/furi/memmgr_heap.c b/core/furi/memmgr_heap.c index 8e57914e..3fe7822c 100644 --- a/core/furi/memmgr_heap.c +++ b/core/furi/memmgr_heap.c @@ -387,6 +387,7 @@ void vPortFree(void* pv) { /* Add this block to the list of free blocks. */ xFreeBytesRemaining += pxLink->xBlockSize; traceFREE(pv, pxLink->xBlockSize); + memset(pv, 0, pxLink->xBlockSize - xHeapStructSize); prvInsertBlockIntoFreeList(((BlockLink_t*)pxLink)); } (void)xTaskResumeAll(); diff --git a/core/furi/pubsub.c b/core/furi/pubsub.c index 0722d2a0..3fbcb51c 100644 --- a/core/furi/pubsub.c +++ b/core/furi/pubsub.c @@ -1,88 +1,95 @@ #include "pubsub.h" -#include +#include "memmgr.h" +#include "check.h" + +#include +#include + +struct FuriPubSubSubscription { + FuriPubSubCallback callback; + void* callback_context; +}; + +LIST_DEF(FuriPubSubSubscriptionList, FuriPubSubSubscription, M_POD_OPLIST); + +struct FuriPubSub { + FuriPubSubSubscriptionList_t items; + osMutexId_t mutex; +}; + +FuriPubSub* furi_pubsub_alloc() { + FuriPubSub* pubsub = furi_alloc(sizeof(FuriPubSub)); -bool init_pubsub(PubSub* pubsub) { - // mutex without name, - // no attributes (unfortunatly robust mutex is not supported by FreeRTOS), - // with dynamic memory allocation pubsub->mutex = osMutexNew(NULL); - if(pubsub->mutex == NULL) return false; + furi_assert(pubsub->mutex); - // construct list - list_pubsub_cb_init(pubsub->items); + FuriPubSubSubscriptionList_init(pubsub->items); - return true; + return pubsub; } -bool delete_pubsub(PubSub* pubsub) { - if(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK) { - bool result = osMutexDelete(pubsub->mutex) == osOK; - list_pubsub_cb_clear(pubsub->items); - return result; - } else { - return false; - } +void furi_pubsub_free(FuriPubSub* pubsub) { + furi_assert(pubsub); + + furi_check(FuriPubSubSubscriptionList_size(pubsub->items) == 0); + + FuriPubSubSubscriptionList_clear(pubsub->items); + + furi_check(osMutexDelete(pubsub->mutex) == osOK); + + free(pubsub); } -PubSubItem* subscribe_pubsub(PubSub* pubsub, PubSubCallback cb, void* ctx) { - if(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK) { - // put uninitialized item to the list - PubSubItem* item = list_pubsub_cb_push_raw(pubsub->items); +FuriPubSubSubscription* + furi_pubsub_subscribe(FuriPubSub* pubsub, FuriPubSubCallback callback, void* callback_context) { + furi_check(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK); + // put uninitialized item to the list + FuriPubSubSubscription* item = FuriPubSubSubscriptionList_push_raw(pubsub->items); - // initialize item - item->cb = cb; - item->ctx = ctx; - item->self = pubsub; + // initialize item + item->callback = callback; + item->callback_context = callback_context; - // TODO unsubscribe pubsub on app exit - //flapp_on_exit(unsubscribe_pubsub, item); + furi_check(osMutexRelease(pubsub->mutex) == osOK); - osMutexRelease(pubsub->mutex); - - return item; - } else { - return NULL; - } + return item; } -bool unsubscribe_pubsub(PubSubItem* pubsub_id) { - if(osMutexAcquire(pubsub_id->self->mutex, osWaitForever) == osOK) { - bool result = false; +void furi_pubsub_unsubscribe(FuriPubSub* pubsub, FuriPubSubSubscription* pubsub_subscription) { + furi_assert(pubsub); + furi_assert(pubsub_subscription); - // iterate over items - list_pubsub_cb_it_t it; - for(list_pubsub_cb_it(it, pubsub_id->self->items); !list_pubsub_cb_end_p(it); - list_pubsub_cb_next(it)) { - const PubSubItem* item = list_pubsub_cb_cref(it); + furi_check(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK); + bool result = false; - // if the iterator is equal to our element - if(item == pubsub_id) { - list_pubsub_cb_remove(pubsub_id->self->items, it); - result = true; - break; - } + // iterate over items + FuriPubSubSubscriptionList_it_t it; + for(FuriPubSubSubscriptionList_it(it, pubsub->items); !FuriPubSubSubscriptionList_end_p(it); + FuriPubSubSubscriptionList_next(it)) { + const FuriPubSubSubscription* item = FuriPubSubSubscriptionList_cref(it); + + // if the iterator is equal to our element + if(item == pubsub_subscription) { + FuriPubSubSubscriptionList_remove(pubsub->items, it); + result = true; + break; } - - osMutexRelease(pubsub_id->self->mutex); - return result; - } else { - return false; } + + furi_check(osMutexRelease(pubsub->mutex) == osOK); + furi_check(result); } -bool notify_pubsub(PubSub* pubsub, void* arg) { - if(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK) { - // iterate over subscribers - list_pubsub_cb_it_t it; - for(list_pubsub_cb_it(it, pubsub->items); !list_pubsub_cb_end_p(it); - list_pubsub_cb_next(it)) { - const PubSubItem* item = list_pubsub_cb_cref(it); - item->cb(arg, item->ctx); - } +void furi_pubsub_publish(FuriPubSub* pubsub, void* message) { + furi_check(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK); - osMutexRelease(pubsub->mutex); - return true; - } else { - return false; + // iterate over subscribers + FuriPubSubSubscriptionList_it_t it; + for(FuriPubSubSubscriptionList_it(it, pubsub->items); !FuriPubSubSubscriptionList_end_p(it); + FuriPubSubSubscriptionList_next(it)) { + const FuriPubSubSubscription* item = FuriPubSubSubscriptionList_cref(it); + item->callback(message, item->callback_context); } + + furi_check(osMutexRelease(pubsub->mutex) == osOK); } diff --git a/core/furi/pubsub.h b/core/furi/pubsub.h index 2f440e1c..446d423f 100644 --- a/core/furi/pubsub.h +++ b/core/furi/pubsub.h @@ -1,95 +1,64 @@ #pragma once -#include "cmsis_os.h" -#include "m-list.h" - #ifdef __cplusplus extern "C" { #endif -/** -== PubSub == +/** FuriPubSub Callback type */ +typedef void (*FuriPubSubCallback)(const void* message, void* context); - * PubSub allows users to subscribe on notifies and notify subscribers. - * Notifier side can pass `void*` arg to subscriber callback, - * and also subscriber can set `void*` context pointer that pass into - * callback (you can see callback signature below). +/** FuriPubSub type */ +typedef struct FuriPubSub FuriPubSub; + +/** FuriPubSubSubscription type */ +typedef struct FuriPubSubSubscription FuriPubSubSubscription; + +/** Allocate FuriPubSub + * + * Reentrable, Not threadsafe, one owner + * + * @return pointer to FuriPubSub instance */ +FuriPubSub* furi_pubsub_alloc(); -typedef void (*PubSubCallback)(const void*, void*); -typedef struct PubSubType PubSub; - -typedef struct { - PubSubCallback cb; - void* ctx; - PubSub* self; -} PubSubItem; - -LIST_DEF(list_pubsub_cb, PubSubItem, M_POD_OPLIST); - -struct PubSubType { - list_pubsub_cb_t items; - osMutexId_t mutex; -}; - -/** - * To create PubSub you should create PubSub instance and call `init_pubsub`. +/** Free FuriPubSub + * + * @param pubsub FuriPubSub instance */ -bool init_pubsub(PubSub* pubsub); +void furi_pubsub_free(FuriPubSub* pubsub); -/** - * Since we use dynamic memory - we must explicity delete pubsub +/** Subscribe to FuriPubSub + * + * Threadsafe, Reentrable + * + * @param pubsub pointer to FuriPubSub instance + * @param[in] callback The callback + * @param callback_context The callback context + * + * @return pointer to FuriPubSubSubscription instance */ -bool delete_pubsub(PubSub* pubsub); +FuriPubSubSubscription* + furi_pubsub_subscribe(FuriPubSub* pubsub, FuriPubSubCallback callback, void* callback_context); -/** - * Use `subscribe_pubsub` to register your callback. +/** Unsubscribe from FuriPubSub + * + * No use of `pubsub_subscription` allowed after call of this method + * Threadsafe, Reentrable. + * + * @param pubsub pointer to FuriPubSub instance + * @param pubsub_subscription pointer to FuriPubSubSubscription instance */ -PubSubItem* subscribe_pubsub(PubSub* pubsub, PubSubCallback cb, void* ctx); +void furi_pubsub_unsubscribe(FuriPubSub* pubsub, FuriPubSubSubscription* pubsub_subscription); -/** - * Use `unsubscribe_pubsub` to unregister callback. +/** Publish message to FuriPubSub + * + * Threadsafe, Reentrable. + * + * @param pubsub pointer to FuriPubSub instance + * @param message message pointer to publish */ -bool unsubscribe_pubsub(PubSubItem* pubsub_id); - -/** - * Use `notify_pubsub` to notify subscribers. - */ -bool notify_pubsub(PubSub* pubsub, void* arg); +void furi_pubsub_publish(FuriPubSub* pubsub, void* message); #ifdef __cplusplus } #endif - -/* - -```C -// MANIFEST -// name="test" -// stack=128 - -void example_pubsub_handler(void* arg, void* ctx) { - printf("get %d from %s\n", *(uint32_t*)arg, (const char*)ctx); -} - -void pubsub_test() { - const char* app_name = "test app"; - - PubSub example_pubsub; - init_pubsub(&example_pubsub); - - if(!subscribe_pubsub(&example_pubsub, example_pubsub_handler, (void*)app_name)) { - printf("critical error\n"); - flapp_exit(NULL); - } - - uint32_t counter = 0; - while(1) { - notify_pubsub(&example_pubsub, (void*)&counter); - counter++; - - osDelay(100); - } -} -``` -*/ diff --git a/core/furi/record.c b/core/furi/record.c index 85d196c0..29e33caf 100644 --- a/core/furi/record.c +++ b/core/furi/record.c @@ -84,8 +84,8 @@ bool furi_record_destroy(const char* name) { FuriRecordData* record_data = FuriRecordDataDict_get(furi_record->records, name_str); furi_assert(record_data); if(record_data->holders_count == 0) { - FuriRecordDataDict_erase(furi_record->records, name_str); furi_check(osOK == osEventFlagsDelete(record_data->flags)); + FuriRecordDataDict_erase(furi_record->records, name_str); ret = true; } diff --git a/core/furi/stdglue.c b/core/furi/stdglue.c index 4755c7ab..bd4b11c9 100644 --- a/core/furi/stdglue.c +++ b/core/furi/stdglue.c @@ -2,6 +2,9 @@ #include "check.h" #include "memmgr.h" +#include +#include + #include #include diff --git a/debug/PyCortexMDebug/cmdebug/svd_gdb.py b/debug/PyCortexMDebug/cmdebug/svd_gdb.py index 3acd014f..2629a3ce 100755 --- a/debug/PyCortexMDebug/cmdebug/svd_gdb.py +++ b/debug/PyCortexMDebug/cmdebug/svd_gdb.py @@ -22,6 +22,7 @@ import math import sys import struct import pkg_resources +import fnmatch from .svd import SVDFile @@ -101,13 +102,6 @@ class LoadSVD(gdb.Command): raise gdb.GdbError("Could not load SVD file {} : {}...\n".format(f, e)) -if __name__ == "__main__": - # This will also get executed by GDB - - # Create just the svd_load command - LoadSVD() - - class SVD(gdb.Command): """The CMSIS SVD (System View Description) inspector command @@ -321,13 +315,19 @@ class SVD(gdb.Command): container = peripheral.name + " > " + register.name self._print_register_fields(container, form, register) - else: - gdb.write( - "Register/cluster {} in peripheral {} does not exist!\n".format( - s[1], peripheral.name + found = False + for key in fnmatch.filter(peripheral.registers.keys(), s[1]): + register = peripheral.registers[key] + container = peripheral.name + " > " + register.name + self._print_register_fields(container, form, register) + found = True + if not found: + gdb.write( + "Register/cluster {} in peripheral {} does not exist!\n".format( + s[1], peripheral.name + ) ) - ) return if len(s) == 3: diff --git a/debug/STM32WB55_CM4.svd b/debug/STM32WB55_CM4.svd index 380e4c3d..9011748d 100755 --- a/debug/STM32WB55_CM4.svd +++ b/debug/STM32WB55_CM4.svd @@ -1,37004 +1,15 @@ - - - - STM32WB55_CM4 - 1.8 - STM32WB55_CM4 - - CM4 - r0p1 - little - true - true - 4 - false - - - - 8 - - 32 - - 0x20 - 0x0 - 0xFFFFFFFF - - - DMA1 - Direct memory access controller - DMA - 0x40020000 - - 0x0 - 0x400 - registers - - - DMA1_Channel1 - DMA1 Channel1 global interrupt - 11 - - - DMA1_Channel2 - DMA1 Channel2 global interrupt - 12 - - - DMA1_Channel3 - DMA1 Channel3 interrupt - 13 - - - DMA1_Channel4 - DMA1 Channel4 interrupt - 14 - - - DMA1_Channel5 - DMA1 Channel5 interrupt - 15 - - - DMA1_Channel6 - DMA1 Channel6 interrupt - 16 - - - DMA1_Channel7 - DMA1 Channel 7 interrupt - 17 - - - - ISR - ISR - interrupt status register - 0x0 - 0x20 - read-only - 0x00000000 - - - TEIF7 - Channel x transfer error flag (x = 1 ..7) - 27 - 1 - - - HTIF7 - Channel x half transfer flag (x = 1 ..7) - 26 - 1 - - - TCIF7 - Channel x transfer complete flag (x = 1 ..7) - 25 - 1 - - - GIF7 - Channel x global interrupt flag (x = 1 ..7) - 24 - 1 - - - TEIF6 - Channel x transfer error flag (x = 1 ..7) - 23 - 1 - - - HTIF6 - Channel x half transfer flag (x = 1 ..7) - 22 - 1 - - - TCIF6 - Channel x transfer complete flag (x = 1 ..7) - 21 - 1 - - - GIF6 - Channel x global interrupt flag (x = 1 ..7) - 20 - 1 - - - TEIF5 - Channel x transfer error flag (x = 1 ..7) - 19 - 1 - - - HTIF5 - Channel x half transfer flag (x = 1 ..7) - 18 - 1 - - - TCIF5 - Channel x transfer complete flag (x = 1 ..7) - 17 - 1 - - - GIF5 - Channel x global interrupt flag (x = 1 ..7) - 16 - 1 - - - TEIF4 - Channel x transfer error flag (x = 1 ..7) - 15 - 1 - - - HTIF4 - Channel x half transfer flag (x = 1 ..7) - 14 - 1 - - - TCIF4 - Channel x transfer complete flag (x = 1 ..7) - 13 - 1 - - - GIF4 - Channel x global interrupt flag (x = 1 ..7) - 12 - 1 - - - TEIF3 - Channel x transfer error flag (x = 1 ..7) - 11 - 1 - - - HTIF3 - Channel x half transfer flag (x = 1 ..7) - 10 - 1 - - - TCIF3 - Channel x transfer complete flag (x = 1 ..7) - 9 - 1 - - - GIF3 - Channel x global interrupt flag (x = 1 ..7) - 8 - 1 - - - TEIF2 - Channel x transfer error flag (x = 1 ..7) - 7 - 1 - - - HTIF2 - Channel x half transfer flag (x = 1 ..7) - 6 - 1 - - - TCIF2 - Channel x transfer complete flag (x = 1 ..7) - 5 - 1 - - - GIF2 - Channel x global interrupt flag (x = 1 ..7) - 4 - 1 - - - TEIF1 - Channel x transfer error flag (x = 1 ..7) - 3 - 1 - - - HTIF1 - Channel x half transfer flag (x = 1 ..7) - 2 - 1 - - - TCIF1 - Channel x transfer complete flag (x = 1 ..7) - 1 - 1 - - - GIF1 - Channel x global interrupt flag (x = 1 ..7) - 0 - 1 - - - - - IFCR - IFCR - interrupt flag clear register - 0x4 - 0x20 - write-only - 0x00000000 - - - CTEIF7 - Channel x transfer error clear (x = 1 ..7) - 27 - 1 - - - CHTIF7 - Channel x half transfer clear (x = 1 ..7) - 26 - 1 - - - CTCIF7 - Channel x transfer complete clear (x = 1 ..7) - 25 - 1 - - - CGIF7 - Channel x global interrupt clear (x = 1 ..7) - 24 - 1 - - - CTEIF6 - Channel x transfer error clear (x = 1 ..7) - 23 - 1 - - - CHTIF6 - Channel x half transfer clear (x = 1 ..7) - 22 - 1 - - - CTCIF6 - Channel x transfer complete clear (x = 1 ..7) - 21 - 1 - - - CGIF6 - Channel x global interrupt clear (x = 1 ..7) - 20 - 1 - - - CTEIF5 - Channel x transfer error clear (x = 1 ..7) - 19 - 1 - - - CHTIF5 - Channel x half transfer clear (x = 1 ..7) - 18 - 1 - - - CTCIF5 - Channel x transfer complete clear (x = 1 ..7) - 17 - 1 - - - CGIF5 - Channel x global interrupt clear (x = 1 ..7) - 16 - 1 - - - CTEIF4 - Channel x transfer error clear (x = 1 ..7) - 15 - 1 - - - CHTIF4 - Channel x half transfer clear (x = 1 ..7) - 14 - 1 - - - CTCIF4 - Channel x transfer complete clear (x = 1 ..7) - 13 - 1 - - - CGIF4 - Channel x global interrupt clear (x = 1 ..7) - 12 - 1 - - - CTEIF3 - Channel x transfer error clear (x = 1 ..7) - 11 - 1 - - - CHTIF3 - Channel x half transfer clear (x = 1 ..7) - 10 - 1 - - - CTCIF3 - Channel x transfer complete clear (x = 1 ..7) - 9 - 1 - - - CGIF3 - Channel x global interrupt clear (x = 1 ..7) - 8 - 1 - - - CTEIF2 - Channel x transfer error clear (x = 1 ..7) - 7 - 1 - - - CHTIF2 - Channel x half transfer clear (x = 1 ..7) - 6 - 1 - - - CTCIF2 - Channel x transfer complete clear (x = 1 ..7) - 5 - 1 - - - CGIF2 - Channel x global interrupt clear (x = 1 ..7) - 4 - 1 - - - CTEIF1 - Channel x transfer error clear (x = 1 ..7) - 3 - 1 - - - CHTIF1 - Channel x half transfer clear (x = 1 ..7) - 2 - 1 - - - CTCIF1 - Channel x transfer complete clear (x = 1 ..7) - 1 - 1 - - - CGIF1 - Channel x global interrupt clear (x = 1 ..7) - 0 - 1 - - - - - CCR1 - CCR1 - channel x configuration register - 0x8 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR1 - CNDTR1 - channel x number of data register - 0xC - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR1 - CPAR1 - channel x peripheral address register - 0x10 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR1 - CMAR1 - channel x memory address register - 0x14 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR2 - CCR2 - channel x configuration register - 0x1C - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR2 - CNDTR2 - channel x number of data register - 0x20 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR2 - CPAR2 - channel x peripheral address register - 0x24 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR2 - CMAR2 - channel x memory address register - 0x28 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR3 - CCR3 - channel x configuration register - 0x30 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR3 - CNDTR3 - channel x number of data register - 0x34 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR3 - CPAR3 - channel x peripheral address register - 0x38 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR3 - CMAR3 - channel x memory address register - 0x3C - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR4 - CCR4 - channel x configuration register - 0x44 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR4 - CNDTR4 - channel x number of data register - 0x48 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR4 - CPAR4 - channel x peripheral address register - 0x4C - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR4 - CMAR4 - channel x memory address register - 0x50 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR5 - CCR5 - channel x configuration register - 0x58 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR5 - CNDTR5 - channel x number of data register - 0x5C - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR5 - CPAR5 - channel x peripheral address register - 0x60 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR5 - CMAR5 - channel x memory address register - 0x64 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR6 - CCR6 - channel x configuration register - 0x6C - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR6 - CNDTR6 - channel x number of data register - 0x70 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR6 - CPAR6 - channel x peripheral address register - 0x74 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR6 - CMAR6 - channel x memory address register - 0x78 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR7 - CCR7 - channel x configuration register - 0x80 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR7 - CNDTR7 - channel x number of data register - 0x84 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR7 - CPAR7 - channel x peripheral address register - 0x88 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR7 - CMAR7 - channel x memory address register - 0x8C - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - - - DMA2 - Direct memory access controller - DMA - 0x40020400 - - 0x0 - 0x400 - registers - - - DMA2_CH1 - DMA2 channel 1 interrupt - 55 - - - DMA2_CH2 - DMA2 channel 2 interrupt - 56 - - - DMA2_CH3 - DMA2 channel 3 interrupt - 57 - - - DMA2_CH4 - DMA2 channel 4 interrupt - 58 - - - DMA2_CH5 - DMA2 channel 5 interrupt - 59 - - - DMA2_CH6 - DMA2 channel 6 interrupt - 60 - - - DMA2_CH7 - DMA2 channel 7 interrupt - 61 - - - - ISR - ISR - interrupt status register - 0x0 - 0x20 - read-only - 0x00000000 - - - TEIF7 - Channel x transfer error flag (x = 1 ..7) - 27 - 1 - - - HTIF7 - Channel x half transfer flag (x = 1 ..7) - 26 - 1 - - - TCIF7 - Channel x transfer complete flag (x = 1 ..7) - 25 - 1 - - - GIF7 - Channel x global interrupt flag (x = 1 ..7) - 24 - 1 - - - TEIF6 - Channel x transfer error flag (x = 1 ..7) - 23 - 1 - - - HTIF6 - Channel x half transfer flag (x = 1 ..7) - 22 - 1 - - - TCIF6 - Channel x transfer complete flag (x = 1 ..7) - 21 - 1 - - - GIF6 - Channel x global interrupt flag (x = 1 ..7) - 20 - 1 - - - TEIF5 - Channel x transfer error flag (x = 1 ..7) - 19 - 1 - - - HTIF5 - Channel x half transfer flag (x = 1 ..7) - 18 - 1 - - - TCIF5 - Channel x transfer complete flag (x = 1 ..7) - 17 - 1 - - - GIF5 - Channel x global interrupt flag (x = 1 ..7) - 16 - 1 - - - TEIF4 - Channel x transfer error flag (x = 1 ..7) - 15 - 1 - - - HTIF4 - Channel x half transfer flag (x = 1 ..7) - 14 - 1 - - - TCIF4 - Channel x transfer complete flag (x = 1 ..7) - 13 - 1 - - - GIF4 - Channel x global interrupt flag (x = 1 ..7) - 12 - 1 - - - TEIF3 - Channel x transfer error flag (x = 1 ..7) - 11 - 1 - - - HTIF3 - Channel x half transfer flag (x = 1 ..7) - 10 - 1 - - - TCIF3 - Channel x transfer complete flag (x = 1 ..7) - 9 - 1 - - - GIF3 - Channel x global interrupt flag (x = 1 ..7) - 8 - 1 - - - TEIF2 - Channel x transfer error flag (x = 1 ..7) - 7 - 1 - - - HTIF2 - Channel x half transfer flag (x = 1 ..7) - 6 - 1 - - - TCIF2 - Channel x transfer complete flag (x = 1 ..7) - 5 - 1 - - - GIF2 - Channel x global interrupt flag (x = 1 ..7) - 4 - 1 - - - TEIF1 - Channel x transfer error flag (x = 1 ..7) - 3 - 1 - - - HTIF1 - Channel x half transfer flag (x = 1 ..7) - 2 - 1 - - - TCIF1 - Channel x transfer complete flag (x = 1 ..7) - 1 - 1 - - - GIF1 - Channel x global interrupt flag (x = 1 ..7) - 0 - 1 - - - - - IFCR - IFCR - interrupt flag clear register - 0x4 - 0x20 - write-only - 0x00000000 - - - CTEIF7 - Channel x transfer error clear (x = 1 ..7) - 27 - 1 - - - CHTIF7 - Channel x half transfer clear (x = 1 ..7) - 26 - 1 - - - CTCIF7 - Channel x transfer complete clear (x = 1 ..7) - 25 - 1 - - - CGIF7 - Channel x global interrupt clear (x = 1 ..7) - 24 - 1 - - - CTEIF6 - Channel x transfer error clear (x = 1 ..7) - 23 - 1 - - - CHTIF6 - Channel x half transfer clear (x = 1 ..7) - 22 - 1 - - - CTCIF6 - Channel x transfer complete clear (x = 1 ..7) - 21 - 1 - - - CGIF6 - Channel x global interrupt clear (x = 1 ..7) - 20 - 1 - - - CTEIF5 - Channel x transfer error clear (x = 1 ..7) - 19 - 1 - - - CHTIF5 - Channel x half transfer clear (x = 1 ..7) - 18 - 1 - - - CTCIF5 - Channel x transfer complete clear (x = 1 ..7) - 17 - 1 - - - CGIF5 - Channel x global interrupt clear (x = 1 ..7) - 16 - 1 - - - CTEIF4 - Channel x transfer error clear (x = 1 ..7) - 15 - 1 - - - CHTIF4 - Channel x half transfer clear (x = 1 ..7) - 14 - 1 - - - CTCIF4 - Channel x transfer complete clear (x = 1 ..7) - 13 - 1 - - - CGIF4 - Channel x global interrupt clear (x = 1 ..7) - 12 - 1 - - - CTEIF3 - Channel x transfer error clear (x = 1 ..7) - 11 - 1 - - - CHTIF3 - Channel x half transfer clear (x = 1 ..7) - 10 - 1 - - - CTCIF3 - Channel x transfer complete clear (x = 1 ..7) - 9 - 1 - - - CGIF3 - Channel x global interrupt clear (x = 1 ..7) - 8 - 1 - - - CTEIF2 - Channel x transfer error clear (x = 1 ..7) - 7 - 1 - - - CHTIF2 - Channel x half transfer clear (x = 1 ..7) - 6 - 1 - - - CTCIF2 - Channel x transfer complete clear (x = 1 ..7) - 5 - 1 - - - CGIF2 - Channel x global interrupt clear (x = 1 ..7) - 4 - 1 - - - CTEIF1 - Channel x transfer error clear (x = 1 ..7) - 3 - 1 - - - CHTIF1 - Channel x half transfer clear (x = 1 ..7) - 2 - 1 - - - CTCIF1 - Channel x transfer complete clear (x = 1 ..7) - 1 - 1 - - - CGIF1 - Channel x global interrupt clear (x = 1 ..7) - 0 - 1 - - - - - CCR1 - CCR1 - channel x configuration register - 0x8 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR1 - CNDTR1 - channel x number of data register - 0xC - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR1 - CPAR1 - channel x peripheral address register - 0x10 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR1 - CMAR1 - channel x memory address register - 0x14 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR2 - CCR2 - channel x configuration register - 0x1C - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR2 - CNDTR2 - channel x number of data register - 0x20 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR2 - CPAR2 - channel x peripheral address register - 0x24 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR2 - CMAR2 - channel x memory address register - 0x28 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR3 - CCR3 - channel x configuration register - 0x30 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR3 - CNDTR3 - channel x number of data register - 0x34 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR3 - CPAR3 - channel x peripheral address register - 0x38 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR3 - CMAR3 - channel x memory address register - 0x3C - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR4 - CCR4 - channel x configuration register - 0x44 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR4 - CNDTR4 - channel x number of data register - 0x48 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR4 - CPAR4 - channel x peripheral address register - 0x4C - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR4 - CMAR4 - channel x memory address register - 0x50 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR5 - CCR5 - channel x configuration register - 0x58 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR5 - CNDTR5 - channel x number of data register - 0x5C - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR5 - CPAR5 - channel x peripheral address register - 0x60 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR5 - CMAR5 - channel x memory address register - 0x64 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR6 - CCR6 - channel x configuration register - 0x6C - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR6 - CNDTR6 - channel x number of data register - 0x70 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR6 - CPAR6 - channel x peripheral address register - 0x74 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR6 - CMAR6 - channel x memory address register - 0x78 - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CCR7 - CCR7 - channel x configuration register - 0x80 - 0x20 - read-write - 0x00000000 - - - MEM2MEM - Memory to memory mode - 14 - 1 - - - PL - Channel priority level - 12 - 2 - - - MSIZE - Memory size - 10 - 2 - - - PSIZE - Peripheral size - 8 - 2 - - - MINC - Memory increment mode - 7 - 1 - - - PINC - Peripheral increment mode - 6 - 1 - - - CIRC - Circular mode - 5 - 1 - - - DIR - Data transfer direction - 4 - 1 - - - TEIE - Transfer error interrupt enable - 3 - 1 - - - HTIE - Half transfer interrupt enable - 2 - 1 - - - TCIE - Transfer complete interrupt enable - 1 - 1 - - - EN - Channel enable - 0 - 1 - - - - - CNDTR7 - CNDTR7 - channel x number of data register - 0x84 - 0x20 - read-write - 0x00000000 - - - NDT - Number of data to transfer - 0 - 16 - - - - - CPAR7 - CPAR7 - channel x peripheral address register - 0x88 - 0x20 - read-write - 0x00000000 - - - PA - Peripheral address - 0 - 32 - - - - - CMAR7 - CMAR7 - channel x memory address register - 0x8C - 0x20 - read-write - 0x00000000 - - - MA - Memory address - 0 - 32 - - - - - CSELR - CSELR - channel selection register - 0xA8 - 0x20 - read-write - 0x00000000 - - - C7S - DMA channel 7 selection - 24 - 4 - - - C6S - DMA channel 6 selection - 20 - 4 - - - C5S - DMA channel 5 selection - 16 - 4 - - - C4S - DMA channel 4 selection - 12 - 4 - - - C3S - DMA channel 3 selection - 8 - 4 - - - C2S - DMA channel 2 selection - 4 - 4 - - - C1S - DMA channel 1 selection - 0 - 4 - - - - - - - DMAMUX1 - Direct memory access Multiplexer - DMAMUX - 0x40020800 - - 0x0 - 0x400 - registers - - - DMAMUX_OVR - DMAMUX overrun interrupt - 62 - - - - C0CR - C0CR - DMA Multiplexer Channel 0 Control register - 0x0 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C1CR - C1CR - DMA Multiplexer Channel 1 Control register - 0x4 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C2CR - C2CR - DMA Multiplexer Channel 2 Control register - 0x8 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C3CR - C3CR - DMA Multiplexer Channel 3 Control register - 0xC - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C4CR - C4CR - DMA Multiplexer Channel 4 Control register - 0x10 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C5CR - C5CR - DMA Multiplexer Channel 5 Control register - 0x14 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C6CR - C6CR - DMA Multiplexer Channel 6 Control register - 0x18 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C7CR - C7CR - DMA Multiplexer Channel 7 Control register - 0x1C - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C8CR - C8CR - DMA Multiplexer Channel 8 Control register - 0x20 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C9CR - C9CR - DMA Multiplexer Channel 9 Control register - 0x24 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C10CR - C10CR - DMA Multiplexer Channel 10 Control register - 0x28 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C11CR - C11CR - DMA Multiplexer Channel 11 Control register - 0x2C - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C12CR - C12CR - DMA Multiplexer Channel 12 Control register - 0x30 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - C13CR - C13CR - DMA Multiplexer Channel 13 Control register - 0x34 - 0x20 - read-write - 0x00000000 - - - SYNC_ID - SYNC_ID - 24 - 5 - - - NBREQ - Nb request - 19 - 5 - - - SPOL - Sync polarity - 17 - 2 - - - SE - Synchronization enable - 16 - 1 - - - EGE - Event Generation Enable - 9 - 1 - - - SOIE - Synchronization Overrun Interrupt Enable - 8 - 1 - - - DMAREQ_ID - DMA Request ID - 0 - 8 - - - - - CSR - CSR - DMA Multiplexer Channel Status register - 0x80 - 0x20 - read-only - 0x00000000 - - - SOF0 - Synchronization Overrun Flag 0 - 0 - 1 - - - SOF1 - Synchronization Overrun Flag 1 - 1 - 1 - - - SOF2 - Synchronization Overrun Flag 2 - 2 - 1 - - - SOF3 - Synchronization Overrun Flag 3 - 3 - 1 - - - SOF4 - Synchronization Overrun Flag 4 - 4 - 1 - - - SOF5 - Synchronization Overrun Flag 5 - 5 - 1 - - - SOF6 - Synchronization Overrun Flag 6 - 6 - 1 - - - SOF7 - Synchronization Overrun Flag 7 - 7 - 1 - - - SOF8 - Synchronization Overrun Flag 8 - 8 - 1 - - - SOF9 - Synchronization Overrun Flag 9 - 9 - 1 - - - SOF10 - Synchronization Overrun Flag 10 - 10 - 1 - - - SOF11 - Synchronization Overrun Flag 11 - 11 - 1 - - - SOF12 - Synchronization Overrun Flag 12 - 12 - 1 - - - SOF13 - Synchronization Overrun Flag 13 - 13 - 1 - - - - - CFR - CFR - DMA Channel Clear Flag Register - 0x84 - 0x20 - write-only - 0x00000000 - - - CSOF0 - Synchronization Clear Overrun Flag 0 - 0 - 1 - - - CSOF1 - Synchronization Clear Overrun Flag 1 - 1 - 1 - - - CSOF2 - Synchronization Clear Overrun Flag 2 - 2 - 1 - - - CSOF3 - Synchronization Clear Overrun Flag 3 - 3 - 1 - - - CSOF4 - Synchronization Clear Overrun Flag 4 - 4 - 1 - - - CSOF5 - Synchronization Clear Overrun Flag 5 - 5 - 1 - - - CSOF6 - Synchronization Clear Overrun Flag 6 - 6 - 1 - - - CSOF7 - Synchronization Clear Overrun Flag 7 - 7 - 1 - - - CSOF8 - Synchronization Clear Overrun Flag 8 - 8 - 1 - - - CSOF9 - Synchronization Clear Overrun Flag 9 - 9 - 1 - - - CSOF10 - Synchronization Clear Overrun Flag 10 - 10 - 1 - - - CSOF11 - Synchronization Clear Overrun Flag 11 - 11 - 1 - - - CSOF12 - Synchronization Clear Overrun Flag 12 - 12 - 1 - - - CSOF13 - Synchronization Clear Overrun Flag 13 - 13 - 1 - - - - - RG0CR - RG0CR - DMA Request Generator 0 Control Register - 0x100 - 0x20 - read-write - 0x00000000 - - - GNBREQ - Number of Request - 19 - 5 - - - GPOL - Generation Polarity - 17 - 2 - - - GE - Generation Enable - 16 - 1 - - - OIE - Overrun Interrupt Enable - 8 - 1 - - - SIG_ID - Signal ID - 0 - 5 - - - - - RG1CR - RG1CR - DMA Request Generator 1 Control Register - 0x104 - 0x20 - read-write - 0x00000000 - - - GNBREQ - Number of Request - 19 - 5 - - - GPOL - Generation Polarity - 17 - 2 - - - GE - Generation Enable - 16 - 1 - - - OIE - Overrun Interrupt Enable - 8 - 1 - - - SIG_ID - Signal ID - 0 - 5 - - - - - RG2CR - RG2CR - DMA Request Generator 2 Control Register - 0x108 - 0x20 - read-write - 0x00000000 - - - GNBREQ - Number of Request - 19 - 5 - - - GPOL - Generation Polarity - 17 - 2 - - - GE - Generation Enable - 16 - 1 - - - OIE - Overrun Interrupt Enable - 8 - 1 - - - SIG_ID - Signal ID - 0 - 5 - - - - - RG3CR - RG3CR - DMA Request Generator 3 Control Register - 0x10C - 0x20 - read-write - 0x00000000 - - - GNBREQ - Number of Request - 19 - 5 - - - GPOL - Generation Polarity - 17 - 2 - - - GE - Generation Enable - 16 - 1 - - - OIE - Overrun Interrupt Enable - 8 - 1 - - - SIG_ID - Signal ID - 0 - 5 - - - - - RGSR - RGSR - DMA Request Generator Status Register - 0x140 - 0x20 - read-only - 0x00000000 - - - OF0 - Generator Overrun Flag 0 - 0 - 1 - - - OF1 - Generator Overrun Flag 1 - 1 - 1 - - - OF2 - Generator Overrun Flag 2 - 2 - 1 - - - OF3 - Generator Overrun Flag 3 - 3 - 1 - - - - - RGCFR - RGCFR - DMA Request Generator Clear Flag Register - 0x144 - 0x20 - write-only - 0x00000000 - - - COF0 - Clear trigger Overrun Flag 0 - 0 - 1 - - - COF1 - Clear trigger Overrun Flag 1 - 1 - 1 - - - COF2 - Clear trigger Overrun Flag 2 - 2 - 1 - - - COF3 - Clear trigger Overrun Flag 3 - 3 - 1 - - - - - - - CRC - Cyclic redundancy check calculation unit - CRC - 0x40023000 - - 0x0 - 0x400 - registers - - - - DR - DR - Data register - 0x0 - 0x20 - read-write - 0xFFFFFFFF - - - DR - Data register bits - 0 - 32 - - - - - IDR - IDR - Independent data register - 0x4 - 0x20 - read-write - 0x00000000 - - - IDR - General-purpose 32-bit data register bits - 0 - 32 - - - - - CR - CR - Control register - 0x8 - 0x20 - read-write - 0x00000000 - - - REV_OUT - Reverse output data - 7 - 1 - - - REV_IN - Reverse input data - 5 - 2 - - - POLYSIZE - Polynomial size - 3 - 2 - - - RESET - RESET bit - 0 - 1 - - - - - INIT - INIT - Initial CRC value - 0x10 - 0x20 - read-write - 0xFFFFFFFF - - - CRC_INIT - Programmable initial CRC value - 0 - 32 - - - - - POL - POL - polynomial - 0x14 - 0x20 - read-write - 0x04C11DB7 - - - POL - Programmable polynomial - 0 - 32 - - - - - - - LCD - Liquid crystal display controller - LCD - 0x40002400 - - 0x0 - 0x400 - registers - - - LCD - LCD global interrupt - 49 - - - - CR - CR - control register - 0x0 - 0x20 - read-write - 0x00000000 - - - BIAS - Bias selector - 5 - 2 - - - DUTY - Duty selection - 2 - 3 - - - VSEL - Voltage source selection - 1 - 1 - - - LCDEN - LCD controller enable - 0 - 1 - - - MUX_SEG - Mux segment enable - 7 - 1 - - - BUFEN - Voltage output buffer enable - 8 - 1 - - - - - FCR - FCR - frame control register - 0x4 - 0x20 - read-write - 0x00000000 - - - PS - PS 16-bit prescaler - 22 - 4 - - - DIV - DIV clock divider - 18 - 4 - - - BLINK - Blink mode selection - 16 - 2 - - - BLINKF - Blink frequency selection - 13 - 3 - - - CC - Contrast control - 10 - 3 - - - DEAD - Dead time duration - 7 - 3 - - - PON - Pulse ON duration - 4 - 3 - - - UDDIE - Update display done interrupt enable - 3 - 1 - - - SOFIE - Start of frame interrupt enable - 1 - 1 - - - HD - High drive enable - 0 - 1 - - - - - SR - SR - status register - 0x8 - 0x20 - 0x00000020 - - - FCRSF - LCD Frame Control Register Synchronization flag - 5 - 1 - read-only - - - RDY - Ready flag - 4 - 1 - read-only - - - UDD - Update Display Done - 3 - 1 - read-only - - - UDR - Update display request - 2 - 1 - read-write - - - SOF - Start of frame flag - 1 - 1 - read-only - - - ENS - ENS - 0 - 1 - read-only - - - - - CLR - CLR - clear register - 0xC - 0x20 - write-only - 0x00000000 - - - UDDC - Update display done clear - 3 - 1 - - - SOFC - Start of frame flag clear - 1 - 1 - - - - - RAM_COM0 - RAM_COM0 - display memory - 0x14 - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM1 - RAM_COM1 - display memory - 0x1C - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM2 - RAM_COM2 - display memory - 0x24 - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM3 - RAM_COM3 - display memory - 0x2C - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM4 - RAM_COM4 - display memory - 0x34 - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM5 - RAM_COM5 - display memory - 0x3C - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM6 - RAM_COM6 - display memory - 0x44 - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - RAM_COM7 - RAM_COM7 - display memory - 0x4C - 0x20 - read-write - 0x00000000 - - - S31 - S31 - 31 - 1 - - - S30 - S30 - 30 - 1 - - - S29 - S29 - 29 - 1 - - - S28 - S28 - 28 - 1 - - - S27 - S27 - 27 - 1 - - - S26 - S26 - 26 - 1 - - - S25 - S25 - 25 - 1 - - - S24 - S24 - 24 - 1 - - - S23 - S23 - 23 - 1 - - - S22 - S22 - 22 - 1 - - - S21 - S21 - 21 - 1 - - - S20 - S20 - 20 - 1 - - - S19 - S19 - 19 - 1 - - - S18 - S18 - 18 - 1 - - - S17 - S17 - 17 - 1 - - - S16 - S16 - 16 - 1 - - - S15 - S15 - 15 - 1 - - - S14 - S14 - 14 - 1 - - - S13 - S13 - 13 - 1 - - - S12 - S12 - 12 - 1 - - - S11 - S11 - 11 - 1 - - - S10 - S10 - 10 - 1 - - - S09 - S09 - 9 - 1 - - - S08 - S08 - 8 - 1 - - - S07 - S07 - 7 - 1 - - - S06 - S06 - 6 - 1 - - - S05 - S05 - 5 - 1 - - - S04 - S04 - 4 - 1 - - - S03 - S03 - 3 - 1 - - - S02 - S02 - 2 - 1 - - - S01 - S01 - 1 - 1 - - - S00 - S00 - 0 - 1 - - - - - - - TSC - Touch sensing controller - TSC - 0x40024000 - - 0x0 - 0x400 - registers - - - TSC - TSC global interrupt - 39 - - - - CR - CR - control register - 0x0 - 0x20 - read-write - 0x00000000 - - - CTPH - Charge transfer pulse high - 28 - 4 - - - CTPL - Charge transfer pulse low - 24 - 4 - - - SSD - Spread spectrum deviation - 17 - 7 - - - SSE - Spread spectrum enable - 16 - 1 - - - SSPSC - Spread spectrum prescaler - 15 - 1 - - - PGPSC - pulse generator prescaler - 12 - 3 - - - MCV - Max count value - 5 - 3 - - - IODEF - I/O Default mode - 4 - 1 - - - SYNCPOL - Synchronization pin polarity - 3 - 1 - - - AM - Acquisition mode - 2 - 1 - - - START - Start a new acquisition - 1 - 1 - - - TSCE - Touch sensing controller enable - 0 - 1 - - - - - IER - IER - interrupt enable register - 0x4 - 0x20 - read-write - 0x00000000 - - - MCEIE - Max count error interrupt enable - 1 - 1 - - - EOAIE - End of acquisition interrupt enable - 0 - 1 - - - - - ICR - ICR - interrupt clear register - 0x8 - 0x20 - read-write - 0x00000000 - - - MCEIC - Max count error interrupt clear - 1 - 1 - - - EOAIC - End of acquisition interrupt clear - 0 - 1 - - - - - ISR - ISR - interrupt status register - 0xC - 0x20 - read-write - 0x00000000 - - - MCEF - Max count error flag - 1 - 1 - - - EOAF - End of acquisition flag - 0 - 1 - - - - - IOHCR - IOHCR - I/O hysteresis control register - 0x10 - 0x20 - read-write - 0xFFFFFFFF - - - G7_IO4 - G7_IO4 - 27 - 1 - - - G7_IO3 - G7_IO3 - 26 - 1 - - - G7_IO2 - G7_IO2 - 25 - 1 - - - G7_IO1 - G7_IO1 - 24 - 1 - - - G6_IO4 - G6_IO4 - 23 - 1 - - - G6_IO3 - G6_IO3 - 22 - 1 - - - G6_IO2 - G6_IO2 - 21 - 1 - - - G6_IO1 - G6_IO1 - 20 - 1 - - - G5_IO4 - G5_IO4 - 19 - 1 - - - G5_IO3 - G5_IO3 - 18 - 1 - - - G5_IO2 - G5_IO2 - 17 - 1 - - - G5_IO1 - G5_IO1 - 16 - 1 - - - G4_IO4 - G4_IO4 - 15 - 1 - - - G4_IO3 - G4_IO3 - 14 - 1 - - - G4_IO2 - G4_IO2 - 13 - 1 - - - G4_IO1 - G4_IO1 - 12 - 1 - - - G3_IO4 - G3_IO4 - 11 - 1 - - - G3_IO3 - G3_IO3 - 10 - 1 - - - G3_IO2 - G3_IO2 - 9 - 1 - - - G3_IO1 - G3_IO1 - 8 - 1 - - - G2_IO4 - G2_IO4 - 7 - 1 - - - G2_IO3 - G2_IO3 - 6 - 1 - - - G2_IO2 - G2_IO2 - 5 - 1 - - - G2_IO1 - G2_IO1 - 4 - 1 - - - G1_IO4 - G1_IO4 - 3 - 1 - - - G1_IO3 - G1_IO3 - 2 - 1 - - - G1_IO2 - G1_IO2 - 1 - 1 - - - G1_IO1 - G1_IO1 - 0 - 1 - - - - - IOASCR - IOASCR - I/O analog switch control register - 0x18 - 0x20 - read-write - 0x00000000 - - - G7_IO4 - G7_IO4 - 27 - 1 - - - G7_IO3 - G7_IO3 - 26 - 1 - - - G7_IO2 - G7_IO2 - 25 - 1 - - - G7_IO1 - G7_IO1 - 24 - 1 - - - G6_IO4 - G6_IO4 - 23 - 1 - - - G6_IO3 - G6_IO3 - 22 - 1 - - - G6_IO2 - G6_IO2 - 21 - 1 - - - G6_IO1 - G6_IO1 - 20 - 1 - - - G5_IO4 - G5_IO4 - 19 - 1 - - - G5_IO3 - G5_IO3 - 18 - 1 - - - G5_IO2 - G5_IO2 - 17 - 1 - - - G5_IO1 - G5_IO1 - 16 - 1 - - - G4_IO4 - G4_IO4 - 15 - 1 - - - G4_IO3 - G4_IO3 - 14 - 1 - - - G4_IO2 - G4_IO2 - 13 - 1 - - - G4_IO1 - G4_IO1 - 12 - 1 - - - G3_IO4 - G3_IO4 - 11 - 1 - - - G3_IO3 - G3_IO3 - 10 - 1 - - - G3_IO2 - G3_IO2 - 9 - 1 - - - G3_IO1 - G3_IO1 - 8 - 1 - - - G2_IO4 - G2_IO4 - 7 - 1 - - - G2_IO3 - G2_IO3 - 6 - 1 - - - G2_IO2 - G2_IO2 - 5 - 1 - - - G2_IO1 - G2_IO1 - 4 - 1 - - - G1_IO4 - G1_IO4 - 3 - 1 - - - G1_IO3 - G1_IO3 - 2 - 1 - - - G1_IO2 - G1_IO2 - 1 - 1 - - - G1_IO1 - G1_IO1 - 0 - 1 - - - - - IOSCR - IOSCR - I/O sampling control register - 0x20 - 0x20 - read-write - 0x00000000 - - - G7_IO4 - G7_IO4 - 27 - 1 - - - G7_IO3 - G7_IO3 - 26 - 1 - - - G7_IO2 - G7_IO2 - 25 - 1 - - - G7_IO1 - G7_IO1 - 24 - 1 - - - G6_IO4 - G6_IO4 - 23 - 1 - - - G6_IO3 - G6_IO3 - 22 - 1 - - - G6_IO2 - G6_IO2 - 21 - 1 - - - G6_IO1 - G6_IO1 - 20 - 1 - - - G5_IO4 - G5_IO4 - 19 - 1 - - - G5_IO3 - G5_IO3 - 18 - 1 - - - G5_IO2 - G5_IO2 - 17 - 1 - - - G5_IO1 - G5_IO1 - 16 - 1 - - - G4_IO4 - G4_IO4 - 15 - 1 - - - G4_IO3 - G4_IO3 - 14 - 1 - - - G4_IO2 - G4_IO2 - 13 - 1 - - - G4_IO1 - G4_IO1 - 12 - 1 - - - G3_IO4 - G3_IO4 - 11 - 1 - - - G3_IO3 - G3_IO3 - 10 - 1 - - - G3_IO2 - G3_IO2 - 9 - 1 - - - G3_IO1 - G3_IO1 - 8 - 1 - - - G2_IO4 - G2_IO4 - 7 - 1 - - - G2_IO3 - G2_IO3 - 6 - 1 - - - G2_IO2 - G2_IO2 - 5 - 1 - - - G2_IO1 - G2_IO1 - 4 - 1 - - - G1_IO4 - G1_IO4 - 3 - 1 - - - G1_IO3 - G1_IO3 - 2 - 1 - - - G1_IO2 - G1_IO2 - 1 - 1 - - - G1_IO1 - G1_IO1 - 0 - 1 - - - - - IOCCR - IOCCR - I/O channel control register - 0x28 - 0x20 - read-write - 0x00000000 - - - G7_IO4 - G7_IO4 - 27 - 1 - - - G7_IO3 - G7_IO3 - 26 - 1 - - - G7_IO2 - G7_IO2 - 25 - 1 - - - G7_IO1 - G7_IO1 - 24 - 1 - - - G6_IO4 - G6_IO4 - 23 - 1 - - - G6_IO3 - G6_IO3 - 22 - 1 - - - G6_IO2 - G6_IO2 - 21 - 1 - - - G6_IO1 - G6_IO1 - 20 - 1 - - - G5_IO4 - G5_IO4 - 19 - 1 - - - G5_IO3 - G5_IO3 - 18 - 1 - - - G5_IO2 - G5_IO2 - 17 - 1 - - - G5_IO1 - G5_IO1 - 16 - 1 - - - G4_IO4 - G4_IO4 - 15 - 1 - - - G4_IO3 - G4_IO3 - 14 - 1 - - - G4_IO2 - G4_IO2 - 13 - 1 - - - G4_IO1 - G4_IO1 - 12 - 1 - - - G3_IO4 - G3_IO4 - 11 - 1 - - - G3_IO3 - G3_IO3 - 10 - 1 - - - G3_IO2 - G3_IO2 - 9 - 1 - - - G3_IO1 - G3_IO1 - 8 - 1 - - - G2_IO4 - G2_IO4 - 7 - 1 - - - G2_IO3 - G2_IO3 - 6 - 1 - - - G2_IO2 - G2_IO2 - 5 - 1 - - - G2_IO1 - G2_IO1 - 4 - 1 - - - G1_IO4 - G1_IO4 - 3 - 1 - - - G1_IO3 - G1_IO3 - 2 - 1 - - - G1_IO2 - G1_IO2 - 1 - 1 - - - G1_IO1 - G1_IO1 - 0 - 1 - - - - - IOGCSR - IOGCSR - I/O group control status register - 0x30 - 0x20 - 0x00000000 - - - G7S - Analog I/O group x status - 22 - 1 - read-only - - - G6S - Analog I/O group x status - 21 - 1 - read-only - - - G5S - Analog I/O group x status - 20 - 1 - read-only - - - G4S - Analog I/O group x status - 19 - 1 - read-only - - - G3S - Analog I/O group x status - 18 - 1 - read-only - - - G2S - Analog I/O group x status - 17 - 1 - read-only - - - G1S - Analog I/O group x status - 16 - 1 - read-only - - - G7E - Analog I/O group x enable - 6 - 1 - read-write - - - G6E - Analog I/O group x enable - 5 - 1 - read-write - - - G5E - Analog I/O group x enable - 4 - 1 - read-write - - - G4E - Analog I/O group x enable - 3 - 1 - read-write - - - G3E - Analog I/O group x enable - 2 - 1 - read-write - - - G2E - Analog I/O group x enable - 1 - 1 - read-write - - - G1E - Analog I/O group x enable - 0 - 1 - read-write - - - - - IOG1CR - IOG1CR - I/O group x counter register - 0x34 - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - IOG2CR - IOG2CR - I/O group x counter register - 0x38 - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - IOG3CR - IOG3CR - I/O group x counter register - 0x3C - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - IOG4CR - IOG4CR - I/O group x counter register - 0x40 - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - IOG5CR - IOG5CR - I/O group x counter register - 0x44 - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - IOG6CR - IOG6CR - I/O group x counter register - 0x48 - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - IOG7CR - IOG7CR - I/O group x counter register - 0x4C - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 14 - - - - - - - IWDG - Independent watchdog - IWDG - 0x40003000 - - 0x0 - 0x400 - registers - - - - KR - KR - Key register - 0x0 - 0x20 - write-only - 0x00000000 - - - KEY - Key value (write only, read 0x0000) - 0 - 16 - - - - - PR - PR - Prescaler register - 0x4 - 0x20 - read-write - 0x00000000 - - - PR - Prescaler divider - 0 - 3 - - - - - RLR - RLR - Reload register - 0x8 - 0x20 - read-write - 0x00000FFF - - - RL - Watchdog counter reload value - 0 - 12 - - - - - SR - SR - Status register - 0xC - 0x20 - read-only - 0x00000000 - - - WVU - Watchdog counter window value update - 2 - 1 - - - RVU - Watchdog counter reload value update - 1 - 1 - - - PVU - Watchdog prescaler value update - 0 - 1 - - - - - WINR - WINR - Window register - 0x10 - 0x20 - read-write - 0x00000FFF - - - WIN - Watchdog counter window value - 0 - 12 - - - - - - - WWDG - System window watchdog - WWDG - 0x40002C00 - - 0x0 - 0x400 - registers - - - WWDG - Window Watchdog interrupt - 0 - - - - CR - CR - Control register - 0x0 - 0x20 - read-write - 0x0000007F - - - WDGA - Activation bit - 7 - 1 - - - T - 7-bit counter (MSB to LSB) - 0 - 7 - - - - - CFR - CFR - Configuration register - 0x4 - 0x20 - read-write - 0x0000007F - - - WDGTB - Timer base - 11 - 3 - - - EWI - Early wakeup interrupt - 9 - 1 - - - W - 7-bit window value - 0 - 7 - - - - - SR - SR - Status register - 0x8 - 0x20 - read-write - 0x00000000 - - - EWIF - Early wakeup interrupt flag - 0 - 1 - - - - - - - I2C1 - Inter-integrated circuit - I2C - 0x40005400 - - 0x0 - 0x400 - registers - - - I2C1_EV - I2C1 event interrupt - 30 - - - I2C1_ER - I2C1 error interrupt - 31 - - - - CR1 - CR1 - Control register 1 - 0x0 - 0x20 - read-write - 0x00000000 - - - PE - Peripheral enable - 0 - 1 - - - TXIE - TX Interrupt enable - 1 - 1 - - - RXIE - RX Interrupt enable - 2 - 1 - - - ADDRIE - Address match interrupt enable (slave only) - 3 - 1 - - - NACKIE - Not acknowledge received interrupt enable - 4 - 1 - - - STOPIE - STOP detection Interrupt enable - 5 - 1 - - - TCIE - Transfer Complete interrupt enable - 6 - 1 - - - ERRIE - Error interrupts enable - 7 - 1 - - - DNF - Digital noise filter - 8 - 4 - - - ANFOFF - Analog noise filter OFF - 12 - 1 - - - TXDMAEN - DMA transmission requests enable - 14 - 1 - - - RXDMAEN - DMA reception requests enable - 15 - 1 - - - SBC - Slave byte control - 16 - 1 - - - NOSTRETCH - Clock stretching disable - 17 - 1 - - - WUPEN - Wakeup from STOP enable - 18 - 1 - - - GCEN - General call enable - 19 - 1 - - - SMBHEN - SMBus Host address enable - 20 - 1 - - - SMBDEN - SMBus Device Default address enable - 21 - 1 - - - ALERTEN - SMBUS alert enable - 22 - 1 - - - PECEN - PEC enable - 23 - 1 - - - - - CR2 - CR2 - Control register 2 - 0x4 - 0x20 - read-write - 0x00000000 - - - PECBYTE - Packet error checking byte - 26 - 1 - - - AUTOEND - Automatic end mode (master mode) - 25 - 1 - - - RELOAD - NBYTES reload mode - 24 - 1 - - - NBYTES - Number of bytes - 16 - 8 - - - NACK - NACK generation (slave mode) - 15 - 1 - - - STOP - Stop generation (master mode) - 14 - 1 - - - START - Start generation - 13 - 1 - - - HEAD10R - 10-bit address header only read direction (master receiver mode) - 12 - 1 - - - ADD10 - 10-bit addressing mode (master mode) - 11 - 1 - - - RD_WRN - Transfer direction (master mode) - 10 - 1 - - - SADD - Slave address bit (master mode) - 0 - 10 - - - - - OAR1 - OAR1 - Own address register 1 - 0x8 - 0x20 - read-write - 0x00000000 - - - OA1 - Interface address - 0 - 10 - - - OA1MODE - Own Address 1 10-bit mode - 10 - 1 - - - OA1EN - Own Address 1 enable - 15 - 1 - - - - - OAR2 - OAR2 - Own address register 2 - 0xC - 0x20 - read-write - 0x00000000 - - - OA2 - Interface address - 1 - 7 - - - OA2MSK - Own Address 2 masks - 8 - 3 - - - OA2EN - Own Address 2 enable - 15 - 1 - - - - - TIMINGR - TIMINGR - Timing register - 0x10 - 0x20 - read-write - 0x00000000 - - - SCLL - SCL low period (master mode) - 0 - 8 - - - SCLH - SCL high period (master mode) - 8 - 8 - - - SDADEL - Data hold time - 16 - 4 - - - SCLDEL - Data setup time - 20 - 4 - - - PRESC - Timing prescaler - 28 - 4 - - - - - TIMEOUTR - TIMEOUTR - Status register 1 - 0x14 - 0x20 - read-write - 0x00000000 - - - TIMEOUTA - Bus timeout A - 0 - 12 - - - TIDLE - Idle clock timeout detection - 12 - 1 - - - TIMOUTEN - Clock timeout enable - 15 - 1 - - - TIMEOUTB - Bus timeout B - 16 - 12 - - - TEXTEN - Extended clock timeout enable - 31 - 1 - - - - - ISR - ISR - Interrupt and Status register - 0x18 - 0x20 - 0x00000001 - - - ADDCODE - Address match code (Slave mode) - 17 - 7 - read-only - - - DIR - Transfer direction (Slave mode) - 16 - 1 - read-only - - - BUSY - Bus busy - 15 - 1 - read-only - - - ALERT - SMBus alert - 13 - 1 - read-only - - - TIMEOUT - Timeout or t_low detection flag - 12 - 1 - read-only - - - PECERR - PEC Error in reception - 11 - 1 - read-only - - - OVR - Overrun/Underrun (slave mode) - 10 - 1 - read-only - - - ARLO - Arbitration lost - 9 - 1 - read-only - - - BERR - Bus error - 8 - 1 - read-only - - - TCR - Transfer Complete Reload - 7 - 1 - read-only - - - TC - Transfer Complete (master mode) - 6 - 1 - read-only - - - STOPF - Stop detection flag - 5 - 1 - read-only - - - NACKF - Not acknowledge received flag - 4 - 1 - read-only - - - ADDR - Address matched (slave mode) - 3 - 1 - read-only - - - RXNE - Receive data register not empty (receivers) - 2 - 1 - read-only - - - TXIS - Transmit interrupt status (transmitters) - 1 - 1 - read-write - - - TXE - Transmit data register empty (transmitters) - 0 - 1 - read-write - - - - - ICR - ICR - Interrupt clear register - 0x1C - 0x20 - write-only - 0x00000000 - - - ALERTCF - Alert flag clear - 13 - 1 - - - TIMOUTCF - Timeout detection flag clear - 12 - 1 - - - PECCF - PEC Error flag clear - 11 - 1 - - - OVRCF - Overrun/Underrun flag clear - 10 - 1 - - - ARLOCF - Arbitration lost flag clear - 9 - 1 - - - BERRCF - Bus error flag clear - 8 - 1 - - - STOPCF - Stop detection flag clear - 5 - 1 - - - NACKCF - Not Acknowledge flag clear - 4 - 1 - - - ADDRCF - Address Matched flag clear - 3 - 1 - - - - - PECR - PECR - PEC register - 0x20 - 0x20 - read-only - 0x00000000 - - - PEC - Packet error checking register - 0 - 8 - - - - - RXDR - RXDR - Receive data register - 0x24 - 0x20 - read-only - 0x00000000 - - - RXDATA - 8-bit receive data - 0 - 8 - - - - - TXDR - TXDR - Transmit data register - 0x28 - 0x20 - read-write - 0x00000000 - - - TXDATA - 8-bit transmit data - 0 - 8 - - - - - - - I2C3 - 0x40005C00 - - I2C3_EV - I2C3 event interrupt - 32 - - - I2C3_ER - I2C3 error interrupt - 33 - - - - Flash - Flash - Flash - 0x58004000 - - 0x0 - 0x90 - registers - - - FLASH - Flash global interrupt - 4 - - - - ACR - ACR - Access control register - 0x0 - 0x20 - read-write - 0x00000600 - - - LATENCY - Latency - 0 - 3 - - - PRFTEN - Prefetch enable - 8 - 1 - - - ICEN - Instruction cache enable - 9 - 1 - - - DCEN - Data cache enable - 10 - 1 - - - ICRST - Instruction cache reset - 11 - 1 - - - DCRST - Data cache reset - 12 - 1 - - - PES - CPU1 CortexM4 program erase suspend request - 15 - 1 - - - EMPTY - Flash User area empty - 16 - 1 - - - - - KEYR - KEYR - Flash key register - 0x8 - 0x20 - write-only - 0x00000000 - - - KEYR - KEYR - 0 - 32 - - - - - OPTKEYR - OPTKEYR - Option byte key register - 0xC - 0x20 - write-only - 0x00000000 - - - OPTKEYR - Option byte key - 0 - 32 - - - - - SR - SR - Status register - 0x10 - 0x20 - 0x00000000 - - - EOP - End of operation - 0 - 1 - read-write - - - OPERR - Operation error - 1 - 1 - read-write - - - PROGERR - Programming error - 3 - 1 - read-write - - - WRPERR - Write protected error - 4 - 1 - read-write - - - PGAERR - Programming alignment error - 5 - 1 - read-write - - - SIZERR - Size error - 6 - 1 - read-write - - - PGSERR - Programming sequence error - 7 - 1 - read-write - - - MISERR - Fast programming data miss error - 8 - 1 - read-write - - - FASTERR - Fast programming error - 9 - 1 - read-write - - - OPTNV - User Option OPTVAL indication - 13 - 1 - read-only - - - RDERR - PCROP read error - 14 - 1 - read-write - - - OPTVERR - Option validity error - 15 - 1 - read-write - - - BSY - Busy - 16 - 1 - read-only - - - CFGBSY - Programming or erase configuration busy - 18 - 1 - read-only - - - PESD - Programming or erase operation suspended - 19 - 1 - read-only - - - - - CR - CR - Flash control register - 0x14 - 0x20 - read-write - 0xC0000000 - - - PG - Programming - 0 - 1 - - - PER - Page erase - 1 - 1 - - - MER - This bit triggers the mass erase (all user pages) when set - 2 - 1 - - - PNB - Page number selection - 3 - 8 - - - STRT - Start - 16 - 1 - - - OPTSTRT - Options modification start - 17 - 1 - - - FSTPG - Fast programming - 18 - 1 - - - EOPIE - End of operation interrupt enable - 24 - 1 - - - ERRIE - Error interrupt enable - 25 - 1 - - - RDERRIE - PCROP read error interrupt enable - 26 - 1 - - - OBL_LAUNCH - Force the option byte loading - 27 - 1 - - - OPTLOCK - Options Lock - 30 - 1 - - - LOCK - FLASH_CR Lock - 31 - 1 - - - - - ECCR - ECCR - Flash ECC register - 0x18 - 0x20 - 0x00000000 - - - ADDR_ECC - ECC fail address - 0 - 17 - read-only - - - SYSF_ECC - System Flash ECC fail - 20 - 1 - read-only - - - ECCCIE - ECC correction interrupt enable - 24 - 1 - read-write - - - CPUID - CPU identification - 26 - 3 - read-only - - - ECCC - ECC correction - 30 - 1 - read-write - - - ECCD - ECC detection - 31 - 1 - read-write - - - - - OPTR - OPTR - Flash option register - 0x20 - 0x20 - read-write - 0x10708000 - - - RDP - Read protection level - 0 - 8 - - - ESE - Security enabled - 8 - 1 - - - BOR_LEV - BOR reset Level - 9 - 3 - - - nRST_STOP - nRST_STOP - 12 - 1 - - - nRST_STDBY - nRST_STDBY - 13 - 1 - - - nRST_SHDW - nRST_SHDW - 14 - 1 - - - IDWG_SW - Independent watchdog selection - 16 - 1 - - - IWDG_STOP - Independent watchdog counter freeze in Stop mode - 17 - 1 - - - IWDG_STDBY - Independent watchdog counter freeze in Standby mode - 18 - 1 - - - WWDG_SW - Window watchdog selection - 19 - 1 - - - nBOOT1 - Boot configuration - 23 - 1 - - - SRAM2_PE - SRAM2 parity check enable - 24 - 1 - - - SRAM2_RST - SRAM2 Erase when system reset - 25 - 1 - - - nSWBOOT0 - Software Boot0 - 26 - 1 - - - nBOOT0 - nBoot0 option bit - 27 - 1 - - - AGC_TRIM - Radio Automatic Gain Control Trimming - 29 - 3 - - - - - PCROP1ASR - PCROP1ASR - Flash Bank 1 PCROP Start address zone A register - 0x24 - 0x20 - read-write - 0xFFFFFE00 - - - PCROP1A_STRT - Bank 1 PCROPQ area start offset - 0 - 9 - - - - - PCROP1AER - PCROP1AER - Flash Bank 1 PCROP End address zone A register - 0x28 - 0x20 - read-write - 0x7FFFFE00 - - - PCROP1A_END - Bank 1 PCROP area end offset - 0 - 9 - - - PCROP_RDP - PCROP area preserved when RDP level decreased - 31 - 1 - - - - - WRP1AR - WRP1AR - Flash Bank 1 WRP area A address register - 0x2C - 0x20 - read-write - 0xFF00FF00 - - - WRP1A_STRT - Bank 1 WRP first area A start offset - 0 - 8 - - - WRP1A_END - Bank 1 WRP first area A end offset - 16 - 8 - - - - - WRP1BR - WRP1BR - Flash Bank 1 WRP area B address register - 0x30 - 0x20 - read-write - 0xFF00FF00 - - - WRP1B_STRT - Bank 1 WRP second area B end offset - 16 - 8 - - - WRP1B_END - Bank 1 WRP second area B start offset - 0 - 8 - - - - - PCROP1BSR - PCROP1BSR - Flash Bank 1 PCROP Start address area B register - 0x34 - 0x20 - read-write - 0xFFFFFE00 - - - PCROP1B_STRT - Bank 1 PCROP area B start offset - 0 - 9 - - - - - PCROP1BER - PCROP1BER - Flash Bank 1 PCROP End address area B register - 0x38 - 0x20 - read-write - 0xFFFFFE00 - - - PCROP1B_END - Bank 1 PCROP area end area B offset - 0 - 9 - - - - - IPCCBR - IPCCBR - IPCC mailbox data buffer address register - 0x3C - 0x20 - read-write - 0xFFFFC000 - - - IPCCDBA - PCC mailbox data buffer base address - 0 - 14 - - - - - C2ACR - C2ACR - CPU2 cortex M0 access control register - 0x5C - 0x20 - read-write - 0x00000600 - - - PRFTEN - CPU2 cortex M0 prefetch enable - 8 - 1 - - - ICEN - CPU2 cortex M0 instruction cache enable - 9 - 1 - - - ICRST - CPU2 cortex M0 instruction cache reset - 11 - 1 - - - PES - CPU2 cortex M0 program erase suspend request - 15 - 1 - - - - - C2SR - C2SR - CPU2 cortex M0 status register - 0x60 - 0x20 - read-write - 0x00000000 - - - EOP - End of operation - 0 - 1 - - - OPERR - Operation error - 1 - 1 - - - PROGERR - Programming error - 3 - 1 - - - WRPERR - write protection error - 4 - 1 - - - PGAERR - Programming alignment error - 5 - 1 - - - SIZERR - Size error - 6 - 1 - - - PGSERR - Programming sequence error - 7 - 1 - - - MISSERR - Fast programming data miss error - 8 - 1 - - - FASTERR - Fast programming error - 9 - 1 - - - RDERR - PCROP read error - 14 - 1 - - - BSY - Busy - 16 - 1 - - - CFGBSY - Programming or erase configuration busy - 18 - 1 - - - PESD - Programming or erase operation suspended - 19 - 1 - - - - - C2CR - C2CR - CPU2 cortex M0 control register - 0x64 - 0x20 - read-write - 0x00000000 - - - PG - Programming - 0 - 1 - - - PER - Page erase - 1 - 1 - - - MER - Masse erase - 2 - 1 - - - PNB - Page Number selection - 3 - 8 - - - STRT - Start - 16 - 1 - - - FSTPG - Fast programming - 18 - 1 - - - EOPIE - End of operation interrupt enable - 24 - 1 - - - ERRIE - Error interrupt enable - 25 - 1 - - - RDERRIE - PCROP read error interrupt enable - 26 - 1 - - - - - SFR - SFR - Secure flash start address register - 0x80 - 0x20 - read-write - 0xFFFFEE00 - - - SFSA - Secure flash start address - 0 - 8 - - - DDS - Disable Cortex M0 debug access - 12 - 1 - - - FSD - Flash security disable - 8 - 1 - - - - - SRRVR - SRRVR - Secure SRAM2 start address and cortex M0 reset vector register - 0x84 - 0x20 - read-write - 0x01000000 - - - SBRV - cortex M0 access control register - 0 - 18 - - - SBRSA - Secure backup SRAM2a start address - 18 - 5 - - - BRSD - backup SRAM2a security disable - 23 - 1 - - - SNBRSA - Secure non backup SRAM2a start address - 25 - 5 - - - C2OPT - CPU2 cortex M0 boot reset vector memory selection - 31 - 1 - - - NBRSD - non-backup SRAM2b security disable - 30 - 1 - - - - - - - QUADSPI - QuadSPI interface - QUADSPI - 0xA0001000 - - 0x0 - 0x400 - registers - - - QUADSPI - QSPI global interrupt - 50 - - - - CR - CR - control register - 0x0 - 0x20 - read-write - 0x00000000 - - - PRESCALER - Clock prescaler - 24 - 8 - - - PMM - Polling match mode - 23 - 1 - - - APMS - Automatic poll mode stop - 22 - 1 - - - TOIE - TimeOut interrupt enable - 20 - 1 - - - SMIE - Status match interrupt enable - 19 - 1 - - - FTIE - FIFO threshold interrupt enable - 18 - 1 - - - TCIE - Transfer complete interrupt enable - 17 - 1 - - - TEIE - Transfer error interrupt enable - 16 - 1 - - - FTHRES - FIFO threshold level - 8 - 5 - - - SSHIFT - Sample shift - 4 - 1 - - - TCEN - Timeout counter enable - 3 - 1 - - - DMAEN - DMA enable - 2 - 1 - - - ABORT - Abort request - 1 - 1 - - - EN - Enable - 0 - 1 - - - - - DCR - DCR - device configuration register - 0x4 - 0x20 - read-write - 0x00000000 - - - FSIZE - FLASH memory size - 16 - 5 - - - CSHT - Chip select high time - 8 - 3 - - - CKMODE - Mode 0 / mode 3 - 0 - 1 - - - - - SR - SR - status register - 0x8 - 0x20 - read-only - 0x00000000 - - - FLEVEL - FIFO level - 8 - 6 - - - BUSY - Busy - 5 - 1 - - - TOF - Timeout flag - 4 - 1 - - - SMF - Status match flag - 3 - 1 - - - FTF - FIFO threshold flag - 2 - 1 - - - TCF - Transfer complete flag - 1 - 1 - - - TEF - Transfer error flag - 0 - 1 - - - - - FCR - FCR - flag clear register - 0xC - 0x20 - read-write - 0x00000000 - - - CTOF - Clear timeout flag - 4 - 1 - - - CSMF - Clear status match flag - 3 - 1 - - - CTCF - Clear transfer complete flag - 1 - 1 - - - CTEF - Clear transfer error flag - 0 - 1 - - - - - DLR - DLR - data length register - 0x10 - 0x20 - read-write - 0x00000000 - - - DL - Data length - 0 - 32 - - - - - CCR - CCR - communication configuration register - 0x14 - 0x20 - read-write - 0x00000000 - - - DDRM - Double data rate mode - 31 - 1 - - - SIOO - Send instruction only once mode - 28 - 1 - - - FMODE - Functional mode - 26 - 2 - - - DMODE - Data mode - 24 - 2 - - - DCYC - Number of dummy cycles - 18 - 5 - - - ABSIZE - Alternate bytes size - 16 - 2 - - - ABMODE - Alternate bytes mode - 14 - 2 - - - ADSIZE - Address size - 12 - 2 - - - ADMODE - Address mode - 10 - 2 - - - IMODE - Instruction mode - 8 - 2 - - - INSTRUCTION - Instruction - 0 - 8 - - - - - AR - AR - address register - 0x18 - 0x20 - read-write - 0x00000000 - - - ADDRESS - Address - 0 - 32 - - - - - ABR - ABR - ABR - 0x1C - 0x20 - read-write - 0x00000000 - - - ALTERNATE - ALTERNATE - 0 - 32 - - - - - DR - DR - data register - 0x20 - 0x20 - read-write - 0x00000000 - - - DATA - Data - 0 - 32 - - - - - PSMKR - PSMKR - polling status mask register - 0x24 - 0x20 - read-write - 0x00000000 - - - MASK - Status mask - 0 - 32 - - - - - PSMAR - PSMAR - polling status match register - 0x28 - 0x20 - read-write - 0x00000000 - - - MATCH - Status match - 0 - 32 - - - - - PIR - PIR - polling interval register - 0x2C - 0x20 - read-write - 0x00000000 - - - INTERVAL - Polling interval - 0 - 16 - - - - - LPTR - LPTR - low-power timeout register - 0x30 - 0x20 - read-write - 0x00000000 - - - TIMEOUT - Timeout period - 0 - 16 - - - - - - - RCC - Reset and clock control - RCC - 0x58000000 - - 0x0 - 0x400 - registers - - - RCC - RCC global interrupt - 5 - - - - CR - CR - Clock control register - 0x0 - 0x20 - 0x00000061 - - - PLLSAI1RDY - SAI1 PLL clock ready flag - 27 - 1 - read-only - - - PLLSAI1ON - SAI1 PLL enable - 26 - 1 - read-write - - - PLLRDY - Main PLL clock ready flag - 25 - 1 - read-only - - - PLLON - Main PLL enable - 24 - 1 - read-write - - - HSEPRE - HSE sysclk and PLL M divider prescaler - 20 - 1 - read-write - - - CSSON - HSE Clock security system enable - 19 - 1 - write-only - - - HSEBYP - HSE crystal oscillator bypass - 18 - 1 - read-write - - - HSERDY - HSE clock ready flag - 17 - 1 - read-only - - - HSEON - HSE clock enabled - 16 - 1 - read-write - - - HSIKERDY - HSI kernel clock ready flag for peripherals requests - 12 - 1 - read-only - - - HSIASFS - HSI automatic start from Stop - 11 - 1 - read-write - - - HSIRDY - HSI clock ready flag - 10 - 1 - read-only - - - HSIKERON - HSI always enable for peripheral kernels - 9 - 1 - read-write - - - HSION - HSI clock enabled - 8 - 1 - read-write - - - MSIRANGE - MSI clock ranges - 4 - 4 - read-write - - - MSIPLLEN - MSI clock PLL enable - 2 - 1 - read-write - - - MSIRDY - MSI clock ready flag - 1 - 1 - read-only - - - MSION - MSI clock enable - 0 - 1 - read-write - - - - - ICSCR - ICSCR - Internal clock sources calibration register - 0x4 - 0x20 - 0x40000000 - - - HSITRIM - HSI clock trimming - 24 - 7 - read-write - - - HSICAL - HSI clock calibration - 16 - 8 - read-only - - - MSITRIM - MSI clock trimming - 8 - 8 - read-write - - - MSICAL - MSI clock calibration - 0 - 8 - read-only - - - - - CFGR - CFGR - Clock configuration register - 0x8 - 0x20 - 0x00070000 - - - MCOPRE - Microcontroller clock output prescaler - 28 - 3 - read-write - - - MCOSEL - Microcontroller clock output - 24 - 4 - read-write - - - PPRE2F - APB2 prescaler flag - 18 - 1 - read-only - - - PPRE1F - APB1 prescaler flag - 17 - 1 - read-only - - - HPREF - AHB prescaler flag - 16 - 1 - read-only - - - STOPWUCK - Wakeup from Stop and CSS backup clock selection - 15 - 1 - read-write - - - PPRE2 - APB high-speed prescaler (APB2) - 11 - 3 - read-write - - - PPRE1 - PB low-speed prescaler (APB1) - 8 - 3 - read-write - - - HPRE - AHB prescaler - 4 - 4 - read-write - - - SWS - System clock switch status - 2 - 2 - read-only - - - SW - System clock switch - 0 - 2 - read-write - - - - - PLLCFGR - PLLCFGR - PLLSYS configuration register - 0xC - 0x20 - read-write - 0x22040100 - - - PLLR - Main PLLSYS division factor R for SYSCLK (system clock) - 29 - 3 - - - PLLREN - Main PLLSYSR PLLCLK output enable - 28 - 1 - - - PLLQ - Main PLLSYS division factor Q for PLLSYSUSBCLK - 25 - 3 - - - PLLQEN - Main PLLSYSQ output enable - 24 - 1 - - - PLLP - Main PLL division factor P for PPLSYSSAICLK - 17 - 5 - - - PLLPEN - Main PLLSYSP output enable - 16 - 1 - - - PLLN - Main PLLSYS multiplication factor N - 8 - 7 - - - PLLM - Division factor M for the main PLL and audio PLL (PLLSAI1 and PLLSAI2) input clock - 4 - 3 - - - PLLSRC - Main PLL, PLLSAI1 and PLLSAI2 entry clock source - 0 - 2 - - - - - PLLSAI1CFGR - PLLSAI1CFGR - PLLSAI1 configuration register - 0x10 - 0x20 - read-write - 0x22040100 - - - PLLR - PLLSAI division factor R for PLLADC1CLK (ADC clock) - 29 - 3 - - - PLLREN - PLLSAI PLLADC1CLK output enable - 28 - 1 - - - PLLQ - SAIPLL division factor Q for PLLSAIUSBCLK (48 MHz clock) - 25 - 3 - - - PLLQEN - SAIPLL PLLSAIUSBCLK output enable - 24 - 1 - - - PLLP - SAI1PLL division factor P for PLLSAICLK (SAI1clock) - 17 - 5 - - - PLLPEN - SAIPLL PLLSAI1CLK output enable - 16 - 1 - - - PLLN - SAIPLL multiplication factor for VCO - 8 - 7 - - - - - CIER - CIER - Clock interrupt enable register - 0x18 - 0x20 - read-write - 0x00000000 - - - LSI2RDYIE - LSI2 ready interrupt enable - 11 - 1 - - - HSI48RDYIE - HSI48 ready interrupt enable - 10 - 1 - - - LSECSSIE - LSE clock security system interrupt enable - 9 - 1 - - - PLLSAI1RDYIE - PLLSAI1 ready interrupt enable - 6 - 1 - - - PLLRDYIE - PLLSYS ready interrupt enable - 5 - 1 - - - HSERDYIE - HSE ready interrupt enable - 4 - 1 - - - HSIRDYIE - HSI ready interrupt enable - 3 - 1 - - - MSIRDYIE - MSI ready interrupt enable - 2 - 1 - - - LSERDYIE - LSE ready interrupt enable - 1 - 1 - - - LSI1RDYIE - LSI1 ready interrupt enable - 0 - 1 - - - - - CIFR - CIFR - Clock interrupt flag register - 0x1C - 0x20 - read-only - 0x00000000 - - - LSI2RDYF - LSI2 ready interrupt flag - 11 - 1 - - - HSI48RDYF - HSI48 ready interrupt flag - 10 - 1 - - - LSECSSF - LSE Clock security system interrupt flag - 9 - 1 - - - HSECSSF - HSE Clock security system interrupt flag - 8 - 1 - - - PLLSAI1RDYF - PLLSAI1 ready interrupt flag - 6 - 1 - - - PLLRDYF - PLL ready interrupt flag - 5 - 1 - - - HSERDYF - HSE ready interrupt flag - 4 - 1 - - - HSIRDYF - HSI ready interrupt flag - 3 - 1 - - - MSIRDYF - MSI ready interrupt flag - 2 - 1 - - - LSERDYF - LSE ready interrupt flag - 1 - 1 - - - LSI1RDYF - LSI1 ready interrupt flag - 0 - 1 - - - - - CICR - CICR - Clock interrupt clear register - 0x20 - 0x20 - write-only - 0x00000000 - - - LSI2RDYC - LSI2 ready interrupt clear - 11 - 1 - - - HSI48RDYC - HSI48 ready interrupt clear - 10 - 1 - - - LSECSSC - LSE Clock security system interrupt clear - 9 - 1 - - - HSECSSC - HSE Clock security system interrupt clear - 8 - 1 - - - PLLSAI1RDYC - PLLSAI1 ready interrupt clear - 6 - 1 - - - PLLRDYC - PLL ready interrupt clear - 5 - 1 - - - HSERDYC - HSE ready interrupt clear - 4 - 1 - - - HSIRDYC - HSI ready interrupt clear - 3 - 1 - - - MSIRDYC - MSI ready interrupt clear - 2 - 1 - - - LSERDYC - LSE ready interrupt clear - 1 - 1 - - - LSI1RDYC - LSI1 ready interrupt clear - 0 - 1 - - - - - SMPSCR - SMPSCR - Step Down converter control register - 0x24 - 0x20 - 0x00000301 - - - SMPSSWS - Step Down converter clock switch status - 8 - 2 - read-only - - - SMPSDIV - Step Down converter clock prescaler - 4 - 2 - read-write - - - SMPSSEL - Step Down converter clock selection - 0 - 2 - read-write - - - - - AHB1RSTR - AHB1RSTR - AHB1 peripheral reset register - 0x28 - 0x20 - read-write - 0x00000000 - - - TSCRST - Touch Sensing Controller reset - 16 - 1 - - - CRCRST - CRC reset - 12 - 1 - - - DMAMUXRST - DMAMUX reset - 2 - 1 - - - DMA2RST - DMA2 reset - 1 - 1 - - - DMA1RST - DMA1 reset - 0 - 1 - - - - - AHB2RSTR - AHB2RSTR - AHB2 peripheral reset register - 0x2C - 0x20 - read-write - 0x00000000 - - - AES1RST - AES1 hardware accelerator reset - 16 - 1 - - - ADCRST - ADC reset - 13 - 1 - - - GPIOHRST - IO port H reset - 7 - 1 - - - GPIOERST - IO port E reset - 4 - 1 - - - GPIODRST - IO port D reset - 3 - 1 - - - GPIOCRST - IO port C reset - 2 - 1 - - - GPIOBRST - IO port B reset - 1 - 1 - - - GPIOARST - IO port A reset - 0 - 1 - - - - - AHB3RSTR - AHB3RSTR - AHB3 peripheral reset register - 0x30 - 0x20 - read-write - 0x00000000 - - - FLASHRST - Flash interface reset - 25 - 1 - - - IPCCRST - IPCC interface reset - 20 - 1 - - - HSEMRST - HSEM interface reset - 19 - 1 - - - RNGRST - RNG interface reset - 18 - 1 - - - AES2RST - AES2 interface reset - 17 - 1 - - - PKARST - PKA interface reset - 16 - 1 - - - QSPIRST - Quad SPI memory interface reset - 8 - 1 - - - - - APB1RSTR1 - APB1RSTR1 - APB1 peripheral reset register 1 - 0x38 - 0x20 - read-write - 0x00000000 - - - LPTIM1RST - Low Power Timer 1 reset - 31 - 1 - - - USBFSRST - USB FS reset - 26 - 1 - - - CRSRST - CRS reset - 24 - 1 - - - I2C3RST - I2C3 reset - 23 - 1 - - - I2C1RST - I2C1 reset - 21 - 1 - - - SPI2RST - SPI2 reset - 14 - 1 - - - LCDRST - LCD interface reset - 9 - 1 - - - TIM2RST - TIM2 timer reset - 0 - 1 - - - - - APB1RSTR2 - APB1RSTR2 - APB1 peripheral reset register 2 - 0x3C - 0x20 - read-write - 0x00000000 - - - LPTIM2RST - Low-power timer 2 reset - 5 - 1 - - - LPUART1RST - Low-power UART 1 reset - 0 - 1 - - - - - APB2RSTR - APB2RSTR - APB2 peripheral reset register - 0x40 - 0x20 - read-write - 0x00000000 - - - SAI1RST - Serial audio interface 1 (SAI1) reset - 21 - 1 - - - TIM17RST - TIM17 timer reset - 18 - 1 - - - TIM16RST - TIM16 timer reset - 17 - 1 - - - USART1RST - USART1 reset - 14 - 1 - - - SPI1RST - SPI1 reset - 12 - 1 - - - TIM1RST - TIM1 timer reset - 11 - 1 - - - - - APB3RSTR - APB3RSTR - APB3 peripheral reset register - 0x44 - 0x20 - read-write - 0x00000000 - - - RFRST - Radio system BLE reset - 0 - 1 - - - - - AHB1ENR - AHB1ENR - AHB1 peripheral clock enable register - 0x48 - 0x20 - read-write - 0x00000100 - - - TSCEN - Touch Sensing Controller clock enable - 16 - 1 - - - CRCEN - CPU1 CRC clock enable - 12 - 1 - - - DMAMUXEN - DMAMUX clock enable - 2 - 1 - - - DMA2EN - DMA2 clock enable - 1 - 1 - - - DMA1EN - DMA1 clock enable - 0 - 1 - - - - - AHB2ENR - AHB2ENR - AHB2 peripheral clock enable register - 0x4C - 0x20 - read-write - 0x00000000 - - - AES1EN - AES1 accelerator clock enable - 16 - 1 - - - ADCEN - ADC clock enable - 13 - 1 - - - GPIOHEN - IO port H clock enable - 7 - 1 - - - GPIOEEN - IO port E clock enable - 4 - 1 - - - GPIODEN - IO port D clock enable - 3 - 1 - - - GPIOCEN - IO port C clock enable - 2 - 1 - - - GPIOBEN - IO port B clock enable - 1 - 1 - - - GPIOAEN - IO port A clock enable - 0 - 1 - - - - - AHB3ENR - AHB3ENR - AHB3 peripheral clock enable register - 0x50 - 0x20 - read-write - 0x02080000 - - - FLASHEN - FLASHEN - 25 - 1 - - - IPCCEN - IPCCEN - 20 - 1 - - - HSEMEN - HSEMEN - 19 - 1 - - - RNGEN - RNGEN - 18 - 1 - - - AES2EN - AES2EN - 17 - 1 - - - PKAEN - PKAEN - 16 - 1 - - - QSPIEN - QSPIEN - 8 - 1 - - - - - APB1ENR1 - APB1ENR1 - APB1ENR1 - 0x58 - 0x20 - read-write - 0x00000400 - - - LPTIM1EN - CPU1 Low power timer 1 clock enable - 31 - 1 - - - USBEN - CPU1 USB clock enable - 26 - 1 - - - CRSEN - CPU1 CRS clock enable - 24 - 1 - - - I2C3EN - CPU1 I2C3 clock enable - 23 - 1 - - - I2C1EN - CPU1 I2C1 clock enable - 21 - 1 - - - SPI2EN - CPU1 SPI2 clock enable - 14 - 1 - - - WWDGEN - CPU1 Window watchdog clock enable - 11 - 1 - - - RTCAPBEN - CPU1 RTC APB clock enable - 10 - 1 - - - LCDEN - CPU1 LCD clock enable - 9 - 1 - - - TIM2EN - CPU1 TIM2 timer clock enable - 0 - 1 - - - - - APB1ENR2 - APB1ENR2 - APB1 peripheral clock enable register 2 - 0x5C - 0x20 - read-write - 0x00000000 - - - LPTIM2EN - CPU1 LPTIM2EN - 5 - 1 - - - LPUART1EN - CPU1 Low power UART 1 clock enable - 0 - 1 - - - - - APB2ENR - APB2ENR - APB2ENR - 0x60 - 0x20 - read-write - 0x00000000 - - - SAI1EN - CPU1 SAI1 clock enable - 21 - 1 - - - TIM17EN - CPU1 TIM17 timer clock enable - 18 - 1 - - - TIM16EN - CPU1 TIM16 timer clock enable - 17 - 1 - - - USART1EN - CPU1 USART1clock enable - 14 - 1 - - - SPI1EN - CPU1 SPI1 clock enable - 12 - 1 - - - TIM1EN - CPU1 TIM1 timer clock enable - 11 - 1 - - - - - AHB1SMENR - AHB1SMENR - AHB1 peripheral clocks enable in Sleep and Stop modes register - 0x68 - 0x20 - read-write - 0x00011207 - - - TSCSMEN - CPU1 Touch Sensing Controller clocks enable during Sleep and Stop modes - 16 - 1 - - - CRCSMEN - CPU1 CRCSMEN - 12 - 1 - - - SRAM1SMEN - CPU1 SRAM1 interface clocks enable during Sleep and Stop modes - 9 - 1 - - - DMAMUXSMEN - CPU1 DMAMUX clocks enable during Sleep and Stop modes - 2 - 1 - - - DMA2SMEN - CPU1 DMA2 clocks enable during Sleep and Stop modes - 1 - 1 - - - DMA1SMEN - CPU1 DMA1 clocks enable during Sleep and Stop modes - 0 - 1 - - - - - AHB2SMENR - AHB2SMENR - AHB2 peripheral clocks enable in Sleep and Stop modes register - 0x6C - 0x20 - read-write - 0x0001209F - - - AES1SMEN - CPU1 AES1 accelerator clocks enable during Sleep and Stop modes - 16 - 1 - - - ADCFSSMEN - CPU1 ADC clocks enable during Sleep and Stop modes - 13 - 1 - - - GPIOHSMEN - CPU1 IO port H clocks enable during Sleep and Stop modes - 7 - 1 - - - GPIOESMEN - CPU1 IO port E clocks enable during Sleep and Stop modes - 4 - 1 - - - GPIODSMEN - CPU1 IO port D clocks enable during Sleep and Stop modes - 3 - 1 - - - GPIOCSMEN - CPU1 IO port C clocks enable during Sleep and Stop modes - 2 - 1 - - - GPIOBSMEN - CPU1 IO port B clocks enable during Sleep and Stop modes - 1 - 1 - - - GPIOASMEN - CPU1 IO port A clocks enable during Sleep and Stop modes - 0 - 1 - - - - - AHB3SMENR - AHB3SMENR - AHB3 peripheral clocks enable in Sleep and Stop modes register - 0x70 - 0x20 - read-write - 0x03070100 - - - FLASHSMEN - Flash interface clocks enable during CPU1 sleep mode - 25 - 1 - - - SRAM2SMEN - SRAM2a and SRAM2b memory interface clocks enable during CPU1 sleep mode - 24 - 1 - - - RNGSMEN - True RNG clocks enable during CPU1 sleep mode - 18 - 1 - - - AES2SMEN - AES2 accelerator clocks enable during CPU1 sleep mode - 17 - 1 - - - PKASMEN - PKA accelerator clocks enable during CPU1 sleep mode - 16 - 1 - - - QSPISMEN - QSPISMEN - 8 - 1 - - - - - APB1SMENR1 - APB1SMENR1 - APB1SMENR1 - 0x78 - 0x20 - read-write - 0x85A04E01 - - - LPTIM1SMEN - Low power timer 1 clocks enable during CPU1 Sleep mode - 31 - 1 - - - USBSMEN - USB FS clocks enable during CPU1 Sleep mode - 26 - 1 - - - CRSMEN - CRS clocks enable during CPU1 Sleep mode - 24 - 1 - - - I2C3SMEN - I2C3 clocks enable during CPU1 Sleep mode - 23 - 1 - - - I2C1SMEN - I2C1 clocks enable during CPU1 Sleep mode - 21 - 1 - - - SPI2SMEN - SPI2 clocks enable during CPU1 Sleep mode - 14 - 1 - - - WWDGSMEN - Window watchdog clocks enable during CPU1 Sleep mode - 11 - 1 - - - RTCAPBSMEN - RTC APB clocks enable during CPU1 Sleep mode - 10 - 1 - - - LCDSMEN - LCD clocks enable during CPU1 Sleep mode - 9 - 1 - - - TIM2SMEN - TIM2 timer clocks enable during CPU1 Sleep mode - 0 - 1 - - - - - APB1SMENR2 - APB1SMENR2 - APB1 peripheral clocks enable in Sleep and Stop modes register 2 - 0x7C - 0x20 - read-write - 0x000000021 - - - LPTIM2SMEN - Low power timer 2 clocks enable during CPU1 Sleep mode - 5 - 1 - - - LPUART1SMEN - Low power UART 1 clocks enable during CPU1 Sleep mode - 0 - 1 - - - - - APB2SMENR - APB2SMENR - APB2SMENR - 0x80 - 0x20 - read-write - 0x00265800 - - - SAI1SMEN - SAI1 clocks enable during CPU1 Sleep mode - 21 - 1 - - - TIM17SMEN - TIM17 timer clocks enable during CPU1 Sleep mode - 18 - 1 - - - TIM16SMEN - TIM16 timer clocks enable during CPU1 Sleep mode - 17 - 1 - - - USART1SMEN - USART1clocks enable during CPU1 Sleep mode - 14 - 1 - - - SPI1SMEN - SPI1 clocks enable during CPU1 Sleep mode - 12 - 1 - - - TIM1SMEN - TIM1 timer clocks enable during CPU1 Sleep mode - 11 - 1 - - - - - CCIPR - CCIPR - CCIPR - 0x88 - 0x20 - read-write - 0x00000000 - - - RNGSEL - RNG clock source selection - 30 - 2 - - - ADCSEL - ADCs clock source selection - 28 - 2 - - - CLK48SEL - 48 MHz clock source selection - 26 - 2 - - - SAI1SEL - SAI1 clock source selection - 22 - 2 - - - LPTIM2SEL - Low power timer 2 clock source selection - 20 - 2 - - - LPTIM1SEL - Low power timer 1 clock source selection - 18 - 2 - - - I2C3SEL - I2C3 clock source selection - 16 - 2 - - - I2C1SEL - I2C1 clock source selection - 12 - 2 - - - LPUART1SEL - LPUART1 clock source selection - 10 - 2 - - - USART1SEL - USART1 clock source selection - 0 - 2 - - - - - BDCR - BDCR - BDCR - 0x90 - 0x20 - 0x00000000 - - - LSCOSEL - Low speed clock output selection - 25 - 1 - read-write - - - LSCOEN - Low speed clock output enable - 24 - 1 - read-write - - - BDRST - Backup domain software reset - 16 - 1 - read-write - - - RTCEN - RTC clock enable - 15 - 1 - read-write - - - RTCSEL - RTC clock source selection - 8 - 2 - read-write - - - LSECSSD_ - CSS on LSE failure detection - 6 - 1 - read-only - - - LSECSSON - LSECSSON - 5 - 1 - read-write - - - LSEDRV - SE oscillator drive capability - 3 - 2 - read-write - - - LSEBYP - LSE oscillator bypass - 2 - 1 - read-write - - - LSERDY - LSE oscillator ready - 1 - 1 - read-only - - - LSEON - LSE oscillator enable - 0 - 1 - read-write - - - - - CSR - CSR - CSR - 0x94 - 0x20 - 0x0C000000 - - - LPWRRSTF - Low-power reset flag - 31 - 1 - read-only - - - WWDGRSTF - Window watchdog reset flag - 30 - 1 - read-only - - - IWDGRSTF - Independent window watchdog reset flag - 29 - 1 - read-only - - - SFTRSTF - Software reset flag - 28 - 1 - read-only - - - BORRSTF - BOR flag - 27 - 1 - read-only - - - PINRSTF - Pin reset flag - 26 - 1 - read-only - - - OBLRSTF - Option byte loader reset flag - 25 - 1 - read-only - - - RMVF - Remove reset flag - 23 - 1 - read-write - - - RFWKPSEL - RF system wakeup clock source selection - 14 - 2 - read-write - - - LSI2BW - LSI2 oscillator bias configuration - 8 - 4 - read-write - - - LSI2TRIMOK - LSI2 oscillator trim OK - 5 - 1 - read-only - - - LSI2TRIMEN - LSI2 oscillator trimming enable - 4 - 1 - read-write - - - LSI2RDY - LSI2 oscillator ready - 3 - 1 - read-only - - - LSI2ON - LSI2 oscillator enabled - 2 - 1 - read-write - - - LSI1RDY - LSI1 oscillator ready - 1 - 1 - read-only - - - LSI1ON - LSI1 oscillator enabled - 0 - 1 - read-write - - - RFRSTS - Radio system BLE and 802.15.4 reset status - 16 - 1 - read-only - - - - - CRRCR - CRRCR - Clock recovery RC register - 0x98 - 0x20 - 0x00000000 - - - HSI48CAL - HSI48 clock calibration - 7 - 9 - read-only - - - HSI48RDY - HSI48 clock ready - 1 - 1 - read-only - - - HSI48ON - HSI48 oscillator enabled - 0 - 1 - read-write - - - - - HSECR - HSECR - Clock HSE register - 0x9C - 0x20 - 0x00000030 - - - HSETUNE - HSE capacitor tuning - 8 - 6 - read-only - - - HSEGMC - HSE current control - 4 - 3 - read-write - - - HSES - HSE Sense amplifier threshold - 3 - 1 - read-write - - - UNLOCKED - Register lock system - 0 - 1 - read-write - - - - - EXTCFGR - EXTCFGR - Extended clock recovery register - 0x108 - 0x20 - 0x00030000 - - - RFCSS - RF clock source selected - 20 - 1 - read-only - - - C2HPREF - CPU2 AHB prescaler flag - 17 - 1 - read-only - - - SHDHPREF - Shared AHB prescaler flag - 16 - 1 - read-only - - - C2HPRE - CPU2 AHB prescaler - 4 - 4 - read-write - - - SHDHPRE - Shared AHB prescaler - 0 - 4 - read-write - - - - - C2AHB1ENR - C2AHB1ENR - CPU2 AHB1 peripheral clock enable register - 0x148 - 0x20 - read-write - 0x00000000 - - - TSCEN - CPU2 Touch Sensing Controller clock enable - 16 - 1 - - - CRCEN - CPU2 CRC clock enable - 12 - 1 - - - SRAM1EN - CPU2 SRAM1 clock enable - 9 - 1 - - - DMAMUXEN - CPU2 DMAMUX clock enable - 2 - 1 - - - DMA2EN - CPU2 DMA2 clock enable - 1 - 1 - - - DMA1EN - CPU2 DMA1 clock enable - 0 - 1 - - - - - C2AHB2ENR - C2AHB2ENR - CPU2 AHB2 peripheral clock enable register - 0x14C - 0x20 - read-write - 0x00000000 - - - AES1EN - CPU2 AES1 accelerator clock enable - 16 - 1 - - - ADCEN - CPU2 ADC clock enable - 13 - 1 - - - GPIOHEN - CPU2 IO port H clock enable - 7 - 1 - - - GPIOEEN - CPU2 IO port E clock enable - 4 - 1 - - - GPIODEN - CPU2 IO port D clock enable - 3 - 1 - - - GPIOCEN - CPU2 IO port C clock enable - 2 - 1 - - - GPIOBEN - CPU2 IO port B clock enable - 1 - 1 - - - GPIOAEN - CPU2 IO port A clock enable - 0 - 1 - - - - - C2AHB3ENR - C2AHB3ENR - CPU2 AHB3 peripheral clock enable register - 0x150 - 0x20 - read-write - 0x02080000 - - - FLASHEN - CPU2 FLASHEN - 25 - 1 - - - IPCCEN - CPU2 IPCCEN - 20 - 1 - - - HSEMEN - CPU2 HSEMEN - 19 - 1 - - - RNGEN - CPU2 RNGEN - 18 - 1 - - - AES2EN - CPU2 AES2EN - 17 - 1 - - - PKAEN - CPU2 PKAEN - 16 - 1 - - - - - C2APB1ENR1 - C2APB1ENR1 - CPU2 APB1ENR1 - 0x158 - 0x20 - read-write - 0x00000400 - - - LPTIM1EN - CPU2 Low power timer 1 clock enable - 31 - 1 - - - USBEN - CPU2 USB clock enable - 26 - 1 - - - CRSEN - CPU2 CRS clock enable - 24 - 1 - - - I2C3EN - CPU2 I2C3 clock enable - 23 - 1 - - - I2C1EN - CPU2 I2C1 clock enable - 21 - 1 - - - SPI2EN - CPU2 SPI2 clock enable - 14 - 1 - - - RTCAPBEN - CPU2 RTC APB clock enable - 10 - 1 - - - LCDEN - CPU2 LCD clock enable - 9 - 1 - - - TIM2EN - CPU2 TIM2 timer clock enable - 0 - 1 - - - - - C2APB1ENR2 - C2APB1ENR2 - CPU2 APB1 peripheral clock enable register 2 - 0x15C - 0x20 - read-write - 0x00000000 - - - LPTIM2EN - CPU2 LPTIM2EN - 5 - 1 - - - LPUART1EN - CPU2 Low power UART 1 clock enable - 0 - 1 - - - - - C2APB2ENR - C2APB2ENR - CPU2 APB2ENR - 0x160 - 0x20 - read-write - 0x00000000 - - - SAI1EN - CPU2 SAI1 clock enable - 21 - 1 - - - TIM17EN - CPU2 TIM17 timer clock enable - 18 - 1 - - - TIM16EN - CPU2 TIM16 timer clock enable - 17 - 1 - - - USART1EN - CPU2 USART1clock enable - 14 - 1 - - - SPI1EN - CPU2 SPI1 clock enable - 12 - 1 - - - TIM1EN - CPU2 TIM1 timer clock enable - 11 - 1 - - - - - C2APB3ENR - C2APB3ENR - CPU2 APB3ENR - 0x164 - 0x20 - read-write - 0x00000000 - - - EN802 - CPU2 802.15.4 interface clock enable - 1 - 1 - - - BLEEN - CPU2 BLE interface clock enable - 0 - 1 - - - - - C2AHB1SMENR - C2AHB1SMENR - CPU2 AHB1 peripheral clocks enable in Sleep and Stop modes register - 0x168 - 0x20 - read-write - 0x00011207 - - - TSCSMEN - CPU2 Touch Sensing Controller clocks enable during Sleep and Stop modes - 16 - 1 - - - CRCSMEN - CPU2 CRCSMEN - 12 - 1 - - - SRAM1SMEN - SRAM1 interface clock enable during CPU1 CSleep mode - 9 - 1 - - - DMAMUXSMEN - CPU2 DMAMUX clocks enable during Sleep and Stop modes - 2 - 1 - - - DMA2SMEN - CPU2 DMA2 clocks enable during Sleep and Stop modes - 1 - 1 - - - DMA1SMEN - CPU2 DMA1 clocks enable during Sleep and Stop modes - 0 - 1 - - - - - C2AHB2SMENR - C2AHB2SMENR - CPU2 AHB2 peripheral clocks enable in Sleep and Stop modes register - 0x16C - 0x20 - read-write - 0x0001209F - - - AES1SMEN - CPU2 AES1 accelerator clocks enable during Sleep and Stop modes - 16 - 1 - - - ADCFSSMEN - CPU2 ADC clocks enable during Sleep and Stop modes - 13 - 1 - - - GPIOHSMEN - CPU2 IO port H clocks enable during Sleep and Stop modes - 7 - 1 - - - GPIOESMEN - CPU2 IO port E clocks enable during Sleep and Stop modes - 4 - 1 - - - GPIODSMEN - CPU2 IO port D clocks enable during Sleep and Stop modes - 3 - 1 - - - GPIOCSMEN - CPU2 IO port C clocks enable during Sleep and Stop modes - 2 - 1 - - - GPIOBSMEN - CPU2 IO port B clocks enable during Sleep and Stop modes - 1 - 1 - - - GPIOASMEN - CPU2 IO port A clocks enable during Sleep and Stop modes - 0 - 1 - - - - - C2AHB3SMENR - C2AHB3SMENR - CPU2 AHB3 peripheral clocks enable in Sleep and Stop modes register - 0x170 - 0x20 - read-write - 0x03070000 - - - FLASHSMEN - Flash interface clocks enable during CPU2 sleep modes - 25 - 1 - - - SRAM2SMEN - SRAM2a and SRAM2b memory interface clocks enable during CPU2 sleep modes - 24 - 1 - - - RNGSMEN - True RNG clocks enable during CPU2 sleep modes - 18 - 1 - - - AES2SMEN - AES2 accelerator clocks enable during CPU2 sleep modes - 17 - 1 - - - PKASMEN - PKA accelerator clocks enable during CPU2 sleep modes - 16 - 1 - - - - - C2APB1SMENR1 - C2APB1SMENR1 - CPU2 APB1SMENR1 - 0x178 - 0x20 - read-write - 0x85A04601 - - - LPTIM1SMEN - Low power timer 1 clocks enable during CPU2 Sleep mode - 31 - 1 - - - USBSMEN - USB FS clocks enable during CPU2 Sleep mode - 26 - 1 - - - CRSMEN - CRS clocks enable during CPU2 Sleep mode - 24 - 1 - - - I2C3SMEN - I2C3 clocks enable during CPU2 Sleep mode - 23 - 1 - - - I2C1SMEN - I2C1 clocks enable during CPU2 Sleep mode - 21 - 1 - - - SPI2SMEN - SPI2 clocks enable during CPU2 Sleep mode - 14 - 1 - - - RTCAPBSMEN - RTC APB clocks enable during CPU2 Sleep mode - 10 - 1 - - - LCDSMEN - LCD clocks enable during CPU2 Sleep mode - 9 - 1 - - - TIM2SMEN - TIM2 timer clocks enable during CPU2 Sleep mode - 0 - 1 - - - - - C2APB1SMENR2 - C2APB1SMENR2 - CPU2 APB1 peripheral clocks enable in Sleep and Stop modes register 2 - 0x17C - 0x20 - read-write - 0x000000021 - - - LPTIM2SMEN - Low power timer 2 clocks enable during CPU2 Sleep mode - 5 - 1 - - - LPUART1SMEN - Low power UART 1 clocks enable during CPU2 Sleep mode - 0 - 1 - - - - - C2APB2SMENR - C2APB2SMENR - CPU2 APB2SMENR - 0x180 - 0x20 - read-write - 0x00265800 - - - SAI1SMEN - SAI1 clocks enable during CPU2 Sleep mode - 21 - 1 - - - TIM17SMEN - TIM17 timer clocks enable during CPU2 Sleep mode - 18 - 1 - - - TIM16SMEN - TIM16 timer clocks enable during CPU2 Sleep mode - 17 - 1 - - - USART1SMEN - USART1clocks enable during CPU2 Sleep mode - 14 - 1 - - - SPI1SMEN - SPI1 clocks enable during CPU2 Sleep mode - 12 - 1 - - - TIM1SMEN - TIM1 timer clocks enable during CPU2 Sleep mode - 11 - 1 - - - - - C2APB3SMENR - C2APB3SMENR - CPU2 APB3SMENR - 0x184 - 0x20 - read-write - 0x0000003 - - - SMEN802 - 802.15.4 interface clocks enable during CPU2 Sleep modes - 1 - 1 - - - BLESMEN - BLE interface clocks enable during CPU2 Sleep mode - 0 - 1 - - - - - - - PWR - Power control - PWR - 0x58000400 - - 0x0 - 0x400 - registers - - - PWR_SOTF - PWR switching on the fly - interrupt - 43 - - - - CR1 - CR1 - Power control register 1 - 0x0 - 0x20 - read-write - 0x00000200 - - - LPR - Low-power run - 14 - 1 - - - VOS - Voltage scaling range selection - 9 - 2 - - - DBP - Disable backup domain write protection - 8 - 1 - - - FPDS - Flash power down mode during LPsSleep for CPU1 - 5 - 1 - - - FPDR - Flash power down mode during LPRun for CPU1 - 4 - 1 - - - LPMS - Low-power mode selection for CPU1 - 0 - 3 - - - - - CR2 - CR2 - Power control register 2 - 0x4 - 0x20 - read-write - 0x00000000 - - - USV - VDDUSB USB supply valid - 10 - 1 - - - PVME3 - Peripheral voltage monitoring 3 enable: VDDA vs. 1.62V - 6 - 1 - - - PVME1 - Peripheral voltage monitoring 1 enable: VDDUSB vs. 1.2V - 4 - 1 - - - PLS - Power voltage detector level selection - 1 - 3 - - - PVDE - Power voltage detector enable - 0 - 1 - - - - - CR3 - CR3 - Power control register 3 - 0x8 - 0x20 - read-write - 0x00008000 - - - EIWUL - Enable internal wakeup line for CPU1 - 15 - 1 - - - EC2H - Enable CPU2 Hold interrupt for CPU1 - 14 - 1 - - - E802A - Enable end of activity interrupt for CPU1 - 13 - 1 - - - EBLEA - Enable BLE end of activity interrupt for CPU1 - 11 - 1 - - - ECRPE - Enable critical radio phase end of activity interrupt for CPU1 - 12 - 1 - - - APC - Apply pull-up and pull-down configuration - 10 - 1 - - - RRS - SRAM2a retention in Standby mode - 9 - 1 - - - EBORHSDFB - Enable BORH and Step Down counverter forced in Bypass interrups for CPU1 - 8 - 1 - - - EWUP5 - Enable Wakeup pin WKUP5 - 4 - 1 - - - EWUP4 - Enable Wakeup pin WKUP4 - 3 - 1 - - - EWUP3 - Enable Wakeup pin WKUP3 - 2 - 1 - - - EWUP2 - Enable Wakeup pin WKUP2 - 1 - 1 - - - EWUP1 - Enable Wakeup pin WKUP1 - 0 - 1 - - - - - CR4 - CR4 - Power control register 4 - 0xC - 0x20 - read-write - 0x00000000 - - - C2BOOT - BOOT CPU2 after reset or wakeup from Stop or Standby modes - 15 - 1 - - - VBRS - VBAT battery charging resistor selection - 9 - 1 - - - VBE - VBAT battery charging enable - 8 - 1 - - - WP5 - Wakeup pin WKUP5 polarity - 4 - 1 - - - WP4 - Wakeup pin WKUP4 polarity - 3 - 1 - - - WP3 - Wakeup pin WKUP3 polarity - 2 - 1 - - - WP2 - Wakeup pin WKUP2 polarity - 1 - 1 - - - WP1 - Wakeup pin WKUP1 polarity - 0 - 1 - - - - - SR1 - SR1 - Power status register 1 - 0x10 - 0x20 - read-only - 0x00000000 - - - WUFI - Internal Wakeup interrupt flag - 15 - 1 - - - C2HF - CPU2 Hold interrupt flag - 14 - 1 - - - AF802 - 802.15.4 end of activity interrupt flag - 13 - 1 - - - BLEAF - BLE end of activity interrupt flag - 12 - 1 - - - CRPEF - Enable critical radio phase end of activity interrupt flag - 11 - 1 - - - WUF802 - 802.15.4 wakeup interrupt flag - 10 - 1 - - - BLEWUF - BLE wakeup interrupt flag - 9 - 1 - - - BORHF - BORH interrupt flag - 8 - 1 - - - SDFBF - Step Down converter forced in Bypass interrupt flag - 7 - 1 - - - CWUF5 - Wakeup flag 5 - 4 - 1 - - - CWUF4 - Wakeup flag 4 - 3 - 1 - - - CWUF3 - Wakeup flag 3 - 2 - 1 - - - CWUF2 - Wakeup flag 2 - 1 - 1 - - - CWUF1 - Wakeup flag 1 - 0 - 1 - - - - - SR2 - SR2 - Power status register 2 - 0x14 - 0x20 - read-only - 0x00000002 - - - PVMO3 - Peripheral voltage monitoring output: VDDA vs. 1.62 V - 14 - 1 - - - PVMO1 - Peripheral voltage monitoring output: VDDUSB vs. 1.2 V - 12 - 1 - - - PVDO - Power voltage detector output - 11 - 1 - - - VOSF - Voltage scaling flag - 10 - 1 - - - REGLPF - Low-power regulator flag - 9 - 1 - - - REGLPS - Low-power regulator started - 8 - 1 - - - SDSMPSF - Step Down converter SMPS mode flag - 1 - 1 - - - SDBF - Step Down converter Bypass mode flag - 0 - 1 - - - - - SCR - SCR - Power status clear register - 0x18 - 0x20 - write-only - 0x00000000 - - - CC2HF - Clear CPU2 Hold interrupt flag - 14 - 1 - - - C802AF - Clear 802.15.4 end of activity interrupt flag - 13 - 1 - - - CBLEAF - Clear BLE end of activity interrupt flag - 12 - 1 - - - CCRPEF - Clear critical radio phase end of activity interrupt flag - 11 - 1 - - - C802WUF - Clear 802.15.4 wakeup interrupt flag - 10 - 1 - - - CBLEWUF - Clear BLE wakeup interrupt flag - 9 - 1 - - - CBORHF - Clear BORH interrupt flag - 8 - 1 - - - CSMPSFBF - Clear SMPS Step Down converter forced in Bypass interrupt flag - 7 - 1 - - - CWUF5 - Clear wakeup flag 5 - 4 - 1 - - - CWUF4 - Clear wakeup flag 4 - 3 - 1 - - - CWUF3 - Clear wakeup flag 3 - 2 - 1 - - - CWUF2 - Clear wakeup flag 2 - 1 - 1 - - - CWUF1 - Clear wakeup flag 1 - 0 - 1 - - - - - CR5 - CR5 - Power control register 5 - 0x1C - 0x20 - read-write - 0x00004270 - - - SDEB - Enable Step Down converter SMPS mode enabled - 15 - 1 - - - SDBEN - Enable Step Down converter Bypass mode enabled - 14 - 1 - - - SMPSCFG - VOS configuration selection (non user) - 9 - 1 - - - BORHC - BORH configuration selection - 8 - 1 - - - SDSC - Step Down converter supplt startup current selection - 4 - 3 - - - SDVOS - Step Down converter voltage output scaling - 0 - 4 - - - - - PUCRA - PUCRA - Power Port A pull-up control register - 0x20 - 0x20 - read-write - 0x00000000 - - - PU15 - Port A pull-up bit y (y=0..15) - 15 - 1 - - - PU13 - Port A pull-up bit y (y=0..15) - 13 - 1 - - - PU12 - Port A pull-up bit y (y=0..15) - 12 - 1 - - - PU11 - Port A pull-up bit y (y=0..15) - 11 - 1 - - - PU10 - Port A pull-up bit y (y=0..15) - 10 - 1 - - - PU9 - Port A pull-up bit y (y=0..15) - 9 - 1 - - - PU8 - Port A pull-up bit y (y=0..15) - 8 - 1 - - - PU7 - Port A pull-up bit y (y=0..15) - 7 - 1 - - - PU6 - Port A pull-up bit y (y=0..15) - 6 - 1 - - - PU5 - Port A pull-up bit y (y=0..15) - 5 - 1 - - - PU4 - Port A pull-up bit y (y=0..15) - 4 - 1 - - - PU3 - Port A pull-up bit y (y=0..15) - 3 - 1 - - - PU2 - Port A pull-up bit y (y=0..15) - 2 - 1 - - - PU1 - Port A pull-up bit y (y=0..15) - 1 - 1 - - - PU0 - Port A pull-up bit y (y=0..15) - 0 - 1 - - - - - PDCRA - PDCRA - Power Port A pull-down control register - 0x24 - 0x20 - read-write - 0x00000000 - - - PD14 - Port A pull-down bit y (y=0..15) - 14 - 1 - - - PD12 - Port A pull-down bit y (y=0..15) - 12 - 1 - - - PD11 - Port A pull-down bit y (y=0..15) - 11 - 1 - - - PD10 - Port A pull-down bit y (y=0..15) - 10 - 1 - - - PD9 - Port A pull-down bit y (y=0..15) - 9 - 1 - - - PD8 - Port A pull-down bit y (y=0..15) - 8 - 1 - - - PD7 - Port A pull-down bit y (y=0..15) - 7 - 1 - - - PD6 - Port A pull-down bit y (y=0..15) - 6 - 1 - - - PD5 - Port A pull-down bit y (y=0..15) - 5 - 1 - - - PD4 - Port A pull-down bit y (y=0..15) - 4 - 1 - - - PD3 - Port A pull-down bit y (y=0..15) - 3 - 1 - - - PD2 - Port A pull-down bit y (y=0..15) - 2 - 1 - - - PD1 - Port A pull-down bit y (y=0..15) - 1 - 1 - - - PD0 - Port A pull-down bit y (y=0..15) - 0 - 1 - - - - - PUCRB - PUCRB - Power Port B pull-up control register - 0x28 - 0x20 - read-write - 0x00000000 - - - PU15 - Port B pull-up bit y (y=0..15) - 15 - 1 - - - PU14 - Port B pull-up bit y (y=0..15) - 14 - 1 - - - PU13 - Port B pull-up bit y (y=0..15) - 13 - 1 - - - PU12 - Port B pull-up bit y (y=0..15) - 12 - 1 - - - PU11 - Port B pull-up bit y (y=0..15) - 11 - 1 - - - PU10 - Port B pull-up bit y (y=0..15) - 10 - 1 - - - PU9 - Port B pull-up bit y (y=0..15) - 9 - 1 - - - PU8 - Port B pull-up bit y (y=0..15) - 8 - 1 - - - PU7 - Port B pull-up bit y (y=0..15) - 7 - 1 - - - PU6 - Port B pull-up bit y (y=0..15) - 6 - 1 - - - PU5 - Port B pull-up bit y (y=0..15) - 5 - 1 - - - PU4 - Port B pull-up bit y (y=0..15) - 4 - 1 - - - PU3 - Port B pull-up bit y (y=0..15) - 3 - 1 - - - PU2 - Port B pull-up bit y (y=0..15) - 2 - 1 - - - PU1 - Port B pull-up bit y (y=0..15) - 1 - 1 - - - PU0 - Port B pull-up bit y (y=0..15) - 0 - 1 - - - - - PDCRB - PDCRB - Power Port B pull-down control register - 0x2C - 0x20 - read-write - 0x00000000 - - - PD15 - Port B pull-down bit y (y=0..15) - 15 - 1 - - - PD14 - Port B pull-down bit y (y=0..15) - 14 - 1 - - - PD13 - Port B pull-down bit y (y=0..15) - 13 - 1 - - - PD12 - Port B pull-down bit y (y=0..15) - 12 - 1 - - - PD11 - Port B pull-down bit y (y=0..15) - 11 - 1 - - - PD10 - Port B pull-down bit y (y=0..15) - 10 - 1 - - - PD9 - Port B pull-down bit y (y=0..15) - 9 - 1 - - - PD8 - Port B pull-down bit y (y=0..15) - 8 - 1 - - - PD7 - Port B pull-down bit y (y=0..15) - 7 - 1 - - - PD6 - Port B pull-down bit y (y=0..15) - 6 - 1 - - - PD5 - Port B pull-down bit y (y=0..15) - 5 - 1 - - - PD3 - Port B pull-down bit y (y=0..15) - 3 - 1 - - - PD2 - Port B pull-down bit y (y=0..15) - 2 - 1 - - - PD1 - Port B pull-down bit y (y=0..15) - 1 - 1 - - - PD0 - Port B pull-down bit y (y=0..15) - 0 - 1 - - - - - PUCRC - PUCRC - Power Port C pull-up control register - 0x30 - 0x20 - read-write - 0x00000000 - - - PU15 - Port C pull-up bit y (y=0..15) - 15 - 1 - - - PU14 - Port C pull-up bit y (y=0..15) - 14 - 1 - - - PU13 - Port C pull-up bit y (y=0..15) - 13 - 1 - - - PU12 - Port C pull-up bit y (y=0..15) - 12 - 1 - - - PU11 - Port C pull-up bit y (y=0..15) - 11 - 1 - - - PU10 - Port C pull-up bit y (y=0..15) - 10 - 1 - - - PU9 - Port C pull-up bit y (y=0..15) - 9 - 1 - - - PU8 - Port C pull-up bit y (y=0..15) - 8 - 1 - - - PU7 - Port C pull-up bit y (y=0..15) - 7 - 1 - - - PU6 - Port C pull-up bit y (y=0..15) - 6 - 1 - - - PU5 - Port C pull-up bit y (y=0..15) - 5 - 1 - - - PU4 - Port C pull-up bit y (y=0..15) - 4 - 1 - - - PU3 - Port C pull-up bit y (y=0..15) - 3 - 1 - - - PU2 - Port C pull-up bit y (y=0..15) - 2 - 1 - - - PU1 - Port C pull-up bit y (y=0..15) - 1 - 1 - - - PU0 - Port C pull-up bit y (y=0..15) - 0 - 1 - - - - - PDCRC - PDCRC - Power Port C pull-down control register - 0x34 - 0x20 - read-write - 0x00000000 - - - PD15 - Port C pull-down bit y (y=0..15) - 15 - 1 - - - PD14 - Port C pull-down bit y (y=0..15) - 14 - 1 - - - PD13 - Port C pull-down bit y (y=0..15) - 13 - 1 - - - PD12 - Port C pull-down bit y (y=0..15) - 12 - 1 - - - PD11 - Port C pull-down bit y (y=0..15) - 11 - 1 - - - PD10 - Port C pull-down bit y (y=0..15) - 10 - 1 - - - PD9 - Port C pull-down bit y (y=0..15) - 9 - 1 - - - PD8 - Port C pull-down bit y (y=0..15) - 8 - 1 - - - PD7 - Port C pull-down bit y (y=0..15) - 7 - 1 - - - PD6 - Port C pull-down bit y (y=0..15) - 6 - 1 - - - PD5 - Port C pull-down bit y (y=0..15) - 5 - 1 - - - PD4 - Port C pull-down bit y (y=0..15) - 4 - 1 - - - PD3 - Port C pull-down bit y (y=0..15) - 3 - 1 - - - PD2 - Port C pull-down bit y (y=0..15) - 2 - 1 - - - PD1 - Port C pull-down bit y (y=0..15) - 1 - 1 - - - PD0 - Port C pull-down bit y (y=0..15) - 0 - 1 - - - - - PUCRD - PUCRD - Power Port D pull-up control register - 0x38 - 0x20 - read-write - 0x00000000 - - - PU15 - Port D pull-up bit y (y=0..15) - 15 - 1 - - - PU14 - Port D pull-up bit y (y=0..15) - 14 - 1 - - - PU13 - Port D pull-up bit y (y=0..15) - 13 - 1 - - - PU12 - Port D pull-up bit y (y=0..15) - 12 - 1 - - - PU11 - Port D pull-up bit y (y=0..15) - 11 - 1 - - - PU10 - Port D pull-up bit y (y=0..15) - 10 - 1 - - - PU9 - Port D pull-up bit y (y=0..15) - 9 - 1 - - - PU8 - Port D pull-up bit y (y=0..15) - 8 - 1 - - - PU7 - Port D pull-up bit y (y=0..15) - 7 - 1 - - - PU6 - Port D pull-up bit y (y=0..15) - 6 - 1 - - - PU5 - Port D pull-up bit y (y=0..15) - 5 - 1 - - - PU4 - Port D pull-up bit y (y=0..15) - 4 - 1 - - - PU3 - Port D pull-up bit y (y=0..15) - 3 - 1 - - - PU2 - Port D pull-up bit y (y=0..15) - 2 - 1 - - - PU1 - Port D pull-up bit y (y=0..15) - 1 - 1 - - - PU0 - Port D pull-up bit y (y=0..15) - 0 - 1 - - - - - PDCRD - PDCRD - Power Port D pull-down control register - 0x3C - 0x20 - read-write - 0x00000000 - - - PD15 - Port D pull-down bit y (y=0..15) - 15 - 1 - - - PD14 - Port D pull-down bit y (y=0..15) - 14 - 1 - - - PD13 - Port D pull-down bit y (y=0..15) - 13 - 1 - - - PD12 - Port D pull-down bit y (y=0..15) - 12 - 1 - - - PD11 - Port D pull-down bit y (y=0..15) - 11 - 1 - - - PD10 - Port D pull-down bit y (y=0..15) - 10 - 1 - - - PD9 - Port D pull-down bit y (y=0..15) - 9 - 1 - - - PD8 - Port D pull-down bit y (y=0..15) - 8 - 1 - - - PD7 - Port D pull-down bit y (y=0..15) - 7 - 1 - - - PD6 - Port D pull-down bit y (y=0..15) - 6 - 1 - - - PD5 - Port D pull-down bit y (y=0..15) - 5 - 1 - - - PD4 - Port D pull-down bit y (y=0..15) - 4 - 1 - - - PD3 - Port D pull-down bit y (y=0..15) - 3 - 1 - - - PD2 - Port D pull-down bit y (y=0..15) - 2 - 1 - - - PD1 - Port D pull-down bit y (y=0..15) - 1 - 1 - - - PD0 - Port D pull-down bit y (y=0..15) - 0 - 1 - - - - - PUCRE - PUCRE - Power Port E pull-up control register - 0x40 - 0x20 - read-write - 0x00000000 - - - PU4 - Port E pull-up bit y (y=0..15) - 4 - 1 - - - PU3 - Port E pull-up bit y (y=0..15) - 3 - 1 - - - PU2 - Port E pull-up bit y (y=0..15) - 2 - 1 - - - PU1 - Port E pull-up bit y (y=0..15) - 1 - 1 - - - PU0 - Port E pull-up bit y (y=0..15) - 0 - 1 - - - - - PDCRE - PDCRE - Power Port E pull-down control register - 0x44 - 0x20 - read-write - 0x00000000 - - - PD4 - Port E pull-down bit y (y=0..15) - 4 - 1 - - - PD3 - Port E pull-down bit y (y=0..15) - 3 - 1 - - - PD2 - Port E pull-down bit y (y=0..15) - 2 - 1 - - - PD1 - Port E pull-down bit y (y=0..15) - 1 - 1 - - - PD0 - Port E pull-down bit y (y=0..15) - 0 - 1 - - - - - PUCRH - PUCRH - Power Port H pull-up control register - 0x58 - 0x20 - read-write - 0x00000000 - - - PU3 - Port H pull-up bit y (y=0..1) - 3 - 1 - - - PU1 - Port H pull-up bit y (y=0..1) - 1 - 1 - - - PU0 - Port H pull-up bit y (y=0..1) - 0 - 1 - - - - - PDCRH - PDCRH - Power Port H pull-down control register - 0x5C - 0x20 - read-write - 0x00000000 - - - PD3 - Port H pull-down bit y (y=0..1) - 3 - 1 - - - PD1 - Port H pull-down bit y (y=0..1) - 1 - 1 - - - PD0 - Port H pull-down bit y (y=0..1) - 0 - 1 - - - - - C2CR1 - C2CR1 - CPU2 Power control register 1 - 0x80 - 0x20 - read-write - 0x00000000 - - - EWKUP802 - 802.15.4 external wakeup signal - 15 - 1 - - - BLEEWKUP - BLE external wakeup signal - 14 - 1 - - - FPDS - Flash power down mode during LPSleep for CPU2 - 5 - 1 - - - FPDR - Flash power down mode during LPRun for CPU2 - 4 - 1 - - - LPMS - Low-power mode selection for CPU2 - 0 - 3 - - - - - C2CR3 - C2CR3 - CPU2 Power control register 3 - 0x84 - 0x20 - read-write - 0X00008000 - - - EIWUL - Enable internal wakeup line for CPU2 - 15 - 1 - - - APC - Apply pull-up and pull-down configuration for CPU2 - 12 - 1 - - - E802WUP - Enable 802.15.4 host wakeup interrupt for CPU2 - 10 - 1 - - - EBLEWUP - Enable BLE host wakeup interrupt for CPU2 - 9 - 1 - - - EWUP5 - Enable Wakeup pin WKUP5 for CPU2 - 4 - 1 - - - EWUP4 - Enable Wakeup pin WKUP4 for CPU2 - 3 - 1 - - - EWUP3 - Enable Wakeup pin WKUP3 for CPU2 - 2 - 1 - - - EWUP2 - Enable Wakeup pin WKUP2 for CPU2 - 1 - 1 - - - EWUP1 - Enable Wakeup pin WKUP1 for CPU2 - 0 - 1 - - - - - EXTSCR - EXTSCR - Power status clear register - 0x88 - 0x20 - 0x00000000 - - - C2DS - CPU2 deepsleep mode - 15 - 1 - read-only - - - C1DS - CPU1 deepsleep mode - 14 - 1 - read-only - - - CRPF - Critical Radio system phase - 13 - 1 - read-only - - - C2STOPF - System Stop flag for CPU2 - 11 - 1 - read-only - - - C2SBF - System Standby flag for CPU2 - 10 - 1 - read-only - - - C1STOPF - System Stop flag for CPU1 - 9 - 1 - read-only - - - C1SBF - System Standby flag for CPU1 - 8 - 1 - read-only - - - CCRPF - Clear Critical Radio system phase - 2 - 1 - write-only - - - C2CSSF - Clear CPU2 Stop Standby flags - 1 - 1 - write-only - - - C1CSSF - Clear CPU1 Stop Standby flags - 0 - 1 - write-only - - - - - - - SYSCFG_VREFBUF - SYSCFG_VREFBUF - SYSCFG_VREFBUF - 0x40010000 - - 0x0 - 0x200 - registers - - - - SYSCFG_MEMRMP - SYSCFG_MEMRMP - memory remap register - 0x0 - 0x20 - read-write - 0x00000000 - - - MEM_MODE - Memory mapping selection - 0 - 3 - - - - - SYSCFG_CFGR1 - SYSCFG_CFGR1 - configuration register 1 - 0x4 - 0x20 - read-write - 0x7C000001 - - - FPU_IE - Floating Point Unit interrupts enable bits - 26 - 6 - - - I2C3_FMP - I2C3 Fast-mode Plus driving capability activation - 22 - 1 - - - I2C1_FMP - I2C1 Fast-mode Plus driving capability activation - 20 - 1 - - - I2C_PB9_FMP - Fast-mode Plus (Fm+) driving capability activation on PB9 - 19 - 1 - - - I2C_PB8_FMP - Fast-mode Plus (Fm+) driving capability activation on PB8 - 18 - 1 - - - I2C_PB7_FMP - Fast-mode Plus (Fm+) driving capability activation on PB7 - 17 - 1 - - - I2C_PB6_FMP - Fast-mode Plus (Fm+) driving capability activation on PB6 - 16 - 1 - - - BOOSTEN - I/O analog switch voltage booster enable - 8 - 1 - - - - - SYSCFG_EXTICR1 - SYSCFG_EXTICR1 - external interrupt configuration register 1 - 0x8 - 0x20 - read-write - 0x00000000 - - - EXTI3 - EXTI 3 configuration bits - 12 - 3 - - - EXTI2 - EXTI 2 configuration bits - 8 - 3 - - - EXTI1 - EXTI 1 configuration bits - 4 - 3 - - - EXTI0 - EXTI 0 configuration bits - 0 - 3 - - - - - SYSCFG_EXTICR2 - SYSCFG_EXTICR2 - external interrupt configuration register 2 - 0xC - 0x20 - read-write - 0x00000000 - - - EXTI7 - EXTI 7 configuration bits - 12 - 3 - - - EXTI6 - EXTI 6 configuration bits - 8 - 3 - - - EXTI5 - EXTI 5 configuration bits - 4 - 3 - - - EXTI4 - EXTI 4 configuration bits - 0 - 3 - - - - - SYSCFG_EXTICR3 - SYSCFG_EXTICR3 - external interrupt configuration register 3 - 0x10 - 0x20 - read-write - 0x00000000 - - - EXTI11 - EXTI 11 configuration bits - 12 - 3 - - - EXTI10 - EXTI 10 configuration bits - 8 - 3 - - - EXTI9 - EXTI 9 configuration bits - 4 - 3 - - - EXTI8 - EXTI 8 configuration bits - 0 - 3 - - - - - SYSCFG_EXTICR4 - SYSCFG_EXTICR4 - external interrupt configuration register 4 - 0x14 - 0x20 - read-write - 0x00000000 - - - EXTI15 - EXTI15 configuration bits - 12 - 3 - - - EXTI14 - EXTI14 configuration bits - 8 - 3 - - - EXTI13 - EXTI13 configuration bits - 4 - 3 - - - EXTI12 - EXTI12 configuration bits - 0 - 3 - - - - - SYSCFG_SCSR - SYSCFG_SCSR - SCSR - 0x18 - 0x20 - 0x00000000 - - - SRAM2BSY - SRAM2 busy by erase operation - 1 - 1 - read-only - - - SRAM2ER - SRAM2 Erase - 0 - 1 - read-write - - - C2RFD - CPU2 SRAM fetch (execution) disable. - 31 - 1 - read-write - - - - - SYSCFG_CFGR2 - SYSCFG_CFGR2 - CFGR2 - 0x1C - 0x20 - 0x00000000 - - - SPF - SRAM2 parity error flag - 8 - 1 - read-write - - - ECCL - ECC Lock - 3 - 1 - write-only - - - PVDL - PVD lock enable bit - 2 - 1 - write-only - - - SPL - SRAM2 parity lock bit - 1 - 1 - write-only - - - CLL - Cortex-M4 LOCKUP (Hardfault) output enable bit - 0 - 1 - write-only - - - - - SYSCFG_SWPR - SYSCFG_SWPR - SRAM2 write protection register - 0x20 - 0x20 - write-only - 0x00000000 - - - P31WP - SRAM2 page 31 write protection - 31 - 1 - - - P30WP - P30WP - 30 - 1 - - - P29WP - P29WP - 29 - 1 - - - P28WP - P28WP - 28 - 1 - - - P27WP - P27WP - 27 - 1 - - - P26WP - P26WP - 26 - 1 - - - P25WP - P25WP - 25 - 1 - - - P24WP - P24WP - 24 - 1 - - - P23WP - P23WP - 23 - 1 - - - P22WP - P22WP - 22 - 1 - - - P21WP - P21WP - 21 - 1 - - - P20WP - P20WP - 20 - 1 - - - P19WP - P19WP - 19 - 1 - - - P18WP - P18WP - 18 - 1 - - - P17WP - P17WP - 17 - 1 - - - P16WP - P16WP - 16 - 1 - - - P15WP - P15WP - 15 - 1 - - - P14WP - P14WP - 14 - 1 - - - P13WP - P13WP - 13 - 1 - - - P12WP - P12WP - 12 - 1 - - - P11WP - P11WP - 11 - 1 - - - P10WP - P10WP - 10 - 1 - - - P9WP - P9WP - 9 - 1 - - - P8WP - P8WP - 8 - 1 - - - P7WP - P7WP - 7 - 1 - - - P6WP - P6WP - 6 - 1 - - - P5WP - P5WP - 5 - 1 - - - P4WP - P4WP - 4 - 1 - - - P3WP - P3WP - 3 - 1 - - - P2WP - P2WP - 2 - 1 - - - P1WP - P1WP - 1 - 1 - - - P0WP - P0WP - 0 - 1 - - - - - SYSCFG_SKR - SYSCFG_SKR - SKR - 0x24 - 0x20 - write-only - 0x00000000 - - - KEY - SRAM2 write protection key for software erase - 0 - 8 - - - - - SYSCFG_SWPR2 - SYSCFG_SWPR2 - SRAM2 write protection register 2 - 0x28 - 0x20 - write-only - 0x00000000 - - - P63WP - SRAM2 page 63 write protection - 31 - 1 - - - P62WP - P62WP - 30 - 1 - - - P61WP - P61WP - 29 - 1 - - - P60WP - P60WP - 28 - 1 - - - P59WP - P59WP - 27 - 1 - - - P58WP - P58WP - 26 - 1 - - - P57WP - P57WP - 25 - 1 - - - P56WP - P56WP - 24 - 1 - - - P55WP - P55WP - 23 - 1 - - - P54WP - P54WP - 22 - 1 - - - P53WP - P53WP - 21 - 1 - - - P52WP - P52WP - 20 - 1 - - - P51WP - P51WP - 19 - 1 - - - P50WP - P50WP - 18 - 1 - - - P49WP - P49WP - 17 - 1 - - - P48WP - P48WP - 16 - 1 - - - P47WP - P47WP - 15 - 1 - - - P46WP - P46WP - 14 - 1 - - - P45WP - P45WP - 13 - 1 - - - P44WP - P44WP - 12 - 1 - - - P43WP - P43WP - 11 - 1 - - - P42WP - P42WP - 10 - 1 - - - P41WP - P41WP - 9 - 1 - - - P40WP - P40WP - 8 - 1 - - - P39WP - P39WP - 7 - 1 - - - P38WP - P38WP - 6 - 1 - - - P37WP - P37WP - 5 - 1 - - - P36WP - P36WP - 4 - 1 - - - P35WP - P35WP - 3 - 1 - - - P34WP - P34WP - 2 - 1 - - - P33WP - P33WP - 1 - 1 - - - P32WP - P32WP - 0 - 1 - - - - - VREFBUF_CSR - VREFBUF_CSR - VREF control and status register - 0x30 - 0x20 - 0x00000002 - - - ENVR - Voltage reference buffer enable - 0 - 1 - read-write - - - HIZ - High impedance mode - 1 - 1 - read-write - - - VRS - Voltage reference scale - 2 - 1 - read-write - - - VRR - Voltage reference buffer ready - 3 - 1 - read-only - - - - - VREFBUF_CCR - VREFBUF_CCR - calibration control register - 0x34 - 0x20 - read-write - 0x00000000 - - - TRIM - Trimming code - 0 - 6 - - - - - SYSCFG_IMR1 - SYSCFG_IMR1 - CPU1 interrupt mask register 1 - 0x100 - 0x20 - read-write - 0x00000000 - - - TIM1IM - Peripheral TIM1 interrupt mask to CPU1 - 13 - 1 - - - TIM16IM - Peripheral TIM16 interrupt mask to CPU1 - 14 - 1 - - - TIM17IM - Peripheral TIM17 interrupt mask to CPU1 - 15 - 1 - - - EXIT5IM - Peripheral EXIT5 interrupt mask to CPU1 - 21 - 1 - - - EXIT6IM - Peripheral EXIT6 interrupt mask to CPU1 - 22 - 1 - - - EXIT7IM - Peripheral EXIT7 interrupt mask to CPU1 - 23 - 1 - - - EXIT8IM - Peripheral EXIT8 interrupt mask to CPU1 - 24 - 1 - - - EXIT9IM - Peripheral EXIT9 interrupt mask to CPU1 - 25 - 1 - - - EXIT10IM - Peripheral EXIT10 interrupt mask to CPU1 - 26 - 1 - - - EXIT11IM - Peripheral EXIT11 interrupt mask to CPU1 - 27 - 1 - - - EXIT12IM - Peripheral EXIT12 interrupt mask to CPU1 - 28 - 1 - - - EXIT13IM - Peripheral EXIT13 interrupt mask to CPU1 - 29 - 1 - - - EXIT14IM - Peripheral EXIT14 interrupt mask to CPU1 - 30 - 1 - - - EXIT15IM - Peripheral EXIT15 interrupt mask to CPU1 - 31 - 1 - - - - - SYSCFG_IMR2 - SYSCFG_IMR2 - CPU1 interrupt mask register 2 - 0x104 - 0x20 - read-write - 0x00000000 - - - PVM3IM - Peripheral PVM3 interrupt mask to CPU1 - 18 - 1 - - - PVM1IM - Peripheral PVM1 interrupt mask to CPU1 - 16 - 1 - - - PVDIM - Peripheral PVD interrupt mask to CPU1 - 20 - 1 - - - - - SYSCFG_C2IMR1 - SYSCFG_C2IMR1 - CPU2 interrupt mask register 1 - 0x108 - 0x20 - read-write - 0x00000000 - - - RTCSTAMP - Peripheral RTCSTAMP interrupt mask to CPU2 - 0 - 1 - - - RTCWKUP - Peripheral RTCWKUP interrupt mask to CPU2 - 3 - 1 - - - RTCALARM - Peripheral RTCALARM interrupt mask to CPU2 - 4 - 1 - - - RCC - Peripheral RCC interrupt mask to CPU2 - 5 - 1 - - - FLASH - Peripheral FLASH interrupt mask to CPU2 - 6 - 1 - - - PKA - Peripheral PKA interrupt mask to CPU2 - 8 - 1 - - - RNG - Peripheral RNG interrupt mask to CPU2 - 9 - 1 - - - AES1 - Peripheral AES1 interrupt mask to CPU2 - 10 - 1 - - - COMP - Peripheral COMP interrupt mask to CPU2 - 11 - 1 - - - ADC - Peripheral ADC interrupt mask to CPU2 - 12 - 1 - - - - - SYSCFG_C2IMR2 - SYSCFG_C2IMR2 - CPU2 interrupt mask register 1 - 0x10C - 0x20 - read-write - 0x00000000 - - - DMA1_CH1_IM - Peripheral DMA1 CH1 interrupt mask to CPU2 - 0 - 1 - - - DMA1_CH2_IM - Peripheral DMA1 CH2 interrupt mask to CPU2 - 1 - 1 - - - DMA1_CH3_IM - Peripheral DMA1 CH3 interrupt mask to CPU2 - 2 - 1 - - - DMA1_CH4_IM - Peripheral DMA1 CH4 interrupt mask to CPU2 - 3 - 1 - - - DMA1_CH5_IM - Peripheral DMA1 CH5 interrupt mask to CPU2 - 4 - 1 - - - DMA1_CH6_IM - Peripheral DMA1 CH6 interrupt mask to CPU2 - 5 - 1 - - - DMA1_CH7_IM - Peripheral DMA1 CH7 interrupt mask to CPU2 - 6 - 1 - - - DMA2_CH1_IM - Peripheral DMA2 CH1 interrupt mask to CPU1 - 8 - 1 - - - DMA2_CH2_IM - Peripheral DMA2 CH2 interrupt mask to CPU1 - 9 - 1 - - - DMA2_CH3_IM - Peripheral DMA2 CH3 interrupt mask to CPU1 - 10 - 1 - - - DMA2_CH4_IM - Peripheral DMA2 CH4 interrupt mask to CPU1 - 11 - 1 - - - DMA2_CH5_IM - Peripheral DMA2 CH5 interrupt mask to CPU1 - 12 - 1 - - - DMA2_CH6_IM - Peripheral DMA2 CH6 interrupt mask to CPU1 - 13 - 1 - - - DMA2_CH7_IM - Peripheral DMA2 CH7 interrupt mask to CPU1 - 14 - 1 - - - DMAM_UX1_IM - Peripheral DMAM UX1 interrupt mask to CPU1 - 15 - 1 - - - PVM1IM - Peripheral PVM1IM interrupt mask to CPU1 - 16 - 1 - - - PVM3IM - Peripheral PVM3IM interrupt mask to CPU1 - 18 - 1 - - - PVDIM - Peripheral PVDIM interrupt mask to CPU1 - 20 - 1 - - - TSCIM - Peripheral TSCIM interrupt mask to CPU1 - 21 - 1 - - - LCDIM - Peripheral LCDIM interrupt mask to CPU1 - 22 - 1 - - - - - SYSCFG_SIPCR - SYSCFG_SIPCR - secure IP control register - 0x110 - 0x20 - read-write - 0x00000000 - - - SAES1 - Enable AES1 KEY[7:0] security. - 0 - 1 - - - SAES2 - Enable AES2 security. - 1 - 1 - - - SPKA - Enable PKA security - 2 - 1 - - - SRNG - Enable True RNG security - 3 - 1 - - - - - - - COMP - Comparator instance 1 - COMP - 0x40010200 - - 0x0 - 0x9 - registers - - - COMP - COMP2 & COMP1 interrupt through - AIEC[21:20] - 22 - - - - COMP1_CSR - COMP1_CSR - Comparator control and status register - 0x0 - 0x20 - 0x00000000 - - - COMP1_EN - Comparator enable - 0 - 1 - read-write - - - COMP1_PWRMODE - Comparator power mode - 2 - 2 - read-write - - - COMP1_INMSEL - Comparator input minus selection - 4 - 3 - read-write - - - COMP1_INPSEL - Comparator input plus selection - 7 - 2 - read-write - - - COMP1_POLARITY - Comparator output polarity - 15 - 1 - read-write - - - COMP1_HYST - Comparator hysteresis - 16 - 2 - read-write - - - COMP1_BLANKING - Comparator blanking source - 18 - 3 - read-write - - - COMP1_BRGEN - Comparator voltage scaler enable - 22 - 1 - read-write - - - COMP1_SCALEN - Comparator scaler bridge enable - 23 - 1 - read-write - - - COMP1_INMESEL - Comparator input minus extended selection - 25 - 2 - read-write - - - COMP1_VALUE - Comparator output level - 30 - 1 - read-only - - - COMP1_LOCK - Comparator lock - 31 - 1 - read-write - - - - - COMP2_CSR - COMP2_CSR - Comparator 2 control and status register - 0x4 - 0x20 - 0x00000000 - - - COMP2_EN - Comparator 2 enable bit - 0 - 1 - read-write - - - COMP2_PWRMODE - Power Mode of the comparator 2 - 2 - 2 - read-write - - - COMP2_INMSEL - Comparator 2 input minus selection bits - 4 - 2 - read-write - - - COMP2_INPSEL - Comparator 1 input plus selection bit - 7 - 2 - read-write - - - COMP2_WINMODE - Windows mode selection bit - 9 - 1 - read-write - - - COMP2_POLARITY - Comparator 2 polarity selection bit - 15 - 1 - read-write - - - COMP2_HYST - Comparator 2 hysteresis selection bits - 16 - 2 - read-write - - - COMP2_BLANKING - Comparator 2 blanking source selection bits - 18 - 3 - read-write - - - COMP2_BRGEN - Scaler bridge enable - 22 - 1 - read-write - - - COMP2_SCALEN - Voltage scaler enable bit - 23 - 1 - read-write - - - COMP2_INMESEL - comparator 2 input minus extended selection bits. - 25 - 2 - read-write - - - COMP2_VALUE - Comparator 2 output status bit - 30 - 1 - read-only - - - COMP2_LOCK - CSR register lock bit - 31 - 1 - read-write - - - - - - - RNG - Random number generator - RNG - 0x58001000 - - 0x0 - 0x400 - registers - - - True_RNG - True random number generator - interrupt - 53 - - - - CR - CR - control register - 0x0 - 0x20 - read-write - 0x00000000 - - - RNGEN - Random number generator enable - 2 - 1 - - - IE - Interrupt enable - 3 - 1 - - - BYP - Bypass mode enable - 6 - 1 - - - - - SR - SR - status register - 0x4 - 0x20 - 0x00000000 - - - SEIS - Seed error interrupt status - 6 - 1 - read-write - - - CEIS - Clock error interrupt status - 5 - 1 - read-write - - - SECS - Seed error current status - 2 - 1 - read-only - - - CECS - Clock error current status - 1 - 1 - read-only - - - DRDY - Data ready - 0 - 1 - read-only - - - - - DR - DR - data register - 0x8 - 0x20 - read-only - 0x00000000 - - - RNDATA - Random data - 0 - 32 - - - - - - - AES1 - Advanced encryption standard hardware accelerator 1 - AES1 - 0x50060000 - - 0x0 - 0x400 - registers - - - AES1 - AES1 global interrupt - 51 - - - - CR - CR - control register - 0x0 - 0x20 - read-write - 0x00000000 - - - NPBLB - Number of padding bytes in last block of payload - 20 - 4 - - - KEYSIZE - Key size selection - 18 - 1 - - - CHMOD2 - AES chaining mode Bit2 - 16 - 1 - - - GCMPH - Used only for GCM, CCM and GMAC algorithms and has no effect when other algorithms are selected - 13 - 2 - - - DMAOUTEN - Enable DMA management of data output phase - 12 - 1 - - - DMAINEN - Enable DMA management of data input phase - 11 - 1 - - - ERRIE - Error interrupt enable - 10 - 1 - - - CCFIE - CCF flag interrupt enable - 9 - 1 - - - ERRC - Error clear - 8 - 1 - - - CCFC - Computation Complete Flag Clear - 7 - 1 - - - CHMOD10 - AES chaining mode Bit1 Bit0 - 5 - 2 - - - MODE - AES operating mode - 3 - 2 - - - DATATYPE - Data type selection (for data in and data out to/from the cryptographic block) - 1 - 2 - - - EN - AES enable - 0 - 1 - - - - - SR - SR - status register - 0x4 - 0x20 - read-only - 0x00000000 - - - BUSY - Busy flag - 3 - 1 - - - WRERR - Write error flag - 2 - 1 - - - RDERR - Read error flag - 1 - 1 - - - CCF - Computation complete flag - 0 - 1 - - - - - DINR - DINR - data input register - 0x8 - 0x20 - read-write - 0x00000000 - - - AES_DINR - Data Input Register - 0 - 32 - - - - - DOUTR - DOUTR - data output register - 0xC - 0x20 - read-only - 0x00000000 - - - AES_DOUTR - Data output register - 0 - 32 - - - - - KEYR0 - KEYR0 - key register 0 - 0x10 - 0x20 - read-write - 0x00000000 - - - AES_KEYR0 - Data Output Register (LSB key [31:0]) - 0 - 32 - - - - - KEYR1 - KEYR1 - key register 1 - 0x14 - 0x20 - read-write - 0x00000000 - - - AES_KEYR1 - AES key register (key [63:32]) - 0 - 32 - - - - - KEYR2 - KEYR2 - key register 2 - 0x18 - 0x20 - read-write - 0x00000000 - - - AES_KEYR2 - AES key register (key [95:64]) - 0 - 32 - - - - - KEYR3 - KEYR3 - key register 3 - 0x1C - 0x20 - read-write - 0x00000000 - - - AES_KEYR3 - AES key register (MSB key [127:96]) - 0 - 32 - - - - - IVR0 - IVR0 - initialization vector register 0 - 0x20 - 0x20 - read-write - 0x00000000 - - - AES_IVR0 - initialization vector register (LSB IVR [31:0]) - 0 - 32 - - - - - IVR1 - IVR1 - initialization vector register 1 - 0x24 - 0x20 - read-write - 0x00000000 - - - AES_IVR1 - Initialization Vector Register (IVR [63:32]) - 0 - 32 - - - - - IVR2 - IVR2 - initialization vector register 2 - 0x28 - 0x20 - read-write - 0x00000000 - - - AES_IVR2 - Initialization Vector Register (IVR [95:64]) - 0 - 32 - - - - - IVR3 - IVR3 - initialization vector register 3 - 0x2C - 0x20 - read-write - 0x00000000 - - - AES_IVR3 - Initialization Vector Register (MSB IVR [127:96]) - 0 - 32 - - - - - KEYR4 - KEYR4 - key register 4 - 0x30 - 0x20 - read-write - 0x00000000 - - - AES_KEYR4 - AES key register (MSB key [159:128]) - 0 - 32 - - - - - KEYR5 - KEYR5 - key register 5 - 0x34 - 0x20 - read-write - 0x00000000 - - - AES_KEYR5 - AES key register (MSB key [191:160]) - 0 - 32 - - - - - KEYR6 - KEYR6 - key register 6 - 0x38 - 0x20 - read-write - 0x00000000 - - - AES_KEYR6 - AES key register (MSB key [223:192]) - 0 - 32 - - - - - KEYR7 - KEYR7 - key register 7 - 0x3C - 0x20 - read-write - 0x00000000 - - - AES_KEYR7 - AES key register (MSB key [255:224]) - 0 - 32 - - - - - SUSP0R - SUSP0R - AES suspend register 0 - 0x40 - 0x20 - read-write - 0x00000000 - - - AES_SUSP0R - AES suspend register 0 - 0 - 32 - - - - - SUSP1R - SUSP1R - AES suspend register 1 - 0x44 - 0x20 - read-write - 0x00000000 - - - AES_SUSP1R - AES suspend register 1 - 0 - 32 - - - - - SUSP2R - SUSP2R - AES suspend register 2 - 0x48 - 0x20 - read-write - 0x00000000 - - - AES_SUSP2R - AES suspend register 2 - 0 - 32 - - - - - SUSP3R - SUSP3R - AES suspend register 3 - 0x4C - 0x20 - read-write - 0x00000000 - - - AES_SUSP3R - AES suspend register 3 - 0 - 32 - - - - - SUSP4R - SUSP4R - AES suspend register 4 - 0x50 - 0x20 - read-write - 0x00000000 - - - AES_SUSP4R - AES suspend register 4 - 0 - 32 - - - - - SUSP5R - SUSP5R - AES suspend register 5 - 0x54 - 0x20 - read-write - 0x00000000 - - - AES_SUSP5R - AES suspend register 5 - 0 - 32 - - - - - SUSP6R - SUSP6R - AES suspend register 6 - 0x58 - 0x20 - read-write - 0x00000000 - - - AES_SUSP6R - AES suspend register 6 - 0 - 32 - - - - - SUSP7R - SUSP7R - AES suspend register 7 - 0x5C - 0x20 - read-write - 0x00000000 - - - AES_SUSP7R - AES suspend register 7 - 0 - 32 - - - - - HWCFR - HWCFR - AES hardware configuration register - 0x3F0 - 0x20 - read-only - 0x00000002 - - - CFG4 - HW Generic 4 - 12 - 4 - - - CFG3 - HW Generic 3 - 8 - 4 - - - CFG2 - HW Generic 2 - 4 - 4 - - - CFG1 - HW Generic 1 - 0 - 4 - - - - - VERR - VERR - AES version register - 0x3F4 - 0x20 - read-only - 0x00000010 - - - MAJREV - Major revision - 4 - 4 - - - MINREV - Minor revision - 0 - 4 - - - - - IPIDR - IPIDR - AES identification register - 0x3F8 - 0x20 - read-only - 0x00170023 - - - ID - Identification code - 0 - 32 - - - - - SIDR - SIDR - AES size ID register - 0x3FC - 0x20 - read-only - 0xA3C5DD01 - - - ID - Size Identification code - 0 - 32 - - - - - - - AES2 - Advanced encryption standard hardware accelerator 1 - AES1 - 0x58001800 - - 0x0 - 0x400 - registers - - - AES2 - AES2 global interrupt - 52 - - - - CR - CR - control register - 0x0 - 0x20 - read-write - 0x00000000 - - - NPBLB - Number of padding bytes in last block of payload - 20 - 4 - - - KEYSIZE - Key size selection - 18 - 1 - - - CHMOD2 - AES chaining mode Bit2 - 16 - 1 - - - GCMPH - Used only for GCM, CCM and GMAC algorithms and has no effect when other algorithms are selected - 13 - 2 - - - DMAOUTEN - Enable DMA management of data output phase - 12 - 1 - - - DMAINEN - Enable DMA management of data input phase - 11 - 1 - - - ERRIE - Error interrupt enable - 10 - 1 - - - CCFIE - CCF flag interrupt enable - 9 - 1 - - - ERRC - Error clear - 8 - 1 - - - CCFC - Computation Complete Flag Clear - 7 - 1 - - - CHMOD10 - AES chaining mode Bit1 Bit0 - 5 - 2 - - - MODE - AES operating mode - 3 - 2 - - - DATATYPE - Data type selection (for data in and data out to/from the cryptographic block) - 1 - 2 - - - EN - AES enable - 0 - 1 - - - - - SR - SR - status register - 0x4 - 0x20 - read-only - 0x00000000 - - - BUSY - Busy flag - 3 - 1 - - - WRERR - Write error flag - 2 - 1 - - - RDERR - Read error flag - 1 - 1 - - - CCF - Computation complete flag - 0 - 1 - - - - - DINR - DINR - data input register - 0x8 - 0x20 - read-write - 0x00000000 - - - AES_DINR - Data Input Register - 0 - 32 - - - - - DOUTR - DOUTR - data output register - 0xC - 0x20 - read-only - 0x00000000 - - - AES_DOUTR - Data output register - 0 - 32 - - - - - KEYR0 - KEYR0 - key register 0 - 0x10 - 0x20 - read-write - 0x00000000 - - - AES_KEYR0 - Data Output Register (LSB key [31:0]) - 0 - 32 - - - - - KEYR1 - KEYR1 - key register 1 - 0x14 - 0x20 - read-write - 0x00000000 - - - AES_KEYR1 - AES key register (key [63:32]) - 0 - 32 - - - - - KEYR2 - KEYR2 - key register 2 - 0x18 - 0x20 - read-write - 0x00000000 - - - AES_KEYR2 - AES key register (key [95:64]) - 0 - 32 - - - - - KEYR3 - KEYR3 - key register 3 - 0x1C - 0x20 - read-write - 0x00000000 - - - AES_KEYR3 - AES key register (MSB key [127:96]) - 0 - 32 - - - - - IVR0 - IVR0 - initialization vector register 0 - 0x20 - 0x20 - read-write - 0x00000000 - - - AES_IVR0 - initialization vector register (LSB IVR [31:0]) - 0 - 32 - - - - - IVR1 - IVR1 - initialization vector register 1 - 0x24 - 0x20 - read-write - 0x00000000 - - - AES_IVR1 - Initialization Vector Register (IVR [63:32]) - 0 - 32 - - - - - IVR2 - IVR2 - initialization vector register 2 - 0x28 - 0x20 - read-write - 0x00000000 - - - AES_IVR2 - Initialization Vector Register (IVR [95:64]) - 0 - 32 - - - - - IVR3 - IVR3 - initialization vector register 3 - 0x2C - 0x20 - read-write - 0x00000000 - - - AES_IVR3 - Initialization Vector Register (MSB IVR [127:96]) - 0 - 32 - - - - - KEYR4 - KEYR4 - key register 4 - 0x30 - 0x20 - read-write - 0x00000000 - - - AES_KEYR4 - AES key register (MSB key [159:128]) - 0 - 32 - - - - - KEYR5 - KEYR5 - key register 5 - 0x34 - 0x20 - read-write - 0x00000000 - - - AES_KEYR5 - AES key register (MSB key [191:160]) - 0 - 32 - - - - - KEYR6 - KEYR6 - key register 6 - 0x38 - 0x20 - read-write - 0x00000000 - - - AES_KEYR6 - AES key register (MSB key [223:192]) - 0 - 32 - - - - - KEYR7 - KEYR7 - key register 7 - 0x3C - 0x20 - read-write - 0x00000000 - - - AES_KEYR7 - AES key register (MSB key [255:224]) - 0 - 32 - - - - - SUSP0R - SUSP0R - AES suspend register 0 - 0x40 - 0x20 - read-write - 0x00000000 - - - AES_SUSP0R - AES suspend register 0 - 0 - 32 - - - - - SUSP1R - SUSP1R - AES suspend register 1 - 0x44 - 0x20 - read-write - 0x00000000 - - - AES_SUSP1R - AES suspend register 1 - 0 - 32 - - - - - SUSP2R - SUSP2R - AES suspend register 2 - 0x48 - 0x20 - read-write - 0x00000000 - - - AES_SUSP2R - AES suspend register 2 - 0 - 32 - - - - - SUSP3R - SUSP3R - AES suspend register 3 - 0x4C - 0x20 - read-write - 0x00000000 - - - AES_SUSP3R - AES suspend register 3 - 0 - 32 - - - - - SUSP4R - SUSP4R - AES suspend register 4 - 0x50 - 0x20 - read-write - 0x00000000 - - - AES_SUSP4R - AES suspend register 4 - 0 - 32 - - - - - SUSP5R - SUSP5R - AES suspend register 5 - 0x54 - 0x20 - read-write - 0x00000000 - - - AES_SUSP5R - AES suspend register 5 - 0 - 32 - - - - - SUSP6R - SUSP6R - AES suspend register 6 - 0x58 - 0x20 - read-write - 0x00000000 - - - AES_SUSP6R - AES suspend register 6 - 0 - 32 - - - - - SUSP7R - SUSP7R - AES suspend register 7 - 0x5C - 0x20 - read-write - 0x00000000 - - - AES_SUSP7R - AES suspend register 7 - 0 - 32 - - - - - HWCFR - HWCFR - AES hardware configuration register - 0x60 - 0x20 - read-only - 0x00000002 - - - CFG4 - HW Generic 4 - 12 - 4 - - - CFG3 - HW Generic 3 - 8 - 4 - - - CFG2 - HW Generic 2 - 4 - 4 - - - CFG1 - HW Generic 1 - 0 - 4 - - - - - VERR - VERR - AES version register - 0x64 - 0x20 - read-only - 0x00000010 - - - MAJREV - Major revision - 4 - 4 - - - MINREV - Minor revision - 0 - 4 - - - - - IPIDR - IPIDR - AES identification register - 0x68 - 0x20 - read-only - 0x00170023 - - - ID - Identification code - 0 - 32 - - - - - SIDR - SIDR - AES size ID register - 0x6C - 0x20 - read-only - 0x00170023 - - - ID - Size Identification code - 0 - 32 - - - - - - - HSEM - HSEM - Hardware_Semaphore - 0x58001400 - - 0x0 - 0x400 - registers - - - HSEM - Semaphore interrupt 0 to CPU1 - 46 - - - - R0 - R0 - Semaphore 0 register - 0x0 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R1 - R1 - Semaphore 1 register - 0x4 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R2 - R2 - Semaphore 2 register - 0x8 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R3 - R3 - Semaphore 3 register - 0xC - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R4 - R4 - Semaphore 4 register - 0x10 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R5 - R5 - Semaphore 5 register - 0x14 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R6 - R6 - Semaphore 6 register - 0x18 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R7 - R7 - Semaphore 7 register - 0x1C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R8 - R8 - Semaphore 8 register - 0x20 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R9 - R9 - Semaphore 9 register - 0x24 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R10 - R10 - Semaphore 10 register - 0x28 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R11 - R11 - Semaphore 11 register - 0x2C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R12 - R12 - Semaphore 12 register - 0x30 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R13 - R13 - Semaphore 13 register - 0x34 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R14 - R14 - Semaphore 14 register - 0x38 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R15 - R15 - Semaphore 15 register - 0x3C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R16 - R16 - Semaphore 16 register - 0x40 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R17 - R17 - Semaphore 17 register - 0x44 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R18 - R18 - Semaphore 18 register - 0x48 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R19 - R19 - Semaphore 19 register - 0x4C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R20 - R20 - Semaphore 20 register - 0x50 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R21 - R21 - Semaphore 21 register - 0x54 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R22 - R22 - Semaphore 22 register - 0x58 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R23 - R23 - Semaphore 23 register - 0x5C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R24 - R24 - Semaphore 24 register - 0x60 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R25 - R25 - Semaphore 25 register - 0x64 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R26 - R26 - Semaphore 26 register - 0x68 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R27 - R27 - Semaphore 27 register - 0x6C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R28 - R28 - Semaphore 28 register - 0x70 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R29 - R29 - Semaphore 29 register - 0x74 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R30 - R30 - Semaphore 30 register - 0x78 - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - R31 - R31 - Semaphore 31 register - 0x7C - 0x20 - read-write - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR0 - RLR0 - Semaphore 0 read lock register - 0x80 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR1 - RLR1 - Semaphore 1 read lock register - 0x84 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR2 - RLR2 - Semaphore 2 read lock register - 0x88 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR3 - RLR3 - Semaphore 3 read lock register - 0x8C - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR4 - RLR4 - Semaphore 4 read lock read lock register - 0x90 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR5 - RLR5 - Semaphore 5 read lock register - 0x94 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR6 - RLR6 - Semaphore 6 read lock register - 0x98 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR7 - RLR7 - Semaphore 7 read lock register - 0x9C - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR8 - RLR8 - Semaphore 8 read lock register - 0xA0 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR9 - RLR9 - Semaphore 9 read lock register - 0xA4 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR10 - RLR10 - Semaphore 10 read lock register - 0xA8 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR11 - RLR11 - Semaphore 11 read lock register - 0xAC - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR12 - RLR12 - Semaphore 12 read lock register - 0xB0 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR13 - RLR13 - Semaphore 13 read lock register - 0xB4 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR14 - RLR14 - Semaphore 14 read lock register - 0xB8 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR15 - RLR15 - Semaphore 15 read lock register - 0xBC - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR16 - RLR16 - Semaphore 16 read lock register - 0xC0 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR17 - RLR17 - Semaphore 17 read lock register - 0xC4 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR18 - RLR18 - Semaphore 18 read lock register - 0xC8 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR19 - RLR19 - Semaphore 19 read lock register - 0xCC - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR20 - RLR20 - Semaphore 20 read lock register - 0xD0 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR21 - RLR21 - Semaphore 21 read lock register - 0xD4 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR22 - RLR22 - Semaphore 22 read lock register - 0xD8 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR23 - RLR23 - Semaphore 23 read lock register - 0xDC - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR24 - RLR24 - Semaphore 24 read lock register - 0xE0 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR25 - RLR25 - Semaphore 25 read lock register - 0xE4 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR26 - RLR26 - Semaphore 26 read lock register - 0xE8 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR27 - RLR27 - Semaphore 27 read lock register - 0xEC - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR28 - RLR28 - Semaphore 28 read lock register - 0xF0 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR29 - RLR29 - Semaphore 29 read lock register - 0xF4 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR30 - RLR30 - Semaphore 30 read lock register - 0xF8 - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - RLR31 - RLR31 - Semaphore 31 read lock register - 0xFC - 0x20 - read-only - 0x00000000 - - - LOCK - lock indication - 31 - 1 - - - COREID - Semaphore CoreID - 8 - 4 - - - PROCID - Semaphore ProcessID - 0 - 8 - - - - - CR - CR - Semaphore Clear register - 0x140 - 0x20 - read-write - 0x00000000 - - - KEY - Semaphore clear Key - 16 - 16 - - - COREID - CoreID of semaphore to be cleared - 8 - 4 - - - - - KEYR - KEYR - Interrupt clear register - 0x144 - 0x20 - read-write - 0x00000000 - - - KEY - Semaphore Clear Key - 16 - 16 - - - - - HWCFGR2 - HWCFGR2 - Semaphore hardware configuration register 2 - 0x3EC - 0x20 - read-only - 0x00000084 - - - MASTERID4 - Hardware Configuration valid bus masters ID4 - 12 - 4 - - - MASTERID3 - Hardware Configuration valid bus masters ID3 - 8 - 4 - - - MASTERID2 - Hardware Configuration valid bus masters ID2 - 4 - 4 - - - MASTERID1 - Hardware Configuration valid bus masters ID1 - 0 - 4 - - - - - HWCFGR1 - HWCFGR1 - Semaphore hardware configuration register 1 - 0x3F0 - 0x20 - read-only - 0x00000220 - - - NBINT - Hardware Configuration number of interrupts supported number of master IDs - 8 - 4 - - - NBSEM - Hardware Configuration number of semaphores - 0 - 8 - - - - - VERR - VERR - HSEM version register - 0x3F4 - 0x20 - read-only - 0x00000020 - - - MAJREV - Major Revision - 4 - 4 - - - MINREV - Minor Revision - 0 - 4 - - - - - IPIDR - IPIDR - HSEM indentification register - 0x3F8 - 0x20 - read-only - 0x00100072 - - - ID - Identification Code - 0 - 32 - - - - - SIDR - SIDR - HSEM size indentification register - 0x3FC - 0x20 - read-only - 0xA3C5DD01 - - - SID - Size Identification Code - 0 - 32 - - - - - C1IER0 - C1IER0 - HSEM Interrupt enable register - 0x100 - 0x20 - read-write - 0x00000000 - - - ISEm - CPU(n) semaphore m enable bit - 0 - 32 - - - - - C1ICR - C1ICR - HSEM Interrupt clear register - 0x104 - 0x20 - read-write - 0x00000000 - - - ISCm - CPU(n) semaphore m clear bit - 0 - 32 - - - - - C1ISR - C1ISR - HSEM Interrupt status register - 0x108 - 0x20 - read-only - 0x00000000 - - - ISFm - CPU(n) semaphore m status bit before enable (mask) - 0 - 32 - - - - - C1MISR - C1MISR - HSEM Masked interrupt status register - 0x10C - 0x20 - read-only - 0x00000000 - - - MISFm - masked CPU(n) semaphore m status bit after enable (mask). - 0 - 32 - - - - - C2IER0 - C2IER0 - HSEM Interrupt enable register - 0x110 - 0x20 - read-write - 0x00000000 - - - ISEm - CPU(2) semaphore m enable bit. - 0 - 32 - - - - - C2ICR - C2ICR - HSEM Interrupt clear register - 0x114 - 0x20 - read-write - 0x00000000 - - - ISCm - CPU(2) semaphore m clear bit - 0 - 32 - - - - - C2ISR - C2ISR - HSEM Interrupt status register - 0x118 - 0x20 - read-only - 0x00000000 - - - ISFm - CPU(2) semaphore m status bit before enable (mask). - 0 - 32 - - - - - C2MISR - C2MISR - HSEM Masked interrupt status register - 0x11C - 0x20 - read-only - 0x00000000 - - - MISFm - masked CPU(2) semaphore m status bit after enable (mask). - 0 - 32 - - - - - - - ADC - Analog to Digital Converter instance 1 - ADC - 0x50040000 - - 0x0 - 0x400 - registers - - - ADC1 - ADC1 global interrupt - 18 - - - - ISR - ISR - ADC interrupt and status register - 0x0 - 0x20 - read-write - 0x00000000 - - - JQOVF - ADC group injected contexts queue overflow flag - 10 - 1 - - - AWD3 - ADC analog watchdog 3 flag - 9 - 1 - - - AWD2 - ADC analog watchdog 2 flag - 8 - 1 - - - AWD1 - ADC analog watchdog 1 flag - 7 - 1 - - - JEOS - ADC group injected end of sequence conversions flag - 6 - 1 - - - JEOC - ADC group injected end of unitary conversion flag - 5 - 1 - - - OVR - ADC group regular overrun flag - 4 - 1 - - - EOS - ADC group regular end of sequence conversions flag - 3 - 1 - - - EOC - ADC group regular end of unitary conversion flag - 2 - 1 - - - EOSMP - ADC group regular end of sampling flag - 1 - 1 - - - ADRDY - ADC ready flag - 0 - 1 - - - - - IER - IER - ADC interrupt enable register - 0x4 - 0x20 - read-write - 0x00000000 - - - JQOVFIE - ADC group injected contexts queue overflow interrupt - 10 - 1 - - - AWD3IE - ADC analog watchdog 3 interrupt - 9 - 1 - - - AWD2IE - ADC analog watchdog 2 interrupt - 8 - 1 - - - AWD1IE - ADC analog watchdog 1 interrupt - 7 - 1 - - - JEOSIE - ADC group injected end of sequence conversions interrupt - 6 - 1 - - - JEOCIE - ADC group injected end of unitary conversion interrupt - 5 - 1 - - - OVRIE - ADC group regular overrun interrupt - 4 - 1 - - - EOSIE - ADC group regular end of sequence conversions interrupt - 3 - 1 - - - EOCIE - ADC group regular end of unitary conversion interrupt - 2 - 1 - - - EOSMPIE - ADC group regular end of sampling interrupt - 1 - 1 - - - ADRDYIE - ADC ready interrupt - 0 - 1 - - - - - CR - CR - ADC control register - 0x8 - 0x20 - read-write - 0x00000000 - - - ADCAL - ADC calibration - 31 - 1 - - - ADCALDIF - ADC differential mode for calibration - 30 - 1 - - - DEEPPWD - ADC deep power down enable - 29 - 1 - - - ADVREGEN - ADC voltage regulator enable - 28 - 1 - - - JADSTP - ADC group injected conversion stop - 5 - 1 - - - ADSTP - ADC group regular conversion stop - 4 - 1 - - - JADSTART - ADC group injected conversion start - 3 - 1 - - - ADSTART - ADC group regular conversion start - 2 - 1 - - - ADDIS - ADC disable - 1 - 1 - - - ADEN - ADC enable - 0 - 1 - - - - - CFGR - CFGR - ADC configuration register 1 - 0xC - 0x20 - read-write - 0x80000000 - - - JQDIS - ADC group injected contexts queue disable - 31 - 1 - - - AWDCH1CH - ADC analog watchdog 1 monitored channel selection - 26 - 5 - - - JAUTO - ADC group injected automatic trigger mode - 25 - 1 - - - JAWD1EN - ADC analog watchdog 1 enable on scope ADC group injected - 24 - 1 - - - AWD1EN - ADC analog watchdog 1 enable on scope ADC group regular - 23 - 1 - - - AWD1SGL - ADC analog watchdog 1 monitoring a single channel or all channels - 22 - 1 - - - JQM - ADC group injected contexts queue mode - 21 - 1 - - - JDISCEN - ADC group injected sequencer discontinuous mode - 20 - 1 - - - DISCNUM - ADC group regular sequencer discontinuous number of ranks - 17 - 3 - - - DISCEN - ADC group regular sequencer discontinuous mode - 16 - 1 - - - AUTDLY - ADC low power auto wait - 14 - 1 - - - CONT - ADC group regular continuous conversion mode - 13 - 1 - - - OVRMOD - ADC group regular overrun configuration - 12 - 1 - - - EXTEN - ADC group regular external trigger polarity - 10 - 2 - - - EXTSEL - ADC group regular external trigger source - 6 - 4 - - - ALIGN - ADC data alignement - 5 - 1 - - - RES - ADC data resolution - 3 - 2 - - - DMACFG - ADC DMA transfer configuration - 1 - 1 - - - DMAEN - ADC DMA transfer enable - 0 - 1 - - - - - CFGR2 - CFGR2 - ADC configuration register 2 - 0x10 - 0x20 - read-write - 0x00000000 - - - ROVSM - ADC oversampling mode managing interlaced conversions of ADC group regular and group injected - 10 - 1 - - - TOVS - ADC oversampling discontinuous mode (triggered mode) for ADC group regular - 9 - 1 - - - OVSS - ADC oversampling shift - 5 - 4 - - - OVSR - ADC oversampling ratio - 2 - 3 - - - JOVSE - ADC oversampler enable on scope ADC group injected - 1 - 1 - - - ROVSE - ADC oversampler enable on scope ADC group regular - 0 - 1 - - - - - SMPR1 - SMPR1 - ADC sampling time register 1 - 0x14 - 0x20 - read-write - 0x00000000 - - - SMP9 - ADC channel 9 sampling time selection - 27 - 3 - - - SMP8 - ADC channel 8 sampling time selection - 24 - 3 - - - SMP7 - ADC channel 7 sampling time selection - 21 - 3 - - - SMP6 - ADC channel 6 sampling time selection - 18 - 3 - - - SMP5 - ADC channel 5 sampling time selection - 15 - 3 - - - SMP4 - ADC channel 4 sampling time selection - 12 - 3 - - - SMP3 - ADC channel 3 sampling time selection - 9 - 3 - - - SMP2 - ADC channel 2 sampling time selection - 6 - 3 - - - SMP1 - ADC channel 1 sampling time selection - 3 - 3 - - - - - SMPR2 - SMPR2 - ADC sampling time register 2 - 0x18 - 0x20 - read-write - 0x00000000 - - - SMP18 - ADC channel 18 sampling time selection - 24 - 3 - - - SMP17 - ADC channel 17 sampling time selection - 21 - 3 - - - SMP16 - ADC channel 16 sampling time selection - 18 - 3 - - - SMP15 - ADC channel 15 sampling time selection - 15 - 3 - - - SMP14 - ADC channel 14 sampling time selection - 12 - 3 - - - SMP13 - ADC channel 13 sampling time selection - 9 - 3 - - - SMP12 - ADC channel 12 sampling time selection - 6 - 3 - - - SMP11 - ADC channel 11 sampling time selection - 3 - 3 - - - SMP10 - ADC channel 10 sampling time selection - 0 - 3 - - - - - TR1 - TR1 - ADC analog watchdog 1 threshold register - 0x20 - 0x20 - read-write - 0x0FFF0000 - - - HT1 - ADC analog watchdog 1 threshold high - 16 - 12 - - - LT1 - ADC analog watchdog 1 threshold low - 0 - 12 - - - - - TR2 - TR2 - ADC analog watchdog 2 threshold register - 0x24 - 0x20 - read-write - 0x0FFF0000 - - - HT2 - ADC analog watchdog 2 threshold high - 16 - 8 - - - LT2 - ADC analog watchdog 2 threshold low - 0 - 8 - - - - - TR3 - TR3 - ADC analog watchdog 3 threshold register - 0x28 - 0x20 - read-write - 0x0FFF0000 - - - HT3 - ADC analog watchdog 3 threshold high - 16 - 8 - - - LT3 - ADC analog watchdog 3 threshold low - 0 - 8 - - - - - SQR1 - SQR1 - ADC group regular sequencer ranks register 1 - 0x30 - 0x20 - read-write - 0x00000000 - - - SQ4 - ADC group regular sequencer rank 4 - 24 - 5 - - - SQ3 - ADC group regular sequencer rank 3 - 18 - 5 - - - SQ2 - ADC group regular sequencer rank 2 - 12 - 5 - - - SQ1 - ADC group regular sequencer rank 1 - 6 - 5 - - - L3 - L3 - 0 - 4 - - - - - SQR2 - SQR2 - ADC group regular sequencer ranks register 2 - 0x34 - 0x20 - read-write - 0x00000000 - - - SQ9 - ADC group regular sequencer rank 9 - 24 - 5 - - - SQ8 - ADC group regular sequencer rank 8 - 18 - 5 - - - SQ7 - ADC group regular sequencer rank 7 - 12 - 5 - - - SQ6 - ADC group regular sequencer rank 6 - 6 - 5 - - - SQ5 - ADC group regular sequencer rank 5 - 0 - 5 - - - - - SQR3 - SQR3 - ADC group regular sequencer ranks register 3 - 0x38 - 0x20 - read-write - 0x00000000 - - - SQ14 - ADC group regular sequencer rank 14 - 24 - 5 - - - SQ13 - ADC group regular sequencer rank 13 - 18 - 5 - - - SQ12 - ADC group regular sequencer rank 12 - 12 - 5 - - - SQ11 - ADC group regular sequencer rank 11 - 6 - 5 - - - SQ10 - ADC group regular sequencer rank 10 - 0 - 5 - - - - - SQR4 - SQR4 - ADC group regular sequencer ranks register 4 - 0x3C - 0x20 - read-write - 0x00000000 - - - SQ16 - ADC group regular sequencer rank 16 - 6 - 5 - - - SQ15 - ADC group regular sequencer rank 15 - 0 - 5 - - - - - DR - DR - ADC group regular conversion data register - 0x40 - 0x20 - 0x00000000 - - - RDATA_0_6 - Regular Data converted 0_6 - 0 - 6 - read-write - - - RDATA_7_15 - 15 - 7 - 9 - read-only - - - - - JSQR - JSQR - ADC group injected sequencer register - 0x4C - 0x20 - read-write - 0x00000000 - - - JSQ4 - ADC group injected sequencer rank 4 - 26 - 5 - - - JSQ3 - ADC group injected sequencer rank 3 - 20 - 5 - - - JSQ2 - ADC group injected sequencer rank 2 - 14 - 5 - - - JSQ1 - ADC group injected sequencer rank 1 - 8 - 5 - - - JEXTEN - ADC group injected external trigger polarity - 6 - 2 - - - JEXTSEL - ADC group injected external trigger source - 2 - 4 - - - JL - ADC group injected sequencer scan length - 0 - 2 - - - - - OFR1 - OFR1 - ADC offset number 1 register - 0x60 - 0x20 - read-write - 0x00000000 - - - OFFSET1_EN - ADC offset number 1 enable - 31 - 1 - - - OFFSET1_CH - ADC offset number 1 channel selection - 26 - 5 - - - OFFSET1 - ADC offset number 1 offset level - 0 - 12 - - - - - OFR2 - OFR2 - ADC offset number 2 register - 0x64 - 0x20 - read-write - 0x00000000 - - - OFFSET2_EN - ADC offset number 2 enable - 31 - 1 - - - OFFSET2_CH - ADC offset number 2 channel selection - 26 - 5 - - - OFFSET2 - ADC offset number 2 offset level - 0 - 12 - - - - - OFR3 - OFR3 - ADC offset number 3 register - 0x68 - 0x20 - read-write - 0x00000000 - - - OFFSET3_EN - ADC offset number 3 enable - 31 - 1 - - - OFFSET3_CH - ADC offset number 3 channel selection - 26 - 5 - - - OFFSET3 - ADC offset number 3 offset level - 0 - 12 - - - - - OFR4 - OFR4 - ADC offset number 4 register - 0x6C - 0x20 - read-write - 0x00000000 - - - OFFSET4_EN - ADC offset number 4 enable - 31 - 1 - - - OFFSET4_CH - ADC offset number 4 channel selection - 26 - 5 - - - OFFSET4 - ADC offset number 4 offset level - 0 - 12 - - - - - JDR1 - JDR1 - ADC group injected sequencer rank 1 register - 0x80 - 0x20 - read-only - 0x00000000 - - - JDATA1 - ADC group injected sequencer rank 1 conversion data - 0 - 16 - - - - - JDR2 - JDR2 - ADC group injected sequencer rank 2 register - 0x84 - 0x20 - read-only - 0x00000000 - - - JDATA2 - ADC group injected sequencer rank 2 conversion data - 0 - 16 - - - - - JDR3 - JDR3 - ADC group injected sequencer rank 3 register - 0x88 - 0x20 - read-only - 0x00000000 - - - JDATA3 - ADC group injected sequencer rank 3 conversion data - 0 - 16 - - - - - JDR4 - JDR4 - ADC group injected sequencer rank 4 register - 0x8C - 0x20 - read-only - 0x00000000 - - - JDATA4 - ADC group injected sequencer rank 4 conversion data - 0 - 16 - - - - - AWD2CR - AWD2CR - ADC analog watchdog 2 configuration register - 0xA0 - 0x20 - read-write - 0x00000000 - - - AWD2CH - ADC analog watchdog 2 monitored channel selection - 0 - 19 - - - - - AWD3CR - AWD3CR - ADC analog watchdog 3 configuration register - 0xA4 - 0x20 - read-write - 0x00000000 - - - AWD3CH - ADC analog watchdog 3 monitored channel selection - 0 - 19 - - - - - DIFSEL - DIFSEL - ADC channel differential or single-ended mode selection register - 0xB0 - 0x20 - 0x00000000 - - - DIFSEL_0 - ADC channel differential or single-ended mode for channel 0 - 0 - 1 - read-only - - - DIFSEL_1_15 - ADC channel differential or single-ended mode for channels 1 to 15 - 1 - 15 - read-write - - - DIFSEL_16_18 - ADC channel differential or single-ended mode for channels 18 to 16 - 16 - 3 - read-only - - - - - CALFACT - CALFACT - ADC calibration factors register - 0xB4 - 0x20 - read-write - 0x00000000 - - - CALFACT_D - ADC calibration factor in differential mode - 16 - 7 - - - CALFACT_S - ADC calibration factor in single-ended mode - 0 - 7 - - - - - CCR - CCR - ADC common control register - 0x308 - 0x20 - read-write - 0x00000000 - - - VBATEN - VBAT enable - 24 - 1 - - - TSEN - Temperature sensor enable - 23 - 1 - - - VREFEN - VREFEN - 22 - 1 - - - PRESC - ADC prescaler - 18 - 4 - - - CKMODE - ADC clock mode - 16 - 2 - - - - - - - GPIOA - General-purpose I/Os - GPIO - 0x48000000 - - 0x0 - 0x400 - registers - - - - MODER - MODER - GPIO port mode register - 0x0 - 0x20 - read-write - 0xABFFFFFF - - - MODER15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - MODER14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - MODER13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - MODER12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - MODER11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - MODER10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - MODER9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - MODER8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - MODER7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - MODER6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - MODER5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - MODER4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - MODER3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - MODER2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - MODER1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - MODER0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - OTYPER - OTYPER - GPIO port output type register - 0x4 - 0x20 - read-write - 0x00000000 - - - OT15 - Port x configuration bits (y = 0..15) - 15 - 1 - - - OT14 - Port x configuration bits (y = 0..15) - 14 - 1 - - - OT13 - Port x configuration bits (y = 0..15) - 13 - 1 - - - OT12 - Port x configuration bits (y = 0..15) - 12 - 1 - - - OT11 - Port x configuration bits (y = 0..15) - 11 - 1 - - - OT10 - Port x configuration bits (y = 0..15) - 10 - 1 - - - OT9 - Port x configuration bits (y = 0..15) - 9 - 1 - - - OT8 - Port x configuration bits (y = 0..15) - 8 - 1 - - - OT7 - Port x configuration bits (y = 0..15) - 7 - 1 - - - OT6 - Port x configuration bits (y = 0..15) - 6 - 1 - - - OT5 - Port x configuration bits (y = 0..15) - 5 - 1 - - - OT4 - Port x configuration bits (y = 0..15) - 4 - 1 - - - OT3 - Port x configuration bits (y = 0..15) - 3 - 1 - - - OT2 - Port x configuration bits (y = 0..15) - 2 - 1 - - - OT1 - Port x configuration bits (y = 0..15) - 1 - 1 - - - OT0 - Port x configuration bits (y = 0..15) - 0 - 1 - - - - - OSPEEDR - OSPEEDR - GPIO port output speed register - 0x8 - 0x20 - read-write - 0x0C000000 - - - OSPEEDR15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - OSPEEDR14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - OSPEEDR13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - OSPEEDR12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - OSPEEDR11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - OSPEEDR10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - OSPEEDR9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - OSPEEDR8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - OSPEEDR7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - OSPEEDR6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - OSPEEDR5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - OSPEEDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - OSPEEDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - OSPEEDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - OSPEEDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - OSPEEDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - PUPDR - PUPDR - GPIO port pull-up/pull-down register - 0xC - 0x20 - read-write - 0x64000000 - - - PUPDR15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - PUPDR14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - PUPDR13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - PUPDR12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - PUPDR11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - PUPDR10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - PUPDR9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - PUPDR8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - PUPDR7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - PUPDR6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - PUPDR5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - PUPDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - PUPDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - PUPDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - PUPDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - PUPDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - IDR - IDR - GPIO port input data register - 0x10 - 0x20 - read-only - 0x00000000 - - - IDR15 - Port input data (y = 0..15) - 15 - 1 - - - IDR14 - Port input data (y = 0..15) - 14 - 1 - - - IDR13 - Port input data (y = 0..15) - 13 - 1 - - - IDR12 - Port input data (y = 0..15) - 12 - 1 - - - IDR11 - Port input data (y = 0..15) - 11 - 1 - - - IDR10 - Port input data (y = 0..15) - 10 - 1 - - - IDR9 - Port input data (y = 0..15) - 9 - 1 - - - IDR8 - Port input data (y = 0..15) - 8 - 1 - - - IDR7 - Port input data (y = 0..15) - 7 - 1 - - - IDR6 - Port input data (y = 0..15) - 6 - 1 - - - IDR5 - Port input data (y = 0..15) - 5 - 1 - - - IDR4 - Port input data (y = 0..15) - 4 - 1 - - - IDR3 - Port input data (y = 0..15) - 3 - 1 - - - IDR2 - Port input data (y = 0..15) - 2 - 1 - - - IDR1 - Port input data (y = 0..15) - 1 - 1 - - - IDR0 - Port input data (y = 0..15) - 0 - 1 - - - - - ODR - ODR - GPIO port output data register - 0x14 - 0x20 - read-write - 0x00000000 - - - ODR15 - Port output data (y = 0..15) - 15 - 1 - - - ODR14 - Port output data (y = 0..15) - 14 - 1 - - - ODR13 - Port output data (y = 0..15) - 13 - 1 - - - ODR12 - Port output data (y = 0..15) - 12 - 1 - - - ODR11 - Port output data (y = 0..15) - 11 - 1 - - - ODR10 - Port output data (y = 0..15) - 10 - 1 - - - ODR9 - Port output data (y = 0..15) - 9 - 1 - - - ODR8 - Port output data (y = 0..15) - 8 - 1 - - - ODR7 - Port output data (y = 0..15) - 7 - 1 - - - ODR6 - Port output data (y = 0..15) - 6 - 1 - - - ODR5 - Port output data (y = 0..15) - 5 - 1 - - - ODR4 - Port output data (y = 0..15) - 4 - 1 - - - ODR3 - Port output data (y = 0..15) - 3 - 1 - - - ODR2 - Port output data (y = 0..15) - 2 - 1 - - - ODR1 - Port output data (y = 0..15) - 1 - 1 - - - ODR0 - Port output data (y = 0..15) - 0 - 1 - - - - - BSRR - BSRR - GPIO port bit set/reset register - 0x18 - 0x20 - write-only - 0x00000000 - - - BR15 - Port x reset bit y (y = 0..15) - 31 - 1 - - - BR14 - Port x reset bit y (y = 0..15) - 30 - 1 - - - BR13 - Port x reset bit y (y = 0..15) - 29 - 1 - - - BR12 - Port x reset bit y (y = 0..15) - 28 - 1 - - - BR11 - Port x reset bit y (y = 0..15) - 27 - 1 - - - BR10 - Port x reset bit y (y = 0..15) - 26 - 1 - - - BR9 - Port x reset bit y (y = 0..15) - 25 - 1 - - - BR8 - Port x reset bit y (y = 0..15) - 24 - 1 - - - BR7 - Port x reset bit y (y = 0..15) - 23 - 1 - - - BR6 - Port x reset bit y (y = 0..15) - 22 - 1 - - - BR5 - Port x reset bit y (y = 0..15) - 21 - 1 - - - BR4 - Port x reset bit y (y = 0..15) - 20 - 1 - - - BR3 - Port x reset bit y (y = 0..15) - 19 - 1 - - - BR2 - Port x reset bit y (y = 0..15) - 18 - 1 - - - BR1 - Port x reset bit y (y = 0..15) - 17 - 1 - - - BR0 - Port x set bit y (y= 0..15) - 16 - 1 - - - BS15 - Port x set bit y (y= 0..15) - 15 - 1 - - - BS14 - Port x set bit y (y= 0..15) - 14 - 1 - - - BS13 - Port x set bit y (y= 0..15) - 13 - 1 - - - BS12 - Port x set bit y (y= 0..15) - 12 - 1 - - - BS11 - Port x set bit y (y= 0..15) - 11 - 1 - - - BS10 - Port x set bit y (y= 0..15) - 10 - 1 - - - BS9 - Port x set bit y (y= 0..15) - 9 - 1 - - - BS8 - Port x set bit y (y= 0..15) - 8 - 1 - - - BS7 - Port x set bit y (y= 0..15) - 7 - 1 - - - BS6 - Port x set bit y (y= 0..15) - 6 - 1 - - - BS5 - Port x set bit y (y= 0..15) - 5 - 1 - - - BS4 - Port x set bit y (y= 0..15) - 4 - 1 - - - BS3 - Port x set bit y (y= 0..15) - 3 - 1 - - - BS2 - Port x set bit y (y= 0..15) - 2 - 1 - - - BS1 - Port x set bit y (y= 0..15) - 1 - 1 - - - BS0 - Port x set bit y (y= 0..15) - 0 - 1 - - - - - LCKR - LCKR - GPIO port configuration lock register - 0x1C - 0x20 - read-write - 0x00000000 - - - LCKK - Port x lock bit y (y= 0..15) - 16 - 1 - - - LCK15 - Port x lock bit y (y= 0..15) - 15 - 1 - - - LCK14 - Port x lock bit y (y= 0..15) - 14 - 1 - - - LCK13 - Port x lock bit y (y= 0..15) - 13 - 1 - - - LCK12 - Port x lock bit y (y= 0..15) - 12 - 1 - - - LCK11 - Port x lock bit y (y= 0..15) - 11 - 1 - - - LCK10 - Port x lock bit y (y= 0..15) - 10 - 1 - - - LCK9 - Port x lock bit y (y= 0..15) - 9 - 1 - - - LCK8 - Port x lock bit y (y= 0..15) - 8 - 1 - - - LCK7 - Port x lock bit y (y= 0..15) - 7 - 1 - - - LCK6 - Port x lock bit y (y= 0..15) - 6 - 1 - - - LCK5 - Port x lock bit y (y= 0..15) - 5 - 1 - - - LCK4 - Port x lock bit y (y= 0..15) - 4 - 1 - - - LCK3 - Port x lock bit y (y= 0..15) - 3 - 1 - - - LCK2 - Port x lock bit y (y= 0..15) - 2 - 1 - - - LCK1 - Port x lock bit y (y= 0..15) - 1 - 1 - - - LCK0 - Port x lock bit y (y= 0..15) - 0 - 1 - - - - - AFRL - AFRL - GPIO alternate function low register - 0x20 - 0x20 - read-write - 0x00000000 - - - AFSEL7 - Alternate function selection for port x bit y (y = 0..7) - 28 - 4 - - - AFSEL6 - Alternate function selection for port x bit y (y = 0..7) - 24 - 4 - - - AFSEL5 - Alternate function selection for port x bit y (y = 0..7) - 20 - 4 - - - AFSEL4 - Alternate function selection for port x bit y (y = 0..7) - 16 - 4 - - - AFSEL3 - Alternate function selection for port x bit y (y = 0..7) - 12 - 4 - - - AFSEL2 - Alternate function selection for port x bit y (y = 0..7) - 8 - 4 - - - AFSEL1 - Alternate function selection for port x bit y (y = 0..7) - 4 - 4 - - - AFSEL0 - Alternate function selection for port x bit y (y = 0..7) - 0 - 4 - - - - - AFRH - AFRH - GPIO alternate function high register - 0x24 - 0x20 - read-write - 0x00000000 - - - AFSEL15 - Alternate function selection for port x bit y (y = 8..15) - 28 - 4 - - - AFSEL14 - Alternate function selection for port x bit y (y = 8..15) - 24 - 4 - - - AFSEL13 - Alternate function selection for port x bit y (y = 8..15) - 20 - 4 - - - AFSEL12 - Alternate function selection for port x bit y (y = 8..15) - 16 - 4 - - - AFSEL11 - Alternate function selection for port x bit y (y = 8..15) - 12 - 4 - - - AFSEL10 - Alternate function selection for port x bit y (y = 8..15) - 8 - 4 - - - AFSEL9 - Alternate function selection for port x bit y (y = 8..15) - 4 - 4 - - - AFSEL8 - Alternate function selection for port x bit y (y = 8..15) - 0 - 4 - - - - - BRR - BRR - port bit reset register - 0x28 - 0x20 - write-only - 0x00000000 - - - BR0 - Port Reset bit - 0 - 1 - - - BR1 - Port Reset bit - 1 - 1 - - - BR2 - Port Reset bit - 2 - 1 - - - BR3 - Port Reset bit - 3 - 1 - - - BR4 - Port Reset bit - 4 - 1 - - - BR5 - Port Reset bit - 5 - 1 - - - BR6 - Port Reset bit - 6 - 1 - - - BR7 - Port Reset bit - 7 - 1 - - - BR8 - Port Reset bit - 8 - 1 - - - BR9 - Port Reset bit - 9 - 1 - - - BR10 - Port Reset bit - 10 - 1 - - - BR11 - Port Reset bit - 11 - 1 - - - BR12 - Port Reset bit - 12 - 1 - - - BR13 - Port Reset bit - 13 - 1 - - - BR14 - Port Reset bit - 14 - 1 - - - BR15 - Port Reset bit - 15 - 1 - - - - - - - GPIOB - General-purpose I/Os - GPIO - 0x48000400 - - 0x0 - 0x400 - registers - - - - MODER - MODER - GPIO port mode register - 0x0 - 0x20 - read-write - 0xFFFFFEBF - - - MODER15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - MODER14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - MODER13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - MODER12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - MODER11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - MODER10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - MODER9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - MODER8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - MODER7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - MODER6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - MODER5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - MODER4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - MODER3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - MODER2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - MODER1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - MODER0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - OTYPER - OTYPER - GPIO port output type register - 0x4 - 0x20 - read-write - 0x00000000 - - - OT15 - Port x configuration bits (y = 0..15) - 15 - 1 - - - OT14 - Port x configuration bits (y = 0..15) - 14 - 1 - - - OT13 - Port x configuration bits (y = 0..15) - 13 - 1 - - - OT12 - Port x configuration bits (y = 0..15) - 12 - 1 - - - OT11 - Port x configuration bits (y = 0..15) - 11 - 1 - - - OT10 - Port x configuration bits (y = 0..15) - 10 - 1 - - - OT9 - Port x configuration bits (y = 0..15) - 9 - 1 - - - OT8 - Port x configuration bits (y = 0..15) - 8 - 1 - - - OT7 - Port x configuration bits (y = 0..15) - 7 - 1 - - - OT6 - Port x configuration bits (y = 0..15) - 6 - 1 - - - OT5 - Port x configuration bits (y = 0..15) - 5 - 1 - - - OT4 - Port x configuration bits (y = 0..15) - 4 - 1 - - - OT3 - Port x configuration bits (y = 0..15) - 3 - 1 - - - OT2 - Port x configuration bits (y = 0..15) - 2 - 1 - - - OT1 - Port x configuration bits (y = 0..15) - 1 - 1 - - - OT0 - Port x configuration bits (y = 0..15) - 0 - 1 - - - - - OSPEEDR - OSPEEDR - GPIO port output speed register - 0x8 - 0x20 - read-write - 0x000000C0 - - - OSPEEDR15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - OSPEEDR14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - OSPEEDR13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - OSPEEDR12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - OSPEEDR11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - OSPEEDR10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - OSPEEDR9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - OSPEEDR8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - OSPEEDR7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - OSPEEDR6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - OSPEEDR5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - OSPEEDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - OSPEEDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - OSPEEDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - OSPEEDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - OSPEEDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - PUPDR - PUPDR - GPIO port pull-up/pull-down register - 0xC - 0x20 - read-write - 0x00000100 - - - PUPDR15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - PUPDR14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - PUPDR13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - PUPDR12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - PUPDR11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - PUPDR10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - PUPDR9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - PUPDR8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - PUPDR7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - PUPDR6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - PUPDR5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - PUPDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - PUPDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - PUPDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - PUPDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - PUPDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - IDR - IDR - GPIO port input data register - 0x10 - 0x20 - read-only - 0x00000000 - - - IDR15 - Port input data (y = 0..15) - 15 - 1 - - - IDR14 - Port input data (y = 0..15) - 14 - 1 - - - IDR13 - Port input data (y = 0..15) - 13 - 1 - - - IDR12 - Port input data (y = 0..15) - 12 - 1 - - - IDR11 - Port input data (y = 0..15) - 11 - 1 - - - IDR10 - Port input data (y = 0..15) - 10 - 1 - - - IDR9 - Port input data (y = 0..15) - 9 - 1 - - - IDR8 - Port input data (y = 0..15) - 8 - 1 - - - IDR7 - Port input data (y = 0..15) - 7 - 1 - - - IDR6 - Port input data (y = 0..15) - 6 - 1 - - - IDR5 - Port input data (y = 0..15) - 5 - 1 - - - IDR4 - Port input data (y = 0..15) - 4 - 1 - - - IDR3 - Port input data (y = 0..15) - 3 - 1 - - - IDR2 - Port input data (y = 0..15) - 2 - 1 - - - IDR1 - Port input data (y = 0..15) - 1 - 1 - - - IDR0 - Port input data (y = 0..15) - 0 - 1 - - - - - ODR - ODR - GPIO port output data register - 0x14 - 0x20 - read-write - 0x00000000 - - - ODR15 - Port output data (y = 0..15) - 15 - 1 - - - ODR14 - Port output data (y = 0..15) - 14 - 1 - - - ODR13 - Port output data (y = 0..15) - 13 - 1 - - - ODR12 - Port output data (y = 0..15) - 12 - 1 - - - ODR11 - Port output data (y = 0..15) - 11 - 1 - - - ODR10 - Port output data (y = 0..15) - 10 - 1 - - - ODR9 - Port output data (y = 0..15) - 9 - 1 - - - ODR8 - Port output data (y = 0..15) - 8 - 1 - - - ODR7 - Port output data (y = 0..15) - 7 - 1 - - - ODR6 - Port output data (y = 0..15) - 6 - 1 - - - ODR5 - Port output data (y = 0..15) - 5 - 1 - - - ODR4 - Port output data (y = 0..15) - 4 - 1 - - - ODR3 - Port output data (y = 0..15) - 3 - 1 - - - ODR2 - Port output data (y = 0..15) - 2 - 1 - - - ODR1 - Port output data (y = 0..15) - 1 - 1 - - - ODR0 - Port output data (y = 0..15) - 0 - 1 - - - - - BSRR - BSRR - GPIO port bit set/reset register - 0x18 - 0x20 - write-only - 0x00000000 - - - BR15 - Port x reset bit y (y = 0..15) - 31 - 1 - - - BR14 - Port x reset bit y (y = 0..15) - 30 - 1 - - - BR13 - Port x reset bit y (y = 0..15) - 29 - 1 - - - BR12 - Port x reset bit y (y = 0..15) - 28 - 1 - - - BR11 - Port x reset bit y (y = 0..15) - 27 - 1 - - - BR10 - Port x reset bit y (y = 0..15) - 26 - 1 - - - BR9 - Port x reset bit y (y = 0..15) - 25 - 1 - - - BR8 - Port x reset bit y (y = 0..15) - 24 - 1 - - - BR7 - Port x reset bit y (y = 0..15) - 23 - 1 - - - BR6 - Port x reset bit y (y = 0..15) - 22 - 1 - - - BR5 - Port x reset bit y (y = 0..15) - 21 - 1 - - - BR4 - Port x reset bit y (y = 0..15) - 20 - 1 - - - BR3 - Port x reset bit y (y = 0..15) - 19 - 1 - - - BR2 - Port x reset bit y (y = 0..15) - 18 - 1 - - - BR1 - Port x reset bit y (y = 0..15) - 17 - 1 - - - BR0 - Port x set bit y (y= 0..15) - 16 - 1 - - - BS15 - Port x set bit y (y= 0..15) - 15 - 1 - - - BS14 - Port x set bit y (y= 0..15) - 14 - 1 - - - BS13 - Port x set bit y (y= 0..15) - 13 - 1 - - - BS12 - Port x set bit y (y= 0..15) - 12 - 1 - - - BS11 - Port x set bit y (y= 0..15) - 11 - 1 - - - BS10 - Port x set bit y (y= 0..15) - 10 - 1 - - - BS9 - Port x set bit y (y= 0..15) - 9 - 1 - - - BS8 - Port x set bit y (y= 0..15) - 8 - 1 - - - BS7 - Port x set bit y (y= 0..15) - 7 - 1 - - - BS6 - Port x set bit y (y= 0..15) - 6 - 1 - - - BS5 - Port x set bit y (y= 0..15) - 5 - 1 - - - BS4 - Port x set bit y (y= 0..15) - 4 - 1 - - - BS3 - Port x set bit y (y= 0..15) - 3 - 1 - - - BS2 - Port x set bit y (y= 0..15) - 2 - 1 - - - BS1 - Port x set bit y (y= 0..15) - 1 - 1 - - - BS0 - Port x set bit y (y= 0..15) - 0 - 1 - - - - - LCKR - LCKR - GPIO port configuration lock register - 0x1C - 0x20 - read-write - 0x00000000 - - - LCKK - Port x lock bit y (y= 0..15) - 16 - 1 - - - LCK15 - Port x lock bit y (y= 0..15) - 15 - 1 - - - LCK14 - Port x lock bit y (y= 0..15) - 14 - 1 - - - LCK13 - Port x lock bit y (y= 0..15) - 13 - 1 - - - LCK12 - Port x lock bit y (y= 0..15) - 12 - 1 - - - LCK11 - Port x lock bit y (y= 0..15) - 11 - 1 - - - LCK10 - Port x lock bit y (y= 0..15) - 10 - 1 - - - LCK9 - Port x lock bit y (y= 0..15) - 9 - 1 - - - LCK8 - Port x lock bit y (y= 0..15) - 8 - 1 - - - LCK7 - Port x lock bit y (y= 0..15) - 7 - 1 - - - LCK6 - Port x lock bit y (y= 0..15) - 6 - 1 - - - LCK5 - Port x lock bit y (y= 0..15) - 5 - 1 - - - LCK4 - Port x lock bit y (y= 0..15) - 4 - 1 - - - LCK3 - Port x lock bit y (y= 0..15) - 3 - 1 - - - LCK2 - Port x lock bit y (y= 0..15) - 2 - 1 - - - LCK1 - Port x lock bit y (y= 0..15) - 1 - 1 - - - LCK0 - Port x lock bit y (y= 0..15) - 0 - 1 - - - - - AFRL - AFRL - GPIO alternate function low register - 0x20 - 0x20 - read-write - 0x00000000 - - - AFSEL7 - Alternate function selection for port x bit y (y = 0..7) - 28 - 4 - - - AFSEL6 - Alternate function selection for port x bit y (y = 0..7) - 24 - 4 - - - AFSEL5 - Alternate function selection for port x bit y (y = 0..7) - 20 - 4 - - - AFSEL4 - Alternate function selection for port x bit y (y = 0..7) - 16 - 4 - - - AFSEL3 - Alternate function selection for port x bit y (y = 0..7) - 12 - 4 - - - AFSEL2 - Alternate function selection for port x bit y (y = 0..7) - 8 - 4 - - - AFSEL1 - Alternate function selection for port x bit y (y = 0..7) - 4 - 4 - - - AFSEL0 - Alternate function selection for port x bit y (y = 0..7) - 0 - 4 - - - - - AFRH - AFRH - GPIO alternate function high register - 0x24 - 0x20 - read-write - 0x00000000 - - - AFSEL15 - Alternate function selection for port x bit y (y = 8..15) - 28 - 4 - - - AFSEL14 - Alternate function selection for port x bit y (y = 8..15) - 24 - 4 - - - AFSEL13 - Alternate function selection for port x bit y (y = 8..15) - 20 - 4 - - - AFSEL12 - Alternate function selection for port x bit y (y = 8..15) - 16 - 4 - - - AFSEL11 - Alternate function selection for port x bit y (y = 8..15) - 12 - 4 - - - AFSEL10 - Alternate function selection for port x bit y (y = 8..15) - 8 - 4 - - - AFSEL9 - Alternate function selection for port x bit y (y = 8..15) - 4 - 4 - - - AFSEL8 - Alternate function selection for port x bit y (y = 8..15) - 0 - 4 - - - - - BRR - BRR - port bit reset register - 0x28 - 0x20 - write-only - 0x00000000 - - - BR0 - Port Reset bit - 0 - 1 - - - BR1 - Port Reset bit - 1 - 1 - - - BR2 - Port Reset bit - 2 - 1 - - - BR3 - Port Reset bit - 3 - 1 - - - BR4 - Port Reset bit - 4 - 1 - - - BR5 - Port Reset bit - 5 - 1 - - - BR6 - Port Reset bit - 6 - 1 - - - BR7 - Port Reset bit - 7 - 1 - - - BR8 - Port Reset bit - 8 - 1 - - - BR9 - Port Reset bit - 9 - 1 - - - BR10 - Port Reset bit - 10 - 1 - - - BR11 - Port Reset bit - 11 - 1 - - - BR12 - Port Reset bit - 12 - 1 - - - BR13 - Port Reset bit - 13 - 1 - - - BR14 - Port Reset bit - 14 - 1 - - - BR15 - Port Reset bit - 15 - 1 - - - - - - - GPIOC - General-purpose I/Os - GPIO - 0x48000800 - - 0x0 - 0x400 - registers - - - - MODER - MODER - GPIO port mode register - 0x0 - 0x20 - read-write - 0xFFFFFFFF - - - MODER15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - MODER14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - MODER13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - MODER12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - MODER11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - MODER10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - MODER9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - MODER8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - MODER7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - MODER6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - MODER5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - MODER4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - MODER3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - MODER2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - MODER1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - MODER0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - OTYPER - OTYPER - GPIO port output type register - 0x4 - 0x20 - read-write - 0x00000000 - - - OT15 - Port x configuration bits (y = 0..15) - 15 - 1 - - - OT14 - Port x configuration bits (y = 0..15) - 14 - 1 - - - OT13 - Port x configuration bits (y = 0..15) - 13 - 1 - - - OT12 - Port x configuration bits (y = 0..15) - 12 - 1 - - - OT11 - Port x configuration bits (y = 0..15) - 11 - 1 - - - OT10 - Port x configuration bits (y = 0..15) - 10 - 1 - - - OT9 - Port x configuration bits (y = 0..15) - 9 - 1 - - - OT8 - Port x configuration bits (y = 0..15) - 8 - 1 - - - OT7 - Port x configuration bits (y = 0..15) - 7 - 1 - - - OT6 - Port x configuration bits (y = 0..15) - 6 - 1 - - - OT5 - Port x configuration bits (y = 0..15) - 5 - 1 - - - OT4 - Port x configuration bits (y = 0..15) - 4 - 1 - - - OT3 - Port x configuration bits (y = 0..15) - 3 - 1 - - - OT2 - Port x configuration bits (y = 0..15) - 2 - 1 - - - OT1 - Port x configuration bits (y = 0..15) - 1 - 1 - - - OT0 - Port x configuration bits (y = 0..15) - 0 - 1 - - - - - OSPEEDR - OSPEEDR - GPIO port output speed register - 0x8 - 0x20 - read-write - 0x000000C0 - - - OSPEEDR15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - OSPEEDR14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - OSPEEDR13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - OSPEEDR12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - OSPEEDR11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - OSPEEDR10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - OSPEEDR9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - OSPEEDR8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - OSPEEDR7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - OSPEEDR6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - OSPEEDR5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - OSPEEDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - OSPEEDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - OSPEEDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - OSPEEDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - OSPEEDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - PUPDR - PUPDR - GPIO port pull-up/pull-down register - 0xC - 0x20 - read-write - 0x00000100 - - - PUPDR15 - Port x configuration bits (y = 0..15) - 30 - 2 - - - PUPDR14 - Port x configuration bits (y = 0..15) - 28 - 2 - - - PUPDR13 - Port x configuration bits (y = 0..15) - 26 - 2 - - - PUPDR12 - Port x configuration bits (y = 0..15) - 24 - 2 - - - PUPDR11 - Port x configuration bits (y = 0..15) - 22 - 2 - - - PUPDR10 - Port x configuration bits (y = 0..15) - 20 - 2 - - - PUPDR9 - Port x configuration bits (y = 0..15) - 18 - 2 - - - PUPDR8 - Port x configuration bits (y = 0..15) - 16 - 2 - - - PUPDR7 - Port x configuration bits (y = 0..15) - 14 - 2 - - - PUPDR6 - Port x configuration bits (y = 0..15) - 12 - 2 - - - PUPDR5 - Port x configuration bits (y = 0..15) - 10 - 2 - - - PUPDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - PUPDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - PUPDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - PUPDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - PUPDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - IDR - IDR - GPIO port input data register - 0x10 - 0x20 - read-only - 0x00000000 - - - IDR15 - Port input data (y = 0..15) - 15 - 1 - - - IDR14 - Port input data (y = 0..15) - 14 - 1 - - - IDR13 - Port input data (y = 0..15) - 13 - 1 - - - IDR12 - Port input data (y = 0..15) - 12 - 1 - - - IDR11 - Port input data (y = 0..15) - 11 - 1 - - - IDR10 - Port input data (y = 0..15) - 10 - 1 - - - IDR9 - Port input data (y = 0..15) - 9 - 1 - - - IDR8 - Port input data (y = 0..15) - 8 - 1 - - - IDR7 - Port input data (y = 0..15) - 7 - 1 - - - IDR6 - Port input data (y = 0..15) - 6 - 1 - - - IDR5 - Port input data (y = 0..15) - 5 - 1 - - - IDR4 - Port input data (y = 0..15) - 4 - 1 - - - IDR3 - Port input data (y = 0..15) - 3 - 1 - - - IDR2 - Port input data (y = 0..15) - 2 - 1 - - - IDR1 - Port input data (y = 0..15) - 1 - 1 - - - IDR0 - Port input data (y = 0..15) - 0 - 1 - - - - - ODR - ODR - GPIO port output data register - 0x14 - 0x20 - read-write - 0x00000000 - - - ODR15 - Port output data (y = 0..15) - 15 - 1 - - - ODR14 - Port output data (y = 0..15) - 14 - 1 - - - ODR13 - Port output data (y = 0..15) - 13 - 1 - - - ODR12 - Port output data (y = 0..15) - 12 - 1 - - - ODR11 - Port output data (y = 0..15) - 11 - 1 - - - ODR10 - Port output data (y = 0..15) - 10 - 1 - - - ODR9 - Port output data (y = 0..15) - 9 - 1 - - - ODR8 - Port output data (y = 0..15) - 8 - 1 - - - ODR7 - Port output data (y = 0..15) - 7 - 1 - - - ODR6 - Port output data (y = 0..15) - 6 - 1 - - - ODR5 - Port output data (y = 0..15) - 5 - 1 - - - ODR4 - Port output data (y = 0..15) - 4 - 1 - - - ODR3 - Port output data (y = 0..15) - 3 - 1 - - - ODR2 - Port output data (y = 0..15) - 2 - 1 - - - ODR1 - Port output data (y = 0..15) - 1 - 1 - - - ODR0 - Port output data (y = 0..15) - 0 - 1 - - - - - BSRR - BSRR - GPIO port bit set/reset register - 0x18 - 0x20 - write-only - 0x00000000 - - - BR15 - Port x reset bit y (y = 0..15) - 31 - 1 - - - BR14 - Port x reset bit y (y = 0..15) - 30 - 1 - - - BR13 - Port x reset bit y (y = 0..15) - 29 - 1 - - - BR12 - Port x reset bit y (y = 0..15) - 28 - 1 - - - BR11 - Port x reset bit y (y = 0..15) - 27 - 1 - - - BR10 - Port x reset bit y (y = 0..15) - 26 - 1 - - - BR9 - Port x reset bit y (y = 0..15) - 25 - 1 - - - BR8 - Port x reset bit y (y = 0..15) - 24 - 1 - - - BR7 - Port x reset bit y (y = 0..15) - 23 - 1 - - - BR6 - Port x reset bit y (y = 0..15) - 22 - 1 - - - BR5 - Port x reset bit y (y = 0..15) - 21 - 1 - - - BR4 - Port x reset bit y (y = 0..15) - 20 - 1 - - - BR3 - Port x reset bit y (y = 0..15) - 19 - 1 - - - BR2 - Port x reset bit y (y = 0..15) - 18 - 1 - - - BR1 - Port x reset bit y (y = 0..15) - 17 - 1 - - - BR0 - Port x set bit y (y= 0..15) - 16 - 1 - - - BS15 - Port x set bit y (y= 0..15) - 15 - 1 - - - BS14 - Port x set bit y (y= 0..15) - 14 - 1 - - - BS13 - Port x set bit y (y= 0..15) - 13 - 1 - - - BS12 - Port x set bit y (y= 0..15) - 12 - 1 - - - BS11 - Port x set bit y (y= 0..15) - 11 - 1 - - - BS10 - Port x set bit y (y= 0..15) - 10 - 1 - - - BS9 - Port x set bit y (y= 0..15) - 9 - 1 - - - BS8 - Port x set bit y (y= 0..15) - 8 - 1 - - - BS7 - Port x set bit y (y= 0..15) - 7 - 1 - - - BS6 - Port x set bit y (y= 0..15) - 6 - 1 - - - BS5 - Port x set bit y (y= 0..15) - 5 - 1 - - - BS4 - Port x set bit y (y= 0..15) - 4 - 1 - - - BS3 - Port x set bit y (y= 0..15) - 3 - 1 - - - BS2 - Port x set bit y (y= 0..15) - 2 - 1 - - - BS1 - Port x set bit y (y= 0..15) - 1 - 1 - - - BS0 - Port x set bit y (y= 0..15) - 0 - 1 - - - - - LCKR - LCKR - GPIO port configuration lock register - 0x1C - 0x20 - read-write - 0x00000000 - - - LCKK - Port x lock bit y (y= 0..15) - 16 - 1 - - - LCK15 - Port x lock bit y (y= 0..15) - 15 - 1 - - - LCK14 - Port x lock bit y (y= 0..15) - 14 - 1 - - - LCK13 - Port x lock bit y (y= 0..15) - 13 - 1 - - - LCK12 - Port x lock bit y (y= 0..15) - 12 - 1 - - - LCK11 - Port x lock bit y (y= 0..15) - 11 - 1 - - - LCK10 - Port x lock bit y (y= 0..15) - 10 - 1 - - - LCK9 - Port x lock bit y (y= 0..15) - 9 - 1 - - - LCK8 - Port x lock bit y (y= 0..15) - 8 - 1 - - - LCK7 - Port x lock bit y (y= 0..15) - 7 - 1 - - - LCK6 - Port x lock bit y (y= 0..15) - 6 - 1 - - - LCK5 - Port x lock bit y (y= 0..15) - 5 - 1 - - - LCK4 - Port x lock bit y (y= 0..15) - 4 - 1 - - - LCK3 - Port x lock bit y (y= 0..15) - 3 - 1 - - - LCK2 - Port x lock bit y (y= 0..15) - 2 - 1 - - - LCK1 - Port x lock bit y (y= 0..15) - 1 - 1 - - - LCK0 - Port x lock bit y (y= 0..15) - 0 - 1 - - - - - AFRL - AFRL - GPIO alternate function low register - 0x20 - 0x20 - read-write - 0x00000000 - - - AFSEL7 - Alternate function selection for port x bit y (y = 0..7) - 28 - 4 - - - AFSEL6 - Alternate function selection for port x bit y (y = 0..7) - 24 - 4 - - - AFSEL5 - Alternate function selection for port x bit y (y = 0..7) - 20 - 4 - - - AFSEL4 - Alternate function selection for port x bit y (y = 0..7) - 16 - 4 - - - AFSEL3 - Alternate function selection for port x bit y (y = 0..7) - 12 - 4 - - - AFSEL2 - Alternate function selection for port x bit y (y = 0..7) - 8 - 4 - - - AFSEL1 - Alternate function selection for port x bit y (y = 0..7) - 4 - 4 - - - AFSEL0 - Alternate function selection for port x bit y (y = 0..7) - 0 - 4 - - - - - AFRH - AFRH - GPIO alternate function high register - 0x24 - 0x20 - read-write - 0x00000000 - - - AFSEL15 - Alternate function selection for port x bit y (y = 8..15) - 28 - 4 - - - AFSEL14 - Alternate function selection for port x bit y (y = 8..15) - 24 - 4 - - - AFSEL13 - Alternate function selection for port x bit y (y = 8..15) - 20 - 4 - - - AFSEL12 - Alternate function selection for port x bit y (y = 8..15) - 16 - 4 - - - AFSEL11 - Alternate function selection for port x bit y (y = 8..15) - 12 - 4 - - - AFSEL10 - Alternate function selection for port x bit y (y = 8..15) - 8 - 4 - - - AFSEL9 - Alternate function selection for port x bit y (y = 8..15) - 4 - 4 - - - AFSEL8 - Alternate function selection for port x bit y (y = 8..15) - 0 - 4 - - - - - BRR - BRR - port bit reset register - 0x28 - 0x20 - write-only - 0x00000000 - - - BR0 - Port Reset bit - 0 - 1 - - - BR1 - Port Reset bit - 1 - 1 - - - BR2 - Port Reset bit - 2 - 1 - - - BR3 - Port Reset bit - 3 - 1 - - - BR4 - Port Reset bit - 4 - 1 - - - BR5 - Port Reset bit - 5 - 1 - - - BR6 - Port Reset bit - 6 - 1 - - - BR7 - Port Reset bit - 7 - 1 - - - BR8 - Port Reset bit - 8 - 1 - - - BR9 - Port Reset bit - 9 - 1 - - - BR10 - Port Reset bit - 10 - 1 - - - BR11 - Port Reset bit - 11 - 1 - - - BR12 - Port Reset bit - 12 - 1 - - - BR13 - Port Reset bit - 13 - 1 - - - BR14 - Port Reset bit - 14 - 1 - - - BR15 - Port Reset bit - 15 - 1 - - - - - - - GPIOD - 0x48000C00 - - - GPIOE - General-purpose I/Os - GPIO - 0x48001000 - - 0x0 - 0x400 - registers - - - - MODER - MODER - GPIO port mode register - 0x0 - 0x20 - read-write - 0x000003FF - - - MODER4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - MODER3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - MODER2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - MODER1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - MODER0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - OTYPER - OTYPER - GPIO port output type register - 0x4 - 0x20 - read-write - 0x00000000 - - - OT4 - Port x configuration bits (y = 0..15) - 4 - 1 - - - OT3 - Port x configuration bits (y = 0..15) - 3 - 1 - - - OT2 - Port x configuration bits (y = 0..15) - 2 - 1 - - - OT1 - Port x configuration bits (y = 0..15) - 1 - 1 - - - OT0 - Port x configuration bits (y = 0..15) - 0 - 1 - - - - - OSPEEDR - OSPEEDR - GPIO port output speed register - 0x8 - 0x20 - read-write - 0x000000C0 - - - OSPEEDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - OSPEEDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - OSPEEDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - OSPEEDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - OSPEEDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - PUPDR - PUPDR - GPIO port pull-up/pull-down register - 0xC - 0x20 - read-write - 0x00000000 - - - PUPDR4 - Port x configuration bits (y = 0..15) - 8 - 2 - - - PUPDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - PUPDR2 - Port x configuration bits (y = 0..15) - 4 - 2 - - - PUPDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - PUPDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - IDR - IDR - GPIO port input data register - 0x10 - 0x20 - read-only - 0x00000000 - - - IDR4 - Port input data (y = 0..15) - 4 - 1 - - - IDR3 - Port input data (y = 0..15) - 3 - 1 - - - IDR2 - Port input data (y = 0..15) - 2 - 1 - - - IDR1 - Port input data (y = 0..15) - 1 - 1 - - - IDR0 - Port input data (y = 0..15) - 0 - 1 - - - - - ODR - ODR - GPIO port output data register - 0x14 - 0x20 - read-write - 0x00000000 - - - ODR4 - Port output data (y = 0..15) - 4 - 1 - - - ODR3 - Port output data (y = 0..15) - 3 - 1 - - - ODR2 - Port output data (y = 0..15) - 2 - 1 - - - ODR1 - Port output data (y = 0..15) - 1 - 1 - - - ODR0 - Port output data (y = 0..15) - 0 - 1 - - - - - BSRR - BSRR - GPIO port bit set/reset register - 0x18 - 0x20 - write-only - 0x00000000 - - - BR4 - Port x reset bit y (y = 0..15) - 20 - 1 - - - BR3 - Port x reset bit y (y = 0..15) - 19 - 1 - - - BR2 - Port x reset bit y (y = 0..15) - 18 - 1 - - - BR1 - Port x reset bit y (y = 0..15) - 17 - 1 - - - BR0 - Port x set bit y (y= 0..15) - 16 - 1 - - - BS4 - Port x set bit y (y= 0..15) - 4 - 1 - - - BS3 - Port x set bit y (y= 0..15) - 3 - 1 - - - BS2 - Port x set bit y (y= 0..15) - 2 - 1 - - - BS1 - Port x set bit y (y= 0..15) - 1 - 1 - - - BS0 - Port x set bit y (y= 0..15) - 0 - 1 - - - - - LCKR - LCKR - GPIO port configuration lock register - 0x1C - 0x20 - read-write - 0x00000000 - - - LCKK - Port x lock bit y (y= 0..15) - 16 - 1 - - - LCK4 - Port x lock bit y (y= 0..15) - 4 - 1 - - - LCK3 - Port x lock bit y (y= 0..15) - 3 - 1 - - - LCK2 - Port x lock bit y (y= 0..15) - 2 - 1 - - - LCK1 - Port x lock bit y (y= 0..15) - 1 - 1 - - - LCK0 - Port x lock bit y (y= 0..15) - 0 - 1 - - - - - AFRL - AFRL - GPIO alternate function low register - 0x20 - 0x20 - read-write - 0x00000000 - - - AFSEL4 - Alternate function selection for port x bit y (y = 0..7) - 16 - 4 - - - AFSEL3 - Alternate function selection for port x bit y (y = 0..7) - 12 - 4 - - - AFSEL2 - Alternate function selection for port x bit y (y = 0..7) - 8 - 4 - - - AFSEL1 - Alternate function selection for port x bit y (y = 0..7) - 4 - 4 - - - AFSEL0 - Alternate function selection for port x bit y (y = 0..7) - 0 - 4 - - - - - AFRH - AFRH - GPIO alternate function high register - 0x24 - 0x20 - read-write - 0x00000000 - - - AFSEL15 - Alternate function selection for port x bit y (y = 8..15) - 28 - 4 - - - AFSEL14 - Alternate function selection for port x bit y (y = 8..15) - 24 - 4 - - - AFSEL13 - Alternate function selection for port x bit y (y = 8..15) - 20 - 4 - - - AFSEL12 - Alternate function selection for port x bit y (y = 8..15) - 16 - 4 - - - AFSEL11 - Alternate function selection for port x bit y (y = 8..15) - 12 - 4 - - - AFSEL10 - Alternate function selection for port x bit y (y = 8..15) - 8 - 4 - - - AFSEL9 - Alternate function selection for port x bit y (y = 8..15) - 4 - 4 - - - AFSEL8 - Alternate function selection for port x bit y (y = 8..15) - 0 - 4 - - - - - BRR - BRR - port bit reset register - 0x28 - 0x20 - write-only - 0x00000000 - - - BR0 - Port Reset bit - 0 - 1 - - - BR1 - Port Reset bit - 1 - 1 - - - BR2 - Port Reset bit - 2 - 1 - - - BR3 - Port Reset bit - 3 - 1 - - - BR4 - Port Reset bit - 4 - 1 - - - - - - - GPIOH - General-purpose I/Os - GPIO - 0x48001C00 - - 0x0 - 0x400 - registers - - - - MODER - MODER - GPIO port mode register - 0x0 - 0x20 - read-write - 0x000000CF - - - MODER3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - MODER1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - MODER0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - OTYPER - OTYPER - GPIO port output type register - 0x4 - 0x20 - read-write - 0x00000000 - - - OT3 - Port x configuration bits (y = 0..15) - 3 - 1 - - - OT1 - Port x configuration bits (y = 0..15) - 1 - 1 - - - OT0 - Port x configuration bits (y = 0..15) - 0 - 1 - - - - - OSPEEDR - OSPEEDR - GPIO port output speed register - 0x8 - 0x20 - read-write - 0x00000000 - - - OSPEEDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - OSPEEDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - OSPEEDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - PUPDR - PUPDR - GPIO port pull-up/pull-down register - 0xC - 0x20 - read-write - 0x00000000 - - - PUPDR3 - Port x configuration bits (y = 0..15) - 6 - 2 - - - PUPDR1 - Port x configuration bits (y = 0..15) - 2 - 2 - - - PUPDR0 - Port x configuration bits (y = 0..15) - 0 - 2 - - - - - IDR - IDR - GPIO port input data register - 0x10 - 0x20 - read-only - 0x00000000 - - - IDR3 - Port input data (y = 0..15) - 3 - 1 - - - IDR1 - Port input data (y = 0..15) - 1 - 1 - - - IDR0 - Port input data (y = 0..15) - 0 - 1 - - - - - ODR - ODR - GPIO port output data register - 0x14 - 0x20 - read-write - 0x00000000 - - - ODR3 - Port output data (y = 0..15) - 3 - 1 - - - ODR1 - Port output data (y = 0..15) - 1 - 1 - - - ODR0 - Port output data (y = 0..15) - 0 - 1 - - - - - BSRR - BSRR - GPIO port bit set/reset register - 0x18 - 0x20 - write-only - 0x00000000 - - - BR3 - Port x reset bit y (y = 0..15) - 19 - 1 - - - BR1 - Port x reset bit y (y = 0..15) - 17 - 1 - - - BR0 - Port x set bit y (y= 0..15) - 16 - 1 - - - BS3 - Port x set bit y (y= 0..15) - 3 - 1 - - - BS1 - Port x set bit y (y= 0..15) - 1 - 1 - - - BS0 - Port x set bit y (y= 0..15) - 0 - 1 - - - - - LCKR - LCKR - GPIO port configuration lock register - 0x1C - 0x20 - read-write - 0x00000000 - - - LCKK - Port x lock bit y (y= 0..15) - 16 - 1 - - - LCK3 - Port x lock bit y (y= 0..15) - 3 - 1 - - - LCK1 - Port x lock bit y (y= 0..15) - 1 - 1 - - - LCK0 - Port x lock bit y (y= 0..15) - 0 - 1 - - - - - AFRL - AFRL - GPIO alternate function low register - 0x20 - 0x20 - read-write - 0x00000000 - - - AFSEL3 - Alternate function selection for port x bit y (y = 0..7) - 12 - 4 - - - AFSEL1 - Alternate function selection for port x bit y (y = 0..7) - 4 - 4 - - - AFSEL0 - Alternate function selection for port x bit y (y = 0..7) - 0 - 4 - - - - - AFRH - AFRH - GPIO alternate function high register - 0x24 - 0x20 - read-write - 0x00000000 - - - AFSEL15 - Alternate function selection for port x bit y (y = 8..15) - 28 - 4 - - - AFSEL14 - Alternate function selection for port x bit y (y = 8..15) - 24 - 4 - - - AFSEL13 - Alternate function selection for port x bit y (y = 8..15) - 20 - 4 - - - AFSEL12 - Alternate function selection for port x bit y (y = 8..15) - 16 - 4 - - - AFSEL11 - Alternate function selection for port x bit y (y = 8..15) - 12 - 4 - - - AFSEL10 - Alternate function selection for port x bit y (y = 8..15) - 8 - 4 - - - AFSEL9 - Alternate function selection for port x bit y (y = 8..15) - 4 - 4 - - - AFSEL8 - Alternate function selection for port x bit y (y = 8..15) - 0 - 4 - - - - - BRR - BRR - port bit reset register - 0x28 - 0x20 - write-only - 0x00000000 - - - BR0 - Port Reset bit - 0 - 1 - - - BR1 - Port Reset bit - 1 - 1 - - - BR3 - Port Reset bit - 3 - 1 - - - - - - - SAI1 - Serial audio interface - SAI - 0x40015400 - - 0x0 - 0x400 - registers - - - SAI1 - SAI1 global interrupt - 38 - - - - GCR - GCR - Global configuration register - 0x0 - 0x20 - read-write - 0x00000000 - - - SYNCOUT - Synchronization outputs - 4 - 2 - - - SYNCIN - Synchronization inputs - 0 - 2 - - - - - BCR1 - BCR1 - BConfiguration register 1 - 0x24 - 0x20 - read-write - 0x00000040 - - - MCKEN - Master clock generation enable - 27 - 1 - - - OSR - Oversampling ratio for master clock - 26 - 1 - - - MCJDIV - Master clock divider - 20 - 6 - - - NODIV - No divider - 19 - 1 - - - DMAEN - DMA enable - 17 - 1 - - - SAIBEN - Audio block B enable - 16 - 1 - - - OutDri - Output drive - 13 - 1 - - - MONO - Mono mode - 12 - 1 - - - SYNCEN - Synchronization enable - 10 - 2 - - - CKSTR - Clock strobing edge - 9 - 1 - - - LSBFIRST - Least significant bit first - 8 - 1 - - - DS - Data size - 5 - 3 - - - PRTCFG - Protocol configuration - 2 - 2 - - - MODE - Audio block mode - 0 - 2 - - - - - BCR2 - BCR2 - BConfiguration register 2 - 0x28 - 0x20 - read-write - 0x00000000 - - - COMP - Companding mode - 14 - 2 - - - CPL - Complement bit - 13 - 1 - - - MUTECN - Mute counter - 7 - 6 - - - MUTEVAL - Mute value - 6 - 1 - - - MUTE - Mute - 5 - 1 - - - TRIS - Tristate management on data line - 4 - 1 - - - FFLUS - FIFO flush - 3 - 1 - - - FTH - FIFO threshold - 0 - 3 - - - - - BFRCR - BFRCR - BFRCR - 0x2C - 0x20 - read-write - 0x00000007 - - - FSOFF - Frame synchronization offset - 18 - 1 - - - FSPOL - Frame synchronization polarity - 17 - 1 - - - FSDEF - Frame synchronization definition - 16 - 1 - - - FSALL - Frame synchronization active level length - 8 - 7 - - - FRL - Frame length - 0 - 8 - - - - - BSLOTR - BSLOTR - BSlot register - 0x30 - 0x20 - read-write - 0x00000000 - - - SLOTEN - Slot enable - 16 - 16 - - - NBSLOT - Number of slots in an audio frame - 8 - 4 - - - SLOTSZ - Slot size - 6 - 2 - - - FBOFF - First bit offset - 0 - 5 - - - - - BIM - BIM - BInterrupt mask register2 - 0x34 - 0x20 - read-write - 0x00000000 - - - LFSDETIE - Late frame synchronization detection interrupt enable - 6 - 1 - - - AFSDETIE - Anticipated frame synchronization detection interrupt enable - 5 - 1 - - - CNRDYIE - Codec not ready interrupt enable - 4 - 1 - - - FREQIE - FIFO request interrupt enable - 3 - 1 - - - WCKCFG - Wrong clock configuration interrupt enable - 2 - 1 - - - MUTEDET - Mute detection interrupt enable - 1 - 1 - - - OVRUDRIE - Overrun/underrun interrupt enable - 0 - 1 - - - - - BSR - BSR - BStatus register - 0x38 - 0x20 - read-only - 0x00000008 - - - FLVL - FIFO level threshold - 16 - 3 - - - LFSDET - Late frame synchronization detection - 6 - 1 - - - AFSDET - Anticipated frame synchronization detection - 5 - 1 - - - CNRDY - Codec not ready - 4 - 1 - - - FREQ - FIFO request - 3 - 1 - - - WCKCFG - Wrong clock configuration flag - 2 - 1 - - - MUTEDET - Mute detection - 1 - 1 - - - OVRUDR - Overrun / underrun - 0 - 1 - - - - - BCLRFR - BCLRFR - BClear flag register - 0x3C - 0x20 - write-only - 0x00000000 - - - LFSDET - Clear late frame synchronization detection flag - 6 - 1 - - - CAFSDET - Clear anticipated frame synchronization detection flag - 5 - 1 - - - CNRDY - Clear codec not ready flag - 4 - 1 - - - WCKCFG - Clear wrong clock configuration flag - 2 - 1 - - - MUTEDET - Mute detection flag - 1 - 1 - - - OVRUDR - Clear overrun / underrun - 0 - 1 - - - - - BDR - BDR - BData register - 0x40 - 0x20 - read-write - 0x00000000 - - - DATA - Data - 0 - 32 - - - - - ACR1 - ACR1 - AConfiguration register 1 - 0x4 - 0x20 - read-write - 0x00000040 - - - MCKEN - Master clock generation enable - 27 - 1 - - - OSR - Oversampling ratio for master clock - 26 - 1 - - - MCJDIV - Master clock divider - 20 - 6 - - - NODIV - No divider - 19 - 1 - - - DMAEN - DMA enable - 17 - 1 - - - SAIBEN - Audio block B enable - 16 - 1 - - - OutDri - Output drive - 13 - 1 - - - MONO - Mono mode - 12 - 1 - - - SYNCEN - Synchronization enable - 10 - 2 - - - CKSTR - Clock strobing edge - 9 - 1 - - - LSBFIRST - Least significant bit first - 8 - 1 - - - DS - Data size - 5 - 3 - - - PRTCFG - Protocol configuration - 2 - 2 - - - MODE - Audio block mode - 0 - 2 - - - - - ACR2 - ACR2 - AConfiguration register 2 - 0x8 - 0x20 - read-write - 0x00000000 - - - COMP - Companding mode - 14 - 2 - - - CPL - Complement bit - 13 - 1 - - - MUTECN - Mute counter - 7 - 6 - - - MUTEVAL - Mute value - 6 - 1 - - - MUTE - Mute - 5 - 1 - - - TRIS - Tristate management on data line - 4 - 1 - - - FFLUS - FIFO flush - 3 - 1 - - - FTH - FIFO threshold - 0 - 3 - - - - - AFRCR - AFRCR - AFRCR - 0xC - 0x20 - read-write - 0x00000007 - - - FSOFF - Frame synchronization offset - 18 - 1 - - - FSPOL - Frame synchronization polarity - 17 - 1 - - - FSDEF - Frame synchronization definition - 16 - 1 - - - FSALL - Frame synchronization active level length - 8 - 7 - - - FRL - Frame length - 0 - 8 - - - - - ASLOTR - ASLOTR - ASlot register - 0x10 - 0x20 - read-write - 0x00000000 - - - SLOTEN - Slot enable - 16 - 16 - - - NBSLOT - Number of slots in an audio frame - 8 - 4 - - - SLOTSZ - Slot size - 6 - 2 - - - FBOFF - First bit offset - 0 - 5 - - - - - AIM - AIM - AInterrupt mask register2 - 0x14 - 0x20 - read-write - 0x00000000 - - - LFSDET - Late frame synchronization detection interrupt enable - 6 - 1 - - - AFSDETIE - Anticipated frame synchronization detection interrupt enable - 5 - 1 - - - CNRDYIE - Codec not ready interrupt enable - 4 - 1 - - - FREQIE - FIFO request interrupt enable - 3 - 1 - - - WCKCFG - Wrong clock configuration interrupt enable - 2 - 1 - - - MUTEDET - Mute detection interrupt enable - 1 - 1 - - - OVRUDRIE - Overrun/underrun interrupt enable - 0 - 1 - - - - - ASR - ASR - AStatus register - 0x18 - 0x20 - read-only - 0x00000008 - - - FLVL - FIFO level threshold - 16 - 3 - - - LFSDET - Late frame synchronization detection - 6 - 1 - - - AFSDET - Anticipated frame synchronization detection - 5 - 1 - - - CNRDY - Codec not ready - 4 - 1 - - - FREQ - FIFO request - 3 - 1 - - - WCKCFG - Wrong clock configuration flag. This bit is read only - 2 - 1 - - - MUTEDET - Mute detection - 1 - 1 - - - OVRUDR - Overrun / underrun - 0 - 1 - - - - - ACLRFR - ACLRFR - AClear flag register - 0x1C - 0x20 - write-only - 0x00000000 - - - LFSDET - Clear late frame synchronization detection flag - 6 - 1 - - - CAFSDET - Clear anticipated frame synchronization detection flag - 5 - 1 - - - CNRDY - Clear codec not ready flag - 4 - 1 - - - WCKCFG - Clear wrong clock configuration flag - 2 - 1 - - - MUTEDET - Mute detection flag - 1 - 1 - - - OVRUDR - Clear overrun / underrun - 0 - 1 - - - - - ADR - ADR - AData register - 0x20 - 0x20 - read-write - 0x00000000 - - - DATA - Data - 0 - 32 - - - - - PDMCR - PDMCR - PDM control register - 0x44 - 0x20 - read-write - 0x00000000 - - - CKEN4 - Clock enable of bitstream clock number 4 - 11 - 1 - - - CKEN3 - Clock enable of bitstream clock number 3 - 10 - 1 - - - CKEN2 - Clock enable of bitstream clock number 2 - 9 - 1 - - - CKEN1 - Clock enable of bitstream clock number 1 - 8 - 1 - - - MICNBR - Number of microphones - 4 - 2 - - - PDMEN - PDM enable - 0 - 1 - - - - - PDMDLY - PDMDLY - PDM delay register - 0x48 - 0x20 - read-write - 0x00000000 - - - DLYM4R - Delay line for second microphone of pair 4 - 28 - 3 - - - DLYM4L - Delay line for first microphone of pair 4 - 24 - 3 - - - DLYM3R - Delay line for second microphone of pair 3 - 20 - 3 - - - DLYM3L - Delay line for first microphone of pair 3 - 16 - 3 - - - DLYM2R - Delay line for second microphone of pair 2 - 12 - 3 - - - DLYM2L - Delay line for first microphone of pair 2 - 8 - 3 - - - DLYM1R - Delay line for second microphone of pair 1 - 4 - 3 - - - DLYM1L - Delay line for first microphone of pair 1 - 0 - 3 - - - - - - - TIM2 - General-purpose-timers - TIM - 0x40000000 - - 0x0 - 0x400 - registers - - - TIM2 - TIM2 global interrupt - 28 - - - - CR1 - CR1 - control register 1 - 0x0 - 0x20 - read-write - 0x0000 - - - UIFREMAP - UIF status bit remapping - 11 - 1 - - - CKD - Clock division - 8 - 2 - - - ARPE - Auto-reload preload enable - 7 - 1 - - - CMS - Center-aligned mode selection - 5 - 2 - - - DIR - Direction - 4 - 1 - - - OPM - One-pulse mode - 3 - 1 - - - URS - Update request source - 2 - 1 - - - UDIS - Update disable - 1 - 1 - - - CEN - Counter enable - 0 - 1 - - - - - CR2 - CR2 - control register 2 - 0x4 - 0x20 - read-write - 0x0000 - - - TI1S - TI1 selection - 7 - 1 - - - MMS - Master mode selection - 4 - 3 - - - CCDS - Capture/compare DMA selection - 3 - 1 - - - - - SMCR - SMCR - slave mode control register - 0x8 - 0x20 - read-write - 0x0000 - - - SMS_3 - Slave mode selection - bit 3 - 16 - 1 - - - ETP - External trigger polarity - 15 - 1 - - - ECE - External clock enable - 14 - 1 - - - ETPS - External trigger prescaler - 12 - 2 - - - ETF - External trigger filter - 8 - 4 - - - MSM - Master/Slave mode - 7 - 1 - - - TS - Trigger selection - 4 - 3 - - - OCCS - OCREF clear selection - 3 - 1 - - - SMS - Slave mode selection - 0 - 3 - - - - - DIER - DIER - DMA/Interrupt enable register - 0xC - 0x20 - read-write - 0x0000 - - - CC4DE - Capture/Compare 4 DMA request enable - 12 - 1 - - - CC3DE - Capture/Compare 3 DMA request enable - 11 - 1 - - - CC2DE - Capture/Compare 2 DMA request enable - 10 - 1 - - - CC1DE - Capture/Compare 1 DMA request enable - 9 - 1 - - - UDE - Update DMA request enable - 8 - 1 - - - TIE - Trigger interrupt enable - 6 - 1 - - - CC4IE - Capture/Compare 4 interrupt enable - 4 - 1 - - - CC3IE - Capture/Compare 3 interrupt enable - 3 - 1 - - - CC2IE - Capture/Compare 2 interrupt enable - 2 - 1 - - - CC1IE - Capture/Compare 1 interrupt enable - 1 - 1 - - - UIE - Update interrupt enable - 0 - 1 - - - - - SR - SR - status register - 0x10 - 0x20 - read-write - 0x0000 - - - CC4OF - Capture/Compare 4 overcapture flag - 12 - 1 - - - CC3OF - Capture/Compare 3 overcapture flag - 11 - 1 - - - CC2OF - Capture/compare 2 overcapture flag - 10 - 1 - - - CC1OF - Capture/Compare 1 overcapture flag - 9 - 1 - - - TIF - Trigger interrupt flag - 6 - 1 - - - CC4IF - Capture/Compare 4 interrupt flag - 4 - 1 - - - CC3IF - Capture/Compare 3 interrupt flag - 3 - 1 - - - CC2IF - Capture/Compare 2 interrupt flag - 2 - 1 - - - CC1IF - Capture/compare 1 interrupt flag - 1 - 1 - - - UIF - Update interrupt flag - 0 - 1 - - - - - EGR - EGR - event generation register - 0x14 - 0x20 - write-only - 0x0000 - - - TG - Trigger generation - 6 - 1 - - - CC4G - Capture/compare 4 generation - 4 - 1 - - - CC3G - Capture/compare 3 generation - 3 - 1 - - - CC2G - Capture/compare 2 generation - 2 - 1 - - - CC1G - Capture/compare 1 generation - 1 - 1 - - - UG - Update generation - 0 - 1 - - - - - CCMR1_Output - CCMR1_Output - capture/compare mode register 1 (output mode) - 0x18 - 0x20 - read-write - 0x00000000 - - - OC2M_3 - Output Compare 2 mode - bit 3 - 24 - 1 - - - OC1M_3 - Output Compare 1 mode - bit 3 - 16 - 1 - - - OC2CE - Output compare 2 clear enable - 15 - 1 - - - OC2M - Output compare 2 mode - 12 - 3 - - - OC2PE - Output compare 2 preload enable - 11 - 1 - - - OC2FE - Output compare 2 fast enable - 10 - 1 - - - CC2S - Capture/Compare 2 selection - 8 - 2 - - - OC1CE - Output compare 1 clear enable - 7 - 1 - - - OC1M - Output compare 1 mode - 4 - 3 - - - OC1PE - Output compare 1 preload enable - 3 - 1 - - - OC1FE - Output compare 1 fast enable - 2 - 1 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - - - CCMR1_Input - CCMR1_Input - capture/compare mode register 1 (input mode) - CCMR1_Output - 0x18 - 0x20 - read-write - 0x00000000 - - - IC2F - Input capture 2 filter - 12 - 4 - - - IC2PSC - Input capture 2 prescaler - 10 - 2 - - - CC2S - Capture/compare 2 selection - 8 - 2 - - - IC1F - Input capture 1 filter - 4 - 4 - - - IC1PSC - Input capture 1 prescaler - 2 - 2 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - - - CCMR2_Output - CCMR2_Output - capture/compare mode register 2 (output mode) - 0x1C - 0x20 - read-write - 0x00000000 - - - OC4M_3 - Output Compare 4 mode - bit 3 - 24 - 1 - - - OC3M_3 - Output Compare 3 mode - bit 3 - 16 - 1 - - - OC4CE - Output compare 4 clear enable - 15 - 1 - - - OC4M - Output compare 4 mode - 12 - 3 - - - OC4PE - Output compare 4 preload enable - 11 - 1 - - - OC4FE - Output compare 4 fast enable - 10 - 1 - - - CC4S - Capture/Compare 4 selection - 8 - 2 - - - OC3CE - Output compare 3 clear enable - 7 - 1 - - - OC3M - Output compare 3 mode - 4 - 3 - - - OC3PE - Output compare 3 preload enable - 3 - 1 - - - OC3FE - Output compare 3 fast enable - 2 - 1 - - - CC3S - Capture/Compare 3 selection - 0 - 2 - - - - - CCMR2_Input - CCMR2_Input - capture/compare mode register 2 (input mode) - CCMR2_Output - 0x1C - 0x20 - read-write - 0x00000000 - - - IC4F - Input capture 4 filter - 12 - 4 - - - IC4PSC - Input capture 4 prescaler - 10 - 2 - - - CC4S - Capture/Compare 4 selection - 8 - 2 - - - IC3F - Input capture 3 filter - 4 - 4 - - - IC3PSC - Input capture 3 prescaler - 2 - 2 - - - CC3S - Capture/Compare 3 selection - 0 - 2 - - - - - CCER - CCER - capture/compare enable register - 0x20 - 0x20 - read-write - 0x0000 - - - CC4NP - Capture/Compare 4 output Polarity - 15 - 1 - - - CC4P - Capture/Compare 3 output Polarity - 13 - 1 - - - CC4E - Capture/Compare 4 output enable - 12 - 1 - - - CC3NP - Capture/Compare 3 output Polarity - 11 - 1 - - - CC3P - Capture/Compare 3 output Polarity - 9 - 1 - - - CC3E - Capture/Compare 3 output enable - 8 - 1 - - - CC2NP - Capture/Compare 2 output Polarity - 7 - 1 - - - CC2P - Capture/Compare 2 output Polarity - 5 - 1 - - - CC2E - Capture/Compare 2 output enable - 4 - 1 - - - CC1NP - Capture/Compare 1 output Polarity - 3 - 1 - - - CC1P - Capture/Compare 1 output Polarity - 1 - 1 - - - CC1E - Capture/Compare 1 output enable - 0 - 1 - - - - - CNT - CNT - counter - 0x24 - 0x20 - 0x00000000 - - - CNT_H - High counter value (TIM2 only) - 16 - 15 - read-write - - - CNT_L - Low counter value - 0 - 16 - read-write - - - UIFCPY - Value depends on IUFREMAP in TIM2_CR1. - 31 - 1 - read-only - - - - - PSC - PSC - prescaler - 0x28 - 0x20 - read-write - 0x0000 - - - PSC - Prescaler value - 0 - 16 - - - - - ARR - ARR - auto-reload register - 0x2C - 0x20 - read-write - 0x00000000 - - - ARR_H - High Auto-reload value (TIM2 only) - 16 - 16 - - - ARR_L - Low Auto-reload value - 0 - 16 - - - - - CCR1 - CCR1 - capture/compare register 1 - 0x34 - 0x20 - read-write - 0x00000000 - - - CCR1_H - High Capture/Compare 1 value (TIM2 only) - 16 - 16 - - - CCR1_L - Low Capture/Compare 1 value - 0 - 16 - - - - - CCR2 - CCR2 - capture/compare register 2 - 0x38 - 0x20 - read-write - 0x00000000 - - - CCR2_H - High Capture/Compare 2 value (TIM2 only) - 16 - 16 - - - CCR2_L - Low Capture/Compare 2 value - 0 - 16 - - - - - CCR3 - CCR3 - capture/compare register 3 - 0x3C - 0x20 - read-write - 0x00000000 - - - CCR3_H - High Capture/Compare value (TIM2 only) - 16 - 16 - - - CCR3_L - Low Capture/Compare value - 0 - 16 - - - - - CCR4 - CCR4 - capture/compare register 4 - 0x40 - 0x20 - read-write - 0x00000000 - - - CCR4_H - High Capture/Compare value (TIM2 only) - 16 - 16 - - - CCR4_L - Low Capture/Compare value - 0 - 16 - - - - - DCR - DCR - DMA control register - 0x48 - 0x20 - read-write - 0x0000 - - - DBL - DMA burst length - 8 - 5 - - - DBA - DMA base address - 0 - 5 - - - - - DMAR - DMAR - DMA address for full transfer - 0x4C - 0x20 - read-write - 0x0000 - - - DMAB - DMA register for burst accesses - 0 - 16 - - - - - OR - OR - TIM2 option register - 0x50 - 0x20 - read-write - 0x0000 - - - TI4_RMP - Input capture 4 remap - 2 - 2 - - - ETR_RMP - External trigger remap - 1 - 1 - - - ITR_RMP - Internal trigger remap - 0 - 1 - - - - - AF - AF - TIM2 alternate function option register 1 - 0x60 - 0x20 - read-write - 0x0000 - - - ETRSEL - External trigger source selection - 14 - 3 - - - - - - - TIM16 - General purpose timers - TIM - 0x40014400 - - 0x0 - 0x400 - registers - - - - CR1 - CR1 - control register 1 - 0x0 - 0x20 - read-write - 0x0000 - - - CEN - Counter enable - 0 - 1 - - - UDIS - Update disable - 1 - 1 - - - URS - Update request source - 2 - 1 - - - OPM - One-pulse mode - 3 - 1 - - - ARPE - Auto-reload preload enable - 7 - 1 - - - CKD - Clock division - 8 - 2 - - - UIFREMAP - UIF status bit remapping - 11 - 1 - - - - - CR2 - CR2 - control register 2 - 0x4 - 0x20 - read-write - 0x0000 - - - OIS1N - Output Idle state 1 - 9 - 1 - - - OIS1 - Output Idle state 1 - 8 - 1 - - - CCDS - Capture/compare DMA selection - 3 - 1 - - - CCUS - Capture/compare control update selection - 2 - 1 - - - CCPC - Capture/compare preloaded control - 0 - 1 - - - - - DIER - DIER - DMA/Interrupt enable register - 0xC - 0x20 - read-write - 0x0000 - - - UIE - Update interrupt enable - 0 - 1 - - - CC1IE - Capture/Compare 1 interrupt enable - 1 - 1 - - - COMIE - COM interrupt enable - 5 - 1 - - - BIE - Break interrupt enable - 7 - 1 - - - UDE - Update DMA request enable - 8 - 1 - - - CC1DE - Capture/Compare 1 DMA request enable - 9 - 1 - - - - - SR - SR - status register - 0x10 - 0x20 - read-write - 0x0000 - - - CC1OF - Capture/Compare 1 overcapture flag - 9 - 1 - - - BIF - Break interrupt flag - 7 - 1 - - - COMIF - COM interrupt flag - 5 - 1 - - - CC1IF - Capture/compare 1 interrupt flag - 1 - 1 - - - UIF - Update interrupt flag - 0 - 1 - - - - - EGR - EGR - event generation register - 0x14 - 0x20 - write-only - 0x0000 - - - BG - Break generation - 7 - 1 - - - COMG - Capture/Compare control update generation - 5 - 1 - - - CC1G - Capture/compare 1 generation - 1 - 1 - - - UG - Update generation - 0 - 1 - - - - - CCMR1_Output - CCMR1_Output - capture/compare mode register (output mode) - 0x18 - 0x20 - read-write - 0x00000000 - - - OC1M_3 - Output Compare 1 mode - 16 - 1 - - - OC1M - Output Compare 1 mode - 4 - 3 - - - OC1PE - Output Compare 1 preload enable - 3 - 1 - - - OC1FE - Output Compare 1 fast enable - 2 - 1 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - - - CCMR1_Input - CCMR1_Input - capture/compare mode register 1 (input mode) - CCMR1_Output - 0x18 - 0x20 - read-write - 0x00000000 - - - IC1F - Input capture 1 filter - 4 - 4 - - - IC1PSC - Input capture 1 prescaler - 2 - 2 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - - - CCER - CCER - capture/compare enable register - 0x20 - 0x20 - read-write - 0x0000 - - - CC1NP - Capture/Compare 1 output Polarity - 3 - 1 - - - CC1NE - Capture/Compare 1 complementary output enable - 2 - 1 - - - CC1P - Capture/Compare 1 output Polarity - 1 - 1 - - - CC1E - Capture/Compare 1 output enable - 0 - 1 - - - - - CNT - CNT - counter - 0x24 - 0x20 - 0x00000000 - - - CNT - counter value - 0 - 16 - read-write - - - UIFCPY - UIF Copy - 31 - 1 - read-only - - - - - PSC - PSC - prescaler - 0x28 - 0x20 - read-write - 0x0000 - - - PSC - Prescaler value - 0 - 16 - - - - - ARR - ARR - auto-reload register - 0x2C - 0x20 - read-write - 0xFFFF - - - ARR - Auto-reload value - 0 - 16 - - - - - RCR - RCR - repetition counter register - 0x30 - 0x20 - read-write - 0x0000 - - - REP - Repetition counter value - 0 - 8 - - - - - CCR1 - CCR1 - capture/compare register 1 - 0x34 - 0x20 - read-write - 0x00000000 - - - CCR1 - Capture/Compare 1 value - 0 - 16 - - - - - BDTR - BDTR - break and dead-time register - 0x44 - 0x20 - read-write - 0x0000 - - - DTG - Dead-time generator setup - 0 - 8 - - - LOCK - Lock configuration - 8 - 2 - - - OSSI - Off-state selection for Idle mode - 10 - 1 - - - OSSR - Off-state selection for Run mode - 11 - 1 - - - BKE - Break enable - 12 - 1 - - - BKP - Break polarity - 13 - 1 - - - AOE - Automatic output enable - 14 - 1 - - - MOE - Main output enable - 15 - 1 - - - BKDSRM - Break Disarm - 26 - 1 - - - BKBID - Break Bidirectional - 28 - 1 - - - - - DCR - DCR - DMA control register - 0x48 - 0x20 - read-write - 0x0000 - - - DBL - DMA burst length - 8 - 5 - - - DBA - DMA base address - 0 - 5 - - - - - DMAR - DMAR - DMA address for full transfer - 0x4C - 0x20 - read-write - 0x0000 - - - DMAB - DMA register for burst accesses - 0 - 16 - - - - - OR1 - OR1 - TIM option register 1 - 0x50 - 0x20 - read-write - 0x0000 - - - TI1_RMP - Input capture 1 remap - 0 - 2 - - - - - AF1 - AF1 - alternate function register 1 - 0x60 - 0x20 - read-write - 0x00000001 - - - BKINE - BRK BKIN input enable - 0 - 1 - - - BKCMP1E - BRK COMP1 enable - 1 - 1 - - - BKCMP2E - BRK COMP2 enable - 2 - 1 - - - BKINP - BRK BKIN input polarity - 9 - 1 - - - BKCMP1P - BRK COMP1 input polarity - 10 - 1 - - - BKCMP2P - BRK COMP2 input polarit - 11 - 1 - - - - - TISEL - TISEL - input selection register - 0x68 - 0x20 - read-write - 0x00000000 - - - TI1SEL - selects TI1[0] to TI1[15] input - 0 - 4 - - - - - - - TIM17 - General purpose timers - TIM - 0x40014800 - - 0x0 - 0x400 - registers - - - - CR1 - CR1 - control register 1 - 0x0 - 0x20 - read-write - 0x0000 - - - CEN - Counter enable - 0 - 1 - - - UDIS - Update disable - 1 - 1 - - - URS - Update request source - 2 - 1 - - - OPM - One-pulse mode - 3 - 1 - - - ARPE - Auto-reload preload enable - 7 - 1 - - - CKD - Clock division - 8 - 2 - - - UIFREMAP - UIF status bit remapping - 11 - 1 - - - - - CR2 - CR2 - control register 2 - 0x4 - 0x20 - read-write - 0x0000 - - - OIS1N - Output Idle state 1 - 9 - 1 - - - OIS1 - Output Idle state 1 - 8 - 1 - - - CCDS - Capture/compare DMA selection - 3 - 1 - - - CCUS - Capture/compare control update selection - 2 - 1 - - - CCPC - Capture/compare preloaded control - 0 - 1 - - - - - DIER - DIER - DMA/Interrupt enable register - 0xC - 0x20 - read-write - 0x0000 - - - UIE - Update interrupt enable - 0 - 1 - - - CC1IE - Capture/Compare 1 interrupt enable - 1 - 1 - - - COMIE - COM interrupt enable - 5 - 1 - - - BIE - Break interrupt enable - 7 - 1 - - - UDE - Update DMA request enable - 8 - 1 - - - CC1DE - Capture/Compare 1 DMA request enable - 9 - 1 - - - - - SR - SR - status register - 0x10 - 0x20 - read-write - 0x0000 - - - CC1OF - Capture/Compare 1 overcapture flag - 9 - 1 - - - BIF - Break interrupt flag - 7 - 1 - - - COMIF - COM interrupt flag - 5 - 1 - - - CC1IF - Capture/compare 1 interrupt flag - 1 - 1 - - - UIF - Update interrupt flag - 0 - 1 - - - - - EGR - EGR - event generation register - 0x14 - 0x20 - write-only - 0x0000 - - - BG - Break generation - 7 - 1 - - - COMG - Capture/Compare control update generation - 5 - 1 - - - CC1G - Capture/compare 1 generation - 1 - 1 - - - UG - Update generation - 0 - 1 - - - - - CCMR1_Output - CCMR1_Output - capture/compare mode register (output mode) - 0x18 - 0x20 - read-write - 0x00000000 - - - OC1M_3 - Output Compare 1 mode - 16 - 1 - - - OC1M - Output Compare 1 mode - 4 - 3 - - - OC1PE - Output Compare 1 preload enable - 3 - 1 - - - OC1FE - Output Compare 1 fast enable - 2 - 1 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - - - CCMR1_Input - CCMR1_Input - capture/compare mode register 1 (input mode) - CCMR1_Output - 0x18 - 0x20 - read-write - 0x00000000 - - - IC1F - Input capture 1 filter - 4 - 4 - - - IC1PSC - Input capture 1 prescaler - 2 - 2 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - - - CCER - CCER - capture/compare enable register - 0x20 - 0x20 - read-write - 0x0000 - - - CC1NP - Capture/Compare 1 output Polarity - 3 - 1 - - - CC1NE - Capture/Compare 1 complementary output enable - 2 - 1 - - - CC1P - Capture/Compare 1 output Polarity - 1 - 1 - - - CC1E - Capture/Compare 1 output enable - 0 - 1 - - - - - CNT - CNT - counter - 0x24 - 0x20 - 0x00000000 - - - CNT - counter value - 0 - 16 - read-write - - - UIFCPY - UIF Copy - 31 - 1 - read-only - - - - - PSC - PSC - prescaler - 0x28 - 0x20 - read-write - 0x0000 - - - PSC - Prescaler value - 0 - 16 - - - - - ARR - ARR - auto-reload register - 0x2C - 0x20 - read-write - 0xFFFF - - - ARR - Auto-reload value - 0 - 16 - - - - - RCR - RCR - repetition counter register - 0x30 - 0x20 - read-write - 0x0000 - - - REP - Repetition counter value - 0 - 8 - - - - - CCR1 - CCR1 - capture/compare register 1 - 0x34 - 0x20 - read-write - 0x00000000 - - - CCR1 - Capture/Compare 1 value - 0 - 16 - - - - - BDTR - BDTR - break and dead-time register - 0x44 - 0x20 - read-write - 0x0000 - - - DTG - Dead-time generator setup - 0 - 8 - - - LOCK - Lock configuration - 8 - 2 - - - OSSI - Off-state selection for Idle mode - 10 - 1 - - - OSSR - Off-state selection for Run mode - 11 - 1 - - - BKE - Break enable - 12 - 1 - - - BKP - Break polarity - 13 - 1 - - - AOE - Automatic output enable - 14 - 1 - - - MOE - Main output enable - 15 - 1 - - - BKDSRM - Break Disarm - 26 - 1 - - - BKBID - Break Bidirectional - 28 - 1 - - - - - DCR - DCR - DMA control register - 0x48 - 0x20 - read-write - 0x0000 - - - DBL - DMA burst length - 8 - 5 - - - DBA - DMA base address - 0 - 5 - - - - - DMAR - DMAR - DMA address for full transfer - 0x4C - 0x20 - read-write - 0x0000 - - - DMAB - DMA register for burst accesses - 0 - 16 - - - - - OR1 - OR1 - TIM option register 1 - 0x50 - 0x20 - read-write - 0x0000 - - - TI1_RMP - Input capture 1 remap - 0 - 2 - - - - - AF1 - AF1 - alternate function register 1 - 0x60 - 0x20 - read-write - 0x00000001 - - - BKINE - BRK BKIN input enable - 0 - 1 - - - BKCMP1E - BRK COMP1 enable - 1 - 1 - - - BKCMP2E - BRK COMP2 enable - 2 - 1 - - - BKINP - BRK BKIN input polarity - 9 - 1 - - - BKCMP1P - BRK COMP1 input polarity - 10 - 1 - - - BKCMP2P - BRK COMP2 input polarit - 11 - 1 - - - - - TISEL - TISEL - input selection register - 0x68 - 0x20 - read-write - 0x00000000 - - - TI1SEL - selects TI1[0] to TI1[15] input - 0 - 4 - - - - - - - TIM1 - Advanced-timers - TIM - 0x40012C00 - - 0x0 - 0x400 - registers - - - TIM1_BRK - Timer 1 break interrupt - 24 - - - TIM1_UP - Timer 1 Update - 25 - - - TIM1_TRG_COM_TIM17 - TIM1 Trigger and Commutation interrupts and - TIM17 global interrupt - 26 - - - TIM1_CC - TIM1 Capture Compare interrupt - 27 - - - - CR1 - CR1 - control register 1 - 0x0 - 0x20 - read-write - 0x0000 - - - CEN - Counter enable - 0 - 1 - - - OPM - One-pulse mode - 3 - 1 - - - UDIS - Update disable - 1 - 1 - - - URS - Update request source - 2 - 1 - - - DIR - Direction - 4 - 1 - - - CMS - Center-aligned mode selection - 5 - 2 - - - ARPE - Auto-reload preload enable - 7 - 1 - - - CKD - Clock division - 8 - 2 - - - UIFREMAP - UIF status bit remapping - 11 - 1 - - - - - CR2 - CR2 - control register 2 - 0x4 - 0x20 - read-write - 0x0000 - - - MMS2 - Master mode selection 2 - 20 - 4 - - - OIS6 - Output Idle state 6 (OC6 output) - 18 - 1 - - - OIS5 - Output Idle state 5 (OC5 output) - 16 - 1 - - - OIS4 - Output Idle state 4 - 14 - 1 - - - OIS3N - Output Idle state 3 - 13 - 1 - - - OIS3 - Output Idle state 3 - 12 - 1 - - - OIS2N - Output Idle state 2 - 11 - 1 - - - OIS2 - Output Idle state 2 - 10 - 1 - - - OIS1N - Output Idle state 1 - 9 - 1 - - - OIS1 - Output Idle state 1 - 8 - 1 - - - TI1S - TI1 selection - 7 - 1 - - - MMS - Master mode selection - 4 - 3 - - - CCDS - Capture/compare DMA selection - 3 - 1 - - - CCUS - Capture/compare control update selection - 2 - 1 - - - CCPC - Capture/compare preloaded control - 0 - 1 - - - - - SMCR - SMCR - slave mode control register - 0x8 - 0x20 - read-write - 0x0000 - - - SMS - Slave mode selection - 0 - 3 - - - OCCS - OCREF clear selection - 3 - 1 - - - TS - Trigger selection - 4 - 3 - - - MSM - Master/Slave mode - 7 - 1 - - - ETF - External trigger filter - 8 - 4 - - - ETPS - External trigger prescaler - 12 - 2 - - - ECE - External clock enable - 14 - 1 - - - ETP - External trigger polarity - 15 - 1 - - - SMS_3 - Slave mode selection - bit 3 - 16 - 1 - - - - - DIER - DIER - DMA/Interrupt enable register - 0xC - 0x20 - read-write - 0x0000 - - - UIE - Update interrupt enable - 0 - 1 - - - CC1IE - Capture/Compare 1 interrupt enable - 1 - 1 - - - CC2IE - Capture/Compare 2 interrupt enable - 2 - 1 - - - CC3IE - Capture/Compare 3 interrupt enable - 3 - 1 - - - CC4IE - Capture/Compare 4 interrupt enable - 4 - 1 - - - COMIE - COM interrupt enable - 5 - 1 - - - TIE - Trigger interrupt enable - 6 - 1 - - - BIE - Break interrupt enable - 7 - 1 - - - UDE - Update DMA request enable - 8 - 1 - - - CC1DE - Capture/Compare 1 DMA request enable - 9 - 1 - - - CC2DE - Capture/Compare 2 DMA request enable - 10 - 1 - - - CC3DE - Capture/Compare 3 DMA request enable - 11 - 1 - - - CC4DE - Capture/Compare 4 DMA request enable - 12 - 1 - - - COMDE - COM DMA request enable - 13 - 1 - - - TDE - Trigger DMA request enable - 14 - 1 - - - - - SR - SR - status register - 0x10 - 0x20 - read-write - 0x0000 - - - UIF - Update interrupt flag - 0 - 1 - - - CC1IF - Capture/compare 1 interrupt flag - 1 - 1 - - - CC2IF - Capture/Compare 2 interrupt flag - 2 - 1 - - - CC3IF - Capture/Compare 3 interrupt flag - 3 - 1 - - - CC4IF - Capture/Compare 4 interrupt flag - 4 - 1 - - - COMIF - COM interrupt flag - 5 - 1 - - - TIF - Trigger interrupt flag - 6 - 1 - - - BIF - Break interrupt flag - 7 - 1 - - - B2IF - Break 2 interrupt flag - 8 - 1 - - - CC1OF - Capture/Compare 1 overcapture flag - 9 - 1 - - - CC2OF - Capture/compare 2 overcapture flag - 10 - 1 - - - CC3OF - Capture/Compare 3 overcapture flag - 11 - 1 - - - CC4OF - Capture/Compare 4 overcapture flag - 12 - 1 - - - SBIF - System Break interrupt flag - 13 - 1 - - - CC5IF - Compare 5 interrupt flag - 16 - 1 - - - CC6IF - Compare 6 interrupt flag - 17 - 1 - - - - - EGR - EGR - event generation register - 0x14 - 0x20 - write-only - 0x0000 - - - UG - Update generation - 0 - 1 - - - CC1G - Capture/compare 1 generation - 1 - 1 - - - CC2G - Capture/compare 2 generation - 2 - 1 - - - CC3G - Capture/compare 3 generation - 3 - 1 - - - CC4G - Capture/compare 4 generation - 4 - 1 - - - COMG - Capture/Compare control update generation - 5 - 1 - - - TG - Trigger generation - 6 - 1 - - - BG - Break generation - 7 - 1 - - - B2G - Break 2 generation - 8 - 1 - - - - - CCMR1_Input - CCMR1_Input - capture/compare mode register 1 (output mode) - 0x18 - 0x20 - read-write - 0x00000000 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - IC1PSC - Input capture 1 prescaler - 2 - 2 - - - C1F - Input capture 1 filter - 4 - 4 - - - CC2S - capture/Compare 2 selection - 8 - 2 - - - IC2PSC - Input capture 2 prescaler - 10 - 2 - - - IC2F - Input capture 2 filter - 12 - 4 - - - - - CCMR1_Output - CCMR1_Output - capture/compare mode register 1 (output mode) - CCMR1_Input - 0x18 - 0x20 - read-write - 0x00000000 - - - CC1S - Capture/Compare 1 selection - 0 - 2 - - - OC1FE - Output Compare 1 fast enable - 2 - 1 - - - OC1PE - Output Compare 1 preload enable - 3 - 1 - - - OC1M - Output Compare 1 mode - 4 - 3 - - - OC1CE - Output Compare 1 clear enable - 7 - 1 - - - CC2S - Capture/Compare 2 selection - 8 - 2 - - - OC2FE - Output Compare 2 fast enable - 10 - 1 - - - OC2PE - Output Compare 2 preload enable - 11 - 1 - - - OC2M - Output Compare 2 mode - 12 - 3 - - - OC2CE - Output Compare 2 clear enable - 15 - 1 - - - OC1M_3 - Output Compare 1 mode - bit 3 - 16 - 1 - - - OC2M_3 - Output Compare 2 mode - bit 3 - 24 - 1 - - - - - CCMR2_Output - CCMR2_Output - capture/compare mode register 2 (output mode) - 0x1C - 0x20 - read-write - 0x00000000 - - - CC3S - Capture/Compare 3 selection - 0 - 2 - - - OC3FE - Output compare 3 fast enable - 2 - 1 - - - OC3PE - Output compare 3 preload enable - 3 - 1 - - - OC3M - Output compare 3 mode - 4 - 3 - - - OC3CE - Output compare 3 clear enable - 7 - 1 - - - CC4S - Capture/Compare 4 selection - 8 - 2 - - - OC4FE - Output compare 4 fast enable - 10 - 1 - - - OC4PE - Output compare 4 preload enable - 11 - 1 - - - OC4M - Output compare 4 mode - 12 - 3 - - - OC4CE - Output compare 4 clear enable - 15 - 1 - - - OC3M_3 - Output Compare 3 mode - bit 3 - 16 - 1 - - - OC4M_3 - Output Compare 4 mode - bit 3 - 24 - 1 - - - - - CCMR2_Input - CCMR2_Input - capture/compare mode register 2 (output mode) - CCMR2_Output - 0x1C - 0x20 - read-write - 0x00000000 - - - CC3S - Capture/Compare 3 selection - 0 - 2 - - - C3PSC - Input capture 3 prescaler - 2 - 2 - - - IC3F - Input capture 3 filter - 4 - 4 - - - CC4S - Capture/Compare 4 selection - 8 - 2 - - - IC4PSC - Input capture 4 prescaler - 10 - 2 - - - IC4F - Input capture 4 filter - 12 - 4 - - - - - CCER - CCER - capture/compare enable register - 0x20 - 0x20 - read-write - 0x0000 - - - CC1E - Capture/Compare 1 output enable - 0 - 1 - - - CC1P - Capture/Compare 1 output Polarity - 1 - 1 - - - CC1NE - Capture/Compare 1 complementary output enable - 2 - 1 - - - CC1NP - Capture/Compare 1 output Polarity - 3 - 1 - - - CC2E - Capture/Compare 2 output enable - 4 - 1 - - - CC2P - Capture/Compare 2 output Polarity - 5 - 1 - - - CC2NE - Capture/Compare 2 complementary output enable - 6 - 1 - - - CC2NP - Capture/Compare 2 output Polarity - 7 - 1 - - - CC3E - Capture/Compare 3 output enable - 8 - 1 - - - CC3P - Capture/Compare 3 output Polarity - 9 - 1 - - - CC3NE - Capture/Compare 3 complementary output enable - 10 - 1 - - - CC3NP - Capture/Compare 3 output Polarity - 11 - 1 - - - CC4E - Capture/Compare 4 output enable - 12 - 1 - - - CC4P - Capture/Compare 3 output Polarity - 13 - 1 - - - CC4NP - Capture/Compare 4 complementary output polarity - 15 - 1 - - - CC5E - Capture/Compare 5 output enable - 16 - 1 - - - CC5P - Capture/Compare 5 output polarity - 17 - 1 - - - CC6E - Capture/Compare 6 output enable - 20 - 1 - - - CC6P - Capture/Compare 6 output polarity - 21 - 1 - - - - - CNT - CNT - counter - 0x24 - 0x20 - 0x00000000 - - - CNT - counter value - 0 - 16 - read-write - - - UIFCPY - UIF copy - 31 - 1 - read-only - - - - - PSC - PSC - prescaler - 0x28 - 0x20 - read-write - 0x0000 - - - PSC - Prescaler value - 0 - 16 - - - - - ARR - ARR - auto-reload register - 0x2C - 0x20 - read-write - 0x0000FFFF - - - ARR - Auto-reload value - 0 - 16 - - - - - RCR - RCR - repetition counter register - 0x30 - 0x20 - read-write - 0x0000 - - - REP - Repetition counter value - 0 - 16 - - - - - CCR1 - CCR1 - capture/compare register 1 - 0x34 - 0x20 - read-write - 0x00000000 - - - CCR1 - Capture/Compare 1 value - 0 - 16 - - - - - CCR2 - CCR2 - capture/compare register 2 - 0x38 - 0x20 - read-write - 0x00000000 - - - CCR2 - Capture/Compare 2 value - 0 - 16 - - - - - CCR3 - CCR3 - capture/compare register 3 - 0x3C - 0x20 - read-write - 0x00000000 - - - CCR3 - Capture/Compare value - 0 - 16 - - - - - CCR4 - CCR4 - capture/compare register 4 - 0x40 - 0x20 - read-write - 0x00000000 - - - CCR4 - Capture/Compare value - 0 - 16 - - - - - BDTR - BDTR - break and dead-time register - 0x44 - 0x20 - read-write - 0x0000 - - - DTG - Dead-time generator setup - 0 - 8 - - - LOCK - Lock configuration - 8 - 2 - - - OSSI - Off-state selection for Idle mode - 10 - 1 - - - OSSR - Off-state selection for Run mode - 11 - 1 - - - BKE - Break enable - 12 - 1 - - - BKP - Break polarity - 13 - 1 - - - AOE - Automatic output enable - 14 - 1 - - - MOE - Main output enable - 15 - 1 - - - BKF - Break filter - 16 - 4 - - - BK2F - Break 2 filter - 20 - 4 - - - BK2E - Break 2 enable - 24 - 1 - - - BK2P - Break 2 polarity - 25 - 1 - - - - - DCR - DCR - DMA control register - 0x48 - 0x20 - read-write - 0x0000 - - - DBL - DMA burst length - 8 - 5 - - - DBA - DMA base address - 0 - 5 - - - - - DMAR - DMAR - DMA address for full transfer - 0x4C - 0x20 - read-write - 0x0000 - - - DMAB - DMA register for burst accesses - 0 - 16 - - - - - OR - OR - DMA address for full transfer - 0x50 - 0x20 - read-write - 0x0000 - - - TIM1_ETR_ADC1_RMP - TIM1_ETR_ADC1 remapping capability - 0 - 2 - - - TI1_RMP - Input Capture 1 remap - 4 - 1 - - - - - CCMR3_Output - CCMR3_Output - capture/compare mode register 2 (output mode) - 0x54 - 0x20 - read-write - 0x00000000 - - - OC6M_bit3 - Output Compare 6 mode bit 3 - 24 - 1 - - - OC5M_bit3 - Output Compare 5 mode bit 3 - 16 - 1 - - - OC6CE - Output compare 6 clear enable - 15 - 1 - - - OC6M - Output compare 6 mode - 12 - 3 - - - OC6PE - Output compare 6 preload enable - 11 - 1 - - - OC6FE - Output compare 6 fast enable - 10 - 1 - - - OC5CE - Output compare 5 clear enable - 7 - 1 - - - OC5M - Output compare 5 mode - 4 - 3 - - - OC5PE - Output compare 5 preload enable - 3 - 1 - - - OC5FE - Output compare 5 fast enable - 2 - 1 - - - - - CCR5 - CCR5 - capture/compare register 4 - 0x58 - 0x20 - read-write - 0x00000000 - - - CCR5 - Capture/Compare value - 0 - 16 - - - GC5C1 - Group Channel 5 and Channel 1 - 29 - 1 - - - GC5C2 - Group Channel 5 and Channel 2 - 30 - 1 - - - GC5C3 - Group Channel 5 and Channel 3 - 31 - 1 - - - - - CCR6 - CCR6 - capture/compare register 4 - 0x5C - 0x20 - read-write - 0x00000000 - - - CCR6 - Capture/Compare value - 0 - 16 - - - - - AF1 - AF1 - DMA address for full transfer - 0x60 - 0x20 - read-write - 0x00000001 - - - BKINE - BRK BKIN input enable - 0 - 1 - - - BKCMP1E - BRK COMP1 enable - 1 - 1 - - - BKCMP2E - BRK COMP2 enable - 2 - 1 - - - BKINP - BRK BKIN input polarity - 9 - 1 - - - BKCMP1P - BRK COMP1 input polarity - 10 - 1 - - - BKCMP2P - BRK COMP2 input polarity - 11 - 1 - - - ETRSEL - ETR source selection - 14 - 3 - - - - - AF2 - AF2 - DMA address for full transfer - 0x64 - 0x20 - read-write - 0x00000001 - - - BK2INE - BRK2 BKIN input enable - 0 - 1 - - - BK2CMP1E - BRK2 COMP1 enable - 1 - 1 - - - BK2CMP2E - BRK2 COMP2 enable - 2 - 1 - - - BK2DFBK0E - BRK2 DFSDM_BREAK0 enable - 8 - 1 - - - BK2INP - BRK2 BKIN input polarity - 9 - 1 - - - BK2CMP1P - BRK2 COMP1 input polarity - 10 - 1 - - - BK2CMP2P - BRK2 COMP2 input polarity - 11 - 1 - - - - - - - LPTIM1 - Low power timer - LPTIM - 0x40007C00 - - 0x0 - 0x400 - registers - - - LPTIM1 - LPtimer 1 global interrupt - 47 - - - - ISR - ISR - Interrupt and Status Register - 0x0 - 0x20 - read-only - 0x00000000 - - - DOWN - Counter direction change up to down - 6 - 1 - - - UP - Counter direction change down to up - 5 - 1 - - - ARROK - Autoreload register update OK - 4 - 1 - - - CMPOK - Compare register update OK - 3 - 1 - - - EXTTRIG - External trigger edge event - 2 - 1 - - - ARRM - Autoreload match - 1 - 1 - - - CMPM - Compare match - 0 - 1 - - - - - ICR - ICR - Interrupt Clear Register - 0x4 - 0x20 - write-only - 0x00000000 - - - DOWNCF - Direction change to down Clear Flag - 6 - 1 - - - UPCF - Direction change to UP Clear Flag - 5 - 1 - - - ARROKCF - Autoreload register update OK Clear Flag - 4 - 1 - - - CMPOKCF - Compare register update OK Clear Flag - 3 - 1 - - - EXTTRIGCF - External trigger valid edge Clear Flag - 2 - 1 - - - ARRMCF - Autoreload match Clear Flag - 1 - 1 - - - CMPMCF - compare match Clear Flag - 0 - 1 - - - - - IER - IER - Interrupt Enable Register - 0x8 - 0x20 - read-write - 0x00000000 - - - DOWNIE - Direction change to down Interrupt Enable - 6 - 1 - - - UPIE - Direction change to UP Interrupt Enable - 5 - 1 - - - ARROKIE - Autoreload register update OK Interrupt Enable - 4 - 1 - - - CMPOKIE - Compare register update OK Interrupt Enable - 3 - 1 - - - EXTTRIGIE - External trigger valid edge Interrupt Enable - 2 - 1 - - - ARRMIE - Autoreload match Interrupt Enable - 1 - 1 - - - CMPMIE - Compare match Interrupt Enable - 0 - 1 - - - - - CFGR - CFGR - Configuration Register - 0xC - 0x20 - read-write - 0x00000000 - - - ENC - Encoder mode enable - 24 - 1 - - - COUNTMODE - counter mode enabled - 23 - 1 - - - PRELOAD - Registers update mode - 22 - 1 - - - WAVPOL - Waveform shape polarity - 21 - 1 - - - WAVE - Waveform shape - 20 - 1 - - - TIMOUT - Timeout enable - 19 - 1 - - - TRIGEN - Trigger enable and polarity - 17 - 2 - - - TRIGSEL - Trigger selector - 13 - 3 - - - PRESC - Clock prescaler - 9 - 3 - - - TRGFLT - Configurable digital filter for trigger - 6 - 2 - - - CKFLT - Configurable digital filter for external clock - 3 - 2 - - - CKPOL - Clock Polarity - 1 - 2 - - - CKSEL - Clock selector - 0 - 1 - - - - - CR - CR - Control Register - 0x10 - 0x20 - read-write - 0x00000000 - - - RSTARE - Reset after read enable - 4 - 1 - - - COUNTRST - Counter reset - 3 - 1 - - - CNTSTRT - Timer start in continuous mode - 2 - 1 - - - SNGSTRT - LPTIM start in single mode - 1 - 1 - - - ENABLE - LPTIM Enable - 0 - 1 - - - - - CMP - CMP - Compare Register - 0x14 - 0x20 - read-write - 0x00000000 - - - CMP - Compare value - 0 - 16 - - - - - ARR - ARR - Autoreload Register - 0x18 - 0x20 - read-write - 0x00000001 - - - ARR - Auto reload value - 0 - 16 - - - - - CNT - CNT - Counter Register - 0x1C - 0x20 - read-only - 0x00000000 - - - CNT - Counter value - 0 - 16 - - - - - OR - OR - Option Register - 0x20 - 0x20 - read-write - 0x00000000 - - - OR1 - Option register bit 1 - 0 - 1 - - - OR2 - Option register bit 2 - 1 - 1 - - - - - - - LPTIM2 - 0x40009400 - - LPTIM2 - LPtimer 2 global interrupt - 48 - - - - USART1 - Universal synchronous asynchronous receiver transmitter - USART - 0x40013800 - - 0x0 - 0x400 - registers - - - USART1 - USART1 global interrupt - 36 - - - - CR1 - CR1 - Control register 1 - 0x0 - 0x20 - read-write - 0x0000 - - - RXFFIE - RXFIFO Full interrupt enable - 31 - 1 - - - TXFEIE - TXFIFO empty interrupt enable - 30 - 1 - - - FIFOEN - FIFO mode enable - 29 - 1 - - - M1 - Word length - 28 - 1 - - - EOBIE - End of Block interrupt enable - 27 - 1 - - - RTOIE - Receiver timeout interrupt enable - 26 - 1 - - - DEAT4 - Driver Enable assertion time - 25 - 1 - - - DEAT3 - DEAT3 - 24 - 1 - - - DEAT2 - DEAT2 - 23 - 1 - - - DEAT1 - DEAT1 - 22 - 1 - - - DEAT0 - DEAT0 - 21 - 1 - - - DEDT4 - Driver Enable de-assertion time - 20 - 1 - - - DEDT3 - DEDT3 - 19 - 1 - - - DEDT2 - DEDT2 - 18 - 1 - - - DEDT1 - DEDT1 - 17 - 1 - - - DEDT0 - DEDT0 - 16 - 1 - - - OVER8 - Oversampling mode - 15 - 1 - - - CMIE - Character match interrupt enable - 14 - 1 - - - MME - Mute mode enable - 13 - 1 - - - M0 - Word length - 12 - 1 - - - WAKE - Receiver wakeup method - 11 - 1 - - - PCE - Parity control enable - 10 - 1 - - - PS - Parity selection - 9 - 1 - - - PEIE - PE interrupt enable - 8 - 1 - - - TXEIE - interrupt enable - 7 - 1 - - - TCIE - Transmission complete interrupt enable - 6 - 1 - - - RXNEIE - RXNE interrupt enable - 5 - 1 - - - IDLEIE - IDLE interrupt enable - 4 - 1 - - - TE - Transmitter enable - 3 - 1 - - - RE - Receiver enable - 2 - 1 - - - UESM - USART enable in Stop mode - 1 - 1 - - - UE - USART enable - 0 - 1 - - - - - CR2 - CR2 - Control register 2 - 0x4 - 0x20 - read-write - 0x0000 - - - ADD4_7 - Address of the USART node - 28 - 4 - - - ADD0_3 - Address of the USART node - 24 - 4 - - - RTOEN - Receiver timeout enable - 23 - 1 - - - ABRMOD1 - Auto baud rate mode - 22 - 1 - - - ABRMOD0 - ABRMOD0 - 21 - 1 - - - ABREN - Auto baud rate enable - 20 - 1 - - - MSBFIRST - Most significant bit first - 19 - 1 - - - TAINV - Binary data inversion - 18 - 1 - - - TXINV - TX pin active level inversion - 17 - 1 - - - RXINV - RX pin active level inversion - 16 - 1 - - - SWAP - Swap TX/RX pins - 15 - 1 - - - LINEN - LIN mode enable - 14 - 1 - - - STOP - STOP bits - 12 - 2 - - - CLKEN - Clock enable - 11 - 1 - - - CPOL - Clock polarity - 10 - 1 - - - CPHA - Clock phase - 9 - 1 - - - LBCL - Last bit clock pulse - 8 - 1 - - - LBDIE - LIN break detection interrupt enable - 6 - 1 - - - LBDL - LIN break detection length - 5 - 1 - - - ADDM7 - 7-bit Address Detection/4-bit Address Detection - 4 - 1 - - - DIS_NSS - When the DSI_NSS bit is set, the NSS pin input will be ignored - 3 - 1 - - - SLVEN - Synchronous Slave mode enable - 0 - 1 - - - - - CR3 - CR3 - Control register 3 - 0x8 - 0x20 - read-write - 0x0000 - - - TXFTCFG - TXFIFO threshold configuration - 29 - 3 - - - RXFTIE - RXFIFO threshold interrupt enable - 28 - 1 - - - RXFTCFG - Receive FIFO threshold configuration - 25 - 3 - - - TCBGTIE - Tr Complete before guard time, interrupt enable - 24 - 1 - - - TXFTIE - threshold interrupt enable - 23 - 1 - - - WUFIE - Wakeup from Stop mode interrupt enable - 22 - 1 - - - WUS - Wakeup from Stop mode interrupt flag selection - 20 - 2 - - - SCARCNT - Smartcard auto-retry count - 17 - 3 - - - DEP - Driver enable polarity selection - 15 - 1 - - - DEM - Driver enable mode - 14 - 1 - - - DDRE - DMA Disable on Reception Error - 13 - 1 - - - OVRDIS - Overrun Disable - 12 - 1 - - - ONEBIT - One sample bit method enable - 11 - 1 - - - CTSIE - CTS interrupt enable - 10 - 1 - - - CTSE - CTS enable - 9 - 1 - - - RTSE - RTS enable - 8 - 1 - - - DMAT - DMA enable transmitter - 7 - 1 - - - DMAR - DMA enable receiver - 6 - 1 - - - SCEN - Smartcard mode enable - 5 - 1 - - - NACK - Smartcard NACK enable - 4 - 1 - - - HDSEL - Half-duplex selection - 3 - 1 - - - IRLP - Ir low-power - 2 - 1 - - - IREN - Ir mode enable - 1 - 1 - - - EIE - Error interrupt enable - 0 - 1 - - - - - BRR - BRR - Baud rate register - 0xC - 0x20 - read-write - 0x0000 - - - BRR - BRR_4_15 - 0 - 16 - - - - - GTPR - GTPR - Guard time and prescaler register - 0x10 - 0x20 - read-write - 0x0000 - - - GT - Guard time value - 8 - 8 - - - PSC - Prescaler value - 0 - 8 - - - - - RTOR - RTOR - Receiver timeout register - 0x14 - 0x20 - read-write - 0x0000 - - - BLEN - Block Length - 24 - 8 - - - RTO - Receiver timeout value - 0 - 24 - - - - - RQR - RQR - Request register - 0x18 - 0x20 - write-only - 0x0000 - - - TXFRQ - Transmit data flush request - 4 - 1 - - - RXFRQ - Receive data flush request - 3 - 1 - - - MMRQ - Mute mode request - 2 - 1 - - - SBKRQ - Send break request - 1 - 1 - - - ABRRQ - Auto baud rate request - 0 - 1 - - - - - ISR - ISR - Interrupt & status register - 0x1C - 0x20 - read-only - 0x00C0 - - - TXFT - TXFIFO threshold flag - 27 - 1 - - - RXFT - RXFIFO threshold flag - 26 - 1 - - - TCBGT - Transmission complete before guard time flag - 25 - 1 - - - RXFF - RXFIFO Full - 24 - 1 - - - TXFE - TXFIFO Empty - 23 - 1 - - - REACK - REACK - 22 - 1 - - - TEACK - TEACK - 21 - 1 - - - WUF - WUF - 20 - 1 - - - RWU - RWU - 19 - 1 - - - SBKF - SBKF - 18 - 1 - - - CMF - CMF - 17 - 1 - - - BUSY - BUSY - 16 - 1 - - - ABRF - ABRF - 15 - 1 - - - ABRE - ABRE - 14 - 1 - - - UDR - SPI slave underrun error flag - 13 - 1 - - - EOBF - EOBF - 12 - 1 - - - RTOF - RTOF - 11 - 1 - - - CTS - CTS - 10 - 1 - - - CTSIF - CTSIF - 9 - 1 - - - LBDF - LBDF - 8 - 1 - - - TXE - TXE - 7 - 1 - - - TC - TC - 6 - 1 - - - RXNE - RXNE - 5 - 1 - - - IDLE - IDLE - 4 - 1 - - - ORE - ORE - 3 - 1 - - - NF - NF - 2 - 1 - - - FE - FE - 1 - 1 - - - PE - PE - 0 - 1 - - - - - ICR - ICR - Interrupt flag clear register - 0x20 - 0x20 - write-only - 0x0000 - - - WUCF - Wakeup from Stop mode clear flag - 20 - 1 - - - CMCF - Character match clear flag - 17 - 1 - - - UDRCF - SPI slave underrun clear flag - 13 - 1 - - - EOBCF - End of block clear flag - 12 - 1 - - - RTOCF - Receiver timeout clear flag - 11 - 1 - - - CTSCF - CTS clear flag - 9 - 1 - - - LBDCF - LIN break detection clear flag - 8 - 1 - - - TCBGTCF - Transmission complete before Guard time clear flag - 7 - 1 - - - TCCF - Transmission complete clear flag - 6 - 1 - - - TXFECF - TXFIFO empty clear flag - 5 - 1 - - - IDLECF - Idle line detected clear flag - 4 - 1 - - - ORECF - Overrun error clear flag - 3 - 1 - - - NCF - Noise detected clear flag - 2 - 1 - - - FECF - Framing error clear flag - 1 - 1 - - - PECF - Parity error clear flag - 0 - 1 - - - - - RDR - RDR - Receive data register - 0x24 - 0x20 - read-only - 0x0000 - - - RDR - Receive data value - 0 - 9 - - - - - TDR - TDR - Transmit data register - 0x28 - 0x20 - read-write - 0x0000 - - - TDR - Transmit data value - 0 - 9 - - - - - PRESC - PRESC - Prescaler register - 0x2C - 0x20 - read-write - 0x0000 - - - PRESCALER - Clock prescaler - 0 - 4 - - - - - - - LPUART1 - 0x40008000 - - LPUART1 - LPUART1 global interrupt - 37 - - - - SPI1 - Serial peripheral interface/Inter-IC sound - SPI - 0x40013000 - - 0x0 - 0x400 - registers - - - SPI1 - SPI 1 global interrupt - 34 - - - - CR1 - CR1 - control register 1 - 0x0 - 0x20 - read-write - 0x00000000 - - - BIDIMODE - Bidirectional data mode enable - 15 - 1 - - - BIDIOE - Output enable in bidirectional mode - 14 - 1 - - - CRCEN - Hardware CRC calculation enable - 13 - 1 - - - CRCNEXT - CRC transfer next - 12 - 1 - - - DFF - Data frame format - 11 - 1 - - - RXONLY - Receive only - 10 - 1 - - - SSM - Software slave management - 9 - 1 - - - SSI - Internal slave select - 8 - 1 - - - LSBFIRST - Frame format - 7 - 1 - - - SPE - SPI enable - 6 - 1 - - - BR - Baud rate control - 3 - 3 - - - MSTR - Master selection - 2 - 1 - - - CPOL - Clock polarity - 1 - 1 - - - CPHA - Clock phase - 0 - 1 - - - - - CR2 - CR2 - control register 2 - 0x4 - 0x20 - read-write - 0x00000700 - - - RXDMAEN - Rx buffer DMA enable - 0 - 1 - - - TXDMAEN - Tx buffer DMA enable - 1 - 1 - - - SSOE - SS output enable - 2 - 1 - - - NSSP - NSS pulse management - 3 - 1 - - - FRF - Frame format - 4 - 1 - - - ERRIE - Error interrupt enable - 5 - 1 - - - RXNEIE - RX buffer not empty interrupt enable - 6 - 1 - - - TXEIE - Tx buffer empty interrupt enable - 7 - 1 - - - DS - Data size - 8 - 4 - - - FRXTH - FIFO reception threshold - 12 - 1 - - - LDMA_RX - Last DMA transfer for reception - 13 - 1 - - - LDMA_TX - Last DMA transfer for transmission - 14 - 1 - - - - - SR - SR - status register - 0x8 - 0x20 - 0x00000002 - - - RXNE - Receive buffer not empty - 0 - 1 - read-only - - - TXE - Transmit buffer empty - 1 - 1 - read-only - - - CRCERR - CRC error flag - 4 - 1 - read-write - - - MODF - Mode fault - 5 - 1 - read-only - - - OVR - Overrun flag - 6 - 1 - read-only - - - BSY - Busy flag - 7 - 1 - read-only - - - TIFRFE - TI frame format error - 8 - 1 - read-only - - - FRLVL - FIFO reception level - 9 - 2 - read-only - - - FTLVL - FIFO transmission level - 11 - 2 - read-only - - - - - DR - DR - data register - 0xC - 0x20 - read-write - 0x00000000 - - - DR - Data register - 0 - 16 - - - - - CRCPR - CRCPR - CRC polynomial register - 0x10 - 0x20 - read-write - 0x00000007 - - - CRCPOLY - CRC polynomial register - 0 - 16 - - - - - RXCRCR - RXCRCR - RX CRC register - 0x14 - 0x20 - read-only - 0x00000000 - - - RxCRC - Rx CRC register - 0 - 16 - - - - - TXCRCR - TXCRCR - TX CRC register - 0x18 - 0x20 - read-only - 0x00000000 - - - TxCRC - Tx CRC register - 0 - 16 - - - - - - - SPI2 - 0x40003800 - - SPI2 - SPI1 global interrupt - 35 - - - - RTC - Real-time clock - RTC - 0x40002800 - - 0x0 - 0x400 - registers - - - RTC_TAMP - RTC/TAMP/CSS on LSE through EXTI line 19 interrupt - 2 - - - RTC_WKUP - RTC wakeup interrupt through EXTI[19] - 3 - - - RTC_ALARM - RTC Alarms (A and B) interrupt through - AIEC - 41 - - - - TR - TR - time register - 0x0 - 0x20 - read-write - 0x00000000 - - - PM - AM/PM notation - 22 - 1 - - - HT - Hour tens in BCD format - 20 - 2 - - - HU - Hour units in BCD format - 16 - 4 - - - MNT - Minute tens in BCD format - 12 - 3 - - - MNU - Minute units in BCD format - 8 - 4 - - - ST - Second tens in BCD format - 4 - 3 - - - SU - Second units in BCD format - 0 - 4 - - - - - DR - DR - date register - 0x4 - 0x20 - read-write - 0x00002101 - - - YT - Year tens in BCD format - 20 - 4 - - - YU - Year units in BCD format - 16 - 4 - - - WDU - Week day units - 13 - 3 - - - MT - Month tens in BCD format - 12 - 1 - - - MU - Month units in BCD format - 8 - 4 - - - DT - Date tens in BCD format - 4 - 2 - - - DU - Date units in BCD format - 0 - 4 - - - - - CR - CR - control register - 0x8 - 0x20 - read-write - 0x00000000 - - - WCKSEL - Wakeup clock selection - 0 - 3 - - - TSEDGE - Time-stamp event active edge - 3 - 1 - - - REFCKON - Reference clock detection enable (50 or 60 Hz) - 4 - 1 - - - BYPSHAD - Bypass the shadow registers - 5 - 1 - - - FMT - Hour format - 6 - 1 - - - ALRAE - Alarm A enable - 8 - 1 - - - ALRBE - Alarm B enable - 9 - 1 - - - WUTE - Wakeup timer enable - 10 - 1 - - - TSE - Time stamp enable - 11 - 1 - - - ALRAIE - Alarm A interrupt enable - 12 - 1 - - - ALRBIE - Alarm B interrupt enable - 13 - 1 - - - WUTIE - Wakeup timer interrupt enable - 14 - 1 - - - TSIE - Time-stamp interrupt enable - 15 - 1 - - - ADD1H - Add 1 hour (summer time change) - 16 - 1 - - - SUB1H - Subtract 1 hour (winter time change) - 17 - 1 - - - BKP - Backup - 18 - 1 - - - COSEL - Calibration output selection - 19 - 1 - - - POL - Output polarity - 20 - 1 - - - OSEL - Output selection - 21 - 2 - - - COE - Calibration output enable - 23 - 1 - - - ITSE - timestamp on internal event enable - 24 - 1 - - - - - ISR - ISR - initialization and status register - 0xC - 0x20 - 0x00000007 - - - ALRAWF - Alarm A write flag - 0 - 1 - read-only - - - ALRBWF - Alarm B write flag - 1 - 1 - read-only - - - WUTWF - Wakeup timer write flag - 2 - 1 - read-only - - - SHPF - Shift operation pending - 3 - 1 - read-write - - - INITS - Initialization status flag - 4 - 1 - read-only - - - RSF - Registers synchronization flag - 5 - 1 - read-write - - - INITF - Initialization flag - 6 - 1 - read-only - - - INIT - Initialization mode - 7 - 1 - read-write - - - ALRAF - Alarm A flag - 8 - 1 - read-write - - - ALRBF - Alarm B flag - 9 - 1 - read-write - - - WUTF - Wakeup timer flag - 10 - 1 - read-write - - - TSF - Time-stamp flag - 11 - 1 - read-write - - - TSOVF - Time-stamp overflow flag - 12 - 1 - read-write - - - TAMP1F - Tamper detection flag - 13 - 1 - read-write - - - TAMP2F - RTC_TAMP2 detection flag - 14 - 1 - read-write - - - TAMP3F - RTC_TAMP3 detection flag - 15 - 1 - read-write - - - RECALPF - Recalibration pending Flag - 16 - 1 - read-only - - - ITSF - INTERNAL TIME-STAMP FLAG - 17 - 1 - read-write - - - - - PRER - PRER - prescaler register - 0x10 - 0x20 - read-write - 0x007F00FF - - - PREDIV_A - Asynchronous prescaler factor - 16 - 7 - - - PREDIV_S - Synchronous prescaler factor - 0 - 15 - - - - - WUTR - WUTR - wakeup timer register - 0x14 - 0x20 - read-write - 0x0000FFFF - - - WUT - Wakeup auto-reload value bits - 0 - 16 - - - - - ALRMAR - ALRMAR - alarm A register - 0x1C - 0x20 - read-write - 0x00000000 - - - MSK4 - Alarm A date mask - 31 - 1 - - - WDSEL - Week day selection - 30 - 1 - - - DT - Date tens in BCD format - 28 - 2 - - - DU - Date units or day in BCD format - 24 - 4 - - - MSK3 - Alarm A hours mask - 23 - 1 - - - PM - AM/PM notation - 22 - 1 - - - HT - Hour tens in BCD format - 20 - 2 - - - HU - Hour units in BCD format - 16 - 4 - - - MSK2 - Alarm A minutes mask - 15 - 1 - - - MNT - Minute tens in BCD format - 12 - 3 - - - MNU - Minute units in BCD format - 8 - 4 - - - MSK1 - Alarm A seconds mask - 7 - 1 - - - ST - Second tens in BCD format - 4 - 3 - - - SU - Second units in BCD format - 0 - 4 - - - - - ALRMBR - ALRMBR - alarm B register - 0x20 - 0x20 - read-write - 0x00000000 - - - MSK4 - Alarm B date mask - 31 - 1 - - - WDSEL - Week day selection - 30 - 1 - - - DT - Date tens in BCD format - 28 - 2 - - - DU - Date units or day in BCD format - 24 - 4 - - - MSK3 - Alarm B hours mask - 23 - 1 - - - PM - AM/PM notation - 22 - 1 - - - HT - Hour tens in BCD format - 20 - 2 - - - HU - Hour units in BCD format - 16 - 4 - - - MSK2 - Alarm B minutes mask - 15 - 1 - - - MNT - Minute tens in BCD format - 12 - 3 - - - MNU - Minute units in BCD format - 8 - 4 - - - MSK1 - Alarm B seconds mask - 7 - 1 - - - ST - Second tens in BCD format - 4 - 3 - - - SU - Second units in BCD format - 0 - 4 - - - - - WPR - WPR - write protection register - 0x24 - 0x20 - write-only - 0x00000000 - - - KEY - Write protection key - 0 - 8 - - - - - SSR - SSR - sub second register - 0x28 - 0x20 - read-only - 0x00000000 - - - SS - Sub second value - 0 - 16 - - - - - SHIFTR - SHIFTR - shift control register - 0x2C - 0x20 - write-only - 0x00000000 - - - ADD1S - Add one second - 31 - 1 - - - SUBFS - Subtract a fraction of a second - 0 - 15 - - - - - TSTR - TSTR - time stamp time register - 0x30 - 0x20 - read-only - 0x00000000 - - - SU - Second units in BCD format - 0 - 4 - - - ST - Second tens in BCD format - 4 - 3 - - - MNU - Minute units in BCD format - 8 - 4 - - - MNT - Minute tens in BCD format - 12 - 3 - - - HU - Hour units in BCD format - 16 - 4 - - - HT - Hour tens in BCD format - 20 - 2 - - - PM - AM/PM notation - 22 - 1 - - - - - TSDR - TSDR - time stamp date register - 0x34 - 0x20 - read-only - 0x00000000 - - - WDU - Week day units - 13 - 3 - - - MT - Month tens in BCD format - 12 - 1 - - - MU - Month units in BCD format - 8 - 4 - - - DT - Date tens in BCD format - 4 - 2 - - - DU - Date units in BCD format - 0 - 4 - - - - - TSSSR - TSSSR - timestamp sub second register - 0x38 - 0x20 - read-only - 0x00000000 - - - SS - Sub second value - 0 - 16 - - - - - CALR - CALR - calibration register - 0x3C - 0x20 - read-write - 0x00000000 - - - CALP - Increase frequency of RTC by 488.5 ppm - 15 - 1 - - - CALW8 - Use an 8-second calibration cycle period - 14 - 1 - - - CALW16 - Use a 16-second calibration cycle period - 13 - 1 - - - CALM - Calibration minus - 0 - 9 - - - - - TAMPCR - TAMPCR - tamper configuration register - 0x40 - 0x20 - read-write - 0x00000000 - - - TAMP1E - Tamper 1 detection enable - 0 - 1 - - - TAMP1TRG - Active level for tamper 1 - 1 - 1 - - - TAMPIE - Tamper interrupt enable - 2 - 1 - - - TAMP2E - Tamper 2 detection enable - 3 - 1 - - - TAMP2TRG - Active level for tamper 2 - 4 - 1 - - - TAMP3E - Tamper 3 detection enable - 5 - 1 - - - TAMP3TRG - Active level for tamper 3 - 6 - 1 - - - TAMPTS - Activate timestamp on tamper detection event - 7 - 1 - - - TAMPFREQ - Tamper sampling frequency - 8 - 3 - - - TAMPFLT - Tamper filter count - 11 - 2 - - - TAMPPRCH - Tamper precharge duration - 13 - 2 - - - TAMPPUDIS - TAMPER pull-up disable - 15 - 1 - - - TAMP1IE - Tamper 1 interrupt enable - 16 - 1 - - - TAMP1NOERASE - Tamper 1 no erase - 17 - 1 - - - TAMP1MF - Tamper 1 mask flag - 18 - 1 - - - TAMP2IE - Tamper 2 interrupt enable - 19 - 1 - - - TAMP2NOERASE - Tamper 2 no erase - 20 - 1 - - - TAMP2MF - Tamper 2 mask flag - 21 - 1 - - - TAMP3IE - Tamper 3 interrupt enable - 22 - 1 - - - TAMP3NOERASE - Tamper 3 no erase - 23 - 1 - - - TAMP3MF - Tamper 3 mask flag - 24 - 1 - - - - - ALRMASSR - ALRMASSR - alarm A sub second register - 0x44 - 0x20 - read-write - 0x00000000 - - - MASKSS - Mask the most-significant bits starting at this bit - 24 - 4 - - - SS - Sub seconds value - 0 - 15 - - - - - ALRMBSSR - ALRMBSSR - alarm B sub second register - 0x48 - 0x20 - read-write - 0x00000000 - - - MASKSS - Mask the most-significant bits starting at this bit - 24 - 4 - - - SS - Sub seconds value - 0 - 15 - - - - - OR - OR - option register - 0x4C - 0x20 - read-write - 0x00000000 - - - RTC_ALARM_TYPE - RTC_ALARM on PC13 output type - 0 - 1 - - - RTC_OUT_RMP - RTC_OUT remap - 1 - 1 - - - - - BKP0R - BKP0R - backup register - 0x50 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP1R - BKP1R - backup register - 0x54 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP2R - BKP2R - backup register - 0x58 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP3R - BKP3R - backup register - 0x5C - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP4R - BKP4R - backup register - 0x60 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP5R - BKP5R - backup register - 0x64 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP6R - BKP6R - backup register - 0x68 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP7R - BKP7R - backup register - 0x6C - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP8R - BKP8R - backup register - 0x70 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP9R - BKP9R - backup register - 0x74 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP10R - BKP10R - backup register - 0x78 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP11R - BKP11R - backup register - 0x7C - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP12R - BKP12R - backup register - 0x80 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP13R - BKP13R - backup register - 0x84 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP14R - BKP14R - backup register - 0x88 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP15R - BKP15R - backup register - 0x8C - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP16R - BKP16R - backup register - 0x90 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP17R - BKP17R - backup register - 0x94 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP18R - BKP18R - backup register - 0x98 - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - BKP19R - BKP19R - backup register - 0x9C - 0x20 - read-write - 0x00000000 - - - BKP - BKP - 0 - 32 - - - - - - - DBGMCU - Debug support - DBGMCU - 0xE0042000 - - 0x0 - 0x400 - registers - - - - IDCODE - IDCODE - MCU Device ID Code Register - 0x0 - 0x20 - read-only - 0x0 - - - DEV_ID - Device Identifier - 0 - 12 - - - REV_ID - Revision Identifier - 16 - 16 - - - - - CR - CR - Debug MCU Configuration Register - 0x4 - 0x20 - read-write - 0x0 - - - DBG_SLEEP - Debug Sleep Mode - 0 - 1 - - - DBG_STOP - Debug Stop Mode - 1 - 1 - - - DBG_STANDBY - Debug Standby Mode - 2 - 1 - - - TRACE_IOEN - Trace port and clock enable - 5 - 1 - - - TRGOEN - External trigger output enable - 28 - 1 - - - - - APB1FZR1 - APB1FZR1 - APB1 Low Freeze Register CPU1 - 0x3C - 0x20 - read-write - 0x0 - - - DBG_TIMER2_STOP - Debug Timer 2 stopped when Core is halted - 0 - 1 - - - DBG_RTC_STOP - RTC counter stopped when core is halted - 10 - 1 - - - DBG_WWDG_STOP - WWDG counter stopped when core is halted - 11 - 1 - - - DBG_IWDG_STOP - IWDG counter stopped when core is halted - 12 - 1 - - - DBG_I2C1_STOP - Debug I2C1 SMBUS timeout stopped when Core is halted - 21 - 1 - - - DBG_I2C3_STOP - Debug I2C3 SMBUS timeout stopped when core is halted - 23 - 1 - - - DBG_LPTIM1_STOP - Debug LPTIM1 stopped when Core is halted - 31 - 1 - - - - - C2AP_B1FZR1 - C2AP_B1FZR1 - APB1 Low Freeze Register CPU2 - 0x40 - 0x20 - read-write - 0x0 - - - DBG_LPTIM2_STOP - LPTIM2 counter stopped when core is halted - 0 - 1 - - - DBG_RTC_STOP - RTC counter stopped when core is halted - 10 - 1 - - - DBG_IWDG_STOP - IWDG stopped when core is halted - 12 - 1 - - - DBG_I2C1_STOP - I2C1 SMBUS timeout stopped when core is halted - 21 - 1 - - - DBG_I2C3_STOP - I2C3 SMBUS timeout stopped when core is halted - 23 - 1 - - - DBG_LPTIM1_STOP - LPTIM1 counter stopped when core is halted - 31 - 1 - - - - - APB1FZR2 - APB1FZR2 - APB1 High Freeze Register CPU1 - 0x44 - 0x20 - read-write - 0x0 - - - DBG_LPTIM2_STOP - LPTIM2 counter stopped when core is halted - 5 - 1 - - - - - C2APB1FZR2 - C2APB1FZR2 - APB1 High Freeze Register CPU2 - 0x48 - 0x20 - read-write - 0x0 - - - DBG_LPTIM2_STOP - LPTIM2 counter stopped when core is halted - 5 - 1 - - - - - APB2FZR - APB2FZR - APB2 Freeze Register CPU1 - 0x4C - 0x20 - read-write - 0x0 - - - DBG_TIM1_STOP - TIM1 counter stopped when core is halted - 11 - 1 - - - DBG_TIM16_STOP - TIM16 counter stopped when core is halted - 17 - 1 - - - DBG_TIM17_STOP - TIM17 counter stopped when core is halted - 18 - 1 - - - - - C2APB2FZR - C2APB2FZR - APB2 Freeze Register CPU2 - C2APB1FZR2 - 0x48 - 0x20 - read-write - 0x0 - - - DBG_TIM1_STOP - TIM1 counter stopped when core is halted - 11 - 1 - - - DBG_TIM16_STOP - TIM16 counter stopped when core is halted - 17 - 1 - - - DBG_TIM17_STOP - TIM17 counter stopped when core is halted - 18 - 1 - - - - - - - PKA - PKA - PKA - 0x58002000 - - 0x0 - 0x2000 - registers - - - PKA - Private key accelerator - interrupt - 29 - - - - CR - CR - Control register - 0x0 - 0x20 - read-write - 0x00000000 - - - ADDRERRIE - Address error interrupt enable - 20 - 1 - - - RAMERRIE - RAM error interrupt enable - 19 - 1 - - - PROCENDIE - End of operation interrupt enable - 17 - 1 - - - MODE - PKA Operation Mode - 8 - 6 - - - SECLVL - Security Enable - 2 - 1 - - - START - Start the operation - 1 - 1 - - - EN - Peripheral Enable - 0 - 1 - - - - - SR - SR - PKA status register - 0x4 - 0x20 - read-only - 0x00000000 - - - ADDRERRF - Address error flag - 20 - 1 - - - RAMERRF - RAM error flag - 19 - 1 - - - PROCENDF - PKA End of Operation flag - 17 - 1 - - - BUSY - PKA Operation in progress - 16 - 1 - - - - - CLRFR - CLRFR - PKA clear flag register - 0x8 - 0x20 - read-write - 0x00000000 - - - ADDRERRFC - Clear Address error flag - 20 - 1 - - - RAMERRFC - Clear RAM error flag - 19 - 1 - - - PROCENDFC - Clear PKA End of Operation flag - 17 - 1 - - - - - VERR - VERR - PKA version register - 0x1FF4 - 0x20 - read-only - 0x00000010 - - - MINREV - Minor revision - 0 - 4 - - - MAJREV - Major revision - 4 - 4 - - - - - IPIDR - IPIDR - PKA identification register - 0x1FF8 - 0x20 - read-only - 0x00170061 - - - ID - Identification Code - 0 - 32 - - - - - SIDR - SIDR - PKA size ID register - 0x1FFC - 0x20 - read-only - 0xA3C5DD08 - - - SID - Side Identification Code - 0 - 32 - - - - - - - IPCC - IPCC - IPCC - 0x58000C00 - - 0x0 - 0x400 - registers - - - IPCC_C1_RX_IT - IPCC CPU1 RX occupied interrupt - 44 - - - IPCC_C1_TX_IT - IPCC CPU1 TX free interrupt - 45 - - - - C1CR - C1CR - Control register CPU1 - 0x0 - 0x20 - read-write - 0x00000000 - - - TXFIE - processor 1 Transmit channel free interrupt enable - 16 - 1 - - - RXOIE - processor 1 Receive channel occupied interrupt enable - 0 - 1 - - - - - C1MR - C1MR - Mask register CPU1 - 0x4 - 0x20 - read-write - 0xFFFFFFFF - - - CH6FM - processor 1 Transmit channel 6 free interrupt mask - 21 - 1 - - - CH5FM - processor 1 Transmit channel 5 free interrupt mask - 20 - 1 - - - CH4FM - processor 1 Transmit channel 4 free interrupt mask - 19 - 1 - - - CH3FM - processor 1 Transmit channel 3 free interrupt mask - 18 - 1 - - - CH2FM - processor 1 Transmit channel 2 free interrupt mask - 17 - 1 - - - CH1FM - processor 1 Transmit channel 1 free interrupt mask - 16 - 1 - - - CH6OM - processor 1 Receive channel 6 occupied interrupt enable - 5 - 1 - - - CH5OM - processor 1 Receive channel 5 occupied interrupt enable - 4 - 1 - - - CH4OM - processor 1 Receive channel 4 occupied interrupt enable - 3 - 1 - - - CH3OM - processor 1 Receive channel 3 occupied interrupt enable - 2 - 1 - - - CH2OM - processor 1 Receive channel 2 occupied interrupt enable - 1 - 1 - - - CH1OM - processor 1 Receive channel 1 occupied interrupt enable - 0 - 1 - - - - - C1SCR - C1SCR - Status Set or Clear register CPU1 - 0x8 - 0x20 - write-only - 0x00000000 - - - CH6S - processor 1 Transmit channel 6 status set - 21 - 1 - - - CH5S - processor 1 Transmit channel 5 status set - 20 - 1 - - - CH4S - processor 1 Transmit channel 4 status set - 19 - 1 - - - CH3S - processor 1 Transmit channel 3 status set - 18 - 1 - - - CH2S - processor 1 Transmit channel 2 status set - 17 - 1 - - - CH1S - processor 1 Transmit channel 1 status set - 16 - 1 - - - CH6C - processor 1 Receive channel 6 status clear - 5 - 1 - - - CH5C - processor 1 Receive channel 5 status clear - 4 - 1 - - - CH4C - processor 1 Receive channel 4 status clear - 3 - 1 - - - CH3C - processor 1 Receive channel 3 status clear - 2 - 1 - - - CH2C - processor 1 Receive channel 2 status clear - 1 - 1 - - - CH1C - processor 1 Receive channel 1 status clear - 0 - 1 - - - - - C1TO2SR - C1TO2SR - CPU1 to CPU2 status register - 0xC - 0x20 - read-only - 0x00000000 - - - CH6F - processor 1 transmit to process 2 Receive channel 6 status flag - 5 - 1 - - - CH5F - processor 1 transmit to process 2 Receive channel 5 status flag - 4 - 1 - - - CH4F - processor 1 transmit to process 2 Receive channel 4 status flag - 3 - 1 - - - CH3F - processor 1 transmit to process 2 Receive channel 3 status flag - 2 - 1 - - - CH2F - processor 1 transmit to process 2 Receive channel 2 status flag - 1 - 1 - - - CH1F - processor 1 transmit to process 2 Receive channel 1 status flag - 0 - 1 - - - - - C2CR - C2CR - Control register CPU2 - 0x10 - 0x20 - read-write - 0x00000000 - - - TXFIE - processor 2 Transmit channel free interrupt enable - 16 - 1 - - - RXOIE - processor 2 Receive channel occupied interrupt enable - 0 - 1 - - - - - C2MR - C2MR - Mask register CPU2 - 0x14 - 0x20 - read-write - 0xFFFFFFFF - - - CH6FM - processor 2 Transmit channel 6 free interrupt mask - 21 - 1 - - - CH5FM - processor 2 Transmit channel 5 free interrupt mask - 20 - 1 - - - CH4FM - processor 2 Transmit channel 4 free interrupt mask - 19 - 1 - - - CH3FM - processor 2 Transmit channel 3 free interrupt mask - 18 - 1 - - - CH2FM - processor 2 Transmit channel 2 free interrupt mask - 17 - 1 - - - CH1FM - processor 2 Transmit channel 1 free interrupt mask - 16 - 1 - - - CH6OM - processor 2 Receive channel 6 occupied interrupt enable - 5 - 1 - - - CH5OM - processor 2 Receive channel 5 occupied interrupt enable - 4 - 1 - - - CH4OM - processor 2 Receive channel 4 occupied interrupt enable - 3 - 1 - - - CH3OM - processor 2 Receive channel 3 occupied interrupt enable - 2 - 1 - - - CH2OM - processor 2 Receive channel 2 occupied interrupt enable - 1 - 1 - - - CH1OM - processor 2 Receive channel 1 occupied interrupt enable - 0 - 1 - - - - - C2SCR - C2SCR - Status Set or Clear register CPU2 - 0x18 - 0x20 - write-only - 0x00000000 - - - CH6S - processor 2 Transmit channel 6 status set - 21 - 1 - - - CH5S - processor 2 Transmit channel 5 status set - 20 - 1 - - - CH4S - processor 2 Transmit channel 4 status set - 19 - 1 - - - CH3S - processor 2 Transmit channel 3 status set - 18 - 1 - - - CH2S - processor 2 Transmit channel 2 status set - 17 - 1 - - - CH1S - processor 2 Transmit channel 1 status set - 16 - 1 - - - CH6C - processor 2 Receive channel 6 status clear - 5 - 1 - - - CH5C - processor 2 Receive channel 5 status clear - 4 - 1 - - - CH4C - processor 2 Receive channel 4 status clear - 3 - 1 - - - CH3C - processor 2 Receive channel 3 status clear - 2 - 1 - - - CH2C - processor 2 Receive channel 2 status clear - 1 - 1 - - - CH1C - processor 2 Receive channel 1 status clear - 0 - 1 - - - - - C2TOC1SR - C2TOC1SR - CPU2 to CPU1 status register - 0x1C - 0x20 - read-only - 0x00000000 - - - CH6F - processor 2 transmit to process 1 Receive channel 6 status flag - 5 - 1 - - - CH5F - processor 2 transmit to process 1 Receive channel 5 status flag - 4 - 1 - - - CH4F - processor 2 transmit to process 1 Receive channel 4 status flag - 3 - 1 - - - CH3F - processor 2 transmit to process 1 Receive channel 3 status flag - 2 - 1 - - - CH2F - processor 2 transmit to process 1 Receive channel 2 status flag - 1 - 1 - - - CH1F - processor 2 transmit to process 1 Receive channel 1 status flag - 0 - 1 - - - - - HWCFGR - HWCFGR - IPCC Hardware configuration register - 0x3F0 - 0x20 - read-only - 0x00000006 - - - CHANNELS - Number of channels per CPU supported by the IP, range 1 to 16 - 0 - 8 - - - - - VERR - VERR - IPCC version register - 0x3F4 - 0x20 - read-only - 0x00000010 - - - MAJREV - Major Revision - 4 - 4 - - - MINREV - Minor Revision - 0 - 4 - - - - - IPIDR - IPIDR - IPCC indentification register - 0x3F8 - 0x20 - read-only - 0x00100071 - - - IPID - Identification Code - 0 - 32 - - - - - SIDR - SIDR - IPCC size indentification register - 0x3FC - 0x20 - read-only - 0xA3C5DD01 - - - SID - Size Identification Code - 0 - 32 - - - - - - - EXTI - External interrupt/event controller - EXTI - 0x58000800 - - 0x0 - 0x400 - registers - - - PVD - PVD through EXTI[16] (C1IMR2[20]) - 1 - - - EXTI0 - EXTI line 0 interrupt through - EXTI[0] - 6 - - - EXTI1 - EXTI line 0 interrupt through - EXTI[1] - 7 - - - EXTI2 - EXTI line 0 interrupt through - EXTI[2] - 8 - - - EXTI3 - EXTI line 0 interrupt through - EXTI[3] - 9 - - - EXTI4 - EXTI line 0 interrupt through - EXTI[4] - 10 - - - C2SEV - CPU2 SEV through EXTI[40] - 21 - - - EXTI5_9 - EXTI line [9:5] interrupt through - EXTI[9:5] - 23 - - - EXTI10_15 - EXTI line [15:10] interrupt through - EXTI[15:10] - 40 - - - - RTSR1 - RTSR1 - rising trigger selection register - 0x0 - 0x20 - read-write - 0x00000000 - - - RT - Rising trigger event configuration bit of Configurable Event input - 0 - 22 - - - RT_31 - Rising trigger event configuration bit of Configurable Event input - 31 - 1 - - - - - FTSR1 - FTSR1 - falling trigger selection register - 0x4 - 0x20 - read-write - 0x00000000 - - - FT - Falling trigger event configuration bit of Configurable Event input - 0 - 22 - - - FT_31 - Falling trigger event configuration bit of Configurable Event input - 31 - 1 - - - - - SWIER1 - SWIER1 - software interrupt event register - 0x8 - 0x20 - read-write - 0x00000000 - - - SWI - Software interrupt on event - 0 - 22 - - - SWI_31 - Software interrupt on event - 31 - 1 - - - - - PR1 - PR1 - EXTI pending register - 0xC - 0x20 - read-write - 0x00000000 - - - PIF - Configurable event inputs Pending bit - 0 - 22 - - - PIF_31 - Configurable event inputs Pending bit - 31 - 1 - - - - - RTSR2 - RTSR2 - rising trigger selection register - 0x20 - 0x20 - read-write - 0x00000000 - - - RT33 - Rising trigger event configuration bit of Configurable Event input - 1 - 1 - - - RT40_41 - Rising trigger event configuration bit of Configurable Event input - 8 - 2 - - - - - FTSR2 - FTSR2 - falling trigger selection register - 0x24 - 0x20 - read-write - 0x00000000 - - - FT33 - Falling trigger event configuration bit of Configurable Event input - 1 - 1 - - - FT40_41 - Falling trigger event configuration bit of Configurable Event input - 8 - 2 - - - - - SWIER2 - SWIER2 - software interrupt event register - 0x28 - 0x20 - read-write - 0x00000000 - - - SWI33 - Software interrupt on event - 1 - 1 - - - SWI40_41 - Software interrupt on event - 8 - 2 - - - - - PR2 - PR2 - pending register - 0x2C - 0x20 - read-write - 0x00000000 - - - PIF33 - Configurable event inputs x+32 Pending bit. - 1 - 1 - - - PIF40_41 - Configurable event inputs x+32 Pending bit. - 8 - 2 - - - - - C1IMR1 - C1IMR1 - CPUm wakeup with interrupt mask register - 0x80 - 0x20 - read-write - 0x7FC00000 - - - IM - CPU(m) wakeup with interrupt Mask on Event input - 0 - 32 - - - - - C2IMR1 - C2IMR1 - CPUm wakeup with interrupt mask register - 0xC0 - 0x20 - read-write - 0x7FC00000 - - - IM - CPU(m) wakeup with interrupt Mask on Event input - 0 - 32 - - - - - C1EMR1 - C1EMR1 - CPUm wakeup with event mask register - 0x84 - 0x20 - read-write - 0x00000000 - - - EM0_15 - CPU(m) Wakeup with event generation Mask on Event input - 0 - 16 - - - EM17_21 - CPU(m) Wakeup with event generation Mask on Event input - 17 - 5 - - - - - C2EMR1 - C2EMR1 - CPUm wakeup with event mask register - 0xC4 - 0x20 - read-write - 0x00000000 - - - EM0_15 - CPU(m) Wakeup with event generation Mask on Event input - 0 - 16 - - - EM17_21 - CPU(m) Wakeup with event generation Mask on Event input - 17 - 5 - - - - - C1IMR2 - C1IMR2 - CPUm wakeup with interrupt mask register - 0x90 - 0x20 - read-write - 0x0001FCFD - - - IM - CPUm Wakeup with interrupt Mask on Event input - 0 - 17 - - - - - C2IMR2 - C2IMR2 - CPUm wakeup with interrupt mask register - 0xD0 - 0x20 - read-write - 0x0001FCFD - - - IM - CPUm Wakeup with interrupt Mask on Event input - 0 - 17 - - - - - C1EMR2 - C1EMR2 - CPUm wakeup with event mask register - 0x94 - 0x20 - read-write - 0x00000000 - - - EM - CPU(m) Wakeup with event generation Mask on Event input - 8 - 2 - - - - - C2EMR2 - C2EMR2 - CPUm wakeup with event mask register - 0xD4 - 0x20 - read-write - 0x00000000 - - - EM - CPU(m) Wakeup with event generation Mask on Event input - 8 - 2 - - - - - HWCFGR5 - HWCFGR5 - Hardware configuration registers - 0x3E0 - 0x20 - read-only - 0x003EFFFF - - - CPUEVENT - HW configuration CPU event generation - 0 - 32 - - - - - HWCFGR6 - HWCFGR6 - Hardware configuration registers - 0x3DC - 0x20 - read-only - 0x00000300 - - - CPUEVENT - HW configuration CPU event generation - 0 - 32 - - - - - HWCFGR7 - HWCFGR7 - EXTI Hardware configuration registers - 0x3D8 - 0x20 - read-only - 0x00000000 - - - CPUEVENT - HW configuration CPU event generation - 0 - 32 - - - - - HWCFGR2 - HWCFGR2 - Hardware configuration registers - 0x3EC - 0x20 - read-only - 0x803FFFFF - - - EVENT_TRG - HW configuration event trigger type - 0 - 32 - - - - - HWCFGR3 - HWCFGR3 - Hardware configuration registers - 0x3E8 - 0x20 - read-only - 0x00000302 - - - EVENT_TRG - HW configuration event trigger type - 0 - 32 - - - - - HWCFGR4 - HWCFGR4 - Hardware configuration registers - 0x3E4 - 0x20 - read-only - 0x00000000 - - - EVENT_TRG - HW configuration event trigger type - 0 - 32 - - - - - HWCFGR1 - HWCFGR1 - Hardware configuration register 1 - 0x3F0 - 0x20 - read-only - 0x00003130 - - - NBEVENTS - HW configuration number of event - 0 - 8 - - - NBCPUS - HW configuration number of CPUs - 8 - 4 - - - CPUEVTEN - HW configuration of CPU(m) event output enable - 12 - 4 - - - - - VERR - VERR - EXTI IP Version register - 0x3F4 - 0x20 - read-only - 0X00000020 - - - MINREV - Minor Revision number - 0 - 4 - - - MAJREV - Major Revision number - 4 - 4 - - - - - IPIDR - IPIDR - Identification register - 0x3F8 - 0x20 - read-only - 0x000E0001 - - - IPID - IP Identification - 0 - 32 - - - - - SIDR - SIDR - Size ID register - 0x3FC - 0x20 - read-only - 0xA3C5DD01 - - - SID - Size Identification - 0 - 32 - - - - - - - CRS - Clock recovery system - CRS - 0x40006000 - - 0x0 - 0x400 - registers - - - CRS_IT - CRS interrupt - 42 - - - - CR - CR - CRS control register - 0x0 - 0x20 - read-write - 0x00002000 - - - SYNCOKIE - SYNC event OK interrupt enable - 0 - 1 - - - SYNCWARNIE - SYNC warning interrupt enable - 1 - 1 - - - ERRIE - Synchronization or trimming error interrupt enable - 2 - 1 - - - ESYNCIE - Expected SYNC interrupt enable - 3 - 1 - - - CEN - Frequency error counter enable - 5 - 1 - - - AUTOTRIMEN - Automatic trimming enable - 6 - 1 - - - SWSYNC - Automatic trimming enable - 7 - 1 - - - TRIM - HSI48 oscillator smooth trimming - 8 - 6 - - - - - CFGR - CFGR - CRS configuration register - 0x4 - 0x20 - read-write - 0x2022BB7F - - - RELOAD - Counter reload value - 0 - 16 - - - FELIM - Frequency error limit - 16 - 8 - - - SYNCDIV - SYNCDIV - 24 - 3 - - - SYNCSRC - SYNC signal source selection - 28 - 2 - - - SYNCPOL - SYNC polarity selection - 31 - 1 - - - - - ISR - ISR - CRS interrupt and status register - 0x8 - 0x20 - read-only - 0x00000000 - - - SYNCOKF - SYNC event OK flag - 0 - 1 - - - SYNCWARNF - SYNC warning flag - 1 - 1 - - - ERRF - Error flag - 2 - 1 - - - ESYNCF - Expected SYNC flag - 3 - 1 - - - SYNCERR - SYNC error - 8 - 1 - - - SYNCMISS - SYNC missed - 9 - 1 - - - TRIMOVF - Trimming overflow or underflow - 10 - 1 - - - FEDIR - Frequency error direction - 15 - 1 - - - FECAP - Frequency error capture - 16 - 16 - - - - - ICR - ICR - CRS interrupt flag clear register - 0xC - 0x20 - read-write - 0x00000000 - - - SYNCOKC - SYNC event OK clear flag - 0 - 1 - - - SYNCWARNC - warning clear flag - 1 - 1 - - - ERRC - Error clear flag - 2 - 1 - - - ESYNCC - Expected SYNC clear flag - 3 - 1 - - - - - - - USB - Universal serial bus full-speed device interface - USB - 0x40006800 - - 0x0 - 0x800 - registers - - - USB_HP - USB high priority interrupt - 19 - - - USB_LP - USB low priority interrupt (including USB - wakeup) - 20 - - - - EP0R - EP0R - endpoint 0 register - 0x0 - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP1R - EP1R - endpoint 1 register - 0x4 - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP2R - EP2R - endpoint 2 register - 0x8 - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP3R - EP3R - endpoint 3 register - 0xC - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP4R - EP4R - endpoint 4 register - 0x10 - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP5R - EP5R - endpoint 5 register - 0x14 - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP6R - EP6R - endpoint 6 register - 0x18 - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - EP7R - EP7R - endpoint 7 register - 0x1C - 0x10 - read-write - 0x00000000 - - - EA - Endpoint address - 0 - 4 - - - STAT_TX - Status bits, for transmission transfers - 4 - 2 - - - DTOG_TX - Data Toggle, for transmission transfers - 6 - 1 - - - CTR_TX - Correct Transfer for transmission - 7 - 1 - - - EP_KIND - Endpoint kind - 8 - 1 - - - EP_TYPE - Endpoint type - 9 - 2 - - - SETUP - Setup transaction completed - 11 - 1 - - - STAT_RX - Status bits, for reception transfers - 12 - 2 - - - DTOG_RX - Data Toggle, for reception transfers - 14 - 1 - - - CTR_RX - Correct transfer for reception - 15 - 1 - - - - - CNTR - CNTR - control register - 0x40 - 0x10 - read-write - 0x00000003 - - - FRES - Force USB Reset - 0 - 1 - - - PDWN - Power down - 1 - 1 - - - LPMODE - Low-power mode - 2 - 1 - - - FSUSP - Force suspend - 3 - 1 - - - RESUME - Resume request - 4 - 1 - - - L1RESUME - LPM L1 Resume request - 5 - 1 - - - L1REQM - LPM L1 state request interrupt mask - 7 - 1 - - - ESOFM - Expected start of frame interrupt mask - 8 - 1 - - - SOFM - Start of frame interrupt mask - 9 - 1 - - - RESETM - USB reset interrupt mask - 10 - 1 - - - SUSPM - Suspend mode interrupt mask - 11 - 1 - - - WKUPM - Wakeup interrupt mask - 12 - 1 - - - ERRM - Error interrupt mask - 13 - 1 - - - PMAOVRM - Packet memory area over / underrun interrupt mask - 14 - 1 - - - CTRM - Correct transfer interrupt mask - 15 - 1 - - - - - ISTR - ISTR - interrupt status register - 0x44 - 0x10 - 0x00000000 - - - EP_ID - Endpoint Identifier - 0 - 4 - read-only - - - DIR - Direction of transaction - 4 - 1 - read-only - - - L1REQ - LPM L1 state request - 7 - 1 - read-write - - - ESOF - Expected start frame - 8 - 1 - read-write - - - SOF - start of frame - 9 - 1 - read-write - - - RESET - reset request - 10 - 1 - read-write - - - SUSP - Suspend mode request - 11 - 1 - read-write - - - WKUP - Wakeup - 12 - 1 - read-write - - - ERR - Error - 13 - 1 - read-write - - - PMAOVR - Packet memory area over / underrun - 14 - 1 - read-write - - - CTR - Correct transfer - 15 - 1 - read-only - - - - - FNR - FNR - frame number register - 0x48 - 0x10 - read-only - 0x0000 - - - FN - Frame number - 0 - 11 - - - LSOF - Lost SOF - 11 - 2 - - - LCK - Locked - 13 - 1 - - - RXDM - Receive data - line status - 14 - 1 - - - RXDP - Receive data + line status - 15 - 1 - - - - - DADDR - DADDR - device address - 0x4C - 0x10 - read-write - 0x0000 - - - ADD - Device address - 0 - 7 - - - EF - Enable function - 7 - 1 - - - - - BTABLE - BTABLE - Buffer table address - 0x50 - 0x10 - read-write - 0x0000 - - - BTABLE - Buffer table - 3 - 13 - - - - - COUNT0_TX - COUNT0_TX - Transmission byte count 0 - 0x52 - 0x10 - read-write - 0x0000 - - - COUNT0_TX - Transmission byte count - 0 - 10 - - - - - COUNT1_TX - COUNT1_TX - Transmission byte count 0 - 0x5A - 0x10 - read-write - 0x0000 - - - COUNT1_TX - Transmission byte count - 0 - 10 - - - - - COUNT2_TX - COUNT2_TX - Transmission byte count 0 - 0x62 - 0x10 - read-write - 0x0000 - - - COUNT2_TX - Transmission byte count - 0 - 10 - - - - - COUNT3_TX - COUNT3_TX - Transmission byte count 0 - 0x6A - 0x10 - read-write - 0x0000 - - - COUNT3_TX - Transmission byte count - 0 - 10 - - - - - COUNT4_TX - COUNT4_TX - Transmission byte count 0 - 0x72 - 0x10 - read-write - 0x0000 - - - COUNT4_TX - Transmission byte count - 0 - 10 - - - - - COUNT5_TX - COUNT5_TX - Transmission byte count 0 - 0x7A - 0x10 - read-write - 0x0000 - - - COUNT5_TX - Transmission byte count - 0 - 10 - - - - - COUNT6_TX - COUNT6_TX - Transmission byte count 0 - 0x82 - 0x10 - read-write - 0x0000 - - - COUNT6_TX - Transmission byte count - 0 - 10 - - - - - COUNT7_TX - COUNT7_TX - Transmission byte count 0 - 0x8A - 0x10 - read-write - 0x0000 - - - COUNT7_TX - Transmission byte count - 0 - 10 - - - - - ADDR0_RX - ADDR0_RX - Reception buffer address 0 - 0x54 - 0x10 - read-write - 0x0000 - - - ADDR0_RX - Reception buffer address - 1 - 15 - - - - - ADDR1_RX - ADDR1_RX - Reception buffer address 0 - 0x5C - 0x10 - read-write - 0x0000 - - - ADDR1_RX - Reception buffer address - 1 - 15 - - - - - ADDR2_RX - ADDR2_RX - Reception buffer address 0 - 0x64 - 0x10 - read-write - 0x0000 - - - ADDR2_RX - Reception buffer address - 1 - 15 - - - - - ADDR3_RX - ADDR3_RX - Reception buffer address 0 - 0x6C - 0x10 - read-write - 0x0000 - - - ADDR3_RX - Reception buffer address - 1 - 15 - - - - - ADDR4_RX - ADDR4_RX - Reception buffer address 0 - 0x74 - 0x10 - read-write - 0x0000 - - - ADDR4_RX - Reception buffer address - 1 - 15 - - - - - ADDR5_RX - ADDR5_RX - Reception buffer address 0 - 0x7C - 0x10 - read-write - 0x0000 - - - ADDR5_RX - Reception buffer address - 1 - 15 - - - - - ADDR6_RX - ADDR6_RX - Reception buffer address 0 - 0x84 - 0x10 - read-write - 0x0000 - - - ADDR6_RX - Reception buffer address - 1 - 15 - - - - - ADDR7_RX - ADDR7_RX - Reception buffer address 0 - 0x8C - 0x10 - read-write - 0x0000 - - - ADDR7_RX - Reception buffer address - 1 - 15 - - - - - COUNT0_RX - COUNT0_RX - Reception byte count 0 - 0x56 - 0x10 - 0x0000 - - - COUNT0_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT1_RX - COUNT1_RX - Reception byte count 0 - 0x5E - 0x10 - 0x0000 - - - COUNT1_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT2_RX - COUNT2_RX - Reception byte count 0 - 0x66 - 0x10 - 0x0000 - - - COUNT2_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT3_RX - COUNT3_RX - Reception byte count 0 - 0x6E - 0x10 - 0x0000 - - - COUNT3_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT4_RX - COUNT4_RX - Reception byte count 0 - 0x76 - 0x10 - 0x0000 - - - COUNT4_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT5_RX - COUNT5_RX - Reception byte count 0 - 0x7E - 0x10 - 0x0000 - - - COUNT5_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT6_RX - COUNT6_RX - Reception byte count 0 - 0x86 - 0x10 - 0x0000 - - - COUNT6_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - COUNT7_RX - COUNT7_RX - Reception byte count 0 - 0x8E - 0x10 - 0x0000 - - - COUNT7_RX - Reception byte count - 0 - 10 - read-only - - - NUM_BLOCK - Number of blocks - 10 - 5 - read-write - - - BL_SIZE - Block size - 15 - 1 - read-write - - - - - LPMCSR - LPMCSR - control and status register - ADDR0_RX - 0x54 - 0x10 - 0x0000 - - - LPMEN - LPM support enable - 0 - 1 - read-write - - - LPMACK - LPM Token acknowledge enable - 1 - 1 - read-write - - - REMWAKE - RemoteWake value - 3 - 1 - read-write - - - BESL - BESL value - 4 - 4 - read-only - - - - - BCDR - BCDR - Battery charging detector( - 0x58 - 0x10 - 0x0000 - - - BCDEN - Battery charging detector (BCD) enable - 0 - 1 - read-write - - - DCDEN - Data contact detection (DCD) mode enable - 1 - 1 - read-write - - - PDEN - Primary detection (PD) mode enable - 2 - 1 - read-write - - - SDEN - Secondary detection (SD) mode enable - 3 - 1 - read-write - - - DCDET - Data contact detection (DCD) status - 4 - 1 - read-only - - - PDET - Primary detection (PD) status - 5 - 1 - read-only - - - SDET - Secondary detection (SD) status - 6 - 1 - read-only - - - PS2DET - DM pull-up detection status - 7 - 1 - read-only - - - DPPU - DP pull-up control - 15 - 1 - read-write - - - - - - - SCB - System control block - SCB - 0xE000ED00 - - 0x0 - 0x41 - registers - - - - CPUID - CPUID - CPUID base register - 0x0 - 0x20 - read-only - 0x410FC241 - - - Revision - Revision number - 0 - 4 - - - PartNo - Part number of the processor - 4 - 12 - - - Constant - Reads as 0xF - 16 - 4 - - - Variant - Variant number - 20 - 4 - - - Implementer - Implementer code - 24 - 8 - - - - - ICSR - ICSR - Interrupt control and state register - 0x4 - 0x20 - read-write - 0x00000000 - - - VECTACTIVE - Active vector - 0 - 9 - - - RETTOBASE - Return to base level - 11 - 1 - - - VECTPENDING - Pending vector - 12 - 7 - - - ISRPENDING - Interrupt pending flag - 22 - 1 - - - PENDSTCLR - SysTick exception clear-pending bit - 25 - 1 - - - PENDSTSET - SysTick exception set-pending bit - 26 - 1 - - - PENDSVCLR - PendSV clear-pending bit - 27 - 1 - - - PENDSVSET - PendSV set-pending bit - 28 - 1 - - - NMIPENDSET - NMI set-pending bit. - 31 - 1 - - - - - VTOR - VTOR - Vector table offset register - 0x8 - 0x20 - read-write - 0x00000000 - - - TBLOFF - Vector table base offset field - 9 - 21 - - - - - AIRCR - AIRCR - Application interrupt and reset control register - 0xC - 0x20 - read-write - 0x00000000 - - - VECTRESET - VECTRESET - 0 - 1 - - - VECTCLRACTIVE - VECTCLRACTIVE - 1 - 1 - - - SYSRESETREQ - SYSRESETREQ - 2 - 1 - - - PRIGROUP - PRIGROUP - 8 - 3 - - - ENDIANESS - ENDIANESS - 15 - 1 - - - VECTKEYSTAT - Register key - 16 - 16 - - - - - SCR - SCR - System control register - 0x10 - 0x20 - read-write - 0x00000000 - - - SLEEPONEXIT - SLEEPONEXIT - 1 - 1 - - - SLEEPDEEP - SLEEPDEEP - 2 - 1 - - - SEVEONPEND - Send Event on Pending bit - 4 - 1 - - - - - CCR - CCR - Configuration and control register - 0x14 - 0x20 - read-write - 0x00000000 - - - NONBASETHRDENA - Configures how the processor enters Thread mode - 0 - 1 - - - USERSETMPEND - USERSETMPEND - 1 - 1 - - - UNALIGN__TRP - UNALIGN_ TRP - 3 - 1 - - - DIV_0_TRP - DIV_0_TRP - 4 - 1 - - - BFHFNMIGN - BFHFNMIGN - 8 - 1 - - - STKALIGN - STKALIGN - 9 - 1 - - - - - SHPR1 - SHPR1 - System handler priority registers - 0x18 - 0x20 - read-write - 0x00000000 - - - PRI_4 - Priority of system handler 4 - 0 - 8 - - - PRI_5 - Priority of system handler 5 - 8 - 8 - - - PRI_6 - Priority of system handler 6 - 16 - 8 - - - - - SHPR2 - SHPR2 - System handler priority registers - 0x1C - 0x20 - read-write - 0x00000000 - - - PRI_11 - Priority of system handler 11 - 24 - 8 - - - - - SHPR3 - SHPR3 - System handler priority registers - 0x20 - 0x20 - read-write - 0x00000000 - - - PRI_14 - Priority of system handler 14 - 16 - 8 - - - PRI_15 - Priority of system handler 15 - 24 - 8 - - - - - SHCSR - SHCSR - System handler control and state register - 0x24 - 0x20 - read-write - 0x00000000 - - - MEMFAULTACT - Memory management fault exception active bit - 0 - 1 - - - BUSFAULTACT - Bus fault exception active bit - 1 - 1 - - - USGFAULTACT - Usage fault exception active bit - 3 - 1 - - - SVCALLACT - SVC call active bit - 7 - 1 - - - MONITORACT - Debug monitor active bit - 8 - 1 - - - PENDSVACT - PendSV exception active bit - 10 - 1 - - - SYSTICKACT - SysTick exception active bit - 11 - 1 - - - USGFAULTPENDED - Usage fault exception pending bit - 12 - 1 - - - MEMFAULTPENDED - Memory management fault exception pending bit - 13 - 1 - - - BUSFAULTPENDED - Bus fault exception pending bit - 14 - 1 - - - SVCALLPENDED - SVC call pending bit - 15 - 1 - - - MEMFAULTENA - Memory management fault enable bit - 16 - 1 - - - BUSFAULTENA - Bus fault enable bit - 17 - 1 - - - USGFAULTENA - Usage fault enable bit - 18 - 1 - - - - - CFSR_UFSR_BFSR_MMFSR - CFSR_UFSR_BFSR_MMFSR - Configurable fault status register - 0x28 - 0x20 - read-write - 0x00000000 - - - IACCVIOL - Instruction access violation flag - 1 - 1 - - - MUNSTKERR - Memory manager fault on unstacking for a return from exception - 3 - 1 - - - MSTKERR - Memory manager fault on stacking for exception entry. - 4 - 1 - - - MLSPERR - MLSPERR - 5 - 1 - - - MMARVALID - Memory Management Fault Address Register (MMAR) valid flag - 7 - 1 - - - IBUSERR - Instruction bus error - 8 - 1 - - - PRECISERR - Precise data bus error - 9 - 1 - - - IMPRECISERR - Imprecise data bus error - 10 - 1 - - - UNSTKERR - Bus fault on unstacking for a return from exception - 11 - 1 - - - STKERR - Bus fault on stacking for exception entry - 12 - 1 - - - LSPERR - Bus fault on floating-point lazy state preservation - 13 - 1 - - - BFARVALID - Bus Fault Address Register (BFAR) valid flag - 15 - 1 - - - UNDEFINSTR - Undefined instruction usage fault - 16 - 1 - - - INVSTATE - Invalid state usage fault - 17 - 1 - - - INVPC - Invalid PC load usage fault - 18 - 1 - - - NOCP - No coprocessor usage fault. - 19 - 1 - - - UNALIGNED - Unaligned access usage fault - 24 - 1 - - - DIVBYZERO - Divide by zero usage fault - 25 - 1 - - - - - HFSR - HFSR - Hard fault status register - 0x2C - 0x20 - read-write - 0x00000000 - - - VECTTBL - Vector table hard fault - 1 - 1 - - - FORCED - Forced hard fault - 30 - 1 - - - DEBUG_VT - Reserved for Debug use - 31 - 1 - - - - - MMFAR - MMFAR - Memory management fault address register - 0x34 - 0x20 - read-write - 0x00000000 - - - MMFAR - Memory management fault address - 0 - 32 - - - - - BFAR - BFAR - Bus fault address register - 0x38 - 0x20 - read-write - 0x00000000 - - - BFAR - Bus fault address - 0 - 32 - - - - - AFSR - AFSR - Auxiliary fault status register - 0x3C - 0x20 - read-write - 0x00000000 - - - IMPDEF - Implementation defined - 0 - 32 - - - - - - - STK - SysTick timer - STK - 0xE000E010 - - 0x0 - 0x11 - registers - - - - CTRL - CTRL - SysTick control and status register - 0x0 - 0x20 - read-write - 0X00000000 - - - ENABLE - Counter enable - 0 - 1 - - - TICKINT - SysTick exception request enable - 1 - 1 - - - CLKSOURCE - Clock source selection - 2 - 1 - - - COUNTFLAG - COUNTFLAG - 16 - 1 - - - - - LOAD - LOAD - SysTick reload value register - 0x4 - 0x20 - read-write - 0X00000000 - - - RELOAD - RELOAD value - 0 - 24 - - - - - VAL - VAL - SysTick current value register - 0x8 - 0x20 - read-write - 0X00000000 - - - CURRENT - Current counter value - 0 - 24 - - - - - CALIB - CALIB - SysTick calibration value register - 0xC - 0x20 - read-write - 0X00000000 - - - TENMS - Calibration value - 0 - 24 - - - SKEW - SKEW flag: Indicates whether the TENMS value is exact - 30 - 1 - - - NOREF - NOREF flag. Reads as zero - 31 - 1 - - - - - - - MPU - Memory protection unit - MPU - 0xE000ED90 - - 0x0 - 0x15 - registers - - - - MPU_TYPER - MPU_TYPER - MPU type register - 0x0 - 0x20 - read-only - 0X00000800 - - - SEPARATE - Separate flag - 0 - 1 - - - DREGION - Number of MPU data regions - 8 - 8 - - - IREGION - Number of MPU instruction regions - 16 - 8 - - - - - MPU_CTRL - MPU_CTRL - MPU control register - 0x4 - 0x20 - read-only - 0X00000000 - - - ENABLE - Enables the MPU - 0 - 1 - - - HFNMIENA - Enables the operation of MPU during hard fault - 1 - 1 - - - PRIVDEFENA - Enable priviliged software access to default memory map - 2 - 1 - - - - - MPU_RNR - MPU_RNR - MPU region number register - 0x8 - 0x20 - read-write - 0X00000000 - - - REGION - MPU region - 0 - 8 - - - - - MPU_RBAR - MPU_RBAR - MPU region base address register - 0xC - 0x20 - read-write - 0X00000000 - - - REGION - MPU region field - 0 - 4 - - - VALID - MPU region number valid - 4 - 1 - - - ADDR - Region base address field - 5 - 27 - - - - - MPU_RASR - MPU_RASR - MPU region attribute and size register - 0x10 - 0x20 - read-write - 0X00000000 - - - ENABLE - Region enable bit. - 0 - 1 - - - SIZE - Size of the MPU protection region - 1 - 5 - - - SRD - Subregion disable bits - 8 - 8 - - - B - memory attribute - 16 - 1 - - - C - memory attribute - 17 - 1 - - - S - Shareable memory attribute - 18 - 1 - - - TEX - memory attribute - 19 - 3 - - - AP - Access permission - 24 - 3 - - - XN - Instruction access disable bit - 28 - 1 - - - - - - - FPU - Floting point unit - FPU - 0xE000EF34 - - 0x0 - 0xD - registers - - - FPU - Floating point unit interrupt - 54 - - - - FPCCR - FPCCR - Floating-point context control register - 0x0 - 0x20 - read-write - 0x00000000 - - - LSPACT - LSPACT - 0 - 1 - - - USER - USER - 1 - 1 - - - THREAD - THREAD - 3 - 1 - - - HFRDY - HFRDY - 4 - 1 - - - MMRDY - MMRDY - 5 - 1 - - - BFRDY - BFRDY - 6 - 1 - - - MONRDY - MONRDY - 8 - 1 - - - LSPEN - LSPEN - 30 - 1 - - - ASPEN - ASPEN - 31 - 1 - - - - - FPCAR - FPCAR - Floating-point context address register - 0x4 - 0x20 - read-write - 0x00000000 - - - ADDRESS - Location of unpopulated floating-point - 3 - 29 - - - - - FPSCR - FPSCR - Floating-point status control register - 0x8 - 0x20 - read-write - 0x00000000 - - - IOC - Invalid operation cumulative exception bit - 0 - 1 - - - DZC - Division by zero cumulative exception bit. - 1 - 1 - - - OFC - Overflow cumulative exception bit - 2 - 1 - - - UFC - Underflow cumulative exception bit - 3 - 1 - - - IXC - Inexact cumulative exception bit - 4 - 1 - - - IDC - Input denormal cumulative exception bit. - 7 - 1 - - - RMode - Rounding Mode control field - 22 - 2 - - - FZ - Flush-to-zero mode control bit: - 24 - 1 - - - DN - Default NaN mode control bit - 25 - 1 - - - AHP - Alternative half-precision control bit - 26 - 1 - - - V - Overflow condition code flag - 28 - 1 - - - C - Carry condition code flag - 29 - 1 - - - Z - Zero condition code flag - 30 - 1 - - - N - Negative condition code flag - 31 - 1 - - - - - - - NVIC - Nested Vectored Interrupt Controller - NVIC - 0xE000E100 - - 0x0 - 0x351 - registers - - - - ISER0 - ISER0 - Interrupt Set-Enable Register - 0x0 - 0x20 - read-write - 0x00000000 - - - SETENA - SETENA - 0 - 32 - - - - - ISER1 - ISER1 - Interrupt Set-Enable Register - 0x4 - 0x20 - read-write - 0x00000000 - - - SETENA - SETENA - 0 - 32 - - - - - ICER0 - ICER0 - Interrupt Clear-Enable Register - 0x80 - 0x20 - read-write - 0x00000000 - - - CLRENA - CLRENA - 0 - 32 - - - - - ICER1 - ICER1 - Interrupt Clear-Enable Register - 0x84 - 0x20 - read-write - 0x00000000 - - - CLRENA - CLRENA - 0 - 32 - - - - - ISPR0 - ISPR0 - Interrupt Set-Pending Register - 0x100 - 0x20 - read-write - 0x00000000 - - - SETPEND - SETPEND - 0 - 32 - - - - - ISPR1 - ISPR1 - Interrupt Set-Pending Register - 0x104 - 0x20 - read-write - 0x00000000 - - - SETPEND - SETPEND - 0 - 32 - - - - - ICPR0 - ICPR0 - Interrupt Clear-Pending Register - 0x180 - 0x20 - read-write - 0x00000000 - - - CLRPEND - CLRPEND - 0 - 32 - - - - - ICPR1 - ICPR1 - Interrupt Clear-Pending Register - 0x184 - 0x20 - read-write - 0x00000000 - - - CLRPEND - CLRPEND - 0 - 32 - - - - - IABR0 - IABR0 - Interrupt Active Bit Register - 0x200 - 0x20 - read-only - 0x00000000 - - - ACTIVE - ACTIVE - 0 - 32 - - - - - IABR1 - IABR1 - Interrupt Active Bit Register - 0x204 - 0x20 - read-only - 0x00000000 - - - ACTIVE - ACTIVE - 0 - 32 - - - - - IPR0 - IPR0 - Interrupt Priority Register - 0x300 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR1 - IPR1 - Interrupt Priority Register - 0x304 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR2 - IPR2 - Interrupt Priority Register - 0x308 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR3 - IPR3 - Interrupt Priority Register - 0x30C - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR4 - IPR4 - Interrupt Priority Register - 0x310 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR5 - IPR5 - Interrupt Priority Register - 0x314 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR6 - IPR6 - Interrupt Priority Register - 0x318 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR7 - IPR7 - Interrupt Priority Register - 0x31C - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR8 - IPR8 - Interrupt Priority Register - 0x320 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR9 - IPR9 - Interrupt Priority Register - 0x324 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR10 - IPR10 - Interrupt Priority Register - 0x328 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR11 - IPR11 - Interrupt Priority Register - 0x32C - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR12 - IPR12 - Interrupt Priority Register - 0x330 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR13 - IPR13 - Interrupt Priority Register - 0x334 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR14 - IPR14 - Interrupt Priority Register - 0x338 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR15 - IPR15 - Interrupt Priority Register - 0x33C - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR16 - IPR16 - Interrupt Priority Register - 0x340 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - IPR17 - IPR17 - Interrupt Priority Register - 0x344 - 0x20 - read-write - 0x00000000 - - - IPR_N0 - IPR_N0 - 0 - 8 - - - IPR_N1 - IPR_N1 - 8 - 8 - - - IPR_N2 - IPR_N2 - 16 - 8 - - - IPR_N3 - IPR_N3 - 24 - 8 - - - - - - - NVIC_STIR - Nested vectored interrupt controller - NVIC - 0xE000EF00 - - 0x0 - 0x5 - registers - - - - STIR - STIR - Software trigger interrupt register - 0x0 - 0x20 - read-write - 0x00000000 - - - INTID - Software generated interrupt ID - 0 - 9 - - - - - - - SCB_ACTRL - System control block ACTLR - SCB - 0xE000E008 - - 0x0 - 0x5 - registers - - - - ACTRL - ACTRL - Auxiliary control register - 0x0 - 0x20 - read-write - 0x00000000 - - - DISMCYCINT - DISMCYCINT - 0 - 1 - - - DISDEFWBUF - DISDEFWBUF - 1 - 1 - - - DISFOLD - DISFOLD - 2 - 1 - - - DISFPCA - DISFPCA - 8 - 1 - - - DISOOFP - DISOOFP - 9 - 1 - - - - - - - FPU_CPACR - Floating point unit CPACR - FPU - 0xE000ED88 - - 0x0 - 0x5 - registers - - - - CPACR - CPACR - Coprocessor access control register - 0x0 - 0x20 - read-write - 0x0000000 - - - CP - CP - 20 - 4 - - - - - - - +STM32WB55_CM41.9STM32WB55_CM4CM4r0p1littletruetrue4false8320x200x00xFFFFFFFFDMA1Direct memory access controllerDMA0x400200000x00x400registersDMA1_Channel1DMA1 Channel1 global interrupt11DMA1_Channel2DMA1 Channel2 global interrupt12DMA1_Channel3DMA1 Channel3 interrupt13DMA1_Channel4DMA1 Channel4 interrupt14DMA1_Channel5DMA1 Channel5 interrupt15DMA1_Channel6DMA1 Channel6 interrupt16DMA1_Channel7DMA1 Channel 7 interrupt17ISRISRinterrupt status register0x00x20read-only0x00000000TEIF7Channel x transfer error flag (x = 1 ..7)271HTIF7Channel x half transfer flag (x = 1 ..7)261TCIF7Channel x transfer complete flag (x = 1 ..7)251GIF7Channel x global interrupt flag (x = 1 ..7)241TEIF6Channel x transfer error flag (x = 1 ..7)231HTIF6Channel x half transfer flag (x = 1 ..7)221TCIF6Channel x transfer complete flag (x = 1 ..7)211GIF6Channel x global interrupt flag (x = 1 ..7)201TEIF5Channel x transfer error flag (x = 1 ..7)191HTIF5Channel x half transfer flag (x = 1 ..7)181TCIF5Channel x transfer complete flag (x = 1 ..7)171GIF5Channel x global interrupt flag (x = 1 ..7)161TEIF4Channel x transfer error flag (x = 1 ..7)151HTIF4Channel x half transfer flag (x = 1 ..7)141TCIF4Channel x transfer complete flag (x = 1 ..7)131GIF4Channel x global interrupt flag (x = 1 ..7)121TEIF3Channel x transfer error flag (x = 1 ..7)111HTIF3Channel x half transfer flag (x = 1 ..7)101TCIF3Channel x transfer complete flag (x = 1 ..7)91GIF3Channel x global interrupt flag (x = 1 ..7)81TEIF2Channel x transfer error flag (x = 1 ..7)71HTIF2Channel x half transfer flag (x = 1 ..7)61TCIF2Channel x transfer complete flag (x = 1 ..7)51GIF2Channel x global interrupt flag (x = 1 ..7)41TEIF1Channel x transfer error flag (x = 1 ..7)31HTIF1Channel x half transfer flag (x = 1 ..7)21TCIF1Channel x transfer complete flag (x = 1 ..7)11GIF1Channel x global interrupt flag (x = 1 ..7)01IFCRIFCRinterrupt flag clear register0x40x20write-only0x00000000CTEIF7Channel x transfer error clear (x = 1 ..7)271CHTIF7Channel x half transfer clear (x = 1 ..7)261CTCIF7Channel x transfer complete clear (x = 1 ..7)251CGIF7Channel x global interrupt clear (x = 1 ..7)241CTEIF6Channel x transfer error clear (x = 1 ..7)231CHTIF6Channel x half transfer clear (x = 1 ..7)221CTCIF6Channel x transfer complete clear (x = 1 ..7)211CGIF6Channel x global interrupt clear (x = 1 ..7)201CTEIF5Channel x transfer error clear (x = 1 ..7)191CHTIF5Channel x half transfer clear (x = 1 ..7)181CTCIF5Channel x transfer complete clear (x = 1 ..7)171CGIF5Channel x global interrupt clear (x = 1 ..7)161CTEIF4Channel x transfer error clear (x = 1 ..7)151CHTIF4Channel x half transfer clear (x = 1 ..7)141CTCIF4Channel x transfer complete clear (x = 1 ..7)131CGIF4Channel x global interrupt clear (x = 1 ..7)121CTEIF3Channel x transfer error clear (x = 1 ..7)111CHTIF3Channel x half transfer clear (x = 1 ..7)101CTCIF3Channel x transfer complete clear (x = 1 ..7)91CGIF3Channel x global interrupt clear (x = 1 ..7)81CTEIF2Channel x transfer error clear (x = 1 ..7)71CHTIF2Channel x half transfer clear (x = 1 ..7)61CTCIF2Channel x transfer complete clear (x = 1 ..7)51CGIF2Channel x global interrupt clear (x = 1 ..7)41CTEIF1Channel x transfer error clear (x = 1 ..7)31CHTIF1Channel x half transfer clear (x = 1 ..7)21CTCIF1Channel x transfer complete clear (x = 1 ..7)11CGIF1Channel x global interrupt clear (x = 1 ..7)01CCR1CCR1channel x configuration register0x80x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR1CNDTR1channel x number of data register0xC0x20read-write0x00000000NDTNumber of data to transfer016CPAR1CPAR1channel x peripheral address register0x100x20read-write0x00000000PAPeripheral address032CMAR1CMAR1channel x memory address register0x140x20read-write0x00000000MAMemory address032CCR2CCR2channel x configuration register0x1C0x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR2CNDTR2channel x number of data register0x200x20read-write0x00000000NDTNumber of data to transfer016CPAR2CPAR2channel x peripheral address register0x240x20read-write0x00000000PAPeripheral address032CMAR2CMAR2channel x memory address register0x280x20read-write0x00000000MAMemory address032CCR3CCR3channel x configuration register0x300x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR3CNDTR3channel x number of data register0x340x20read-write0x00000000NDTNumber of data to transfer016CPAR3CPAR3channel x peripheral address register0x380x20read-write0x00000000PAPeripheral address032CMAR3CMAR3channel x memory address register0x3C0x20read-write0x00000000MAMemory address032CCR4CCR4channel x configuration register0x440x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR4CNDTR4channel x number of data register0x480x20read-write0x00000000NDTNumber of data to transfer016CPAR4CPAR4channel x peripheral address register0x4C0x20read-write0x00000000PAPeripheral address032CMAR4CMAR4channel x memory address register0x500x20read-write0x00000000MAMemory address032CCR5CCR5channel x configuration register0x580x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR5CNDTR5channel x number of data register0x5C0x20read-write0x00000000NDTNumber of data to transfer016CPAR5CPAR5channel x peripheral address register0x600x20read-write0x00000000PAPeripheral address032CMAR5CMAR5channel x memory address register0x640x20read-write0x00000000MAMemory address032CCR6CCR6channel x configuration register0x6C0x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR6CNDTR6channel x number of data register0x700x20read-write0x00000000NDTNumber of data to transfer016CPAR6CPAR6channel x peripheral address register0x740x20read-write0x00000000PAPeripheral address032CMAR6CMAR6channel x memory address register0x780x20read-write0x00000000MAMemory address032CCR7CCR7channel x configuration register0x800x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR7CNDTR7channel x number of data register0x840x20read-write0x00000000NDTNumber of data to transfer016CPAR7CPAR7channel x peripheral address register0x880x20read-write0x00000000PAPeripheral address032CMAR7CMAR7channel x memory address register0x8C0x20read-write0x00000000MAMemory address032DMA2Direct memory access controllerDMA0x400204000x00x400registersDMA2_CH1DMA2 channel 1 interrupt55DMA2_CH2DMA2 channel 2 interrupt56DMA2_CH3DMA2 channel 3 interrupt57DMA2_CH4DMA2 channel 4 interrupt58DMA2_CH5DMA2 channel 5 interrupt59DMA2_CH6DMA2 channel 6 interrupt60DMA2_CH7DMA2 channel 7 interrupt61ISRISRinterrupt status register0x00x20read-only0x00000000TEIF7Channel x transfer error flag (x = 1 ..7)271HTIF7Channel x half transfer flag (x = 1 ..7)261TCIF7Channel x transfer complete flag (x = 1 ..7)251GIF7Channel x global interrupt flag (x = 1 ..7)241TEIF6Channel x transfer error flag (x = 1 ..7)231HTIF6Channel x half transfer flag (x = 1 ..7)221TCIF6Channel x transfer complete flag (x = 1 ..7)211GIF6Channel x global interrupt flag (x = 1 ..7)201TEIF5Channel x transfer error flag (x = 1 ..7)191HTIF5Channel x half transfer flag (x = 1 ..7)181TCIF5Channel x transfer complete flag (x = 1 ..7)171GIF5Channel x global interrupt flag (x = 1 ..7)161TEIF4Channel x transfer error flag (x = 1 ..7)151HTIF4Channel x half transfer flag (x = 1 ..7)141TCIF4Channel x transfer complete flag (x = 1 ..7)131GIF4Channel x global interrupt flag (x = 1 ..7)121TEIF3Channel x transfer error flag (x = 1 ..7)111HTIF3Channel x half transfer flag (x = 1 ..7)101TCIF3Channel x transfer complete flag (x = 1 ..7)91GIF3Channel x global interrupt flag (x = 1 ..7)81TEIF2Channel x transfer error flag (x = 1 ..7)71HTIF2Channel x half transfer flag (x = 1 ..7)61TCIF2Channel x transfer complete flag (x = 1 ..7)51GIF2Channel x global interrupt flag (x = 1 ..7)41TEIF1Channel x transfer error flag (x = 1 ..7)31HTIF1Channel x half transfer flag (x = 1 ..7)21TCIF1Channel x transfer complete flag (x = 1 ..7)11GIF1Channel x global interrupt flag (x = 1 ..7)01IFCRIFCRinterrupt flag clear register0x40x20write-only0x00000000CTEIF7Channel x transfer error clear (x = 1 ..7)271CHTIF7Channel x half transfer clear (x = 1 ..7)261CTCIF7Channel x transfer complete clear (x = 1 ..7)251CGIF7Channel x global interrupt clear (x = 1 ..7)241CTEIF6Channel x transfer error clear (x = 1 ..7)231CHTIF6Channel x half transfer clear (x = 1 ..7)221CTCIF6Channel x transfer complete clear (x = 1 ..7)211CGIF6Channel x global interrupt clear (x = 1 ..7)201CTEIF5Channel x transfer error clear (x = 1 ..7)191CHTIF5Channel x half transfer clear (x = 1 ..7)181CTCIF5Channel x transfer complete clear (x = 1 ..7)171CGIF5Channel x global interrupt clear (x = 1 ..7)161CTEIF4Channel x transfer error clear (x = 1 ..7)151CHTIF4Channel x half transfer clear (x = 1 ..7)141CTCIF4Channel x transfer complete clear (x = 1 ..7)131CGIF4Channel x global interrupt clear (x = 1 ..7)121CTEIF3Channel x transfer error clear (x = 1 ..7)111CHTIF3Channel x half transfer clear (x = 1 ..7)101CTCIF3Channel x transfer complete clear (x = 1 ..7)91CGIF3Channel x global interrupt clear (x = 1 ..7)81CTEIF2Channel x transfer error clear (x = 1 ..7)71CHTIF2Channel x half transfer clear (x = 1 ..7)61CTCIF2Channel x transfer complete clear (x = 1 ..7)51CGIF2Channel x global interrupt clear (x = 1 ..7)41CTEIF1Channel x transfer error clear (x = 1 ..7)31CHTIF1Channel x half transfer clear (x = 1 ..7)21CTCIF1Channel x transfer complete clear (x = 1 ..7)11CGIF1Channel x global interrupt clear (x = 1 ..7)01CCR1CCR1channel x configuration register0x80x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR1CNDTR1channel x number of data register0xC0x20read-write0x00000000NDTNumber of data to transfer016CPAR1CPAR1channel x peripheral address register0x100x20read-write0x00000000PAPeripheral address032CMAR1CMAR1channel x memory address register0x140x20read-write0x00000000MAMemory address032CCR2CCR2channel x configuration register0x1C0x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR2CNDTR2channel x number of data register0x200x20read-write0x00000000NDTNumber of data to transfer016CPAR2CPAR2channel x peripheral address register0x240x20read-write0x00000000PAPeripheral address032CMAR2CMAR2channel x memory address register0x280x20read-write0x00000000MAMemory address032CCR3CCR3channel x configuration register0x300x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR3CNDTR3channel x number of data register0x340x20read-write0x00000000NDTNumber of data to transfer016CPAR3CPAR3channel x peripheral address register0x380x20read-write0x00000000PAPeripheral address032CMAR3CMAR3channel x memory address register0x3C0x20read-write0x00000000MAMemory address032CCR4CCR4channel x configuration register0x440x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR4CNDTR4channel x number of data register0x480x20read-write0x00000000NDTNumber of data to transfer016CPAR4CPAR4channel x peripheral address register0x4C0x20read-write0x00000000PAPeripheral address032CMAR4CMAR4channel x memory address register0x500x20read-write0x00000000MAMemory address032CCR5CCR5channel x configuration register0x580x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR5CNDTR5channel x number of data register0x5C0x20read-write0x00000000NDTNumber of data to transfer016CPAR5CPAR5channel x peripheral address register0x600x20read-write0x00000000PAPeripheral address032CMAR5CMAR5channel x memory address register0x640x20read-write0x00000000MAMemory address032CCR6CCR6channel x configuration register0x6C0x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR6CNDTR6channel x number of data register0x700x20read-write0x00000000NDTNumber of data to transfer016CPAR6CPAR6channel x peripheral address register0x740x20read-write0x00000000PAPeripheral address032CMAR6CMAR6channel x memory address register0x780x20read-write0x00000000MAMemory address032CCR7CCR7channel x configuration register0x800x20read-write0x00000000MEM2MEMMemory to memory mode141PLChannel priority level122MSIZEMemory size102PSIZEPeripheral size82MINCMemory increment mode71PINCPeripheral increment mode61CIRCCircular mode51DIRData transfer direction41TEIETransfer error interrupt enable31HTIEHalf transfer interrupt enable21TCIETransfer complete interrupt enable11ENChannel enable01CNDTR7CNDTR7channel x number of data register0x840x20read-write0x00000000NDTNumber of data to transfer016CPAR7CPAR7channel x peripheral address register0x880x20read-write0x00000000PAPeripheral address032CMAR7CMAR7channel x memory address register0x8C0x20read-write0x00000000MAMemory address032CSELRCSELRchannel selection register0xA80x20read-write0x00000000C7SDMA channel 7 selection244C6SDMA channel 6 selection204C5SDMA channel 5 selection164C4SDMA channel 4 selection124C3SDMA channel 3 selection84C2SDMA channel 2 selection44C1SDMA channel 1 selection04DMAMUX1Direct memory access MultiplexerDMAMUX0x400208000x00x400registersDMAMUX_OVRDMAMUX overrun interrupt62C0CRC0CRDMA Multiplexer Channel 0 Control register0x00x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C1CRC1CRDMA Multiplexer Channel 1 Control register0x40x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C2CRC2CRDMA Multiplexer Channel 2 Control register0x80x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C3CRC3CRDMA Multiplexer Channel 3 Control register0xC0x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C4CRC4CRDMA Multiplexer Channel 4 Control register0x100x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C5CRC5CRDMA Multiplexer Channel 5 Control register0x140x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C6CRC6CRDMA Multiplexer Channel 6 Control register0x180x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C7CRC7CRDMA Multiplexer Channel 7 Control register0x1C0x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C8CRC8CRDMA Multiplexer Channel 8 Control register0x200x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C9CRC9CRDMA Multiplexer Channel 9 Control register0x240x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C10CRC10CRDMA Multiplexer Channel 10 Control register0x280x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C11CRC11CRDMA Multiplexer Channel 11 Control register0x2C0x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C12CRC12CRDMA Multiplexer Channel 12 Control register0x300x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08C13CRC13CRDMA Multiplexer Channel 13 Control register0x340x20read-write0x00000000SYNC_IDSYNC_ID245NBREQNb request195SPOLSync polarity172SESynchronization enable161EGEEvent Generation Enable91SOIESynchronization Overrun Interrupt Enable81DMAREQ_IDDMA Request ID08CSRCSRDMA Multiplexer Channel Status register0x800x20read-only0x00000000SOF0Synchronization Overrun Flag 001SOF1Synchronization Overrun Flag 111SOF2Synchronization Overrun Flag 221SOF3Synchronization Overrun Flag 331SOF4Synchronization Overrun Flag 441SOF5Synchronization Overrun Flag 551SOF6Synchronization Overrun Flag 661SOF7Synchronization Overrun Flag 771SOF8Synchronization Overrun Flag 881SOF9Synchronization Overrun Flag 991SOF10Synchronization Overrun Flag 10101SOF11Synchronization Overrun Flag 11111SOF12Synchronization Overrun Flag 12121SOF13Synchronization Overrun Flag 13131CFRCFRDMA Channel Clear Flag Register0x840x20write-only0x00000000CSOF0Synchronization Clear Overrun Flag 001CSOF1Synchronization Clear Overrun Flag 111CSOF2Synchronization Clear Overrun Flag 221CSOF3Synchronization Clear Overrun Flag 331CSOF4Synchronization Clear Overrun Flag 441CSOF5Synchronization Clear Overrun Flag 551CSOF6Synchronization Clear Overrun Flag 661CSOF7Synchronization Clear Overrun Flag 771CSOF8Synchronization Clear Overrun Flag 881CSOF9Synchronization Clear Overrun Flag 991CSOF10Synchronization Clear Overrun Flag 10101CSOF11Synchronization Clear Overrun Flag 11111CSOF12Synchronization Clear Overrun Flag 12121CSOF13Synchronization Clear Overrun Flag 13131RG0CRRG0CRDMA Request Generator 0 Control Register0x1000x20read-write0x00000000GNBREQNumber of Request195GPOLGeneration Polarity172GEGeneration Enable161OIEOverrun Interrupt Enable81SIG_IDSignal ID05RG1CRRG1CRDMA Request Generator 1 Control Register0x1040x20read-write0x00000000GNBREQNumber of Request195GPOLGeneration Polarity172GEGeneration Enable161OIEOverrun Interrupt Enable81SIG_IDSignal ID05RG2CRRG2CRDMA Request Generator 2 Control Register0x1080x20read-write0x00000000GNBREQNumber of Request195GPOLGeneration Polarity172GEGeneration Enable161OIEOverrun Interrupt Enable81SIG_IDSignal ID05RG3CRRG3CRDMA Request Generator 3 Control Register0x10C0x20read-write0x00000000GNBREQNumber of Request195GPOLGeneration Polarity172GEGeneration Enable161OIEOverrun Interrupt Enable81SIG_IDSignal ID05RGSRRGSRDMA Request Generator Status Register0x1400x20read-only0x00000000OF0Generator Overrun Flag 001OF1Generator Overrun Flag 111OF2Generator Overrun Flag 221OF3Generator Overrun Flag 331RGCFRRGCFRDMA Request Generator Clear Flag Register0x1440x20write-only0x00000000COF0Clear trigger Overrun Flag 001COF1Clear trigger Overrun Flag 111COF2Clear trigger Overrun Flag 221COF3Clear trigger Overrun Flag 331CRCCyclic redundancy check calculation unitCRC0x400230000x00x400registersDRDRData register0x00x20read-write0xFFFFFFFFDRData register bits032IDRIDRIndependent data register0x40x20read-write0x00000000IDRGeneral-purpose 32-bit data register bits032CRCRControl register0x80x20read-write0x00000000REV_OUTReverse output data71REV_INReverse input data52POLYSIZEPolynomial size32RESETRESET bit01INITINITInitial CRC value0x100x20read-write0xFFFFFFFFCRC_INITProgrammable initial CRC value032POLPOLpolynomial0x140x20read-write0x04C11DB7POLProgrammable polynomial032LCDLiquid crystal display controllerLCD0x400024000x00x400registersLCDLCD global interrupt49CRCRcontrol register0x00x20read-write0x00000000BIASBias selector52DUTYDuty selection23VSELVoltage source selection11LCDENLCD controller enable01MUX_SEGMux segment enable71BUFENVoltage output buffer enable81FCRFCRframe control register0x40x20read-write0x00000000PSPS 16-bit prescaler224DIVDIV clock divider184BLINKBlink mode selection162BLINKFBlink frequency selection133CCContrast control103DEADDead time duration73PONPulse ON duration43UDDIEUpdate display done interrupt enable31SOFIEStart of frame interrupt enable11HDHigh drive enable01SRSRstatus register0x80x200x00000020FCRSFLCD Frame Control Register Synchronization flag51read-onlyRDYReady flag41read-onlyUDDUpdate Display Done31read-onlyUDRUpdate display request21read-writeSOFStart of frame flag11read-onlyENSENS01read-onlyCLRCLRclear register0xC0x20write-only0x00000000UDDCUpdate display done clear31SOFCStart of frame flag clear11RAM_COM0RAM_COM0display memory0x140x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM1RAM_COM1display memory0x1C0x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM2RAM_COM2display memory0x240x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM3RAM_COM3display memory0x2C0x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM4RAM_COM4display memory0x340x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM5RAM_COM5display memory0x3C0x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM6RAM_COM6display memory0x440x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001RAM_COM7RAM_COM7display memory0x4C0x20read-write0x00000000S31S31311S30S30301S29S29291S28S28281S27S27271S26S26261S25S25251S24S24241S23S23231S22S22221S21S21211S20S20201S19S19191S18S18181S17S17171S16S16161S15S15151S14S14141S13S13131S12S12121S11S11111S10S10101S09S0991S08S0881S07S0771S06S0661S05S0551S04S0441S03S0331S02S0221S01S0111S00S0001TSCTouch sensing controllerTSC0x400240000x00x400registersTSCTSC global interrupt39CRCRcontrol register0x00x20read-write0x00000000CTPHCharge transfer pulse high284CTPLCharge transfer pulse low244SSDSpread spectrum deviation177SSESpread spectrum enable161SSPSCSpread spectrum prescaler151PGPSCpulse generator prescaler123MCVMax count value53IODEFI/O Default mode41SYNCPOLSynchronization pin polarity31AMAcquisition mode21STARTStart a new acquisition11TSCETouch sensing controller enable01IERIERinterrupt enable register0x40x20read-write0x00000000MCEIEMax count error interrupt enable11EOAIEEnd of acquisition interrupt enable01ICRICRinterrupt clear register0x80x20read-write0x00000000MCEICMax count error interrupt clear11EOAICEnd of acquisition interrupt clear01ISRISRinterrupt status register0xC0x20read-write0x00000000MCEFMax count error flag11EOAFEnd of acquisition flag01IOHCRIOHCRI/O hysteresis control register0x100x20read-write0xFFFFFFFFG7_IO4G7_IO4271G7_IO3G7_IO3261G7_IO2G7_IO2251G7_IO1G7_IO1241G6_IO4G6_IO4231G6_IO3G6_IO3221G6_IO2G6_IO2211G6_IO1G6_IO1201G5_IO4G5_IO4191G5_IO3G5_IO3181G5_IO2G5_IO2171G5_IO1G5_IO1161G4_IO4G4_IO4151G4_IO3G4_IO3141G4_IO2G4_IO2131G4_IO1G4_IO1121G3_IO4G3_IO4111G3_IO3G3_IO3101G3_IO2G3_IO291G3_IO1G3_IO181G2_IO4G2_IO471G2_IO3G2_IO361G2_IO2G2_IO251G2_IO1G2_IO141G1_IO4G1_IO431G1_IO3G1_IO321G1_IO2G1_IO211G1_IO1G1_IO101IOASCRIOASCRI/O analog switch control register0x180x20read-write0x00000000G7_IO4G7_IO4271G7_IO3G7_IO3261G7_IO2G7_IO2251G7_IO1G7_IO1241G6_IO4G6_IO4231G6_IO3G6_IO3221G6_IO2G6_IO2211G6_IO1G6_IO1201G5_IO4G5_IO4191G5_IO3G5_IO3181G5_IO2G5_IO2171G5_IO1G5_IO1161G4_IO4G4_IO4151G4_IO3G4_IO3141G4_IO2G4_IO2131G4_IO1G4_IO1121G3_IO4G3_IO4111G3_IO3G3_IO3101G3_IO2G3_IO291G3_IO1G3_IO181G2_IO4G2_IO471G2_IO3G2_IO361G2_IO2G2_IO251G2_IO1G2_IO141G1_IO4G1_IO431G1_IO3G1_IO321G1_IO2G1_IO211G1_IO1G1_IO101IOSCRIOSCRI/O sampling control register0x200x20read-write0x00000000G7_IO4G7_IO4271G7_IO3G7_IO3261G7_IO2G7_IO2251G7_IO1G7_IO1241G6_IO4G6_IO4231G6_IO3G6_IO3221G6_IO2G6_IO2211G6_IO1G6_IO1201G5_IO4G5_IO4191G5_IO3G5_IO3181G5_IO2G5_IO2171G5_IO1G5_IO1161G4_IO4G4_IO4151G4_IO3G4_IO3141G4_IO2G4_IO2131G4_IO1G4_IO1121G3_IO4G3_IO4111G3_IO3G3_IO3101G3_IO2G3_IO291G3_IO1G3_IO181G2_IO4G2_IO471G2_IO3G2_IO361G2_IO2G2_IO251G2_IO1G2_IO141G1_IO4G1_IO431G1_IO3G1_IO321G1_IO2G1_IO211G1_IO1G1_IO101IOCCRIOCCRI/O channel control register0x280x20read-write0x00000000G7_IO4G7_IO4271G7_IO3G7_IO3261G7_IO2G7_IO2251G7_IO1G7_IO1241G6_IO4G6_IO4231G6_IO3G6_IO3221G6_IO2G6_IO2211G6_IO1G6_IO1201G5_IO4G5_IO4191G5_IO3G5_IO3181G5_IO2G5_IO2171G5_IO1G5_IO1161G4_IO4G4_IO4151G4_IO3G4_IO3141G4_IO2G4_IO2131G4_IO1G4_IO1121G3_IO4G3_IO4111G3_IO3G3_IO3101G3_IO2G3_IO291G3_IO1G3_IO181G2_IO4G2_IO471G2_IO3G2_IO361G2_IO2G2_IO251G2_IO1G2_IO141G1_IO4G1_IO431G1_IO3G1_IO321G1_IO2G1_IO211G1_IO1G1_IO101IOGCSRIOGCSRI/O group control status register0x300x200x00000000G7SAnalog I/O group x status221read-onlyG6SAnalog I/O group x status211read-onlyG5SAnalog I/O group x status201read-onlyG4SAnalog I/O group x status191read-onlyG3SAnalog I/O group x status181read-onlyG2SAnalog I/O group x status171read-onlyG1SAnalog I/O group x status161read-onlyG7EAnalog I/O group x enable61read-writeG6EAnalog I/O group x enable51read-writeG5EAnalog I/O group x enable41read-writeG4EAnalog I/O group x enable31read-writeG3EAnalog I/O group x enable21read-writeG2EAnalog I/O group x enable11read-writeG1EAnalog I/O group x enable01read-writeIOG1CRIOG1CRI/O group x counter register0x340x20read-only0x00000000CNTCounter value014IOG2CRIOG2CRI/O group x counter register0x380x20read-only0x00000000CNTCounter value014IOG3CRIOG3CRI/O group x counter register0x3C0x20read-only0x00000000CNTCounter value014IOG4CRIOG4CRI/O group x counter register0x400x20read-only0x00000000CNTCounter value014IOG5CRIOG5CRI/O group x counter register0x440x20read-only0x00000000CNTCounter value014IOG6CRIOG6CRI/O group x counter register0x480x20read-only0x00000000CNTCounter value014IOG7CRIOG7CRI/O group x counter register0x4C0x20read-only0x00000000CNTCounter value014IWDGIndependent watchdogIWDG0x400030000x00x400registersKRKRKey register0x00x20write-only0x00000000KEYKey value (write only, read 0x0000)016PRPRPrescaler register0x40x20read-write0x00000000PRPrescaler divider03RLRRLRReload register0x80x20read-write0x00000FFFRLWatchdog counter reload value012SRSRStatus register0xC0x20read-only0x00000000WVUWatchdog counter window value update21RVUWatchdog counter reload value update11PVUWatchdog prescaler value update01WINRWINRWindow register0x100x20read-write0x00000FFFWINWatchdog counter window value012WWDGSystem window watchdogWWDG0x40002C000x00x400registersWWDGWindow Watchdog interrupt0CRCRControl register0x00x20read-write0x0000007FWDGAActivation bit71T7-bit counter (MSB to LSB)07CFRCFRConfiguration register0x40x20read-write0x0000007FWDGTBTimer base113EWIEarly wakeup interrupt91W7-bit window value07SRSRStatus register0x80x20read-write0x00000000EWIFEarly wakeup interrupt flag01I2C1Inter-integrated circuitI2C0x400054000x00x400registersI2C1_EVI2C1 event interrupt30I2C1_ERI2C1 error interrupt31CR1CR1Control register 10x00x20read-write0x00000000PEPeripheral enable01TXIETX Interrupt enable11RXIERX Interrupt enable21ADDRIEAddress match interrupt enable (slave only)31NACKIENot acknowledge received interrupt enable41STOPIESTOP detection Interrupt enable51TCIETransfer Complete interrupt enable61ERRIEError interrupts enable71DNFDigital noise filter84ANFOFFAnalog noise filter OFF121TXDMAENDMA transmission requests enable141RXDMAENDMA reception requests enable151SBCSlave byte control161NOSTRETCHClock stretching disable171WUPENWakeup from STOP enable181GCENGeneral call enable191SMBHENSMBus Host address enable201SMBDENSMBus Device Default address enable211ALERTENSMBUS alert enable221PECENPEC enable231CR2CR2Control register 20x40x20read-write0x00000000PECBYTEPacket error checking byte261AUTOENDAutomatic end mode (master mode)251RELOADNBYTES reload mode241NBYTESNumber of bytes168NACKNACK generation (slave mode)151STOPStop generation (master mode)141STARTStart generation131HEAD10R10-bit address header only read direction (master receiver mode)121ADD1010-bit addressing mode (master mode)111RD_WRNTransfer direction (master mode)101SADDSlave address bit (master mode)010OAR1OAR1Own address register 10x80x20read-write0x00000000OA1Interface address010OA1MODEOwn Address 1 10-bit mode101OA1ENOwn Address 1 enable151OAR2OAR2Own address register 20xC0x20read-write0x00000000OA2Interface address17OA2MSKOwn Address 2 masks83OA2ENOwn Address 2 enable151TIMINGRTIMINGRTiming register0x100x20read-write0x00000000SCLLSCL low period (master mode)08SCLHSCL high period (master mode)88SDADELData hold time164SCLDELData setup time204PRESCTiming prescaler284TIMEOUTRTIMEOUTRStatus register 10x140x20read-write0x00000000TIMEOUTABus timeout A012TIDLEIdle clock timeout detection121TIMOUTENClock timeout enable151TIMEOUTBBus timeout B1612TEXTENExtended clock timeout enable311ISRISRInterrupt and Status register0x180x200x00000001ADDCODEAddress match code (Slave mode)177read-onlyDIRTransfer direction (Slave mode)161read-onlyBUSYBus busy151read-onlyALERTSMBus alert131read-onlyTIMEOUTTimeout or t_low detection flag121read-onlyPECERRPEC Error in reception111read-onlyOVROverrun/Underrun (slave mode)101read-onlyARLOArbitration lost91read-onlyBERRBus error81read-onlyTCRTransfer Complete Reload71read-onlyTCTransfer Complete (master mode)61read-onlySTOPFStop detection flag51read-onlyNACKFNot acknowledge received flag41read-onlyADDRAddress matched (slave mode)31read-onlyRXNEReceive data register not empty (receivers)21read-onlyTXISTransmit interrupt status (transmitters)11read-writeTXETransmit data register empty (transmitters)01read-writeICRICRInterrupt clear register0x1C0x20write-only0x00000000ALERTCFAlert flag clear131TIMOUTCFTimeout detection flag clear121PECCFPEC Error flag clear111OVRCFOverrun/Underrun flag clear101ARLOCFArbitration lost flag clear91BERRCFBus error flag clear81STOPCFStop detection flag clear51NACKCFNot Acknowledge flag clear41ADDRCFAddress Matched flag clear31PECRPECRPEC register0x200x20read-only0x00000000PECPacket error checking register08RXDRRXDRReceive data register0x240x20read-only0x00000000RXDATA8-bit receive data08TXDRTXDRTransmit data register0x280x20read-write0x00000000TXDATA8-bit transmit data08I2C30x40005C00I2C3_EVI2C3 event interrupt32I2C3_ERI2C3 error interrupt33FlashFlashFlash0x580040000x00x90registersFLASHFlash global interrupt4ACRACRAccess control register0x00x20read-write0x00000600LATENCYLatency03PRFTENPrefetch enable81ICENInstruction cache enable91DCENData cache enable101ICRSTInstruction cache reset111DCRSTData cache reset121PESCPU1 CortexM4 program erase suspend request151EMPTYFlash User area empty161KEYRKEYRFlash key register0x80x20write-only0x00000000KEYRKEYR032OPTKEYROPTKEYROption byte key register0xC0x20write-only0x00000000OPTKEYROption byte key032SRSRStatus register0x100x200x00000000EOPEnd of operation01read-writeOPERROperation error11read-writePROGERRProgramming error31read-writeWRPERRWrite protected error41read-writePGAERRProgramming alignment error51read-writeSIZERRSize error61read-writePGSERRProgramming sequence error71read-writeMISERRFast programming data miss error81read-writeFASTERRFast programming error91read-writeOPTNVUser Option OPTVAL indication131read-onlyRDERRPCROP read error141read-writeOPTVERROption validity error151read-writeBSYBusy161read-onlyCFGBSYProgramming or erase configuration busy181read-onlyPESDProgramming or erase operation suspended191read-onlyCRCRFlash control register0x140x20read-write0xC0000000PGProgramming01PERPage erase11MERThis bit triggers the mass erase (all user pages) when set21PNBPage number selection38STRTStart161OPTSTRTOptions modification start171FSTPGFast programming181EOPIEEnd of operation interrupt enable241ERRIEError interrupt enable251RDERRIEPCROP read error interrupt enable261OBL_LAUNCHForce the option byte loading271OPTLOCKOptions Lock301LOCKFLASH_CR Lock311ECCRECCRFlash ECC register0x180x200x00000000ADDR_ECCECC fail address017read-onlySYSF_ECCSystem Flash ECC fail201read-onlyECCCIEECC correction interrupt enable241read-writeCPUIDCPU identification263read-onlyECCCECC correction301read-writeECCDECC detection311read-writeOPTROPTRFlash option register0x200x20read-write0x10708000RDPRead protection level08ESESecurity enabled81BOR_LEVBOR reset Level93nRST_STOPnRST_STOP121nRST_STDBYnRST_STDBY131nRST_SHDWnRST_SHDW141IDWG_SWIndependent watchdog selection161IWDG_STOPIndependent watchdog counter freeze in Stop mode171IWDG_STDBYIndependent watchdog counter freeze in Standby mode181WWDG_SWWindow watchdog selection191nBOOT1Boot configuration231SRAM2_PESRAM2 parity check enable241SRAM2_RSTSRAM2 Erase when system reset251nSWBOOT0Software Boot0261nBOOT0nBoot0 option bit271AGC_TRIMRadio Automatic Gain Control Trimming293PCROP1ASRPCROP1ASRFlash Bank 1 PCROP Start address zone A register0x240x20read-write0xFFFFFE00PCROP1A_STRTBank 1 PCROPQ area start offset09PCROP1AERPCROP1AERFlash Bank 1 PCROP End address zone A register0x280x20read-write0x7FFFFE00PCROP1A_ENDBank 1 PCROP area end offset09PCROP_RDPPCROP area preserved when RDP level decreased311WRP1ARWRP1ARFlash Bank 1 WRP area A address register0x2C0x20read-write0xFF00FF00WRP1A_STRTBank 1 WRP first area A start offset08WRP1A_ENDBank 1 WRP first area A end offset168WRP1BRWRP1BRFlash Bank 1 WRP area B address register0x300x20read-write0xFF00FF00WRP1B_STRTBank 1 WRP second area B end offset168WRP1B_ENDBank 1 WRP second area B start offset08PCROP1BSRPCROP1BSRFlash Bank 1 PCROP Start address area B register0x340x20read-write0xFFFFFE00PCROP1B_STRTBank 1 PCROP area B start offset09PCROP1BERPCROP1BERFlash Bank 1 PCROP End address area B register0x380x20read-write0xFFFFFE00PCROP1B_ENDBank 1 PCROP area end area B offset09IPCCBRIPCCBRIPCC mailbox data buffer address register0x3C0x20read-write0xFFFFC000IPCCDBAPCC mailbox data buffer base address014C2ACRC2ACRCPU2 cortex M0 access control register0x5C0x20read-write0x00000600PRFTENCPU2 cortex M0 prefetch enable81ICENCPU2 cortex M0 instruction cache enable91ICRSTCPU2 cortex M0 instruction cache reset111PESCPU2 cortex M0 program erase suspend request151C2SRC2SRCPU2 cortex M0 status register0x600x20read-write0x00000000EOPEnd of operation01OPERROperation error11PROGERRProgramming error31WRPERRwrite protection error41PGAERRProgramming alignment error51SIZERRSize error61PGSERRProgramming sequence error71MISSERRFast programming data miss error81FASTERRFast programming error91RDERRPCROP read error141BSYBusy161CFGBSYProgramming or erase configuration busy181PESDProgramming or erase operation suspended191C2CRC2CRCPU2 cortex M0 control register0x640x20read-write0x00000000PGProgramming01PERPage erase11MERMasse erase21PNBPage Number selection38STRTStart161FSTPGFast programming181EOPIEEnd of operation interrupt enable241ERRIEError interrupt enable251RDERRIEPCROP read error interrupt enable261SFRSFRSecure flash start address register0x800x20read-write0xFFFFEE00SFSASecure flash start address08DDSDisable Cortex M0 debug access121FSDFlash security disable81SRRVRSRRVRSecure SRAM2 start address and cortex M0 reset vector register0x840x20read-write0x01000000SBRVcortex M0 access control register018SBRSASecure backup SRAM2a start address185BRSDbackup SRAM2a security disable231SNBRSASecure non backup SRAM2a start address255C2OPTCPU2 cortex M0 boot reset vector memory selection311NBRSDnon-backup SRAM2b security disable301QUADSPIQuadSPI interfaceQUADSPI0xA00010000x00x400registersQUADSPIQSPI global interrupt50CRCRcontrol register0x00x20read-write0x00000000PRESCALERClock prescaler248PMMPolling match mode231APMSAutomatic poll mode stop221TOIETimeOut interrupt enable201SMIEStatus match interrupt enable191FTIEFIFO threshold interrupt enable181TCIETransfer complete interrupt enable171TEIETransfer error interrupt enable161FTHRESFIFO threshold level85SSHIFTSample shift41TCENTimeout counter enable31DMAENDMA enable21ABORTAbort request11ENEnable01DCRDCRdevice configuration register0x40x20read-write0x00000000FSIZEFLASH memory size165CSHTChip select high time83CKMODEMode 0 / mode 301SRSRstatus register0x80x20read-only0x00000000FLEVELFIFO level86BUSYBusy51TOFTimeout flag41SMFStatus match flag31FTFFIFO threshold flag21TCFTransfer complete flag11TEFTransfer error flag01FCRFCRflag clear register0xC0x20read-write0x00000000CTOFClear timeout flag41CSMFClear status match flag31CTCFClear transfer complete flag11CTEFClear transfer error flag01DLRDLRdata length register0x100x20read-write0x00000000DLData length032CCRCCRcommunication configuration register0x140x20read-write0x00000000DDRMDouble data rate mode311SIOOSend instruction only once mode281FMODEFunctional mode262DMODEData mode242DCYCNumber of dummy cycles185ABSIZEAlternate bytes size162ABMODEAlternate bytes mode142ADSIZEAddress size122ADMODEAddress mode102IMODEInstruction mode82INSTRUCTIONInstruction08ARARaddress register0x180x20read-write0x00000000ADDRESSAddress032ABRABRABR0x1C0x20read-write0x00000000ALTERNATEALTERNATE032DRDRdata register0x200x20read-write0x00000000DATAData032PSMKRPSMKRpolling status mask register0x240x20read-write0x00000000MASKStatus mask032PSMARPSMARpolling status match register0x280x20read-write0x00000000MATCHStatus match032PIRPIRpolling interval register0x2C0x20read-write0x00000000INTERVALPolling interval016LPTRLPTRlow-power timeout register0x300x20read-write0x00000000TIMEOUTTimeout period016RCCReset and clock controlRCC0x580000000x00x400registersRCCRCC global interrupt5CRCRClock control register0x00x200x00000061PLLSAI1RDYSAI1 PLL clock ready flag271read-onlyPLLSAI1ONSAI1 PLL enable261read-writePLLRDYMain PLL clock ready flag251read-onlyPLLONMain PLL enable241read-writeHSEPREHSE sysclk and PLL M divider prescaler201read-writeCSSONHSE Clock security system enable191write-onlyHSEBYPHSE crystal oscillator bypass181read-writeHSERDYHSE clock ready flag171read-onlyHSEONHSE clock enabled161read-writeHSIKERDYHSI kernel clock ready flag for peripherals requests121read-onlyHSIASFSHSI automatic start from Stop111read-writeHSIRDYHSI clock ready flag101read-onlyHSIKERONHSI always enable for peripheral kernels91read-writeHSIONHSI clock enabled81read-writeMSIRANGEMSI clock ranges44read-writeMSIPLLENMSI clock PLL enable21read-writeMSIRDYMSI clock ready flag11read-onlyMSIONMSI clock enable01read-writeICSCRICSCRInternal clock sources calibration register0x40x200x40000000HSITRIMHSI clock trimming247read-writeHSICALHSI clock calibration168read-onlyMSITRIMMSI clock trimming88read-writeMSICALMSI clock calibration08read-onlyCFGRCFGRClock configuration register0x80x200x00070000MCOPREMicrocontroller clock output prescaler283read-writeMCOSELMicrocontroller clock output244read-writePPRE2FAPB2 prescaler flag181read-onlyPPRE1FAPB1 prescaler flag171read-onlyHPREFAHB prescaler flag161read-onlySTOPWUCKWakeup from Stop and CSS backup clock selection151read-writePPRE2APB high-speed prescaler (APB2)113read-writePPRE1PB low-speed prescaler (APB1)83read-writeHPREAHB prescaler44read-writeSWSSystem clock switch status22read-onlySWSystem clock switch02read-writePLLCFGRPLLCFGRPLLSYS configuration register0xC0x20read-write0x22040100PLLRMain PLLSYS division factor R for SYSCLK (system clock)293PLLRENMain PLLSYSR PLLCLK output enable281PLLQMain PLLSYS division factor Q for PLLSYSUSBCLK253PLLQENMain PLLSYSQ output enable241PLLPMain PLL division factor P for PPLSYSSAICLK175PLLPENMain PLLSYSP output enable161PLLNMain PLLSYS multiplication factor N87PLLMDivision factor M for the main PLL and audio PLL (PLLSAI1 and PLLSAI2) input clock43PLLSRCMain PLL, PLLSAI1 and PLLSAI2 entry clock source02PLLSAI1CFGRPLLSAI1CFGRPLLSAI1 configuration register0x100x20read-write0x22040100PLLRPLLSAI division factor R for PLLADC1CLK (ADC clock)293PLLRENPLLSAI PLLADC1CLK output enable281PLLQSAIPLL division factor Q for PLLSAIUSBCLK (48 MHz clock)253PLLQENSAIPLL PLLSAIUSBCLK output enable241PLLPSAI1PLL division factor P for PLLSAICLK (SAI1clock)175PLLPENSAIPLL PLLSAI1CLK output enable161PLLNSAIPLL multiplication factor for VCO87CIERCIERClock interrupt enable register0x180x20read-write0x00000000LSI2RDYIELSI2 ready interrupt enable111HSI48RDYIEHSI48 ready interrupt enable101LSECSSIELSE clock security system interrupt enable91PLLSAI1RDYIEPLLSAI1 ready interrupt enable61PLLRDYIEPLLSYS ready interrupt enable51HSERDYIEHSE ready interrupt enable41HSIRDYIEHSI ready interrupt enable31MSIRDYIEMSI ready interrupt enable21LSERDYIELSE ready interrupt enable11LSI1RDYIELSI1 ready interrupt enable01CIFRCIFRClock interrupt flag register0x1C0x20read-only0x00000000LSI2RDYFLSI2 ready interrupt flag111HSI48RDYFHSI48 ready interrupt flag101LSECSSFLSE Clock security system interrupt flag91HSECSSFHSE Clock security system interrupt flag81PLLSAI1RDYFPLLSAI1 ready interrupt flag61PLLRDYFPLL ready interrupt flag51HSERDYFHSE ready interrupt flag41HSIRDYFHSI ready interrupt flag31MSIRDYFMSI ready interrupt flag21LSERDYFLSE ready interrupt flag11LSI1RDYFLSI1 ready interrupt flag01CICRCICRClock interrupt clear register0x200x20write-only0x00000000LSI2RDYCLSI2 ready interrupt clear111HSI48RDYCHSI48 ready interrupt clear101LSECSSCLSE Clock security system interrupt clear91HSECSSCHSE Clock security system interrupt clear81PLLSAI1RDYCPLLSAI1 ready interrupt clear61PLLRDYCPLL ready interrupt clear51HSERDYCHSE ready interrupt clear41HSIRDYCHSI ready interrupt clear31MSIRDYCMSI ready interrupt clear21LSERDYCLSE ready interrupt clear11LSI1RDYCLSI1 ready interrupt clear01SMPSCRSMPSCRStep Down converter control register0x240x200x00000301SMPSSWSStep Down converter clock switch status82read-onlySMPSDIVStep Down converter clock prescaler42read-writeSMPSSELStep Down converter clock selection02read-writeAHB1RSTRAHB1RSTRAHB1 peripheral reset register0x280x20read-write0x00000000TSCRSTTouch Sensing Controller reset161CRCRSTCRC reset121DMAMUXRSTDMAMUX reset21DMA2RSTDMA2 reset11DMA1RSTDMA1 reset01AHB2RSTRAHB2RSTRAHB2 peripheral reset register0x2C0x20read-write0x00000000AES1RSTAES1 hardware accelerator reset161ADCRSTADC reset131GPIOHRSTIO port H reset71GPIOERSTIO port E reset41GPIODRSTIO port D reset31GPIOCRSTIO port C reset21GPIOBRSTIO port B reset11GPIOARSTIO port A reset01AHB3RSTRAHB3RSTRAHB3 peripheral reset register0x300x20read-write0x00000000FLASHRSTFlash interface reset251IPCCRSTIPCC interface reset201HSEMRSTHSEM interface reset191RNGRSTRNG interface reset181AES2RSTAES2 interface reset171PKARSTPKA interface reset161QSPIRSTQuad SPI memory interface reset81APB1RSTR1APB1RSTR1APB1 peripheral reset register 10x380x20read-write0x00000000LPTIM1RSTLow Power Timer 1 reset311USBFSRSTUSB FS reset261CRSRSTCRS reset241I2C3RSTI2C3 reset231I2C1RSTI2C1 reset211SPI2RSTSPI2 reset141LCDRSTLCD interface reset91TIM2RSTTIM2 timer reset01APB1RSTR2APB1RSTR2APB1 peripheral reset register 20x3C0x20read-write0x00000000LPTIM2RSTLow-power timer 2 reset51LPUART1RSTLow-power UART 1 reset01APB2RSTRAPB2RSTRAPB2 peripheral reset register0x400x20read-write0x00000000SAI1RSTSerial audio interface 1 (SAI1) reset211TIM17RSTTIM17 timer reset181TIM16RSTTIM16 timer reset171USART1RSTUSART1 reset141SPI1RSTSPI1 reset121TIM1RSTTIM1 timer reset111APB3RSTRAPB3RSTRAPB3 peripheral reset register0x440x20read-write0x00000000RFRSTRadio system BLE reset01AHB1ENRAHB1ENRAHB1 peripheral clock enable register0x480x20read-write0x00000100TSCENTouch Sensing Controller clock enable161CRCENCPU1 CRC clock enable121DMAMUXENDMAMUX clock enable21DMA2ENDMA2 clock enable11DMA1ENDMA1 clock enable01AHB2ENRAHB2ENRAHB2 peripheral clock enable register0x4C0x20read-write0x00000000AES1ENAES1 accelerator clock enable161ADCENADC clock enable131GPIOHENIO port H clock enable71GPIOEENIO port E clock enable41GPIODENIO port D clock enable31GPIOCENIO port C clock enable21GPIOBENIO port B clock enable11GPIOAENIO port A clock enable01AHB3ENRAHB3ENRAHB3 peripheral clock enable register0x500x20read-write0x02080000FLASHENFLASHEN251IPCCENIPCCEN201HSEMENHSEMEN191RNGENRNGEN181AES2ENAES2EN171PKAENPKAEN161QSPIENQSPIEN81APB1ENR1APB1ENR1APB1ENR10x580x20read-write0x00000400LPTIM1ENCPU1 Low power timer 1 clock enable311USBENCPU1 USB clock enable261CRSENCPU1 CRS clock enable241I2C3ENCPU1 I2C3 clock enable231I2C1ENCPU1 I2C1 clock enable211SPI2ENCPU1 SPI2 clock enable141WWDGENCPU1 Window watchdog clock enable111RTCAPBENCPU1 RTC APB clock enable101LCDENCPU1 LCD clock enable91TIM2ENCPU1 TIM2 timer clock enable01APB1ENR2APB1ENR2APB1 peripheral clock enable register 20x5C0x20read-write0x00000000LPTIM2ENCPU1 LPTIM2EN51LPUART1ENCPU1 Low power UART 1 clock enable01APB2ENRAPB2ENRAPB2ENR0x600x20read-write0x00000000SAI1ENCPU1 SAI1 clock enable211TIM17ENCPU1 TIM17 timer clock enable181TIM16ENCPU1 TIM16 timer clock enable171USART1ENCPU1 USART1clock enable141SPI1ENCPU1 SPI1 clock enable121TIM1ENCPU1 TIM1 timer clock enable111AHB1SMENRAHB1SMENRAHB1 peripheral clocks enable in Sleep and Stop modes register0x680x20read-write0x00011207TSCSMENCPU1 Touch Sensing Controller clocks enable during Sleep and Stop modes161CRCSMENCPU1 CRCSMEN121SRAM1SMENCPU1 SRAM1 interface clocks enable during Sleep and Stop modes91DMAMUXSMENCPU1 DMAMUX clocks enable during Sleep and Stop modes21DMA2SMENCPU1 DMA2 clocks enable during Sleep and Stop modes11DMA1SMENCPU1 DMA1 clocks enable during Sleep and Stop modes01AHB2SMENRAHB2SMENRAHB2 peripheral clocks enable in Sleep and Stop modes register0x6C0x20read-write0x0001209FAES1SMENCPU1 AES1 accelerator clocks enable during Sleep and Stop modes161ADCFSSMENCPU1 ADC clocks enable during Sleep and Stop modes131GPIOHSMENCPU1 IO port H clocks enable during Sleep and Stop modes71GPIOESMENCPU1 IO port E clocks enable during Sleep and Stop modes41GPIODSMENCPU1 IO port D clocks enable during Sleep and Stop modes31GPIOCSMENCPU1 IO port C clocks enable during Sleep and Stop modes21GPIOBSMENCPU1 IO port B clocks enable during Sleep and Stop modes11GPIOASMENCPU1 IO port A clocks enable during Sleep and Stop modes01AHB3SMENRAHB3SMENRAHB3 peripheral clocks enable in Sleep and Stop modes register0x700x20read-write0x03070100FLASHSMENFlash interface clocks enable during CPU1 sleep mode251SRAM2SMENSRAM2a and SRAM2b memory interface clocks enable during CPU1 sleep mode241RNGSMENTrue RNG clocks enable during CPU1 sleep mode181AES2SMENAES2 accelerator clocks enable during CPU1 sleep mode171PKASMENPKA accelerator clocks enable during CPU1 sleep mode161QSPISMENQSPISMEN81APB1SMENR1APB1SMENR1APB1SMENR10x780x20read-write0x85A04E01LPTIM1SMENLow power timer 1 clocks enable during CPU1 Sleep mode311USBSMENUSB FS clocks enable during CPU1 Sleep mode261CRSMENCRS clocks enable during CPU1 Sleep mode241I2C3SMENI2C3 clocks enable during CPU1 Sleep mode231I2C1SMENI2C1 clocks enable during CPU1 Sleep mode211SPI2SMENSPI2 clocks enable during CPU1 Sleep mode141WWDGSMENWindow watchdog clocks enable during CPU1 Sleep mode111RTCAPBSMENRTC APB clocks enable during CPU1 Sleep mode101LCDSMENLCD clocks enable during CPU1 Sleep mode91TIM2SMENTIM2 timer clocks enable during CPU1 Sleep mode01APB1SMENR2APB1SMENR2APB1 peripheral clocks enable in Sleep and Stop modes register 20x7C0x20read-write0x000000021LPTIM2SMENLow power timer 2 clocks enable during CPU1 Sleep mode51LPUART1SMENLow power UART 1 clocks enable during CPU1 Sleep mode01APB2SMENRAPB2SMENRAPB2SMENR0x800x20read-write0x00265800SAI1SMENSAI1 clocks enable during CPU1 Sleep mode211TIM17SMENTIM17 timer clocks enable during CPU1 Sleep mode181TIM16SMENTIM16 timer clocks enable during CPU1 Sleep mode171USART1SMENUSART1clocks enable during CPU1 Sleep mode141SPI1SMENSPI1 clocks enable during CPU1 Sleep mode121TIM1SMENTIM1 timer clocks enable during CPU1 Sleep mode111CCIPRCCIPRCCIPR0x880x20read-write0x00000000RNGSELRNG clock source selection302ADCSELADCs clock source selection282CLK48SEL48 MHz clock source selection262SAI1SELSAI1 clock source selection222LPTIM2SELLow power timer 2 clock source selection202LPTIM1SELLow power timer 1 clock source selection182I2C3SELI2C3 clock source selection162I2C1SELI2C1 clock source selection122LPUART1SELLPUART1 clock source selection102USART1SELUSART1 clock source selection02BDCRBDCRBDCR0x900x200x00000000LSCOSELLow speed clock output selection251read-writeLSCOENLow speed clock output enable241read-writeBDRSTBackup domain software reset161read-writeRTCENRTC clock enable151read-writeRTCSELRTC clock source selection82read-writeLSECSSD_CSS on LSE failure detection61read-onlyLSECSSONLSECSSON51read-writeLSEDRVSE oscillator drive capability32read-writeLSEBYPLSE oscillator bypass21read-writeLSERDYLSE oscillator ready11read-onlyLSEONLSE oscillator enable01read-writeCSRCSRCSR0x940x200x0C000000LPWRRSTFLow-power reset flag311read-onlyWWDGRSTFWindow watchdog reset flag301read-onlyIWDGRSTFIndependent window watchdog reset flag291read-onlySFTRSTFSoftware reset flag281read-onlyBORRSTFBOR flag271read-onlyPINRSTFPin reset flag261read-onlyOBLRSTFOption byte loader reset flag251read-onlyRMVFRemove reset flag231read-writeRFWKPSELRF system wakeup clock source selection142read-writeLSI2BWLSI2 oscillator bias configuration84read-writeLSI2TRIMOKLSI2 oscillator trim OK51read-onlyLSI2TRIMENLSI2 oscillator trimming enable41read-writeLSI2RDYLSI2 oscillator ready31read-onlyLSI2ONLSI2 oscillator enabled21read-writeLSI1RDYLSI1 oscillator ready11read-onlyLSI1ONLSI1 oscillator enabled01read-writeRFRSTSRadio system BLE and 802.15.4 reset status161read-onlyCRRCRCRRCRClock recovery RC register0x980x200x00000000HSI48CALHSI48 clock calibration79read-onlyHSI48RDYHSI48 clock ready11read-onlyHSI48ONHSI48 oscillator enabled01read-writeHSECRHSECRClock HSE register0x9C0x200x00000030HSETUNEHSE capacitor tuning86read-onlyHSEGMCHSE current control43read-writeHSESHSE Sense amplifier threshold31read-writeUNLOCKEDRegister lock system01read-writeEXTCFGREXTCFGRExtended clock recovery register0x1080x200x00030000RFCSSRF clock source selected201read-onlyC2HPREFCPU2 AHB prescaler flag171read-onlySHDHPREFShared AHB prescaler flag161read-onlyC2HPRECPU2 AHB prescaler44read-writeSHDHPREShared AHB prescaler04read-writeC2AHB1ENRC2AHB1ENRCPU2 AHB1 peripheral clock enable register0x1480x20read-write0x00000000TSCENCPU2 Touch Sensing Controller clock enable161CRCENCPU2 CRC clock enable121SRAM1ENCPU2 SRAM1 clock enable91DMAMUXENCPU2 DMAMUX clock enable21DMA2ENCPU2 DMA2 clock enable11DMA1ENCPU2 DMA1 clock enable01C2AHB2ENRC2AHB2ENRCPU2 AHB2 peripheral clock enable register0x14C0x20read-write0x00000000AES1ENCPU2 AES1 accelerator clock enable161ADCENCPU2 ADC clock enable131GPIOHENCPU2 IO port H clock enable71GPIOEENCPU2 IO port E clock enable41GPIODENCPU2 IO port D clock enable31GPIOCENCPU2 IO port C clock enable21GPIOBENCPU2 IO port B clock enable11GPIOAENCPU2 IO port A clock enable01C2AHB3ENRC2AHB3ENRCPU2 AHB3 peripheral clock enable register0x1500x20read-write0x02080000FLASHENCPU2 FLASHEN251IPCCENCPU2 IPCCEN201HSEMENCPU2 HSEMEN191RNGENCPU2 RNGEN181AES2ENCPU2 AES2EN171PKAENCPU2 PKAEN161C2APB1ENR1C2APB1ENR1CPU2 APB1ENR10x1580x20read-write0x00000400LPTIM1ENCPU2 Low power timer 1 clock enable311USBENCPU2 USB clock enable261CRSENCPU2 CRS clock enable241I2C3ENCPU2 I2C3 clock enable231I2C1ENCPU2 I2C1 clock enable211SPI2ENCPU2 SPI2 clock enable141RTCAPBENCPU2 RTC APB clock enable101LCDENCPU2 LCD clock enable91TIM2ENCPU2 TIM2 timer clock enable01C2APB1ENR2C2APB1ENR2CPU2 APB1 peripheral clock enable register 20x15C0x20read-write0x00000000LPTIM2ENCPU2 LPTIM2EN51LPUART1ENCPU2 Low power UART 1 clock enable01C2APB2ENRC2APB2ENRCPU2 APB2ENR0x1600x20read-write0x00000000SAI1ENCPU2 SAI1 clock enable211TIM17ENCPU2 TIM17 timer clock enable181TIM16ENCPU2 TIM16 timer clock enable171USART1ENCPU2 USART1clock enable141SPI1ENCPU2 SPI1 clock enable121TIM1ENCPU2 TIM1 timer clock enable111C2APB3ENRC2APB3ENRCPU2 APB3ENR0x1640x20read-write0x00000000EN802CPU2 802.15.4 interface clock enable11BLEENCPU2 BLE interface clock enable01C2AHB1SMENRC2AHB1SMENRCPU2 AHB1 peripheral clocks enable in Sleep and Stop modes register0x1680x20read-write0x00011207TSCSMENCPU2 Touch Sensing Controller clocks enable during Sleep and Stop modes161CRCSMENCPU2 CRCSMEN121SRAM1SMENSRAM1 interface clock enable during CPU1 CSleep mode91DMAMUXSMENCPU2 DMAMUX clocks enable during Sleep and Stop modes21DMA2SMENCPU2 DMA2 clocks enable during Sleep and Stop modes11DMA1SMENCPU2 DMA1 clocks enable during Sleep and Stop modes01C2AHB2SMENRC2AHB2SMENRCPU2 AHB2 peripheral clocks enable in Sleep and Stop modes register0x16C0x20read-write0x0001209FAES1SMENCPU2 AES1 accelerator clocks enable during Sleep and Stop modes161ADCFSSMENCPU2 ADC clocks enable during Sleep and Stop modes131GPIOHSMENCPU2 IO port H clocks enable during Sleep and Stop modes71GPIOESMENCPU2 IO port E clocks enable during Sleep and Stop modes41GPIODSMENCPU2 IO port D clocks enable during Sleep and Stop modes31GPIOCSMENCPU2 IO port C clocks enable during Sleep and Stop modes21GPIOBSMENCPU2 IO port B clocks enable during Sleep and Stop modes11GPIOASMENCPU2 IO port A clocks enable during Sleep and Stop modes01C2AHB3SMENRC2AHB3SMENRCPU2 AHB3 peripheral clocks enable in Sleep and Stop modes register0x1700x20read-write0x03070000FLASHSMENFlash interface clocks enable during CPU2 sleep modes251SRAM2SMENSRAM2a and SRAM2b memory interface clocks enable during CPU2 sleep modes241RNGSMENTrue RNG clocks enable during CPU2 sleep modes181AES2SMENAES2 accelerator clocks enable during CPU2 sleep modes171PKASMENPKA accelerator clocks enable during CPU2 sleep modes161C2APB1SMENR1C2APB1SMENR1CPU2 APB1SMENR10x1780x20read-write0x85A04601LPTIM1SMENLow power timer 1 clocks enable during CPU2 Sleep mode311USBSMENUSB FS clocks enable during CPU2 Sleep mode261CRSMENCRS clocks enable during CPU2 Sleep mode241I2C3SMENI2C3 clocks enable during CPU2 Sleep mode231I2C1SMENI2C1 clocks enable during CPU2 Sleep mode211SPI2SMENSPI2 clocks enable during CPU2 Sleep mode141RTCAPBSMENRTC APB clocks enable during CPU2 Sleep mode101LCDSMENLCD clocks enable during CPU2 Sleep mode91TIM2SMENTIM2 timer clocks enable during CPU2 Sleep mode01C2APB1SMENR2C2APB1SMENR2CPU2 APB1 peripheral clocks enable in Sleep and Stop modes register 20x17C0x20read-write0x000000021LPTIM2SMENLow power timer 2 clocks enable during CPU2 Sleep mode51LPUART1SMENLow power UART 1 clocks enable during CPU2 Sleep mode01C2APB2SMENRC2APB2SMENRCPU2 APB2SMENR0x1800x20read-write0x00265800SAI1SMENSAI1 clocks enable during CPU2 Sleep mode211TIM17SMENTIM17 timer clocks enable during CPU2 Sleep mode181TIM16SMENTIM16 timer clocks enable during CPU2 Sleep mode171USART1SMENUSART1clocks enable during CPU2 Sleep mode141SPI1SMENSPI1 clocks enable during CPU2 Sleep mode121TIM1SMENTIM1 timer clocks enable during CPU2 Sleep mode111C2APB3SMENRC2APB3SMENRCPU2 APB3SMENR0x1840x20read-write0x0000003SMEN802802.15.4 interface clocks enable during CPU2 Sleep modes11BLESMENBLE interface clocks enable during CPU2 Sleep mode01PWRPower controlPWR0x580004000x00x400registersPWR_SOTFPWR switching on the fly + interrupt43CR1CR1Power control register 10x00x20read-write0x00000200LPRLow-power run141VOSVoltage scaling range selection92DBPDisable backup domain write protection81FPDSFlash power down mode during LPsSleep for CPU151FPDRFlash power down mode during LPRun for CPU141LPMSLow-power mode selection for CPU103CR2CR2Power control register 20x40x20read-write0x00000000USVVDDUSB USB supply valid101PVME3Peripheral voltage monitoring 3 enable: VDDA vs. 1.62V61PVME1Peripheral voltage monitoring 1 enable: VDDUSB vs. 1.2V41PLSPower voltage detector level selection13PVDEPower voltage detector enable01CR3CR3Power control register 30x80x20read-write0x00008000EIWULEnable internal wakeup line for CPU1151EC2HEnable CPU2 Hold interrupt for CPU1141E802AEnable end of activity interrupt for CPU1131EBLEAEnable BLE end of activity interrupt for CPU1111ECRPEEnable critical radio phase end of activity interrupt for CPU1121APCApply pull-up and pull-down configuration101RRSSRAM2a retention in Standby mode91EBORHSDFBEnable BORH and Step Down counverter forced in Bypass interrups for CPU181EWUP5Enable Wakeup pin WKUP541EWUP4Enable Wakeup pin WKUP431EWUP3Enable Wakeup pin WKUP321EWUP2Enable Wakeup pin WKUP211EWUP1Enable Wakeup pin WKUP101CR4CR4Power control register 40xC0x20read-write0x00000000C2BOOTBOOT CPU2 after reset or wakeup from Stop or Standby modes151VBRSVBAT battery charging resistor selection91VBEVBAT battery charging enable81WP5Wakeup pin WKUP5 polarity41WP4Wakeup pin WKUP4 polarity31WP3Wakeup pin WKUP3 polarity21WP2Wakeup pin WKUP2 polarity11WP1Wakeup pin WKUP1 polarity01SR1SR1Power status register 10x100x20read-only0x00000000WUFIInternal Wakeup interrupt flag151C2HFCPU2 Hold interrupt flag141AF802802.15.4 end of activity interrupt flag131BLEAFBLE end of activity interrupt flag121CRPEFEnable critical radio phase end of activity interrupt flag111WUF802802.15.4 wakeup interrupt flag101BLEWUFBLE wakeup interrupt flag91BORHFBORH interrupt flag81SDFBFStep Down converter forced in Bypass interrupt flag71CWUF5Wakeup flag 541CWUF4Wakeup flag 431CWUF3Wakeup flag 321CWUF2Wakeup flag 211CWUF1Wakeup flag 101SR2SR2Power status register 20x140x20read-only0x00000002PVMO3Peripheral voltage monitoring output: VDDA vs. 1.62 V141PVMO1Peripheral voltage monitoring output: VDDUSB vs. 1.2 V121PVDOPower voltage detector output111VOSFVoltage scaling flag101REGLPFLow-power regulator flag91REGLPSLow-power regulator started81SDSMPSFStep Down converter SMPS mode flag11SDBFStep Down converter Bypass mode flag01SCRSCRPower status clear register0x180x20write-only0x00000000CC2HFClear CPU2 Hold interrupt flag141C802AFClear 802.15.4 end of activity interrupt flag131CBLEAFClear BLE end of activity interrupt flag121CCRPEFClear critical radio phase end of activity interrupt flag111C802WUFClear 802.15.4 wakeup interrupt flag101CBLEWUFClear BLE wakeup interrupt flag91CBORHFClear BORH interrupt flag81CSMPSFBFClear SMPS Step Down converter forced in Bypass interrupt flag71CWUF5Clear wakeup flag 541CWUF4Clear wakeup flag 431CWUF3Clear wakeup flag 321CWUF2Clear wakeup flag 211CWUF1Clear wakeup flag 101CR5CR5Power control register 50x1C0x20read-write0x00004270SDEBEnable Step Down converter SMPS mode enabled151SDBENEnable Step Down converter Bypass mode enabled141SMPSCFGVOS configuration selection (non user)91BORHCBORH configuration selection81SDSCStep Down converter supplt startup current selection43SDVOSStep Down converter voltage output scaling04PUCRAPUCRAPower Port A pull-up control register0x200x20read-write0x00000000PU15Port A pull-up bit y (y=0..15)151PU13Port A pull-up bit y (y=0..15)131PU12Port A pull-up bit y (y=0..15)121PU11Port A pull-up bit y (y=0..15)111PU10Port A pull-up bit y (y=0..15)101PU9Port A pull-up bit y (y=0..15)91PU8Port A pull-up bit y (y=0..15)81PU7Port A pull-up bit y (y=0..15)71PU6Port A pull-up bit y (y=0..15)61PU5Port A pull-up bit y (y=0..15)51PU4Port A pull-up bit y (y=0..15)41PU3Port A pull-up bit y (y=0..15)31PU2Port A pull-up bit y (y=0..15)21PU1Port A pull-up bit y (y=0..15)11PU0Port A pull-up bit y (y=0..15)01PDCRAPDCRAPower Port A pull-down control register0x240x20read-write0x00000000PD14Port A pull-down bit y (y=0..15)141PD12Port A pull-down bit y (y=0..15)121PD11Port A pull-down bit y (y=0..15)111PD10Port A pull-down bit y (y=0..15)101PD9Port A pull-down bit y (y=0..15)91PD8Port A pull-down bit y (y=0..15)81PD7Port A pull-down bit y (y=0..15)71PD6Port A pull-down bit y (y=0..15)61PD5Port A pull-down bit y (y=0..15)51PD4Port A pull-down bit y (y=0..15)41PD3Port A pull-down bit y (y=0..15)31PD2Port A pull-down bit y (y=0..15)21PD1Port A pull-down bit y (y=0..15)11PD0Port A pull-down bit y (y=0..15)01PUCRBPUCRBPower Port B pull-up control register0x280x20read-write0x00000000PU15Port B pull-up bit y (y=0..15)151PU14Port B pull-up bit y (y=0..15)141PU13Port B pull-up bit y (y=0..15)131PU12Port B pull-up bit y (y=0..15)121PU11Port B pull-up bit y (y=0..15)111PU10Port B pull-up bit y (y=0..15)101PU9Port B pull-up bit y (y=0..15)91PU8Port B pull-up bit y (y=0..15)81PU7Port B pull-up bit y (y=0..15)71PU6Port B pull-up bit y (y=0..15)61PU5Port B pull-up bit y (y=0..15)51PU4Port B pull-up bit y (y=0..15)41PU3Port B pull-up bit y (y=0..15)31PU2Port B pull-up bit y (y=0..15)21PU1Port B pull-up bit y (y=0..15)11PU0Port B pull-up bit y (y=0..15)01PDCRBPDCRBPower Port B pull-down control register0x2C0x20read-write0x00000000PD15Port B pull-down bit y (y=0..15)151PD14Port B pull-down bit y (y=0..15)141PD13Port B pull-down bit y (y=0..15)131PD12Port B pull-down bit y (y=0..15)121PD11Port B pull-down bit y (y=0..15)111PD10Port B pull-down bit y (y=0..15)101PD9Port B pull-down bit y (y=0..15)91PD8Port B pull-down bit y (y=0..15)81PD7Port B pull-down bit y (y=0..15)71PD6Port B pull-down bit y (y=0..15)61PD5Port B pull-down bit y (y=0..15)51PD3Port B pull-down bit y (y=0..15)31PD2Port B pull-down bit y (y=0..15)21PD1Port B pull-down bit y (y=0..15)11PD0Port B pull-down bit y (y=0..15)01PUCRCPUCRCPower Port C pull-up control register0x300x20read-write0x00000000PU15Port C pull-up bit y (y=0..15)151PU14Port C pull-up bit y (y=0..15)141PU13Port C pull-up bit y (y=0..15)131PU12Port C pull-up bit y (y=0..15)121PU11Port C pull-up bit y (y=0..15)111PU10Port C pull-up bit y (y=0..15)101PU9Port C pull-up bit y (y=0..15)91PU8Port C pull-up bit y (y=0..15)81PU7Port C pull-up bit y (y=0..15)71PU6Port C pull-up bit y (y=0..15)61PU5Port C pull-up bit y (y=0..15)51PU4Port C pull-up bit y (y=0..15)41PU3Port C pull-up bit y (y=0..15)31PU2Port C pull-up bit y (y=0..15)21PU1Port C pull-up bit y (y=0..15)11PU0Port C pull-up bit y (y=0..15)01PDCRCPDCRCPower Port C pull-down control register0x340x20read-write0x00000000PD15Port C pull-down bit y (y=0..15)151PD14Port C pull-down bit y (y=0..15)141PD13Port C pull-down bit y (y=0..15)131PD12Port C pull-down bit y (y=0..15)121PD11Port C pull-down bit y (y=0..15)111PD10Port C pull-down bit y (y=0..15)101PD9Port C pull-down bit y (y=0..15)91PD8Port C pull-down bit y (y=0..15)81PD7Port C pull-down bit y (y=0..15)71PD6Port C pull-down bit y (y=0..15)61PD5Port C pull-down bit y (y=0..15)51PD4Port C pull-down bit y (y=0..15)41PD3Port C pull-down bit y (y=0..15)31PD2Port C pull-down bit y (y=0..15)21PD1Port C pull-down bit y (y=0..15)11PD0Port C pull-down bit y (y=0..15)01PUCRDPUCRDPower Port D pull-up control register0x380x20read-write0x00000000PU15Port D pull-up bit y (y=0..15)151PU14Port D pull-up bit y (y=0..15)141PU13Port D pull-up bit y (y=0..15)131PU12Port D pull-up bit y (y=0..15)121PU11Port D pull-up bit y (y=0..15)111PU10Port D pull-up bit y (y=0..15)101PU9Port D pull-up bit y (y=0..15)91PU8Port D pull-up bit y (y=0..15)81PU7Port D pull-up bit y (y=0..15)71PU6Port D pull-up bit y (y=0..15)61PU5Port D pull-up bit y (y=0..15)51PU4Port D pull-up bit y (y=0..15)41PU3Port D pull-up bit y (y=0..15)31PU2Port D pull-up bit y (y=0..15)21PU1Port D pull-up bit y (y=0..15)11PU0Port D pull-up bit y (y=0..15)01PDCRDPDCRDPower Port D pull-down control register0x3C0x20read-write0x00000000PD15Port D pull-down bit y (y=0..15)151PD14Port D pull-down bit y (y=0..15)141PD13Port D pull-down bit y (y=0..15)131PD12Port D pull-down bit y (y=0..15)121PD11Port D pull-down bit y (y=0..15)111PD10Port D pull-down bit y (y=0..15)101PD9Port D pull-down bit y (y=0..15)91PD8Port D pull-down bit y (y=0..15)81PD7Port D pull-down bit y (y=0..15)71PD6Port D pull-down bit y (y=0..15)61PD5Port D pull-down bit y (y=0..15)51PD4Port D pull-down bit y (y=0..15)41PD3Port D pull-down bit y (y=0..15)31PD2Port D pull-down bit y (y=0..15)21PD1Port D pull-down bit y (y=0..15)11PD0Port D pull-down bit y (y=0..15)01PUCREPUCREPower Port E pull-up control register0x400x20read-write0x00000000PU4Port E pull-up bit y (y=0..15)41PU3Port E pull-up bit y (y=0..15)31PU2Port E pull-up bit y (y=0..15)21PU1Port E pull-up bit y (y=0..15)11PU0Port E pull-up bit y (y=0..15)01PDCREPDCREPower Port E pull-down control register0x440x20read-write0x00000000PD4Port E pull-down bit y (y=0..15)41PD3Port E pull-down bit y (y=0..15)31PD2Port E pull-down bit y (y=0..15)21PD1Port E pull-down bit y (y=0..15)11PD0Port E pull-down bit y (y=0..15)01PUCRHPUCRHPower Port H pull-up control register0x580x20read-write0x00000000PU3Port H pull-up bit y (y=0..1)31PU1Port H pull-up bit y (y=0..1)11PU0Port H pull-up bit y (y=0..1)01PDCRHPDCRHPower Port H pull-down control register0x5C0x20read-write0x00000000PD3Port H pull-down bit y (y=0..1)31PD1Port H pull-down bit y (y=0..1)11PD0Port H pull-down bit y (y=0..1)01C2CR1C2CR1CPU2 Power control register 10x800x20read-write0x00000000EWKUP802802.15.4 external wakeup signal151BLEEWKUPBLE external wakeup signal141FPDSFlash power down mode during LPSleep for CPU251FPDRFlash power down mode during LPRun for CPU241LPMSLow-power mode selection for CPU203C2CR3C2CR3CPU2 Power control register 30x840x20read-write0X00008000EIWULEnable internal wakeup line for CPU2151APCApply pull-up and pull-down configuration for CPU2121E802WUPEnable 802.15.4 host wakeup interrupt for CPU2101EBLEWUPEnable BLE host wakeup interrupt for CPU291EWUP5Enable Wakeup pin WKUP5 for CPU241EWUP4Enable Wakeup pin WKUP4 for CPU231EWUP3Enable Wakeup pin WKUP3 for CPU221EWUP2Enable Wakeup pin WKUP2 for CPU211EWUP1Enable Wakeup pin WKUP1 for CPU201EXTSCREXTSCRPower status clear register0x880x200x00000000C2DSCPU2 deepsleep mode151read-onlyC1DSCPU1 deepsleep mode141read-onlyCRPFCritical Radio system phase131read-onlyC2STOPFSystem Stop flag for CPU2111read-onlyC2SBFSystem Standby flag for CPU2101read-onlyC1STOPFSystem Stop flag for CPU191read-onlyC1SBFSystem Standby flag for CPU181read-onlyCCRPFClear Critical Radio system phase21write-onlyC2CSSFClear CPU2 Stop Standby flags11write-onlyC1CSSFClear CPU1 Stop Standby flags01write-onlySYSCFG_VREFBUFSYSCFG_VREFBUFSYSCFG_VREFBUF0x400100000x00x200registersSYSCFG_MEMRMPSYSCFG_MEMRMPmemory remap register0x00x20read-write0x00000000MEM_MODEMemory mapping selection03SYSCFG_CFGR1SYSCFG_CFGR1configuration register 10x40x20read-write0x7C000001FPU_IEFloating Point Unit interrupts enable bits266I2C3_FMPI2C3 Fast-mode Plus driving capability activation221I2C1_FMPI2C1 Fast-mode Plus driving capability activation201I2C_PB9_FMPFast-mode Plus (Fm+) driving capability activation on PB9191I2C_PB8_FMPFast-mode Plus (Fm+) driving capability activation on PB8181I2C_PB7_FMPFast-mode Plus (Fm+) driving capability activation on PB7171I2C_PB6_FMPFast-mode Plus (Fm+) driving capability activation on PB6161BOOSTENI/O analog switch voltage booster enable81SYSCFG_EXTICR1SYSCFG_EXTICR1external interrupt configuration register 10x80x20read-write0x00000000EXTI3EXTI 3 configuration bits123EXTI2EXTI 2 configuration bits83EXTI1EXTI 1 configuration bits43EXTI0EXTI 0 configuration bits03SYSCFG_EXTICR2SYSCFG_EXTICR2external interrupt configuration register 20xC0x20read-write0x00000000EXTI7EXTI 7 configuration bits123EXTI6EXTI 6 configuration bits83EXTI5EXTI 5 configuration bits43EXTI4EXTI 4 configuration bits03SYSCFG_EXTICR3SYSCFG_EXTICR3external interrupt configuration register 30x100x20read-write0x00000000EXTI11EXTI 11 configuration bits123EXTI10EXTI 10 configuration bits83EXTI9EXTI 9 configuration bits43EXTI8EXTI 8 configuration bits03SYSCFG_EXTICR4SYSCFG_EXTICR4external interrupt configuration register 40x140x20read-write0x00000000EXTI15EXTI15 configuration bits123EXTI14EXTI14 configuration bits83EXTI13EXTI13 configuration bits43EXTI12EXTI12 configuration bits03SYSCFG_SCSRSYSCFG_SCSRSCSR0x180x200x00000000SRAM2BSYSRAM2 busy by erase operation11read-onlySRAM2ERSRAM2 Erase01read-writeC2RFDCPU2 SRAM fetch (execution) disable.311read-writeSYSCFG_CFGR2SYSCFG_CFGR2CFGR20x1C0x200x00000000SPFSRAM2 parity error flag81read-writeECCLECC Lock31write-onlyPVDLPVD lock enable bit21write-onlySPLSRAM2 parity lock bit11write-onlyCLLCortex-M4 LOCKUP (Hardfault) output enable bit01write-onlySYSCFG_SWPRSYSCFG_SWPRSRAM2 write protection register0x200x20write-only0x00000000P31WPSRAM2 page 31 write protection311P30WPP30WP301P29WPP29WP291P28WPP28WP281P27WPP27WP271P26WPP26WP261P25WPP25WP251P24WPP24WP241P23WPP23WP231P22WPP22WP221P21WPP21WP211P20WPP20WP201P19WPP19WP191P18WPP18WP181P17WPP17WP171P16WPP16WP161P15WPP15WP151P14WPP14WP141P13WPP13WP131P12WPP12WP121P11WPP11WP111P10WPP10WP101P9WPP9WP91P8WPP8WP81P7WPP7WP71P6WPP6WP61P5WPP5WP51P4WPP4WP41P3WPP3WP31P2WPP2WP21P1WPP1WP11P0WPP0WP01SYSCFG_SKRSYSCFG_SKRSKR0x240x20write-only0x00000000KEYSRAM2 write protection key for software erase08SYSCFG_SWPR2SYSCFG_SWPR2SRAM2 write protection register 20x280x20write-only0x00000000P63WPSRAM2 page 63 write protection311P62WPP62WP301P61WPP61WP291P60WPP60WP281P59WPP59WP271P58WPP58WP261P57WPP57WP251P56WPP56WP241P55WPP55WP231P54WPP54WP221P53WPP53WP211P52WPP52WP201P51WPP51WP191P50WPP50WP181P49WPP49WP171P48WPP48WP161P47WPP47WP151P46WPP46WP141P45WPP45WP131P44WPP44WP121P43WPP43WP111P42WPP42WP101P41WPP41WP91P40WPP40WP81P39WPP39WP71P38WPP38WP61P37WPP37WP51P36WPP36WP41P35WPP35WP31P34WPP34WP21P33WPP33WP11P32WPP32WP01VREFBUF_CSRVREFBUF_CSRVREF control and status register0x300x200x00000002ENVRVoltage reference buffer enable01read-writeHIZHigh impedance mode11read-writeVRSVoltage reference scale21read-writeVRRVoltage reference buffer ready31read-onlyVREFBUF_CCRVREFBUF_CCRcalibration control register0x340x20read-write0x00000000TRIMTrimming code06SYSCFG_IMR1SYSCFG_IMR1CPU1 interrupt mask register 10x1000x20read-write0x00000000TIM1IMPeripheral TIM1 interrupt mask to CPU1131TIM16IMPeripheral TIM16 interrupt mask to CPU1141TIM17IMPeripheral TIM17 interrupt mask to CPU1151EXIT5IMPeripheral EXIT5 interrupt mask to CPU1211EXIT6IMPeripheral EXIT6 interrupt mask to CPU1221EXIT7IMPeripheral EXIT7 interrupt mask to CPU1231EXIT8IMPeripheral EXIT8 interrupt mask to CPU1241EXIT9IMPeripheral EXIT9 interrupt mask to CPU1251EXIT10IMPeripheral EXIT10 interrupt mask to CPU1261EXIT11IMPeripheral EXIT11 interrupt mask to CPU1271EXIT12IMPeripheral EXIT12 interrupt mask to CPU1281EXIT13IMPeripheral EXIT13 interrupt mask to CPU1291EXIT14IMPeripheral EXIT14 interrupt mask to CPU1301EXIT15IMPeripheral EXIT15 interrupt mask to CPU1311SYSCFG_IMR2SYSCFG_IMR2CPU1 interrupt mask register 20x1040x20read-write0x00000000PVM3IMPeripheral PVM3 interrupt mask to CPU1181PVM1IMPeripheral PVM1 interrupt mask to CPU1161PVDIMPeripheral PVD interrupt mask to CPU1201SYSCFG_C2IMR1SYSCFG_C2IMR1CPU2 interrupt mask register 10x1080x20read-write0x00000000RTCSTAMPPeripheral RTCSTAMP interrupt mask to CPU201RTCWKUPPeripheral RTCWKUP interrupt mask to CPU231RTCALARMPeripheral RTCALARM interrupt mask to CPU241RCCPeripheral RCC interrupt mask to CPU251FLASHPeripheral FLASH interrupt mask to CPU261PKAPeripheral PKA interrupt mask to CPU281RNGPeripheral RNG interrupt mask to CPU291AES1Peripheral AES1 interrupt mask to CPU2101COMPPeripheral COMP interrupt mask to CPU2111ADCPeripheral ADC interrupt mask to CPU2121SYSCFG_C2IMR2SYSCFG_C2IMR2CPU2 interrupt mask register 10x10C0x20read-write0x00000000DMA1_CH1_IMPeripheral DMA1 CH1 interrupt mask to CPU201DMA1_CH2_IMPeripheral DMA1 CH2 interrupt mask to CPU211DMA1_CH3_IMPeripheral DMA1 CH3 interrupt mask to CPU221DMA1_CH4_IMPeripheral DMA1 CH4 interrupt mask to CPU231DMA1_CH5_IMPeripheral DMA1 CH5 interrupt mask to CPU241DMA1_CH6_IMPeripheral DMA1 CH6 interrupt mask to CPU251DMA1_CH7_IMPeripheral DMA1 CH7 interrupt mask to CPU261DMA2_CH1_IMPeripheral DMA2 CH1 interrupt mask to CPU181DMA2_CH2_IMPeripheral DMA2 CH2 interrupt mask to CPU191DMA2_CH3_IMPeripheral DMA2 CH3 interrupt mask to CPU1101DMA2_CH4_IMPeripheral DMA2 CH4 interrupt mask to CPU1111DMA2_CH5_IMPeripheral DMA2 CH5 interrupt mask to CPU1121DMA2_CH6_IMPeripheral DMA2 CH6 interrupt mask to CPU1131DMA2_CH7_IMPeripheral DMA2 CH7 interrupt mask to CPU1141DMAM_UX1_IMPeripheral DMAM UX1 interrupt mask to CPU1151PVM1IMPeripheral PVM1IM interrupt mask to CPU1161PVM3IMPeripheral PVM3IM interrupt mask to CPU1181PVDIMPeripheral PVDIM interrupt mask to CPU1201TSCIMPeripheral TSCIM interrupt mask to CPU1211LCDIMPeripheral LCDIM interrupt mask to CPU1221SYSCFG_SIPCRSYSCFG_SIPCRsecure IP control register0x1100x20read-write0x00000000SAES1Enable AES1 KEY[7:0] security.01SAES2Enable AES2 security.11SPKAEnable PKA security21SRNGEnable True RNG security31COMPComparator instance 1COMP0x400102000x00x9registersCOMPCOMP2 & COMP1 interrupt through + AIEC[21:20]22COMP1_CSRCOMP1_CSRComparator control and status register0x00x200x00000000COMP1_ENComparator enable01read-writeCOMP1_PWRMODEComparator power mode22read-writeCOMP1_INMSELComparator input minus selection43read-writeCOMP1_INPSELComparator input plus selection72read-writeCOMP1_POLARITYComparator output polarity151read-writeCOMP1_HYSTComparator hysteresis162read-writeCOMP1_BLANKINGComparator blanking source183read-writeCOMP1_BRGENComparator voltage scaler enable221read-writeCOMP1_SCALENComparator scaler bridge enable231read-writeCOMP1_INMESELComparator input minus extended selection252read-writeCOMP1_VALUEComparator output level301read-onlyCOMP1_LOCKComparator lock311read-writeCOMP2_CSRCOMP2_CSRComparator 2 control and status register0x40x200x00000000COMP2_ENComparator 2 enable bit01read-writeCOMP2_PWRMODEPower Mode of the comparator 222read-writeCOMP2_INMSELComparator 2 input minus selection bits42read-writeCOMP2_INPSELComparator 1 input plus selection bit72read-writeCOMP2_WINMODEWindows mode selection bit91read-writeCOMP2_POLARITYComparator 2 polarity selection bit151read-writeCOMP2_HYSTComparator 2 hysteresis selection bits162read-writeCOMP2_BLANKINGComparator 2 blanking source selection bits183read-writeCOMP2_BRGENScaler bridge enable221read-writeCOMP2_SCALENVoltage scaler enable bit231read-writeCOMP2_INMESELcomparator 2 input minus extended selection bits.252read-writeCOMP2_VALUEComparator 2 output status bit301read-onlyCOMP2_LOCKCSR register lock bit311read-writeRNGRandom number generatorRNG0x580010000x00x400registersTrue_RNGTrue random number generator + interrupt53CRCRcontrol register0x00x20read-write0x00000000RNGENRandom number generator enable21IEInterrupt enable31BYPBypass mode enable61SRSRstatus register0x40x200x00000000SEISSeed error interrupt status61read-writeCEISClock error interrupt status51read-writeSECSSeed error current status21read-onlyCECSClock error current status11read-onlyDRDYData ready01read-onlyDRDRdata register0x80x20read-only0x00000000RNDATARandom data032AES1Advanced encryption standard hardware accelerator 1AES10x500600000x00x400registersAES1AES1 global interrupt51CRCRcontrol register0x00x20read-write0x00000000NPBLBNumber of padding bytes in last block of payload204KEYSIZEKey size selection181CHMOD2AES chaining mode Bit2161GCMPHUsed only for GCM, CCM and GMAC algorithms and has no effect when other algorithms are selected132DMAOUTENEnable DMA management of data output phase121DMAINENEnable DMA management of data input phase111ERRIEError interrupt enable101CCFIECCF flag interrupt enable91ERRCError clear81CCFCComputation Complete Flag Clear71CHMOD10AES chaining mode Bit1 Bit052MODEAES operating mode32DATATYPEData type selection (for data in and data out to/from the cryptographic block)12ENAES enable01SRSRstatus register0x40x20read-only0x00000000BUSYBusy flag31WRERRWrite error flag21RDERRRead error flag11CCFComputation complete flag01DINRDINRdata input register0x80x20read-write0x00000000AES_DINRData Input Register032DOUTRDOUTRdata output register0xC0x20read-only0x00000000AES_DOUTRData output register032KEYR0KEYR0key register 00x100x20read-write0x00000000AES_KEYR0Data Output Register (LSB key [31:0])032KEYR1KEYR1key register 10x140x20read-write0x00000000AES_KEYR1AES key register (key [63:32])032KEYR2KEYR2key register 20x180x20read-write0x00000000AES_KEYR2AES key register (key [95:64])032KEYR3KEYR3key register 30x1C0x20read-write0x00000000AES_KEYR3AES key register (MSB key [127:96])032IVR0IVR0initialization vector register 00x200x20read-write0x00000000AES_IVR0initialization vector register (LSB IVR [31:0])032IVR1IVR1initialization vector register 10x240x20read-write0x00000000AES_IVR1Initialization Vector Register (IVR [63:32])032IVR2IVR2initialization vector register 20x280x20read-write0x00000000AES_IVR2Initialization Vector Register (IVR [95:64])032IVR3IVR3initialization vector register 30x2C0x20read-write0x00000000AES_IVR3Initialization Vector Register (MSB IVR [127:96])032KEYR4KEYR4key register 40x300x20read-write0x00000000AES_KEYR4AES key register (MSB key [159:128])032KEYR5KEYR5key register 50x340x20read-write0x00000000AES_KEYR5AES key register (MSB key [191:160])032KEYR6KEYR6key register 60x380x20read-write0x00000000AES_KEYR6AES key register (MSB key [223:192])032KEYR7KEYR7key register 70x3C0x20read-write0x00000000AES_KEYR7AES key register (MSB key [255:224])032SUSP0RSUSP0RAES suspend register 00x400x20read-write0x00000000AES_SUSP0RAES suspend register 0032SUSP1RSUSP1RAES suspend register 10x440x20read-write0x00000000AES_SUSP1RAES suspend register 1032SUSP2RSUSP2RAES suspend register 20x480x20read-write0x00000000AES_SUSP2RAES suspend register 2032SUSP3RSUSP3RAES suspend register 30x4C0x20read-write0x00000000AES_SUSP3RAES suspend register 3032SUSP4RSUSP4RAES suspend register 40x500x20read-write0x00000000AES_SUSP4RAES suspend register 4032SUSP5RSUSP5RAES suspend register 50x540x20read-write0x00000000AES_SUSP5RAES suspend register 5032SUSP6RSUSP6RAES suspend register 60x580x20read-write0x00000000AES_SUSP6RAES suspend register 6032SUSP7RSUSP7RAES suspend register 70x5C0x20read-write0x00000000AES_SUSP7RAES suspend register 7032HWCFRHWCFRAES hardware configuration register0x3F00x20read-only0x00000002CFG4HW Generic 4124CFG3HW Generic 384CFG2HW Generic 244CFG1HW Generic 104VERRVERRAES version register0x3F40x20read-only0x00000010MAJREVMajor revision44MINREVMinor revision04IPIDRIPIDRAES identification register0x3F80x20read-only0x00170023IDIdentification code032SIDRSIDRAES size ID register0x3FC0x20read-only0xA3C5DD01IDSize Identification code032AES2Advanced encryption standard hardware accelerator 1AES10x580018000x00x400registersAES2AES2 global interrupt52CRCRcontrol register0x00x20read-write0x00000000NPBLBNumber of padding bytes in last block of payload204KEYSIZEKey size selection181CHMOD2AES chaining mode Bit2161GCMPHUsed only for GCM, CCM and GMAC algorithms and has no effect when other algorithms are selected132DMAOUTENEnable DMA management of data output phase121DMAINENEnable DMA management of data input phase111ERRIEError interrupt enable101CCFIECCF flag interrupt enable91ERRCError clear81CCFCComputation Complete Flag Clear71CHMOD10AES chaining mode Bit1 Bit052MODEAES operating mode32DATATYPEData type selection (for data in and data out to/from the cryptographic block)12ENAES enable01SRSRstatus register0x40x20read-only0x00000000BUSYBusy flag31WRERRWrite error flag21RDERRRead error flag11CCFComputation complete flag01DINRDINRdata input register0x80x20read-write0x00000000AES_DINRData Input Register032DOUTRDOUTRdata output register0xC0x20read-only0x00000000AES_DOUTRData output register032KEYR0KEYR0key register 00x100x20read-write0x00000000AES_KEYR0Data Output Register (LSB key [31:0])032KEYR1KEYR1key register 10x140x20read-write0x00000000AES_KEYR1AES key register (key [63:32])032KEYR2KEYR2key register 20x180x20read-write0x00000000AES_KEYR2AES key register (key [95:64])032KEYR3KEYR3key register 30x1C0x20read-write0x00000000AES_KEYR3AES key register (MSB key [127:96])032IVR0IVR0initialization vector register 00x200x20read-write0x00000000AES_IVR0initialization vector register (LSB IVR [31:0])032IVR1IVR1initialization vector register 10x240x20read-write0x00000000AES_IVR1Initialization Vector Register (IVR [63:32])032IVR2IVR2initialization vector register 20x280x20read-write0x00000000AES_IVR2Initialization Vector Register (IVR [95:64])032IVR3IVR3initialization vector register 30x2C0x20read-write0x00000000AES_IVR3Initialization Vector Register (MSB IVR [127:96])032KEYR4KEYR4key register 40x300x20read-write0x00000000AES_KEYR4AES key register (MSB key [159:128])032KEYR5KEYR5key register 50x340x20read-write0x00000000AES_KEYR5AES key register (MSB key [191:160])032KEYR6KEYR6key register 60x380x20read-write0x00000000AES_KEYR6AES key register (MSB key [223:192])032KEYR7KEYR7key register 70x3C0x20read-write0x00000000AES_KEYR7AES key register (MSB key [255:224])032SUSP0RSUSP0RAES suspend register 00x400x20read-write0x00000000AES_SUSP0RAES suspend register 0032SUSP1RSUSP1RAES suspend register 10x440x20read-write0x00000000AES_SUSP1RAES suspend register 1032SUSP2RSUSP2RAES suspend register 20x480x20read-write0x00000000AES_SUSP2RAES suspend register 2032SUSP3RSUSP3RAES suspend register 30x4C0x20read-write0x00000000AES_SUSP3RAES suspend register 3032SUSP4RSUSP4RAES suspend register 40x500x20read-write0x00000000AES_SUSP4RAES suspend register 4032SUSP5RSUSP5RAES suspend register 50x540x20read-write0x00000000AES_SUSP5RAES suspend register 5032SUSP6RSUSP6RAES suspend register 60x580x20read-write0x00000000AES_SUSP6RAES suspend register 6032SUSP7RSUSP7RAES suspend register 70x5C0x20read-write0x00000000AES_SUSP7RAES suspend register 7032HWCFRHWCFRAES hardware configuration register0x600x20read-only0x00000002CFG4HW Generic 4124CFG3HW Generic 384CFG2HW Generic 244CFG1HW Generic 104VERRVERRAES version register0x640x20read-only0x00000010MAJREVMajor revision44MINREVMinor revision04IPIDRIPIDRAES identification register0x680x20read-only0x00170023IDIdentification code032SIDRSIDRAES size ID register0x6C0x20read-only0x00170023IDSize Identification code032HSEMHSEMHardware_Semaphore0x580014000x00x400registersHSEMSemaphore interrupt 0 to CPU146R0R0Semaphore 0 register0x00x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R1R1Semaphore 1 register0x40x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R2R2Semaphore 2 register0x80x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R3R3Semaphore 3 register0xC0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R4R4Semaphore 4 register0x100x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R5R5Semaphore 5 register0x140x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R6R6Semaphore 6 register0x180x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R7R7Semaphore 7 register0x1C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R8R8Semaphore 8 register0x200x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R9R9Semaphore 9 register0x240x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R10R10Semaphore 10 register0x280x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R11R11Semaphore 11 register0x2C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R12R12Semaphore 12 register0x300x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R13R13Semaphore 13 register0x340x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R14R14Semaphore 14 register0x380x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R15R15Semaphore 15 register0x3C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R16R16Semaphore 16 register0x400x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R17R17Semaphore 17 register0x440x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R18R18Semaphore 18 register0x480x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R19R19Semaphore 19 register0x4C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R20R20Semaphore 20 register0x500x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R21R21Semaphore 21 register0x540x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R22R22Semaphore 22 register0x580x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R23R23Semaphore 23 register0x5C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R24R24Semaphore 24 register0x600x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R25R25Semaphore 25 register0x640x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R26R26Semaphore 26 register0x680x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R27R27Semaphore 27 register0x6C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R28R28Semaphore 28 register0x700x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R29R29Semaphore 29 register0x740x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R30R30Semaphore 30 register0x780x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08R31R31Semaphore 31 register0x7C0x20read-write0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR0RLR0Semaphore 0 read lock register0x800x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR1RLR1Semaphore 1 read lock register0x840x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR2RLR2Semaphore 2 read lock register0x880x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR3RLR3Semaphore 3 read lock register0x8C0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR4RLR4Semaphore 4 read lock read lock register0x900x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR5RLR5Semaphore 5 read lock register0x940x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR6RLR6Semaphore 6 read lock register0x980x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR7RLR7Semaphore 7 read lock register0x9C0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR8RLR8Semaphore 8 read lock register0xA00x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR9RLR9Semaphore 9 read lock register0xA40x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR10RLR10Semaphore 10 read lock register0xA80x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR11RLR11Semaphore 11 read lock register0xAC0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR12RLR12Semaphore 12 read lock register0xB00x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR13RLR13Semaphore 13 read lock register0xB40x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR14RLR14Semaphore 14 read lock register0xB80x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR15RLR15Semaphore 15 read lock register0xBC0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR16RLR16Semaphore 16 read lock register0xC00x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR17RLR17Semaphore 17 read lock register0xC40x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR18RLR18Semaphore 18 read lock register0xC80x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR19RLR19Semaphore 19 read lock register0xCC0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR20RLR20Semaphore 20 read lock register0xD00x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR21RLR21Semaphore 21 read lock register0xD40x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR22RLR22Semaphore 22 read lock register0xD80x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR23RLR23Semaphore 23 read lock register0xDC0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR24RLR24Semaphore 24 read lock register0xE00x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR25RLR25Semaphore 25 read lock register0xE40x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR26RLR26Semaphore 26 read lock register0xE80x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR27RLR27Semaphore 27 read lock register0xEC0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR28RLR28Semaphore 28 read lock register0xF00x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR29RLR29Semaphore 29 read lock register0xF40x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR30RLR30Semaphore 30 read lock register0xF80x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08RLR31RLR31Semaphore 31 read lock register0xFC0x20read-only0x00000000LOCKlock indication311COREIDSemaphore CoreID84PROCIDSemaphore ProcessID08CRCRSemaphore Clear register0x1400x20read-write0x00000000KEYSemaphore clear Key1616COREIDCoreID of semaphore to be cleared84KEYRKEYRInterrupt clear register0x1440x20read-write0x00000000KEYSemaphore Clear Key1616HWCFGR2HWCFGR2Semaphore hardware configuration register 20x3EC0x20read-only0x00000084MASTERID4Hardware Configuration valid bus masters ID4124MASTERID3Hardware Configuration valid bus masters ID384MASTERID2Hardware Configuration valid bus masters ID244MASTERID1Hardware Configuration valid bus masters ID104HWCFGR1HWCFGR1Semaphore hardware configuration register 10x3F00x20read-only0x00000220NBINTHardware Configuration number of interrupts supported number of master IDs84NBSEMHardware Configuration number of semaphores08VERRVERRHSEM version register0x3F40x20read-only0x00000020MAJREVMajor Revision44MINREVMinor Revision04IPIDRIPIDRHSEM indentification register0x3F80x20read-only0x00100072IDIdentification Code032SIDRSIDRHSEM size indentification register0x3FC0x20read-only0xA3C5DD01SIDSize Identification Code032C1IER0C1IER0HSEM Interrupt enable register0x1000x20read-write0x00000000ISEmCPU(n) semaphore m enable bit032C1ICRC1ICRHSEM Interrupt clear register0x1040x20read-write0x00000000ISCmCPU(n) semaphore m clear bit032C1ISRC1ISRHSEM Interrupt status register0x1080x20read-only0x00000000ISFmCPU(n) semaphore m status bit before enable (mask)032C1MISRC1MISRHSEM Masked interrupt status register0x10C0x20read-only0x00000000MISFmmasked CPU(n) semaphore m status bit after enable (mask).032C2IER0C2IER0HSEM Interrupt enable register0x1100x20read-write0x00000000ISEmCPU(2) semaphore m enable bit.032C2ICRC2ICRHSEM Interrupt clear register0x1140x20read-write0x00000000ISCmCPU(2) semaphore m clear bit032C2ISRC2ISRHSEM Interrupt status register0x1180x20read-only0x00000000ISFmCPU(2) semaphore m status bit before enable (mask).032C2MISRC2MISRHSEM Masked interrupt status register0x11C0x20read-only0x00000000MISFmmasked CPU(2) semaphore m status bit after enable (mask).032ADCAnalog to Digital Converter instance 1ADC0x500400000x00x400registersADC1ADC1 global interrupt18ISRISRADC interrupt and status register0x00x20read-write0x00000000JQOVFADC group injected contexts queue overflow flag101AWD3ADC analog watchdog 3 flag91AWD2ADC analog watchdog 2 flag81AWD1ADC analog watchdog 1 flag71JEOSADC group injected end of sequence conversions flag61JEOCADC group injected end of unitary conversion flag51OVRADC group regular overrun flag41EOSADC group regular end of sequence conversions flag31EOCADC group regular end of unitary conversion flag21EOSMPADC group regular end of sampling flag11ADRDYADC ready flag01IERIERADC interrupt enable register0x40x20read-write0x00000000JQOVFIEADC group injected contexts queue overflow interrupt101AWD3IEADC analog watchdog 3 interrupt91AWD2IEADC analog watchdog 2 interrupt81AWD1IEADC analog watchdog 1 interrupt71JEOSIEADC group injected end of sequence conversions interrupt61JEOCIEADC group injected end of unitary conversion interrupt51OVRIEADC group regular overrun interrupt41EOSIEADC group regular end of sequence conversions interrupt31EOCIEADC group regular end of unitary conversion interrupt21EOSMPIEADC group regular end of sampling interrupt11ADRDYIEADC ready interrupt01CRCRADC control register0x80x20read-write0x00000000ADCALADC calibration311ADCALDIFADC differential mode for calibration301DEEPPWDADC deep power down enable291ADVREGENADC voltage regulator enable281JADSTPADC group injected conversion stop51ADSTPADC group regular conversion stop41JADSTARTADC group injected conversion start31ADSTARTADC group regular conversion start21ADDISADC disable11ADENADC enable01CFGRCFGRADC configuration register 10xC0x20read-write0x80000000JQDISADC group injected contexts queue disable311AWDCH1CHADC analog watchdog 1 monitored channel selection265JAUTOADC group injected automatic trigger mode251JAWD1ENADC analog watchdog 1 enable on scope ADC group injected241AWD1ENADC analog watchdog 1 enable on scope ADC group regular231AWD1SGLADC analog watchdog 1 monitoring a single channel or all channels221JQMADC group injected contexts queue mode211JDISCENADC group injected sequencer discontinuous mode201DISCNUMADC group regular sequencer discontinuous number of ranks173DISCENADC group regular sequencer discontinuous mode161AUTDLYADC low power auto wait141CONTADC group regular continuous conversion mode131OVRMODADC group regular overrun configuration121EXTENADC group regular external trigger polarity102EXTSELADC group regular external trigger source64ALIGNADC data alignement51RESADC data resolution32DMACFGADC DMA transfer configuration11DMAENADC DMA transfer enable01CFGR2CFGR2ADC configuration register 20x100x20read-write0x00000000ROVSMADC oversampling mode managing interlaced conversions of ADC group regular and group injected101TOVSADC oversampling discontinuous mode (triggered mode) for ADC group regular91OVSSADC oversampling shift54OVSRADC oversampling ratio23JOVSEADC oversampler enable on scope ADC group injected11ROVSEADC oversampler enable on scope ADC group regular01SMPR1SMPR1ADC sampling time register 10x140x20read-write0x00000000SMP9ADC channel 9 sampling time selection273SMP8ADC channel 8 sampling time selection243SMP7ADC channel 7 sampling time selection213SMP6ADC channel 6 sampling time selection183SMP5ADC channel 5 sampling time selection153SMP4ADC channel 4 sampling time selection123SMP3ADC channel 3 sampling time selection93SMP2ADC channel 2 sampling time selection63SMP1ADC channel 1 sampling time selection33SMPR2SMPR2ADC sampling time register 20x180x20read-write0x00000000SMP18ADC channel 18 sampling time selection243SMP17ADC channel 17 sampling time selection213SMP16ADC channel 16 sampling time selection183SMP15ADC channel 15 sampling time selection153SMP14ADC channel 14 sampling time selection123SMP13ADC channel 13 sampling time selection93SMP12ADC channel 12 sampling time selection63SMP11ADC channel 11 sampling time selection33SMP10ADC channel 10 sampling time selection03TR1TR1ADC analog watchdog 1 threshold register0x200x20read-write0x0FFF0000HT1ADC analog watchdog 1 threshold high1612LT1ADC analog watchdog 1 threshold low012TR2TR2ADC analog watchdog 2 threshold register0x240x20read-write0x0FFF0000HT2ADC analog watchdog 2 threshold high168LT2ADC analog watchdog 2 threshold low08TR3TR3ADC analog watchdog 3 threshold register0x280x20read-write0x0FFF0000HT3ADC analog watchdog 3 threshold high168LT3ADC analog watchdog 3 threshold low08SQR1SQR1ADC group regular sequencer ranks register 10x300x20read-write0x00000000SQ4ADC group regular sequencer rank 4245SQ3ADC group regular sequencer rank 3185SQ2ADC group regular sequencer rank 2125SQ1ADC group regular sequencer rank 165L3L304SQR2SQR2ADC group regular sequencer ranks register 20x340x20read-write0x00000000SQ9ADC group regular sequencer rank 9245SQ8ADC group regular sequencer rank 8185SQ7ADC group regular sequencer rank 7125SQ6ADC group regular sequencer rank 665SQ5ADC group regular sequencer rank 505SQR3SQR3ADC group regular sequencer ranks register 30x380x20read-write0x00000000SQ14ADC group regular sequencer rank 14245SQ13ADC group regular sequencer rank 13185SQ12ADC group regular sequencer rank 12125SQ11ADC group regular sequencer rank 1165SQ10ADC group regular sequencer rank 1005SQR4SQR4ADC group regular sequencer ranks register 40x3C0x20read-write0x00000000SQ16ADC group regular sequencer rank 1665SQ15ADC group regular sequencer rank 1505DRDRADC group regular conversion data register0x400x200x00000000RDATA_0_6Regular Data converted 0_606read-writeRDATA_7_151579read-onlyJSQRJSQRADC group injected sequencer register0x4C0x20read-write0x00000000JSQ4ADC group injected sequencer rank 4265JSQ3ADC group injected sequencer rank 3205JSQ2ADC group injected sequencer rank 2145JSQ1ADC group injected sequencer rank 185JEXTENADC group injected external trigger polarity62JEXTSELADC group injected external trigger source24JLADC group injected sequencer scan length02OFR1OFR1ADC offset number 1 register0x600x20read-write0x00000000OFFSET1_ENADC offset number 1 enable311OFFSET1_CHADC offset number 1 channel selection265OFFSET1ADC offset number 1 offset level012OFR2OFR2ADC offset number 2 register0x640x20read-write0x00000000OFFSET2_ENADC offset number 2 enable311OFFSET2_CHADC offset number 2 channel selection265OFFSET2ADC offset number 2 offset level012OFR3OFR3ADC offset number 3 register0x680x20read-write0x00000000OFFSET3_ENADC offset number 3 enable311OFFSET3_CHADC offset number 3 channel selection265OFFSET3ADC offset number 3 offset level012OFR4OFR4ADC offset number 4 register0x6C0x20read-write0x00000000OFFSET4_ENADC offset number 4 enable311OFFSET4_CHADC offset number 4 channel selection265OFFSET4ADC offset number 4 offset level012JDR1JDR1ADC group injected sequencer rank 1 register0x800x20read-only0x00000000JDATA1ADC group injected sequencer rank 1 conversion data016JDR2JDR2ADC group injected sequencer rank 2 register0x840x20read-only0x00000000JDATA2ADC group injected sequencer rank 2 conversion data016JDR3JDR3ADC group injected sequencer rank 3 register0x880x20read-only0x00000000JDATA3ADC group injected sequencer rank 3 conversion data016JDR4JDR4ADC group injected sequencer rank 4 register0x8C0x20read-only0x00000000JDATA4ADC group injected sequencer rank 4 conversion data016AWD2CRAWD2CRADC analog watchdog 2 configuration register0xA00x20read-write0x00000000AWD2CHADC analog watchdog 2 monitored channel selection019AWD3CRAWD3CRADC analog watchdog 3 configuration register0xA40x20read-write0x00000000AWD3CHADC analog watchdog 3 monitored channel selection019DIFSELDIFSELADC channel differential or single-ended mode selection register0xB00x200x00000000DIFSEL_0ADC channel differential or single-ended mode for channel 001read-onlyDIFSEL_1_15ADC channel differential or single-ended mode for channels 1 to 15115read-writeDIFSEL_16_18ADC channel differential or single-ended mode for channels 18 to 16163read-onlyCALFACTCALFACTADC calibration factors register0xB40x20read-write0x00000000CALFACT_DADC calibration factor in differential mode167CALFACT_SADC calibration factor in single-ended mode07CCRCCRADC common control register0x3080x20read-write0x00000000VBATENVBAT enable241TSENTemperature sensor enable231VREFENVREFEN221PRESCADC prescaler184CKMODEADC clock mode162GPIOAGeneral-purpose I/OsGPIO0x480000000x00x400registersMODERMODERGPIO port mode register0x00x20read-write0xABFFFFFFMODER15Port x configuration bits (y = 0..15)302MODER14Port x configuration bits (y = 0..15)282MODER13Port x configuration bits (y = 0..15)262MODER12Port x configuration bits (y = 0..15)242MODER11Port x configuration bits (y = 0..15)222MODER10Port x configuration bits (y = 0..15)202MODER9Port x configuration bits (y = 0..15)182MODER8Port x configuration bits (y = 0..15)162MODER7Port x configuration bits (y = 0..15)142MODER6Port x configuration bits (y = 0..15)122MODER5Port x configuration bits (y = 0..15)102MODER4Port x configuration bits (y = 0..15)82MODER3Port x configuration bits (y = 0..15)62MODER2Port x configuration bits (y = 0..15)42MODER1Port x configuration bits (y = 0..15)22MODER0Port x configuration bits (y = 0..15)02OTYPEROTYPERGPIO port output type register0x40x20read-write0x00000000OT15Port x configuration bits (y = 0..15)151OT14Port x configuration bits (y = 0..15)141OT13Port x configuration bits (y = 0..15)131OT12Port x configuration bits (y = 0..15)121OT11Port x configuration bits (y = 0..15)111OT10Port x configuration bits (y = 0..15)101OT9Port x configuration bits (y = 0..15)91OT8Port x configuration bits (y = 0..15)81OT7Port x configuration bits (y = 0..15)71OT6Port x configuration bits (y = 0..15)61OT5Port x configuration bits (y = 0..15)51OT4Port x configuration bits (y = 0..15)41OT3Port x configuration bits (y = 0..15)31OT2Port x configuration bits (y = 0..15)21OT1Port x configuration bits (y = 0..15)11OT0Port x configuration bits (y = 0..15)01OSPEEDROSPEEDRGPIO port output speed register0x80x20read-write0x0C000000OSPEEDR15Port x configuration bits (y = 0..15)302OSPEEDR14Port x configuration bits (y = 0..15)282OSPEEDR13Port x configuration bits (y = 0..15)262OSPEEDR12Port x configuration bits (y = 0..15)242OSPEEDR11Port x configuration bits (y = 0..15)222OSPEEDR10Port x configuration bits (y = 0..15)202OSPEEDR9Port x configuration bits (y = 0..15)182OSPEEDR8Port x configuration bits (y = 0..15)162OSPEEDR7Port x configuration bits (y = 0..15)142OSPEEDR6Port x configuration bits (y = 0..15)122OSPEEDR5Port x configuration bits (y = 0..15)102OSPEEDR4Port x configuration bits (y = 0..15)82OSPEEDR3Port x configuration bits (y = 0..15)62OSPEEDR2Port x configuration bits (y = 0..15)42OSPEEDR1Port x configuration bits (y = 0..15)22OSPEEDR0Port x configuration bits (y = 0..15)02PUPDRPUPDRGPIO port pull-up/pull-down register0xC0x20read-write0x64000000PUPDR15Port x configuration bits (y = 0..15)302PUPDR14Port x configuration bits (y = 0..15)282PUPDR13Port x configuration bits (y = 0..15)262PUPDR12Port x configuration bits (y = 0..15)242PUPDR11Port x configuration bits (y = 0..15)222PUPDR10Port x configuration bits (y = 0..15)202PUPDR9Port x configuration bits (y = 0..15)182PUPDR8Port x configuration bits (y = 0..15)162PUPDR7Port x configuration bits (y = 0..15)142PUPDR6Port x configuration bits (y = 0..15)122PUPDR5Port x configuration bits (y = 0..15)102PUPDR4Port x configuration bits (y = 0..15)82PUPDR3Port x configuration bits (y = 0..15)62PUPDR2Port x configuration bits (y = 0..15)42PUPDR1Port x configuration bits (y = 0..15)22PUPDR0Port x configuration bits (y = 0..15)02IDRIDRGPIO port input data register0x100x20read-only0x00000000IDR15Port input data (y = 0..15)151IDR14Port input data (y = 0..15)141IDR13Port input data (y = 0..15)131IDR12Port input data (y = 0..15)121IDR11Port input data (y = 0..15)111IDR10Port input data (y = 0..15)101IDR9Port input data (y = 0..15)91IDR8Port input data (y = 0..15)81IDR7Port input data (y = 0..15)71IDR6Port input data (y = 0..15)61IDR5Port input data (y = 0..15)51IDR4Port input data (y = 0..15)41IDR3Port input data (y = 0..15)31IDR2Port input data (y = 0..15)21IDR1Port input data (y = 0..15)11IDR0Port input data (y = 0..15)01ODRODRGPIO port output data register0x140x20read-write0x00000000ODR15Port output data (y = 0..15)151ODR14Port output data (y = 0..15)141ODR13Port output data (y = 0..15)131ODR12Port output data (y = 0..15)121ODR11Port output data (y = 0..15)111ODR10Port output data (y = 0..15)101ODR9Port output data (y = 0..15)91ODR8Port output data (y = 0..15)81ODR7Port output data (y = 0..15)71ODR6Port output data (y = 0..15)61ODR5Port output data (y = 0..15)51ODR4Port output data (y = 0..15)41ODR3Port output data (y = 0..15)31ODR2Port output data (y = 0..15)21ODR1Port output data (y = 0..15)11ODR0Port output data (y = 0..15)01BSRRBSRRGPIO port bit set/reset register0x180x20write-only0x00000000BR15Port x reset bit y (y = 0..15)311BR14Port x reset bit y (y = 0..15)301BR13Port x reset bit y (y = 0..15)291BR12Port x reset bit y (y = 0..15)281BR11Port x reset bit y (y = 0..15)271BR10Port x reset bit y (y = 0..15)261BR9Port x reset bit y (y = 0..15)251BR8Port x reset bit y (y = 0..15)241BR7Port x reset bit y (y = 0..15)231BR6Port x reset bit y (y = 0..15)221BR5Port x reset bit y (y = 0..15)211BR4Port x reset bit y (y = 0..15)201BR3Port x reset bit y (y = 0..15)191BR2Port x reset bit y (y = 0..15)181BR1Port x reset bit y (y = 0..15)171BR0Port x set bit y (y= 0..15)161BS15Port x set bit y (y= 0..15)151BS14Port x set bit y (y= 0..15)141BS13Port x set bit y (y= 0..15)131BS12Port x set bit y (y= 0..15)121BS11Port x set bit y (y= 0..15)111BS10Port x set bit y (y= 0..15)101BS9Port x set bit y (y= 0..15)91BS8Port x set bit y (y= 0..15)81BS7Port x set bit y (y= 0..15)71BS6Port x set bit y (y= 0..15)61BS5Port x set bit y (y= 0..15)51BS4Port x set bit y (y= 0..15)41BS3Port x set bit y (y= 0..15)31BS2Port x set bit y (y= 0..15)21BS1Port x set bit y (y= 0..15)11BS0Port x set bit y (y= 0..15)01LCKRLCKRGPIO port configuration lock register0x1C0x20read-write0x00000000LCKKPort x lock bit y (y= 0..15)161LCK15Port x lock bit y (y= 0..15)151LCK14Port x lock bit y (y= 0..15)141LCK13Port x lock bit y (y= 0..15)131LCK12Port x lock bit y (y= 0..15)121LCK11Port x lock bit y (y= 0..15)111LCK10Port x lock bit y (y= 0..15)101LCK9Port x lock bit y (y= 0..15)91LCK8Port x lock bit y (y= 0..15)81LCK7Port x lock bit y (y= 0..15)71LCK6Port x lock bit y (y= 0..15)61LCK5Port x lock bit y (y= 0..15)51LCK4Port x lock bit y (y= 0..15)41LCK3Port x lock bit y (y= 0..15)31LCK2Port x lock bit y (y= 0..15)21LCK1Port x lock bit y (y= 0..15)11LCK0Port x lock bit y (y= 0..15)01AFRLAFRLGPIO alternate function low register0x200x20read-write0x00000000AFSEL7Alternate function selection for port x bit y (y = 0..7)284AFSEL6Alternate function selection for port x bit y (y = 0..7)244AFSEL5Alternate function selection for port x bit y (y = 0..7)204AFSEL4Alternate function selection for port x bit y (y = 0..7)164AFSEL3Alternate function selection for port x bit y (y = 0..7)124AFSEL2Alternate function selection for port x bit y (y = 0..7)84AFSEL1Alternate function selection for port x bit y (y = 0..7)44AFSEL0Alternate function selection for port x bit y (y = 0..7)04AFRHAFRHGPIO alternate function high register0x240x20read-write0x00000000AFSEL15Alternate function selection for port x bit y (y = 8..15)284AFSEL14Alternate function selection for port x bit y (y = 8..15)244AFSEL13Alternate function selection for port x bit y (y = 8..15)204AFSEL12Alternate function selection for port x bit y (y = 8..15)164AFSEL11Alternate function selection for port x bit y (y = 8..15)124AFSEL10Alternate function selection for port x bit y (y = 8..15)84AFSEL9Alternate function selection for port x bit y (y = 8..15)44AFSEL8Alternate function selection for port x bit y (y = 8..15)04BRRBRRport bit reset register0x280x20write-only0x00000000BR0Port Reset bit01BR1Port Reset bit11BR2Port Reset bit21BR3Port Reset bit31BR4Port Reset bit41BR5Port Reset bit51BR6Port Reset bit61BR7Port Reset bit71BR8Port Reset bit81BR9Port Reset bit91BR10Port Reset bit101BR11Port Reset bit111BR12Port Reset bit121BR13Port Reset bit131BR14Port Reset bit141BR15Port Reset bit151GPIOBGeneral-purpose I/OsGPIO0x480004000x00x400registersMODERMODERGPIO port mode register0x00x20read-write0xFFFFFEBFMODER15Port x configuration bits (y = 0..15)302MODER14Port x configuration bits (y = 0..15)282MODER13Port x configuration bits (y = 0..15)262MODER12Port x configuration bits (y = 0..15)242MODER11Port x configuration bits (y = 0..15)222MODER10Port x configuration bits (y = 0..15)202MODER9Port x configuration bits (y = 0..15)182MODER8Port x configuration bits (y = 0..15)162MODER7Port x configuration bits (y = 0..15)142MODER6Port x configuration bits (y = 0..15)122MODER5Port x configuration bits (y = 0..15)102MODER4Port x configuration bits (y = 0..15)82MODER3Port x configuration bits (y = 0..15)62MODER2Port x configuration bits (y = 0..15)42MODER1Port x configuration bits (y = 0..15)22MODER0Port x configuration bits (y = 0..15)02OTYPEROTYPERGPIO port output type register0x40x20read-write0x00000000OT15Port x configuration bits (y = 0..15)151OT14Port x configuration bits (y = 0..15)141OT13Port x configuration bits (y = 0..15)131OT12Port x configuration bits (y = 0..15)121OT11Port x configuration bits (y = 0..15)111OT10Port x configuration bits (y = 0..15)101OT9Port x configuration bits (y = 0..15)91OT8Port x configuration bits (y = 0..15)81OT7Port x configuration bits (y = 0..15)71OT6Port x configuration bits (y = 0..15)61OT5Port x configuration bits (y = 0..15)51OT4Port x configuration bits (y = 0..15)41OT3Port x configuration bits (y = 0..15)31OT2Port x configuration bits (y = 0..15)21OT1Port x configuration bits (y = 0..15)11OT0Port x configuration bits (y = 0..15)01OSPEEDROSPEEDRGPIO port output speed register0x80x20read-write0x000000C0OSPEEDR15Port x configuration bits (y = 0..15)302OSPEEDR14Port x configuration bits (y = 0..15)282OSPEEDR13Port x configuration bits (y = 0..15)262OSPEEDR12Port x configuration bits (y = 0..15)242OSPEEDR11Port x configuration bits (y = 0..15)222OSPEEDR10Port x configuration bits (y = 0..15)202OSPEEDR9Port x configuration bits (y = 0..15)182OSPEEDR8Port x configuration bits (y = 0..15)162OSPEEDR7Port x configuration bits (y = 0..15)142OSPEEDR6Port x configuration bits (y = 0..15)122OSPEEDR5Port x configuration bits (y = 0..15)102OSPEEDR4Port x configuration bits (y = 0..15)82OSPEEDR3Port x configuration bits (y = 0..15)62OSPEEDR2Port x configuration bits (y = 0..15)42OSPEEDR1Port x configuration bits (y = 0..15)22OSPEEDR0Port x configuration bits (y = 0..15)02PUPDRPUPDRGPIO port pull-up/pull-down register0xC0x20read-write0x00000100PUPDR15Port x configuration bits (y = 0..15)302PUPDR14Port x configuration bits (y = 0..15)282PUPDR13Port x configuration bits (y = 0..15)262PUPDR12Port x configuration bits (y = 0..15)242PUPDR11Port x configuration bits (y = 0..15)222PUPDR10Port x configuration bits (y = 0..15)202PUPDR9Port x configuration bits (y = 0..15)182PUPDR8Port x configuration bits (y = 0..15)162PUPDR7Port x configuration bits (y = 0..15)142PUPDR6Port x configuration bits (y = 0..15)122PUPDR5Port x configuration bits (y = 0..15)102PUPDR4Port x configuration bits (y = 0..15)82PUPDR3Port x configuration bits (y = 0..15)62PUPDR2Port x configuration bits (y = 0..15)42PUPDR1Port x configuration bits (y = 0..15)22PUPDR0Port x configuration bits (y = 0..15)02IDRIDRGPIO port input data register0x100x20read-only0x00000000IDR15Port input data (y = 0..15)151IDR14Port input data (y = 0..15)141IDR13Port input data (y = 0..15)131IDR12Port input data (y = 0..15)121IDR11Port input data (y = 0..15)111IDR10Port input data (y = 0..15)101IDR9Port input data (y = 0..15)91IDR8Port input data (y = 0..15)81IDR7Port input data (y = 0..15)71IDR6Port input data (y = 0..15)61IDR5Port input data (y = 0..15)51IDR4Port input data (y = 0..15)41IDR3Port input data (y = 0..15)31IDR2Port input data (y = 0..15)21IDR1Port input data (y = 0..15)11IDR0Port input data (y = 0..15)01ODRODRGPIO port output data register0x140x20read-write0x00000000ODR15Port output data (y = 0..15)151ODR14Port output data (y = 0..15)141ODR13Port output data (y = 0..15)131ODR12Port output data (y = 0..15)121ODR11Port output data (y = 0..15)111ODR10Port output data (y = 0..15)101ODR9Port output data (y = 0..15)91ODR8Port output data (y = 0..15)81ODR7Port output data (y = 0..15)71ODR6Port output data (y = 0..15)61ODR5Port output data (y = 0..15)51ODR4Port output data (y = 0..15)41ODR3Port output data (y = 0..15)31ODR2Port output data (y = 0..15)21ODR1Port output data (y = 0..15)11ODR0Port output data (y = 0..15)01BSRRBSRRGPIO port bit set/reset register0x180x20write-only0x00000000BR15Port x reset bit y (y = 0..15)311BR14Port x reset bit y (y = 0..15)301BR13Port x reset bit y (y = 0..15)291BR12Port x reset bit y (y = 0..15)281BR11Port x reset bit y (y = 0..15)271BR10Port x reset bit y (y = 0..15)261BR9Port x reset bit y (y = 0..15)251BR8Port x reset bit y (y = 0..15)241BR7Port x reset bit y (y = 0..15)231BR6Port x reset bit y (y = 0..15)221BR5Port x reset bit y (y = 0..15)211BR4Port x reset bit y (y = 0..15)201BR3Port x reset bit y (y = 0..15)191BR2Port x reset bit y (y = 0..15)181BR1Port x reset bit y (y = 0..15)171BR0Port x set bit y (y= 0..15)161BS15Port x set bit y (y= 0..15)151BS14Port x set bit y (y= 0..15)141BS13Port x set bit y (y= 0..15)131BS12Port x set bit y (y= 0..15)121BS11Port x set bit y (y= 0..15)111BS10Port x set bit y (y= 0..15)101BS9Port x set bit y (y= 0..15)91BS8Port x set bit y (y= 0..15)81BS7Port x set bit y (y= 0..15)71BS6Port x set bit y (y= 0..15)61BS5Port x set bit y (y= 0..15)51BS4Port x set bit y (y= 0..15)41BS3Port x set bit y (y= 0..15)31BS2Port x set bit y (y= 0..15)21BS1Port x set bit y (y= 0..15)11BS0Port x set bit y (y= 0..15)01LCKRLCKRGPIO port configuration lock register0x1C0x20read-write0x00000000LCKKPort x lock bit y (y= 0..15)161LCK15Port x lock bit y (y= 0..15)151LCK14Port x lock bit y (y= 0..15)141LCK13Port x lock bit y (y= 0..15)131LCK12Port x lock bit y (y= 0..15)121LCK11Port x lock bit y (y= 0..15)111LCK10Port x lock bit y (y= 0..15)101LCK9Port x lock bit y (y= 0..15)91LCK8Port x lock bit y (y= 0..15)81LCK7Port x lock bit y (y= 0..15)71LCK6Port x lock bit y (y= 0..15)61LCK5Port x lock bit y (y= 0..15)51LCK4Port x lock bit y (y= 0..15)41LCK3Port x lock bit y (y= 0..15)31LCK2Port x lock bit y (y= 0..15)21LCK1Port x lock bit y (y= 0..15)11LCK0Port x lock bit y (y= 0..15)01AFRLAFRLGPIO alternate function low register0x200x20read-write0x00000000AFSEL7Alternate function selection for port x bit y (y = 0..7)284AFSEL6Alternate function selection for port x bit y (y = 0..7)244AFSEL5Alternate function selection for port x bit y (y = 0..7)204AFSEL4Alternate function selection for port x bit y (y = 0..7)164AFSEL3Alternate function selection for port x bit y (y = 0..7)124AFSEL2Alternate function selection for port x bit y (y = 0..7)84AFSEL1Alternate function selection for port x bit y (y = 0..7)44AFSEL0Alternate function selection for port x bit y (y = 0..7)04AFRHAFRHGPIO alternate function high register0x240x20read-write0x00000000AFSEL15Alternate function selection for port x bit y (y = 8..15)284AFSEL14Alternate function selection for port x bit y (y = 8..15)244AFSEL13Alternate function selection for port x bit y (y = 8..15)204AFSEL12Alternate function selection for port x bit y (y = 8..15)164AFSEL11Alternate function selection for port x bit y (y = 8..15)124AFSEL10Alternate function selection for port x bit y (y = 8..15)84AFSEL9Alternate function selection for port x bit y (y = 8..15)44AFSEL8Alternate function selection for port x bit y (y = 8..15)04BRRBRRport bit reset register0x280x20write-only0x00000000BR0Port Reset bit01BR1Port Reset bit11BR2Port Reset bit21BR3Port Reset bit31BR4Port Reset bit41BR5Port Reset bit51BR6Port Reset bit61BR7Port Reset bit71BR8Port Reset bit81BR9Port Reset bit91BR10Port Reset bit101BR11Port Reset bit111BR12Port Reset bit121BR13Port Reset bit131BR14Port Reset bit141BR15Port Reset bit151GPIOCGeneral-purpose I/OsGPIO0x480008000x00x400registersMODERMODERGPIO port mode register0x00x20read-write0xFFFFFFFFMODER15Port x configuration bits (y = 0..15)302MODER14Port x configuration bits (y = 0..15)282MODER13Port x configuration bits (y = 0..15)262MODER12Port x configuration bits (y = 0..15)242MODER11Port x configuration bits (y = 0..15)222MODER10Port x configuration bits (y = 0..15)202MODER9Port x configuration bits (y = 0..15)182MODER8Port x configuration bits (y = 0..15)162MODER7Port x configuration bits (y = 0..15)142MODER6Port x configuration bits (y = 0..15)122MODER5Port x configuration bits (y = 0..15)102MODER4Port x configuration bits (y = 0..15)82MODER3Port x configuration bits (y = 0..15)62MODER2Port x configuration bits (y = 0..15)42MODER1Port x configuration bits (y = 0..15)22MODER0Port x configuration bits (y = 0..15)02OTYPEROTYPERGPIO port output type register0x40x20read-write0x00000000OT15Port x configuration bits (y = 0..15)151OT14Port x configuration bits (y = 0..15)141OT13Port x configuration bits (y = 0..15)131OT12Port x configuration bits (y = 0..15)121OT11Port x configuration bits (y = 0..15)111OT10Port x configuration bits (y = 0..15)101OT9Port x configuration bits (y = 0..15)91OT8Port x configuration bits (y = 0..15)81OT7Port x configuration bits (y = 0..15)71OT6Port x configuration bits (y = 0..15)61OT5Port x configuration bits (y = 0..15)51OT4Port x configuration bits (y = 0..15)41OT3Port x configuration bits (y = 0..15)31OT2Port x configuration bits (y = 0..15)21OT1Port x configuration bits (y = 0..15)11OT0Port x configuration bits (y = 0..15)01OSPEEDROSPEEDRGPIO port output speed register0x80x20read-write0x000000C0OSPEEDR15Port x configuration bits (y = 0..15)302OSPEEDR14Port x configuration bits (y = 0..15)282OSPEEDR13Port x configuration bits (y = 0..15)262OSPEEDR12Port x configuration bits (y = 0..15)242OSPEEDR11Port x configuration bits (y = 0..15)222OSPEEDR10Port x configuration bits (y = 0..15)202OSPEEDR9Port x configuration bits (y = 0..15)182OSPEEDR8Port x configuration bits (y = 0..15)162OSPEEDR7Port x configuration bits (y = 0..15)142OSPEEDR6Port x configuration bits (y = 0..15)122OSPEEDR5Port x configuration bits (y = 0..15)102OSPEEDR4Port x configuration bits (y = 0..15)82OSPEEDR3Port x configuration bits (y = 0..15)62OSPEEDR2Port x configuration bits (y = 0..15)42OSPEEDR1Port x configuration bits (y = 0..15)22OSPEEDR0Port x configuration bits (y = 0..15)02PUPDRPUPDRGPIO port pull-up/pull-down register0xC0x20read-write0x00000100PUPDR15Port x configuration bits (y = 0..15)302PUPDR14Port x configuration bits (y = 0..15)282PUPDR13Port x configuration bits (y = 0..15)262PUPDR12Port x configuration bits (y = 0..15)242PUPDR11Port x configuration bits (y = 0..15)222PUPDR10Port x configuration bits (y = 0..15)202PUPDR9Port x configuration bits (y = 0..15)182PUPDR8Port x configuration bits (y = 0..15)162PUPDR7Port x configuration bits (y = 0..15)142PUPDR6Port x configuration bits (y = 0..15)122PUPDR5Port x configuration bits (y = 0..15)102PUPDR4Port x configuration bits (y = 0..15)82PUPDR3Port x configuration bits (y = 0..15)62PUPDR2Port x configuration bits (y = 0..15)42PUPDR1Port x configuration bits (y = 0..15)22PUPDR0Port x configuration bits (y = 0..15)02IDRIDRGPIO port input data register0x100x20read-only0x00000000IDR15Port input data (y = 0..15)151IDR14Port input data (y = 0..15)141IDR13Port input data (y = 0..15)131IDR12Port input data (y = 0..15)121IDR11Port input data (y = 0..15)111IDR10Port input data (y = 0..15)101IDR9Port input data (y = 0..15)91IDR8Port input data (y = 0..15)81IDR7Port input data (y = 0..15)71IDR6Port input data (y = 0..15)61IDR5Port input data (y = 0..15)51IDR4Port input data (y = 0..15)41IDR3Port input data (y = 0..15)31IDR2Port input data (y = 0..15)21IDR1Port input data (y = 0..15)11IDR0Port input data (y = 0..15)01ODRODRGPIO port output data register0x140x20read-write0x00000000ODR15Port output data (y = 0..15)151ODR14Port output data (y = 0..15)141ODR13Port output data (y = 0..15)131ODR12Port output data (y = 0..15)121ODR11Port output data (y = 0..15)111ODR10Port output data (y = 0..15)101ODR9Port output data (y = 0..15)91ODR8Port output data (y = 0..15)81ODR7Port output data (y = 0..15)71ODR6Port output data (y = 0..15)61ODR5Port output data (y = 0..15)51ODR4Port output data (y = 0..15)41ODR3Port output data (y = 0..15)31ODR2Port output data (y = 0..15)21ODR1Port output data (y = 0..15)11ODR0Port output data (y = 0..15)01BSRRBSRRGPIO port bit set/reset register0x180x20write-only0x00000000BR15Port x reset bit y (y = 0..15)311BR14Port x reset bit y (y = 0..15)301BR13Port x reset bit y (y = 0..15)291BR12Port x reset bit y (y = 0..15)281BR11Port x reset bit y (y = 0..15)271BR10Port x reset bit y (y = 0..15)261BR9Port x reset bit y (y = 0..15)251BR8Port x reset bit y (y = 0..15)241BR7Port x reset bit y (y = 0..15)231BR6Port x reset bit y (y = 0..15)221BR5Port x reset bit y (y = 0..15)211BR4Port x reset bit y (y = 0..15)201BR3Port x reset bit y (y = 0..15)191BR2Port x reset bit y (y = 0..15)181BR1Port x reset bit y (y = 0..15)171BR0Port x set bit y (y= 0..15)161BS15Port x set bit y (y= 0..15)151BS14Port x set bit y (y= 0..15)141BS13Port x set bit y (y= 0..15)131BS12Port x set bit y (y= 0..15)121BS11Port x set bit y (y= 0..15)111BS10Port x set bit y (y= 0..15)101BS9Port x set bit y (y= 0..15)91BS8Port x set bit y (y= 0..15)81BS7Port x set bit y (y= 0..15)71BS6Port x set bit y (y= 0..15)61BS5Port x set bit y (y= 0..15)51BS4Port x set bit y (y= 0..15)41BS3Port x set bit y (y= 0..15)31BS2Port x set bit y (y= 0..15)21BS1Port x set bit y (y= 0..15)11BS0Port x set bit y (y= 0..15)01LCKRLCKRGPIO port configuration lock register0x1C0x20read-write0x00000000LCKKPort x lock bit y (y= 0..15)161LCK15Port x lock bit y (y= 0..15)151LCK14Port x lock bit y (y= 0..15)141LCK13Port x lock bit y (y= 0..15)131LCK12Port x lock bit y (y= 0..15)121LCK11Port x lock bit y (y= 0..15)111LCK10Port x lock bit y (y= 0..15)101LCK9Port x lock bit y (y= 0..15)91LCK8Port x lock bit y (y= 0..15)81LCK7Port x lock bit y (y= 0..15)71LCK6Port x lock bit y (y= 0..15)61LCK5Port x lock bit y (y= 0..15)51LCK4Port x lock bit y (y= 0..15)41LCK3Port x lock bit y (y= 0..15)31LCK2Port x lock bit y (y= 0..15)21LCK1Port x lock bit y (y= 0..15)11LCK0Port x lock bit y (y= 0..15)01AFRLAFRLGPIO alternate function low register0x200x20read-write0x00000000AFSEL7Alternate function selection for port x bit y (y = 0..7)284AFSEL6Alternate function selection for port x bit y (y = 0..7)244AFSEL5Alternate function selection for port x bit y (y = 0..7)204AFSEL4Alternate function selection for port x bit y (y = 0..7)164AFSEL3Alternate function selection for port x bit y (y = 0..7)124AFSEL2Alternate function selection for port x bit y (y = 0..7)84AFSEL1Alternate function selection for port x bit y (y = 0..7)44AFSEL0Alternate function selection for port x bit y (y = 0..7)04AFRHAFRHGPIO alternate function high register0x240x20read-write0x00000000AFSEL15Alternate function selection for port x bit y (y = 8..15)284AFSEL14Alternate function selection for port x bit y (y = 8..15)244AFSEL13Alternate function selection for port x bit y (y = 8..15)204AFSEL12Alternate function selection for port x bit y (y = 8..15)164AFSEL11Alternate function selection for port x bit y (y = 8..15)124AFSEL10Alternate function selection for port x bit y (y = 8..15)84AFSEL9Alternate function selection for port x bit y (y = 8..15)44AFSEL8Alternate function selection for port x bit y (y = 8..15)04BRRBRRport bit reset register0x280x20write-only0x00000000BR0Port Reset bit01BR1Port Reset bit11BR2Port Reset bit21BR3Port Reset bit31BR4Port Reset bit41BR5Port Reset bit51BR6Port Reset bit61BR7Port Reset bit71BR8Port Reset bit81BR9Port Reset bit91BR10Port Reset bit101BR11Port Reset bit111BR12Port Reset bit121BR13Port Reset bit131BR14Port Reset bit141BR15Port Reset bit151GPIOD0x48000C00GPIOEGeneral-purpose I/OsGPIO0x480010000x00x400registersMODERMODERGPIO port mode register0x00x20read-write0x000003FFMODER4Port x configuration bits (y = 0..15)82MODER3Port x configuration bits (y = 0..15)62MODER2Port x configuration bits (y = 0..15)42MODER1Port x configuration bits (y = 0..15)22MODER0Port x configuration bits (y = 0..15)02OTYPEROTYPERGPIO port output type register0x40x20read-write0x00000000OT4Port x configuration bits (y = 0..15)41OT3Port x configuration bits (y = 0..15)31OT2Port x configuration bits (y = 0..15)21OT1Port x configuration bits (y = 0..15)11OT0Port x configuration bits (y = 0..15)01OSPEEDROSPEEDRGPIO port output speed register0x80x20read-write0x000000C0OSPEEDR4Port x configuration bits (y = 0..15)82OSPEEDR3Port x configuration bits (y = 0..15)62OSPEEDR2Port x configuration bits (y = 0..15)42OSPEEDR1Port x configuration bits (y = 0..15)22OSPEEDR0Port x configuration bits (y = 0..15)02PUPDRPUPDRGPIO port pull-up/pull-down register0xC0x20read-write0x00000000PUPDR4Port x configuration bits (y = 0..15)82PUPDR3Port x configuration bits (y = 0..15)62PUPDR2Port x configuration bits (y = 0..15)42PUPDR1Port x configuration bits (y = 0..15)22PUPDR0Port x configuration bits (y = 0..15)02IDRIDRGPIO port input data register0x100x20read-only0x00000000IDR4Port input data (y = 0..15)41IDR3Port input data (y = 0..15)31IDR2Port input data (y = 0..15)21IDR1Port input data (y = 0..15)11IDR0Port input data (y = 0..15)01ODRODRGPIO port output data register0x140x20read-write0x00000000ODR4Port output data (y = 0..15)41ODR3Port output data (y = 0..15)31ODR2Port output data (y = 0..15)21ODR1Port output data (y = 0..15)11ODR0Port output data (y = 0..15)01BSRRBSRRGPIO port bit set/reset register0x180x20write-only0x00000000BR4Port x reset bit y (y = 0..15)201BR3Port x reset bit y (y = 0..15)191BR2Port x reset bit y (y = 0..15)181BR1Port x reset bit y (y = 0..15)171BR0Port x set bit y (y= 0..15)161BS4Port x set bit y (y= 0..15)41BS3Port x set bit y (y= 0..15)31BS2Port x set bit y (y= 0..15)21BS1Port x set bit y (y= 0..15)11BS0Port x set bit y (y= 0..15)01LCKRLCKRGPIO port configuration lock register0x1C0x20read-write0x00000000LCKKPort x lock bit y (y= 0..15)161LCK4Port x lock bit y (y= 0..15)41LCK3Port x lock bit y (y= 0..15)31LCK2Port x lock bit y (y= 0..15)21LCK1Port x lock bit y (y= 0..15)11LCK0Port x lock bit y (y= 0..15)01AFRLAFRLGPIO alternate function low register0x200x20read-write0x00000000AFSEL4Alternate function selection for port x bit y (y = 0..7)164AFSEL3Alternate function selection for port x bit y (y = 0..7)124AFSEL2Alternate function selection for port x bit y (y = 0..7)84AFSEL1Alternate function selection for port x bit y (y = 0..7)44AFSEL0Alternate function selection for port x bit y (y = 0..7)04AFRHAFRHGPIO alternate function high register0x240x20read-write0x00000000AFSEL15Alternate function selection for port x bit y (y = 8..15)284AFSEL14Alternate function selection for port x bit y (y = 8..15)244AFSEL13Alternate function selection for port x bit y (y = 8..15)204AFSEL12Alternate function selection for port x bit y (y = 8..15)164AFSEL11Alternate function selection for port x bit y (y = 8..15)124AFSEL10Alternate function selection for port x bit y (y = 8..15)84AFSEL9Alternate function selection for port x bit y (y = 8..15)44AFSEL8Alternate function selection for port x bit y (y = 8..15)04BRRBRRport bit reset register0x280x20write-only0x00000000BR0Port Reset bit01BR1Port Reset bit11BR2Port Reset bit21BR3Port Reset bit31BR4Port Reset bit41GPIOHGeneral-purpose I/OsGPIO0x48001C000x00x400registersMODERMODERGPIO port mode register0x00x20read-write0x000000CFMODER3Port x configuration bits (y = 0..15)62MODER1Port x configuration bits (y = 0..15)22MODER0Port x configuration bits (y = 0..15)02OTYPEROTYPERGPIO port output type register0x40x20read-write0x00000000OT3Port x configuration bits (y = 0..15)31OT1Port x configuration bits (y = 0..15)11OT0Port x configuration bits (y = 0..15)01OSPEEDROSPEEDRGPIO port output speed register0x80x20read-write0x00000000OSPEEDR3Port x configuration bits (y = 0..15)62OSPEEDR1Port x configuration bits (y = 0..15)22OSPEEDR0Port x configuration bits (y = 0..15)02PUPDRPUPDRGPIO port pull-up/pull-down register0xC0x20read-write0x00000000PUPDR3Port x configuration bits (y = 0..15)62PUPDR1Port x configuration bits (y = 0..15)22PUPDR0Port x configuration bits (y = 0..15)02IDRIDRGPIO port input data register0x100x20read-only0x00000000IDR3Port input data (y = 0..15)31IDR1Port input data (y = 0..15)11IDR0Port input data (y = 0..15)01ODRODRGPIO port output data register0x140x20read-write0x00000000ODR3Port output data (y = 0..15)31ODR1Port output data (y = 0..15)11ODR0Port output data (y = 0..15)01BSRRBSRRGPIO port bit set/reset register0x180x20write-only0x00000000BR3Port x reset bit y (y = 0..15)191BR1Port x reset bit y (y = 0..15)171BR0Port x set bit y (y= 0..15)161BS3Port x set bit y (y= 0..15)31BS1Port x set bit y (y= 0..15)11BS0Port x set bit y (y= 0..15)01LCKRLCKRGPIO port configuration lock register0x1C0x20read-write0x00000000LCKKPort x lock bit y (y= 0..15)161LCK3Port x lock bit y (y= 0..15)31LCK1Port x lock bit y (y= 0..15)11LCK0Port x lock bit y (y= 0..15)01AFRLAFRLGPIO alternate function low register0x200x20read-write0x00000000AFSEL3Alternate function selection for port x bit y (y = 0..7)124AFSEL1Alternate function selection for port x bit y (y = 0..7)44AFSEL0Alternate function selection for port x bit y (y = 0..7)04AFRHAFRHGPIO alternate function high register0x240x20read-write0x00000000AFSEL15Alternate function selection for port x bit y (y = 8..15)284AFSEL14Alternate function selection for port x bit y (y = 8..15)244AFSEL13Alternate function selection for port x bit y (y = 8..15)204AFSEL12Alternate function selection for port x bit y (y = 8..15)164AFSEL11Alternate function selection for port x bit y (y = 8..15)124AFSEL10Alternate function selection for port x bit y (y = 8..15)84AFSEL9Alternate function selection for port x bit y (y = 8..15)44AFSEL8Alternate function selection for port x bit y (y = 8..15)04BRRBRRport bit reset register0x280x20write-only0x00000000BR0Port Reset bit01BR1Port Reset bit11BR3Port Reset bit31SAI1Serial audio interfaceSAI0x400154000x00x400registersSAI1SAI1 global interrupt38GCRGCRGlobal configuration register0x00x20read-write0x00000000SYNCOUTSynchronization outputs42SYNCINSynchronization inputs02BCR1BCR1BConfiguration register 10x240x20read-write0x00000040MCKENMaster clock generation enable271OSROversampling ratio for master clock261MCJDIVMaster clock divider206NODIVNo divider191DMAENDMA enable171SAIBENAudio block B enable161OutDriOutput drive131MONOMono mode121SYNCENSynchronization enable102CKSTRClock strobing edge91LSBFIRSTLeast significant bit first81DSData size53PRTCFGProtocol configuration22MODEAudio block mode02BCR2BCR2BConfiguration register 20x280x20read-write0x00000000COMPCompanding mode142CPLComplement bit131MUTECNMute counter76MUTEVALMute value61MUTEMute51TRISTristate management on data line41FFLUSFIFO flush31FTHFIFO threshold03BFRCRBFRCRBFRCR0x2C0x20read-write0x00000007FSOFFFrame synchronization offset181FSPOLFrame synchronization polarity171FSDEFFrame synchronization definition161FSALLFrame synchronization active level length87FRLFrame length08BSLOTRBSLOTRBSlot register0x300x20read-write0x00000000SLOTENSlot enable1616NBSLOTNumber of slots in an audio frame84SLOTSZSlot size62FBOFFFirst bit offset05BIMBIMBInterrupt mask register20x340x20read-write0x00000000LFSDETIELate frame synchronization detection interrupt enable61AFSDETIEAnticipated frame synchronization detection interrupt enable51CNRDYIECodec not ready interrupt enable41FREQIEFIFO request interrupt enable31WCKCFGWrong clock configuration interrupt enable21MUTEDETMute detection interrupt enable11OVRUDRIEOverrun/underrun interrupt enable01BSRBSRBStatus register0x380x20read-only0x00000008FLVLFIFO level threshold163LFSDETLate frame synchronization detection61AFSDETAnticipated frame synchronization detection51CNRDYCodec not ready41FREQFIFO request31WCKCFGWrong clock configuration flag21MUTEDETMute detection11OVRUDROverrun / underrun01BCLRFRBCLRFRBClear flag register0x3C0x20write-only0x00000000LFSDETClear late frame synchronization detection flag61CAFSDETClear anticipated frame synchronization detection flag51CNRDYClear codec not ready flag41WCKCFGClear wrong clock configuration flag21MUTEDETMute detection flag11OVRUDRClear overrun / underrun01BDRBDRBData register0x400x20read-write0x00000000DATAData032ACR1ACR1AConfiguration register 10x40x20read-write0x00000040MCKENMaster clock generation enable271OSROversampling ratio for master clock261MCJDIVMaster clock divider206NODIVNo divider191DMAENDMA enable171SAIBENAudio block B enable161OutDriOutput drive131MONOMono mode121SYNCENSynchronization enable102CKSTRClock strobing edge91LSBFIRSTLeast significant bit first81DSData size53PRTCFGProtocol configuration22MODEAudio block mode02ACR2ACR2AConfiguration register 20x80x20read-write0x00000000COMPCompanding mode142CPLComplement bit131MUTECNMute counter76MUTEVALMute value61MUTEMute51TRISTristate management on data line41FFLUSFIFO flush31FTHFIFO threshold03AFRCRAFRCRAFRCR0xC0x20read-write0x00000007FSOFFFrame synchronization offset181FSPOLFrame synchronization polarity171FSDEFFrame synchronization definition161FSALLFrame synchronization active level length87FRLFrame length08ASLOTRASLOTRASlot register0x100x20read-write0x00000000SLOTENSlot enable1616NBSLOTNumber of slots in an audio frame84SLOTSZSlot size62FBOFFFirst bit offset05AIMAIMAInterrupt mask register20x140x20read-write0x00000000LFSDETLate frame synchronization detection interrupt enable61AFSDETIEAnticipated frame synchronization detection interrupt enable51CNRDYIECodec not ready interrupt enable41FREQIEFIFO request interrupt enable31WCKCFGWrong clock configuration interrupt enable21MUTEDETMute detection interrupt enable11OVRUDRIEOverrun/underrun interrupt enable01ASRASRAStatus register0x180x20read-only0x00000008FLVLFIFO level threshold163LFSDETLate frame synchronization detection61AFSDETAnticipated frame synchronization detection51CNRDYCodec not ready41FREQFIFO request31WCKCFGWrong clock configuration flag. This bit is read only21MUTEDETMute detection11OVRUDROverrun / underrun01ACLRFRACLRFRAClear flag register0x1C0x20write-only0x00000000LFSDETClear late frame synchronization detection flag61CAFSDETClear anticipated frame synchronization detection flag51CNRDYClear codec not ready flag41WCKCFGClear wrong clock configuration flag21MUTEDETMute detection flag11OVRUDRClear overrun / underrun01ADRADRAData register0x200x20read-write0x00000000DATAData032PDMCRPDMCRPDM control register0x440x20read-write0x00000000CKEN4Clock enable of bitstream clock number 4111CKEN3Clock enable of bitstream clock number 3101CKEN2Clock enable of bitstream clock number 291CKEN1Clock enable of bitstream clock number 181MICNBRNumber of microphones42PDMENPDM enable01PDMDLYPDMDLYPDM delay register0x480x20read-write0x00000000DLYM4RDelay line for second microphone of pair 4283DLYM4LDelay line for first microphone of pair 4243DLYM3RDelay line for second microphone of pair 3203DLYM3LDelay line for first microphone of pair 3163DLYM2RDelay line for second microphone of pair 2123DLYM2LDelay line for first microphone of pair 283DLYM1RDelay line for second microphone of pair 143DLYM1LDelay line for first microphone of pair 103TIM2General-purpose-timersTIM0x400000000x00x400registersTIM2TIM2 global interrupt28CR1CR1control register 10x00x20read-write0x0000UIFREMAPUIF status bit remapping111CKDClock division82ARPEAuto-reload preload enable71CMSCenter-aligned mode selection52DIRDirection41OPMOne-pulse mode31URSUpdate request source21UDISUpdate disable11CENCounter enable01CR2CR2control register 20x40x20read-write0x0000TI1STI1 selection71MMSMaster mode selection43CCDSCapture/compare DMA selection31SMCRSMCRslave mode control register0x80x20read-write0x0000SMS_3Slave mode selection - bit 3161ETPExternal trigger polarity151ECEExternal clock enable141ETPSExternal trigger prescaler122ETFExternal trigger filter84MSMMaster/Slave mode71TSTrigger selection43OCCSOCREF clear selection31SMSSlave mode selection03DIERDIERDMA/Interrupt enable register0xC0x20read-write0x0000CC4DECapture/Compare 4 DMA request enable121CC3DECapture/Compare 3 DMA request enable111CC2DECapture/Compare 2 DMA request enable101CC1DECapture/Compare 1 DMA request enable91UDEUpdate DMA request enable81TIETrigger interrupt enable61CC4IECapture/Compare 4 interrupt enable41CC3IECapture/Compare 3 interrupt enable31CC2IECapture/Compare 2 interrupt enable21CC1IECapture/Compare 1 interrupt enable11UIEUpdate interrupt enable01SRSRstatus register0x100x20read-write0x0000CC4OFCapture/Compare 4 overcapture flag121CC3OFCapture/Compare 3 overcapture flag111CC2OFCapture/compare 2 overcapture flag101CC1OFCapture/Compare 1 overcapture flag91TIFTrigger interrupt flag61CC4IFCapture/Compare 4 interrupt flag41CC3IFCapture/Compare 3 interrupt flag31CC2IFCapture/Compare 2 interrupt flag21CC1IFCapture/compare 1 interrupt flag11UIFUpdate interrupt flag01EGREGRevent generation register0x140x20write-only0x0000TGTrigger generation61CC4GCapture/compare 4 generation41CC3GCapture/compare 3 generation31CC2GCapture/compare 2 generation21CC1GCapture/compare 1 generation11UGUpdate generation01CCMR1_OutputCCMR1_Outputcapture/compare mode register 1 (output mode)0x180x20read-write0x00000000OC2M_3Output Compare 2 mode - bit 3241OC1M_3Output Compare 1 mode - bit 3161OC2CEOutput compare 2 clear enable151OC2MOutput compare 2 mode123OC2PEOutput compare 2 preload enable111OC2FEOutput compare 2 fast enable101CC2SCapture/Compare 2 selection82OC1CEOutput compare 1 clear enable71OC1MOutput compare 1 mode43OC1PEOutput compare 1 preload enable31OC1FEOutput compare 1 fast enable21CC1SCapture/Compare 1 selection02CCMR1_InputCCMR1_Inputcapture/compare mode register 1 (input mode)CCMR1_Output0x180x20read-write0x00000000IC2FInput capture 2 filter124IC2PSCInput capture 2 prescaler102CC2SCapture/compare 2 selection82IC1FInput capture 1 filter44IC1PSCInput capture 1 prescaler22CC1SCapture/Compare 1 selection02CCMR2_OutputCCMR2_Outputcapture/compare mode register 2 (output mode)0x1C0x20read-write0x00000000OC4M_3Output Compare 4 mode - bit 3241OC3M_3Output Compare 3 mode - bit 3161OC4CEOutput compare 4 clear enable151OC4MOutput compare 4 mode123OC4PEOutput compare 4 preload enable111OC4FEOutput compare 4 fast enable101CC4SCapture/Compare 4 selection82OC3CEOutput compare 3 clear enable71OC3MOutput compare 3 mode43OC3PEOutput compare 3 preload enable31OC3FEOutput compare 3 fast enable21CC3SCapture/Compare 3 selection02CCMR2_InputCCMR2_Inputcapture/compare mode register 2 (input mode)CCMR2_Output0x1C0x20read-write0x00000000IC4FInput capture 4 filter124IC4PSCInput capture 4 prescaler102CC4SCapture/Compare 4 selection82IC3FInput capture 3 filter44IC3PSCInput capture 3 prescaler22CC3SCapture/Compare 3 selection02CCERCCERcapture/compare enable register0x200x20read-write0x0000CC4NPCapture/Compare 4 output Polarity151CC4PCapture/Compare 3 output Polarity131CC4ECapture/Compare 4 output enable121CC3NPCapture/Compare 3 output Polarity111CC3PCapture/Compare 3 output Polarity91CC3ECapture/Compare 3 output enable81CC2NPCapture/Compare 2 output Polarity71CC2PCapture/Compare 2 output Polarity51CC2ECapture/Compare 2 output enable41CC1NPCapture/Compare 1 output Polarity31CC1PCapture/Compare 1 output Polarity11CC1ECapture/Compare 1 output enable01CNTCNTcounter0x240x200x00000000CNT_HHigh counter value (TIM2 only)1615read-writeCNT_LLow counter value016read-writeUIFCPYValue depends on IUFREMAP in TIM2_CR1.311read-onlyPSCPSCprescaler0x280x20read-write0x0000PSCPrescaler value016ARRARRauto-reload register0x2C0x20read-write0x00000000ARR_HHigh Auto-reload value (TIM2 only)1616ARR_LLow Auto-reload value016CCR1CCR1capture/compare register 10x340x20read-write0x00000000CCR1_HHigh Capture/Compare 1 value (TIM2 only)1616CCR1_LLow Capture/Compare 1 value016CCR2CCR2capture/compare register 20x380x20read-write0x00000000CCR2_HHigh Capture/Compare 2 value (TIM2 only)1616CCR2_LLow Capture/Compare 2 value016CCR3CCR3capture/compare register 30x3C0x20read-write0x00000000CCR3_HHigh Capture/Compare value (TIM2 only)1616CCR3_LLow Capture/Compare value016CCR4CCR4capture/compare register 40x400x20read-write0x00000000CCR4_HHigh Capture/Compare value (TIM2 only)1616CCR4_LLow Capture/Compare value016DCRDCRDMA control register0x480x20read-write0x0000DBLDMA burst length85DBADMA base address05DMARDMARDMA address for full transfer0x4C0x20read-write0x0000DMABDMA register for burst accesses016ORORTIM2 option register0x500x20read-write0x0000TI4_RMPInput capture 4 remap22ETR_RMPExternal trigger remap11ITR_RMPInternal trigger remap01AFAFTIM2 alternate function option register 10x600x20read-write0x0000ETRSELExternal trigger source selection143TIM16General purpose timersTIM0x400144000x00x400registersCR1CR1control register 10x00x20read-write0x0000CENCounter enable01UDISUpdate disable11URSUpdate request source21OPMOne-pulse mode31ARPEAuto-reload preload enable71CKDClock division82UIFREMAPUIF status bit remapping111CR2CR2control register 20x40x20read-write0x0000OIS1NOutput Idle state 191OIS1Output Idle state 181CCDSCapture/compare DMA selection31CCUSCapture/compare control update selection21CCPCCapture/compare preloaded control01DIERDIERDMA/Interrupt enable register0xC0x20read-write0x0000UIEUpdate interrupt enable01CC1IECapture/Compare 1 interrupt enable11COMIECOM interrupt enable51BIEBreak interrupt enable71UDEUpdate DMA request enable81CC1DECapture/Compare 1 DMA request enable91SRSRstatus register0x100x20read-write0x0000CC1OFCapture/Compare 1 overcapture flag91BIFBreak interrupt flag71COMIFCOM interrupt flag51CC1IFCapture/compare 1 interrupt flag11UIFUpdate interrupt flag01EGREGRevent generation register0x140x20write-only0x0000BGBreak generation71COMGCapture/Compare control update generation51CC1GCapture/compare 1 generation11UGUpdate generation01CCMR1_OutputCCMR1_Outputcapture/compare mode register (output mode)0x180x20read-write0x00000000OC1M_3Output Compare 1 mode161OC1MOutput Compare 1 mode43OC1PEOutput Compare 1 preload enable31OC1FEOutput Compare 1 fast enable21CC1SCapture/Compare 1 selection02CCMR1_InputCCMR1_Inputcapture/compare mode register 1 (input mode)CCMR1_Output0x180x20read-write0x00000000IC1FInput capture 1 filter44IC1PSCInput capture 1 prescaler22CC1SCapture/Compare 1 selection02CCERCCERcapture/compare enable register0x200x20read-write0x0000CC1NPCapture/Compare 1 output Polarity31CC1NECapture/Compare 1 complementary output enable21CC1PCapture/Compare 1 output Polarity11CC1ECapture/Compare 1 output enable01CNTCNTcounter0x240x200x00000000CNTcounter value016read-writeUIFCPYUIF Copy311read-onlyPSCPSCprescaler0x280x20read-write0x0000PSCPrescaler value016ARRARRauto-reload register0x2C0x20read-write0xFFFFARRAuto-reload value016RCRRCRrepetition counter register0x300x20read-write0x0000REPRepetition counter value08CCR1CCR1capture/compare register 10x340x20read-write0x00000000CCR1Capture/Compare 1 value016BDTRBDTRbreak and dead-time register0x440x20read-write0x0000DTGDead-time generator setup08LOCKLock configuration82OSSIOff-state selection for Idle mode101OSSROff-state selection for Run mode111BKEBreak enable121BKPBreak polarity131AOEAutomatic output enable141MOEMain output enable151BKDSRMBreak Disarm261BKBIDBreak Bidirectional281DCRDCRDMA control register0x480x20read-write0x0000DBLDMA burst length85DBADMA base address05DMARDMARDMA address for full transfer0x4C0x20read-write0x0000DMABDMA register for burst accesses016OR1OR1TIM option register 10x500x20read-write0x0000TI1_RMPInput capture 1 remap02AF1AF1alternate function register 10x600x20read-write0x00000001BKINEBRK BKIN input enable01BKCMP1EBRK COMP1 enable11BKCMP2EBRK COMP2 enable21BKINPBRK BKIN input polarity91BKCMP1PBRK COMP1 input polarity101BKCMP2PBRK COMP2 input polarit111TISELTISELinput selection register0x680x20read-write0x00000000TI1SELselects TI1[0] to TI1[15] input04TIM17General purpose timersTIM0x400148000x00x400registersCR1CR1control register 10x00x20read-write0x0000CENCounter enable01UDISUpdate disable11URSUpdate request source21OPMOne-pulse mode31ARPEAuto-reload preload enable71CKDClock division82UIFREMAPUIF status bit remapping111CR2CR2control register 20x40x20read-write0x0000OIS1NOutput Idle state 191OIS1Output Idle state 181CCDSCapture/compare DMA selection31CCUSCapture/compare control update selection21CCPCCapture/compare preloaded control01DIERDIERDMA/Interrupt enable register0xC0x20read-write0x0000UIEUpdate interrupt enable01CC1IECapture/Compare 1 interrupt enable11COMIECOM interrupt enable51BIEBreak interrupt enable71UDEUpdate DMA request enable81CC1DECapture/Compare 1 DMA request enable91SRSRstatus register0x100x20read-write0x0000CC1OFCapture/Compare 1 overcapture flag91BIFBreak interrupt flag71COMIFCOM interrupt flag51CC1IFCapture/compare 1 interrupt flag11UIFUpdate interrupt flag01EGREGRevent generation register0x140x20write-only0x0000BGBreak generation71COMGCapture/Compare control update generation51CC1GCapture/compare 1 generation11UGUpdate generation01CCMR1_OutputCCMR1_Outputcapture/compare mode register (output mode)0x180x20read-write0x00000000OC1M_3Output Compare 1 mode161OC1MOutput Compare 1 mode43OC1PEOutput Compare 1 preload enable31OC1FEOutput Compare 1 fast enable21CC1SCapture/Compare 1 selection02CCMR1_InputCCMR1_Inputcapture/compare mode register 1 (input mode)CCMR1_Output0x180x20read-write0x00000000IC1FInput capture 1 filter44IC1PSCInput capture 1 prescaler22CC1SCapture/Compare 1 selection02CCERCCERcapture/compare enable register0x200x20read-write0x0000CC1NPCapture/Compare 1 output Polarity31CC1NECapture/Compare 1 complementary output enable21CC1PCapture/Compare 1 output Polarity11CC1ECapture/Compare 1 output enable01CNTCNTcounter0x240x200x00000000CNTcounter value016read-writeUIFCPYUIF Copy311read-onlyPSCPSCprescaler0x280x20read-write0x0000PSCPrescaler value016ARRARRauto-reload register0x2C0x20read-write0xFFFFARRAuto-reload value016RCRRCRrepetition counter register0x300x20read-write0x0000REPRepetition counter value08CCR1CCR1capture/compare register 10x340x20read-write0x00000000CCR1Capture/Compare 1 value016BDTRBDTRbreak and dead-time register0x440x20read-write0x0000DTGDead-time generator setup08LOCKLock configuration82OSSIOff-state selection for Idle mode101OSSROff-state selection for Run mode111BKEBreak enable121BKPBreak polarity131AOEAutomatic output enable141MOEMain output enable151BKDSRMBreak Disarm261BKBIDBreak Bidirectional281DCRDCRDMA control register0x480x20read-write0x0000DBLDMA burst length85DBADMA base address05DMARDMARDMA address for full transfer0x4C0x20read-write0x0000DMABDMA register for burst accesses016OR1OR1TIM option register 10x500x20read-write0x0000TI1_RMPInput capture 1 remap02AF1AF1alternate function register 10x600x20read-write0x00000001BKINEBRK BKIN input enable01BKCMP1EBRK COMP1 enable11BKCMP2EBRK COMP2 enable21BKINPBRK BKIN input polarity91BKCMP1PBRK COMP1 input polarity101BKCMP2PBRK COMP2 input polarit111TISELTISELinput selection register0x680x20read-write0x00000000TI1SELselects TI1[0] to TI1[15] input04TIM1Advanced-timersTIM0x40012C000x00x400registersTIM1_BRKTimer 1 break interrupt24TIM1_UPTimer 1 Update25TIM1_TRG_COM_TIM17TIM1 Trigger and Commutation interrupts and + TIM17 global interrupt26TIM1_CCTIM1 Capture Compare interrupt27CR1CR1control register 10x00x20read-write0x0000CENCounter enable01OPMOne-pulse mode31UDISUpdate disable11URSUpdate request source21DIRDirection41CMSCenter-aligned mode selection52ARPEAuto-reload preload enable71CKDClock division82UIFREMAPUIF status bit remapping111CR2CR2control register 20x40x20read-write0x0000MMS2Master mode selection 2204OIS6Output Idle state 6 (OC6 output)181OIS5Output Idle state 5 (OC5 output)161OIS4Output Idle state 4141OIS3NOutput Idle state 3131OIS3Output Idle state 3121OIS2NOutput Idle state 2111OIS2Output Idle state 2101OIS1NOutput Idle state 191OIS1Output Idle state 181TI1STI1 selection71MMSMaster mode selection43CCDSCapture/compare DMA selection31CCUSCapture/compare control update selection21CCPCCapture/compare preloaded control01SMCRSMCRslave mode control register0x80x20read-write0x0000SMSSlave mode selection03OCCSOCREF clear selection31TSTrigger selection43MSMMaster/Slave mode71ETFExternal trigger filter84ETPSExternal trigger prescaler122ECEExternal clock enable141ETPExternal trigger polarity151SMS_3Slave mode selection - bit 3161DIERDIERDMA/Interrupt enable register0xC0x20read-write0x0000UIEUpdate interrupt enable01CC1IECapture/Compare 1 interrupt enable11CC2IECapture/Compare 2 interrupt enable21CC3IECapture/Compare 3 interrupt enable31CC4IECapture/Compare 4 interrupt enable41COMIECOM interrupt enable51TIETrigger interrupt enable61BIEBreak interrupt enable71UDEUpdate DMA request enable81CC1DECapture/Compare 1 DMA request enable91CC2DECapture/Compare 2 DMA request enable101CC3DECapture/Compare 3 DMA request enable111CC4DECapture/Compare 4 DMA request enable121COMDECOM DMA request enable131TDETrigger DMA request enable141SRSRstatus register0x100x20read-write0x0000UIFUpdate interrupt flag01CC1IFCapture/compare 1 interrupt flag11CC2IFCapture/Compare 2 interrupt flag21CC3IFCapture/Compare 3 interrupt flag31CC4IFCapture/Compare 4 interrupt flag41COMIFCOM interrupt flag51TIFTrigger interrupt flag61BIFBreak interrupt flag71B2IFBreak 2 interrupt flag81CC1OFCapture/Compare 1 overcapture flag91CC2OFCapture/compare 2 overcapture flag101CC3OFCapture/Compare 3 overcapture flag111CC4OFCapture/Compare 4 overcapture flag121SBIFSystem Break interrupt flag131CC5IFCompare 5 interrupt flag161CC6IFCompare 6 interrupt flag171EGREGRevent generation register0x140x20write-only0x0000UGUpdate generation01CC1GCapture/compare 1 generation11CC2GCapture/compare 2 generation21CC3GCapture/compare 3 generation31CC4GCapture/compare 4 generation41COMGCapture/Compare control update generation51TGTrigger generation61BGBreak generation71B2GBreak 2 generation81CCMR1_InputCCMR1_Inputcapture/compare mode register 1 (output mode)0x180x20read-write0x00000000CC1SCapture/Compare 1 selection02IC1PSCInput capture 1 prescaler22C1FInput capture 1 filter44CC2Scapture/Compare 2 selection82IC2PSCInput capture 2 prescaler102IC2FInput capture 2 filter124CCMR1_OutputCCMR1_Outputcapture/compare mode register 1 (output mode)CCMR1_Input0x180x20read-write0x00000000CC1SCapture/Compare 1 selection02OC1FEOutput Compare 1 fast enable21OC1PEOutput Compare 1 preload enable31OC1MOutput Compare 1 mode43OC1CEOutput Compare 1 clear enable71CC2SCapture/Compare 2 selection82OC2FEOutput Compare 2 fast enable101OC2PEOutput Compare 2 preload enable111OC2MOutput Compare 2 mode123OC2CEOutput Compare 2 clear enable151OC1M_3Output Compare 1 mode - bit 3161OC2M_3Output Compare 2 mode - bit 3241CCMR2_OutputCCMR2_Outputcapture/compare mode register 2 (output mode)0x1C0x20read-write0x00000000CC3SCapture/Compare 3 selection02OC3FEOutput compare 3 fast enable21OC3PEOutput compare 3 preload enable31OC3MOutput compare 3 mode43OC3CEOutput compare 3 clear enable71CC4SCapture/Compare 4 selection82OC4FEOutput compare 4 fast enable101OC4PEOutput compare 4 preload enable111OC4MOutput compare 4 mode123OC4CEOutput compare 4 clear enable151OC3M_3Output Compare 3 mode - bit 3161OC4M_3Output Compare 4 mode - bit 3241CCMR2_InputCCMR2_Inputcapture/compare mode register 2 (output mode)CCMR2_Output0x1C0x20read-write0x00000000CC3SCapture/Compare 3 selection02C3PSCInput capture 3 prescaler22IC3FInput capture 3 filter44CC4SCapture/Compare 4 selection82IC4PSCInput capture 4 prescaler102IC4FInput capture 4 filter124CCERCCERcapture/compare enable register0x200x20read-write0x0000CC1ECapture/Compare 1 output enable01CC1PCapture/Compare 1 output Polarity11CC1NECapture/Compare 1 complementary output enable21CC1NPCapture/Compare 1 output Polarity31CC2ECapture/Compare 2 output enable41CC2PCapture/Compare 2 output Polarity51CC2NECapture/Compare 2 complementary output enable61CC2NPCapture/Compare 2 output Polarity71CC3ECapture/Compare 3 output enable81CC3PCapture/Compare 3 output Polarity91CC3NECapture/Compare 3 complementary output enable101CC3NPCapture/Compare 3 output Polarity111CC4ECapture/Compare 4 output enable121CC4PCapture/Compare 3 output Polarity131CC4NPCapture/Compare 4 complementary output polarity151CC5ECapture/Compare 5 output enable161CC5PCapture/Compare 5 output polarity171CC6ECapture/Compare 6 output enable201CC6PCapture/Compare 6 output polarity211CNTCNTcounter0x240x200x00000000CNTcounter value016read-writeUIFCPYUIF copy311read-onlyPSCPSCprescaler0x280x20read-write0x0000PSCPrescaler value016ARRARRauto-reload register0x2C0x20read-write0x0000FFFFARRAuto-reload value016RCRRCRrepetition counter register0x300x20read-write0x0000REPRepetition counter value016CCR1CCR1capture/compare register 10x340x20read-write0x00000000CCR1Capture/Compare 1 value016CCR2CCR2capture/compare register 20x380x20read-write0x00000000CCR2Capture/Compare 2 value016CCR3CCR3capture/compare register 30x3C0x20read-write0x00000000CCR3Capture/Compare value016CCR4CCR4capture/compare register 40x400x20read-write0x00000000CCR4Capture/Compare value016BDTRBDTRbreak and dead-time register0x440x20read-write0x0000DTGDead-time generator setup08LOCKLock configuration82OSSIOff-state selection for Idle mode101OSSROff-state selection for Run mode111BKEBreak enable121BKPBreak polarity131AOEAutomatic output enable141MOEMain output enable151BKFBreak filter164BK2FBreak 2 filter204BK2EBreak 2 enable241BK2PBreak 2 polarity251DCRDCRDMA control register0x480x20read-write0x0000DBLDMA burst length85DBADMA base address05DMARDMARDMA address for full transfer0x4C0x20read-write0x0000DMABDMA register for burst accesses016ORORDMA address for full transfer0x500x20read-write0x0000TIM1_ETR_ADC1_RMPTIM1_ETR_ADC1 remapping capability02TI1_RMPInput Capture 1 remap41CCMR3_OutputCCMR3_Outputcapture/compare mode register 2 (output mode)0x540x20read-write0x00000000OC6M_bit3Output Compare 6 mode bit 3241OC5M_bit3Output Compare 5 mode bit 3161OC6CEOutput compare 6 clear enable151OC6MOutput compare 6 mode123OC6PEOutput compare 6 preload enable111OC6FEOutput compare 6 fast enable101OC5CEOutput compare 5 clear enable71OC5MOutput compare 5 mode43OC5PEOutput compare 5 preload enable31OC5FEOutput compare 5 fast enable21CCR5CCR5capture/compare register 40x580x20read-write0x00000000CCR5Capture/Compare value016GC5C1Group Channel 5 and Channel 1291GC5C2Group Channel 5 and Channel 2301GC5C3Group Channel 5 and Channel 3311CCR6CCR6capture/compare register 40x5C0x20read-write0x00000000CCR6Capture/Compare value016AF1AF1DMA address for full transfer0x600x20read-write0x00000001BKINEBRK BKIN input enable01BKCMP1EBRK COMP1 enable11BKCMP2EBRK COMP2 enable21BKINPBRK BKIN input polarity91BKCMP1PBRK COMP1 input polarity101BKCMP2PBRK COMP2 input polarity111ETRSELETR source selection143AF2AF2DMA address for full transfer0x640x20read-write0x00000001BK2INEBRK2 BKIN input enable01BK2CMP1EBRK2 COMP1 enable11BK2CMP2EBRK2 COMP2 enable21BK2DFBK0EBRK2 DFSDM_BREAK0 enable81BK2INPBRK2 BKIN input polarity91BK2CMP1PBRK2 COMP1 input polarity101BK2CMP2PBRK2 COMP2 input polarity111LPTIM1Low power timerLPTIM0x40007C000x00x400registersLPTIM1LPtimer 1 global interrupt47ISRISRInterrupt and Status Register0x00x20read-only0x00000000DOWNCounter direction change up to down61UPCounter direction change down to up51ARROKAutoreload register update OK41CMPOKCompare register update OK31EXTTRIGExternal trigger edge event21ARRMAutoreload match11CMPMCompare match01ICRICRInterrupt Clear Register0x40x20write-only0x00000000DOWNCFDirection change to down Clear Flag61UPCFDirection change to UP Clear Flag51ARROKCFAutoreload register update OK Clear Flag41CMPOKCFCompare register update OK Clear Flag31EXTTRIGCFExternal trigger valid edge Clear Flag21ARRMCFAutoreload match Clear Flag11CMPMCFcompare match Clear Flag01IERIERInterrupt Enable Register0x80x20read-write0x00000000DOWNIEDirection change to down Interrupt Enable61UPIEDirection change to UP Interrupt Enable51ARROKIEAutoreload register update OK Interrupt Enable41CMPOKIECompare register update OK Interrupt Enable31EXTTRIGIEExternal trigger valid edge Interrupt Enable21ARRMIEAutoreload match Interrupt Enable11CMPMIECompare match Interrupt Enable01CFGRCFGRConfiguration Register0xC0x20read-write0x00000000ENCEncoder mode enable241COUNTMODEcounter mode enabled231PRELOADRegisters update mode221WAVPOLWaveform shape polarity211WAVEWaveform shape201TIMOUTTimeout enable191TRIGENTrigger enable and polarity172TRIGSELTrigger selector133PRESCClock prescaler93TRGFLTConfigurable digital filter for trigger62CKFLTConfigurable digital filter for external clock32CKPOLClock Polarity12CKSELClock selector01CRCRControl Register0x100x20read-write0x00000000RSTAREReset after read enable41COUNTRSTCounter reset31CNTSTRTTimer start in continuous mode21SNGSTRTLPTIM start in single mode11ENABLELPTIM Enable01CMPCMPCompare Register0x140x20read-write0x00000000CMPCompare value016ARRARRAutoreload Register0x180x20read-write0x00000001ARRAuto reload value016CNTCNTCounter Register0x1C0x20read-only0x00000000CNTCounter value016OROROption Register0x200x20read-write0x00000000OR1Option register bit 101OR2Option register bit 211LPTIM20x40009400LPTIM2LPtimer 2 global interrupt48USART1Universal synchronous asynchronous receiver transmitterUSART0x400138000x00x400registersUSART1USART1 global interrupt36CR1CR1Control register 10x00x20read-write0x0000RXFFIERXFIFO Full interrupt enable311TXFEIETXFIFO empty interrupt enable301FIFOENFIFO mode enable291M1Word length281EOBIEEnd of Block interrupt enable271RTOIEReceiver timeout interrupt enable261DEAT4Driver Enable assertion time251DEAT3DEAT3241DEAT2DEAT2231DEAT1DEAT1221DEAT0DEAT0211DEDT4Driver Enable de-assertion time201DEDT3DEDT3191DEDT2DEDT2181DEDT1DEDT1171DEDT0DEDT0161OVER8Oversampling mode151CMIECharacter match interrupt enable141MMEMute mode enable131M0Word length121WAKEReceiver wakeup method111PCEParity control enable101PSParity selection91PEIEPE interrupt enable81TXEIEinterrupt enable71TCIETransmission complete interrupt enable61RXNEIERXNE interrupt enable51IDLEIEIDLE interrupt enable41TETransmitter enable31REReceiver enable21UESMUSART enable in Stop mode11UEUSART enable01CR2CR2Control register 20x40x20read-write0x0000ADD4_7Address of the USART node284ADD0_3Address of the USART node244RTOENReceiver timeout enable231ABRMOD1Auto baud rate mode221ABRMOD0ABRMOD0211ABRENAuto baud rate enable201MSBFIRSTMost significant bit first191TAINVBinary data inversion181TXINVTX pin active level inversion171RXINVRX pin active level inversion161SWAPSwap TX/RX pins151LINENLIN mode enable141STOPSTOP bits122CLKENClock enable111CPOLClock polarity101CPHAClock phase91LBCLLast bit clock pulse81LBDIELIN break detection interrupt enable61LBDLLIN break detection length51ADDM77-bit Address Detection/4-bit Address Detection41DIS_NSSWhen the DSI_NSS bit is set, the NSS pin input will be ignored31SLVENSynchronous Slave mode enable01CR3CR3Control register 30x80x20read-write0x0000TXFTCFGTXFIFO threshold configuration293RXFTIERXFIFO threshold interrupt enable281RXFTCFGReceive FIFO threshold configuration253TCBGTIETr Complete before guard time, interrupt enable241TXFTIEthreshold interrupt enable231WUFIEWakeup from Stop mode interrupt enable221WUSWakeup from Stop mode interrupt flag selection202SCARCNTSmartcard auto-retry count173DEPDriver enable polarity selection151DEMDriver enable mode141DDREDMA Disable on Reception Error131OVRDISOverrun Disable121ONEBITOne sample bit method enable111CTSIECTS interrupt enable101CTSECTS enable91RTSERTS enable81DMATDMA enable transmitter71DMARDMA enable receiver61SCENSmartcard mode enable51NACKSmartcard NACK enable41HDSELHalf-duplex selection31IRLPIr low-power21IRENIr mode enable11EIEError interrupt enable01BRRBRRBaud rate register0xC0x20read-write0x0000BRRBRR_4_15016GTPRGTPRGuard time and prescaler register0x100x20read-write0x0000GTGuard time value88PSCPrescaler value08RTORRTORReceiver timeout register0x140x20read-write0x0000BLENBlock Length248RTOReceiver timeout value024RQRRQRRequest register0x180x20write-only0x0000TXFRQTransmit data flush request41RXFRQReceive data flush request31MMRQMute mode request21SBKRQSend break request11ABRRQAuto baud rate request01ISRISRInterrupt & status register0x1C0x20read-only0x00C0TXFTTXFIFO threshold flag271RXFTRXFIFO threshold flag261TCBGTTransmission complete before guard time flag251RXFFRXFIFO Full241TXFETXFIFO Empty231REACKREACK221TEACKTEACK211WUFWUF201RWURWU191SBKFSBKF181CMFCMF171BUSYBUSY161ABRFABRF151ABREABRE141UDRSPI slave underrun error flag131EOBFEOBF121RTOFRTOF111CTSCTS101CTSIFCTSIF91LBDFLBDF81TXETXE71TCTC61RXNERXNE51IDLEIDLE41OREORE31NFNF21FEFE11PEPE01ICRICRInterrupt flag clear register0x200x20write-only0x0000WUCFWakeup from Stop mode clear flag201CMCFCharacter match clear flag171UDRCFSPI slave underrun clear flag131EOBCFEnd of block clear flag121RTOCFReceiver timeout clear flag111CTSCFCTS clear flag91LBDCFLIN break detection clear flag81TCBGTCFTransmission complete before Guard time clear flag71TCCFTransmission complete clear flag61TXFECFTXFIFO empty clear flag51IDLECFIdle line detected clear flag41ORECFOverrun error clear flag31NCFNoise detected clear flag21FECFFraming error clear flag11PECFParity error clear flag01RDRRDRReceive data register0x240x20read-only0x0000RDRReceive data value09TDRTDRTransmit data register0x280x20read-write0x0000TDRTransmit data value09PRESCPRESCPrescaler register0x2C0x20read-write0x0000PRESCALERClock prescaler04LPUART10x40008000LPUART1LPUART1 global interrupt37SPI1Serial peripheral interface/Inter-IC soundSPI0x400130000x00x400registersSPI1SPI 1 global interrupt34CR1CR1control register 10x00x20read-write0x00000000BIDIMODEBidirectional data mode enable151BIDIOEOutput enable in bidirectional mode141CRCENHardware CRC calculation enable131CRCNEXTCRC transfer next121CRCLCRC length111RXONLYReceive only101SSMSoftware slave management91SSIInternal slave select81LSBFIRSTFrame format71SPESPI enable61BRBaud rate control33MSTRMaster selection21CPOLClock polarity11CPHAClock phase01CR2CR2control register 20x40x20read-write0x00000700RXDMAENRx buffer DMA enable01TXDMAENTx buffer DMA enable11SSOESS output enable21NSSPNSS pulse management31FRFFrame format41ERRIEError interrupt enable51RXNEIERX buffer not empty interrupt enable61TXEIETx buffer empty interrupt enable71DSData size84FRXTHFIFO reception threshold121LDMA_RXLast DMA transfer for reception131LDMA_TXLast DMA transfer for transmission141SRSRstatus register0x80x200x00000002RXNEReceive buffer not empty01read-onlyTXETransmit buffer empty11read-onlyCRCERRCRC error flag41read-writeMODFMode fault51read-onlyOVROverrun flag61read-onlyBSYBusy flag71read-onlyTIFRFETI frame format error81read-onlyFRLVLFIFO reception level92read-onlyFTLVLFIFO transmission level112read-onlyDRDRdata register0xC0x20read-write0x00000000DRData register016CRCPRCRCPRCRC polynomial register0x100x20read-write0x00000007CRCPOLYCRC polynomial register016RXCRCRRXCRCRRX CRC register0x140x20read-only0x00000000RxCRCRx CRC register016TXCRCRTXCRCRTX CRC register0x180x20read-only0x00000000TxCRCTx CRC register016SPI20x40003800SPI2SPI1 global interrupt35RTCReal-time clockRTC0x400028000x00x400registersRTC_TAMPRTC/TAMP/CSS on LSE through EXTI line 19 interrupt2RTC_WKUPRTC wakeup interrupt through EXTI[19]3RTC_ALARMRTC Alarms (A and B) interrupt through + AIEC41TRTRtime register0x00x20read-write0x00000000PMAM/PM notation221HTHour tens in BCD format202HUHour units in BCD format164MNTMinute tens in BCD format123MNUMinute units in BCD format84STSecond tens in BCD format43SUSecond units in BCD format04DRDRdate register0x40x20read-write0x00002101YTYear tens in BCD format204YUYear units in BCD format164WDUWeek day units133MTMonth tens in BCD format121MUMonth units in BCD format84DTDate tens in BCD format42DUDate units in BCD format04CRCRcontrol register0x80x20read-write0x00000000WCKSELWakeup clock selection03TSEDGETime-stamp event active edge31REFCKONReference clock detection enable (50 or 60 Hz)41BYPSHADBypass the shadow registers51FMTHour format61ALRAEAlarm A enable81ALRBEAlarm B enable91WUTEWakeup timer enable101TSETime stamp enable111ALRAIEAlarm A interrupt enable121ALRBIEAlarm B interrupt enable131WUTIEWakeup timer interrupt enable141TSIETime-stamp interrupt enable151ADD1HAdd 1 hour (summer time change)161SUB1HSubtract 1 hour (winter time change)171BKPBackup181COSELCalibration output selection191POLOutput polarity201OSELOutput selection212COECalibration output enable231ITSEtimestamp on internal event enable241ISRISRinitialization and status register0xC0x200x00000007ALRAWFAlarm A write flag01read-onlyALRBWFAlarm B write flag11read-onlyWUTWFWakeup timer write flag21read-onlySHPFShift operation pending31read-writeINITSInitialization status flag41read-onlyRSFRegisters synchronization flag51read-writeINITFInitialization flag61read-onlyINITInitialization mode71read-writeALRAFAlarm A flag81read-writeALRBFAlarm B flag91read-writeWUTFWakeup timer flag101read-writeTSFTime-stamp flag111read-writeTSOVFTime-stamp overflow flag121read-writeTAMP1FTamper detection flag131read-writeTAMP2FRTC_TAMP2 detection flag141read-writeTAMP3FRTC_TAMP3 detection flag151read-writeRECALPFRecalibration pending Flag161read-onlyITSFINTERNAL TIME-STAMP FLAG171read-writePRERPRERprescaler register0x100x20read-write0x007F00FFPREDIV_AAsynchronous prescaler factor167PREDIV_SSynchronous prescaler factor015WUTRWUTRwakeup timer register0x140x20read-write0x0000FFFFWUTWakeup auto-reload value bits016ALRMARALRMARalarm A register0x1C0x20read-write0x00000000MSK4Alarm A date mask311WDSELWeek day selection301DTDate tens in BCD format282DUDate units or day in BCD format244MSK3Alarm A hours mask231PMAM/PM notation221HTHour tens in BCD format202HUHour units in BCD format164MSK2Alarm A minutes mask151MNTMinute tens in BCD format123MNUMinute units in BCD format84MSK1Alarm A seconds mask71STSecond tens in BCD format43SUSecond units in BCD format04ALRMBRALRMBRalarm B register0x200x20read-write0x00000000MSK4Alarm B date mask311WDSELWeek day selection301DTDate tens in BCD format282DUDate units or day in BCD format244MSK3Alarm B hours mask231PMAM/PM notation221HTHour tens in BCD format202HUHour units in BCD format164MSK2Alarm B minutes mask151MNTMinute tens in BCD format123MNUMinute units in BCD format84MSK1Alarm B seconds mask71STSecond tens in BCD format43SUSecond units in BCD format04WPRWPRwrite protection register0x240x20write-only0x00000000KEYWrite protection key08SSRSSRsub second register0x280x20read-only0x00000000SSSub second value016SHIFTRSHIFTRshift control register0x2C0x20write-only0x00000000ADD1SAdd one second311SUBFSSubtract a fraction of a second015TSTRTSTRtime stamp time register0x300x20read-only0x00000000SUSecond units in BCD format04STSecond tens in BCD format43MNUMinute units in BCD format84MNTMinute tens in BCD format123HUHour units in BCD format164HTHour tens in BCD format202PMAM/PM notation221TSDRTSDRtime stamp date register0x340x20read-only0x00000000WDUWeek day units133MTMonth tens in BCD format121MUMonth units in BCD format84DTDate tens in BCD format42DUDate units in BCD format04TSSSRTSSSRtimestamp sub second register0x380x20read-only0x00000000SSSub second value016CALRCALRcalibration register0x3C0x20read-write0x00000000CALPIncrease frequency of RTC by 488.5 ppm151CALW8Use an 8-second calibration cycle period141CALW16Use a 16-second calibration cycle period131CALMCalibration minus09TAMPCRTAMPCRtamper configuration register0x400x20read-write0x00000000TAMP1ETamper 1 detection enable01TAMP1TRGActive level for tamper 111TAMPIETamper interrupt enable21TAMP2ETamper 2 detection enable31TAMP2TRGActive level for tamper 241TAMP3ETamper 3 detection enable51TAMP3TRGActive level for tamper 361TAMPTSActivate timestamp on tamper detection event71TAMPFREQTamper sampling frequency83TAMPFLTTamper filter count112TAMPPRCHTamper precharge duration132TAMPPUDISTAMPER pull-up disable151TAMP1IETamper 1 interrupt enable161TAMP1NOERASETamper 1 no erase171TAMP1MFTamper 1 mask flag181TAMP2IETamper 2 interrupt enable191TAMP2NOERASETamper 2 no erase201TAMP2MFTamper 2 mask flag211TAMP3IETamper 3 interrupt enable221TAMP3NOERASETamper 3 no erase231TAMP3MFTamper 3 mask flag241ALRMASSRALRMASSRalarm A sub second register0x440x20read-write0x00000000MASKSSMask the most-significant bits starting at this bit244SSSub seconds value015ALRMBSSRALRMBSSRalarm B sub second register0x480x20read-write0x00000000MASKSSMask the most-significant bits starting at this bit244SSSub seconds value015ORORoption register0x4C0x20read-write0x00000000RTC_ALARM_TYPERTC_ALARM on PC13 output type01RTC_OUT_RMPRTC_OUT remap11BKP0RBKP0Rbackup register0x500x20read-write0x00000000BKPBKP032BKP1RBKP1Rbackup register0x540x20read-write0x00000000BKPBKP032BKP2RBKP2Rbackup register0x580x20read-write0x00000000BKPBKP032BKP3RBKP3Rbackup register0x5C0x20read-write0x00000000BKPBKP032BKP4RBKP4Rbackup register0x600x20read-write0x00000000BKPBKP032BKP5RBKP5Rbackup register0x640x20read-write0x00000000BKPBKP032BKP6RBKP6Rbackup register0x680x20read-write0x00000000BKPBKP032BKP7RBKP7Rbackup register0x6C0x20read-write0x00000000BKPBKP032BKP8RBKP8Rbackup register0x700x20read-write0x00000000BKPBKP032BKP9RBKP9Rbackup register0x740x20read-write0x00000000BKPBKP032BKP10RBKP10Rbackup register0x780x20read-write0x00000000BKPBKP032BKP11RBKP11Rbackup register0x7C0x20read-write0x00000000BKPBKP032BKP12RBKP12Rbackup register0x800x20read-write0x00000000BKPBKP032BKP13RBKP13Rbackup register0x840x20read-write0x00000000BKPBKP032BKP14RBKP14Rbackup register0x880x20read-write0x00000000BKPBKP032BKP15RBKP15Rbackup register0x8C0x20read-write0x00000000BKPBKP032BKP16RBKP16Rbackup register0x900x20read-write0x00000000BKPBKP032BKP17RBKP17Rbackup register0x940x20read-write0x00000000BKPBKP032BKP18RBKP18Rbackup register0x980x20read-write0x00000000BKPBKP032BKP19RBKP19Rbackup register0x9C0x20read-write0x00000000BKPBKP032DBGMCUDebug supportDBGMCU0xE00420000x00x400registersIDCODEIDCODEMCU Device ID Code Register0x00x20read-only0x0DEV_IDDevice Identifier012REV_IDRevision Identifier1616CRCRDebug MCU Configuration Register0x40x20read-write0x0DBG_SLEEPDebug Sleep Mode01DBG_STOPDebug Stop Mode11DBG_STANDBYDebug Standby Mode21TRACE_IOENTrace port and clock enable51TRGOENExternal trigger output enable281APB1FZR1APB1FZR1APB1 Low Freeze Register CPU10x3C0x20read-write0x0DBG_TIMER2_STOPDebug Timer 2 stopped when Core is halted01DBG_RTC_STOPRTC counter stopped when core is halted101DBG_WWDG_STOPWWDG counter stopped when core is halted111DBG_IWDG_STOPIWDG counter stopped when core is halted121DBG_I2C1_STOPDebug I2C1 SMBUS timeout stopped when Core is halted211DBG_I2C3_STOPDebug I2C3 SMBUS timeout stopped when core is halted231DBG_LPTIM1_STOPDebug LPTIM1 stopped when Core is halted311C2AP_B1FZR1C2AP_B1FZR1APB1 Low Freeze Register CPU20x400x20read-write0x0DBG_LPTIM2_STOPLPTIM2 counter stopped when core is halted01DBG_RTC_STOPRTC counter stopped when core is halted101DBG_IWDG_STOPIWDG stopped when core is halted121DBG_I2C1_STOPI2C1 SMBUS timeout stopped when core is halted211DBG_I2C3_STOPI2C3 SMBUS timeout stopped when core is halted231DBG_LPTIM1_STOPLPTIM1 counter stopped when core is halted311APB1FZR2APB1FZR2APB1 High Freeze Register CPU10x440x20read-write0x0DBG_LPTIM2_STOPLPTIM2 counter stopped when core is halted51C2APB1FZR2C2APB1FZR2APB1 High Freeze Register CPU20x480x20read-write0x0DBG_LPTIM2_STOPLPTIM2 counter stopped when core is halted51APB2FZRAPB2FZRAPB2 Freeze Register CPU10x4C0x20read-write0x0DBG_TIM1_STOPTIM1 counter stopped when core is halted111DBG_TIM16_STOPTIM16 counter stopped when core is halted171DBG_TIM17_STOPTIM17 counter stopped when core is halted181C2APB2FZRC2APB2FZRAPB2 Freeze Register CPU2C2APB1FZR20x480x20read-write0x0DBG_TIM1_STOPTIM1 counter stopped when core is halted111DBG_TIM16_STOPTIM16 counter stopped when core is halted171DBG_TIM17_STOPTIM17 counter stopped when core is halted181PKAPKAPKA0x580020000x00x2000registersPKAPrivate key accelerator + interrupt29CRCRControl register0x00x20read-write0x00000000ADDRERRIEAddress error interrupt enable201RAMERRIERAM error interrupt enable191PROCENDIEEnd of operation interrupt enable171MODEPKA Operation Mode86SECLVLSecurity Enable21STARTStart the operation11ENPeripheral Enable01SRSRPKA status register0x40x20read-only0x00000000ADDRERRFAddress error flag201RAMERRFRAM error flag191PROCENDFPKA End of Operation flag171BUSYPKA Operation in progress161CLRFRCLRFRPKA clear flag register0x80x20read-write0x00000000ADDRERRFCClear Address error flag201RAMERRFCClear RAM error flag191PROCENDFCClear PKA End of Operation flag171VERRVERRPKA version register0x1FF40x20read-only0x00000010MINREVMinor revision04MAJREVMajor revision44IPIDRIPIDRPKA identification register0x1FF80x20read-only0x00170061IDIdentification Code032SIDRSIDRPKA size ID register0x1FFC0x20read-only0xA3C5DD08SIDSide Identification Code032IPCCIPCCIPCC0x58000C000x00x400registersIPCC_C1_RX_ITIPCC CPU1 RX occupied interrupt44IPCC_C1_TX_ITIPCC CPU1 TX free interrupt45C1CRC1CRControl register CPU10x00x20read-write0x00000000TXFIEprocessor 1 Transmit channel free interrupt enable161RXOIEprocessor 1 Receive channel occupied interrupt enable01C1MRC1MRMask register CPU10x40x20read-write0xFFFFFFFFCH6FMprocessor 1 Transmit channel 6 free interrupt mask211CH5FMprocessor 1 Transmit channel 5 free interrupt mask201CH4FMprocessor 1 Transmit channel 4 free interrupt mask191CH3FMprocessor 1 Transmit channel 3 free interrupt mask181CH2FMprocessor 1 Transmit channel 2 free interrupt mask171CH1FMprocessor 1 Transmit channel 1 free interrupt mask161CH6OMprocessor 1 Receive channel 6 occupied interrupt enable51CH5OMprocessor 1 Receive channel 5 occupied interrupt enable41CH4OMprocessor 1 Receive channel 4 occupied interrupt enable31CH3OMprocessor 1 Receive channel 3 occupied interrupt enable21CH2OMprocessor 1 Receive channel 2 occupied interrupt enable11CH1OMprocessor 1 Receive channel 1 occupied interrupt enable01C1SCRC1SCRStatus Set or Clear register CPU10x80x20write-only0x00000000CH6Sprocessor 1 Transmit channel 6 status set211CH5Sprocessor 1 Transmit channel 5 status set201CH4Sprocessor 1 Transmit channel 4 status set191CH3Sprocessor 1 Transmit channel 3 status set181CH2Sprocessor 1 Transmit channel 2 status set171CH1Sprocessor 1 Transmit channel 1 status set161CH6Cprocessor 1 Receive channel 6 status clear51CH5Cprocessor 1 Receive channel 5 status clear41CH4Cprocessor 1 Receive channel 4 status clear31CH3Cprocessor 1 Receive channel 3 status clear21CH2Cprocessor 1 Receive channel 2 status clear11CH1Cprocessor 1 Receive channel 1 status clear01C1TO2SRC1TO2SRCPU1 to CPU2 status register0xC0x20read-only0x00000000CH6Fprocessor 1 transmit to process 2 Receive channel 6 status flag51CH5Fprocessor 1 transmit to process 2 Receive channel 5 status flag41CH4Fprocessor 1 transmit to process 2 Receive channel 4 status flag31CH3Fprocessor 1 transmit to process 2 Receive channel 3 status flag21CH2Fprocessor 1 transmit to process 2 Receive channel 2 status flag11CH1Fprocessor 1 transmit to process 2 Receive channel 1 status flag01C2CRC2CRControl register CPU20x100x20read-write0x00000000TXFIEprocessor 2 Transmit channel free interrupt enable161RXOIEprocessor 2 Receive channel occupied interrupt enable01C2MRC2MRMask register CPU20x140x20read-write0xFFFFFFFFCH6FMprocessor 2 Transmit channel 6 free interrupt mask211CH5FMprocessor 2 Transmit channel 5 free interrupt mask201CH4FMprocessor 2 Transmit channel 4 free interrupt mask191CH3FMprocessor 2 Transmit channel 3 free interrupt mask181CH2FMprocessor 2 Transmit channel 2 free interrupt mask171CH1FMprocessor 2 Transmit channel 1 free interrupt mask161CH6OMprocessor 2 Receive channel 6 occupied interrupt enable51CH5OMprocessor 2 Receive channel 5 occupied interrupt enable41CH4OMprocessor 2 Receive channel 4 occupied interrupt enable31CH3OMprocessor 2 Receive channel 3 occupied interrupt enable21CH2OMprocessor 2 Receive channel 2 occupied interrupt enable11CH1OMprocessor 2 Receive channel 1 occupied interrupt enable01C2SCRC2SCRStatus Set or Clear register CPU20x180x20write-only0x00000000CH6Sprocessor 2 Transmit channel 6 status set211CH5Sprocessor 2 Transmit channel 5 status set201CH4Sprocessor 2 Transmit channel 4 status set191CH3Sprocessor 2 Transmit channel 3 status set181CH2Sprocessor 2 Transmit channel 2 status set171CH1Sprocessor 2 Transmit channel 1 status set161CH6Cprocessor 2 Receive channel 6 status clear51CH5Cprocessor 2 Receive channel 5 status clear41CH4Cprocessor 2 Receive channel 4 status clear31CH3Cprocessor 2 Receive channel 3 status clear21CH2Cprocessor 2 Receive channel 2 status clear11CH1Cprocessor 2 Receive channel 1 status clear01C2TOC1SRC2TOC1SRCPU2 to CPU1 status register0x1C0x20read-only0x00000000CH6Fprocessor 2 transmit to process 1 Receive channel 6 status flag51CH5Fprocessor 2 transmit to process 1 Receive channel 5 status flag41CH4Fprocessor 2 transmit to process 1 Receive channel 4 status flag31CH3Fprocessor 2 transmit to process 1 Receive channel 3 status flag21CH2Fprocessor 2 transmit to process 1 Receive channel 2 status flag11CH1Fprocessor 2 transmit to process 1 Receive channel 1 status flag01HWCFGRHWCFGRIPCC Hardware configuration register0x3F00x20read-only0x00000006CHANNELSNumber of channels per CPU supported by the IP, range 1 to 1608VERRVERRIPCC version register0x3F40x20read-only0x00000010MAJREVMajor Revision44MINREVMinor Revision04IPIDRIPIDRIPCC indentification register0x3F80x20read-only0x00100071IPIDIdentification Code032SIDRSIDRIPCC size indentification register0x3FC0x20read-only0xA3C5DD01SIDSize Identification Code032EXTIExternal interrupt/event controllerEXTI0x580008000x00x400registersPVDPVD through EXTI[16] (C1IMR2[20])1EXTI0EXTI line 0 interrupt through + EXTI[0]6EXTI1EXTI line 0 interrupt through + EXTI[1]7EXTI2EXTI line 0 interrupt through + EXTI[2]8EXTI3EXTI line 0 interrupt through + EXTI[3]9EXTI4EXTI line 0 interrupt through + EXTI[4]10C2SEVCPU2 SEV through EXTI[40]21EXTI5_9EXTI line [9:5] interrupt through + EXTI[9:5]23EXTI10_15EXTI line [15:10] interrupt through + EXTI[15:10]40RTSR1RTSR1rising trigger selection register0x00x20read-write0x00000000RTRising trigger event configuration bit of Configurable Event input022RT_31Rising trigger event configuration bit of Configurable Event input311FTSR1FTSR1falling trigger selection register0x40x20read-write0x00000000FTFalling trigger event configuration bit of Configurable Event input022FT_31Falling trigger event configuration bit of Configurable Event input311SWIER1SWIER1software interrupt event register0x80x20read-write0x00000000SWISoftware interrupt on event022SWI_31Software interrupt on event311PR1PR1EXTI pending register0xC0x20read-write0x00000000PIFConfigurable event inputs Pending bit022PIF_31Configurable event inputs Pending bit311RTSR2RTSR2rising trigger selection register0x200x20read-write0x00000000RT33Rising trigger event configuration bit of Configurable Event input11RT40_41Rising trigger event configuration bit of Configurable Event input82FTSR2FTSR2falling trigger selection register0x240x20read-write0x00000000FT33Falling trigger event configuration bit of Configurable Event input11FT40_41Falling trigger event configuration bit of Configurable Event input82SWIER2SWIER2software interrupt event register0x280x20read-write0x00000000SWI33Software interrupt on event11SWI40_41Software interrupt on event82PR2PR2pending register0x2C0x20read-write0x00000000PIF33Configurable event inputs x+32 Pending bit.11PIF40_41Configurable event inputs x+32 Pending bit.82C1IMR1C1IMR1CPUm wakeup with interrupt mask register0x800x20read-write0x7FC00000IMCPU(m) wakeup with interrupt Mask on Event input032C2IMR1C2IMR1CPUm wakeup with interrupt mask register0xC00x20read-write0x7FC00000IMCPU(m) wakeup with interrupt Mask on Event input032C1EMR1C1EMR1CPUm wakeup with event mask register0x840x20read-write0x00000000EM0_15CPU(m) Wakeup with event generation Mask on Event input016EM17_21CPU(m) Wakeup with event generation Mask on Event input175C2EMR1C2EMR1CPUm wakeup with event mask register0xC40x20read-write0x00000000EM0_15CPU(m) Wakeup with event generation Mask on Event input016EM17_21CPU(m) Wakeup with event generation Mask on Event input175C1IMR2C1IMR2CPUm wakeup with interrupt mask register0x900x20read-write0x0001FCFDIMCPUm Wakeup with interrupt Mask on Event input017C2IMR2C2IMR2CPUm wakeup with interrupt mask register0xD00x20read-write0x0001FCFDIMCPUm Wakeup with interrupt Mask on Event input017C1EMR2C1EMR2CPUm wakeup with event mask register0x940x20read-write0x00000000EMCPU(m) Wakeup with event generation Mask on Event input82C2EMR2C2EMR2CPUm wakeup with event mask register0xD40x20read-write0x00000000EMCPU(m) Wakeup with event generation Mask on Event input82HWCFGR5HWCFGR5Hardware configuration registers0x3E00x20read-only0x003EFFFFCPUEVENTHW configuration CPU event generation032HWCFGR6HWCFGR6Hardware configuration registers0x3DC0x20read-only0x00000300CPUEVENTHW configuration CPU event generation032HWCFGR7HWCFGR7EXTI Hardware configuration registers0x3D80x20read-only0x00000000CPUEVENTHW configuration CPU event generation032HWCFGR2HWCFGR2Hardware configuration registers0x3EC0x20read-only0x803FFFFFEVENT_TRGHW configuration event trigger type032HWCFGR3HWCFGR3Hardware configuration registers0x3E80x20read-only0x00000302EVENT_TRGHW configuration event trigger type032HWCFGR4HWCFGR4Hardware configuration registers0x3E40x20read-only0x00000000EVENT_TRGHW configuration event trigger type032HWCFGR1HWCFGR1Hardware configuration register 10x3F00x20read-only0x00003130NBEVENTSHW configuration number of event08NBCPUSHW configuration number of CPUs84CPUEVTENHW configuration of CPU(m) event output enable124VERRVERREXTI IP Version register0x3F40x20read-only0X00000020MINREVMinor Revision number04MAJREVMajor Revision number44IPIDRIPIDRIdentification register0x3F80x20read-only0x000E0001IPIDIP Identification032SIDRSIDRSize ID register0x3FC0x20read-only0xA3C5DD01SIDSize Identification032CRSClock recovery systemCRS0x400060000x00x400registersCRS_ITCRS interrupt42CRCRCRS control register0x00x20read-write0x00002000SYNCOKIESYNC event OK interrupt enable01SYNCWARNIESYNC warning interrupt enable11ERRIESynchronization or trimming error interrupt enable21ESYNCIEExpected SYNC interrupt enable31CENFrequency error counter enable51AUTOTRIMENAutomatic trimming enable61SWSYNCAutomatic trimming enable71TRIMHSI48 oscillator smooth trimming86CFGRCFGRCRS configuration register0x40x20read-write0x2022BB7FRELOADCounter reload value016FELIMFrequency error limit168SYNCDIVSYNCDIV243SYNCSRCSYNC signal source selection282SYNCPOLSYNC polarity selection311ISRISRCRS interrupt and status register0x80x20read-only0x00000000SYNCOKFSYNC event OK flag01SYNCWARNFSYNC warning flag11ERRFError flag21ESYNCFExpected SYNC flag31SYNCERRSYNC error81SYNCMISSSYNC missed91TRIMOVFTrimming overflow or underflow101FEDIRFrequency error direction151FECAPFrequency error capture1616ICRICRCRS interrupt flag clear register0xC0x20read-write0x00000000SYNCOKCSYNC event OK clear flag01SYNCWARNCwarning clear flag11ERRCError clear flag21ESYNCCExpected SYNC clear flag31USBUniversal serial bus full-speed device interfaceUSB0x400068000x00x800registersUSB_HPUSB high priority interrupt19USB_LPUSB low priority interrupt (including USB + wakeup)20EP0REP0Rendpoint 0 register0x00x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP1REP1Rendpoint 1 register0x40x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP2REP2Rendpoint 2 register0x80x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP3REP3Rendpoint 3 register0xC0x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP4REP4Rendpoint 4 register0x100x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP5REP5Rendpoint 5 register0x140x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP6REP6Rendpoint 6 register0x180x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151EP7REP7Rendpoint 7 register0x1C0x10read-write0x00000000EAEndpoint address04STAT_TXStatus bits, for transmission transfers42DTOG_TXData Toggle, for transmission transfers61CTR_TXCorrect Transfer for transmission71EP_KINDEndpoint kind81EP_TYPEEndpoint type92SETUPSetup transaction completed111STAT_RXStatus bits, for reception transfers122DTOG_RXData Toggle, for reception transfers141CTR_RXCorrect transfer for reception151CNTRCNTRcontrol register0x400x10read-write0x00000003FRESForce USB Reset01PDWNPower down11LPMODELow-power mode21FSUSPForce suspend31RESUMEResume request41L1RESUMELPM L1 Resume request51L1REQMLPM L1 state request interrupt mask71ESOFMExpected start of frame interrupt mask81SOFMStart of frame interrupt mask91RESETMUSB reset interrupt mask101SUSPMSuspend mode interrupt mask111WKUPMWakeup interrupt mask121ERRMError interrupt mask131PMAOVRMPacket memory area over / underrun interrupt mask141CTRMCorrect transfer interrupt mask151ISTRISTRinterrupt status register0x440x100x00000000EP_IDEndpoint Identifier04read-onlyDIRDirection of transaction41read-onlyL1REQLPM L1 state request71read-writeESOFExpected start frame81read-writeSOFstart of frame91read-writeRESETreset request101read-writeSUSPSuspend mode request111read-writeWKUPWakeup121read-writeERRError131read-writePMAOVRPacket memory area over / underrun141read-writeCTRCorrect transfer151read-onlyFNRFNRframe number register0x480x10read-only0x0000FNFrame number011LSOFLost SOF112LCKLocked131RXDMReceive data - line status141RXDPReceive data + line status151DADDRDADDRdevice address0x4C0x10read-write0x0000ADDDevice address07EFEnable function71BTABLEBTABLEBuffer table address0x500x10read-write0x0000BTABLEBuffer table313COUNT0_TXCOUNT0_TXTransmission byte count 00x520x10read-write0x0000COUNT0_TXTransmission byte count010COUNT1_TXCOUNT1_TXTransmission byte count 00x5A0x10read-write0x0000COUNT1_TXTransmission byte count010COUNT2_TXCOUNT2_TXTransmission byte count 00x620x10read-write0x0000COUNT2_TXTransmission byte count010COUNT3_TXCOUNT3_TXTransmission byte count 00x6A0x10read-write0x0000COUNT3_TXTransmission byte count010COUNT4_TXCOUNT4_TXTransmission byte count 00x720x10read-write0x0000COUNT4_TXTransmission byte count010COUNT5_TXCOUNT5_TXTransmission byte count 00x7A0x10read-write0x0000COUNT5_TXTransmission byte count010COUNT6_TXCOUNT6_TXTransmission byte count 00x820x10read-write0x0000COUNT6_TXTransmission byte count010COUNT7_TXCOUNT7_TXTransmission byte count 00x8A0x10read-write0x0000COUNT7_TXTransmission byte count010ADDR0_RXADDR0_RXReception buffer address 00x540x10read-write0x0000ADDR0_RXReception buffer address115ADDR1_RXADDR1_RXReception buffer address 00x5C0x10read-write0x0000ADDR1_RXReception buffer address115ADDR2_RXADDR2_RXReception buffer address 00x640x10read-write0x0000ADDR2_RXReception buffer address115ADDR3_RXADDR3_RXReception buffer address 00x6C0x10read-write0x0000ADDR3_RXReception buffer address115ADDR4_RXADDR4_RXReception buffer address 00x740x10read-write0x0000ADDR4_RXReception buffer address115ADDR5_RXADDR5_RXReception buffer address 00x7C0x10read-write0x0000ADDR5_RXReception buffer address115ADDR6_RXADDR6_RXReception buffer address 00x840x10read-write0x0000ADDR6_RXReception buffer address115ADDR7_RXADDR7_RXReception buffer address 00x8C0x10read-write0x0000ADDR7_RXReception buffer address115COUNT0_RXCOUNT0_RXReception byte count 00x560x100x0000COUNT0_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT1_RXCOUNT1_RXReception byte count 00x5E0x100x0000COUNT1_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT2_RXCOUNT2_RXReception byte count 00x660x100x0000COUNT2_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT3_RXCOUNT3_RXReception byte count 00x6E0x100x0000COUNT3_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT4_RXCOUNT4_RXReception byte count 00x760x100x0000COUNT4_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT5_RXCOUNT5_RXReception byte count 00x7E0x100x0000COUNT5_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT6_RXCOUNT6_RXReception byte count 00x860x100x0000COUNT6_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeCOUNT7_RXCOUNT7_RXReception byte count 00x8E0x100x0000COUNT7_RXReception byte count010read-onlyNUM_BLOCKNumber of blocks105read-writeBL_SIZEBlock size151read-writeLPMCSRLPMCSRcontrol and status registerADDR0_RX0x540x100x0000LPMENLPM support enable01read-writeLPMACKLPM Token acknowledge enable11read-writeREMWAKERemoteWake value31read-writeBESLBESL value44read-onlyBCDRBCDRBattery charging detector(0x580x100x0000BCDENBattery charging detector (BCD) enable01read-writeDCDENData contact detection (DCD) mode enable11read-writePDENPrimary detection (PD) mode enable21read-writeSDENSecondary detection (SD) mode enable31read-writeDCDETData contact detection (DCD) status41read-onlyPDETPrimary detection (PD) status51read-onlySDETSecondary detection (SD) status61read-onlyPS2DETDM pull-up detection status71read-onlyDPPUDP pull-up control151read-writeSCBSystem control blockSCB0xE000ED000x00x41registersCPUIDCPUIDCPUID base register0x00x20read-only0x410FC241RevisionRevision number04PartNoPart number of the processor412ConstantReads as 0xF164VariantVariant number204ImplementerImplementer code248ICSRICSRInterrupt control and state register0x40x20read-write0x00000000VECTACTIVEActive vector09RETTOBASEReturn to base level111VECTPENDINGPending vector127ISRPENDINGInterrupt pending flag221PENDSTCLRSysTick exception clear-pending bit251PENDSTSETSysTick exception set-pending bit261PENDSVCLRPendSV clear-pending bit271PENDSVSETPendSV set-pending bit281NMIPENDSETNMI set-pending bit.311VTORVTORVector table offset register0x80x20read-write0x00000000TBLOFFVector table base offset field921AIRCRAIRCRApplication interrupt and reset control register0xC0x20read-write0x00000000VECTRESETVECTRESET01VECTCLRACTIVEVECTCLRACTIVE11SYSRESETREQSYSRESETREQ21PRIGROUPPRIGROUP83ENDIANESSENDIANESS151VECTKEYSTATRegister key1616SCRSCRSystem control register0x100x20read-write0x00000000SLEEPONEXITSLEEPONEXIT11SLEEPDEEPSLEEPDEEP21SEVEONPENDSend Event on Pending bit41CCRCCRConfiguration and control register0x140x20read-write0x00000000NONBASETHRDENAConfigures how the processor enters Thread mode01USERSETMPENDUSERSETMPEND11UNALIGN__TRPUNALIGN_ TRP31DIV_0_TRPDIV_0_TRP41BFHFNMIGNBFHFNMIGN81STKALIGNSTKALIGN91SHPR1SHPR1System handler priority registers0x180x20read-write0x00000000PRI_4Priority of system handler 408PRI_5Priority of system handler 588PRI_6Priority of system handler 6168SHPR2SHPR2System handler priority registers0x1C0x20read-write0x00000000PRI_11Priority of system handler 11248SHPR3SHPR3System handler priority registers0x200x20read-write0x00000000PRI_14Priority of system handler 14168PRI_15Priority of system handler 15248SHCSRSHCSRSystem handler control and state register0x240x20read-write0x00000000MEMFAULTACTMemory management fault exception active bit01BUSFAULTACTBus fault exception active bit11USGFAULTACTUsage fault exception active bit31SVCALLACTSVC call active bit71MONITORACTDebug monitor active bit81PENDSVACTPendSV exception active bit101SYSTICKACTSysTick exception active bit111USGFAULTPENDEDUsage fault exception pending bit121MEMFAULTPENDEDMemory management fault exception pending bit131BUSFAULTPENDEDBus fault exception pending bit141SVCALLPENDEDSVC call pending bit151MEMFAULTENAMemory management fault enable bit161BUSFAULTENABus fault enable bit171USGFAULTENAUsage fault enable bit181CFSR_UFSR_BFSR_MMFSRCFSR_UFSR_BFSR_MMFSRConfigurable fault status register0x280x20read-write0x00000000IACCVIOLInstruction access violation flag11MUNSTKERRMemory manager fault on unstacking for a return from exception31MSTKERRMemory manager fault on stacking for exception entry.41MLSPERRMLSPERR51MMARVALIDMemory Management Fault Address Register (MMAR) valid flag71IBUSERRInstruction bus error81PRECISERRPrecise data bus error91IMPRECISERRImprecise data bus error101UNSTKERRBus fault on unstacking for a return from exception111STKERRBus fault on stacking for exception entry121LSPERRBus fault on floating-point lazy state preservation131BFARVALIDBus Fault Address Register (BFAR) valid flag151UNDEFINSTRUndefined instruction usage fault161INVSTATEInvalid state usage fault171INVPCInvalid PC load usage fault181NOCPNo coprocessor usage fault.191UNALIGNEDUnaligned access usage fault241DIVBYZERODivide by zero usage fault251HFSRHFSRHard fault status register0x2C0x20read-write0x00000000VECTTBLVector table hard fault11FORCEDForced hard fault301DEBUG_VTReserved for Debug use311MMFARMMFARMemory management fault address register0x340x20read-write0x00000000MMFARMemory management fault address032BFARBFARBus fault address register0x380x20read-write0x00000000BFARBus fault address032AFSRAFSRAuxiliary fault status register0x3C0x20read-write0x00000000IMPDEFImplementation defined032STKSysTick timerSTK0xE000E0100x00x11registersCTRLCTRLSysTick control and status register0x00x20read-write0X00000000ENABLECounter enable01TICKINTSysTick exception request enable11CLKSOURCEClock source selection21COUNTFLAGCOUNTFLAG161LOADLOADSysTick reload value register0x40x20read-write0X00000000RELOADRELOAD value024VALVALSysTick current value register0x80x20read-write0X00000000CURRENTCurrent counter value024CALIBCALIBSysTick calibration value register0xC0x20read-write0X00000000TENMSCalibration value024SKEWSKEW flag: Indicates whether the TENMS value is exact301NOREFNOREF flag. Reads as zero311MPUMemory protection unitMPU0xE000ED900x00x15registersMPU_TYPERMPU_TYPERMPU type register0x00x20read-only0X00000800SEPARATESeparate flag01DREGIONNumber of MPU data regions88IREGIONNumber of MPU instruction regions168MPU_CTRLMPU_CTRLMPU control register0x40x20read-only0X00000000ENABLEEnables the MPU01HFNMIENAEnables the operation of MPU during hard fault11PRIVDEFENAEnable priviliged software access to default memory map21MPU_RNRMPU_RNRMPU region number register0x80x20read-write0X00000000REGIONMPU region08MPU_RBARMPU_RBARMPU region base address register0xC0x20read-write0X00000000REGIONMPU region field04VALIDMPU region number valid41ADDRRegion base address field527MPU_RASRMPU_RASRMPU region attribute and size register0x100x20read-write0X00000000ENABLERegion enable bit.01SIZESize of the MPU protection region15SRDSubregion disable bits88Bmemory attribute161Cmemory attribute171SShareable memory attribute181TEXmemory attribute193APAccess permission243XNInstruction access disable bit281FPUFloting point unitFPU0xE000EF340x00xDregistersFPUFloating point unit interrupt54FPCCRFPCCRFloating-point context control register0x00x20read-write0x00000000LSPACTLSPACT01USERUSER11THREADTHREAD31HFRDYHFRDY41MMRDYMMRDY51BFRDYBFRDY61MONRDYMONRDY81LSPENLSPEN301ASPENASPEN311FPCARFPCARFloating-point context address register0x40x20read-write0x00000000ADDRESSLocation of unpopulated floating-point329FPSCRFPSCRFloating-point status control register0x80x20read-write0x00000000IOCInvalid operation cumulative exception bit01DZCDivision by zero cumulative exception bit.11OFCOverflow cumulative exception bit21UFCUnderflow cumulative exception bit31IXCInexact cumulative exception bit41IDCInput denormal cumulative exception bit.71RModeRounding Mode control field222FZFlush-to-zero mode control bit:241DNDefault NaN mode control bit251AHPAlternative half-precision control bit261VOverflow condition code flag281CCarry condition code flag291ZZero condition code flag301NNegative condition code flag311NVICNested Vectored Interrupt ControllerNVIC0xE000E1000x00x351registersISER0ISER0Interrupt Set-Enable Register0x00x20read-write0x00000000SETENASETENA032ISER1ISER1Interrupt Set-Enable Register0x40x20read-write0x00000000SETENASETENA032ICER0ICER0Interrupt Clear-Enable Register0x800x20read-write0x00000000CLRENACLRENA032ICER1ICER1Interrupt Clear-Enable Register0x840x20read-write0x00000000CLRENACLRENA032ISPR0ISPR0Interrupt Set-Pending Register0x1000x20read-write0x00000000SETPENDSETPEND032ISPR1ISPR1Interrupt Set-Pending Register0x1040x20read-write0x00000000SETPENDSETPEND032ICPR0ICPR0Interrupt Clear-Pending Register0x1800x20read-write0x00000000CLRPENDCLRPEND032ICPR1ICPR1Interrupt Clear-Pending Register0x1840x20read-write0x00000000CLRPENDCLRPEND032IABR0IABR0Interrupt Active Bit Register0x2000x20read-only0x00000000ACTIVEACTIVE032IABR1IABR1Interrupt Active Bit Register0x2040x20read-only0x00000000ACTIVEACTIVE032IPR0IPR0Interrupt Priority Register0x3000x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR1IPR1Interrupt Priority Register0x3040x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR2IPR2Interrupt Priority Register0x3080x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR3IPR3Interrupt Priority Register0x30C0x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR4IPR4Interrupt Priority Register0x3100x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR5IPR5Interrupt Priority Register0x3140x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR6IPR6Interrupt Priority Register0x3180x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR7IPR7Interrupt Priority Register0x31C0x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR8IPR8Interrupt Priority Register0x3200x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR9IPR9Interrupt Priority Register0x3240x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR10IPR10Interrupt Priority Register0x3280x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR11IPR11Interrupt Priority Register0x32C0x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR12IPR12Interrupt Priority Register0x3300x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR13IPR13Interrupt Priority Register0x3340x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR14IPR14Interrupt Priority Register0x3380x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR15IPR15Interrupt Priority Register0x33C0x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR16IPR16Interrupt Priority Register0x3400x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248IPR17IPR17Interrupt Priority Register0x3440x20read-write0x00000000IPR_N0IPR_N008IPR_N1IPR_N188IPR_N2IPR_N2168IPR_N3IPR_N3248NVIC_STIRNested vectored interrupt controllerNVIC0xE000EF000x00x5registersSTIRSTIRSoftware trigger interrupt register0x00x20read-write0x00000000INTIDSoftware generated interrupt ID09SCB_ACTRLSystem control block ACTLRSCB0xE000E0080x00x5registersACTRLACTRLAuxiliary control register0x00x20read-write0x00000000DISMCYCINTDISMCYCINT01DISDEFWBUFDISDEFWBUF11DISFOLDDISFOLD21DISFPCADISFPCA81DISOOFPDISOOFP91FPU_CPACRFloating point unit CPACRFPU0xE000ED880x00x5registersCPACRCPACRCoprocessor access control register0x00x20read-write0x0000000CPCP204 diff --git a/firmware/targets/f6/ble-glue/app_conf.h b/firmware/targets/f6/ble-glue/app_conf.h index e3820e11..eebdbbdb 100644 --- a/firmware/targets/f6/ble-glue/app_conf.h +++ b/firmware/targets/f6/ble-glue/app_conf.h @@ -427,16 +427,5 @@ typedef enum #define DBG_TRACE_MSG_QUEUE_SIZE 4096 #define MAX_DBG_TRACE_MSG_SIZE 1024 -/****************************************************************************** - * FreeRTOS - ******************************************************************************/ -#define CFG_SHCI_USER_EVT_PROCESS_NAME "ble_shci_evt" -#define CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_SIZE (0) -#define CFG_SHCI_USER_EVT_PROCESS_STACK_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_PRIORITY osPriorityNone -#define CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE (128 * 7) - #define CFG_OTP_BASE_ADDRESS OTP_AREA_BASE #define CFG_OTP_END_ADRESS OTP_AREA_END_ADDR diff --git a/firmware/targets/f6/ble-glue/app_entry.c b/firmware/targets/f6/ble-glue/app_entry.c deleted file mode 100644 index 5c8c0b2a..00000000 --- a/firmware/targets/f6/ble-glue/app_entry.c +++ /dev/null @@ -1,180 +0,0 @@ -#include "app_common.h" -#include "main.h" -#include "app_entry.h" -#include "ble_app.h" -#include "ble.h" -#include "tl.h" -#include "cmsis_os.h" -#include "shci_tl.h" -#include "app_debug.h" -#include - -extern RTC_HandleTypeDef hrtc; - -#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) - -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; - -osMutexId_t MtxShciId; -osSemaphoreId_t SemShciId; -osThreadId_t ShciUserEvtProcessId; - -volatile static BleGlueStatus ble_glue_status = BleGlueStatusUninitialized; - -const osThreadAttr_t ShciUserEvtProcess_attr = { - .name = CFG_SHCI_USER_EVT_PROCESS_NAME, - .attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS, - .cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM, - .cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE, - .stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM, - .priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY, - .stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE -}; - -static void ShciUserEvtProcess(void *argument); -static void SystemPower_Config( void ); -static void appe_Tl_Init( void ); -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ); -static void APPE_SysUserEvtRx( void * pPayload ); - -BleGlueStatus APPE_Status() { - return ble_glue_status; -} - -void APPE_Init() { - ble_glue_status = BleGlueStatusStartup; - SystemPower_Config(); /**< Configure the system Power Mode */ - - // APPD_Init(); - furi_hal_power_insomnia_enter(); - - appe_Tl_Init(); /* Initialize all transport layers */ - - /** - * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) - * received on the system channel before starting the Stack - * This system event is received with APPE_SysUserEvtRx() - */ -} - -/************************************************************* - * - * LOCAL FUNCTIONS - * - *************************************************************/ - -/** - * @brief Configure the system for power optimization - * - * @note This API configures the system to be ready for low power mode - * - * @param None - * @retval None - */ -static void SystemPower_Config(void) { - // Select HSI as system clock source after Wake Up from Stop mode - LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); - - /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); -} - -static void appe_Tl_Init( void ) { - TL_MM_Config_t tl_mm_config; - SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; - /**< Reference table initialization */ - TL_Init(); - - MtxShciId = osMutexNew( NULL ); - SemShciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */ - - /** FreeRTOS system task creation */ - ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr); - - /**< System channel initialization */ - SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer; - SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot; - shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf); - - /**< Memory Manager channel initialization */ - tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer; - tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer; - tl_mm_config.p_AsynchEvtPool = EvtPool; - tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; - TL_MM_Init( &tl_mm_config ); - - TL_Enable(); -} - -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ) { - switch (status) { - case SHCI_TL_CmdBusy: - osMutexAcquire( MtxShciId, osWaitForever ); - break; - case SHCI_TL_CmdAvailable: - osMutexRelease( MtxShciId ); - break; - default: - break; - } -} - -/** - * The type of the payload for a system user event is tSHCI_UserEvtRxParam - * When the system event is both : - * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) - * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) - * The buffer shall not be released - * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) - * When the status is not filled, the buffer is released by default - */ -static void APPE_SysUserEvtRx( void * pPayload ) { - UNUSED(pPayload); - /* Traces channel initialization */ - // APPD_EnableCPU2( ); - - if(ble_app_init()) { - FURI_LOG_I("Core2", "BLE stack started"); - ble_glue_status = BleGlueStatusStarted; - } else { - FURI_LOG_E("Core2", "BLE stack startup failed"); - ble_glue_status = BleGlueStatusBroken; - } - furi_hal_power_insomnia_exit(); -} - -/************************************************************* - * - * FREERTOS WRAPPER FUNCTIONS - * -*************************************************************/ -static void ShciUserEvtProcess(void *argument) { - UNUSED(argument); - for(;;) { - osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); - shci_user_evt_proc(); - } -} - -/************************************************************* - * - * WRAP FUNCTIONS - * - *************************************************************/ -void shci_notify_asynch_evt(void* pdata) { - UNUSED(pdata); - osThreadFlagsSet( ShciUserEvtProcessId, 1 ); -} - -void shci_cmd_resp_release(uint32_t flag) { - UNUSED(flag); - osSemaphoreRelease( SemShciId ); -} - -void shci_cmd_resp_wait(uint32_t timeout) { - UNUSED(timeout); - osSemaphoreAcquire( SemShciId, osWaitForever ); -} diff --git a/firmware/targets/f6/ble-glue/app_entry.h b/firmware/targets/f6/ble-glue/app_entry.h deleted file mode 100644 index f1ce6038..00000000 --- a/firmware/targets/f6/ble-glue/app_entry.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - BleGlueStatusUninitialized, - BleGlueStatusStartup, - BleGlueStatusBroken, - BleGlueStatusStarted -} BleGlueStatus; - -void APPE_Init(); - -BleGlueStatus APPE_Status(); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/firmware/targets/f6/ble-glue/ble_app.c b/firmware/targets/f6/ble-glue/ble_app.c index e28facd6..33e5264a 100644 --- a/firmware/targets/f6/ble-glue/ble_app.c +++ b/firmware/targets/f6/ble-glue/ble_app.c @@ -11,6 +11,7 @@ #define BLE_APP_TAG "ble app" PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; typedef struct { osMutexId_t hci_mtx; @@ -26,8 +27,8 @@ static void ble_app_hci_event_handler(void * pPayload); static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status); bool ble_app_init() { + SHCI_CmdStatus_t status; ble_app = furi_alloc(sizeof(BleApp)); - // Allocate semafore and mutex for ble command buffer access ble_app->hci_mtx = osMutexNew(NULL); ble_app->hci_sem = osSemaphoreNew(1, 0, NULL); @@ -43,6 +44,18 @@ bool ble_app_init() { }; hci_init(ble_app_hci_event_handler, (void*)&hci_tl_config); + // Configure NVM store for pairing data + SHCI_C2_CONFIG_Cmd_Param_t config_param = { + .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, + .Config1 =SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, + .BleNvmRamAddress = (uint32_t)ble_app_nvm, + .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, + }; + status = SHCI_C2_Config(&config_param); + if(status) { + FURI_LOG_E(BLE_APP_TAG, "Failed to configure 2nd core: %d", status); + } + // Start ble stack on 2nd core SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { .Header = {{0,0,0}}, // Header unused @@ -67,13 +80,18 @@ bool ble_app_init() { 0, } }; - SHCI_CmdStatus_t status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); + status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); if(status) { FURI_LOG_E(BLE_APP_TAG, "Failed to start ble stack: %d", status); } return status == SHCI_Success; } +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) { + *addr = (uint8_t*)ble_app_nvm; + *size = sizeof(ble_app_nvm); +} + static void ble_app_hci_thread(void *arg) { while(1) { osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); diff --git a/firmware/targets/f6/ble-glue/ble_app.h b/firmware/targets/f6/ble-glue/ble_app.h index 17d8dc5f..64000bde 100644 --- a/firmware/targets/f6/ble-glue/ble_app.h +++ b/firmware/targets/f6/ble-glue/ble_app.h @@ -5,8 +5,10 @@ extern "C" { #endif #include +#include bool ble_app_init(); +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size); #ifdef __cplusplus } diff --git a/firmware/targets/f6/ble-glue/ble_glue.c b/firmware/targets/f6/ble-glue/ble_glue.c new file mode 100644 index 00000000..4a9c144e --- /dev/null +++ b/firmware/targets/f6/ble-glue/ble_glue.c @@ -0,0 +1,173 @@ +#include "ble_glue.h" +#include "app_common.h" +#include "main.h" +#include "ble_app.h" +#include "ble.h" +#include "tl.h" +#include "shci.h" +#include "cmsis_os.h" +#include "shci_tl.h" +#include "app_debug.h" +#include + +#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) + +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_event_pool[POOL_SIZE]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_buff; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; + +typedef struct { + osMutexId_t shci_mtx; + osSemaphoreId_t shci_sem; + osThreadId_t shci_user_event_thread_id; + osThreadAttr_t shci_user_event_thread_attr; + BleGlueStatus status; + BleGlueKeyStorageChangedCallback callback; + void* context; +} BleGlue; + +static BleGlue* ble_glue = NULL; + +static void ble_glue_user_event_thread(void *argument); +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status); +static void ble_glue_sys_user_event_callback(void* pPayload); + +BleGlueStatus ble_glue_get_status() { + if(!ble_glue) { + return BleGlueStatusUninitialized; + } + return ble_glue->status; +} + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(ble_glue); + furi_assert(callback); + ble_glue->callback = callback; + ble_glue->context = context; +} + +void ble_glue_init() { + ble_glue = furi_alloc(sizeof(BleGlue)); + ble_glue->status = BleGlueStatusStartup; + ble_glue->shci_user_event_thread_attr.name = "ble_shci_evt"; + ble_glue->shci_user_event_thread_attr.stack_size = 1024; + + // Configure the system Power Mode + // Select HSI as system clock source after Wake Up from Stop mode + LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); + /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ + LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); + furi_hal_power_insomnia_enter(); + + // APPD_Init(); + + // Initialize all transport layers + TL_MM_Config_t tl_mm_config; + SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; + // Reference table initialization + TL_Init(); + + ble_glue->shci_mtx = osMutexNew(NULL); + ble_glue->shci_sem = osSemaphoreNew(1, 0, NULL); + + // FreeRTOS system task creation + ble_glue->shci_user_event_thread_id = osThreadNew(ble_glue_user_event_thread, NULL, &ble_glue->shci_user_event_thread_attr); + + // System channel initialization + SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&ble_glue_system_cmd_buff; + SHci_Tl_Init_Conf.StatusNotCallBack = ble_glue_sys_status_not_callback; + shci_init(ble_glue_sys_user_event_callback, (void*) &SHci_Tl_Init_Conf); + + /**< Memory Manager channel initialization */ + tl_mm_config.p_BleSpareEvtBuffer = ble_glue_ble_spare_event_buff; + tl_mm_config.p_SystemSpareEvtBuffer = ble_glue_system_spare_event_buff; + tl_mm_config.p_AsynchEvtPool = ble_glue_event_pool; + tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; + TL_MM_Init( &tl_mm_config ); + TL_Enable(); + + /* + * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) + * received on the system channel before starting the Stack + * This system event is received with ble_glue_sys_user_event_callback() + */ +} + +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { + switch (status) { + case SHCI_TL_CmdBusy: + osMutexAcquire( ble_glue->shci_mtx, osWaitForever ); + break; + case SHCI_TL_CmdAvailable: + osMutexRelease( ble_glue->shci_mtx ); + break; + default: + break; + } +} + +/* + * The type of the payload for a system user event is tSHCI_UserEvtRxParam + * When the system event is both : + * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) + * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) + * The buffer shall not be released + * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) + * When the status is not filled, the buffer is released by default + */ +static void ble_glue_sys_user_event_callback( void * pPayload ) { + UNUSED(pPayload); + /* Traces channel initialization */ + // APPD_EnableCPU2( ); + + TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload); + + if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { + if(ble_app_init()) { + FURI_LOG_I("Core2", "BLE stack started"); + ble_glue->status = BleGlueStatusStarted; + if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) { + FURI_LOG_I("Core2", "Flash activity control switched to SEM7"); + } else { + FURI_LOG_E("Core2", "Failed to switch flash activity control to SEM7"); + } + } else { + FURI_LOG_E("Core2", "BLE stack startup failed"); + ble_glue->status = BleGlueStatusBleStackMissing; + } + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) { + FURI_LOG_E("Core2", "Error during initialization"); + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE) { + SHCI_C2_BleNvmRamUpdate_Evt_t* p_sys_ble_nvm_ram_update_event = (SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload; + if(ble_glue->callback) { + ble_glue->callback((uint8_t*)p_sys_ble_nvm_ram_update_event->StartAddress, p_sys_ble_nvm_ram_update_event->Size, ble_glue->context); + } + } +} + +// Wrap functions +static void ble_glue_user_event_thread(void *argument) { + UNUSED(argument); + for(;;) { + osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); + shci_user_evt_proc(); + } +} + +void shci_notify_asynch_evt(void* pdata) { + UNUSED(pdata); + osThreadFlagsSet(ble_glue->shci_user_event_thread_id, 1); +} + +void shci_cmd_resp_release(uint32_t flag) { + UNUSED(flag); + osSemaphoreRelease(ble_glue->shci_sem); +} + +void shci_cmd_resp_wait(uint32_t timeout) { + UNUSED(timeout); + osSemaphoreAcquire(ble_glue->shci_sem, osWaitForever); +} diff --git a/firmware/targets/f6/ble-glue/ble_glue.h b/firmware/targets/f6/ble-glue/ble_glue.h new file mode 100644 index 00000000..e9d6c03f --- /dev/null +++ b/firmware/targets/f6/ble-glue/ble_glue.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context); + +typedef enum { + BleGlueStatusUninitialized, + BleGlueStatusStartup, + BleGlueStatusBleStackMissing, + BleGlueStatusStarted +} BleGlueStatus; + +void ble_glue_init(); + +BleGlueStatus ble_glue_get_status(); + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f6/ble-glue/gap.c b/firmware/targets/f6/ble-glue/gap.c index eae5f87c..9ddae208 100644 --- a/firmware/targets/f6/ble-glue/gap.c +++ b/firmware/targets/f6/ble-glue/gap.c @@ -1,6 +1,5 @@ #include "gap.h" -#include "app_entry.h" #include "ble.h" #include "cmsis_os.h" @@ -375,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) { } bool gap_init(BleEventCallback on_event_cb, void* context) { - if (APPE_Status() != BleGlueStatusStarted) { + if (ble_glue_get_status() != BleGlueStatusStarted) { return false; } diff --git a/firmware/targets/f6/ble-glue/hw_conf.h b/firmware/targets/f6/ble-glue/hw_conf.h index dcda0176..9545238b 100644 --- a/firmware/targets/f6/ble-glue/hw_conf.h +++ b/firmware/targets/f6/ble-glue/hw_conf.h @@ -29,6 +29,37 @@ * Semaphores * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ *****************************************************************************/ +/** +* Index of the semaphore used the prevent conflicts after standby sleep. +* Each CPUs takes this semaphore at standby wakeup until conclicting elements are restored. +*/ +#define CFG_HW_PWR_STANDBY_SEMID 10 +/** +* The CPU2 may be configured to store the Thread persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* CFG_HW_THREAD_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_THREAD_NVM_SRAM_SEMID 9 + +/** +* The CPU2 may be configured to store the BLE persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* CFG_HW_BLE_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_BLE_NVM_SRAM_SEMID 8 + /** * Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash * The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 diff --git a/firmware/targets/f6/furi-hal/furi-hal-bt.c b/firmware/targets/f6/furi-hal/furi-hal-bt.c index 97db87c7..a018085c 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f6/furi-hal/furi-hal-bt.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -7,11 +6,37 @@ #include +osMutexId_t furi_hal_bt_core2_mtx = NULL; + void furi_hal_bt_init() { + furi_hal_bt_core2_mtx = osMutexNew(NULL); +} + +static bool furi_hal_bt_wait_startup() { + uint16_t counter = 0; + while (!(ble_glue_get_status() == BleGlueStatusStarted || ble_glue_get_status() == BleGlueStatusBleStackMissing)) { + osDelay(10); + counter++; + if (counter > 1000) { + return false; + } + } + return true; +} + +bool furi_hal_bt_start_core2() { + furi_assert(furi_hal_bt_core2_mtx); + + bool ret = false; + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); // Explicitly tell that we are in charge of CLK48 domain HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID); - // Start Core2, init HCI and start GAP/GATT - APPE_Init(); + // Start Core2 + ble_glue_init(); + // Wait for Core2 start + ret = furi_hal_bt_wait_startup(); + osMutexRelease(furi_hal_bt_core2_mtx); + return ret; } bool furi_hal_bt_init_app(BleEventCallback event_cb, void* context) { @@ -45,8 +70,33 @@ bool furi_hal_bt_tx(uint8_t* data, uint16_t size) { return serial_svc_update_tx(data, size); } +bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) { + bool ret = false; + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusUninitialized || BleGlueStatusStarted) { + ble_app_get_key_storage_buff(key_buff_addr, key_buff_size); + ret = true; + } + return ret; +} + +void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(callback); + ble_glue_set_key_storage_changed_callback(callback, context); +} + +void furi_hal_bt_nvm_sram_sem_acquire() { + while(HAL_HSEM_FastTake(CFG_HW_BLE_NVM_SRAM_SEMID) != HAL_OK) { + osDelay(1); + } +} + +void furi_hal_bt_nvm_sram_sem_release() { + HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); +} + void furi_hal_bt_dump_state(string_t buffer) { - BleGlueStatus status = APPE_Status(); + BleGlueStatus status = ble_glue_get_status(); if (status == BleGlueStatusStarted) { uint8_t HCI_Version; uint16_t HCI_Revision; @@ -68,56 +118,97 @@ void furi_hal_bt_dump_state(string_t buffer) { } bool furi_hal_bt_is_alive() { - BleGlueStatus status = APPE_Status(); - return (status == BleGlueStatusBroken) || (status == BleGlueStatusStarted); + BleGlueStatus status = ble_glue_get_status(); + return (status == BleGlueStatusBleStackMissing) || (status == BleGlueStatusStarted); } bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } -bool furi_hal_bt_wait_startup() { - uint16_t counter = 0; - while (!(APPE_Status() == BleGlueStatusStarted || APPE_Status() == BleGlueStatusBroken)) { - osDelay(10); - counter++; - if (counter > 1000) { - return false; - } - } - return true; -} - -bool furi_hal_bt_lock_flash(bool erase_flag) { - if (!furi_hal_bt_wait_startup()) { - return false; - } - +static void furi_hal_bt_lock_flash_core2(bool erase_flag) { + // Take flash controller ownership while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { - osDelay(1); + taskYIELD(); } + // Unlock flash operation HAL_FLASH_Unlock(); + // Erase activity notification if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); - while(LL_FLASH_IsActiveFlag_OperationSuspended()) { - osDelay(1); - }; + while(true) { + // Wait till flash controller become usable + while(LL_FLASH_IsActiveFlag_OperationSuspended()) { + taskYIELD(); + }; - __disable_irq(); + // Just a little more love + taskENTER_CRITICAL(); - return true; + // Actually we already have mutex for it, but specification is specification + if (HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { + taskEXIT_CRITICAL(); + continue; + } + + // Take sempahopre and prevent core2 from anyting funky + if (HAL_HSEM_FastTake(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != HAL_OK) { + taskEXIT_CRITICAL(); + continue; + } + + break; + } +} + +void furi_hal_bt_lock_flash(bool erase_flag) { + // Acquire dangerous ops mutex + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); + + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_lock_flash_core2(erase_flag); + } else { + HAL_FLASH_Unlock(); + } +} + +static void furi_hal_bt_unlock_flash_core2(bool erase_flag) { + // Funky ops are ok at this point + HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, 0); + + // Task switching is ok + taskEXIT_CRITICAL(); + + // Doesn't make much sense, does it? + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + taskYIELD(); + } + + // Erase activity over, core2 can continue + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + + // Lock flash controller + HAL_FLASH_Lock(); + + // Release flash controller ownership + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, 0); } void furi_hal_bt_unlock_flash(bool erase_flag) { - __enable_irq(); + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_unlock_flash_core2(erase_flag); + } else { + HAL_FLASH_Lock(); + } - if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); - - HAL_FLASH_Lock(); - - HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); + // Release dangerous ops mutex + osMutexRelease(furi_hal_bt_core2_mtx); } void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { diff --git a/firmware/targets/f6/furi-hal/furi-hal-console.h b/firmware/targets/f6/furi-hal/furi-hal-console.h index 4c10d81e..637c17f6 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-console.h +++ b/firmware/targets/f6/furi-hal/furi-hal-console.h @@ -7,12 +7,6 @@ extern "C" { #endif -typedef enum { - UartIrqEventRXNE, - UartIrqEventIDLE, - //TODO: more events -} UartIrqEvent; - void furi_hal_console_init(); void furi_hal_console_enable(); diff --git a/firmware/targets/f6/furi-hal/furi-hal-crypto.c b/firmware/targets/f6/furi-hal/furi-hal-crypto.c index 3e4ec98f..648f3f18 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-crypto.c +++ b/firmware/targets/f6/furi-hal/furi-hal-crypto.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,24 +13,28 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { furi_assert(key); furi_assert(slot); + if(!furi_hal_bt_is_alive()) { + return false; + } + SHCI_C2_FUS_StoreUsrKey_Cmd_Param_t pParam; size_t key_data_size = 0; - if (key->type == FuriHalCryptoKeyTypeMaster) { + if(key->type == FuriHalCryptoKeyTypeMaster) { pParam.KeyType = KEYTYPE_MASTER; - } else if (key->type == FuriHalCryptoKeyTypeSimple) { + } else if(key->type == FuriHalCryptoKeyTypeSimple) { pParam.KeyType = KEYTYPE_SIMPLE; - } else if (key->type == FuriHalCryptoKeyTypeEncrypted) { + } else if(key->type == FuriHalCryptoKeyTypeEncrypted) { pParam.KeyType = KEYTYPE_ENCRYPTED; key_data_size += 12; } else { furi_crash("Incorrect key type"); } - if (key->size == FuriHalCryptoKeySize128) { + if(key->size == FuriHalCryptoKeySize128) { pParam.KeySize = KEYSIZE_16; key_data_size += 16; - } else if (key->size == FuriHalCryptoKeySize256) { + } else if(key->size == FuriHalCryptoKeySize256) { pParam.KeySize = KEYSIZE_32; key_data_size += 32; } else { @@ -44,16 +49,21 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(slot > 0 && slot <= 100); + if(!furi_hal_bt_is_alive()) { + return false; + } + crypt.Instance = AES1; crypt.Init.DataType = CRYP_DATATYPE_32B; crypt.Init.KeySize = CRYP_KEYSIZE_256B; crypt.Init.Algorithm = CRYP_AES_CBC; crypt.Init.pInitVect = (uint32_t*)iv; + crypt.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE; crypt.Init.pKey = NULL; furi_check(HAL_CRYP_Init(&crypt) == HAL_OK); - if (SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { + if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { return true; } else { furi_check(HAL_CRYP_DeInit(&crypt) == HAL_OK); @@ -62,14 +72,18 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { } bool furi_hal_crypto_store_unload_key(uint8_t slot) { + if(!furi_hal_bt_is_alive()) { + return false; + } + furi_check(HAL_CRYP_DeInit(&crypt) == HAL_OK); return SHCI_C2_FUS_UnloadUsrKey(slot) == SHCI_Success; } -bool furi_hal_crypto_encrypt(const uint8_t *input, uint8_t *output, size_t size) { - return HAL_CRYP_Encrypt(&crypt, (uint32_t*)input, size/4, (uint32_t*)output, 1000) == HAL_OK; +bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) { + return HAL_CRYP_Encrypt(&crypt, (uint32_t*)input, size / 4, (uint32_t*)output, 1000) == HAL_OK; } -bool furi_hal_crypto_decrypt(const uint8_t *input, uint8_t *output, size_t size) { - return HAL_CRYP_Decrypt(&crypt, (uint32_t*)input, size/4, (uint32_t*)output, 1000) == HAL_OK; +bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size) { + return HAL_CRYP_Decrypt(&crypt, (uint32_t*)input, size / 4, (uint32_t*)output, 1000) == HAL_OK; } diff --git a/firmware/targets/f6/furi-hal/furi-hal-flash.c b/firmware/targets/f6/furi-hal/furi-hal-flash.c index c9922122..1e270bc0 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-flash.c +++ b/firmware/targets/f6/furi-hal/furi-hal-flash.c @@ -1,11 +1,14 @@ #include #include -#include #include +#include + /* Free flash space borders, exported by linker */ extern const void __free_flash_start__; +#define FURI_HAL_TAG "FuriHalFlash" +#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" #define FURI_HAL_FLASH_READ_BLOCK 8 #define FURI_HAL_FLASH_WRITE_BLOCK 8 #define FURI_HAL_FLASH_PAGE_SIZE 4096 @@ -57,33 +60,46 @@ size_t furi_hal_flash_get_free_page_count() { } bool furi_hal_flash_erase(uint8_t page, uint8_t count) { - if (!furi_hal_bt_lock_flash(true)) { - return false; - } + furi_hal_bt_lock_flash(true); + FLASH_EraseInitTypeDef erase; erase.TypeErase = FLASH_TYPEERASE_PAGES; erase.Page = page; erase.NbPages = count; - uint32_t error; - HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); + + uint32_t error_page = 0; + HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error_page); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Erase failed, ret: %d, page: %d", status, error_page); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(true); - return status == HAL_OK; + + return true; } bool furi_hal_flash_write_dword(size_t address, uint64_t data) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Programming failed, ret: %d, address: %p", status, address); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } +bool furi_hal_flash_write_row(size_t address, size_t source_address) { + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); + furi_check(status == HAL_OK); + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } diff --git a/firmware/targets/f6/furi-hal/furi-hal-flash.h b/firmware/targets/f6/furi-hal/furi-hal-flash.h index 583d53eb..92a65a65 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-flash.h +++ b/firmware/targets/f6/furi-hal/furi-hal-flash.h @@ -80,7 +80,7 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count); */ bool furi_hal_flash_write_dword(size_t address, uint64_t data); -/** Write double word (64 bits) from address +/** Write row: 64 double word (64 bits) from address * * Locking operation, uses HSEM to manage shared access. * @@ -89,4 +89,4 @@ bool furi_hal_flash_write_dword(size_t address, uint64_t data); * * @return true on success */ -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address); +bool furi_hal_flash_write_row(size_t address, size_t source_address); diff --git a/firmware/targets/f6/furi-hal/furi-hal-lock.c b/firmware/targets/f6/furi-hal/furi-hal-lock.c new file mode 100644 index 00000000..0f519380 --- /dev/null +++ b/firmware/targets/f6/furi-hal/furi-hal-lock.c @@ -0,0 +1,17 @@ +#include "furi-hal-lock.h" +#include + +#define FLIPPER_LOCKED_VALUE 0x5432FAFA + +bool furi_hal_lock_get() { + return FLIPPER_LOCKED_VALUE == LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR3); +} + +void furi_hal_lock_set(bool locked) { + if (locked) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, FLIPPER_LOCKED_VALUE); + } else { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, 0); + } +} + diff --git a/firmware/targets/f6/furi-hal/furi-hal-spi.c b/firmware/targets/f6/furi-hal/furi-hal-spi.c index c925abee..805b8dfb 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-spi.c +++ b/firmware/targets/f6/furi-hal/furi-hal-spi.c @@ -133,7 +133,7 @@ const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) { furi_assert(device_id < FuriHalSpiDeviceIdMax); const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id]; - assert(device); + furi_assert(device); furi_hal_spi_bus_lock(device->bus); furi_hal_spi_device_configure(device); diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c index e25c40d1..cd610cb2 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c @@ -676,7 +676,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { } uint32_t duration = level_duration_get_duration(ld); - assert(duration > 0); + furi_assert(duration > 0); *buffer = duration; buffer++; samples--; diff --git a/firmware/targets/f6/furi-hal/furi-hal-uart.h b/firmware/targets/f6/furi-hal/furi-hal-uart.h index 6be156b7..731a12a2 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-uart.h +++ b/firmware/targets/f6/furi-hal/furi-hal-uart.h @@ -2,7 +2,6 @@ #include #include -#include "furi-hal-console.h" #ifdef __cplusplus extern "C" { @@ -13,6 +12,11 @@ typedef enum { FuriHalUartIdLPUART1, } FuriHalUartId; +typedef enum { + UartIrqEventRXNE, + UartIrqEventIDLE, + //TODO: more events +} UartIrqEvent; void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud); diff --git a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c index 9386b100..dd82cf16 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c +++ b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c @@ -7,12 +7,12 @@ #include "usb_cdc.h" #define CDC0_RXD_EP 0x01 -#define CDC0_TXD_EP 0x81 -#define CDC0_NTF_EP 0x82 +#define CDC0_TXD_EP 0x82 +#define CDC0_NTF_EP 0x83 -#define CDC1_RXD_EP 0x03 -#define CDC1_TXD_EP 0x83 -#define CDC1_NTF_EP 0x84 +#define CDC1_RXD_EP 0x04 +#define CDC1_TXD_EP 0x85 +#define CDC1_NTF_EP 0x86 #define CDC_NTF_SZ 0x08 @@ -446,10 +446,12 @@ void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) { } int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) { + int32_t len = 0; if (if_num == 0) - return usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); + len = usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); else - return usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); + len = usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); + return ((len < 0) ? 0 : len); } static void cdc_on_wakeup(usbd_device *dev) { diff --git a/firmware/targets/f6/furi-hal/furi-hal-vcp.c b/firmware/targets/f6/furi-hal/furi-hal-vcp.c index b2f17842..b0b47f46 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-vcp.c +++ b/firmware/targets/f6/furi-hal/furi-hal-vcp.c @@ -3,18 +3,28 @@ #include #include -#define APP_RX_DATA_SIZE CDC_DATA_SZ -#define APP_TX_DATA_SIZE CDC_DATA_SZ -#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16) +#define USB_CDC_PKT_LEN CDC_DATA_SZ #define VCP_IF_NUM 0 +typedef enum { + VcpConnect, + VcpDisconnect, +} VcpEvent; + typedef struct { volatile bool connected; - StreamBufferHandle_t rx_stream; - volatile bool rx_stream_full; + uint8_t rx_buf[USB_CDC_PKT_LEN]; + uint8_t rx_buf_start; + uint8_t rx_buf_len; + + osMessageQueueId_t event_queue; + + osMutexId_t usb_mutex; + + osSemaphoreId_t tx_sem; + osSemaphoreId_t rx_sem; - osSemaphoreId_t tx_semaphore; } FuriHalVcp; static void vcp_on_cdc_tx_complete(); @@ -30,22 +40,21 @@ static CdcCallbacks cdc_cb = { NULL, }; -static FuriHalVcp* furi_hal_vcp = NULL; +static FuriHalVcp* vcp = NULL; static const uint8_t ascii_soh = 0x01; static const uint8_t ascii_eot = 0x04; -static uint8_t* vcp_rx_buf; - void furi_hal_vcp_init() { - furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); - vcp_rx_buf = furi_alloc(APP_RX_DATA_SIZE); - furi_hal_vcp->connected = false; - - furi_hal_vcp->rx_stream = xStreamBufferCreate(FURI_HAL_VCP_RX_BUFFER_SIZE, 1); - furi_hal_vcp->rx_stream_full = false; + vcp = furi_alloc(sizeof(FuriHalVcp)); + vcp->connected = false; - furi_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL); + vcp->usb_mutex = osMutexNew(NULL); + + vcp->tx_sem = osSemaphoreNew(1, 1, NULL); + vcp->rx_sem = osSemaphoreNew(1, 0, NULL); + + vcp->event_queue = osMessageQueueNew(8, sizeof(VcpEvent), NULL); furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb); @@ -54,111 +63,149 @@ void furi_hal_vcp_init() { void furi_hal_vcp_enable() { furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb); - furi_hal_vcp->connected = true; + VcpEvent evt = VcpConnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + vcp->connected = true; + osSemaphoreRelease(vcp->tx_sem); + osSemaphoreRelease(vcp->rx_sem); } void furi_hal_vcp_disable() { furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL); - furi_hal_vcp->connected = false; - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); -} - -size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) { - furi_assert(furi_hal_vcp); - - size_t received = xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); - - if(furi_hal_vcp->rx_stream_full - && xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) { - furi_hal_vcp->rx_stream_full = false; - } - - return received; + VcpEvent evt = VcpDisconnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + vcp->connected = false; + osSemaphoreRelease(vcp->tx_sem); + osSemaphoreRelease(vcp->rx_sem); } size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) { - furi_assert(furi_hal_vcp); - return xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, timeout); + furi_assert(vcp); + furi_assert(buffer); + + size_t rx_cnt = 0; + + VcpEvent evt = VcpDisconnect; + + if (vcp->rx_buf_len > 0) { + size_t len = (vcp->rx_buf_len > size) ? (size) : (vcp->rx_buf_len); + memcpy(&buffer[rx_cnt], &vcp->rx_buf[vcp->rx_buf_start], len); + vcp->rx_buf_len -= len; + vcp->rx_buf_start += len; + rx_cnt += len; + } + + while (rx_cnt < size) { + if (osMessageQueueGet(vcp->event_queue, &evt, NULL, 0) == osOK) { + if (evt == VcpConnect) + buffer[rx_cnt] = ascii_soh; + else { + buffer[rx_cnt] = ascii_eot; + vcp->rx_buf_len = 0; + } + rx_cnt++; + return rx_cnt; + } + + if (osSemaphoreAcquire(vcp->rx_sem, timeout) == osErrorTimeout) + return rx_cnt; + + furi_check(osMutexAcquire(vcp->usb_mutex, osWaitForever) == osOK); + size_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->rx_buf, USB_CDC_PKT_LEN); + furi_check(osMutexRelease(vcp->usb_mutex) == osOK); + + vcp->rx_buf_len = len; + vcp->rx_buf_start = 0; + + if (vcp->rx_buf_len > (size - rx_cnt)) { + len = size - rx_cnt; + memcpy(&buffer[rx_cnt], vcp->rx_buf, len); + vcp->rx_buf_len -= len; + vcp->rx_buf_start += len; + } else { + memcpy(&buffer[rx_cnt], vcp->rx_buf, vcp->rx_buf_len); + vcp->rx_buf_len = 0; + } + rx_cnt += len; + } + return rx_cnt; +} + +size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) { + furi_assert(vcp); + + return furi_hal_vcp_rx_with_timeout(buffer, size, portMAX_DELAY); } void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { - furi_assert(furi_hal_vcp); + furi_assert(vcp); - while (size > 0 && furi_hal_vcp->connected) { - furi_check(osSemaphoreAcquire(furi_hal_vcp->tx_semaphore, osWaitForever) == osOK); - if (!furi_hal_vcp->connected) + while (size > 0 && vcp->connected) { + furi_check(osSemaphoreAcquire(vcp->tx_sem, osWaitForever) == osOK); + if (!vcp->connected) break; size_t batch_size = size; - if (batch_size > APP_TX_DATA_SIZE) { - batch_size = APP_TX_DATA_SIZE; + if (batch_size > USB_CDC_PKT_LEN) { + batch_size = USB_CDC_PKT_LEN; } + furi_check(osMutexAcquire(vcp->usb_mutex, osWaitForever) == osOK); furi_hal_cdc_send(VCP_IF_NUM, (uint8_t*)buffer, batch_size); + furi_check(osMutexRelease(vcp->usb_mutex) == osOK); + size -= batch_size; buffer += batch_size; } } static void vcp_state_callback(uint8_t state) { - if (state == 1) - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); - else if (furi_hal_vcp->connected) { - furi_hal_vcp->connected = false; - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); + if (state == 1) { + osSemaphoreRelease(vcp->rx_sem); + //osSemaphoreRelease(vcp->tx_sem); + } + else if (vcp->connected) { + vcp->connected = false; + osSemaphoreRelease(vcp->rx_sem); + VcpEvent evt = VcpDisconnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + //osSemaphoreRelease(vcp->tx_sem); } } static void vcp_on_cdc_control_line(uint8_t state) { - - BaseType_t xHigherPriorityTaskWoken = pdFALSE; // bit 0: DTR state, bit 1: RTS state - // bool dtr = state & 0b01; bool dtr = state & 0b1; if (dtr) { - if (!furi_hal_vcp->connected) { - furi_hal_vcp->connected = true; - xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, &ascii_soh, 1, &xHigherPriorityTaskWoken); // SOH - + if (!vcp->connected) { + vcp->connected = true; + VcpEvent evt = VcpConnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); } } else { - if (furi_hal_vcp->connected) { - xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, &ascii_eot, 1, &xHigherPriorityTaskWoken); // EOT - furi_hal_vcp->connected = false; + if (vcp->connected) { + VcpEvent evt = VcpDisconnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + vcp->connected = false; } } - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + osSemaphoreRelease(vcp->tx_sem); + osSemaphoreRelease(vcp->rx_sem); } -static void vcp_on_cdc_rx() { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream); - if (max_len > 0) { - if (max_len > APP_RX_DATA_SIZE) - max_len = APP_RX_DATA_SIZE; - int32_t size = furi_hal_cdc_receive(VCP_IF_NUM, vcp_rx_buf, max_len); - - if (size > 0) { - size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken); - furi_check(ret == size); - } - } else { - furi_hal_vcp->rx_stream_full = true; - }; - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +static void vcp_on_cdc_rx() { + if (vcp->connected == false) + return; + osSemaphoreRelease(vcp->rx_sem); } static void vcp_on_cdc_tx_complete() { - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); + osSemaphoreRelease(vcp->tx_sem); } bool furi_hal_vcp_is_connected(void) { - return furi_hal_vcp->connected; + return vcp->connected; } diff --git a/firmware/targets/f7/ble-glue/app_conf.h b/firmware/targets/f7/ble-glue/app_conf.h index e3820e11..eebdbbdb 100644 --- a/firmware/targets/f7/ble-glue/app_conf.h +++ b/firmware/targets/f7/ble-glue/app_conf.h @@ -427,16 +427,5 @@ typedef enum #define DBG_TRACE_MSG_QUEUE_SIZE 4096 #define MAX_DBG_TRACE_MSG_SIZE 1024 -/****************************************************************************** - * FreeRTOS - ******************************************************************************/ -#define CFG_SHCI_USER_EVT_PROCESS_NAME "ble_shci_evt" -#define CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_SIZE (0) -#define CFG_SHCI_USER_EVT_PROCESS_STACK_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_PRIORITY osPriorityNone -#define CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE (128 * 7) - #define CFG_OTP_BASE_ADDRESS OTP_AREA_BASE #define CFG_OTP_END_ADRESS OTP_AREA_END_ADDR diff --git a/firmware/targets/f7/ble-glue/app_entry.c b/firmware/targets/f7/ble-glue/app_entry.c deleted file mode 100644 index 5c8c0b2a..00000000 --- a/firmware/targets/f7/ble-glue/app_entry.c +++ /dev/null @@ -1,180 +0,0 @@ -#include "app_common.h" -#include "main.h" -#include "app_entry.h" -#include "ble_app.h" -#include "ble.h" -#include "tl.h" -#include "cmsis_os.h" -#include "shci_tl.h" -#include "app_debug.h" -#include - -extern RTC_HandleTypeDef hrtc; - -#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) - -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; - -osMutexId_t MtxShciId; -osSemaphoreId_t SemShciId; -osThreadId_t ShciUserEvtProcessId; - -volatile static BleGlueStatus ble_glue_status = BleGlueStatusUninitialized; - -const osThreadAttr_t ShciUserEvtProcess_attr = { - .name = CFG_SHCI_USER_EVT_PROCESS_NAME, - .attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS, - .cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM, - .cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE, - .stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM, - .priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY, - .stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE -}; - -static void ShciUserEvtProcess(void *argument); -static void SystemPower_Config( void ); -static void appe_Tl_Init( void ); -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ); -static void APPE_SysUserEvtRx( void * pPayload ); - -BleGlueStatus APPE_Status() { - return ble_glue_status; -} - -void APPE_Init() { - ble_glue_status = BleGlueStatusStartup; - SystemPower_Config(); /**< Configure the system Power Mode */ - - // APPD_Init(); - furi_hal_power_insomnia_enter(); - - appe_Tl_Init(); /* Initialize all transport layers */ - - /** - * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) - * received on the system channel before starting the Stack - * This system event is received with APPE_SysUserEvtRx() - */ -} - -/************************************************************* - * - * LOCAL FUNCTIONS - * - *************************************************************/ - -/** - * @brief Configure the system for power optimization - * - * @note This API configures the system to be ready for low power mode - * - * @param None - * @retval None - */ -static void SystemPower_Config(void) { - // Select HSI as system clock source after Wake Up from Stop mode - LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); - - /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); -} - -static void appe_Tl_Init( void ) { - TL_MM_Config_t tl_mm_config; - SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; - /**< Reference table initialization */ - TL_Init(); - - MtxShciId = osMutexNew( NULL ); - SemShciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */ - - /** FreeRTOS system task creation */ - ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr); - - /**< System channel initialization */ - SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer; - SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot; - shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf); - - /**< Memory Manager channel initialization */ - tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer; - tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer; - tl_mm_config.p_AsynchEvtPool = EvtPool; - tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; - TL_MM_Init( &tl_mm_config ); - - TL_Enable(); -} - -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ) { - switch (status) { - case SHCI_TL_CmdBusy: - osMutexAcquire( MtxShciId, osWaitForever ); - break; - case SHCI_TL_CmdAvailable: - osMutexRelease( MtxShciId ); - break; - default: - break; - } -} - -/** - * The type of the payload for a system user event is tSHCI_UserEvtRxParam - * When the system event is both : - * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) - * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) - * The buffer shall not be released - * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) - * When the status is not filled, the buffer is released by default - */ -static void APPE_SysUserEvtRx( void * pPayload ) { - UNUSED(pPayload); - /* Traces channel initialization */ - // APPD_EnableCPU2( ); - - if(ble_app_init()) { - FURI_LOG_I("Core2", "BLE stack started"); - ble_glue_status = BleGlueStatusStarted; - } else { - FURI_LOG_E("Core2", "BLE stack startup failed"); - ble_glue_status = BleGlueStatusBroken; - } - furi_hal_power_insomnia_exit(); -} - -/************************************************************* - * - * FREERTOS WRAPPER FUNCTIONS - * -*************************************************************/ -static void ShciUserEvtProcess(void *argument) { - UNUSED(argument); - for(;;) { - osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); - shci_user_evt_proc(); - } -} - -/************************************************************* - * - * WRAP FUNCTIONS - * - *************************************************************/ -void shci_notify_asynch_evt(void* pdata) { - UNUSED(pdata); - osThreadFlagsSet( ShciUserEvtProcessId, 1 ); -} - -void shci_cmd_resp_release(uint32_t flag) { - UNUSED(flag); - osSemaphoreRelease( SemShciId ); -} - -void shci_cmd_resp_wait(uint32_t timeout) { - UNUSED(timeout); - osSemaphoreAcquire( SemShciId, osWaitForever ); -} diff --git a/firmware/targets/f7/ble-glue/app_entry.h b/firmware/targets/f7/ble-glue/app_entry.h deleted file mode 100644 index f1ce6038..00000000 --- a/firmware/targets/f7/ble-glue/app_entry.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - BleGlueStatusUninitialized, - BleGlueStatusStartup, - BleGlueStatusBroken, - BleGlueStatusStarted -} BleGlueStatus; - -void APPE_Init(); - -BleGlueStatus APPE_Status(); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/firmware/targets/f7/ble-glue/ble_app.c b/firmware/targets/f7/ble-glue/ble_app.c index e28facd6..33e5264a 100644 --- a/firmware/targets/f7/ble-glue/ble_app.c +++ b/firmware/targets/f7/ble-glue/ble_app.c @@ -11,6 +11,7 @@ #define BLE_APP_TAG "ble app" PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; typedef struct { osMutexId_t hci_mtx; @@ -26,8 +27,8 @@ static void ble_app_hci_event_handler(void * pPayload); static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status); bool ble_app_init() { + SHCI_CmdStatus_t status; ble_app = furi_alloc(sizeof(BleApp)); - // Allocate semafore and mutex for ble command buffer access ble_app->hci_mtx = osMutexNew(NULL); ble_app->hci_sem = osSemaphoreNew(1, 0, NULL); @@ -43,6 +44,18 @@ bool ble_app_init() { }; hci_init(ble_app_hci_event_handler, (void*)&hci_tl_config); + // Configure NVM store for pairing data + SHCI_C2_CONFIG_Cmd_Param_t config_param = { + .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, + .Config1 =SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, + .BleNvmRamAddress = (uint32_t)ble_app_nvm, + .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, + }; + status = SHCI_C2_Config(&config_param); + if(status) { + FURI_LOG_E(BLE_APP_TAG, "Failed to configure 2nd core: %d", status); + } + // Start ble stack on 2nd core SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { .Header = {{0,0,0}}, // Header unused @@ -67,13 +80,18 @@ bool ble_app_init() { 0, } }; - SHCI_CmdStatus_t status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); + status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); if(status) { FURI_LOG_E(BLE_APP_TAG, "Failed to start ble stack: %d", status); } return status == SHCI_Success; } +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) { + *addr = (uint8_t*)ble_app_nvm; + *size = sizeof(ble_app_nvm); +} + static void ble_app_hci_thread(void *arg) { while(1) { osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); diff --git a/firmware/targets/f7/ble-glue/ble_app.h b/firmware/targets/f7/ble-glue/ble_app.h index 17d8dc5f..64000bde 100644 --- a/firmware/targets/f7/ble-glue/ble_app.h +++ b/firmware/targets/f7/ble-glue/ble_app.h @@ -5,8 +5,10 @@ extern "C" { #endif #include +#include bool ble_app_init(); +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size); #ifdef __cplusplus } diff --git a/firmware/targets/f7/ble-glue/ble_glue.c b/firmware/targets/f7/ble-glue/ble_glue.c new file mode 100644 index 00000000..4a9c144e --- /dev/null +++ b/firmware/targets/f7/ble-glue/ble_glue.c @@ -0,0 +1,173 @@ +#include "ble_glue.h" +#include "app_common.h" +#include "main.h" +#include "ble_app.h" +#include "ble.h" +#include "tl.h" +#include "shci.h" +#include "cmsis_os.h" +#include "shci_tl.h" +#include "app_debug.h" +#include + +#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) + +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_event_pool[POOL_SIZE]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_buff; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; + +typedef struct { + osMutexId_t shci_mtx; + osSemaphoreId_t shci_sem; + osThreadId_t shci_user_event_thread_id; + osThreadAttr_t shci_user_event_thread_attr; + BleGlueStatus status; + BleGlueKeyStorageChangedCallback callback; + void* context; +} BleGlue; + +static BleGlue* ble_glue = NULL; + +static void ble_glue_user_event_thread(void *argument); +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status); +static void ble_glue_sys_user_event_callback(void* pPayload); + +BleGlueStatus ble_glue_get_status() { + if(!ble_glue) { + return BleGlueStatusUninitialized; + } + return ble_glue->status; +} + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(ble_glue); + furi_assert(callback); + ble_glue->callback = callback; + ble_glue->context = context; +} + +void ble_glue_init() { + ble_glue = furi_alloc(sizeof(BleGlue)); + ble_glue->status = BleGlueStatusStartup; + ble_glue->shci_user_event_thread_attr.name = "ble_shci_evt"; + ble_glue->shci_user_event_thread_attr.stack_size = 1024; + + // Configure the system Power Mode + // Select HSI as system clock source after Wake Up from Stop mode + LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); + /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ + LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); + furi_hal_power_insomnia_enter(); + + // APPD_Init(); + + // Initialize all transport layers + TL_MM_Config_t tl_mm_config; + SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; + // Reference table initialization + TL_Init(); + + ble_glue->shci_mtx = osMutexNew(NULL); + ble_glue->shci_sem = osSemaphoreNew(1, 0, NULL); + + // FreeRTOS system task creation + ble_glue->shci_user_event_thread_id = osThreadNew(ble_glue_user_event_thread, NULL, &ble_glue->shci_user_event_thread_attr); + + // System channel initialization + SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&ble_glue_system_cmd_buff; + SHci_Tl_Init_Conf.StatusNotCallBack = ble_glue_sys_status_not_callback; + shci_init(ble_glue_sys_user_event_callback, (void*) &SHci_Tl_Init_Conf); + + /**< Memory Manager channel initialization */ + tl_mm_config.p_BleSpareEvtBuffer = ble_glue_ble_spare_event_buff; + tl_mm_config.p_SystemSpareEvtBuffer = ble_glue_system_spare_event_buff; + tl_mm_config.p_AsynchEvtPool = ble_glue_event_pool; + tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; + TL_MM_Init( &tl_mm_config ); + TL_Enable(); + + /* + * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) + * received on the system channel before starting the Stack + * This system event is received with ble_glue_sys_user_event_callback() + */ +} + +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { + switch (status) { + case SHCI_TL_CmdBusy: + osMutexAcquire( ble_glue->shci_mtx, osWaitForever ); + break; + case SHCI_TL_CmdAvailable: + osMutexRelease( ble_glue->shci_mtx ); + break; + default: + break; + } +} + +/* + * The type of the payload for a system user event is tSHCI_UserEvtRxParam + * When the system event is both : + * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) + * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) + * The buffer shall not be released + * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) + * When the status is not filled, the buffer is released by default + */ +static void ble_glue_sys_user_event_callback( void * pPayload ) { + UNUSED(pPayload); + /* Traces channel initialization */ + // APPD_EnableCPU2( ); + + TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload); + + if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { + if(ble_app_init()) { + FURI_LOG_I("Core2", "BLE stack started"); + ble_glue->status = BleGlueStatusStarted; + if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) { + FURI_LOG_I("Core2", "Flash activity control switched to SEM7"); + } else { + FURI_LOG_E("Core2", "Failed to switch flash activity control to SEM7"); + } + } else { + FURI_LOG_E("Core2", "BLE stack startup failed"); + ble_glue->status = BleGlueStatusBleStackMissing; + } + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) { + FURI_LOG_E("Core2", "Error during initialization"); + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE) { + SHCI_C2_BleNvmRamUpdate_Evt_t* p_sys_ble_nvm_ram_update_event = (SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload; + if(ble_glue->callback) { + ble_glue->callback((uint8_t*)p_sys_ble_nvm_ram_update_event->StartAddress, p_sys_ble_nvm_ram_update_event->Size, ble_glue->context); + } + } +} + +// Wrap functions +static void ble_glue_user_event_thread(void *argument) { + UNUSED(argument); + for(;;) { + osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); + shci_user_evt_proc(); + } +} + +void shci_notify_asynch_evt(void* pdata) { + UNUSED(pdata); + osThreadFlagsSet(ble_glue->shci_user_event_thread_id, 1); +} + +void shci_cmd_resp_release(uint32_t flag) { + UNUSED(flag); + osSemaphoreRelease(ble_glue->shci_sem); +} + +void shci_cmd_resp_wait(uint32_t timeout) { + UNUSED(timeout); + osSemaphoreAcquire(ble_glue->shci_sem, osWaitForever); +} diff --git a/firmware/targets/f7/ble-glue/ble_glue.h b/firmware/targets/f7/ble-glue/ble_glue.h new file mode 100644 index 00000000..e9d6c03f --- /dev/null +++ b/firmware/targets/f7/ble-glue/ble_glue.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context); + +typedef enum { + BleGlueStatusUninitialized, + BleGlueStatusStartup, + BleGlueStatusBleStackMissing, + BleGlueStatusStarted +} BleGlueStatus; + +void ble_glue_init(); + +BleGlueStatus ble_glue_get_status(); + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/ble-glue/gap.c b/firmware/targets/f7/ble-glue/gap.c index eae5f87c..9ddae208 100644 --- a/firmware/targets/f7/ble-glue/gap.c +++ b/firmware/targets/f7/ble-glue/gap.c @@ -1,6 +1,5 @@ #include "gap.h" -#include "app_entry.h" #include "ble.h" #include "cmsis_os.h" @@ -375,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) { } bool gap_init(BleEventCallback on_event_cb, void* context) { - if (APPE_Status() != BleGlueStatusStarted) { + if (ble_glue_get_status() != BleGlueStatusStarted) { return false; } diff --git a/firmware/targets/f7/ble-glue/hw_conf.h b/firmware/targets/f7/ble-glue/hw_conf.h index dcda0176..9545238b 100644 --- a/firmware/targets/f7/ble-glue/hw_conf.h +++ b/firmware/targets/f7/ble-glue/hw_conf.h @@ -29,6 +29,37 @@ * Semaphores * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ *****************************************************************************/ +/** +* Index of the semaphore used the prevent conflicts after standby sleep. +* Each CPUs takes this semaphore at standby wakeup until conclicting elements are restored. +*/ +#define CFG_HW_PWR_STANDBY_SEMID 10 +/** +* The CPU2 may be configured to store the Thread persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* CFG_HW_THREAD_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_THREAD_NVM_SRAM_SEMID 9 + +/** +* The CPU2 may be configured to store the BLE persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* CFG_HW_BLE_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_BLE_NVM_SRAM_SEMID 8 + /** * Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash * The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 diff --git a/firmware/targets/f7/furi-hal/furi-hal-bt.c b/firmware/targets/f7/furi-hal/furi-hal-bt.c index 97db87c7..a018085c 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f7/furi-hal/furi-hal-bt.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -7,11 +6,37 @@ #include +osMutexId_t furi_hal_bt_core2_mtx = NULL; + void furi_hal_bt_init() { + furi_hal_bt_core2_mtx = osMutexNew(NULL); +} + +static bool furi_hal_bt_wait_startup() { + uint16_t counter = 0; + while (!(ble_glue_get_status() == BleGlueStatusStarted || ble_glue_get_status() == BleGlueStatusBleStackMissing)) { + osDelay(10); + counter++; + if (counter > 1000) { + return false; + } + } + return true; +} + +bool furi_hal_bt_start_core2() { + furi_assert(furi_hal_bt_core2_mtx); + + bool ret = false; + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); // Explicitly tell that we are in charge of CLK48 domain HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID); - // Start Core2, init HCI and start GAP/GATT - APPE_Init(); + // Start Core2 + ble_glue_init(); + // Wait for Core2 start + ret = furi_hal_bt_wait_startup(); + osMutexRelease(furi_hal_bt_core2_mtx); + return ret; } bool furi_hal_bt_init_app(BleEventCallback event_cb, void* context) { @@ -45,8 +70,33 @@ bool furi_hal_bt_tx(uint8_t* data, uint16_t size) { return serial_svc_update_tx(data, size); } +bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) { + bool ret = false; + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusUninitialized || BleGlueStatusStarted) { + ble_app_get_key_storage_buff(key_buff_addr, key_buff_size); + ret = true; + } + return ret; +} + +void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(callback); + ble_glue_set_key_storage_changed_callback(callback, context); +} + +void furi_hal_bt_nvm_sram_sem_acquire() { + while(HAL_HSEM_FastTake(CFG_HW_BLE_NVM_SRAM_SEMID) != HAL_OK) { + osDelay(1); + } +} + +void furi_hal_bt_nvm_sram_sem_release() { + HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); +} + void furi_hal_bt_dump_state(string_t buffer) { - BleGlueStatus status = APPE_Status(); + BleGlueStatus status = ble_glue_get_status(); if (status == BleGlueStatusStarted) { uint8_t HCI_Version; uint16_t HCI_Revision; @@ -68,56 +118,97 @@ void furi_hal_bt_dump_state(string_t buffer) { } bool furi_hal_bt_is_alive() { - BleGlueStatus status = APPE_Status(); - return (status == BleGlueStatusBroken) || (status == BleGlueStatusStarted); + BleGlueStatus status = ble_glue_get_status(); + return (status == BleGlueStatusBleStackMissing) || (status == BleGlueStatusStarted); } bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } -bool furi_hal_bt_wait_startup() { - uint16_t counter = 0; - while (!(APPE_Status() == BleGlueStatusStarted || APPE_Status() == BleGlueStatusBroken)) { - osDelay(10); - counter++; - if (counter > 1000) { - return false; - } - } - return true; -} - -bool furi_hal_bt_lock_flash(bool erase_flag) { - if (!furi_hal_bt_wait_startup()) { - return false; - } - +static void furi_hal_bt_lock_flash_core2(bool erase_flag) { + // Take flash controller ownership while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { - osDelay(1); + taskYIELD(); } + // Unlock flash operation HAL_FLASH_Unlock(); + // Erase activity notification if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); - while(LL_FLASH_IsActiveFlag_OperationSuspended()) { - osDelay(1); - }; + while(true) { + // Wait till flash controller become usable + while(LL_FLASH_IsActiveFlag_OperationSuspended()) { + taskYIELD(); + }; - __disable_irq(); + // Just a little more love + taskENTER_CRITICAL(); - return true; + // Actually we already have mutex for it, but specification is specification + if (HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { + taskEXIT_CRITICAL(); + continue; + } + + // Take sempahopre and prevent core2 from anyting funky + if (HAL_HSEM_FastTake(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != HAL_OK) { + taskEXIT_CRITICAL(); + continue; + } + + break; + } +} + +void furi_hal_bt_lock_flash(bool erase_flag) { + // Acquire dangerous ops mutex + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); + + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_lock_flash_core2(erase_flag); + } else { + HAL_FLASH_Unlock(); + } +} + +static void furi_hal_bt_unlock_flash_core2(bool erase_flag) { + // Funky ops are ok at this point + HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, 0); + + // Task switching is ok + taskEXIT_CRITICAL(); + + // Doesn't make much sense, does it? + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + taskYIELD(); + } + + // Erase activity over, core2 can continue + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + + // Lock flash controller + HAL_FLASH_Lock(); + + // Release flash controller ownership + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, 0); } void furi_hal_bt_unlock_flash(bool erase_flag) { - __enable_irq(); + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_unlock_flash_core2(erase_flag); + } else { + HAL_FLASH_Lock(); + } - if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); - - HAL_FLASH_Lock(); - - HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); + // Release dangerous ops mutex + osMutexRelease(furi_hal_bt_core2_mtx); } void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.h b/firmware/targets/f7/furi-hal/furi-hal-console.h index 4c10d81e..637c17f6 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-console.h +++ b/firmware/targets/f7/furi-hal/furi-hal-console.h @@ -7,12 +7,6 @@ extern "C" { #endif -typedef enum { - UartIrqEventRXNE, - UartIrqEventIDLE, - //TODO: more events -} UartIrqEvent; - void furi_hal_console_init(); void furi_hal_console_enable(); diff --git a/firmware/targets/f7/furi-hal/furi-hal-crypto.c b/firmware/targets/f7/furi-hal/furi-hal-crypto.c index 3e4ec98f..648f3f18 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-crypto.c +++ b/firmware/targets/f7/furi-hal/furi-hal-crypto.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,24 +13,28 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { furi_assert(key); furi_assert(slot); + if(!furi_hal_bt_is_alive()) { + return false; + } + SHCI_C2_FUS_StoreUsrKey_Cmd_Param_t pParam; size_t key_data_size = 0; - if (key->type == FuriHalCryptoKeyTypeMaster) { + if(key->type == FuriHalCryptoKeyTypeMaster) { pParam.KeyType = KEYTYPE_MASTER; - } else if (key->type == FuriHalCryptoKeyTypeSimple) { + } else if(key->type == FuriHalCryptoKeyTypeSimple) { pParam.KeyType = KEYTYPE_SIMPLE; - } else if (key->type == FuriHalCryptoKeyTypeEncrypted) { + } else if(key->type == FuriHalCryptoKeyTypeEncrypted) { pParam.KeyType = KEYTYPE_ENCRYPTED; key_data_size += 12; } else { furi_crash("Incorrect key type"); } - if (key->size == FuriHalCryptoKeySize128) { + if(key->size == FuriHalCryptoKeySize128) { pParam.KeySize = KEYSIZE_16; key_data_size += 16; - } else if (key->size == FuriHalCryptoKeySize256) { + } else if(key->size == FuriHalCryptoKeySize256) { pParam.KeySize = KEYSIZE_32; key_data_size += 32; } else { @@ -44,16 +49,21 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(slot > 0 && slot <= 100); + if(!furi_hal_bt_is_alive()) { + return false; + } + crypt.Instance = AES1; crypt.Init.DataType = CRYP_DATATYPE_32B; crypt.Init.KeySize = CRYP_KEYSIZE_256B; crypt.Init.Algorithm = CRYP_AES_CBC; crypt.Init.pInitVect = (uint32_t*)iv; + crypt.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE; crypt.Init.pKey = NULL; furi_check(HAL_CRYP_Init(&crypt) == HAL_OK); - if (SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { + if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { return true; } else { furi_check(HAL_CRYP_DeInit(&crypt) == HAL_OK); @@ -62,14 +72,18 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { } bool furi_hal_crypto_store_unload_key(uint8_t slot) { + if(!furi_hal_bt_is_alive()) { + return false; + } + furi_check(HAL_CRYP_DeInit(&crypt) == HAL_OK); return SHCI_C2_FUS_UnloadUsrKey(slot) == SHCI_Success; } -bool furi_hal_crypto_encrypt(const uint8_t *input, uint8_t *output, size_t size) { - return HAL_CRYP_Encrypt(&crypt, (uint32_t*)input, size/4, (uint32_t*)output, 1000) == HAL_OK; +bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) { + return HAL_CRYP_Encrypt(&crypt, (uint32_t*)input, size / 4, (uint32_t*)output, 1000) == HAL_OK; } -bool furi_hal_crypto_decrypt(const uint8_t *input, uint8_t *output, size_t size) { - return HAL_CRYP_Decrypt(&crypt, (uint32_t*)input, size/4, (uint32_t*)output, 1000) == HAL_OK; +bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size) { + return HAL_CRYP_Decrypt(&crypt, (uint32_t*)input, size / 4, (uint32_t*)output, 1000) == HAL_OK; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.c b/firmware/targets/f7/furi-hal/furi-hal-flash.c index c9922122..1e270bc0 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-flash.c +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.c @@ -1,11 +1,14 @@ #include #include -#include #include +#include + /* Free flash space borders, exported by linker */ extern const void __free_flash_start__; +#define FURI_HAL_TAG "FuriHalFlash" +#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" #define FURI_HAL_FLASH_READ_BLOCK 8 #define FURI_HAL_FLASH_WRITE_BLOCK 8 #define FURI_HAL_FLASH_PAGE_SIZE 4096 @@ -57,33 +60,46 @@ size_t furi_hal_flash_get_free_page_count() { } bool furi_hal_flash_erase(uint8_t page, uint8_t count) { - if (!furi_hal_bt_lock_flash(true)) { - return false; - } + furi_hal_bt_lock_flash(true); + FLASH_EraseInitTypeDef erase; erase.TypeErase = FLASH_TYPEERASE_PAGES; erase.Page = page; erase.NbPages = count; - uint32_t error; - HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); + + uint32_t error_page = 0; + HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error_page); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Erase failed, ret: %d, page: %d", status, error_page); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(true); - return status == HAL_OK; + + return true; } bool furi_hal_flash_write_dword(size_t address, uint64_t data) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Programming failed, ret: %d, address: %p", status, address); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } +bool furi_hal_flash_write_row(size_t address, size_t source_address) { + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); + furi_check(status == HAL_OK); + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.h b/firmware/targets/f7/furi-hal/furi-hal-flash.h index 583d53eb..92a65a65 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-flash.h +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.h @@ -80,7 +80,7 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count); */ bool furi_hal_flash_write_dword(size_t address, uint64_t data); -/** Write double word (64 bits) from address +/** Write row: 64 double word (64 bits) from address * * Locking operation, uses HSEM to manage shared access. * @@ -89,4 +89,4 @@ bool furi_hal_flash_write_dword(size_t address, uint64_t data); * * @return true on success */ -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address); +bool furi_hal_flash_write_row(size_t address, size_t source_address); diff --git a/firmware/targets/f7/furi-hal/furi-hal-lock.c b/firmware/targets/f7/furi-hal/furi-hal-lock.c new file mode 100644 index 00000000..0f519380 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-lock.c @@ -0,0 +1,17 @@ +#include "furi-hal-lock.h" +#include + +#define FLIPPER_LOCKED_VALUE 0x5432FAFA + +bool furi_hal_lock_get() { + return FLIPPER_LOCKED_VALUE == LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR3); +} + +void furi_hal_lock_set(bool locked) { + if (locked) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, FLIPPER_LOCKED_VALUE); + } else { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, 0); + } +} + diff --git a/firmware/targets/f7/furi-hal/furi-hal-spi.c b/firmware/targets/f7/furi-hal/furi-hal-spi.c index c925abee..805b8dfb 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-spi.c +++ b/firmware/targets/f7/furi-hal/furi-hal-spi.c @@ -133,7 +133,7 @@ const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) { furi_assert(device_id < FuriHalSpiDeviceIdMax); const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id]; - assert(device); + furi_assert(device); furi_hal_spi_bus_lock(device->bus); furi_hal_spi_device_configure(device); diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c index e25c40d1..cd610cb2 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c @@ -676,7 +676,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { } uint32_t duration = level_duration_get_duration(ld); - assert(duration > 0); + furi_assert(duration > 0); *buffer = duration; buffer++; samples--; diff --git a/firmware/targets/f7/furi-hal/furi-hal-uart.c b/firmware/targets/f7/furi-hal/furi-hal-uart.c index c6e74101..ff2d94a7 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-uart.c +++ b/firmware/targets/f7/furi-hal/furi-hal-uart.c @@ -182,6 +182,8 @@ void LPUART1_IRQHandler(void) { } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); LL_LPUART_ClearFlag_IDLE(LPUART1); + } else if (LL_LPUART_IsActiveFlag_ORE(LPUART1)) { + LL_LPUART_ClearFlag_ORE(LPUART1); } //TODO: more events } @@ -193,5 +195,7 @@ void USART1_IRQHandler(void) { } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); LL_USART_ClearFlag_IDLE(USART1); + } else if (LL_USART_IsActiveFlag_ORE(USART1)) { + LL_USART_ClearFlag_ORE(USART1); } } diff --git a/firmware/targets/f7/furi-hal/furi-hal-uart.h b/firmware/targets/f7/furi-hal/furi-hal-uart.h index 6be156b7..731a12a2 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-uart.h +++ b/firmware/targets/f7/furi-hal/furi-hal-uart.h @@ -2,7 +2,6 @@ #include #include -#include "furi-hal-console.h" #ifdef __cplusplus extern "C" { @@ -13,6 +12,11 @@ typedef enum { FuriHalUartIdLPUART1, } FuriHalUartId; +typedef enum { + UartIrqEventRXNE, + UartIrqEventIDLE, + //TODO: more events +} UartIrqEvent; void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud); diff --git a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c index 9386b100..dd82cf16 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c +++ b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c @@ -7,12 +7,12 @@ #include "usb_cdc.h" #define CDC0_RXD_EP 0x01 -#define CDC0_TXD_EP 0x81 -#define CDC0_NTF_EP 0x82 +#define CDC0_TXD_EP 0x82 +#define CDC0_NTF_EP 0x83 -#define CDC1_RXD_EP 0x03 -#define CDC1_TXD_EP 0x83 -#define CDC1_NTF_EP 0x84 +#define CDC1_RXD_EP 0x04 +#define CDC1_TXD_EP 0x85 +#define CDC1_NTF_EP 0x86 #define CDC_NTF_SZ 0x08 @@ -446,10 +446,12 @@ void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) { } int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) { + int32_t len = 0; if (if_num == 0) - return usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); + len = usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); else - return usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); + len = usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); + return ((len < 0) ? 0 : len); } static void cdc_on_wakeup(usbd_device *dev) { diff --git a/firmware/targets/f7/furi-hal/furi-hal-vcp.c b/firmware/targets/f7/furi-hal/furi-hal-vcp.c index b2f17842..b0b47f46 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-vcp.c +++ b/firmware/targets/f7/furi-hal/furi-hal-vcp.c @@ -3,18 +3,28 @@ #include #include -#define APP_RX_DATA_SIZE CDC_DATA_SZ -#define APP_TX_DATA_SIZE CDC_DATA_SZ -#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16) +#define USB_CDC_PKT_LEN CDC_DATA_SZ #define VCP_IF_NUM 0 +typedef enum { + VcpConnect, + VcpDisconnect, +} VcpEvent; + typedef struct { volatile bool connected; - StreamBufferHandle_t rx_stream; - volatile bool rx_stream_full; + uint8_t rx_buf[USB_CDC_PKT_LEN]; + uint8_t rx_buf_start; + uint8_t rx_buf_len; + + osMessageQueueId_t event_queue; + + osMutexId_t usb_mutex; + + osSemaphoreId_t tx_sem; + osSemaphoreId_t rx_sem; - osSemaphoreId_t tx_semaphore; } FuriHalVcp; static void vcp_on_cdc_tx_complete(); @@ -30,22 +40,21 @@ static CdcCallbacks cdc_cb = { NULL, }; -static FuriHalVcp* furi_hal_vcp = NULL; +static FuriHalVcp* vcp = NULL; static const uint8_t ascii_soh = 0x01; static const uint8_t ascii_eot = 0x04; -static uint8_t* vcp_rx_buf; - void furi_hal_vcp_init() { - furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); - vcp_rx_buf = furi_alloc(APP_RX_DATA_SIZE); - furi_hal_vcp->connected = false; - - furi_hal_vcp->rx_stream = xStreamBufferCreate(FURI_HAL_VCP_RX_BUFFER_SIZE, 1); - furi_hal_vcp->rx_stream_full = false; + vcp = furi_alloc(sizeof(FuriHalVcp)); + vcp->connected = false; - furi_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL); + vcp->usb_mutex = osMutexNew(NULL); + + vcp->tx_sem = osSemaphoreNew(1, 1, NULL); + vcp->rx_sem = osSemaphoreNew(1, 0, NULL); + + vcp->event_queue = osMessageQueueNew(8, sizeof(VcpEvent), NULL); furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb); @@ -54,111 +63,149 @@ void furi_hal_vcp_init() { void furi_hal_vcp_enable() { furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb); - furi_hal_vcp->connected = true; + VcpEvent evt = VcpConnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + vcp->connected = true; + osSemaphoreRelease(vcp->tx_sem); + osSemaphoreRelease(vcp->rx_sem); } void furi_hal_vcp_disable() { furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL); - furi_hal_vcp->connected = false; - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); -} - -size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) { - furi_assert(furi_hal_vcp); - - size_t received = xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); - - if(furi_hal_vcp->rx_stream_full - && xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) { - furi_hal_vcp->rx_stream_full = false; - } - - return received; + VcpEvent evt = VcpDisconnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + vcp->connected = false; + osSemaphoreRelease(vcp->tx_sem); + osSemaphoreRelease(vcp->rx_sem); } size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) { - furi_assert(furi_hal_vcp); - return xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, timeout); + furi_assert(vcp); + furi_assert(buffer); + + size_t rx_cnt = 0; + + VcpEvent evt = VcpDisconnect; + + if (vcp->rx_buf_len > 0) { + size_t len = (vcp->rx_buf_len > size) ? (size) : (vcp->rx_buf_len); + memcpy(&buffer[rx_cnt], &vcp->rx_buf[vcp->rx_buf_start], len); + vcp->rx_buf_len -= len; + vcp->rx_buf_start += len; + rx_cnt += len; + } + + while (rx_cnt < size) { + if (osMessageQueueGet(vcp->event_queue, &evt, NULL, 0) == osOK) { + if (evt == VcpConnect) + buffer[rx_cnt] = ascii_soh; + else { + buffer[rx_cnt] = ascii_eot; + vcp->rx_buf_len = 0; + } + rx_cnt++; + return rx_cnt; + } + + if (osSemaphoreAcquire(vcp->rx_sem, timeout) == osErrorTimeout) + return rx_cnt; + + furi_check(osMutexAcquire(vcp->usb_mutex, osWaitForever) == osOK); + size_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->rx_buf, USB_CDC_PKT_LEN); + furi_check(osMutexRelease(vcp->usb_mutex) == osOK); + + vcp->rx_buf_len = len; + vcp->rx_buf_start = 0; + + if (vcp->rx_buf_len > (size - rx_cnt)) { + len = size - rx_cnt; + memcpy(&buffer[rx_cnt], vcp->rx_buf, len); + vcp->rx_buf_len -= len; + vcp->rx_buf_start += len; + } else { + memcpy(&buffer[rx_cnt], vcp->rx_buf, vcp->rx_buf_len); + vcp->rx_buf_len = 0; + } + rx_cnt += len; + } + return rx_cnt; +} + +size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) { + furi_assert(vcp); + + return furi_hal_vcp_rx_with_timeout(buffer, size, portMAX_DELAY); } void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { - furi_assert(furi_hal_vcp); + furi_assert(vcp); - while (size > 0 && furi_hal_vcp->connected) { - furi_check(osSemaphoreAcquire(furi_hal_vcp->tx_semaphore, osWaitForever) == osOK); - if (!furi_hal_vcp->connected) + while (size > 0 && vcp->connected) { + furi_check(osSemaphoreAcquire(vcp->tx_sem, osWaitForever) == osOK); + if (!vcp->connected) break; size_t batch_size = size; - if (batch_size > APP_TX_DATA_SIZE) { - batch_size = APP_TX_DATA_SIZE; + if (batch_size > USB_CDC_PKT_LEN) { + batch_size = USB_CDC_PKT_LEN; } + furi_check(osMutexAcquire(vcp->usb_mutex, osWaitForever) == osOK); furi_hal_cdc_send(VCP_IF_NUM, (uint8_t*)buffer, batch_size); + furi_check(osMutexRelease(vcp->usb_mutex) == osOK); + size -= batch_size; buffer += batch_size; } } static void vcp_state_callback(uint8_t state) { - if (state == 1) - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); - else if (furi_hal_vcp->connected) { - furi_hal_vcp->connected = false; - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); + if (state == 1) { + osSemaphoreRelease(vcp->rx_sem); + //osSemaphoreRelease(vcp->tx_sem); + } + else if (vcp->connected) { + vcp->connected = false; + osSemaphoreRelease(vcp->rx_sem); + VcpEvent evt = VcpDisconnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + //osSemaphoreRelease(vcp->tx_sem); } } static void vcp_on_cdc_control_line(uint8_t state) { - - BaseType_t xHigherPriorityTaskWoken = pdFALSE; // bit 0: DTR state, bit 1: RTS state - // bool dtr = state & 0b01; bool dtr = state & 0b1; if (dtr) { - if (!furi_hal_vcp->connected) { - furi_hal_vcp->connected = true; - xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, &ascii_soh, 1, &xHigherPriorityTaskWoken); // SOH - + if (!vcp->connected) { + vcp->connected = true; + VcpEvent evt = VcpConnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); } } else { - if (furi_hal_vcp->connected) { - xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, &ascii_eot, 1, &xHigherPriorityTaskWoken); // EOT - furi_hal_vcp->connected = false; + if (vcp->connected) { + VcpEvent evt = VcpDisconnect; + osMessageQueuePut(vcp->event_queue, &evt, 0, 0); + vcp->connected = false; } } - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + osSemaphoreRelease(vcp->tx_sem); + osSemaphoreRelease(vcp->rx_sem); } -static void vcp_on_cdc_rx() { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream); - if (max_len > 0) { - if (max_len > APP_RX_DATA_SIZE) - max_len = APP_RX_DATA_SIZE; - int32_t size = furi_hal_cdc_receive(VCP_IF_NUM, vcp_rx_buf, max_len); - - if (size > 0) { - size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken); - furi_check(ret == size); - } - } else { - furi_hal_vcp->rx_stream_full = true; - }; - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +static void vcp_on_cdc_rx() { + if (vcp->connected == false) + return; + osSemaphoreRelease(vcp->rx_sem); } static void vcp_on_cdc_tx_complete() { - osSemaphoreRelease(furi_hal_vcp->tx_semaphore); + osSemaphoreRelease(vcp->tx_sem); } bool furi_hal_vcp_is_connected(void) { - return furi_hal_vcp->connected; + return vcp->connected; } diff --git a/firmware/targets/furi-hal-include/furi-hal-bt.h b/firmware/targets/furi-hal-include/furi-hal-bt.h index fe9a6de9..461fc4ce 100644 --- a/firmware/targets/furi-hal-include/furi-hal-bt.h +++ b/firmware/targets/furi-hal-include/furi-hal-bt.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include + #define FURI_HAL_BT_PACKET_SIZE_MAX SERIAL_SVC_DATA_LEN_MAX @@ -20,6 +23,12 @@ extern "C" { */ void furi_hal_bt_init(); +/** Start 2nd core and BLE stack + * + * @return true on success + */ +bool furi_hal_bt_start_core2(); + /** Start BLE app * @param event_cb - BleEventCallback instance * @param context - pointer to context @@ -52,6 +61,32 @@ void furi_hal_bt_dump_state(string_t buffer); */ bool furi_hal_bt_is_alive(); +/** Get key storage buffer address and size + * + * @param key_buff_addr pointer to store buffer address + * @param key_buff_size pointer to store buffer size + * + * @return true on success + */ +bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size); + +/** Get SRAM2 hardware semaphore + * @note Must be called before SRAM2 read/write operations + */ +void furi_hal_bt_nvm_sram_sem_acquire(); + +/** Release SRAM2 hardware semaphore + * @note Must be called after SRAM2 read/write operations + */ +void furi_hal_bt_nvm_sram_sem_release(); + +/** Set key storage change callback + * + * @param callback BleGlueKeyStorageChangedCallback instance + * @param context pointer to context + */ +void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context); + /** Set data event callbacks * @param on_received_cb - SerialSvcDataReceivedCallback instance * @param on_sent_cb - SerialSvcDataSentCallback instance @@ -65,16 +100,11 @@ void furi_hal_bt_set_data_event_callbacks(SerialSvcDataReceivedCallback on_recei */ bool furi_hal_bt_tx(uint8_t* data, uint16_t size); -/** Wait for Core2 startup */ -bool furi_hal_bt_wait_startup(); - /** Lock shared access to flash controller * * @param[in] erase_flag true if erase operation - * - * @return true if lock was successful, false if not */ -bool furi_hal_bt_lock_flash(bool erase_flag); +void furi_hal_bt_lock_flash(bool erase_flag); /** Unlock shared access to flash controller * diff --git a/firmware/targets/furi-hal-include/furi-hal-crypto.h b/firmware/targets/furi-hal-include/furi-hal-crypto.h index 0428f781..482b3d7a 100644 --- a/firmware/targets/furi-hal-include/furi-hal-crypto.h +++ b/firmware/targets/furi-hal-include/furi-hal-crypto.h @@ -11,7 +11,7 @@ /** FuriHalCryptoKey Type */ typedef enum { FuriHalCryptoKeyTypeMaster, /**< Master key */ - FuriHalCryptoKeyTypeSimple, /**< Simple enencrypted key */ + FuriHalCryptoKeyTypeSimple, /**< Simple enencrypted key */ FuriHalCryptoKeyTypeEncrypted, /**< Encrypted with Master key */ } FuriHalCryptoKeyType; @@ -59,7 +59,6 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv); */ bool furi_hal_crypto_store_unload_key(uint8_t slot); - /** Encrypt data * * @param input pointer to input data @@ -68,7 +67,7 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot); * * @return true on success */ -bool furi_hal_crypto_encrypt(const uint8_t *input, uint8_t *output, size_t size); +bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size); /** Decrypt data * @@ -78,4 +77,4 @@ bool furi_hal_crypto_encrypt(const uint8_t *input, uint8_t *output, size_t size) * * @return true on success */ -bool furi_hal_crypto_decrypt(const uint8_t *input, uint8_t *output, size_t size); +bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size); diff --git a/firmware/targets/furi-hal-include/furi-hal-lock.h b/firmware/targets/furi-hal-include/furi-hal-lock.h new file mode 100644 index 00000000..d07ce571 --- /dev/null +++ b/firmware/targets/furi-hal-include/furi-hal-lock.h @@ -0,0 +1,5 @@ +#pragma once +#include + +bool furi_hal_lock_get(); +void furi_hal_lock_set(bool locked); diff --git a/lib/app-scened-template/file-worker.c b/lib/app-scened-template/file-worker.c index dec23cf2..316e7507 100644 --- a/lib/app-scened-template/file-worker.c +++ b/lib/app-scened-template/file-worker.c @@ -367,7 +367,7 @@ bool file_worker_read_until_buffered( file_worker->file, &file_buf[*file_buf_cnt], file_buf_size - *file_buf_cnt); if(storage_file_get_error(file_worker->file) != FSE_OK) { file_worker_show_error_internal(file_worker, "Cannot read\nfile"); - string_clear(str_result); + string_clean(str_result); *file_buf_cnt = 0; break; } diff --git a/lib/common-api/task-control-block.h b/lib/common-api/task-control-block.h index 8d7b9b91..32d2edec 100644 --- a/lib/common-api/task-control-block.h +++ b/lib/common-api/task-control-block.h @@ -1,7 +1,7 @@ #pragma once -#include "FreeRTOS.h" - +#include +#include typedef struct /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { diff --git a/lib/flipper_file/file_helper.c b/lib/flipper_file/file_helper.c new file mode 100644 index 00000000..c0feb993 --- /dev/null +++ b/lib/flipper_file/file_helper.c @@ -0,0 +1,204 @@ +#include "file_helper.h" + +const char flipper_file_eoln = '\n'; +const char flipper_file_eolr = '\r'; + +bool file_helper_seek(File* file, int32_t offset) { + uint64_t position = storage_file_tell(file); + return storage_file_seek(file, position + offset, true); +} + +bool file_helper_write_hex(File* file, const uint8_t* data, const uint16_t data_size) { + const uint8_t byte_text_size = 3; + char byte_text[byte_text_size]; + + bool result = true; + uint16_t bytes_written; + for(uint8_t i = 0; i < data_size; i++) { + snprintf(byte_text, byte_text_size, "%02X", data[i]); + + if(i != 0) { + // space + const char space = ' '; + bytes_written = storage_file_write(file, &space, sizeof(char)); + if(bytes_written != sizeof(char)) { + result = false; + break; + } + } + + bytes_written = storage_file_write(file, &byte_text, strlen(byte_text)); + if(bytes_written != strlen(byte_text)) { + result = false; + break; + } + } + + return result; +} + +bool file_helper_read_line(File* file, string_t str_result) { + string_clean(str_result); + const uint8_t buffer_size = 32; + uint8_t buffer[buffer_size]; + + do { + uint16_t bytes_were_read = storage_file_read(file, buffer, buffer_size); + // TODO process EOF + if(bytes_were_read == 0) break; + + bool result = false; + bool error = false; + for(uint16_t i = 0; i < bytes_were_read; i++) { + if(buffer[i] == flipper_file_eoln) { + if(!file_helper_seek(file, i - bytes_were_read)) { + error = true; + break; + } + + result = true; + break; + } else if(buffer[i] == flipper_file_eolr) { + // Ignore + } else { + string_push_back(str_result, buffer[i]); + } + } + + if(result || error) { + break; + } + } while(true); + + return string_size(str_result) != 0; +} + +bool file_helper_seek_to_next_line(File* file) { + const uint8_t buffer_size = 32; + uint8_t buffer[buffer_size]; + bool result = false; + bool error = false; + + do { + uint16_t bytes_were_read = storage_file_read(file, buffer, buffer_size); + if(bytes_were_read == 0) { + if(storage_file_eof(file)) { + result = true; + break; + } + } + + for(uint16_t i = 0; i < bytes_were_read; i++) { + if(buffer[i] == flipper_file_eoln) { + if(!file_helper_seek(file, i - bytes_were_read)) { + error = true; + break; + } + + result = true; + break; + } + } + + if(result || error) { + break; + } + } while(true); + + return result; +} + +bool file_helper_read_value(File* file, string_t value, bool* last) { + string_clean(value); + const uint8_t buffer_size = 32; + uint8_t buffer[buffer_size]; + bool result = false; + bool error = false; + + while(true) { + uint16_t bytes_were_read = storage_file_read(file, buffer, buffer_size); + + if(bytes_were_read == 0) { + // check EOF + if(storage_file_eof(file) && string_size(value) > 0) { + result = true; + *last = true; + break; + } + } + + for(uint16_t i = 0; i < bytes_were_read; i++) { + if(buffer[i] == flipper_file_eoln) { + if(string_size(value) > 0) { + if(!file_helper_seek(file, i - bytes_were_read)) { + error = true; + break; + } + + result = true; + *last = true; + break; + } else { + error = true; + } + } else if(buffer[i] == ' ') { + if(string_size(value) > 0) { + if(!file_helper_seek(file, i - bytes_were_read)) { + error = true; + break; + } + + result = true; + *last = false; + break; + } + + } else if(buffer[i] == flipper_file_eolr) { + // Ignore + } else { + string_push_back(value, buffer[i]); + } + } + + if(error || result) break; + } + + return result; +} + +bool file_helper_write(File* file, const void* data, uint16_t data_size) { + uint16_t bytes_written = storage_file_write(file, data, data_size); + return bytes_written == data_size; +} + +bool file_helper_write_eol(File* file) { + return file_helper_write(file, &flipper_file_eoln, sizeof(char)); +} + +bool file_helper_copy(File* file_from, File* file_to, uint64_t start_offset, uint64_t stop_offset) { + bool result = false; + + const uint8_t buffer_size = 32; + uint8_t buffer[buffer_size]; + uint64_t current_offset = start_offset; + + if(storage_file_seek(file_from, start_offset, true)) { + do { + int32_t bytes_count = MIN(buffer_size, stop_offset - current_offset); + if(bytes_count <= 0) { + result = true; + break; + } + + uint16_t bytes_were_read = storage_file_read(file_from, buffer, bytes_count); + if(bytes_were_read != bytes_count) break; + + uint16_t bytes_were_written = storage_file_write(file_to, buffer, bytes_count); + if(bytes_were_written != bytes_count) break; + + current_offset += bytes_count; + } while(true); + } + + return result; +} \ No newline at end of file diff --git a/lib/flipper_file/file_helper.h b/lib/flipper_file/file_helper.h new file mode 100644 index 00000000..66306797 --- /dev/null +++ b/lib/flipper_file/file_helper.h @@ -0,0 +1,81 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char flipper_file_eoln; +extern const char flipper_file_eolr; + +/** + * Negative seek helper + * @param file + * @param offset + * @return bool + */ +bool file_helper_seek(File* file, int32_t offset); + +/** + * Writes data to a file as a hexadecimal array. + * @param file + * @param data + * @param data_size + * @return true on success write + */ +bool file_helper_write_hex(File* file, const uint8_t* data, const uint16_t data_size); + +/** + * Reads data as a string from the stored rw pointer to the \\n symbol position. Ignores \r. + * @param file + * @param str_result + * @return true on success read + */ +bool file_helper_read_line(File* file, string_t str_result); + +/** + * Moves the RW pointer to the beginning of the next line + * @param file + * @return bool + */ +bool file_helper_seek_to_next_line(File* file); + +/** + * Read one value from array-like string (separated by ' ') + * @param file + * @param value + * @return bool + */ +bool file_helper_read_value(File* file, string_t value, bool* last); + +/** + * Write helper + * @param file + * @param data + * @param data_size + * @return bool + */ +bool file_helper_write(File* file, const void* data, uint16_t data_size); + +/** + * Write EOL + * @param file + * @return bool + */ +bool file_helper_write_eol(File* file); + +/** + * Appends part of one file to the end of another file + * @param file_from + * @param file_to + * @param start_offset + * @param stop_offset + * @return bool + */ +bool file_helper_copy(File* file_from, File* file_to, uint64_t start_offset, uint64_t stop_offset); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/flipper_file/flipper_file.c b/lib/flipper_file/flipper_file.c new file mode 100644 index 00000000..21cd5f26 --- /dev/null +++ b/lib/flipper_file/flipper_file.c @@ -0,0 +1,395 @@ +#include +#include "file_helper.h" +#include "flipper_file_helper.h" +#include "flipper_file.h" +#include "flipper_file_i.h" +#include +#include + +FlipperFile* flipper_file_alloc(Storage* storage) { + // furi_assert(storage); + + FlipperFile* flipper_file = malloc(sizeof(FlipperFile)); + flipper_file->storage = storage; + flipper_file->file = storage_file_alloc(flipper_file->storage); + + return flipper_file; +} + +void flipper_file_free(FlipperFile* flipper_file) { + furi_assert(flipper_file); + if(storage_file_is_open(flipper_file->file)) { + storage_file_close(flipper_file->file); + } + storage_file_free(flipper_file->file); + free(flipper_file); +} + +bool flipper_file_open_existing(FlipperFile* flipper_file, const char* filename) { + furi_assert(flipper_file); + bool result = storage_file_open( + flipper_file->file, filename, FSAM_READ | FSAM_WRITE, FSOM_OPEN_EXISTING); + return result; +} + +bool flipper_file_open_append(FlipperFile* flipper_file, const char* filename) { + furi_assert(flipper_file); + + bool result = + storage_file_open(flipper_file->file, filename, FSAM_READ | FSAM_WRITE, FSOM_OPEN_APPEND); + + // Add EOL if it is not there + if(storage_file_size(flipper_file->file) >= 1) { + do { + char last_char; + result = false; + + if(!file_helper_seek(flipper_file->file, -1)) break; + + uint16_t bytes_were_read = storage_file_read(flipper_file->file, &last_char, 1); + if(bytes_were_read != 1) break; + + if(last_char != flipper_file_eoln) { + if(!file_helper_write_eol(flipper_file->file)) break; + } + + result = true; + } while(false); + } + + return result; +} + +bool flipper_file_open_always(FlipperFile* flipper_file, const char* filename) { + furi_assert(flipper_file); + bool result = storage_file_open( + flipper_file->file, filename, FSAM_READ | FSAM_WRITE, FSOM_CREATE_ALWAYS); + return result; +} + +bool flipper_file_open_new(FlipperFile* flipper_file, const char* filename) { + furi_assert(flipper_file); + bool result = storage_file_open( + flipper_file->file, filename, FSAM_READ | FSAM_WRITE, FSOM_CREATE_NEW); + return result; +} + +bool flipper_file_close(FlipperFile* flipper_file) { + furi_assert(flipper_file); + if(storage_file_is_open(flipper_file->file)) { + return storage_file_close(flipper_file->file); + } + return true; +} + +bool flipper_file_rewind(FlipperFile* flipper_file) { + furi_assert(flipper_file); + return storage_file_seek(flipper_file->file, 0, true); +} + +bool flipper_file_read_header(FlipperFile* flipper_file, string_t filetype, uint32_t* version) { + bool result = false; + do { + result = flipper_file_read_string(flipper_file, flipper_file_filetype_key, filetype); + if(!result) break; + result = flipper_file_read_uint32(flipper_file, flipper_file_version_key, version, 1); + if(!result) break; + } while(false); + + return result; +} + +bool flipper_file_write_header( + FlipperFile* flipper_file, + string_t filetype, + const uint32_t version) { + bool result = false; + do { + result = flipper_file_write_string(flipper_file, flipper_file_filetype_key, filetype); + if(!result) break; + result = flipper_file_write_uint32(flipper_file, flipper_file_version_key, &version, 1); + if(!result) break; + } while(false); + + return result; +} + +bool flipper_file_write_header_cstr( + FlipperFile* flipper_file, + const char* filetype, + const uint32_t version) { + bool result = false; + string_t value; + string_init_set(value, filetype); + result = flipper_file_write_header(flipper_file, value, version); + string_clear(value); + return result; +} + +bool flipper_file_get_value_count(FlipperFile* flipper_file, const char* key, uint32_t* count) { + furi_assert(flipper_file); + bool result = false; + bool last = false; + + string_t value; + string_init(value); + + uint32_t position = storage_file_tell(flipper_file->file); + do { + if(!flipper_file_seek_to_key(flipper_file->file, key)) break; + + // Balance between speed and memory consumption + // I prefer lower speed but less memory consumption + *count = 0; + + result = true; + while(true) { + if(!file_helper_read_value(flipper_file->file, value, &last)) { + result = false; + break; + } + + *count = *count + 1; + if(last) break; + } + + } while(true); + + if(!storage_file_seek(flipper_file->file, position, true)) { + result = false; + } + + string_clear(value); + return result; +} + +bool flipper_file_write_comment(FlipperFile* flipper_file, string_t data) { + furi_assert(flipper_file); + + bool result = false; + do { + const char comment_buffer[2] = {flipper_file_comment, ' '}; + result = file_helper_write(flipper_file->file, comment_buffer, sizeof(comment_buffer)); + if(!result) break; + + result = file_helper_write(flipper_file->file, string_get_cstr(data), string_size(data)); + if(!result) break; + + result = file_helper_write_eol(flipper_file->file); + } while(false); + + return result; +} + +bool flipper_file_write_comment_cstr(FlipperFile* flipper_file, const char* data) { + bool result = false; + string_t value; + string_init_set(value, data); + result = flipper_file_write_comment(flipper_file, value); + string_clear(value); + return result; +} + +bool flipper_file_delete_key_and_call( + FlipperFile* flipper_file, + const char* key, + flipper_file_cb call, + const char* cb_key, + const void* cb_data, + const uint16_t cb_data_size) { + bool result = false; + File* scratch_file = storage_file_alloc(flipper_file->storage); + + do { + // get size + uint64_t file_size = storage_file_size(flipper_file->file); + if(file_size == 0) break; + + if(!storage_file_seek(flipper_file->file, 0, true)) break; + + // find key + if(!flipper_file_seek_to_key(flipper_file->file, key)) break; + // get key start position + uint64_t start_position = storage_file_tell(flipper_file->file) - strlen(key); + if(start_position >= 2) { + start_position -= 2; + } else { + // something wrong + break; + } + + // get value end position + if(!file_helper_seek_to_next_line(flipper_file->file)) break; + uint64_t end_position = storage_file_tell(flipper_file->file); + // newline symbol + if(end_position < file_size) { + end_position += 1; + } + + // open scratchpad + const char* scratch_name = ""; + if(!flipper_file_get_scratchpad_name(&scratch_name)) break; + + if(!storage_file_open( + scratch_file, scratch_name, FSAM_READ | FSAM_WRITE, FSOM_CREATE_ALWAYS)) + break; + + // copy key file before key to scratchpad + if(!file_helper_copy(flipper_file->file, scratch_file, 0, start_position)) break; + + // do something in between if needed + if(call != NULL) { + if(!call(scratch_file, cb_key, cb_data, cb_data_size)) break; + }; + + // copy key file after key value to scratchpad + if(!file_helper_copy(flipper_file->file, scratch_file, end_position, file_size)) break; + + file_size = storage_file_tell(scratch_file); + if(file_size == 0) break; + + if(!storage_file_seek(flipper_file->file, 0, true)) break; + + // copy whole scratchpad file to the original file + if(!file_helper_copy(scratch_file, flipper_file->file, 0, file_size)) break; + + // and truncate original file + if(!storage_file_truncate(flipper_file->file)) break; + + // close and remove scratchpad file + if(!storage_file_close(scratch_file)) break; + if(storage_common_remove(flipper_file->storage, scratch_name) != FSE_OK) break; + result = true; + } while(false); + + storage_file_free(scratch_file); + + return result; +} + +bool flipper_file_delete_key(FlipperFile* flipper_file, const char* key) { + furi_assert(flipper_file); + return flipper_file_delete_key_and_call(flipper_file, key, NULL, NULL, NULL, 0); +} + +bool flipper_file_write_internal( + File* file, + const char* key, + const void* _data, + const uint16_t data_size, + FlipperFileValueType type) { + bool result = false; + string_t value; + string_init(value); + + do { + result = flipper_file_write_key(file, key); + if(!result) break; + + for(uint16_t i = 0; i < data_size; i++) { + switch(type) { + case FlipperFileValueHex: { + const uint8_t* data = _data; + string_printf(value, "%02X", data[i]); + }; break; + case FlipperFileValueFloat: { + const float* data = _data; + string_printf(value, "%f", data[i]); + }; break; + case FlipperFileValueInt32: { + const int32_t* data = _data; + string_printf(value, "%" PRIi32, data[i]); + }; break; + case FlipperFileValueUint32: { + const uint32_t* data = _data; + string_printf(value, "%" PRId32, data[i]); + }; break; + } + + if((i + 1) < data_size) { + string_cat(value, " "); + } + + result = file_helper_write(file, string_get_cstr(value), string_size(value)); + if(!result) break; + } + + result = file_helper_write_eol(file); + } while(false); + + string_clear(value); + return result; +} + +bool flipper_file_read_internal( + File* file, + const char* key, + void* _data, + const uint16_t data_size, + FlipperFileValueType type) { + bool result = false; + string_t value; + string_init(value); + + if(flipper_file_seek_to_key(file, key)) { + result = true; + for(uint16_t i = 0; i < data_size; i++) { + bool last = false; + result = file_helper_read_value(file, value, &last); + if(result) { + int scan_values = 0; + switch(type) { + case FlipperFileValueHex: { + uint8_t* data = _data; + // sscanf "%02X" does not work here + if(hex_chars_to_uint8( + string_get_char(value, 0), string_get_char(value, 1), &data[i])) { + scan_values = 1; + } + }; break; + case FlipperFileValueFloat: { + float* data = _data; + // newlib-nano does not have sscanf for floats + // scan_values = sscanf(string_get_cstr(value), "%f", &data[i]); + char* end_char; + data[i] = strtof(string_get_cstr(value), &end_char); + if(*end_char == 0) { + // very probably ok + scan_values = 1; + } + }; break; + case FlipperFileValueInt32: { + int32_t* data = _data; + scan_values = sscanf(string_get_cstr(value), "%" PRIi32, &data[i]); + }; break; + case FlipperFileValueUint32: { + uint32_t* data = _data; + scan_values = sscanf(string_get_cstr(value), "%" PRId32, &data[i]); + }; break; + } + + if(scan_values != 1) { + result = false; + break; + } + } else { + break; + } + + if(last && ((i + 1) != data_size)) { + result = false; + break; + } + } + } + + string_clear(value); + return result; +} + +File* flipper_file_get_file(FlipperFile* flipper_file) { + furi_assert(flipper_file); + furi_assert(flipper_file->file); + + return flipper_file->file; +} \ No newline at end of file diff --git a/lib/toolbox/flipper-file.h b/lib/flipper_file/flipper_file.h similarity index 50% rename from lib/toolbox/flipper-file.h rename to lib/flipper_file/flipper_file.h index db6ad938..4c0f6cf1 100644 --- a/lib/toolbox/flipper-file.h +++ b/lib/flipper_file/flipper_file.h @@ -17,8 +17,10 @@ * * ~~~~~~~~~~~~~~~~~~~~~ * String: text - * Uint32: 1 - * Hex Array: A4 B3 C2 D1 12 FF + * Int32: 1 2 -3 4 + * Uint32: 1 2 3 4 + * Float: 1.0 1234.654 + * Hex: A4 B3 C2 D1 12 FF * ~~~~~~~~~~~~~~~~~~~~~ * * End of line is LF when writing, but CR is supported when reading. @@ -33,7 +35,7 @@ * # Just test file * String: String value * UINT: 1234 - * Hex Array: 00 01 FF A3 + * Hex: 00 01 FF A3 * ~~~~~~~~~~~~~~~~~~~~~ * * Writing: @@ -48,12 +50,12 @@ * const uint16_t array_size = 4; * const uint8_t* array[array_size] = {0x00, 0x01, 0xFF, 0xA3}; * - * if(!flipper_file_new_write(file, "/ext/flipper_file_test")) break; + * if(!flipper_file_open_new(file, "/ext/flipper_file_test")) break; * if(!flipper_file_write_header_cstr(file, "Flipper Test File", version)) break; * if(!flipper_file_write_comment_cstr(file, "Just test file")) break; * if(!flipper_file_write_string_cstr(file, "String", string_value)) break; - * if(!flipper_file_flipper_file_write_uint32(file, "UINT", uint32_value)) break; - * if(!flipper_file_write_hex_array(file, "Hex Array", array, array_size)) break; + * if(!flipper_file_flipper_file_write_uint32(file, "UINT", &uint32_value, 1)) break; + * if(!flipper_file_write_hex(file, "Hex Array", array, array_size)) break; * * // signal that the file was written successfully * } while(0); @@ -77,11 +79,11 @@ * string_init(file_type); * string_init(string_value); * - * if(!flipper_file_open_read(file, "/ext/flipper_file_test")) break; + * if(!flipper_file_open_existing(file, "/ext/flipper_file_test")) break; * if(!flipper_file_read_header(file, file_type, &version)) break; * if(!flipper_file_read_string(file, "String", string_value)) break; - * if(!flipper_file_read_uint32(file, "UINT", &uint32_value)) break; - * if(!flipper_file_read_hex_array(file, "Hex Array", array, array_size)) break; + * if(!flipper_file_read_uint32(file, "UINT", &uint32_value, 1)) break; + * if(!flipper_file_read_hex(file, "Hex Array", array, array_size)) break; * * // signal that the file was read successfully * } while(0); @@ -118,20 +120,36 @@ FlipperFile* flipper_file_alloc(Storage* storage); void flipper_file_free(FlipperFile* flipper_file); /** - * Open file for reading. + * Open existing file. * @param flipper_file Pointer to a FlipperFile instance * @param filename File name and path * @return True on success */ -bool flipper_file_open_read(FlipperFile* flipper_file, const char* filename); +bool flipper_file_open_existing(FlipperFile* flipper_file, const char* filename); /** - * Open file for writing. Creates a new file, or deletes the contents of the file if it already exists. + * Open existing file for writing and add values to the end of file. * @param flipper_file Pointer to a FlipperFile instance * @param filename File name and path * @return True on success */ -bool flipper_file_new_write(FlipperFile* flipper_file, const char* filename); +bool flipper_file_open_append(FlipperFile* flipper_file, const char* filename); + +/** + * Open file. Creates a new file, or deletes the contents of the file if it already exists. + * @param flipper_file Pointer to a FlipperFile instance + * @param filename File name and path + * @return True on success + */ +bool flipper_file_open_always(FlipperFile* flipper_file, const char* filename); + +/** + * Open file. Creates a new file, fails if file already exists. + * @param flipper_file Pointer to a FlipperFile instance + * @param filename File name and path + * @return True on success + */ +bool flipper_file_open_new(FlipperFile* flipper_file, const char* filename); /** * Close the file. @@ -140,6 +158,13 @@ bool flipper_file_new_write(FlipperFile* flipper_file, const char* filename); */ bool flipper_file_close(FlipperFile* flipper_file); +/** + * Rewind the file RW pointer. + * @param flipper_file Pointer to a FlipperFile instance + * @return True on success + */ +bool flipper_file_rewind(FlipperFile* flipper_file); + /** * Read the header (file type and version) from the file. * @param flipper_file Pointer to a FlipperFile instance @@ -173,6 +198,15 @@ bool flipper_file_write_header_cstr( const char* filetype, const uint32_t version); +/** + * Get the count of values by key + * @param flipper_file + * @param key + * @param count + * @return bool + */ +bool flipper_file_get_value_count(FlipperFile* flipper_file, const char* key, uint32_t* count); + /** * Read a string from a file by Key * @param flipper_file Pointer to a FlipperFile instance @@ -201,22 +235,116 @@ bool flipper_file_write_string(FlipperFile* flipper_file, const char* key, strin bool flipper_file_write_string_cstr(FlipperFile* flipper_file, const char* key, const char* data); /** - * Read uint32 from a file by Key + * Read array of uint32 from a file by Key * @param flipper_file Pointer to a FlipperFile instance * @param key Key * @param data Value + * @param data_size Values count * @return True on success */ -bool flipper_file_read_uint32(FlipperFile* flipper_file, const char* key, uint32_t* data); +bool flipper_file_read_uint32( + FlipperFile* flipper_file, + const char* key, + uint32_t* data, + const uint16_t data_size); /** - * Write key and uint32 to file. + * Write key and array of uint32 to file. * @param flipper_file Pointer to a FlipperFile instance * @param key Key * @param data Value + * @param data_size Values count * @return True on success */ -bool flipper_file_write_uint32(FlipperFile* flipper_file, const char* key, const uint32_t data); +bool flipper_file_write_uint32( + FlipperFile* flipper_file, + const char* key, + const uint32_t* data, + const uint16_t data_size); + +/** + * Read array of int32 from a file by Key + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_read_int32( + FlipperFile* flipper_file, + const char* key, + int32_t* data, + const uint16_t data_size); + +/** + * Write key and array of int32 to file. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_write_int32( + FlipperFile* flipper_file, + const char* key, + const int32_t* data, + const uint16_t data_size); + +/** + * Read array of float from a file by Key + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_read_float( + FlipperFile* flipper_file, + const char* key, + float* data, + const uint16_t data_size); + +/** + * Write key and array of float to file. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_write_float( + FlipperFile* flipper_file, + const char* key, + const float* data, + const uint16_t data_size); + +/** + * Read hex array from a file by Key + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Value size + * @return True on success + */ +bool flipper_file_read_hex( + FlipperFile* flipper_file, + const char* key, + uint8_t* data, + const uint16_t data_size); + +/** + * Write key and hex array to file. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_write_hex( + FlipperFile* flipper_file, + const char* key, + const uint8_t* data, + const uint16_t data_size); /** * Write comment to file. @@ -235,33 +363,96 @@ bool flipper_file_write_comment(FlipperFile* flipper_file, string_t data); bool flipper_file_write_comment_cstr(FlipperFile* flipper_file, const char* data); /** - * Read hex array from a file by Key + * Removes the first matching key and its value from the file. Changes the RW pointer to an undefined position. * @param flipper_file Pointer to a FlipperFile instance * @param key Key - * @param data Value - * @param data_size Value size * @return True on success */ -bool flipper_file_read_hex_array( +bool flipper_file_delete_key(FlipperFile* flipper_file, const char* key); + +/** + * Updates the value of the first matching key to a string value. Changes the RW pointer to an undefined position. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @return True on success + */ +bool flipper_file_update_string(FlipperFile* flipper_file, const char* key, string_t data); + +/** + * Updates the value of the first matching key to a string value. Plain C version. Changes the RW pointer to an undefined position. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @return True on success + */ +bool flipper_file_update_string_cstr(FlipperFile* flipper_file, const char* key, const char* data); + +/** + * Updates the value of the first matching key to a uint32 array value. Changes the RW pointer to an undefined position. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_update_uint32( FlipperFile* flipper_file, const char* key, - uint8_t* data, + const uint32_t* data, const uint16_t data_size); /** - * Write key and hex array to file. - * @param flipper_file Pointer to a FlipperFile instance + * Updates the value of the first matching key to a int32 array value. Changes the RW pointer to an undefined position. + * @param flipper_file Pointer to a FlipperFile instance * @param key Key * @param data Value - * @param data_size Value size + * @param data_size Values count * @return True on success */ -bool flipper_file_write_hex_array( +bool flipper_file_update_int32( + FlipperFile* flipper_file, + const char* key, + const int32_t* data, + const uint16_t data_size); + +/** + * Updates the value of the first matching key to a float array value. Changes the RW pointer to an undefined position. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_update_float( + FlipperFile* flipper_file, + const char* key, + const float* data, + const uint16_t data_size); + +/** + * Updates the value of the first matching key to a hex array value. Changes the RW pointer to an undefined position. + * @param flipper_file Pointer to a FlipperFile instance + * @param key Key + * @param data Value + * @param data_size Values count + * @return True on success + */ +bool flipper_file_update_hex( FlipperFile* flipper_file, const char* key, const uint8_t* data, const uint16_t data_size); +/** Get file descriptor. + * + * We higly don't recommend to use it. + * This instance is owned by FlipperFile. + * @param flipper_file + * @return File* + */ +File* flipper_file_get_file(FlipperFile* flipper_file); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_float.c b/lib/flipper_file/flipper_file_float.c new file mode 100644 index 00000000..288e545d --- /dev/null +++ b/lib/flipper_file/flipper_file_float.c @@ -0,0 +1,42 @@ +#include + +#include "flipper_file.h" +#include "flipper_file_i.h" +#include "flipper_file_helper.h" + +static bool flipper_file_write_float_internal( + File* file, + const char* key, + const void* _data, + const uint16_t data_size) { + return flipper_file_write_internal(file, key, _data, data_size, FlipperFileValueFloat); +}; + +bool flipper_file_read_float( + FlipperFile* flipper_file, + const char* key, + float* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_read_internal( + flipper_file->file, key, data, data_size, FlipperFileValueFloat); +} + +bool flipper_file_write_float( + FlipperFile* flipper_file, + const char* key, + const float* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_write_float_internal(flipper_file->file, key, data, data_size); +} + +bool flipper_file_update_float( + FlipperFile* flipper_file, + const char* key, + const float* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_delete_key_and_call( + flipper_file, key, flipper_file_write_float_internal, key, data, data_size); +} \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_helper.c b/lib/flipper_file/flipper_file_helper.c new file mode 100644 index 00000000..5b8bfb2d --- /dev/null +++ b/lib/flipper_file/flipper_file_helper.c @@ -0,0 +1,118 @@ +#include "flipper_file_helper.h" + +const char* flipper_file_filetype_key = "Filetype"; +const char* flipper_file_version_key = "Version"; +const char flipper_file_delimiter = ':'; +const char flipper_file_comment = '#'; + +#ifdef __linux__ +const char* flipper_file_scratchpad = ".scratch.pad"; +#else +const char* flipper_file_scratchpad = "/any/.scratch.pad"; +#endif + +bool flipper_file_read_valid_key(File* file, string_t key) { + string_clean(key); + bool found = false; + bool error = false; + const uint8_t buffer_size = 32; + uint8_t buffer[buffer_size]; + bool accumulate = true; + bool new_line = true; + + while(true) { + uint16_t bytes_were_read = storage_file_read(file, buffer, buffer_size); + if(bytes_were_read == 0) break; + + for(uint16_t i = 0; i < bytes_were_read; i++) { + if(buffer[i] == flipper_file_eoln) { + // EOL found, clean data, start accumulating data and set the new_line flag + string_clean(key); + accumulate = true; + new_line = true; + } else if(buffer[i] == flipper_file_eolr) { + // Ignore + } else if(buffer[i] == flipper_file_comment && new_line) { + // if there is a comment character and we are at the beginning of a new line + // do not accumulate comment data and reset the new_line flag + accumulate = false; + new_line = false; + } else if(buffer[i] == flipper_file_delimiter) { + if(new_line) { + // we are on a "new line" and found the delimiter + // this can only be if we have previously found some kind of key, so + // clear the data, set the flag that we no longer want to accumulate data + // and reset the new_line flag + string_clean(key); + accumulate = false; + new_line = false; + } else { + // parse the delimiter only if we are accumulating data + if(accumulate) { + // we found the delimiter, move the rw pointer to the correct location + // and signal that we have found something + if(!file_helper_seek(file, i - bytes_were_read)) { + error = true; + break; + } + + found = true; + break; + } + } + } else { + // just new symbol, reset the new_line flag + new_line = false; + if(accumulate) { + // and accumulate data if we want + string_push_back(key, buffer[i]); + } + } + } + + if(found || error) break; + } + + return found; +} + +bool flipper_file_seek_to_key(File* file, const char* key) { + bool found = false; + string_t readed_key; + + string_init(readed_key); + + while(!storage_file_eof(file)) { + if(flipper_file_read_valid_key(file, readed_key)) { + if(string_cmp_str(readed_key, key) == 0) { + if(!file_helper_seek(file, 2)) break; + + found = true; + break; + } + } + } + string_clear(readed_key); + + return found; +} + +bool flipper_file_write_key(File* file, const char* key) { + bool result = false; + + do { + result = file_helper_write(file, key, strlen(key)); + if(!result) break; + + const char delimiter_buffer[2] = {flipper_file_delimiter, ' '}; + result = file_helper_write(file, delimiter_buffer, sizeof(delimiter_buffer)); + } while(false); + + return result; +} + +bool flipper_file_get_scratchpad_name(const char** name) { + // TODO do not rewrite existing file + *name = flipper_file_scratchpad; + return true; +} \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_helper.h b/lib/flipper_file/flipper_file_helper.h new file mode 100644 index 00000000..770be74e --- /dev/null +++ b/lib/flipper_file/flipper_file_helper.h @@ -0,0 +1,51 @@ +#pragma once +#include +#include +#include +#include "file_helper.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char* flipper_file_filetype_key; +extern const char* flipper_file_version_key; +extern const char flipper_file_delimiter; +extern const char flipper_file_comment; + +/** + * Reads a valid key from a file as a string. + * After reading, the rw pointer will be on the flipper_file_delimiter symbol. + * Optimized not to read comments and values into RAM. + * @param file + * @param key + * @return true on success read + */ +bool flipper_file_read_valid_key(File* file, string_t key); + +/** + * Sets rw pointer to the data after the key + * @param file + * @param key + * @return true if key was found + */ +bool flipper_file_seek_to_key(File* file, const char* key); + +/** + * Write key and key delimiter + * @param file + * @param key + * @return bool + */ +bool flipper_file_write_key(File* file, const char* key); + +/** + * Get scratchpad name and path + * @param name + * @return bool + */ +bool flipper_file_get_scratchpad_name(const char** name); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_hex.c b/lib/flipper_file/flipper_file_hex.c new file mode 100644 index 00000000..602652eb --- /dev/null +++ b/lib/flipper_file/flipper_file_hex.c @@ -0,0 +1,42 @@ +#include + +#include "flipper_file.h" +#include "flipper_file_i.h" +#include "flipper_file_helper.h" + +static bool flipper_file_write_hex_internal( + File* file, + const char* key, + const void* _data, + const uint16_t data_size) { + return flipper_file_write_internal(file, key, _data, data_size, FlipperFileValueHex); +}; + +bool flipper_file_write_hex( + FlipperFile* flipper_file, + const char* key, + const uint8_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_write_hex_internal(flipper_file->file, key, data, data_size); +} + +bool flipper_file_read_hex( + FlipperFile* flipper_file, + const char* key, + uint8_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_read_internal( + flipper_file->file, key, data, data_size, FlipperFileValueHex); +} + +bool flipper_file_update_hex( + FlipperFile* flipper_file, + const char* key, + const uint8_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_delete_key_and_call( + flipper_file, key, flipper_file_write_hex_internal, key, data, data_size); +} \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_i.h b/lib/flipper_file/flipper_file_i.h new file mode 100644 index 00000000..68f7fe6a --- /dev/null +++ b/lib/flipper_file/flipper_file_i.h @@ -0,0 +1,72 @@ +#include +#include + +struct FlipperFile { + File* file; + Storage* storage; +}; + +/** + * Value write type callback + */ +typedef bool (*flipper_file_cb)(File* file, const char* key, const void* data, uint16_t data_size); + +/** + * + * @param flipper_file + * @param key + * @param cb + * @param cb_key + * @param cb_data + * @param cb_data_size + * @return bool + */ +bool flipper_file_delete_key_and_call( + FlipperFile* flipper_file, + const char* key, + flipper_file_cb cb, + const char* cb_key, + const void* cb_data, + const uint16_t cb_data_size); + +/** + * Value types + */ +typedef enum { + FlipperFileValueHex, + FlipperFileValueFloat, + FlipperFileValueInt32, + FlipperFileValueUint32, +} FlipperFileValueType; + +/** + * Internal write values function + * @param file + * @param key + * @param _data + * @param data_size + * @param type + * @return bool + */ +bool flipper_file_write_internal( + File* file, + const char* key, + const void* _data, + const uint16_t data_size, + FlipperFileValueType type); + +/** + * Internal read values function + * @param file + * @param key + * @param _data + * @param data_size + * @param type + * @return bool + */ +bool flipper_file_read_internal( + File* file, + const char* key, + void* _data, + const uint16_t data_size, + FlipperFileValueType type); \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_int32.c b/lib/flipper_file/flipper_file_int32.c new file mode 100644 index 00000000..6b8ad3b8 --- /dev/null +++ b/lib/flipper_file/flipper_file_int32.c @@ -0,0 +1,42 @@ +#include + +#include "flipper_file.h" +#include "flipper_file_i.h" +#include "flipper_file_helper.h" + +static bool flipper_file_write_int32_internal( + File* file, + const char* key, + const void* _data, + const uint16_t data_size) { + return flipper_file_write_internal(file, key, _data, data_size, FlipperFileValueInt32); +}; + +bool flipper_file_read_int32( + FlipperFile* flipper_file, + const char* key, + int32_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_read_internal( + flipper_file->file, key, data, data_size, FlipperFileValueInt32); +} + +bool flipper_file_write_int32( + FlipperFile* flipper_file, + const char* key, + const int32_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_write_int32_internal(flipper_file->file, key, data, data_size); +} + +bool flipper_file_update_int32( + FlipperFile* flipper_file, + const char* key, + const int32_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_delete_key_and_call( + flipper_file, key, flipper_file_write_int32_internal, key, data, data_size); +} \ No newline at end of file diff --git a/lib/flipper_file/flipper_file_string.c b/lib/flipper_file/flipper_file_string.c new file mode 100644 index 00000000..6b75fcc5 --- /dev/null +++ b/lib/flipper_file/flipper_file_string.c @@ -0,0 +1,67 @@ +#include + +#include "flipper_file.h" +#include "flipper_file_i.h" +#include "flipper_file_helper.h" + +static bool flipper_file_write_string_internal( + File* file, + const char* key, + const void* data, + const uint16_t data_size) { + bool result = false; + (void)data_size; + + do { + result = flipper_file_write_key(file, key); + if(!result) break; + + result = file_helper_write(file, string_get_cstr(data), string_size(data)); + if(!result) break; + + result = file_helper_write_eol(file); + } while(false); + + return result; +}; + +bool flipper_file_read_string(FlipperFile* flipper_file, const char* key, string_t data) { + furi_assert(flipper_file); + + bool result = false; + if(flipper_file_seek_to_key(flipper_file->file, key)) { + if(file_helper_read_line(flipper_file->file, data)) { + result = true; + } + } + return result; +} + +bool flipper_file_write_string(FlipperFile* flipper_file, const char* key, string_t data) { + furi_assert(flipper_file); + return flipper_file_write_string_internal(flipper_file->file, key, data, 0); +} + +bool flipper_file_write_string_cstr(FlipperFile* flipper_file, const char* key, const char* data) { + bool result = false; + string_t value; + string_init_set(value, data); + result = flipper_file_write_string(flipper_file, key, value); + string_clear(value); + return result; +} + +bool flipper_file_update_string(FlipperFile* flipper_file, const char* key, string_t data) { + furi_assert(flipper_file); + return flipper_file_delete_key_and_call( + flipper_file, key, flipper_file_write_string_internal, key, data, 0); +} + +bool flipper_file_update_string_cstr(FlipperFile* flipper_file, const char* key, const char* data) { + bool result = false; + string_t value; + string_init_set(value, data); + result = flipper_file_update_string(flipper_file, key, value); + string_clear(value); + return result; +} diff --git a/lib/flipper_file/flipper_file_uint32.c b/lib/flipper_file/flipper_file_uint32.c new file mode 100644 index 00000000..6a3b58e4 --- /dev/null +++ b/lib/flipper_file/flipper_file_uint32.c @@ -0,0 +1,42 @@ +#include + +#include "flipper_file.h" +#include "flipper_file_i.h" +#include "flipper_file_helper.h" + +static bool flipper_file_write_uint32_internal( + File* file, + const char* key, + const void* _data, + const uint16_t data_size) { + return flipper_file_write_internal(file, key, _data, data_size, FlipperFileValueUint32); +}; + +bool flipper_file_read_uint32( + FlipperFile* flipper_file, + const char* key, + uint32_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_read_internal( + flipper_file->file, key, data, data_size, FlipperFileValueUint32); +} + +bool flipper_file_write_uint32( + FlipperFile* flipper_file, + const char* key, + const uint32_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_write_uint32_internal(flipper_file->file, key, data, data_size); +} + +bool flipper_file_update_uint32( + FlipperFile* flipper_file, + const char* key, + const uint32_t* data, + const uint16_t data_size) { + furi_assert(flipper_file); + return flipper_file_delete_key_and_call( + flipper_file, key, flipper_file_write_uint32_internal, key, data, data_size); +} \ No newline at end of file diff --git a/lib/irda/worker/irda_worker.c b/lib/irda/worker/irda_worker.c index 98b091f4..58b6ef5a 100644 --- a/lib/irda/worker/irda_worker.c +++ b/lib/irda/worker/irda_worker.c @@ -7,6 +7,7 @@ #include #include #include + #include #include diff --git a/lib/lfs_config.h b/lib/lfs_config.h new file mode 100644 index 00000000..7a883982 --- /dev/null +++ b/lib/lfs_config.h @@ -0,0 +1,187 @@ +#pragma once + +#include + +#ifdef FURI_NDEBUG +#define LFS_NO_ASSERT +#endif + +#define LFS_TAG "Lfs" + +#define LFS_TRACE(...) FURI_LOG_D(LFS_TAG, __VA_ARGS__); + +#define LFS_DEBUG(...) FURI_LOG_I(LFS_TAG, __VA_ARGS__); + +#define LFS_WARN(...) FURI_LOG_W(LFS_TAG, __VA_ARGS__); + +#define LFS_ERROR(...) FURI_LOG_E(LFS_TAG, __VA_ARGS__); + +#define LFS_ASSERT furi_assert + +// Because crc +#undef LFS_CONFIG + +// System includes +#include +#include +#include +#include + +#ifndef LFS_NO_MALLOC +#include +#endif +#ifndef LFS_NO_ASSERT +#include +#endif +#if !defined(LFS_NO_DEBUG) || \ + !defined(LFS_NO_WARN) || \ + !defined(LFS_NO_ERROR) || \ + defined(LFS_YES_TRACE) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs_max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +static inline uint32_t lfs_min(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +// Align to nearest multiple of a size +static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { + return a - (a % alignment); +} + +static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { + return lfs_aligndown(a + alignment-1, alignment); +} + +// Find the smallest power of 2 greater than or equal to a +static inline uint32_t lfs_npw2(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a-1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; a >>= s; r |= s; + s = (a > 0xff ) << 3; a >>= s; r |= s; + s = (a > 0xf ) << 2; a >>= s; r |= s; + s = (a > 0x3 ) << 1; a >>= s; r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs_ctz(0) may be undefined +static inline uint32_t lfs_ctz(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs_popc(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs_scmp(uint32_t a, uint32_t b) { + return (int)(unsigned)(a - b); +} + +// Convert between 32-bit little-endian and native order +static inline uint32_t lfs_fromle32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t*)&a)[0] << 0) | + (((uint8_t*)&a)[1] << 8) | + (((uint8_t*)&a)[2] << 16) | + (((uint8_t*)&a)[3] << 24); +#endif +} + +static inline uint32_t lfs_tole32(uint32_t a) { + return lfs_fromle32(a); +} + +// Convert between 32-bit big-endian and native order +static inline uint32_t lfs_frombe32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return __builtin_bswap32(a); +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return a; +#else + return (((uint8_t*)&a)[0] << 24) | + (((uint8_t*)&a)[1] << 16) | + (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); +#endif +} + +static inline uint32_t lfs_tobe32(uint32_t a) { + return lfs_frombe32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +// Note, memory must be 64-bit aligned +static inline void *lfs_malloc(size_t size) { +#ifndef LFS_NO_MALLOC + return malloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs_free(void *p) { +#ifndef LFS_NO_MALLOC + free(p); +#else + (void)p; +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/lib/lib.mk b/lib/lib.mk index f1b3ddd9..34f43bd4 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -37,7 +37,7 @@ C_SOURCES += $(FATFS_DIR)/option/unicode.c # Little FS LITTLEFS_DIR = $(LIB_DIR)/littlefs -CFLAGS += -I$(LITTLEFS_DIR) +CFLAGS += -I$(LITTLEFS_DIR) -DLFS_CONFIG=lfs_config.h C_SOURCES += $(LITTLEFS_DIR)/lfs.c C_SOURCES += $(LITTLEFS_DIR)/lfs_util.c @@ -120,3 +120,7 @@ C_SOURCES += $(wildcard $(LIB_DIR)/nanopb/*.c) # heatshrink CFLAGS += -I$(LIB_DIR)/heatshrink C_SOURCES += $(wildcard $(LIB_DIR)/heatshrink/*.c) + +# Toolbox +CFLAGS += -I$(LIB_DIR)/flipper_file +C_SOURCES += $(wildcard $(LIB_DIR)/flipper_file/*.c) \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_came_atomo.c b/lib/subghz/protocols/subghz_protocol_came_atomo.c index 37c0860f..2f2bd071 100644 --- a/lib/subghz/protocols/subghz_protocol_came_atomo.c +++ b/lib/subghz/protocols/subghz_protocol_came_atomo.c @@ -1,6 +1,7 @@ #include "subghz_protocol_came_atomo.h" #include "subghz_protocol_common.h" #include +#include "../subghz_keystore.h" #define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF @@ -25,14 +26,8 @@ SubGhzProtocolCameAtomo* subghz_protocol_came_atomo_alloc() { instance->common.te_delta = 250; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_atomo_to_str; - // instance->common.to_save_string = - // (SubGhzProtocolCommonGetStrSave)subghz_protocol_came_atomo_to_save_str; - //instance->common.to_load_protocol_from_file = - // (SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_atomo_to_load_protocol_from_file; instance->common.to_load_protocol = (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_atomo_to_load_protocol; - // instance->common.get_upload_protocol = - // (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_came_atomo_send_key; return instance; } @@ -62,20 +57,14 @@ uint64_t subghz_came_atomo_get_atomo_magic_xor_in_file( uint32_t address = number_atomo_magic_xor * sizeof(uint64_t); uint64_t atomo_magic_xor = 0; - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open( - file_worker, instance->rainbow_table_file_name, FSAM_READ, FSOM_OPEN_EXISTING)) { - file_worker_seek(file_worker, address, true); - file_worker_read(file_worker, &buffer, sizeof(uint64_t)); + if(subghz_keystore_raw_get_data( + instance->rainbow_table_file_name, address, buffer, sizeof(uint64_t))) { for(size_t i = 0; i < sizeof(uint64_t); i++) { atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i]; } } else { atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE; } - file_worker_close(file_worker); - file_worker_free(file_worker); - return atomo_magic_xor; } @@ -265,64 +254,6 @@ void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string instance->common.cnt); } -// void subghz_protocol_came_atomo_to_save_str(SubGhzProtocolCameAtomo* instance, string_t output) { -// string_printf( -// output, -// "Protocol: %s\n" -// "Bit: %d\n" -// "Key: %08lX%08lX\r\n", -// instance->common.name, -// instance->common.code_last_count_bit, -// (uint32_t)(instance->common.code_last_found >> 32), -// (uint32_t)(instance->common.code_last_found & 0xFFFFFFFF)); -// } - -// bool subghz_protocol_came_atomo_to_load_protocol_from_file( -// FileWorker* file_worker, -// SubGhzProtocolCameAtomo* instance, -// const char* file_path) { -// bool loaded = false; -// string_t temp_str; -// string_init(temp_str); -// int res = 0; -// int data = 0; - -// do { -// // Read and parse bit data from 2nd line -// if(!file_worker_read_until(file_worker, temp_str, '\n')) { -// break; -// } -// res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); -// if(res != 1) { -// break; -// } -// instance->common.code_last_count_bit = (uint8_t)data; - -// // Read and parse key data from 3nd line -// if(!file_worker_read_until(file_worker, temp_str, '\n')) { -// break; -// } -// // strlen("Key: ") = 5 -// string_right(temp_str, 5); - -// uint8_t buf_key[8] = {0}; -// if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) { -// break; -// } - -// for(uint8_t i = 0; i < 8; i++) { -// instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i]; -// } - -// loaded = true; -// } while(0); - -// string_clear(temp_str); - -// subghz_protocol_came_atomo_remote_controller(instance); -// return loaded; -// } - void subghz_decoder_came_atomo_to_load_protocol(SubGhzProtocolCameAtomo* instance, void* context) { furi_assert(context); furi_assert(instance); diff --git a/lib/subghz/protocols/subghz_protocol_came_atomo.h b/lib/subghz/protocols/subghz_protocol_came_atomo.h index 2b349399..cc841441 100644 --- a/lib/subghz/protocols/subghz_protocol_came_atomo.h +++ b/lib/subghz/protocols/subghz_protocol_came_atomo.h @@ -23,16 +23,6 @@ void subghz_protocol_came_atomo_free(SubGhzProtocolCameAtomo* instance); */ void subghz_protocol_came_atomo_name_file(SubGhzProtocolCameAtomo* instance, const char* name); -// /** Get upload protocol -// * -// * @param instance - SubGhzProtocolCameAtomo instance -// * @param encoder - SubGhzProtocolCommonEncoder encoder -// * @return bool -// */ -// bool subghz_protocol_came_atomo_send_key( -// SubGhzProtocolCameAtomo* instance, -// SubGhzProtocolCommonEncoder* encoder); - /** Reset internal state * @param instance - SubGhzProtocolCameAtomo instance */ @@ -55,25 +45,6 @@ void subghz_protocol_came_atomo_parse( */ void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string_t output); -// /** Get a string to save the protocol -// * -// * @param instance - SubGhzProtocolCameAtomo instance -// * @param output - the resulting string -// */ -// void subghz_protocol_came_atomo_to_save_str(SubGhzProtocolCameAtomo* instance, string_t output); - -// /** Loading protocol from file -// * -// * @param file_worker - FileWorker file_worker -// * @param instance - SubGhzProtocolCameAtomo instance -// * @param file_path - file path -// * @return bool -// */ -// bool subghz_protocol_came_atomo_to_load_protocol_from_file( -// FileWorker* file_worker, -// SubGhzProtocolCameAtomo* instance, -// const char* file_path); - /** Loading protocol from bin data * * @param instance - SubGhzProtocolCameAtomo instance diff --git a/lib/subghz/protocols/subghz_protocol_faac_slh.c b/lib/subghz/protocols/subghz_protocol_faac_slh.c index 5cc0a995..a6ee72ed 100644 --- a/lib/subghz/protocols/subghz_protocol_faac_slh.c +++ b/lib/subghz/protocols/subghz_protocol_faac_slh.c @@ -167,7 +167,7 @@ void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t o string_cat_printf( output, "%s %dbit\r\n" - "Key:0x%lX%08lX\r\n" + "Key:%lX%08lX\r\n" "Fix:%08lX \r\n" "Hop:%08lX \r\n" "Sn:%07lX Btn:%lX\r\n", diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index 609809ca..2fce7989 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -69,7 +69,7 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { switch(manufacture_code->type) { case KEELOQ_LEARNING_SIMPLE: - //Simple Learning + // Simple Learning decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) || diff --git a/lib/subghz/protocols/subghz_protocol_nice_flor_s.c b/lib/subghz/protocols/subghz_protocol_nice_flor_s.c index 32d528bc..95e0216a 100644 --- a/lib/subghz/protocols/subghz_protocol_nice_flor_s.c +++ b/lib/subghz/protocols/subghz_protocol_nice_flor_s.c @@ -2,6 +2,7 @@ #include #include "file-worker.h" +#include "../subghz_keystore.h" /* * https://phreakerclub.com/1615 * https://phreakerclub.com/forum/showthread.php?t=2360 @@ -103,17 +104,13 @@ void subghz_protocol_nice_flor_s_send_key( uint8_t subghz_nice_flor_s_get_byte_in_file(SubGhzProtocolNiceFlorS* instance, uint32_t address) { if(!instance->rainbow_table_file_name) return 0; - uint8_t buffer = 0; - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open( - file_worker, instance->rainbow_table_file_name, FSAM_READ, FSOM_OPEN_EXISTING)) { - file_worker_seek(file_worker, address, true); - file_worker_read(file_worker, &buffer, 1); + uint8_t buffer[1] = {0}; + if(subghz_keystore_raw_get_data( + instance->rainbow_table_file_name, address, buffer, sizeof(uint8_t))) { + return buffer[0]; + } else { + return 0; } - file_worker_close(file_worker); - file_worker_free(file_worker); - - return buffer; } /** Decrypt protocol Nice Flor S diff --git a/lib/subghz/subghz_keystore.c b/lib/subghz/subghz_keystore.c index dea11e0b..3b55b700 100644 --- a/lib/subghz/subghz_keystore.c +++ b/lib/subghz/subghz_keystore.c @@ -1,10 +1,29 @@ #include "subghz_keystore.h" #include +#include + #include +#include +#include + +#define SUBGHZ_KEYSTORE_TAG "SubGhzParser" #define FILE_BUFFER_SIZE 64 +#define SUBGHZ_KEYSTORE_FILE_TYPE "Flipper SubGhz Keystore File" +#define SUBGHZ_KEYSTORE_FILE_RAW_TYPE "Flipper SubGhz Keystore RAW File" +#define SUBGHZ_KEYSTORE_FILE_VERSION 0 + +#define SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT 1 +#define SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE 512 +#define SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE (SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE * 2) + +typedef enum { + SubGhzKeystoreEncryptionNone, + SubGhzKeystoreEncryptionAES256, +} SubGhzKeystoreEncryption; + struct SubGhzKeystore { SubGhzKeyArray_t data; }; @@ -21,65 +40,559 @@ void subghz_keystore_free(SubGhzKeystore* instance) { furi_assert(instance); for - M_EACH(manufacture_code, instance->data, SubGhzKeyArray_t) { - string_clear(manufacture_code->name); - manufacture_code->key = 0; - } + M_EACH(manufacture_code, instance->data, SubGhzKeyArray_t) { + string_clear(manufacture_code->name); + manufacture_code->key = 0; + } SubGhzKeyArray_clear(instance->data); free(instance); } -static void subghz_keystore_add_key(SubGhzKeystore* instance, const char* name, uint64_t key, uint16_t type) { +static void subghz_keystore_add_key( + SubGhzKeystore* instance, + const char* name, + uint64_t key, + uint16_t type) { SubGhzKey* manufacture_code = SubGhzKeyArray_push_raw(instance->data); string_init_set_str(manufacture_code->name, name); manufacture_code->key = key; manufacture_code->type = type; } -static void subghz_keystore_process_line(SubGhzKeystore* instance, string_t line) { +static bool subghz_keystore_process_line(SubGhzKeystore* instance, char* line) { uint64_t key = 0; uint16_t type = 0; char skey[17] = {0}; char name[65] = {0}; - int ret = sscanf(string_get_cstr(line), "%16s:%hu:%64s", skey, &type, name); + int ret = sscanf(line, "%16s:%hu:%64s", skey, &type, name); key = strtoull(skey, NULL, 16); - if (ret == 3) { + if(ret == 3) { subghz_keystore_add_key(instance, name, key, type); + return true; } else { - printf("Failed to load line: %s\r\n", string_get_cstr(line)); + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Failed to load line: %s\r\n", line); + return false; } } -void subghz_keystore_load(SubGhzKeystore* instance, const char* file_name) { - File* manufacture_keys_file = storage_file_alloc(furi_record_open("storage")); - string_t line; - string_init(line); - if(storage_file_open(manufacture_keys_file, file_name, FSAM_READ, FSOM_OPEN_EXISTING)) { - printf("Loading manufacture keys file %s\r\n", file_name); - char buffer[FILE_BUFFER_SIZE]; - uint16_t ret; - do { - ret = storage_file_read(manufacture_keys_file, buffer, FILE_BUFFER_SIZE); - for (uint16_t i=0; i < ret; i++) { - if (buffer[i] == '\n' && string_size(line) > 0) { - subghz_keystore_process_line(instance, line); - string_clean(line); +static void subghz_keystore_mess_with_iv(uint8_t* iv) { + // Please do not share decrypted manufacture keys + // Sharing them will bring some discomfort to legal owners + // And potential legal action against you + // While you reading this code think about your own personal responsibility + asm volatile("movs r0, #0x0 \n" + "movs r1, #0x0 \n" + "movs r2, #0x0 \n" + "movs r3, #0x0 \n" + "nani: \n" + "ldrb r1, [r0, %0]\n" + "mov r2, r1 \n" + "add r1, r3 \n" + "mov r3, r2 \n" + "strb r1, [r0, %0]\n" + "adds r0, #0x1 \n" + "cmp r0, #0xF \n" + "bls nani \n" + : + : "r"(iv) + : "r0", "r1", "r2", "r3", "memory"); +} + +static bool subghz_keystore_read_file(SubGhzKeystore* instance, File* file, uint8_t* iv) { + bool result = true; + char buffer[FILE_BUFFER_SIZE]; + + char* decrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + char* encrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + size_t encrypted_line_cursor = 0; + + if(iv) furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv); + + size_t ret = 0; + do { + ret = storage_file_read(file, buffer, FILE_BUFFER_SIZE); + for(uint16_t i = 0; i < ret; i++) { + if(buffer[i] == '\n' && encrypted_line_cursor > 0) { + // Process line + if(iv) { + // Data alignment check, 32 instead of 16 because of hex encoding + size_t len = strlen(encrypted_line); + if(len % 32 == 0) { + // Inplace hex to bin conversion + for(size_t i = 0; i < len; i += 2) { + uint8_t hi_nibble = 0; + uint8_t lo_nibble = 0; + hex_char_to_hex_nibble(encrypted_line[i], &hi_nibble); + hex_char_to_hex_nibble(encrypted_line[i + 1], &lo_nibble); + encrypted_line[i / 2] = (hi_nibble << 4) | lo_nibble; + } + len /= 2; + + if(furi_hal_crypto_decrypt( + (uint8_t*)encrypted_line, (uint8_t*)decrypted_line, len)) { + subghz_keystore_process_line(instance, decrypted_line); + } else { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Decryption failed"); + result = false; + break; + } + } else { + FURI_LOG_E( + SUBGHZ_KEYSTORE_TAG, "Invalid encrypted data: %s", encrypted_line); + } } else { - string_push_back(line, buffer[i]); + subghz_keystore_process_line(instance, encrypted_line); + } + // reset line buffer + memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + encrypted_line_cursor = 0; + } else if(buffer[i] == '\r' || buffer[i] == '\n') { + // do not add line endings to the buffer + } else { + if(encrypted_line_cursor < SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE) { + encrypted_line[encrypted_line_cursor] = buffer[i]; + encrypted_line_cursor++; + } else { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Malformed file"); + result = false; + break; } } - } while(ret > 0); - } else { - printf("Manufacture keys file is not found: %s\r\n", file_name); - } - string_clear(line); - storage_file_close(manufacture_keys_file); - storage_file_free(manufacture_keys_file); + } + } while(ret > 0 && result); + + if(iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + + free(encrypted_line); + free(decrypted_line); + + return result; +} + +bool subghz_keystore_load(SubGhzKeystore* instance, const char* file_name) { + furi_assert(instance); + bool result = false; + uint8_t iv[16]; + uint32_t version; + SubGhzKeystoreEncryption encryption; + + string_t filetype; + string_init(filetype); + + Storage* storage = furi_record_open("storage"); + + FlipperFile* flipper_file = flipper_file_alloc(storage); + do { + if(!flipper_file_open_existing(flipper_file, file_name)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for read: %s", file_name); + break; + } + if(!flipper_file_read_header(flipper_file, filetype, &version)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing or incorrect header"); + break; + } + if(!flipper_file_read_uint32(flipper_file, "Encryption", (uint32_t*)&encryption, 1)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing encryption type"); + break; + } + + if(strcmp(string_get_cstr(filetype), SUBGHZ_KEYSTORE_FILE_TYPE) != 0 || + version != SUBGHZ_KEYSTORE_FILE_VERSION) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Type or version mismatch"); + break; + } + + File* file = flipper_file_get_file(flipper_file); + if(encryption == SubGhzKeystoreEncryptionNone) { + result = subghz_keystore_read_file(instance, file, NULL); + } else if(encryption == SubGhzKeystoreEncryptionAES256) { + if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing IV"); + break; + } + subghz_keystore_mess_with_iv(iv); + result = subghz_keystore_read_file(instance, file, iv); + } else { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unknown encryption"); + break; + } + } while(0); + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + furi_record_close("storage"); + + string_clear(filetype); + + return result; +} + +bool subghz_keystore_save(SubGhzKeystore* instance, const char* file_name, uint8_t* iv) { + furi_assert(instance); + bool result = false; + + Storage* storage = furi_record_open("storage"); + char* decrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + char* encrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + + FlipperFile* flipper_file = flipper_file_alloc(storage); + do { + if(!flipper_file_open_always(flipper_file, file_name)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for write: %s", file_name); + break; + } + if(!flipper_file_write_header_cstr( + flipper_file, SUBGHZ_KEYSTORE_FILE_TYPE, SUBGHZ_KEYSTORE_FILE_VERSION)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add header"); + break; + } + SubGhzKeystoreEncryption encryption = SubGhzKeystoreEncryptionAES256; + if(!flipper_file_write_uint32(flipper_file, "Encryption", (uint32_t*)&encryption, 1)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add Encryption"); + break; + } + if(!flipper_file_write_hex(flipper_file, "IV", iv, 16)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add IV"); + break; + } + + subghz_keystore_mess_with_iv(iv); + + if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to load encryption key"); + break; + } + + File* file = flipper_file_get_file(flipper_file); + size_t encrypted_line_count = 0; + for + M_EACH(key, instance->data, SubGhzKeyArray_t) { + // Wipe buffer before packing + memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + // Form unecreypted line + int len = snprintf( + decrypted_line, + SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE, + "%08lX%08lX:%hu:%s", + (uint32_t)(key->key >> 32), + (uint32_t)key->key, + key->type, + string_get_cstr(key->name)); + // Verify length and align + furi_assert(len > 0); + if(len % 16 != 0) { + len += (16 - len % 16); + } + furi_assert(len % 16 == 0); + furi_assert(len <= SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + // Form encrypted line + if(!furi_hal_crypto_encrypt( + (uint8_t*)decrypted_line, (uint8_t*)encrypted_line, len)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Encryption failed"); + break; + } + // HEX Encode encrypted line + const char xx[] = "0123456789ABCDEF"; + for(size_t i = 0; i < len; i++) { + size_t cursor = len - i - 1; + size_t hex_cursor = len * 2 - i * 2 - 1; + encrypted_line[hex_cursor] = xx[encrypted_line[cursor] & 0xF]; + encrypted_line[hex_cursor - 1] = xx[(encrypted_line[cursor] >> 4) & 0xF]; + } + storage_file_write(file, encrypted_line, strlen(encrypted_line)); + storage_file_write(file, "\n", 1); + encrypted_line_count++; + + FURI_LOG_I( + SUBGHZ_KEYSTORE_TAG, "Encrypted: `%s` -> `%s`", decrypted_line, encrypted_line); + } + furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + result = encrypted_line_count == SubGhzKeyArray_size(instance->data); + } while(0); + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + + free(encrypted_line); + free(decrypted_line); + furi_record_close("storage"); + + return result; } SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance) { furi_assert(instance); return &instance->data; } + +bool subghz_keystore_raw_encrypted_save( + const char* input_file_name, + const char* output_file_name, + uint8_t* iv) { + bool encrypted = false; + uint32_t version; + string_t filetype; + string_init(filetype); + SubGhzKeystoreEncryption encryption; + + Storage* storage = furi_record_open("storage"); + + char* encrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + + FlipperFile* input_flipper_file = flipper_file_alloc(storage); + do { + if(!flipper_file_open_existing(input_flipper_file, input_file_name)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for read: %s", input_file_name); + break; + } + if(!flipper_file_read_header(input_flipper_file, filetype, &version)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing or incorrect header"); + break; + } + if(!flipper_file_read_uint32(input_flipper_file, "Encryption", (uint32_t*)&encryption, 1)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing encryption type"); + break; + } + + if(strcmp(string_get_cstr(filetype), SUBGHZ_KEYSTORE_FILE_RAW_TYPE) != 0 || + version != SUBGHZ_KEYSTORE_FILE_VERSION) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Type or version mismatch"); + break; + } + + if(encryption != SubGhzKeystoreEncryptionNone) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Already encryption"); + break; + } + File* input_file = flipper_file_get_file(input_flipper_file); + + FlipperFile* output_flipper_file = flipper_file_alloc(storage); + + if(!flipper_file_open_always(output_flipper_file, output_file_name)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for write: %s", output_file_name); + break; + } + if(!flipper_file_write_header_cstr( + output_flipper_file, string_get_cstr(filetype), SUBGHZ_KEYSTORE_FILE_VERSION)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add header"); + break; + } + SubGhzKeystoreEncryption tmp_encryption = SubGhzKeystoreEncryptionAES256; + if(!flipper_file_write_uint32( + output_flipper_file, "Encryption", (uint32_t*)&tmp_encryption, 1)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add Encryption"); + break; + } + if(!flipper_file_write_hex(output_flipper_file, "IV", iv, 16)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add IV"); + break; + } + + if(!flipper_file_write_string_cstr(output_flipper_file, "Encrypt_data", "RAW")) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add Encrypt_data"); + break; + } + + subghz_keystore_mess_with_iv(iv); + + if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to load encryption key"); + break; + } + + File* output_file = flipper_file_get_file(output_flipper_file); + char buffer[FILE_BUFFER_SIZE]; + bool result = true; + + size_t ret = 0; + furi_assert(FILE_BUFFER_SIZE % 16 == 0); + + //skip the end of the previous line "\n" + storage_file_read(input_file, buffer, 1); + + do { + memset(buffer, 0, FILE_BUFFER_SIZE); + ret = storage_file_read(input_file, buffer, FILE_BUFFER_SIZE); + if(ret == 0) { + break; + } + + for(uint16_t i = 0; i < FILE_BUFFER_SIZE - 1; i += 2) { + uint8_t hi_nibble = 0; + uint8_t lo_nibble = 0; + hex_char_to_hex_nibble(buffer[i], &hi_nibble); + hex_char_to_hex_nibble(buffer[i + 1], &lo_nibble); + buffer[i / 2] = (hi_nibble << 4) | lo_nibble; + } + + memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE); + // Form encrypted line + if(!furi_hal_crypto_encrypt( + (uint8_t*)buffer, (uint8_t*)encrypted_line, FILE_BUFFER_SIZE / 2)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Encryption failed"); + result = false; + break; + } + + // HEX Encode encrypted line + const char xx[] = "0123456789ABCDEF"; + for(size_t i = 0; i < FILE_BUFFER_SIZE / 2; i++) { + size_t cursor = FILE_BUFFER_SIZE / 2 - i - 1; + size_t hex_cursor = FILE_BUFFER_SIZE - i * 2 - 1; + encrypted_line[hex_cursor] = xx[encrypted_line[cursor] & 0xF]; + encrypted_line[hex_cursor - 1] = xx[(encrypted_line[cursor] >> 4) & 0xF]; + } + storage_file_write(output_file, encrypted_line, strlen(encrypted_line)); + + } while(ret > 0 && result); + + flipper_file_close(output_flipper_file); + flipper_file_free(output_flipper_file); + + furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + + if(!result) break; + + encrypted = true; + } while(0); + + flipper_file_close(input_flipper_file); + flipper_file_free(input_flipper_file); + + free(encrypted_line); + + furi_record_close("storage"); + + return encrypted; +} + +bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t* data, size_t len) { + bool result = false; + uint8_t iv[16]; + uint32_t version; + SubGhzKeystoreEncryption encryption; + + string_t str_temp; + string_init(str_temp); + + Storage* storage = furi_record_open("storage"); + char* decrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + + FlipperFile* flipper_file = flipper_file_alloc(storage); + do { + if(!flipper_file_open_existing(flipper_file, file_name)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for read: %s", file_name); + break; + } + if(!flipper_file_read_header(flipper_file, str_temp, &version)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing or incorrect header"); + break; + } + if(!flipper_file_read_uint32(flipper_file, "Encryption", (uint32_t*)&encryption, 1)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing encryption type"); + break; + } + + if(strcmp(string_get_cstr(str_temp), SUBGHZ_KEYSTORE_FILE_RAW_TYPE) != 0 || + version != SUBGHZ_KEYSTORE_FILE_VERSION) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Type or version mismatch"); + break; + } + + File* file = flipper_file_get_file(flipper_file); + if(encryption != SubGhzKeystoreEncryptionAES256) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unknown encryption"); + break; + } + + if(offset < 16) { + if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing IV"); + break; + } + subghz_keystore_mess_with_iv(iv); + } + + if(!flipper_file_read_string(flipper_file, "Encrypt_data", str_temp)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing Encrypt_data"); + break; + } + + size_t bufer_size; + if(len <= (16 - offset % 16)) { + bufer_size = 32; + } else { + bufer_size = (((len) / 16) + 2) * 32; + } + furi_assert(SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE >= bufer_size / 2); + + char buffer[bufer_size]; + size_t ret = 0; + bool decrypted = true; + //skip the end of the previous line "\n" + storage_file_read(file, buffer, 1); + + size_t size = storage_file_size(file); + size -= storage_file_tell(file); + if(size < (offset * 2 + len * 2)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Seek position exceeds file size"); + break; + } + + if(offset >= 16) { + storage_file_seek(file, ((offset / 16) - 1) * 32, false); + ret = storage_file_read(file, buffer, 32); + furi_assert(ret == 32); + for(uint16_t i = 0; i < ret - 1; i += 2) { + uint8_t hi_nibble = 0; + uint8_t lo_nibble = 0; + hex_char_to_hex_nibble(buffer[i], &hi_nibble); + hex_char_to_hex_nibble(buffer[i + 1], &lo_nibble); + iv[i / 2] = (hi_nibble << 4) | lo_nibble; + } + } + + if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) { + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to load encryption key"); + break; + } + + do { + memset(buffer, 0, bufer_size); + ret = storage_file_read(file, buffer, bufer_size); + furi_assert(ret == bufer_size); + for(uint16_t i = 0; i < ret - 1; i += 2) { + uint8_t hi_nibble = 0; + uint8_t lo_nibble = 0; + hex_char_to_hex_nibble(buffer[i], &hi_nibble); + hex_char_to_hex_nibble(buffer[i + 1], &lo_nibble); + buffer[i / 2] = (hi_nibble << 4) | lo_nibble; + } + + memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE); + + if(!furi_hal_crypto_decrypt( + (uint8_t*)buffer, (uint8_t*)decrypted_line, bufer_size / 2)) { + decrypted = false; + FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Decryption failed"); + break; + } + memcpy(data, (uint8_t*)decrypted_line + (offset - (offset / 16) * 16), len); + + } while(0); + furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT); + if(decrypted) result = true; + } while(0); + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + + furi_record_close("storage"); + + free(decrypted_line); + + string_clear(str_temp); + + return result; +} diff --git a/lib/subghz/subghz_keystore.h b/lib/subghz/subghz_keystore.h index 4cd388f5..58af35e5 100644 --- a/lib/subghz/subghz_keystore.h +++ b/lib/subghz/subghz_keystore.h @@ -33,7 +33,14 @@ void subghz_keystore_free(SubGhzKeystore* instance); * @param instance - SubGhzKeystore instance * @param filename - const char* full path to the file */ -void subghz_keystore_load(SubGhzKeystore* instance, const char* filename); +bool subghz_keystore_load(SubGhzKeystore* instance, const char* filename); + +/** Save manufacture key to file + * + * @param instance - SubGhzKeystore instance + * @param filename - const char* full path to the file + */ +bool subghz_keystore_save(SubGhzKeystore* instance, const char* filename, uint8_t* iv); /** Get array of keys and names manufacture * @@ -41,3 +48,22 @@ void subghz_keystore_load(SubGhzKeystore* instance, const char* filename); * @return SubGhzKeyArray_t* */ SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance); + +/** Save RAW encrypted to file + * + * @param input_file_name - const char* full path to the input file + * @param output_file_name - const char* full path to the output file + */ +bool subghz_keystore_raw_encrypted_save( + const char* input_file_name, + const char* output_file_name, + uint8_t* iv); + +/** Get decrypt RAW data to file + * + * @param file_name - const char* full path to the input file + * @param offset - offset from the start of the RAW data + * @param data - returned array + * @param len - required data length + */ +bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t* data, size_t len); diff --git a/lib/subghz/subghz_parser.c b/lib/subghz/subghz_parser.c index f702dda9..93c48cb7 100644 --- a/lib/subghz/subghz_parser.c +++ b/lib/subghz/subghz_parser.c @@ -24,6 +24,8 @@ #include #include +#define SUBGHZ_PARSER_TAG "SubGhzParser" + typedef enum { SubGhzProtocolTypeCame, SubGhzProtocolTypeCameTwee, @@ -214,7 +216,11 @@ void subghz_parser_load_came_atomo_file(SubGhzParser* instance, const char* file } void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name) { - subghz_keystore_load(instance->keystore, file_name); + if (subghz_keystore_load(instance->keystore, file_name)) { + FURI_LOG_I(SUBGHZ_PARSER_TAG, "Successfully loaded keeloq keys from %s", file_name); + } else { + FURI_LOG_W(SUBGHZ_PARSER_TAG, "Failed to load keeloq keysfrom %s", file_name); + } } void subghz_parser_reset(SubGhzParser* instance) { diff --git a/lib/toolbox/flipper-file-cpp.cpp b/lib/toolbox/flipper-file-cpp.cpp deleted file mode 100644 index 84e6d181..00000000 --- a/lib/toolbox/flipper-file-cpp.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "flipper-file-cpp.h" - -FlipperFileCpp::FlipperFileCpp(Storage* storage) { - file = flipper_file_alloc(storage); -} - -FlipperFileCpp::~FlipperFileCpp() { - flipper_file_free(file); -} - -bool FlipperFileCpp::open_read(const char* filename) { - return flipper_file_open_read(file, filename); -} - -bool FlipperFileCpp::new_write(const char* filename) { - return flipper_file_new_write(file, filename); -} - -bool FlipperFileCpp::close() { - return flipper_file_close(file); -} - -bool FlipperFileCpp::read_header(string_t filetype, uint32_t* version) { - return flipper_file_read_header(file, filetype, version); -} - -bool FlipperFileCpp::write_header(string_t filetype, const uint32_t version) { - return flipper_file_write_header(file, filetype, version); -} - -bool FlipperFileCpp::write_header_cstr(const char* filetype, const uint32_t version) { - return flipper_file_write_header_cstr(file, filetype, version); -} - -bool FlipperFileCpp::read_string(const char* key, string_t data) { - return flipper_file_read_string(file, key, data); -} - -bool FlipperFileCpp::write_string(const char* key, string_t data) { - return flipper_file_write_string(file, key, data); -} - -bool FlipperFileCpp::write_string_cstr(const char* key, const char* data) { - return flipper_file_write_string_cstr(file, key, data); -} - -bool FlipperFileCpp::read_uint32(const char* key, uint32_t* data) { - return flipper_file_read_uint32(file, key, data); -} - -bool FlipperFileCpp::write_uint32(const char* key, const uint32_t data) { - return flipper_file_write_uint32(file, key, data); -} - -bool FlipperFileCpp::write_comment(string_t data) { - return flipper_file_write_comment(file, data); -} - -bool FlipperFileCpp::write_comment_cstr(const char* data) { - return flipper_file_write_comment_cstr(file, data); -} - -bool FlipperFileCpp::write_hex_array( - const char* key, - const uint8_t* data, - const uint16_t data_size) { - return flipper_file_write_hex_array(file, key, data, data_size); -} - -bool FlipperFileCpp::read_hex_array(const char* key, uint8_t* data, const uint16_t data_size) { - return flipper_file_read_hex_array(file, key, data, data_size); -} diff --git a/lib/toolbox/flipper-file-cpp.h b/lib/toolbox/flipper-file-cpp.h deleted file mode 100644 index bac19cba..00000000 --- a/lib/toolbox/flipper-file-cpp.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include "flipper-file.h" - -class FlipperFileCpp { -private: - FlipperFile* file; - -public: - FlipperFileCpp(Storage* storage); - ~FlipperFileCpp(); - - bool open_read(const char* filename); - - bool new_write(const char* filename); - - bool close(); - - bool read_header(string_t filetype, uint32_t* version); - - bool write_header(string_t filetype, const uint32_t version); - - bool write_header_cstr(const char* filetype, const uint32_t version); - - bool read_string(const char* key, string_t data); - - bool write_string(const char* key, string_t data); - - bool write_string_cstr(const char* key, const char* data); - - bool read_uint32(const char* key, uint32_t* data); - - bool write_uint32(const char* key, const uint32_t data); - - bool write_comment(string_t data); - - bool write_comment_cstr(const char* data); - - bool write_hex_array(const char* key, const uint8_t* data, const uint16_t data_size); - - bool read_hex_array(const char* key, uint8_t* data, const uint16_t data_size); -}; diff --git a/lib/toolbox/flipper-file.c b/lib/toolbox/flipper-file.c deleted file mode 100644 index e16cd868..00000000 --- a/lib/toolbox/flipper-file.c +++ /dev/null @@ -1,464 +0,0 @@ -#include -#include "flipper-file.h" -#include -#include - -struct FlipperFile { - File* file; -}; - -const char* flipper_file_filetype_key = "Filetype"; -const char* flipper_file_version_key = "Version"; -const char flipper_file_eoln = '\n'; -const char flipper_file_eolr = '\r'; -const char flipper_file_delimiter = ':'; -const char flipper_file_comment = '#'; - -/** - * Writes data to a file as a hexadecimal array. - * @param file - * @param data - * @param data_size - * @return true on success write - */ -bool flipper_file_write_hex_internal(File* file, const uint8_t* data, const uint16_t data_size) { - const uint8_t byte_text_size = 3; - char byte_text[byte_text_size]; - - bool result = true; - uint16_t bytes_written; - for(uint8_t i = 0; i < data_size; i++) { - snprintf(byte_text, byte_text_size, "%02X", data[i]); - - if(i != 0) { - // space - const char space = ' '; - bytes_written = storage_file_write(file, &space, sizeof(space)); - if(bytes_written != sizeof(space)) { - result = false; - break; - } - } - - bytes_written = storage_file_write(file, &byte_text, strlen(byte_text)); - if(bytes_written != strlen(byte_text)) { - result = false; - break; - } - } - - return result; -} - -/** - * Reads a valid key from a file as a string. - * After reading, the rw pointer will be on the flipper_file_delimiter symbol. - * Optimized not to read comments and values into RAM. - * @param file - * @param key - * @return true on success read - */ -bool flipper_file_read_valid_key(File* file, string_t key) { - string_clean(key); - bool found = false; - bool error = false; - const uint8_t buffer_size = 32; - uint8_t buffer[buffer_size]; - bool accumulate = true; - bool new_line = true; - - while(true) { - uint16_t bytes_were_read = storage_file_read(file, buffer, buffer_size); - if(bytes_were_read == 0) break; - - for(uint16_t i = 0; i < bytes_were_read; i++) { - if(buffer[i] == flipper_file_eoln) { - // EOL found, clean data, start accumulating data and set the new_line flag - string_clean(key); - accumulate = true; - new_line = true; - } else if(buffer[i] == flipper_file_eolr) { - // Ignore - } else if(buffer[i] == flipper_file_comment && new_line) { - // if there is a comment character and we are at the beginning of a new line - // do not accumulate comment data and reset the new_line flag - accumulate = false; - new_line = false; - } else if(buffer[i] == flipper_file_delimiter) { - if(new_line) { - // we are on a "new line" and found the delimiter - // this can only be if we have previously found some kind of key, so - // clear the data, set the flag that we no longer want to accumulate data - // and reset the new_line flag - string_clean(key); - accumulate = false; - new_line = false; - } else { - // parse the delimiter only if we are accumulating data - if(accumulate) { - // we found the delimiter, move the rw pointer to the correct location - // and signal that we have found something - // TODO negative seek - uint64_t position = storage_file_tell(file); - position = position - bytes_were_read + i; - if(!storage_file_seek(file, position, true)) { - error = true; - break; - } - - found = true; - break; - } - } - } else { - // just new symbol, reset the new_line flag - new_line = false; - if(accumulate) { - // and accumulate data if we want - string_push_back(key, buffer[i]); - } - } - } - - if(found || error) break; - } - - return found; -} - -/** - * Sets rw pointer to the data after the key - * @param file - * @param key - * @return true if key was found - */ -bool flipper_file_seek_to_key(File* file, const char* key) { - bool found = false; - string_t readed_key; - - string_init(readed_key); - - // TODO optimize this to search from a stored rw pointer - if(storage_file_seek(file, 0, true)) { - while(!storage_file_eof(file)) { - if(flipper_file_read_valid_key(file, readed_key)) { - if(string_cmp_str(readed_key, key) == 0) { - uint64_t position = storage_file_tell(file); - if(!storage_file_seek(file, position + 2, true)) break; - - found = true; - break; - } - } - } - } - string_clear(readed_key); - - return found; -} - -/** - * Reads data as a string from the stored rw pointer to the \r or \n symbol position - * @param file - * @param str_result - * @return true on success read - */ -bool flipper_file_read_until(File* file, string_t str_result) { - string_clean(str_result); - const uint8_t buffer_size = 32; - uint8_t buffer[buffer_size]; - - do { - uint16_t bytes_were_read = storage_file_read(file, buffer, buffer_size); - if(bytes_were_read == 0) break; - - bool result = false; - bool error = false; - for(uint16_t i = 0; i < bytes_were_read; i++) { - if(buffer[i] == flipper_file_eoln) { - // TODO negative seek - uint64_t position = storage_file_tell(file); - position = position - bytes_were_read + i; - if(!storage_file_seek(file, position, true)) { - error = true; - break; - } - - result = true; - break; - } else if(buffer[i] == flipper_file_eolr) { - // Ignore - } else { - string_push_back(str_result, buffer[i]); - } - } - - if(result || error) { - break; - } - } while(true); - - return string_size(str_result) != 0; -} - -/** - * Reads single hexadecimal data from a file to byte - * @param file - * @param byte - * @return bool - */ -bool flipper_file_read_hex_byte(File* file, uint8_t* byte) { - uint8_t hi_nibble_value, low_nibble_value; - uint8_t text[3]; - bool result = false; - - uint16_t bytes_were_read = storage_file_read(file, text, 3); - if(bytes_were_read >= 2) { - if(text[0] != ' ') { - if(hex_char_to_hex_nibble(text[0], &hi_nibble_value) && - hex_char_to_hex_nibble(text[1], &low_nibble_value)) { - *byte = (hi_nibble_value << 4) | low_nibble_value; - result = true; - } - } else { - if(hex_char_to_hex_nibble(text[1], &hi_nibble_value) && - hex_char_to_hex_nibble(text[2], &low_nibble_value)) { - *byte = (hi_nibble_value << 4) | low_nibble_value; - result = true; - } - } - } - - return result; -} - -FlipperFile* flipper_file_alloc(Storage* storage) { - FlipperFile* flipper_file = malloc(sizeof(FlipperFile)); - flipper_file->file = storage_file_alloc(storage); - return flipper_file; -} - -void flipper_file_free(FlipperFile* flipper_file) { - furi_assert(flipper_file); - if(storage_file_is_open(flipper_file->file)) { - storage_file_close(flipper_file->file); - } - storage_file_free(flipper_file->file); - free(flipper_file); -} - -bool flipper_file_open_read(FlipperFile* flipper_file, const char* filename) { - furi_assert(flipper_file); - bool result = storage_file_open(flipper_file->file, filename, FSAM_READ, FSOM_OPEN_EXISTING); - return result; -} - -bool flipper_file_new_write(FlipperFile* flipper_file, const char* filename) { - furi_assert(flipper_file); - bool result = storage_file_open(flipper_file->file, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS); - return result; -} - -bool flipper_file_close(FlipperFile* flipper_file) { - furi_assert(flipper_file); - if(storage_file_is_open(flipper_file->file)) { - return storage_file_close(flipper_file->file); - } - return true; -} - -bool flipper_file_read_header(FlipperFile* flipper_file, string_t filetype, uint32_t* version) { - bool result = false; - do { - result = flipper_file_read_string(flipper_file, flipper_file_filetype_key, filetype); - if(!result) break; - result = flipper_file_read_uint32(flipper_file, flipper_file_version_key, version); - if(!result) break; - } while(false); - - return result; -} - -bool flipper_file_write_header( - FlipperFile* flipper_file, - string_t filetype, - const uint32_t version) { - bool result = false; - do { - result = flipper_file_write_string(flipper_file, flipper_file_filetype_key, filetype); - if(!result) break; - result = flipper_file_write_uint32(flipper_file, flipper_file_version_key, version); - if(!result) break; - } while(false); - - return result; -} - -bool flipper_file_write_header_cstr( - FlipperFile* flipper_file, - const char* filetype, - const uint32_t version) { - bool result = false; - string_t value; - string_init_set(value, filetype); - result = flipper_file_write_header(flipper_file, value, version); - string_clear(value); - return result; -} - -bool flipper_file_read_string(FlipperFile* flipper_file, const char* key, string_t data) { - furi_assert(flipper_file); - - bool result = false; - if(flipper_file_seek_to_key(flipper_file->file, key)) { - if(flipper_file_read_until(flipper_file->file, data)) { - result = true; - } - } - return result; -} - -bool flipper_file_write_string(FlipperFile* flipper_file, const char* key, string_t data) { - furi_assert(flipper_file); - - bool result = false; - do { - uint16_t bytes_written; - bytes_written = storage_file_write(flipper_file->file, key, strlen(key)); - if(bytes_written != strlen(key)) break; - - const char delimiter_buffer[2] = {flipper_file_delimiter, ' '}; - bytes_written = - storage_file_write(flipper_file->file, delimiter_buffer, sizeof(delimiter_buffer)); - if(bytes_written != sizeof(delimiter_buffer)) break; - - bytes_written = - storage_file_write(flipper_file->file, string_get_cstr(data), string_size(data)); - if(bytes_written != string_size(data)) break; - - bytes_written = - storage_file_write(flipper_file->file, &flipper_file_eoln, sizeof(flipper_file_eoln)); - if(bytes_written != sizeof(flipper_file_eoln)) break; - - result = true; - } while(false); - - return result; -} - -bool flipper_file_write_string_cstr(FlipperFile* flipper_file, const char* key, const char* data) { - bool result = false; - string_t value; - string_init_set(value, data); - result = flipper_file_write_string(flipper_file, key, value); - string_clear(value); - return result; -} - -bool flipper_file_read_uint32(FlipperFile* flipper_file, const char* key, uint32_t* data) { - bool result = false; - string_t value; - string_init(value); - - result = flipper_file_read_string(flipper_file, key, value); - if(result) { - int ret = sscanf(string_get_cstr(value), "%" PRIu32, data); - if(ret != 1) result = false; - } - - string_clear(value); - return result; -} - -bool flipper_file_write_uint32(FlipperFile* flipper_file, const char* key, const uint32_t data) { - bool result = false; - string_t value; - string_init_printf(value, "%" PRIu32, data); - result = flipper_file_write_string(flipper_file, key, value); - string_clear(value); - return result; -} - -bool flipper_file_write_comment(FlipperFile* flipper_file, string_t data) { - furi_assert(flipper_file); - - bool result = false; - do { - uint16_t bytes_written; - const char comment_buffer[2] = {flipper_file_comment, ' '}; - bytes_written = - storage_file_write(flipper_file->file, comment_buffer, sizeof(comment_buffer)); - if(bytes_written != sizeof(comment_buffer)) break; - - bytes_written = - storage_file_write(flipper_file->file, string_get_cstr(data), string_size(data)); - if(bytes_written != string_size(data)) break; - - bytes_written = - storage_file_write(flipper_file->file, &flipper_file_eoln, sizeof(flipper_file_eoln)); - if(bytes_written != sizeof(flipper_file_eoln)) break; - - result = true; - } while(false); - - return result; -} - -bool flipper_file_write_comment_cstr(FlipperFile* flipper_file, const char* data) { - bool result = false; - string_t value; - string_init_set(value, data); - result = flipper_file_write_comment(flipper_file, value); - string_clear(value); - return result; -} - -bool flipper_file_write_hex_array( - FlipperFile* flipper_file, - const char* key, - const uint8_t* data, - const uint16_t data_size) { - furi_assert(flipper_file); - - bool result = false; - do { - uint16_t bytes_written; - bytes_written = storage_file_write(flipper_file->file, key, strlen(key)); - if(bytes_written != strlen(key)) break; - - const char delimiter_buffer[2] = {flipper_file_delimiter, ' '}; - bytes_written = - storage_file_write(flipper_file->file, delimiter_buffer, sizeof(delimiter_buffer)); - if(bytes_written != sizeof(delimiter_buffer)) break; - - if(!flipper_file_write_hex_internal(flipper_file->file, data, data_size)) break; - - bytes_written = - storage_file_write(flipper_file->file, &flipper_file_eoln, sizeof(flipper_file_eoln)); - if(bytes_written != sizeof(flipper_file_eoln)) break; - - result = true; - } while(false); - - return result; -} - -bool flipper_file_read_hex_array( - FlipperFile* flipper_file, - const char* key, - uint8_t* data, - const uint16_t data_size) { - furi_assert(flipper_file); - - bool result = false; - if(flipper_file_seek_to_key(flipper_file->file, key)) { - result = true; - for(uint16_t i = 0; i < data_size; i++) { - if(!flipper_file_read_hex_byte(flipper_file->file, &data[i])) { - result = false; - break; - } - } - } - return result; -} \ No newline at end of file diff --git a/lib/toolbox/hex.c b/lib/toolbox/hex.c index cc869beb..8b443e12 100644 --- a/lib/toolbox/hex.c +++ b/lib/toolbox/hex.c @@ -13,4 +13,16 @@ bool hex_char_to_hex_nibble(char c, uint8_t* nibble) { } else { return false; } +} + +bool hex_chars_to_uint8(char hi, char low, uint8_t* value) { + uint8_t hi_nibble_value, low_nibble_value; + + if(hex_char_to_hex_nibble(hi, &hi_nibble_value) && + hex_char_to_hex_nibble(low, &low_nibble_value)) { + *value = (hi_nibble_value << 4) | low_nibble_value; + return true; + } else { + return false; + } } \ No newline at end of file diff --git a/lib/toolbox/hex.h b/lib/toolbox/hex.h index 2c5d8404..ac67549a 100644 --- a/lib/toolbox/hex.h +++ b/lib/toolbox/hex.h @@ -7,14 +7,22 @@ extern "C" { #endif /** - * @brief Convert ASCII hex value to nibble - * + * Convert ASCII hex value to nibble * @param c ASCII character * @param nibble nibble pointer, output * @return bool conversion status */ bool hex_char_to_hex_nibble(char c, uint8_t* nibble); +/** + * Convert ASCII hex values to byte + * @param hi hi nibble text + * @param low low nibble text + * @param value output value + * @return bool conversion status + */ +bool hex_chars_to_uint8(char hi, char low, uint8_t* value); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/toolbox/saved_struct.c b/lib/toolbox/saved_struct.c new file mode 100644 index 00000000..61b5bdc6 --- /dev/null +++ b/lib/toolbox/saved_struct.c @@ -0,0 +1,149 @@ +#include "saved_struct.h" +#include +#include +#include + +#define SAVED_STRUCT_TAG "SAVED_STRUCT" + +typedef struct { + uint8_t magic; + uint8_t version; + uint8_t checksum; + uint8_t flags; + uint32_t timestamp; +} SavedStructHeader; + +bool saved_struct_save(const char* path, + void* data, + size_t size, + uint8_t magic, + uint8_t version) { + furi_assert(path); + furi_assert(data); + furi_assert(size); + SavedStructHeader header; + + FURI_LOG_I(SAVED_STRUCT_TAG, "Saving \"%s\"", path); + + // Store + Storage* storage = furi_record_open("storage"); + File* file = storage_file_alloc(storage); + bool result = true; + bool saved = storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS); + if(!saved) { + FURI_LOG_E( + SAVED_STRUCT_TAG, + "Open failed \"%s\". Error: \'%s\'", + path, + storage_file_get_error_desc(file)); + result = false; + } + + if(result) { + // Calculate checksum + uint8_t checksum = 0; + uint8_t* source = data; + for(size_t i = 0; i < size; i++) { + checksum += source[i]; + } + // Set header + header.magic = magic; + header.version = version; + header.checksum = checksum; + header.flags = 0; + header.timestamp = 0; + + uint16_t bytes_count = storage_file_write(file, &header, sizeof(header)); + bytes_count += storage_file_write(file, data, size); + + if(bytes_count != (size + sizeof(header))) { + FURI_LOG_E( + SAVED_STRUCT_TAG, + "Write failed \"%s\". Error: \'%s\'", + path, + storage_file_get_error_desc(file)); + result = false; + } + } + + storage_file_close(file); + storage_file_free(file); + furi_record_close("storage"); + return result; +} + +bool saved_struct_load(const char* path, + void* data, + size_t size, + uint8_t magic, + uint8_t version) { + FURI_LOG_I(SAVED_STRUCT_TAG, "Loading \"%s\"", path); + + SavedStructHeader header; + + uint8_t* data_read = furi_alloc(size); + Storage* storage = furi_record_open("storage"); + File* file = storage_file_alloc(storage); + bool result = true; + bool loaded = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); + if (!loaded) { + FURI_LOG_E( + SAVED_STRUCT_TAG, + "Failed to read \"%s\". Error: %s", + path, + storage_file_get_error_desc(file)); + result = false; + } + + if (result) { + uint16_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); + bytes_count += storage_file_read(file, data_read, size); + + if(bytes_count != (sizeof(SavedStructHeader) + size)) { + FURI_LOG_E(SAVED_STRUCT_TAG, "Size mismatch of file \"%s\"", path); + result = false; + } + } + + if(result && (header.magic != magic || header.version != version)) { + FURI_LOG_E( + SAVED_STRUCT_TAG, + "Magic(%d != %d) or Version(%d != %d) mismatch of file \"%s\"", + header.magic, + magic, + header.version, + version, + path); + result = false; + } + + if(result) { + uint8_t checksum = 0; + const uint8_t* source = (const uint8_t*)data_read; + for(size_t i = 0; i < size; i++) { + checksum += source[i]; + } + + if(header.checksum != checksum) { + FURI_LOG_E( + SAVED_STRUCT_TAG, + "Checksum(%d != %d) mismatch of file \"%s\"", + header.checksum, + checksum, + path); + result = false; + } + } + + if (result) { + memcpy(data, data_read, size); + } + + storage_file_close(file); + storage_file_free(file); + furi_record_close("storage"); + free(data_read); + + return result; +} + diff --git a/lib/toolbox/saved_struct.h b/lib/toolbox/saved_struct.h new file mode 100644 index 00000000..09b7024f --- /dev/null +++ b/lib/toolbox/saved_struct.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +bool saved_struct_load(const char* path, + void* data, + size_t size, + uint8_t magic, + uint8_t version); + +bool saved_struct_save(const char* path, + void* data, + size_t size, + uint8_t magic, + uint8_t version); + diff --git a/make/rules.mk b/make/rules.mk index 9f1402b9..831f9958 100644 --- a/make/rules.mk +++ b/make/rules.mk @@ -129,14 +129,6 @@ zz: clean zzz: clean $(MAKE) debug -FORMAT_SOURCES := $(shell find ../applications -iname "*.h" -o -iname "*.c" -o -iname "*.cpp") -FORMAT_SOURCES += $(shell find ../bootloader -iname "*.h" -o -iname "*.c" -o -iname "*.cpp") -FORMAT_SOURCES += $(shell find ../core -iname "*.h" -o -iname "*.c" -o -iname "*.cpp") - -format: - @echo "Formatting sources with clang-format" - @clang-format -style=file -i $(FORMAT_SOURCES) - generate_cscope_db: @echo "$(C_SOURCES) $(CPP_SOURCES) $(ASM_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/source.list.p @cat ~/headers.list >> $(OBJ_DIR)/source.list.p diff --git a/make/toolchain.mk b/make/toolchain.mk index 9b4f6f8e..9b7368c2 100644 --- a/make/toolchain.mk +++ b/make/toolchain.mk @@ -18,11 +18,11 @@ BIN = $(CP) -O binary -S DEBUG ?= 1 COMPACT ?= 0 ifeq ($(DEBUG), 1) -CFLAGS += -DFURI_DEBUG -DNDEBUG -DLFS_NO_ASSERT -Og -g +CFLAGS += -DFURI_DEBUG -DNDEBUG -Og -g else ifeq ($(COMPACT), 1) -CFLAGS += -DFURI_NDEBUG -DNDEBUG -DLFS_NO_ASSERT -Os +CFLAGS += -DFURI_NDEBUG -DNDEBUG -Os else -CFLAGS += -DFURI_NDEBUG -DNDEBUG -DLFS_NO_ASSERT -Og +CFLAGS += -DFURI_NDEBUG -DNDEBUG -Og endif CFLAGS += -fdata-sections -ffunction-sections -fno-math-errno -fstack-usage -MMD -MP -MF"$(@:%.o=%.d)" diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index 73799cef..53c01d8c 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -1,4 +1,5 @@ import os +import sys import serial import time import hashlib @@ -143,7 +144,7 @@ class FlipperStorage: walk_dirs = [] path = path.replace("//", "/") - self.send_and_wait_eol('storage list "' + path + '"\r') + self.send_and_wait_eol(f'storage list "{path}"\r') data = self.read.until(self.CLI_PROMPT) lines = data.split(b"\r\n") @@ -198,9 +199,7 @@ class FlipperStorage: if size == 0: break - self.send_and_wait_eol( - 'storage write_chunk "' + filename_to + '" ' + str(size) + "\r" - ) + self.send_and_wait_eol(f'storage write_chunk "{filename_to}" {size}\r') answer = self.read.until(self.CLI_EOL) if self.has_error(answer): self.last_error = self.get_error(answer) @@ -214,9 +213,8 @@ class FlipperStorage: percent = str(math.ceil(file.tell() / filesize * 100)) total_chunks = str(math.ceil(filesize / buffer_size)) current_chunk = str(math.ceil(file.tell() / buffer_size)) - print( - percent + "%, chunk " + current_chunk + " of " + total_chunks, end="\r" - ) + sys.stdout.write(f"\r{percent}%, chunk {current_chunk} of {total_chunks}") + sys.stdout.flush() file.close() print() return True @@ -246,9 +244,8 @@ class FlipperStorage: percent = str(math.ceil(readed_size / size * 100)) total_chunks = str(math.ceil(size / buffer_size)) current_chunk = str(math.ceil(readed_size / buffer_size)) - print( - percent + "%, chunk " + current_chunk + " of " + total_chunks, end="\r" - ) + sys.stdout.write(f"\r{percent}%, chunk {current_chunk} of {total_chunks}") + sys.stdout.flush() print() self.read.until(self.CLI_PROMPT) return filedata