From 6d6c89e4118c92f17a9871248fd117bb7aa6194f Mon Sep 17 00:00:00 2001 From: mikecarper Date: Fri, 28 Aug 2026 16:36:34 -0700 Subject: [PATCH] fix: harden ESP-NOW and full companion networking Add selectable shared ESP-NOW channels, raw/wrapped bridge compatibility, and bounded fragmentation for maximum-size packets.\n\nGive ESP32 Full profiles WiFi coexistence, stabilize WebConfig and USB terminal lifecycles, and keep disabled bridges stopped during observer updates.\n\nUpdate generated UI, firmware selection, documentation, and regression coverage. --- build.sh | 39 + docs/WiFi.md | 99 +- docs/_javascript/firmware_picker.js | 51 +- docs/cli_command_availability.md | 3 + docs/cli_commands.md | 106 +- docs/companion_protocol.md | 14 +- docs/companion_radio_full.md | 53 +- docs/firmware_picker.md | 12 + docs/terminal_chat_cli.md | 25 +- examples/companion_radio/CompanionWiFi.h | 6 +- examples/companion_radio/MyMesh.cpp | 90 +- examples/companion_radio/MyMesh.h | 5 + examples/companion_radio/main.cpp | 166 +- examples/simple_repeater/MyMesh.cpp | 10 +- examples/simple_repeater/MyMesh.h | 28 +- examples/simple_room_server/MyMesh.cpp | 6 +- examples/simple_room_server/MyMesh.h | 19 +- mesh-america/update-provider-release.py | 79 +- platformio.ini | 8 +- scripts/generate_webconfig_html.py | 46 +- scripts/webconfig_cli_audit.py | 2 + scripts/webconfig_mock_server.py | 23 +- src/helpers/CLICommandUtils.h | 26 +- src/helpers/CommonCLI.cpp | 129 +- src/helpers/CommonCLI.h | 14 +- src/helpers/CommonCLI_Observer.cpp | 54 +- src/helpers/ESPNowRawFragmentation.h | 385 ++ src/helpers/UsbAsciiBinarySwitch.h | 27 + src/helpers/WebConfigBatch.h | 13 +- src/helpers/WebConfigKeys.h | 10 +- src/helpers/WiFiChannelPolicy.h | 46 + src/helpers/WiFiPowerSave.h | 10 +- src/helpers/WiFiSetupPortal.cpp | 66 +- src/helpers/bridges/ESPNowBridge.cpp | 432 +- src/helpers/bridges/ESPNowBridge.h | 103 +- src/helpers/bridges/ESPNowBridgeFormat.h | 80 + src/helpers/bridges/MQTTBridge.cpp | 29 +- src/helpers/esp32/ESPNOWRadio.cpp | 252 +- src/helpers/esp32/WebConfigHtml.h | 3676 +++++++++-------- src/helpers/esp32/WebConfigServer.cpp | 324 +- src/helpers/esp32/WebConfigServer.h | 5 +- src/helpers/esp32/WiFiRadioPolicy.h | 130 + src/helpers/esp32/WiFiStationPolicy.h | 93 + test/README.md | 11 +- test/test_build_profiles.sh | 83 + .../test_cli_command_utils.cpp | 173 +- .../test_config_serializer.cpp | 36 + .../test_espnow_raw_fragmentation.cpp | 458 ++ test/test_firmware_picker.js | 83 + .../test_serial_mode_switch.cpp | 33 + .../test_webconfig_batch.cpp | 25 +- .../test_webconfig_keys.cpp | 10 + tools/mota/test_mota.py | 164 +- variants/generic_espnow/platformio.ini | 3 + .../sensecap_indicator-espnow/platformio.ini | 2 + webui/index.html | 63 +- 56 files changed, 5783 insertions(+), 2155 deletions(-) create mode 100644 src/helpers/ESPNowRawFragmentation.h create mode 100644 src/helpers/WiFiChannelPolicy.h create mode 100644 src/helpers/bridges/ESPNowBridgeFormat.h create mode 100644 src/helpers/esp32/WiFiRadioPolicy.h create mode 100644 src/helpers/esp32/WiFiStationPolicy.h create mode 100644 test/test_espnow_raw_fragmentation/test_espnow_raw_fragmentation.cpp diff --git a/build.sh b/build.sh index 0443bb15..78a5d40a 100755 --- a/build.sh +++ b/build.sh @@ -2884,6 +2884,32 @@ apply_esp32_full_size_profile() { fi } +apply_esp32_full_async_tcp_profile() { + local env_name=$1 + + if [ "${PIO_ENV_PLATFORM_BY_NAME[$env_name]:-}" != "ESP32_PLATFORM" ] \ + || { [ "$ESP32_FULL_BUILD" != "1" ] \ + && ! is_esp32_companion_radio_full_target "$env_name"; }; then + return 0 + fi + + # AsyncTCP 3.x defaults to a 16 KiB task stack. A feature-complete image can + # have less than that as one contiguous internal-DRAM block by the time its + # WebConfig server starts, even when total/PSRAM capacity remains plentiful. + # Use the library's documented 4 KiB reduced configuration. Eight KiB let + # the task start on the most constrained measured Full Companion, but left + # too little internal heap to retire successive HTTP responses reliably. + # Pin its event/callback task to the application core as recommended by the + # library. Leaving it on the WiFi/Bluetooth core lets a long response to a + # lossy client starve the shared radio until even ARP recovery fails. + # Also disable ESPAsyncWebServer's optional 2-MSS in-flight gate. A slow peer + # can acknowledge one MSS at a time; after a fixed response crosses the TCP + # window the gate then waits forever for two MSS of space. WebConfig's + # response fillers are fast flash/memory copies, and the TCP send buffer still + # provides back-pressure without that gate. + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DCONFIG_ASYNC_TCP_STACK_SIZE=4096 -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 -DASYNCWEBSERVER_USE_CHUNK_INFLIGHT=0" +} + apply_repeater_neighbor_capacity() { local env_name=$1 local max_neighbours=$REPEATER_MAX_NEIGHBOURS @@ -3208,6 +3234,18 @@ apply_companion_radio_full_profile() { # mode when WiFi is unavailable and serve the same folder protocol there. export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DWIFI_OTA_SEEDER=1 -DCOMPANION_FEATURE_NETWORK_TERMINAL=1 -DCOMPANION_FEATURE_MEMORY_DIAGNOSTICS=1" + # ESP-NOW is the primary mesh radio on these two layouts, so conventional + # Companion WiFi must share its protocol mask and fixed channel instead of + # resetting the driver to B/G/N on an arbitrary access-point channel. The + # runtime policy keeps B/G/N enabled for phones and normal routers while LR + # remains available for the mesh packets. + case "${env_name,,}" in + generic_espnow_companion_radio_full|\ + sensecapindicator-espnow_companion_radio_full) + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DMESH_ESPNOW_RADIO=1 -DMESH_ESPNOW_CHANNEL=1" + ;; + esac + # Qualified BLE-based Full recipes did not previously need WiFi credentials. # Supply the same first-boot setup placeholders used by ordinary WiFi # Companion recipes; saved credentials and WebConfig replace them at runtime. @@ -3689,6 +3727,7 @@ build_firmware() { apply_esp32_lora_ota_size_profile "$env_name" apply_esp32_constrained_companion_size_profile "$env_name" apply_esp32_full_size_profile "$env_name" + apply_esp32_full_async_tcp_profile "$env_name" apply_repeater_neighbor_capacity "$env_name" apply_nrf52_size_profile "$env_name" apply_lora_ota_no_external_sensors_profile "$env_name" diff --git a/docs/WiFi.md b/docs/WiFi.md index 45b0650d..ae0db3d4 100644 --- a/docs/WiFi.md +++ b/docs/WiFi.md @@ -27,7 +27,7 @@ to MQTT unless its target name also contains `mqtt`. | `*_companion_radio_wifi` | Yes | No | Exposes the MeshCore companion protocol on TCP port 5000 | | `*_companion_radio_wifi_mqtt` | Yes | Yes | Runs both the TCP companion interface and the MQTT uplink | | USB, BLE, or serial companion | No | No | Uses the transport named by the target instead | -| `*_repeater_bridge_espnow` | Build-dependent on ESP32 | No | Uses ESP-NOW for its bridge; a FULL build also exposes the TCP 5001 LoRa-OTA seeder whenever WiFi is usable | +| `*_repeater_bridge_espnow` | Build-dependent on ESP32 | No | Uses ESP-NOW for its bridge; `bridge.format wrapped|raw` selects legacy bridge framing or primary-ESP-NOW compatibility; a FULL build also exposes the TCP 5001 LoRa-OTA seeder whenever WiFi is usable | | RS232 bridge | No | No | Bridges through a serial interface | | Ethernet repeater/room server | No WiFi | No | Uses wired Ethernet for its role-specific network interface | | `*_sensor` | Build-dependent on ESP32 | No | A FULL ESP32 sensor can expose the TCP 5001 LoRa-OTA seeder through its browser-OTA setup AP | @@ -227,7 +227,71 @@ set wifi.pwd your-password Credential writes are persisted immediately. After the reply has drained, the Companion restarts its WiFi station with the saved pair. A port-5002 client is expected to disconnect and can reconnect at the new LAN IP. USB masks the -password as it is entered; `get wifi.pwd` is intentionally unavailable. +password as it is entered; `get wifi.pwd` is intentionally unavailable. The +standalone credential store accepts an empty password, ordinary passphrases up +to 63 characters, or an exact 64-character hexadecimal WPA/WPA2 PSK. A +non-hexadecimal 64-character value and every longer value are rejected. + +On Full Companion targets whose primary mesh radio is ESP-NOW, ESP-NOW, the +setup AP, and the infrastructure-WiFi station must share one 2.4 GHz channel. +The persisted channel defaults to 1 and can be inspected or changed from the +text terminal: + +```text +get espnow.channel +set espnow.channel 6 +reboot +``` + +Valid values are 1 through 13; use only a channel permitted in your region and +supported by the router. `set espnow.channel` saves the new value but does not +move the running radio; reboot the node to apply it. Every primary +ESP-NOW node that should communicate with it must use the same channel, and +the configured router's 2.4 GHz radio must be fixed to that channel as well. +A router left on automatic channel selection can move the infrastructure +connection away from the ESP-NOW mesh. + +`espnow.channel` configures the node's primary ESP-NOW mesh radio. It is +distinct from `bridge.channel`, which applies only to the separate ESP-NOW +bridge feature. WiFi power saving does not let ESP-NOW and infrastructure WiFi +operate on different channels. On an ESP32 Full build whose primary radio is +ESP-NOW, `wifi.powersave max` is unavailable because a station using maximum +modem sleep can miss ESP-NOW broadcasts; use `min` for coexistence. + +ESP-NOW compatibility also depends on the bytes and PHY used above the common +Espressif transport. The historical `*_repeater_bridge_espnow` firmware wraps +each MeshCore packet with a magic value, checksum, and secret-based XOR, while +`Generic_ESPNOW` and `SenseCapIndicator-ESPNow` send the serialized MeshCore +packet directly using the ESP-NOW LR PHY. Updated bridge firmware can select +either behavior without changing the board target: + +```text +get bridge.format +set bridge.channel 1 +set bridge.format raw +``` + +On a Heltec V4, the ordinary `companion_radio_full` image remains a +LoRa-primary Companion and does not instantiate this bridge. Select and flash +the existing `heltec_v4_repeater_bridge_espnow` role before using these +commands. Treat that Companion-to-repeater change as a role/partition +migration: back up the node and use the exact V4 merged install artifact. + +`wrapped` remains the default and interoperates with existing bridge nodes +that use the same channel and `bridge.secret`. `raw` interoperates with +primary-ESP-NOW nodes and other raw bridges; it requires channel 1-13, enables +LR reception, forces LR transmission, and ignores `bridge.secret`. Receive +parsing is strict to the selected format, so migrate peers deliberately rather +than expecting one bridge to accept both. Match `bridge.channel` on the LoRa +gateway to the primary nodes' `espnow.channel`; a primary-node channel change +takes effect after its reboot. + +Raw mode retains MeshCore's normal packet parsing, authentication/encryption, +and the bridge's duplicate suppression, but it does not provide the wrapper's +secret-based network isolation. That XOR wrapper is itself only lightweight +isolation, not cryptographic security. Multiple LoRa/ESP-NOW gateways covering +the same nodes can temporarily amplify duplicates, even though seen-packet +tracking prevents an individual bridge from immediately echoing a packet back. If the configured network remains unavailable for two minutes, the companion opens its setup AP so the credentials can be repaired. It continues retrying @@ -237,11 +301,16 @@ WiFi card in Companion WebConfig exposes `none`, `min`, and `max`. Fresh Cascade-profile builds select `min`; target-default builds select `none`. A saved setting takes precedence after an upgrade. -WiFi-only Companions can use all three modes. A Full Companion also runs BLE, -so ESP32 WiFi/Bluetooth coexistence requires at least minimum modem sleep. It +WiFi-only Companions can use all three modes. Full Companion also runs BLE, so +ESP32 WiFi/Bluetooth coexistence requires at least minimum modem sleep. It reports `min` when an old or target-default `none` value is found and rejects a -new `none` selection while Bluetooth is compiled in. Device power saving can -therefore be turned on or off without changing the selected WiFi modem policy. +new `none` selection while Bluetooth is compiled in. When ESP-NOW is also the +Full Companion's primary mesh radio, `max` is unavailable: the access point does +not buffer ESP-NOW broadcasts for a sleeping station, so maximum modem sleep can +lose them. Firmware caps a previously saved `max` value to and reports it as +`min`, and rejects a new `max` selection. Thus a WiFi/BLE/primary-ESP-NOW Full +Companion uses `min`. Device power saving can still be turned on or off without +changing the selected WiFi modem policy. WiFi companions do not have the repeater/room-server admin CLI password model, so their LAN WebConfig page is intentionally unauthenticated. Use them only on @@ -372,7 +441,10 @@ connect temporarily. Standalone credentials can be changed through WebConfig or with the listed CLI commands. Changing the SSID or password stops an active WebConfig session; start it again to connect with the new values. Use `set wifi.pwd` with no value for an open network. The password is write-only -and is never returned by `get`. +and is never returned by `get`. Standalone WiFi accepts ordinary passphrases up +to 63 characters and exact 64-character hexadecimal WPA/WPA2 PSKs; other +64-character values and all longer values are rejected. MQTT observer WiFi +passwords remain limited to 63 characters by their fixed persisted layout. `get webui` starts with the saved boot setting, then reports the current session. For example, `> off, http://192.168.1.130/` means automatic WebConfig @@ -475,7 +547,13 @@ card and USB text terminal. Full Companion also accepts the text commands from TCP port 5002. The normal binary Companion protocol can read or write the setting over USB, BLE, or TCP port 5000 without entering terminal mode. Full Companion rejects `none` because its simultaneous BLE transport requires WiFi -modem sleep. +modem sleep. An ESP32 Full Companion whose primary mesh radio is ESP-NOW also +rejects `max`; maximum +modem sleep can cause the station to miss ESP-NOW broadcasts because the access +point does not buffer them. A previously saved `max` value is capped to and +reported as `min`. Such a primary-ESP-NOW Full Companion therefore uses `min`. +ESP-NOW and +infrastructure WiFi still must use the same fixed channel. MQTT observer targets normally limit ESP32 WiFi transmit power to 11 dBm unless the board configuration overrides `MQTT_WIFI_TX_POWER`. This setting affects @@ -531,5 +609,8 @@ For a WiFi companion, find its station IP in the router, connect the client to TCP port 5000, and use the open `MeshCore-Setup-XXXX` AP at `http://192.168.4.1/` if it cannot join the saved network. Current firmware normalizes both ESP32 WiFi interfaces to standard b/g/n before advertising the -setup AP, including after an ESP-NOW image used its long-range protocol mode. +setup AP. Full Companion targets whose primary mesh radio is ESP-NOW use +b/g/n+LR instead and keep the setup AP, infrastructure station, and mesh on the +persisted `espnow.channel` (channel 1 by default). Their configured 2.4 GHz +router and every other primary ESP-NOW node must use that same channel. MQTT diagnostics apply only to a `wifi_mqtt` companion target. diff --git a/docs/_javascript/firmware_picker.js b/docs/_javascript/firmware_picker.js index 1ae0791a..483726a8 100644 --- a/docs/_javascript/firmware_picker.js +++ b/docs/_javascript/firmware_picker.js @@ -294,7 +294,7 @@ let value = String(tail); if (role === "companion") { value = value.replace( - /^(?:full|usb_ble|ble|usb|wifi|serial|ethernet)(?=$|[_-])/i, + /^(?:full|wifi_mqtt|usb_ble|usb_wifi|ble|usb|wifi|serial|ethernet)(?=$|[_-])/i, " " ); // Power saving and controllable FEM gain are persisted settings. Legacy @@ -330,7 +330,9 @@ ? "runtime" : fullLoggingFallback ? "usb-runtime" - : lowerTarget.includes("observer_mqtt") + : lowerTarget.includes("observer_mqtt") || + (parts.role === "companion" && + /(?:^|[_-])wifi_mqtt(?=$|[_-])/.test(lowerTail)) ? "wifi" : lowerTarget.includes("-logging") ? "usb" @@ -388,9 +390,17 @@ if (!profile || profile.role !== "companion" || profile.mode !== "full") { return false; } - // Native nRF52 Serial DFU packages use .zip. ESP32 Full Companion always - // has one USB TTY and never receives the dedicated-port capability. - return profile.installKinds.includes("zip"); + const installKinds = Array.isArray(profile.installKinds) + ? profile.installKinds + : []; + // Native nRF52 releases normally publish both Serial DFU ZIP and UF2. + // Treat a UF2-only Full profile as nRF52 too so an incomplete release page + // does not mislabel it as an ESP32 single-TTY image. ESP32 Full profiles + // always publish BIN assets. + return installKinds.includes("zip") || + (installKinds.includes("uf2") && + !installKinds.includes("bin") && + !installKinds.includes("merged-bin")); } function isFullCompanion(profile) { @@ -398,28 +408,31 @@ profile.mode === "full"); } + function replacementKey(profile) { + let hardware = String(profile && profile.hardware || "").toLowerCase(); + // The generated base V4 Full image auto-detects both V4.2 and V4.3 FEMs. + // Older V4.3 transport artifacts therefore have the same physical + // replacement even though their filename hardware prefix differs. + if (hardware === "heltec_v4_3") hardware = "heltec_v4"; + return hardware + "\n" + String(profile && profile.variant || "default"); + } + function omitTransportsReplacedByFull(profiles) { const fullKeys = new Set((profiles || []).filter(function (profile) { return isFullCompanion(profile); - }).map(function (profile) { - return profile.hardware + "\n" + profile.variant; - })); + }).map(replacementKey)); const combinedUsbBleKeys = new Set((profiles || []).filter( function (profile) { return profile.role === "companion" && profile.mode === "usb-ble"; } - ).map(function (profile) { - return profile.hardware + "\n" + profile.variant; - })); + ).map(replacementKey)); const terminalReplacementKeys = new Set((profiles || []).filter( function (profile) { return profile.role === "companion" && (profile.mode === "full" || profile.mode === "usb" || profile.mode === "usb-ble"); } - ).map(function (profile) { - return profile.hardware + "\n" + profile.variant; - })); + ).map(replacementKey)); const targets = new Set((profiles || []).map(function (profile) { return String(profile.target || "").toLowerCase(); })); @@ -450,7 +463,7 @@ }; return (profiles || []).filter(function (profile) { - const key = profile.hardware + "\n" + profile.variant; + const key = replacementKey(profile); const replacedAttachedTransport = profile.role === "companion" && (profile.mode === "usb" || profile.mode === "ble" || profile.mode === "wifi" || profile.mode === "serial" || @@ -474,9 +487,10 @@ return (profiles || []).map(function (profile) { if (!isFullCompanion(profile)) return profile; - // Every Full Companion has a runtime USB logging mode. nRF52 adds an - // independent plaintext interface after reboot. Every ESP32 target - // switches its one TTY between framed and plaintext modes. + // Every Full Companion controls diagnostics with usb.logging. Some + // qualified boards also contain a direct MQTT bridge, but the Companion + // command parser does not implement the observer-only logging.output + // selector, so never advertise its off/USB/WiFi/both modes here. profile.logging = "usb-runtime"; profile.loggingModes = ["none", "usb"]; profile.dedicatedUsbLogging = false; @@ -1209,6 +1223,7 @@ facetValues: facetValues, uniqueValues: uniqueValues, canonicalAsset: canonicalAsset, + installSteps: installSteps, humanizeHardware: humanizeHardware, humanizeVariant: humanizeVariant, labelFor: labelFor, diff --git a/docs/cli_command_availability.md b/docs/cli_command_availability.md index 88cd2046..f2fc6f19 100644 --- a/docs/cli_command_availability.md +++ b/docs/cli_command_availability.md @@ -157,6 +157,7 @@ fix, no WiFi connection, an inactive bridge, or an nRF52 bootloader without | Bridge | [`get/set bridge.baud`](cli_commands.md#view-or-change-the-speed-of-the-bridge-rs-232-only) | RS-232 bridge | Feature | Feature | Feature | | Bridge | [`get/set bridge.uart`](cli_commands.md#view-or-change-the-uart-used-by-the-bridge-rs-232-only) | RS-232 bridge | Feature | Feature | Feature | | Bridge | [`get/set bridge.channel`](cli_commands.md#view-or-change-the-channel-used-for-bridging-espnow-only) | ESP-NOW is ESP32 only | No | No | No | +| Bridge | [`get/set bridge.format`](cli_commands.md#view-or-change-the-esp-now-bridge-wire-format) | ESP-NOW bridge | No | No | No | | Bridge | [`get/set bridge.secret`](cli_commands.md#set-the-esp-now-secret) | ESP-NOW is ESP32 only | No | No | No | | Board | [`get bootloader.ver`](cli_commands.md#view-the-bootloader-version-nrf52-only) | nRF52 bootloader metadata | Yes | Yes | Yes | | Board | [`get pwrmgt.support`; `get pwrmgt.source`; `get pwrmgt.bootreason`; `get pwrmgt.bootmv`](nrf52_power_management.md#cli-commands) | Board power-management implementation | Feature | Feature | Feature | @@ -243,6 +244,7 @@ fix, no WiFi connection, an inactive bridge, or an nRF52 bootloader without | Radio | [`get/set/del radioat`; `get/set/del tempradioat`](cli_commands.md#schedule-radio-parameter-changes) | Full parser | Yes | Yes | Yes | Yes | Yes | | Radio | [`get freq`; `set freq `](cli_commands.md#view-or-change-this-nodes-frequency) | `set` is local serial only | Yes | Yes | Yes | Yes | Yes | | Radio | [`get/set radio.rxgain`](cli_commands.md#view-or-change-this-nodes-rx-boosted-gain-mode-sx12xx-and-lr1110-v1141) | Supported radio | Feature | Feature | Feature | Feature | Feature | +| Radio | [`get/set espnow.channel`](cli_commands.md#view-or-change-the-primary-esp-nowwifi-channel) | Primary ESP-NOW mesh radio | Feature | Feature | Feature | Feature | Feature | | Radio | [`get/set radio.fem.rxgain`](cli_commands.md#view-or-change-the-lora-fem-receive-path-gain-state-on-supported-boards) | Controllable LoRa FEM | Feature | Feature | Feature | Feature | Feature | | Radio | [`get/set radio.fem.txgain`](cli_commands.md#view-or-change-the-lora-fem-transmit-path-gain-state-on-supported-boards) | Controllable LoRa FEM | Feature | Feature | Feature | Feature | Feature | | Radio | [`get/set radio.rxps`; `get rxps.wd`](#radio-rxps) | Full parser and RX power-saving support | Feature | Feature | Feature | Feature | Feature | @@ -321,6 +323,7 @@ fix, no WiFi connection, an inactive bridge, or an nRF52 bootloader without | Bridge | [`get/set bridge.baud`](cli_commands.md#view-or-change-the-speed-of-the-bridge-rs-232-only) | RS-232 bridge | Feature | Feature | Feature | No | Feature | | Bridge | [`get/set bridge.uart`](cli_commands.md#view-or-change-the-uart-used-by-the-bridge-rs-232-only) | RS-232 bridge | Feature | Feature | Feature | No | Feature | | Bridge | [`get/set bridge.channel`](cli_commands.md#view-or-change-the-channel-used-for-bridging-espnow-only) | ESP-NOW bridge | No | No | No | Feature | Feature | +| Bridge | [`get/set bridge.format`](cli_commands.md#view-or-change-the-esp-now-bridge-wire-format) | ESP-NOW bridge | No | No | No | Feature | Feature | | Bridge | [`get/set bridge.secret`](cli_commands.md#set-the-esp-now-secret) | ESP-NOW bridge | No | No | No | Feature | Feature | | Board | [`get bootloader.ver`](cli_commands.md#view-the-bootloader-version-nrf52-only) | nRF52 only | No | No | No | No | No | | Board | [`get pwrmgt.support`; `get pwrmgt.source`; `get pwrmgt.bootreason`; `get pwrmgt.bootmv`](nrf52_power_management.md#cli-commands) | nRF52 only | No | No | No | No | No | diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 4134a94e..b41a38ec 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -247,6 +247,10 @@ The WiFi `set` commands work on MQTT observers and on FULL standalone ESP32 repeater/room-server builds. On a standalone build, changing the SSID or password stops an active WebConfig session; run `start webconfig` again to use the new credentials. `set wifi.pwd` with no value selects an open network. +Standalone WiFi also accepts an exact 64-character hexadecimal WPA/WPA2 PSK; +ordinary passphrases remain limited to 63 characters. Other 64-character values +and all longer values are rejected. MQTT observer WiFi passwords retain their +fixed 63-character limit. Power-save changes are applied immediately when WiFi is running and otherwise take effect on the next connection. `get wifi.pwd` is intentionally unavailable so the standalone password is never returned by the CLI. @@ -260,9 +264,45 @@ restarting the WiFi station, so a TCP client should expect to reconnect at the new address; USB password input is masked. Binary Companion clients can use command bytes `0x46` and `0x47` over USB, BLE, or TCP port 5000 without the terminal-start -token. WiFi-only Companions accept all three modes; Full Companion rejects +token. WiFi-only Companions accept all three modes. Full Companion rejects `none` because its simultaneous BLE transport requires modem sleep. Companion -device `powersaving` and LoRa `radio.rxps` remain independent. +device `powersaving` and LoRa `radio.rxps` remain independent. On an ESP32 Full +Companion whose primary mesh radio is ESP-NOW, `max` is also unavailable: a +station using maximum modem sleep can miss ESP-NOW broadcasts, which the access +point does not buffer for it. A previously saved `max` value is capped to and +reported as `min`, and a new `max` selection is rejected. These +WiFi/BLE/primary-ESP-NOW builds therefore use `min`. + +#### View or change the primary ESP-NOW/WiFi channel + +**Usage:** + +- `get espnow.channel` +- `set espnow.channel ` + +**Parameters:** + +- `channel`: Shared 2.4 GHz WiFi channel from `1` through `13`; choose one + permitted in your region and supported by the router. + +**Default:** `1` + +This command is available when ESP-NOW is the node's primary mesh radio. The +setting is persisted. A `set` reply reports that reboot is required; until +reboot, the running ESP-NOW radio remains on its previous channel. On builds +that also provide ordinary WiFi, its station and setup AP share that channel. + +After reboot, ESP-NOW, the setup AP, and the infrastructure-WiFi station use +the selected channel. Every primary ESP-NOW node that must communicate with +this node, plus the configured router's 2.4 GHz radio, must use the same fixed +channel. WiFi power saving does not allow the transports to use different +channels. On an ESP32 Full build with primary ESP-NOW, `wifi.powersave max` is +unavailable because maximum modem sleep can miss ESP-NOW broadcasts; use `min` +for coexistence. + +`espnow.channel` is the channel of the primary ESP-NOW mesh transport. It is +separate from `bridge.channel`, which configures only an ESP-NOW bridge on a +firmware role whose primary mesh radio is LoRa. The browser portal is not compiled into the two 4 MB `LilyGo_TLora_V2_1_1_6_*_observer_mqtt` targets because it does not fit while @@ -648,7 +688,10 @@ frames active on interface `00`; ESP32 resumes the ordinary ASCII/Binary switcher after the logging terminal turns logging off. This setting does not change the node-storage capture controlled by `log start` and `log stop`. -Unified ESP32 FULL builds add one saved selector for both output paths: +Unified non-Companion ESP32 FULL USB+WiFi observer builds add one saved +selector for both output paths. Full Companion builds control USB diagnostics +with `usb.logging` instead; their text-command parser does not expose +`logging.output`: ```text get logging.output @@ -3490,7 +3533,60 @@ rate before running `set bridge.enabled on`. - `set bridge.channel ` **Parameters:** -- `channel`: Channel number (1-14) +- `channel`: Channel number from 1 through 13 in either format. This matches + the primary-ESP-NOW policy and the default regulatory range used by the + supported ESP32 targets. + +This controls the optional ESP-NOW bridge transport; it does not change a +node's primary ESP-NOW mesh channel. Primary-ESP-NOW firmware uses +`get espnow.channel` and `set espnow.channel <1-13>` instead. + +--- + +#### View or change the ESP-NOW bridge wire format +**Usage:** +- `get bridge.format` +- `set bridge.format ` + +**Parameters:** +- `format`: + - `wrapped`: the original ESP-NOW bridge framing (magic, checksum, and XOR + using `bridge.secret`) + - `raw`: the exact serialized MeshCore packet used by primary + `ESPNOWRadio` firmware + +**Default:** `wrapped` + +The setting is persistent and restarts an enabled bridge immediately. Receive +parsing is strict: `wrapped` accepts only wrapped frames and `raw` accepts only +raw MeshCore frames. Coordinate the format and channel on every ESP-NOW peer; +there is no automatic dual-format receive mode because it would permit +ambiguous, asymmetric bridge deployments. + +Use `raw` to connect a LoRa-primary `*_repeater_bridge_espnow` node to +`Generic_ESPNOW`, `SenseCapIndicator-ESPNow`, or another primary-ESP-NOW node. +Raw mode enables the ESP-NOW LR PHY and sends at the same LR rate used by those +targets. All nodes must use the same 1-13 channel. On a primary-ESP-NOW node, +change that side with `set espnow.channel <1-13>` and reboot; on the bridge, +use `set bridge.channel <1-13>`. + +Raw mode ignores `bridge.secret` and removes the bridge wrapper's lightweight +network isolation. MeshCore's own packet authentication/encryption still +applies where the packet type provides it, but public frames and routing +metadata remain visible. The wrapped format's XOR is isolation, not strong +cryptography. Bridge duplicate tracking remains active in both formats, but +deploying multiple gateways between the same LoRa and ESP-NOW coverage areas +can still increase duplicate traffic while their seen-packet tables converge. + +One ESP-NOW frame carries at most 250 payload bytes. In raw mode, serialized +MeshCore packets up to that size remain byte-for-byte compatible with existing +raw endpoints. Updated raw endpoints split 251-255-byte transport units into +two versioned fragments and reassemble them by source MAC, length, and CRC; +both endpoints must include this support for those sizes. Current valid +MeshCore packet geometry reaches 254 bytes, while 255 is retained as transport +headroom. Wrapped mode retains its legacy 246-byte maximum after the four-byte +magic and checksum overhead, and drops larger packets instead of truncating +them. --- @@ -3504,6 +3600,8 @@ rate before running `set bridge.enabled on`. **Default:** Varies by board +This setting is used only by `bridge.format wrapped`; raw mode ignores it. + --- #### View the bootloader version (nRF52 only) diff --git a/docs/companion_protocol.md b/docs/companion_protocol.md index 5dc81654..e0358be0 100644 --- a/docs/companion_protocol.md +++ b/docs/companion_protocol.md @@ -261,7 +261,7 @@ text such as `set radio.rxgain off` still requires the USB terminal start token. The WiFi power-save pair is available on ESP32 WiFi Companion builds over the normal binary USB, BLE, or TCP port 5000 transport. `CMD_GET_WIFI_POWER_SAVE` -has no body and replies with `RESP_CODE_OK` followed by one mode byte. +has no body and replies with `RESP_CODE_OK` followed by the effective mode byte. `CMD_SET_WIFI_POWER_SAVE` is followed by that mode byte and replies with `RESP_CODE_OK` after saving it: @@ -274,10 +274,14 @@ has no body and replies with `RESP_CODE_OK` followed by one mode byte. An out-of-range value returns `ERR_CODE_ILLEGAL_ARG`. A non-WiFi Companion returns `ERR_CODE_UNSUPPORTED_CMD`. Full Companion has Bluetooth enabled and therefore returns `ERR_CODE_BAD_STATE` for `none`, because ESP32 WiFi/Bluetooth -coexistence requires modem sleep. A storage failure also returns -`ERR_CODE_BAD_STATE`. If an already-saved mode cannot be applied to the active -WiFi driver, SET still returns `RESP_CODE_OK` and the mode is applied on the -next connection. Device `powersaving` does not overwrite this setting. +coexistence requires modem sleep. On an ESP32 Full Companion whose primary mesh +radio is ESP-NOW, SET also returns `ERR_CODE_BAD_STATE` for `max` (value `2`): maximum +modem sleep can make the station miss ESP-NOW broadcasts, which the access point +cannot buffer. If an older image already saved `max`, GET reports `min` (value +`0`) and the running policy uses `min`. A storage failure also returns +`ERR_CODE_BAD_STATE`. If an otherwise permitted saved mode cannot be applied to +the active WiFi driver, SET still returns `RESP_CODE_OK` and the mode is applied +on the next connection. Device `powersaving` does not overwrite this setting. The Bluetooth-name pair is available on Companion builds regardless of the currently selected transport, so a host can configure a BLE-capable image over diff --git a/docs/companion_radio_full.md b/docs/companion_radio_full.md index 1fad6112..d0cf1e72 100644 --- a/docs/companion_radio_full.md +++ b/docs/companion_radio_full.md @@ -39,6 +39,39 @@ T-Echo Lite, LilyGo T-Impulse Plus, and Wio Tracker L1 E-Ink. Their old transport-specific names remain available for explicit compatibility builds, but the Full image is the canonical release artifact. +Every ESP32 Full image includes ordinary WiFi Companion, WebConfig, and the TCP +mOTA services, even when its historical build base was USB- or BLE-only. On +`Generic_ESPNOW` and `SenseCapIndicator-ESPNow`, ESP-NOW is also the primary +mesh radio and shares the same 2.4 GHz hardware. Those two Full images retain +B/G/N for ordinary clients alongside ESP-NOW LR. Their ESP-NOW mesh, setup AP, +and infrastructure connection all use one persisted channel, which defaults +to 1. Configure the router's 2.4 GHz radio and every other primary ESP-NOW node +for that same fixed channel. Turning Companion WiFi off stops its TCP/AP +services but deliberately leaves the ESP-NOW mesh radio running on the +selected channel. + +Inspect or change the shared channel from the Full Companion text terminal: + +```text +get espnow.channel +set espnow.channel 6 +reboot +``` + +The accepted range is 1 through 13; use only a channel permitted in your region +and supported by the router. The setter persists the selection, but the +running radio stays on its current channel until reboot. Coordinate the change +across every primary ESP-NOW node and the router before rebooting, or the node +will lose one or both links. This primary-radio setting is not +`bridge.channel`; that command belongs to the separate ESP-NOW bridge feature. +To attach a LoRa-primary `*_repeater_bridge_espnow` gateway to these nodes, +match its `bridge.channel` and select `set bridge.format raw`; the bridge's +backward-compatible default is the distinct wrapped format. +WiFi power saving cannot put infrastructure WiFi and ESP-NOW on different +channels. On these two primary-ESP-NOW Full targets, `max` is unavailable +because maximum modem sleep can make the station miss ESP-NOW broadcasts; use +`min` for WiFi/BLE/ESP-NOW coexistence. + List the available targets: ```bash @@ -142,17 +175,29 @@ start webconfig stop webconfig ``` +On the two primary-ESP-NOW Full targets, the same terminal also provides +`get espnow.channel` and `set espnow.channel <1-13>`. A channel change is +persisted and requires a reboot, unlike a WiFi power-save change. + SSID and password writes return their reply first, then restart the Companion WiFi station with the saved credentials. A TCP terminal therefore disconnects shortly after either write; reconnect to the IP reported by the new network. -The password is write-only and is masked while it is entered over USB. +The password is write-only and is masked while it is entered over USB. It may +be empty for an open network, an ordinary passphrase of up to 63 characters, or +an exact 64-character hexadecimal WPA/WPA2 PSK. Other 64-character values and +all longer values are rejected. The normal binary Companion connection can also read or write this setting over -USB, BLE, or TCP port 5000 without entering terminal mode. The saved values are +USB, BLE, or TCP port 5000 without entering terminal mode. The mode values are `0` for `min`, `1` for `none`, and `2` for `max`; see the [Companion protocol](./companion_protocol.md#commands). Full Companion rejects -`none` because simultaneous WiFi and BLE require modem sleep. Fresh Cascade -builds select `min`, and an existing saved selection takes precedence. +`none` because simultaneous WiFi and BLE require modem sleep. The two +primary-ESP-NOW Full targets also reject `max`; unlike infrastructure traffic, +peer ESP-NOW +broadcasts cannot be buffered by the access point while the station sleeps. If +an older image saved `max`, firmware applies and reports `min` instead. Fresh +Cascade builds select `min`, and an existing valid saved selection takes +precedence. On radios with RX duty-cycle support, WebConfig and the text terminal also expose the persisted RXPS setting: diff --git a/docs/firmware_picker.md b/docs/firmware_picker.md index d61d02c1..a3aa7697 100644 --- a/docs/firmware_picker.md +++ b/docs/firmware_picker.md @@ -148,6 +148,18 @@ board has room; use `set bridge.enabled on` after configuring `bridge.uart` and RS-232 image. Repeaters may also offer separate ESP-NOW, Ethernet, or MQTT observer modes. +An ESP-NOW bridge target keeps LoRa as its primary mesh radio. Its runtime +`bridge.format` setting chooses the peer protocol: `wrapped` (the +backward-compatible bridge-to-bridge default using `bridge.secret`) or `raw` +(direct MeshCore ESP-NOW LR frames for `Generic_ESPNOW`, +`SenseCapIndicator-ESPNow`, and other primary-ESP-NOW nodes). This is one +firmware choice, not two board images. Match `bridge.channel` to the primary +nodes' `espnow.channel` before selecting `set bridge.format raw`. +For Heltec V4 specifically, `companion_radio_full` is still a LoRa-primary +Companion; choose the existing `heltec_v4_repeater_bridge_espnow` firmware to +make that board the LoRa/ESP-NOW gateway. Use its exact merged artifact when +changing roles or partition layouts. + ## FULL versus standard For a new installation, use the FULL / complete profile when it exists and the diff --git a/docs/terminal_chat_cli.md b/docs/terminal_chat_cli.md index 38de32e9..8d09640a 100644 --- a/docs/terminal_chat_cli.md +++ b/docs/terminal_chat_cli.md @@ -189,7 +189,30 @@ set wifi.powersave {none|min|max} Shows or changes the persisted WiFi modem-sleep policy on ESP32 WiFi Companion builds. Full Companion requires at least `min` while BLE is present and rejects `none`. The WebConfig WiFi card and the normal binary Companion protocol expose -the same setting; binary clients do not need the terminal-start token. +the same setting; binary clients do not need the terminal-start token. On an +ESP32 Full Companion whose primary mesh radio is ESP-NOW, `max` is also +unavailable because maximum modem sleep can make the +station miss ESP-NOW broadcasts, which the access point does not buffer. A +previously saved `max` value is capped to and reported as `min`, and a new `max` +selection is rejected. Such a WiFi/BLE/primary-ESP-NOW build therefore uses +`min`. + +``` +get espnow.channel +set espnow.channel <1-13> +``` +On Full Companion builds whose primary mesh radio is ESP-NOW, this shows or +saves the single channel shared by ESP-NOW, the setup AP, and the +infrastructure-WiFi station. The default is channel 1. Use only a channel +permitted in your region and supported by the router. A saved change takes +effect only after reboot. Every primary ESP-NOW node and the router's 2.4 GHz +radio must use the same fixed channel; power saving does not permit separate +channels. On these ESP32 Full builds, `wifi.powersave max` is unavailable and +`min` is the coexistence setting. This channel setting is also distinct from +`bridge.channel`, which controls the optional ESP-NOW bridge transport. An +updated LoRa-primary ESP-NOW bridge can join this raw primary transport by +selecting the same channel and running `set bridge.format raw`; its default +`wrapped` format remains the bridge-to-bridge protocol. ``` get radio.rxgain diff --git a/examples/companion_radio/CompanionWiFi.h b/examples/companion_radio/CompanionWiFi.h index a1a009bd..41c92f63 100644 --- a/examples/companion_radio/CompanionWiFi.h +++ b/examples/companion_radio/CompanionWiFi.h @@ -9,6 +9,7 @@ enum class CompanionWiFiPowerSaveResult : uint8_t { SavedForNextConnection, InvalidMode, BluetoothConflict, + PrimaryEspNowConflict, StorageError, }; @@ -22,9 +23,10 @@ bool isCompanionWiFiEnabled(); void scheduleCompanionWiFiCredentialReload(); // Companion WiFi power save is stored in the shared mesh-wifi NVS namespace. -// The returned mode is always the effective mode: WiFi+BLE builds map a stale +// The returned mode is always the effective mode. WiFi+BLE builds map a stale // or default "none" value to "min" because modem sleep is required for radio -// coexistence. +// coexistence. Primary ESP-NOW builds also map stale "max" to "min" so the +// receiver does not sleep through unbuffered ESP-NOW broadcasts. uint8_t getCompanionWiFiPowerSave(); const char* getCompanionWiFiPowerSaveName(); const char* companionWiFiPowerSaveName(uint8_t mode); diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index fdefbbae..574b02d6 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -21,6 +21,10 @@ #include #endif +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW +#include +#endif + #include #ifdef ENABLE_USB_INTERFACE #include @@ -2118,6 +2122,22 @@ bool MyMesh::handleLocalControlCommand(const char* command, char* reply, return true; } +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (strcmp(command, "get espnow.channel") == 0) { + formatEspNowChannel(reply, reply_size); + return true; + } + + if (strncmp(command, "set espnow.channel", 18) == 0 + && (command[18] == 0 || command[18] == ' ' + || command[18] == '\t')) { + const char* value = command + 18; + while (*value == ' ' || *value == '\t') value++; + applyAndSaveEspNowChannel(value, reply, reply_size); + return true; + } +#endif + #if defined(ESP32) && defined(WIFI_SSID) #ifdef WITH_WEBCONFIG if (strncmp(command, "get ", 4) == 0) { @@ -2162,7 +2182,7 @@ bool MyMesh::handleLocalControlCommand(const char* command, char* reply, || wifi_key == mesh::cli::StandaloneWiFiKey::Password) { if (saved) { char saved_ssid[32] = {0}; - char saved_password[64] = {0}; + char saved_password[65] = {0}; uint8_t saved_power_save = mesh::wifi::kDefaultPowerSave; const bool has_ssid = WebConfigServer::loadStandaloneWiFi( saved_ssid, sizeof(saved_ssid), saved_password, @@ -2516,6 +2536,9 @@ void MyMesh::getNodeSnapshot(WebConfigServer::NodeSnapshot& s) { #endif #if defined(ESP32) && defined(WIFI_SSID) s.capabilities |= WebConfigServer::CAP_WIFI_POWER_SAVE; +#endif +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + s.capabilities |= WebConfigServer::CAP_ESPNOW_CHANNEL; #endif if (radio_driver.supportsRxBoostedGainMode()) { s.capabilities |= WebConfigServer::CAP_RX_GAIN; @@ -2621,6 +2644,12 @@ void MyMesh::execCommand(char* cmd, char* reply) { formatBluetoothNameStatus(reply, 160); return; } +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (cmd && strcmp(cmd, "get espnow.channel") == 0) { + formatEspNowChannel(reply, 160); + return; + } +#endif #if defined(ESP32) && defined(WIFI_SSID) if (cmd && strcmp(cmd, "get wifi.powersave") == 0) { formatWiFiPowerSaving(reply, 160); @@ -2653,6 +2682,12 @@ void MyMesh::execCommand(char* cmd, char* reply) { applyAndSaveBluetoothName(value, reply, 160); return; } +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (strcmp(key, "espnow.channel") == 0) { + applyAndSaveEspNowChannel(value, reply, 160); + return; + } +#endif if (strcmp(key, "lat") == 0 || strcmp(key, "lon") == 0) { double parsed; const bool latitude = key[1] == 'a'; @@ -4413,6 +4448,50 @@ void MyMesh::formatBluetoothNameStatus(char* reply, size_t reply_size) const { ? "custom" : "default from node name"); } +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW +void MyMesh::formatEspNowChannel(char* reply, size_t reply_size) const { + if (reply == NULL || reply_size == 0) return; + const uint8_t saved = mesh::wifi::loadConfiguredEspNowChannel(); + const uint8_t active = mesh::wifi::activeEspNowChannel(); + if (saved == active) { + snprintf(reply, reply_size, "> %u (saved and active)", + (unsigned)saved); + } else { + snprintf(reply, reply_size, + "> saved %u, active %u; reboot required", + (unsigned)saved, (unsigned)active); + } +} + +bool MyMesh::applyAndSaveEspNowChannel(const char* value, char* reply, + size_t reply_size) { + if (reply == NULL || reply_size == 0) return false; + uint8_t channel = 0; + if (!mesh::wifi::parseEspNowChannel(value, channel)) { + snprintf(reply, reply_size, "Error: ESP-NOW channel must be 1-13"); + return false; + } + // Snapshot the boot channel before writing NVS so even a CLI-only image + // cannot reinterpret the newly-saved setting as active in this boot. + const uint8_t active = mesh::wifi::activeEspNowChannel(); + if (!mesh::wifi::saveConfiguredEspNowChannel(channel)) { + snprintf(reply, reply_size, "Error: failed to save ESP-NOW channel"); + return false; + } + + if (channel == active) { + snprintf(reply, reply_size, + "OK - ESP-NOW channel %u saved and active", + (unsigned)channel); + } else { + snprintf(reply, reply_size, + "OK - ESP-NOW channel %u saved; active %u; reboot required", + (unsigned)channel, (unsigned)active); + } + return true; +} +#endif + bool MyMesh::applyAndSavePowerSaving(const char* value, char* reply) { bool enabled; if (strcmp(value, "on") == 0) { @@ -4465,6 +4544,11 @@ bool MyMesh::applyAndSaveWiFiPowerSaving(const char* value, char* reply, const CompanionWiFiPowerSaveResult result = setCompanionWiFiPowerSave(mode); + if (result == CompanionWiFiPowerSaveResult::PrimaryEspNowConflict) { + snprintf(reply, reply_size, + "Error: power save max is unavailable while ESP-NOW is the primary radio"); + return false; + } if (result == CompanionWiFiPowerSaveResult::BluetoothConflict) { snprintf(reply, reply_size, "Error: power save none is unavailable while Bluetooth is active"); @@ -5744,6 +5828,10 @@ void MyMesh::handleTerminalCommand(char* command) { terminalOutput().print(" start webconfig [ap]\r\n"); terminalOutput().print(" stop webconfig\r\n"); #endif +#endif +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + terminalOutput().print(" get espnow.channel\r\n"); + terminalOutput().print(" set espnow.channel <1-13>\r\n"); #endif terminalOutput().print(" get radio.rxps\r\n"); terminalOutput().print(" get radio.rxps.config\r\n"); diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index c626f5b1..d951ecfb 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -322,6 +322,11 @@ private: bool applyAndSaveBluetoothName(const char* value, char* reply, size_t reply_size); void formatBluetoothNameStatus(char* reply, size_t reply_size) const; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + bool applyAndSaveEspNowChannel(const char* value, char* reply, + size_t reply_size); + void formatEspNowChannel(char* reply, size_t reply_size) const; +#endif bool applyAndSavePowerSaving(const char* value, char* reply); bool applyAndSaveRxPowerSaving(const char* value, char* reply); void appendRxPowerSavingAdjustmentNote(char* reply, size_t reply_size, diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index eac48daa..abd15090 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -64,8 +64,11 @@ MultiSerialInterface interface_manager; // include esp32 wifi interface #include #include + #include #include #include + #include + #include #include #include SerialWifiInterface wifi_interface; @@ -98,6 +101,10 @@ MultiSerialInterface interface_manager; #endif #endif +#if COMPANION_FEATURE_NETWORK_TERMINAL +static bool isNetworkTerminalActive(); +#endif + // include ethernet interface #if defined(ETHERNET_ENABLED) #include @@ -595,18 +602,37 @@ static void serviceUsbTerminal() { // A saved logging-on preference makes the one available TTY behave like a // logging repeater: plaintext diagnostics plus an input-capable CLI. Put the // Companion interface into passthrough before it can mix framed traffic with - // logs. `set usb.logging off` remains available here and returns this TTY to - // the normal ASCII terminal, matching a fresh Full install. Binary Companion - // starts only after the usual terminal-stop token or framed startup probe. + // logs. An active TCP terminal owns the role CLI, so logging must not reclaim + // it. Turning logging off restores the build's normal USB mode: ASCII for + // Full Companion and Binary Companion for every other single-TTY build. #if MESH_USB_LOGGING_AVAILABLE - if (!mesh::hasDedicatedUsbLoggingPort()) { - if (mesh::isUsbLoggingEnabled()) { + const mesh::UsbLoggingTerminalAction logging_action = + mesh::selectUsbLoggingTerminalAction( + mesh::hasDedicatedUsbLoggingPort(), mesh::isUsbLoggingEnabled(), + the_mesh.isTerminalMode(), usb_logging_terminal_mode, +#if defined(COMPANION_RADIO_FULL) + true, +#else + false, +#endif +#if COMPANION_FEATURE_NETWORK_TERMINAL + isNetworkTerminalActive() +#else + false +#endif + ); + switch (logging_action) { + case mesh::UsbLoggingTerminalAction::CLAIM_USB: if (!the_mesh.isTerminalMode()) { enterUsbLoggingTerminalMode(); return; } usb_logging_terminal_mode = true; - } else if (usb_logging_terminal_mode && the_mesh.isTerminalMode()) { + break; + case mesh::UsbLoggingTerminalAction::RETURN_TO_BINARY: + leaveUsbTerminalMode(true); + return; + case mesh::UsbLoggingTerminalAction::KEEP_ASCII: // Logging may also be disabled over BLE/WiFi. Stop treating this session // as the logging terminal, but keep the ordinary ASCII terminal active; // do not silently change the USB protocol underneath an idle host. A @@ -616,7 +642,9 @@ static void serviceUsbTerminal() { clearUsbTerminalLine(); usb_terminal_discard_line = false; Serial.print("\r\nUSB logging off; ASCII terminal active\r\n> "); - } + break; + case mesh::UsbLoggingTerminalAction::NONE: + break; } #endif if (!the_mesh.isTerminalMode()) { @@ -641,12 +669,20 @@ static void serviceUsbTerminal() { return; } +#if defined(ESP32) && defined(ARDUINO_USB_MODE) && ARDUINO_USB_MODE == 1 \ + && defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT + // HWCDC has no DTR/open signal, and its bool operator is only a transient + // RX/TX activity heuristic. Do not interpret an idle interval as the host + // closing Full Companion's startup terminal. TCP handoff is separately + // arbitrated by hasObservableActiveUsbTerminalClient(), using actual input. +#else if (isUsbTerminalDataConnected()) { usb_terminal_disconnect_armed = true; } else if (usb_terminal_disconnect_armed) { leaveUsbTerminalMode(false); return; } +#endif #if defined(COMPANION_RADIO_FULL) // Full Companion boots as a useful ASCII terminal. MeshCLI's first framed @@ -705,10 +741,15 @@ static void serviceUsbTerminal() { #if MESH_USB_LOGGING_AVAILABLE if (usb_logging_terminal_mode && !mesh::isUsbLoggingEnabled()) { - // The command reply belongs to the ASCII session. Leave that session - // active so a separate, observable mode switch is required before the +#if defined(COMPANION_RADIO_FULL) + // The command reply belongs to the Full Companion's normal ASCII + // session. A separate, observable mode switch is required before the // port accepts framed Binary Companion traffic again. usb_logging_terminal_mode = false; +#else + leaveUsbTerminalMode(true); + return; +#endif } #endif Serial.print("> "); @@ -764,7 +805,7 @@ void halt() { unsigned long last_wifi_setup_attempt = 0; bool wifi_setup_recovery_mode = false; static char configured_wifi_ssid[32]; - static char configured_wifi_password[64]; + static char configured_wifi_password[65]; static bool companion_wifi_has_credentials = false; static bool companion_wifi_requested = true; static bool companion_wifi_active = false; @@ -803,7 +844,8 @@ void halt() { nvs.end(); } companion_wifi_power_save = mesh::wifi::effectivePowerSave( - configured, companionWiFiBluetoothActive()); + configured, companionWiFiBluetoothActive(), + mesh::wifi::kPrimaryEspNowRadio); companion_wifi_power_save_loaded = true; applyCompanionWiFiPowerSave(); } @@ -831,11 +873,16 @@ void halt() { if (mode > mesh::wifi::kPowerSaveMax) { return CompanionWiFiPowerSaveResult::InvalidMode; } - if (mesh::wifi::effectivePowerSave(mode, companionWiFiBluetoothActive()) + if (mesh::wifi::kPrimaryEspNowRadio + && mode == mesh::wifi::kPowerSaveMax) { + return CompanionWiFiPowerSaveResult::PrimaryEspNowConflict; + } + if (mesh::wifi::effectivePowerSave( + mode, companionWiFiBluetoothActive(), + mesh::wifi::kPrimaryEspNowRadio) != mode) { return CompanionWiFiPowerSaveResult::BluetoothConflict; } - Preferences nvs; if (!nvs.begin("mesh-wifi", false)) { return CompanionWiFiPowerSaveResult::StorageError; @@ -860,7 +907,8 @@ void halt() { configured_wifi_ssid, sizeof(configured_wifi_ssid), configured_wifi_password, sizeof(configured_wifi_password)); if (!companion_wifi_has_credentials - && !WiFiSetupPortal::isPlaceholderSSID(WIFI_SSID)) { + && !WiFiSetupPortal::isPlaceholderSSID(WIFI_SSID) + && mesh::cli::standaloneWiFiPasswordValid(WIFI_PWD)) { strncpy(configured_wifi_ssid, WIFI_SSID, sizeof(configured_wifi_ssid) - 1); configured_wifi_ssid[sizeof(configured_wifi_ssid) - 1] = '\0'; strncpy(configured_wifi_password, WIFI_PWD, sizeof(configured_wifi_password) - 1); @@ -978,6 +1026,12 @@ void halt() { static mesh::UsbTcpTerminalHandoff ota_console_usb_handoff; #endif +#if COMPANION_FEATURE_NETWORK_TERMINAL + static bool isNetworkTerminalActive() { + return the_mesh.isNetworkTerminalMode(ota_console_client); + } +#endif + static void ota_console_clear_line() { memset(ota_console_line, 0, sizeof(ota_console_line)); ota_console_len = 0; @@ -1140,9 +1194,11 @@ void halt() { } WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); + mesh::wifi::applyProtocolMask(WIFI_IF_STA); + mesh::wifi::setStationAutoReconnect(true); WiFi.disconnect(false, false); - WiFi.begin(configured_wifi_ssid, configured_wifi_password); + mesh::wifi::beginStation( + configured_wifi_ssid, configured_wifi_password); wifi_reconnect_tracker.noteAttempt(millis()); WIFI_DEBUG_PRINTLN("WiFi credentials reloaded; reconnecting to saved SSID"); } @@ -1151,13 +1207,15 @@ void halt() { if (companion_wifi_active) return; board.setInhibitSleep(true); - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); resetCompanionWiFiRecoveryState(); if (companion_wifi_has_credentials) { WiFi.mode(WIFI_STA); + mesh::wifi::applyProtocolMask(WIFI_IF_STA); wifi_reconnect_tracker.noteDisconnected(millis()); - WiFi.begin(configured_wifi_ssid, configured_wifi_password); + mesh::wifi::beginStation( + configured_wifi_ssid, configured_wifi_password); } #ifndef WITH_WEBCONFIG else if (!wifiSetupPortal().begin(COMPANION_WIFI_SETUP_AP, @@ -1197,6 +1255,21 @@ void halt() { companion_wifi_services_stopped = true; } + static void stopCompanionInfrastructureWiFi() { + WiFi.setAutoReconnect(false); +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + // ESP-NOW is the mesh radio on this target. Drop the station/AP services + // without stopping the driver, then restore its fixed LR mesh channel. + WiFi.disconnect(false, false); + WiFi.mode(WIFI_STA); + mesh::wifi::applyProtocolMask(WIFI_IF_STA); + mesh::wifi::restoreEspNowChannel(); +#else + WiFi.disconnect(true, false); + WiFi.mode(WIFI_OFF); +#endif + } + static bool finishStoppingCompanionWiFi() { stopCompanionWiFiServices(); #ifdef WITH_WEBCONFIG @@ -1212,13 +1285,16 @@ void halt() { if (wifiSetupPortal().isStopping()) return false; #endif - WiFi.setAutoReconnect(false); - WiFi.disconnect(true, false); - WiFi.mode(WIFI_OFF); + stopCompanionInfrastructureWiFi(); board.setInhibitSleep(false); resetCompanionWiFiRecoveryState(); companion_wifi_active = false; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + WIFI_DEBUG_PRINTLN( + "Companion WiFi services disabled; ESP-NOW mesh radio remains active"); +#else WIFI_DEBUG_PRINTLN("WiFi radio disabled by BOOT/GPIO 0 control"); +#endif return true; } @@ -1455,10 +1531,29 @@ void setup() { #ifdef WIFI_SSID WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){ if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + mesh::wifi::restoreEspNowChannel(); +#endif if (companion_wifi_requested) { WIFI_DEBUG_PRINTLN("WiFi disconnected; automatic recovery is active"); } } else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) { + if (!mesh::wifi::enforceStationChannel()) { + WIFI_DEBUG_PRINTLN( + "Rejected WiFi association outside ESP-NOW channel %u", + (unsigned)mesh::wifi::activeEspNowChannel()); + return; + } +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + // Association can replace the station protocol bitmap after the + // pre-connect setup. Restore LR receive support once the AP has + // finished configuring the shared radio; B/G/N remain enabled for + // the infrastructure connection. + if (mesh::wifi::applyProtocolMask(WIFI_IF_STA) != ESP_OK) { + WIFI_DEBUG_PRINTLN( + "Failed to restore ESP-NOW/WiFi protocol coexistence"); + } +#endif WIFI_DEBUG_PRINTLN("connected! IP %s (companion app on :%d)", WiFi.localIP().toString().c_str(), TCP_PORT); } @@ -1469,8 +1564,7 @@ void setup() { if (companion_wifi_requested) { startCompanionWiFi(); } else { - WiFi.setAutoReconnect(false); - WiFi.mode(WIFI_OFF); + stopCompanionInfrastructureWiFi(); board.setInhibitSleep(false); WIFI_DEBUG_PRINTLN("WiFi remains off from the saved BOOT/GPIO 0 setting"); } @@ -1504,10 +1598,10 @@ void setup() { // the kiss_modem tuning) Serial.setTxBufferSize(4096); Serial.setTxTimeoutMs(5); - // The ESP32 USB-Serial-JTAG peripheral (HWCDC) has no DTR concept at all: - // (bool)Serial only tells us the host has enumerated the device, which is - // already true when the cable is plugged into a powered port. Fall back to - // activity: a real client has to send us frames. + // The ESP32 USB-Serial-JTAG peripheral (HWCDC) has no DTR concept at all, + // and its bool operator is only a transient RX/TX activity heuristic. A real + // Binary Companion client therefore has to prove ownership by sending + // frames; an idle physical cable must not claim the interface. usb_serial_interface.setConnectedCheck([]() { uint32_t last = usb_serial_interface.getLastFrameMillis(); return (bool)Serial && usb_serial_interface.hasReceivedFrame() @@ -1682,7 +1776,8 @@ void loop() { ota_console_loop(); // service the OTA text console (port 5002) #endif const unsigned long wifi_now = millis(); - if (WiFi.status() == WL_CONNECTED) { + const bool station_channel_ok = mesh::wifi::enforceStationChannel(); + if (station_channel_ok && WiFi.status() == WL_CONNECTED) { wifi_reconnect_tracker.noteConnected(); wifi_setup_attempted = false; #ifdef WITH_WEBCONFIG @@ -1692,7 +1787,7 @@ void loop() { if (configured_wifi_ssid[0] && the_mesh.isWebConfigSetupActive() && (wifi_setup_recovery_mode || the_mesh.isWebConfigWiFiRecoveryActive())) { - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); the_mesh.stopWebConfig(); wifi_setup_recovery_mode = false; } @@ -1742,8 +1837,10 @@ void loop() { } } - // The ESP stack normally reconnects by itself. If it gets wedged after an AP - // outage, reassert the saved credentials every five minutes. WebConfig's + // Reassert the saved credentials every five minutes after an AP outage. + // Primary ESP-NOW builds deliberately disable the driver's unconstrained + // auto-reconnect; ordinary builds retain it and use this as a recovery path. + // WebConfig's // setup AP uses AP+STA mode, so the station retry can run without taking the // recovery page down. The legacy portal owns its own identical retry timer. const bool reconnect_owned_here = @@ -1762,14 +1859,15 @@ void loop() { #ifdef WITH_WEBCONFIG if (!the_mesh.isWebConfigSetupActive()) { WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); } #else WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); #endif WiFi.disconnect(false, false); - WiFi.begin(configured_wifi_ssid, configured_wifi_password); + mesh::wifi::beginStation( + configured_wifi_ssid, configured_wifi_password); } #ifdef WITH_MQTT_BRIDGE the_mesh.serviceMQTT(configured_wifi_ssid, configured_wifi_password); diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index ad5e0593..95655153 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -3345,6 +3345,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc _prefs.bridge_pkt_src = 1; // logRx (RX packets) _prefs.bridge_baud = 115200; // baud rate _prefs.bridge_channel = 1; // channel 1 + _prefs.bridge_format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; #ifdef WITH_RS232_BRIDGE _prefs.bridge_uart = WITH_RS232_BRIDGE_UART; #else @@ -9995,6 +9996,9 @@ void MyMesh::getNodeSnapshot(WebConfigServer::NodeSnapshot& s) { | WebConfigServer::CAP_ADVERT | WebConfigServer::CAP_FLOOD | WebConfigServer::CAP_LOOP | WebConfigServer::CAP_WIFI_POWER_SAVE | WebConfigServer::CAP_POWER_SAVING; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + s.capabilities |= WebConfigServer::CAP_ESPNOW_CHANNEL; +#endif if (board.canControlLoRaFemLna()) { s.capabilities |= WebConfigServer::CAP_FEM_RX_GAIN; } @@ -10148,14 +10152,16 @@ bool MyMesh::setWiFiCLI(const char* value, char* reply) { void MyMesh::onConfigBatchEnd() { _wc_batch_active = false; -#ifdef WITH_MQTT_BRIDGE +#ifdef WITH_BRIDGE if (_wc_restart_pending) { _wc_restart_pending = false; _wc_slot_restart_mask = 0; - restartBridge(); + if (_prefs.bridge_enabled) restartBridge(); return; } +#endif +#ifdef WITH_MQTT_BRIDGE const uint8_t mask = _wc_slot_restart_mask; _wc_slot_restart_mask = 0; for (int i = 0; i < RUNTIME_MQTT_SLOTS; i++) { diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 8b66b6e7..b780e727 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -994,7 +994,11 @@ public: } #endif - void setBridgeState(bool enable) override { + bool setBridgeState(bool enable) override { + // Disabling an already-absent heap-backed bridge is successful and must + // not allocate an instance merely to stop it. The embedded ESP-NOW bridge + // is always present, so it continues through the normal state check. + if (!enable && !activeBridge()) return true; #ifdef WITH_MQTT_BRIDGE if (!mqtt_bridge) { MQTTNodeInfo node_info; @@ -1007,17 +1011,17 @@ public: node_info.repeat_when_nonzero = false; mqtt_bridge = new MQTTBridge(node_info, _cli.getObserverPrefs(), getRTCClock(), &self_id); - if (!mqtt_bridge) return; + if (!mqtt_bridge) return false; } #endif #ifdef WITH_RS232_BRIDGE if (enable && !bridge) { bridge = createRS232Bridge(); - if (!bridge) return; + if (!bridge) return false; } #endif AbstractBridge* active_bridge = activeBridge(); - if (!active_bridge) return; + if (!active_bridge) return false; if (enable == active_bridge->isRunning()) { #ifdef WITH_RS232_BRIDGE if (!enable) { @@ -1025,7 +1029,7 @@ public: bridge = nullptr; } #endif - return; + return true; } if (enable) { @@ -1048,6 +1052,7 @@ public: else { active_bridge->end(); + const bool stopped = !active_bridge->isRunning(); #ifdef WITH_RS232_BRIDGE delete bridge; bridge = nullptr; @@ -1055,24 +1060,26 @@ public: #ifdef WITH_MQTT_BRIDGE _alerter.setBridge(nullptr); #endif + return stopped; } + return active_bridge->isRunning(); } - void restartBridge() override { + bool restartBridge() override { AbstractBridge* active_bridge = activeBridge(); - if (!active_bridge || !active_bridge->isRunning()) return; + if (!active_bridge) return false; #ifdef WITH_WEBCONFIG if (_wc_batch_active) { // coalesced: applied once in onConfigBatchEnd() _wc_restart_pending = true; - return; + return true; } #endif - active_bridge->end(); + if (active_bridge->isRunning()) active_bridge->end(); #ifdef WITH_RS232_BRIDGE delete bridge; bridge = createRS232Bridge(); if (bridge) bridge->begin(); - return; + return bridge && bridge->isRunning(); #endif #ifdef WITH_MQTT_BRIDGE // Set device metadata before restarting bridge (same as in begin()) @@ -1086,6 +1093,7 @@ public: mqtt_bridge->setStatsSources(this, _radio, _cli.getBoard(), _ms); #endif active_bridge->begin(); + return active_bridge->isRunning(); } void restartBridgeSlot(int slot) override { diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 6f49ef61..590e7e73 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -1236,6 +1236,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc _prefs.bridge_pkt_src = 1; // logRx (RX packets) _prefs.bridge_baud = 115200; // baud rate _prefs.bridge_channel = 1; // channel 1 + _prefs.bridge_format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; // MQTT/WiFi/timezone defaults live in /mqtt_prefs now (see applyMQTTDefaults). @@ -1633,6 +1634,9 @@ void MyMesh::getNodeSnapshot(WebConfigServer::NodeSnapshot& s) { | WebConfigServer::CAP_ADVERT | WebConfigServer::CAP_FLOOD | WebConfigServer::CAP_LOOP | WebConfigServer::CAP_WIFI_POWER_SAVE | WebConfigServer::CAP_POWER_SAVING; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + s.capabilities |= WebConfigServer::CAP_ESPNOW_CHANNEL; +#endif if (board.canControlLoRaFemLna()) { s.capabilities |= WebConfigServer::CAP_FEM_RX_GAIN; } @@ -1790,7 +1794,7 @@ void MyMesh::onConfigBatchEnd() { if (_wc_restart_pending) { _wc_restart_pending = false; _wc_slot_restart_mask = 0; - restartBridge(); + if (_prefs.bridge_enabled) restartBridge(); return; } const uint8_t mask = _wc_slot_restart_mask; diff --git a/examples/simple_room_server/MyMesh.h b/examples/simple_room_server/MyMesh.h index 429a4767..6f3a6349 100644 --- a/examples/simple_room_server/MyMesh.h +++ b/examples/simple_room_server/MyMesh.h @@ -467,7 +467,10 @@ public: void loop(); #if defined(WITH_BRIDGE) - void setBridgeState(bool enable) override { + bool setBridgeState(bool enable) override { + // An absent MQTT bridge is already stopped. Do not allocate one solely to + // satisfy an idempotent disable request. + if (!enable && !bridge) return true; if (!bridge) { #ifdef WITH_MQTT_BRIDGE MQTTNodeInfo node_info; @@ -481,9 +484,9 @@ public: bridge = new MQTTBridge(node_info, _cli.getObserverPrefs(), getRTCClock(), &self_id); #endif - if (!bridge) return; + if (!bridge) return false; } - if (enable == bridge->isRunning()) return; + if (enable == bridge->isRunning()) return true; if (enable) { char device_id[65]; @@ -515,17 +518,18 @@ public: _alerter.setBridge(nullptr); #endif } + return enable ? bridge->isRunning() : !bridge->isRunning(); } - void restartBridge() override { - if (!bridge || !bridge->isRunning()) return; + bool restartBridge() override { + if (!bridge) return false; #ifdef WITH_WEBCONFIG if (_wc_batch_active) { // coalesced: applied once in onConfigBatchEnd() _wc_restart_pending = true; - return; + return true; } #endif - bridge->end(); + if (bridge->isRunning()) bridge->end(); char device_id[65]; mesh::LocalIdentity self_id = getSelfId(); mesh::Utils::toHex(device_id, self_id.pub_key, PUB_KEY_SIZE); @@ -537,6 +541,7 @@ public: bridge->setStatsSources(this, _radio, _cli.getBoard(), _ms); #endif bridge->begin(); + return bridge->isRunning(); } void restartBridgeSlot(int slot) override { diff --git a/mesh-america/update-provider-release.py b/mesh-america/update-provider-release.py index a93b2c05..df724ffc 100644 --- a/mesh-america/update-provider-release.py +++ b/mesh-america/update-provider-release.py @@ -44,6 +44,41 @@ LEGACY_COMPANION_IDENTITY_ALIASES = { "LilyGo_TBeam_1W_companion_radio_wifi", } +# These legacy recipes do not use the regular +# ``_companion_radio_`` spelling, or they carry a capability +# name that Full now provides at runtime. Keep the mapping beside the shared +# resolver so the main and logging catalog updaters cannot drift apart. +LEGACY_PLAIN_FULL_COMPANION_ALIASES = { + "generic_espnow_comp_radio_usb": + "Generic_ESPNOW_companion_radio_full", + "heltec_e290_companion_ble": + "Heltec_E290_companion_radio_full", + "heltec_e290_companion_usb": + "Heltec_E290_companion_radio_full", + "heltec_e290_companion_usb_ble": + "Heltec_E290_companion_radio_full", + "heltec_t190_companion_radio_usb_ble_": + "Heltec_T190_companion_radio_full_", + "sensecapindicator-espnow_comp_radio_usb": + "SenseCapIndicator-ESPNow_companion_radio_full", + "sensecapindicator-lora_comp_radio_usb_wifi": + "SenseCapIndicator-LoRa_companion_radio_full", + "heltec_v3_companion_radio_wifi_mqtt": + "Heltec_v3_companion_radio_full", + "heltec_v4_companion_radio_wifi_mqtt": + "heltec_v4_2_v4_3_companion_radio_full_femon", + "heltec_v4_companion_radio_wifi_mqtt_femon": + "heltec_v4_2_v4_3_companion_radio_full_femon", +} + +LEGACY_COMPANION_ARTIFACT_SUFFIXES = ( + "-full-logging-ota", + "-logging-ota", + "-ota-logging", + "-logging", + "-ota", +) + def parse_args() -> argparse.Namespace: script_dir = Path(__file__).resolve().parent @@ -392,16 +427,48 @@ def normalize_esp32_full_companion_metadata( def canonical_full_identity_for_transport(identity: str) -> str | None: + # OTA and logging were artifact variants of the old transport-specific + # recipes. The consolidated target is a plain Full identity, so carrying + # either suffix through the transport substitution produces a name that + # can never exist (for example ``..._full-ota``). + legacy_identity = identity + while True: + lowered = legacy_identity.lower() + suffix = next( + ( + suffix + for suffix in LEGACY_COMPANION_ARTIFACT_SUFFIXES + if lowered.endswith(suffix) + ), + None, + ) + if suffix is None: + break + legacy_identity = legacy_identity[: -len(suffix)] + + legacy_identity = canonical_runtime_identity(legacy_identity) + fixed_alias = LEGACY_PLAIN_FULL_COMPANION_ALIASES.get( + legacy_identity.lower() + ) + if fixed_alias is not None: + return fixed_alias + + # A catalog can already use the Full recipe while retaining an old + # ``-logging`` or ``-ota`` artifact qualifier. Once the qualifier is + # removed there is no transport substitution left to perform. + if "_companion_radio_full" in legacy_identity.lower(): + return canonical_runtime_identity(legacy_identity) + match = re.search( - r"_companion_radio_(?:usb|ble|wifi(?!_mqtt))(?=-|_|$)", - identity, + r"_companion_radio_(?:usb|ble|wifi(?!_mqtt)|serial|ethernet)(?=-|_|$)", + legacy_identity, flags=re.IGNORECASE, ) if match is None: return None full_identity = ( - identity[:match.start()] + "_companion_radio_full" + - identity[match.end():] + legacy_identity[:match.start()] + "_companion_radio_full" + + legacy_identity[match.end():] ) return canonical_runtime_identity(full_identity) @@ -431,7 +498,7 @@ def resolve_release_identity( if full_identity is not None and release_identity_is_full_companion( release_files, full_identity ): - return full_identity, False + return full_identity, "_wifi_mqtt" in logging_base.lower() # Canonical Full Companion replaces separate USB, BLE, and ordinary Wi-Fi # artifacts. Full is source-only for LoRa OTA and needs no target-side @@ -441,7 +508,7 @@ def resolve_release_identity( if full_identity is not None and release_identity_is_full_companion( release_files, full_identity ): - return full_identity, False + return full_identity, "_wifi_mqtt" in candidate.lower() # Accept catalogs produced while portable MQTT observers were still # emitted, and migrate them to the expanded-partition FULL artifact. diff --git a/platformio.ini b/platformio.ini index 882b5fc9..34fa893d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -84,7 +84,10 @@ build_flags = ${arduino_base.build_flags} -Wl,--wrap=esp_transport_ws_init ; -D ESP32_CPU_FREQ=80 ; change it to your need lib_deps = ${arduino_base.lib_deps} - ESP32Async/ESPAsyncWebServer @ 3.10.3 + ; Keep these as a matched pair. ESPAsyncWebServer 3.12.0 relies on + ; AsyncTCP 3.5.0's synchronous close/abort behavior and request-lifetime fix. + ESP32Async/AsyncTCP @ 3.5.0 + ESP32Async/ESPAsyncWebServer @ 3.12.0 bblanchon/ArduinoJson @ 7.4.3 build_src_filter = ${arduino_base.build_src_filter} + @@ -95,7 +98,8 @@ build_src_filter = ${arduino_base.build_src_filter} [esp32_ota] lib_deps = - ESP32Async/ESPAsyncWebServer @ 3.10.3 + ESP32Async/AsyncTCP @ 3.5.0 + ESP32Async/ESPAsyncWebServer @ 3.12.0 file://arch/esp32/AsyncElegantOTA ; esp32c6 uses arduino framework 3.x diff --git a/scripts/generate_webconfig_html.py b/scripts/generate_webconfig_html.py index 7617105c..20f85706 100644 --- a/scripts/generate_webconfig_html.py +++ b/scripts/generate_webconfig_html.py @@ -11,9 +11,9 @@ # flash, so the page ships smaller than it reads. # # Output: src/helpers/esp32/WebConfigHtml.h -# WEBCONFIG_HTML_GZ[] - gzipped page (PROGMEM) -# WEBCONFIG_HTML_GZ_LEN - byte length -# WEBCONFIG_HTML_ETAG - quoted strong ETag (sha256 prefix of the gz body) +# WEBCONFIG_HTML_LOADER[] - small bootstrap page (PROGMEM) +# WEBCONFIG_HTML_GZ[] - complete gzipped page (PROGMEM) +# WEBCONFIG_HTML_ETAG - quoted strong ETag for the loader page # # Runnable outside SCons to inspect exactly what gets shipped: # python3 scripts/generate_webconfig_html.py --emit /tmp/shipped.html @@ -83,6 +83,14 @@ def shipped_page(): return raw, stripped +def append_byte_array(lines, name, data): + lines.append("const uint8_t %s[] PROGMEM = {" % name) + for i in range(0, len(data), 16): + chunk = data[i:i + 16] + lines.append(" " + "".join("0x%02x," % b for b in chunk)) + lines.append("};") + + def main(): if not os.path.isfile(SOURCE): status("ERROR: %s not found" % SOURCE) @@ -103,9 +111,24 @@ def main(): src, stripped = shipped_page() raw = stripped.encode("utf-8") - # mtime=0 keeps the gzip output (and therefore the ETag) deterministic + # mtime=0 keeps the gzip output and its immutable URL deterministic. gz = gzip.compress(raw, compresslevel=9, mtime=0) - etag = hashlib.sha256(gz).hexdigest()[:16] + version = hashlib.sha256(gz).hexdigest()[:16] + loader = ("MeshCore " + "WebConfigLoading MeshCore WebConfig…" % version) + loader_bytes = loader.encode("utf-8") + etag = hashlib.sha256(loader_bytes).hexdigest()[:16] lines = [] lines.append("// Auto-generated by scripts/generate_webconfig_html.py from %s" % SOURCE.replace(os.sep, "/")) @@ -115,20 +138,21 @@ def main(): lines.append("#include ") lines.append("#include ") lines.append("") + lines.append("const uint32_t WEBCONFIG_HTML_RAW_LEN = %d;" % len(raw)) lines.append("const uint32_t WEBCONFIG_HTML_GZ_LEN = %d;" % len(gz)) lines.append('const char WEBCONFIG_HTML_ETAG[] = "\\"%s\\"";' % etag) - lines.append("const uint8_t WEBCONFIG_HTML_GZ[] PROGMEM = {") - for i in range(0, len(gz), 16): - chunk = gz[i:i + 16] - lines.append(" " + "".join("0x%02x," % b for b in chunk)) - lines.append("};") + lines.append('const char WEBCONFIG_HTML_VERSION[] = "%s";' % version) + lines.append("const uint16_t WEBCONFIG_HTML_LOADER_LEN = %d;" % len(loader_bytes)) + append_byte_array(lines, "WEBCONFIG_HTML_LOADER", loader_bytes) + lines.append("") + append_byte_array(lines, "WEBCONFIG_HTML_GZ", gz) lines.append("") os.makedirs(os.path.dirname(OUTPUT), exist_ok=True) with open(OUTPUT, "w") as f: f.write("\n".join(lines)) - status("%s -> %s (%d bytes source, %d stripped, %d gzipped)" + status("%s -> %s (%d bytes source, %d stripped, %d gzip)" % (SOURCE, OUTPUT, len(src.encode("utf-8")), len(raw), len(gz))) diff --git a/scripts/webconfig_cli_audit.py b/scripts/webconfig_cli_audit.py index be28cdcf..9ee11e75 100644 --- a/scripts/webconfig_cli_audit.py +++ b/scripts/webconfig_cli_audit.py @@ -102,6 +102,8 @@ ROUND_TRIPS = [ ("set dutycycle 25", "get dutycycle", "25.0"), ("set alert.mqtt on", "get alert.mqtt", "on"), ("set bridge.source tx", "get bridge.source", "tx"), + ("set bridge.channel 1", "get bridge.channel", "1"), + ("set bridge.format raw", "get bridge.format", "raw"), ("set mqtt.neighbors on", "get mqtt.neighbors", "on"), ("set path.hash.mode 2", "get path.hash.mode", "2"), ("set mqtt.iata den", "get mqtt.iata", "DEN"), diff --git a/scripts/webconfig_mock_server.py b/scripts/webconfig_mock_server.py index de6e14f4..0ce82891 100644 --- a/scripts/webconfig_mock_server.py +++ b/scripts/webconfig_mock_server.py @@ -60,10 +60,11 @@ ADMIN_PASSWORD = "password" # matches the default ADMIN_PASSWORD build BATCH_PENDING_SECS = 0.8 # how long POST->done takes, to exercise polling SCAN_SECS = 0.8 -# Destination buffer sizes (chars, minus the NUL) -- mirrors the MQTTPrefs fields -# the firmware validates in CommonCLI_Observer.cpp. +# Destination buffer sizes (chars, minus the NUL). Most mirror MQTTPrefs; +# wifi.pwd models the standalone mesh-wifi NVS path and receives the additional +# exact-64-hex check in apply_set(). Slot credentials remain fixed-layout. LEN_LIMITS = { - "name": 31, "wifi.ssid": 31, "wifi.pwd": 63, "mqtt.origin": 31, + "name": 31, "wifi.ssid": 31, "wifi.pwd": 64, "mqtt.origin": 31, "mqtt.email": 63, "mqtt.ntp": 63, "timezone": 31, "snmp.community": 23, } # "filter" is absent on purpose: it is a bitmask, not a text buffer, so it has @@ -89,11 +90,11 @@ PRESETS = ( ) SCAN_NETWORKS = [ - {"ssid": "Wokwi-GUEST", "rssi": -42, "enc": False}, - {"ssid": "HomeNet", "rssi": -55, "enc": True}, - {"ssid": "HomeNet-5G", "rssi": -61, "enc": True}, - {"ssid": "Neighbor 2.4", "rssi": -78, "enc": True}, - {"ssid": "OpenGuest", "rssi": -83, "enc": False}, + {"ssid": "Wokwi-GUEST", "rssi": -42, "enc": False, "channel": 6}, + {"ssid": "HomeNet", "rssi": -55, "enc": True, "channel": 1}, + {"ssid": "HomeNet-5G", "rssi": -61, "enc": True, "channel": 11}, + {"ssid": "Neighbor 2.4", "rssi": -78, "enc": True, "channel": 9}, + {"ssid": "OpenGuest", "rssi": -83, "enc": False, "channel": 3}, ] @@ -137,7 +138,8 @@ def default_config(setup_mode): "alert.region": "", "alert.interval": 15, "alert.mqtt": False, "alert.wifi": False, "bridge.enabled": False, "bridge.source": "rx", "bridge.baud": 115200, - "bridge.delay": 0, "bridge.channel": 0, "bridge.secret": "", + "bridge.delay": 0, "bridge.channel": 0, + "bridge.format": "wrapped", "bridge.secret": "", }, } @@ -196,6 +198,7 @@ class State: "role": "Repeater", "board": "Heltec V3 (mock)", "uptime_s": int(time.time() - self.start), "runtime_slots": 6, "max_slots": 6, "active_slots": self.active_slots, + "wifi_psk64": True, # Every ordinary repeater feature except an external FEM, plus # radio RX power saving (bit 12) and device power saving (bit 13). "capabilities": 0x37FF, @@ -262,6 +265,8 @@ def _rxps_level_timings(level, sf, bw, preamble): def apply_set(cfg, key, val): """Return (ok, reply) and mutate cfg. Mirrors the firmware's validation for the fields where it matters (length, IATA, owner key, port, radio combo).""" + if key == "wifi.pwd" and (len(val) > 64 or (len(val) == 64 and not _hex64(val))): + return False, "Error: WiFi password must be 0-63 characters or 64 hex characters" # length guard for the plain string fields if key in LEN_LIMITS and len(val) > LEN_LIMITS[key]: return False, "Error: %s too long (max %d chars)" % (key, LEN_LIMITS[key]) diff --git a/src/helpers/CLICommandUtils.h b/src/helpers/CLICommandUtils.h index b860397a..093be2cb 100644 --- a/src/helpers/CLICommandUtils.h +++ b/src/helpers/CLICommandUtils.h @@ -454,8 +454,32 @@ inline bool standaloneWiFiSSIDValid(const char* value) { return len >= 1 && len <= 31; } +// Observer settings may need a live bridge restart, but an allocated bridge +// object can remain present after `bridge.enabled` is turned off. Never invoke +// restart in that state: doing so would start runtime services while the saved +// enabled flag still says off. Propagate a real restart failure when enabled. +template +inline bool restartBridgeIfEnabled(bool bridge_enabled, RestartFn restart) { + return !bridge_enabled || restart(); +} + inline bool standaloneWiFiPasswordValid(const char* value) { - return value != nullptr && strlen(value) <= 63; + if (value == nullptr) return false; + const size_t len = strlen(value); + if (len <= 63) return true; + if (len != 64) return false; + // IEEE 802.11 permits a 64-character WPA/WPA2 PSK only in its raw + // hexadecimal form. Ordinary passphrases retain the historical 0-63 + // character behavior above. + for (size_t i = 0; i < len; i++) { + const char c = value[i]; + if (!((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F'))) { + return false; + } + } + return true; } inline bool parseStandaloneWiFiPowerSave(const char* value, diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index f9681602..0028fbf8 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -60,6 +60,9 @@ static void resetToUf2Bootloader() { #else #include // mallinfo() for the `memory` command on nRF52/RP2040 #endif +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW +#include +#endif #if defined(STM32_PLATFORM) #include #endif @@ -779,6 +782,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) { #else _prefs->bridge_uart = 0; #endif + _prefs->bridge_format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; #ifdef WITH_MQTT_BRIDGE bool node_prefs_needs_migration = false; @@ -1277,6 +1281,10 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { #if defined(WITH_RS232_BRIDGE) && defined(RS232_BRIDGE_MERGED) has_runtime_bridge_uart = true; #endif + if (file.available() >= (int)sizeof(_prefs->bridge_format)) { + file.read((uint8_t *)&_prefs->bridge_format, + sizeof(_prefs->bridge_format)); + } } } } @@ -1348,7 +1356,6 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { _prefs->bridge_delay = constrain(_prefs->bridge_delay, 0, 10000); _prefs->bridge_pkt_src = constrain(_prefs->bridge_pkt_src, 0, 1); _prefs->bridge_baud = constrain(_prefs->bridge_baud, 9600, BRIDGE_MAX_BAUD); - _prefs->bridge_channel = constrain(_prefs->bridge_channel, 0, 14); #ifdef WITH_RS232_BRIDGE if (_prefs->bridge_uart != WITH_RS232_BRIDGE_UART #ifdef WITH_RS232_BRIDGE_ALT @@ -1361,6 +1368,17 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { #else _prefs->bridge_uart = 0; #endif + if (!mesh::bridge::isValidEspNowFormat(_prefs->bridge_format)) { + _prefs->bridge_format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; + _com_prefs_needs_upgrade = true; + } +#ifdef WITH_ESPNOW_BRIDGE + if (!mesh::bridge::isValidEspNowBridgeChannel( + _prefs->bridge_channel, _prefs->bridge_format)) { + _prefs->bridge_channel = 1; + _com_prefs_needs_upgrade = true; + } +#endif _prefs->powersaving_enabled = constrain(_prefs->powersaving_enabled, 0, 1); _prefs->reboot_interval = constrain(_prefs->reboot_interval, 0, 255); @@ -1581,6 +1599,7 @@ static bool writeCommonPrefsImage(Writer& writer, NodePrefs* prefs) { WRITE_COMMON_PREFS(&prefs->radio_fem_txgain); // 860 WRITE_COMMON_PREFS(&prefs->usb_logging_enabled); // 861 WRITE_COMMON_PREFS(&prefs->bridge_uart); // 862 + WRITE_COMMON_PREFS(&prefs->bridge_format); // 863 #undef WRITE_COMMON_PREFS_BYTES #undef WRITE_COMMON_PREFS @@ -1734,7 +1753,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs, PrefsSaveRouting::Scope scope) { file.write((uint8_t *)&_prefs->radio_fem_txgain, sizeof(_prefs->radio_fem_txgain)); // 860 file.write((uint8_t *)&_prefs->usb_logging_enabled, sizeof(_prefs->usb_logging_enabled)); // 861 file.write((uint8_t *)&_prefs->bridge_uart, sizeof(_prefs->bridge_uart)); // 862 - // next: 863 + file.write((uint8_t *)&_prefs->bridge_format, sizeof(_prefs->bridge_format)); // 863 + // next: 864 #if defined(NRF52_PLATFORM) if (!file.commit()) { @@ -3137,6 +3157,34 @@ bool CommonCLI::handleSdCardGetCmd(const char* config, char* reply) { void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* reply) { const char* config = &command[4]; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (strncmp(config, "espnow.channel", 14) == 0 + && (config[14] == 0 || config[14] == ' ' || config[14] == '\t')) { + const char* value = config + 14; + while (*value == ' ' || *value == '\t') value++; + uint8_t channel = 0; + if (!mesh::wifi::parseEspNowChannel(value, channel)) { + strcpy(reply, "Error: ESP-NOW channel must be 1-13"); + } else { + // Snapshot the boot channel before writing NVS. The saved setting must + // never become the active value in this boot merely because this is the + // first policy helper reached by a CLI-only image. + const uint8_t active = mesh::wifi::activeEspNowChannel(); + if (!mesh::wifi::saveConfiguredEspNowChannel(channel)) { + strcpy(reply, "Error: failed to save ESP-NOW channel"); + } else if (channel == active) { + snprintf(reply, 160, + "OK - ESP-NOW channel %u saved and active", + (unsigned)channel); + } else { + snprintf(reply, 160, + "OK - ESP-NOW channel %u saved; active %u; reboot required", + (unsigned)channel, (unsigned)active); + } + } + return; + } +#endif #if MESH_USB_LOGGING_AVAILABLE if (strncmp(config, "usb.logging", 11) == 0 && (config[11] == 0 || config[11] == ' ' || config[11] == '\t')) { @@ -4081,9 +4129,14 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep #endif { _prefs->bridge_enabled = enable; - _callbacks->setBridgeState(_prefs->bridge_enabled); + const bool applied = _callbacks->setBridgeState(_prefs->bridge_enabled); savePrefs(); - strcpy(reply, "OK"); + if (applied) { + strcpy(reply, "OK"); + } else { + strcpy(reply, enable ? "Error: bridge failed to start; setting saved" + : "Error: bridge failed to stop; setting saved"); + } } } else if (memcmp(config, "bridge.delay ", 13) == 0) { int delay = _atoi(&config[13]); @@ -4115,9 +4168,10 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep uint32_t baud = atoi(&config[12]); if (baud >= 9600 && baud <= BRIDGE_MAX_BAUD) { _prefs->bridge_baud = (uint32_t)baud; - _callbacks->restartBridge(); + const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge(); savePrefs(); - strcpy(reply, "OK"); + strcpy(reply, applied ? "OK" + : "Error: setting saved; bridge failed to restart"); } else { sprintf(reply, "Error: baud rate must be between 9600-%d",BRIDGE_MAX_BAUD); } @@ -4144,21 +4198,28 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep #endif else { _prefs->bridge_uart = (uint8_t)uart; - _callbacks->restartBridge(); + const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge(); savePrefs(); - strcpy(reply, "OK"); + strcpy(reply, applied ? "OK" + : "Error: setting saved; bridge failed to restart"); } #endif #ifdef WITH_ESPNOW_BRIDGE } else if (memcmp(config, "bridge.channel ", 15) == 0) { - int ch = atoi(&config[15]); - if (ch > 0 && ch < 15) { - _prefs->bridge_channel = (uint8_t)ch; - _callbacks->restartBridge(); + uint8_t channel = 0; + const uint8_t max_channel = + mesh::bridge::espNowMaxChannel(_prefs->bridge_format); + if (mesh::bridge::parseEspNowBridgeChannel( + &config[15], _prefs->bridge_format, channel)) { + _prefs->bridge_channel = channel; + const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge(); savePrefs(); - strcpy(reply, "OK"); + strcpy(reply, applied ? "OK" + : "Error: setting saved; bridge failed to restart"); } else { - strcpy(reply, "Error: channel must be between 1-14"); + sprintf(reply, "Error: channel must be an integer between 1-%u for %s format", + (unsigned)max_channel, + mesh::bridge::espNowFormatName(_prefs->bridge_format)); } } else if (memcmp(config, "bridge.secret ", 14) == 0) { const char* secret = &config[14]; @@ -4166,9 +4227,29 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep sprintf(reply, "Error: secret must be 1-%u characters", (unsigned)(sizeof(_prefs->bridge_secret) - 1)); } else { StrHelper::strncpy(_prefs->bridge_secret, secret, sizeof(_prefs->bridge_secret)); - _callbacks->restartBridge(); + const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge(); savePrefs(); - strcpy(reply, "OK"); + strcpy(reply, applied ? "OK" + : "Error: setting saved; bridge failed to restart"); + } + } else if (memcmp(config, "bridge.format ", 14) == 0) { + uint8_t format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; + if (!mesh::bridge::parseEspNowFormat(&config[14], format)) { + strcpy(reply, "Error: format must be wrapped or raw"); + } else if (!mesh::bridge::isValidEspNowBridgeChannel( + _prefs->bridge_channel, format)) { + strcpy(reply, "Error: set bridge.channel to 1-13 before changing format"); + } else { + _prefs->bridge_format = format; + const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge(); + savePrefs(); + if (!applied) { + strcpy(reply, "Error: setting saved; bridge failed to restart"); + } else { + strcpy(reply, format == mesh::bridge::ESPNOW_FORMAT_RAW + ? "OK - raw MeshCore frames; bridge.secret is ignored" + : "OK - wrapped bridge frames"); + } } #endif } else if (memcmp(config, "adc.multiplier ", 15) == 0) { @@ -4226,6 +4307,19 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* reply) { const char* config = &command[4]; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (strcmp(config, "espnow.channel") == 0) { + const uint8_t saved = mesh::wifi::loadConfiguredEspNowChannel(); + const uint8_t active = mesh::wifi::activeEspNowChannel(); + if (saved == active) { + snprintf(reply, 160, "> %u (saved and active)", (unsigned)saved); + } else { + snprintf(reply, 160, "> saved %u, active %u; reboot required", + (unsigned)saved, (unsigned)active); + } + return; + } +#endif #if MESH_USB_LOGGING_AVAILABLE if (strcmp(config, "usb.logging") == 0) { snprintf(reply, 160, "> %s", @@ -4551,6 +4645,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep sprintf(reply, "> %d", (uint32_t)_prefs->bridge_channel); } else if (configKeyEquals(config, "bridge.secret")) { sprintf(reply, "> %s", _prefs->bridge_secret); + } else if (configKeyEquals(config, "bridge.format")) { + sprintf(reply, "> %s", + mesh::bridge::espNowFormatName(_prefs->bridge_format)); #endif } else if (configKeyEquals(config, "bootloader.ver")) { #ifdef NRF52_PLATFORM diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 260d7e8a..8af289e9 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -9,6 +9,7 @@ #include #include #include +#include #ifndef DEFAULT_CAD_ENABLED #define DEFAULT_CAD_ENABLED 0 @@ -147,7 +148,7 @@ public: uint16_t bridge_delay = 0; // milliseconds (default 500 ms) uint8_t bridge_pkt_src = 0; // 0 = logTx, 1 = logRx (default logRx) uint32_t bridge_baud = 0; // 9600, 19200, 38400, 57600, 115200 (default 115200) - uint8_t bridge_channel = 0; // 1-14 (ESP-NOW only) + uint8_t bridge_channel = 0; // 1-13 (ESP-NOW only) char bridge_secret[16] = {}; // for XOR encryption of bridge packets (ESP-NOW only) // Power setting uint8_t powersaving_enabled = 0; // boolean @@ -179,6 +180,9 @@ public: // Runtime UART choice for merged RS-232 repeater artifacts. Appended at // /com_prefs offset 862; single-UART builds keep their compiled port here. uint8_t bridge_uart = 0; + // ESP-NOW bridge wire format. Appended at /com_prefs offset 863; zero keeps + // existing installations on the original wrapped/checksummed/XOR format. + uint8_t bridge_format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; uint8_t retry_preset = 0; uint8_t direct_retry_attempts = 0; uint16_t direct_retry_base_ms = 0; @@ -277,6 +281,7 @@ private: def("uart", _parent->bridge_uart); def("ch", _parent->bridge_channel); def("secret", _parent->bridge_secret, sizeof(_parent->bridge_secret)); + def("format", _parent->bridge_format); def("usb_log", _parent->usb_logging_enabled); } @@ -494,12 +499,15 @@ public: // no op by default } - virtual void setBridgeState(bool enable) { + virtual bool setBridgeState(bool enable) { // no op by default + (void)enable; + return false; }; - virtual void restartBridge() { + virtual bool restartBridge() { // no op by default + return false; }; virtual void restartBridgeSlot(int slot) { diff --git a/src/helpers/CommonCLI_Observer.cpp b/src/helpers/CommonCLI_Observer.cpp index f4f94eb0..0462cd4b 100644 --- a/src/helpers/CommonCLI_Observer.cpp +++ b/src/helpers/CommonCLI_Observer.cpp @@ -22,6 +22,8 @@ #include #include #include +#include "WiFiPowerSave.h" +#include "esp32/WiFiRadioPolicy.h" #endif #if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \ (defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID)) @@ -45,6 +47,14 @@ static uint32_t _atoi(const char* sp) { } #ifdef ESP_PLATFORM +static bool observerBluetoothWiFiCoexistenceRequired() { +#if defined(BLE_PIN_CODE) && defined(WIFI_SSID) + return true; +#else + return false; +#endif +} + // Optional embedded CA bundle symbols produced by board_build.embed_files. // Weak linkage keeps non-bundle builds linkable. extern const uint8_t rootca_crt_bundle_start[] asm("_binary_src_certs_x509_crt_bundle_bin_start") __attribute__((weak)); @@ -170,6 +180,11 @@ static void formatMQTTPresetListReply(char* reply, size_t reply_size, int start) bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* config, char* reply) { #ifdef WITH_MQTT_BRIDGE bool handled = true; + const auto restart_observer_bridge = [this]() { + return mesh::cli::restartBridgeIfEnabled( + _prefs->bridge_enabled != 0, + [this]() { return _callbacks->restartBridge(); }); + }; if (memcmp(config, "snmp.community ", 15) == 0) { if (valueTooLong(&config[15], sizeof(_mqtt_prefs.snmp_community), reply, "snmp.community")) return true; StrHelper::strncpy(_mqtt_prefs.snmp_community, &config[15], sizeof(_mqtt_prefs.snmp_community)); @@ -222,8 +237,9 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf // until one is set). This keeps the pre-existing "clear IATA" capability. _mqtt_prefs.mqtt_iata[0] = '\0'; saveObserverPrefs(); - _callbacks->restartBridge(); - strcpy(reply, "OK - IATA cleared"); + strcpy(reply, restart_observer_bridge() + ? "OK - IATA cleared" + : "Error: IATA cleared; bridge failed to restart"); } else { // A region code goes straight into MQTT topic paths, so require exactly // three alphanumeric characters (real IATA codes are 3 letters, e.g. DEN). @@ -235,8 +251,9 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf _mqtt_prefs.mqtt_iata[i] = toupper(_mqtt_prefs.mqtt_iata[i]); } saveObserverPrefs(); - _callbacks->restartBridge(); - strcpy(reply, "OK"); + strcpy(reply, restart_observer_bridge() + ? "OK" + : "Error: IATA saved; bridge failed to restart"); } } } else if (memcmp(config, "mqtt.status ", 12) == 0) { @@ -268,8 +285,17 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf if (minutes >= 1 && minutes <= 60) { _mqtt_prefs.mqtt_status_interval = minutes * 60000; saveObserverPrefs(); - _callbacks->restartBridge(); - sprintf(reply, "OK - interval set to %u minutes (%lu ms), bridge restarted", minutes, (unsigned long)_mqtt_prefs.mqtt_status_interval); + if (!restart_observer_bridge()) { + strcpy(reply, "Error: interval saved; bridge failed to restart"); + } else if (_prefs->bridge_enabled) { + sprintf(reply, + "OK - interval set to %u minutes (%lu ms), bridge restarted", + minutes, (unsigned long)_mqtt_prefs.mqtt_status_interval); + } else { + sprintf(reply, + "OK - interval set to %u minutes (%lu ms), bridge disabled", + minutes, (unsigned long)_mqtt_prefs.mqtt_status_interval); + } } else { strcpy(reply, "Error: interval must be between 1-60 minutes"); } @@ -358,6 +384,17 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf } if (!valid) { strcpy(reply, "Error: must be none, min, or max"); +#ifdef ESP_PLATFORM + } else if (mesh::wifi::kPrimaryEspNowRadio + && ps_value == mesh::wifi::kPowerSaveMax) { + strcpy(reply, + "Error: power save max is unavailable while ESP-NOW is the primary radio"); + } else if (mesh::wifi::effectivePowerSave( + ps_value, observerBluetoothWiFiCoexistenceRequired(), + mesh::wifi::kPrimaryEspNowRadio) != ps_value) { + strcpy(reply, + "Error: power save none is unavailable while Bluetooth is active"); +#endif } else { _mqtt_prefs.wifi_power_save = ps_value; saveObserverPrefs(); @@ -999,6 +1036,11 @@ bool CommonCLI::handleObserverGetCmd(uint32_t sender_timestamp, const char* conf #endif } else if (memcmp(config, "wifi.powersave", 14) == 0) { uint8_t ps = _mqtt_prefs.wifi_power_save; +#ifdef ESP_PLATFORM + ps = mesh::wifi::effectivePowerSave( + ps, observerBluetoothWiFiCoexistenceRequired(), + mesh::wifi::kPrimaryEspNowRadio); +#endif const char* ps_name = (ps == 1) ? "none" : (ps == 2) ? "max" : "min"; sprintf(reply, "> %s", ps_name); } else if (memcmp(config, "timezone.offset", 15) == 0) { diff --git a/src/helpers/ESPNowRawFragmentation.h b/src/helpers/ESPNowRawFragmentation.h new file mode 100644 index 00000000..78c3b338 --- /dev/null +++ b/src/helpers/ESPNowRawFragmentation.h @@ -0,0 +1,385 @@ +#pragma once + +#include +#include +#include + +namespace mesh { +namespace espnow { + +// ESP-NOW v1 payloads are limited to 250 bytes while MeshCore's serialized +// packet length is an unsigned byte and can therefore reach 255 bytes. Keep +// ordinary packets byte-for-byte compatible and use this envelope only for +// the five otherwise-unrepresentable lengths, 251 through 255. +static constexpr size_t ESPNOW_RAW_MAX_FRAME_SIZE = 250; +static constexpr size_t ESPNOW_RAW_MAX_PACKET_SIZE = 255; +static constexpr size_t ESPNOW_RAW_SOURCE_MAC_SIZE = 6; +static constexpr uint8_t ESPNOW_RAW_FRAGMENT_COUNT = 2; +static constexpr uint8_t ESPNOW_RAW_FRAGMENT_VERSION = 1; + +// 0xFE has MeshCore payload-version bits 0b11. Current MeshCore receivers +// reject every such packet before parsing its route or payload, so this marker +// cannot collide with a valid serialized MeshCore packet. This deliberately +// reserves every raw frame beginning with 0xFE for fragmentation until a +// future MeshCore wire-version change revises the reservation. The following +// MCF bytes and explicit version make malformed envelopes fail closed. +static constexpr uint8_t ESPNOW_RAW_FRAGMENT_MAGIC[] = { + 0xFE, 0x4D, 0x43, 0x46}; // unsupported MeshCore version, "MCF" +static constexpr size_t ESPNOW_RAW_FRAGMENT_MAGIC_SIZE = + sizeof(ESPNOW_RAW_FRAGMENT_MAGIC); + +// Fragment header, all multi-byte fields in network byte order: +// magic[4], version, count, index, total_len, offset, crc32[4] +// Fragment zero carries a full 237-byte body. Fragment one carries the +// remaining 14-18 bytes. Both frames therefore fit ESP-NOW's 250-byte limit. +static constexpr size_t ESPNOW_RAW_FRAGMENT_HEADER_SIZE = 13; +static constexpr size_t ESPNOW_RAW_FRAGMENT_DATA_SIZE = + ESPNOW_RAW_MAX_FRAME_SIZE - ESPNOW_RAW_FRAGMENT_HEADER_SIZE; + +static_assert(ESPNOW_RAW_FRAGMENT_DATA_SIZE < ESPNOW_RAW_MAX_FRAME_SIZE, + "ESP-NOW fragment header must leave room for data"); +static_assert(ESPNOW_RAW_FRAGMENT_DATA_SIZE * ESPNOW_RAW_FRAGMENT_COUNT >= + ESPNOW_RAW_MAX_PACKET_SIZE, + "two ESP-NOW fragments must hold one maximum MeshCore packet"); + +struct ESPNowRawFrames { + uint8_t count; + uint16_t lengths[ESPNOW_RAW_FRAGMENT_COUNT]; + uint8_t data[ESPNOW_RAW_FRAGMENT_COUNT][ESPNOW_RAW_MAX_FRAME_SIZE]; + + ESPNowRawFrames() : count(0), lengths{0, 0}, data{} {} +}; + +inline uint32_t espNowRawCrc32(const uint8_t* data, size_t len) { + if (data == nullptr && len != 0) return 0; + + uint32_t crc = 0xFFFFFFFFUL; + for (size_t i = 0; i < len; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + const uint32_t mask = 0U - (crc & 1U); + crc = (crc >> 1) ^ (0xEDB88320UL & mask); + } + } + return ~crc; +} + +inline void writeEspNowRawUint32(uint8_t* dest, uint32_t value) { + dest[0] = static_cast(value >> 24); + dest[1] = static_cast(value >> 16); + dest[2] = static_cast(value >> 8); + dest[3] = static_cast(value); +} + +inline uint32_t readEspNowRawUint32(const uint8_t* src) { + return (static_cast(src[0]) << 24) + | (static_cast(src[1]) << 16) + | (static_cast(src[2]) << 8) + | static_cast(src[3]); +} + +/** + * Encode one serialized MeshCore packet for raw ESP-NOW transport. + * + * Packets up to 250 bytes produce one exact, unwrapped frame. Only packets + * from 251 through 255 bytes produce the versioned two-frame envelope. + * `frames.count` is zero on every failure. + */ +inline bool encodeEspNowRawFrames(const uint8_t* packet, size_t packet_len, + ESPNowRawFrames& frames) { + frames.count = 0; + frames.lengths[0] = 0; + frames.lengths[1] = 0; + + if (packet == nullptr || packet_len < 2 + || packet_len > ESPNOW_RAW_MAX_PACKET_SIZE) { + return false; + } + + if (packet_len <= ESPNOW_RAW_MAX_FRAME_SIZE) { + memcpy(frames.data[0], packet, packet_len); + frames.lengths[0] = static_cast(packet_len); + frames.count = 1; + return true; + } + + const uint32_t checksum = espNowRawCrc32(packet, packet_len); + for (uint8_t index = 0; index < ESPNOW_RAW_FRAGMENT_COUNT; ++index) { + const size_t offset = index == 0 ? 0 : ESPNOW_RAW_FRAGMENT_DATA_SIZE; + const size_t remaining = packet_len - offset; + const size_t body_len = remaining < ESPNOW_RAW_FRAGMENT_DATA_SIZE + ? remaining : ESPNOW_RAW_FRAGMENT_DATA_SIZE; + uint8_t* frame = frames.data[index]; + + memcpy(frame, ESPNOW_RAW_FRAGMENT_MAGIC, + ESPNOW_RAW_FRAGMENT_MAGIC_SIZE); + frame[4] = ESPNOW_RAW_FRAGMENT_VERSION; + frame[5] = ESPNOW_RAW_FRAGMENT_COUNT; + frame[6] = index; + frame[7] = static_cast(packet_len); + frame[8] = static_cast(offset); + writeEspNowRawUint32(frame + 9, checksum); + memcpy(frame + ESPNOW_RAW_FRAGMENT_HEADER_SIZE, packet + offset, + body_len); + frames.lengths[index] = static_cast( + ESPNOW_RAW_FRAGMENT_HEADER_SIZE + body_len); + } + frames.count = ESPNOW_RAW_FRAGMENT_COUNT; + return true; +} + +enum class ESPNowRawReassemblyResult : uint8_t { + PASSTHROUGH, + FRAGMENT_STORED, + PACKET_COMPLETE, + DUPLICATE, + REJECTED, + OUTPUT_TOO_SMALL, +}; + +/** + * Fixed-storage ESP-NOW raw-packet reassembler. + * + * Slots are keyed by source MAC, complete-packet CRC, and packet length. + * Fragments may arrive in either order. Identical fragments are harmless; + * conflicting duplicates and malformed envelopes are rejected without + * replacing a valid fragment. Completed identities are remembered until the + * same timeout while their bounded slot remains resident; under slot pressure, + * delivered duplicate-cache entries are evicted before in-flight assemblies. + */ +template +class ESPNowRawReassemblerT { + public: + static_assert(SlotCount > 0, "ESP-NOW reassembly needs at least one slot"); + + explicit ESPNowRawReassemblerT(uint32_t timeout_ms = 2000) + : _timeout_ms(timeout_ms) { + reset(); + } + + void reset() { + memset(_slots, 0, sizeof(_slots)); + } + + size_t expire(uint32_t now_ms) { + size_t expired = 0; + for (size_t i = 0; i < SlotCount; ++i) { + if (_slots[i].state != SLOT_EMPTY + && elapsed(now_ms, _slots[i].updated_ms) >= _timeout_ms) { + clearSlot(_slots[i]); + ++expired; + } + } + return expired; + } + + ESPNowRawReassemblyResult acceptFrame( + const uint8_t source_mac[ESPNOW_RAW_SOURCE_MAC_SIZE], + const uint8_t* frame, size_t frame_len, uint32_t now_ms, + uint8_t* packet_out, size_t packet_capacity, size_t& packet_len) { + packet_len = 0; + expire(now_ms); + + if (frame == nullptr || frame_len == 0 + || frame_len > ESPNOW_RAW_MAX_FRAME_SIZE) { + return ESPNowRawReassemblyResult::REJECTED; + } + + // Valid current MeshCore packets can never begin with 0xFE. Reserve that + // entire prefix so truncated or corrupted envelopes cannot be handed to + // the ordinary MeshCore parser as if they were legacy raw frames. + if (frame[0] != ESPNOW_RAW_FRAGMENT_MAGIC[0]) { + if (packet_out == nullptr || packet_capacity < frame_len) { + return ESPNowRawReassemblyResult::OUTPUT_TOO_SMALL; + } + memcpy(packet_out, frame, frame_len); + packet_len = frame_len; + return ESPNowRawReassemblyResult::PASSTHROUGH; + } + + FragmentInfo fragment; + if (source_mac == nullptr || !parseFragment(frame, frame_len, fragment)) { + return ESPNowRawReassemblyResult::REJECTED; + } + + Slot* slot = findSlot(source_mac, fragment.total_len, fragment.checksum); + if (slot == nullptr) { + slot = allocateSlot(now_ms); + initializeSlot(*slot, source_mac, fragment.total_len, + fragment.checksum, now_ms); + } + + const uint8_t bit = static_cast(1U << fragment.index); + if ((slot->received_mask & bit) != 0) { + if (memcmp(slot->packet + fragment.offset, fragment.body, + fragment.body_len) != 0) { + return ESPNowRawReassemblyResult::REJECTED; + } + return ESPNowRawReassemblyResult::DUPLICATE; + } + if (slot->state == SLOT_DELIVERED) { + // A delivered slot necessarily has both bits, but fail closed if its + // metadata was ever corrupted rather than writing into it again. + return ESPNowRawReassemblyResult::REJECTED; + } + + memcpy(slot->packet + fragment.offset, fragment.body, fragment.body_len); + slot->received_mask = static_cast(slot->received_mask | bit); + slot->updated_ms = now_ms; + + const uint8_t all_fragments = + static_cast((1U << ESPNOW_RAW_FRAGMENT_COUNT) - 1U); + if (slot->received_mask != all_fragments) { + return ESPNowRawReassemblyResult::FRAGMENT_STORED; + } + + if (espNowRawCrc32(slot->packet, slot->total_len) != slot->checksum) { + clearSlot(*slot); + return ESPNowRawReassemblyResult::REJECTED; + } + if (packet_out == nullptr || packet_capacity < slot->total_len) { + clearSlot(*slot); + return ESPNowRawReassemblyResult::OUTPUT_TOO_SMALL; + } + + memcpy(packet_out, slot->packet, slot->total_len); + packet_len = slot->total_len; + slot->state = SLOT_DELIVERED; + slot->updated_ms = now_ms; + return ESPNowRawReassemblyResult::PACKET_COMPLETE; + } + + private: + enum SlotState : uint8_t { + SLOT_EMPTY = 0, + SLOT_ASSEMBLING = 1, + SLOT_DELIVERED = 2, + }; + + struct FragmentInfo { + uint8_t index; + uint8_t total_len; + uint8_t offset; + uint32_t checksum; + const uint8_t* body; + size_t body_len; + }; + + struct Slot { + SlotState state; + uint8_t source_mac[ESPNOW_RAW_SOURCE_MAC_SIZE]; + uint8_t total_len; + uint8_t received_mask; + uint32_t checksum; + uint32_t updated_ms; + uint8_t packet[ESPNOW_RAW_MAX_PACKET_SIZE]; + }; + + static uint32_t elapsed(uint32_t now_ms, uint32_t then_ms) { + return static_cast(now_ms - then_ms); + } + + static void clearSlot(Slot& slot) { + slot.state = SLOT_EMPTY; + slot.received_mask = 0; + } + + static bool parseFragment(const uint8_t* frame, size_t frame_len, + FragmentInfo& fragment) { + if (frame_len < ESPNOW_RAW_FRAGMENT_HEADER_SIZE + || memcmp(frame, ESPNOW_RAW_FRAGMENT_MAGIC, + ESPNOW_RAW_FRAGMENT_MAGIC_SIZE) != 0 + || frame[4] != ESPNOW_RAW_FRAGMENT_VERSION + || frame[5] != ESPNOW_RAW_FRAGMENT_COUNT + || frame[6] >= ESPNOW_RAW_FRAGMENT_COUNT + || frame[7] <= ESPNOW_RAW_MAX_FRAME_SIZE + || frame[7] > ESPNOW_RAW_MAX_PACKET_SIZE) { + return false; + } + + fragment.index = frame[6]; + fragment.total_len = frame[7]; + fragment.offset = frame[8]; + fragment.checksum = readEspNowRawUint32(frame + 9); + fragment.body = frame + ESPNOW_RAW_FRAGMENT_HEADER_SIZE; + fragment.body_len = frame_len - ESPNOW_RAW_FRAGMENT_HEADER_SIZE; + + const size_t expected_offset = fragment.index == 0 + ? 0 : ESPNOW_RAW_FRAGMENT_DATA_SIZE; + const size_t expected_body_len = fragment.index == 0 + ? ESPNOW_RAW_FRAGMENT_DATA_SIZE + : static_cast(fragment.total_len) + - ESPNOW_RAW_FRAGMENT_DATA_SIZE; + return fragment.offset == expected_offset + && fragment.body_len == expected_body_len + && static_cast(fragment.offset) + fragment.body_len + <= fragment.total_len; + } + + Slot* findSlot(const uint8_t* source_mac, uint8_t total_len, + uint32_t checksum) { + for (size_t i = 0; i < SlotCount; ++i) { + Slot& slot = _slots[i]; + if (slot.state != SLOT_EMPTY && slot.total_len == total_len + && slot.checksum == checksum + && memcmp(slot.source_mac, source_mac, + ESPNOW_RAW_SOURCE_MAC_SIZE) == 0) { + return &slot; + } + } + return nullptr; + } + + Slot* allocateSlot(uint32_t now_ms) { + for (size_t i = 0; i < SlotCount; ++i) { + if (_slots[i].state == SLOT_EMPTY) return &_slots[i]; + } + + // Delivered identities are only a duplicate-suppression cache, so evict + // the oldest of those before sacrificing an in-flight reassembly. + Slot* candidate = nullptr; + uint32_t candidate_age = 0; + for (size_t i = 0; i < SlotCount; ++i) { + Slot& slot = _slots[i]; + if (slot.state != SLOT_DELIVERED) continue; + const uint32_t age = elapsed(now_ms, slot.updated_ms); + if (candidate == nullptr || age > candidate_age) { + candidate = &slot; + candidate_age = age; + } + } + if (candidate != nullptr) return candidate; + + // If every bounded slot is assembling, retain the freshest work and + // replace the oldest. No input can grow memory usage beyond SlotCount. + candidate = &_slots[0]; + candidate_age = elapsed(now_ms, candidate->updated_ms); + for (size_t i = 1; i < SlotCount; ++i) { + const uint32_t age = elapsed(now_ms, _slots[i].updated_ms); + if (age > candidate_age) { + candidate = &_slots[i]; + candidate_age = age; + } + } + return candidate; + } + + static void initializeSlot(Slot& slot, const uint8_t* source_mac, + uint8_t total_len, uint32_t checksum, + uint32_t now_ms) { + slot.state = SLOT_ASSEMBLING; + memcpy(slot.source_mac, source_mac, ESPNOW_RAW_SOURCE_MAC_SIZE); + slot.total_len = total_len; + slot.received_mask = 0; + slot.checksum = checksum; + slot.updated_ms = now_ms; + } + + uint32_t _timeout_ms; + Slot _slots[SlotCount]; +}; + +using ESPNowRawReassembler = ESPNowRawReassemblerT<4>; + +} // namespace espnow +} // namespace mesh diff --git a/src/helpers/UsbAsciiBinarySwitch.h b/src/helpers/UsbAsciiBinarySwitch.h index f4ee9625..90468133 100644 --- a/src/helpers/UsbAsciiBinarySwitch.h +++ b/src/helpers/UsbAsciiBinarySwitch.h @@ -89,6 +89,33 @@ public: bool isBorrowingAscii() const { return _restore_ascii; } }; +// Keeps the single-TTY logging transitions independent from the platform's +// stream objects. In particular, an active TCP terminal owns the role CLI and +// must not be displaced just because USB logging is enabled. +enum class UsbLoggingTerminalAction : uint8_t { + NONE, + CLAIM_USB, + RETURN_TO_BINARY, + KEEP_ASCII, +}; + +inline UsbLoggingTerminalAction selectUsbLoggingTerminalAction( + bool has_dedicated_logging_port, bool logging_enabled, + bool usb_terminal_active, bool usb_logging_terminal_active, + bool full_companion, bool network_terminal_active) { + if (has_dedicated_logging_port || network_terminal_active) { + return UsbLoggingTerminalAction::NONE; + } + if (logging_enabled) { + return UsbLoggingTerminalAction::CLAIM_USB; + } + if (!usb_terminal_active || !usb_logging_terminal_active) { + return UsbLoggingTerminalAction::NONE; + } + return full_companion ? UsbLoggingTerminalAction::KEEP_ASCII + : UsbLoggingTerminalAction::RETURN_TO_BINARY; +} + enum class UsbMotaEntryOrigin : uint8_t { BINARY, ASCII }; inline bool shouldRestoreAsciiAfterMotaFailure(UsbMotaEntryOrigin origin) { diff --git a/src/helpers/WebConfigBatch.h b/src/helpers/WebConfigBatch.h index a6d5055b..5bd0868f 100644 --- a/src/helpers/WebConfigBatch.h +++ b/src/helpers/WebConfigBatch.h @@ -156,15 +156,20 @@ static inline uint32_t finishRebootAt(bool batch_reboot, bool batch_all_ok, uint // A successful setup-portal save that changes station credentials is held in // Pending while AP+STA joins the selected network. That makes the DHCP address -// available to the captive page before its setup AP disappears. Other saves -// keep the ordinary batch/reboot path. +// available to the captive page before its setup AP disappears. When the +// shared ESP-NOW channel changes, the station must remain on the old boot +// channel until reboot, so credentials are applied together on the next boot +// instead of attempting this live handoff. Other saves keep the ordinary +// batch/reboot path. static inline bool shouldStartSetupWiFiHandoff(bool setup_mode, bool batch_reboot, bool batch_all_ok, bool wifi_credentials_changed, - bool has_wifi_ssid) { + bool has_wifi_ssid, + bool espnow_channel_changed) { return setup_mode && batch_reboot && batch_all_ok - && wifi_credentials_changed && has_wifi_ssid; + && wifi_credentials_changed && has_wifi_ssid + && !espnow_channel_changed; } static inline uint32_t setupWiFiConnectDeadline(uint32_t now) { diff --git a/src/helpers/WebConfigKeys.h b/src/helpers/WebConfigKeys.h index 4ad4658c..3e156d65 100644 --- a/src/helpers/WebConfigKeys.h +++ b/src/helpers/WebConfigKeys.h @@ -24,7 +24,7 @@ static const char* const WC_ALLOWED_SET_KEYS[] = { "advert.interval", "flood.advert.interval", "flood.max", "flood.max.advert", "flood.max.unscoped", "loop.detect", // MQTTPrefs (WiFi / MQTT / misc observer) - "wifi.ssid", "wifi.pwd", "wifi.powersave", + "wifi.ssid", "wifi.pwd", "wifi.powersave", "espnow.channel", "mqtt.origin", "mqtt.iata", "mqtt.status", "mqtt.packets", "mqtt.raw", "mqtt.tx", "mqtt.rx", "mqtt.interval", "mqtt.neighbors", "mqtt.neighbors.interval", "mqtt.ntp", "mqtt.owner", "mqtt.email", @@ -57,6 +57,14 @@ static inline bool wcIsAllowedSetKey(const char* key) { return false; } +// Changing the primary ESP-NOW channel cannot be applied live: every peer and +// any infrastructure-WiFi association must stay on the boot channel until the +// node restarts. The server enforces this even when a crafted client omits the +// browser's reboot flag. +static inline bool wcSetKeyRequiresReboot(const char* key) { + return key != NULL && strcmp(key, "espnow.channel") == 0; +} + // The admin password maps to the top-level `password` command, not a setter, so // it is classified apart from the `set` allowlist. It is the only key that gets // this treatment, which is what keeps the allowlist the sole route to `set` and diff --git a/src/helpers/WiFiChannelPolicy.h b/src/helpers/WiFiChannelPolicy.h new file mode 100644 index 00000000..a6bd4d8b --- /dev/null +++ b/src/helpers/WiFiChannelPolicy.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace mesh { +namespace wifi { + +// ESP-NOW primary-radio targets use the 2.4 GHz channel range that can also +// carry ordinary b/g/n WiFi. Channel 14 is deliberately excluded: it is +// country-specific and restricted to 802.11b, so it cannot satisfy the shared +// b/g/n+LR coexistence policy used by Full builds. +static constexpr uint8_t kEspNowChannelMin = 1; +static constexpr uint8_t kEspNowChannelMax = 13; + +inline bool isValidEspNowChannel(unsigned long channel) { + return channel >= kEspNowChannelMin && channel <= kEspNowChannelMax; +} + +// Strict whole-value parser for CLI and WebConfig input. Whitespace around the +// decimal channel is accepted; signs, decimal points, and trailing text are +// rejected so a malformed request cannot silently select a different channel. +inline bool parseEspNowChannel(const char* value, uint8_t& channel) { + if (value == nullptr) return false; + while (*value == ' ' || *value == '\t') value++; + if (*value < '0' || *value > '9') return false; + + unsigned long parsed = 0; + do { + parsed = parsed * 10UL + static_cast(*value - '0'); + if (parsed > kEspNowChannelMax) return false; + value++; + } while (*value >= '0' && *value <= '9'); + + while (*value == ' ' || *value == '\t') value++; + if (*value != 0 || !isValidEspNowChannel(parsed)) return false; + channel = static_cast(parsed); + return true; +} + +inline uint8_t validEspNowChannelOrDefault(uint8_t stored, + uint8_t fallback) { + return isValidEspNowChannel(stored) ? stored : fallback; +} + +} // namespace wifi +} // namespace mesh diff --git a/src/helpers/WiFiPowerSave.h b/src/helpers/WiFiPowerSave.h index 1d18ce97..28eaec61 100644 --- a/src/helpers/WiFiPowerSave.h +++ b/src/helpers/WiFiPowerSave.h @@ -22,10 +22,16 @@ static constexpr uint8_t kPowerSaveMax = 2; static constexpr uint8_t kDefaultPowerSave = DEFAULT_WIFI_POWER_SAVE_MODE; // ESP32 WiFi and Bluetooth coexistence requires modem sleep, so "none" must -// fall back to the minimum sleep policy whenever Bluetooth is active. +// fall back to the minimum sleep policy whenever Bluetooth is active. A +// primary ESP-NOW receiver must also avoid maximum modem sleep: infrastructure +// access points do not buffer ESP-NOW broadcasts while the station is asleep. inline uint8_t effectivePowerSave(uint8_t configured, - bool bluetooth_active) { + bool bluetooth_active, + bool primary_espnow_active = false) { if (configured > kPowerSaveMax) configured = kDefaultPowerSave; + if (primary_espnow_active && configured == kPowerSaveMax) { + configured = kPowerSaveMin; + } return bluetooth_active && configured == kPowerSaveNone ? kPowerSaveMin : configured; } diff --git a/src/helpers/WiFiSetupPortal.cpp b/src/helpers/WiFiSetupPortal.cpp index 17d71c3b..d0f947d8 100644 --- a/src/helpers/WiFiSetupPortal.cpp +++ b/src/helpers/WiFiSetupPortal.cpp @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include namespace { @@ -28,8 +31,8 @@ button{margin-top:1.2rem}small{color:#555}

MeshCore WiFi setup

Enter the WiFi network this node should join.

- -Leave the password blank for an open network. + +Leave blank for an open network. A 64-character key must be hexadecimal.
)HTML"; struct PortalImpl { @@ -42,7 +45,7 @@ struct PortalImpl { uint32_t close_ap_at = 0; char ap_name[33] = "MeshCore-Setup"; char recovery_ssid[32] = ""; - char recovery_password[64] = ""; + char recovery_password[65] = ""; uint32_t recovery_interval_ms = 0; uint32_t next_recovery_at = 0; uint32_t recovery_deadline = 0; @@ -114,7 +117,7 @@ static bool getFormField(const char* body, const char* name, while (field && *field) { const char* end = strchr(field, '&'); size_t field_len = end ? static_cast(end - field) : strlen(field); - if (field_len > name_len + 1 && field[name_len] == '=' + if (field_len >= name_len + 1 && field[name_len] == '=' && strncmp(field, name, name_len) == 0) { return decodeFormValue(field + name_len + 1, field_len - name_len - 1, output, output_size); @@ -125,22 +128,53 @@ static bool getFormField(const char* body, const char* name, return false; } +static bool hasFormField(const char* body, const char* name) { + if (!body || !name) return false; + const size_t name_len = strlen(name); + const char* field = body; + while (*field) { + const char* end = strchr(field, '&'); + const size_t field_len = end + ? static_cast(end - field) : strlen(field); + if (field_len >= name_len + 1 && field[name_len] == '=' + && strncmp(field, name, name_len) == 0) { + return true; + } + field = end ? end + 1 : nullptr; + if (!field) break; + } + return false; +} + static void handleSave(PortalImpl* impl, WiFiClient& client, const char* body) { char ssid[32]; - char password[64]; + char password[65]; if (!getFormField(body, "ssid", ssid, sizeof(ssid)) || ssid[0] == 0) { sendResponse(client, 400, "Bad Request", "text/plain", "A valid SSID is required."); return; } // Browsers omit an empty password only if the form is modified. Treat either // an empty field or an absent one as an open network. - if (!getFormField(body, "password", password, sizeof(password))) password[0] = 0; + if (hasFormField(body, "password")) { + if (!getFormField(body, "password", password, sizeof(password))) { + sendResponse(client, 400, "Bad Request", "text/plain", + "WiFi password must be 0-63 characters or exactly 64 hexadecimal characters."); + return; + } + } else { + password[0] = 0; + } + if (!mesh::cli::standaloneWiFiPasswordValid(password)) { + sendResponse(client, 400, "Bad Request", "text/plain", + "WiFi password must be 0-63 characters or exactly 64 hexadecimal characters."); + return; + } // A submitted configuration takes priority over a background retry of the // previously saved network. impl->recovery_connecting = false; Serial.printf("WiFi setup: connecting to '%s'...\n", ssid); - WiFi.begin(ssid, password); + mesh::wifi::beginStation(ssid, password); uint32_t deadline = millis() + CONNECT_TIMEOUT_MS; while (impl->active && *impl->active && WiFi.status() != WL_CONNECTED && static_cast(millis() - deadline) < 0) { @@ -250,7 +284,8 @@ static void portalTask(void* arg) { } else if (impl->recovery_ssid[0] && impl->recovery_interval_ms && static_cast(now - impl->next_recovery_at) >= 0) { Serial.printf("WiFi setup: retrying saved network '%s'...\n", impl->recovery_ssid); - WiFi.begin(impl->recovery_ssid, impl->recovery_password); + mesh::wifi::beginStation( + impl->recovery_ssid, impl->recovery_password); impl->recovery_connecting = true; impl->recovery_deadline = now + CONNECT_TIMEOUT_MS; impl->next_recovery_at = now + impl->recovery_interval_ms; @@ -297,14 +332,15 @@ bool WiFiSetupPortal::begin(const char* ap_name, SaveCallback save_callback, voi WiFi.mode(WIFI_AP_STA); if (!WiFi.softAPConfig(SETUP_IP, SETUP_IP, SETUP_MASK) - || !WiFi.softAP(impl->ap_name, nullptr) + || !WiFi.softAP(impl->ap_name, nullptr, + mesh::wifi::accessPointChannel()) || esp_wifi_set_protocol( WIFI_IF_AP, - WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) + mesh::wifi::kProtocolMask) != ESP_OK || esp_wifi_set_protocol( WIFI_IF_STA, - WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) + mesh::wifi::kProtocolMask) != ESP_OK) { WiFi.softAPdisconnect(true); return false; @@ -366,7 +402,8 @@ bool WiFiSetupPortal::loadStoredCredentials(char* ssid, size_t ssid_size, String stored_password = prefs.getString("password", ""); prefs.end(); if (stored_ssid.length() == 0 || stored_ssid.length() >= ssid_size - || stored_password.length() >= password_size) return false; + || stored_password.length() >= password_size + || !mesh::cli::standaloneWiFiPasswordValid(stored_password.c_str())) return false; strncpy(ssid, stored_ssid.c_str(), ssid_size - 1); ssid[ssid_size - 1] = 0; strncpy(password, stored_password.c_str(), password_size - 1); @@ -375,10 +412,11 @@ bool WiFiSetupPortal::loadStoredCredentials(char* ssid, size_t ssid_size, } bool WiFiSetupPortal::saveStoredCredentials(const char* ssid, const char* password) { - if (!ssid || !ssid[0] || strlen(ssid) > 31 || (password && strlen(password) > 63)) return false; + const char* saved_password = password ? password : ""; + if (!ssid || !ssid[0] || strlen(ssid) > 31 + || !mesh::cli::standaloneWiFiPasswordValid(saved_password)) return false; Preferences prefs; if (!prefs.begin("mesh-wifi", false)) return false; - const char* saved_password = password ? password : ""; bool ok = prefs.putString("ssid", ssid) == strlen(ssid); prefs.putString("password", saved_password); // An empty String reports zero bytes even on success. ok = ok && prefs.getString("password", "\x01") == saved_password; diff --git a/src/helpers/bridges/ESPNowBridge.cpp b/src/helpers/bridges/ESPNowBridge.cpp index 649bcabc..e7d7c528 100644 --- a/src/helpers/bridges/ESPNowBridge.cpp +++ b/src/helpers/bridges/ESPNowBridge.cpp @@ -12,13 +12,13 @@ ESPNowBridge *ESPNowBridge::_instance = nullptr; void ESPNowBridge::recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) { const uint8_t *mac = info != nullptr ? info->src_addr : nullptr; if (_instance) { - _instance->onDataRecv(mac, data, len); + _instance->queueReceivedFrame(mac, data, len); } } #else void ESPNowBridge::recv_cb(const uint8_t *mac, const uint8_t *data, int len) { if (_instance) { - _instance->onDataRecv(mac, data, len); + _instance->queueReceivedFrame(mac, data, len); } } #endif @@ -36,7 +36,12 @@ void ESPNowBridge::send_cb(const uint8_t *mac, esp_now_send_status_t status) { } ESPNowBridge::ESPNowBridge(NodePrefs *prefs, mesh::PacketManager *mgr, mesh::RTCClock *rtc) - : BridgeBase(prefs, mgr, rtc), _rx_buffer_pos(0) { + : BridgeBase(prefs, mgr, rtc), _rx_head(0), _rx_tail(0), _rx_count(0), + _rx_dropped(0), _rx_dropped_reported(0), + _tx_head(0), _tx_tail(0), _tx_count(0), _tx_waiting(false), + _tx_callback_done(false), _tx_callback_status(ESP_NOW_SEND_SUCCESS), + _tx_dropped(0), _tx_dropped_reported(0), + _active_format(mesh::bridge::ESPNOW_FORMAT_WRAPPED) { _instance = this; } @@ -45,6 +50,33 @@ void ESPNowBridge::begin() { if (_initialized) return; + _active_format = mesh::bridge::isValidEspNowFormat(_prefs->bridge_format) + ? _prefs->bridge_format : mesh::bridge::ESPNOW_FORMAT_WRAPPED; + portENTER_CRITICAL(&_rx_mux); + _rx_head = 0; + _rx_tail = 0; + _rx_count = 0; + _rx_dropped = 0; + portEXIT_CRITICAL(&_rx_mux); + _rx_dropped_reported = 0; + _raw_reassembler.reset(); + portENTER_CRITICAL(&_tx_mux); + _tx_head = 0; + _tx_tail = 0; + _tx_count = 0; + _tx_waiting = false; + _tx_callback_done = false; + _tx_callback_status = ESP_NOW_SEND_SUCCESS; + _tx_dropped = 0; + portEXIT_CRITICAL(&_tx_mux); + _tx_dropped_reported = 0; + + if (!mesh::bridge::isValidEspNowBridgeChannel( + _prefs->bridge_channel, _active_format)) { + BRIDGE_DEBUG_PRINTLN("ESP-NOW channel must be 1-13\n"); + return; + } + // ESP-NOW only needs the ESP-IDF station interface. Avoid Arduino's WiFi // facade here: it pulls DHCP, DNS, scanning, AP, and event plumbing that an // ESP-NOW-only bridge never uses. @@ -57,6 +89,21 @@ void ESPNowBridge::begin() { esp_wifi_deinit(); return; } + + const bool raw_format = + _active_format == mesh::bridge::ESPNOW_FORMAT_RAW; + if (raw_format) { + // Primary ESPNOWRadio nodes use Espressif's LR PHY. Retain B/G/N receive + // support as well, but force this peer's outgoing frames to LR below. + const uint8_t protocols = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G + | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR; + if (esp_wifi_set_protocol(WIFI_IF_STA, protocols) != ESP_OK) { + BRIDGE_DEBUG_PRINTLN("Error enabling ESP-NOW LR protocol\n"); + esp_wifi_stop(); + esp_wifi_deinit(); + return; + } + } // Set Wi-Fi channel if (esp_wifi_set_channel(_prefs->bridge_channel, WIFI_SECOND_CHAN_NONE) != ESP_OK) { @@ -90,6 +137,7 @@ void ESPNowBridge::begin() { memset(&peerInfo, 0, sizeof(peerInfo)); memset(peerInfo.peer_addr, 0xFF, ESP_NOW_ETH_ALEN); // Broadcast address peerInfo.channel = _prefs->bridge_channel; + peerInfo.ifidx = WIFI_IF_STA; peerInfo.encrypt = false; if (esp_now_add_peer(&peerInfo) != ESP_OK) { @@ -102,6 +150,31 @@ void ESPNowBridge::begin() { return; } + if (raw_format) { + esp_err_t rate_result; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) + esp_now_rate_config_t rate_config = {}; + rate_config.phymode = WIFI_PHY_MODE_LR; + rate_config.rate = WIFI_PHY_RATE_LORA_250K; + rate_config.ersu = false; + rate_config.dcm = false; + rate_result = esp_now_set_peer_rate_config(peerInfo.peer_addr, &rate_config); +#else + rate_result = esp_wifi_config_espnow_rate( + WIFI_IF_STA, WIFI_PHY_RATE_LORA_250K); +#endif + if (rate_result != ESP_OK) { + BRIDGE_DEBUG_PRINTLN("Error configuring ESP-NOW LR peer rate\n"); + esp_now_del_peer(peerInfo.peer_addr); + esp_now_register_recv_cb(nullptr); + esp_now_register_send_cb(nullptr); + esp_now_deinit(); + esp_wifi_stop(); + esp_wifi_deinit(); + return; + } + } + // Update bridge state _initialized = true; } @@ -128,12 +201,189 @@ void ESPNowBridge::end() { esp_wifi_stop(); esp_wifi_deinit(); + portENTER_CRITICAL(&_rx_mux); + _rx_head = 0; + _rx_tail = 0; + _rx_count = 0; + portEXIT_CRITICAL(&_rx_mux); + _raw_reassembler.reset(); + + // queueTransmitFrames() marks packets seen at admission so the same bridge + // loop cannot enqueue duplicates. Undo that mark for entries which never + // reached esp_now_send() before an explicit bridge stop/restart. + uint8_t tx_index = _tx_tail; + for (uint8_t i = 0; i < _tx_count; ++i) { + const QueuedTransmit& queued_tx = _tx_queue[tx_index]; + if (!queued_tx.started) _seen_packets.clear(&queued_tx.packet); + tx_index = static_cast((tx_index + 1) % TX_QUEUE_DEPTH); + } + portENTER_CRITICAL(&_tx_mux); + _tx_head = 0; + _tx_tail = 0; + _tx_count = 0; + _tx_waiting = false; + _tx_callback_done = false; + portEXIT_CRITICAL(&_tx_mux); + // Update bridge state _initialized = false; } void ESPNowBridge::loop() { - // Nothing to do here - ESP-NOW is callback based + pumpTransmitQueue(); + + uint8_t frame[MAX_ESPNOW_PACKET_SIZE]; + uint8_t source[mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE]; + for (uint8_t processed = 0; processed < RX_QUEUE_DEPTH; ++processed) { + size_t frame_len = 0; + uint32_t dropped = 0; + + portENTER_CRITICAL(&_rx_mux); + dropped = _rx_dropped; + if (_rx_count > 0) { + frame_len = _rx_lengths[_rx_tail]; + if (frame_len > 0 && frame_len <= sizeof(frame)) { + memcpy(frame, _rx_buffers[_rx_tail], frame_len); + memcpy(source, _rx_sources[_rx_tail], sizeof(source)); + } else { + frame_len = 0; + } + _rx_tail = static_cast((_rx_tail + 1) % RX_QUEUE_DEPTH); + _rx_count--; + } + portEXIT_CRITICAL(&_rx_mux); + + if (dropped != _rx_dropped_reported) { + BRIDGE_DEBUG_PRINTLN("RX queue full, dropped=%lu\n", + (unsigned long)dropped); + _rx_dropped_reported = dropped; + } + if (frame_len == 0) break; + processReceivedFrame(source, frame, frame_len); + } +} + +bool ESPNowBridge::queueTransmitFrames( + const mesh::espnow::ESPNowRawFrames& frames, + const mesh::Packet& packet) { + if (frames.count == 0 || frames.count > mesh::espnow::ESPNOW_RAW_FRAGMENT_COUNT) { + return false; + } + for (uint8_t i = 0; i < frames.count; ++i) { + if (frames.lengths[i] == 0 + || frames.lengths[i] > MAX_ESPNOW_PACKET_SIZE) { + return false; + } + } + + bool queued = false; + portENTER_CRITICAL(&_tx_mux); + if (_tx_count < TX_QUEUE_DEPTH) { + QueuedTransmit& queued_tx = _tx_queue[_tx_head]; + queued_tx.frames = frames; + queued_tx.packet = packet; + queued_tx.next_frame = 0; + queued_tx.started = false; + _tx_head = static_cast((_tx_head + 1) % TX_QUEUE_DEPTH); + _tx_count++; + queued = true; + } else { + _tx_dropped++; + } + portEXIT_CRITICAL(&_tx_mux); + return queued; +} + +void ESPNowBridge::pumpTransmitQueue() { + uint8_t frame[MAX_ESPNOW_PACKET_SIZE]; + uint16_t frame_len = 0; + bool completed = false; + int completed_status = ESP_NOW_SEND_SUCCESS; + bool clear_unsent_seen = false; + mesh::Packet unsent_packet; + uint32_t dropped = 0; + + portENTER_CRITICAL(&_tx_mux); + dropped = _tx_dropped; + if (_tx_waiting && _tx_callback_done) { + completed = true; + completed_status = _tx_callback_status; + _tx_waiting = false; + _tx_callback_done = false; + + if (_tx_count > 0) { + QueuedTransmit& queued_tx = _tx_queue[_tx_tail]; + if (completed_status == ESP_NOW_SEND_SUCCESS) { + queued_tx.next_frame++; + if (queued_tx.next_frame >= queued_tx.frames.count) { + _tx_tail = static_cast( + (_tx_tail + 1) % TX_QUEUE_DEPTH); + _tx_count--; + } + } else { + // esp_now_send() accepted at least one frame, matching the old bridge + // definition of "seen", but never submit any remaining fragments from + // a logical packet whose preceding frame failed. + _tx_tail = static_cast((_tx_tail + 1) % TX_QUEUE_DEPTH); + _tx_count--; + } + } + } + if (!_tx_waiting && _tx_count > 0) { + QueuedTransmit& queued_tx = _tx_queue[_tx_tail]; + if (queued_tx.next_frame < queued_tx.frames.count) { + frame_len = queued_tx.frames.lengths[queued_tx.next_frame]; + if (frame_len > 0 && frame_len <= sizeof(frame)) { + memcpy(frame, queued_tx.frames.data[queued_tx.next_frame], frame_len); + } else { + frame_len = 0; + } + } + if (frame_len > 0) { + _tx_waiting = true; + _tx_callback_done = false; + } + } + portEXIT_CRITICAL(&_tx_mux); + + if (dropped != _tx_dropped_reported) { + BRIDGE_DEBUG_PRINTLN("TX queue full, dropped=%lu\n", + (unsigned long)dropped); + _tx_dropped_reported = dropped; + } + if (completed && completed_status != ESP_NOW_SEND_SUCCESS) { + BRIDGE_DEBUG_PRINTLN("TX callback failed, status=%d\n", + completed_status); + } + if (frame_len == 0) return; + + static const uint8_t broadcast_address[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + const esp_err_t result = esp_now_send( + broadcast_address, frame, frame_len); + if (result != ESP_OK) { + portENTER_CRITICAL(&_tx_mux); + _tx_waiting = false; + _tx_callback_done = false; + if (_tx_count > 0) { + QueuedTransmit& queued_tx = _tx_queue[_tx_tail]; + if (!queued_tx.started) { + unsent_packet = queued_tx.packet; + clear_unsent_seen = true; + } + _tx_tail = static_cast((_tx_tail + 1) % TX_QUEUE_DEPTH); + _tx_count--; + } + portEXIT_CRITICAL(&_tx_mux); + // Admission marks the packet to suppress duplicate queue entries. Restore + // the prior behavior when even its first esp_now_send() cannot start. + if (clear_unsent_seen) _seen_packets.clear(&unsent_packet); + BRIDGE_DEBUG_PRINTLN("TX failed to start, error=%d\n", (int)result); + } else { + portENTER_CRITICAL(&_tx_mux); + if (_tx_count > 0) _tx_queue[_tx_tail].started = true; + portEXIT_CRITICAL(&_tx_mux); + } } bool ESPNowBridge::xorCrypt(uint8_t *data, size_t len) { @@ -149,16 +399,84 @@ bool ESPNowBridge::xorCrypt(uint8_t *data, size_t len) { return true; } -void ESPNowBridge::onDataRecv(const uint8_t *mac, const uint8_t *data, int len) { - // Ignore packets that are too small to contain header + checksum - if (len < (BRIDGE_MAGIC_SIZE + BRIDGE_CHECKSUM_SIZE)) { - BRIDGE_DEBUG_PRINTLN("RX packet too small, len=%d\n", len); +void ESPNowBridge::receiveMeshPacket(const uint8_t *data, size_t len) { + mesh::Packet *pkt = _mgr->allocNew(); + if (!pkt) return; + + if (pkt->readFrom(data, len)) { + onPacketReceived(pkt); + } else { + _mgr->free(pkt); + } +} + +void ESPNowBridge::queueReceivedFrame(const uint8_t *mac, const uint8_t *data, + int len) { + if (data == nullptr || len <= 0 || len > MAX_ESPNOW_PACKET_SIZE) { return; } - // Validate total packet size - if (len > MAX_ESPNOW_PACKET_SIZE) { - BRIDGE_DEBUG_PRINTLN("RX packet too large, len=%d\n", len); + // Wrapped deployments share the WiFi channel with unrelated ESP-NOW users. + // Reject obvious foreign traffic before it can occupy a queue slot. + if (_active_format == mesh::bridge::ESPNOW_FORMAT_WRAPPED + && (len < BRIDGE_MAGIC_SIZE + || data[0] != static_cast(BRIDGE_PACKET_MAGIC >> 8) + || data[1] != static_cast(BRIDGE_PACKET_MAGIC & 0xFF))) { + return; + } + + portENTER_CRITICAL(&_rx_mux); + if (_rx_count < RX_QUEUE_DEPTH) { + memcpy(_rx_buffers[_rx_head], data, static_cast(len)); + _rx_lengths[_rx_head] = static_cast(len); + if (mac != nullptr) { + memcpy(_rx_sources[_rx_head], mac, + mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE); + } else { + memset(_rx_sources[_rx_head], 0, + mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE); + } + _rx_head = static_cast((_rx_head + 1) % RX_QUEUE_DEPTH); + _rx_count++; + } else { + _rx_dropped++; + } + portEXIT_CRITICAL(&_rx_mux); +} + +void ESPNowBridge::processReceivedFrame(const uint8_t *mac, + const uint8_t *data, size_t len) { + if (data == nullptr || len == 0 || len > MAX_ESPNOW_PACKET_SIZE) { + return; + } + + if (_active_format == mesh::bridge::ESPNOW_FORMAT_RAW) { + uint8_t packet[MAX_TRANS_UNIT]; + size_t packet_len = 0; + const mesh::espnow::ESPNowRawReassemblyResult result = + _raw_reassembler.acceptFrame( + mac, data, len, millis(), packet, sizeof(packet), packet_len); + if (result == mesh::espnow::ESPNowRawReassemblyResult::PASSTHROUGH + || result == + mesh::espnow::ESPNowRawReassemblyResult::PACKET_COMPLETE) { + BRIDGE_DEBUG_PRINTLN("RX raw, payload_len=%u%s\n", + (unsigned)packet_len, + result == mesh::espnow::ESPNowRawReassemblyResult::PACKET_COMPLETE + ? " (reassembled)" : ""); + receiveMeshPacket(packet, packet_len); + } else if (result == mesh::espnow::ESPNowRawReassemblyResult::REJECTED + || result == + mesh::espnow::ESPNowRawReassemblyResult::OUTPUT_TOO_SMALL) { + BRIDGE_DEBUG_PRINTLN("RX raw fragment rejected, result=%u len=%u\n", + (unsigned)result, (unsigned)len); + } + return; + } + + // Wrapped mode is strict: ignore packets too small to contain its header + // and checksum rather than trying to auto-detect raw MeshCore traffic. + if (len < (BRIDGE_MAGIC_SIZE + BRIDGE_CHECKSUM_SIZE)) { + BRIDGE_DEBUG_PRINTLN("RX packet too small, len=%u\n", (unsigned)len); return; } @@ -187,21 +505,18 @@ void ESPNowBridge::onDataRecv(const uint8_t *mac, const uint8_t *data, int len) return; } - BRIDGE_DEBUG_PRINTLN("RX, payload_len=%d\n", payloadLen); - - // Create mesh packet - mesh::Packet *pkt = _instance->_mgr->allocNew(); - if (!pkt) return; - - if (pkt->readFrom(decrypted + BRIDGE_CHECKSUM_SIZE, payloadLen)) { - _instance->onPacketReceived(pkt); - } else { - _instance->_mgr->free(pkt); - } + BRIDGE_DEBUG_PRINTLN("RX, payload_len=%u\n", (unsigned)payloadLen); + receiveMeshPacket(decrypted + BRIDGE_CHECKSUM_SIZE, payloadLen); } void ESPNowBridge::onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { - // Could add transmission error handling here if needed + (void)mac_addr; + portENTER_CRITICAL(&_tx_mux); + if (_tx_waiting) { + _tx_callback_status = static_cast(status); + _tx_callback_done = true; + } + portEXIT_CRITICAL(&_tx_mux); } void ESPNowBridge::sendPacket(mesh::Packet *packet) { @@ -219,50 +534,61 @@ void ESPNowBridge::sendPacket(mesh::Packet *packet) { if (!_seen_packets.wasSeen(packet)) { // Check the serialized size before writing into the ESP-NOW-sized buffer. const int expectedMeshPacketLen = packet->getRawLength(); - if (expectedMeshPacketLen < 0 || (size_t)expectedMeshPacketLen > MAX_PAYLOAD_SIZE) { - BRIDGE_DEBUG_PRINTLN("TX packet too large (payload=%d, max=%d)\n", expectedMeshPacketLen, - MAX_PAYLOAD_SIZE); + const size_t maxPayload = + mesh::bridge::espNowMaxMeshPacketSize(_active_format); + if (expectedMeshPacketLen < 0 + || (size_t)expectedMeshPacketLen > maxPayload) { + BRIDGE_DEBUG_PRINTLN("TX packet too large (payload=%d, max=%u)\n", + expectedMeshPacketLen, (unsigned)maxPayload); return; } - uint8_t sizingBuffer[MAX_PAYLOAD_SIZE]; - uint16_t meshPacketLen = packet->writeTo(sizingBuffer); + uint8_t buffer[MAX_TRANS_UNIT]; + uint16_t meshPacketLen = packet->writeTo(buffer); if (meshPacketLen != (uint16_t)expectedMeshPacketLen) { BRIDGE_DEBUG_PRINTLN("TX packet length mismatch (actual=%d, expected=%d)\n", meshPacketLen, expectedMeshPacketLen); return; } - uint8_t buffer[MAX_ESPNOW_PACKET_SIZE]; + size_t totalPacketSize = meshPacketLen; + if (_active_format != mesh::bridge::ESPNOW_FORMAT_RAW) { + const size_t packetOffset = BRIDGE_MAGIC_SIZE + BRIDGE_CHECKSUM_SIZE; + memmove(buffer + packetOffset, buffer, meshPacketLen); - // Write magic header (2 bytes) - buffer[0] = (BRIDGE_PACKET_MAGIC >> 8) & 0xFF; - buffer[1] = BRIDGE_PACKET_MAGIC & 0xFF; + // Write the legacy magic and encrypted checksum/payload wrapper. + buffer[0] = (BRIDGE_PACKET_MAGIC >> 8) & 0xFF; + buffer[1] = BRIDGE_PACKET_MAGIC & 0xFF; + const uint16_t checksum = + fletcher16(buffer + packetOffset, meshPacketLen); + buffer[2] = (checksum >> 8) & 0xFF; + buffer[3] = checksum & 0xFF; + if (!xorCrypt(buffer + BRIDGE_MAGIC_SIZE, + meshPacketLen + BRIDGE_CHECKSUM_SIZE)) { + return; + } + totalPacketSize = packetOffset + meshPacketLen; + } - // Write packet payload starting after magic header and checksum - const size_t packetOffset = BRIDGE_MAGIC_SIZE + BRIDGE_CHECKSUM_SIZE; - memcpy(buffer + packetOffset, sizingBuffer, meshPacketLen); + mesh::espnow::ESPNowRawFrames frames; + bool encoded = false; + if (_active_format == mesh::bridge::ESPNOW_FORMAT_RAW) { + encoded = mesh::espnow::encodeEspNowRawFrames( + buffer, totalPacketSize, frames); + } else if (totalPacketSize <= MAX_ESPNOW_PACKET_SIZE) { + frames.count = 1; + frames.lengths[0] = static_cast(totalPacketSize); + memcpy(frames.data[0], buffer, totalPacketSize); + encoded = true; + } - // Calculate and add checksum (only of the payload) - uint16_t checksum = fletcher16(buffer + packetOffset, meshPacketLen); - buffer[2] = (checksum >> 8) & 0xFF; // High byte - buffer[3] = checksum & 0xFF; // Low byte - - // Encrypt payload and checksum (not including magic header) - if (!xorCrypt(buffer + BRIDGE_MAGIC_SIZE, meshPacketLen + BRIDGE_CHECKSUM_SIZE)) return; - - // Total packet size: magic header + checksum + payload - const size_t totalPacketSize = BRIDGE_MAGIC_SIZE + BRIDGE_CHECKSUM_SIZE + meshPacketLen; - - // Broadcast using ESP-NOW - uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - esp_err_t result = esp_now_send(broadcastAddress, buffer, totalPacketSize); - - if (result == ESP_OK) { + if (encoded && queueTransmitFrames(frames, *packet)) { _seen_packets.markSeen(packet); - BRIDGE_DEBUG_PRINTLN("TX, len=%d\n", meshPacketLen); + BRIDGE_DEBUG_PRINTLN("TX %s, len=%d, frames=%u\n", + mesh::bridge::espNowFormatName(_active_format), + meshPacketLen, (unsigned)frames.count); } else { - BRIDGE_DEBUG_PRINTLN("TX FAILED!\n"); + BRIDGE_DEBUG_PRINTLN("TX queue/encode failed!\n"); } } } diff --git a/src/helpers/bridges/ESPNowBridge.h b/src/helpers/bridges/ESPNowBridge.h index 7c4a21bc..b0e7ac93 100644 --- a/src/helpers/bridges/ESPNowBridge.h +++ b/src/helpers/bridges/ESPNowBridge.h @@ -3,7 +3,10 @@ #include "MeshCore.h" #include "esp_now.h" #include "esp_idf_version.h" +#include +#include "helpers/ESPNowRawFragmentation.h" #include "helpers/bridges/BridgeBase.h" +#include "helpers/bridges/ESPNowBridgeFormat.h" #ifdef WITH_ESPNOW_BRIDGE @@ -16,27 +19,35 @@ * * Features: * - Broadcast-based communication (all bridges receive all packets) - * - Network isolation using XOR encryption with shared secret + * - Selectable wrapped or raw MeshCore wire format + * - Network isolation using XOR encryption with shared secret in wrapped mode * - Duplicate packet detection using SimpleMeshTables tracking - * - Maximum packet size of 250 bytes (ESP-NOW limitation) + * - Raw MeshCore packets up to 255 bytes using two frames only when needed * - * Packet Structure: + * Wrapped Packet Structure (the backward-compatible default): * [2 bytes] Magic Header - Used to identify ESPNowBridge packets - * [2 bytes] Fletcher-16 checksum of encrypted payload (calculated over payload only) - * [246 bytes max] Encrypted payload containing the mesh packet + * [2 bytes] Fletcher-16 checksum of the plaintext mesh payload + * [246 bytes max] Mesh packet payload * * The Fletcher-16 checksum is used to validate packet integrity and detect - * corrupted or tampered packets. It's calculated over the encrypted payload - * and provides a simple but effective way to verify packets are both - * uncorrupted and from the same network (since the checksum is calculated - * after encryption). + * corrupted packets. It is calculated over the plaintext payload; the + * checksum and payload are then XORed together using bridge.secret. A receiver + * with the wrong secret will normally fail checksum validation. + * + * Raw mode sends the exact bytes produced by mesh::Packet::writeTo(). It is + * compatible with primary ESPNOWRadio nodes, but has no bridge-secret wrapper. + * Packets up to the ESP-NOW frame limit remain byte-for-byte unchanged; + * 251-255-byte packets use a versioned two-frame envelope understood by + * updated raw endpoints. Receive parsing is deliberately strict to the + * selected format so a mixed deployment cannot silently become asymmetric. * * Configuration: * - Define WITH_ESPNOW_BRIDGE to enable this bridge * - Define _prefs->bridge_secret with a string to set the network encryption key + * - Set _prefs->bridge_format to wrapped (default) or raw * - * Network Isolation: - * Multiple independent mesh networks can coexist by using different + * Network Isolation (wrapped mode only): + * Multiple independent wrapped mesh networks can coexist by using different * _prefs->bridge_secret values. Packets encrypted with a different key will * fail the checksum validation and be discarded. */ @@ -66,18 +77,52 @@ private: * - Checksum: 2 bytes * - Available payload: 246 bytes */ - static const size_t MAX_ESPNOW_PACKET_SIZE = 250; + static const size_t MAX_ESPNOW_PACKET_SIZE = mesh::bridge::ESPNOW_MAX_FRAME_SIZE; + static const uint8_t RX_QUEUE_DEPTH = 4; + static const uint8_t TX_QUEUE_DEPTH = 6; - /** - * Size constants for packet parsing - */ - static const size_t MAX_PAYLOAD_SIZE = MAX_ESPNOW_PACKET_SIZE - (BRIDGE_MAGIC_SIZE + BRIDGE_CHECKSUM_SIZE); + /** Bounded callback-to-loop queue for receiving ESP-NOW packets. */ + uint8_t _rx_buffers[RX_QUEUE_DEPTH][MAX_ESPNOW_PACKET_SIZE]; + uint16_t _rx_lengths[RX_QUEUE_DEPTH]; + uint8_t _rx_sources[RX_QUEUE_DEPTH] + [mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE]; - /** Buffer for receiving ESP-NOW packets */ - uint8_t _rx_buffer[MAX_ESPNOW_PACKET_SIZE]; + // The ESP-NOW callback runs on the WiFi task. It only prefilters and copies + // bounded frames here; loop() owns PacketManager and duplicate processing. + portMUX_TYPE _rx_mux = portMUX_INITIALIZER_UNLOCKED; + volatile uint8_t _rx_head; + volatile uint8_t _rx_tail; + volatile uint8_t _rx_count; + volatile uint32_t _rx_dropped; + uint32_t _rx_dropped_reported; - /** Current position in receive buffer */ - size_t _rx_buffer_pos; + // Keep logical packets intact in the queue. Espressif recommends waiting + // for a frame's send callback before submitting the next one, and retaining + // the packet boundary lets a failed first fragment discard its sibling + // instead of transmitting an orphan fragment. + struct QueuedTransmit { + mesh::espnow::ESPNowRawFrames frames; + mesh::Packet packet; + uint8_t next_frame; + bool started; + }; + QueuedTransmit _tx_queue[TX_QUEUE_DEPTH]; + portMUX_TYPE _tx_mux = portMUX_INITIALIZER_UNLOCKED; + volatile uint8_t _tx_head; + volatile uint8_t _tx_tail; + volatile uint8_t _tx_count; + volatile bool _tx_waiting; + volatile bool _tx_callback_done; + volatile int _tx_callback_status; + volatile uint32_t _tx_dropped; + uint32_t _tx_dropped_reported; + + /** Raw-mode fragment assemblies, keyed by source MAC. */ + mesh::espnow::ESPNowRawReassembler _raw_reassembler; + + // Snapshotted by begin() and immutable until end(), so callbacks and sends + // never observe a partially applied preference change. + uint8_t _active_format; /** * Performs XOR encryption/decryption of data @@ -92,6 +137,9 @@ private: */ bool xorCrypt(uint8_t *data, size_t len); + /** Parse and queue one serialized MeshCore packet. */ + void receiveMeshPacket(const uint8_t *data, size_t len); + /** * ESP-NOW receive callback * Called by ESP-NOW when a packet is received @@ -100,7 +148,18 @@ private: * @param data Received data * @param len Length of received data */ - void onDataRecv(const uint8_t *mac, const uint8_t *data, int len); + void queueReceivedFrame(const uint8_t *mac, const uint8_t *data, int len); + + /** Parse a queued frame from loop(), never from the WiFi callback. */ + void processReceivedFrame(const uint8_t *mac, const uint8_t *data, + size_t len); + + /** Atomically append one logical packet's one or two transport frames. */ + bool queueTransmitFrames(const mesh::espnow::ESPNowRawFrames& frames, + const mesh::Packet& packet); + + /** Submit at most one queued frame after the previous send callback. */ + void pumpTransmitQueue(); /** * ESP-NOW send callback @@ -143,7 +202,7 @@ public: /** * Main loop handler - * ESP-NOW is callback-based, so this is currently empty + * Drains the bounded frames handed off by the WiFi receive callback. */ void loop() override; diff --git a/src/helpers/bridges/ESPNowBridgeFormat.h b/src/helpers/bridges/ESPNowBridgeFormat.h new file mode 100644 index 00000000..71d9188f --- /dev/null +++ b/src/helpers/bridges/ESPNowBridgeFormat.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include +#include + +namespace mesh { +namespace bridge { + +// Keep wrapped as zero so every existing preference image and a freshly +// zero-initialized NodePrefs retains the original bridge wire format. +static constexpr uint8_t ESPNOW_FORMAT_WRAPPED = 0; +static constexpr uint8_t ESPNOW_FORMAT_RAW = 1; + +static constexpr size_t ESPNOW_MAX_FRAME_SIZE = 250; +static constexpr size_t ESPNOW_WRAPPED_OVERHEAD = 4; + +static inline bool isValidEspNowFormat(uint8_t format) { + return format == ESPNOW_FORMAT_WRAPPED || format == ESPNOW_FORMAT_RAW; +} + +static inline bool parseEspNowFormat(const char* text, uint8_t& format) { + if (text == nullptr) return false; + if (strcmp(text, "wrapped") == 0) { + format = ESPNOW_FORMAT_WRAPPED; + return true; + } + if (strcmp(text, "raw") == 0) { + format = ESPNOW_FORMAT_RAW; + return true; + } + return false; +} + +static inline const char* espNowFormatName(uint8_t format) { + return format == ESPNOW_FORMAT_RAW ? "raw" : "wrapped"; +} + +static inline size_t espNowMaxMeshPacketSize(uint8_t format) { + return format == ESPNOW_FORMAT_RAW + ? mesh::espnow::ESPNOW_RAW_MAX_PACKET_SIZE + : ESPNOW_MAX_FRAME_SIZE - ESPNOW_WRAPPED_OVERHEAD; +} + +static inline uint8_t espNowMaxChannel(uint8_t format) { + (void)format; + return 13; +} + +static inline bool isValidEspNowBridgeChannel(uint8_t channel, + uint8_t format) { + return channel >= 1 && channel <= espNowMaxChannel(format); +} + +// Accept surrounding spaces/tabs, but no signs, separators, suffixes, or +// decimal notation. Leave the caller's output unchanged on every failure. +static inline bool parseEspNowBridgeChannel(const char* text, uint8_t format, + uint8_t& channel) { + if (text == nullptr) return false; + while (*text == ' ' || *text == '\t') text++; + if (*text < '0' || *text > '9') return false; + + uint16_t parsed = 0; + while (*text >= '0' && *text <= '9') { + parsed = (uint16_t)(parsed * 10 + (uint8_t)(*text - '0')); + if (parsed > 13) return false; + text++; + } + while (*text == ' ' || *text == '\t') text++; + if (*text != '\0' || !isValidEspNowBridgeChannel((uint8_t)parsed, format)) { + return false; + } + + channel = (uint8_t)parsed; + return true; +} + +} // namespace bridge +} // namespace mesh diff --git a/src/helpers/bridges/MQTTBridge.cpp b/src/helpers/bridges/MQTTBridge.cpp index 8c79c0d5..9f8e76db 100644 --- a/src/helpers/bridges/MQTTBridge.cpp +++ b/src/helpers/bridges/MQTTBridge.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1290,12 +1291,17 @@ void MQTTBridge::initializeWiFiInTask() { // Initialize WiFi WiFi.mode(WIFI_STA); - // Enable automatic reconnection - ESP32 will handle reconnection automatically - WiFi.setAutoReconnect(true); + // A primary ESP-NOW radio must reconnect through the fixed-channel policy; + // other ESP32 targets retain the driver's normal automatic reconnect. + mesh::wifi::setStationAutoReconnect(true); #if !defined(ESP_ARDUINO_VERSION_MAJOR) || ESP_ARDUINO_VERSION_MAJOR < 3 // Arduino-ESP32 3.x removed setAutoConnect(); begin() plus // setAutoReconnect() is the supported equivalent there. +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + WiFi.setAutoConnect(false); +#else WiFi.setAutoConnect(true); +#endif #endif // Set up WiFi event handlers for better diagnostics and immediate disconnection @@ -1340,7 +1346,7 @@ void MQTTBridge::initializeWiFiInTask() { // because _ntp_synced persists across end() (only _slots_setup_done is reset). if (WiFi.status() != WL_CONNECTED) { if (_manage_wifi) { - WiFi.begin(_obs->wifi_ssid, _obs->wifi_password); + mesh::wifi::beginStation(_obs->wifi_ssid, _obs->wifi_password); } } else if (!_ntp_synced && !_ntp_sync_pending) { _ntp_sync_pending = true; // already connected but never synced - kick NTP now @@ -2834,6 +2840,14 @@ void MQTTBridge::checkConfigurationMismatch() { bool MQTTBridge::handleWiFiConnection(unsigned long now) { wl_status_t current_wifi_status = WiFi.status(); +#ifdef ESP_PLATFORM + if (current_wifi_status == WL_CONNECTED + && !mesh::wifi::enforceStationChannel()) { + current_wifi_status = WL_DISCONNECTED; + MQTT_DEBUG_PRINTLN( + "Rejected WiFi association outside the primary ESP-NOW channel"); + } +#endif bool transitioned_to_connected = false; if (current_wifi_status == WL_CONNECTED && s_wifi_connected_at == 0) { @@ -2869,10 +2883,11 @@ bool MQTTBridge::handleWiFiConnection(unsigned long now) { uint8_t ps_pref = mesh::wifi::effectivePowerSave( _obs->wifi_power_save, #if defined(BLE_PIN_CODE) && defined(WIFI_SSID) - true + true, #else - false + false, #endif + mesh::wifi::kPrimaryEspNowRadio ); if (ps_pref == 1) { ps_mode = WIFI_PS_NONE; @@ -2920,7 +2935,11 @@ bool MQTTBridge::handleWiFiConnection(unsigned long now) { _wifi_reconnect_backoff_attempt = MQTTConnectionPolicy::nextWifiBackoffAttempt(_wifi_reconnect_backoff_attempt); WiFi.disconnect(); +#ifdef ESP_PLATFORM + mesh::wifi::beginStation(_obs->wifi_ssid, _obs->wifi_password); +#else WiFi.begin(_obs->wifi_ssid, _obs->wifi_password); +#endif } } _last_wifi_status = current_wifi_status; diff --git a/src/helpers/esp32/ESPNOWRadio.cpp b/src/helpers/esp32/ESPNOWRadio.cpp index 39cf88f5..8e459461 100644 --- a/src/helpers/esp32/ESPNOWRadio.cpp +++ b/src/helpers/esp32/ESPNOWRadio.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #if ESP_ARDUINO_VERSION_MAJOR >= 3 #include #endif @@ -11,8 +13,25 @@ static uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static esp_now_peer_info_t peerInfo; static volatile bool is_send_complete = false; static esp_err_t last_send_result; -static uint8_t rx_buf[256]; -static uint8_t last_rx_len = 0; +static volatile esp_now_send_status_t last_send_status = + ESP_NOW_SEND_SUCCESS; +static bool tx_second_pending = false; +static uint16_t tx_second_length = 0; +static uint8_t tx_second_frame[mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE]; +static constexpr uint16_t RX_FRAME_MAX = + mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE; +static constexpr uint8_t RX_QUEUE_DEPTH = 4; +static uint8_t rx_frames[RX_QUEUE_DEPTH][RX_FRAME_MAX]; +static uint16_t rx_lengths[RX_QUEUE_DEPTH]; +static uint8_t rx_sources[RX_QUEUE_DEPTH] + [mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE]; +static volatile uint8_t rx_head = 0; +static volatile uint8_t rx_tail = 0; +static volatile uint8_t rx_count = 0; +static volatile uint32_t rx_dropped = 0; +static uint32_t rx_dropped_reported = 0; +static portMUX_TYPE rx_mux = portMUX_INITIALIZER_UNLOCKED; +static mesh::espnow::ESPNowRawReassembler rx_reassembler; // callback when data is sent #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0) @@ -23,6 +42,7 @@ static void OnDataSent(const esp_now_send_info_t *info, static void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { (void)mac_addr; #endif + last_send_status = status; is_send_complete = true; ESPNOW_DEBUG_PRINTLN("Send Status: %d", (int)status); } @@ -30,25 +50,78 @@ static void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { #if ESP_ARDUINO_VERSION_MAJOR >= 3 static void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len) { - (void)info; + const uint8_t *mac = info != nullptr ? info->src_addr : nullptr; #else static void OnDataRecv(const uint8_t *mac, const uint8_t *data, int len) { - (void)mac; #endif ESPNOW_DEBUG_PRINTLN("Recv: len = %d", len); - memcpy(rx_buf, data, len); - last_rx_len = len; + portENTER_CRITICAL(&rx_mux); + if (data != nullptr && len > 0 && len <= RX_FRAME_MAX + && rx_count < RX_QUEUE_DEPTH) { + memcpy(rx_frames[rx_head], data, static_cast(len)); + rx_lengths[rx_head] = static_cast(len); + if (mac != nullptr) { + memcpy(rx_sources[rx_head], mac, + mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE); + } else { + memset(rx_sources[rx_head], 0, + mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE); + } + rx_head = static_cast((rx_head + 1) % RX_QUEUE_DEPTH); + rx_count++; + } else { + rx_dropped++; + } + portEXIT_CRITICAL(&rx_mux); } void ESPNOWRadio::init() { + portENTER_CRITICAL(&rx_mux); + rx_head = 0; + rx_tail = 0; + rx_count = 0; + rx_dropped = 0; + portEXIT_CRITICAL(&rx_mux); + rx_dropped_reported = 0; + rx_reassembler.reset(); + tx_second_pending = false; + tx_second_length = 0; + last_send_status = ESP_NOW_SEND_SUCCESS; + // Set device as a Wi-Fi Station // ESP-NOW's LR protocol is local to this radio transport. Keeping WiFi // driver writes in RAM prevents a later conventional WiFi image from // inheriting the proprietary protocol bit through NVS. WiFi.persistent(false); +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + // Arduino defaults station auto-reconnect to enabled. Disable it before the + // driver starts so credentials left by another image cannot pull the radio + // away from the configured mesh channel behind this policy's back. + WiFi.setAutoReconnect(false); +#endif WiFi.mode(WIFI_STA); - // Long Range mode - esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR); +#if defined(MESH_ESPNOW_RADIO) && MESH_ESPNOW_RADIO + // Full Companion also exposes ordinary WiFi. Preserve B/G/N for normal + // access points while retaining LR for ESP-NOW, and pin both transports to + // one channel because an ESP32 cannot associate and send ESP-NOW on two + // different channels simultaneously. + if (mesh::wifi::applyProtocolMask(WIFI_IF_STA) != ESP_OK) { + ESPNOW_DEBUG_PRINTLN("Error configuring ESP-NOW/WiFi coexistence"); + return; + } +#else + // Dedicated ESP-NOW targets retain the original LR-only behavior. + if (esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR) != ESP_OK) { + ESPNOW_DEBUG_PRINTLN("Error configuring ESP-NOW LR protocol"); + return; + } +#endif +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (mesh::wifi::restoreEspNowChannel() != ESP_OK) { + ESPNOW_DEBUG_PRINTLN("Error setting primary ESP-NOW channel"); + return; + } +#endif // Init ESP-NOW if (esp_now_init() != ESP_OK) { @@ -62,14 +135,41 @@ void ESPNOWRadio::init() { esp_now_register_recv_cb(OnDataRecv); // Register peer + memset(&peerInfo, 0, sizeof(peerInfo)); memcpy(peerInfo.peer_addr, broadcastAddress, 6); +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + // Zero follows the station/AP's current channel. The policy pins that radio + // channel and rejects off-channel infrastructure associations, avoiding a + // stale fixed peer entry after a configured-channel reboot. +#endif peerInfo.channel = 0; + peerInfo.ifidx = WIFI_IF_STA; peerInfo.encrypt = false; is_send_complete = true; // Add peer if (esp_now_add_peer(&peerInfo) == ESP_OK) { +#if defined(MESH_ESPNOW_RADIO) && MESH_ESPNOW_RADIO + // Enabling interoperable B/G/N alongside LR changes the interface's + // default rate selection. Force ESP-NOW packets back to the legacy LR rate + // so Full images remain compatible with existing LR-only mesh nodes. + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) + esp_now_rate_config_t rate_config = {}; + rate_config.phymode = WIFI_PHY_MODE_LR; + rate_config.rate = WIFI_PHY_RATE_LORA_250K; + rate_config.ersu = false; + rate_config.dcm = false; + if (esp_now_set_peer_rate_config(broadcastAddress, &rate_config) != ESP_OK) { + ESPNOW_DEBUG_PRINTLN("Error configuring ESP-NOW LR peer rate"); + } + #else + if (esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_LORA_250K) + != ESP_OK) { + ESPNOW_DEBUG_PRINTLN("Error configuring ESP-NOW LR interface rate"); + } + #endif +#endif ESPNOW_DEBUG_PRINTLN("init success"); } else { // ESPNOW_DEBUG_PRINTLN("Failed to add peer"); @@ -96,44 +196,158 @@ uint32_t ESPNOWRadio::intID() { } bool ESPNOWRadio::startSendRaw(const uint8_t* bytes, int len) { - // Send message via ESP-NOW + mesh::espnow::ESPNowRawFrames frames; + if (len < 0 + || !mesh::espnow::encodeEspNowRawFrames( + bytes, static_cast(len), frames)) { + ESPNOW_DEBUG_PRINTLN("Invalid TX length: %d", len); + return false; + } + + tx_second_pending = frames.count == 2; + tx_second_length = 0; + if (tx_second_pending) { + tx_second_length = frames.lengths[1]; + memcpy(tx_second_frame, frames.data[1], tx_second_length); + } + + // Send the first (or only) message via ESP-NOW. isSendComplete() submits a + // second fragment only after this frame's callback, preserving Espressif's + // required callback ordering without blocking the mesh dispatcher. + last_send_status = ESP_NOW_SEND_SUCCESS; is_send_complete = false; - esp_err_t result = esp_now_send(broadcastAddress, bytes, len); + esp_err_t result = esp_now_send( + broadcastAddress, frames.data[0], frames.lengths[0]); if (result == ESP_OK) { n_sent++; - ESPNOW_DEBUG_PRINTLN("Send success"); + ESPNOW_DEBUG_PRINTLN("Send started: frames=%u raw_len=%d", + (unsigned)frames.count, len); return true; } last_send_result = result; + tx_second_pending = false; + tx_second_length = 0; is_send_complete = true; ESPNOW_DEBUG_PRINTLN("Send failed: %d", result); return false; } bool ESPNOWRadio::isSendComplete() { + if (!is_send_complete) return false; + if (last_send_status != ESP_NOW_SEND_SUCCESS) { + // A failed callback means the logical packet was not transmitted. Do not + // send an orphan second fragment; remaining incomplete lets Dispatcher use + // its bounded timeout/retry path. + tx_second_pending = false; + tx_second_length = 0; + is_send_complete = false; + ESPNOW_DEBUG_PRINTLN("Send callback failed: %d", (int)last_send_status); + return false; + } + if (tx_second_pending) { + tx_second_pending = false; + last_send_status = ESP_NOW_SEND_SUCCESS; + is_send_complete = false; + const esp_err_t result = esp_now_send( + broadcastAddress, tx_second_frame, tx_second_length); + if (result != ESP_OK) { + // Leave the operation incomplete. Dispatcher will use its bounded radio + // timeout/retry path instead of reporting a partially sent packet as a + // success. + last_send_result = result; + tx_second_length = 0; + ESPNOW_DEBUG_PRINTLN("Second fragment failed to start: %d", result); + return false; + } + tx_second_length = 0; + ESPNOW_DEBUG_PRINTLN("Second fragment started"); + return false; + } return is_send_complete; } void ESPNOWRadio::onSendFinished() { + tx_second_pending = false; + tx_second_length = 0; + last_send_status = ESP_NOW_SEND_SUCCESS; is_send_complete = true; } bool ESPNOWRadio::isInRecvMode() const { - return is_send_complete; // if NO send in progress, then we're in Rx mode + return is_send_complete && !tx_second_pending; } float ESPNOWRadio::getLastRSSI() const { return 0; } float ESPNOWRadio::getLastSNR() const { return 0; } int ESPNOWRadio::recvRaw(uint8_t* bytes, int sz) { - int len = last_rx_len; - if (last_rx_len > 0) { - memcpy(bytes, rx_buf, last_rx_len); - last_rx_len = 0; - n_recv++; + if (bytes == nullptr || sz <= 0) return 0; + + uint32_t dropped = 0; + portENTER_CRITICAL(&rx_mux); + dropped = rx_dropped; + portEXIT_CRITICAL(&rx_mux); + + if (dropped != rx_dropped_reported) { + n_recv_errors += dropped - rx_dropped_reported; + ESPNOW_DEBUG_PRINTLN("RX queue/length drops: %lu", + (unsigned long)dropped); + rx_dropped_reported = dropped; } - return len; + + // Drain fragment-only and malformed frames in one dispatcher poll. This + // lets a queued two-frame packet become one ordinary MeshCore receive while + // retaining the callback's fixed, bounded handoff queue. + for (uint8_t processed = 0; processed < RX_QUEUE_DEPTH; ++processed) { + uint8_t frame[RX_FRAME_MAX]; + uint8_t source[mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE]; + uint16_t frame_len = 0; + + portENTER_CRITICAL(&rx_mux); + if (rx_count > 0) { + frame_len = rx_lengths[rx_tail]; + if (frame_len > 0 && frame_len <= sizeof(frame)) { + memcpy(frame, rx_frames[rx_tail], frame_len); + memcpy(source, rx_sources[rx_tail], sizeof(source)); + } else { + frame_len = 0; + } + rx_tail = static_cast((rx_tail + 1) % RX_QUEUE_DEPTH); + rx_count--; + } + portEXIT_CRITICAL(&rx_mux); + + if (frame_len == 0) break; + size_t packet_len = 0; + const mesh::espnow::ESPNowRawReassemblyResult result = + rx_reassembler.acceptFrame( + source, frame, frame_len, millis(), bytes, + static_cast(sz), packet_len); + if (result == mesh::espnow::ESPNowRawReassemblyResult::PASSTHROUGH + || result == + mesh::espnow::ESPNowRawReassemblyResult::PACKET_COMPLETE) { + n_recv++; + return static_cast(packet_len); + } + if (result == mesh::espnow::ESPNowRawReassemblyResult::REJECTED + || result == + mesh::espnow::ESPNowRawReassemblyResult::OUTPUT_TOO_SMALL) { + n_recv_errors++; + ESPNOW_DEBUG_PRINTLN("RX fragment rejected: result=%u len=%u size=%d", + (unsigned)result, (unsigned)frame_len, sz); + } + } + return 0; } uint32_t ESPNOWRadio::getEstAirtimeFor(int len_bytes) { - return 4; // Fast AF + if (len_bytes > static_cast( + mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE)) { + // A maximum raw packet becomes one full ESP-NOW LR frame plus one short + // frame. Include callback scheduling margin for both transmissions. + return 40; + } + // At the forced 250-kbit/s LR rate, a 250-byte payload alone takes 8 ms. + // Dispatcher applies a 1.5x deadline multiplier, so 20 ms leaves room for + // ESP-NOW/MAC overhead and callback scheduling without false timeouts. + return 20; } diff --git a/src/helpers/esp32/WebConfigHtml.h b/src/helpers/esp32/WebConfigHtml.h index 54dcb4bf..6e920426 100644 --- a/src/helpers/esp32/WebConfigHtml.h +++ b/src/helpers/esp32/WebConfigHtml.h @@ -1,1794 +1,1896 @@ // Auto-generated by scripts/generate_webconfig_html.py from webui/index.html // DO NOT EDIT - edit webui/index.html instead. -// build-inputs-sha256: 06a53cedbec36462b444bf6e263418c2c256fc6fa0adaf597df9b14b85bbfc38 +// build-inputs-sha256: 311458e7bf30c4c768989272ce4e9c42c4b44dd780fb8fd27854437448834433 #pragma once #include #include -const uint32_t WEBCONFIG_HTML_GZ_LEN = 28516; -const char WEBCONFIG_HTML_ETAG[] = "\"08f14d18781e82ea\""; -const uint8_t WEBCONFIG_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0xd4,0xbd,0x69,0x7b,0xdb,0x46, - 0xb2,0x28,0xfc,0x9d,0xbf,0x02,0x81,0x73,0x24,0x22,0x02,0x21,0x92,0x5a,0x2c,0x93, - 0xa6,0x74,0x15,0xc5,0x4e,0x7c,0xe2,0x45,0x47,0x52,0x26,0x99,0xab,0x68,0x7c,0x41, - 0x12,0x24,0x31,0x02,0x01,0x04,0x00,0xb5,0x98,0xd2,0xfd,0xed,0x6f,0x2d,0xdd,0x8d, - 0xc6,0x42,0x4a,0x4e,0x72,0x9e,0x73,0xdf,0xcc,0x58,0x04,0x1a,0xbd,0x56,0x57,0x57, - 0x57,0x55,0x57,0x55,0xbf,0xfe,0xe6,0x87,0x4f,0x27,0x17,0xff,0x3c,0x7d,0x63,0xcc, - 0xb2,0x79,0x70,0xd8,0x78,0x8d,0x3f,0x46,0xe0,0x86,0xd3,0x81,0xe9,0x85,0x26,0x26, - 0x78,0xee,0x18,0x7e,0xe6,0x5e,0xe6,0x1a,0xa3,0x99,0x9b,0xa4,0x5e,0x36,0x30,0x17, - 0xd9,0xa4,0x75,0x60,0xca,0xe4,0xd0,0x9d,0x7b,0x03,0xf3,0xc6,0xf7,0x6e,0xe3,0x28, - 0xc9,0x4c,0x63,0x14,0x85,0x99,0x17,0x42,0xb6,0x5b,0x7f,0x9c,0xcd,0x06,0x63,0xef, - 0xc6,0x1f,0x79,0x2d,0x7a,0xb1,0x0d,0x3f,0xf4,0x33,0xdf,0x0d,0x5a,0xe9,0xc8,0x0d, - 0xbc,0x41,0xc7,0x36,0xe6,0xee,0x9d,0x3f,0x5f,0xcc,0xf3,0x04,0x59,0x51,0x6b,0xe2, - 0x67,0x83,0x51,0x74,0xe3,0x25,0xd8,0x52,0xe6,0x67,0x81,0x77,0xf8,0xc1,0x4b,0x67, - 0x27,0x51,0xe2,0x19,0x27,0x51,0x38,0xf1,0xa7,0xaf,0xb7,0x39,0xb9,0xf1,0x3a,0xcd, - 0xee,0xf1,0xb7,0x97,0x44,0x51,0xb6,0x6c,0xb4,0x5a,0xc3,0x69,0xef,0xc5,0x64,0x77, - 0xb2,0x3f,0x39,0xe8,0x1b,0xad,0xd6,0xc8,0x4d,0xc6,0xf0,0x3e,0x99,0xe0,0x8b,0x1f, - 0x5e,0xf7,0x5e,0x74,0xdc,0xee,0xce,0x4e,0x1b,0x5f,0xe7,0x8b,0xac,0xf7,0x62,0x7f, - 0xff,0xe5,0xce,0x81,0x8b,0xaf,0x81,0x1f,0x7a,0xbd,0x17,0x5e,0xd7,0x7b,0xe9,0x79, - 0x7d,0xa8,0xc8,0x1d,0x8d,0x7a,0x2f,0xba,0xc3,0x97,0x63,0xef,0x15,0x7e,0x86,0x57, - 0xae,0x40,0x54,0x16,0x61,0x5d,0xe3,0x57,0xe3,0x3d,0x7a,0xf3,0x92,0xa4,0xf7,0x62, - 0xbc,0xbf,0xbb,0xb7,0xbb,0x87,0xaf,0xb7,0x6e,0x12,0xf6,0x5e,0x8c,0x0e,0x0e,0x5e, - 0x76,0x5c,0xac,0x6b,0x34,0xf3,0x63,0xa8,0xdb,0x9b,0x74,0x27,0x2f,0xb9,0x27,0xdc, - 0x4f,0xd9,0x2f,0xd1,0xf8,0xe8,0x60,0xdc,0x1d,0x7b,0x98,0x94,0xce,0xdc,0x71,0x74, - 0xdb,0x6b,0x1b,0x9d,0xf8,0xce,0xd8,0x81,0x7f,0xc9,0x74,0xe8,0x36,0x3b,0xfb,0x76, - 0xf7,0xc0,0xde,0xdd,0xb3,0x9d,0xf6,0x81,0xd5,0x6f,0x3c,0x36,0xfe,0xd7,0xdc,0x1b, - 0xfb,0xae,0xd1,0x8c,0x13,0x6f,0xe2,0x25,0x69,0x6b,0x14,0x05,0x51,0x02,0x00,0x9d, - 0x79,0x73,0xaf,0x37,0x76,0x93,0x6b,0x6b,0x59,0x00,0x4c,0xa7,0xdd,0xd9,0xeb,0x8c, - 0x72,0xc0,0x00,0x30,0x3a,0xdd,0xa1,0x82,0x8d,0xb7,0xef,0x0d,0x27,0x5d,0x05,0x9b, - 0x83,0xe1,0xab,0x03,0x77,0x98,0xc3,0xa6,0xeb,0xee,0xec,0xee,0x76,0x15,0x6c,0x76, - 0xdd,0x57,0xbb,0x13,0x82,0x24,0x0f,0xaf,0xbb,0xd3,0x1d,0xef,0xb8,0xda,0xf0,0x3a, - 0xbb,0x50,0x7f,0xb7,0x30,0xc2,0x1d,0x77,0x77,0x7f,0x6f,0x7f,0xf5,0x08,0xdb,0x36, - 0xfe,0xcf,0xd9,0xc5,0xd1,0x3d,0x36,0xbe,0x5b,0x0e,0xa3,0xbb,0x56,0xea,0x7f,0xf1, - 0xc3,0x69,0x6f,0x18,0x25,0x63,0x2f,0x69,0x41,0x4a,0x7f,0xee,0x26,0x53,0x3f,0xec, - 0xb5,0x1f,0x1b,0x88,0xb5,0xcb,0xd6,0xad,0x37,0xbc,0xf6,0xb3,0x56,0xe6,0xdd,0x65, - 0x98,0xdb,0x6b,0xb9,0xe3,0x7f,0x2f,0xd2,0xac,0xd7,0x69,0xb7,0xff,0xe3,0xb1,0x31, - 0x8c,0xc6,0xf7,0xcb,0x09,0xa0,0x66,0xaf,0xb3,0x17,0xdf,0x6d,0x77,0x9c,0xdd,0x3d, - 0x23,0xbd,0x4f,0x33,0x6f,0xde,0x5a,0xf8,0x76,0xcb,0x8d,0xe3,0xc0,0x6b,0x71,0x82, - 0x6d,0x9e,0x7b,0xd3,0xc8,0x33,0x7e,0x79,0x67,0xda,0x67,0xd1,0x30,0xca,0x22,0x3b, - 0x75,0xc3,0xb4,0x95,0x7a,0x89,0x3f,0xe9,0x0f,0xdd,0xd1,0xf5,0x34,0x89,0x16,0xe1, - 0xb8,0x77,0xe3,0x26,0x4d,0x04,0xa9,0xd5,0x27,0x90,0x8b,0x77,0x00,0xa2,0xd5,0x8f, - 0xdd,0xf1,0x18,0xfa,0x0b,0x1d,0xcd,0xb2,0x68,0xde,0x7b,0xd5,0x8e,0xef,0xfa,0x88, - 0xcb,0x93,0x20,0xba,0x6d,0xdd,0xf5,0x66,0xfe,0x78,0xec,0x85,0xd0,0xf3,0x0e,0xf5, - 0x89,0xfa,0xdb,0xeb,0xbc,0x84,0x4c,0xf4,0x7a,0xeb,0xf9,0xd3,0x59,0xd6,0xdb,0xdf, - 0xc3,0xc1,0x75,0xf5,0x2c,0xbb,0xd5,0x2c,0x7d,0x1a,0x71,0x96,0x40,0x17,0x27,0x51, - 0x32,0xef,0x2d,0xe2,0xd8,0x4b,0x46,0x6e,0xea,0xf5,0x03,0x2f,0xcb,0x00,0x58,0x69, - 0xec,0x8e,0x10,0x76,0x4e,0x7b,0xcf,0x9b,0x17,0xba,0x0a,0x13,0x6c,0x49,0x38,0x76, - 0xbb,0x00,0x7e,0x98,0x08,0xe8,0x29,0x36,0xda,0x9b,0xf8,0x49,0x9a,0xe1,0xa4,0x06, - 0xe3,0x25,0x67,0x69,0x65,0x51,0x8c,0xe0,0x76,0x97,0x7a,0x1d,0x80,0x05,0x16,0x14, - 0x00,0x3a,0xe1,0x25,0xcb,0xb1,0x9f,0xc6,0x81,0x7b,0xdf,0x9b,0x04,0xde,0x5d,0xdf, - 0x0d,0xfc,0x69,0xd8,0xf2,0x01,0xa2,0x69,0x6f,0x04,0x14,0xc1,0x4b,0xfa,0x53,0x37, - 0xee,0x61,0x0b,0x12,0x3e,0xbd,0x0e,0xb6,0xda,0xd9,0x87,0x94,0x0a,0x5c,0x11,0x39, - 0xad,0xbe,0x9a,0x70,0x82,0x23,0xa2,0x49,0x1a,0x05,0xfe,0xd8,0xe0,0x3c,0x88,0x4f, - 0x00,0xec,0x28,0x05,0xaa,0x12,0x85,0xbd,0x34,0xf3,0x47,0xd7,0xf7,0x7d,0xea,0x67, - 0xff,0x0b,0xcc,0xc4,0xd8,0xbb,0x83,0xf6,0x64,0xf7,0x8c,0xf4,0x66,0xba,0xc4,0xae, - 0xf5,0xc2,0x28,0xf4,0x1e,0x1b,0xce,0x0c,0x09,0xd8,0x72,0x0e,0x43,0x23,0xf2,0x84, - 0x83,0xe3,0x34,0x63,0xec,0xdf,0xe8,0x60,0x87,0x5e,0x56,0x01,0x77,0x3b,0x83,0xb1, - 0x11,0x74,0x3d,0xa8,0xf0,0x36,0x71,0x63,0x35,0xc5,0x62,0x82,0x79,0x6a,0x54,0xa2, - 0x17,0x04,0x7e,0x9c,0xfa,0x29,0xb4,0x32,0x74,0xc7,0x53,0x4f,0xc2,0x35,0xf0,0x26, - 0x59,0xcf,0x5d,0x64,0x51,0x5f,0x75,0xae,0xaf,0x35,0xde,0xa9,0x99,0x73,0x09,0x3f, - 0x5c,0x33,0xaf,0x10,0x7a,0x0c,0xa6,0xc4,0x1d,0xfb,0x8b,0xb4,0xf7,0xea,0x55,0x2d, - 0x40,0x61,0x81,0x5a,0x95,0x61,0xc8,0xce,0x38,0x40,0xda,0x17,0xf1,0x52,0x2b,0xf5, - 0x62,0xb2,0xe3,0x1d,0x8c,0x77,0x44,0x89,0x17,0x07,0xee,0xde,0xa8,0x4d,0x10,0xf2, - 0x81,0xc4,0xe7,0x70,0xec,0xeb,0xa3,0x38,0xd0,0xe6,0x16,0xfb,0x76,0xa0,0xfa,0x56, - 0x99,0x3b,0x41,0x0e,0xac,0x52,0xdf,0x71,0x11,0x34,0x2a,0x7d,0x27,0x62,0x52,0xed, - 0x7c,0x7f,0xb4,0x48,0x52,0x48,0x89,0x23,0x9f,0xf0,0x0b,0x2b,0x6c,0xcd,0x18,0x4c, - 0x1d,0x67,0xa7,0xdf,0xa0,0x15,0xff,0xb2,0x0d,0x78,0xdd,0xa5,0x55,0xbf,0x63,0x2c, - 0xfc,0xd6,0x3c,0x0a,0x23,0x9a,0x36,0xfb,0x83,0x17,0x06,0x91,0x0d,0xbb,0x09,0x74, - 0xcc,0x4d,0x6d,0xf5,0x41,0x8e,0xb2,0x37,0xc3,0xc9,0xab,0xe0,0xbb,0xec,0x72,0x75, - 0x1d,0x3c,0x83,0x16,0xaf,0x04,0xf7,0x8e,0xdb,0x9d,0x74,0x76,0x25,0xb8,0xbd,0xf6, - 0x70,0x77,0x6f,0x04,0xf4,0x6f,0xee,0xfa,0x21,0x60,0xca,0x9d,0xc0,0xd1,0xfd,0x5d, - 0x5c,0x3f,0x92,0xf8,0x19,0x84,0x36,0x6a,0x35,0xed,0xe3,0xe2,0x75,0x70,0xe5,0x2c, - 0xd7,0xae,0xa7,0x15,0x0b,0xa9,0x38,0x13,0x84,0xf5,0x7a,0xd5,0x7d,0x22,0xc4,0x4c, - 0xb2,0xb9,0x18,0xbf,0x48,0x1a,0xa2,0x56,0xe9,0x2e,0x75,0x23,0x73,0x87,0x69,0x91, - 0x22,0xe0,0xf2,0xdf,0x5d,0x8d,0x9a,0xb2,0xad,0xdd,0x0a,0x42,0x77,0xf2,0x31,0xd7, - 0x34,0x62,0x0c,0x17,0x90,0x24,0x50,0xb2,0x23,0x87,0xd8,0xd6,0x9b,0x21,0x44,0xad, - 0x60,0x0f,0x61,0x87,0x1f,0xce,0x80,0xb0,0x67,0xfa,0x8a,0xdb,0x71,0xf6,0xca,0x6b, - 0xae,0x9d,0xaf,0x39,0xc0,0x50,0xa3,0xda,0x45,0xc4,0xdb,0x22,0x36,0x16,0x7b,0xe7, - 0x40,0x07,0x57,0xcc,0x49,0x65,0xf7,0x58,0x05,0x67,0xa8,0x71,0xb2,0x2c,0x81,0x61, - 0x87,0xc0,0x30,0x01,0xae,0x6d,0xe8,0x05,0x0a,0xdc,0xc3,0x20,0x1a,0x5d,0xeb,0x43, - 0xea,0xd6,0x0e,0xa9,0x58,0xd7,0xae,0xa8,0x0a,0x70,0x3f,0xcc,0x74,0xf2,0xd7,0xa1, - 0xc2,0x2b,0x76,0x0e,0xda,0x16,0xa8,0x17,0x7e,0x18,0x2f,0xb2,0xcb,0xec,0x3e,0xf6, - 0x06,0x48,0xf8,0xae,0x6c,0x2d,0x21,0x76,0xd3,0xf4,0x16,0x00,0x56,0x48,0x0c,0x17, - 0xf3,0xa1,0x97,0x14,0x92,0x3c,0x40,0xf7,0xe0,0xca,0x4e,0xbd,0xc0,0x1b,0x01,0xc7, - 0xc2,0x38,0x8f,0x5b,0xb8,0x02,0xff,0x01,0xee,0x18,0x6d,0x31,0x98,0xba,0xd9,0xdb, - 0x2f,0xf5,0x95,0x41,0xba,0x82,0xa2,0x34,0xbe,0x8e,0x3a,0x21,0x3d,0x8b,0x16,0x19, - 0xf1,0x31,0xb4,0x89,0x18,0xc6,0xf6,0x77,0xc6,0xe1,0x00,0x1b,0xed,0x19,0x29,0x80, - 0x22,0x35,0xfc,0x4f,0xe7,0xc6,0x97,0x28,0x9a,0xb7,0xa2,0xb0,0x35,0x89,0x46,0x8b, - 0xd4,0x68,0xa6,0xfe,0xd8,0xbb,0x75,0xef,0x81,0x87,0x18,0x25,0x51,0x10,0x00,0x1b, - 0x6c,0x8c,0xdc,0x38,0xf3,0x6f,0x3c,0x23,0x9d,0x79,0x5e,0x66,0x19,0xdf,0x6d,0x33, - 0xf8,0x7a,0x54,0x42,0x8c,0x9f,0x5f,0x96,0x2b,0xa8,0x8d,0x8e,0x26,0x6d,0x03,0xff, - 0x87,0x9b,0x29,0x53,0x9c,0xb9,0x7f,0xd7,0x84,0x46,0x52,0xe0,0xa7,0xec,0xbc,0x84, - 0xd1,0xdd,0xfb,0x0f,0x9b,0x38,0x85,0xd8,0x4d,0x60,0x47,0xb6,0xc4,0x9c,0x39,0x63, - 0x3f,0xc9,0xee,0x45,0xa3,0xfc,0x52,0xd7,0x28,0x32,0xb4,0x88,0x83,0xf1,0xf5,0x54, - 0x21,0xda,0x34,0xf1,0xc7,0x7d,0xfc,0x03,0x8c,0xd7,0x1c,0x52,0x60,0x47,0x84,0x22, - 0x8b,0x79,0x98,0xf6,0x12,0x2f,0xf6,0xdc,0xac,0x89,0x14,0x0a,0x98,0xf9,0x20,0xb0, - 0x61,0xa3,0x05,0x3a,0xd6,0xec,0x20,0xab,0x61,0x77,0x26,0x89,0x65,0x11,0x45,0xe8, - 0x8a,0x7d,0xe2,0x4f,0x4c,0x85,0x86,0x13,0xab,0x66,0x18,0x31,0x9a,0x87,0x64,0x50, - 0xc7,0xd7,0x8e,0xeb,0x59,0x0c,0xcc,0xbe,0x5c,0x48,0xab,0x56,0xd6,0xae,0x5a,0x59, - 0x40,0x84,0x1a,0xc8,0x5e,0x88,0x2d,0xa9,0xbb,0x5f,0x47,0x24,0xe2,0x6b,0x83,0x66, - 0x61,0x29,0x90,0x1d,0xab,0x93,0x7b,0xd8,0x9e,0x46,0xeb,0xfb,0x3a,0xeb,0x02,0x85, - 0x60,0x12,0xc3,0xe5,0xf3,0x38,0x8e,0x1a,0x5e,0x85,0xea,0x70,0x9f,0xcf,0xb1,0x69, - 0x8b,0x7d,0xaf,0x08,0x00,0xa2,0x0e,0x50,0x5d,0x10,0x5e,0x2f,0xcb,0x24,0x57,0x4c, - 0x29,0x3d,0xcb,0xc9,0x6a,0xaf,0x5c,0xb9,0x55,0x3a,0x43,0x78,0xde,0x28,0xed,0xf2, - 0x34,0xc6,0xb1,0x37,0x8a,0x12,0x97,0xd8,0x3e,0x68,0xcd,0x4b,0x10,0x45,0x70,0x4c, - 0x93,0x74,0x31,0x5f,0xae,0x22,0x55,0x8a,0xd3,0x82,0x9c,0x49,0x74,0x5b,0xdd,0x9d, - 0x88,0xfd,0xc5,0x4f,0x87,0x40,0x69,0xc5,0x7e,0x52,0xe4,0x0f,0xd3,0xdb,0x27,0x61, - 0x86,0x62,0x87,0x3f,0xb9,0x6f,0x09,0x49,0xb8,0x47,0x60,0x6f,0x0d,0xbd,0xec,0xd6, - 0x83,0x19,0xaa,0xf0,0xc0,0xaf,0x90,0xf1,0xa6,0x9a,0x69,0x4a,0x8d,0xe1,0x6a,0x2a, - 0x5e,0xbb,0x31,0x69,0x45,0x7d,0x41,0xb5,0x51,0x1c,0x06,0xa0,0x27,0x73,0x37,0xe8, - 0x3f,0x49,0xc7,0x71,0x9f,0x9a,0x06,0x4b,0xc5,0x45,0x27,0x1e,0x2c,0x63,0x20,0x4d, - 0x7d,0x1e,0xf4,0x6e,0x37,0xc7,0xc7,0x2e,0xc9,0x1f,0x1a,0x1a,0x42,0x41,0x81,0xbc, - 0xaa,0x38,0x6c,0x79,0x40,0x00,0x32,0xaf,0x1f,0xa1,0xdc,0x91,0xdd,0xc3,0x7c,0x6b, - 0x54,0x5c,0x22,0x36,0x3e,0x2b,0xc4,0xae,0xee,0x9b,0x50,0xed,0xa2,0xa6,0x4a,0x3f, - 0x04,0xb6,0xa9,0xb8,0xb3,0xaf,0xa5,0x11,0xc4,0x08,0x13,0xc1,0xe3,0x8a,0x9c,0xce, - 0x5e,0xda,0x17,0xcd,0xb4,0xbc,0x1b,0x98,0x9c,0x54,0x1f,0xc9,0xa2,0x37,0xf4,0x40, - 0x86,0xf2,0x96,0x72,0xe6,0x4c,0xb3,0x5f,0xed,0x84,0xd8,0xef,0xfa,0x84,0x4c,0xf8, - 0x20,0x86,0x77,0xa0,0xad,0xdb,0x12,0x41,0x22,0x21,0xbf,0xd8,0xb5,0x3d,0x00,0x40, - 0xa9,0x67,0x3a,0x3c,0x7b,0xc0,0x32,0x8e,0xae,0xbd,0xf1,0xd6,0xa2,0xca,0x35,0x30, - 0xab,0x59,0x97,0x57,0xf6,0x9f,0xba,0xd6,0xed,0xe0,0xb2,0x14,0xdc,0xc7,0x30,0x0b, - 0x15,0x5a,0xf9,0x21,0xf1,0xc9,0xcf,0x45,0xdf,0x12,0xe9,0x53,0xec,0xd5,0xaa,0x55, - 0x5c,0x27,0xa3,0x36,0x74,0x64,0xef,0xec,0x57,0x25,0x96,0x0a,0x61,0xec,0xd7,0x0e, - 0xbb,0x4c,0x1c,0x68,0x73,0xd7,0x07,0x09,0x7c,0xf5,0x68,0xf9,0x0c,0xd1,0xa7,0x5c, - 0xae,0x07,0xc0,0x71,0x87,0x81,0x37,0x5e,0x4a,0xb4,0x75,0xf6,0x64,0x8f,0xc6,0xde, - 0xc4,0x5d,0x04,0x59,0xb1,0x99,0xf9,0xb2,0xb2,0x07,0xc8,0x31,0xee,0x0b,0x0e,0x05, - 0x59,0x71,0x68,0xb8,0x0c,0xf7,0xca,0xaa,0x5e,0x27,0xe0,0x75,0x0b,0x42,0x54,0x01, - 0xaf,0x75,0x9a,0x86,0x10,0x05,0xa2,0x0f,0xf2,0xaf,0x1b,0xb4,0x68,0x4e,0x7b,0x1d, - 0xd5,0x01,0x27,0x2a,0x10,0xe6,0x55,0x1c,0x42,0x74,0x6d,0x19,0x9d,0x12,0x83,0x50, - 0x80,0x59,0x84,0x20,0xe3,0x1a,0xbd,0x24,0x79,0x4e,0x95,0x90,0xed,0x89,0x3a,0x31, - 0x07,0x12,0x30,0xf7,0xc6,0x1b,0xba,0x49,0xbe,0xe4,0x27,0xfe,0x9d,0x37,0xe6,0x25, - 0xd6,0xee,0x27,0x04,0x16,0x58,0xf6,0xcc,0xa7,0xe6,0xb2,0x7d,0xb7,0xfd,0x84,0xde, - 0x00,0xd7,0x6a,0xbd,0xac,0xa3,0x30,0x12,0x67,0x8a,0x50,0x12,0x58,0xb2,0x60,0xd4, - 0xa4,0xd7,0x2d,0xc3,0x0b,0x6f,0x9a,0xa9,0x3b,0xf1,0x5a,0xd0,0x67,0xb7,0x45,0x74, - 0x47,0xb0,0xc9,0xc0,0xb5,0xc8,0x09,0xa5,0x6d,0x6d,0xd5,0xa6,0xd9,0x25,0xf8,0x8b, - 0x81,0x39,0xe9,0xac,0xb4,0xdd,0xe4,0xdf,0x80,0xe0,0x97,0x49,0xbc,0xf6,0xd1,0x49, - 0x63,0xb1,0x11,0x61,0x62,0x10,0x65,0xcb,0xaf,0x11,0xe1,0xca,0xba,0x96,0xb2,0x10, - 0xc5,0x58,0x8a,0xd5,0x42,0x43,0xd9,0xb3,0xb8,0x81,0x83,0xa7,0x6a,0xa9,0x1f,0x4f, - 0x0c,0x1c,0xa0,0x9e,0xde,0xae,0x6c,0x65,0x2f,0xdb,0xcf,0x42,0xfb,0x67,0xea,0x35, - 0xbe,0x42,0x2d,0xb6,0xeb,0xcd,0x45,0x07,0xff,0xde,0x95,0x42,0x35,0x4e,0x40,0x9e, - 0xb1,0xf9,0x11,0xa0,0x3b,0xfa,0x5b,0x57,0x0d,0xd5,0x7a,0xeb,0xfa,0xd9,0x73,0x6a, - 0x25,0x2e,0x77,0x7d,0xb5,0x92,0x11,0xce,0xfc,0xc0,0x4b,0xff,0x12,0x8b,0x8f,0x4a, - 0x0a,0x8d,0xc5,0x17,0x18,0x82,0xf5,0xae,0x22,0xce,0xeb,0x10,0x97,0x56,0x68,0x57, - 0x55,0x51,0xcb,0xe6,0xac,0xe4,0x99,0xea,0xa8,0xeb,0x5f,0x46,0x16,0xea,0x46,0x01, - 0xcf,0x0f,0xea,0x94,0xb7,0x9c,0x2f,0x5d,0x96,0x39,0xd6,0x8a,0x8a,0x6f,0x05,0x63, - 0x36,0x72,0xc3,0x1b,0x37,0x5d,0x56,0xf9,0xa7,0x3d,0x24,0xf8,0x85,0x21,0x43,0x63, - 0xa1,0x97,0x3d,0x9f,0x9f,0xd7,0xea,0x7c,0x96,0xc2,0x84,0xa4,0xe8,0xc2,0x96,0x5f, - 0xa4,0xa0,0xda,0x9e,0xbe,0x56,0x59,0x5b,0xc7,0xcb,0xf3,0x86,0x85,0xc4,0x9e,0x47, - 0xd1,0x0b,0x5c,0xa5,0x7b,0x2e,0xd6,0xd9,0xe6,0x0c,0x40,0x66,0x52,0xc9,0x9e,0x97, - 0x75,0x1a,0x7f,0x45,0x22,0xc2,0xaa,0x53,0xc0,0xa6,0x60,0x59,0xc3,0x24,0xa7,0x30, - 0x1b,0xc0,0x64,0x7b,0xc1,0x57,0x53,0xe0,0x95,0x7b,0xd4,0x5a,0x75,0x5a,0xaf,0x25, - 0x54,0xf2,0xac,0xe2,0x51,0xcd,0xe3,0x96,0xd0,0x42,0x8d,0xf6,0x9f,0x92,0x56,0xff, - 0xfe,0x03,0x84,0xca,0x32,0x35,0x76,0x4b,0x1d,0x7e,0x81,0x8f,0x00,0x1e,0xd8,0x61, - 0x50,0x91,0x29,0x70,0x78,0x77,0xef,0x66,0x96,0xcf,0x56,0x41,0x91,0xd9,0x46,0xe2, - 0x6f,0xb0,0x36,0x33,0xcd,0xbc,0xb8,0x46,0x8f,0xb8,0x5f,0xdd,0x86,0xb4,0xfc,0x48, - 0x22,0x18,0x3d,0x64,0x63,0x95,0xcd,0xa4,0x5b,0x37,0x31,0x34,0x85,0x79,0x25,0xb5, - 0x4a,0x3b,0xc9,0x7e,0x47,0x80,0xa4,0x65,0x86,0x05,0xf9,0x8d,0xfd,0x5d,0x29,0x1c, - 0x28,0x1e,0x9f,0xe0,0x4a,0x4f,0x48,0x3e,0x7f,0x6b,0xb6,0xe0,0x8b,0xa5,0xb8,0x98, - 0xdd,0x5a,0x81,0xe6,0xba,0x48,0x9b,0x49,0x59,0xf5,0x6c,0x1d,0xe5,0x1a,0x36,0x3b, - 0x17,0xcb,0x74,0xf1,0xa3,0x5b,0x2f,0x18,0xf5,0x73,0xc5,0xf3,0xab,0xf6,0xcd,0xad, - 0x1c,0x36,0xb3,0x33,0xb2,0x26,0xe4,0x4c,0x70,0x1e,0x61,0x7e,0xca,0xf0,0x90,0x02, - 0x9b,0x1c,0xea,0x5e,0xbb,0xfe,0x00,0xed,0x29,0x8e,0x6a,0x85,0x4c,0xa2,0x51,0x0f, - 0x91,0xa2,0x18,0x08,0xc6,0x41,0xd1,0xad,0x7a,0xf6,0x2b,0xf6,0x43,0x41,0x5a,0xbb, - 0xba,0x8c,0xdb,0xcd,0x85,0x9c,0x9d,0x75,0x2b,0x1c,0xe6,0xba,0xb5,0xea,0x64,0x40, - 0x13,0xf2,0xdc,0xd0,0x9f,0x33,0xd5,0x4f,0x8c,0x4e,0x6a,0x60,0x15,0xc0,0xd6,0xf9, - 0xe1,0x04,0xcf,0xc2,0xbd,0x7e,0x9d,0x70,0xf0,0xd8,0xf8,0x5f,0xd7,0xde,0xfd,0x24, - 0x71,0xe7,0x5e,0x6a,0x24,0xcb,0x2c,0x5a,0xe6,0x58,0x94,0x44,0x19,0xa0,0x50,0x73, - 0x67,0xbf,0x3d,0xf6,0xa6,0xd6,0x23,0x8c,0x03,0x98,0x01,0x3a,0xf5,0x5c,0x96,0x39, - 0x84,0x82,0xe6,0xa0,0xa8,0xc2,0x21,0x26,0x2e,0x57,0x4c,0xe1,0xee,0x05,0x35,0x5d, - 0xdf,0x54,0x38,0xb7,0x7e,0x61,0xe1,0x3d,0x43,0xb3,0xd1,0x2d,0x09,0x42,0xed,0xe7, - 0xec,0x0a,0xd4,0xf6,0x7a,0xaa,0x7f,0x7d,0x53,0xbb,0xed,0xd7,0xd0,0x69,0xc8,0x29, - 0x76,0x66,0x6d,0x61,0x68,0x98,0x42,0xd2,0xc4,0xf3,0x8f,0xea,0xe0,0xbb,0xb7,0xd4, - 0xf1,0xf3,0x1b,0x7f,0x8e,0x06,0x0a,0x6e,0x48,0xbb,0x55,0x94,0x79,0x55,0x49,0xb0, - 0x42,0x23,0x9f,0xc5,0xf4,0x1c,0x94,0x94,0x42,0xc4,0xba,0xd4,0xaa,0xfb,0x01,0xd3, - 0xe7,0xcb,0x56,0x2b,0x9b,0xf4,0x5e,0x8c,0x5f,0x7a,0x6d,0xcf,0xed,0xc3,0xcb,0xd8, - 0x9f,0xf7,0x5e,0xec,0x8f,0x5f,0x8e,0x0e,0x26,0xf8,0x4a,0xc7,0xf3,0x7b,0x07,0xee, - 0xfe,0x84,0x5e,0xa7,0x68,0x8c,0xb0,0xf7,0x72,0xd4,0xdd,0xf7,0xf0,0x95,0x6c,0x15, - 0x26,0x93,0x97,0xc3,0x97,0x5d,0x7c,0x65,0x5b,0x05,0x6f,0x67,0xb8,0xb3,0xdb,0x29, - 0x1c,0xbf,0xbd,0x68,0x0f,0xdb,0x5e,0xa7,0x5b,0x18,0x51,0x36,0xa9,0x39,0x47,0x7a, - 0xd1,0x6d,0x77,0x0f,0x76,0xba,0x75,0x67,0x48,0x4c,0xb6,0x26,0xee,0xdc,0x0f,0xee, - 0x7b,0x85,0xf3,0xb7,0xf3,0xb7,0x1f,0xe0,0xb9,0x75,0xe6,0x4d,0x17,0x81,0x9b,0x94, - 0x8f,0xe3,0xcc,0xf7,0xfe,0xd0,0x63,0x8e,0xc9,0xc0,0x7c,0x66,0x7e,0x40,0x57,0x24, - 0x85,0x48,0x6f,0x0b,0x27,0x7f,0x7b,0x45,0xb4,0xc5,0x3f,0xad,0xb1,0x9f,0x78,0x23, - 0x5a,0x87,0xcc,0xbd,0x56,0x30,0xa0,0x21,0x8a,0xbf,0x3c,0x80,0x7d,0x49,0xd7,0xda, - 0xee,0x12,0xf7,0xca,0x47,0x7b,0x4d,0x41,0x24,0xa1,0x12,0xb4,0x86,0xb1,0x96,0x3c, - 0x17,0xc5,0xe3,0x87,0x47,0xb6,0x37,0xc0,0xe3,0x9f,0xd6,0x28,0xf0,0x97,0x25,0x6b, - 0x80,0xb6,0x98,0xc1,0xd6,0x6c,0xfc,0x6c,0x89,0x2b,0x3f,0x6e,0x2d,0x6b,0x19,0x8a, - 0xd3,0xd5,0xe9,0x74,0xf6,0x3b,0xe3,0x95,0x6b,0x4e,0xce,0x52,0xde,0x5f,0xe7,0xa0, - 0x5b,0xda,0xd4,0x11,0x91,0xac,0xbc,0x8b,0x45,0x09,0x54,0x26,0xea,0x47,0x6e,0xac, - 0xe9,0xad,0xd7,0xfc,0xea,0x4d,0xbb,0x3b,0x3b,0x3b,0x15,0x35,0x18,0x0e,0xa0,0xd2, - 0x7a,0x91,0xd1,0x54,0x0c,0x86,0x10,0x0a,0xab,0xea,0xc2,0x42,0xa7,0x6a,0x0e,0x6d, - 0x73,0x8c,0x15,0x14,0xfb,0xc5,0xce,0x78,0xd7,0xdd,0x73,0x65,0xd9,0x68,0x91,0x49, - 0x7e,0x41,0x59,0x69,0xdc,0x33,0x4b,0x52,0xb1,0xda,0x28,0xf0,0x3b,0x7d,0x69,0x76, - 0xa2,0xb2,0xf1,0x09,0x0f,0x7e,0xcf,0xa2,0xc5,0x68,0xa6,0xb5,0x70,0x88,0x46,0x05, - 0x3a,0xdb,0x19,0x27,0x5e,0x8b,0xcc,0x06,0xf0,0x60,0xac,0x35,0x4c,0x3c,0xf7,0xba, - 0x47,0x7f,0x5b,0x98,0xa0,0x95,0x34,0x9c,0xd1,0x7c,0x2c,0x06,0x84,0xaa,0xc4,0xf2, - 0xa7,0x8a,0xda,0xf2,0xd0,0x30,0x8b,0x53,0x3a,0x15,0x82,0x9d,0x2a,0x05,0x92,0x9b, - 0xac,0xf0,0xa5,0xe7,0xbd,0x3c,0x78,0x59,0xf8,0x8a,0xea,0x9d,0x42,0x79,0x21,0x70, - 0xe6,0x39,0xd2,0xfb,0x74,0xb9,0x12,0x69,0x28,0x07,0x60,0xee,0x52,0xac,0x20,0x67, - 0x6f,0x8f,0xa5,0x26,0xfc,0xe8,0x86,0xa3,0x59,0x94,0xd4,0xa8,0x9b,0x45,0x66,0xed, - 0x9c,0x23,0xd7,0xf3,0xc8,0xc2,0xe9,0x62,0x5a,0xa3,0x16,0x5e,0xa5,0x26,0xd2,0x98, - 0x4d,0xc1,0x60,0x2f,0xa6,0x90,0x66,0xef,0xee,0xde,0xcc,0xac,0xca,0x4c,0x17,0xc9, - 0x9e,0xd7,0xd9,0xe9,0xb8,0xf5,0x6a,0xa4,0x9c,0xd4,0x69,0xe7,0x6f,0x2d,0x62,0x7f, - 0x91,0xed,0x28,0x18,0x31,0xed,0xed,0x11,0x3b,0x39,0xad,0x3f,0x6a,0x28,0xac,0xf8, - 0x21,0xb0,0xdc,0x48,0xc6,0x14,0x82,0xed,0xc9,0x15,0x5e,0x41,0xf8,0x74,0x8a,0x5b, - 0x5c,0xd1,0x58,0x44,0x6c,0x76,0x7b,0x6d,0x29,0xde,0xbe,0x18,0x4d,0xbc,0x1d,0x20, - 0xfe,0x25,0x94,0x13,0xc5,0x8d,0x45,0x71,0xfe,0x88,0x7b,0x29,0xab,0x63,0xea,0xe4, - 0x56,0x2e,0xef,0xeb,0x66,0x33,0xfd,0x75,0xa7,0x0e,0xce,0xc1,0x6e,0x1d,0x81,0xe9, - 0x37,0xfe,0x8a,0xa0,0x96,0x4e,0x4b,0xac,0xf9,0x8b,0x8e,0xd7,0x1d,0xee,0xb8,0xfa, - 0x9c,0x10,0xef,0x49,0x56,0x65,0x78,0x36,0xaa,0x0d,0x53,0x96,0x07,0x18,0x16,0xd6, - 0x14,0x27,0xfa,0x32,0xf1,0x60,0xf8,0x6a,0xe8,0xaa,0x65,0x88,0x33,0xf3,0x17,0xa8, - 0xf5,0x41,0x2d,0xb5,0x7e,0x06,0x96,0xc9,0xf6,0xe3,0x54,0x9b,0xf0,0x9a,0xb5,0xfd, - 0x82,0x72,0xf9,0x61,0xcd,0xa9,0x95,0x76,0xf2,0x96,0x8b,0xfa,0x05,0x2a,0xbc,0x4a, - 0xf4,0xa7,0x73,0x8b,0x46,0x81,0x18,0xeb,0xa7,0xdf,0x7d,0x90,0x63,0xbd,0xac,0xb5, - 0xa6,0x37,0x85,0x13,0x6c,0x6a,0x56,0x4d,0x0f,0xe3,0x92,0xca,0xd8,0x03,0xc0,0x8e, - 0xbc,0x59,0x14,0x8c,0x15,0xed,0x7e,0xb1,0xfb,0x6a,0xef,0xe5,0xfe,0x4b,0x2d,0x93, - 0x52,0xd2,0xaf,0x24,0x3d,0xd3,0x68,0x59,0x05,0x7e,0x57,0x02,0xff,0x99,0x9b,0xd2, - 0x7e,0x69,0x9e,0xaa,0x30,0xaf,0x6e,0x52,0xf5,0x9b,0xd2,0x34,0xaa,0xdb,0x8d,0x10, - 0x46,0x6b,0xf7,0x23,0x28,0x56,0x3d,0x8f,0xd8,0xad,0x9c,0x47,0x70,0xe6,0xd1,0x64, - 0xbe,0x7c,0x6a,0x60,0xf2,0xac,0xaa,0xc0,0x7a,0x13,0xd7,0x57,0xc7,0x84,0x16,0x39, - 0x8a,0x6e,0xe7,0xa0,0x33,0xa9,0x22,0xb2,0x50,0x52,0xec,0x8b,0xd3,0x4b,0xd9,0x15, - 0xc3,0x99,0x15,0x07,0xcb,0x8d,0x14,0xd9,0xd8,0x3d,0xc5,0xc5,0x72,0x91,0x20,0x94, - 0x53,0xee,0xbe,0x1a,0xbe,0x1c,0xed,0xf7,0x9f,0xbf,0x4d,0x2a,0x35,0x14,0x8f,0x91, - 0x1b,0x0d,0xed,0x9d,0xd1,0x4c,0x68,0xf5,0x70,0x07,0x41,0x89,0x11,0x95,0xfb,0xad, - 0x8e,0xf1,0x9d,0xa1,0x67,0xb1,0x4a,0xdd,0x58,0xa5,0xab,0x5b,0x89,0x6f,0x54,0xee, - 0x76,0xcd,0x88,0xab,0x07,0xe6,0xce,0xab,0x7c,0x33,0xa4,0xe2,0xc3,0x2c,0xac,0x51, - 0x70,0x48,0x3a,0x42,0x63,0xef,0x11,0x00,0x8a,0x02,0x9c,0x5e,0x87,0x60,0xc7,0xbe, - 0x02,0xbf,0x0b,0x53,0x3c,0xec,0xee,0xed,0xb4,0x2b,0x3c,0x7e,0xa3,0x96,0x0b,0xdb, - 0x15,0x5a,0x9e,0x15,0x18,0x9f,0xf7,0xc6,0x81,0xb5,0x58,0x68,0x65,0xbc,0x33,0xec, - 0x1e,0x94,0xf0,0xbe,0x3b,0xd9,0x1f,0xee,0xee,0x29,0x1b,0xc3,0x89,0xd7,0x76,0xf7, - 0xaa,0x55,0xd5,0xad,0x86,0xea,0xf1,0x9c,0x03,0xbc,0x76,0x2b,0xf3,0xe3,0x27,0x2d, - 0x37,0x35,0x38,0xbe,0x2a,0x8b,0xb8,0x4a,0x88,0x2d,0xc2,0x3e,0xaf,0xdd,0xb8,0x1e, - 0x8e,0x97,0xd5,0xb3,0xcf,0x3a,0xf1,0x86,0xe5,0x99,0x5c,0x68,0x59,0x21,0x05,0x36, - 0x8a,0xb3,0xb3,0xab,0x89,0x81,0x6d,0xd6,0xa5,0xbd,0xde,0x16,0x16,0xee,0xaf,0xb7, - 0x85,0x45,0x3e,0xca,0x17,0xc2,0x3e,0xdf,0x4b,0xd0,0x02,0xfe,0x66,0x6a,0xb0,0xc1, - 0xbd,0xd9,0xdd,0x37,0x0d,0xe6,0x7a,0xf8,0x19,0x2d,0xea,0xbf,0x8f,0xee,0x06,0x26, - 0x99,0x08,0xed,0xc2,0xff,0x4d,0x03,0x95,0xf5,0x03,0x13,0x51,0xdb,0x34,0xd2,0x2c, - 0x89,0xae,0xd1,0x84,0x5f,0x69,0x31,0x64,0x5a,0x4b,0xd6,0xa8,0x12,0x90,0xf4,0x8f, - 0xdc,0x78,0x60,0xd2,0x28,0xd0,0x32,0x7f,0xe4,0x27,0xa3,0xc0,0x33,0x46,0x50,0x7f, - 0x07,0xf2,0x8d,0xee,0xf9,0x37,0x81,0x52,0x4e,0x57,0x36,0x54,0xad,0x5a,0x34,0xbe, - 0x0d,0x35,0xc4,0x6e,0x36,0x33,0xc6,0x03,0xf3,0xc3,0x4b,0xe7,0xa5,0x01,0xff,0xdc, - 0x7d,0x63,0xdf,0x68,0x8b,0xff,0x1d,0x38,0xfb,0x1f,0x3a,0xfb,0xce,0x4e,0xe1,0x43, - 0x47,0x7c,0xd8,0x75,0x5e,0x19,0xf0,0xcf,0xed,0xa0,0xdd,0xb2,0x2a,0xd2,0xd9,0x75, - 0xba,0x1f,0x3a,0xaf,0x9c,0x4e,0xe9,0x5b,0x47,0x7c,0xa3,0x46,0xb7,0x01,0x60,0xf0, - 0x03,0x2c,0xb9,0x31,0x02,0x59,0x33,0x1d,0x98,0x64,0xf8,0x4b,0x3e,0x0f,0x1d,0xc3, - 0x87,0xee,0xcc,0x5a,0xe8,0xd9,0x60,0x2a,0xa7,0x03,0x00,0x7d,0x47,0x94,0xe0,0xcf, - 0xe9,0x62,0x68,0x1e,0x02,0xcb,0x1d,0xa2,0x58,0x19,0x4e,0x37,0x66,0xc4,0xb2,0xf4, - 0x5f,0x6f,0x43,0x16,0x6c,0x81,0x7f,0xc8,0x2e,0x43,0x34,0x41,0x96,0x9f,0x06,0x2a, - 0x14,0x4c,0x51,0x07,0xa5,0x98,0x87,0xd0,0x1d,0xc8,0x86,0xd3,0x4a,0xe8,0xae,0xba, - 0x84,0x36,0xa8,0x85,0xfc,0x23,0x92,0x8d,0xe1,0x95,0x8c,0xe5,0x4c,0xce,0x6e,0x1a, - 0x51,0x08,0xc8,0x39,0xba,0x46,0xaf,0x0d,0x58,0x39,0x2c,0x40,0x7b,0x4d,0xcb,0x6c, - 0x90,0x83,0xc4,0xc0,0x14,0x29,0x46,0xab,0x65,0xa4,0xd7,0x80,0xc2,0x64,0x7c,0x6a, - 0xb8,0xe1,0xd8,0x88,0xdd,0x34,0xf3,0x0c,0xd7,0x00,0x22,0x8b,0x27,0x42,0x63,0x74, - 0xdf,0x98,0xf8,0x53,0xb3,0xe1,0x26,0xbe,0xdb,0x22,0xa3,0xc2,0x81,0xf9,0x29,0xf6, - 0x42,0x43,0x36,0x7d,0xb8,0x31,0xcd,0xfa,0x9f,0x5f,0x6f,0x73,0xdb,0x12,0x25,0x09, - 0x09,0xd1,0x54,0x15,0x87,0xcc,0x72,0x36,0x75,0xf9,0xa6,0x15,0x44,0xb0,0xd6,0xcc, - 0x7c,0x48,0x30,0x98,0x22,0xe0,0x51,0x19,0x4e,0x70,0xef,0x1e,0x1e,0x8f,0x81,0x6d, - 0x31,0xa8,0x04,0x54,0xdb,0x45,0xe4,0x30,0x08,0xf3,0x07,0x66,0x45,0x31,0xb5,0x6a, - 0x55,0x4b,0x99,0x17,0xd6,0xb0,0x79,0xf8,0x06,0xe1,0x61,0x64,0x33,0x3f,0x35,0xc2, - 0x68,0xec,0x6d,0xa6,0x86,0x4b,0x4d,0x48,0x73,0x44,0xa3,0x99,0xcd,0x3c,0x23,0x85, - 0x89,0x06,0x18,0x7a,0xc6,0x22,0x05,0x08,0x80,0x28,0x65,0x24,0xde,0x3c,0x02,0xb8, - 0x9c,0xbc,0x7f,0xc7,0x05,0x2c,0xe7,0xf5,0x76,0x0c,0xdd,0x41,0x15,0x1c,0x8d,0x8b, - 0xfa,0xd8,0xc2,0xd7,0xd2,0x68,0x26,0x30,0x9b,0x04,0x36,0xac,0x47,0xe6,0x8b,0x6f, - 0x61,0x84,0xa7,0xa2,0xcd,0xd7,0xdb,0xf4,0x1d,0x8a,0x91,0xf5,0x86,0x98,0x4a,0xd9, - 0x23,0x53,0xab,0x1e,0x8b,0x91,0x85,0xef,0x28,0x9a,0xc7,0x81,0x97,0x41,0x36,0xa0, - 0x79,0x78,0x6e,0xd7,0xca,0xb3,0xe3,0x77,0xe2,0xb2,0x0e,0x25,0xca,0x15,0x91,0x08, - 0x76,0x17,0x89,0x2e,0x80,0xb1,0x73,0x3f,0xd3,0x5b,0xc0,0x8f,0x87,0xe7,0xc0,0xc7, - 0x1a,0x08,0x71,0x35,0xa5,0xda,0x78,0xa4,0x76,0x51,0x2f,0x05,0x69,0xa6,0x6a,0x6d, - 0x1b,0x81,0x90,0xe3,0xfb,0xb6,0x98,0xfd,0x0a,0x1e,0xdc,0xfa,0x5f,0x70,0xa2,0xd7, - 0x20,0x02,0xea,0xd2,0xb8,0x99,0x51,0xe8,0xb6,0xe8,0xed,0xf0,0x5d,0x68,0xe0,0x0c, - 0xfd,0xea,0xbf,0xf5,0x8d,0x94,0xf8,0x6d,0x98,0xbc,0x28,0x5e,0xc4,0x47,0xc6,0xbb, - 0x0c,0x0a,0x46,0xa9,0x97,0x1a,0xfe,0xc4,0xb8,0x8f,0x16,0x89,0x11,0xcf,0x70,0x12, - 0xd3,0xc0,0xf3,0xe2,0xd4,0x69,0xbc,0x76,0x8d,0x59,0xe2,0x4d,0x06,0xe6,0x0b,0x6d, - 0x81,0x40,0xd9,0x4f,0x8b,0xac,0x69,0xf5,0x81,0x71,0x5d,0x24,0xa1,0x31,0x71,0x83, - 0x94,0x68,0x20,0x21,0x59,0x55,0xd6,0x30,0x0f,0x09,0xf9,0xa1,0x55,0x6a,0x61,0x98, - 0x44,0xb7,0xa9,0x97,0xbc,0xde,0x76,0x0f,0x8d,0x2c,0x32,0xae,0xa1,0x25,0xd1,0x74, - 0x12,0x4d,0x13,0x2f,0x4d,0x1d,0x09,0x07,0x6d,0x5c,0x74,0x98,0x00,0x00,0xf3,0x69, - 0x6c,0x69,0x16,0x77,0x14,0x14,0x60,0xf1,0x02,0x20,0x7d,0xed,0x5b,0xb7,0x9c,0xb0, - 0x53,0x4e,0xd8,0x15,0x09,0x5a,0x43,0xf8,0xe5,0xf6,0x4b,0x67,0xf5,0xc2,0x3a,0x87, - 0x2e,0x00,0x01,0xdc,0x98,0x83,0xa8,0x15,0x65,0x7d,0x82,0xe7,0xdf,0xb2,0xc2,0x44, - 0xd3,0x30,0xbb,0x13,0x1f,0xa8,0x53,0x7c,0x6f,0x1e,0x9e,0x30,0x49,0xcc,0x57,0x1d, - 0x42,0x8a,0x80,0x44,0xb3,0x18,0x7a,0x19,0x20,0xee,0x35,0x30,0x28,0x86,0x0f,0x33, - 0x08,0xd4,0x11,0x78,0xb9,0xd1,0x8c,0xa6,0xf9,0xc3,0x7f,0x5d,0x5c,0x00,0x71,0x4a, - 0x80,0x63,0x4e,0xc5,0x8a,0x2b,0xe3,0xc7,0xe1,0xeb,0xe1,0xe1,0x29,0x11,0x2b,0xa0, - 0xb9,0xfa,0x5a,0x1d,0x7b,0x71,0x10,0xdd,0xcf,0x61,0x71,0x1c,0x01,0x26,0x1f,0x1a, - 0x17,0xd8,0x3c,0x23,0x9d,0x91,0x79,0x69,0x96,0xe6,0x88,0xc4,0xea,0x12,0x28,0x38, - 0x8c,0xa2,0xcc,0x31,0xde,0x4d,0xe8,0x53,0x5e,0x81,0xea,0x23,0x0d,0x20,0x33,0xdc, - 0x1b,0xd7,0x0f,0x90,0xff,0x80,0x7d,0x35,0xf1,0x6c,0x24,0x13,0xc6,0x2f,0xe7,0xdf, - 0x63,0x4f,0x7d,0x37,0x30,0xdc,0xcc,0x80,0x4e,0x31,0xe1,0x74,0xe6,0xb0,0x5d,0x00, - 0xef,0xe8,0x39,0x7e,0x44,0xdd,0x40,0x22,0x9b,0x2c,0x42,0xcc,0x81,0xe2,0x28,0xc2, - 0xc9,0x49,0x53,0x60,0xcd,0x1c,0xc7,0x51,0x19,0xf4,0x8f,0xb0,0xe8,0xe5,0x37,0x07, - 0x06,0xe1,0x31,0x08,0xd1,0x1c,0x84,0x46,0x30,0x87,0x5c,0xd9,0x0c,0x35,0x2c,0xf9, - 0xd6,0xc3,0x8d,0x78,0x59,0xe2,0x43,0x1e,0x77,0x82,0x24,0x2f,0x1f,0x4c,0x1d,0x46, - 0x2a,0x22,0x75,0xf8,0x51,0x8c,0x14,0xf7,0x3a,0xa3,0x79,0x7e,0xfe,0xee,0x07,0x2b, - 0xa7,0x4f,0x5a,0x09,0xc0,0x7b,0xb5,0x4a,0x04,0x77,0x6a,0x96,0x28,0x18,0x53,0x89, - 0xb1,0x9b,0xb9,0xad,0x6b,0xf4,0xfe,0x13,0x03,0x55,0x28,0xc2,0x2f,0x44,0xce,0xdc, - 0xd8,0xcf,0x40,0x7c,0xfe,0x02,0xa5,0xa2,0xc9,0x44,0xd2,0xb8,0x04,0x15,0xb4,0x22, - 0x45,0xe2,0x24,0x09,0xb3,0x66,0x1d,0x51,0x03,0xe8,0x8f,0xaa,0xfb,0xe0,0x3c,0x42, - 0x1a,0x1e,0xdd,0x86,0x40,0xb9,0xf0,0x18,0xcb,0x81,0x8d,0x0d,0x7f,0x7f,0x60,0x26, - 0x11,0xf6,0xc4,0x9c,0x16,0x44,0xb0,0xb2,0xcf,0x01,0x01,0x9b,0x9b,0xa2,0x77,0x9b, - 0x16,0x10,0x43,0x48,0xd0,0x37,0x37,0x84,0xdd,0x5a,0x08,0x3e,0x97,0xac,0x17,0x00, - 0x53,0x43,0xd9,0x71,0xd8,0x25,0x8e,0x04,0x18,0x6b,0xf3,0xf0,0xbd,0x07,0x53,0x6f, - 0x0c,0x03,0x37,0xbc,0x26,0x74,0x87,0x05,0x83,0x1d,0x97,0x38,0xea,0x18,0x5d,0x67, - 0x77,0x03,0xd6,0x5a,0x98,0xc6,0xfd,0x1f,0x7f,0xfa,0x22,0xd3,0x53,0x18,0x67,0x70, - 0xef,0x3c,0x63,0x00,0x1f,0x11,0xbf,0x70,0xfe,0xeb,0x47,0x50,0x9c,0x56,0xe2,0x89, - 0xd0,0x6b,0x33,0xf0,0xc2,0x29,0xf2,0x86,0x3b,0x9d,0xba,0x5e,0xcb,0x39,0xc7,0xec, - 0x2d,0x1e,0xc7,0xf9,0x0c,0x66,0x05,0x3a,0x45,0x6b,0x0d,0x57,0x09,0x61,0x2d,0x10, - 0x56,0x5e,0xf4,0x99,0x9b,0x2d,0x52,0x4c,0x4f,0xdd,0xa9,0x97,0x96,0xfa,0xbd,0x7a, - 0x63,0x53,0x93,0x79,0xfb,0xe5,0xc7,0xa8,0xd9,0x85,0x09,0xfc,0x08,0xfd,0xed,0x19, - 0x67,0xc0,0x4b,0x47,0xe5,0x79,0xd4,0x89,0x65,0xf7,0x99,0x2c,0x09,0x51,0xce,0x6e, - 0x4e,0x39,0x45,0xc5,0x7f,0x07,0x73,0x82,0x80,0xe7,0x69,0x02,0xba,0xe2,0x26,0x06, - 0x91,0xc1,0x08,0xc0,0x93,0x18,0xb4,0x6b,0x02,0xda,0xa2,0x3d,0x9f,0x81,0x72,0x41, - 0x84,0x3c,0x1b,0xae,0xf5,0xd4,0x31,0x4e,0x61,0xc0,0x04,0x45,0xc0,0x6d,0x24,0x1b, - 0x44,0x5b,0x83,0x08,0xb3,0x12,0x5c,0x61,0x05,0xd4,0x50,0xcf,0x7c,0xc2,0xcf,0xbc, - 0x29,0x6e,0xcb,0x5c,0x3a,0x9f,0x74,0x36,0xff,0x97,0x33,0x97,0xc4,0x04,0xdc,0x99, - 0x1b,0x4e,0x71,0x63,0xfc,0x42,0xe3,0x3e,0xf7,0x82,0x26,0x92,0x75,0x8b,0x58,0x56, - 0xca,0xbf,0x66,0xf2,0x93,0xb8,0x05,0xec,0x8a,0xe4,0x14,0xd6,0xe2,0xe0,0xc5,0x6f, - 0xb0,0xab,0xdf,0xc2,0xc0,0x9b,0xe3,0xef,0xe7,0x56,0x3d,0x22,0xb2,0xb7,0x48,0x8e, - 0x8a,0x19,0xec,0x3e,0xc0,0x9a,0x0d,0xcc,0xd6,0x2b,0xc2,0x48,0xc0,0xc5,0xb6,0x22, - 0x1c,0xf9,0xb9,0x75,0xa7,0xdb,0x66,0x5a,0x55,0x59,0x59,0x1f,0xd8,0xf7,0xd8,0x08, - 0xbc,0x29,0x80,0x8e,0xdb,0x87,0x29,0x43,0x22,0x3a,0xbc,0x07,0x7a,0x4a,0x50,0xda, - 0x98,0x8f,0xdd,0x74,0xd6,0x37,0xc8,0xc6,0x56,0x40,0x39,0x59,0x04,0x15,0x14,0xad, - 0xec,0x53,0x1f,0x3d,0xe0,0x25,0xe5,0xa4,0xc1,0x74,0xc1,0x2e,0x81,0x26,0x57,0x9b, - 0x99,0x81,0x86,0x10,0xde,0xf8,0xc8,0x38,0x99,0x45,0xc0,0xbe,0x20,0xf1,0xff,0x19, - 0xf9,0x08,0xc1,0xda,0xa9,0x32,0xb8,0x03,0xd8,0x06,0x1e,0x13,0xc3,0x9c,0x12,0xc7, - 0x6e,0xe3,0xac,0x87,0x98,0xe4,0xb5,0xb2,0x05,0xb0,0x3a,0x3e,0xaf,0xa6,0x5a,0x4e, - 0x87,0x44,0x81,0xe3,0x38,0x2e,0xf3,0x3a,0xc0,0x64,0xdf,0xb8,0xe1,0x08,0x3a,0xe7, - 0x8d,0xfd,0x2c,0x22,0x5e,0xc6,0x29,0x2d,0xb4,0xd2,0x52,0x50,0xec,0x72,0xab,0xc2, - 0xab,0xc7,0x8a,0xfa,0xfd,0x1d,0x2b,0xe2,0xcc,0x23,0x2d,0x20,0x6f,0xd5,0x13,0x77, - 0x04,0xdd,0xbb,0x57,0x4d,0x38,0xc8,0xf1,0xc1,0x8e,0x4c,0x4c,0x3a,0xb0,0x14,0x29, - 0xb3,0xad,0xb4,0x27,0x1b,0x68,0x57,0x91,0x10,0x45,0x81,0x2f,0xc4,0xb2,0x23,0x90, - 0x13,0xaa,0x88,0x36,0x50,0xe6,0x12,0x60,0xa9,0xa1,0x3a,0x4e,0xd1,0xa0,0x75,0xcb, - 0xe4,0xa3,0x77,0xab,0x0d,0xef,0x79,0xc4,0x3d,0x4f,0xd1,0x48,0x64,0x67,0xaf,0x4c, - 0xeb,0x43,0xef,0x36,0xe7,0xe0,0xd7,0xa1,0x66,0x67,0x8f,0xdc,0xee,0x01,0x12,0xcc, - 0x11,0x3d,0xb9,0x90,0xc8,0x33,0x1e,0x64,0x94,0xaf,0xea,0xf8,0x68,0x32,0xff,0x93, - 0x5d,0x5f,0x8d,0x37,0xc8,0x30,0xac,0xde,0xb6,0x8b,0x64,0xbb,0x03,0xf4,0xe4,0x7b, - 0x77,0x74,0xad,0xd1,0xeb,0x1a,0x52,0x5f,0x64,0x09,0x14,0x91,0x41,0xba,0xd4,0x0a, - 0x69,0x93,0x2a,0xd6,0xba,0xa3,0x36,0x03,0xdc,0x61,0xaa,0x7b,0x41,0x65,0x4b,0xd8, - 0xf9,0x9a,0x2d,0x61,0x27,0xdf,0x12,0xb8,0x7a,0xc2,0xff,0xda,0x39,0xf9,0x34,0x64, - 0x96,0x56,0x30,0x59,0x51,0xe2,0x03,0xe2,0x5b,0xcf,0xd9,0x6d,0xe7,0x7f,0x64,0x99, - 0xc3,0xf9,0xeb,0x39,0xa7,0x3a,0xdc,0xf9,0x29,0xba,0x65,0xde,0x3b,0x92,0xed,0xf2, - 0x56,0x32,0x41,0xc2,0xe6,0x67,0x40,0xb6,0x27,0xb8,0x6c,0xe2,0xc5,0x10,0x08,0xd1, - 0x0c,0x89,0x14,0xed,0xbd,0xdb,0x20,0xf5,0x5c,0xc3,0x6e,0xa2,0xb6,0x60,0xe3,0x5d, - 0x88,0xa2,0x1d,0x69,0x41,0x81,0xe8,0xd1,0x3e,0x25,0xa9,0x21,0x72,0xc5,0x4a,0x58, - 0xce,0xa2,0xd8,0x1f,0x41,0x73,0x09,0x76,0x71,0xc6,0xbb,0x16,0x16,0x82,0x9d,0x0a, - 0xa8,0x92,0x1f,0x04,0x90,0x0f,0x99,0xd6,0x7c,0x31,0x22,0x20,0x9e,0x83,0xcd,0xef, - 0x8e,0x2f,0x8e,0x25,0x21,0x1e,0x41,0xc1,0x67,0xc3,0xcc,0x87,0x97,0x22,0x9b,0x52, - 0x85,0x5f,0xbe,0xb0,0x14,0x6e,0xad,0xb4,0x84,0x7b,0xce,0x76,0xf2,0x11,0xf6,0x70, - 0x90,0x33,0x0c,0xd7,0x4f,0xd0,0x3e,0x84,0x3a,0x6c,0x1b,0x9e,0x33,0x75,0x90,0xc4, - 0xff,0xf0,0xe6,0x23,0xb3,0xf4,0xbf,0x20,0xd8,0x90,0x70,0x23,0xd4,0x0c,0x54,0x7e, - 0x3d,0x6b,0x61,0x7f,0xba,0x0d,0x61,0x26,0x69,0xd2,0x46,0x20,0x77,0xde,0x3f,0x1f, - 0x7d,0xb0,0x60,0x01,0x16,0xfb,0xbb,0xcf,0x66,0xc3,0x9f,0xc7,0xa2,0x7e,0x8a,0x05, - 0x8e,0x48,0xf4,0xd8,0xdf,0x6d,0x21,0x74,0x81,0x34,0xdf,0x69,0x5d,0x36,0x22,0x21, - 0xa7,0x63,0x8d,0x6e,0x88,0x93,0x8a,0xd8,0x80,0x88,0x36,0x0a,0x16,0x63,0x06,0x0b, - 0xa2,0x90,0xf1,0x9f,0xbf,0x5e,0xa4,0x28,0x20,0x22,0xfe,0xfa,0xbc,0x1f,0xc0,0xf6, - 0x99,0xc2,0x7c,0x20,0x60,0x85,0xd8,0x18,0x30,0xeb,0x83,0x5d,0xf1,0xe7,0xb9,0xb4, - 0xf9,0x7c,0x60,0x92,0xaf,0x69,0x3d,0x1c,0xe9,0x53,0x09,0x90,0x22,0xed,0xb9,0xcb, - 0xb0,0x02,0x14,0xd8,0x7d,0x41,0xe4,0xad,0x1d,0x2a,0xae,0x22,0x1a,0x06,0x0a,0x73, - 0xb9,0xdc,0x0c,0x00,0x4a,0x23,0x20,0x19,0x12,0x0c,0xa5,0xa1,0x21,0x29,0x62,0x59, - 0x59,0xa3,0x3e,0x52,0xd8,0x0a,0xa2,0x2c,0xfd,0xbb,0xe8,0x73,0xf7,0xcf,0xd0,0xe7, - 0x62,0x15,0xbb,0x16,0xee,0xee,0xa8,0x8a,0x7e,0x06,0x21,0xde,0x7d,0x1e,0x21,0x56, - 0x5b,0x00,0xd5,0xdb,0x22,0x5d,0xa7,0xc9,0xd4,0x79,0x57,0x63,0xd8,0xe9,0xab,0xb1, - 0xe1,0xce,0xe3,0x3e,0x89,0xd1,0x55,0x60,0x71,0x05,0xeb,0xa0,0xc5,0x2c,0xdd,0xb9, - 0x7b,0x43,0x13,0xa4,0xb4,0x09,0xcc,0x02,0xc3,0x6c,0xa2,0x5a,0xc1,0x36,0xd0,0xca, - 0x30,0x55,0x54,0x6e,0x13,0x66,0x11,0x1a,0x96,0xba,0x04,0x77,0x3c,0x46,0x05,0x91, - 0xe0,0xe1,0x58,0xf7,0x00,0xf4,0x38,0x04,0x7e,0x85,0xcf,0xcc,0x51,0xac,0x4b,0x04, - 0xe1,0xbc,0x10,0xba,0x25,0xe2,0xf2,0x81,0x1a,0x6b,0x2a,0x08,0xe2,0x74,0xec,0x82, - 0x4e,0xc1,0x1b,0x2e,0x7c,0x80,0x37,0xd1,0x97,0xaf,0x9e,0xea,0x22,0x10,0xf1,0x88, - 0xa2,0x6e,0x23,0xfd,0xb3,0xdb,0x33,0x02,0x5c,0xaf,0x8f,0xf4,0x31,0x00,0x47,0xd4, - 0x4e,0x23,0x3c,0x3d,0x31,0x31,0x0c,0x8f,0x7a,0x81,0xad,0x56,0x13,0x09,0x75,0x17, - 0xd5,0x90,0xfc,0x13,0x17,0x48,0x79,0xc1,0x34,0x54,0x3b,0xf5,0x41,0x23,0x2d,0x28, - 0xfa,0x35,0x6c,0x73,0x1d,0x63,0x8b,0x95,0xd4,0x70,0xd3,0xcc,0x53,0xae,0x54,0x84, - 0xba,0x71,0xbc,0x0e,0xbf,0x31,0x66,0x00,0x0f,0x91,0x9e,0x72,0x60,0x13,0x31,0x02, - 0xc2,0x4c,0x1c,0x4f,0x41,0x83,0x58,0x16,0x76,0x4b,0x05,0x90,0x7a,0x01,0x4b,0x59, - 0x64,0x82,0x4a,0x79,0x50,0x2b,0x61,0x1e,0xb2,0x5a,0x70,0x55,0x1e,0xe4,0x13,0x52, - 0x5c,0x60,0xf0,0xb3,0x3a,0x17,0xc0,0xd1,0x3c,0x3c,0x79,0xff,0x6e,0xb5,0xf0,0x9d, - 0x31,0xd3,0xb6,0x9a,0xc1,0xfa,0x48,0x5b,0xfd,0x6a,0x86,0xea,0xa3,0xa6,0xac,0xf8, - 0x5a,0x5d,0x45,0xed,0xbe,0x20,0xd8,0x60,0x3c,0xd8,0xea,0xec,0xef,0x1c,0xec,0xaa, - 0x96,0xbe,0x0f,0x16,0x5e,0x06,0x88,0x39,0x7b,0xb6,0x82,0x64,0x28,0x4b,0x38,0x75, - 0xcd,0x1b,0x9a,0x95,0xc3,0xc0,0x04,0x56,0xc0,0x90,0xc7,0x4b,0xad,0x8d,0x20,0xeb, - 0x2b,0xe6,0x08,0xcf,0x58,0xd6,0xef,0x2a,0x72,0x57,0x36,0xf2,0x2e,0x72,0xa8,0x2d, - 0x66,0xae,0x0c,0x5d,0x6d,0x04,0x24,0x66,0x12,0x05,0x01,0xf1,0x85,0xcf,0xe2,0xc0, - 0x48,0xdb,0xa7,0xc1,0x64,0xd5,0x19,0xc7,0xe1,0x7b,0xa0,0x57,0xd9,0x62,0x5c,0x3f, - 0x1b,0x65,0x81,0x1d,0x28,0x17,0x2e,0x23,0x0f,0x6a,0x74,0xc3,0x7b,0x73,0xfd,0x16, - 0xfd,0x3e,0x0a,0xa7,0x5f,0x51,0x75,0x14,0xd6,0x56,0xfd,0x37,0x89,0xb5,0xd5,0x9d, - 0x00,0xe8,0x4a,0xaa,0x84,0x4f,0x14,0x3b,0x35,0xd6,0x17,0x8d,0xb6,0x59,0x27,0xcd, - 0x87,0x4d,0x30,0x55,0x73,0xc8,0x92,0x96,0x44,0xcf,0xf2,0x14,0x29,0x82,0x2f,0x15, - 0x01,0xb9,0xe0,0xbb,0x4e,0x1c,0xfc,0x9f,0x96,0x5e,0xff,0xff,0x21,0x8e,0x6a,0x33, - 0xfc,0x3e,0x3a,0x73,0x85,0x4e,0xad,0x70,0x3a,0x8b,0x87,0xf1,0x06,0xec,0x29,0xda, - 0x81,0x2b,0x0b,0x97,0x68,0xcf,0x61,0x1e,0xf2,0x0e,0x45,0xea,0x85,0x38,0x0e,0xee, - 0xc5,0x91,0xed,0x2a,0x04,0x79,0x9b,0x78,0x7f,0x2c,0xbc,0x70,0x74,0x6f,0x1b,0x43, - 0x98,0x7b,0x11,0xfe,0xee,0xfc,0x2d,0xe1,0xca,0xc9,0x99,0x31,0x5f,0x80,0xa4,0x00, - 0xb2,0xd5,0x68,0xc6,0x2c,0x31,0x29,0xee,0xbc,0x3b,0x98,0x59,0x4d,0xca,0x72,0x8d, - 0xdb,0x04,0x96,0x81,0x71,0xe3,0xc2,0x1a,0x37,0x32,0xf7,0x9a,0x38,0x61,0xc5,0x1d, - 0x4e,0xf8,0xdc,0x02,0xe4,0x0d,0x63,0x01,0x98,0x17,0x18,0xe4,0x73,0xc1,0x58,0xc6, - 0x47,0x13,0x6b,0xb8,0x81,0xda,0xe9,0x52,0xbd,0x36,0x9a,0x1f,0x7e,0xfa,0x62,0x3d, - 0xbd,0xf4,0x92,0x29,0x14,0x87,0x42,0x72,0xf1,0xb5,0x9d,0x76,0xbb,0x23,0xd4,0x72, - 0x9d,0xbd,0xb6,0xd0,0xcb,0x75,0xf7,0xda,0xed,0x27,0x10,0xe5,0x7b,0x09,0x24,0xa3, - 0x79,0xfd,0xec,0x96,0x87,0xb7,0x5a,0xbb,0xb2,0xd9,0x97,0xa2,0xd1,0x42,0x9b,0x5f, - 0x07,0x86,0xf3,0x38,0xf1,0xdc,0x31,0x9d,0x2f,0x91,0x0e,0xaa,0xa2,0x23,0x55,0x3d, - 0x48,0xb1,0x50,0x44,0x34,0xf9,0x70,0xef,0xf5,0xb6,0x78,0x92,0x29,0xfb,0x95,0x94, - 0x97,0x95,0x94,0x83,0x4a,0xca,0xab,0x4a,0x4a,0xa7,0x5d,0x4d,0xea,0x54,0x93,0xba, - 0x79,0x92,0x54,0xce,0x3e,0xb1,0x38,0x69,0x8c,0xc0,0x73,0x7a,0xab,0x47,0x38,0x4a, - 0xfe,0xc6,0x11,0x96,0xbb,0xf5,0xf5,0x2a,0xe1,0xbf,0x51,0x23,0xfc,0x2c,0x62,0x21, - 0xd9,0xbb,0xea,0x3a,0xaf,0x43,0x20,0x6d,0xcf,0xec,0xaa,0x81,0x1c,0xfb,0x49,0xe6, - 0xcf,0xbd,0x12,0x2e,0xad,0x1d,0x88,0x3b,0xc9,0x11,0x5b,0xe2,0x75,0x7b,0xe5,0x39, - 0x8b,0x3b,0x69,0x8d,0x47,0x6b,0xd5,0xec,0x5a,0xbf,0x72,0xde,0xe6,0xec,0x37,0xe0, - 0x18,0x02,0xf7,0xde,0x40,0xc3,0xe3,0x67,0x75,0x2b,0xb9,0xa3,0x02,0x75,0x7d,0x13, - 0x0b,0x7d,0xed,0x92,0x2b,0xf4,0x63,0xaf,0xd3,0xd5,0xa7,0x9a,0x7b,0xf2,0x15,0x20, - 0xca,0x9e,0xec,0xcb,0xd3,0x33,0xaf,0x9f,0xd1,0x17,0x18,0x9e,0x03,0xc8,0xc3,0xe4, - 0x7d,0x78,0x78,0x72,0xfc,0x83,0xd1,0x24,0x95,0x7d,0x28,0x0f,0x8e,0x49,0x43,0x34, - 0xf7,0x33,0x0b,0x25,0xae,0xd7,0xfe,0xe1,0xc9,0xcc,0x0d,0xd1,0xcf,0x11,0x7a,0xef, - 0xdf,0xf8,0xd9,0x3d,0x8c,0x26,0x63,0x96,0x9f,0x0f,0xea,0x85,0x71,0x8f,0xbe,0xd9, - 0x64,0xd3,0xc0,0x2c,0x0e,0x90,0x0e,0x18,0x86,0xd1,0x5d,0x3e,0xc4,0x91,0x8b,0x5b, - 0xda,0x02,0x2a,0x58,0x1c,0xaa,0xed,0xe6,0x89,0x9e,0x77,0xf6,0xb5,0xae,0xc3,0x0c, - 0xc3,0x9e,0x85,0x87,0x0d,0xc6,0xd4,0x25,0x03,0x0f,0xec,0xed,0xf9,0x6f,0x9d,0xee, - 0xfe,0x1d,0xb0,0x28,0x23,0xcf,0x47,0xe5,0x01,0x69,0xf6,0xfe,0x52,0x47,0x69,0x9b, - 0x74,0x92,0x3b,0x6c,0xe4,0xab,0x7b,0xdc,0x6d,0xef,0xea,0xe0,0x7e,0xfb,0xe6,0x83, - 0x21,0xfb,0x2d,0x3a,0xfc,0xe6,0x0e,0xd8,0x1d,0xe4,0x79,0x27,0x09,0x0a,0x5f,0x5e, - 0x38,0x6e,0xcd,0xa3,0xf1,0x02,0x64,0xe1,0xf7,0x1f,0x8f,0xff,0x86,0x8e,0x4f,0xbc, - 0xf9,0x9f,0xed,0xfc,0x41,0xe7,0x55,0x57,0xeb,0xfc,0x0f,0xcc,0x81,0x33,0xdd,0x4a, - 0x49,0x5b,0x20,0xc6,0x70,0xe6,0x8d,0x17,0x23,0x4f,0xb2,0xe8,0xc8,0x04,0xfc,0x78, - 0x7a,0x0e,0xab,0x37,0x10,0xb9,0xff,0xd2,0x30,0xa8,0x06,0x6e,0x6e,0xdd,0x08,0x34, - 0x22,0xd0,0x7e,0xb5,0x2f,0x38,0x9c,0xbb,0x38,0x6d,0xb1,0xa1,0x4b,0x79,0x98,0x05, - 0x3c,0xaa,0x19,0xd2,0x0f,0x8b,0xec,0xbe,0x35,0xba,0x47,0xeb,0x3f,0x64,0x43,0x98, - 0xad,0x12,0x48,0xd5,0x27,0xee,0x04,0x39,0xda,0x94,0x02,0x02,0xfb,0xe1,0x22,0x5a, - 0xa4,0xf2,0xf3,0x9f,0x1f,0x2c,0x76,0x17,0x65,0x74,0x32,0x06,0x7d,0xc6,0x6c,0x91, - 0x20,0xa3,0xc6,0xc9,0xdb,0x50,0xba,0x72,0xdf,0x3f,0xfb,0x0d,0xe6,0x24,0xf0,0x6e, - 0xbc,0x60,0xc5,0x7e,0x48,0xad,0x53,0x06,0xb5,0x29,0x32,0x73,0x46,0x32,0x52,0xc7, - 0x68,0xa2,0x91,0x9c,0x97,0xdc,0x90,0x43,0x8b,0x55,0xde,0x09,0x65,0x56,0xc0,0x98, - 0xee,0xaa,0x6f,0x3b,0xe6,0xe1,0xce,0xaa,0x6f,0x40,0xba,0x77,0x57,0x7d,0xdb,0x33, - 0x0f,0xf7,0x8c,0xe6,0xd0,0x0d,0x68,0xb7,0x5a,0xd9,0x34,0x50,0x87,0xfd,0x55,0xdf, - 0x5e,0x9a,0xd5,0xcd,0x5b,0x7e,0x83,0x15,0x7a,0xb0,0xea,0xdb,0x2b,0xb3,0xca,0xb2, - 0x28,0xa8,0xc0,0x86,0x50,0xe5,0x5e,0xe4,0x57,0x90,0x8a,0x16,0x6e,0x80,0xa7,0x5d, - 0xf8,0x6b,0x64,0xa4,0xff,0x4c,0xab,0xec,0x42,0x51,0x5a,0x60,0x77,0x91,0x2a,0xf5, - 0x89,0xd3,0x55,0xd2,0xbd,0x42,0x00,0xe4,0xeb,0xe6,0x80,0x3a,0xad,0x89,0xef,0x05, - 0xe3,0xdc,0x84,0x43,0x24,0xaf,0x9b,0x75,0x59,0xb4,0x32,0xf1,0x30,0xc2,0xe3,0x05, - 0x4a,0xd8,0x49,0x34,0x37,0xd2,0x0a,0xe7,0xb8,0x02,0x2e,0x30,0x11,0x9d,0x7d,0x23, - 0xbd,0x9f,0x0f,0xa3,0x20,0x5d,0x89,0x0c,0x80,0x29,0x3b,0xdd,0x6a,0xae,0xa7,0xd9, - 0x28,0xc0,0x7b,0x5d,0x8c,0xc1,0xb1,0x4b,0x60,0xaf,0x34,0x0a,0xa0,0xa5,0x69,0xdc, - 0xfa,0xe1,0x18,0x0a,0x37,0x37,0xe6,0xfe,0x28,0x89,0xfa,0xe9,0x73,0x58,0x71,0x02, - 0x50,0x22,0x99,0xaf,0x4e,0xbb,0xdd,0x56,0xec,0x17,0xff,0x27,0x77,0xe9,0xce,0x13, - 0x52,0xc0,0x39,0x9a,0xee,0xfd,0xf9,0x2e,0x90,0xe5,0xdf,0x57,0xf5,0xa2,0xda,0x99, - 0x9c,0xad,0x22,0xa8,0xb1,0xd6,0x65,0x75,0xf6,0xe2,0x76,0xb0,0xa3,0x6f,0x06,0x67, - 0x14,0x1c,0x45,0x10,0xcb,0xb7,0x51,0x72,0x8b,0x2a,0x07,0x92,0xf3,0x80,0x7f,0x98, - 0x4c,0xfc,0x91,0x63,0x7c,0x02,0x22,0x39,0x60,0x7b,0x80,0xb0,0x45,0x07,0x6c,0xcd, - 0x14,0x04,0xb9,0x40,0x1e,0xdd,0xa5,0x6c,0xa3,0x2b,0x4e,0xea,0x52,0xb4,0x42,0xfd, - 0x2b,0xbb,0x1d,0x75,0xe8,0xb9,0x54,0x53,0x31,0x4f,0x4a,0x6b,0x8a,0x4a,0x53,0x6d, - 0xb0,0xfb,0xbb,0xab,0xd5,0x42,0x64,0x26,0xe1,0x8e,0x31,0x24,0x95,0xd1,0x9c,0x6b, - 0xa7,0x9d,0xeb,0xd9,0x5e,0x2a,0xe0,0x90,0x3f,0x01,0x2c,0x81,0x32,0x43,0xb7,0x5b, - 0xcb,0x02,0x1f,0xb6,0x01,0x84,0xb0,0xdb,0x3c,0xe3,0xd8,0xe7,0x6d,0x10,0x45,0x63, - 0xd5,0xad,0x59,0x92,0x3e,0xaf,0x5b,0x13,0x2c,0xe6,0xac,0xef,0x5c,0x67,0xff,0x60, - 0x5d,0xe7,0x6c,0xc3,0x0b,0x52,0xcf,0xd8,0xd9,0x08,0x49,0xb2,0x87,0xdc,0xb5,0x06, - 0x4e,0x2b,0x44,0x11,0x4d,0x17,0x41,0x7d,0xd1,0xf5,0x55,0x34,0x26,0x24,0x38,0xac, - 0x47,0x87,0xb7,0x38,0x5d,0xa5,0x94,0xf8,0x29,0x8a,0x01,0xd9,0x80,0x71,0xe5,0x13, - 0x27,0xaa,0x4b,0x22,0xa3,0xa6,0x58,0x98,0x30,0xae,0xa6,0x0e,0xec,0xe9,0x6c,0x13, - 0x03,0xd4,0x88,0xf7,0x71,0xe0,0x91,0x20,0x8f,0x9f,0xde,0x1b,0x21,0x7a,0x18,0x0c, - 0xa3,0x45,0x92,0xf6,0x8d,0x2c,0x8a,0x0c,0xd2,0x2e,0x92,0x86,0x22,0x76,0x13,0x68, - 0x20,0x9a,0xe4,0x86,0x5e,0x68,0xad,0x08,0xef,0x64,0xe7,0xe9,0x3c,0x43,0xdd,0xd8, - 0x3d,0x58,0x89,0x59,0x1f,0xdc,0x3b,0xd1,0xef,0x19,0x0d,0xf4,0xd9,0xd3,0x07,0xb3, - 0x54,0x9a,0xb2,0x0a,0xfe,0x8a,0x19,0x13,0x73,0xb4,0xbf,0xeb,0x18,0xc2,0x6a,0xd0, - 0x80,0xe7,0x67,0xa0,0x17,0xf6,0x4d,0x20,0xd7,0xd7,0x77,0x4e,0xe0,0xd7,0x9f,0xef, - 0xe3,0x41,0xbd,0xcd,0xdc,0x4a,0x3d,0x37,0x02,0x59,0xeb,0xf8,0x22,0x4c,0x47,0x51, - 0x8c,0x27,0xfa,0x7f,0x12,0xba,0x8e,0xac,0xa1,0x3a,0x84,0xaf,0x31,0xca,0x3a,0x8e, - 0xe3,0x00,0x0d,0x15,0x60,0x47,0x65,0x83,0x84,0x94,0x6d,0x07,0xc2,0x48,0x1a,0x02, - 0x50,0x2b,0x8e,0xa1,0xc1,0x60,0x9d,0xe4,0xfb,0x24,0x19,0xeb,0xee,0xed,0x6b,0x74, - 0x0b,0x56,0x88,0x26,0xbc,0xd5,0xb1,0x03,0xa4,0x6d,0x8e,0x62,0x87,0xb3,0x55,0xd8, - 0x01,0x3a,0x0e,0xfe,0x84,0xe4,0x68,0x05,0xcf,0xe3,0x63,0x3c,0x10,0x64,0x7a,0xf8, - 0x61,0x65,0x3e,0x58,0x89,0xa8,0x99,0x81,0x8c,0xe2,0x69,0x55,0xce,0x34,0x4b,0x7c, - 0xec,0xc8,0x39,0xfd,0xd6,0x71,0x4f,0x15,0x20,0xff,0x90,0x60,0xa0,0x62,0x9e,0x69, - 0x09,0x65,0xb6,0x50,0x0b,0x90,0x7f,0xb9,0x37,0x80,0xc0,0x24,0xf7,0x05,0xbf,0x89, - 0x99,0x8b,0x2a,0x6b,0x6e,0x03,0x68,0xc2,0xc0,0x98,0x78,0x48,0x1b,0x78,0x4f,0xc1, - 0xe9,0x0a,0xa8,0x93,0x63,0x29,0x23,0x8f,0xa1,0x89,0x18,0xe8,0x92,0xf3,0x14,0xa1, - 0xe3,0x13,0x21,0x3a,0xa3,0x7a,0x9e,0xf9,0xcd,0x3b,0xb2,0x66,0xc9,0xee,0xff,0xbc, - 0xc9,0xcd,0xff,0xb8,0xc5,0x8d,0xb4,0xb1,0xe9,0x63,0x1c,0x98,0x92,0x8d,0x8d,0x63, - 0x7c,0x4f,0x27,0x02,0x83,0xbf,0xc7,0x54,0xe6,0x7f,0xdc,0x52,0xe6,0x4f,0x59,0xb5, - 0xfc,0x77,0x1a,0xb5,0xd4,0xcd,0xe0,0x6a,0x83,0x15,0xdc,0xc4,0xa8,0xb5,0xcd,0xb4, - 0x64,0xb7,0x02,0x68,0x25,0x0e,0xe3,0xac,0x3f,0x69,0x73,0xf2,0x4c,0x93,0x93,0xe7, - 0x69,0x2a,0x4f,0x19,0xbb,0x48,0x3e,0xaf,0xdf,0xfe,0x2f,0x34,0xc3,0x12,0x60,0x35, - 0x3d,0x44,0x54,0xe0,0x53,0x17,0x71,0x10,0xb9,0x63,0x32,0x37,0x45,0xaa,0x4b,0xe6, - 0xd8,0x2d,0xb4,0xf0,0x9a,0x91,0x1c,0x83,0x62,0x8d,0x8b,0x8e,0x2f,0xd7,0x88,0xd7, - 0x78,0xe8,0xf5,0x6f,0xb6,0x79,0x20,0xd3,0x05,0xcd,0x90,0xb2,0x8e,0x37,0xce,0xb9, - 0x61,0xb2,0x32,0x67,0x4b,0x33,0xc1,0x12,0x9f,0x7a,0x89,0x0f,0xac,0xcb,0x08,0x8d, - 0x9f,0x83,0x6c,0xb6,0x4d,0xc7,0xcb,0x86,0xa8,0x53,0xd8,0x83,0x93,0x91,0xd4,0x5f, - 0x62,0x7a,0x09,0x8e,0x5c,0xdb,0xf3,0xb4,0x3b,0x79,0x97,0x05,0x44,0x25,0x85,0x14, - 0xdd,0xfe,0xe0,0x92,0x61,0x69,0x0a,0xbb,0xd2,0x68,0xc6,0x16,0xf9,0xc0,0xb0,0x0b, - 0xe3,0x39,0xc9,0x4c,0xc1,0xec,0x46,0xb7,0x7f,0xbd,0xdf,0xa2,0xe5,0xaf,0xed,0xf8, - 0xf1,0x78,0x6c,0x24,0xee,0xad,0xc1,0x11,0xa4,0x44,0xbf,0x8f,0x03,0x32,0xa8,0x42, - 0x0b,0x59,0x34,0xae,0x5d,0x40,0xa7,0x11,0xdb,0x29,0x8f,0x84,0x3a,0x16,0xfa,0x9b, - 0x40,0x0e,0x55,0x7d,0x6d,0xb7,0x85,0x08,0x3a,0x2e,0x01,0x1c,0xe4,0x28,0xb4,0xfa, - 0x92,0xfb,0x14,0x9a,0xca,0x8f,0xf3,0xa3,0x54,0xd7,0x4f,0xfe,0x86,0xce,0xde,0xfd, - 0x59,0xdc,0x10,0x6c,0x70,0x52,0x41,0x6a,0xf9,0x01,0x98,0x62,0xb4,0xda,0x41,0x39, - 0x8e,0x18,0x97,0xd4,0x68,0x9e,0x9e,0x9f,0x1d,0x7f,0x30,0x86,0x11,0xf2,0xd8,0xb4, - 0x14,0xad,0xbf,0x3e,0x02,0xd5,0x8f,0xbf,0x26,0xde,0xad,0x3c,0x8c,0x11,0x1a,0xef, - 0x4c,0x9f,0x9d,0x15,0xdc,0x11,0xf5,0x27,0xbb,0xfb,0x6a,0xce,0x08,0x2d,0x59,0x8e, - 0x01,0x2b,0x2f,0x7e,0x5b,0x95,0x43,0xb0,0xc8,0x48,0x4a,0x05,0xa3,0x2d,0x95,0xd7, - 0xcf,0xe0,0x79,0x4a,0x68,0x94,0x8b,0x3b,0xb8,0x26,0x9e,0x65,0x82,0x79,0xce,0x34, - 0x49,0x4a,0x80,0x5f,0x21,0xd8,0xf2,0x4e,0x5b,0x94,0x1c,0x3b,0x92,0x3f,0x7e,0xf2, - 0x98,0xf2,0x2b,0xe7,0xea,0xa3,0x44,0x05,0xad,0xa7,0x33,0x14,0xd4,0xbe,0xa2,0xaf, - 0x0a,0x9d,0x2a,0xbd,0xee,0x4a,0xa5,0xca,0xce,0xfe,0x4a,0x5e,0x28,0x9a,0xe0,0x61, - 0x09,0x72,0xf0,0x62,0x95,0x90,0xd9,0x49,0x71,0x41,0x34,0x3b,0xdd,0x16,0xd4,0x61, - 0x1b,0xc2,0x7d,0xdf,0xe8,0xee,0x5a,0xce,0xd7,0x08,0xc5,0xeb,0x0c,0x20,0xdd,0x38, - 0x7e,0xda,0x02,0x52,0xab,0xe5,0x02,0xcf,0xe7,0x58,0x80,0x3e,0xff,0xf8,0xe1,0x74, - 0xad,0xed,0xd1,0xc5,0xa9,0xf0,0x50,0x7c,0x2e,0xaf,0x12,0x66,0xf1,0x0a,0xd6,0xa4, - 0x60,0x0c,0x14,0x47,0x51,0x80,0x79,0x81,0xfb,0x9c,0xd6,0x42,0x96,0x7d,0x99,0x81, - 0xf6,0xa0,0xe7,0xbc,0xdc,0xad,0x47,0x01,0x90,0xc3,0xf5,0x86,0x3c,0x2b,0xd7,0x34, - 0x0c,0xfa,0x0b,0x3a,0xcc,0x36,0x4f,0x3f,0x9d,0xbf,0xfb,0xed,0x39,0xdc,0x71,0x26, - 0x8a,0x3c,0x67,0x3c,0x1f,0xce,0x2f,0x5e,0x7e,0xf8,0xe1,0xc2,0xfe,0xb0,0xe3,0x74, - 0x9d,0xb6,0xfd,0xa1,0xd3,0x71,0x3a,0xce,0x2a,0x33,0x80,0x1a,0x09,0xb1,0xc3,0xdc, - 0x23,0xf7,0xe9,0x97,0x8b,0x13,0x54,0xa3,0x68,0xfe,0x4a,0xeb,0x0f,0x07,0x45,0x3f, - 0x1d,0x2e,0x23,0x4f,0x85,0x15,0xf2,0x76,0x76,0x9f,0xd0,0xe9,0xe5,0x84,0x1e,0xf1, - 0xc1,0x00,0x5e,0x3d,0xcc,0xd4,0x76,0x04,0xdc,0x04,0x10,0x12,0x34,0x95,0xf0,0x13, - 0x3c,0x19,0xfe,0x0b,0xb4,0x3b,0x0d,0xe7,0xf1,0x33,0x28,0xb6,0x46,0x83,0xb0,0x3b, - 0x68,0x50,0xb4,0x08,0x49,0x04,0x7a,0x72,0xca,0xb0,0x05,0x47,0x15,0x58,0x21,0xd3, - 0x3c,0x25,0x9d,0x91,0x75,0xe0,0xf3,0xa4,0x33,0x72,0xb0,0x95,0xae,0xa9,0x51,0xb8, - 0x8a,0x17,0xc5,0x23,0xd3,0x29,0xf2,0x97,0x94,0x3f,0x61,0x98,0xb2,0xed,0x6c,0x5e, - 0x58,0x19,0xc2,0x10,0xb1,0x26,0x3b,0xd8,0x5b,0xd4,0x8e,0xa2,0x6c,0xc9,0xbe,0x3e, - 0xb9,0x77,0x0f,0x2c,0x79,0x58,0x09,0xa9,0x74,0x30,0xd4,0x2c,0x6f,0x1d,0xe3,0xad, - 0x8f,0x9e,0x86,0x19,0xdb,0xe3,0xbe,0x3b,0x65,0x9e,0x96,0xcc,0x6e,0x92,0x68,0x81, - 0x8b,0x2a,0x4a,0x84,0x39,0x2f,0xf9,0xf3,0x8a,0x48,0x07,0xff,0x6f,0x38,0xce,0x12, - 0x29,0xfb,0x7f,0xd7,0x73,0x56,0x76,0xef,0x6f,0x71,0x9d,0xfd,0x2b,0x9e,0xb3,0x4f, - 0xea,0xbb,0xda,0xdd,0xdc,0xf4,0xe1,0x54,0x9e,0x66,0x7a,0x2b,0xb9,0x18,0x6e,0x4c, - 0x1c,0xac,0x56,0x4f,0x7d,0xe6,0x78,0x58,0x4c,0x2a,0x9c,0xc5,0x7c,0x15,0xbb,0x42, - 0x11,0x4e,0x40,0xf0,0x41,0x12,0x0b,0xe2,0x00,0xfa,0x86,0xa0,0xf1,0x76,0x38,0xba, - 0xb7,0x56,0x9f,0x88,0xdd,0xe5,0xce,0x5f,0xcd,0xa1,0x8b,0xf1,0x97,0xf5,0xdc,0x4f, - 0x9f,0xfc,0x68,0x4b,0xf1,0x83,0x8b,0x9b,0x77,0x88,0x27,0x82,0x2b,0xcd,0x57,0x56, - 0x20,0xc7,0x2a,0x5b,0xfe,0x71,0x74,0x46,0x66,0x70,0x4d,0x32,0xe7,0x27,0x83,0xb8, - 0x90,0x94,0x0d,0xab,0x2d,0xc3,0x6b,0x2b,0x14,0xb1,0x24,0x60,0xf5,0xb5,0x8a,0x6e, - 0xbc,0xe3,0xe8,0x3d,0x25,0x93,0x79,0x38,0x3a,0xf8,0xc1,0xf3,0x4a,0x8f,0x81,0x0a, - 0x9d,0x62,0x0b,0xe5,0xe7,0x11,0x2a,0x71,0x56,0xcf,0x24,0x9b,0x43,0x2b,0x40,0xe1, - 0x16,0x10,0x19,0xad,0xb7,0x91,0x9b,0x89,0x78,0xb1,0xe5,0x18,0x7b,0x25,0x05,0x08, - 0x45,0x89,0x2a,0xc5,0xcb,0x6e,0x9b,0x87,0x2b,0xad,0x04,0x29,0xc4,0xbe,0x30,0xf3, - 0xa6,0xc7,0xe7,0x4d,0xe9,0xdb,0xc4,0xc3,0x20,0x04,0x6e,0x6c,0x34,0x7f,0xfe,0xde, - 0xa2,0x6a,0x5f,0x73,0x90,0x78,0x1e,0x42,0xec,0x26,0xd7,0x18,0x1b,0x3c,0xce,0x43, - 0x00,0x91,0x7a,0x73,0x9b,0x33,0x49,0xf3,0x6a,0x3f,0xf5,0x48,0xfb,0xa7,0x8c,0xab, - 0x6a,0xeb,0x41,0x45,0xbf,0xb7,0xb2,0xa2,0x75,0x67,0x15,0xc8,0xf7,0xf0,0x64,0xe8, - 0x47,0x15,0x7a,0x74,0x87,0x12,0xc3,0x86,0x79,0x05,0xc7,0xf6,0x6c,0x0f,0x52,0x5c, - 0x5a,0xb4,0x5c,0x8d,0x7b,0x2f,0x73,0x9e,0x42,0x0d,0x34,0x4b,0x7f,0x0a,0x31,0x64, - 0xd3,0xfa,0x8d,0x19,0x65,0xeb,0x7c,0x2f,0x99,0x8b,0x69,0xf3,0x2a,0xb1,0x5f,0x44, - 0x1c,0x52,0xb3,0xc4,0x08,0xa4,0x71,0x35,0xc2,0x4f,0x91,0xfa,0xea,0xfd,0x52,0x95, - 0xb7,0xc8,0xe7,0xf7,0x79,0xa4,0xb9,0xa1,0x16,0x10,0xfa,0xa0,0xfc,0x4a,0x5e,0x16, - 0xb8,0x84,0x36,0x02,0x37,0x49,0xfa,0xec,0x3d,0x5c,0x5d,0xa4,0x7f,0x65,0x0b,0x80, - 0x9f,0x9f,0xbc,0x20,0xc6,0x46,0x66,0xf0,0xfb,0xb7,0x57,0x7e,0x82,0x8c,0x2d,0xd6, - 0x4e,0x1c,0xee,0x5a,0xc7,0x10,0x19,0x73,0x54,0x03,0x1d,0xbe,0x1d,0xae,0xca,0xca, - 0x11,0x48,0xe1,0x7b,0xf9,0x43,0xba,0x98,0x1a,0xe5,0x39,0x58,0x4c,0xd7,0x58,0xd6, - 0xa9,0xc8,0x90,0xe5,0x29,0x17,0x21,0x1b,0x39,0x58,0x92,0x9a,0xfb,0xea,0xa6,0xaf, - 0xda,0x51,0xea,0xe6,0xc2,0xae,0xb6,0xca,0x23,0xaf,0xc4,0x05,0x34,0xd2,0xd8,0x0b, - 0x02,0xe2,0x2e,0x61,0xdd,0xb0,0xbb,0x0a,0xf9,0xb1,0x5c,0x7b,0xf7,0x28,0x3b,0x00, - 0xe7,0x11,0x95,0xb8,0x73,0xec,0x84,0xe1,0x4a,0xd3,0xf4,0xea,0x4e,0x20,0xc2,0x10, - 0xfe,0x19,0x36,0xa1,0xa1,0x4f,0xe3,0x39,0x85,0x1c,0xc2,0x79,0x4c,0x16,0xe1,0x5a, - 0xd7,0x2f,0xb9,0x10,0x39,0xca,0x9a,0x04,0xe8,0xe1,0xeb,0xeb,0xe1,0xf8,0xf0,0xc2, - 0x1d,0xbe,0xde,0xc6,0x07,0xe5,0xf6,0x20,0x09,0x6b,0x9e,0x67,0x63,0x81,0xa8,0xce, - 0xd9,0x38,0x61,0x9c,0x27,0xc0,0xb4,0xa6,0xe8,0x4c,0x5e,0x60,0xd4,0x39,0xdb,0x9b, - 0x74,0x24,0xf2,0x8c,0xfd,0x74,0xee,0xa7,0x69,0xa1,0x6a,0x8e,0x8f,0x35,0x87,0x91, - 0xf9,0x31,0x3a,0x5f,0xc1,0x5c,0x93,0x8e,0x12,0xdd,0xaf,0x5c,0x58,0x57,0x64,0x2e, - 0xed,0xa9,0x6a,0x6b,0x89,0x90,0xe6,0x09,0xb4,0x2d,0x42,0x64,0xe9,0xd2,0x06,0x5f, - 0xf4,0xc3,0xb8,0x20,0x5f,0x70,0x3e,0x54,0x42,0x8b,0x82,0x04,0x0d,0x0f,0x9f,0x24, - 0x2a,0xc5,0x4d,0xd7,0x48,0xe7,0xda,0x92,0xc2,0x59,0x4a,0xb2,0xe3,0x20,0xe0,0xad, - 0x1b,0x5f,0xd6,0xef,0xda,0xf3,0xbc,0x47,0xa5,0x3d,0x1a,0x78,0xbe,0x82,0x07,0x17, - 0x07,0x89,0x48,0xd7,0xae,0xd1,0xfc,0x32,0x88,0x7c,0x81,0xd1,0xad,0x10,0x94,0x58, - 0x36,0x3e,0xe3,0xfb,0x2d,0xd8,0xa5,0x76,0x78,0xaf,0x42,0x9a,0x30,0x00,0x4a,0x0c, - 0xee,0x33,0x80,0xf0,0x57,0x48,0x11,0x09,0x26,0xc4,0xeb,0x66,0xc9,0xc2,0x23,0xd8, - 0xa5,0x45,0x3e,0xf7,0xbf,0xa7,0x5d,0x0a,0x6d,0x45,0xed,0x42,0x9b,0x27,0xf8,0xa2, - 0x9a,0x2c,0x6f,0x6e,0xea,0x76,0x0d,0x41,0xd2,0x56,0x7a,0xc0,0xa9,0x7d,0x8d,0x84, - 0x90,0x12,0x3a,0x91,0xf5,0xa3,0x2e,0x81,0xae,0x5e,0xa3,0x74,0x07,0x84,0x20,0x5e, - 0xf4,0x58,0x47,0x1b,0xc5,0xd5,0x0b,0x9c,0xcd,0xbb,0xa3,0x18,0xd9,0x72,0x9e,0x2b, - 0xd2,0xfe,0x2e,0x9e,0x15,0x95,0x2f,0x83,0x11,0xc1,0xf8,0x8a,0xda,0x2f,0x2d,0x5e, - 0x44,0xf5,0xfa,0x07,0x0a,0x3e,0x85,0xc6,0x86,0x5e,0x35,0x62,0x17,0x45,0xef,0x8b, - 0x82,0x1a,0xf6,0x62,0xaf,0x12,0x3f,0xfe,0x55,0xbf,0x10,0x54,0xb4,0x5b,0x8e,0x22, - 0x39,0x99,0x5a,0xd8,0xb9,0xc0,0x07,0xca,0x14,0x93,0x77,0xb7,0x54,0xc9,0x34,0x23, - 0x52,0xd1,0x9c,0x20,0xd3,0x1d,0x60,0x8a,0x25,0x83,0x74,0x00,0x19,0xc7,0x03,0x20, - 0x3a,0x52,0xa2,0xc8,0x54,0x68,0xe4,0xe4,0xbc,0x1e,0x26,0x72,0xeb,0xa8,0x75,0x30, - 0xac,0xe1,0x7a,0xde,0x4d,0x0c,0x37,0xbd,0xf6,0xc6,0x36,0x2c,0x3c,0x19,0x40,0x04, - 0x3d,0xc9,0x7e,0x15,0x71,0xa1,0xde,0x21,0x24,0x42,0x8f,0xf4,0x15,0xc6,0x36,0x7e, - 0x3d,0xcf,0xdc,0x7b,0x29,0x56,0xa3,0xc2,0x82,0xdc,0x44,0xc5,0x4c,0xc3,0x18,0x68, - 0x20,0x14,0xe6,0xec,0xdc,0x9d,0xb8,0x89,0x8f,0xe2,0xf0,0xc9,0x2c,0x89,0x28,0x28, - 0x1e,0xf7,0x96,0xed,0x56,0x9d,0x3c,0xfb,0x8f,0x11,0x52,0x41,0x20,0x52,0xd5,0x5e, - 0xbf,0x94,0x61,0xc1,0x68,0xd2,0x17,0x09,0xac,0xee,0x59,0x96,0xc5,0xbd,0xed,0xed, - 0xce,0xab,0xae,0xd3,0xd9,0x3f,0x70,0x76,0x9d,0x0e,0xd1,0x33,0xae,0x6d,0x3b,0x0a, - 0xea,0xe2,0xc0,0x55,0x95,0x9e,0x78,0xb3,0xa0,0x59,0x1a,0x8c,0x3c,0xb9,0x80,0x51, - 0x2a,0x4f,0xba,0x73,0xc1,0xed,0x1c,0x16,0x02,0x8e,0x39,0xc6,0x3f,0xf5,0x40,0x6d, - 0xec,0xb9,0xe5,0xa7,0x18,0x90,0x05,0x4f,0xbb,0x7d,0xe9,0x39,0x93,0xeb,0x1c,0x3c, - 0x11,0x27,0x51,0x69,0x27,0xc4,0x4c,0x0a,0x94,0xb2,0x8d,0x5b,0xae,0x03,0x3d,0xd3, - 0x93,0x1b,0x5f,0x04,0xe8,0x32,0xd2,0x11,0x30,0xe9,0x18,0xc5,0x70,0x74,0x9d,0x9f, - 0x7f,0x3f,0xdb,0x33,0xb5,0xbd,0xd2,0x33,0x75,0x1c,0x8d,0x16,0x14,0xd0,0x6b,0xea, - 0x65,0x6f,0x02,0x0f,0x1f,0xbf,0xbf,0x7f,0x37,0x6e,0x6e,0x8a,0xc5,0xb5,0x69,0x39, - 0x04,0xc0,0xf7,0x40,0x09,0x1c,0x74,0x40,0x03,0x12,0xbd,0x89,0xec,0xe0,0xe6,0x33, - 0x5d,0x59,0x61,0x4e,0x87,0xe4,0xe6,0xab,0x5c,0x58,0x57,0x11,0x80,0xc2,0xda,0x66, - 0xc7,0xa8,0x7c,0x75,0x57,0xb8,0x5f,0x3f,0xf7,0x0e,0xe6,0xd5,0xbe,0xb3,0x9b,0x5f, - 0xb7,0xb2,0xb3,0xcb,0x87,0xc4,0x82,0x88,0x97,0xd7,0x3b,0xb9,0xea,0x1a,0x74,0x1f, - 0x50,0xa1,0x35,0xe1,0xec,0xcd,0x32,0x68,0x21,0xfa,0x26,0xad,0xf3,0x58,0xcf,0x3b, - 0x4f,0xa7,0xaa,0x03,0x35,0x61,0x68,0x0a,0x34,0xc8,0x14,0x43,0x8f,0xab,0x3c,0xb9, - 0xa8,0x0d,0x78,0x93,0x95,0xb8,0xf9,0xb1,0xea,0xef,0xdd,0xc3,0x15,0x0e,0xf3,0x59, - 0xa8,0x01,0x79,0xc6,0x6b,0x33,0x9f,0xe3,0xca,0x84,0x74,0xdb,0xd5,0x7b,0x9a,0xb0, - 0x6b,0xae,0xea,0x5e,0x7d,0x17,0xb4,0x30,0xc3,0xdd,0xfd,0x9a,0x2a,0xf4,0x6e,0x8c, - 0xa2,0x05,0xdb,0x36,0x56,0xa7,0x1a,0x50,0xd8,0x8f,0xb3,0xc3,0x86,0x89,0x91,0xee, - 0x84,0x7d,0x49,0xbf,0x01,0x50,0x33,0xce,0xdf,0x7c,0xbc,0x78,0xf7,0xf1,0xcd,0xfb, - 0x81,0xf9,0x9d,0xf8,0x4f,0x7c,0x48,0xb3,0xc1,0x12,0x6d,0x56,0x7a,0xa6,0x69,0x93, - 0x2f,0xe4,0xb8,0x47,0xd8,0x66,0xcf,0xdc,0xf4,0x03,0x88,0x83,0xf9,0xdb,0x49,0xe0, - 0x8b,0x17,0xa9,0xe2,0x39,0xe7,0xc0,0x0e,0xaa,0x48,0xe8,0x79,0xe3,0x54,0x2a,0x87, - 0x44,0x1a,0xf0,0xbc,0x69,0xaf,0x6d,0x8f,0x26,0xd3,0x5e,0xb8,0x08,0x02,0x1b,0x6d, - 0x34,0x7a,0xcb,0x47,0x9b,0xae,0x76,0xc6,0x07,0x0e,0x67,0x95,0xf6,0x2e,0xaf,0xec, - 0x90,0x24,0x49,0xc8,0x4d,0x22,0x28,0xea,0xb9,0x13,0x78,0x41,0x16,0xb0,0xb7,0x44, - 0xe1,0x98,0xf2,0xa0,0x70,0x0b,0x0f,0x8f,0x36,0x6e,0x9f,0x17,0x00,0x46,0x0f,0xef, - 0x7b,0xe5,0x37,0x2e,0xf1,0xd8,0x6f,0x4c,0x16,0x21,0x6b,0x22,0xbf,0x6d,0xa6,0xd6, - 0x52,0xac,0x22,0xb5,0x10,0x81,0xf9,0x4b,0xee,0xcf,0x49,0x23,0x13,0x25,0x90,0xe1, - 0x51,0xcb,0xaf,0x17,0x38,0x4e,0x12,0xf7,0x1e,0x36,0xfb,0x28,0x8b,0x90,0x25,0x70, - 0xd2,0x00,0x89,0xe9,0xc8,0x05,0x66,0xac,0xbe,0x2e,0x64,0xd3,0x52,0x4b,0xaf,0x8f, - 0xf6,0xd9,0xe6,0xdc,0x5a,0x22,0xac,0xb3,0xc1,0xb7,0x4d,0xf3,0x05,0x6f,0xbd,0x56, - 0x3f,0x73,0x90,0xa2,0x9c,0xf0,0xdd,0x0f,0x83,0x39,0xbc,0xe7,0x64,0x00,0x90,0xb0, - 0x49,0x22,0x21,0xe4,0x23,0x41,0x0a,0x87,0x86,0xea,0x95,0xcc,0xf9,0x8c,0x01,0xb2, - 0xe1,0xef,0x00,0xa0,0x26,0x53,0x65,0x73,0x4d,0x6b,0x99,0x55,0x89,0x89,0xa8,0xe8, - 0xd1,0xee,0xee,0xb7,0xdb,0x7a,0xe7,0x80,0x23,0xd2,0x46,0x8b,0x36,0x42,0xe1,0x14, - 0x12,0xf0,0x92,0x09,0x94,0x39,0x9a,0xdb,0x97,0x1b,0xaf,0x0f,0xcd,0xab,0xed,0xa9, - 0xad,0x1a,0x18,0xc9,0xec,0x4b,0x73,0xc3,0xec,0x99,0x74,0xf6,0x62,0xda,0xe6,0x6b, - 0x7c,0x0e,0x32,0x7c,0x3c,0xc4,0x47,0x74,0x83,0xb6,0x37,0xcd,0x4d,0x78,0xfc,0x63, - 0x11,0xc1,0xcb,0xe3,0xe5,0xe8,0xea,0x51,0x6f,0x1b,0xfa,0x94,0x64,0xff,0xf0,0x40, - 0x54,0x5c,0x12,0x1e,0x4e,0x6e,0x07,0xd0,0xe3,0xc9,0xed,0xc3,0x03,0x4c,0xe6,0x7c, - 0xb0,0xfd,0xaf,0xe6,0xcd,0xd1,0xef,0xe3,0xad,0xdf,0x1d,0xf9,0xa7,0x79,0xd4,0xa3, - 0x5f,0xeb,0xc8,0xda,0x76,0xbc,0x3b,0x6f,0xd4,0x9c,0xdc,0x5a,0x02,0x87,0x07,0xf3, - 0xa3,0xf9,0x65,0xe7,0xaa,0xd7,0xa4,0xf2,0x8b,0xf0,0x3a,0xc4,0x98,0x75,0xa8,0xaf, - 0x80,0xa6,0x00,0x84,0x0d,0x7f,0xd2,0xdc,0x6e,0xc1,0x66,0xd8,0x6c,0x3d,0x7c,0x0b, - 0xc5,0x31,0x12,0x04,0x16,0xb7,0xd2,0xad,0x81,0x89,0xe9,0x66,0xdf,0xd0,0xfe,0xdb, - 0xde,0x36,0x3e,0x5d,0x1c,0x7f,0x3e,0xf9,0xe9,0xf8,0x23,0x2c,0x99,0xcf,0x17,0xc7, - 0x3f,0x0e,0x86,0x5e,0xe6,0x62,0xc6,0x06,0xd9,0x83,0x52,0x75,0x98,0x54,0x5b,0x1f, - 0x7e,0x10,0x15,0x42,0x4d,0xae,0x41,0x65,0xc9,0x74,0x63,0xc4,0x0e,0x47,0x36,0x46, - 0x3e,0x45,0x56,0xbe,0x21,0x40,0x0f,0x23,0x1f,0x2e,0xfc,0x60,0x7c,0x94,0x6e,0x99, - 0x46,0xd3,0xdc,0x92,0xef,0x5b,0xa6,0x65,0xf6,0xd2,0x7e,0x43,0x83,0x1b,0x88,0x90, - 0x4d,0x0c,0x3e,0x63,0x47,0x71,0x06,0x73,0xd7,0xc0,0x9f,0x01,0xfe,0x79,0x78,0x58, - 0x3e,0xd2,0x40,0xbf,0xc1,0x37,0xc0,0x52,0x90,0x2b,0xad,0xfc,0x11,0xb7,0xe7,0x16, - 0xca,0x52,0x1e,0x74,0x0d,0xba,0x85,0xb7,0xdd,0xd3,0x87,0x14,0x05,0x4c,0x20,0x45, - 0x3f,0x5d,0x5c,0x9c,0x1a,0xc7,0xa7,0xef,0x8c,0x1f,0xdf,0x5c,0xa4,0x86,0x3b,0x4a, - 0x22,0xd8,0x6c,0x53,0xa0,0x84,0xe8,0x7a,0x81,0xf5,0x52,0x5d,0x19,0x63,0xdc,0xc6, - 0x86,0xe0,0x83,0x8e,0x87,0x30,0x8d,0x88,0xc3,0x78,0x7b,0x8a,0x97,0x88,0xc9,0x1c, - 0x65,0xc1,0x00,0x75,0xf6,0xa5,0xaf,0x4d,0xab,0x4f,0x95,0x60,0x04,0x30,0x37,0x18, - 0x40,0x2e,0xf1,0xd8,0x6f,0xd4,0x23,0x33,0xe6,0x70,0xb1,0x8e,0x26,0x60,0xaf,0xde, - 0xbe,0x85,0x30,0x91,0x9b,0xa3,0x97,0x8d,0x66,0x1a,0x4c,0x1c,0x74,0xe8,0xce,0x6b, - 0xc1,0x3e,0x41,0xef,0x13,0x61,0x4c,0x32,0x18,0x0c,0x76,0xdb,0x1d,0x6b,0x89,0x6b, - 0xe2,0x3d,0x46,0xc5,0x85,0x4e,0x65,0x33,0xb4,0xbb,0xc7,0x0e,0xbf,0x49,0x12,0xa0, - 0x08,0x26,0x12,0x42,0x58,0x30,0xb2,0x85,0xc4,0xf9,0x77,0x8a,0xfd,0x01,0x48,0x62, - 0x53,0x5a,0x07,0xb9,0xe6,0xe8,0xda,0xaa,0x54,0xb1,0x08,0xd1,0x22,0x8f,0x8e,0x4c, - 0x71,0x39,0xdd,0xf3,0xe1,0x85,0x3c,0xf8,0x40,0x9c,0x14,0x95,0xe3,0xac,0x3d,0x96, - 0x3b,0xfd,0x6f,0xae,0xfa,0x1b,0xac,0x7b,0x63,0x43,0xf6,0xfd,0x9b,0xc1,0xa0,0xdb, - 0xee,0x0a,0x18,0x7b,0x83,0xbc,0xb5,0x7f,0xe3,0xcd,0x2f,0x51,0xf2,0xf0,0xd0,0x34, - 0x69,0x1a,0xcd,0x2d,0x59,0xc4,0xb2,0xfa,0x9e,0x1c,0xb9,0x4c,0x83,0x94,0xc4,0xfb, - 0x03,0x76,0x94,0x7f,0xf3,0x2f,0xbc,0x5f,0x7b,0xf7,0xf0,0x06,0x7f,0x05,0x2c,0x3c, - 0x0d,0xbe,0xff,0xc6,0xfe,0x89,0x7f,0x39,0x1e,0xc6,0x11,0xa0,0x3c,0x01,0x1d,0x43, - 0x9a,0x2b,0x22,0xa2,0xd0,0x73,0x39,0xf7,0x80,0xad,0x1d,0xf7,0xcc,0xd3,0x4f,0xe7, - 0x17,0xa6,0xcd,0xb1,0xa6,0xd3,0xde,0xd2,0x14,0x04,0xaf,0x75,0x01,0x14,0x15,0x48, - 0x05,0x3a,0x65,0x8b,0xb8,0x53,0xdb,0x08,0x65,0xf3,0x91,0x2a,0xec,0xfd,0xe7,0xf9, - 0xa7,0x8f,0x4e,0x4a,0x24,0xc9,0x9f,0xdc,0x37,0xa9,0x91,0x02,0x01,0x99,0x5f,0x9f, - 0x79,0x7f,0x00,0x1b,0x25,0xc0,0xe1,0x12,0x38,0x7e,0xf1,0xc3,0xec,0x80,0xc8,0x76, - 0xf3,0x80,0x97,0xbd,0xc0,0xd3,0x51,0x72,0x1f,0x67,0xd1,0xc6,0x06,0xff,0x22,0x2b, - 0x76,0xe6,0xc2,0x87,0xf9,0x3f,0xc8,0x46,0xda,0xaa,0x4f,0x6e,0xba,0x50,0x07,0x2d, - 0xf8,0x09,0x00,0x19,0x5b,0xf1,0x07,0xed,0xbe,0xff,0xfa,0xa0,0xef,0x6f,0x6d,0x59, - 0xee,0xa5,0x7f,0x35,0xf8,0x00,0x63,0x75,0x48,0x25,0xdb,0xa4,0xc7,0x84,0x8a,0x37, - 0xad,0xef,0xba,0x7b,0xfb,0xf9,0x1c,0x97,0x37,0x92,0xb9,0x1b,0xf3,0x36,0xe2,0xe6, - 0x94,0x75,0x08,0x03,0xe1,0xec,0xcd,0xe1,0xeb,0xce,0xfe,0x91,0xd9,0x06,0xe8,0x98, - 0xd6,0xd6,0xd0,0xc9,0x22,0x41,0x9a,0x3b,0xfb,0x34,0x0f,0xce,0xbf,0x23,0x40,0x5b, - 0xd3,0xb4,0x4a,0x84,0x01,0xb0,0xec,0xad,0x07,0x13,0x0c,0x1b,0x2a,0x42,0x05,0xb6, - 0xb2,0xcd,0x4b,0x79,0x90,0x72,0x05,0x5c,0x26,0x0c,0xe2,0x8d,0xab,0xe3,0xaf,0x17, - 0x40,0x36,0x2f,0xd0,0x76,0x8c,0x2c,0x9a,0x4e,0x03,0xd8,0x31,0x88,0x7b,0xb2,0xbf, - 0x69,0x42,0x12,0x6e,0xe0,0x1b,0x1f,0xe9,0xa0,0x16,0x0a,0x38,0x58,0x21,0x2c,0x56, - 0x4c,0xb6,0x2c,0x81,0x16,0x44,0xbf,0xd1,0x28,0xf5,0xc4,0x4d,0xc6,0xb4,0xc7,0x55, - 0x8c,0xde,0x79,0x32,0x54,0x26,0x4b,0x3d,0x3d,0xa3,0xf1,0x66,0xa7,0x7b,0xf0,0x80, - 0xf0,0xc4,0xf6,0x60,0x54,0xa6,0x53,0x0c,0x00,0xb1,0x62,0x64,0xeb,0x06,0x96,0x66, - 0x4e,0x85,0x89,0xb1,0x1e,0xb9,0x93,0xf8,0x91,0xd9,0x1d,0x49,0xcd,0x02,0xff,0xc2, - 0x1d,0xc2,0xb8,0x36,0x5f,0x60,0x68,0x17,0x71,0xb7,0xc1,0xa5,0x1e,0x38,0x05,0xc0, - 0xdb,0x87,0xa2,0x9c,0xd3,0xe2,0x1f,0xb9,0xfd,0x62,0xa7,0x71,0xdb,0x27,0x55,0xb6, - 0x55,0xde,0xe4,0xa9,0x43,0x34,0x93,0x50,0x9e,0x5b,0x46,0xb6,0xcb,0x62,0x54,0x60, - 0xd8,0xa2,0x5a,0x7e,0x5d,0x0f,0xc8,0x08,0x57,0x74,0x41,0xe4,0xb5,0xc4,0x6f,0xa5, - 0x13,0x94,0x77,0x65,0x2f,0x30,0x0f,0x06,0xd4,0x5b,0x9b,0x81,0x82,0x5b,0xaf,0xcd, - 0x51,0x3e,0x47,0x78,0xa2,0x3d,0x2d,0x0a,0xb5,0x55,0x60,0x8a,0xcc,0xaf,0x89,0x49, - 0x9d,0x8a,0x18,0xf8,0x0b,0x71,0xf5,0x1c,0x9d,0x3b,0x43,0xb1,0x3c,0x04,0x53,0x24, - 0x74,0x0b,0xef,0x8f,0x3f,0x3a,0xa6,0x6a,0x3c,0x8f,0x75,0x5b,0x6a,0x9c,0x23,0xdf, - 0x42,0x83,0x1c,0xdb,0x35,0x14,0x61,0x5f,0x73,0xdb,0xc9,0xbc,0x0e,0x2d,0x9a,0x61, - 0xa9,0x12,0x0e,0x63,0xa5,0xe5,0xd4,0x83,0x5e,0x59,0x8e,0x0f,0xe3,0x4b,0x7e,0xba, - 0xf8,0x00,0x8c,0x79,0x39,0x3c,0x61,0x25,0x00,0x56,0xa5,0x12,0x0a,0xfa,0x64,0x39, - 0x52,0xd2,0xd4,0xf6,0x25,0x11,0xfe,0xeb,0xb1,0x40,0x21,0xf8,0x00,0x70,0xd9,0x40, - 0x1a,0x6d,0x6e,0xc3,0xdf,0x6d,0x61,0x5f,0x59,0xde,0x7d,0x90,0xaf,0x80,0x99,0x42, - 0xb1,0x60,0x90,0xd2,0x4f,0x1f,0x27,0x8e,0xa4,0x03,0x48,0xc0,0x87,0x7e,0x8e,0xaa, - 0x83,0x6f,0xbe,0x81,0x4c,0xf0,0xd0,0x57,0x0b,0x87,0x92,0xa0,0x53,0xfd,0x46,0xdd, - 0x42,0xa3,0xaf,0x32,0xf5,0x73,0x2a,0x93,0xb1,0x78,0x41,0x82,0xa0,0x7c,0x94,0xf2, - 0x59,0xe6,0xa6,0x0a,0x29,0x89,0x94,0x05,0x5a,0x0e,0x12,0xf9,0xfb,0x82,0x64,0x0c, - 0x90,0xe9,0x89,0xdd,0xa1,0x1f,0xf8,0x99,0xef,0x01,0x6b,0xd4,0xe6,0x82,0x24,0x5f, - 0x0c,0xf2,0xae,0x1f,0x35,0x61,0x34,0xe8,0xfc,0xed,0x7d,0xa6,0x4f,0x0f,0x0f,0xa9, - 0x93,0x60,0x4c,0x8e,0xb9,0x4a,0x68,0x5b,0xbd,0x36,0x91,0x85,0x14,0x9d,0x25,0x3e, - 0x8f,0xe6,0xe3,0xf4,0xb0,0x6d,0x9d,0xbc,0x7f,0xf7,0xf9,0xc3,0xf1,0x6f,0x83,0x3c, - 0x91,0x1a,0x40,0x26,0x56,0xf0,0xb0,0x7d,0xc9,0xc3,0x41,0x0a,0xfd,0x7e,0x86,0xd5, - 0xea,0xc9,0x2f,0xc0,0x0f,0x21,0x68,0xf1,0x47,0x65,0x46,0xbb,0x42,0xcc,0x8c,0xbf, - 0x94,0x48,0xb3,0x2d,0xae,0xb3,0x28,0x62,0x55,0x4a,0x41,0x8a,0x20,0x93,0xd4,0x9d, - 0xa8,0xcc,0x78,0xb9,0x45,0x39,0x2f,0xb6,0x02,0x7c,0xe5,0x77,0xc0,0x16,0xe4,0x5c, - 0xb7,0x4c,0xe0,0xf6,0x98,0xce,0x0c,0x07,0x5c,0x09,0xdf,0x6e,0x61,0xf5,0x87,0x35, - 0xb2,0x84,0x5c,0xb9,0x0c,0x11,0xc4,0x90,0xc1,0xc0,0xe4,0x13,0x2f,0x6b,0x39,0x2c, - 0x2d,0xa0,0x37,0x17,0xbf,0x9c,0x9a,0x85,0x6a,0x58,0xb0,0xe1,0xec,0x8f,0xb8,0xb5, - 0x96,0xcb,0xc0,0xda,0x34,0x1f,0xc5,0x60,0xe4,0xd5,0x15,0x2b,0xc9,0x47,0x69,0xcf, - 0xeb,0x6b,0xfc,0xb4,0x9c,0xe1,0x1c,0xd9,0x85,0xa0,0x69,0xd6,0xb0,0x71,0x42,0xa4, - 0xc9,0x45,0xd1,0xc7,0x47,0xab,0xa7,0xbf,0xd6,0xb0,0x68,0x31,0x2f,0x12,0x91,0x69, - 0x10,0xcb,0xa7,0x87,0x87,0xcb,0xab,0xbe,0x20,0xe6,0x65,0xf8,0xe8,0x87,0x7c,0x8f, - 0x4a,0x94,0xf8,0x46,0x2d,0xae,0x02,0x5b,0xca,0x19,0x96,0x79,0x60,0xb3,0x47,0xec, - 0x44,0xa9,0xef,0x1e,0x33,0x8a,0x9e,0x23,0x5c,0x13,0x80,0x45,0x14,0xdc,0xeb,0x72, - 0x15,0x42,0x98,0x9a,0xa1,0x0e,0xde,0x72,0xef,0x8d,0x8d,0x16,0x45,0xa1,0xbf,0x47, - 0x3f,0xf4,0xbe,0xc6,0x89,0x23,0xc1,0xb0,0xbb,0x6d,0x12,0x1a,0x4b,0xec,0x1f,0xf6, - 0xb3,0x79,0x63,0x2d,0x2f,0xcd,0x17,0xf2,0xaa,0x10,0x1b,0x1f,0xc5,0x6d,0x11,0xf4, - 0x8c,0x01,0xd3,0xae,0xaa,0x7b,0xb3,0x3f,0xc6,0xbe,0xc1,0xdf,0xfa,0x59,0x85,0x86, - 0xbe,0x85,0x9a,0xd7,0xa0,0x9e,0x92,0xbd,0xe9,0xb2,0xce,0x6a,0x3e,0x71,0x7d,0x27, - 0x64,0x65,0x09,0x2c,0xf1,0x5a,0x6e,0x32,0x47,0x17,0x97,0x7b,0xa2,0xdd,0xf0,0xdd, - 0x20,0x8a,0x89,0x8a,0x40,0x26,0xe7,0x78,0x61,0x88,0xcf,0x6a,0x40,0xba,0x8a,0x02, - 0x29,0x7f,0x63,0x11,0xe3,0x92,0xc5,0xa3,0x92,0xef,0xf1,0x48,0xb3,0x34,0x7a,0x31, - 0x4b,0x34,0x63,0xcd,0x1c,0x0a,0x16,0x23,0xaf,0x76,0xcf,0x88,0x85,0xa3,0x7b,0x83, - 0xe7,0x05,0xef,0xc9,0x61,0x14,0x56,0x9f,0xbc,0xd1,0x23,0xe7,0xfe,0xbc,0x1b,0x64, - 0xc5,0x6e,0x2a,0x27,0x0b,0x62,0x61,0x66,0xe1,0x20,0xaf,0x15,0x4f,0x75,0x60,0x71, - 0x66,0xa1,0x23,0xaf,0x57,0x1a,0xe0,0x19,0x47,0x3f,0xcf,0x81,0x11,0xf6,0x4a,0x93, - 0x0e,0x14,0x82,0x05,0x25,0x5e,0x0c,0x62,0xca,0xfe,0x02,0x97,0xde,0xa8,0x63,0xd3, - 0x97,0x92,0x50,0xf7,0xf2,0xce,0xa0,0xe5,0x8f,0xe5,0x90,0xa1,0x0c,0x30,0xf0,0x56, - 0xa3,0x2a,0x9f,0x95,0xc5,0xac,0x8a,0x2c,0x24,0xd6,0x67,0xda,0x93,0x22,0x8c,0xfd, - 0xef,0xde,0xbf,0x1f,0xeb,0x6a,0xbb,0x03,0x30,0x16,0x20,0x43,0x5a,0x28,0x5a,0x8f, - 0x77,0x0e,0x0a,0x7f,0x80,0xce,0x30,0x67,0x6a,0x37,0x2b,0x01,0x4e,0xeb,0x2b,0x82, - 0x4c,0x5f,0x7b,0xb4,0x5a,0xd7,0x81,0xf8,0xce,0x51,0x62,0x18,0xdf,0xb7,0x22,0x56, - 0x97,0xd9,0xaf,0x59,0xb7,0x40,0x2b,0xab,0xbd,0x5c,0x3b,0x81,0xda,0xaa,0xa5,0x56, - 0x4c,0x29,0x94,0x29,0xac,0xcc,0x6d,0x70,0x96,0x24,0x9d,0xa9,0x99,0xc6,0x53,0x75, - 0x7b,0x59,0xa1,0x60,0x3a,0x1c,0xb8,0x03,0x3a,0xf5,0xa9,0xe9,0x72,0x41,0xfe,0x1a, - 0x4d,0xa6,0x20,0x25,0x35,0xaf,0xad,0x25,0xae,0x31,0x90,0x68,0x0c,0xd7,0xf8,0x3f, - 0x40,0x3c,0xfe,0x0f,0x79,0xe0,0x64,0x82,0x23,0x13,0x21,0xd1,0x38,0x12,0x16,0xe3, - 0x89,0x2d,0x5c,0xee,0x61,0xab,0x9e,0x4c,0x99,0xc1,0x1e,0xf0,0x8b,0x3d,0xb7,0x93, - 0xc1,0xc8,0x21,0x66,0xca,0xfe,0x03,0x9e,0x90,0xab,0x78,0x78,0x58,0xb2,0x5a,0x10, - 0x75,0x7e,0xb7,0x90,0x88,0xcc,0x22,0x4d,0x68,0x73,0x3e,0xb8,0x76,0x28,0x16,0x57, - 0x73,0xfb,0x5f,0x98,0xb5,0x79,0xd9,0x69,0xbd,0xba,0xb2,0x7e,0x77,0x9a,0xbf,0xdf, - 0x6e,0x59,0xdf,0x6e,0x83,0xc0,0xb0,0x64,0xfd,0x50,0xf3,0x0f,0x47,0xec,0xe7,0x97, - 0x57,0xd6,0xe5,0x16,0x2a,0x8b,0x5a,0x9d,0x2b,0x52,0x99,0x60,0x86,0x9b,0x41,0x7a, - 0x39,0xbf,0xec,0x5e,0x5d,0x49,0x85,0xfb,0xcd,0x60,0x80,0xda,0xca,0x23,0xd3,0xec, - 0x09,0xd9,0xeb,0x06,0xc6,0xce,0xbe,0x23,0x38,0xe4,0x06,0xfa,0x4c,0x71,0xa0,0xc2, - 0x9e,0xc2,0x5e,0x7c,0xed,0xd3,0x87,0x52,0x30,0xc1,0x3c,0x8b,0xfa,0xf0,0x59,0x6c, - 0xe0,0x80,0x1c,0x54,0x02,0x63,0xec,0xf5,0x8a,0x8a,0xb8,0xc4,0x81,0x44,0x8b,0x2b, - 0xc4,0x38,0x79,0xd5,0xcf,0x51,0x68,0x89,0xe2,0xd9,0x5d,0xf5,0x73,0x76,0x27,0x0a, - 0xbb,0x93,0xea,0x47,0x77,0x22,0x8b,0xca,0xe0,0x40,0x95,0x2c,0xe2,0x83,0xa8,0x24, - 0x5b,0x95,0x2d,0x93,0xd9,0xb8,0x3a,0x0c,0x7e,0x93,0x8f,0x17,0xde,0x8e,0xd0,0x41, - 0xa0,0x47,0xf6,0x0e,0x5c,0x53,0x21,0xea,0x4c,0x9e,0x95,0x13,0xf4,0xdc,0x0d,0x2d, - 0xbb,0x16,0xeb,0x25,0x2f,0x02,0x89,0x9f,0xd7,0x17,0xa3,0xe8,0x12,0xaa,0x00,0xbc, - 0x9c,0x10,0xd6,0x2e,0x3c,0x20,0x3b,0x22,0xa3,0x1e,0x84,0x25,0xaf,0x5a,0x4b,0xad, - 0xa9,0x9b,0x1d,0xf2,0xb5,0xbe,0x53,0x42,0x35,0x63,0xee,0xc2,0x5c,0x01,0x1b,0x7d, - 0xfa,0x0c,0x9f,0xac,0x72,0x5e,0xe9,0x51,0xbc,0xba,0xc8,0x67,0xce,0x51,0x2d,0xa9, - 0x5c,0x79,0xd7,0x94,0x95,0x79,0x64,0x69,0xdd,0x29,0x36,0x1f,0x11,0xa6,0x7e,0xe6, - 0x54,0x91,0xaf,0xec,0x47,0x5f,0x45,0x29,0xca,0xf0,0x59,0x66,0x28,0xf6,0xee,0xc9, - 0xd2,0xdc,0xc1,0x15,0x75,0x28,0x9b,0x52,0x51,0x4c,0x2d,0x9b,0xdc,0xe8,0x56,0x56, - 0x78,0x4b,0xaf,0xfd,0xfc,0x2b,0x92,0xf4,0xfc,0x23,0xbc,0xe9,0xdf,0x94,0x9d,0xa8, - 0x96,0x43,0xa6,0x89,0x26,0x74,0xcf,0x52,0x99,0xeb,0x0f,0x91,0xd0,0xcf,0x73,0x90, - 0x3f,0x66,0xfe,0x1d,0x5f,0xf5,0x0a,0x84,0xa4,0x95,0x67,0xe0,0x84,0xca,0xe2,0x28, - 0xb8,0x8f,0xe5,0xb9,0x45,0x4a,0x15,0xc3,0x94,0xcf,0x56,0x9e,0x17,0xde,0xea,0xab, - 0xd5,0x88,0xc4,0x1f,0xf0,0xa2,0x7d,0x49,0xf4,0x2f,0xc9,0xdd,0x8a,0x66,0x56,0x4d, - 0xde,0x1f,0x4e,0x79,0xbe,0x4a,0xae,0x4d,0x79,0xdd,0x2a,0xad,0xbe,0x87,0x35,0xee, - 0x2b,0x95,0xb6,0x54,0x9e,0xcf,0xf5,0xad,0x66,0xb1,0xde,0x5e,0x16,0x17,0xa6,0x91, - 0xdc,0x4f,0xb5,0x59,0xc4,0x77,0xad,0x7d,0xf6,0xdb,0xcc,0xbf,0xd3,0xbb,0x24,0xb1, - 0xd2,0x87,0x42,0x83,0xa1,0x48,0xea,0x17,0x32,0x48,0xe7,0x85,0x4a,0xcf,0x65,0x86, - 0xcf,0x9c,0x41,0x76,0x9b,0x7c,0x09,0x34,0xc4,0x80,0xd7,0x0a,0x74,0x4a,0xde,0x00, - 0xc5,0xdc,0x9f,0xd5,0x87,0x5c,0x6b,0x8b,0x2b,0x44,0x3f,0xe9,0x09,0x70,0xaf,0x26, - 0x7d,0x1f,0x4a,0x0b,0x81,0x43,0x26,0x2e,0x03,0xcd,0xb5,0x41,0x28,0x9c,0x0c,0xd4, - 0x9a,0x61,0x9a,0x57,0x20,0xdc,0x8d,0xfc,0x2b,0x6d,0xe5,0x45,0x59,0x00,0xcf,0xb5, - 0xa1,0x52,0xfb,0x66,0x4d,0xf5,0x79,0xbd,0x83,0xe6,0x0d,0x7e,0xe2,0x83,0x19,0xe2, - 0xaa,0x64,0xad,0x83,0x9b,0x42,0xbd,0x25,0x7a,0x2d,0x35,0xe2,0x98,0xfc,0x59,0x84, - 0x92,0x12,0xbd,0x16,0x9d,0xc4,0xad,0x9c,0xa2,0x3c,0x0d,0x84,0xbe,0x52,0x64,0xa6, - 0x34,0x0b,0x64,0x79,0x5b,0x46,0x03,0x2a,0x65,0x90,0xc9,0x16,0x69,0x0a,0xa0,0x19, - 0x2a,0x71,0x38,0xe8,0x6c,0x6c,0x70,0x58,0xa9,0x41,0xa7,0x2d,0x9b,0xa2,0x04,0x90, - 0x9c,0xe9,0x77,0xab,0xd9,0x54,0x55,0x0e,0x06,0x9d,0xfd,0x87,0x07,0xed,0x75,0xa7, - 0x6b,0x1d,0x99,0x86,0x4c,0x80,0x22,0xf2,0xb1,0x67,0x6a,0xfa,0x7f,0x6d,0xbf,0x85, - 0x9e,0x24,0x40,0xa0,0x81,0x4b,0xd9,0xdf,0xdb,0xef,0xee,0xa1,0x8c,0x6e,0x6e,0x15, - 0xbf,0x53,0xa8,0x1c,0xce,0x82,0xa1,0x71,0x8a,0x42,0x19,0xfa,0x03,0x9f,0x41,0xae, - 0xa6,0x3c,0x87,0x11,0x50,0x1a,0x28,0x4d,0x70,0x31,0x0e,0xd7,0xd5,0xa6,0x65,0x33, - 0xbc,0x4a,0x19,0x38,0x54,0x16,0x6a,0x14,0x09,0xe6,0x22,0xff,0xc3,0xc3,0x37,0x0c, - 0x49,0xa9,0x9b,0x14,0xe9,0x6a,0x62,0xbf,0x29,0xcd,0x0e,0xcf,0x48,0xb8,0x6a,0x36, - 0xfa,0xf4,0x24,0xa6,0x3e,0x24,0x68,0x87,0x08,0xe9,0x23,0x31,0xe4,0xd0,0xea,0xc9, - 0x50,0x53,0xa8,0xde,0x28,0xf4,0x50,0x85,0x75,0x42,0xc5,0x36,0xd7,0x50,0x04,0x54, - 0x69,0x5a,0xaa,0xa9,0x3b,0xdd,0xa3,0x52,0x62,0xaf,0x6d,0x55,0xda,0x01,0xca,0xb8, - 0xaa,0x85,0xc2,0x54,0x55,0x0a,0x72,0x4c,0xa3,0x55,0x65,0xab,0xd3,0x98,0x78,0x93, - 0xc4,0x4b,0x67,0x34,0x7d,0xc4,0x8c,0x17,0xa7,0x56,0xff,0x3c,0x77,0x93,0xeb,0x67, - 0x4f,0xb0,0x9c,0x9c,0x27,0x26,0x5a,0x2e,0x6b,0x52,0x37,0x13,0xcc,0x07,0x5c,0x60, - 0xa0,0xc2,0x7d,0xe5,0x8b,0xe7,0xc9,0xb9,0x60,0x6d,0x94,0x1e,0xbe,0xca,0x5a,0xad, - 0x8b,0xe7,0x1c,0x96,0x56,0xa6,0x14,0xee,0x6b,0x75,0x59,0x55,0x94,0x98,0xf8,0xdc, - 0x5d,0x95,0xd0,0x56,0x92,0x08,0x84,0x14,0x7e,0xe1,0xcc,0x8d,0x23,0x63,0xcd,0x14, - 0xd3,0x8a,0x5b,0x3f,0x93,0x8d,0x9e,0x51,0xa6,0x01,0xb2,0xbf,0xa8,0x7c,0x69,0x9b, - 0xeb,0xd6,0xfc,0x23,0xf5,0x94,0x23,0xa1,0xe5,0x60,0x2c,0x06,0x43,0xc3,0x65,0xc7, - 0x39,0x24,0x55,0xcc,0xa7,0x86,0xac,0x26,0x06,0x88,0x00,0x1b,0x1b,0x94,0x0c,0x4d, - 0xa6,0xcc,0x9e,0x5c,0x16,0xea,0xe8,0x6b,0xc7,0x3f,0x98,0xb2,0xf2,0xfc,0xa7,0xf6, - 0x94,0x84,0x9a,0x31,0xd9,0x46,0x43,0x1e,0x8b,0x10,0xd6,0xe1,0x9f,0x1f,0x30,0xb5, - 0xa9,0xb7,0x66,0x53,0x57,0x6c,0xee,0xb4,0x3e,0x91,0x35,0x5a,0x75,0x49,0x4c,0x60, - 0x1e,0xcc,0x4f,0x93,0x49,0xaf,0x1a,0x83,0x50,0xc4,0xd5,0xd2,0x03,0x10,0x06,0xf7, - 0x8e,0x09,0x70,0x57,0x33,0x68,0x9e,0x2c,0xd2,0x0c,0x64,0x48,0x51,0x64,0x3b,0xd5, - 0xe2,0x8f,0xa5,0x78,0x5d,0x17,0x9d,0x86,0xa1,0x69,0x98,0x3f,0x9f,0x7b,0x63,0x60, - 0xc6,0xf0,0x06,0x29,0x71,0xdb,0x22,0x88,0x0b,0xf0,0x81,0xaf,0x5b,0x14,0x57,0x49, - 0x62,0xe5,0xe6,0x7b,0x9a,0x54,0x0e,0x66,0x87,0xca,0x20,0xa8,0xdc,0x0d,0x46,0x8b, - 0x80,0xa2,0xa3,0x4c,0x94,0xab,0x99,0xb8,0x39,0x42,0x84,0x84,0x56,0x41,0xa2,0x59, - 0x97,0x84,0x7c,0xe3,0xd8,0x29,0xee,0xbd,0x04,0xa8,0x93,0x68,0x3e,0x8c,0xe4,0x59, - 0x65,0x3c,0x00,0xb9,0x13,0x0f,0xb2,0xc4,0xfc,0x4c,0xaf,0x56,0x9d,0x61,0xc5,0x97, - 0xda,0x91,0x1b,0xe4,0x1b,0x48,0x7a,0xf9,0x98,0x6f,0x20,0xb1,0x83,0x91,0x9c,0xb7, - 0x4c,0x1b,0x90,0xcd,0x19,0xde,0x8a,0x87,0x74,0x22,0x1e,0x46,0x49,0x65,0x8f,0xa0, - 0xe8,0xde,0xd3,0xa6,0x3a,0x70,0x34,0x72,0x25,0xa9,0xb8,0x46,0xb8,0xac,0x2a,0x18, - 0xb1,0xb2,0x13,0x64,0xf4,0xc1,0xa8,0x2f,0x10,0x0e,0x07,0x01,0x8f,0x8c,0x92,0xc2, - 0xf6,0x40,0x3b,0xc0,0x5a,0x92,0xd6,0xfb,0x1c,0xa5,0x6e,0x40,0x87,0xdc,0xb3,0xd7, - 0xea,0x17,0x3e,0xa8,0x3b,0x4f,0x50,0x71,0xa6,0x40,0x72,0xbd,0x12,0x22,0x04,0xc0, - 0xeb,0x81,0x06,0x96,0x6b,0xfb,0x66,0xa0,0x94,0x11,0xa4,0x86,0xa7,0xe5,0x70,0x7d, - 0x05,0xec,0x84,0xc6,0x9a,0xf4,0x0b,0x98,0x2e,0x75,0x85,0x8c,0xe9,0x82,0x82,0x04, - 0xee,0x70,0x40,0xb9,0xf0,0x76,0xda,0xac,0x69,0x3a,0x13,0xf8,0x42,0x0a,0x8a,0xd9, - 0x00,0xbe,0x01,0x33,0xe0,0x0e,0x4b,0xc6,0x43,0xa6,0x83,0xe1,0xc7,0x4d,0x3e,0xfd, - 0x9b,0x59,0xa3,0x99,0x76,0xe0,0xf6,0x28,0x8e,0x2b,0x2f,0x65,0x74,0xf4,0xab,0x35, - 0x47,0x95,0x52,0xe7,0x54,0x2c,0xb4,0x06,0x35,0x54,0x19,0xb1,0xb3,0x08,0xbd,0x49, - 0x09,0x61,0xd6,0x0f,0x1b,0x1b,0x53,0x4c,0x83,0xa8,0x20,0x07,0x21,0xbf,0x0f,0x74, - 0xfc,0xed,0xbb,0x93,0x9f,0x60,0x4d,0x37,0xe9,0x92,0x79,0x79,0x24,0xde,0xe9,0xfb, - 0xaf,0x07,0xea,0x78,0x85,0xce,0xc6,0x97,0x62,0xbf,0xc2,0x59,0x7e,0x8b,0x44,0x3c, - 0x6d,0x7e,0x5b,0xc4,0x02,0xdb,0x47,0xeb,0xc6,0xba,0x4c,0x39,0x46,0x40,0x9e,0xc7, - 0x46,0x7a,0x1f,0x8e,0x4e,0x49,0xfc,0x79,0xeb,0x07,0x18,0xcb,0x06,0x1b,0x2f,0xa9, - 0x66,0x2b,0xd6,0x09,0x39,0x9d,0x02,0xec,0xb0,0x25,0xdf,0x8b,0x7c,0x67,0x8e,0x1e, - 0xd6,0x72,0xec,0xd1,0x4d,0x0c,0x12,0x89,0x21,0x8d,0x8f,0x24,0xb4,0x84,0xc1,0xcd, - 0x23,0xb3,0xb4,0xd6,0x3a,0x42,0x79,0x8d,0x26,0xa6,0xb2,0x14,0x93,0xcb,0x6b,0xdc, - 0x39,0x5d,0x40,0xa0,0x1c,0x62,0xd5,0x4e,0x6b,0xa7,0xf7,0x22,0x97,0xb4,0xed,0x20, - 0x68,0x51,0x7c,0x68,0x42,0xad,0x6f,0xbc,0xc2,0x81,0xb0,0x3b,0x19,0xc4,0x6e,0x92, - 0x7a,0x6f,0xd1,0xd1,0xad,0xa9,0xef,0x23,0xd0,0xa2,0xda,0xa9,0x90,0xbd,0x2e,0xd0, - 0x5e,0x3f,0x7d,0xeb,0x83,0x98,0xe0,0x35,0xdd,0x89,0xb5,0xb1,0xe1,0x4e,0x0e,0x07, - 0xed,0x23,0xf3,0xff,0xc2,0x26,0x25,0x6c,0x17,0xf0,0x6e,0xf8,0x26,0x06,0x60,0xdc, - 0x86,0x1c,0x5b,0x1d,0xcb,0xda,0x06,0xb6,0x77,0xcb,0xfc,0x0f,0x63,0xbc,0xc8,0xee, - 0x0d,0x0a,0x19,0x8b,0x36,0x09,0xd8,0x71,0xa5,0x83,0xaf,0xea,0xb6,0xc9,0x5b,0xa6, - 0xac,0xda,0xa6,0x51,0x05,0x03,0xef,0xc6,0xc9,0xc8,0x64,0xaf,0x2f,0x04,0x05,0x85, - 0xaa,0x80,0x81,0x44,0x8f,0x72,0x36,0x87,0xec,0xf6,0xa1,0x2d,0x79,0x4c,0xa2,0x2f, - 0xf9,0x82,0x79,0x03,0x0c,0x7b,0x73,0x4b,0xff,0xba,0xb5,0x69,0xd6,0xee,0x77,0x91, - 0xb5,0x44,0x3b,0x26,0xd8,0x33,0x61,0x3e,0x99,0x34,0x44,0xb6,0x12,0x8d,0x68,0x35, - 0xe4,0x88,0x53,0xa0,0x30,0x2a,0x13,0xe2,0x52,0x7d,0x9f,0x60,0x7d,0x17,0x8d,0x2e, - 0xf0,0x36,0x84,0x42,0xbf,0x20,0xe5,0x59,0x3d,0x8b,0xc4,0xc2,0xd6,0x69,0x7d,0x5d, - 0x8b,0xc9,0x54,0x00,0xf6,0xa6,0xb8,0x46,0x9f,0xa6,0x1f,0xd0,0x5c,0xb4,0x1a,0x9b, - 0x6f,0x72,0xa6,0x42,0x90,0x84,0x22,0x64,0xc4,0x4d,0x36,0x48,0x53,0x85,0xf9,0x9d, - 0x3c,0x96,0x46,0x42,0x88,0xda,0x60,0x75,0x25,0x86,0xb8,0xc7,0x59,0x5c,0x78,0x8a, - 0xfe,0xdf,0xe8,0x46,0x61,0xe0,0x7d,0xdf,0x69,0x46,0x1b,0xc6,0xc6,0x46,0xea,0x88, - 0xf8,0xbe,0x0e,0xc7,0x84,0x12,0x83,0x9a,0x0f,0x5a,0x9d,0xfe,0xd9,0xf1,0x0f,0xef, - 0x3e,0x7d,0x3e,0x3d,0x7b,0x73,0xfe,0xe6,0xe2,0xbc,0x3a,0x8e,0x18,0x28,0x04,0x02, - 0x6e,0x84,0x23,0x7f,0xf3,0x47,0x93,0xdb,0x61,0x38,0xc4,0x16,0x74,0xd0,0x9a,0x0f, - 0x7c,0xec,0x7c,0x2a,0x40,0x3a,0x47,0x94,0x17,0x04,0x73,0x6e,0xf5,0x9a,0x72,0x2c, - 0x85,0xf5,0x7b,0x64,0x62,0xff,0xcd,0x5e,0xaa,0x96,0xd1,0x63,0xe3,0xb1,0xa8,0x6a, - 0x2f,0x2d,0xe5,0xa5,0x10,0x74,0x3e,0x0d,0x31,0xc6,0x12,0xda,0x51,0xa5,0x4d,0x55, - 0x9d,0x18,0x96,0x58,0xb9,0x71,0xfc,0x0f,0x3f,0xf5,0x91,0x8b,0xfe,0xe6,0xdb,0xa6, - 0x3c,0x25,0xd3,0x39,0x5c,0x11,0xae,0x31,0x2d,0xd9,0x5c,0x08,0x07,0xa3,0x3a,0x5e, - 0x98,0xcc,0x3b,0xed,0xf0,0xb0,0x0d,0x6b,0x5a,0x55,0xaf,0x95,0x6b,0x85,0x25,0x1e, - 0x2c,0xdc,0x6a,0x86,0x28,0x17,0x01,0xa7,0xca,0x3e,0x40,0xb0,0xaa,0xa5,0x37,0x90, - 0x59,0x96,0x3b,0x94,0xfb,0xd1,0x52,0x67,0x1d,0x2a,0x47,0x09,0x6c,0xe8,0x6a,0xb2, - 0x87,0x12,0x88,0x1e,0x64,0xac,0x45,0x96,0xc7,0xef,0x3f,0x5d,0xe0,0x59,0xf9,0xfb, - 0x37,0x1f,0x07,0x90,0xeb,0xda,0x0b,0x7b,0xbb,0x2f,0xed,0x45,0x8a,0xa1,0xc1,0xe7, - 0x5e,0x6f,0xa7,0xa3,0xcc,0x89,0x7b,0xfb,0x3b,0x36,0xbb,0x99,0xe2,0x13,0xc5,0x33, - 0xea,0xbd,0xda,0xb3,0xdd,0xc5,0xd8,0x47,0x67,0x2d,0x48,0x7c,0x64,0x20,0x9e,0xfe, - 0x7c,0xf1,0xf9,0xe2,0x9f,0xa7,0x6f,0xce,0x07,0x97,0x97,0x6d,0xdb,0x3c,0x7b,0xf3, - 0x5f,0xe6,0x95,0x7d,0xd9,0xc1,0xa7,0xf3,0xd3,0x4f,0x1f,0xcf,0xdf,0xe0,0x6b,0xd7, - 0x36,0x2f,0x7e,0x83,0x96,0xcf,0x7f,0xc4,0xb7,0x1d,0xdb,0x3c,0x3e,0xf9,0x19,0x9f, - 0x76,0xe1,0xe9,0x87,0x7f,0xbc,0x39,0xbb,0x80,0x97,0xc6,0xe5,0x9e,0x6d,0xfe,0x78, - 0x76,0xfa,0x19,0x72,0xe2,0xb7,0x7d,0x7e,0xfb,0xe1,0xf8,0xe2,0x18,0x5f,0x5f,0x42, - 0xd6,0x8f,0x9f,0x3e,0x7e,0x16,0x0d,0x1c,0xd8,0xe6,0xe9,0xf1,0xc5,0x4f,0xf8,0xf8, - 0x0a,0x2a,0x3f,0x3b,0x3e,0x79,0x43,0x75,0x74,0xa0,0x0f,0x1f,0x7e,0x79,0x7f,0xf1, - 0xee,0xf4,0x98,0x6a,0xbd,0xec,0x40,0x57,0x4e,0x3e,0x7d,0xbc,0x38,0xfb,0xf4,0x9e, - 0x5e,0xa1,0x2b,0x88,0x98,0x30,0xb2,0x31,0xbd,0xef,0x94,0xde,0x77,0x0b,0xef,0x50, - 0x21,0xf4,0xea,0xec,0xf8,0xd7,0xcf,0x27,0xbf,0x9c,0x5f,0x7c,0xfa,0x60,0x5e,0x5d, - 0xe5,0xc3,0xfe,0x78,0xfc,0xe1,0xcd,0x0f,0x12,0xcf,0x46,0x20,0x5b,0x00,0x35,0xc7, - 0x93,0x0a,0x98,0x35,0x05,0x95,0x9a,0x75,0x42,0xab,0x24,0xbe,0xec,0x5c,0xa1,0x88, - 0xa2,0xda,0xb2,0x54,0x8d,0x97,0xf8,0x0d,0x10,0x8a,0x02,0x87,0x9e,0x00,0x75,0x69, - 0x5a,0x57,0x83,0xf8,0xb2,0x7d,0x55,0xc0,0xfa,0x09,0x6d,0xc0,0x1f,0xdc,0xf4,0xba, - 0x89,0xe8,0x24,0xd0,0x3e,0x93,0x1c,0x08,0xa6,0xe5,0xe7,0x26,0x94,0xc3,0x81,0x2f, - 0xf3,0x26,0xef,0x88,0x19,0xee,0x88,0xe6,0xc3,0x03,0xfd,0xba,0x41,0xa0,0x54,0x4e, - 0xed,0xbb,0xb7,0xf0,0x5f,0x9e,0x87,0xfc,0xef,0xd5,0x47,0x29,0x93,0xa6,0xd7,0x83, - 0xb6,0x1d,0x5d,0xf3,0x89,0x5d,0x23,0x73,0x52,0x60,0xf0,0x01,0xe1,0xec,0x3a,0xfa, - 0x86,0xa1,0x4c,0x65,0xef,0xa0,0x08,0xbe,0x8a,0x9e,0xd8,0x21,0x92,0x15,0xb2,0x07, - 0xfe,0xd7,0x65,0xbb,0xf5,0xea,0x6a,0xeb,0x5b,0x61,0xbe,0x0b,0x19,0x2d,0x2b,0xe4, - 0x7d,0xf5,0x5d,0x48,0xef,0x76,0xa7,0x2d,0x55,0x54,0xd8,0xb7,0xe8,0xba,0x08,0x21, - 0x24,0x1a,0x0a,0x82,0x50,0x34,0x87,0x66,0x25,0x2b,0x5b,0x04,0x84,0xaf,0xdb,0x0f, - 0x0f,0xe1,0x61,0x67,0x0f,0xc8,0xef,0xb5,0x38,0x72,0xe3,0x61,0x3e,0x36,0x70,0x80, - 0x0f,0x83,0x66,0xe7,0xf5,0xeb,0x50,0xb0,0x33,0x02,0x00,0xd1,0xf5,0x11,0x7e,0xeb, - 0x49,0x28,0x3d,0x96,0xe7,0xe3,0x02,0x00,0xdd,0xc4,0x2c,0xcc,0xe4,0x10,0xa4,0x06, - 0x03,0xce,0x2e,0x95,0x56,0x08,0xee,0xbe,0xfe,0x55,0x7e,0x20,0x58,0x33,0x88,0xa3, - 0x45,0x36,0x40,0xd3,0x85,0xa2,0xad,0x63,0x67,0x9f,0x18,0x3a,0x51,0x74,0x03,0x3b, - 0xe8,0x5b,0x16,0xe4,0x75,0xe2,0x45,0x3a,0x6b,0xfa,0x5a,0x47,0x21,0x8d,0x2d,0x13, - 0xed,0x12,0x11,0x49,0x25,0x83,0xf7,0x53,0x36,0x0f,0x9a,0xbe,0x3d,0xb1,0x51,0x3f, - 0x68,0x53,0x04,0x07,0x1b,0x65,0x44,0x25,0x89,0x6c,0x16,0xe2,0x40,0x18,0xe9,0xa4, - 0xb5,0xb9,0x35,0x81,0x4d,0x53,0x06,0x80,0xd8,0xdc,0xa2,0xdf,0xad,0xcd,0xda,0xd0, - 0x13,0x9b,0x5b,0xf8,0x0b,0xd9,0x0b,0x81,0x7c,0x36,0xb7,0xfc,0xad,0x4d,0x87,0xeb, - 0xf9,0x0b,0xf7,0x67,0x6e,0x6e,0x35,0xb1,0xab,0x47,0x9b,0xd5,0x08,0x3f,0x9b,0x5b, - 0xf8,0x8b,0x9d,0x42,0x37,0x8c,0xcd,0xde,0xe6,0xa6,0xa5,0x5e,0x8a,0x46,0xb3,0x1a, - 0x1f,0xcb,0xb0,0x10,0x58,0x3a,0x8c,0xee,0xbc,0x74,0x90,0xaf,0xe0,0xb9,0x1b,0x17, - 0x2d,0x4d,0x24,0x78,0x68,0xd4,0xb2,0xf5,0xf8,0x7a,0x7d,0xa0,0x9a,0x78,0x82,0x30, - 0xf1,0x71,0xdc,0x42,0xbc,0xd8,0xdc,0xc2,0x45,0x8d,0x00,0xe5,0x00,0x0a,0x87,0x32, - 0xc1,0xc0,0x87,0xce,0x15,0x76,0x5b,0x3a,0x98,0x31,0xc0,0x4b,0x06,0xa7,0xab,0xa6, - 0x89,0x51,0x51,0x8b,0x10,0xc2,0x61,0xf5,0xa0,0x57,0x2a,0xe0,0xd8,0x66,0x03,0x6a, - 0x5f,0x17,0x10,0x3e,0x9f,0x2c,0x59,0x1b,0x15,0xd1,0x9a,0x8a,0xaf,0xa7,0x08,0x6d, - 0x82,0x96,0x82,0x70,0x25,0x8f,0x0b,0xdd,0x58,0xe7,0xae,0x1f,0xa0,0x0f,0x8f,0x00, - 0x10,0xb0,0x0b,0x02,0x46,0x3d,0x5c,0x23,0x18,0xc8,0x4c,0xf9,0x6b,0x52,0xcd,0x7f, - 0xa2,0xa2,0x3c,0x7e,0x48,0xb1,0x2a,0xdd,0xbb,0x0a,0x0a,0x2c,0xe6,0x25,0xc7,0xcd, - 0xf2,0x48,0x18,0xb9,0x7e,0x9d,0xf9,0x23,0x8c,0x65,0x78,0x8f,0xdb,0x2f,0x43,0x94, - 0x34,0x1c,0x1c,0xfe,0x51,0x7a,0xd2,0xf9,0xa9,0x08,0xf5,0xe8,0x18,0x5a,0x24,0xde, - 0x21,0x5e,0x2f,0x27,0x42,0x1c,0x92,0xf6,0xc3,0xbd,0x15,0xe5,0xd2,0xbe,0x0c,0xd5, - 0x88,0xe9,0xea,0x4c,0x85,0x6a,0x0e,0x29,0xc2,0x24,0xcf,0x81,0x37,0x76,0x0c,0x72, - 0xe9,0x47,0xa5,0x08,0xa6,0xdf,0x23,0xae,0xca,0x4a,0x64,0xb4,0xc9,0x42,0x20,0xab, - 0x22,0xca,0xd7,0x88,0x6f,0x05,0xde,0xfd,0xdb,0x81,0x29,0xa7,0xbb,0x96,0x33,0x96, - 0xec,0xa0,0x3f,0x98,0xe5,0xfc,0x78,0xfd,0xa9,0xff,0xb6,0x05,0x18,0xcc,0xb4,0x0c, - 0xad,0x4e,0xa1,0x40,0x2e,0xc9,0x23,0x09,0x12,0xa2,0x14,0x7e,0x2b,0x9a,0xd7,0x22, - 0x4d,0xd4,0xf6,0xb6,0x99,0xe2,0xfb,0x30,0x6b,0xd5,0xc3,0x47,0x74,0x3d,0x5f,0x5d, - 0xb5,0x1d,0x1f,0xa1,0x41,0xf7,0x68,0x98,0x9f,0x7a,0x28,0xfa,0xa9,0xb6,0x18,0xf8, - 0xca,0x9a,0x33,0xd8,0x67,0x2c,0x0b,0xb6,0xe6,0x76,0x6e,0x4f,0x0d,0xe8,0x31,0xa8, - 0x36,0x8f,0xb6,0xcf,0x84,0x39,0xc2,0x02,0x6f,0x31,0xb7,0xe0,0x5f,0xd1,0x91,0x48, - 0xa7,0xff,0x47,0x48,0xf9,0x19,0x69,0xcc,0x9e,0x22,0xfe,0x47,0xa6,0x8c,0x12,0x2a, - 0x91,0xc8,0xec,0x95,0xf7,0x12,0xd1,0x0d,0xbc,0x62,0xa4,0x00,0xc8,0x89,0x68,0x1a, - 0x3f,0x58,0xf8,0x67,0xb5,0x1c,0xa1,0x4d,0x58,0x49,0x3e,0x2e,0xfb,0x12,0x68,0xf8, - 0x41,0x01,0xa6,0xbc,0x31,0xec,0x12,0x34,0x4f,0x4b,0x6d,0xf7,0xff,0x1b,0xe6,0x03, - 0x65,0x05,0x35,0x25,0x56,0xbe,0xe7,0xd6,0x4f,0x49,0x3e,0x1b,0x82,0x3a,0x99,0x50, - 0xbd,0x42,0x57,0xfb,0x66,0x50,0x06,0x5a,0xbf,0x2c,0x95,0xae,0x14,0x45,0x01,0xad, - 0x67,0x52,0xbd,0x5b,0x94,0xae,0xae,0x49,0xae,0xaa,0xd5,0x7a,0xe8,0xb6,0xbc,0xb9, - 0x0e,0x2d,0x55,0x6a,0xb1,0x59,0x94,0xa2,0x8b,0x19,0x26,0x10,0xa6,0xe3,0x7b,0x01, - 0xd3,0x67,0xb0,0xe7,0xb0,0x29,0xd8,0x5a,0xe5,0x0d,0xb3,0x03,0xe8,0x58,0xb4,0x59, - 0x1b,0x1a,0x09,0xa3,0xcc,0x86,0x9e,0xd1,0x52,0xf1,0x8d,0x36,0xfb,0x9a,0x29,0x64, - 0x2d,0xfb,0x89,0xb5,0x6d,0x55,0xaa,0x03,0xf1,0x38,0x1d,0x35,0x63,0xb2,0x92,0xb1, - 0x70,0x57,0x2a,0x25,0xe4,0x0d,0x20,0x8c,0xea,0xeb,0x18,0x91,0x2a,0xd8,0x3c,0xe4, - 0x5f,0xc7,0x71,0xf4,0x5e,0xe1,0x80,0xb1,0x88,0x1e,0xa4,0x00,0x29,0x01,0x53,0x6d, - 0x7c,0x94,0x38,0x53,0xa1,0xbe,0xe4,0x1e,0x3f,0x3c,0x44,0x18,0x1b,0x94,0x85,0x5d, - 0x9f,0xeb,0x08,0xf5,0x44,0xbf,0x91,0x44,0x8f,0x75,0x57,0x13,0x61,0x93,0x37,0x38, - 0x06,0x15,0x8e,0x97,0x06,0xb5,0x59,0x0a,0x10,0x05,0x0d,0x94,0x79,0x26,0x93,0x44, - 0x27,0x60,0xad,0x94,0x2d,0x04,0x08,0x27,0xa3,0x11,0x7a,0x44,0xcb,0x2f,0xa6,0x55, - 0x53,0x4c,0x0a,0x5a,0xf0,0x9d,0x42,0x97,0xd8,0x78,0x7b,0xa9,0x4c,0xa9,0x2d,0xa1, - 0x35,0xa0,0x3d,0x9e,0xe6,0x8f,0xb5,0xa5,0x58,0x70,0xcb,0x5b,0xe1,0x00,0x8f,0x84, - 0x92,0x2b,0x1b,0x8a,0x12,0xfc,0x26,0x82,0x00,0x42,0x13,0xfc,0x5e,0x9b,0x97,0xa4, - 0xc1,0xbc,0xf6,0x0b,0xba,0x84,0x3d,0xf3,0x80,0x43,0xc3,0x58,0xeb,0x50,0x36,0x0f, - 0x92,0x92,0xf6,0x8c,0x25,0x9a,0x5f,0x3c,0x1a,0x4b,0x76,0x7f,0x87,0x07,0xa4,0x80, - 0xf8,0x83,0x90,0x7a,0xac,0x6d,0x40,0x4a,0x99,0x79,0x1b,0xff,0xf9,0xeb,0x85,0xa1, - 0xa5,0xaa,0x1b,0x5c,0x5b,0xe2,0xea,0x4f,0x3c,0x12,0x40,0xe8,0x6e,0x23,0x94,0x0c, - 0x36,0xba,0x6d,0x6c,0xd5,0xb0,0x78,0x8d,0x02,0x33,0x88,0x10,0xd1,0xcc,0xfe,0x11, - 0x43,0xeb,0x4e,0xfa,0x34,0xa5,0x28,0x96,0x40,0x45,0x47,0xa3,0x76,0x4d,0xf3,0x56, - 0x87,0x95,0x16,0x77,0x0a,0x41,0x86,0x74,0x1c,0x17,0x2e,0x22,0xd5,0x1d,0x90,0xd1, - 0xf1,0x4d,0x50,0xb7,0xe3,0xe4,0xe4,0xac,0x82,0xbe,0x74,0x40,0x4c,0x9a,0x0f,0x40, - 0xa7,0x81,0xac,0x44,0x3f,0x4a,0x1c,0x7b,0x13,0x12,0x08,0xfb,0x4f,0x90,0x07,0x94, - 0x4e,0x69,0xd1,0xc3,0xf6,0x44,0x6b,0x1f,0x0b,0xc6,0x92,0xfa,0x92,0x85,0xff,0x40, - 0x7c,0x96,0x0b,0xfe,0x48,0x3e,0xf4,0x9a,0x90,0xf9,0x08,0xfe,0xb1,0x27,0x40,0x4f, - 0xc8,0x8f,0x62,0x1b,0x9d,0x45,0xb7,0x1f,0x60,0x0b,0x13,0x9a,0x07,0xae,0x69,0x30, - 0x90,0xab,0x49,0xa9,0x21,0xd4,0x07,0x4c,0xc1,0x09,0x05,0x41,0x55,0xa5,0x89,0x86, - 0xec,0x86,0xd2,0x54,0xac,0xcd,0xae,0x56,0x4d,0x4d,0x15,0x42,0xbf,0x51,0x53,0x35, - 0x20,0x7f,0x35,0x99,0x95,0x20,0x95,0x64,0xa5,0x12,0xa9,0x7c,0xe1,0x1d,0xa9,0x87, - 0x63,0xfa,0x46,0x8a,0xd2,0x8f,0xfd,0x46,0x41,0x31,0xc5,0x20,0xa9,0xd9,0x94,0x26, - 0x82,0xf4,0xdf,0xd6,0x73,0x1e,0xc0,0xe6,0x9b,0x5b,0x13,0x42,0xa1,0x5b,0xeb,0x76, - 0x8d,0x73,0x15,0x37,0x70,0x39,0xb9,0x52,0x5b,0xfd,0x1a,0x75,0xb1,0xd0,0x40,0x3d, - 0xa1,0x2f,0xb6,0xe7,0x65,0x8d,0xf1,0xf5,0xc6,0x46,0x73,0x5e,0x38,0x07,0xaa,0xe7, - 0x0a,0x19,0xed,0xd8,0x18,0xb4,0x71,0xa9,0x9f,0x41,0xd8,0xda,0x59,0x43,0x8d,0x9d, - 0x3a,0xed,0xab,0x75,0x47,0x14,0xf8,0xc1,0x26,0x1b,0x52,0x6b,0x95,0x6a,0x36,0x96, - 0xa0,0xa4,0xd5,0x59,0x38,0x53,0x12,0x9c,0x28,0xb1,0x22,0xb8,0x0e,0xeb,0x98,0x9f, - 0x42,0x4d,0xcc,0x08,0xf5,0x85,0x0a,0x72,0x1d,0x24,0xd1,0xa6,0xbd,0x0e,0x90,0xc3, - 0x1c,0x8e,0xb2,0x23,0x47,0x95,0x14,0xa9,0x32,0x26,0x51,0xe6,0xca,0xb4,0xc8,0x5d, - 0x9f,0xed,0x3f,0x86,0x45,0x62,0x81,0x31,0x35,0x06,0x43,0xad,0x87,0xf8,0x57,0xa8, - 0x63,0x7a,0x78,0x6a,0x43,0x0a,0x97,0x14,0xe4,0x4a,0x1b,0xb8,0x4f,0xf1,0xd2,0xb9, - 0x92,0x6a,0x1f,0x8d,0x6c,0x0d,0x9f,0xc1,0xa1,0xff,0x55,0x9e,0x4f,0x63,0xc1,0xa1, - 0x75,0x04,0xe1,0x1a,0x76,0xb3,0x64,0x51,0x8d,0x67,0x7b,0x6f,0x23,0xf4,0x7b,0xb4, - 0xa3,0x6b,0x7b,0x9e,0x4a,0x85,0x7b,0xed,0x41,0x21,0xf6,0x1c,0x3e,0x14,0x60,0x05, - 0x1b,0xd2,0x60,0xfd,0xa1,0x21,0xe4,0xb0,0xe0,0x9f,0x76,0x6c,0xc8,0x16,0xd1,0x6a, - 0x9e,0x59,0xc9,0x27,0x02,0x87,0x34,0x31,0xc4,0x1f,0x19,0x4e,0x8d,0x78,0xfd,0xe1, - 0x95,0xea,0xe2,0x0a,0x64,0x73,0xab,0x19,0x5d,0x1f,0x99,0xd1,0x35,0x4c,0x02,0xd9, - 0x8f,0xf7,0x47,0x45,0xc1,0x20,0x9d,0xf6,0x1b,0x35,0x9d,0x21,0x5e,0x05,0xbd,0x14, - 0xe2,0xd8,0x0b,0xc7,0x27,0x33,0x60,0x2c,0x9b,0xa3,0x92,0x02,0xc7,0xbd,0xf1,0x18, - 0x52,0x69,0x13,0x6a,0x4c,0x5c,0x9b,0xb8,0x69,0x22,0xb0,0x5e,0x36,0x77,0xe9,0x40, - 0xbb,0x51,0xaf,0xfd,0x4e,0xd1,0x7d,0x5b,0xcd,0x88,0x6b,0xcb,0x82,0xb1,0x3b,0xd8, - 0xce,0x57,0x27,0xeb,0xe0,0x5c,0xeb,0x48,0x95,0xbc,0x74,0xaf,0x94,0x32,0xf0,0xa8, - 0xdd,0xeb,0x58,0xbd,0xae,0xc0,0xbf,0x61,0xb5,0xe0,0x50,0x2f,0x38,0xac,0x29,0x28, - 0xcf,0xca,0x01,0x65,0x86,0x0f,0x0f,0xae,0x13,0xe0,0x4d,0x57,0xde,0x09,0x5e,0x0c, - 0x91,0x78,0x50,0x9c,0xd4,0x1c,0x15,0xfc,0xb9,0xb6,0x96,0x3c,0x3e,0x3c,0x09,0xd4, - 0x8f,0x09,0xa5,0x5f,0x46,0x34,0xbe,0x1f,0x60,0x96,0x1e,0x67,0xe3,0x43,0x70,0x06, - 0xd1,0xc6,0x06,0xfd,0x38,0x6c,0x62,0x60,0xa1,0x6f,0xb6,0x1e,0x22,0x36,0x14,0x90, - 0xcb,0x3f,0x50,0x84,0xd4,0x3c,0xdd,0x22,0xef,0x16,0x2e,0x2d,0x94,0x9e,0x50,0x77, - 0x01,0xc6,0x9c,0x51,0x9c,0x2f,0xa0,0x60,0xb7,0xb1,0xf1,0x8d,0x56,0x4a,0x29,0xe5, - 0x3f,0x0a,0x69,0x2f,0x8b,0xd8,0x8f,0xd0,0x52,0x5a,0x47,0x1c,0x04,0xfb,0x82,0x2b, - 0x77,0xea,0xbe,0xa8,0x01,0x13,0xd9,0x3d,0x3c,0x3f,0x48,0x20,0xcf,0x93,0x92,0xd7, - 0x49,0x43,0xf3,0x35,0x10,0xd6,0x03,0xec,0x12,0x5e,0x39,0x22,0x88,0xa3,0x20,0x38, - 0xf3,0x52,0xf4,0x6b,0x19,0x0d,0xed,0x36,0xfc,0x0f,0x2b,0xb0,0xa9,0x11,0x5b,0x0c, - 0x06,0x3d,0x3a,0x9e,0x70,0x71,0x1a,0x14,0x5d,0x9c,0xea,0x3a,0xc6,0xaa,0x55,0x12, - 0xf6,0xac,0xd1,0x90,0x14,0xe4,0xb6,0x30,0xaa,0x92,0x23,0xa7,0x1a,0xb5,0x90,0x00, - 0xed,0x87,0x07,0xfd,0xbd,0xb3,0x83,0x6a,0x8a,0xb5,0xd5,0x73,0x15,0x30,0x13,0xac, - 0xd0,0x78,0xda,0x72,0xa1,0xb4,0x7f,0x41,0x33,0x5c,0x5c,0xa3,0x32,0x1c,0x33,0x45, - 0x0d,0xf5,0xe1,0xc1,0x4c,0x3c,0xbe,0xb6,0xc3,0x54,0x7b,0x69,0xed,0xb0,0x68,0x0f, - 0xe2,0xe9,0x6e,0xea,0xc5,0x29,0xd0,0x5b,0x5e,0xc7,0x16,0xf7,0xf8,0xc8,0xec,0x01, - 0xb9,0xa0,0x47,0xb4,0x4b,0x52,0x7a,0x3d,0x51,0x7d,0x01,0x30,0xaf,0x24,0xf8,0x19, - 0x25,0x06,0x8c,0x14,0xcf,0x9b,0x4d,0x05,0xed,0xa7,0x21,0xb9,0x76,0x48,0xe6,0x71, - 0xc8,0x3e,0xb8,0xcc,0x2c,0xa0,0x75,0xce,0xd0,0x43,0x8c,0x96,0x66,0x3e,0xc2,0x81, - 0x8d,0xa3,0x8a,0x04,0xf7,0x66,0x61,0x44,0xd5,0x9e,0x32,0x98,0x8b,0x5d,0x2d,0x2b, - 0x25,0x54,0xb4,0x3c,0xc1,0x13,0xc1,0x12,0x15,0x9b,0xc5,0xa0,0xb2,0x92,0x25,0xb1, - 0xab,0xae,0xe5,0x5c,0xe7,0x41,0xa4,0xeb,0x76,0xfc,0x26,0x49,0x06,0xee,0x78,0xee, - 0x87,0xa7,0xf4,0x0c,0xd3,0xae,0xd5,0xcc,0x6c,0x01,0xe7,0x22,0xfc,0xab,0xf7,0xf7, - 0xe6,0x33,0x4b,0x32,0xee,0xc3,0x2d,0x1f,0x37,0x0d,0x86,0x93,0x28,0xa9,0x0f,0x5e, - 0x27,0xdd,0xe5,0x08,0x0e,0x3a,0x58,0x60,0xc7,0x48,0x6d,0xbc,0xd7,0x36,0xb5,0x5d, - 0xb2,0x17,0x14,0xd0,0x21,0x47,0xb5,0x8c,0xcc,0xe8,0x30,0xcb,0x00,0xff,0xa0,0xed, - 0x26,0x65,0x1d,0xd0,0x5f,0x32,0x9a,0xcd,0x0f,0x25,0x5c,0x1f,0x0f,0x0b,0xbf,0x6a, - 0xc6,0xa9,0xc5,0xc2,0x8c,0xbb,0x6c,0x81,0x8c,0x33,0x30,0xb6,0x71,0xfc,0xec,0xdc, - 0x2d,0xae,0x5c,0x32,0x6e,0xdd,0xd4,0x80,0xcd,0x37,0xa3,0x89,0x67,0xc5,0x68,0x84, - 0xf1,0x5e,0xfc,0xc9,0x3d,0xec,0x7e,0x84,0xf4,0xca,0xb5,0x91,0x76,0x7f,0x3d,0x3a, - 0xb9,0xb0,0x03,0x4b,0xd0,0x00,0xa6,0x51,0x36,0x7d,0xda,0x4e,0x08,0x24,0x47,0x8c, - 0xed,0xb0,0x48,0x42,0xbc,0x95,0xe9,0x97,0xb3,0x77,0xb8,0x57,0xc0,0x96,0x02,0x7b, - 0x30,0x2f,0x00,0x7b,0x29,0x62,0x91,0xf4,0x80,0x78,0xb4,0x1f,0x57,0x86,0x1d,0xa1, - 0xdc,0xdf,0xa8,0x65,0xc3,0xe0,0xd1,0xc9,0x10,0xfb,0xb4,0x11,0x59,0xc3,0x0d,0x18, - 0xfd,0x50,0x68,0xdb,0xa9,0x89,0x87,0x52,0xc6,0x64,0x9e,0x2f,0x7d,0xdd,0xa9,0xe9, - 0x7a,0xb4,0x77,0xd1,0xae,0xb4,0xda,0x0e,0x8a,0x05,0x63,0x92,0x90,0xa8,0x83,0x54, - 0xc5,0xeb,0xdd,0xe7,0xb5,0x98,0x23,0xc9,0x56,0x67,0x05,0x9a,0x3c,0xda,0x2f,0xf5, - 0x76,0x0b,0xc3,0x45,0xf4,0x7b,0x02,0x2f,0x28,0x94,0x04,0x94,0x49,0x07,0x6d,0x9b, - 0xd0,0x9c,0x23,0x85,0xc9,0xcf,0x04,0x4f,0xec,0x0d,0x7b,0x72,0xd5,0x38,0x97,0xca, - 0x73,0xbf,0xe8,0x7a,0xb0,0xfd,0xaf,0x4f,0x3f,0x6f,0xfb,0xcc,0x20,0xf8,0x19,0x45, - 0x35,0x12,0xc6,0x39,0xdf,0x44,0xd7,0x16,0xb5,0xb2,0xb5,0xc5,0xef,0xa3,0xe1,0xc6, - 0x06,0x46,0x5a,0x51,0xe3,0x00,0xe1,0xc2,0xa7,0x6d,0x96,0x56,0xb1,0x1a,0x1d,0xe4, - 0x90,0x5c,0x00,0x7f,0x46,0x56,0x43,0x7d,0x96,0x69,0x56,0xd9,0xb0,0x48,0xa4,0x53, - 0x5b,0xfc,0x8c,0xb3,0xcd,0xcb,0x98,0xa7,0x61,0x9b,0xb7,0xec,0x4a,0x77,0x2d,0x1d, - 0x08,0xbc,0xdf,0x3e,0x4a,0xe1,0x68,0x45,0x3c,0xab,0x4d,0x36,0x2a,0x30,0x34,0x35, - 0x24,0xb7,0x29,0x34,0x00,0xc2,0x9e,0xa9,0xc8,0xdb,0x22,0xe7,0xf8,0xe9,0x67,0xb3, - 0x27,0x1b,0xce,0x63,0x40,0xfd,0x0b,0x28,0x4a,0x33,0x4a,0xac,0xa3,0xcb,0x9e,0x7d, - 0x75,0xf4,0x7b,0xfa,0xdd,0xb6,0x6f,0xf3,0x9e,0xf1,0x28,0x4d,0x3d,0x29,0xf8,0xc1, - 0xad,0x9b,0x84,0xeb,0xcc,0x7c,0xb5,0x81,0x58,0x72,0xfd,0x03,0x73,0x8e,0x8e,0x58, - 0x1a,0x92,0xd2,0xac,0x58,0x4c,0x03,0x78,0x86,0x4c,0x64,0x88,0x32,0x8e,0x4c,0xa5, - 0x76,0x32,0x58,0xd6,0xa9,0x07,0x6b,0x9c,0x44,0x32,0x53,0x3b,0xa4,0x4d,0x14,0xef, - 0xd3,0x28,0xd8,0x26,0xa2,0x4c,0x2a,0x42,0xa0,0x27,0xe4,0x41,0xf8,0xd9,0x8f,0xd1, - 0x90,0xf4,0x42,0xde,0x44,0x80,0x47,0x5c,0xde,0xb8,0x68,0xe3,0x89,0x31,0x26,0x1c, - 0xe3,0x42,0x5d,0x62,0x80,0x84,0x43,0x84,0x87,0xc3,0xd3,0x93,0x7b,0xe3,0x86,0x6d, - 0x2d,0x8c,0x5b,0x60,0x9a,0x29,0xa0,0x20,0x37,0x9e,0x3a,0xc6,0x99,0x27,0x08,0x0e, - 0x47,0x9c,0x88,0xd1,0xe2,0x05,0xe3,0x33,0x06,0x6e,0x0c,0x32,0x3d,0x9f,0xd9,0xb8, - 0x99,0x0c,0x60,0x61,0x63,0xbb,0xa1,0x81,0xe1,0xf9,0xf9,0x72,0x24,0x6e,0x84,0xed, - 0x52,0x55,0x17,0xc9,0x26,0x95,0x42,0x1a,0xe2,0xd6,0x47,0xb7,0x2b,0x52,0x77,0x91, - 0x46,0x72,0x3c,0x0c,0x01,0xa9,0x42,0xfb,0xa5,0xa6,0x68,0x10,0xaa,0x21,0xaa,0x17, - 0x3e,0xa2,0xaf,0x26,0xdf,0xa9,0xd0,0x82,0xe9,0xf3,0xa7,0x64,0x21,0x2b,0x3b,0x61, - 0x37,0x78,0xbf,0x34,0xcf,0x45,0xf5,0xa2,0xc9,0xcb,0x4f,0x3f,0x5f,0x11,0x01,0x16, - 0xb1,0xfc,0x4c,0x5b,0x81,0xd6,0xe6,0xc4,0x73,0xec,0xc5,0x18,0xfd,0x11,0xf4,0x3d, - 0x49,0xdf,0xd8,0xcf,0x55,0x4d,0xa6,0xb0,0x45,0x64,0x0b,0x93,0xf3,0x68,0x92,0xb1, - 0x5d,0xdf,0x57,0xb0,0x83,0x55,0xda,0xba,0x8e,0xc5,0x6b,0xef,0xd6,0x96,0x00,0x12, - 0xf7,0xba,0xdb,0x7e,0x3e,0x3d,0x04,0x4a,0xb8,0x6e,0xdb,0xac,0xa7,0x87,0x65,0x66, - 0xa3,0x3c,0xf0,0xa5,0xf0,0x5b,0xc7,0x63,0x00,0x83,0x7d,0xcd,0xe4,0x75,0xae,0xb7, - 0x22,0x5c,0x28,0x08,0x9f,0xc3,0xa1,0x47,0xe7,0x72,0x4c,0x12,0x49,0x5a,0x4d,0x1b, - 0x5f,0x67,0xcb,0xfb,0xa7,0x6d,0x6e,0x29,0x94,0xd8,0x78,0x85,0xe1,0x2d,0x7f,0x64, - 0x61,0xa8,0x78,0xf6,0xa3,0x11,0xd0,0xeb,0x2b,0xb2,0x33,0xc3,0x9c,0x04,0x6d,0x36, - 0xd4,0xd5,0x3e,0x97,0x6c,0x57,0x29,0x46,0x80,0x34,0x5c,0xe5,0xd8,0x08,0x55,0x03, - 0xce,0xbe,0x56,0x11,0xd5,0xbc,0xde,0xfe,0xb5,0x21,0x63,0xfe,0x34,0xb5,0x7b,0x2b, - 0xf4,0xfe,0x5a,0x7f,0xca,0x80,0x97,0x03,0x2b,0x62,0xfb,0x67,0x64,0x42,0x7b,0x29, - 0x6c,0x6b,0xc9,0x52,0xdb,0x96,0x2f,0xc3,0x5b,0xf5,0x98,0x4e,0xd4,0xe3,0x28,0xb9, - 0xd2,0xcd,0x28,0x8a,0xb6,0xb8,0x5a,0xa5,0xe2,0x60,0xca,0xf3,0x62,0x6e,0xa3,0xd6, - 0x94,0x0d,0x04,0x42,0x69,0x1b,0x27,0xd3,0x84,0x7b,0xb5,0x56,0x93,0x00,0x81,0xaa, - 0xaa,0xbc,0x7d,0x71,0x09,0x6e,0x8f,0x1e,0x4f,0x49,0x03,0xd4,0x54,0x05,0x8e,0x8a, - 0x39,0x7b,0x7a,0xdd,0x9a,0x9d,0xce,0x33,0x0d,0x9b,0xf9,0xb8,0x77,0x7c,0x37,0x58, - 0x22,0xb4,0x7a,0x6d,0x7b,0x78,0xdb,0xeb,0xd8,0xe9,0xa4,0xd7,0xb5,0x47,0x49,0x6f, - 0xe7,0xb1,0x64,0xe1,0x8c,0xb4,0x5f,0x00,0x3f,0xef,0xdc,0x25,0x94,0xbf,0xea,0xaf, - 0x35,0xd9,0x55,0xa3,0x15,0x3a,0x9f,0xff,0x49,0x73,0xe6,0x75,0x36,0xc2,0xb5,0x7e, - 0xf8,0x45,0xe7,0x3e,0x15,0xa5,0x60,0xd9,0x50,0xd1,0x28,0xc8,0xac,0x50,0xa7,0xa8, - 0xcd,0x3a,0x4a,0x5a,0x1f,0x3a,0x44,0xd0,0xe6,0xb7,0xcc,0x41,0x67,0x11,0x91,0x27, - 0x43,0x92,0x93,0xba,0xd6,0x4f,0x38,0x52,0x0b,0xf6,0x20,0xef,0x4d,0xbf,0xf1,0x44, - 0xc8,0xac,0x5c,0x7c,0x61,0xbe,0x10,0xb3,0xd6,0x86,0xcb,0xf8,0x1a,0xcd,0x66,0x53, - 0x5a,0x69,0xb0,0x46,0x2e,0xd7,0xc7,0x7d,0x2b,0x9b,0x30,0x64,0x86,0x2a,0xfe,0xdd, - 0x59,0xcb,0xbb,0x1a,0x9c,0x81,0xcc,0xf6,0x1d,0xec,0x19,0x43,0x1a,0xfc,0xa5,0x34, - 0x80,0xe5,0x33,0x61,0x9b,0x44,0x3e,0xf8,0xe1,0x5b,0x4c,0x6c,0x1e,0x5d,0xb5,0xee, - 0x8c,0x85,0xa2,0xac,0x65,0x6e,0x65,0xab,0xf9,0xa4,0x0c,0xa6,0x21,0xd7,0xad,0x66, - 0xd2,0xfb,0x46,0x4b,0xa2,0x80,0x32,0xd4,0x94,0xc5,0x41,0xce,0xf1,0xb9,0x29,0xa4, - 0x27,0x58,0x7a,0xb1,0x4c,0x58,0x19,0x28,0x45,0xb6,0x28,0x03,0xa5,0xd8,0xa5,0xda, - 0x39,0x78,0x4a,0x4d,0xb3,0xf4,0x81,0x27,0x3c,0xf0,0x9b,0x65,0x6d,0xe9,0x64,0x9e, - 0xfd,0x12,0x63,0xf0,0x28,0x3a,0xf9,0xd1,0x43,0xe3,0xa5,0xdb,0x07,0xfb,0x28,0x8e, - 0xd8,0xb3,0x42,0xea,0x7f,0x50,0xea,0xf6,0x0e,0x86,0x25,0xb5,0xe7,0xc5,0x4f,0x98, - 0xb8,0xbd,0xdf,0xce,0xcd,0xcb,0xc6,0x87,0xed,0xa3,0xf1,0x96,0x39,0x36,0xcc,0xad, - 0xd9,0x96,0x39,0x33,0x7b,0xcd,0x19,0xa4,0xe0,0x23,0xa4,0xcc,0xb7,0xcc,0xb9,0xd9, - 0xa3,0xbf,0x85,0xe8,0xab,0x80,0xc0,0x4d,0xdf,0x1e,0xda,0x2a,0xca,0xe9,0x66,0xf9, - 0x32,0x17,0xb4,0xa0,0x3a,0x14,0xe7,0xbb,0x3e,0x1e,0xf8,0x6e,0x6e,0x0d,0xf9,0xac, - 0x77,0x73,0xab,0x99,0x1e,0x6d,0x1a,0xaf,0x53,0x78,0xe2,0x23,0xda,0x92,0x69,0x97, - 0xae,0x20,0xd5,0x26,0x62,0xa9,0xcf,0x01,0xf2,0x0b,0xf2,0x39,0x65,0x37,0x70,0x0e, - 0x6c,0x8b,0xe1,0x5b,0xdf,0x09,0x07,0xe6,0xa6,0xca,0x65,0xef,0xb4,0x8b,0x21,0x5a, - 0xb5,0xba,0x96,0xec,0x5f,0x93,0x57,0x01,0xec,0x33,0x5a,0xe6,0xa8,0x5a,0x8a,0x1f, - 0x4b,0xcd,0xb5,0x1f,0x4b,0xa2,0xbf,0xac,0xb5,0x14,0x0e,0xac,0x3e,0x1a,0x18,0x45, - 0x7b,0xaa,0x11,0x53,0x39,0x1c,0x9c,0xbc,0x7f,0xa7,0x12,0xb1,0x24,0x40,0x46,0x1a, - 0xed,0x83,0x1c,0xc7,0x2c,0xea,0x82,0x56,0x95,0x11,0xa7,0x03,0xd7,0xc3,0x81,0xe6, - 0x92,0x90,0x3a,0x18,0xfd,0xf7,0x33,0x50,0x57,0x6f,0x1b,0xef,0x83,0x92,0xc1,0xec, - 0xe8,0x02,0x1e,0x3d,0x86,0x5a,0x83,0x26,0xdc,0xfc,0x25,0x46,0xd1,0x1c,0xe8,0x05, - 0x23,0xa4,0xb3,0x88,0x39,0xa2,0x97,0x65,0x6d,0x89,0x1c,0xdf,0xf3,0x0d,0x4d,0xa6, - 0x0d,0x5f,0xf1,0xb6,0xa6,0xcf,0xf3,0x9b,0x6d,0x74,0x7c,0x80,0xde,0x44,0x6f,0xfd, - 0x3b,0x6f,0xdc,0xec,0x5a,0xb6,0xf9,0x0f,0x53,0x15,0x50,0x17,0xf8,0xc0,0xce,0x31, - 0xb4,0xcd,0x9f,0xbf,0x37,0xbe,0xc3,0xcb,0xe9,0x00,0xf5,0xaa,0xfd,0x84,0x74,0xee, - 0xa6,0x2a,0x4d,0x37,0xcc,0x07,0x41,0x34,0x32,0xed,0x9a,0xec,0x18,0xd0,0x01,0x3f, - 0x72,0x21,0xac,0x3c,0x6f,0x57,0xbb,0xf3,0xc7,0xb4,0x53,0x87,0xa2,0x1f,0xdb,0xe6, - 0xf8,0xfb,0x79,0x9e,0xe5,0x3d,0x10,0x6b,0xe3,0xec,0xfc,0xfc,0x1d,0x66,0x48,0x80, - 0x7b,0xa7,0xef,0xd0,0xbf,0xf3,0x8f,0x67,0x14,0xe1,0x2b,0x0d,0x13,0x95,0xf9,0x18, - 0x76,0x3f,0xbc,0x34,0xf1,0xe2,0xb7,0x1c,0x3c,0x2e,0xa7,0xe9,0xf0,0x91,0xd9,0xce, - 0xb4,0x6c,0x09,0x74,0xb3,0x9a,0xf3,0x54,0xdc,0xcb,0x89,0x39,0x21,0x8f,0x37,0xba, - 0xb1,0xf1,0xf4,0x81,0x1a,0x86,0x12,0xf0,0x58,0xc9,0x7a,0x41,0x59,0x53,0x98,0xef, - 0x1c,0xbc,0x74,0xa5,0xf9,0xd9,0x6f,0xdb,0x17,0xaa,0x9a,0xcf,0x14,0x11,0x02,0xc4, - 0xbf,0x6d,0x1e,0x04,0x64,0xe7,0x24,0x55,0xe8,0x07,0x1f,0x2d,0x36,0x4b,0xa5,0xc6, - 0x94,0x58,0x2c,0xc6,0x69,0xaa,0xdc,0xc5,0x6f,0x06,0x48,0xcc,0x0b,0x0f,0xcb,0x64, - 0x77,0x9f,0xe9,0x19,0x3e,0x6a,0xce,0x6b,0x47,0x62,0xda,0xf0,0xe2,0x23,0x95,0x15, - 0x89,0xbd,0xc8,0x4c,0x81,0x39,0x45,0x6d,0x24,0x78,0x49,0xf0,0x93,0xf8,0xa3,0xe6, - 0x20,0xcf,0xf4,0xee,0x14,0xbf,0xfa,0xf1,0xc3,0x83,0xd9,0x42,0xd2,0x4a,0xb6,0xb3, - 0xd8,0x1e,0x92,0x63,0xc4,0x02,0xc0,0x2a,0x20,0x16,0x7a,0x2a,0x4f,0xb5,0x98,0x72, - 0x64,0x04,0xf1,0x6e,0x27,0xe2,0x28,0xb4,0xdb,0xa2,0x2c,0x5b,0xaf,0x04,0xd6,0x7c, - 0x29,0x13,0x5f,0x05,0x95,0xe7,0x92,0x95,0x95,0x5c,0xf5,0x98,0x61,0x0d,0x06,0x69, - 0x1e,0x25,0xa7,0xaf,0xd6,0xa9,0x64,0x5f,0xb4,0x75,0x96,0x06,0xe2,0xd0,0xe1,0x08, - 0x9e,0x0a,0xb6,0xaa,0x77,0x32,0x9c,0xf3,0xa0,0x79,0x47,0x86,0x52,0x6c,0x10,0x6e, - 0xa1,0x45,0x78,0x81,0xf6,0x5e,0xdf,0x10,0xe5,0x65,0xa2,0x5b,0x08,0xa4,0x2e,0xc2, - 0x9e,0xc3,0xce,0x50,0x73,0x89,0x82,0x38,0xdf,0x36,0x36,0x1b,0x64,0x29,0x24,0xdb, - 0x60,0x9b,0x36,0xbc,0xb0,0xad,0x6c,0xd9,0x66,0x15,0x4c,0xdb,0x38,0xbf,0x65,0x15, - 0xac,0x79,0xc4,0x91,0x1b,0x86,0x55,0x4f,0xb1,0xdb,0xd1,0x35,0x77,0xfa,0xe1,0xe1, - 0x0e,0x03,0x3a,0x69,0x23,0x40,0xef,0x60,0xfc,0x0e,0xe8,0x15,0x5d,0x13,0x86,0x51, - 0x0e,0x78,0xc5,0x03,0xb7,0x5a,0xeb,0x58,0x31,0x4e,0x61,0x46,0x74,0xe7,0x84,0x22, - 0xf0,0x1e,0xf7,0x5e,0xd9,0x39,0xd1,0xd6,0x53,0xb4,0x10,0xc5,0x1b,0x13,0x37,0x45, - 0x3e,0x22,0xbd,0x9a,0x85,0x54,0x9e,0x22,0x2c,0x48,0x37,0xb7,0xb8,0xff,0x85,0x81, - 0x6d,0x4d,0x0a,0xd6,0xbb,0x3d,0xa0,0x26,0xf2,0x1e,0x2f,0x15,0x2b,0x53,0xba,0xab, - 0x3e,0x83,0xcf,0x24,0xf4,0x74,0x31,0xca,0x83,0xcb,0xc6,0xdf,0x37,0xc4,0x62,0xb9, - 0x02,0x17,0x0e,0x61,0xb7,0x76,0x9d,0x74,0xe6,0xa3,0x00,0xab,0x6f,0x61,0x84,0x93, - 0x40,0x17,0x90,0x95,0x10,0xe8,0x31,0x8e,0x93,0x81,0x88,0xcc,0xcb,0x36,0x3a,0xa7, - 0x40,0x74,0x83,0x33,0x54,0xee,0x3e,0x3c,0x74,0x30,0xcc,0xd3,0x0d,0x32,0x87,0xb0, - 0x78,0x7f,0x45,0xe7,0x5a,0xe0,0x1b,0xf6,0xf6,0xfb,0x0d,0x48,0x24,0x5f,0xdb,0xc1, - 0xed,0x77,0x50,0x41,0x1f,0x5e,0xc5,0x1d,0x67,0x33,0x7a,0xa7,0x9a,0xa7,0x58,0x74, - 0xea,0xf1,0x8e,0x02,0x33,0x6e,0x76,0xf1,0xe8,0x64,0xea,0xa4,0x78,0xde,0xd7,0x84, - 0x6c,0x36,0xfc,0xc3,0x04,0xda,0x3b,0xcf,0x80,0x2e,0x34,0xf1,0x44,0xe0,0xd6,0x9e, - 0xf1,0xb2,0xc0,0x4e,0x8a,0x01,0xbd,0xee,0x16,0xcd,0x44,0x43,0xde,0x93,0x80,0xbc, - 0x3b,0x14,0x78,0x90,0x75,0xd7,0x34,0x2a,0x7b,0x7e,0x27,0x3e,0x62,0xfc,0x9e,0xd2, - 0x47,0x36,0xbc,0x47,0xfe,0x71,0x1e,0x5a,0xcb,0xf9,0xdd,0x16,0x88,0x18,0xf3,0xb0, - 0x35,0xe8,0x3c,0x36,0xa6,0x18,0x3b,0x2d,0xba,0xf6,0xce,0x09,0xff,0xa9,0xdb,0xf3, - 0x78,0x91,0x79,0x63,0x4a,0xc8,0xa3,0xcc,0xcb,0x07,0x71,0x0c,0x6c,0xe1,0x08,0x4f, - 0x93,0x28,0xf6,0x40,0x96,0xe1,0xf8,0x18,0x66,0xab,0xe5,0x8e,0x46,0xa6,0xf4,0xb8, - 0x00,0x42,0xf3,0xa2,0x3b,0x7c,0x39,0xf6,0x5e,0xc1,0xec,0x4e,0x1d,0xbc,0x26,0x85, - 0x20,0x39,0xe8,0xf6,0xf9,0xed,0x3f,0x23,0xbc,0x5a,0x95,0x36,0x22,0x13,0x92,0x86, - 0xde,0xd4,0x0f,0x4f,0x61,0x04,0xc4,0x37,0x22,0x0c,0x2a,0xfc,0xeb,0x8d,0x2d,0xad, - 0xd5,0xef,0x06,0xfe,0xb6,0x0e,0xa8,0x56,0xc7,0xfa,0xae,0x79,0xdb,0xda,0xb5,0xb6, - 0xba,0xf6,0xfd,0x60,0xd6,0xda,0x6d,0x35,0x6f,0x5a,0x30,0xd6,0x6d,0x18,0x35,0xfe, - 0x7e,0xd7,0x84,0x2c,0xc8,0xca,0xf9,0x47,0xdc,0xf8,0x45,0xd4,0xbc,0xb3,0xef,0xad, - 0xde,0xd4,0x41,0x71,0x5c,0xbc,0x31,0x37,0x29,0x21,0xd2,0xa4,0x67,0x58,0xad,0x81, - 0x80,0x8d,0x0e,0x29,0xe8,0x30,0x92,0x0a,0xbc,0x1d,0x32,0xbe,0x33,0xd2,0x7b,0x90, - 0x13,0xe6,0xad,0x85,0x8f,0x03,0xc1,0x49,0x3f,0xc6,0x4b,0x3a,0x60,0x70,0x88,0x1b, - 0xa6,0xac,0x86,0xd6,0x3f,0x76,0xfa,0xb2,0xd0,0xf3,0x2b,0xfb,0xb6,0xd5,0x65,0x47, - 0x0f,0x0d,0x67,0xd1,0x53,0xed,0x67,0xef,0x9e,0x62,0x63,0x36,0x59,0xbe,0xc8,0x8d, - 0x52,0xf8,0x7d,0x63,0x63,0xd5,0xc5,0x1e,0x22,0x7f,0x5f,0xf9,0x8d,0x0e,0x83,0x45, - 0x22,0x4f,0xf6,0x5d,0x2f,0xd7,0xdb,0x72,0xe8,0x51,0x51,0x94,0xb0,0xc4,0xf5,0x36, - 0x36,0x5c,0x94,0xc4,0x0a,0xac,0x3b,0xa6,0x51,0x25,0x96,0xf8,0x2d,0x9d,0xe4,0xa8, - 0x6b,0x3d,0x55,0x4f,0x91,0xf7,0x53,0xd7,0x23,0x0c,0xa4,0xcb,0x65,0x59,0x6f,0x5c, - 0xdf,0x6f,0x9b,0xae,0x76,0x22,0x9f,0x3e,0xed,0xa6,0x27,0x19,0xe6,0x79,0xe0,0x05, - 0x1b,0x1b,0x15,0xdb,0x07,0x52,0xdd,0x6e,0x6c,0x4c,0x1c,0x3c,0x4e,0x0f,0xb3,0x8f, - 0xd1,0xd8,0xb3,0xf4,0x17,0xd8,0x3b,0x80,0xf0,0x64,0xdf,0x7b,0x80,0x55,0x5e,0x93, - 0x6a,0xb4,0xd1,0x5e,0xeb,0x2e,0x3b,0xf7,0x87,0x80,0x11,0x53,0x32,0xcb,0x08,0x6b, - 0x75,0x35,0x2a,0xec,0x63,0xcd,0x9c,0xac,0x0a,0x1c,0x5f,0x97,0xf7,0xd1,0xee,0xec, - 0xb5,0x49,0xa3,0x22,0x6f,0x86,0xe2,0x83,0x46,0x3d,0xa6,0x5d,0x7e,0x79,0xd3,0xb2, - 0x3c,0xfe,0x15,0x31,0x48,0x0b,0xb7,0x33,0x48,0xb0,0x13,0x03,0x5e,0x11,0x0f,0xa8, - 0xc9,0x28,0x19,0x79,0xf2,0x68,0x59,0xdd,0xff,0xa4,0xef,0xad,0x9b,0x7f,0xe7,0x5d, - 0x50,0x9b,0x7d,0x3a,0xfd,0xcc,0x9b,0x3e,0x12,0x9c,0x3e,0x24,0x1c,0x25,0x74,0x23, - 0xd6,0xa0,0x03,0xfb,0x9a,0x4a,0x2c,0x79,0xee,0x0c,0xdd,0x24,0x6d,0x22,0x3f,0xc3, - 0x42,0x5d,0x38,0xc0,0xe7,0xc3,0xd6,0xde,0xde,0xd1,0x6e,0x8f,0x1f,0xf7,0x5f,0x1e, - 0xed,0x88,0xc7,0x97,0x07,0x47,0xdd,0x5e,0x87,0x1c,0xe6,0xa3,0x3a,0x2b,0xe3,0x5d, - 0xd2,0xa5,0x44,0x68,0x8f,0xab,0x5f,0x9c,0x34,0xf6,0xd3,0x38,0x70,0xef,0x7b,0x7e, - 0x48,0x97,0x39,0x0d,0xf1,0x02,0x9e,0xbe,0xb8,0x70,0x26,0xbe,0x93,0x97,0xec,0x24, - 0x7c,0xc5,0x13,0x24,0x0c,0xa3,0x64,0xec,0x25,0x14,0x72,0x79,0x91,0x52,0x8a,0xb8, - 0x92,0x06,0x04,0xb6,0x9d,0x2d,0xff,0xbb,0x1d,0xd8,0x15,0x31,0x1b,0x70,0x9b,0x53, - 0xa2,0x6f,0xf8,0x01,0x9a,0x0f,0x8f,0x4c,0xe6,0x24,0x80,0x4e,0x02,0x57,0x20,0x5e, - 0xb0,0x4d,0xcb,0xa4,0xad,0x55,0x6e,0xa5,0xf9,0x3e,0xbe,0xa6,0x9b,0x78,0x8d,0x59, - 0x9f,0x66,0xa6,0xe5,0x03,0xf5,0x49,0x7b,0x98,0xd0,0x02,0xc1,0x48,0xf6,0x06,0xaf, - 0xa7,0x22,0x03,0xdf,0x2d,0x53,0x54,0x6c,0x96,0x25,0x30,0x9c,0x95,0x45,0x12,0x08, - 0x19,0x0c,0x9f,0xd6,0xdd,0x5d,0xc0,0x91,0x64,0xa1,0x4c,0x28,0x8e,0x08,0x35,0x64, - 0x1b,0xac,0xd6,0x56,0x53,0x2b,0xfa,0x04,0xd3,0x3a,0x68,0x17,0x6d,0x40,0x42,0x0c, - 0x61,0x0b,0xed,0xc8,0x1b,0xdb,0xc4,0xe9,0x1a,0x31,0x4e,0x79,0x85,0xa1,0x0a,0xd5, - 0x19,0xd2,0xe1,0x37,0xd2,0x6b,0x2c,0x59,0x67,0xe3,0x23,0x32,0x0e,0x49,0x22,0x69, - 0xb9,0xf4,0xa3,0x54,0xa3,0x9e,0x17,0xe2,0xa9,0x0c,0xb5,0x4a,0x15,0xd4,0xb4,0x84, - 0x2c,0x2a,0xe4,0xbb,0xe4,0xa6,0xae,0x2c,0xfd,0x2a,0xa4,0xbe,0xfe,0x05,0x90,0x4b, - 0x7c,0xc3,0xf3,0x31,0x79,0x28,0x55,0xbf,0xb8,0xa8,0x31,0xc1,0xba,0xd2,0x73,0x81, - 0x79,0x0d,0x35,0x47,0xab,0x75,0x7e,0x3f,0xa1,0xa7,0x2c,0xc8,0x53,0x3c,0x24,0x66, - 0x9e,0x8c,0xbb,0x23,0x98,0x34,0x5a,0x38,0x21,0x8d,0xda,0x2a,0xfb,0xfe,0xa4,0xa9, - 0x64,0xe3,0x64,0x11,0x85,0x21,0x5b,0x90,0xe4,0x85,0xa3,0x23,0x73,0xe3,0x45,0xa7, - 0x7b,0xd0,0x7d,0xb9,0xdb,0xe7,0x4b,0x00,0xcc,0xd7,0xe9,0x1c,0x64,0x44,0xc8,0xc0, - 0x75,0x52,0x09,0x4a,0x51,0x2e,0x46,0x66,0x91,0xd7,0xdb,0xcc,0xef,0x1a,0xaa,0xdc, - 0x9d,0x54,0xbc,0x27,0x15,0x98,0x42,0x39,0xed,0xc6,0x04,0xd7,0x8b,0x83,0x57,0x0b, - 0x6d,0xd6,0xab,0x1e,0xd7,0xd1,0xad,0xe7,0x36,0x88,0x18,0x29,0x8e,0xe7,0xb9,0xa9, - 0x47,0xa5,0x01,0xd4,0xab,0xfe,0xab,0x6a,0x40,0x44,0xe6,0x8a,0x12,0xf0,0x89,0x2d, - 0xb0,0xb0,0x6f,0x5a,0x9a,0x6a,0x39,0x57,0x84,0x51,0x78,0x41,0xfc,0x80,0x04,0x01, - 0xc1,0x43,0x9d,0x6c,0xd2,0x65,0x1c,0xf4,0x24,0x03,0x20,0x2c,0x87,0x8b,0xe1,0x30, - 0xf0,0xd2,0x1e,0xa3,0x25,0xda,0xec,0xe5,0xdb,0x4b,0xee,0x5a,0x52,0x70,0x71,0x1f, - 0x5c,0x36,0x96,0x59,0xcf,0xfc,0xe5,0xfc,0x78,0xfb,0xc4,0x0d,0xdd,0xb1,0x6b,0x34, - 0xf1,0x24,0x6f,0x0e,0x1d,0x24,0x59,0xc6,0x9e,0xf4,0xcc,0x57,0x9d,0xb6,0xb3,0xd7, - 0xdd,0x33,0x51,0x2f,0x6e,0xee,0x77,0x1d,0x78,0x4a,0x21,0xf9,0xa5,0x89,0xea,0x71, - 0x73,0x0f,0x43,0xf3,0x62,0x1d,0xc7,0x0b,0x60,0x98,0x80,0x40,0xb9,0xa2,0xd0,0x9e, - 0x73,0xd0,0x6e,0x73,0xa1,0xee,0x5e,0x9b,0xcb,0x74,0xda,0xab,0x0a,0x19,0xcd,0x8f, - 0x6e,0x92,0x44,0xb7,0xb2,0xc9,0x7d,0x67,0xef,0xe5,0xaa,0x26,0x0f,0x6a,0x4a,0x7f, - 0xf0,0x55,0x6f,0xf7,0x9c,0xb6,0x2c,0xda,0xe9,0x8a,0x92,0xaf,0x56,0xb5,0xdb,0x33, - 0xce,0x8f,0x6d,0xe3,0xd7,0x63,0x2e,0xdb,0xdd,0x71,0x3a,0xd5,0x91,0x1e,0xac,0x6a, - 0xb6,0x67,0xfc,0xd7,0xfb,0x1f,0x9e,0x51,0x52,0x35,0xfb,0x7d,0xe2,0x7e,0xf1,0x83, - 0xaf,0x69,0xeb,0xcd,0x2f,0xdb,0xbf,0xfc,0x5c,0x04,0xce,0xc1,0xfe,0x2b,0x67,0xbf, - 0x73,0xf0,0xcc,0x92,0x3f,0x78,0x31,0x06,0x16,0xca,0xe4,0x6c,0x62,0x69,0x35,0x9b, - 0xf9,0xc4,0x74,0x4a,0x3d,0x3d,0xf9,0xe2,0x8d,0x66,0xc6,0x99,0x17,0x2f,0x80,0x5d, - 0x1a,0x55,0x3b,0xb0,0xbb,0xd3,0x7d,0x0a,0x21,0xde,0xfc,0x62,0xec,0xee,0xec,0x7c, - 0xf8,0xe9,0x8b,0xd1,0x7c,0x1f,0x81,0x84,0x7c,0x86,0x46,0x41,0x5c,0x03,0xa4,0x3b, - 0x78,0xcd,0xd8,0x13,0x9d,0xd0,0x6a,0xd0,0xdb,0x2f,0x94,0x5e,0x0d,0x80,0x8f,0x1e, - 0x9a,0x70,0x05,0x6e,0x38,0x4e,0xd7,0xc1,0xad,0xdc,0x6d,0xbc,0x9b,0xed,0x7f,0x7b, - 0x2e,0x96,0x13,0x08,0xf5,0xd2,0xd9,0x79,0xf9,0x24,0xc0,0xb4,0x62,0x65,0x5c,0xd6, - 0xca,0xaf,0x6e,0x16,0x9d,0x51,0x16,0x53,0x37,0xc0,0x11,0xab,0x51,0xd6,0x94,0x13, - 0x98,0xbc,0x5f,0x29,0x77,0xb0,0x7f,0xf0,0x8c,0x61,0xaa,0x72,0xe7,0xb7,0x7e,0xf6, - 0x85,0xc1,0xf3,0x35,0x58,0xf5,0x0f,0xdf,0xcb,0x42,0x77,0x5e,0x1a,0x62,0xb7,0xed, - 0x74,0x57,0x4e,0xc8,0x5e,0xa5,0x6c,0x19,0x27,0x0b,0xe5,0xeb,0x40,0xdc,0xb8,0xd2, - 0xd4,0xfe,0xc5,0xa0,0x1b,0xcb,0x3c,0x2a,0xd5,0x9a,0x90,0x54,0x3a,0xcf,0x2d,0xce, - 0x27,0x89,0x6b,0xc0,0x63,0xef,0x10,0x28,0x73,0x02,0x38,0x3e,0x62,0xe3,0xdc,0x9e, - 0xc1,0x43,0x00,0xe6,0x07,0x7f,0xa1,0x33,0x06,0xf5,0x09,0xde,0xe1,0xc7,0x69,0x9b, - 0x74,0x78,0xe9,0x3e,0x3c,0x28,0x2a,0x6f,0x68,0xb6,0x44,0x77,0x03,0x57,0x3b,0x81, - 0x04,0xe9,0x74,0x58,0x38,0x90,0x2c,0xfa,0xba,0xef,0x4a,0x57,0x77,0x11,0xb0,0xf0, - 0xee,0xd2,0xbf,0x42,0xb7,0x4c,0xf1,0x7a,0x8f,0xaf,0xa5,0x36,0x34,0xce,0xa3,0xa8, - 0x2b,0x21,0xa0,0xfc,0x40,0xde,0x6c,0x45,0x98,0x18,0xb8,0x7e,0xd4,0x25,0x1f,0xdf, - 0xff,0x2a,0x41,0x94,0xa7,0x9d,0xbf,0x95,0xd0,0xca,0xd3,0x4e,0xce,0x2a,0x80,0xbb, - 0xfd,0x42,0xe7,0x97,0x6f,0x7d,0x0a,0xce,0x21,0x18,0xab,0x40,0x8f,0xc5,0x62,0x8f, - 0x16,0x49,0x31,0x92,0x0b,0x47,0x9c,0x56,0xae,0x80,0x65,0x5f,0x3a,0xd8,0x9b,0xd9, - 0x63,0x8d,0x8c,0x56,0x12,0x6f,0x0a,0xdf,0xf2,0x1b,0x1a,0x73,0xb7,0x3a,0xf6,0xc9, - 0x84,0xbd,0x8f,0x82,0x29,0x3c,0x27,0x48,0x4b,0x63,0x75,0x94,0x16,0xe8,0xa4,0x65, - 0x71,0x6d,0x7e,0xee,0xb1,0x57,0x76,0x14,0xf4,0x75,0xf7,0xc0,0x0c,0xb8,0x2c,0x75, - 0xe1,0xe7,0xe6,0x56,0x01,0xd8,0xba,0xd7,0x20,0xef,0xb2,0xf5,0x55,0x52,0x8c,0x97, - 0xc3,0x9f,0x31,0x52,0x8d,0x8c,0x52,0x2e,0xcd,0x67,0x0a,0x7e,0x8d,0xb0,0xd3,0x97, - 0xbd,0xb5,0x28,0x18,0x02,0xf4,0xf7,0x70,0xd0,0xb6,0xd2,0x72,0x1c,0x2e,0xfa,0xa2, - 0xcc,0xf8,0x9b,0x6c,0x69,0x41,0x66,0x0f,0xf0,0x2b,0xe2,0xe9,0xf0,0x5d,0x6d,0x6a, - 0xa6,0x5a,0xd0,0x81,0xe2,0x5d,0x30,0x27,0xdc,0xa3,0xe0,0xbe,0x87,0x37,0xa4,0xb2, - 0xb6,0x70,0x44,0xd6,0x03,0x56,0x1d,0x06,0xf1,0xe7,0xe1,0xad,0x55,0x46,0x23,0xfe, - 0x90,0x4e,0xac,0x32,0x2e,0xf1,0x87,0x51,0x42,0xbc,0x27,0xb4,0xd0,0xd8,0xe2,0x8e, - 0xbf,0x6e,0x1f,0x99,0x46,0x73,0x1c,0x79,0x74,0xc1,0x2a,0x25,0x19,0xae,0xc0,0x04, - 0x20,0x6a,0x0c,0x69,0xcb,0xe4,0x68,0x86,0xe9,0xfa,0x90,0x6a,0x55,0x5c,0x05,0xec, - 0xd2,0xdc,0x55,0x6f,0x06,0x0a,0x78,0x36,0xe1,0x46,0x5f,0x06,0xe9,0xc2,0x30,0x21, - 0xf4,0x4b,0x93,0x64,0x2d,0xe9,0x6b,0x11,0x93,0x85,0x05,0x08,0x87,0xd3,0x2b,0x60, - 0xe0,0xe5,0xd6,0xcd,0x55,0x9f,0x4b,0x14,0x31,0xed,0xf1,0x2b,0xec,0x0f,0xd8,0xc9, - 0x85,0x6a,0xd1,0xe9,0xc7,0x9f,0x32,0x4b,0x88,0x73,0x8b,0x84,0xc6,0x3a,0x93,0x04, - 0x6a,0xad,0x12,0x7b,0x89,0x71,0x38,0xfd,0x33,0x05,0xab,0x21,0x9b,0x28,0x67,0xf5, - 0x26,0x0f,0x79,0x27,0x89,0x66,0x3f,0x20,0x2e,0xf2,0x28,0x9b,0x10,0x90,0x7c,0xaa, - 0x51,0x9e,0xa7,0xb5,0xc6,0x74,0x15,0x51,0x28,0xbc,0x17,0xf3,0x43,0x87,0x8d,0x0d, - 0x0c,0x41,0xb4,0x63,0x85,0x83,0xdd,0x7e,0xe3,0xb2,0x63,0x77,0xed,0x1d,0x7b,0xb7, - 0xee,0xb6,0x10,0xa1,0x2c,0xb9,0xfd,0x62,0x6e,0xf9,0xab,0x8f,0xcd,0x7d,0x18,0x7e, - 0x98,0xdf,0x4f,0xb5,0x22,0x2f,0x9e,0xe3,0xa3,0x26,0x40,0x00,0x15,0x43,0xb2,0x50, - 0x27,0x84,0xc9,0x28,0x5d,0xb0,0x75,0xfb,0x65,0xc7,0x28,0xb8,0x3c,0xca,0xe0,0xdf, - 0xb9,0xb7,0xe3,0x5c,0xf9,0x82,0x88,0x7b,0x78,0x24,0xe0,0xf3,0xa0,0xfe,0xe8,0xd9, - 0xb3,0xb1,0xf1,0x8d,0x08,0xe5,0x05,0x83,0x9d,0x63,0xc8,0x2d,0x11,0xea,0x76,0xde, - 0x8f,0xbe,0x5a,0x7a,0x78,0x64,0xd3,0x7c,0xec,0xef,0xae,0x45,0xde,0xdf,0x7c,0x3f, - 0x14,0x8a,0x12,0x42,0x93,0x9e,0x8e,0xf0,0x9a,0xc5,0x8b,0x08,0x15,0xda,0x65,0x53, - 0xef,0xf8,0xd3,0xa2,0x74,0xf7,0x13,0x3a,0x1c,0xba,0xc1,0x36,0x5e,0x42,0x5c,0xbe, - 0x07,0x64,0xa5,0x31,0x33,0x5e,0x45,0x88,0x6a,0x0a,0x84,0xb2,0xba,0x25,0xba,0x78, - 0x82,0x4b,0x19,0x78,0x1e,0xe4,0xe5,0xe1,0xd6,0x8a,0x8b,0x4d,0x6b,0x05,0x4c,0x61, - 0x7b,0x72,0x12,0x2d,0x82,0x31,0x92,0xa0,0xc4,0x03,0x74,0xc8,0x6d,0x15,0x5b,0x06, - 0x9a,0xf9,0xbb,0x74,0x11,0x40,0xc5,0x12,0x65,0x32,0x41,0x8f,0x1d,0xb1,0xd9,0x96, - 0x0c,0xcf,0x8e,0x34,0x23,0xb1,0x5e,0x33,0xb7,0x55,0xc3,0xe9,0xd2,0x55,0x75,0x45, - 0xdb,0xfc,0x89,0x1f,0xfa,0x29,0x9e,0x27,0xe5,0xf8,0x5b,0xbd,0x37,0x2e,0x8f,0xb8, - 0xcd,0xd4,0x08,0xfb,0x91,0x9b,0x93,0xc1,0x06,0x37,0x28,0x06,0x85,0x53,0x9f,0xb4, - 0x78,0xb9,0xa8,0x3f,0x95,0x6d,0xd1,0x66,0x51,0xb8,0x09,0x0b,0x30,0x29,0x96,0xcd, - 0x9c,0x53,0x2c,0x0f,0xee,0xa7,0xa1,0xaa,0x62,0x5b,0xbb,0xf8,0xe1,0x61,0x64,0x6d, - 0x6c,0xc4,0xb0,0x18,0x46,0x32,0xff,0x71,0x21,0x63,0x6a,0x8c,0x23,0x8c,0xda,0xc1, - 0xa4,0x5d,0x1d,0x59,0x95,0xc2,0x85,0x17,0xf0,0x8b,0x17,0x07,0xde,0x9d,0x3d,0xb8, - 0xbc,0xb2,0xc7,0x0a,0xf7,0x35,0x16,0x10,0x3e,0x36,0x29,0xfc,0x37,0xe6,0xe2,0xb3, - 0xa1,0xba,0x43,0xb0,0xcd,0xad,0x00,0xb7,0x1b,0x3a,0xeb,0xe2,0x2d,0xe8,0x46,0xec, - 0x3f,0xac,0xad,0xa4,0x2b,0x37,0x91,0xfe,0xe8,0x97,0xbb,0x99,0xf6,0xf8,0x52,0xf3, - 0xb7,0xb8,0x52,0xab,0xad,0x94,0x6a,0xe2,0xd1,0x9f,0x41,0xbb,0x13,0x1a,0x8d,0xa8, - 0x6a,0x72,0x1f,0x76,0x59,0x0f,0x3a,0x67,0x5c,0x1d,0x89,0x8b,0x90,0xcd,0x1c,0x19, - 0x0a,0x5f,0x9b,0x30,0x36,0xe1,0x94,0x01,0xbb,0x5d,0x93,0x2c,0x66,0x45,0x8f,0x2c, - 0xb2,0x7e,0xc6,0xb3,0xa2,0x9a,0xe5,0x6f,0x51,0xcb,0xa8,0xf3,0x36,0xd8,0xc9,0xbe, - 0x36,0x93,0x30,0xa6,0x1b,0x0d,0xc6,0x92,0x2f,0xab,0xb0,0x69,0x76,0x12,0xb3,0xeb, - 0xf4,0x93,0xfc,0xd5,0xba,0x10,0x78,0xc9,0x08,0x38,0xd6,0x98,0x5d,0xa9,0xa9,0x67, - 0x67,0xbc,0x11,0x34,0x93,0xf8,0x28,0x01,0x46,0x0a,0xf8,0x82,0x96,0xc1,0x3a,0xa6, - 0x64,0xa4,0xc7,0xd4,0x62,0x45,0x12,0x9e,0x71,0x5a,0x5b,0x4d,0xd1,0x4b,0x3e,0x02, - 0xd5,0x21,0xa3,0x00,0x91,0xdd,0xf1,0xc0,0x2f,0x7e,0x33,0xe8,0x02,0x05,0x1c,0x77, - 0x76,0x07,0xb5,0xd3,0x31,0xb8,0x3c,0x70,0xae,0xac,0x9d,0x8d,0x8d,0x66,0x19,0xd7, - 0x1f,0x1e,0x4a,0xeb,0xc7,0xe2,0x9a,0x8b,0x78,0x6c,0xda,0xa5,0x5c,0x47,0x26,0xc5, - 0xdc,0x2f,0x62,0x41,0xf9,0x98,0x9b,0x2a,0xfa,0x34,0xe4,0x33,0x50,0x39,0x3f,0x97, - 0x45,0x2a,0xaf,0xe1,0x57,0x29,0xbd,0x06,0xc3,0xde,0x61,0xa4,0x38,0xbb,0x29,0xeb, - 0xa0,0x4b,0x20,0x2a,0x35,0xc8,0x54,0xbd,0x3c,0x6c,0x49,0xbf,0xc4,0xb1,0x0c,0x0f, - 0x26,0xf0,0x21,0xba,0x0d,0x07,0xaa,0x3b,0x74,0x55,0x41,0xb5,0x37,0x9c,0xcc,0x1b, - 0xcc,0x6d,0xc8,0xa0,0xf9,0x84,0x89,0x78,0xed,0x8e,0x69,0x43,0x9a,0x3c,0x8e,0xed, - 0x74,0x8f,0xf0,0x8d,0x2e,0xad,0x86,0x2d,0xa1,0xd3,0x85,0xb5,0x86,0x86,0x38,0x3d, - 0x2c,0x27,0x34,0x61,0x73,0xd5,0x1e,0x5f,0x7d,0x50,0x69,0x4f,0x24,0xb3,0xd3,0xc0, - 0x5c,0x6f,0x8e,0xbf,0xd8,0x90,0xf8,0xac,0x70,0x22,0xb1,0x6c,0x89,0x63,0xa8,0xc8, - 0x08,0x02,0xa5,0xf6,0x8a,0x1f,0xd9,0x1b,0x8a,0xe9,0x99,0x8c,0x0a,0x87,0x1d,0xa0, - 0xc3,0x74,0xc8,0x6a,0xc7,0x22,0x36,0x23,0x8d,0x05,0xbd,0x2d,0x0b,0x11,0x18,0xc7, - 0x55,0x0d,0xb6,0xda,0x1e,0xbe,0xd9,0xfe,0x17,0x39,0x5e,0xfd,0xee,0x3c,0x48,0x1c, - 0xfa,0xf6,0x01,0x11,0xe2,0xdb,0x07,0x42,0xf5,0x6f,0x1f,0xb2,0xbb,0x6f,0x1f,0xb0, - 0x4b,0xbf,0x0b,0x0c,0x10,0x2f,0x38,0x99,0x32,0x1d,0xe1,0x20,0x9e,0x09,0x1a,0xf4, - 0x4c,0x7e,0xe7,0xbf,0x3b,0xf2,0x56,0xe8,0x6b,0xbc,0x49,0x49,0x46,0x80,0x44,0x20, - 0x62,0x37,0x05,0x1c,0x35,0x97,0xb6,0x14,0x20,0x89,0x5f,0x0a,0xee,0x0e,0xda,0x0d, - 0x99,0x7c,0xe3,0x63,0x41,0x48,0x20,0x5a,0x5b,0x7b,0x15,0x2c,0xf3,0x6e,0xd2,0x7b, - 0x4d,0xec,0x5b,0xbc,0xf9,0xe9,0x34,0x13,0x76,0x95,0x3a,0x52,0xca,0x4a,0x5e,0x68, - 0xb3,0xe6,0x12,0xaa,0xd3,0xc0,0x73,0xd1,0xca,0x10,0xf7,0xa0,0xe2,0x15,0x9c,0xb0, - 0xd0,0x40,0x92,0xea,0x58,0x9a,0xa1,0x17,0x34,0xac,0x09,0xa3,0x82,0xf9,0x41,0xe6, - 0xfe,0x19,0x2d,0x8c,0x66,0x51,0x04,0x3f,0x2e,0x1b,0x1c,0xcb,0x00,0xa2,0xdc,0x48, - 0xd7,0x32,0x5a,0xe2,0x36,0xce,0x14,0x1d,0x9f,0xc9,0x13,0x02,0xd0,0xa3,0xf5,0xcb, - 0x39,0x06,0x9c,0xc0,0x8b,0xd3,0x52,0xad,0x1b,0x2b,0x1d,0xef,0x44,0x80,0x59,0xcd, - 0xe3,0x6e,0x65,0xb7,0x38,0x03,0x5e,0xce,0x2d,0x7a,0x50,0x1c,0xa6,0xce,0xd6,0x02, - 0x66,0x5d,0x1e,0xb7,0xfe,0xb7,0xdb,0xfa,0x72,0xb5,0xdc,0x79,0x94,0x0e,0xca,0xf9, - 0x04,0x3c,0x87,0x50,0x98,0x96,0xe2,0x7a,0xd7,0xc0,0x88,0x0e,0x04,0x01,0x44,0x3b, - 0xad,0xc0,0x43,0x73,0x36,0x03,0xa9,0x91,0x90,0xd5,0x0c,0xf4,0x5a,0x33,0x9a,0x64, - 0xc1,0x84,0x5d,0xb6,0x4a,0x06,0x78,0xf5,0x15,0x9b,0xfa,0x3d,0x90,0x68,0xb8,0x4c, - 0xde,0xc2,0xf6,0x90,0x5c,0xc4,0x07,0x85,0x9b,0x1a,0xfb,0xc3,0x92,0x1f,0x70,0xe9, - 0x1e,0xc7,0x0b,0x18,0x35,0xda,0xe1,0x90,0x0f,0x0d,0x9a,0xff,0x15,0x3c,0x11,0x97, - 0xec,0x1f,0xc2,0xcc,0x6d,0xae,0xd0,0x4f,0x84,0x27,0xe0,0xb2,0x31,0x2c,0x7b,0x86, - 0x15,0xab,0xe7,0x1e,0xb1,0xdd,0xba,0x60,0x4e,0x65,0x49,0xcd,0xd3,0x27,0x77,0x9d, - 0x71,0x47,0x23,0x2f,0xce,0x94,0x7f,0x8f,0x70,0x63,0xc1,0x08,0x2e,0x71,0x12,0x61, - 0x10,0x1d,0xba,0x97,0x0c,0xdd,0x0c,0x31,0x43,0xc1,0xd5,0x90,0x6f,0xef,0x96,0x0e, - 0x87,0x8e,0xf1,0x6e,0x22,0xe2,0xa0,0x89,0x6a,0x68,0x4b,0x42,0x27,0x45,0xf4,0xa1, - 0x01,0x16,0xdc,0xf3,0x58,0xa6,0x4a,0x8d,0xdf,0x4d,0x16,0x9b,0xd8,0x5d,0xe6,0x9b, - 0xdf,0x4d,0xf2,0xbd,0xc9,0xbd,0x84,0x08,0x71,0x61,0x4f,0xdb,0x69,0x43,0x5d,0xe4, - 0x28,0x43,0xb5,0x43,0x06,0x74,0x2e,0x4a,0x85,0x2f,0xf8,0x22,0x36,0xf0,0x1a,0x49, - 0x1b,0xe3,0xd1,0xe7,0x2e,0x3d,0xf2,0xe2,0xcf,0x16,0xdd,0x83,0x4a,0x15,0x8b,0x08, - 0x86,0x34,0x02,0xe5,0x27,0x45,0x1e,0x52,0xb5,0x2e,0x3c,0xa8,0xf0,0x68,0x09,0x9f, - 0xc9,0xc2,0xbd,0xe4,0x05,0xbf,0xa9,0xa2,0xe3,0x5e,0x3d,0xd6,0xac,0xe2,0xd5,0x85, - 0xbb,0xb9,0x63,0x9c,0x90,0x07,0x26,0x05,0xa9,0x63,0x6b,0x1f,0x74,0x65,0x02,0xf4, - 0x08,0x02,0x79,0x9d,0x6e,0x69,0x38,0x88,0x34,0xc2,0x27,0x8a,0x1c,0x35,0x1d,0x53, - 0xef,0x49,0xee,0x23,0x58,0x71,0x07,0x2c,0x91,0xfb,0x3b,0x8d,0xdc,0xe7,0xbe,0x80, - 0x77,0xc2,0xb7,0x4e,0x88,0x80,0x54,0x55,0x1e,0x7b,0x78,0xe5,0x38,0x39,0x5f,0xd9, - 0xda,0x4d,0x48,0x1b,0x77,0xe4,0x60,0x47,0x6e,0xd5,0xa2,0x7a,0x75,0x18,0x87,0xe6, - 0x5e,0x65,0x0f,0x6b,0xe5,0x28,0xb5,0x0a,0x61,0x85,0x3b,0xda,0x26,0xb0,0xc9,0xc8, - 0xe7,0xe4,0xe4,0xd9,0x6a,0x6c,0x99,0x9b,0xff,0xbd,0x4e,0x69,0x1a,0xf4,0xab,0x1e, - 0x69,0x0a,0x93,0x88,0xfa,0x8b,0xfa,0x6a,0x9c,0xc1,0x8c,0x34,0x42,0x69,0x7b,0xad, - 0x47,0x18,0x47,0x5b,0xaf,0x00,0x40,0xad,0x4f,0xe0,0x23,0x85,0x7b,0x5b,0xbe,0x36, - 0x09,0x3a,0x63,0x7f,0x4c,0x42,0x0c,0x00,0x1a,0xd8,0x48,0x20,0x81,0x28,0x3f,0x2b, - 0x07,0x37,0xd1,0xd5,0xa2,0x0f,0xdc,0xa6,0xd9,0xa8,0x80,0x12,0x20,0x49,0xe0,0x5b, - 0x00,0x31,0x65,0x8d,0x27,0xb9,0xc0,0x21,0x48,0x36,0xa7,0xb0,0xdd,0xdc,0x7a,0x20, - 0x08,0x6d,0x62,0x69,0x90,0xcd,0x70,0xe5,0x7e,0x8d,0x2f,0x1c,0xd9,0x7f,0xd5,0x0d, - 0xba,0xb8,0xc0,0x1e,0xcb,0xf1,0x96,0x8b,0x05,0xd4,0xdd,0x98,0x28,0x7a,0xf3,0xc7, - 0xcf,0x7e,0xf8,0x79,0x9e,0x1e,0x49,0x73,0xb3,0x66,0x87,0x6d,0x8a,0x47,0x9e,0x1f, - 0x34,0x8b,0x79,0xd8,0xa4,0xd9,0xea,0xed,0xb4,0x75,0xd3,0x26,0xe1,0x84,0x29,0x59, - 0x03,0x41,0xec,0x30,0x74,0x33,0x26,0x6b,0x57,0x6d,0x87,0xd1,0xed,0x91,0x69,0xa9, - 0xa3,0x53,0x2d,0xce,0x03,0x37,0x52,0x7f,0xa7,0x64,0x3d,0x3e,0x17,0x7c,0x17,0x75, - 0xf4,0xbd,0x45,0x2a,0x80,0x32,0x3d,0x40,0x39,0xa7,0x70,0x18,0x7f,0x15,0xe9,0xef, - 0xc8,0x0d,0xf0,0xee,0x0f,0x5b,0xc6,0x82,0xff,0x6a,0x1f,0x16,0x31,0x28,0x3e,0x6d, - 0xe6,0xa0,0x07,0x22,0xab,0x55,0x73,0xa3,0xad,0xe8,0xf6,0x3c,0x9d,0xda,0xaa,0x2f, - 0x36,0x5d,0xd5,0x6d,0x03,0x06,0x0b,0x22,0x2d,0x68,0x04,0xc3,0x40,0x5d,0xe4,0xad, - 0x53,0x0a,0x4a,0x83,0x6d,0xfc,0x4c,0x62,0x03,0x6f,0x80,0x5a,0x29,0x68,0xa1,0x54, - 0x86,0xa2,0xb3,0x10,0x0f,0x0d,0x3b,0xd2,0xed,0x40,0xcb,0x8b,0x91,0x62,0xa0,0xf9, - 0xc0,0x0f,0xaf,0x8b,0xc9,0x68,0xbb,0x72,0x2d,0xc4,0x1c,0xa4,0x24,0x58,0x7a,0x91, - 0x04,0x03,0x73,0x96,0x65,0x71,0x6f,0x7b,0x1b,0x38,0xe4,0x78,0xcb,0xdc,0x36,0xfb, - 0x5c,0xb8,0xd0,0x1c,0x2a,0x69,0x44,0xf2,0x2c,0xf1,0x26,0xe2,0x1d,0x5a,0x5e,0x69, - 0x80,0x25,0x14,0xae,0x35,0x75,0x99,0x66,0xa1,0x2a,0xf3,0x85,0x59,0xa9,0x4a,0xbf, - 0xdf,0x57,0x87,0xc3,0x3a,0xed,0x10,0x1b,0x1c,0x09,0xa0,0x3f,0x3c,0xec,0xb4,0xfb, - 0x5a,0x41,0xb2,0x76,0x2d,0x87,0x35,0xef,0x8b,0x78,0xd4,0xba,0x6b,0x85,0x8e,0x99, - 0x61,0xab,0xf5,0x64,0x1d,0x87,0xed,0xa3,0xb0,0x27,0x34,0x78,0xe1,0xeb,0xc1,0x1e, - 0xac,0x3b,0x89,0x09,0x50,0x83,0x7e,0x85,0xae,0xb8,0xd2,0xcf,0x5e,0x8e,0x60,0xd7, - 0xf3,0x30,0xec,0x58,0x8b,0x1c,0xdf,0x6a,0xd5,0x67,0x44,0xf3,0xa3,0xeb,0xb2,0xcb, - 0x46,0x66,0xf5,0x31,0x12,0x0d,0xe6,0x72,0x38,0x90,0x41,0xd3,0x7a,0x5c,0x6d,0x8a, - 0xcb,0x7d,0x6a,0xd7,0xd4,0xd2,0xa8,0x19,0x97,0x26,0x2a,0xc8,0x21,0x1c,0x6d,0xbe, - 0x76,0x0d,0x9e,0xa5,0x6d,0xf3,0xf0,0x8c,0x5a,0x7c,0xbd,0xed,0x1e,0x6e,0xf6,0xcc, - 0x7f,0x46,0x0b,0x63,0xe4,0x0a,0x1b,0x38,0xa6,0x02,0xb8,0x40,0x85,0x75,0xb0,0xdd, - 0x91,0xb7,0x8d,0x21,0x88,0xe5,0xf5,0xe7,0xdd,0xdd,0xbe,0x7a,0xff,0xc7,0x9b,0xb3, - 0xef,0xd1,0x7e,0xe1,0xd2,0xe4,0x38,0x80,0x6f,0x81,0xa8,0xdc,0x62,0x38,0x59,0x34, - 0x37,0x86,0x41,0x50,0x64,0x73,0x93,0x2c,0xf2,0xe0,0xeb,0xf7,0xf8,0x4b,0xc4,0x77, - 0x06,0x0f,0x94,0xcf,0x0f,0x27,0x11,0x67,0x1a,0xa1,0x09,0x18,0xc6,0x10,0x04,0x4c, - 0x20,0xa2,0x2f,0xb8,0x06,0x4a,0x37,0x9a,0xbf,0x5c,0x9c,0x58,0x9c,0x91,0x7c,0x14, - 0x28,0xd8,0xa0,0x60,0xdc,0x28,0xc3,0x12,0x76,0x85,0xd1,0xac,0x25,0x30,0xe7,0x91, - 0xb3,0x32,0x5b,0xac,0x57,0x9a,0x5b,0x40,0x0b,0x9e,0x99,0x33,0xce,0x01,0xeb,0xd1, - 0x33,0xc4,0xfc,0xc9,0x73,0x99,0xb1,0x3a,0x3d,0x3f,0x3b,0xfe,0x60,0x90,0xf7,0x09, - 0xba,0x76,0x04,0x68,0x1c,0x92,0x66,0x06,0x19,0xaa,0x71,0x99,0xfc,0xaa,0x43,0x9b, - 0x54,0x3f,0x29,0xba,0x8a,0x24,0x63,0xba,0x9f,0x08,0x4f,0x71,0x6c,0x96,0x51,0xd0, - 0x4b,0x80,0xf7,0xeb,0xa9,0x57,0x2c,0x28,0xd6,0x1a,0x8e,0xe5,0x87,0x04,0xb6,0x62, - 0xdc,0x98,0xc5,0x37,0xd8,0x96,0x96,0xfb,0xbb,0xad,0x99,0x77,0xd7,0x02,0x51,0x31, - 0x69,0x01,0x9f,0x21,0x86,0x04,0x1c,0xf2,0x08,0x0a,0x25,0x8e,0xde,0xfc,0x71,0x7a, - 0x9d,0x97,0xa4,0x20,0xc0,0xb0,0xea,0xc2,0x4c,0x30,0x79,0xf3,0xd4,0x0b,0x6e,0x40, - 0xd8,0x2c,0x96,0xa7,0x0b,0x41,0xb1,0xf0,0x09,0x7b,0xec,0x68,0x4d,0xf3,0x27,0xa3, - 0x49,0x2a,0x1a,0xde,0x80,0x55,0xac,0x60,0xd2,0x12,0x8a,0x99,0x80,0x25,0x17,0x7b, - 0xc9,0x5c,0x4e,0x86,0x4b,0x54,0x7f,0x33,0x35,0x8e,0x4f,0xde,0x1b,0xf8,0xc1,0x4f, - 0x11,0x07,0xd2,0xea,0x50,0x8c,0xa5,0x1f,0x66,0x07,0x62,0x44,0xe2,0xe6,0x53,0xac, - 0x03,0xa1,0x84,0x5a,0x4e,0x4c,0xc0,0x9d,0xc8,0x68,0x92,0xf3,0x87,0x27,0x1b,0x14, - 0x17,0x8a,0x7e,0xf1,0x92,0x68,0x16,0xc5,0x35,0x45,0x72,0x18,0xd0,0x16,0x23,0xd8, - 0x05,0xbc,0xb7,0x95,0x51,0xc7,0x9b,0xc7,0x2c,0x5b,0x62,0x38,0x49,0xd8,0x7f,0x84, - 0xa0,0xe9,0x26,0xee,0x3c,0x77,0xb2,0xe6,0x1b,0x60,0x0d,0x3a,0xf2,0xb1,0x87,0xb7, - 0x36,0xfa,0xe9,0x26,0x8f,0x12,0x4b,0x3d,0x72,0xf3,0x65,0xa7,0xbf,0x33,0x12,0x50, - 0x11,0x40,0x85,0x78,0xcb,0x58,0x27,0xad,0x47,0x58,0x04,0x02,0x52,0xe4,0xfa,0x34, - 0x42,0x42,0x81,0x00,0x4f,0x3c,0xf5,0xdd,0x68,0x92,0xfb,0x0c,0xb1,0xe6,0xb6,0x21, - 0x7c,0x6d,0x2c,0xbd,0x94,0xbc,0x18,0xd4,0x36,0x4f,0xbd,0x44,0xbc,0xb5,0xd0,0x44, - 0xad,0xb6,0x0d,0xe9,0xa5,0x78,0x56,0xe8,0x85,0xd1,0x44,0x34,0xb4,0xd1,0x3b,0xc8, - 0x36,0xd8,0x1f,0xa4,0x52,0xa8,0x35,0xf6,0x5d,0x60,0x61,0xcc,0x37,0x77,0x19,0x19, - 0x1e,0x89,0x81,0x60,0x6a,0x08,0x5c,0x80,0x3f,0x12,0xed,0x04,0xd1,0x94,0x6d,0x5b, - 0x11,0xfe,0xf8,0x2b,0x07,0x0f,0x1f,0xa6,0x22,0xe2,0x14,0x82,0x64,0x82,0x9e,0x5a, - 0x64,0xa5,0xad,0x97,0xe3,0x69,0x43,0xce,0xb3,0x58,0x2a,0xcf,0xe3,0x25,0x78,0xf9, - 0x25,0xac,0x09,0x76,0x48,0x26,0xe1,0x8d,0x7c,0x8b,0xb5,0x12,0x72,0xc8,0x5e,0x98, - 0x46,0x7c,0x77,0x18,0x14,0xc0,0xdd,0xc4,0x70,0xb3,0x0c,0x29,0xf3,0xd8,0xe0,0x6f, - 0xc5,0x8c,0xc8,0xdf,0xd1,0xb4,0xb9,0x63,0xbe,0xf2,0x9d,0x93,0x01,0x1b,0xc7,0xde, - 0xdd,0x63,0x21,0x6b,0xca,0x59,0x7f,0x4d,0xfc,0xcc,0xab,0xc9,0x6b,0x2c,0xf9,0x96, - 0x16,0x2e,0x33,0x8d,0x53,0x83,0xe8,0xcc,0x29,0xaa,0x41,0x8d,0x05,0xdf,0x83,0xf2, - 0xe3,0xe9,0xb9,0xf6,0x79,0x32,0x51,0xdf,0xe9,0x3a,0x94,0x4a,0x0e,0x74,0x12,0xae, - 0x90,0x35,0x44,0x28,0xb9,0x59,0xf0,0x15,0xda,0xd5,0x72,0x5e,0x46,0x4e,0x66,0x80, - 0x57,0x31,0x0b,0x75,0xf2,0x68,0x1b,0xb2,0xc1,0x2c,0xdc,0x01,0x91,0x45,0x77,0x5e, - 0x37,0xdb,0x0e,0x24,0xbd,0xc3,0x72,0x6a,0x99,0x85,0x04,0x6d,0x3e,0x21,0xf0,0xc3, - 0x51,0xb0,0x18,0x53,0x0b,0x06,0xf0,0x7e,0x3e,0xb5,0xeb,0xcb,0x05,0x96,0x56,0x4a, - 0xa7,0xb0,0xa4,0xb1,0xf8,0x31,0xbd,0xfa,0x29,0xcf,0x57,0xe0,0xdf,0x14,0xab,0xa8, - 0x94,0x8b,0x61,0x3b,0x4a,0x2b,0xe5,0xc4,0x3c,0x17,0xba,0xaa,0x5f,0xd5,0xac,0x11, - 0x72,0x4a,0x6e,0x89,0xa5,0x8a,0xb2,0x72,0x25,0x37,0xcf,0xc8,0x1b,0xba,0x79,0x8e, - 0xb3,0x8b,0x95,0x5d,0x93,0x93,0x26,0xe7,0x07,0x56,0x3e,0xd4,0xe5,0x15,0xda,0x42, - 0xc4,0x08,0xd6,0x66,0x08,0xf9,0x48,0xd7,0x4e,0x1b,0x4b,0x10,0x48,0x5a,0xf2,0x4d, - 0x12,0xb7,0x00,0x47,0x8b,0x12,0xa8,0xa2,0x56,0xf4,0x66,0xf0,0x07,0x21,0x09,0x6b, - 0xbb,0x12,0x6a,0x06,0xd1,0xf4,0x9c,0x4a,0x47,0x99,0xcb,0x91,0x8c,0xa8,0x5d,0x94, - 0xa7,0x51,0x7b,0x41,0x92,0x0f,0xf4,0x90,0x48,0x31,0x9f,0xdb,0xd3,0xdc,0x4d,0x80, - 0xa5,0x9a,0x59,0x79,0x49,0x76,0x2b,0xa7,0xb9,0xbd,0x0d,0xc9,0x9b,0x1b,0xb1,0x89, - 0x72,0x09,0xa2,0xae,0x6a,0x51,0x72,0x37,0xb1,0xf8,0x92,0x32,0x24,0x24,0x0d,0xc9, - 0xf8,0x6e,0x62,0xb1,0x33,0x93,0x40,0xe7,0x88,0xb2,0xfb,0xef,0x8f,0x3f,0xd6,0x96, - 0x31,0xdc,0x78,0x55,0x31,0xd4,0x9b,0xe0,0x2a,0x60,0x5d,0xc7,0xf1,0xa9,0x2c,0x0f, - 0x74,0xa1,0xd8,0x24,0x8a,0xa8,0x79,0x51,0xb9,0xad,0xb3,0x24,0x82,0xf4,0x57,0x54, - 0x2e,0x34,0x19,0x82,0x46,0x5f,0xaf,0xcc,0x61,0xb3,0x56,0x31,0xa1,0x69,0x57,0xcb, - 0x4c,0xc3,0x08,0x7d,0x9d,0x2a,0xd1,0x13,0x13,0xb9,0x83,0xb3,0x45,0x86,0xab,0xb7, - 0x36,0x8b,0xd1,0x4c,0x5d,0x60,0x4d,0xdc,0xd4,0x90,0x35,0x89,0xc9,0x90,0x14,0xed, - 0x0d,0xfe,0x96,0x68,0xa3,0xd1,0x6a,0xe5,0xb2,0x2f,0xa9,0x8a,0x68,0xe7,0xce,0xee, - 0xcd,0xab,0xc6,0x55,0xce,0x68,0xfd,0xfc,0xe6,0x9f,0xcc,0x67,0x89,0x20,0xce,0xda, - 0x59,0x53,0x9b,0x29,0xa7,0x9b,0xa9,0xe5,0x84,0x0b,0xc8,0xcf,0x16,0xe3,0xfc,0x23, - 0x2d,0x05,0xf9,0x31,0x0a,0xa7,0x85,0xaf,0x6c,0x5e,0xe8,0xd0,0x51,0x82,0x79,0x21, - 0x25,0x41,0xd8,0xc7,0x85,0xdd,0x21,0x7d,0xe8,0x70,0xd6,0xe4,0x46,0xe4,0x43,0xc0, - 0xe2,0x3e,0x06,0x9b,0xaf,0xec,0x71,0x0d,0xcb,0x62,0x77,0x79,0xc2,0xa2,0x40,0x75, - 0x9a,0x9f,0xb9,0xba,0xe2,0x66,0x45,0xdb,0xb0,0x47,0xdb,0x55,0x79,0xef,0x15,0x3d, - 0xc5,0x54,0xe4,0x32,0xe1,0x67,0xe1,0x85,0x23,0x8a,0xd3,0xf4,0xe1,0xa7,0x2f,0xf2, - 0x73,0x76,0x87,0x03,0x10,0x87,0x51,0xf8,0x0d,0xcf,0xa1,0xc4,0x37,0x17,0xa7,0x55, - 0x7a,0xb8,0x4e,0x5c,0x0c,0x9a,0x24,0x3f,0xe1,0x45,0x67,0x7c,0xcf,0x19,0x2c,0x15, - 0x75,0xe9,0x19,0x72,0x30,0xc8,0xc8,0x19,0xcd,0x5b,0xdc,0x03,0x52,0xb9,0x37,0x8b, - 0xc2,0x96,0x2c,0x3d,0x72,0xc7,0x62,0xef,0x81,0x05,0x34,0x24,0x5f,0x17,0x10,0x6d, - 0xdd,0x30,0x9d,0xe3,0x19,0x7b,0xdb,0x36,0xa3,0xf0,0x41,0xe1,0x8f,0xbc,0x3f,0x93, - 0x8e,0xb2,0x01,0xbd,0x7f,0xeb,0x74,0xf7,0xef,0x8c,0xb3,0xdf,0x0c,0x40,0xd7,0x14, - 0x35,0x2a,0xfc,0xa1,0xb6,0xd4,0xc4,0x9b,0xe7,0x25,0xdf,0x26,0xe8,0x35,0x89,0xf4, - 0x04,0x68,0xdf,0x22,0x40,0xa7,0x5d,0x59,0xb6,0xd0,0x50,0x4c,0x6c,0xca,0x6f,0x74, - 0x99,0x5b,0x4b,0x8c,0x4b,0x27,0x6f,0xd4,0xd4,0x64,0xf2,0xc0,0x97,0x9b,0x76,0x5a, - 0x9d,0xb6,0xf6,0x98,0x5f,0x69,0xda,0xd9,0x7f,0xd8,0xe9,0x3e,0xd0,0xe5,0xb7,0x86, - 0xbc,0xc6,0x56,0xef,0xdb,0x2d,0x8a,0x2e,0xe3,0x68,0x5a,0x5a,0x71,0xcc,0x41,0xf8, - 0x13,0x23,0x05,0x7c,0x0f,0x05,0x11,0x40,0xfc,0x33,0x96,0xed,0x56,0xa7,0xdb,0x46, - 0x6f,0x6a,0x35,0xb9,0xb0,0x4b,0x81,0x08,0x85,0xc1,0x34,0xa0,0x16,0x12,0x73,0x26, - 0x5e,0x82,0x01,0x8f,0x0d,0x4e,0x8d,0x82,0xb1,0x9a,0xcc,0xe9,0xc8,0xa1,0xc3,0x81, - 0xfc,0xca,0x70,0x98,0xdc,0x1f,0x4f,0x0c,0x3e,0x31,0x90,0x89,0xac,0x4c,0x25,0x81, - 0x40,0xc1,0xe5,0x6e,0xec,0x05,0xee,0xbd,0x00,0x0a,0x3e,0x1a,0x43,0x5a,0x9c,0x12, - 0x83,0xe4,0xe7,0x0b,0xf9,0x99,0xa7,0x1b,0x3b,0xdc,0x55,0x5d,0x65,0xdf,0x62,0x67, - 0x75,0x6e,0x24,0xd3,0x9c,0x49,0x30,0x2d,0x69,0xb1,0x02,0xc1,0x94,0xc2,0x3c,0x46, - 0xc9,0x2d,0x0a,0x0d,0x73,0x0f,0x89,0x72,0xe2,0x4e,0x26,0x18,0xf1,0xbc,0x34,0xff, - 0xf3,0x45,0x90,0xf9,0x0e,0xd4,0x93,0x32,0x7b,0x96,0xb8,0xc0,0x62,0xff,0x4c,0x7c, - 0x3e,0x70,0x25,0x39,0x54,0x82,0x00,0xe4,0x6f,0x98,0xb2,0xb1,0x13,0x85,0x01,0x76, - 0xeb,0x18,0x53,0x50,0x43,0x3b,0x6e,0x61,0x8a,0x81,0x02,0x47,0xc6,0x8a,0xf1,0x34, - 0xad,0x34,0x23,0xb8,0x6b,0x0d,0xa4,0xef,0x31,0x60,0xaa,0xdc,0xb2,0x75,0xa8,0xc2, - 0xbc,0x2d,0x70,0x4d,0x34,0xdb,0xc6,0xc0,0x20,0x42,0x27,0x57,0x28,0xf2,0xeb,0x4e, - 0xb5,0x26,0xf6,0xf5,0xae,0xa9,0x69,0x46,0xdc,0xfa,0x8a,0x7a,0xe6,0x2e,0xae,0x68, - 0x74,0xa4,0xa7,0x77,0xc8,0x1c,0x13,0x20,0xf7,0x77,0x1f,0x2b,0x19,0x1d,0x25,0x47, - 0x90,0xe3,0x3d,0xb7,0xb4,0xb6,0xc0,0x22,0x24,0x41,0x67,0x2c,0x8a,0x50,0x5e,0x8a, - 0xef,0x2e,0xd2,0xb9,0xd1,0x72,0x79,0x48,0x8b,0x9d,0x31,0x90,0xa9,0x51,0x26,0x05, - 0x37,0x91,0xcf,0x0d,0x10,0xd2,0xf7,0x18,0xe5,0x38,0xb9,0xe7,0xfd,0x25,0xa7,0xa5, - 0x33,0x17,0xf1,0x5a,0xac,0x36,0x00,0x9f,0x3f,0x77,0x83,0x07,0xe4,0x5b,0x12,0xd8, - 0xa3,0x1f,0xd2,0x2c,0xf1,0x47,0x99,0x64,0x36,0xb2,0x19,0x9e,0x2c,0xcd,0x1c,0x62, - 0x6b,0x30,0x0a,0x3f,0x88,0x91,0x98,0x40,0x7c,0x0e,0x74,0xe7,0xa1,0xf3,0x90,0xa3, - 0x12,0x1d,0x48,0x3a,0x24,0x47,0xdb,0xe2,0x94,0x16,0x5f,0x0c,0x54,0x70,0x18,0xcd, - 0x07,0x20,0x49,0xa3,0x68,0x8e,0xe4,0x0b,0xf7,0x7b,0x76,0x7c,0x12,0x25,0xa7,0x0b, - 0x4f,0x3b,0x9e,0x87,0xd2,0x3f,0x62,0x82,0x76,0xda,0x2e,0xd0,0x6a,0x3c,0x72,0x08, - 0x03,0x31,0xea,0x26,0x0a,0xf9,0x22,0x8e,0x82,0x71,0xfc,0xc3,0x89,0xa1,0x7f,0xe0, - 0xec,0xb9,0xaa,0xd5,0x2e,0x98,0x74,0x14,0x76,0x2b,0x65,0x74,0x61,0x97,0xed,0x35, - 0xf4,0xef,0x82,0x43,0xf3,0x54,0x2e,0xc9,0xf3,0x79,0xcc,0xf1,0x21,0x38,0x91,0x7d, - 0x45,0x78,0x3e,0x20,0xae,0x68,0x1d,0x10,0x7a,0x9a,0x82,0xc6,0x1a,0x18,0x51,0xdb, - 0x78,0x77,0x6a,0xe7,0x32,0xf9,0x42,0x04,0x8d,0xe0,0xed,0x48,0x3f,0xfa,0xb7,0x8b, - 0x26,0x03,0x88,0xaa,0xb4,0x1d,0xa6,0x28,0x5b,0x08,0x6d,0xa2,0xa2,0x2a,0xf9,0x41, - 0x9e,0x6d,0x56,0xce,0xe3,0x16,0x29,0x5e,0x49,0x0c,0x9c,0x12,0x5d,0x5f,0x80,0xb3, - 0x5b,0x2c,0xa7,0xba,0x8a,0xe2,0x1d,0x9e,0xa0,0xeb,0x61,0x2b,0xe5,0xc7,0x4e,0x31, - 0x3f,0x65,0xe7,0xee,0x6c,0x53,0x74,0x82,0x5c,0x16,0xd4,0xb3,0x8a,0xe8,0xfb,0x48, - 0x09,0x6e,0x5c,0x3f,0x20,0xee,0x96,0x6f,0x0c,0x32,0xd4,0x27,0x2d,0x3b,0xb3,0x5d, - 0x78,0x66,0xcb,0xb3,0x37,0x23,0xe3,0x7d,0x3e,0xab,0xc1,0x33,0x45,0xc1,0xd5,0x01, - 0x52,0x2f,0x88,0x53,0x2e,0xb6,0x95,0x8b,0xa9,0xdc,0x31,0x29,0xae,0x69,0xc0,0x2a, - 0x91,0x35,0x2c,0x96,0xb8,0xb7,0x44,0xa8,0xd2,0x48,0xc2,0xd7,0x98,0x2c,0x40,0x74, - 0xc7,0x5b,0x8b,0x26,0xc8,0x0f,0xac,0x2a,0x77,0x57,0x69,0x49,0x2a,0x60,0x50,0xbd, - 0xc1,0xfc,0xb9,0x9f,0xd4,0x17,0xce,0xea,0x0a,0xe7,0x3a,0x70,0x24,0xaa,0xa9,0x5a, - 0xac,0x50,0x5a,0x90,0x16,0x6d,0xae,0x73,0xca,0x76,0xce,0x37,0x2a,0xc9,0xce,0x2b, - 0xda,0xb6,0xec,0xb4,0xf6,0x8b,0x1b,0x1c,0x95,0xd4,0xd5,0x36,0xb2,0x07,0x9a,0x86, - 0x65,0x01,0x3d,0xa7,0x69,0x6a,0xb2,0x02,0x8a,0x54,0x67,0xa9,0x55,0x3f,0x0c,0x55, - 0x97,0xde,0x9f,0x8f,0xaa,0xa2,0x9a,0x2e,0x75,0x5b,0x3b,0x3b,0xfb,0x4c,0x73,0x8b, - 0xdd,0x62,0x13,0x13,0x49,0x40,0x72,0xc6,0xaf,0x8e,0xa7,0xd3,0x8a,0x09,0x7b,0x10, - 0xdd,0x3a,0x44,0x1e,0xc5,0x14,0x47,0x9d,0xa1,0x24,0xf0,0xf1,0xe2,0x54,0x84,0x22, - 0xc0,0x90,0x0d,0x21,0x32,0xdf,0x30,0x61,0x29,0x08,0x03,0x56,0x39,0xb7,0x23,0x94, - 0x11,0x14,0xe7,0x84,0xca,0x61,0x50,0x3c,0x3e,0xf7,0x93,0x68,0x87,0x4b,0xf7,0x0b, - 0x4b,0xaf,0xa7,0x9f,0xce,0xdf,0xfd,0x66,0xc8,0x04,0x23,0x25,0xab,0x6c,0xb5,0xa9, - 0x8b,0x64,0x07,0xa0,0x87,0x26,0x26,0xb6,0xf9,0xcb,0xc5,0x89,0xc1,0x2f,0xf9,0x16, - 0xb4,0x04,0x86,0x04,0x77,0xd4,0x4e,0x4e,0xea,0xd3,0x70,0x4e,0x02,0xcc,0xc7,0x0f, - 0xa7,0xa8,0xbd,0x43,0x5e,0x50,0x9c,0x67,0x60,0xfc,0xec,0x85,0x9f,0x90,0xef,0x44, - 0x69,0x66,0xb0,0x90,0x83,0xde,0x5b,0x8b,0x10,0xb9,0x78,0x51,0x5c,0x25,0x94,0xfa, - 0x46,0x62,0x20,0x2d,0x00,0xdc,0xae,0xa4,0xf0,0x57,0xd9,0x99,0xf1,0xab,0x13,0xa7, - 0xd7,0xe5,0x9c,0xb8,0x8c,0x5b,0x24,0x83,0x8f,0x99,0x4d,0xd7,0x6a,0xa5,0x3d,0x24, - 0x23,0x28,0x16,0xcb,0xa8,0x74,0x3d,0xb3,0x52,0x95,0x72,0x5e,0x41,0xc0,0xe4,0xad, - 0x47,0x7a,0x4e,0x0d,0xd7,0x3e,0xe0,0x3e,0xb6,0x98,0x2b,0x76,0x60,0x08,0xa4,0x1e, - 0x8f,0xc2,0x29,0x63,0x5a,0x2c,0x26,0xc2,0x66,0xb1,0x0c,0x4c,0xdf,0xe9,0x48,0x1b, - 0xe8,0xca,0x8a,0xe1,0x8a,0x00,0x5b,0xc7,0x52,0x50,0xe6,0x2d,0x20,0x89,0x60,0x75, - 0xcc,0xab,0x44,0x61,0x98,0xf8,0xe3,0xa9,0xe7,0x88,0x8b,0xe6,0xf9,0x2e,0x1a,0x1f, - 0x8d,0xd7,0x99,0x08,0xf1,0xe7,0x55,0xa5,0x52,0xc0,0x80,0x11,0x6f,0xb5,0x92,0x16, - 0x78,0xa2,0x08,0xed,0xe6,0xbe,0xa0,0x42,0xc9,0xdd,0x43,0x76,0x57,0x28,0x39,0x74, - 0x17,0xa4,0xd9,0xe6,0xbc,0x29,0xb7,0x89,0x89,0x46,0x42,0xb2,0x77,0x5b,0xcf,0x2c, - 0xb9,0x45,0x95,0x1b,0x40,0x21,0xd2,0x0a,0xf9,0x14,0x1a,0xc8,0x9c,0x39,0x5e,0x14, - 0x7a,0xed,0x8d,0x12,0x42,0x67,0x59,0x1f,0xe3,0x81,0x4c,0x6e,0x17,0x04,0x48,0xbc, - 0x91,0x95,0x04,0x48,0x61,0x67,0x65,0xab,0x87,0x8e,0x50,0x7b,0x89,0xab,0x7c,0xf8, - 0x52,0x11,0xb9,0x4d,0xe0,0x1d,0x33,0xb4,0x71,0x0b,0x09,0x99,0x90,0x55,0x6e,0x21, - 0x78,0x0c,0x8b,0x64,0x6e,0x6f,0x6f,0x67,0x4f,0xe8,0x3b,0xb4,0x9b,0x87,0xd4,0x63, - 0x41,0x85,0xa2,0x5f,0x30,0xc4,0xab,0x53,0x5c,0x64,0x44,0xbf,0xb8,0xc0,0x78,0x61, - 0x19,0x43,0x58,0x2a,0xc0,0xb8,0xc8,0x8d,0x4a,0x2a,0xff,0xc5,0x95,0x40,0xa2,0x97, - 0x59,0xe1,0x4a,0x20,0xdb,0xf0,0x9c,0xa9,0x23,0x2e,0x02,0xda,0x96,0x17,0x01,0x6d, - 0xf3,0x45,0x40,0x02,0xb5,0xf2,0xbb,0x7d,0xf4,0xab,0x7e,0x50,0x0a,0x67,0xd4,0x49, - 0x8d,0x37,0xe3,0xee,0xde,0x5e,0xe7,0x15,0x5d,0xee,0x63,0x8b,0x6b,0x7f,0x98,0x50, - 0x71,0x15,0x72,0x4d,0x98,0xb1,0x76,0xdf,0x21,0xe2,0xb2,0xa0,0xb7,0x3d,0x8c,0xfa, - 0x64,0x93,0x5e,0xcd,0x36,0x48,0x5d,0x73,0x72,0xfe,0x0f,0x20,0x37,0xc4,0x47,0xa4, - 0xdb,0x20,0xf8,0xec,0x15,0x65,0x7b,0xbe,0xd5,0xd6,0x44,0x89,0x17,0xc6,0x1a,0x47, - 0x61,0xea,0xd9,0xd9,0x5d,0xf6,0x19,0x4f,0x24,0xa1,0x09,0x9b,0x77,0x1f,0x7b,0x9a, - 0xc4,0x9f,0x21,0x99,0x7e,0xd1,0xae,0xd8,0x76,0xa1,0x89,0xcf,0x58,0x0a,0x79,0x0a, - 0x1b,0xa4,0x82,0x91,0x67,0x33,0x3f,0x06,0x14,0xca,0xc6,0x2b,0x85,0x41,0xd6,0xb6, - 0x61,0x23,0xfd,0x2c,0x2e,0x8a,0x29,0x78,0x41,0x91,0xab,0x4a,0xe0,0x0f,0x96,0xa8, - 0x00,0xca,0x7a,0x6d,0x3b,0x1b,0x06,0xbd,0xcb,0x2b,0x1b,0x43,0x06,0xf1,0xef,0x5d, - 0xaf,0xd5,0xb1,0xc7,0x20,0x93,0x64,0x3d,0xd3,0xb4,0xd3,0xc5,0x14,0x93,0x53,0x2f, - 0xc0,0xe4,0xe1,0x22,0xbd,0xef,0xf1,0xa9,0x38,0x1e,0xdd,0x85,0xe2,0x19,0x58,0x3a, - 0x7e,0x7a,0xd4,0x2f,0xd4,0x08,0xfc,0x0b,0x04,0xad,0x38,0x7c,0x86,0x57,0x87,0xda, - 0xe4,0x8b,0xd9,0xd9,0x68,0x50,0x7a,0x58,0xe1,0x47,0xe8,0x88,0x3c,0xd4,0x53,0x67, - 0x4c,0xc2,0xa2,0x11,0xfa,0x2d,0xb5,0x21,0xb5,0x17,0x37,0xb0,0x8b,0x09,0x74,0x60, - 0x70,0x7d,0xb9,0x73,0x75,0x64,0x1a,0x4b,0x73,0x0b,0x9f,0xb6,0xcc,0x47,0x53,0x1e, - 0xf0,0x5d,0x5f,0x76,0x31,0x08,0x69,0xd7,0x12,0xb7,0x99,0x02,0x23,0x8c,0xba,0x5e, - 0xc8,0x07,0xab,0xeb,0xfa,0xb2,0x73,0x75,0x65,0xe9,0xf9,0x3a,0x79,0xbe,0x54,0xe5, - 0xdb,0x32,0x0d,0x93,0xf2,0x6e,0x61,0x63,0x57,0xa5,0x70,0x92,0xe1,0xa0,0xd3,0x0f, - 0x75,0x8b,0xc8,0x90,0x2c,0x22,0xe5,0x32,0xac,0xbf,0x83,0xa7,0xd0,0x1b,0x36,0x8b, - 0x0c,0xb7,0x4c,0xc7,0xdc,0x9a,0x60,0xbf,0xa4,0xf9,0x23,0x46,0x12,0xc2,0x24,0xee, - 0x65,0xa1,0x67,0xe5,0x32,0xd4,0xc7,0xfa,0x72,0x7c,0xb0,0x28,0x60,0x3d,0xc8,0xfa, - 0xf9,0x94,0xe4,0x7d,0x56,0x5e,0x6e,0x85,0x03,0x73,0xc8,0xf9,0x26,0x5c,0xcc,0x9b, - 0x7c,0x03,0x02,0x5f,0xd9,0x0d,0xcf,0x85,0x5b,0x78,0x84,0x31,0x64,0xf3,0xf7,0xdb, - 0x2d,0xeb,0xdb,0x6d,0x11,0x09,0x47,0xdc,0x53,0x2b,0xae,0x84,0x11,0xb4,0x47,0xce, - 0xba,0x76,0x51,0x54,0xf9,0x12,0x54,0xe5,0x45,0x87,0xab,0x07,0x0f,0x49,0xa3,0x70, - 0xe4,0x66,0x30,0x64,0x79,0xf9,0x11,0xdb,0x88,0x8a,0x39,0x93,0xf5,0x8b,0x35,0x2a, - 0xeb,0x27,0xd9,0x58,0x65,0x95,0x75,0xa8,0xb5,0x97,0xc7,0x1b,0x64,0xdb,0xeb,0xc7, - 0x92,0x8b,0xa0,0x42,0x39,0x61,0xd2,0xc9,0x06,0xae,0xd0,0x9c,0xfc,0x70,0xe9,0x5f, - 0x01,0xc0,0xa1,0x61,0x04,0x8b,0xa8,0x4a,0xff,0x06,0xa8,0x58,0x7c,0x95,0x2b,0xf1, - 0x41,0x5d,0xb9,0xf3,0x58,0xe9,0x82,0x0e,0xf2,0xd1,0x2c,0x82,0x75,0x93,0xda,0xda, - 0x0d,0xcc,0x78,0x73,0x2f,0x05,0xc4,0xf3,0x92,0x79,0x0b,0x5e,0xe4,0x9a,0x76,0xb3, - 0x37,0xe1,0x78,0x80,0xf7,0xf2,0x4a,0xd7,0x90,0x78,0x0b,0xdf,0x38,0xb2,0xd2,0x4f, - 0x14,0xa7,0xe2,0x50,0xfb,0xce,0x29,0x2d,0x79,0xaa,0x3b,0x5e,0x79,0x09,0xcd,0xd8, - 0xbf,0xa1,0x88,0x2c,0xda,0x1d,0x34,0xd0,0xa5,0xfe,0xb8,0x68,0x05,0x01,0xcf,0xfd, - 0x06,0xd6,0xae,0xdf,0x2c,0x83,0x77,0x1c,0x90,0x65,0x52,0x93,0x7a,0x82,0x69,0x74, - 0x62,0x2a,0xad,0x96,0x31,0x4c,0x24,0x7e,0xe1,0x03,0x51,0x2e,0x83,0xef,0x13,0x3f, - 0x49,0x33,0x7a,0xe5,0xe9,0xa5,0xb1,0x59,0x85,0xb1,0x55,0x46,0x92,0xc7,0x8e,0x2c, - 0x43,0xf1,0x47,0x17,0xa3,0xa5,0xf2,0x20,0x25,0x50,0xcd,0x29,0xe9,0xa8,0xd5,0xed, - 0x28,0xc6,0xb8,0x58,0x86,0xae,0x41,0x15,0x21,0x10,0x72,0x48,0xeb,0x5e,0x7b,0x26, - 0xae,0x9e,0xef,0x71,0x7f,0xc6,0x08,0x3d,0x2a,0x9f,0xcf,0xa1,0x46,0x01,0x4b,0x9b, - 0xc5,0x60,0x33,0x2a,0xef,0xb2,0xa1,0x3a,0x91,0xde,0xa3,0x38,0x20,0xed,0xe1,0x30, - 0x86,0x1d,0x5e,0x69,0xf1,0x0f,0xcc,0x45,0x11,0x04,0xf4,0x6c,0x68,0x55,0x8a,0x3a, - 0x54,0xb2,0x18,0x15,0x71,0xc5,0x30,0x8d,0x24,0x05,0x4e,0x6c,0xc0,0x42,0xbc,0x39, - 0xfa,0x7d,0xbc,0xf5,0xbb,0x23,0xff,0x68,0x26,0xa9,0x93,0x5b,0xca,0x75,0x84,0x45, - 0xe9,0x46,0x1c,0x79,0x04,0xf0,0x09,0x04,0xd7,0x30,0xca,0xb4,0xd3,0x08,0x53,0x5c, - 0x14,0xc2,0xd6,0xae,0x28,0x73,0x53,0x38,0x12,0xd4,0xd9,0x9b,0xd5,0xfe,0x9f,0x2b, - 0xbb,0x45,0xdc,0x4e,0x61,0x97,0x47,0x55,0x13,0xee,0xdf,0x31,0xf1,0x25,0x5c,0xad, - 0x38,0x69,0x60,0xbf,0x17,0x3e,0x21,0x37,0xb7,0x1a,0xe6,0xef,0xf9,0x19,0xcb,0xeb, - 0xd0,0xbb,0x3d,0x14,0x76,0x93,0xbf,0x0b,0x5d,0xff,0xef,0xa6,0x03,0xcf,0xaf,0x5b, - 0x7c,0x5e,0x00,0x1f,0x79,0xb6,0x52,0x79,0xd6,0x38,0x5d,0xf8,0x78,0x62,0x89,0x46, - 0xaf,0xa9,0x63,0x4a,0xea,0xa6,0x77,0xee,0x02,0x0f,0x4c,0x67,0x5e,0x10,0x8b,0x23, - 0x94,0x74,0x31,0x9f,0xbb,0xc9,0xbd,0xd8,0xa1,0xf1,0x38,0xca,0xbf,0xa3,0x26,0x61, - 0xab,0xc2,0x5a,0xe5,0x45,0xd0,0x4e,0xc9,0xcc,0x1a,0xaa,0xfd,0x09,0x6a,0x11,0xd3, - 0x47,0x28,0xa5,0xcd,0xd0,0x68,0x8e,0x0c,0x0e,0x36,0x63,0xea,0xc9,0x00,0x02,0xd3, - 0x6e,0xa0,0x8d,0x84,0xb1,0xcd,0x22,0x1d,0xfc,0xf2,0x01,0x1f,0xff,0x27,0x55,0xe8, - 0xb6,0x31,0x91,0x16,0x14,0xd8,0x17,0x94,0x5c,0x7e,0x0f,0x11,0x3e,0xb8,0x29,0xbc, - 0x06,0xea,0x72,0x68,0x94,0xff,0x43,0x9d,0x13,0x64,0x56,0xa6,0xa9,0x9c,0x3f,0x55, - 0xf9,0x5f,0xd3,0x41,0x65,0x5e,0x4e,0xdc,0xa6,0x52,0x29,0x21,0x34,0x66,0x35,0xff, - 0xa5,0x95,0x73,0x79,0x2e,0x91,0x1b,0x05,0x94,0xff,0x0b,0x6b,0xcc,0x21,0xb8,0x0c, - 0x1b,0x5a,0xc0,0xe8,0xf3,0x13,0x71,0x51,0x06,0x72,0x07,0x80,0x0c,0x52,0x8f,0x91, - 0x0f,0x5b,0x53,0x92,0x68,0x4d,0xc4,0x52,0x59,0x22,0x98,0xd1,0x5c,0x67,0x22,0x8a, - 0x32,0xe2,0xd4,0x8d,0x27,0x29,0x9f,0x1a,0x55,0xd6,0x98,0x89,0x48,0x20,0x31,0x20, - 0x25,0x58,0x09,0x0c,0x69,0x9a,0x5b,0x39,0x3b,0x23,0xc8,0x17,0x2c,0x42,0x14,0xef, - 0x30,0xc6,0x81,0x71,0x1d,0xa2,0xa3,0x85,0x43,0x38,0x7d,0x4a,0x2b,0x20,0x45,0xc3, - 0x61,0x58,0x64,0xa8,0x7a,0x23,0x7c,0x4d,0x16,0x74,0x6a,0x36,0x67,0xed,0x34,0x1d, - 0x64,0x78,0x0e,0x73,0x98,0x20,0x41,0xc7,0x19,0x5d,0xe3,0x8c,0xba,0x08,0xe1,0xe1, - 0x27,0x1d,0x02,0x2a,0x64,0xa5,0x8c,0x97,0xe7,0x8b,0xe9,0x27,0xa0,0xb9,0x4d,0xb5, - 0x69,0x7e,0xa3,0x8a,0x01,0xf3,0x56,0xb0,0xb9,0x42,0xe6,0xd0,0xf5,0xc3,0x34,0xb7, - 0xcf,0x2a,0x20,0x38,0xa4,0x41,0x65,0x3a,0xd9,0x2b,0x57,0xa0,0x47,0xc3,0x2a,0x65, - 0x2a,0xd3,0x46,0x07,0x92,0xf1,0x8e,0x79,0x7a,0xf4,0x82,0x41,0xab,0x53,0x6c,0xed, - 0x3d,0x1a,0xfd,0x37,0x67,0xee,0xbd,0xfd,0x47,0xc1,0x0f,0xf7,0x0f,0xb1,0x49,0x6e, - 0xff,0x9e,0x6e,0x6d,0x57,0xdc,0xf6,0x29,0x4f,0x61,0x43,0x46,0x93,0x7e,0x76,0xba, - 0xbd,0xda,0xd8,0x80,0xea,0x1c,0x3a,0xa9,0xff,0x94,0xa7,0x5a,0xaf,0xdb,0x05,0x47, - 0xfe,0xc7,0x95,0x8e,0xfc,0xd0,0xab,0x0f,0xc4,0xd0,0x00,0xf3,0x2c,0xbd,0xec,0x07, - 0xf0,0xac,0x5d,0x90,0x81,0x9d,0xa2,0x7d,0x83,0x5d,0x2d,0x44,0xc5,0xcb,0x40,0x70, - 0xcf,0x80,0x2e,0xbd,0xf6,0x23,0x6f,0xa9,0x37,0x29,0x6e,0x37,0x14,0xb1,0x8f,0x6b, - 0x4d,0xb9,0xd4,0x8d,0xe2,0x7a,0x6f,0x52,0xce,0x19,0x44,0x83,0xd4,0xc9,0xa2,0xf7, - 0xa8,0xe7,0x64,0x27,0x21,0xac,0x08,0x3d,0xf0,0x02,0x04,0x12,0x42,0xb1,0xa1,0xa1, - 0x5f,0xd5,0x93,0x59,0x74,0x36,0x1b,0x78,0xc0,0x8f,0x14,0x6b,0xa2,0x26,0x33,0x05, - 0x94,0x20,0xb2,0x30,0x82,0xa6,0x05,0xf5,0x33,0x13,0xe9,0x69,0x17,0x6a,0x50,0x6b, - 0x32,0x20,0xe2,0x6e,0x7b,0x63,0x43,0x4d,0x53,0x06,0x3d,0xb1,0x2c,0xfe,0xae,0x8a, - 0x09,0x9b,0x6a,0xac,0x4a,0x58,0x54,0xeb,0xd0,0xc0,0x64,0xe9,0x8f,0xb4,0xdf,0xa6, - 0x11,0xf5,0xe4,0xcc,0x29,0x63,0x73,0xce,0xca,0xf5,0xca,0xcc,0xbb,0x22,0x33,0xc2, - 0xb1,0x38,0x39,0x05,0x58,0x4a,0x36,0x34,0x55,0x4c,0x28,0xd0,0x35,0x98,0x9e,0xe6, - 0xef,0xe7,0x5b,0x16,0xfe,0x3a,0xdf,0x29,0x36,0xf4,0x9b,0xb9,0x55,0x60,0xb3,0x94, - 0xb8,0x20,0xf9,0x5a,0xba,0xe0,0x91,0xb3,0x62,0xfa,0xba,0x69,0x05,0x82,0x35,0xa6, - 0xe0,0xa9,0xdc,0x5b,0x39,0xa4,0xd6,0x1c,0xe4,0x06,0x09,0x07,0x1b,0x85,0xc3,0xf1, - 0x00,0x93,0x84,0xc4,0x05,0x5c,0x1b,0xa5,0x39,0xb0,0x94,0xb2,0x77,0x62,0x32,0x58, - 0x22,0x43,0xd9,0x68,0x91,0x61,0x7c,0x81,0x25,0xd6,0xbd,0x25,0x32,0xca,0x06,0xe0, - 0xdb,0x56,0xc7,0xea,0x73,0x8d,0xfa,0x27,0xfe,0xf0,0x28,0x31,0x88,0x3f,0x15,0xb1, - 0x08,0x99,0xc5,0x4b,0xea,0x42,0x50,0x73,0x17,0xeb,0x0d,0x73,0xb3,0x37,0xc5,0x42, - 0x15,0x54,0x41,0x4e,0x8b,0xe5,0x0d,0xea,0xde,0x8d,0x2d,0x67,0xe2,0x63,0x94,0x79, - 0x04,0x39,0xfb,0xc6,0x92,0xe2,0x85,0x0e,0x38,0x28,0x48,0x90,0xc3,0x62,0x92,0x66, - 0x0a,0x20,0x48,0x2c,0xa8,0x99,0x5f,0xaa,0x15,0xb6,0x30,0x1b,0x3a,0x2d,0xee,0xcb, - 0xd1,0xc5,0x8b,0xe2,0x5d,0x80,0xc8,0x78,0xa3,0xa9,0x66,0x81,0x46,0x68,0x62,0x45, - 0x99,0x73,0xcf,0x3f,0x01,0x61,0x70,0xc4,0xcd,0xa9,0xd8,0x10,0x52,0x46,0x3f,0x14, - 0xde,0xb9,0xa5,0x5c,0xc5,0x7b,0x64,0xa5,0xaf,0x2d,0x5b,0xc9,0xb9,0xe2,0x46,0xe6, - 0x75,0xe5,0xd4,0xbd,0xb1,0xe5,0xa2,0x52,0x55,0x42,0x9b,0xbe,0xe6,0xde,0xab,0xfb, - 0xe9,0x4a,0x52,0xe1,0x06,0xf9,0x45,0x87,0x26,0x6c,0x1a,0x37,0xc2,0x6e,0x93,0x36, - 0xc3,0x45,0x88,0xa7,0x0d,0x66,0xaf,0x29,0xb2,0xe5,0xd7,0xe6,0x4a,0x9e,0x4e,0xa8, - 0xb6,0x68,0xcf,0x1c,0xde,0x1b,0x33,0x0c,0x3d,0xd3,0x13,0xbe,0x64,0x65,0x10,0xb3, - 0x14,0x55,0x02,0x31,0x0b,0xb8,0x4a,0x76,0x52,0x58,0x82,0xc0,0xcb,0xe5,0x28,0x0c, - 0x29,0x01,0xf5,0x6a,0x2a,0x12,0x64,0x53,0x45,0xaf,0x34,0x95,0xc4,0x51,0x67,0xaf, - 0x47,0x9e,0xf9,0xf5,0x3e,0xc9,0xbc,0xab,0x35,0xd5,0x1a,0x57,0x84,0xb9,0xb8,0x21, - 0x12,0x8b,0xc3,0xbb,0x38,0xed,0x36,0x73,0x07,0xf1,0x4e,0xdb,0x71,0xe4,0xcd,0x8d, - 0x77,0x83,0xe2,0x66,0x25,0x88,0x02,0x65,0x57,0xde,0x20,0xfa,0x0e,0x58,0x70,0x28, - 0x9b,0x91,0xb3,0x94,0xc8,0x5d,0x25,0xbe,0x2a,0x54,0x2a,0x51,0x06,0xf4,0x74,0x26, - 0x2a,0x2c,0xd7,0xef,0x1c,0x71,0xc2,0x02,0x92,0xe0,0xfa,0x41,0xf9,0xab,0xf8,0xd6, - 0x6f,0xcc,0xca,0x17,0x97,0x4f,0x45,0xd0,0x39,0x5f,0xc5,0x43,0xa1,0x70,0xf5,0x5c, - 0xe2,0xc8,0x7c,0xbd,0x38,0x34,0xb7,0x68,0x39,0x9a,0xaf,0xb7,0xe1,0x99,0xd6,0x98, - 0xb5,0x85,0x6d,0x88,0x20,0x1f,0x20,0x0d,0x78,0xb0,0x34,0x8f,0x36,0xc9,0x17,0x9b, - 0xdb,0x05,0x1a,0xc7,0x3e,0xd9,0x32,0xd0,0x1c,0x7b,0x62,0xf3,0xca,0x05,0x28,0xe9, - 0xc1,0x4f,0xfa,0xf8,0xbe,0x32,0x40,0x27,0x7e,0xcc,0x65,0xb1,0x76,0x79,0xf2,0x4e, - 0x5d,0xba,0xe2,0x62,0x29,0xee,0x61,0x10,0x70,0x37,0x1c,0xb2,0x84,0xaf,0x09,0xc4, - 0xa1,0x40,0x18,0x85,0x03,0x1f,0x50,0x45,0xcc,0x60,0xfd,0xa5,0x1e,0xa8,0xae,0x8e, - 0x42,0x9e,0xc3,0x28,0xa4,0x00,0xa5,0xdc,0x95,0x77,0x61,0x16,0xfd,0xc3,0xf7,0x6e, - 0xad,0x4a,0x4a,0x73,0x49,0x06,0xbc,0x3d,0x58,0x79,0x2e,0xb2,0x81,0x74,0x71,0xcb, - 0x63,0x85,0x93,0xfa,0x80,0x43,0x1c,0x4b,0x5f,0x09,0x46,0xaa,0xe2,0xd6,0x26,0x70, - 0x0d,0x90,0x4b,0xfc,0x02,0xc2,0x37,0xf1,0xb6,0x82,0x76,0xaf,0x98,0xbf,0xd5,0xb1, - 0x7a,0x4d,0x91,0x67,0x6b,0xbc,0x55,0xaa,0xec,0x3f,0x8a,0xef,0x54,0xab,0x80,0x59, - 0xb9,0x4f,0xc7,0xe4,0xcd,0xd6,0x94,0x00,0xf2,0x06,0xff,0x5f,0x6f,0x57,0xdb,0x9c, - 0xc6,0x91,0x84,0xbf,0xeb,0x57,0xa0,0x4d,0x4a,0x05,0x06,0x24,0xe4,0x4b,0x72,0x77, - 0xa0,0x85,0x72,0x2e,0xe7,0x94,0xcb,0xb9,0x5c,0x4a,0xae,0xd4,0x7d,0xb0,0xec,0x2a, - 0x04,0x48,0xa2,0x84,0x16,0xb2,0xbb,0x46,0x52,0x80,0xff,0x7e,0xfd,0x74,0xf7,0xbc, - 0xed,0x0b,0xa8,0x72,0x2f,0x2e,0x97,0xcd,0xee,0xce,0x6b,0xcf,0x4c,0xcf,0x74,0x4f, - 0xf7,0xd3,0x9a,0x95,0x38,0x0c,0xc3,0xdd,0xcd,0x02,0xb8,0xbb,0x79,0xb2,0x8a,0x83, - 0x35,0x42,0x54,0x4a,0x56,0xea,0x8e,0x89,0x89,0x37,0xc0,0xa3,0x3d,0x48,0xa2,0xac, - 0xbb,0xf9,0x13,0xaf,0x14,0xb3,0xe6,0x06,0x7c,0x58,0x96,0x90,0x44,0x06,0x81,0x7b, - 0x6c,0x4e,0xba,0xe2,0x34,0x94,0x8f,0xef,0xf9,0x78,0xdc,0x18,0xa7,0xb7,0xac,0x33, - 0x60,0xa3,0xdd,0xe5,0xcd,0x0d,0x6c,0x78,0x24,0x74,0x51,0xa1,0x17,0x74,0x74,0x79, - 0x3f,0x7b,0x6e,0x56,0x93,0x76,0x63,0xab,0xae,0xa5,0xfb,0xce,0x68,0x10,0x89,0x9c, - 0x43,0x31,0x8a,0x37,0x94,0xd1,0xb7,0xe1,0x92,0x05,0x18,0x52,0x05,0xaf,0xa8,0x38, - 0xc8,0x75,0x16,0x93,0x95,0xa5,0x69,0x0f,0xfa,0x1c,0xcb,0x4f,0xea,0x0f,0x5a,0x09, - 0x4d,0x79,0x51,0x6c,0x24,0x17,0x94,0x5f,0xdb,0x7a,0x72,0x92,0x5c,0xf0,0xe2,0x36, - 0x8f,0xf8,0x84,0x0b,0xb4,0x37,0x79,0x33,0xc1,0x5e,0xca,0x1f,0xed,0x8b,0x56,0x82, - 0x88,0x74,0xa8,0x1e,0xe9,0x0c,0xbb,0xf0,0xf0,0x4a,0x5c,0xc9,0x43,0xea,0x8f,0xa5, - 0x56,0x45,0xbf,0x50,0xc2,0xc0,0x52,0xd1,0x10,0xc2,0xd1,0xa8,0xe7,0xc2,0xae,0xb8, - 0x03,0x7b,0x19,0x73,0xf1,0x61,0x89,0x6d,0x84,0xed,0xdc,0x02,0xdc,0xc5,0xd9,0x1a, - 0x5c,0x07,0x69,0x7f,0x10,0x97,0xdb,0x66,0x6b,0xe7,0x4b,0x27,0x75,0xe5,0xd5,0x62, - 0x38,0xa6,0x95,0x18,0x8e,0xe0,0x0e,0x03,0xf1,0xf2,0xf4,0x56,0x9b,0x76,0xa1,0x9d, - 0x5a,0xc4,0x9d,0x79,0x29,0x74,0x33,0xad,0x1e,0x1c,0x50,0xd8,0xcc,0xc1,0x2a,0x9b, - 0xa1,0xd1,0xfe,0x68,0x7e,0x38,0x0c,0x68,0xda,0xf0,0x39,0x9d,0xfd,0xb2,0xb2,0x59, - 0x07,0x7e,0x56,0x0f,0xe9,0xdc,0xbe,0x52,0xc0,0xf3,0x70,0xe1,0x14,0x85,0xa8,0x2c, - 0xb7,0x7c,0xa4,0x6e,0x49,0xea,0x34,0xf7,0xaa,0xb1,0x3d,0xb6,0x2d,0x78,0xba,0x90, - 0x69,0x7e,0xca,0xaa,0xf8,0xd8,0x2e,0xe3,0x81,0xa9,0xbb,0x50,0xc2,0xce,0x34,0xaa, - 0x1d,0x4f,0x0b,0xc5,0x98,0x1c,0x3d,0xff,0xfd,0xb0,0x58,0x80,0xd4,0xa6,0xbd,0x72, - 0x5c,0xc3,0x36,0x61,0xa7,0x72,0x42,0xf0,0xc5,0x23,0xf2,0x93,0xac,0x1c,0xb7,0x87, - 0xea,0x52,0xb1,0x19,0x2c,0xb7,0xcb,0xd3,0xe7,0x0d,0xde,0xd2,0x60,0x0a,0x06,0x19, - 0xd1,0x8e,0x11,0x0a,0x9b,0x09,0xcd,0xff,0x9d,0x38,0xc4,0xd0,0x48,0xee,0xfc,0x49, - 0xcb,0xb3,0xbd,0x3c,0xc7,0x14,0x42,0xc7,0x73,0x9f,0xf1,0x7a,0x61,0x96,0xc4,0xae, - 0x24,0x4b,0x97,0x0b,0x02,0xd6,0x76,0x50,0x8e,0x07,0xb3,0xeb,0xba,0xd5,0x39,0x7f, - 0xdd,0x7b,0x51,0x71,0xcc,0x63,0x8b,0xed,0x7a,0x3b,0xcf,0x5f,0xd6,0x18,0x3a,0x74, - 0x55,0xac,0x43,0x13,0x9b,0x8d,0x8d,0x31,0xe5,0xb2,0x02,0xe7,0x2a,0x62,0xae,0x51, - 0xe5,0x22,0x1d,0x78,0x9c,0xd7,0x77,0x61,0xe7,0x5c,0x6f,0x80,0x21,0xf8,0xeb,0x2a, - 0xda,0x6e,0xdd,0x23,0x2c,0x86,0x23,0x03,0xdb,0x1f,0x17,0xde,0x8f,0xce,0xfb,0x98, - 0xee,0x55,0xf5,0xe8,0xb4,0xb2,0x9a,0x88,0x96,0xdb,0x4c,0x25,0x54,0x51,0xb8,0x30, - 0x0a,0x0e,0xb2,0x5c,0xcf,0xdf,0x13,0xd6,0xdc,0x6f,0x5e,0x54,0x3e,0x4b,0xa6,0x2f, - 0xd9,0x0b,0x38,0x13,0xc2,0xf3,0x05,0x71,0x49,0x6d,0x9d,0xd9,0x64,0xbc,0x32,0xc1, - 0x51,0x83,0xf6,0x57,0x1f,0x06,0x71,0xe0,0xb6,0xb1,0xdf,0x06,0xde,0x3c,0x0b,0x8a, - 0x96,0xb2,0x17,0x86,0xb0,0x3f,0x45,0xd4,0x5c,0xea,0xd4,0x24,0x4f,0x17,0xef,0x71, - 0x7d,0x52,0x33,0x50,0xaa,0x72,0xde,0x1d,0xbd,0x64,0x7e,0xb0,0x96,0xb5,0x6a,0x76, - 0x4c,0x18,0x1e,0x97,0x8a,0x5b,0xb1,0xbe,0xf1,0x07,0x20,0x58,0x6c,0x55,0xa3,0x14, - 0xbc,0x35,0xb1,0x50,0x83,0xe3,0x03,0xd4,0xf8,0xf1,0xe4,0x1a,0x48,0xb9,0x48,0xd3, - 0x64,0x4c,0xf2,0xa8,0x65,0x61,0xae,0x8e,0xcf,0x3e,0x5e,0xa5,0x57,0xc9,0x27,0x15, - 0x0d,0xf8,0x5a,0xc2,0x16,0x50,0x39,0x70,0xdc,0xa6,0x87,0x29,0x4b,0xda,0xbf,0x8c, - 0x53,0xa8,0x12,0x90,0x49,0x3f,0xc0,0x62,0x2e,0x76,0x54,0x95,0x71,0xc6,0x4b,0x8d, - 0x6c,0x40,0xe3,0x4c,0x79,0x1d,0x7f,0xa2,0x07,0x5c,0xb8,0x70,0x92,0xb6,0x3e,0x0d, - 0x82,0x51,0xd9,0x49,0xb7,0x82,0x5c,0xa1,0x8e,0xcf,0x0b,0x90,0x0e,0x95,0x5c,0xb7, - 0x2b,0x67,0x1a,0xd1,0x5b,0xdf,0xcd,0x16,0xf0,0x36,0xb6,0x8a,0xbd,0xd3,0x28,0x58, - 0x38,0x5e,0xb9,0x31,0xae,0x08,0x37,0x5e,0xdd,0xa6,0x39,0x55,0xdb,0xb0,0xc7,0x13, - 0x31,0xd2,0xea,0x85,0x8b,0x1c,0x55,0x5b,0x99,0x23,0x93,0xbb,0xf2,0x81,0x14,0x8f, - 0x57,0x56,0x39,0x46,0xc3,0xb0,0xbd,0x4a,0xb7,0x57,0xc9,0x59,0xc5,0x89,0xda,0xe9, - 0xaf,0x16,0xac,0xbf,0x12,0x6a,0xca,0x10,0x2e,0xb6,0xdb,0x85,0x39,0x84,0xf4,0x70, - 0x2a,0x89,0xbe,0x32,0x82,0xe9,0xa0,0xa4,0x33,0xa5,0x63,0x20,0xdf,0x84,0x67,0x8a, - 0x3a,0x00,0x70,0xe2,0x3c,0x3b,0x5a,0xc4,0x0b,0xef,0x28,0xd5,0x1c,0xf5,0x3f,0x0e, - 0xbf,0xfe,0xb4,0x85,0x31,0x2b,0x34,0xbb,0x57,0xd9,0x2b,0x7a,0xfe,0xea,0x53,0xcb, - 0x2a,0xcb,0x50,0x4e,0xbe,0x5c,0xb0,0xd1,0x23,0xd4,0xee,0x63,0x36,0x7a,0x66,0x73, - 0xe9,0x49,0x3a,0x5f,0xe5,0x7c,0xda,0x71,0x8a,0x86,0x45,0xa0,0x4c,0x40,0xff,0x7d, - 0x67,0xc4,0xcb,0x77,0x1f,0xde,0xc3,0xa4,0xe1,0xec,0x33,0x1b,0xd8,0x7f,0x7d,0xd6, - 0x11,0x4b,0xfb,0xac,0xca,0xc4,0x5e,0x3c,0x4b,0x02,0x4b,0x7b,0xdf,0x3c,0xd3,0x59, - 0xdd,0x77,0x50,0xa0,0x75,0x21,0xa0,0x32,0x45,0x90,0x2f,0xf8,0xe4,0xa8,0x0e,0x39, - 0x0b,0x5d,0x0f,0xce,0x3e,0xfb,0xb9,0x2a,0x13,0x34,0x8d,0x6f,0xc0,0xd6,0xf8,0x12, - 0xb4,0x28,0xb5,0x98,0x3a,0x96,0x1d,0x0e,0xce,0x3e,0x3b,0x47,0x0e,0x4a,0x36,0x55, - 0x47,0x8e,0xcc,0x79,0x72,0xc0,0xf7,0x63,0xf6,0x68,0xaf,0x0d,0x02,0x47,0x8e,0x4c, - 0xcb,0x08,0xdd,0x2a,0x40,0x27,0xbc,0xc9,0x4a,0x8e,0x15,0xac,0x39,0x6b,0x08,0x42, - 0x4e,0x13,0x26,0x9c,0xdb,0xd5,0xe3,0x94,0x06,0x8f,0x32,0x28,0x60,0x8d,0x18,0xe1, - 0xf0,0x52,0x09,0x7c,0xb9,0x11,0x7a,0xc1,0x2b,0x82,0xed,0xbe,0x83,0x7c,0x69,0xd1, - 0xc2,0x9f,0xca,0x18,0x37,0x1e,0x53,0xd8,0x82,0xf3,0xb2,0x51,0x59,0xc2,0x19,0xe1, - 0xc1,0xa1,0xc2,0x18,0xf1,0xb9,0x92,0xe1,0x01,0x10,0x14,0xcc,0x43,0x6d,0xfd,0x01, - 0xfe,0x40,0xa9,0x46,0xdd,0x52,0x2a,0xb5,0x00,0xb6,0xe6,0xda,0xb0,0x4a,0xd7,0x57, - 0xd8,0x78,0x39,0x87,0xce,0xfe,0xac,0x66,0x36,0x05,0xa0,0xb9,0xb4,0xa6,0x2f,0xe7, - 0xd9,0x7d,0x26,0x0b,0x7e,0xe3,0xc3,0xe2,0x5b,0x0d,0x1d,0x73,0x96,0xd2,0x3a,0x9e, - 0xa8,0xf9,0x00,0xa6,0x7c,0xc5,0x2a,0x57,0xa4,0x3e,0xd6,0xf9,0x82,0x1f,0x03,0x0f, - 0xee,0x98,0xe1,0xf2,0x53,0xbe,0xf1,0xdf,0xb8,0xdf,0xf1,0xf9,0xc0,0x2e,0x2f,0xbc, - 0xd0,0x7d,0xa6,0xbc,0xca,0x82,0x5b,0x50,0x9f,0x51,0x29,0x2f,0x5a,0xcf,0xd2,0xd8, - 0x63,0x83,0x43,0x75,0x0f,0x16,0x69,0x9c,0x3e,0xb6,0x84,0xdb,0x23,0x85,0x11,0x69, - 0x34,0x89,0x01,0x42,0x03,0x29,0xe2,0x90,0x26,0x24,0xcf,0xcf,0xe2,0x02,0x73,0x1d, - 0xd4,0x5c,0x77,0x77,0xa0,0xce,0x39,0x70,0x59,0x6d,0x75,0x17,0x7c,0x5d,0x1d,0x71, - 0xe6,0xc9,0xcd,0x83,0x81,0xc3,0x3d,0x90,0xfd,0xce,0xcf,0x0b,0xdc,0xbc,0xbb,0xe0, - 0xae,0x9b,0xda,0x3a,0x8a,0x2e,0xf9,0x36,0x67,0x9e,0x99,0x9d,0x62,0x14,0xf5,0x9b, - 0xfa,0x92,0xf8,0x46,0x23,0x6a,0x7b,0xbd,0xf1,0x2f,0x8a,0x68,0x6a,0x71,0x48,0x8b, - 0x91,0x69,0xa6,0x7f,0x5f,0x6e,0xa0,0x64,0x1f,0x0d,0xbe,0xac,0xbf,0x8f,0xd9,0xd3, - 0x33,0xeb,0x5e,0x00,0xbe,0x8f,0xf3,0xb3,0x09,0x0c,0x84,0x98,0x40,0x74,0x5c,0x6c, - 0x3e,0xb6,0x01,0xfd,0x35,0xb9,0xe3,0xcb,0xad,0xea,0x39,0x65,0x95,0x2d,0x87,0xee, - 0xfc,0xfd,0x2b,0xff,0x68,0x91,0x44,0xe6,0x40,0x5f,0x97,0x8b,0x83,0x73,0x27,0x01, - 0xad,0x18,0xec,0x92,0x8e,0x90,0xe3,0xe7,0xe6,0x63,0x57,0x3b,0x35,0x6f,0x9f,0xdb, - 0x2b,0xb4,0xf3,0x96,0x45,0x4e,0x01,0xf6,0x1c,0x3e,0x11,0xb5,0x1a,0x11,0xec,0x0d, - 0x7c,0xca,0x24,0x68,0x4d,0x60,0x5a,0x10,0xb6,0x01,0x01,0x7f,0x60,0x5a,0x40,0x4b, - 0xa0,0x82,0xae,0x53,0x27,0x53,0xf3,0x14,0x35,0xb7,0x25,0xfb,0xbb,0x9f,0xfb,0xdd, - 0x7f,0x8c,0x60,0x76,0x13,0x20,0x21,0xfc,0x13,0xae,0x15,0xb2,0xe5,0xa4,0x19,0x8c, - 0x6d,0x74,0x9e,0x53,0x07,0xe4,0xd2,0x4f,0x1c,0xdd,0xd9,0xb1,0x72,0x2a,0xcc,0x73, - 0xc6,0x1b,0x88,0x60,0x9d,0x80,0x77,0xae,0x24,0x22,0x57,0xb1,0xbd,0xb9,0x51,0xcb, - 0xf2,0x5a,0x71,0x70,0x35,0x22,0x3a,0xef,0x6f,0x75,0x5a,0x6c,0x75,0x1a,0xb6,0xfa, - 0x5f,0x6f,0x2e,0x7f,0x7e,0xf7,0xf3,0x8f,0x7d,0x81,0xe5,0x88,0xda,0x52,0x85,0x8c, - 0xc1,0x80,0xf7,0x17,0x68,0x06,0xab,0x5a,0x95,0x9a,0x56,0x95,0x6c,0x02,0x10,0x79, - 0x78,0xc1,0x86,0xfd,0x7a,0x60,0x83,0x05,0x5f,0xc0,0xc5,0x94,0xc7,0xd0,0x3e,0x28, - 0x5b,0xd4,0xd6,0xee,0xb4,0x2d,0xa3,0x67,0x9e,0x90,0x60,0xe4,0xf0,0xe3,0xf6,0xf6, - 0x71,0x55,0xec,0xe3,0xaa,0xa6,0x8f,0xc6,0xa9,0xb6,0xe0,0xb1,0xc9,0x03,0xd6,0xe7, - 0xe3,0x5f,0xc1,0x00,0xc1,0xfa,0x71,0x0e,0x61,0x7a,0x80,0xdb,0x5c,0x8b,0x6a,0xc2, - 0x1b,0x5e,0x3a,0xbb,0xf9,0xc2,0x01,0xcd,0x8d,0x25,0x83,0x38,0x32,0xaa,0x43,0xa4, - 0x78,0x01,0x3d,0xc3,0x6f,0xb8,0x8a,0x80,0x2b,0x8b,0xa9,0x70,0x9d,0x27,0xd9,0x81, - 0x3e,0x22,0x89,0xdf,0x4d,0x3c,0xeb,0x0a,0xbc,0x5d,0xd6,0xe6,0xb5,0xe1,0x70,0x6f, - 0x97,0x7e,0xe6,0xdb,0x25,0x42,0x63,0x2d,0x2b,0xd9,0x98,0x61,0x5c,0x75,0x2c,0xcb, - 0xc2,0x73,0xbc,0xa0,0xd6,0x64,0x59,0x40,0x8b,0x1a,0x27,0x93,0xd9,0x02,0xa4,0x40, - 0x6f,0x7c,0x5a,0xdc,0x2e,0xb5,0x8b,0xc1,0x2a,0x5f,0x8a,0x66,0xd9,0x7f,0x87,0x44, - 0xfe,0x01,0x19,0x47,0xb9,0x85,0x3d,0x1e,0x73,0x11,0xaa,0x9b,0x36,0x01,0x67,0x0e, - 0x10,0x36,0x2b,0x4c,0x9e,0xac,0x6c,0xc8,0x54,0x6c,0x03,0x9f,0xd2,0x41,0xbf,0x65, - 0x62,0x55,0x64,0x71,0x12,0x3e,0x1e,0x54,0x98,0x0d,0xa4,0x00,0xd6,0x89,0xc5,0xa1, - 0x9a,0x01,0x1d,0x32,0xc3,0x91,0x28,0x84,0x4c,0xdf,0x3c,0xd4,0x0e,0x0c,0x52,0xb1, - 0xe4,0x48,0x09,0x65,0x1b,0xa5,0x3a,0x92,0x7d,0x75,0xe8,0x78,0x2c,0x84,0x1d,0x99, - 0xe8,0x89,0x80,0x3b,0x03,0x0c,0xc1,0x69,0x54,0x67,0xc7,0x54,0xb6,0xec,0x22,0x0a, - 0xb5,0x06,0x87,0x0c,0xb2,0xc2,0xc2,0x34,0x96,0x99,0x08,0x15,0x02,0xcd,0x26,0x46, - 0x10,0x0d,0xbd,0x0e,0x4b,0xe8,0x6f,0xc6,0xae,0xc9,0xe2,0x4d,0xf9,0xc0,0x2e,0x95, - 0xcf,0x2b,0x6a,0x63,0xe9,0x6e,0x48,0x44,0x7a,0xcf,0xae,0x34,0x7b,0xde,0xaf,0x07, - 0xef,0x80,0x25,0x7b,0xaa,0x28,0x23,0x11,0x85,0xc2,0x19,0xcb,0x47,0xd0,0x04,0x7a, - 0xfa,0x47,0xa7,0x59,0xf4,0x94,0x62,0x2a,0x0f,0x73,0xa1,0x1c,0x2b,0x99,0x64,0x77, - 0x12,0xf8,0xdd,0x73,0x16,0xb1,0xe0,0xa9,0x42,0xbd,0x2f,0x43,0x9a,0x34,0x6c,0x2d, - 0xe4,0xb2,0x8c,0x24,0x83,0x18,0x19,0x0d,0x42,0xad,0xb7,0x9c,0x94,0x3e,0x22,0xe9, - 0xa7,0x96,0x2f,0xd7,0x9a,0x03,0x9a,0x7e,0xf2,0x45,0x4e,0x4c,0x0a,0xf3,0xba,0x40, - 0xbe,0xef,0x89,0x5a,0x34,0xdf,0xc4,0x94,0x89,0x69,0x47,0xcc,0xa0,0x38,0x5c,0x16, - 0x92,0x4f,0x3f,0x9d,0xf2,0x27,0x62,0x24,0x85,0x4f,0x20,0x19,0x6e,0x61,0x54,0xc7, - 0xc0,0x77,0xf1,0xff,0x98,0x4d,0xe7,0xe3,0x66,0x44,0x32,0x0f,0x3b,0x0d,0xf4,0x6f, - 0x24,0xee,0x96,0x7c,0x9c,0x65,0xad,0x17,0x99,0xb5,0xd8,0x59,0xcd,0xcd,0xe4,0x36, - 0x2b,0x32,0x94,0x33,0xc0,0xe2,0x0d,0x71,0xf6,0xdb,0x7c,0x1a,0x3f,0xdc,0x5f,0xce, - 0x7e,0x7b,0x37,0xb5,0x4c,0x80,0xed,0x86,0xe2,0x50,0xf4,0xf7,0x8f,0xad,0xe7,0xa3, - 0x28,0xd5,0xf5,0xd5,0x3b,0x2b,0xac,0x30,0x59,0x7e,0xb2,0xbc,0x7c,0x24,0x2c,0x0e, - 0x9f,0xbd,0xe1,0xfa,0xfa,0xfc,0x2f,0x97,0xd8,0xc7,0x3f,0x55,0xd8,0x58,0x98,0x3b, - 0xb4,0x1a,0x9a,0x2e,0x69,0xa7,0xd7,0x91,0x86,0x75,0x14,0xb5,0xbb,0x0a,0xe2,0xea, - 0xc8,0xc7,0xb8,0x8a,0x2d,0xc6,0xd5,0xc6,0x10,0x41,0x02,0xd9,0x0d,0xa4,0x20,0xc7, - 0xfb,0xbc,0x19,0x33,0x53,0xb3,0x29,0xc0,0x87,0xf7,0xbe,0x11,0x05,0x08,0x42,0x10, - 0x4b,0xd5,0xe2,0xea,0x6d,0xed,0xcd,0xee,0xc6,0x99,0x28,0x3c,0x38,0xa8,0x7b,0x83, - 0x56,0x38,0x8f,0x5a,0x1d,0x83,0xa8,0xab,0xe6,0xaf,0x27,0x27,0xb8,0x5d,0xa1,0x9e, - 0x1e,0xc7,0x31,0xff,0x5f,0xaa,0xf7,0x0d,0xca,0x83,0x0b,0xb2,0x59,0xf7,0x16,0x18, - 0xd0,0x8c,0x44,0xb7,0x2b,0x10,0x80,0x0d,0xb6,0x83,0x04,0x18,0x58,0x7d,0x85,0xbd, - 0xed,0xd6,0x7f,0x3e,0xff,0x53,0xb1,0x3e,0x4b,0x43,0x06,0xe7,0x52,0x88,0xc4,0x6b, - 0x07,0x7f,0xe8,0x17,0xfe,0x92,0xa1,0x2a,0xdb,0x43,0xdb,0xaa,0x1e,0xb2,0x5b,0x6f, - 0x96,0xea,0x00,0x1d,0xe9,0x08,0x79,0xbb,0x0d,0x07,0x8e,0xd5,0xd7,0x25,0x3c,0xb0, - 0x82,0xa9,0xa9,0x63,0xac,0x95,0x1f,0x0c,0x8f,0x2d,0xdc,0xbb,0x16,0x3a,0x01,0xe4, - 0x10,0xd3,0x0f,0xaa,0x3c,0xeb,0xcc,0xa7,0x8b,0x59,0x16,0x40,0xc3,0x53,0xae,0x33, - 0xf1,0xaf,0x1a,0xc9,0x4a,0x8a,0xda,0x34,0x38,0x44,0x9f,0x5f,0x2f,0xdf,0x21,0x40, - 0x29,0xed,0x4b,0xb4,0x77,0xca,0x88,0xb6,0xa3,0x13,0x94,0x48,0x49,0xb8,0xe0,0x4d, - 0x2e,0xea,0xf1,0xfe,0xb7,0xbd,0x5e,0x6f,0xd7,0x3a,0xda,0x1b,0xd0,0x0e,0x68,0x6d, - 0xa8,0x3d,0x12,0x70,0xbb,0x7d,0x13,0xe5,0x27,0x5a,0x72,0x50,0x0e,0x4d,0xee,0xe1, - 0x3e,0x21,0x56,0x0e,0x66,0xce,0xf0,0x14,0x61,0x50,0x0b,0x18,0x6b,0x2a,0xd6,0xe4, - 0xcc,0x08,0xe0,0x5c,0x53,0x61,0xd6,0x78,0x01,0xf5,0xb8,0x7e,0x69,0x15,0x13,0xe2, - 0xe2,0xdb,0x40,0xcb,0x1f,0xea,0xea,0x5f,0x46,0x4b,0x58,0xe0,0x74,0xbe,0xf1,0x43, - 0xec,0x95,0x56,0x9b,0x9e,0x1f,0x13,0x18,0x04,0xb2,0x59,0xe4,0x7c,0xad,0xe0,0xa4, - 0xba,0x93,0xbb,0x06,0x63,0x3c,0x4b,0x38,0x97,0x45,0x01,0xee,0x89,0x05,0xb8,0xd0, - 0xf6,0x94,0x95,0x8f,0x68,0x61,0x7b,0x2e,0x98,0xb2,0x2a,0x3d,0xdf,0x4b,0x8c,0xe3, - 0x63,0x0d,0x6b,0x8c,0xdf,0xfd,0x63,0x5c,0x7e,0xbe,0xa2,0x2e,0x14,0x30,0x32,0xbd, - 0x7c,0xfc,0x1c,0x07,0x1f,0x3c,0x7d,0xdf,0xf0,0x2a,0x1b,0x39,0x23,0x38,0xc1,0xd7, - 0x34,0xcd,0x59,0xde,0x8f,0xd8,0xec,0xb5,0xcf,0x93,0xbd,0x23,0x1f,0x55,0xc7,0x89, - 0xe6,0x95,0x60,0x3c,0x3d,0xb8,0x64,0x6f,0xa6,0x4c,0x19,0x00,0x7a,0x53,0xd0,0xb9, - 0x0e,0xcf,0x5b,0x15,0xab,0xc7,0x32,0x72,0x99,0x96,0x40,0xc1,0x2b,0xf3,0xf3,0xba, - 0xe0,0xa1,0x07,0x06,0x1a,0x8b,0x7f,0xd7,0x79,0xcd,0xb1,0x44,0xdd,0x10,0x15,0x79, - 0x6f,0x69,0xe9,0xe3,0x46,0xe2,0x06,0xe8,0xa4,0x5c,0x60,0xfa,0x7f,0x62,0xf5,0x05, - 0x96,0x58,0xc9,0xfa,0xcd,0x64,0x5c,0x32,0x1e,0x03,0x3c,0xbd,0xc6,0x19,0x07,0x7d, - 0xc1,0x90,0xb0,0x8d,0x74,0xb0,0xde,0x8a,0x1c,0x98,0xe6,0xfd,0xc5,0xeb,0xde,0x7f, - 0xb0,0x6a,0xda,0xe7,0xca,0x83,0x76,0x9d,0x3f,0xef,0x59,0x35,0xc2,0x02,0x04,0x22, - 0xc7,0xf8,0x44,0x0b,0xc6,0x69,0x70,0x72,0xc4,0xce,0x14,0x6c,0x1e,0x87,0x39,0x43, - 0x05,0x27,0x0f,0x86,0x4a,0x75,0x03,0xcb,0x2f,0x40,0x93,0x52,0x3c,0xe2,0x3d,0xda, - 0x39,0xb6,0x9d,0xf2,0x74,0x89,0x46,0x96,0x6d,0xa9,0x40,0x2c,0x78,0xc9,0x92,0xac, - 0x49,0x54,0xb3,0x08,0xe4,0x2d,0x3f,0xb1,0xa9,0x4e,0x2d,0x52,0xd5,0x68,0x53,0x5e, - 0xb6,0x5c,0x4c,0x96,0x0f,0xcb,0x1b,0x73,0x1b,0xe6,0x63,0x84,0xc2,0x9a,0x1e,0x17, - 0x17,0x3e,0x57,0xe0,0xd5,0x87,0xbb,0x0e,0x0f,0xa5,0x95,0xb5,0xa4,0x06,0xc9,0x98, - 0x49,0xa7,0xdb,0xe2,0x69,0xe3,0x2d,0xe0,0xa2,0x14,0xc7,0x8c,0xa5,0x62,0x63,0x7f, - 0x2f,0xe1,0x37,0x4e,0xcb,0xa0,0xb6,0xae,0xfe,0xff,0x2d,0x0c,0xa8,0xab,0xf5,0xc0, - 0x20,0x54,0x69,0xd8,0x2d,0x81,0xeb,0x1a,0xc8,0x79,0x14,0x0a,0xca,0x07,0x91,0x15, - 0xb0,0x14,0x6a,0xdf,0x35,0x7f,0x25,0xd2,0x20,0xc4,0x2c,0xb5,0x4a,0x11,0x61,0x7f, - 0xf1,0xf3,0xc9,0x41,0xd1,0x18,0xd1,0xfa,0xb7,0x08,0x07,0xeb,0xff,0xaf,0xe0,0xa4, - 0x16,0xe7,0xf3,0x5b,0x91,0x8d,0xd8,0xc8,0x75,0x6d,0x42,0xaf,0xaf,0xe7,0xd9,0x97, - 0xf1,0x02,0xc6,0x50,0xd0,0xfc,0x77,0x9c,0x56,0xd5,0x18,0x24,0xe4,0xdb,0x2d,0xbf, - 0xea,0xe2,0x98,0xbb,0xcf,0x68,0x5c,0xd2,0xad,0xbb,0x24,0x0f,0xee,0x4d,0x67,0x85, - 0xa8,0x5c,0xd5,0x95,0x1a,0xc0,0x9d,0x64,0xa7,0x46,0xf5,0x1f,0xdc,0x36,0x61,0xd7, - 0x57,0xef,0x0e,0xce,0x95,0xdd,0xcd,0x66,0x39,0x80,0x34,0x38,0xb3,0x58,0xe8,0xae, - 0x03,0x59,0x0f,0x40,0x2e,0x71,0xae,0x5e,0xde,0xe6,0x5c,0xe4,0xa2,0x04,0x50,0x63, - 0x1f,0x38,0x82,0x0c,0x6e,0x35,0xbf,0x47,0xcc,0x53,0xa2,0xf6,0xdf,0xd8,0x2b,0x8a, - 0x23,0xc2,0x93,0x64,0xba,0xcc,0x89,0xb2,0xdd,0xfc,0x40,0x82,0xf6,0x77,0x2a,0x5b, - 0x08,0x64,0x3a,0xf0,0x28,0xae,0x49,0xea,0x63,0x93,0x95,0xec,0xba,0x92,0x10,0x02, - 0x6f,0xda,0x12,0xb4,0xff,0x98,0x12,0x95,0x1b,0x99,0xd3,0x09,0xaf,0xbe,0x66,0xfa, - 0xda,0x5d,0xaf,0x35,0x1b,0x1d,0x06,0xd5,0xd7,0x0b,0xa8,0x0e,0x12,0x83,0x9e,0x83, - 0x1e,0x37,0x29,0x89,0xd0,0xa7,0x8b,0x0c,0x12,0x76,0x40,0x3c,0xa7,0x90,0xf2,0x02, - 0x14,0x6a,0x15,0x46,0xc1,0x41,0x0a,0xff,0xa5,0xd7,0xe1,0x64,0x74,0xbc,0x5b,0x3d, - 0x45,0x6e,0xb8,0x0a,0xda,0xe5,0xec,0xcb,0x2d,0xe3,0xb2,0x78,0xd5,0x86,0x44,0x7f, - 0xd5,0x3b,0xfd,0xee,0xb5,0x14,0xd2,0xaa,0x53,0xde,0x1f,0xd4,0x19,0x30,0x73,0xa9, - 0x9c,0xb2,0x34,0xa3,0x2b,0xdf,0x57,0xdc,0x8e,0xd3,0xaa,0x9a,0xff,0x3e,0x8b,0x3a, - 0xb2,0x16,0x5c,0xd0,0xa4,0x83,0x19,0xa5,0x2d,0x5e,0x46,0x3f,0xe2,0x10,0x44,0x59, - 0x1a,0x9c,0xa6,0x62,0x02,0x8b,0xe5,0x93,0xf8,0x44,0xd5,0x86,0xaa,0x52,0x55,0xe9, - 0xb1,0x73,0x9f,0x72,0xd6,0x3f,0xec,0x40,0x2b,0xe6,0x2a,0xfc,0x53,0xb8,0xbf,0xe7, - 0x29,0xb6,0xab,0x0e,0xf6,0xe4,0x34,0x28,0x68,0xc2,0x1c,0xa1,0xda,0xe6,0x72,0x75, - 0xf5,0x78,0x07,0x11,0x2e,0x1f,0x5f,0x0f,0x18,0xe1,0x18,0x0e,0xc9,0x38,0x41,0xcf, - 0xf3,0x23,0xc3,0x15,0x06,0x1e,0x79,0xff,0xb0,0xa8,0xbe,0x51,0xdd,0xd6,0x07,0x6e, - 0x56,0xdf,0x44,0x62,0xde,0x1d,0x09,0xd4,0xf4,0xe0,0xe8,0xe2,0x4c,0xae,0x75,0x87, - 0xf4,0x0b,0x31,0xed,0xf1,0x3f,0xa2,0xe9,0x0d,0x8f,0xfe,0x0d,0x88,0x66,0x33,0x06, - 0xce,0x66,0x01,0x00, +const uint32_t WEBCONFIG_HTML_RAW_LEN = 94689; +const uint32_t WEBCONFIG_HTML_GZ_LEN = 29288; +const char WEBCONFIG_HTML_ETAG[] = "\"79ecac58e6589f34\""; +const char WEBCONFIG_HTML_VERSION[] = "9993576a3aa8d54e"; +const uint16_t WEBCONFIG_HTML_LOADER_LEN = 762; +const uint8_t WEBCONFIG_HTML_LOADER[] PROGMEM = { + 0x3c,0x21,0x64,0x6f,0x63,0x74,0x79,0x70,0x65,0x20,0x68,0x74,0x6d,0x6c,0x3e,0x3c, + 0x6d,0x65,0x74,0x61,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66, + 0x2d,0x38,0x3e,0x3c,0x6d,0x65,0x74,0x61,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x76,0x69, + 0x65,0x77,0x70,0x6f,0x72,0x74,0x20,0x63,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x3d,0x22, + 0x77,0x69,0x64,0x74,0x68,0x3d,0x64,0x65,0x76,0x69,0x63,0x65,0x2d,0x77,0x69,0x64, + 0x74,0x68,0x2c,0x69,0x6e,0x69,0x74,0x69,0x61,0x6c,0x2d,0x73,0x63,0x61,0x6c,0x65, + 0x3d,0x31,0x22,0x3e,0x3c,0x74,0x69,0x74,0x6c,0x65,0x3e,0x4d,0x65,0x73,0x68,0x43, + 0x6f,0x72,0x65,0x20,0x57,0x65,0x62,0x43,0x6f,0x6e,0x66,0x69,0x67,0x3c,0x2f,0x74, + 0x69,0x74,0x6c,0x65,0x3e,0x3c,0x62,0x6f,0x64,0x79,0x3e,0x4c,0x6f,0x61,0x64,0x69, + 0x6e,0x67,0x20,0x4d,0x65,0x73,0x68,0x43,0x6f,0x72,0x65,0x20,0x57,0x65,0x62,0x43, + 0x6f,0x6e,0x66,0x69,0x67,0x26,0x68,0x65,0x6c,0x6c,0x69,0x70,0x3b,0x3c,0x73,0x63, + 0x72,0x69,0x70,0x74,0x3e,0x28,0x61,0x73,0x79,0x6e,0x63,0x28,0x29,0x3d,0x3e,0x7b, + 0x6c,0x65,0x74,0x20,0x70,0x3b,0x66,0x6f,0x72,0x28,0x6c,0x65,0x74,0x20,0x6e,0x3d, + 0x30,0x3b,0x6e,0x3c,0x33,0x26,0x26,0x70,0x3d,0x3d,0x3d,0x75,0x6e,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x64,0x3b,0x6e,0x2b,0x2b,0x29,0x7b,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x43,0x3d,0x77,0x69,0x6e,0x64,0x6f,0x77,0x2e,0x41,0x62,0x6f,0x72,0x74,0x43,0x6f, + 0x6e,0x74,0x72,0x6f,0x6c,0x6c,0x65,0x72,0x2c,0x63,0x3d,0x43,0x26,0x26,0x6e,0x65, + 0x77,0x20,0x43,0x28,0x29,0x2c,0x74,0x3d,0x63,0x26,0x26,0x73,0x65,0x74,0x54,0x69, + 0x6d,0x65,0x6f,0x75,0x74,0x28,0x28,0x29,0x3d,0x3e,0x63,0x2e,0x61,0x62,0x6f,0x72, + 0x74,0x28,0x29,0x2c,0x39,0x30,0x30,0x30,0x30,0x29,0x3b,0x74,0x72,0x79,0x7b,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x72,0x3d,0x61,0x77,0x61,0x69,0x74,0x20,0x66,0x65,0x74, + 0x63,0x68,0x28,0x22,0x2f,0x75,0x69,0x3f,0x76,0x3d,0x39,0x39,0x39,0x33,0x35,0x37, + 0x36,0x61,0x33,0x61,0x61,0x38,0x64,0x35,0x34,0x65,0x22,0x2c,0x63,0x3f,0x7b,0x73, + 0x69,0x67,0x6e,0x61,0x6c,0x3a,0x63,0x2e,0x73,0x69,0x67,0x6e,0x61,0x6c,0x7d,0x3a, + 0x7b,0x7d,0x29,0x3b,0x69,0x66,0x28,0x72,0x2e,0x6f,0x6b,0x29,0x70,0x3d,0x61,0x77, + 0x61,0x69,0x74,0x20,0x72,0x2e,0x74,0x65,0x78,0x74,0x28,0x29,0x3b,0x65,0x6c,0x73, + 0x65,0x20,0x69,0x66,0x28,0x72,0x2e,0x73,0x74,0x61,0x74,0x75,0x73,0x3d,0x3d,0x3d, + 0x34,0x30,0x39,0x29,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x2e,0x72,0x65,0x6c,0x6f,0x61,0x64,0x28,0x29,0x7d,0x63,0x61,0x74, + 0x63,0x68,0x28,0x65,0x29,0x7b,0x7d,0x66,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x7b,0x69, + 0x66,0x28,0x74,0x29,0x63,0x6c,0x65,0x61,0x72,0x54,0x69,0x6d,0x65,0x6f,0x75,0x74, + 0x28,0x74,0x29,0x7d,0x69,0x66,0x28,0x70,0x3d,0x3d,0x3d,0x75,0x6e,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x64,0x29,0x61,0x77,0x61,0x69,0x74,0x20,0x6e,0x65,0x77,0x20,0x50, + 0x72,0x6f,0x6d,0x69,0x73,0x65,0x28,0x72,0x3d,0x3e,0x73,0x65,0x74,0x54,0x69,0x6d, + 0x65,0x6f,0x75,0x74,0x28,0x72,0x2c,0x35,0x30,0x30,0x2a,0x28,0x6e,0x2b,0x31,0x29, + 0x29,0x29,0x7d,0x69,0x66,0x28,0x70,0x3d,0x3d,0x3d,0x75,0x6e,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x64,0x29,0x74,0x68,0x72,0x6f,0x77,0x20,0x45,0x72,0x72,0x6f,0x72,0x28, + 0x22,0x74,0x72,0x61,0x6e,0x73,0x66,0x65,0x72,0x20,0x66,0x61,0x69,0x6c,0x65,0x64, + 0x22,0x29,0x3b,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x6f,0x70,0x65,0x6e, + 0x28,0x29,0x3b,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x77,0x72,0x69,0x74, + 0x65,0x28,0x70,0x29,0x3b,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x63,0x6c, + 0x6f,0x73,0x65,0x28,0x29,0x7d,0x29,0x28,0x29,0x2e,0x63,0x61,0x74,0x63,0x68,0x28, + 0x65,0x3d,0x3e,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x62,0x6f,0x64,0x79, + 0x2e,0x74,0x65,0x78,0x74,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x3d,0x22,0x55,0x6e, + 0x61,0x62,0x6c,0x65,0x20,0x74,0x6f,0x20,0x6c,0x6f,0x61,0x64,0x20,0x57,0x65,0x62, + 0x43,0x6f,0x6e,0x66,0x69,0x67,0x3a,0x20,0x22,0x2b,0x65,0x2b,0x22,0x2e,0x20,0x52, + 0x65,0x6c,0x6f,0x61,0x64,0x20,0x74,0x6f,0x20,0x72,0x65,0x74,0x72,0x79,0x2e,0x22, + 0x29,0x3c,0x2f,0x73,0x63,0x72,0x69,0x70,0x74,0x3e, +}; + +const uint8_t WEBCONFIG_HTML_GZ[] PROGMEM = { + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0xe4,0xbd,0x69,0x7b,0xe3,0x46, + 0x92,0x20,0xfc,0x9d,0xbf,0x02,0x46,0x79,0x24,0xc2,0x02,0x21,0x92,0x3a,0x4a,0x45, + 0x16,0xa5,0x95,0xe5,0xb2,0x5d,0xe3,0x3a,0x34,0x25,0xb9,0xed,0x59,0x59,0x5d,0x0b, + 0x92,0x20,0x89,0x16,0x08,0xc0,0x00,0xa8,0xc3,0x94,0xf6,0xb7,0xbf,0x71,0x64,0x26, + 0x12,0x07,0x29,0x96,0xed,0x79,0x66,0xdf,0x5d,0x77,0xab,0x08,0x24,0xf2,0x8c,0x8c, + 0x8c,0x8c,0x88,0x8c,0x88,0x7c,0xfd,0xd5,0x77,0x1f,0xcf,0x2e,0xff,0xf3,0xfc,0x8d, + 0x31,0xcb,0xe6,0xc1,0x71,0xe3,0x35,0xfe,0x18,0x81,0x1b,0x4e,0x07,0xa6,0x17,0x9a, + 0x98,0xe0,0xb9,0x63,0xf8,0x99,0x7b,0x99,0x6b,0x8c,0x66,0x6e,0x92,0x7a,0xd9,0xc0, + 0x5c,0x64,0x93,0xd6,0x91,0x29,0x93,0x43,0x77,0xee,0x0d,0xcc,0x5b,0xdf,0xbb,0x8b, + 0xa3,0x24,0x33,0x8d,0x51,0x14,0x66,0x5e,0x08,0xd9,0xee,0xfc,0x71,0x36,0x1b,0x8c, + 0xbd,0x5b,0x7f,0xe4,0xb5,0xe8,0xc5,0x36,0xfc,0xd0,0xcf,0x7c,0x37,0x68,0xa5,0x23, + 0x37,0xf0,0x06,0x1d,0xdb,0x98,0xbb,0xf7,0xfe,0x7c,0x31,0xcf,0x13,0x64,0x45,0xad, + 0x89,0x9f,0x0d,0x46,0xd1,0xad,0x97,0x60,0x4b,0x99,0x9f,0x05,0xde,0xf1,0x7b,0x2f, + 0x9d,0x9d,0x45,0x89,0x67,0x9c,0x45,0xe1,0xc4,0x9f,0xbe,0xde,0xe5,0xe4,0xc6,0xeb, + 0x34,0x7b,0xc0,0xdf,0x5e,0x12,0x45,0xd9,0xb2,0xd1,0x6a,0x0d,0xa7,0xbd,0x17,0x93, + 0xfd,0xc9,0xe1,0xe4,0xa8,0x6f,0xb4,0x5a,0x23,0x37,0x19,0xc3,0xfb,0x64,0x82,0x2f, + 0x7e,0x78,0xd3,0x7b,0xd1,0x71,0xbb,0x7b,0x7b,0x6d,0x7c,0x9d,0x2f,0xb2,0xde,0x8b, + 0xc3,0xc3,0x97,0x7b,0x47,0x2e,0xbe,0x06,0x7e,0xe8,0xf5,0x5e,0x78,0x5d,0xef,0xa5, + 0xe7,0xf5,0xa1,0x22,0x77,0x34,0xea,0xbd,0xe8,0x0e,0x5f,0x8e,0xbd,0x57,0xf8,0x19, + 0x5e,0xb9,0x02,0x51,0x59,0x84,0x75,0x8d,0x5f,0x8d,0x0f,0xe8,0xcd,0x4b,0x92,0xde, + 0x8b,0xf1,0xe1,0xfe,0xc1,0xfe,0x01,0xbe,0xde,0xb9,0x49,0xd8,0x7b,0x31,0x3a,0x3a, + 0x7a,0xd9,0x71,0xb1,0xae,0xd1,0xcc,0x8f,0xa1,0x6e,0x6f,0xd2,0x9d,0xbc,0xe4,0x9e, + 0x70,0x3f,0x65,0xbf,0x44,0xe3,0xa3,0xa3,0x71,0x77,0xec,0x61,0x52,0x3a,0x73,0xc7, + 0xd1,0x5d,0xaf,0x6d,0x74,0xe2,0x7b,0x63,0x0f,0xfe,0x92,0xe9,0xd0,0x6d,0x76,0x0e, + 0xed,0xee,0x91,0xbd,0x7f,0x60,0x3b,0xed,0x23,0xab,0xdf,0x78,0x6a,0xfc,0x8f,0xb9, + 0x37,0xf6,0x5d,0xa3,0x19,0x27,0xde,0xc4,0x4b,0xd2,0xd6,0x28,0x0a,0xa2,0x04,0x00, + 0x3a,0xf3,0xe6,0x5e,0x6f,0xec,0x26,0x37,0xd6,0xb2,0x00,0x98,0x4e,0xbb,0x73,0xd0, + 0x19,0xe5,0x80,0x01,0x60,0x74,0xba,0x43,0x05,0x1b,0xef,0xd0,0x1b,0x4e,0xba,0x0a, + 0x36,0x47,0xc3,0x57,0x47,0xee,0x30,0x87,0x4d,0xd7,0xdd,0xdb,0xdf,0xef,0x2a,0xd8, + 0xec,0xbb,0xaf,0xf6,0x27,0x04,0x49,0x1e,0x5e,0x77,0xaf,0x3b,0xde,0x73,0xb5,0xe1, + 0x75,0xf6,0xa1,0xfe,0x6e,0x61,0x84,0x7b,0xee,0xfe,0xe1,0xc1,0xe1,0xea,0x11,0xb6, + 0x6d,0xfc,0x9f,0xb3,0x8f,0xa3,0x7b,0x6a,0x7c,0xb3,0x1c,0x46,0xf7,0xad,0xd4,0xff, + 0xc3,0x0f,0xa7,0xbd,0x61,0x94,0x8c,0xbd,0xa4,0x05,0x29,0xfd,0xb9,0x9b,0x4c,0xfd, + 0xb0,0xd7,0x7e,0x6a,0x20,0xd6,0x2e,0x5b,0x77,0xde,0xf0,0xc6,0xcf,0x5a,0x99,0x77, + 0x9f,0x61,0x6e,0xaf,0xe5,0x8e,0xff,0xb5,0x48,0xb3,0x5e,0xa7,0xdd,0xfe,0xb7,0xa7, + 0xc6,0x30,0x1a,0x3f,0x2c,0x27,0x80,0x9a,0xbd,0xce,0x41,0x7c,0xbf,0xdb,0x71,0xf6, + 0x0f,0x8c,0xf4,0x21,0xcd,0xbc,0x79,0x6b,0xe1,0xdb,0x2d,0x37,0x8e,0x03,0xaf,0xc5, + 0x09,0xb6,0x79,0xe1,0x4d,0x23,0xcf,0xf8,0xf9,0xad,0x69,0x7f,0x8a,0x86,0x51,0x16, + 0xd9,0xa9,0x1b,0xa6,0xad,0xd4,0x4b,0xfc,0x49,0x7f,0xe8,0x8e,0x6e,0xa6,0x49,0xb4, + 0x08,0xc7,0xbd,0x5b,0x37,0x69,0x22,0x48,0xad,0x3e,0x81,0x5c,0xbc,0x03,0x10,0xad, + 0x7e,0xec,0x8e,0xc7,0xd0,0x5f,0xe8,0x68,0x96,0x45,0xf3,0xde,0xab,0x76,0x7c,0xdf, + 0x47,0x5c,0x9e,0x04,0xd1,0x5d,0xeb,0xbe,0x37,0xf3,0xc7,0x63,0x2f,0x84,0x9e,0x77, + 0xa8,0x4f,0xd4,0xdf,0x5e,0xe7,0x25,0x64,0xa2,0xd7,0x3b,0xcf,0x9f,0xce,0xb2,0xde, + 0xe1,0x01,0x0e,0xae,0xab,0x67,0xd9,0xaf,0x66,0xe9,0xd3,0x88,0xb3,0x04,0xba,0x38, + 0x89,0x92,0x79,0x6f,0x11,0xc7,0x5e,0x32,0x72,0x53,0xaf,0x1f,0x78,0x59,0x06,0xc0, + 0x4a,0x63,0x77,0x84,0xb0,0x73,0xda,0x07,0xde,0xbc,0xd0,0x55,0x98,0x60,0x4b,0xc2, + 0xb1,0xdb,0x05,0xf0,0xc3,0x44,0x40,0x4f,0xb1,0xd1,0xde,0xc4,0x4f,0xd2,0x0c,0x27, + 0x35,0x18,0x2f,0x39,0x4b,0x2b,0x8b,0x62,0x04,0xb7,0xbb,0xd4,0xeb,0x00,0x2c,0xb0, + 0xa0,0x00,0xd0,0x09,0x2f,0x59,0x8e,0xfd,0x34,0x0e,0xdc,0x87,0xde,0x24,0xf0,0xee, + 0xfb,0x6e,0xe0,0x4f,0xc3,0x96,0x0f,0x10,0x4d,0x7b,0x23,0xa0,0x08,0x5e,0xd2,0x9f, + 0xba,0x71,0x0f,0x5b,0x90,0xf0,0xe9,0x75,0xb0,0xd5,0xce,0x21,0xa4,0x54,0xe0,0x8a, + 0xc8,0x69,0xf5,0xd5,0x84,0x13,0x1c,0x11,0x4d,0xd2,0x28,0xf0,0xc7,0x06,0xe7,0x41, + 0x7c,0x02,0x60,0x47,0x29,0x50,0x95,0x28,0xec,0xa5,0x99,0x3f,0xba,0x79,0xe8,0x53, + 0x3f,0xfb,0x7f,0xc0,0x4c,0x8c,0xbd,0x7b,0x68,0x4f,0x76,0xcf,0x48,0x6f,0xa7,0x4b, + 0xec,0x5a,0x2f,0x8c,0x42,0xef,0xa9,0xe1,0xcc,0x90,0x80,0x2d,0xe7,0x30,0x34,0x22, + 0x4f,0x38,0x38,0x4e,0x33,0xc6,0xfe,0xad,0x0e,0x76,0xe8,0x65,0x15,0x70,0x77,0x33, + 0x18,0x1b,0x41,0xd7,0x83,0x0a,0xef,0x12,0x37,0x56,0x53,0x2c,0x26,0x98,0xa7,0x46, + 0x25,0x7a,0x41,0xe0,0xc7,0xa9,0x9f,0x42,0x2b,0x43,0x77,0x3c,0xf5,0x24,0x5c,0x03, + 0x6f,0x92,0xf5,0xdc,0x45,0x16,0xf5,0x55,0xe7,0xfa,0x5a,0xe3,0x9d,0x9a,0x39,0x97, + 0xf0,0xc3,0x35,0xf3,0x0a,0xa1,0xc7,0x60,0x4a,0xdc,0xb1,0xbf,0x48,0x7b,0xaf,0x5e, + 0xd5,0x02,0x14,0x16,0xa8,0x55,0x19,0x86,0xec,0x8c,0x03,0xa4,0x7d,0x11,0x2f,0xb5, + 0x52,0x2f,0x26,0x7b,0xde,0xd1,0x78,0x4f,0x94,0x78,0x71,0xe4,0x1e,0x8c,0xda,0x04, + 0x21,0x1f,0x48,0x7c,0x0e,0xc7,0xbe,0x3e,0x8a,0x23,0x6d,0x6e,0xb1,0x6f,0x47,0xaa, + 0x6f,0x95,0xb9,0x13,0xe4,0xc0,0x2a,0xf5,0x1d,0x17,0x41,0xa3,0xd2,0x77,0x22,0x26, + 0xd5,0xce,0xf7,0x47,0x8b,0x24,0x85,0x94,0x38,0xf2,0x09,0xbf,0xb0,0xc2,0xd6,0x8c, + 0xc1,0xd4,0x71,0xf6,0xfa,0x0d,0x5a,0xf1,0x2f,0xdb,0x80,0xd7,0x5d,0x5a,0xf5,0x7b, + 0xc6,0xc2,0x6f,0xcd,0xa3,0x30,0xa2,0x69,0xb3,0xdf,0x7b,0x61,0x10,0xd9,0xb0,0x9b, + 0x40,0xc7,0xdc,0xd4,0x56,0x1f,0xe4,0x28,0x7b,0x33,0x9c,0xbc,0x0a,0xbe,0xcb,0x2e, + 0x57,0xd7,0xc1,0x06,0xb4,0x78,0x25,0xb8,0xf7,0xdc,0xee,0xa4,0xb3,0x2f,0xc1,0xed, + 0xb5,0x87,0xfb,0x07,0x23,0xa0,0x7f,0x73,0xd7,0x0f,0x01,0x53,0xee,0x05,0x8e,0x1e, + 0xee,0xe3,0xfa,0x91,0xc4,0xcf,0x20,0xb4,0x51,0xab,0xe9,0x10,0x17,0xaf,0x83,0x2b, + 0x67,0xb9,0x76,0x3d,0xad,0x58,0x48,0xc5,0x99,0x20,0xac,0xd7,0xab,0xee,0x13,0x21, + 0x66,0x92,0xcd,0xc5,0xf8,0x45,0xd2,0x10,0xb5,0x4a,0xf7,0xa9,0x1b,0x99,0x3b,0x4c, + 0x8b,0x14,0x01,0x97,0xff,0xfe,0x6a,0xd4,0x94,0x6d,0xed,0x57,0x10,0xba,0x93,0x8f, + 0xb9,0xa6,0x11,0x63,0xb8,0x80,0x24,0x81,0x92,0x1d,0x39,0xc4,0xb6,0xde,0x0c,0x21, + 0x6a,0x05,0x7b,0x08,0x3b,0xfc,0x70,0x06,0x84,0x3d,0xd3,0x57,0xdc,0x9e,0x73,0x50, + 0x5e,0x73,0xed,0x7c,0xcd,0x01,0x86,0x1a,0xd5,0x2e,0x22,0xde,0x16,0xb1,0xb1,0xd8, + 0x3b,0x07,0x3a,0xb8,0x62,0x4e,0x2a,0xbb,0xc7,0x2a,0x38,0x43,0x8d,0x93,0x65,0x09, + 0x0c,0x7b,0x04,0x86,0x09,0x70,0x6d,0x43,0x2f,0x50,0xe0,0x1e,0x06,0xd1,0xe8,0x46, + 0x1f,0x52,0xb7,0x76,0x48,0xc5,0xba,0xf6,0x45,0x55,0x80,0xfb,0x61,0xa6,0x93,0xbf, + 0x0e,0x15,0x5e,0xb1,0x73,0xd0,0xb6,0x40,0xbd,0xf0,0xc3,0x78,0x91,0x5d,0x65,0x0f, + 0xb1,0x37,0x40,0xc2,0x77,0x6d,0x6b,0x09,0xb1,0x9b,0xa6,0x77,0x00,0xb0,0x42,0x62, + 0xb8,0x98,0x0f,0xbd,0xa4,0x90,0xe4,0x01,0xba,0x07,0xd7,0x76,0xea,0x05,0xde,0x08, + 0x38,0x16,0xc6,0x79,0xdc,0xc2,0x15,0xf8,0x8f,0x70,0xc7,0x68,0x8b,0xc1,0xd4,0xcd, + 0xde,0x61,0xa9,0xaf,0x0c,0xd2,0x15,0x14,0xa5,0xf1,0x65,0xd4,0x09,0xe9,0x59,0xb4, + 0xc8,0x88,0x8f,0xa1,0x4d,0xc4,0x30,0x76,0xbf,0x31,0x8e,0x07,0xd8,0x68,0xcf,0x48, + 0x01,0x14,0xa9,0xe1,0x7f,0xbc,0x30,0xfe,0x88,0xa2,0x79,0x2b,0x0a,0x5b,0x93,0x68, + 0xb4,0x48,0x8d,0x66,0xea,0x8f,0xbd,0x3b,0xf7,0x01,0x78,0x88,0x51,0x12,0x05,0x01, + 0xb0,0xc1,0xc6,0xc8,0x8d,0x33,0xff,0xd6,0x33,0xd2,0x99,0xe7,0x65,0x96,0xf1,0xcd, + 0x2e,0x83,0xaf,0x47,0x25,0xc4,0xf8,0xf9,0x65,0xb9,0x82,0xda,0xe8,0x68,0xd2,0x36, + 0xf0,0x7f,0xb8,0x99,0x32,0xc5,0x99,0xfb,0xf7,0x4d,0x68,0x24,0x05,0x7e,0xca,0xce, + 0x4b,0x18,0xdd,0x83,0x7f,0xb3,0x89,0x53,0x88,0xdd,0x04,0x76,0x64,0x4b,0xcc,0x99, + 0x33,0xf6,0x93,0xec,0x41,0x34,0xca,0x2f,0x75,0x8d,0x22,0x43,0x8b,0x38,0x18,0xdf, + 0x4c,0x15,0xa2,0x4d,0x13,0x7f,0xdc,0xc7,0x7f,0x80,0xf1,0x9a,0x43,0x0a,0xec,0x88, + 0x50,0x64,0x31,0x0f,0xd3,0x5e,0xe2,0xc5,0x9e,0x9b,0x35,0x91,0x42,0x01,0x33,0x1f, + 0x04,0x36,0x6c,0xb4,0x40,0xc7,0x9a,0x1d,0x64,0x35,0xec,0xce,0x24,0xb1,0x2c,0xa2, + 0x08,0x5d,0xb1,0x4f,0xfc,0x89,0xa9,0xd0,0x70,0x62,0xd5,0x0c,0x23,0x46,0xf3,0x90, + 0x0c,0xea,0xf8,0xda,0x71,0x6d,0xc4,0xc0,0x1c,0xca,0x85,0xb4,0x6a,0x65,0xed,0xab, + 0x95,0x05,0x44,0xa8,0x81,0xec,0x85,0xd8,0x92,0xba,0x87,0x75,0x44,0x22,0xbe,0x31, + 0x68,0x16,0x96,0x02,0xd9,0xb1,0x3a,0xb9,0x87,0x1d,0x68,0xb4,0xbe,0xaf,0xb3,0x2e, + 0x50,0x08,0x26,0x31,0x5c,0x6e,0xc6,0x71,0xd4,0xf0,0x2a,0x54,0x87,0xbb,0x39,0xc7, + 0xa6,0x2d,0xf6,0x83,0x22,0x00,0x88,0x3a,0x40,0x75,0x41,0x78,0xb3,0x2c,0x93,0x5c, + 0x31,0xa5,0xf4,0x2c,0x27,0xab,0xbd,0x72,0xe5,0x56,0xe9,0x0c,0xe1,0x79,0xa3,0xb4, + 0xcb,0xd3,0x18,0xc7,0xde,0x28,0x4a,0x5c,0x62,0xfb,0xa0,0x35,0x2f,0x41,0x14,0xc1, + 0x31,0x4d,0xd2,0xc5,0x7c,0xb9,0x8a,0x54,0x29,0x4e,0x0b,0x72,0x26,0xd1,0x5d,0x75, + 0x77,0x22,0xf6,0x17,0x3f,0x1d,0x03,0xa5,0x15,0xfb,0x49,0x91,0x3f,0x4c,0xef,0x9e, + 0x85,0x19,0x8a,0x1d,0xfe,0xe4,0xa1,0x25,0x24,0xe1,0x1e,0x81,0xbd,0x35,0xf4,0xb2, + 0x3b,0x0f,0x66,0xa8,0xc2,0x03,0xbf,0x42,0xc6,0x9b,0x6a,0xa6,0x29,0x35,0x86,0xab, + 0xa9,0x78,0xed,0xc6,0xa4,0x15,0xf5,0x05,0xd5,0x46,0x71,0x18,0x80,0x9e,0xcc,0xdd, + 0xa0,0xff,0x2c,0x1d,0xc7,0x7d,0x6a,0x1a,0x2c,0x15,0x17,0x9d,0x78,0xb0,0x8c,0x81, + 0x34,0xf5,0x79,0xd0,0xfb,0xdd,0x1c,0x1f,0xbb,0x24,0x7f,0x68,0x68,0x08,0x05,0x05, + 0xf2,0xaa,0xe2,0xb0,0xe5,0x01,0x01,0xc8,0xbc,0x7e,0x84,0x72,0x47,0xf6,0x00,0xf3, + 0xad,0x51,0x71,0x89,0xd8,0xf8,0xac,0x10,0xbb,0xba,0x6f,0x42,0xb5,0x8b,0x9a,0x2a, + 0xfd,0x10,0xd8,0xa6,0xe2,0xce,0xbe,0x96,0x46,0x10,0x23,0x4c,0x04,0x8f,0x2b,0x72, + 0x3a,0x07,0x69,0x5f,0x34,0xd3,0xf2,0x6e,0x61,0x72,0x52,0x7d,0x24,0x8b,0xde,0xd0, + 0x03,0x19,0xca,0x5b,0xca,0x99,0x33,0xcd,0x7e,0xb5,0x13,0x62,0xbf,0xeb,0x13,0x32, + 0xe1,0x83,0x18,0xde,0x91,0xb6,0x6e,0x4b,0x04,0x89,0x84,0xfc,0x62,0xd7,0x0e,0x00, + 0x00,0xa5,0x9e,0xe9,0xf0,0xec,0x01,0xcb,0x38,0xba,0xf1,0xc6,0x3b,0x8b,0x2a,0xd7, + 0xc0,0xac,0x66,0x5d,0x5e,0xd9,0x7f,0xea,0x5a,0xb7,0x83,0xcb,0x52,0x70,0x1f,0xc3, + 0x2c,0x54,0x68,0xe5,0x87,0xc4,0x27,0x6f,0x8a,0xbe,0x25,0xd2,0xa7,0xd8,0xab,0x55, + 0xab,0xb8,0x4e,0x46,0x6d,0xe8,0xc8,0xde,0x39,0xac,0x4a,0x2c,0x15,0xc2,0xd8,0xaf, + 0x1d,0x76,0x99,0x38,0xd0,0xe6,0xae,0x0f,0x12,0xf8,0xea,0xd1,0x72,0x03,0xd1,0xa7, + 0x5c,0xae,0x07,0xc0,0x71,0x87,0x81,0x37,0x5e,0x4a,0xb4,0x75,0x0e,0x64,0x8f,0xc6, + 0xde,0xc4,0x5d,0x04,0x59,0xb1,0x99,0xf9,0xb2,0xb2,0x07,0xc8,0x31,0x1e,0x0a,0x0e, + 0x05,0x59,0x71,0x68,0xb8,0x0c,0xf7,0xca,0xaa,0x5e,0x27,0xe0,0x75,0x0b,0x42,0x54, + 0x01,0xaf,0x75,0x9a,0x86,0x10,0x05,0xa2,0x0f,0xf2,0xaf,0x1b,0xb4,0x68,0x4e,0x7b, + 0x1d,0xd5,0x01,0x27,0x2a,0x10,0xe6,0x55,0x1c,0x42,0x74,0x63,0x19,0x9d,0x12,0x83, + 0x50,0x80,0x59,0x84,0x20,0xe3,0x1a,0xbd,0x24,0xd9,0xa4,0x4a,0xc8,0xf6,0x4c,0x9d, + 0x98,0x03,0x09,0x98,0x7b,0xeb,0x0d,0xdd,0x24,0x5f,0xf2,0x13,0xff,0xde,0x1b,0xf3, + 0x12,0x6b,0xf7,0x13,0x02,0x0b,0x2c,0x7b,0xe6,0x53,0x73,0xd9,0xbe,0xdb,0x7e,0x46, + 0x6f,0x80,0x6b,0xb5,0x5e,0xd6,0x51,0x18,0x89,0x33,0x45,0x28,0x09,0x2c,0x59,0x30, + 0x6a,0xd2,0xeb,0x8e,0xe1,0x85,0xb7,0xcd,0xd4,0x9d,0x78,0x2d,0xe8,0xb3,0xdb,0x22, + 0xba,0x23,0xd8,0x64,0xe0,0x5a,0xe4,0x84,0xd2,0xb6,0xb6,0x6a,0xd3,0xec,0x12,0xfc, + 0xc5,0xc0,0x9c,0x74,0x56,0xda,0x6e,0xf2,0x6f,0x40,0xf0,0xcb,0x24,0x5e,0xfb,0xe8, + 0xa4,0xb1,0xd8,0x88,0x30,0x31,0x88,0xb2,0xe5,0x97,0x88,0x70,0x65,0x5d,0x4b,0x59, + 0x88,0x62,0x2c,0xc5,0x6a,0xa1,0xa1,0x6c,0x23,0x6e,0xe0,0xe8,0xb9,0x5a,0xea,0xc7, + 0x13,0x03,0x07,0xa8,0xa7,0xb7,0x2b,0x5b,0xd9,0xcb,0xf6,0x46,0x68,0xbf,0xa1,0x5e, + 0xe3,0x0b,0xd4,0x62,0xfb,0xde,0x5c,0x74,0xf0,0xef,0x5d,0x29,0x54,0xe3,0x04,0xe4, + 0x19,0x9b,0x1f,0x01,0xba,0xa3,0xbf,0x75,0xd5,0x50,0xad,0x77,0xae,0x9f,0x6d,0x52, + 0x2b,0x71,0xb9,0xeb,0xab,0x95,0x8c,0x70,0xe6,0x07,0x5e,0xfa,0x97,0x58,0x7c,0x54, + 0x52,0x68,0x2c,0xbe,0xc0,0x10,0xac,0x77,0x15,0x71,0x5e,0x87,0xb8,0xb4,0x42,0xbb, + 0xaa,0x8a,0x5a,0x36,0x67,0x25,0xcf,0x54,0x47,0x5d,0xff,0x32,0xb2,0x50,0x37,0x0a, + 0x78,0x7e,0x54,0xa7,0xbc,0xe5,0x7c,0xe9,0xb2,0xcc,0xb1,0x56,0x54,0x7c,0x2b,0x18, + 0xb3,0x91,0x1b,0xde,0xba,0xe9,0xb2,0xca,0x3f,0x1d,0x20,0xc1,0x2f,0x0c,0x19,0x1a, + 0x0b,0xbd,0x6c,0x73,0x7e,0x5e,0xab,0x73,0x23,0x85,0x09,0x49,0xd1,0x85,0x2d,0xbf, + 0x48,0x41,0xb5,0x3d,0x7d,0xad,0xb2,0xb6,0x8e,0x97,0xe7,0x0d,0x0b,0x89,0x3d,0x8f, + 0xa2,0x17,0xb8,0x4a,0xf7,0x5c,0xac,0xb3,0xcd,0x19,0x80,0xcc,0xa4,0x92,0x3d,0x2f, + 0xeb,0x34,0xfe,0x8a,0x44,0x84,0x55,0xa7,0x80,0x4d,0xc1,0xb2,0x86,0x49,0x4e,0x61, + 0x36,0x80,0xc9,0xf6,0x82,0x2f,0xa6,0xc0,0x2b,0xf7,0xa8,0xb5,0xea,0xb4,0x5e,0x4b, + 0xa8,0xe4,0x59,0xc5,0xa3,0x9a,0xc7,0x2d,0xa1,0x85,0x1a,0xed,0x3f,0x25,0xad,0xfe, + 0xfd,0x07,0x08,0x95,0x65,0x6a,0xec,0x97,0x3a,0xfc,0x02,0x1f,0x01,0x3c,0xb0,0xc3, + 0xa0,0x22,0x53,0xe0,0xf0,0xfe,0xc1,0xed,0x2c,0x9f,0xad,0x82,0x22,0xb3,0x8d,0xc4, + 0xdf,0x60,0x6d,0x66,0x9a,0x79,0x71,0x8d,0x1e,0xf1,0xb0,0xba,0x0d,0x69,0xf9,0x91, + 0x44,0x30,0x7a,0xc8,0xc6,0x2a,0x9b,0x49,0xb7,0x6e,0x62,0x68,0x0a,0xf3,0x4a,0x6a, + 0x95,0x76,0x92,0xfd,0x8e,0x00,0x49,0xcb,0x0c,0x0b,0xf2,0x1b,0x87,0xfb,0x52,0x38, + 0x50,0x3c,0x3e,0xc1,0x95,0x9e,0x90,0x7c,0xfe,0xda,0x6c,0xc1,0x17,0x4b,0x71,0x31, + 0xfb,0xb5,0x02,0xcd,0x4d,0x91,0x36,0x93,0xb2,0x6a,0x63,0x1d,0xe5,0x1a,0x36,0x3b, + 0x17,0xcb,0x74,0xf1,0xa3,0x5b,0x2f,0x18,0xf5,0x73,0xc5,0xf3,0xab,0xf6,0xed,0x9d, + 0x1c,0x36,0xb3,0x33,0xb2,0x26,0xe4,0x4c,0x70,0x1e,0x61,0x7e,0xca,0xf0,0x90,0x02, + 0x9b,0x1c,0xea,0x41,0xbb,0xfe,0x00,0xed,0x39,0x8e,0x6a,0x85,0x4c,0xa2,0x51,0x0f, + 0x91,0xa2,0x18,0x08,0xc6,0x41,0xd1,0xad,0x7a,0xf6,0x2b,0xf6,0x43,0x41,0x5a,0xbb, + 0xba,0x8c,0xdb,0xcd,0x85,0x9c,0xbd,0x75,0x2b,0x1c,0xe6,0xba,0xb5,0xea,0x64,0x40, + 0x13,0xf2,0xdc,0xd0,0x9f,0x33,0xd5,0x4f,0x8c,0x4e,0x6a,0x60,0x15,0xc0,0xd6,0xf9, + 0xe1,0x04,0xcf,0xc2,0xbd,0x7e,0x9d,0x70,0xf0,0xd4,0xf8,0x1f,0x37,0xde,0xc3,0x24, + 0x71,0xe7,0x5e,0x6a,0x24,0xcb,0x2c,0x5a,0xe6,0x58,0x94,0x44,0x19,0xa0,0x50,0x73, + 0xef,0xb0,0x3d,0xf6,0xa6,0xd6,0x13,0x8c,0x03,0x98,0x01,0x3a,0xf5,0x5c,0x96,0x39, + 0x84,0x82,0xe6,0xa0,0xa8,0xc2,0x21,0x26,0x2e,0x57,0x4c,0xe1,0xee,0x05,0x35,0xdd, + 0xdc,0x56,0x38,0xb7,0x7e,0x61,0xe1,0x6d,0xa0,0xd9,0xe8,0x96,0x04,0xa1,0xf6,0x26, + 0xbb,0x02,0xb5,0xbd,0x9e,0xea,0xdf,0xdc,0xd6,0x6e,0xfb,0x35,0x74,0x1a,0x72,0x8a, + 0x9d,0x59,0x5b,0x18,0x1a,0xa6,0x90,0x34,0xb1,0xf9,0x51,0x1d,0x7c,0xf7,0x96,0x3a, + 0x7e,0x7e,0xe5,0xcf,0xd1,0x40,0xc1,0x0d,0x69,0xb7,0x8a,0x32,0xaf,0x2a,0x09,0x56, + 0x68,0xe4,0x46,0x4c,0xcf,0x51,0x49,0x29,0x44,0xac,0x4b,0xad,0xba,0x1f,0x30,0x7d, + 0xbe,0x6c,0xb5,0xb2,0x49,0xef,0xc5,0xf8,0xa5,0xd7,0xf6,0xdc,0x3e,0xbc,0x8c,0xfd, + 0x79,0xef,0xc5,0xe1,0xf8,0xe5,0xe8,0x68,0x82,0xaf,0x74,0x3c,0x7f,0x70,0xe4,0x1e, + 0x4e,0xe8,0x75,0x8a,0xc6,0x08,0x07,0x2f,0x47,0xdd,0x43,0x0f,0x5f,0xc9,0x56,0x61, + 0x32,0x79,0x39,0x7c,0xd9,0xc5,0x57,0xb6,0x55,0xf0,0xf6,0x86,0x7b,0xfb,0x9d,0xc2, + 0xf1,0xdb,0x8b,0xf6,0xb0,0xed,0x75,0xba,0x85,0x11,0x65,0x93,0x9a,0x73,0xa4,0x17, + 0xdd,0x76,0xf7,0x68,0xaf,0x5b,0x77,0x86,0xc4,0x64,0x6b,0xe2,0xce,0xfd,0xe0,0xa1, + 0x57,0x38,0x7f,0xbb,0xf8,0xfe,0x3d,0x3c,0xb7,0x3e,0x79,0xd3,0x45,0xe0,0x26,0xe5, + 0xe3,0x38,0xf3,0x9d,0x3f,0xf4,0x98,0x63,0x32,0x30,0x9f,0x99,0x1f,0xd0,0x15,0x49, + 0x21,0xd2,0xdb,0xc2,0xc9,0xdf,0x41,0x11,0x6d,0xf1,0x9f,0xd6,0xd8,0x4f,0xbc,0x11, + 0xad,0x43,0xe6,0x5e,0x2b,0x18,0xd0,0x10,0xc5,0x5f,0x1e,0xc1,0xbe,0xa4,0x6b,0x6d, + 0xf7,0x89,0x7b,0xe5,0xa3,0xbd,0xa6,0x20,0x92,0x50,0x09,0x5a,0xc3,0x58,0x4b,0x9e, + 0x8b,0xe2,0xf1,0xc3,0x13,0xdb,0x1b,0xe0,0xf1,0x4f,0x6b,0x14,0xf8,0xcb,0x92,0x35, + 0x40,0x5b,0xcc,0x60,0x6b,0x36,0xde,0x58,0xe2,0xca,0x8f,0x5b,0xcb,0x5a,0x86,0xe2, + 0x74,0x75,0x3a,0x9d,0xc3,0xce,0x78,0xe5,0x9a,0x93,0xb3,0x94,0xf7,0xd7,0x39,0xea, + 0x96,0x36,0x75,0x44,0x24,0x2b,0xef,0x62,0x51,0x02,0x95,0x89,0xfa,0x91,0x1b,0x6b, + 0x7a,0xeb,0x35,0xbf,0x7a,0xd3,0xee,0xde,0xde,0x5e,0x45,0x0d,0x86,0x03,0xa8,0xb4, + 0x5e,0x64,0x34,0x15,0x83,0x21,0x84,0xc2,0xaa,0xba,0xb0,0xd0,0xa9,0x9a,0x43,0xdb, + 0x1c,0x63,0x05,0xc5,0x7e,0xb1,0x37,0xde,0x77,0x0f,0x5c,0x59,0x36,0x5a,0x64,0x92, + 0x5f,0x50,0x56,0x1a,0x0f,0xcc,0x92,0x54,0xac,0x36,0x0a,0xfc,0x4e,0x5f,0x9a,0x9d, + 0xa8,0x6c,0x7c,0xc2,0x83,0xdf,0xb3,0x68,0x31,0x9a,0x69,0x2d,0x1c,0xa3,0x51,0x81, + 0xce,0x76,0xc6,0x89,0xd7,0x22,0xb3,0x01,0x3c,0x18,0x6b,0x0d,0x13,0xcf,0xbd,0xe9, + 0xd1,0xbf,0x2d,0x4c,0xd0,0x4a,0x1a,0xce,0x68,0x3e,0x16,0x03,0x42,0x55,0x62,0xf9, + 0x53,0x45,0x6d,0x79,0x6c,0x98,0xc5,0x29,0x9d,0x0a,0xc1,0x4e,0x95,0x02,0xc9,0x4d, + 0x56,0xf8,0xd2,0xf3,0x5e,0x1e,0xbd,0x2c,0x7c,0x45,0xf5,0x4e,0xa1,0xbc,0x10,0x38, + 0xf3,0x1c,0xe9,0x43,0xba,0x5c,0x89,0x34,0x94,0x03,0x30,0x77,0x29,0x56,0x90,0x73, + 0x70,0xc0,0x52,0x13,0x7e,0x74,0xc3,0xd1,0x2c,0x4a,0x6a,0xd4,0xcd,0x22,0xb3,0x76, + 0xce,0x91,0xeb,0x79,0x64,0xe1,0x74,0x31,0xad,0x51,0x0b,0xaf,0x52,0x13,0x69,0xcc, + 0xa6,0x60,0xb0,0x17,0x53,0x48,0xb3,0xf7,0xf7,0x6f,0x67,0x56,0x65,0xa6,0x8b,0x64, + 0xcf,0xeb,0xec,0x75,0xdc,0x7a,0x35,0x52,0x4e,0xea,0xb4,0xf3,0xb7,0x16,0xb1,0xbf, + 0xc8,0x76,0x14,0x8c,0x98,0x0e,0x0e,0x88,0x9d,0x9c,0xd6,0x1f,0x35,0x14,0x56,0xfc, + 0x10,0x58,0x6e,0x24,0x63,0x0a,0xc1,0x0e,0xe4,0x0a,0xaf,0x20,0x7c,0x3a,0xc5,0x2d, + 0xae,0x68,0x2c,0x22,0x36,0xbb,0x83,0xb6,0x14,0x6f,0x5f,0x8c,0x26,0xde,0x1e,0x10, + 0xff,0x12,0xca,0x89,0xe2,0xc6,0xa2,0x38,0x7f,0xc4,0xbd,0x94,0xd5,0x31,0x75,0x72, + 0x2b,0x97,0xf7,0x75,0xb3,0x99,0xfe,0xba,0x53,0x07,0xe7,0x68,0xbf,0x8e,0xc0,0xf4, + 0x1b,0x7f,0x45,0x50,0x4b,0xa7,0x25,0xd6,0xfc,0x45,0xc7,0xeb,0x0e,0xf7,0x5c,0x7d, + 0x4e,0x88,0xf7,0x24,0xab,0x32,0x3c,0x1b,0xd5,0x86,0x29,0xcb,0x03,0x0c,0x0b,0x6b, + 0x8a,0x13,0x7d,0x99,0x78,0x34,0x7c,0x35,0x74,0xd5,0x32,0xc4,0x99,0xf9,0x0b,0xd4, + 0xfa,0xa8,0x96,0x5a,0x6f,0x80,0x65,0xb2,0xfd,0x38,0xd5,0x26,0xbc,0x66,0x6d,0xbf, + 0xa0,0x5c,0x7e,0x58,0x73,0x6a,0xa5,0x9d,0xbc,0xe5,0xa2,0x7e,0x81,0x0a,0xaf,0x12, + 0xfd,0xe9,0xdc,0xa2,0x51,0x20,0xc6,0xfa,0xe9,0x77,0x1f,0xe4,0x58,0x2f,0x6b,0xad, + 0xe9,0x4d,0xe1,0x04,0x9b,0x9a,0x55,0xd3,0xc3,0xb8,0xa4,0x32,0xf6,0x00,0xb0,0x23, + 0x6f,0x16,0x05,0x63,0x45,0xbb,0x5f,0xec,0xbf,0x3a,0x78,0x79,0xf8,0x52,0xcb,0xa4, + 0x94,0xf4,0x2b,0x49,0xcf,0x34,0x5a,0x56,0x81,0xdf,0x95,0xc0,0xdf,0x70,0x53,0x3a, + 0x2c,0xcd,0x53,0x15,0xe6,0xd5,0x4d,0xaa,0x7e,0x53,0x9a,0x46,0x75,0xbb,0x11,0xc2, + 0x68,0xed,0x7e,0x04,0xc5,0xaa,0xe7,0x11,0xfb,0x95,0xf3,0x08,0xce,0x3c,0x9a,0xcc, + 0x97,0xcf,0x0d,0x4c,0x9e,0x55,0x15,0x58,0x6f,0xe2,0xfa,0xea,0x98,0xd0,0x22,0x47, + 0xd1,0xed,0x1c,0x75,0x26,0x55,0x44,0x16,0x4a,0x8a,0x43,0x71,0x7a,0x29,0xbb,0x62, + 0x38,0xb3,0xe2,0x60,0xb9,0x91,0x22,0x1b,0x7b,0xa0,0xb8,0x58,0x2e,0x12,0x84,0x72, + 0xca,0xdd,0x57,0xc3,0x97,0xa3,0xc3,0xfe,0xe6,0xdb,0xa4,0x52,0x43,0xf1,0x18,0xb9, + 0xd1,0xd0,0xde,0x1b,0xcd,0x84,0x56,0x0f,0x77,0x10,0x94,0x18,0x51,0xb9,0xdf,0xea, + 0x18,0xdf,0x18,0x7a,0x16,0xab,0xd4,0x8d,0x55,0xba,0xba,0x95,0xf8,0x46,0xe5,0xee, + 0xd6,0x8c,0xb8,0x7a,0x60,0xee,0xbc,0xca,0x37,0x43,0x2a,0x3e,0xcc,0xc2,0x1a,0x05, + 0x87,0xa4,0x23,0x34,0xf6,0x1e,0x01,0xa0,0x28,0xc0,0xe9,0x75,0x08,0x76,0xec,0x0b, + 0xf0,0xbb,0x30,0xc5,0xc3,0xee,0xc1,0x5e,0xbb,0xc2,0xe3,0x37,0x6a,0xb9,0xb0,0x7d, + 0xa1,0xe5,0x59,0x81,0xf1,0x79,0x6f,0x1c,0x58,0x8b,0x85,0x56,0xc6,0x7b,0xc3,0xee, + 0x51,0x09,0xef,0xbb,0x93,0xc3,0xe1,0xfe,0x81,0xb2,0x31,0x9c,0x78,0x6d,0xf7,0xa0, + 0x5a,0x55,0xdd,0x6a,0xa8,0x1e,0xcf,0x39,0xc0,0x6b,0xb7,0x32,0x3f,0x7e,0xd6,0x72, + 0x53,0x83,0xe3,0xab,0xb2,0x88,0xab,0x84,0xd8,0x22,0xec,0xf3,0xda,0x8d,0x9b,0xe1, + 0x78,0x59,0x3d,0xfb,0xac,0x13,0x6f,0x58,0x9e,0xc9,0x85,0x96,0x15,0x52,0x60,0xa3, + 0x38,0x3b,0xfb,0x9a,0x18,0xd8,0x66,0x5d,0xda,0xeb,0x5d,0x61,0xe1,0xfe,0x7a,0x57, + 0x58,0xe4,0xa3,0x7c,0x21,0xec,0xf3,0xbd,0x04,0x2d,0xe0,0x6f,0xa7,0x06,0x1b,0xdc, + 0x9b,0xdd,0x43,0xd3,0x60,0xae,0x87,0x9f,0xd1,0xa2,0xfe,0xdb,0xe8,0x7e,0x60,0x92, + 0x89,0xd0,0x3e,0xfc,0xdf,0x34,0x50,0x59,0x3f,0x30,0x11,0xb5,0x4d,0x23,0xcd,0x92, + 0xe8,0x06,0x4d,0xf8,0x95,0x16,0x43,0xa6,0xb5,0x64,0x8d,0x2a,0x01,0x49,0xff,0xc8, + 0x8d,0x07,0x26,0x8d,0x02,0x2d,0xf3,0x47,0x7e,0x32,0x0a,0x3c,0x63,0x04,0xf5,0x77, + 0x20,0xdf,0xe8,0x81,0x7f,0x13,0x28,0xe5,0x74,0x65,0x43,0xd5,0xaa,0x45,0xe3,0xbb, + 0x50,0x43,0xec,0x66,0x33,0x63,0x3c,0x30,0xdf,0xbf,0x74,0x5e,0x1a,0xf0,0xe7,0x1e, + 0x1a,0x87,0x46,0x5b,0xfc,0xef,0xc8,0x39,0x7c,0xdf,0x39,0x74,0xf6,0x0a,0x1f,0x3a, + 0xe2,0xc3,0xbe,0xf3,0xca,0x80,0x3f,0xb7,0x83,0x76,0xcb,0xaa,0x48,0x67,0xdf,0xe9, + 0xbe,0xef,0xbc,0x72,0x3a,0xa5,0x6f,0x1d,0xf1,0x8d,0x1a,0xdd,0x05,0x80,0xc1,0x0f, + 0xb0,0xe4,0xc6,0x08,0x64,0xcd,0x74,0x60,0x92,0xe1,0x2f,0xf9,0x3c,0x74,0x0c,0x1f, + 0xba,0x33,0x6b,0xa1,0x67,0x83,0xa9,0x9c,0x0e,0x00,0xf4,0x1d,0x51,0x82,0x3f,0xa7, + 0x8b,0xa1,0x79,0x0c,0x2c,0x77,0x88,0x62,0x65,0x38,0xdd,0x9a,0x11,0xcb,0xd2,0x7f, + 0xbd,0x0b,0x59,0xb0,0x05,0xfe,0x21,0xbb,0x0c,0xd1,0x04,0x59,0x7e,0x1a,0xa8,0x50, + 0x30,0x45,0x1d,0x94,0x62,0x1e,0x43,0x77,0x20,0x1b,0x4e,0x2b,0xa1,0xbb,0xea,0x12, + 0xda,0xa0,0x16,0xf2,0x8f,0x48,0x36,0x86,0x57,0x32,0x96,0x33,0x39,0xbb,0x69,0x44, + 0x21,0x20,0xe7,0xe8,0x06,0xbd,0x36,0x60,0xe5,0xb0,0x00,0xed,0x35,0x2d,0xb3,0x41, + 0x0e,0x12,0x03,0x53,0xa4,0x18,0xad,0x96,0x91,0xde,0x00,0x0a,0x93,0xf1,0xa9,0xe1, + 0x86,0x63,0x23,0x76,0xd3,0xcc,0x33,0x5c,0x03,0x88,0x2c,0x9e,0x08,0x8d,0xd1,0x7d, + 0x63,0xe2,0x4f,0xcd,0x86,0x9b,0xf8,0x6e,0x8b,0x8c,0x0a,0x07,0xe6,0xc7,0xd8,0x0b, + 0x0d,0xd9,0xf4,0xf1,0xd6,0x34,0xeb,0x7f,0x7e,0xbd,0xcb,0x6d,0x4b,0x94,0x24,0x24, + 0x44,0x53,0x55,0x1c,0x32,0xcb,0xd9,0xd4,0xe5,0xdb,0x56,0x10,0xc1,0x5a,0x33,0xf3, + 0x21,0xc1,0x60,0x8a,0x80,0x47,0x65,0x38,0xc1,0xbd,0x7b,0x7c,0x3a,0x06,0xb6,0xc5, + 0xa0,0x12,0x50,0x6d,0x17,0x91,0xc3,0x20,0xcc,0x1f,0x98,0x15,0xc5,0xd4,0xaa,0x55, + 0x2d,0x65,0x5e,0x58,0xc3,0xe6,0xf1,0x1b,0x84,0x87,0x91,0xcd,0xfc,0xd4,0x08,0xa3, + 0xb1,0xb7,0x9d,0x1a,0x2e,0x35,0x21,0xcd,0x11,0x8d,0x66,0x36,0xf3,0x8c,0x14,0x26, + 0x1a,0x60,0xe8,0x19,0x8b,0x14,0x20,0x00,0xa2,0x94,0x91,0x78,0xf3,0x08,0xe0,0x72, + 0xf6,0xee,0x2d,0x17,0xb0,0x9c,0xd7,0xbb,0x31,0x74,0x07,0x55,0x70,0x34,0x2e,0xea, + 0x63,0x0b,0x5f,0x4b,0xa3,0x99,0xc0,0x6c,0x12,0xd8,0xb0,0x1e,0x99,0x2f,0xbe,0x83, + 0x11,0x9e,0x8b,0x36,0x5f,0xef,0xd2,0x77,0x28,0x46,0xd6,0x1b,0x62,0x2a,0x65,0x8f, + 0x4c,0xad,0x7a,0x2c,0x46,0x16,0xbe,0xa3,0x68,0x1e,0x07,0x5e,0x06,0xd9,0x80,0xe6, + 0xe1,0xb9,0x5d,0x2b,0xcf,0x8e,0xdf,0x89,0xcb,0x3a,0x96,0x28,0x57,0x44,0x22,0xd8, + 0x5d,0x24,0xba,0x00,0xc6,0xce,0xfd,0x4c,0x6f,0x01,0x3f,0x1e,0x5f,0x00,0x1f,0x6b, + 0x20,0xc4,0xd5,0x94,0x6a,0xe3,0x91,0xda,0x45,0xbd,0x14,0xa4,0x99,0xaa,0xb5,0x5d, + 0x04,0x42,0x8e,0xef,0xbb,0x62,0xf6,0x2b,0x78,0x70,0xe7,0xff,0x81,0x13,0xbd,0x06, + 0x11,0x50,0x97,0xc6,0xcd,0x8c,0x42,0xb7,0x45,0x6f,0xc7,0x6f,0x43,0x03,0x67,0xe8, + 0x17,0xff,0x7b,0xdf,0x48,0x89,0xdf,0x86,0xc9,0x8b,0xe2,0x45,0x7c,0x62,0xbc,0xcd, + 0xa0,0x60,0x94,0x7a,0xa9,0xe1,0x4f,0x8c,0x87,0x68,0x91,0x18,0xf1,0x0c,0x27,0x31, + 0x0d,0x3c,0x2f,0x4e,0x9d,0xc6,0x6b,0xd7,0x98,0x25,0xde,0x64,0x60,0xbe,0xd0,0x16, + 0x08,0x94,0xfd,0xb8,0xc8,0x9a,0x56,0x1f,0x18,0xd7,0x45,0x12,0x1a,0x13,0x37,0x48, + 0x89,0x06,0x12,0x92,0x55,0x65,0x0d,0xf3,0x98,0x90,0x1f,0x5a,0xa5,0x16,0x86,0x49, + 0x74,0x97,0x7a,0xc9,0xeb,0x5d,0xf7,0xd8,0xc8,0x22,0xe3,0x06,0x5a,0x12,0x4d,0x27, + 0xd1,0x34,0xf1,0xd2,0xd4,0x91,0x70,0xd0,0xc6,0x45,0x87,0x09,0x00,0x30,0x9f,0xc6, + 0x96,0x66,0x71,0x47,0x41,0x01,0x16,0x2f,0x00,0xd2,0xd7,0xbe,0x75,0xcb,0x09,0x7b, + 0xe5,0x84,0x7d,0x91,0xa0,0x35,0x84,0x5f,0xee,0xfe,0xe8,0xac,0x5e,0x58,0x17,0xd0, + 0x05,0x20,0x80,0x5b,0x73,0x10,0xb5,0xa2,0xac,0x4f,0xf0,0xfc,0x5b,0x56,0x98,0x68, + 0x1a,0x66,0x77,0xe2,0x03,0x75,0x8a,0x1f,0xcc,0xe3,0x33,0x26,0x89,0xf9,0xaa,0x43, + 0x48,0x11,0x90,0x68,0x16,0x43,0x2f,0x03,0xc4,0xbd,0x01,0x06,0xc5,0xf0,0x61,0x06, + 0x81,0x3a,0x02,0x2f,0x37,0x9a,0xd1,0x34,0xbf,0xff,0x8f,0xcb,0x4b,0x20,0x4e,0x09, + 0x70,0xcc,0xa9,0x58,0x71,0x65,0xfc,0x38,0x7e,0x3d,0x3c,0x3e,0x27,0x62,0x05,0x34, + 0x57,0x5f,0xab,0x63,0x2f,0x0e,0xa2,0x87,0x39,0x2c,0x8e,0x13,0xc0,0xe4,0x63,0xe3, + 0x12,0x9b,0x67,0xa4,0x33,0x32,0x2f,0xcd,0xd2,0x1c,0x91,0x58,0x5d,0x02,0x05,0x87, + 0x51,0x94,0x31,0x85,0x1e,0xbb,0x99,0xdb,0xa2,0x9d,0x6d,0xaf,0xfb,0xf2,0xf0,0xc8, + 0x3c,0x36,0x16,0x61,0x00,0xf3,0x89,0x1d,0x37,0x00,0x47,0x22,0x74,0x7f,0x0b,0x81, + 0x7a,0x13,0xbd,0x98,0x11,0xa9,0x7c,0x73,0x71,0xde,0xfa,0xf0,0xf1,0x17,0xfa,0x12, + 0x7a,0x81,0x20,0xe2,0x8e,0xf1,0x76,0x42,0xb9,0xf2,0x0e,0xa9,0x31,0x13,0x40,0x32, + 0xc3,0xbd,0x75,0xfd,0x00,0xf9,0x19,0xd8,0xa7,0x13,0xcf,0x46,0xb2,0x63,0xfc,0x7c, + 0xf1,0x2d,0x8e,0xdc,0x77,0x03,0xc3,0xcd,0x0c,0x18,0x24,0x13,0x62,0x67,0x0e,0xdb, + 0x0f,0xf0,0xa2,0x9e,0xe3,0x47,0x34,0x2c,0x24,0xda,0xc9,0x22,0xc4,0x1c,0x28,0xde, + 0x22,0xdc,0x9d,0x34,0x05,0x56,0xcf,0x71,0x1c,0x95,0x41,0xff,0x08,0x44,0x44,0x7e, + 0x73,0x00,0x28,0x1e,0x4f,0x09,0x9a,0x97,0x10,0x44,0xe6,0x90,0x2b,0x9b,0xa1,0xc6, + 0x26,0xdf,0xca,0xb8,0x11,0x2f,0x4b,0x7c,0xc8,0xe3,0x4e,0x90,0x84,0xe6,0x83,0xa9, + 0xc3,0x70,0x45,0xf4,0x8e,0x3f,0x88,0x91,0xe2,0xde,0x69,0x34,0x2f,0x2e,0xde,0x7e, + 0x67,0xe5,0xf4,0x4e,0x2b,0x01,0xeb,0x48,0xad,0x3a,0xc1,0xed,0x9a,0x25,0x8a,0xc8, + 0x54,0x87,0x26,0xe6,0x06,0xbd,0x09,0xc5,0x40,0x15,0xca,0xf1,0x0b,0x91,0x47,0x37, + 0xf6,0x33,0x10,0xc7,0xff,0x80,0x52,0xd1,0x64,0x22,0x69,0x66,0x82,0x0a,0x5f,0x91, + 0x22,0x71,0x9c,0x84,0x63,0xb3,0x8e,0x48,0x02,0xf4,0x47,0xd5,0x7d,0x75,0x1e,0xe1, + 0x9e,0x10,0xdd,0x85,0x40,0x09,0xf1,0x58,0xcc,0x81,0x8d,0x12,0x7f,0xbf,0x63,0xa6, + 0x13,0xf6,0xd8,0x9c,0xb6,0x44,0x40,0x29,0x2e,0x00,0xa1,0x9b,0xdb,0xa2,0x77,0xdb, + 0x16,0x10,0x57,0x48,0xd0,0x37,0x4b,0x84,0xdd,0x5a,0x08,0x6e,0xba,0x4d,0x14,0x00, + 0x43,0x3b,0xc5,0xdc,0xbd,0x0f,0xbc,0x70,0x8a,0x1c,0xdb,0xe1,0x7e,0x79,0xe3,0x40, + 0x28,0x94,0x18,0x1e,0xe0,0xdb,0xcd,0xe3,0x77,0x1e,0x60,0x82,0x31,0x0c,0xdc,0xf0, + 0x86,0x56,0x13,0xac,0x05,0x1c,0x87,0x44,0x59,0xc7,0xd0,0xd6,0x07,0x2d,0x72,0x68, + 0xaa,0x85,0x45,0xa9,0xa3,0xf1,0x2c,0x71,0x91,0x02,0xcf,0xdd,0x07,0x58,0x55,0x06, + 0x30,0x15,0xb0,0xd6,0x0f,0xf7,0xc8,0x57,0xd4,0x1d,0x01,0xe2,0xa4,0x7d,0x60,0x2e, + 0x0e,0xf7,0x5b,0x2a,0x01,0x68,0xe6,0x83,0x31,0x5f,0xa0,0x99,0x10,0xa2,0xff,0x3d, + 0xb0,0x0e,0x23,0x7f,0xee,0x06,0x8e,0x58,0x3e,0x46,0xd7,0xd9,0xdf,0x02,0xd2,0x11, + 0xa6,0x71,0xff,0x87,0x1f,0xff,0x90,0xfd,0x48,0x01,0xcc,0xc1,0x83,0xb3,0x06,0x7e, + 0xd5,0x25,0x2c,0x00,0x2a,0x97,0xe9,0x2e,0x2f,0x7e,0xb5,0x5a,0xeb,0xc0,0xcb,0x1e, + 0x09,0x39,0x70,0xbd,0x34,0x86,0x7d,0xc0,0x11,0x65,0x00,0xc4,0x3e,0x20,0x42,0x87, + 0x40,0x0d,0xbf,0x7b,0x88,0x57,0x5e,0x4c,0x29,0x02,0xc1,0xf2,0xf3,0xd2,0x4e,0xb7, + 0xcd,0x38,0x5d,0x01,0xf9,0x7b,0x1c,0xfd,0xdc,0xcd,0x04,0xd1,0x2b,0x0d,0x18,0x38, + 0x6b,0x04,0x13,0x2e,0x41,0xc0,0xb4,0xe4,0x41,0x91,0x19,0x5c,0xb7,0x8e,0x81,0xf8, + 0x14,0x12,0xe9,0x03,0xce,0x9a,0x69,0x1a,0x97,0x00,0xde,0x46,0x74,0xd3,0x31,0x7e, + 0x4e,0x3d,0x82,0x97,0xe1,0xca,0x34,0x23,0x06,0x89,0xca,0xcf,0x32,0x20,0x5b,0x01, + 0xac,0x97,0x00,0x60,0x69,0x9c,0x2a,0x9a,0xe6,0xde,0xc0,0x1c,0x7a,0x93,0x09,0x92, + 0x6d,0x5e,0xef,0x4c,0x1b,0x6d,0xa4,0xd2,0x04,0x35,0xa0,0x5c,0xff,0x02,0x41,0x0f, + 0x8a,0xf3,0x77,0x6a,0x97,0xf2,0xc0,0x8c,0x47,0xce,0x06,0x78,0xfd,0x01,0xc9,0x0e, + 0x92,0x85,0x7a,0xc8,0x17,0x57,0x3b,0xb1,0xde,0x3a,0x42,0xef,0x75,0xea,0x40,0x29, + 0x49,0x01,0x66,0x6f,0x31,0x70,0x2f,0x66,0xb0,0x58,0x61,0xf0,0xd4,0x43,0x24,0x9e, + 0x04,0x49,0xd8,0xbf,0x79,0x6f,0xc9,0xdc,0x6c,0x91,0x62,0x7a,0xea,0x4e,0xbd,0xb4, + 0xd4,0xef,0xd5,0xfc,0x93,0x5a,0xe3,0x77,0x7f,0xfc,0x10,0x35,0xbb,0xb0,0xae,0x3f, + 0x40,0x7f,0x7b,0xc6,0x27,0x10,0xd9,0xa2,0xf2,0xf2,0xd6,0xf7,0xe4,0xee,0x86,0x9c, + 0x2f,0x6d,0xd0,0xdd,0x7c,0x83,0x16,0x15,0xff,0x1d,0x3c,0x30,0x02,0x9e,0x97,0x0f, + 0xac,0x37,0x37,0x31,0x68,0xb7,0x8d,0x00,0x3c,0x89,0x41,0xcc,0x19,0x50,0x33,0x34, + 0x1b,0x35,0x50,0xfc,0x8c,0x50,0x34,0xc0,0x2d,0x20,0x75,0x8c,0x73,0x18,0x30,0x41, + 0x11,0x48,0x1e,0xee,0x26,0xb4,0x85,0x13,0xf2,0x30,0x5c,0x81,0x30,0xd6,0x6c,0xd2, + 0xf9,0x84,0x7f,0xf2,0xa6,0xc8,0xfd,0x71,0xe9,0x7c,0xd2,0xd9,0xcb,0x44,0xce,0x5c, + 0x12,0x13,0x70,0x09,0x0f,0x31,0x81,0xc6,0x7d,0xe1,0x05,0x4d,0xe4,0x1e,0x2c,0x92, + 0x8c,0x28,0xff,0x9a,0xc9,0x4f,0xe2,0x16,0x70,0xc5,0x92,0x21,0x5d,0x8b,0x83,0x97, + 0xbf,0x02,0xf3,0x78,0x07,0x03,0x6f,0x8e,0xbf,0x9d,0x5b,0x9b,0x91,0x80,0xec,0x5e, + 0x2c,0xfb,0xd6,0x2b,0xb1,0xee,0xf7,0xda,0x5f,0xb6,0xdc,0xd9,0xc5,0xdd,0x08,0xbc, + 0x29,0x80,0x8e,0xdb,0x87,0x29,0xc3,0xbd,0x75,0xf8,0x00,0x8b,0x88,0xa0,0xb4,0x35, + 0x1f,0xbb,0xe9,0xac,0x6f,0x90,0x29,0xb7,0x80,0x72,0xb2,0x08,0x2a,0x28,0x5a,0x61, + 0x87,0x3e,0x78,0xb0,0x26,0xe5,0xa4,0xc1,0x74,0x01,0xf3,0x80,0x96,0x7d,0xdb,0x99, + 0x81,0xf6,0x36,0xde,0xf8,0xc4,0x38,0x9b,0x45,0xc0,0x25,0x23,0x4f,0xf0,0x13,0xb2, + 0xab,0x42,0x82,0x50,0x65,0x90,0x31,0xb0,0x0d,0xb4,0x46,0x80,0x39,0x25,0xc1,0xd0, + 0xc6,0x59,0x0f,0x31,0xc9,0x6b,0x65,0x0b,0xe0,0xa8,0x7d,0x5e,0x4d,0xb5,0x0c,0x35, + 0x49,0x9c,0xa7,0x71,0x5c,0x66,0xa9,0x41,0x96,0xbb,0x75,0xc3,0x11,0x74,0xce,0x1b, + 0xfb,0x59,0x44,0x2c,0xb3,0x53,0x5a,0x68,0xa5,0xa5,0xa0,0xa4,0xb2,0x56,0x45,0x24, + 0x8c,0xd5,0xa6,0xf8,0x77,0xac,0x88,0x4f,0x1e,0x29,0x9b,0x99,0x7a,0x4e,0x60,0x5b, + 0x8a,0x80,0xcc,0xca,0x26,0x1c,0x14,0x2c,0x80,0xdc,0x91,0x2c,0x08,0xbb,0x59,0xca, + 0xd2,0x11,0xb1,0x6a,0x06,0x9a,0xef,0x30,0x6d,0x86,0x2f,0x24,0x19,0x22,0x90,0x99, + 0x1c,0x12,0x5f,0xc5,0xcc,0x28,0x2c,0x35,0xd4,0xfa,0x2a,0x1a,0xb4,0x6e,0x99,0x7c, + 0xf0,0xee,0xb4,0xe1,0x6d,0xb6,0xe7,0xe7,0x29,0x1a,0x89,0xec,0x1c,0x94,0xf7,0xfc, + 0xd0,0xbb,0xcb,0x05,0xc5,0x75,0xa8,0xd9,0x39,0xd0,0x76,0xec,0x4d,0x88,0x39,0x05, + 0x60,0x00,0x51,0xf8,0x8b,0x3a,0x3e,0x9a,0xcc,0xff,0x64,0xd7,0x57,0xe3,0x0d,0xf2, + 0x91,0xab,0xb9,0xb9,0x22,0xd9,0xee,0x00,0x3d,0xf9,0xd6,0x1d,0xdd,0x68,0xf4,0xba, + 0x86,0xd4,0x17,0x39,0x45,0x45,0x64,0x90,0x2e,0xb5,0x42,0xda,0xa4,0x8a,0xb5,0xee, + 0xa9,0xcd,0x00,0x77,0x98,0xea,0x5e,0x50,0xd9,0x12,0xf6,0xbe,0x64,0x4b,0xd8,0xcb, + 0xb7,0x04,0xae,0x9e,0xf0,0xbf,0x76,0x4e,0x3e,0x0e,0x59,0x72,0x12,0xbc,0x77,0x94, + 0xf8,0x80,0xf8,0xd6,0x26,0xbb,0xed,0xfc,0xf7,0x2c,0x73,0x38,0x7f,0x3d,0x43,0x5d, + 0x87,0x3b,0x3f,0x46,0x77,0x2c,0xe2,0x45,0xb2,0x5d,0xde,0x4a,0x26,0x48,0xd8,0xfc, + 0x0c,0xc8,0xf6,0x04,0x97,0x4d,0xbc,0x18,0x02,0x21,0x9a,0x21,0x91,0xa2,0xbd,0x77, + 0x17,0x84,0xeb,0x1b,0xd8,0x4d,0xd4,0x16,0x6c,0xbc,0x0d,0x51,0x83,0x40,0xca,0x76, + 0x20,0x7a,0xb4,0x4f,0x49,0x6a,0x88,0xc2,0x92,0xd2,0xc9,0x64,0x51,0xec,0x8f,0xa0, + 0xb9,0x04,0xbb,0x38,0xe3,0x5d,0x0b,0x0b,0xc1,0x4e,0x05,0x54,0x09,0xb8,0x21,0xc8, + 0x87,0xb2,0x4c,0xbe,0x18,0x11,0x10,0x9b,0x60,0xf3,0xdb,0xd3,0xcb,0x53,0x49,0x88, + 0x47,0x50,0x70,0x63,0x98,0xf9,0xf0,0x52,0x64,0x53,0xaa,0xf0,0xcb,0x17,0x96,0xc2, + 0xad,0x95,0x06,0x97,0x9b,0x6c,0x27,0x1f,0x60,0x0f,0x07,0x71,0xd6,0x70,0xfd,0x04, + 0xcd,0x90,0xa8,0xc3,0xb6,0xe1,0x39,0x53,0x07,0x49,0xfc,0x77,0x6f,0x3e,0xb0,0xa4, + 0xf7,0x33,0x82,0x0d,0x09,0x37,0x42,0xcd,0x40,0x1d,0xeb,0x46,0x0b,0xfb,0xe3,0x5d, + 0x08,0x33,0x49,0x93,0x36,0x42,0x56,0x7d,0x73,0xf4,0xc1,0x82,0xf5,0x32,0xc8,0xf3, + 0xd2,0xd9,0x66,0xa2,0xca,0xc7,0x58,0xe0,0x88,0x44,0x0f,0x21,0x57,0xa0,0x18,0xa1, + 0x75,0xd9,0x88,0x84,0x3a,0x08,0x6b,0x74,0x43,0x9c,0x54,0x66,0x9d,0xdf,0xc2,0xba, + 0x5d,0x8c,0x19,0x2c,0x88,0x42,0xc6,0xbf,0xff,0x72,0x99,0x22,0x87,0x8b,0xf8,0xeb, + 0xf3,0x7e,0x00,0xdb,0x67,0x0a,0xf3,0x81,0x80,0x15,0xda,0x89,0x80,0x59,0x1f,0xec, + 0x8a,0x3f,0xcf,0x95,0x1a,0x9b,0x03,0x93,0x5c,0x9a,0xeb,0xe1,0x48,0x9f,0x4a,0x80, + 0x14,0x69,0x9b,0x2e,0xc3,0x0a,0x50,0x48,0x59,0xe1,0xd7,0x0e,0x15,0x57,0x11,0x0d, + 0x03,0xe5,0x87,0x5c,0x3d,0x03,0x00,0x4a,0x23,0x20,0x19,0x12,0x0c,0xa5,0xa1,0x21, + 0x29,0x62,0x95,0x8c,0x46,0x7d,0xa4,0x0c,0x1e,0x44,0x59,0xfa,0x77,0xd1,0xe7,0xee, + 0x9f,0xa1,0xcf,0xc5,0x2a,0xf6,0x2d,0xdc,0xdd,0xf1,0xc4,0x63,0x03,0x42,0xbc,0xbf, + 0x19,0x21,0x56,0x5b,0x00,0xd5,0xdb,0x22,0x95,0xba,0xc9,0xd4,0x79,0x5f,0x63,0xd8, + 0xe9,0xab,0xb1,0xe5,0xce,0xe3,0x3e,0x69,0x57,0xaa,0xc0,0xe2,0x0a,0xd6,0x41,0x8b, + 0x59,0xba,0x0b,0xf7,0x96,0x26,0x48,0x29,0xad,0x98,0x05,0x86,0xd9,0x44,0x51,0x0c, + 0x64,0x32,0x10,0x71,0x52,0x45,0xe5,0x40,0xee,0x83,0xcd,0x52,0xa9,0x98,0xdc,0xf1, + 0x18,0xf5,0x90,0x82,0x87,0x63,0x11,0x0d,0xe8,0x71,0x08,0xfc,0x0a,0x9b,0x66,0xa0, + 0x78,0x9f,0x08,0xc2,0x79,0x29,0x54,0x98,0xc4,0xe5,0x03,0x35,0xd6,0x34,0x53,0xc4, + 0xe9,0xd8,0x05,0x55,0x93,0x37,0x5c,0xf8,0x00,0x6f,0xa2,0x2f,0x5f,0x3c,0xd5,0x45, + 0x20,0xe2,0x49,0x58,0xdd,0x46,0xfa,0x67,0xb7,0x67,0x04,0xb8,0x5e,0x1f,0xa9,0xfd, + 0x00,0x8e,0x78,0x08,0x82,0xf0,0xf4,0xc4,0xc4,0x08,0x95,0x5f,0xad,0xc0,0x56,0xab, + 0xf0,0x86,0xba,0x8b,0xda,0x6e,0xfe,0x89,0x0b,0xa4,0xbc,0x60,0x81,0xac,0x1d,0x2e, + 0xa2,0x2d,0x20,0x14,0xfd,0x12,0xb6,0xb9,0x8e,0xb1,0xc5,0x4a,0x6a,0xb8,0x69,0xe6, + 0x29,0x57,0xea,0xdb,0xdd,0x38,0x5e,0x87,0xdf,0x18,0x9a,0x82,0x87,0x48,0x4f,0x39, + 0xb0,0x89,0x18,0x01,0x61,0x26,0x8e,0xa7,0xa0,0xa8,0x2e,0x0b,0xbb,0xa5,0x02,0x48, + 0xbd,0x80,0xa5,0x2c,0x32,0x41,0xa5,0x3c,0xa8,0x41,0x32,0x8f,0x59,0xfb,0xbc,0x2a, + 0x0f,0xf2,0x09,0x29,0x2e,0x30,0xf8,0x59,0x9d,0x0b,0xe0,0x68,0x1e,0x9f,0xbd,0x7b, + 0xbb,0x5a,0xf8,0xce,0x98,0x69,0x5b,0xcd,0x60,0x7d,0xa0,0xad,0x7e,0x35,0x43,0xf5, + 0x41,0x53,0x56,0x7c,0xa9,0xae,0xe2,0x39,0x15,0x55,0xe7,0x70,0xef,0x68,0x5f,0xb5, + 0xf4,0x6d,0xb0,0xf0,0x32,0x40,0xcc,0xd9,0xc6,0x0a,0x92,0xa1,0x2c,0xe1,0xd4,0x35, + 0x6f,0x68,0xc6,0x34,0x03,0x13,0xb5,0x41,0xf2,0x14,0xb3,0xb5,0x15,0x64,0x7d,0xc5, + 0x1c,0xe1,0x51,0xde,0xfa,0x5d,0x45,0xee,0xca,0x46,0xde,0x45,0x8e,0xe8,0xc6,0xcc, + 0x95,0xa1,0xab,0x0f,0x81,0xc4,0x4c,0xa2,0x20,0x20,0xbe,0x70,0x23,0x0e,0x8c,0x94, + 0xc0,0x1a,0x4c,0x56,0x1d,0xa5,0x1d,0xbf,0x03,0x7a,0x95,0x2d,0xc6,0xf5,0xb3,0x51, + 0x16,0xd8,0x81,0x72,0x49,0xbd,0x9c,0x1b,0x3e,0x98,0xeb,0xb7,0xe8,0x77,0x51,0x38, + 0xfd,0x82,0xaa,0xa3,0xb0,0xb6,0xea,0xbf,0x49,0xac,0xad,0xee,0x04,0x40,0x57,0x52, + 0x25,0x7c,0xa2,0xd8,0xa9,0xb1,0xbe,0xe8,0x1b,0xc0,0x47,0x1f,0x7c,0xa6,0x09,0x53, + 0x35,0x87,0x2c,0x69,0x49,0xf4,0x2c,0x4f,0x91,0x22,0xf8,0x52,0x11,0x90,0x0b,0xbe, + 0xeb,0xc4,0xc1,0xff,0x6e,0xe9,0xf5,0xff,0x1f,0xe2,0xa8,0x36,0xc3,0xef,0xa2,0x4f, + 0xae,0xd0,0xa9,0x15,0x8c,0x00,0xd0,0xe6,0xc3,0x80,0x3d,0x45,0x3b,0xd7,0x67,0xe1, + 0x12,0xcd,0x86,0xcc,0x63,0xa5,0x54,0x35,0x30,0x26,0xdd,0x83,0xd0,0x8a,0xaf,0x42, + 0x90,0xef,0x13,0xef,0xf7,0x85,0x17,0x8e,0x1e,0x6c,0x63,0x08,0x73,0x2f,0xa2,0x2c, + 0x5e,0x7c,0x4f,0xb8,0x72,0xf6,0x89,0x15,0xed,0xac,0x6a,0x26,0x96,0x98,0x14,0x77, + 0xde,0x3d,0xcc,0xac,0x26,0x65,0xb9,0xc6,0x5d,0x02,0xcb,0xc0,0xb8,0x75,0x61,0x8d, + 0x0b,0x65,0xb0,0xc6,0x1d,0x4e,0xf8,0x38,0x0b,0xe4,0x0d,0x63,0x01,0x98,0x17,0x18, + 0xe4,0xda,0xc3,0x58,0xc6,0x27,0x56,0x6b,0xb8,0x81,0xda,0xe9,0x52,0xbd,0x36,0x9a, + 0xef,0x7f,0xfc,0xc3,0x7a,0x7e,0xe9,0x25,0x53,0x28,0x0e,0x85,0xe4,0xe2,0x6b,0x3b, + 0xed,0x76,0x47,0x6a,0xe3,0x0f,0xda,0x42,0x2f,0xd7,0x3d,0x68,0xb7,0x9f,0x41,0x94, + 0x6f,0x25,0x90,0x8c,0xe6,0xcd,0xc6,0x2d,0x0f,0xef,0xb4,0x76,0x65,0xb3,0x2f,0x45, + 0xa3,0x85,0x36,0xbf,0x0c,0x0c,0x17,0x71,0xe2,0xb9,0x63,0xd2,0xe5,0x93,0x0e,0xaa, + 0xa2,0x23,0x55,0x3d,0x48,0xb1,0x50,0x44,0x34,0xf9,0xf8,0xe0,0xf5,0xae,0x78,0x92, + 0x29,0x87,0x95,0x94,0x97,0x95,0x94,0xa3,0x4a,0xca,0xab,0x4a,0x4a,0xa7,0x5d,0x4d, + 0xea,0x54,0x93,0xba,0x79,0x92,0x54,0xce,0x3e,0xb3,0x38,0x69,0x8c,0xc0,0x73,0x7a, + 0xab,0x47,0x38,0x4a,0xfe,0xc6,0x11,0x96,0xbb,0xf5,0xe5,0x2a,0xe1,0xbf,0x51,0x23, + 0xbc,0x11,0xb1,0x90,0xec,0x5d,0x75,0x9d,0xd7,0x21,0x90,0xb6,0x67,0x76,0xd5,0x40, + 0x4e,0xfd,0x24,0xf3,0xe7,0x5e,0x09,0x97,0xd6,0x0e,0xc4,0x9d,0xe4,0x88,0x2d,0xf1, + 0xba,0xbd,0xf2,0x9c,0xc5,0x9d,0xb4,0xc6,0xa3,0xb5,0x6a,0x76,0xad,0x5f,0x39,0x6f, + 0xf3,0xe9,0x57,0xe0,0x18,0x02,0x3c,0x1f,0x74,0xd3,0xcd,0x76,0xd9,0xe4,0x9e,0x0a, + 0xd4,0xf5,0x4d,0x2c,0xf4,0xb5,0x4b,0xae,0xd0,0x8f,0x83,0x4e,0x57,0x9f,0x6a,0xee, + 0xc9,0x17,0x80,0x28,0x7b,0xb6,0x2f,0xcf,0xcf,0xbc,0x6e,0x0a,0x52,0x60,0x78,0xf0, + 0x8c,0x92,0xc9,0xfb,0xf0,0xf8,0xec,0xf4,0x3b,0xa3,0x49,0x2a,0xfb,0x50,0xda,0x27, + 0x90,0x86,0x68,0xee,0x67,0x16,0x4a,0x5c,0xaf,0xfd,0xe3,0x33,0x71,0x94,0x07,0xbd, + 0xf7,0x6f,0xfd,0xec,0x01,0x46,0x93,0x31,0xcb,0xcf,0xf6,0x20,0xc2,0x86,0x4c,0xdf, + 0x6c,0xb2,0x69,0x60,0x16,0x07,0x48,0x07,0x0c,0xc3,0xe8,0x3e,0x1f,0xe2,0xc8,0xc5, + 0x2d,0x6d,0x01,0x15,0x2c,0x8e,0xd5,0x76,0xf3,0x4c,0xcf,0x3b,0x87,0x5a,0xd7,0x61, + 0x86,0x61,0xcf,0xc2,0xc3,0x06,0x63,0xea,0x92,0x1d,0x11,0xf6,0xf6,0xe2,0xd7,0x4e, + 0xf7,0xf0,0x1e,0x58,0x94,0x91,0xe7,0xa3,0xf2,0x80,0x34,0x7b,0x7f,0xa9,0xa3,0xb4, + 0x4d,0x3a,0xc9,0x3d,0x36,0xf2,0xc5,0x3d,0xee,0xb6,0xf7,0x75,0x70,0x7f,0xff,0xe6, + 0xbd,0x21,0xfb,0x2d,0x3a,0xfc,0xe6,0x1e,0xd8,0x1d,0xe4,0x79,0x27,0x09,0x0a,0x5f, + 0x5e,0x38,0x6e,0xcd,0xa3,0xf1,0x02,0x64,0xe1,0x77,0x1f,0x4e,0xff,0x86,0x8e,0x4f, + 0xbc,0xf9,0x9f,0xed,0xfc,0x51,0xe7,0x55,0x57,0xeb,0xfc,0x77,0xcc,0x81,0x33,0xdd, + 0x4a,0x49,0x5b,0x20,0xc6,0xf0,0xc9,0x1b,0x2f,0x46,0x9e,0x64,0xd1,0x91,0x09,0xf8, + 0xe1,0xfc,0x02,0x56,0x6f,0x20,0x72,0xff,0xa5,0x61,0x50,0x0d,0xdc,0xdc,0xba,0x11, + 0x68,0x44,0xa0,0xfd,0xea,0x50,0x70,0x38,0xf7,0x71,0xda,0x62,0x7b,0xaa,0xf2,0x30, + 0x0b,0x78,0x54,0x33,0xa4,0xef,0x16,0xd9,0x43,0x6b,0xf4,0x80,0x46,0xa6,0xc8,0x86, + 0x30,0x5b,0x25,0x90,0xaa,0x4f,0xdc,0x09,0x72,0xb4,0x29,0xc5,0x9d,0xf6,0xc3,0x45, + 0xb4,0x48,0xe5,0xe7,0x3f,0x3f,0x58,0xec,0x2e,0xca,0xe8,0x64,0x73,0xbc,0xc1,0x6c, + 0x91,0x20,0xa3,0xc6,0xc9,0xdb,0x50,0xba,0x72,0xdf,0xff,0xf4,0x2b,0xcc,0x49,0xe0, + 0xdd,0xea,0x46,0x08,0x85,0xfd,0x90,0x5a,0xa7,0x0c,0x6a,0x53,0x64,0xe6,0x8c,0x64, + 0xa4,0x8e,0xd1,0x44,0x5b,0x4c,0x2f,0xb9,0x25,0xbf,0x29,0xab,0xbc,0x13,0xca,0xac, + 0x80,0x31,0xdd,0x55,0xdf,0xf6,0xcc,0xe3,0xbd,0x55,0xdf,0x80,0x74,0xef,0xaf,0xfa, + 0x76,0x60,0x1e,0x1f,0x18,0xcd,0xa1,0x1b,0xd0,0x6e,0xb5,0xb2,0x69,0xa0,0x0e,0x87, + 0xab,0xbe,0xbd,0x34,0xab,0x9b,0xb7,0xfc,0x06,0x2b,0xf4,0x68,0xd5,0xb7,0x57,0x66, + 0x95,0x65,0x51,0x50,0x81,0x0d,0xa1,0xca,0xbd,0xc8,0xaf,0x20,0x15,0x2d,0xdc,0x00, + 0x4f,0xbb,0xf0,0xd7,0xc8,0x48,0xff,0x99,0x56,0xd9,0x85,0xa2,0xb4,0xc0,0x5e,0x49, + 0x55,0xea,0x13,0xa7,0xab,0xa4,0x7b,0x85,0x00,0xc8,0xd7,0xcd,0x01,0x75,0x5a,0x13, + 0xdf,0x0b,0xc6,0xb9,0x65,0x8f,0x48,0x5e,0x37,0xeb,0xb2,0x68,0x65,0xe2,0x61,0x84, + 0xa7,0x0b,0x94,0xb0,0x93,0x68,0x6e,0xa4,0x15,0xce,0x71,0x05,0x5c,0x60,0x22,0x3a, + 0x87,0x46,0xfa,0x30,0x1f,0x46,0x41,0xba,0x12,0x19,0x00,0x53,0xf6,0xba,0xd5,0x5c, + 0xcf,0xb3,0x51,0x80,0xf7,0xba,0x18,0x83,0x63,0x97,0xc0,0x5e,0x69,0x14,0x40,0x4b, + 0xd3,0xb8,0xf3,0xc3,0x31,0x14,0x6e,0x6e,0xcd,0xfd,0x51,0x12,0xf5,0xd3,0x4d,0x58, + 0x71,0x02,0x50,0x22,0x99,0xaf,0x4e,0xbb,0xdd,0x56,0xec,0x17,0xff,0x97,0x9b,0xe3, + 0xac,0xe7,0x48,0x2f,0xd0,0x42,0xf4,0xcf,0x77,0x81,0x0c,0x4c,0xbf,0xa8,0x17,0xd5, + 0xce,0xe4,0x6c,0x15,0x41,0x8d,0xb5,0x2e,0xab,0xb3,0x17,0xb7,0x83,0x3d,0x7d,0x33, + 0xf8,0x44,0x31,0x78,0x04,0xb1,0xfc,0x3e,0x4a,0xee,0x50,0xe5,0x40,0x72,0x1e,0xf0, + 0x0f,0x93,0x89,0x3f,0x72,0x8c,0x8f,0x40,0x24,0x07,0x6c,0x0f,0x10,0xb6,0xe8,0x80, + 0xad,0x99,0x82,0x20,0x17,0xc8,0xa3,0xbb,0x94,0x4d,0xc1,0xc5,0x49,0x5d,0x8a,0xc6, + 0xce,0x7f,0x65,0xb7,0xa3,0x0e,0x6d,0x4a,0x35,0x15,0xf3,0xa4,0xb4,0xa6,0xa8,0x34, + 0xd5,0x06,0x7b,0xb8,0xbf,0x5a,0x2d,0x44,0x66,0x12,0xee,0x18,0x23,0x9f,0x19,0xcd, + 0xb9,0x76,0xda,0xb9,0x9e,0xed,0xa5,0x02,0x0e,0xb9,0xad,0xc0,0x12,0x28,0x33,0x74, + 0xfb,0xb5,0x2c,0xf0,0x71,0x1b,0x40,0x08,0xbb,0xcd,0x06,0xc7,0x3e,0xdf,0x07,0x51, + 0x34,0x56,0xdd,0x9a,0x25,0xe9,0x66,0xdd,0x9a,0x60,0x31,0x67,0x7d,0xe7,0x3a,0x87, + 0x47,0xeb,0x3a,0x67,0x1b,0x5e,0x90,0x7a,0xc6,0xde,0x56,0x48,0x92,0x3d,0xe4,0xae, + 0x35,0x70,0x5a,0x21,0x8a,0x68,0xba,0x08,0xea,0x8b,0xae,0xaf,0xa2,0x31,0x21,0xc1, + 0x61,0x3d,0x3a,0xbc,0xc5,0xe9,0x2a,0xa5,0xc4,0x8f,0x51,0x0c,0xc8,0x06,0x8c,0x2b, + 0x9f,0x38,0x51,0x5d,0x12,0x19,0x35,0xc5,0xc2,0x84,0x71,0x35,0x75,0x60,0x4f,0x67, + 0x9b,0x18,0xa0,0x46,0xbc,0x8f,0x03,0x8f,0x04,0x79,0xfc,0xf4,0xc1,0x08,0xd1,0x91, + 0x65,0x18,0x2d,0xd0,0x90,0x30,0x8b,0x22,0x83,0xb4,0x8b,0xa4,0xa1,0x88,0xdd,0x04, + 0x1a,0x88,0x26,0xb9,0xa1,0x17,0x1a,0xb1,0xc2,0x3b,0x99,0x13,0x3b,0x1b,0xa8,0x1b, + 0xbb,0x47,0x2b,0x31,0xeb,0xbd,0x7b,0x2f,0xfa,0x3d,0xa3,0x81,0x6e,0x3c,0x7d,0x30, + 0x4b,0xa5,0x29,0xab,0xe0,0xaf,0x98,0x31,0x31,0x47,0x87,0xfb,0x8e,0x21,0x8c,0x49, + 0x0d,0x78,0xde,0x00,0xbd,0xb0,0x6f,0x02,0xb9,0xbe,0xbc,0x73,0x02,0xbf,0xfe,0x7c, + 0x1f,0x8f,0xea,0x6d,0xe6,0x56,0xea,0xb9,0xbb,0x47,0x85,0x8e,0x2f,0xc2,0x74,0x14, + 0xc5,0x78,0xa2,0xff,0x27,0xa1,0xeb,0xc8,0x1a,0xaa,0x43,0xf8,0x12,0xa3,0xac,0xd3, + 0x38,0x0e,0xd0,0x50,0x01,0x76,0x54,0x36,0x48,0x48,0xd9,0x76,0x20,0x8c,0xa4,0x21, + 0x00,0xb5,0xe2,0x18,0x1a,0x0c,0xd6,0x49,0xbe,0xcf,0x92,0xb1,0xee,0xc1,0xa1,0x46, + 0xb7,0x60,0x85,0x68,0xc2,0x5b,0x1d,0x3b,0x40,0xda,0xe6,0x28,0x76,0x38,0x5b,0x85, + 0x1d,0xa0,0xe3,0xe0,0x8f,0x48,0x8e,0x56,0xf0,0x3c,0x3e,0x86,0x9d,0x41,0xa6,0x87, + 0x1f,0x56,0xe6,0x83,0x95,0x88,0x9a,0x19,0xc8,0x28,0x9e,0x56,0xe5,0x4c,0xb3,0xc4, + 0xc7,0x8e,0x5c,0xd0,0x6f,0x1d,0xf7,0x54,0x01,0xf2,0x77,0x09,0xc6,0xc3,0xe6,0x99, + 0x96,0x50,0x66,0x0b,0xb5,0x00,0xf9,0x97,0x07,0x03,0x08,0x4c,0xf2,0x50,0x70,0xcf, + 0x99,0xb9,0xa8,0xb2,0xe6,0x36,0x80,0x26,0x0c,0x8c,0x89,0x77,0x47,0xe6,0xa8,0xb8, + 0xa7,0xe0,0x74,0x05,0xd4,0xc9,0xb1,0x94,0x91,0xc7,0xd0,0x44,0x0c,0x74,0xc9,0x79, + 0x8e,0xd0,0xf1,0x89,0x10,0x9d,0x51,0x6d,0x66,0x7e,0xf3,0x96,0xac,0x59,0xb2,0x87, + 0x3f,0x6f,0x72,0xf3,0xdf,0x6e,0x71,0x23,0x6d,0x6c,0xfa,0x18,0x6e,0xa8,0x64,0x63, + 0xe3,0x18,0xdf,0xd2,0x89,0xc0,0xe0,0xef,0x31,0x95,0xf9,0x6f,0xb7,0x94,0xf9,0x53, + 0x56,0x2d,0xff,0x95,0x46,0x2d,0x75,0x33,0xb8,0xda,0x60,0x05,0x37,0x31,0x6a,0x0d, + 0xcd,0xb8,0x0b,0x76,0x2b,0x80,0x56,0xe2,0x30,0xce,0xfa,0x93,0x36,0x27,0x1b,0x9a, + 0x9c,0x6c,0xa6,0xa9,0x3c,0x67,0xec,0x22,0xf9,0xbc,0x7e,0xfb,0xbf,0xd4,0x0c,0x4b, + 0x80,0xd5,0x44,0x23,0x76,0x34,0x21,0x58,0xc4,0x41,0xe4,0x8e,0xc9,0xdc,0x14,0xa9, + 0x2e,0x99,0x63,0xb7,0xd0,0xc2,0x6b,0x46,0x72,0x0c,0x8a,0x35,0x2e,0xfa,0x57,0xdd, + 0x20,0x5e,0xe3,0xa1,0xd7,0xbf,0xd8,0xe6,0x81,0x4c,0x17,0x34,0x43,0xca,0x3a,0xde, + 0x38,0xe7,0x86,0xc9,0xca,0x9c,0x2d,0xcd,0x04,0x4b,0x7c,0xee,0x25,0x3e,0xb0,0x2e, + 0x23,0x34,0x7e,0x0e,0xb2,0xd9,0x2e,0x1d,0x2f,0x1b,0xa2,0x4e,0x61,0x0f,0x4e,0x46, + 0x52,0x7f,0x89,0xe9,0x25,0x38,0x72,0x6d,0x9b,0x69,0x77,0xf2,0x2e,0x0b,0x88,0x4a, + 0x0a,0x29,0xba,0xfd,0xde,0x25,0xc3,0xd2,0x14,0x76,0xa5,0xd1,0x8c,0x3d,0x33,0x80, + 0x61,0x17,0xc6,0x73,0x92,0x99,0x82,0xd9,0x8d,0xee,0xfe,0x7a,0xbf,0x45,0xcb,0x5f, + 0xda,0xf1,0xd3,0xf1,0xd8,0x48,0xdc,0x3b,0x83,0x03,0x95,0x89,0x7e,0x9f,0x06,0x64, + 0x50,0x85,0x16,0xb2,0x68,0x5c,0xbb,0x80,0x4e,0x23,0xb6,0x53,0x1e,0x09,0x75,0x2c, + 0xf4,0x37,0x81,0x1c,0xaa,0xfa,0xd2,0x6e,0x0b,0x11,0x74,0x5c,0x02,0x38,0xc8,0x51, + 0x68,0xf5,0x25,0xf7,0x29,0x34,0x95,0x1f,0xe7,0x47,0xa9,0xae,0x9f,0xfc,0x0d,0x9d, + 0xbd,0xff,0xb3,0xb8,0x21,0xd8,0xe0,0xa4,0x82,0xd4,0xf2,0x03,0x30,0xc5,0x68,0xb5, + 0x83,0x72,0x1c,0x31,0x2e,0xa9,0xd1,0x3c,0xbf,0xf8,0x74,0xfa,0xde,0x18,0x46,0xc8, + 0x63,0xd3,0x52,0xb4,0xfe,0xfa,0x08,0x54,0x3f,0xfe,0x9a,0x78,0xb7,0xf2,0x30,0x46, + 0x68,0xbc,0x33,0x7d,0x76,0x56,0x70,0x47,0xd4,0x9f,0xec,0xfe,0x8b,0x39,0x23,0xb4, + 0x64,0x39,0x05,0xac,0xbc,0xfc,0x75,0x55,0x0e,0xc1,0x22,0x23,0x29,0x15,0x8c,0xb6, + 0x54,0x5e,0x6f,0xc0,0xf3,0x94,0xd0,0x28,0x17,0x77,0x70,0x4d,0x6c,0x64,0x82,0x79, + 0xc1,0x34,0x49,0x4a,0x80,0x5f,0x20,0xd8,0xf2,0x4e,0x5b,0x94,0x1c,0xa5,0xb3,0xd2, + 0xe1,0xb3,0xc7,0x94,0x5f,0x38,0x57,0x1f,0x24,0x2a,0x68,0x3d,0x9d,0xa1,0xa0,0xf6, + 0x05,0x7d,0x55,0xe8,0x54,0xe9,0x75,0x57,0x2a,0x55,0xf6,0x0e,0x57,0xf2,0x42,0xd1, + 0x04,0x0f,0x4b,0x90,0x83,0x17,0xab,0x84,0xcc,0x4e,0x8a,0x0b,0xa2,0xd9,0xe9,0xb6, + 0xa0,0x0e,0xdb,0x10,0x51,0x22,0x8c,0xee,0xbe,0xe5,0x7c,0x89,0x50,0xbc,0xce,0x00, + 0xd2,0x8d,0xe3,0xe7,0x2d,0x20,0xb5,0x5a,0x2e,0xf1,0x7c,0x8e,0x05,0xe8,0x8b,0x0f, + 0xef,0xcf,0xd7,0xda,0x1e,0x5d,0x9e,0x0b,0x47,0xd8,0x4d,0x79,0x95,0x30,0x8b,0x57, + 0xb0,0x26,0x05,0x63,0xa0,0x38,0x8a,0x02,0xcc,0x0b,0xdc,0xe7,0xb4,0x16,0xb2,0xec, + 0x32,0x0f,0xb4,0x07,0x03,0x34,0xc8,0xdd,0x7a,0x14,0x00,0x39,0x5c,0x6f,0xc8,0xb3, + 0x72,0x4d,0xc3,0xa0,0xff,0x40,0xbf,0xec,0xe6,0xf9,0xc7,0x8b,0xb7,0xbf,0x6e,0xc2, + 0x1d,0x67,0xa2,0xc8,0x26,0xe3,0x79,0x7f,0x71,0xf9,0xf2,0xfd,0x77,0x97,0xf6,0xfb, + 0x3d,0xa7,0xeb,0xb4,0xed,0xf7,0x9d,0x8e,0xd3,0x71,0x56,0x99,0x01,0xd4,0x48,0x88, + 0x1d,0xe6,0x1e,0xb9,0x4f,0x3f,0x5f,0x9e,0xa1,0x1a,0x45,0xf3,0x57,0x5a,0x7f,0x38, + 0x28,0xfa,0xe9,0x70,0x19,0x79,0x2a,0xac,0x90,0xb7,0xb3,0xff,0x8c,0x4e,0x2f,0x27, + 0xf4,0x88,0x0f,0x06,0xf0,0xea,0x61,0xa6,0xb6,0x23,0xe0,0x26,0x80,0x90,0xa0,0xa9, + 0x84,0x9f,0xe0,0xc9,0xf0,0x5f,0xa0,0xdd,0x69,0x38,0x8f,0x37,0xa0,0xd8,0x1a,0x0d, + 0xc2,0xee,0xa0,0x41,0xd1,0x22,0x24,0x11,0xe8,0xd9,0x29,0xc3,0x16,0x1c,0x55,0x60, + 0x85,0x4c,0xf3,0x9c,0x74,0x46,0xd6,0x81,0x9b,0x49,0x67,0xec,0xca,0x29,0x3c,0x96, + 0xa3,0x70,0x15,0x2f,0x8a,0x47,0xa6,0x53,0xe4,0x2f,0x29,0x7f,0xc2,0x30,0x65,0xdb, + 0xd9,0xbc,0xb0,0x32,0x84,0x21,0x62,0x4d,0x76,0xb0,0x77,0xa8,0x1d,0x45,0xd9,0x92, + 0x7d,0x7d,0x72,0xef,0x1e,0x58,0xf2,0xb0,0x12,0x52,0xe9,0x60,0xa8,0x59,0xde,0x3a, + 0xc6,0xf7,0x3e,0x7a,0x1a,0x66,0x6c,0x8f,0xfb,0xf6,0x9c,0x79,0x5a,0x32,0xbb,0x11, + 0x3e,0x9d,0x51,0x22,0xcc,0x79,0xc9,0xcd,0x5b,0x04,0xd4,0xf8,0x3f,0xc3,0x9f,0x9a, + 0x48,0xd9,0xff,0xb9,0x0e,0xd5,0xb2,0x7b,0x7f,0x8b,0x47,0xf5,0xff,0x5b,0x0e,0xd5, + 0xff,0x57,0xb8,0x4c,0x4b,0xd3,0x87,0x4e,0xab,0xb3,0x67,0xdc,0xb1,0x2b,0x1e,0xbb, + 0x31,0xe7,0x8e,0xcd,0x1c,0xdd,0x60,0xad,0xfb,0xb4,0x66,0x0f,0xe7,0x18,0x17,0xc4, + 0xc3,0x51,0xb8,0x03,0x03,0x03,0x94,0xa3,0x73,0xb3,0xb4,0xa2,0x67,0xe7,0x6a,0x5c, + 0xcb,0x62,0x1c,0x7d,0xe1,0x2b,0x9d,0x4a,0x82,0x6c,0xb8,0xc2,0x98,0x7c,0x43,0x9f, + 0xf4,0x4e,0xbb,0x9b,0xdb,0xc4,0x9c,0xcb,0x63,0x6e,0x6f,0x25,0x7b,0xcb,0x58,0x28, + 0x4e,0xdc,0xab,0xc7,0x81,0x73,0xb4,0x22,0x20,0xdd,0xde,0x62,0xbe,0x8a,0x8f,0xa5, + 0x08,0x4b,0x20,0x11,0xe3,0xde,0x0b,0x72,0x22,0x3a,0x0d,0xa1,0x55,0x7f,0x38,0x7a, + 0xb0,0x56,0x1f,0x95,0xde,0xe7,0x5e,0x81,0xcd,0xa1,0x8b,0xf1,0xdf,0xf5,0xdc,0xcf, + 0x1f,0x09,0x6a,0x34,0xfa,0xbd,0x8b,0x5c,0x5d,0x88,0x47,0xc5,0x2b,0xed,0x9a,0x56, + 0x50,0x8d,0x55,0x4e,0x1e,0xe3,0xe8,0x13,0x01,0xbd,0x49,0x7e,0x1e,0x64,0x29,0x19, + 0x92,0x16,0x6a,0xb5,0xcb,0x40,0x6d,0x85,0x22,0x96,0x0d,0xe0,0x4a,0xab,0xe8,0xdf, + 0x3d,0x8e,0xde,0x51,0x32,0xf9,0x0d,0xa0,0xe7,0x27,0x3c,0xaf,0x74,0x25,0xa9,0x6c, + 0x60,0x6c,0xba,0xbe,0xd9,0x0e,0x26,0x8c,0x38,0x98,0x1a,0x70,0x68,0x17,0x28,0xdc, + 0x82,0xdd,0x47,0xeb,0x6d,0xe4,0x66,0x22,0x5e,0x75,0x39,0xc6,0x67,0x49,0x33,0x46, + 0x51,0xea,0x4a,0xf1,0xfa,0xdb,0xe6,0xf1,0x4a,0xf3,0x51,0xba,0xe2,0x43,0xd8,0xff, + 0xd3,0xe3,0x66,0x53,0xfa,0x7d,0xe2,0x21,0x91,0x71,0x63,0xa3,0xf9,0xd3,0xb7,0x16, + 0x55,0xfb,0x9a,0x2f,0xa9,0xe0,0x21,0xc4,0x6e,0x72,0x83,0x77,0x13,0xc4,0x79,0x08, + 0x32,0xd2,0x7b,0xef,0x72,0x26,0x69,0x77,0xef,0xa7,0x1e,0xa9,0x85,0x95,0xd5,0x5d, + 0x6d,0x3d,0x78,0x02,0xe4,0xad,0xac,0x68,0xdd,0x21,0x16,0x32,0xc4,0x3c,0x19,0xfa, + 0x19,0x96,0x1e,0x5d,0xa6,0xc4,0xc9,0x63,0x5e,0xc1,0xca,0x6f,0xec,0x5a,0x8c,0x4b, + 0x8b,0x96,0xab,0xf1,0xe0,0x65,0xce,0x73,0xa8,0x81,0xfe,0x0a,0xcf,0x21,0x86,0x6c, + 0x5a,0xbf,0xb1,0xa7,0xec,0xb6,0x01,0xd4,0x4e,0x4c,0x9b,0x57,0x89,0x3d,0x25,0xe2, + 0x20,0x9b,0x25,0x0e,0x31,0x8d,0xab,0x11,0xc6,0x8a,0xdb,0xb2,0xde,0x2f,0x55,0x79, + 0x8b,0x9c,0xc1,0x37,0xdb,0xb3,0x1b,0x6a,0x01,0xa1,0x73,0xd2,0x2f,0xe4,0x7e,0x83, + 0x4b,0x68,0x2b,0x70,0x93,0xa4,0xcf,0x6e,0xe5,0xd5,0x45,0xfa,0x57,0x78,0x03,0xf8, + 0xf9,0xd1,0x0b,0x62,0x6c,0x64,0x06,0xbf,0x7f,0x7b,0xe5,0x67,0x28,0xf1,0x60,0xed, + 0x24,0xfa,0xac,0xf5,0x18,0x92,0x31,0x8f,0x35,0xd0,0xe1,0xdb,0xf1,0xaa,0xac,0x1c, + 0x01,0x19,0xbe,0x97,0x3f,0xa4,0x8b,0xa9,0x51,0x9e,0x83,0xc5,0x74,0x8d,0xc9,0xa5, + 0x8a,0x4c,0x5b,0x9e,0x72,0x11,0x32,0x96,0x83,0xb5,0xa9,0xb9,0xaf,0x72,0x83,0xaa, + 0x1d,0x75,0x0e,0x51,0xe0,0x6f,0x56,0xb9,0x6a,0x96,0xd8,0xc3,0x46,0x1a,0x7b,0x41, + 0x40,0x62,0x07,0xac,0x1b,0xf6,0x63,0x22,0x07,0x27,0x60,0x4d,0x70,0xff,0x06,0x96, + 0x34,0x2a,0x89,0x6d,0xd8,0x09,0x8c,0x4e,0xc2,0x3e,0x0b,0xd5,0x9d,0x40,0x84,0x41, + 0xfd,0x33,0xfc,0x63,0x43,0x9f,0xc6,0x0b,0x0a,0x79,0x86,0xf3,0x98,0x2c,0xc2,0xb5, + 0x3e,0x81,0x72,0x21,0x72,0x94,0x47,0x09,0xd0,0xe3,0xd7,0x37,0xc3,0xf1,0xf1,0xa5, + 0x3b,0x7c,0xbd,0x8b,0x0f,0xca,0x1f,0x46,0x12,0xd6,0x3c,0xcf,0xd6,0x02,0x51,0x9d, + 0xb3,0x71,0xc2,0x38,0x4f,0x80,0x69,0x4d,0x31,0xca,0x40,0x41,0x82,0xe3,0x6c,0x6f, + 0xd2,0x91,0xc8,0x33,0xf6,0xd3,0xb9,0x9f,0xa6,0x85,0xaa,0x39,0x3e,0xdf,0x1c,0x46, + 0xe6,0xc7,0xe8,0x95,0x07,0x73,0x4d,0xca,0x6b,0xf4,0xcb,0x03,0xb6,0x85,0xed,0xe8, + 0x3d,0x55,0x6d,0x2d,0x11,0xd2,0x5c,0xc4,0x76,0x45,0x88,0x3e,0x5d,0x0c,0xe5,0x8b, + 0xc6,0x18,0x17,0xe4,0x0b,0xce,0x87,0x4a,0x68,0x51,0x90,0xb2,0xe1,0xf1,0xb3,0x44, + 0xa5,0xb8,0xe9,0x1a,0xe9,0x5c,0x5b,0x52,0x38,0x4b,0x49,0x76,0x1a,0x04,0xbc,0x75, + 0xe3,0xcb,0xfa,0x5d,0x7b,0x9e,0xf7,0xa8,0xb4,0x47,0x83,0x30,0x50,0x70,0xed,0x13, + 0x9c,0xd9,0xda,0x35,0x9a,0x5f,0x46,0x93,0x2f,0x30,0xba,0x95,0x86,0x12,0xcb,0x56, + 0x89,0x7c,0xbf,0x0e,0xfb,0x5a,0x0f,0x1f,0x54,0x0c,0x22,0x06,0x40,0x49,0xf2,0xd9, + 0x00,0x08,0x7f,0x85,0x14,0x91,0xc4,0x4a,0x42,0x50,0x96,0x2c,0x3c,0x82,0x5d,0x5a, + 0x14,0x80,0xfe,0x6b,0xda,0xa5,0xd0,0x7a,0xd4,0x2e,0xb4,0x79,0x86,0x2f,0xaa,0xc9, + 0xf2,0xe6,0xa6,0x6e,0xf7,0x11,0x24,0x6d,0xa5,0x6b,0xa4,0xda,0xd7,0x48,0x3a,0x2d, + 0xa1,0x13,0x99,0xc5,0xd6,0x89,0x2c,0x35,0x64,0x0f,0xef,0xa0,0x11,0xc4,0x8b,0x1e, + 0xeb,0x68,0xa3,0xb8,0xfa,0x85,0xb3,0x79,0xf7,0x14,0xa3,0x5f,0xce,0x73,0x45,0xf2, + 0xd8,0x47,0xc9,0xa3,0x7c,0x19,0x95,0x08,0x06,0x5a,0x54,0x8b,0x6a,0x81,0x44,0xaa, + 0xd7,0xcf,0x50,0xf0,0x3b,0xb4,0x42,0xf5,0xaa,0x11,0x03,0x29,0x7a,0x68,0x14,0xd4, + 0xb0,0x17,0x07,0x95,0xfb,0x2b,0x5e,0xf5,0x0b,0x41,0x8d,0xbb,0xe5,0x28,0xb6,0x93, + 0xa9,0x85,0x9d,0x0b,0x7c,0xa0,0x4c,0x31,0xb9,0xfd,0x4b,0x5d,0x5d,0x33,0x22,0xdd, + 0xdd,0x19,0x32,0xdd,0x01,0xa6,0x58,0x32,0x7a,0x0b,0x90,0x71,0x3c,0x19,0xa4,0xb3, + 0x46,0x8a,0x8c,0x87,0xd6,0x6f,0xce,0xeb,0x61,0x22,0xb7,0x8e,0x5a,0xcf,0xd3,0x1a, + 0xae,0xe7,0xed,0xc4,0x70,0xd3,0x1b,0x6f,0x6c,0xc3,0xc2,0x93,0x91,0x65,0xd0,0xc5, + 0xf0,0x17,0x11,0x47,0xee,0x2d,0x42,0x22,0xf4,0x48,0x91,0x05,0x12,0x24,0x2a,0xb7, + 0x32,0x90,0x66,0x85,0xbe,0x05,0x35,0x59,0xe4,0x3f,0x2c,0x66,0x1a,0xc6,0x40,0x03, + 0xa1,0x30,0x8b,0x17,0xee,0xc4,0x4d,0x7c,0xd4,0x93,0x9c,0xcd,0x92,0x88,0x82,0x72, + 0x72,0x6f,0xd9,0xa0,0xd9,0xc9,0xb3,0xff,0x10,0x21,0x15,0x04,0x22,0x55,0xed,0xf5, + 0x4b,0x19,0x96,0x90,0x26,0x7d,0x91,0xc0,0xea,0x9e,0x65,0x59,0xdc,0xdb,0xdd,0xed, + 0xbc,0xea,0x3a,0x9d,0xc3,0x23,0x67,0xdf,0xe9,0x10,0x3d,0xe3,0xda,0x76,0xa3,0xa0, + 0x2e,0x0e,0x65,0x55,0x1b,0x8e,0x37,0x9b,0x9a,0xa5,0xc1,0xc8,0x23,0x2d,0x18,0xa5, + 0x72,0xb1,0xbc,0x10,0xdc,0xce,0x71,0x21,0xe0,0xa1,0x63,0xfc,0xa7,0x1e,0x28,0x92, + 0x5d,0xfa,0xfc,0x14,0x23,0xf5,0xa0,0x19,0x84,0x2f,0x5d,0xaa,0x72,0x65,0x94,0x27, + 0xe2,0xb4,0x2a,0xb5,0x95,0x98,0x49,0x81,0x52,0xb6,0x10,0x84,0x7d,0x0c,0x59,0x90, + 0xdc,0xfa,0x22,0xa0,0x1f,0xc8,0xb2,0xc0,0xa4,0x63,0x14,0xd5,0xd1,0x4d,0x6e,0x18, + 0xb1,0xb1,0xcb,0x72,0x7b,0xa5,0xcb,0xf2,0x38,0x1a,0x2d,0x28,0x00,0xe0,0xd4,0xcb, + 0xde,0x04,0x1e,0x3e,0x7e,0xfb,0xf0,0x76,0xdc,0xdc,0x16,0x8b,0x6b,0xdb,0x72,0x08, + 0x80,0xef,0x80,0x12,0x38,0xe8,0x99,0x08,0x24,0x7a,0x1b,0xd9,0xc1,0xed,0x0d,0x7d, + 0x9c,0x61,0x4e,0x87,0xe4,0xff,0xad,0x7c,0x9b,0x57,0x11,0x80,0xc2,0xda,0x66,0x31, + 0x3c,0x5f,0xdd,0x15,0xee,0xd7,0xcf,0xdd,0xc6,0x79,0xb5,0xef,0xed,0xe7,0xd7,0x3d, + 0xed,0xed,0xb3,0xf5,0x80,0x20,0xe2,0xe5,0xf5,0x4e,0x3e,0xdc,0x06,0xdd,0x47,0x56, + 0x68,0x4d,0x44,0x01,0x60,0x19,0xb4,0x10,0xfd,0x97,0xd6,0x79,0xac,0xe7,0x9d,0xa7, + 0x53,0xd5,0x81,0x9a,0xf8,0x44,0x05,0x1a,0x64,0x8a,0xa1,0xc7,0x55,0x9e,0x5c,0xd4, + 0x06,0xbc,0xc9,0x4a,0xdc,0xfc,0x50,0x0d,0x04,0xd0,0xc3,0x15,0x0e,0xf3,0x59,0xa8, + 0x01,0x79,0xc6,0x1b,0x33,0x9f,0xe3,0xca,0x84,0x10,0x39,0x2c,0xdd,0x13,0x87,0x5d, + 0x73,0x55,0xf7,0xea,0xbb,0xa0,0x85,0x39,0xef,0x1e,0xd6,0x54,0xa1,0x77,0x63,0x14, + 0x2d,0xd8,0xe8,0xb5,0x3a,0xd5,0x80,0xc2,0x7e,0x9c,0x1d,0x37,0x4c,0x8c,0x8c,0x29, + 0x0c,0x8f,0xfa,0x0d,0x80,0x9a,0x71,0xf1,0xe6,0xc3,0xe5,0xdb,0x0f,0x6f,0xde,0x0d, + 0xcc,0x6f,0xc4,0x7f,0xe2,0x43,0x9a,0x0d,0x96,0x68,0xcc,0xd4,0x33,0x4d,0x9b,0x9c, + 0x64,0xc7,0x3d,0xc2,0x36,0x7b,0xe6,0xa6,0xef,0x41,0x1c,0xcc,0xdf,0xce,0x02,0x5f, + 0xbc,0xa0,0x8e,0xe5,0x3c,0xbd,0x39,0xdc,0x17,0xef,0x52,0x17,0x78,0xc1,0x11,0x40, + 0x54,0x15,0xa1,0xe7,0x8d,0x53,0xa9,0x45,0x14,0x69,0xc0,0x03,0xa7,0xbd,0xb6,0x3d, + 0x9a,0x4c,0x7b,0xe1,0x22,0x08,0x6c,0x34,0xe6,0xe9,0x2d,0x9f,0x6c,0xba,0x6a,0x1e, + 0x1f,0x38,0xee,0x59,0xda,0xbb,0xba,0xb6,0x43,0x92,0x2c,0x21,0x37,0x89,0xa4,0x78, + 0x20,0x92,0xc0,0x0b,0xb2,0x84,0xbd,0x25,0x0a,0xcb,0x94,0x07,0x85,0x5d,0x78,0x78, + 0xb2,0x71,0x3b,0xbd,0x04,0xb0,0x7a,0x78,0xff,0x34,0xbf,0x71,0x89,0xa7,0x7e,0x63, + 0xb2,0x08,0x59,0x65,0xfd,0x75,0x33,0xb5,0x96,0x62,0x55,0xa9,0x85,0x09,0xcc,0x60, + 0xf2,0xc0,0x6a,0xad,0x28,0x81,0x0c,0x4f,0x5a,0x7e,0xbd,0xc0,0x69,0x92,0xb8,0x0f, + 0xb0,0xf9,0x47,0x59,0x84,0x2c,0x82,0x93,0x06,0x48,0x5c,0x51,0x9d,0xd6,0xac,0xaf, + 0x0b,0xd9,0xb6,0xd4,0xd2,0xeb,0xa3,0x7d,0xb7,0x39,0xb7,0x96,0x08,0xfb,0x6c,0xf0, + 0x75,0xd3,0x7c,0xc1,0x5b,0xb1,0xd5,0xcf,0x1c,0xa4,0x30,0x67,0x7c,0x17,0xcd,0x60, + 0x0e,0xef,0x39,0x59,0x00,0xa4,0x6c,0x92,0x88,0x08,0xf9,0x48,0xb0,0xc2,0xa1,0xa1, + 0xba,0x25,0x73,0x3e,0x63,0xc0,0x7e,0xf8,0x77,0x00,0x50,0x93,0xa9,0xb2,0xb9,0xa6, + 0xb5,0xcc,0xaa,0xc4,0x45,0x54,0xf4,0x64,0x77,0x0f,0xdb,0x6d,0xbd,0x73,0xc0,0x21, + 0x69,0xa3,0x45,0x63,0xb2,0x70,0x0a,0x09,0x78,0xe9,0x0d,0xca,0x20,0xcd,0xdd,0xab, + 0xad,0xd7,0xc7,0xe6,0xf5,0xee,0xd4,0x56,0x0d,0x8c,0x64,0xf6,0xa5,0xb9,0x65,0xf6, + 0x4c,0x3a,0xa4,0x33,0x6d,0xf3,0x35,0x3e,0x07,0x19,0x3e,0x1e,0xe3,0x23,0xfa,0xcb, + 0xdb,0xdb,0xe6,0x36,0x3c,0xfe,0xbe,0x88,0xe0,0xe5,0xe9,0x6a,0x74,0xfd,0xa4,0xb7, + 0x0d,0x7d,0x4a,0xb2,0x7f,0x78,0x20,0x3a,0x2e,0x09,0x2f,0x27,0x77,0x03,0xe8,0xf1, + 0xe4,0xee,0xf1,0x11,0x26,0x73,0x3e,0xd8,0xfd,0x67,0xf3,0xf6,0xe4,0xb7,0xf1,0xce, + 0x6f,0x8e,0xfc,0xa7,0x79,0xd2,0xa3,0x5f,0xeb,0xc4,0xda,0x75,0xbc,0x7b,0x6f,0xd4, + 0x9c,0xdc,0x59,0x02,0xa7,0x07,0xf3,0x93,0xf9,0x55,0xe7,0xba,0xd7,0xa4,0xf2,0x8b, + 0xf0,0x26,0xc4,0xe0,0x86,0xa8,0xbf,0x80,0xa6,0x00,0x84,0x0d,0x7f,0xd2,0xdc,0x6d, + 0xc1,0xe6,0xd8,0x6c,0x3d,0x7e,0x0d,0xc5,0x31,0x64,0x08,0x16,0xb7,0xd2,0x9d,0x81, + 0x89,0xe9,0x66,0xdf,0xd0,0xfe,0xdb,0xdd,0x35,0x3e,0x5e,0x9e,0x7e,0x3e,0xfb,0xf1, + 0xf4,0x03,0x2c,0xa1,0xcf,0x97,0xa7,0x3f,0x0c,0x86,0x5e,0xe6,0x62,0xc6,0x06,0x19, + 0x0e,0x53,0x75,0x98,0x54,0x5b,0x1f,0x7e,0x10,0x15,0x42,0x4d,0xae,0x41,0x65,0xc9, + 0xc6,0x47,0x28,0x49,0x6d,0x8c,0xc4,0x8c,0xac,0x7d,0x43,0x80,0x1e,0x46,0x3e,0x5c, + 0xf8,0xc1,0xf8,0x24,0xdd,0x31,0x8d,0xa6,0xb9,0x23,0xdf,0x77,0x4c,0xcb,0xec,0xa5, + 0xfd,0x86,0x06,0x37,0x10,0x29,0x9b,0x18,0xa5,0xc8,0x8e,0xe2,0x0c,0xe6,0xae,0x81, + 0x3f,0x03,0xfc,0xe7,0xf1,0x71,0xf9,0x44,0x03,0xfd,0x0a,0xdf,0x00,0x4b,0x41,0xce, + 0xb4,0xf2,0x47,0xdc,0xae,0x5b,0x28,0x5b,0x79,0xd0,0x35,0xe8,0x96,0xff,0xf1,0xc2, + 0xa0,0x0f,0x29,0x0a,0x9c,0x40,0x9a,0x7e,0xbc,0xbc,0x3c,0x37,0x4e,0xcf,0xdf,0x1a, + 0x3f,0xbc,0xb9,0x4c,0x0d,0x77,0x94,0x44,0xb0,0xf9,0xa6,0x40,0x19,0xd1,0x47,0x07, + 0xeb,0xa5,0xba,0x32,0xc6,0xb8,0xad,0x2d,0xc1,0x17,0x9d,0x0e,0x61,0x1a,0x11,0x87, + 0xf1,0x36,0x27,0x2f,0x11,0x93,0x39,0xca,0x82,0x01,0x1e,0xee,0x94,0xbe,0x36,0xad, + 0x3e,0x55,0x82,0xa1,0xe2,0xdc,0x60,0x00,0xb9,0xc4,0x63,0xbf,0x51,0x8f,0xcc,0x98, + 0xc3,0xc5,0x3a,0x9a,0x80,0xbd,0x7a,0xfb,0x16,0xc2,0x44,0x6e,0x96,0x5e,0x36,0x9a, + 0x69,0x30,0x71,0xd0,0xf3,0x3f,0xaf,0x05,0xfb,0x04,0xbd,0x4f,0x84,0xd5,0xd1,0x60, + 0x30,0xd8,0x6f,0x77,0xac,0x25,0xae,0x89,0x77,0x18,0xa5,0x1b,0x3a,0x95,0xcd,0xd0, + 0x41,0x03,0x3b,0xfc,0x26,0x49,0x80,0x22,0x98,0x48,0x18,0x61,0xc1,0xc8,0x16,0x12, + 0xe7,0x5f,0x29,0xf6,0x07,0x20,0x89,0x4d,0x69,0x1d,0xe4,0x9a,0xa3,0x1b,0xab,0x52, + 0xc5,0x22,0x44,0xd3,0x4d,0x3a,0x5b,0xc7,0xe5,0xf4,0xc0,0xa7,0x5c,0xf2,0x84,0x0c, + 0x71,0x52,0x54,0x8e,0xb3,0xf6,0x54,0xee,0xf4,0xbf,0xb8,0xea,0xaf,0xb0,0xee,0xad, + 0x2d,0xd9,0xf7,0xaf,0x06,0x83,0x6e,0xbb,0x2b,0x60,0xec,0x0d,0xf2,0xd6,0xfe,0x85, + 0x37,0x51,0x45,0xc9,0xe3,0x63,0xd3,0xa4,0x69,0x34,0x77,0x64,0x11,0xcb,0xea,0x7b, + 0x72,0xe4,0x32,0x0d,0x52,0x12,0xef,0x77,0xd8,0x61,0xfe,0xc5,0xbf,0xf0,0x7e,0xe3, + 0x3d,0xc0,0x1b,0xfc,0x2b,0x60,0xe1,0x69,0xf0,0xfd,0x17,0xf6,0x4f,0xfc,0xe5,0x78, + 0x18,0x47,0x80,0xf2,0x04,0x74,0xbc,0x62,0x41,0x11,0x11,0x85,0x9e,0xcb,0xb9,0x07, + 0x6c,0xee,0xb8,0x67,0x9e,0x7f,0xbc,0xb8,0x34,0x6d,0x8e,0x7d,0x9f,0xf6,0x96,0xa6, + 0x20,0x78,0xad,0x4b,0xa0,0xa8,0x40,0x2a,0xd0,0x7b,0x5f,0x04,0x28,0xdb,0x45,0x28, + 0x9b,0x4f,0x54,0x61,0xef,0xdf,0x2f,0x3e,0x7e,0x70,0x52,0x22,0x49,0xfe,0xe4,0xa1, + 0x49,0x8d,0x14,0x08,0xc8,0xfc,0xe6,0x93,0xf7,0x3b,0xb0,0x55,0x02,0x1c,0x2e,0x81, + 0xe3,0x67,0x3f,0xcc,0x8e,0x88,0x6c,0x37,0x8f,0x78,0xd9,0x0b,0x3c,0x1d,0x25,0x0f, + 0x71,0x16,0x6d,0x6d,0xf1,0x2f,0xb2,0x66,0x9f,0x5c,0xf8,0x30,0xff,0x07,0x19,0xd3, + 0x5b,0xf5,0xc9,0x4d,0x17,0xea,0xa0,0x05,0x3f,0x01,0x20,0x63,0x2b,0xfe,0xa0,0xdd, + 0xf7,0x5f,0x1f,0xf5,0xfd,0x9d,0x1d,0xcb,0xbd,0xf2,0xaf,0x07,0xef,0x61,0xac,0x0e, + 0xa9,0x68,0x9b,0xf4,0x98,0x50,0xf1,0xa6,0xf5,0x4d,0xf7,0xe0,0x30,0x9f,0xe3,0xf2, + 0x46,0x32,0x77,0x63,0xde,0x46,0xdc,0x9c,0xb2,0x0e,0x61,0x20,0x9c,0xbd,0x39,0x7c, + 0xdd,0x39,0x3c,0x31,0xdb,0x00,0x1d,0xd3,0xda,0x19,0x3a,0x59,0x24,0x48,0x73,0xe7, + 0x90,0xe6,0xc1,0xc1,0x08,0xb3,0x4d,0xd3,0xb4,0x4a,0x84,0x01,0xb0,0xec,0x7b,0x0f, + 0x26,0x18,0x36,0x54,0x84,0x0a,0x6c,0x65,0xdb,0x57,0xf2,0x60,0xe5,0x1a,0xb8,0x4e, + 0x18,0xc4,0x1b,0x57,0xc7,0x5f,0x2f,0x80,0x6c,0x5e,0xa0,0xed,0x18,0x59,0x34,0x9d, + 0x06,0xb0,0x63,0x10,0x37,0x65,0x7f,0xd5,0x84,0x24,0xdc,0xc0,0xb7,0x3e,0xd0,0xe1, + 0x15,0x14,0x70,0xb0,0x42,0x58,0xac,0x98,0x6c,0x59,0x02,0x2d,0x88,0x7e,0xa3,0xf5, + 0xf2,0x99,0x9b,0x8c,0x69,0x8f,0xab,0x78,0x47,0xf0,0x64,0xa8,0x4c,0x96,0x7a,0xda, + 0xa0,0xf1,0x66,0xa7,0x7b,0xf4,0x88,0xf0,0xc4,0xf6,0x60,0x54,0xa6,0x53,0x8c,0x14, + 0xb2,0x62,0x64,0xeb,0x06,0x96,0x66,0x4e,0x85,0x89,0xb1,0x9e,0xb8,0x7a,0x01,0x34, + 0xfd,0x84,0x73,0x25,0xf4,0xa0,0x0d,0x60,0x4c,0xdf,0xf1,0xe1,0x27,0x54,0xaa,0x38, + 0xa5,0x13,0x60,0x96,0x0e,0xf7,0x8a,0x35,0x16,0x4e,0x31,0xd7,0x4e,0x88,0xce,0x18, + 0xe8,0xb5,0x36,0x4e,0x0c,0xf3,0x6f,0x3e,0xfd,0x34,0x1b,0xbd,0x4d,0xeb,0x74,0x4c, + 0x9e,0x6e,0x24,0x4c,0xd0,0x2b,0x66,0x11,0x25,0xc5,0x0f,0xfc,0x4b,0x77,0x08,0x73, + 0xbf,0xfd,0x02,0xe3,0x24,0x89,0xfb,0x68,0xae,0xf4,0x28,0x44,0x30,0xe2,0x3e,0x14, + 0xe5,0x9c,0x16,0xff,0x48,0x16,0x05,0xe1,0x84,0xac,0x11,0xa9,0xff,0xad,0x32,0x23, + 0x44,0x93,0x46,0xd8,0x0e,0xe5,0xb9,0x65,0x64,0x55,0x2d,0x5e,0x2e,0x8c,0x7f,0x78, + 0x94,0xb1,0xae,0x07,0x64,0xd1,0x2e,0xba,0x20,0xf2,0x5a,0xe2,0xb7,0xd2,0x09,0xca, + 0xbb,0xb2,0x17,0x98,0x07,0xa3,0x53,0xae,0xcd,0x40,0x17,0x12,0xac,0xcd,0x51,0x3e, + 0x7b,0x79,0xa6,0x3d,0xed,0xe6,0x00,0xab,0x80,0x1f,0xe6,0x97,0xdc,0x23,0x90,0x8a, + 0x7b,0x4b,0x16,0xe2,0xba,0x50,0x32,0xe2,0x80,0x62,0x79,0x3c,0xb3,0x48,0xe8,0x63, + 0xde,0x9d,0x7e,0xc0,0xf9,0x16,0x8d,0xe7,0x81,0xa3,0x4b,0x8d,0x73,0x18,0x69,0x68, + 0x90,0x03,0x25,0x87,0x22,0x86,0x72,0x6e,0x88,0x9c,0xd7,0xa1,0x85,0x06,0x2d,0x55, + 0xc2,0x31,0xe1,0xb4,0x9c,0x7a,0x04,0x39,0xcb,0xf1,0x61,0x7c,0xc9,0x8f,0x97,0xef, + 0x41,0x98,0x29,0xc7,0xfa,0xac,0x44,0x93,0xab,0x54,0x42,0x11,0xd4,0x2c,0x47,0x4a, + 0xe7,0xda,0xde,0x2d,0x62,0xe9,0x3d,0x15,0xa8,0x28,0x1f,0x9a,0x2e,0x1b,0xb8,0x8f, + 0x99,0xbb,0xf0,0xef,0xae,0x30,0x56,0x2e,0xef,0xd0,0xc8,0x7b,0xc1,0x4c,0xa1,0x28, + 0x35,0x48,0xe9,0xa7,0x8f,0x13,0x47,0x12,0x15,0x24,0xe0,0x43,0x3f,0x47,0xd5,0xc1, + 0x57,0x5f,0x41,0x26,0x78,0xe8,0xab,0x85,0x43,0x49,0xd0,0xa9,0x7e,0x43,0x5f,0xe1, + 0x94,0x8a,0x6f,0x9f,0x63,0x7c,0xa5,0x8f,0x15,0x4a,0x45,0x99,0x64,0xea,0xe7,0x54, + 0x26,0x63,0xdd,0x05,0x11,0x8c,0xf2,0x51,0xca,0x67,0x99,0x9b,0x2a,0xa4,0x24,0xd2, + 0xbe,0x68,0x39,0x48,0x87,0xd2,0x17,0x34,0x77,0x80,0x5c,0x63,0xec,0x0e,0xfd,0xc0, + 0xcf,0x7c,0x0f,0x78,0xcb,0x36,0x17,0x24,0x01,0x6d,0x90,0x8f,0xeb,0xa4,0x09,0x43, + 0xc5,0x30,0x0b,0xde,0x67,0xfa,0xf4,0xf8,0x98,0x3a,0x09,0x46,0xbf,0x99,0xab,0x84, + 0xb6,0xd5,0x6b,0x13,0xcd,0x48,0x91,0x54,0x7e,0x1e,0xcd,0xc7,0xe9,0x71,0xdb,0x3a, + 0x7b,0xf7,0xf6,0xf3,0xfb,0xd3,0x5f,0x07,0x79,0x22,0x35,0x80,0x52,0x80,0x10,0x02, + 0xfa,0x92,0x09,0x86,0x14,0xfa,0xfd,0x0c,0x4b,0xd9,0x93,0x5f,0x80,0xa1,0x44,0xb8, + 0xe3,0x8f,0xca,0x8c,0x16,0xbc,0x98,0x19,0x7f,0x29,0x91,0x50,0x41,0xdc,0x4f,0x54, + 0x44,0xb9,0x94,0xc2,0x81,0x41,0x26,0xa9,0x8c,0x52,0x99,0xf1,0xb6,0xa2,0x72,0x5e, + 0x6c,0x05,0x18,0xf3,0x6f,0x80,0xaf,0xca,0xc5,0x16,0x99,0xc0,0xed,0x31,0x11,0x1a, + 0x0e,0xb8,0x12,0xbe,0xae,0xc8,0xea,0x0f,0x6b,0x84,0x31,0xb9,0xac,0x19,0x22,0x88, + 0x3e,0x83,0x81,0xc9,0x47,0x88,0xd6,0x72,0x58,0x5a,0x5d,0x6f,0x2e,0x7f,0x3e,0x37, + 0x0b,0xd5,0xb0,0x64,0xc8,0xd9,0x9f,0x90,0x37,0x29,0x97,0x81,0x85,0x6b,0x3e,0x89, + 0xc1,0xc8,0xbb,0x88,0x56,0xd2,0x96,0x12,0xd3,0xd0,0xd7,0x04,0x12,0x39,0xc3,0xf9, + 0x4a,0x10,0x92,0xba,0x59,0xc3,0x07,0x0b,0x99,0x30,0x97,0xe5,0x9f,0x9e,0xac,0x9e, + 0xfe,0x5a,0xc3,0xe3,0xc6,0xbc,0x82,0x44,0xa6,0x41,0x2c,0x9f,0x1e,0x1f,0xaf,0xae, + 0xfb,0x82,0xd2,0x97,0xe1,0xa3,0x9f,0x9a,0x3e,0x29,0x59,0xec,0x2b,0xb5,0xf2,0x0a, + 0x7c,0x3d,0x67,0x58,0xe6,0x21,0x04,0x9f,0xb0,0x13,0xa5,0xbe,0x7b,0xcc,0x69,0x7b, + 0x8e,0x70,0x02,0x02,0x1e,0x5b,0xb0,0xff,0xcb,0x55,0x08,0x61,0x6a,0x26,0x71,0x13, + 0xa0,0x9b,0xde,0xd8,0x68,0xd1,0x35,0x20,0x0f,0x18,0xf1,0xa1,0xaf,0x89,0x32,0x74, + 0x37,0x40,0xb7,0x4d,0x52,0x77,0x89,0x7f,0xc6,0x7e,0x36,0x6f,0xad,0xe5,0x95,0xf9, + 0x42,0xde,0xfd,0x64,0xe3,0xa3,0xb8,0xfe,0x87,0x9e,0x31,0x34,0xe1,0x75,0x95,0x4b, + 0xf0,0xc7,0xd8,0x37,0xf8,0xb7,0x7e,0x56,0xa1,0xa1,0xaf,0xa1,0xe6,0x35,0xa8,0xa7, + 0x94,0x17,0x74,0xfb,0x72,0x35,0x9f,0xb8,0x8f,0x19,0xb2,0xb2,0x08,0x9b,0x78,0x2d, + 0x37,0x99,0xa3,0x33,0xd9,0x03,0x11,0x76,0xf8,0x6e,0x10,0x39,0x45,0xcd,0x2a,0xd3, + 0x7a,0xbc,0x01,0xca,0x67,0xbd,0x2a,0xdd,0x2d,0x84,0xdb,0x42,0x63,0x11,0xe3,0x92, + 0xc5,0xb3,0xa7,0x6f,0xf1,0x8c,0xb8,0x34,0x7a,0x31,0x4b,0x34,0x63,0xcd,0x1c,0x0a, + 0x16,0x23,0xaf,0x76,0x71,0x94,0x85,0xa3,0x7b,0x83,0x07,0x30,0xef,0xc8,0x35,0x1b, + 0x56,0x9f,0xbc,0xa2,0x29,0x67,0x9f,0xbd,0x5b,0x64,0x9d,0x6e,0x2b,0x47,0x35,0x62, + 0x61,0x66,0xe1,0x20,0xaf,0x15,0x8f,0xc9,0x60,0x71,0x66,0xa1,0x23,0xef,0xcb,0x1b, + 0xe0,0xa1,0x51,0x3f,0xcf,0x81,0xb1,0x2c,0x4b,0x93,0x0e,0x14,0x82,0x25,0x4d,0x5e, + 0x0c,0x62,0xca,0xfe,0x82,0x98,0xd3,0xa8,0x93,0x73,0x96,0x92,0x50,0xf7,0xf2,0xce, + 0x20,0x07,0x6a,0x39,0x64,0x79,0x04,0x12,0x90,0xd5,0xa8,0x0a,0xb8,0x65,0x39,0xb5, + 0x22,0x4c,0x8a,0xf5,0x99,0xf6,0xa4,0x0c,0x68,0xff,0xab,0xf7,0xaf,0xa7,0xba,0xda, + 0xee,0x01,0x8c,0x05,0xc8,0x90,0x1a,0x8f,0xd6,0xe3,0xbd,0x83,0xd2,0x33,0xa0,0x33, + 0xcc,0x99,0xda,0xea,0x4a,0x80,0xd3,0xfa,0x8a,0x20,0xd3,0xd7,0x1e,0xad,0xd6,0x75, + 0x20,0xbe,0x77,0x94,0x1c,0xcb,0x17,0x68,0x89,0xd5,0x45,0x6c,0x67,0x95,0xe6,0xd4, + 0xf4,0x72,0xed,0x04,0x6a,0xab,0x96,0x5a,0x31,0xa5,0x54,0xab,0xb0,0x32,0x37,0x6a, + 0x5a,0x92,0x78,0xab,0x66,0x1a,0xcd,0x14,0xec,0x65,0x85,0x82,0xe9,0x70,0xe0,0x0e, + 0xe8,0xd4,0xa7,0xa6,0xcb,0x05,0x01,0x76,0x34,0x99,0x82,0x98,0xd9,0xbc,0xb1,0x96, + 0xb8,0xc6,0x40,0x24,0x04,0x96,0xfd,0x7f,0x01,0xf1,0xf8,0x5f,0xc4,0xab,0x67,0x82, + 0x5d,0x13,0xc1,0x07,0x39,0xe6,0x1c,0xe3,0x89,0x2d,0x82,0x5b,0xc0,0x56,0x3d,0x99, + 0x32,0xf7,0x3d,0xe0,0x17,0x7b,0x6e,0x27,0x83,0x91,0x43,0x9c,0x96,0xfd,0x3b,0x3c, + 0x21,0xcb,0xf1,0xf8,0xb8,0x64,0xbd,0x2a,0x2a,0x4d,0xef,0x20,0x11,0xd9,0x0b,0x9a, + 0xd0,0xe6,0x7c,0x70,0xe3,0x90,0x95,0x5f,0x73,0xf7,0x9f,0x98,0xb5,0x79,0xd5,0x69, + 0xbd,0xba,0xb6,0x7e,0x73,0x9a,0xbf,0xdd,0xed,0x58,0x5f,0xef,0x82,0xc4,0xb5,0x64, + 0x05,0x5b,0xf3,0x77,0x47,0xec,0xe7,0x57,0xd7,0xd6,0xd5,0x0e,0x6a,0xdb,0x5a,0x9d, + 0x6b,0xd2,0x39,0x61,0x86,0xdb,0x41,0x7a,0x35,0xbf,0xea,0x5e,0x5f,0xcb,0x13,0x8c, + 0xdb,0xc1,0x00,0xd5,0xbd,0x27,0xa6,0xd9,0x13,0xc2,0xeb,0x2d,0x8c,0x9d,0xbd,0xb4, + 0x70,0xc8,0x0d,0xf4,0x4e,0xe4,0x90,0xa0,0x3d,0x85,0xbd,0xf8,0xda,0xa7,0x0f,0xa5, + 0xb0,0x9d,0x79,0x16,0xf5,0xe1,0xb3,0xd8,0xc0,0x01,0x39,0xa8,0x04,0x46,0xb3,0xec, + 0x15,0x35,0x99,0x89,0x03,0x89,0x16,0x57,0x88,0x11,0x29,0xab,0x9f,0xa3,0xd0,0x12, + 0xc5,0xb3,0xfb,0xea,0xe7,0xec,0x5e,0x14,0x76,0x27,0xd5,0x8f,0xee,0x44,0x16,0x95, + 0x61,0xb8,0x2a,0x59,0xc4,0x07,0x51,0x49,0xb6,0x2a,0x5b,0x26,0xb3,0x71,0x75,0x18, + 0x66,0x2a,0x1f,0x2f,0xbc,0x9d,0xa0,0x2b,0x4e,0x8f,0x0c,0x48,0xb8,0xa6,0x42,0x7c, + 0xa7,0x3c,0x2b,0x27,0xe8,0xb9,0x1b,0x5a,0x76,0x2d,0xaa,0x52,0x5e,0x04,0x12,0x3f, + 0xaf,0x2f,0x46,0x71,0x5c,0x54,0x01,0x78,0x39,0x23,0xac,0x5d,0x78,0x40,0x76,0x44, + 0x46,0x3d,0xdc,0x51,0x5e,0xb5,0x96,0x5a,0x53,0x37,0x87,0xbe,0xd0,0xfa,0x4e,0x09, + 0xd5,0x8c,0x79,0xb0,0x80,0x0a,0xd8,0xe8,0xd3,0x67,0xf8,0x64,0x95,0xf3,0x4a,0xdf, + 0xfd,0xd5,0x45,0x3e,0x73,0x8e,0x6a,0x49,0xe5,0x34,0xbf,0xa6,0xac,0xcc,0x23,0x4b, + 0xeb,0xee,0xe7,0xf9,0x88,0x30,0xf5,0x33,0xa7,0x8a,0x7c,0xe5,0x88,0x15,0x55,0x94, + 0xa2,0x0c,0x9f,0x65,0x86,0x62,0xef,0x9e,0x2d,0xcd,0x1d,0x5c,0x51,0x87,0xb2,0xde, + 0x16,0xc5,0xd4,0xb2,0xc9,0xcd,0xdb,0x65,0x85,0x77,0xf4,0xda,0xcf,0xbf,0x22,0x49, + 0xcf,0x3f,0xc2,0x9b,0xfe,0x4d,0x19,0xde,0x6a,0x39,0x64,0x9a,0x68,0xa2,0x64,0xe8, + 0x5c,0xea,0xf8,0x9d,0xc3,0xdf,0x3f,0x8b,0xef,0x8f,0x8f,0x1d,0xd9,0x69,0xdd,0xf9, + 0x5b,0x96,0xfa,0x5d,0x24,0xf4,0xf3,0x1c,0xe4,0x32,0x9d,0x7f,0xc7,0x57,0xbd,0x02, + 0x21,0xbf,0xe5,0x19,0x38,0xa1,0xb2,0xaa,0x0a,0x1e,0x9e,0x79,0x6e,0x91,0x52,0x45, + 0x4d,0xe5,0x56,0x99,0xe7,0x85,0xb7,0xfa,0x6a,0x35,0xea,0xf2,0x3b,0xbc,0x68,0x5f, + 0x12,0xfd,0x4b,0x72,0xbf,0xa2,0x99,0x55,0xb3,0xfe,0xbb,0x53,0x9e,0xe8,0x92,0xf7, + 0x61,0x5e,0xb7,0x4a,0xab,0xef,0x61,0x8d,0x87,0x59,0xa5,0x2d,0x95,0xe7,0x73,0x7d, + 0xab,0x59,0xac,0xb7,0x97,0xc5,0x85,0x69,0x24,0x0f,0x71,0x6d,0x16,0xf1,0x5d,0x6b, + 0x9f,0x5d,0xab,0xf3,0xef,0xf4,0x2e,0x69,0xb3,0x74,0x73,0xd2,0x60,0x28,0x92,0xfa, + 0x85,0x0c,0xd2,0xbf,0xa8,0xd2,0x73,0x99,0xe1,0x33,0x67,0x90,0xdd,0x26,0x77,0x1f, + 0x0d,0x31,0xe0,0xb5,0x02,0x9d,0x92,0xc3,0x4e,0x31,0xf7,0x67,0xf5,0x21,0xd7,0x97, + 0xe3,0xd2,0xd2,0xcf,0xd8,0x02,0xdc,0xe4,0x49,0xb1,0x87,0x62,0x46,0xe0,0x90,0xb1, + 0xd1,0x40,0xf3,0x3e,0x12,0x6a,0x2c,0x03,0xf5,0x95,0x98,0xe6,0x15,0x28,0x7e,0x23, + 0xff,0x4a,0x3c,0x40,0x51,0x88,0x40,0x0b,0x03,0xa8,0xd4,0xbe,0x5d,0x53,0x7d,0x5e, + 0xef,0xa0,0x79,0x8b,0x9f,0xf8,0x48,0x8c,0xd8,0x31,0x59,0xeb,0xe0,0xb6,0x50,0x6f, + 0x89,0xd0,0xcb,0xb3,0x08,0x4c,0xfe,0x2c,0xa2,0xbd,0x89,0x5e,0x8b,0x4e,0x22,0x0f, + 0x40,0x81,0xd8,0x06,0x42,0x53,0x2c,0x32,0x53,0x9a,0xf5,0xf8,0xd8,0xb6,0x65,0xc0, + 0xae,0x52,0x06,0x99,0x6c,0x91,0x8a,0x01,0x9a,0xa1,0x12,0xc7,0x83,0xce,0xd6,0x16, + 0x47,0x7e,0x1b,0x74,0xda,0xb2,0x29,0x4a,0x00,0x91,0x9b,0x7e,0x77,0x9a,0x4d,0x55, + 0xe5,0x60,0xd0,0x39,0x7c,0x7c,0xd4,0x5e,0xf7,0xba,0xd6,0x89,0x69,0xc8,0x04,0x28, + 0x22,0x1f,0x7b,0xa6,0x76,0xf2,0xa2,0x6d,0xd4,0xd0,0x93,0x04,0x28,0x3b,0xb0,0x37, + 0x87,0x07,0x87,0xdd,0x03,0x14,0xee,0xcd,0x9d,0xe2,0x77,0x8a,0x66,0xc5,0x59,0x30, + 0x7a,0x55,0x51,0x9a,0x43,0x97,0xfd,0x4f,0x90,0xab,0x29,0x4f,0xc0,0x04,0x94,0x06, + 0x4a,0xf9,0x5b,0x0c,0x95,0x77,0xbd,0x6d,0xd9,0x0c,0xaf,0x52,0x06,0x8e,0x66,0x87, + 0x7a,0x4a,0x82,0xb9,0xc8,0xff,0xf8,0xf8,0x15,0x43,0x52,0x6a,0x3c,0x45,0xba,0x9a, + 0xd8,0xaf,0x4a,0xb3,0xc3,0x33,0x12,0xae,0x9a,0x8d,0x3e,0x3d,0x89,0xa9,0x0f,0x09, + 0xda,0x21,0x42,0xfa,0x44,0x0c,0x39,0xb4,0x7a,0x32,0x1a,0x1c,0xea,0x45,0x0a,0x3d, + 0x54,0x91,0xd7,0x50,0x83,0xcd,0x35,0x14,0x01,0x55,0x9a,0x96,0x6a,0xea,0x5e,0xf7, + 0xa4,0x94,0xd8,0x6b,0x5b,0x95,0x76,0x80,0x32,0xae,0x6a,0xa1,0x30,0x55,0x95,0x82, + 0x1c,0x76,0x6c,0x55,0xd9,0xea,0x34,0x26,0xde,0x24,0xf1,0xd2,0x19,0x4d,0x1f,0x71, + 0xf1,0xc5,0xa9,0xd5,0x3f,0xcf,0xdd,0xe4,0x66,0xe3,0x09,0x96,0x93,0xf3,0xcc,0x44, + 0xcb,0x65,0x4d,0x4a,0x6c,0x82,0xf9,0x80,0x0b,0x0c,0x54,0x44,0xbe,0x7c,0xf1,0x3c, + 0x3b,0x17,0xac,0xc6,0xd2,0x23,0xcc,0x59,0xab,0x4f,0x41,0x38,0x87,0xa5,0x95,0x29, + 0x45,0xe4,0x5b,0x5d,0x56,0x15,0x25,0xee,0x3f,0xf7,0x28,0x27,0xb4,0x95,0x24,0x02, + 0x21,0x85,0x5f,0x38,0x73,0xe3,0xc4,0x58,0x33,0xc5,0xb4,0xe2,0xd6,0xcf,0x24,0x9e, + 0x54,0x94,0x68,0x80,0xec,0x2f,0x6a,0x6d,0xda,0xe6,0xba,0x35,0xff,0x44,0x3d,0xe5, + 0x60,0x85,0x03,0xfd,0x90,0x47,0xe3,0x73,0x71,0xd9,0x71,0x0e,0x49,0x15,0xf3,0xa9, + 0x21,0x7b,0x95,0x01,0x22,0xc0,0xd6,0x16,0x25,0x43,0x93,0x29,0xb3,0x27,0x57,0x85, + 0x3a,0xf4,0x13,0x1f,0x4c,0x59,0x77,0x76,0x54,0x85,0x2e,0x35,0x63,0xb2,0x75,0x8c, + 0x25,0x0e,0x5b,0x08,0xeb,0xf0,0x9f,0xef,0x30,0xb5,0xa9,0xb7,0x66,0x53,0x57,0x6c, + 0xee,0xb4,0x3e,0x91,0x35,0xba,0x7a,0x49,0x4c,0xf0,0x10,0xe9,0xe3,0x64,0xd2,0xab, + 0x86,0x09,0x15,0xa1,0xef,0xf4,0x18,0xa1,0xc1,0x03,0x9d,0x10,0xa9,0x19,0x34,0xcf, + 0x16,0x69,0x06,0xc2,0xa7,0x28,0xb2,0x9b,0x6a,0x21,0x02,0x53,0xbc,0x51,0x8f,0xce, + 0x21,0xd1,0x48,0xcf,0x9f,0xcf,0xbd,0x31,0x30,0x63,0x78,0xc9,0x9b,0xb8,0x27,0xd7, + 0xd5,0x2e,0xc6,0x14,0x4e,0x61,0x74,0xfc,0xf4,0x8e,0x26,0x95,0xe3,0x4d,0xa2,0x16, + 0x09,0x2a,0x77,0x83,0xd1,0x22,0xa0,0x00,0x46,0x13,0xe5,0x0d,0x2a,0x2e,0x77,0x11, + 0x51,0xdb,0x55,0x1c,0x77,0x56,0x42,0x21,0xc3,0x39,0x76,0x8a,0x7b,0x2f,0x01,0xea, + 0x2c,0x9a,0x0f,0x23,0x79,0x4a,0x1c,0x0f,0x40,0x60,0xc5,0x23,0x44,0x31,0x3f,0xd3, + 0xeb,0x55,0xa7,0x87,0xf1,0x95,0x76,0xd8,0x09,0xf9,0x06,0x92,0x5e,0x3e,0xe5,0x1b, + 0x48,0xec,0x60,0xb0,0xf5,0x1d,0xd3,0x06,0x64,0x73,0x86,0x77,0xe2,0x21,0x9d,0x88, + 0x87,0x51,0x52,0xd9,0x23,0x28,0x00,0xff,0xb4,0xa9,0x8e,0x7a,0x8d,0x5c,0xbb,0x2a, + 0x2e,0x94,0x2f,0xeb,0x18,0x46,0xac,0x25,0x05,0xe1,0x7e,0x30,0xea,0x0b,0x84,0xc3, + 0x41,0xc0,0x23,0xa3,0xa4,0xb0,0xfa,0xd0,0x8e,0xc5,0x96,0xa4,0x2e,0xbf,0x40,0x71, + 0x1d,0xd0,0x21,0x77,0xbe,0xb7,0xfa,0x85,0x0f,0xea,0x5a,0x22,0xd4,0xb8,0x29,0x90, + 0xdc,0xac,0x84,0x08,0x01,0xf0,0x66,0xa0,0x81,0xe5,0xc6,0xbe,0x1d,0x28,0x2d,0x06, + 0xe9,0xef,0x69,0x39,0xdc,0x5c,0x03,0x3b,0xa1,0xb1,0x26,0xfd,0x02,0xa6,0x4b,0x25, + 0x23,0x63,0xba,0xa0,0x20,0x81,0x3b,0x1c,0x50,0x2e,0xbc,0xa7,0x3c,0x6b,0x9a,0xce, + 0x04,0xbe,0x90,0x66,0x63,0x36,0x80,0x6f,0xc0,0x0c,0xb8,0xc3,0x92,0xd9,0x96,0xe9, + 0xe0,0x0d,0x01,0x26,0x9f,0x29,0xce,0xac,0xd1,0x4c,0x3b,0xc6,0x13,0xe7,0xae,0x62, + 0x48,0xa3,0xc9,0xfc,0x7a,0xcd,0x21,0xb1,0x54,0x56,0x15,0x0b,0xad,0x41,0x0d,0x55, + 0x46,0xec,0x2c,0x42,0xe1,0x52,0x42,0x98,0xf5,0xc3,0xc6,0xc6,0x14,0xd3,0x20,0x2a, + 0xc8,0x41,0xc8,0xef,0x03,0x1d,0x7f,0xfb,0xee,0xe4,0x47,0x58,0xd3,0x38,0xba,0xdc, + 0x18,0xa1,0xd3,0xf7,0x5f,0x0f,0xd4,0xb9,0x0c,0x59,0x25,0x2c,0xc5,0x7e,0x85,0xb3, + 0xfc,0x3d,0x12,0xf1,0xb4,0xf9,0x75,0x11,0x0b,0x6c,0x1f,0xed,0x4c,0xeb,0x32,0xe5, + 0x18,0x01,0x79,0x9e,0x1a,0xe9,0x43,0x38,0x3a,0x27,0xf1,0xe7,0x7b,0x3f,0xc0,0x03, + 0x60,0x6c,0xbc,0xa4,0xd3,0xad,0xd8,0x85,0xe4,0x74,0x0a,0xb0,0xc3,0x96,0x7c,0x2f, + 0xf2,0x9d,0x39,0x7a,0x58,0xcb,0xb1,0x47,0x97,0xa5,0x48,0x24,0x86,0x34,0x3e,0xcb, + 0xd0,0x12,0x06,0xb7,0x4f,0xcc,0xd2,0x5a,0xeb,0x08,0xe5,0x0d,0x1a,0xfb,0xca,0x52, + 0x4c,0x2e,0x6f,0x70,0xe7,0x74,0x01,0x81,0x72,0x88,0x55,0x3b,0xad,0xd9,0x4d,0x88, + 0x5c,0xd2,0xaa,0x86,0xa0,0x45,0x21,0xdc,0x09,0xb5,0xbe,0xf2,0x0a,0xc7,0xcc,0xee, + 0x64,0x10,0xbb,0x49,0xea,0x7d,0x8f,0x2e,0x87,0x4d,0x7d,0x1f,0x81,0x16,0xd5,0x4e, + 0x85,0xec,0x75,0x81,0xf6,0xfa,0xe9,0xf7,0x3e,0x88,0x09,0x5e,0xd3,0x9d,0x58,0x5b, + 0x5b,0xee,0xe4,0x78,0xd0,0x3e,0x31,0xff,0x37,0x6c,0x52,0xc2,0x6a,0x24,0x5a,0x84, + 0xe3,0x26,0xc6,0x48,0xdd,0x85,0x1c,0x3b,0x1d,0xcb,0xda,0x05,0xb6,0x77,0xc7,0xfc, + 0x37,0x63,0xbc,0xc8,0x1e,0x0c,0x8a,0xea,0x8c,0xd6,0x20,0xd8,0x71,0xa5,0xbc,0xaf, + 0x2a,0xc5,0xc9,0x6f,0xa9,0xac,0x13,0xa7,0x51,0x05,0x03,0xef,0xd6,0xc9,0xc8,0x58, + 0xb2,0x2f,0x04,0x05,0x85,0xaa,0x80,0x81,0x44,0x8f,0x72,0x36,0x87,0x3c,0x28,0xa0, + 0x2d,0x79,0xbe,0xa2,0x2f,0xf9,0x82,0x61,0x09,0x0c,0x7b,0x7b,0x47,0xff,0xba,0xb3, + 0x5d,0x6f,0x2b,0x11,0x59,0x4b,0xb4,0x20,0x83,0x3d,0x13,0xe6,0x93,0x49,0x43,0x64, + 0x2b,0xd1,0x88,0x56,0x43,0x8e,0x38,0x05,0x0a,0xa3,0x32,0x21,0x2e,0xd5,0xf7,0x09, + 0xd6,0x77,0xd1,0xdc,0x05,0x2f,0x2c,0x29,0xf4,0x0b,0x52,0x36,0xea,0x59,0x24,0x16, + 0xb6,0x4e,0xeb,0xeb,0x5a,0x4c,0xa6,0x02,0xb0,0xb7,0xc5,0x35,0xfa,0x3c,0xfd,0x80, + 0xe6,0xa2,0xd5,0xd8,0x7c,0x9b,0x33,0x15,0x82,0x24,0x14,0x21,0x23,0x2e,0x9b,0x42, + 0x9a,0x2a,0x0c,0x1f,0xe5,0x61,0x37,0x12,0x42,0x54,0x23,0xab,0x5b,0x6b,0xf8,0x1c, + 0x49,0xde,0x49,0x8c,0x21,0x1a,0xd0,0xa1,0xc5,0x98,0x81,0x14,0x9c,0x66,0xb4,0x61, + 0x6c,0x6d,0xa5,0x8e,0x08,0xc1,0xed,0xb0,0xfb,0xbe,0x18,0xd4,0x7c,0xd0,0xea,0xf4, + 0x3f,0x9d,0x7e,0xf7,0xf6,0xe3,0xe7,0xf3,0x4f,0x6f,0x2e,0xde,0x5c,0x5e,0x54,0xc7, + 0x11,0x03,0x85,0x40,0xc0,0x8d,0x70,0xe4,0x6f,0x7e,0x6f,0x72,0x3b,0x0c,0x87,0xd8, + 0x82,0x0e,0x5a,0xf3,0x81,0x8f,0x9d,0x4f,0x05,0x48,0xe7,0x88,0xf2,0x82,0x60,0xce, + 0xad,0x5e,0x53,0x8e,0xa5,0xb0,0x7e,0x4f,0x4c,0xec,0xbf,0xd9,0x4b,0xd5,0x32,0x7a, + 0x6a,0x3c,0x15,0x75,0xf4,0xa5,0xa5,0xbc,0x14,0x82,0xce,0xc7,0x21,0x86,0x41,0x43, + 0x0b,0xb6,0xb4,0xa9,0xaa,0x13,0xc3,0x12,0x2b,0x37,0x8e,0xff,0xe1,0xa7,0x3e,0x72, + 0xd1,0x5f,0x7d,0xdd,0x94,0xc7,0x6b,0x3a,0x87,0x2b,0x22,0xaa,0xa6,0x25,0x4b,0x0e, + 0xe1,0xea,0x55,0xc7,0x0b,0x93,0x61,0xad,0x1d,0x1e,0xb7,0x61,0x4d,0xab,0xea,0xb5, + 0x72,0xad,0xb0,0xc4,0x83,0x85,0x3b,0xcd,0x10,0xe5,0x22,0xe0,0x54,0xd9,0x1b,0x0b, + 0x56,0xb5,0xf4,0xcb,0x32,0xcb,0x72,0x87,0x72,0x04,0x5b,0xea,0xac,0x43,0xe5,0x0c, + 0x82,0x4d,0x8c,0x4d,0xf6,0x15,0x03,0xd1,0x83,0xcc,0xe4,0xc8,0x06,0xfc,0xdd,0xc7, + 0x4b,0x3c,0x64,0x7f,0xf7,0xe6,0xc3,0x00,0x72,0xdd,0x78,0x61,0x6f,0xff,0xa5,0xbd, + 0x48,0x31,0x7a,0xff,0xdc,0xeb,0xed,0x75,0x94,0x21,0x77,0xef,0x70,0xcf,0x66,0x87, + 0x5f,0x7c,0xa2,0x90,0x63,0xbd,0x57,0x07,0xb6,0xbb,0x18,0xfb,0xe8,0x36,0x87,0x96, + 0x4c,0x0c,0xc4,0xf3,0x9f,0x2e,0x3f,0x5f,0xfe,0xe7,0xf9,0x9b,0x8b,0xc1,0xd5,0x55, + 0xdb,0x36,0x3f,0xbd,0xf9,0x0f,0xf3,0xda,0xbe,0xea,0xe0,0xd3,0xc5,0xf9,0xc7,0x0f, + 0x17,0x6f,0xf0,0xb5,0x6b,0x9b,0x97,0xbf,0x42,0xcb,0x17,0x3f,0xe0,0xdb,0x9e,0x6d, + 0x9e,0x9e,0xfd,0x84,0x4f,0xfb,0xf0,0xf4,0xdd,0x3f,0xde,0x7c,0xba,0x84,0x97,0xc6, + 0xd5,0x81,0x6d,0xfe,0xf0,0xe9,0xfc,0x33,0xe4,0xc4,0x6f,0x87,0xfc,0xf6,0xdd,0xe9, + 0xe5,0x29,0xbe,0xbe,0x84,0xac,0x1f,0x3e,0x7e,0xf8,0x2c,0x1a,0x38,0xb2,0xcd,0xf3, + 0xd3,0xcb,0x1f,0xf1,0xf1,0x15,0x54,0xfe,0xe9,0xf4,0xec,0x0d,0xd5,0xd1,0x81,0x3e, + 0xbc,0xff,0xf9,0xdd,0xe5,0xdb,0xf3,0x53,0xaa,0xf5,0xaa,0x03,0x5d,0x39,0xfb,0xf8, + 0xe1,0xf2,0xd3,0xc7,0x77,0xf4,0x0a,0x5d,0x41,0xc4,0x84,0x91,0x8d,0xe9,0x7d,0xaf, + 0xf4,0xbe,0x5f,0x78,0x87,0x0a,0xa1,0x57,0x9f,0x4e,0x7f,0xf9,0x7c,0xf6,0xf3,0xc5, + 0xe5,0xc7,0xf7,0xe6,0xf5,0x75,0x3e,0xec,0x0f,0xa7,0xef,0xdf,0x7c,0x27,0xf1,0x6c, + 0x04,0xb2,0x05,0x50,0x73,0x3c,0xe2,0x80,0x59,0x53,0x50,0xa9,0x59,0x27,0xb4,0x4a, + 0xe2,0xab,0xce,0x35,0x8a,0x28,0xaa,0x2d,0x4b,0xd5,0x78,0x85,0xdf,0x00,0xa1,0x28, + 0xb6,0xef,0x19,0x50,0x97,0xa6,0x75,0x3d,0x88,0xaf,0xda,0xd7,0x05,0xac,0x9f,0xd0, + 0x06,0xfc,0xde,0x4d,0x6f,0x9a,0x88,0x4e,0x02,0xed,0x33,0xc9,0x81,0x60,0x5a,0x7e, + 0xe0,0x42,0x39,0x1c,0xf8,0x32,0x6f,0xf2,0x8e,0x98,0xe1,0x8e,0x68,0x3e,0x3e,0xd2, + 0xaf,0x1b,0x04,0x4a,0xe5,0xd4,0xbe,0xff,0x1e,0xfe,0xcb,0xf3,0x50,0x24,0x04,0xf5, + 0x51,0xca,0xa4,0xe9,0xcd,0xa0,0x6d,0x47,0x37,0x7c,0xd4,0xd7,0xc8,0x9c,0x14,0x18, + 0x7c,0x40,0x38,0xbb,0x8e,0xbe,0x61,0xb4,0x61,0xd9,0x3b,0x28,0x82,0xaf,0xa2,0x27, + 0x76,0x88,0x64,0x85,0x2c,0xb1,0xff,0x79,0xd5,0x6e,0xbd,0xba,0xde,0xf9,0x5a,0x18, + 0x4e,0x43,0x46,0xcb,0x0a,0x79,0x5f,0x7d,0x1b,0xd2,0xbb,0xdd,0x69,0x4b,0x15,0x15, + 0xf6,0x2d,0xba,0x29,0x42,0x08,0x89,0x86,0x82,0x20,0x14,0xcd,0xa1,0x59,0xc9,0xca, + 0xa6,0x04,0xe1,0xeb,0xf6,0xe3,0x63,0x78,0xdc,0x39,0x00,0xf2,0x7b,0x23,0xce,0xea, + 0x78,0x98,0x4f,0x0d,0x1c,0xe0,0xe3,0xa0,0xd9,0x79,0xfd,0x3a,0x14,0xec,0x8c,0x00, + 0x40,0x74,0x73,0x82,0xdf,0x7a,0x12,0x4a,0x4f,0xe5,0xf9,0xb8,0x04,0x40,0x37,0x31, + 0x0b,0x33,0x39,0x04,0xa9,0xc1,0x80,0xb3,0x4b,0xa5,0x15,0x82,0xbb,0xaf,0x7f,0x95, + 0x1f,0x08,0xd6,0x0c,0xe2,0x68,0x91,0x0d,0xd0,0xe6,0xa1,0x68,0x65,0xda,0x39,0x24, + 0x86,0x4e,0x14,0xdd,0xc2,0x0e,0xfa,0x96,0x05,0x79,0x9d,0x78,0x91,0xce,0x9a,0xbe, + 0xd6,0x51,0x48,0x63,0x9b,0x50,0xbb,0x44,0x44,0x52,0xc9,0xe0,0xfd,0x98,0xcd,0x83, + 0xa6,0x6f,0x4f,0x6c,0xd4,0x0f,0xda,0x14,0x4b,0xc3,0x46,0x19,0x51,0x49,0x22,0xdb, + 0x85,0x88,0x1c,0x46,0x3a,0x69,0x6d,0xef,0x4c,0x60,0xd3,0x94,0xa1,0x38,0xb6,0x77, + 0xe8,0x77,0x67,0xbb,0x36,0x3a,0xcc,0xf6,0x0e,0xfe,0x42,0xf6,0x42,0xac,0xad,0xed, + 0x1d,0x7f,0x67,0xdb,0xe1,0x7a,0xfe,0xc2,0x15,0xb7,0xdb,0x3b,0x4d,0xec,0xea,0xc9, + 0x76,0x35,0xde,0xc9,0xf6,0x0e,0xfe,0x62,0xa7,0xd0,0x21,0x66,0xbb,0xb7,0xbd,0x6d, + 0xa9,0x97,0xa2,0xb9,0xb2,0xc6,0xc7,0x32,0x2c,0x04,0x96,0x0e,0xa3,0x7b,0x2f,0x1d, + 0xe4,0x2b,0x78,0xee,0xc6,0x45,0x13,0x15,0x09,0x1e,0x1a,0xb5,0x6c,0x3d,0xbe,0x59, + 0x1f,0x4b,0x2a,0x9e,0x20,0x4c,0x7c,0x1c,0xb7,0x10,0x2f,0xb6,0x77,0x70,0x51,0x23, + 0x40,0x39,0x94,0xc5,0xb1,0x4c,0x30,0xf0,0xa1,0x73,0x8d,0xdd,0x96,0xae,0x7e,0x0c, + 0xf0,0x92,0xa9,0xef,0xaa,0x69,0x62,0x54,0xd4,0x82,0xf8,0x70,0xe4,0x4b,0xe8,0x95, + 0x8a,0x09,0xb8,0xdd,0x80,0xda,0xd7,0xdd,0xd9,0x90,0x4f,0x96,0xac,0x8d,0x8a,0x68, + 0x4d,0xc5,0x37,0x53,0x84,0x36,0x41,0x4b,0x41,0xb8,0x92,0xc7,0x85,0x6e,0xac,0x0b, + 0x9c,0x10,0xa0,0x37,0x95,0x00,0x10,0xb0,0x0b,0x02,0x46,0x3d,0x5c,0x23,0x18,0x6b, + 0x50,0x79,0xce,0x52,0xcd,0x7f,0xa2,0xa2,0x3c,0x92,0x4b,0xb1,0x2a,0xdd,0xcf,0x0d, + 0x0a,0x2c,0xe6,0x25,0x17,0xda,0xf2,0x48,0x18,0xb9,0x7e,0x99,0xf9,0x23,0x0c,0x37, + 0xfa,0x80,0xdb,0x2f,0x43,0x94,0x34,0x1c,0x1c,0xa1,0x55,0xfa,0x34,0xfa,0xa9,0x88, + 0xc6,0xea,0x18,0x5a,0xb0,0xec,0x21,0xde,0x00,0x29,0xa2,0x90,0x92,0xf6,0xc3,0xbd, + 0x13,0xe5,0xd2,0xbe,0x8c,0xa6,0x8a,0xe9,0xea,0x4c,0x85,0x6a,0x0e,0x29,0x08,0x2c, + 0xcf,0x01,0x06,0xea,0xa1,0xe0,0x0a,0xa8,0x14,0xe1,0x10,0x3d,0x00,0x7d,0x59,0x89, + 0x0c,0x08,0x5b,0x88,0xaa,0x53,0x44,0xf9,0x1a,0xf1,0xad,0xc0,0xbb,0x7f,0x3d,0x30, + 0xe5,0x74,0xd7,0x72,0xc6,0x92,0x1d,0xf4,0x07,0xb3,0x9c,0x1f,0xaf,0x37,0x17,0xd8, + 0xb5,0x00,0x83,0x99,0x96,0xa1,0x2d,0x2b,0x14,0xc8,0x25,0x79,0x24,0x41,0x42,0x94, + 0xc2,0x6f,0x45,0xa3,0x5d,0xa4,0x89,0xda,0xde,0x36,0x53,0x7c,0x1f,0x66,0xad,0xfa, + 0x56,0x89,0xae,0xe7,0xab,0xab,0xb6,0xe3,0x23,0x34,0xa5,0x1f,0x0d,0xf3,0x53,0x0f, + 0x45,0x3f,0xd5,0x16,0x03,0x5f,0x59,0x73,0x06,0xfb,0x8c,0x65,0xc1,0xd6,0xdc,0xce, + 0x2d,0xd9,0x01,0x3d,0x06,0xd5,0xe6,0xd1,0xea,0x9c,0x30,0x47,0x98,0xee,0x2d,0xe6, + 0x16,0xfc,0x15,0x5d,0xb8,0x74,0xfa,0x7f,0x82,0x94,0x9f,0x91,0xc6,0xec,0x29,0xe2, + 0x7f,0x62,0xca,0x40,0xbe,0x12,0x89,0xcc,0x5e,0x79,0x2f,0x11,0xdd,0xc0,0x5b,0x80, + 0x0a,0x80,0x9c,0x88,0xa6,0xf1,0x83,0x85,0xff,0xac,0x96,0x23,0xb4,0x09,0x2b,0xc9, + 0xc7,0x65,0x2f,0x0e,0x0d,0x3f,0x28,0x06,0x9c,0x37,0x86,0x5d,0x82,0xe6,0x69,0xa9, + 0xed,0xfe,0x7f,0xc3,0x7c,0xa0,0xac,0xa0,0xa6,0xc4,0xca,0xf7,0xdc,0xfa,0x29,0xc9, + 0x67,0x43,0x50,0x27,0x13,0xaa,0x57,0xe8,0x6a,0xdf,0x0e,0xca,0x40,0xeb,0x97,0xa5, + 0xd2,0x95,0xa2,0x28,0xa0,0xf5,0x4c,0xaa,0x77,0x8b,0xd2,0xd5,0x0d,0xc9,0x55,0xb5, + 0x5a,0x0f,0xdd,0x42,0x38,0xd7,0xa1,0xa5,0x4a,0x2d,0x36,0x8b,0x52,0x74,0xee,0xc3, + 0x04,0xc2,0x74,0x7c,0x2f,0x60,0xfa,0x0c,0xf6,0x1c,0xb6,0x21,0x5b,0xab,0xbc,0x61, + 0x76,0x00,0x5d,0xba,0xb6,0x6b,0x83,0x54,0x61,0x20,0xe8,0xd0,0x33,0x5a,0x2a,0xd2, + 0xd4,0x76,0x5f,0xb3,0xa1,0xac,0x65,0x3f,0xb1,0xb6,0x9d,0x4a,0x75,0x20,0x1e,0xa7, + 0xa3,0x66,0x4c,0xe6,0x35,0x16,0xee,0x4a,0xa5,0x84,0xbc,0x01,0x84,0x51,0x7d,0x1d, + 0x23,0x52,0x05,0x9b,0xc7,0xfc,0xeb,0x38,0x8e,0xde,0x2b,0x1c,0x30,0x16,0xd1,0xc3, + 0x45,0x20,0x25,0x60,0xaa,0x8d,0x8f,0x12,0x67,0x2a,0xd4,0x97,0x02,0x15,0x0c,0x8f, + 0x11,0xc6,0x06,0x65,0x61,0x27,0xf4,0x3a,0x42,0x3d,0xd1,0x2f,0x0d,0xd2,0xc3,0x51, + 0xd6,0x04,0xc1,0xe5,0x0d,0x8e,0x41,0x85,0xe3,0xa5,0x41,0x6d,0x97,0x42,0x75,0x41, + 0x03,0x65,0x9e,0xc9,0x24,0xd1,0x09,0x58,0x2b,0x65,0x44,0x01,0xc2,0xc9,0x68,0x84, + 0xbe,0xe9,0xf2,0x8b,0x69,0xd5,0x14,0x93,0x82,0x16,0x7c,0xa7,0x20,0x32,0x36,0x5e, + 0x30,0x2c,0x53,0x6a,0x4b,0x68,0x0d,0x68,0x8f,0xe7,0xf9,0x63,0x6d,0x29,0x16,0xdc, + 0xf2,0x56,0x38,0x06,0x2b,0xa1,0xe4,0xca,0x86,0xa2,0x04,0xbf,0x89,0x90,0x74,0xd0, + 0x04,0xbf,0xd7,0xe6,0x25,0x69,0x30,0xaf,0xfd,0x12,0x5f,0x8d,0xcc,0x03,0x0e,0x0d, + 0xaf,0x43,0x80,0xb2,0x79,0xb8,0x9a,0xb4,0x67,0x2c,0xd1,0xfc,0xe2,0xc9,0x58,0x72, + 0x20,0x02,0x78,0x40,0x0a,0x88,0x3f,0x08,0xa9,0xa7,0xda,0x06,0xa4,0x94,0x99,0xb7, + 0xf1,0xef,0xbf,0x5c,0x1a,0x5a,0xaa,0xba,0x64,0xb9,0xa5,0x85,0x0b,0x44,0xe8,0xee, + 0x22,0x94,0x0c,0xb6,0xd6,0x6d,0xec,0xd4,0xb0,0x78,0x8d,0x02,0x33,0x88,0x10,0xd1, + 0x9c,0x09,0x10,0x43,0xeb,0x4e,0xfa,0x34,0xa5,0x28,0x96,0x40,0x45,0x47,0xa3,0x76, + 0x4d,0xf3,0x56,0x87,0x95,0x16,0x77,0x0a,0x41,0x86,0x74,0x1c,0x17,0x8e,0x27,0xd5, + 0x1d,0x90,0xd1,0xf1,0x4d,0x50,0xb7,0xe3,0xe4,0xe4,0xac,0x82,0xbe,0x74,0x40,0x4c, + 0x9a,0x0f,0x40,0xa7,0x81,0xac,0x44,0x3f,0x4a,0x1c,0x7b,0x13,0x12,0x08,0xfb,0xcf, + 0x90,0x07,0x94,0x4e,0x69,0xd1,0xc3,0xf6,0x44,0x6b,0x1f,0x0b,0xc6,0x92,0xfa,0x92, + 0x6b,0xc0,0x40,0x7c,0x96,0x0b,0xfe,0x44,0x3e,0xf4,0x9a,0x90,0xf9,0x04,0xfe,0xd8, + 0x85,0xa0,0x27,0xe4,0x47,0xb1,0x8d,0xce,0xa2,0xbb,0xf7,0xb0,0x85,0x09,0xcd,0x03, + 0xd7,0x34,0x18,0xc8,0xd5,0xa4,0xd4,0x10,0xea,0x03,0xa6,0xe0,0x84,0x82,0xa0,0xaa, + 0xd2,0x44,0x43,0x76,0x43,0x69,0x2a,0xd6,0x66,0x57,0xab,0xa6,0xa6,0x0a,0xa1,0xdf, + 0xa8,0xa9,0x1a,0x90,0xbf,0x9a,0xcc,0x4a,0x90,0x4a,0xb2,0x52,0x89,0x54,0xbe,0xf0, + 0x8e,0xd4,0xc3,0x31,0x7d,0x25,0x45,0xe9,0xa7,0x7e,0xa3,0xa0,0x98,0x62,0x90,0xd4, + 0x6c,0x4a,0x13,0x41,0xfa,0xef,0xea,0x39,0x0f,0x60,0xf3,0xcd,0x9d,0x09,0xa1,0xd0, + 0x9d,0x75,0xb7,0xc6,0xad,0x8d,0x1b,0xb8,0x9a,0x5c,0xab,0xad,0x7e,0x8d,0xba,0x58, + 0x68,0xa0,0x9e,0xd1,0x17,0xdb,0xf3,0xb2,0xc6,0xf8,0x66,0x6b,0xab,0x39,0x2f,0x9c, + 0x03,0xd5,0x73,0x85,0x8c,0x76,0x6c,0x45,0xda,0xb8,0xd2,0xcf,0x20,0x6c,0xed,0xac, + 0xa1,0xc6,0xc0,0x9d,0xf6,0xd5,0xba,0x23,0x0a,0xfc,0x60,0x93,0xf1,0xa9,0xb5,0x4a, + 0x35,0x1b,0x4b,0x50,0xd2,0xea,0x2c,0x9c,0x29,0x09,0x4e,0x94,0x58,0x11,0x5c,0x87, + 0x75,0xcc,0x4f,0xa1,0x26,0x66,0x84,0xfa,0x42,0x05,0xb9,0x0e,0x92,0x68,0x0c,0x5f, + 0x07,0xc8,0x61,0x0e,0x47,0xd9,0x91,0x93,0x4a,0x8a,0x54,0x19,0x93,0x28,0x73,0x6d, + 0x5a,0x14,0x28,0x81,0xed,0x3f,0x86,0x45,0x62,0x81,0xd1,0x4d,0x06,0x43,0xad,0x87, + 0xf8,0xaf,0x50,0xc7,0xf4,0xf0,0xd4,0x86,0x14,0x2e,0x29,0xc8,0x95,0x36,0x70,0x9f, + 0xe2,0xa5,0x73,0x2d,0xd5,0x3e,0x1a,0xd9,0x1a,0x6e,0xc0,0xa1,0xff,0x55,0x9e,0x4f, + 0x63,0xc1,0xa1,0x75,0x04,0xe1,0x1a,0x76,0xb3,0x64,0x8a,0x8d,0x67,0x7b,0xdf,0x47, + 0xe8,0x71,0x6a,0x47,0x37,0xf6,0x3c,0x95,0x0a,0xf7,0xda,0x83,0x42,0xec,0x39,0x7c, + 0x28,0xc0,0x0a,0x36,0xa4,0xc1,0xfa,0x43,0x43,0xc8,0x61,0xc1,0x9f,0x76,0x6c,0xc8, + 0xa6,0xd4,0x6a,0x9e,0x59,0xc9,0x27,0x42,0xb8,0x34,0x31,0xd8,0x22,0x19,0x4e,0x8d, + 0x78,0xfd,0x7d,0x40,0xa2,0xc8,0xb7,0x94,0x9b,0x3b,0xcd,0xe8,0xe6,0xc4,0x8c,0x6e, + 0x60,0x12,0xc8,0xf0,0xbc,0x3f,0x2a,0x0a,0x06,0xe9,0xb4,0xdf,0xa8,0xe9,0x0c,0xf1, + 0x2a,0xe8,0xde,0x10,0xc7,0x5e,0x38,0x3e,0x9b,0x01,0x63,0xd9,0x1c,0x95,0x14,0x38, + 0xee,0xad,0xc7,0x90,0x4a,0x9b,0x50,0x63,0xe2,0xda,0xc4,0x4d,0x13,0x81,0xf5,0xb2, + 0xb9,0x4b,0x07,0xda,0x8d,0x7a,0xed,0x77,0x8a,0x8e,0xf3,0x6a,0x46,0x5c,0x5b,0x16, + 0x8c,0xdd,0xc1,0x6e,0xbe,0x3a,0x59,0x07,0xe7,0x5a,0x27,0xaa,0xe4,0x95,0x7b,0xad, + 0x94,0x81,0x27,0xed,0x5e,0xc7,0xea,0x75,0x05,0xfe,0x0d,0xab,0x05,0x87,0x7a,0xc1, + 0x61,0x4d,0x41,0x79,0x56,0x0e,0x28,0x33,0x7c,0x7c,0x74,0x1d,0x8a,0x47,0xeb,0x9d, + 0xe1,0xdd,0x2d,0x89,0x07,0xc5,0x49,0xcd,0x51,0xc1,0x9f,0x1b,0x6b,0xc9,0xe3,0xc3, + 0x93,0x40,0xfd,0x98,0x50,0x3a,0x74,0x44,0xe3,0x87,0x01,0x66,0xe9,0x71,0x36,0x3e, + 0x04,0x67,0x10,0x6d,0x6d,0xd1,0x8f,0xc3,0x26,0x06,0x16,0x7a,0xc5,0xeb,0x51,0x9c, + 0x43,0x01,0xb9,0xfc,0x03,0x05,0x31,0x2e,0xa6,0x97,0xa3,0xf3,0xe6,0x5f,0x2d,0x72, + 0x9a,0xe1,0xba,0x85,0x4a,0x14,0x5a,0x2e,0xcc,0x00,0x67,0x14,0xa7,0x0f,0x28,0xf6, + 0x6d,0x6d,0x7d,0xa5,0x95,0x52,0x2a,0xfb,0x0f,0x42,0x16,0xcc,0x22,0xf6,0x5d,0xb4, + 0x94,0x4e,0x12,0x87,0xc8,0x3e,0xfa,0xca,0xcd,0xbd,0x2f,0x6a,0xc0,0x44,0x76,0xdb, + 0xcf,0x8f,0x19,0xc8,0xa1,0xa5,0xe4,0xcc,0xd2,0xd0,0x5c,0x18,0x84,0x6d,0x01,0xbb, + 0xea,0x57,0x0e,0x10,0xe2,0x28,0x08,0x3e,0x79,0x29,0xba,0xcb,0x8c,0x86,0x76,0x1b, + 0xfe,0x87,0x15,0xd8,0xd4,0x88,0x2d,0x06,0x83,0x8e,0x22,0xcf,0x78,0x4e,0x0d,0x8a, + 0x9e,0x53,0x75,0x1d,0x63,0xc5,0x2b,0x89,0x82,0xd6,0x68,0x48,0xea,0x73,0x5b,0x98, + 0x5c,0xc9,0x91,0x53,0x8d,0x5a,0xa8,0x86,0xf6,0xe3,0xa3,0xfe,0xde,0xd9,0x43,0x25, + 0xc6,0xda,0xea,0xb9,0x0a,0x98,0x09,0x56,0x77,0x3c,0x6f,0xd7,0x50,0xda,0xdd,0xa0, + 0x19,0x2e,0xae,0xd1,0x20,0x8e,0x65,0xa3,0x86,0xfa,0xf8,0x68,0x26,0x1e,0xdf,0xbb, + 0x63,0xaa,0x9d,0xb6,0x76,0x58,0xb4,0x43,0xf1,0x74,0x37,0xf5,0xe2,0x14,0x90,0x2f, + 0xaf,0x63,0x87,0x7b,0x7c,0x62,0xf6,0x80,0x98,0xd0,0x23,0x5a,0x2d,0x29,0xad,0x9f, + 0xa8,0xbe,0x00,0x98,0x57,0x12,0xfc,0x8c,0x12,0x03,0x46,0x8a,0xcd,0x66,0x53,0x41, + 0xfb,0x79,0x48,0xae,0x1d,0x92,0x79,0x1a,0xb2,0xdf,0x2f,0xb3,0x12,0x68,0xbb,0x33, + 0xf4,0x28,0x52,0xb4,0x30,0x02,0x12,0x7e,0x71,0x1c,0xed,0x25,0x78,0x30,0x0b,0x23, + 0xaa,0xf6,0x94,0xc1,0x5c,0xec,0x6a,0x59,0x65,0xa1,0xa2,0x1a,0x0a,0x8e,0x09,0x16, + 0xb0,0xd8,0x4a,0x06,0x95,0x75,0x2e,0x49,0x61,0x75,0xa5,0xeb,0x5f,0xea,0xd6,0x7a, + 0xae,0x31,0x21,0xc2,0x77,0x37,0x7e,0x93,0x24,0x03,0x77,0x3c,0xf7,0xc3,0x73,0x7a, + 0x06,0xb4,0xd0,0x5a,0x66,0xa6,0x82,0x73,0x11,0x7e,0xd6,0xfb,0xa0,0xf3,0x89,0x27, + 0x99,0x06,0x22,0xc3,0x80,0x5b,0x0e,0xc3,0x51,0x94,0xd4,0x81,0xa3,0x13,0xfe,0x72, + 0xe4,0x0d,0x1d,0x6c,0xb0,0xdf,0xa4,0x36,0x5e,0x5c,0x9d,0xda,0x2e,0x59,0x1b,0x0a, + 0xe8,0x91,0x7f,0x5c,0x46,0x46,0x78,0x98,0x65,0x80,0xff,0xa0,0xe5,0x27,0x65,0x1d, + 0xd0,0xbf,0x64,0x72,0x9b,0x1f,0x69,0xb8,0x3e,0x1e,0x35,0x7e,0x11,0x46,0x50,0x8b, + 0x05,0x8c,0x70,0xd9,0x7e,0x19,0x67,0x68,0x6c,0xe3,0xf8,0xd9,0xe1,0x5c,0xdc,0xa9, + 0x66,0xdc,0xb9,0xa9,0x01,0x5b,0x77,0x46,0x88,0xc1,0x6a,0xd5,0x08,0xe3,0xf4,0xf8, + 0x93,0x07,0xd8,0x3b,0x69,0x51,0x28,0x8f,0x4a,0xe2,0x1d,0xf4,0xeb,0x07,0x84,0x15, + 0x59,0x82,0xe6,0x33,0x8d,0xb2,0xe1,0xd4,0x6e,0x42,0x20,0x39,0xe1,0xd5,0x00,0x8b, + 0x28,0xc4,0x6b,0xd7,0x7e,0xfe,0xf4,0x16,0x77,0x1a,0xd8,0x90,0x60,0x07,0xe7,0x05, + 0x62,0x2f,0x45,0x0c,0x99,0x1e,0x10,0x97,0xf6,0xd3,0xca,0x70,0x31,0x94,0xfb,0x2b, + 0xb5,0xac,0x18,0x3c,0x3a,0x99,0x62,0x57,0x3a,0x22,0x7b,0xb8,0x7d,0xa3,0xfb,0x0b, + 0x6d,0x5a,0x35,0x71,0x6c,0xca,0x98,0xce,0xf3,0xa5,0xaf,0x4b,0x35,0x5d,0x4f,0xf6, + 0x3e,0x5a,0xa5,0x56,0xdb,0x41,0xa1,0x62,0x4c,0xf2,0x15,0x75,0x90,0xaa,0x78,0xbd, + 0xbf,0x59,0x8b,0x39,0x92,0xec,0x74,0x56,0xa0,0xc9,0x93,0xfd,0x52,0x6f,0xb7,0x30, + 0x5c,0x44,0xbf,0x67,0xf0,0x82,0x42,0x80,0x40,0x99,0x74,0xd0,0xb6,0x09,0xcd,0x39, + 0xe2,0x9b,0xfc,0x4c,0xf0,0xc4,0xde,0xb0,0x03,0x59,0x8d,0x4f,0xab,0x3c,0x35,0x8c, + 0x6e,0x06,0xbb,0xff,0xfc,0xf8,0xd3,0xae,0xcf,0xec,0x85,0x9f,0x51,0x34,0x2a,0x61, + 0xda,0xf3,0x55,0x74,0x63,0x51,0x2b,0x3b,0x3b,0xfc,0x3e,0x1a,0x6e,0x6d,0x61,0x84, + 0x1c,0x35,0x0e,0x10,0x4d,0x7c,0xda,0x86,0x69,0x15,0xab,0xd1,0x41,0x0e,0xc9,0x43, + 0xf0,0x67,0x64,0x54,0xd4,0x67,0x99,0x66,0x95,0xcd,0x92,0x44,0x3a,0xb5,0xc5,0xcf, + 0x38,0xdb,0xbc,0x8c,0x79,0x1a,0x76,0x79,0x4b,0xaf,0x74,0xd7,0xd2,0x81,0xc0,0xfb, + 0xf1,0x93,0x14,0xad,0x56,0xc4,0x21,0xdb,0x66,0x93,0x04,0x43,0x53,0x62,0x72,0x9b, + 0x42,0x7f,0x20,0xac,0xa1,0x8a,0x9c,0x31,0xf2,0x9d,0x1f,0x7f,0x32,0x7b,0xb2,0xe1, + 0x3c,0x76,0xd7,0x3f,0x81,0xa2,0x34,0xa3,0xc4,0x3a,0xb9,0xea,0xd9,0xd7,0x27,0xbf, + 0xa5,0xdf,0xec,0xfa,0x36,0xef,0x29,0x4f,0xd2,0x50,0x94,0x02,0x32,0xdc,0xb9,0x49, + 0xb8,0xce,0x48,0x58,0x1b,0x88,0x25,0xd7,0x3f,0xb0,0xf6,0xe8,0xff,0xa5,0x21,0x29, + 0xcd,0x8a,0xc5,0x34,0x80,0x67,0xc8,0x44,0x86,0x29,0xe3,0x88,0x62,0x6a,0xa7,0x83, + 0x65,0x9d,0x7a,0xb0,0xc6,0x49,0xa0,0x33,0xb5,0x23,0xde,0x44,0xf1,0x46,0x8d,0x82, + 0x65,0x23,0x4a,0xb4,0x22,0x94,0x7d,0xc2,0x71,0x11,0xfc,0x18,0xcd,0x50,0x2f,0xe5, + 0x55,0x23,0x78,0x40,0xe6,0x8d,0x8b,0x16,0xa2,0x18,0xf7,0x02,0x6f,0x39,0x90,0xb7, + 0x94,0x20,0xe1,0x10,0x61,0xfe,0xf0,0xec,0xe5,0xc1,0xb8,0x65,0x4b,0x0d,0xe3,0x0e, + 0x58,0x6e,0x0a,0x0c,0xc9,0x8d,0xa7,0x8e,0xf1,0xc9,0x13,0x04,0x87,0xa3,0x60,0xc4, + 0x68,0x2f,0x83,0x71,0x36,0x03,0x37,0xce,0xa2,0x98,0x4f,0x7c,0xdc,0x4c,0x06,0xd5, + 0xb0,0xb1,0x5d,0x71,0x6f,0x05,0xdd,0x7e,0xc6,0x8d,0xb0,0x55,0xab,0xea,0x22,0x59, + 0xb4,0x52,0x68,0x4a,0xdc,0x1a,0xe9,0xfa,0x54,0xea,0x2e,0xd2,0x48,0x8e,0xd1,0x21, + 0x20,0x55,0x68,0xbf,0xd4,0x14,0x0d,0x42,0x35,0x44,0xf5,0xc2,0x47,0x74,0x11,0xe5, + 0x9b,0x1c,0x5a,0x30,0x7d,0xfe,0x94,0xec,0x6b,0x65,0x27,0xec,0x06,0xef,0xa7,0xe6, + 0x85,0xa8,0x5e,0x34,0x79,0xf5,0xf1,0xa7,0x6b,0x22,0xc0,0x22,0x26,0xa3,0x69,0x2b, + 0xd0,0xda,0x9c,0x78,0x81,0xbd,0x18,0xa3,0x37,0x83,0xbe,0x27,0xe9,0x1b,0xff,0x85, + 0xaa,0xc9,0x14,0x96,0x8c,0x6c,0x9f,0x72,0x11,0x4d,0x32,0xb6,0x0a,0xfc,0x02,0x76, + 0xb1,0x4a,0x5b,0xd7,0xb1,0x80,0xed,0xfd,0xda,0x12,0x40,0xe2,0x5e,0x77,0xdb,0x9b, + 0xd3,0x43,0xa0,0x84,0xeb,0xb6,0xcd,0x7a,0x7a,0x58,0x66,0x46,0xca,0x03,0x5f,0x0a, + 0x77,0x79,0x3c,0x44,0x30,0xd8,0x53,0x4d,0xde,0xd7,0x7c,0x27,0xc2,0xbe,0x82,0xe8, + 0x3a,0x1c,0x7a,0x74,0xaa,0xc7,0x24,0x91,0x64,0xdd,0xb4,0xf1,0x65,0x96,0xc0,0x7f, + 0xda,0x62,0x97,0x42,0xc0,0x8d,0x57,0x98,0xed,0xf2,0x47,0x16,0xa5,0x8a,0x27,0x47, + 0x1a,0x01,0xbd,0xb9,0x26,0x2b,0x35,0xcc,0x49,0xd0,0x66,0x33,0x5f,0xed,0x73,0xc9, + 0xf2,0x95,0x42,0x13,0x48,0xb3,0x57,0x0e,0xc9,0x50,0x35,0xff,0xec,0x6b,0x15,0x51, + 0xcd,0xeb,0xad,0x67,0x55,0x1c,0xa2,0xa6,0x76,0x31,0x8d,0xde,0x5f,0xeb,0x4f,0x99, + 0xff,0x72,0x80,0x4c,0x6c,0xff,0x13,0x19,0xe0,0x5e,0x09,0xcb,0x5c,0xb2,0xf3,0xb6, + 0xe5,0xcb,0xf0,0x4e,0x3d,0xa6,0x13,0xf5,0x38,0x4a,0xae,0x75,0x23,0x8c,0xa2,0x25, + 0xaf,0x56,0xa9,0x38,0xd6,0xf2,0xbc,0x98,0xdb,0xa8,0x35,0x84,0x03,0x81,0x51,0x5a, + 0xd6,0xc9,0x34,0xe1,0xd5,0xad,0xd5,0x24,0x40,0xa0,0xaa,0x2a,0x6f,0x5f,0x5c,0x82, + 0xdb,0xa3,0xc7,0x73,0xd2,0x1f,0x35,0x55,0x81,0x93,0x62,0xce,0x9e,0x5e,0xb7,0x66, + 0xe5,0xb3,0xa1,0x59,0x34,0x1f,0x16,0x8f,0xef,0x07,0x4b,0x84,0x56,0xaf,0x6d,0x0f, + 0xef,0x7a,0x1d,0x3b,0x9d,0xf4,0xba,0xf6,0x28,0xe9,0xed,0x3d,0x95,0xec,0xa3,0x91, + 0xf6,0x0b,0xe0,0xe7,0x9d,0xbb,0x82,0xf2,0xd7,0xfd,0xb5,0x06,0xbf,0x6a,0xb4,0x42, + 0x63,0xf4,0xdf,0x69,0x0c,0xbd,0xce,0xc2,0xb8,0xd6,0xfd,0xbf,0xe8,0x1a,0xa8,0x82, + 0x23,0x2c,0x1b,0x2a,0x08,0x06,0x19,0x25,0xea,0x14,0xb5,0x59,0x47,0x49,0xeb,0x23, + 0x96,0x08,0xda,0xfc,0x3d,0x73,0xd0,0x59,0x44,0xe4,0xc9,0x90,0xe4,0xa4,0xae,0xf5, + 0x33,0x0e,0x10,0x83,0x3d,0xc8,0x7b,0xd3,0x6f,0x3c,0x13,0xc6,0x2b,0x17,0x5f,0x98, + 0x2f,0xc4,0xac,0xb5,0x51,0x3a,0xbe,0x44,0x2f,0xda,0x94,0x36,0x1e,0xac,0xcf,0xcb, + 0xb5,0x79,0x5f,0xcb,0x26,0x0c,0x99,0xa1,0x8a,0x7f,0xf7,0xd6,0xf2,0xbe,0x06,0x67, + 0x20,0xb3,0x7d,0x0f,0x7b,0xc6,0x90,0x06,0x7f,0x25,0xcd,0x67,0xf9,0x44,0xd9,0x26, + 0x91,0x10,0x7e,0xf8,0x36,0x1a,0x9b,0x47,0x57,0xad,0x3b,0x63,0xa1,0x28,0x6b,0x99, + 0x3b,0xd9,0x6a,0x3e,0x29,0x83,0x69,0xc8,0x35,0xb3,0x99,0xf4,0xdd,0xd1,0x92,0x28, + 0x8e,0x0d,0x35,0x65,0x71,0xb0,0x7a,0x7c,0x6e,0x0a,0xe9,0x09,0x96,0x5e,0x2c,0x13, + 0x56,0xc6,0x67,0x91,0x2d,0xca,0xf8,0x2c,0x76,0xa9,0x76,0x8e,0xd9,0x52,0xd3,0x2c, + 0x7d,0xe0,0x09,0x0f,0xfc,0x66,0x59,0xd7,0x3a,0x99,0x67,0x3f,0xc7,0x18,0xd0,0x8a, + 0xce,0x8d,0xf4,0x90,0x86,0xe9,0xee,0xd1,0x21,0x8a,0x23,0xf6,0xac,0x90,0xfa,0x6f, + 0x94,0xba,0xbb,0x87,0xe1,0x64,0xed,0x79,0xf1,0x13,0x26,0xee,0x1e,0xb6,0x73,0xe3, + 0xb4,0xf1,0x71,0xfb,0x64,0xbc,0x63,0x8e,0x0d,0x73,0x67,0xb6,0x63,0xce,0xcc,0x5e, + 0x73,0x06,0x29,0xf8,0x08,0x29,0xf3,0x1d,0x73,0x6e,0xf6,0xe8,0xdf,0x42,0xd4,0x5c, + 0x40,0xe0,0xa6,0x6f,0x0f,0x6d,0x15,0x9d,0x76,0xbb,0x7c,0x29,0x0f,0xda,0x5f,0x1d, + 0x8b,0xd3,0x61,0x1f,0x8f,0x8b,0xb7,0x77,0x86,0x7c,0x52,0xbc,0xbd,0xd3,0x4c,0x4f, + 0xb6,0x8d,0xd7,0x29,0x3c,0xf1,0x01,0x6f,0xc9,0x30,0x4c,0x57,0xaf,0x6a,0x13,0xb1, + 0xd4,0xe7,0x00,0xf9,0x05,0xf9,0x9c,0xb2,0x13,0x39,0x07,0x24,0xc6,0xb0,0xbb,0x6f, + 0x85,0xfb,0x73,0x53,0xe5,0xb2,0xf7,0xda,0xc5,0xd0,0xba,0x5a,0x5d,0x4b,0xf6,0xce, + 0xc9,0xab,0x00,0xf6,0x19,0xed,0x7a,0x54,0x2d,0xc5,0x8f,0xa5,0xe6,0xda,0x4f,0x25, + 0xd1,0x5f,0xd6,0x5a,0x0a,0x51,0x56,0x1f,0xa1,0x8c,0x82,0x4c,0xd5,0x88,0xa9,0x1c, + 0xa2,0x4e,0xde,0xa3,0x54,0x09,0x94,0x12,0x88,0x1b,0xbf,0x1c,0xc7,0x31,0x8b,0xba, + 0xa2,0x55,0x65,0xc4,0xd9,0xc2,0xcd,0x70,0xa0,0x39,0x34,0xa4,0x0e,0x46,0x6d,0xfe, + 0x0c,0xd4,0xd5,0xdb,0xc5,0x7b,0xbd,0x64,0x80,0x3d,0xba,0x48,0x49,0x8f,0xeb,0xd6, + 0xa0,0x09,0x37,0x7f,0x8e,0x51,0x34,0x07,0x7a,0xc1,0x08,0xe9,0x2c,0x62,0x0e,0x24, + 0x66,0x59,0x3b,0x22,0xc7,0xb7,0x7c,0xd3,0x96,0x69,0xc3,0x57,0xbc,0x75,0xeb,0xf3, + 0xfc,0x76,0x17,0xdd,0x26,0xa0,0x37,0xd1,0xf7,0xfe,0xbd,0x37,0x6e,0x76,0x2d,0xdb, + 0xfc,0x87,0xa9,0x0a,0xa8,0x8b,0x98,0x60,0xe7,0x18,0xda,0xe6,0x4f,0xdf,0x1a,0xdf, + 0xe0,0x4d,0x6b,0x80,0x7a,0xd5,0x7e,0x42,0x3a,0x77,0x53,0x95,0x7e,0xef,0xde,0xe3, + 0x75,0xd2,0xd1,0xc8,0xb4,0x6b,0xb2,0x63,0x1c,0x09,0xfc,0xc8,0x85,0xb0,0xf2,0xbc, + 0x5d,0xed,0xee,0x26,0xd3,0x4e,0x1d,0x8a,0x5a,0x6d,0x9b,0xe3,0x6f,0xe7,0x79,0x96, + 0x77,0x40,0xac,0x8d,0x4f,0x17,0x17,0x6f,0x31,0x43,0x02,0xdc,0x3b,0x7d,0x87,0xfe, + 0x5d,0x7c,0xf8,0x44,0x81,0xc5,0xd2,0x30,0x51,0x99,0x4f,0x61,0xf7,0xc3,0x5b,0x51, + 0x2f,0x7f,0xcd,0xc1,0xe3,0x72,0x9a,0x0e,0x1f,0x99,0xed,0x93,0x96,0x2d,0x81,0x6e, + 0x56,0x73,0x9e,0x8b,0x8b,0x77,0x31,0x27,0xe4,0xf1,0x46,0xb7,0x36,0x9e,0x5d,0x50, + 0xc3,0x50,0x02,0x1e,0x2b,0x59,0x2f,0x29,0x6b,0x0a,0xf3,0x9d,0x83,0x17,0x83,0x4e, + 0x40,0x1d,0xbb,0x97,0xaa,0x9a,0xcf,0x14,0x88,0x02,0xc4,0xbf,0x5d,0x1e,0x04,0x64, + 0xe7,0x24,0x55,0xe8,0x3b,0x1f,0xed,0x3d,0x4b,0xa5,0xc6,0x94,0x58,0x2c,0xc6,0x69, + 0xaa,0xdc,0xe5,0xaf,0x06,0x48,0xcc,0x0b,0x0f,0xcb,0x64,0xf7,0x9f,0xe9,0x19,0x3e, + 0x6a,0xae,0x6f,0x27,0x62,0xda,0xf0,0x02,0x2b,0x95,0x15,0x89,0xbd,0xc8,0x4c,0x01, + 0x55,0x45,0x6d,0x24,0x78,0x49,0xf0,0x93,0xf8,0xa3,0xe6,0x20,0xcf,0xf4,0xf6,0x1c, + 0xbf,0xfa,0xf1,0xe3,0xa3,0xd9,0x42,0xd2,0x4a,0x96,0xb7,0xd8,0x1e,0x92,0x63,0xc4, + 0x02,0xc0,0x2a,0x20,0x16,0x7a,0x2a,0x4f,0xb5,0x98,0x72,0x64,0x04,0xf1,0x8e,0x2e, + 0xe2,0x28,0xb4,0x5b,0xbf,0x2c,0x5b,0xaf,0x04,0xd6,0x7c,0x29,0x13,0x5f,0xe9,0x95, + 0xe7,0x92,0x95,0x95,0x1c,0xfd,0x98,0x61,0x0d,0x06,0x69,0x1e,0x9c,0xa7,0xaf,0xd6, + 0xa9,0x64,0x5f,0xb4,0x75,0x96,0x06,0xe2,0x50,0xe2,0x24,0x0d,0x8a,0x96,0xae,0xf7, + 0x32,0x0c,0xf7,0xa0,0x79,0x4f,0x66,0x56,0x6c,0x4e,0x6e,0xa1,0x3d,0x79,0x81,0xf6, + 0xde,0xdc,0x12,0xe5,0x65,0xa2,0x5b,0x08,0x88,0x2f,0xc2,0xd7,0xc3,0xce,0x50,0x73, + 0x19,0x86,0x38,0x1d,0x37,0xb6,0x1b,0x64,0x67,0x24,0xdb,0x60,0x8b,0x38,0xbc,0x78, + 0xaf,0x6c,0x17,0x67,0x15,0x0c,0xe3,0x38,0xbf,0x65,0x15,0x6c,0x81,0xc4,0x81,0x1d, + 0x86,0xc7,0x4f,0xb1,0xdb,0xd1,0x0d,0x77,0xfa,0xf1,0xf1,0x1e,0xe3,0x48,0x69,0x23, + 0x40,0xdf,0x62,0xfc,0x0e,0xe8,0x15,0xdd,0x10,0x86,0x51,0x0e,0x78,0xc5,0xe3,0xba, + 0x5a,0xdb,0x5a,0x31,0x4e,0x61,0x84,0x74,0xef,0x84,0x22,0xde,0x1f,0xf7,0x5e,0x59, + 0x49,0xd1,0xd6,0x53,0xb4,0x2f,0xc5,0x2b,0x51,0xb7,0x45,0x3e,0x22,0xbd,0x9a,0x7d, + 0x55,0x9e,0x22,0xec,0x4f,0xb7,0x77,0xb8,0xff,0x85,0x81,0xed,0x4c,0x0a,0xb6,0xbf, + 0x3d,0xa0,0x26,0xf2,0x3e,0x36,0x15,0xbf,0x53,0x3a,0xbb,0x6e,0xc0,0x67,0x12,0x7a, + 0xba,0x18,0x23,0xc2,0x65,0xd3,0xf1,0x5b,0x62,0xb1,0x5c,0x81,0x0b,0xc7,0xb0,0x5b, + 0xbb,0x4e,0x3a,0xf3,0x51,0x80,0xd5,0xb7,0x30,0xc2,0x49,0xa0,0x0b,0xc8,0x4a,0x08, + 0xf4,0x18,0xc7,0xc9,0x40,0x44,0x54,0x66,0x0b,0x9f,0x73,0x20,0xba,0xc1,0x27,0x54, + 0xee,0x3e,0x3e,0x76,0x30,0xba,0xd4,0x2d,0x32,0x87,0xb0,0x78,0x7f,0x41,0xd7,0x5c, + 0xe0,0x1b,0x0e,0x0e,0xfb,0x0d,0x48,0x24,0x4f,0xdd,0xc1,0xdd,0x37,0x50,0x41,0x1f, + 0x5e,0xc5,0x5d,0x75,0x33,0x7a,0xa7,0x9a,0xa7,0x58,0x74,0xea,0xf1,0x8e,0x02,0x33, + 0x6e,0x76,0xf1,0x68,0x65,0xea,0xa4,0x78,0x5a,0xd8,0x84,0x6c,0x36,0xfc,0x61,0x02, + 0xed,0x9d,0x9f,0x80,0x2e,0x34,0xf1,0xc4,0xe0,0xce,0x9e,0xf1,0xb2,0xc0,0x4e,0x8a, + 0x01,0xbd,0xee,0x16,0x8d,0x4c,0x43,0xde,0x93,0x80,0xbc,0x3b,0x14,0xef,0x90,0x75, + 0xd7,0x34,0x2a,0x7b,0x7e,0x2f,0x3e,0x62,0xd8,0xa0,0xd2,0x47,0x36,0xdb,0x47,0xfe, + 0x71,0x1e,0x5a,0xcb,0xf9,0xfd,0x0e,0x88,0x18,0xf3,0xb0,0x35,0xe8,0x3c,0x35,0xa6, + 0x18,0xb2,0x2d,0xba,0xf1,0x2e,0x08,0xff,0xa9,0xdb,0xf3,0x78,0x91,0x79,0x63,0x4a, + 0xc8,0x6f,0x07,0x90,0x0f,0xe2,0x10,0xd9,0xc2,0x11,0x9e,0x27,0x51,0xec,0x81,0x2c, + 0xc3,0xd1,0x35,0xcc,0x56,0xcb,0x1d,0x8d,0x4c,0xe9,0xaf,0x01,0x84,0xe6,0x45,0x77, + 0xf8,0x72,0xec,0xbd,0x82,0xd9,0x9d,0x3a,0x78,0xdd,0x0d,0x41,0x72,0xd0,0xed,0xf3, + 0xdb,0xbf,0x47,0x78,0x4f,0x28,0x6d,0x44,0x26,0x24,0x0d,0xbd,0xa9,0x1f,0x9e,0xc3, + 0x08,0x88,0x6f,0x44,0x18,0x54,0xf8,0xd7,0x5b,0x5b,0xda,0xba,0xdf,0x0f,0xfc,0x5d, + 0x1d,0x50,0xad,0x8e,0xf5,0x4d,0xf3,0xae,0xb5,0x6f,0xed,0x74,0xed,0x87,0xc1,0xac, + 0xb5,0xdf,0x6a,0xde,0xb6,0x60,0xac,0xbb,0x30,0x6a,0xfc,0xfd,0xa6,0x09,0x59,0x90, + 0x95,0xf3,0x4f,0xb8,0xf1,0xcb,0xa8,0x79,0x6f,0x3f,0x58,0xbd,0xa9,0x83,0xe2,0xb8, + 0x78,0x63,0x6e,0x52,0x42,0xa4,0x49,0xcf,0x78,0x2f,0xa8,0x80,0x8d,0x0e,0x29,0xe8, + 0x30,0x92,0x0a,0xbc,0xe5,0x33,0xbe,0x37,0xd2,0x07,0x90,0x13,0xe6,0xad,0x85,0x8f, + 0x03,0xc1,0x49,0x3f,0xc5,0xcb,0x56,0x60,0x70,0x88,0x1b,0xa6,0xac,0x86,0xd6,0x3f, + 0x76,0xfa,0xaa,0xd0,0xf3,0x6b,0xfb,0xae,0xd5,0x65,0x37,0x11,0x0d,0x67,0xd1,0xcf, + 0xed,0x27,0xef,0x81,0x42,0x72,0x36,0x59,0xbe,0xc8,0x4d,0x5a,0xf8,0x7d,0x6b,0x6b, + 0xd5,0x05,0x2d,0x22,0x7f,0x5f,0x79,0x9d,0x0e,0x83,0x45,0x22,0xed,0x02,0x5c,0x2f, + 0xd7,0xdb,0x72,0xc4,0x53,0x51,0x94,0xb0,0xc4,0xf5,0xb6,0xb6,0x5c,0x94,0xc4,0x0a, + 0xac,0x3b,0xa6,0x51,0x25,0x96,0xf8,0x2d,0x9d,0xe4,0xa8,0x7b,0x7b,0x55,0x4f,0x91, + 0xf7,0x53,0xd7,0x5a,0x0c,0xa4,0xc3,0x66,0x59,0x6f,0x5c,0xdf,0x6f,0x9b,0xae,0xe8, + 0x22,0x8f,0x40,0xed,0xc6,0x2e,0x19,0x9e,0x7b,0xe0,0x05,0x5b,0x5b,0x15,0xcb,0x09, + 0x52,0xdd,0x6e,0x6d,0x4d,0x1c,0x3c,0x8c,0x0f,0xb3,0x0f,0xd1,0xd8,0xb3,0xf4,0x17, + 0xd8,0x3b,0x80,0xf0,0x64,0xdf,0x7a,0x80,0x55,0x5e,0x93,0x6a,0xb4,0xd1,0xda,0xeb, + 0x3e,0xbb,0xf0,0x87,0x80,0x11,0x53,0x32,0xea,0x08,0x6b,0x75,0x35,0x2a,0xda,0x64, + 0xcd,0x9c,0xac,0x0a,0xf8,0x5f,0x97,0xf7,0xc9,0xee,0x1c,0xb4,0x49,0xa3,0x22,0x6f, + 0xf8,0xe2,0x83,0x48,0x3d,0x94,0x5e,0x7e,0x09,0xd7,0xb2,0x3c,0xfe,0x15,0xa1,0x4f, + 0x0b,0xb7,0x6a,0x48,0xb0,0x13,0x03,0x5e,0x11,0x0f,0xa8,0xc9,0x28,0x19,0x79,0xf2, + 0xe8,0x59,0xdd,0xe3,0xa5,0xef,0xad,0xdb,0x7f,0xe7,0x9d,0x5e,0xdb,0x7d,0x3a,0x1d, + 0xcd,0x9b,0x3e,0x11,0x9c,0x3e,0x24,0x9c,0x24,0x74,0xb3,0xd9,0xa0,0x03,0xfb,0x9a, + 0x4a,0x2c,0xf9,0xfd,0x0c,0xdd,0x24,0x6d,0x22,0x3f,0xc3,0x42,0x5d,0x38,0xc0,0xe7, + 0xe3,0xd6,0xc1,0xc1,0xc9,0x7e,0x8f,0x1f,0x0f,0x5f,0x9e,0xec,0x89,0xc7,0x97,0x47, + 0x27,0xdd,0x5e,0x87,0xdc,0xed,0xa3,0x3a,0x1b,0xe5,0x7d,0xd2,0xa5,0x44,0x68,0xcd, + 0xab,0x5f,0x80,0x35,0xf6,0xd3,0x38,0x70,0x1f,0x7a,0x7e,0x48,0x97,0x72,0x0d,0xf1, + 0x22,0xa5,0xbe,0xb8,0x38,0x28,0xbe,0x97,0x97,0x25,0x25,0x7c,0x55,0x17,0x24,0x0c, + 0xa3,0x64,0xec,0x25,0x14,0x06,0x7a,0x91,0x52,0x8a,0xb8,0x5a,0x08,0x04,0xb6,0xbd, + 0x1d,0xff,0x9b,0x3d,0xd8,0x15,0x31,0x1b,0x70,0x9b,0x53,0xa2,0x6f,0xf8,0x01,0x9a, + 0x0f,0x4f,0x4c,0xe6,0x24,0x80,0x4e,0x02,0x57,0x20,0x5e,0xb0,0x4d,0xcb,0xa4,0xad, + 0x55,0x6e,0xa5,0xf9,0x3e,0xbe,0xa6,0x9b,0x78,0x1d,0x5d,0x9f,0x66,0xa6,0xe5,0x03, + 0xf5,0x49,0x7b,0x98,0xd0,0x02,0xc1,0x48,0xf6,0x06,0xaf,0x19,0x23,0xf3,0xe0,0x1d, + 0x53,0x54,0x6c,0x96,0x25,0x30,0x9c,0x95,0x45,0x12,0x08,0x19,0x0c,0x9f,0xd6,0xdd, + 0x39,0xc1,0x01,0x6c,0xf1,0xe2,0x64,0x71,0x44,0xa8,0x21,0xdb,0x60,0xb5,0xb6,0x9a, + 0x5a,0xd1,0x27,0x98,0xd6,0x41,0xbb,0x68,0x23,0x12,0x62,0xe4,0x5c,0x68,0x47,0xde, + 0xbc,0x27,0x4e,0xd7,0x88,0x71,0xca,0x2b,0x0c,0x55,0x84,0xd0,0x90,0x0e,0xc7,0x91, + 0x5e,0x63,0xc9,0x3a,0x0b,0x21,0x91,0x71,0x48,0x12,0x49,0xcb,0xa5,0x1f,0xa5,0x1a, + 0xf5,0xbc,0x10,0x4f,0x65,0xa8,0x55,0xaa,0xa0,0xa6,0x25,0x64,0x51,0x21,0xdf,0x15, + 0x37,0x75,0x6d,0xe9,0x57,0x5a,0xf5,0xf5,0x2f,0x80,0x5c,0xe2,0x1b,0x9e,0x8f,0xc9, + 0x43,0xa9,0xfa,0xc5,0x45,0x8d,0x09,0xd6,0x95,0x9e,0x0b,0xcc,0x6b,0xa8,0xb9,0x69, + 0xad,0xf3,0x1a,0x82,0x92,0xd2,0xfe,0x3c,0xc5,0x43,0x62,0xe6,0xc9,0xb8,0x3b,0x96, + 0x72,0x5e,0x13,0x76,0x00,0xf9,0x67,0x15,0x99,0xce,0x34,0x05,0x2b,0x47,0xcb,0x2b, + 0x24,0xd8,0x58,0x65,0xff,0xa2,0x34,0x95,0xcc,0x9e,0xac,0x58,0xe1,0xd1,0x0e,0x24, + 0x79,0xe1,0xe8,0xc4,0xdc,0x7a,0xd1,0xe9,0x1e,0x75,0x5f,0xee,0xf7,0xf9,0x8a,0x07, + 0xf3,0x75,0x3a,0x07,0x49,0xf2,0x78,0x34,0x13,0x0c,0xa6,0xde,0xe6,0x09,0x66,0xc8, + 0x23,0x9e,0x9b,0x3b,0xdc,0x2e,0xd5,0x4a,0xa5,0x94,0xab,0x93,0x59,0xe4,0x1a,0xb7, + 0xf3,0xdb,0xa7,0x2a,0xb7,0x69,0x15,0x6f,0xce,0x05,0xf6,0x52,0x22,0x90,0x31,0xc1, + 0x95,0xe7,0xe0,0x65,0x53,0xdb,0xf5,0x4a,0xcc,0x75,0x14,0x70,0xd3,0x06,0x11,0xb7, + 0xc5,0x41,0x3f,0x37,0xf5,0xa4,0x74,0x89,0x7a,0xd5,0x7f,0x55,0xa1,0x88,0xcb,0xa2, + 0xa2,0x4e,0x7c,0x66,0x33,0x2d,0xec,0xc0,0x96,0xa6,0xa4,0xce,0x55,0x6a,0x14,0x1f, + 0x11,0x3f,0x20,0x69,0x41,0xf0,0x50,0x27,0x9b,0x74,0x1d,0x0b,0x3d,0xc9,0x40,0x0c, + 0xcb,0xe1,0x62,0x38,0x0c,0xbc,0xb4,0xc7,0x08,0x2e,0x2d,0x0c,0x05,0x7e,0x89,0xd8, + 0x5c,0x79,0xbd,0xe2,0x03,0xef,0xca,0xea,0xf6,0x0b,0xba,0x71,0xde,0xda,0xda,0x12, + 0x5f,0x29,0x58,0x97,0xbc,0x68,0x7e,0xd0,0xd9,0xdb,0xda,0xd2,0xd4,0x6f,0xb2,0x06, + 0xa0,0x38,0xf2,0xb1,0x14,0xae,0xa1,0x64,0xeb,0x52,0x6f,0xbb,0x89,0x9e,0x5f,0xa3, + 0x59,0x29,0xc8,0x89,0xec,0x1c,0x7c,0xf8,0xd2,0x71,0x8b,0x53,0x33,0x6d,0x97,0xce, + 0xfd,0x7b,0x0a,0x71,0x06,0x06,0x57,0x8d,0x65,0xd6,0x33,0x7f,0xbe,0x38,0xdd,0x3d, + 0x73,0x43,0x77,0xec,0x1a,0x4d,0x3c,0x10,0x9d,0xc3,0xec,0x90,0x48,0x68,0x4f,0x7a, + 0xe6,0xab,0x4e,0xdb,0x39,0xe8,0x1e,0x98,0x78,0xbc,0x60,0x1e,0x76,0x1d,0x78,0x4a, + 0x21,0xf9,0xa5,0x89,0xa7,0x0c,0xe6,0x01,0x06,0x56,0xc6,0x3a,0x4e,0x17,0xc0,0x77, + 0x02,0x9d,0x77,0x45,0xa1,0x03,0xe7,0xa8,0xdd,0xe6,0x42,0xdd,0x83,0x36,0x97,0xe9, + 0xb4,0x57,0x15,0x32,0x9a,0x1f,0xdc,0x24,0x89,0xee,0x64,0x93,0x87,0xce,0xc1,0xcb, + 0x55,0x4d,0x1e,0xd5,0x94,0x7e,0xef,0xab,0xde,0x1e,0x38,0x6d,0x59,0xb4,0xd3,0x15, + 0x25,0x5f,0xad,0x6a,0xb7,0x67,0x5c,0x9c,0xda,0xc6,0x2f,0xa7,0x5c,0xb6,0xbb,0xe7, + 0x74,0xaa,0x23,0x3d,0x5a,0xd5,0x6c,0xcf,0xf8,0x8f,0x77,0xdf,0x6d,0x50,0x52,0x35, + 0xfb,0x6d,0xe2,0xfe,0xe1,0x07,0x5f,0xd2,0xd6,0x9b,0x9f,0x77,0x7f,0xfe,0xa9,0x08, + 0x9c,0xa3,0xc3,0x57,0xce,0x61,0xe7,0x68,0xc3,0x92,0xdf,0x79,0x31,0x46,0x77,0xca, + 0xe4,0x6c,0x62,0x69,0x35,0x9b,0xf9,0xc4,0x74,0x4a,0x3d,0x3d,0xfb,0xc3,0x03,0xe2, + 0xf8,0xc9,0x8b,0x17,0xc0,0x75,0x8e,0xaa,0x1d,0xd8,0xdf,0xeb,0x3e,0x87,0x10,0x6f, + 0x7e,0x36,0xf6,0xf7,0xf6,0xde,0xff,0xf8,0x87,0xd1,0x7c,0x17,0x85,0x53,0xe3,0x13, + 0xda,0x56,0x71,0x0d,0x90,0xee,0xe0,0xad,0x7b,0xcf,0x74,0x42,0xab,0x41,0x6f,0xbf, + 0x50,0x7a,0x35,0x00,0x3e,0x78,0x68,0x29,0x17,0xb8,0xe1,0x38,0x5d,0x07,0xb7,0x72, + 0xb7,0xf1,0xaa,0xc2,0xff,0xe9,0xb9,0x58,0x4e,0x20,0xd4,0x4b,0x67,0xef,0xe5,0xb3, + 0x00,0xd3,0x8a,0x95,0x71,0x59,0x2b,0xbf,0xba,0x59,0xf4,0x08,0x5a,0x4c,0xdd,0x00, + 0x47,0xac,0x46,0x59,0x53,0x4e,0x60,0xf2,0x61,0xa5,0xdc,0xd1,0xe1,0xd1,0x06,0xc3, + 0x54,0xe5,0x2e,0xee,0xfc,0xec,0x0f,0x06,0xcf,0x97,0x60,0xd5,0x3f,0x7c,0x2f,0x0b, + 0xdd,0x79,0x69,0x88,0xdd,0xb6,0xd3,0x5d,0x39,0x21,0x07,0x95,0xb2,0x65,0x9c,0x2c, + 0x94,0xaf,0x03,0x71,0xe3,0x5a,0x3b,0x3d,0x29,0x46,0x3e,0x59,0xe6,0xa1,0xc1,0xd6, + 0xc4,0x05,0xd3,0x45,0x17,0x71,0xcc,0x4b,0xcc,0x17,0x5a,0x0f,0x84,0xb0,0x2d,0x25, + 0x80,0xe3,0x23,0xb6,0x90,0xee,0x19,0x3c,0x04,0xe0,0x21,0xf1,0x17,0x3a,0x63,0x50, + 0x9f,0xe0,0x1d,0x7e,0x9c,0xb6,0x49,0x67,0xc0,0xee,0xe3,0xa3,0xda,0xe2,0x0c,0xcd, + 0x24,0xeb,0x7e,0xe0,0x6a,0x07,0xb9,0x20,0xe4,0x0f,0x0b,0xe7,0xba,0xc5,0x80,0x03, + 0xfb,0x32,0xde,0x80,0xd8,0x99,0xee,0xaf,0xfc,0x6b,0xf4,0x8d,0x15,0xaf,0x0f,0xf8, + 0x5a,0x6a,0x43,0x63,0xe0,0x8a,0x2a,0x27,0x02,0xca,0x77,0xe4,0x52,0x58,0x84,0x89, + 0x81,0xeb,0x47,0x71,0x33,0xdf,0xfe,0x22,0x41,0x94,0xa7,0x5d,0x7c,0x2f,0xa1,0x95, + 0xa7,0x9d,0x7d,0xaa,0x00,0xee,0xee,0x0f,0x3a,0x06,0xfe,0xde,0xa7,0x08,0x29,0x82, + 0x3f,0x0d,0xf4,0x80,0x38,0xf6,0x68,0x91,0x14,0xc3,0xe9,0x70,0xbc,0x70,0xe5,0x8f, + 0x59,0x76,0x68,0x04,0xc6,0x84,0xdd,0x06,0xc9,0xf6,0x27,0xf1,0xa6,0xf0,0x2d,0xbf, + 0xb0,0x34,0xf7,0x6d,0x64,0xc7,0x58,0xd8,0x00,0x29,0xa2,0xc5,0x26,0x91,0x72,0x1a, + 0xab,0x43,0xe5,0x40,0x27,0x2d,0x8b,0x6b,0xf3,0x73,0xb7,0xc9,0xb2,0xb7,0xa6,0xaf, + 0xfb,0x68,0x66,0xc0,0x86,0xaa,0xfb,0x6f,0xb7,0x77,0x0a,0xc0,0xd6,0x5d,0x37,0x79, + 0x97,0xad,0xaf,0x92,0x02,0xed,0x1c,0xff,0x84,0xe1,0x82,0x64,0x8c,0x79,0x69,0x85, + 0x54,0x70,0x2e,0x05,0x36,0xa7,0xec,0x32,0x47,0x11,0x29,0xa0,0xbf,0xc7,0x83,0xb6, + 0x95,0x96,0x83,0xa1,0xd1,0x17,0xe5,0x4b,0xd1,0x64,0x83,0x15,0xb2,0x1e,0x81,0x5f, + 0x11,0xd4,0x88,0xaf,0x2a,0x54,0x33,0xd5,0x82,0x0e,0x14,0xaf,0xf9,0x39,0xe3,0x1e, + 0x05,0x0f,0x3d,0xbc,0x30,0x98,0x79,0xe2,0x11,0x19,0x61,0x58,0x75,0x18,0xc4,0x9f, + 0x87,0x77,0x56,0x19,0x8d,0xf8,0x43,0x3a,0xb1,0xca,0xb8,0xc4,0x1f,0x46,0x09,0x31, + 0xe7,0xd0,0x42,0x63,0x87,0x3b,0xfe,0xba,0x7d,0x62,0x1a,0xcd,0x71,0xe4,0xd1,0x7d, + 0xc3,0x94,0x64,0xb8,0x02,0x13,0x80,0xa8,0x31,0xa4,0x2d,0x93,0x43,0x4a,0xa6,0xeb, + 0xe3,0xda,0x55,0x71,0x15,0xb0,0x4b,0xf3,0x19,0xbe,0x1d,0x28,0xe0,0xd9,0x84,0x1b, + 0x7d,0x19,0x29,0x0d,0x63,0xb5,0xd0,0x2f,0x4d,0x92,0xb5,0xa4,0xaf,0x45,0x4c,0x16, + 0x86,0x34,0x1c,0xd3,0xb0,0x80,0x81,0x57,0x3b,0xb7,0xd7,0x7d,0x2e,0x51,0xc4,0xb4, + 0xa7,0x2f,0x30,0xe3,0x60,0x4f,0x23,0xaa,0x45,0xa7,0x1f,0x7f,0xca,0xba,0x23,0xce, + 0x0d,0x3b,0x1a,0xeb,0x2c,0x3b,0xa8,0xb5,0x4a,0x00,0x2c,0xc6,0xe1,0xf4,0xcf,0x14, + 0xac,0xc6,0xcd,0xa2,0x9c,0xd5,0x7b,0x58,0xe4,0x8d,0x32,0x9a,0x19,0x86,0xb8,0x86, + 0xa5,0x6c,0x89,0x41,0x62,0xbe,0x46,0x79,0x9e,0x57,0xbe,0xd3,0x2d,0x53,0xa1,0x70, + 0x21,0xcd,0xcf,0x6e,0xb6,0xb6,0x30,0x0e,0xd4,0x9e,0x15,0x0e,0xf6,0xfb,0x8d,0xab, + 0x8e,0xdd,0xb5,0xf7,0xec,0xfd,0xba,0xbb,0x5e,0x84,0xce,0xe9,0xee,0x0f,0x73,0xc7, + 0x5f,0x6d,0x7d,0xe0,0xc3,0xf0,0xc3,0xfc,0xea,0xb1,0x15,0x79,0xd1,0x1c,0x02,0x15, + 0x2a,0x96,0xba,0xc7,0x8d,0x3b,0x21,0x2c,0x6f,0xe9,0xee,0xb4,0xbb,0x3f,0xf6,0x8c, + 0x82,0xdf,0xa9,0x8c,0xc0,0x9e,0xbb,0x9c,0xce,0x95,0x43,0x8e,0xb8,0x45,0x49,0x02, + 0x3e,0xbf,0x92,0x01,0xdd,0xab,0xb6,0xb6,0xbe,0x12,0xf1,0xd4,0x60,0xb0,0x73,0x8c, + 0x7b,0x26,0xe2,0x0d,0xcf,0xfb,0xd1,0x17,0x8b,0x10,0x4f,0xec,0x01,0x81,0xfd,0xdd, + 0xb7,0xc8,0x05,0x9f,0xaf,0xfe,0x42,0x51,0x42,0x1c,0x48,0xa4,0x23,0xbc,0x65,0xf4, + 0x32,0xc2,0x73,0x81,0xb2,0xc5,0x7c,0xfc,0x71,0x51,0xba,0xd6,0x0b,0xbd,0x3e,0xdd, + 0x60,0x17,0xef,0xe4,0x2e,0xdf,0xe2,0xb2,0xd2,0x26,0x1c,0x6f,0xe2,0x44,0x6d,0x0f, + 0x42,0x59,0x5d,0x9a,0x5e,0x3c,0x08,0xa7,0x0c,0x3c,0x0f,0xe2,0xba,0xef,0xaa,0x06, + 0x52,0xdc,0xeb,0x5b,0x2b,0x5d,0x0b,0x13,0x9e,0xb3,0x68,0x11,0x8c,0x91,0x04,0x25, + 0x1e,0xa0,0x43,0x6e,0xf2,0xd9,0x32,0xd0,0x9b,0xc2,0xa5,0x6b,0x1c,0x2a,0x06,0x3d, + 0x93,0x09,0xba,0x4d,0x89,0xcd,0xb6,0x64,0xbf,0x77,0xa2,0xd9,0xda,0xf5,0x9a,0xb9, + 0xc9,0x1f,0x29,0x35,0x74,0xef,0x8a,0x82,0x8b,0xc3,0xc4,0x0f,0xfd,0x14,0x8f,0xe5, + 0x72,0xfc,0xad,0x5e,0x9b,0x98,0x87,0x3d,0x67,0x6a,0x84,0xfd,0xc8,0xad,0xf2,0x60, + 0x83,0x1b,0x14,0x23,0xf3,0xa9,0x4f,0x5a,0xd0,0x62,0x54,0x43,0xcb,0xb6,0x68,0xb3, + 0x28,0xdc,0x63,0x06,0x98,0x14,0xcb,0x66,0x2e,0x28,0xa0,0x0a,0xf7,0xd3,0x50,0x55, + 0xb1,0xc8,0x1c,0x3f,0x3e,0x8e,0x40,0x52,0x8e,0x61,0x31,0x8c,0x64,0xfe,0xd3,0x42, + 0xc6,0xd4,0x18,0x47,0x18,0x3a,0x85,0x49,0xbb,0x3a,0xf9,0x2b,0xc5,0x6c,0x2f,0xe0, + 0x17,0x2f,0x0e,0xbc,0x4a,0x7e,0x70,0x75,0x6d,0x8f,0x15,0xee,0x6b,0x2c,0x20,0x7c, + 0x6c,0x52,0x0c,0x76,0xcc,0xc5,0x47,0x6c,0x75,0x67,0x89,0xdb,0x3b,0x01,0x6e,0x37, + 0x74,0x64,0xc8,0x5b,0xd0,0xad,0xd8,0x7f,0x58,0xe9,0x4b,0x37,0xce,0x22,0xfd,0xd1, + 0xef,0xed,0x33,0xed,0xf1,0x95,0xe6,0xd6,0x72,0xad,0x56,0x5b,0x29,0xd5,0xc4,0x13, + 0x54,0x83,0x76,0x27,0xb4,0xbd,0x51,0xd5,0xe4,0x81,0x04,0x64,0x3d,0x74,0xa1,0xe5, + 0x89,0xb8,0x17,0xdc,0xcc,0x91,0xa1,0xf0,0xb5,0x09,0x63,0x13,0xbe,0x2d,0xb0,0xdb, + 0x35,0xc9,0xf0,0x58,0xf4,0xc8,0x22,0x23,0x72,0x3e,0x89,0xd6,0x34,0x14,0xd4,0xe4, + 0x9b,0x8b,0xf3,0xd6,0x87,0x8f,0xbf,0x18,0xbb,0x6c,0xd7,0x2c,0xd5,0x0c,0xb6,0x79, + 0xc6,0x4f,0xa8,0xdf,0x42,0xf4,0x28,0xa9,0x21,0xac,0x9d,0x26,0xf4,0xae,0xac,0x9b, + 0xc0,0xad,0x98,0xed,0x91,0xd1,0x17,0x6e,0xe1,0x27,0xdc,0x19,0xd9,0xfc,0xb8,0x86, + 0xfa,0x70,0x2f,0xf0,0xe4,0xc2,0xe0,0x40,0x0b,0xb5,0x99,0x84,0x49,0xe4,0x68,0x30, + 0x96,0x6c,0x61,0x85,0x4b,0xb4,0x93,0x98,0xdd,0xe7,0x9f,0x65,0xef,0xd6,0x85,0x41, + 0x4c,0x46,0xc0,0x30,0xc7,0xec,0x4e,0x4f,0x3d,0xfb,0xc4,0xfb,0x50,0x33,0x89,0x4f, + 0x12,0xe0,0xe3,0x80,0x2d,0x69,0x19,0xac,0x03,0x4c,0x46,0x7a,0x5c,0x35,0x56,0xe2, + 0xe1,0x49,0x35,0x82,0x86,0xbb,0xc5,0x07,0xd9,0xfa,0xc4,0x28,0x40,0x64,0xf7,0x3c, + 0xf0,0xcb,0x5f,0x0d,0xba,0x7d,0x03,0xc7,0x9d,0xdd,0x43,0xed,0x64,0xcc,0x20,0x27, + 0xab,0xb2,0x74,0xb7,0xb6,0x9a,0xe5,0xa5,0xf6,0xf8,0x58,0x5a,0xbe,0x16,0xd7,0x5c, + 0x5c,0x46,0xa6,0x5d,0xca,0x75,0x62,0xd2,0xbd,0x0b,0x45,0x24,0x2c,0x1b,0x2b,0x50, + 0x45,0x1f,0x87,0x7c,0x92,0x2d,0xe7,0xe7,0xaa,0xb8,0xc9,0x68,0xe8,0x5d,0x4a,0xaf, + 0x41,0xf0,0xb7,0x18,0x2d,0xd0,0x6e,0xca,0x3a,0xe8,0x22,0x90,0x4a,0x0d,0x32,0x55, + 0x2f,0x0f,0x3b,0xe2,0xcf,0x71,0x2c,0x43,0xc4,0x09,0x7c,0x88,0xee,0xc2,0x81,0xea, + 0x0e,0x5d,0x57,0x51,0xed,0x0d,0x27,0xf3,0xfe,0x76,0x17,0x32,0x68,0x3e,0x62,0x22, + 0xde,0xd9,0x64,0xda,0x90,0x26,0x0f,0xd5,0x3b,0xdd,0x13,0x7c,0xa3,0x2b,0xe3,0x61, + 0x47,0xea,0x74,0x61,0xa9,0xa3,0x39,0x55,0x0f,0xcb,0x09,0x2d,0xe4,0x5c,0xb5,0xc7, + 0xd7,0x5f,0x54,0xda,0x13,0xc9,0xec,0xfa,0x31,0xd7,0x9b,0xe3,0x2f,0x36,0x24,0x6e, + 0x14,0x52,0x26,0x96,0x2d,0x71,0x1c,0x1d,0x19,0x45,0xa2,0xd4,0x5e,0xf1,0x23,0xfb, + 0xb4,0x31,0x39,0x95,0x91,0x01,0xb1,0x03,0x64,0x12,0x01,0x59,0xed,0x58,0xc4,0xe7, + 0xa4,0xb1,0xa0,0xc7,0x6d,0x21,0x0a,0xe7,0xb8,0x7a,0x0e,0xa1,0x76,0xa7,0xaf,0x76, + 0xff,0x49,0xee,0x73,0xbf,0x39,0x8f,0xbc,0xe8,0x7f,0x93,0xab,0xfe,0xeb,0x47,0x89, + 0x54,0x5f,0x3f,0x22,0x86,0x7c,0xfd,0x48,0xb8,0xff,0xf5,0x63,0x76,0xff,0xf5,0x23, + 0xf6,0xf1,0x37,0x81,0x12,0xe2,0x05,0x67,0x57,0xa6,0x23,0x60,0xc4,0x33,0x81,0x87, + 0x9e,0x29,0x18,0xc1,0x6f,0x8e,0xbc,0xa4,0xfd,0x06,0xef,0xe5,0x92,0x61,0x41,0x11, + 0xaa,0xd8,0x6f,0x01,0x58,0xcd,0x93,0x31,0x05,0xd0,0xe2,0x97,0x82,0x17,0x8b,0x76, + 0x19,0x2b,0x5f,0x2e,0x5a,0x10,0x5a,0x88,0xf6,0xd7,0xde,0xcc,0xcc,0xbc,0xa4,0x74, + 0x5a,0x14,0xfb,0x28,0x6f,0xc6,0x3a,0x0d,0x87,0x5d,0xae,0x8e,0xb4,0xb3,0xc6,0x1d, + 0xda,0xac,0xb9,0xd2,0xec,0x3c,0xf0,0x5c,0x34,0x1e,0xc5,0x3d,0xb1,0x78,0xdb,0x2b, + 0xac,0x3c,0x90,0xec,0x3a,0x96,0x66,0xbf,0x07,0x0d,0x6b,0xc2,0xb1,0x60,0xc6,0x50, + 0xd8,0xd8,0xa0,0x85,0xd1,0x2c,0x8a,0xe0,0xc7,0x65,0x3b,0x72,0x19,0x55,0x96,0x1b, + 0xe9,0x5a,0x46,0x4b,0x5c,0xfc,0x9a,0xa2,0x37,0x3c,0x39,0xb8,0x00,0xbe,0xb4,0x7e, + 0xbe,0xc0,0x28,0x24,0x78,0x0d,0x5f,0xaa,0x75,0x63,0xa5,0x3f,0xa5,0x88,0x3a,0xac, + 0x39,0x52,0xae,0xec,0x16,0x67,0x80,0xc9,0x91,0x3d,0x28,0x0e,0x53,0x67,0xb3,0x01, + 0xd5,0xae,0x4e,0x5b,0xff,0xd3,0x6d,0xfd,0x71,0xbd,0xdc,0x7b,0x92,0x5e,0xeb,0xf9, + 0x04,0x6c,0x42,0x39,0x4c,0x4b,0x71,0xe1,0x6b,0x60,0x44,0xe7,0xbc,0x00,0xa2,0xbd, + 0x56,0xe0,0xa1,0x95,0xa2,0x81,0xe4,0x49,0xc8,0x8e,0x06,0x3a,0x23,0x1a,0x4d,0x32, + 0x4c,0xc3,0x2e,0x5b,0x25,0xbb,0xca,0xfa,0x8a,0x4d,0xfd,0x56,0x51,0xb4,0x47,0x27, + 0x27,0x71,0x7b,0x48,0x71,0x03,0x06,0x85,0x7b,0x3f,0xfb,0xc3,0xb2,0xfb,0x77,0xf1, + 0x5a,0xd0,0xf5,0x5e,0xae,0xe4,0xb0,0x89,0xd6,0x57,0xe2,0x2b,0x11,0x2a,0xf3,0x12, + 0x20,0x85,0x89,0xe4,0x4e,0x85,0x96,0xa0,0x05,0xa7,0xd4,0x25,0x6f,0xcd,0xcc,0xa0, + 0xe7,0x27,0x32,0x89,0x70,0x0a,0x5d,0x36,0x86,0x65,0x27,0xc1,0x62,0x8f,0x78,0x14, + 0xec,0xc2,0x20,0x18,0x6c,0x59,0x52,0x73,0xfa,0xca,0xbd,0xa8,0xdc,0xd1,0xc8,0x8b, + 0x33,0xe5,0xea,0x25,0x3c,0x9a,0x30,0x14,0x50,0x9c,0x44,0x18,0x8d,0x89,0x6e,0xc6, + 0x43,0x8f,0x53,0xcc,0x50,0xf0,0x3a,0x25,0xcf,0x38,0xe5,0x7b,0xea,0x18,0x6f,0x27, + 0x22,0xa0,0x9e,0xa8,0x86,0xf6,0x35,0xf4,0x57,0x45,0x77,0x2a,0x10,0x23,0x3c,0x8f, + 0xe5,0xc2,0xd4,0xf8,0xcd,0x64,0xd1,0x8f,0x3d,0xa7,0xbe,0xfa,0xcd,0x24,0x37,0xac, + 0xdc,0x61,0x8c,0x90,0x1d,0x20,0xb9,0xd7,0x86,0xba,0xc8,0x67,0x8a,0x6a,0x87,0x0c, + 0xe8,0x67,0x96,0x8a,0xb0,0x01,0x8b,0xd8,0xc0,0x8b,0x4c,0x6d,0xbc,0xd8,0x20,0xf7, + 0xee,0x92,0x57,0xcf,0xb6,0xe8,0x26,0x5e,0xaa,0x58,0x84,0xc2,0xa4,0x11,0x28,0x97, + 0x39,0x72,0x96,0xab,0xf5,0xe6,0x42,0xa5,0x4d,0x4b,0xb8,0xcf,0x2a,0x19,0x41,0x38, + 0x9f,0xe4,0x2e,0x74,0x45,0x1f,0xce,0x7a,0x4c,0x5b,0x25,0x6f,0x88,0xc8,0x04,0x8e, + 0x71,0x46,0xce,0xb8,0x14,0xed,0x90,0x0d,0xbf,0xd0,0xab,0x0d,0xd0,0x23,0x08,0xe4, + 0x6d,0xcf,0xa5,0xe1,0x20,0xd2,0x08,0xf7,0x38,0xf2,0xd9,0x75,0x4c,0xbd,0x27,0xb9, + 0xbb,0x68,0xc5,0x33,0xb4,0xb4,0x67,0xdc,0x6b,0x7b,0x46,0xee,0x16,0x7a,0x2f,0xdc, + 0x2c,0x85,0x18,0x4b,0x55,0xe5,0x41,0xac,0x57,0x8e,0x93,0xf3,0x95,0x0d,0x1f,0x85, + 0xc4,0x74,0x4f,0xbe,0x96,0xe4,0x81,0x2f,0xaa,0x57,0xa7,0xa9,0x68,0xf9,0x57,0x76, + 0xc6,0x57,0x3e,0x73,0xab,0x10,0x56,0x78,0x26,0x6e,0x0b,0x96,0x37,0x27,0xe9,0x56, + 0x63,0xc7,0xdc,0xfe,0xaf,0xf5,0x4f,0xd4,0xa0,0x5f,0x75,0x4e,0x54,0x98,0xc4,0x3c, + 0x3a,0xd7,0x57,0xe3,0x17,0x68,0xa4,0x11,0x6a,0x0c,0xd6,0x3a,0x07,0x72,0xd8,0x7e, + 0x75,0xae,0x09,0x6c,0xe9,0x99,0x3c,0x3e,0x5f,0x43,0x70,0x0a,0x7e,0x9d,0xcd,0x62, + 0x41,0xe9,0xdd,0x99,0xce,0x5c,0x60,0xf8,0x0d,0x29,0x51,0x88,0x6a,0x08,0x56,0x05, + 0x9f,0x49,0x03,0xf8,0x5d,0xe9,0x4c,0x99,0x45,0x53,0x3a,0x65,0x41,0xe0,0x6a,0xb3, + 0x90,0xd6,0x4d,0x02,0xcc,0x41,0xe1,0x2a,0x12,0x83,0xa2,0xce,0xac,0x97,0x52,0x4c, + 0xc7,0x50,0xae,0x9d,0x35,0xed,0xe7,0xe4,0x87,0x9a,0x1e,0xfb,0x63,0x92,0x35,0x01, + 0x97,0x80,0xdd,0x86,0x9d,0x01,0xd5,0x1c,0xca,0x9d,0x53,0xcc,0x46,0xd1,0xe3,0xb3, + 0xbe,0x9f,0xd0,0x2a,0xe2,0xcc,0xcf,0xb0,0xc9,0xb0,0x66,0x9a,0x3c,0x3e,0x71,0xda, + 0xb7,0x61,0xbc,0xd0,0x01,0x10,0x58,0xb7,0xb1,0x38,0xc8,0xd0,0x63,0x22,0x62,0x7f, + 0xc2,0x07,0x94,0xec,0x1e,0xeb,0x66,0xb8,0x48,0x4d,0x9e,0xca,0x51,0xca,0x8b,0x05, + 0xd4,0x55,0xb4,0xa8,0x2b,0xe1,0x8f,0x9f,0xfd,0xf0,0xf3,0x3c,0x3d,0x91,0x66,0x96, + 0xcd,0x0e,0xdb,0xd2,0x8f,0x3c,0x3f,0x68,0x16,0xf3,0xb0,0x29,0xbf,0xd5,0xdb,0x6b, + 0xeb,0x26,0x7d,0xc2,0xf9,0x58,0xf2,0x4e,0x82,0xb2,0x63,0xc0,0x73,0x9a,0xb6,0xfc, + 0xda,0x7b,0x98,0xab,0x13,0xd3,0x52,0x07,0xfd,0x5a,0xfc,0x13,0x6e,0xa4,0xfe,0x0a, + 0xd7,0xfa,0xc5,0x5b,0xf0,0xd9,0xd5,0xd7,0xea,0x1d,0x92,0x3c,0x54,0xc2,0x00,0xb8, + 0x73,0x72,0x8e,0x51,0x8b,0x71,0xb3,0x19,0xb9,0x01,0xde,0x98,0x63,0xcb,0x1b,0x14, + 0xbe,0xd8,0x77,0x4b,0x0c,0x8a,0x6d,0x23,0x38,0x18,0x88,0xc8,0x6a,0xd5,0x5c,0x20, + 0x2d,0xba,0x3d,0x4f,0xa7,0xb6,0xea,0x8b,0x9d,0xf9,0x59,0xe0,0xd9,0xb0,0x5c,0xc5, + 0x8e,0x24,0x08,0x22,0xc3,0xa0,0x45,0x5f,0x4b,0x64,0x91,0xd2,0x80,0xcf,0xf9,0x24, + 0xb1,0x81,0x77,0x7b,0xad,0x14,0xb4,0x50,0x2a,0x43,0x31,0x8d,0x48,0xea,0x80,0xed, + 0xf7,0x6e,0xa0,0xe5,0xc5,0xf8,0x4a,0xd0,0x7c,0xe0,0x87,0x37,0xc5,0x64,0xb4,0xd9, + 0xba,0x11,0x82,0x21,0x92,0x4d,0x2c,0xbd,0x48,0x80,0x52,0xcc,0xb2,0x2c,0xee,0xed, + 0xee,0x82,0x4c,0x11,0xef,0x98,0xbb,0x66,0x9f,0x0b,0x17,0x9a,0x43,0xad,0x9a,0x48, + 0x9e,0x25,0xde,0x44,0xbc,0x27,0xd1,0xdd,0x4a,0xc3,0x43,0xa1,0x21,0xaf,0xa9,0xcb, + 0x34,0x0b,0x55,0x99,0x2f,0xcc,0x4a,0x55,0xfa,0x75,0xda,0x3a,0x1c,0xd6,0xa9,0xf3, + 0xd8,0xd0,0x4e,0x00,0xfd,0xf1,0x71,0xaf,0xdd,0xd7,0x0a,0x92,0x95,0x77,0xf9,0x32, + 0x80,0xbe,0x88,0xe2,0xae,0xbb,0x14,0xe9,0x98,0x19,0xb6,0x5a,0xcf,0xd6,0x71,0xdc, + 0x3e,0x09,0x7b,0x42,0xe5,0x1a,0xbe,0x1e,0x1c,0xc0,0xba,0x93,0x98,0x00,0x35,0xe8, + 0x37,0x56,0x8b,0x8b,0x30,0xed,0xe5,0x08,0xb6,0x78,0x0f,0x83,0xf5,0xb5,0xc8,0xe1, + 0xb3,0x56,0xdf,0x49,0x1b,0x5c,0x74,0x53,0x76,0x55,0xca,0xac,0x3e,0xc6,0x6f,0xc2, + 0x5c,0x0e,0x07,0xf0,0x68,0x5a,0x4f,0xab,0x4d,0xd0,0xb9,0x4f,0xed,0x9a,0x5a,0x1a, + 0x35,0xe3,0xd2,0x64,0x29,0x39,0x84,0x93,0xed,0xd7,0xae,0xc1,0xb3,0xb4,0x6b,0x1e, + 0x7f,0xa2,0x16,0x5f,0xef,0xba,0xc7,0xdb,0x3d,0xf3,0x3f,0xa3,0x85,0x31,0x72,0x85, + 0xed,0x27,0x53,0x01,0x5c,0xa0,0xc2,0x2a,0xde,0xee,0xc8,0x3b,0xfa,0x10,0xc4,0x67, + 0xef,0xde,0xe2,0x45,0x08,0x83,0xee,0x7e,0x5f,0xbd,0xff,0xe3,0xcd,0xa7,0x6f,0xd1, + 0xe0,0xe4,0xca,0xe4,0xe8,0x99,0xdf,0x03,0x51,0xb9,0xc3,0x20,0xcc,0x68,0x66,0x0f, + 0x83,0xa0,0xfb,0x00,0x4c,0xb2,0x44,0x85,0xaf,0xdf,0xe2,0x2f,0x6d,0x3e,0xb0,0x2d, + 0x8d,0x29,0x9f,0x1f,0x4e,0x22,0xce,0x34,0x42,0xd3,0x47,0x8c,0xbc,0x09,0x98,0x40, + 0xe4,0x5f,0xb0,0x48,0x94,0x6e,0x34,0x7f,0xbe,0x3c,0xb3,0x38,0x23,0xf9,0xe6,0x50, + 0x88,0x4e,0xc1,0xa5,0x52,0x86,0x25,0xec,0x0f,0xa3,0x59,0x4b,0x60,0xce,0x13,0x67, + 0x65,0xb9,0x41,0xaf,0x34,0xb7,0xfc,0x17,0x42,0x05,0x67,0x9c,0x03,0xd6,0xa3,0x47, + 0x94,0xf9,0xa3,0xe7,0x32,0x17,0x79,0x7e,0xf1,0xe9,0xf4,0xbd,0x41,0x5e,0x57,0xe8, + 0xd2,0x14,0xa0,0x29,0x53,0x9a,0x19,0x64,0xa0,0xc9,0x65,0xf2,0x0b,0x42,0x6d,0x52, + 0x96,0xa5,0xe8,0x22,0x95,0x8c,0xe9,0x56,0x2f,0x3c,0x76,0xb3,0x59,0x88,0x43,0xef, + 0x18,0x66,0x4e,0xa6,0x5e,0xb1,0xa0,0x58,0x6b,0x38,0x96,0xef,0x12,0xe0,0x3b,0x90, + 0x0b,0x11,0xdf,0x60,0x7f,0x5a,0x1e,0xee,0xb7,0x66,0xde,0x3d,0x5a,0xd2,0x25,0x2d, + 0x60,0xaa,0xc4,0x90,0x40,0x1c,0x18,0x41,0xa1,0xc4,0xd1,0x9b,0x3f,0x4d,0x6f,0xf2, + 0x92,0x14,0x3a,0x1b,0x56,0x5d,0x98,0x09,0x8e,0x76,0x9e,0x7a,0xc1,0x2d,0x48,0xe3, + 0xc5,0xf2,0x74,0xff,0x2e,0x16,0x3e,0x63,0x4f,0x35,0xad,0x69,0xfe,0x64,0x34,0x49, + 0xa9,0xc5,0x5b,0xb1,0x8a,0xb0,0x4d,0x6a,0x5d,0x31,0x13,0xb0,0xe4,0x62,0x2f,0x99, + 0xcb,0xc9,0x70,0x89,0xea,0x6f,0xa7,0xc6,0xe9,0xd9,0x3b,0x03,0x3f,0xf8,0x29,0xe2, + 0x40,0x5a,0x1d,0x8a,0xb1,0xf4,0xc3,0xec,0x48,0x8c,0x48,0x5c,0x34,0x8c,0x75,0x20, + 0x94,0x50,0x2d,0x8d,0x09,0xb8,0x13,0x19,0x4d,0x72,0x7a,0xf2,0x64,0x83,0xe2,0xfe, + 0xde,0x3f,0xbc,0x24,0x9a,0x45,0x71,0x4d,0x91,0x1c,0x06,0xb4,0xc5,0x08,0xc6,0x01, + 0xaf,0x49,0x66,0xd4,0xf1,0xe6,0x31,0x0b,0xdf,0x18,0x84,0x15,0xf6,0x1f,0x21,0x89, + 0xbb,0x89,0x3b,0xcf,0x83,0x0b,0xf0,0x85,0xcb,0x06,0x9d,0xd1,0xd9,0xc3,0x3b,0x1b, + 0xfd,0xd3,0x93,0x27,0x89,0xa5,0x1e,0xb9,0xb7,0xb3,0xb3,0xeb,0x27,0x92,0xe0,0x11, + 0x40,0x85,0x28,0xe5,0x58,0x27,0xad,0x47,0x58,0x04,0x02,0x52,0xe4,0xf2,0x37,0x42, + 0x42,0x81,0x00,0x4f,0x3c,0xf5,0x1d,0xb5,0xb3,0xa3,0x5b,0x9b,0xe4,0x10,0xdb,0x10, + 0x3e,0x66,0x96,0x5e,0x4a,0x5e,0xa7,0x6b,0x9b,0xe7,0x5e,0x22,0xde,0x5a,0x68,0x9a, + 0x59,0xdb,0x86,0xf4,0xce,0xfd,0x54,0xe8,0x85,0xd1,0x44,0x34,0xb4,0xd1,0x2b,0xce, + 0x36,0xd8,0x0f,0xaa,0x52,0xa8,0x35,0xf6,0x5d,0x60,0x61,0xcc,0x37,0xf7,0x19,0x59, + 0x8a,0x89,0x81,0x60,0x6a,0x08,0x5c,0x80,0x3f,0x12,0xed,0x04,0xd1,0x94,0x6d,0xba, + 0x11,0xfe,0xf8,0x2b,0x07,0x0f,0x1f,0xa6,0x22,0x12,0x1b,0x82,0x64,0x82,0x1e,0x8a, + 0xe4,0x9d,0xa0,0x97,0xe3,0x69,0x43,0x36,0xbb,0x58,0x2a,0xcf,0xe3,0x25,0x78,0x65, + 0x2c,0xac,0x09,0x76,0xc4,0x27,0x49,0x95,0x7c,0xea,0xb5,0x12,0x72,0xc8,0x5e,0x98, + 0x46,0x7c,0xe3,0x1e,0x14,0xc0,0xdd,0xc4,0x70,0xb3,0x0c,0x29,0xf3,0xd8,0xe0,0x6f, + 0xc5,0x8c,0xc8,0xe8,0xd1,0xb4,0xb9,0x63,0x5a,0x6d,0x22,0x19,0xb0,0x71,0xec,0xdd, + 0x3f,0x15,0xb2,0xa6,0x9c,0xf5,0x97,0xc4,0x87,0x3e,0x54,0xf3,0x1a,0x4b,0xbe,0xdb, + 0x88,0xcb,0x4c,0xe3,0xd4,0x20,0x3a,0x73,0x8e,0x8a,0x63,0x63,0xc1,0xb7,0x07,0xfd, + 0x70,0x7e,0xa1,0x7d,0x9e,0x4c,0xd4,0x77,0xba,0x44,0xa8,0x92,0x03,0x9d,0xe3,0x2b, + 0x64,0x0d,0x11,0x4a,0x6e,0x16,0x7c,0x63,0x7d,0xb5,0x9c,0x97,0x91,0x73,0x25,0xe0, + 0x55,0xcc,0x12,0xac,0xb4,0x45,0x80,0x6c,0x30,0x0b,0xf7,0x40,0x64,0xd1,0x8d,0xdd, + 0xcd,0x76,0x03,0x49,0xef,0xb0,0x9c,0x5a,0x66,0x21,0x41,0x9b,0x8f,0x74,0xfc,0x70, + 0x14,0x2c,0xc6,0xd4,0x82,0x01,0xbc,0x9f,0x4f,0xed,0xfa,0x72,0x81,0xa5,0x95,0xd2, + 0x24,0x60,0x20,0x05,0xa2,0x57,0x3f,0xe5,0xf9,0x0a,0xfc,0xdb,0x62,0x15,0x95,0x72, + 0x31,0x6c,0x47,0x69,0xa5,0x9c,0x98,0xe7,0x42,0x57,0xf5,0x9b,0xd1,0x35,0x42,0x4e, + 0xc9,0x2d,0xb1,0x54,0x51,0x31,0x50,0xc9,0xcd,0x33,0xf2,0x86,0xee,0x6b,0xe4,0xec, + 0x62,0x65,0xd7,0xe4,0xa4,0xc9,0xf9,0x8e,0x35,0x2d,0x75,0x79,0x85,0x3a,0xd5,0x10, + 0x87,0x30,0x53,0x4f,0x08,0x83,0xba,0x3e,0xdf,0x58,0x82,0x68,0xd2,0x92,0x6f,0x92, + 0xb8,0x05,0x38,0x5a,0x14,0xb7,0x15,0xb5,0xa2,0x37,0x83,0x3f,0x08,0xb1,0x5f,0xdb, + 0x95,0xd4,0xc1,0x0d,0x96,0x8e,0x32,0x97,0x23,0x78,0x51,0xbb,0xa8,0x3c,0x40,0x55, + 0x0d,0xc9,0x40,0xd0,0x43,0x22,0xc5,0x6c,0x68,0x41,0x73,0x37,0x01,0x96,0x6a,0x66, + 0xe5,0x25,0x39,0x9c,0x02,0xcd,0xed,0x5d,0x48,0x51,0x0c,0x10,0x9b,0x28,0x97,0x20, + 0xea,0xaa,0x16,0xa5,0x64,0x20,0x16,0x5f,0x52,0x86,0x84,0xc4,0x22,0x19,0xf7,0x50, + 0x2c,0x76,0x66,0x12,0xe8,0xe0,0x57,0x76,0xff,0xdd,0xe9,0x87,0xda,0x32,0x86,0x1b, + 0xaf,0x2a,0x86,0xf2,0x15,0xae,0x02,0x56,0xec,0x9c,0x9e,0xcb,0xf2,0x40,0x17,0x8a, + 0x4d,0xa2,0x3c,0x9e,0x17,0x95,0xdb,0x3a,0x4b,0x22,0x48,0x7f,0x45,0xe5,0x42,0x6d, + 0x23,0x68,0xf4,0xcd,0xca,0x1c,0x36,0xab,0x5d,0x13,0x9a,0x76,0xb5,0xcc,0x34,0x8c, + 0xd0,0xd7,0xa9,0x12,0x42,0x31,0x91,0x3b,0x38,0x5b,0x64,0xb8,0x7a,0x6b,0xb3,0x18, + 0xcd,0xd4,0x05,0xd6,0xc4,0x4d,0x0d,0x59,0x93,0x98,0x0c,0x49,0xd1,0xde,0xe0,0x6f, + 0x89,0x36,0x1a,0xad,0x56,0x2e,0x05,0x93,0x5e,0x8c,0x76,0xee,0xec,0xc1,0xbc,0x6e, + 0x5c,0xe7,0x8c,0xd6,0x4f,0x6f,0xfe,0x93,0xf9,0x2c,0x11,0xfa,0x5c,0x3b,0x9d,0x6b, + 0x33,0xe5,0x74,0x33,0xb5,0x9c,0x70,0x01,0xf9,0xd9,0x62,0x9c,0x7f,0xa4,0xa5,0x20, + 0x3f,0x46,0xe1,0xb4,0xf0,0x95,0xed,0x41,0x1d,0x3a,0x7c,0x31,0x2f,0xa5,0x24,0x08, + 0xfb,0xb8,0x30,0x14,0xa5,0x0f,0x1d,0xce,0x9a,0xdc,0x8a,0x7c,0x08,0x58,0xdc,0xc7, + 0x60,0xf3,0x95,0x3d,0xae,0x61,0x59,0xec,0x2e,0x4f,0x58,0x14,0xa8,0x4e,0xf3,0x33, + 0x57,0x57,0xdc,0xac,0x68,0x1b,0xf6,0x68,0xbb,0x2a,0xef,0xbd,0xa2,0xa7,0x98,0x8a, + 0x5c,0x26,0x9e,0x64,0x7a,0xe1,0x88,0xe2,0x93,0xbd,0xff,0xf1,0x0f,0xf9,0x39,0xbb, + 0xc7,0x01,0x88,0xe3,0x3b,0xfc,0x86,0x27,0x77,0xe2,0x9b,0x8b,0xd3,0x2a,0x3d,0xbb, + 0x27,0x2e,0x06,0x0b,0x93,0x9f,0xf0,0x7a,0x40,0xbe,0x1d,0x10,0x96,0x8a,0xba,0x2a, + 0x10,0x39,0x18,0x64,0xe4,0x8c,0xe6,0x1d,0xee,0x01,0xa9,0xdc,0x9b,0x45,0x61,0x4b, + 0x96,0x1e,0xb9,0x63,0xb1,0xf7,0xc0,0x02,0x1a,0x92,0x8f,0x17,0x88,0xb6,0x6e,0x98, + 0xce,0xd1,0x28,0xa2,0x6d,0x9b,0x51,0xf8,0xa8,0xf0,0x47,0xde,0x3a,0x4b,0xb6,0x07, + 0x80,0xde,0xbf,0x76,0xba,0x87,0xf7,0xc6,0xa7,0x5f,0x0d,0x40,0xd7,0x14,0xd5,0x47, + 0xfc,0xa1,0xb6,0xd4,0xc4,0x9b,0xe7,0x25,0xbf,0x4f,0xd0,0x5b,0x18,0xe9,0x09,0xd0, + 0xbe,0x45,0x80,0xce,0xea,0xb2,0x6c,0xa1,0xa1,0x98,0xd8,0x94,0x5f,0xe9,0x0a,0xc4, + 0x96,0x18,0x97,0x4e,0xde,0xa8,0xa9,0xc9,0xe4,0x91,0xaf,0x04,0xee,0xb4,0x3a,0x6d, + 0xed,0x31,0xbf,0x08,0xb8,0x73,0xf8,0xb8,0xd7,0x7d,0xa4,0x2b,0xa3,0x0d,0x79,0xf9, + 0xb3,0xde,0xb7,0x3b,0x14,0x5d,0xc6,0xd1,0xb4,0xb4,0xe2,0x98,0x83,0xf0,0x27,0x46, + 0x0a,0xf8,0x1e,0x0a,0x22,0x80,0xf8,0x67,0x2c,0xdb,0xad,0x4e,0xb7,0x8d,0x51,0x04, + 0xd4,0xe4,0xc2,0x2e,0x05,0x22,0x14,0x06,0x91,0x81,0x5a,0x48,0xcc,0x99,0x78,0x09, + 0x86,0x09,0x37,0x38,0x35,0x0a,0xc6,0x6a,0x32,0xa7,0x23,0x87,0x4e,0x4f,0x40,0xdc, + 0x61,0x71,0x08,0x27,0xf7,0x87,0x33,0x83,0x8f,0x54,0x64,0x22,0x6b,0x8e,0x49,0x20, + 0x50,0x70,0xb9,0x1f,0x7b,0x81,0xfb,0x20,0x80,0x82,0x8f,0xc6,0x90,0x16,0xa7,0xc4, + 0x20,0xf9,0xf9,0x52,0x7e,0xe6,0xe9,0xc6,0x0e,0x77,0x55,0x57,0xd9,0xa7,0xde,0x59, + 0x9d,0x1b,0xc9,0x34,0x67,0x12,0x4c,0x4b,0x5a,0xac,0x40,0x30,0xa5,0x30,0x8f,0x51, + 0x72,0x87,0x42,0xc3,0xdc,0x43,0xa2,0x9c,0xb8,0x93,0x09,0xde,0x13,0x50,0x9a,0xff, + 0xf9,0x22,0xc8,0x7c,0x07,0xea,0x49,0x99,0x3d,0x4b,0x5c,0x60,0xb1,0x7f,0x22,0x3e, + 0x1f,0xb8,0x92,0x1c,0x2a,0x41,0x00,0xf2,0x37,0x4c,0xd9,0xd8,0x89,0xc2,0x00,0xbb, + 0x75,0x8a,0x29,0xa8,0x8e,0x1e,0xb7,0x30,0xc5,0x40,0x81,0x23,0xe3,0x53,0x80,0x34, + 0xad,0x34,0x23,0xb8,0x6b,0x0d,0xa4,0xef,0x30,0xcc,0xb0,0xdc,0xb2,0x75,0xa8,0xc2, + 0xbc,0x2d,0x70,0x4d,0x34,0xdb,0xc6,0xc0,0x20,0x42,0x27,0x57,0x28,0xf2,0xeb,0x4e, + 0xb5,0x26,0x8e,0x71,0x50,0x53,0xd3,0x8c,0xb8,0xf5,0x15,0xf5,0xcc,0x5d,0x5c,0xd1, + 0x18,0x40,0x82,0xde,0x21,0x73,0x4c,0x80,0x3c,0xdc,0x7f,0xaa,0x64,0x74,0x94,0x1c, + 0x41,0x01,0x27,0xb8,0xa5,0xb5,0x05,0x16,0x21,0x09,0x3a,0x63,0x51,0x84,0xf2,0xd2, + 0xad,0x08,0x22,0x9d,0x1b,0x2d,0x97,0x87,0xb4,0xd8,0x19,0x03,0x99,0x1a,0x65,0x52, + 0x70,0x13,0xf9,0xdc,0x00,0x21,0xfd,0x80,0xb1,0xc1,0x93,0x07,0xde,0x5f,0x72,0x5a, + 0x3a,0x73,0x11,0xaf,0xc5,0x6a,0x03,0xf0,0xf9,0x73,0x37,0x78,0x44,0xbe,0x25,0x81, + 0x3d,0xfa,0x31,0xcd,0x12,0x7f,0x94,0x49,0x66,0x23,0x9b,0xe1,0xd1,0xdb,0xcc,0x21, + 0xb6,0x06,0xef,0xae,0x00,0x31,0x12,0x13,0x88,0xcf,0x81,0xee,0x3c,0x76,0x1e,0x73, + 0x54,0xa2,0x13,0x5b,0x87,0xe4,0x68,0x5b,0x9c,0x6b,0xe3,0x8b,0x81,0x0a,0x0e,0xa3, + 0xf9,0x08,0x24,0x69,0x14,0xcd,0x91,0x7c,0xe1,0x7e,0xcf,0x0e,0x7f,0xa2,0xe4,0x74, + 0xe1,0x69,0x06,0x0d,0x50,0xfa,0x07,0x4c,0xd0,0xec,0x13,0x04,0x5a,0x8d,0x47,0x0e, + 0x61,0x20,0x46,0xa3,0x45,0x21,0x5f,0xc4,0x0f,0x31,0x4e,0xbf,0x3b,0x33,0xf4,0x0f, + 0x9c,0x3d,0xd7,0xba,0xda,0x05,0x1b,0x9c,0xc2,0x6e,0xa5,0xac,0x64,0xec,0xb2,0x81, + 0x8d,0xfe,0x5d,0x70,0x68,0x9e,0xca,0x25,0x79,0x3e,0x8f,0x39,0x3e,0x04,0x27,0xb2, + 0xaf,0x08,0xcf,0x47,0xc4,0x15,0xad,0x03,0x42,0x4f,0x53,0x50,0xcf,0x03,0x23,0x6a, + 0x1b,0x6f,0xcf,0xed,0x5c,0x26,0x5f,0x88,0x60,0x29,0xbc,0x1d,0xe9,0xc6,0x12,0x76, + 0xd1,0xc8,0x02,0x51,0x95,0xb6,0xc3,0x14,0x65,0x0b,0xa1,0x4d,0x54,0x54,0x25,0x3f, + 0xe9,0xb4,0xcd,0xca,0x81,0xe5,0x22,0xc5,0x8b,0xbc,0x81,0x53,0xa2,0x4b,0x3f,0x70, + 0x76,0x8b,0xe5,0x54,0x57,0x51,0xbc,0x43,0x9b,0x03,0x3d,0x5c,0xab,0xfc,0xd8,0x29, + 0xe6,0xa7,0xec,0xdc,0x9d,0x5d,0x8a,0xca,0x91,0xcb,0x82,0x7a,0x56,0x71,0x67,0x05, + 0x52,0x82,0x5b,0xd7,0x0f,0x88,0xbb,0xe5,0x7b,0xb6,0x0c,0xf5,0x49,0xcb,0xce,0x6c, + 0x17,0x1e,0x6a,0xf3,0xec,0xcd,0xe8,0x1c,0x80,0x0f,0xa6,0xf0,0xd0,0x55,0x70,0x75, + 0x80,0xd4,0x0b,0xe2,0x94,0x8b,0x6d,0xe5,0x62,0x2a,0x77,0x4c,0x8a,0x6b,0x1a,0xb0, + 0x4a,0x64,0x0d,0x8b,0x25,0xee,0x1d,0x11,0xaa,0x34,0x92,0xf0,0x35,0x26,0x0b,0x10, + 0xdd,0xf1,0xae,0xaf,0x09,0xf2,0x03,0xab,0xca,0xdd,0x57,0x5a,0x92,0x0a,0x18,0x54, + 0x6f,0x30,0x7f,0xee,0x27,0xf5,0x85,0xb3,0xba,0xc2,0xb9,0x0e,0x1c,0x89,0x6a,0xaa, + 0x16,0x2b,0x94,0x16,0xa4,0x45,0x9b,0xeb,0x9c,0xb2,0x5d,0xf0,0x3d,0x64,0xb2,0xf3, + 0x8a,0xb6,0x2d,0x3b,0xad,0xc3,0xe2,0x06,0x47,0x25,0x75,0xb5,0x8d,0xec,0x81,0xa6, + 0x61,0x59,0x40,0xcf,0x69,0x9a,0x9a,0xac,0x80,0x22,0xd5,0x59,0x6a,0xd5,0x0f,0x43, + 0xd5,0xa5,0xf7,0xe7,0x83,0xaa,0xa8,0xa6,0x4b,0xdd,0xd6,0xde,0xde,0x21,0xd3,0xdc, + 0x62,0xb7,0xd8,0x28,0x47,0x12,0x90,0x9c,0xf1,0xab,0xe3,0xe9,0xb4,0x62,0xc2,0x82, + 0x46,0xb7,0xa7,0x91,0xc7,0x26,0xc5,0x51,0x67,0x28,0x09,0x7c,0xb8,0x3c,0x17,0x21, + 0x38,0x30,0x54,0x49,0x88,0xcc,0x37,0x4c,0x58,0x0a,0xc2,0x80,0x55,0xce,0xed,0x08, + 0x65,0x04,0xc5,0xf7,0xa1,0x72,0x18,0x0c,0x92,0x0f,0x39,0x25,0xda,0xe1,0xd2,0xfd, + 0x83,0xa5,0xd7,0xf3,0x8f,0x17,0x6f,0x7f,0x35,0x64,0x82,0x91,0x92,0x19,0xbd,0xda, + 0xd4,0x45,0xb2,0x03,0xd0,0x43,0xa3,0x1c,0xdb,0xfc,0xf9,0xf2,0xcc,0xe0,0x97,0x7c, + 0x0b,0x5a,0x02,0x43,0x82,0x3b,0x6a,0x27,0x27,0xf5,0x69,0x38,0x27,0x01,0xe6,0xc3, + 0xfb,0x73,0xd4,0xde,0x21,0x2f,0x28,0xce,0x33,0x34,0x5b,0xba,0xf2,0xcc,0x60,0x21, + 0x07,0xdd,0xed,0x16,0x21,0x72,0xf1,0xa2,0xb8,0x4a,0x28,0xf5,0x8d,0xc4,0x40,0x5a, + 0x00,0xb8,0x5d,0x29,0x53,0xbf,0xf2,0xce,0x8c,0x5f,0x9d,0x38,0xbd,0x29,0xe7,0xc4, + 0x65,0xdc,0x12,0x87,0x7c,0xc4,0x97,0x6b,0xb5,0xd2,0x1e,0x92,0x11,0x14,0x8b,0x65, + 0x54,0xba,0x9e,0x59,0xa9,0x4a,0x39,0xaf,0x20,0x60,0xf2,0xae,0x30,0x3d,0xa7,0x86, + 0x6b,0xef,0x71,0x1f,0x5b,0xcc,0x15,0x3b,0x30,0x04,0x52,0x8f,0xe7,0xfe,0x94,0x31, + 0x2d,0x16,0x13,0xe1,0xe2,0x58,0x06,0xa6,0xef,0x74,0x7e,0x0f,0x74,0x65,0xc5,0x70, + 0x45,0x60,0xb9,0x53,0x29,0x28,0xf3,0x16,0x90,0x44,0xb0,0x3a,0xe6,0x55,0xa2,0x30, + 0x4c,0xfc,0xf1,0xd4,0x73,0x3c,0x12,0xf7,0xc7,0x7c,0x83,0x93,0x8f,0xde,0x06,0x4c, + 0x84,0xf8,0xf3,0xaa,0x52,0x29,0x60,0xc0,0x88,0xb7,0x5a,0x49,0x0b,0x3c,0x51,0x84, + 0x76,0x73,0x5f,0x50,0xa1,0xe4,0xfe,0x31,0xbb,0x2f,0x94,0x1c,0xba,0x0b,0xd2,0x6c, + 0x73,0xde,0x94,0xdb,0xc4,0x44,0x23,0x21,0xd9,0xbb,0xad,0x67,0x96,0xdc,0xa2,0xca, + 0x0d,0xa0,0x10,0x69,0x85,0x7c,0xb9,0xc5,0xa7,0xc8,0x99,0xe3,0x85,0x9e,0x0d,0x78, + 0x95,0x39,0x31,0x91,0xf2,0x78,0x57,0xf4,0xf8,0x0e,0x10,0xd3,0x90,0x1f,0xa1,0xd7, + 0x78,0xcd,0x1d,0xb0,0x33,0x8f,0x48,0x6a,0x0b,0xa3,0xf6,0x46,0x09,0x2d,0x07,0xd9, + 0x1f,0xc6,0x23,0x99,0xdc,0x2e,0x08,0xa0,0x78,0x0f,0x32,0x09,0xa0,0xc2,0xb2,0xcd, + 0x56,0x0f,0x1d,0xa1,0x36,0x13,0x17,0x68,0xf1,0x55,0x3e,0x72,0x9b,0xc1,0x9b,0x9d, + 0x68,0xe3,0x17,0x12,0x36,0x21,0xbb,0xdc,0x82,0xf0,0x40,0x17,0xc9,0xe4,0xc1,0xc1, + 0xde,0x81,0xd0,0x97,0x68,0xf7,0x7d,0xa9,0xc7,0x82,0x0a,0x46,0xbf,0xd6,0x8b,0x57, + 0xb7,0xb8,0x3e,0x8c,0x7e,0x71,0x81,0xf2,0xc2,0x34,0x86,0xb0,0xd4,0x80,0xf1,0x91, + 0x1b,0x9d,0x3c,0x3c,0x10,0x17,0x71,0x89,0x5e,0x66,0x85,0x8b,0xb8,0x6c,0xc3,0x73, + 0xa6,0x8e,0xb8,0x7e,0x6b,0x57,0x5e,0xbf,0xb5,0xcb,0xd7,0x6f,0x09,0xd4,0xcc,0x6f, + 0xd4,0xd2,0x2f,0xd8,0x42,0x29,0x9e,0x51,0x2f,0x35,0xde,0x8c,0xbb,0x07,0x07,0x9d, + 0x57,0x74,0xa5,0x96,0x2d,0x2e,0xdb,0x62,0x42,0xc7,0x55,0xc8,0x35,0x65,0xc6,0xda, + 0x2d,0xa3,0xb8,0x16,0x04,0xbd,0xee,0x61,0xb4,0x34,0x9b,0xf4,0x72,0xb6,0x41,0xea, + 0x9e,0xb3,0x8b,0x7f,0x00,0xb9,0x22,0x3e,0x24,0xdd,0x05,0xc1,0xe9,0xa0,0xa8,0x1b, + 0xe0,0xbb,0xa4,0x4d,0x94,0x98,0x61,0xac,0x71,0x14,0xa6,0x9e,0x9d,0xdd,0x67,0x9f, + 0xf1,0x44,0x13,0x9a,0xb0,0x79,0xf7,0xb2,0xa7,0x49,0xfc,0x19,0x92,0xe9,0x17,0x0d, + 0xc9,0x6d,0x17,0x9a,0xf8,0x8c,0xa5,0x90,0x27,0xb1,0x41,0xaa,0x18,0x79,0x36,0xf3, + 0x73,0x40,0xe1,0x6c,0xbc,0xc8,0x1b,0x64,0x75,0x1b,0xb0,0xe6,0xb3,0xb8,0x9e,0xa9, + 0xe0,0xf6,0x46,0xd6,0x0a,0x81,0x3f,0x58,0xa2,0x02,0x29,0xeb,0xb5,0x3a,0x76,0x36, + 0x0c,0x7a,0x57,0xd7,0x36,0xc6,0xda,0xe2,0xdf,0x7b,0x4c,0x1d,0x83,0x50,0x93,0xf5, + 0x4c,0xd3,0x4e,0x17,0x53,0x4c,0x4e,0xbd,0x00,0x93,0x87,0x8b,0xf4,0xa1,0xc7,0xc7, + 0xea,0x78,0xf6,0x17,0x8a,0x67,0xe0,0x09,0xf9,0xe9,0x49,0xbf,0xc7,0x26,0xf0,0x2f, + 0x11,0xb6,0xe2,0xf4,0x1a,0x5e,0x1d,0x6a,0x74,0x30,0xc8,0xed,0x34,0xa5,0x4f,0x1d, + 0x7e,0x84,0x8e,0xc8,0x53,0x41,0x75,0x48,0x25,0x8c,0x48,0xa1,0xe3,0x52,0x9d,0x52, + 0x7b,0x5f,0x0a,0x3b,0x15,0x41,0x07,0x06,0x37,0x57,0x7b,0x68,0x3c,0xbd,0x34,0x77, + 0xf0,0x69,0xc7,0x7c,0x32,0xe5,0x09,0xe1,0xcd,0x55,0x17,0xa3,0xf7,0x76,0x2d,0x71, + 0x89,0x30,0x70,0xd2,0xa8,0x2c,0x86,0x7c,0xb0,0x3c,0x6f,0xae,0x3a,0xd7,0xd7,0x96, + 0x9e,0xaf,0x93,0xe7,0x4b,0x55,0xbe,0x1d,0xd3,0x30,0x29,0xef,0x0e,0x36,0x76,0x9d, + 0x3b,0x93,0x14,0xed,0xc1,0x97,0x8d,0x42,0x1b,0x25,0x5b,0x0a,0x54,0x87,0x16,0xec, + 0x3b,0x4a,0x16,0xe3,0x58,0x6d,0xa1,0xed,0x62,0x79,0x23,0xaf,0x40,0xa6,0xc0,0x6a, + 0xec,0xec,0xf5,0x8d,0x92,0xc1,0xf8,0x13,0xd5,0xf4,0xa4,0x6c,0x64,0xc3,0x41,0xa7, + 0x1f,0xea,0x36,0xb2,0x21,0xd9,0xc8,0x4a,0x32,0x51,0x7f,0x33,0x57,0x61,0x20,0x6c, + 0x28,0x1b,0xee,0x98,0x8e,0xb9,0x33,0x41,0xb0,0x49,0x83,0x58,0x8c,0x10,0x86,0x49, + 0x0c,0xc4,0x42,0xe7,0xcb,0x65,0x08,0x84,0xf5,0xe5,0xa4,0xab,0x3c,0xa1,0xc2,0x20, + 0xeb,0xe7,0x18,0x93,0xf7,0x59,0xb9,0x5d,0x16,0x0c,0x02,0x20,0xe7,0x9b,0x70,0x31, + 0x6f,0xf2,0xcd,0x27,0xe4,0xa3,0x38,0x80,0xe7,0xc2,0xdd,0x5c,0xc2,0x1a,0xb6,0xf9, + 0xdb,0xdd,0x8e,0xf5,0xf5,0xae,0x88,0x70,0x25,0x6e,0xaf,0x16,0x17,0x45,0x09,0xda, + 0x28,0x91,0x52,0xbb,0x3e,0xae,0x7c,0x35,0xb2,0x72,0xeb,0xc4,0xd5,0x8d,0x87,0xc0, + 0x51,0x38,0x72,0x33,0x18,0xb2,0xbc,0x12,0x8d,0xad,0x86,0x05,0x4a,0xc9,0xfa,0x05, + 0x0d,0x91,0xf5,0x93,0xec,0xaf,0xb2,0xca,0x3a,0x14,0x6d,0xc8,0xe3,0x88,0xb2,0x35, + 0x3e,0x9d,0x29,0x8b,0x38,0xfc,0x65,0xf3,0x1c,0xce,0x58,0x42,0xc3,0x93,0x2b,0xb3, + 0x03,0xd5,0x77,0xe1,0x6f,0x0f,0xfe,0xf6,0xe1,0xef,0x00,0xfe,0x0e,0xe1,0xef,0x25, + 0xfc,0x1d,0xc1,0xdf,0x2b,0xf8,0xc3,0x50,0x00,0xe4,0xe2,0x6b,0x76,0x30,0x6b,0x67, + 0xcf,0xbc,0x16,0xd7,0x70,0x15,0x7d,0x64,0xd5,0x0a,0x14,0x36,0xc4,0x6c,0x62,0x0d, + 0x7d,0x92,0x1f,0xae,0xfc,0x6b,0x98,0x60,0xe8,0x1e,0x4e,0x83,0xe8,0xba,0xfe,0x0d, + 0x56,0x66,0xf1,0x55,0x52,0xa6,0x47,0x75,0xf1,0xd7,0x53,0x79,0xc8,0x85,0x29,0x1e, + 0xcd,0x22,0x20,0x23,0xa9,0xad,0xdd,0x03,0x8f,0xf7,0x87,0x53,0x60,0x4d,0x2f,0x99, + 0xb7,0xe0,0x45,0xd2,0x38,0x37,0x7b,0x13,0x8e,0x07,0x78,0x3b,0xb8,0xf4,0x8d,0x8a, + 0x77,0xf0,0x8d,0x23,0xb4,0xfd,0x48,0xf1,0x6e,0x8e,0xb5,0xef,0x9c,0xd2,0x92,0xa7, + 0xe4,0xe3,0x95,0x57,0x61,0x8d,0xfd,0x5b,0x8a,0xec,0xa4,0xdd,0x84,0x05,0x5d,0xea, + 0x8f,0x8b,0x56,0x25,0xf0,0xdc,0x6f,0x60,0xed,0xfa,0xfd,0x56,0x78,0x57,0x0a,0x99, + 0xb5,0x35,0xa9,0x27,0x98,0x46,0x27,0xd0,0xd2,0x6e,0x1e,0xc3,0xcd,0xe2,0x17,0x3e, + 0x60,0xe6,0x32,0xf8,0x3e,0xf1,0x93,0x34,0xa3,0x57,0x46,0x27,0x1a,0x9b,0x55,0x18, + 0x5b,0x65,0x24,0x79,0x0c,0xda,0x32,0x14,0x7f,0x70,0x31,0xea,0x32,0x0f,0x52,0x02, + 0xd5,0x9c,0x92,0xce,0x5f,0xdd,0xc2,0x64,0x8c,0x8b,0x65,0xe8,0x32,0x66,0x11,0x00, + 0x25,0x87,0xb4,0xee,0xb6,0x6a,0xe2,0x6a,0xfd,0x16,0xb1,0x11,0x23,0x7d,0xa9,0x7c, + 0x3e,0x87,0x2c,0x86,0x55,0xd1,0x2c,0x06,0xad,0x52,0x79,0x97,0x0d,0xd5,0x89,0xf4, + 0x01,0xc5,0x2b,0x69,0x4c,0x89,0xb1,0x30,0xf1,0xea,0x9c,0x7f,0x60,0x2e,0xbc,0x7b, + 0xac,0x90,0x0d,0x51,0x1d,0x75,0xd2,0x1c,0x99,0x86,0xe3,0x13,0x62,0x1a,0x49,0x5e, + 0x9c,0xd8,0x80,0x85,0x7f,0x7b,0xf2,0xdb,0x78,0xe7,0x37,0x47,0xfe,0xa3,0xd9,0x40, + 0x4f,0xee,0x28,0xd7,0x09,0x16,0xa5,0x7b,0xb9,0xe4,0x91,0xca,0xc7,0xcb,0x53,0x3a, + 0x97,0xc9,0x4f,0x77,0x34,0xc7,0x1b,0x28,0x88,0x3a,0x0c,0x0a,0x6b,0x84,0x67,0x20, + 0x66,0xb5,0xff,0x17,0xca,0xe8,0x15,0xd9,0x0b,0xe0,0x7a,0x50,0x75,0x87,0xfc,0x4c, + 0xcc,0x34,0x9b,0xaa,0x15,0x27,0x37,0xec,0xf8,0xc5,0x16,0x07,0xe6,0x4e,0xc3,0xfc, + 0x2d,0x3f,0xb3,0x7a,0x1d,0x7a,0x77,0xc7,0xc2,0xe8,0xf6,0x37,0x71,0x76,0xf2,0x9b, + 0xe9,0xc0,0xf3,0xeb,0x16,0x9f,0xbf,0xc0,0x47,0x9e,0xad,0x54,0x9e,0xdd,0x4e,0x17, + 0x3e,0x9e,0x00,0xa3,0x95,0x75,0xea,0x98,0x92,0x9a,0xea,0x9d,0xbb,0xc4,0x03,0xe8, + 0x99,0x17,0xc4,0xe2,0x48,0x2a,0x5d,0xcc,0xe7,0x6e,0xf2,0x20,0x38,0x16,0x3c,0xde, + 0xf3,0xef,0xa9,0x49,0xd8,0xb9,0xb1,0x56,0x79,0x1d,0xbd,0x53,0xb2,0xeb,0x87,0x6a, + 0x7f,0x84,0x5a,0xc4,0xf4,0x11,0x4a,0x69,0x33,0x34,0x9a,0x23,0xc3,0x87,0xcd,0x98, + 0x7a,0x32,0x80,0xc0,0xb4,0x1b,0x68,0x73,0x02,0x5b,0x1e,0x4d,0x14,0xfc,0xf2,0x81, + 0x29,0xff,0x27,0x8f,0x24,0x6c,0x63,0x22,0x2d,0x52,0xb0,0x2f,0x28,0x09,0xfe,0x16, + 0x22,0x7c,0x70,0x13,0x7a,0x0d,0xd4,0xe5,0xd8,0x28,0xff,0x87,0x3a,0x3c,0xc8,0xac, + 0xec,0x9a,0x39,0x7f,0xaa,0xf2,0xbf,0xa6,0x83,0xdf,0xbc,0x9c,0xb8,0xb5,0xa9,0x52, + 0x42,0x68,0x20,0x6b,0xfe,0x4b,0x2b,0x76,0x0e,0x5c,0x22,0x37,0xb2,0x28,0xff,0x17, + 0xd6,0x98,0x97,0x70,0x19,0x36,0x5c,0x81,0xd1,0xe7,0x16,0x06,0xa2,0x0c,0xe4,0x0e, + 0x00,0x19,0xa4,0x5e,0x28,0x1f,0xb6,0xa6,0x74,0xd2,0x9a,0x88,0xa5,0xf2,0x49,0x30, + 0xe7,0xb9,0x0e,0x4a,0x14,0x15,0x3c,0x41,0xcd,0x7f,0x49,0xf9,0x14,0xae,0xb2,0xc6, + 0x4c,0x44,0x02,0x89,0x01,0x29,0xc1,0x4a,0x60,0x48,0xd3,0xdc,0xc9,0xb9,0x3b,0x41, + 0xbe,0x60,0x11,0xa2,0xb8,0x8c,0x41,0x3e,0x8c,0x9b,0x10,0x5d,0x7d,0x1c,0xc2,0xe9, + 0x73,0x5a,0x01,0x29,0x5a,0x9d,0xc3,0x22,0x43,0x55,0x26,0xe1,0x6b,0xb2,0xa0,0x53, + 0xc8,0x39,0x6b,0xfb,0xe9,0x60,0xc8,0x73,0x98,0xe3,0x36,0x80,0xb1,0xcf,0xe8,0x32, + 0x79,0xd4,0xed,0x08,0x17,0x57,0xe9,0x81,0x52,0x21,0x2b,0x65,0xbc,0xbc,0x58,0x4c, + 0x3f,0x02,0xcd,0x6d,0xaa,0x4d,0xfa,0x2b,0x55,0x0c,0x78,0xd9,0x82,0x0d,0x1b,0x32, + 0xcb,0xae,0x1f,0xa6,0xb9,0xbd,0x5b,0x01,0xc1,0x21,0x0d,0x2a,0xd3,0xc9,0x5e,0xb9, + 0x02,0x3d,0xaa,0x5e,0x29,0x53,0x99,0x36,0x3a,0x90,0x3c,0xb8,0xba,0xe6,0x47,0x2f, + 0x18,0xb4,0x3a,0xc5,0xd6,0xde,0xa1,0x97,0x49,0x73,0xe6,0x3e,0xd8,0xbf,0x17,0x1c, + 0xd1,0x7f,0x17,0x9b,0xe4,0xee,0x6f,0xe9,0xce,0x6e,0x25,0x6e,0x05,0xe5,0x29,0x6c, + 0xc8,0xe8,0x43,0xc2,0x5e,0xe7,0xd7,0x5b,0x5b,0x50,0x9d,0x43,0x96,0x0f,0x1f,0xf3, + 0x54,0xeb,0x75,0xbb,0x10,0xc9,0xe2,0x69,0x65,0x24,0x0b,0xe8,0xd5,0x7b,0x62,0xa0, + 0x40,0x98,0x90,0x61,0x26,0x06,0xf0,0xac,0x5d,0xb4,0x83,0x9d,0xa2,0x7d,0x83,0x7d, + 0x7b,0x44,0xc5,0xcb,0x40,0x08,0x13,0x80,0x2e,0xbd,0xf6,0x13,0x6f,0xa9,0xb7,0x29, + 0x6e,0x37,0x14,0xf9,0x93,0x6b,0x4d,0xb9,0xd4,0xad,0x12,0x02,0x6e,0x53,0xce,0x19, + 0x44,0x83,0xd4,0xc9,0xa2,0x77,0xa8,0x37,0x66,0x37,0x35,0xac,0x08,0x5d,0x50,0x03, + 0x04,0x12,0x42,0xb1,0xa1,0xa1,0x5f,0xd5,0x95,0x5f,0x74,0x36,0x1b,0x78,0xc0,0x8f, + 0x14,0x6b,0xa2,0x26,0x33,0x05,0x94,0x20,0xc2,0x80,0x51,0x6d,0x0b,0xea,0x67,0xa6, + 0xd5,0xd3,0x2e,0xe6,0xf9,0xff,0x7a,0xbb,0xda,0xe6,0xb6,0x8d,0x23,0xfc,0x5d,0xbf, + 0x42,0x42,0x52,0x95,0x30,0x29,0x8a,0x72,0x6d,0xb7,0x25,0x05,0x71,0x9c,0xa6,0xee, + 0x68,0x9c,0xb8,0x1e,0x7b,0xd2,0x7e,0xb0,0xec,0x19,0x4a,0x84,0x24,0x8e,0x48,0x90, + 0x21,0x20,0x4a,0x2a,0xc9,0xff,0xde,0x7d,0x76,0xf7,0xde,0x00,0x90,0xd4,0xa4,0x2f, + 0x99,0x8c,0x45,0x00,0xf7,0xba,0x77,0xb7,0x77,0xbb,0xb7,0xfb,0x2c,0xd7,0x66,0x80, + 0x55,0x5f,0x75,0x0e,0x0f,0xed,0x30,0x15,0xd4,0x92,0x38,0x96,0xef,0x36,0x9b,0x8a, + 0x02,0x28,0x4a,0xcd,0xf1,0x7d,0x6a,0xe0,0xb5,0xf1,0x88,0x7b,0xd3,0xe1,0x1e,0x75, + 0xcd,0xc8,0x59,0x4f,0x05,0x49,0x2a,0xe5,0x9a,0xc4,0xaf,0x34,0x31,0xe8,0x18,0x0e, + 0x4e,0x40,0x4b,0x73,0xec,0xcd,0xed,0xa1,0x97,0xf8,0x1a,0x0d,0x4f,0xe3,0xe2,0x73, + 0x33,0xc6,0xdf,0xf6,0x0b,0x7b,0xec,0x3d,0x98,0xc4,0xc1,0x31,0xcb,0x4a,0x4f,0xe6, + 0x1c,0xcd,0x61,0x66,0x25,0x29,0xde,0x6f,0x1b,0x56,0x62,0x58,0x43,0x06,0x61,0x96, + 0xd6,0x9a,0x2e,0x1d,0x4d,0x48,0x8c,0x32,0x74,0x68,0x41,0x58,0x1e,0x26,0x78,0xa5, + 0x12,0x28,0x9d,0xda,0xf8,0x5d,0x9b,0x96,0x52,0x71,0xae,0x83,0x21,0x12,0x2a,0x44, + 0xc5,0xfb,0x02,0x00,0x1b,0x4b,0x94,0xdd,0xd4,0x84,0xa6,0x02,0xfa,0xd6,0x3c,0x89, + 0x7b,0x52,0xa2,0xff,0x49,0x3e,0xac,0xcd,0x0c,0x92,0x4f,0xe1,0x2c,0xc2,0x61,0xf1, + 0x0b,0x37,0x61,0x5c,0x13,0x11,0x7a,0x21,0xa7,0xd9,0x45,0x98,0xa9,0x32,0x55,0x70, + 0xd2,0x12,0xf9,0x86,0x9b,0xb7,0x68,0x99,0x91,0xf8,0x30,0x2d,0x52,0xa6,0x5c,0x6b, + 0x11,0x1b,0x71,0xc6,0x27,0x1c,0x65,0x64,0xca,0x21,0x9b,0xe1,0x99,0x4a,0x04,0x33, + 0x0b,0x6a,0xc6,0x97,0x4b,0xa5,0x2d,0xac,0x45,0x8d,0xd6,0xb8,0x5b,0xbe,0x38,0x13, + 0x46,0x24,0xc5,0xc1,0x1b,0xa6,0xaf,0x01,0x8f,0xf0,0xc4,0x98,0xf2,0xc9,0xdd,0x7d, + 0x22,0xc6,0xd0,0xd6,0xf8,0xcd,0xa8,0x08,0x9c,0x71,0x94,0xa9,0x7b,0x7a,0x29,0x55, + 0x18,0xcd,0xda,0x38,0x9b,0x8b,0xd5,0xe1,0x40,0xe3,0xc2,0x6f,0xcb,0x67,0xa3,0x57, + 0x97,0xb3,0x1a,0xd5,0x11,0x6f,0xfa,0x9e,0x7f,0xbb,0xef,0xa8,0x6e,0x58,0xc5,0x60, + 0xec,0xc2,0xad,0x46,0xb4,0x69,0x2c,0xd4,0x0e,0x96,0x37,0xc3,0xfb,0x0c,0xb7,0x37, + 0x51,0xb7,0xa1,0xc9,0x5c,0xf0,0x6e,0x73,0xa6,0x53,0x55,0x21,0xef,0x99,0x97,0x4f, + 0xfb,0xb7,0xc0,0x5e,0xea,0xaa,0xf3,0x62,0x99,0xc4,0x22,0xb5,0x95,0x48,0x2c,0x02, + 0xb5,0x95,0xd5,0xec,0x2c,0x01,0xf1,0x9c,0xdc,0x06,0x4c,0x15,0x2a,0xd7,0x53,0x19, + 0xe1,0x98,0xaa,0xad,0xf2,0x54,0x34,0xfd,0x93,0xd7,0x5d,0x86,0xa6,0xa8,0x77,0xca, + 0x97,0x5d,0xad,0x61,0xd7,0xb8,0x65,0xcc,0xe1,0x86,0xc8,0x47,0x1c,0xd9,0xc5,0x79, + 0xb7,0x99,0xb4,0x31,0xef,0xbc,0x1d,0xc7,0xc4,0x8f,0x7d,0x4c,0xc2,0xcd,0x4a,0x99, + 0x02,0x27,0xb7,0xae,0x44,0xfe,0x0e,0x18,0x78,0x30,0xde,0xb2,0x77,0x9e,0xa6,0xae, + 0x32,0x5f,0x0b,0xb9,0xcc,0x9c,0x01,0xae,0xfe,0xcc,0x85,0xcd,0xfa,0x9d,0x60,0x4e, + 0xc4,0xc4,0x12,0x06,0xa3,0x71,0xf9,0xab,0x7e,0xeb,0xed,0xdd,0x36,0x93,0x00,0x45, + 0x20,0xbf,0x51,0x80,0xca,0x91,0x05,0x04,0xe2,0xb0,0x17,0x92,0xa3,0x1f,0x9d,0xde, + 0x9f,0x45,0x4d,0x5e,0x8e,0xd1,0xe9,0x31,0xfd,0xe6,0x35,0x16,0x37,0x51,0x87,0xa2, + 0xdc,0x90,0x34,0x90,0xd2,0xd2,0xec,0xff,0x9e,0xc1,0x08,0xa4,0x5e,0xe2,0x71,0x02, + 0x4a,0x60,0xa0,0x28,0x05,0x8a,0x40,0x56,0x2e,0x51,0xc9,0x47,0xff,0xe9,0xe1,0x79, + 0x23,0xd0,0x2f,0x3e,0x3a,0x59,0xac,0x53,0x1e,0xbc,0x8f,0x03,0x0e,0x95,0xb3,0xd4, + 0x78,0x2e,0x4a,0xf7,0xfd,0x36,0x7b,0x16,0xd4,0x20,0xd1,0x58,0x12,0x4e,0xb3,0x64, + 0x04,0x40,0x43,0x19,0xc1,0xfa,0xe0,0x40,0x50,0xff,0x4f,0x33,0x19,0xc3,0x69,0xc6, + 0x40,0xc7,0xd2,0x94,0xf3,0xac,0x98,0xfe,0x63,0x94,0x3e,0xc4,0x95,0x37,0x8d,0x25, + 0x1b,0x44,0x77,0x69,0xe5,0x0d,0x70,0x0c,0xe4,0x00,0x50,0xeb,0xca,0x49,0xea,0x67, + 0x74,0x71,0x68,0x7c,0x4f,0x64,0x52,0x85,0x5b,0x9b,0xce,0x35,0x9a,0x5c,0xfa,0x97, + 0x26,0x7c,0x03,0x51,0x4f,0x3a,0xdd,0x30,0xfd,0xd1,0x49,0xdc,0x6d,0x68,0x9a,0xe6, + 0xb0,0x59,0x2a,0xec,0x77,0xe1,0x33,0x97,0xaa,0x34,0x2b,0xb7,0xe9,0x2d,0xbb,0x42, + 0x36,0x0c,0x81,0xd2,0x44,0xb3,0x12,0x87,0x61,0xb0,0xcb,0x34,0x00,0xbb,0x1c,0x65, + 0xb3,0x24,0x58,0x23,0x44,0xa5,0x6c,0xa6,0xfe,0xbf,0x98,0x78,0x3d,0x3c,0xda,0x83, + 0x24,0xca,0xba,0x1d,0x3d,0xf2,0x4a,0x31,0x6b,0xae,0xc7,0x87,0x65,0x09,0x6d,0x66, + 0x90,0xfc,0x07,0xe6,0xa4,0x2b,0x1e,0x67,0xc5,0xe0,0x8e,0x8f,0xc7,0xfb,0x83,0xf9, + 0x0d,0xeb,0x0c,0xd8,0x08,0x7a,0x7a,0x7d,0x0d,0x9b,0x28,0x09,0x81,0x56,0xea,0x05, + 0x1d,0x5d,0xde,0xa7,0x4f,0x8d,0x7a,0xd2,0x2e,0x6d,0xd5,0x1b,0xe9,0xbe,0x36,0x0a, + 0xd5,0x1c,0xa8,0x98,0xec,0x64,0x60,0x28,0xa3,0x6f,0xc3,0x25,0x0b,0x34,0xb0,0x1a, + 0x5e,0x51,0x73,0x90,0x6b,0x8d,0xaf,0x66,0x96,0xa6,0x1d,0xe8,0x73,0x2c,0x3f,0xd9, + 0x7c,0xd0,0xca,0x68,0xca,0x8b,0x62,0x23,0x3b,0xa5,0xfc,0xda,0xd6,0xc3,0xc3,0xec, + 0x94,0x17,0xb7,0x79,0xc4,0x27,0x5c,0x48,0xbe,0x2d,0x1a,0x19,0xf6,0x52,0xfe,0x68, + 0x5f,0xc4,0x19,0x22,0x5b,0xa2,0x7a,0xa4,0x33,0xec,0xc2,0x03,0xec,0x71,0x25,0x9f, + 0x51,0x7f,0x2c,0xb5,0x6a,0xfa,0x85,0x12,0x7a,0x96,0x8a,0x86,0x10,0x8e,0x46,0x1d, + 0x17,0xbe,0xc9,0x1d,0xd8,0xab,0x88,0xab,0x93,0x29,0xb6,0x11,0xb6,0x1b,0x0c,0x50, + 0x57,0xd3,0x05,0xb8,0x0e,0xd2,0xfe,0x28,0x3e,0xde,0x8d,0x78,0xed,0x4b,0x27,0x9b, + 0xca,0xdb,0x88,0xe0,0x3a,0xaf,0x45,0x70,0x05,0x77,0xe8,0x89,0x8b,0xb0,0xb7,0xda, + 0xb4,0x0b,0xcd,0xb9,0x85,0x9c,0x1a,0x55,0x02,0xc8,0xd3,0xea,0xc1,0x01,0x85,0xcd, + 0x46,0xac,0xee,0x1d,0x0a,0xfe,0x2f,0xe6,0x87,0xc3,0x92,0xa7,0x0d,0x9f,0xd3,0xd9, + 0x2f,0x33,0x9b,0xb5,0xe7,0x67,0xf5,0x22,0x26,0xd8,0x57,0x1a,0x38,0x21,0x5c,0x38, + 0x65,0x21,0x2a,0x2f,0x2c,0x1f,0xd9,0xb4,0x24,0x75,0x9a,0x7b,0xd5,0xd8,0x1e,0xdb, + 0x16,0x3c,0x9e,0xca,0x34,0x6f,0xf3,0xcd,0x44,0x62,0x97,0x71,0xcf,0xd4,0x5d,0x2a, + 0x61,0x6d,0x1a,0xd5,0x4c,0x86,0xa5,0x62,0x4c,0x8e,0x8e,0xff,0xfe,0xac,0x5c,0x80, + 0xd4,0xa6,0xbd,0x72,0x5c,0xc3,0x36,0x61,0xad,0x72,0x42,0xf0,0xc5,0x23,0xf2,0xa3, + 0xac,0x1c,0xb7,0x87,0xea,0x52,0xb1,0x19,0x2c,0xb7,0x2b,0xe6,0x4f,0x4b,0xbc,0xa5, + 0xc1,0x14,0x10,0x3e,0xa2,0x1d,0x43,0x74,0x36,0x32,0x9a,0xff,0x6b,0x71,0x30,0xa2, + 0x91,0x5c,0xfb,0x93,0x96,0x67,0x7b,0x75,0x8e,0x29,0x86,0x94,0xe7,0x8e,0xe4,0xf5, + 0xc2,0x2c,0x89,0x75,0x45,0x96,0xae,0x16,0x04,0xcc,0xfe,0xa0,0x1c,0x0f,0xae,0xdb, + 0x75,0xab,0x75,0xf2,0xb2,0xf3,0xac,0xe2,0x98,0xc7,0x96,0xdb,0xf5,0x6e,0x54,0x3c, + 0xaf,0x31,0x74,0xe8,0xaa,0x59,0x87,0x26,0xc6,0x23,0x1b,0xb7,0xca,0xdd,0x0d,0xce, + 0x55,0xc4,0x5c,0xa3,0xda,0x45,0xda,0xf3,0x38,0xaf,0x8f,0x99,0xc0,0xb9,0xde,0x02, + 0x44,0xf3,0x97,0x59,0xb4,0x5a,0xb9,0x47,0x58,0x60,0x47,0x26,0xfc,0x47,0x52,0x7a, + 0xdf,0x3f,0xe9,0x62,0xba,0xd7,0xd5,0xa3,0xd3,0xca,0x6a,0x22,0x62,0xb7,0x99,0x4a, + 0xc8,0xb3,0x70,0x61,0x94,0xbc,0xab,0xb9,0x9e,0xbf,0x66,0x7c,0x53,0xb0,0x7c,0x56, + 0xf9,0x2c,0x99,0x3e,0x67,0x2f,0xe0,0x4c,0x08,0xf3,0x19,0xc4,0x37,0xb6,0x75,0xe6, + 0x57,0x83,0x99,0x09,0xb2,0x1c,0xb4,0xbf,0xfe,0x30,0x88,0x03,0xb7,0x8d,0x21,0xd9, + 0xf3,0xe6,0x59,0x50,0xb4,0x94,0x3d,0x36,0x84,0xfd,0x29,0xa2,0xe6,0x52,0xa7,0xae, + 0x8a,0xf9,0xf8,0x3d,0xae,0x6b,0x36,0x0c,0x94,0xaa,0x9c,0xd7,0x7b,0xcf,0x99,0x1f, + 0xac,0x65,0xad,0x9b,0x1d,0x57,0x0c,0x8e,0x4d,0xc5,0xcd,0x58,0xdf,0xf8,0x23,0x20, + 0x53,0x56,0xaa,0x51,0x0a,0xde,0x9a,0x98,0xca,0xc1,0xf1,0x01,0x6a,0xfc,0xe4,0xea, + 0x12,0x38,0xd9,0x48,0xd3,0xe0,0xd8,0x06,0x51,0x6c,0x71,0xde,0x0e,0x8e,0xbf,0x5c, + 0xcc,0x2f,0xb2,0xaf,0x2a,0x1a,0xf0,0xb5,0x84,0x2d,0xa0,0x76,0xe0,0xb8,0x4d,0x93, + 0x21,0x4b,0xda,0x1f,0x07,0x73,0xa8,0x12,0x90,0x49,0x3f,0xc0,0x02,0x31,0x71,0x54, + 0x95,0x71,0xc6,0x4b,0x8d,0x90,0x42,0xe3,0x4c,0x79,0x1d,0x7f,0xa2,0x07,0x5c,0xb8, + 0x70,0x92,0xa6,0x3e,0xf5,0x82,0x51,0x59,0x4b,0xb7,0x82,0x5c,0xa1,0x8e,0xef,0x83, + 0x06,0x1f,0x52,0x95,0xdc,0xd1,0x91,0x9c,0x69,0x44,0x6f,0x7d,0x9b,0x8e,0xe1,0xc7, + 0x6d,0x15,0x7b,0xed,0x28,0x58,0x38,0x5e,0xb9,0x09,0x6e,0x4c,0x97,0x5e,0xdd,0xa6, + 0x39,0x75,0xdb,0xb0,0xc7,0x13,0x31,0xd2,0xea,0xd5,0x8c,0x1c,0x75,0x5b,0x99,0x23, + 0x93,0xbb,0xf2,0x81,0x14,0x8f,0x57,0x56,0x39,0x46,0xc3,0xb0,0xba,0x98,0xaf,0x2e, + 0xb2,0xe3,0x9a,0x13,0xb5,0xd3,0x5f,0x8d,0x59,0x7f,0x25,0xd4,0x94,0x21,0x1c,0xaf, + 0x56,0x63,0x73,0x08,0xe9,0xe0,0x54,0x12,0x7d,0x67,0x04,0xd3,0x5e,0x45,0x67,0x4a, + 0xc7,0x40,0xb6,0x0c,0xc8,0x15,0xb2,0x02,0xe8,0xdc,0x45,0xbe,0x37,0x4e,0xc6,0xde, + 0x51,0xaa,0xd1,0xef,0x7e,0x39,0xfb,0xfe,0xeb,0x0a,0xc6,0xc1,0xd0,0xec,0x5e,0xe4, + 0x2f,0xe8,0xf9,0xbb,0xaf,0xb1,0x55,0x96,0xa1,0x9c,0x62,0x3a,0x66,0x23,0x52,0xa8, + 0xdd,0x07,0x6c,0x44,0xce,0xe6,0xe7,0x57,0xf3,0xd1,0xac,0xe0,0xd3,0x8e,0x53,0x34, + 0x8c,0x03,0x65,0x02,0xfa,0xef,0x3b,0x77,0x7e,0x3a,0xff,0xfc,0x1e,0x26,0x1e,0xc7, + 0xdf,0xd8,0x61,0xe1,0xfb,0xe3,0x96,0x78,0x2e,0xe4,0x75,0x2e,0x0b,0xe2,0xa9,0x13, + 0x78,0x2e,0xf8,0xe6,0xae,0xce,0x8b,0xa1,0x85,0x02,0xad,0x4b,0x06,0x95,0x29,0x82, + 0x7c,0xc9,0xc7,0x49,0x75,0xc8,0x79,0xe8,0xca,0x71,0xfc,0xcd,0xcf,0x55,0x9b,0xa0, + 0x61,0x7c,0x2d,0x56,0xc6,0x37,0x23,0xa6,0xd4,0x62,0x3a,0x5a,0x75,0xe0,0x38,0xfe, + 0xe6,0x1c,0x63,0x28,0xd9,0x50,0x1d,0x63,0x72,0xe7,0x19,0x03,0x5f,0x9a,0xf4,0xc1, + 0x5e,0x1b,0x04,0x8e,0x31,0xb9,0x96,0x11,0xba,0xa9,0x80,0x4e,0x78,0x93,0x57,0x1c, + 0x55,0x58,0x73,0xb6,0x2f,0x18,0x4d,0x0d,0x98,0xc4,0xae,0x66,0x0f,0x43,0x1a,0x3c, + 0xca,0xa0,0x08,0x49,0x72,0x5f,0xcf,0x4b,0x25,0xf0,0x8d,0x47,0x08,0x17,0xaf,0x88, + 0x12,0xbe,0x53,0x50,0x42,0x51,0x81,0x79,0x38,0xf6,0x8d,0x00,0x42,0x78,0x06,0x98, + 0xa9,0x30,0x68,0x8b,0xb1,0x18,0x98,0xa5,0x80,0xdb,0xc9,0x04,0x10,0x46,0x21,0x11, + 0x26,0xf7,0xb9,0xc1,0xf6,0x73,0x4d,0x60,0x53,0xfe,0xa0,0xe2,0x79,0xd9,0x69,0x83, + 0x0a,0x1f,0xec,0x3f,0xcc,0x61,0xde,0xcf,0x2b,0x57,0xc5,0x19,0x67,0x57,0x09,0x1f, + 0x19,0x63,0x97,0xe9,0x4a,0x86,0x53,0x47,0xa5,0x47,0xd7,0xd6,0xc5,0xe3,0x37,0x94, + 0x6a,0x34,0x3e,0x95,0x52,0x4b,0x80,0x87,0xae,0x0d,0xb3,0xf9,0xe2,0x02,0x7b,0x3f, + 0xe7,0xd0,0x05,0x98,0x6f,0x98,0xd0,0x01,0x70,0x35,0xb1,0x95,0x4f,0xa3,0xfc,0x2e, + 0x17,0x9e,0xb3,0xf4,0x23,0x7c,0x58,0x25,0x21,0x33,0xb7,0x6a,0x80,0x00,0xb5,0x98, + 0xc0,0xaa,0xab,0x61,0x34,0x8a,0x96,0xc9,0x6a,0x67,0x6c,0x09,0xc0,0x64,0x3c,0xe0, + 0xc8,0x1f,0x73,0x36,0x72,0x58,0xba,0xdf,0xc9,0x49,0xcf,0xae,0x70,0xbc,0xd0,0xad, + 0xae,0xba,0xd0,0x83,0x8b,0x58,0x9f,0x57,0x2a,0x3b,0xa4,0x99,0x91,0x78,0x9c,0xf8, + 0x4c,0x3d,0xbe,0x45,0x21,0x40,0x1f,0x63,0xd9,0x70,0x90,0xc2,0x48,0x55,0x9a,0xc4, + 0xa0,0x01,0x82,0x14,0x49,0x48,0x93,0xd6,0x34,0x4b,0x93,0x12,0x7f,0xef,0x6d,0xb8, + 0x71,0x6f,0x41,0xa3,0xb4,0xe3,0xbe,0xdc,0xaa,0x4f,0xf8,0xc6,0x3c,0xe2,0xcc,0x57, + 0xd7,0x13,0x03,0x49,0xbd,0x23,0xfb,0xad,0x9f,0x17,0xd8,0x95,0xb7,0xc1,0x75,0x3b, + 0xb5,0xb5,0x1f,0x7d,0xe2,0x0b,0xa5,0x51,0x6e,0x36,0xab,0x7e,0xd4,0x6d,0xe8,0x4b, + 0x62,0x5d,0xfb,0x51,0xd3,0xeb,0x8d,0x7f,0x57,0x45,0x53,0x8b,0xa3,0xf3,0xf4,0x4d, + 0x33,0xfd,0x2b,0x7b,0x03,0xe7,0xfc,0x60,0x63,0x41,0x78,0x5b,0xa9,0x3d,0xc0,0xb3, + 0xfa,0x07,0xd1,0x3f,0x70,0x84,0x37,0x31,0xce,0x10,0xde,0x8c,0x4e,0xac,0x8d,0x87, + 0x26,0xf0,0xef,0x68,0x55,0xc6,0x1b,0xe7,0x94,0xd5,0xf7,0xec,0x32,0x3b,0xf0,0xad, + 0x0e,0xa2,0x71,0x16,0x19,0x99,0x62,0x53,0xae,0x1c,0x95,0x66,0x21,0x1a,0x16,0xf8, + 0x24,0x9d,0x62,0x07,0x4f,0x8d,0x87,0x23,0xed,0xd4,0xa8,0x79,0x62,0x6f,0xf1,0x4e, + 0x62,0x8b,0xfc,0x03,0x00,0x46,0x7c,0x22,0x6a,0xed,0x47,0x30,0x79,0xf0,0x29,0x93, + 0xa1,0x35,0x81,0x75,0x43,0xd8,0x06,0xc4,0x2e,0x83,0x75,0x03,0x2d,0x81,0x1a,0xba, + 0x0e,0x9d,0x58,0xcf,0x53,0xd4,0x5c,0xd8,0x6c,0xef,0x7e,0xe1,0x77,0xff,0x21,0x82, + 0xa5,0x51,0x00,0x6e,0xf1,0x77,0x78,0xcb,0xc8,0xae,0x37,0xcf,0x61,0x5f,0xa4,0xf3, + 0x9c,0x3a,0x20,0xf7,0x8e,0x82,0x5d,0xc0,0xbe,0xb2,0x43,0xe1,0xdf,0x29,0xef,0x61, + 0x02,0x64,0x03,0xf6,0x3d,0x93,0xe0,0x82,0xe5,0xf6,0x16,0x46,0x33,0xcc,0x6b,0xc5, + 0xc1,0x2d,0x89,0xf4,0xbe,0xbd,0xd5,0xf3,0x72,0xab,0xe7,0x61,0xab,0xff,0xf9,0xf6, + 0xd3,0x87,0xf3,0x0f,0x7f,0xeb,0x0a,0xd2,0x4a,0xd4,0x94,0x2a,0x64,0x0c,0x7a,0xcc, + 0xe5,0x19,0x7e,0xa7,0xa6,0x55,0x73,0xd3,0xaa,0x8a,0x59,0x02,0x82,0xa8,0x8f,0xd9, + 0x57,0x43,0xcf,0x8c,0x30,0xaa,0x0c,0xb8,0x98,0xf2,0x18,0xda,0x8a,0x65,0x93,0x59, + 0xd9,0xcd,0x3e,0x36,0xaa,0xee,0x2b,0x92,0xcd,0x1c,0x88,0xe2,0xd6,0x3e,0xce,0xca, + 0x7d,0x9c,0x6d,0xe8,0xa3,0xf1,0x93,0x2e,0x39,0xe1,0xf2,0x80,0x75,0xf9,0x04,0x5a, + 0xb2,0x81,0xb0,0xae,0xb9,0x67,0xb0,0x7e,0xc0,0x85,0xb2,0x05,0xaa,0xe1,0x3d,0x77, + 0x9e,0x5e,0xdf,0xe7,0xa9,0x22,0x00,0xc1,0x98,0x42,0x7c,0x53,0xd5,0xc7,0x55,0x1c, + 0xbb,0x9e,0xe0,0x0a,0x5e,0x47,0xc0,0x99,0x85,0xc9,0xb8,0x2c,0xb2,0x7c,0x47,0x1f, + 0x91,0xc4,0xef,0x26,0x9e,0x75,0x05,0xde,0x4c,0x37,0xe6,0xb5,0x91,0xbd,0x6f,0xa6, + 0x7e,0xe6,0x9b,0x29,0xa2,0xfc,0x4d,0x6b,0xd9,0x98,0x61,0x5c,0x9b,0x58,0x96,0x45, + 0x5c,0x79,0x46,0xad,0xd9,0xb4,0x84,0x76,0x36,0xc8,0xae,0xd2,0x31,0x48,0x81,0xde, + 0xf8,0xb4,0xb8,0x99,0x6a,0x17,0x83,0x55,0x3e,0x15,0xe5,0xb6,0xff,0x0e,0x89,0xfc, + 0x33,0x3a,0x4e,0x93,0x63,0x7b,0x42,0xe7,0x22,0x54,0x3d,0x6e,0x62,0x67,0xed,0x20, + 0x6c,0x5e,0x9a,0x3c,0x79,0xd5,0x96,0xaa,0xdc,0x06,0x16,0x14,0x40,0xbf,0x69,0x66, + 0xb5,0x74,0x49,0x16,0x3e,0xee,0xd4,0xd9,0xf5,0xa4,0x00,0x56,0xcb,0x25,0xa1,0xa6, + 0x03,0x1d,0x32,0xc3,0x91,0x29,0x2a,0x50,0xd7,0x3c,0x6c,0x1c,0x18,0xa4,0x62,0xe1, + 0x95,0x12,0xca,0x36,0x4a,0x75,0x64,0xdb,0xea,0xd0,0xf1,0x18,0x0b,0x3b,0x32,0x81, + 0x60,0x01,0xd7,0x07,0x64,0x89,0x76,0xb4,0xc9,0x94,0xaa,0x6a,0x5c,0x46,0x14,0x8a, + 0x7b,0xbb,0x6c,0xc2,0xc2,0xc2,0x34,0x2c,0xa3,0xc8,0x35,0x02,0x2d,0x28,0x76,0x18, + 0xfb,0x7a,0x23,0x97,0xd1,0xff,0x39,0x7b,0x9b,0x8b,0x83,0xec,0x84,0xbd,0x64,0x9f, + 0x66,0xd4,0xc6,0xca,0xf5,0x94,0x68,0x15,0x3c,0x4b,0xdf,0xfc,0x69,0xbb,0x2a,0xbe, + 0x05,0x96,0xec,0x69,0xc3,0x8c,0x50,0x16,0xca,0x87,0x2c,0xa2,0x41,0x19,0xe9,0xa9, + 0x40,0x9d,0x72,0xd3,0xd3,0xcb,0xa9,0x48,0xce,0x85,0x72,0xd8,0xf7,0x74,0x30,0x8f, + 0x48,0xb6,0xb3,0xcf,0x79,0xc4,0xb2,0xaf,0xea,0x15,0x7c,0x31,0xd6,0xa4,0x61,0x83, + 0x25,0x97,0xa5,0x2f,0x19,0xc4,0xce,0xa9,0x17,0x2a,0xde,0xe5,0xa4,0xf4,0x05,0x49, + 0xbf,0xc6,0xbe,0x68,0x6d,0x0e,0x68,0xfa,0xc9,0x97,0x7a,0x31,0x29,0xcc,0xeb,0x12, + 0xf9,0x7e,0x20,0x6a,0xd1,0x7c,0x13,0x6b,0x2a,0xa6,0x1d,0x31,0x83,0xf2,0x70,0x59, + 0x48,0x49,0xfd,0xd4,0xe6,0x4f,0xc4,0x48,0x4a,0x9f,0x40,0x32,0x5c,0x04,0xa9,0x9a, + 0x83,0x45,0x82,0x9f,0xd3,0xe1,0x68,0xd0,0x88,0x48,0xec,0x62,0x3f,0x90,0xee,0xb5, + 0x84,0x10,0x94,0x8f,0x69,0x1e,0x3f,0xcb,0xb2,0xc6,0xce,0x6a,0x6e,0x26,0xb7,0x59, + 0xc1,0xbe,0x9c,0x0d,0x18,0x6f,0x88,0xe9,0xaf,0xa3,0x61,0x32,0xb9,0xfb,0x94,0xfe, + 0x7a,0x3e,0xb4,0x4c,0x80,0x4d,0x97,0x92,0x50,0xfb,0xe0,0x1f,0x5b,0x4f,0xfa,0xd1, + 0x5c,0xd7,0x57,0xe7,0xb8,0xb4,0xc2,0x64,0xf9,0xc9,0xf2,0xf2,0xc1,0xcd,0xa8,0xb4, + 0xa8,0xb5,0xe4,0xfa,0xba,0xfc,0x2f,0x97,0xd8,0xc5,0x3f,0x75,0x70,0x67,0x98,0x3b, + 0xb4,0x1a,0x1a,0x2e,0x69,0xab,0xd3,0x92,0x86,0xb5,0x14,0x39,0xbf,0x0e,0xb5,0x6c, + 0xcf,0x87,0x2d,0x4b,0x2c,0x6c,0xd9,0xd2,0x10,0x41,0x62,0x72,0xf6,0xa4,0x20,0xc7, + 0xfb,0xbc,0x19,0x93,0xaa,0xe5,0x16,0x20,0xfc,0x3b,0xaf,0x44,0x07,0x83,0x68,0xea, + 0x52,0xb5,0x78,0xef,0x5b,0x93,0xb7,0xdb,0x41,0x2e,0x3a,0x97,0x2c,0x9f,0x8e,0x81, + 0xad,0x3a,0xe4,0x51,0xdb,0xc4,0x20,0x36,0x55,0xf3,0xe7,0xc3,0x43,0x5c,0xf0,0x50, + 0x4f,0x0f,0x92,0x84,0xff,0x56,0xea,0x7d,0x8b,0xf2,0xe0,0x55,0x6e,0xd6,0xbd,0x05, + 0xb6,0x34,0x23,0x71,0x74,0x24,0x10,0x96,0xfb,0x6c,0x8a,0x09,0x7c,0xb7,0xcd,0x15, + 0x76,0x56,0x2b,0xff,0xf9,0xe4,0x0f,0xe5,0xfa,0x2c,0x0d,0x19,0x6f,0x4d,0x21,0x3e, + 0x2f,0x1d,0x7c,0xa7,0x5f,0xf8,0x73,0x86,0xaa,0x6a,0x02,0x6e,0xab,0x9a,0xe4,0x37, + 0xde,0x2c,0xd5,0x01,0xda,0xd3,0x11,0xf2,0x76,0x1b,0x8e,0x81,0xad,0xaf,0x2b,0x10, + 0x6f,0x25,0x6b,0x57,0xc7,0x58,0x6b,0x3f,0x18,0x1e,0x5b,0xba,0xfa,0x2d,0x75,0x02, + 0x60,0x30,0xa6,0x1f,0x54,0x79,0xde,0x1a,0x0d,0xc7,0x69,0x1e,0x84,0x67,0xa0,0x5c, + 0xc7,0xe2,0x32,0xd7,0x97,0x95,0x14,0x35,0x69,0x70,0x88,0x3e,0xbf,0x7c,0x3a,0x47, + 0xac,0x65,0xda,0x97,0x68,0xef,0x94,0x11,0x6d,0x46,0x87,0x28,0x91,0x92,0x70,0xc1, + 0xcb,0x42,0x34,0xf4,0xdd,0xd7,0x9d,0x4e,0x67,0x1d,0xef,0x6d,0x8d,0xcd,0x09,0x00, + 0x3e,0xd4,0x1e,0x09,0x5e,0xe1,0xb6,0x89,0xf2,0x13,0x2d,0x39,0xe8,0xa7,0xae,0xee, + 0xe0,0xd1,0x22,0x86,0x16,0x66,0xce,0xf0,0x14,0x61,0x9c,0x12,0xd8,0x8b,0x2a,0x56, + 0x6a,0x6a,0x04,0x70,0xae,0xa9,0x34,0x6b,0xbc,0xd8,0xa0,0x5c,0xbf,0xb4,0x8a,0x09, + 0x71,0xfa,0x3a,0xb8,0x68,0x08,0xaf,0x0b,0x9e,0x47,0x4b,0x18,0x01,0xb5,0x5e,0xf9, + 0xd1,0x42,0x2b,0xab,0x4d,0xcf,0x8f,0x19,0x94,0x2a,0x6c,0x99,0x39,0x5a,0x28,0xb8, + 0xae,0xee,0xe4,0xae,0xc1,0x18,0xcf,0x0a,0x4e,0x6b,0x59,0x80,0x7b,0x64,0x01,0x2e, + 0x34,0x7f,0x65,0xfd,0x27,0x5a,0xd8,0x1c,0x09,0x8e,0xb2,0x4a,0xcf,0x77,0x12,0xae, + 0xfd,0x40,0x23,0xb4,0xe3,0x77,0xf7,0x00,0xf7,0xaf,0x2f,0xa8,0x0b,0x25,0x8c,0x57, + 0x2f,0x1f,0x3f,0x27,0xc1,0x07,0x4f,0xe5,0x78,0x76,0x91,0xf7,0x9d,0x1d,0x9e,0xe0, + 0xc3,0x9a,0xe6,0x4c,0xef,0xfa,0x6c,0x79,0xdb,0xe5,0xc9,0xde,0x92,0x8f,0xaa,0x66, + 0x45,0xf3,0x2a,0x30,0xb4,0x1e,0x44,0xb8,0x37,0x53,0x86,0x8c,0x82,0xbe,0x2c,0xa9, + 0x7d,0xcf,0x4e,0xe2,0x9a,0xd5,0x63,0x19,0xb9,0x4c,0x4b,0x00,0x1b,0x56,0xf9,0xf9, + 0xa6,0x38,0xc8,0x3b,0x06,0x1a,0x8b,0x7f,0xdd,0x7a,0xc9,0x61,0x91,0xdd,0x10,0x95, + 0x79,0x6f,0x65,0xe9,0xe3,0x52,0x04,0x2a,0x35,0x6e,0x7c,0x6b,0xfe,0x7f,0x62,0xf5, + 0x25,0x96,0x58,0xcb,0xfa,0xcd,0x64,0x9c,0x32,0xc4,0x06,0x9c,0xef,0x06,0x39,0x07, + 0x5e,0xc2,0x90,0xb0,0x99,0x76,0xb0,0xde,0xca,0x1c,0x98,0xe6,0xfd,0xe9,0xcb,0xce, + 0x7f,0xb0,0x6a,0x9a,0x27,0xca,0x83,0xd6,0xad,0x3f,0x6e,0x59,0x35,0xc2,0x02,0x04, + 0xf5,0xc8,0xb8,0xb9,0x0b,0x46,0x6f,0x70,0x72,0xc4,0xce,0x14,0x6c,0x1e,0xbb,0x39, + 0x43,0x0d,0x27,0x0f,0x86,0x4a,0x75,0x03,0xd3,0x7b,0x00,0x84,0x29,0x9e,0xf6,0x16, + 0xed,0x1c,0x9b,0x6f,0x79,0xba,0x44,0x23,0xcb,0xc6,0x2a,0x10,0x2b,0x46,0x38,0x27, + 0x6b,0x10,0xd5,0x2c,0xea,0x7e,0xec,0x27,0x36,0xd5,0xa9,0x51,0xac,0xda,0x8d,0xca, + 0xcb,0xd8,0xc5,0x45,0xfa,0x3c,0xbd,0x36,0x17,0x72,0x3e,0xec,0x2b,0x0c,0xfa,0x71, + 0x77,0xe2,0x73,0x05,0x5e,0x7d,0xb8,0x6e,0xf1,0x50,0x86,0x59,0x4b,0x6a,0x90,0xb8, + 0x99,0x74,0xba,0x2d,0xb6,0xf7,0xdf,0x01,0x01,0x4c,0xa1,0xe9,0x58,0x2a,0x36,0x2e, + 0x00,0x12,0x02,0xa7,0x5d,0x05,0x65,0x76,0xf5,0xff,0x6f,0x91,0x5d,0x5d,0xad,0x3b, + 0x06,0xa1,0x4e,0xc9,0x6f,0x09,0xbc,0xa9,0x81,0x9c,0x47,0xd1,0xbd,0x7c,0x84,0x60, + 0xc1,0xbf,0xa1,0xf6,0x5d,0xf2,0x57,0x22,0x0d,0xa2,0x65,0x53,0xab,0x14,0xe4,0xf7, + 0xa3,0x9f,0x4f,0x0e,0x8a,0xc6,0x8e,0xd7,0xbf,0xc8,0xd8,0x59,0xff,0x7f,0x05,0xfa, + 0xb6,0x3c,0x9f,0xdf,0x89,0x6c,0xc4,0x76,0xb6,0x8b,0x44,0x0f,0xe6,0x8b,0x51,0x7e, + 0x3f,0x18,0xc3,0x1e,0x0b,0x97,0x0f,0x2d,0xa7,0x55,0x35,0x36,0x11,0xc5,0x6a,0xc5, + 0xaf,0x8e,0x70,0xcc,0xdd,0x66,0xb7,0x2e,0xe9,0x16,0x47,0x24,0x0f,0x6e,0x4d,0x67, + 0x85,0xa8,0x42,0xd5,0x95,0x12,0xf7,0x1b,0xb2,0xd3,0x7e,0xfd,0x7f,0xb8,0xf0,0xc2, + 0xae,0xaf,0x0e,0x26,0x9c,0x2b,0xbf,0x4d,0xd3,0x02,0xd8,0x28,0x9c,0x59,0x8c,0x84, + 0x17,0x81,0xac,0x07,0x6c,0x9e,0xa4,0x50,0xc7,0x7d,0x73,0x2e,0x72,0xa1,0x32,0xa8, + 0xb1,0x13,0x8e,0xe2,0x84,0x8b,0xd5,0x1f,0x10,0x74,0x99,0xa8,0xfd,0x17,0x76,0xcc, + 0xa2,0xf1,0x26,0x4a,0xb5,0x2f,0xa7,0x05,0x51,0xf6,0xa8,0xd8,0x91,0xa0,0xf9,0x46, + 0x65,0x0b,0x09,0x13,0x00,0x88,0x91,0x4b,0x92,0xfa,0xd8,0x6a,0x26,0xbf,0xac,0x25, + 0x84,0x20,0xd6,0xc6,0x12,0xe1,0x22,0xa1,0x44,0xd5,0x46,0x16,0x74,0xc2,0xdb,0x5c, + 0x33,0x7d,0x3d,0x5a,0x2c,0x34,0x1b,0x1d,0x06,0xd5,0xdd,0x0c,0x40,0x1d,0x09,0x83, + 0x3b,0x73,0xfc,0xf6,0x06,0x25,0x11,0xfa,0x1c,0x21,0x83,0x84,0xda,0x10,0xe7,0x2d, + 0xa4,0x3c,0x05,0x85,0xe2,0xd2,0x28,0x38,0x94,0xe8,0x3f,0x75,0x5a,0x9c,0x8c,0x8e, + 0x77,0xb3,0xc7,0xc8,0x0d,0x57,0x49,0xbb,0x9c,0xdf,0xdf,0x30,0xd4,0x8e,0x57,0x6d, + 0x48,0xf4,0x17,0x9d,0xf6,0x9b,0x97,0x52,0x48,0xbc,0x49,0x79,0xbf,0x53,0x67,0xc0, + 0xcc,0xa5,0x76,0xca,0xd2,0x8c,0xae,0x7d,0x5f,0x73,0x41,0x4f,0xab,0x6a,0xf4,0xaf, + 0x34,0x6a,0xc9,0x5a,0x70,0x81,0xcb,0x76,0x66,0x94,0xb6,0x78,0x19,0xfd,0xa8,0x5f, + 0x10,0x65,0x69,0x70,0x1a,0x0a,0xf3,0x2c,0xc6,0x57,0xe2,0x96,0xb5,0x31,0x5c,0x9c, + 0xaa,0x4a,0x0f,0x9c,0x07,0x97,0x33,0x40,0x62,0x97,0x66,0xb1,0x98,0xe1,0x9f,0xc2, + 0xfd,0x3d,0x67,0xb5,0x75,0x7d,0xc0,0x35,0xa7,0x41,0x41,0x13,0x46,0x08,0x97,0x38, + 0x92,0xab,0xab,0x87,0x5b,0x88,0x70,0xc5,0xe0,0xb2,0xc7,0xa0,0xd5,0xf0,0x11,0xc7, + 0x09,0x7a,0x54,0xec,0x19,0xae,0xd0,0xf3,0xc8,0xfb,0x9b,0x45,0xf5,0xa5,0xea,0xb6, + 0x3e,0x73,0xb3,0xba,0x26,0xa8,0xfc,0x7a,0x4f,0xd0,0xc3,0x7b,0x7b,0xa7,0xc7,0x72, + 0xb3,0x7c,0x46,0xbf,0x2e,0xa7,0xc3,0x27,0xfc,0x45,0x44,0xcb,0xb3,0xbd,0x7f,0x03, + 0x98,0x72,0x4a,0x72,0xe1,0x71,0x01,0x00, }; diff --git a/src/helpers/esp32/WebConfigServer.cpp b/src/helpers/esp32/WebConfigServer.cpp index 0db21caf..20e7810f 100644 --- a/src/helpers/esp32/WebConfigServer.cpp +++ b/src/helpers/esp32/WebConfigServer.cpp @@ -28,6 +28,136 @@ #include "helpers/CLICommandUtils.h" #include "helpers/WebConfigKeys.h" #include "helpers/WiFiPowerSave.h" +#include "helpers/esp32/WiFiRadioPolicy.h" +#include "helpers/esp32/WiFiStationPolicy.h" + +// ESPAsyncWebServer closes every ordinary response, so splitting the UI into +// many HTTP requests exhausts a lossy link's TCP/WiFi resources. Its ordinary +// PROGMEM response also fills the whole TCP send window at once. Keep one +// response open and queue only 512 body bytes after the preceding bytes have +// actually been acknowledged. +class WebConfigPacedProgmemResponse final : public AsyncWebServerResponse { + static constexpr size_t kBodyChunk = 512; + + const uint8_t* _content; + String _assembled_headers; + size_t _written_headers = 0; + size_t _in_flight = 0; + size_t _space_before_batch = 0; + + size_t queueNext(AsyncWebServerRequest* request) { + AsyncClient* client = request ? request->client() : nullptr; + if (!client) { + _state = RESPONSE_FAILED; + return 0; + } + + // This response has exactly one writer and never queues another batch + // until the current one is acknowledged. Remembering the send-buffer space + // here lets _ack() recover if AsyncTCP cannot allocate its SENT event: lwIP + // has already restored tcp_sndbuf by then, but that event is not replayed. + const size_t space_before_batch = client->space(); + size_t queued = 0; + if (_state == RESPONSE_HEADERS) { + const size_t added = client->add( + _assembled_headers.c_str() + _written_headers, + _assembled_headers.length() - _written_headers); + _written_headers += added; + _writtenLength += added; + queued += added; + if (_written_headers < _assembled_headers.length()) { + if (queued && client->send()) { + _in_flight += queued; + _space_before_batch = space_before_batch; + } else if (queued) { + _state = RESPONSE_FAILED; + client->close(); + } + return queued; + } + _assembled_headers = String(); + _state = RESPONSE_CONTENT; + } + + if (_state == RESPONSE_CONTENT && _sentLength < _contentLength) { + size_t amount = _contentLength - _sentLength; + if (amount > kBodyChunk) amount = kBodyChunk; + const size_t room = client->space(); + if (amount > room) amount = room; + if (amount) { + const size_t added = client->add( + reinterpret_cast(_content + _sentLength), amount); + _sentLength += added; + _writtenLength += added; + queued += added; + } + if (_sentLength == _contentLength) _state = RESPONSE_WAIT_ACK; + } + + if (queued) { + if (client->send()) { + _in_flight += queued; + _space_before_batch = space_before_batch; + } else { + _state = RESPONSE_FAILED; + client->close(); + } + } + return queued; + } + +public: + WebConfigPacedProgmemResponse(const char* content_type, + const uint8_t* content, size_t length) + : _content(content) { + _code = 200; + _contentType = content_type; + _contentLength = length; + } + + bool _sourceValid() const override { + return _content != nullptr && _contentLength != 0; + } + + void _respond(AsyncWebServerRequest* request) override { + addHeader("Connection", "close", false); + _assembleHead(_assembled_headers, request->version()); + _state = RESPONSE_HEADERS; + queueNext(request); + } + + size_t _ack(AsyncWebServerRequest* request, size_t len, + uint32_t time) override { + (void)time; + AsyncClient* client = request ? request->client() : nullptr; + if (len == 0 && _in_flight != 0 && client + && client->space() >= _space_before_batch) { + // AsyncTCP reports polls as zero-length ACKs. A restored send buffer is + // unambiguous here because this response has only one batch in flight. + // Account for an ACK whose AsyncTCP event allocation failed under low + // internal heap, otherwise the response would remain stuck forever. + len = _in_flight; + } + _ackedLength += len; + if (len >= _in_flight) _in_flight = 0; + else _in_flight -= len; + if (_in_flight != 0) return 0; + if (_state == RESPONSE_WAIT_ACK) { + // The full Content-Length has now been acknowledged. ESPAsyncWebServer + // otherwise performs a graceful active close for every response, and + // this IDF 4.4 stack retains malloc-backed TCP PCBs in TIME_WAIT for about + // two minutes. Repeated WebConfig loads consume scarce internal heap and + // can also prevent AsyncTCP from retiring close events, wedging both + // infrastructure WiFi and ESP-NOW. Abort only after the final ACK so the + // peer has the complete page, while freeing this PCB immediately. Keep + // RESPONSE_WAIT_ACK: abort synchronously dispatches disconnect and the + // request's scoped owner then destroys this response. + if (client) client->abort(); + return 0; + } + return queueNext(request); + } +}; static bool bluetoothWiFiCoexistenceRequired() { #if defined(BLE_PIN_CODE) && defined(WIFI_SSID) @@ -39,7 +169,23 @@ static bool bluetoothWiFiCoexistenceRequired() { static uint8_t effectiveWiFiPowerSave(uint8_t configured) { return mesh::wifi::effectivePowerSave( - configured, bluetoothWiFiCoexistenceRequired()); + configured, bluetoothWiFiCoexistenceRequired(), + mesh::wifi::kPrimaryEspNowRadio); +} + +static void stopOwnedWiFiRadio() { +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + // ESP-NOW is this target's mesh radio. Stop only infrastructure-WiFi + // ownership; powering the driver down would also remove the mesh transport. + WiFi.setAutoReconnect(false); + WiFi.disconnect(false, false); + WiFi.mode(WIFI_STA); + mesh::wifi::applyProtocolMask(WIFI_IF_STA); + mesh::wifi::restoreEspNowChannel(); +#else + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); +#endif } // Placeholder sent instead of stored secrets; POSTs carrying it are dropped @@ -48,6 +194,11 @@ static const char SECRET_SENTINEL[] = "********"; static bool isAllowedSetKey(const char* key, bool has_mqtt) { if (!key || !wcIsAllowedSetKey(key)) return false; +#if !defined(MESH_PRIMARY_ESPNOW) || !MESH_PRIMARY_ESPNOW + // The shared source-level allowlist is host-tested, but only a target whose + // mesh transport is ESP-NOW has a meaningful primary-radio channel to set. + if (wcSetKeyRequiresReboot(key)) return false; +#endif const bool mqtt_only = strncmp(key, "mqtt.", 5) == 0 || strncmp(key, "mqtt", 4) == 0 || strncmp(key, "timezone", 8) == 0 @@ -202,24 +353,31 @@ WebConfigServer::WebConfigServer(Callbacks* callbacks, void* mqtt_prefs, bool ow #ifdef WITH_MQTT_BRIDGE MQTTPrefs* obs = static_cast(_mqtt_prefs); - if (obs) { + if (obs && _owns_wifi) { strncpy(_wifi_ssid, obs->wifi_ssid, sizeof(_wifi_ssid) - 1); strncpy(_wifi_password, obs->wifi_password, sizeof(_wifi_password) - 1); _wifi_power_save = obs->wifi_power_save <= mesh::wifi::kPowerSaveMax ? obs->wifi_power_save : mesh::wifi::kDefaultPowerSave; - // Companion builds keep their canonical connection credentials in the - // shared mesh-wifi namespace. A fresh MQTT configuration can therefore - // have an empty MQTTPrefs WiFi field even while the companion is already - // connected; use the canonical copy until the first WebUI save syncs both. - if (_wifi_ssid[0] == 0 && !_owns_wifi) { - loadStandaloneWiFi(_wifi_ssid, sizeof(_wifi_ssid), - _wifi_password, sizeof(_wifi_password), &_wifi_power_save); - } } else #endif { - loadStandaloneWiFi(_wifi_ssid, sizeof(_wifi_ssid), - _wifi_password, sizeof(_wifi_password), &_wifi_power_save); + // Companion and standalone FULL builds keep their canonical connection + // credentials in mesh-wifi NVS. Do not round-trip a 64-hex raw PSK through + // the fixed-layout MQTTPrefs wifi_password[64] field. + const bool loaded_standalone = loadStandaloneWiFi( + _wifi_ssid, sizeof(_wifi_ssid), + _wifi_password, sizeof(_wifi_password), &_wifi_power_save); +#ifdef WITH_MQTT_BRIDGE + // Preserve the upgrade path from older WiFi-MQTT Companion installs that + // have not written the canonical namespace yet. Once mesh-wifi exists it + // always wins, including when it contains a 64-hex PSK. + if (!loaded_standalone && obs) { + strncpy(_wifi_ssid, obs->wifi_ssid, sizeof(_wifi_ssid) - 1); + strncpy(_wifi_password, obs->wifi_password, sizeof(_wifi_password) - 1); + _wifi_power_save = obs->wifi_power_save <= mesh::wifi::kPowerSaveMax + ? obs->wifi_power_save : mesh::wifi::kDefaultPowerSave; + } +#endif } _wifi_power_save = effectiveWiFiPowerSave(_wifi_power_save); } @@ -275,7 +433,8 @@ bool WebConfigServer::loadStandaloneWiFi(char* ssid, size_t ssid_len, "powersave", mesh::wifi::kDefaultPowerSave); nvs.end(); if (stored_ssid.length() >= ssid_len - || stored_password.length() >= password_len) { + || stored_password.length() >= password_len + || !mesh::cli::standaloneWiFiPasswordValid(stored_password.c_str())) { return false; } strncpy(ssid, stored_ssid.c_str(), ssid_len - 1); @@ -289,14 +448,14 @@ bool WebConfigServer::loadStandaloneWiFi(char* ssid, size_t ssid_len, bool WebConfigServer::saveStandaloneWiFi(const char* ssid, const char* password, uint8_t power_save) { power_save = effectiveWiFiPowerSave(power_save); + const char* pwd = password ? password : ""; if (!ssid || !ssid[0] || strlen(ssid) >= 32 - || (password && strlen(password) >= 64) + || !mesh::cli::standaloneWiFiPasswordValid(pwd) || power_save > mesh::wifi::kPowerSaveMax) { return false; } Preferences nvs; if (!nvs.begin("mesh-wifi", false)) return false; - const char* pwd = password ? password : ""; bool ok = nvs.putString("ssid", ssid) == strlen(ssid); nvs.putString("password", pwd); // empty String legitimately writes zero bytes ok = ok && nvs.getString("password", "\x01") == pwd; @@ -330,7 +489,7 @@ bool WebConfigServer::setStandaloneWiFiPassword(const char* value, char* reply, if (!reply || reply_len == 0) return false; if (!mesh::cli::standaloneWiFiPasswordValid(value)) { snprintf(reply, reply_len, - "Error: WiFi password must be at most 63 characters"); + "Error: WiFi password must be 0-63 characters or 64 hex characters"); return false; } @@ -355,12 +514,17 @@ bool WebConfigServer::setStandaloneWiFiPowerSave(const char* value, char* reply, snprintf(reply, reply_len, "Error: power save must be none, min, or max"); return false; } + if (mesh::wifi::kPrimaryEspNowRadio + && power_save == mesh::wifi::kPowerSaveMax) { + snprintf(reply, reply_len, + "Error: power save max is unavailable while ESP-NOW is the primary radio"); + return false; + } if (effectiveWiFiPowerSave(power_save) != power_save) { snprintf(reply, reply_len, "Error: power save none is unavailable while Bluetooth is active"); return false; } - Preferences nvs; if (!nvs.begin("mesh-wifi", false)) { snprintf(reply, reply_len, "Error: failed to open WiFi settings"); @@ -421,7 +585,7 @@ bool WebConfigServer::formatWiFiSSID(char* reply, size_t reply_len) { if (!reply || reply_len == 0) return false; char ssid[32] = ""; - char password[64] = ""; + char password[65] = ""; uint8_t power_save = mesh::wifi::kDefaultPowerSave; bool configured = loadStandaloneWiFi( ssid, sizeof(ssid), password, sizeof(password), &power_save); @@ -443,7 +607,7 @@ bool WebConfigServer::formatWiFiPowerSave(char* reply, size_t reply_len) { power_save = _active->_wifi_power_save; } else { char ssid[32] = ""; - char password[64] = ""; + char password[65] = ""; loadStandaloneWiFi( ssid, sizeof(ssid), password, sizeof(password), &power_save); } @@ -479,7 +643,7 @@ bool WebConfigServer::formatWiFiStatus(char* reply, size_t reply_len) { if (!reply || reply_len == 0) return false; char ssid[32] = ""; - char password[64] = ""; + char password[65] = ""; uint8_t power_save = mesh::wifi::kDefaultPowerSave; bool configured = loadStandaloneWiFi( ssid, sizeof(ssid), password, sizeof(password), &power_save); @@ -599,9 +763,11 @@ bool WebConfigServer::startSetupMode(char reply[]) { bool ap_ok = false; for (uint8_t attempt = 1; attempt <= 6 && !ap_ok; ++attempt) { #ifdef WEBCONFIG_AP_PASSWORD - ap_ok = WiFi.softAP(_ap_ssid, WEBCONFIG_AP_PASSWORD); + ap_ok = WiFi.softAP(_ap_ssid, WEBCONFIG_AP_PASSWORD, + mesh::wifi::accessPointChannel()); #else - ap_ok = WiFi.softAP(_ap_ssid); + ap_ok = WiFi.softAP(_ap_ssid, nullptr, + mesh::wifi::accessPointChannel()); #endif if (ap_ok) { // ESP-NOW can leave the persistent AP protocol mask with the proprietary @@ -609,11 +775,9 @@ bool WebConfigServer::startSetupMode(char reply[]) { // phones and laptops cannot discover its beacon. A WiFi companion must // advertise using the interoperable 2.4 GHz protocol set. const esp_err_t ap_protocol_result = esp_wifi_set_protocol( - WIFI_IF_AP, - WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); + WIFI_IF_AP, mesh::wifi::kProtocolMask); const esp_err_t sta_protocol_result = esp_wifi_set_protocol( - WIFI_IF_STA, - WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); + WIFI_IF_STA, mesh::wifi::kProtocolMask); if (ap_protocol_result == ESP_OK && sta_protocol_result == ESP_OK) break; Serial.printf("WebConfig protocol reset failed: AP=%d STA=%d\n", (int)ap_protocol_result, (int)sta_protocol_result); @@ -630,7 +794,7 @@ bool WebConfigServer::startSetupMode(char reply[]) { mode_ok = WiFi.mode(WIFI_AP_STA); } if (!ap_ok) { - if (!promote_lan) WiFi.mode(WIFI_OFF); + if (!promote_lan) stopOwnedWiFiRadio(); strcpy(reply, "Err: failed to start AP"); return false; } @@ -692,20 +856,17 @@ bool WebConfigServer::startAutoMode(char reply[]) { } WiFi.mode(WIFI_STA); - if (esp_wifi_set_protocol( - WIFI_IF_STA, - WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) - != ESP_OK) { + if (mesh::wifi::applyProtocolMask(WIFI_IF_STA) != ESP_OK) { strcpy(reply, "Err: failed to reset WiFi station protocol"); return false; } - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); _retry_saved_wifi_in_setup = false; _setup_reconnect_in_progress = false; _setup_reconnect_deadline = 0; _setup_started_at = 0; _wifi_reconnect_tracker.noteDisconnected(millis()); - WiFi.begin(_wifi_ssid, _wifi_password); + mesh::wifi::beginStation(_wifi_ssid, _wifi_password); _wifi_power_save = effectiveWiFiPowerSave(_wifi_power_save); wifi_ps_type_t ps_mode = _wifi_power_save == mesh::wifi::kPowerSaveNone ? WIFI_PS_NONE @@ -764,15 +925,14 @@ void WebConfigServer::finalizeTeardown() { // Nothing else owns WiFi when we raised the AP: either the node is // unconfigured, or `start webconfig ap` required the bridge stopped. if (_wifi_ssid[0] == 0 || _owns_wifi) { - WiFi.mode(WIFI_OFF); + stopOwnedWiFiRadio(); } else { WiFi.mode(WIFI_STA); } _was_setup_ap = false; } if (_owns_wifi && !was_setup_ap) { - WiFi.disconnect(true); - WiFi.mode(WIFI_OFF); + stopOwnedWiFiRadio(); } _initial_setup = false; _setup_started_at = 0; @@ -816,6 +976,13 @@ void WebConfigServer::tick(uint32_t now) { } if (_mode == MODE_OFF) return; + // A primary ESP-NOW radio and its WiFi station cannot remain on different + // channels. Reject a router-driven channel move (for example a CSA) and put + // the mesh radio back on its boot channel before any reconnect work runs. + if (!mesh::wifi::enforceStationChannel()) { + _wifi_reconnect_tracker.noteDisconnected(now); + } + if (_mode == MODE_CONNECTING) { if (WiFi.status() == WL_CONNECTED) { _wifi_reconnect_tracker.noteConnected(); @@ -857,9 +1024,9 @@ void WebConfigServer::tick(uint32_t now) { Serial.printf("WebConfig: WiFi still unavailable; retrying '%s'\n", _wifi_ssid); WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); WiFi.disconnect(false, false); - WiFi.begin(_wifi_ssid, _wifi_password); + mesh::wifi::beginStation(_wifi_ssid, _wifi_password); } } } @@ -881,7 +1048,7 @@ void WebConfigServer::tick(uint32_t now) { } WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); _was_setup_ap = false; _initial_setup = false; _setup_started_at = 0; @@ -905,7 +1072,7 @@ void WebConfigServer::tick(uint32_t now) { _setup_reconnect_in_progress = true; _setup_reconnect_deadline = now + 20000UL; Serial.printf("WebConfig: retrying saved WiFi '%s'\n", _wifi_ssid); - WiFi.begin(_wifi_ssid, _wifi_password); + mesh::wifi::beginStation(_wifi_ssid, _wifi_password); } } @@ -965,7 +1132,7 @@ void WebConfigServer::tick(uint32_t now) { } WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); + mesh::wifi::setStationAutoReconnect(true); _was_setup_ap = false; _initial_setup = false; _setup_started_at = 0; @@ -1090,8 +1257,9 @@ void WebConfigServer::drainBatch(uint32_t now) { strcpy(e.reply, "OK"); } } else if ((_mqtt_prefs == NULL || !_owns_wifi) && strcmp(e.key, "wifi.pwd") == 0) { - if (strlen(value) >= sizeof(_wifi_password)) { - strcpy(e.reply, "Error: WiFi password must be at most 63 characters"); + if (!mesh::cli::standaloneWiFiPasswordValid(value)) { + strcpy(e.reply, + "Error: WiFi password must be 0-63 characters or 64 hex characters"); } else { strncpy(_wifi_password, value, sizeof(_wifi_password) - 1); _wifi_password[sizeof(_wifi_password) - 1] = 0; @@ -1105,7 +1273,11 @@ void WebConfigServer::drainBatch(uint32_t now) { strcpy(e.reply, "Error: power save none is unavailable while Bluetooth is active"); } else if (strcmp(value, "none") == 0) _wifi_power_save = 1; - else if (strcmp(value, "max") == 0) _wifi_power_save = 2; + else if (strcmp(value, "max") == 0 + && mesh::wifi::kPrimaryEspNowRadio) { + strcpy(e.reply, + "Error: power save max is unavailable while ESP-NOW is the primary radio"); + } else if (strcmp(value, "max") == 0) _wifi_power_save = 2; else strcpy(e.reply, "Error: must be none, min, or max"); if (e.reply[0] == 0) { _standalone_wifi_dirty = true; @@ -1169,16 +1341,19 @@ void WebConfigServer::drainBatch(uint32_t now) { } bool wifi_credentials_changed = false; + bool espnow_channel_changed = false; for (int i = 0; i < _batch_count; i++) { if (strcmp(_batch[i].key, "wifi.ssid") == 0 || strcmp(_batch[i].key, "wifi.pwd") == 0) { wifi_credentials_changed = true; - break; + } else if (wcSetKeyRequiresReboot(_batch[i].key)) { + espnow_channel_changed = true; } } if (WebConfigBatch::shouldStartSetupWiFiHandoff( _mode == MODE_SETUP, _batch_reboot, _batch_all_ok, - wifi_credentials_changed, _wifi_ssid[0] != 0)) { + wifi_credentials_changed, _wifi_ssid[0] != 0, + espnow_channel_changed)) { { WCLock lock(_mux); _setup_wifi_handoff_pending = true; @@ -1192,7 +1367,7 @@ void WebConfigServer::drainBatch(uint32_t now) { WiFi.setAutoReconnect(false); Serial.printf("WebConfig: testing saved WiFi '%s' before reboot\n", _wifi_ssid); - WiFi.begin(_wifi_ssid, _wifi_password); + mesh::wifi::beginStation(_wifi_ssid, _wifi_password); return; } finishBatch(now); @@ -1252,6 +1427,9 @@ void WebConfigServer::dispatchRequest(AsyncWebServerRequest* req, } void WebConfigServer::registerRoutes() { + _server->on("/ui", HTTP_GET, [](AsyncWebServerRequest* r) { + dispatchRequest(r, &WebConfigServer::handleUi); + }); _server->on("/", HTTP_GET, [](AsyncWebServerRequest* r) { dispatchRequest(r, &WebConfigServer::handleRoot); }); @@ -1361,12 +1539,34 @@ void WebConfigServer::handleRoot(AsyncWebServerRequest* req) { return; } AsyncWebServerResponse* res = - req->beginResponse(200, "text/html", WEBCONFIG_HTML_GZ, WEBCONFIG_HTML_GZ_LEN); - res->addHeader("Content-Encoding", "gzip"); + req->beginResponse(200, "text/html", WEBCONFIG_HTML_LOADER, + WEBCONFIG_HTML_LOADER_LEN); res->addHeader("ETag", WEBCONFIG_HTML_ETAG); req->send(res); } +void WebConfigServer::handleUi(AsyncWebServerRequest* req) { + if (_mode == MODE_OFF) { req->send(503); return; } + _last_activity = millis(); + if (!req->hasParam("v") || + req->getParam("v")->value() != WEBCONFIG_HTML_VERSION) { + // Part URLs are immutable. Never serve a new layout under an old loader's + // cache key; a 409 tells the loader to refresh itself first. + AsyncWebServerResponse* res = + req->beginResponse(409, "text/plain", "WebConfig version changed"); + res->addHeader("Cache-Control", "no-store"); + req->send(res); + return; + } + AsyncWebServerResponse* res = + new WebConfigPacedProgmemResponse("text/html; charset=utf-8", + WEBCONFIG_HTML_GZ, + WEBCONFIG_HTML_GZ_LEN); + res->addHeader("Content-Encoding", "gzip"); + res->addHeader("Cache-Control", "public, max-age=31536000, immutable"); + req->send(res); +} + void WebConfigServer::handleStatus(AsyncWebServerRequest* req) { if (_mode == MODE_OFF) { req->send(503); return; } bool authed = checkAuth(req); @@ -1405,6 +1605,9 @@ void WebConfigServer::handleStatus(AsyncWebServerRequest* req) { doc["active_slots"] = 0; #endif doc["mqtt"] = has_mqtt; + // The fixed-layout MQTTPrefs path remains limited to 63 characters. + // Standalone mesh-wifi NVS can also hold a standards-defined 64-hex PSK. + doc["wifi_psk64"] = (_mqtt_prefs == NULL || !_owns_wifi); doc["cli"] = _cli_enabled && _mode == MODE_LAN && WiFi.status() == WL_CONNECTED && _cb->supportsCliTerminal(); doc["capabilities"] = node.capabilities; @@ -1524,6 +1727,9 @@ void WebConfigServer::handleConfigGet(AsyncWebServerRequest* req) { wifi["pwd"] = _wifi_password[0] ? SECRET_SENTINEL : ""; wifi["powersave"] = _wifi_power_save == 0 ? "min" : _wifi_power_save == 2 ? "max" : "none"; +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + wifi["espnow_channel"] = mesh::wifi::loadConfiguredEspNowChannel(); +#endif #ifdef WITH_MQTT_BRIDGE MQTTPrefs* obs = static_cast(_mqtt_prefs); @@ -1598,6 +1804,13 @@ void WebConfigServer::handleConfigPost(AsyncWebServerRequest* req) { return; } JsonObject set = doc["set"]; + for (JsonPair kv : set) { + if (wcSetKeyRequiresReboot(kv.key().c_str())) { + // The configured value is intentionally not activated until boot, so a + // client cannot leave persisted and live ESP-NOW channels disagreeing. + reboot_after = true; + } + } WCLock lock(_mux); const WebConfigBatch::State bstate = toSpecState(_batch_state); @@ -1649,6 +1862,18 @@ void WebConfigServer::handleConfigPost(AsyncWebServerRequest* req) { req->send(400, "application/json", out); return; } + if (wcSetKeyRequiresReboot(key)) { + uint8_t channel = 0; + if (!mesh::wifi::parseEspNowChannel(val, channel)) { + StaticJsonDocument<128> err; + err["error"] = "ESP-NOW channel must be 1-13"; + err["key"] = key; + String out; + serializeJson(err, out); + req->send(400, "application/json", out); + return; + } + } if (admin_pwd && !wcIsValidAdminPassword(val)) { req->send(400, "application/json", "{\"error\":\"admin password must be 1-15 characters with no line breaks\"}"); @@ -2120,6 +2345,7 @@ void WebConfigServer::handleScan(AsyncWebServerRequest* req) { net["ssid"] = WiFi.SSID(i); net["rssi"] = WiFi.RSSI(i); net["enc"] = WiFi.encryptionType(i) != WIFI_AUTH_OPEN; + net["channel"] = WiFi.channel(i); } AsyncResponseStream* res = req->beginResponseStream("application/json"); serializeJson(doc, *res); diff --git a/src/helpers/esp32/WebConfigServer.h b/src/helpers/esp32/WebConfigServer.h index e6f120a9..e72378c0 100644 --- a/src/helpers/esp32/WebConfigServer.h +++ b/src/helpers/esp32/WebConfigServer.h @@ -73,6 +73,7 @@ public: CAP_RX_POWER_SAVING = 1UL << 12, CAP_POWER_SAVING = 1UL << 13, CAP_BLUETOOTH_NAME = 1UL << 14, + CAP_ESPNOW_CHANNEL = 1UL << 15, CAP_DELAYS = CAP_RX_DELAY | CAP_TX_DELAY, }; @@ -243,7 +244,8 @@ private: uint32_t _setup_started_at = 0; uint32_t _connect_deadline = 0; char _wifi_ssid[32] = {0}; - char _wifi_password[64] = {0}; + // 63-character passphrase + NUL, or 64-hex raw WPA/WPA2 PSK + NUL. + char _wifi_password[65] = {0}; uint8_t _wifi_power_save = mesh::wifi::kDefaultPowerSave; bool _cli_enabled = true; // A `password` command has succeeded this session. Lets the CLI satisfy the @@ -319,6 +321,7 @@ private: size_t index, size_t total); void handleRoot(AsyncWebServerRequest* req); + void handleUi(AsyncWebServerRequest* req); void handleStatus(AsyncWebServerRequest* req); void handleLogin(AsyncWebServerRequest* req); void handleLogout(AsyncWebServerRequest* req); diff --git a/src/helpers/esp32/WiFiRadioPolicy.h b/src/helpers/esp32/WiFiRadioPolicy.h new file mode 100644 index 00000000..1b314788 --- /dev/null +++ b/src/helpers/esp32/WiFiRadioPolicy.h @@ -0,0 +1,130 @@ +#pragma once + +#include +#include +#include +#include + +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + #include +#endif + +namespace mesh { +namespace wifi { + +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + #ifndef MESH_ESPNOW_CHANNEL + #define MESH_ESPNOW_CHANNEL 1 + #endif +static_assert(MESH_ESPNOW_CHANNEL >= kEspNowChannelMin + && MESH_ESPNOW_CHANNEL <= kEspNowChannelMax, + "MESH_ESPNOW_CHANNEL must be a 2.4 GHz WiFi channel"); +static constexpr bool kPrimaryEspNowRadio = true; +static constexpr bool kKeepEspNowRadioRunning = true; +static constexpr uint8_t kDefaultEspNowChannel = MESH_ESPNOW_CHANNEL; +#else +static constexpr bool kPrimaryEspNowRadio = false; +static constexpr bool kKeepEspNowRadioRunning = false; +static constexpr uint8_t kDefaultEspNowChannel = 1; +#endif + +#if defined(MESH_ESPNOW_RADIO) && MESH_ESPNOW_RADIO +static constexpr uint8_t kProtocolMask = WIFI_PROTOCOL_11B + | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR; +#elif defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW +// A primary ESP-NOW image without conventional WiFi retains its original +// LR-only protocol until a coexistence-capable recipe explicitly opts in. +static constexpr uint8_t kProtocolMask = WIFI_PROTOCOL_LR; +#else +static constexpr uint8_t kProtocolMask = WIFI_PROTOCOL_11B + | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N; +#endif + +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW +struct EspNowBootChannelState { + bool loaded; + uint8_t active; +}; + +inline uint8_t loadConfiguredEspNowChannel() { + uint8_t channel = kDefaultEspNowChannel; + Preferences prefs; + if (prefs.begin("mesh-wifi", true)) { + channel = prefs.getUChar("espnow_ch", kDefaultEspNowChannel); + prefs.end(); + } + return validEspNowChannelOrDefault(channel, kDefaultEspNowChannel); +} + +// This cache intentionally represents the boot channel. Saving a new setting +// must not mutate it: reconnect/AP helpers continue using the old channel until +// reboot, so ESP-NOW, STA, and SoftAP cannot be moved at different times. +inline EspNowBootChannelState& espNowBootChannelState() { + static EspNowBootChannelState state = {false, kDefaultEspNowChannel}; + return state; +} + +inline uint8_t activeEspNowChannel() { + EspNowBootChannelState& state = espNowBootChannelState(); + if (!state.loaded) { + state.active = loadConfiguredEspNowChannel(); + state.loaded = true; + } + return state.active; +} + +inline bool saveConfiguredEspNowChannel(uint8_t channel) { + if (!isValidEspNowChannel(channel)) return false; + Preferences prefs; + if (!prefs.begin("mesh-wifi", false)) return false; + const bool saved = prefs.putUChar("espnow_ch", channel) == sizeof(uint8_t) + && prefs.getUChar("espnow_ch", 0) == channel; + prefs.end(); + return saved; +} +#else +inline uint8_t loadConfiguredEspNowChannel() { + return kDefaultEspNowChannel; +} +inline uint8_t activeEspNowChannel() { + return kDefaultEspNowChannel; +} +inline bool saveConfiguredEspNowChannel(uint8_t) { + return false; +} +#endif + +inline esp_err_t applyProtocolMask(wifi_interface_t interface_id) { + return esp_wifi_set_protocol(interface_id, kProtocolMask); +} + +// An ESP-NOW radio and an associated station cannot occupy different channels. +// Full Companion therefore keeps both its setup AP and any infrastructure-WiFi +// association on the mesh channel. Passing zero on ordinary targets preserves +// Arduino's normal all-channel scan behavior. +inline int32_t stationChannelHint() { + return kPrimaryEspNowRadio + ? static_cast(activeEspNowChannel()) : 0; +} + +inline int accessPointChannel() { + return kPrimaryEspNowRadio + ? static_cast(activeEspNowChannel()) : 1; +} + +inline uint8_t stationScanChannel() { + return kPrimaryEspNowRadio ? activeEspNowChannel() : 0; +} + +inline esp_err_t restoreEspNowChannel() { + if (!kKeepEspNowRadioRunning) return ESP_OK; + // Fail closed instead of silently moving to the build default. A failure can + // be transient (scan/connect in progress), and changing the cached boot + // channel here would split this node from peers which still use the selected + // channel. Callers retry through their normal reconnect/tick paths. + return esp_wifi_set_channel( + activeEspNowChannel(), WIFI_SECOND_CHAN_NONE); +} + +} // namespace wifi +} // namespace mesh diff --git a/src/helpers/esp32/WiFiStationPolicy.h b/src/helpers/esp32/WiFiStationPolicy.h new file mode 100644 index 00000000..a161adb1 --- /dev/null +++ b/src/helpers/esp32/WiFiStationPolicy.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include +#include + +namespace mesh { +namespace wifi { + +// Driver-managed reconnect is intentionally disabled for a primary ESP-NOW +// radio. ESP-IDF treats wifi_sta_config_t::channel as a scan-start hint, so an +// unconstrained reconnect could associate on another channel and silently +// drag ESP-NOW (and a setup AP) with it. Existing application retry timers call +// beginStation() and therefore retain the fixed-channel/BSSID constraint. +inline void setStationAutoReconnect(bool enabled) { + WiFi.setAutoReconnect(enabled && !kPrimaryEspNowRadio); +} + +inline wl_status_t beginStation(const char* ssid, const char* password) { + if (!kPrimaryEspNowRadio) { + return WiFi.begin(ssid, password); + } + +#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW + if (!ssid || !ssid[0]) return WL_CONNECT_FAILED; + setStationAutoReconnect(false); + if (applyProtocolMask(WIFI_IF_STA) != ESP_OK + || restoreEspNowChannel() != ESP_OK) { + return WL_CONNECT_FAILED; + } + + // Do not collide with WebConfig's asynchronous SSID scan. The caller's + // normal retry path will try again after that scan completes. + const int16_t prior_scan = WiFi.scanComplete(); + if (prior_scan == WIFI_SCAN_RUNNING) return WL_IDLE_STATUS; + if (prior_scan >= 0) WiFi.scanDelete(); + + const uint8_t channel = activeEspNowChannel(); + const int16_t count = WiFi.scanNetworks( + false, true, false, 300, channel, ssid, nullptr); + int best = -1; + int32_t best_rssi = INT32_MIN; + for (int i = 0; i < count; i++) { + if (WiFi.channel(i) != channel || WiFi.SSID(i) != ssid) continue; + const int32_t rssi = WiFi.RSSI(i); + if (best < 0 || rssi > best_rssi) { + best = i; + best_rssi = rssi; + } + } + + if (best < 0) { + WiFi.scanDelete(); + restoreEspNowChannel(); + return WL_NO_SSID_AVAIL; + } + + const uint8_t* selected_bssid = WiFi.BSSID(best); + if (!selected_bssid) { + WiFi.scanDelete(); + restoreEspNowChannel(); + return WL_CONNECT_FAILED; + } + uint8_t bssid[6]; + memcpy(bssid, selected_bssid, sizeof(bssid)); + WiFi.scanDelete(); + return WiFi.begin(ssid, password, channel, bssid); +#else + return WL_CONNECT_FAILED; +#endif +} + +// Returns false after dropping an association which moved away from the mesh +// channel (for example after an AP channel-switch announcement). Callers then +// follow their existing disconnected/retry path. +inline bool enforceStationChannel() { + if (!kPrimaryEspNowRadio) return true; + if (WiFi.status() != WL_CONNECTED) { + // A disconnect and scan/association completion are asynchronous. Keep + // reasserting the boot channel so a first ESP_ERR_WIFI_STATE cannot leave + // the mesh parked on the router's former channel. + restoreEspNowChannel(); + return true; + } + if (WiFi.channel() == activeEspNowChannel()) return true; + WiFi.disconnect(false, false); + restoreEspNowChannel(); + return false; +} + +} // namespace wifi +} // namespace mesh diff --git a/test/README.md b/test/README.md index cd0c5c87..bb07b369 100644 --- a/test/README.md +++ b/test/README.md @@ -26,8 +26,8 @@ does not reflect the GoogleTest count -- run the built binary directly |-------|-------------------|--------| | `test_mqtt_presets` | `src/helpers/MQTTPresets.h` | preset lookup; table integrity (unique names, non-empty URLs, JWT-audience invariant, names fit the slot buffer); `mqttPresetNeedsSlotCredentials`; slot-count constants | | `test_observer_validation` | `src/helpers/MQTTObserverValidation.h` | IATA (exactly 3 alphanumerics), owner key (64 hex), NTP hostname, and the buffer-fit check behind the #17 length validation -- including boundaries and nulls | -| `test_webconfig_keys` | `src/helpers/WebConfigKeys.h` | POST-key allowlist, secret detection, admin-password and browser-terminal command validation, slot-index bounds, and short-input guards | -| `test_webconfig_batch` | `src/helpers/WebConfigBatch.h` | config POST/replay/busy decisions; paced command drain; setup WiFi validation/IP handoff; reboot confirmation/fallback; stop/refcount gating; exact timing and rollover boundaries | +| `test_webconfig_keys` | `src/helpers/WebConfigKeys.h` | POST-key allowlist and reboot classification, secret detection, admin-password and browser-terminal command validation, slot-index bounds, and short-input guards | +| `test_webconfig_batch` | `src/helpers/WebConfigBatch.h` | config POST/replay/busy decisions; paced command drain; setup WiFi validation/IP handoff, including channel-change suppression; reboot confirmation/fallback; stop/refcount gating; exact timing and rollover boundaries | | `test_topic_template` | `src/helpers/MQTTTopicTemplate.h` | `{iata}/{device}/{token}/{type}` expansion, overflow/NUL-termination, and a buffer-size fuzz | | `test_mqtt_topic_router` | `src/helpers/MQTTTopicRouter.h` | complete preset/custom topic-routing contract; MeshRank all types except raw; required identifiers; invalid inputs/slots; exact buffer boundaries | | `test_mqtt_connection_policy` | `src/helpers/MQTTConnectionPolicy.h` | reconnect guard/backoff/stagger and breaker transitions; stable reset; JWT lifetime/renewal policy; exact timing boundaries and 32-bit `millis()` rollover | @@ -44,19 +44,20 @@ does not reflect the GoogleTest count -- run the built binary directly | `test_telemetry_history` | `src/helpers/TelemetryHistory.h`, `ExternalVoltageHistory.h` | 30-minute rings; seven-day temperature/battery and four-day multi-channel I2C voltage retention; exact 1 C temperature/status and 0.02 V packed voltage encodings; zero-only channel omission; Base64 pages and raw chunks; GPS differentials, resize preservation, heap budgets, and paging bounds | | `test_flood_filter_policy` | `src/helpers/FloodFilterPolicy.h` | unordered blacklist matching; ordered 1/2/3-byte pbyte rule prefixes; original incoming scope classes and canonical region-name identity; channel-authentication cache key comparison; priority ordering and terminal stop masks; bridge-bucket and regionless channel-target selector encoding; `require=region` and per-channel scope-gate truth tables; fast/slow timing; adding, replacing, and preserving packet scope | | `test_logical_message_cache` | `src/helpers/LogicalMessageCache.h` | bounded logical-message mapping; stable retry timestamps; exact older retries after newer messages; stale and same-timestamp mismatch rejection | -| `test_cli_command_utils` | `src/helpers/CLICommandUtils.h`, `src/helpers/ContactListOrder.h`, `src/helpers/TerminalCommandTracker.h`, `src/helpers/TerminalDisplayFilter.h` | terminal verb/argument/path parsing; routed receive labels; quiet display defaults and independent emergency filtering; favorite-first contact ordering; single-command reply matching, round-trip timing, and rollover-safe expiration | +| `test_cli_command_utils` | `src/helpers/CLICommandUtils.h`, `src/helpers/ContactListOrder.h`, `src/helpers/TerminalCommandTracker.h`, `src/helpers/TerminalDisplayFilter.h`, `src/helpers/WiFiChannelPolicy.h`, `src/helpers/bridges/ESPNowBridgeFormat.h` | terminal verb/argument/path parsing; routed receive labels; quiet display defaults and independent emergency filtering; favorite-first contact ordering; standalone WiFi validation including 64-hex WPA/WPA2 PSKs; strict ESP-NOW channel and bridge-format parsing/range/fallback; single-command reply matching, round-trip timing, and rollover-safe expiration | +| `test_espnow_raw_fragmentation` | `src/helpers/ESPNowRawFragmentation.h` | byte-exact legacy raw frames; 251-255-byte two-frame encoding; CRC-32 integrity; source-MAC-keyed bounded reassembly; malformed, duplicate, out-of-order, timeout, rollover, and capacity handling | | `test_gps_time_validation` | `src/helpers/sensors/GpsTimeValidation.h` | complete NMEA UTC validation; leap years and calendar bounds; rejection of receiver-default and signed-32-bit-out-of-range dates | | `test_identity_generation` | `src/helpers/IdentityGeneration.h` | reserved-prefix rejection; bounded retries; final provisioned attempt; fail-closed exhaustion | | `test_remote_cli_reply_cache` | `src/helpers/RemoteCliReplyCache.h`, `src/helpers/RemoteCliRequest.h`, `src/helpers/RemoteCliTimeout.h` | authenticated logical-request matching; bounded recent-reply history; backward-compatible retry identity; 300% response timeout; empty-response completion; on-air truncation and clearing | | `test_companion_frame_queue` | `src/helpers/CompanionFrameQueue.h` | response/required/best-effort classification; reserved capacity; stable priority; safe eviction; message-waiting coalescing | | `test_companion_status_response` | `src/helpers/CompanionStatusResponse.h` | request-tag correlation and minimum status-response length, including rejection of the three-entry ACL payload that previously masqueraded as status | -| `test_serial_mode_switch` | `src/helpers/ArduinoSerialInterface.cpp`, `src/helpers/MultiSerialInterface.h` | terminal/seeder control-sequence recognition and passthrough ownership; queued/atomic USB output under backpressure and short writes; partial-frame busy state; requester-affine replies, locked contact streams, and Bluetooth-only pairing routing | +| `test_serial_mode_switch` | `src/helpers/ArduinoSerialInterface.cpp`, `src/helpers/MultiSerialInterface.h` | terminal/seeder control-sequence recognition, single-TTY logging transitions, and USB/TCP ownership; queued/atomic USB output under backpressure and short writes; partial-frame busy state; requester-affine replies, locked contact streams, and Bluetooth-only pairing routing | | `test_ble_tx_stall_watchdog` | `src/helpers/BleTxStallWatchdog.h` | exact BLE fragment progress; blocked-reply timeout; rollover-safe elapsed time; disconnect recovery retry and completion | | `test_ble_mota_control` | `src/helpers/BleMotaStream.h`, `CompanionMotaControl.h` | encrypted mOTA channel ring buffering, overflow fail-closed behavior, request gating, and strict rejection of injected or USB-ownership control commands | | `test_atomic_file_writer` | `src/helpers/AtomicFileWriter.h` | verified temporary-file commit; short-write, readback, validation, and rename failures; preservation of the live file and stale-temp cleanup | | `test_cad_timing` | `src/helpers/radiolib/CadTiming.h`, `LR2021SideDetectorConfig.h`, `RadioAirtime.h` | Cascade and slow-profile CAD deadlines; invalid airtime handling; bounded LR2021 side-detector parsing and LDRO recomputation | | `test_companion_node_prefs` | `examples/companion_radio/NodePrefs.h` | independent device power saving, RXPS, Wi-Fi, and FEM preferences; one-time migration of the regressed power-saving default | -| `test_config_serializer` | `src/helpers/ConfigSerializer.cpp`, Companion `NodePrefs` | escaped config save/load, whitespace and malformed input, unknown fields, and FEM preference round trips | +| `test_config_serializer` | `src/helpers/ConfigSerializer.cpp`, Companion `NodePrefs` | escaped config save/load, whitespace and malformed input, unknown fields, and FEM/ESP-NOW bridge-format preference round trips | | `test_deferred_cli_command` | `src/helpers/DeferredCliCommand.h` | copying authenticated command context, single-pending-command enforcement, clearing, and length rejection | | `test_host_cli_bridge` | `src/helpers/HostCliBridge.h` | bounded request/reply parsing, Base64URL serial framing, correlation preservation, one-time service-claim proofs, request-token fields, line safety, and UTF-8-safe truncation | | `test_kiss_modem` | `examples/kiss_modem/KissModem.cpp` | KISS escaping/framing and packet metadata under partial writes, host TX backpressure, queue saturation, and radio completion; run with `native_kiss_modem` | diff --git a/test/test_build_profiles.sh b/test/test_build_profiles.sh index 252afae2..7d4fab50 100644 --- a/test/test_build_profiles.sh +++ b/test/test_build_profiles.sh @@ -290,6 +290,89 @@ SenseCapIndicator-ESPNow_comp_radio_usb|SenseCapIndicator-ESPNow_companion_radio SenseCapIndicator-LoRa_comp_radio_usb_wifi|SenseCapIndicator-LoRa_companion_radio_full|SenseCapIndicator-LoRa_comp_radio_usb_wifi FULL_COMPANION_SPECS +# The Full overlay, not the historical transport used as its build base, owns +# the capability contract. Verify every registered ESP32 Full target receives +# an ordinary WiFi Companion transport even when its base was USB- or BLE-only. +for full_env in "${SUPPORTED_PIO_ENVS[@]}"; do + is_esp32_companion_radio_full_target "$full_env" || continue + pio_env=$(get_pio_build_env "$full_env") + PLATFORMIO_BUILD_FLAGS="" + PLATFORMIO_BUILD_UNFLAGS="" + PLATFORMIO_BUILD_SRC_FILTER="" + BUILD_REDUCTIONS=() + apply_companion_radio_full_profile "$full_env" "$pio_env" + apply_esp32_full_async_tcp_profile "$full_env" + + if ! pio_env_option_contains "$pio_env" build_flags WIFI_SSID \ + && [[ "$PLATFORMIO_BUILD_FLAGS" != *"WIFI_SSID"* ]]; then + fail "$full_env Full Companion omitted ordinary WiFi credentials" + fi + if ! pio_env_option_contains "$pio_env" build_src_filter "helpers/esp32/*.cpp" \ + && ! pio_env_option_contains "$pio_env" build_src_filter \ + "helpers/esp32/SerialWifiInterface.cpp" \ + && [[ "$PLATFORMIO_BUILD_SRC_FILTER" \ + != *"helpers/esp32/SerialWifiInterface.cpp"* ]]; then + fail "$full_env Full Companion omitted SerialWifiInterface" + fi + [[ "$PLATFORMIO_BUILD_FLAGS" == *"WIFI_OTA_SEEDER=1"* ]] \ + || fail "$full_env Full Companion omitted its WiFi runtime overlay" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"CONFIG_ASYNC_TCP_STACK_SIZE=4096"* ]] \ + || fail "$full_env Full Companion omitted its bounded AsyncTCP stack" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"CONFIG_ASYNC_TCP_RUNNING_CORE=1"* ]] \ + || fail "$full_env Full Companion omitted its AsyncTCP core isolation" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"ASYNCWEBSERVER_USE_CHUNK_INFLIGHT=0"* ]] \ + || fail "$full_env Full Companion omitted its slow-client response profile" + + case "${full_env,,}" in + generic_espnow_companion_radio_full|\ + sensecapindicator-espnow_companion_radio_full) + pio_env_option_contains "$pio_env" build_flags "MESH_PRIMARY_ESPNOW=1" \ + || fail "$full_env lost its primary ESP-NOW radio marker" + [[ "$PLATFORMIO_BUILD_UNFLAGS" != *"MESH_PRIMARY_ESPNOW"* ]] \ + || fail "$full_env removed its primary ESP-NOW radio marker" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"MESH_ESPNOW_RADIO=1"* ]] \ + || fail "$full_env omitted ESP-NOW/WiFi coexistence policy" + ;; + esac +done +unset PLATFORMIO_BUILD_FLAGS PLATFORMIO_BUILD_UNFLAGS \ + PLATFORMIO_BUILD_SRC_FILTER + +# The bounded AsyncTCP task stack belongs to every ESP32 Full profile, including +# expanded non-Companion builds, but must not leak into ordinary or nRF52 +# recipes. +ESP32_FULL_BUILD=1 +PLATFORMIO_BUILD_FLAGS="" +apply_esp32_full_async_tcp_profile Heltec_v3_repeater +[[ "$PLATFORMIO_BUILD_FLAGS" == *"CONFIG_ASYNC_TCP_STACK_SIZE=4096"* ]] \ + || fail "expanded ESP32 Full omitted its bounded AsyncTCP stack" +[[ "$PLATFORMIO_BUILD_FLAGS" == *"CONFIG_ASYNC_TCP_RUNNING_CORE=1"* ]] \ + || fail "expanded ESP32 Full omitted its AsyncTCP core isolation" +[[ "$PLATFORMIO_BUILD_FLAGS" == *"ASYNCWEBSERVER_USE_CHUNK_INFLIGHT=0"* ]] \ + || fail "expanded ESP32 Full omitted its slow-client response profile" + +ESP32_FULL_BUILD=0 +PLATFORMIO_BUILD_FLAGS="" +apply_esp32_full_async_tcp_profile Heltec_v3_repeater +[[ "$PLATFORMIO_BUILD_FLAGS" != *"CONFIG_ASYNC_TCP_STACK_SIZE"* ]] \ + || fail "ordinary ESP32 inherited the Full AsyncTCP stack override" +[[ "$PLATFORMIO_BUILD_FLAGS" != *"CONFIG_ASYNC_TCP_RUNNING_CORE"* ]] \ + || fail "ordinary ESP32 inherited the Full AsyncTCP core override" +[[ "$PLATFORMIO_BUILD_FLAGS" != *"ASYNCWEBSERVER_USE_CHUNK_INFLIGHT"* ]] \ + || fail "ordinary ESP32 inherited the Full slow-client response override" + +ESP32_FULL_BUILD=1 +PLATFORMIO_BUILD_FLAGS="" +apply_esp32_full_async_tcp_profile RAK_4631_companion_radio_full +[[ "$PLATFORMIO_BUILD_FLAGS" != *"CONFIG_ASYNC_TCP_STACK_SIZE"* ]] \ + || fail "nRF52 Full inherited the ESP32 AsyncTCP stack override" +[[ "$PLATFORMIO_BUILD_FLAGS" != *"CONFIG_ASYNC_TCP_RUNNING_CORE"* ]] \ + || fail "nRF52 Full inherited the ESP32 AsyncTCP core override" +[[ "$PLATFORMIO_BUILD_FLAGS" != *"ASYNCWEBSERVER_USE_CHUNK_INFLIGHT"* ]] \ + || fail "nRF52 Full inherited the ESP32 slow-client response override" +ESP32_FULL_BUILD=0 +unset PLATFORMIO_BUILD_FLAGS + while IFS='|' read -r source_env full_env; do [ "$(get_esp32_full_companion_replacement "$source_env")" = "$full_env" ] \ || fail "$source_env did not collapse into $full_env" diff --git a/test/test_cli_command_utils/test_cli_command_utils.cpp b/test/test_cli_command_utils/test_cli_command_utils.cpp index 51b0c76c..b11fd5de 100644 --- a/test/test_cli_command_utils/test_cli_command_utils.cpp +++ b/test/test_cli_command_utils/test_cli_command_utils.cpp @@ -1,10 +1,14 @@ #include +#include + #include #include #include #include +#include #include +#include #include TEST(ContactListOrder, SortsFavoritesBeforeNewerNonFavorites) { @@ -543,8 +547,17 @@ TEST(CLICommandUtils, ValidatesStandaloneWiFiValues) { EXPECT_TRUE(mesh::cli::standaloneWiFiPasswordValid("")); EXPECT_TRUE(mesh::cli::standaloneWiFiPasswordValid( "123456789012345678901234567890123456789012345678901234567890123")); + EXPECT_TRUE(mesh::cli::standaloneWiFiPasswordValid( + "0123456789abcdefABCDEF0123456789abcdefABCDEF0123456789abcdef0123")); + + std::string non_hex_64(64, 'a'); + non_hex_64[31] = 'g'; + EXPECT_FALSE(mesh::cli::standaloneWiFiPasswordValid(non_hex_64.c_str())); + non_hex_64[31] = ' '; + EXPECT_FALSE(mesh::cli::standaloneWiFiPasswordValid(non_hex_64.c_str())); EXPECT_FALSE(mesh::cli::standaloneWiFiPasswordValid( - "1234567890123456789012345678901234567890123456789012345678901234")); + std::string(65, 'a').c_str())); + EXPECT_FALSE(mesh::cli::standaloneWiFiPasswordValid(nullptr)); uint8_t power_save = 99; EXPECT_TRUE(mesh::cli::parseStandaloneWiFiPowerSave("min", power_save)); @@ -569,6 +582,18 @@ TEST(CLICommandUtils, EnforcesWiFiSleepForBluetoothCoexistence) { mesh::wifi::effectivePowerSave(99, true)); EXPECT_EQ(mesh::wifi::kPowerSaveNone, mesh::wifi::effectivePowerSave(99, false)); + EXPECT_EQ(mesh::wifi::kPowerSaveMin, + mesh::wifi::effectivePowerSave( + mesh::wifi::kPowerSaveMax, false, true)); + EXPECT_EQ(mesh::wifi::kPowerSaveMin, + mesh::wifi::effectivePowerSave( + mesh::wifi::kPowerSaveMax, true, true)); + EXPECT_EQ(mesh::wifi::kPowerSaveMin, + mesh::wifi::effectivePowerSave( + mesh::wifi::kPowerSaveNone, true, true)); + EXPECT_EQ(mesh::wifi::kPowerSaveNone, + mesh::wifi::effectivePowerSave( + mesh::wifi::kPowerSaveNone, false, true)); } TEST(CLICommandUtils, DefaultsWiFiPowerSaveToNoneWithoutProfileOverride) { @@ -691,6 +716,152 @@ TEST(CLICommandUtils, FormatsUsefulUnknownSettingErrors) { EXPECT_EQ(nullptr, strstr(reply, "??:")); } +TEST(WiFiChannelPolicy, AcceptsTheSupportedEspNowChannelRange) { + uint8_t channel = 0; + + EXPECT_TRUE(mesh::wifi::parseEspNowChannel("1", channel)); + EXPECT_EQ(1, channel); + EXPECT_TRUE(mesh::wifi::parseEspNowChannel("6", channel)); + EXPECT_EQ(6, channel); + EXPECT_TRUE(mesh::wifi::parseEspNowChannel("13", channel)); + EXPECT_EQ(13, channel); + EXPECT_TRUE(mesh::wifi::parseEspNowChannel(" \t11\t ", channel)); + EXPECT_EQ(11, channel); + + EXPECT_FALSE(mesh::wifi::isValidEspNowChannel(0)); + EXPECT_TRUE(mesh::wifi::isValidEspNowChannel(1)); + EXPECT_TRUE(mesh::wifi::isValidEspNowChannel(13)); + EXPECT_FALSE(mesh::wifi::isValidEspNowChannel(14)); +} + +TEST(WiFiChannelPolicy, RejectsMalformedAndOutOfRangeValuesWithoutMutation) { + const char* invalid[] = { + nullptr, "", " \t", "0", "14", "+1", "-1", "1.0", "6GHz", + "1 2", "1\n", "999999999999999999999999999999999999", + }; + + for (const char* value : invalid) { + uint8_t channel = 7; + EXPECT_FALSE(mesh::wifi::parseEspNowChannel(value, channel)) + << (value == nullptr ? "" : value); + EXPECT_EQ(7, channel); + } +} + +TEST(WiFiChannelPolicy, FallsBackOnlyWhenTheStoredChannelIsInvalid) { + EXPECT_EQ(1, mesh::wifi::validEspNowChannelOrDefault(0, 1)); + EXPECT_EQ(6, mesh::wifi::validEspNowChannelOrDefault(6, 1)); + EXPECT_EQ(13, mesh::wifi::validEspNowChannelOrDefault(13, 1)); + EXPECT_EQ(1, mesh::wifi::validEspNowChannelOrDefault(14, 1)); +} + +TEST(CLICommandUtils, ObserverSettingsNeverStartADisabledBridge) { + int calls = 0; + EXPECT_TRUE(mesh::cli::restartBridgeIfEnabled(false, [&calls]() { + ++calls; + return true; + })); + EXPECT_EQ(0, calls); + + EXPECT_TRUE(mesh::cli::restartBridgeIfEnabled(true, [&calls]() { + ++calls; + return true; + })); + EXPECT_EQ(1, calls); + + EXPECT_FALSE(mesh::cli::restartBridgeIfEnabled(true, [&calls]() { + ++calls; + return false; + })); + EXPECT_EQ(2, calls); +} + +TEST(ESPNowBridgeFormat, ParsesOnlyExplicitSupportedNames) { + uint8_t format = 99; + + EXPECT_TRUE(mesh::bridge::parseEspNowFormat("wrapped", format)); + EXPECT_EQ(mesh::bridge::ESPNOW_FORMAT_WRAPPED, format); + EXPECT_STREQ("wrapped", mesh::bridge::espNowFormatName(format)); + + EXPECT_TRUE(mesh::bridge::parseEspNowFormat("raw", format)); + EXPECT_EQ(mesh::bridge::ESPNOW_FORMAT_RAW, format); + EXPECT_STREQ("raw", mesh::bridge::espNowFormatName(format)); + + const char* invalid[] = { + nullptr, "", "auto", "both", "native", "RAW", "raw ", " wrapped", + }; + for (const char* value : invalid) { + format = 7; + EXPECT_FALSE(mesh::bridge::parseEspNowFormat(value, format)); + EXPECT_EQ(7, format); + } +} + +TEST(ESPNowBridgeFormat, PreservesLegacyDefaultAndRawPayloadCapacity) { + EXPECT_TRUE(mesh::bridge::isValidEspNowFormat( + mesh::bridge::ESPNOW_FORMAT_WRAPPED)); + EXPECT_TRUE(mesh::bridge::isValidEspNowFormat( + mesh::bridge::ESPNOW_FORMAT_RAW)); + EXPECT_FALSE(mesh::bridge::isValidEspNowFormat(2)); + + EXPECT_EQ(246U, mesh::bridge::espNowMaxMeshPacketSize( + mesh::bridge::ESPNOW_FORMAT_WRAPPED)); + EXPECT_EQ(255U, mesh::bridge::espNowMaxMeshPacketSize( + mesh::bridge::ESPNOW_FORMAT_RAW)); + EXPECT_EQ(246U, mesh::bridge::espNowMaxMeshPacketSize(99)); +} + +TEST(ESPNowBridgeFormat, BothFormatsAcceptExactlyChannelsOneThroughThirteen) { + const uint8_t formats[] = { + mesh::bridge::ESPNOW_FORMAT_WRAPPED, + mesh::bridge::ESPNOW_FORMAT_RAW, + }; + + for (uint8_t format : formats) { + EXPECT_EQ(13, mesh::bridge::espNowMaxChannel(format)); + EXPECT_FALSE(mesh::bridge::isValidEspNowBridgeChannel(0, format)); + EXPECT_FALSE(mesh::bridge::isValidEspNowBridgeChannel(14, format)); + + for (uint8_t expected = 1; expected <= 13; ++expected) { + char text[4]; + snprintf(text, sizeof(text), "%u", (unsigned)expected); + uint8_t channel = 99; + EXPECT_TRUE(mesh::bridge::parseEspNowBridgeChannel( + text, format, channel)) << "format=" << (unsigned)format + << " channel=" << (unsigned)expected; + EXPECT_EQ(expected, channel); + EXPECT_TRUE(mesh::bridge::isValidEspNowBridgeChannel(channel, format)); + } + } +} + +TEST(ESPNowBridgeFormat, BothFormatsRejectMalformedChannelsWithoutMutation) { + const uint8_t formats[] = { + mesh::bridge::ESPNOW_FORMAT_WRAPPED, + mesh::bridge::ESPNOW_FORMAT_RAW, + }; + const char* invalid[] = { + nullptr, "", " ", "0", "14", "15", "+6", "-6", "6junk", "1 2", + "6.0", "6\n", "999999999999999999999999999999999", + }; + + for (uint8_t format : formats) { + for (const char* value : invalid) { + uint8_t channel = 7; + EXPECT_FALSE(mesh::bridge::parseEspNowBridgeChannel( + value, format, channel)) + << "format=" << (unsigned)format + << " value=" << (value == nullptr ? "" : value); + EXPECT_EQ(7, channel); + } + + uint8_t channel = 0; + EXPECT_TRUE(mesh::bridge::parseEspNowBridgeChannel( + " \t13\t ", format, channel)); + EXPECT_EQ(13, channel); + } +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/test_config_serializer/test_config_serializer.cpp b/test/test_config_serializer/test_config_serializer.cpp index ad8d56ae..16ec43e1 100644 --- a/test/test_config_serializer/test_config_serializer.cpp +++ b/test/test_config_serializer/test_config_serializer.cpp @@ -254,6 +254,7 @@ TEST(NodePrefs, FemGainSettingsRoundTrip) { saved.radio_fem_txgain = 1; saved.usb_logging_enabled = 0; saved.bridge_uart = 2; + saved.bridge_format = mesh::bridge::ESPNOW_FORMAT_RAW; MockPrintStream output; ASSERT_TRUE(saved.saveSerial(output)); @@ -263,6 +264,7 @@ TEST(NodePrefs, FemGainSettingsRoundTrip) { EXPECT_NE(std::string::npos, serialised.find("fem_txgain:1")); EXPECT_NE(std::string::npos, serialised.find("usb_log:0")); EXPECT_NE(std::string::npos, serialised.find("uart:2")); + EXPECT_NE(std::string::npos, serialised.find("format:1")); MockInputStream input(serialised.c_str()); NodePrefs loaded; @@ -270,12 +272,46 @@ TEST(NodePrefs, FemGainSettingsRoundTrip) { loaded.radio_fem_txgain = 0; loaded.usb_logging_enabled = 1; loaded.bridge_uart = 1; + loaded.bridge_format = mesh::bridge::ESPNOW_FORMAT_WRAPPED; ASSERT_TRUE(loaded.loadSerial(input)); EXPECT_EQ(0, loaded.radio_fem_rxgain); EXPECT_EQ(1, loaded.radio_fem_txgain); EXPECT_EQ(0, loaded.usb_logging_enabled); EXPECT_EQ(2, loaded.bridge_uart); + EXPECT_EQ(mesh::bridge::ESPNOW_FORMAT_RAW, loaded.bridge_format); +} + +TEST(NodePrefs, BridgeFormatDefaultsToWrappedAndIsWrittenExplicitly) { + NodePrefs prefs; + EXPECT_EQ(mesh::bridge::ESPNOW_FORMAT_WRAPPED, prefs.bridge_format); + + MockPrintStream output; + ASSERT_TRUE(prefs.saveSerial(output)); + + std::string serialised(reinterpret_cast(output.getBytes()), + output.getLength()); + EXPECT_NE(std::string::npos, serialised.find("format:0")); +} + +TEST(NodePrefs, LegacySerialWithoutBridgeFormatKeepsWrappedDefault) { + MockInputStream legacy("{bridge:{ch:13,secret:\"legacy\"}}"); + NodePrefs loaded; + ASSERT_EQ(mesh::bridge::ESPNOW_FORMAT_WRAPPED, loaded.bridge_format); + + ASSERT_TRUE(loaded.loadSerial(legacy)); + EXPECT_EQ(13, loaded.bridge_channel); + EXPECT_STREQ("legacy", loaded.bridge_secret); + EXPECT_EQ(mesh::bridge::ESPNOW_FORMAT_WRAPPED, loaded.bridge_format); +} + +TEST(NodePrefs, ExplicitWrappedBridgeFormatReplacesRawInMemoryValue) { + MockInputStream serialised("{bridge:{format:0}}"); + NodePrefs loaded; + loaded.bridge_format = mesh::bridge::ESPNOW_FORMAT_RAW; + + ASSERT_TRUE(loaded.loadSerial(serialised)); + EXPECT_EQ(mesh::bridge::ESPNOW_FORMAT_WRAPPED, loaded.bridge_format); } diff --git a/test/test_espnow_raw_fragmentation/test_espnow_raw_fragmentation.cpp b/test/test_espnow_raw_fragmentation/test_espnow_raw_fragmentation.cpp new file mode 100644 index 00000000..9b220007 --- /dev/null +++ b/test/test_espnow_raw_fragmentation/test_espnow_raw_fragmentation.cpp @@ -0,0 +1,458 @@ +#include + +#include +#include +#include + +#include +#include + +namespace { + +using mesh::espnow::ESPNowRawFrames; +using mesh::espnow::ESPNowRawReassemblerT; +using mesh::espnow::ESPNowRawReassemblyResult; + +static std::array makePacket(uint8_t salt = 0) { + std::array packet{}; + // Version zero is the only currently valid serialized MeshCore version. + packet[0] = static_cast(0x03U | ((salt & 0x0FU) << 2)); + for (size_t i = 1; i < packet.size(); ++i) { + packet[i] = static_cast((i * 37U + salt * 19U) & 0xFFU); + } + return packet; +} + +static const uint8_t MAC_A[mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE] = + {0x02, 0x11, 0x22, 0x33, 0x44, 0x55}; +static const uint8_t MAC_B[mesh::espnow::ESPNOW_RAW_SOURCE_MAC_SIZE] = + {0x02, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE}; + +struct ValidWirePacket { + std::array bytes{}; + size_t length = 0; +}; + +static ValidWirePacket makeValidWirePacket(size_t target_length) { + mesh::Packet packet; + packet.payload_len = MAX_PACKET_PAYLOAD; + for (size_t i = 0; i < packet.payload_len; ++i) { + packet.payload[i] = static_cast((i * 3U + 7U) & 0xFFU); + } + + if (target_length == 250) { + packet.header = static_cast( + (PAYLOAD_TYPE_RAW_CUSTOM << PH_TYPE_SHIFT) | ROUTE_TYPE_FLOOD); + packet.setPathHashSizeAndCount(2, 32); // 64 path bytes + } else { + packet.header = static_cast( + (PAYLOAD_TYPE_RAW_CUSTOM << PH_TYPE_SHIFT) + | ROUTE_TYPE_TRANSPORT_FLOOD); + packet.transport_codes[0] = 0x1122; + packet.transport_codes[1] = 0x3344; + const size_t path_bytes = target_length - 1U - 4U - 1U + - MAX_PACKET_PAYLOAD; + if (path_bytes == 64) { + packet.setPathHashSizeAndCount(2, 32); + } else { + packet.setPathHashSizeAndCount(1, + static_cast(path_bytes)); + } + } + for (size_t i = 0; i < packet.getPathByteLen(); ++i) { + packet.path[i] = static_cast((0x80U + i) & 0xFFU); + } + + ValidWirePacket wire; + wire.length = packet.writeTo(wire.bytes.data()); + return wire; +} + +TEST(ESPNowRawFragmentation, ConstantsMatchMeshCoreAndReserveInvalidVersion) { + EXPECT_EQ(static_cast(MAX_TRANS_UNIT), + mesh::espnow::ESPNOW_RAW_MAX_PACKET_SIZE); + EXPECT_EQ(250U, mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE); + EXPECT_EQ(3U, mesh::espnow::ESPNOW_RAW_FRAGMENT_MAGIC[0] >> 6); + EXPECT_LE(mesh::espnow::ESPNOW_RAW_FRAGMENT_HEADER_SIZE + + mesh::espnow::ESPNOW_RAW_FRAGMENT_DATA_SIZE, + mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE); +} + +TEST(ESPNowRawFragmentation, Crc32UsesTheStandardIEEEVector) { + static const uint8_t input[] = {'1', '2', '3', '4', '5', + '6', '7', '8', '9'}; + EXPECT_EQ(0xCBF43926UL, + mesh::espnow::espNowRawCrc32(input, sizeof(input))); + EXPECT_EQ(0U, mesh::espnow::espNowRawCrc32(nullptr, 0)); +} + +TEST(ESPNowRawFragmentation, OrdinaryRawFramesRemainExactlyOneUnchangedFrame) { + const auto packet = makePacket(); + const size_t lengths[] = {2, 249, 250}; + + for (size_t len : lengths) { + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), len, + frames)); + ASSERT_EQ(1U, frames.count) << "len=" << len; + EXPECT_EQ(len, frames.lengths[0]); + EXPECT_EQ(0, memcmp(packet.data(), frames.data[0], len)); + EXPECT_EQ(0U, frames.lengths[1]); + } +} + +TEST(ESPNowRawFragmentation, RejectsNullEmptyAndOverLimitInput) { + auto packet = makePacket(); + ESPNowRawFrames frames; + + EXPECT_FALSE(mesh::espnow::encodeEspNowRawFrames(nullptr, 2, frames)); + EXPECT_EQ(0U, frames.count); + EXPECT_FALSE(mesh::espnow::encodeEspNowRawFrames(packet.data(), 0, frames)); + EXPECT_EQ(0U, frames.count); + EXPECT_FALSE(mesh::espnow::encodeEspNowRawFrames( + packet.data(), mesh::espnow::ESPNOW_RAW_MAX_PACKET_SIZE + 1, frames)); + EXPECT_EQ(0U, frames.count); +} + +TEST(ESPNowRawFragmentation, SplitsOnlyOversizePacketsIntoTwoBoundedFrames) { + const auto packet = makePacket(); + const size_t lengths[] = {251, 252, 253, 254, 255}; + + for (size_t len : lengths) { + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), len, + frames)); + ASSERT_EQ(2U, frames.count) << "len=" << len; + EXPECT_EQ(mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE, frames.lengths[0]); + EXPECT_LE(frames.lengths[1], + mesh::espnow::ESPNOW_RAW_MAX_FRAME_SIZE); + EXPECT_EQ(0, memcmp(frames.data[0], + mesh::espnow::ESPNOW_RAW_FRAGMENT_MAGIC, + mesh::espnow::ESPNOW_RAW_FRAGMENT_MAGIC_SIZE)); + EXPECT_EQ(0, memcmp(frames.data[1], + mesh::espnow::ESPNOW_RAW_FRAGMENT_MAGIC, + mesh::espnow::ESPNOW_RAW_FRAGMENT_MAGIC_SIZE)); + EXPECT_EQ(len, frames.data[0][7]); + EXPECT_EQ(len, frames.data[1][7]); + EXPECT_EQ(0U, frames.data[0][6]); + EXPECT_EQ(1U, frames.data[1][6]); + EXPECT_EQ(0U, frames.data[0][8]); + EXPECT_EQ(mesh::espnow::ESPNOW_RAW_FRAGMENT_DATA_SIZE, + frames.data[1][8]); + } +} + +TEST(ESPNowRawFragmentation, ValidMeshCorePacketsRoundTripAcrossBoundary) { + const size_t lengths[] = {250, 251, 254}; + for (size_t expected_length : lengths) { + const ValidWirePacket wire = makeValidWirePacket(expected_length); + ASSERT_EQ(expected_length, wire.length); + + mesh::Packet input_check; + ASSERT_TRUE(input_check.readFrom( + wire.bytes.data(), static_cast(wire.length))); + + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames( + wire.bytes.data(), wire.length, frames)); + ASSERT_EQ(expected_length <= 250 ? 1U : 2U, frames.count); + + ESPNowRawReassemblerT<2> reassembler; + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + ESPNowRawReassemblyResult result = + ESPNowRawReassemblyResult::REJECTED; + for (uint8_t i = 0; i < frames.count; ++i) { + result = reassembler.acceptFrame( + MAC_A, frames.data[i], frames.lengths[i], 100U + i, + output, sizeof(output), output_len); + } + EXPECT_EQ(expected_length <= 250 + ? ESPNowRawReassemblyResult::PASSTHROUGH + : ESPNowRawReassemblyResult::PACKET_COMPLETE, + result); + ASSERT_EQ(wire.length, output_len); + EXPECT_EQ(0, memcmp(wire.bytes.data(), output, output_len)); + + mesh::Packet decoded; + EXPECT_TRUE(decoded.readFrom(output, static_cast(output_len))); + EXPECT_EQ(MAX_PACKET_PAYLOAD, decoded.payload_len); + } +} + +TEST(ESPNowRawFragmentation, FragmentEnvelopeHasStableGoldenWireOrder) { + const ValidWirePacket wire = makeValidWirePacket(251); + ASSERT_EQ(251U, wire.length); + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames( + wire.bytes.data(), wire.length, frames)); + ASSERT_EQ(2U, frames.count); + + // Header fields and CRC32 are network byte order. These bytes intentionally + // do not derive their expected checksum from the implementation under test. + static const uint8_t expected_first_header[] = { + 0xFE, 0x4D, 0x43, 0x46, 0x01, 0x02, 0x00, + 0xFB, 0x00, 0x51, 0x24, 0x1C, 0xDC}; + static const uint8_t expected_second_header[] = { + 0xFE, 0x4D, 0x43, 0x46, 0x01, 0x02, 0x01, + 0xFB, 0xED, 0x51, 0x24, 0x1C, 0xDC}; + EXPECT_EQ(0, memcmp(expected_first_header, frames.data[0], + sizeof(expected_first_header))); + EXPECT_EQ(0, memcmp(expected_second_header, frames.data[1], + sizeof(expected_second_header))); +} + +TEST(ESPNowRawFragmentation, PassesOrdinaryFramesThroughExactly) { + const auto packet = makePacket(); + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 99; + ESPNowRawReassemblerT<2> reassembler; + + EXPECT_EQ(ESPNowRawReassemblyResult::PASSTHROUGH, + reassembler.acceptFrame(MAC_A, packet.data(), 250, 10, + output, sizeof(output), output_len)); + EXPECT_EQ(250U, output_len); + EXPECT_EQ(0, memcmp(packet.data(), output, output_len)); +} + +TEST(ESPNowRawFragmentation, ReassemblesEveryOversizeLengthInOrder) { + const auto packet = makePacket(); + for (size_t len = 251; len <= MAX_TRANS_UNIT; ++len) { + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), len, + frames)); + ESPNowRawReassemblerT<2> reassembler; + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 100, output, sizeof(output), output_len)); + EXPECT_EQ(0U, output_len); + EXPECT_EQ(ESPNowRawReassemblyResult::PACKET_COMPLETE, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 101, output, sizeof(output), output_len)); + ASSERT_EQ(len, output_len); + EXPECT_EQ(0, memcmp(packet.data(), output, len)); + } +} + +TEST(ESPNowRawFragmentation, ReassemblesOutOfOrder) { + const auto packet = makePacket(); + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + frames)); + ESPNowRawReassemblerT<2> reassembler; + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 1, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::PACKET_COMPLETE, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 2, output, sizeof(output), output_len)); + ASSERT_EQ(packet.size(), output_len); + EXPECT_EQ(0, memcmp(packet.data(), output, output_len)); +} + +TEST(ESPNowRawFragmentation, KeysConcurrentAssembliesBySourceMac) { + const auto packet = makePacket(); + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + frames)); + ESPNowRawReassemblerT<2> reassembler; + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 10, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_B, frames.data[0], frames.lengths[0], + 11, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::PACKET_COMPLETE, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 12, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::PACKET_COMPLETE, + reassembler.acceptFrame(MAC_B, frames.data[1], frames.lengths[1], + 13, output, sizeof(output), output_len)); +} + +TEST(ESPNowRawFragmentation, HandlesIdenticalAndConflictingDuplicates) { + const auto packet = makePacket(); + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + frames)); + ESPNowRawReassemblerT<2> reassembler; + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 1, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::DUPLICATE, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 2, output, sizeof(output), output_len)); + + ESPNowRawFrames conflicting = frames; + conflicting.data[0][mesh::espnow::ESPNOW_RAW_FRAGMENT_HEADER_SIZE + 3] ^= 1; + EXPECT_EQ(ESPNowRawReassemblyResult::REJECTED, + reassembler.acceptFrame(MAC_A, conflicting.data[0], + conflicting.lengths[0], 3, output, + sizeof(output), output_len)); + + EXPECT_EQ(ESPNowRawReassemblyResult::PACKET_COMPLETE, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 4, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::DUPLICATE, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 5, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::DUPLICATE, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 6, output, sizeof(output), output_len)); +} + +TEST(ESPNowRawFragmentation, RejectsCorruptPayloadAtWholePacketIntegrityCheck) { + const auto packet = makePacket(); + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + frames)); + frames.data[1][mesh::espnow::ESPNOW_RAW_FRAGMENT_HEADER_SIZE] ^= 0x80; + + ESPNowRawReassemblerT<2> reassembler; + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 1, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::REJECTED, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 2, output, sizeof(output), output_len)); + EXPECT_EQ(0U, output_len); +} + +TEST(ESPNowRawFragmentation, RejectsMalformedReservedEnvelopes) { + const auto packet = makePacket(); + ESPNowRawFrames original; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + original)); + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + + auto expectRejected = [&](ESPNowRawFrames frames, size_t frame_len) { + ESPNowRawReassemblerT<1> reassembler; + EXPECT_EQ(ESPNowRawReassemblyResult::REJECTED, + reassembler.acceptFrame(MAC_A, frames.data[0], frame_len, 1, + output, sizeof(output), output_len)); + EXPECT_EQ(0U, output_len); + }; + + ESPNowRawFrames bad = original; + bad.data[0][1] ^= 1; + expectRejected(bad, bad.lengths[0]); + bad = original; + bad.data[0][4]++; + expectRejected(bad, bad.lengths[0]); + bad = original; + bad.data[0][5] = 3; + expectRejected(bad, bad.lengths[0]); + bad = original; + bad.data[0][6] = 2; + expectRejected(bad, bad.lengths[0]); + bad = original; + bad.data[0][7] = 250; + expectRejected(bad, bad.lengths[0]); + bad = original; + bad.data[0][8] = 1; + expectRejected(bad, bad.lengths[0]); + expectRejected(original, + mesh::espnow::ESPNOW_RAW_FRAGMENT_HEADER_SIZE - 1); + expectRejected(original, original.lengths[0] - 1); +} + +TEST(ESPNowRawFragmentation, RequiresAdequateOutputWithoutOverflowingIt) { + const auto packet = makePacket(); + ESPNowRawReassemblerT<1> reassembler; + uint8_t output[254] = {}; + size_t output_len = 77; + + EXPECT_EQ(ESPNowRawReassemblyResult::OUTPUT_TOO_SMALL, + reassembler.acceptFrame(MAC_A, packet.data(), 250, 1, + output, 249, output_len)); + EXPECT_EQ(0U, output_len); + + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + frames)); + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 2, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::OUTPUT_TOO_SMALL, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 3, output, sizeof(output), output_len)); + EXPECT_EQ(0U, output_len); +} + +TEST(ESPNowRawFragmentation, ExpiresAssembliesAcrossMillisRollover) { + const auto packet = makePacket(); + ESPNowRawFrames frames; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames(packet.data(), packet.size(), + frames)); + ESPNowRawReassemblerT<1> reassembler(20); + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[0], frames.lengths[0], + 0xFFFFFFF0UL, output, sizeof(output), + output_len)); + // 0xFFFFFFF0 -> 0x00000005 is 21 ms, so fragment zero has expired. + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames.data[1], frames.lengths[1], + 0x00000005UL, output, sizeof(output), + output_len)); + EXPECT_EQ(0U, output_len); +} + +TEST(ESPNowRawFragmentation, BoundedSlotsEvictOldestIncompleteAssembly) { + const auto packet_a = makePacket(1); + const auto packet_b = makePacket(2); + const auto packet_c = makePacket(3); + ESPNowRawFrames frames_a; + ESPNowRawFrames frames_b; + ESPNowRawFrames frames_c; + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames( + packet_a.data(), packet_a.size(), frames_a)); + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames( + packet_b.data(), packet_b.size(), frames_b)); + ASSERT_TRUE(mesh::espnow::encodeEspNowRawFrames( + packet_c.data(), packet_c.size(), frames_c)); + + ESPNowRawReassemblerT<2> reassembler(1000); + uint8_t output[MAX_TRANS_UNIT] = {}; + size_t output_len = 0; + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames_a.data[0], frames_a.lengths[0], + 10, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames_b.data[0], frames_b.lengths[0], + 20, output, sizeof(output), output_len)); + EXPECT_EQ(ESPNowRawReassemblyResult::FRAGMENT_STORED, + reassembler.acceptFrame(MAC_A, frames_c.data[0], frames_c.lengths[0], + 30, output, sizeof(output), output_len)); + + // A was oldest and was evicted; B remains and can complete. + EXPECT_EQ(ESPNowRawReassemblyResult::PACKET_COMPLETE, + reassembler.acceptFrame(MAC_A, frames_b.data[1], frames_b.lengths[1], + 40, output, sizeof(output), output_len)); + ASSERT_EQ(packet_b.size(), output_len); + EXPECT_EQ(0, memcmp(packet_b.data(), output, output_len)); +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/test_firmware_picker.js b/test/test_firmware_picker.js index 306bc3d8..25de61fe 100644 --- a/test/test_firmware_picker.js +++ b/test/test_firmware_picker.js @@ -329,6 +329,77 @@ const heltecV4TftFemOff = picker.parseTargetProfile( assert.strictEqual(heltecV4TftFemOff.hardware, "heltec_v4_3_tft"); assert.strictEqual(heltecV4TftFemOff.variant, "default"); +const directWifiMqtt = picker.parseTargetProfile( + "Heltec_v3_companion_radio_wifi_mqtt" +); +assert.strictEqual(directWifiMqtt.mode, "wifi"); +assert.strictEqual(directWifiMqtt.logging, "wifi"); +assert.deepStrictEqual(directWifiMqtt.loggingModes, ["wifi"]); +assert.strictEqual(directWifiMqtt.variant, "default"); + +const consolidatedV3 = [ + "Heltec_v3_companion_radio_full", + "Heltec_v3_companion_radio_wifi_mqtt", +].map(function (target) { + return Object.assign(picker.parseTargetProfile(target), { + installKinds: ["bin", "merged-bin"], + }); +}); +picker.applyFullCompanionCapabilities(consolidatedV3); +assert.deepStrictEqual( + consolidatedV3[0].loggingModes, + ["none", "usb"] +); +assert(!picker.profileMatches(consolidatedV3[0], { logging: "wifi" })); +assert.deepStrictEqual( + picker.omitTransportsReplacedByFull(consolidatedV3).map(function (item) { + return item.target; + }), + ["Heltec_v3_companion_radio_full"] +); + +const consolidatedV4 = [ + "heltec_v4_2_v4_3_companion_radio_full_femon", + "heltec_v4_companion_radio_wifi_mqtt_femon", + "heltec_v4_3_companion_radio_wifi_mqtt_femoff", +].map(function (target) { + return Object.assign(picker.parseTargetProfile(target), { + installKinds: ["bin", "merged-bin"], + }); +}); +picker.applyFullCompanionCapabilities(consolidatedV4); +assert.deepStrictEqual( + picker.omitTransportsReplacedByFull(consolidatedV4).map(function (item) { + return item.target; + }), + ["heltec_v4_2_v4_3_companion_radio_full_femon"] +); + +const consolidatedSenseCap = [ + "SenseCapIndicator-LoRa_companion_radio_full", + "SenseCapIndicator-LoRa_comp_radio_usb_wifi", +].map(function (target) { + return Object.assign(picker.parseTargetProfile(target), { + installKinds: ["bin", "merged-bin"], + }); +}); +assert.strictEqual(consolidatedSenseCap[1].variant, "default"); +picker.applyFullCompanionCapabilities(consolidatedSenseCap); +assert.deepStrictEqual( + picker.omitTransportsReplacedByFull(consolidatedSenseCap).map( + function (item) { return item.target; } + ), + ["SenseCapIndicator-LoRa_companion_radio_full"] +); + +const nrfUf2OnlyFull = Object.assign( + picker.parseTargetProfile("RAK_4631_companion_radio_full"), + { installKinds: ["uf2"] } +); +picker.applyFullCompanionCapabilities([nrfUf2OnlyFull]); +assert.strictEqual(nrfUf2OnlyFull.dedicatedUsbLogging, true); +assert.strictEqual(nrfUf2OnlyFull.logging, "usb-runtime"); + const g2RxBoosted = picker.parseTargetProfile( "Station_G2_logging_repeater" ); @@ -436,6 +507,18 @@ assert.strictEqual(mqtt.mode, "mqtt"); assert.strictEqual(mqtt.ota, "lora-receiver"); assert.strictEqual(mqtt.variant, "default"); +const fullCompanionSteps = picker.installSteps(v4Full, "merged-bin"); +assert(fullCompanionSteps.some(function (step) { + return step.includes("usb.logging"); +})); +assert(!fullCompanionSteps.some(function (step) { + return step.includes("logging.output"); +})); +const observerSteps = picker.installSteps(mqtt, "merged-bin"); +assert(observerSteps.some(function (step) { + return step.includes("logging.output"); +})); + const lora = profile( "Station_G2_repeater_lora_ota_no_external_sensors" ); diff --git a/test/test_serial_mode_switch/test_serial_mode_switch.cpp b/test/test_serial_mode_switch/test_serial_mode_switch.cpp index 5c669461..45b0822a 100644 --- a/test/test_serial_mode_switch/test_serial_mode_switch.cpp +++ b/test/test_serial_mode_switch/test_serial_mode_switch.cpp @@ -470,6 +470,39 @@ TEST(SerialModeSwitch, UsbBinaryActivityWinsDuringTcpBorrow) { EXPECT_FALSE(handoff.shouldRestoreAscii(21)); } +TEST(SerialModeSwitch, SingleTtyLoggingCannotStealNetworkTerminal) { + using Action = mesh::UsbLoggingTerminalAction; + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + false, true, false, false, true, true), + Action::NONE); + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + false, true, false, false, false, true), + Action::NONE); +} + +TEST(SerialModeSwitch, LoggingClaimsOnlySingleTtyUsb) { + using Action = mesh::UsbLoggingTerminalAction; + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + false, true, false, false, true, false), + Action::CLAIM_USB); + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + true, true, false, false, true, false), + Action::NONE); +} + +TEST(SerialModeSwitch, LoggingOffRestoresTheBuildDefaultUsbMode) { + using Action = mesh::UsbLoggingTerminalAction; + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + false, false, true, true, false, false), + Action::RETURN_TO_BINARY); + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + false, false, true, true, true, false), + Action::KEEP_ASCII); + EXPECT_EQ(mesh::selectUsbLoggingTerminalAction( + false, false, true, false, false, false), + Action::NONE); +} + TEST(SerialModeSwitch, FailedMotaRestoresOnlyItsAsciiOrigin) { EXPECT_TRUE(mesh::shouldRestoreAsciiAfterMotaFailure( mesh::UsbMotaEntryOrigin::ASCII)); diff --git a/test/test_webconfig_batch/test_webconfig_batch.cpp b/test/test_webconfig_batch/test_webconfig_batch.cpp index 70d1bca1..004b547d 100644 --- a/test/test_webconfig_batch/test_webconfig_batch.cpp +++ b/test/test_webconfig_batch/test_webconfig_batch.cpp @@ -112,12 +112,25 @@ TEST(WebConfigBatch, FinishArmsThirtySecondFallbackOnlyForAFullyOkRebootBatch) { TEST(WebConfigBatch, SetupWiFiHandoffRequiresASuccessfulCredentialChangingReboot) { EXPECT_TRUE(Batch::shouldStartSetupWiFiHandoff( /*setup=*/true, /*reboot=*/true, /*all_ok=*/true, - /*wifi_changed=*/true, /*has_ssid=*/true)); - EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff(false, true, true, true, true)); - EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff(true, false, true, true, true)); - EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff(true, true, false, true, true)); - EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff(true, true, true, false, true)); - EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff(true, true, true, true, false)); + /*wifi_changed=*/true, /*has_ssid=*/true, + /*espnow_channel_changed=*/false)); + EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff( + false, true, true, true, true, false)); + EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff( + true, false, true, true, true, false)); + EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff( + true, true, false, true, true, false)); + EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff( + true, true, true, false, true, false)); + EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff( + true, true, true, true, false, false)); +} + +TEST(WebConfigBatch, EspNowChannelChangeSkipsLiveSetupWiFiHandoff) { + EXPECT_FALSE(Batch::shouldStartSetupWiFiHandoff( + /*setup=*/true, /*reboot=*/true, /*all_ok=*/true, + /*wifi_changed=*/true, /*has_ssid=*/true, + /*espnow_channel_changed=*/true)); } TEST(WebConfigBatch, SetupWiFiHandoffUsesBoundedConnectAndBriefFlushDelays) { diff --git a/test/test_webconfig_keys/test_webconfig_keys.cpp b/test/test_webconfig_keys/test_webconfig_keys.cpp index bd5fcd15..78009d72 100644 --- a/test/test_webconfig_keys/test_webconfig_keys.cpp +++ b/test/test_webconfig_keys/test_webconfig_keys.cpp @@ -14,6 +14,7 @@ TEST(WebConfigKeys, AllowsKnownScalarKeys) { EXPECT_TRUE(wcIsAllowedSetKey("powersaving")); EXPECT_TRUE(wcIsAllowedSetKey("repeat")); EXPECT_TRUE(wcIsAllowedSetKey("wifi.ssid")); + EXPECT_TRUE(wcIsAllowedSetKey("espnow.channel")); EXPECT_TRUE(wcIsAllowedSetKey("mqtt.iata")); EXPECT_TRUE(wcIsAllowedSetKey("mqtt.neighbors")); EXPECT_TRUE(wcIsAllowedSetKey("mqtt.neighbors.interval")); @@ -67,6 +68,15 @@ TEST(WebConfigKeys, IsCaseSensitive) { EXPECT_FALSE(wcIsAllowedSetKey("MQTT1.preset")); } +TEST(WebConfigKeys, EspNowChannelAlwaysRequiresAReboot) { + EXPECT_TRUE(wcSetKeyRequiresReboot("espnow.channel")); + EXPECT_FALSE(wcSetKeyRequiresReboot(NULL)); + EXPECT_FALSE(wcSetKeyRequiresReboot("espnow.channel.extra")); + EXPECT_FALSE(wcSetKeyRequiresReboot("ESPNOW.channel")); + EXPECT_FALSE(wcSetKeyRequiresReboot("wifi.ssid")); + EXPECT_FALSE(wcSetKeyRequiresReboot("")); +} + // ---- short-key OOB guard -------------------------------------------------- // The slot-prefix probe indexes key[4..6]; these short strings must be rejected // without ever reading past the terminator. diff --git a/tools/mota/test_mota.py b/tools/mota/test_mota.py index a399d7ff..555e2102 100644 --- a/tools/mota/test_mota.py +++ b/tools/mota/test_mota.py @@ -281,8 +281,9 @@ def test_canonical_bulk_matrix_omits_runtime_and_transport_aliases(): ) assert "COMPANION_FEATURE_DEDICATED_USB_LOGGING" in companion_features assert "defined(COMPANION_RADIO_FULL)" in companion - assert "if (!mesh::hasDedicatedUsbLoggingPort())" in companion_main - assert "if (mesh::isUsbLoggingEnabled())" in companion_main + assert "mesh::selectUsbLoggingTerminalAction(" in companion_main + assert "mesh::hasDedicatedUsbLoggingPort()" in companion_main + assert "mesh::isUsbLoggingEnabled()" in companion_main assert "enterUsbLoggingTerminalMode();" in companion_main assert "usb_logging_terminal_mode" in companion_main assert "_prefs.usb_logging_enabled = 0" in companion @@ -306,7 +307,7 @@ def test_canonical_bulk_matrix_omits_runtime_and_transport_aliases(): assert "is_esp32_dual_cdc_companion_radio_full_target" not in replacement -def test_single_tty_logging_off_requires_a_subsequent_mode_switch(): +def test_single_tty_logging_off_restores_each_builds_default_mode(): root = Path(__file__).resolve().parents[2] companion_main = ( root / "examples/companion_radio/main.cpp" @@ -317,30 +318,36 @@ def test_single_tty_logging_off_requires_a_subsequent_mode_switch(): "static void expireUsbBinaryStartupProbeBeforeDispatch()", 1 )[0] - # A logging preference changed through BLE/WiFi must release logging's - # exclusive ownership without silently changing the protocol of an open - # USB ASCII session. - external_disable = service.split( - "else if (usb_logging_terminal_mode && the_mesh.isTerminalMode()) {", - 1, - )[1].split("\n }\n }\n#endif", 1)[0] - assert "usb_logging_terminal_mode = false;" in external_disable - assert "clearUsbTerminalLine();" in external_disable - assert "usb_terminal_discard_line = false;" in external_disable - assert "leaveUsbTerminalMode" not in external_disable + # The shared policy distinguishes Full's startup ASCII mode from an + # ordinary USB Companion's Binary default, and an active TCP terminal keeps + # ownership even when the saved USB logging preference is on. + assert "mesh::selectUsbLoggingTerminalAction(" in service + assert "isNetworkTerminalActive()" in service + assert "case mesh::UsbLoggingTerminalAction::RETURN_TO_BINARY:" in service + assert "leaveUsbTerminalMode(true);" in service + assert "case mesh::UsbLoggingTerminalAction::KEEP_ASCII:" in service + keep_ascii = service.split( + "case mesh::UsbLoggingTerminalAction::KEEP_ASCII:", 1 + )[1].split( + "case mesh::UsbLoggingTerminalAction::NONE:", 1 + )[0] + assert "usb_logging_terminal_mode = false;" in keep_ascii + assert "clearUsbTerminalLine();" in keep_ascii + assert "usb_terminal_discard_line = false;" in keep_ascii + assert "leaveUsbTerminalMode" not in keep_ascii - # The same rule applies when `set usb.logging off` is entered on the USB - # logging terminal itself: keep the fresh-flash ASCII mode after replying. + # A command entered on the logging terminal follows the same split: Full + # stays in ASCII, while a non-Full Companion returns to Binary immediately. command_disable = service.split( "the_mesh.handleTerminalCommand(usb_terminal_line);", 1 )[1].split('Serial.print("> ");', 1)[0] assert "!mesh::isUsbLoggingEnabled()" in command_disable assert "usb_logging_terminal_mode = false;" in command_disable - assert "leaveUsbTerminalMode" not in command_disable + assert "#if defined(COMPANION_RADIO_FULL)" in command_disable + assert "leaveUsbTerminalMode(true);" in command_disable - # Binary Companion remains reachable, but only through the ordinary mode - # switch that follows the logging-off command (explicit token or framed - # startup probe), never as a side effect of changing the preference. + # Full Companion reaches Binary through its ordinary explicit token or + # framed startup probe after logging is disabled. terminal_stop = service.split( "if (strcmp(usb_terminal_line, USB_TERMINAL_STOP_TOKEN) == 0) {", 1 )[1].split("}", 1)[0] @@ -728,6 +735,123 @@ def test_release_catalog_resolves_canonical_runtime_aliases(): assert catalog["device"][0]["firmware"] == [canonical] +def test_release_catalog_resolves_legacy_companions_to_plain_full(): + root = Path(__file__).resolve().parents[2] + + def load_module(name, relative_path): + spec = importlib.util.spec_from_file_location(name, root / relative_path) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + provider = load_module( + "meshcore_provider_plain_full_test", + "mesh-america/update-provider-release.py", + ) + logging_provider = load_module( + "meshcore_logging_provider_plain_full_test", + "mesh-america/update-logging-provider-release.py", + ) + + release_files = { + identity: [Path(f"{index}.bin")] + for index, identity in enumerate( + ( + "Station_G2_companion_radio_full", + "ThinkNode_M2_companion_radio_full", + "RAK_4631_companion_radio_full", + "Heltec_v2_companion_radio_full", + "heltec_tracker_v2_companion_radio_full_femon", + "Heltec_v3_companion_radio_full", + "heltec_v4_2_v4_3_companion_radio_full_femon", + "Generic_ESPNOW_companion_radio_full", + "Heltec_E290_companion_radio_full", + "Heltec_T190_companion_radio_full_", + "SenseCapIndicator-ESPNow_companion_radio_full", + "SenseCapIndicator-LoRa_companion_radio_full", + ) + ) + } + migrations = { + # Ordinary transport artifacts can carry either release qualifier. + "Station_G2_companion_radio_usb-ota": ( + "Station_G2_companion_radio_full", False + ), + "Station_G2_companion_radio_ble": ( + "Station_G2_companion_radio_full", False + ), + "Station_G2_companion_radio_wifi-logging": ( + "Station_G2_companion_radio_full", False + ), + "ThinkNode_M2_companion_radio_serial-logging": ( + "ThinkNode_M2_companion_radio_full", False + ), + "RAK_4631_companion_radio_ethernet-logging": ( + "RAK_4631_companion_radio_full", False + ), + "Heltec_v2_companion_radio_wifi-full-logging-ota": ( + "Heltec_v2_companion_radio_full", False + ), + "heltec_tracker_v2_companion_radio_usb_femoff-ota": ( + "heltec_tracker_v2_companion_radio_full_femon", False + ), + # Direct MQTT observers become the MQTT-capable Full image and must + # retain their observer metadata in both catalogs. + "Heltec_v3_companion_radio_wifi_mqtt-ota": ( + "Heltec_v3_companion_radio_full", True + ), + "heltec_v4_companion_radio_wifi_mqtt_femon-ota": ( + "heltec_v4_2_v4_3_companion_radio_full_femon", True + ), + "heltec_v4_3_companion_radio_wifi_mqtt_femoff-ota": ( + "heltec_v4_2_v4_3_companion_radio_full_femon", True + ), + # Nonstandard and combined legacy recipe names use explicit aliases. + "Generic_ESPNOW_comp_radio_usb-ota": ( + "Generic_ESPNOW_companion_radio_full", False + ), + "Generic_ESPNOW_comp_radio_usb-logging": ( + "Generic_ESPNOW_companion_radio_full", False + ), + "Heltec_E290_companion_usb-ota": ( + "Heltec_E290_companion_radio_full", False + ), + "Heltec_E290_companion_ble": ( + "Heltec_E290_companion_radio_full", False + ), + "Heltec_E290_companion_usb_ble-logging": ( + "Heltec_E290_companion_radio_full", False + ), + "Heltec_T190_companion_radio_usb_-ota": ( + "Heltec_T190_companion_radio_full_", False + ), + "Heltec_T190_companion_radio_ble_": ( + "Heltec_T190_companion_radio_full_", False + ), + "Heltec_T190_companion_radio_usb_ble_-logging": ( + "Heltec_T190_companion_radio_full_", False + ), + "SenseCapIndicator-ESPNow_comp_radio_usb-ota": ( + "SenseCapIndicator-ESPNow_companion_radio_full", False + ), + "SenseCapIndicator-ESPNow_comp_radio_usb-logging": ( + "SenseCapIndicator-ESPNow_companion_radio_full", False + ), + "SenseCapIndicator-LoRa_comp_radio_usb_wifi-logging": ( + "SenseCapIndicator-LoRa_companion_radio_full", False + ), + } + + # The logging updater intentionally imports this resolver from the main + # updater. Exercise both loaded modules so a future local copy cannot drift. + for resolver_owner in (provider, logging_provider.common): + for old_identity, expected in migrations.items(): + assert resolver_owner.resolve_release_identity( + old_identity, release_files + ) == expected + + def test_ota_target_generation_honors_explicit_disable(): from gen_targets import ota_envs, release_aliases diff --git a/variants/generic_espnow/platformio.ini b/variants/generic_espnow/platformio.ini index fcc9e722..9106bf76 100644 --- a/variants/generic_espnow/platformio.ini +++ b/variants/generic_espnow/platformio.ini @@ -8,6 +8,7 @@ board = esp32-c3-devkitm-1 build_flags = ${esp32_base.build_flags} -I variants/generic_espnow + -D MESH_PRIMARY_ESPNOW=1 ; -D ESP32_CPU_FREQ=80 -D PIN_BOARD_SDA=-1 -D PIN_BOARD_SCL=-1 @@ -45,6 +46,7 @@ build_flags = -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' + -D MESH_ESPNOW_RADIO=1 -D MAX_NEIGHBOURS=50 build_src_filter = ${Generic_ESPNOW.build_src_filter} +<../examples/simple_repeater/*.cpp> @@ -78,6 +80,7 @@ build_flags = -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' -D ROOM_PASSWORD='"hello"' + -D MESH_ESPNOW_RADIO=1 build_src_filter = ${Generic_ESPNOW.build_src_filter} +<../examples/simple_room_server/*.cpp> lib_deps = diff --git a/variants/sensecap_indicator-espnow/platformio.ini b/variants/sensecap_indicator-espnow/platformio.ini index b86941b1..ec3abfce 100644 --- a/variants/sensecap_indicator-espnow/platformio.ini +++ b/variants/sensecap_indicator-espnow/platformio.ini @@ -9,6 +9,7 @@ board_upload.maximum_size = 8388608 board_build.partitions = default.csv build_flags = ${esp32_base.build_flags} + -D MESH_PRIMARY_ESPNOW=1 -D PIN_BOARD_SDA=39 -D PIN_BOARD_SCL=40 -D BOARD_HAS_PSRAM @@ -63,6 +64,7 @@ lib_deps=${esp32_base.lib_deps} extends = SenseCapIndicator-ESPNow build_flags = ${SenseCapIndicator-ESPNow.build_flags} + -UMESH_PRIMARY_ESPNOW -D SENSECAP_INDICATOR_LORA -D USE_SX1262 -D RADIO_CLASS=CustomSX1262 diff --git a/webui/index.html b/webui/index.html index 5232faeb..13bf6a37 100644 --- a/webui/index.html +++ b/webui/index.html @@ -248,15 +248,18 @@ body.tab-cli{padding-bottom:0}

Step 1 · WiFi

Connect this node to your WiFi network so it can reach the MQTT servers.

-
Preparing for remote deployment? This wizard tests the WiFi before reboot. If the deployment network is not available here, use USB serial at config.meshcore.io and run set wifi.ssid ... and set wifi.pwd .... The node saves them without connecting and retries after deployment.
+
Preparing for remote deployment? This wizard tests the WiFi before reboot unless you also change the shared ESP-NOW channel. If the deployment network is not available here, use USB serial at config.meshcore.io and run set wifi.ssid ... and set wifi.pwd .... The node saves them without connecting and retries after deployment.
- -
Leave blank for an open network. 2.4 GHz networks only.
+ +
Leave blank for an open network. Passphrases may be up to 63 characters; a 64-character key must be hexadecimal. 2.4 GHz networks only.
+
+ +
Must match the 2.4 GHz router and every ESP-NOW node. Scanning fills the router's channel. Use only a channel permitted locally. A change takes effect after reboot, so WiFi is joined after the reboot too.
Shown on the mesh and in MQTT status messages.
@@ -495,7 +498,11 @@ body.tab-cli{padding-bottom:0} -
+
+
Leave blank for an open network. Passphrases may be up to 63 characters; a 64-character key must be hexadecimal.
+
+ +
Channel 1-13 where locally permitted. The router and every ESP-NOW node must match. Selecting a scanned network fills its channel; changes require a reboot.
@@ -598,7 +605,7 @@ body.tab-cli{padding-bottom:0}