Device registry (/devices + hello), static-IP fallback, WS keepalive, uncompressed fonts
Test, Build and Push / test-gateway (push) Successful in 11s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped

- gateway: GET /devices registry (per-IP connect count, timestamps,
  device/fw from new 'hello' protocol event); graceful utterance
  errors -> error event; uvicorn ws-ping-timeout 120s
- firmware: hello on WS connect; static 192.168.86.53 fallback after
  15s without DHCP; scan-on-boot removed (kept for diagnostics);
  ping_interval 8s; fonts regenerated --no-compress (compressed
  glyphs render blank with LV_USE_FONT_COMPRESSED off); 8MB factory
  partition; montserrat_28; LVGL lock timeout semantics fixed
- docs: sauron endpoint plan, power ladder, versioning policy

Known issue: 'Outside' AP association succeeds but no L2 traffic
flows (no DHCP, no ARP) — worked once at 22:05 then never again;
ToJ side verified clean. Investigation ongoing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 22:34:57 +02:00
co-authored by Claude Fable 5
parent ed0e8221f1
commit 3a402220b0
10 changed files with 4928 additions and 1568 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ idf_component_register(
"fonts/font_rain_22.c"
"fonts/font_rage_64.c"
INCLUDE_DIRS "."
PRIV_REQUIRES nvs_flash esp_wifi esp_event esp_netif json esp_timer
PRIV_REQUIRES nvs_flash esp_wifi esp_event esp_netif json esp_timer esp_app_format
)
target_compile_definitions(${COMPONENT_LIB} PRIVATE LV_LVGL_H_INCLUDE_SIMPLE)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+472 -363
View File
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 22 px
* Bpp: 2
* Opts: --font /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf -r 0x20,0x23-0x25,0x2A,0x2B,0x30-0x39,0x3C-0x3E,0x41,0x43,0x45,0x46,0x48,0x4B,0x5A --font /tmp/claude-1000/-mnt-media-Projects-desklock/a3bb8d9c-268f-465a-b40b-889c5b60f451/scratchpad/NotoMonoCJKJP.ttf -r 0x30A2,0x30A4,0x30A6,0x30A8,0x30AA,0x30AB,0x30AD,0x30AF,0x30B1,0x30B3,0x30B5,0x30B7,0x30B9,0x30BB,0x30BD,0x30BF,0x30C1,0x30C4,0x30C6,0x30C8,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE --size 22 --bpp 2 --format lvgl --lv-font-name font_rain_22 -o font_rain_22.c
* Opts: --no-compress --font /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf -r 0x20,0x23-0x25,0x2A,0x2B,0x30-0x39,0x3C-0x3E,0x41,0x43,0x45,0x46,0x48,0x4B,0x5A --font /tmp/claude-1000/-mnt-media-Projects-desklock/a3bb8d9c-268f-465a-b40b-889c5b60f451/scratchpad/NotoMonoCJKJP.ttf -r 0x30A2,0x30A4,0x30A6,0x30A8,0x30AA,0x30AB,0x30AD,0x30AF,0x30B1,0x30B3,0x30B5,0x30B7,0x30B9,0x30BB,0x30BD,0x30BF,0x30C1,0x30C4,0x30C6,0x30C8,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE --size 22 --bpp 2 --format lvgl --lv-font-name font_rain_22 -o font_rain_22.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -25,408 +25,517 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
/* U+0020 " " */
/* U+0023 "#" */
0xe, 0x70, 0xb8, 0x3e, 0xc2, 0x4c, 0x3e, 0x42,
0xc4, 0x3f, 0x20, 0x43, 0xf2, 0x61, 0x21, 0xbe,
0x8b, 0xc3, 0xe0, 0x4a, 0x2, 0x80, 0xb0, 0x1a,
0xd, 0x1, 0x50, 0x64, 0xc2, 0x43, 0xec, 0x44,
0xc3, 0x7c, 0x9e, 0x8b, 0xc0, 0x58, 0xa, 0x2,
0xc0, 0xa6, 0x54, 0x35, 0x6, 0xc4, 0x4c, 0x3e,
0x42, 0xc4, 0x3f, 0x20, 0x43, 0xe0,
0x0, 0x1c, 0xe, 0x0, 0x2, 0xc1, 0xd0, 0x0,
0x3c, 0x2c, 0x0, 0x3, 0x83, 0xc0, 0x0, 0x74,
0x38, 0x3, 0xff, 0xff, 0xfc, 0x1a, 0xfa, 0xfa,
0x80, 0xe, 0xf, 0x0, 0x1, 0xd0, 0xe0, 0x0,
0x2c, 0x1d, 0x0, 0xff, 0xff, 0xff, 0xa, 0xbe,
0xbe, 0xa0, 0x7, 0x43, 0x80, 0x0, 0xb0, 0x74,
0x0, 0xf, 0xb, 0x0, 0x0, 0xe0, 0xf0, 0x0,
/* U+0024 "$" */
0xd, 0x21, 0xff, 0xc4, 0xb6, 0xf4, 0x3b, 0xc,
0xa2, 0x25, 0x6d, 0x84, 0x87, 0xff, 0x16, 0x34,
0x3c, 0xa2, 0x6d, 0xa, 0xe0, 0xac, 0x32, 0xac,
0x10, 0x7d, 0x88, 0x7f, 0xa0, 0xf2, 0x2b, 0xd3,
0x51, 0x68, 0x81, 0x58, 0x2f, 0x37, 0x7, 0xff,
0x28,
0x0, 0x90, 0x0, 0x9, 0x0, 0xb, 0xff, 0x87,
0xde, 0x6c, 0xf4, 0x90, 0xf, 0x9, 0x0, 0xf0,
0x90, 0x7, 0xd9, 0x0, 0x2f, 0xfd, 0x0, 0x1f,
0xfc, 0x0, 0x93, 0xe0, 0x9, 0xf, 0x0, 0x90,
0xf8, 0x9, 0x1e, 0xfe, 0xfb, 0xc2, 0xff, 0xe0,
0x0, 0x90, 0x0, 0x9, 0x0, 0x0, 0x90, 0x0,
/* U+0025 "%" */
0xf, 0xfe, 0x13, 0xf4, 0x1f, 0xa2, 0x8c, 0x1e,
0x8d, 0x52, 0x1f, 0xfc, 0x7c, 0x86, 0xe, 0x46,
0x78, 0xc1, 0x70, 0x1f, 0xcf, 0x8f, 0x6, 0x6f,
0x5c, 0x1a, 0xef, 0x47, 0xc8, 0x3e, 0x46, 0x66,
0x2, 0x1a, 0x66, 0x20, 0xff, 0x94, 0x1f, 0x21,
0x28, 0x3d, 0x13, 0x90, 0x79, 0x98, 0x80,
0x0, 0x0, 0x0, 0x7, 0xf8, 0x0, 0x3, 0xd7,
0x80, 0x2, 0xc0, 0x70, 0x0, 0xb0, 0x1c, 0x0,
0x1e, 0x1f, 0x0, 0x41, 0xff, 0x2, 0xf0, 0x0,
0x1f, 0x80, 0x1, 0xb9, 0x0, 0xb, 0xd0, 0x7f,
0x41, 0x0, 0x79, 0xb0, 0x0, 0x38, 0xe, 0x0,
0xe, 0x2, 0xc0, 0x3, 0xc0, 0xe0, 0x0, 0x79,
0xf0, 0x0, 0x7, 0xf4,
/* U+002A "*" */
0xe, 0xc3, 0xff, 0x8b, 0xc1, 0xce, 0xd, 0xd1,
0xe8, 0x17, 0x42, 0x9a, 0x1b, 0xb, 0xc, 0xe6,
0x47, 0x3, 0xa0, 0x1b, 0xa, 0x43, 0xd0, 0x7f,
0xf0, 0x0,
0x0, 0x30, 0x0, 0x0, 0xc0, 0x3, 0x83, 0x7,
0x3, 0xdd, 0xf4, 0x1, 0xfd, 0x0, 0xb, 0xf8,
0x1, 0xe3, 0x6e, 0x9, 0xc, 0x8, 0x0, 0x30,
0x0, 0x0, 0xc0, 0x0,
/* U+002B "+" */
0xf, 0xfe, 0x33, 0xc1, 0xff, 0xe1, 0xfd, 0xf,
0xe0, 0xff, 0xe0, 0xa7, 0xe8, 0x7f, 0x21, 0xff,
0xe8,
0x0, 0x0, 0x0, 0x0, 0x7, 0x80, 0x0, 0x1,
0xe0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x1e, 0x0,
0xf, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf4, 0x0,
0x78, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x7, 0x80,
0x0, 0x1, 0xe0, 0x0, 0x0, 0x78, 0x0,
/* U+0030 "0" */
0xa, 0xfa, 0xe, 0xd1, 0x1c, 0x28, 0x1d, 0xa4,
0x4, 0x82, 0x84, 0x32, 0x19, 0x14, 0x1f, 0xde,
0x11, 0xd3, 0xf, 0x44, 0x12, 0x1a, 0x10, 0xfc,
0xf0, 0x4e, 0x21, 0xd8, 0x10, 0xfe, 0xc2, 0x43,
0x22, 0x24, 0x14, 0x20, 0x81, 0xda, 0x41, 0x68,
0x8e, 0x0,
0x2, 0xfe, 0x0, 0x3f, 0xbf, 0x2, 0xf0, 0x2e,
0xf, 0x40, 0x3c, 0x3c, 0x0, 0xb5, 0xf0, 0x2,
0xeb, 0x87, 0x47, 0xae, 0x3f, 0x1f, 0xb8, 0x78,
0x7e, 0xe0, 0x1, 0xe7, 0xc0, 0xb, 0x8f, 0x0,
0x2d, 0x3d, 0x0, 0xf0, 0xbc, 0xb, 0x80, 0xfe,
0xfc, 0x0, 0xbf, 0x80,
/* U+0031 "1" */
0x1b, 0xe4, 0x26, 0x43, 0xf3, 0x68, 0x73, 0x21,
0xff, 0xff, 0xf, 0xfe, 0xaf, 0xc9, 0x7a, 0xf,
0xe4,
0x1b, 0xf4, 0x7, 0xff, 0x40, 0x64, 0xb4, 0x0,
0xb, 0x40, 0x0, 0xb4, 0x0, 0xb, 0x40, 0x0,
0xb4, 0x0, 0xb, 0x40, 0x0, 0xb4, 0x0, 0xb,
0x40, 0x0, 0xb4, 0x0, 0xb, 0x40, 0x0, 0xb4,
0x0, 0xb, 0x40, 0x3f, 0xff, 0xe3, 0xff, 0xff,
/* U+0032 "2" */
0x1b, 0xf4, 0x1a, 0x43, 0x38, 0x6b, 0xf0, 0x30,
0x68, 0x6c, 0x3f, 0xfa, 0x90, 0x87, 0xe4, 0x83,
0xec, 0x83, 0xec, 0x50, 0x7b, 0x18, 0x3d, 0xc,
0x1e, 0x95, 0x7, 0xa5, 0x41, 0xe5, 0xf, 0xf9,
0xf, 0xf8,
0x1b, 0xfe, 0x0, 0xff, 0xff, 0x3, 0x40, 0x3f,
0x0, 0x0, 0x3c, 0x0, 0x0, 0xf0, 0x0, 0x3,
0xc0, 0x0, 0x2e, 0x0, 0x0, 0xf0, 0x0, 0xf,
0x40, 0x0, 0xf8, 0x0, 0xf, 0x80, 0x0, 0xb8,
0x0, 0xb, 0x80, 0x0, 0xb8, 0x0, 0x7, 0xff,
0xff, 0x5f, 0xff, 0xfd,
/* U+0033 "3" */
0x1b, 0xf4, 0x1a, 0x43, 0x38, 0x57, 0xf2, 0x60,
0x43, 0xa0, 0xff, 0xe4, 0xc1, 0xeb, 0xe4, 0xc3,
0x21, 0xb0, 0xef, 0xa3, 0x43, 0xe7, 0x20, 0xfe,
0x44, 0x3f, 0xd8, 0x7e, 0x4d, 0x41, 0xd0, 0x1e,
0xfe, 0x48, 0x94, 0x19, 0xd0,
0x1b, 0xfe, 0x0, 0xff, 0xff, 0x1, 0x0, 0x2f,
0x0, 0x0, 0x3c, 0x0, 0x0, 0xf0, 0x0, 0xb,
0xc0, 0x2f, 0xfc, 0x0, 0xff, 0xc0, 0x0, 0x7,
0xd0, 0x0, 0x3, 0xc0, 0x0, 0xb, 0x40, 0x0,
0x2e, 0x0, 0x0, 0xf5, 0x40, 0xb, 0xcb, 0xff,
0xfd, 0xa, 0xff, 0x80,
/* U+0034 "4" */
0xf, 0x7c, 0x1f, 0x90, 0xff, 0xa4, 0x3f, 0xa2,
0xf, 0xca, 0x83, 0xfa, 0x50, 0x7e, 0x88, 0x3f,
0x2c, 0x1f, 0xd1, 0x7, 0xe8, 0x83, 0xf9, 0x3a,
0xc0, 0xa0, 0x4b, 0xc0, 0x51, 0xff, 0x3, 0xc1,
0xff, 0xd9,
0x0, 0xf, 0xc0, 0x0, 0x1f, 0xc0, 0x0, 0x3b,
0xc0, 0x0, 0xb3, 0xc0, 0x1, 0xd3, 0xc0, 0x3,
0x83, 0xc0, 0xb, 0x3, 0xc0, 0x1e, 0x3, 0xc0,
0x3c, 0x3, 0xc0, 0xb4, 0x3, 0xc0, 0xfa, 0xab,
0xe8, 0xff, 0xff, 0xfc, 0x0, 0x3, 0xc0, 0x0,
0x3, 0xc0, 0x0, 0x3, 0xc0, 0x0, 0x3, 0xc0,
/* U+0035 "5" */
0x3f, 0xf2, 0x1f, 0xfc, 0x3f, 0xf2, 0x1f, 0xfc,
0xea, 0xc8, 0x79, 0x75, 0x2, 0x6f, 0xa1, 0x81,
0x21, 0x30, 0x87, 0xe4, 0x8, 0x7e, 0x43, 0xfc,
0x87, 0xff, 0x1, 0x60, 0xec, 0x35, 0xfc, 0xc,
0x50, 0x75, 0x80,
0x3f, 0xff, 0xd0, 0xff, 0xff, 0x43, 0xc0, 0x0,
0xf, 0x0, 0x0, 0x3c, 0x0, 0x0, 0xfa, 0xa4,
0x3, 0xff, 0xf8, 0x9, 0x1, 0xf8, 0x0, 0x1,
0xf0, 0x0, 0x3, 0xd0, 0x0, 0xb, 0x40, 0x0,
0x3d, 0x0, 0x0, 0xf1, 0x40, 0xf, 0xc7, 0xff,
0xfc, 0xb, 0xff, 0x40,
/* U+0036 "6" */
0xd, 0x7d, 0x21, 0x3a, 0x13, 0x81, 0x8b, 0xf8,
0x11, 0x21, 0x90, 0xc8, 0x7c, 0x88, 0xd1, 0xf,
0x72, 0xad, 0x31, 0x2f, 0x24, 0x1a, 0x41, 0x1,
0x9, 0xd, 0x1e, 0xf, 0xe4, 0x3f, 0xe4, 0x3e,
0xc4, 0x48, 0x25, 0x11, 0xf, 0x70, 0x85, 0xa2,
0xa, 0x0,
0x0, 0xbf, 0x90, 0x1f, 0xff, 0x81, 0xf4, 0x1,
0xf, 0x40, 0x0, 0x3c, 0x0, 0x1, 0xe1, 0xa4,
0x7, 0xbf, 0xfd, 0x2f, 0xd0, 0xbc, 0xbd, 0x0,
0xf6, 0xf0, 0x1, 0xe7, 0xc0, 0x7, 0xdf, 0x0,
0x1f, 0x3c, 0x0, 0xb8, 0xb8, 0x7, 0xc0, 0xfe,
0xfe, 0x0, 0xbf, 0xd0,
/* U+0037 "7" */
0xbf, 0xfa, 0xc3, 0xfb, 0x7f, 0xe0, 0x21, 0xf4,
0x21, 0xf9, 0x20, 0xf9, 0xf, 0xf6, 0x41, 0xf9,
0x10, 0xf9, 0x10, 0xfd, 0x18, 0x7c, 0x81, 0xf,
0xb1, 0xf, 0xc9, 0x7, 0xc8, 0x7f, 0xa2, 0xf,
0xf2, 0x1c,
0xbf, 0xff, 0xf9, 0xff, 0xff, 0xd0, 0x0, 0xf,
0x0, 0x0, 0xb8, 0x0, 0x3, 0xc0, 0x0, 0x1f,
0x0, 0x0, 0xb4, 0x0, 0x3, 0xc0, 0x0, 0x1e,
0x0, 0x0, 0xf4, 0x0, 0x7, 0xc0, 0x0, 0x2e,
0x0, 0x0, 0xf0, 0x0, 0x7, 0xc0, 0x0, 0x3d,
0x0, 0x0, 0xf0, 0x0,
/* U+0038 "8" */
0xa, 0xfc, 0x84, 0xe8, 0x82, 0x80, 0x8b, 0xb8,
0x43, 0x21, 0x20, 0x43, 0xff, 0x84, 0x84, 0x81,
0x32, 0xee, 0x70, 0xb0, 0x21, 0xe7, 0x3e, 0x56,
0x8, 0xc2, 0x91, 0x42, 0x1d, 0x9e, 0xf, 0xe7,
0x10, 0xec, 0x50, 0x10, 0x94, 0x62, 0x5d, 0xc2,
0x8a, 0x22, 0xa, 0x0,
0x2, 0xff, 0x40, 0x7f, 0xbf, 0x83, 0xd0, 0x1f,
0xf, 0x0, 0x3d, 0x3c, 0x0, 0xf4, 0xf4, 0x7,
0xc0, 0xfe, 0xf8, 0x0, 0xff, 0xe0, 0x1f, 0x2,
0xf0, 0xf0, 0x2, 0xd7, 0x80, 0x7, 0xae, 0x0,
0x1f, 0x7c, 0x0, 0xb8, 0xf4, 0x7, 0xd2, 0xfe,
0xfe, 0x1, 0xbf, 0xd0,
/* U+0039 "9" */
0x3, 0x7d, 0x6, 0x64, 0x47, 0xa, 0x2e, 0xd2,
0x10, 0x21, 0x42, 0x62, 0x1c, 0x88, 0x7f, 0xb0,
0xfc, 0x83, 0x10, 0xfc, 0x82, 0x3, 0x86, 0xc7,
0xd1, 0x6, 0xe5, 0x58, 0x79, 0xa2, 0x66, 0x1f,
0x91, 0xf, 0xb2, 0x3, 0xfc, 0x28, 0xa, 0x9,
0xa0, 0x0,
0x6, 0xfe, 0x0, 0x7f, 0xbf, 0x3, 0xd0, 0x2e,
0x1f, 0x0, 0x3c, 0xb8, 0x0, 0xb6, 0xe0, 0x2,
0xeb, 0x80, 0xf, 0x9f, 0x0, 0x3e, 0x3e, 0x7,
0xf8, 0x3f, 0xfd, 0xe0, 0x1a, 0x47, 0x80, 0x0,
0x2d, 0x0, 0x0, 0xf0, 0x0, 0xf, 0x41, 0xff,
0xf8, 0x2, 0xfe, 0x40,
/* U+003C "<" */
0xf, 0xf3, 0x21, 0xf9, 0xe4, 0x3c, 0xdc, 0x3a,
0x15, 0xca, 0xb8, 0x2f, 0x25, 0xc8, 0x7c, 0xe8,
0x7e, 0x87, 0xc8, 0x7c, 0xf9, 0x2f, 0x21, 0xf5,
0xc9, 0x70, 0x7c, 0xdc, 0x28, 0x3f, 0x9f, 0x20,
0x0, 0x0, 0x6, 0x40, 0x0, 0x1f, 0xd0, 0x1,
0xbf, 0x80, 0xb, 0xf9, 0x0, 0x3f, 0xd0, 0x0,
0xf, 0x80, 0x0, 0x1, 0xff, 0x40, 0x0, 0x2,
0xff, 0x40, 0x0, 0x6, 0xfe, 0x0, 0x0, 0x7,
0xd0, 0x0, 0x0, 0x0,
/* U+003D "=" */
0x3f, 0xfe, 0x43, 0xff, 0x80, 0x9f, 0xff, 0x7,
0xff, 0xf, 0xff, 0xe0, 0xff, 0xe0, 0xa0,
0x3f, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xc0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff,
0xf, 0xff, 0xff, 0xd0,
/* U+003E ">" */
0x24, 0x3f, 0xe6, 0xe0, 0xfe, 0xd1, 0xf2, 0x1f,
0x5c, 0x97, 0x21, 0xe6, 0xe5, 0x58, 0x7e, 0x64,
0x8, 0x79, 0xf2, 0x48, 0x4d, 0xc3, 0xe4, 0x17,
0x25, 0xc1, 0xc8, 0xf9, 0xf, 0xae, 0xf, 0xe0,
0x24, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xbf,
0xd0, 0x0, 0x1, 0xbf, 0x90, 0x0, 0x1, 0xbf,
0x0, 0x0, 0xb, 0xd0, 0x0, 0x7f, 0xd0, 0x6,
0xfe, 0x0, 0x2f, 0xf4, 0x0, 0xf, 0x80, 0x0,
0x1, 0x0, 0x0, 0x0,
/* U+0041 "A" */
0xe, 0xf8, 0x3f, 0xf8, 0x28, 0x7e, 0x42, 0xc3,
0xf4, 0x42, 0x1f, 0xe4, 0x8, 0x79, 0x12, 0x30,
0xf6, 0x62, 0x21, 0xe4, 0x43, 0xf9, 0xe, 0x48,
0x36, 0x21, 0x62, 0x19, 0x1a, 0xb0, 0xfe, 0x5c,
0x4, 0x10, 0xff, 0x44, 0x4, 0xc3, 0x90, 0xf2,
0x1f, 0x94, 0x1f, 0xc9, 0x80,
0x0, 0x3f, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x7,
0xf8, 0x0, 0x3, 0xdf, 0x0, 0x0, 0xf3, 0xd0,
0x0, 0x78, 0x78, 0x0, 0x2d, 0xf, 0x0, 0xf,
0x3, 0xc0, 0x7, 0xc0, 0xb8, 0x2, 0xe0, 0x1f,
0x0, 0xfe, 0xab, 0xc0, 0x3f, 0xff, 0xf4, 0x2e,
0x0, 0x1f, 0xf, 0x40, 0x3, 0xc3, 0xc0, 0x0,
0xf5, 0xf0, 0x0, 0x2e,
/* U+0043 "C" */
0xd, 0x7e, 0x83, 0x68, 0x66, 0x6, 0x3f, 0xac,
0x86, 0xc, 0xa1, 0x30, 0xf9, 0x2, 0x1f, 0xff,
0x24, 0x3f, 0xe4, 0x83, 0xf4, 0x30, 0x65, 0x3,
0x1e, 0x9d, 0x85, 0xa2, 0x86,
0x0, 0xbf, 0xe0, 0xf, 0xff, 0xe0, 0xf8, 0x1,
0x4b, 0x80, 0x0, 0x3d, 0x0, 0x1, 0xf0, 0x0,
0x7, 0xc0, 0x0, 0x1f, 0x0, 0x0, 0x7c, 0x0,
0x1, 0xf0, 0x0, 0x7, 0xc0, 0x0, 0xf, 0x0,
0x0, 0x2e, 0x0, 0x0, 0x3e, 0x0, 0x50, 0x3f,
0xaf, 0x80, 0x2f, 0xf8,
/* U+0045 "E" */
0xff, 0xe8, 0x3f, 0xf8, 0x17, 0xfa, 0xf, 0xfe,
0xf5, 0xfe, 0x43, 0xf9, 0x5, 0xfe, 0xf, 0xfe,
0xfd, 0xfe, 0x83, 0xf9,
0xff, 0xff, 0xef, 0xff, 0xfe, 0xf4, 0x0, 0xf,
0x40, 0x0, 0xf4, 0x0, 0xf, 0x40, 0x0, 0xf4,
0x0, 0xf, 0xff, 0xfd, 0xff, 0xff, 0xcf, 0x40,
0x0, 0xf4, 0x0, 0xf, 0x40, 0x0, 0xf4, 0x0,
0xf, 0x40, 0x0, 0xff, 0xff, 0xef, 0xff, 0xff,
/* U+0046 "F" */
0xbf, 0xf8, 0x3f, 0x90, 0x3f, 0xe8, 0x3f, 0xfb,
0xcf, 0xf9, 0xf, 0xe4, 0xf, 0xf8, 0x3f, 0xfe,
0x20,
0xbf, 0xff, 0xfb, 0xff, 0xfe, 0xb8, 0x0, 0xb,
0x80, 0x0, 0xb8, 0x0, 0xb, 0x80, 0x0, 0xb8,
0x0, 0xb, 0xff, 0xfd, 0xbf, 0xff, 0xcb, 0x80,
0x0, 0xb8, 0x0, 0xb, 0x80, 0x0, 0xb8, 0x0,
0xb, 0x80, 0x0, 0xb8, 0x0, 0xb, 0x80, 0x0,
/* U+0048 "H" */
0xb8, 0x39, 0xf0, 0x7f, 0xfe, 0x1f, 0xe8, 0x3f,
0xf8, 0x6f, 0xf4, 0x1f, 0xff, 0x80,
0xb8, 0x0, 0x7e, 0xe0, 0x1, 0xfb, 0x80, 0x7,
0xee, 0x0, 0x1f, 0xb8, 0x0, 0x7e, 0xe0, 0x1,
0xfb, 0x80, 0x7, 0xef, 0xff, 0xff, 0xbf, 0xff,
0xfe, 0xe0, 0x1, 0xfb, 0x80, 0x7, 0xee, 0x0,
0x1f, 0xb8, 0x0, 0x7e, 0xe0, 0x1, 0xfb, 0x80,
0x7, 0xee, 0x0, 0x1f,
/* U+004B "K" */
0xb8, 0x3d, 0xe8, 0x3f, 0xb1, 0x83, 0xf6, 0x30,
0x7e, 0xc6, 0xf, 0xd8, 0xc1, 0xfb, 0x18, 0x3f,
0x40, 0x83, 0xf2, 0x80, 0x87, 0xfa, 0x20, 0xfe,
0xd4, 0x41, 0xf2, 0x8, 0x50, 0x7f, 0xa2, 0xf,
0xf2, 0x8c, 0x3f, 0xd0, 0x10, 0xff, 0x44, 0x1f,
0xe4, 0x18,
0xb8, 0x0, 0x3e, 0x2e, 0x0, 0x3e, 0xb, 0x80,
0x3e, 0x2, 0xe0, 0x3e, 0x0, 0xb8, 0x3e, 0x0,
0x2e, 0x3e, 0x0, 0xb, 0xaf, 0x0, 0x2, 0xff,
0xd0, 0x0, 0xbf, 0x7c, 0x0, 0x2f, 0xb, 0x80,
0xb, 0x80, 0xf4, 0x2, 0xe0, 0x1f, 0x0, 0xb8,
0x2, 0xf0, 0x2e, 0x0, 0x3d, 0xb, 0x80, 0x7,
0xc2, 0xe0, 0x0, 0xfc,
/* U+005A "Z" */
0x3f, 0xfc, 0x87, 0xff, 0x7, 0xfe, 0x45, 0x7,
0xca, 0x20, 0xfd, 0x10, 0x7e, 0x85, 0x7, 0xe4,
0x83, 0xf6, 0x41, 0xfa, 0x14, 0x1f, 0x92, 0xf,
0xd9, 0x7, 0xe4, 0x50, 0x7e, 0x88, 0x3f, 0x44,
0x1f, 0x94, 0x5f, 0xf2, 0x1f, 0xf6,
0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x0,
0xb8, 0x0, 0x1, 0xf0, 0x0, 0x3, 0xd0, 0x0,
0xb, 0x80, 0x0, 0xf, 0x0, 0x0, 0x3d, 0x0,
0x0, 0xb8, 0x0, 0x0, 0xf0, 0x0, 0x3, 0xd0,
0x0, 0x7, 0x80, 0x0, 0xf, 0x0, 0x0, 0x2d,
0x0, 0x0, 0x7f, 0xff, 0xfd, 0x7f, 0xff, 0xfe,
/* U+30A2 "ア" */
0x3e, 0xaf, 0xfb, 0xd0, 0x84, 0xbf, 0xf0, 0x11,
0xff, 0xfe, 0x12, 0x21, 0xff, 0xc3, 0x51, 0x7,
0xf7, 0x6, 0x8c, 0x3f, 0xf8, 0x4e, 0x61, 0xff,
0xc2, 0xa1, 0x7, 0xfc, 0x85, 0x9a, 0x1f, 0xfc,
0x1c, 0x70, 0xff, 0xe0, 0xe2, 0x1f, 0xfc, 0x44,
0x3f, 0xf8, 0xa8, 0x7f, 0xf1, 0xa2, 0xf, 0xfe,
0x1c, 0x28, 0x3f, 0xf8, 0x2e, 0x90, 0x7f, 0xf0,
0x68, 0x38, 0x7f, 0xf0, 0xa6, 0x81, 0xff, 0xc1,
0x3f, 0xaa, 0xaa, 0xab, 0xe1, 0xff, 0xff, 0xff,
0xff, 0xc0, 0x0, 0x0, 0x0, 0x2e, 0x0, 0x0,
0x0, 0x1, 0xf0, 0x0, 0x0, 0xe0, 0xf, 0x0,
0x0, 0x3, 0x81, 0xf0, 0x0, 0x0, 0xe, 0x2f,
0x40, 0x0, 0x0, 0x78, 0x70, 0x0, 0x0, 0x1,
0xd0, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0x0, 0x1, 0xf0, 0x0,
0x0, 0x0, 0xf, 0x40, 0x0, 0x0, 0x0, 0xb8,
0x0, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x0, 0x2,
0xf8, 0x0, 0x0, 0x0, 0x2, 0x40, 0x0, 0x0,
0x0,
/* U+30A4 "イ" */
0xf, 0xfe, 0xb6, 0x87, 0xff, 0xf, 0x30, 0xff,
0xe0, 0xb8, 0xc1, 0xff, 0xc0, 0xa1, 0x40, 0xff,
0xe0, 0x69, 0xa1, 0xff, 0x38, 0xe1, 0xff, 0x3c,
0x8, 0x3f, 0xd7, 0x8, 0x7f, 0x9f, 0x23, 0xc1,
0xfd, 0xc0, 0xb8, 0x3f, 0xe9, 0xf2, 0x1f, 0xfc,
0x16, 0xf, 0xff, 0xf8, 0x7f, 0xf7, 0x14, 0x1e,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xd, 0x0, 0x0, 0x0, 0x3, 0xe0, 0x0, 0x0,
0x1, 0xf8, 0x0, 0x0, 0x0, 0xbd, 0x0, 0x0,
0x0, 0x3f, 0x0, 0x0, 0x0, 0x1f, 0x80, 0x0,
0x0, 0x1f, 0xf0, 0x0, 0x0, 0x2f, 0xef, 0x0,
0x0, 0x7f, 0xe0, 0xf0, 0x0, 0x3f, 0xd0, 0xf,
0x0, 0x1, 0x80, 0x0, 0xf0, 0x0, 0x0, 0x0,
0xf, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0x0, 0xa, 0x0, 0x0,
/* U+30A6 "ウ" */
0xf, 0xd4, 0xf, 0xfe, 0x22, 0x83, 0xff, 0xc3,
0xff, 0x3, 0xfe, 0xc, 0xbf, 0xfc, 0x0, 0xf5,
0x7f, 0xf0, 0x3, 0xff, 0xae, 0x88, 0x7f, 0xf0,
0xe2, 0xf, 0xfe, 0x47, 0x83, 0xfd, 0x10, 0x7f,
0xf0, 0x94, 0x21, 0xff, 0xc2, 0x88, 0x3f, 0xf8,
0x2e, 0x28, 0x3f, 0xf8, 0x14, 0x28, 0x1f, 0xe6,
0xd2, 0x43, 0xfd, 0xc8, 0xe8, 0x7f, 0xdb, 0x70,
0x7e,
0x0, 0x0, 0xa0, 0x0, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xc3, 0xea,
0xaa, 0xaa, 0xbc, 0x3c, 0x0, 0x0, 0x3, 0xc3,
0xc0, 0x0, 0x0, 0x3c, 0x3c, 0x0, 0x0, 0x7,
0x83, 0xc0, 0x0, 0x0, 0xf0, 0x3c, 0x0, 0x0,
0xf, 0x0, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0,
0x0, 0x7c, 0x0, 0x0, 0x0, 0xf, 0x40, 0x0,
0x0, 0x7, 0xe0, 0x0, 0x0, 0x2, 0xf4, 0x0,
0x0, 0x6, 0xfd, 0x0, 0x0, 0x3, 0xfe, 0x0,
0x0, 0x0, 0x9, 0x0, 0x0, 0x0,
/* U+30A8 "エ" */
0x5, 0x7f, 0xf0, 0xf0, 0xcb, 0xff, 0xc3, 0xe,
0xff, 0x81, 0xff, 0x7, 0xff, 0xfc, 0x3f, 0xff,
0xe1, 0xff, 0xd5, 0xf5, 0x76, 0xa, 0xf7, 0x83,
0x2f, 0x4, 0xbe, 0xd, 0xff, 0xfc, 0x60,
0xa, 0xaa, 0xaa, 0xaa, 0xb0, 0xf, 0xff, 0xff,
0xff, 0xf0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0,
0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0,
0x3c, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0,
0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x3c,
0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0x3e, 0xaa, 0xfe, 0xaa,
0xbc, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0,
0x0, 0x0, 0x0,
/* U+30AA "オ" */
0xf, 0xfe, 0x8f, 0x7, 0xff, 0xc3, 0xff, 0xc3,
0xfc, 0x2f, 0xf0, 0x4b, 0xc5, 0x7e, 0xc0, 0xd7,
0x7, 0xe6, 0xf, 0xfe, 0x1b, 0x18, 0x7f, 0xf0,
0x58, 0xc3, 0xff, 0x83, 0x43, 0x9, 0xf, 0xed,
0x30, 0xff, 0xe0, 0x38, 0xe1, 0xff, 0x3c, 0x50,
0x3f, 0xf8, 0x4e, 0x87, 0xff, 0x5, 0xe0, 0xff,
0xe5, 0x7e, 0x10, 0xff, 0xe0, 0x4b, 0x50, 0x38,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
0x0, 0x0, 0x0, 0x3, 0x80, 0x0, 0x0, 0x0,
0x38, 0x0, 0x0, 0x0, 0x3, 0x80, 0x3, 0xff,
0xff, 0xff, 0xff, 0x2a, 0xaa, 0xaf, 0xea, 0xa0,
0x0, 0x1, 0xf8, 0x0, 0x0, 0x0, 0x7f, 0x80,
0x0, 0x0, 0x1f, 0x38, 0x0, 0x0, 0x7, 0xc3,
0x80, 0x0, 0x2, 0xf0, 0x3c, 0x0, 0x0, 0xfc,
0x3, 0xc0, 0x0, 0x7e, 0x0, 0x3c, 0x0, 0x7f,
0x40, 0x3, 0xc0, 0x7, 0x80, 0x0, 0x3c, 0x0,
0x0, 0x0, 0x3, 0xc0, 0x0, 0x0, 0x3f, 0xf8,
0x0, 0x0, 0x1, 0xa9, 0x0, 0x0,
/* U+30AB "カ" */
0xf, 0xfe, 0x67, 0x83, 0xff, 0xe1, 0xfe, 0x7,
0xfd, 0xb, 0xe0, 0x2f, 0x82, 0xaf, 0xd, 0x78,
0x3f, 0x26, 0x1f, 0xfc, 0x2c, 0x43, 0xff, 0x84,
0x87, 0xc9, 0x87, 0x22, 0x1f, 0xfc, 0x28, 0x83,
0xff, 0x83, 0x8, 0x7d, 0x88, 0x4a, 0x20, 0xf9,
0xc, 0xc6, 0x1f, 0xfc, 0xa, 0x10, 0x6a, 0xd9,
0x1, 0x34, 0x39, 0x61, 0x40, 0xf0, 0x7a, 0xfd,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0x3, 0xc0, 0x0, 0xf, 0xff, 0xff,
0xff, 0xe2, 0xaa, 0xbe, 0xaa, 0xb8, 0x0, 0xe,
0x0, 0xe, 0x0, 0x7, 0x40, 0x3, 0x80, 0x2,
0xc0, 0x0, 0xe0, 0x0, 0xf0, 0x0, 0x74, 0x0,
0x78, 0x0, 0x1d, 0x0, 0x3c, 0x0, 0x7, 0x40,
0x2e, 0x0, 0x2, 0xc0, 0x1f, 0x0, 0x0, 0xf0,
0x1f, 0x0, 0x0, 0x3c, 0x2f, 0x40, 0x2a, 0xbd,
0xf, 0x0, 0xb, 0xfe, 0x0, 0x0, 0x0, 0x0,
0x0,
/* U+30AD "キ" */
0xf, 0x90, 0xff, 0xe2, 0x51, 0xf, 0xfe, 0x1e,
0x1f, 0xfc, 0x54, 0xc3, 0x2c, 0x1f, 0xe6, 0xfa,
0x98, 0x4d, 0x3e, 0x2, 0x6, 0xa0, 0x32, 0x85,
0x8b, 0xd2, 0x82, 0x6f, 0xa9, 0x87, 0xfc, 0x87,
0x26, 0x1f, 0xfc, 0x54, 0x39, 0x90, 0xff, 0x53,
0xe9, 0xc2, 0x69, 0xe0, 0x28, 0x55, 0xd3, 0xd2,
0x85, 0xf, 0xa8, 0x83, 0x55, 0xf5, 0x3, 0xf9,
0xa2, 0x1e, 0x43, 0xff, 0xac, 0x87, 0xff, 0x17,
0x10, 0xff, 0xe6, 0x0,
0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0xb4, 0x0,
0x0, 0x0, 0x7, 0x40, 0x0, 0x0, 0x0, 0x38,
0x1, 0x50, 0x0, 0x3, 0xef, 0xfe, 0x1, 0xaf,
0xff, 0xf9, 0x40, 0x7f, 0xea, 0xd0, 0x0, 0x1,
0x0, 0x1d, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x0,
0x0, 0x0, 0xf, 0x0, 0x19, 0x0, 0x0, 0xfa,
0xff, 0xe0, 0x1a, 0xff, 0xfe, 0x90, 0xbf, 0xfe,
0xb8, 0x0, 0x6, 0x90, 0x3, 0x80, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0x0, 0x3, 0xc0, 0x0,
0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x1, 0xd0,
0x0, 0x0, 0x0, 0x1d, 0x0, 0x0,
/* U+30AF "ク" */
0xf, 0x99, 0xf, 0xfe, 0x1e, 0x87, 0xff, 0xd,
0x42, 0x1f, 0xfc, 0x28, 0x6b, 0xe4, 0x3d, 0x1,
0x7f, 0x41, 0xca, 0x3f, 0xe8, 0x43, 0x31, 0x87,
0xd9, 0x84, 0xc6, 0x1f, 0x91, 0x5, 0xc, 0x3f,
0x44, 0x5, 0x18, 0x7f, 0x22, 0x7, 0xc1, 0xfd,
0x90, 0x7f, 0xf0, 0xa1, 0x41, 0xff, 0xc1, 0x51,
0x7, 0xff, 0x5, 0x8c, 0x3f, 0xf8, 0x34, 0x20,
0xff, 0xe0, 0x3a, 0x68, 0x7f, 0x9e, 0x1c, 0x3f,
0xee, 0x7, 0x7, 0xff, 0x2, 0x7c, 0x1f, 0xf0,
0x0, 0x1, 0x90, 0x0, 0x0, 0x0, 0x2d, 0x0,
0x0, 0x0, 0x7, 0xc0, 0x0, 0x0, 0x0, 0xfa,
0xaa, 0xa4, 0x0, 0x2f, 0xff, 0xff, 0xc0, 0x7,
0xc0, 0x0, 0x78, 0x1, 0xf0, 0x0, 0xb, 0x40,
0x7c, 0x0, 0x0, 0xf0, 0x2f, 0x0, 0x0, 0x2d,
0x7, 0xc0, 0x0, 0x3, 0xc0, 0x0, 0x0, 0x0,
0xf4, 0x0, 0x0, 0x0, 0x2e, 0x0, 0x0, 0x0,
0x7, 0xc0, 0x0, 0x0, 0x1, 0xf0, 0x0, 0x0,
0x0, 0xbd, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0,
0x0, 0x7f, 0x80, 0x0, 0x0, 0x3f, 0xc0, 0x0,
0x0, 0x1, 0x80, 0x0, 0x0, 0x0,
/* U+30B1 "ケ" */
0xf, 0xfe, 0x77, 0x83, 0xff, 0x8a, 0x88, 0x7f,
0xf1, 0x72, 0xf, 0xfe, 0x2a, 0x1f, 0xfc, 0x68,
0x1f, 0xff, 0xc0, 0xe, 0x45, 0xe0, 0x97, 0x83,
0x65, 0x79, 0x3a, 0xe0, 0xa1, 0x41, 0xc8, 0x7f,
0x49, 0x7, 0xff, 0x11, 0x30, 0xff, 0xe2, 0xf8,
0x3e, 0x88, 0x3f, 0xf8, 0xa8, 0x87, 0xff, 0x11,
0x10, 0xff, 0xe2, 0xc4, 0x1f, 0xfc, 0x4c, 0x83,
0xff, 0x89, 0x8a, 0xf, 0xfe, 0x15, 0x8c, 0x1f,
0xfc, 0x38, 0xa0, 0x7f, 0xf1, 0x74, 0x3f, 0xf8,
0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x0,
0x2c, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0,
0x0, 0x0, 0xbf, 0xff, 0xff, 0xfc, 0x0, 0xfa,
0xab, 0xfa, 0xa8, 0x3, 0xd0, 0x2, 0xc0, 0x0,
0xb, 0x80, 0x3, 0xc0, 0x0, 0x2f, 0x0, 0x3,
0xc0, 0x0, 0x3c, 0x0, 0x3, 0xc0, 0x0, 0x0,
0x0, 0xb, 0x40, 0x0, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x0,
0x3c, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x0, 0x0,
0x0, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x2f, 0x80,
0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
/* U+30B3 "コ" */
0xf, 0xfe, 0x2f, 0xff, 0xf0, 0xc3, 0xff, 0x8b,
0xff, 0xfc, 0x10, 0xff, 0xff, 0x87, 0xff, 0xed,
0xff, 0xfe, 0x8, 0x7f, 0xf1, 0x9f, 0xff, 0xe0,
0x87, 0xff, 0x13, 0xc0,
0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff,
0x3f, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf, 0x7f, 0xff, 0xff, 0xff,
0x7f, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0x0,
/* U+30B5 "サ" */
0xf, 0xfe, 0x6f, 0x83, 0xde, 0xf, 0xff, 0xab,
0x58, 0x15, 0xe0, 0x56, 0x35, 0xc0, 0x5f, 0x1,
0x7a, 0xfc, 0xf, 0xf0, 0x3f, 0x21, 0xff, 0xd6,
0x43, 0xff, 0xcc, 0xa0, 0xe8, 0xc3, 0xfd, 0x40,
0xe4, 0x43, 0xff, 0x88, 0x88, 0x7f, 0xf1, 0x18,
0x83, 0xff, 0x87, 0x42, 0xf, 0xfe, 0x15, 0xa6,
0x87, 0xff, 0xa, 0x6c, 0x3f, 0x80,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0,
0x3c, 0x0, 0x0, 0x3c, 0x0, 0x3c, 0x0, 0x0,
0x3c, 0x0, 0x3c, 0x0, 0x0, 0x3c, 0x0, 0x3c,
0x0, 0x6a, 0xbe, 0xaa, 0xbe, 0xa8, 0xbf, 0xff,
0xff, 0xff, 0xfd, 0x0, 0x3c, 0x0, 0x3c, 0x0,
0x0, 0x3c, 0x0, 0x3c, 0x0, 0x0, 0x3c, 0x0,
0x38, 0x0, 0x0, 0x3c, 0x0, 0x38, 0x0, 0x0,
0x3c, 0x0, 0x38, 0x0, 0x0, 0x28, 0x0, 0xb4,
0x0, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0,
0x1, 0xe0, 0x0, 0x0, 0x0, 0x7, 0xc0, 0x0,
0x0, 0x0, 0x2f, 0x40, 0x0, 0x0, 0x2, 0xfc,
0x0, 0x0, 0x0, 0x0, 0x90, 0x0, 0x0,
/* U+30B7 "シ" */
0xd, 0x21, 0xff, 0xc5, 0x68, 0x1f, 0xfc, 0x4c,
0x74, 0x3f, 0xf8, 0x7c, 0x41, 0xff, 0xc4, 0x78,
0x3f, 0xe9, 0xe, 0x43, 0xfc, 0xaa, 0x7, 0xff,
0x3, 0xc3, 0x8e, 0x87, 0xf4, 0x21, 0x71, 0x7,
0xe5, 0x10, 0x67, 0xc1, 0xf3, 0x18, 0x7f, 0xf0,
0x98, 0x83, 0xff, 0x85, 0x42, 0x43, 0xff, 0x80,
0xe9, 0xa1, 0xff, 0xc0, 0xa0, 0xe1, 0xff, 0x3e,
0x4a, 0x7, 0xf3, 0x70, 0x2d, 0xf, 0xe6, 0x46,
0xd0, 0xff, 0x9a, 0x72, 0x1f, 0xfc, 0x0,
0x0, 0x90, 0x0, 0x0, 0x0, 0x3, 0xe0, 0x0,
0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0x0, 0x1,
0xf0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0,
0x90, 0x0, 0x0, 0x0, 0x7, 0xe0, 0x0, 0x0,
0xf, 0x3, 0xf4, 0x0, 0x0, 0xb8, 0x1, 0xf0,
0x0, 0x7, 0xc0, 0x0, 0x0, 0x0, 0x7c, 0x0,
0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0x0, 0xbd,
0x0, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x0, 0x2,
0xf8, 0x0, 0x0, 0x1, 0xff, 0x40, 0x0, 0x1,
0xbf, 0xd0, 0x0, 0x0, 0x1f, 0xe4, 0x0, 0x0,
0x0, 0x14, 0x0, 0x0, 0x0, 0x0,
/* U+30B9 "ス" */
0x5, 0x7f, 0xf0, 0x43, 0x97, 0xff, 0x84, 0x1b,
0xff, 0xd0, 0x10, 0xff, 0xe1, 0x64, 0x1f, 0xfc,
0x34, 0x43, 0xff, 0x85, 0x10, 0x7f, 0xf0, 0x97,
0x7, 0xff, 0xa, 0x20, 0xff, 0xe1, 0x62, 0x1f,
0xfc, 0x2c, 0xa, 0xf, 0xfe, 0x6, 0x59, 0x21,
0xfc, 0xe4, 0x99, 0x40, 0xfa, 0x84, 0x85, 0x8a,
0xc, 0xe9, 0xa1, 0xd9, 0x23, 0xc3, 0x87, 0xe8,
0x94, 0xa, 0x7, 0xf3, 0x5, 0xe4, 0x3f, 0xe7,
0x40,
0xa, 0xaa, 0xaa, 0xa8, 0x0, 0xff, 0xff, 0xff,
0xd0, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0,
0xb, 0x40, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0x0, 0x2d, 0x0, 0x0, 0x0, 0x7, 0x80, 0x0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x3e, 0x0,
0x0, 0x0, 0xf, 0xf4, 0x0, 0x0, 0x3, 0xd3,
0xd0, 0x0, 0x1, 0xf4, 0xf, 0x80, 0x0, 0xbd,
0x0, 0x3d, 0x0, 0x7f, 0x0, 0x0, 0xf4, 0x7f,
0x80, 0x0, 0x7, 0xd3, 0xd0, 0x0, 0x0, 0x1d,
0x0, 0x0, 0x0, 0x0, 0x0,
/* U+30BB "セ" */
0xf, 0x70, 0x7f, 0xf1, 0x90, 0xff, 0xe3, 0x21,
0xff, 0xd0, 0x43, 0xff, 0x82, 0xd3, 0xd2, 0x1f,
0x34, 0xf4, 0xa0, 0x91, 0x57, 0x80, 0xba, 0xf4,
0x43, 0x44, 0x37, 0xa8, 0x82, 0x11, 0x57, 0xc2,
0x1e, 0xcc, 0x29, 0xf, 0xf4, 0x41, 0xff, 0xc3,
0x96, 0xf, 0xfe, 0x1c, 0xc1, 0xff, 0xc5, 0x83,
0xff, 0xa6, 0x87, 0xff, 0x1e, 0xc, 0xb5, 0x3,
0xe8, 0x7f, 0x54, 0x87, 0xe7, 0xa2, 0xab, 0x70,
0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0,
0x0, 0x0, 0x0, 0xe0, 0x0, 0x0, 0x0, 0x3,
0x80, 0x0, 0x4, 0x0, 0xe, 0x0, 0x6b, 0xf4,
0x0, 0x3e, 0xbf, 0xff, 0xc1, 0x6f, 0xff, 0xa4,
0x1d, 0x1f, 0xff, 0xc0, 0x0, 0xf0, 0x24, 0xe,
0x0, 0xf, 0x0, 0x0, 0x38, 0x0, 0xb4, 0x0,
0x0, 0xe0, 0xb, 0x80, 0x0, 0x3, 0x80, 0x8,
0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x38,
0x0, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0,
0x3, 0xe0, 0x5, 0x68, 0x0, 0x7, 0xff, 0xff,
0xe0, 0x0, 0x1, 0x69, 0x54, 0x0,
/* U+30BD "ソ" */
0xf, 0xfe, 0x33, 0x7, 0xfd, 0x69, 0x28, 0x3f,
0xf8, 0x51, 0x7, 0xf9, 0x11, 0x42, 0x1f, 0xfc,
0x28, 0x83, 0xf2, 0x21, 0x92, 0xf, 0xb3, 0xd,
0x8, 0x7c, 0x88, 0x77, 0x83, 0xd1, 0x7, 0xff,
0x9, 0x10, 0xff, 0xe0, 0xe4, 0x1f, 0xfc, 0x18,
0x50, 0x7f, 0xf0, 0x24, 0x83, 0xff, 0x81, 0x26,
0x1f, 0xfc, 0xd, 0x30, 0xff, 0xac, 0x18, 0x7f,
0xd2, 0x58, 0x7f, 0xf0, 0x29, 0xa1, 0xfc,
0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x2,
0xd3, 0xd0, 0x0, 0x0, 0xb4, 0x7c, 0x0, 0x0,
0x3c, 0xb, 0x40, 0x0, 0xf, 0x0, 0xf0, 0x0,
0x7, 0x80, 0x2e, 0x0, 0x2, 0xd0, 0x3, 0xc0,
0x0, 0xf0, 0x0, 0x0, 0x0, 0xb4, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0,
0x0, 0x2e, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0,
0x0, 0x2f, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0,
0x0, 0xbf, 0x0, 0x0, 0x0, 0xbd, 0x0, 0x0,
0x0, 0x4, 0x0, 0x0, 0x0,
/* U+30BF "タ" */
0xf, 0xd0, 0x7f, 0xf1, 0x25, 0x7, 0xff, 0xd,
0x10, 0xff, 0xe1, 0x60, 0xaf, 0x68, 0x7a, 0x9,
0x7c, 0x41, 0xca, 0x3f, 0xe8, 0x43, 0x31, 0x87,
0xd1, 0x4, 0xc6, 0x1f, 0xfc, 0x16, 0x21, 0x83,
0xa2, 0x5, 0xd, 0x37, 0x40, 0xa1, 0x4, 0xe1,
0x50, 0xb2, 0x30, 0xd0, 0x73, 0xa6, 0x21, 0xff,
0xc1, 0x90, 0xff, 0xe2, 0x28, 0xe, 0x1f, 0xf5,
0xf, 0x22, 0x1f, 0xda, 0x60, 0xa2, 0x1f, 0x58,
0xe1, 0x90, 0xe7, 0xc9, 0xc1, 0xff, 0x20, 0xb0,
0xff, 0xe1, 0x79, 0xf, 0xfe, 0x0,
0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x2d, 0x0,
0x0, 0x0, 0x3, 0xc0, 0x0, 0x0, 0x0, 0xfe,
0xaa, 0xb4, 0x0, 0x2f, 0xff, 0xff, 0xc0, 0x7,
0xc0, 0x0, 0x78, 0x1, 0xf0, 0x0, 0xf, 0x0,
0x7c, 0x0, 0x0, 0xf0, 0x1f, 0x46, 0x0, 0x2d,
0xb, 0xc0, 0xbd, 0x7, 0xc0, 0x20, 0x1, 0xfc,
0xf0, 0x0, 0x0, 0x2, 0xfe, 0x0, 0x0, 0x0,
0xb, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xc0, 0x0,
0x0, 0xbc, 0x2d, 0x0, 0x0, 0x3f, 0x0, 0x40,
0x0, 0x2f, 0x80, 0x0, 0x0, 0x7f, 0xc0, 0x0,
0x0, 0x3, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0,
/* U+30C1 "チ" */
0xf, 0xfe, 0x13, 0x7, 0xfc, 0xb5, 0xf4, 0xc1,
0xef, 0xd5, 0x22, 0xae, 0xf, 0x57, 0x69, 0x52,
0x1f, 0x97, 0x8c, 0x3f, 0xfc, 0xff, 0xfa, 0x2f,
0xf8, 0xb, 0xf8, 0x25, 0xf8, 0x15, 0xf9, 0x3a,
0xf8, 0x3f, 0xc8, 0x7f, 0xf6, 0xa2, 0xf, 0xfe,
0x2a, 0x21, 0xff, 0xc4, 0xc8, 0x3f, 0xf8, 0x6e,
0x28, 0x3f, 0xf8, 0x54, 0x18, 0x3f, 0xf8, 0x73,
0x40, 0xff, 0xe0, 0x0,
0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x1, 0x5b,
0xff, 0x80, 0x3, 0xff, 0xff, 0xa4, 0x0, 0x1,
0x55, 0x2d, 0x0, 0x0, 0x0, 0x0, 0x1d, 0x0,
0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x0,
0x1d, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfc,
0x2a, 0xaa, 0xbf, 0xaa, 0xa8, 0x0, 0x0, 0x2c,
0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0xb4, 0x0,
0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x3,
0xd0, 0x0, 0x0, 0x0, 0x1f, 0x80, 0x0, 0x0,
0x0, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x24, 0x0,
0x0, 0x0,
/* U+30C4 "ツ" */
0xf, 0x90, 0xff, 0xe2, 0x32, 0x1f, 0x25, 0x86,
0x48, 0x3c, 0xd3, 0x20, 0xc8, 0x7d, 0x9a, 0x21,
0xb2, 0xe, 0x44, 0x84, 0x24, 0x43, 0x22, 0x4,
0x83, 0x50, 0x36, 0x61, 0x21, 0xca, 0xc, 0x88,
0x56, 0x1f, 0xd1, 0x7, 0xff, 0xd, 0x10, 0xff,
0xe1, 0x66, 0x1f, 0xfc, 0x2c, 0x43, 0xff, 0x85,
0x8c, 0x1f, 0xfc, 0x1c, 0x10, 0x7f, 0xf0, 0x2c,
0x70, 0xff, 0xad, 0x28, 0x1f, 0xf6, 0x8e, 0x87,
0xff, 0x3, 0x78, 0x3f, 0xc0,
/* U+30C6 "テ" */
0xf, 0xfe, 0x4b, 0xff, 0xfc, 0x8, 0x39, 0x7f,
0xf8, 0x38, 0x7a, 0xbf, 0xf8, 0x8, 0x7f, 0xf7,
0x6b, 0xff, 0x8c, 0x2f, 0xff, 0x18, 0xff, 0xd1,
0x7f, 0xc1, 0xfd, 0x87, 0xff, 0x21, 0xf, 0xfe,
0x22, 0x1f, 0xfc, 0x54, 0x43, 0xff, 0x89, 0x98,
0x7f, 0xf0, 0xe4, 0x43, 0xff, 0x85, 0x26, 0x1f,
0xfc, 0x17, 0x4c, 0x3f, 0xf8, 0x48, 0xe1, 0xff,
0xc4, 0xe0, 0xff, 0xe0, 0x80,
/* U+30C8 "ト" */
0xf, 0xfe, 0x7, 0x83, 0xff, 0xf9, 0xc8, 0x7f,
0x9b, 0x83, 0xee, 0x47, 0xc8, 0x73, 0x70, 0x2c,
0x3e, 0x78, 0x3f, 0xe7, 0xc1, 0xff, 0xf1, 0x50,
0x7f, 0x80,
/* U+30CA "ナ" */
0xf, 0xfe, 0x7b, 0xc1, 0xff, 0xd7, 0x43, 0xff,
0xc9, 0xff, 0xc3, 0xff, 0x28, 0x3f, 0xf8, 0xd7,
0xfd, 0xf, 0xfc, 0x87, 0xfb, 0xf, 0xfe, 0x26,
0x1f, 0xfc, 0x64, 0x43, 0xff, 0xad, 0x10, 0x7f,
0xf0, 0xd4, 0x21, 0xff, 0xc2, 0x63, 0xf, 0xfe,
0x15, 0x8, 0x3f, 0xf8, 0x5a, 0x48, 0x7f, 0xf0,
0xb7, 0x43, 0xff, 0x80,
/* U+30CB "ニ" */
0xf, 0xfe, 0x47, 0xff, 0xf0, 0x60, 0xff, 0xe5,
0x7f, 0xff, 0x6, 0xf, 0xff, 0xf8, 0x7f, 0xfe,
0xff, 0xff, 0x8b, 0x7, 0xff, 0x17,
/* U+30CC "ヌ" */
0xf, 0xfe, 0x12, 0x1b, 0xff, 0xf8, 0x14, 0x9,
0x7f, 0xe0, 0xf5, 0x7f, 0xc0, 0x83, 0xff, 0x94,
0x87, 0xd1, 0x7, 0x36, 0x1e, 0x44, 0x39, 0x47,
0x5, 0x10, 0x7d, 0x63, 0xa2, 0x21, 0xfd, 0xa5,
0x90, 0x7f, 0xd6, 0x12, 0x1f, 0xfc, 0xc, 0x2d,
0xf, 0xf6, 0xe, 0x28, 0x1f, 0x38, 0xe3, 0x8c,
0x19, 0xe2, 0x81, 0xb0, 0xd7, 0x3, 0x43, 0xdc,
0xc, 0x16, 0x1f, 0xfc, 0x7, 0xc8, 0x7f, 0xf0,
0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0,
0x4, 0xb0, 0x3, 0xc0, 0x1, 0xe7, 0x80, 0x2c,
0x0, 0x2d, 0x3c, 0x1, 0xe0, 0x3, 0xc1, 0xd0,
0xf, 0x0, 0x78, 0xf, 0x0, 0x50, 0xb, 0x40,
0xb0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x2d,
0x0, 0x0, 0x0, 0x3, 0xc0, 0x0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0,
0xf, 0x80, 0x0, 0x0, 0x3, 0xf0, 0x0, 0x0,
0x2, 0xf8, 0x0, 0x0, 0x2, 0xfd, 0x0, 0x0,
0x0, 0xfe, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0,
0x0,
/* U+30C6 "テ" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
0xf8, 0x0, 0x2a, 0xaa, 0xaa, 0x90, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xa, 0xaa, 0xaa, 0xaa,
0xaa, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0,
0x74, 0x0, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0,
0x0, 0xb, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0,
0x0, 0x0, 0x1, 0xe0, 0x0, 0x0, 0x0, 0xb,
0x40, 0x0, 0x0, 0x0, 0xbc, 0x0, 0x0, 0x0,
0xb, 0xc0, 0x0, 0x0, 0x1, 0xfc, 0x0, 0x0,
0x0, 0x3, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0,
/* U+30C8 "ト" */
0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xfe, 0x40, 0x0,
0xff, 0xf8, 0x0, 0xf1, 0xbf, 0xd0, 0xf0, 0x7,
0xfc, 0xf0, 0x0, 0x7c, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xa0, 0x0,
0x0,
/* U+30CA "ナ" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0,
0x0, 0x0, 0x0, 0x7, 0x80, 0x0, 0x0, 0x0,
0xe, 0x0, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0,
0x0, 0x0, 0xe0, 0x0, 0xf, 0xff, 0xff, 0xff,
0xff, 0x6f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0,
0x78, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x0, 0x0,
0x0, 0xb, 0x40, 0x0, 0x0, 0x0, 0x3c, 0x0,
0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0xb,
0x40, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0,
0x7, 0xc0, 0x0, 0x0, 0x0, 0xbd, 0x0, 0x0,
0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0x8, 0x0,
0x0, 0x0, 0x0,
/* U+30CB "ニ" */
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff,
0xe0, 0xf, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xfd,
/* U+30CC "ヌ" */
0x0, 0x0, 0x0, 0x4, 0x3, 0xff, 0xff, 0xff,
0x80, 0xaa, 0xaa, 0xab, 0xe0, 0x0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x10, 0x0,
0x2d, 0x0, 0x1f, 0x0, 0xf, 0x0, 0x2, 0xf8,
0xb, 0x40, 0x0, 0xf, 0xd3, 0xc0, 0x0, 0x0,
0xbf, 0xd0, 0x0, 0x0, 0x3, 0xf0, 0x0, 0x0,
0x3, 0xff, 0x40, 0x0, 0x3, 0xf1, 0xf8, 0x0,
0x7, 0xe0, 0xf, 0x80, 0x1f, 0xd0, 0x0, 0xe0,
0xbf, 0xc0, 0x0, 0x0, 0x1f, 0x40, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
/* U+30CD "ネ" */
0xf, 0xe5, 0x7, 0xff, 0x1a, 0x81, 0xff, 0xe7,
0xbf, 0xc0, 0xfe, 0x83, 0xb5, 0xff, 0x83, 0xf3,
0x5f, 0xe0, 0x30, 0x7f, 0xf0, 0xe5, 0x41, 0xff,
0xc3, 0xd5, 0x7, 0xff, 0x9, 0xc6, 0xf, 0xfe,
0x15, 0xa, 0x7, 0xff, 0x6, 0xd0, 0x25, 0xc1,
0xf3, 0xe4, 0x83, 0x43, 0xa1, 0x7a, 0x1f, 0x21,
0xdc, 0x58, 0x15, 0x70, 0x7f, 0x3a, 0x15, 0x10,
0xff, 0xe0, 0xd8, 0x7f, 0xfe, 0xbc, 0x1f, 0xc0,
0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x0, 0x3c,
0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0,
0x0, 0x3c, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff,
0x80, 0x6, 0xaa, 0xaa, 0xaf, 0x80, 0x0, 0x0,
0x0, 0x2e, 0x0, 0x0, 0x0, 0x0, 0xb8, 0x0,
0x0, 0x0, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x1f,
0x80, 0x0, 0x0, 0x0, 0xbd, 0x0, 0x0, 0x0,
0xb, 0xfc, 0x2e, 0x0, 0x1, 0xff, 0x7c, 0xf,
0xd0, 0x3f, 0xe0, 0x3c, 0x1, 0xfc, 0x29, 0x0,
0x3c, 0x0, 0x2c, 0x0, 0x0, 0x3c, 0x0, 0x0,
0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x3c,
0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
/* U+30CE "" */
0xf, 0xfe, 0x7d, 0xa1, 0xff, 0xc0, 0x44, 0x3f,
0xe4, 0x3f, 0xf8, 0x59, 0x7, 0xff, 0x1, 0x10,
0xff, 0xa1, 0xf, 0xfe, 0x2, 0x41, 0xff, 0x44,
0x1f, 0xf2, 0x84, 0x3f, 0xe8, 0x83, 0xfe, 0xc5,
0x7, 0xf3, 0x8c, 0x1f, 0xd4, 0x18, 0x3f, 0x3a,
0x50, 0x3e, 0x78, 0x1a, 0x1f, 0xf5, 0x87, 0xf9,
0xf2, 0x1f, 0xf0
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xd0,
0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x7c, 0x0,
0x0, 0x2, 0xd0, 0x0, 0x0, 0xf, 0x0, 0x0,
0x0, 0xb8, 0x0, 0x0, 0x3, 0xc0, 0x0, 0x0,
0x2d, 0x0, 0x0, 0x1, 0xf0, 0x0, 0x0, 0xf,
0x40, 0x0, 0x0, 0xf8, 0x0, 0x0, 0x1f, 0x80,
0x0, 0x2, 0xf8, 0x0, 0x0, 0x7f, 0x40, 0x0,
0x1f, 0xf0, 0x0, 0x0, 0x7d, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0
};
@@ -438,55 +547,55 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 212, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 212, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 54, .adv_w = 212, .box_w = 10, .box_h = 19, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 95, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 142, .adv_w = 212, .box_w = 11, .box_h = 10, .ofs_x = 1, .ofs_y = 6},
{.bitmap_index = 168, .adv_w = 212, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 185, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 227, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 244, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 278, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 315, .adv_w = 212, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 349, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 384, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 426, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 460, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 504, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 546, .adv_w = 212, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 578, .adv_w = 212, .box_w = 13, .box_h = 6, .ofs_x = 0, .ofs_y = 4},
{.bitmap_index = 593, .adv_w = 212, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 625, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 670, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 699, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 719, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 736, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 750, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 792, .adv_w = 212, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 830, .adv_w = 352, .box_w = 19, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 894, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 942, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 999, .adv_w = 352, .box_w = 20, .box_h = 15, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1030, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1086, .adv_w = 352, .box_w = 17, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1143, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1211, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1283, .adv_w = 352, .box_w = 20, .box_h = 20, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 1356, .adv_w = 352, .box_w = 16, .box_h = 17, .ofs_x = 3, .ofs_y = -1},
{.bitmap_index = 1384, .adv_w = 352, .box_w = 20, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 1438, .adv_w = 352, .box_w = 19, .box_h = 18, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1509, .adv_w = 352, .box_w = 18, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1574, .adv_w = 352, .box_w = 19, .box_h = 18, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 1638, .adv_w = 352, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1701, .adv_w = 352, .box_w = 18, .box_h = 20, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 1779, .adv_w = 352, .box_w = 20, .box_h = 18, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 1839, .adv_w = 352, .box_w = 18, .box_h = 18, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1908, .adv_w = 352, .box_w = 19, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 1969, .adv_w = 352, .box_w = 12, .box_h = 19, .ofs_x = 7, .ofs_y = -1},
{.bitmap_index = 1995, .adv_w = 352, .box_w = 19, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2047, .adv_w = 352, .box_w = 18, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
{.bitmap_index = 2069, .adv_w = 352, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 2134, .adv_w = 352, .box_w = 20, .box_h = 20, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 2198, .adv_w = 352, .box_w = 15, .box_h = 18, .ofs_x = 3, .ofs_y = -1}
{.bitmap_index = 56, .adv_w = 212, .box_w = 10, .box_h = 19, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 104, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 156, .adv_w = 212, .box_w = 11, .box_h = 10, .ofs_x = 1, .ofs_y = 6},
{.bitmap_index = 184, .adv_w = 212, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 223, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 267, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 307, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 351, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 395, .adv_w = 212, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 443, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 487, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 531, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 575, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 619, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 663, .adv_w = 212, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 699, .adv_w = 212, .box_w = 13, .box_h = 6, .ofs_x = 0, .ofs_y = 4},
{.bitmap_index = 719, .adv_w = 212, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 755, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 807, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 851, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 891, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 931, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 975, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1027, .adv_w = 212, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1075, .adv_w = 352, .box_w = 19, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1156, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 1242, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1328, .adv_w = 352, .box_w = 20, .box_h = 15, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1403, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1489, .adv_w = 352, .box_w = 17, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1570, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1656, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 1742, .adv_w = 352, .box_w = 20, .box_h = 20, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 1842, .adv_w = 352, .box_w = 16, .box_h = 17, .ofs_x = 3, .ofs_y = -1},
{.bitmap_index = 1910, .adv_w = 352, .box_w = 20, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 2005, .adv_w = 352, .box_w = 19, .box_h = 18, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2091, .adv_w = 352, .box_w = 18, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2168, .adv_w = 352, .box_w = 19, .box_h = 18, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 2254, .adv_w = 352, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2331, .adv_w = 352, .box_w = 18, .box_h = 20, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 2421, .adv_w = 352, .box_w = 20, .box_h = 18, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 2511, .adv_w = 352, .box_w = 18, .box_h = 18, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2592, .adv_w = 352, .box_w = 19, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 2683, .adv_w = 352, .box_w = 12, .box_h = 19, .ofs_x = 7, .ofs_y = -1},
{.bitmap_index = 2740, .adv_w = 352, .box_w = 19, .box_h = 19, .ofs_x = 2, .ofs_y = -1},
{.bitmap_index = 2831, .adv_w = 352, .box_w = 18, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
{.bitmap_index = 2894, .adv_w = 352, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 2971, .adv_w = 352, .box_w = 20, .box_h = 20, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 3071, .adv_w = 352, .box_w = 15, .box_h = 18, .ofs_x = 3, .ofs_y = -1}
};
/*---------------------
@@ -536,7 +645,7 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
.cmap_num = 1,
.bpp = 2,
.kern_classes = 0,
.bitmap_format = 1,
.bitmap_format = 0,
#if LVGL_VERSION_MAJOR == 8
.cache = &cache
#endif
+9 -1
View File
@@ -5,6 +5,7 @@
#include <string.h>
#include "cJSON.h"
#include "esp_app_desc.h"
#include "esp_log.h"
#include "esp_websocket_client.h"
@@ -61,11 +62,17 @@ static void ws_event(void *arg, esp_event_base_t base, int32_t id, void *data)
(void)base;
esp_websocket_event_data_t *ev = (esp_websocket_event_data_t *)data;
switch (id) {
case WEBSOCKET_EVENT_CONNECTED:
case WEBSOCKET_EVENT_CONNECTED: {
ESP_LOGI(TAG, "gateway connected");
s_connected = true;
char hello[128];
snprintf(hello, sizeof(hello),
"{\"type\":\"hello\",\"device\":\"desklock-p4\",\"fw\":\"%s\"}",
esp_app_get_description()->version);
gw_send_text(hello);
face_set(FACE_IDLE);
break;
}
case WEBSOCKET_EVENT_DISCONNECTED:
case WEBSOCKET_EVENT_ERROR:
if (s_connected) {
@@ -97,6 +104,7 @@ void gw_start(void)
.buffer_size = 8192,
.reconnect_timeout_ms = 5000,
.network_timeout_ms = 10000,
.ping_interval_sec = 8, /* keep the link visibly alive through long Tatlock turns */
};
s_ws = esp_websocket_client_init(&cfg);
esp_websocket_register_events(s_ws, WEBSOCKET_EVENT_ANY, ws_event, NULL);
+34 -2
View File
@@ -14,6 +14,36 @@
static const char *TAG = "net";
static esp_netif_t *s_netif;
static volatile bool s_got_ip;
/* Router DHCP has been observed to go silent for this MAC (flap throttling).
* After 15 s without a lease, claim the previously granted address statically. */
static void static_ip_fallback(void *arg)
{
(void)arg;
vTaskDelay(pdMS_TO_TICKS(15000));
if (!s_got_ip) {
ESP_LOGW(TAG, "no DHCP lease after 15s — falling back to static 192.168.86.53");
esp_netif_dhcpc_stop(s_netif);
esp_netif_ip_info_t ip = { 0 };
ip.ip.addr = esp_ip4addr_aton("192.168.86.53");
ip.gw.addr = esp_ip4addr_aton("192.168.86.1");
ip.netmask.addr = esp_ip4addr_aton("255.255.255.0");
esp_netif_set_ip_info(s_netif, &ip);
esp_netif_dns_info_t dns = { 0 };
dns.ip.u_addr.ip4.addr = esp_ip4addr_aton("192.168.86.1");
dns.ip.type = ESP_IPADDR_TYPE_V4;
esp_netif_set_dns_info(s_netif, ESP_NETIF_DNS_MAIN, &dns);
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
tzset();
esp_sntp_config_t sntp = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
esp_netif_sntp_init(&sntp);
gw_start();
}
vTaskDelete(NULL);
}
static void scan_then_connect(void *arg)
{
(void)arg;
@@ -38,7 +68,7 @@ static void wifi_event(void *arg, esp_event_base_t base, int32_t id, void *data)
(void)arg;
(void)data;
if (base == WIFI_EVENT && id == WIFI_EVENT_STA_START) {
xTaskCreate(scan_then_connect, "scan", 4096, NULL, 4, NULL);
esp_wifi_connect();
} else if (base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t *dc = (wifi_event_sta_disconnected_t *)data;
ESP_LOGW(TAG, "wifi disconnected (reason %d), retrying", dc ? dc->reason : -1);
@@ -47,6 +77,7 @@ static void wifi_event(void *arg, esp_event_base_t base, int32_t id, void *data)
esp_wifi_connect();
} else if (base == IP_EVENT && id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data;
s_got_ip = true;
ESP_LOGI(TAG, "got ip " IPSTR, IP2STR(&ev->ip_info.ip));
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
tzset();
@@ -65,7 +96,7 @@ void net_start(void)
}
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
s_netif = esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
@@ -79,5 +110,6 @@ void net_start(void)
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wc));
ESP_ERROR_CHECK(esp_wifi_start());
xTaskCreate(static_ip_fallback, "ipfb", 4096, NULL, 3, NULL);
ESP_LOGI(TAG, "wifi starting, ssid=%s", WIFI_SSID);
}
+3
View File
@@ -28,3 +28,6 @@ CONFIG_LV_FONT_MONTSERRAT_28=y
# ESP-Hosted C6 radio
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
# custom fonts are uncompressed, but enable the decoder as belt-and-braces
CONFIG_LV_USE_FONT_COMPRESSED=y
+2 -1
View File
@@ -9,4 +9,5 @@ COPY src ./src
RUN pip install --no-cache-dir .
EXPOSE 8600
CMD ["uvicorn", "desklock_gateway.main:app", "--host", "0.0.0.0", "--port", "8600"]
# generous ws ping timeout: the device stays quiet during 10-25s Tatlock turns
CMD ["uvicorn", "desklock_gateway.main:app", "--host", "0.0.0.0", "--port", "8600", "--ws-ping-interval", "25", "--ws-ping-timeout", "120"]
+39 -3
View File
@@ -7,6 +7,7 @@ Protocol (see docs/architecture.md — keep in sync):
import asyncio
import logging
from datetime import datetime, timezone
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
@@ -20,21 +21,40 @@ app = FastAPI(title="DeskLock Gateway")
PCM_CHUNK_BYTES = 4096
# device registry: every endpoint that ever connected, keyed by client IP
DEVICES: dict[str, dict] = {}
def _now() -> str:
return datetime.now(timezone.utc).astimezone().isoformat(timespec="seconds")
@app.get("/healthz")
async def healthz() -> dict[str, str]:
return {"status": "ok"}
@app.get("/devices")
async def devices() -> dict[str, dict]:
return DEVICES
@app.websocket("/ws/voice")
async def voice(ws: WebSocket) -> None:
await ws.accept()
ip = ws.client.host if ws.client else "unknown"
device = DEVICES.setdefault(ip, {"connections": 0})
device["connections"] += 1
device.update(connected=True, connected_at=_now(), last_seen=_now())
logger.info("device connected from %s (connection #%d)", ip, device["connections"])
tatlock = TatlockClient()
pcm = bytearray()
recording = False
try:
while True:
message = await ws.receive()
device["last_seen"] = _now()
if "bytes" in message and message["bytes"] is not None:
if recording:
pcm.extend(message["bytes"])
@@ -45,15 +65,31 @@ async def voice(ws: WebSocket) -> None:
import json
event = json.loads(message["text"])
if event["type"] == "utterance_start":
if event["type"] == "hello":
device["device"] = event.get("device", "unknown")
device["fw"] = event.get("fw", "unknown")
logger.info("device identified: %s fw=%s", device["device"], device["fw"])
elif event["type"] == "utterance_start":
pcm.clear()
recording = True
elif event["type"] == "utterance_end":
recording = False
await _handle_utterance(ws, tatlock, bytes(pcm))
try:
await _handle_utterance(ws, tatlock, bytes(pcm))
except WebSocketDisconnect:
raise
except Exception:
logger.exception("utterance failed")
try:
await ws.send_json({"type": "error"})
await ws.send_json({"type": "state", "value": "idle"})
except Exception:
logger.info("device gone before error could be reported")
break
except WebSocketDisconnect:
logger.info("device disconnected")
logger.info("device disconnected: %s", ip)
finally:
device.update(connected=False, disconnected_at=_now())
await tatlock.aclose()
+7
View File
@@ -8,3 +8,10 @@ def test_healthz() -> None:
response = client.get("/healthz")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
def test_devices_registry_empty() -> None:
client = TestClient(app)
response = client.get("/devices")
assert response.status_code == 200
assert isinstance(response.json(), dict)