diff --git a/.gitignore b/.gitignore index 4eb34921..30e1f5ce 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ enc-ctrl/tests/test_runner # Source-built CV610 sensor-plugin artifacts sensors/cv610/imx662/*.o +sensors/cv610/imx662/*.d sensors/cv610/imx662/*.so # Performance benchmark artifacts — local-only, not shipped upstream @@ -41,3 +42,6 @@ a-*.d # Serena LSP tooling config — local developer machine only, not shipped /.serena/ + +# CI-pinned SDK checkouts (.github/workflows/main.yml lint-build-cv610) +.deps/ diff --git a/HISTORY.md b/HISTORY.md index 86f9ad9d..d9e4a5d4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,645 @@ # History +## [0.67.1] - 2026-08-22 + +Pre-upstream review pass over 0.65.3..0.67.0. Three defects introduced by that +range, one long-standing sensor-register error, and the documentation the +range changed but did not update. No wire format, config schema or frame-SHM +layout changes. + +- **Star6E dual-VENC crashed at startup.** `star6e_pipeline_start_venc()` + accepts `vcfg == NULL` — `star6e_pipeline_start_dual()` passes it for ch1 — + but 0.66.0's slice block dereferenced it unguarded. Any craft with + `record.mode=dual`/`dual-stream` segfaulted during startup controls, + independent of `sliceCount`, because the fault is the *read* of + `slice_count`. `record.mode` is gated on mode alone, not `record.enabled`. + Host tests could not see it: `star6e_pipeline.c` is not in the test library. +- `MI_VENC_ParamH265SliceSplit_t` was passed to the vendor with its padding + uninitialised; both sibling structs in the same function are memset. +- A `libmi_venc.so` without the optional `MI_VENC_SetH265SliceSplit` export + failed startup with a message that read as a driver rejection. The failure + stays fatal — delivering one slice while the API advertises N would lie to + the receiver's spatial concealment — but now names the missing symbol. +- **The CV610 partial-load rollback could still wedge the SoC.** `stop_modules()` + refuses to unload while a consumer holds an MPP device, and its comment + claimed every unload path was covered; `cleanup_partial()`, armed as an EXIT + trap across the whole load sequence, was not. A consumer can claim a device + created earlier in that same sequence — `waybeam_hub` rebinds `/dev/rgn` + within ~1 s of `open_rgn` appearing — so a later insmod failure unloaded it + underneath a live holder. It now carries the same guard and leaves the + modules loaded, which is recoverable; a wedged SoC is not. +- **The IMX662 analog gain register was never written.** Sony's register list + puts `GAIN[10:0]` at `3070h`/`3071h` and jumps straight from `3069h` to + `3070h` — `306Ch`/`306Dh` are not registers. Every AE gain update went to a + dead address, so analog gain never actuated, all gain was ISP digital, and + the HCG conversion-gain compensation never landed, making each HCG engage an + uncompensated ~5.8x brightness step. The vendor's own reference driver + carries the same pair. **This changes low-light behaviour materially and the + gain/ISO tuning in 0.65.6 was measured against the dead register — the + low-light path needs re-verification on hardware.** +- The HCG band's compile-time guard could not fire in the dangerous direction: + all three operands are `u`-suffixed, so lowering `HCG_OFF_REG` below + `HCG_GAIN_OFFSET` wrapped and passed clean. Now evaluated signed, with a + second assert rejecting an inverted ON/OFF pair. Both mutation-tested. +- `make stage SOC_BUILD=cv610` returned 0 when the sensor plugin failed to + build, because the recipe chains with `;` and the last `cp` succeeded. CI + caught it only via its explicit `test -f` on the `.so`. +- `data.routes.iq` claimed `/api/v1/iq` *and* `/api/v1/iq/set` were serviced + while testing only `query_iq_info`; `/iq/set` gates on `apply_iq_param`. Now + requires both. Every shipped backend registers both, so no response changes. + The test that asserted the old pairing gained the missing arm. +- Docs: `docs/CV610_BACKEND.md` said the init script unloads the MPP stack on + stop and guards unloading itself — both untrue since 0.65.8/0.65.10 — and + recorded none of the operator rules those releases established. Its audio + timestamp note still claimed 10 ms against `CV610_AUDIO_POINT_NUM` 960. + `/api/v1/intra/status` and `/api/v1/resilience/status` are documented for the + first time. An orphaned code fence in the capabilities section rendered ~25 + lines of prose as a code block. + +## [0.67.0] - 2026-08-22 + +Ports the shared resilience contract and whole-access-unit H.265 slicing to +CV610. All resilience presets now drive the HiSilicon row-intra-refresh and +base/enhance reference controls with strict setter/getter verification; +`video0.sliceCount` drives 32-pixel LCU-row splitting with early slice output +kept disabled. The existing config schema and frame-SHM v1 wire layout are +unchanged. + +- CV610 consumes per-frame vendor `ref_type`, marks non-reference enhancement + frames in frame-SHM, rewrites their copied TRAIL_R NAL headers to TRAIL_N, + publishes GDR cycle position/length, and rate-limits recovery IDRs when a + full output ring drops a reference-chain frame. +- `/api/v1/capabilities`, intra status, and resilience status now report the + implemented CV610 controls. Startup fails on an encoder readback mismatch + instead of silently claiming resilience or slice geometry. +- Confirmed on the IMX662 CV610 bench at 1080p30/60/100. Slice requests 1, 3, + 4, 6, 9, 12 and 17 delivered exact VCL-NAL counts; shared ref presets matched + vendor cadence; frame-SHM metadata/integrity passed; and an IDR-started + 380-frame 1080p60 stream decoded cleanly under FFmpeg `-xerror`. +- Maruko now binds the device-aware H.265 slice Set/Get ABI and applies it in + the required CreateChn-before-StartRecvPic window, including stab-fill. + Explicit multi-slice requests fail startup if the ABI cannot be applied or + read back; `sliceCount=1` remains compatible with older libraries. +- Confirmed on SSC378QE/Maruko at 1280x720@30 with `rally`: requests 1, 4 and + 12 delivered exactly, while 17 and 32 quantized to the picture maximum of + 12. All sampled access units retained their complete VCL census and a + cold-start 284-frame, 12-slice capture decoded cleanly with FFmpeg. +- Fixed a pre-existing Maruko frame-SHM startup guard that rejected a valid + frame ring because it checked only socket and packet-ring transports. +- The 0.66 eight-slice ceiling and CV610/Maruko deferrals are superseded: + `packetInfo[8]` is per pack, while every output path walks all packs in the + access unit. The shared request range is now 1..32 and device geometry sets + the delivered ceiling. +- The frame-SHM consumer test can optionally dump an IDR-started Annex-B stream + for offline decoder validation. + +## [0.66.0] - 2026-08-19 + +Adds H.265 multi-slice output on Star6E: `video0.sliceCount` (1..8, default +1 = today's single-slice stream, restart-class) binds the vendor +`MI_VENC_SetH265SliceSplit` — exported by the shipped `libmi_venc.so` all +along, never wired — and asks for `ceil(rows/sliceCount)` CTU rows per slice +between CreateChn and StartRecvPic, the same SDK window as refPred. + +The consumer is waybeam-link's new §6.3b spatial concealment: with several +independent slices per picture, RF loss past the FEC budget costs a frozen +region instead of the whole frame. The knob defaults off so nothing changes +until a craft opts in. + +- Frame-SHM publication is untouched: still one access unit per slot, now + with N slice NALs inside it. RTP/recorder walkers already iterate + `packetInfo[]` and stay correct. + +- The 8-entry `packetInfo[]` clamp is the known ceiling — the field is + range-limited to 8, and the frame-ring walker now WARNs (once) if the SDK + ever reports more NALs in a pack than the table holds, instead of silently + shipping a truncated frame. Whether the SDK emits one pack per slice or + packs slices into one `packetInfo[]` still needs the on-device readout; + until then treat sliceCount 4 as the validated envelope (offline: 4-slice + 1080p streams repaired and decoded clean by ffmpeg/libde265/HM-18.0). + +- CV610: not exposed (allowlist unchanged); the SDK headers are external and + its slice-split contract is unverified. Maruko: `libmi_venc.so` exports the + symbol, but only the Star6E pipeline applies it for now. + +## [0.65.10] - 2026-08-17 + +Removes both CV610 paths that unloaded MPP modules on a running craft: the +`S95waybeam reload` action, and `start()`'s module rollback on a failed daemon +start. `reload` was dead code built on a premise the hardware disproved in the +release that added it; the rollback was reachable on the post-crash start this +release prescribes as the recovery. + +- **Nothing in production called it** — the hub uses `restart` + (`mod_venc.c:687`), venc never did, and the crash test does not. Only the + suite's own T5 exercised it, to test the action itself. + +- **Its premise was already falsified.** Its comment claimed VB is left held by a + dead owner after a crash and reload is "the way out". 0.65.8's own notes say + the opposite — *"ISP, not VB, is what a crash leaves behind… VB is released"* — + and the suite prints `VB was released when the process died` on every run. What + a crash actually leaves (ISP, and since 0.65.9 the AI device claim) venc + pre-cleans itself, so a hard-killed venc recovers from a plain `start`, video + and audio both. + +- **Unloading is not free.** A hard kill poisons module reloading for the rest of + the boot (`no sys ko!` → `load vpp.ko ...FAILURE!`), so a reload issued + afterwards leaves the craft with no modules at all — and on a video-only craft + it resets the SoC outright (measured). The underlying defect is in the vendor + modules and is unchanged. + + `reload` was not the only unload on that path, which an adversarial review + caught before this merged: `start()` rolled back with `"$LOADER" stop` on a + failed daemon start, and since 0.65.8 made the loader's start idempotent + ("MPP modules already loaded" → success) that rollback tore down a set the + invocation had not created — on exactly the post-crash start this release + prescribes as the recovery. That rollback is removed too. Leaving the modules + up after a failed start costs nothing, because the next start re-inits against + them. + +- The loader's audio-mismatch hint pointed at `S95waybeam reload`; it now says + reboot, which is what actually applies a `CV610_AUDIO` or sensor-profile + change. `load-cv610-online restart` remains for a dirty or partial module set, + but run **bare** it reloads with the loader's defaults (video-only, imx662 + clock) rather than the craft's profile — a caveat that used to live inside + `reload()` and is now recorded where it survives it. `load-cv610-online stop` + followed by `S95waybeam start` is the safer form; that passes the profile. + +- The suite loses T5 (it tested `reload`) and, with it, the contaminated-boot + precondition T5 needed. The suite no longer *performs* an unload: T1 still + attempts one, but only to assert the loader refuses it while the hub holds + `/dev/rgn`. It also no longer stops the hub anywhere, so T6 now always runs + with a holder present. + +## [0.65.9] - 2026-08-17 + +CV610 audio now survives an abnormal venc exit. Investigating the "aenc MMB +leak" reported in 0.65.8 showed it is **not a leak** — and that it was masking a +real regression. + +- **The MMB LEAK lines are the kernel reclaiming, not losing.** Measured on + `.181`: a hard kill prints `MMB LEAK(pid=N) 'aenc(0)_strm'`/`'aenc(0)_cir'`, + and the two blocks are gone from `/proc/umap/media-mem` immediately after. + Across **five** kill cycles the pool returned to its exact baseline — + `34 blocks / 38332 KB` before and after. Nothing accumulates. + +- **What actually broke: audio, silently.** MPP objects are kernel state, so a + killed venc leaves the AI device claimed by the dead pid. Every AI call from + the successor is then refused with `OT_ERR_AI_NOT_PERM` (`0xa015800d`) — + including `ss_mpi_ai_disable()`, so the successor could not even clean up. + `ss_mpi_ai_set_pub_attr()` failed, audio never started, and venc reported + *"needs CV610_AUDIO=1 at module load"* — which is not what happened. Video + streamed normally, so nothing looked wrong. Deterministic, 2 of 2. + + This was masked until 0.65.8: the module reload that release removed also + wiped the AI claim. So the hard-kill path regressed there, and `reload` is not + a way out — a hard kill also poisons module reloading for the rest of the boot. + +- **Fix: cycle the audio module before bring-up.** `cv610_audio_start()` now + calls `ss_mpi_audio_exit()` + `ss_mpi_audio_init()`, then `ss_mpi_ai_disable()`, + before configuring anything. The module cycle is what clears the dead owner's + claim — it is precisely why a *second* graceful restart used to recover audio + where the first did not, and this folds that cycle into the first start. Same + shape as `sys_setup()`'s `isp_exit`/`sys_exit`/`vb_exit` pre-clean. + + Releasing the objects one by one does **not** work and is not attempted: the + SDK tracks `sys_unbind`, `aenc_destroy_chn`, `opus_deinit` and + `ai_disable_chn` process-locally, so a successor cannot release a dead + predecessor's copies. Only `ss_mpi_ai_disable()` reaches kernel state, and it + is the only one whose return code ever differed between the broken and healthy + cases. `opus_deinit` was additionally printing `illegal handle(-1)!` to stderr + on every clean start. + + Verified on `.181`: kill a venc with healthy audio, start, audio back — **2 of + 2**, `aenc` blocks 0 → 2, `ai_disable` `0xa015800d` → `0x0`. It also recovered + a craft already stuck in the broken state with no reboot, and a graceful + restart is unchanged. + +- **The audio warning no longer guesses a cause.** It asserted *"needs + CV610_AUDIO=1 at module load"* for every failure — the misreport above. The + module hint moved to `ss_mpi_audio_init()`, which is where an absent module set + actually lands (it opens `/dev/ab`, created by `open_aio`, which the loader + stages only under `CV610_AUDIO=1` — a switch independent of `audio.enabled`). + The `/dev/acodec` open is *not* that path. + +- The verify suite's T6 asserted *video* streaming, which is why this went + unnoticed — it passed with audio dead. It now asserts the aenc block count and + the absence of an audio-start failure, and skips explicitly (not silently) on + a video-only craft. T5 refuses to run on a boot where a hard kill already + happened, instead of failing for a reason that predates the run. + +## [0.65.8] - 2026-08-17 + +CV610 venc restarts no longer reload the MPP kernel modules — the same model +star6e and maruko have always used, where the init script never touches +`insmod`/`rmmod` at all. + +- **The reload was bring-up scaffolding.** Both cv610 init scripts have been + unchanged since the initial backend commit. `mpp_cleanup()` is already a + complete teardown and, critically, calls `ss_mpi_vb_exit()` *from the process + that created VB* — the only process permitted to. So after a graceful stop + there is nothing for a module reload to clean up, and the next start can + re-init the graph against the modules already loaded. + +- **What the reload was actually protecting.** A venc that dies without running + `mpp_cleanup()` leaves VB held by a dead owner; `vb_set_cfg` then returns + BUSY. That was tolerated blindly, which is only harmless while the modules + are reloaded every time. Without the reload it would mean running on the + previous mode's pool sizes. + + `sys_setup()` now reads the live config back with `ss_mpi_vb_get_cfg()` and + compares the pools it was about to request. Identical layout is adopted and + says so; a different layout is a hard failure naming the way out + (`load-cv610-online restart`) instead of silently handing out wrong-sized + blocks that surface later as corruption. + +- `load-cv610-online start` is idempotent when the full set is up (`open_user` + is the last module loaded, so its presence means a completed sequence); a + *partial* set is still refused as dirty. `S95waybeam stop` leaves the modules + loaded, and a new `S95waybeam reload` is the recovery path after a crash — + it unloads, so the holder guard applies and the hub must be stopped first. + +- **ISP, not VB, is what a crash leaves behind.** Measured on `.181`: after + `kill -9`, VB *is* released (set_cfg succeeds) but ISP[0] stays inited and the + next run dies at `ss_mpi_isp_mem_init` with `0xa01c800c` "already inited". + `sys_setup()` now pre-cleans with `ss_mpi_isp_exit(VI_PIPE)` alongside the + existing `sys_exit`/`vb_exit`, before anything of ours is registered, so a + hard kill recovers without a module reload. + +- `S95waybeam reload` passes `CV610_SENSOR_PROFILE`/`CV610_AUDIO` through to the + loader. A bare `$LOADER restart` reloads with the loader's own defaults — + video-only, imx662 clock — and `start()` then correctly refuses the audio + mismatch, leaving the craft with no daemon at all. + +- Device verification on `.181`, `scripts/cv610_reload_free_verify.sh`: + **23 passed, 0 failed**. T3 restarts across a real mode change and asserts the + *encoded geometry* moved (1920x1080 → 640x360) from venc's own VPSS line, + because asserting the config key instead let an earlier revision report a mode + change that never happened. T2 asserts the hub's OSD survived, from the + compositor's VGS job counters in `/proc/umap/rgn` rather than the hub's own + perf line — the hub counts the publish it made, which is the stimulus; those + counters count the composite that consumed it. Verified to fail on a region + that is not there. T3 asserts it too, across the mode change, because the hub + rebinds at its old window size and only its own source poll re-anchors it: an + oversized region sits on the smaller channel for a few seconds. Measured + benign — 30 s at 640x360 with `job_fail` 0 and venc streaming. + +Two things the hardware showed that are **not** fixed here: + +- **A SIGKILL leaks two `aenc` MMB blocks** (`aenc(0)_strm`, `aenc(0)_cir`, + 16 KB each) and after that the next module unload/reload fails at sys.ko init + — `no sys ko!` then `load vpp.ko ...FAILURE!` — for the rest of the boot, so + even a fresh load from zero modules fails. Graceful stops leak nothing. This + makes `reload` the wrong recovery after a hard kill; reboot is. It is also an + independent argument for this change: the fewer module reload cycles, the + better, and it plausibly underlies the old "reboot instead" folklore. + +- **The hub's RGN OSD does not survive a venc restart.** With `open_rgn` no + longer unloaded the hub keeps its `/dev/rgn` handle, but the region does not + survive our teardown: after a restart `/proc/umap/rgn` lists **no regions at + all** — `mpp_cleanup()`'s `ss_mpi_sys_exit()` takes the whole table with it, + because MPP objects are kernel state shared across processes. The hub keeps + painting into a handle that no longer exists: `osd_render` goes from + `40 rgn … drops 0` to `0 rgn … drops 42`, silently. A hub restart restores it. + Fixed on the hub side in waybeam-hub#213 (the region is recreated and rebound + after five consecutive failed publishes), which is what T2 now asserts. + +## [0.65.7] - 2026-08-17 + +CV610 SoC wedge on `stop`. On the `.181` bench, `S95waybeam stop` while +`waybeam_hub` was running killed the SoC outright — no network, ARP +incomplete, physical power cycle required. It had been misfiled as an +intermittent "reboot sometimes hangs" for weeks. + +- **Root cause: the MPP modules were unloaded under a live consumer.** + `stop()` waits only for `waybeam`/`waybeam-resp`/`waybeam-wd` and then calls + `load-cv610-online stop`, which rmmods the whole stack. `waybeam_hub` holds + `/dev/rgn` for the CV610 RGN OSD and `/dev/mmz_userdev`, and the MPP drivers + do not set `.owner` on their file operations — `/proc/modules` reports + `open_rgn used=0` while the hub has `/dev/rgn` open. `rmmod` therefore + succeeds and frees the file operations out from under a live consumer. + + The script already carried the right invariant in a comment — *"Never unload + the MPP stack while any of them still owns the graph"* — it just never + counted the hub as an owner. + +- **Measured, with controls.** 10/10 monitored `reboot` cycles clean (ping gap + 12.6–15.8 s, back 18–20.5 s). 20/20 venc stop/start cycles clean with the hub + stopped, 2100 frames and 0 output drops afterwards. First stop/start with the + hub running: dead. Then 5/5 clean again once the hub was released first. + + Reboot was never safe for the reason everyone assumed. `rcK` iterates + `ls -r /etc/init.d/S??*`, so `S97waybeam-hub` stops *before* `S95waybeam`. + That accident is the entire difference, and it retro-explains the standing + "never stop/start venc on cv610, reboot instead" rule. + +- **Fix.** The guard lives in `load-cv610-online stop_modules()`, next to the + `rmmod` it protects, so it covers every path that unloads — `S95waybeam + stop`, the start-failure rollback that also calls `$LOADER stop`, and a + hand-run `load-cv610-online stop`. It scans `/proc/*/fd` and refuses, naming + the holders. + + `S95waybeam stop` additionally asks up front, via `load-cv610-online holders` + ignoring its own pids, so it can refuse *before* killing anything: refusing + after the kill would leave venc dead with the modules still loaded, which + `load-cv610-online start` then rejects as dirty state. + + `rcK` and `reboot` are unaffected because the hub is already gone by then; a + manual `S95waybeam stop`/`restart` on a live craft now fails with a message + instead of wedging the SoC. `/api/v1/restart` is untouched — it re-execs the + daemon without unloading modules. + +## [0.65.6] - 2026-08-16 + +Low-light bitrate. On the `.181` bench with the room lights off, a 9.26 Mbps +CBR target produced 29-65 Mbps. In good light the same build holds target +(measured 9.98 vs 9.26), so this was specific to high sensor gain. + +- **The borrowed sharpen table was the cause — 88% of it.** Measured by + A/B with interleaved controls: turning sharpen off dropped the stream + 65.4 -> 7.8 Mbps, *below* the target. Pinning sharpen strength to a constant + gave 0 -> 11.8, 40 -> 36.5, 80 -> 62.7, 150 -> 91.5 Mbps. Nothing else came + close: saturation -7.3%, CSC satu -4.5%, CA +1.7%, LDCI +2.2% (inside drift, + no effect). Disabling bayer NR *raised* the bitrate 15.7%, so NR was already + earning its keep and is untouched. + + Sharpening is a high-pass filter, so at high gain it amplifies precisely the + noise that inter prediction cannot code. `g_cmos_yuv_sharpen` runs in AUTO, + and its sc450ai-derived `[32 gain][16 ISO]` tables *rise* along the ISO axis + — `texture_strength` to 310 where the low-ISO value is 216, `edge_strength` + 195 -> 500. They sharpen harder the darker it gets. Defensible for sc450ai's + noise model and NR softening; backwards on IMX662. + + Both tables are now tapered along ISO only, to 0 by bucket 9, with the rule + the original breaks: sharpening never increases with gain. Verified by four + invariants — ISO buckets 0-3 byte-identical, ISO 9-15 zero, monotonic + non-increasing from bucket 3, and no value anywhere raised. + +- **QP bounds are wired on CV610** (`apply_qp_bounds`, `video0.minQp/maxQp`, + live and at startup). The config fields, mutability and WebUI metadata + already existed; only the backend callback was missing. + + This is **not** the low-light fix, and the measurement says so: the driver + default is `min=10 max=51`, already the H.265 maximum. The rate controller + always had full authority and still emitted 29-65 Mbps, so QP saturation was + never the cause. At 100 fps even maximum-QP frames of a noise-dominated + image exceed 10 Mbps. The knob is worth having to *cap* quality or raise the + floor; it cannot rescue a scene the encoder is already coding as coarsely as + the standard allows. + +- **AE is exposed as an `exposure` IQ group** — the gain ceilings and exposure + window that decide how much noise is created in the first place. Before this + release the bench ran `a_gain_max` 407654 (398x, matching + `IMX662_AGAIN_MAX`), `ispd_gain_max` 32768 (32x) and `sys_gain_max` 13044928 + — **12739x total, about 82 dB**, which is why a dark room ended up as + amplified noise. Those ceilings are now readable and settable at runtime + instead of being compile-time constants, and the digital one is lowered + below. + +- **Saturation tapers harder above daylight.** Chroma noise is the ugliest + high-gain artifact and colour is least trustworthy exactly where gain is + highest; dropping chroma measured -7.3%. The first four buckets are + unchanged, the top drops from 90 to 32. + +- **ISP digital gain is capped 32x -> 4x.** It is the worst gain in the chain: + it amplifies noise and quantisation equally and buys no SNR, where analog + gain and HCG act ahead of the ADC. The shipped total ceiling moves from + 12739x (~82 dB) to **398 x 4 = 1592x (64.0 dB)**, inside the range an + operator preferred on the bench, and AE now exhausts analog before reaching + for digital. Tunable live at + `/api/v1/iq/set?exposure.auto.ispd_gain_max=` (1024 = 1x), because + darker-but-cleaner is an operator trade rather than a constant. + `IMX662_AGAIN_MAX`'s comment claimed ~72 dB while the value gives 52; the + comment is corrected and the value deliberately left alone. + +- **IMX662 HCG conversion gain is selected at high analog gain.** `FDG_SEL0` + (0x3030) was defined and never written, so the sensor sat at its 0h reset — + low conversion gain — and every dark frame was amplified through the noisier + path. It is now a ninth fast-update register, chosen per frame from the gain + code with hysteresis. + + HCG is **not** brightness-neutral: the GAIN register is PGA gain applied + after the conversion gain, so the two multiply. The datasheet gives the ratio + (Rcg typ 5.8, corroborated by G sensitivity HCG 18383 vs LCG 3166 + Digit/lx/s), which is 15.3 dB — so the written code has the offset + subtracted while HCG is on, and the thresholds sit where the compensated code + still clears Sony's 34-code floor (on at 91, off below 85). Without that + there is no fixed point between 12 dB and 25.5 dB: AE brightens 5.8x, slams + the code down past the floor, HCG drops out, and it limit-cycles — a band + that neither daylight nor a dark room enters, which is why an uncompensated + first cut measured clean in both. + + Sony's 34-code floor is a saturation constraint, not the conversion gain: + Vsat is 3895 digits in LCG against 1204 in HCG, a ratio of 3.235, and 34 + codes x 0.3 dB = 10.2 dB = 3.236x — the floor exists so HCG's clip level + refills the ADC to LCG's. + +- **`nr.md_en` and `nr.coring_ratio` are exposed.** The intended fix here was a + re-fit of `g_cmos_noise_calibration`, which is sc450ai's photon-transfer + curve — 16 doubles measured from different silicon. That is a lab + calibration, not a code change, and inventing coefficients would be strictly + worse than keeping a real fit while looking identical in review. The knobs + that fit drives are exposed instead, so the borrowed model can be corrected + by eye until someone measures the real one. `md_en` reads back 1 — CV610's + motion-detect temporal NR was already on. + +The IQ field table is now 64-bit internally: the AE gain and exposure fields +are `td_u32`, and a driver default of 0xFFFFFFFF would have read back as -1. + +`/api/v1/capabilities` gains `data.routes` and `contract_version` moves to +`0.18.4`; the CV610 IQ response shape is documented in +`documentation/HTTP_API_CONTRACT.md`. + +A pre-merge adversarial review pass also corrected this release's own record +and three defects in it: the WebUI IQ tab no longer starts hidden (that made +visibility depend on `init()` completing, so any failed init fetch latched the +tab off permanently on star6e and maruko); a chip click no longer prefills the +actuator (on star6e's legacy path even an identical value forces `enable=1` +and `op_type=manual`); the per-set full-ISP re-query is gone; the shared query +parser rejects an over-long value instead of truncating it mid-token; and the +QP-bounds path leaves the I-frame FLOOR alone so `video0.qp_delta` still +biases I-frames. The 0.65.5 entry above was revised where this stack +invalidated it. + +Verified on `.181`: the sharpen taper was confirmed by the operator on the +live stream (dark room holds target) with daylight unchanged at 10.09 Mbps +against 9.26 and the encoder nominal at 100.20 fps. The gain-chain and HCG +changes landed after that arm and were re-verified separately — see the +per-commit evidence — and `make verify` is green with lint clean on all three +backends. + +## [0.65.5] - 2026-08-16 + +0.65.4 seeded the CV610 ISP well but froze every value into the sensor plugin, +which the ISP reads once at pipe start — correcting one meant a cross-compile, +a plugin deploy and a reboot. This makes those blocks live knobs. No contract +change; `/api/v1/iq` and `/api/v1/iq/set` are existing routes that answered +`501` on this backend only because it supplied no callbacks. + +- **`cv610_iq.c` exposes 11 ISP groups, 59 fields.** saturation, color_tone, + csc, ccm, wb, sharpen, nr, drc, ldci, dehaze and ca, wired into + `g_cv610_apply_callbacks`. Unlike `star6e_iq.c` there is no `dlopen` and no + hand-computed struct offsets: the backend links `ss_mpi` directly, so every + field is an `offsetof()` into the SDK's own type and every range is the + header's documented one. Values are read back from the ISP rather than + cached, and a value outside its declared range is REJECTED rather than + clamped, so the value echoed by `/api/v1/iq/set` is the value applied. +- **Writing a field selects the half of the block it lives in.** A value under + `manual_attr` is inert while the block runs its auto curve and vice versa, + and an ignored write is indistinguishable from a broken setter — so the + write selects that `op_type`. The schema reports each field's `domain` + (`direct` | `manual` | `auto`) and the WebUI marks both kinds on the chip. +- **DRC and dehaze are registered but bypassed**, measured through the new + surface: `drc.enable` and `dehaze.enable` both read 0, and + `ss_mpi_isp_get_module_ctrl()` confirms the hardware bypasses both. Toggling + `drc.enable` clears and restores that bypass bit, so the two agree. 0.65.4's + note that the algorithm blocks were "enabled" over-stated it for these two; + that entry is corrected. Their sc450ai-derived tables ship `enable = 0`, so + DRC has never contributed to a CV610 image and remains unevaluated. +- **The WebUI IQ tab is capability-driven.** It was hidden by a hardcoded + `backendName === 'cv610'` test; visibility now comes from + `/api/v1/capabilities`' `data.routes.iq`, and the knob list is rendered from + the `_schema` the backend describes itself with, so the field table stays in + one place instead of being copied into the page. Backends with no schema keep + the existing hardcoded list. + +Verified on the `.181` bench, cold-booted onto a build of this change +(`/proc/PID/exe` confirmed not `(deleted)`; the binary was rebuilt again for +0.65.6, so the hash is not quoted here): all 11 groups +return `ret=0`; a mutation sweep wrote and read back one field per group with +11/11 agreeing and the device diffing clean against its boot state afterwards; +saturation 60 → 220 → 60 moved mean chroma 4.84 → 22.95 → 4.81, the repeat of +the first arm landing within 0.6% so the change is the knob and not the scene; +arrays of the wrong length in either direction and unknown names are +rejected; encoder rate stayed nominal at 100.10 fps with `pressureDrops` +frozen at 0. + +`/api/v1/capabilities` advertises `routes.iq_import:false` because +`handle_iq_import()` is compiled only for Star6E and Maruko; the WebUI hides +the control rather than offer a button that 501s. (An earlier `_caps` block in +the IQ payload was replaced by this before release — one fact, one place.) + +## [0.65.4] - 2026-08-16 + +The CV610 IMX662 plugin was a scaffold in two places its comments admitted to, +and both were costing image quality. It wrote 26 of the sensor's 131 power-on +registers, and it handed the ISP a zeroed `ot_isp_cmos_default`, which switches +every algorithm block off. No HTTP behaviour changes; contract stays `0.18.3`. + +- **The power-on register sequence is written.** `imx662_sensor_ctl.c` carried a + TODO naming the range it was missing, `0x301C..0x4549`. Sony's sequence for + that range is 131 entries — the reserved analog/ADC trim, the MIPI TX timing, + the readout window and the HDR context linear mode needs parked — and it now + lives in `imx662_cfg.h`. The table runs first, in standby, so the per-mode + writes that follow win where the two overlap; that ordering is load-bearing + for `0x3A50/51/52`, which keys off ADBIT rather than output depth, so the + table holds the 12-bit form and the RAW10 modes overwrite it. Measured on + hardware: 94 entries differ from the module's power-on state, the + readout-window group already matched bit for bit, and a RAW10-vs-RAW12 dump + of the whole range differs in only 8 registers — none of them in the reserved + blocks, which is what made writing the table wholesale safe. +- **The ISP algorithm blocks are enabled.** `cmos_get_isp_default()` memset the + struct and returned, leaving demosaic, gamma, CLUT, LDCI, CAC, + anti-false-colour, dehaze, CA, sharpen, DRC and bayer NR all off. That, not + the sensor, was the flat and hazy image. Tables are ported from the in-tree + `smart_sc450ai` driver, which targets this same ISP silicon. The blocks that + describe ISP behaviour transfer on principle; the noise-fitted ones are + borrowed from a 4 MP sensor and are kept on a hardware A/B rather than a + calibration. Two of them are registered but not switched on: `g_cmos_drc` + and `g_cmos_dehaze` carry `enable = 0`, inherited from sc450ai's linear-mode + defaults, so the ISP bypasses both at runtime. See 0.65.5, which measured + that on hardware. +- **Saturation is configured at all.** `cmos_get_awb_default()` left + `agc_tbl.valid` at 0 with every `saturation[]` entry 0, so the ISP was never + told what saturation to run — the washed-out colour. The shipped curve is + scaled up at the low-ISO end from sc450ai's and keeps its taper at high gain, + where chroma noise scales. Measured +41% mean chroma with sharpness flat. +- **`sns_mode` is populated.** `sns_id` was 0, disagreeing with + `cv610_pipeline.c`'s `IMX662_SNS_ID` — which that file already documents as + having to match, and which would misbind a future PQ `.bin`, since those are + chip- and sensor-locked. `sns_mode` was never set. +- **The sensor plugin Makefile generates header dependencies.** A bare + `%.o: %.c` rule meant a header-only edit relinked stale objects and shipped a + binary without the change, while `make` exited 0. Both the register sequence + and every tuning table live in headers. Found when two plugins built from + different saturation tables came out byte-identical. +- **`tools/cv610_i2c_dump.c`** reads sensor registers over `/dev/i2c` from a + second process while the pipeline runs. `imx662_read_register()` is a stub — + the ISP only ever writes — so nothing could previously confirm an init landed. + +Verified on the Hi3516CV610 bench at 192.168.2.181, cold boot per arm: +1080p30 30.03 fps, 1080p60 60.03, 1080p90 90.03, 1080p100 100.06 — all nominal +and matching the pre-change baseline — with a 1222-register readback at zero +I2C errors and every reference entry matching silicon. + +## [0.65.3] - 2026-08-16 + +CV610 sensor-mode selection reaches parity with SigmaStar, so one client can +render one set of sensor controls against all three backends. Contract +`0.18.2` → `0.18.3`. + +- **`sensor.index` and `sensor.mode` select on CV610 now.** Both parsed and + both sat in the config file, but the backend read neither and the capability + set advertised neither, so `/api/v1/set` answered `409` for a field the + daemon carried. `video0.fps` was the selector instead, through an + exact-match lookup — a request for 45 fps was a hard config error where + SigmaStar substitutes a mode and says so. The two knobs now mean what + `sensor_select()` makes them mean: a forced `sensor.mode` wins over the + requested rate and must exist, otherwise the rate is a target. +- **One case diverges from SigmaStar deliberately.** Its `sensor_mode_cost()` + tie-break scores fps-excess at zero for every mode *below* the target, so a + target above them all falls back to table order — the slowest mode. That + rarely fires there because its modes carry min–max fps ranges; on CV610's + four point-rate modes it would fire constantly, so a target above every mode + clamps to the fastest instead. Verified on the bench: `video0.fps=120` + selects 1080p100, and `45` selects 1080p60. +- **`/api/v1/modes` reports what is running, not what is configured.** + `selected_pad` / `selected_mode` were recomputed from `video0.fps` on every + request, so they described the configured mode even when bring-up had chosen + another or failed outright. They are now published by the backend once the + pipeline resolves, through the same `venc_api_set_sensor_info()` Star6E uses. +- **`video0.gopSize` is checked against the selected mode's rate.** The + encoder has always derived its GOP length from that rate rather than from + `video0.fps`; the two were identical only while selection was exact-match. + A forced mode or a substituted target separates them, and the old check + would have passed a `gopSize` that then exceeded the encoder's 65536-frame + limit. +- A substituted rate is announced (`Requested 45 fps, using 60 fps (sensor + mode 1: 1080p60 RAW12)`) and shows up over HTTP as `/api/v1/fps/live` + disagreeing with `/api/v1/fps/config`. Neither measures anything — the + sensor clock follows the mode automatically, but a client that needs the + delivered rate must still measure it downstream. +- **`isp.keepAspect` works on CV610 now; a 4:3 `video0.size` was silently + squashed.** The field sat in the config defaulting `true`, but CV610 + advertised no `isp.*` field and read none — a knob that did nothing, which + is worse than one that is absent. `1440x1080` validated, then VPSS stretched + the whole 1920x1080 capture into it. The backend now takes a centred crop + first, through the same `pipeline_common_compute_precrop()` Star6E and + Maruko call, so the rule cannot drift between the three: `1440x1080` uses a + 1440x1080 window at x=240 and scales 1:1. `isp.keepAspect=false` restores + stretch-to-fit. Verified both directions on the bench. +- **The CV610 default bitrate drops 8000 → 2600 kbps.** waybeam-link is the + single rate controller and actuates within seconds, so the config value is + a **boot seed**, not an operating point — and what a seed has to survive is + the worst rung, not the expected one. Landing at the §9.8 MCS0 no-feedback + floor while offering 8 Mbps floods the air, and on this fleet an + over-offered craft has already been measured demoting a *second* craft's + link on the same channel within a minute. Pinning the seed low costs + nothing once the controller takes over. +- **CV610 was skipping the shared config validation entirely.** + `venc_api_validate_loaded_config()` dispatched to the CV610 backend + validator *instead of* the shared `validate_field_cfg()` sweep, so sixteen + shared rules never ran there — and CV610 re-implemented two of them + (`video0.size`'s >=128 and multiple-of-8 gates) inside + `cv610_mode_check_output()`, which is the drift risk that made the gap + visible. The `/api/v1/set` path always ran the shared rules, so the same + value was accepted from the config file at boot and rejected with `409` + over HTTP. The sweep now runs first and the backend rules after. +- The CV610 Opus banner said `10.0 ms frames` for a whole release after + `CV610_AUDIO_POINT_NUM` went 480 → 960. Behaviour was right at 20 ms; only + the one line a reader could check the packet rate against was wrong. It is + now derived from the constants rather than spelled out. + ## [0.65.2] - 2026-08-15 CV610 gets a scaler, one mode table instead of five copies of it, and a diff --git a/Makefile b/Makefile index 2b5f56c8..a638add1 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,8 @@ MARUKO_ONLY_SRC := src/maruko_mi.c src/maruko_config.c src/maruko_video.c src/ma STAR6E_ONLY_SRC := src/star6e_output.c src/star6e_audio.c src/star6e_hevc_rtp.c src/star6e_video.c src/star6e_pipeline.c src/star6e_controls.c src/star6e_runtime.c src/star6e_cus3a.c src/star6e_iq.c src/star6e_jpeg.c src/star6e_ipu.c src/star6e_ipu_yolo.c src/star6e_vpe_ports.c src/star6e_luma_tap.c src/star6e_awb.c CV610_SRC := src/main.c src/backend_cv610.c src/cv610_runtime.c \ src/cv610_audio.c \ + src/cv610_encoder_config.c \ + src/cv610_iq.c \ src/cv610_modes.c \ src/cv610_pipeline.c src/cv610_validation.c src/backend.c \ src/venc_config.c src/venc_httpd.c src/venc_api.c src/venc_webui.c \ @@ -358,7 +360,7 @@ stage: build qr-decode mkdir -p $(OUT_DIR)/isp-bins; cp -f iq-profiles/maruko-bin/*.bin $(OUT_DIR)/isp-bins/; \ fi; \ fi - @if [ "$(SOC_BUILD)" = "cv610" ]; then \ + @set -e; if [ "$(SOC_BUILD)" = "cv610" ]; then \ $(MAKE) sensor-cv610 SOC_BUILD=cv610 \ CV610_CC="$(CV610_CC)" CV610_SDK_INC="$(CV610_SDK_INC)"; \ mkdir -p $(OUT_DIR)/sensors; \ @@ -392,7 +394,7 @@ TEST_SRCS := tests/test_runner.c tests/test_venc_config.c \ tests/test_sensor_select.c tests/test_venc_ring.c \ tests/test_file_util.c tests/test_h26x_util.c \ tests/test_h26x_param_sets.c \ - tests/test_maruko_config.c \ + tests/test_maruko_config.c tests/test_maruko_video.c \ tests/test_pipeline_common.c \ tests/test_codec_config.c tests/test_sdk_quiet.c \ tests/test_rtp_packetizer.c \ @@ -425,13 +427,14 @@ TEST_SRCS := tests/test_runner.c tests/test_venc_config.c \ TEST_LIB_SRCS := src/qr_scan.c tools/qr/waybeam_qr_format.c \ tools/qr/quirc/quirc.c tools/qr/quirc/decode.c \ tools/qr/quirc/identify.c tools/qr/quirc/version_db.c \ - src/backend.c src/venc_config.c src/venc_api.c src/venc_httpd.c src/venc_webui.c src/venc_recordings.c src/sensor_select.c src/venc_ring.c src/venc_frame_ring.c src/file_util.c src/h26x_util.c src/h26x_param_sets.c src/intra_refresh.c src/isp_runtime.c src/maruko_config.c src/codec_config.c src/pipeline_common.c src/rtp_session.c src/sdk_quiet.c src/rtp_packetizer.c src/hevc_rtp.c src/star6e_hevc_rtp.c src/star6e_output.c src/star6e_audio.c src/audio_codec.c src/star6e_video.c src/star6e_recorder.c src/star6e_ts_recorder.c src/ts_mux.c src/rtp_sidecar.c src/stream_metrics.c src/output_socket.c src/timing.c src/idr_rate_limit.c src/venc_shm_throttle.c src/debug_osd_draw.c src/venc_jpeg.c src/mdns_wire.c src/mdns_beacon.c src/device_id.c src/framing_kalman.c src/attitude_est.c src/detect_dequant.c src/detect_wire.c src/star6e_vpe_ports.c src/maruko_scl_ports.c lib/cJSON.c + src/backend.c src/venc_config.c src/venc_api.c src/venc_httpd.c src/venc_webui.c src/venc_recordings.c src/sensor_select.c src/venc_ring.c src/venc_frame_ring.c src/file_util.c src/h26x_util.c src/h26x_param_sets.c src/intra_refresh.c src/isp_runtime.c src/maruko_config.c src/maruko_video.c src/maruko_output.c src/codec_config.c src/pipeline_common.c src/rtp_session.c src/sdk_quiet.c src/rtp_packetizer.c src/hevc_rtp.c src/star6e_hevc_rtp.c src/star6e_output.c src/star6e_audio.c src/audio_codec.c src/star6e_video.c src/star6e_recorder.c src/star6e_ts_recorder.c src/ts_mux.c src/rtp_sidecar.c src/stream_metrics.c src/output_socket.c src/timing.c src/idr_rate_limit.c src/venc_shm_throttle.c src/debug_osd_draw.c src/venc_jpeg.c src/mdns_wire.c src/mdns_beacon.c src/device_id.c src/framing_kalman.c src/attitude_est.c src/detect_dequant.c src/detect_wire.c src/star6e_vpe_ports.c src/maruko_scl_ports.c lib/cJSON.c $(TEST_RUNNER): $(TEST_SRCS) $(TEST_LIB_SRCS) tests/test_helpers.h include/backend.h include/h26x_param_sets.h include/hevc_rtp.h include/isp_runtime.h include/maruko_config.h include/pipeline_common.h include/rtp_packetizer.h include/rtp_session.h include/rtp_sidecar.h include/star6e_audio.h include/star6e_hevc_rtp.h include/star6e_output.h include/star6e_recorder.h include/star6e_ts_recorder.h include/ts_mux.h include/audio_ring.h include/star6e_video.h include/stream_metrics.h include/venc_frame_ring.h include/venc_shm_throttle.h $(HOST_CC) $(HOST_CFLAGS) $(TEST_SRCS) $(TEST_LIB_SRCS) -lpthread -ldl -lm -o $@ $(CV610_VALIDATION_TEST): tests/test_cv610_validation.c src/cv610_validation.c \ src/cv610_modes.c \ + src/cv610_encoder_config.c src/intra_refresh.c \ src/venc_config.c src/codec_config.c lib/cJSON.c $(HOST_CC) $(HOST_CFLAGS) -Werror $^ -lm -o $@ @@ -440,8 +443,9 @@ test: $(TEST_RUNNER) $(CV610_VALIDATION_TEST) ./$(CV610_VALIDATION_TEST) test-werror: HOST_CFLAGS += -Werror -test-werror: $(TEST_RUNNER) +test-werror: $(TEST_RUNNER) $(CV610_VALIDATION_TEST) ./$(TEST_RUNNER) + ./$(CV610_VALIDATION_TEST) test-asan: $(HOST_CC) $(HOST_CFLAGS) -Werror -fsanitize=address,undefined $(TEST_SRCS) $(TEST_LIB_SRCS) -lpthread -ldl -lm -o $(TEST_RUNNER) diff --git a/README.md b/README.md index 5dac1921..dc2e48c8 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,7 @@ omitted fields keep their compiled-in defaults. "bitrate": 8192, "gopSize": 1.0, "qpDelta": -4, "sceneThreshold": 0, "sceneHoldoff": 2, + "sliceCount": 1, "resilience": "off", "framing": "off", "zoomX": 0.5, "zoomY": 0.5 }, @@ -309,7 +310,8 @@ omitted fields keep their compiled-in defaults. - **`video0`** — rate control, fps, resolution, bitrate, GOP, per-section QP delta. Video codec is hardcoded H.265 (HEVC). Scene-change-triggered IDR (`sceneThreshold`, - `sceneHoldoff`) is Star6E-only. Intra-refresh is on Star6E and Maruko. The + `sceneHoldoff`) is on Star6E and Maruko. Intra-refresh and whole-access-unit H.265 + slicing are on Star6E, Maruko and CV610. The `framing` knob expands to either digital zoom (Star6E and Maruko) or image stabilization (`stab` HW-crop / `stab-fill` floating-image, Star6E only; live `pauseStab`). @@ -383,7 +385,7 @@ curl http://:/api/v1/version ``` ```json -{"ok":true,"data":{"app_version":"...","backend":"star6e","contract_version":"0.2.0","config_schema_version":"0.2.0"}} +{"ok":true,"data":{"app_version":"0.67.0","backend":"star6e","contract_version":"0.18.5","config_schema_version":"1.0.0"}} ``` #### GET /api/v1/config @@ -852,10 +854,10 @@ behaviour. Requires root (silent fallback otherwise). A *separate* jitter source — a large I-frame whose serialization exceeds one frame interval on a constrained uplink (e.g. 50 Mbps on a 100 Mbps link) — is not a scheduling issue and is unaffected by this priority; mitigate it with a -[resilience preset](#resilience-preset-star6e--maruko) (intra-refresh) or a +[resilience preset](#resilience-preset-star6e--maruko--cv610) (intra-refresh) or a lower bitrate. -#### Resilience preset (Star6E + Maruko) +#### Resilience preset (Star6E + Maruko + CV610) A single field picks an error-resilience profile. Intra-refresh (rolling GDR stripe), the SVC-T reference pyramid (refPred), and the GOP @@ -941,32 +943,16 @@ prediction is from the previous frame either way. | Field | Type | Mutability | Description | |-------|------|------------|-------------| -| `video0.resilience` | string | **reboot** | `off` \| `rescue` \| `quality` \| `sprint` \| `racing` \| `endurance` \| `patrol` \| `rally` \| `range` \| `fpv` \| `ltr` \| `ltr:` (default `off`) | +| `video0.resilience` | string | restart | `off` \| `rescue` \| `quality` \| `sprint` \| `racing` \| `endurance` \| `patrol` \| `rally` \| `range` \| `fpv` \| `ltr` \| `ltr:` (default `off`) | | `video0.gopSize` | double | restart | Seconds between IDRs. Honoured **only** when `resilience` is `"off"` or an `ltr` form; the other named presets override it. Live-reinit applies (no reboot). | -> ⚠️ **Resilience changes require a reboot on both Star6E and Maruko.** -> Setting `video0.resilience` (or any of the derived fields -> `intra_refresh_*` or `ref_*`) persists the new value to -> `/etc/waybeam.json` and returns `{"reboot_required": true}`. The -> live encoder pipeline keeps running the previous preset until the -> next daemon start. -> -> The SigmaStar MI SDK kernel module does not survive a live -> re-configure of these fields. Empirically confirmed on both -> backends (2026-05-15 bench testing): -> -> - **Star6E (Infinity6E)** — fork+exec respawn for the new config -> triggers an SoC kernel panic within 1–2 transitions; ICMP dies, -> requires a power-cycle. -> - **Maruko (Infinity6C)** — in-process pipeline reinit completes -> cleanly for most transitions, but one in a sweep of 7 zombied -> the daemon via a page fault in `MI_SYS_IMPL_FlushInputPortTasks` -> inside the `mi` kernel module. System stays up but waybeam dies -> and does not respawn — reboot is required to restart it. -> -> Different failure modes, same root cause. Cold-boot into any -> preset is 100 % reliable on both SigmaStar backends, so the reboot model is -> what we ship. +Resilience and slice-count changes are restart-required on all three encoder +backends. The API persists the value and uses the backend's process-respawn +handoff to build a fresh encoder graph; a hardware reboot is not part of the +normal apply contract. SigmaStar deliberately avoids in-process MI teardown +and reinitialization because vendor-kernel teardown has proven unsafe. Verify +the running result through `/api/v1/resilience/status` and startup slice +readback logs. Expansion table: diff --git a/VERSION b/VERSION index 8fbb20c5..5caa138c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.65.2 +0.67.1 diff --git a/config/waybeam.default.cv610.json b/config/waybeam.default.cv610.json index 6ecefe96..f77c1cdc 100644 --- a/config/waybeam.default.cv610.json +++ b/config/waybeam.default.cv610.json @@ -7,9 +7,10 @@ "rcMode": "cbr", "fps": 100, "size": "1280x720", - "bitrate": 8000, + "bitrate": 2600, "gopSize": 1.0, "qpDelta": -4, + "sliceCount": 1, "resilience": "off", "framing": "off" }, diff --git a/config/waybeam.default.json b/config/waybeam.default.json index 7ecd310c..5b53a31d 100644 --- a/config/waybeam.default.json +++ b/config/waybeam.default.json @@ -40,6 +40,7 @@ "maxQp": 0, "sceneThreshold": 0, "sceneHoldoff": 2, + "sliceCount": 1, "resilience": "off", "zoomX": 0.5, "zoomY": 0.5, diff --git a/config/waybeam.default.maruko.json b/config/waybeam.default.maruko.json index 5268b609..b1344ec9 100644 --- a/config/waybeam.default.maruko.json +++ b/config/waybeam.default.maruko.json @@ -33,6 +33,7 @@ "qpDelta": -4, "sceneThreshold": 0, "sceneHoldoff": 2, + "sliceCount": 1, "resilience": "off", "zoomX": 0.5, "zoomY": 0.5, diff --git a/docs/CV610_BACKEND.md b/docs/CV610_BACKEND.md index febd3784..9df31312 100644 --- a/docs/CV610_BACKEND.md +++ b/docs/CV610_BACKEND.md @@ -16,6 +16,11 @@ large control surface. (see "Sensor modes" below — the table in `src/cv610_modes.c` is the only place they are written down). - H.265 CBR, GOP, and I/P QP delta come from the existing `VencConfig` fields. +- Shared resilience presets drive row GDR and reference cadence with strict + vendor readback; frame-SHM carries GDR/ENHANCE metadata and copied droppable + NALs are marked TRAIL_N. +- `video0.sliceCount` enables whole-access-unit H.265 slicing. CV610 uses + 32-pixel LCU-row units and keeps early per-slice output disabled. - UDP and abstract UNIX outputs use the shared HEVC RTP packetizer. - `frame-shm://` publishes the existing VFRM v1 whole-frame contract. - The shared HTTP/WebUI API advertises a CV610-specific capability mask and @@ -35,6 +40,26 @@ The graph uses VI-online mode, matching the standalone streamer's production path. The module loader must provide a clean SYS/VB lifecycle; the backend verifies the requested mode by reading it back before creating the VI pipe. +## Encoder capability delta + +CV610 has a substantially broader vendor encoder surface than the current +backend exposes: nine declared RC families, multiple P/CRR GOP structures, +intra refresh, reference prediction, SVC, hierarchical QP, native frame-loss +and super-frame policies, ROI/QP maps, VUI/user data, and slice/low-delay +controls. SSC338Q currently has the broader device-proven Waybeam integration. + +The evidence levels, live-device readback, exact comparison and deliberately +deferred controls are documented in +`documentation/SSC338Q_CV610_ENCODER_CAPABILITIES.md`. The resilience and +whole-access-unit slice port is tracked in +`documentation/CV610_RESILIENCE_SLICES_PLAN.md`. + +The port is confirmed on device at 1080p30/60/100. Requests for 1, 3, 4, 6, 9, +12 and 17 slices delivered the requested VCL NAL census, reference cadences and +TRAIL_N counts matched, and an IDR-started 1080p60 capture decoded cleanly +under FFmpeg `-xerror`. Native SVC, extra RC/GOP modes and encoder-side loss +policies remain deliberately deferred. + ## Build The public OpenHisilicon headers and OpenIPC CV610 runtime library directory @@ -66,10 +91,25 @@ chmod +x /etc/init.d/S95waybeam /usr/bin/load-cv610-online ``` The init script invokes the staged `/usr/bin/load-cv610-online` module -loader before starting the daemon and unloads the MPP stack after graceful -termination. Only one service may own the graph; disable the standalone +loader before starting the daemon. It does **not** unload the MPP stack on +stop: the HiSilicon drivers take no module reference for an open fd, so an +`rmmod` under a live consumer (typically `waybeam_hub` holding `/dev/rgn`) +frees file operations still in use and wedges the SoC hard enough to need a +physical power cycle. Unloading is done only by an explicit +`load-cv610-online stop`, which refuses while any consumer holds an MPP +device. Only one service may own the graph; disable the standalone `S95cv610-streamer` service when enabling `S95waybeam`. +Three operator rules follow from that: + +- **Recovery after an abnormal exit is a plain `S95waybeam start`.** The + modules are still loaded and the daemon re-initialises against them; there + is no `reload` action and no module rollback on a failed start. +- **Changing `CV610_AUDIO` or `CV610_SENSOR_PROFILE` needs a reboot.** The + loader refuses to re-load a differing module set over a live one. +- **A boot that has seen a hard kill cannot be unloaded cleanly.** Reboot + rather than fighting it. + `CV610_SENSOR_PROFILE` picks the sensor clock the modules load with. It is now only a fallback: the daemon sets the clock for the selected mode during bring-up (see "Sensor clock" below), so the profile matters only against a @@ -80,8 +120,8 @@ Audio is opt-in in both layers: set `CV610_AUDIO=1` in `open_aenc`, and `open_acodec`, then set `audio.enabled=true`, 48000 Hz, mono, Opus, and a non-negative `outgoing.audioPort` in `/etc/waybeam.json`. The daemon refuses other CV610 audio formats. The init script tracks the daemon -across API-driven process respawns and will not unload modules while any -Waybeam process still owns the graph. `audio.enabled` and `audio.mute` are +across API-driven process respawns; module unloading is guarded separately in +`load-cv610-online`, which refuses while any process holds an MPP device. `audio.enabled` and `audio.mute` are restart-required HTTP controls; the rest of the audio group is hardcoded and advertised unsupported. Enabling audio from a video-only boot still needs kernel modules that a daemon respawn cannot load, so the daemon warns and @@ -153,21 +193,22 @@ and continues on the boot-time clock. ## Deferred phases -1. Device smoke-test frame-SHM, repeated restart cycles, and a bounded soak. +1. Run a longer-duration soak beyond the bounded device matrices already + completed. 2. Add live output redirection and encoder output-FPS control. 3. Add frame-SHM pressure metrics/throttling and sidecar parity. -4. Port advanced features selectively: IQ controls and recording, and only - then consider dual VENC or stabilization. Add live audio gain/mute only - after the analog control path can be operator-verified. +4. Port recording selectively, and only then consider dual VENC or + stabilization. Add live audio gain/mute only after the analog control path + can be operator-verified. Unsupported SigmaStar-only fields remain in the common configuration schema but are marked unsupported in `/api/v1/capabilities` and rejected before mutation. This keeps the shared dashboard honest while the CV610 control surface grows feature by feature. -The pull-request CI cross-builds this experimental backend, but the production -release workflow remains limited to Star6E and Maruko until the integrated -binary passes the phase-1 device gate above. +Pull-request verification cross-builds this backend. Release promotion remains +gated on the CV610 build plus the focused device matrix documented in +`documentation/CV610_RESILIENCE_SLICES_PLAN.md`. ## Hardware verification @@ -185,9 +226,12 @@ The integrated audio path initialized on the same target, resolved the known ACODEC power-up race after its expected 100 ms retry, and produced about 100 Opus access units/s with zero reported send drops. A host receiver checked 12 consecutive RTP v2/PT98 packets: sequence deltas were 1 and 48 kHz timestamp -deltas were 480, exactly 10 ms. No microphone was connected, so acoustic -content is explicitly not operator-verified. A later service-stop hang was -localized to stale pidfile handling after an API respawn, not audio teardown; -the init-script fix requires a power-cycle and device retest. See -`documentation/CRASH_LOG.md`. Frame-SHM and long-duration soak verification -remain pending. +deltas were 960, exactly 20 ms (`CV610_AUDIO_POINT_NUM` 960; the 480/10 ms +figure predates the Opus frame-size parity fix). No microphone was connected, so acoustic +content is explicitly not operator-verified. + +On 2026-08-22 the resilience/slice branch was also confirmed through +frame-SHM at 1080p30/60/100. Slice requests 1, 3, 4, 6, 9, 12 and 17 produced +the requested VCL census; a 380-frame IDR-started 1080p60 capture decoded +cleanly with FFmpeg `-xerror`; and GDR/ENHANCE metadata, TRAIL_N rewriting and +one-second loss recovery passed. Only a longer-duration soak remains pending. diff --git a/documentation/CV610_RESILIENCE_SLICES_PLAN.md b/documentation/CV610_RESILIENCE_SLICES_PLAN.md new file mode 100644 index 00000000..0901f1ce --- /dev/null +++ b/documentation/CV610_RESILIENCE_SLICES_PLAN.md @@ -0,0 +1,232 @@ +# CV610 resilience and H.265 multi-slice plan + +Status: implemented and confirmed on CV610 and Maruko devices on 2026-08-22. + +Branch: `feature/encoder-resilience-slices`, based directly on +`origin/master` (`921b131`) so the already-squashed Star6E slice work is not +reintroduced as duplicate ancestry. + +## Objective + +Bring the existing resilience contract and whole-access-unit H.265 multi-slice +support to the CV610 backend without changing the config schema or frame-SHM +wire format. Preserve the current Star6E behavior and only expose CV610 modes +whose vendor behavior is confirmed on the device. + +The first release keeps `slice_output_en` disabled. Early per-slice delivery is +a different transport contract: the current CV610 output loop treats every +`GetStream` result as a complete access unit and advances frame-SHM/RTP state +once per result. + +## Evidence gathered + +The online CV610 bench at `192.168.2.181` was inspected and tested on 2026-08-22. +It was running Waybeam `0.65.10`, H.265 1920x1080 at 100 fps, on Linux 5.10.221. +The device's `/usr/lib/libss_mpi.so` SHA-256 was +`9ec42150a2901376a91ccd1d3f051dc721b29d1895e7a3190539cb8df4bb4e1a`. + +The shipped library exports and the running channel accepts the getter side of: + +- intra refresh; +- reference parameters; +- slice splitting; +- hierarchical QP; +- frame-loss strategy; +- super-frame discard/re-encode strategy; +- H.265 deblock and SAO controls. + +Current channel readback was: + +| Control | Current value | +|---|---| +| Intra refresh | disabled; row mode; 8 units; request-I QP 51 | +| Reference parameters | base 1; enhance 0; prediction enabled | +| Slice splitting | disabled; mode 1; size 1; early output disabled | +| Frame-loss strategy | disabled; normal mode | +| Super-frame strategy | disabled; 500,000-bit I/P/B thresholds | +| Hierarchical QP | disabled; default deltas -2/-4 | +| H.265 filtering | deblock enabled across slices; luma/chroma SAO enabled | + +`ss_mpi_venc_get_chn_capability()` reported payload mask `0x1f`, RC mask +`0x1ff`, GOP mask `0x1c7`, and a 3840x2160 maximum. This means the record lists +H.264, H.265, SVAC3, JPEG and MJPEG; all nine declared RC families; and Normal-P, +Dual-P, Smart-P, Smart-CRR, Single-SP and all-I GOPs. However, the same record +reported only 30 fps while the live channel was delivering 100 fps and its +`enable` field was false. Treat this record as a vendor capability/default +record, not as proof of the effective channel limit. Every newly used setter +still requires device validation and readback. + +## SSC338Q and CV610 divergence + +| Area | SSC338Q / Star6E | CV610 | Consequence | +|---|---|---|---| +| Waybeam maturity | Resilience, ref cadence, slice geometry, ENHANCE/GDR metadata, ROI, framing, recording and snapshot paths are implemented | Backend deliberately exposes a narrower subset | Port in small independently verifiable stages | +| Encoder API breadth | Simpler MI VENC surface; CBR/VBR/ABR/QP/AVBR families and basic I/P GOP | Nine RC families, multiple P/B/CRR GOP structures, hierarchical QP, native frame-loss and super-frame policies, SVC, QP-map, VUI/SEI and advanced analysis/tuning APIs | CV610 has more future encoder headroom | +| Current RC integration | CBR, VBR, AVBR and a QVBR policy are exposed | H.265 CBR only | Do not mix RC expansion into the resilience port | +| GDR | Implemented and device-confirmed | Row-mode setter/readback and bitstream behavior device-confirmed | Integrated with strict readback | +| Ref prediction | Implemented through base/enhance cadence and TRAIL_N rewriting | Compatible ref-param API and stream `ref_type`, now integrated; dedicated SVC APIs also exist | Keep full native SVC separate | +| Slices | Whole-AU multi-slice implemented; delivered geometry is logged | Whole-AU row splitting confirmed; one unit is a 32-pixel LCU row | Integrated with early output disabled | +| Native loss handling | Waybeam heals reference-chain-breaking output drops with paced IDRs | Additionally offers encoder-side P-skip and super-frame discard/re-encode | Experiment separately after parity | +| VUI/user data | No VUI or SEI control is currently loaded | H.265 VUI is already programmed; user-data insertion is available | CV610 is ahead here | +| Sensor envelope in this project | IMX335 modes reach 2560x1920 and up to 144 fps depending on geometry | IMX662 modes are 1080p30/60/90/100; VPSS can scale down | Star6E currently offers more spatial/high-FPS mode variety; CV610's encoder record is not the sensor limit | +| Channels | Vendor header declares 9 VENC channels; project uses main, optional record and snapshot channels | Vendor header declares 16 channels; project uses only channel 0 | CV610 has theoretical multi-channel headroom, not current feature parity | +| Early slice/low delay | SigmaStar streaming modes were rejected in prior device work; production remains frame-based | VENC slice output plus VI/VPSS low-delay APIs exist | CV610 is the better candidate for a future sub-frame-latency experiment | + +In short: CV610 has the richer vendor encoder, but SSC338Q has the richer, +device-proven Waybeam product surface today. + +## Implementation and hardware results + +The implementation derives CV610 intra-refresh, ref cadence and slice controls +in a pure mapping module, applies them between channel creation and start, and +requires exact getter readback. Runtime status exposes requested/effective GDR +settings, while startup and first-frame census logs report slice geometry. The +stream path consumes vendor `ref_type`, marks +droppable enhancement frames, rewrites copied TRAIL_R NALs to TRAIL_N, +publishes GDR cycle metadata, and requests a paced recovery IDR only when a +dropped frame breaks the reference chain. + +Confirmed on the IMX662 CV610 bench: + +| Test | Result | +|---|---| +| Resilience presets | `off`, `sprint`, `racing`, `endurance`, `patrol`, `quality`, `rescue`, `fpv`, `rally`, `range`, `ltr`, and `ltr:4` applied and read back | +| Sensor rates | GDR + 12 slices passed at 1080p30, 1080p60 and 1080p100 | +| Slice requests | 1, 3, 4, 6, 9, 12 and 17 delivered exactly the requested VCL NAL count | +| Slice geometry | 1080p uses 34 32-pixel LCU rows; request 12 -> split size 3 and 12 slices; request 17 -> split size 2 and 17 slices | +| Ref cadence | `rally` 1/1, `range`/`fpv` 1/4, `ltr` 1/1 and `ltr:4` 1/4 matched requested cadence and prediction mode | +| TRAIL_N rewrite | With 12 slices, 31 non-reference frames produced 372 rewritten NALs for `rally`; the 1/4 presets produced 144 for 12 non-reference frames | +| Frame-SHM metadata | 60 fps run: 454 frames, 450 GDR, 227 ENHANCE, zero metadata/start-code/PTS errors | +| Decoder | IDR-started 1080p60 capture decoded 380/380 frames with FFmpeg `-xerror`, no warnings or errors | +| Ring-pressure recovery | With no consumer, full-ring reference losses produced roughly one recovery IDR per second; droppable enhancement losses did not request recovery | + +All slice runs retained one whole access unit per frame-ring slot. CV610's +32-pixel row unit differs from the 64-pixel CTU geometry observed on Star6E; +the shared config contract is the requested count, while each backend reports +its delivered geometry. + +## Scope and phases + +### Phase 1: pure mappings and configuration surface + +1. Add testable CV610 mapping helpers for: + - resilience preset to `ot_venc_intra_refresh`; + - preset reference cadence to `ot_venc_ref_param`; + - requested slice count to `ot_venc_slice_split`. +2. Preserve the shared preset expansion and `video0.sliceCount` validation. +3. Add `resilience: off` and `sliceCount: 1` to the CV610 default config. +4. Remove the blanket CV610 resilience rejection. Continue rejecting a mode + individually if the device gate below fails. +5. Advertise the two fields in `/api/v1/capabilities` only when their backend + setup and status callbacks are present. + +Verification: focused host tests for all presets, disabled values, boundary +slice counts, signed/clamped inputs and 1080p row geometry; existing config/API +tests must remain green. + +### Phase 2: CV610 GDR and whole-AU slices + +1. Apply intra-refresh and slice-split after channel creation and before start. +2. Use row refresh for H.265 and read back every applied structure. A mismatch + fails channel startup rather than claiming resilience that is not active. +3. Keep `slice_output_en = false` and concatenate all packs into one access unit, + as today. +4. Store effective refresh/slice geometry in the CV610 runtime for status and + frame metadata. +5. Add CV610 intra/resilience status output. + +Device gate on `192.168.2.181`: + +- `off`, `sprint`, `racing`, `endurance` and `patrol` at 1080p30/60/100; +- slice requests 1, 3, 4, 6, 9, 12 and 17; +- setter return, getter equality, raw H.265 slice-NAL census, decoded FPS, + bitrate stability, truncation logs and IDR cadence; +- restoration of the original `/etc/waybeam.json` after the matrix. + +The delivered slice count may differ from the request because a row split must +land on the encoder's effective CTU/LCU geometry. Log both requested and +delivered geometry, as the Star6E backend does. + +### Phase 3: ref prediction and loss metadata + +1. Apply `refBase`, `refEnhance` and `refPred` through + `ss_mpi_venc_set_ref_param()`. +2. Read `stream.h265_info.ref_type` before releasing each stream. +3. Mark non-reference enhancement frames with the existing frame-SHM ENHANCE + flag and rewrite copied H.265 TRAIL_R NAL headers to TRAIL_N. +4. Publish existing GDR cycle position/length metadata. +5. Port the one-per-second recovery IDR when an output-ring loss breaks the + reference chain; do not request recovery for a confirmed droppable ENHANCE + frame. + +Device gate: + +- `rally`, `range`, `fpv`, and `ltr:N` preset/readback matrix; +- raw-ES reference-type and TRAIL_N census; +- loss injection showing that ENHANCE loss remains decodable while reference + loss triggers one paced recovery IDR; +- frame-SHM consumer confirmation of ENHANCE and GDR metadata. + +If CV610's base/enhance cadence differs materially from SigmaStar, keep the +affected presets unsupported rather than silently changing their shared names. + +### Phase 4: Maruko slice integration + +Completed on the SSC378QE/Maruko bench at `192.168.2.233`: + +1. Bound the device-aware `MI_VENC_SetH265SliceSplit` and Get ABI through the + optional Maruko loader. +2. Applied it immediately after `CreateChn`, before input-source setup and the + stab-fill early return, then verified enabled/nonzero/in-picture readback. +3. Kept `sliceCount=1` compatible with older libraries; explicit multi-slice + requests fail startup when Set/Get is unavailable or invalid. +4. Confirmed whole-AU delivery through frame-SHM with a per-frame VCL census: + 1 -> 1, 4 -> 4, 12 -> 12, 17 -> 12, and 32 -> 12 at 1280x720. Maruko + normalizes a requested one-row split to two 32-pixel rows, exposing the + CTU-64 ceiling directly in getter readback. +5. Confirmed the combination with `rally` GDR/ref-pred metadata and decoded a + cold-start 284-frame, 12-slice capture cleanly with FFmpeg. + +The test also fixed a pre-existing frame-SHM run-loop guard that failed to +recognize `frame_ring` as a valid output transport. + +### Phase 5: advanced CV610 experiments + +Keep these outside the parity implementation and evaluate separately: + +- native frame-loss P-skip strategy; +- super-frame discard/re-encode versus Waybeam's max-I/P-byte contract; +- native QVBR/CVBR/RANGEQP and non-Normal-P GOP modes; +- dedicated SVC v1/v2 and hierarchical QP; +- ROI/QP-map support; +- `slice_output_en=true` plus VI/VPSS low-delay operation. + +Each changes rate control, reference structure or transport timing enough to +need its own RF-loss, decoder and latency experiment. + +## Files expected to change + +- `config/waybeam.default.cv610.json` +- `config/waybeam.default.maruko.json` +- `include/cv610_runtime.h` or a focused new CV610 encoder-control header +- Maruko loader/config/pipeline bindings +- `src/cv610_runtime.c` +- `src/cv610_validation.c` +- `src/venc_api.c` +- focused config/mapping/API tests +- `HISTORY.md`, `VERSION`, and relevant backend/API documentation at release + +No `VencConfig` field addition and no frame-SHM layout change are required. +The coordination `protocols/frame-shm.md` producer list should include CV610; +the wire layout itself is unchanged because CV610 emits the already-defined +GDR/ENHANCE fields. + +## Completion gates + +1. `make lint SOC_BUILD=cv610` +2. CV610 cross-build with the OpenHisilicon headers and shipped firmware libs +3. `make verify` for Star6E/Maruko regressions +4. Focused CV610 device matrix above, marked **confirmed on device** +5. Maruko Set/Get, delivered-VCL and decoder matrix above +6. Coordination `/audit-protocols`, `/check-ports`, `/sync-check` +7. Protocol documentation matches the implemented producer behavior diff --git a/documentation/HTTP_API_CONTRACT.md b/documentation/HTTP_API_CONTRACT.md index e3d5a5a7..506b7ddd 100644 --- a/documentation/HTTP_API_CONTRACT.md +++ b/documentation/HTTP_API_CONTRACT.md @@ -18,7 +18,7 @@ - `read_only` — cannot be changed via API. ## Contract Version -- `contract_version`: `0.18.2` +- `contract_version`: `0.18.6` - `status`: `active` ## Governance Rules @@ -79,8 +79,8 @@ Response `200`: { "ok": true, "data": { - "app_version": "0.1.7", - "contract_version": "0.12.0", + "app_version": "0.67.0", + "contract_version": "0.18.6", "config_schema_version": "1.0.0", "backend": "star6e" } @@ -105,7 +105,7 @@ Response `200`: "sensor": { "index": -1, "mode": -1 }, "isp": { "sensorBin": "/etc/sensors/imx415_greg_fpvXVIII-gpt200.bin", "aeEngine": "sdk", "aeFps": 15, "gainMax": 0, "awbMode": "auto", "awbCt": 5500, "keepAspect": true }, "image": { "mirror": false, "flip": false, "rotate": 0 }, - "video0": { "rcMode": "cbr", "fps": 90, "size": "auto", "bitrate": 8192, "gopSize": 1.0, "qpDelta": 0, "sceneThreshold": 0, "sceneHoldoff": 2, "resilience": "off", "zoomX": 0.5, "zoomY": 0.5, "framing": "off" }, + "video0": { "rcMode": "cbr", "fps": 90, "size": "auto", "bitrate": 8192, "gopSize": 1.0, "qpDelta": 0, "sceneThreshold": 0, "sceneHoldoff": 2, "sliceCount": 1, "resilience": "off", "zoomX": 0.5, "zoomY": 0.5, "framing": "off" }, "outgoing": { "enabled": true, "server": "udp://192.168.2.20:5600", "streamMode": "rtp", "maxPayloadSize": 1400, "connectedUdp": false, "allowUnixEncoderStall": false }, "fpv": { "roiEnabled": true, "roiQp": 0, "roiSteps": 2, "roiCenter": 0.25, "noiseLevel": 0 }, "record": { "enabled": false, "mode": "off", "dir": "/tmp/sdcard", "format": "ts", "maxSeconds": 300, "maxMB": 500 }, @@ -158,6 +158,7 @@ Response `200`: "video0.size": { "mutability": "restart_required", "supported": true }, "video0.scene_threshold": { "mutability": "restart_required", "supported": true }, "video0.scene_holdoff": { "mutability": "restart_required", "supported": true }, + "video0.slice_count": { "mutability": "restart_required", "supported": true }, "video0.resilience": { "mutability": "restart_required", "supported": true }, "video0.zoom_x": { "mutability": "live", "supported": true }, "video0.zoom_y": { "mutability": "live", "supported": true }, @@ -193,6 +194,29 @@ Response `200`: ``` (truncated — all fields listed in actual response) +`video0.slice_count` / JSON `video0.sliceCount` requests 1–32 H.265 slices +per picture; 1 disables splitting. Star6E, Maruko and CV610 advertise the +field. The request is mapped to backend row geometry, so delivered counts may +quantize or saturate; startup performs vendor Set/Get verification and fails +an explicit multi-slice request when the backend cannot apply it. Slice NALs +remain one whole access unit for RTP, recording and frame-SHM. + +`data.routes` (added 0.18.4) reports which optional routes the running +backend actually services, so a client does not have to call an expensive +endpoint just to discover whether it exists: + +```json +{"ok":true,"data":{"routes":{"iq":true,"iq_import":false},"fields":{ ... }}} +``` + +| key | meaning | +|---|---| +| `iq` | `/api/v1/iq` and `/api/v1/iq/set` are serviced (the backend registers **both** `query_iq_info` and `apply_iq_param`). | +| `iq_import` | `/api/v1/iq/import` is compiled in (Star6E/Maruko only). | + +Absent `routes` means an older build: treat every route as possibly present +and fall back to calling it. + `supported` is backend-specific. Current Star6E and Maruko builds both expose scene detection, intra refresh, and digital zoom fields. @@ -754,7 +778,9 @@ Error `501`: ### `GET /api/v1/iq` -Query all ISP IQ parameter values. Always available on Star6E backend. +Query all ISP IQ parameter values. Star6E and Maruko share the SigmaStar +response shape shown below. CV610 also serves this route, using the +self-describing response documented under "CV610 IQ response shape". ```bash curl http:///api/v1/iq @@ -792,7 +818,7 @@ Multi-field example (colortrans): } ``` -Error `501` if backend doesn't support IQ (Maruko): +Error `501` when the active backend does not register an IQ query callback: ```json {"ok":false,"error":{"code":"not_implemented","message":"IQ query not available"}} ``` @@ -1216,6 +1242,72 @@ Error `409 record_active` — file is currently being written; stop recording first. Error `500 delete_failed` — filesystem error. +### `GET /api/v1/intra/status` + +Report the intra-refresh (GDR) state the encoder actually applied, as opposed +to what was requested. Served by Star6E, Maruko and CV610. + +```bash +curl http:///api/v1/intra/status +``` + +```json +{"ok":true,"data":{ + "mode":"gdr","active":true,"mi_supported":true,"apply_ok":true, + "target_ms":500,"total_rows":34, + "lines":{"requested":0,"effective":2,"clamped":false}, + "qp":{"requested":0,"effective":0}, + "gop":{"explicit_sec":0.000,"effective_sec":2.000,"auto":true}}} +``` + +| field | meaning | +|---|---| +| `mode` | resolved refresh mode name (`off`, `gdr`, …). | +| `active` | the encoder is refreshing now. | +| `mi_supported` | the vendor library exports the refresh setter. | +| `apply_ok` | the setter was called **and** read back clean. `active` with `apply_ok:false` means requested-but-not-delivered. | +| `target_ms` | intended full-refresh cycle duration. | +| `total_rows` | picture height in refresh rows. | +| `lines.requested` / `.effective` | rows per P-frame asked for vs applied; `clamped` when geometry forced a change. | +| `qp.requested` / `.effective` | refresh QP offset asked for vs applied. | +| `gop.explicit_sec` / `.effective_sec` | configured GOP vs the one in force; `auto` when derived rather than configured. | + +Always `200`. A backend with no intra-refresh support reports `mode:"off"`, +`active:false`, `mi_supported:false`. + +### `GET /api/v1/resilience/status` + +Report the resolved `video0.resilience` preset and both mechanisms it drives. +Served by Star6E, Maruko and CV610. + +```bash +curl http:///api/v1/resilience/status +``` + +```json +{"ok":true,"data":{ + "preset":"rally", + "intra":{"mode":"gdr","active":true,"mi_supported":true,"apply_ok":true, + "effective_lines":2,"effective_qp":0}, + "refPred":{"active":true,"mi_supported":true,"apply_ok":true, + "base":1,"enhance":3,"pred":true}, + "gop":{"effective_sec":2.000,"auto":true}}} +``` + +| field | meaning | +|---|---| +| `preset` | resolved `video0.resilience` value. | +| `intra.*` | the intra-refresh subset of `/api/v1/intra/status`. | +| `refPred.active` | base/enhance reference structure is in force. | +| `refPred.mi_supported` | the vendor library exports the reference-parameter setter. | +| `refPred.apply_ok` | the setter was called and read back clean. | +| `refPred.base` / `.enhance` | applied base layer and enhancement period. | +| `refPred.pred` | non-reference enhancement frames are being marked. | +| `gop.effective_sec` / `.auto` | GOP in force, and whether it was derived. | + +Always `200`. Read `apply_ok` on both mechanisms before trusting `preset`: a +preset names an intent, and only `apply_ok` says the encoder took it. + ### `GET /request/idr` Request an IDR (keyframe) from the encoder. @@ -1496,13 +1588,42 @@ Every other mode then runs at the wrong rate, scaled by the clock ratio CV610 preserves the same envelope and `selected_pad` / `selected_mode` / `pads[].modes[]` shape. Its initial IMX662 backend reports one synthetic pad containing the four supported fixed-rate modes (1080p30/60 RAW12 and -1080p90/100 RAW10); each entry has equal `min_fps` and `max_fps`, and the entry -matching `video0.fps` is marked selected. +1080p90/100 RAW10); each entry has equal `min_fps` and `max_fps`. + +`selected_pad` / `selected_mode` are what bring-up **actually selected**, not +what the config asks for — the backend publishes them once the pipeline is +resolved, so a forced `sensor.mode`, a substituted rate and a failed bring-up +are all reported honestly. Both read `-1` until bring-up completes, which in a +healthy daemon is never observable: the HTTP server starts after the backend +prepares. The `width` / `height` of a CV610 entry is what the **sensor captures**, not -what is encoded. `video0.fps` alone selects the mode — every entry captures -1920x1080 — and `video0.size` is the encoded geometry VPSS scales that capture -down to. A client must not read a mode's `width` / `height` as the stream +what is encoded. Every entry captures 1920x1080, and `video0.size` is the +encoded geometry VPSS scales that capture down to. + +**Aspect ratio is preserved by cropping, gated on `isp.keepAspect`** (default +`true`), the same rule and the same shared code Star6E and Maruko use. A +`video0.size` whose aspect differs from the capture takes a centred crop of +the capture first, then scales: `1440x1080` out of `1920x1080` uses a +1440x1080 window at x=240 and scales 1:1, so 4:3 is framed rather than +squashed. A matching aspect crops nothing. Setting `isp.keepAspect=false` +restores the plain stretch-to-fit. + +**Selecting a CV610 mode uses the same two knobs as SigmaStar.** An explicit +`sensor.mode` is an index into this list and wins outright; the mode's rate +becomes the pipeline rate and `video0.fps` is left as written. With +`sensor.mode` at `-1` (or any negative value, meaning auto) `video0.fps` is a +**target** rather than a command: an exact match is used, otherwise the +slowest mode still faster than the target, and a target above every mode +clamps to the fastest. `sensor.index` accepts only `-1` or `0` — one synthetic +pad — and anything else is `409`, as is a `sensor.mode` past the end of the +list. + +A substituted rate is announced on the daemon's log +(`Requested 45 fps, using 60 fps (sensor mode 1: 1080p60 RAW12)`) and is +visible over HTTP as `/api/v1/fps/live` disagreeing with +`/api/v1/fps/config`. Neither endpoint measures anything, so that pair states +the *intended* rate, not the delivered one. A client must not read a mode's `width` / `height` as the stream resolution — `video0.size` in `/api/v1/config` is the encoded size, and `auto` there means the mode's capture geometry. @@ -1671,8 +1792,9 @@ Behavior: ### Backend Support Matrix -Endpoints that behave the same on both backends are omitted. Only feature -divergence is listed. As of `contract_version: 0.12.1`: +Endpoints that behave the same on all three backends are omitted. The table +compares the two SigmaStar implementations; CV610 differences are called out +in Notes. As of `contract_version: 0.18.6`: | Feature / Endpoint | Star6E | Maruko | Notes | |---|---|---|---| @@ -1683,8 +1805,8 @@ divergence is listed. As of `contract_version: 0.12.1`: | `/api/v1/audio/status` | yes | yes | Both backends register `query_audio_status`. | | `/api/v1/dual/status`, `/dual/idr` | yes | yes | `/dual/status` always 200 (`active:false` when off, `active:true,channel,bitrate,fps,gop` when on). `/dual/idr` returns 200 when active, 404 when not. Maruko HTTP registration landed in 0.10.4 — earlier Maruko builds returned 404 from these even when `record.mode=dual` was running. | | `/api/v1/dual/set` | yes | **501** | Star6E-only: the underlying `MI_VENC_*ChnAttr` write path binds to `i6_venc_chn`, but Maruko's venc library expects `i6c_venc_chn` (different layout). Maruko returns 501 until the call path is ported. | -| `/api/v1/iq` and `/api/v1/iq/set` | full (≈45 params) | full (parity in `maruko_iq.c`) | Both backends use the same IQ table schema. | -| `/api/v1/awb` | live | live | Both backends register `query_awb_info`. | +| `/api/v1/iq` and `/api/v1/iq/set` | full (≈45 params) | full (parity in `maruko_iq.c`) | Star6E/Maruko share one IQ table schema. **CV610 also serves these from 0.18.4, in a DIFFERENT shape** — see "CV610 IQ response shape" below. `/api/v1/iq/import` stays Star6E/Maruko-only and 501s on CV610 (advertised as `routes.iq_import:false`). | +| `/api/v1/awb` | live | live | Both backends register `query_awb_info`. CV610: **501**. | | `/api/v1/ae` | live + `runtime.active_precrop` | live + `runtime.active_precrop` | Both backends now include `runtime.active_precrop` in the AE response (Maruko parity landed in `0.8.4`). | | `/api/v1/transport/status` | yes | yes | SHM-ring fields are shown when `outgoing.server=shm://`; otherwise the UDP/Unix subset. | | `/api/v1/idr/stats` | yes | yes | Identical schema; values reflect each backend's IDR rate-limit. | @@ -1693,10 +1815,71 @@ divergence is listed. As of `contract_version: 0.12.1`: | `video0.framing` / `zoom_x` / `zoom_y` | yes | partial | `framing` requires reinit; zoom presets work on both backends, the `stab` preset is Star6E-only (no-op on Maruko); `zoom_x/y` are live pan controls (ignored under `stab`). | | `detect.model_path` / `model_id` / `conf_thresh` / `nms_iou` | **live** | **live** | Both backends hot-swap the NPU detector on the pipeline thread without respawning video. Star6E uses VPE port 1; Maruko uses SCL port 3 and its drain-while-disable teardown. A model whose reported input geometry disagrees with the configured tap is refused and leaves detection off. | | `detect.net_width` / `net_height` | restart | restart | Tap geometry is fixed when the VPE/SCL detector port is created. | -| `video0.min_qp` / `max_qp` | live | **501** | Star6E-only RC QP bounds; Maruko capabilities report these fields unsupported. | +| `video0.min_qp` / `max_qp` | live | **501** | RC QP bounds. Star6E live; Maruko reports unsupported. **CV610 live from 0.18.4** (`cv610_apply_qp_bounds`, applied live and at startup); it sets the P bounds and the I-frame ceiling, leaving the I-frame floor to `video0.qp_delta`. | | `isp.aeEngine` ("sdk" only) | applied | applied | Unified AE selector landed in 0.10.13. `custom` (userspace AE governor) is RETIRED — Maruko in 0.22.0, Star6E in 0.47.0 — and the value was **removed** in 0.47.0. `sdk` is the only accepted value; any other (e.g. a stale `custom`) warns and falls back to `sdk`. Both backends run the SDK firmware/bin AE for convergence plus a supervisory thread that enforces the `isp.gain*`/`isp.shutter*` limits. | ## Change Log (Contract) +- `0.18.6` (documentation + correctness; no shipped response changes): + `GET /api/v1/intra/status` and `GET /api/v1/resilience/status` are now + documented — both have been served for several releases and the CV610 + branch added in 0.18.5 made them report live device state, but neither had + a contract entry. `data.routes.iq` now requires the backend to register + **both** `query_iq_info` and `apply_iq_param`, matching its documented + meaning that `/api/v1/iq` *and* `/api/v1/iq/set` are serviced; every + shipped backend registers both, so no response changes. +- `0.18.5` (additive — resilience and slices reach three-backend parity): + CV610 now advertises `video0.resilience` and `video0.slice_count` and serves + the existing intra/resilience status routes. Maruko now advertises and + applies `video0.slice_count`. Explicit multi-slice requests use pre-start + vendor Set/Get verification on all three backends; no field or response key + was removed. +- `0.18.4` (additive — CV610 gains the IQ surface and RC QP bounds): + `/api/v1/capabilities` gains `data.routes` (`iq`, `iq_import`) so a client can + discover optional routes without calling them. `/api/v1/iq` and + `/api/v1/iq/set` go from 501 to live on CV610, in a second response shape + documented under "CV610 IQ response shape" — group-keyed, self-describing via + `_schema`, and rejecting out-of-range values rather than clamping. + `video0.min_qp` / `video0.max_qp` become live on CV610. No field was removed + and no existing response key changed, so 0.18.3 clients keep working. +- `0.18.3` (additive — CV610 sensor-mode selection reaches SigmaStar parity): + - **`sensor.index` and `sensor.mode` are now supported on CV610**, both + `restart_required`, the same `mutability` the shared table gives them on + Star6E and Maruko. They parsed before but were read by nothing, so + `/api/v1/set` answered `409` for a field the config file carried. A + client that renders sensor controls from `/api/v1/capabilities` now gets + the same surface on all three backends. + - **`video0.fps` is a target on CV610, not a command.** With `sensor.mode` + auto, an exact match is used, otherwise the slowest mode still faster + than the target, and a target above every mode clamps to the fastest. + Rates that are not in the table were `409` before and are now honoured + with a substitution — see `/api/v1/modes`. `video0.fps=0` remains `409`. + - **`/api/v1/modes` reports the achieved selection.** `selected_pad` / + `selected_mode` were recomputed from `video0.fps` per request, so they + described the configured mode even when another one was running. They are + now published by the backend at bring-up, and read `-1` before it + completes. Shape unchanged. + - **`isp.keepAspect` is now supported on CV610** (`restart_required`), and + a non-native `video0.size` is centre-cropped before scaling instead of + stretched. The field was in the config file and defaulted `true`, but + CV610 advertised no `isp.*` field and read none, so it was a knob that + did nothing — `1440x1080` validated and then squashed 16:9 into 4:3. + CV610 now calls the same `pipeline_common_compute_precrop()` Star6E and + Maruko use. No shape changed and no request that used to succeed now + fails; the pixels are different. + - **CV610 now runs the shared field validation at config load**, which it + had been skipping entirely: `venc_api_validate_loaded_config()` dispatched + to the CV610 backend validator *instead of* the shared + `validate_field_cfg()` sweep, so sixteen shared rules never ran on that + backend. The HTTP `/api/v1/set` path always applied them, so the same + value was accepted from `/etc/waybeam.json` at boot and rejected with + `409` over HTTP. A CV610 config carrying e.g. `isp.awbMode:"bogus"` used + to load and now fails with the same message Star6E gives. Configs that + were valid on Star6E are unaffected. + - `video0.gopSize` is validated against the **selected** mode's rate. The + encoder has always derived its GOP length from that rate; the check used + `video0.fps`, which the two knobs above can now separate from it. A + `gopSize` that was accepted and then exceeded the encoder's 65536-frame + limit is now rejected at `409`. - `0.18.2` (additive — CV610 `video0.size` becomes a real control): - **`video0.size` on CV610 now accepts any geometry the mode can be scaled down to**, not just the capture size. VI has no scaler, so the backend @@ -2056,3 +2239,34 @@ divergence is listed. As of `contract_version: 0.12.1`: - Updated examples to use `video.capture_resolution` restart semantics. - `0.1.0`: - Initial draft contract and endpoint definitions. + + +## CV610 IQ response shape (0.18.4) + +`/api/v1/iq` on CV610 is a **second, structurally different form** from the +Star6E/Maruko one documented above. A client written against that shape reads +`data["contrast"].value` and gets `undefined` on CV610 — branch on +`data._schema` being present, not on backend name. + +```json +{"ok":true,"data":{ + "_schema":[{"name":"saturation","fields":[ + {"name":"manual.saturation","count":1,"min":0,"max":255,"domain":"manual"}]}], + "saturation":{"ret":0,"fields":{"op_type":0,"manual.saturation":128}}, + "module_ctrl":{"ret":0,"bypass":{"drc":1,"dehaze":1}}}} +``` + +- Keyed by ISP **group**, not by parameter. Each group has `ret` (the MPI + return, 0 on success) and `fields`, whose keys are dotted field names. +- No `value`, `enabled`, `op_type` or `available` at group level, and no + `_diag` block. +- `_schema` describes the whole surface — name, element `count`, `min`/`max`, + and `domain` (`direct` | `manual` | `auto`). The WebUI renders from it, so + the field table lives only in the backend. +- `domain` is load-bearing: writing a `manual.*` or `auto.*` field also selects + that `op_type`, because a value in the other half is ignored by the ISP and + an ignored write is indistinguishable from a broken setter. +- `module_ctrl` is read-only and reports which ISP blocks the hardware is + bypassing. +- Values out of a field's declared range are **rejected**, not clamped, so the + value echoed by `/api/v1/iq/set` is the value applied. diff --git a/documentation/README.md b/documentation/README.md index ffba34cd..794964d7 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -3,6 +3,12 @@ This folder is the canonical place for waybeam_venc project documentation. ## Core Docs +- `documentation/SSC338Q_CV610_ENCODER_CAPABILITIES.md` + - Evidence-tiered comparison of the two encoder APIs and their current + Waybeam integration, including the richer CV610-only future surface. +- `documentation/CV610_RESILIENCE_SLICES_PLAN.md` + - Approved phased plan and device gates for CV610 resilience, ref prediction, + frame metadata and whole-access-unit H.265 slicing. - `documentation/DUAL_BACKEND_SPLIT_PLAN.md` - Current architecture/implementation plan for Star6E + Maruko targeted builds. - Tracks only remaining implementation steps from the current stable baseline. diff --git a/documentation/SSC338Q_CV610_ENCODER_CAPABILITIES.md b/documentation/SSC338Q_CV610_ENCODER_CAPABILITIES.md new file mode 100644 index 00000000..1ac18639 --- /dev/null +++ b/documentation/SSC338Q_CV610_ENCODER_CAPABILITIES.md @@ -0,0 +1,117 @@ +# SSC338Q and CV610 encoder capability delta + +This note distinguishes three different meanings of "supported": + +1. **Declared** — present in the vendor header or exported runtime ABI. +2. **Accepted** — a getter/setter succeeds on the running device. +3. **Integrated** — Waybeam configures it, reports it honestly, transports the + result correctly, and has device-level regression coverage. + +Confusing these levels is particularly risky on CV610. Its capability record +advertises a broad encoder, but on the 2026-08-22 bench it reported a 30 fps +limit while the same channel was actively delivering 1080p100. Vendor capability +records are useful discovery hints, not substitutes for apply/readback and +bitstream tests. + +## Executive summary + +CV610 has the richer raw encoder API. SSC338Q currently has the richer and more +mature Waybeam product integration. + +CV610 exposes native controls for nine RC families, six useful GOP structures, +hierarchical QP, reference prediction, SVC, frame-loss P-skip, super-frame +discard/re-encode, ROI/QP maps, VUI/SEI, analysis statistics, and early slice +delivery. SSC338Q's MI VENC surface is smaller, but Waybeam already integrates +and device-verifies resilience presets, reference-layer metadata, multi-slice +whole-access-unit output, ROI, recording, snapshots, and dynamic framing there. + +## Evidence + +The CV610 bench at `192.168.2.181` was inspected and tested on 2026-08-22: + +- Waybeam `0.65.10`, H.265 1920x1080 at 100 fps; +- Linux 5.10.221 on armv7l; +- `/usr/lib/libss_mpi.so` SHA-256 + `9ec42150a2901376a91ccd1d3f051dc721b29d1895e7a3190539cb8df4bb4e1a`; +- getter calls succeeded for intra refresh, ref parameters, slice split, + hierarchical QP, frame-loss strategy, super-frame strategy, H.265 deblock, + and SAO. + +The parity controls were then applied with strict readback. GDR and 12-slice +whole-access-unit output passed at 1080p30/60/100; requests for 1, 3, 4, 6, 9, +12 and 17 slices delivered those exact VCL NAL counts. The `rally`, `range`, +`fpv`, `ltr`, and `ltr:4` reference cadences matched vendor `ref_type` output, +and a 380-frame IDR-started 1080p60 capture decoded cleanly with FFmpeg +`-xerror`. These controls are therefore **Integrated**, not merely Declared. + +The same shared slice contract is now also integrated on SSC378QE/Maruko. Its +SigmaStar ABI adds a VENC device argument but uses the same 8-byte enable/row +structure and the same pre-start lifecycle. Hardware readback exposed one +useful divergence: Maruko normalizes a requested one-32-pixel-row split to two +rows (one CTU-64). At 1280x720, requests 1/4/12 delivered 1/4/12 slices, while +17 and 32 saturated at 12. A `rally` run preserved whole-AU frame-SHM metadata +and exact VCL counts; its cold-start capture decoded cleanly. + +## Local validation samples + +The device never stores encoded captures. The frame-SHM consumer writes to a +FIFO and SSH carries the elementary stream directly into host FFmpeg. These +workspace-local `bench/` artifacts are intentionally gitignored rather than +release assets; the checksums make the evidence identifiable in this session. + +| Backend | Host artifact | Evidence | +|---|---|---| +| CV610 | `bench/cv610-rally-slice12-1080p60.mp4` | 380 frames, 6.33 s, 1920x1080@60, SHA-256 `58eca88af6e753ef8a2ff90b2210a02acde2f955384d08eeb1941bc4e26a7759` | +| Maruko | `bench/maruko-rally-slice12-720p30.mp4` | 284 frames, 9.47 s, 1280x720@30, SHA-256 `355710cfc44f59d8944f131a517787d45ccf1aef8dd07cf7b1dac07583806cb8` | + +Both samples start at an IDR and decode without FFmpeg warnings or errors. + +The channel capability record returned: + +| Record | Value | Interpretation | +|---|---:|---| +| Payload mask | `0x1f` | H.264, H.265, SVAC3, JPEG and MJPEG declared | +| RC mask | `0x1ff` | ABR, CBR, VBR, AVBR, QVBR, CVBR, FIXQP, QPMAP and RANGEQP declared | +| GOP mask | `0x1c7` | Normal-P, Dual-P, Smart-P, Smart-CRR, Single-SP and all-I declared | +| Maximum picture | 3840x2160 | Encoder record; the integrated IMX662 path is 1920x1080 | +| Feature enable | false | The returned structure behaves as a default/capability record | + +## Detailed delta + +| Area | SSC338Q / Star6E | CV610 | Current decision | +|---|---|---|---| +| Payloads | Vendor surface includes H.264/H.265/MJPEG; Waybeam uses H.265 | Header/capability record also includes SVAC3 and JPEG | Keep H.265 parity scope | +| Rate control | CBR, VBR, AVBR and Waybeam's QVBR policy integrated | Nine native RC families declared; only H.265 CBR integrated | RC expansion is separate work | +| GOP structures | Basic I/P GOP used | Normal/Dual/Smart P, CRR, Single-SP and all-I declared; B modes exist in headers but were absent from the device mask | Use Normal-P for parity | +| GDR | Integrated and device-confirmed | Row GDR integrated and confirmed at 1080p30/60/100 with strict readback | Keep column refresh outside the shared contract | +| Ref prediction | Base/enhance cadence, TRAIL_N propagation and ENHANCE metadata integrated | Equivalent ref cadence, TRAIL_N rewrite and metadata now integrated and device-confirmed; fuller SVC API also exported | Leave native SVC gated | +| Slices | Whole-AU slicing and delivered CTU geometry integrated | Whole-AU 32-pixel-row splitting integrated; requests through 17 confirmed; early-slice output also represented | Keep early output off | +| Loss handling | Output-ring chain breaks trigger paced recovery IDRs | Also exposes native P-skip and super-frame discard/re-encode | Preserve parity policy; experiment with native loss controls later | +| QP tools | I/P delta, bounds and frame-size caps integrated | Adds hierarchical QP, QP maps, foreground protection, skip bias and quality balance APIs | Do not bundle unverified tools | +| ROI | Eight horizontal delta-QP bands integrated | Eight ROI regions, extended per-frame ROI, background-rate and QP-map APIs | A future CV610 parity opportunity | +| VUI/user data | No MI VUI/user-data wrapper loaded | H.265 VUI already programmed; user-data insertion exported | CV610 is already richer here | +| H.265 tools | Encoder defaults plus resilience/slices | Deblock, SAO, transform, entropy, CU prediction, search window, deblur and motion-stat controls exported | Documented future tuning surface | +| Low delay | SigmaStar stream modes were rejected in prior device tests; production is frame-based | Slice-output plus VI/VPSS low-delay APIs exist | Best candidate for a later sub-frame experiment, requiring transport redesign | +| Channels | Header declares 9; project uses main, optional record and snapshot channels | Header declares 16; project uses channel 0 | Theoretical CV610 headroom only | +| Sensor envelope here | IMX335 combinations reach 2560x1920 and up to 144 fps | IMX662 modes are 1080p30/60/90/100, with VPSS downscale | Star6E currently offers the broader integrated mode set | + +## CV610 controls deliberately deferred + +The following are real ABI opportunities, but none should be advertised merely +because a symbol exists: + +- native QVBR/CVBR/RANGEQP and alternative GOP structures; +- P-skip frame-loss strategy and super-frame discard/re-encode; +- SVC v1/v2, hierarchical QP and per-frame SVC masks; +- ROI/QP-map, foreground protection, skip bias and quality balance; +- advanced deblur, motion analysis, CU/search-window tuning; +- early slice delivery with VI/VPSS low-delay mode. + +Each requires setter/readback verification plus bitrate, decoder, reference-chain, +RF-loss and latency measurements. Early slice delivery additionally changes the +current one-`GetStream`-result-per-access-unit assumption in RTP and frame-SHM. + +## Related implementation plan + +See `documentation/CV610_RESILIENCE_SLICES_PLAN.md` for the phased parity port, +device matrix, rollback rules and completion gates. diff --git a/include/cv610_encoder_config.h b/include/cv610_encoder_config.h new file mode 100644 index 00000000..9c07d078 --- /dev/null +++ b/include/cv610_encoder_config.h @@ -0,0 +1,50 @@ +#ifndef CV610_ENCODER_CONFIG_H +#define CV610_ENCODER_CONFIG_H + +#include "intra_refresh.h" +#include "venc_config.h" + +#include + +/* The CV610 getter reports split_mode=1 for its H.265 row-split default. + * OpenHisilicon does not publish a named enum for this field. Keep the raw + * value isolated here and verify it by setter/readback plus slice-NAL census. */ +#define CV610_SLICE_SPLIT_MODE_LCU_ROW 1u + +typedef struct { + IntraRefreshDerived derived; + uint32_t enabled; + uint32_t mode; /* 0 = OT_VENC_INTRA_REFRESH_ROW */ + uint32_t refresh_num; + uint32_t request_i_qp; +} Cv610IntraConfig; + +typedef struct { + uint32_t enabled; + uint32_t base; + uint32_t enhance; + uint32_t pred; +} Cv610RefConfig; + +typedef struct { + uint32_t enabled; + uint32_t requested_count; + uint32_t total_lcu_rows; + uint32_t split_mode; + uint32_t split_size; + uint32_t expected_count; +} Cv610SliceConfig; + +typedef struct { + Cv610IntraConfig intra; + Cv610RefConfig ref; + Cv610SliceConfig slice; +} Cv610EncoderConfig; + +/* Pure mapping from the shared config to CV610 encoder concepts. Vendor + * structs are intentionally filled in cv610_runtime.c so this logic remains + * host-testable without the external OpenHisilicon headers. */ +int cv610_encoder_config_derive(const VencConfig *cfg, uint32_t height, + uint32_t fps, Cv610EncoderConfig *out); + +#endif /* CV610_ENCODER_CONFIG_H */ diff --git a/include/cv610_iq.h b/include/cv610_iq.h new file mode 100644 index 00000000..4923ba38 --- /dev/null +++ b/include/cv610_iq.h @@ -0,0 +1,37 @@ +#ifndef CV610_IQ_H +#define CV610_IQ_H + +/* Runtime IQ control for the Hi3516CV610 ISP. + * + * PR #229 seeded this ISP through the IMX662 sensor plugin's + * cmos_get_isp_default(), which the ISP reads once at pipe start. This + * module exposes the same blocks as live knobs, so a value can be corrected + * without a cross-compile and a reboot. + * + * Unlike star6e_iq.c there is no dlopen: the CV610 backend links ss_mpi + * directly, so the attribute structs are the SDK's own types and the field + * table is built from offsetof() rather than hand-computed offsets. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Query every exposed IQ group. + * Returns malloc'd JSON, caller frees. NULL when the ISP is not running. + * Values are read back from the ISP, not cached, so a rejected set shows. */ +char *cv610_iq_query(void); + +/** Set one IQ field. + * `param` is "." using the names cv610_iq_query() emits; + * `value` is a decimal integer, or a comma-separated list for arrays. + * Writing a field under manual_attr also forces that group's op_type to + * manual — otherwise the ISP keeps running its auto curve and the set has + * no visible effect. + * Returns 0 on success, -1 on unknown name, bad value, or an MPI error. */ +int cv610_iq_set(const char *param, const char *value); + +#ifdef __cplusplus +} +#endif + +#endif /* CV610_IQ_H */ diff --git a/include/cv610_modes.h b/include/cv610_modes.h index d1c3acd6..e05f6ffe 100644 --- a/include/cv610_modes.h +++ b/include/cv610_modes.h @@ -33,6 +33,29 @@ const Cv610SensorMode *cv610_mode_table(size_t *count); * different capture. */ const Cv610SensorMode *cv610_mode_for_fps(uint32_t fps); +/* Resolve sensor.mode + video0.fps to one mode, the way SigmaStar's + * sensor_select() resolves sensor.mode + video0.fps against MI_SNR_GetRes(): + * an explicit index wins and must exist, otherwise the frame rate is a TARGET + * rather than a command and the closest usable mode is chosen. + * + * forced_mode >= 0 that index, or NULL when the table has no such index + * forced_mode < 0 exact rate if the table has it; else the slowest mode + * still faster than the target; else the fastest mode + * target_fps == 0 NULL — nothing to select against + * + * The last auto case is a deliberate divergence. SigmaStar's tie-break + * (sensor_select.c sensor_mode_cost) scores fps_excess at 0 for every mode + * BELOW the target, so a target above them all falls back to table order — + * the slowest mode. That rarely fires there because its modes carry min-max + * fps ranges; on this point-fps table it would fire constantly, and answering + * "100" to a request for "120" is what the operator meant. + * + * *out_index (optional) receives the table index, or -1 when NULL is returned. + * A caller that acts on the result must report a substituted rate: the sensor + * runs at the MODE's rate, not the requested one. */ +const Cv610SensorMode *cv610_mode_select(int forced_mode, uint32_t target_fps, + int *out_index); + /* Whether an encoded geometry can be produced from this mode. Returns NULL * when it can, or a static reason string. A zero width AND height mean * "the mode's own size" and always pass. */ diff --git a/include/cv610_pipeline.h b/include/cv610_pipeline.h index 11edd333..67b20805 100644 --- a/include/cv610_pipeline.h +++ b/include/cv610_pipeline.h @@ -11,6 +11,10 @@ typedef struct { * the capture size unless video0.size asks for something smaller. */ uint32_t out_width; uint32_t out_height; + /* isp.keepAspect: centre-crop the capture to the encoded aspect ratio + * before scaling, so a 4:3 video0.size out of a 16:9 sensor is framed + * rather than squashed. Same rule Star6E and Maruko apply. */ + int keep_aspect; uint32_t fps; int lanes; int data_rate_x2; @@ -33,4 +37,9 @@ void cv610_pipeline_stop(void); void cv610_pipeline_request_stop(void); int cv610_pipeline_stop_requested(void); +/* Nonzero once ss_mpi_isp_run() is up, so callers outside this file know the + * ISP will answer an ss_mpi_isp_* attribute call. Used by cv610_iq.c to + * refuse rather than fire MPI ioctls at an ISP that was never inited. */ +int cv610_pipeline_isp_ready(void); + #endif /* CV610_PIPELINE_H */ diff --git a/include/cv610_runtime.h b/include/cv610_runtime.h index 72dc32f2..64bf2ba8 100644 --- a/include/cv610_runtime.h +++ b/include/cv610_runtime.h @@ -3,6 +3,36 @@ #include "backend.h" +#include + +typedef struct { + char mode_name[16]; + int active; + int mi_supported; /* Kept for status-JSON parity; means MPP API present. */ + int apply_ok; + uint32_t target_ms; + uint32_t total_rows; + uint32_t requested_lines; + uint32_t effective_lines_per_p; + int lines_clamped; + uint32_t requested_qp; + uint32_t effective_qp; + double explicit_gop_sec; + double effective_gop_sec; + int gop_auto; +} Cv610IntraRefreshStatus; + +typedef struct { + int active; + int mi_supported; /* Kept for status-JSON parity; means MPP API present. */ + int apply_ok; + uint32_t base; + uint32_t enhance; + int pred; +} Cv610RefPredStatus; + const BackendOps *cv610_runtime_backend_ops(void); +void cv610_runtime_intra_refresh_status(Cv610IntraRefreshStatus *out); +void cv610_runtime_ref_pred_status(Cv610RefPredStatus *out); #endif /* CV610_RUNTIME_H */ diff --git a/include/h26x_util.h b/include/h26x_util.h index bb92f3ce..66716458 100644 --- a/include/h26x_util.h +++ b/include/h26x_util.h @@ -21,4 +21,11 @@ uint8_t h26x_util_hevc_nalu_type(const uint8_t *data, size_t len); int h26x_util_annexb_next(const uint8_t *data, size_t len, size_t *cursor, const uint8_t **nal, size_t *nal_len); +/** Rewrite every single-layer HEVC TRAIL_R NAL (type 1) in an Annex-B access + * unit to TRAIL_N (type 0). Returns the number of NAL headers changed. This + * propagates an encoder's non-reference frame designation to generic decoders; + * callers must only use it when vendor frame metadata says the whole picture + * is not used for reference. */ +size_t h26x_util_hevc_patch_trail_r_to_n(uint8_t *data, size_t len); + #endif /* H26X_UTIL_H */ diff --git a/include/maruko_bindings.h b/include/maruko_bindings.h index 7e7f365b..8a8d99a8 100644 --- a/include/maruko_bindings.h +++ b/include/maruko_bindings.h @@ -86,6 +86,10 @@ typedef int (*maruko_isp_disable_userspace3a_fn_t)(MI_U32 dev_id, MI_U32 channel g_mi_venc.fnSetRefParam((dev), (chn), (p)) #define maruko_mi_venc_get_ref_param(dev, chn, p) \ g_mi_venc.fnGetRefParam((dev), (chn), (p)) +#define maruko_mi_venc_set_h265_slice_split(dev, chn, p) \ + g_mi_venc.fnSetH265SliceSplit((dev), (chn), (p)) +#define maruko_mi_venc_get_h265_slice_split(dev, chn, p) \ + g_mi_venc.fnGetH265SliceSplit((dev), (chn), (p)) #define maruko_mi_sys_config_private_pool(soc, cfg) \ g_mi_sys.fnConfigPrivateMMAPool((soc), (cfg)) diff --git a/include/maruko_config.h b/include/maruko_config.h index 9b24e958..a198b638 100644 --- a/include/maruko_config.h +++ b/include/maruko_config.h @@ -68,6 +68,8 @@ typedef struct { uint8_t ref_base; uint8_t ref_enhance; uint8_t ref_pred; + /* Requested whole-access-unit H.265 slice count. 1 disables splitting. */ + uint32_t slice_count; /* Resilience preset name — mirror of video0.resilience. Used by * the debug OSD; pipeline behaviour is fully determined by the * already-expanded intra_refresh_* / ref_* fields above. */ diff --git a/include/maruko_controls.h b/include/maruko_controls.h index 3c875810..519e75c0 100644 --- a/include/maruko_controls.h +++ b/include/maruko_controls.h @@ -22,7 +22,7 @@ const VencConfig *maruko_controls_vcfg(void); * thread. The HTTP callback only posts a coherent config snapshot. */ void maruko_controls_service_detect_reload(void); -/** Publish the frame-shm ring-fill clamp factor (permille, 250..1000) and +/** Publish the frame-shm ring-fill clamp factor (permille, 50..1000) and * re-program the encoder from the configured bitrate scaled by it. Mirrors * star6e_controls_set_output_throttle; video0.bitrate is never written. */ int maruko_controls_set_output_throttle(uint16_t permille); diff --git a/include/maruko_mi.h b/include/maruko_mi.h index 0e2d35a2..fcc8e1e9 100644 --- a/include/maruko_mi.h +++ b/include/maruko_mi.h @@ -134,6 +134,8 @@ typedef struct { int (*fnGetIntraRefresh)(int dev, int chn, void *cfg); int (*fnSetRefParam)(int dev, int chn, void *p); int (*fnGetRefParam)(int dev, int chn, void *p); + int (*fnSetH265SliceSplit)(int dev, int chn, void *p); + int (*fnGetH265SliceSplit)(int dev, int chn, void *p); } maruko_venc_impl; /* MI_AI (audio input) — i6c surface differs from Star6E: diff --git a/include/maruko_output.h b/include/maruko_output.h index 88b45e43..f80f93b6 100644 --- a/include/maruko_output.h +++ b/include/maruko_output.h @@ -101,9 +101,17 @@ typedef struct { * there. A full ring discards an already-encoded frame, so the * reference chain breaks until the next IDR; the producer is the only * party that knows instantly, so it re-establishes locally rather than - * waiting for a ground RecoveryRequest over RF. */ - void (*request_idr)(void *ctx); + * waiting for a ground RecoveryRequest over RF. Paced by + * venc_frame_drop_idr_due() (1 s holdoff, state below) so a + * consumer-less ring does not become an IDR storm. Returns 1 when + * issued, 0 when the shared 100 ms limiter swallowed it — the caller + * rolls the holdoff back so the next drop retries. */ + int (*request_idr)(void *ctx); void *idr_ctx; + uint64_t drop_idr_last_us; + /* One WARN per init when packet metadata is incomplete or invalid (frame + * aborted, never shipped truncated). */ + uint8_t trunc_warned; } MarukoOutput; /** Initialize UDP or Unix socket output from a parsed URI. */ diff --git a/include/maruko_video.h b/include/maruko_video.h index 306ec0fa..5aa70bcd 100644 --- a/include/maruko_video.h +++ b/include/maruko_video.h @@ -23,6 +23,17 @@ typedef RtpSessionState MarukoRtpState; void maruko_video_init_rtp_state(MarukoRtpState *rtp, PAYLOAD_TYPE_E codec, uint32_t sensor_fps); +/** Return non-zero when every vendor pack exposes descriptors for all of its + * NAL units. The i6c ABI has a fixed-size packetInfo table; callers must drop + * the whole access unit rather than silently emit only the table prefix. */ +int maruko_video_stream_packet_info_complete(const i6c_venc_strm *stream); + +/** Reject an incomplete access unit before any consumer sees it. Returns 1 + * when rejected, emits a one-time warning, and requests paced recovery when + * the dropped picture participates in the reference chain. */ +int maruko_video_reject_incomplete_access_unit(const i6c_venc_strm *stream, + MarukoOutput *output); + /** Packetize and send one encoder frame over RTP. * If stats is non-NULL and the stream is H.265 in RTP mode, per-frame * packetizer counters are accumulated into *stats. */ diff --git a/include/rtp_sidecar.h b/include/rtp_sidecar.h index 2873cde2..c65fe037 100644 --- a/include/rtp_sidecar.h +++ b/include/rtp_sidecar.h @@ -177,7 +177,7 @@ typedef struct { uint8_t fill_pct; /* output queue fill: 0..100 */ uint8_t in_pressure; /* 1 = pressure hysteresis flag asserted */ uint16_t throttle_permille; /* frame-shm ring-fill bitrate clamp: - * 1000 = unclamped, 250 = floor. Carved + * 1000 = unclamped, 50 = minimum. Carved * from the old _pad[2] in 0.57.0, so the * trailer is still 16 bytes and every * later trailer keeps its offset. A diff --git a/include/star6e.h b/include/star6e.h index 85ab975e..bca5d8ab 100644 --- a/include/star6e.h +++ b/include/star6e.h @@ -492,6 +492,19 @@ typedef struct { _Static_assert(sizeof(MI_VENC_ParamRef_t) == 12, "MI_VENC_ParamRef_t layout changed — verify SDK match"); +/* H.265 multi-slice split (mi_venc_datatype.h:558) — u32SliceRowCount is + * 32-px rows PER SLICE, not a slice count, and NOT CTU rows: the encoder's + * CTU is 64 (measured 2026-08-20, SPS 30x17 CTBs at 1080p) and the SDK + * rounds the request up to whole CTU-64 rows. Symbol is exported by both + * star6e and maruko libmi_venc.so; Maruko adds VeDev and therefore binds it + * through its backend-specific loader. */ +typedef struct { + MI_BOOL bSplitEnable; + MI_U32 u32SliceRowCount; +} MI_VENC_ParamH265SliceSplit_t; +_Static_assert(sizeof(MI_VENC_ParamH265SliceSplit_t) == 8, + "MI_VENC_ParamH265SliceSplit_t layout changed — verify SDK match"); + /* MI_VENC ----------------------------------------------------------------- */ #if defined(PLATFORM_MARUKO) #define MI_VENC_CreateChn(chn, attr) g_mi_venc.fnCreateChn(0, (chn), (attr)) @@ -548,6 +561,12 @@ _Static_assert(sizeof(MI_VENC_ParamRef_t) == 12, #define MI_VENC_GetRefParam(chn, p) \ (g_mi_venc.fnGetRefParam ? \ g_mi_venc.fnGetRefParam((chn), (p)) : -1) +#define MI_VENC_SetH265SliceSplit(chn, p) \ + (g_mi_venc.fnSetH265SliceSplit ? \ + g_mi_venc.fnSetH265SliceSplit((chn), (p)) : -1) +#define MI_VENC_GetH265SliceSplit(chn, p) \ + (g_mi_venc.fnGetH265SliceSplit ? \ + g_mi_venc.fnGetH265SliceSplit((chn), (p)) : -1) #else MI_S32 MI_VENC_CreateChn(MI_VENC_CHN chn, MI_VENC_ChnAttr_t* attr); MI_S32 MI_VENC_DestroyChn(MI_VENC_CHN chn); diff --git a/include/star6e_controls.h b/include/star6e_controls.h index ad8ac951..7d45e822 100644 --- a/include/star6e_controls.h +++ b/include/star6e_controls.h @@ -20,7 +20,7 @@ const VencApplyCallbacks *star6e_controls_callbacks(void); /** Apply frame rate change to running encoder pipeline. */ int star6e_controls_apply_fps(uint32_t fps); -/** Publish the frame-shm ring-fill clamp factor (permille, 250..1000) and +/** Publish the frame-shm ring-fill clamp factor (permille, 50..1000) and * re-program the encoder from the configured bitrate scaled by it. * video0.bitrate is never written — see include/venc_shm_throttle.h for * why the clamp deliberately does not take ownership of the rate. diff --git a/include/star6e_mi.h b/include/star6e_mi.h index 35925973..928a290c 100644 --- a/include/star6e_mi.h +++ b/include/star6e_mi.h @@ -99,6 +99,8 @@ typedef struct { int (*fnGetIntraRefresh)(int chn, void *cfg); int (*fnSetRefParam)(int chn, void *p); int (*fnGetRefParam)(int chn, void *p); + int (*fnSetH265SliceSplit)(int chn, void *p); + int (*fnGetH265SliceSplit)(int chn, void *p); } star6e_venc_impl; /* Global instances — defined in star6e_mi.c. diff --git a/include/star6e_output.h b/include/star6e_output.h index 15eefb3b..99b53eb0 100644 --- a/include/star6e_output.h +++ b/include/star6e_output.h @@ -155,12 +155,23 @@ typedef struct { * RecoveryRequest arriving over RF, which is a full round trip and is * off by default (venc.recovery_enabled). * - * Wired to star6e_scene_request_idr(), so it inherits the shared - * per-channel IDR rate limiter (100 ms) — a persistently full ring - * coalesces into at most ~10 IDRs/s instead of a keyframe storm into - * the very ring that is already congested. */ - void (*request_idr)(void *ctx); + * Wired to star6e_ring_request_idr(), so it inherits the shared + * per-channel IDR rate limiter (100 ms) — but 10 IDRs/s into an + * already-congested ring is still a storm (measured: a consumer-less + * ring degraded the stream to an IDR every ~7 frames with GDR + * suppressed), so this path adds its own holdoff on top: + * venc_frame_drop_idr_due(), one request per second, state in + * drop_idr_last_us. Returns 1 when the IDR was actually issued, 0 + * when the shared limiter swallowed it — the caller then rolls the + * holdoff anchor back so the next drop retries instead of leaving + * the chain unhealed for up to a second. */ + int (*request_idr)(void *ctx); void *idr_ctx; + uint64_t drop_idr_last_us; + /* One WARN per pipeline start (reset by star6e_output_reset's memset) + * when packet metadata is incomplete or invalid — the frame is aborted, + * never shipped truncated. */ + uint8_t trunc_warned; /* Ring-full drops split by whether they actually broke the chain. * A non-referenced (SVC-T) frame is droppable by construction, so * those cost exactly one frame and must NOT trigger an IDR. */ @@ -229,6 +240,16 @@ void star6e_output_observe_pressure(Star6eOutput *output); int star6e_output_frame_ring_fill( const Star6eOutput *output, venc_frame_ring_fill_t *out); +/** Validate that every vendor pack exposes complete, in-bounds NAL + * descriptors. All consumers must reject the AU when this returns zero. */ +int star6e_output_stream_packet_info_complete( + const MI_VENC_Stream_t *stream); + +/** Reject an incomplete AU before output/recording. Returns 1 when rejected, + * emits a one-time warning, and requests paced recovery for reference frames. */ +int star6e_output_reject_incomplete_access_unit(Star6eOutput *output, + const MI_VENC_Stream_t *stream); + /** Begin accumulating RTP packets for a frame. When the transport is UDP * and SHM is not in use, subsequent star6e_output_send_rtp_parts() calls diff --git a/include/venc_config.h b/include/venc_config.h index 773dd19b..49b7a8b8 100644 --- a/include/venc_config.h +++ b/include/venc_config.h @@ -36,6 +36,20 @@ extern "C" { #define VENC_BITRATE_MIN_KBPS 1000 #define VENC_BITRATE_MAX_KBPS 200000 +/* Requested H.265 slices per picture. A sanity bound, NOT the delivered + * count: SigmaStar takes slice height in 32-px rows and quantizes it to + * whole CTU-64 rows, while CV610 uses its own 32-pixel LCU-row geometry. + * The delivered count therefore depends on backend and picture height. + * + * This was 8, on the stated grounds that the SDK's packetInfo table holds 8 + * NALs. That table is per PACK and the output walker iterates packs + * (star6e_output.c), so it never bounded slices per access unit: the GDR + * refresh AU is a 17-slice picture and has always flowed through that walker + * (measured 2026-08-20 on .232 — ~10,800 of them in 6 h, zero truncation + * warnings). The old cap made 9 and 17 unreachable and capped the fleet at + * 6, since 7 and 8 both quantize down to 6. */ +#define VENC_SLICE_COUNT_MAX 32 + /* ── Sub-structs mirroring JSON sections ─────────────────────────────── */ typedef struct { @@ -115,6 +129,11 @@ typedef struct { uint32_t max_qp; /* RC QP ceiling; 0 = leave the driver default */ uint16_t scene_threshold; /* frame size spike ratio x100 for scene IDR (0=off, 150=1.5x) */ uint8_t scene_holdoff; /* consecutive frames above threshold to trigger */ + uint32_t slice_count; /* independent H.265 slices per picture, + * 1..VENC_SLICE_COUNT_MAX; 1 = split off. + * >1 enables spatial loss concealment on the + * link RX (waybeam-link PROTOCOL.md §6.3b). + * Star6E, Maruko and CV610. */ /* Derived from `resilience` preset only. Not part of the JSON * schema or HTTP API — written exclusively by * apply_resilience_preset() at load time. Do not parse from JSON, diff --git a/include/venc_frame_ring.h b/include/venc_frame_ring.h index 65d263b2..9d813878 100644 --- a/include/venc_frame_ring.h +++ b/include/venc_frame_ring.h @@ -56,13 +56,36 @@ * must NOT provoke a recovery IDR: that would spend the largest frame in the * stream to repair damage that never happened, into a ring already full. * - * Shared by both backends so the policy has one definition rather than two + * Shared by all encoder backends so the policy has one definition rather than + * several * copies that can drift. */ static inline int venc_frame_drop_breaks_chain(uint8_t flags) { return (flags & VENC_FRAME_FLAG_ENHANCE) ? 0 : 1; } +/* Holdoff between ring-full recovery IDRs. The shared per-channel IDR + * limiter (100 ms) exists for scene changes, where speed matters; through + * it a ring with NO consumer draining it — every frame dropping — still + * degrades the stream into an IDR every ~7 frames with GDR suppressed + * (measured on star6e, 2026-08-20). A chain break only needs ONE IDR to + * heal, and a consumer-less ring needs none at all, so pace this path at + * one request per second: a live consumer that missed a frame resyncs + * exactly within 1 s (GDR already covers it approximately in one refresh + * cycle), and the worst case costs ~one extra I-frame per second. */ +#define VENC_FRAME_DROP_IDR_HOLDOFF_US (1000u * 1000u) + +/* Pure so tests can drive the clock: *last_us is caller-owned state (zero + * = never fired), now_us is CLOCK_MONOTONIC microseconds. */ +static inline int venc_frame_drop_idr_due(uint64_t *last_us, uint64_t now_us) +{ + if (*last_us != 0 && + now_us - *last_us < VENC_FRAME_DROP_IDR_HOLDOFF_US) + return 0; + *last_us = now_us; + return 1; +} + typedef struct { uint32_t pts; /* capture timestamp (µs, truncated to 32 bits) */ uint8_t codec; /* VENC_FRAME_CODEC_H265 */ @@ -103,7 +126,7 @@ typedef struct __attribute__((aligned(64))) { uint32_t futex_seq; uint32_t health_magic; /* VENC_FRAME_RING_HEALTH_MAGIC, or 0 */ uint64_t full_drops; /* lifetime full-ring drops */ - uint16_t throttle_permille; /* 1000 = unclamped, 250 = floor */ + uint16_t throttle_permille; /* 1000 = unclamped; lower = active clamp */ uint8_t _pad1[38]; /* Line 2: Consumer-owned */ diff --git a/init.d/S95waybeam.cv610 b/init.d/S95waybeam.cv610 index 7e0538cf..079cc1a3 100755 --- a/init.d/S95waybeam.cv610 +++ b/init.d/S95waybeam.cv610 @@ -55,7 +55,14 @@ start() echo "$NAME failed to start" >&2 cat "$LOGFILE" >&2 rm -f "$PIDFILE" - "$LOADER" stop + # Deliberately no module rollback here. The loader's start is + # idempotent -- it returns success having done nothing when the set is + # already up -- so unloading on a failed daemon start tears down a set + # this invocation did not create. That is the same hazard as the + # deleted reload action, on the worse path: a venc that dies at + # bring-up is usually a venc that was hard-killed earlier, and on such + # a boot the modules cannot be loaded back. Leaving them up costs + # nothing; the next start re-inits against them. return 1 fi echo "Started $NAME (sensor profile $CV610_SENSOR_PROFILE, audio $CV610_AUDIO)" @@ -64,7 +71,6 @@ start() stop() { # Cover the current daemon plus either side of an API-respawn handoff. - # Never unload the MPP stack while any of them still owns the graph. killall "$NAME" "$RESPAWN" "$WATCHDOG" 2>/dev/null || true i=0 while still_running && [ "$i" -lt 100 ]; do @@ -73,14 +79,37 @@ stop() done if still_running; then echo "$NAME did not stop within 10 seconds" >&2 - echo "refusing to unload CV610 modules while the graph is owned" >&2 return 1 fi rm -f "$PIDFILE" - "$LOADER" stop - echo "Stopped $NAME" + # The MPP modules stay loaded, the way they do on star6e and maruko. venc + # tears its own graph down in mpp_cleanup() -- including vb_exit() from the + # process that created it, which is the only process allowed to -- so the + # next start re-inits against the modules already up. Unloading them here + # was bring-up scaffolding, and it is what wedged the SoC whenever a + # consumer still held one of their devices. + echo "Stopped $NAME (MPP modules left loaded)" } +# There is deliberately no "reload" action. It existed to unload and reload the +# MPP modules after a venc that died without mpp_cleanup(), on the premise that +# VB was left held by a dead owner -- a premise the hardware disproved in the +# same release that added it: VB *is* released when the process dies, and what a +# crash actually leaves behind (ISP, and the AI device claim) venc now pre-cleans +# itself. A hard-killed venc recovers from a plain start, video and audio both. +# +# Nothing in production called it, and unloading is not free: a hard kill +# poisons module reloading for the rest of the boot, so a reload issued +# afterwards leaves the craft with no modules at all -- or, measured on a +# video-only craft, resets the SoC. Recovery after a hard kill is a plain start; +# applying a module-parameter change (CV610_AUDIO, sensor profile) is a reboot. +# +# 'load-cv610-online restart' still exists for a dirty/partial module set, but +# run it BARE and it reloads with the loader's own defaults -- video-only, +# imx662 clock -- not this craft's profile. That caveat used to live inside +# reload(); it is stated here because it outlived the function. Prefer +# 'load-cv610-online stop' followed by 'S95waybeam start', which passes +# CV610_SENSOR_PROFILE and CV610_AUDIO for you. case "${1:-}" in start|stop) "$1" ;; restart) stop && start ;; diff --git a/init.d/load-cv610-online b/init.d/load-cv610-online index c370cd10..d7279d98 100755 --- a/init.d/load-cv610-online +++ b/init.d/load-cv610-online @@ -20,6 +20,45 @@ is_loaded() grep -q "^$1 " /proc/modules } +# Character devices created by the modules below. Derived from the target's +# actual /dev, not from module names -- guessing from names missed ot_mipi_rx +# (not "mipi_rx"), logmpp and venc_msg. To re-derive after a module set change: +# ls -l /dev | awk '$1 ~ /^c/ {print $NF}' | sort # before and after a load +# Built by concatenation, not as one multi-line literal: the lookup below matches +# on " name ", so a name landing on a line boundary would carry a newline +# instead of a space and never match at all. +MPP_DEVICES="ab acodec adec aenc ai aio ao bus chnl h265e i2c isp_dev logmpp" +MPP_DEVICES="$MPP_DEVICES mipi_rx mmz_userdev ot_mipi_rx rc rgn sys user vb" +MPP_DEVICES="$MPP_DEVICES vca venc venc_msg vgs vi vpp vpss" + +is_mpp_device() +{ + case "$1" in /dev/*) ;; *) return 1 ;; esac + case " $MPP_DEVICES " in *" ${1#/dev/} "*) return 0 ;; esac + return 1 +} + +# Processes holding one of those devices open, minus any pid in $1. +# +# The drivers do not set .owner on their file operations, so opening the device +# takes no module reference -- /proc/modules reports open_rgn "used=0" while a +# consumer holds /dev/rgn. rmmod therefore succeeds under a live consumer and +# frees the file operations it is still using, wedging the SoC hard enough to +# need a physical power cycle. waybeam_hub is the one that matters in practice: +# it holds /dev/rgn for the CV610 RGN OSD. +mpp_holders() +{ + ignore=" ${1:-} " + for fd in /proc/[0-9]*/fd/*; do + [ -L "$fd" ] || continue + is_mpp_device "$(readlink "$fd" 2>/dev/null)" || continue + pid=${fd#/proc/} + pid=${pid%%/*} + case "$ignore" in *" $pid "*) continue ;; esac + echo "$pid($(cat "/proc/$pid/comm" 2>/dev/null))" + done | sort -u | tr '\n' ' ' +} + load_stock() { name=$1 @@ -29,9 +68,21 @@ load_stock() loaded="$name $loaded" } +# Rollback for a load sequence that failed part way through. Carries the same +# guard as stop_modules(): a consumer can grab a device created EARLIER in this +# very sequence -- waybeam_hub rebinds /dev/rgn within ~1s of open_rgn appearing, +# and the sequence runs for seconds afterwards -- and unloading under it wedges +# the SoC hard enough to need a physical power cycle. Leaving the modules loaded +# is recoverable; a wedged SoC is not. cleanup_partial() { set +e + holders=$(mpp_holders) + if [ -n "$holders" ]; then + echo "partial load failed; NOT unloading -- MPP devices open by $holders" >&2 + echo "stop those consumers, then run '$0 stop' to clear the partial state" >&2 + return 0 + fi for name in $loaded; do rmmod "$name" 2>/dev/null done @@ -51,6 +102,23 @@ start_modules() echo "refusing vendor open_pm" >&2 return 1 } + # open_user is the last module the sequence loads, so its presence means a + # previous run completed. Loading is idempotent from here: a venc restart + # re-inits the graph against the modules already up, the way star6e and + # maruko have always worked. Only a *partial* set is dirty. + if is_loaded open_user && is_loaded open_base; then + if [ "$AUDIO" = "1" ] && ! is_loaded open_acodec; then + # Reboot, not a reload. Swapping the module set means unloading, + # and a boot that has already seen a hard kill cannot load them + # back -- the craft ends up with no modules at all. A reboot + # applies the profile the platform conf asks for, every time. + echo "modules are up but were loaded without audio;" >&2 + echo "reboot to bring them up with the configured profile" >&2 + return 1 + fi + echo "MPP modules already loaded" + return 0 + fi is_loaded open_base && { echo "refusing dirty MPP module state" >&2 return 1 @@ -106,6 +174,15 @@ start_modules() stop_modules() { + # Guard the rmmod itself, not its callers: any unload is fatal with a + # consumer still attached. The partial-load rollback carries the same + # guard (see cleanup_partial); a hand-run stop is the only other caller. + holders=$(mpp_holders) + if [ -n "$holders" ]; then + echo "refusing to unload: MPP devices still open by $holders" >&2 + echo "stop those consumers first, e.g. /etc/init.d/S97waybeam-hub stop" >&2 + return 1 + fi modules="open_user open_mipi_rx open_sensor_i2c \ open_acodec open_aenc open_ai open_aio \ open_h265e open_venc open_rc open_chnl open_isp open_vi \ @@ -134,8 +211,13 @@ case "${1:-}" in restart) stop_modules && start_modules ;; + holders) + # Callers that must decide *before* destroying state ask here, passing + # the pids they own as one space-separated argument. + mpp_holders "${2:-}" + ;; *) - echo "Usage: $0 {start|stop|restart}" >&2 + echo "Usage: $0 {start|stop|restart|holders [ignore-pids]}" >&2 exit 1 ;; esac diff --git a/scripts/cv610_reload_free_verify.sh b/scripts/cv610_reload_free_verify.sh new file mode 100755 index 00000000..30e6fd92 --- /dev/null +++ b/scripts/cv610_reload_free_verify.sh @@ -0,0 +1,325 @@ +#!/bin/sh +# cv610_reload_free_verify.sh -- run ON the CV610 target. +# +# Verifies that a venc restart no longer reloads the MPP modules, and that the +# cases which make that unsafe are caught rather than tolerated. +# +# The interesting case is a restart across a MODE CHANGE. A same-mode restart +# passes even when the VB config was silently inherited, because the inherited +# layout happens to be the right one -- so a suite that only restarts in place +# proves nothing about the thing being changed. T3 changes video0.size and then +# asserts the ENCODED SIZE moved in venc's own VPSS line, which is what moves +# out_blk, before checking which path sys_setup() took. +# +# Instruments are the markers sys_setup() prints: +# "ok ss_mpi_vb_set_cfg" -> fresh config applied +# "ok ss_mpi_vb_set_cfg (adopted identical ...)" -> BUSY, layout matched +# "FAIL VB is held by a dead owner ..." -> BUSY, layout differed +# +# Two steps can kill the SoC, by design, and need an operator who can power +# cycle: +# T1 attempts the unload the guard is supposed to refuse. If the guard has +# regressed, the unload proceeds under the hub and wedges the board -- +# that is exactly the bug, observed as no network and ARP incomplete. +# T6 hard-kills venc so MPP state is left dirty on purpose. The kill itself +# is survivable -- venc self-heals -- but it poisons module reloading for +# the rest of the boot, and an unload issued after this point leaves the +# craft with no modules (and resets a video-only SoC). So it runs last. +# Everything else is a normal restart. +# +# Usage: cv610_reload_free_verify.sh [--keep-going] +set -u + +INIT=/etc/init.d/S95waybeam +HUB=/etc/init.d/S97waybeam-hub +LOADER=/usr/bin/load-cv610-online +CFG=/etc/waybeam.json +LOG=/var/run/waybeam.log +BACKUP=/tmp/waybeam.json.verify-backup +KEEP=0 +[ "${1:-}" = "--keep-going" ] && KEEP=1 + +pass=0; fail=0; note=0 +ok() { pass=$((pass+1)); echo " PASS $1"; } +bad() { fail=$((fail+1)); echo " FAIL $1"; [ "$KEEP" = 1 ] || { echo; echo "halting so the state can be inspected"; summary; exit 1; }; } +info() { note=$((note+1)); echo " NOTE $1"; } +summary() { echo; echo "=== $pass passed, $fail failed, $note measurement(s) ==="; } +chk() { desc=$1; shift; if "$@"; then ok "$desc"; else bad "$desc"; fi; } + +mods() { grep -c '^open' /proc/modules; } +venc_pid(){ pidof waybeam 2>/dev/null; } +hub_pid() { pidof waybeam_hub 2>/dev/null; } +pkts() { wget -qO- --timeout=3 http://127.0.0.1:80/api/v1/transport/status 2>/dev/null \ + | sed 's/.*"packetsSent"://; s/[^0-9].*//'; } + +flowing() { + a=$(pkts); sleep 3; b=$(pkts) + [ -n "$a" ] && [ -n "$b" ] && [ "$b" -gt "$a" ] 2>/dev/null +} + +# The encoded size venc actually chose, straight from its own bring-up line: +# "ok VPSS 1920x1080 -> 1280x720 (scaled)" +# This, not the config, is what decides out_blk and the pool count. +out_size() { + sed -n 's/.*VPSS [0-9]*x[0-9]* -> \([0-9]*x[0-9]*\).*/\1/p' "$LOG" | tail -1 +} + +# video0.size is a STRING ("1920x1080"), and video0.width/height do not exist -- +# setting those creates keys nothing reads, which is how the first version of +# this suite reported a mode change that never happened. Assert the geometry, +# not the key. +set_size() { + command -v json_cli >/dev/null 2>&1 || return 1 + json_cli -s .video0.size "\"$1\"" -i "$CFG" >/dev/null 2>&1 || return 1 + [ "$(json_cli -g .video0.size --raw -i "$CFG" 2>/dev/null)" = "$1" ] || return 1 + return 0 +} + +# The hub's OSD region, HIRGN_HANDLE in waybeam-hub src/osd_backend_hirgn.c. +# Fixed there so it never collides with venc's own debug OSD on handle 0. +HUB_RGN_HANDLE=8 + +# The compositor's job counters for that region, from /proc/umap/rgn: +# hdl call_cnt job_suc job_fail task_suc task_fail end_suc end_fail +# Read these, not the hub's perf line: the hub counts a publish it made, which +# is the stimulus. These count the composite that consumed it. +rgn_field() { + awk -v hdl="$HUB_RGN_HANDLE" -v col="$1" ' + /region call vgs/ { in_tbl = 1; next } + in_tbl && $1 == hdl && NF >= 8 { print $col; exit } + ' /proc/umap/rgn 2>/dev/null +} +rgn_jobs() { rgn_field 2; } +rgn_fails() { rgn_field 4; } + +# The audio encoder's two MMZ blocks: present exactly when AENC is up. Reading +# these rather than the log because the log's own message is misleading (it +# blames the module load for what is actually a dead predecessor's AI claim). +# grep -c prints "0" AND exits 1 when it matches nothing, so "|| echo 0" would +# print 0 twice. Count with awk, which has one exit path and one line of output. +aenc_blocks() { + awk '/aenc\(0\)/ { n++ } END { print n + 0 }' /proc/umap/media-mem 2>/dev/null || + echo 0 +} + +# Is audio even configured? Without this a video-only craft would "fail" the +# audio assertion for the correct reason of having no audio. +audio_enabled() { + command -v json_cli >/dev/null 2>&1 || return 1 + [ "$(json_cli -g .audio.enabled --raw -i "$CFG" 2>/dev/null)" = "true" ] +} + +not_grep() { ! grep -q "$1" "$2"; } + +osd_compositing() { + # Two samples must advance, with no failed jobs. Retried once because the + # counters belong to the region, not to the hub: if the hub recreates the + # region between the samples the count RESTARTS, so b < a is a rebind in + # progress, not a stall. Without the retry this flakes exactly when the + # thing it is checking is working. + i=0 + while [ "$i" -lt 3 ]; do + i=$((i + 1)) + a=$(rgn_jobs); sleep 3; b=$(rgn_jobs) + [ -n "$a" ] && [ -n "$b" ] || return 1 + [ "$b" -lt "$a" ] 2>/dev/null && continue + [ "$b" -gt "$a" ] 2>/dev/null && [ "$(rgn_fails)" = 0 ] && return 0 + return 1 + done + return 1 +} + +# The region is created by the hub a few seconds after ITS start, not ours, so +# a baseline sampled too early reads as "this build has no OSD" and silently +# downgrades the T2 assertion to a note. Wait for it when the hub is up. +wait_for_rgn() { + i=0 + while [ "$i" -lt 12 ]; do + [ -n "$(rgn_jobs)" ] && return 0 + i=$((i + 1)); sleep 2 + done + return 1 +} + +# ---------------------------------------------------------------- preconditions +echo "=== preconditions ===" +cp "$CFG" "$BACKUP" || { echo "cannot back up $CFG"; exit 1; } +echo " config backed up to $BACKUP" +[ -n "$(venc_pid)" ] || $INIT start >/dev/null 2>&1 +[ -n "$(hub_pid)" ] || $HUB start >/dev/null 2>&1 +sleep 8 +base_mods=$(mods) +[ -n "$(hub_pid)" ] && wait_for_rgn +base_rgn=$(rgn_jobs) +audio_cfg=0 +audio_enabled && audio_cfg=1 +echo " venc=$(venc_pid) hub=$(hub_pid) modules=$base_mods osd_jobs=${base_rgn:-none} audio=$audio_cfg" +[ -n "$(hub_pid)" ] || { echo "hub is not running -- T1/T2/T3 need it up"; exit 1; } + +# ------------------------------------------------------- T1: the guard still fires +echo +echo "=== T1: unload is refused while the hub holds /dev/rgn ===" +out=$("$LOADER" stop 2>&1); rc=$? +case "$out" in + *"refusing to unload"*) ok "loader refused, naming holders" ;; + *) bad "loader did NOT refuse (rc=$rc): $out" ;; +esac +chk "refusal is a non-zero exit" test "$rc" -ne 0 +chk "module count unchanged ($base_mods)" test "$(mods)" = "$base_mods" + +# ------------------------------------ T2: graceful restart, same mode, hub RUNNING +echo +echo "=== T2: venc restart with the hub up (the case that used to wedge) ===" +: >"$LOG" +$INIT restart >/dev/null 2>&1 +sleep 8 +chk "venc came back (pid $(venc_pid))" test -n "$(venc_pid)" +chk "hub survived the restart" test -n "$(hub_pid)" +chk "modules never unloaded ($base_mods)" test "$(mods)" = "$base_mods" +chk "frames flowing after restart" flowing +chk "sys_setup ran vb_set_cfg" grep -q "ss_mpi_vb_set_cfg" "$LOG" + +# The check this suite used to hand to a human. venc's teardown takes the whole +# RGN table with it (mpp_cleanup -> ss_mpi_sys_exit, and MPP objects are kernel +# state shared across processes), so the hub's OSD region does not merely go +# stale -- it disappears, and before waybeam-hub#212 the hub kept painting into +# nothing without saying so. +now_rgn=$(rgn_jobs) +echo " OSD region $HUB_RGN_HANDLE: was $base_rgn, now ${now_rgn:-GONE}, fails=$(rgn_fails)" +if [ -z "$base_rgn" ]; then + info "hub had no OSD region before the restart (built without CV610_OSD?) -- OSD survival UNVERIFIED" +else + chk "hub OSD still compositing after the restart (waybeam-hub#212)" \ + osd_compositing +fi + +# ------------------------------------------- T3: restart ACROSS a mode change +echo +echo "=== T3: restart across a mode change, hub up ===" +base_out=$(out_size) +echo " baseline encoded size: ${base_out:-unknown}" +if [ -z "$base_out" ]; then + info "no VPSS size line in $LOG -- cannot tell a mode change from a no-op, T3 skipped" +elif ! set_size 640x360; then + info "could not edit $CFG -- T3 skipped, mode-change path UNVERIFIED" +else + : >"$LOG" + $INIT restart >/dev/null 2>&1 + sleep 8 + new_out=$(out_size) + if [ -z "$new_out" ] || [ "$new_out" = "$base_out" ]; then + # The whole point of T3. Without this the suite happily "passes" a + # same-mode restart and leaves the layout-change path unexercised. + bad "encoded size did not move ($base_out -> ${new_out:-none}) -- NOT a mode change" + else + ok "encoded size moved $base_out -> $new_out, so the VB layout differs" + if grep -q "adopted identical live config" "$LOG"; then + bad "VB config was ADOPTED across a mode change -- pools are stale" + elif grep -q "held by a dead owner" "$LOG"; then + bad "vb_set_cfg refused after a *graceful* stop -- vb_exit did not release" + elif grep -q "ok ss_mpi_vb_set_cfg" "$LOG"; then + ok "fresh VB config applied for the new layout" + else + bad "no vb_set_cfg marker at all" + fi + chk "venc running in the new mode" test -n "$(venc_pid)" + chk "frames flowing in the new mode" flowing + chk "still no module reload" test "$(mods)" = "$base_mods" + # The nastier OSD case. The hub rebinds its region within ~1 s, but at + # the OLD window size, and only its own 5 s source poll re-anchors it + # to the smaller frame -- so for a few seconds an oversized region is + # attached to this channel. Assert both that venc survived it (above) + # and that the OSD ends up compositing anyway. + if [ -n "$base_rgn" ]; then + chk "hub OSD compositing after a mode-change restart" osd_compositing + fi + fi +fi + +# ------------------------------------------------ T4: back to the original mode +echo +echo "=== T4: restore 1080p ===" +cp "$BACKUP" "$CFG" +: >"$LOG" +$INIT restart >/dev/null 2>&1 +sleep 8 +chk "restored mode: venc up" test -n "$(venc_pid)" +chk "restored mode: streaming" flowing + +# T5 tested the init script's "reload" action, which no longer exists: it was +# built for a VB-held-by-a-dead-owner case the hardware disproved, nothing called +# it, and it was the only shipped path that unloaded modules on a running craft. +# With it gone, nothing in this suite unloads, so the contaminated-boot check it +# needed is gone too -- a hard kill can no longer poison anything this suite does. +cp "$BACKUP" "$CFG" + +# --------------------------------------------------------- T6: the crash path +# LAST on purpose. Measured on .181: after a SIGKILL the next module +# unload/reload fails at sys.ko init -- 'no sys ko!' then 'load vpp.ko +# ...FAILURE!' -- for the rest of the boot, and on a video-only craft it resets +# the SoC outright. Nothing in this suite unloads any more, so that no longer +# breaks a later step; it still runs last so it cannot poison a hand-run +# 'load-cv610-online restart' someone does afterwards. +# Expected result is NOT known in advance: if the driver's .release frees VB +# when the process dies, a hard kill self-heals and set_cfg simply succeeds. +# Report what happens rather than asserting. +echo +echo "=== T6: hard-kill venc (no mpp_cleanup), then start in a DIFFERENT mode ===" +echo " measurement, not an assertion" +killall -9 waybeam 2>/dev/null +sleep 3 +set_size 640x360 || info "config edit failed; T6 degraded to a same-mode start" +: >"$LOG" +$INIT start >/dev/null 2>&1 +sleep 8 +if grep -q "held by a dead owner" "$LOG"; then + info "VB survived the kill and the mismatch was REFUSED (reboot needed)" +elif grep -q "adopted identical live config" "$LOG"; then + bad "stale VB adopted across a mode change after a crash -- silent wrong pools" +elif grep -q "ok ss_mpi_vb_set_cfg" "$LOG"; then + info "VB was released when the process died" +else + info "no VB marker; inspect $LOG" +fi +grep -q "already inited" "$LOG" && bad "ISP survived the kill and blocked the restart" +# The VB marker alone says nothing about whether the daemon came up: the first +# run of this suite recorded a cheerful NOTE while venc was dead on the floor at +# ss_mpi_isp_mem_init. Assert the outcome, not just the milestone. +chk "venc actually running after the crash restart" test -n "$(venc_pid)" +chk "streaming after the crash restart" flowing + +# "streaming" above is VIDEO. It passed for months while AUDIO was silently +# dead: a SIGKILL leaves the AI device claimed by the dead pid, every AI call +# from the successor is refused with OT_ERR_AI_NOT_PERM, and venc reports it as +# "needs CV610_AUDIO=1 at module load" -- so neither the log nor this suite said +# anything true. The aenc MMB blocks are the observable: the audio encoder has +# exactly two, and they are absent when audio failed to start. +if [ "$audio_cfg" = 1 ]; then + echo " aenc blocks: $(aenc_blocks) (2 = audio up, 0 = audio silently lost)" + chk "audio came back after the crash restart" test "$(aenc_blocks)" = 2 + chk "no audio-start failure logged" not_grep "audio did not start" "$LOG" +else + info "audio disabled in $CFG -- crash-restart audio recovery UNVERIFIED" +fi + +leaks=$(dmesg | grep -c "MMB LEAK") +info "MMB LEAK lines this boot: $leaks (2 per hard kill; they are the kernel" +info " RECLAIMING those blocks, not losing them -- measured: the pool returns" +info " to its exact baseline across repeated kills)" +echo " NOTE module reloading is poisoned until reboot -- unloading is NOT the" +echo " recovery after a hard kill; reboot is. venc itself self-heals above." + +echo +# T6 leaves video0.size at the test value. Put the craft back on its configured +# mode and restart into it, so the bench is not silently left encoding 640x360 +# under a message claiming it was restored. +cp "$BACKUP" "$CFG" +$INIT restart >/dev/null 2>&1 +sleep 8 +chk "config restored and venc restarted into it" test -n "$(venc_pid)" +echo " encoded size now: $(out_size)" +echo "Config restored from $BACKUP." +echo "Still to check by hand: one reboot. (The OSD is asserted in T2 now, via" +echo "the compositor's own job counters in /proc/umap/rgn.)" +summary +[ "$fail" = 0 ] diff --git a/sensors/cv610/imx662/Makefile b/sensors/cv610/imx662/Makefile index 35b351ac..d7fb69d5 100644 --- a/sensors/cv610/imx662/Makefile +++ b/sensors/cv610/imx662/Makefile @@ -16,6 +16,12 @@ CFLAGS += -fPIC -Wall -Wextra -Werror -O2 \ SRCS := imx662_cmos.c imx662_sensor_ctl.c $(COMMON)/sensor_common.c OBJS := imx662_cmos.o imx662_sensor_ctl.o sensor_common.o +DEPS := $(OBJS:.o=.d) + +# The tuning tables and the register sequence live in headers, so without +# generated dependencies a header-only edit relinks the old objects and ships +# a binary that does not contain the change. +CFLAGS += -MMD -MP .PHONY: all clean @@ -27,8 +33,10 @@ all: $(LIB_NAME).so sensor_common.o: $(COMMON)/sensor_common.c $(CV610_CC) $(CFLAGS) -c $< -o $@ +-include $(DEPS) + $(LIB_NAME).so: $(OBJS) $(CV610_CC) -shared -o $@ $(OBJS) clean: - rm -f $(OBJS) $(LIB_NAME).so + rm -f $(OBJS) $(DEPS) $(LIB_NAME).so diff --git a/sensors/cv610/imx662/README.md b/sensors/cv610/imx662/README.md index 4e7d2dd3..492f2eee 100644 --- a/sensors/cv610/imx662/README.md +++ b/sensors/cv610/imx662/README.md @@ -21,5 +21,58 @@ Install the result as `/usr/lib/sensors/libsns_imx662.so`. No proprietary SDK source or binary is stored here; the build consumes the public sensor interface and `sensor_common.c` from the external OpenHisilicon checkout. -The initial backend supports linear mode only. HDR and broad ISP tuning are -deliberately deferred by issue #220. +Linear mode only — `cmos_set_wdr_mode()` rejects every other WDR mode, and HDR +stays deferred by issue #220. + +## What the plugin programs + +`imx662_cfg.h` holds Sony's power-on sequence — the reserved analog/ADC trim, +the MIPI TX timing, the readout window and the HDR context that linear mode +needs parked. It runs once, in standby, before the per-mode writes, and the +per-mode writes win where the two overlap. That ordering matters for +`0x3A50/51/52`, which keys off ADBIT rather than output depth: the table holds +the 12-bit form and the RAW10 modes overwrite it. + +`cmos_get_isp_default()` and `cmos_get_awb_default()` seed the ISP once at init. +The algorithm tables in `imx662_cmos_param.h` are ported from the in-tree +`smart_sc450ai` driver, which targets this same ISP silicon. The blocks that +describe ISP behaviour (gamma, CLUT, demosaic, CAC, anti-false-colour, LDCI, +dehaze, CA) transfer on principle; the noise-fitted ones (bayer_nr, sharpen, +noise_calibration, DRC) are borrowed from a 4 MP sensor and are kept on a +hardware A/B rather than a calibration — a measured IMX662 fit should replace +them. The AWB saturation curve is scaled up from sc450ai's at the low-ISO end. + +These are compile-time seeds, read once at pipe start. `src/cv610_iq.c` exposes +the same blocks as live knobs over `/api/v1/iq` and `/api/v1/iq/set`, so a value +here is a starting point that can be corrected without a rebuild — but only the +seed survives a reboot, so a value worth keeping belongs back in this file. + +Two blocks are seeded but not switched on: `g_cmos_drc` and `g_cmos_dehaze` +carry `enable = 0`, inherited from sc450ai's linear-mode defaults, and the ISP +bypasses both at runtime (confirmed by `ss_mpi_isp_get_module_ctrl()`). Setting +`drc.enable=1` over the IQ API is the cheap way to evaluate DRC on this sensor +before deciding whether the seed should change. + +## Low-light behaviour + +The sharpen auto tables are tapered along their ISO axis to zero by bucket 9, +with the daylight buckets (0-3) left byte-identical. Sharpening is a high-pass +filter, so at high gain the sc450ai tables — which *rise* along ISO, edge +strength 195 to 500 — were amplifying noise into the encoder: measured 65.4 to +7.8 Mbps on the bench with sharpen off. The AWB saturation curve tapers harder +above daylight for the same reason, chroma noise being the ugliest high-gain +artifact. + +Conversion gain follows the analog gain: `FDG_SEL0` selects HCG above a +threshold and LCG below it, with the written gain code compensated by 15.3 dB +(Rcg typ 5.8) so the switch is continuous. `max_isp_dgain_target` is 4x, which +puts the total ceiling at 398 x 4 = 1592x (~64 dB) and makes AE exhaust analog +before it reaches for digital. + +`g_cmos_noise_calibration` is still sc450ai's photon-transfer fit and is the +main thing left wrong for this sensor; `nr.coring_ratio` and `nr.md_en` are +exposed over `/api/v1/iq` so it can be corrected by eye until a real IMX662 +calibration exists. + +Reference material for further tuning lives outside this repo, in +`hisilicon/vendor/imx662-docs/`. diff --git a/sensors/cv610/imx662/imx662_cfg.h b/sensors/cv610/imx662/imx662_cfg.h new file mode 100644 index 00000000..bade193f --- /dev/null +++ b/sensors/cv610/imx662/imx662_cfg.h @@ -0,0 +1,192 @@ +/* + * imx662_cfg.h — IMX662 power-on register sequence. + * + * Sony's one-shot init block: the reserved analog/ADC trim, the MIPI TX + * timing, the readout window and the HDR-context registers that must be + * parked for linear mode. The ISP never writes these; the plugin does, + * once, while the sensor is in standby. + * + * Transcribed from imx662_global_settings[] in pauliustumas/imx662 + * (driver/imx662.c), covering 0x301A..0x4549. Values are held verbatim, + * comments included, so a future diff against that source stays mechanical. + * + * Departures from the source list: + * + * - {0x3002, 0x00} (master mode operation start) is dropped. This + * table runs inside standby; imx662_default_reg_init() releases + * STANDBY and XMSTA itself once the mode registers are in. + * - The HMAX pair is absent — it is commented out upstream, and HMAX + * is per-mode state that imx662_linear_1080p_init() owns. + * - {0x44C0, 0x7F} is ADDED: upstream omits it and Sony's map requires + * it. See the comment at that entry. + * - {0x30A6, 0x0F} is KEPT as upstream has it, which leaves XVS_DRV / + * XHS_DRV at Hi-Z, where Sony's All-pixel modes set 0x00 (drive). + * Nothing on this module consumes XVS/XHS, and starting to drive two + * pads whose wiring is unknown is a hardware risk with no benefit + * today. Revisit if frame-sync or a second sensor is ever wired. + * + * The 0x3A50/51/52 AD-timing triplet below carries the 12-bit values, and + * 0x301A appears here and again in the per-mode block. Both are harmless + * overlaps only because this table runs FIRST — see imx662_sensor_ctl.c, + * where that ordering is load-bearing for the RAW10 modes. + * + * Measured against silicon on the 192.168.2.181 bench, 2026-08-16: + * 94 of these entries differ from the sensor's power-on state, and the + * readout-window group (0x303C-0x303F, 0x3044-0x3047) already matches + * bit for bit, so writing it is a confirmed no-op on this module. A + * RAW10-vs-RAW12 dump of the whole range showed the reserved blocks are + * identical in both, i.e. none of this is bit-depth dependent. + */ + +#ifndef IMX662_CFG_H +#define IMX662_CFG_H + +#include "ot_type.h" + +typedef struct { + td_u16 addr; + td_u8 data; +} imx662_reg_cfg; + +static const imx662_reg_cfg g_imx662_init_seq[] = { + { 0x301A, 0x00 }, /* HDR mode select (Normal) */ + { 0x301B, 0x00 }, /* Normal/binning */ + { 0x301C, 0x00 }, /* XVS sub sample */ + { 0x301E, 0x01 }, /* virtual channel */ + { 0x303C, 0x00 }, /* PIX HSTART */ + { 0x303D, 0x00 }, /* PIX HSTART */ + { 0x303E, 0x90 }, /* H WIDTH */ + { 0x303F, 0x07 }, /* H WIDTH */ + { 0x3044, 0x00 }, /* PIX VSTART */ + { 0x3045, 0x00 }, /* PIX VSTART */ + { 0x3046, 0x4C }, /* V WIDTH */ + { 0x3047, 0x04 }, /* V WIDTH */ + { 0x3060, 0x16 }, /* DOL output timing */ + { 0x3061, 0x01 }, /* DOL output timing */ + { 0x3062, 0x00 }, /* DOL output timing */ + { 0x3064, 0xC4 }, /* DOL output timing */ + { 0x3065, 0x0C }, /* DOL output timing */ + { 0x3066, 0x00 }, /* DOL output timing */ + { 0x3069, 0x00 }, /* Direct Gain Enable */ + { 0x3072, 0x00 }, /* GAIN SEF1 */ + { 0x3073, 0x00 }, /* GAIN SEF1 */ + { 0x3074, 0x00 }, /* GAIN SEF2 */ + { 0x3075, 0x00 }, /* GAIN SEF2 */ + { 0x3081, 0x00 }, /* EXP_GAIN */ + { 0x308C, 0x00 }, /* Clear HDR DGAIN */ + { 0x308D, 0x01 }, /* Clear HDR DGAIN */ + { 0x3094, 0x00 }, /* CHDR AGAIN LG */ + { 0x3095, 0x00 }, /* CHDR AGAIN LG */ + { 0x3096, 0x00 }, /* CHDR AGAIN1 */ + { 0x3097, 0x00 }, /* CHDR AGAIN1 */ + { 0x309C, 0x00 }, /* CHDR AGAIN HG */ + { 0x309D, 0x00 }, /* CHDR AGAIN HG */ + { 0x30A4, 0xAA }, /* XVS/XHS OUT */ + { 0x30A6, 0x0F }, /* XVS/XHS DRIVE HiZ */ + { 0x30CC, 0x00 }, /* XVS width */ + { 0x30CD, 0x00 }, /* XHS width */ + { 0x3400, 0x01 }, /* GAIN Adjust */ + { 0x3444, 0xAC }, /* RESERVED */ + { 0x3460, 0x21 }, /* Normal Mode 22H=C HDR mode */ + { 0x3492, 0x08 }, /* RESERVED */ + { 0x3A50, 0xFF }, /* Normal 12bit */ + { 0x3A51, 0x03 }, /* Normal 12bit */ + { 0x3A52, 0x00 }, /* AD 12bit */ + { 0x3B00, 0x39 }, /* RESERVED */ + { 0x3B23, 0x2D }, /* RESERVED */ + { 0x3B45, 0x04 }, /* RESERVED */ + { 0x3C0A, 0x1F }, /* RESERVED */ + { 0x3C0B, 0x1E }, /* RESERVED */ + { 0x3C38, 0x21 }, /* RESERVED */ + { 0x3C40, 0x06 }, /* Normal mode. CHDR=05h */ + { 0x3C44, 0x00 }, /* RESERVED */ + { 0x3CB6, 0xD8 }, /* RESERVED */ + { 0x3CC4, 0xDA }, /* RESERVED */ + { 0x3E24, 0x79 }, /* RESERVED */ + { 0x3E2C, 0x15 }, /* RESERVED */ + { 0x3EDC, 0x2D }, /* RESERVED */ + { 0x4498, 0x05 }, /* RESERVED */ + { 0x449C, 0x19 }, /* RESERVED */ + { 0x449D, 0x00 }, /* RESERVED */ + { 0x449E, 0x32 }, /* RESERVED */ + { 0x449F, 0x01 }, /* RESERVED */ + { 0x44A0, 0x92 }, /* RESERVED */ + { 0x44A2, 0x91 }, /* RESERVED */ + { 0x44A4, 0x8C }, /* RESERVED */ + { 0x44A6, 0x87 }, /* RESERVED */ + { 0x44A8, 0x82 }, /* RESERVED */ + { 0x44AA, 0x78 }, /* RESERVED */ + { 0x44AC, 0x6E }, /* RESERVED */ + { 0x44AE, 0x69 }, /* RESERVED */ + { 0x44B0, 0x92 }, /* RESERVED */ + { 0x44B2, 0x91 }, /* RESERVED */ + { 0x44B4, 0x8C }, /* RESERVED */ + { 0x44B6, 0x87 }, /* RESERVED */ + { 0x44B8, 0x82 }, /* RESERVED */ + { 0x44BA, 0x78 }, /* RESERVED */ + { 0x44BC, 0x6E }, /* RESERVED */ + { 0x44BE, 0x69 }, /* RESERVED */ + /* 0x44C0 is absent from pauliustumas/imx662's imx662_global_settings[], + * which this table was transcribed from -- the upstream list is wrong + * against Sony's map, which gives 44C0h "Set to 7Fh" (reset 00h) in all + * 18 All-pixel modes. 0x44C0/0x44C1 is the first entry of an 8x16-bit + * little-endian table mirrored verbatim at 0x44D0..0x44DF, and the mirror + * below does carry 7F/01 -- so without this the two banks disagree at + * exactly one index, bank 0 latching 0x0100 instead of 0x017F. */ + { 0x44C0, 0x7F }, /* RESERVED */ + { 0x44C1, 0x01 }, /* RESERVED */ + { 0x44C2, 0x7F }, /* RESERVED */ + { 0x44C3, 0x01 }, /* RESERVED */ + { 0x44C4, 0x7A }, /* RESERVED */ + { 0x44C5, 0x01 }, /* RESERVED */ + { 0x44C6, 0x7A }, /* RESERVED */ + { 0x44C7, 0x01 }, /* RESERVED */ + { 0x44C8, 0x70 }, /* RESERVED */ + { 0x44C9, 0x01 }, /* RESERVED */ + { 0x44CA, 0x6B }, /* RESERVED */ + { 0x44CB, 0x01 }, /* RESERVED */ + { 0x44CC, 0x6B }, /* RESERVED */ + { 0x44CD, 0x01 }, /* RESERVED */ + { 0x44CE, 0x5C }, /* RESERVED */ + { 0x44CF, 0x01 }, /* RESERVED */ + { 0x44D0, 0x7F }, /* RESERVED */ + { 0x44D1, 0x01 }, /* RESERVED */ + { 0x44D2, 0x7F }, /* RESERVED */ + { 0x44D3, 0x01 }, /* RESERVED */ + { 0x44D4, 0x7A }, /* RESERVED */ + { 0x44D5, 0x01 }, /* RESERVED */ + { 0x44D6, 0x7A }, /* RESERVED */ + { 0x44D7, 0x01 }, /* RESERVED */ + { 0x44D8, 0x70 }, /* RESERVED */ + { 0x44D9, 0x01 }, /* RESERVED */ + { 0x44DA, 0x6B }, /* RESERVED */ + { 0x44DB, 0x01 }, /* RESERVED */ + { 0x44DC, 0x6B }, /* RESERVED */ + { 0x44DD, 0x01 }, /* RESERVED */ + { 0x44DE, 0x5C }, /* RESERVED */ + { 0x44DF, 0x01 }, /* RESERVED */ + { 0x4534, 0x1C }, /* RESERVED */ + { 0x4535, 0x03 }, /* RESERVED */ + { 0x4538, 0x1C }, /* RESERVED */ + { 0x4539, 0x1C }, /* RESERVED */ + { 0x453A, 0x1C }, /* RESERVED */ + { 0x453B, 0x1C }, /* RESERVED */ + { 0x453C, 0x1C }, /* RESERVED */ + { 0x453D, 0x1C }, /* RESERVED */ + { 0x453E, 0x1C }, /* RESERVED */ + { 0x453F, 0x1C }, /* RESERVED */ + { 0x4540, 0x1C }, /* RESERVED */ + { 0x4541, 0x03 }, /* RESERVED */ + { 0x4542, 0x03 }, /* RESERVED */ + { 0x4543, 0x03 }, /* RESERVED */ + { 0x4544, 0x03 }, /* RESERVED */ + { 0x4545, 0x03 }, /* RESERVED */ + { 0x4546, 0x03 }, /* RESERVED */ + { 0x4547, 0x03 }, /* RESERVED */ + { 0x4548, 0x03 }, /* RESERVED */ + { 0x4549, 0x03 }, /* RESERVED */ +}; + +#define IMX662_INIT_SEQ_LEN (sizeof(g_imx662_init_seq) / sizeof(g_imx662_init_seq[0])) + +#endif /* IMX662_CFG_H */ diff --git a/sensors/cv610/imx662/imx662_cmos.c b/sensors/cv610/imx662/imx662_cmos.c index 329c9f97..56d87402 100644 --- a/sensors/cv610/imx662/imx662_cmos.c +++ b/sensors/cv610/imx662/imx662_cmos.c @@ -119,7 +119,17 @@ static td_s32 cmos_get_ae_default(ot_vi_pipe vi_pipe, ot_isp_ae_sensor_default * * zero makes the AE library emit 1, below the ISP's legal minimum 256. */ ae_sns_dft->isp_dgain_shift = 8; ae_sns_dft->min_isp_dgain_target = 1u << ae_sns_dft->isp_dgain_shift; - ae_sns_dft->max_isp_dgain_target = 32u << ae_sns_dft->isp_dgain_shift; + /* ISP digital gain is the worst gain in the chain: it amplifies the noise + * and the quantisation equally and buys no SNR, where analog gain and HCG + * at least act before the ADC. 32x let the total ceiling reach 398 * 32 + * = 12739x (~82 dB), and on the .181 bench a dark room at that ceiling was + * judged "super grainy" while 1-2 steps down looked better. 4x puts the + * ceiling at 398 * 4 = 1592x (~64 dB), inside the range that was preferred, + * and makes AE exhaust analog before it reaches for digital. + * + * This is an operator trade -- darker but cleaner -- so it is also live at + * /api/v1/iq/set?exposure.auto.ispd_gain_max= for tuning by eye. */ + ae_sns_dft->max_isp_dgain_target = 4u << ae_sns_dft->isp_dgain_shift; switch (sns_state->wdr_mode) { case OT_WDR_MODE_NONE: @@ -232,7 +242,11 @@ static td_void cmos_dgain_calc_table(ot_vi_pipe vi_pipe, td_u32 *dgain_lin, td_u *dgain_db = 0; } -/* gain register at fast-update i2c_data[3..4]. */ +/* Conversion-gain state, per pipe. Held here rather than derived fresh each + * frame so the hysteresis below has something to latch against. */ +static td_bool g_imx662_hcg_on[OT_ISP_MAX_PIPE_NUM] = { 0 }; + +/* gain register at fast-update i2c_data[3..4], conversion gain at [8]. */ static td_void cmos_gains_update(ot_vi_pipe vi_pipe, td_u32 again, td_u32 dgain) { ot_isp_sns_state *sns_state = imx662_get_ctx(vi_pipe); @@ -247,6 +261,43 @@ static td_void cmos_gains_update(ot_vi_pipe vi_pipe, td_u32 again, td_u32 dgain) reg = IMX662_GAIN_REG_MAX; } + /* Dual conversion gain. HCG lowers read noise; it also multiplies the + * frame by ~5.8x, so the written code must give that back or AE has no + * fixed point in the band where it engages (see imx662_cmos.h). + * + * `reg` arrives as the TOTAL gain the AE asked for, so subtracting the + * offset keeps cmos_again_calc_table()'s reported again_lin -- and hence + * the ISP's ISO bucket, which indexes the sharpen, saturation and NR + * tables -- describing the gain actually delivered. + * + * Slot 8 is linear-mode only: ClearHDR needs 3030h = 02h and a matching + * FDG_SEL1 (3031h) that has no slot here, so stamping 0/1 every frame + * would silently corrupt an HDR blend. cmos_set_wdr_mode() rejects every + * non-linear mode today; this keeps that true if it stops doing so. */ + if (sns_state->wdr_mode == OT_WDR_MODE_NONE) { + if (!g_imx662_hcg_on[vi_pipe] && reg >= IMX662_HCG_ON_REG) { + g_imx662_hcg_on[vi_pipe] = TD_TRUE; + } else if (g_imx662_hcg_on[vi_pipe] && reg < IMX662_HCG_OFF_REG) { + g_imx662_hcg_on[vi_pipe] = TD_FALSE; + } + if (g_imx662_hcg_on[vi_pipe]) { + /* Test BEFORE subtracting: reg is unsigned, so an underflow + * would wrap to a huge value that a post-subtraction floor + * check reads as "above the floor" and lets through. The + * hysteresis makes this unreachable (latched implies + * reg >= OFF_REG, and the header asserts + * OFF_REG - OFFSET >= the floor), but a guard that cannot + * catch the case it names is worse than no guard. */ + if (reg < IMX662_HCG_GAIN_OFFSET + IMX662_HCG_GAIN_REG_MIN) { + reg = IMX662_HCG_GAIN_REG_MIN; + } else { + reg -= IMX662_HCG_GAIN_OFFSET; + } + } + sns_state->regs_info[0].i2c_data[8].data = + g_imx662_hcg_on[vi_pipe] ? IMX662_FDG_HCG : IMX662_FDG_LCG; + } + sns_state->regs_info[0].i2c_data[3].data = low_8bits(reg); sns_state->regs_info[0].i2c_data[4].data = high_8bits(reg); } @@ -319,7 +370,15 @@ static td_s32 cmos_get_awb_default(ot_vi_pipe vi_pipe, ot_isp_awb_sensor_default awb_sns_dft->wb_para[5] = IMX662_AWB_C1; (td_void)memcpy_s(&awb_sns_dft->ccm, sizeof(awb_sns_dft->ccm), &g_imx662_awb_ccm, sizeof(g_imx662_awb_ccm)); - /* TODO(tuning): ISO-dependent saturation and IR-cut-aware day/night bank. */ + /* Without the agc_tbl copy the memset above leaves agc_tbl.valid = 0 and + * every saturation entry 0, so the ISP is never told what saturation to + * run. The sector copy is seeded but inert: g_imx662_color_sector.valid + * is 0, so the ISP ignores the hue/sat shifts until that is raised. */ + (td_void)memcpy_s(&awb_sns_dft->agc_tbl, sizeof(awb_sns_dft->agc_tbl), + &g_imx662_awb_agc_table, sizeof(g_imx662_awb_agc_table)); + (td_void)memcpy_s(&awb_sns_dft->sector, sizeof(awb_sns_dft->sector), + &g_imx662_color_sector, sizeof(g_imx662_color_sector)); + /* TODO(tuning): IR-cut-aware day/night bank. */ return TD_SUCCESS; } @@ -342,17 +401,51 @@ static td_s32 cmos_get_isp_default(ot_vi_pipe vi_pipe, ot_isp_cmos_default *isp_ sns_check_pointer_return(sns_state); (td_void)memset_s(isp_def, sizeof(ot_isp_cmos_default), 0, sizeof(ot_isp_cmos_default)); - /* TODO(tuning): assign noise / demosaic / sharpen / gamma / - * drc / dpc / shading blocks. These get you from "flat" to "good". */ /* ot_isp_cmos_alg_key holds its bitfields directly, not under a .bits - * member. All keys default to 0 from the memset above, which disables every - * ISP block and yields a flat image -- the in-tree cv6xx drivers enable - * demosaic / sharpen / drc / bayer_nr / anti_false_color / cac / ldci here - * (cf. sc450ai_cmos.c:911-923). Left off until first light, so the raw path - * can be judged without the ISP in the way. */ - isp_def->key.bit1_ca = 0; - isp_def->key.bit1_dpc = 0; - isp_def->sns_mode.sns_id = 0; + * member. Everything is 0 from the memset above, so a block is off unless + * it is turned on here -- and each key needs its parameter table, or the + * ISP reads a null pointer. + * + * Linear mode only; cmos_set_wdr_mode() rejects every other WDR mode. + * + * Everything enabled below comes from sc450ai, which targets this same ISP + * silicon; see imx662_cmos_param.h for which of it transfers on principle + * and which is borrowed noise tuning kept on a hardware A/B. + * + * Still off, each for its own reason: lsc needs a per-module shading + * capture, and dpc is enabled in sc450ai's common path and is a candidate + * here but has not been measured on this sensor yet. */ + isp_def->key.bit1_demosaic = 1; + isp_def->demosaic = &g_cmos_demosaic; + isp_def->key.bit1_gamma = 1; + isp_def->gamma = &g_cmos_gamma; + isp_def->key.bit1_clut = 1; + isp_def->clut = &g_cmos_clut; + isp_def->key.bit1_anti_false_color = 1; + isp_def->anti_false_color = &g_cmos_anti_false_color; + isp_def->key.bit1_cac = 1; + isp_def->cac = &g_cmos_cac; + isp_def->key.bit1_ldci = 1; + isp_def->ldci = &g_cmos_ldci; + isp_def->key.bit1_dehaze = 1; + isp_def->dehaze = &g_cmos_dehaze; + isp_def->key.bit1_ca = 1; + isp_def->ca = &g_cmos_ca; + isp_def->key.bit1_bayer_nr = 1; + isp_def->bayer_nr = &g_cmos_bayer_nr; + isp_def->key.bit1_sharpen = 1; + isp_def->sharpen = &g_cmos_yuv_sharpen; + isp_def->key.bit1_drc = 1; + isp_def->drc = &g_cmos_drc; + (td_void)memcpy_s(&isp_def->noise_calibration, sizeof(ot_isp_noise_calibration), + &g_cmos_noise_calibration, sizeof(ot_isp_noise_calibration)); + + /* The ISP identifies the sensor by these. sns_id was 0, which disagrees + * with cv610_pipeline.c's IMX662_SNS_ID -- that file already documents + * the two as having to match -- and would misbind any future PQ .bin, + * which is chip- and sensor-locked. sns_mode was never set at all. */ + isp_def->sns_mode.sns_id = IMX662_ID; + isp_def->sns_mode.sns_mode = sns_state->img_mode; return TD_SUCCESS; } @@ -404,16 +497,20 @@ static td_s32 cmos_set_wdr_mode(ot_vi_pipe vi_pipe, td_u8 mode) static td_void cmos_comm_sns_reg_info_init(ot_vi_pipe vi_pipe, ot_isp_sns_state *sns_state) { td_u32 i; - const td_u16 reg_addr[8] = { + /* Sized from the initializer so adding a slot cannot silently overflow; + * reg_num below is derived from it for the same reason. */ + const td_u16 reg_addr[] = { IMX662_REG_SHR0_L, IMX662_REG_SHR0_M, IMX662_REG_SHR0_H, /* 0..2 exposure */ IMX662_REG_GAIN_L, IMX662_REG_GAIN_H, /* 3..4 gain */ - IMX662_REG_VMAX_L, IMX662_REG_VMAX_M, IMX662_REG_VMAX_H /* 5..7 vmax */ + IMX662_REG_VMAX_L, IMX662_REG_VMAX_M, IMX662_REG_VMAX_H, /* 5..7 vmax */ + IMX662_REG_FDG_SEL0 /* 8 HCG/LCG */ }; sns_state->regs_info[0].sns_type = OT_ISP_SNS_TYPE_I2C; sns_state->regs_info[0].com_bus.i2c_dev = g_imx662_bus_info[vi_pipe].i2c_dev; sns_state->regs_info[0].cfg2_valid_delay_max = 2; - sns_state->regs_info[0].reg_num = 8; + sns_state->regs_info[0].reg_num = + (td_u32)(sizeof(reg_addr) / sizeof(reg_addr[0])); for (i = 0; i < sns_state->regs_info[0].reg_num; i++) { sns_state->regs_info[0].i2c_data[i].update = TD_TRUE; @@ -503,6 +600,11 @@ static td_void sensor_global_init(ot_vi_pipe vi_pipe) sizeof(ot_isp_sns_regs_info)); (td_void)memset_s(&sns_state->regs_info[1], sizeof(ot_isp_sns_regs_info), 0, sizeof(ot_isp_sns_regs_info)); + /* Conversion-gain latch is per-session state, reset alongside regs_info. + * A reinit landing while the scene is still dark would otherwise assert + * HCG on frame 1 with no gain measurement behind it -- with the offset + * compensation now applied, that is a 5.8x exposure error. */ + g_imx662_hcg_on[vi_pipe] = TD_FALSE; } static td_s32 cmos_init_sensor_exp_function(ot_isp_sns_exp_func *sensor_exp_func) diff --git a/sensors/cv610/imx662/imx662_cmos.h b/sensors/cv610/imx662/imx662_cmos.h index 3c273be8..4be8f586 100644 --- a/sensors/cv610/imx662/imx662_cmos.h +++ b/sensors/cv610/imx662/imx662_cmos.h @@ -56,11 +56,17 @@ extern "C" { #define IMX662_REG_HMAX_H 0x302D #define IMX662_REG_FDG_SEL0 0x3030 /* conversion gain HCG/LCG select */ #define IMX662_REG_LANEMODE 0x3040 /* 0x01 = 2-lane, 0x03 = 4-lane */ /* VERIFY */ -#define IMX662_REG_SHR0_L 0x3050 /* SHR0 [23:0] exposure */ +#define IMX662_REG_SHR0_L 0x3050 /* SHR0 [19:0] exposure */ #define IMX662_REG_SHR0_M 0x3051 #define IMX662_REG_SHR0_H 0x3052 -#define IMX662_REG_GAIN_L 0x306C /* analog gain [15:0], 0.3 dB / LSB */ -#define IMX662_REG_GAIN_H 0x306D +/* GAIN[10:0], 0.3 dB / LSB, 0.0..72 dB. Sony's register list (IMX662 + * Register.xlsx, and SRM Rev3.0) puts GAIN at 3070h/3071h and jumps straight + * from 3069h to 3070h -- 306Ch/306Dh are not registers at all, so the gain + * writes landed nowhere and analog gain never actuated. The vendor's own + * reference driver carries the same wrong pair; do not "restore" it. + * 3072h/3073h and 3074h/3075h are GAIN_1/GAIN_2 (DOL per-frame), not this. */ +#define IMX662_REG_GAIN_L 0x3070 +#define IMX662_REG_GAIN_H 0x3071 #define IMX662_REG_BLKLEVEL_L 0x30DC /* black level (OFFSET), default 0x32=50 */ #define IMX662_REG_BLKLEVEL_H 0x30DD #define IMX662_REG_DIG_CLAMP 0x3458 /* digital clamp */ /* VERIFY */ @@ -84,10 +90,59 @@ extern "C" { #define IMX662_MIN_SHR0_HDR 10u /* min shutter (Clear-HDR) */ #define IMX662_AGAIN_MIN 1024u /* 1x (0 dB) */ -#define IMX662_AGAIN_MAX (1024u * 3981u / 10u) /* ~72 dB, VERIFY */ +/* 398x = 52 dB, NOT the ~72 dB the old comment claimed -- the /10 makes it a + * factor of 10 (20 dB) smaller than 10^(72/20). Left at 52 dB deliberately: + * IMX662_GAIN_REG_MAX (240 codes x 0.3 dB) does allow 72 dB, but the measured + * complaint on this bench is too much gain, not too little. Raise this only + * together with the ISP-digital cap below, and A/B it -- the two together set + * the total ceiling. */ +#define IMX662_AGAIN_MAX (1024u * 3981u / 10u) /* 398x = 52 dB */ #define IMX662_GAIN_STEP_MDB 30 /* 0.3 dB, in milli-dB */ #define IMX662_GAIN_REG_MAX 240u /* 72 dB / 0.3 dB */ +/* Dual conversion gain. + * + * HCG is NOT brightness-neutral. The GAIN register is PGA gain applied after + * the conversion gain, so the two multiply: asserting FDG_SEL0=1 at an + * unchanged code brightens the frame by the conversion-efficiency ratio. The + * datasheet gives that ratio directly -- Rcg (HCG/LCG) min 5.6, typ 5.8, max + * 6.0, corroborated by the electro-optical table's G sensitivity, HCG 18383 vs + * LCG 3166 Digit/lx/s = 5.81x. 5.8x is 15.3 dB, and at 0.3 dB per code that + * is IMX662_HCG_GAIN_OFFSET below. + * + * Sony's 22h (34-code) floor is NOT the conversion gain -- that reading would + * require a 51-code floor. It is a saturation constraint: Vsat is 3895 digits + * in LCG against 1204 in HCG, a ratio of 3.235, and 34 codes x 0.3 dB = 10.2 dB + * = 3.236x. The floor exists so HCG's clip level refills the ADC to LCG's. + * + * So a write must subtract the offset while HCG is selected, and the thresholds + * must sit where the compensated code still clears the floor: a stable HCG + * solution needs (requested - 51) >= 34, i.e. requested >= 85. Latching on + * below that has no fixed point -- AE brightens 5.8x, slams the code down past + * the floor, HCG drops out, the frame goes dark, and it limit-cycles. That + * band is ordinary dim-indoor light, between the daylight and dark-room cases + * that are easy to test. */ +#define IMX662_HCG_GAIN_OFFSET 51u /* 15.3 dB / 0.3 dB per code */ +#define IMX662_HCG_GAIN_REG_MIN 34u /* 10.2 dB; SRM lower bound */ +#define IMX662_HCG_ON_REG 91u /* requested; writes 40 */ +#define IMX662_HCG_OFF_REG 85u /* requested; writes 34 = floor */ +#define IMX662_FDG_LCG 0x00u +#define IMX662_FDG_HCG 0x01u + +/* The floor is held by the OFF threshold, not by the clamp in + * cmos_gains_update(); keep them consistent if either is ever retuned. */ +/* Signed: all three macros are u-suffixed, so an unsigned subtraction wraps and + * the assert passes clean for exactly the retune that breaks it (OFF_REG below + * OFFSET). Lowering OFF_REG is the natural response to "HCG drops out too + * eagerly", and it re-enters the unstable band the block above warns about. */ +typedef char imx662_hcg_off_clears_floor[ + ((int)IMX662_HCG_OFF_REG - (int)IMX662_HCG_GAIN_OFFSET >= + (int)IMX662_HCG_GAIN_REG_MIN) ? 1 : -1]; +/* An inverted pair would toggle conversion gain every frame -- a visible 5.8x + * flicker at frame rate -- and nothing else rejects it. */ +typedef char imx662_hcg_hysteresis_ordered[ + (IMX662_HCG_ON_REG > IMX662_HCG_OFF_REG) ? 1 : -1]; + /* ---- resolution modes ----------------------------------------------------- * Bring linear up first. Add Clear-HDR (2-frame) as a second mode later. */ diff --git a/sensors/cv610/imx662/imx662_cmos_param.h b/sensors/cv610/imx662/imx662_cmos_param.h index 835400af..731cfb29 100644 --- a/sensors/cv610/imx662/imx662_cmos_param.h +++ b/sensors/cv610/imx662/imx662_cmos_param.h @@ -100,4 +100,1450 @@ * - Final CCM after verifying HiSilicon's sign/format + saturation. */ + +/* ========================================================================== + * ISP algorithm defaults + * + * cmos_get_isp_default() used to hand the ISP a zeroed ot_isp_cmos_default, + * which leaves every algorithm key at 0 and therefore runs the pipeline with + * demosaic, gamma, CLUT, LDCI, CAC, anti-false-colour, dehaze and CA all + * switched off. That is what "flat" looked like. + * + * The tables below are the linear-mode set from the in-tree Hi3516CV610 + * driver smart_sc450ai (sc450ai_cmos_param.h), which targets this exact ISP + * silicon. They are ported verbatim. + * + * PROVENANCE MATTERS HERE. These describe how the ISP behaves, not how the + * IMX662 behaves, which is why this group transfers: gamma is a tone curve, + * CLUT a colour lookup, CAC/anti-false-colour/demosaic are interpolation + * artefact controls. Nothing in this group is fitted to sc450ai's noise. + * The blocks that ARE fitted to sensor noise -- bayer_nr, sharpen and the + * noise_calibration polynomial -- are deliberately NOT here; sc450ai is a + * 4 MP sensor and IMX662 a 2 MP STARVIS with different pixel noise, so + * those need their own calibration rather than a copy. + * + * Verified on the 192.168.2.181 bench, 2026-08-16. + * ========================================================================== */ + +static const ot_isp_demosaic_attr g_cmos_demosaic = { + 1, /* en */ + OT_OP_MODE_AUTO, /* op_type */ + 128, /* aidm_blend_ratio */ + { + 48, /* nddm_strength */ + 64, /* nddm_mf_detail_strength */ + { 0 }, /* hf_detail_strength */ + 2, /* detail_smooth_range */ + 0, /* color_noise_f_threshold */ + 8, /* color_noise_f_strength */ + 1, /* color_noise_y_threshold */ + 10, /* color_noise_y_strength */ + }, + { + /* nddm_strength */ + { 48, 48, 48, 54, 54, 54, 48, 40, 40, 48, 48, 48, 48, 48, 48, 48 }, + /* nddm_mf_detail_strength */ + { 82, 74, 68, 60, 54, 50, 44, 40, 40, 40, 40, 32, 16, 16, 16, 16 }, + /* hf_detail_strength */ + { + { 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + }, + /* detail_smooth_range */ + { 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 7, 7, 7, 7 }, + /* color_noise_f_threshold */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* color_noise_f_strength */ + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + /* color_noise_y_threshold */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* color_noise_y_strength */ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, + } +}; + +static const ot_isp_anti_false_color_attr g_cmos_anti_false_color = { + 1, /* en */ + OT_OP_MODE_AUTO, /* op_type */ + { 8, 8 }, /* manual_attr */ + { + { 20, 10, 8, 8, 7, 7, 7, 6, 6, 6, 5, 4, 3, 2, 1, 0 }, /* anti_false_color_threshold */ + { 24, 12, 8, 8, 7, 7, 7, 6, 6, 6, 5, 4, 3, 2, 1, 0 }, /* anti_false_color_strength */ + } +}; + +static const ot_isp_cac_attr g_cmos_cac = { + 1, /* en */ + OT_OP_MODE_AUTO, /* op_type */ + 1, /* detect_mode */ + 35, /* purple_upper_limit */ + (-15), /* purple_lower_limit */ + /* acac_cfg */ + { + { + {10, 300}, /* edge_threshold */ + 16, /* edge_gain */ + 3, /* cac_rb_strength */ + 63, /* purple_alpha */ + 63, /* edge_alpha */ + 25, /* satu_low_threshold */ + 16383, /* satu_high_threshold */ + }, + { + /* edge_threshold */ + { + {100, 100, 100, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150}, + {500, 500, 500, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600} + }, + /* edge_gain */ + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }, + /* cac_rb_strength */ + { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + /* purple_alpha */ + { 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + /* edge_alpha */ + { 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + /* satu_low_threshold */ + { 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 }, + /* satu_high_threshold */ + { 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, + 16383, 16383 }, + } + }, + /* lcac_cfg */ + { + 60, /* purple_detect_range */ + 200, /* var_threshold */ + { 1500, 1500, 0 }, /* r_detect_threshold */ + { 1500, 1500, 0 }, /* g_detect_threshold */ + { 4095, 1500, 0 }, /* b_detect_threshold */ + { + 0, /* de_purple_cr_strength */ + 3, /* de_purple_cb_strength */ + }, + { + /* de_purple_cr_strength */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* de_purple_cb_strength */ + { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + } + } +}; + +static const ot_isp_ldci_attr g_cmos_ldci = { + /* enable */ + 1, + /* gauss_lpf_sigma */ + 36, + /* ot_op_mode */ + 0, + + /* ot_isp_ldci_manual_attr */ + { + /* ot_isp_ldci_he_wgt_attr */ + { + /* he_pos_wgt */ + { + 50, 80, 32 + }, + /* he_neg_wgt */ + { + 60, 80, 128 + } + }, + + /* blc_ctrl */ + 20 + }, + + /* ot_isp_ldci_auto_attr */ + { + /* he_wgt[OT_ISP_AUTO_ISO_NUM] */ + { + {{48, 80, 32}, {60, 80, 128}}, + {{45, 80, 16}, {45, 80, 128}}, + {{42, 70, 0}, {45, 80, 128}}, + {{40, 70, 0}, {45, 80, 0}}, + {{35, 70, 0}, {45, 80, 0}}, + {{32, 64, 0}, {24, 72, 0}}, + {{12, 24, 0}, {12, 64, 0}}, + {{8, 20, 0}, {8, 54, 0}}, + {{6, 12, 0}, {6, 36, 0}}, + {{0, 8, 0}, {0, 8, 0}}, + {{0, 6, 0}, {0, 6, 0}}, + {{0, 2, 0}, {0, 2, 0}}, + {{0, 1, 0}, {0, 1, 0}}, + {{0, 1, 0}, {0, 1, 0}}, + {{0, 1, 0}, {0, 1, 0}}, + {{0, 1, 0}, {0, 1, 0}} + }, + + /* blc_ctrl */ + { 20, 20, 20, 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 } + }, + + /* tpr_incr_coef */ + 8, + /* tpr_decr_coef */ + 8 +}; + +static const ot_isp_gamma_attr g_cmos_gamma = { + 1, + { + 0, 13, 27, 40, 54, 68, 81, 95, 108, 121, 135, 150, 166, 180, 195, 210, 226, 242, + 259, 269, 281, 292, 303, 315, 327, 339, 352, 364, 376, 389, 402, 415, 425, 435, 446, 456, + 467, 477, 488, 499, 510, 521, 532, 543, 555, 566, 578, 591, 602, 613, 625, 636, 648, 659, + 671, 683, 695, 708, 721, 734, 748, 762, 777, 792, 809, 817, 826, 836, 845, 855, 865, 875, + 885, 896, 906, 917, 928, 939, 950, 961, 972, 983, 994, 1005, 1017, 1028, 1039, 1051, 1062, 1073, + 1085, 1096, 1107, 1118, 1129, 1140, 1151, 1161, 1172, 1182, 1193, 1203, 1213, 1223, 1234, 1244, 1254, 1264, + 1274, 1284, 1295, 1305, 1315, 1325, 1336, 1346, 1357, 1367, 1378, 1389, 1400, 1411, 1422, 1433, 1445, 1456, + 1468, 1480, 1493, 1499, 1505, 1511, 1518, 1524, 1531, 1537, 1544, 1551, 1558, 1564, 1571, 1578, 1585, 1592, + 1599, 1607, 1614, 1621, 1628, 1635, 1643, 1650, 1657, 1665, 1672, 1679, 1687, 1694, 1702, 1709, 1716, 1724, + 1731, 1738, 1746, 1753, 1761, 1768, 1775, 1783, 1790, 1797, 1804, 1811, 1819, 1826, 1833, 1840, 1847, 1854, + 1861, 1867, 1874, 1881, 1888, 1894, 1901, 1907, 1914, 1920, 1926, 1932, 1939, 1945, 1951, 1956, 1962, 1968, + 1974, 1980, 1986, 1991, 1997, 2003, 2008, 2014, 2020, 2025, 2031, 2036, 2042, 2047, 2052, 2058, 2063, 2068, + 2074, 2079, 2084, 2089, 2094, 2099, 2105, 2110, 2115, 2120, 2125, 2130, 2135, 2140, 2145, 2150, 2154, 2159, + 2164, 2169, 2174, 2179, 2183, 2188, 2193, 2198, 2202, 2207, 2212, 2217, 2221, 2226, 2231, 2235, 2240, 2244, + 2249, 2254, 2258, 2263, 2268, 2272, 2277, 2281, 2286, 2290, 2295, 2299, 2304, 2308, 2312, 2317, 2321, 2325, + 2330, 2334, 2338, 2342, 2347, 2351, 2355, 2359, 2363, 2368, 2372, 2376, 2380, 2384, 2388, 2392, 2396, 2400, + 2404, 2408, 2412, 2416, 2420, 2424, 2428, 2432, 2436, 2439, 2443, 2447, 2451, 2455, 2459, 2463, 2466, 2470, + 2474, 2478, 2482, 2485, 2489, 2493, 2497, 2500, 2504, 2508, 2512, 2515, 2519, 2523, 2527, 2530, 2534, 2538, + 2541, 2545, 2548, 2552, 2556, 2559, 2563, 2566, 2570, 2574, 2577, 2581, 2584, 2588, 2591, 2594, 2598, 2601, + 2605, 2608, 2612, 2615, 2618, 2622, 2625, 2629, 2632, 2635, 2639, 2642, 2645, 2649, 2652, 2655, 2659, 2662, + 2665, 2668, 2672, 2675, 2678, 2681, 2685, 2688, 2691, 2694, 2698, 2701, 2704, 2707, 2710, 2714, 2717, 2720, + 2723, 2727, 2730, 2733, 2736, 2739, 2743, 2746, 2749, 2752, 2755, 2758, 2762, 2765, 2768, 2771, 2774, 2777, + 2781, 2784, 2787, 2790, 2793, 2796, 2800, 2803, 2806, 2809, 2812, 2815, 2818, 2821, 2824, 2827, 2831, 2834, + 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858, 2861, 2864, 2867, 2870, 2873, 2876, 2879, 2882, 2885, 2887, + 2890, 2893, 2896, 2899, 2902, 2905, 2908, 2910, 2913, 2916, 2919, 2922, 2924, 2927, 2930, 2933, 2936, 2938, + 2941, 2944, 2946, 2949, 2952, 2954, 2957, 2960, 2962, 2965, 2967, 2970, 2972, 2975, 2978, 2980, 2983, 2985, + 2988, 2990, 2993, 2995, 2998, 3000, 3002, 3005, 3007, 3010, 3012, 3015, 3017, 3019, 3022, 3024, 3026, 3029, + 3031, 3034, 3036, 3038, 3041, 3043, 3045, 3048, 3050, 3052, 3055, 3057, 3059, 3062, 3064, 3066, 3069, 3071, + 3073, 3075, 3078, 3080, 3082, 3085, 3087, 3089, 3092, 3094, 3096, 3098, 3101, 3103, 3105, 3107, 3110, 3112, + 3114, 3116, 3119, 3121, 3123, 3125, 3128, 3130, 3132, 3134, 3136, 3139, 3141, 3143, 3145, 3147, 3149, 3152, + 3154, 3156, 3158, 3160, 3162, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3182, 3184, 3186, 3188, 3190, + 3192, 3194, 3196, 3198, 3201, 3203, 3205, 3207, 3209, 3211, 3213, 3215, 3217, 3219, 3221, 3223, 3225, 3227, + 3230, 3232, 3234, 3236, 3238, 3240, 3242, 3244, 3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 3262, 3264, + 3266, 3268, 3270, 3272, 3274, 3276, 3278, 3280, 3282, 3283, 3285, 3287, 3289, 3291, 3293, 3295, 3297, 3299, + 3301, 3303, 3305, 3307, 3309, 3311, 3312, 3314, 3316, 3318, 3320, 3322, 3324, 3326, 3328, 3330, 3332, 3334, + 3335, 3337, 3339, 3341, 3343, 3345, 3347, 3349, 3351, 3353, 3355, 3356, 3358, 3360, 3362, 3364, 3366, 3368, + 3370, 3371, 3373, 3375, 3377, 3379, 3381, 3382, 3384, 3386, 3388, 3390, 3392, 3393, 3395, 3397, 3399, 3401, + 3403, 3404, 3406, 3408, 3410, 3412, 3413, 3415, 3417, 3419, 3421, 3423, 3424, 3426, 3428, 3430, 3432, 3434, + 3435, 3437, 3439, 3441, 3443, 3445, 3447, 3448, 3450, 3452, 3454, 3456, 3458, 3460, 3462, 3464, 3466, 3468, + 3470, 3472, 3474, 3475, 3477, 3479, 3481, 3483, 3486, 3488, 3490, 3492, 3494, 3496, 3498, 3500, 3502, 3504, + 3506, 3508, 3510, 3512, 3514, 3517, 3519, 3521, 3523, 3525, 3527, 3529, 3531, 3533, 3536, 3538, 3540, 3542, + 3544, 3546, 3548, 3550, 3553, 3555, 3557, 3559, 3561, 3563, 3565, 3568, 3570, 3572, 3574, 3576, 3578, 3580, + 3582, 3585, 3587, 3589, 3591, 3593, 3595, 3597, 3599, 3601, 3603, 3605, 3608, 3610, 3612, 3614, 3616, 3618, + 3620, 3622, 3624, 3626, 3628, 3630, 3632, 3634, 3636, 3638, 3640, 3642, 3645, 3647, 3649, 3651, 3653, 3655, + 3657, 3659, 3661, 3663, 3665, 3667, 3669, 3671, 3673, 3675, 3677, 3679, 3681, 3683, 3685, 3687, 3689, 3691, + 3693, 3695, 3697, 3699, 3701, 3704, 3706, 3708, 3710, 3712, 3714, 3716, 3718, 3720, 3722, 3724, 3726, 3728, + 3730, 3732, 3734, 3736, 3738, 3740, 3742, 3744, 3746, 3748, 3750, 3752, 3754, 3756, 3758, 3760, 3762, 3764, + 3766, 3767, 3769, 3771, 3773, 3775, 3777, 3779, 3781, 3783, 3785, 3787, 3789, 3791, 3793, 3795, 3797, 3799, + 3801, 3803, 3804, 3806, 3808, 3810, 3812, 3814, 3816, 3818, 3820, 3822, 3824, 3826, 3828, 3830, 3832, 3834, + 3836, 3837, 3839, 3841, 3843, 3845, 3847, 3849, 3851, 3853, 3855, 3857, 3858, 3860, 3862, 3864, 3866, 3868, + 3870, 3872, 3873, 3875, 3877, 3879, 3881, 3883, 3885, 3887, 3888, 3890, 3892, 3894, 3896, 3898, 3900, 3902, + 3904, 3905, 3907, 3909, 3911, 3913, 3915, 3917, 3919, 3920, 3922, 3924, 3926, 3928, 3930, 3932, 3934, 3935, + 3937, 3939, 3941, 3943, 3945, 3947, 3949, 3950, 3952, 3954, 3955, 3957, 3959, 3961, 3963, 3965, 3967, 3969, + 3971, 3972, 3974, 3976, 3977, 3979, 3981, 3983, 3985, 3987, 3989, 3991, 3993, 3994, 3996, 3998, 4000, 4001, + 4003, 4005, 4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4023, 4025, 4027, 4028, 4030, 4032, 4034, + 4036, 4037, 4039, 4041, 4042, 4044, 4046, 4048, 4050, 4052, 4054, 4056, 4058, 4059, 4061, 4063, 4064, 4066, + 4068, 4070, 4072, 4073, 4075, 4077, 4078, 4080, 4082, 4084, 4086, 4087, 4089, 4091, 4092, 4094, 4095, + }, + 3, +}; + +static const ot_isp_dehaze_attr g_cmos_dehaze = { + /* enable */ + 0, + /* user_lut_enable */ + 0, + /* dehaze_lut */ + { + 0, 9, 13, 17, 21, 25, 29, 33, 37, 42, 46, 50, 54, 58, 62, 67, 71, 75, 79, 83, 87, 91, + 95, 99, 102, 106, 110, 114, 117, 121, 124, 128, 131, 134, 137, 141, 144, 147, 150, + 153, 156, 159, 162, 165, 168, 170, 173, 176, 178, 181, 184, 186, 189, 191, 193, 196, + 198, 200, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 222, 224, 226, 228, 229, + 231, 232, 234, 235, 237, 238, 240, 241, 242, 243, 244, 246, 247, 248, 249, 249, 250, + 251, 252, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 253, 252, 251, 251, 250, 249, + 249, 248, 247, 247, 246, 245, 244, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, + 233, 232, 231, 230, 229, 227, 226, 225, 223, 222, 221, 219, 218, 216, 215, 213, 212, + 210, 209, 208, 206, 205, 203, 201, 200, 198, 197, 195, 193, 192, 190, 188, 187, 185, + 183, 181, 180, 178, 176, 174, 172, 170, 169, 167, 165, 163, 161, 159, 157, 155, 153, + 151, 149, 147, 145, 143, 140, 138, 136, 134, 132, 130, 128, 125, 123, 121, 119, 116, + 114, 112, 110, 107, 105, 103, 100, 98, 96, 93, 91, 89, 86, 84, 81, 79, 77, 74, 72, 69, + 67, 64, 62, 59, 57, 54, 52, 49, 47, 44, 42, 39, 37, 34, 31, 29, 26, 24, 21, 18, 16, 13, 11, + 8, 5, 3, 0 + }, + /* op_type */ + 0, + /* manual_strength */ + { + 128 + }, + /* auto_strength */ + { + 128 + }, + /* tmprflt_incr_coef */ + 8, + /* tmprflt_decr_coef */ + 64, +}; + +static const ot_isp_ca_attr g_cmos_ca = { + /* CA */ + 1, + 0, + { + { + 36, 81, 111, 136, 158, 182, 207, 228, 259, 290, 317, 345, 369, 396, 420, 444, 468, 492, 515, 534, + 556, 574, 597, 614, 632, 648, 666, 681, 697, 709, 723, 734, 748, 758, 771, 780, 788, 800, 808, + 815, 822, 829, 837, 841, 848, 854, 858, 864, 868, 871, 878, 881, 885, 890, 893, 897, 900, 903, + 906, 909, 912, 915, 918, 921, 924, 926, 929, 931, 934, 936, 938, 941, 943, 945, 947, 949, 951, + 952, 954, 956, 958, 961, 962, 964, 966, 968, 969, 970, 971, 973, 974, 976, 977, 979, 980, 981, + 983, 984, 985, 986, 988, 989, 990, 991, 992, 993, 995, 996, 997, 998, 999, 1000, 1001, 1004, + 1005, 1006, 1007, 1009, 1010, 1011, 1012, 1014, 1016, 1017, 1019, 1020, 1022, 1024 + }, + /* ISO */ + { 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1000, 950, 900, 900, 800, 800, 800, 800, 800 }, + { + 811, 812, 812, 812, 812, 812, 811, 810, 810, 809, 808, 807, 807, 806, 805, 805, 804, 804, 804, 804, + 804, 805, 806, 807, 808, 810, 813, 815, 819, 822, 827, 831, 837, 843, 850, 857, 865, 874, 883, + 893, 903, 914, 925, 936, 947, 959, 971, 983, 995, 1007, 1018, 1030, 1042, 1053, 1065, 1075, + 1086, 1096, 1106, 1115, 1124, 1132, 1139, 1146, 1152, 1158, 1163, 1168, 1172, 1176, 1180, + 1183, 1186, 1189, 1192, 1194, 1196, 1198, 1200, 1201, 1202, 1204, 1205, 1206, 1207, 1208, + 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1217, 1218, 1220, 1222, 1224, 1226, 1227, 1229, + 1231, 1232, 1234, 1236, 1237, 1239, 1240, 1242, 1243, 1245, 1246, 1248, 1249, 1250, 1252, + 1253, 1255, 1256, 1258, 1259, 1260, 1262, 1263, 1265, 1266, 1268, 1269 + }, + }, + { + { + 56, 60, 64, 68, 71, 74, 77, 79, 82, 85, 87, 89, 93, 96, 99, 102, 105, 108, 110, 112, 115, 117, 119, + 120, 122, 124, 125, 127, 128, 130, 131, 133, 135, 136, 138, 141, 143, 145, 147, 150, 152, 155, + 157, 159, 162, 164, 166, 168, 171, 173, 175, 177, 179, 181, 184, 186, 188, 190, 192, 193, 195, + 197, 198, 198, 199, 198, 198, 196, 195, 193, 191, 189, 186, 184, 181, 179, 177, 174, 172, 169, + 167, 164, 161, 159, 156, 153, 151, 148, 145, 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, + 113, 110, 109, 108, 108, 109, 111, 113, 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145, + 148, 151, 154, 157, 160, 163, 166, 169, 172, 175 + }, + { + 232, 225, 219, 214, 208, 202, 197, 192, 186, 181, 176, 171, 166, 161, 156, 151, 146, 141, 136, 132, + 128, 123, 119, 115, 110, 106, 101, 97, 92, 88, 83, 79, 75, 71, 67, 64, 61, 59, 57, 55, 54, 54, + 53, 52, 51, 50, 50, 49, 48, 48, 47, 46, 46, 45, 44, 44, 43, 42, 42, 41, 41, 40, 40, 40, 40, 40, + 40, 41, 41, 42, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 64, 65, 67, 68, 70, 72, 75, 78, 81, 84, 87, 91, 94, 97, 100, 103, 106, 109, 112, 115, + 118, 121, 124, 127, 130, 133, 136, 139, 143, 146, 149, 152, 155, 159, 162, 166 + }, + { + 92, 89, 87, 85, 83, 81, 79, 77, 75, 74, 72, 72, 73, 76, 78, 80, 82, 84, 85, 87, 88, 88, 89, 89, 89, + 88, 88, 87, 87, 87, 86, 87, 87, 88, 90, 92, 94, 96, 99, 101, 103, 106, 108, 110, 113, 115, 117, + 119, 121, 123, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 147, 149, 151, 153, 155, 157, + 159, 161, 163, 165, 166, 168, 170, 172, 173, 175, 176, 178, 180, 181, 183, 185, 186, 188, 190, + 191, 193, 194, 196, 198, 200, 201, 203, 205, 207, 208, 210, 212, 214, 215, 217, 218, 219, 219, + 219, 219, 218, 216, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 194, 192, 190, 188, + 186, 184, 182, 180, 178 + }, + }, +}; + +static const ot_isp_cmos_clut g_cmos_clut = { + { + 1, + 128, + 128, + 128, + }, + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 0, 67174464, 0, 67174464, 67174464, 67174464, 67174464, 0, 67174464, + 0, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 0, 67174464, 0, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 0, 67174464, 0, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 0, 67174464, 0, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 0, 67174464, 0, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 0, 67174464, 0, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 0, 67174464, 0, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 0, + 67174464, 0, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 0, 67174464, 0, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 0, 67174464, 0, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, + 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 67174464, 0, 67174464, 0, + 67174464, 67174464, 0, 67174464, 0, 67174464, 67174464, 67174464, 0, 67174464, 67174464, + 67174464, 0, 67174464, 67174464, 67174464, 0, 67174464, 67174464, 67174464, 0, 67174464, + 67174464, 67174464, 0, 67174464, 67174464, 67174464, 0, 67174464, 67174464, 67174464, 0, 0, 0, + 0, 0, 67174464, 67174464, 0, 0, 67174464, 67174464, 0, 0, 67174464, 67174464, 0, 0, 67174464, + 67174464, 0, 0, 67174464, 67174464, 0, 0, 67174464, 67174464, 0, 0, 67174464, 67174464, 0, 0, + 67174464, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, + 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, + 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, + 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, + 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, + 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, + 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, + 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, + 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, + 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, + 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, + 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, + 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, + 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, + 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, + 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, 67174464, 0, 0, 0, + 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67174464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 67174464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + } + }, +}; + + +/* -------------------------------------------------------------------------- + * Noise-fitted blocks -- BORROWED, NOT CALIBRATED FOR THIS SENSOR. + * + * bayer_nr picks its strength from noise_calibration, a polynomial fitted to + * a specific sensor's read noise. The one below is sc450ai's: a 4 MP sensor, + * where IMX662 is 2 MP STARVIS with larger pixels and less noise per pixel. + * These were A/B'd on hardware and kept on the operator's verdict, but a + * measured IMX662 fit would still be the right thing to replace them with. + * + * sharpen reads the same noise model to decide how hard to push an edge, so + * bayer_nr and noise_calibration are not independently droppable: on a bright + * bench scene bayer_nr alone measured as a no-op, but removing it changes + * what sharpen does. + * -------------------------------------------------------------------------- */ + +static ot_isp_noise_calibration g_cmos_noise_calibration = { + { + 6400.0000000000, 0.0001279210, 0.0016242186, 0.0000000204, -0.0000027303, 0.1199406222, + 0.0001268708, 0.0040083983, -0.0000000102, 0.0001914447, 0.0227515276, 0, 0, 0, 0, 0 + } +}; + +static const ot_isp_nr_attr g_cmos_bayer_nr = { + 1, /* bEnable */ + OT_OP_MODE_AUTO, /* enOpType */ + { + 1, /* md_enable */ + }, + 0, /* lsc_nr_enable */ + 0, /* lsc_ratio1 */ + { + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 90, 90, 90, 95, 95, 95, 100, 100, 100, 100, 100 + }, /* CoringRatio */ + { + 128, 128, 128, 128, 128, 128, 110, 90, + 77, 77, 77, 77, 77, 77, 77, 77, // u1.7 x 32 (128 = 1.0f) mix_gain + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77 + }, + OT_ISP_MD_MODE, /* ref_mode */ + 0, /* load_ref_enable */ + /* snr_cfg */ + { + 0, /* snr_version */ + { + { + /* snr auto */ + { + { + {108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108}, + {108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108}, + {108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108}, + {108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108} + }, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, /* sfm0_detail_prot */ + {512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}, /* sfm1_str */ + {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, /* sfm1_adp_strength */ + {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, /* sfm6_strength */ + {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, /* sfm7_strength */ + {100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100}, /* sth */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* tss */ + {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, /* fine_str */ + {50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50}, /* coring_wgt */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* coring_mot_ratio */ + { /* noisesd_lut */ + {2, 2, 3, 3, 4, 6, 7, 15, 29, 59, 117, 234, 255, 255, 255, 255}, + {2, 2, 3, 3, 4, 6, 7, 15, 29, 59, 117, 234, 255, 255, 255, 255}, + {2, 2, 3, 3, 4, 6, 7, 15, 29, 59, 117, 234, 255, 255, 255, 255}, + {3, 4, 6, 8, 11, 15, 21, 32, 50, 82, 142, 255, 255, 255, 255, 255}, + {4, 6, 8, 11, 15, 21, 30, 43, 65, 100, 164, 255, 255, 255, 255, 255}, + {5, 7, 9, 13, 18, 26, 36, 52, 76, 116, 183, 255, 255, 255, 255, 255}, + {6, 8, 11, 15, 21, 29, 41, 60, 87, 129, 201, 255, 255, 255, 255, 255}, + {7, 9, 12, 17, 23, 33, 46, 66, 96, 142, 217, 255, 255, 255, 255, 255}, + {7, 10, 13, 18, 26, 36, 50, 72, 104, 153, 232, 255, 255, 255, 255, 255}, + {8, 10, 14, 20, 28, 39, 54, 78, 112, 164, 246, 255, 255, 255, 255, 255}, + {8, 11, 15, 21, 29, 41, 58, 83, 119, 174, 255, 255, 255, 255, 255, 255}, + {9, 12, 16, 22, 31, 44, 62, 88, 126, 183, 255, 255, 255, 255, 255, 255}, + {9, 12, 17, 23, 33, 46, 65, 93, 133, 192, 255, 255, 255, 255, 255, 255}, + {10, 13, 18, 25, 34, 48, 68, 97, 139, 201, 255, 255, 255, 255, 255, 255}, + {10, 14, 19, 26, 36, 50, 71, 101, 145, 209, 255, 255, 255, 255, 255, 255}, + {11, 14, 19, 27, 37, 53, 74, 105, 150, 217, 255, 255, 255, 255, 255, 255}, + {11, 15, 20, 28, 39, 54, 77, 109, 156, 224, 255, 255, 255, 255, 255, 255}, + {11, 15, 21, 29, 40, 56, 79, 113, 161, 232, 255, 255, 255, 255, 255, 255}, + {12, 16, 21, 30, 41, 58, 82, 117, 166, 239, 255, 255, 255, 255, 255, 255}, + {12, 16, 22, 30, 43, 60, 85, 120, 171, 246, 255, 255, 255, 255, 255, 255}, + {13, 17, 23, 31, 44, 62, 87, 124, 176, 252, 255, 255, 255, 255, 255, 255}, + {13, 17, 23, 32, 45, 63, 89, 127, 181, 255, 255, 255, 255, 255, 255, 255}, + {13, 17, 24, 33, 46, 65, 92, 130, 185, 255, 255, 255, 255, 255, 255, 255}, + {14, 18, 24, 34, 47, 67, 94, 133, 190, 255, 255, 255, 255, 255, 255, 255}, + {14, 18, 25, 35, 48, 68, 96, 137, 194, 255, 255, 255, 255, 255, 255, 255}, + {14, 19, 26, 35, 50, 70, 98, 140, 198, 255, 255, 255, 255, 255, 255, 255}, + {14, 19, 26, 36, 51, 71, 100, 143, 203, 255, 255, 255, 255, 255, 255, 255}, + {15, 19, 27, 37, 52, 73, 102, 146, 207, 255, 255, 255, 255, 255, 255, 255}, + {15, 20, 27, 38, 53, 74, 104, 148, 211, 255, 255, 255, 255, 255, 255, 255}, + {15, 20, 28, 38, 54, 75, 106, 151, 215, 255, 255, 255, 255, 255, 255, 255}, + {16, 21, 28, 39, 55, 77, 108, 154, 219, 255, 255, 255, 255, 255, 255, 255}, + {16, 21, 29, 40, 56, 78, 110, 157, 222, 255, 255, 255, 255, 255, 255, 255} + }, + }, + + /* snr manual */ + { + { 108, 108, 108, 108 }, /* snr_sfm0_coarstr */ + 16, /* sfm0_detail_prot */ + 512, /* sfm1_str */ + 2, /* sfm1_adp_strength */ + 64, /* sfm6_strength */ + 64, /* sfm7_strength */ + 100, /* sth */ + 0, /* tss */ + 128, /* fine_str */ + 50, /* coring_wgt */ + 0, /* coring_mot_ratio */ + { + 7, 7, 7, 21, 29, 35, 40, 45, 49, 53, 56, 60, 63, 66, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107 + }, /* noisesd_lut */ + }, + }, + }, + }, + /* md_cfg */ + { + .md_cfg = { + /* md auto */ + { + {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, /* md_mode */ + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, /* md_size_ratio */ + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, /* md_anti_flicker_str */ + {26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26}, /* md_static_ratio */ + {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}, /* md_motion_ratio */ + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, /* md_static_finestr */ + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, /* tnr_tfs */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* user_define_md */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* user_define_slope */ + {90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90}, /* user_define_dark_thresh */ + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, /* user_define_color_thresh */ + {26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26}, /* sfr_r */ + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, /* sfr_g */ + {26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26} /* sfr_b */ + }, + + /* md_manual */ + { + 2, /* md_mode */ + 32, /* md_size_ratio */ + 32, /* md_anti_flicker_str */ + 26, /* md_static_ratio */ + 13, /* md_motion_ratio */ + 32, /* md_static_finestr */ + 255, /* tnr_tfs */ + 0, /* user_define_md */ + 0, /* user_define_bright_thresh */ + 90, /* user_define_dark_thresh */ + 16, /* user_define_color_thresh */ + 26, /* sfr_r */ + 32, /* sfr_g */ + 26 /* sfr_b */ + }, + }, + }, + /* wdr_cfg */ + { + {16, 16, 16, 16}, /* sfm0_wdr_frame_str */ + {16, 16, 16, 16}, /* sfm0_fusion_frame_str */ + {64, 16, 16, 16}, /* snr_wdr_sfm6_strength */ + {64, 16, 16, 16}, /* snr_wdr_sfm7_strength */ + {64, 16, 16, 16}, /* snr_fusion_sfm6_strength */ + {64, 16, 16, 16}, /* snr_fusion_sfm7_strength */ + {16, 16, 16, 16}, /* md_wdr_frame_str */ + {16, 16, 16, 16}, /* md_fusion_frame_str */ + }, + /* dering_cfg */ + { + { + {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, /* dering_strength */ + {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}, /* dering_thresh */ + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, /* dering_static_str */ + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, /* dering_motion_str */ + }, + { + 64, /* dering_strength */ + 64, /* dering_thresh */ + 16, /* dering_static_str */ + 16, /* dering_motion_str */ + }, + }, +}; + +static const ot_isp_sharpen_attr g_cmos_yuv_sharpen = { + /* en */ + 1, + /* motion_en */ + 0, + /* motion_threshold0 */ + 4, + /* motion_threshold1 */ + 10, + /* motion_gain0 */ + 0, + /* motion_gain1 */ + 255, + /* skin_umin */ + 99, + /* skin_vmin */ + 134, + /* skin_umax */ + 127, + /* skin_vmax */ + 150, + /* op_type */ + OT_OP_MODE_AUTO, + /* detail_map */ + OT_ISP_SHARPEN_NORMAL, + /* manual para */ + { + /* luma_wgt[OT_ISP_SHARPEN_LUMA_NUM] */ + { + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 + }, + /* texture_strength[OT_ISP_SHARPEN_GAIN_NUM] */ + { + 250, 420, 390, 390, 390, 390, 390, 370, 350, 330, 310, 290, 270, 270, 270, 270, + 270, 270, 266, 260, 244, 230, 230, 230, 230, 230, 230, 210, 190, 190, 170, 150 + }, + /* edge_strength[OT_ISP_SHARPEN_GAIN_NUM] */ + { + 120, 123, 125, 128, 130, 135, 140, 148, 160, 168, 180, 190, 200, 210, 210, 210, + 210, 210, 200, 190, 185, 175, 165, 160, 146, 136, 130, 128, 125, 123, 120, 120 + }, + /* texture_freq */ + 190, + /* edge_freq */ + 128, + /* over_shoot */ + 65, + /* under_shoot */ + 75, + /* motion_texture_strength[OT_ISP_SHARPEN_GAIN_NUM] */ + { + 250, 420, 390, 390, 390, 390, 390, 370, 350, 330, 310, 290, 270, 270, 270, 270, + 270, 270, 266, 260, 244, 230, 230, 230, 230, 230, 230, 210, 190, 190, 170, 150 + }, + /* motion_edge_strength[OT_ISP_SHARPEN_GAIN_NUM] */ + { + 120, 123, 125, 128, 130, 135, 140, 148, 160, 168, 180, 190, 200, 210, 210, 210, + 210, 210, 200, 190, 185, 175, 165, 160, 146, 136, 130, 128, 125, 123, 120, 120 + }, + /* motion_texture_freq */ + 190, + /* motion_edge_freq */ + 128, + /* motion_over_shoot */ + 65, + /* motion_under_shoot */ + 75, + /* u8shoot_sup_str */ + 7, + /* u8shoot_sup_adj */ + 9, + /* detail_ctrl */ + 128, + /* detail_ctrl_threshold */ + 180, + /* edge_filt_strength */ + 60, + /* edge_filt_max_cap */ + 18, + /* r_gain */ + 20, + /* g_gain */ + 32, + /* b_gain */ + 20, + /* skin_gain */ + 25, + /* max_sharp_gain */ + 40, + { + /* shoot_inner_threshold */ + 0, + /* shoot_outer_threshold */ + 0, + /* shoot_protect_threshold */ + 0, + }, + + { + /* edge_rly_fine_threshold */ + 0, + /* edge_rly_coarse_threshold */ + 0, + /* edge_overshoot */ + 65, + /* edge_undershoot */ + 120, + /* edge_gain_by_rly[OT_ISP_SHARPEN_RLYWGT_NUM] */ + { + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + }, + /* edge_rly_by_mot[OT_ISP_SHARPEN_STDGAIN_NUM] */ + { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + }, + /* edge_rly_by_luma[OT_ISP_SHARPEN_STDGAIN_NUM] */ + { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + }, + }, + { + /* mf_gain_by_mot[OT_ISP_SHARPEN_MOT_NUM] */ + { + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + }, + /* hf_gain_by_mot[OT_ISP_SHARPEN_MOT_NUM] */ + { + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + }, + /* lmt_gain_by_mot[OT_ISP_SHARPEN_MOT_NUM] */ + { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + }, + }, + }, + /* auto para */ + { + /* luma_wgt[OT_ISP_SHARPEN_GAIN_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + { 31, 31, 20, 20, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, + { 31, 31, 20, 20, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, + { 31, 31, 20, 20, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, + { 31, 31, 20, 20, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, + { 31, 31, 20, 20, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, + { 31, 31, 20, 20, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, + { 31, 31, 20, 20, 20, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 }, + { 31, 31, 23, 23, 23, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21 }, + { 31, 31, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 }, + { 31, 31, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 }, + { 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 28, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + { 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 } + }, + /* texture_strength[OT_ISP_SHARPEN_GAIN_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + { 153, 153, 160, 145, 110, 84, 58, 26, 10, 0, 0, 0, 0, 0, 0, 0 }, + { 172, 167, 190, 170, 123, 94, 65, 30, 12, 0, 0, 0, 0, 0, 0, 0 }, + { 186, 178, 220, 195, 140, 107, 72, 35, 14, 0, 0, 0, 0, 0, 0, 0 }, + { 201, 192, 255, 215, 153, 117, 79, 40, 16, 0, 0, 0, 0, 0, 0, 0 }, + { 217, 207, 275, 230, 170, 130, 83, 44, 18, 0, 0, 0, 0, 0, 0, 0 }, + { 233, 223, 285, 245, 178, 140, 90, 48, 19, 0, 0, 0, 0, 0, 0, 0 }, + { 251, 239, 280, 260, 191, 146, 97, 51, 20, 0, 0, 0, 0, 0, 0, 0 }, + { 269, 255, 275, 265, 204, 156, 104, 55, 22, 0, 0, 0, 0, 0, 0, 0 }, + { 286, 272, 270, 270, 212, 162, 108, 56, 22, 0, 0, 0, 0, 0, 0, 0 }, + { 300, 288, 265, 270, 212, 169, 110, 59, 24, 0, 0, 0, 0, 0, 0, 0 }, + { 308, 299, 260, 265, 212, 176, 115, 61, 24, 0, 0, 0, 0, 0, 0, 0 }, + { 312, 307, 260, 260, 212, 179, 117, 62, 25, 0, 0, 0, 0, 0, 0, 0 }, + { 313, 310, 255, 255, 208, 182, 119, 64, 26, 0, 0, 0, 0, 0, 0, 0 }, + { 311, 311, 250, 250, 204, 185, 122, 64, 26, 0, 0, 0, 0, 0, 0, 0 }, + { 306, 311, 245, 245, 204, 188, 124, 62, 26, 0, 0, 0, 0, 0, 0, 0 }, + { 297, 308, 240, 240, 204, 192, 126, 60, 25, 0, 0, 0, 0, 0, 0, 0 }, + { 285, 301, 235, 235, 200, 192, 126, 59, 25, 0, 0, 0, 0, 0, 0, 0 }, + { 273, 291, 230, 230, 196, 188, 126, 58, 25, 0, 0, 0, 0, 0, 0, 0 }, + { 263, 281, 225, 225, 191, 185, 124, 56, 24, 0, 0, 0, 0, 0, 0, 0 }, + { 255, 271, 225, 220, 187, 179, 122, 56, 24, 0, 0, 0, 0, 0, 0, 0 }, + { 249, 259, 220, 215, 183, 176, 119, 56, 24, 0, 0, 0, 0, 0, 0, 0 }, + { 243, 248, 220, 210, 178, 169, 117, 55, 24, 0, 0, 0, 0, 0, 0, 0 }, + { 234, 238, 215, 205, 174, 166, 115, 55, 23, 0, 0, 0, 0, 0, 0, 0 }, + { 224, 228, 215, 200, 170, 159, 110, 55, 23, 0, 0, 0, 0, 0, 0, 0 }, + { 216, 218, 210, 195, 166, 153, 108, 54, 22, 0, 0, 0, 0, 0, 0, 0 }, + { 208, 208, 200, 190, 162, 150, 106, 54, 22, 0, 0, 0, 0, 0, 0, 0 }, + { 201, 201, 195, 180, 153, 143, 101, 52, 22, 0, 0, 0, 0, 0, 0, 0 }, + { 195, 195, 185, 175, 149, 133, 99, 51, 22, 0, 0, 0, 0, 0, 0, 0 }, + { 188, 188, 175, 170, 144, 127, 94, 49, 21, 0, 0, 0, 0, 0, 0, 0 }, + { 181, 181, 170, 160, 136, 117, 92, 49, 20, 0, 0, 0, 0, 0, 0, 0 }, + { 175, 175, 160, 155, 132, 107, 88, 49, 20, 0, 0, 0, 0, 0, 0, 0 }, + { 171, 171, 150, 150, 128, 98, 68, 38, 20, 0, 0, 0, 0, 0, 0, 0 } + }, + /* edge_strength */ + { + { 195, 195, 195, 195, 166, 127, 127, 110, 50, 0, 0, 0, 0, 0, 0, 0 }, + { 210, 210, 200, 200, 170, 130, 130, 110, 50, 0, 0, 0, 0, 0, 0, 0 }, + { 235, 235, 220, 220, 187, 143, 143, 110, 50, 0, 0, 0, 0, 0, 0, 0 }, + { 260, 260, 230, 230, 196, 150, 150, 110, 50, 0, 0, 0, 0, 0, 0, 0 }, + { 295, 295, 240, 240, 204, 156, 156, 110, 50, 0, 0, 0, 0, 0, 0, 0 }, + { 320, 320, 250, 250, 212, 162, 162, 110, 50, 0, 0, 0, 0, 0, 0, 0 }, + { 340, 340, 260, 260, 221, 169, 169, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 350, 350, 270, 270, 230, 176, 176, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 360, 360, 280, 280, 238, 182, 182, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 360, 360, 280, 280, 238, 182, 182, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 355, 355, 285, 285, 242, 185, 185, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 345, 345, 290, 290, 246, 188, 188, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 335, 335, 290, 290, 246, 188, 188, 115, 54, 0, 0, 0, 0, 0, 0, 0 }, + { 330, 330, 295, 295, 251, 192, 192, 118, 55, 0, 0, 0, 0, 0, 0, 0 }, + { 325, 325, 295, 295, 251, 192, 192, 118, 55, 0, 0, 0, 0, 0, 0, 0 }, + { 320, 320, 295, 295, 251, 192, 192, 118, 55, 0, 0, 0, 0, 0, 0, 0 }, + { 315, 315, 295, 295, 251, 192, 192, 118, 55, 0, 0, 0, 0, 0, 0, 0 }, + { 310, 310, 295, 295, 251, 192, 192, 120, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 305, 305, 295, 295, 251, 192, 192, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 295, 295, 290, 290, 246, 188, 188, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 285, 285, 285, 285, 242, 185, 185, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 280, 280, 280, 280, 238, 182, 182, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 275, 275, 275, 275, 234, 179, 179, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 265, 265, 265, 265, 225, 172, 172, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 250, 250, 250, 250, 212, 162, 162, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 240, 240, 240, 240, 204, 156, 156, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 220, 220, 220, 220, 187, 143, 143, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 200, 200, 200, 200, 170, 130, 130, 125, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 180, 180, 180, 180, 153, 117, 117, 117, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 160, 160, 160, 160, 136, 104, 104, 104, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 140, 140, 140, 140, 119, 91, 91, 91, 58, 0, 0, 0, 0, 0, 0, 0 }, + { 125, 125, 125, 125, 106, 81, 81, 81, 58, 0, 0, 0, 0, 0, 0, 0 } + }, + /* texture_freq[OT_ISP_AUTO_ISO_NUM] */ + { 180, 190, 190, 170, 170, 170, 160, 140, 128, 128, 128, 100, 100, 100, 100, 100 }, + /* edge_freq[OT_ISP_AUTO_ISO_NUM] */ + { 128, 100, 100, 100, 100, 100, 100, 100, 100, 100, 96, 96, 96, 96, 96, 96 }, + /* over_shoot[OT_ISP_AUTO_ISO_NUM] */ + { 60, 62, 62, 64, 64, 64, 56, 52, 50, 50, 30, 10, 10, 10, 10, 10 }, + /* under_shoot[OT_ISP_AUTO_ISO_NUM] */ + { 60, 62, 62, 64, 64, 64, 54, 50, 50, 30, 20, 20, 15, 15, 15, 15 }, + /* motion_texture_strength[OT_ISP_SHARPEN_GAIN_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + { 153, 153, 160, 145, 130, 130, 130, 105, 105, 105, 105, 85, 85, 85, 85, 85 }, + { 172, 167, 190, 170, 145, 145, 145, 120, 120, 120, 120, 100, 100, 100, 100, 100 }, + { 186, 178, 220, 195, 165, 165, 160, 140, 140, 135, 135, 120, 120, 120, 120, 120 }, + { 201, 192, 255, 215, 180, 180, 175, 160, 160, 150, 150, 135, 135, 140, 140, 140 }, + { 217, 207, 275, 230, 200, 200, 185, 175, 175, 160, 160, 150, 150, 160, 160, 160 }, + { 233, 223, 285, 245, 210, 215, 200, 190, 190, 170, 170, 165, 165, 180, 180, 180 }, + { 251, 239, 280, 260, 225, 225, 215, 205, 205, 180, 180, 185, 185, 200, 200, 200 }, + { 269, 255, 275, 265, 240, 240, 230, 220, 220, 190, 190, 200, 200, 210, 210, 210 }, + { 286, 272, 270, 270, 250, 250, 240, 225, 225, 200, 200, 220, 220, 220, 220, 220 }, + { 300, 288, 265, 270, 250, 260, 245, 235, 235, 210, 210, 235, 235, 230, 230, 230 }, + { 308, 299, 260, 265, 250, 270, 255, 245, 245, 220, 220, 245, 245, 230, 230, 230 }, + { 312, 307, 260, 260, 250, 275, 260, 250, 250, 230, 230, 255, 255, 230, 230, 230 }, + { 313, 310, 255, 255, 245, 280, 265, 255, 255, 235, 235, 265, 265, 230, 230, 230 }, + { 311, 311, 250, 250, 240, 285, 270, 255, 255, 240, 240, 275, 275, 230, 230, 230 }, + { 306, 311, 245, 245, 240, 290, 275, 250, 255, 245, 245, 280, 280, 230, 230, 230 }, + { 297, 308, 240, 240, 240, 295, 280, 240, 250, 250, 250, 285, 285, 230, 230, 230 }, + { 285, 301, 235, 235, 235, 295, 280, 235, 250, 250, 255, 290, 290, 230, 230, 230 }, + { 273, 291, 230, 230, 230, 290, 280, 230, 250, 250, 260, 295, 295, 230, 230, 230 }, + { 263, 281, 225, 225, 225, 285, 275, 225, 245, 250, 265, 300, 300, 225, 225, 225 }, + { 255, 271, 225, 220, 220, 275, 270, 225, 245, 250, 270, 300, 300, 220, 220, 220 }, + { 249, 259, 220, 215, 215, 270, 265, 225, 240, 245, 275, 300, 300, 210, 210, 210 }, + { 243, 248, 220, 210, 210, 260, 260, 220, 235, 245, 280, 305, 305, 200, 200, 200 }, + { 234, 238, 215, 205, 205, 255, 255, 220, 230, 240, 280, 305, 305, 190, 190, 190 }, + { 224, 228, 215, 200, 200, 245, 245, 220, 230, 240, 285, 310, 310, 180, 180, 180 }, + { 216, 218, 210, 195, 195, 235, 240, 215, 225, 235, 285, 310, 310, 175, 175, 175 }, + { 208, 208, 200, 190, 190, 230, 235, 215, 220, 230, 285, 305, 305, 170, 170, 170 }, + { 201, 201, 195, 180, 180, 220, 225, 210, 220, 225, 285, 305, 305, 160, 160, 160 }, + { 195, 195, 185, 175, 175, 205, 220, 205, 215, 220, 285, 300, 300, 160, 160, 160 }, + { 188, 188, 175, 170, 170, 195, 210, 195, 210, 215, 280, 300, 300, 150, 150, 150 }, + { 181, 181, 170, 160, 160, 180, 205, 195, 205, 210, 280, 300, 300, 145, 145, 145 }, + { 175, 175, 160, 155, 155, 165, 195, 195, 200, 205, 275, 300, 300, 130, 130, 130 }, + { 171, 171, 150, 150, 150, 150, 150, 150, 195, 200, 270, 300, 300, 115, 115, 115 } + }, + /* motion_edge_strength */ + { + { 195, 195, 195, 195, 195, 195, 400, 440, 500, 475, 475, 475, 475, 475, 475, 475 }, + { 210, 210, 200, 200, 200, 200, 400, 440, 500, 485, 485, 485, 485, 485, 485, 485 }, + { 235, 235, 220, 220, 220, 220, 400, 440, 500, 495, 495, 495, 495, 495, 495, 495 }, + { 260, 260, 230, 230, 230, 230, 400, 440, 500, 500, 500, 500, 500, 500, 500, 500 }, + { 295, 295, 240, 240, 240, 240, 400, 440, 500, 510, 510, 510, 510, 510, 510, 510 }, + { 320, 320, 250, 250, 250, 250, 400, 440, 500, 520, 520, 520, 520, 520, 520, 520 }, + { 340, 340, 260, 260, 260, 260, 420, 460, 540, 530, 530, 530, 530, 530, 530, 530 }, + { 350, 350, 270, 270, 270, 270, 420, 460, 540, 540, 540, 540, 540, 540, 540, 540 }, + { 360, 360, 280, 280, 280, 280, 420, 460, 540, 545, 545, 545, 545, 545, 545, 545 }, + { 360, 360, 280, 280, 280, 280, 420, 460, 540, 550, 550, 550, 550, 550, 550, 550 }, + { 355, 355, 285, 285, 285, 285, 420, 460, 540, 560, 560, 560, 560, 560, 560, 560 }, + { 345, 345, 290, 290, 290, 290, 420, 460, 540, 565, 565, 565, 565, 565, 565, 565 }, + { 335, 335, 290, 290, 290, 290, 420, 460, 540, 570, 570, 570, 570, 570, 570, 570 }, + { 330, 330, 295, 295, 295, 295, 430, 470, 550, 575, 575, 575, 575, 575, 575, 575 }, + { 325, 325, 295, 295, 295, 295, 430, 470, 550, 580, 580, 580, 580, 580, 580, 580 }, + { 320, 320, 295, 295, 295, 295, 440, 470, 550, 575, 575, 575, 575, 575, 575, 575 }, + { 315, 315, 295, 295, 295, 295, 440, 470, 550, 570, 570, 570, 570, 570, 570, 570 }, + { 310, 310, 295, 295, 295, 295, 450, 480, 580, 565, 565, 565, 565, 565, 565, 565 }, + { 305, 305, 295, 295, 295, 295, 460, 500, 580, 560, 560, 560, 560, 560, 560, 560 }, + { 295, 295, 290, 290, 290, 290, 460, 500, 580, 555, 555, 555, 555, 555, 555, 555 }, + { 285, 285, 285, 285, 285, 285, 460, 500, 580, 550, 550, 550, 550, 550, 550, 550 }, + { 280, 280, 280, 280, 280, 280, 460, 500, 580, 540, 540, 540, 540, 540, 540, 540 }, + { 275, 275, 275, 275, 275, 275, 460, 500, 580, 535, 535, 535, 535, 535, 535, 535 }, + { 265, 265, 265, 265, 265, 265, 460, 500, 580, 530, 530, 530, 530, 530, 530, 530 }, + { 250, 250, 250, 250, 250, 250, 460, 500, 580, 520, 520, 520, 520, 520, 520, 520 }, + { 240, 240, 240, 240, 240, 240, 470, 500, 580, 515, 515, 515, 515, 515, 515, 515 }, + { 220, 220, 220, 220, 220, 220, 470, 500, 580, 510, 510, 510, 510, 510, 510, 510 }, + { 200, 200, 200, 200, 200, 200, 470, 500, 580, 500, 500, 500, 500, 500, 500, 500 }, + { 180, 180, 180, 180, 180, 180, 480, 500, 580, 495, 495, 495, 495, 495, 495, 495 }, + { 160, 160, 160, 160, 160, 160, 480, 500, 580, 485, 485, 485, 485, 485, 485, 485 }, + { 140, 140, 140, 140, 140, 140, 480, 500, 580, 480, 480, 480, 480, 480, 480, 480 }, + { 125, 125, 125, 125, 125, 125, 480, 500, 580, 470, 470, 470, 470, 470, 470, 470 } + }, + /* motion_texture_freq[OT_ISP_AUTO_ISO_NUM] */ + { 180, 190, 190, 170, 170, 170, 160, 140, 128, 128, 128, 100, 100, 100, 100, 100 }, + /* motion_edge_freq[OT_ISP_AUTO_ISO_NUM] */ + { 128, 100, 100, 100, 100, 100, 100, 100, 100, 100, 96, 96, 96, 96, 96, 96 }, + /* motion_over_shoot[OT_ISP_AUTO_ISO_NUM] */ + { 60, 62, 62, 64, 64, 64, 56, 52, 50, 50, 30, 10, 10, 10, 10, 10 }, + /* motion_under_shoot[OT_ISP_AUTO_ISO_NUM] */ + { 60, 62, 62, 64, 64, 64, 54, 50, 50, 30, 20, 20, 15, 15, 15, 15 }, + /* shoot_sup_strength[OT_ISP_AUTO_ISO_NUM] */ + { 8, 8, 7, 7, 7, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* shoot_sup_adj[OT_ISP_AUTO_ISO_NUM] */ + { 9, 9, 8, 8, 7, 7, 7, 6, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* detail_ctrl[OT_ISP_AUTO_ISO_NUM] */ + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 120, 120, 120, 120, 120, 120 }, + /* detail_ctrl_threshold[OT_ISP_AUTO_ISO_NUM] */ + { 180, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160 }, + /* edge_filt_strength[OT_ISP_AUTO_ISO_NUM] */ + { 60, 58, 60, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62 }, + /* edge_filt_max_cap */ + { 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 }, + /* r_gain[OT_ISP_AUTO_ISO_NUM] */ + { 12, 16, 20, 24, 24, 24, 26, 28, 31, 31, 31, 31, 31, 31, 31, 31 }, + /* g_gain[OT_ISP_AUTO_ISO_NUM] */ + { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 }, + /* b_gain[OT_ISP_AUTO_ISO_NUM] */ + { 18, 20, 24, 24, 24, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 }, + /* skin_gain[OT_ISP_AUTO_ISO_NUM] */ + { 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, + /* max_sharp_gain[OT_ISP_AUTO_ISO_NUM] */ + { 30, 30, 30, 30, 30, 26, 20, 20, 18, 18, 18, 18, 18, 18, 18, 18 }, + { + /* shoot_inner_threshold[OT_ISP_AUTO_ISO_NUM] */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* shoot_outer_threshold[OT_ISP_AUTO_ISO_NUM] */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* shoot_protect_threshold[OT_ISP_AUTO_ISO_NUM] */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + { + /* edge_rly_fine_threshold[OT_ISP_AUTO_ISO_NUM] */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* edge_rly_coarse_threshold[OT_ISP_AUTO_ISO_NUM] */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* edge_overshoot[OT_ISP_AUTO_ISO_NUM] */ + {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20}, + /* edge_undershoot[OT_ISP_AUTO_ISO_NUM] */ + {120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120}, + /* edge_gain_by_rly[OT_ISP_SHARPEN_RLYWGT_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} + }, + /* edge_rly_by_mot[OT_ISP_SHARPEN_STDGAIN_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16} + }, + /* edge_rly_by_luma[OT_ISP_SHARPEN_STDGAIN_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16} + }, + }, + { + /* mf_gain_by_mot[OT_ISP_SHARPEN_MOT_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} + }, + /* hf_gain_by_mot[OT_ISP_SHARPEN_MOT_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}, + {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} + }, + /* lmf_gain_by_mot[OT_ISP_SHARPEN_MOT_NUM][OT_ISP_AUTO_ISO_NUM] */ + { + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16} + }, + } + }, +}; + +static const ot_isp_drc_attr g_cmos_drc = { + /* enable */ + 0, + /* curve_select */ + OT_ISP_DRC_CURVE_ASYMMETRY, + /* purple_reduction_strength */ + 35, + /* bright_gain_limit */ + 10, + /* bright_gain_limit_step */ + 8, + /* dark_gain_limit_luma */ + 0, + /* dark_gain_limit_chroma */ + 0, + /* contrast_ctrl */ + 8, + /* rim_reduction_strength */ + 32, + /* rim_reduction_threshold */ + 30, + /* color_correction_lut[OT_ISP_DRC_CC_NODE_NUM] */ + { + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 + }, + /* tone_mapping_value[OT_ISP_DRC_TM_NODE_NUM] */ + { + 8, 8, 16, 24, 31, 39, 48, 56, 65, 75, 85, 95, 106, 118, 130, 143, + 156, 170, 185, 201, 218, 235, 254, 274, 294, 316, 339, 364, 390, 417, 446, 477, + 509, 543, 579, 617, 658, 701, 746, 794, 844, 898, 955, 1015, 1078, 1145, 1216, 1291, + 1370, 1454, 1543, 1637, 1736, 1841, 1952, 2069, 2194, 2325, 2465, 2612, 2767, 2932, 3106, 3290, + 3485, 3691, 3909, 4140, 4384, 4641, 4914, 5202, 5507, 5830, 6171, 6531, 6913, 7316, 7742, 8193, + 8669, 9173, 9705, 10268, 10863, 11492, 12145, 12808, 13483, 14171, 14872, 15587, 16319, 17069, 17840, 18635, + 19458, 19881, 20313, 20754, 21204, 21661, 22122, 22586, 23053, 23525, 24000, 24480, 24965, 25455, 25950, 26451, + 26959, 27473, 27995, 28524, 29062, 29609, 30165, 30732, 31309, 31899, 32501, 33116, 33746, 34391, 35043, 35706, + 36381, 37066, 37763, 38472, 39192, 39925, 40671, 41429, 42201, 42591, 42986, 43383, 43784, 44189, 44597, 45008, + 45424, 45842, 46265, 46691, 47121, 47555, 47993, 48434, 48880, 49329, 49783, 50241, 50703, 51169, 51639, 52113, + 52592, 53075, 53564, 54056, 54552, 55054, 55560, 56071, 56586, 56846, 57107, 57369, 57632, 57896, 58162, 58429, + 58697, 58967, 59238, 59510, 59783, 60057, 60333, 60611, 60889, 61169, 61451, 61733, 62017, 62303, 62589, 62877, + 63167, 63458, 63750, 64044, 64340, 64636, 64934, 65234 + }, + /* spatial_filter_coef */ + 1, + /* range_filter_coef */ + 2, + /* detail_adjust_coef */ + 8, + { + { + /* local_mixing_bright_max */ + 96, + /* local_mixing_bright_min */ + 48, + /* local_mixing_bright_threshold */ + 100, + /* local_mixing_bright_slope */ + -3, + }, + }, + { + { + /* local_mixing_dark_max */ + 96, + /* local_mixing_dark_min */ + 48, + /* local_mixing_dark_threshold */ + 100, + /* local_mixing_dark_slope */ + -3, + }, + }, + /* high_saturation_color_ctrl */ + 15, + /* global_color_ctrl */ + 0, + /* shoot_reduction_en */ + 1, + /* op_type */ + OT_OP_MODE_MANUAL, + /* manual_attr */ + { + /* manual_strength */ + 256, + }, + /* auto_attr */ + { + /* auto_strength */ + 512, + /* auto_strength_max */ + 1023, + /* auto_strength_min */ + 512, + }, + /* asymmetry_curve */ + { + /* asymmetry */ + 6, + /* second_pole */ + 200, + /* stretch */ + 40, + /* compress */ + 170 + }, + /* auto_curve */ + { + /* brightness */ + 8, + /* contrast */ + 8, + /* tolerance */ + 6, + }, + /* bcnr_attr */ + { + /* bcnr_en */ + 0, + /* bcnr_detail_restore */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* bcnr_strength */ + 3, + } +}; + + +/* -------------------------------------------------------------------------- + * AWB saturation and colour sectors. + * + * cmos_get_awb_default() memset the whole ot_isp_awb_sensor_default and then + * filled in only the reference temperature, the static WB gains and wb_para. + * That left agc_tbl zeroed -- valid = 0 and every saturation entry 0 -- so + * the ISP was never told what saturation to run, which is the washed-out + * colour. saturation[] is indexed by AGC bucket, 128 == nominal, and tapers + * at high gain because chroma noise scales with gain. + * + * From sc450ai, same ISP silicon. The taper shape is an ISP behaviour rather + * than a sensor measurement, so it transfers. + * -------------------------------------------------------------------------- */ + +static ot_isp_color_sector g_imx662_color_sector = { + 0, + { + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + { + { 20, 20, 20, 20, 20, 20 }, + { 20, 20, 20, 20, 20, 20 }, + }, + }, +}; + +static ot_isp_awb_agc_table g_imx662_awb_agc_table = { + /* bvalid */ + 1, + + /* 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 */ + /* saturation + * + * The first four buckets are the daylight rendition the operator signed + * off on and are unchanged. Above them the taper is much steeper than + * sc450ai's: chroma noise is the ugliest high-gain artifact, colour is + * least trustworthy exactly where gain is highest, and dropping chroma + * measured -7.3% on the encoded bitrate with the lights off. The top + * buckets are heavily desaturated rather than fully grey, so the image + * degrades toward monochrome instead of switching to it. */ + { 168, 168, 166, 162, 150, 138, 124, 108, 92, 76, 64, 54, 46, 40, 36, 32 } +}; + #endif /* IMX662_CMOS_PARAM_H */ diff --git a/sensors/cv610/imx662/imx662_sensor_ctl.c b/sensors/cv610/imx662/imx662_sensor_ctl.c index 3d18ee88..db9863ee 100644 --- a/sensors/cv610/imx662/imx662_sensor_ctl.c +++ b/sensors/cv610/imx662/imx662_sensor_ctl.c @@ -1,12 +1,12 @@ /* * imx662_sensor_ctl.c — IMX662 low-level transport + power-on register init. * - * SCAFFOLD (original). Implements the standard HiSilicon sensor transport - * (Linux /dev/i2c-N + OT_I2C_SLAVE_FORCE) and the per-mode register init the - * ISP calls at stream start. The bulk power-on "reserved register" block is - * left as a TODO to transcribe from the Sony IMX662 datasheet / - * will127534/imx662-v4l2-driver at integration — those magic values cannot be - * invented and must match silicon. + * Implements the standard HiSilicon sensor transport (Linux /dev/i2c-N + + * OT_I2C_SLAVE_FORCE) and the per-mode register init the ISP calls at stream + * start. The bulk power-on "reserved register" block lives in imx662_cfg.h, + * transcribed from pauliustumas/imx662 and cross-checked against Sony's + * IMX662_Register.xlsx; imx662_write_init_seq() writes it in standby, before + * the per-mode registers below, so the per-mode writes win where they overlap. */ #include @@ -22,6 +22,7 @@ #include "securec.h" #include "imx662_cmos.h" +#include "imx662_cfg.h" #define I2C_DEV_FILE_NUM 16 #define I2C_BUF_NUM 8 @@ -169,11 +170,24 @@ td_void imx662_blc_clamp(ot_vi_pipe vi_pipe, ot_isp_sns_blc_clamp blc_clamp) } /* ---- power-on register block --------------------------------------------- - * TODO(integration): transcribe the full IMX662 power-on / reserved-register - * sequence (~89 writes, addresses 0x301C..0x4549) from the datasheet or the - * RPi driver's imx662_common_regs[]. The few below are the mode-defining - * writes only; the reserved block is required for a correct image. + * The Sony power-on sequence (reserved analog/ADC trim, MIPI TX timing, + * readout window, HDR context parked for linear) lives in imx662_cfg.h and + * runs first, in standby. Everything below it is per-mode state that + * overrides the table where the two overlap -- notably the 0x3A50/51/52 + * AD-timing triplet, which the table carries in its 12-bit form. */ +static td_s32 imx662_write_init_seq(ot_vi_pipe vi_pipe) +{ + td_s32 ret = 0; + td_u32 i; + + for (i = 0; i < IMX662_INIT_SEQ_LEN; i++) { + ret += imx662_write_register(vi_pipe, g_imx662_init_seq[i].addr, + g_imx662_init_seq[i].data); + } + return ret; +} + static td_s32 imx662_linear_1080p_init(ot_vi_pipe vi_pipe, td_u32 hmax, td_bool raw_10bit, td_bool overclock_100fps) { @@ -182,6 +196,8 @@ static td_s32 imx662_linear_1080p_init(ot_vi_pipe vi_pipe, td_u32 hmax, ret += imx662_write_register(vi_pipe, IMX662_REG_STANDBY, 0x01); /* stop for cfg */ delay_ms(1); + ret += imx662_write_init_seq(vi_pipe); + /* --- clock / interface (VERIFY against board wiring) --- */ /* 100 fps follows the public IMX662 mode: feed 27 MHz externally while * selecting the 24 MHz profile (0x04), which raises its 1440 Mbps timing @@ -212,10 +228,14 @@ static td_s32 imx662_linear_1080p_init(ot_vi_pipe vi_pipe, td_u32 hmax, ret += imx662_write_register(vi_pipe, IMX662_REG_AD10_2, raw_10bit ? 0x19 : 0x00); /* --- black level --- */ + /* BLKLEVEL is [11:0] across 30DC/30DD, so 30DD's low nibble carries + * BLKLEVEL[11:8] and its top nibble is reserved with bit 6 documented + * "Fixed to 1h" (Sony's map gives 30DDh an initial value of 40h, and the + * register list's own changelog calls out "Revised: Initial value of + * fixed register (30DDh)"). 0x40 therefore keeps BLKLEVEL at 50 and + * stops clearing a fixed bit -- the black level itself does not move. */ ret += imx662_write_register(vi_pipe, IMX662_REG_BLKLEVEL_L, 0x32); /* 50 */ - ret += imx662_write_register(vi_pipe, IMX662_REG_BLKLEVEL_H, 0x00); - - /* TODO: reserved-register block goes here (see note above). */ + ret += imx662_write_register(vi_pipe, IMX662_REG_BLKLEVEL_H, 0x40); return ret; } diff --git a/specs/2026-08-16-cv610-runtime-iq/requirements.md b/specs/2026-08-16-cv610-runtime-iq/requirements.md new file mode 100644 index 00000000..59d56b27 --- /dev/null +++ b/specs/2026-08-16-cv610-runtime-iq/requirements.md @@ -0,0 +1,208 @@ +# CV610 runtime IQ control surface + +Status: **IMPLEMENTED** in v0.65.5 — see the closing note at the end of this +file for what shipped, what changed from this plan, and what is still open. +Date: 2026-08-16. +Device: `root@192.168.2.181` (Hi3516CV610 DEMO Board, IMX662). +Follows PR #229, which landed the compile-time ISP seeds this made editable. + +## Why + +PR #229 fixed the CV610 image by seeding the ISP properly at init: Sony's 131-entry +power-on register sequence, the ISP algorithm blocks (which were *all* disabled), +and the AWB saturation table (which was zeroed). The result is a large, verified +improvement — but every value is a **compile-time constant in the sensor plugin**. + +Two consequences make that unsatisfactory: + +1. **The operator cannot tune.** SigmaStar has an Image Quality tab driven by + `/api/v1/iq/*`; CV610 has nothing. Changing saturation today means editing + `imx662_cmos_param.h`, cross-compiling, deploying an `.so`, and **rebooting the + board** — the plugin is read once at pipe start, so there is no live path at all. +2. **The tables are borrowed, not calibrated.** bayer_nr, sharpen, + noise_calibration and DRC come from `smart_sc450ai`, a 4 MP sensor, where IMX662 + is 2 MP STARVIS. They were kept on an operator A/B, not a measurement. Runtime + knobs are what turns "borrowed defaults" into "a starting point you can correct". + +## Current state (measured, 2026-08-16) + +``` +GET /api/v1/iq/get → {"ok":false,"error":{"code":"not_implemented","message":"IQ query not available"}} +GET /api/v1/iq/set → {"ok":false,"error":{"code":"not_implemented","message":"IQ set not available"}} +``` + +The endpoints are generic and already routed (`src/venc_api.c:4114`). They dispatch +on backend callbacks and 501 when those are NULL: + +- `src/venc_api.c:3131` → `g_cb->query_iq_info` +- `src/venc_api.c:3148,3169` → `g_cb->apply_iq_param` + +Declared in `include/venc_api.h:43-45`: + +```c +char *(*query_iq_info)(void); /* malloc'd JSON, caller frees */ +int (*apply_iq_param)(const char *param, const char *value); /* 0 ok, -1 error */ +``` + +Both are wired on the other two backends and NULL on CV610: + +| backend | registration site | implementation | +|---|---|---| +| Star6E | `src/star6e_controls.c:1772-1773` | `src/star6e_iq.c` (~66 ISP setter calls, dlopens `libmi_isp.so`) | +| Maruko | `src/maruko_controls.c:1496-1497` | `src/maruko_iq.c` | +| **CV610** | `src/cv610_runtime.c:242` (`g_cv610_apply_callbacks`) | **absent** | + +The WebUI hides the tab explicitly — `web/dashboard.html:1787-1788`: +```js +const iqTab = document.getElementById('tab-btn-iq'); +if(iqTab) iqTab.hidden = true; // /api/v1/iq|ae|awb are 501 here +``` + +## Reference implementation already on disk + +`/home/snokvist/dev/hisilicon/venc/src/app/cv610_streamer/isp_control.c` — 30 KB, +covering the knob set with getters and setters: + +- **setters**: `ss_mpi_isp_set_{ccm,color_tone,csc,nr,saturation,sharpen,wb}_attr` +- **getters**: `ss_mpi_isp_get_{ca,ccm,color_tone,csc,dehaze,drc,gamma,ldci,module_ctrl,nr,saturation,sharpen,wb}_attr` + +A `cv610_isp_ctl` CLI built from it is already deployed on `.181`, so the calls are +proven against this silicon. This is a port with a working reference, not research. + +**Simpler than Star6E.** `star6e_iq.c` has to `dlopen("libmi_isp.so")` and resolve +`MI_ISP_IQ_*` symbols at runtime. CV610 links `ss_mpi` directly (`cv610_pipeline.c` +already calls `ss_mpi_isp_set_ccm_attr`), so `cv610_iq.c` calls the MPI directly — +no dlopen, no symbol table, no init failure path. + +## Scope + +### Must + +- `src/cv610_iq.c` + `include/cv610_iq.h` exposing `cv610_iq_query()` and + `cv610_iq_set(param, value)`, matching the `star6e_iq.h` contract (dot-notation + for sub-fields, comma-separated values for arrays). +- Wire `.query_iq_info` / `.apply_iq_param` into `g_cv610_apply_callbacks` + (`src/cv610_runtime.c:242`). +- Cover, at minimum, the knobs that PR #229 seeded and the operator will want to + correct: **saturation** (the one that fixed washed-out colour), **sharpen**, + **nr**, **ccm**, **wb**, **color_tone**, **csc**. +- Un-hide the WebUI tab on CV610 by **capability**, not by backend name — the + current `hidden = true` is hardcoded. Drive it off whether `/api/v1/iq/get` + answers, so the same code stays correct if a backend gains or loses the surface. + +### Should + +- Read-back verification in `cv610_iq_query()` — return what the ISP reports, not + what was last written, so a rejected set is visible. +- Reject unknown parameter names with `-1` so `/api/v1/iq/set` 400s rather than + silently accepting. + +### Out of scope + +- **Persistence.** These are live-only knobs. Whether tuned values survive a reboot + is a separate decision (config fields vs a profile file vs the PQ `.bin` route) + and should not be bundled. +- **AE / AWB endpoints.** `/api/v1/ae` and `/api/v1/awb` are also 501 on CV610. + Related, but a different callback set; do not widen this. +- **PQ `.bin` import.** `libbin.so` / `OT_PQ_BIN_ImportBinData()` is vendored and + verified loadable on `.181`, but a `.bin` is chip- *and* sensor-locked and must be + produced with PQTools against the IMX662. Separate workstream. +- **Re-tuning the sc450ai-derived tables.** This spec builds the instrument; using + it to replace borrowed tuning with measured tuning is the follow-on. + +## Verification plan + +Per-step checks, each independently confirmable: + +1. **Build gate.** `make build SOC_BUILD=cv610 CV610_SDK_INC=/home/snokvist/dev/hisilicon/oh CV610_SDK_LIB=/home/snokvist/dev/hisilicon/firmware/output-waybeam/target/usr/lib`, then `make verify` for Star6E/Maruko regression. The sensor plugin builds `-Wall -Wextra -Werror`. +2. **Endpoint liveness.** `/api/v1/iq/get` returns JSON instead of 501; `/api/v1/iq/set?saturation=` returns ok. +3. **The knob actually moves the image.** Set saturation low and high, capture over + RTP, and compare **mean chroma magnitude** — the metric that showed +41% for the + compile-time change (20.19 → 28.46). A set that returns ok but does not move the + image is the failure mode to look for. +4. **Read-back agrees.** `iq/get` after `iq/set` reports the value the ISP holds. +5. **No regression.** Four-mode cold-boot sweep still nominal: 30.03 / 60.03 / + 90.03 / 100.06 fps, drops frozen. +6. **Control.** A knob left untouched must read unchanged across the session — a + table where everything moved cannot distinguish a working setter from a reinit. + +## Bench traps that will bite (learned the hard way in the PR #229 session) + +- **Never `S95waybeam stop` + `start` on CV610.** Two quick cycles hard-hung the + SoC — no ARP, needed a power/watchdog reboot. `$LOADER stop` unloads the MPP `.ko` + set and had not finished after 3 s. **Reboot to cycle the daemon.** ~15 reboots in + that session were all clean. +- **`/api/v1/set?outgoing.server=…` triggers a reinit that stalls the HTTP server + for seconds.** Rebooting within ~3 s loses the config write. Other fields persist + to `/etc/waybeam.json` immediately. GET-verify before rebooting. +- **`sensor.mode` pins the mode** and overrides fps-derived selection; setting + `video0.fps` alone does nothing while it is pinned. +- **`/tmp` on `.181` is tmpfs.** Bench tools vanish on reboot — re-scp + `tools/cv610_i2c_dump.c`'s binary or a dump silently returns "not found", and an + empty comparison reads as a pass. +- **The co-resident `waybeam_hub` rewrites venc's config.** Disable + `/etc/init.d/S97waybeam-hub` for any A/B, or arms will not share settings. +- **Scene motion invalidates image A/B.** Two arms minutes apart showed a "noise + fix" and a "blue cast fix" that were entirely the camera being repointed. Re-run + adjacent arms on the same scene before concluding anything. +- **md5 the artifact, not the exit code.** Fixed in PR #229 for the sensor plugin + (`-MMD -MP`), but the habit matters: two builds from different tuning tables came + out byte-identical because the Makefile tracked no headers. +- **Objective sharpness metrics mislead on denoising changes.** Variance-of-Laplacian + counts grain as detail. The operator's verdict on the live stream is the gate for + image quality; metrics rank candidates and catch pipeline regressions. + +## Open questions for the operator + +1. Which knobs matter most day to day — is saturation/sharpen enough to start, or is + CCM/WB needed in the first cut? + → Answered by building all of them: the field table costs one line per knob, + so picking a subset would have saved nothing. 11 groups, 59 fields. +2. Should tuned values persist across reboot, and if so via config fields or a + profile file? (Deliberately out of scope above; needs a decision before anyone + asks why their tuning vanished.) + → **Still open.** Values are live-only; a reboot returns to the plugin's + seeds. Nothing in v0.65.5 changes that. + +--- + +## Closing note (v0.65.5) + +**Shipped as planned**: `src/cv610_iq.c` + `include/cv610_iq.h`, wired into +`g_cv610_apply_callbacks`; all seven "must" knobs plus drc, ldci, dehaze and +ca; read-back from the ISP rather than a cache; unknown names rejected; the +WebUI tab driven by a capability probe rather than a backend-name test. + +**Changed from the plan**, and why: + +- *No byte offsets.* The plan said "matching the `star6e_iq.h` contract". The + wire contract matches, but the implementation does not copy Star6E's + hand-computed offsets — CV610 links `ss_mpi` directly, so every field is an + `offsetof()` into the SDK's own struct. A mistyped member is then a compile + error rather than a write into a neighbouring field. +- *The schema is emitted, not duplicated.* The plan only said "un-hide the tab + by capability". Un-hiding it alone would have shown the SigmaStar knob list + on a CV610, so `query()` emits a `_schema` block and the page renders from + it. This is the same trap as the modes store's third copy of the mode list. +- *`cv610_pipeline_isp_ready()` was added.* Firing MPI ioctls at an ISP that + was never inited is not something to find out about in the field. +- *The field's `domain` is exposed.* Not in the plan; the mutation sweep made + the side-effect visible and it was cheap to surface rather than document + only. (Shipped first as a manual-only `forces_manual` flag, then generalised + to `direct`/`manual`/`auto` when review showed the auto half had the same + trap in the other direction.) + +**Found while verifying, not predicted**: DRC and dehaze are registered with +the ISP but ship `enable = 0` and are bypassed in hardware. See HISTORY 0.65.5; +0.65.4's wording is corrected. DRC has never contributed to a CV610 image. + +**Still open**: + +- Persistence (question 2 above). +- `/api/v1/ae` and `/api/v1/awb` remain 501 — deliberately out of scope. +- The `!cv610_pipeline_isp_ready()` path returns cleanly by inspection but was + not exercised: reaching it means stopping the pipeline, and stop/start is the + one thing that hard-hangs this SoC. +- Re-tuning the sc450ai-derived tables. The instrument now exists; using it is + the follow-on, and DRC is the obvious first candidate since it has never been + switched on. diff --git a/src/cv610_audio.c b/src/cv610_audio.c index b7fb8470..cc686fb8 100644 --- a/src/cv610_audio.c +++ b/src/cv610_audio.c @@ -208,7 +208,13 @@ static int cv610_aenc_start(Cv610AudioState *state) destination.chn_id = CV610_AENC_CHN; AUDIO_CHECK(ss_mpi_sys_bind(&source, &destination)); state->bound = 1; - printf("> CV610 AENC Opus 32000 bit/s restricted-low-delay, 10.0 ms frames\n"); + /* Derived, not spelled out: this line claimed "10.0 ms" for a release + * after CV610_AUDIO_POINT_NUM went 480 -> 960, so the only banner a + * reader could check the packet rate against was wrong. */ + printf("> CV610 AENC Opus %u bit/s restricted-low-delay, %.1f ms frames\n", + CV610_AUDIO_BITRATE, + (double)CV610_AUDIO_POINT_NUM * 1000.0 / + (double)CV610_AUDIO_SAMPLE_RATE); return 0; } @@ -359,6 +365,64 @@ int cv610_audio_is_running(Cv610AudioState *state) return state ? __atomic_load_n(&state->running, __ATOMIC_ACQUIRE) : 0; } +/* Release what a predecessor that died without cv610_audio_stop() left behind. + * + * MPP objects are kernel state, not process state, so a venc killed with + * SIGKILL leaves the AI device claimed by the dead pid. Measured on the .181 + * bench: the next start is then refused at ss_mpi_ai_set_pub_attr with + * OT_ERR_AI_NOT_PERM (0xa015800d) and the craft comes back SILENTLY WITHOUT + * AUDIO -- 2 of 2 runs, while a graceful restart restores it every time. The + * kernel does reclaim the two aenc MMB blocks (those "MMB LEAK(pid=...)" lines + * are that reclaim reporting itself, not a leak); it does not undo the claim. + * + * The module cycle is what does the work. Releasing the objects one by one does + * not: ss_mpi_ai_disable() is refused with the same NOT_PERM as the + * set_pub_attr it was meant to unblock. A module-level exit/init pair from a + * process that has initialised is what clears the claim -- measured, and it is + * exactly why a SECOND graceful restart recovered audio where the first did + * not. This folds that cycle into the first start. The pair runs AFTER the + * caller's own ss_mpi_audio_init() on purpose: that is the ordering verified on + * hardware. + * + * An earlier revision also called sys_unbind/aenc_destroy_chn/opus_deinit/ + * ai_disable_chn here, mirroring cv610_audio_stop()'s teardown. They were + * removed: the SDK tracks those objects PROCESS-locally, so a successor cannot + * release a dead predecessor's copies, and all four returned the same code in + * the broken and healthy cases while only ai_disable's changed. opus_deinit was + * worse than inert -- it printed "illegal handle(-1)!" to stderr on every clean + * start, from a process-local static that is -1 in a fresh process. Removal was + * re-verified on hardware, not assumed. ai_disable is kept because it is the + * one call measured to reach kernel state. + * + * Same shape and the same reason as sys_setup()'s isp_exit/sys_exit/vb_exit. */ +static int cv610_audio_preclean(void) +{ + td_s32 exit_ret, init_ret, ai; + + /* audio_initialized is deliberately NOT touched across the cycle. It only + * decides whether cv610_audio_stop() calls ss_mpi_audio_exit(), and the two + * error directions are not symmetric: a second exit is safe (the module's + * sub-exits are flag-guarded, so it is not a double free), while a SKIPPED + * exit leaks the kernel AUDIO_INIT claim and the /dev fd -- which is opened + * without O_CLOEXEC and therefore survives venc_respawn_after_exit()'s + * execv. A partially-succeeded re-init leaves exactly that to clean up, so + * the flag must stay set. */ + exit_ret = ss_mpi_audio_exit(); + init_ret = ss_mpi_audio_init(); + ai = ss_mpi_ai_disable(CV610_AUDIO_DEV); + printf(" audio pre-clean: exit=0x%x init=0x%x ai=0x%x\n", + exit_ret, init_ret, ai); + + /* Fatal only when the exit actually happened and the re-init did not: that + * is the one combination where this function has taken the module down and + * failed to bring it back. If the EXIT failed, nothing was reclaimed and + * there is nothing to restore -- returning -1 there would turn a start that + * previously worked into a dead one, on a call that was not on the start + * path before this change. Let bring-up proceed and let the AUDIO_CHECKs + * below produce the real diagnosis. */ + return (exit_ret == TD_SUCCESS && init_ret != TD_SUCCESS) ? -1 : 0; +} + Cv610AudioState *cv610_audio_start(const VencConfig *config, const VencOutputUri *video_output) { @@ -368,18 +432,33 @@ Cv610AudioState *cv610_audio_start(const VencConfig *config, if (!config || !config->audio.enabled) return NULL; state = calloc(1, sizeof(*state)); - if (!state) + if (!state) { + fprintf(stderr, "ERROR: audio state alloc failed\n"); return NULL; + } state->acodec_fd = -1; state->aenc_fd = -1; state->socket_handle = -1; - if (pthread_mutex_init(&state->stats_lock, NULL) != 0) + if (pthread_mutex_init(&state->stats_lock, NULL) != 0) { + fprintf(stderr, "ERROR: audio stats lock init failed\n"); goto fail; + } if (ss_mpi_audio_init() != TD_SUCCESS) { - fprintf(stderr, "ERROR: ss_mpi_audio_init failed\n"); + /* This is where an absent module set lands, not the /dev/acodec open + * below: audio_init opens /dev/ab first, and open_aio -- the module + * that creates it -- is staged only under CV610_AUDIO=1 + * (load-cv610-online). audio.enabled in the JSON is a separate switch, + * so the two diverging is a configuration the operator can reach. */ + fprintf(stderr, "ERROR: ss_mpi_audio_init failed " + "(are the audio modules loaded? they need CV610_AUDIO=1 at " + "module load, which is separate from audio.enabled)\n"); goto fail_mutex; } state->audio_initialized = 1; + if (cv610_audio_preclean() != 0) { + fprintf(stderr, "ERROR: audio module re-init failed after pre-clean\n"); + goto fail_started; + } /* Load-bearing order, established by the standalone hardware bring-up. */ if (cv610_acodec_reset(state) != 0 || cv610_ai_set_attr(state) != 0 || cv610_ai_enable(state) != 0 || diff --git a/src/cv610_encoder_config.c b/src/cv610_encoder_config.c new file mode 100644 index 00000000..4d0f174b --- /dev/null +++ b/src/cv610_encoder_config.c @@ -0,0 +1,53 @@ +#include "cv610_encoder_config.h" + +#include + +int cv610_encoder_config_derive(const VencConfig *cfg, uint32_t height, + uint32_t fps, Cv610EncoderConfig *out) +{ + IntraRefreshMode mode; + uint32_t rows; + uint32_t per; + + if (!cfg || !out || height == 0 || fps == 0 || + cfg->video0.slice_count < 1 || + cfg->video0.slice_count > VENC_SLICE_COUNT_MAX) + return -1; + + memset(out, 0, sizeof(*out)); + mode = intra_refresh_parse_mode(cfg->video0.intra_refresh_mode); + intra_refresh_compute(mode, height, fps, + cfg->video0.intra_refresh_lines, + cfg->video0.intra_refresh_qp, + cfg->video0.gop_size, &out->intra.derived); + out->intra.enabled = mode != INTRA_MODE_OFF; + out->intra.mode = 0; /* OT_VENC_INTRA_REFRESH_ROW */ + out->intra.refresh_num = out->intra.derived.lines; + out->intra.request_i_qp = out->intra.derived.req_iqp; + + if (cfg->video0.ref_base > 0) { + out->ref.enabled = 1; + out->ref.base = cfg->video0.ref_base; + out->ref.enhance = cfg->video0.ref_enhance + ? cfg->video0.ref_enhance : 1; + out->ref.pred = cfg->video0.ref_pred ? 1u : 0u; + } + + rows = (height + 31u) / 32u; + out->slice.requested_count = cfg->video0.slice_count; + out->slice.total_lcu_rows = rows; + out->slice.split_mode = CV610_SLICE_SPLIT_MODE_LCU_ROW; + out->slice.split_size = 1; + out->slice.expected_count = 1; + if (cfg->video0.slice_count > 1) { + per = (rows + cfg->video0.slice_count - 1u) / + cfg->video0.slice_count; + if (per < 1) + per = 1; + out->slice.enabled = 1; + out->slice.split_size = per; + out->slice.expected_count = (rows + per - 1u) / per; + } + + return 0; +} diff --git a/src/cv610_iq.c b/src/cv610_iq.c new file mode 100644 index 00000000..77585b44 --- /dev/null +++ b/src/cv610_iq.c @@ -0,0 +1,760 @@ +/* + * cv610_iq.c — runtime IQ control for the Hi3516CV610 ISP. + * + * The IMX662 sensor plugin seeds this ISP once, at pipe start, through + * cmos_get_isp_default() (PR #229). This module exposes the same blocks as + * live knobs so a value can be corrected without a cross-compile, a plugin + * deploy and a reboot. + * + * Two things differ from star6e_iq.c and make this the simpler backend: + * + * - No dlopen. The CV610 backend links ss_mpi directly, so the attribute + * structs are the SDK's own types. Every field offset comes from + * offsetof(), not from a hand-computed constant that can drift when the + * SDK header changes. + * - The table is self-describing. query() emits a "_schema" block so the + * WebUI renders the knob list this file declares, rather than carrying a + * second copy of it. + * + * Ranges in the field table are the "Range:" comments from the SDK's + * ot_common_isp.h. A value outside its range is REJECTED, not clamped: the + * HTTP layer echoes the requested value back, so silently substituting a + * different one would make both the response and the log a record of + * something that never happened. + */ + +#include "cv610_iq.h" +#include "cv610_pipeline.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ot_type.h" +#include "ot_common.h" +#include "ot_common_video.h" +#include "ot_common_isp.h" +#include "ss_mpi_isp.h" +#include "ss_mpi_awb.h" +#include "ss_mpi_ae.h" + +/* The backend runs a single VI pipe; cv610_pipeline.c calls it VI_PIPE 0. */ +#define CV610_IQ_PIPE 0 + +/* td_bool and ot_op_mode are enums, so both are int-sized. The field table + * encodes them as FT_S32; assert that rather than trusting it. */ +typedef char cv610_iq_bool_is_int[(sizeof(td_bool) == 4) ? 1 : -1]; +typedef char cv610_iq_mode_is_int[(sizeof(ot_op_mode) == 4) ? 1 : -1]; + +typedef enum { + FT_U8, + FT_U16, + FT_S32, /* also carries td_bool and ot_op_mode */ + FT_U32, /* AE gain/exposure ranges; needs 64-bit to stay exact */ +} Cv610IqType; + +typedef struct { + const char *name; + Cv610IqType type; + uint16_t offset; /* offsetof() into the group's attr struct */ + uint16_t count; /* 1 = scalar, N = array */ + /* 64-bit because td_u32 fields (AE gain and exposure ranges) do not fit + * an int32_t -- a driver default of 0xFFFFFFFF would read back as -1. */ + int64_t min; + int64_t max; + /* Which half of the block this value lives in. A manual_attr value is + * ignored while the block runs its auto curve and vice versa, and an + * ignored write reads exactly like a broken setter — so a write to a + * domain also selects it. F_DIRECT fields sit outside both halves. */ + uint8_t domain; +} Cv610IqField; + +typedef struct { + const char *name; + int (*get)(void *attr); + int (*set)(const void *attr); + int32_t op_type_offset; /* -1 when the group has no op_type */ + const Cv610IqField *fields; + uint16_t field_count; +} Cv610IqGroup; + +/* domain values. Every field here is writable; these say only which op_type + * the value is read under, and therefore which one a write must select. */ +#define F_DIRECT 0 /* outside manual_attr/auto_attr; op_type irrelevant */ +#define F_MANUAL 1 /* under manual_attr; a write selects op_type = manual */ +#define F_AUTO 2 /* under auto_attr; a write selects op_type = auto */ + +/* ── MPI wrappers ─────────────────────────────────────────────────────── + * Typed one-liners rather than casting function pointers: converting a + * function pointer to a different signature and calling through it is + * undefined behaviour, and void * -> struct * is a plain implicit + * conversion. */ + +#define IQ_ACCESSORS(group, getter, setter) \ + static int iq_get_##group(void *a) { return getter(CV610_IQ_PIPE, a); } \ + static int iq_set_##group(const void *a) { return setter(CV610_IQ_PIPE, a); } + +IQ_ACCESSORS(saturation, + ss_mpi_isp_get_saturation_attr, ss_mpi_isp_set_saturation_attr) +IQ_ACCESSORS(color_tone, + ss_mpi_isp_get_color_tone_attr, ss_mpi_isp_set_color_tone_attr) +IQ_ACCESSORS(csc, + ss_mpi_isp_get_csc_attr, ss_mpi_isp_set_csc_attr) +IQ_ACCESSORS(ccm, + ss_mpi_isp_get_ccm_attr, ss_mpi_isp_set_ccm_attr) +IQ_ACCESSORS(wb, + ss_mpi_isp_get_wb_attr, ss_mpi_isp_set_wb_attr) +IQ_ACCESSORS(sharpen, + ss_mpi_isp_get_sharpen_attr, ss_mpi_isp_set_sharpen_attr) +IQ_ACCESSORS(nr, + ss_mpi_isp_get_nr_attr, ss_mpi_isp_set_nr_attr) +IQ_ACCESSORS(drc, + ss_mpi_isp_get_drc_attr, ss_mpi_isp_set_drc_attr) +IQ_ACCESSORS(ldci, + ss_mpi_isp_get_ldci_attr, ss_mpi_isp_set_ldci_attr) +IQ_ACCESSORS(dehaze, + ss_mpi_isp_get_dehaze_attr, ss_mpi_isp_set_dehaze_attr) +IQ_ACCESSORS(ca, + ss_mpi_isp_get_ca_attr, ss_mpi_isp_set_ca_attr) +IQ_ACCESSORS(exposure, + ss_mpi_isp_get_exposure_attr, ss_mpi_isp_set_exposure_attr) + +#undef IQ_ACCESSORS + +/* ── Field tables ─────────────────────────────────────────────────────── + * Ranges are the SDK header's documented limits. Fields the CV610 does not + * support (motion sharpen, tnr, dering, cp LUT, radial crop) are omitted + * rather than exposed as knobs that do nothing. */ + +#define OFS(t, m) ((uint16_t)offsetof(t, m)) + +static const Cv610IqField f_saturation[] = { + { "op_type", FT_S32, OFS(ot_isp_saturation_attr, op_type), + 1, 0, 1, F_DIRECT }, + { "manual.saturation", FT_U8, OFS(ot_isp_saturation_attr, manual_attr.saturation), + 1, 0, 255, F_MANUAL }, + /* Indexed by AGC bucket; 128 == nominal. This is the curve the sensor + * plugin's g_imx662_awb_agc_table seeds. */ + { "auto.sat", FT_U8, OFS(ot_isp_saturation_attr, auto_attr.sat), + OT_ISP_AUTO_ISO_NUM, 0, 255, F_AUTO }, +}; + +static const Cv610IqField f_color_tone[] = { + { "red_cast_gain", FT_U16, OFS(ot_isp_color_tone_attr, red_cast_gain), + 1, 256, 384, F_DIRECT }, + { "green_cast_gain", FT_U16, OFS(ot_isp_color_tone_attr, green_cast_gain), + 1, 256, 384, F_DIRECT }, + { "blue_cast_gain", FT_U16, OFS(ot_isp_color_tone_attr, blue_cast_gain), + 1, 256, 384, F_DIRECT }, +}; + +static const Cv610IqField f_csc[] = { + { "enable", FT_S32, OFS(ot_isp_csc_attr, enable), 1, 0, 1, F_DIRECT }, + { "hue", FT_U8, OFS(ot_isp_csc_attr, hue), 1, 0, 100, F_DIRECT }, + { "luma", FT_U8, OFS(ot_isp_csc_attr, luma), 1, 0, 100, F_DIRECT }, + { "contr", FT_U8, OFS(ot_isp_csc_attr, contr), 1, 0, 100, F_DIRECT }, + { "satu", FT_U8, OFS(ot_isp_csc_attr, satu), 1, 0, 100, F_DIRECT }, + { "limited_range_en", FT_S32, OFS(ot_isp_csc_attr, limited_range_en), + 1, 0, 1, F_DIRECT }, +}; + +static const Cv610IqField f_ccm[] = { + { "op_type", FT_S32, OFS(ot_isp_color_matrix_attr, op_type), + 1, 0, 1, F_DIRECT }, + { "manual.sat_en", FT_S32, OFS(ot_isp_color_matrix_attr, manual_attr.sat_en), + 1, 0, 1, F_MANUAL }, + { "manual.ccm", FT_U16, OFS(ot_isp_color_matrix_attr, manual_attr.ccm), + OT_ISP_CCM_MATRIX_SIZE, 0, 65535, F_MANUAL }, + /* cv610_pipeline.c's enable_sensor_ccm() clears both of these so the + * auto CCM never bypasses; they are surfaced to make that visible. */ + { "auto.iso_act_en", FT_S32, OFS(ot_isp_color_matrix_attr, auto_attr.iso_act_en), + 1, 0, 1, F_AUTO }, + { "auto.temp_act_en", FT_S32, OFS(ot_isp_color_matrix_attr, auto_attr.temp_act_en), + 1, 0, 1, F_AUTO }, +}; + +static const Cv610IqField f_wb[] = { + { "bypass", FT_S32, OFS(ot_isp_wb_attr, bypass), 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_wb_attr, op_type), 1, 0, 1, F_DIRECT }, + { "manual.r_gain", FT_U16, OFS(ot_isp_wb_attr, manual_attr.r_gain), + 1, 0, 4095, F_MANUAL }, + { "manual.gr_gain", FT_U16, OFS(ot_isp_wb_attr, manual_attr.gr_gain), + 1, 0, 4095, F_MANUAL }, + { "manual.gb_gain", FT_U16, OFS(ot_isp_wb_attr, manual_attr.gb_gain), + 1, 0, 4095, F_MANUAL }, + { "manual.b_gain", FT_U16, OFS(ot_isp_wb_attr, manual_attr.b_gain), + 1, 0, 4095, F_MANUAL }, +}; + +static const Cv610IqField f_sharpen[] = { + { "enable", FT_S32, OFS(ot_isp_sharpen_attr, enable), + 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_sharpen_attr, op_type), + 1, 0, 1, F_DIRECT }, + { "manual.texture_strength", FT_U16, OFS(ot_isp_sharpen_attr, manual_attr.texture_strength), + OT_ISP_SHARPEN_GAIN_NUM, 0, 4095, F_MANUAL }, + { "manual.edge_strength", FT_U16, OFS(ot_isp_sharpen_attr, manual_attr.edge_strength), + OT_ISP_SHARPEN_GAIN_NUM, 0, 4095, F_MANUAL }, + { "manual.texture_freq", FT_U16, OFS(ot_isp_sharpen_attr, manual_attr.texture_freq), + 1, 0, 4095, F_MANUAL }, + { "manual.edge_freq", FT_U16, OFS(ot_isp_sharpen_attr, manual_attr.edge_freq), + 1, 0, 4095, F_MANUAL }, + { "manual.over_shoot", FT_U8, OFS(ot_isp_sharpen_attr, manual_attr.over_shoot), + 1, 0, 127, F_MANUAL }, + { "manual.under_shoot", FT_U8, OFS(ot_isp_sharpen_attr, manual_attr.under_shoot), + 1, 0, 127, F_MANUAL }, + { "manual.shoot_sup_strength", FT_U8, OFS(ot_isp_sharpen_attr, manual_attr.shoot_sup_strength), + 1, 0, 255, F_MANUAL }, + { "manual.detail_ctrl", FT_U8, OFS(ot_isp_sharpen_attr, manual_attr.detail_ctrl), + 1, 0, 255, F_MANUAL }, + { "manual.edge_filt_strength", FT_U8, OFS(ot_isp_sharpen_attr, manual_attr.edge_filt_strength), + 1, 0, 63, F_MANUAL }, + { "manual.max_sharp_gain", FT_U16, OFS(ot_isp_sharpen_attr, manual_attr.max_sharp_gain), + 1, 0, 2047, F_MANUAL }, + { "manual.luma_wgt", FT_U8, OFS(ot_isp_sharpen_attr, manual_attr.luma_wgt), + OT_ISP_SHARPEN_LUMA_NUM, 0, 31, F_MANUAL }, +}; + +/* Bayer NR. Only the switches are exposed: the strength LUTs are the + * sc450ai-derived tables PR #229 borrowed, and re-tuning those is a + * calibration exercise, not a slider. */ +static const Cv610IqField f_nr[] = { + { "enable", FT_S32, OFS(ot_isp_nr_attr, enable), 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_nr_attr, op_type), 1, 0, 1, F_DIRECT }, + /* Motion-detect temporal NR -- CV610's variant of the tnr_en slot, which + * this chip does not have. Temporal filtering is the strongest tool + * against high-gain grain because the noise is uncorrelated frame to + * frame while the scene is not; its cost is smearing on motion. */ + { "md_en", FT_S32, OFS(ot_isp_nr_attr, md_en), 1, 0, 1, F_DIRECT }, + /* "Strength of reserving the random noise according to luma" -- so LOWER + * values filter harder. This is what g_cmos_noise_calibration's fit + * ultimately drives, and that fit is sc450ai's, not IMX662's. Until a + * real photon-transfer calibration exists for this sensor, this is the + * honest way to correct it: by eye, against the live image. */ + { "coring_ratio", FT_U16, OFS(ot_isp_nr_attr, coring_ratio), + OT_ISP_BAYERNR_LUT_LENGTH, 0, 1023, F_DIRECT }, +}; + +static const Cv610IqField f_drc[] = { + { "enable", FT_S32, OFS(ot_isp_drc_attr, enable), 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_drc_attr, op_type), 1, 0, 1, F_DIRECT }, + { "manual.strength", FT_U16, OFS(ot_isp_drc_attr, manual_attr.strength), + 1, 0, 1023, F_MANUAL }, + { "auto.strength", FT_U16, OFS(ot_isp_drc_attr, auto_attr.strength), + 1, 0, 1023, F_AUTO }, + { "auto.strength_max", FT_U16, OFS(ot_isp_drc_attr, auto_attr.strength_max), + 1, 0, 1023, F_AUTO }, + { "auto.strength_min", FT_U16, OFS(ot_isp_drc_attr, auto_attr.strength_min), + 1, 0, 1023, F_AUTO }, + { "contrast_ctrl", FT_U8, OFS(ot_isp_drc_attr, contrast_ctrl), + 1, 0, 15, F_DIRECT }, + { "detail_adjust_coef", FT_U8, OFS(ot_isp_drc_attr, detail_adjust_coef), + 1, 0, 15, F_DIRECT }, + { "bright_gain_limit", FT_U8, OFS(ot_isp_drc_attr, bright_gain_limit), + 1, 0, 15, F_DIRECT }, + { "dark_gain_limit_luma", FT_U8, OFS(ot_isp_drc_attr, dark_gain_limit_luma), + 1, 0, 133, F_DIRECT }, +}; + +static const Cv610IqField f_ldci[] = { + { "enable", FT_S32, OFS(ot_isp_ldci_attr, enable), 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_ldci_attr, op_type), 1, 0, 1, F_DIRECT }, + { "gauss_lpf_sigma", FT_U8, OFS(ot_isp_ldci_attr, gauss_lpf_sigma), + 1, 1, 255, F_DIRECT }, + { "manual.blc_ctrl", FT_U16, OFS(ot_isp_ldci_attr, manual_attr.blc_ctrl), + 1, 0, 511, F_MANUAL }, + { "tpr_incr_coef", FT_U16, OFS(ot_isp_ldci_attr, tpr_incr_coef), + 1, 0, 256, F_DIRECT }, + { "tpr_decr_coef", FT_U16, OFS(ot_isp_ldci_attr, tpr_decr_coef), + 1, 0, 256, F_DIRECT }, +}; + +static const Cv610IqField f_dehaze[] = { + { "enable", FT_S32, OFS(ot_isp_dehaze_attr, enable), 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_dehaze_attr, op_type), 1, 0, 1, F_DIRECT }, + { "manual.strength", FT_U8, OFS(ot_isp_dehaze_attr, manual_attr.strength), + 1, 0, 255, F_MANUAL }, + { "auto.strength", FT_U8, OFS(ot_isp_dehaze_attr, auto_attr.strength), + 1, 0, 255, F_AUTO }, +}; + +static const Cv610IqField f_ca[] = { + { "enable", FT_S32, OFS(ot_isp_ca_attr, enable), 1, 0, 1, F_DIRECT }, +}; + +/* AE. Gains are 22.10 fixed point, so 1024 == 1x. The ceilings are what + * stop the sensor climbing into the regime where the frame is mostly + * amplified noise -- which is where sharpening then multiplies the bitrate. + * Exposure time is in microseconds and is the better lever of the two: it + * collects photons rather than amplifying them, at the cost of frame rate. + * + * These sit under auto_attr, so writing one selects AE auto mode -- which is + * the mode a ceiling is meant to apply in. */ +static const Cv610IqField f_exposure[] = { + { "bypass", FT_S32, OFS(ot_isp_exposure_attr, bypass), 1, 0, 1, F_DIRECT }, + { "op_type", FT_S32, OFS(ot_isp_exposure_attr, op_type), 1, 0, 1, F_DIRECT }, + { "ae_run_interval", FT_U8, OFS(ot_isp_exposure_attr, ae_run_interval), + 1, 1, 255, F_DIRECT }, + { "auto.exp_time_max", FT_U32, + OFS(ot_isp_exposure_attr, auto_attr.exp_time_range.max), + 1, 0, 4294967295LL, F_AUTO }, + { "auto.exp_time_min", FT_U32, + OFS(ot_isp_exposure_attr, auto_attr.exp_time_range.min), + 1, 0, 4294967295LL, F_AUTO }, + { "auto.a_gain_max", FT_U32, + OFS(ot_isp_exposure_attr, auto_attr.a_gain_range.max), + 1, 1024, 4294967295LL, F_AUTO }, + { "auto.d_gain_max", FT_U32, + OFS(ot_isp_exposure_attr, auto_attr.d_gain_range.max), + 1, 1024, 4294967295LL, F_AUTO }, + { "auto.ispd_gain_max", FT_U32, + OFS(ot_isp_exposure_attr, auto_attr.ispd_gain_range.max), + 1, 1024, 262144, F_AUTO }, + /* The single cap that bounds the product of all three. */ + { "auto.sys_gain_max", FT_U32, + OFS(ot_isp_exposure_attr, auto_attr.sys_gain_range.max), + 1, 1024, 4294967295LL, F_AUTO }, + { "auto.compensation", FT_U8, + OFS(ot_isp_exposure_attr, auto_attr.compensation), 1, 0, 255, F_AUTO }, + { "auto.speed", FT_U8, + OFS(ot_isp_exposure_attr, auto_attr.speed), 1, 0, 255, F_AUTO }, + { "auto.tolerance", FT_U8, + OFS(ot_isp_exposure_attr, auto_attr.tolerance), 1, 0, 255, F_AUTO }, +}; + +#undef OFS + +#define GROUP(n, ops) \ + { #n, iq_get_##n, iq_set_##n, ops, f_##n, \ + (uint16_t)(sizeof(f_##n) / sizeof(f_##n[0])) } + +static const Cv610IqGroup g_groups[] = { + GROUP(saturation, + (int32_t)offsetof(ot_isp_saturation_attr, op_type)), + GROUP(color_tone, -1), + GROUP(csc, -1), + GROUP(ccm, + (int32_t)offsetof(ot_isp_color_matrix_attr, op_type)), + GROUP(wb, + (int32_t)offsetof(ot_isp_wb_attr, op_type)), + GROUP(sharpen, + (int32_t)offsetof(ot_isp_sharpen_attr, op_type)), + GROUP(nr, + (int32_t)offsetof(ot_isp_nr_attr, op_type)), + GROUP(drc, + (int32_t)offsetof(ot_isp_drc_attr, op_type)), + GROUP(ldci, + (int32_t)offsetof(ot_isp_ldci_attr, op_type)), + GROUP(dehaze, + (int32_t)offsetof(ot_isp_dehaze_attr, op_type)), + GROUP(ca, -1), + GROUP(exposure, + (int32_t)offsetof(ot_isp_exposure_attr, op_type)), +}; + +#undef GROUP + +#define NUM_GROUPS (sizeof(g_groups) / sizeof(g_groups[0])) + +/* Largest attribute struct, with the right alignment for every member. */ +typedef union { + ot_isp_saturation_attr saturation; + ot_isp_color_tone_attr color_tone; + ot_isp_csc_attr csc; + ot_isp_color_matrix_attr ccm; + ot_isp_wb_attr wb; + ot_isp_sharpen_attr sharpen; + ot_isp_nr_attr nr; + ot_isp_drc_attr drc; + ot_isp_ldci_attr ldci; + ot_isp_dehaze_attr dehaze; + ot_isp_ca_attr ca; + ot_isp_exposure_attr exposure; +} Cv610IqAttr; + +/* Guards the shared scratch attribute and the static emit buffer below — + * nothing more. It does NOT serialize the ss_mpi_isp_* calls themselves: + * cv610_pipeline.c's ISP thread never takes this lock, and MPI-level + * serialization is the SDK's own responsibility. */ +static pthread_mutex_t g_iq_mutex = PTHREAD_MUTEX_INITIALIZER; +static Cv610IqAttr g_attr; + +/* ── Field access ───────────────────────────────────────────────────────── */ + +static size_t field_elem_size(Cv610IqType t) +{ + switch (t) { + case FT_U8: return 1; + case FT_U16: return 2; + case FT_S32: + case FT_U32: return 4; + } + return 4; +} + +static int64_t field_read(const void *attr, const Cv610IqField *f, uint16_t idx) +{ + const uint8_t *p = (const uint8_t *)attr + f->offset + + idx * field_elem_size(f->type); + + switch (f->type) { + case FT_U8: return (int64_t)*p; + case FT_U16: { uint16_t v; memcpy(&v, p, sizeof(v)); return (int64_t)v; } + case FT_S32: { int32_t v; memcpy(&v, p, sizeof(v)); return (int64_t)v; } + case FT_U32: { uint32_t v; memcpy(&v, p, sizeof(v)); return (int64_t)v; } + } + return 0; +} + +/* Callers must range-check first; cv610_iq_set() is the only caller and + * rejects out-of-range values rather than silently substituting one. */ +static void field_write(void *attr, const Cv610IqField *f, uint16_t idx, int64_t val) +{ + uint8_t *p = (uint8_t *)attr + f->offset + idx * field_elem_size(f->type); + + switch (f->type) { + case FT_U8: *p = (uint8_t)val; return; + case FT_U16: { uint16_t v = (uint16_t)val; memcpy(p, &v, sizeof(v)); return; } + case FT_S32: { int32_t v = (int32_t)val; memcpy(p, &v, sizeof(v)); return; } + case FT_U32: { uint32_t v = (uint32_t)val; memcpy(p, &v, sizeof(v)); return; } + } +} + +/* ── JSON emission ──────────────────────────────────────────────────────── */ + +#define JSON_CLAMP(p, sz) do { \ + if ((p) >= (int)(sz)) (p) = (int)(sz) - 1; } while (0) + +#define JSON_PUT(buf, pos, sz, ...) do { \ + (pos) += snprintf((buf) + (pos), (sz) - (size_t)(pos), __VA_ARGS__); \ + JSON_CLAMP(pos, sz); } while (0) + +static int emit_group_values(char *buf, size_t sz, int pos, + const Cv610IqGroup *g, const void *attr) +{ + for (uint16_t i = 0; i < g->field_count; i++) { + const Cv610IqField *f = &g->fields[i]; + + JSON_PUT(buf, pos, sz, "%s\"%s\":", i ? "," : "", f->name); + if (f->count == 1) { + JSON_PUT(buf, pos, sz, "%lld", + (long long)field_read(attr, f, 0)); + continue; + } + JSON_PUT(buf, pos, sz, "["); + for (uint16_t e = 0; e < f->count; e++) + JSON_PUT(buf, pos, sz, "%s%lld", + e ? "," : "", (long long)field_read(attr, f, e)); + JSON_PUT(buf, pos, sz, "]"); + } + return pos; +} + +/* The WebUI builds its knob list from this, so the table here stays the only + * copy of the field set. */ +static int emit_schema(char *buf, size_t sz, int pos) +{ + JSON_PUT(buf, pos, sz, "\"_schema\":["); + for (size_t i = 0; i < NUM_GROUPS; i++) { + const Cv610IqGroup *g = &g_groups[i]; + + JSON_PUT(buf, pos, sz, "%s{\"name\":\"%s\",\"fields\":[", + i ? "," : "", g->name); + for (uint16_t f = 0; f < g->field_count; f++) { + const Cv610IqField *fd = &g->fields[f]; + JSON_PUT(buf, pos, sz, + "%s{\"name\":\"%s\",\"count\":%u," + "\"min\":%lld,\"max\":%lld,\"domain\":\"%s\"}", + f ? "," : "", fd->name, + (unsigned)fd->count, (long long)fd->min, (long long)fd->max, + fd->domain == F_MANUAL ? "manual" : + fd->domain == F_AUTO ? "auto" : "direct"); + } + JSON_PUT(buf, pos, sz, "]}"); + } + JSON_PUT(buf, pos, sz, "]"); + return pos; +} + +/* Read-only: which ISP blocks the hardware is bypassing right now. This is + * the control for "did enabling that block actually reach silicon" — a + * seeded-but-bypassed block looks identical to one that was never seeded. */ +static int emit_module_ctrl(char *buf, size_t sz, int pos) +{ + ot_isp_module_ctrl mod; + int ret; + + memset(&mod, 0, sizeof(mod)); + ret = ss_mpi_isp_get_module_ctrl(CV610_IQ_PIPE, &mod); + JSON_PUT(buf, pos, sz, "\"module_ctrl\":{\"ret\":%d", ret); + if (ret == 0) { + JSON_PUT(buf, pos, sz, + ",\"bypass\":{\"anti_false_color\":%u,\"crosstalk\":%u," + "\"dpc\":%u,\"nr\":%u,\"dehaze\":%u,\"wb_gain\":%u," + "\"mesh_shading\":%u,\"drc\":%u,\"demosaic\":%u," + "\"color_matrix\":%u,\"gamma\":%u,\"ca\":%u,\"csc\":%u," + "\"sharpen\":%u,\"cac\":%u,\"ldci\":%u}", + (unsigned)mod.bit_bypass_anti_false_color, + (unsigned)mod.bit_bypass_crosstalk_removal, + (unsigned)mod.bit_bypass_dpc, + (unsigned)mod.bit_bypass_nr, + (unsigned)mod.bit_bypass_dehaze, + (unsigned)mod.bit_bypass_wb_gain, + (unsigned)mod.bit_bypass_mesh_shading, + (unsigned)mod.bit_bypass_drc, + (unsigned)mod.bit_bypass_demosaic, + (unsigned)mod.bit_bypass_color_matrix, + (unsigned)mod.bit_bypass_gamma, + (unsigned)mod.bit_bypass_ca, + (unsigned)mod.bit_bypass_csc, + (unsigned)mod.bit_bypass_sharpen, + (unsigned)mod.bit_bypass_cac, + (unsigned)mod.bit_bypass_ldci); + } + JSON_PUT(buf, pos, sz, "}"); + return pos; +} + +char *cv610_iq_query(void) +{ + static char buf[24576]; + int pos = 0; + char *result; + + if (!cv610_pipeline_isp_ready()) + return NULL; + + pthread_mutex_lock(&g_iq_mutex); + + JSON_PUT(buf, pos, sizeof(buf), "{\"ok\":true,\"data\":{"); + pos = emit_schema(buf, sizeof(buf), pos); + + for (size_t i = 0; i < NUM_GROUPS; i++) { + const Cv610IqGroup *g = &g_groups[i]; + int ret; + + memset(&g_attr, 0, sizeof(g_attr)); + ret = g->get(&g_attr); + + JSON_PUT(buf, pos, sizeof(buf), ",\"%s\":{\"ret\":%d", + g->name, ret); + if (ret == 0) { + JSON_PUT(buf, pos, sizeof(buf), ",\"fields\":{"); + pos = emit_group_values(buf, sizeof(buf), pos, g, &g_attr); + JSON_PUT(buf, pos, sizeof(buf), "}"); + } + JSON_PUT(buf, pos, sizeof(buf), "}"); + } + + JSON_PUT(buf, pos, sizeof(buf), ","); + pos = emit_module_ctrl(buf, sizeof(buf), pos); + JSON_PUT(buf, pos, sizeof(buf), "}}"); + + /* JSON_PUT clamps at the buffer end, so an overflow would serve + * syntactically broken JSON and the page would fail to parse it with no + * clue why. Fail the request instead; the caller answers 500. */ + if (pos >= (int)sizeof(buf) - 1) { + fprintf(stderr, "[cv610-iq] query truncated at %d bytes; " + "grow buf[] past %zu\n", pos, sizeof(buf)); + pthread_mutex_unlock(&g_iq_mutex); + return NULL; + } + + result = strdup(buf); + pthread_mutex_unlock(&g_iq_mutex); + return result; +} + +/* ── Set ────────────────────────────────────────────────────────────────── */ + +/* strtoll with the whole-token check the caller needs: "12abc" and "" are + * rejected rather than silently read as 12 and 0. 64-bit because the AE + * gain/exposure fields are td_u32 and a legitimate value can exceed INT32_MAX. + * + * 64-bit because the AE gain and exposure fields are td_u32 and a legitimate + * value can exceed INT32_MAX; overflow is caught by errno == ERANGE from + * strtoll, which is the only portable check once the value type is as wide as + * the return type. */ +static int parse_i64(const char *s, const char **end, int64_t *out) +{ + char *stop = NULL; + long long v; + + while (*s == ' ') + s++; + if (*s == '\0') + return -1; + errno = 0; + v = strtoll(s, &stop, 10); + if (stop == s) + return -1; + if (errno == ERANGE) + return -1; + while (*stop == ' ') + stop++; + if (*stop != '\0' && *stop != ',') + return -1; + *out = (int64_t)v; + *end = stop; + return 0; +} + +int cv610_iq_set(const char *param, const char *value) +{ + const Cv610IqGroup *group = NULL; + const Cv610IqField *field = NULL; + char group_name[32]; + const char *field_name; + const char *dot; + size_t glen; + int ret; + int rc = -1; + + if (!param || !value) + return -1; + if (!cv610_pipeline_isp_ready()) { + fprintf(stderr, "[cv610-iq] ISP is not running\n"); + return -1; + } + + /* Group and field split on the FIRST dot: field names carry their own + * dot ("manual.saturation"), which is what makes the auto/manual half + * of the struct visible in the name. */ + dot = strchr(param, '.'); + if (!dot) { + fprintf(stderr, "[cv610-iq] %s: expected .\n", param); + return -1; + } + glen = (size_t)(dot - param); + if (glen == 0 || glen >= sizeof(group_name)) { + fprintf(stderr, "[cv610-iq] %s: bad group name\n", param); + return -1; + } + memcpy(group_name, param, glen); + group_name[glen] = '\0'; + field_name = dot + 1; + + for (size_t i = 0; i < NUM_GROUPS; i++) { + if (strcmp(g_groups[i].name, group_name) == 0) { + group = &g_groups[i]; + break; + } + } + if (!group) { + fprintf(stderr, "[cv610-iq] unknown group: %s\n", group_name); + return -1; + } + for (uint16_t i = 0; i < group->field_count; i++) { + if (strcmp(group->fields[i].name, field_name) == 0) { + field = &group->fields[i]; + break; + } + } + if (!field) { + fprintf(stderr, "[cv610-iq] %s: unknown field: %s\n", + group_name, field_name); + return -1; + } + + pthread_mutex_lock(&g_iq_mutex); + + /* Read-modify-write: the attribute structs carry far more state than + * this table describes, and a zeroed struct would wipe the sensor + * plugin's seeds. */ + memset(&g_attr, 0, sizeof(g_attr)); + ret = group->get(&g_attr); + if (ret != 0) { + fprintf(stderr, "[cv610-iq] %s: get failed: 0x%x\n", + group_name, (unsigned)ret); + goto out; + } + + if (field->count == 1) { + int64_t v; + const char *end; + if (parse_i64(value, &end, &v) != 0 || *end == ',') { + fprintf(stderr, "[cv610-iq] %s: expected one integer\n", + param); + goto out; + } + if (v < field->min || v > field->max) { + fprintf(stderr, "[cv610-iq] %s: %lld out of range [%lld, %lld]\n", + param, (long long)v, (long long)field->min, + (long long)field->max); + goto out; + } + field_write(&g_attr, field, 0, v); + } else { + const char *p = value; + const char *end = value; + uint16_t n = 0; + while (n < field->count) { + int64_t v; + if (parse_i64(p, &end, &v) != 0) + break; + if (v < field->min || v > field->max) { + fprintf(stderr, + "[cv610-iq] %s: element %u = %lld out of range " + "[%lld, %lld]\n", + param, (unsigned)n, (long long)v, + (long long)field->min, (long long)field->max); + goto out; + } + field_write(&g_attr, field, n, v); + n++; + if (*end != ',') + break; + p = end + 1; + } + /* Require exactly the declared count, in both directions. A short + * list leaves the tail at whatever the ISP held; a long one drops + * its excess. Either way the curve applied is not the curve asked + * for, and a partly-applied curve reads as a successful set. */ + if (n != field->count || *end != '\0') { + fprintf(stderr, "[cv610-iq] %s: expected exactly %u values\n", + param, (unsigned)field->count); + goto out; + } + } + + /* A value is inert unless the block is running the domain it lives in, + * so writing one selects that domain. One rule, both directions: + * without the auto half, restoring an ISO curve after any manual write + * stores the numbers, reads them back, and changes nothing. */ + if (field->domain != F_DIRECT && group->op_type_offset >= 0) { + int32_t mode = (field->domain == F_MANUAL) ? + OT_OP_MODE_MANUAL : OT_OP_MODE_AUTO; + int32_t was = 0; + + memcpy(&was, (uint8_t *)&g_attr + group->op_type_offset, + sizeof(was)); + memcpy((uint8_t *)&g_attr + group->op_type_offset, + &mode, sizeof(mode)); + /* Say so when it actually moves. Selecting a domain is a side effect + * of the write, and an operator who pinned op_type by hand deserves a + * trace of it being taken back. */ + if (was != mode) + printf("[cv610-iq] %s: op_type %s -> %s\n", group->name, + was == OT_OP_MODE_MANUAL ? "manual" : "auto", + mode == OT_OP_MODE_MANUAL ? "manual" : "auto"); + } + + ret = group->set(&g_attr); + if (ret != 0) { + fprintf(stderr, "[cv610-iq] %s: set failed: 0x%x\n", + param, (unsigned)ret); + goto out; + } + + printf("[cv610-iq] %s = %s\n", param, value); + rc = 0; + +out: + pthread_mutex_unlock(&g_iq_mutex); + return rc; +} diff --git a/src/cv610_modes.c b/src/cv610_modes.c index 308ad303..358a14b7 100644 --- a/src/cv610_modes.c +++ b/src/cv610_modes.c @@ -43,6 +43,63 @@ const Cv610SensorMode *cv610_mode_for_fps(uint32_t fps) return NULL; } +const Cv610SensorMode *cv610_mode_select(int forced_mode, uint32_t target_fps, + int *out_index) +{ + const Cv610SensorMode *pick; + size_t pick_i = 0; + size_t i; + + if (out_index) + *out_index = -1; + + /* A forced index is the whole answer: it exists or the config is wrong. + * Parity with find_best_mode(), which fails bring-up rather than + * quietly running a mode the operator did not ask for. */ + if (forced_mode >= 0) { + if ((size_t)forced_mode >= CV610_MODE_COUNT) + return NULL; + if (out_index) + *out_index = forced_mode; + return &g_cv610_modes[forced_mode]; + } + /* Nothing to select against. Rejecting keeps the behaviour this + * function replaced — a bare cv610_mode_for_fps(0) returned NULL too — + * rather than inventing a rate for a config that names none. */ + if (target_fps == 0) + return NULL; + + pick = cv610_mode_for_fps(target_fps); + if (pick != NULL) { + if (out_index) + *out_index = (int)(pick - g_cv610_modes); + return pick; + } + + /* Slowest mode still faster than the target: never deliver fewer frames + * than asked for while a mode that can keep up exists. */ + for (i = 0; i < CV610_MODE_COUNT; ++i) { + const Cv610SensorMode *m = &g_cv610_modes[i]; + + if (m->fps > target_fps && (pick == NULL || m->fps < pick->fps)) { + pick = m; + pick_i = i; + } + } + /* Target above every mode: clamp to the fastest. */ + if (pick == NULL) { + for (i = 0; i < CV610_MODE_COUNT; ++i) { + if (pick == NULL || g_cv610_modes[i].fps > pick->fps) { + pick = &g_cv610_modes[i]; + pick_i = i; + } + } + } + if (out_index) + *out_index = (int)pick_i; + return pick; +} + const char *cv610_mode_check_output(const Cv610SensorMode *mode, uint32_t width, uint32_t height) { diff --git a/src/cv610_pipeline.c b/src/cv610_pipeline.c index 56bcd70a..669be227 100644 --- a/src/cv610_pipeline.c +++ b/src/cv610_pipeline.c @@ -4,6 +4,8 @@ * the public lifecycle is the small cv610_pipeline_* interface below. */ #include "cv610_pipeline.h" + +#include "pipeline_common.h" /* Minimal Hi3516CV610 + IMX662 MIPI/VI/ISP graph. The target's MPP module * loader and sensor-clock prerequisites are documented in * docs/CV610_BACKEND.md. VENC and output ownership stay in cv610_runtime.c. */ @@ -89,6 +91,7 @@ typedef struct { uint32_t sensor_clock_hz; /* MCLK this mode's line timing assumes */ unsigned int out_width; /* VPSS output = encoded size */ unsigned int out_height; + int keep_aspect; /* isp.keepAspect: crop before scaling */ int vi_online; /* VI -> ISP online/realtime mode */ } Cv610PipelineRuntimeConfig; @@ -228,12 +231,31 @@ static int mipi_setup(const Cv610PipelineRuntimeConfig *c) /* --------------------------------------------------------------- VB / SYS -- */ +/* Two configs match when they would hand out the same buffers. Only the pools + * actually in use are compared; the rest of the struct is zero-filled padding + * and an mmz_name this backend never sets. */ +static int vb_cfg_equal(const ot_vb_cfg *a, const ot_vb_cfg *b) +{ + unsigned int i; + + if (a->max_pool_cnt != b->max_pool_cnt) { + return 0; + } + for (i = 0; i < a->max_pool_cnt && i < OT_VB_MAX_COMMON_POOLS; i++) { + if (a->common_pool[i].blk_size != b->common_pool[i].blk_size || + a->common_pool[i].blk_cnt != b->common_pool[i].blk_cnt) { + return 0; + } + } + return 1; +} + static int sys_setup(const Cv610PipelineRuntimeConfig *c) { ot_vb_cfg vb; ot_vi_vpss_mode vi_vpss_mode; td_u64 raw_blk, yuv_blk, out_blk; - td_s32 sys_ret, vb_ret; + td_s32 sys_ret, vb_ret, set_ret, isp_ret; unsigned int i; /* RAW12 is stored 16bpp in the pipe buffers; be generous, this is a probe. */ @@ -260,14 +282,23 @@ static int sys_setup(const Cv610PipelineRuntimeConfig *c) /* VB/SYS state lives in the kernel and survives the process that created * it, and only the creating process may tear it down — so after a crashed * run vb_exit returns NOT_PERM and the config below cannot be replaced. - * BUSY is therefore acceptable for the normal offline restart path. For - * online mode it is not: selecting VI-online must happen after a complete, + * A clean exit runs mpp_cleanup()'s vb_exit, so this pre-clean normally + * finds nothing to do and the set_cfg below simply takes. For online mode + * BUSY is not acceptable: selecting VI-online must happen after a complete, * successful SYS init and before any VI pipe exists. */ /* C does not define function-argument evaluation order. Keep the vendor * API's SYS-then-VB shutdown order explicit and make each result legible. */ + /* ISP mem-init is the one piece of graph state a hard kill leaves behind: + * measured on the .181 bench, SIGKILL releases VB (set_cfg then succeeds) + * but leaves ISP[0] inited, so the next run dies at ss_mpi_isp_mem_init + * with 0xa01c800c "already inited". Clear it here, with the other + * pre-cleans and before anything of ours is registered, so a crash does + * not need a module reload to recover. */ + isp_ret = ss_mpi_isp_exit(VI_PIPE); sys_ret = ss_mpi_sys_exit(); vb_ret = ss_mpi_vb_exit(); - printf(" pre-clean: sys_exit=0x%x vb_exit=0x%x\n", sys_ret, vb_ret); + printf(" pre-clean: isp_exit=0x%x sys_exit=0x%x vb_exit=0x%x\n", + isp_ret, sys_ret, vb_ret); memset(&vi_vpss_mode, 0, sizeof(vi_vpss_mode)); for (i = 0; i < OT_VI_MAX_PIPE_NUM; i++) { @@ -277,7 +308,35 @@ static int sys_setup(const Cv610PipelineRuntimeConfig *c) vi_vpss_mode.mode[VI_PIPE] = OT_VI_ONLINE_VPSS_OFFLINE; } - CV610_CHECK_OR_BUSY(ss_mpi_vb_set_cfg(&vb)); + set_ret = ss_mpi_vb_set_cfg(&vb); + if (set_ret != TD_SUCCESS) { + ot_vb_cfg live; + + if (cv610_error_id(set_ret) != OT_ERR_BUSY) { + fprintf(stderr, "FAIL ss_mpi_vb_set_cfg = 0x%x\n", set_ret); + return -1; + } + /* VB is still held by an owner that never tore it down — a crashed + * run, since a clean exit calls vb_exit from mpp_cleanup(). Adopting + * it is only safe when the live pool layout is the one this mode was + * about to ask for. Tolerating BUSY blindly would leave every block + * the wrong size, and that surfaces far downstream as corruption + * rather than as a failed init. */ + memset(&live, 0, sizeof(live)); + if (ss_mpi_vb_get_cfg(&live) != TD_SUCCESS || + !vb_cfg_equal(&live, &vb)) { + /* Points at a reboot, not a module reload. This fires only after + * a predecessor died abnormally, which is exactly the boot state + * where an unload cannot be undone: the modules will not load + * back, and on a video-only craft the attempt resets the SoC. */ + fprintf(stderr, "FAIL VB is held by a dead owner and its layout " + "differs from this mode; reboot to clear it\n"); + return -1; + } + printf(" ok ss_mpi_vb_set_cfg (adopted identical live config)\n"); + } else { + printf(" ok ss_mpi_vb_set_cfg\n"); + } CV610_CHECK_OR_BUSY(ss_mpi_vb_init()); if (c->vi_online) { /* Online mode can only be selected after a complete SYS init. Do not @@ -528,6 +587,41 @@ static int vpss_setup(const Cv610PipelineRuntimeConfig *c) grp_attr.frame_rate.dst_frame_rate = -1; CV610_CHECK(ss_mpi_vpss_create_grp(VPSS_GRP, &grp_attr)); + /* Aspect: the channel below scales whatever the group hands it, so + * without this a 4:3 video0.size out of a 16:9 capture is squashed + * rather than framed. Crop the group's input to the encoded aspect + * first — the same centre-crop rule Star6E and Maruko apply through + * pipeline_common_compute_precrop(), from the same shared function so + * the three backends cannot drift. + * + * Written UNCONDITIONALLY, including the disable. MPP objects are + * kernel state on this SoC and a group that outlives a teardown keeps + * whatever crop it was last given, so "skip the call when no crop is + * needed" would inherit a stale rectangle from the previous run's + * geometry. vpss_teardown() destroys the group precisely so that + * cannot happen today — this keeps it true without depending on it. */ + { + PipelinePrecropRect precrop = pipeline_common_compute_precrop( + c->width, c->height, c->out_width, c->out_height, + c->keep_aspect ? true : false); + int cropping = (precrop.w != c->width || precrop.h != c->height); + ot_vpss_crop_info crop; + + memset(&crop, 0, sizeof(crop)); + crop.enable = cropping ? TD_TRUE : TD_FALSE; + crop.crop_mode = OT_COORD_ABS; + crop.crop_rect.x = precrop.x; + crop.crop_rect.y = precrop.y; + crop.crop_rect.width = precrop.w; + crop.crop_rect.height = precrop.h; + CV610_CHECK(ss_mpi_vpss_set_grp_crop(VPSS_GRP, &crop)); + if (cropping) + printf(" ok aspect crop %ux%u+%u+%u of %ux%u -> %ux%u\n", + (unsigned)precrop.w, (unsigned)precrop.h, + (unsigned)precrop.x, (unsigned)precrop.y, + c->width, c->height, c->out_width, c->out_height); + } + memset(&chn_attr, 0, sizeof(chn_attr)); chn_attr.width = c->out_width; chn_attr.height = c->out_height; @@ -637,6 +731,7 @@ int cv610_pipeline_start(const Cv610PipelineConfig *config) c.sensor_clock_hz = config->sensor_clock_hz; c.out_width = config->out_width; c.out_height = config->out_height; + c.keep_aspect = config->keep_aspect; c.vi_online = config->vi_online; g_stop = 0; @@ -672,6 +767,11 @@ int cv610_pipeline_start(const Cv610PipelineConfig *config) return 0; } +int cv610_pipeline_isp_ready(void) +{ + return g_isp_thread_ok; +} + void cv610_pipeline_stop(void) { g_stop = 1; diff --git a/src/cv610_runtime.c b/src/cv610_runtime.c index 3ed38870..458ff111 100644 --- a/src/cv610_runtime.c +++ b/src/cv610_runtime.c @@ -1,6 +1,8 @@ #include "cv610_runtime.h" #include "cv610_audio.h" +#include "cv610_encoder_config.h" +#include "cv610_iq.h" #include "cv610_modes.h" #include "cv610_pipeline.h" #include "debug_osd.h" @@ -10,6 +12,7 @@ #include "idr_rate_limit.h" #include "output_socket.h" #include "rtp_session.h" +#include "timing.h" #include "venc_frame_ring.h" #include "venc_ring.h" #include "venc_api.h" @@ -17,6 +20,7 @@ #include "venc_respawn.h" #include +#include #include #include #include @@ -61,6 +65,17 @@ typedef struct { uint64_t bytes; uint64_t output_drops; uint64_t packets_sent; + uint64_t drop_idr_last_us; + uint8_t gdr_active; + uint8_t gdr_cycle_len; + uint8_t gdr_counter; + uint8_t svct_active; + uint8_t delivered_slice_count; + uint8_t slice_census_done; + uint32_t requested_slice_count; + uint32_t ref_census_frames; + uint32_t ref_type_counts[OT_VENC_P_SLICE_BUTT]; + uint32_t trail_n_patched; int venc_created; int venc_started; int venc_bound; @@ -72,6 +87,40 @@ typedef struct { * runner. It is published before HTTP starts and cleared after HTTP joins. */ static Cv610RunnerContext *g_cv610_runner; +static Cv610IntraRefreshStatus g_cv610_intra_status; +static Cv610RefPredStatus g_cv610_ref_status; +static pthread_mutex_t g_cv610_status_mutex = PTHREAD_MUTEX_INITIALIZER; + +void cv610_runtime_intra_refresh_status(Cv610IntraRefreshStatus *out) +{ + if (!out) + return; + pthread_mutex_lock(&g_cv610_status_mutex); + *out = g_cv610_intra_status; + pthread_mutex_unlock(&g_cv610_status_mutex); +} + +void cv610_runtime_ref_pred_status(Cv610RefPredStatus *out) +{ + if (!out) + return; + pthread_mutex_lock(&g_cv610_status_mutex); + *out = g_cv610_ref_status; + pthread_mutex_unlock(&g_cv610_status_mutex); +} + +static void cv610_publish_encoder_status( + const Cv610IntraRefreshStatus *intra, + const Cv610RefPredStatus *ref) +{ + pthread_mutex_lock(&g_cv610_status_mutex); + if (intra) + g_cv610_intra_status = *intra; + if (ref) + g_cv610_ref_status = *ref; + pthread_mutex_unlock(&g_cv610_status_mutex); +} + static int cv610_update_venc_attr(uint32_t bitrate, uint32_t gop, int qp_delta, unsigned int fields) { @@ -112,6 +161,87 @@ static int cv610_apply_qp_delta(int delta) return cv610_update_venc_attr(0, 0, delta, 4u); } +/* Captured on the first write so that 0 restores the driver's own default + * rather than pinning whatever happened to be in force at the time. */ +static struct { + td_u32 max_qp, min_qp, max_i_qp, min_i_qp; + int captured; +} g_cv610_qp_defaults; + +/* CBR can only hold its target by raising QP. In a high-gain, noise-dominated + * scene the QP the encoder needs can exceed the driver's default ceiling, and + * once it saturates the bitrate overshoots with the rate controller powerless + * — measured at 3-7x target on the .181 bench with the lights off. This is + * the knob that lets it squeeze; it does not make the picture better, it stops + * the overshoot. 0 on either bound leaves/restores the driver default. */ +static int cv610_apply_qp_bounds(uint32_t min_qp, uint32_t max_qp) +{ + ot_venc_chn_attr attr; + ot_venc_rc_param param; + td_s32 ret; + + if (min_qp == 0 && max_qp == 0 && !g_cv610_qp_defaults.captured) + return 0; /* never written — driver defaults already in force */ + + memset(&attr, 0, sizeof(attr)); + if (ss_mpi_venc_get_chn_attr(CV610_VENC_CHN, &attr) != TD_SUCCESS) + return -1; + /* Only CBR carries these bounds; the backend configures nothing else, + * but a future mode change must not write through the wrong union arm. */ + if (attr.rc_attr.rc_mode != OT_VENC_RC_MODE_H265_CBR) + return -1; + + memset(¶m, 0, sizeof(param)); + if (ss_mpi_venc_get_rc_param(CV610_VENC_CHN, ¶m) != TD_SUCCESS) + return -1; + + if (!g_cv610_qp_defaults.captured) { + g_cv610_qp_defaults.max_qp = param.h265_cbr_param.max_qp; + g_cv610_qp_defaults.min_qp = param.h265_cbr_param.min_qp; + g_cv610_qp_defaults.max_i_qp = param.h265_cbr_param.max_i_qp; + g_cv610_qp_defaults.min_i_qp = param.h265_cbr_param.min_i_qp; + g_cv610_qp_defaults.captured = 1; + } + + param.h265_cbr_param.max_qp = max_qp ? max_qp : g_cv610_qp_defaults.max_qp; + param.h265_cbr_param.min_qp = min_qp ? min_qp : g_cv610_qp_defaults.min_qp; + /* I-frames get the same CEILING -- raising only the P bound leaves the + * I-frame free to blow the budget on its own, which in a noisy scene is + * where the biggest frames come from. Their FLOOR is deliberately left + * alone: video0.qp_delta biases I-frames below the P QP (this craft ships + * -4), and an I-frame floor would silently cancel it. Star6E's + * apply_qp_bounds() touches only the P bounds for the same reason. */ + param.h265_cbr_param.max_i_qp = max_qp ? max_qp : g_cv610_qp_defaults.max_i_qp; + + /* The API validator only compares min against max when BOTH are non-zero, + * so a half-specified pair can still resolve to min > max against the + * driver default. The SDK takes that without complaint and then behaves + * erratically, so reject it here rather than write it. */ + if (param.h265_cbr_param.min_qp > param.h265_cbr_param.max_qp || + param.h265_cbr_param.min_i_qp > param.h265_cbr_param.max_i_qp) { + fprintf(stderr, "ERROR: qpBounds min>max after resolving defaults " + "(p %u/%u, i %u/%u)\n", + (unsigned)param.h265_cbr_param.min_qp, + (unsigned)param.h265_cbr_param.max_qp, + (unsigned)param.h265_cbr_param.min_i_qp, + (unsigned)param.h265_cbr_param.max_i_qp); + return -1; + } + + ret = ss_mpi_venc_set_rc_param(CV610_VENC_CHN, ¶m); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_set_rc_param=0x%x\n", + (unsigned)ret); + return -1; + } + printf("> qpBounds: min=%u max=%u (0 = driver default %u/%u)\n", + (unsigned)param.h265_cbr_param.min_qp, + (unsigned)param.h265_cbr_param.max_qp, + (unsigned)g_cv610_qp_defaults.min_qp, + (unsigned)g_cv610_qp_defaults.max_qp); + return 0; +} + static int cv610_apply_verbose(bool on) { if (!g_cv610_runner) @@ -139,6 +269,17 @@ static int cv610_request_idr(void) ? 0 : -1; } +/* Ring-drop recovery form: unlike the public callback, report whether the + * request actually passed the shared limiter so the one-second holdoff can + * retry a coalesced request on the next chain-breaking drop. */ +static int cv610_ring_request_idr(void) +{ + if (!idr_rate_limit_allow(CV610_VENC_CHN)) + return 0; + return ss_mpi_venc_request_idr(CV610_VENC_CHN, TD_TRUE) == TD_SUCCESS + ? 1 : 0; +} + static uint32_t cv610_query_live_fps(void) { return g_cv610_runner ? g_cv610_runner->pipeline.fps : 0; @@ -249,6 +390,9 @@ static const VencApplyCallbacks g_cv610_apply_callbacks = { .apply_max_payload_size = cv610_apply_max_payload_size, .query_transport_status = cv610_query_transport_status, .query_audio_status = cv610_query_audio_status, + .query_iq_info = cv610_iq_query, + .apply_iq_param = cv610_iq_set, + .apply_qp_bounds = cv610_apply_qp_bounds, }; static void cv610_signal_handler(int signo) @@ -291,6 +435,20 @@ static int cv610_frame_is_idr(const uint8_t *frame, size_t len) return 0; } +static uint32_t cv610_frame_vcl_nal_count(const uint8_t *frame, size_t len) +{ + size_t cursor = 0; + const uint8_t *nal; + size_t nal_len; + uint32_t count = 0; + + while (h26x_util_annexb_next(frame, len, &cursor, &nal, &nal_len)) { + if (h26x_util_hevc_nalu_type(nal, nal_len) <= 31) + count++; + } + return count; +} + static int cv610_send_rtp_frame(Cv610RunnerContext *ctx, const uint8_t *frame, size_t len) { @@ -366,8 +524,229 @@ static int cv610_copy_stream(const ot_venc_stream *stream, uint8_t **out, return 0; } +static int cv610_apply_encoder_config(Cv610RunnerContext *ctx, + const Cv610EncoderConfig *enc) +{ + Cv610IntraRefreshStatus intra_status; + Cv610RefPredStatus ref_status; + ot_venc_intra_refresh intra; + ot_venc_intra_refresh intra_rb; + ot_venc_ref_param ref; + ot_venc_ref_param ref_rb; + ot_venc_slice_split split; + ot_venc_slice_split split_rb; + uint32_t delivered_slices = 1; + uint32_t cycle_len = 0; + td_s32 ret; + + if (!ctx || !enc) + return -1; + + memset(&intra_status, 0, sizeof(intra_status)); + memset(&ref_status, 0, sizeof(ref_status)); + snprintf(intra_status.mode_name, sizeof(intra_status.mode_name), "%s", + intra_refresh_mode_name(enc->intra.derived.mode)); + intra_status.mi_supported = 1; + intra_status.target_ms = enc->intra.derived.target_ms; + intra_status.total_rows = enc->intra.derived.total_rows; + intra_status.requested_lines = ctx->config.video0.intra_refresh_lines; + intra_status.effective_lines_per_p = enc->intra.refresh_num; + intra_status.lines_clamped = enc->intra.derived.lines_clamped; + intra_status.requested_qp = ctx->config.video0.intra_refresh_qp; + intra_status.effective_qp = enc->intra.request_i_qp; + intra_status.explicit_gop_sec = ctx->config.video0.gop_size; + intra_status.effective_gop_sec = enc->intra.derived.gop_overridden + ? ctx->config.video0.gop_size : enc->intra.derived.gop_sec; + intra_status.gop_auto = enc->intra.derived.gop_overridden + ? 0 : enc->intra.derived.gop_sec > 0.0; + + ref_status.mi_supported = 1; + ref_status.base = enc->ref.base; + ref_status.enhance = enc->ref.enhance; + ref_status.pred = enc->ref.pred ? 1 : 0; + + ctx->gdr_active = 0; + ctx->gdr_cycle_len = 0; + ctx->gdr_counter = 0; + ctx->svct_active = 0; + ctx->delivered_slice_count = 1; + ctx->slice_census_done = 0; + ctx->requested_slice_count = enc->slice.requested_count; + ctx->ref_census_frames = 0; + memset(ctx->ref_type_counts, 0, sizeof(ctx->ref_type_counts)); + ctx->trail_n_patched = 0; + + /* Fresh channels default intra refresh off, but always write the enable + * bit so restart behavior does not depend on a future firmware default. + * Preserve the driver's inactive refresh/QP values when disabling because + * zero is outside some vendor revisions' accepted range. */ + memset(&intra, 0, sizeof(intra)); + ret = ss_mpi_venc_get_intra_refresh(CV610_VENC_CHN, &intra); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_get_intra_refresh=0x%x\n", + (unsigned)ret); + goto fail; + } + intra.enable = enc->intra.enabled ? TD_TRUE : TD_FALSE; + intra.mode = OT_VENC_INTRA_REFRESH_ROW; + if (enc->intra.enabled) { + intra.refresh_num = enc->intra.refresh_num; + intra.request_i_qp = enc->intra.request_i_qp; + } + ret = ss_mpi_venc_set_intra_refresh(CV610_VENC_CHN, &intra); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_set_intra_refresh=0x%x " + "enable=%u rows=%u qp=%u\n", (unsigned)ret, + (unsigned)intra.enable, (unsigned)intra.refresh_num, + (unsigned)intra.request_i_qp); + goto fail; + } + memset(&intra_rb, 0, sizeof(intra_rb)); + ret = ss_mpi_venc_get_intra_refresh(CV610_VENC_CHN, &intra_rb); + if (ret != TD_SUCCESS || intra_rb.enable != intra.enable || + (enc->intra.enabled && + (intra_rb.mode != intra.mode || + intra_rb.refresh_num != intra.refresh_num || + intra_rb.request_i_qp != intra.request_i_qp))) { + fprintf(stderr, "ERROR: CV610 intra-refresh readback mismatch " + "ret=0x%x want=%u/%u/%u/%u got=%u/%u/%u/%u\n", + (unsigned)ret, (unsigned)intra.enable, (unsigned)intra.mode, + (unsigned)intra.refresh_num, (unsigned)intra.request_i_qp, + (unsigned)intra_rb.enable, (unsigned)intra_rb.mode, + (unsigned)intra_rb.refresh_num, + (unsigned)intra_rb.request_i_qp); + goto fail; + } + intra_status.apply_ok = 1; + intra_status.active = enc->intra.enabled ? 1 : 0; + intra_status.effective_lines_per_p = enc->intra.enabled + ? intra_rb.refresh_num : 0; + intra_status.effective_qp = enc->intra.enabled + ? intra_rb.request_i_qp : 0; + if (enc->intra.enabled && intra_rb.refresh_num > 0) { + cycle_len = (enc->intra.derived.total_rows + + intra_rb.refresh_num - 1u) / intra_rb.refresh_num; + ctx->gdr_active = 1; + ctx->gdr_cycle_len = cycle_len > 255u ? 255u : (uint8_t)cycle_len; + } + + /* The disabled state is the fresh-channel default. Only program the + * reference cadence when a preset requested it, avoiding an invented + * "off" tuple for an API whose base field must be greater than zero. */ + memset(&ref_rb, 0, sizeof(ref_rb)); + ret = ss_mpi_venc_get_ref_param(CV610_VENC_CHN, &ref_rb); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_get_ref_param=0x%x\n", + (unsigned)ret); + goto fail; + } + if (enc->ref.enabled) { + memset(&ref, 0, sizeof(ref)); + ref.base = enc->ref.base; + ref.enhance = enc->ref.enhance; + ref.pred_en = enc->ref.pred ? TD_TRUE : TD_FALSE; + ref.base_qp_delta_en = TD_FALSE; + ref.base_qp_delta = 0; + ret = ss_mpi_venc_set_ref_param(CV610_VENC_CHN, &ref); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_set_ref_param=0x%x " + "base=%u enhance=%u pred=%u\n", (unsigned)ret, + (unsigned)ref.base, (unsigned)ref.enhance, + (unsigned)ref.pred_en); + goto fail; + } + memset(&ref_rb, 0, sizeof(ref_rb)); + ret = ss_mpi_venc_get_ref_param(CV610_VENC_CHN, &ref_rb); + if (ret != TD_SUCCESS || ref_rb.base != ref.base || + ref_rb.enhance != ref.enhance || + ref_rb.pred_en != ref.pred_en || + ref_rb.base_qp_delta_en != ref.base_qp_delta_en || + ref_rb.base_qp_delta != ref.base_qp_delta) { + fprintf(stderr, "ERROR: CV610 ref-param readback mismatch " + "ret=0x%x want=%u/%u/%u/%u/%d " + "got=%u/%u/%u/%u/%d\n", + (unsigned)ret, (unsigned)ref.base, + (unsigned)ref.enhance, (unsigned)ref.pred_en, + (unsigned)ref.base_qp_delta_en, + (int)ref.base_qp_delta, + (unsigned)ref_rb.base, (unsigned)ref_rb.enhance, + (unsigned)ref_rb.pred_en, + (unsigned)ref_rb.base_qp_delta_en, + (int)ref_rb.base_qp_delta); + goto fail; + } + ref_status.active = 1; + ctx->svct_active = 1; + } + ref_status.apply_ok = 1; + + /* split_mode=1 is the live firmware's row-split default. Early slice + * output remains off: this runtime publishes one whole access unit per + * GetStream result to both frame-SHM and RTP. */ + memset(&split, 0, sizeof(split)); + ret = ss_mpi_venc_get_slice_split(CV610_VENC_CHN, &split); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_get_slice_split=0x%x\n", + (unsigned)ret); + goto fail; + } + split.enable = enc->slice.enabled ? TD_TRUE : TD_FALSE; + split.slice_output_en = TD_FALSE; + if (enc->slice.enabled) { + split.split_mode = enc->slice.split_mode; + split.split_size = enc->slice.split_size; + } + ret = ss_mpi_venc_set_slice_split(CV610_VENC_CHN, &split); + if (ret != TD_SUCCESS) { + fprintf(stderr, "ERROR: ss_mpi_venc_set_slice_split=0x%x " + "enable=%u mode=%u size=%u\n", (unsigned)ret, + (unsigned)split.enable, (unsigned)split.split_mode, + (unsigned)split.split_size); + goto fail; + } + memset(&split_rb, 0, sizeof(split_rb)); + ret = ss_mpi_venc_get_slice_split(CV610_VENC_CHN, &split_rb); + if (ret != TD_SUCCESS || split_rb.enable != split.enable || + split_rb.slice_output_en != TD_FALSE || + (enc->slice.enabled && + (split_rb.split_mode != split.split_mode || + split_rb.split_size != split.split_size))) { + fprintf(stderr, "ERROR: CV610 slice readback mismatch " + "ret=0x%x want=%u/%u/%u/0 got=%u/%u/%u/%u\n", + (unsigned)ret, (unsigned)split.enable, + (unsigned)split.split_mode, (unsigned)split.split_size, + (unsigned)split_rb.enable, (unsigned)split_rb.split_mode, + (unsigned)split_rb.split_size, + (unsigned)split_rb.slice_output_en); + goto fail; + } + if (enc->slice.enabled && split_rb.split_size > 0) + delivered_slices = (enc->slice.total_lcu_rows + + split_rb.split_size - 1u) / split_rb.split_size; + ctx->delivered_slice_count = delivered_slices > 255u + ? 255u : (uint8_t)delivered_slices; + + cv610_publish_encoder_status(&intra_status, &ref_status); + fprintf(stderr, "[waybeam] CV610 resilience: intra=%s rows=%u qp=%u " + "cycle=%u ref=%u/%u pred=%u\n", intra_status.mode_name, + (unsigned)intra_status.effective_lines_per_p, + (unsigned)intra_status.effective_qp, (unsigned)cycle_len, + (unsigned)ref_status.base, (unsigned)ref_status.enhance, + (unsigned)ref_status.pred); + fprintf(stderr, "[waybeam] CV610 slices: requested=%u delivered=%u " + "mode=%u lcu_rows_per_slice=%u early_output=0\n", + (unsigned)enc->slice.requested_count, (unsigned)delivered_slices, + (unsigned)split_rb.split_mode, (unsigned)split_rb.split_size); + return 0; + +fail: + cv610_publish_encoder_status(&intra_status, &ref_status); + return -1; +} + static int cv610_venc_start(Cv610RunnerContext *ctx) { + Cv610EncoderConfig enc; ot_venc_chn_attr attr; ot_venc_h265_vui vui; ot_venc_start_param start; @@ -376,8 +755,16 @@ static int cv610_venc_start(Cv610RunnerContext *ctx) uint32_t gop; td_s32 ret; + if (cv610_encoder_config_derive(&ctx->config, ctx->pipeline.out_height, + ctx->pipeline.fps, &enc) != 0) { + fprintf(stderr, "ERROR: invalid CV610 encoder resilience/slice config\n"); + return -1; + } gop = ctx->config.video0.gop_size <= 0.0 ? 1u : (uint32_t)(ctx->config.video0.gop_size * ctx->pipeline.fps + 0.5); + if (enc.intra.enabled && !enc.intra.derived.gop_overridden && + enc.intra.derived.gop_frames > 0) + gop = enc.intra.derived.gop_frames; if (gop == 0) gop = 1; memset(&attr, 0, sizeof(attr)); @@ -407,6 +794,21 @@ static int cv610_venc_start(Cv610RunnerContext *ctx) return -1; } ctx->venc_created = 1; + if (cv610_apply_encoder_config(ctx, &enc) != 0) + return -1; + /* video0.minQp/maxQp are MUT_LIVE, but they also have to take effect on + * a cold boot -- the config is read before the channel exists, so the + * live path never runs for a value that was already in the file. */ + if (ctx->config.video0.min_qp || ctx->config.video0.max_qp) { + /* Not (void): a rejected cold-boot apply would otherwise leave the + * operator booting with no QP bound and no indication. */ + if (cv610_apply_qp_bounds(ctx->config.video0.min_qp, + ctx->config.video0.max_qp) != 0) + fprintf(stderr, "WARN: qpBounds from config not applied " + "(min=%u max=%u)\n", + (unsigned)ctx->config.video0.min_qp, + (unsigned)ctx->config.video0.max_qp); + } memset(&vui, 0, sizeof(vui)); ret = ss_mpi_venc_get_h265_vui(CV610_VENC_CHN, &vui); if (ret != TD_SUCCESS) @@ -517,22 +919,35 @@ static int cv610_prepare(void *opaque) Cv610RunnerContext *ctx = opaque; VencConfig *cfg = &ctx->config; const Cv610SensorMode *mode; + int mode_index = -1; setvbuf(stdout, NULL, _IONBF, 0); /* Config loading and every staged HTTP mutation run the same lookup * through cv610_validate_config(), so reaching this is a config file * edited behind the daemon's back. */ - mode = cv610_mode_for_fps(cfg->video0.fps); + mode = cv610_mode_select(cfg->sensor.mode, cfg->video0.fps, &mode_index); if (mode == NULL || cv610_mode_check_output(mode, cfg->video0.width, cfg->video0.height) != NULL) { fprintf(stderr, "ERROR: CV610 cannot encode %ux%u @ %u fps\n", cfg->video0.width, cfg->video0.height, cfg->video0.fps); return 1; } + /* The sensor runs at the MODE's rate. Say so when that is not what was + * asked for — a forced sensor.mode and a substituted target both land + * here, and silence would leave every status endpoint reporting a rate + * the operator never chose. */ + if (mode->fps != cfg->video0.fps) + printf("> Requested %u fps, using %u fps (sensor mode %d: %s)\n", + cfg->video0.fps, mode->fps, mode_index, mode->desc); + /* Publish what was actually selected, so /api/v1/modes reports the + * achieved mode rather than recomputing the configured one — the same + * contract star6e_pipeline.c fulfils after sensor_select(). */ + venc_api_set_sensor_info(0, mode_index, cfg->sensor.index); ctx->pipeline.width = mode->width; ctx->pipeline.height = mode->height; cv610_mode_resolve_output(mode, cfg->video0.width, cfg->video0.height, &ctx->pipeline.out_width, &ctx->pipeline.out_height); + ctx->pipeline.keep_aspect = cfg->isp.keep_aspect ? 1 : 0; ctx->pipeline.fps = mode->fps; ctx->pipeline.lanes = 4; ctx->pipeline.data_rate_x2 = 0; @@ -587,10 +1002,15 @@ static int cv610_init(void *opaque) * config toggle must not be able to take video down with it. * /api/v1/audio/status reports the running state, not the flag. */ ctx->audio = cv610_audio_start(&ctx->config, &ctx->output_uri); + /* No cause is guessed here. This line used to assert "needs + * CV610_AUDIO=1 at module load" for every failure, which sent the + * operator after the module set while the real cause was a + * predecessor's stale AI claim. Each failure point in + * cv610_audio_start() names itself, including the module-absent one. */ if (!ctx->audio) fprintf(stderr, "WARNING: CV610 audio did not start; continuing without it " - "(needs CV610_AUDIO=1 at module load)\n"); + "(cause reported above)\n"); } g_cv610_runner = ctx; if (venc_api_register(&ctx->config, "cv610", @@ -692,19 +1112,82 @@ static int cv610_run(void *opaque) continue; } if (cv610_copy_stream(&stream, &frame, &frame_len) == 0) { - int is_idr = cv610_frame_is_idr(frame, frame_len); + int is_enhance = ctx->svct_active && + stream.h265_info.ref_type == + OT_VENC_ENHANCE_P_SLICE_NOT_FOR_REF; + int is_idr; + size_t patched = 0; + + if (is_enhance) + patched = h26x_util_hevc_patch_trail_r_to_n(frame, frame_len); + if (ctx->svct_active && ctx->ref_census_frames < 64u) { + unsigned int ref_type = (unsigned int)stream.h265_info.ref_type; + + if (ref_type < OT_VENC_P_SLICE_BUTT) + ctx->ref_type_counts[ref_type]++; + ctx->trail_n_patched += (uint32_t)patched; + ctx->ref_census_frames++; + if (ctx->ref_census_frames == 64u) { + fprintf(stderr, "[waybeam] CV610 ref census: frames=64 " + "types=%u,%u,%u,%u,%u,%u trail_n_patched=%u\n", + (unsigned)ctx->ref_type_counts[0], + (unsigned)ctx->ref_type_counts[1], + (unsigned)ctx->ref_type_counts[2], + (unsigned)ctx->ref_type_counts[3], + (unsigned)ctx->ref_type_counts[4], + (unsigned)ctx->ref_type_counts[5], + (unsigned)ctx->trail_n_patched); + } + } + is_idr = cv610_frame_is_idr(frame, frame_len); + if (!ctx->slice_census_done && + ctx->requested_slice_count > 1) { + uint32_t vcl_nals = cv610_frame_vcl_nal_count(frame, + frame_len); + + if (vcl_nals > 0) { + fprintf(stderr, "[waybeam] CV610 slice census: " + "requested=%u expected=%u actual_vcl_nals=%u\n", + (unsigned)ctx->requested_slice_count, + (unsigned)ctx->delivered_slice_count, + (unsigned)vcl_nals); + ctx->delivered_slice_count = vcl_nals > 255u + ? 255u : (uint8_t)vcl_nals; + ctx->slice_census_done = 1; + } + } if (ctx->frame_ring) { VencFrameMeta meta; + int write_ret; memset(&meta, 0, sizeof(meta)); meta.pts = stream.pack_cnt ? (uint32_t)stream.pack[0].pts : 0; meta.codec = VENC_FRAME_CODEC_H265; meta.flags = is_idr ? VENC_FRAME_FLAG_IDR : 0; - if (venc_frame_ring_write(ctx->frame_ring, &meta, - frame, (uint32_t)frame_len) != 0) + if (is_enhance) + meta.flags |= VENC_FRAME_FLAG_ENHANCE; + if (is_idr) { + ctx->gdr_counter = 0; + } else if (ctx->gdr_active && ctx->gdr_cycle_len > 0) { + meta.flags |= VENC_FRAME_FLAG_GDR; + meta.gdr_pos = ctx->gdr_counter; + meta.gdr_len = ctx->gdr_cycle_len; + ctx->gdr_counter++; + if (ctx->gdr_counter >= ctx->gdr_cycle_len) + ctx->gdr_counter = 0; + } + write_ret = venc_frame_ring_write(ctx->frame_ring, &meta, + frame, (uint32_t)frame_len); + if (write_ret != 0) { __atomic_add_fetch(&ctx->output_drops, 1, __ATOMIC_RELAXED); + if (venc_frame_drop_breaks_chain(meta.flags) && + venc_frame_drop_idr_due(&ctx->drop_idr_last_us, + wb_monotonic_us()) && + cv610_ring_request_idr() == 0) + ctx->drop_idr_last_us = 0; + } } else if (ctx->socket_handle >= 0) { /* cv610_output_write owns per-datagram drop accounting. */ (void)cv610_send_rtp_frame(ctx, frame, frame_len); diff --git a/src/cv610_validation.c b/src/cv610_validation.c index 5888bbfb..06fd37ae 100644 --- a/src/cv610_validation.c +++ b/src/cv610_validation.c @@ -8,35 +8,42 @@ * loading and staged HTTP mutations. */ const char *cv610_validate_config(const VencConfig *cfg) { + const Cv610SensorMode *mode; VencOutputUri uri; + size_t mode_count = 0; + const char *err; if (!cfg) return "missing config"; - /* video0.fps selects the sensor mode; video0.size is the encoded size - * VPSS scales that capture down to. /api/v1/modes lists the modes. */ - { - const Cv610SensorMode *mode = cv610_mode_for_fps(cfg->video0.fps); - const char *err; - - if (mode == NULL) - return "CV610 video0.fps must name a mode listed by /api/v1/modes"; - err = cv610_mode_check_output(mode, cfg->video0.width, - cfg->video0.height); - if (err) - return err; - } + /* sensor.mode and video0.fps select the sensor mode together, the way + * they do on SigmaStar: an explicit sensor.mode wins, otherwise the rate + * is a target. video0.size is the encoded size VPSS scales that capture + * down to. /api/v1/modes lists the modes. */ + cv610_mode_table(&mode_count); + if (cfg->sensor.index > 0) + return "CV610 has a single sensor pad: sensor.index must be -1 or 0"; + if (cfg->sensor.mode >= 0 && (size_t)cfg->sensor.mode >= mode_count) + return "CV610 sensor.mode is not an index listed by /api/v1/modes"; + mode = cv610_mode_select(cfg->sensor.mode, cfg->video0.fps, NULL); + if (mode == NULL) + return "CV610 video0.fps must name a mode listed by /api/v1/modes"; + err = cv610_mode_check_output(mode, cfg->video0.width, + cfg->video0.height); + if (err) + return err; if (cfg->video0.bitrate < VENC_BITRATE_MIN_KBPS || cfg->video0.bitrate > VENC_BITRATE_MAX_KBPS) return "video0.bitrate is outside the supported range"; if (cfg->video0.qp_delta < -10 || cfg->video0.qp_delta > 30) return "CV610 video0.qp_delta must be between -10 and 30"; + /* Against the SELECTED mode's rate, which is what cv610_runtime.c turns + * into a GOP length. Once sensor.mode can force a mode, or a target + * rate can be substituted, that is no longer video0.fps. */ if (!isfinite(cfg->video0.gop_size) || cfg->video0.gop_size < 0.0 || - cfg->video0.gop_size * cfg->video0.fps > 65536.0) + cfg->video0.gop_size * mode->fps > 65536.0) return "CV610 video0.gop_size exceeds the encoder's 65536-frame limit"; if (strcmp(cfg->video0.rc_mode, "cbr") != 0) return "CV610 phase one supports video0.rc_mode=cbr only"; - if (strcmp(cfg->video0.resilience, "off") != 0) - return "CV610 phase one supports video0.resilience=off only"; if (strcmp(cfg->video0.framing, "off") != 0) return "CV610 phase one supports video0.framing=off only"; if (cfg->audio.enabled && diff --git a/src/h26x_util.c b/src/h26x_util.c index 25fcd06a..06ce7011 100644 --- a/src/h26x_util.c +++ b/src/h26x_util.c @@ -101,3 +101,24 @@ int h26x_util_annexb_next(const uint8_t *data, size_t len, size_t *cursor, *cursor = len; return 0; } + +size_t h26x_util_hevc_patch_trail_r_to_n(uint8_t *data, size_t len) +{ + size_t cursor = 0; + size_t changed = 0; + const uint8_t *nal; + size_t nal_len; + + if (!data) + return 0; + while (h26x_util_annexb_next(data, len, &cursor, &nal, &nal_len)) { + /* Byte 0 is forbidden_zero | nal_unit_type | layer_id_msb; + * byte 1 starts with the other five layer-id bits. Only rewrite + * layer zero: 0x02 is TRAIL_R and 0x00 is TRAIL_N there. */ + if (nal_len > 1 && nal[0] == 0x02 && (nal[1] & 0xf8u) == 0) { + data[nal - data] = 0x00; + changed++; + } + } + return changed; +} diff --git a/src/maruko_config.c b/src/maruko_config.c index a8c63e65..ecef469c 100644 --- a/src/maruko_config.c +++ b/src/maruko_config.c @@ -47,6 +47,7 @@ void maruko_config_defaults(MarukoBackendConfig *cfg) cfg->ref_base = 0; cfg->ref_enhance = 0; cfg->ref_pred = 1; + cfg->slice_count = 1; snprintf(cfg->resilience, sizeof(cfg->resilience), "%s", "off"); memset(&cfg->imu, 0, sizeof(cfg->imu)); memset(&cfg->audio, 0, sizeof(cfg->audio)); @@ -126,6 +127,7 @@ int maruko_config_from_venc(const VencConfig *vcfg, MarukoBackendConfig *cfg) cfg->ref_base = vcfg->video0.ref_base; cfg->ref_enhance = vcfg->video0.ref_enhance; cfg->ref_pred = vcfg->video0.ref_pred ? 1 : 0; + cfg->slice_count = vcfg->video0.slice_count; snprintf(cfg->resilience, sizeof(cfg->resilience), "%s", vcfg->video0.resilience); cfg->gop_size_sec = vcfg->video0.gop_size; diff --git a/src/maruko_mi.c b/src/maruko_mi.c index 10f7d225..019e9e0e 100644 --- a/src/maruko_mi.c +++ b/src/maruko_mi.c @@ -271,6 +271,10 @@ static int i6c_venc_load(maruko_venc_impl *venc) int (*)(int, int, void *), "MI_VENC_SetRefParam"); LOAD_SYM(venc, "libmi_venc.so", fnGetRefParam, int (*)(int, int, void *), "MI_VENC_GetRefParam"); + LOAD_SYM_OPTIONAL(venc, "libmi_venc.so", fnSetH265SliceSplit, + int (*)(int, int, void *), "MI_VENC_SetH265SliceSplit"); + LOAD_SYM_OPTIONAL(venc, "libmi_venc.so", fnGetH265SliceSplit, + int (*)(int, int, void *), "MI_VENC_GetH265SliceSplit"); if (!venc->fnCreateDev || !venc->fnDestroyDev || !venc->fnCreateChn || !venc->fnDestroyChn || diff --git a/src/maruko_output.c b/src/maruko_output.c index f15c04ff..717b9dc7 100644 --- a/src/maruko_output.c +++ b/src/maruko_output.c @@ -41,6 +41,8 @@ int maruko_output_init(MarukoOutput *output, const VencOutputUri *uri, output->connected_udp = 0; output->allow_unix_encoder_stall = allow_unix_encoder_stall ? 1 : 0; output->send_errors = 0; + output->drop_idr_last_us = 0; + output->trunc_warned = 0; memset(&output->send_queue, 0, sizeof(output->send_queue)); __atomic_store_n(&output->socket_drops, 0, __ATOMIC_RELAXED); __atomic_store_n(&output->socket_writes, 0, __ATOMIC_RELAXED); @@ -74,6 +76,8 @@ int maruko_output_init_shm(MarukoOutput *output, const char *shm_name) output->connected_udp = 0; output->allow_unix_encoder_stall = 0; output->send_errors = 0; + output->drop_idr_last_us = 0; + output->trunc_warned = 0; memset(&output->send_queue, 0, sizeof(output->send_queue)); __atomic_store_n(&output->socket_drops, 0, __ATOMIC_RELAXED); __atomic_store_n(&output->socket_writes, 0, __ATOMIC_RELAXED); @@ -112,6 +116,8 @@ int maruko_output_init_frame_shm(MarukoOutput *output, const char *shm_name) output->connected_udp = 0; output->allow_unix_encoder_stall = 0; output->send_errors = 0; + output->drop_idr_last_us = 0; + output->trunc_warned = 0; memset(&output->send_queue, 0, sizeof(output->send_queue)); __atomic_store_n(&output->socket_drops, 0, __ATOMIC_RELAXED); __atomic_store_n(&output->socket_writes, 0, __ATOMIC_RELAXED); diff --git a/src/maruko_pipeline.c b/src/maruko_pipeline.c index 073bcfe8..6169af91 100644 --- a/src/maruko_pipeline.c +++ b/src/maruko_pipeline.c @@ -6,6 +6,7 @@ #include "debug_osd.h" #include "detect_wire.h" #include "hevc_rtp.h" +#include "h26x_util.h" #include "idr_rate_limit.h" #include "intra_refresh.h" #include "isp_runtime.h" @@ -1974,15 +1975,17 @@ void maruko_pipeline_ref_pred_status(MarukoRefPredStatus *out) * just broke. Gated by the shared per-channel IDR rate limiter so a * persistently full ring coalesces instead of firing keyframes into the ring * that is already congested. Mirrors star6e_scene_request_idr(). */ -static void maruko_ring_request_idr(void *vctx) +static int maruko_ring_request_idr(void *vctx) { MarukoBackendContext *ctx = (MarukoBackendContext *)vctx; if (!ctx) - return; - if (idr_rate_limit_allow(ctx->venc_channel)) - maruko_mi_venc_request_idr(ctx->venc_device, - ctx->venc_channel, 1); + return 0; + if (!idr_rate_limit_allow(ctx->venc_channel)) + return 0; + maruko_mi_venc_request_idr(ctx->venc_device, + ctx->venc_channel, 1); + return 1; } static int maruko_apply_ref_pred(MI_VENC_DEV dev, MI_VENC_CHN chn, @@ -2031,6 +2034,67 @@ static int maruko_apply_ref_pred(MI_VENC_DEV dev, MI_VENC_CHN chn, return snap.active ? 0 : (cfg && cfg->ref_base > 0 ? -1 : 0); } +static int maruko_apply_slice_split(MI_VENC_DEV dev, MI_VENC_CHN chn, + const MarukoBackendConfig *cfg, uint32_t height) +{ + MI_VENC_ParamH265SliceSplit_t requested; + MI_VENC_ParamH265SliceSplit_t actual; + uint32_t rows32; + uint32_t rows_per_slice; + uint32_t ctu_rows; + uint32_t ctu_per_slice; + uint32_t predicted; + + if (!cfg || cfg->slice_count <= 1) + return 0; + if (cfg->rc_codec != PT_H265) { + fprintf(stderr, "ERROR: [maruko] sliceCount=%u requires H.265\n", + cfg->slice_count); + return -1; + } + if (!g_mi_venc.fnSetH265SliceSplit || + !g_mi_venc.fnGetH265SliceSplit) { + fprintf(stderr, "ERROR: [maruko] sliceCount=%u requested but " + "libmi_venc.so lacks H.265 slice split Set/Get\n", + cfg->slice_count); + return -1; + } + + rows32 = (height + 31U) / 32U; + rows_per_slice = (rows32 + cfg->slice_count - 1U) / + cfg->slice_count; + memset(&requested, 0, sizeof(requested)); + requested.bSplitEnable = 1; + requested.u32SliceRowCount = rows_per_slice; + if (maruko_mi_venc_set_h265_slice_split(dev, chn, &requested) != 0) { + fprintf(stderr, "ERROR: [maruko] MI_VENC_SetH265SliceSplit" + "(dev=%d, chn=%d, rows=%u) failed\n", + dev, chn, rows_per_slice); + return -1; + } + + memset(&actual, 0, sizeof(actual)); + if (maruko_mi_venc_get_h265_slice_split(dev, chn, &actual) != 0 || + !actual.bSplitEnable || + actual.u32SliceRowCount == 0 || + actual.u32SliceRowCount > rows32) { + fprintf(stderr, "ERROR: [maruko] H.265 slice split readback " + "invalid: enable=%u rows=%u requested_rows=%u\n", + (unsigned int)actual.bSplitEnable, + actual.u32SliceRowCount, rows_per_slice); + return -1; + } + + ctu_rows = (height + 63U) / 64U; + ctu_per_slice = (actual.u32SliceRowCount + 1U) / 2U; + predicted = (ctu_rows + ctu_per_slice - 1U) / ctu_per_slice; + fprintf(stderr, "[waybeam] sliceSplit: dev=%d chn=%d requested=%u " + "requested_rows32=%u applied_rows32=%u predicted=%u " + "(readback verified)\n", dev, chn, cfg->slice_count, + rows_per_slice, actual.u32SliceRowCount, predicted); + return 0; +} + static int maruko_start_venc(const MarukoBackendConfig *cfg, uint32_t width, uint32_t height, uint32_t framerate, MI_VENC_DEV venc_dev, MI_VENC_CHN *chn, int *dev_created) @@ -2100,6 +2164,15 @@ static int maruko_start_venc(const MarukoBackendConfig *cfg, } return ret; } + ret = maruko_apply_slice_split(venc_dev, *chn, cfg, height); + if (ret != 0) { + (void)maruko_mi_venc_destroy_chn(venc_dev, *chn); + if (dev_created && *dev_created) { + (void)maruko_mi_venc_destroy_dev(venc_dev); + *dev_created = 0; + } + return ret; + } /* stab-fill: NORMAL (frame-base) input — required for the manual * ChnInputPortGetBuf/PutBuf feed (NORMAL == E_MI_VENC_INPUT_MODE_ @@ -2407,6 +2480,27 @@ static void assign_maruko_ports(MarukoBackendContext *ctx, }; } +static void maruko_update_output_resilience_flags(MarukoBackendContext *ctx) +{ + MarukoIntraRefreshStatus ir_status; + MarukoRefPredStatus ref_status; + uint32_t clen; + + if (!ctx) + return; + maruko_pipeline_intra_refresh_status(&ir_status); + maruko_pipeline_ref_pred_status(&ref_status); + ctx->output.gdr_active = ir_status.active && ir_status.apply_ok; + ctx->output.svct_active = ref_status.active && ref_status.apply_ok; + clen = (ctx->output.gdr_active && ir_status.total_rows && + ir_status.effective_lines_per_p) + ? (ir_status.total_rows + ir_status.effective_lines_per_p - 1) / + ir_status.effective_lines_per_p + : 0; + ctx->output.gdr_cycle_len = clen > 255 ? 255 : (uint8_t)clen; + ctx->output.gdr_counter = 0; +} + /* stab-fill: finish the manual-feed VENC bring-up. The fill module pushes the * composed frames straight into the (NORMAL_FRMBASE, unbound) VENC input port * — device-proven at 50 fps. Phase 5a's "the i6c VENC cannot be manually @@ -2428,6 +2522,7 @@ static int maruko_setup_stabfill_venc(MarukoBackendContext *ctx) (void)maruko_apply_intra_refresh(ctx->venc_device, ctx->venc_channel, &ctx->cfg, ctx->cfg.image_height, ctx->sensor.fps, ctx->cfg.rc_codec); + maruko_update_output_resilience_flags(ctx); printf("> [maruko] stab-fill: VENC(%d,%d) NORMAL_FRMBASE manual-feed " "@ %ux%u (port0 RAW unbound -> compose -> push)\n", @@ -2448,23 +2543,9 @@ static int bind_maruko_pipeline(MarukoBackendContext *ctx) return -1; ctx->venc_started = 1; - ctx->output.gdr_active = - (ctx->cfg.intra_refresh_mode[0] != '\0' && - strcmp(ctx->cfg.intra_refresh_mode, "off") != 0) ? 1 : 0; - ctx->output.svct_active = ctx->cfg.ref_base > 0 ? 1 : 0; ctx->output.request_idr = maruko_ring_request_idr; ctx->output.idr_ctx = ctx; - { - IntraRefreshDerived gdr_ir; - (void)maruko_intra_refresh_derive(&ctx->cfg, - ctx->cfg.image_height, ctx->sensor.fps, - ctx->cfg.rc_codec, &gdr_ir); - uint32_t clen = (gdr_ir.total_rows && gdr_ir.lines) - ? (gdr_ir.total_rows + gdr_ir.lines - 1) / gdr_ir.lines - : 0; - ctx->output.gdr_cycle_len = clen > 255 ? 255 : (uint8_t)clen; - ctx->output.gdr_counter = 0; - } + maruko_update_output_resilience_flags(ctx); MI_U32 venc_device = (MI_U32)ctx->venc_device; assign_maruko_ports(ctx, venc_device); @@ -2967,6 +3048,28 @@ static void *maruko_dual_stream_thread(void *arg) usleep(1000); continue; } + if (!maruko_video_stream_packet_info_complete(&stream)) { + static int incomplete_warned; + if (!incomplete_warned) { + incomplete_warned = 1; + fprintf(stderr, "WARN: [maruko][dual] invalid packetInfo; " + "dropping whole access unit\n"); + } + if (!(d->output.svct_active && + stream.h265Info.refType == + MARUKO_REFTYPE_ENHANCE_P_NOTFORREF) && + venc_frame_drop_idr_due(&d->output.drop_idr_last_us, + wb_monotonic_us())) { + if (idr_rate_limit_allow(d->channel)) + (void)maruko_mi_venc_request_idr( + ctx->venc_device, d->channel, 1); + else + d->output.drop_idr_last_us = 0; + } + (void)maruko_mi_venc_release_stream(ctx->venc_device, + d->channel, &stream); + continue; + } if (g_maruko_running) { if (d->is_dual_stream) { @@ -3654,12 +3757,38 @@ static uint8_t maruko_scene_is_idr(const i6c_venc_strm *s, int codec) if (!s || !s->packet) return 0; for (i = 0; i < s->count; i++) { const i6c_venc_pack *p = &s->packet[i]; - unsigned int k, n = p->packNum > 8 ? 8 : p->packNum; + const unsigned int info_cap = (unsigned int)( + sizeof(p->packetInfo) / sizeof(p->packetInfo[0])); + unsigned int k, n = p->packNum; + if (n > info_cap) { + if (p->data && p->length > p->offset) { + size_t cursor = 0; + const uint8_t *nal; + size_t nal_len; + + while (h26x_util_annexb_next(p->data + p->offset, + p->length - p->offset, &cursor, &nal, + &nal_len)) { + uint8_t type = codec == 0 + ? h26x_util_h264_nalu_type(nal, + nal_len) + : h26x_util_hevc_nalu_type(nal, + nal_len); + if ((codec == 0 && type == 5) || + (codec != 0 && + (type == 19 || type == 20))) + return 1; + } + } + continue; + } if (n > 0) { for (k = 0; k < n; k++) { if (codec == 0 && p->packetInfo[k].packType.h264Nalu == 5) return 1; - if (codec != 0 && p->packetInfo[k].packType.h265Nalu == 19) + if (codec != 0 && + (p->packetInfo[k].packType.h265Nalu == 19 || + p->packetInfo[k].packType.h265Nalu == 20)) return 1; } } else { @@ -3885,8 +4014,15 @@ static void maruko_patch_pack_to_trail_n(i6c_venc_pack *pack) if (pack->packNum > 0) { const unsigned int info_cap = (unsigned int)(sizeof(pack->packetInfo) / sizeof(pack->packetInfo[0])); - unsigned int n = pack->packNum > info_cap ? info_cap : pack->packNum; + unsigned int n = pack->packNum; unsigned int k; + if (n > info_cap) { + unsigned int off = pack->offset; + if (off < pack->length) + (void)h26x_util_hevc_patch_trail_r_to_n( + pack->data + off, pack->length - off); + return; + } for (k = 0; k < n; ++k) { unsigned int off = pack->packetInfo[k].offset; unsigned int nlen = pack->packetInfo[k].length; @@ -4049,6 +4185,12 @@ static int maruko_pipeline_process_stream(MarukoBackendContext *ctx, "ERROR: [maruko] MI_VENC_GetStream failed %d\n", ret); return -1; } + if (maruko_video_reject_incomplete_access_unit(&stream, + &ctx->output)) { + (void)maruko_mi_venc_release_stream(ctx->venc_device, + ctx->venc_channel, &stream); + return 0; + } /* refPred error-resilience marking — rewrite TRAIL_R → TRAIL_N for * frames the SDK marked as ENHANCE_P_NOTFORREF. i6c shares this @@ -4056,7 +4198,7 @@ static int maruko_pipeline_process_stream(MarukoBackendContext *ctx, * correct internally but every NAL is emitted as TRAIL_R, leaving * generic decoders unable to identify non-reference frames. See * star6e_runtime.c for the matching helper. */ - if (ctx->cfg.ref_base > 0 && + if (ctx->output.svct_active && stream.h265Info.refType == MARUKO_REFTYPE_ENHANCE_P_NOTFORREF) { maruko_patch_stream_to_trail_n(&stream); } @@ -4463,7 +4605,8 @@ int maruko_pipeline_run(MarukoBackendContext *ctx) MarukoStreamRuntime rt; int result = -1; - if (!ctx || (ctx->output.socket_handle < 0 && !ctx->output.ring)) + if (!ctx || (ctx->output.socket_handle < 0 && !ctx->output.ring && + !ctx->output.frame_ring)) return -1; if (ctx->cfg.stream_mode == MARUKO_STREAM_RTP && diff --git a/src/maruko_recorder.c b/src/maruko_recorder.c index ec882d3a..706b56fb 100644 --- a/src/maruko_recorder.c +++ b/src/maruko_recorder.c @@ -1,4 +1,5 @@ #include "maruko_recorder.h" +#include "maruko_video.h" #include #include @@ -14,15 +15,45 @@ * difference does not have to be juggled with #ifdefs in * star6e_recorder.c. */ -static ssize_t writev_retry(int fd, const struct iovec *iov, int iov_count) +static ssize_t writev_all(int fd, const struct iovec *iov, int iov_count) { - ssize_t ret; + struct iovec pending[16]; + ssize_t total = 0; + int first = 0; - do { - ret = writev(fd, iov, iov_count); - } while (ret < 0 && errno == EINTR); + if (!iov || iov_count <= 0 || iov_count > 16) { + errno = EINVAL; + return -1; + } + memcpy(pending, iov, (size_t)iov_count * sizeof(pending[0])); + while (first < iov_count) { + ssize_t ret; + ssize_t consumed; + + do { + ret = writev(fd, &pending[first], iov_count - first); + } while (ret < 0 && errno == EINTR); + if (ret < 0) + return -1; + if (ret == 0) { + errno = EIO; + return -1; + } + total += ret; + consumed = ret; + while (first < iov_count && + consumed >= (ssize_t)pending[first].iov_len) { + consumed -= (ssize_t)pending[first].iov_len; + first++; + } + if (first < iov_count && consumed > 0) { + pending[first].iov_base = + (char *)pending[first].iov_base + consumed; + pending[first].iov_len -= (size_t)consumed; + } + } - return ret; + return total; } static int check_disk_space(Star6eRecorderState *state) @@ -71,16 +102,28 @@ static void stop_with_error(Star6eRecorderState *state, int err) int maruko_recorder_write_frame(Star6eRecorderState *state, const i6c_venc_strm *stream) { + static int incomplete_warned; struct iovec iov[16]; int iov_count = 0; ssize_t written; size_t total = 0; + off_t frame_start; if (!state || state->fd < 0 || !stream || !stream->packet) return 0; + if (!maruko_video_stream_packet_info_complete(stream)) { + if (!incomplete_warned) { + incomplete_warned = 1; + fprintf(stderr, + "[maruko_recorder] incomplete packetInfo table; " + "dropping whole access unit\n"); + } + return 0; + } if (check_disk_space(state) != 0) return 0; + frame_start = lseek(state->fd, 0, SEEK_CUR); for (unsigned int i = 0; i < stream->count; ++i) { const i6c_venc_pack *pack = &stream->packet[i]; @@ -89,14 +132,8 @@ int maruko_recorder_write_frame(Star6eRecorderState *state, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; - if (nal_count > info_cap) - nal_count = info_cap; - for (unsigned int k = 0; k < nal_count; ++k) { unsigned int off = pack->packetInfo[k].offset; unsigned int len = pack->packetInfo[k].length; @@ -106,7 +143,7 @@ int maruko_recorder_write_frame(Star6eRecorderState *state, continue; if (iov_count >= 16) { - written = writev_retry(state->fd, + written = writev_all(state->fd, iov, iov_count); if (written < 0) goto write_error; @@ -124,7 +161,7 @@ int maruko_recorder_write_frame(Star6eRecorderState *state, continue; if (iov_count >= 16) { - written = writev_retry(state->fd, iov, + written = writev_all(state->fd, iov, iov_count); if (written < 0) goto write_error; @@ -141,7 +178,7 @@ int maruko_recorder_write_frame(Star6eRecorderState *state, } if (iov_count > 0) { - written = writev_retry(state->fd, iov, iov_count); + written = writev_all(state->fd, iov, iov_count); if (written < 0) goto write_error; total += (size_t)written; @@ -160,6 +197,13 @@ int maruko_recorder_write_frame(Star6eRecorderState *state, return (int)total; write_error: - stop_with_error(state, errno); + { + int saved_errno = errno; + /* A failure may follow a short successful write. Roll the regular file + * back to its frame boundary so recording never retains half an AU. */ + if (frame_start >= 0) + (void)ftruncate(state->fd, frame_start); + stop_with_error(state, saved_errno); + } return -1; } diff --git a/src/maruko_ts_recorder.c b/src/maruko_ts_recorder.c index 867d9e95..0c16db02 100644 --- a/src/maruko_ts_recorder.c +++ b/src/maruko_ts_recorder.c @@ -1,4 +1,5 @@ #include "maruko_ts_recorder.h" +#include "maruko_video.h" #include "ts_mux.h" #include @@ -8,6 +9,7 @@ int maruko_ts_recorder_write_stream(Star6eTsRecorderState *state, const i6c_venc_strm *stream) { + static int incomplete_warned; uint8_t nal_buf[512 * 1024]; /* matches Star6E adapter — ~50 Mbps IDR */ size_t nal_len = 0; int is_idr = 0; @@ -16,6 +18,15 @@ int maruko_ts_recorder_write_stream(Star6eTsRecorderState *state, if (!state || state->fd < 0 || !stream || !stream->packet) return 0; + if (!maruko_video_stream_packet_info_complete(stream)) { + if (!incomplete_warned) { + incomplete_warned = 1; + fprintf(stderr, + "[maruko_ts] incomplete packetInfo table; " + "dropping whole access unit\n"); + } + return 0; + } for (unsigned int i = 0; i < stream->count; ++i) { const i6c_venc_pack *pack = &stream->packet[i]; @@ -23,12 +34,7 @@ int maruko_ts_recorder_write_stream(Star6eTsRecorderState *state, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; - if (nal_count > info_cap) - nal_count = info_cap; for (unsigned int k = 0; k < nal_count; ++k) { unsigned int off = pack->packetInfo[k].offset; @@ -46,9 +52,9 @@ int maruko_ts_recorder_write_stream(Star6eTsRecorderState *state, if (nal_len + len > sizeof(nal_buf)) { fprintf(stderr, "[maruko_ts] frame too large " - "(%zu + %u > %zu), truncated\n", + "(%zu + %u > %zu), access unit dropped\n", nal_len, len, sizeof(nal_buf)); - break; + return 0; } memcpy(nal_buf + nal_len, pack->data + off, len); @@ -61,9 +67,9 @@ int maruko_ts_recorder_write_stream(Star6eTsRecorderState *state, if (nal_len + len > sizeof(nal_buf)) { fprintf(stderr, "[maruko_ts] frame too large " - "(%zu + %u > %zu), truncated\n", + "(%zu + %u > %zu), access unit dropped\n", nal_len, len, sizeof(nal_buf)); - break; + return 0; } memcpy(nal_buf + nal_len, pack->data + pack->offset, len); diff --git a/src/maruko_video.c b/src/maruko_video.c index e695fe8e..12076d4b 100644 --- a/src/maruko_video.c +++ b/src/maruko_video.c @@ -2,6 +2,7 @@ #include "h26x_util.h" #include "hevc_rtp.h" +#include "timing.h" #include "rtp_packetizer.h" #include "rtp_session.h" @@ -16,6 +17,71 @@ typedef struct { venc_ring_t *ring; } MarukoRtpWriteContext; +int maruko_video_stream_packet_info_complete(const i6c_venc_strm *stream) +{ + unsigned int i; + + if (!stream || stream->count == 0 || !stream->packet) + return 0; + + for (i = 0; i < stream->count; ++i) { + const i6c_venc_pack *pack = &stream->packet[i]; + const unsigned int info_cap = (unsigned int)( + sizeof(pack->packetInfo) / sizeof(pack->packetInfo[0])); + unsigned int k; + + if (!pack->data || pack->packNum > info_cap) + return 0; + if (pack->packNum == 0) { + if (pack->length <= pack->offset) + return 0; + continue; + } + for (k = 0; k < (unsigned int)pack->packNum; ++k) { + MI_U32 offset = pack->packetInfo[k].offset; + MI_U32 length = pack->packetInfo[k].length; + + if (length == 0 || offset >= pack->length || + length > pack->length - offset) + return 0; + } + } + + return 1; +} + +static void maruko_recover_dropped_access_unit(const i6c_venc_strm *stream, + MarukoOutput *output) +{ + uint8_t flags = 0; + + if (!stream || !output) + return; + if (output->svct_active && + stream->h265Info.refType == MARUKO_REFTYPE_ENHANCE_P_NOTFORREF) + flags |= VENC_FRAME_FLAG_ENHANCE; + if (venc_frame_drop_breaks_chain(flags) && output->request_idr && + venc_frame_drop_idr_due(&output->drop_idr_last_us, + wb_monotonic_us()) && + output->request_idr(output->idr_ctx) == 0) + output->drop_idr_last_us = 0; +} + +int maruko_video_reject_incomplete_access_unit(const i6c_venc_strm *stream, + MarukoOutput *output) +{ + if (maruko_video_stream_packet_info_complete(stream)) + return 0; + if (output && !output->trunc_warned) { + output->trunc_warned = 1; + fprintf(stderr, + "WARN: Maruko packetInfo table is incomplete or invalid; " + "dropping whole access unit\n"); + } + maruko_recover_dropped_access_unit(stream, output); + return 1; +} + static int maruko_rtp_write(const uint8_t *header, size_t header_len, const uint8_t *payload1, size_t payload1_len, const uint8_t *payload2, size_t payload2_len, void *opaque) @@ -87,9 +153,6 @@ static size_t maruko_send_frame_hevc(const i6c_venc_strm *stream, for (i = 0; i < stream->count; ++i) { const i6c_venc_pack *pack = &stream->packet[i]; - const unsigned int info_cap = - (unsigned int)(sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count; unsigned int k; @@ -97,8 +160,6 @@ static size_t maruko_send_frame_hevc(const i6c_venc_strm *stream, continue; nal_count = pack->packNum > 0 ? (unsigned int)pack->packNum : 1; - if (pack->packNum > 0 && nal_count > info_cap) - nal_count = info_cap; for (k = 0; k < nal_count; ++k) { const uint8_t *data = NULL; @@ -237,15 +298,9 @@ static size_t maruko_send_frame_compact(const i6c_venc_strm *stream, continue; if (pack->packNum > 0) { - const unsigned int info_cap = - (unsigned int)(sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; unsigned int k; - if (nal_count > info_cap) - nal_count = info_cap; - for (k = 0; k < nal_count; ++k) { MI_U32 length = pack->packetInfo[k].length; MI_U32 offset = pack->packetInfo[k].offset; @@ -297,13 +352,8 @@ static size_t maruko_send_frame_ring(const i6c_venc_strm *stream, for (i = 0; i < stream->count && !is_idr; ++i) { const i6c_venc_pack *pack = &stream->packet[i]; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; unsigned int k; - if (nal_count > info_cap) - nal_count = info_cap; for (k = 0; k < nal_count; ++k) { uint8_t nt = (uint8_t)pack->packetInfo[k] .packType.h265Nalu; @@ -336,8 +386,14 @@ static size_t maruko_send_frame_ring(const i6c_venc_strm *stream, if (venc_frame_ring_begin_write(frame_ring, &meta) != 0) { if (venc_frame_drop_breaks_chain(meta.flags) && - output->request_idr) - output->request_idr(output->idr_ctx); + output->request_idr && + venc_frame_drop_idr_due(&output->drop_idr_last_us, + wb_monotonic_us()) && + output->request_idr(output->idr_ctx) == 0) { + /* Swallowed by the shared 100 ms limiter — roll the + * holdoff back so the next drop retries. */ + output->drop_idr_last_us = 0; + } return 0; } @@ -348,15 +404,9 @@ static size_t maruko_send_frame_ring(const i6c_venc_strm *stream, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; unsigned int k; - if (nal_count > info_cap) - nal_count = info_cap; - for (k = 0; k < nal_count; ++k) { unsigned int length = pack->packetInfo[k].length; unsigned int offset = pack->packetInfo[k].offset; @@ -368,6 +418,8 @@ static size_t maruko_send_frame_ring(const i6c_venc_strm *stream, if (venc_frame_ring_append(frame_ring, pack->data + offset, length) != 0) { venc_frame_ring_abort_write(frame_ring); + maruko_recover_dropped_access_unit(stream, + output); return 0; } total_bytes += length; @@ -381,6 +433,7 @@ static size_t maruko_send_frame_ring(const i6c_venc_strm *stream, if (venc_frame_ring_append(frame_ring, pack->data + pack->offset, length) != 0) { venc_frame_ring_abort_write(frame_ring); + maruko_recover_dropped_access_unit(stream, output); return 0; } total_bytes += length; @@ -399,6 +452,8 @@ size_t maruko_video_send_frame(const i6c_venc_strm *stream, if (!stream || !output || !cfg) return 0; + if (maruko_video_reject_incomplete_access_unit(stream, output)) + return 0; if (output->frame_ring) return maruko_send_frame_ring(stream, output); diff --git a/src/star6e_hevc_rtp.c b/src/star6e_hevc_rtp.c index 3f6452b8..c29ca898 100644 --- a/src/star6e_hevc_rtp.c +++ b/src/star6e_hevc_rtp.c @@ -28,13 +28,9 @@ size_t star6e_hevc_rtp_send_frame(const MI_VENC_Stream_t *stream, for (unsigned int i = 0; i < stream->count; ++i) { const MI_VENC_Pack_t *pack = &stream->packet[i]; - const unsigned int info_cap = (unsigned int)(sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (pack->packNum > 0) ? (unsigned int)pack->packNum : 1; - if (pack->packNum > 0 && nal_count > info_cap) - nal_count = info_cap; if (!pack->data) continue; diff --git a/src/star6e_mi.c b/src/star6e_mi.c index a1d3b535..8c2e6231 100644 --- a/src/star6e_mi.c +++ b/src/star6e_mi.c @@ -302,6 +302,10 @@ static int i6e_venc_load(star6e_venc_impl *venc) int (*)(int, void *), "MI_VENC_SetRefParam"); LOAD_SYM(venc, "libmi_venc.so", fnGetRefParam, int (*)(int, void *), "MI_VENC_GetRefParam"); + LOAD_SYM(venc, "libmi_venc.so", fnSetH265SliceSplit, + int (*)(int, void *), "MI_VENC_SetH265SliceSplit"); + LOAD_SYM(venc, "libmi_venc.so", fnGetH265SliceSplit, + int (*)(int, void *), "MI_VENC_GetH265SliceSplit"); if (!venc->fnCreateChn || !venc->fnDestroyChn || !venc->fnStartRecvPic || !venc->fnStopRecvPic || diff --git a/src/star6e_output.c b/src/star6e_output.c index 6c33ec0f..99756669 100644 --- a/src/star6e_output.c +++ b/src/star6e_output.c @@ -16,6 +16,70 @@ #define STAR6E_RTP_HEADER_SIZE 12 /* STAR6E_REFTYPE_ENHANCE_P_NOTFORREF (=5) is defined in star6e.h. */ +int star6e_output_stream_packet_info_complete( + const MI_VENC_Stream_t *stream) +{ + unsigned int i; + + if (!stream || stream->count == 0 || !stream->packet) + return 0; + for (i = 0; i < stream->count; ++i) { + const MI_VENC_Pack_t *pack = &stream->packet[i]; + const unsigned int info_cap = (unsigned int)( + sizeof(pack->packetInfo) / sizeof(pack->packetInfo[0])); + unsigned int k; + + if (!pack->data || pack->packNum > info_cap) + return 0; + if (pack->packNum == 0) { + if (pack->length <= pack->offset) + return 0; + continue; + } + for (k = 0; k < (unsigned int)pack->packNum; ++k) { + MI_U32 offset = pack->packetInfo[k].offset; + MI_U32 length = pack->packetInfo[k].length; + + if (length == 0 || offset >= pack->length || + length > pack->length - offset) + return 0; + } + } + return 1; +} + +static void star6e_output_recover_dropped_access_unit(Star6eOutput *output, + const MI_VENC_Stream_t *stream) +{ + uint8_t flags = 0; + + if (!output || !stream) + return; + if (output->svct_active && + stream->h265Info.refType == STAR6E_REFTYPE_ENHANCE_P_NOTFORREF) + flags |= VENC_FRAME_FLAG_ENHANCE; + if (venc_frame_drop_breaks_chain(flags) && output->request_idr && + venc_frame_drop_idr_due(&output->drop_idr_last_us, + wb_monotonic_us()) && + output->request_idr(output->idr_ctx) == 0) + output->drop_idr_last_us = 0; +} + +int star6e_output_reject_incomplete_access_unit(Star6eOutput *output, + const MI_VENC_Stream_t *stream) +{ + if (star6e_output_stream_packet_info_complete(stream)) + return 0; + if (output && !output->trunc_warned) { + output->trunc_warned = 1; + fprintf(stderr, + "WARN: Star6E packetInfo table is incomplete or invalid; " + "dropping whole access unit\n"); + } + star6e_output_recover_dropped_access_unit(output, stream); + return 1; +} + static uint16_t star6e_read_be16(const uint8_t *data) { return (uint16_t)((uint16_t)data[0] << 8 | (uint16_t)data[1]); @@ -813,14 +877,9 @@ size_t star6e_output_send_compact_frame(Star6eOutput *output, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)(sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; unsigned int k; - if (nal_count > info_cap) - nal_count = info_cap; - for (k = 0; k < nal_count; ++k) { MI_U32 length = pack->packetInfo[k].length; MI_U32 offset = pack->packetInfo[k].offset; @@ -864,13 +923,8 @@ static size_t star6e_output_send_frame_ring(Star6eOutput *output, for (i = 0; i < stream->count && !is_idr; ++i) { const MI_VENC_Pack_t *pack = &stream->packet[i]; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; unsigned int k; - if (nal_count > info_cap) - nal_count = info_cap; for (k = 0; k < nal_count; ++k) { uint8_t nt = (uint8_t)pack->packetInfo[k] .packType.h265Nalu; @@ -903,8 +957,15 @@ static size_t star6e_output_send_frame_ring(Star6eOutput *output, if (venc_frame_ring_begin_write(output->frame_ring, &meta) != 0) { if (venc_frame_drop_breaks_chain(meta.flags) && - output->request_idr) - output->request_idr(output->idr_ctx); + output->request_idr && + venc_frame_drop_idr_due(&output->drop_idr_last_us, + wb_monotonic_us()) && + output->request_idr(output->idr_ctx) == 0) { + /* Swallowed by the shared 100 ms limiter — roll the + * holdoff back so the next drop retries, instead of + * pacing a request that never happened. */ + output->drop_idr_last_us = 0; + } return 0; } @@ -915,15 +976,9 @@ static size_t star6e_output_send_frame_ring(Star6eOutput *output, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; unsigned int k; - if (nal_count > info_cap) - nal_count = info_cap; - for (k = 0; k < nal_count; ++k) { MI_U32 length = pack->packetInfo[k].length; MI_U32 offset = pack->packetInfo[k].offset; @@ -936,6 +991,8 @@ static size_t star6e_output_send_frame_ring(Star6eOutput *output, pack->data + offset, length) != 0) { venc_frame_ring_abort_write( output->frame_ring); + star6e_output_recover_dropped_access_unit( + output, stream); return 0; } total_bytes += length; @@ -949,6 +1006,8 @@ static size_t star6e_output_send_frame_ring(Star6eOutput *output, if (venc_frame_ring_append(output->frame_ring, pack->data + pack->offset, length) != 0) { venc_frame_ring_abort_write(output->frame_ring); + star6e_output_recover_dropped_access_unit(output, + stream); return 0; } total_bytes += length; @@ -967,6 +1026,8 @@ size_t star6e_output_send_frame(Star6eOutput *output, if (!output || !stream) return 0; + if (star6e_output_reject_incomplete_access_unit(output, stream)) + return 0; if (output->frame_ring) return star6e_output_send_frame_ring(output, stream); diff --git a/src/star6e_pipeline.c b/src/star6e_pipeline.c index 5f9d3bd4..2c794ef6 100644 --- a/src/star6e_pipeline.c +++ b/src/star6e_pipeline.c @@ -1448,6 +1448,78 @@ static int star6e_pipeline_start_venc(uint32_t width, uint32_t height, * StartRecvPic, producing a flat single-layer stream. */ (void)star6e_pipeline_pre_start_apply_ref_pred(*chn, vcfg); + /* H.265 multi-slice split (same pre-Start window as SetRefParam). + * sliceCount is what the operator asks for; the SDK field is 32-px + * rows per slice, but the encoder's CTU is 64 (measured 2026-08-20: + * SPS says 30x17 CTBs at 1080p), so the SDK rounds the request up to + * whole CTU-64 rows. Log the DELIVERED geometry, not the request — + * at 1080p sliceCount 8 quantizes to 6 slices of 3 CTU rows. + * vcfg is optional on this path: star6e_pipeline_start_dual() + * passes NULL for ch1, so guard before reading slice_count. */ + if (vcfg && vcfg->video0.slice_count > 1) { + uint32_t rows = (height + 31) / 32; + uint32_t per = (rows + vcfg->video0.slice_count - 1) / vcfg->video0.slice_count; + uint32_t ctu_rows = (height + 63) / 64; + uint32_t ctu_per; + MI_VENC_ParamH265SliceSplit_t split; + MI_VENC_ParamH265SliceSplit_t rb; + + if (codec != PT_H265) { + fprintf(stderr, "ERROR: sliceCount=%u requires H.265\n", + vcfg->video0.slice_count); + MI_VENC_DestroyChn(*chn); + return -1; + } + + /* Optional export: some libmi_venc.so revisions omit it and the + * macro then returns -1, which reads as a driver rejection and + * sends the operator hunting geometry. Stay fatal -- delivering + * one slice while the API advertises N would lie to the + * receiver's spatial concealment -- but say why. */ + if (!g_mi_venc.fnSetH265SliceSplit || + !g_mi_venc.fnGetH265SliceSplit) { + fprintf(stderr, "ERROR: sliceCount=%u requested but " + "libmi_venc.so does not export " + "MI_VENC_SetH265SliceSplit/GetH265SliceSplit\n", + vcfg->video0.slice_count); + MI_VENC_DestroyChn(*chn); + return -1; + } + + /* B3: the vendor reads all 8 bytes; leaving the pad + * uninitialised puts stack garbage across the ABI. */ + memset(&split, 0, sizeof(split)); + split.bSplitEnable = 1; + split.u32SliceRowCount = per; + ret = MI_VENC_SetH265SliceSplit(*chn, &split); + if (ret != 0) { + fprintf(stderr, + "ERROR: MI_VENC_SetH265SliceSplit(%u rows/slice) " + "failed %d\n", + split.u32SliceRowCount, ret); + MI_VENC_DestroyChn(*chn); + return ret; + } + memset(&rb, 0, sizeof(rb)); + ret = MI_VENC_GetH265SliceSplit(*chn, &rb); + if (ret != 0 || !rb.bSplitEnable || + rb.u32SliceRowCount == 0 || rb.u32SliceRowCount > rows) { + fprintf(stderr, "ERROR: H.265 slice split readback invalid: " + "ret=%d enable=%u rows=%u requested_rows=%u\n", + ret, (unsigned)rb.bSplitEnable, + (unsigned)rb.u32SliceRowCount, + (unsigned)split.u32SliceRowCount); + MI_VENC_DestroyChn(*chn); + return ret != 0 ? ret : -1; + } + ctu_per = (rb.u32SliceRowCount + 1) / 2; + printf("VENC: H.265 slice split ON: requested=%u rows32=%u " + "applied_rows32=%u predicted=%u (readback verified)\n", + vcfg->video0.slice_count, split.u32SliceRowCount, + rb.u32SliceRowCount, + (ctu_rows + ctu_per - 1) / ctu_per); + } + ret = MI_VENC_StartRecvPic(*chn); if (ret != 0) { fprintf(stderr, "ERROR: MI_VENC_StartRecvPic failed %d\n", ret); @@ -2683,17 +2755,19 @@ int star6e_pipeline_start(Star6ePipelineState *state, const VencConfig *vcfg, * star6e_output_init() -> star6e_output_reset(), which memsets the * whole output struct and would otherwise zero these GDR/SVC-T * tagging fields. */ - state->output.gdr_active = - (vcfg->video0.intra_refresh_mode[0] != '\0' && - strcmp(vcfg->video0.intra_refresh_mode, "off") != 0) ? 1 : 0; - state->output.svct_active = vcfg->video0.ref_base > 0 ? 1 : 0; { - IntraRefreshDerived gdr_ir; - (void)star6e_pipeline_intra_refresh_derive( - vcfg, pconf.image_height, venc_fps, pconf.rc_codec, - &gdr_ir); - uint32_t clen = (gdr_ir.total_rows && gdr_ir.lines) - ? (gdr_ir.total_rows + gdr_ir.lines - 1) / gdr_ir.lines + Star6eIntraRefreshStatus ir_status; + Star6eRefPredStatus ref_status; + uint32_t clen; + + star6e_pipeline_intra_refresh_status(&ir_status); + star6e_pipeline_ref_pred_status(&ref_status); + state->output.gdr_active = ir_status.active && ir_status.apply_ok; + state->output.svct_active = ref_status.active && ref_status.apply_ok; + clen = (state->output.gdr_active && ir_status.total_rows && + ir_status.effective_lines_per_p) + ? (ir_status.total_rows + ir_status.effective_lines_per_p - 1) / + ir_status.effective_lines_per_p : 0; state->output.gdr_cycle_len = clen > 255 ? 255 : (uint8_t)clen; state->output.gdr_counter = 0; diff --git a/src/star6e_recorder.c b/src/star6e_recorder.c index 332bdd79..089f3234 100644 --- a/src/star6e_recorder.c +++ b/src/star6e_recorder.c @@ -1,4 +1,7 @@ #include "star6e_recorder.h" +#ifndef PLATFORM_MARUKO +#include "star6e_output.h" +#endif #include #include @@ -56,16 +59,48 @@ static int build_recording_path(char *path, size_t path_size, const char *dir) return 0; } -static ssize_t writev_retry(int fd, const struct iovec *iov, int iov_count) +#ifndef PLATFORM_MARUKO +static ssize_t writev_all(int fd, const struct iovec *iov, int iov_count) { - ssize_t ret; + struct iovec pending[16]; + ssize_t total = 0; + int first = 0; - do { - ret = writev(fd, iov, iov_count); - } while (ret < 0 && errno == EINTR); + if (!iov || iov_count <= 0 || iov_count > 16) { + errno = EINVAL; + return -1; + } + memcpy(pending, iov, (size_t)iov_count * sizeof(pending[0])); + while (first < iov_count) { + ssize_t ret; + ssize_t consumed; + + do { + ret = writev(fd, &pending[first], iov_count - first); + } while (ret < 0 && errno == EINTR); + if (ret < 0) + return -1; + if (ret == 0) { + errno = EIO; + return -1; + } + total += ret; + consumed = ret; + while (first < iov_count && + consumed >= (ssize_t)pending[first].iov_len) { + consumed -= (ssize_t)pending[first].iov_len; + first++; + } + if (first < iov_count && consumed > 0) { + pending[first].iov_base = + (char *)pending[first].iov_base + consumed; + pending[first].iov_len -= (size_t)consumed; + } + } - return ret; + return total; } +#endif static const char *stop_reason_str(Star6eRecorderStopReason reason) { @@ -159,20 +194,32 @@ static int check_disk_space(Star6eRecorderState *state) return 0; } +#ifndef PLATFORM_MARUKO int star6e_recorder_write_frame(Star6eRecorderState *state, const MI_VENC_Stream_t *stream) { + static int incomplete_warned; struct iovec iov[16]; int iov_count = 0; ssize_t written; size_t total = 0; + off_t frame_start; if (!state || state->fd < 0 || !stream || !stream->packet) return 0; + if (!star6e_output_stream_packet_info_complete(stream)) { + if (!incomplete_warned) { + incomplete_warned = 1; + fprintf(stderr, "[recorder] invalid packetInfo; " + "dropping whole access unit\n"); + } + return 0; + } /* Periodic disk space check */ if (check_disk_space(state) != 0) return 0; + frame_start = lseek(state->fd, 0, SEEK_CUR); for (unsigned int i = 0; i < stream->count; ++i) { const MI_VENC_Pack_t *pack = &stream->packet[i]; @@ -181,14 +228,8 @@ int star6e_recorder_write_frame(Star6eRecorderState *state, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; - if (nal_count > info_cap) - nal_count = info_cap; - for (unsigned int k = 0; k < nal_count; ++k) { MI_U32 offset = pack->packetInfo[k].offset; MI_U32 len = pack->packetInfo[k].length; @@ -198,7 +239,7 @@ int star6e_recorder_write_frame(Star6eRecorderState *state, continue; if (iov_count >= 16) { - written = writev_retry(state->fd, + written = writev_all(state->fd, iov, iov_count); if (written < 0) goto write_error; @@ -216,7 +257,7 @@ int star6e_recorder_write_frame(Star6eRecorderState *state, continue; if (iov_count >= 16) { - written = writev_retry(state->fd, iov, iov_count); + written = writev_all(state->fd, iov, iov_count); if (written < 0) goto write_error; total += (size_t)written; @@ -232,7 +273,7 @@ int star6e_recorder_write_frame(Star6eRecorderState *state, } if (iov_count > 0) { - written = writev_retry(state->fd, iov, iov_count); + written = writev_all(state->fd, iov, iov_count); if (written < 0) goto write_error; total += (size_t)written; @@ -254,6 +295,15 @@ int star6e_recorder_write_frame(Star6eRecorderState *state, return (int)total; write_error: + { + int saved_errno = errno; + + /* A failure may follow a short successful write. Roll the regular + * file back to its frame boundary so it never retains half an AU. */ + if (frame_start >= 0) + (void)ftruncate(state->fd, frame_start); + errno = saved_errno; + } if (errno == ENOSPC) { fprintf(stderr, "[recorder] disk full (ENOSPC)\n"); stop_with_reason(state, RECORDER_STOP_DISK_FULL); @@ -264,6 +314,7 @@ int star6e_recorder_write_frame(Star6eRecorderState *state, } return -1; } +#endif void star6e_recorder_stop(Star6eRecorderState *state) { diff --git a/src/star6e_runtime.c b/src/star6e_runtime.c index d5244ebf..814a1ec2 100644 --- a/src/star6e_runtime.c +++ b/src/star6e_runtime.c @@ -378,7 +378,7 @@ static uint8_t star6e_scene_is_idr(const MI_VENC_Stream_t *s) if (!s || !s->packet) return 0; for (i = 0; i < s->count; i++) { const MI_VENC_Pack_t *p = &s->packet[i]; - unsigned int k, n = p->packNum > 8 ? 8 : p->packNum; + unsigned int k, n = p->packNum; if (n > 0) { for (k = 0; k < n; k++) { if (p->packetInfo[k].packType.h265Nalu == 19) @@ -391,11 +391,22 @@ static uint8_t star6e_scene_is_idr(const MI_VENC_Stream_t *s) return 0; } -static void star6e_scene_request_idr(void *ctx) +/* Ring-full recovery form: reports whether the shared 100 ms limiter let + * the IDR through, so the frame-ring holdoff can retry a swallowed request + * on the next drop instead of pacing a no-op (Star6eOutput.request_idr). */ +static int star6e_ring_request_idr(void *ctx) { int venc_chn = *(const int *)ctx; - if (idr_rate_limit_allow(venc_chn)) - MI_VENC_RequestIdr(venc_chn, 1); + if (!idr_rate_limit_allow(venc_chn)) + return 0; + MI_VENC_RequestIdr(venc_chn, 1); + return 1; +} + +/* Scene-detector form (SceneRequestIdrFn is void). */ +static void star6e_scene_request_idr(void *ctx) +{ + (void)star6e_ring_request_idr(ctx); } /* ── Runner context ────────────────────────────────────────────────────── */ @@ -728,6 +739,23 @@ static void *dual_rec_thread_fn(void *arg) usleep(1000); continue; } + if (!star6e_output_stream_packet_info_complete(&stream)) { + static int incomplete_warned; + if (!incomplete_warned) { + incomplete_warned = 1; + fprintf(stderr, "WARN: [dual] invalid packetInfo; " + "dropping whole access unit\n"); + } + if (!(d->output.svct_active && + stream.h265Info.refType == + STAR6E_REFTYPE_ENHANCE_P_NOTFORREF) && + venc_frame_drop_idr_due(&d->output.drop_idr_last_us, + wb_monotonic_us()) && + star6e_ring_request_idr(&d->channel) == 0) + d->output.drop_idr_last_us = 0; + MI_VENC_ReleaseStream(d->channel, &stream); + continue; + } /* Skip slow SD writes during shutdown — keep draining * to prevent VPE backpressure while pipeline tears down. */ @@ -866,7 +894,7 @@ static int star6e_runtime_apply_startup_controls(Star6eRunnerContext *ctx) * both producers of forced IDRs coalesce through one 100 ms window. * Set here rather than in the pipeline because the callback is * runtime-local; safe against pipeline restarts, which re-run this. */ - ps->output.request_idr = star6e_scene_request_idr; + ps->output.request_idr = star6e_ring_request_idr; ps->output.idr_ctx = &ps->venc_channel; star6e_recorder_init(&ps->recorder); @@ -1195,6 +1223,11 @@ static int star6e_runtime_process_stream(Star6eRunnerContext *ctx, fprintf(stderr, "ERROR: MI_VENC_GetStream failed %d\n", ret); return ret; } + if (star6e_output_reject_incomplete_access_unit(&ps->output, + &stream)) { + MI_VENC_ReleaseStream(ps->venc_channel, &stream); + return 0; + } /* refPred error-resilience marking — rewrite TRAIL_R → TRAIL_N for * frames the SDK marked as ENHANCE_P_NOTFORREF. The encoder's own @@ -1202,9 +1235,9 @@ static int star6e_runtime_process_stream(Star6eRunnerContext *ctx, * just propagate that designation into the bitstream so generic * receivers can safely drop those NALs without cascade. * - * Only active when refPred is enabled (ref_base > 0) — otherwise the - * encoder produces a flat single-ref stream and every frame matters. */ - if (vcfg->video0.ref_base > 0 && + * Only active when refPred was successfully applied — otherwise the encoder + * produces a flat single-ref stream and every frame matters. */ + if (ps->output.svct_active && stream.h265Info.refType == STAR6E_REFTYPE_ENHANCE_P_NOTFORREF) { star6e_patch_stream_to_trail_n(&stream); } diff --git a/src/star6e_ts_recorder.c b/src/star6e_ts_recorder.c index 530a8fe9..309e8eed 100644 --- a/src/star6e_ts_recorder.c +++ b/src/star6e_ts_recorder.c @@ -1,4 +1,7 @@ #include "star6e_ts_recorder.h" +#ifndef PLATFORM_MARUKO +#include "star6e_output.h" +#endif #include #include @@ -334,9 +337,11 @@ int star6e_ts_recorder_is_active(const Star6eTsRecorderState *state) return state && state->fd >= 0; } +#ifndef PLATFORM_MARUKO int star6e_ts_recorder_write_stream(Star6eTsRecorderState *state, const MI_VENC_Stream_t *stream) { + static int incomplete_warned; uint8_t nal_buf[512 * 1024]; /* 512KB — supports up to ~50 Mbps IDR frames */ size_t nal_len = 0; int is_idr = 0; @@ -345,6 +350,14 @@ int star6e_ts_recorder_write_stream(Star6eTsRecorderState *state, if (!state || state->fd < 0 || !stream || !stream->packet) return 0; + if (!star6e_output_stream_packet_info_complete(stream)) { + if (!incomplete_warned) { + incomplete_warned = 1; + fprintf(stderr, "[ts_recorder] invalid packetInfo; " + "dropping whole access unit\n"); + } + return 0; + } /* Extract all NAL data from stream packs */ for (unsigned int i = 0; i < stream->count; ++i) { @@ -353,12 +366,7 @@ int star6e_ts_recorder_write_stream(Star6eTsRecorderState *state, continue; if (pack->packNum > 0) { - const unsigned int info_cap = (unsigned int)( - sizeof(pack->packetInfo) / - sizeof(pack->packetInfo[0])); unsigned int nal_count = (unsigned int)pack->packNum; - if (nal_count > info_cap) - nal_count = info_cap; for (unsigned int k = 0; k < nal_count; ++k) { MI_U32 off = pack->packetInfo[k].offset; @@ -377,9 +385,9 @@ int star6e_ts_recorder_write_stream(Star6eTsRecorderState *state, if (nal_len + len > sizeof(nal_buf)) { fprintf(stderr, "[ts_recorder] frame too large " - "(%zu + %u > %zu), truncated\n", + "(%zu + %u > %zu), access unit dropped\n", nal_len, len, sizeof(nal_buf)); - break; + return 0; } memcpy(nal_buf + nal_len, pack->data + off, len); @@ -392,9 +400,9 @@ int star6e_ts_recorder_write_stream(Star6eTsRecorderState *state, if (nal_len + len > sizeof(nal_buf)) { fprintf(stderr, "[ts_recorder] frame too large " - "(%zu + %u > %zu), truncated\n", + "(%zu + %u > %zu), access unit dropped\n", nal_len, len, sizeof(nal_buf)); - break; + return 0; } memcpy(nal_buf + nal_len, pack->data + pack->offset, len); @@ -412,6 +420,7 @@ int star6e_ts_recorder_write_stream(Star6eTsRecorderState *state, return star6e_ts_recorder_write_video(state, nal_buf, nal_len, pts, is_idr); } +#endif void star6e_ts_recorder_status(const Star6eTsRecorderState *state, uint64_t *bytes_written, uint32_t *frames_written, diff --git a/src/venc_api.c b/src/venc_api.c index f1bd0172..cf4d8d39 100644 --- a/src/venc_api.c +++ b/src/venc_api.c @@ -6,6 +6,7 @@ #include "intra_refresh.h" #include "pipeline_common.h" #if HAVE_BACKEND_CV610 +#include "cv610_runtime.h" #include "cv610_modes.h" #include "cv610_validation.h" #endif @@ -472,6 +473,15 @@ static const FieldUi ui_max_qp = { "Video", "Max QP", "number", 0, 51, 1, NULL, "RC QP ceiling. 0 = leave the SDK default. Raising the ceiling lets the encoder compress a scene change hard enough to stay inside the frame budget instead of emitting a burst frame. Applied live." }; +static const FieldUi ui_slice_count = { + "Video", "Slices per frame", "number", 1, VENC_SLICE_COUNT_MAX, 1, NULL, + "Independent H.265 slices per picture. 1 = off. Multi-slice " + "output lets the waybeam-link receiver conceal RF loss spatially " + "instead of dropping the whole frame, and the concealed area shrinks " + "as 1/N. The request is quantized to encoder row geometry; startup logs " + "the requested/applied mapping and validation tools report the VCL census. On Star6E, " + "1080p delivers only 1,2,3,4,5,6,9,17 and saturates at 17. Restart-only." +}; static const FieldUi ui_max_i_bytes = { "Video", "Max I-frame bytes", "number", 0, 2000000, 500, NULL, "Hard per-frame cap on the encoded I-frame size in bytes. 0 = unlimited. " @@ -630,6 +640,7 @@ static const FieldDesc g_fields[] = { FIELD_UI(snapshot, height, FT_UINT, MUT_RESTART, &ui_snapshot_height), FIELD(video0, scene_threshold, FT_UINT16, MUT_RESTART), FIELD(video0, scene_holdoff, FT_UINT8, MUT_RESTART), + FIELD_UI(video0, slice_count, FT_UINT, MUT_RESTART, &ui_slice_count), FIELD(video0, resilience, FT_STRING, MUT_RESTART), /* zoom_x/y stay live for smooth panning via MI_VPE_SetPortCrop; the zoom * magnitude is part of the framing preset (derived zoom_pct), not a @@ -758,6 +769,7 @@ static const FieldAlias g_field_aliases[] = { { "record.gopSize", "record.gop_size" }, { "video0.sceneThreshold", "video0.scene_threshold" }, { "video0.sceneHoldoff", "video0.scene_holdoff" }, + { "video0.sliceCount", "video0.slice_count" }, { "video0.zoomX", "video0.zoom_x" }, { "video0.zoomY", "video0.zoom_y" }, { "video0.stabCropPct", "video0.stab_crop_pct" }, @@ -869,8 +881,15 @@ int venc_api_field_supported_for_backend(const char *backend_name, if (backend_name && strcmp(backend_name, "cv610") == 0) { static const char *const supported[] = { "system.web_port", "system.verbose", + "sensor.index", "sensor.mode", + "isp.keep_aspect", "video0.fps", "video0.size", "video0.bitrate", "video0.gop_size", "video0.qp_delta", + "video0.slice_count", "video0.resilience", + /* Read by cv610_apply_qp_bounds(), live and at startup. + * CBR cannot hold its target in a noise-dominated scene + * without room to raise QP. */ + "video0.min_qp", "video0.max_qp", "outgoing.enabled", "outgoing.server", "outgoing.max_payload_size", "outgoing.audio_port", "outgoing.connected_udp", @@ -1236,6 +1255,14 @@ static const char *validate_field_cfg(const VencConfig *cfg, const char *key) cfg->video0.scene_holdoff == 0 && cfg->video0.scene_threshold > 0) return "video0.scene_holdoff must be >= 1 when scene_threshold > 0"; + if (strcmp(key, "video0.slice_count") == 0) { + /* 1 = split off. The ceiling is a cross-backend sanity bound, + * not necessarily the delivered count: row-based vendor APIs + * quantize or saturate requests to the picture geometry. */ + if (cfg->video0.slice_count < 1 || + cfg->video0.slice_count > VENC_SLICE_COUNT_MAX) + return "video0.slice_count must be 1..32"; + } if (strcmp(key, "video0.min_qp") == 0 || strcmp(key, "video0.max_qp") == 0) { /* H.264/H.265 QP range; the SDK accepts min > max without * complaint and then behaves erratically (device-observed), @@ -1298,9 +1325,6 @@ static const char *validate_field_cfg(const VencConfig *cfg, const char *key) const char *venc_api_validate_loaded_config(const VencConfig *cfg) { -#if HAVE_BACKEND_CV610 - return cv610_validate_config(cfg); -#else /* Keys with rules in validate_field_cfg(). Backend-coupled checks * (validate_backend_config) intentionally excluded — g_backend is * registered after config load, so they cannot run here. */ @@ -1312,6 +1336,7 @@ const char *venc_api_validate_loaded_config(const VencConfig *cfg) "video0.max_qp", "video0.size", "video0.scene_holdoff", + "video0.slice_count", "video0.zoom_x", "video0.zoom_y", "video0.framing", @@ -1332,6 +1357,20 @@ const char *venc_api_validate_loaded_config(const VencConfig *cfg) if (err) return err; } +#if HAVE_BACKEND_CV610 + /* CV610's rules run AFTER the shared sweep, not instead of it. This + * branch used to return cv610_validate_config() directly, so CV610 was + * the one backend that never ran validate_field_cfg() at all — it + * re-implemented video0.size's >=128 and multiple-of-8 gates inside + * cv610_mode_check_output() and silently skipped every other shared + * rule. Two copies of one HEVC constraint is a drift risk; missing the + * rest is a parity hole, and it also meant the same bad value produced + * different error text on CV610 than on Star6E. CV610 keeps its own + * copy of the size gates as a pipeline-boundary guard, because + * cv610_prepare() calls cv610_mode_check_output() directly against a + * config file edited behind the daemon's back. */ + return cv610_validate_config(cfg); +#else return NULL; #endif } @@ -1407,18 +1446,32 @@ static int parse_first_query_param(const char *query, char *key, size_t key_sz, const char *amp = strchr(query, '&'); if (eq) { size_t klen = (size_t)(eq - query); - if (klen >= key_sz) klen = key_sz - 1; + if (klen >= key_sz) { + if (error_message) *error_message = "parameter name too long"; + return -1; + } memcpy(key, query, klen); key[klen] = '\0'; const char *vstart = eq + 1; size_t vlen = amp ? (size_t)(amp - vstart) : strlen(vstart); - if (vlen >= val_sz) vlen = val_sz - 1; + /* Reject rather than truncate. A silently shortened value can still + * satisfy a caller's own validation -- an array setter counting + * comma-separated elements sees the right count with its last element + * cut mid-token -- and then writes something the operator never asked + * for. No legitimate request approaches this length. */ + if (vlen >= val_sz) { + if (error_message) *error_message = "parameter value too long"; + return -1; + } memcpy(val, vstart, vlen); val[vlen] = '\0'; } else { /* key only, no value (used by GET) */ size_t klen = amp ? (size_t)(amp - query) : strlen(query); - if (klen >= key_sz) klen = key_sz - 1; + if (klen >= key_sz) { + if (error_message) *error_message = "parameter name too long"; + return -1; + } memcpy(key, query, klen); key[klen] = '\0'; val[0] = '\0'; @@ -2878,7 +2931,7 @@ static int handle_version(int fd, const HttpRequest *req, void *ctx) snprintf(buf, sizeof(buf), "{\"ok\":true,\"data\":{" "\"app_version\":\"%s\"," - "\"contract_version\":\"0.18.2\"," + "\"contract_version\":\"0.18.6\"," "\"config_schema_version\":\"1.0.0\"," "\"backend\":\"%s\"" "}}", VENC_VERSION, g_backend); @@ -2950,6 +3003,20 @@ static int handle_capabilities(int fd, const HttpRequest *req, void *ctx) cJSON *root = cJSON_CreateObject(); cJSON_AddBoolToObject(root, "ok", 1); cJSON *data = cJSON_AddObjectToObject(root, "data"); + + /* Which optional routes this backend actually services. The dashboard + * already fetches this at init, so it can decide whether to show the IQ + * tab from a pointer test here instead of firing a full ISP sweep at + * /api/v1/iq on every page load just to find out. */ + cJSON *routes = cJSON_AddObjectToObject(data, "routes"); + cJSON_AddBoolToObject(routes, "iq", + (g_cb && g_cb->query_iq_info && g_cb->apply_iq_param) ? 1 : 0); +#if HAVE_BACKEND_STAR6E || HAVE_BACKEND_MARUKO + cJSON_AddBoolToObject(routes, "iq_import", 1); +#else + cJSON_AddBoolToObject(routes, "iq_import", 0); +#endif + cJSON *fields = cJSON_AddObjectToObject(data, "fields"); for (size_t i = 0; i < FIELD_COUNT; i++) { cJSON *entry = cJSON_AddObjectToObject(fields, g_fields[i].key); @@ -3760,7 +3827,7 @@ static int handle_idr_stats(int fd, const HttpRequest *req, void *ctx) return httpd_send_json(fd, 200, buf); } -#if HAVE_BACKEND_STAR6E || HAVE_BACKEND_MARUKO +#if HAVE_BACKEND_STAR6E || HAVE_BACKEND_MARUKO || HAVE_BACKEND_CV610 static int handle_intra_status(int fd, const HttpRequest *req, void *ctx) { struct { @@ -3815,6 +3882,25 @@ static int handle_intra_status(int fd, const HttpRequest *req, void *ctx) s.effective_gop_sec = st.effective_gop_sec; s.gop_auto = st.gop_auto; } +#elif HAVE_BACKEND_CV610 + { + Cv610IntraRefreshStatus st; + cv610_runtime_intra_refresh_status(&st); + snprintf(s.mode_name, sizeof(s.mode_name), "%s", st.mode_name); + s.active = st.active; + s.mi_supported = st.mi_supported; + s.apply_ok = st.apply_ok; + s.target_ms = st.target_ms; + s.total_rows = st.total_rows; + s.requested_lines = st.requested_lines; + s.effective_lines_per_p = st.effective_lines_per_p; + s.lines_clamped = st.lines_clamped; + s.requested_qp = st.requested_qp; + s.effective_qp = st.effective_qp; + s.explicit_gop_sec = st.explicit_gop_sec; + s.effective_gop_sec = st.effective_gop_sec; + s.gop_auto = st.gop_auto; + } #endif if (s.mode_name[0] == '\0') snprintf(s.mode_name, sizeof(s.mode_name), "off"); @@ -3913,6 +3999,27 @@ static int handle_resilience_status(int fd, const HttpRequest *req, void *ctx) rp_enhance = rp.enhance; rp_pred = rp.pred; } +#elif HAVE_BACKEND_CV610 + { + Cv610IntraRefreshStatus st; + Cv610RefPredStatus rp; + cv610_runtime_intra_refresh_status(&st); + cv610_runtime_ref_pred_status(&rp); + snprintf(intra_mode, sizeof(intra_mode), "%s", + st.mode_name[0] ? st.mode_name : "off"); + intra_active = st.active; + intra_supported = st.mi_supported; + intra_apply_ok = st.apply_ok; + intra_lines = st.effective_lines_per_p; + intra_qp = st.effective_qp; + gop_auto = st.gop_auto; + rp_active = rp.active; + rp_supported = rp.mi_supported; + rp_apply_ok = rp.apply_ok; + rp_base = rp.base; + rp_enhance = rp.enhance; + rp_pred = rp.pred; + } #endif snprintf(buf, sizeof(buf), @@ -3988,28 +4095,28 @@ static int handle_modes(int fd, const HttpRequest *req, void *ctx) size_t count = 0; size_t i; const Cv610SensorMode *modes = cv610_mode_table(&count); - const Cv610SensorMode *selected; - uint32_t fps = 0; + int selected, selected_pad; cJSON *root, *data, *pads, *pad, *arr; char *str; int rc; + /* What the backend actually brought up, published by cv610_prepare() + * through the same venc_api_set_sensor_info() star6e_pipeline.c uses. + * Recomputing it from video0.fps here would report the CONFIGURED mode + * even when a forced sensor.mode, a substituted rate, or a failed + * bring-up means something else is running. -1 until bring-up runs. */ pthread_mutex_lock(&g_cfg_mutex); - if (g_cfg) - fps = g_cfg->video0.fps; + selected = g_sensor_mode; + selected_pad = g_sensor_pad; pthread_mutex_unlock(&g_cfg_mutex); - /* The listed geometry is what the sensor captures. video0.size is the - * encoded size VPSS scales that to, so the frame rate alone selects. */ - selected = cv610_mode_for_fps(fps); root = cJSON_CreateObject(); if (!root) return httpd_send_error(fd, 500, "internal_error", "out of memory"); cJSON_AddBoolToObject(root, "ok", 1); data = cJSON_AddObjectToObject(root, "data"); - cJSON_AddNumberToObject(data, "selected_pad", 0); - cJSON_AddNumberToObject(data, "selected_mode", - selected ? (double)(selected - modes) : -1); + cJSON_AddNumberToObject(data, "selected_pad", selected_pad); + cJSON_AddNumberToObject(data, "selected_mode", selected); pads = cJSON_AddArrayToObject(data, "pads"); pad = cJSON_CreateObject(); cJSON_AddItemToArray(pads, pad); @@ -4025,7 +4132,7 @@ static int handle_modes(int fd, const HttpRequest *req, void *ctx) cJSON_AddNumberToObject(m, "min_fps", modes[i].fps); cJSON_AddNumberToObject(m, "max_fps", modes[i].fps); cJSON_AddStringToObject(m, "desc", modes[i].desc); - cJSON_AddBoolToObject(m, "selected", &modes[i] == selected); + cJSON_AddBoolToObject(m, "selected", (int)i == selected); } str = cJSON_PrintUnformatted(root); cJSON_Delete(root); @@ -4113,7 +4220,7 @@ int venc_api_register(VencConfig *cfg, const char *backend_name, r |= venc_httpd_route("GET", "/api/v1/dual/set", handle_dual_set, NULL); r |= venc_httpd_route("GET", "/api/v1/dual/idr", handle_dual_idr, NULL); r |= venc_httpd_route("GET", "/api/v1/idr/stats", handle_idr_stats, NULL); -#if HAVE_BACKEND_STAR6E || HAVE_BACKEND_MARUKO +#if HAVE_BACKEND_STAR6E || HAVE_BACKEND_MARUKO || HAVE_BACKEND_CV610 r |= venc_httpd_route("GET", "/api/v1/intra/status", handle_intra_status, NULL); r |= venc_httpd_route("GET", "/api/v1/resilience/status", handle_resilience_status, NULL); diff --git a/src/venc_config.c b/src/venc_config.c index 9b9ce007..02718a1b 100644 --- a/src/venc_config.c +++ b/src/venc_config.c @@ -165,6 +165,9 @@ void venc_config_defaults(VencConfig *cfg) cfg->video0.scene_threshold = 0; /* 0 = off */ cfg->video0.scene_holdoff = 2; + /* H.265 multi-slice split (video0, all encoder backends) — 1 = off */ + cfg->video0.slice_count = 1; + /* intra refresh (video0) — disabled by default; mode-driven */ safe_strcpy(cfg->video0.intra_refresh_mode, sizeof(cfg->video0.intra_refresh_mode), "off"); @@ -634,6 +637,14 @@ static void load_video0(const cJSON *root, VencConfigVideo *v) v->scene_holdoff = (uint8_t)json_get_int(obj, "sceneHoldoff", (int)v->scene_holdoff); if (v->scene_holdoff < 1 && v->scene_threshold > 0) v->scene_holdoff = 1; + { + /* Clamp in signed space: a negative value must floor to 1 + * (single slice), not wrap through uint32 to the maximum. */ + int sc = json_get_int(obj, "sliceCount", (int)v->slice_count); + if (sc < 1) sc = 1; + if (sc > VENC_SLICE_COUNT_MAX) sc = VENC_SLICE_COUNT_MAX; + v->slice_count = (uint32_t)sc; + } /* Resilience preset is the sole driver of intra-refresh + SVC-T * (refPred). For named presets it also overrides gop_size; only @@ -1379,6 +1390,7 @@ static void render_video0(PrettyBuf *p, const VencConfig *cfg, int is_last) pp_field_uint(p, 2, "maxQp", cfg->video0.max_qp, 0); pp_field_uint(p, 2, "sceneThreshold", cfg->video0.scene_threshold, 0); pp_field_uint(p, 2, "sceneHoldoff", cfg->video0.scene_holdoff, 0); + pp_field_uint(p, 2, "sliceCount", cfg->video0.slice_count, 0); pp_field_string(p, 2, "resilience", cfg->video0.resilience, 0); pp_field_double(p, 2, "zoomX", cfg->video0.zoom_x, 0); pp_field_double(p, 2, "zoomY", cfg->video0.zoom_y, 0); @@ -1636,6 +1648,7 @@ static cJSON *config_to_cjson(const VencConfig *cfg) cJSON_AddNumberToObject(vid, "maxQp", cfg->video0.max_qp); cJSON_AddNumberToObject(vid, "sceneThreshold", cfg->video0.scene_threshold); cJSON_AddNumberToObject(vid, "sceneHoldoff", cfg->video0.scene_holdoff); + cJSON_AddNumberToObject(vid, "sliceCount", cfg->video0.slice_count); cJSON_AddStringToObject(vid, "resilience", cfg->video0.resilience); cJSON_AddNumberToObject(vid, "zoomX", cfg->video0.zoom_x); cJSON_AddNumberToObject(vid, "zoomY", cfg->video0.zoom_y); diff --git a/src/venc_webui.c b/src/venc_webui.c index 97678f2e..6b518c1f 100644 --- a/src/venc_webui.c +++ b/src/venc_webui.c @@ -6,1422 +6,1514 @@ #include static const unsigned char dashboard_gz[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xed, 0xbd, 0xdb, 0x76, 0xe3, 0x46, - 0x96, 0x28, 0xf8, 0xae, 0xaf, 0x08, 0xd3, 0x55, 0x05, 0xb2, 0x04, 0x82, 0xa4, 0x6e, 0x99, 0x49, - 0x26, 0x95, 0x9d, 0x17, 0xd9, 0x56, 0x77, 0xde, 0x2c, 0x29, 0x5d, 0xd5, 0x2b, 0x9d, 0x4b, 0x06, - 0x09, 0x50, 0x84, 0x05, 0x02, 0x30, 0x00, 0xea, 0x62, 0x59, 0x67, 0xf5, 0xd3, 0x7c, 0xc0, 0xac, - 0xb3, 0x66, 0xfe, 0x60, 0x9e, 0xcf, 0xcb, 0x79, 0x3b, 0x4f, 0x3d, 0x7f, 0xd2, 0x5f, 0x32, 0xfb, - 0x12, 0x01, 0x44, 0x80, 0xe0, 0x45, 0xe9, 0x74, 0x9f, 0x9e, 0x5e, 0x5d, 0xdd, 0x4e, 0x11, 0x40, - 0xc4, 0x8e, 0x88, 0x1d, 0x3b, 0x76, 0xec, 0x5b, 0xec, 0x78, 0xfa, 0xd5, 0xab, 0x77, 0x2f, 0xcf, - 0xfe, 0xf9, 0xfd, 0x91, 0x98, 0xe6, 0xb3, 0xf0, 0x70, 0x6b, 0xeb, 0x29, 0xfe, 0x15, 0xa1, 0x1b, - 0x5d, 0x0c, 0x1b, 0x7e, 0xd4, 0xa0, 0x37, 0xbe, 0xeb, 0xe1, 0xdf, 0x99, 0x9f, 0xbb, 0x62, 0x3c, - 0x75, 0xd3, 0xcc, 0xcf, 0x87, 0x8d, 0x0f, 0x67, 0xdf, 0xb4, 0x1f, 0x37, 0x8a, 0xf7, 0x91, 0x3b, - 0xf3, 0x87, 0x8d, 0xab, 0xc0, 0xbf, 0x4e, 0xe2, 0x34, 0x6f, 0x88, 0x71, 0x1c, 0xe5, 0x7e, 0x04, - 0xe5, 0xae, 0x03, 0x2f, 0x9f, 0x0e, 0x3d, 0xff, 0x2a, 0x18, 0xfb, 0x6d, 0x7a, 0xb0, 0x45, 0x10, - 0x05, 0x79, 0xe0, 0x86, 0xed, 0x6c, 0xec, 0x86, 0xfe, 0xb0, 0xe7, 0x74, 0x09, 0x4e, 0x1e, 0xe4, - 0xa1, 0x7f, 0x78, 0xed, 0xde, 0x8e, 0x7c, 0x77, 0x76, 0x7e, 0xe5, 0x47, 0xe3, 0xa7, 0x1d, 0x7e, - 0x07, 0x1f, 0xb3, 0xfc, 0x96, 0x7e, 0xfc, 0x43, 0x30, 0xc3, 0x06, 0xc4, 0x3c, 0x0d, 0x9b, 0xd6, - 0x34, 0xcf, 0x93, 0xac, 0xdf, 0xe9, 0x4c, 0xa0, 0xb1, 0xcc, 0xb9, 0x88, 0xe3, 0x8b, 0xd0, 0x77, - 0x93, 0x20, 0x73, 0xc6, 0xf1, 0xac, 0x33, 0xce, 0xb2, 0x9d, 0x67, 0x13, 0x77, 0x16, 0x84, 0xb7, - 0xc3, 0x7f, 0xf4, 0xf3, 0x17, 0xa9, 0x1b, 0x44, 0xd9, 0xf6, 0x9b, 0x38, 0x8a, 0xfb, 0xd7, 0x17, - 0xd3, 0xfc, 0x1f, 0xf6, 0xba, 0xdd, 0xc1, 0x3e, 0xfc, 0x77, 0x00, 0xff, 0x3d, 0xea, 0x76, 0xff, - 0x22, 0x8b, 0xbe, 0x7a, 0xb3, 0x7d, 0xea, 0x46, 0x59, 0x7d, 0x19, 0x2f, 0xc8, 0x92, 0xd0, 0xbd, - 0x1d, 0x66, 0xd7, 0x6e, 0x62, 0xb5, 0x06, 0x5b, 0x5b, 0x7f, 0xbd, 0x9b, 0xb9, 0xe9, 0x45, 0x10, - 0xf5, 0xbb, 0x83, 0xc4, 0xf5, 0xbc, 0x20, 0xba, 0x80, 0x5f, 0xa3, 0xf8, 0xa6, 0x9d, 0x05, 0xbf, - 0xe2, 0xc3, 0x28, 0x4e, 0x3d, 0x3f, 0x6d, 0xc3, 0x9b, 0xfb, 0xad, 0xad, 0x7e, 0x1a, 0xc7, 0xf9, - 0xdd, 0xd6, 0x56, 0xbb, 0x3d, 0xba, 0xe8, 0x7f, 0xdd, 0x75, 0xbb, 0x6e, 0x6f, 0x67, 0x80, 0x0f, - 0x3b, 0xf0, 0x34, 0xe9, 0x75, 0x7b, 0x4f, 0xe0, 0x69, 0xec, 0xa6, 0x5e, 0xff, 0xeb, 0xde, 0x5e, - 0x6f, 0x7f, 0xa7, 0x2b, 0x1f, 0xdb, 0xd3, 0xf8, 0xca, 0x4f, 0xe1, 0xe5, 0x93, 0x9e, 0xbb, 0xe3, - 0x0e, 0x08, 0x00, 0xc1, 0x85, 0x57, 0xfe, 0x4e, 0x77, 0x77, 0x7f, 0xa0, 0x5e, 0xb4, 0xa7, 0x41, - 0xff, 0xeb, 0x1d, 0x77, 0xc7, 0xdb, 0xe3, 0x62, 0xb9, 0x7f, 0x93, 0xf7, 0xbf, 0x1e, 0x3f, 0x1e, - 0xbb, 0x1e, 0x02, 0xc3, 0xc7, 0xb6, 0x17, 0xcc, 0xfa, 0x5f, 0x1f, 0x8c, 0x0e, 0xfc, 0x47, 0xae, - 0x7a, 0x35, 0x4a, 0x03, 0x18, 0x6d, 0xff, 0x6b, 0xdf, 0x9f, 0x74, 0x27, 0x7b, 0x54, 0xd3, 0x1d, - 0x8f, 0x61, 0xfa, 0xe0, 0xd5, 0x93, 0xbd, 0xfd, 0x03, 0xac, 0xcb, 0x2f, 0xda, 0x17, 0x61, 0x7c, - 0xdd, 0x4f, 0x2f, 0x46, 0x6e, 0x73, 0x67, 0x77, 0xd7, 0x3e, 0x78, 0x62, 0x3f, 0x39, 0xb0, 0x9d, - 0xde, 0x7e, 0x8b, 0x2a, 0x85, 0xc1, 0x95, 0x0f, 0xed, 0xef, 0x8c, 0xf7, 0xf7, 0xfd, 0x01, 0x3f, - 0xe2, 0x50, 0xa9, 0xf8, 0xee, 0x9e, 0xdd, 0x7b, 0xf2, 0xc8, 0x7e, 0xb2, 0x07, 0xc5, 0xb9, 0x74, - 0xea, 0x67, 0xb9, 0x9b, 0x42, 0x1b, 0x93, 0xfd, 0x27, 0x7e, 0x77, 0x34, 0x28, 0xde, 0x14, 0x75, - 0x76, 0xf6, 0xf6, 0xed, 0xde, 0xfe, 0x63, 0xbb, 0xd7, 0x2b, 0x2a, 0x8d, 0xc2, 0x39, 0x34, 0xb1, - 0x3b, 0x7a, 0xbc, 0x33, 0x39, 0x18, 0xf0, 0x63, 0x51, 0x7c, 0xff, 0x89, 0xdd, 0xdb, 0xed, 0xda, - 0x3b, 0x7b, 0x07, 0xb2, 0x38, 0xe0, 0x1c, 0xc9, 0xf9, 0x0e, 0xe9, 0x03, 0x67, 0xc4, 0xef, 0xf7, - 0x76, 0x13, 0x9c, 0x89, 0x51, 0xec, 0xdd, 0xde, 0x8d, 0xdc, 0xf1, 0xe5, 0x45, 0x1a, 0xcf, 0x23, - 0xaf, 0x7f, 0xe5, 0xa6, 0x4d, 0x9c, 0x88, 0xd6, 0x60, 0x1c, 0x87, 0x71, 0x2a, 0x9f, 0x11, 0x37, - 0xad, 0x01, 0x55, 0x66, 0xe2, 0xe8, 0x5b, 0xaf, 0xde, 0x08, 0xa4, 0x0e, 0xcb, 0xce, 0x6e, 0xb3, - 0xdc, 0x9f, 0xb5, 0xe7, 0x81, 0x9d, 0xc1, 0x73, 0x3b, 0xf3, 0xd3, 0x60, 0x32, 0x98, 0x05, 0x51, - 0x7b, 0xea, 0x13, 0x2e, 0x7b, 0xdd, 0xee, 0xd5, 0x74, 0x80, 0xf3, 0x36, 0x01, 0x8c, 0xb5, 0x6f, - 0xfa, 0xd3, 0xc0, 0xf3, 0xfc, 0x08, 0xda, 0x1e, 0xc7, 0x9e, 0x6f, 0x27, 0xa9, 0x6f, 0x3b, 0x33, - 0xa0, 0xc5, 0x3b, 0x03, 0x7c, 0x41, 0xa7, 0x02, 0xe9, 0xd4, 0xb2, 0xb1, 0x44, 0x96, 0xb8, 0x63, - 0x7f, 0x50, 0x0e, 0xc1, 0x79, 0xbc, 0xef, 0xcf, 0x00, 0x4e, 0xe7, 0xaf, 0xe2, 0xdf, 0xfe, 0xfb, - 0xbf, 0xc0, 0xff, 0x8b, 0x33, 0x3f, 0xf4, 0x61, 0x11, 0xa6, 0xb7, 0xe2, 0x85, 0x9b, 0xaa, 0x97, - 0x7f, 0xed, 0x6c, 0x6d, 0x39, 0xf9, 0xc8, 0x4d, 0xef, 0x92, 0x38, 0x83, 0xe5, 0x16, 0x47, 0xfd, - 0x2c, 0x0f, 0xc6, 0x97, 0xb7, 0x83, 0x3c, 0x4e, 0x80, 0x48, 0x7f, 0x6d, 0x07, 0x91, 0xe7, 0xdf, - 0x60, 0x47, 0x07, 0x35, 0x98, 0xd8, 0x69, 0x0d, 0x0a, 0xda, 0xcd, 0xf3, 0x78, 0xd6, 0xef, 0x25, - 0x37, 0x22, 0x8b, 0xc3, 0xc0, 0x13, 0xb2, 0x08, 0x7d, 0x6d, 0x95, 0x64, 0x2f, 0x7a, 0xce, 0x4e, - 0xea, 0xcf, 0x06, 0x12, 0x01, 0x7b, 0x7b, 0xc9, 0xcd, 0x40, 0xae, 0x97, 0xfe, 0x24, 0xf4, 0x6f, - 0x06, 0x6e, 0x18, 0x5c, 0x44, 0xed, 0x00, 0xd0, 0x96, 0xf5, 0x91, 0x96, 0xfc, 0x74, 0x70, 0xe1, - 0x26, 0xfd, 0x1e, 0x56, 0xc2, 0x1e, 0x78, 0x69, 0x9c, 0xb4, 0x27, 0x41, 0x08, 0x1f, 0xfa, 0x30, - 0xaf, 0x69, 0xb3, 0xb7, 0x93, 0xdc, 0xb4, 0xee, 0xe5, 0x30, 0xda, 0xc4, 0x0a, 0x1e, 0x84, 0xae, - 0x6b, 0xee, 0x09, 0x2c, 0x5c, 0x0d, 0x7d, 0xd4, 0x5c, 0x75, 0x96, 0xe5, 0x0a, 0x68, 0x0d, 0x42, - 0x3f, 0x87, 0xe6, 0xdb, 0x08, 0x04, 0x07, 0xd5, 0x76, 0xba, 0x3b, 0x50, 0xfc, 0x7a, 0x0a, 0xbd, - 0xa6, 0x97, 0x7e, 0x3f, 0x8a, 0xaf, 0x53, 0x37, 0x31, 0x7b, 0x25, 0xe0, 0x53, 0x74, 0xa7, 0x03, - 0xe5, 0xd5, 0xd2, 0x32, 0xfa, 0x01, 0xcc, 0xa4, 0xa8, 0x96, 0xf9, 0xc9, 0x1d, 0x31, 0x43, 0xc4, - 0xab, 0x42, 0xd9, 0x4e, 0x17, 0x7e, 0x2f, 0xce, 0x05, 0x23, 0xba, 0xa8, 0x8a, 0x08, 0xbc, 0xdb, - 0x04, 0xb1, 0xce, 0x1e, 0x0e, 0x55, 0x27, 0x9c, 0xda, 0xa1, 0x03, 0x3f, 0x68, 0xad, 0x1a, 0x21, - 0xc2, 0x15, 0xa3, 0xbb, 0x25, 0x0b, 0x43, 0x8e, 0xed, 0x40, 0x1b, 0x9b, 0x07, 0x4c, 0x8e, 0xc7, - 0xf6, 0xa8, 0x1c, 0x1b, 0xfe, 0x94, 0x04, 0x95, 0xba, 0x5e, 0x30, 0xcf, 0xfa, 0xfb, 0xdd, 0x3f, - 0x0f, 0xb0, 0xfb, 0xed, 0x6c, 0x9a, 0x06, 0xd1, 0x65, 0xdf, 0x00, 0xe0, 0xc4, 0xd1, 0xe2, 0xfa, - 0x54, 0x48, 0x25, 0xfe, 0x3a, 0x75, 0x3d, 0xe0, 0x44, 0x5d, 0xd1, 0x15, 0x8f, 0x81, 0x32, 0x8d, - 0x02, 0x26, 0xa0, 0xc9, 0x64, 0x11, 0x52, 0x39, 0xf0, 0x18, 0x67, 0x3a, 0xbf, 0x05, 0x64, 0x19, - 0xb5, 0x88, 0x75, 0x4d, 0x92, 0x6c, 0xb1, 0x2a, 0x7e, 0x59, 0xe8, 0xc2, 0x01, 0x74, 0xa1, 0xca, - 0xe5, 0x80, 0x27, 0xba, 0x51, 0x30, 0x73, 0x69, 0xe9, 0x25, 0xf3, 0x30, 0xf3, 0x11, 0xb2, 0xd8, - 0xc9, 0x84, 0xef, 0x66, 0x3e, 0xec, 0x81, 0x13, 0xdc, 0x06, 0x7d, 0x68, 0xf6, 0x1f, 0x2e, 0xfd, - 0xdb, 0x49, 0x0a, 0x1b, 0x68, 0x26, 0x8a, 0x72, 0x77, 0xdd, 0x3f, 0xdb, 0xb0, 0x34, 0xff, 0x7c, - 0xa7, 0x3a, 0xd8, 0xbb, 0xdf, 0xd7, 0x9e, 0x9c, 0xfd, 0xfb, 0xa2, 0xbf, 0x44, 0xba, 0x72, 0x1f, - 0x6a, 0x87, 0xfe, 0x24, 0xef, 0xbb, 0xf3, 0x3c, 0xde, 0x68, 0xed, 0x11, 0x49, 0x14, 0x80, 0x46, - 0xb9, 0x81, 0xf4, 0x28, 0x8e, 0x7c, 0x39, 0x67, 0x4b, 0x57, 0x7f, 0x3d, 0x35, 0x29, 0x9e, 0x00, - 0x2c, 0x40, 0xf4, 0xba, 0x0b, 0x33, 0x8f, 0x9c, 0x61, 0x3c, 0x4f, 0x33, 0xa8, 0x99, 0xc4, 0x01, - 0x75, 0x46, 0xa3, 0xd2, 0x47, 0xfb, 0x05, 0xd9, 0xae, 0x5f, 0xe7, 0x79, 0x0a, 0xdc, 0x97, 0xb9, - 0x9b, 0x1b, 0x86, 0x02, 0x76, 0xa2, 0x4c, 0x1f, 0x4e, 0x9f, 0x76, 0xce, 0x3b, 0xd9, 0x7c, 0x7d, - 0x67, 0x17, 0x08, 0xdb, 0xe4, 0xad, 0xee, 0x28, 0x33, 0x59, 0x2a, 0xbc, 0x30, 0x97, 0xdf, 0x17, - 0xe5, 0x9e, 0x38, 0x2b, 0xbc, 0x12, 0xdc, 0xd1, 0x9d, 0xfa, 0xea, 0x3c, 0x82, 0x4f, 0xaa, 0x44, - 0x05, 0x73, 0xf5, 0x83, 0xd2, 0xd7, 0xe6, 0xbe, 0xc1, 0xff, 0x60, 0xfb, 0x20, 0x86, 0x6b, 0x74, - 0x6f, 0xa7, 0xe8, 0x1e, 0x21, 0x34, 0x71, 0x53, 0xa0, 0x91, 0x3a, 0xe4, 0x0e, 0xe6, 0x19, 0xb2, - 0x47, 0xd8, 0x70, 0xc6, 0x39, 0x11, 0x88, 0xec, 0xaa, 0x44, 0x74, 0x1d, 0x2e, 0xf1, 0xb3, 0xe3, - 0x8e, 0x73, 0x58, 0x37, 0xb5, 0x2c, 0xd2, 0xe8, 0x49, 0xbb, 0xa6, 0x84, 0x84, 0xd1, 0x96, 0x22, - 0x65, 0x81, 0x7c, 0xa2, 0x4f, 0x85, 0x22, 0x89, 0x9c, 0x99, 0x7b, 0xd3, 0x96, 0x7c, 0x15, 0x56, - 0x0f, 0xd0, 0x99, 0x12, 0xcf, 0x04, 0xae, 0x89, 0x0a, 0x24, 0xd5, 0x2b, 0x05, 0x70, 0x14, 0xc6, - 0xe3, 0x4b, 0x6d, 0xd1, 0x4e, 0x5c, 0xcf, 0x3f, 0x8e, 0x84, 0x23, 0x97, 0xac, 0xb9, 0x52, 0xf9, - 0xe3, 0xdd, 0x24, 0x8d, 0x67, 0xc5, 0xaa, 0xec, 0x32, 0xca, 0x26, 0x71, 0x3a, 0xeb, 0xd3, 0xaf, - 0xd0, 0xcd, 0xfd, 0x7f, 0x6e, 0xee, 0xe1, 0x36, 0x96, 0xc7, 0xe5, 0x52, 0xd6, 0x8a, 0x11, 0x0e, - 0x0d, 0x8a, 0x3b, 0xf1, 0xc7, 0x80, 0x11, 0x18, 0x53, 0x86, 0xc4, 0x67, 0xd0, 0x5e, 0xea, 0x8f, - 0xdb, 0x28, 0x8d, 0x03, 0xa6, 0x0d, 0x0a, 0xfc, 0x79, 0x0e, 0x5b, 0xfb, 0xe4, 0x56, 0x8d, 0xab, - 0x4f, 0x6b, 0xa3, 0x3d, 0xf2, 0xf3, 0x6b, 0xdf, 0x8f, 0xea, 0xd6, 0x3e, 0xf1, 0x5d, 0xe4, 0xf2, - 0x7d, 0xfc, 0xc7, 0xdc, 0x86, 0x0d, 0x52, 0x46, 0xf1, 0xb3, 0xb5, 0x8e, 0x09, 0x98, 0xab, 0x1b, - 0x78, 0x61, 0x31, 0x2b, 0xc4, 0x5f, 0x44, 0x8f, 0x67, 0x86, 0xf8, 0x93, 0x24, 0x38, 0xc9, 0x78, - 0x68, 0x44, 0xa8, 0x3f, 0x98, 0xe3, 0xa1, 0xfe, 0x38, 0xcc, 0x07, 0xcc, 0x9e, 0x6e, 0xb6, 0x9b, - 0xe9, 0x23, 0x1e, 0xc1, 0xcc, 0x85, 0x01, 0x12, 0x6a, 0xd1, 0x58, 0xcd, 0x6e, 0x56, 0x08, 0x00, - 0x0b, 0x9b, 0x5a, 0x59, 0x8b, 0x7e, 0xc5, 0xe6, 0x3e, 0x4f, 0xbb, 0xc1, 0x62, 0x21, 0xd8, 0x73, - 0x6a, 0x7b, 0x26, 0x4b, 0x22, 0xdd, 0xc5, 0x51, 0xb6, 0x38, 0xe8, 0xba, 0x31, 0xcb, 0x3a, 0xd7, - 0x6e, 0x6a, 0x70, 0xe7, 0x05, 0x01, 0xb9, 0xfb, 0xb8, 0x66, 0xa2, 0x16, 0x4a, 0xed, 0x9a, 0x0c, - 0x4f, 0x4a, 0xdc, 0xad, 0x1a, 0x0e, 0x5d, 0xcc, 0x21, 0xf6, 0x49, 0x30, 0xba, 0x6b, 0x26, 0xb1, - 0x3a, 0x25, 0xf7, 0x5b, 0x5f, 0x63, 0x77, 0x61, 0x99, 0x81, 0x5c, 0x94, 0x7b, 0x4e, 0x34, 0x9f, - 0xdd, 0xd1, 0xf8, 0x69, 0x52, 0xfa, 0x84, 0x66, 0xae, 0x03, 0x3d, 0x08, 0x5c, 0xf8, 0x0b, 0x25, - 0x40, 0x7a, 0x1e, 0xf7, 0xa1, 0xca, 0x3c, 0x04, 0xbe, 0x0d, 0xcf, 0x59, 0x15, 0x4a, 0x1a, 0x5f, - 0x03, 0x3b, 0xcf, 0x16, 0x21, 0xd5, 0x09, 0x2e, 0xb5, 0x55, 0x85, 0x83, 0xdb, 0x5b, 0x31, 0xa8, - 0x5d, 0x1a, 0xd4, 0xa3, 0xca, 0x00, 0x1e, 0xed, 0x68, 0xa3, 0xa4, 0xad, 0x94, 0x0a, 0xca, 0x29, - 0xf0, 0x67, 0x49, 0x7e, 0x7b, 0xb7, 0x7a, 0xcb, 0x23, 0x5a, 0xd7, 0x7a, 0xa9, 0x16, 0x5c, 0x3d, - 0xff, 0xa5, 0x99, 0xf2, 0xdc, 0x6c, 0xea, 0xaf, 0x5d, 0x53, 0xf7, 0x9a, 0x38, 0xe6, 0x8c, 0x43, - 0x90, 0xe4, 0x71, 0x80, 0x77, 0x95, 0xdd, 0x40, 0x63, 0xd9, 0xd4, 0x4f, 0xb9, 0x23, 0xd6, 0x55, - 0x5d, 0xc2, 0xb2, 0xd5, 0x4a, 0x30, 0x78, 0xd2, 0x29, 0x88, 0xc5, 0xc4, 0x91, 0x4e, 0x7d, 0x26, - 0x5d, 0x83, 0x2d, 0x65, 0xfc, 0xf2, 0xee, 0x4b, 0x71, 0x8f, 0x3a, 0x2a, 0x53, 0x9a, 0x54, 0xa9, - 0x47, 0xa9, 0x66, 0x6b, 0x39, 0x62, 0x0d, 0xcf, 0x2b, 0xa6, 0xfe, 0xa0, 0xe0, 0x49, 0x15, 0xe4, - 0x55, 0xf7, 0x36, 0x6d, 0x49, 0x6a, 0x78, 0x2d, 0x47, 0x09, 0xc8, 0xcd, 0x16, 0x3b, 0xa2, 0x64, - 0x8e, 0x3a, 0x64, 0xb0, 0x26, 0xdf, 0x5a, 0xac, 0x24, 0xa6, 0xbb, 0x77, 0x0b, 0x34, 0x52, 0xe1, - 0x45, 0xcb, 0xb5, 0x16, 0x1c, 0x32, 0x08, 0x88, 0x1a, 0xd4, 0xf1, 0xd4, 0xbf, 0x4a, 0x2b, 0xbc, - 0xaa, 0x22, 0x1d, 0x48, 0x8a, 0xaf, 0x8c, 0xae, 0xd8, 0x99, 0x70, 0xdb, 0xd3, 0x20, 0x3a, 0x00, - 0x29, 0x74, 0x93, 0x0c, 0x08, 0x75, 0xa1, 0x91, 0x72, 0x37, 0x4b, 0xe3, 0x1c, 0x76, 0xbc, 0x66, - 0xfb, 0x49, 0xd7, 0xf3, 0x2f, 0x5a, 0x6b, 0xaa, 0x93, 0x12, 0xae, 0x6f, 0xe6, 0xfa, 0x00, 0x58, - 0x43, 0x67, 0xd2, 0x40, 0x85, 0x75, 0x09, 0xf5, 0x18, 0x54, 0xfa, 0x4d, 0xe0, 0x87, 0x9e, 0x38, - 0x89, 0xaf, 0x4d, 0xf2, 0x9c, 0xe0, 0xeb, 0xa2, 0xa1, 0x8b, 0x34, 0xf0, 0x06, 0xf8, 0x0f, 0xe0, - 0x63, 0x96, 0xe0, 0x06, 0x8d, 0x32, 0xc7, 0x7c, 0x16, 0x65, 0xa0, 0x7f, 0x75, 0x51, 0x60, 0x9d, - 0xa4, 0x24, 0x2c, 0xac, 0xa4, 0xa1, 0xfd, 0x82, 0x86, 0x36, 0x93, 0xf3, 0x0a, 0x61, 0xbb, 0x56, - 0xa8, 0x92, 0x30, 0x88, 0xe1, 0xec, 0xd6, 0x89, 0x62, 0xf7, 0x6a, 0x18, 0xfd, 0xd0, 0xcd, 0x72, - 0x40, 0x7c, 0x00, 0x23, 0x32, 0x5b, 0x56, 0x08, 0xa4, 0x62, 0xce, 0x78, 0xea, 0x46, 0x17, 0x7e, - 0x51, 0x06, 0x21, 0xb7, 0xeb, 0xf9, 0xfe, 0xaa, 0x1d, 0x65, 0xb7, 0x55, 0x40, 0x6c, 0x87, 0xee, - 0xc8, 0x0f, 0xef, 0xd6, 0xed, 0xbf, 0x2d, 0xb5, 0xa6, 0xa6, 0x7e, 0x98, 0x0c, 0x36, 0xd6, 0x52, - 0x2b, 0xcd, 0xac, 0x67, 0x4d, 0xce, 0xc8, 0xf5, 0x2e, 0x7c, 0xbd, 0x3b, 0xb8, 0xaa, 0x4b, 0x2e, - 0x0c, 0x48, 0xdc, 0x5f, 0xd0, 0x3b, 0x00, 0xb5, 0x0b, 0x6b, 0x8a, 0xe0, 0x96, 0x04, 0x3c, 0x4f, - 0x12, 0x3f, 0x1d, 0x83, 0xc8, 0xb0, 0xa9, 0x02, 0x52, 0x31, 0x18, 0x00, 0xce, 0x78, 0x34, 0xd4, - 0x3f, 0x12, 0x0f, 0x16, 0xe5, 0x85, 0x41, 0xad, 0x52, 0x89, 0xe6, 0xa7, 0xb2, 0xa6, 0x9c, 0xa0, - 0xbb, 0x75, 0x93, 0x66, 0x7c, 0x61, 0x10, 0x12, 0x42, 0xe4, 0xca, 0xca, 0x5f, 0x3f, 0x19, 0xbb, - 0xbb, 0xee, 0x64, 0x61, 0xaa, 0x7b, 0xfb, 0x07, 0x76, 0xef, 0x60, 0xd7, 0xee, 0x3d, 0xda, 0x27, - 0x13, 0xde, 0xbd, 0x9a, 0x03, 0xa8, 0xa9, 0xe9, 0x99, 0xe5, 0x5b, 0xd0, 0x59, 0x93, 0x79, 0x6e, - 0x97, 0xcf, 0xcc, 0x2b, 0xb5, 0x17, 0x4e, 0x1e, 0x5f, 0x5c, 0xc0, 0xae, 0x24, 0x39, 0x6a, 0xdb, - 0xbf, 0x82, 0x89, 0xce, 0x14, 0x6d, 0x96, 0x2b, 0xf5, 0x18, 0x01, 0x19, 0xab, 0x94, 0x40, 0x7f, - 0xcc, 0x6f, 0x13, 0x7f, 0xd8, 0xc0, 0x39, 0x69, 0x7c, 0xb2, 0xf5, 0x57, 0x20, 0x13, 0x8c, 0xfc, - 0x14, 0x5e, 0x72, 0x93, 0x77, 0x5b, 0x5b, 0xb5, 0xd6, 0xbb, 0x07, 0x6a, 0xab, 0xe5, 0xb6, 0x0d, - 0xc4, 0x82, 0x76, 0x84, 0x1a, 0x31, 0xa8, 0x4a, 0xf1, 0x4b, 0xcc, 0x81, 0xa5, 0x11, 0x50, 0xaa, - 0x1f, 0xa0, 0xbb, 0x6b, 0xda, 0xc8, 0xce, 0x63, 0x54, 0x46, 0xf4, 0x5d, 0x44, 0x53, 0x49, 0x95, - 0xda, 0x4a, 0x03, 0xee, 0x4f, 0xe2, 0xf1, 0x3c, 0x93, 0xe3, 0xe4, 0x87, 0xbb, 0x78, 0x9e, 0xa3, - 0x08, 0xab, 0x6b, 0xe4, 0xf5, 0x8a, 0x52, 0x1d, 0xca, 0xee, 0xda, 0xb3, 0xf8, 0xd7, 0xb6, 0x0b, - 0x84, 0xed, 0x42, 0xf3, 0x20, 0x26, 0xe1, 0xc8, 0x69, 0xc6, 0xea, 0xcb, 0xf7, 0xfb, 0xb0, 0x3e, - 0x46, 0x97, 0x41, 0xde, 0x86, 0x66, 0x89, 0xb4, 0x71, 0x2f, 0x9e, 0x03, 0x93, 0x89, 0xec, 0xd5, - 0xe5, 0x83, 0x28, 0x32, 0xcb, 0xdf, 0xa9, 0x2f, 0x5a, 0xeb, 0x34, 0x06, 0xa5, 0x95, 0xc1, 0xa0, - 0xe5, 0x84, 0x56, 0xb6, 0xe2, 0x65, 0x15, 0xab, 0xcf, 0x25, 0x15, 0xb4, 0x41, 0x6b, 0xbb, 0xf0, - 0xfb, 0xe8, 0x17, 0x68, 0x78, 0x6e, 0xee, 0xf6, 0xe9, 0xb9, 0x93, 0x5d, 0x5d, 0x6c, 0xdf, 0xcc, - 0x42, 0xfb, 0xcf, 0xbb, 0x2f, 0xe1, 0xa7, 0x80, 0x9f, 0x51, 0x36, 0x24, 0xc7, 0x41, 0xbf, 0xd3, - 0xb9, 0xbe, 0xbe, 0x76, 0xae, 0x77, 0x9d, 0x38, 0xbd, 0xe8, 0x00, 0xef, 0xef, 0x62, 0x61, 0x4b, - 0xb0, 0xc3, 0xc2, 0xea, 0x75, 0x2d, 0xc1, 0xb6, 0xab, 0xa1, 0x75, 0x60, 0xfd, 0x79, 0xf7, 0x08, - 0x20, 0x24, 0x6e, 0x3e, 0x15, 0xde, 0xd0, 0x7a, 0xd3, 0x15, 0xdd, 0x70, 0x5f, 0x1c, 0x88, 0xfd, - 0xf6, 0xc1, 0xaf, 0x96, 0x98, 0x04, 0x61, 0x38, 0xb4, 0xfe, 0xbc, 0xb3, 0xcb, 0x56, 0x75, 0xab, - 0xc3, 0xa5, 0x11, 0x1c, 0xfc, 0x6a, 0xe8, 0xeb, 0x15, 0x56, 0x2a, 0x0c, 0x00, 0xc5, 0x0b, 0xf9, - 0x4b, 0xff, 0x56, 0x18, 0x6a, 0x89, 0xcd, 0x91, 0x5d, 0xcb, 0xdc, 0x77, 0xd8, 0xd4, 0xd3, 0xdf, - 0xd9, 0x23, 0x23, 0x36, 0x2c, 0xa7, 0x33, 0x5a, 0x6e, 0xe2, 0xf4, 0x3a, 0xc8, 0xc7, 0x53, 0x69, - 0x9f, 0x50, 0x2b, 0x50, 0xc1, 0xf2, 0x61, 0x8f, 0x03, 0xf6, 0x52, 0x30, 0xe3, 0x20, 0x42, 0x5a, - 0x6a, 0xb3, 0xb2, 0xcb, 0xd4, 0xb9, 0x77, 0xa0, 0x19, 0x21, 0xf1, 0xb7, 0x61, 0x97, 0x1b, 0x00, - 0x2f, 0xce, 0x83, 0xb1, 0x1b, 0x4a, 0x91, 0x76, 0x06, 0x12, 0x58, 0x88, 0xfa, 0x14, 0x37, 0xc5, - 0x5c, 0xa1, 0x6c, 0xd0, 0x1d, 0xc1, 0xd2, 0x03, 0xca, 0x19, 0x94, 0x5a, 0x31, 0xb7, 0xd2, 0x55, - 0x4d, 0x74, 0x8b, 0xba, 0xc8, 0x79, 0xc7, 0x97, 0x15, 0x05, 0x7c, 0x49, 0x9f, 0xb4, 0x05, 0xff, - 0xf5, 0xee, 0xee, 0xee, 0xc1, 0x7e, 0xb7, 0xb2, 0x5a, 0xd1, 0xb6, 0x3f, 0x58, 0x2e, 0x0f, 0xeb, - 0x72, 0xdb, 0x6e, 0x66, 0x97, 0x16, 0x3c, 0x7c, 0xd4, 0x0d, 0x7a, 0xc0, 0xe6, 0xfd, 0x5c, 0x74, - 0x05, 0x1a, 0x45, 0xf6, 0x94, 0x61, 0xaf, 0x6b, 0xe3, 0xff, 0x39, 0xfb, 0x2d, 0xbb, 0x2b, 0x90, - 0xbd, 0x74, 0xa5, 0x6a, 0xb5, 0xbf, 0x6f, 0xab, 0xff, 0x9c, 0x2e, 0xf1, 0x50, 0x7d, 0x64, 0xfd, - 0xfe, 0xc8, 0x87, 0x7d, 0x05, 0xf7, 0x00, 0xd6, 0xcc, 0x2d, 0x6b, 0x60, 0x0e, 0x76, 0x11, 0x6d, - 0x28, 0xed, 0xe0, 0x48, 0x94, 0x34, 0x20, 0xf1, 0x41, 0xc6, 0xe1, 0x25, 0x86, 0xe2, 0xaf, 0x1f, - 0xbb, 0x8f, 0xbd, 0x27, 0x6e, 0x8d, 0x81, 0xb5, 0x5e, 0xb2, 0xdb, 0xcd, 0xc4, 0x78, 0x3e, 0x0a, - 0xc6, 0xed, 0x91, 0xff, 0x6b, 0xe0, 0xa7, 0x4d, 0x67, 0x0f, 0x3a, 0x6f, 0x3b, 0x3b, 0x76, 0xaf, - 0x65, 0x9b, 0x68, 0x32, 0x0d, 0x9d, 0x75, 0x18, 0xd9, 0x6b, 0x55, 0x28, 0xa1, 0x0f, 0x62, 0xe1, - 0xf8, 0xd2, 0xf7, 0xb6, 0xcd, 0x39, 0xde, 0xc4, 0x9a, 0xbb, 0x0a, 0xf3, 0xbb, 0x88, 0xf9, 0x2e, - 0x99, 0x13, 0x45, 0xd5, 0xff, 0xb4, 0xbb, 0xe9, 0xac, 0xac, 0xea, 0x61, 0x31, 0x57, 0x35, 0x36, - 0x9c, 0xbf, 0x37, 0x11, 0xe5, 0xc6, 0xc6, 0xfb, 0xf5, 0x64, 0x32, 0x59, 0x8f, 0x9d, 0x5d, 0x53, - 0x42, 0x7d, 0x4e, 0xc2, 0xad, 0x78, 0x41, 0xdc, 0xd1, 0x94, 0x52, 0x97, 0xdb, 0x04, 0x4c, 0xc9, - 0x06, 0x05, 0xcf, 0xee, 0xa0, 0xea, 0xd3, 0x91, 0x42, 0x60, 0xad, 0x2b, 0xa7, 0x50, 0xb1, 0x56, - 0xc8, 0xd1, 0x4a, 0xe7, 0xc2, 0x22, 0xac, 0xf1, 0x94, 0xfe, 0x21, 0x12, 0x4a, 0x74, 0xdd, 0x79, - 0x5f, 0xb3, 0x46, 0xca, 0x1d, 0x57, 0xdf, 0x99, 0x14, 0xf9, 0xad, 0xb4, 0xf2, 0x3e, 0xae, 0x53, - 0x70, 0xea, 0x64, 0xe3, 0x75, 0xfb, 0xad, 0xec, 0x5d, 0x1f, 0xf0, 0x86, 0x5a, 0xad, 0x57, 0x8a, - 0x2e, 0xbb, 0xfb, 0xaa, 0xfd, 0x28, 0x46, 0x75, 0x1c, 0xb4, 0x47, 0xdf, 0x93, 0xc5, 0x71, 0x63, - 0x09, 0x6f, 0x97, 0x59, 0xf7, 0xa5, 0xdc, 0xd4, 0xed, 0x76, 0x8d, 0xe2, 0x2c, 0x96, 0x22, 0xb4, - 0x66, 0xd1, 0x5c, 0x4b, 0x87, 0xf1, 0x75, 0xef, 0xc0, 0xdd, 0xdd, 0x73, 0xeb, 0xad, 0x80, 0xed, - 0x9e, 0xf4, 0x66, 0x21, 0x3c, 0x25, 0xde, 0x2d, 0x93, 0xe4, 0xea, 0xfa, 0xa0, 0xfc, 0xa5, 0x6b, - 0x7b, 0xe1, 0x3d, 0x79, 0xf4, 0xa8, 0x7b, 0xb0, 0x41, 0x2f, 0xa0, 0x3a, 0x6a, 0xa5, 0x77, 0xcb, - 0x7c, 0x4e, 0xb5, 0xb6, 0x71, 0xbd, 0xe6, 0x32, 0x5d, 0xb7, 0xf0, 0x46, 0x57, 0x8c, 0xe9, 0x31, - 0x68, 0x2f, 0xa6, 0x35, 0x3d, 0x26, 0x7d, 0x06, 0xe6, 0x18, 0xa4, 0x6b, 0x5f, 0xf3, 0x55, 0x4e, - 0x82, 0x1b, 0xdf, 0x23, 0x5e, 0xb8, 0x0f, 0xeb, 0x6a, 0xc0, 0x1b, 0x5f, 0x4f, 0x27, 0x4c, 0xd8, - 0xb1, 0x4d, 0x05, 0x83, 0x36, 0x2d, 0x2f, 0x48, 0x59, 0x83, 0xec, 0xb3, 0x56, 0x67, 0xea, 0x18, - 0xd4, 0xdc, 0xdd, 0x72, 0x2d, 0x4e, 0x23, 0xdd, 0x7a, 0x4d, 0x87, 0x56, 0x7d, 0x69, 0x21, 0x26, - 0x78, 0x68, 0x22, 0xde, 0x65, 0x13, 0xb1, 0x4d, 0x2f, 0xde, 0xcd, 0xf3, 0xe2, 0x8d, 0xd8, 0x71, - 0x1e, 0x65, 0x02, 0x66, 0xe1, 0x1a, 0xd0, 0x95, 0x69, 0x12, 0xe1, 0xee, 0x41, 0xb7, 0xa2, 0x8e, - 0xa0, 0x9d, 0xbe, 0x56, 0x13, 0x2c, 0x7a, 0xde, 0x8e, 0x2f, 0x17, 0x4c, 0x80, 0xba, 0x5f, 0x7d, - 0xbf, 0x35, 0x58, 0xa6, 0xf0, 0xe9, 0x84, 0x6d, 0x98, 0x2e, 0x15, 0x68, 0x3f, 0x4d, 0x17, 0xcd, - 0x8b, 0xa6, 0x8b, 0x7f, 0x19, 0x6c, 0xc5, 0xc9, 0xeb, 0x6d, 0xf7, 0x9a, 0xcd, 0x5c, 0xa2, 0x6b, - 0x03, 0xa3, 0xb9, 0x64, 0xb8, 0xeb, 0xac, 0xe6, 0x55, 0xd8, 0x80, 0xf9, 0x3b, 0xad, 0xca, 0x4a, - 0xd0, 0x26, 0x63, 0x7e, 0x7f, 0x2c, 0x4e, 0xfc, 0x89, 0x0f, 0xca, 0xf6, 0xd8, 0x47, 0xbb, 0x3b, - 0xec, 0x15, 0x06, 0x77, 0x4e, 0x82, 0x36, 0x62, 0x26, 0xb9, 0x33, 0x8d, 0x53, 0x6c, 0xa5, 0xbe, - 0xd7, 0x4b, 0xd4, 0x9a, 0x72, 0xea, 0xd0, 0x55, 0x31, 0x73, 0x1d, 0xd4, 0x72, 0xc4, 0x65, 0xea, - 0xe9, 0x82, 0xde, 0x79, 0x50, 0x76, 0x83, 0x4c, 0x9f, 0x77, 0x9a, 0x1e, 0x52, 0xaa, 0x0c, 0x64, - 0x83, 0xe9, 0xab, 0x1f, 0x5f, 0xcc, 0xde, 0x5f, 0xb1, 0xce, 0x2d, 0xda, 0x84, 0xb5, 0x8e, 0x89, - 0x7c, 0xaa, 0x9b, 0x71, 0x91, 0x9a, 0x6a, 0x6d, 0xcd, 0xf5, 0x6e, 0xb5, 0xf5, 0xee, 0xae, 0x03, - 0xd3, 0xdd, 0xf5, 0xa8, 0x30, 0xc8, 0x6e, 0x84, 0xc6, 0xbd, 0x85, 0xde, 0x7a, 0x77, 0xb5, 0xbd, - 0x5b, 0xbf, 0xa5, 0x56, 0xc4, 0x66, 0x28, 0x5a, 0x81, 0x2c, 0x4d, 0x85, 0xd8, 0xc4, 0x3a, 0x6b, - 0x21, 0xd6, 0x42, 0xed, 0x63, 0xd3, 0xf8, 0x07, 0x1d, 0x4d, 0x18, 0x23, 0x63, 0xda, 0xfc, 0x68, - 0x04, 0xf5, 0x2e, 0x7f, 0x6c, 0x68, 0xe6, 0xe7, 0xd3, 0xd8, 0xfb, 0x9c, 0xa6, 0x98, 0xcb, 0x54, - 0xb1, 0x5f, 0x09, 0xc6, 0x50, 0xcd, 0x78, 0x7e, 0x36, 0xae, 0xf7, 0x18, 0xe2, 0x57, 0xff, 0xc6, - 0x9d, 0x25, 0x0f, 0x0c, 0xf8, 0xd0, 0xda, 0xac, 0xa7, 0x13, 0x8d, 0xfd, 0x92, 0x0c, 0x7d, 0x0d, - 0x53, 0xd5, 0x1e, 0xa5, 0xbe, 0x7b, 0xd9, 0xa7, 0x7f, 0x51, 0x4a, 0x30, 0x0d, 0x15, 0xdf, 0x2f, - 0x38, 0xe1, 0x82, 0x5f, 0x60, 0x03, 0xca, 0xd3, 0x78, 0xbd, 0x6d, 0x95, 0x97, 0x3e, 0x69, 0x5b, - 0x2a, 0x2a, 0xc8, 0x39, 0x18, 0x54, 0x19, 0xc8, 0x4e, 0x55, 0xbc, 0xfb, 0x52, 0xab, 0xf2, 0x9e, - 0x3b, 0x8b, 0x9b, 0x6b, 0x1a, 0x87, 0x4b, 0x25, 0xcb, 0x8a, 0x87, 0xad, 0xd2, 0x3d, 0xb9, 0x7a, - 0x01, 0x8e, 0x21, 0x02, 0xee, 0x55, 0xb7, 0xce, 0xe5, 0xdd, 0xaa, 0x1f, 0xcc, 0xa2, 0x29, 0xe6, - 0x77, 0x49, 0x8f, 0xfb, 0xf5, 0xd2, 0x63, 0xd9, 0xf5, 0xe5, 0x91, 0x00, 0xab, 0x77, 0x2f, 0x59, - 0xdd, 0x09, 0x63, 0x17, 0x47, 0xae, 0x19, 0xc6, 0x06, 0xf5, 0x46, 0x2e, 0xac, 0x00, 0x92, 0xda, - 0x3c, 0xcc, 0xef, 0xbe, 0xb4, 0x37, 0xb5, 0xc6, 0x8f, 0xda, 0x53, 0x4e, 0xef, 0x69, 0x11, 0x63, - 0xa4, 0xb3, 0x63, 0x23, 0x10, 0x64, 0xa1, 0x83, 0xce, 0x55, 0x90, 0x05, 0xb8, 0x55, 0x18, 0x2a, - 0xa9, 0x51, 0x44, 0x24, 0xa9, 0x61, 0x65, 0x7d, 0xb4, 0x5f, 0x6f, 0xf5, 0x35, 0x89, 0x7c, 0xdf, - 0x60, 0x2e, 0x00, 0xa2, 0xad, 0xd8, 0x0b, 0x00, 0x06, 0x15, 0xaf, 0x8d, 0x5c, 0x78, 0x99, 0xf7, - 0xb3, 0xc6, 0x4e, 0x5c, 0xb7, 0xe7, 0x2e, 0x78, 0x49, 0x0d, 0xe0, 0xd2, 0x28, 0xa1, 0x85, 0x03, - 0xa0, 0x01, 0xae, 0x5a, 0xc8, 0x54, 0x6b, 0xf6, 0x14, 0x49, 0xab, 0x85, 0xe3, 0xc2, 0xa8, 0xff, - 0x58, 0xd7, 0xd6, 0xc1, 0x12, 0xd7, 0x96, 0x6c, 0xfd, 0xa1, 0x9e, 0x2d, 0x6d, 0x7f, 0xfa, 0x42, - 0xae, 0x2d, 0xa3, 0x23, 0x1b, 0x7a, 0xb6, 0x8c, 0x3a, 0x62, 0xba, 0x77, 0xb7, 0x4e, 0xed, 0xab, - 0x0d, 0x9c, 0x23, 0x97, 0x96, 0x6e, 0x28, 0xac, 0xc0, 0x75, 0x68, 0xfb, 0x58, 0xf0, 0xdd, 0x2e, - 0xe3, 0xfb, 0x84, 0x76, 0xd6, 0x22, 0x0a, 0x91, 0x4d, 0x02, 0xdc, 0xd8, 0x57, 0x76, 0xb0, 0xbf, - 0xce, 0x59, 0x66, 0x52, 0x8d, 0xee, 0xf4, 0xaa, 0xb4, 0xb5, 0xca, 0x65, 0xb6, 0x16, 0x48, 0xad, - 0xe3, 0x4c, 0xff, 0xb6, 0x81, 0x70, 0x62, 0x52, 0x3d, 0x13, 0xe2, 0xa2, 0x36, 0x65, 0x86, 0x88, - 0x48, 0x5f, 0x38, 0xb5, 0x95, 0xb8, 0x20, 0x76, 0xa3, 0x23, 0x2a, 0x29, 0x16, 0xd0, 0xae, 0xb2, - 0xa1, 0x7f, 0x86, 0x65, 0x7e, 0x89, 0xdd, 0xfd, 0x61, 0xfb, 0xfe, 0xce, 0x4a, 0x8f, 0x54, 0x8d, - 0x49, 0x70, 0x65, 0x54, 0x93, 0x31, 0xc8, 0xcf, 0xda, 0x3e, 0x06, 0x4b, 0x6c, 0x5e, 0x14, 0x44, - 0x8d, 0x46, 0x29, 0x68, 0xc2, 0xbf, 0x49, 0x5c, 0x50, 0x67, 0xbd, 0x7f, 0xb7, 0xcd, 0x62, 0x45, - 0x78, 0x93, 0xde, 0x9f, 0xea, 0xba, 0x5d, 0xa3, 0xc5, 0x50, 0x14, 0x64, 0xed, 0xea, 0xae, 0x80, - 0xc5, 0x07, 0x76, 0x17, 0xa5, 0xf1, 0xf5, 0x66, 0x61, 0xac, 0x07, 0x35, 0x91, 0x27, 0xf5, 0x71, - 0x32, 0xf5, 0x0d, 0x2d, 0x78, 0x2e, 0xeb, 0x37, 0x31, 0xc9, 0x29, 0xa0, 0x91, 0x22, 0x80, 0x6c, - 0xc1, 0x12, 0xbe, 0x19, 0x51, 0x2e, 0xed, 0x09, 0x6f, 0x4a, 0x5f, 0xd6, 0x73, 0xb5, 0xb7, 0xb1, - 0xe7, 0x8a, 0x87, 0xf5, 0xb8, 0x5b, 0x5d, 0x5c, 0x75, 0x4e, 0xac, 0x15, 0x3e, 0xa3, 0x55, 0x63, - 0x5b, 0xe1, 0x0b, 0xb2, 0x37, 0xab, 0xb7, 0xe0, 0x73, 0x5a, 0xe6, 0x43, 0x5a, 0xd3, 0x91, 0x07, - 0x3a, 0xce, 0x56, 0xc1, 0xaa, 0x3a, 0xd3, 0x1f, 0xee, 0x47, 0xdf, 0xaf, 0x6b, 0x01, 0x56, 0x61, - 0x1a, 0xdc, 0xb4, 0x31, 0x14, 0xe1, 0xae, 0xe2, 0x9b, 0xe1, 0x18, 0x05, 0xa0, 0xeb, 0xbd, 0x52, - 0x64, 0x40, 0x66, 0xbe, 0x43, 0x61, 0x40, 0x2b, 0x00, 0x49, 0xb1, 0x87, 0x67, 0xfa, 0x00, 0x6b, - 0x2f, 0x84, 0x22, 0xd5, 0x00, 0x58, 0x13, 0x8e, 0xa6, 0x9b, 0x86, 0x1f, 0x6b, 0xca, 0x0a, 0xbf, - 0x39, 0xd8, 0x4c, 0x1b, 0xe6, 0x66, 0x3f, 0xc7, 0x39, 0xb5, 0x7b, 0x50, 0x71, 0x7c, 0x54, 0x82, - 0xc6, 0x4b, 0xb8, 0x72, 0xf4, 0x2b, 0xfd, 0x4e, 0x45, 0xe1, 0x76, 0x06, 0x7d, 0xd4, 0x2d, 0x8e, - 0x85, 0x03, 0xa6, 0xb2, 0x5f, 0x90, 0x53, 0xa2, 0xd6, 0xb2, 0x5e, 0xcb, 0x83, 0x77, 0x2a, 0x8e, - 0x5e, 0x92, 0x0c, 0x16, 0x9a, 0xad, 0x73, 0x0c, 0x2d, 0xf6, 0x44, 0x09, 0xd4, 0x7b, 0x85, 0x17, - 0x88, 0x7e, 0x16, 0x9e, 0x21, 0xc9, 0x0d, 0x77, 0xeb, 0x36, 0xdd, 0x92, 0xa5, 0xad, 0xf4, 0x0a, - 0x55, 0xba, 0x57, 0x75, 0x90, 0x2c, 0xa0, 0x6b, 0x99, 0x1b, 0xe7, 0x21, 0x40, 0x56, 0x7b, 0x5a, - 0x7a, 0x07, 0x35, 0x9e, 0x16, 0x33, 0x1a, 0x6d, 0x0c, 0xfa, 0x6c, 0x38, 0x32, 0xcf, 0xba, 0x94, - 0x2c, 0x24, 0x53, 0x9f, 0xd5, 0x3a, 0x28, 0xe9, 0x87, 0xb5, 0xe2, 0x9a, 0xa2, 0xcb, 0x9c, 0x54, - 0x1c, 0x93, 0x51, 0x5b, 0x61, 0x3a, 0x9f, 0x8d, 0x56, 0x59, 0xbe, 0x17, 0x83, 0x4f, 0x56, 0x41, - 0x5a, 0x26, 0x5b, 0x6b, 0xa1, 0xa3, 0x1a, 0x06, 0x5e, 0xb3, 0x36, 0x6a, 0x46, 0xe1, 0x25, 0xc4, - 0x73, 0xef, 0x56, 0x2c, 0x25, 0xa2, 0x1e, 0x9d, 0xa8, 0xe4, 0xae, 0xb3, 0xb3, 0x5a, 0xba, 0x80, - 0x65, 0xdd, 0x5e, 0x11, 0xb9, 0xad, 0x11, 0x56, 0x29, 0x5c, 0x60, 0x6f, 0x40, 0xac, 0xcc, 0x04, - 0x76, 0x02, 0x66, 0xaa, 0xfe, 0xb8, 0x03, 0x96, 0x42, 0x83, 0xed, 0x82, 0x38, 0xbc, 0x7b, 0xc0, - 0xe2, 0x30, 0x0a, 0x62, 0x52, 0xf5, 0x6e, 0x23, 0x82, 0x60, 0x60, 0x6b, 0x85, 0x86, 0x6a, 0x34, - 0x74, 0x45, 0x4b, 0xda, 0x5d, 0xbe, 0xf9, 0x17, 0xe2, 0x06, 0x34, 0xfb, 0xb4, 0xa3, 0x8e, 0x1c, - 0x3e, 0xed, 0xa8, 0x13, 0x90, 0x28, 0x5c, 0xe3, 0xdf, 0xaf, 0xda, 0xed, 0xca, 0xa1, 0xab, 0x76, - 0x1b, 0xdf, 0x7b, 0xc1, 0x95, 0x18, 0x87, 0x6e, 0x96, 0x0d, 0x1b, 0x18, 0x70, 0x89, 0xa7, 0x1a, - 0x85, 0xa8, 0xbe, 0xe5, 0x23, 0x43, 0x0d, 0x75, 0xd0, 0xf1, 0x29, 0x9e, 0x1d, 0x3a, 0x94, 0xc7, - 0x1d, 0xe9, 0xf7, 0xd3, 0x0e, 0xd4, 0xa8, 0xaf, 0x9a, 0xf9, 0x49, 0x63, 0xd5, 0x77, 0xc4, 0x43, - 0x43, 0x04, 0x9e, 0x7c, 0x04, 0x84, 0x65, 0x30, 0x19, 0x8d, 0xc3, 0xab, 0xa7, 0xa3, 0xc3, 0xf6, - 0xd3, 0xce, 0xe8, 0x01, 0x75, 0x91, 0x12, 0xfd, 0xc8, 0x83, 0xe6, 0xd6, 0x57, 0xdd, 0xa8, 0x5b, - 0x87, 0x0b, 0xaf, 0xf1, 0x38, 0x8c, 0x3a, 0x68, 0xa3, 0xea, 0x7f, 0xf3, 0xfe, 0x54, 0x3c, 0x1d, - 0x95, 0xdd, 0xa0, 0x4f, 0x9b, 0x74, 0x5d, 0x14, 0x81, 0xad, 0x0d, 0x11, 0x47, 0xf4, 0x30, 0x6c, - 0x64, 0x14, 0x18, 0x71, 0xe6, 0x8e, 0x9a, 0x56, 0x5a, 0x84, 0xd5, 0x5b, 0xad, 0x86, 0xa0, 0x39, - 0x18, 0x36, 0xde, 0x25, 0x7e, 0xa4, 0x07, 0xdc, 0xe7, 0xee, 0xa8, 0x71, 0x78, 0x72, 0xf4, 0x52, - 0xd4, 0xf6, 0x35, 0x9e, 0x4c, 0x34, 0x04, 0x01, 0x40, 0xd5, 0xe9, 0x15, 0x5d, 0x23, 0x95, 0x93, - 0x09, 0x01, 0xbe, 0xb2, 0x48, 0x63, 0x14, 0x18, 0xe5, 0x91, 0xd6, 0x61, 0xd8, 0x97, 0xe3, 0x34, - 0x7f, 0x19, 0xc3, 0x6a, 0xb9, 0x68, 0xb6, 0x1a, 0x87, 0x47, 0xf4, 0x2c, 0xfe, 0xf1, 0xf4, 0xdd, - 0x5b, 0xc0, 0x01, 0xd5, 0xe6, 0x76, 0x64, 0x8b, 0xc5, 0x5f, 0x22, 0x49, 0x3c, 0xab, 0xb2, 0x48, - 0x89, 0xf0, 0xb6, 0x86, 0x12, 0xdd, 0x91, 0xe0, 0xe3, 0x0f, 0xf5, 0xe8, 0xca, 0x64, 0xc4, 0x2f, - 0x20, 0xeb, 0x50, 0x45, 0xff, 0x2e, 0x19, 0x26, 0xe0, 0xac, 0x16, 0x84, 0x9b, 0x04, 0x58, 0xdb, - 0x70, 0xad, 0xac, 0x00, 0x41, 0x88, 0x75, 0x47, 0x88, 0x90, 0x76, 0xf0, 0x4b, 0x3d, 0xc8, 0xe0, - 0x17, 0x84, 0x78, 0x8c, 0x91, 0x3d, 0xe2, 0xfb, 0x39, 0xac, 0xfd, 0xfc, 0x76, 0x43, 0x88, 0xe5, - 0xf4, 0x6f, 0x40, 0x1e, 0x87, 0x25, 0x49, 0xd4, 0x23, 0x9a, 0xfc, 0x98, 0x2f, 0x95, 0xd7, 0xb2, - 0x06, 0xe7, 0xa6, 0x5b, 0x53, 0x76, 0x05, 0x5f, 0x66, 0xe5, 0x42, 0x51, 0x73, 0xd6, 0x2f, 0xc3, - 0xab, 0xeb, 0x26, 0x4f, 0xf1, 0xb1, 0x62, 0xba, 0xd4, 0xb0, 0xd4, 0x14, 0x2d, 0x4e, 0x6e, 0x85, - 0x63, 0x72, 0x15, 0x55, 0xbc, 0x2d, 0xbf, 0x9a, 0x0b, 0x52, 0xee, 0x1e, 0xaa, 0x77, 0xc5, 0x0e, - 0x33, 0x26, 0x52, 0x9c, 0xa7, 0xc4, 0xd5, 0x1d, 0xc7, 0xa9, 0xa0, 0xdb, 0x00, 0x8c, 0x0c, 0xbc, - 0x21, 0x88, 0x6d, 0x0e, 0x1b, 0xba, 0x7d, 0x62, 0x19, 0x73, 0x90, 0x82, 0x67, 0xa5, 0x7f, 0xc5, - 0xdb, 0x5a, 0x48, 0xb5, 0x2b, 0x09, 0x66, 0x58, 0x14, 0x6e, 0x7a, 0x06, 0xa7, 0x3d, 0x2a, 0x2f, - 0x79, 0x39, 0xf1, 0xf4, 0xe1, 0x25, 0x89, 0xf5, 0x19, 0x2e, 0xb3, 0xe7, 0xf8, 0x2c, 0xe4, 0x0b, - 0x63, 0xa1, 0x2d, 0x6d, 0x4a, 0x4a, 0xfe, 0x3a, 0x35, 0xb9, 0x57, 0xfe, 0xf3, 0xc8, 0x3b, 0xe1, - 0x0f, 0x08, 0xf6, 0x14, 0xde, 0x88, 0xbf, 0xb8, 0xb3, 0x64, 0x20, 0xe4, 0xdb, 0xcd, 0x60, 0x4b, - 0xef, 0xba, 0x06, 0x5b, 0xbe, 0xd1, 0xba, 0xfc, 0x8a, 0xdf, 0x7c, 0x2e, 0x40, 0xec, 0x3e, 0x88, - 0x60, 0xaf, 0xfc, 0x89, 0x3b, 0x0f, 0x73, 0x84, 0xa8, 0xd0, 0xbd, 0x44, 0x13, 0x5d, 0x61, 0xe7, - 0xc0, 0xf5, 0x42, 0xd0, 0x84, 0x02, 0x57, 0xed, 0x15, 0xee, 0x6b, 0x0a, 0xfe, 0xc2, 0x41, 0xc5, - 0xcd, 0x34, 0x73, 0x9e, 0x55, 0x56, 0xc5, 0x60, 0x49, 0xcc, 0xa3, 0x1c, 0xa9, 0x8a, 0x36, 0xcc, - 0x55, 0x0c, 0xb1, 0x5f, 0x71, 0xed, 0xae, 0x5a, 0x61, 0xe5, 0xd2, 0x02, 0xd6, 0xd5, 0xa8, 0x94, - 0x2b, 0xfc, 0xbb, 0x9c, 0x13, 0x61, 0xf7, 0xf0, 0xa5, 0xbe, 0x32, 0x40, 0x46, 0xd8, 0xa5, 0x1c, - 0x06, 0xe4, 0xd9, 0xd3, 0xaa, 0xd0, 0x0b, 0xe8, 0x69, 0x4e, 0x32, 0xc4, 0xd3, 0x3c, 0xc5, 0x9f, - 0x87, 0x6f, 0xc8, 0xc3, 0xf6, 0xb4, 0x03, 0x3f, 0xf1, 0xf1, 0x28, 0xf2, 0x48, 0xdb, 0x28, 0x5e, - 0xbc, 0xf2, 0x41, 0x3c, 0x0c, 0x12, 0x86, 0x2c, 0xdf, 0x01, 0x8e, 0x13, 0x58, 0x16, 0xbe, 0x38, - 0x62, 0xcf, 0x18, 0x7f, 0xe8, 0x20, 0xc4, 0x8e, 0x82, 0xae, 0x04, 0x14, 0x6a, 0xc6, 0xd3, 0xfb, - 0xc1, 0x3e, 0xbd, 0xc6, 0xe1, 0xb7, 0x47, 0x67, 0x50, 0xdc, 0xab, 0x7e, 0x46, 0xdf, 0x62, 0xe3, - 0xb0, 0x03, 0x3f, 0x3b, 0x57, 0xbd, 0x8e, 0x94, 0x1b, 0xea, 0x0a, 0xa2, 0xd5, 0x95, 0xd6, 0x8b, - 0x90, 0x85, 0x6c, 0x21, 0x25, 0x05, 0x81, 0x61, 0xa1, 0x36, 0xa1, 0x9b, 0x5c, 0x4e, 0xb0, 0x8c, - 0xc5, 0x0a, 0x40, 0xd2, 0xbf, 0xd7, 0x38, 0xbc, 0x6b, 0xc4, 0x97, 0x0d, 0x50, 0x00, 0xe6, 0xbe, - 0x4d, 0x81, 0x9b, 0x8d, 0xfe, 0x1d, 0xae, 0xcf, 0x73, 0x25, 0xbc, 0xf4, 0x1b, 0x5d, 0x67, 0xd7, - 0xd9, 0x6b, 0xd8, 0x0d, 0x25, 0x92, 0xf4, 0x1b, 0xb8, 0x96, 0x0e, 0xfc, 0xc6, 0xfd, 0x3d, 0x43, - 0x46, 0x24, 0xfc, 0xfe, 0x51, 0x33, 0xab, 0x5b, 0x3e, 0xe8, 0x6f, 0xe6, 0x61, 0x68, 0xf2, 0x43, - 0xe1, 0x66, 0x72, 0x6b, 0x7e, 0xe0, 0xf8, 0x18, 0x0a, 0xfc, 0x02, 0x8e, 0x7a, 0xff, 0x85, 0x47, - 0xe1, 0x26, 0xee, 0x28, 0x80, 0x9d, 0x31, 0x40, 0x4e, 0xb6, 0x74, 0x2c, 0x74, 0x54, 0x02, 0x4f, - 0xac, 0x61, 0x97, 0x04, 0xec, 0x83, 0x53, 0x31, 0x9b, 0xe7, 0x5c, 0xf3, 0x16, 0xa5, 0xf5, 0xf8, - 0xc1, 0x83, 0x22, 0x93, 0x49, 0x86, 0xbf, 0xae, 0x40, 0xcb, 0x8b, 0xbb, 0x0e, 0xca, 0x6e, 0xf0, - 0x54, 0xc2, 0x85, 0x99, 0x43, 0x79, 0x0f, 0xe6, 0xed, 0xcb, 0x8e, 0x79, 0x16, 0x7b, 0xab, 0x06, - 0x7b, 0xea, 0x47, 0xa0, 0xd0, 0x0b, 0x2c, 0x25, 0x7c, 0x3a, 0x6d, 0xc6, 0xb3, 0x47, 0xa3, 0x06, - 0x46, 0x88, 0xca, 0x36, 0x51, 0x32, 0x08, 0x9f, 0xb6, 0x70, 0x81, 0x94, 0x79, 0xab, 0x15, 0xa0, - 0x32, 0x10, 0xec, 0x07, 0xa3, 0x82, 0x4d, 0xc9, 0xbe, 0x77, 0x0e, 0x10, 0x1a, 0xfd, 0xae, 0x5d, - 0xbe, 0x40, 0x70, 0x8d, 0xfe, 0x8e, 0xdd, 0x80, 0x2f, 0x80, 0x9d, 0x8f, 0x77, 0x0d, 0x55, 0x84, - 0x06, 0x41, 0x6f, 0x28, 0xbe, 0x89, 0xde, 0x91, 0xda, 0x06, 0xc5, 0xf7, 0x0f, 0xe0, 0x81, 0x15, - 0xb7, 0x06, 0x68, 0x6e, 0x7b, 0x58, 0xdc, 0xbd, 0x39, 0x27, 0x04, 0x3f, 0x81, 0x07, 0x1a, 0x67, - 0xbf, 0x01, 0xd4, 0xd4, 0xb8, 0xff, 0x04, 0xff, 0xf7, 0x45, 0xb1, 0x7b, 0xe1, 0xe7, 0xcf, 0x9e, - 0x06, 0x87, 0xa0, 0xb5, 0x3d, 0xed, 0x04, 0x87, 0xcb, 0xd1, 0xfc, 0xad, 0x0f, 0x32, 0x8a, 0xc8, - 0x60, 0x0f, 0x47, 0x16, 0x48, 0x14, 0x2e, 0x88, 0x26, 0x60, 0x07, 0x09, 0xe7, 0xfe, 0xe7, 0xd1, - 0x13, 0x8c, 0x4a, 0xa3, 0x26, 0xbb, 0x41, 0xa0, 0x1a, 0xfd, 0x83, 0xee, 0x97, 0x1d, 0x63, 0x56, - 0x8c, 0x71, 0x28, 0x3b, 0xbb, 0x6a, 0xa4, 0x20, 0xaf, 0x19, 0x03, 0x74, 0xc4, 0x6b, 0x24, 0x17, - 0x5e, 0x00, 0x82, 0x84, 0x0b, 0x11, 0xcc, 0x66, 0xbe, 0x17, 0x80, 0x2e, 0x1b, 0xde, 0x0e, 0x84, - 0x14, 0x16, 0x54, 0x09, 0x8c, 0x72, 0x4d, 0x7d, 0xd4, 0x87, 0xcf, 0x41, 0x01, 0x41, 0x39, 0xeb, - 0xf7, 0x22, 0x67, 0x14, 0x00, 0xc3, 0xcd, 0xfd, 0x12, 0x41, 0x7b, 0x18, 0x38, 0xf8, 0x45, 0x51, - 0x94, 0x2a, 0x09, 0x66, 0x19, 0x56, 0x4e, 0x7c, 0x94, 0x2c, 0x0b, 0xc4, 0xa4, 0xf1, 0x0c, 0x25, - 0xaf, 0x4b, 0x5a, 0x50, 0x3c, 0x5a, 0x01, 0xfb, 0x94, 0x98, 0x20, 0x1b, 0x85, 0xbd, 0x38, 0x46, - 0x2f, 0x5e, 0x12, 0x24, 0x74, 0x3a, 0xf7, 0xc1, 0xe3, 0x67, 0x80, 0xfc, 0xd6, 0x18, 0xe7, 0xef, - 0x1d, 0xa6, 0x0b, 0x52, 0x68, 0x3e, 0xaf, 0x5f, 0xf3, 0x3c, 0x4e, 0x9e, 0xeb, 0x39, 0x7a, 0xe4, - 0x54, 0x61, 0xd1, 0x8c, 0x7c, 0x1f, 0xa7, 0x5e, 0x3e, 0x3b, 0x7e, 0xc4, 0x12, 0xe7, 0x36, 0xd0, - 0xc1, 0x5c, 0x3d, 0x0d, 0xc4, 0x29, 0xee, 0x5b, 0x47, 0x20, 0x85, 0x85, 0xb7, 0xad, 0x07, 0x0f, - 0x19, 0x66, 0x36, 0xf0, 0xd4, 0x4b, 0x94, 0x96, 0x01, 0xa4, 0x7a, 0x44, 0x5b, 0xd2, 0x2b, 0x1f, - 0x76, 0x94, 0xae, 0xb3, 0x0f, 0xbc, 0x05, 0xd5, 0x1a, 0x7a, 0x6c, 0x77, 0x1d, 0xe0, 0x35, 0xb7, - 0xee, 0x35, 0x3d, 0xf5, 0x9c, 0x27, 0x7f, 0x08, 0xae, 0x60, 0xd3, 0x09, 0x83, 0x11, 0x12, 0xe0, - 0x79, 0xe8, 0x5f, 0xf9, 0xe1, 0x72, 0xdc, 0x7d, 0x17, 0x03, 0x3b, 0x40, 0x2a, 0x18, 0xbb, 0xc8, - 0x86, 0x05, 0x15, 0xef, 0x0b, 0x90, 0x93, 0x53, 0xd0, 0xe9, 0x32, 0xf1, 0xdf, 0x7a, 0x18, 0x38, - 0x19, 0x4f, 0x04, 0x8a, 0x96, 0xa1, 0x8d, 0x12, 0xe8, 0x15, 0xbc, 0x46, 0x12, 0x4a, 0x50, 0x1e, - 0x00, 0x05, 0xaa, 0x44, 0x72, 0x9e, 0x06, 0xb3, 0x13, 0x1e, 0x78, 0x07, 0x7f, 0xbf, 0x97, 0xc3, - 0x16, 0x4d, 0xb5, 0xde, 0x52, 0xff, 0x97, 0x79, 0x90, 0xfa, 0xde, 0xc3, 0x91, 0xad, 0xc1, 0x06, - 0x2c, 0xee, 0x38, 0xc8, 0x80, 0xf5, 0x36, 0x80, 0x29, 0x77, 0x9d, 0xbd, 0x5d, 0xbb, 0x21, 0x9b, - 0x3a, 0x91, 0x2d, 0xd5, 0x50, 0x24, 0xc8, 0xa4, 0x2c, 0x98, 0xc1, 0x5f, 0xa4, 0x03, 0x5d, 0x4a, - 0x5d, 0x25, 0x60, 0x1e, 0xc9, 0x35, 0xf2, 0x92, 0x03, 0x78, 0xfe, 0x73, 0x89, 0x98, 0xc0, 0xcd, - 0xd7, 0x0a, 0x5c, 0x4a, 0xc2, 0x86, 0x75, 0x84, 0x66, 0x21, 0xe2, 0x6c, 0xcc, 0x57, 0xb2, 0xc2, - 0x22, 0xf1, 0x50, 0xb6, 0x89, 0x3b, 0xe6, 0x97, 0xde, 0x3c, 0x70, 0x2c, 0x28, 0xd7, 0xac, 0x90, - 0x97, 0xc7, 0xf9, 0xdc, 0x0d, 0xc9, 0xd8, 0x55, 0xb0, 0x3e, 0x1c, 0x52, 0x73, 0xe6, 0xde, 0x02, - 0x93, 0x9c, 0x80, 0x76, 0xc2, 0x03, 0x63, 0x94, 0xb4, 0x3e, 0x6f, 0x5c, 0xfb, 0x4f, 0xbe, 0xd0, - 0xb8, 0x70, 0xd9, 0x00, 0x59, 0x77, 0x02, 0x2f, 0x5d, 0x21, 0x42, 0xc6, 0x29, 0xe8, 0x53, 0xa0, - 0xd7, 0x15, 0x3b, 0x9d, 0x38, 0x7e, 0x75, 0x22, 0x94, 0x71, 0xf7, 0xc1, 0x43, 0x80, 0xc6, 0xbe, - 0xe0, 0xe2, 0x39, 0x3e, 0x7d, 0x2f, 0x35, 0xef, 0x8a, 0xb5, 0xe8, 0x3f, 0xd3, 0x22, 0x72, 0x57, - 0x91, 0x1c, 0xa8, 0xd6, 0xe8, 0xe6, 0x8b, 0x33, 0x58, 0x40, 0x40, 0x63, 0xee, 0x45, 0x14, 0xe3, - 0x61, 0x91, 0xac, 0x2f, 0xb2, 0xe9, 0x1c, 0xa3, 0x5e, 0x6d, 0x71, 0xe1, 0x06, 0x20, 0xf5, 0x86, - 0x74, 0xda, 0x8c, 0x56, 0x17, 0x30, 0x5c, 0x34, 0xbf, 0x3f, 0x78, 0xee, 0x54, 0x3b, 0xe7, 0x73, - 0x20, 0xc3, 0xc7, 0xbb, 0xbb, 0xbb, 0xb8, 0x41, 0xa1, 0xd0, 0x7d, 0x8e, 0x4d, 0xc0, 0xc6, 0xd3, - 0xdd, 0xd9, 0xb3, 0x49, 0xd7, 0xf9, 0x92, 0xeb, 0xce, 0xbd, 0x1e, 0xad, 0x1e, 0xbf, 0xe0, 0x30, - 0xb4, 0x91, 0x1b, 0x92, 0xdb, 0x58, 0xf0, 0x69, 0x4b, 0x3c, 0xf7, 0x8d, 0x2a, 0x00, 0xf4, 0xd7, - 0x16, 0x27, 0xdf, 0xbe, 0x20, 0x34, 0x64, 0x34, 0x74, 0x56, 0x53, 0x3e, 0x43, 0x9d, 0x03, 0xb8, - 0xe7, 0x08, 0x17, 0x16, 0xe1, 0x7e, 0x17, 0xb6, 0x0a, 0x35, 0x70, 0x90, 0xdc, 0xbf, 0xfc, 0xb8, - 0x83, 0x5f, 0x96, 0x0f, 0xfb, 0xfb, 0xb9, 0x9f, 0xde, 0x0a, 0x0c, 0x6c, 0xc1, 0x15, 0x70, 0xfc, - 0xbd, 0xa0, 0x18, 0x16, 0x1f, 0xa6, 0x3b, 0x63, 0x7d, 0x67, 0x3c, 0x4f, 0xf1, 0x44, 0x39, 0xcf, - 0xf7, 0x43, 0x19, 0x28, 0xa9, 0x2b, 0x00, 0x8f, 0x14, 0x39, 0xa0, 0x9a, 0xc8, 0xcf, 0x34, 0xa1, - 0x7c, 0xbf, 0x0b, 0xaa, 0xc7, 0x97, 0x1d, 0xa8, 0x12, 0xcc, 0xa9, 0xd5, 0x4d, 0x45, 0xf3, 0x42, - 0x09, 0xd1, 0x87, 0xef, 0x88, 0x57, 0x71, 0xde, 0x8e, 0xd0, 0xbd, 0x84, 0xba, 0xdf, 0x04, 0x08, - 0x21, 0x9b, 0x8f, 0xda, 0x52, 0x22, 0x6f, 0xfa, 0xce, 0x85, 0xc3, 0xf4, 0x41, 0xbe, 0x28, 0xe7, - 0xf6, 0x3c, 0x9e, 0x64, 0xf9, 0x70, 0xa7, 0xdb, 0x7d, 0x38, 0x33, 0x56, 0x28, 0x62, 0x33, 0x48, - 0x96, 0x7f, 0x96, 0xda, 0xf2, 0xfe, 0xdd, 0xe9, 0x66, 0x18, 0xe2, 0x84, 0x98, 0xcb, 0x31, 0xf2, - 0xc2, 0x05, 0x89, 0xa5, 0x2d, 0xd3, 0x66, 0x9a, 0x04, 0x41, 0x5b, 0x0e, 0x1a, 0x30, 0x44, 0x33, - 0x9e, 0xe7, 0xc9, 0x1c, 0x5d, 0x1c, 0xa2, 0x04, 0xdd, 0x72, 0x74, 0x81, 0xf5, 0xe1, 0x0c, 0x9d, - 0x9a, 0x5c, 0x22, 0x12, 0x7d, 0x2e, 0x65, 0xa0, 0xcb, 0x0d, 0x98, 0x58, 0x27, 0xc8, 0x92, 0x15, - 0x9a, 0x88, 0x7b, 0x4d, 0xe4, 0x2f, 0x0b, 0xa3, 0x99, 0xe6, 0x3d, 0x0c, 0x15, 0x1a, 0xf0, 0xe7, - 0x59, 0x9b, 0xec, 0x90, 0x22, 0x09, 0x61, 0x81, 0x0a, 0x34, 0x2f, 0xae, 0x1c, 0x18, 0xfa, 0xe5, - 0xce, 0x35, 0xf6, 0x26, 0x90, 0xbb, 0xfd, 0xb8, 0xb5, 0x45, 0xef, 0x71, 0x8d, 0x0b, 0xe4, 0x6d, - 0x5f, 0x60, 0xc3, 0x2a, 0x5c, 0x0e, 0xff, 0xb9, 0xb6, 0x28, 0xf6, 0xab, 0x74, 0xd6, 0xa8, 0x8e, - 0xa7, 0x52, 0x5a, 0x97, 0x28, 0x70, 0xc4, 0x3b, 0xea, 0x30, 0x88, 0x4c, 0x4f, 0x51, 0x58, 0x3a, - 0x7c, 0xe6, 0x05, 0xe9, 0xb0, 0x83, 0x90, 0x9f, 0x76, 0xe8, 0x05, 0xad, 0x5f, 0x49, 0xb3, 0x7c, - 0xe4, 0x2b, 0x4e, 0x1f, 0x4e, 0xa1, 0xec, 0x69, 0x90, 0xf6, 0x44, 0x5c, 0xa6, 0x00, 0x0a, 0x9e, - 0x3a, 0x39, 0x30, 0xf2, 0x2f, 0xad, 0x3c, 0x4b, 0x34, 0xc4, 0xc9, 0x2a, 0x2c, 0xc4, 0x49, 0xc1, - 0x9f, 0xd3, 0x92, 0x1e, 0x3e, 0x7f, 0x54, 0xf1, 0x1f, 0x36, 0x0e, 0xd8, 0x3e, 0xb3, 0x55, 0xa6, - 0x00, 0xd9, 0x79, 0x96, 0x27, 0x6c, 0x31, 0xba, 0xcd, 0x41, 0x8d, 0xbb, 0x4e, 0x03, 0x10, 0x3c, - 0x40, 0xe4, 0x20, 0x09, 0x51, 0x90, 0x15, 0x1f, 0xf6, 0x5d, 0xff, 0x62, 0x86, 0x11, 0xf4, 0x9f, - 0x35, 0xd0, 0x2b, 0xe0, 0xaa, 0x13, 0x37, 0xcc, 0xe0, 0x35, 0xc7, 0x14, 0x90, 0xdd, 0x8c, 0x9a, - 0x83, 0x5f, 0x7f, 0xc4, 0xe0, 0x97, 0xe9, 0x1d, 0xca, 0x38, 0x90, 0xe5, 0x92, 0x68, 0x1d, 0x1c, - 0x12, 0xfd, 0xea, 0xc8, 0x17, 0x53, 0xff, 0x6a, 0x5c, 0x10, 0x70, 0x10, 0x02, 0x46, 0x80, 0x7f, - 0xf0, 0x37, 0x86, 0xed, 0x00, 0x01, 0xaa, 0x02, 0xb4, 0x5b, 0xa3, 0x5b, 0xc4, 0x16, 0xb3, 0x3c, - 0x98, 0xf9, 0x88, 0x35, 0xdf, 0xef, 0xe4, 0xb0, 0x83, 0x85, 0x8c, 0x4f, 0x47, 0x7c, 0x38, 0x26, - 0x9d, 0x82, 0xe0, 0xa0, 0x56, 0x6d, 0xba, 0xb2, 0x85, 0x3b, 0x8a, 0xaf, 0x7c, 0xe7, 0xc1, 0x78, - 0x95, 0xab, 0x60, 0x16, 0xe5, 0x9d, 0xd9, 0x6c, 0x3c, 0x0a, 0x2f, 0xbb, 0x49, 0x0f, 0x16, 0x07, - 0xf5, 0x18, 0x64, 0x00, 0x90, 0x67, 0x3e, 0xfd, 0x51, 0x88, 0xed, 0x78, 0xf1, 0x75, 0x84, 0x66, - 0xa4, 0x67, 0xd8, 0xda, 0x10, 0x76, 0xfe, 0x88, 0x74, 0x89, 0x95, 0x5b, 0x7e, 0x9e, 0xfa, 0xee, - 0x0c, 0x76, 0xfd, 0x02, 0x0c, 0x32, 0x7c, 0x50, 0x4c, 0xdc, 0x3c, 0x77, 0xc7, 0x53, 0xa4, 0x2d, - 0xa1, 0xc0, 0xae, 0xc4, 0x45, 0x13, 0xdb, 0x14, 0xc8, 0xf8, 0x5a, 0x7f, 0xd4, 0xe8, 0xfc, 0x10, - 0x76, 0xde, 0x07, 0x8c, 0xed, 0x15, 0x55, 0x30, 0xc6, 0x46, 0x9b, 0xf6, 0x12, 0xa2, 0x71, 0xd0, - 0xd3, 0x35, 0xcf, 0x70, 0xa9, 0x4d, 0xfd, 0x88, 0x68, 0x4c, 0x04, 0x99, 0x34, 0x67, 0x87, 0xb7, - 0x62, 0xe4, 0x23, 0x04, 0xae, 0xe6, 0x7b, 0x1b, 0x12, 0xc6, 0x97, 0x50, 0xc7, 0x5e, 0x81, 0xfa, - 0xd5, 0xe6, 0x89, 0xfa, 0xcf, 0xb5, 0xbf, 0x79, 0x30, 0xb0, 0xb5, 0xec, 0x10, 0x47, 0x8f, 0x99, - 0xd3, 0xa3, 0xc8, 0x0f, 0x05, 0x17, 0x16, 0xcd, 0xbd, 0xee, 0x9e, 0x08, 0x26, 0x02, 0x24, 0x52, - 0x39, 0x3f, 0xad, 0xcf, 0x66, 0x80, 0xfc, 0x56, 0xd9, 0x80, 0xc9, 0xf6, 0x6b, 0xff, 0x31, 0xa6, - 0x0e, 0x1e, 0x2e, 0xc8, 0xe4, 0xb2, 0x31, 0xa4, 0xe2, 0xb7, 0xeb, 0x25, 0x72, 0x4f, 0x47, 0x80, - 0xac, 0x8a, 0x3c, 0xeb, 0x72, 0x94, 0x00, 0x26, 0x7a, 0x6d, 0xcc, 0xbe, 0xf2, 0x39, 0x92, 0xb6, - 0xb2, 0x82, 0xff, 0x3b, 0x98, 0xbf, 0x8b, 0x91, 0x5f, 0xc4, 0xc9, 0xe7, 0x8c, 0xfa, 0xdb, 0x77, - 0xef, 0x05, 0x05, 0x94, 0x42, 0x0f, 0x71, 0xe8, 0x19, 0x2c, 0xc2, 0xc8, 0xcb, 0x3e, 0x7b, 0xc8, - 0xd0, 0x8d, 0x72, 0xb8, 0x3d, 0xa7, 0x5b, 0xee, 0x7f, 0x7f, 0xc8, 0x9c, 0x6f, 0x60, 0x0a, 0xd2, - 0xad, 0x3f, 0xa0, 0x31, 0x18, 0xc3, 0xff, 0x77, 0xb0, 0x06, 0x2d, 0x38, 0xfe, 0x0d, 0xc3, 0xcf, - 0x86, 0x8e, 0xff, 0xe0, 0x97, 0xc5, 0x68, 0x1a, 0x75, 0xe0, 0x53, 0xc5, 0x9e, 0x9c, 0x4d, 0x49, - 0xb3, 0xe4, 0x0c, 0xf0, 0x22, 0x49, 0x63, 0xf4, 0xc1, 0x64, 0x52, 0x0c, 0x25, 0xc3, 0x75, 0x86, - 0xc7, 0xd1, 0xc5, 0xd3, 0xd1, 0xe1, 0x69, 0x70, 0x31, 0x73, 0x51, 0xb8, 0x45, 0x75, 0x04, 0x83, - 0xd8, 0x04, 0x65, 0x25, 0xc2, 0x4a, 0x58, 0x0a, 0x99, 0xb1, 0xa6, 0x8e, 0x5d, 0x05, 0xc0, 0xe7, - 0x41, 0x24, 0x82, 0xcd, 0x5e, 0x78, 0x61, 0x8c, 0xb1, 0x69, 0xa0, 0x8f, 0x31, 0xab, 0x0f, 0x83, - 0xd1, 0x2c, 0x38, 0x07, 0xad, 0xc7, 0xc9, 0xe2, 0x82, 0xd9, 0xbf, 0x2f, 0xeb, 0xba, 0x29, 0xe0, - 0x3c, 0xbd, 0x70, 0x23, 0x10, 0x18, 0x3c, 0x10, 0x0f, 0xc4, 0x18, 0xd6, 0xc3, 0x45, 0x8c, 0xb6, - 0x80, 0x08, 0xb0, 0x0e, 0xbb, 0xe1, 0xc8, 0x17, 0xbf, 0xcc, 0xfd, 0x34, 0x40, 0xb7, 0x05, 0xbc, - 0x9a, 0xc5, 0x5e, 0x30, 0xc1, 0x07, 0x32, 0x4a, 0xa2, 0xb0, 0x01, 0xe2, 0xb4, 0x72, 0x54, 0x61, - 0xc7, 0x50, 0x9e, 0x50, 0xee, 0x19, 0x47, 0xc5, 0xc6, 0x80, 0x58, 0x71, 0xe9, 0x0b, 0x7f, 0x32, - 0xc1, 0xa1, 0xc6, 0x2c, 0x74, 0x44, 0xa0, 0x43, 0xb1, 0x44, 0xe7, 0xe8, 0x91, 0x18, 0xf0, 0x6b, - 0xba, 0xab, 0x82, 0x3e, 0x56, 0x1e, 0x25, 0x31, 0x72, 0x19, 0xea, 0xe7, 0x49, 0x30, 0x14, 0x93, - 0x97, 0x52, 0x31, 0x52, 0xde, 0x3d, 0xb4, 0xe8, 0x23, 0x2d, 0x98, 0x9d, 0x03, 0x90, 0x54, 0xac, - 0xd1, 0xc2, 0x24, 0xaa, 0x63, 0x7f, 0x0d, 0x55, 0x2f, 0x0b, 0x90, 0xfe, 0x64, 0x2d, 0x0e, 0x54, - 0xa1, 0xc8, 0x65, 0xa1, 0xa5, 0x21, 0x53, 0x65, 0xf9, 0x28, 0x10, 0x6e, 0xd8, 0x0d, 0x54, 0x1d, - 0xc7, 0xfe, 0x34, 0x0e, 0x3d, 0x3f, 0x1d, 0x36, 0x8a, 0x9e, 0xd1, 0x15, 0x18, 0x85, 0x21, 0x81, - 0x35, 0xff, 0xd6, 0x86, 0x70, 0x79, 0x19, 0x9b, 0x80, 0x7f, 0x20, 0x73, 0x77, 0x13, 0xf4, 0x9c, - 0x9e, 0xbd, 0x63, 0xef, 0x92, 0xc6, 0xe3, 0xa6, 0xa9, 0x7b, 0x9b, 0x15, 0x50, 0x57, 0x06, 0x41, - 0x95, 0x71, 0x49, 0x7e, 0x7e, 0xfc, 0x3d, 0x75, 0xb3, 0xc9, 0xc1, 0x7c, 0x65, 0x74, 0x4e, 0x31, - 0x5b, 0xf0, 0x23, 0xa9, 0x99, 0xab, 0x0d, 0xce, 0xd4, 0xe9, 0x59, 0x3a, 0x1b, 0x87, 0x2f, 0xb1, - 0x49, 0x10, 0x57, 0x0a, 0xaa, 0x06, 0xb2, 0x0b, 0xe3, 0x6b, 0x5c, 0x0e, 0x44, 0xcf, 0x41, 0x9e, - 0x09, 0xdf, 0x0b, 0x40, 0x5b, 0x73, 0xc4, 0x9b, 0x79, 0x98, 0x07, 0x6c, 0x80, 0xe1, 0xf2, 0xf0, - 0x89, 0x66, 0x92, 0x45, 0x5f, 0xb4, 0x61, 0x95, 0x16, 0x1a, 0x90, 0x62, 0x93, 0xdf, 0x4d, 0x54, - 0x7c, 0x40, 0xb2, 0x20, 0xac, 0x72, 0xea, 0x5e, 0xf2, 0x62, 0xa1, 0x90, 0x09, 0x92, 0x4e, 0x96, - 0xe1, 0x63, 0x7f, 0x63, 0x7c, 0x1c, 0x2c, 0xc1, 0x07, 0x60, 0x82, 0x83, 0x01, 0x00, 0x17, 0x34, - 0xa7, 0x88, 0x0e, 0x92, 0x59, 0xa5, 0xb0, 0x9e, 0x98, 0xd1, 0x75, 0x7c, 0xae, 0x4f, 0xf6, 0xce, - 0x08, 0xa4, 0xfb, 0x1d, 0x88, 0xe0, 0x53, 0xe7, 0x25, 0x26, 0xd8, 0x6a, 0xc8, 0xf6, 0x72, 0x19, - 0x72, 0xda, 0x01, 0xfe, 0xc9, 0x86, 0x25, 0x6d, 0xc1, 0x95, 0x8b, 0x49, 0x9d, 0x2a, 0xaf, 0x27, - 0x45, 0x3e, 0x34, 0xad, 0xd1, 0x20, 0x72, 0x9e, 0xdb, 0xe3, 0xef, 0x91, 0x00, 0xb9, 0xad, 0xe7, - 0x61, 0xa8, 0x93, 0xe1, 0x7a, 0x08, 0x1c, 0x19, 0xcb, 0x20, 0x6a, 0xa3, 0x62, 0x09, 0x08, 0x9d, - 0xf5, 0xaa, 0xc2, 0x90, 0x58, 0x32, 0xcf, 0x75, 0x60, 0x18, 0x69, 0x01, 0xc5, 0x5c, 0xa0, 0x28, - 0x36, 0x37, 0x88, 0x91, 0x27, 0xf9, 0xb0, 0xe1, 0xfc, 0x9c, 0xc5, 0x51, 0x7d, 0x30, 0x22, 0xf6, - 0x8e, 0xf8, 0xe2, 0x50, 0x1a, 0xbb, 0xa0, 0x7b, 0xf9, 0x34, 0xc0, 0x05, 0xfa, 0xb4, 0x43, 0x5d, - 0x39, 0x34, 0x19, 0xa2, 0x89, 0x43, 0x3e, 0x62, 0x6d, 0xb2, 0x82, 0x4c, 0xbd, 0x55, 0xa1, 0x73, - 0x09, 0x30, 0x76, 0xb3, 0x00, 0xbc, 0x41, 0xf8, 0xf0, 0x67, 0x4d, 0xe4, 0x9b, 0xa6, 0x0d, 0x6e, - 0xb6, 0xfb, 0x69, 0x41, 0xb2, 0x0b, 0xfd, 0x2d, 0x73, 0x8f, 0xab, 0x29, 0xaf, 0x7c, 0xc4, 0x60, - 0x22, 0xf9, 0x89, 0x3f, 0x1e, 0xc2, 0x8e, 0xd8, 0x57, 0xc1, 0xdc, 0x58, 0x02, 0xf5, 0xca, 0xc3, - 0xbf, 0xcc, 0x30, 0xdf, 0xf1, 0x40, 0x8b, 0xe8, 0xd6, 0x6a, 0xa0, 0x86, 0xab, 0xd7, 0xc0, 0x67, - 0xa3, 0x0a, 0x90, 0xa5, 0xf6, 0x99, 0x74, 0xe1, 0x35, 0x20, 0x31, 0xac, 0xc6, 0xe8, 0x05, 0x45, - 0xe0, 0xac, 0xae, 0x53, 0xe0, 0xc1, 0xa8, 0xa8, 0xe2, 0x6f, 0xb5, 0x31, 0x63, 0x44, 0xf8, 0x12, - 0x50, 0xfa, 0xcf, 0x0a, 0xa6, 0x54, 0x80, 0x6b, 0xd1, 0xe6, 0xda, 0x60, 0x56, 0xac, 0x85, 0xaf, - 0xaa, 0x21, 0xa7, 0xf0, 0xfe, 0xb4, 0x08, 0x36, 0x35, 0x6d, 0x68, 0xe6, 0xc2, 0x58, 0x1f, 0x19, - 0x6a, 0x36, 0x03, 0xc2, 0x65, 0xa5, 0x95, 0x38, 0xe1, 0x46, 0xd0, 0x80, 0xf5, 0x30, 0xc8, 0x1a, - 0x1c, 0x98, 0xcf, 0x6c, 0x5a, 0x92, 0x65, 0x93, 0x42, 0x47, 0xe9, 0x65, 0x65, 0x1d, 0x17, 0xbb, - 0xd2, 0x62, 0xb8, 0xb1, 0x9a, 0x43, 0xb4, 0xe5, 0x9b, 0xb3, 0x81, 0x29, 0xd2, 0x1b, 0x82, 0x4f, - 0xd1, 0x57, 0xa4, 0x00, 0x55, 0x91, 0x8b, 0xac, 0xa9, 0x83, 0x95, 0x96, 0x68, 0xa7, 0x25, 0xe9, - 0xb1, 0xb2, 0xca, 0xbd, 0x35, 0x35, 0xd6, 0xb7, 0xec, 0xfd, 0x24, 0x55, 0x54, 0x41, 0x88, 0xe6, - 0x28, 0xc8, 0x00, 0x87, 0x2e, 0x74, 0xd4, 0x37, 0x52, 0xfe, 0x2a, 0x5e, 0x2c, 0x2a, 0xa9, 0x12, - 0x38, 0x0a, 0xbc, 0xe5, 0x8a, 0x20, 0x23, 0xcc, 0xa1, 0x92, 0x83, 0x09, 0x45, 0x4a, 0x14, 0x5e, - 0xa4, 0x34, 0xca, 0x58, 0x5e, 0x76, 0x5a, 0x3e, 0xca, 0xd1, 0xbe, 0x8d, 0x4b, 0x6a, 0xc1, 0x14, - 0x55, 0x78, 0xec, 0x1f, 0xed, 0x51, 0x23, 0xb3, 0xfc, 0xc2, 0xb2, 0x75, 0x16, 0x38, 0x0e, 0x6b, - 0xe0, 0x87, 0xc6, 0x19, 0x2d, 0xb4, 0xfb, 0xe9, 0xe7, 0x93, 0x42, 0x90, 0xe2, 0x32, 0xd0, 0x7e, - 0xfc, 0x94, 0xdd, 0xfa, 0x62, 0x28, 0xee, 0xee, 0x07, 0xfc, 0x3e, 0x8c, 0xc7, 0x6e, 0xb8, 0xf8, - 0x5a, 0x0f, 0x65, 0x94, 0xef, 0xf1, 0xb5, 0x0c, 0x03, 0x45, 0x34, 0xc3, 0x5b, 0xcb, 0x1a, 0x00, - 0x96, 0x3a, 0x1d, 0x61, 0x71, 0x50, 0xa8, 0x25, 0x7e, 0x13, 0x16, 0x6c, 0x73, 0xf3, 0xcb, 0xd8, - 0x12, 0xff, 0xf6, 0x2f, 0xff, 0x9d, 0xed, 0x25, 0x95, 0xc8, 0x56, 0x74, 0x7d, 0xa2, 0x41, 0x32, - 0xf1, 0xd3, 0x76, 0x4c, 0xb6, 0x03, 0x34, 0xa5, 0xb1, 0xec, 0x86, 0x92, 0xac, 0xb4, 0x5c, 0x8e, - 0x50, 0xc4, 0x7d, 0x43, 0xb0, 0x5a, 0x78, 0x71, 0x53, 0x94, 0xe5, 0x42, 0x1e, 0x06, 0xfd, 0x86, - 0xfd, 0x46, 0x43, 0x90, 0x7e, 0xaf, 0x31, 0x7e, 0xbf, 0x89, 0xf7, 0x4d, 0x71, 0x89, 0xb3, 0x77, - 0xef, 0x5e, 0x9f, 0x1d, 0xbf, 0x3f, 0xc5, 0x2e, 0x6f, 0x6d, 0x59, 0xac, 0x27, 0x38, 0xd7, 0xfe, - 0xe8, 0x3d, 0xec, 0x10, 0x56, 0xdf, 0xfa, 0xee, 0xec, 0xec, 0xbd, 0x44, 0x85, 0xc0, 0x4d, 0x43, - 0x09, 0xd7, 0x2a, 0x5a, 0x25, 0x53, 0x52, 0xb8, 0xa3, 0xe2, 0xa9, 0xfb, 0xe2, 0x71, 0xd7, 0xb2, - 0x4b, 0x58, 0x18, 0xd7, 0x3f, 0xc6, 0x73, 0x5d, 0xaf, 0x31, 0x7c, 0x06, 0x40, 0xbe, 0x7c, 0xff, - 0x41, 0x14, 0x2f, 0x39, 0xa8, 0x46, 0x34, 0xbb, 0xed, 0x9d, 0x96, 0x23, 0xbe, 0x83, 0x8d, 0x1f, - 0x1a, 0x1a, 0x82, 0xc0, 0x0f, 0x3b, 0x09, 0x0c, 0x18, 0xc5, 0x5d, 0x74, 0x87, 0x0a, 0x58, 0x70, - 0xfc, 0x12, 0x88, 0x4d, 0x6f, 0xab, 0xa7, 0x37, 0x05, 0x40, 0x47, 0x71, 0xe6, 0x43, 0x1b, 0x47, - 0x14, 0xc4, 0x24, 0x3c, 0x60, 0xf3, 0x01, 0x86, 0x36, 0x85, 0xf1, 0xc5, 0x05, 0xe9, 0x09, 0x20, - 0xd0, 0xe4, 0x1e, 0x28, 0x0f, 0x8e, 0xf8, 0x90, 0xf9, 0x93, 0x79, 0x48, 0x52, 0x8d, 0xe7, 0x8f, - 0xe6, 0xf4, 0x5d, 0x03, 0x0c, 0xdc, 0x92, 0x41, 0x93, 0x6b, 0xd8, 0xa1, 0x30, 0x47, 0x00, 0x2c, - 0xc3, 0x33, 0xa7, 0xc0, 0x2c, 0xae, 0x51, 0x8d, 0xa1, 0xf7, 0x8e, 0x68, 0xf7, 0xa0, 0xd3, 0x18, - 0x20, 0x0e, 0x4a, 0x66, 0x0e, 0xf2, 0x92, 0x23, 0xde, 0x45, 0xe1, 0xad, 0xc4, 0x3f, 0x5a, 0x4e, - 0x66, 0x28, 0x3f, 0x26, 0x78, 0xfb, 0x12, 0x01, 0x40, 0x23, 0x28, 0xa0, 0x2d, 0x84, 0xbe, 0xe9, - 0xad, 0x20, 0xab, 0x28, 0x1b, 0x29, 0xa3, 0x3d, 0x31, 0x6a, 0x83, 0x42, 0x42, 0xb5, 0x96, 0x44, - 0x73, 0x8a, 0xd8, 0x02, 0xb9, 0x1d, 0x74, 0xab, 0x38, 0x99, 0xe3, 0x81, 0x44, 0x4f, 0x78, 0xb7, - 0x20, 0xd9, 0x63, 0x22, 0x27, 0x68, 0xdd, 0x20, 0x26, 0x8a, 0xd8, 0xa4, 0xb6, 0x48, 0x2f, 0xa3, - 0x16, 0x5e, 0x04, 0x11, 0xb4, 0xf6, 0x1e, 0x13, 0xc5, 0x02, 0x3c, 0x74, 0x42, 0xa9, 0xd8, 0x28, - 0x24, 0xb2, 0x51, 0x10, 0xb9, 0x20, 0xfc, 0x34, 0x1d, 0xf8, 0x01, 0x6d, 0x1c, 0xe1, 0xfa, 0x82, - 0xb6, 0xe7, 0x19, 0xce, 0x46, 0x10, 0xe2, 0xb1, 0x69, 0xc0, 0x1c, 0xc7, 0xd0, 0x23, 0x60, 0x86, - 0x8c, 0x6e, 0xa6, 0x37, 0x2e, 0xa2, 0x0a, 0xfe, 0x0d, 0x66, 0xf3, 0x99, 0x1c, 0x31, 0x39, 0xae, - 0x41, 0x7f, 0x9b, 0x05, 0x80, 0x9c, 0xae, 0x84, 0x83, 0x4d, 0x4a, 0x10, 0x68, 0x0d, 0xf4, 0xe6, - 0xa0, 0x68, 0x8a, 0x28, 0x0e, 0xe8, 0xca, 0x21, 0xe1, 0xb9, 0xe9, 0xa5, 0xc8, 0xc6, 0x7e, 0x44, - 0x1d, 0xe7, 0x7e, 0x73, 0x34, 0x00, 0x80, 0xfe, 0x90, 0x69, 0x4d, 0x14, 0xa1, 0x03, 0xa4, 0x8e, - 0x42, 0x55, 0x40, 0x41, 0x1a, 0x4b, 0xab, 0x05, 0x37, 0x87, 0x28, 0xc3, 0xe3, 0x7e, 0x63, 0xd1, - 0xc4, 0x08, 0x4a, 0xf2, 0xf7, 0x03, 0x56, 0xd1, 0x6d, 0xc8, 0xf1, 0x39, 0x02, 0x85, 0x21, 0x16, - 0x6c, 0x39, 0xf4, 0x8f, 0x4c, 0x03, 0x40, 0x83, 0x41, 0xec, 0xc9, 0xd5, 0xb6, 0x8b, 0xff, 0x13, - 0x6e, 0x2e, 0x0e, 0xba, 0x58, 0x15, 0x69, 0x07, 0x3b, 0xcc, 0x25, 0xf1, 0x46, 0xb0, 0xcc, 0x86, - 0x49, 0x83, 0x51, 0x20, 0x38, 0xd6, 0x3b, 0x51, 0x5f, 0xc5, 0xe0, 0x19, 0x50, 0xa2, 0x71, 0xf9, - 0x90, 0x9f, 0x28, 0xbc, 0x75, 0xc4, 0x0b, 0x69, 0x57, 0xa2, 0x5b, 0x05, 0xa5, 0xb7, 0xdb, 0xa8, - 0x51, 0x4c, 0x95, 0x7b, 0x3d, 0x7a, 0xc3, 0x64, 0xf1, 0x37, 0x0c, 0x10, 0x10, 0x32, 0x40, 0x40, - 0x92, 0x03, 0x51, 0x82, 0x36, 0x3a, 0x5b, 0x8c, 0xf3, 0x73, 0x58, 0x32, 0x68, 0xce, 0x18, 0x0a, - 0x4a, 0x4c, 0xb8, 0x18, 0x49, 0xa0, 0xc3, 0x7e, 0x89, 0xab, 0xfc, 0x65, 0xb5, 0x04, 0xe2, 0xf0, - 0x9f, 0xfc, 0xf0, 0x0a, 0xfe, 0x90, 0x71, 0x16, 0x0a, 0x52, 0x34, 0xf0, 0xb0, 0x80, 0xee, 0x08, - 0xb4, 0x83, 0xb5, 0x7b, 0x68, 0x0b, 0xd3, 0x96, 0x0d, 0x46, 0x14, 0x30, 0x78, 0xb4, 0x1d, 0x38, - 0xb3, 0x20, 0x4d, 0xe3, 0x14, 0x5a, 0xf8, 0x26, 0x0c, 0x12, 0x69, 0x4f, 0x98, 0x82, 0x76, 0xf0, - 0x2b, 0x9e, 0x36, 0x22, 0x44, 0x9c, 0x54, 0xf8, 0x88, 0x56, 0x79, 0x02, 0x75, 0xcc, 0xaa, 0x2a, - 0x4b, 0xd9, 0x9a, 0x8a, 0x7c, 0x2e, 0x13, 0xaa, 0x9e, 0xd0, 0x0f, 0x59, 0xb9, 0xd9, 0x15, 0xa8, - 0x9f, 0x3e, 0xee, 0x02, 0xc9, 0x5d, 0x80, 0xac, 0x86, 0x73, 0x5f, 0x0b, 0x44, 0x86, 0xa9, 0xa6, - 0x63, 0x89, 0xf7, 0x13, 0x84, 0x21, 0x75, 0x88, 0xbe, 0x18, 0x8f, 0xd2, 0x21, 0xf1, 0x4e, 0x37, - 0xca, 0x95, 0x79, 0xd0, 0x16, 0x57, 0xf0, 0x96, 0xee, 0x08, 0x01, 0xb6, 0x63, 0x0b, 0x17, 0x1f, - 0x5d, 0xcf, 0x4d, 0x68, 0x36, 0xcb, 0xf7, 0xbf, 0xe0, 0xfb, 0x5f, 0xa4, 0x91, 0xe7, 0x87, 0x17, - 0x27, 0x7a, 0x73, 0x40, 0x51, 0xd0, 0xd6, 0x19, 0xe8, 0x3c, 0xbe, 0xb4, 0x50, 0x10, 0xcb, 0x97, - 0xb6, 0x37, 0xe0, 0xbb, 0x21, 0x68, 0x3c, 0x30, 0x9b, 0xa4, 0x93, 0x71, 0x8c, 0x38, 0x53, 0xbf, - 0x23, 0xf0, 0x44, 0x90, 0xb2, 0x8e, 0xe8, 0x20, 0x51, 0xcb, 0xc2, 0xfe, 0x17, 0x7c, 0x04, 0x7d, - 0x0d, 0x7f, 0xbb, 0xf9, 0x4e, 0x92, 0x73, 0xef, 0xc9, 0x4e, 0xf7, 0xa6, 0xd7, 0x7d, 0xdc, 0x05, - 0x44, 0x3c, 0x27, 0x05, 0x22, 0x13, 0x19, 0xcc, 0x4e, 0x3e, 0x9e, 0xe7, 0x59, 0x5f, 0x3c, 0xda, - 0xe9, 0x26, 0xb6, 0xc0, 0xef, 0xf0, 0x67, 0xef, 0xcd, 0xfb, 0xd5, 0xd8, 0x92, 0x98, 0x28, 0x87, - 0xb0, 0xdc, 0x72, 0xaa, 0xf1, 0xf9, 0x11, 0xa5, 0xb4, 0x13, 0x12, 0x25, 0x36, 0xb3, 0xf8, 0x11, - 0xa8, 0xd5, 0x14, 0x4c, 0xbe, 0x7c, 0x64, 0x17, 0x71, 0x72, 0xca, 0x83, 0x5b, 0x62, 0xaa, 0x94, - 0x8b, 0x3e, 0x0c, 0xc9, 0x1c, 0xe6, 0xc2, 0x88, 0xaf, 0x50, 0x93, 0xe3, 0xa5, 0x0a, 0xeb, 0x5c, - 0xd9, 0xfe, 0x5a, 0xcb, 0xdb, 0xf8, 0x25, 0x79, 0xe5, 0x87, 0xb9, 0x0b, 0x6d, 0x1c, 0x77, 0xde, - 0xcb, 0x9a, 0xdf, 0x23, 0xbf, 0x82, 0x97, 0xa2, 0xd9, 0xee, 0xed, 0xe0, 0x54, 0x6c, 0xf7, 0x70, - 0xdf, 0x7a, 0xeb, 0x5f, 0x50, 0x6a, 0x80, 0x72, 0x44, 0xc7, 0x6d, 0xae, 0x20, 0x47, 0xb6, 0x62, - 0x8e, 0x90, 0xbf, 0x9d, 0x4d, 0x51, 0xac, 0x8c, 0x43, 0x0f, 0x99, 0x3f, 0xbe, 0x68, 0xcb, 0x9d, - 0x03, 0xcd, 0x94, 0x39, 0xa8, 0xc3, 0x17, 0xa8, 0x8c, 0xab, 0x42, 0x38, 0x8b, 0xc4, 0xa3, 0x05, - 0xcc, 0x5e, 0x97, 0x47, 0x0a, 0xdb, 0x15, 0xcc, 0xd5, 0x3e, 0xfe, 0xec, 0x39, 0xfb, 0x37, 0x78, - 0x58, 0xf9, 0xd2, 0x5f, 0x3d, 0x63, 0xd4, 0x32, 0xc6, 0xb8, 0xe2, 0x56, 0x87, 0x3c, 0x20, 0x02, - 0xdc, 0xcd, 0x69, 0x18, 0xf4, 0xa9, 0x4d, 0x30, 0x14, 0x29, 0xaa, 0xe8, 0x54, 0xc1, 0xc7, 0xe1, - 0x85, 0x0c, 0xbb, 0x43, 0x4e, 0x07, 0x9d, 0xd4, 0x38, 0xc0, 0xce, 0x9a, 0x55, 0xe5, 0x67, 0x20, - 0x25, 0xe1, 0xf1, 0x26, 0xdc, 0xa6, 0x91, 0x3b, 0xb4, 0xcb, 0x57, 0x98, 0xc1, 0x0b, 0xe3, 0xcd, - 0x9b, 0x34, 0x69, 0x6d, 0x29, 0x83, 0x8b, 0x6d, 0x71, 0xfa, 0xc3, 0xcb, 0xf6, 0x19, 0x80, 0x9b, - 0xbc, 0x4f, 0x29, 0x50, 0x19, 0x66, 0x1d, 0xd0, 0xfe, 0xee, 0xf4, 0x55, 0x3b, 0x73, 0x27, 0x3e, - 0xed, 0xd6, 0x18, 0xf3, 0x3d, 0x9e, 0xfb, 0x1d, 0x89, 0xf1, 0x4e, 0x96, 0xa4, 0x00, 0xa5, 0x93, - 0x52, 0xb2, 0xc4, 0x0e, 0xc8, 0x60, 0x73, 0xca, 0xc7, 0x81, 0x8e, 0x79, 0x58, 0xc7, 0x5c, 0x79, - 0x1e, 0x61, 0x75, 0xd1, 0x94, 0xe1, 0xba, 0xe8, 0x7c, 0x43, 0xce, 0x00, 0x54, 0x34, 0xc3, 0x73, - 0xe0, 0x94, 0xf0, 0x10, 0xca, 0xa1, 0xc1, 0xd2, 0x6d, 0xf5, 0x01, 0xe9, 0xc0, 0x79, 0x00, 0x22, - 0xcc, 0x0c, 0xec, 0xc8, 0x57, 0xb4, 0x85, 0x19, 0x3d, 0x73, 0x04, 0x77, 0x62, 0xd8, 0x75, 0x76, - 0xf6, 0x33, 0x44, 0x0c, 0xa6, 0x15, 0x83, 0x15, 0xca, 0x9d, 0x19, 0xd2, 0xb0, 0xb6, 0xbb, 0x0e, - 0x7f, 0xc3, 0xad, 0xc7, 0x17, 0x27, 0x47, 0xcf, 0x5f, 0xbd, 0x39, 0x22, 0x39, 0xa4, 0x88, 0x38, - 0x27, 0x21, 0xd9, 0xc0, 0xe3, 0x28, 0x8e, 0x73, 0xde, 0x64, 0x25, 0x1e, 0x7f, 0x8d, 0xe3, 0xd9, - 0xdf, 0x01, 0x85, 0xaf, 0x82, 0x8b, 0x00, 0x9d, 0xac, 0xf8, 0x2c, 0x60, 0xd3, 0x4b, 0x64, 0x1a, - 0x76, 0xf1, 0x77, 0x9b, 0x08, 0x03, 0x8f, 0xae, 0x91, 0x0d, 0x15, 0xe5, 0x06, 0x32, 0xac, 0x2c, - 0xa7, 0x45, 0x84, 0xf1, 0xcf, 0xab, 0x60, 0xfe, 0x33, 0xc3, 0x44, 0xd7, 0xbf, 0x02, 0xc9, 0x26, - 0xa4, 0xe5, 0x30, 0xa5, 0x84, 0x8a, 0x7c, 0x5c, 0xca, 0xaa, 0x74, 0xb4, 0x05, 0x85, 0x5d, 0x0a, - 0xad, 0x46, 0xe8, 0xba, 0xf5, 0x96, 0x4e, 0x24, 0x04, 0xe8, 0x2f, 0x86, 0x39, 0xc5, 0x2d, 0x0c, - 0xf1, 0xc1, 0x6c, 0x9d, 0xa5, 0xdc, 0xa1, 0x64, 0xe7, 0x32, 0x02, 0xee, 0x57, 0x97, 0x8f, 0xc3, - 0x20, 0xa0, 0x6d, 0x4e, 0xb4, 0x21, 0x9a, 0xd0, 0xa9, 0xa9, 0x12, 0xbd, 0x81, 0x93, 0xc9, 0xc0, - 0x20, 0x34, 0x59, 0xff, 0xf0, 0xfe, 0x88, 0x8a, 0xda, 0x52, 0x54, 0xa6, 0x97, 0xa7, 0x2f, 0x5f, - 0xd3, 0xcb, 0x81, 0x1c, 0x27, 0xee, 0x99, 0x54, 0x26, 0x8b, 0xe7, 0x14, 0x37, 0x8a, 0x82, 0xdd, - 0xb8, 0xe4, 0xbf, 0x4f, 0x87, 0x05, 0xeb, 0xc4, 0xc7, 0x4b, 0xdf, 0x4f, 0x04, 0xb0, 0xef, 0x41, - 0xd1, 0x27, 0x98, 0xb2, 0xf1, 0xb4, 0x4b, 0x91, 0x48, 0x03, 0xc2, 0xe2, 0xdf, 0x3b, 0x84, 0x5b, - 0x81, 0x47, 0x0b, 0x71, 0xb4, 0x45, 0x41, 0xb4, 0x1f, 0x46, 0x5e, 0x7c, 0x3d, 0x60, 0xd3, 0x76, - 0xe2, 0x02, 0x4d, 0x9d, 0xe2, 0x30, 0x39, 0x09, 0x45, 0x8b, 0x07, 0x8d, 0x9a, 0x54, 0xb8, 0x6c, - 0xe4, 0x93, 0x30, 0x76, 0x69, 0x1d, 0xf2, 0x57, 0xe4, 0xf2, 0x62, 0x14, 0xc2, 0xe0, 0x05, 0x9f, - 0x8e, 0xac, 0xa0, 0x63, 0x20, 0x83, 0x7a, 0x11, 0xcc, 0x6d, 0x46, 0xf8, 0xc5, 0x15, 0xc8, 0x21, - 0x85, 0x2f, 0x61, 0xd8, 0xef, 0xc7, 0xa8, 0xfc, 0xc0, 0x5e, 0x40, 0x1d, 0x9d, 0x06, 0x93, 0xbc, - 0x23, 0x01, 0x8d, 0xe6, 0x1e, 0x70, 0xf6, 0x25, 0x5d, 0x1d, 0x28, 0x8c, 0x8e, 0xe3, 0x19, 0x48, - 0x63, 0xec, 0xe7, 0xcf, 0xe2, 0x49, 0x8e, 0x72, 0xf2, 0xf6, 0x77, 0x7f, 0x6b, 0x8f, 0x60, 0x59, - 0xb2, 0x35, 0x9f, 0x04, 0x08, 0x14, 0x50, 0xe9, 0x1c, 0x02, 0x36, 0x23, 0xe3, 0x8c, 0x61, 0xb8, - 0x88, 0xa7, 0x76, 0x0f, 0x96, 0xcf, 0x4d, 0x07, 0x18, 0x59, 0x17, 0xff, 0x7d, 0x04, 0xbf, 0x77, - 0x6e, 0x3a, 0xbb, 0x37, 0x9d, 0xbd, 0x1b, 0x40, 0x42, 0xc2, 0x31, 0xa2, 0x1a, 0x89, 0x56, 0x07, - 0x58, 0x87, 0x71, 0x22, 0x34, 0xec, 0xf8, 0x00, 0x04, 0x4c, 0x31, 0x4f, 0x48, 0xf0, 0x22, 0x32, - 0x9c, 0xf2, 0x66, 0x44, 0x90, 0xfc, 0x19, 0x1a, 0x7d, 0x5d, 0x58, 0xff, 0x28, 0x9b, 0xa7, 0x42, - 0xed, 0x11, 0xb5, 0x1c, 0x8d, 0xd4, 0x06, 0x10, 0x49, 0xe3, 0xeb, 0x77, 0x99, 0xa7, 0x2b, 0x1d, - 0xf0, 0x9a, 0xd8, 0x86, 0x3c, 0xd2, 0xac, 0x7c, 0x0f, 0x84, 0xb6, 0x8c, 0x03, 0x00, 0x9a, 0x92, - 0x26, 0x19, 0x59, 0x01, 0xea, 0x77, 0x2e, 0x1f, 0x39, 0x41, 0x0a, 0x45, 0x51, 0x71, 0x20, 0x83, - 0x2a, 0xf4, 0xc9, 0x16, 0x38, 0xdf, 0x92, 0x7e, 0xa0, 0x9f, 0x30, 0x36, 0xd0, 0x9d, 0x80, 0xab, - 0x4d, 0x91, 0x79, 0x60, 0x52, 0x10, 0xc6, 0xe6, 0x2c, 0xbe, 0xa2, 0xe3, 0xd0, 0x38, 0x64, 0x26, - 0x2f, 0x98, 0x08, 0x34, 0xe1, 0xf2, 0x94, 0xa3, 0xf1, 0x50, 0xc6, 0x60, 0x30, 0xde, 0x3d, 0x81, - 0x77, 0x61, 0x2f, 0x1b, 0x26, 0x68, 0x4b, 0x17, 0x31, 0x2a, 0x47, 0xf2, 0x64, 0x48, 0x39, 0x52, - 0x5a, 0xe2, 0x2a, 0xb2, 0x89, 0x07, 0x46, 0x4a, 0xd4, 0xdf, 0x50, 0x64, 0x54, 0x07, 0x99, 0xed, - 0x22, 0x88, 0x3c, 0x05, 0x76, 0x8b, 0xa3, 0x0c, 0xbc, 0x90, 0x44, 0xdc, 0x1a, 0xa6, 0x51, 0xb4, - 0xc5, 0x2a, 0x27, 0xf2, 0x22, 0xda, 0x64, 0x78, 0xf4, 0x1f, 0x4e, 0x94, 0xde, 0x3b, 0xf7, 0xf0, - 0x4a, 0x0c, 0x58, 0x85, 0x4e, 0xef, 0xe0, 0xb1, 0xd3, 0x73, 0x7a, 0xfd, 0xfd, 0x03, 0x92, 0x2c, - 0x56, 0x40, 0xa4, 0xfe, 0x49, 0x91, 0xee, 0x8c, 0xae, 0x2b, 0x42, 0x8b, 0x2a, 0x08, 0xe6, 0x79, - 0x3c, 0x46, 0xc1, 0x2e, 0xcd, 0x13, 0xd1, 0x44, 0xb1, 0xce, 0xc3, 0x64, 0x66, 0xeb, 0x90, 0x01, - 0xc2, 0xd7, 0x7b, 0xf7, 0x16, 0xc3, 0x34, 0xa4, 0x20, 0x02, 0xba, 0x88, 0x38, 0x39, 0x7b, 0xdf, - 0xc1, 0x19, 0xc5, 0xe3, 0xa4, 0x09, 0x7f, 0x95, 0xd1, 0x44, 0xcd, 0xfd, 0x47, 0x07, 0x8e, 0xb3, - 0xc7, 0xe2, 0x4f, 0x0f, 0xfe, 0xa2, 0x10, 0x42, 0x9b, 0xcf, 0x84, 0x4e, 0xfb, 0x81, 0x2a, 0x1e, - 0xf9, 0xf9, 0x75, 0x9c, 0x5e, 0x02, 0xfd, 0xa6, 0x2e, 0x6a, 0x40, 0xf8, 0xe1, 0xe7, 0xf9, 0x6c, - 0x14, 0x4b, 0x51, 0x02, 0xb8, 0xe3, 0xa5, 0x0a, 0xfe, 0x44, 0x40, 0x54, 0x60, 0xf7, 0xc9, 0x93, - 0xdd, 0xf6, 0x9b, 0xb3, 0x0f, 0xd0, 0x5b, 0x37, 0xcc, 0xfd, 0xcb, 0x95, 0x28, 0x00, 0xc9, 0x28, - 0xa2, 0x93, 0x7d, 0x1f, 0x3c, 0x14, 0xac, 0x41, 0x03, 0x16, 0xc5, 0x2b, 0xf1, 0xe1, 0x15, 0x28, - 0xfa, 0xa0, 0x91, 0xfb, 0x6c, 0xe9, 0xc7, 0x04, 0xf4, 0x29, 0xb0, 0xb6, 0x14, 0x49, 0x0c, 0x09, - 0x19, 0xad, 0x3c, 0xba, 0x7e, 0x1c, 0xad, 0xc3, 0x10, 0x25, 0xb1, 0xff, 0x10, 0x05, 0x37, 0xf2, - 0x6c, 0xc8, 0x29, 0x4a, 0xfc, 0x24, 0x68, 0x00, 0x82, 0xf2, 0x40, 0x9e, 0xde, 0xa4, 0xdd, 0x00, - 0x1b, 0x9c, 0x43, 0x49, 0x98, 0x53, 0x49, 0x4e, 0x92, 0x88, 0x24, 0xc9, 0x81, 0x44, 0xcd, 0x1b, - 0x01, 0x0a, 0xde, 0x78, 0x26, 0x12, 0xbd, 0x83, 0x73, 0x90, 0x14, 0xd1, 0x84, 0x60, 0x70, 0x10, - 0x81, 0x2e, 0xc9, 0x90, 0x57, 0xbc, 0x2a, 0x8b, 0x46, 0xea, 0x99, 0xcf, 0x2a, 0x37, 0x0c, 0x02, - 0xfd, 0x94, 0xa8, 0xac, 0x25, 0xca, 0x71, 0x98, 0xfa, 0x33, 0x17, 0xf5, 0xf8, 0x14, 0xbf, 0x14, - 0xaa, 0x9f, 0x69, 0x0b, 0x58, 0x3b, 0xd8, 0xb9, 0x17, 0xc4, 0xd2, 0x66, 0xf2, 0x1c, 0x7f, 0x13, - 0x3e, 0xd9, 0x62, 0x72, 0x88, 0x7b, 0x26, 0xac, 0xb2, 0x60, 0x4c, 0x2a, 0x3a, 0x2f, 0x6e, 0x7c, - 0x97, 0x4d, 0xd1, 0x84, 0xc0, 0xab, 0x88, 0x51, 0x3f, 0x10, 0x4f, 0xbb, 0x72, 0x8a, 0xdb, 0xbd, - 0x16, 0xee, 0xd8, 0x64, 0xf4, 0x6a, 0xe3, 0x4e, 0x22, 0x9a, 0x63, 0x50, 0x28, 0x80, 0xf9, 0x6d, - 0xf3, 0x4b, 0x1b, 0x28, 0x06, 0x05, 0x14, 0x26, 0x6c, 0x1f, 0x49, 0xb6, 0x54, 0xc3, 0x0e, 0xba, - 0xbd, 0x75, 0x5d, 0xce, 0xa0, 0xdd, 0xb1, 0x9b, 0xca, 0x4e, 0xab, 0xee, 0x72, 0xb0, 0x31, 0x7f, - 0x2a, 0xce, 0xdc, 0x9a, 0x90, 0x97, 0x49, 0x78, 0x68, 0x44, 0x45, 0x4a, 0xb9, 0xd5, 0x38, 0xc5, - 0xf3, 0x28, 0x8a, 0xe7, 0x28, 0xd9, 0x91, 0x76, 0xad, 0x26, 0x89, 0x43, 0x9e, 0x66, 0xaf, 0xde, - 0x9e, 0x92, 0x6d, 0x29, 0x80, 0xef, 0xcd, 0x73, 0x99, 0x63, 0xa6, 0x8d, 0xd1, 0xaa, 0xce, 0x79, - 0x3e, 0x4e, 0x5a, 0xc8, 0xb5, 0x38, 0xc1, 0x50, 0xe7, 0x79, 0x04, 0x53, 0x16, 0xa0, 0x4b, 0x3e, - 0xc0, 0xf0, 0x3b, 0xa1, 0xda, 0x42, 0xae, 0x46, 0x7c, 0x12, 0x98, 0xba, 0x02, 0x30, 0x9d, 0x8f, - 0xd6, 0x13, 0xaa, 0xd6, 0x5b, 0xd9, 0x85, 0xb3, 0xdb, 0x04, 0xd7, 0xb1, 0xd1, 0x2b, 0xf4, 0xb1, - 0x08, 0xd7, 0x23, 0xbd, 0x33, 0xa3, 0xa4, 0x0c, 0x44, 0x20, 0xaf, 0x9f, 0xbf, 0xd5, 0x5a, 0x58, - 0xec, 0x39, 0xed, 0x2b, 0xa1, 0x8f, 0x19, 0x15, 0xdc, 0xac, 0x0d, 0x03, 0x9f, 0x47, 0x21, 0x3a, - 0xda, 0x6f, 0xe3, 0xb9, 0xb8, 0x8c, 0x80, 0x1d, 0x5f, 0x4f, 0x6f, 0xd7, 0xf5, 0x0a, 0x3d, 0xb4, - 0xaa, 0x3b, 0x64, 0x2c, 0x42, 0x2c, 0xb2, 0xcb, 0xa8, 0xc9, 0x44, 0x0a, 0x98, 0xf0, 0x80, 0x2c, - 0xc8, 0x95, 0x8b, 0xbb, 0x50, 0x84, 0xc2, 0x88, 0x44, 0x90, 0x66, 0xb0, 0x01, 0x84, 0xd3, 0x21, - 0x40, 0xb4, 0x06, 0xd1, 0xde, 0xc1, 0xb1, 0x00, 0x53, 0xe0, 0x39, 0x11, 0xd1, 0xf9, 0xea, 0x7e, - 0x8c, 0x80, 0x46, 0x9f, 0x87, 0x81, 0x8b, 0xda, 0xe9, 0xf3, 0x30, 0xc3, 0x16, 0xdc, 0x80, 0x21, - 0xe1, 0x27, 0x85, 0x75, 0x87, 0xec, 0xa2, 0x05, 0x54, 0xd1, 0xe4, 0x00, 0xfe, 0x38, 0x02, 0x2d, - 0x7e, 0x9c, 0x6b, 0xb6, 0xac, 0x16, 0x87, 0xc3, 0x46, 0x3e, 0x39, 0xa8, 0x65, 0x08, 0xc2, 0x26, - 0x8c, 0x85, 0x96, 0x98, 0x33, 0x9b, 0x93, 0x92, 0xf9, 0x66, 0x8e, 0x91, 0x66, 0xb4, 0xd0, 0xe4, - 0xaa, 0x30, 0x19, 0x1f, 0xe8, 0x64, 0x71, 0x1b, 0xb6, 0xbf, 0x60, 0x22, 0x4b, 0x95, 0xa1, 0x4b, - 0x04, 0x0c, 0xc4, 0x77, 0x07, 0x08, 0xea, 0xa8, 0xba, 0xa5, 0x9d, 0xbc, 0x83, 0x2d, 0xe6, 0xc4, - 0xbf, 0xa0, 0xcd, 0x76, 0x22, 0x8e, 0x49, 0x1c, 0xcc, 0xf2, 0x96, 0xf8, 0x71, 0xbe, 0xd3, 0xed, - 0xed, 0xa1, 0x46, 0x19, 0xe3, 0x32, 0x96, 0x9a, 0x2a, 0x4a, 0x0b, 0x88, 0x74, 0x16, 0x8f, 0xa1, - 0x82, 0x64, 0x1d, 0x0b, 0x3c, 0x58, 0xb6, 0xf7, 0x3d, 0xf2, 0x5d, 0x6c, 0x03, 0x14, 0x49, 0xd7, - 0xc3, 0xe4, 0x4f, 0x14, 0xf1, 0xd7, 0x6c, 0xef, 0x92, 0x24, 0xb9, 0xbd, 0xdb, 0x35, 0xb5, 0x49, - 0x29, 0x9b, 0x28, 0x93, 0x01, 0xec, 0xda, 0xdc, 0x14, 0x2b, 0x7d, 0x6a, 0x8b, 0x5d, 0xde, 0xde, - 0x69, 0xee, 0x93, 0x59, 0xe1, 0x2d, 0xdd, 0x7f, 0x85, 0x1d, 0x2c, 0xad, 0x2f, 0x34, 0x56, 0xd4, - 0xb5, 0x49, 0x37, 0xdf, 0x83, 0x86, 0xdf, 0xe0, 0x98, 0x32, 0xac, 0x82, 0xcc, 0x69, 0x06, 0x2a, - 0x07, 0x36, 0x7e, 0x81, 0x39, 0xb3, 0xf0, 0x06, 0xe2, 0xa5, 0xad, 0xbc, 0xa4, 0x3e, 0x21, 0x6b, - 0x67, 0x3c, 0xa4, 0x8c, 0xbf, 0x49, 0xca, 0xce, 0x23, 0xd1, 0xec, 0x3a, 0xbd, 0x76, 0xd7, 0x79, - 0x82, 0xc6, 0x36, 0x29, 0x58, 0x81, 0x12, 0x81, 0xba, 0x08, 0xfc, 0x92, 0xb8, 0xa3, 0x1c, 0x88, - 0x4b, 0x9a, 0x20, 0x8b, 0xa0, 0x32, 0x1f, 0xef, 0xbe, 0x92, 0x16, 0x42, 0xb2, 0xb4, 0x11, 0xfc, - 0xc2, 0x86, 0xfc, 0x68, 0xc1, 0x86, 0xfc, 0xf6, 0xa4, 0xd0, 0x8f, 0xeb, 0x09, 0x9d, 0xcc, 0x60, - 0xfe, 0x51, 0x74, 0x01, 0xba, 0x07, 0x52, 0xf8, 0x11, 0x30, 0x29, 0xfc, 0xdd, 0x17, 0x99, 0x07, - 0x9a, 0x84, 0xb4, 0x4e, 0xb6, 0xa0, 0x0d, 0x98, 0x6a, 0xb4, 0x57, 0x4e, 0x82, 0x74, 0x46, 0xa6, - 0x5f, 0x10, 0x67, 0xc4, 0xf3, 0x23, 0x47, 0x40, 0xbf, 0x41, 0x03, 0x62, 0xe9, 0x06, 0x73, 0xb3, - 0x52, 0x5a, 0x4d, 0x7c, 0xbb, 0xeb, 0x12, 0x1f, 0xd0, 0x8e, 0x25, 0x0c, 0x4a, 0x1b, 0xbd, 0xaa, - 0x16, 0x60, 0x6f, 0x72, 0xd2, 0xac, 0x51, 0x36, 0x0e, 0x2e, 0xa2, 0x18, 0x7f, 0x37, 0x11, 0x88, - 0x27, 0x22, 0x26, 0x84, 0xdd, 0xe7, 0x14, 0x19, 0x19, 0x5e, 0xa3, 0xf8, 0x86, 0x87, 0x79, 0x5b, - 0xab, 0x06, 0xf3, 0x0d, 0x4d, 0x39, 0x8c, 0x64, 0x16, 0x47, 0x18, 0xbd, 0x40, 0x61, 0x94, 0xd2, - 0x14, 0xf3, 0xdd, 0xaf, 0xea, 0x9c, 0x44, 0x5f, 0xf5, 0x00, 0x0a, 0xc2, 0xca, 0x1d, 0x73, 0x11, - 0xb6, 0xf6, 0x49, 0x7c, 0x0c, 0xb9, 0x84, 0x23, 0xbb, 0xdc, 0x87, 0x6d, 0x93, 0x02, 0x78, 0x89, - 0x8b, 0xcc, 0x13, 0xe4, 0x91, 0x19, 0x46, 0xed, 0x90, 0x55, 0x37, 0x23, 0x03, 0x05, 0x6c, 0xaf, - 0x4d, 0x37, 0xba, 0x2d, 0x40, 0xe8, 0x9b, 0x52, 0x6f, 0x7f, 0x79, 0xaf, 0x51, 0x87, 0x7a, 0x9e, - 0x25, 0x20, 0x8a, 0x40, 0xd7, 0x31, 0x94, 0x0a, 0xe6, 0x8c, 0x29, 0xa3, 0x5d, 0xa8, 0x88, 0xd2, - 0xec, 0x05, 0xeb, 0xa4, 0xdc, 0xf0, 0x81, 0xbf, 0x62, 0x25, 0x69, 0x0f, 0x69, 0x92, 0xfd, 0x20, - 0xc5, 0x3e, 0x5e, 0xf8, 0x31, 0x65, 0x3c, 0x6b, 0x0d, 0x04, 0x85, 0x5c, 0x23, 0x45, 0xc3, 0x46, - 0x99, 0x8f, 0xa7, 0x1d, 0x52, 0xa6, 0x0a, 0x5d, 0x5b, 0x42, 0x45, 0x15, 0x5f, 0x0d, 0xb4, 0x73, - 0x7c, 0xf0, 0x52, 0xf8, 0x37, 0x68, 0x11, 0xc3, 0xf4, 0x70, 0xc5, 0x19, 0x9d, 0xb6, 0x7b, 0x83, - 0x52, 0x1b, 0xc8, 0x1e, 0xfe, 0xaf, 0x18, 0xed, 0x82, 0xda, 0xea, 0x0d, 0x4d, 0x0c, 0x0e, 0x1c, - 0x64, 0x19, 0x3c, 0xbd, 0xa2, 0xa4, 0x0a, 0x96, 0x63, 0x5a, 0x82, 0xcc, 0xfc, 0x8c, 0x33, 0x04, - 0x0b, 0xba, 0x26, 0xea, 0x95, 0xf0, 0xec, 0x62, 0x50, 0x92, 0x5f, 0x74, 0x14, 0x67, 0x58, 0x1b, - 0x31, 0xaa, 0x9a, 0xb0, 0x8e, 0x40, 0x14, 0x0d, 0x89, 0x3f, 0x2e, 0x43, 0x9c, 0xb4, 0x88, 0x9f, - 0xcc, 0x43, 0xbf, 0xf7, 0xb8, 0x0b, 0xc8, 0x83, 0x7f, 0xff, 0xf5, 0x7f, 0xa8, 0x63, 0x73, 0x40, - 0x95, 0x21, 0x90, 0x32, 0xe6, 0xb7, 0x2b, 0x6d, 0xe4, 0x31, 0xfc, 0x86, 0x95, 0x09, 0x5b, 0x47, - 0xaf, 0xd3, 0xdc, 0xf9, 0x7f, 0xff, 0x6f, 0xb2, 0x65, 0x23, 0xa5, 0xba, 0xc6, 0x31, 0x3c, 0x05, - 0x02, 0xfa, 0x85, 0x62, 0x16, 0x4a, 0x61, 0x64, 0xc3, 0x07, 0x79, 0x1c, 0xd0, 0xc6, 0xdc, 0x0b, - 0x57, 0x2c, 0x9a, 0xc3, 0x51, 0xfd, 0x95, 0xfa, 0x62, 0x51, 0x89, 0x8d, 0xcf, 0x30, 0xca, 0x5e, - 0xa7, 0xb7, 0xd3, 0x15, 0xc0, 0x65, 0xf0, 0x38, 0x8a, 0xf8, 0xd7, 0xff, 0xc9, 0x96, 0x73, 0xa4, - 0xed, 0x79, 0x8a, 0x51, 0x77, 0x40, 0x26, 0x33, 0x17, 0x88, 0x95, 0xbd, 0x0e, 0xe1, 0x3c, 0xad, - 0x1f, 0x2d, 0xf3, 0xff, 0x05, 0x25, 0xc4, 0xd8, 0x04, 0x68, 0x0d, 0x69, 0x9a, 0xc8, 0x72, 0x38, - 0x19, 0xc5, 0xf3, 0x9d, 0xb0, 0xc9, 0x92, 0x25, 0x36, 0x7e, 0xa5, 0x2d, 0x15, 0xe8, 0x31, 0x46, - 0xa7, 0x8a, 0xde, 0x01, 0xfd, 0xd9, 0x7b, 0xcc, 0xe2, 0x7b, 0x41, 0xd0, 0xf4, 0x62, 0x55, 0x23, - 0x32, 0xa0, 0x30, 0x2b, 0x9a, 0x50, 0x2f, 0x80, 0xe3, 0x0e, 0x31, 0x05, 0xaf, 0x2d, 0x76, 0x86, - 0x19, 0x6e, 0x31, 0xb1, 0xb1, 0x50, 0x56, 0xc2, 0x04, 0xaa, 0x1f, 0x97, 0x00, 0xf1, 0x09, 0x26, - 0x78, 0x3c, 0x83, 0xd9, 0x79, 0xd4, 0xeb, 0xb9, 0xfc, 0x67, 0x6e, 0xa3, 0xad, 0x3b, 0x4e, 0xe6, - 0xc6, 0xce, 0x4a, 0x8f, 0xcb, 0x21, 0x5f, 0xe1, 0x25, 0x44, 0x25, 0x3a, 0x14, 0x4a, 0xf9, 0x35, - 0xb2, 0xd7, 0x9e, 0x39, 0xfc, 0xc7, 0x4b, 0xc6, 0xae, 0x65, 0x11, 0x28, 0xa7, 0xe9, 0xc5, 0x9b, - 0xe3, 0x9d, 0x47, 0x5d, 0x71, 0xfc, 0xe6, 0x03, 0x5a, 0xf7, 0x50, 0x9e, 0x82, 0xa9, 0x9f, 0xf9, - 0x2e, 0x92, 0x1a, 0xed, 0x81, 0x20, 0xff, 0xa3, 0x2b, 0xeb, 0x95, 0xca, 0x7f, 0x35, 0xba, 0x55, - 0xae, 0xa1, 0x81, 0x9c, 0x19, 0x96, 0xfa, 0x5c, 0x8c, 0x06, 0x57, 0x02, 0x95, 0x5b, 0x4a, 0xf9, - 0x01, 0x7a, 0x51, 0x90, 0x75, 0x06, 0xd1, 0xf2, 0x6e, 0x05, 0x3b, 0xe3, 0x57, 0x3e, 0x4a, 0x76, - 0x68, 0xd5, 0xdd, 0x79, 0x29, 0x46, 0x73, 0x00, 0x4a, 0x2f, 0x04, 0xdd, 0x97, 0x88, 0x74, 0x09, - 0x5d, 0xd4, 0x06, 0xd9, 0x81, 0xcf, 0x1d, 0xa8, 0xd6, 0xee, 0xad, 0x84, 0xfa, 0xdc, 0xf3, 0x70, - 0x03, 0xc4, 0xe1, 0x21, 0x5c, 0x17, 0x1e, 0xb1, 0x7f, 0xcd, 0xa9, 0x7f, 0xa3, 0xa3, 0xac, 0x7b, - 0x73, 0xf0, 0x58, 0x34, 0x19, 0x17, 0xad, 0xe5, 0x00, 0x4b, 0xe2, 0xfc, 0xee, 0x57, 0x09, 0x95, - 0x5e, 0x55, 0x39, 0x79, 0x69, 0x74, 0xed, 0xae, 0x98, 0x8b, 0x8b, 0xdb, 0x34, 0x3e, 0x41, 0xa3, - 0xe5, 0x2b, 0xda, 0x18, 0xbe, 0x85, 0x47, 0x10, 0xee, 0x12, 0xe6, 0x7f, 0x6d, 0x36, 0x84, 0xa4, - 0xec, 0xa8, 0x8c, 0x94, 0x6f, 0xa4, 0x93, 0xf9, 0x63, 0x9d, 0x22, 0xbb, 0xab, 0x1a, 0x00, 0x08, - 0xdf, 0x04, 0xa1, 0xaf, 0xfb, 0x12, 0xa1, 0xc7, 0xba, 0x2f, 0x11, 0x23, 0x01, 0x74, 0xa4, 0x02, - 0x1f, 0xee, 0xc8, 0x9a, 0x2b, 0xc1, 0x9e, 0xf2, 0xc4, 0x1b, 0x12, 0x8c, 0x22, 0x06, 0x9c, 0x2b, - 0x1c, 0x1a, 0x48, 0x61, 0xa0, 0x4f, 0xe8, 0xad, 0xb9, 0x64, 0xe9, 0x48, 0xf3, 0x79, 0xa2, 0x2f, - 0xd6, 0xa5, 0x4b, 0xb5, 0x92, 0x07, 0x03, 0x69, 0x16, 0xf6, 0x33, 0x81, 0x69, 0x2a, 0x3a, 0x94, - 0x9d, 0xa2, 0x73, 0xeb, 0x5e, 0x17, 0xa7, 0x56, 0xd0, 0x1f, 0x2e, 0xd5, 0xa3, 0xe7, 0x67, 0x67, - 0xc7, 0x67, 0x1f, 0x5e, 0x1d, 0xa1, 0xed, 0x25, 0x40, 0xa9, 0x46, 0x66, 0xd6, 0x58, 0x9a, 0x46, - 0x63, 0x4d, 0x07, 0x70, 0x33, 0xf9, 0xe6, 0xda, 0x2b, 0x3d, 0xc0, 0xb4, 0xbb, 0x50, 0x0c, 0x18, - 0xce, 0x7c, 0xcc, 0x67, 0x1e, 0xc9, 0x94, 0x04, 0xdf, 0xfb, 0x62, 0xfb, 0xc6, 0x16, 0x6d, 0xf8, - 0x6f, 0xfb, 0x16, 0xfe, 0xc2, 0x7f, 0xdb, 0xbf, 0xc2, 0x5f, 0x20, 0x8b, 0x97, 0x2a, 0xc3, 0x45, - 0x9f, 0x2b, 0x17, 0x55, 0x90, 0x35, 0xba, 0x74, 0x82, 0x1a, 0xcf, 0x98, 0x14, 0x46, 0x58, 0x6a, - 0x06, 0xc4, 0xbc, 0x2b, 0x94, 0x31, 0x43, 0x92, 0x08, 0x01, 0x8b, 0xb8, 0xb1, 0x71, 0x87, 0x34, - 0x2c, 0x6e, 0xdf, 0x6c, 0x30, 0x86, 0x57, 0x00, 0x7c, 0xd9, 0x20, 0xa8, 0x61, 0x92, 0x32, 0xb4, - 0xcc, 0x1a, 0xb8, 0xc5, 0xa0, 0x0c, 0x67, 0x74, 0x7d, 0x5a, 0x97, 0x7e, 0x63, 0xb3, 0x3e, 0x63, - 0x07, 0x30, 0x66, 0x33, 0xcb, 0x8d, 0x84, 0x05, 0x35, 0xc3, 0xf9, 0x75, 0xcd, 0x70, 0xb4, 0xd4, - 0x1a, 0x30, 0xa2, 0x17, 0x31, 0xfa, 0x2a, 0x10, 0x7f, 0xf8, 0xbe, 0xcf, 0x04, 0xf1, 0xee, 0xf5, - 0x6b, 0x16, 0x48, 0x60, 0x63, 0x04, 0x09, 0x80, 0x1c, 0xf7, 0xae, 0x87, 0xa7, 0x5a, 0x82, 0xd0, - 0xaf, 0x8c, 0x72, 0x8a, 0xf1, 0xa3, 0x52, 0x5c, 0x75, 0x27, 0xb8, 0x51, 0xca, 0x3e, 0x75, 0x54, - 0xb7, 0x29, 0x38, 0x3a, 0xf3, 0x91, 0x15, 0xbe, 0x8c, 0x53, 0x8c, 0xd2, 0x46, 0x2e, 0x37, 0x8a, - 0x81, 0xed, 0x81, 0xc8, 0x1c, 0xe6, 0xc4, 0xe0, 0x90, 0x00, 0x09, 0xf2, 0x34, 0x9e, 0x67, 0x66, - 0xdc, 0x42, 0x77, 0x83, 0x01, 0xa9, 0xbc, 0x20, 0x4b, 0x46, 0xf4, 0xfe, 0xf8, 0xec, 0xe5, 0x77, - 0x9f, 0x31, 0x24, 0x50, 0x39, 0xd1, 0x70, 0xc1, 0x45, 0xb7, 0x31, 0xe5, 0x08, 0x4f, 0xb4, 0x9c, - 0xb8, 0xff, 0xe3, 0xff, 0xa4, 0x5c, 0x42, 0xf8, 0xfe, 0x01, 0xfd, 0x9d, 0xe1, 0xb9, 0x3b, 0xee, - 0xeb, 0x6b, 0x10, 0x87, 0xc6, 0xb7, 0x52, 0xb0, 0x6a, 0x13, 0x0e, 0x52, 0x75, 0x44, 0xda, 0x1d, - 0xe1, 0xea, 0xd0, 0x7a, 0x46, 0xf4, 0xd1, 0xec, 0x76, 0x9e, 0x74, 0x3b, 0x20, 0x11, 0x75, 0x98, - 0xdf, 0xbe, 0x4f, 0x31, 0xb7, 0xde, 0x02, 0xce, 0x07, 0x52, 0x57, 0xef, 0x8a, 0x72, 0x4e, 0x74, - 0x86, 0xb2, 0xa6, 0x8b, 0x41, 0x84, 0xf6, 0x01, 0xa4, 0x12, 0xe5, 0xad, 0x46, 0xd6, 0x01, 0x5c, - 0xe2, 0x22, 0x92, 0x00, 0x69, 0x10, 0x65, 0x67, 0x9b, 0xe8, 0x38, 0x0a, 0x78, 0x25, 0x3f, 0xff, - 0xee, 0x98, 0xe6, 0x95, 0xc5, 0xa7, 0xeb, 0x34, 0x86, 0x35, 0x02, 0x62, 0x7e, 0x6b, 0xa3, 0x36, - 0x69, 0x22, 0x55, 0xa3, 0xc4, 0xaa, 0x96, 0xb7, 0xba, 0x44, 0xcf, 0xe7, 0x70, 0x95, 0x92, 0xf5, - 0x9d, 0xcc, 0x79, 0x65, 0xbe, 0xc5, 0x28, 0x9d, 0xd1, 0xcf, 0x28, 0x5b, 0x73, 0x19, 0x20, 0x82, - 0xa6, 0xc9, 0xcb, 0xde, 0x72, 0x1a, 0xa1, 0xf2, 0x7b, 0x12, 0xce, 0x2f, 0x30, 0x93, 0x32, 0x88, - 0xb7, 0x9e, 0x9f, 0x84, 0xf1, 0x6d, 0x69, 0x31, 0xe1, 0x4d, 0x16, 0xd7, 0x64, 0xce, 0xb6, 0x7f, - 0x10, 0xaf, 0x43, 0xa0, 0x5d, 0x19, 0xce, 0x2f, 0x4c, 0x6f, 0xd1, 0x90, 0x3c, 0x3d, 0x6c, 0xd6, - 0x67, 0x73, 0x83, 0xb2, 0x8a, 0xf7, 0x2a, 0x06, 0xce, 0x82, 0x1f, 0x14, 0x9d, 0xa0, 0xa1, 0x65, - 0x74, 0x7a, 0x35, 0x2b, 0x8e, 0x0a, 0x90, 0x87, 0x38, 0x9d, 0x27, 0xc5, 0x61, 0x01, 0x96, 0x11, - 0x35, 0x0c, 0x70, 0xdf, 0xb5, 0x2d, 0xcc, 0x00, 0x5a, 0x8e, 0xcc, 0xa1, 0x23, 0x15, 0xf2, 0x19, - 0x68, 0x47, 0x59, 0xdc, 0x3d, 0x20, 0x71, 0x75, 0x1e, 0x02, 0x85, 0x50, 0xd8, 0x21, 0xe0, 0xdd, - 0x00, 0xed, 0x53, 0x41, 0x56, 0xa2, 0x23, 0xf3, 0x31, 0x30, 0x16, 0x13, 0x6d, 0x31, 0x4b, 0x52, - 0xd6, 0x93, 0x55, 0x93, 0x43, 0xc0, 0xb1, 0x5b, 0xd2, 0x78, 0x4a, 0x11, 0x4d, 0xdc, 0xa2, 0x13, - 0xcc, 0x2e, 0xc4, 0x94, 0xb3, 0xe3, 0xcb, 0x3e, 0x73, 0xd7, 0x4a, 0xf3, 0x8f, 0xec, 0x6a, 0x11, - 0x66, 0xa3, 0x63, 0xaf, 0x5f, 0x41, 0xdd, 0xb5, 0x9b, 0x64, 0x0a, 0x0e, 0xc6, 0x8a, 0x71, 0x23, - 0x0a, 0x89, 0x6e, 0xe9, 0xa4, 0x83, 0x4e, 0x26, 0xee, 0x75, 0x24, 0x35, 0x19, 0x69, 0xc3, 0xec, - 0x2a, 0xe7, 0x06, 0x19, 0xbc, 0x0a, 0x94, 0xa3, 0x36, 0x1b, 0xc1, 0xc2, 0x2f, 0x14, 0x9d, 0x19, - 0xf2, 0xe5, 0x91, 0x0f, 0x65, 0x64, 0x7c, 0x1a, 0xaf, 0x4c, 0x0c, 0x18, 0xbd, 0xc0, 0x23, 0x8d, - 0x80, 0x7f, 0x1a, 0x17, 0x9f, 0x3a, 0x65, 0x6b, 0x28, 0x90, 0xd1, 0xe9, 0xab, 0x16, 0x8b, 0xf7, - 0x7c, 0x81, 0xb4, 0xb2, 0xfa, 0xa9, 0xf8, 0xb3, 0x2a, 0xc2, 0x8e, 0x91, 0x9a, 0x5f, 0x62, 0x78, - 0xa1, 0xbc, 0xc2, 0x8e, 0x23, 0xd9, 0x99, 0x42, 0xc8, 0x93, 0x17, 0x2f, 0xee, 0xe8, 0xaf, 0x8e, - 0xce, 0x8e, 0x5e, 0x9e, 0x95, 0xfb, 0x39, 0x9a, 0x0e, 0x7e, 0x00, 0x26, 0x91, 0xa2, 0xbd, 0xaa, - 0x87, 0xaa, 0x00, 0xbc, 0x38, 0x7d, 0x7e, 0x42, 0x09, 0x9e, 0xe2, 0x88, 0xa3, 0x87, 0x70, 0x8e, - 0xf3, 0xf8, 0xc2, 0x27, 0x6b, 0x09, 0x67, 0x27, 0x54, 0x33, 0x86, 0xf8, 0x51, 0x12, 0x6a, 0x26, - 0xad, 0x77, 0x06, 0x72, 0x7f, 0xb4, 0x32, 0x18, 0xf1, 0x0d, 0x3a, 0x0c, 0x99, 0xdb, 0x87, 0x95, - 0x58, 0x01, 0x7d, 0x5c, 0x68, 0x4d, 0xe3, 0x50, 0x01, 0x72, 0x8c, 0xc8, 0x59, 0x23, 0xf7, 0x63, - 0x19, 0x1c, 0xf0, 0xb1, 0x6b, 0xf7, 0x5a, 0x6c, 0x5f, 0x36, 0xa7, 0x1e, 0xcd, 0x30, 0x7b, 0x55, - 0x1f, 0x89, 0x0e, 0x3e, 0x9a, 0x65, 0xc7, 0xf1, 0x1c, 0x65, 0xad, 0x37, 0xa7, 0xe2, 0x38, 0xfe, - 0xb0, 0x31, 0xd0, 0xfd, 0x55, 0x40, 0xfd, 0xfc, 0x6f, 0x18, 0xcb, 0x01, 0x60, 0x8b, 0x35, 0x2c, - 0x72, 0x37, 0x11, 0xdb, 0x92, 0xba, 0x38, 0x98, 0x5d, 0xc6, 0x7b, 0x60, 0x03, 0x07, 0x7b, 0x5d, - 0xb9, 0x77, 0x93, 0x3e, 0x2d, 0x6d, 0xf9, 0x92, 0xec, 0x89, 0x30, 0x90, 0x0a, 0x46, 0x78, 0xd0, - 0xb4, 0x88, 0xaa, 0x03, 0xb1, 0x68, 0x77, 0x47, 0x34, 0x0f, 0x87, 0x07, 0x7b, 0x35, 0x9c, 0x93, - 0x0d, 0xa6, 0xaa, 0x79, 0x36, 0xb9, 0x8c, 0x81, 0x52, 0x73, 0x24, 0x3d, 0xb3, 0xaf, 0xdf, 0x51, - 0xde, 0xc2, 0x35, 0x9d, 0xe5, 0xe4, 0x86, 0xdc, 0xdb, 0xdd, 0xfd, 0x9d, 0xff, 0x4d, 0xbd, 0x55, - 0x86, 0x28, 0xc9, 0x19, 0x90, 0x61, 0x17, 0xb6, 0xa9, 0x4d, 0x58, 0x42, 0xe7, 0xf4, 0xd5, 0x3f, - 0xe9, 0xd1, 0x77, 0x4b, 0xf9, 0x4f, 0x10, 0xc1, 0xa6, 0x79, 0x2c, 0x63, 0x6c, 0xe4, 0x16, 0x41, - 0xef, 0x28, 0x64, 0x03, 0x56, 0x51, 0x0f, 0x47, 0xc4, 0x01, 0x36, 0x6f, 0x95, 0xda, 0xe8, 0xc9, - 0xc0, 0x11, 0x87, 0x96, 0x8c, 0x16, 0x7d, 0xb3, 0x5e, 0xcf, 0x95, 0xcd, 0xc6, 0xe4, 0x54, 0x7d, - 0x95, 0x82, 0xec, 0xcd, 0x6f, 0xc8, 0x3c, 0x40, 0x6b, 0xa5, 0xd8, 0x54, 0x94, 0xa7, 0x55, 0x0a, - 0xde, 0x86, 0x47, 0x96, 0xf4, 0x2e, 0x59, 0xaf, 0x30, 0x9e, 0x49, 0x0e, 0xb5, 0x7e, 0xe9, 0xaf, - 0xb3, 0xbd, 0xc8, 0xe3, 0xcc, 0x0b, 0x7a, 0x6e, 0x79, 0xf6, 0x39, 0x8e, 0x4a, 0x2d, 0x64, 0x05, - 0x04, 0x2f, 0x48, 0x29, 0x46, 0xab, 0xa8, 0x56, 0x49, 0x14, 0xa1, 0xab, 0x4d, 0xf9, 0x6c, 0x35, - 0x2c, 0x0a, 0x97, 0xcd, 0x0d, 0x70, 0x45, 0x5e, 0x6f, 0xc1, 0x1f, 0x81, 0xe5, 0x03, 0x4f, 0x7d, - 0xf3, 0xfe, 0xe8, 0xdb, 0xf6, 0xd9, 0x69, 0x0b, 0xad, 0x04, 0x78, 0xd0, 0x5f, 0x34, 0x01, 0xcd, - 0xba, 0xa2, 0x9a, 0xaf, 0x1e, 0xb6, 0x0c, 0x54, 0x2d, 0x9b, 0xe1, 0x93, 0x0b, 0x14, 0x85, 0xc4, - 0x31, 0x7f, 0xa2, 0x09, 0x2a, 0x26, 0x46, 0xc0, 0x76, 0x5b, 0x36, 0x9f, 0xae, 0x6c, 0xaa, 0xbd, - 0x0f, 0x5e, 0xf6, 0xe4, 0xcb, 0xb6, 0x72, 0x87, 0xc3, 0x2b, 0x8e, 0x6c, 0x43, 0xb7, 0x6f, 0x6b, - 0x75, 0xdb, 0xee, 0xcd, 0x29, 0x07, 0x79, 0x91, 0xa9, 0x22, 0x8f, 0xdb, 0x1c, 0xef, 0xa7, 0x1f, - 0xa9, 0x27, 0xf9, 0xe7, 0xad, 0x19, 0x0c, 0x86, 0x7b, 0x45, 0x21, 0x0b, 0x15, 0x03, 0xdd, 0xa5, - 0x78, 0x45, 0x0d, 0xf6, 0x9b, 0x17, 0x6b, 0xc1, 0xce, 0x80, 0x36, 0x64, 0x52, 0x83, 0xe5, 0x80, - 0xf7, 0x0d, 0xc0, 0x65, 0x78, 0x9c, 0x71, 0xbe, 0x1a, 0xc7, 0xdd, 0xaa, 0x86, 0xca, 0x31, 0x54, - 0x66, 0x27, 0x18, 0x46, 0x22, 0x3f, 0x53, 0xc8, 0x32, 0x45, 0xbd, 0xd3, 0x21, 0x57, 0x1d, 0x7d, - 0x2a, 0xb8, 0xb7, 0xa0, 0x03, 0x52, 0xf4, 0x6b, 0x5a, 0x62, 0x4f, 0x32, 0x43, 0x2b, 0x1b, 0x91, - 0x26, 0x50, 0x72, 0xc9, 0x6f, 0xdc, 0x46, 0x19, 0x82, 0x57, 0xd3, 0xce, 0xca, 0xa8, 0xbc, 0x62, - 0x64, 0x0f, 0x68, 0xad, 0x8c, 0x07, 0xd0, 0x0a, 0x79, 0x9b, 0xc7, 0x06, 0xa0, 0xdc, 0x48, 0x21, - 0xd9, 0x73, 0xad, 0x45, 0xbd, 0x31, 0x6b, 0xeb, 0xbe, 0x08, 0x8a, 0x3f, 0x7a, 0xfb, 0xe1, 0x8d, - 0x8a, 0x88, 0xaf, 0x04, 0x83, 0x7e, 0xb4, 0xc6, 0xa3, 0xd4, 0xb2, 0xad, 0x2b, 0xfa, 0xd7, 0xe5, - 0x3f, 0x18, 0xd6, 0x69, 0x7d, 0xb2, 0x6b, 0x63, 0xdc, 0x3e, 0x5a, 0x14, 0x49, 0x6e, 0x71, 0x60, - 0x18, 0x16, 0x66, 0x5f, 0x0e, 0xfc, 0xe2, 0xa0, 0x30, 0xfc, 0x46, 0x31, 0x6a, 0xf4, 0x03, 0x44, - 0x63, 0xf8, 0x5b, 0x44, 0xab, 0xc1, 0x6f, 0x8e, 0x57, 0xa3, 0x8f, 0x20, 0x2b, 0xc1, 0xdf, 0x49, - 0x72, 0xa5, 0x37, 0x56, 0x04, 0x58, 0xa9, 0x96, 0x50, 0x76, 0x96, 0x7f, 0x28, 0x6e, 0x08, 0x7e, - 0x97, 0x41, 0x35, 0xe5, 0xc3, 0x7e, 0x57, 0x7b, 0x78, 0x54, 0x7e, 0xd9, 0x29, 0x7e, 0xed, 0x16, - 0xbf, 0xf6, 0x6e, 0xa8, 0x45, 0xd3, 0x57, 0xf2, 0xd1, 0xca, 0xbc, 0x4b, 0x28, 0xc1, 0x4e, 0x82, - 0xb2, 0x80, 0x8a, 0x57, 0xfe, 0x68, 0xa1, 0x3d, 0x19, 0x0b, 0xa8, 0x98, 0x61, 0x2a, 0x63, 0x58, - 0x31, 0xa1, 0xcf, 0xc9, 0x3c, 0xc3, 0x51, 0x8e, 0x41, 0x18, 0xb7, 0xc8, 0x82, 0x29, 0xff, 0xce, - 0xa9, 0x74, 0x85, 0xb1, 0x7d, 0xb4, 0x30, 0xd6, 0xdc, 0x42, 0x96, 0xa5, 0x7f, 0x9e, 0xc9, 0x06, - 0x19, 0x01, 0x32, 0xe8, 0xd8, 0xb6, 0x70, 0x8e, 0xe5, 0x1f, 0x39, 0xd5, 0x54, 0xa9, 0x36, 0x24, - 0xe4, 0xa3, 0x95, 0xe6, 0x89, 0xf5, 0x49, 0xa3, 0x02, 0x20, 0x82, 0x17, 0x47, 0x27, 0xe7, 0xcf, - 0xcf, 0xce, 0x4e, 0x2a, 0xc4, 0x50, 0x8d, 0xd9, 0xbc, 0x83, 0x09, 0xe8, 0x5b, 0xb0, 0xdc, 0x81, - 0x7d, 0xf4, 0x2d, 0xb4, 0x95, 0x59, 0x36, 0xba, 0xd1, 0xe0, 0xb7, 0x75, 0x6f, 0x2f, 0x09, 0xb8, - 0xe4, 0x4a, 0x3d, 0x59, 0x69, 0x67, 0x7f, 0xbf, 0xb6, 0x8e, 0x0c, 0xf3, 0xab, 0xb4, 0xa0, 0x8a, - 0x76, 0x9d, 0xee, 0x42, 0xe9, 0x7f, 0x5e, 0x53, 0x5a, 0x1b, 0xe1, 0xab, 0x77, 0x1f, 0x5e, 0xbc, - 0x3e, 0x3a, 0xff, 0xe6, 0xf8, 0xe8, 0xf5, 0xab, 0x53, 0xed, 0x78, 0xc8, 0xc7, 0xc5, 0x40, 0x5b, - 0xbb, 0xea, 0xec, 0x5b, 0x64, 0x04, 0xd5, 0x4e, 0x57, 0xbb, 0xb5, 0xf5, 0xa9, 0x3c, 0x76, 0x72, - 0x0a, 0x5b, 0xed, 0xf1, 0xbb, 0xb7, 0xd8, 0x28, 0x34, 0x76, 0x17, 0x78, 0x7d, 0x79, 0x86, 0xc3, - 0xb2, 0xe9, 0xb6, 0x93, 0xbe, 0x75, 0x2a, 0x1f, 0x2f, 0xfd, 0xdb, 0x0c, 0x49, 0xcd, 0x3c, 0x98, - 0x62, 0x2f, 0x39, 0x5d, 0x62, 0x57, 0x8f, 0x82, 0x7c, 0x02, 0xec, 0x48, 0xf8, 0xc4, 0xe4, 0x4a, - 0xf8, 0xf2, 0x51, 0xc1, 0xd7, 0x8f, 0x79, 0xd8, 0xc6, 0x79, 0x8c, 0x12, 0x04, 0x90, 0x77, 0x51, - 0xff, 0xf8, 0xf4, 0x7d, 0x51, 0xd9, 0x3c, 0x51, 0x61, 0x1b, 0xe7, 0x20, 0xec, 0xc5, 0x73, 0x0b, - 0xb6, 0xb1, 0x4e, 0x6c, 0x2d, 0x12, 0xdf, 0x36, 0x97, 0x98, 0xad, 0x39, 0xf4, 0xec, 0xaa, 0x9b, - 0xcc, 0xae, 0x73, 0xff, 0x60, 0x5f, 0xb9, 0xab, 0x18, 0x0b, 0x58, 0x76, 0x96, 0x9f, 0x54, 0x77, - 0xf5, 0xd0, 0x7c, 0x5b, 0x0f, 0xb6, 0xb7, 0xcd, 0x00, 0xfa, 0x02, 0x1a, 0xcf, 0x63, 0x01, 0xee, - 0x07, 0x7c, 0x2c, 0xc0, 0x99, 0x1c, 0xd2, 0xd6, 0xe3, 0xd9, 0x6d, 0x23, 0x12, 0xdd, 0xae, 0xc6, - 0x8a, 0xdb, 0x0b, 0x54, 0x56, 0x8d, 0xbd, 0xb6, 0x97, 0x2c, 0x39, 0xbb, 0x76, 0x4d, 0xd9, 0x35, - 0x0c, 0xd8, 0xae, 0x10, 0xa5, 0x49, 0x93, 0x76, 0x95, 0x8b, 0x16, 0x43, 0x56, 0x4c, 0xa2, 0x18, - 0xf4, 0xbb, 0xe2, 0x85, 0x1c, 0xf7, 0x42, 0x5c, 0x9c, 0xbd, 0x10, 0xbe, 0x66, 0xd7, 0xf2, 0x1a, - 0x7b, 0x69, 0x14, 0x99, 0xbd, 0x24, 0x56, 0xcb, 0x5e, 0x17, 0x55, 0x65, 0xd7, 0x45, 0x22, 0xd9, - 0xf5, 0xb1, 0x3e, 0xc5, 0x10, 0x8b, 0x18, 0x8f, 0x62, 0x8c, 0xaf, 0xca, 0x37, 0x72, 0x90, 0x8b, - 0x31, 0x3d, 0xf6, 0x92, 0xc8, 0x19, 0xbb, 0x1a, 0xbb, 0x62, 0xd7, 0x06, 0x91, 0x14, 0xad, 0x53, - 0x3f, 0x8b, 0x96, 0x9f, 0xf3, 0x93, 0x6c, 0xd5, 0x74, 0xf5, 0xd9, 0xc6, 0x9e, 0x61, 0x2f, 0x3a, - 0xf0, 0xec, 0xaa, 0xbb, 0xcd, 0x36, 0x3d, 0x5a, 0xb6, 0x1e, 0x3b, 0x52, 0x74, 0x00, 0xf7, 0x51, - 0xd5, 0xfc, 0x37, 0xef, 0x7f, 0x28, 0x1a, 0xaf, 0x84, 0x86, 0xd8, 0x5a, 0xec, 0x86, 0x6d, 0xc6, - 0x55, 0xd8, 0x55, 0x9e, 0x58, 0x8d, 0x56, 0xd0, 0x96, 0xe3, 0xbc, 0x5c, 0x8c, 0x6f, 0x3e, 0x68, - 0x4b, 0x71, 0xae, 0x0d, 0xd3, 0xf4, 0x50, 0xd9, 0x86, 0x6f, 0xc9, 0x5e, 0x74, 0x0c, 0xd9, 0x8b, - 0xde, 0x1d, 0xdb, 0xf0, 0xc7, 0xd8, 0x55, 0x37, 0x4a, 0x89, 0x7c, 0x69, 0x47, 0x2c, 0xf1, 0x5f, - 0xbc, 0x50, 0x53, 0x50, 0xf5, 0x8a, 0xd8, 0x8b, 0x7e, 0x0a, 0xbb, 0xc6, 0xec, 0x6f, 0xd7, 0xdb, - 0xce, 0xed, 0x25, 0x16, 0x68, 0xbb, 0xc6, 0xd2, 0x6b, 0xd7, 0x9a, 0x56, 0xed, 0x7a, 0xe3, 0x67, - 0x49, 0xcd, 0xa4, 0xeb, 0x95, 0xa4, 0xac, 0x54, 0xbf, 0x92, 0x94, 0x4d, 0x53, 0xa7, 0x5d, 0xb1, - 0xfc, 0xd9, 0x8b, 0xe6, 0x36, 0xbb, 0x6a, 0x50, 0xb2, 0x6b, 0x2c, 0x31, 0x76, 0xc5, 0x7c, 0x62, - 0x2f, 0x58, 0x3e, 0xec, 0x45, 0xfb, 0x82, 0x5d, 0xab, 0xc4, 0xdb, 0xf5, 0x1a, 0xb7, 0xad, 0x6b, - 0xc4, 0xc5, 0x78, 0x79, 0xf7, 0x2d, 0xc6, 0x5b, 0xa8, 0x62, 0xc5, 0x78, 0x2b, 0x1a, 0xaa, 0x6d, - 0x08, 0x4b, 0x76, 0x45, 0xb2, 0xb2, 0x75, 0x75, 0xd4, 0xae, 0x51, 0xb5, 0x6c, 0x53, 0x45, 0xb2, - 0xab, 0x8a, 0x8d, 0xad, 0xeb, 0x1e, 0xf6, 0x82, 0x6c, 0x50, 0x91, 0xe3, 0x3f, 0xdd, 0x6f, 0x7d, - 0x1a, 0xe8, 0x47, 0x70, 0xf1, 0x26, 0x96, 0xa9, 0x1f, 0xa2, 0x59, 0x4d, 0x3f, 0x88, 0xeb, 0x66, - 0xb7, 0xd1, 0x58, 0x4c, 0xe6, 0x11, 0x6b, 0xff, 0x6e, 0x12, 0x34, 0xd1, 0x4f, 0xdb, 0xba, 0xc3, - 0x03, 0xc4, 0x2c, 0x4a, 0x60, 0xa8, 0x8f, 0x7b, 0xed, 0x62, 0x82, 0x0a, 0x8c, 0xee, 0xe0, 0xef, - 0x03, 0xfc, 0x9e, 0xfa, 0xf9, 0x3c, 0x8d, 0x44, 0x4a, 0x49, 0x11, 0xe8, 0xcc, 0xeb, 0xfd, 0xd6, - 0x56, 0x01, 0x8b, 0x6e, 0xb8, 0x6a, 0xce, 0xb2, 0x0b, 0x5b, 0xc4, 0x97, 0x43, 0x0c, 0x39, 0xd1, - 0xa1, 0xfa, 0x18, 0x6e, 0xef, 0xc5, 0xe3, 0x39, 0xfa, 0xa6, 0x1d, 0x36, 0xbf, 0x1c, 0x85, 0xe4, - 0xa9, 0x6e, 0x02, 0x5f, 0xbb, 0xb2, 0xb8, 0x09, 0x3f, 0x74, 0xe8, 0x04, 0xb3, 0x3a, 0xdf, 0x4b, - 0x40, 0x85, 0x25, 0xb6, 0x45, 0x33, 0xbe, 0x14, 0xcf, 0xe4, 0x8b, 0x76, 0x7c, 0x69, 0x89, 0xbe, - 0x7a, 0xf0, 0xd3, 0xb4, 0xac, 0x8d, 0x09, 0x2f, 0x5e, 0xca, 0x3b, 0xb3, 0x40, 0x33, 0xca, 0x2e, - 0xe8, 0x43, 0xd1, 0xf0, 0x85, 0x9f, 0xcb, 0x56, 0x5f, 0xdc, 0x1e, 0x7b, 0x4d, 0x86, 0x90, 0x59, - 0x2d, 0x07, 0x2f, 0x98, 0x8d, 0xbc, 0x97, 0xd3, 0x20, 0xf4, 0x9a, 0x7e, 0xc8, 0xe0, 0x32, 0x3f, - 0x3f, 0x0b, 0x66, 0x3e, 0x30, 0xfd, 0x66, 0xb3, 0x25, 0x86, 0x87, 0x08, 0x3f, 0xf5, 0x67, 0xc0, - 0x81, 0x9b, 0xa0, 0x6e, 0xef, 0x62, 0xf0, 0x02, 0xe3, 0xa0, 0x44, 0x3b, 0xdd, 0xc2, 0xa6, 0xe1, - 0xbb, 0xc0, 0x4e, 0x79, 0xdb, 0x58, 0xe0, 0x31, 0x5e, 0x8a, 0x3e, 0x51, 0x7a, 0x8c, 0x53, 0x69, - 0x4c, 0x7d, 0x1e, 0x86, 0x4d, 0xcb, 0x41, 0x8d, 0xa3, 0x85, 0xa4, 0x74, 0xe4, 0xc2, 0x0c, 0x34, - 0x73, 0x3b, 0xa0, 0xf6, 0xef, 0x38, 0x2d, 0x04, 0x63, 0x34, 0xa0, 0x13, 0xc8, 0x1f, 0xcb, 0xcb, - 0xda, 0x6c, 0xba, 0x74, 0xcd, 0xc6, 0x7b, 0xd2, 0x6c, 0xfd, 0x4a, 0xb3, 0x4f, 0x03, 0xae, 0x96, - 0x33, 0x6a, 0x31, 0x49, 0xa1, 0xc3, 0x47, 0x0c, 0x9a, 0x96, 0x8a, 0xe0, 0x43, 0x68, 0x1f, 0x83, - 0x4f, 0x62, 0x38, 0x1c, 0xc2, 0x4f, 0x1e, 0xfe, 0x7d, 0x6b, 0xb0, 0x41, 0x3f, 0x55, 0x22, 0x09, - 0xad, 0xbf, 0x63, 0xec, 0xeb, 0x58, 0x6b, 0x4d, 0x22, 0x4d, 0xb5, 0xd6, 0x6a, 0xad, 0x99, 0x14, - 0x80, 0x6a, 0x6d, 0x43, 0x37, 0x34, 0x10, 0xae, 0xe7, 0x95, 0xf5, 0xa9, 0x7a, 0x30, 0x69, 0x72, - 0x2c, 0xbe, 0x73, 0x0e, 0x83, 0x7d, 0x0f, 0x2c, 0xad, 0x75, 0x27, 0xc6, 0xa1, 0xef, 0x16, 0x0b, - 0x7d, 0xe1, 0xfb, 0x40, 0x54, 0xde, 0xa0, 0x8c, 0x3e, 0x0f, 0xc3, 0x81, 0xb8, 0x67, 0x80, 0x81, - 0x47, 0x18, 0x30, 0x2e, 0x84, 0xbb, 0x23, 0xe4, 0xd5, 0xa4, 0x2f, 0x18, 0xd0, 0x07, 0x98, 0xfb, - 0xd7, 0xe4, 0xef, 0x4b, 0x00, 0x5e, 0x9f, 0x5c, 0x39, 0x32, 0xcb, 0xdb, 0x76, 0x08, 0x1d, 0xb7, - 0x8b, 0x2b, 0x31, 0x70, 0x31, 0xf1, 0x35, 0x64, 0x3e, 0x9f, 0x43, 0x24, 0x8a, 0x70, 0x90, 0x4c, - 0x10, 0xce, 0x62, 0xcf, 0x30, 0x75, 0x8f, 0x1a, 0x09, 0xd3, 0x1f, 0x36, 0x51, 0xf4, 0xe0, 0x94, - 0x1a, 0x41, 0x4a, 0xdc, 0x61, 0x4a, 0x84, 0x19, 0xab, 0x50, 0xa3, 0x96, 0x03, 0x04, 0x28, 0xaf, - 0x96, 0x2e, 0xa1, 0xb9, 0x6f, 0x66, 0x80, 0xf7, 0xdc, 0xcf, 0x9a, 0x11, 0x8d, 0x15, 0xd0, 0x10, - 0x01, 0x16, 0x08, 0x31, 0xe2, 0xb7, 0xdf, 0x44, 0x24, 0x9e, 0x8a, 0x6e, 0x4b, 0x2d, 0x7e, 0x8b, - 0xe3, 0x36, 0xad, 0x41, 0xb1, 0xb2, 0xe7, 0x44, 0x85, 0xc8, 0xc1, 0xfe, 0x09, 0xff, 0x21, 0x5e, - 0xf6, 0x2d, 0xfe, 0x73, 0xf6, 0x02, 0x49, 0x4f, 0x60, 0xa4, 0x9f, 0x08, 0xa0, 0x50, 0x17, 0x1f, - 0xc8, 0xe3, 0x09, 0x0d, 0x1c, 0x0e, 0x29, 0x77, 0xae, 0xf8, 0xcb, 0x5f, 0xe0, 0xdb, 0x53, 0x31, - 0x77, 0x42, 0x3f, 0xba, 0xc8, 0xa7, 0xa2, 0x2d, 0x7a, 0x30, 0x8d, 0x91, 0xe8, 0xf0, 0xf7, 0x81, - 0x08, 0xb6, 0xb7, 0x79, 0x7a, 0x64, 0x07, 0x9a, 0x01, 0x4d, 0x51, 0x17, 0x98, 0x41, 0x04, 0x64, - 0xfc, 0x0d, 0x06, 0x45, 0x35, 0xa1, 0x7f, 0x7d, 0xed, 0xb1, 0xd7, 0x6a, 0x01, 0xc7, 0xb0, 0x88, - 0x6f, 0xcc, 0x81, 0xac, 0x07, 0x06, 0xa3, 0x82, 0x21, 0xbf, 0x70, 0x41, 0xbd, 0x00, 0x16, 0xd3, - 0x4c, 0x68, 0xc8, 0x72, 0x41, 0x41, 0x1f, 0x9b, 0x09, 0x0e, 0xd9, 0x02, 0x62, 0x06, 0xca, 0x03, - 0xf4, 0x83, 0xf6, 0xf2, 0x6e, 0xd2, 0xb4, 0x3a, 0x16, 0xe1, 0x57, 0x76, 0x21, 0xc0, 0xde, 0x63, - 0x07, 0x40, 0x5d, 0x08, 0x41, 0xb2, 0x80, 0x2e, 0x6d, 0x43, 0xb7, 0xa1, 0x0b, 0x45, 0x75, 0x6a, - 0xb1, 0xc2, 0x6c, 0x6b, 0x48, 0x08, 0x1b, 0xcf, 0xd3, 0xdb, 0x3b, 0x6d, 0x59, 0x7f, 0x64, 0xaa, - 0x61, 0x12, 0x02, 0xea, 0x99, 0x5c, 0x7c, 0x2a, 0x18, 0x32, 0xe6, 0x31, 0x06, 0x59, 0x08, 0x65, - 0x56, 0xd0, 0x29, 0x39, 0x01, 0x07, 0xb2, 0x70, 0x6b, 0x31, 0xdb, 0x24, 0x8c, 0x60, 0x8c, 0x66, - 0x21, 0x49, 0x39, 0x38, 0x99, 0x2d, 0x7b, 0x79, 0x15, 0x99, 0xc5, 0x70, 0xe3, 0x5a, 0x4c, 0xd4, - 0x75, 0xc5, 0xa9, 0xf4, 0x27, 0xb9, 0x38, 0xe4, 0x8e, 0xe2, 0x8f, 0x5f, 0x4e, 0x30, 0xb9, 0x43, - 0x13, 0x46, 0x83, 0x33, 0x0e, 0x7f, 0x1c, 0x60, 0xe7, 0xf2, 0x17, 0x5d, 0x42, 0xa5, 0xfd, 0x76, - 0xe4, 0x8a, 0x59, 0x7c, 0xe5, 0x70, 0x67, 0x5b, 0x88, 0x64, 0x4c, 0x08, 0x51, 0x36, 0x41, 0xa7, - 0x1e, 0x86, 0xb2, 0x25, 0xda, 0x91, 0x69, 0x22, 0x34, 0x62, 0x55, 0x25, 0x01, 0xa4, 0x94, 0x44, - 0xa1, 0xfc, 0x57, 0x5f, 0xc9, 0x1a, 0x2a, 0xba, 0x84, 0x0a, 0x2e, 0x65, 0x4c, 0x2a, 0xfb, 0x08, - 0x8c, 0xbb, 0xb2, 0xcf, 0xa0, 0x6b, 0x52, 0x6b, 0x24, 0x8a, 0xe5, 0xbd, 0x1d, 0x18, 0x75, 0x59, - 0x36, 0x08, 0x23, 0xe2, 0x8e, 0x22, 0x8f, 0xd1, 0xad, 0x28, 0x7a, 0xdd, 0x51, 0x1e, 0x71, 0x36, - 0x97, 0xe1, 0xea, 0x8e, 0x14, 0x29, 0x61, 0xac, 0xd6, 0x42, 0xf5, 0x38, 0xd9, 0xac, 0x76, 0x9c, - 0x98, 0x95, 0x31, 0xab, 0xca, 0xba, 0x9a, 0x45, 0xfa, 0x15, 0x55, 0x15, 0x19, 0x86, 0x1a, 0xaf, - 0xe4, 0x96, 0xa2, 0x18, 0x85, 0x53, 0xdc, 0xbf, 0x38, 0x14, 0x28, 0x13, 0x0c, 0xf4, 0xef, 0x71, - 0xb2, 0xec, 0x33, 0xc2, 0xaf, 0xe0, 0x58, 0x17, 0xb7, 0x86, 0xba, 0xb5, 0x51, 0xde, 0xe4, 0xa5, - 0x0b, 0x67, 0x24, 0x7e, 0xf4, 0xd1, 0x2e, 0x4e, 0xc7, 0x82, 0x10, 0x40, 0xae, 0x12, 0x9e, 0x48, - 0x91, 0x89, 0x0f, 0xa3, 0x9e, 0x9c, 0xbd, 0xb7, 0x29, 0x94, 0x5d, 0x66, 0x27, 0xc6, 0x62, 0x78, - 0x6f, 0x91, 0x23, 0x38, 0x51, 0x07, 0x0e, 0x81, 0x5c, 0xdf, 0x08, 0x47, 0xc5, 0x12, 0xa3, 0x03, - 0x2a, 0x8a, 0xa5, 0x3b, 0x15, 0x43, 0x65, 0x40, 0xd2, 0x4a, 0x7d, 0xc7, 0x32, 0x3a, 0xcf, 0x79, - 0x56, 0xf0, 0xc0, 0x25, 0x46, 0xcb, 0xf2, 0xa7, 0x7b, 0x90, 0x20, 0x32, 0x5f, 0xac, 0xc2, 0x91, - 0x56, 0xba, 0x16, 0x49, 0xc6, 0x77, 0xb3, 0xa1, 0x12, 0x7f, 0xf7, 0x6a, 0x5e, 0x90, 0x97, 0x20, - 0xd5, 0xe1, 0x5f, 0x58, 0x71, 0xc5, 0xec, 0xf0, 0x6c, 0x23, 0x3c, 0xfa, 0x82, 0x4b, 0x4c, 0xc1, - 0x5c, 0x39, 0xf7, 0x28, 0xcc, 0x56, 0x69, 0x9f, 0x44, 0xdc, 0xc5, 0xd5, 0xb6, 0x06, 0x12, 0x26, - 0x77, 0x5a, 0x00, 0xa5, 0x6f, 0x46, 0x20, 0xf8, 0x42, 0x91, 0x73, 0x72, 0x0b, 0xb4, 0x36, 0x02, - 0x49, 0x09, 0xa1, 0xd6, 0xc0, 0xa4, 0x32, 0x15, 0xa0, 0x8c, 0x0c, 0xcc, 0x05, 0xb4, 0x8e, 0xf4, - 0xb1, 0x8c, 0x55, 0xd4, 0x03, 0xfc, 0x02, 0xc0, 0x14, 0xd8, 0x3b, 0xb9, 0x12, 0x15, 0x6e, 0x05, - 0x81, 0xaa, 0x12, 0xef, 0xe9, 0x34, 0xbe, 0x46, 0x97, 0x47, 0xe4, 0x5f, 0xfb, 0x52, 0xa2, 0x85, - 0x11, 0x22, 0x05, 0xa9, 0x9d, 0x0f, 0x37, 0x2c, 0x26, 0x29, 0x79, 0x34, 0x82, 0x52, 0x01, 0xea, - 0x59, 0x7a, 0xe4, 0x4c, 0xe3, 0xb1, 0x25, 0xb1, 0x8f, 0xe7, 0xe4, 0x0b, 0x54, 0xcb, 0x36, 0xeb, - 0x68, 0x6e, 0x81, 0xea, 0xaa, 0x65, 0xf5, 0x65, 0x77, 0x6f, 0xa0, 0x24, 0x1f, 0xad, 0x43, 0x08, - 0xf5, 0xd7, 0xaa, 0x60, 0xd2, 0x57, 0xe7, 0x64, 0x56, 0xd5, 0xa4, 0x42, 0x65, 0xcd, 0x7c, 0xe4, - 0xd0, 0x15, 0xb4, 0xdf, 0x9d, 0xbd, 0x79, 0xcd, 0x79, 0x7d, 0x4a, 0x24, 0x7f, 0x65, 0x22, 0x4a, - 0x43, 0xf4, 0xfa, 0x16, 0x1e, 0x46, 0xb1, 0x82, 0xfb, 0xbe, 0x29, 0x1e, 0x2b, 0x85, 0x75, 0x44, - 0x8a, 0x62, 0x76, 0xb3, 0x38, 0x05, 0xf5, 0xc1, 0xb5, 0x47, 0xb4, 0x45, 0x8e, 0x1c, 0x4a, 0xe7, - 0x0d, 0x62, 0x8e, 0xcb, 0xbf, 0x5a, 0x65, 0x0d, 0x10, 0x9f, 0x9b, 0x8c, 0xc1, 0x09, 0x1d, 0xa9, - 0x63, 0x00, 0xda, 0x70, 0x8b, 0x79, 0x49, 0x57, 0xe8, 0x52, 0x79, 0x6a, 0x69, 0x30, 0x51, 0xbc, - 0xd0, 0x31, 0xab, 0x7d, 0x10, 0xc2, 0xaa, 0xcd, 0xfc, 0x4a, 0x19, 0x57, 0x81, 0x3e, 0x97, 0x16, - 0xa5, 0x74, 0x56, 0x4b, 0x4b, 0xad, 0xaf, 0x9f, 0xc6, 0xd7, 0xc0, 0xd8, 0x30, 0x8f, 0xd5, 0xca, - 0xdc, 0x61, 0xc2, 0x0b, 0x1b, 0x87, 0xaf, 0x8a, 0xd4, 0xdd, 0x32, 0x43, 0xd8, 0x22, 0xe0, 0xd5, - 0x40, 0xb4, 0x4b, 0x89, 0x6b, 0x2f, 0xaf, 0xe5, 0x1c, 0xdb, 0x05, 0x78, 0xee, 0x7c, 0x05, 0x7f, - 0x63, 0xd4, 0x0a, 0x53, 0x3f, 0xfa, 0xd8, 0xfd, 0x54, 0xa1, 0xa4, 0x09, 0x59, 0xe6, 0x96, 0x15, - 0xef, 0x7d, 0x5a, 0xc1, 0x8b, 0x26, 0x64, 0xc3, 0x6d, 0x2d, 0xab, 0xbb, 0xb3, 0xd8, 0x14, 0x53, - 0xce, 0x33, 0xf2, 0x2a, 0xbc, 0x82, 0x29, 0x6f, 0xaa, 0x57, 0x7f, 0xa5, 0x70, 0x62, 0xa0, 0xf2, - 0xf8, 0x35, 0x9e, 0x19, 0xf3, 0x4f, 0x73, 0x3c, 0xa2, 0xd2, 0x44, 0x81, 0x74, 0x91, 0xc2, 0xa9, - 0x19, 0x43, 0x95, 0x03, 0x3d, 0xce, 0x43, 0xbe, 0x29, 0x53, 0xb5, 0xa1, 0x9c, 0x26, 0xb5, 0x4d, - 0x1d, 0xd1, 0x52, 0x3f, 0xa1, 0xd3, 0x5a, 0xe8, 0x98, 0x9d, 0x82, 0x38, 0x8b, 0x2b, 0x75, 0x6d, - 0x1a, 0x77, 0x64, 0x75, 0x7c, 0xb6, 0xe4, 0xc3, 0xc9, 0x31, 0x86, 0x5b, 0xc5, 0x11, 0x12, 0x2a, - 0xa3, 0xce, 0x18, 0xff, 0xfd, 0x9a, 0x5e, 0xa6, 0xb3, 0x9a, 0x5e, 0x42, 0xbb, 0x3c, 0x87, 0x75, - 0x10, 0x81, 0xad, 0xe8, 0x8a, 0x7d, 0x9e, 0x6a, 0x5f, 0xef, 0x0d, 0x9e, 0x57, 0x59, 0xdc, 0x9b, - 0x70, 0xbd, 0x25, 0x1c, 0x4b, 0x0a, 0xa4, 0x19, 0x09, 0xbc, 0xc6, 0x06, 0xec, 0x93, 0x1f, 0xdf, - 0x78, 0x72, 0x66, 0x7e, 0x96, 0xb9, 0x17, 0x3e, 0x89, 0xb4, 0xd6, 0x84, 0x93, 0x6b, 0x81, 0x0c, - 0x42, 0xf5, 0x34, 0x69, 0xbe, 0xe0, 0x93, 0xa5, 0x91, 0x85, 0x78, 0x53, 0x4b, 0xdf, 0xf0, 0xeb, - 0x2c, 0x2d, 0x75, 0xfd, 0x2f, 0xd5, 0x68, 0xc9, 0x61, 0x65, 0x56, 0x72, 0xe8, 0x19, 0xff, 0x92, - 0xc2, 0xb9, 0x7c, 0x40, 0xe9, 0xa0, 0xe0, 0x42, 0x45, 0x69, 0x96, 0xcb, 0x65, 0xf2, 0xf2, 0x92, - 0x54, 0xa4, 0x1c, 0xc9, 0xe6, 0x1b, 0x5d, 0xd3, 0xd2, 0x6b, 0x49, 0x93, 0x92, 0x59, 0x87, 0x8f, - 0xe0, 0x83, 0x2e, 0xf9, 0xa9, 0xfc, 0x02, 0xad, 0xe1, 0x89, 0x51, 0x0c, 0x52, 0xd7, 0xaa, 0xcb, - 0x0c, 0x2a, 0x24, 0x45, 0x47, 0x14, 0xc6, 0x6e, 0xb5, 0xb8, 0xba, 0x93, 0xcc, 0xb3, 0x69, 0xb3, - 0xa6, 0x2c, 0x6d, 0xae, 0xf4, 0x53, 0xe7, 0x8e, 0xf5, 0xe0, 0xf9, 0x80, 0xf9, 0x52, 0xe8, 0xfa, - 0x22, 0x5e, 0xa8, 0xd6, 0x5a, 0x0b, 0x5d, 0x5d, 0x78, 0x61, 0x34, 0x50, 0xc1, 0x76, 0x59, 0xe8, - 0x10, 0xf5, 0x4a, 0xad, 0x71, 0x0b, 0xbe, 0x90, 0xf0, 0x50, 0x57, 0x7a, 0x01, 0xa5, 0x98, 0xac, - 0x8d, 0xce, 0x69, 0x61, 0x7d, 0x29, 0x66, 0x3c, 0x83, 0xea, 0xa2, 0xa9, 0x40, 0x64, 0xce, 0xcf, - 0x71, 0x10, 0x35, 0x2d, 0x5b, 0x58, 0xa4, 0x32, 0xb7, 0xc8, 0xae, 0xa6, 0x6f, 0x88, 0x55, 0x93, - 0x5a, 0x93, 0xe6, 0x16, 0xa0, 0xdc, 0x96, 0x92, 0x0a, 0x42, 0xa3, 0xd7, 0x7d, 0x7a, 0x4d, 0xa0, - 0xb0, 0x6d, 0x03, 0x8c, 0x61, 0xd7, 0xa3, 0xfc, 0x99, 0x91, 0xb5, 0x74, 0x6b, 0x55, 0x8a, 0xa3, - 0x9b, 0xc5, 0x91, 0x1c, 0x41, 0x31, 0x5a, 0x90, 0x88, 0xcf, 0xf9, 0xcb, 0x8a, 0x6e, 0xca, 0xaa, - 0x80, 0x57, 0xf9, 0xeb, 0x2b, 0x42, 0x37, 0xf0, 0x1e, 0xab, 0xfa, 0x52, 0xfa, 0xd2, 0x71, 0x4c, - 0x20, 0xd5, 0x13, 0x6a, 0xe4, 0xe7, 0x02, 0x21, 0x51, 0x6c, 0xad, 0x19, 0xcb, 0x64, 0x62, 0x0d, - 0x56, 0x31, 0x94, 0x85, 0x0e, 0x56, 0x39, 0xf3, 0x6a, 0xa8, 0x08, 0xf3, 0x5e, 0xb0, 0xb2, 0xad, - 0x96, 0x1b, 0xf3, 0x02, 0xcd, 0x56, 0xd5, 0xa7, 0x89, 0xf0, 0x15, 0x4f, 0xd1, 0x59, 0xc4, 0xbd, - 0x34, 0x0c, 0x91, 0xa9, 0xea, 0xda, 0xd7, 0x0c, 0x56, 0xc4, 0x69, 0x14, 0x3d, 0xb1, 0xf9, 0x0a, - 0xd4, 0x39, 0x61, 0x2a, 0xfa, 0x68, 0xb6, 0x19, 0x4f, 0x81, 0xab, 0xf8, 0x59, 0x64, 0xe5, 0x5b, - 0xb0, 0xe3, 0xc8, 0x7c, 0x4a, 0x6e, 0x5e, 0x04, 0xe9, 0x96, 0x51, 0xad, 0x32, 0xc4, 0xa8, 0xe5, - 0x08, 0x3c, 0x7e, 0x80, 0x1c, 0x8d, 0xc3, 0xd5, 0x76, 0x84, 0x16, 0xf1, 0x8e, 0x40, 0x2a, 0x37, - 0x96, 0x04, 0x98, 0x05, 0x3d, 0x0b, 0x28, 0xb6, 0x34, 0x96, 0xcb, 0xb5, 0xc3, 0xab, 0x31, 0x47, - 0x96, 0xcf, 0xe7, 0x90, 0xff, 0xda, 0xa9, 0x1a, 0x56, 0x6a, 0xcd, 0x62, 0xeb, 0x4c, 0x2b, 0xff, - 0x9b, 0xad, 0x2a, 0x86, 0x99, 0xe4, 0x0f, 0xd0, 0xd4, 0xfe, 0xc3, 0xe8, 0x57, 0xff, 0xb5, 0x35, - 0xfd, 0xd7, 0xd6, 0xf4, 0x5f, 0x5b, 0xd3, 0x7f, 0xac, 0xad, 0xc9, 0xdc, 0x4c, 0xee, 0x6b, 0x6d, - 0xd5, 0x2a, 0xb7, 0x74, 0x69, 0x1f, 0xff, 0xb9, 0xe0, 0x98, 0x4b, 0x58, 0x1d, 0x9a, 0x22, 0x25, - 0xa7, 0xf3, 0x91, 0xd1, 0x35, 0xef, 0x44, 0x7c, 0x29, 0x2f, 0xe8, 0x12, 0x24, 0xee, 0xf6, 0xef, - 0x84, 0xdc, 0x9c, 0xfa, 0xc5, 0x36, 0x25, 0xee, 0xef, 0x99, 0x34, 0x81, 0x28, 0x7f, 0x26, 0xd6, - 0xb7, 0xb0, 0xb3, 0xb1, 0x1d, 0xce, 0xf7, 0x60, 0x81, 0xe8, 0x4e, 0xb9, 0x05, 0x83, 0xba, 0x8d, - 0x41, 0xa2, 0x2d, 0x76, 0x17, 0xd0, 0xac, 0x31, 0x20, 0x00, 0x5b, 0x88, 0xde, 0x3f, 0xd7, 0xc9, - 0xdd, 0xf2, 0x7e, 0x76, 0x92, 0xbe, 0xad, 0x72, 0xdb, 0x5c, 0x82, 0x16, 0x4c, 0x86, 0xbd, 0x39, - 0x56, 0xd0, 0xc4, 0xfa, 0x47, 0x21, 0x85, 0x4e, 0xb5, 0xff, 0x71, 0x48, 0x89, 0x93, 0x0d, 0x71, - 0x22, 0x15, 0x30, 0x52, 0xbf, 0xa4, 0x0b, 0xe9, 0x2b, 0x12, 0x1c, 0xd2, 0x59, 0xd3, 0x92, 0xb7, - 0x58, 0x15, 0x0b, 0x11, 0x28, 0xf7, 0x99, 0xd5, 0x52, 0x0e, 0xa5, 0xc1, 0x66, 0x88, 0x5c, 0xb8, - 0x40, 0x6b, 0x89, 0x56, 0x49, 0x5d, 0xf8, 0xa2, 0xf8, 0xe6, 0x46, 0xbd, 0xa2, 0xff, 0x80, 0xc9, - 0x3a, 0x5f, 0xe0, 0x83, 0xd1, 0xcb, 0x70, 0x6b, 0x11, 0x5c, 0x3a, 0xf0, 0xbe, 0x09, 0x5d, 0xb2, - 0x4a, 0x47, 0x20, 0x51, 0x51, 0xe2, 0x59, 0x12, 0xc6, 0x82, 0x08, 0xad, 0xd4, 0x31, 0x99, 0xeb, - 0x39, 0x58, 0xb7, 0xce, 0xb3, 0x37, 0xe1, 0xba, 0x9c, 0x59, 0xbb, 0x19, 0x8f, 0x7e, 0xb6, 0x31, - 0x1b, 0xe4, 0x24, 0xb8, 0x19, 0x5a, 0x96, 0xee, 0x99, 0x47, 0x99, 0x4d, 0xe6, 0xdd, 0xd6, 0x6d, - 0x50, 0x1f, 0x2f, 0xed, 0xab, 0x4f, 0x68, 0x87, 0x7a, 0x47, 0x87, 0xd6, 0x1c, 0xc0, 0x2e, 0x5e, - 0x42, 0x81, 0x80, 0x5a, 0x2d, 0xc3, 0x11, 0x7d, 0xe9, 0xd3, 0x19, 0x08, 0x82, 0x8d, 0x4e, 0x31, - 0xfa, 0xb1, 0x6d, 0x39, 0xd6, 0xf6, 0x25, 0x30, 0xa8, 0x4b, 0xe9, 0x7d, 0x06, 0xc4, 0x5e, 0x21, - 0x32, 0xe4, 0xbe, 0x73, 0xc5, 0x9b, 0x0c, 0x9f, 0x88, 0x23, 0xbe, 0xf7, 0xd5, 0x73, 0xbc, 0xdf, - 0xc4, 0x09, 0x32, 0xfa, 0xdb, 0xbc, 0x2a, 0x5a, 0x11, 0xaa, 0x0b, 0xc0, 0xd8, 0x82, 0x8b, 0x08, - 0x6f, 0x2b, 0xb5, 0x2b, 0xa3, 0xbb, 0xb2, 0xb1, 0x17, 0xd2, 0xaf, 0xac, 0xf1, 0x6c, 0x59, 0x1f, - 0x6a, 0x7c, 0x84, 0xef, 0x28, 0xf2, 0x5d, 0xa9, 0x22, 0x5b, 0x5b, 0xf2, 0x1f, 0xe9, 0xd4, 0x83, - 0x32, 0x55, 0x67, 0x3e, 0x86, 0xbc, 0xa4, 0x33, 0x3c, 0x9e, 0xc5, 0xf7, 0x94, 0x50, 0xf2, 0xa2, - 0x5a, 0x54, 0xe3, 0x67, 0x0c, 0xda, 0x6a, 0x42, 0x2b, 0x36, 0xde, 0xae, 0xcb, 0x7d, 0x87, 0x31, - 0x13, 0x72, 0x70, 0xa4, 0x7a, 0xe0, 0x5e, 0xe9, 0x4d, 0xa5, 0x47, 0xe5, 0xce, 0xa6, 0x30, 0x69, - 0xea, 0x68, 0x59, 0xc0, 0x87, 0x6d, 0xb8, 0x28, 0x60, 0xc4, 0x97, 0x3a, 0x53, 0x37, 0x6b, 0xd2, - 0xa8, 0x8b, 0xc2, 0x5e, 0x3c, 0x07, 0xe1, 0xb9, 0x28, 0xae, 0x50, 0x8d, 0xa9, 0x8b, 0xb1, 0x0b, - 0xa3, 0x38, 0x0e, 0x7d, 0x37, 0xd2, 0x9a, 0xc7, 0x37, 0x4b, 0x8b, 0x2b, 0x09, 0xe3, 0xae, 0x98, - 0x40, 0x3e, 0x33, 0x0e, 0x53, 0x84, 0x7e, 0xe9, 0x0b, 0x3f, 0x6d, 0xe2, 0x48, 0x4b, 0x68, 0x18, - 0x7c, 0x2d, 0xd1, 0x5b, 0xd7, 0x23, 0x1d, 0xdb, 0xc0, 0x5d, 0xd0, 0x46, 0x65, 0x55, 0x62, 0x48, - 0xe8, 0x38, 0xd0, 0xf3, 0x3c, 0x4f, 0x79, 0x64, 0x1a, 0x95, 0xba, 0xf8, 0x12, 0xe6, 0x4f, 0x0f, - 0x22, 0xe6, 0x39, 0x95, 0xbe, 0xc0, 0x12, 0x76, 0x85, 0x60, 0xa9, 0x26, 0xcb, 0xdb, 0xce, 0xcc, - 0x4d, 0x9a, 0xcd, 0x8f, 0xb8, 0x8c, 0x6d, 0xbe, 0x03, 0xf9, 0x13, 0x49, 0xe4, 0x3f, 0x89, 0x3f, - 0xdd, 0xe1, 0xcb, 0xfb, 0x61, 0xe3, 0x4f, 0x77, 0xf4, 0xfe, 0xbe, 0xf1, 0x93, 0xac, 0xc2, 0x42, - 0x88, 0xb5, 0x10, 0xe9, 0x71, 0xe2, 0x53, 0x86, 0x33, 0x15, 0x7d, 0x41, 0xa7, 0x41, 0x96, 0x78, - 0xd8, 0xb1, 0xa0, 0x4c, 0x8a, 0x4d, 0x8a, 0x49, 0x31, 0x28, 0xaa, 0xb3, 0x42, 0x22, 0x56, 0xc0, - 0xe9, 0x96, 0x22, 0x19, 0xf6, 0x80, 0x3f, 0x17, 0x2c, 0x4f, 0xc6, 0xca, 0xcd, 0xfc, 0x31, 0xae, - 0x5b, 0x15, 0x12, 0x6c, 0x2e, 0x56, 0xbc, 0x23, 0x60, 0x93, 0x40, 0x1c, 0x81, 0x25, 0x4d, 0x61, - 0x22, 0x93, 0x47, 0x86, 0xc6, 0xa0, 0x6e, 0xb9, 0x49, 0x06, 0x5c, 0x4b, 0x2b, 0xa9, 0xf7, 0xe8, - 0x27, 0xfd, 0x26, 0x02, 0x59, 0x4b, 0x5d, 0x1f, 0x52, 0x5e, 0x08, 0x81, 0x09, 0xcc, 0x40, 0xdc, - 0xc6, 0xfb, 0x4e, 0x65, 0xfb, 0x35, 0xf1, 0x29, 0x65, 0x5b, 0x2d, 0x75, 0x29, 0x0a, 0x5d, 0x7e, - 0x73, 0xf8, 0xa7, 0x3b, 0x4c, 0xa8, 0x40, 0xb1, 0x5a, 0xf7, 0x74, 0x4b, 0xcd, 0xd3, 0x0c, 0x33, - 0x53, 0x56, 0x1a, 0x1d, 0x4f, 0xfd, 0xab, 0x34, 0x8e, 0x1a, 0x87, 0x20, 0x0d, 0xee, 0xbf, 0x78, - 0xf9, 0xb4, 0x83, 0x85, 0xe4, 0x4d, 0x0f, 0x75, 0x9d, 0xc4, 0x6b, 0x15, 0xd4, 0x35, 0x3b, 0x3f, - 0x0d, 0x74, 0xbc, 0xd1, 0x3d, 0x0c, 0x43, 0x1a, 0x6a, 0xd5, 0x2c, 0xa9, 0x57, 0x2e, 0xb0, 0x87, - 0xca, 0x08, 0x74, 0x50, 0x05, 0x94, 0x14, 0xf1, 0x81, 0x15, 0xc5, 0x2e, 0xe4, 0xb4, 0x54, 0x6b, - 0xe6, 0x83, 0x6b, 0x90, 0xfa, 0x6b, 0xcc, 0x08, 0xf1, 0x1d, 0xcb, 0xf8, 0xbe, 0x74, 0x1e, 0xa8, - 0x6c, 0x9b, 0x4e, 0x4c, 0x36, 0x0e, 0xa9, 0x59, 0xd5, 0x27, 0x61, 0xa0, 0x6e, 0xe4, 0x7a, 0x78, - 0x68, 0x14, 0xff, 0x6d, 0x63, 0xb1, 0xc6, 0xe1, 0xeb, 0xe3, 0x1f, 0x8e, 0x0c, 0xcc, 0x15, 0xe2, - 0x26, 0xc1, 0xaf, 0xdc, 0x8d, 0x33, 0x09, 0xfd, 0x9b, 0xc1, 0x85, 0x9b, 0xf0, 0xa5, 0x50, 0x03, - 0x37, 0x04, 0x96, 0xdd, 0x0e, 0x72, 0x7f, 0x96, 0xf5, 0x39, 0x1b, 0x4f, 0xe3, 0x50, 0x33, 0xd0, - 0x72, 0xd3, 0x78, 0xe5, 0x04, 0xf4, 0x86, 0xdb, 0x33, 0xee, 0x35, 0x9a, 0xb8, 0xb3, 0x20, 0xbc, - 0xed, 0x63, 0x6a, 0x17, 0x4a, 0x03, 0xa5, 0xdd, 0x45, 0x41, 0x1d, 0xd2, 0x41, 0xad, 0xbc, 0x48, - 0x45, 0x02, 0x95, 0xf7, 0x34, 0x61, 0x12, 0xdf, 0x3e, 0x9e, 0xa6, 0xd0, 0xe8, 0x51, 0x9d, 0x4f, - 0xe7, 0x50, 0xd3, 0xb3, 0x34, 0x98, 0xe1, 0x15, 0x25, 0x82, 0x48, 0x6c, 0xd8, 0xf8, 0xae, 0x2e, - 0x79, 0x02, 0xe5, 0x0e, 0xc5, 0x16, 0x01, 0x40, 0x5f, 0x60, 0xb6, 0x3a, 0xe1, 0x5e, 0xc1, 0x57, - 0xbc, 0x2b, 0xed, 0xbf, 0xf5, 0x9c, 0xdd, 0x0c, 0xd7, 0x21, 0xba, 0x1a, 0x42, 0x3c, 0xd8, 0x1b, - 0x52, 0xaa, 0xa7, 0x32, 0x86, 0xb3, 0xa3, 0x07, 0x6e, 0xaa, 0x14, 0x42, 0xb6, 0x90, 0xb9, 0x93, - 0xe9, 0x1c, 0xf4, 0x8c, 0x7c, 0xcd, 0xd2, 0x9e, 0x92, 0x39, 0x8d, 0xc3, 0x97, 0x32, 0x87, 0x0c, - 0xa7, 0x00, 0x40, 0x00, 0x59, 0xf5, 0x46, 0x16, 0x75, 0x6f, 0xca, 0x4f, 0x85, 0x17, 0x19, 0xe8, - 0xd2, 0x30, 0x83, 0x23, 0x9a, 0x0b, 0xed, 0x7c, 0xcb, 0x74, 0x3d, 0xe1, 0x7e, 0x85, 0x6a, 0x21, - 0xd0, 0x2e, 0x86, 0x3d, 0x96, 0x7b, 0x30, 0xca, 0x74, 0xb4, 0x9b, 0xe1, 0xad, 0x03, 0xe5, 0x95, - 0x1d, 0xc0, 0xfe, 0x31, 0x00, 0x2c, 0x88, 0xd0, 0xf7, 0x65, 0x90, 0x36, 0xed, 0x23, 0x7a, 0x51, - 0x62, 0xd7, 0x95, 0x42, 0x33, 0x12, 0x3e, 0xf4, 0xbb, 0x3e, 0xa8, 0xd4, 0x33, 0x0c, 0x2d, 0x76, - 0x65, 0x46, 0x4b, 0x94, 0x96, 0x24, 0x0a, 0xce, 0x55, 0xd6, 0x6c, 0xab, 0x02, 0x67, 0x42, 0x2e, - 0x92, 0xc5, 0x6d, 0xb8, 0x52, 0x2c, 0x8d, 0xaf, 0x37, 0xe4, 0x7e, 0x02, 0xcb, 0xd6, 0xaf, 0x36, - 0xed, 0x3b, 0x2e, 0x6f, 0xf9, 0xa1, 0x0d, 0xe2, 0x8e, 0x7f, 0x5b, 0x69, 0x8f, 0x0f, 0x28, 0x0f, - 0x45, 0x21, 0x05, 0xac, 0x09, 0x3b, 0x2f, 0xa6, 0x10, 0x14, 0xbe, 0xe7, 0x58, 0x42, 0x7c, 0x78, - 0x7b, 0xfc, 0xf7, 0x22, 0xcd, 0x63, 0x66, 0x16, 0xea, 0x23, 0x5c, 0x07, 0x96, 0x5d, 0x00, 0x9d, - 0x77, 0x40, 0xcd, 0x48, 0x50, 0x35, 0x71, 0x52, 0x9f, 0xae, 0x92, 0x6b, 0x76, 0xce, 0x3b, 0x17, - 0xb6, 0x25, 0xac, 0x2a, 0x12, 0x68, 0x6d, 0xd3, 0x41, 0x6e, 0x8c, 0x5c, 0xc1, 0x09, 0xc0, 0x9e, - 0x51, 0x82, 0x38, 0x6c, 0xb7, 0x5c, 0xfa, 0xa4, 0x5f, 0xf2, 0xa3, 0x3a, 0x35, 0x58, 0x07, 0xea, - 0x0c, 0xaf, 0x00, 0xac, 0x83, 0x84, 0x8c, 0x83, 0x60, 0x9c, 0x1c, 0x9d, 0x9e, 0x3d, 0x3f, 0x39, - 0x2b, 0x6b, 0x53, 0x48, 0x18, 0x1d, 0xfd, 0x2d, 0xf6, 0x2f, 0x49, 0x63, 0x93, 0xbc, 0x94, 0x55, - 0xac, 0x92, 0xfa, 0x44, 0x51, 0xfc, 0x27, 0xf3, 0x9a, 0x2f, 0xde, 0x28, 0x80, 0x67, 0xeb, 0x77, - 0x78, 0x01, 0xdb, 0x1f, 0x5f, 0x8e, 0xe2, 0x9b, 0x86, 0x40, 0xb5, 0xbc, 0x0d, 0x58, 0xc2, 0x8d, - 0x1d, 0xfe, 0xdc, 0x37, 0x04, 0x6d, 0xf0, 0xcf, 0x2c, 0x2a, 0x42, 0xe7, 0x4c, 0xad, 0x7b, 0xed, - 0x26, 0x2f, 0x9a, 0x4a, 0xbe, 0x91, 0x05, 0xf6, 0x5f, 0xae, 0x63, 0xd9, 0xb4, 0x55, 0xc9, 0x1a, - 0x78, 0xbd, 0x97, 0xce, 0x2f, 0xb9, 0x03, 0x6d, 0xca, 0x16, 0x8c, 0x5b, 0x87, 0xe4, 0x93, 0x7c, - 0x01, 0xd8, 0x4f, 0xc5, 0xd0, 0xa4, 0x48, 0xaa, 0x8d, 0x90, 0x24, 0x3b, 0x7d, 0x84, 0x1a, 0xc9, - 0xe0, 0xcc, 0x20, 0x11, 0x43, 0x41, 0xe3, 0xe8, 0x0c, 0xca, 0xc9, 0x2a, 0x50, 0x10, 0x5f, 0xbc, - 0xa6, 0xc2, 0x2d, 0x40, 0xf6, 0xe2, 0x5b, 0x8c, 0x88, 0xc3, 0xd8, 0xc6, 0x0a, 0xfc, 0x38, 0x21, - 0x53, 0x56, 0x29, 0x6b, 0x92, 0x50, 0x14, 0x57, 0x1d, 0x7e, 0xb2, 0x33, 0x23, 0x5a, 0xc3, 0x04, - 0xef, 0x19, 0xff, 0xf9, 0x18, 0x7f, 0xfa, 0xed, 0xb7, 0xb8, 0x1f, 0xeb, 0x6e, 0x36, 0x29, 0x78, - 0xfd, 0xf4, 0x54, 0x5e, 0xa7, 0x43, 0x22, 0x14, 0xa2, 0x3c, 0x26, 0x84, 0xc7, 0x30, 0x0c, 0xe9, - 0x93, 0xc4, 0x35, 0xf9, 0xcc, 0xe2, 0xcc, 0x01, 0x12, 0xfb, 0xb0, 0x95, 0x43, 0x33, 0xb0, 0x89, - 0x73, 0xe5, 0x92, 0x6f, 0x61, 0x04, 0xaa, 0x26, 0x7e, 0x99, 0x3d, 0x1b, 0xc7, 0x3e, 0x66, 0x12, - 0x1f, 0x8a, 0x25, 0x52, 0x2b, 0xd2, 0x1f, 0x08, 0x17, 0x99, 0x0f, 0xa2, 0x2a, 0x5d, 0xcb, 0xe6, - 0x50, 0xa7, 0xd8, 0x66, 0x52, 0x3e, 0x97, 0xb4, 0xa7, 0x53, 0x98, 0xbc, 0xa3, 0x6f, 0x91, 0x78, - 0xd6, 0x11, 0xca, 0x9f, 0xee, 0xb8, 0x5f, 0xf7, 0x40, 0x25, 0x30, 0x6e, 0x40, 0x35, 0x8c, 0x8b, - 0xa1, 0xad, 0xa4, 0x05, 0x29, 0x26, 0x2f, 0x52, 0x83, 0x12, 0x7b, 0x2b, 0x82, 0x31, 0xf1, 0x44, - 0xca, 0x2c, 0x09, 0x1b, 0x67, 0x74, 0xdb, 0xd0, 0x4c, 0x40, 0xe5, 0x28, 0xf4, 0x15, 0xc1, 0x58, - 0x81, 0x71, 0x10, 0xc0, 0xfb, 0x9a, 0xa1, 0x15, 0x73, 0x06, 0x3f, 0x36, 0x18, 0x29, 0xe1, 0xf6, - 0x1b, 0xcc, 0x94, 0xae, 0x63, 0x17, 0x86, 0xbd, 0x6a, 0x98, 0xa8, 0x20, 0xd4, 0xaf, 0xe9, 0xda, - 0xbe, 0x56, 0x06, 0xfd, 0xa5, 0x7a, 0x5d, 0xa1, 0x88, 0xba, 0x3e, 0xaf, 0xed, 0x23, 0x5f, 0xe3, - 0xf9, 0xbb, 0xfb, 0xa3, 0x75, 0xc3, 0xe8, 0x85, 0xfa, 0xd1, 0xe9, 0x88, 0x6f, 0x53, 0x9f, 0x52, - 0xf4, 0x88, 0xa6, 0xc7, 0x49, 0x57, 0xa7, 0xa0, 0x48, 0x62, 0xe2, 0x8e, 0x5b, 0xa5, 0x95, 0x52, - 0xe2, 0x58, 0x4a, 0xd5, 0x0e, 0x0b, 0x11, 0x53, 0x1c, 0x60, 0xb6, 0x90, 0x6c, 0x9e, 0xe0, 0x4f, - 0xdf, 0xc3, 0x84, 0x2e, 0x25, 0x34, 0x3a, 0xd0, 0x2b, 0xcf, 0xc7, 0x7d, 0x93, 0x64, 0x65, 0xfa, - 0x4c, 0x5b, 0xba, 0x78, 0x40, 0xa9, 0xa4, 0x7c, 0xee, 0x45, 0xde, 0xcd, 0xe7, 0x7f, 0x7b, 0x01, - 0x9b, 0x78, 0x9c, 0x38, 0xe2, 0x9f, 0x7c, 0x9f, 0x93, 0x12, 0x96, 0xe0, 0xe4, 0x25, 0x2e, 0x85, - 0xdb, 0x86, 0xef, 0xee, 0xa4, 0xdc, 0x88, 0xa1, 0x1b, 0x61, 0xa2, 0xa3, 0x5b, 0x91, 0x03, 0x27, - 0xcf, 0xf1, 0xc6, 0x19, 0x60, 0x99, 0x6e, 0x86, 0x79, 0x1b, 0xbe, 0xfb, 0x1b, 0x27, 0x87, 0xc3, - 0x1b, 0x96, 0xd2, 0x12, 0x18, 0xee, 0x31, 0x98, 0x3d, 0x49, 0xa6, 0x92, 0x64, 0xf5, 0x89, 0x6f, - 0xfb, 0x30, 0x36, 0x1d, 0x7d, 0x70, 0x35, 0xb2, 0x03, 0xc5, 0x8d, 0x56, 0x5f, 0x3a, 0x5a, 0x95, - 0x61, 0x11, 0xd7, 0x53, 0x6e, 0x3b, 0x1a, 0xcc, 0xd6, 0x5d, 0x31, 0xe7, 0xf4, 0xb7, 0xdc, 0x4f, - 0x9f, 0x36, 0xe9, 0xc5, 0x6f, 0xbc, 0xa0, 0x5b, 0x3f, 0x8e, 0x3a, 0xb6, 0xb0, 0x9e, 0xfe, 0xa9, - 0x57, 0xe4, 0x8d, 0xb5, 0xc8, 0x0e, 0xa4, 0xed, 0x71, 0x38, 0x6e, 0xe0, 0xe4, 0xea, 0x52, 0x30, - 0xea, 0xca, 0x6f, 0xbf, 0x59, 0xda, 0x96, 0x5c, 0x69, 0x5b, 0xd6, 0xb0, 0xde, 0x62, 0x76, 0x5d, - 0xca, 0x08, 0x49, 0x49, 0x10, 0x28, 0xbd, 0x42, 0x90, 0xa9, 0x79, 0x76, 0xc8, 0x1a, 0x05, 0x45, - 0x97, 0x82, 0x31, 0x85, 0x97, 0xed, 0x21, 0xc5, 0x96, 0xa1, 0x94, 0x12, 0xb9, 0x15, 0x09, 0x66, - 0x13, 0x7d, 0x41, 0x09, 0xc1, 0x7f, 0xba, 0x83, 0x36, 0x4b, 0x7c, 0x34, 0x50, 0xbe, 0xf8, 0xcb, - 0x2f, 0xf3, 0x38, 0x1f, 0x58, 0xad, 0x7b, 0xe4, 0x78, 0x54, 0xfc, 0xbe, 0x4e, 0xa1, 0xf8, 0xd3, - 0x5d, 0x29, 0x76, 0x50, 0xd1, 0x42, 0x74, 0xb8, 0x97, 0x7b, 0xe6, 0x9f, 0xee, 0xb4, 0x11, 0x3c, - 0xb3, 0x96, 0x6b, 0x25, 0x91, 0xdb, 0x38, 0x7c, 0xdb, 0x79, 0x2e, 0xab, 0xd1, 0x1e, 0x52, 0x6a, - 0x74, 0x87, 0x92, 0x6d, 0xdc, 0x9b, 0x4a, 0x5c, 0x8d, 0x14, 0x0c, 0xa3, 0x6f, 0xe9, 0xc6, 0x20, - 0xa9, 0x5a, 0xeb, 0x45, 0x00, 0x42, 0xab, 0x34, 0x5d, 0x00, 0x89, 0xbe, 0xc2, 0x05, 0x4f, 0x49, - 0x5b, 0x23, 0x20, 0xe1, 0x2c, 0xeb, 0x4b, 0xed, 0x9e, 0x96, 0x63, 0x41, 0x74, 0xe5, 0xca, 0x74, - 0xf1, 0x1e, 0xbb, 0x14, 0xcd, 0x10, 0xe2, 0xa7, 0x79, 0xf0, 0x53, 0x91, 0xff, 0x9b, 0xa1, 0xe1, - 0x1d, 0x6c, 0x72, 0xbd, 0xa1, 0x17, 0x21, 0x18, 0x97, 0xc7, 0x78, 0x51, 0x50, 0xe5, 0xd3, 0xf7, - 0xd2, 0x6e, 0x54, 0xdc, 0x0e, 0x81, 0x5e, 0xd5, 0x6f, 0xd3, 0x78, 0x9e, 0x50, 0x4a, 0x47, 0x06, - 0x34, 0x0f, 0x1c, 0x4c, 0xeb, 0x9d, 0xb0, 0x65, 0x50, 0xea, 0xcc, 0xec, 0x47, 0x95, 0xe9, 0x3a, - 0x1c, 0xba, 0xb9, 0x3a, 0x93, 0x96, 0xac, 0x4c, 0xcc, 0xdc, 0x5b, 0xcc, 0xa1, 0x22, 0x7d, 0xb7, - 0x9c, 0x0e, 0x1d, 0x54, 0x0d, 0x06, 0xe7, 0x8e, 0x28, 0x62, 0xd6, 0xb8, 0xee, 0x8c, 0x4d, 0x8f, - 0x65, 0x7e, 0x22, 0xba, 0x9f, 0x98, 0x62, 0x6b, 0xc3, 0x49, 0x5b, 0x26, 0x3d, 0xc1, 0x0c, 0xab, - 0x2e, 0x25, 0xed, 0x81, 0x91, 0x47, 0x5b, 0x72, 0x51, 0xbb, 0x1e, 0x43, 0xd2, 0x34, 0x01, 0xe8, - 0xcd, 0x73, 0x8f, 0x33, 0x40, 0xa8, 0xcc, 0x3d, 0xf3, 0x50, 0x59, 0xd9, 0x38, 0xf3, 0x08, 0xe0, - 0x04, 0xf5, 0x3c, 0xce, 0xd3, 0x86, 0xb7, 0xe4, 0x22, 0x0f, 0xb8, 0x33, 0x82, 0xca, 0x11, 0xf1, - 0xc4, 0x02, 0xb4, 0x5b, 0xf8, 0x4c, 0x65, 0x26, 0x33, 0xec, 0x20, 0xba, 0x96, 0x43, 0x3a, 0x0e, - 0x6b, 0x38, 0x05, 0x24, 0x3a, 0x63, 0x72, 0x69, 0xc4, 0x43, 0x13, 0x56, 0xd5, 0xf5, 0x83, 0x26, - 0xec, 0x8f, 0xa4, 0x63, 0xc0, 0x9c, 0xd7, 0x19, 0x49, 0x75, 0xfe, 0xd3, 0xd2, 0x1d, 0x94, 0x5f, - 0x61, 0xec, 0x26, 0x6c, 0xde, 0xf8, 0xd7, 0x99, 0x07, 0xba, 0xf2, 0x54, 0x94, 0x41, 0xa1, 0x3e, - 0x00, 0xad, 0x14, 0x54, 0xf3, 0xac, 0x69, 0x9d, 0x5b, 0xba, 0x8a, 0xa5, 0x47, 0x64, 0x01, 0x76, - 0xb3, 0x4b, 0x60, 0x17, 0x59, 0xe4, 0x5e, 0xfa, 0xe7, 0xc4, 0x5b, 0x3d, 0xa0, 0x01, 0xa8, 0x5e, - 0xc2, 0x2a, 0xc6, 0x56, 0x1a, 0x0b, 0x97, 0xc1, 0x52, 0x49, 0x77, 0x03, 0xbc, 0xef, 0x44, 0xd2, - 0xa3, 0x24, 0x9f, 0x92, 0x47, 0xbf, 0x7d, 0x77, 0x76, 0xd4, 0x37, 0x38, 0xb0, 0x24, 0x28, 0x4c, - 0x92, 0x03, 0x1f, 0xa9, 0x47, 0x48, 0x9a, 0x18, 0x11, 0xcd, 0x59, 0xdb, 0xf1, 0xce, 0x23, 0x75, - 0xc5, 0x06, 0x80, 0xc4, 0x65, 0x53, 0xc2, 0x2b, 0xae, 0x87, 0xbb, 0x55, 0x2b, 0xe9, 0x02, 0xf6, - 0x3b, 0xdf, 0x6b, 0xf3, 0x8e, 0x27, 0xf9, 0x6a, 0x6b, 0xd5, 0xc6, 0x62, 0x57, 0x76, 0x37, 0x6c, - 0xeb, 0xd4, 0xb8, 0xe4, 0x83, 0xd7, 0x46, 0x99, 0x29, 0x1a, 0xe3, 0x1b, 0x40, 0x35, 0xe1, 0xdb, - 0x0e, 0x60, 0x3d, 0xe1, 0x16, 0x6b, 0x17, 0x7b, 0xab, 0xb9, 0xd9, 0x5c, 0xf0, 0x16, 0xe3, 0x14, - 0x4b, 0x0c, 0x25, 0xaf, 0x37, 0x44, 0xaf, 0x85, 0xd0, 0xd5, 0x64, 0x32, 0xf9, 0x48, 0x27, 0x35, - 0xca, 0xdf, 0x50, 0xf2, 0xe3, 0xa7, 0x16, 0x3b, 0x47, 0x4b, 0x6a, 0x31, 0xdc, 0xe2, 0x1a, 0x39, - 0x51, 0x3d, 0xbc, 0xdb, 0x83, 0x28, 0xa8, 0x8e, 0xa8, 0x18, 0x72, 0x49, 0x4e, 0x30, 0xe0, 0xe3, - 0x49, 0xb9, 0xf6, 0x23, 0xf2, 0x26, 0x13, 0x8e, 0x02, 0xbe, 0x47, 0x4a, 0x19, 0xec, 0x98, 0x91, - 0x34, 0x8e, 0x4f, 0xdf, 0x37, 0x6c, 0xd1, 0xa0, 0xc3, 0xe6, 0x8d, 0x96, 0x2d, 0x98, 0xd3, 0x95, - 0xc0, 0x88, 0x79, 0x10, 0xcf, 0xc2, 0xdb, 0x1c, 0x28, 0xaf, 0xa4, 0x76, 0xc3, 0x03, 0xe5, 0x27, - 0x53, 0x4b, 0xd6, 0x4d, 0xdb, 0x40, 0x6a, 0x21, 0x5d, 0xc0, 0x40, 0x49, 0x97, 0x47, 0x3e, 0xa5, - 0x0f, 0xe4, 0x65, 0x2a, 0xe1, 0xbd, 0xf6, 0x29, 0xd5, 0xa2, 0xb1, 0xb8, 0x29, 0x5a, 0x3e, 0xe0, - 0xab, 0xc0, 0x55, 0xbe, 0xe2, 0x69, 0x8c, 0xd1, 0x23, 0x14, 0x17, 0xc2, 0xa9, 0x90, 0xf1, 0x50, - 0x3e, 0xdd, 0xbf, 0x93, 0x6b, 0x94, 0xc2, 0xb7, 0x44, 0x19, 0xc2, 0x84, 0x76, 0x41, 0xa8, 0xc6, - 0x77, 0x38, 0x8f, 0x23, 0xb0, 0x0d, 0xbe, 0x89, 0x85, 0x36, 0x50, 0x79, 0x0f, 0xa1, 0xa3, 0x6d, - 0xcd, 0x6c, 0x08, 0x45, 0x0d, 0xc9, 0x56, 0xc6, 0x3d, 0x5d, 0x5d, 0x2a, 0x67, 0x66, 0x4a, 0x69, - 0xe8, 0x71, 0x6b, 0xa8, 0x39, 0x00, 0xa7, 0x50, 0x7c, 0x28, 0x1c, 0xd3, 0xd0, 0x09, 0x6f, 0xa6, - 0xbb, 0x56, 0x4b, 0x0b, 0x3f, 0x80, 0xd5, 0x38, 0x35, 0x3d, 0xc1, 0x43, 0x49, 0x2d, 0x46, 0x88, - 0x2f, 0xf7, 0x6b, 0x0a, 0xbb, 0x37, 0xde, 0xf9, 0x93, 0x97, 0x6d, 0x98, 0x61, 0xbd, 0x0f, 0xb0, - 0x47, 0x6a, 0x95, 0x60, 0x85, 0x5f, 0x2e, 0x8b, 0x80, 0x64, 0xfe, 0x84, 0x95, 0xf4, 0x08, 0xeb, - 0x4d, 0xcc, 0xc5, 0x5a, 0xe1, 0xf5, 0x16, 0x63, 0xbd, 0xf0, 0xbf, 0x87, 0xd1, 0x98, 0x8d, 0xc5, - 0x84, 0xe7, 0x4d, 0x0c, 0xc5, 0xff, 0xf6, 0x7f, 0xfd, 0xaf, 0x87, 0x5a, 0x89, 0x3f, 0x7b, 0x4a, - 0xee, 0x17, 0x68, 0xcd, 0xdc, 0x54, 0xe4, 0xc2, 0x5f, 0x08, 0x61, 0x99, 0x07, 0x05, 0x53, 0x5a, - 0x50, 0x8b, 0xf3, 0x14, 0x35, 0x76, 0x60, 0x0a, 0x4a, 0x34, 0x47, 0x7e, 0x85, 0x54, 0xa7, 0xa1, - 0x1e, 0xc9, 0x9f, 0xad, 0x73, 0x75, 0x06, 0x3d, 0xd0, 0x9c, 0xab, 0x46, 0x3b, 0x8d, 0x84, 0xfa, - 0xa2, 0xc9, 0x6d, 0x0c, 0xe9, 0x74, 0x2e, 0x22, 0x1c, 0x75, 0x6d, 0x4e, 0x09, 0x6f, 0x7c, 0x2c, - 0x15, 0xf1, 0x26, 0x74, 0x67, 0x16, 0x44, 0xbf, 0xfd, 0x46, 0xc7, 0xf4, 0x2c, 0xab, 0x12, 0x89, - 0xb2, 0xc4, 0xac, 0x58, 0xed, 0x04, 0x3a, 0xef, 0xdc, 0x70, 0xc0, 0xfb, 0x9e, 0x8f, 0x3b, 0x4f, - 0x4c, 0xee, 0x17, 0xbc, 0xaf, 0xeb, 0xba, 0x82, 0x86, 0xc2, 0xac, 0x58, 0xb5, 0x23, 0x92, 0x6d, - 0x6a, 0x50, 0x67, 0x72, 0x61, 0xac, 0xf1, 0x4f, 0x28, 0xb9, 0xa9, 0x65, 0xcd, 0x84, 0xf4, 0xfb, - 0x4c, 0x6b, 0x35, 0xb0, 0xc8, 0xb6, 0xb6, 0xa9, 0x71, 0x4d, 0x9f, 0x5f, 0xdd, 0xba, 0xa6, 0xe1, - 0x7a, 0x61, 0xee, 0x0c, 0xde, 0xf3, 0xff, 0x57, 0x1b, 0x5b, 0xc1, 0xd0, 0x0a, 0x8b, 0x43, 0x39, - 0x4e, 0x56, 0xd6, 0xac, 0x9a, 0x63, 0x14, 0xd2, 0x12, 0x86, 0xd4, 0xc9, 0xa6, 0xa7, 0xec, 0xb7, - 0xdf, 0x70, 0xc3, 0x26, 0x7b, 0xd8, 0xf0, 0xf0, 0xb3, 0xad, 0x59, 0xb1, 0x66, 0xcb, 0xaa, 0x33, - 0x60, 0x7d, 0x11, 0x4b, 0x93, 0x61, 0x39, 0xa8, 0x31, 0x35, 0xad, 0x42, 0x49, 0xe9, 0xd8, 0xad, - 0xa2, 0xc4, 0xc5, 0x4e, 0x09, 0x58, 0xab, 0xd8, 0x11, 0x5e, 0xb5, 0xd0, 0x97, 0x99, 0x7b, 0xa3, - 0x9e, 0xdd, 0x9b, 0xfb, 0x86, 0xb4, 0x3b, 0xd1, 0x0b, 0xfc, 0x09, 0x0a, 0x2d, 0xa8, 0x3f, 0xd6, - 0x7d, 0xe3, 0xa7, 0xfa, 0x31, 0xd6, 0xdb, 0xa1, 0xfe, 0x60, 0x1b, 0x54, 0x65, 0xfc, 0x77, 0x6b, - 0x7b, 0xf6, 0x07, 0x59, 0x74, 0xaa, 0x7b, 0xed, 0x2a, 0x9b, 0x8e, 0x14, 0xa5, 0x37, 0x37, 0xe8, - 0x10, 0x30, 0xce, 0x3b, 0x94, 0x55, 0x65, 0x6c, 0x29, 0x5a, 0x37, 0xd7, 0xc8, 0xc4, 0x3a, 0xa4, - 0x5a, 0x4b, 0x90, 0x2e, 0x28, 0x63, 0xa6, 0x5e, 0xf6, 0x82, 0x64, 0x82, 0xaf, 0x47, 0x62, 0x69, - 0x4c, 0xe9, 0xb8, 0xa5, 0x6d, 0x88, 0xf5, 0x5b, 0x1e, 0x44, 0x1b, 0xf3, 0x2b, 0x05, 0x13, 0xe8, - 0x97, 0x0c, 0x8d, 0x13, 0xd7, 0x74, 0x31, 0x29, 0x4a, 0x9f, 0x40, 0x71, 0x17, 0x3e, 0x08, 0x01, - 0xd8, 0x69, 0x0e, 0x20, 0xd9, 0x46, 0x11, 0x16, 0xd4, 0x7b, 0xe6, 0x7f, 0x4e, 0x75, 0xeb, 0xab, - 0xda, 0x7e, 0xea, 0x0d, 0x3b, 0x1a, 0xc7, 0xfb, 0x92, 0x96, 0x1d, 0x9d, 0xc1, 0x4a, 0xd3, 0x0e, - 0xac, 0x01, 0x89, 0x05, 0x69, 0xd7, 0x59, 0xd2, 0xf4, 0x83, 0x0d, 0x3b, 0xc5, 0x11, 0x16, 0xaa, - 0xb7, 0xdc, 0xee, 0x52, 0xdd, 0x36, 0x36, 0x72, 0x71, 0x15, 0x86, 0xfb, 0x8a, 0x8f, 0x4b, 0x47, - 0xef, 0x33, 0xe9, 0xd8, 0x2a, 0x0d, 0x47, 0xb8, 0xdb, 0x98, 0x2e, 0xe7, 0xa5, 0x5e, 0x30, 0xe3, - 0xf3, 0x83, 0x4d, 0x4c, 0xff, 0x61, 0x6d, 0x49, 0xba, 0xa8, 0x57, 0x63, 0x4c, 0x32, 0x97, 0x7a, - 0xe7, 0xaf, 0x9c, 0x21, 0x91, 0xcb, 0xa9, 0x1c, 0xfd, 0x98, 0xbb, 0x1f, 0x97, 0xa7, 0xcc, 0x40, - 0x2b, 0x2f, 0xe2, 0x21, 0xf1, 0x10, 0x23, 0xcb, 0xda, 0x5c, 0x9a, 0x14, 0xad, 0x62, 0x71, 0xfe, - 0xb5, 0xd4, 0xe9, 0x50, 0xd9, 0xba, 0x8e, 0xe7, 0x30, 0x2d, 0xb7, 0x6e, 0x74, 0xc9, 0x99, 0x92, - 0x99, 0x63, 0xd0, 0xbd, 0xb1, 0xc5, 0x8d, 0x7b, 0xa8, 0xaf, 0xa8, 0xd4, 0x12, 0x7c, 0x54, 0x15, - 0xc4, 0x52, 0x43, 0x70, 0xa6, 0x08, 0x53, 0x2c, 0xd7, 0x5a, 0x66, 0xf8, 0x2a, 0x62, 0x45, 0x57, - 0x66, 0xeb, 0x28, 0x82, 0x54, 0xf0, 0xc8, 0x17, 0xc6, 0xf4, 0xb4, 0x1c, 0x72, 0xb6, 0x3b, 0x32, - 0x22, 0x40, 0xa8, 0xe0, 0xd6, 0x32, 0x7c, 0x65, 0xe1, 0x3b, 0x31, 0x18, 0x6b, 0xb0, 0x59, 0x3b, - 0x7c, 0x09, 0x56, 0x56, 0xd7, 0x0e, 0x06, 0x1f, 0x54, 0x63, 0x8a, 0x0c, 0x3e, 0x6d, 0xc6, 0x67, - 0x2d, 0x11, 0x31, 0xb5, 0x5c, 0x38, 0xe6, 0x62, 0xaa, 0x76, 0x49, 0x23, 0xf9, 0x96, 0x56, 0x2b, - 0xbb, 0xa2, 0xec, 0x1d, 0x78, 0xca, 0xbc, 0xea, 0xf9, 0x86, 0x89, 0xd0, 0x64, 0x07, 0x9a, 0x02, - 0xf9, 0x9c, 0x95, 0x01, 0x6f, 0x32, 0x8b, 0xf7, 0x37, 0xb4, 0x1d, 0xb0, 0x55, 0x4a, 0x35, 0x40, - 0x2b, 0xea, 0x59, 0x35, 0x2f, 0x8a, 0xac, 0x20, 0xcd, 0xca, 0xa6, 0x0f, 0xc3, 0x04, 0xc6, 0x51, - 0x87, 0x2b, 0xe0, 0xa9, 0x54, 0x2d, 0x15, 0x90, 0xf8, 0xcf, 0x3c, 0x81, 0xdd, 0xd1, 0x7f, 0x41, - 0xc1, 0x06, 0xd9, 0x42, 0xfa, 0x9f, 0xca, 0x57, 0x2d, 0xca, 0x09, 0xa3, 0xa4, 0xcd, 0x5e, 0x60, - 0xd4, 0xdb, 0xea, 0xc9, 0x2e, 0x22, 0x37, 0x60, 0x96, 0xb5, 0xd3, 0xef, 0x11, 0xe7, 0xfe, 0x58, - 0x5d, 0x97, 0xdb, 0x6a, 0x8f, 0x31, 0xfd, 0xd5, 0xc2, 0x71, 0x85, 0x08, 0x0f, 0x50, 0x52, 0xcc, - 0x3d, 0x17, 0xa3, 0xd4, 0x42, 0xd1, 0x61, 0x0f, 0xc4, 0x38, 0x5c, 0xfd, 0x2d, 0x19, 0x63, 0x6e, - 0xc6, 0x7a, 0x61, 0x2e, 0xee, 0x5b, 0xd1, 0x11, 0x27, 0x32, 0xa1, 0x74, 0x07, 0x6f, 0xd5, 0xa1, - 0xe3, 0xa5, 0xab, 0x52, 0x2b, 0x41, 0x1d, 0x26, 0x3b, 0x13, 0x1d, 0x18, 0x98, 0x32, 0xdc, 0x68, - 0xe4, 0x34, 0x4c, 0x78, 0x5e, 0x4c, 0x92, 0x20, 0xdf, 0x57, 0x4e, 0x14, 0x51, 0x37, 0x31, 0xb8, - 0xc0, 0x71, 0x78, 0x2d, 0xe1, 0x3e, 0x15, 0xe3, 0x51, 0xc9, 0xae, 0x4d, 0x81, 0xa6, 0x42, 0xe1, - 0x6e, 0x21, 0xde, 0xe3, 0x23, 0xd4, 0x31, 0xe6, 0xe8, 0x93, 0x22, 0x46, 0x3a, 0x43, 0xf3, 0xf0, - 0xc0, 0x8e, 0xb4, 0x3e, 0x9a, 0x17, 0x16, 0xf1, 0x33, 0x6b, 0xbb, 0x26, 0x70, 0x17, 0x29, 0x72, - 0xdb, 0x1a, 0xd6, 0x7e, 0xa3, 0x28, 0x43, 0xdd, 0xd5, 0x91, 0xf2, 0x09, 0x99, 0x82, 0x1d, 0x2f, - 0xac, 0x35, 0x6d, 0x21, 0xcb, 0x4e, 0xad, 0x59, 0x05, 0x2b, 0x0f, 0xbf, 0xe8, 0xcb, 0x7c, 0xfd, - 0x5a, 0x91, 0x21, 0xa7, 0x97, 0xdb, 0xdb, 0x2b, 0xbc, 0x8a, 0x1c, 0x24, 0x0c, 0x00, 0xb7, 0x2d, - 0x20, 0xb8, 0x6d, 0x18, 0x11, 0x85, 0x08, 0x3f, 0x53, 0x31, 0xc2, 0x20, 0x4c, 0xc8, 0xc8, 0xe0, - 0x56, 0x19, 0x1a, 0x5c, 0x9e, 0x14, 0x87, 0x4f, 0x3a, 0x78, 0x15, 0xf5, 0x5a, 0x9e, 0x0f, 0xdb, - 0xaa, 0x6d, 0xa6, 0xe6, 0x68, 0xd8, 0x56, 0x0d, 0xc4, 0x32, 0x36, 0x16, 0x70, 0x0d, 0x98, 0x96, - 0x60, 0x60, 0x48, 0xd2, 0x8b, 0x04, 0x1d, 0x8e, 0x2f, 0xcb, 0x35, 0x03, 0xaf, 0xf9, 0x92, 0x71, - 0x4f, 0xa3, 0xd9, 0x3a, 0xda, 0x14, 0x72, 0x3d, 0x30, 0x75, 0xd6, 0xf2, 0x93, 0x9a, 0xa3, 0x5d, - 0x2a, 0x95, 0x9e, 0x1e, 0x75, 0xbf, 0xfa, 0x24, 0x91, 0x8a, 0x25, 0xb3, 0x54, 0x48, 0xf7, 0x57, - 0x7e, 0xa8, 0x07, 0x9c, 0x57, 0xce, 0x85, 0x2d, 0xa1, 0xd5, 0x32, 0x66, 0x4f, 0x77, 0x09, 0xe0, - 0x22, 0x4c, 0x39, 0x67, 0x8d, 0x96, 0x85, 0x66, 0xe1, 0x90, 0x87, 0x87, 0x4a, 0x40, 0xa0, 0xac, - 0xab, 0xcf, 0xc4, 0x4f, 0x74, 0x85, 0xc9, 0x9f, 0xee, 0x3c, 0x27, 0xe5, 0xe8, 0xaf, 0xc3, 0x61, - 0x17, 0x56, 0x02, 0x49, 0x1c, 0xda, 0x5b, 0x2d, 0x85, 0xd1, 0xfd, 0xbf, 0xfe, 0x0f, 0x21, 0xef, - 0x20, 0xc1, 0x02, 0x89, 0x0c, 0x14, 0xab, 0xd4, 0x53, 0xaf, 0xab, 0x15, 0xf1, 0x86, 0x25, 0xfc, - 0x0e, 0x7f, 0x17, 0x2b, 0xf1, 0x4b, 0xb3, 0x0a, 0xbe, 0xc7, 0x2d, 0x36, 0x44, 0x81, 0x09, 0x4a, - 0x62, 0x7a, 0x71, 0x78, 0x02, 0x76, 0xf2, 0x6f, 0xff, 0xf2, 0xff, 0xb4, 0xac, 0xfb, 0x9f, 0xb6, - 0x94, 0x01, 0xc8, 0x22, 0xdf, 0x4c, 0xce, 0x97, 0x31, 0xb2, 0xb7, 0xa6, 0x9a, 0xdc, 0x10, 0x98, - 0xaa, 0x9e, 0x89, 0x91, 0x4e, 0x20, 0x16, 0xc4, 0x59, 0x73, 0x16, 0x72, 0x1e, 0xb9, 0x57, 0x40, - 0x81, 0x2e, 0xc5, 0x0a, 0x8b, 0xba, 0x03, 0x29, 0xb5, 0xd1, 0x79, 0x0b, 0x67, 0x0d, 0xaa, 0x51, - 0x7a, 0xaf, 0x8f, 0x7e, 0x38, 0x7a, 0x2d, 0x9a, 0x74, 0x55, 0x93, 0xbc, 0x0e, 0x5c, 0xde, 0xd7, - 0x69, 0xcb, 0xdb, 0xdd, 0xe7, 0x49, 0x8a, 0x87, 0x21, 0xf9, 0x26, 0x0c, 0xba, 0xf9, 0x81, 0xae, - 0xf5, 0x0e, 0xc2, 0xd0, 0xf9, 0x31, 0xfa, 0x31, 0xa2, 0x98, 0xbe, 0x6b, 0xba, 0x9f, 0x8f, 0x03, - 0xfb, 0xea, 0xe3, 0xfa, 0xa4, 0x04, 0xa6, 0x5f, 0xfd, 0x93, 0x15, 0x91, 0x7c, 0x0b, 0x81, 0x7c, - 0x7c, 0x87, 0x80, 0xbc, 0xfa, 0x03, 0xaf, 0x25, 0x62, 0x87, 0x4c, 0xe5, 0x54, 0xc4, 0xc3, 0x88, - 0xb4, 0x53, 0x20, 0xe8, 0x9c, 0x62, 0x03, 0x37, 0x21, 0x5a, 0x5e, 0xd6, 0x3f, 0x11, 0x32, 0x8b, - 0x6b, 0x06, 0xfa, 0xa2, 0xa0, 0x54, 0x2d, 0x56, 0x11, 0x08, 0xc4, 0xd6, 0x88, 0x51, 0x8f, 0x5c, - 0x44, 0x72, 0x43, 0x4a, 0x90, 0x83, 0x63, 0x82, 0xf9, 0x49, 0x36, 0xaf, 0xef, 0x12, 0xf5, 0x89, - 0x2c, 0x3f, 0xd1, 0x62, 0xd1, 0xde, 0xac, 0xab, 0x58, 0xa4, 0xba, 0x2c, 0x6b, 0xaa, 0x57, 0x5c, - 0xd5, 0xd8, 0x0d, 0x1e, 0xd4, 0xe8, 0x8a, 0x9a, 0x6b, 0x5b, 0xad, 0x86, 0x79, 0xf3, 0xdb, 0xda, - 0x03, 0x2d, 0x5a, 0xd6, 0xa6, 0xfb, 0xda, 0x23, 0xbd, 0x2f, 0xf5, 0x9b, 0xde, 0x68, 0x1b, 0x58, - 0xc2, 0xbd, 0x45, 0xed, 0x5a, 0xc9, 0x80, 0x56, 0x9f, 0x47, 0x9e, 0x94, 0x56, 0xa4, 0xf0, 0xa1, - 0x7a, 0xa2, 0x4b, 0x25, 0xc4, 0x86, 0x65, 0x9b, 0x27, 0xc5, 0xf4, 0x95, 0xa4, 0x09, 0x72, 0x04, - 0x97, 0x59, 0x3d, 0x0c, 0x43, 0x0e, 0x94, 0x89, 0x37, 0x4c, 0xc9, 0x47, 0x9b, 0x4d, 0x74, 0xa6, - 0x02, 0x60, 0x1d, 0xd5, 0x1c, 0xbd, 0x6f, 0x6e, 0xd1, 0x94, 0xc8, 0xaf, 0xa9, 0xf2, 0x4e, 0x56, - 0x51, 0x5b, 0xbb, 0x7b, 0x94, 0xe8, 0xe3, 0xb6, 0xcb, 0xdb, 0x0d, 0xad, 0xfa, 0xcd, 0x45, 0x06, - 0x9c, 0xc8, 0x1b, 0x06, 0x54, 0x5f, 0x0d, 0x86, 0x72, 0xc2, 0x45, 0xf0, 0x9a, 0xe2, 0x32, 0xd4, - 0x1f, 0x4f, 0xdf, 0xc8, 0x3a, 0x4b, 0x97, 0xf5, 0x33, 0x71, 0x86, 0xaa, 0x9e, 0xec, 0x42, 0x46, - 0x01, 0x02, 0x41, 0xd4, 0x9e, 0x81, 0xc8, 0x90, 0xde, 0xca, 0xb1, 0xaa, 0xda, 0xa8, 0x38, 0xb1, - 0xfd, 0x26, 0xa6, 0xc4, 0x25, 0x97, 0xf2, 0xa0, 0xcf, 0x5c, 0xde, 0x96, 0xa5, 0xf3, 0x05, 0x73, - 0xc2, 0xf8, 0x2e, 0xda, 0xba, 0xce, 0x48, 0x31, 0x50, 0xe2, 0xa5, 0x90, 0xe1, 0x6a, 0x26, 0x52, - 0xd5, 0x2e, 0xc4, 0x17, 0xed, 0x30, 0x19, 0x23, 0xac, 0xd9, 0x1a, 0x1e, 0x96, 0x22, 0x85, 0x26, - 0x0f, 0x6a, 0x39, 0xd5, 0x4e, 0xea, 0xd9, 0x93, 0xca, 0x13, 0xa7, 0x87, 0xd9, 0x4d, 0x30, 0x0d, - 0xdc, 0x49, 0x45, 0x84, 0x33, 0x17, 0x1f, 0x06, 0xf3, 0x1a, 0x07, 0x7c, 0xa8, 0x86, 0x96, 0x09, - 0x4e, 0x07, 0xb8, 0x19, 0x79, 0x55, 0x22, 0xab, 0x56, 0xd1, 0x9b, 0x0a, 0x6a, 0xac, 0xa1, 0x3a, - 0xfe, 0x5f, 0x1d, 0xed, 0xe9, 0x02, 0x97, 0xa5, 0x48, 0x4a, 0x91, 0x98, 0x2e, 0x1b, 0x6a, 0x1b, - 0x61, 0x31, 0x93, 0x48, 0x01, 0x2b, 0x57, 0x7a, 0x21, 0xe3, 0x15, 0xd9, 0x1e, 0xb7, 0xea, 0x21, - 0xe9, 0x47, 0x19, 0x97, 0x83, 0x32, 0x73, 0x96, 0xfa, 0x28, 0x3b, 0xe1, 0x45, 0x52, 0x28, 0x6d, - 0x21, 0x41, 0x2d, 0xd7, 0x6a, 0xb0, 0x44, 0x51, 0x5e, 0x2e, 0x98, 0x92, 0x22, 0xa4, 0x13, 0x6b, - 0x92, 0xc0, 0xe6, 0x97, 0xfa, 0xe3, 0x65, 0x47, 0xec, 0xeb, 0x0e, 0xcc, 0x43, 0x9d, 0x0e, 0x8b, - 0x6c, 0xc5, 0x59, 0xf9, 0xe1, 0xa1, 0x3c, 0x5f, 0xff, 0x90, 0x03, 0xf6, 0xb2, 0xd2, 0x56, 0x71, - 0xbe, 0x5e, 0x9d, 0xc6, 0x80, 0x06, 0x9e, 0x21, 0xcd, 0xad, 0x48, 0x3b, 0x3a, 0x72, 0xd3, 0x36, - 0x66, 0xdb, 0xad, 0xea, 0x8c, 0xf0, 0x4e, 0x9e, 0xd8, 0x4e, 0xb2, 0x12, 0x20, 0xf4, 0xe0, 0x99, - 0x41, 0xc4, 0x72, 0xab, 0x8d, 0x57, 0x66, 0xee, 0xa3, 0x46, 0xa0, 0xaa, 0x46, 0x10, 0x50, 0xa3, - 0x92, 0xf4, 0x16, 0xcb, 0x20, 0x1c, 0x52, 0x4e, 0xa1, 0xb0, 0x7e, 0xa0, 0x1d, 0xed, 0x72, 0x71, - 0x44, 0xb6, 0x38, 0x3c, 0xd9, 0x6b, 0x84, 0x30, 0xdd, 0x6b, 0x67, 0x7a, 0xcd, 0x39, 0x3e, 0xfe, - 0xbe, 0x9a, 0x01, 0xb4, 0x32, 0xb1, 0xe4, 0xb1, 0x3c, 0xfe, 0xbe, 0xb9, 0x3c, 0x67, 0x6f, 0x75, - 0x24, 0xc1, 0x2f, 0x6d, 0xbc, 0x7e, 0x66, 0x96, 0xa1, 0x07, 0x0b, 0x88, 0xdd, 0xd2, 0x4d, 0x20, - 0x49, 0xea, 0x6f, 0x56, 0x17, 0x0a, 0x56, 0x52, 0xff, 0x96, 0x66, 0x0d, 0x19, 0x55, 0x28, 0xbf, - 0x43, 0xc9, 0xaa, 0xd8, 0xf8, 0x9a, 0x2d, 0x4e, 0x85, 0xbe, 0x5b, 0xa5, 0xc4, 0x25, 0x32, 0x53, - 0xf0, 0x8b, 0x7e, 0x4c, 0xc7, 0x54, 0x26, 0xe1, 0x85, 0x79, 0x0e, 0x91, 0xc5, 0xa6, 0x96, 0xce, - 0xab, 0xc8, 0xfc, 0x4b, 0x31, 0xef, 0xd6, 0x7b, 0x1c, 0x05, 0x1e, 0x13, 0x14, 0x0b, 0xff, 0xfb, - 0x81, 0x42, 0xa4, 0xf0, 0x7f, 0x78, 0x24, 0xe1, 0xc7, 0x2d, 0x9c, 0x4c, 0x4c, 0xfa, 0x81, 0xf7, - 0xd8, 0xa0, 0x2d, 0xd7, 0x77, 0xf3, 0xe6, 0x7e, 0x97, 0x8e, 0xb6, 0xc3, 0x47, 0x5d, 0xbb, 0x2b, - 0x94, 0xf3, 0x04, 0xe5, 0xcc, 0x54, 0x65, 0x39, 0xd0, 0xf3, 0x1a, 0x41, 0xeb, 0xdb, 0x98, 0xad, - 0xd4, 0x21, 0x34, 0x92, 0xe9, 0x19, 0x7e, 0x7a, 0x47, 0x91, 0xd7, 0xdc, 0x39, 0x40, 0x98, 0xd2, - 0xaa, 0x94, 0xb0, 0x2f, 0x42, 0x3c, 0x03, 0xaa, 0x69, 0x97, 0x65, 0x7a, 0xd4, 0x2e, 0x7c, 0x45, - 0xdf, 0x07, 0xd5, 0x5e, 0xec, 0x86, 0xc6, 0x2a, 0x17, 0x51, 0x0f, 0x1d, 0x58, 0xa1, 0xdd, 0x2e, - 0x96, 0xff, 0xc7, 0xd3, 0x77, 0x6f, 0x1d, 0x3e, 0xf3, 0x17, 0x4c, 0x14, 0x52, 0x6d, 0x19, 0x7e, - 0xb1, 0xd3, 0x5a, 0x54, 0x65, 0x09, 0xe4, 0x7a, 0x38, 0x15, 0x10, 0x1a, 0x47, 0xac, 0x21, 0x97, - 0x23, 0x3a, 0xfd, 0xab, 0x33, 0xc5, 0x7a, 0x5d, 0x03, 0x6f, 0xec, 0x4e, 0x73, 0x5e, 0x0c, 0x9b, - 0xca, 0xe1, 0x4c, 0x53, 0xca, 0xa3, 0xcd, 0x34, 0x25, 0x99, 0xf2, 0x11, 0x81, 0x2b, 0x4e, 0xfa, - 0x4a, 0x36, 0x2c, 0x37, 0x74, 0x3d, 0x3d, 0xc6, 0x28, 0x8c, 0x47, 0x32, 0x9c, 0xed, 0x05, 0xfc, - 0x6c, 0x7e, 0x5c, 0x83, 0xb5, 0x4f, 0xf6, 0x1d, 0xce, 0x5f, 0xdf, 0x22, 0xed, 0x9b, 0xf3, 0x72, - 0x75, 0x30, 0x37, 0xb7, 0x75, 0x6f, 0x48, 0xff, 0xee, 0x0a, 0x87, 0x80, 0xab, 0xba, 0xed, 0xaa, - 0x8c, 0x5e, 0x1f, 0x4e, 0x5e, 0xcb, 0x42, 0x1c, 0x7f, 0x04, 0xcf, 0x4d, 0xec, 0x59, 0x51, 0x4e, - 0xa5, 0xf7, 0x42, 0x94, 0x06, 0xbf, 0x9c, 0xf3, 0x42, 0x3e, 0xb7, 0xb6, 0x8b, 0xbc, 0x64, 0x98, - 0x89, 0xec, 0xf8, 0xf4, 0x9d, 0x4a, 0x43, 0x26, 0x93, 0xe4, 0x76, 0xed, 0xde, 0x13, 0xcd, 0x85, - 0xde, 0x47, 0x27, 0x46, 0x1b, 0x8d, 0x07, 0x94, 0x4e, 0xdc, 0x52, 0xd0, 0x29, 0xd0, 0x43, 0x89, - 0xcf, 0xd8, 0x97, 0xd4, 0xbf, 0x8a, 0x2f, 0xb5, 0xbe, 0x70, 0x47, 0x5b, 0xba, 0x0a, 0x63, 0x01, - 0x7b, 0x4b, 0xd4, 0x4a, 0xcc, 0xe4, 0xfc, 0xf1, 0xa6, 0xab, 0xd3, 0x44, 0xdd, 0x7c, 0x98, 0x7b, - 0xa4, 0x9c, 0x9b, 0x3a, 0xa2, 0x08, 0x66, 0x92, 0x28, 0xc8, 0x25, 0xa0, 0x99, 0x22, 0xf0, 0x38, - 0x7a, 0xe1, 0x51, 0xa2, 0xd4, 0x60, 0x1f, 0xbb, 0x9f, 0x94, 0xdd, 0x01, 0x9f, 0x57, 0x28, 0x75, - 0x39, 0x1f, 0x9d, 0x91, 0xe9, 0xd6, 0xf1, 0x4e, 0x67, 0x7c, 0xd3, 0x34, 0xb3, 0xe7, 0x56, 0xf2, - 0xb1, 0x6b, 0x24, 0xd7, 0xe1, 0x4e, 0x59, 0xf6, 0x1d, 0x8c, 0x7c, 0x1a, 0x7b, 0x7d, 0xeb, 0xfd, - 0xbb, 0xd3, 0x33, 0xcb, 0xe6, 0xb0, 0x99, 0xac, 0x7f, 0x67, 0x49, 0xea, 0x6f, 0xd3, 0x8d, 0x12, - 0x75, 0x84, 0x62, 0xa3, 0x2b, 0xa3, 0x8f, 0xad, 0x9a, 0x34, 0x53, 0x9e, 0xc6, 0x2f, 0xd3, 0xbd, - 0x4b, 0xea, 0xa6, 0xf3, 0xf1, 0xf5, 0x98, 0xe7, 0xfe, 0xe0, 0xb5, 0x9c, 0x73, 0xd0, 0x8e, 0xb3, - 0x0c, 0x2f, 0xc4, 0x2e, 0x02, 0x5e, 0xb4, 0xd3, 0xf1, 0xd6, 0x31, 0x15, 0x24, 0xd3, 0xd7, 0xcf, - 0x8b, 0xa6, 0xaf, 0xc4, 0xe5, 0xeb, 0xcc, 0x71, 0x8a, 0xe6, 0xb8, 0x41, 0xd8, 0x9a, 0xc2, 0x53, - 0x9d, 0x4e, 0x06, 0xb5, 0x7a, 0x3a, 0xa5, 0xd3, 0x57, 0x32, 0x43, 0x8e, 0x8a, 0xe0, 0xfd, 0xf1, - 0x0d, 0xde, 0x21, 0xd8, 0x66, 0x47, 0x97, 0xe7, 0x67, 0xe3, 0x34, 0x48, 0x72, 0xf4, 0xa6, 0x72, - 0xc0, 0x21, 0xee, 0x00, 0x82, 0x0c, 0xc9, 0xf2, 0x7a, 0xec, 0x34, 0xf0, 0xa4, 0x60, 0x88, 0x72, - 0x12, 0xec, 0xa3, 0x8c, 0xad, 0xe3, 0xef, 0xcb, 0x4b, 0x7f, 0x98, 0x32, 0x42, 0xe8, 0x53, 0xea, - 0xe2, 0xa5, 0xd2, 0x1f, 0xef, 0xa2, 0xbe, 0x75, 0x7b, 0x1e, 0x4f, 0x32, 0x98, 0xa8, 0x71, 0xbf, - 0x77, 0x6f, 0xe3, 0x8b, 0x79, 0xf5, 0xc5, 0x55, 0xf5, 0xc5, 0xcc, 0x85, 0xf5, 0x73, 0x83, 0x2f, - 0x9e, 0xd8, 0x00, 0x2f, 0xeb, 0xef, 0xde, 0x7f, 0xc2, 0x58, 0xc7, 0x74, 0xe7, 0x56, 0x02, 0xad, - 0x29, 0x41, 0x35, 0x61, 0xf3, 0x3c, 0xbf, 0xed, 0x1d, 0x30, 0x2c, 0xaa, 0x13, 0x8f, 0xc6, 0xb2, - 0x0e, 0x60, 0xe0, 0x3c, 0xd5, 0x9b, 0x85, 0xe7, 0x8b, 0x85, 0x17, 0xa3, 0xca, 0x8b, 0x91, 0x09, - 0xeb, 0x3c, 0xe9, 0x7d, 0x31, 0x70, 0x1e, 0x68, 0x44, 0x99, 0x1b, 0xa8, 0xfe, 0x79, 0x41, 0x7a, - 0x9e, 0x4f, 0xf1, 0x1e, 0x86, 0xa2, 0x86, 0xef, 0x5d, 0xf8, 0xe7, 0xd9, 0x2c, 0x8e, 0xf3, 0xe9, - 0xf9, 0xed, 0x92, 0xf7, 0x63, 0x0d, 0x22, 0xcd, 0xfa, 0x39, 0x67, 0x7b, 0x64, 0xa0, 0x93, 0xd4, - 0xff, 0xa5, 0x1e, 0x2a, 0x08, 0x91, 0x7e, 0xf5, 0xcb, 0x78, 0x0a, 0xd2, 0xaa, 0x4b, 0x6f, 0xcf, - 0x67, 0xee, 0xcd, 0xb2, 0x2f, 0xc1, 0xd2, 0x3a, 0x78, 0xf9, 0x45, 0xf1, 0x05, 0x93, 0x14, 0x63, - 0x76, 0x9b, 0x4a, 0x05, 0xed, 0x75, 0xa4, 0xf5, 0x7d, 0x9c, 0xc6, 0x19, 0x9e, 0xf2, 0xbb, 0x94, - 0x3d, 0x57, 0xc5, 0xea, 0x6a, 0x8e, 0x6e, 0x25, 0x3a, 0xf6, 0x79, 0xf6, 0xf7, 0xf9, 0x7b, 0x5e, - 0x5e, 0xea, 0x53, 0xd4, 0x01, 0x49, 0x11, 0xb4, 0x3a, 0xad, 0x9d, 0x6b, 0x2f, 0x3d, 0x1f, 0xcf, - 0x41, 0x47, 0x3a, 0x77, 0xbd, 0x2b, 0xd5, 0x56, 0x18, 0xe3, 0xb5, 0x33, 0x45, 0x25, 0xa2, 0xdf, - 0x73, 0xba, 0x68, 0xfc, 0xbc, 0xbb, 0xe4, 0x7d, 0x4f, 0xef, 0x18, 0xc5, 0x73, 0xc2, 0xea, 0xe7, - 0x6f, 0x3a, 0x76, 0xa8, 0x25, 0x3c, 0x9a, 0x76, 0x9e, 0xe1, 0xa5, 0x52, 0xd4, 0x0d, 0xba, 0x37, - 0xab, 0xb4, 0x59, 0x90, 0xe7, 0xfd, 0xf8, 0x7b, 0x12, 0xa8, 0xca, 0x4c, 0x22, 0xba, 0x4c, 0x8d, - 0x2f, 0xf9, 0x42, 0x29, 0x4c, 0xc9, 0xee, 0x30, 0x5b, 0x51, 0xb1, 0x52, 0x19, 0xcb, 0x9b, 0xb9, - 0x4a, 0xcd, 0x4e, 0x85, 0xb3, 0xf9, 0x88, 0x77, 0x4f, 0xd8, 0x7c, 0xf0, 0x23, 0x65, 0x89, 0x97, - 0x09, 0x3b, 0x15, 0xf3, 0xa6, 0x90, 0x8b, 0x61, 0xb9, 0x82, 0x3f, 0x22, 0x2c, 0xc5, 0xbf, 0xe5, - 0xe7, 0xbf, 0xfc, 0x85, 0x40, 0x63, 0x1e, 0x7c, 0xe6, 0xde, 0x80, 0xa8, 0x08, 0xb6, 0x11, 0xba, - 0x14, 0xf4, 0x9b, 0x38, 0x9d, 0x35, 0xb1, 0x12, 0xb3, 0x27, 0x3d, 0xde, 0x64, 0x95, 0xfc, 0xeb, - 0xcb, 0xea, 0xf2, 0x6c, 0x7f, 0x6d, 0x32, 0xc9, 0x55, 0xf5, 0xb3, 0x00, 0xaf, 0xa0, 0x51, 0xb5, - 0x97, 0x79, 0x42, 0xd7, 0x41, 0x21, 0xde, 0xdd, 0xa6, 0xeb, 0x85, 0x5a, 0x05, 0x77, 0x2c, 0x73, - 0x9a, 0xae, 0xaf, 0xca, 0xa7, 0xe8, 0x5a, 0x06, 0x67, 0x7d, 0x58, 0xcd, 0x09, 0x94, 0x94, 0xf6, - 0xb2, 0xba, 0x7d, 0x77, 0x01, 0xd5, 0x54, 0xfb, 0xad, 0x49, 0x20, 0xe5, 0xa5, 0x9c, 0xc3, 0x87, - 0x20, 0x7d, 0x25, 0x1d, 0x14, 0xed, 0x68, 0x9b, 0x39, 0x16, 0x6a, 0xdd, 0x69, 0xa2, 0xdb, 0xef, - 0x98, 0x21, 0xe9, 0x13, 0x17, 0x65, 0xe7, 0x4d, 0x1a, 0xd0, 0x23, 0x25, 0xb4, 0xae, 0x37, 0x0e, - 0xf5, 0x53, 0xf7, 0x7a, 0x4e, 0x5b, 0xdc, 0xc4, 0xdb, 0x5e, 0x30, 0x6b, 0x0d, 0xe8, 0xe8, 0x3c, - 0x3a, 0x59, 0xf9, 0x10, 0x7e, 0xe3, 0x50, 0x2a, 0x4a, 0xb0, 0x39, 0x16, 0xa3, 0x02, 0xb9, 0xcb, - 0x71, 0x64, 0xac, 0x03, 0xfd, 0x6b, 0x0d, 0x7e, 0x97, 0xb0, 0x5b, 0x33, 0x8a, 0x21, 0x10, 0x43, - 0x8d, 0x98, 0x9b, 0x90, 0x1d, 0x5a, 0x19, 0xa4, 0x2b, 0x78, 0x66, 0x90, 0x89, 0x32, 0x55, 0xf3, - 0x2f, 0x47, 0x61, 0xde, 0x70, 0x6b, 0x69, 0x43, 0xe9, 0x73, 0x3e, 0x76, 0xda, 0xc4, 0xb1, 0x66, - 0xe9, 0x4d, 0xb0, 0xf5, 0x34, 0xa9, 0xb5, 0xb8, 0x1e, 0x5a, 0xeb, 0x33, 0x96, 0xaf, 0x9e, 0xcd, - 0xa1, 0xbe, 0xda, 0x84, 0x26, 0xed, 0x99, 0xd9, 0xef, 0xa6, 0x6e, 0x56, 0xde, 0x3c, 0x60, 0x29, - 0xdf, 0x08, 0x06, 0xbe, 0x26, 0x65, 0x5a, 0x3f, 0xd4, 0x2d, 0xa7, 0xf9, 0x2c, 0x5c, 0x4d, 0x01, - 0xd3, 0xbd, 0x43, 0x63, 0x2a, 0x9f, 0x76, 0xf0, 0x4d, 0x81, 0xbf, 0xb2, 0xa5, 0x4a, 0xba, 0x09, - 0x19, 0x5f, 0x89, 0xe9, 0x7a, 0x08, 0xaf, 0xca, 0x5d, 0xf3, 0x8c, 0xfc, 0xe1, 0x1c, 0xad, 0x69, - 0x64, 0x59, 0xa3, 0xae, 0x6c, 0x2f, 0xf6, 0x85, 0x5d, 0xa2, 0x69, 0x7c, 0x5d, 0x89, 0xd4, 0x2c, - 0x3e, 0xc9, 0x44, 0x13, 0xb2, 0x01, 0x15, 0x5f, 0xb3, 0x08, 0xd6, 0x08, 0x34, 0x85, 0xda, 0x6b, - 0x62, 0x4d, 0x31, 0x53, 0x04, 0xa2, 0x82, 0xc0, 0xb6, 0x0d, 0x1c, 0x34, 0xac, 0x6d, 0x39, 0x84, - 0x6d, 0x4b, 0x0b, 0xd3, 0x63, 0x80, 0xc7, 0xdf, 0x4b, 0x84, 0x34, 0x7f, 0xb4, 0x8c, 0x5a, 0x3f, - 0xae, 0x8e, 0x3c, 0x2d, 0x7a, 0xd4, 0x06, 0x25, 0x06, 0x43, 0xd1, 0xab, 0xd1, 0xa7, 0xda, 0xda, - 0x59, 0x3c, 0xd4, 0x31, 0xa1, 0x93, 0x13, 0x15, 0xe2, 0xd5, 0x9d, 0xe8, 0x3a, 0x75, 0x7f, 0x9c, - 0x78, 0x4e, 0xf4, 0xe9, 0x4b, 0x21, 0xde, 0xda, 0x46, 0x70, 0x48, 0x19, 0x26, 0xe6, 0x71, 0x53, - 0xf3, 0x9c, 0x31, 0xc5, 0x51, 0xf4, 0xb4, 0x08, 0xd0, 0xb2, 0xbd, 0x9a, 0x70, 0xcd, 0x85, 0x46, - 0xa8, 0x8c, 0x8c, 0x96, 0x24, 0x64, 0x0e, 0x1b, 0x26, 0x6b, 0x51, 0xcd, 0x17, 0xf1, 0x93, 0x20, - 0xe8, 0x63, 0x4c, 0xf0, 0x33, 0x72, 0x17, 0x37, 0x0e, 0xd7, 0xa5, 0xd7, 0x03, 0xc9, 0x1b, 0xd0, - 0x53, 0xc9, 0x08, 0x85, 0x11, 0x33, 0xcf, 0x08, 0x73, 0x7d, 0x23, 0x15, 0xa3, 0xda, 0x03, 0xe8, - 0xd8, 0x3c, 0x8e, 0x0e, 0x7f, 0x01, 0xf3, 0xc0, 0x9f, 0x83, 0x9a, 0x11, 0x9a, 0x18, 0x65, 0x29, - 0xba, 0x8d, 0xa2, 0x7d, 0x91, 0x26, 0x04, 0x1f, 0x80, 0x9f, 0xc2, 0x8a, 0x07, 0x79, 0xa6, 0x3d, - 0xc6, 0x5b, 0xef, 0x40, 0x94, 0x97, 0x46, 0x1b, 0xa0, 0x33, 0x68, 0x60, 0xdb, 0xb2, 0x7b, 0x93, - 0xb4, 0xd5, 0xd0, 0xb3, 0x85, 0xe3, 0xcc, 0x53, 0xf0, 0xf5, 0xb0, 0x3b, 0x08, 0x9e, 0x52, 0xf3, - 0xc1, 0xf6, 0xb6, 0x11, 0x67, 0xfb, 0x87, 0xe1, 0x99, 0xca, 0x04, 0xde, 0x0d, 0x96, 0x08, 0x4c, - 0xc4, 0x03, 0x32, 0x3f, 0x06, 0x9f, 0x9e, 0x3d, 0xeb, 0x9a, 0xa8, 0xd7, 0x83, 0x52, 0xcb, 0x6e, - 0xe9, 0xf4, 0x5c, 0x96, 0xa8, 0xff, 0xce, 0x5f, 0x97, 0x21, 0x56, 0xc6, 0x69, 0x15, 0x2d, 0x96, - 0xe5, 0x56, 0x66, 0x6a, 0x29, 0xce, 0x7a, 0xd0, 0xb3, 0xb1, 0xf5, 0x2f, 0xac, 0x5d, 0x40, 0x3f, - 0x07, 0x16, 0x3c, 0x0f, 0xc3, 0x32, 0x45, 0xfc, 0x66, 0xcd, 0x49, 0xd7, 0x8c, 0xd6, 0xe0, 0x82, - 0xa8, 0x51, 0xd7, 0xde, 0x09, 0x27, 0x7f, 0xfb, 0xfd, 0xad, 0xd1, 0x01, 0x1f, 0xa3, 0x39, 0x80, - 0xfe, 0x12, 0x5f, 0x2e, 0x87, 0x5d, 0xdd, 0xae, 0x97, 0x09, 0x0f, 0x58, 0xa3, 0xfa, 0xbd, 0xe6, - 0xf4, 0x92, 0x49, 0x67, 0xda, 0x0d, 0x5e, 0xf0, 0x8c, 0x2e, 0x9f, 0x22, 0x5e, 0x9a, 0x76, 0x6a, - 0xd0, 0x20, 0x9c, 0x38, 0x25, 0x17, 0x0b, 0xbe, 0x22, 0xfa, 0x1a, 0x68, 0x65, 0x40, 0xed, 0x3c, - 0xba, 0x82, 0x2d, 0x13, 0x0d, 0xb8, 0x18, 0xd3, 0x0b, 0xdb, 0x26, 0x81, 0xb5, 0x95, 0x2c, 0xd7, - 0xd4, 0x56, 0x02, 0x33, 0xdd, 0xc5, 0xa3, 0x3b, 0x32, 0x94, 0x46, 0x8b, 0xa3, 0xfe, 0x6a, 0x38, - 0xa4, 0x07, 0xbd, 0x0b, 0x65, 0xac, 0xa5, 0x0a, 0x53, 0xac, 0xb7, 0x0d, 0x7c, 0x53, 0x26, 0x54, - 0x07, 0x09, 0xa8, 0xd6, 0x38, 0xb0, 0x44, 0x22, 0xb8, 0x37, 0x9c, 0x9a, 0x35, 0x73, 0x75, 0xb7, - 0xf5, 0x7b, 0xe5, 0xfb, 0xdf, 0x2f, 0xdd, 0x2f, 0x4a, 0xcb, 0xd5, 0xdd, 0xae, 0xa0, 0x5e, 0x1b, - 0x08, 0xef, 0x41, 0xe6, 0x4c, 0x19, 0xaa, 0xa5, 0x33, 0x1b, 0x75, 0xb9, 0x0e, 0x86, 0xff, 0x44, - 0xcf, 0xac, 0x9e, 0x85, 0x77, 0x22, 0xb7, 0x4a, 0x49, 0x30, 0xd5, 0x0c, 0x43, 0x5a, 0x3d, 0x21, - 0xcb, 0x2b, 0x89, 0x87, 0x2e, 0x4a, 0x95, 0x51, 0xd5, 0x8b, 0xa6, 0xa1, 0x9a, 0x48, 0xa8, 0x6f, - 0x4c, 0xcb, 0x69, 0xcd, 0x44, 0x6f, 0x64, 0xc1, 0x5b, 0xe4, 0x27, 0x75, 0xaa, 0xc4, 0x43, 0x34, - 0x01, 0x4d, 0xd4, 0xe3, 0x50, 0xbb, 0xa1, 0x0c, 0xb4, 0x1b, 0xd2, 0x5d, 0x67, 0x2b, 0x05, 0x01, - 0x79, 0xe7, 0x18, 0xae, 0x90, 0x4c, 0xd7, 0x5a, 0x16, 0x97, 0xe9, 0xc7, 0x0d, 0xd8, 0xff, 0x27, - 0x5d, 0x20, 0x67, 0xa0, 0xea, 0xba, 0x94, 0xca, 0x11, 0x63, 0xb9, 0xbf, 0x46, 0x32, 0x0a, 0xc0, - 0x2b, 0xb6, 0x59, 0x3c, 0xa4, 0xcd, 0xc6, 0xcd, 0x0c, 0x28, 0x2e, 0x9e, 0xf9, 0xcc, 0x05, 0x8a, - 0xa5, 0x0e, 0xeb, 0xb0, 0xca, 0x09, 0xb4, 0x36, 0x4b, 0x80, 0xd5, 0x06, 0xe5, 0x69, 0xb3, 0xa2, - 0x68, 0x8d, 0xf8, 0xc1, 0xc2, 0x10, 0xb7, 0x8d, 0x97, 0x6c, 0x68, 0xac, 0xa5, 0x22, 0x1f, 0x70, - 0xc9, 0x9a, 0x0e, 0xe3, 0xa1, 0x1d, 0xb3, 0xbf, 0xea, 0xe8, 0x8d, 0x6d, 0x19, 0x47, 0x6e, 0x0b, - 0xfa, 0xff, 0x9c, 0x15, 0xa0, 0xf0, 0x0d, 0x4b, 0x80, 0xb3, 0x4b, 0x55, 0x43, 0x12, 0xcd, 0xf0, - 0x3f, 0xe3, 0xc4, 0x49, 0x56, 0xe1, 0xae, 0x55, 0x64, 0x0e, 0x4b, 0xa6, 0x8a, 0xbf, 0x56, 0x85, - 0x19, 0xde, 0xb7, 0x96, 0x8a, 0x4f, 0x2a, 0x90, 0xcf, 0x74, 0x48, 0x73, 0xaf, 0xd7, 0x46, 0x1a, - 0x9a, 0xba, 0x92, 0x4c, 0x16, 0x5c, 0x2c, 0x35, 0x09, 0xba, 0x0a, 0xb1, 0xd6, 0xdc, 0x7a, 0xff, - 0x19, 0xc1, 0x83, 0xc8, 0xa6, 0x35, 0x74, 0x17, 0xb1, 0x7b, 0x9c, 0xf1, 0xfb, 0x2b, 0x6c, 0xbe, - 0x30, 0x3b, 0xbf, 0x8d, 0x8b, 0x18, 0x0a, 0xa8, 0x55, 0xc4, 0xcb, 0xde, 0x6f, 0x95, 0x06, 0xd9, - 0x97, 0xcf, 0xcf, 0x8e, 0xbe, 0x7d, 0x77, 0x72, 0x7c, 0xc4, 0x97, 0xa2, 0x0b, 0x41, 0x29, 0x1e, - 0xe5, 0xdd, 0xdd, 0xe2, 0xfb, 0x39, 0x65, 0x16, 0xb1, 0x6c, 0x34, 0xfa, 0xf6, 0xad, 0x97, 0x18, - 0xe4, 0xc1, 0x11, 0x61, 0x18, 0x07, 0x0f, 0x7d, 0xc0, 0x6b, 0x1a, 0xe5, 0x19, 0xca, 0xcc, 0x11, - 0x6f, 0x62, 0xca, 0x59, 0x7d, 0xe9, 0x8b, 0x6e, 0x7b, 0x67, 0x7f, 0x9f, 0x4f, 0x23, 0xb3, 0x88, - 0x95, 0x59, 0x74, 0x02, 0x9d, 0xdd, 0x20, 0xfd, 0x8f, 0x56, 0x88, 0x21, 0x60, 0x11, 0xa0, 0x04, - 0x28, 0x8f, 0x00, 0xb8, 0x68, 0xd6, 0xb5, 0x46, 0xa9, 0xf6, 0x5e, 0x9a, 0xca, 0xe8, 0x36, 0x5d, - 0x2b, 0x9b, 0xba, 0x69, 0x22, 0x3f, 0x4c, 0xb3, 0x2b, 0xba, 0x91, 0xb6, 0xe8, 0xed, 0x5b, 0xbc, - 0xfc, 0x58, 0x9c, 0xf8, 0xde, 0x5c, 0x5e, 0xbe, 0xcb, 0xfd, 0xdd, 0x7d, 0x45, 0xc1, 0x1e, 0x3b, - 0xaf, 0x04, 0x4a, 0xa9, 0x71, 0xea, 0x86, 0x28, 0xe7, 0x93, 0xd1, 0x9c, 0xae, 0x4b, 0x06, 0xce, - 0x24, 0x6b, 0x38, 0x02, 0x4d, 0x7c, 0xd0, 0xd5, 0x34, 0x70, 0xd1, 0x8c, 0x1d, 0x4f, 0x26, 0x7e, - 0x0a, 0x33, 0x11, 0xf9, 0x20, 0xf2, 0xe2, 0xc6, 0xe7, 0xa9, 0x61, 0x56, 0xc6, 0x11, 0xa5, 0xbb, - 0x78, 0xc9, 0x2d, 0xfe, 0x39, 0xa7, 0x3b, 0xdc, 0xe9, 0x57, 0xd2, 0xa3, 0x5f, 0xe7, 0xd0, 0x8d, - 0x24, 0xb8, 0xf4, 0xf9, 0x01, 0xc4, 0x63, 0xb7, 0xfc, 0x85, 0xed, 0xf1, 0x13, 0x5b, 0x45, 0xf5, - 0xdf, 0xd5, 0x6f, 0xe7, 0xe8, 0xff, 0x35, 0x06, 0xfc, 0x12, 0x2d, 0x1a, 0xe2, 0x2f, 0x02, 0x66, - 0x24, 0x95, 0xc9, 0x2b, 0xca, 0x49, 0xc2, 0x4f, 0x49, 0x1a, 0xa3, 0x6b, 0x41, 0x0f, 0x54, 0xea, - 0x17, 0x56, 0x64, 0x78, 0x6b, 0x0b, 0x96, 0xe8, 0x05, 0xd9, 0x29, 0x71, 0x07, 0xcd, 0x64, 0xec, - 0x03, 0x9b, 0xe5, 0x05, 0x1e, 0x0c, 0x49, 0x11, 0x02, 0xa2, 0xd3, 0x18, 0xb2, 0x66, 0x39, 0xc6, - 0xc9, 0x53, 0xb6, 0x58, 0xba, 0x30, 0x98, 0xe1, 0xe3, 0xcd, 0xaa, 0x17, 0xa3, 0x73, 0x65, 0x79, - 0xb7, 0x4a, 0x43, 0xbf, 0xf1, 0xc0, 0x08, 0x4b, 0x77, 0x6e, 0xb1, 0xea, 0x2d, 0x0c, 0x2c, 0x18, - 0x9f, 0xd3, 0xb5, 0xe3, 0x5e, 0x72, 0x3e, 0x0e, 0xe7, 0x19, 0x5f, 0x6e, 0x1d, 0x8f, 0xc6, 0xe6, - 0xd8, 0x5f, 0x71, 0x51, 0x41, 0xd7, 0x4f, 0xab, 0x51, 0xff, 0x0d, 0x0f, 0xd6, 0x4b, 0x20, 0x4c, - 0x77, 0xb6, 0x48, 0x80, 0x1c, 0xf1, 0x1a, 0x1a, 0x74, 0x3c, 0x8f, 0xe3, 0x19, 0xc8, 0xad, 0x19, - 0x51, 0x93, 0x2d, 0xbe, 0x7b, 0x75, 0x02, 0x2b, 0x22, 0xf2, 0x01, 0x09, 0x49, 0x42, 0xb7, 0x17, - 0x1b, 0x23, 0xbc, 0xa6, 0x9b, 0xaf, 0x0d, 0xeb, 0xaf, 0xf1, 0x8c, 0x0e, 0x1b, 0xf9, 0x22, 0xcc, - 0x67, 0xf2, 0x57, 0x84, 0x75, 0x92, 0xc9, 0x98, 0xff, 0xe5, 0xb1, 0x4d, 0x09, 0x10, 0xfc, 0xcb, - 0x8f, 0xd9, 0x34, 0xc1, 0x1f, 0xc6, 0x68, 0x5e, 0x63, 0xd4, 0xa5, 0x16, 0xca, 0xa6, 0x06, 0x44, - 0xef, 0x81, 0xe8, 0xc9, 0x22, 0x35, 0x2e, 0xa6, 0xd9, 0x16, 0x98, 0x90, 0xb1, 0xfd, 0xfa, 0xf4, - 0xa5, 0x8d, 0x47, 0x33, 0x83, 0x31, 0xd0, 0xf2, 0x28, 0x74, 0xc7, 0x97, 0x45, 0xec, 0xe7, 0xe2, - 0x84, 0x85, 0x19, 0x76, 0x0a, 0xfe, 0x3d, 0xc7, 0xd3, 0x8d, 0x78, 0x03, 0x2e, 0xbf, 0x71, 0x2b, - 0xaf, 0x60, 0x9c, 0x3f, 0x33, 0xc2, 0x99, 0x80, 0xb3, 0x1c, 0x63, 0xf7, 0xce, 0xc3, 0x04, 0xef, - 0xb8, 0xf7, 0xdc, 0xf4, 0xf2, 0x5c, 0xf6, 0x87, 0xe7, 0x37, 0x48, 0xcd, 0x91, 0x7c, 0xeb, 0xce, - 0x66, 0x2e, 0xd0, 0xe4, 0xeb, 0x0f, 0x67, 0x6a, 0x10, 0x67, 0x88, 0x63, 0xc2, 0x19, 0x2d, 0xc4, - 0x30, 0x8e, 0x2f, 0xe7, 0x09, 0x27, 0x1b, 0x90, 0xe7, 0xbb, 0x28, 0xef, 0x7d, 0xa5, 0xbf, 0x48, - 0x3b, 0x17, 0x08, 0x0c, 0xda, 0xb9, 0x9d, 0x5f, 0x15, 0xbf, 0x5d, 0xcf, 0x4d, 0x30, 0xb8, 0x43, - 0xbe, 0x30, 0x1a, 0x3f, 0x23, 0x91, 0xae, 0x58, 0x04, 0x2f, 0x82, 0xc8, 0x4d, 0x6f, 0xc5, 0xc4, - 0x77, 0x29, 0x11, 0x24, 0xdf, 0x22, 0xeb, 0x67, 0x7d, 0x01, 0xab, 0xf9, 0x36, 0xc3, 0xeb, 0x9f, - 0xe8, 0x8e, 0x49, 0x1b, 0xa3, 0xc2, 0xa0, 0x26, 0x2d, 0x88, 0x09, 0x86, 0xf9, 0xe2, 0xf5, 0x5e, - 0x40, 0x2f, 0x11, 0x33, 0x08, 0xf8, 0xee, 0xde, 0x76, 0x22, 0xbe, 0x3c, 0xdb, 0xe8, 0x23, 0x51, - 0xf1, 0x79, 0x1e, 0x9f, 0x23, 0x40, 0x22, 0x7d, 0x80, 0x43, 0x57, 0xb1, 0x47, 0x74, 0xb9, 0xf0, - 0xb9, 0xbc, 0xef, 0x1a, 0xea, 0x9f, 0xcb, 0xfa, 0x16, 0x32, 0x21, 0x44, 0x5d, 0x1c, 0x98, 0x7d, - 0x7f, 0x7e, 0x24, 0x5e, 0x2a, 0xe6, 0xc2, 0xdd, 0x7f, 0x8e, 0x73, 0x8c, 0x0e, 0xda, 0x0c, 0x7b, - 0x0f, 0x12, 0x0a, 0xa6, 0x57, 0x2e, 0x3d, 0x88, 0x95, 0xbe, 0xb8, 0xfe, 0xb9, 0x7f, 0x75, 0x8e, - 0x14, 0x8e, 0x48, 0xf2, 0x55, 0xd3, 0xf0, 0x0b, 0x03, 0x7f, 0xe4, 0xcf, 0x09, 0xea, 0x53, 0xb4, - 0xa0, 0xca, 0x07, 0xa6, 0x4a, 0x78, 0xbe, 0x0e, 0xa2, 0xf3, 0xeb, 0x8b, 0xfc, 0x1c, 0xf5, 0x6c, - 0x09, 0x83, 0x72, 0xea, 0x9f, 0x63, 0x1f, 0xf8, 0x05, 0xfe, 0x3a, 0x0f, 0x83, 0x59, 0x90, 0x17, - 0xa0, 0xe9, 0xa0, 0xa4, 0x02, 0xc9, 0x04, 0x41, 0x3f, 0x91, 0xea, 0xcd, 0x01, 0xfe, 0xed, 0x45, - 0xdd, 0x08, 0xf1, 0x08, 0x65, 0xee, 0xb7, 0x47, 0x6e, 0x48, 0xfb, 0xc8, 0xda, 0x61, 0x5e, 0x8f, - 0xce, 0x31, 0x31, 0x9b, 0xec, 0x35, 0x3c, 0x8d, 0xf3, 0xf3, 0x6b, 0x75, 0xb3, 0x39, 0x3e, 0xcf, - 0xd0, 0x4d, 0x79, 0x1e, 0x66, 0xf2, 0x51, 0xeb, 0xa2, 0xbc, 0xf9, 0xbb, 0x92, 0x6e, 0xf8, 0xf8, - 0xfb, 0x97, 0x80, 0x9f, 0x8b, 0x98, 0x12, 0x87, 0x7c, 0x86, 0xa1, 0x7c, 0x5c, 0xd4, 0x2e, 0xac, - 0xe4, 0x75, 0x36, 0x6a, 0xcb, 0x14, 0x73, 0xa1, 0x16, 0xca, 0xb9, 0xc6, 0xe6, 0x6b, 0x88, 0xbb, - 0x98, 0x9a, 0x78, 0xa3, 0xc3, 0x89, 0x98, 0x7f, 0xd4, 0x88, 0x89, 0xe2, 0x3e, 0xb5, 0x97, 0x65, - 0x94, 0x40, 0x21, 0x73, 0x3c, 0x0d, 0x92, 0xec, 0x3b, 0x69, 0x3b, 0xb5, 0xaa, 0xf9, 0x7a, 0x28, - 0x96, 0x06, 0x40, 0x70, 0xc4, 0x4c, 0xd5, 0x1c, 0x57, 0x27, 0xf5, 0x7f, 0xd2, 0x6d, 0x66, 0xa6, - 0x0d, 0x4f, 0x68, 0x8d, 0x15, 0x96, 0x0f, 0x23, 0xc5, 0x6c, 0x7f, 0x27, 0xb9, 0x11, 0xdd, 0x45, - 0x23, 0x1d, 0xfb, 0x3e, 0xb0, 0x76, 0x61, 0x6c, 0xc2, 0xb3, 0x9f, 0x78, 0x1c, 0x37, 0xf2, 0x8c, - 0xcb, 0xe9, 0xda, 0x17, 0x21, 0x1e, 0x2a, 0x1c, 0xc5, 0x29, 0xcc, 0x67, 0xbb, 0xe6, 0xf2, 0xba, - 0x41, 0xdd, 0x85, 0x76, 0xeb, 0xac, 0x19, 0xd2, 0x8a, 0x41, 0xbf, 0xa4, 0x6d, 0x50, 0xe8, 0xa9, - 0x07, 0xf4, 0x61, 0xf1, 0xa0, 0x49, 0xb4, 0x9e, 0x88, 0xa1, 0x9e, 0x6b, 0xd7, 0x5a, 0x35, 0xac, - 0xa2, 0x07, 0xa6, 0x4f, 0x4f, 0x36, 0x8f, 0x32, 0x34, 0x8a, 0x8e, 0xb2, 0x1b, 0x13, 0xdd, 0x48, - 0x59, 0xb4, 0x50, 0x9b, 0xf7, 0xd1, 0xc4, 0x78, 0xc5, 0x4e, 0xb5, 0x60, 0x46, 0x34, 0x4b, 0x7f, - 0x76, 0x77, 0x57, 0x60, 0xeb, 0x5e, 0xd3, 0x2a, 0x28, 0xd7, 0xf3, 0x0a, 0xef, 0x0d, 0xd2, 0xee, - 0x67, 0x25, 0x33, 0xf9, 0xb1, 0xcc, 0x66, 0x22, 0xbb, 0xb2, 0xa5, 0xa6, 0x80, 0x9c, 0x00, 0x48, - 0xd1, 0x51, 0xe9, 0x03, 0x30, 0x06, 0x8a, 0xfc, 0xa8, 0x21, 0xcb, 0xe0, 0xef, 0x12, 0xd1, 0x25, - 0x90, 0x0a, 0x62, 0xb0, 0x9f, 0xab, 0x92, 0x66, 0x6b, 0x35, 0x17, 0x07, 0xc8, 0x79, 0x51, 0xd0, - 0x0c, 0x2f, 0x71, 0xbf, 0x6d, 0x2d, 0xb1, 0x55, 0xe9, 0x67, 0x4d, 0x01, 0x75, 0xda, 0xe5, 0xe5, - 0xd5, 0x50, 0x76, 0xbf, 0x98, 0x10, 0xe3, 0x48, 0x21, 0x73, 0x85, 0x87, 0x79, 0x36, 0x29, 0x68, - 0xbf, 0xa9, 0x47, 0x29, 0x2a, 0xa7, 0xe5, 0x03, 0xdd, 0x9c, 0x3a, 0x20, 0x54, 0x50, 0xa8, 0x37, - 0xbf, 0xfd, 0xa6, 0xc0, 0x61, 0x8a, 0x05, 0xab, 0x8c, 0x36, 0xc2, 0x9c, 0xd7, 0x25, 0xeb, 0xe7, - 0xae, 0xa3, 0xc8, 0xc0, 0x20, 0x17, 0xc2, 0xc1, 0x1e, 0x12, 0xc6, 0xb8, 0xfc, 0x38, 0x1d, 0x39, - 0xd0, 0x95, 0x9e, 0x3a, 0xf7, 0xab, 0xe1, 0x8e, 0x52, 0x8d, 0x62, 0xc2, 0x41, 0x72, 0x35, 0x8b, - 0xad, 0x30, 0xc7, 0x50, 0x16, 0x95, 0x53, 0xbf, 0xe6, 0xb6, 0x94, 0xba, 0x80, 0xe4, 0x0d, 0xa2, - 0x8f, 0x65, 0x34, 0x96, 0xbc, 0xda, 0x62, 0x79, 0x80, 0x2a, 0x07, 0x75, 0xc9, 0x70, 0xf0, 0xfa, - 0xc0, 0xe3, 0x74, 0xa3, 0x18, 0xf4, 0x4d, 0x63, 0xed, 0xe2, 0xcb, 0x67, 0xa9, 0x1e, 0x72, 0xde, - 0x4f, 0xf5, 0xc8, 0x3b, 0xb1, 0x2a, 0xf4, 0xee, 0x21, 0xb1, 0x77, 0x1b, 0x07, 0xdf, 0xd5, 0x44, - 0xdf, 0x5d, 0xbb, 0xb7, 0x23, 0xdf, 0x9d, 0x9d, 0xe3, 0x29, 0xa5, 0x73, 0x79, 0x45, 0xba, 0x0c, - 0xa6, 0xab, 0x46, 0xd3, 0xad, 0x0f, 0xa7, 0x33, 0x0e, 0xa0, 0xf0, 0x6c, 0xe8, 0x81, 0x74, 0xb5, - 0xf1, 0xe6, 0x2b, 0x42, 0xe9, 0x96, 0x4e, 0xf8, 0x71, 0x04, 0x13, 0xb4, 0x7c, 0x9e, 0x03, 0xf8, - 0xbc, 0x2c, 0xb0, 0x1c, 0x4f, 0x01, 0x50, 0x7a, 0x24, 0xf8, 0xf7, 0xca, 0x4f, 0xe1, 0x5f, 0x14, - 0x08, 0xb3, 0x93, 0x87, 0x04, 0x9a, 0x2b, 0x6a, 0xa8, 0x0f, 0x2b, 0xd7, 0x93, 0x8a, 0x2d, 0x2b, - 0x73, 0x85, 0xc7, 0xba, 0x30, 0x1f, 0x57, 0xfd, 0x67, 0xea, 0x92, 0x11, 0x91, 0xde, 0xbc, 0x53, - 0x37, 0xd0, 0xdc, 0xb7, 0x6a, 0x22, 0xd3, 0x17, 0x4e, 0x43, 0x7c, 0xe6, 0x49, 0x88, 0xcd, 0x4e, - 0x41, 0xdc, 0x97, 0xed, 0x02, 0x1e, 0x6b, 0x02, 0xd8, 0x53, 0xf7, 0x9a, 0x53, 0x6b, 0xc8, 0x66, - 0xa4, 0x68, 0x54, 0x5e, 0xb3, 0x41, 0x45, 0xf5, 0xe4, 0x6b, 0x43, 0xfd, 0xcb, 0xfa, 0x1b, 0x64, - 0xa0, 0x01, 0x23, 0x9c, 0xda, 0x4c, 0xd6, 0xaa, 0x5f, 0xd2, 0xa2, 0xc5, 0x0c, 0x60, 0xfe, 0x7b, - 0x4c, 0xa4, 0xae, 0x25, 0x65, 0x5a, 0x28, 0x84, 0x87, 0xfe, 0xc8, 0xab, 0x8a, 0x85, 0x3f, 0x76, - 0x3f, 0x91, 0xb0, 0x41, 0x0f, 0x32, 0x04, 0xb5, 0xa7, 0xe4, 0x0a, 0x4c, 0xe9, 0x54, 0x26, 0x73, - 0x6a, 0x7e, 0x74, 0xdb, 0xbf, 0x7e, 0x6a, 0x75, 0x2e, 0xec, 0xe6, 0xb9, 0x3d, 0x86, 0x09, 0x1b, - 0xc3, 0xee, 0xfb, 0x01, 0xb6, 0xa8, 0xf4, 0xa5, 0x9b, 0xf9, 0xcd, 0x56, 0xf5, 0xf4, 0x0a, 0x35, - 0x83, 0x47, 0xf7, 0x81, 0x91, 0x1a, 0x9d, 0xa7, 0x2f, 0xe6, 0x00, 0xee, 0xab, 0x58, 0x47, 0xba, - 0x35, 0xb0, 0xbe, 0xfa, 0xa8, 0x40, 0x41, 0x6c, 0xa6, 0x78, 0x71, 0xf5, 0x74, 0x04, 0x1b, 0x2d, - 0xc1, 0xe2, 0xb3, 0x01, 0x49, 0x72, 0x2e, 0x8b, 0xe2, 0xa6, 0x3b, 0x3a, 0x2c, 0x23, 0xb9, 0x65, - 0x6a, 0x11, 0x29, 0x48, 0x97, 0x55, 0x54, 0x8a, 0x19, 0x64, 0xe8, 0xd6, 0x60, 0xb3, 0xde, 0xc8, - 0x3a, 0xd5, 0xde, 0x54, 0x3a, 0x23, 0x4b, 0x55, 0x3b, 0xd2, 0xe9, 0x88, 0xef, 0xd0, 0x96, 0x71, - 0x3d, 0x8d, 0xf1, 0x0a, 0x48, 0x77, 0x84, 0xb7, 0x41, 0xc6, 0xb0, 0xd3, 0xf0, 0xed, 0x90, 0x20, - 0x01, 0xe7, 0xb8, 0x33, 0x66, 0xd7, 0x18, 0x49, 0xba, 0xdf, 0xed, 0x75, 0xf6, 0xba, 0x7b, 0xd5, - 0x04, 0x29, 0xb6, 0x9e, 0x10, 0xb0, 0x4c, 0xf9, 0x17, 0xfa, 0xee, 0x15, 0xe7, 0x26, 0xc4, 0x7b, - 0x24, 0x29, 0x87, 0x21, 0x1f, 0xaa, 0xa2, 0x9c, 0x86, 0x2e, 0x9e, 0xc4, 0x04, 0xb5, 0x0f, 0xc3, - 0xc0, 0xf9, 0x26, 0x26, 0xcc, 0x64, 0x53, 0x42, 0x82, 0xaf, 0x32, 0x02, 0x14, 0xf3, 0xce, 0x60, - 0x02, 0x4a, 0xca, 0x3e, 0xb8, 0x78, 0x75, 0x0b, 0xd0, 0x19, 0x22, 0x99, 0xd3, 0xe9, 0x14, 0xa7, - 0xc1, 0xdc, 0xd1, 0xa0, 0x84, 0x45, 0x9d, 0x0d, 0x38, 0x5a, 0x94, 0x87, 0x88, 0x81, 0xa4, 0x51, - 0xac, 0x67, 0x87, 0xc5, 0x85, 0x80, 0xe9, 0x2b, 0xa9, 0x29, 0xa7, 0x54, 0x32, 0x8c, 0x99, 0x42, - 0x29, 0x62, 0x7c, 0x75, 0xd0, 0xeb, 0x5a, 0x0b, 0xf9, 0xdf, 0x82, 0x5f, 0xf0, 0x2c, 0xc7, 0xaa, - 0x43, 0x26, 0xee, 0xa8, 0x8d, 0x4e, 0xc7, 0x32, 0x4e, 0x47, 0xb6, 0x40, 0x35, 0x5b, 0x0c, 0xa0, - 0x72, 0x71, 0x39, 0x77, 0xbf, 0x94, 0x2d, 0x7e, 0x73, 0xfd, 0xdf, 0x40, 0xd5, 0xa4, 0xc4, 0x9e, - 0x30, 0x19, 0x94, 0xd0, 0x53, 0x4f, 0xee, 0x83, 0xb9, 0x80, 0x42, 0x99, 0x94, 0xe4, 0x3a, 0x4e, - 0x2f, 0x33, 0xd1, 0x04, 0xfe, 0x1b, 0x60, 0xc6, 0x47, 0x2f, 0x48, 0xc9, 0x7b, 0x71, 0x4b, 0xd9, - 0x5f, 0x5b, 0x36, 0x25, 0xba, 0x8d, 0x62, 0x40, 0x0d, 0x25, 0xa5, 0x4c, 0xaf, 0x60, 0x2d, 0x42, - 0x39, 0x1d, 0x1a, 0x1f, 0xe7, 0x11, 0x78, 0xbd, 0x83, 0x8f, 0xa9, 0xb9, 0x40, 0x26, 0xc5, 0xb1, - 0xd3, 0xc1, 0x52, 0xc4, 0x36, 0x11, 0x47, 0x26, 0xa9, 0x03, 0xfb, 0xc3, 0xe9, 0xa8, 0xe9, 0x1b, - 0x8c, 0xd6, 0xd6, 0x61, 0x49, 0xef, 0x12, 0x7d, 0x73, 0xc7, 0xf9, 0xdc, 0xa5, 0x80, 0x5e, 0x99, - 0xb8, 0x96, 0x3d, 0xab, 0x78, 0xdc, 0x35, 0xc2, 0xc4, 0x4b, 0x61, 0xa0, 0xa5, 0x18, 0x2a, 0x59, - 0x57, 0x40, 0xfe, 0x9a, 0x8f, 0x74, 0x7f, 0x1e, 0x22, 0x92, 0x8f, 0x3a, 0xda, 0xda, 0x73, 0x9c, - 0x58, 0x9f, 0x6a, 0x12, 0x68, 0xad, 0x9a, 0x96, 0xc0, 0x33, 0x93, 0x80, 0xc1, 0x84, 0xc3, 0x4e, - 0x3a, 0x5a, 0xc8, 0xee, 0x00, 0xaf, 0x28, 0x19, 0x0e, 0xae, 0xac, 0xe2, 0x8e, 0x31, 0xc4, 0x2c, - 0x76, 0x98, 0xfc, 0x82, 0x08, 0x12, 0xca, 0xc7, 0x9c, 0xeb, 0x92, 0x31, 0xa5, 0x96, 0xa6, 0x9e, - 0xa7, 0xe8, 0x7e, 0x19, 0x13, 0xe2, 0x6d, 0x53, 0xde, 0xa5, 0x29, 0x1f, 0x28, 0x70, 0xca, 0x7c, - 0xc4, 0xe3, 0x22, 0x55, 0x4d, 0x39, 0x21, 0xd1, 0xa3, 0x5a, 0x08, 0x76, 0x89, 0xc8, 0x6b, 0x26, - 0xc3, 0x43, 0x3c, 0x91, 0xe2, 0x01, 0xf1, 0xea, 0x05, 0x54, 0x82, 0xb4, 0x73, 0xf8, 0x44, 0xa9, - 0xeb, 0xab, 0xb5, 0x65, 0xc0, 0xbc, 0xec, 0x1c, 0xb6, 0x00, 0xfd, 0x80, 0x3f, 0x74, 0xe9, 0x41, - 0x66, 0x3c, 0x28, 0xaf, 0x56, 0x75, 0x4d, 0x90, 0xd6, 0xff, 0xd1, 0x6a, 0xf7, 0xac, 0x85, 0xc0, - 0x90, 0xd9, 0x6b, 0x75, 0xa5, 0xc2, 0x1d, 0x7e, 0x97, 0x16, 0x9a, 0xe6, 0x34, 0xb8, 0x98, 0x02, - 0xad, 0xb5, 0xac, 0xfb, 0x41, 0x0d, 0x05, 0x50, 0x26, 0x9d, 0xa2, 0xd5, 0x9a, 0x99, 0xc6, 0xb4, - 0x1a, 0xf2, 0x84, 0xc3, 0x8c, 0xa3, 0x52, 0x8d, 0xd9, 0x9d, 0x85, 0x9c, 0xf8, 0xf5, 0xd2, 0x7c, - 0xcb, 0x5d, 0xe1, 0x5d, 0x6e, 0x46, 0x4a, 0x19, 0xe2, 0xa3, 0x79, 0xc9, 0xae, 0x94, 0x99, 0x73, - 0x1d, 0x78, 0xf9, 0x74, 0xdb, 0xba, 0xc1, 0xdf, 0x53, 0x32, 0x00, 0x6d, 0x5b, 0xff, 0x80, 0x0f, - 0x33, 0xf7, 0xe6, 0x7c, 0x92, 0x64, 0xad, 0xba, 0xe0, 0x0d, 0xbe, 0xcb, 0xc1, 0xb8, 0x28, 0x82, - 0xe0, 0x6b, 0x77, 0x3f, 0xd4, 0x5c, 0x0f, 0x31, 0x54, 0xbd, 0xa9, 0xea, 0xb3, 0x5b, 0x2b, 0x4e, - 0x3f, 0xd6, 0x59, 0x97, 0xe4, 0xa7, 0xca, 0xd1, 0xc0, 0xf2, 0x30, 0x29, 0x5e, 0x16, 0x96, 0x82, - 0x7e, 0xd1, 0x34, 0x4a, 0xe8, 0x07, 0x19, 0x17, 0x8b, 0xa9, 0x9c, 0x0f, 0x36, 0x5f, 0x6d, 0x5f, - 0x11, 0x3f, 0xb7, 0x56, 0x87, 0x98, 0xd6, 0x64, 0x24, 0xaa, 0x9c, 0x04, 0x5a, 0x11, 0x17, 0xa0, - 0xf2, 0xdd, 0xc0, 0xff, 0xb3, 0x28, 0x0a, 0x2f, 0x40, 0x05, 0xa6, 0x83, 0x01, 0x87, 0xf8, 0x13, - 0xb5, 0x5c, 0xfa, 0x81, 0x41, 0x16, 0x87, 0x5b, 0xff, 0x1f, 0x03, 0x41, 0xa8, 0xf5, 0x45, 0x37, - 0x01, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xed, 0xbd, 0xdd, 0x76, 0xe3, 0x46, + 0x92, 0x2e, 0x7a, 0xaf, 0xa7, 0x48, 0xcb, 0xdd, 0x0d, 0xb2, 0x05, 0xfe, 0xe9, 0xcf, 0x55, 0x64, + 0x49, 0x35, 0xf5, 0x67, 0x5b, 0x33, 0xf5, 0x67, 0x49, 0x76, 0x4f, 0xaf, 0xea, 0x5a, 0x32, 0x48, + 0x82, 0x22, 0x2c, 0x12, 0xa0, 0x01, 0x50, 0x3f, 0x96, 0xb5, 0xd7, 0x5c, 0xed, 0x07, 0xd8, 0x67, + 0xaf, 0x73, 0xde, 0xe0, 0x5c, 0xef, 0x9b, 0x73, 0x77, 0xae, 0xe6, 0xbc, 0x49, 0x3f, 0xc9, 0x89, + 0x2f, 0x22, 0x13, 0x48, 0x80, 0x20, 0x29, 0x95, 0xcb, 0x33, 0xb3, 0x67, 0x8d, 0x67, 0xba, 0x44, + 0x00, 0x99, 0x91, 0x99, 0x91, 0x91, 0x91, 0x11, 0x91, 0x11, 0x91, 0x4f, 0xbe, 0x78, 0xf9, 0xee, + 0xc5, 0xe9, 0x5f, 0xdf, 0xbf, 0x52, 0xe3, 0x74, 0x3a, 0x39, 0xdc, 0xd8, 0x78, 0x82, 0xbf, 0x6a, + 0xe2, 0x85, 0xe7, 0x07, 0x9b, 0x7e, 0xb8, 0xc9, 0x6f, 0x7c, 0x6f, 0x88, 0xbf, 0x53, 0x3f, 0xf5, + 0xd4, 0x60, 0xec, 0xc5, 0x89, 0x9f, 0x1e, 0x6c, 0x7e, 0x7f, 0xfa, 0x75, 0xe3, 0xd1, 0x66, 0xf6, + 0x3e, 0xf4, 0xa6, 0xfe, 0xc1, 0xe6, 0x65, 0xe0, 0x5f, 0xcd, 0xa2, 0x38, 0xdd, 0x54, 0x83, 0x28, + 0x4c, 0xfd, 0x90, 0xca, 0x5d, 0x05, 0xc3, 0x74, 0x7c, 0x30, 0xf4, 0x2f, 0x83, 0x81, 0xdf, 0xe0, + 0x07, 0x57, 0x05, 0x61, 0x90, 0x06, 0xde, 0xa4, 0x91, 0x0c, 0xbc, 0x89, 0x7f, 0xd0, 0x69, 0xb6, + 0x19, 0x4e, 0x1a, 0xa4, 0x13, 0xff, 0xf0, 0xca, 0xbb, 0xe9, 0xfb, 0xde, 0xf4, 0xec, 0xd2, 0x0f, + 0x07, 0x4f, 0x5a, 0xf2, 0x8e, 0x3e, 0x26, 0xe9, 0x0d, 0xff, 0xf8, 0x87, 0x60, 0x8a, 0x06, 0xd4, + 0x3c, 0x9e, 0xd4, 0x9c, 0x71, 0x9a, 0xce, 0x92, 0x6e, 0xab, 0x35, 0xa2, 0xc6, 0x92, 0xe6, 0x79, + 0x14, 0x9d, 0x4f, 0x7c, 0x6f, 0x16, 0x24, 0xcd, 0x41, 0x34, 0x6d, 0x0d, 0x92, 0x64, 0xfb, 0xe9, + 0xc8, 0x9b, 0x06, 0x93, 0x9b, 0x83, 0x7f, 0xf4, 0xd3, 0xe7, 0xb1, 0x17, 0x84, 0xc9, 0xd6, 0x9b, + 0x28, 0x8c, 0xba, 0x57, 0xe7, 0xe3, 0xf4, 0x1f, 0x76, 0xdb, 0xed, 0xde, 0x1e, 0xfd, 0x6f, 0x9f, + 0xfe, 0xf7, 0x55, 0xbb, 0xfd, 0x27, 0x5d, 0xf4, 0xe5, 0x9b, 0xad, 0x13, 0x2f, 0x4c, 0xaa, 0xcb, + 0x0c, 0x83, 0x64, 0x36, 0xf1, 0x6e, 0x0e, 0x92, 0x2b, 0x6f, 0xe6, 0xd4, 0x7b, 0x1b, 0x1b, 0x7f, + 0xbe, 0x9d, 0x7a, 0xf1, 0x79, 0x10, 0x76, 0xdb, 0xbd, 0x99, 0x37, 0x1c, 0x06, 0xe1, 0x39, 0xfd, + 0xea, 0x47, 0xd7, 0x8d, 0x24, 0xf8, 0x05, 0x0f, 0xfd, 0x28, 0x1e, 0xfa, 0x71, 0x83, 0xde, 0xdc, + 0x6d, 0x6c, 0x74, 0xe3, 0x28, 0x4a, 0x6f, 0x37, 0x36, 0x1a, 0x8d, 0xfe, 0x79, 0xf7, 0xcb, 0xb6, + 0xd7, 0xf6, 0x3a, 0xdb, 0x3d, 0x3c, 0x6c, 0xd3, 0xd3, 0xa8, 0xd3, 0xee, 0x3c, 0xa6, 0xa7, 0x81, + 0x17, 0x0f, 0xbb, 0x5f, 0x76, 0x76, 0x3b, 0x7b, 0xdb, 0x6d, 0xfd, 0xd8, 0x18, 0x47, 0x97, 0x7e, + 0x4c, 0x2f, 0x1f, 0x77, 0xbc, 0x6d, 0xaf, 0xc7, 0x00, 0x18, 0x2e, 0xbd, 0xf2, 0xb7, 0xdb, 0x3b, + 0x7b, 0x3d, 0xf3, 0xa2, 0x31, 0x0e, 0xba, 0x5f, 0x6e, 0x7b, 0xdb, 0xc3, 0x5d, 0x29, 0x96, 0xfa, + 0xd7, 0x69, 0xf7, 0xcb, 0xc1, 0xa3, 0x81, 0x37, 0x04, 0x30, 0x3c, 0x36, 0x86, 0xc1, 0xb4, 0xfb, + 0xe5, 0x7e, 0x7f, 0xdf, 0xff, 0xca, 0x33, 0xaf, 0xfa, 0x71, 0x40, 0xa3, 0xed, 0x7e, 0xe9, 0xfb, + 0xa3, 0xf6, 0x68, 0x97, 0x6b, 0x7a, 0x83, 0x01, 0x4d, 0x1f, 0xbd, 0x7a, 0xbc, 0xbb, 0xb7, 0x8f, + 0xba, 0xf2, 0xa2, 0x71, 0x3e, 0x89, 0xae, 0xba, 0xf1, 0x79, 0xdf, 0xab, 0x6d, 0xef, 0xec, 0xb8, + 0xfb, 0x8f, 0xdd, 0xc7, 0xfb, 0x6e, 0xb3, 0xb3, 0x57, 0xe7, 0x4a, 0x93, 0xe0, 0xd2, 0xa7, 0xf6, + 0xb7, 0x07, 0x7b, 0x7b, 0x7e, 0x4f, 0x1e, 0x31, 0x54, 0x2e, 0xbe, 0xb3, 0xeb, 0x76, 0x1e, 0x7f, + 0xe5, 0x3e, 0xde, 0xa5, 0xe2, 0x52, 0x3a, 0xf6, 0x93, 0xd4, 0x8b, 0xa9, 0x8d, 0xd1, 0xde, 0x63, + 0xbf, 0xdd, 0xef, 0x65, 0x6f, 0xb2, 0x3a, 0xdb, 0xbb, 0x7b, 0x6e, 0x67, 0xef, 0x91, 0xdb, 0xe9, + 0x64, 0x95, 0xfa, 0x93, 0x39, 0x35, 0xb1, 0xd3, 0x7f, 0xb4, 0x3d, 0xda, 0xef, 0xc9, 0x63, 0x56, + 0x7c, 0xef, 0xb1, 0xdb, 0xd9, 0x69, 0xbb, 0xdb, 0xbb, 0xfb, 0xba, 0x38, 0xe1, 0x1c, 0xe4, 0x7c, + 0x0b, 0xfa, 0xc0, 0x8c, 0xf8, 0xdd, 0xce, 0xce, 0x0c, 0x33, 0xd1, 0x8f, 0x86, 0x37, 0xb7, 0x7d, + 0x6f, 0x70, 0x71, 0x1e, 0x47, 0xf3, 0x70, 0xd8, 0xbd, 0xf4, 0xe2, 0x1a, 0x26, 0xa2, 0xde, 0x1b, + 0x44, 0x93, 0x28, 0xd6, 0xcf, 0xc0, 0x4d, 0xbd, 0xc7, 0x95, 0x85, 0x38, 0xba, 0xce, 0xcb, 0x37, + 0x0a, 0xd4, 0xe1, 0xb8, 0xc9, 0x4d, 0x92, 0xfa, 0xd3, 0xc6, 0x3c, 0x70, 0x13, 0x7a, 0x6e, 0x24, + 0x7e, 0x1c, 0x8c, 0x7a, 0xd3, 0x20, 0x6c, 0x8c, 0x7d, 0xc6, 0x65, 0xa7, 0xdd, 0xbe, 0x1c, 0xf7, + 0x30, 0x6f, 0x23, 0xc2, 0x58, 0xe3, 0xba, 0x3b, 0x0e, 0x86, 0x43, 0x3f, 0xa4, 0xb6, 0x07, 0xd1, + 0xd0, 0x77, 0x67, 0xb1, 0xef, 0x36, 0xa7, 0x44, 0x8b, 0xb7, 0x05, 0xf0, 0x19, 0x9d, 0x2a, 0xd0, + 0xa9, 0xe3, 0xa2, 0x44, 0x32, 0xf3, 0x06, 0x7e, 0x2f, 0x1f, 0x42, 0xf3, 0xd1, 0x9e, 0x3f, 0x25, + 0x38, 0xad, 0x3f, 0xab, 0xbf, 0xff, 0xcf, 0x7f, 0xa1, 0xff, 0x57, 0xa7, 0xfe, 0xc4, 0xa7, 0x45, + 0x18, 0xdf, 0xa8, 0xe7, 0x5e, 0x6c, 0x5e, 0xfe, 0xb9, 0xb5, 0xb1, 0xd1, 0x4c, 0xfb, 0x5e, 0x7c, + 0x3b, 0x8b, 0x12, 0x5a, 0x6e, 0x51, 0xd8, 0x4d, 0xd2, 0x60, 0x70, 0x71, 0xd3, 0x4b, 0xa3, 0x19, + 0x11, 0xe9, 0x2f, 0x8d, 0x20, 0x1c, 0xfa, 0xd7, 0xe8, 0x68, 0xaf, 0x02, 0x13, 0xdb, 0xf5, 0x5e, + 0x46, 0xbb, 0x69, 0x1a, 0x4d, 0xbb, 0x9d, 0xd9, 0xb5, 0x4a, 0xa2, 0x49, 0x30, 0x54, 0xba, 0x08, + 0x7f, 0xad, 0xe7, 0x64, 0xaf, 0x3a, 0xcd, 0xed, 0xd8, 0x9f, 0xf6, 0x34, 0x02, 0x76, 0x77, 0x67, + 0xd7, 0x3d, 0xbd, 0x5e, 0xba, 0xa3, 0x89, 0x7f, 0xdd, 0xf3, 0x26, 0xc1, 0x79, 0xd8, 0x08, 0x08, + 0x6d, 0x49, 0x17, 0xb4, 0xe4, 0xc7, 0xbd, 0x73, 0x6f, 0xd6, 0xed, 0xa0, 0x12, 0x7a, 0x30, 0x8c, + 0xa3, 0x59, 0x63, 0x14, 0x4c, 0xe8, 0x43, 0x97, 0xe6, 0x35, 0xae, 0x75, 0xb6, 0x67, 0xd7, 0xf5, + 0x3b, 0x3d, 0x8c, 0x06, 0xb3, 0x82, 0x07, 0xa1, 0xeb, 0x4a, 0x7a, 0x42, 0x0b, 0xd7, 0x42, 0x1f, + 0x37, 0x57, 0x9e, 0x65, 0xbd, 0x02, 0xea, 0xbd, 0x89, 0x9f, 0x52, 0xf3, 0x0d, 0x00, 0xc1, 0xa0, + 0x1a, 0xcd, 0xf6, 0x36, 0x15, 0xbf, 0x1a, 0x53, 0xaf, 0xf9, 0xa5, 0xdf, 0x0d, 0xa3, 0xab, 0xd8, + 0x9b, 0x15, 0x7b, 0xa5, 0xe8, 0x53, 0x78, 0x6b, 0x03, 0x95, 0xd5, 0x52, 0x2f, 0xf4, 0x83, 0x98, + 0x49, 0x56, 0x2d, 0xf1, 0x67, 0xb7, 0xcc, 0x0c, 0x81, 0x57, 0x83, 0xb2, 0xed, 0x36, 0xfd, 0x5e, + 0x9c, 0x0b, 0x41, 0x74, 0x56, 0x15, 0x08, 0xbc, 0xbd, 0x0f, 0x62, 0x9b, 0xbb, 0x18, 0xaa, 0x4d, + 0x38, 0x95, 0x43, 0x27, 0x7e, 0x50, 0x5f, 0x35, 0x42, 0xc0, 0x55, 0xfd, 0xdb, 0x25, 0x0b, 0x43, + 0x8f, 0x6d, 0xdf, 0x1a, 0xdb, 0x90, 0x98, 0x9c, 0x8c, 0xed, 0xab, 0x7c, 0x6c, 0xf8, 0xa9, 0x09, + 0x2a, 0xf6, 0x86, 0xc1, 0x3c, 0xe9, 0xee, 0xb5, 0xff, 0xd8, 0x43, 0xf7, 0x1b, 0xc9, 0x38, 0x0e, + 0xc2, 0x8b, 0x6e, 0x01, 0x40, 0x33, 0x0a, 0x17, 0xd7, 0xa7, 0x41, 0x2a, 0xf3, 0xd7, 0xb1, 0x37, + 0x24, 0x4e, 0xd4, 0x56, 0x6d, 0xf5, 0x88, 0x28, 0xb3, 0x50, 0xa0, 0x08, 0x68, 0x34, 0x5a, 0x84, + 0x94, 0x0f, 0x3c, 0xc2, 0x4c, 0xa7, 0x37, 0x84, 0xac, 0x42, 0x2d, 0x66, 0x5d, 0xa3, 0x59, 0xb2, + 0x58, 0x15, 0x5f, 0x16, 0xba, 0xb0, 0x4f, 0x5d, 0x28, 0x73, 0x39, 0xe2, 0x89, 0x5e, 0x18, 0x4c, + 0x3d, 0x5e, 0x7a, 0xb3, 0xf9, 0x24, 0xf1, 0x01, 0x59, 0x6d, 0x27, 0xca, 0xf7, 0x12, 0x9f, 0xf6, + 0xc0, 0x11, 0xb6, 0x41, 0x9f, 0x9a, 0xfd, 0x87, 0x0b, 0xff, 0x66, 0x14, 0xd3, 0x06, 0x9a, 0xa8, + 0xac, 0xdc, 0x6d, 0xfb, 0x8f, 0x2e, 0x2d, 0xcd, 0x3f, 0xde, 0x9a, 0x0e, 0x76, 0xee, 0xf6, 0xac, + 0xa7, 0xe6, 0xde, 0x5d, 0xd6, 0x5f, 0x26, 0x5d, 0xbd, 0x0f, 0x35, 0x26, 0xfe, 0x28, 0xed, 0x7a, + 0xf3, 0x34, 0xba, 0xd7, 0xda, 0x63, 0x92, 0xc8, 0x00, 0xf5, 0xd3, 0x02, 0xd2, 0xc3, 0x28, 0xf4, + 0xf5, 0x9c, 0x2d, 0x5d, 0xfd, 0xd5, 0xd4, 0x64, 0x78, 0x02, 0xb1, 0x00, 0xd5, 0x69, 0x2f, 0xcc, + 0x3c, 0x38, 0xc3, 0x60, 0x1e, 0x27, 0x54, 0x73, 0x16, 0x05, 0xdc, 0x19, 0x8b, 0x4a, 0xbf, 0xda, + 0xcb, 0xc8, 0x76, 0xfd, 0x3a, 0x4f, 0x63, 0xe2, 0xbe, 0xc2, 0xdd, 0xbc, 0xc9, 0x44, 0xd1, 0x4e, + 0x94, 0xd8, 0xc3, 0xe9, 0xf2, 0xce, 0x79, 0xab, 0x9b, 0xaf, 0xee, 0xec, 0x02, 0x61, 0x17, 0x79, + 0xab, 0xd7, 0x4f, 0x8a, 0x2c, 0x95, 0x5e, 0x14, 0x97, 0xdf, 0x67, 0xe5, 0x9e, 0x98, 0x15, 0x59, + 0x09, 0x5e, 0xff, 0xd6, 0x7c, 0x6d, 0x7e, 0x45, 0x9f, 0x4c, 0x89, 0x12, 0xe6, 0xaa, 0x07, 0x65, + 0xaf, 0xcd, 0xbd, 0x02, 0xff, 0xa3, 0xed, 0x83, 0x19, 0x6e, 0xa1, 0x7b, 0xdb, 0x59, 0xf7, 0x18, + 0xa1, 0x33, 0x2f, 0x26, 0x1a, 0xa9, 0x42, 0x6e, 0x6f, 0x9e, 0x80, 0x3d, 0xd2, 0x86, 0x33, 0x48, + 0x99, 0x40, 0x74, 0x57, 0x35, 0xa2, 0xab, 0x70, 0x89, 0xcf, 0x4d, 0x6f, 0x90, 0xd2, 0xba, 0xa9, + 0x64, 0x91, 0x85, 0x9e, 0x34, 0x2a, 0x4a, 0x68, 0x18, 0x0d, 0x2d, 0x52, 0x66, 0xc8, 0x67, 0xfa, + 0x34, 0x28, 0xd2, 0xc8, 0x99, 0x7a, 0xd7, 0x0d, 0xcd, 0x57, 0x69, 0xf5, 0x10, 0x9d, 0x19, 0xf1, + 0x4c, 0x61, 0x4d, 0x94, 0x20, 0x99, 0x5e, 0x19, 0x80, 0xfd, 0x49, 0x34, 0xb8, 0xb0, 0x16, 0xed, + 0xc8, 0x1b, 0xfa, 0x47, 0xa1, 0x6a, 0xea, 0x25, 0x5b, 0x5c, 0xa9, 0xf2, 0xf1, 0x76, 0x14, 0x47, + 0xd3, 0x6c, 0x55, 0xb6, 0x05, 0x65, 0xa3, 0x28, 0x9e, 0x76, 0xf9, 0xd7, 0xc4, 0x4b, 0xfd, 0xbf, + 0xd6, 0x76, 0xb1, 0x8d, 0xa5, 0x51, 0xbe, 0x94, 0xad, 0x62, 0x8c, 0xc3, 0x02, 0xc5, 0x1d, 0xfb, + 0x03, 0xc2, 0x08, 0x8d, 0x29, 0x01, 0xf1, 0x15, 0x68, 0x2f, 0xf6, 0x07, 0x0d, 0x48, 0xe3, 0x84, + 0xe9, 0x02, 0x05, 0xfe, 0x34, 0xa7, 0xad, 0x7d, 0x74, 0x63, 0xc6, 0xd5, 0xe5, 0xb5, 0xd1, 0xe8, + 0xfb, 0xe9, 0x95, 0xef, 0x87, 0x55, 0x6b, 0x9f, 0xf9, 0x2e, 0xb8, 0x7c, 0x17, 0xff, 0x14, 0xb7, + 0xe1, 0x02, 0x29, 0x43, 0xfc, 0xac, 0xaf, 0x63, 0x02, 0xc5, 0xd5, 0x4d, 0xbc, 0x30, 0x9b, 0x15, + 0xe6, 0x2f, 0xaa, 0x23, 0x33, 0xc3, 0xfc, 0x49, 0x13, 0x9c, 0x66, 0x3c, 0x3c, 0x22, 0xe8, 0x0f, + 0xc5, 0xf1, 0x70, 0x7f, 0x9a, 0xc2, 0x07, 0x8a, 0x3d, 0xbd, 0xdf, 0x6e, 0x66, 0x8f, 0xb8, 0x4f, + 0x33, 0x37, 0x09, 0x40, 0xa8, 0x59, 0x63, 0x15, 0xbb, 0x59, 0x26, 0x00, 0x2c, 0x6c, 0x6a, 0x79, + 0x2d, 0xfe, 0x15, 0x15, 0xf7, 0x79, 0xde, 0x0d, 0x16, 0x0b, 0xd1, 0x9e, 0x53, 0xd9, 0x33, 0x5d, + 0x12, 0x74, 0x17, 0x85, 0xc9, 0xe2, 0xa0, 0xab, 0xc6, 0xac, 0xeb, 0x5c, 0x79, 0x71, 0x81, 0x3b, + 0x2f, 0x08, 0xc8, 0xed, 0x47, 0x15, 0x13, 0xb5, 0x50, 0x6a, 0xa7, 0xc8, 0xf0, 0xb4, 0xc4, 0x5d, + 0xaf, 0xe0, 0xd0, 0xd9, 0x1c, 0xa2, 0x4f, 0x4a, 0xd0, 0x5d, 0x31, 0x89, 0xe5, 0x29, 0xb9, 0xdb, + 0xf8, 0x12, 0xdd, 0xa5, 0x65, 0x46, 0x72, 0x51, 0x3a, 0x6c, 0x86, 0xf3, 0xe9, 0x2d, 0x8f, 0x9f, + 0x27, 0xa5, 0xcb, 0x68, 0x96, 0x3a, 0xd4, 0x83, 0xc0, 0xa3, 0xbf, 0x54, 0x82, 0xa4, 0xe7, 0x41, + 0x97, 0xaa, 0xcc, 0x27, 0xc4, 0xb7, 0xe9, 0x39, 0x29, 0x43, 0x89, 0xa3, 0x2b, 0x62, 0xe7, 0xc9, + 0x22, 0xa4, 0x2a, 0xc1, 0xa5, 0xb2, 0xaa, 0x6a, 0x62, 0x7b, 0xcb, 0x06, 0xb5, 0xc3, 0x83, 0xfa, + 0xaa, 0x34, 0x80, 0xaf, 0xb6, 0xad, 0x51, 0xf2, 0x56, 0xca, 0x05, 0xf5, 0x14, 0xf8, 0xd3, 0x59, + 0x7a, 0x73, 0xbb, 0x7a, 0xcb, 0x63, 0x5a, 0xb7, 0x7a, 0x69, 0x16, 0x5c, 0x35, 0xff, 0xe5, 0x99, + 0x1a, 0x7a, 0xc9, 0xd8, 0x5f, 0xbb, 0xa6, 0xee, 0x2c, 0x71, 0xac, 0x39, 0x98, 0x90, 0x24, 0x8f, + 0x01, 0xde, 0x96, 0x76, 0x03, 0x8b, 0x65, 0x73, 0x3f, 0xf5, 0x8e, 0x58, 0x55, 0x75, 0x09, 0xcb, + 0x36, 0x2b, 0xa1, 0xc0, 0x93, 0x4e, 0x48, 0x2c, 0x66, 0x8e, 0x74, 0xe2, 0x0b, 0xe9, 0x16, 0xd8, + 0x52, 0x22, 0x2f, 0x6f, 0x3f, 0x17, 0xf7, 0xa8, 0xa2, 0x32, 0xa3, 0x49, 0xe5, 0x7a, 0x94, 0x69, + 0xb6, 0x92, 0x23, 0x56, 0xf0, 0xbc, 0x6c, 0xea, 0xf7, 0x33, 0x9e, 0x54, 0x42, 0x5e, 0x79, 0x6f, + 0xb3, 0x96, 0xa4, 0x85, 0xd7, 0x7c, 0x94, 0x84, 0xdc, 0x64, 0xb1, 0x23, 0x46, 0xe6, 0xa8, 0x42, + 0x86, 0x68, 0xf2, 0xf5, 0xc5, 0x4a, 0x6a, 0xbc, 0x73, 0xbb, 0x40, 0x23, 0x25, 0x5e, 0xb4, 0x5c, + 0x6b, 0xc1, 0x90, 0x49, 0x40, 0xb4, 0xa0, 0x0e, 0xc6, 0xfe, 0x65, 0x5c, 0xe2, 0x55, 0x25, 0xe9, + 0x40, 0x53, 0x7c, 0x69, 0x74, 0xd9, 0xce, 0x84, 0x6d, 0xcf, 0x82, 0xd8, 0x24, 0x48, 0x13, 0x6f, + 0x96, 0x10, 0xa1, 0x2e, 0x34, 0x92, 0xef, 0x66, 0x71, 0x94, 0xd2, 0x8e, 0x57, 0x6b, 0x3c, 0x6e, + 0x0f, 0xfd, 0xf3, 0xfa, 0x9a, 0xea, 0xac, 0x84, 0xdb, 0x9b, 0xb9, 0x3d, 0x00, 0xd1, 0xd0, 0x85, + 0x34, 0xa0, 0xb0, 0x2e, 0xa1, 0x9e, 0x02, 0x95, 0x7e, 0x1d, 0xf8, 0x93, 0xa1, 0x3a, 0x8e, 0xae, + 0x8a, 0xe4, 0x39, 0xc2, 0xeb, 0xac, 0xa1, 0xf3, 0x38, 0x18, 0xf6, 0xf0, 0x0f, 0xe1, 0x63, 0x3a, + 0xc3, 0x06, 0x0d, 0x99, 0x63, 0x3e, 0x0d, 0x13, 0xd2, 0xbf, 0xda, 0x10, 0x58, 0x47, 0x31, 0x0b, + 0x0b, 0x2b, 0x69, 0x68, 0x2f, 0xa3, 0xa1, 0xfb, 0xc9, 0x79, 0x99, 0xb0, 0x5d, 0x29, 0x54, 0x69, + 0x18, 0xcc, 0x70, 0x76, 0xaa, 0x44, 0xb1, 0x3b, 0x33, 0x8c, 0xee, 0xc4, 0x4b, 0x52, 0x42, 0x7c, + 0x40, 0x23, 0x2a, 0xb6, 0x6c, 0x10, 0xc8, 0xc5, 0x9a, 0x83, 0xb1, 0x17, 0x9e, 0xfb, 0x59, 0x19, + 0x40, 0x6e, 0x54, 0xf3, 0xfd, 0x55, 0x3b, 0xca, 0x4e, 0x3d, 0x83, 0xd8, 0x98, 0x78, 0x7d, 0x7f, + 0x72, 0xbb, 0x6e, 0xff, 0xad, 0x9b, 0x35, 0x35, 0xf6, 0x27, 0xb3, 0xde, 0xbd, 0xb5, 0xd4, 0x52, + 0x33, 0xeb, 0x59, 0x53, 0xb3, 0xef, 0x0d, 0xcf, 0x7d, 0xbb, 0x3b, 0x58, 0xd5, 0x39, 0x17, 0x26, + 0x24, 0xee, 0x2d, 0xe8, 0x1d, 0x84, 0xda, 0x85, 0x35, 0xc5, 0x70, 0x73, 0x02, 0x9e, 0xcf, 0x66, + 0x7e, 0x3c, 0x20, 0x91, 0xe1, 0xbe, 0x0a, 0x48, 0xc9, 0x60, 0x40, 0x38, 0x93, 0xd1, 0x70, 0xff, + 0x58, 0x3c, 0x58, 0x94, 0x17, 0x7a, 0x95, 0x4a, 0x25, 0xcc, 0x4f, 0x79, 0x4d, 0x3d, 0x41, 0xb7, + 0xeb, 0x26, 0xad, 0xf0, 0x45, 0x40, 0x68, 0x08, 0xa1, 0xa7, 0x2b, 0x7f, 0xf9, 0x78, 0xe0, 0xed, + 0x78, 0xa3, 0x85, 0xa9, 0xee, 0xec, 0xed, 0xbb, 0x9d, 0xfd, 0x1d, 0xb7, 0xf3, 0xd5, 0x1e, 0x9b, + 0xf0, 0xee, 0xcc, 0x1c, 0x50, 0x4d, 0x4b, 0xcf, 0xcc, 0xdf, 0x92, 0xce, 0x3a, 0x9b, 0xa7, 0x6e, + 0xfe, 0x2c, 0xbc, 0xd2, 0x7a, 0xd1, 0x4c, 0xa3, 0xf3, 0x73, 0xda, 0x95, 0x34, 0x47, 0x6d, 0xf8, + 0x97, 0x34, 0xd1, 0x89, 0xa1, 0xcd, 0x7c, 0xa5, 0x1e, 0x01, 0x50, 0x61, 0x95, 0x32, 0xe8, 0x0f, + 0xe9, 0xcd, 0xcc, 0x3f, 0xd8, 0xc4, 0x9c, 0x6c, 0x7e, 0x74, 0xed, 0x57, 0x24, 0x13, 0xf4, 0xfd, + 0x98, 0x5e, 0x4a, 0x93, 0xb7, 0x1b, 0x1b, 0x95, 0xd6, 0xbb, 0x07, 0x6a, 0xab, 0xf9, 0xb6, 0x4d, + 0xc4, 0x02, 0x3b, 0x42, 0x85, 0x18, 0x54, 0xa6, 0xf8, 0x25, 0xe6, 0xc0, 0xdc, 0x08, 0xa8, 0xd5, + 0x0f, 0xd2, 0xdd, 0x2d, 0x6d, 0x64, 0xfb, 0x11, 0x94, 0x11, 0x7b, 0x17, 0xb1, 0x54, 0x52, 0xa3, + 0xb6, 0xf2, 0x80, 0xbb, 0xa3, 0x68, 0x30, 0x4f, 0xf4, 0x38, 0xe5, 0xe1, 0x36, 0x9a, 0xa7, 0x10, + 0x61, 0x6d, 0x8d, 0xbc, 0x5a, 0x51, 0xaa, 0x42, 0xd9, 0x6d, 0x63, 0x1a, 0xfd, 0xd2, 0xf0, 0x88, + 0xb0, 0x3d, 0x6a, 0x9e, 0xc4, 0x24, 0x8c, 0x9c, 0x67, 0xac, 0xba, 0x7c, 0xb7, 0x4b, 0xeb, 0xa3, + 0x7f, 0x11, 0xa4, 0x0d, 0x6a, 0x96, 0x49, 0x1b, 0x7b, 0xf1, 0x9c, 0x98, 0x4c, 0xe8, 0xae, 0x2e, + 0x1f, 0x84, 0x61, 0xb1, 0xfc, 0xad, 0xf9, 0x62, 0xb5, 0xce, 0x63, 0x30, 0x5a, 0x19, 0x0d, 0x5a, + 0x4f, 0x68, 0x69, 0x2b, 0x5e, 0x56, 0xb1, 0xfc, 0x9c, 0x53, 0x41, 0x83, 0xb4, 0xb6, 0x73, 0xbf, + 0x8b, 0x73, 0x81, 0xcd, 0xa1, 0x97, 0x7a, 0x5d, 0x7e, 0x6e, 0x25, 0x97, 0xe7, 0x5b, 0xd7, 0xd3, + 0x89, 0xfb, 0xc7, 0x9d, 0x17, 0xf4, 0x53, 0xd1, 0xcf, 0x30, 0x39, 0xe0, 0x83, 0x83, 0x6e, 0xab, + 0x75, 0x75, 0x75, 0xd5, 0xbc, 0xda, 0x69, 0x46, 0xf1, 0x79, 0x8b, 0x78, 0x7f, 0x1b, 0x85, 0x1d, + 0x25, 0x07, 0x16, 0x4e, 0xa7, 0xed, 0x28, 0xb1, 0x5d, 0x1d, 0x38, 0xfb, 0xce, 0x1f, 0x77, 0x5e, + 0x11, 0x84, 0x99, 0x97, 0x8e, 0xd5, 0xf0, 0xc0, 0x79, 0xd3, 0x56, 0xed, 0xc9, 0x9e, 0xda, 0x57, + 0x7b, 0x8d, 0xfd, 0x5f, 0x1c, 0x35, 0x0a, 0x26, 0x93, 0x03, 0xe7, 0x8f, 0xdb, 0x3b, 0x62, 0x55, + 0x77, 0x5a, 0x52, 0x1a, 0xe0, 0xe8, 0xd7, 0xa6, 0xbd, 0x5e, 0x69, 0xa5, 0xd2, 0x00, 0x20, 0x5e, + 0xe8, 0x5f, 0xf6, 0xb7, 0xcc, 0x50, 0xcb, 0x6c, 0x8e, 0xed, 0x5a, 0xc5, 0x7d, 0x47, 0x4c, 0x3d, + 0xdd, 0xed, 0x5d, 0x36, 0x62, 0xd3, 0x72, 0x3a, 0xe5, 0xe5, 0xa6, 0x4e, 0xae, 0x82, 0x74, 0x30, + 0xd6, 0xf6, 0x09, 0xb3, 0x02, 0x0d, 0x2c, 0x9f, 0xf6, 0x38, 0x62, 0x2f, 0x19, 0x33, 0x0e, 0x42, + 0xd0, 0x52, 0x43, 0x94, 0x5d, 0xa1, 0xce, 0xdd, 0x7d, 0xcb, 0x08, 0x89, 0xdf, 0x05, 0xbb, 0x5c, + 0x8f, 0x78, 0x71, 0x1a, 0x0c, 0xbc, 0x89, 0x16, 0x69, 0xa7, 0x24, 0x81, 0x4d, 0xa0, 0x4f, 0x49, + 0x53, 0xc2, 0x15, 0xf2, 0x06, 0xbd, 0x3e, 0x2d, 0x3d, 0xa2, 0x9c, 0x5e, 0xae, 0x15, 0x4b, 0x2b, + 0x6d, 0xd3, 0x44, 0x3b, 0xab, 0x0b, 0xce, 0x3b, 0xb8, 0x28, 0x29, 0xe0, 0x4b, 0xfa, 0x64, 0x2d, + 0xf8, 0x2f, 0x77, 0x76, 0x76, 0xf6, 0xf7, 0xda, 0xa5, 0xd5, 0x0a, 0xdb, 0x7e, 0x6f, 0xb9, 0x3c, + 0x6c, 0xcb, 0x6d, 0x3b, 0x89, 0x9b, 0x5b, 0xf0, 0xf0, 0x68, 0x1b, 0xf4, 0x88, 0xcd, 0xfb, 0xa9, + 0x6a, 0x2b, 0x18, 0x45, 0x76, 0x8d, 0x61, 0xaf, 0xed, 0xe2, 0xff, 0x9a, 0x7b, 0x75, 0xb7, 0xad, + 0xc0, 0x5e, 0xda, 0x5a, 0xb5, 0xda, 0xdb, 0x73, 0xcd, 0xff, 0x9a, 0x6d, 0xe6, 0xa1, 0xf6, 0xc8, + 0xba, 0xdd, 0xbe, 0x4f, 0xfb, 0x0a, 0xf6, 0x00, 0xd1, 0xcc, 0x1d, 0xa7, 0x57, 0x1c, 0xec, 0x22, + 0xda, 0x20, 0xed, 0x60, 0x24, 0x46, 0x1a, 0xd0, 0xf8, 0x60, 0xe3, 0xf0, 0x12, 0x43, 0xf1, 0x97, + 0x8f, 0xbc, 0x47, 0xc3, 0xc7, 0x5e, 0x85, 0x81, 0xb5, 0x5a, 0xb2, 0xdb, 0x49, 0xd4, 0x60, 0xde, + 0x0f, 0x06, 0x8d, 0xbe, 0xff, 0x4b, 0xe0, 0xc7, 0xb5, 0xe6, 0x2e, 0x75, 0xde, 0x6d, 0x6e, 0xbb, + 0x9d, 0xba, 0x5b, 0x44, 0x53, 0xd1, 0xd0, 0x59, 0x85, 0x91, 0xdd, 0x7a, 0x89, 0x12, 0xba, 0x24, + 0x16, 0x0e, 0x2e, 0xfc, 0xe1, 0x56, 0x71, 0x8e, 0xef, 0x63, 0xcd, 0x5d, 0x85, 0xf9, 0x1d, 0x60, + 0xbe, 0xcd, 0xe6, 0x44, 0x55, 0x3e, 0x7f, 0xda, 0xb9, 0xef, 0xac, 0xac, 0xea, 0x61, 0x36, 0x57, + 0x15, 0x36, 0x9c, 0x7f, 0xae, 0x01, 0xe5, 0x85, 0x8d, 0xf7, 0xcb, 0xd1, 0x68, 0xb4, 0x1e, 0x3b, + 0x3b, 0x45, 0x09, 0xf5, 0x19, 0x0b, 0xb7, 0xea, 0x39, 0x73, 0xc7, 0xa2, 0x94, 0xba, 0xdc, 0x26, + 0x50, 0x94, 0x6c, 0x20, 0x78, 0xb6, 0x7b, 0xe5, 0x33, 0x1d, 0x2d, 0x04, 0x56, 0x1e, 0xe5, 0x64, + 0x2a, 0xd6, 0x0a, 0x39, 0xda, 0xe8, 0x5c, 0x28, 0x22, 0x1a, 0x4f, 0x7e, 0x3e, 0xc4, 0x42, 0x89, + 0xad, 0x3b, 0xef, 0x59, 0xd6, 0x48, 0xbd, 0xe3, 0xda, 0x3b, 0x93, 0x21, 0xbf, 0x95, 0x56, 0xde, + 0x47, 0x55, 0x0a, 0x4e, 0x95, 0x6c, 0xbc, 0x6e, 0xbf, 0xd5, 0xbd, 0xeb, 0x12, 0xde, 0xa0, 0xd5, + 0x0e, 0x73, 0xd1, 0x65, 0x67, 0xcf, 0xb4, 0x1f, 0x46, 0x50, 0xc7, 0x49, 0x7b, 0xf4, 0x87, 0xba, + 0x38, 0x36, 0x96, 0xc9, 0xcd, 0x32, 0xeb, 0xbe, 0x96, 0x9b, 0xda, 0xed, 0x76, 0xa1, 0xb8, 0x88, + 0xa5, 0x80, 0x56, 0xcb, 0x9a, 0xab, 0xdb, 0x30, 0xbe, 0xec, 0xec, 0x7b, 0x3b, 0xbb, 0x5e, 0xb5, + 0x15, 0xb0, 0xd1, 0xd1, 0xa7, 0x59, 0x80, 0x67, 0xc4, 0xbb, 0x65, 0x92, 0x5c, 0x55, 0x1f, 0xcc, + 0x79, 0xe9, 0xda, 0x5e, 0x0c, 0x1f, 0x7f, 0xf5, 0x55, 0x7b, 0xff, 0x1e, 0xbd, 0xa0, 0xea, 0xd0, + 0x4a, 0x6f, 0x97, 0x9d, 0x39, 0x55, 0xda, 0xc6, 0xed, 0x9a, 0xcb, 0x74, 0xdd, 0xec, 0x34, 0xba, + 0x64, 0x4c, 0x8f, 0x48, 0x7b, 0x29, 0x5a, 0xd3, 0x23, 0xd6, 0x67, 0x68, 0x8e, 0x49, 0xba, 0xf6, + 0xad, 0xb3, 0xca, 0x51, 0x70, 0xed, 0x0f, 0x99, 0x17, 0xee, 0xd1, 0xba, 0xea, 0xc9, 0xc6, 0xd7, + 0xb1, 0x09, 0x93, 0x76, 0xec, 0xa2, 0x82, 0xc1, 0x9b, 0xd6, 0x30, 0x88, 0x45, 0x83, 0xec, 0x8a, + 0x56, 0x57, 0xd4, 0x31, 0xb8, 0xb9, 0xdb, 0xe5, 0x5a, 0x9c, 0x45, 0xba, 0xd5, 0x9a, 0x0e, 0xaf, + 0xfa, 0xdc, 0x42, 0xcc, 0xf0, 0x60, 0x22, 0xde, 0x11, 0x13, 0xb1, 0xcb, 0x2f, 0xde, 0xcd, 0xd3, + 0xec, 0x8d, 0xda, 0x6e, 0x7e, 0x95, 0x28, 0x9a, 0x85, 0x2b, 0x42, 0x57, 0x62, 0x49, 0x84, 0x3b, + 0xfb, 0xed, 0x92, 0x3a, 0x02, 0x3b, 0x7d, 0xa5, 0x26, 0x98, 0xf5, 0xbc, 0x11, 0x5d, 0x2c, 0x98, + 0x00, 0xed, 0x73, 0xf5, 0xbd, 0x7a, 0x6f, 0x99, 0xc2, 0x67, 0x13, 0x76, 0xc1, 0x74, 0x69, 0x40, + 0xfb, 0x71, 0xbc, 0x68, 0x5e, 0x2c, 0x1e, 0xf1, 0x2f, 0x83, 0x6d, 0x38, 0x79, 0xb5, 0xed, 0xde, + 0xb2, 0x99, 0x6b, 0x74, 0xdd, 0xc3, 0x68, 0xae, 0x19, 0xee, 0x3a, 0xab, 0x79, 0x19, 0x36, 0x61, + 0xfe, 0xd6, 0xaa, 0xb2, 0x12, 0x74, 0x91, 0x31, 0xbf, 0x3f, 0x52, 0xc7, 0xfe, 0xc8, 0x27, 0x65, + 0x7b, 0xe0, 0xc3, 0xee, 0x4e, 0x7b, 0x45, 0x81, 0x3b, 0xcf, 0x82, 0x06, 0x30, 0x33, 0xbb, 0x2d, + 0x1a, 0xa7, 0xc4, 0x4a, 0x7d, 0x67, 0x97, 0xa8, 0x34, 0xe5, 0x54, 0xa1, 0xab, 0x64, 0xe6, 0xda, + 0xaf, 0xe4, 0x88, 0xcb, 0xd4, 0xd3, 0x05, 0xbd, 0x73, 0x3f, 0xef, 0x06, 0x9b, 0x3e, 0x6f, 0x2d, + 0x3d, 0x24, 0x57, 0x19, 0xd8, 0x06, 0xd3, 0x35, 0x3f, 0x3e, 0x9b, 0xbd, 0xbf, 0x64, 0x9d, 0x5b, + 0xb4, 0x09, 0x5b, 0x1d, 0x53, 0xe9, 0xd8, 0x36, 0xe3, 0x82, 0x9a, 0x2a, 0x6d, 0xcd, 0xd5, 0xc7, + 0x6a, 0xeb, 0x8f, 0xbb, 0xf6, 0x8b, 0xc7, 0x5d, 0x5f, 0x65, 0x06, 0xd9, 0x7b, 0xa1, 0x71, 0x77, + 0xa1, 0xb7, 0xc3, 0xdb, 0xca, 0xde, 0xad, 0xdf, 0x52, 0x4b, 0x62, 0x33, 0x15, 0x2d, 0x41, 0xd6, + 0xa6, 0x42, 0x34, 0xb1, 0xce, 0x5a, 0x88, 0x5a, 0xd0, 0x3e, 0xee, 0xeb, 0xff, 0x60, 0xa3, 0x09, + 0x3e, 0x32, 0x45, 0x9b, 0x1f, 0x8f, 0xa0, 0xfa, 0xc8, 0x1f, 0x0d, 0x4d, 0xfd, 0x74, 0x1c, 0x0d, + 0x3f, 0xa5, 0x29, 0xe1, 0x32, 0x65, 0xec, 0x97, 0x9c, 0x31, 0x4c, 0x33, 0x43, 0x3f, 0x19, 0x54, + 0x9f, 0x18, 0xe2, 0xab, 0x7f, 0xed, 0x4d, 0x67, 0x0f, 0x74, 0xf8, 0xb0, 0xda, 0xac, 0xa6, 0x13, + 0x8b, 0xfd, 0xb2, 0x0c, 0x7d, 0x45, 0x53, 0xd5, 0xe8, 0xc7, 0xbe, 0x77, 0xd1, 0xe5, 0x7f, 0x21, + 0x25, 0x14, 0x0d, 0x15, 0xdf, 0x2d, 0x1c, 0xc2, 0x05, 0x3f, 0xd3, 0x06, 0x94, 0xc6, 0xd1, 0x7a, + 0xdb, 0xaa, 0x2c, 0x7d, 0xd6, 0xb6, 0x8c, 0x57, 0x50, 0x73, 0xbf, 0x57, 0x66, 0x20, 0xdb, 0x65, + 0xf1, 0xee, 0x73, 0xad, 0xca, 0x3b, 0xe9, 0x2c, 0x36, 0xd7, 0x38, 0x9a, 0x2c, 0x95, 0x2c, 0x4b, + 0x27, 0x6c, 0xa5, 0xee, 0xe9, 0xd5, 0x4b, 0x70, 0x0a, 0x22, 0xe0, 0x6e, 0x79, 0xeb, 0x5c, 0xde, + 0xad, 0xea, 0xc1, 0x2c, 0x9a, 0x62, 0x7e, 0x93, 0xf4, 0xb8, 0x57, 0x2d, 0x3d, 0xe6, 0x5d, 0x5f, + 0xee, 0x09, 0xb0, 0x7a, 0xf7, 0xd2, 0xd5, 0x9b, 0x93, 0xc8, 0xc3, 0xc8, 0x2d, 0xc3, 0x58, 0xaf, + 0xda, 0xc8, 0x85, 0x0a, 0x24, 0xa9, 0xcd, 0x27, 0xe9, 0xed, 0xe7, 0x3e, 0x4d, 0xad, 0x38, 0x47, + 0xed, 0x98, 0x43, 0xef, 0x71, 0xe6, 0x63, 0x64, 0xb3, 0xe3, 0x82, 0x23, 0xc8, 0x42, 0x07, 0x9b, + 0x97, 0x41, 0x12, 0x60, 0xab, 0x28, 0xa8, 0xa4, 0x85, 0x22, 0x6a, 0x16, 0x17, 0xac, 0xac, 0x5f, + 0xed, 0x55, 0x5b, 0x7d, 0x8b, 0x44, 0xbe, 0x57, 0x60, 0x2e, 0x04, 0xa2, 0x61, 0xd8, 0x0b, 0x01, + 0x26, 0xc1, 0xd5, 0xbf, 0xc7, 0xda, 0x91, 0x63, 0x37, 0x2a, 0x4f, 0x2a, 0x61, 0x03, 0x5c, 0x7b, + 0xd9, 0x69, 0x69, 0x85, 0x5d, 0xb9, 0x6a, 0x8f, 0x5e, 0x38, 0x55, 0x2d, 0x00, 0xd7, 0x46, 0x0c, + 0xcb, 0x7d, 0x00, 0x06, 0xbb, 0x72, 0xa1, 0xa2, 0x1a, 0xb4, 0x6b, 0x96, 0x80, 0x59, 0x68, 0x1e, + 0x75, 0xfe, 0xf7, 0x3d, 0x0a, 0xdb, 0x5f, 0x72, 0x14, 0xa6, 0x5b, 0x7f, 0xe8, 0x49, 0x98, 0xb5, + 0x9f, 0x7d, 0xa6, 0xa3, 0xb0, 0x42, 0x47, 0xee, 0x79, 0x12, 0x56, 0xa8, 0xa3, 0xc6, 0xbb, 0xb7, + 0xeb, 0xd4, 0xc4, 0x4a, 0x47, 0x3b, 0x3e, 0x02, 0xb3, 0x0d, 0x8b, 0x25, 0xb8, 0x4d, 0xde, 0x6e, + 0x16, 0xce, 0x7a, 0x97, 0xed, 0x13, 0x8c, 0x76, 0xd1, 0x3a, 0x32, 0x11, 0x4f, 0x03, 0xbc, 0xf7, + 0xd9, 0xda, 0xfe, 0xde, 0xba, 0xc3, 0xb5, 0x22, 0xd5, 0xd8, 0x87, 0x64, 0xa5, 0xb6, 0x56, 0x1d, + 0xb1, 0xad, 0x05, 0x52, 0x79, 0xd0, 0x66, 0x7f, 0xbb, 0x87, 0x30, 0x53, 0xa4, 0x7a, 0x21, 0xc4, + 0x45, 0xed, 0xab, 0xe8, 0x52, 0xa2, 0xcf, 0xce, 0xb9, 0xad, 0x99, 0x47, 0x62, 0x3a, 0x0e, 0xae, + 0x66, 0xd9, 0x02, 0xda, 0x31, 0x36, 0xf7, 0x4f, 0xb0, 0xe4, 0x2f, 0xb1, 0xd3, 0x3f, 0x4c, 0x4e, + 0xd8, 0x5e, 0x79, 0x82, 0x55, 0x61, 0x42, 0x5c, 0xe9, 0x05, 0x55, 0x18, 0xe4, 0x27, 0x6d, 0x37, + 0xbd, 0x25, 0x36, 0x32, 0x76, 0xba, 0xae, 0x0b, 0x37, 0xf4, 0xaf, 0x67, 0x1e, 0xa9, 0xbf, 0xc3, + 0x7f, 0xb3, 0xcd, 0x65, 0x85, 0x3b, 0x94, 0xdd, 0x9f, 0xf2, 0xba, 0x5d, 0xa3, 0xf5, 0xb0, 0xd7, + 0x64, 0xe5, 0xea, 0x2e, 0x81, 0xc5, 0x83, 0x1c, 0x2f, 0xc5, 0xd1, 0xd5, 0xfd, 0xdc, 0x5e, 0xf7, + 0x2b, 0x3c, 0x55, 0xaa, 0xfd, 0x6a, 0xaa, 0x1b, 0x5a, 0x38, 0xe9, 0xac, 0xde, 0xf4, 0x34, 0xa7, + 0xa0, 0x46, 0x32, 0x87, 0xb3, 0x05, 0xcb, 0xf9, 0xfd, 0x88, 0x72, 0x69, 0x4f, 0x64, 0x53, 0xfa, + 0xbc, 0x27, 0x5d, 0xbb, 0xf7, 0x3e, 0xe9, 0x92, 0x61, 0x3d, 0x6a, 0x97, 0x17, 0x57, 0xd5, 0xa1, + 0xd7, 0x8a, 0x33, 0xa6, 0x55, 0x63, 0x5b, 0x71, 0x76, 0xe4, 0xde, 0xaf, 0xde, 0xc2, 0x19, 0xd5, + 0xb2, 0x33, 0xa7, 0x35, 0x1d, 0x79, 0xe0, 0x41, 0xdb, 0x2a, 0x58, 0xe5, 0xc3, 0xf7, 0x87, 0x9f, + 0xbb, 0xef, 0x55, 0xb5, 0x40, 0xab, 0x30, 0x0e, 0xae, 0x1b, 0x70, 0x5d, 0xb8, 0x2d, 0x9d, 0xe5, + 0x88, 0x4f, 0x03, 0xd1, 0xf5, 0x6e, 0x2e, 0x32, 0x80, 0x99, 0x6f, 0xb3, 0xdb, 0xd0, 0x0a, 0x40, + 0x5a, 0xec, 0x91, 0x99, 0xde, 0x47, 0xed, 0x05, 0xd7, 0xa5, 0x0a, 0x00, 0x6b, 0xdc, 0xd7, 0x6c, + 0x53, 0xf2, 0x23, 0x4b, 0xb9, 0x91, 0x37, 0xfb, 0xf7, 0xd3, 0x9e, 0xa5, 0xd9, 0x4f, 0x39, 0xcc, + 0xda, 0xd9, 0x2f, 0x1d, 0x94, 0x94, 0x9c, 0xcc, 0x73, 0xb8, 0x7a, 0xf4, 0x2b, 0xcf, 0xa9, 0xb2, + 0xc2, 0x8d, 0x84, 0xfa, 0x68, 0x5b, 0x28, 0xb3, 0x03, 0x9b, 0xd2, 0x7e, 0xc1, 0x87, 0x18, 0x95, + 0x96, 0xf8, 0x4a, 0x1e, 0xbc, 0x5d, 0x3a, 0x18, 0x66, 0xc9, 0x60, 0xa1, 0xd9, 0xaa, 0x83, 0xa4, + 0xc5, 0x9e, 0x18, 0x01, 0x7c, 0x37, 0x3b, 0x35, 0xe2, 0x9f, 0xd9, 0x49, 0x92, 0xe6, 0x86, 0x3b, + 0x55, 0x9b, 0x6e, 0xce, 0xd2, 0x56, 0x9e, 0x22, 0x95, 0xba, 0x57, 0x3e, 0x50, 0x59, 0x40, 0xd7, + 0xb2, 0x63, 0x9f, 0x87, 0x00, 0x59, 0x7d, 0x32, 0xd3, 0xd9, 0xaf, 0x38, 0x99, 0x29, 0x7a, 0xaf, + 0x0d, 0x48, 0xff, 0x9d, 0xf4, 0x8b, 0xb1, 0x31, 0x39, 0x0b, 0x49, 0xcc, 0x67, 0xb3, 0x0e, 0x72, + 0xfa, 0x11, 0x2d, 0xba, 0xa2, 0xe8, 0xb2, 0x43, 0x2d, 0xf1, 0xe1, 0xa8, 0xac, 0x30, 0x9e, 0x4f, + 0xfb, 0xab, 0x2c, 0xe5, 0x8b, 0xce, 0x2a, 0xab, 0x20, 0x2d, 0x93, 0xad, 0x2d, 0x57, 0x53, 0x0b, + 0x03, 0xaf, 0x45, 0x7b, 0x2d, 0x7a, 0xed, 0xcd, 0x98, 0xe7, 0xde, 0xae, 0x58, 0x4a, 0x4c, 0x3d, + 0x36, 0x51, 0xe9, 0x5d, 0x67, 0x7b, 0xb5, 0x74, 0x41, 0xcb, 0xba, 0xb1, 0xc2, 0xd3, 0xdb, 0x22, + 0xac, 0x5c, 0xb8, 0x40, 0x6f, 0x48, 0xac, 0x4c, 0x14, 0x3a, 0x41, 0x33, 0x55, 0x1d, 0x1e, 0x81, + 0x52, 0x30, 0xf0, 0x2e, 0x88, 0xc3, 0x3b, 0xfb, 0x22, 0x0e, 0x43, 0x10, 0xd3, 0xaa, 0x7a, 0x03, + 0x08, 0xa2, 0x81, 0xad, 0x15, 0x1a, 0xca, 0xde, 0xd3, 0x25, 0x2d, 0x69, 0x67, 0xf9, 0xe6, 0x9f, + 0x89, 0x1b, 0xd4, 0xec, 0x93, 0x96, 0x09, 0x51, 0x7c, 0xd2, 0x32, 0x11, 0x93, 0x10, 0xae, 0xf1, + 0xf7, 0x8b, 0x46, 0xa3, 0x14, 0xa4, 0xd5, 0x68, 0xe0, 0xfd, 0x30, 0xb8, 0x54, 0x83, 0x89, 0x97, + 0x24, 0x07, 0x9b, 0x70, 0xd0, 0x44, 0x14, 0xa4, 0x52, 0xe5, 0xb7, 0x12, 0x62, 0xb4, 0x69, 0x02, + 0x23, 0x9f, 0x20, 0xd6, 0xe8, 0x50, 0x87, 0x47, 0xf2, 0xef, 0x27, 0x2d, 0xaa, 0x51, 0x5d, 0x35, + 0xf1, 0x67, 0x9b, 0xab, 0xbe, 0x03, 0x0f, 0x9b, 0x2a, 0x18, 0xea, 0x47, 0x42, 0x58, 0x42, 0x93, + 0xb1, 0x79, 0x78, 0xf9, 0xa4, 0x7f, 0xd8, 0x78, 0xd2, 0xea, 0x3f, 0xa0, 0x2e, 0x28, 0xd1, 0x0f, + 0x87, 0xd4, 0xdc, 0xfa, 0xaa, 0xf7, 0xea, 0xd6, 0xe1, 0xc2, 0x6b, 0x84, 0xcf, 0x98, 0xc0, 0x1c, + 0x53, 0xff, 0xeb, 0xf7, 0x27, 0xea, 0x49, 0x3f, 0xef, 0x06, 0x7f, 0xba, 0x4f, 0xd7, 0x55, 0xe6, + 0x08, 0xbb, 0xa9, 0xa2, 0x90, 0x1f, 0x0e, 0x36, 0x13, 0x76, 0xa4, 0x38, 0xf5, 0xfa, 0x35, 0x27, + 0xce, 0xdc, 0xf0, 0x9d, 0xfa, 0xa6, 0xe2, 0x39, 0x38, 0xd8, 0x7c, 0x37, 0xf3, 0x43, 0xdb, 0x41, + 0x3f, 0xf5, 0xfa, 0x9b, 0x87, 0xc7, 0xaf, 0x5e, 0xa8, 0xca, 0xbe, 0x46, 0xa3, 0x91, 0x85, 0x20, + 0x02, 0x68, 0x3a, 0xbd, 0xa2, 0x6b, 0xac, 0x72, 0x0a, 0x21, 0xd0, 0x57, 0x11, 0x69, 0x0a, 0x05, + 0xfa, 0x69, 0x68, 0x75, 0x98, 0xf6, 0xe5, 0x28, 0x4e, 0x5f, 0x44, 0xb4, 0x5a, 0xce, 0x6b, 0xf5, + 0xcd, 0xc3, 0x57, 0xfc, 0xac, 0xfe, 0xf1, 0xe4, 0xdd, 0x5b, 0xc2, 0x01, 0xd7, 0x96, 0x76, 0x74, + 0x8b, 0xd9, 0x5f, 0x26, 0x49, 0xc4, 0xb6, 0x2c, 0x52, 0x22, 0xbd, 0xad, 0xa0, 0x44, 0xaf, 0xaf, + 0x24, 0x5c, 0xa2, 0x1a, 0x5d, 0x89, 0xf6, 0x10, 0x26, 0x64, 0x1d, 0x1a, 0x6f, 0xe1, 0x25, 0xc3, + 0x24, 0x9c, 0x55, 0x82, 0xf0, 0x66, 0x01, 0x6a, 0x17, 0x8e, 0x62, 0x2c, 0x10, 0xe8, 0xf1, 0x0f, + 0x62, 0xb0, 0x52, 0xfd, 0x1b, 0x35, 0xf4, 0x47, 0x1e, 0x6c, 0x58, 0x8a, 0x8f, 0x66, 0x8f, 0xbe, + 0x7b, 0xe1, 0xcd, 0xbc, 0x7e, 0x30, 0xa1, 0x8d, 0xbc, 0x56, 0x57, 0x63, 0xda, 0x36, 0x12, 0x15, + 0xd0, 0x14, 0x84, 0x93, 0x1b, 0x75, 0x35, 0xf6, 0x43, 0xc6, 0x27, 0xfd, 0xd7, 0xa2, 0x56, 0x5a, + 0x97, 0x9d, 0xd6, 0xc0, 0x14, 0x0f, 0x10, 0x75, 0xc5, 0x3b, 0xe9, 0xa5, 0x4f, 0x65, 0x63, 0x1f, + 0x08, 0x4c, 0x54, 0x0c, 0xc1, 0x32, 0xa1, 0xad, 0x48, 0x1d, 0x1c, 0x1c, 0xa8, 0x91, 0x37, 0x49, + 0xfc, 0x9e, 0x62, 0xd9, 0x8d, 0x46, 0x66, 0x80, 0x89, 0x01, 0x46, 0x4d, 0x49, 0x31, 0x52, 0x5e, + 0xc8, 0x61, 0xcd, 0x54, 0x34, 0x98, 0xcc, 0x63, 0x5f, 0xd1, 0xe6, 0x34, 0x18, 0xab, 0x74, 0xec, + 0x83, 0x48, 0x40, 0x0a, 0x8a, 0x46, 0x3a, 0x56, 0x61, 0xa4, 0x68, 0x21, 0x2b, 0xac, 0x96, 0x26, + 0xe3, 0xbe, 0x02, 0x39, 0x4c, 0x32, 0x5e, 0x1f, 0x53, 0xdd, 0x08, 0x7e, 0xae, 0x46, 0x56, 0xf0, + 0x33, 0x70, 0x75, 0x04, 0x1f, 0x27, 0xf5, 0xdd, 0xdc, 0xc3, 0xb8, 0x57, 0xa0, 0xdb, 0x86, 0x98, + 0x13, 0xf6, 0x3d, 0x08, 0xff, 0x30, 0x27, 0xf6, 0x6a, 0x12, 0xe2, 0x13, 0xdd, 0x17, 0xe6, 0xfc, + 0xb6, 0x82, 0x9a, 0x8a, 0x07, 0xbc, 0xba, 0x2b, 0x78, 0x99, 0xe4, 0x2c, 0xc0, 0x50, 0x63, 0x37, + 0x77, 0x34, 0xaf, 0x22, 0x4b, 0xc3, 0xa1, 0x33, 0x42, 0x34, 0xc3, 0x32, 0xc4, 0xb7, 0x48, 0xb6, + 0xa5, 0xbd, 0x40, 0xaa, 0x98, 0xe2, 0x0d, 0xfd, 0xb5, 0xc8, 0x6a, 0xf4, 0xbe, 0x68, 0x7a, 0x97, + 0xed, 0x9d, 0x03, 0x5e, 0x64, 0xf3, 0x98, 0xf7, 0xab, 0x66, 0xb3, 0x59, 0x42, 0x77, 0x01, 0x30, + 0xb6, 0xa6, 0x4d, 0xc5, 0x1b, 0xc2, 0xc1, 0xa6, 0x6d, 0x79, 0x59, 0xc6, 0xf6, 0xb4, 0x48, 0x5d, + 0xea, 0x5f, 0xf6, 0xb6, 0x12, 0x52, 0x25, 0x8f, 0xa0, 0x19, 0x56, 0x99, 0xc3, 0x82, 0x80, 0xb3, + 0x1e, 0x8d, 0xbf, 0x40, 0x3e, 0xf1, 0xfc, 0xe1, 0x05, 0x2b, 0x2c, 0x09, 0x18, 0xc8, 0x33, 0x3c, + 0x2b, 0xfd, 0xa2, 0xc0, 0x42, 0x96, 0x36, 0xa5, 0x75, 0x1a, 0x9b, 0x9a, 0xbc, 0x4b, 0xff, 0x59, + 0x38, 0x3c, 0x96, 0x0f, 0x00, 0x7b, 0x42, 0x6f, 0xd4, 0x9f, 0xbc, 0xe9, 0xac, 0xa7, 0xf4, 0xdb, + 0xfb, 0xc1, 0xd6, 0x7e, 0x06, 0x16, 0x6c, 0xfd, 0xc6, 0xea, 0xf2, 0x4b, 0x79, 0xf3, 0xa9, 0x00, + 0xd1, 0x7d, 0x12, 0x2e, 0x5f, 0x0a, 0x3f, 0x01, 0x44, 0x83, 0xee, 0x25, 0x3a, 0xf6, 0x0a, 0x0b, + 0x0e, 0xd6, 0x0b, 0x43, 0x53, 0x06, 0x5c, 0xb9, 0x57, 0xd8, 0xb1, 0x0d, 0xfc, 0x85, 0x90, 0xcd, + 0xfb, 0xd9, 0x1c, 0x64, 0x56, 0x45, 0xc9, 0xa4, 0x25, 0x31, 0x0f, 0x53, 0x50, 0x15, 0x8b, 0x02, + 0xab, 0x58, 0x7d, 0xb7, 0x74, 0xc8, 0xbd, 0x6a, 0x85, 0xe5, 0x4b, 0x8b, 0xd8, 0xe5, 0x66, 0xa9, + 0x5c, 0x76, 0xd2, 0x2d, 0xd9, 0x21, 0x76, 0x0e, 0x5f, 0xd8, 0x2b, 0x83, 0xa4, 0x9f, 0x1d, 0xce, + 0xe6, 0xc0, 0x67, 0x9c, 0x56, 0x15, 0x7e, 0x41, 0x3d, 0x4d, 0x59, 0x3a, 0x7a, 0x92, 0xc6, 0xf8, + 0x79, 0xf8, 0x86, 0xcf, 0x1a, 0x9f, 0xb4, 0xe8, 0x27, 0x1e, 0x5f, 0x85, 0x43, 0xd6, 0xa3, 0xb2, + 0x17, 0x2f, 0x7d, 0x12, 0x7c, 0x83, 0x99, 0x40, 0xd6, 0xef, 0x08, 0xc7, 0x33, 0x5a, 0x16, 0xbe, + 0x7a, 0x25, 0x67, 0x84, 0xf2, 0xa1, 0x05, 0x88, 0x2d, 0x03, 0xdd, 0x88, 0x5e, 0xdc, 0xcc, 0xd0, + 0xee, 0x87, 0x9c, 0x6e, 0x6e, 0x1e, 0x7e, 0xf3, 0xea, 0x94, 0x8a, 0x0f, 0xcb, 0x9f, 0x71, 0xca, + 0xba, 0x79, 0x68, 0xb6, 0x09, 0x2d, 0x11, 0x55, 0x15, 0x84, 0x3d, 0x99, 0xd7, 0x8b, 0xd2, 0x85, + 0x5c, 0xa5, 0x65, 0x20, 0x05, 0x07, 0x59, 0x97, 0xd1, 0xcd, 0x87, 0x6f, 0xb4, 0x8c, 0xd5, 0x0a, + 0x40, 0xfa, 0xa4, 0x73, 0xf3, 0xf0, 0x76, 0x33, 0xba, 0xd8, 0x24, 0xd5, 0x66, 0xee, 0xbb, 0xec, + 0xc2, 0xba, 0xd9, 0xbd, 0xc5, 0xfa, 0x3c, 0x33, 0x62, 0x59, 0x77, 0xb3, 0xdd, 0xdc, 0x69, 0xee, + 0x6e, 0xba, 0x9b, 0x46, 0xd8, 0xea, 0x6e, 0x62, 0x2d, 0xed, 0xfb, 0x9b, 0x77, 0x77, 0x02, 0x19, + 0x48, 0xf8, 0xed, 0xa3, 0x16, 0x56, 0xb7, 0x7c, 0xd0, 0x5f, 0xcf, 0x27, 0x93, 0x22, 0x3f, 0x54, + 0x5e, 0xa2, 0x85, 0x8e, 0x07, 0x8e, 0x4f, 0xa0, 0xd0, 0x2f, 0xe2, 0xa8, 0x77, 0x9f, 0x79, 0x14, + 0xd6, 0x16, 0xbf, 0x62, 0x2c, 0x1c, 0x34, 0x82, 0xd8, 0x3d, 0x74, 0x49, 0x36, 0xe9, 0xe9, 0x3c, + 0xd5, 0xb2, 0x04, 0xf4, 0x90, 0xe8, 0xc1, 0x83, 0x62, 0x63, 0x50, 0x82, 0x5f, 0x97, 0x24, 0x88, + 0x44, 0xed, 0x26, 0xa4, 0x52, 0x7a, 0xca, 0xe1, 0xd2, 0xcc, 0x41, 0x92, 0xa5, 0x79, 0xfb, 0xbc, + 0x63, 0x9e, 0x46, 0xc3, 0x55, 0x83, 0x3d, 0xf1, 0xc3, 0x24, 0x8a, 0x15, 0x4a, 0x29, 0x9f, 0xe3, + 0xee, 0x64, 0xf6, 0x78, 0xd4, 0xc4, 0x08, 0x61, 0x46, 0x60, 0x4a, 0x26, 0xb1, 0xda, 0x25, 0x91, + 0x66, 0xa8, 0xb7, 0x5a, 0x45, 0xca, 0x10, 0xc3, 0x7e, 0x30, 0x2a, 0xc4, 0x48, 0xee, 0x0f, 0xcf, + 0x08, 0xc2, 0x66, 0xb7, 0xed, 0xe6, 0x2f, 0x00, 0x6e, 0xb3, 0xbb, 0xed, 0x6e, 0xd2, 0x17, 0xc2, + 0xce, 0x87, 0xdb, 0x4d, 0x53, 0x84, 0x07, 0xc1, 0x6f, 0xd8, 0xd3, 0x8b, 0xdf, 0xb1, 0x42, 0x4a, + 0xc5, 0xf7, 0xf6, 0xe9, 0x41, 0x54, 0xd2, 0x4d, 0xd2, 0x49, 0x77, 0x51, 0xdc, 0xbb, 0x3e, 0x63, + 0x04, 0x3f, 0xa6, 0x07, 0x1e, 0x67, 0x77, 0x93, 0xa8, 0x69, 0xf3, 0xee, 0x23, 0xfd, 0xdf, 0x67, + 0xc5, 0xee, 0xb9, 0x9f, 0x3e, 0x7d, 0x12, 0x1c, 0x92, 0x3e, 0xfa, 0xa4, 0x15, 0x1c, 0x2e, 0x47, + 0xf3, 0x37, 0x3e, 0xc9, 0x28, 0x2a, 0xa1, 0x3d, 0x1c, 0x2c, 0x90, 0x29, 0x5c, 0x31, 0x4d, 0xd0, + 0x0e, 0x32, 0x99, 0xfb, 0x9f, 0x46, 0x4f, 0x34, 0x2a, 0x8b, 0x9a, 0xdc, 0x4d, 0x06, 0xb5, 0xd9, + 0xdd, 0x6f, 0x7f, 0xde, 0x31, 0x26, 0xd9, 0x18, 0x0f, 0x74, 0x67, 0x57, 0x8d, 0x94, 0xe4, 0xb5, + 0xc2, 0x00, 0x9b, 0xea, 0x35, 0xc8, 0x45, 0x16, 0x80, 0x88, 0xe6, 0x2a, 0x98, 0x4e, 0xfd, 0x61, + 0x40, 0x5a, 0xfa, 0xe4, 0xa6, 0xa7, 0xb4, 0xb0, 0x60, 0x4a, 0xc0, 0xdf, 0x37, 0xf6, 0x21, 0x38, + 0x9f, 0x91, 0x6a, 0x05, 0x39, 0xeb, 0xb7, 0x22, 0xa7, 0x1f, 0x10, 0xc3, 0x4d, 0xfd, 0x1c, 0x41, + 0xbb, 0x70, 0xa1, 0xfc, 0xac, 0x28, 0x8a, 0x8d, 0x04, 0xb3, 0x0c, 0x2b, 0xc7, 0x3e, 0x24, 0xcb, + 0x0c, 0x31, 0x71, 0x34, 0x85, 0xe4, 0x75, 0xc1, 0x0b, 0x4a, 0x46, 0xcb, 0x8a, 0xc1, 0x08, 0x6c, + 0x94, 0xf6, 0xe2, 0x08, 0xe7, 0x93, 0xb3, 0x60, 0xc6, 0x71, 0xca, 0x0f, 0x1e, 0xbf, 0x00, 0x94, + 0xb7, 0x85, 0x71, 0xfe, 0xd6, 0x61, 0x7a, 0x24, 0x85, 0xa6, 0xf3, 0xea, 0x35, 0x2f, 0xe3, 0x94, + 0xb9, 0x9e, 0xe3, 0xac, 0xd1, 0x14, 0x56, 0xb5, 0xd0, 0xf7, 0x31, 0xf5, 0xfa, 0xb9, 0xe9, 0x87, + 0x22, 0x71, 0x6e, 0x11, 0x1d, 0xcc, 0xcd, 0x53, 0x4f, 0x9d, 0x60, 0xdf, 0x7a, 0xc5, 0xfa, 0x59, + 0xfd, 0xc1, 0x43, 0xa6, 0x99, 0x0d, 0x86, 0xe6, 0x25, 0xa4, 0x65, 0x02, 0x69, 0x1e, 0x61, 0x25, + 0x7b, 0xe9, 0xd3, 0x8e, 0xd2, 0x6e, 0xee, 0x11, 0x6f, 0x81, 0x5a, 0xc3, 0x8f, 0x8d, 0x76, 0x93, + 0x78, 0xcd, 0x8d, 0x77, 0xc5, 0x4f, 0x9d, 0xe6, 0xe3, 0xdf, 0x05, 0x57, 0xb4, 0xe9, 0x4c, 0x82, + 0x3e, 0x08, 0xf0, 0x6c, 0xe2, 0x93, 0x42, 0xb9, 0x1c, 0x77, 0xdf, 0x46, 0xc4, 0x0e, 0x40, 0x05, + 0x03, 0x0f, 0x6c, 0x58, 0x71, 0xf1, 0xae, 0x22, 0x39, 0x39, 0x26, 0x9d, 0x2e, 0x51, 0xff, 0xad, + 0x03, 0x17, 0xd2, 0x68, 0xa4, 0x20, 0x5a, 0x4e, 0x5c, 0x48, 0xa0, 0x97, 0xf4, 0x1a, 0x24, 0x34, + 0x83, 0x3c, 0x40, 0x0a, 0x54, 0x8e, 0xe4, 0x34, 0x0e, 0xa6, 0xc7, 0x32, 0xf0, 0x16, 0x7e, 0xbf, + 0xd7, 0xc3, 0x56, 0x35, 0xb3, 0xde, 0x62, 0xff, 0xe7, 0x79, 0x10, 0xfb, 0xc3, 0x87, 0x23, 0xdb, + 0x82, 0x4d, 0x58, 0xdc, 0x6e, 0x82, 0x01, 0xdb, 0x6d, 0x10, 0x53, 0x6e, 0x37, 0x77, 0x77, 0xdc, + 0x4d, 0xdd, 0xd4, 0xb1, 0x6e, 0xa9, 0x82, 0x22, 0x49, 0x26, 0x15, 0xc1, 0x8c, 0xfe, 0x82, 0x0e, + 0x6c, 0x29, 0x75, 0x95, 0x80, 0xf9, 0x4a, 0xaf, 0x91, 0x17, 0xe2, 0xca, 0xf4, 0x9f, 0x4b, 0xc4, + 0x24, 0x6e, 0xbe, 0x56, 0xe0, 0x32, 0x12, 0x36, 0xad, 0x23, 0x18, 0xbc, 0x98, 0xb3, 0x09, 0x5f, + 0x49, 0x32, 0x5b, 0xcb, 0x43, 0xd9, 0x26, 0x76, 0xcc, 0xcf, 0xbd, 0x79, 0x60, 0x2c, 0x90, 0x6b, + 0x56, 0xc8, 0xcb, 0x83, 0x74, 0xee, 0x4d, 0xd8, 0x8c, 0x97, 0xb1, 0x3e, 0x0c, 0xa9, 0x36, 0xf5, + 0x6e, 0x88, 0x49, 0x8e, 0x48, 0x3b, 0x91, 0x81, 0x09, 0x4a, 0xea, 0x9f, 0x36, 0xae, 0xbd, 0xc7, + 0x9f, 0x69, 0x5c, 0x58, 0x36, 0x44, 0xd6, 0xad, 0x60, 0x18, 0xaf, 0x10, 0x21, 0xa3, 0x78, 0x20, + 0x06, 0x20, 0xb3, 0xd3, 0xa9, 0xa3, 0x97, 0xc7, 0xca, 0x98, 0xad, 0x1f, 0x3c, 0x04, 0x6a, 0xec, + 0x33, 0x2e, 0x9e, 0xa3, 0x93, 0xf7, 0x5a, 0xf3, 0x2e, 0x59, 0x8b, 0xfe, 0x33, 0x2d, 0x22, 0x6f, + 0x15, 0xc9, 0x91, 0x6a, 0x8d, 0x03, 0xcc, 0x28, 0x81, 0x5d, 0x8e, 0xe6, 0xe7, 0x3c, 0x8c, 0x10, + 0x36, 0x93, 0x74, 0x55, 0x32, 0x9e, 0xc3, 0xff, 0xd7, 0x55, 0xe7, 0x5e, 0x40, 0x52, 0xef, 0x84, + 0xe3, 0xee, 0x78, 0x75, 0xb9, 0x30, 0xf6, 0xa5, 0x0f, 0x9f, 0x3b, 0xd3, 0xce, 0xd9, 0x9c, 0xc8, + 0xf0, 0xd1, 0xce, 0xce, 0x0e, 0x36, 0x28, 0x08, 0xdd, 0x67, 0x68, 0x82, 0x36, 0x9e, 0xf6, 0xf6, + 0xae, 0xcb, 0xba, 0xce, 0xe7, 0x5c, 0x77, 0xde, 0x55, 0x7f, 0xf5, 0xf8, 0x95, 0x38, 0xe4, 0xf5, + 0xbd, 0x09, 0x1f, 0x88, 0x2b, 0x89, 0x3b, 0x45, 0x04, 0x3c, 0x54, 0x00, 0xea, 0xaf, 0xab, 0x8e, + 0xbf, 0x79, 0xce, 0x68, 0x48, 0x78, 0xe8, 0xa2, 0xa6, 0x7c, 0x82, 0x3a, 0x47, 0x70, 0xcf, 0x00, + 0x97, 0x16, 0xe1, 0x5e, 0x9b, 0xb6, 0x0a, 0x33, 0x70, 0x92, 0xdc, 0x3f, 0xff, 0xb8, 0x83, 0x9f, + 0x97, 0x0f, 0xfb, 0xbb, 0xb9, 0x1f, 0xdf, 0x28, 0xb8, 0xec, 0x60, 0x05, 0x1c, 0x7d, 0xa7, 0xd8, + 0x3b, 0xc7, 0xa7, 0xe9, 0x4e, 0x44, 0xdf, 0x19, 0xcc, 0x63, 0xc4, 0xd6, 0xcb, 0x7c, 0x3f, 0x94, + 0x81, 0xb2, 0xba, 0x42, 0xf0, 0x58, 0x91, 0x23, 0xaa, 0x09, 0xfd, 0xc4, 0x12, 0xca, 0xf7, 0xda, + 0xa4, 0x7a, 0x7c, 0xde, 0x81, 0x1a, 0xc1, 0x9c, 0x5b, 0xbd, 0xaf, 0x68, 0x9e, 0x29, 0x21, 0xf6, + 0xf0, 0x9b, 0xea, 0x65, 0x94, 0xc2, 0x0d, 0x53, 0x74, 0xbf, 0x11, 0x11, 0x42, 0x32, 0xef, 0x37, + 0xb4, 0x44, 0x5e, 0xf3, 0x9b, 0xe7, 0x4d, 0xa1, 0x0f, 0x3e, 0x65, 0x6b, 0xde, 0x9c, 0x45, 0xa3, + 0x24, 0x3d, 0xd8, 0x6e, 0xb7, 0x1f, 0xce, 0x8c, 0x0d, 0x8a, 0xc4, 0x0c, 0x92, 0xa4, 0x9f, 0xa4, + 0xb6, 0xbc, 0x7f, 0x77, 0x72, 0x3f, 0x0c, 0x49, 0x6a, 0xd0, 0xe5, 0x18, 0x79, 0x0e, 0x93, 0x7c, + 0x43, 0x27, 0x10, 0x2d, 0x12, 0x04, 0x6f, 0x39, 0x30, 0x60, 0xa8, 0x5a, 0x34, 0x4f, 0x67, 0x73, + 0x1c, 0xde, 0xa8, 0x1c, 0x74, 0xbd, 0x69, 0x0b, 0xac, 0x0f, 0x67, 0xe8, 0xdc, 0xe4, 0x12, 0x91, + 0xe8, 0x53, 0x29, 0x03, 0x87, 0x89, 0xc4, 0xc4, 0x5a, 0x41, 0x32, 0x5b, 0xa1, 0x89, 0x78, 0x57, + 0x4c, 0xfe, 0xba, 0x30, 0xcc, 0x34, 0xef, 0x69, 0xa8, 0xd4, 0x80, 0x3f, 0x4f, 0x1a, 0x6c, 0x87, + 0x54, 0xb3, 0x09, 0x2d, 0x50, 0x05, 0xf3, 0xe2, 0xca, 0x81, 0xe1, 0xc4, 0xf1, 0xcc, 0x62, 0x6f, + 0x0a, 0xdc, 0xed, 0x6f, 0x1b, 0x1b, 0xfc, 0x1e, 0x6b, 0x5c, 0x81, 0xb7, 0x7d, 0x86, 0x0d, 0x2b, + 0x3b, 0x72, 0xf8, 0xcf, 0xb5, 0x45, 0xc9, 0xb9, 0x4a, 0x6b, 0x8d, 0xea, 0x78, 0xa2, 0xa5, 0x75, + 0x8d, 0x82, 0xa6, 0x7a, 0xc7, 0x1d, 0x26, 0x91, 0xe9, 0x09, 0x84, 0xa5, 0xc3, 0xa7, 0xc3, 0x20, + 0x3e, 0x68, 0x01, 0xf2, 0x93, 0x16, 0xbf, 0xe0, 0xf5, 0xab, 0x69, 0x56, 0x82, 0xdf, 0xa2, 0xf8, + 0xe1, 0x14, 0x2a, 0x27, 0x0d, 0xda, 0x9e, 0x88, 0x65, 0x4a, 0xa0, 0xe8, 0xa9, 0x95, 0x12, 0x23, + 0xff, 0xdc, 0xca, 0xb3, 0x46, 0x43, 0x34, 0x5b, 0x85, 0x85, 0x68, 0x96, 0xf1, 0xe7, 0x38, 0xa7, + 0x87, 0x4f, 0x1f, 0x55, 0xf4, 0xbb, 0x8d, 0x83, 0xb6, 0xcf, 0x64, 0x95, 0x29, 0x40, 0x77, 0x5e, + 0xe4, 0x09, 0x57, 0xf5, 0x6f, 0x52, 0x52, 0xe3, 0xae, 0xe2, 0x80, 0x04, 0x0f, 0x12, 0x39, 0x58, + 0x42, 0x54, 0x6c, 0xc5, 0xa7, 0x7d, 0xd7, 0x3f, 0x9f, 0x22, 0x96, 0xe0, 0x93, 0x06, 0x7a, 0x49, + 0x5c, 0x95, 0xcf, 0x29, 0xdd, 0x4d, 0xf1, 0x96, 0x60, 0xbb, 0x19, 0x37, 0x47, 0xbf, 0x7e, 0x8f, + 0xc1, 0x2f, 0xd3, 0x3b, 0x8c, 0x71, 0x20, 0x49, 0x35, 0xd1, 0x36, 0x31, 0x24, 0xfe, 0xd5, 0xd2, + 0x2f, 0xc6, 0xfe, 0xe5, 0x20, 0x23, 0xe0, 0x60, 0x82, 0xc3, 0xda, 0x50, 0x17, 0x16, 0xd8, 0x4d, + 0x22, 0x40, 0x53, 0x80, 0x77, 0x6b, 0x1c, 0x8b, 0xb8, 0x6a, 0x9a, 0x06, 0x53, 0x1f, 0x58, 0xf3, + 0xfd, 0x56, 0x4a, 0x3b, 0xd8, 0x44, 0xf0, 0xd9, 0x54, 0xdf, 0x1f, 0xb1, 0x4e, 0xc1, 0x70, 0xa0, + 0x55, 0x17, 0x0f, 0xe9, 0x95, 0xd7, 0x8f, 0x2e, 0xfd, 0xe6, 0x83, 0xf1, 0xaa, 0x57, 0xc1, 0x34, + 0x4c, 0x5b, 0xd3, 0xe9, 0xa0, 0x3f, 0xb9, 0x68, 0xcf, 0x3a, 0xb4, 0x38, 0xb8, 0xc7, 0x24, 0x03, + 0x90, 0x3c, 0xf3, 0xf1, 0xf7, 0x42, 0x6c, 0x6b, 0x18, 0x5d, 0x85, 0x30, 0x23, 0x3d, 0x45, 0x6b, + 0x07, 0xb4, 0xf3, 0x87, 0xac, 0x4b, 0xac, 0xdc, 0xf2, 0xd3, 0xd8, 0xf7, 0xa6, 0xb4, 0xeb, 0x67, + 0x60, 0xc0, 0xf0, 0x49, 0x31, 0xf1, 0xd2, 0xd4, 0x1b, 0x8c, 0x41, 0x5b, 0xca, 0x80, 0x5d, 0x89, + 0x8b, 0x1a, 0xda, 0x54, 0x60, 0x7c, 0xf5, 0xdf, 0x6b, 0x74, 0xfe, 0x84, 0x76, 0xde, 0x07, 0x8c, + 0xed, 0x25, 0x57, 0x28, 0x8c, 0x8d, 0x37, 0xed, 0x25, 0x44, 0xd3, 0xc4, 0x49, 0xd7, 0x3c, 0xc1, + 0x52, 0x1b, 0xfb, 0x21, 0xd3, 0x98, 0x0a, 0x12, 0x6d, 0xce, 0x9e, 0xdc, 0xa8, 0xbe, 0x0f, 0x08, + 0x52, 0xcd, 0x1f, 0xde, 0x93, 0x30, 0x3e, 0x87, 0x3a, 0xf6, 0x92, 0xd4, 0xaf, 0x86, 0x4c, 0xd4, + 0x7f, 0xae, 0xfd, 0x6d, 0x48, 0x03, 0x5b, 0xcb, 0x0e, 0x31, 0x7a, 0xe4, 0x90, 0x0f, 0x43, 0x7f, + 0xa2, 0xa4, 0xb0, 0xaa, 0xed, 0xb6, 0x77, 0x55, 0x30, 0x52, 0x24, 0x91, 0xea, 0xf9, 0xa9, 0x7f, + 0x32, 0x03, 0x94, 0xb7, 0xc6, 0x06, 0xcc, 0xb6, 0x5f, 0xf7, 0xf7, 0x31, 0x75, 0xc8, 0x70, 0x49, + 0x26, 0xd7, 0x8d, 0x81, 0x8a, 0xdf, 0xae, 0x97, 0xc8, 0x87, 0x36, 0x02, 0x74, 0x55, 0xf0, 0xac, + 0x8b, 0xfe, 0x8c, 0x30, 0xd1, 0x69, 0x20, 0x0f, 0xcd, 0xa7, 0x48, 0xda, 0xc6, 0x0a, 0xfe, 0x6f, + 0x60, 0xfe, 0xce, 0x46, 0x7e, 0x1e, 0xcd, 0x3e, 0x65, 0xd4, 0xdf, 0xbc, 0x7b, 0xaf, 0xd8, 0x55, + 0x96, 0x7a, 0x88, 0xa1, 0x27, 0xb4, 0x08, 0xc3, 0x61, 0xf2, 0xc9, 0x43, 0xa6, 0x6e, 0xe4, 0xc3, + 0xed, 0x34, 0xdb, 0xf9, 0xfe, 0xf7, 0xbb, 0xcc, 0xf9, 0x3d, 0x4c, 0x41, 0xb6, 0xf5, 0x87, 0x34, + 0x86, 0xc2, 0xf0, 0xff, 0x0d, 0xac, 0x41, 0x0b, 0x07, 0xff, 0x05, 0xc3, 0xcf, 0x3d, 0x0f, 0xfe, + 0x83, 0x9f, 0x17, 0xbd, 0x69, 0x4c, 0xe8, 0xab, 0xf1, 0x3d, 0x79, 0xc9, 0xf2, 0x26, 0x5b, 0xa8, + 0x13, 0x44, 0xe0, 0xf3, 0xce, 0x4b, 0xea, 0x86, 0x43, 0xdb, 0x30, 0x9a, 0x6c, 0xcc, 0xe2, 0x08, + 0x9f, 0xc0, 0x6a, 0x73, 0x65, 0xab, 0xa9, 0x7e, 0x60, 0x8d, 0x5b, 0x79, 0xb1, 0x4f, 0x1c, 0xd8, + 0x1b, 0xf2, 0xb9, 0xb9, 0x70, 0x73, 0x0d, 0x40, 0x11, 0x0d, 0x8f, 0x11, 0x19, 0x4d, 0x38, 0x53, + 0x03, 0xda, 0xba, 0xfc, 0xa1, 0x1c, 0x47, 0x8a, 0xd7, 0x03, 0xf6, 0xf4, 0x0b, 0x5f, 0xf9, 0xa3, + 0x11, 0x9a, 0x8f, 0x64, 0xc7, 0x0f, 0x49, 0x81, 0xd1, 0xe2, 0x14, 0x04, 0x06, 0x12, 0x89, 0xcd, + 0x61, 0x13, 0x9a, 0x47, 0x09, 0x73, 0xc4, 0xd2, 0xb4, 0xdd, 0x24, 0xe8, 0xd7, 0x78, 0xc7, 0x78, + 0x64, 0xac, 0x8c, 0x60, 0x29, 0xa4, 0x5c, 0xb4, 0xc3, 0x58, 0xe0, 0x01, 0x2a, 0x74, 0xfe, 0xde, + 0x0c, 0x52, 0x58, 0xbb, 0xe5, 0x1a, 0x64, 0xf9, 0xd0, 0x8b, 0x77, 0x90, 0x71, 0x04, 0x5a, 0xc0, + 0xb0, 0x89, 0x36, 0xdc, 0x34, 0xf5, 0x92, 0x00, 0xc4, 0xa1, 0x6b, 0x89, 0x17, 0x09, 0x3b, 0x4c, + 0x2b, 0x2b, 0x5b, 0x9a, 0x29, 0x2b, 0x11, 0x48, 0xd8, 0x4d, 0x37, 0xa1, 0xd7, 0x0d, 0xfc, 0x71, + 0x34, 0x19, 0xfa, 0xf1, 0xc1, 0x66, 0xd6, 0x33, 0xbe, 0xa9, 0x23, 0xd3, 0xf2, 0x45, 0x2d, 0xaf, + 0xdf, 0x13, 0xae, 0xac, 0xb1, 0x22, 0x60, 0x9e, 0x4b, 0xd2, 0x9a, 0x63, 0xd5, 0x71, 0xb7, 0xdd, + 0x1d, 0x56, 0x47, 0xbc, 0x38, 0xf6, 0x6e, 0x92, 0x0c, 0xea, 0x4a, 0x0f, 0xa5, 0xdc, 0x69, 0xc8, + 0x4f, 0x8f, 0xbe, 0xe3, 0x6e, 0xd6, 0xc4, 0x87, 0x30, 0x77, 0x9d, 0xc9, 0x66, 0x8b, 0x7e, 0xcc, + 0x2a, 0xe6, 0xea, 0x1e, 0xa1, 0x7c, 0x76, 0x32, 0xd1, 0xcd, 0xc3, 0x17, 0x68, 0x92, 0x64, 0x89, + 0x8c, 0x28, 0x49, 0x1e, 0x98, 0x44, 0x57, 0x20, 0xe1, 0x08, 0x2e, 0x9e, 0x41, 0x9a, 0x28, 0x7f, + 0x18, 0x90, 0x2a, 0xd5, 0x54, 0x6f, 0xe6, 0x93, 0x34, 0x10, 0xeb, 0x88, 0x94, 0xa7, 0x4f, 0x3c, + 0x93, 0x22, 0x97, 0xc2, 0xc0, 0x94, 0x9b, 0x4f, 0x48, 0xc4, 0x9c, 0xfd, 0x66, 0xa2, 0x92, 0xb8, + 0xcc, 0x8c, 0xb0, 0xf2, 0xa9, 0x7b, 0x41, 0x9c, 0xfd, 0x3c, 0x8a, 0xd9, 0x9f, 0x81, 0x45, 0x87, + 0x65, 0xf8, 0xd8, 0xbb, 0x37, 0x3e, 0xf6, 0x97, 0xe0, 0x83, 0x30, 0x21, 0x27, 0xf5, 0xf0, 0xa2, + 0xc4, 0x9c, 0x02, 0x1d, 0x2c, 0x50, 0xb2, 0x24, 0x4d, 0x93, 0x7a, 0xf8, 0x67, 0x78, 0xd9, 0xd2, + 0xf8, 0x13, 0x53, 0x34, 0xd1, 0xc2, 0x58, 0x34, 0x3b, 0x03, 0x09, 0xa9, 0x03, 0x35, 0xf5, 0x42, + 0x62, 0x3a, 0x5a, 0x24, 0xeb, 0xa1, 0xd2, 0x9f, 0x86, 0xfe, 0x79, 0x6f, 0x7d, 0x45, 0xb8, 0x43, + 0x19, 0x49, 0x2e, 0x43, 0xa9, 0xb5, 0x96, 0x06, 0x19, 0x26, 0x0a, 0x1e, 0x75, 0xbf, 0x01, 0xe9, + 0x12, 0x88, 0x9f, 0x63, 0x5d, 0xcc, 0x87, 0x62, 0x38, 0xd7, 0x5e, 0xb5, 0x2d, 0x62, 0xa4, 0x62, + 0x61, 0xb2, 0x16, 0x77, 0xbe, 0x70, 0x4d, 0xa0, 0x7d, 0x35, 0xd9, 0x4b, 0x1c, 0xb9, 0x45, 0xef, + 0x3f, 0xa3, 0x81, 0xa3, 0xef, 0x40, 0xec, 0xd2, 0xd6, 0xb3, 0xc9, 0xc4, 0x26, 0xf9, 0xf5, 0x10, + 0xc4, 0xf9, 0x57, 0x40, 0x54, 0x3a, 0xfe, 0x32, 0x10, 0x0e, 0x67, 0x2b, 0xc3, 0xd0, 0x68, 0x14, + 0xc3, 0x94, 0xbc, 0xd2, 0x88, 0x2b, 0x46, 0xb3, 0xc0, 0xc5, 0x34, 0x03, 0x5c, 0xe4, 0x0f, 0x10, + 0xa9, 0x37, 0x99, 0xf7, 0xcf, 0xd2, 0x83, 0xcd, 0xe6, 0x4f, 0x49, 0x14, 0x56, 0x3b, 0x2a, 0xa2, + 0xc3, 0xcc, 0xb6, 0x0f, 0xb4, 0x21, 0x8c, 0x7a, 0x9c, 0x8e, 0x03, 0xf0, 0x87, 0x27, 0x2d, 0xee, + 0xdd, 0x61, 0x91, 0x1f, 0x17, 0xd1, 0x2a, 0x81, 0xe8, 0x45, 0x4e, 0x94, 0x98, 0xb7, 0xc6, 0xad, + 0x6e, 0x46, 0x5b, 0x49, 0xb1, 0x00, 0xbd, 0x01, 0x7c, 0xfa, 0xb3, 0xc6, 0x2b, 0xce, 0xd2, 0x14, + 0xef, 0xb7, 0x33, 0x5a, 0x0e, 0xb4, 0x0b, 0xfd, 0xcd, 0x33, 0xb4, 0x1b, 0x2a, 0x28, 0x7d, 0x84, + 0xa3, 0x91, 0xfe, 0x24, 0x1f, 0x0f, 0x49, 0x67, 0xe9, 0x1a, 0x17, 0x76, 0x94, 0x80, 0xce, 0x79, + 0xf8, 0xa7, 0x29, 0xb2, 0x42, 0xf7, 0x2c, 0x3f, 0x76, 0xab, 0x06, 0xb4, 0x5f, 0xbb, 0x06, 0x9e, + 0x0b, 0x55, 0x88, 0x52, 0xad, 0xcf, 0xac, 0x27, 0xaf, 0x01, 0x09, 0x97, 0x9b, 0x42, 0x2f, 0xd8, + 0x3b, 0x67, 0x75, 0x9d, 0x0c, 0x0f, 0x85, 0x8a, 0xc6, 0x37, 0xd7, 0x1a, 0x33, 0xfc, 0xe0, 0x97, + 0x80, 0xb2, 0x7f, 0x96, 0x30, 0x65, 0x9c, 0x5f, 0xb3, 0x36, 0xd7, 0x3a, 0xba, 0xa2, 0x16, 0x5e, + 0x95, 0xdd, 0x51, 0xe9, 0xfd, 0x49, 0xe6, 0x88, 0x5a, 0xb4, 0xaf, 0x15, 0xd7, 0xca, 0x7a, 0xaf, + 0xd1, 0x62, 0x33, 0x24, 0x78, 0x96, 0x5a, 0x89, 0x66, 0xd2, 0x08, 0x8c, 0x5b, 0x0f, 0x83, 0x6c, + 0xc1, 0xa1, 0xf9, 0x4c, 0xc6, 0x39, 0x59, 0xd6, 0xd8, 0xad, 0x94, 0x5f, 0x96, 0x96, 0x76, 0xb6, + 0x29, 0x2e, 0xba, 0x22, 0x9b, 0x39, 0xe4, 0x74, 0x0b, 0x85, 0xd9, 0x40, 0x22, 0xf9, 0x4d, 0xed, + 0xba, 0x5e, 0x12, 0x42, 0x4c, 0x45, 0x29, 0xb2, 0xa6, 0x0e, 0x2a, 0x2d, 0xd1, 0x5c, 0x73, 0xd2, + 0x13, 0x45, 0x56, 0x7a, 0x5b, 0xd4, 0x66, 0xdf, 0xca, 0xc9, 0x28, 0xab, 0xa9, 0x06, 0x42, 0x38, + 0x87, 0x1c, 0x45, 0x4c, 0x3b, 0xd3, 0x5f, 0xdf, 0x44, 0xc3, 0x80, 0x76, 0xd6, 0x5c, 0xeb, 0x5d, + 0x54, 0x60, 0x35, 0x70, 0x08, 0xc3, 0xf9, 0x8a, 0x60, 0x03, 0xcd, 0xa1, 0x91, 0x91, 0x19, 0x45, + 0x46, 0x4c, 0x5e, 0xa4, 0x34, 0xce, 0xeb, 0x9e, 0x77, 0x5a, 0x3f, 0xea, 0xd1, 0xbe, 0x8d, 0x72, + 0x6a, 0x41, 0x22, 0x2f, 0x24, 0x3b, 0x80, 0xad, 0xaa, 0x5f, 0x2c, 0xbf, 0xb0, 0x6c, 0x9b, 0x0b, + 0x1c, 0x47, 0xb4, 0xf3, 0xc3, 0x42, 0x64, 0x1a, 0x6c, 0x82, 0x76, 0x54, 0xd6, 0x84, 0x84, 0xc8, + 0x84, 0x34, 0x23, 0x3f, 0x96, 0x23, 0x7f, 0xda, 0x0a, 0x6f, 0xef, 0x7a, 0xf2, 0x7e, 0x12, 0x0d, + 0xbc, 0xc9, 0xe2, 0xeb, 0x42, 0x24, 0x83, 0xbc, 0xc7, 0x6b, 0xed, 0x22, 0x0a, 0x34, 0xd3, 0x5b, + 0xc7, 0xe9, 0x21, 0xf8, 0xa1, 0xa5, 0x1c, 0x71, 0x18, 0x75, 0xd4, 0xaf, 0xca, 0xa1, 0x9d, 0x6f, + 0x7e, 0x11, 0x39, 0xea, 0xef, 0xff, 0xf2, 0x3f, 0x45, 0xfa, 0x2e, 0x79, 0xbd, 0xe2, 0x58, 0x14, + 0xc6, 0xca, 0x99, 0x1f, 0x37, 0x22, 0xb6, 0x2b, 0xc0, 0xcc, 0x26, 0xa2, 0x23, 0x04, 0x6d, 0x6d, + 0xd5, 0xec, 0x43, 0x02, 0x7f, 0xc3, 0xb0, 0xea, 0xb8, 0xde, 0x2a, 0x4c, 0x52, 0x2d, 0xa7, 0x0f, + 0xbf, 0x96, 0x33, 0xa5, 0x03, 0x12, 0xce, 0xaf, 0xe0, 0xdb, 0x5f, 0xc3, 0xad, 0x5c, 0x52, 0xe2, + 0xf4, 0xdd, 0xbb, 0xd7, 0xa7, 0x47, 0xef, 0x4f, 0xd0, 0xe5, 0x8d, 0x0d, 0x47, 0xee, 0xd3, 0x6a, + 0x5e, 0xf9, 0xfd, 0xf7, 0xb4, 0x43, 0x38, 0x5d, 0xe7, 0xdb, 0xd3, 0xd3, 0xf7, 0x1a, 0x15, 0x0a, + 0x9b, 0x46, 0x53, 0x3b, 0xa5, 0x1b, 0x4f, 0x96, 0xc4, 0x48, 0xf7, 0x4d, 0xe3, 0x6b, 0xdd, 0x55, + 0x8f, 0xda, 0x8e, 0x9b, 0xc3, 0x82, 0xcf, 0xff, 0x00, 0xd1, 0x6c, 0xaf, 0xe1, 0x5a, 0x43, 0x20, + 0x5f, 0xbc, 0xff, 0x5e, 0x65, 0x2f, 0xc5, 0xe1, 0x46, 0xd5, 0xda, 0x8d, 0xed, 0x7a, 0x53, 0x7d, + 0x4b, 0xb2, 0x00, 0x35, 0x44, 0x12, 0x0b, 0x9c, 0xb7, 0x69, 0xc0, 0x90, 0xb6, 0x71, 0x54, 0xaa, + 0x68, 0xc1, 0xc9, 0x4b, 0x22, 0x36, 0xbb, 0xad, 0x8e, 0xdd, 0x14, 0x01, 0xed, 0x47, 0x89, 0x4f, + 0x6d, 0xbc, 0x62, 0x07, 0x27, 0x35, 0x24, 0x36, 0x1f, 0xc0, 0xed, 0x69, 0x12, 0x9d, 0x9f, 0xb3, + 0xfe, 0x41, 0xb2, 0x4e, 0x3a, 0x24, 0xa5, 0xa4, 0xa9, 0xbe, 0x4f, 0xfc, 0xd1, 0x7c, 0xc2, 0x42, + 0xd5, 0xd0, 0xef, 0xcf, 0xf9, 0xbb, 0x05, 0x98, 0xb8, 0xa5, 0x80, 0xe6, 0x63, 0xe3, 0x26, 0xbb, + 0x40, 0x12, 0x60, 0xed, 0xba, 0x39, 0x26, 0x66, 0x71, 0x05, 0xc5, 0x89, 0xdf, 0x37, 0x55, 0xa3, + 0xa3, 0xa5, 0x25, 0x52, 0x40, 0x53, 0x12, 0xa5, 0x9a, 0xea, 0x1d, 0x42, 0x5e, 0x04, 0xff, 0xb0, + 0xaa, 0x4c, 0x21, 0xbe, 0xce, 0x70, 0x47, 0x15, 0x03, 0x80, 0x81, 0x94, 0xd0, 0x36, 0xa1, 0xbe, + 0xd9, 0xad, 0x80, 0x55, 0xe4, 0x8d, 0xe4, 0x9e, 0xa0, 0xf0, 0xe8, 0x60, 0x77, 0x51, 0xab, 0x25, + 0x55, 0x1b, 0x03, 0x5b, 0xa4, 0x36, 0x34, 0xd5, 0xfb, 0x68, 0x36, 0x47, 0x18, 0xe6, 0x50, 0x0d, + 0x6f, 0x48, 0xb1, 0x40, 0xba, 0x2b, 0x6a, 0xbd, 0x40, 0x4c, 0xec, 0xcd, 0xc9, 0x6d, 0x91, 0x50, + 0xd0, 0x94, 0xf6, 0x9e, 0x07, 0x21, 0xb5, 0xf6, 0x1e, 0xe9, 0x74, 0x09, 0x1e, 0x14, 0x3e, 0xe3, + 0x37, 0x05, 0x22, 0xeb, 0x07, 0xa1, 0x47, 0xf2, 0x50, 0xad, 0x49, 0x3f, 0xa8, 0x8d, 0x57, 0x58, + 0x5f, 0xd4, 0xf6, 0x3c, 0xc1, 0x6c, 0x04, 0x13, 0x04, 0x8b, 0x9b, 0xf0, 0x1f, 0x06, 0x2c, 0x90, + 0x71, 0x04, 0xf5, 0xc6, 0x03, 0xaa, 0xe8, 0xdf, 0x60, 0x3a, 0x9f, 0xea, 0x11, 0xf3, 0xa1, 0xb6, + 0x9a, 0x04, 0xd3, 0x80, 0x90, 0xd3, 0xd6, 0x70, 0xd0, 0x64, 0x16, 0x41, 0x74, 0xec, 0x0f, 0xe7, + 0xa4, 0xa6, 0xaa, 0x30, 0x0a, 0xf8, 0x62, 0x26, 0x35, 0xf4, 0xe2, 0x0b, 0x95, 0x0c, 0xfc, 0x90, + 0x3b, 0x2e, 0xfd, 0x16, 0x4f, 0x01, 0x02, 0xfd, 0x7d, 0x62, 0x35, 0x91, 0xb9, 0x15, 0xc0, 0x2e, + 0x8d, 0xaa, 0x84, 0x82, 0x38, 0xd2, 0x16, 0x0d, 0x69, 0x0e, 0x28, 0x43, 0x90, 0xe3, 0x40, 0xd5, + 0xe0, 0x5d, 0xc9, 0xbe, 0x00, 0x84, 0x55, 0x1c, 0x29, 0x8a, 0xef, 0x8e, 0x82, 0x30, 0x24, 0x72, + 0xb5, 0xb8, 0x05, 0xb2, 0x0e, 0x4b, 0x34, 0x18, 0x44, 0x43, 0xbd, 0xda, 0x76, 0xf0, 0x9f, 0xf2, + 0x52, 0xb5, 0xdf, 0x46, 0x55, 0xd0, 0x0e, 0x3a, 0x2c, 0x25, 0x71, 0x6f, 0x5a, 0xe2, 0xd2, 0xa4, + 0xd1, 0x28, 0x00, 0x4e, 0xd4, 0x62, 0x38, 0xd8, 0xc0, 0xb1, 0x86, 0x54, 0x70, 0x2c, 0x1f, 0x3e, + 0x43, 0x9a, 0xdc, 0x34, 0xd5, 0x73, 0x6d, 0x73, 0xe2, 0xbb, 0x17, 0xf5, 0x49, 0x78, 0xa1, 0x46, + 0x36, 0x55, 0xde, 0x55, 0xff, 0x8d, 0x90, 0xc5, 0x5f, 0xe0, 0x3c, 0xa0, 0xb4, 0xf3, 0x80, 0x26, + 0x07, 0xa6, 0x04, 0x6b, 0x74, 0xae, 0x1a, 0xa4, 0x67, 0x22, 0xef, 0xd3, 0x6b, 0x4e, 0xdf, 0xb8, + 0xe8, 0x65, 0x60, 0xc3, 0x7e, 0x81, 0x55, 0xfe, 0xa2, 0x5c, 0x02, 0x38, 0xfc, 0x27, 0x7f, 0x72, + 0x49, 0x7f, 0xd8, 0x70, 0x4b, 0x05, 0xd9, 0x53, 0xf8, 0x20, 0x83, 0xde, 0x54, 0xb0, 0x91, 0x35, + 0x3a, 0xb0, 0x93, 0x59, 0xcb, 0x06, 0xde, 0x06, 0x02, 0x1e, 0x96, 0x87, 0xe6, 0x34, 0x88, 0xe3, + 0x28, 0xa6, 0x16, 0xbe, 0x9e, 0x04, 0x33, 0xb1, 0x46, 0xa8, 0x31, 0x29, 0x0c, 0xbf, 0x20, 0x12, + 0x89, 0x11, 0x71, 0x5c, 0xe2, 0x23, 0x56, 0xe5, 0x11, 0xd5, 0x29, 0x56, 0x35, 0xb9, 0xdc, 0xd6, + 0x54, 0x94, 0x68, 0x54, 0xaa, 0x7a, 0xcc, 0x3f, 0x74, 0xe5, 0x5a, 0x5b, 0x41, 0x3d, 0x7e, 0xd4, + 0x26, 0x92, 0x3b, 0x27, 0x59, 0x0d, 0x73, 0x5f, 0x09, 0x44, 0xbb, 0xb0, 0xc6, 0x03, 0x8d, 0xf7, + 0x63, 0xc0, 0xd0, 0x6a, 0x45, 0x57, 0x0d, 0xfa, 0xf1, 0x01, 0xf3, 0x4e, 0x2f, 0x4c, 0x8d, 0xe9, + 0xd0, 0x55, 0x97, 0xf4, 0x96, 0x6f, 0x52, 0x21, 0xb6, 0xe3, 0x2a, 0x0f, 0x8f, 0xde, 0xd0, 0x9b, + 0xf1, 0x6c, 0xe6, 0xef, 0x7f, 0xc6, 0xfb, 0x9f, 0xb5, 0x01, 0xe8, 0x87, 0xe7, 0xc7, 0x76, 0x73, + 0x44, 0x51, 0xd4, 0xd6, 0x29, 0xa9, 0x41, 0xbe, 0x36, 0xa0, 0x30, 0xcb, 0xd7, 0x76, 0x39, 0xe2, + 0xbb, 0x13, 0x52, 0x82, 0x68, 0x36, 0x59, 0x25, 0x14, 0xff, 0x71, 0xa1, 0xfe, 0xa6, 0x42, 0xb4, + 0x50, 0x00, 0x2e, 0x47, 0xad, 0xd9, 0x20, 0xa1, 0x78, 0xa1, 0xff, 0x19, 0x1f, 0xc1, 0x39, 0xc4, + 0x5f, 0xae, 0xbf, 0xd5, 0xe4, 0xdc, 0x79, 0xbc, 0xdd, 0xbe, 0xee, 0xb4, 0x1f, 0xb5, 0x09, 0x11, + 0xcf, 0x58, 0x81, 0x48, 0x54, 0x42, 0xb3, 0x93, 0x0e, 0xe6, 0x69, 0xd2, 0x55, 0x5f, 0x6d, 0xb7, + 0x67, 0xae, 0xc2, 0x77, 0xfa, 0xb3, 0xfb, 0xe6, 0xfd, 0x6a, 0x6c, 0x69, 0x4c, 0xe4, 0x43, 0x58, + 0x6e, 0x55, 0xb5, 0xf8, 0x7c, 0x9f, 0x13, 0xff, 0x29, 0x8d, 0x12, 0x57, 0x58, 0x7c, 0x9f, 0xb4, + 0x7a, 0x76, 0x34, 0x5f, 0x3e, 0xb2, 0xf3, 0x68, 0x76, 0x22, 0x83, 0x5b, 0x62, 0xc6, 0xd4, 0x8b, + 0x7e, 0x32, 0x61, 0x53, 0x99, 0x47, 0x23, 0xbe, 0x84, 0x72, 0x27, 0x4b, 0x95, 0xd6, 0xb9, 0xb1, + 0x0b, 0xd6, 0x97, 0xb7, 0xf1, 0xf3, 0xec, 0xa5, 0x3f, 0x49, 0x3d, 0x6a, 0xe3, 0xa8, 0xf5, 0x5e, + 0xd7, 0xfc, 0x0e, 0xfc, 0x8a, 0x5e, 0xaa, 0x5a, 0xa3, 0xb3, 0x8d, 0xa9, 0xd8, 0xea, 0x60, 0xdf, + 0x7a, 0xeb, 0x9f, 0x73, 0x42, 0x84, 0x7c, 0x44, 0x47, 0x0d, 0xa9, 0xa0, 0x47, 0xb6, 0x62, 0x8e, + 0xc0, 0xdf, 0x4e, 0xc7, 0x10, 0x2b, 0xa3, 0xc9, 0x10, 0xcc, 0x1f, 0x2f, 0x1a, 0x7a, 0xe7, 0x80, + 0x09, 0x33, 0x25, 0x0d, 0xf9, 0x9c, 0xad, 0x70, 0xba, 0x10, 0x66, 0x91, 0x79, 0xb4, 0xa2, 0xd9, + 0x6b, 0xcb, 0x48, 0x69, 0xbb, 0xa2, 0xb9, 0xda, 0xc3, 0xcf, 0x4e, 0x73, 0xef, 0x1a, 0x21, 0xda, + 0x17, 0xfe, 0xea, 0x19, 0xe3, 0x96, 0xe1, 0xff, 0x8a, 0xad, 0x0e, 0x3c, 0x20, 0x24, 0xdc, 0xcd, + 0x79, 0x18, 0xfc, 0xa9, 0xc1, 0x30, 0x0c, 0x29, 0x1a, 0xcf, 0x55, 0x25, 0x49, 0x00, 0x94, 0x76, + 0xc9, 0x03, 0xa7, 0xa3, 0x4e, 0x5a, 0x1c, 0x60, 0x7b, 0xcd, 0xaa, 0xf2, 0x13, 0x92, 0x92, 0x10, + 0xfa, 0x84, 0x6d, 0x1a, 0xdc, 0xa1, 0x91, 0xbf, 0x42, 0x9e, 0x33, 0xf8, 0xa2, 0xd7, 0x78, 0xd2, + 0x1a, 0x5a, 0x06, 0x57, 0x5b, 0xea, 0xe4, 0x87, 0x17, 0x8d, 0x53, 0x02, 0x37, 0x7a, 0x1f, 0xb3, + 0x13, 0x33, 0xcd, 0x3a, 0xa1, 0xfd, 0xdd, 0xc9, 0xcb, 0x46, 0xe2, 0x8d, 0x7c, 0xde, 0xad, 0xe1, + 0x0f, 0x3e, 0x98, 0xfb, 0x2d, 0x8d, 0xf1, 0x56, 0x32, 0x8b, 0x09, 0x4a, 0x2b, 0xe6, 0x94, 0x92, + 0x2d, 0x92, 0xc1, 0xe6, 0x9c, 0x85, 0x04, 0x87, 0xf6, 0xb4, 0x8e, 0xa5, 0xf2, 0x3c, 0x44, 0x75, + 0x55, 0xd3, 0xae, 0xbc, 0x38, 0x98, 0x03, 0x67, 0x20, 0x2a, 0x9a, 0x22, 0xfa, 0x9d, 0xd3, 0x42, + 0x52, 0x39, 0x98, 0x48, 0xbd, 0x7a, 0x97, 0x90, 0x4e, 0x9c, 0x87, 0x20, 0xd2, 0xcc, 0xd0, 0x8e, + 0x7c, 0xc9, 0x5b, 0x58, 0xa1, 0x67, 0x4d, 0x25, 0x9d, 0x38, 0x68, 0x37, 0xb7, 0xf7, 0x12, 0x20, + 0x06, 0xc9, 0xd7, 0x68, 0x85, 0x4a, 0x67, 0x0e, 0x78, 0x58, 0x5b, 0xed, 0xa6, 0x7c, 0xc3, 0xd6, + 0xe3, 0xab, 0xe3, 0x57, 0xcf, 0x5e, 0xbe, 0x79, 0xc5, 0x72, 0x48, 0xe6, 0x8d, 0xce, 0x42, 0x72, + 0x01, 0x8f, 0xfd, 0x28, 0x4a, 0x65, 0x93, 0xd5, 0x78, 0xfc, 0x25, 0x8a, 0xa6, 0xff, 0x4c, 0x28, + 0x7c, 0x19, 0x9c, 0x07, 0x38, 0x80, 0xc5, 0xb3, 0xa2, 0x4d, 0x6f, 0xa6, 0x93, 0xd5, 0xab, 0x7f, + 0x76, 0x99, 0x30, 0x10, 0xd6, 0xc6, 0x36, 0x5b, 0xc8, 0x0d, 0x6c, 0x6b, 0x59, 0x4e, 0x8b, 0x80, + 0xf1, 0xd7, 0x55, 0x30, 0xff, 0x2a, 0x30, 0xe1, 0x16, 0x60, 0x40, 0x8a, 0x05, 0x6b, 0x39, 0x4c, + 0x2d, 0xa1, 0x82, 0x8f, 0x6b, 0x59, 0x95, 0xc3, 0x5e, 0x20, 0xec, 0xb2, 0xdb, 0x35, 0xa0, 0xdb, + 0x56, 0x61, 0x8e, 0x56, 0x08, 0x70, 0x96, 0x8c, 0x60, 0xdd, 0x03, 0xc1, 0x87, 0xb0, 0x75, 0x91, + 0x72, 0x0f, 0x34, 0x3b, 0xd7, 0xde, 0x71, 0xbf, 0x78, 0x12, 0x2a, 0x03, 0x40, 0x5b, 0x92, 0x5e, + 0x44, 0xd5, 0xa8, 0x53, 0x63, 0x23, 0x7a, 0x13, 0x27, 0xd3, 0x4e, 0x43, 0x97, 0x81, 0xa7, 0x7e, + 0x78, 0xff, 0x8a, 0x8b, 0xba, 0x5a, 0x54, 0xe6, 0x97, 0x27, 0x2f, 0x5e, 0xf3, 0xcb, 0x9e, 0x1e, + 0x27, 0xf6, 0x4c, 0x2e, 0x93, 0x44, 0x73, 0xf6, 0x29, 0x85, 0x60, 0x37, 0xc8, 0xf9, 0xef, 0x93, + 0x83, 0x8c, 0x75, 0xe2, 0xf1, 0xc2, 0xf7, 0x67, 0x8a, 0xd8, 0x77, 0x2f, 0xeb, 0x13, 0x4d, 0xd9, + 0x60, 0xdc, 0x66, 0x2f, 0xa5, 0x1e, 0x63, 0xf1, 0x9f, 0x5b, 0x8c, 0x5b, 0x85, 0xb0, 0x43, 0x8c, + 0x36, 0x2b, 0x08, 0xf3, 0x65, 0x38, 0x8c, 0xae, 0x7a, 0xe2, 0x8b, 0x3b, 0xf3, 0x88, 0xa6, 0x4e, + 0x30, 0x4c, 0x49, 0xbd, 0x51, 0x97, 0x41, 0x43, 0x93, 0x9a, 0x2c, 0x1b, 0xf9, 0x68, 0x12, 0x79, + 0xbc, 0x0e, 0xe5, 0x2b, 0xb8, 0xbc, 0xea, 0x4f, 0x60, 0xcb, 0x97, 0xc8, 0xc9, 0x12, 0x3a, 0x7a, + 0xda, 0xe1, 0x17, 0x60, 0x6e, 0x12, 0xc6, 0x2f, 0x56, 0xa0, 0xb8, 0x1b, 0xbe, 0xa0, 0x61, 0xbf, + 0x1f, 0x40, 0xf9, 0xa1, 0xbd, 0x80, 0x3b, 0x3a, 0x0e, 0x46, 0x69, 0x4b, 0x03, 0xea, 0xcf, 0x87, + 0xc4, 0xd9, 0x97, 0x74, 0xb5, 0x67, 0x30, 0x3a, 0x88, 0xa6, 0x24, 0x8d, 0x89, 0x0f, 0x40, 0x12, + 0x8d, 0x52, 0xc8, 0xc9, 0x5b, 0xdf, 0xfe, 0xa5, 0xd1, 0xa7, 0x65, 0xc9, 0x64, 0x23, 0x02, 0x04, + 0x04, 0x54, 0x8e, 0x51, 0x40, 0x33, 0xda, 0x07, 0x99, 0x86, 0x0b, 0x3c, 0x35, 0x3a, 0xb4, 0x7c, + 0xae, 0x5b, 0xc4, 0xc8, 0xda, 0xf8, 0xf7, 0x2b, 0xfa, 0xbd, 0x7d, 0xdd, 0xda, 0xb9, 0x6e, 0xed, + 0x5e, 0x13, 0x12, 0x66, 0xe2, 0x3f, 0x6a, 0x91, 0x68, 0x79, 0x80, 0x55, 0x18, 0x67, 0x42, 0x43, + 0xc7, 0x7b, 0x08, 0xfe, 0x9e, 0xcf, 0x58, 0xf0, 0x62, 0x32, 0x1c, 0xcb, 0x66, 0xc4, 0x90, 0xfc, + 0x29, 0x6c, 0xce, 0x1e, 0xad, 0x7f, 0xc8, 0xe6, 0xb1, 0x32, 0x7b, 0x44, 0x25, 0x47, 0x63, 0xb5, + 0x81, 0x44, 0xd2, 0xe8, 0xea, 0x5d, 0x32, 0xb4, 0x95, 0x0e, 0x7a, 0xcd, 0x6c, 0x43, 0x87, 0x3b, + 0x9b, 0xa3, 0x11, 0x46, 0x5b, 0x22, 0xce, 0x01, 0x35, 0x4d, 0x93, 0x82, 0xac, 0x00, 0xfa, 0x9d, + 0x27, 0xe1, 0x28, 0xa0, 0x50, 0x88, 0x8a, 0x3d, 0xed, 0x70, 0x61, 0x4f, 0xb6, 0xc2, 0x7c, 0x6b, + 0xfa, 0xa1, 0x7e, 0xd2, 0xd8, 0x48, 0x77, 0x22, 0xae, 0x36, 0x06, 0xf3, 0x40, 0x2a, 0x14, 0xc1, + 0xe6, 0x34, 0xba, 0xe4, 0x50, 0x69, 0x0c, 0x59, 0xc8, 0x8b, 0x26, 0x02, 0x16, 0x64, 0x99, 0x72, + 0x18, 0x0f, 0xb5, 0x7f, 0x86, 0xe0, 0x7d, 0xa8, 0x70, 0x63, 0xf8, 0xb2, 0x61, 0x92, 0xb6, 0x74, + 0x1e, 0x41, 0x39, 0xd2, 0x51, 0x23, 0xf9, 0x48, 0x79, 0x89, 0x1b, 0xaf, 0x27, 0x19, 0x18, 0x2b, + 0x51, 0x7f, 0x81, 0xc8, 0x68, 0x82, 0x9c, 0xdd, 0xcc, 0xc1, 0x3c, 0x26, 0x76, 0x8b, 0x51, 0x06, + 0xc3, 0x09, 0x8b, 0xb8, 0x15, 0x4c, 0x23, 0x6b, 0x4b, 0x54, 0x4e, 0xf0, 0x22, 0xde, 0x64, 0x64, + 0xf4, 0xdf, 0x1f, 0x1b, 0xbd, 0x77, 0x3e, 0xc4, 0xc5, 0x21, 0xb4, 0x0a, 0x9b, 0x9d, 0xfd, 0x47, + 0xcd, 0x4e, 0xb3, 0xd3, 0xdd, 0xdb, 0x67, 0xc9, 0x62, 0x05, 0x44, 0xee, 0x9f, 0x16, 0xe9, 0x4e, + 0xf9, 0x52, 0x27, 0x58, 0x54, 0x49, 0x30, 0x4f, 0xa3, 0x01, 0x04, 0xbb, 0x38, 0x9d, 0xa9, 0x1a, + 0xc4, 0xba, 0x21, 0x52, 0xb8, 0xad, 0x43, 0x06, 0x09, 0x5f, 0xef, 0xbd, 0x1b, 0xb8, 0x70, 0x68, + 0x41, 0x84, 0x74, 0x11, 0x75, 0x7c, 0xfa, 0xbe, 0x85, 0x19, 0x45, 0xa8, 0xe9, 0x4c, 0xbe, 0x6a, + 0x4f, 0xa3, 0xda, 0xde, 0x57, 0xfb, 0xcd, 0xe6, 0xae, 0x88, 0x3f, 0x1d, 0xfa, 0x0b, 0x21, 0x84, + 0x37, 0x9f, 0x11, 0x47, 0x02, 0x92, 0x2a, 0x1e, 0xfa, 0xe9, 0x55, 0x14, 0x5f, 0x10, 0xfd, 0xc6, + 0x1e, 0x34, 0x20, 0x7c, 0xf8, 0x69, 0x3e, 0xed, 0x47, 0x5a, 0x94, 0x20, 0xee, 0x78, 0x61, 0x1c, + 0x43, 0x01, 0x88, 0x0b, 0xec, 0x3c, 0x7e, 0xbc, 0xd3, 0x78, 0x73, 0xfa, 0x3d, 0xf5, 0xd6, 0x9b, + 0xa4, 0xfe, 0xc5, 0x4a, 0x14, 0x90, 0x64, 0x14, 0x72, 0xd4, 0xdf, 0xf7, 0x43, 0x08, 0xd6, 0xa4, + 0x01, 0xab, 0xec, 0x95, 0xfa, 0xfe, 0x25, 0x29, 0xfa, 0xa4, 0x91, 0xfb, 0x72, 0xd0, 0x80, 0x34, + 0xfd, 0x31, 0xb1, 0xb6, 0x18, 0x24, 0x06, 0x42, 0x86, 0x95, 0xc7, 0xd6, 0x8f, 0xc3, 0x75, 0x18, + 0xe2, 0x54, 0xff, 0xdf, 0x87, 0xc1, 0xb5, 0x8e, 0x1b, 0x39, 0x81, 0xc4, 0xcf, 0x82, 0x06, 0x21, + 0x28, 0x0d, 0x74, 0x64, 0x27, 0xef, 0x06, 0x68, 0x70, 0x4e, 0x25, 0x69, 0x4e, 0x35, 0x39, 0x69, + 0x22, 0xd2, 0x24, 0x47, 0x12, 0xb5, 0x6c, 0x04, 0x10, 0xbc, 0x11, 0x2f, 0x49, 0x72, 0x95, 0x3f, + 0x27, 0x49, 0x11, 0x26, 0x84, 0x02, 0x07, 0x21, 0x30, 0x69, 0x30, 0x91, 0x15, 0x6f, 0xca, 0xc2, + 0x48, 0x3d, 0xf5, 0x45, 0xe5, 0xc6, 0x39, 0x67, 0x34, 0x62, 0x65, 0x6d, 0x66, 0x0e, 0x24, 0x63, + 0x7f, 0xea, 0x41, 0x8f, 0x8f, 0xf1, 0x25, 0x53, 0xfd, 0x8a, 0xb6, 0x80, 0xb5, 0x83, 0x9d, 0x0f, + 0x83, 0x48, 0xdb, 0x4c, 0x9e, 0xe1, 0x37, 0xe3, 0x53, 0x2c, 0x26, 0x87, 0xd8, 0x33, 0x69, 0x95, + 0x05, 0x03, 0x56, 0xd1, 0x65, 0x71, 0xe3, 0x5d, 0x32, 0x86, 0x09, 0x41, 0x56, 0x91, 0xa0, 0xbe, + 0xa7, 0x9e, 0xb4, 0xf5, 0x14, 0x37, 0x3a, 0x75, 0xec, 0xd8, 0x6c, 0xf4, 0x6a, 0x70, 0x02, 0x8d, + 0xda, 0x80, 0x14, 0x0a, 0x62, 0x7e, 0x5b, 0xf2, 0xd2, 0x25, 0x8a, 0x81, 0x80, 0x22, 0x84, 0xed, + 0x83, 0x64, 0x73, 0x35, 0x6c, 0xbf, 0xdd, 0x59, 0xd7, 0xe5, 0x84, 0xda, 0x1d, 0x78, 0xb1, 0xee, + 0xb4, 0xe9, 0xae, 0x38, 0x22, 0xcb, 0xa7, 0x2c, 0x1e, 0xb7, 0x08, 0x79, 0x99, 0x84, 0x07, 0x23, + 0x2a, 0x28, 0xe5, 0xc6, 0xe2, 0x14, 0xcf, 0xc2, 0x30, 0x9a, 0x43, 0xb2, 0x63, 0xed, 0xda, 0x4c, + 0x92, 0xb8, 0x43, 0x4d, 0x5f, 0xbe, 0x3d, 0x61, 0xdb, 0x52, 0x40, 0xdf, 0x6b, 0x67, 0x3a, 0xb3, + 0x4e, 0x03, 0x9e, 0xac, 0xcd, 0xb3, 0x74, 0x30, 0xab, 0x83, 0x6b, 0x49, 0x5a, 0xa5, 0xd6, 0xb3, + 0x90, 0xa6, 0x2c, 0xc0, 0x71, 0x7d, 0x00, 0xd7, 0x3c, 0x65, 0xda, 0x02, 0x57, 0xb3, 0x32, 0x7a, + 0x30, 0x80, 0xf1, 0xbc, 0xbf, 0x9e, 0x50, 0xad, 0xde, 0xea, 0x2e, 0x9c, 0xde, 0xcc, 0xb0, 0x8e, + 0x0b, 0xbd, 0xe2, 0x73, 0x30, 0x6f, 0xc8, 0x7a, 0x67, 0xc2, 0x09, 0x1b, 0x98, 0x40, 0x5e, 0x3f, + 0x7b, 0x6b, 0xb5, 0xb0, 0xd8, 0x73, 0xde, 0x57, 0x26, 0x3e, 0xb2, 0x2d, 0x78, 0x49, 0x83, 0x06, + 0x3e, 0x0f, 0x27, 0x38, 0x9b, 0xbf, 0x89, 0xe6, 0xea, 0x22, 0x24, 0x76, 0x7c, 0x35, 0xbe, 0x59, + 0xd7, 0x2b, 0x1c, 0x10, 0x9b, 0xee, 0xb0, 0xb1, 0x08, 0x58, 0x94, 0x53, 0xa4, 0x9a, 0x10, 0x29, + 0x61, 0x62, 0x48, 0x64, 0xc1, 0x27, 0xc9, 0xd8, 0x85, 0x42, 0x08, 0x23, 0x1a, 0x41, 0x96, 0xc1, + 0x86, 0x10, 0xce, 0x01, 0x82, 0xe6, 0x60, 0x5f, 0x8c, 0x65, 0xa4, 0x86, 0x27, 0x69, 0xc8, 0x74, + 0xbe, 0xba, 0x1f, 0x7d, 0xa2, 0xd1, 0x67, 0x93, 0xc0, 0x83, 0x76, 0xfa, 0x0c, 0x87, 0x85, 0x24, + 0x08, 0x05, 0x02, 0x09, 0x9f, 0x0c, 0xd6, 0x9b, 0x6c, 0x17, 0xcd, 0xa0, 0xaa, 0x9a, 0x38, 0xf7, + 0x47, 0x21, 0x69, 0xf1, 0x83, 0xd4, 0xb2, 0x65, 0xd5, 0xc5, 0x55, 0x36, 0xf4, 0xf9, 0x7c, 0x5c, + 0x7b, 0x2d, 0xdc, 0x87, 0xb1, 0xf0, 0x12, 0x6b, 0x4e, 0xe7, 0xac, 0x64, 0xbe, 0x99, 0xc3, 0x0b, + 0x8d, 0x17, 0x9a, 0x5e, 0x15, 0x45, 0xc6, 0x47, 0x3a, 0x59, 0xd4, 0xa0, 0xed, 0x2f, 0x18, 0xe9, + 0x52, 0xb9, 0x5b, 0x13, 0x03, 0x23, 0xf1, 0xbd, 0x49, 0x04, 0xf5, 0xaa, 0xbc, 0xa5, 0x1d, 0xbf, + 0xa3, 0x2d, 0xe6, 0xd8, 0x3f, 0xe7, 0xcd, 0x76, 0xa4, 0x8e, 0x58, 0x1c, 0x4c, 0xd2, 0xba, 0xfa, + 0xdb, 0x7c, 0xbb, 0xdd, 0xd9, 0x85, 0x46, 0x19, 0x61, 0x19, 0x6b, 0x4d, 0x15, 0xd2, 0x02, 0x90, + 0x2e, 0xe2, 0x31, 0x55, 0xd0, 0xac, 0x63, 0x81, 0x07, 0xeb, 0xf6, 0xbe, 0x03, 0xdf, 0x45, 0x1b, + 0xa4, 0x48, 0x7a, 0x43, 0xa4, 0xbc, 0x62, 0x6f, 0xc0, 0x5a, 0x63, 0x87, 0x25, 0xc9, 0xad, 0x9d, + 0x76, 0x51, 0x9b, 0xd4, 0xb2, 0x89, 0x31, 0x19, 0xd0, 0xae, 0x2d, 0x4d, 0x89, 0xd2, 0x67, 0xb6, + 0xd8, 0xe5, 0xed, 0x9d, 0xa4, 0x3e, 0x9b, 0x15, 0xde, 0xf2, 0x2d, 0x61, 0xe8, 0x60, 0x6e, 0x7d, + 0xe1, 0xb1, 0x42, 0xd7, 0x66, 0xdd, 0x7c, 0x97, 0x1a, 0x7e, 0x83, 0x31, 0x25, 0xa8, 0x02, 0xe6, + 0x34, 0x25, 0x95, 0x03, 0x8d, 0x9f, 0x23, 0x53, 0x18, 0xee, 0x69, 0x5e, 0xda, 0xca, 0x0b, 0xee, + 0x13, 0x58, 0xbb, 0xe0, 0x21, 0x16, 0xfc, 0x8d, 0x62, 0x39, 0x3c, 0x52, 0xb5, 0x76, 0xb3, 0xd3, + 0x68, 0x37, 0x1f, 0xc3, 0xd8, 0xa6, 0x05, 0x2b, 0x52, 0x22, 0xa0, 0x8b, 0xd0, 0x2f, 0x8d, 0x3b, + 0xce, 0xfc, 0xb8, 0xa4, 0x09, 0xb6, 0x08, 0x1a, 0xf3, 0xf1, 0xce, 0x4b, 0x6d, 0x21, 0x64, 0x4b, + 0x1b, 0xc3, 0xcf, 0x6c, 0xc8, 0x5f, 0x2d, 0xd8, 0x90, 0xdf, 0x1e, 0x67, 0xfa, 0x71, 0x35, 0xa1, + 0xb3, 0x19, 0xcc, 0x7f, 0x15, 0x9e, 0x93, 0xee, 0x01, 0x0a, 0x7f, 0x45, 0x4c, 0x0a, 0xbf, 0xbb, + 0x2a, 0x19, 0x92, 0x26, 0xa1, 0xad, 0x93, 0x75, 0x6a, 0x83, 0xa6, 0x1a, 0xf6, 0xca, 0x51, 0x10, + 0x4f, 0xd9, 0xf4, 0x4b, 0xe2, 0x8c, 0x7a, 0xf6, 0xaa, 0xa9, 0xa8, 0xdf, 0xa4, 0x01, 0x89, 0x74, + 0x83, 0x8c, 0xb4, 0x9c, 0x4c, 0x14, 0x6f, 0x77, 0x3c, 0xe6, 0x03, 0x56, 0xc8, 0x42, 0x2f, 0xb7, + 0xd1, 0x9b, 0x6a, 0x01, 0x7a, 0x93, 0xb2, 0x66, 0x0d, 0xd9, 0x38, 0x38, 0x0f, 0x23, 0xfc, 0xae, + 0x01, 0xc8, 0x50, 0x85, 0x42, 0x08, 0x3b, 0xcf, 0xd8, 0x6b, 0x72, 0x72, 0x05, 0xf1, 0x0d, 0x81, + 0xbe, 0xf5, 0x55, 0x83, 0xf9, 0x9a, 0xa7, 0x9c, 0x46, 0x32, 0x8d, 0x42, 0x38, 0x4f, 0xb0, 0x8b, + 0xa5, 0x36, 0xc5, 0x7c, 0xfb, 0x8b, 0x89, 0xa1, 0xe8, 0x9a, 0x1e, 0x50, 0x41, 0x5a, 0xb9, 0x03, + 0x29, 0x22, 0xd6, 0x3e, 0x8d, 0x8f, 0x03, 0x29, 0xd1, 0xd4, 0x5d, 0xee, 0xd2, 0xb6, 0xc9, 0xce, + 0xbd, 0xcc, 0x45, 0xe6, 0x33, 0xf0, 0xc8, 0x24, 0x8a, 0x6f, 0xc4, 0xaa, 0x9b, 0xb0, 0x81, 0x82, + 0xb6, 0xd7, 0x9a, 0x17, 0xde, 0x64, 0x20, 0xec, 0x4d, 0xa9, 0xb3, 0xb7, 0xbc, 0xd7, 0xd0, 0xa1, + 0x9e, 0x25, 0x33, 0x12, 0x45, 0xa8, 0xeb, 0x70, 0xb3, 0xa2, 0x39, 0x13, 0xca, 0x68, 0x64, 0x2a, + 0xa2, 0x36, 0x7b, 0x69, 0x07, 0x27, 0xad, 0xc5, 0x78, 0x5c, 0x49, 0xdb, 0x43, 0x6a, 0x6c, 0x3f, + 0x88, 0xd1, 0xc7, 0x73, 0x3f, 0xe2, 0x3c, 0x6f, 0xf5, 0x9e, 0xa4, 0x8d, 0x02, 0x45, 0xd3, 0x46, + 0x99, 0x0e, 0xc6, 0x2d, 0x56, 0xa6, 0x32, 0x5d, 0x5b, 0x43, 0x85, 0x8a, 0x6f, 0x06, 0xda, 0x3a, + 0xda, 0x7f, 0xa1, 0xfc, 0x6b, 0x58, 0xc4, 0x90, 0x14, 0x2f, 0x8b, 0xdf, 0x69, 0x78, 0xd7, 0x90, + 0xda, 0x48, 0xf6, 0xf0, 0x7f, 0x81, 0xb3, 0x0d, 0xb4, 0xd5, 0x6b, 0x9e, 0x18, 0x0c, 0x9c, 0x64, + 0x19, 0x44, 0xb6, 0x18, 0xa9, 0x42, 0xe4, 0x98, 0xba, 0x62, 0x33, 0xbf, 0xe0, 0x0c, 0x60, 0x49, + 0xd7, 0x84, 0x5e, 0x09, 0x9f, 0x2a, 0xf8, 0x4c, 0xf9, 0x59, 0x47, 0x31, 0xc3, 0xd6, 0x88, 0xa1, + 0x6a, 0xd2, 0x3a, 0x22, 0x51, 0x74, 0xc2, 0xfc, 0x71, 0x19, 0xe2, 0xb4, 0x45, 0xfc, 0x78, 0x3e, + 0xf1, 0x3b, 0x8f, 0xda, 0x84, 0x3c, 0xfa, 0xf7, 0x5f, 0xff, 0x97, 0x09, 0xa9, 0x23, 0xaa, 0x9c, + 0x10, 0x29, 0x23, 0xab, 0x5f, 0x6e, 0x23, 0x8f, 0xe8, 0x37, 0xad, 0x4c, 0xda, 0x3a, 0x3a, 0xad, + 0xda, 0xf6, 0xff, 0xf7, 0x7f, 0xb1, 0x2d, 0x1b, 0x94, 0xea, 0x15, 0x42, 0xf4, 0x0c, 0x08, 0xea, + 0x17, 0xc4, 0x2c, 0x48, 0x61, 0x6c, 0xc3, 0x27, 0x79, 0x9c, 0xd0, 0x26, 0xdc, 0x0b, 0x2b, 0x16, + 0xe6, 0x70, 0xa8, 0xbf, 0x5a, 0x5f, 0xcc, 0x2a, 0x89, 0xf1, 0x99, 0x46, 0xd9, 0x69, 0x75, 0xb6, + 0xdb, 0x8a, 0xb8, 0x0c, 0x42, 0x55, 0xd4, 0xbf, 0xfe, 0x3f, 0x62, 0x39, 0x07, 0x6d, 0xcf, 0x63, + 0x78, 0xe4, 0x11, 0x99, 0x4c, 0x3d, 0x22, 0x56, 0x39, 0x75, 0x98, 0xcc, 0xe3, 0xea, 0xd1, 0x0a, + 0xff, 0x5f, 0x50, 0x42, 0x0a, 0x9b, 0x00, 0xaf, 0x21, 0x4b, 0x13, 0x59, 0x0e, 0x27, 0x61, 0x5f, + 0xbf, 0x63, 0x31, 0x59, 0x8a, 0xc4, 0x26, 0xaf, 0xac, 0xa5, 0x42, 0x3d, 0x86, 0xe7, 0xaa, 0xea, + 0xec, 0xf3, 0x9f, 0xdd, 0x47, 0x22, 0xbe, 0x67, 0x04, 0xcd, 0x2f, 0x56, 0x35, 0xa2, 0x9d, 0x0d, + 0x93, 0xac, 0x09, 0xf3, 0x82, 0x38, 0xee, 0x01, 0x12, 0x0f, 0xbb, 0x6a, 0xfb, 0x20, 0xc1, 0x16, + 0x13, 0x15, 0x16, 0xca, 0x4a, 0x98, 0x44, 0xf5, 0x83, 0x1c, 0x20, 0x9e, 0x68, 0x82, 0x07, 0x53, + 0x9a, 0x9d, 0xaf, 0x3a, 0x1d, 0x4f, 0xfe, 0xcc, 0x5d, 0xd8, 0xba, 0xa3, 0xd9, 0xbc, 0xb0, 0xb3, + 0xf2, 0xe3, 0x72, 0xc8, 0x97, 0xb8, 0xaa, 0x29, 0x47, 0x87, 0x41, 0xa9, 0xbc, 0x06, 0x7b, 0xed, + 0x14, 0x87, 0xff, 0x68, 0xc9, 0xd8, 0xad, 0x0c, 0x03, 0xf9, 0x34, 0x3d, 0x7f, 0x73, 0xb4, 0xfd, + 0x55, 0x5b, 0x1d, 0xbd, 0xf9, 0x1e, 0xd6, 0x3d, 0xc8, 0x53, 0x34, 0xf5, 0x53, 0xdf, 0x03, 0xa9, + 0xf1, 0x1e, 0x48, 0xf2, 0x3f, 0x8e, 0xb2, 0x5e, 0x9a, 0xdc, 0x58, 0x79, 0x72, 0xb9, 0x9e, 0x9e, + 0x19, 0x91, 0xfa, 0x3c, 0x78, 0x8a, 0x1b, 0x81, 0xca, 0xcb, 0xa5, 0xfc, 0x00, 0xa7, 0x28, 0x60, + 0x9d, 0x41, 0xb8, 0xbc, 0x5b, 0xc1, 0xf6, 0xe0, 0xa5, 0x0f, 0xc9, 0x0e, 0x56, 0xdd, 0xed, 0x17, + 0xaa, 0x3f, 0x27, 0xa0, 0xfc, 0x42, 0xf1, 0xad, 0x92, 0xa0, 0x4b, 0xea, 0xa2, 0x35, 0xc8, 0x16, + 0x7d, 0x6e, 0x51, 0xb5, 0x46, 0x67, 0x25, 0xd4, 0x67, 0xc3, 0x21, 0x36, 0x40, 0x0c, 0x0f, 0x70, + 0x3d, 0x7a, 0x44, 0xff, 0x6a, 0x63, 0xff, 0xda, 0x46, 0x59, 0xfb, 0x7a, 0xff, 0x91, 0xaa, 0x09, + 0x2e, 0xea, 0xcb, 0x01, 0xe6, 0xc4, 0xf9, 0xed, 0x2f, 0x1a, 0x2a, 0xbf, 0x2a, 0x73, 0xf2, 0xdc, + 0xe8, 0xda, 0x5e, 0x31, 0x17, 0xe7, 0x37, 0x71, 0x74, 0x0c, 0xa3, 0xe5, 0x4b, 0xde, 0x18, 0xbe, + 0xa1, 0x47, 0x12, 0xee, 0x66, 0xc2, 0xff, 0x1a, 0x62, 0x08, 0x89, 0xe5, 0xa0, 0x32, 0x34, 0x67, + 0x23, 0xad, 0xc4, 0x1f, 0xd8, 0x14, 0xd9, 0x5e, 0xd5, 0x00, 0x41, 0xf8, 0x3a, 0x98, 0xf8, 0xf6, + 0x59, 0x22, 0xf5, 0xd8, 0x3e, 0x4b, 0x84, 0x27, 0x80, 0x8d, 0x54, 0xe2, 0xc3, 0x2d, 0x5d, 0x73, + 0x25, 0xd8, 0x13, 0x99, 0xf8, 0x82, 0x04, 0x63, 0x88, 0x01, 0x73, 0x85, 0xa1, 0x91, 0x14, 0x46, + 0xfa, 0x84, 0xdd, 0x9a, 0x97, 0x4a, 0x8e, 0xc0, 0xf9, 0xcc, 0x5e, 0xac, 0x4b, 0x97, 0x6a, 0x29, + 0x47, 0x06, 0x68, 0x96, 0xf6, 0x33, 0x85, 0x14, 0x16, 0x2d, 0xce, 0x5c, 0xd1, 0xba, 0xf1, 0xae, + 0xb2, 0x88, 0x16, 0x9c, 0x87, 0x6b, 0xf5, 0xe8, 0xd9, 0xe9, 0xe9, 0xd1, 0xe9, 0xf7, 0x2f, 0x5f, + 0xc1, 0xf6, 0x12, 0x40, 0xaa, 0xd1, 0x59, 0x37, 0x96, 0xa6, 0xd8, 0x58, 0xd3, 0x01, 0x6c, 0x26, + 0x5f, 0x5f, 0x0d, 0xf3, 0x13, 0x60, 0xde, 0x5d, 0xd8, 0x07, 0x0c, 0x33, 0x1f, 0x49, 0x3c, 0x24, + 0x9b, 0x92, 0xe8, 0x7b, 0x57, 0x6d, 0x5d, 0xbb, 0xaa, 0x41, 0xff, 0xdb, 0xba, 0xa1, 0xbf, 0xf4, + 0xbf, 0xad, 0x5f, 0xe8, 0x2f, 0x91, 0xc5, 0x0b, 0x93, 0xfd, 0xa2, 0x2b, 0x95, 0xb3, 0x2a, 0x60, + 0x8d, 0x1e, 0x47, 0x57, 0x23, 0xfe, 0x24, 0x33, 0xc2, 0x72, 0x33, 0x24, 0xe6, 0x5d, 0x42, 0xc6, + 0x9c, 0xb0, 0x44, 0x48, 0x58, 0xc4, 0xc6, 0x26, 0x1d, 0xb2, 0xb0, 0xb8, 0x75, 0x7d, 0x8f, 0x31, + 0xbc, 0x24, 0xe0, 0xcb, 0x06, 0xc1, 0x0d, 0xb3, 0x94, 0x61, 0x65, 0xdd, 0xc0, 0x16, 0x03, 0x19, + 0xae, 0xd0, 0xf5, 0x71, 0x55, 0x6a, 0x8e, 0xfb, 0xf5, 0x19, 0x1d, 0x80, 0xcb, 0x68, 0x92, 0x16, + 0x92, 0x19, 0x54, 0x0c, 0xe7, 0x97, 0x35, 0xc3, 0xb1, 0xd2, 0x6e, 0xd0, 0x88, 0x9e, 0x47, 0x38, + 0xab, 0x00, 0xfe, 0xf0, 0xbe, 0x2b, 0x04, 0xf1, 0xee, 0xf5, 0x6b, 0x11, 0x48, 0x68, 0x63, 0x24, + 0x09, 0x80, 0x0f, 0xee, 0xbd, 0x21, 0x22, 0x5e, 0x82, 0x89, 0x5f, 0x1a, 0xe5, 0x18, 0xee, 0xab, + 0x5a, 0x5c, 0xf5, 0x46, 0xd8, 0x28, 0x75, 0x9f, 0x5a, 0xa6, 0xdb, 0xec, 0x8e, 0x9d, 0xf8, 0x60, + 0x85, 0x2f, 0xa2, 0x38, 0x66, 0xb7, 0x4c, 0x4f, 0xf5, 0x23, 0x62, 0x7b, 0x24, 0x32, 0x4f, 0x52, + 0x66, 0x70, 0x20, 0x40, 0x86, 0x3c, 0x8e, 0xe6, 0x49, 0xd1, 0x6f, 0xa1, 0x7d, 0x8f, 0x01, 0x99, + 0x9c, 0x21, 0x4b, 0x46, 0xf4, 0xfe, 0xe8, 0xf4, 0xc5, 0xb7, 0x9f, 0x30, 0x24, 0x52, 0x39, 0x61, + 0xb8, 0x90, 0xa2, 0x5b, 0x48, 0x47, 0x22, 0x13, 0xad, 0x27, 0xee, 0xbf, 0xff, 0x0f, 0xce, 0x33, + 0x84, 0xf7, 0x0f, 0xe8, 0xef, 0x14, 0x31, 0x79, 0xd2, 0xd7, 0xd7, 0x24, 0x0e, 0x0d, 0x6e, 0xb4, + 0x60, 0xd5, 0x60, 0x1c, 0xc4, 0x26, 0x7c, 0xda, 0xeb, 0x63, 0x75, 0x58, 0x3d, 0x63, 0xfa, 0xa8, + 0xb5, 0x5b, 0x8f, 0xdb, 0x2d, 0x92, 0x88, 0x5a, 0xc2, 0x6f, 0xdf, 0xc7, 0xc8, 0xbb, 0xb7, 0x80, + 0xf3, 0x9e, 0xd6, 0xd5, 0xdb, 0x2a, 0x9f, 0x13, 0x9b, 0xa1, 0xac, 0xe9, 0x62, 0x10, 0xc2, 0x3e, + 0x00, 0x2a, 0x31, 0xa7, 0xd5, 0x60, 0x1d, 0xc4, 0x25, 0xce, 0x43, 0x0d, 0x90, 0x07, 0x91, 0x77, + 0xb6, 0x86, 0x83, 0xa3, 0x40, 0x56, 0xf2, 0xb3, 0x6f, 0x8f, 0x78, 0x5e, 0x45, 0x7c, 0xba, 0x8a, + 0x23, 0x5a, 0x23, 0x24, 0xe6, 0xd7, 0xef, 0xd5, 0x26, 0x4f, 0xa4, 0x69, 0x94, 0x59, 0xd5, 0xf2, + 0x56, 0x97, 0xe8, 0xf9, 0xe2, 0xae, 0x92, 0xb3, 0xbe, 0xe3, 0xb9, 0xac, 0xcc, 0xb7, 0xf0, 0xd2, + 0xe9, 0xff, 0x04, 0xd9, 0x5a, 0xca, 0x10, 0x11, 0xd4, 0x8a, 0xbc, 0xec, 0xad, 0xa4, 0x18, 0xca, + 0xbf, 0xcf, 0x26, 0xf3, 0x73, 0xe4, 0x8f, 0x26, 0xf1, 0x76, 0xe8, 0xcf, 0x26, 0xd1, 0x4d, 0x6e, + 0x31, 0x91, 0x4d, 0x16, 0x6b, 0x32, 0x15, 0xdb, 0x3f, 0x89, 0xd7, 0x13, 0xa2, 0xdd, 0x4b, 0x09, + 0x13, 0x50, 0xc5, 0xd3, 0xa2, 0x03, 0x3e, 0xe9, 0x11, 0xb3, 0xbe, 0x98, 0x1b, 0x8c, 0x55, 0xbc, + 0x53, 0x32, 0x70, 0x66, 0xfc, 0x20, 0xeb, 0x04, 0x0f, 0x2d, 0xe1, 0xc8, 0xd6, 0x24, 0x0b, 0x41, + 0xe0, 0x13, 0xe2, 0x78, 0x3e, 0xcb, 0x82, 0x10, 0x44, 0x46, 0xb4, 0x30, 0x20, 0x7d, 0xb7, 0xb6, + 0xb0, 0x02, 0xd0, 0x7c, 0x64, 0x4d, 0x75, 0x8a, 0xd3, 0x2a, 0x79, 0x26, 0xda, 0x31, 0x16, 0xf7, + 0x21, 0x91, 0x78, 0x0c, 0xe3, 0xe3, 0x54, 0x84, 0x50, 0xda, 0x21, 0xe8, 0x5d, 0x0f, 0xf6, 0xa9, + 0x20, 0xc9, 0xd1, 0x91, 0xf8, 0x70, 0x8c, 0x45, 0x12, 0x2e, 0x61, 0x49, 0xc6, 0x7a, 0xb2, 0x6a, + 0x72, 0x18, 0x38, 0xba, 0xa5, 0x8d, 0xa7, 0xec, 0xd1, 0x24, 0x2d, 0x36, 0x83, 0xe9, 0xb9, 0x1a, + 0xcb, 0x9d, 0x00, 0xba, 0xcf, 0xd2, 0xb5, 0xdc, 0xfc, 0xa3, 0xbb, 0x9a, 0xb9, 0xd9, 0xd8, 0xd8, + 0xeb, 0x96, 0x50, 0x77, 0xe5, 0xcd, 0xb2, 0x00, 0x12, 0xf8, 0x8a, 0x49, 0x23, 0x06, 0x89, 0x5e, + 0x7e, 0x48, 0x47, 0x9d, 0x9c, 0x79, 0x57, 0xa1, 0xd6, 0x64, 0xb4, 0x0d, 0xb3, 0x6d, 0x0e, 0x37, + 0xd8, 0xe0, 0x95, 0xa1, 0x1c, 0xda, 0x6c, 0x48, 0x0b, 0x3f, 0x53, 0x74, 0xa6, 0xe0, 0xcb, 0x7d, + 0x9f, 0xca, 0x68, 0xff, 0x34, 0x59, 0x99, 0x70, 0x18, 0x3d, 0x47, 0xb8, 0x23, 0xe1, 0x9f, 0xc7, + 0x25, 0x11, 0xa9, 0x62, 0x0d, 0x25, 0x32, 0x3a, 0x79, 0x59, 0x17, 0xf1, 0x5e, 0xae, 0xd9, 0x36, + 0x56, 0x3f, 0xe3, 0x7f, 0x56, 0x46, 0xd8, 0x11, 0xa8, 0xf9, 0x05, 0xdc, 0x0b, 0xf5, 0x45, 0x7f, + 0xe2, 0xe4, 0x2e, 0x14, 0xc2, 0x27, 0x79, 0xd1, 0xe2, 0x8e, 0xfe, 0xf2, 0xd5, 0xe9, 0xab, 0x17, + 0xa7, 0xf9, 0x7e, 0x0e, 0xd3, 0xc1, 0x0f, 0xc4, 0x24, 0x62, 0xd8, 0xab, 0x3a, 0x50, 0x05, 0xe8, + 0xc5, 0xc9, 0xb3, 0x63, 0x4e, 0xfe, 0x14, 0x85, 0xe2, 0x3d, 0x84, 0x39, 0x4e, 0xa3, 0x73, 0x9f, + 0xad, 0x25, 0x92, 0xb9, 0xd0, 0xcc, 0x18, 0xf0, 0x63, 0x24, 0xd4, 0x44, 0x5b, 0xef, 0x0a, 0xc8, + 0xfd, 0x9b, 0x93, 0xd0, 0x88, 0xaf, 0x71, 0x60, 0x28, 0xdc, 0x7e, 0x52, 0xf2, 0x15, 0xb0, 0xc7, + 0x05, 0x6b, 0x9a, 0xb8, 0x0a, 0xf0, 0xc1, 0x88, 0x9e, 0x35, 0x3e, 0x7e, 0xcc, 0x9d, 0x03, 0x3e, + 0xb4, 0xdd, 0x4e, 0x5d, 0xec, 0xcb, 0xc5, 0xa9, 0x87, 0x19, 0x66, 0xb7, 0x7c, 0x46, 0x62, 0x83, + 0x0f, 0xa7, 0xc9, 0x51, 0x34, 0x87, 0xac, 0xf5, 0xe6, 0x44, 0x1d, 0x45, 0xdf, 0xdf, 0x1b, 0xe8, + 0xde, 0x2a, 0xa0, 0x7e, 0xfa, 0x17, 0xf8, 0x72, 0x10, 0xd8, 0x6c, 0x0d, 0xab, 0xd4, 0x9b, 0xa9, + 0x2d, 0x4d, 0x5d, 0xe2, 0xcc, 0xae, 0xfd, 0x3d, 0xd0, 0xc0, 0xfe, 0x6e, 0x5b, 0xef, 0xdd, 0xd3, + 0x2c, 0x79, 0xf3, 0xc0, 0x90, 0x3d, 0x13, 0x06, 0xa8, 0xa0, 0x8f, 0x20, 0xd4, 0xcc, 0xab, 0x8e, + 0xc4, 0xa2, 0x9d, 0x6d, 0x55, 0x3b, 0x3c, 0xd8, 0xdf, 0xad, 0xe0, 0x9c, 0x62, 0x30, 0x35, 0xcd, + 0x8b, 0xc9, 0x65, 0x40, 0x94, 0x9a, 0x82, 0xf4, 0x8a, 0x7d, 0xfd, 0x96, 0x73, 0x1a, 0xae, 0xe9, + 0xac, 0x24, 0x3e, 0x94, 0xde, 0xee, 0xec, 0x6d, 0xff, 0x3b, 0xf5, 0xd6, 0x18, 0xa2, 0x34, 0x67, + 0x00, 0xc3, 0xce, 0x6c, 0x53, 0xf7, 0x61, 0x09, 0xad, 0x93, 0x97, 0xff, 0x64, 0x7b, 0xdf, 0x2d, + 0xe5, 0x3f, 0x41, 0x48, 0x9b, 0xe6, 0x91, 0xf6, 0xb1, 0xd1, 0x5b, 0x04, 0xbf, 0x63, 0x97, 0x0d, + 0x5a, 0x45, 0x1d, 0x8c, 0x48, 0x1c, 0x6c, 0xde, 0x1a, 0xb5, 0x71, 0xa8, 0x1d, 0x47, 0x9a, 0xbc, + 0x64, 0x2c, 0xef, 0x9b, 0xf5, 0x7a, 0xae, 0x6e, 0x36, 0xe2, 0x43, 0xd5, 0x97, 0x31, 0xc9, 0xde, + 0xf2, 0x86, 0xcd, 0x03, 0xbc, 0x56, 0xb2, 0x4d, 0xc5, 0x9c, 0xb4, 0x6a, 0xc1, 0xbb, 0x70, 0x22, + 0xcb, 0x7a, 0x97, 0xae, 0x97, 0x19, 0xcf, 0x34, 0x87, 0x5a, 0xbf, 0xf4, 0xd7, 0xd9, 0x5e, 0x74, + 0xa8, 0xf3, 0x82, 0x9e, 0x9b, 0xc7, 0x45, 0x47, 0x61, 0xae, 0x85, 0xac, 0x80, 0x30, 0x0c, 0x62, + 0xf6, 0xd1, 0xca, 0xaa, 0x95, 0x92, 0x48, 0xd8, 0x6a, 0x53, 0x3a, 0x5d, 0x0d, 0x8b, 0xdd, 0x65, + 0xd3, 0x02, 0xb8, 0x2c, 0xe7, 0xb7, 0x92, 0x8f, 0xc4, 0xf2, 0x89, 0xa7, 0xbe, 0x79, 0xff, 0xea, + 0x9b, 0xc6, 0xe9, 0x49, 0x1d, 0x56, 0x02, 0x24, 0x01, 0x50, 0x35, 0x42, 0xb3, 0xad, 0xa8, 0xa6, + 0xab, 0x87, 0xad, 0x1d, 0x55, 0xf3, 0x66, 0x24, 0x72, 0x81, 0xbd, 0x90, 0xc4, 0xe7, 0x4f, 0xd5, + 0x48, 0xc5, 0x84, 0x07, 0x6c, 0xbb, 0xee, 0x4a, 0xe4, 0x65, 0xcd, 0xec, 0x7d, 0xf4, 0xb2, 0xa3, + 0x5f, 0x36, 0xcc, 0x71, 0x38, 0xbd, 0x12, 0xcf, 0x36, 0x1c, 0xfb, 0xd6, 0x57, 0xb7, 0xed, 0x5d, + 0x9f, 0x88, 0x93, 0x17, 0x9b, 0x2a, 0xd2, 0xa8, 0x21, 0xfe, 0x7e, 0x76, 0xb8, 0x3d, 0xcb, 0x3f, + 0x6f, 0x8b, 0xce, 0x60, 0xd8, 0x2b, 0x32, 0x59, 0x28, 0x1b, 0xe8, 0x0e, 0xfb, 0x2b, 0x5a, 0xb0, + 0xdf, 0x3c, 0x5f, 0x0b, 0x76, 0x4a, 0xb4, 0xa1, 0x13, 0x1e, 0x2c, 0x07, 0xbc, 0x57, 0x00, 0x9c, + 0xbb, 0xc7, 0x15, 0x62, 0xaf, 0x31, 0xee, 0x7a, 0xd9, 0x55, 0x4e, 0xa0, 0x0a, 0x3b, 0x81, 0x1b, + 0x89, 0xfe, 0xcc, 0x2e, 0xcb, 0xec, 0xf5, 0xce, 0x01, 0xb0, 0x36, 0xfa, 0x8c, 0x73, 0x6f, 0x46, + 0x07, 0xac, 0xe8, 0x57, 0xb4, 0x24, 0x27, 0xc9, 0x02, 0x2d, 0x6f, 0x44, 0x9b, 0x40, 0xf9, 0x48, + 0xfe, 0xde, 0x6d, 0xe4, 0x2e, 0x78, 0x15, 0xed, 0xac, 0xf4, 0xca, 0xcb, 0x46, 0xf6, 0x80, 0xd6, + 0x72, 0x7f, 0x00, 0xab, 0xd0, 0xf0, 0xfe, 0xbe, 0x01, 0x90, 0x1b, 0xd9, 0x25, 0x7b, 0x6e, 0xb5, + 0x68, 0x37, 0xe6, 0x6c, 0xdc, 0x65, 0x4e, 0xf1, 0xaf, 0xde, 0x7e, 0xff, 0xc6, 0x78, 0xc4, 0x97, + 0x9c, 0x41, 0x3f, 0x38, 0x83, 0x7e, 0xec, 0xb8, 0xce, 0x25, 0xff, 0xeb, 0xc9, 0x1f, 0xb8, 0x75, + 0x3a, 0x1f, 0xdd, 0x4a, 0x1f, 0xb7, 0x0f, 0x0e, 0x7b, 0x92, 0x3b, 0xe2, 0x18, 0x86, 0xc2, 0x72, + 0x96, 0x43, 0xbf, 0xc4, 0x29, 0x0c, 0xdf, 0xd8, 0x47, 0x8d, 0x7f, 0x90, 0x68, 0x4c, 0x7f, 0x33, + 0x6f, 0x35, 0xfa, 0x2d, 0xfe, 0x6a, 0xfc, 0x91, 0x64, 0x25, 0xfa, 0x3b, 0x9a, 0x5d, 0xda, 0x8d, + 0x65, 0x0e, 0x56, 0xa6, 0x25, 0xc8, 0xce, 0xfa, 0x0f, 0xfb, 0x0d, 0xd1, 0xef, 0xdc, 0xa9, 0x26, + 0x7f, 0xd8, 0x6b, 0x5b, 0x0f, 0x5f, 0xe5, 0x5f, 0xb6, 0xb3, 0x5f, 0x3b, 0xd9, 0xaf, 0xdd, 0x6b, + 0x6e, 0xb1, 0x78, 0x56, 0xf2, 0xc1, 0x49, 0x86, 0x17, 0x54, 0x42, 0x0e, 0x09, 0xf2, 0x02, 0xc6, + 0x5f, 0xf9, 0x83, 0x03, 0x7b, 0x32, 0x0a, 0x18, 0x9f, 0x61, 0x2e, 0x53, 0xb0, 0x62, 0x52, 0x9f, + 0x67, 0xf3, 0x04, 0xa3, 0x1c, 0x90, 0x30, 0xee, 0xb0, 0x05, 0x53, 0xff, 0x9d, 0x73, 0xe9, 0x12, + 0x63, 0xfb, 0xe0, 0xc0, 0xd7, 0xdc, 0x01, 0xcb, 0xb2, 0x3f, 0x4f, 0x75, 0x83, 0x82, 0x00, 0xed, + 0x74, 0xec, 0x3a, 0x98, 0x63, 0xfd, 0x47, 0x4f, 0x35, 0x57, 0xaa, 0x74, 0x09, 0xf9, 0xe0, 0xc4, + 0xe9, 0xcc, 0xf9, 0x68, 0x51, 0x01, 0x11, 0xc1, 0xf3, 0x57, 0xc7, 0x67, 0xcf, 0x4e, 0x4f, 0x8f, + 0x4b, 0xc4, 0x50, 0xf6, 0xd9, 0xbc, 0xa5, 0x09, 0xe8, 0x3a, 0xb4, 0xdc, 0x89, 0x7d, 0x74, 0x1d, + 0xd8, 0xca, 0x1c, 0x17, 0xc7, 0x68, 0xf4, 0xdb, 0xb9, 0x73, 0x97, 0x38, 0x5c, 0x4a, 0xa5, 0x8e, + 0xae, 0xb4, 0xbd, 0xb7, 0x57, 0x59, 0x47, 0xbb, 0xf9, 0x95, 0x5a, 0x30, 0x45, 0xdb, 0xcd, 0xf6, + 0x42, 0xe9, 0xbf, 0xae, 0x29, 0x6d, 0x8d, 0xf0, 0xe5, 0xbb, 0xef, 0x9f, 0xbf, 0x7e, 0x75, 0xf6, + 0xf5, 0xd1, 0xab, 0xd7, 0x2f, 0x4f, 0xac, 0xf0, 0x90, 0x0f, 0x8b, 0x8e, 0xb6, 0x6e, 0xf9, 0xb0, + 0x6f, 0x91, 0x11, 0x94, 0x3b, 0x5d, 0xee, 0xd6, 0xc6, 0xc7, 0x3c, 0xec, 0xe4, 0x84, 0xb6, 0xda, + 0xa3, 0x77, 0x6f, 0xd1, 0x28, 0x35, 0x76, 0x1b, 0x0c, 0xbb, 0x3a, 0x86, 0xc3, 0x71, 0xf9, 0x8e, + 0x97, 0xae, 0x73, 0xa2, 0x1f, 0x2f, 0xfc, 0x9b, 0x04, 0xa4, 0x56, 0x0c, 0x4c, 0x71, 0x97, 0x44, + 0x97, 0xb8, 0xe5, 0x50, 0x90, 0x8f, 0x84, 0x1d, 0x0d, 0x9f, 0x99, 0x5c, 0x0e, 0x5f, 0x3f, 0x1a, + 0xf8, 0x76, 0x98, 0x87, 0x5b, 0x88, 0xc7, 0xc8, 0x41, 0x10, 0x79, 0x67, 0xf5, 0x11, 0x5f, 0x6f, + 0x2a, 0x17, 0x23, 0x2a, 0xdc, 0x42, 0x1c, 0x84, 0xbb, 0x18, 0xb7, 0xe0, 0x16, 0xd6, 0x89, 0x6b, + 0x79, 0xe2, 0xbb, 0xc5, 0x25, 0xe6, 0x5a, 0x07, 0x7a, 0x6e, 0xf9, 0x98, 0xcc, 0xad, 0x3a, 0xfe, + 0x41, 0x5f, 0xa5, 0xab, 0xf0, 0x05, 0xcc, 0x3b, 0x2b, 0x4f, 0xa6, 0xbb, 0xb6, 0x6b, 0xbe, 0x6b, + 0x3b, 0xdb, 0xbb, 0x45, 0x07, 0xfa, 0x0c, 0x9a, 0xcc, 0x63, 0x06, 0xee, 0x07, 0x3c, 0x66, 0xe0, + 0x8a, 0x1c, 0xd2, 0xb5, 0xfd, 0xd9, 0xdd, 0x82, 0x27, 0xba, 0x5b, 0xf6, 0x15, 0x77, 0x17, 0xa8, + 0xac, 0xec, 0x7b, 0xed, 0x2e, 0x59, 0x72, 0x6e, 0xe5, 0x9a, 0x72, 0x2b, 0x18, 0xb0, 0x5b, 0x22, + 0xca, 0x22, 0x4d, 0xba, 0x65, 0x2e, 0x9a, 0x0d, 0xd9, 0x30, 0x89, 0x6c, 0xd0, 0xef, 0xb2, 0x17, + 0x7a, 0xdc, 0x0b, 0x7e, 0x71, 0xee, 0x82, 0xfb, 0x9a, 0x5b, 0xc9, 0x6b, 0xdc, 0xa5, 0x5e, 0x64, + 0xee, 0x12, 0x5f, 0x2d, 0x77, 0x9d, 0x57, 0x95, 0x5b, 0xe5, 0x89, 0xe4, 0x56, 0xfb, 0xfa, 0x64, + 0x43, 0xcc, 0x7c, 0x3c, 0xb2, 0x31, 0xbe, 0xcc, 0xdf, 0xe8, 0x41, 0x2e, 0xfa, 0xf4, 0xb8, 0x4b, + 0x3c, 0x67, 0xdc, 0xb2, 0xef, 0x8a, 0x5b, 0xe9, 0x44, 0x92, 0xb5, 0xce, 0xfd, 0xcc, 0x5a, 0x7e, + 0x26, 0x4f, 0xba, 0xd5, 0xe2, 0x51, 0x9f, 0x5b, 0xd8, 0x33, 0xdc, 0xc5, 0x03, 0x3c, 0xb7, 0x7c, + 0xdc, 0xe6, 0x16, 0x4f, 0xb4, 0x5c, 0xdb, 0x77, 0x24, 0xeb, 0x00, 0xf6, 0x51, 0xd3, 0xfc, 0xd7, + 0xef, 0x7f, 0xc8, 0x1a, 0x2f, 0xb9, 0x86, 0xb8, 0x96, 0xef, 0x86, 0x5b, 0xf4, 0xab, 0x70, 0xcb, + 0x3c, 0xb1, 0xec, 0xad, 0x60, 0x2d, 0xc7, 0x79, 0xbe, 0x18, 0xdf, 0x7c, 0x6f, 0x2d, 0xc5, 0xb9, + 0x35, 0xcc, 0xe2, 0x09, 0x95, 0x5b, 0x38, 0x5b, 0x72, 0x17, 0x0f, 0x86, 0xdc, 0xc5, 0xd3, 0x1d, + 0xb7, 0x70, 0x1e, 0xe3, 0x96, 0x8f, 0x51, 0x72, 0xe4, 0x6b, 0x3b, 0x62, 0x8e, 0xff, 0xec, 0x85, + 0x99, 0x82, 0xf2, 0xa9, 0x88, 0xbb, 0x78, 0x4e, 0xe1, 0x56, 0x98, 0xfd, 0xdd, 0x6a, 0xdb, 0xb9, + 0xbb, 0xc4, 0x02, 0xed, 0x56, 0x58, 0x7a, 0xdd, 0x4a, 0xd3, 0xaa, 0x5b, 0x6d, 0xfc, 0xcc, 0xa9, + 0x99, 0x75, 0xbd, 0x9c, 0x94, 0x8d, 0xea, 0x97, 0x93, 0x72, 0xd1, 0xd4, 0xe9, 0x96, 0x2c, 0x7f, + 0xee, 0xa2, 0xb9, 0xcd, 0x2d, 0x1b, 0x94, 0xdc, 0x0a, 0x4b, 0x8c, 0x5b, 0x32, 0x9f, 0xb8, 0x0b, + 0x96, 0x0f, 0x77, 0xd1, 0xbe, 0xe0, 0x56, 0x2a, 0xf1, 0x6e, 0xb5, 0xc6, 0xed, 0xda, 0x1a, 0x71, + 0x36, 0x5e, 0xd9, 0x7d, 0xb3, 0xf1, 0x66, 0xaa, 0x58, 0x36, 0xde, 0x92, 0x86, 0xea, 0x16, 0x84, + 0x25, 0xb7, 0x24, 0x59, 0xb9, 0xb6, 0x3a, 0xea, 0x56, 0xa8, 0x5a, 0x6e, 0x51, 0x45, 0x72, 0xcb, + 0x8a, 0x8d, 0x6b, 0xeb, 0x1e, 0xee, 0x82, 0x6c, 0x50, 0x92, 0xe3, 0x3f, 0xde, 0x6d, 0x7c, 0xec, + 0xd9, 0x21, 0xb8, 0xb8, 0xa5, 0x65, 0xec, 0x4f, 0x60, 0x56, 0xb3, 0x03, 0x71, 0xbd, 0xe4, 0x26, + 0x1c, 0xa8, 0xd1, 0x3c, 0x14, 0xed, 0xdf, 0x9b, 0x05, 0x35, 0x9c, 0xd3, 0xd6, 0x6f, 0x11, 0x40, + 0x2c, 0xa2, 0x04, 0x5c, 0x7d, 0xbc, 0x2b, 0x0f, 0xf9, 0x31, 0xe0, 0xdd, 0x21, 0xdf, 0x7b, 0xf8, + 0x1e, 0xfb, 0xe9, 0x3c, 0x0e, 0x55, 0xcc, 0x49, 0x11, 0x38, 0xe6, 0xf5, 0x6e, 0x63, 0x23, 0x83, + 0xc5, 0xb7, 0x5f, 0xd5, 0xa6, 0xc9, 0xb9, 0xab, 0xa2, 0x8b, 0x03, 0xb8, 0x9c, 0xd8, 0x50, 0x7d, + 0xb8, 0xdb, 0x0f, 0xa3, 0xc1, 0x1c, 0x67, 0xd3, 0x4d, 0x31, 0xbf, 0xbc, 0x9a, 0xf0, 0x49, 0x75, + 0x8d, 0xf8, 0xda, 0xa5, 0x23, 0x4d, 0xf8, 0x93, 0x26, 0x47, 0x30, 0x9b, 0xf8, 0x5e, 0x06, 0xaa, + 0x1c, 0xb5, 0xa5, 0x6a, 0xd1, 0x85, 0x7a, 0xaa, 0x5f, 0x34, 0xa2, 0x0b, 0x47, 0x75, 0xcd, 0x83, + 0x1f, 0xc7, 0x79, 0x6d, 0xe4, 0xc0, 0x78, 0xa1, 0xef, 0xd3, 0x22, 0xcd, 0x28, 0x39, 0xe7, 0x0f, + 0x59, 0xc3, 0xe7, 0x7e, 0xaa, 0x5b, 0x7d, 0x7e, 0x73, 0x34, 0xac, 0x09, 0x84, 0xc4, 0xa9, 0x37, + 0x71, 0xad, 0x6e, 0x38, 0x7c, 0x31, 0x0e, 0x26, 0xc3, 0x9a, 0x3f, 0x11, 0x70, 0x89, 0x9f, 0x9e, + 0x06, 0x53, 0x9f, 0x98, 0x7e, 0xad, 0x56, 0x57, 0x07, 0x87, 0x80, 0x1f, 0xfb, 0x53, 0xe2, 0xc0, + 0x35, 0x52, 0xb7, 0x77, 0xe0, 0xbc, 0x20, 0x38, 0xc8, 0xd1, 0xce, 0x77, 0xcf, 0x59, 0xf8, 0xce, + 0xb0, 0x93, 0xdf, 0x44, 0x16, 0x0c, 0x05, 0x2f, 0x59, 0x9f, 0x38, 0x63, 0xc6, 0x89, 0x36, 0xa6, + 0x3e, 0x9b, 0x4c, 0x6a, 0x4e, 0x13, 0x1a, 0x47, 0x1d, 0xa4, 0xf4, 0xca, 0xa3, 0x19, 0xa8, 0xa5, + 0x6e, 0xc0, 0xed, 0xdf, 0x4a, 0x5a, 0x08, 0xc1, 0x68, 0xc0, 0x11, 0xc8, 0x1f, 0xf2, 0x2b, 0xea, + 0x5c, 0xbe, 0x6a, 0xce, 0xc5, 0x1d, 0x6a, 0xae, 0x7d, 0xdd, 0xd9, 0xc7, 0x9e, 0x54, 0x4b, 0x05, + 0xb5, 0x48, 0x60, 0xd8, 0x94, 0x10, 0x83, 0x9a, 0x63, 0x3c, 0xf8, 0x00, 0xed, 0x43, 0xf0, 0x91, + 0x6f, 0x85, 0xa3, 0x0e, 0x72, 0x8d, 0xbb, 0x7a, 0xef, 0x1e, 0xfd, 0x34, 0x89, 0x24, 0xac, 0xfe, + 0x0e, 0xd0, 0xd7, 0x81, 0xd5, 0x9a, 0x46, 0x9a, 0x69, 0xad, 0x5e, 0x5f, 0x33, 0x29, 0x04, 0xd5, + 0xd9, 0xa2, 0x6e, 0x58, 0x20, 0xbc, 0xe1, 0x30, 0xaf, 0xcf, 0xd5, 0x09, 0xe9, 0x38, 0x39, 0xe0, + 0x84, 0xb7, 0xe2, 0x19, 0x8e, 0xc3, 0x4a, 0x39, 0xc4, 0xe0, 0x5c, 0x4b, 0xbe, 0x37, 0x64, 0x7b, + 0x3a, 0x93, 0xb1, 0xdc, 0x9a, 0xa7, 0xa8, 0x8d, 0xf8, 0xa6, 0x90, 0x86, 0xc9, 0x4b, 0x25, 0x93, + 0xc1, 0x0c, 0xb6, 0x72, 0x80, 0x71, 0xf5, 0x7d, 0x16, 0x12, 0x2a, 0x45, 0xd5, 0x7c, 0x0f, 0x66, + 0x48, 0x9c, 0x43, 0x10, 0xb0, 0x19, 0x7d, 0x08, 0xe0, 0x7f, 0x34, 0xa0, 0xad, 0x31, 0x4a, 0xd5, + 0x79, 0xc4, 0x0e, 0x49, 0xa4, 0xfe, 0xd3, 0x74, 0x2b, 0x15, 0x8c, 0x68, 0x7e, 0x19, 0x8b, 0x7c, + 0x95, 0x1d, 0x81, 0x81, 0x1f, 0x34, 0xae, 0xf1, 0x33, 0x89, 0x5d, 0x6a, 0x34, 0x2a, 0xe8, 0xeb, + 0x35, 0xa2, 0x6f, 0x09, 0xf2, 0x97, 0x85, 0xe3, 0xd0, 0x40, 0x78, 0x14, 0x23, 0x8e, 0xb0, 0xee, + 0x32, 0xd1, 0x13, 0x13, 0xf7, 0x93, 0x84, 0x7a, 0xe6, 0x8a, 0xd3, 0x95, 0xc6, 0x1c, 0xb5, 0x22, + 0x61, 0x08, 0xcd, 0x33, 0x9a, 0xe7, 0xf7, 0xc4, 0xcd, 0xeb, 0xb7, 0x6a, 0x30, 0xf1, 0xbd, 0x8c, + 0xc7, 0x2d, 0x7c, 0xef, 0xa9, 0xd2, 0x1b, 0xa8, 0x27, 0xf3, 0xc9, 0xa4, 0xa7, 0xee, 0x8a, 0xdd, + 0xb6, 0xef, 0xc9, 0xbb, 0xe5, 0xfe, 0x55, 0x64, 0x6e, 0xe8, 0xf1, 0x07, 0x9a, 0x81, 0xd7, 0x7c, + 0xd4, 0x39, 0x23, 0x78, 0x5d, 0xb9, 0x94, 0x50, 0x92, 0xdf, 0x6d, 0x4d, 0x68, 0xce, 0xdc, 0xec, + 0xa6, 0x10, 0x4c, 0x80, 0xdc, 0xce, 0xe6, 0x4b, 0x08, 0x26, 0x2f, 0x06, 0x8d, 0x32, 0x55, 0xd1, + 0x33, 0x24, 0x4d, 0x32, 0x23, 0x91, 0xa5, 0x87, 0x26, 0xb2, 0x1e, 0x9c, 0x70, 0x23, 0x58, 0x84, + 0xdb, 0xb2, 0x08, 0x89, 0x58, 0x4b, 0x0b, 0xd1, 0x4a, 0x7f, 0x42, 0x8b, 0xae, 0x72, 0x49, 0x52, + 0x73, 0x5f, 0x4f, 0x89, 0xe4, 0x52, 0x9a, 0x94, 0x90, 0xc7, 0x4a, 0x68, 0x08, 0x09, 0x0b, 0x8c, + 0x18, 0xf5, 0xeb, 0xaf, 0x2a, 0x54, 0x4f, 0x54, 0xbb, 0x6e, 0xf8, 0x9e, 0x23, 0x2e, 0xab, 0x4e, + 0x2f, 0x63, 0x6a, 0x73, 0x5e, 0x80, 0x60, 0xde, 0xff, 0x84, 0x7f, 0x98, 0x8d, 0x7f, 0x83, 0x7f, + 0x4e, 0x9f, 0x63, 0xd5, 0x29, 0x38, 0x39, 0xaa, 0x80, 0x0a, 0xb5, 0xf1, 0xc0, 0x87, 0xbd, 0xd4, + 0xc0, 0xe1, 0x01, 0xa7, 0x14, 0x56, 0x7f, 0xfa, 0x13, 0x7d, 0x7b, 0xa2, 0xe6, 0xcd, 0x89, 0x1f, + 0x9e, 0xa7, 0x63, 0xd5, 0x50, 0x1d, 0x9a, 0xc6, 0x50, 0xb5, 0xe4, 0x7b, 0x4f, 0x05, 0x5b, 0x5b, + 0x32, 0x3d, 0xba, 0x03, 0xb5, 0x80, 0xa7, 0xa8, 0x4d, 0x7c, 0x30, 0xa4, 0x15, 0xfc, 0x35, 0xfc, + 0xc1, 0x6a, 0xd4, 0xbf, 0xae, 0xf5, 0xd8, 0xa9, 0xd7, 0x89, 0x6e, 0x1c, 0xa6, 0x9e, 0x39, 0xad, + 0xe8, 0x5e, 0x81, 0x47, 0xd3, 0x90, 0x9f, 0x7b, 0xa4, 0x59, 0x11, 0x77, 0xad, 0xcd, 0x78, 0xc8, + 0x9a, 0x97, 0x50, 0x1f, 0x6b, 0x33, 0x0c, 0xd9, 0xa1, 0x75, 0x4c, 0x8b, 0x8e, 0xd0, 0x4f, 0x8a, + 0xdb, 0xbb, 0x51, 0xcd, 0x69, 0x39, 0x8c, 0x5f, 0xdd, 0x85, 0x00, 0xbd, 0x47, 0x07, 0x48, 0x53, + 0x9a, 0x90, 0x50, 0x45, 0x5d, 0xda, 0xa2, 0x6e, 0x53, 0x17, 0xb2, 0xea, 0xdc, 0x62, 0x69, 0x9f, + 0xa9, 0x20, 0x21, 0x34, 0x4e, 0x6b, 0xf1, 0xd6, 0xe2, 0x68, 0x1f, 0x84, 0x6a, 0x84, 0x84, 0x88, + 0x7a, 0x46, 0xe7, 0x1f, 0xb3, 0xbd, 0x08, 0xe9, 0x9d, 0x49, 0x0c, 0x84, 0xb8, 0x4e, 0xea, 0xb4, + 0xe4, 0x1e, 0xc1, 0xee, 0xe5, 0x2c, 0x26, 0xe1, 0x74, 0xcc, 0x0a, 0x13, 0xca, 0xc1, 0x64, 0xd6, + 0xdd, 0xe5, 0x55, 0x74, 0x72, 0xc7, 0x7b, 0xd7, 0x12, 0xa2, 0xae, 0x2a, 0xce, 0xa5, 0x3f, 0xea, + 0xc5, 0xa1, 0x37, 0x53, 0x7f, 0xf0, 0x62, 0x84, 0xbc, 0x16, 0x35, 0x1a, 0x0d, 0x66, 0x9c, 0xfe, + 0x34, 0x69, 0x27, 0xd3, 0xbf, 0xf8, 0x6e, 0x2e, 0xeb, 0x77, 0x53, 0xaf, 0x98, 0xc5, 0x57, 0x4d, + 0xe9, 0x6c, 0x1d, 0x48, 0x46, 0x2e, 0x8c, 0xbc, 0x09, 0x0e, 0xf8, 0x38, 0xd0, 0x2d, 0xb1, 0x30, + 0xc2, 0x13, 0x61, 0x11, 0xab, 0x29, 0x49, 0x20, 0xb5, 0x10, 0x4e, 0xe5, 0xbf, 0xf8, 0x42, 0xd7, + 0x30, 0x8e, 0x35, 0x5c, 0x70, 0x29, 0x4f, 0x36, 0x89, 0x57, 0x68, 0xdc, 0xa5, 0x2d, 0x16, 0xa7, + 0xb2, 0x56, 0x23, 0x61, 0xa4, 0xaf, 0x33, 0x81, 0xc3, 0x69, 0xde, 0x20, 0x8d, 0x48, 0x3a, 0x0a, + 0x1e, 0x63, 0x1b, 0x90, 0xec, 0xba, 0xfd, 0x34, 0x94, 0x44, 0x36, 0x07, 0xab, 0x3b, 0x92, 0x65, + 0xc3, 0x71, 0xea, 0x0b, 0xd5, 0xa3, 0xd9, 0xfd, 0x6a, 0x47, 0xb3, 0x62, 0x65, 0x24, 0x94, 0x59, + 0x57, 0x33, 0xcb, 0x3c, 0x63, 0xaa, 0x82, 0x61, 0x98, 0xf1, 0x6a, 0x6e, 0xa9, 0xb2, 0x51, 0x34, + 0xb3, 0x6b, 0x29, 0x0f, 0x14, 0xc4, 0xa1, 0x9e, 0xfd, 0x3d, 0x9a, 0x2d, 0xfb, 0x0c, 0xf8, 0x25, + 0x1c, 0xdb, 0x92, 0xe6, 0x81, 0x6d, 0x68, 0xd5, 0x17, 0x9c, 0xd9, 0x72, 0x29, 0x4b, 0x5e, 0x5d, + 0x1c, 0x09, 0x70, 0x44, 0x14, 0x00, 0xa4, 0x26, 0xd7, 0x8b, 0x96, 0x16, 0x25, 0x0e, 0xf7, 0xf8, + 0xf4, 0xbd, 0xcb, 0x5e, 0xfc, 0x3a, 0x69, 0x33, 0x8a, 0xe1, 0x3a, 0xa7, 0xa6, 0x92, 0x1c, 0x25, + 0x18, 0x02, 0x9f, 0xfa, 0x03, 0x8e, 0x71, 0xa3, 0xc6, 0xd6, 0x18, 0x46, 0xfa, 0x24, 0x19, 0x5e, + 0x42, 0x24, 0x64, 0xc6, 0x7e, 0xd3, 0x29, 0x74, 0x5e, 0xdf, 0x1f, 0x6b, 0xee, 0x97, 0xe5, 0x4f, + 0x77, 0x24, 0x3c, 0x25, 0xbe, 0x5a, 0x85, 0x23, 0xab, 0x74, 0x25, 0x92, 0x0a, 0xdf, 0x8b, 0x0d, + 0xe5, 0xf8, 0xbb, 0x33, 0xf3, 0x02, 0x5e, 0x02, 0xaa, 0xc3, 0x5f, 0x5a, 0x71, 0xd9, 0xec, 0xc8, + 0x6c, 0x03, 0x1e, 0x7f, 0xc1, 0x12, 0x33, 0x30, 0x57, 0xce, 0x3d, 0xe4, 0xf8, 0x32, 0xed, 0xb3, + 0x74, 0xbf, 0xb8, 0xda, 0xd6, 0x40, 0x42, 0x5e, 0xab, 0x05, 0x50, 0xf6, 0x66, 0x44, 0x32, 0x3f, + 0x15, 0x39, 0xe3, 0x13, 0x91, 0xfa, 0xbd, 0x40, 0x72, 0x2e, 0xac, 0x35, 0x30, 0xb9, 0x4c, 0x09, + 0xa8, 0x20, 0x03, 0x69, 0x90, 0xd6, 0x91, 0x3e, 0xca, 0x38, 0x59, 0x3d, 0xc2, 0x2f, 0x01, 0x8c, + 0x89, 0xbd, 0xf3, 0x29, 0xaa, 0xc1, 0xad, 0x62, 0x50, 0x65, 0xe2, 0x3d, 0x19, 0x47, 0x57, 0x38, + 0xed, 0x09, 0xfd, 0x2b, 0x5f, 0x0b, 0xf3, 0x34, 0x42, 0x50, 0x90, 0xd9, 0xf9, 0xb0, 0x61, 0x09, + 0x49, 0xe9, 0xa8, 0x10, 0x4e, 0xc2, 0x68, 0x27, 0x28, 0xd2, 0x33, 0x8d, 0x88, 0x2d, 0xb5, 0x87, + 0x14, 0x01, 0x19, 0xaa, 0x75, 0x9b, 0x55, 0x34, 0xb7, 0x40, 0x75, 0xe5, 0xb2, 0xf6, 0xb2, 0xbb, + 0x2b, 0xa0, 0x24, 0xed, 0xaf, 0x43, 0x08, 0xf7, 0xd7, 0x29, 0x61, 0xd2, 0x37, 0x21, 0x42, 0xab, + 0x6a, 0x72, 0xa1, 0xbc, 0x66, 0xda, 0x6f, 0xf2, 0xcd, 0xbc, 0xdf, 0x9e, 0xbe, 0x79, 0x2d, 0x29, + 0x8d, 0x72, 0x24, 0x7f, 0x51, 0x44, 0x94, 0x85, 0xe8, 0xf5, 0x2d, 0x3c, 0x8c, 0x62, 0x95, 0xf4, + 0xfd, 0xbe, 0x78, 0x2c, 0x15, 0xb6, 0x11, 0xa9, 0xb2, 0xd9, 0x4d, 0xa2, 0x98, 0x34, 0x27, 0xcf, + 0xed, 0xf3, 0x16, 0xd9, 0x6f, 0x72, 0x96, 0x73, 0x12, 0x73, 0x3c, 0xf9, 0x55, 0xcf, 0x6b, 0x90, + 0xe6, 0x50, 0x13, 0x0c, 0x8e, 0x38, 0x9a, 0x50, 0x00, 0x58, 0xc3, 0xcd, 0xe6, 0x25, 0x5e, 0xa1, + 0x46, 0xa6, 0xb1, 0x63, 0xc1, 0x84, 0x78, 0x61, 0x63, 0xd6, 0xfa, 0xa0, 0x94, 0x53, 0x99, 0x10, + 0x97, 0x13, 0xd1, 0x12, 0x7d, 0x2e, 0x2d, 0xca, 0x99, 0xbc, 0x96, 0x96, 0x5a, 0x5f, 0x3f, 0x8e, + 0xae, 0x88, 0xb1, 0x21, 0x85, 0xd7, 0xca, 0xb4, 0x69, 0x6a, 0x38, 0xd9, 0x3c, 0x7c, 0x99, 0x65, + 0x34, 0xd7, 0xc9, 0xd1, 0x16, 0x01, 0xaf, 0x06, 0x62, 0xdd, 0xd5, 0x5c, 0x79, 0xa7, 0xaf, 0xa4, + 0x1e, 0xcf, 0xc0, 0x4b, 0xe7, 0x4b, 0xf8, 0x1b, 0x40, 0x21, 0x26, 0x25, 0xe6, 0x43, 0xfb, 0x63, + 0x89, 0x92, 0x46, 0x6c, 0x94, 0x5c, 0x56, 0xbc, 0xf3, 0x71, 0x05, 0x2f, 0x1a, 0xb1, 0xf9, 0xba, + 0xbe, 0xac, 0xee, 0xf6, 0x62, 0x53, 0x42, 0x39, 0x4f, 0xf9, 0x40, 0xe5, 0x25, 0x4d, 0x79, 0xcd, + 0xbc, 0xfa, 0x33, 0x7b, 0x52, 0x13, 0x95, 0x47, 0xaf, 0x11, 0x2e, 0xe7, 0x9f, 0xa4, 0x88, 0xce, + 0xa9, 0x41, 0x20, 0x5d, 0xa4, 0x70, 0x6e, 0xa6, 0xa0, 0xc5, 0x92, 0x0a, 0x3b, 0x04, 0xdf, 0xd4, + 0x59, 0xea, 0x20, 0xa7, 0x69, 0x45, 0xdb, 0x46, 0xb4, 0xd6, 0x4f, 0x38, 0x50, 0x0d, 0x67, 0xd2, + 0x63, 0x12, 0x67, 0xb1, 0x52, 0xd7, 0x66, 0xb7, 0x67, 0x15, 0x8e, 0xcd, 0xca, 0xdf, 0x1f, 0x1f, + 0xc1, 0xd3, 0x2c, 0x0a, 0x41, 0xa8, 0x82, 0xba, 0xc2, 0xf8, 0xef, 0xd6, 0xf4, 0x32, 0x9e, 0x56, + 0xf4, 0x92, 0xda, 0x95, 0x39, 0xac, 0x82, 0x48, 0x6c, 0xc5, 0xb6, 0x69, 0xa4, 0xb1, 0xf5, 0xf5, + 0xae, 0xc0, 0xf3, 0x4a, 0x8b, 0xfb, 0x3e, 0x5c, 0x6f, 0x09, 0xc7, 0xd2, 0x02, 0x69, 0xc2, 0x02, + 0x6f, 0x61, 0x03, 0xf6, 0xd9, 0x85, 0xa1, 0xf0, 0x64, 0x54, 0x5b, 0x16, 0x69, 0x1d, 0xd1, 0x7a, + 0x21, 0x83, 0x70, 0x3d, 0x4b, 0x9a, 0xcf, 0xf8, 0x64, 0x6e, 0x5f, 0x12, 0x5d, 0xd8, 0xde, 0xf0, + 0xab, 0x8c, 0x4c, 0x55, 0xfd, 0xcf, 0x2d, 0x08, 0x9a, 0xc3, 0xea, 0x64, 0xed, 0xd4, 0x33, 0xf9, + 0xa5, 0x85, 0x73, 0xfd, 0x00, 0xe9, 0x20, 0xe3, 0x42, 0x59, 0x69, 0x91, 0xcb, 0x75, 0x4e, 0xf7, + 0x9c, 0x54, 0xb4, 0x1c, 0x29, 0x96, 0x2b, 0x5b, 0xd3, 0xb2, 0x6b, 0x69, 0x6b, 0x5a, 0xb1, 0x8e, + 0x64, 0x1f, 0x20, 0x5d, 0xf2, 0x63, 0xfe, 0x85, 0x5a, 0x43, 0xb0, 0x2c, 0xfc, 0xf3, 0xad, 0xea, + 0x3a, 0x79, 0x0c, 0x4b, 0xd1, 0x21, 0x7b, 0xf0, 0x3b, 0x75, 0xa9, 0xde, 0x9c, 0xcd, 0x93, 0x71, + 0xad, 0xa2, 0x2c, 0x6f, 0xae, 0xfc, 0xd3, 0xe6, 0x8e, 0xd5, 0xe0, 0x25, 0xb6, 0x7e, 0x29, 0x74, + 0x7b, 0x11, 0x2f, 0x54, 0xab, 0xaf, 0x85, 0x6e, 0xee, 0x01, 0x29, 0x34, 0x50, 0xc2, 0x76, 0x5e, + 0xe8, 0x10, 0x7a, 0xa5, 0xd5, 0xb8, 0x43, 0x5f, 0x58, 0x78, 0xa8, 0x2a, 0xbd, 0x80, 0x52, 0xe4, + 0xa9, 0xe3, 0x10, 0x35, 0xd4, 0xd7, 0x62, 0xc6, 0x53, 0xaa, 0xae, 0x6a, 0x06, 0x44, 0xd2, 0xfc, + 0x29, 0x0a, 0xc2, 0x9a, 0xe3, 0x2a, 0x87, 0x55, 0xe6, 0x3a, 0x9b, 0x14, 0xed, 0x0d, 0xb1, 0x6c, + 0x4d, 0xac, 0xf1, 0xdc, 0x12, 0x94, 0x9b, 0x5c, 0x52, 0x01, 0x34, 0x7e, 0xdd, 0xe5, 0xd7, 0x0c, + 0x0a, 0x6d, 0x17, 0xc0, 0x14, 0x4c, 0x9a, 0x9c, 0x3a, 0x34, 0x74, 0x96, 0x6e, 0xad, 0x46, 0x71, + 0xf4, 0x92, 0x28, 0xd4, 0x23, 0xc8, 0x46, 0x4b, 0x12, 0xf1, 0x99, 0x7c, 0x59, 0xd1, 0x4d, 0x5d, + 0x95, 0xf0, 0xaa, 0x7f, 0x7d, 0xc1, 0xe8, 0x26, 0xde, 0xe3, 0x94, 0x5f, 0x6a, 0x37, 0x02, 0x8c, + 0x89, 0xa4, 0x7a, 0x46, 0x8d, 0xfe, 0x9c, 0x21, 0x24, 0x8c, 0x9c, 0x35, 0x63, 0x19, 0x8d, 0x9c, + 0xde, 0x2a, 0x86, 0xb2, 0xd0, 0xc1, 0x32, 0x67, 0x5e, 0x0d, 0x15, 0x30, 0xef, 0x94, 0xb6, 0x99, + 0xe9, 0xe5, 0xa6, 0x4d, 0x66, 0x39, 0x97, 0x58, 0x62, 0x2e, 0x13, 0xcb, 0x90, 0x18, 0x86, 0xd8, + 0x54, 0x75, 0xe5, 0x5b, 0x06, 0x2b, 0xe6, 0x34, 0x86, 0x9e, 0xc4, 0x7c, 0x45, 0xea, 0x9c, 0x2a, + 0x2a, 0xfa, 0x30, 0xdb, 0x0c, 0xc6, 0xc4, 0x55, 0xfc, 0x24, 0x74, 0xd2, 0x0d, 0xda, 0x71, 0x74, + 0x2a, 0x29, 0x2f, 0xcd, 0xfc, 0x93, 0x73, 0x87, 0x5e, 0xed, 0x5d, 0x55, 0x6f, 0x2a, 0x44, 0x5e, + 0x80, 0xa3, 0x89, 0xa7, 0xde, 0xb6, 0xb2, 0x9c, 0xfd, 0x01, 0xa4, 0x74, 0x91, 0x0b, 0xa9, 0x58, + 0x97, 0x41, 0x12, 0xb0, 0x5b, 0x6d, 0xa4, 0x97, 0x6b, 0x4b, 0x56, 0x63, 0x0a, 0x96, 0x2f, 0x21, + 0xd8, 0x7f, 0x6e, 0x95, 0x0d, 0x2b, 0x95, 0x66, 0xb1, 0x75, 0xa6, 0x95, 0x7f, 0x67, 0xab, 0x4a, + 0xc1, 0x4c, 0xf2, 0x3b, 0x68, 0x6a, 0xff, 0x61, 0xf4, 0xab, 0xff, 0xda, 0x9a, 0xfe, 0x6b, 0x6b, + 0xfa, 0xaf, 0xad, 0xe9, 0x3f, 0xd6, 0xd6, 0x54, 0xdc, 0x4c, 0xee, 0x2a, 0x6d, 0xd5, 0x26, 0xad, + 0x76, 0x6e, 0x1f, 0xff, 0x29, 0xe3, 0x98, 0x4b, 0x58, 0x1d, 0x4c, 0x91, 0xd6, 0xb9, 0x8e, 0xaa, + 0xdd, 0xaa, 0xe8, 0x42, 0xdf, 0x5b, 0xa6, 0x58, 0xdc, 0xed, 0xde, 0x2a, 0xbd, 0x39, 0x75, 0xb3, + 0x6d, 0x4a, 0xdd, 0xdd, 0x09, 0x69, 0x12, 0x51, 0xfe, 0xc4, 0xac, 0x6f, 0x61, 0x67, 0x13, 0x3b, + 0x9c, 0x3f, 0xa4, 0x05, 0x62, 0x9f, 0x47, 0x2e, 0x18, 0xd4, 0x5d, 0xf8, 0xc7, 0xd6, 0xe5, 0xb8, + 0x80, 0x67, 0x4d, 0x00, 0x11, 0xd8, 0x4c, 0xf4, 0xfe, 0xa9, 0x4a, 0xee, 0xd6, 0xd7, 0xd6, 0xb3, + 0xf4, 0xed, 0xe4, 0xdb, 0xe6, 0x12, 0xb4, 0x20, 0x0f, 0xf8, 0xfd, 0xb1, 0x02, 0x13, 0xeb, 0xef, + 0x85, 0x14, 0x0e, 0xe8, 0xff, 0xfd, 0x90, 0x12, 0xcd, 0xee, 0x89, 0x13, 0xad, 0x80, 0xb1, 0xfa, + 0xa5, 0x8f, 0x90, 0xbe, 0x60, 0xc1, 0x21, 0x9e, 0xd6, 0x1c, 0x7d, 0xb9, 0x57, 0xb6, 0x10, 0x89, + 0x72, 0x9f, 0x3a, 0x75, 0x73, 0xa0, 0xd4, 0xbb, 0x1f, 0x22, 0x17, 0xee, 0x15, 0x5b, 0xa2, 0x55, + 0x72, 0x17, 0x3e, 0x2b, 0xbe, 0xa5, 0xd1, 0x61, 0xd6, 0x7f, 0xc2, 0x64, 0xd5, 0x59, 0xe0, 0x83, + 0xd1, 0x2b, 0x70, 0x2b, 0x11, 0x9c, 0x1f, 0xe0, 0x7d, 0x3d, 0xf1, 0xd8, 0x2a, 0x1d, 0x92, 0x44, + 0xc5, 0x39, 0x77, 0x59, 0x18, 0x0b, 0x42, 0x58, 0xa9, 0x23, 0x36, 0xd7, 0x8b, 0x9f, 0x72, 0xd5, + 0xc9, 0xde, 0x48, 0xea, 0x4a, 0x52, 0xf1, 0x5a, 0xd4, 0xff, 0xc9, 0x95, 0x73, 0xdb, 0xeb, 0x03, + 0xc7, 0xb1, 0x9d, 0x12, 0x20, 0xb3, 0xe9, 0x94, 0xe3, 0xb6, 0x0d, 0xea, 0xc3, 0x85, 0x7b, 0xf9, + 0x11, 0x76, 0xa8, 0x77, 0x1c, 0xaf, 0xd7, 0xc4, 0xa1, 0x31, 0x4e, 0x6e, 0x09, 0x50, 0xbd, 0x5e, + 0x38, 0x83, 0xbf, 0xf0, 0x39, 0xfc, 0x83, 0x61, 0xe3, 0x50, 0x8c, 0x7f, 0x6c, 0x39, 0x4d, 0x67, + 0xeb, 0x82, 0x18, 0xd4, 0x85, 0x3e, 0x78, 0x27, 0xc4, 0x5e, 0x02, 0x19, 0x7a, 0xdf, 0xb9, 0x94, + 0x4d, 0x46, 0x82, 0x01, 0x99, 0xef, 0x7d, 0xf1, 0x0c, 0x37, 0xcb, 0x34, 0x83, 0x84, 0xff, 0xd6, + 0x2e, 0xb3, 0x56, 0x94, 0xe9, 0x02, 0x31, 0xb6, 0xe0, 0x3c, 0xc4, 0x25, 0xae, 0x6e, 0x69, 0x74, + 0x97, 0x2e, 0x7a, 0xa1, 0x0f, 0x86, 0x2d, 0x9e, 0xad, 0xeb, 0x53, 0x8d, 0x0f, 0xf4, 0x1d, 0x22, + 0xdf, 0xa5, 0x29, 0xb2, 0xb1, 0xa1, 0xff, 0xd1, 0x87, 0x7a, 0x54, 0xa6, 0xec, 0xc7, 0x00, 0x6f, + 0x9f, 0x78, 0x8a, 0xc8, 0x34, 0xb9, 0x21, 0x86, 0xf3, 0x36, 0x55, 0xa2, 0x1a, 0x9f, 0xe1, 0xaf, + 0x56, 0xa3, 0x56, 0x5c, 0x5c, 0x3a, 0x2c, 0x7d, 0xa7, 0x31, 0x33, 0x72, 0x30, 0x52, 0xdb, 0x67, + 0x31, 0x3f, 0x4d, 0xe5, 0x47, 0x73, 0x9c, 0xcd, 0x1e, 0xe2, 0xdc, 0xd1, 0xbc, 0x80, 0x4f, 0xdb, + 0x70, 0x56, 0xa0, 0xe0, 0x5a, 0xdb, 0x1c, 0x7b, 0x49, 0x8d, 0x47, 0x9d, 0x15, 0x1e, 0x46, 0x73, + 0x12, 0x9e, 0xb3, 0xe2, 0x06, 0xd5, 0xc8, 0xda, 0x8c, 0x2e, 0xf4, 0xa3, 0x68, 0xe2, 0x7b, 0xa1, + 0xd5, 0x3c, 0xde, 0x2c, 0x2d, 0x6e, 0x24, 0x8c, 0xdb, 0x6c, 0x02, 0x25, 0x5c, 0x9e, 0xa6, 0x08, + 0xe7, 0xd2, 0xe7, 0x7e, 0x5c, 0xc3, 0x48, 0x73, 0x68, 0xf0, 0x3b, 0xd7, 0xe8, 0xad, 0xea, 0x91, + 0x8d, 0x6d, 0xe2, 0x2e, 0xb0, 0x51, 0x39, 0x25, 0xf7, 0x19, 0x8e, 0x84, 0x7a, 0x96, 0xa6, 0xb1, + 0x8c, 0xcc, 0xa2, 0x52, 0x0f, 0x2f, 0x69, 0xfe, 0x6c, 0xff, 0x69, 0x99, 0x53, 0x7d, 0x16, 0x98, + 0xc3, 0x2e, 0x11, 0x2c, 0xd7, 0x14, 0x79, 0xbb, 0x39, 0xf5, 0x66, 0xb5, 0xda, 0x07, 0x2c, 0x63, + 0x57, 0xae, 0x86, 0xfe, 0xc8, 0x12, 0xf9, 0x8f, 0xea, 0x0f, 0xb7, 0x78, 0x79, 0x77, 0xb0, 0xf9, + 0x87, 0x5b, 0x7e, 0x7f, 0xb7, 0xf9, 0xa3, 0xae, 0x22, 0x42, 0x88, 0xb3, 0xe0, 0xe4, 0x72, 0xcc, + 0x4e, 0x0d, 0xca, 0x38, 0x9e, 0x70, 0x20, 0xcc, 0x92, 0x13, 0x76, 0x14, 0xd4, 0xf9, 0xc0, 0x59, + 0x31, 0xc9, 0x06, 0xc5, 0x75, 0x56, 0x48, 0xc4, 0x06, 0x38, 0xdf, 0x0f, 0xa5, 0x3d, 0x3e, 0xf0, + 0x73, 0xc1, 0xf2, 0x54, 0x58, 0xb9, 0x89, 0x3f, 0xc0, 0xba, 0x35, 0xde, 0xd0, 0xc5, 0xc5, 0x8a, + 0xeb, 0x11, 0xee, 0xe3, 0x83, 0xa4, 0x50, 0xb2, 0x28, 0x4c, 0x24, 0x3a, 0x5a, 0x6a, 0x40, 0xea, + 0x96, 0x37, 0x4b, 0x88, 0x6b, 0x59, 0x25, 0xed, 0x1e, 0xfd, 0x68, 0x5f, 0xc2, 0xa0, 0x6b, 0x99, + 0x9b, 0x53, 0xf2, 0xbb, 0x30, 0x90, 0xbb, 0x8d, 0xc4, 0x6d, 0x5c, 0x03, 0xab, 0xdb, 0xaf, 0x70, + 0xcd, 0xc9, 0xdb, 0xaa, 0x9b, 0xfb, 0x60, 0xf8, 0x2a, 0xa0, 0xc3, 0x3f, 0xdc, 0x22, 0x97, 0x04, + 0xbb, 0xa9, 0xdd, 0xf1, 0x9d, 0x3d, 0x4f, 0x12, 0x24, 0xe5, 0x2c, 0x35, 0x3a, 0x18, 0xfb, 0x97, + 0x71, 0x14, 0x6e, 0x1e, 0x92, 0x34, 0xb8, 0xf7, 0xfc, 0xc5, 0x93, 0x16, 0x0a, 0xe9, 0x4b, 0x2e, + 0xaa, 0x3a, 0x89, 0x1b, 0x25, 0xcc, 0xa5, 0x43, 0x3f, 0xf6, 0x6c, 0xbc, 0xf1, 0x15, 0x14, 0x07, + 0x3c, 0xd4, 0xb2, 0x59, 0xd2, 0xae, 0x9c, 0x61, 0x0f, 0xca, 0x08, 0x75, 0xd0, 0x38, 0x94, 0x64, + 0xae, 0x91, 0x25, 0xc5, 0x6e, 0x22, 0x19, 0xb9, 0xd6, 0xcc, 0x87, 0xd4, 0x60, 0xf5, 0xb7, 0x30, + 0x23, 0xcc, 0x77, 0x9c, 0xc2, 0xf7, 0xa5, 0xf3, 0xc0, 0x65, 0x1b, 0x1c, 0x2c, 0xba, 0x79, 0xc8, + 0xcd, 0x9a, 0x3e, 0xa9, 0x02, 0xea, 0xfa, 0xde, 0x10, 0xf1, 0xb2, 0xf8, 0xb7, 0x81, 0x62, 0x9b, + 0x87, 0xaf, 0x8f, 0x7e, 0x78, 0x55, 0xc0, 0x5c, 0x26, 0x6e, 0x32, 0xfc, 0xd2, 0xb5, 0x40, 0xa3, + 0x89, 0x7f, 0xdd, 0x3b, 0xf7, 0x66, 0x72, 0x1d, 0x57, 0xcf, 0x9b, 0x10, 0xcb, 0x6e, 0x04, 0xa9, + 0x3f, 0x4d, 0xba, 0x92, 0x88, 0x68, 0xf3, 0xd0, 0x32, 0xd0, 0x4a, 0xd3, 0xb8, 0x6d, 0x83, 0x7a, + 0x23, 0xed, 0x15, 0x6e, 0x79, 0x1a, 0x79, 0xd3, 0x60, 0x72, 0xd3, 0x45, 0x56, 0x1b, 0xce, 0x80, + 0x65, 0x5d, 0xc3, 0xc1, 0x1d, 0xb2, 0x41, 0xad, 0xbc, 0x43, 0x46, 0x03, 0xd5, 0x37, 0x64, 0x21, + 0x7f, 0x71, 0x17, 0x81, 0x24, 0x16, 0x3d, 0x9a, 0xd0, 0x7c, 0xf1, 0xb2, 0x3d, 0x8d, 0x83, 0x29, + 0x6e, 0x67, 0x51, 0x4c, 0x62, 0x07, 0x9b, 0xdf, 0x56, 0xe5, 0x8d, 0xe0, 0xb4, 0xa9, 0x68, 0x91, + 0x00, 0x74, 0x15, 0x12, 0xf5, 0x29, 0xef, 0x92, 0xbe, 0xe2, 0x16, 0xbb, 0xff, 0xd6, 0x69, 0xee, + 0x24, 0x58, 0x87, 0x38, 0x6a, 0x98, 0xc0, 0x07, 0x6b, 0xc2, 0x59, 0xae, 0x72, 0xf7, 0xd5, 0x96, + 0xed, 0xb3, 0x6a, 0xb2, 0x27, 0xb9, 0x4a, 0xa7, 0x8d, 0xe6, 0x10, 0xf0, 0xa9, 0x76, 0xc3, 0x92, + 0xf0, 0xf3, 0xe6, 0xe6, 0xe1, 0x0b, 0x9d, 0x3e, 0x47, 0xb2, 0x1f, 0x00, 0x40, 0x52, 0xbe, 0x8c, + 0xc6, 0x5c, 0x19, 0xf3, 0x63, 0x76, 0x8a, 0x4c, 0x74, 0x59, 0x30, 0x83, 0x03, 0xcd, 0x99, 0x76, + 0xbe, 0x51, 0x3c, 0x7a, 0xc2, 0x7e, 0x05, 0xb5, 0x90, 0x68, 0x17, 0x1e, 0x9f, 0xf9, 0x1e, 0x0c, + 0x99, 0x8e, 0x77, 0x33, 0x5c, 0xb8, 0x90, 0xdf, 0x56, 0x42, 0xec, 0x1f, 0xbe, 0x6f, 0x41, 0x88, + 0xb3, 0xaf, 0x02, 0x69, 0xf3, 0x3e, 0x62, 0x17, 0x65, 0x76, 0x5d, 0x2a, 0x34, 0x65, 0xe1, 0xc3, + 0xbe, 0xe6, 0x84, 0x4b, 0x3d, 0x85, 0x57, 0xb5, 0xa7, 0x93, 0x79, 0x42, 0x5a, 0xd2, 0x28, 0x38, + 0x33, 0x09, 0xc3, 0x9d, 0x12, 0x9c, 0x11, 0x1f, 0x91, 0x2c, 0x6e, 0xc3, 0xa5, 0x62, 0x71, 0x74, + 0x75, 0x4f, 0xee, 0xa7, 0x50, 0xb6, 0x7a, 0xb5, 0x59, 0xdf, 0xb1, 0xbc, 0xf5, 0x87, 0x06, 0x89, + 0x3b, 0xfe, 0x4d, 0xa9, 0x3d, 0x89, 0xcd, 0x3e, 0x50, 0x99, 0x14, 0xb0, 0xc6, 0xe3, 0x3e, 0x9b, + 0x42, 0x52, 0xf8, 0x9e, 0xa1, 0x84, 0xfa, 0xfe, 0xed, 0xd1, 0x3f, 0x67, 0x19, 0x2e, 0x93, 0x62, + 0xa1, 0x2e, 0xe0, 0x36, 0x69, 0xd9, 0x05, 0xd4, 0xf9, 0x26, 0xa9, 0x19, 0x33, 0xa8, 0x26, 0xcd, + 0xd8, 0xe7, 0x4b, 0xfc, 0x6a, 0xad, 0xb3, 0xd6, 0xb9, 0xeb, 0x28, 0xa7, 0x8c, 0x04, 0x5e, 0xdb, + 0x1c, 0xc3, 0x0e, 0xcf, 0x15, 0x4c, 0x00, 0x7a, 0xc6, 0xb9, 0xf1, 0xd0, 0x6e, 0xbe, 0xf4, 0x59, + 0xbf, 0x94, 0x47, 0x13, 0x30, 0x59, 0x05, 0xea, 0x14, 0x97, 0x33, 0x56, 0x41, 0x02, 0xe3, 0x60, + 0x18, 0xc7, 0xaf, 0x4e, 0x4e, 0x9f, 0x1d, 0x9f, 0xe6, 0xb5, 0xd9, 0x25, 0x8c, 0xa3, 0x9e, 0xb3, + 0xfd, 0x4b, 0xd3, 0xd8, 0x28, 0xcd, 0x65, 0x15, 0x27, 0xa7, 0x3e, 0x95, 0x15, 0xff, 0xb1, 0x78, + 0xe9, 0x99, 0x6c, 0x14, 0xc4, 0xb3, 0xed, 0xeb, 0xcb, 0x88, 0xed, 0x0f, 0x2e, 0xfa, 0xd1, 0xf5, + 0xa6, 0x82, 0x5a, 0xde, 0x20, 0x2c, 0x61, 0x63, 0xa7, 0x3f, 0x77, 0x9b, 0x8a, 0x37, 0xf8, 0xa7, + 0x0e, 0x17, 0xe1, 0x10, 0x5b, 0xe7, 0xce, 0xba, 0xc4, 0x8c, 0xa7, 0x52, 0x2e, 0xa3, 0xa1, 0xfd, + 0x57, 0xea, 0x38, 0x2e, 0x6f, 0x55, 0xba, 0x06, 0x6e, 0x36, 0xb3, 0xf9, 0xa5, 0x74, 0xa0, 0xc1, + 0x89, 0x92, 0xb1, 0x75, 0x68, 0x3e, 0x29, 0x77, 0x9f, 0xfd, 0x98, 0x0d, 0x4d, 0x8b, 0xa4, 0xd6, + 0x08, 0x59, 0xb2, 0xb3, 0x47, 0x68, 0x91, 0x0c, 0x66, 0x06, 0x44, 0x4c, 0x05, 0x0b, 0x51, 0x43, + 0x90, 0x93, 0x8d, 0xa3, 0x20, 0x5e, 0xbc, 0xe6, 0xc2, 0x75, 0x42, 0xf6, 0xe2, 0x5b, 0x78, 0xc4, + 0xc1, 0xb7, 0xb1, 0x04, 0x3f, 0x9a, 0xb1, 0x29, 0x2b, 0x97, 0x35, 0x59, 0x28, 0x8a, 0xca, 0x07, + 0x7e, 0xba, 0x33, 0x7d, 0x5e, 0xc3, 0x0c, 0xef, 0xa9, 0xfc, 0xf9, 0x10, 0x7d, 0xfc, 0xf5, 0xd7, + 0xa8, 0x1b, 0xd9, 0xc7, 0x6c, 0x5a, 0xf0, 0xfa, 0xf1, 0x89, 0xbe, 0x49, 0x88, 0x45, 0x28, 0xa0, + 0x3c, 0x62, 0x84, 0x47, 0x34, 0x0c, 0x7d, 0x26, 0x89, 0x35, 0xf9, 0xd4, 0x91, 0xa4, 0x09, 0x1a, + 0xfb, 0xb4, 0x95, 0x53, 0x33, 0xb4, 0x89, 0x4b, 0xe5, 0x9c, 0x6f, 0xc1, 0xf9, 0xd6, 0x12, 0xbf, + 0x8a, 0x3d, 0x1b, 0x44, 0x3e, 0x92, 0xa8, 0x1f, 0xa8, 0x25, 0x52, 0x2b, 0xe8, 0x8f, 0x84, 0x8b, + 0xc4, 0x27, 0x51, 0x95, 0x6f, 0xa4, 0x6b, 0x72, 0xa7, 0xc4, 0x66, 0x92, 0x3f, 0xe7, 0xb4, 0x67, + 0x53, 0x98, 0xbe, 0x1d, 0x71, 0x91, 0x78, 0xd6, 0x11, 0xca, 0x1f, 0x6e, 0xa5, 0x5f, 0x77, 0x44, + 0x25, 0x34, 0x6e, 0x42, 0x35, 0x8d, 0x4b, 0xa0, 0xad, 0xa4, 0x05, 0x2d, 0x26, 0x2f, 0x52, 0x83, + 0x11, 0x7b, 0x4b, 0x82, 0x31, 0xf3, 0x44, 0x4e, 0xaa, 0x49, 0x1b, 0x67, 0x78, 0xb3, 0x69, 0x99, + 0x80, 0xf2, 0x51, 0xd8, 0x2b, 0x42, 0xb0, 0x42, 0xe3, 0x60, 0x80, 0x77, 0x15, 0x43, 0xcb, 0xe6, + 0x8c, 0x7e, 0xdc, 0x63, 0xa4, 0x8c, 0xdb, 0xaf, 0x91, 0x24, 0xde, 0xc6, 0x2e, 0x0d, 0x7b, 0xd5, + 0x30, 0xa1, 0x20, 0x54, 0xaf, 0xe9, 0xca, 0xbe, 0x96, 0x06, 0xfd, 0xb9, 0x7a, 0x5d, 0xa2, 0x88, + 0xaa, 0x3e, 0xaf, 0xed, 0xa3, 0x5c, 0xa0, 0xfa, 0x9b, 0xfb, 0x63, 0x75, 0xa3, 0xd0, 0x0b, 0xf3, + 0xa3, 0xd5, 0x52, 0xdf, 0xc4, 0x3e, 0x67, 0x27, 0x52, 0xb5, 0xa1, 0xe4, 0x9b, 0x1d, 0x93, 0x22, + 0x89, 0x9c, 0x25, 0x37, 0x46, 0x2b, 0xe5, 0x9c, 0xb9, 0x9c, 0xa5, 0x9e, 0x16, 0x22, 0xb2, 0x3b, + 0x20, 0x51, 0x4a, 0x32, 0x9f, 0xe1, 0xa7, 0x3f, 0x44, 0x2e, 0x9b, 0x1c, 0x1a, 0xc7, 0x32, 0xeb, + 0xd0, 0xc0, 0xaf, 0x67, 0x49, 0x9e, 0x39, 0xd4, 0xd5, 0x47, 0x3c, 0xa4, 0x54, 0x72, 0x2a, 0xfb, + 0x2c, 0xe5, 0xe8, 0xb3, 0xbf, 0x3c, 0xa7, 0x4d, 0x3c, 0x9a, 0x35, 0xd5, 0x3f, 0xf9, 0xbe, 0xe4, + 0x63, 0xcc, 0xc1, 0xe9, 0xfb, 0x6b, 0xb2, 0x63, 0x1b, 0xb9, 0x35, 0x95, 0xd3, 0x42, 0x4e, 0xbc, + 0x10, 0x39, 0x9e, 0x6e, 0x54, 0x4a, 0x9c, 0x3c, 0xc5, 0x65, 0x3b, 0xb8, 0xed, 0x37, 0x41, 0xca, + 0x8a, 0x6f, 0xff, 0x22, 0x79, 0xf1, 0x70, 0xb9, 0x54, 0x9c, 0x03, 0xc3, 0x1e, 0x83, 0xc4, 0x51, + 0x3a, 0x8b, 0xa6, 0xa8, 0x4f, 0x72, 0xd1, 0x49, 0x61, 0xd3, 0xb1, 0x07, 0x57, 0x21, 0x3b, 0xb0, + 0xdf, 0x68, 0xf9, 0x65, 0xd3, 0xaa, 0x72, 0x90, 0xf9, 0xf5, 0xe4, 0xdb, 0x8e, 0x05, 0xb3, 0x7e, + 0x9b, 0xcd, 0x39, 0xff, 0xcd, 0xf7, 0xd3, 0x27, 0x35, 0x7e, 0xf1, 0xab, 0x2c, 0xe8, 0xfa, 0xdf, + 0xfa, 0x2d, 0x57, 0x39, 0x4f, 0xfe, 0xd0, 0xc9, 0x52, 0xe6, 0x3a, 0x6c, 0x07, 0xb2, 0xf6, 0x38, + 0x8c, 0x9b, 0x38, 0xb9, 0xb9, 0x0f, 0x8d, 0xbb, 0xf2, 0xeb, 0xaf, 0x8e, 0xb5, 0x25, 0x97, 0xda, + 0xd6, 0x35, 0x9c, 0xb7, 0x48, 0x2c, 0xcc, 0xc9, 0x30, 0x39, 0xff, 0x03, 0x67, 0x96, 0x08, 0x12, + 0x33, 0xcf, 0x4d, 0xb6, 0x46, 0x51, 0xd1, 0xa5, 0x60, 0x8a, 0xc2, 0xcb, 0xd6, 0x01, 0xfb, 0x96, + 0x41, 0x4a, 0x09, 0xbd, 0x92, 0x04, 0x73, 0x1f, 0x7d, 0xc1, 0x08, 0xc1, 0x7f, 0xb8, 0xa5, 0x36, + 0x73, 0x7c, 0x6c, 0x42, 0xbe, 0xf8, 0xd3, 0xcf, 0xf3, 0x28, 0xed, 0x39, 0xf5, 0x3b, 0x70, 0x3c, + 0x2e, 0x7e, 0x57, 0xa5, 0x50, 0xfc, 0xe1, 0x36, 0x17, 0x3b, 0xb8, 0x68, 0x26, 0x3a, 0xdc, 0xe9, + 0x3d, 0xf3, 0x0f, 0xb7, 0xd6, 0x08, 0x9e, 0x3a, 0xcb, 0xb5, 0x92, 0xd0, 0xdb, 0x3c, 0x7c, 0xdb, + 0x7a, 0xa6, 0xab, 0xf1, 0x1e, 0x92, 0x6b, 0x74, 0x87, 0x9a, 0x6d, 0xdc, 0x15, 0x95, 0xb8, 0x0a, + 0x29, 0x98, 0x46, 0x5f, 0xb7, 0x8d, 0x41, 0x5a, 0xb5, 0xb6, 0x8b, 0x10, 0x84, 0x7a, 0x6e, 0xba, + 0x20, 0x12, 0x7d, 0x89, 0x05, 0xcf, 0xf9, 0x6a, 0x43, 0x22, 0xe1, 0x24, 0xe9, 0x6a, 0xed, 0x9e, + 0x97, 0x63, 0x46, 0x74, 0xf9, 0xca, 0xf4, 0x70, 0x85, 0x5f, 0x0c, 0x33, 0x84, 0xfa, 0x71, 0x1e, + 0xfc, 0x98, 0xa5, 0x3e, 0x17, 0x68, 0xb8, 0x7e, 0x4e, 0xaf, 0x37, 0x9c, 0x22, 0x04, 0x83, 0x3c, + 0x82, 0x19, 0x82, 0xaa, 0x24, 0x1e, 0xd0, 0x76, 0xa3, 0xec, 0x62, 0x0c, 0x9c, 0xaa, 0x7e, 0x13, + 0x47, 0xf3, 0x19, 0x67, 0xb3, 0x14, 0x40, 0xf3, 0xa0, 0x89, 0x8c, 0xe6, 0x33, 0xb1, 0x0c, 0x6a, + 0x9d, 0x59, 0xce, 0x51, 0x75, 0xa6, 0x12, 0xaa, 0x74, 0x3a, 0xf6, 0x13, 0x6d, 0xc9, 0x4a, 0xd4, + 0xd4, 0xbb, 0x41, 0xfa, 0x18, 0x7d, 0x76, 0x2b, 0x99, 0xe0, 0x49, 0xd5, 0x10, 0x70, 0x5e, 0x9f, + 0x3d, 0x66, 0x0b, 0x37, 0xbd, 0x89, 0xe9, 0x31, 0x4f, 0xcd, 0xc4, 0x37, 0x43, 0xb3, 0x6f, 0xed, + 0x64, 0xd4, 0xd0, 0xf9, 0x5e, 0x90, 0x5c, 0x36, 0x0f, 0x2a, 0xd9, 0xd0, 0x8b, 0x1a, 0xd1, 0x1c, + 0x80, 0x64, 0x69, 0x02, 0xd4, 0x9b, 0x67, 0x43, 0x49, 0x7e, 0x61, 0x92, 0x16, 0xcd, 0x27, 0xc6, + 0xca, 0x26, 0x49, 0x57, 0x08, 0x27, 0xd0, 0xf3, 0x24, 0x45, 0x1d, 0xee, 0x27, 0x06, 0x0f, 0xb8, + 0x2d, 0x38, 0x95, 0x03, 0xf1, 0xcc, 0x02, 0xac, 0x0b, 0x08, 0x8b, 0xca, 0x4c, 0x52, 0xb0, 0x83, + 0xd8, 0x5a, 0x0e, 0xeb, 0x38, 0xa2, 0xe1, 0x64, 0x90, 0x38, 0xbc, 0xe6, 0xa2, 0xe0, 0x0f, 0xcd, + 0x58, 0x35, 0x37, 0x2f, 0x16, 0x61, 0x7f, 0x60, 0x1d, 0x83, 0xe6, 0xbc, 0xca, 0x48, 0x6a, 0xf3, + 0x9f, 0xba, 0x7d, 0x40, 0xf9, 0x05, 0x7c, 0x37, 0x69, 0xf3, 0xc6, 0xdf, 0xe6, 0x3c, 0xb0, 0x95, + 0xa7, 0xac, 0x0c, 0x84, 0xfa, 0x80, 0xb4, 0x52, 0x52, 0xcd, 0x93, 0x9a, 0x73, 0xe6, 0xd8, 0x2a, + 0x96, 0xed, 0x91, 0x45, 0xd8, 0x4d, 0x2e, 0x88, 0x5d, 0x24, 0xa1, 0x77, 0xe1, 0x9f, 0x31, 0x6f, + 0x1d, 0x12, 0x0d, 0x50, 0xf5, 0x1c, 0x56, 0x36, 0xb6, 0xdc, 0x58, 0xb8, 0x0c, 0x96, 0xc9, 0x37, + 0x1c, 0xe0, 0xaa, 0x17, 0x4d, 0x8f, 0x9a, 0x7c, 0x72, 0x1e, 0xfd, 0xf6, 0xdd, 0xe9, 0xab, 0x6e, + 0x81, 0x03, 0x6b, 0x82, 0x42, 0x7e, 0x20, 0xfa, 0xc8, 0x3d, 0x02, 0x69, 0xc2, 0x23, 0x5a, 0x12, + 0xd6, 0xe3, 0xba, 0x27, 0x73, 0xbb, 0x08, 0x81, 0xc4, 0xb2, 0xc9, 0xe1, 0x65, 0x37, 0xe3, 0xdd, + 0x98, 0x95, 0x74, 0x4e, 0xfb, 0x9d, 0x3f, 0x6c, 0xc8, 0x8e, 0xa7, 0xf9, 0x6a, 0x7d, 0xd5, 0xc6, + 0xe2, 0x96, 0x76, 0x37, 0xb4, 0x75, 0x52, 0xb8, 0xdf, 0x44, 0xd6, 0x46, 0x9e, 0x24, 0x1b, 0xfe, + 0x0d, 0xa4, 0x9a, 0xc8, 0x45, 0x0f, 0xb4, 0x9e, 0xb0, 0xc5, 0xba, 0xd9, 0xde, 0x5a, 0xdc, 0x6c, + 0xce, 0x65, 0x8b, 0x69, 0x66, 0x4b, 0x0c, 0x92, 0xd7, 0x1b, 0xa6, 0xd7, 0x4c, 0xe8, 0xaa, 0x09, + 0x99, 0x7c, 0xe0, 0x48, 0x8d, 0xfc, 0x37, 0x95, 0xfc, 0xf0, 0xb1, 0x2e, 0x87, 0xa3, 0x39, 0xb5, + 0x14, 0x8e, 0xc5, 0x2d, 0x72, 0xe2, 0x7a, 0xae, 0xd2, 0x14, 0x54, 0x45, 0x54, 0x02, 0x39, 0x27, + 0x27, 0x1a, 0xf0, 0xd1, 0x28, 0x5f, 0xfb, 0x21, 0x9f, 0x26, 0x33, 0x8e, 0x02, 0xb9, 0x42, 0xcb, + 0x18, 0xec, 0x84, 0x91, 0x6c, 0x1e, 0x9d, 0xbc, 0xdf, 0x74, 0xd5, 0x26, 0xc7, 0xd9, 0x6f, 0xd6, + 0x5d, 0x25, 0x9c, 0x2e, 0x07, 0xc6, 0xcc, 0x83, 0x79, 0x16, 0x2e, 0xb2, 0xe0, 0x94, 0x9a, 0xd6, + 0xe5, 0x16, 0x9c, 0x9a, 0xcd, 0x2c, 0x59, 0x2f, 0x6e, 0x10, 0xa9, 0x4d, 0xf8, 0xee, 0x09, 0xce, + 0x37, 0xdd, 0xf7, 0x39, 0x73, 0xa2, 0x2c, 0x53, 0x0d, 0xef, 0xb5, 0xcf, 0x59, 0x26, 0x0b, 0x8b, + 0x9b, 0xbd, 0xe5, 0x03, 0xb9, 0x84, 0xdd, 0xa4, 0x6a, 0x1e, 0x47, 0xf0, 0x1e, 0x61, 0xbf, 0x10, + 0xc9, 0x02, 0x8d, 0x7c, 0x04, 0x7c, 0xf5, 0x50, 0x6a, 0x51, 0x8a, 0x5c, 0x90, 0x55, 0x10, 0x26, + 0xac, 0xbb, 0x51, 0xed, 0x60, 0x36, 0x4e, 0x61, 0x49, 0x6c, 0x43, 0x2e, 0xa1, 0xe1, 0x0d, 0x54, + 0x5f, 0xc1, 0xd8, 0xb4, 0xb6, 0x66, 0x31, 0x84, 0x42, 0x43, 0x72, 0x8d, 0x71, 0xcf, 0x56, 0x97, + 0xf2, 0x99, 0x19, 0x73, 0x06, 0x7e, 0x6c, 0x0d, 0x15, 0xb1, 0x7f, 0x06, 0xc5, 0x87, 0xaa, 0x59, + 0x34, 0x74, 0xd2, 0x9b, 0xf1, 0x8e, 0x53, 0xb7, 0xdc, 0x0f, 0x68, 0x35, 0x8e, 0x8b, 0x27, 0xc1, + 0x07, 0x9a, 0x5a, 0x0a, 0x2e, 0xbe, 0xd2, 0xaf, 0x31, 0xed, 0xde, 0xb8, 0xee, 0x28, 0xcd, 0xdb, + 0x28, 0xba, 0xf5, 0x3e, 0xc0, 0x1e, 0x69, 0x55, 0xa2, 0x15, 0x7e, 0xb1, 0xcc, 0x03, 0x52, 0xf8, + 0x13, 0x2a, 0xd9, 0x1e, 0xd6, 0xf7, 0x31, 0x17, 0x5b, 0x85, 0xd7, 0x5b, 0x8c, 0xed, 0xc2, 0xff, + 0x16, 0x46, 0x63, 0x31, 0x16, 0x33, 0x9e, 0xef, 0x63, 0x28, 0xfe, 0xfb, 0xff, 0xf9, 0xff, 0x3e, + 0xd4, 0x4a, 0xfc, 0xc9, 0x53, 0x72, 0xb7, 0x40, 0x6b, 0xc5, 0x4d, 0x45, 0x2f, 0xfc, 0x05, 0x17, + 0x96, 0x79, 0x90, 0x31, 0xa5, 0x05, 0xb5, 0x38, 0x8d, 0xa1, 0xb1, 0x13, 0x53, 0x30, 0xa2, 0x39, + 0xf8, 0x15, 0xa8, 0xce, 0x42, 0x3d, 0xc8, 0x5f, 0xac, 0x73, 0x55, 0x06, 0x3d, 0xd2, 0x9c, 0xcb, + 0x46, 0x3b, 0x8b, 0x84, 0xba, 0xaa, 0x26, 0x6d, 0x1c, 0x70, 0x60, 0x32, 0x10, 0x0e, 0x5d, 0x5b, + 0xb2, 0xe1, 0x17, 0x3e, 0xe6, 0x8a, 0x78, 0x8d, 0xba, 0x33, 0x0d, 0xc2, 0x5f, 0x7f, 0xe5, 0x30, + 0x3d, 0xc7, 0x29, 0x79, 0xa2, 0x2c, 0x31, 0x2b, 0x96, 0x3b, 0x81, 0xc3, 0x3b, 0x6f, 0xd2, 0x93, + 0x7d, 0xcf, 0xc7, 0xce, 0x13, 0xf1, 0xf1, 0x0b, 0xae, 0x2a, 0xbb, 0x2a, 0xa1, 0x21, 0x33, 0x2b, + 0x96, 0xed, 0x88, 0x6c, 0x9b, 0xea, 0x55, 0x99, 0x5c, 0x04, 0x6b, 0xf2, 0x93, 0x4a, 0xde, 0xd7, + 0xb2, 0x56, 0x84, 0xf4, 0xdb, 0x4c, 0x6b, 0x15, 0xb0, 0xd8, 0xb6, 0x76, 0x5f, 0xe3, 0x9a, 0x3d, + 0xbf, 0xb6, 0x75, 0xcd, 0xc2, 0xf5, 0xc2, 0xdc, 0x15, 0x78, 0xcf, 0xff, 0xae, 0x36, 0xb6, 0x8c, + 0xa1, 0x65, 0x16, 0x87, 0x7c, 0x9c, 0xa2, 0xac, 0x39, 0x15, 0x61, 0x14, 0xda, 0x12, 0x06, 0xea, + 0x14, 0xd3, 0x53, 0xf2, 0xeb, 0xaf, 0xd8, 0xb0, 0xd9, 0x1e, 0x76, 0x70, 0xf8, 0xc9, 0xd6, 0xac, + 0xc8, 0xb2, 0x65, 0x55, 0x19, 0xb0, 0x3e, 0x8b, 0xa5, 0xa9, 0x60, 0x39, 0xa8, 0x30, 0x35, 0xad, + 0x42, 0x49, 0x7e, 0xb0, 0x5b, 0x46, 0x89, 0x87, 0x4e, 0x29, 0x5a, 0xab, 0xe8, 0x88, 0xac, 0x5a, + 0xea, 0xcb, 0xd4, 0xbb, 0x36, 0xcf, 0xde, 0xf5, 0xdd, 0xa6, 0xb6, 0x3b, 0xf1, 0x0b, 0xfc, 0x24, + 0x85, 0x96, 0xd4, 0x1f, 0xe7, 0x6e, 0xf3, 0xc7, 0xea, 0x31, 0x56, 0xdb, 0xa1, 0x7e, 0x67, 0x1b, + 0x54, 0x69, 0xfc, 0xb7, 0x6b, 0x7b, 0xf6, 0x3b, 0x59, 0x74, 0xca, 0x7b, 0xed, 0x2a, 0x9b, 0x8e, + 0x16, 0xa5, 0xef, 0x6f, 0xd0, 0x61, 0x60, 0x92, 0x72, 0x29, 0x29, 0xcb, 0xd8, 0x5a, 0xb4, 0xae, + 0xad, 0x91, 0x89, 0x6d, 0x48, 0x95, 0x96, 0x20, 0x5b, 0x50, 0x46, 0xaa, 0x01, 0x39, 0x05, 0x49, + 0x94, 0xdc, 0x0c, 0x25, 0xd2, 0x98, 0xd1, 0x71, 0x73, 0xdb, 0x90, 0xe8, 0xb7, 0x32, 0x88, 0x06, + 0x52, 0x4b, 0x05, 0x23, 0xea, 0x97, 0x76, 0x8d, 0x53, 0x57, 0x7c, 0x27, 0x2b, 0xa4, 0x4f, 0xa2, + 0xb8, 0x73, 0x9f, 0x84, 0x00, 0x74, 0x5a, 0x1c, 0x48, 0xb6, 0x20, 0xc2, 0x92, 0x7a, 0x2f, 0xfc, + 0xaf, 0x59, 0xde, 0xfa, 0xca, 0xb6, 0x9f, 0x6a, 0xc3, 0x8e, 0xc5, 0xf1, 0x3e, 0xa7, 0x65, 0xc7, + 0x66, 0xb0, 0xda, 0xb4, 0x43, 0x6b, 0x40, 0x63, 0x41, 0xdb, 0x75, 0x96, 0x34, 0xfd, 0x60, 0xc3, + 0x4e, 0x16, 0xc2, 0xc2, 0xf5, 0x96, 0xdb, 0x5d, 0xca, 0xdb, 0xc6, 0xbd, 0x8e, 0xb8, 0x32, 0xc3, + 0x7d, 0xe9, 0x8c, 0xcb, 0x46, 0xef, 0x53, 0x7d, 0xb0, 0x95, 0x1b, 0x8e, 0xb0, 0xdb, 0x14, 0x8f, + 0x9c, 0x97, 0x9e, 0x82, 0x15, 0x3e, 0x3f, 0xd8, 0xc4, 0xf4, 0x1f, 0xd6, 0x96, 0x64, 0x8b, 0x7a, + 0x15, 0xc6, 0xa4, 0xe2, 0x52, 0x6f, 0xfd, 0x59, 0x92, 0x43, 0x4a, 0x39, 0x73, 0x3d, 0x01, 0xae, + 0x2d, 0xc0, 0xf2, 0xd4, 0xc9, 0x77, 0xf5, 0x1d, 0x44, 0x2c, 0x1e, 0xc2, 0xb3, 0xac, 0x21, 0xa5, + 0x59, 0xd1, 0xca, 0x16, 0xe7, 0x9f, 0x73, 0x9d, 0x0e, 0xca, 0xd6, 0x55, 0x34, 0xa7, 0x69, 0xb9, + 0xf1, 0xc2, 0x0b, 0x49, 0x12, 0x2d, 0x1c, 0x83, 0xaf, 0xcc, 0xcd, 0x2e, 0x1b, 0x84, 0xbe, 0x62, + 0x52, 0x4b, 0x48, 0xa8, 0x2a, 0x89, 0xa5, 0x05, 0xc1, 0x99, 0x3d, 0x4c, 0x51, 0xae, 0xbe, 0xcc, + 0xf0, 0x95, 0xf9, 0x8a, 0xae, 0x4c, 0x54, 0x92, 0x39, 0xa9, 0x20, 0xe4, 0x0b, 0x3e, 0x3d, 0xf5, + 0x26, 0x1f, 0xb6, 0x37, 0xb5, 0x47, 0x80, 0x32, 0xce, 0xad, 0xb9, 0xfb, 0xca, 0xc2, 0x77, 0x66, + 0x30, 0x4e, 0xef, 0x7e, 0xed, 0xc8, 0xfd, 0x5f, 0x49, 0x55, 0x3b, 0x70, 0x3e, 0x28, 0xfb, 0x14, + 0x15, 0xf8, 0x74, 0xd1, 0x3f, 0x6b, 0x89, 0x88, 0x69, 0xa5, 0x01, 0x2a, 0x2e, 0xa6, 0x72, 0x97, + 0x2c, 0x92, 0xaf, 0x5b, 0xb5, 0x92, 0x4b, 0xce, 0xde, 0x81, 0x28, 0xf3, 0xf2, 0xc9, 0x37, 0x4d, + 0x84, 0x25, 0x3b, 0xf0, 0x14, 0xe8, 0xe7, 0x24, 0x77, 0x78, 0xd3, 0x09, 0xcc, 0xbf, 0xe6, 0xed, + 0x40, 0xac, 0x52, 0xa6, 0x01, 0x5e, 0x51, 0x4f, 0xcb, 0x29, 0x61, 0x74, 0x05, 0x6d, 0x56, 0x2e, + 0x9e, 0x61, 0x14, 0x81, 0x89, 0xd7, 0xe1, 0x0a, 0x78, 0x26, 0x4b, 0x4d, 0x09, 0x24, 0xfe, 0x99, + 0xcf, 0x68, 0x77, 0xf4, 0x9f, 0xb3, 0xb3, 0x41, 0xb2, 0x90, 0xf9, 0xa8, 0xf4, 0xd5, 0xf2, 0x72, + 0x82, 0x97, 0x74, 0xb1, 0x17, 0xf0, 0x7a, 0x5b, 0x3d, 0xd9, 0x99, 0xe7, 0x06, 0xcd, 0xb2, 0x15, + 0xfd, 0x1e, 0x4a, 0xee, 0x8f, 0xd5, 0x75, 0xa5, 0xad, 0xc6, 0x00, 0x99, 0xbf, 0x16, 0xc2, 0x15, + 0x42, 0x04, 0x50, 0xb2, 0xcf, 0xbd, 0x14, 0xe3, 0xac, 0x4a, 0xe1, 0x61, 0x87, 0xc4, 0x38, 0xac, + 0xfe, 0xba, 0xf6, 0x31, 0x2f, 0xfa, 0x7a, 0x21, 0x0d, 0xf9, 0x8d, 0x6a, 0xa9, 0x63, 0x9d, 0x4b, + 0xbb, 0x85, 0x0b, 0x85, 0x38, 0xbc, 0x74, 0x55, 0x56, 0x29, 0xaa, 0x23, 0x64, 0x57, 0x44, 0x07, + 0x1c, 0x53, 0x0e, 0xee, 0x35, 0x72, 0x1e, 0x26, 0x3d, 0x2f, 0x26, 0x49, 0xd0, 0xef, 0x4b, 0x11, + 0x45, 0xdc, 0x4d, 0x38, 0x17, 0x34, 0x9b, 0xb2, 0x96, 0xb0, 0x4f, 0x45, 0x08, 0x95, 0x6c, 0xbb, + 0xec, 0x68, 0xaa, 0x0c, 0xee, 0x16, 0xfc, 0x3d, 0x3e, 0x50, 0x9d, 0xc2, 0x1c, 0x7d, 0x34, 0xc4, + 0xc8, 0x31, 0x34, 0x0f, 0x77, 0xec, 0x88, 0xab, 0xbd, 0x79, 0x69, 0x11, 0x3f, 0x75, 0xb6, 0x2a, + 0x1c, 0x77, 0x41, 0x91, 0x5b, 0xce, 0x41, 0xe5, 0x37, 0xf6, 0x32, 0xb4, 0x8f, 0x3a, 0x62, 0x89, + 0x90, 0xc9, 0xd8, 0xf1, 0xc2, 0x5a, 0xb3, 0x16, 0xb2, 0xee, 0xd4, 0x9a, 0x55, 0xb0, 0x32, 0xf8, + 0xc5, 0x5e, 0xe6, 0xeb, 0xd7, 0x8a, 0x76, 0x39, 0xbd, 0xd8, 0xda, 0x5a, 0x71, 0xaa, 0x28, 0x4e, + 0xc2, 0x04, 0x70, 0xcb, 0x21, 0x82, 0xdb, 0xa2, 0x11, 0xb1, 0x8b, 0xf0, 0x53, 0xe3, 0x23, 0x4c, + 0xc2, 0x84, 0xf6, 0x0c, 0xae, 0xe7, 0xae, 0xc1, 0x79, 0xa4, 0x38, 0x7d, 0xb2, 0xc1, 0x1b, 0xaf, + 0xd7, 0x3c, 0x3e, 0x6c, 0xa3, 0xb2, 0x99, 0x8a, 0xd0, 0xb0, 0x8d, 0x0a, 0x88, 0xb9, 0x6f, 0x2c, + 0xe1, 0x9a, 0x30, 0xad, 0xc1, 0xd0, 0x90, 0xf4, 0x29, 0x12, 0x75, 0x38, 0xba, 0xc8, 0xd7, 0x0c, + 0xbd, 0x96, 0xfb, 0xd5, 0x87, 0x16, 0xcd, 0x56, 0xd1, 0xa6, 0xd2, 0xeb, 0x41, 0xa8, 0xb3, 0x92, + 0x9f, 0x54, 0x84, 0x76, 0x99, 0x2c, 0x82, 0xb6, 0xd7, 0xfd, 0xea, 0x48, 0x22, 0xe3, 0x4b, 0xe6, + 0x18, 0x97, 0xee, 0x2f, 0xfc, 0x89, 0xed, 0x70, 0x5e, 0x8a, 0x0b, 0x5b, 0x42, 0xab, 0xb9, 0xcf, + 0x9e, 0x7d, 0x24, 0x80, 0x45, 0x18, 0x4b, 0xce, 0x1a, 0x2b, 0x0b, 0xcd, 0x42, 0x90, 0xc7, 0x10, + 0x4a, 0x40, 0x60, 0xac, 0xab, 0x4f, 0xd5, 0x8f, 0x7c, 0x7b, 0xcb, 0x1f, 0x6e, 0x87, 0xcd, 0x58, + 0xbc, 0xbf, 0x0e, 0x0f, 0xda, 0xb4, 0x12, 0x58, 0xe2, 0xb0, 0xde, 0x5a, 0x29, 0x8c, 0xee, 0xfe, + 0xf5, 0x7f, 0x29, 0x7d, 0xfd, 0x0a, 0x0a, 0xcc, 0xb4, 0xa3, 0x58, 0xa9, 0x9e, 0x79, 0x5d, 0xae, + 0x88, 0xcb, 0xa5, 0xf0, 0x9d, 0xfe, 0x2e, 0x56, 0x92, 0x97, 0xc5, 0x2a, 0x78, 0x8f, 0x2d, 0x76, + 0x02, 0x81, 0x89, 0x4a, 0x22, 0xb3, 0x3a, 0x3d, 0x11, 0x3b, 0xf9, 0xfb, 0xbf, 0xfc, 0xdf, 0x75, + 0xe7, 0xee, 0xc7, 0x0d, 0x63, 0x00, 0x72, 0xf8, 0x6c, 0x26, 0x95, 0x7b, 0x28, 0xe5, 0xb4, 0xa6, + 0x9c, 0xd7, 0x91, 0x98, 0xaa, 0x9d, 0x84, 0x92, 0x23, 0x10, 0x33, 0xe2, 0xac, 0x88, 0x85, 0x9c, + 0x87, 0xde, 0x25, 0x51, 0xa0, 0xc7, 0xbe, 0xc2, 0xaa, 0x2a, 0x20, 0xa5, 0xd2, 0x3b, 0x6f, 0x21, + 0xd6, 0xa0, 0xec, 0xa5, 0xf7, 0xfa, 0xd5, 0x0f, 0xaf, 0x5e, 0xab, 0x1a, 0xdf, 0x52, 0xa5, 0x6f, + 0x42, 0xd7, 0x57, 0x95, 0xba, 0xfa, 0x62, 0xfb, 0xf9, 0x2c, 0x46, 0x30, 0xa4, 0x5c, 0x02, 0xc2, + 0x97, 0x5e, 0xf0, 0x8d, 0xe6, 0xc1, 0x64, 0xd2, 0xfc, 0x5b, 0xf8, 0xb7, 0x90, 0x7d, 0xfa, 0xae, + 0xf8, 0x6a, 0x42, 0x71, 0xec, 0xab, 0xf6, 0xeb, 0xd3, 0x12, 0x98, 0x7d, 0xeb, 0x51, 0x92, 0x79, + 0xf2, 0x2d, 0x38, 0xf2, 0xc9, 0xf5, 0x09, 0xfa, 0xd6, 0x13, 0xdc, 0xc8, 0x24, 0x07, 0x32, 0xa5, + 0xa8, 0x88, 0x87, 0x11, 0x69, 0x2b, 0x43, 0xd0, 0x19, 0xfb, 0x06, 0xde, 0x87, 0x68, 0x65, 0x59, + 0xff, 0xc8, 0xc8, 0xcc, 0x6e, 0x58, 0xe8, 0xaa, 0x8c, 0x52, 0x2d, 0x5f, 0x45, 0x22, 0x10, 0xd7, + 0x22, 0x46, 0xdb, 0x73, 0x11, 0xe4, 0x06, 0x4a, 0xd0, 0x83, 0x13, 0x82, 0xf9, 0x51, 0x37, 0x6f, + 0xef, 0x12, 0xd5, 0x39, 0x3c, 0x3f, 0xf2, 0x62, 0xb1, 0xde, 0xac, 0xab, 0x98, 0x65, 0xf9, 0xcc, + 0x6b, 0x9a, 0x57, 0x52, 0xb5, 0xb0, 0x1b, 0x3c, 0xa8, 0xd1, 0x15, 0x35, 0xd7, 0xb6, 0x5a, 0x76, + 0xf3, 0x96, 0xb7, 0x95, 0x01, 0x2d, 0x56, 0xd6, 0xa6, 0xbb, 0xca, 0x90, 0xde, 0x17, 0xf6, 0x25, + 0x77, 0x26, 0x13, 0xde, 0xd6, 0xf2, 0xc0, 0xde, 0xd2, 0x5a, 0x49, 0x88, 0x56, 0x9f, 0x85, 0x43, + 0x2d, 0xad, 0x68, 0xe1, 0xc3, 0xf4, 0xc4, 0x96, 0x4a, 0x98, 0x0d, 0xeb, 0x36, 0x8f, 0xb3, 0xe9, + 0xcb, 0x49, 0x93, 0xe4, 0x08, 0x29, 0xb3, 0x7a, 0x18, 0x05, 0x39, 0x50, 0x27, 0xde, 0x28, 0x4a, + 0x3e, 0xd6, 0x6c, 0xe2, 0x30, 0x95, 0x00, 0xdb, 0xa8, 0x16, 0xef, 0xfd, 0xe2, 0x16, 0xcd, 0x89, + 0xfc, 0x6a, 0x26, 0xe5, 0x66, 0x19, 0xb5, 0x95, 0xbb, 0x47, 0x8e, 0x3e, 0x69, 0x3b, 0xbf, 0xd8, + 0xd1, 0xa9, 0xde, 0x5c, 0xb4, 0xc3, 0x89, 0xbe, 0x5c, 0xc1, 0xf4, 0xb5, 0xc0, 0x50, 0x8e, 0xa5, + 0x08, 0x6e, 0x68, 0xce, 0x5d, 0xfd, 0x11, 0x7d, 0xa3, 0xeb, 0x2c, 0x5d, 0xd6, 0x4f, 0xd5, 0x29, + 0x54, 0x3d, 0xdd, 0x85, 0x84, 0x1d, 0x04, 0x82, 0xb0, 0x31, 0x25, 0x91, 0x21, 0xbe, 0xd1, 0x63, + 0x35, 0xb5, 0xa1, 0x38, 0x89, 0xfd, 0x26, 0xe2, 0xc4, 0x25, 0x17, 0x3a, 0xd0, 0x67, 0xae, 0x2f, + 0x0a, 0xb3, 0xf9, 0x42, 0x71, 0xc2, 0xe4, 0x1a, 0xde, 0xaa, 0xce, 0x68, 0x31, 0x50, 0xe3, 0x25, + 0x93, 0xe1, 0x2a, 0x26, 0xd2, 0xd4, 0xce, 0xc4, 0x17, 0x2b, 0x98, 0x4c, 0x10, 0x56, 0xab, 0x1f, + 0x1c, 0xe6, 0x22, 0x85, 0x25, 0x0f, 0x5a, 0x39, 0xd5, 0x8e, 0xab, 0xd9, 0x93, 0xc9, 0x13, 0x67, + 0xbb, 0xd9, 0x8d, 0x90, 0x06, 0xee, 0xb8, 0x24, 0xc2, 0x15, 0x17, 0x1f, 0x9c, 0x79, 0x0b, 0x01, + 0x3e, 0x5c, 0xc3, 0xca, 0x04, 0x67, 0x03, 0xbc, 0x1f, 0x79, 0x95, 0x3c, 0xab, 0x56, 0xd1, 0x9b, + 0x71, 0x6a, 0xac, 0xa0, 0x3a, 0xf9, 0xaf, 0x8a, 0xf6, 0x6c, 0x81, 0xcb, 0x31, 0x24, 0x65, 0x48, + 0xcc, 0x96, 0x0d, 0xad, 0x8d, 0x30, 0x9b, 0xc9, 0x62, 0xce, 0xcb, 0x8a, 0x95, 0x9e, 0xc9, 0x78, + 0x59, 0xb6, 0xc7, 0x8d, 0x6a, 0x48, 0x76, 0x28, 0xe3, 0x72, 0x50, 0xc5, 0x74, 0xad, 0x3e, 0x64, + 0x27, 0xa4, 0x04, 0x85, 0xb4, 0x05, 0x82, 0x5a, 0xae, 0xd5, 0xa0, 0x44, 0x56, 0x5e, 0x2f, 0x98, + 0x9c, 0x22, 0xf4, 0x21, 0xd6, 0x68, 0x46, 0x9b, 0x5f, 0xec, 0x0f, 0x96, 0x85, 0xd8, 0x57, 0x05, + 0xcc, 0x53, 0x9d, 0x96, 0x88, 0x6c, 0x59, 0xac, 0xfc, 0xc1, 0xa1, 0x8e, 0xaf, 0x7f, 0x48, 0x80, + 0xbd, 0xae, 0xb4, 0x91, 0xc5, 0xd7, 0x9b, 0x68, 0x0c, 0x6a, 0xe0, 0x29, 0x68, 0x6e, 0x45, 0xc6, + 0xd5, 0xbe, 0x17, 0x37, 0x90, 0x68, 0xb8, 0xac, 0x33, 0xd2, 0x3b, 0x1d, 0xb1, 0x3d, 0x4b, 0x72, + 0x80, 0xd4, 0x83, 0xa7, 0x05, 0x22, 0xd6, 0x5b, 0x6d, 0xb4, 0x32, 0x73, 0x1f, 0x37, 0x42, 0x55, + 0x2d, 0x82, 0xa0, 0x1a, 0xa5, 0x7c, 0xbf, 0x28, 0x03, 0x38, 0xac, 0x9c, 0x52, 0x61, 0x3b, 0xa0, + 0x1d, 0x76, 0xb9, 0x28, 0x64, 0x5b, 0x1c, 0x22, 0x7b, 0x0b, 0x2e, 0x4c, 0x77, 0x56, 0x4c, 0x6f, + 0x71, 0x8e, 0x8f, 0xbe, 0x2b, 0x67, 0x00, 0x2d, 0x4d, 0x2c, 0x9f, 0x58, 0x1e, 0x7d, 0x57, 0x5b, + 0x9e, 0xae, 0xb8, 0x3c, 0x92, 0xe0, 0xe7, 0x06, 0x6e, 0xde, 0x99, 0x26, 0x38, 0xc1, 0x22, 0x62, + 0x77, 0x6c, 0x13, 0xc8, 0x2c, 0xf6, 0xef, 0x57, 0x97, 0x0a, 0x96, 0xb2, 0x1e, 0xe7, 0x66, 0x0d, + 0xed, 0x55, 0xa8, 0xbf, 0x53, 0xc9, 0xb2, 0xd8, 0xf8, 0x5a, 0x2c, 0x4e, 0x99, 0xbe, 0x5b, 0xa6, + 0xc4, 0x25, 0x32, 0x13, 0x92, 0xd2, 0x5a, 0xf3, 0x58, 0x98, 0x44, 0x7a, 0x51, 0x8c, 0x43, 0x14, + 0xb1, 0xa9, 0x6e, 0xf3, 0x2a, 0x36, 0xff, 0xb2, 0xcf, 0xbb, 0xf3, 0x1e, 0xa3, 0x40, 0x98, 0xa0, + 0x5a, 0xf8, 0xef, 0x07, 0x76, 0x91, 0xc2, 0x7f, 0x08, 0x49, 0xf8, 0xdb, 0x06, 0x26, 0x13, 0x49, + 0x3f, 0x70, 0x85, 0x0f, 0x6c, 0xb9, 0xbe, 0x97, 0xd6, 0xf6, 0xda, 0x1c, 0xda, 0x4e, 0x1f, 0x6d, + 0xed, 0x2e, 0x53, 0xce, 0x67, 0x90, 0x33, 0x63, 0x93, 0xe5, 0xc0, 0xce, 0x6b, 0x44, 0xad, 0x6f, + 0x21, 0x5b, 0x69, 0x93, 0xd1, 0xc8, 0xa6, 0x67, 0xfa, 0x39, 0x7c, 0x15, 0x0e, 0x6b, 0xdb, 0xfb, + 0x80, 0xa9, 0xad, 0x4a, 0x33, 0x39, 0x8b, 0x50, 0x4f, 0x89, 0x6a, 0x1a, 0x79, 0x99, 0x0e, 0xb7, + 0x4b, 0x5f, 0x71, 0xf6, 0xc1, 0xb5, 0x17, 0xbb, 0x61, 0xb1, 0xca, 0x45, 0xd4, 0x53, 0x07, 0x56, + 0x68, 0xb7, 0x8b, 0xe5, 0xff, 0xf1, 0xe4, 0xdd, 0xdb, 0xa6, 0xc4, 0xfc, 0x05, 0x23, 0x83, 0x54, + 0x57, 0xbb, 0x5f, 0x6c, 0xd7, 0x17, 0x55, 0x59, 0x06, 0xb9, 0x1e, 0x4e, 0x09, 0x84, 0xc5, 0x11, + 0x2b, 0xc8, 0xe5, 0x15, 0x47, 0xff, 0xda, 0x4c, 0xb1, 0x5a, 0xd7, 0xc0, 0x65, 0xe5, 0x71, 0x2a, + 0x8b, 0xe1, 0xbe, 0x72, 0xb8, 0xd0, 0x94, 0x39, 0xd1, 0x16, 0x9a, 0xd2, 0x4c, 0xf9, 0x15, 0x83, + 0xcb, 0x22, 0x7d, 0x35, 0x1b, 0xd6, 0x1b, 0xba, 0x9d, 0x1e, 0xa3, 0x3f, 0x89, 0xfa, 0xda, 0x9d, + 0xed, 0x39, 0xfd, 0xac, 0x7d, 0x58, 0x83, 0xb5, 0x8f, 0xee, 0x2d, 0xe6, 0xaf, 0xeb, 0xb0, 0xf6, + 0x2d, 0x79, 0xb9, 0x5a, 0x48, 0x4b, 0xee, 0xdc, 0x15, 0xa4, 0x7f, 0x6f, 0xc5, 0x81, 0x80, 0x67, + 0xba, 0xed, 0x99, 0x8c, 0x5e, 0xdf, 0x1f, 0xbf, 0xd6, 0x85, 0xc4, 0xff, 0x88, 0x9e, 0x6b, 0xe8, + 0x59, 0x56, 0xce, 0xa4, 0xf7, 0x52, 0x9c, 0xdf, 0xf9, 0x4c, 0x16, 0xf2, 0x99, 0xb3, 0x95, 0xe5, + 0x25, 0x43, 0x26, 0xb2, 0xa3, 0x93, 0x77, 0x26, 0x0d, 0x99, 0x4e, 0x92, 0xdb, 0x76, 0x3b, 0x8f, + 0xad, 0x23, 0xf4, 0x2e, 0x0e, 0x31, 0x1a, 0x30, 0x1e, 0x70, 0x26, 0x75, 0xc7, 0x40, 0x67, 0x47, + 0x0f, 0x23, 0x3e, 0xa3, 0x2f, 0xb1, 0x7f, 0x19, 0x5d, 0x58, 0x7d, 0x91, 0x8e, 0xd6, 0x7b, 0xa5, + 0xb4, 0xd1, 0x33, 0xb3, 0x12, 0x13, 0x3d, 0x7f, 0xb2, 0xe9, 0xda, 0x34, 0x51, 0x35, 0x1f, 0xc5, + 0x3d, 0x52, 0xcf, 0x4d, 0x15, 0x51, 0x04, 0x53, 0x4d, 0x14, 0x7c, 0x24, 0x60, 0x99, 0x22, 0x10, + 0x8e, 0x9e, 0x9d, 0x28, 0x71, 0x6a, 0xb0, 0x0f, 0xed, 0x8f, 0xc6, 0xee, 0x80, 0xe7, 0x15, 0x4a, + 0x5d, 0x2a, 0xa1, 0x33, 0x3a, 0xd3, 0x3c, 0xae, 0xb3, 0xc6, 0x9b, 0x5a, 0x31, 0x7b, 0x6e, 0x29, + 0x15, 0xbd, 0x45, 0x72, 0x2d, 0xe9, 0x94, 0xe3, 0xde, 0xd2, 0xc8, 0xc7, 0xd1, 0xb0, 0xeb, 0xbc, + 0x7f, 0x77, 0x72, 0xea, 0xb8, 0xe2, 0x36, 0x93, 0x74, 0x6f, 0x1d, 0x4d, 0xfd, 0x0d, 0xbe, 0x4c, + 0xa3, 0x8a, 0x50, 0x5c, 0x1c, 0x65, 0x74, 0xd1, 0x6a, 0x91, 0x66, 0xf2, 0x68, 0xfc, 0x3c, 0xd3, + 0xbd, 0xa6, 0x6e, 0x8e, 0x8f, 0xaf, 0xc6, 0xbc, 0xf4, 0x07, 0x37, 0x92, 0xce, 0x49, 0x3b, 0x4e, + 0x12, 0xdc, 0x05, 0x9e, 0x39, 0xbc, 0x58, 0xd1, 0xf1, 0xce, 0x11, 0x17, 0x64, 0xd3, 0xd7, 0x4f, + 0x8b, 0xa6, 0xaf, 0x99, 0x27, 0x37, 0xb9, 0x63, 0x8a, 0xe6, 0xd8, 0x20, 0x5c, 0x4b, 0xe1, 0x29, + 0x4f, 0xa7, 0x80, 0x5a, 0x3d, 0x9d, 0xfa, 0xd0, 0x57, 0x33, 0x43, 0xf1, 0x8a, 0x90, 0xfd, 0xf1, + 0x0d, 0xae, 0x4f, 0x6c, 0xc8, 0x41, 0xd7, 0xd0, 0x4f, 0x06, 0x71, 0x30, 0x4b, 0x71, 0x9a, 0x2a, + 0x0e, 0x87, 0xd8, 0x01, 0x14, 0x1b, 0x92, 0xf5, 0xcd, 0xe0, 0x71, 0x30, 0xd4, 0x82, 0x21, 0xe4, + 0x24, 0xda, 0x47, 0x05, 0x5b, 0x47, 0xdf, 0xe5, 0xf7, 0x1d, 0x09, 0x65, 0x4c, 0xa8, 0x4f, 0xb1, + 0x87, 0xfb, 0xb4, 0x3f, 0xdc, 0x86, 0x5d, 0xe7, 0xe6, 0x2c, 0x1a, 0x25, 0x34, 0x51, 0x83, 0x6e, + 0xe7, 0xce, 0xc5, 0x8b, 0x79, 0xf9, 0xc5, 0x65, 0xf9, 0xc5, 0xd4, 0xa3, 0xf5, 0x73, 0x8d, 0x17, + 0x8f, 0x5d, 0x82, 0x97, 0x74, 0x77, 0xee, 0x3e, 0xc2, 0xd7, 0x31, 0xde, 0xbe, 0xd1, 0x40, 0x2b, + 0x4a, 0x70, 0x4d, 0xda, 0x3c, 0xcf, 0x6e, 0x3a, 0xfb, 0x02, 0x8b, 0xeb, 0x44, 0xfd, 0x81, 0xae, + 0x43, 0x18, 0x38, 0x8b, 0xed, 0x66, 0xe9, 0xf9, 0x7c, 0xe1, 0x45, 0xbf, 0xf4, 0xa2, 0x5f, 0x84, + 0x75, 0x36, 0xeb, 0x7c, 0x36, 0x70, 0x43, 0xd2, 0x88, 0x12, 0x2f, 0x30, 0xfd, 0x1b, 0x06, 0xf1, + 0x59, 0x3a, 0xc6, 0x15, 0x14, 0x59, 0x0d, 0x7f, 0x78, 0xee, 0x9f, 0x25, 0xd3, 0x28, 0x4a, 0xc7, + 0x67, 0x37, 0x4b, 0xde, 0x0f, 0x2c, 0x88, 0x3c, 0xeb, 0x67, 0x92, 0xed, 0x51, 0x80, 0x8e, 0x62, + 0xff, 0xe7, 0x6a, 0xa8, 0x24, 0x44, 0xfa, 0xe5, 0x2f, 0x83, 0x31, 0x49, 0xab, 0x1e, 0xbf, 0x3d, + 0x9b, 0x7a, 0xd7, 0xcb, 0xbe, 0x04, 0x4b, 0xeb, 0xe0, 0xde, 0x8f, 0xec, 0x0b, 0x92, 0x14, 0x23, + 0xbb, 0x4d, 0xa9, 0x82, 0xf5, 0x3a, 0xb4, 0xfa, 0x3e, 0x88, 0xa3, 0x04, 0x51, 0x7e, 0x17, 0xba, + 0xe7, 0xa6, 0x58, 0x55, 0xcd, 0xfe, 0x8d, 0x46, 0xc7, 0x9e, 0xcc, 0xfe, 0x9e, 0x7c, 0x4f, 0xf3, + 0xfb, 0x8c, 0xb2, 0x3a, 0x24, 0x29, 0x92, 0x56, 0x67, 0xb5, 0x73, 0x35, 0x8c, 0xcf, 0x06, 0x73, + 0xd2, 0x91, 0xce, 0xbc, 0xe1, 0xa5, 0x69, 0x6b, 0x12, 0xe1, 0xc6, 0x9d, 0xac, 0x12, 0xd3, 0xef, + 0x19, 0xdf, 0xb1, 0x7e, 0xd6, 0x5e, 0xf2, 0xbe, 0x63, 0x77, 0x8c, 0xfd, 0x39, 0x69, 0xf5, 0xcb, + 0x37, 0x1b, 0x3b, 0xdc, 0x12, 0x42, 0xd3, 0xce, 0x12, 0xdc, 0xa7, 0xc5, 0xdd, 0xe0, 0x2b, 0xc3, + 0x72, 0x9b, 0x05, 0x9f, 0xbc, 0x1f, 0x7d, 0xc7, 0x02, 0x55, 0x9e, 0x49, 0xc4, 0x96, 0xa9, 0xf1, + 0x52, 0xee, 0xd2, 0x42, 0x4a, 0xf6, 0xa6, 0xb0, 0x15, 0xe3, 0x2b, 0x95, 0x88, 0xbc, 0x99, 0x9a, + 0xd4, 0xec, 0x5c, 0x38, 0x99, 0xf7, 0x65, 0xf7, 0xa4, 0xcd, 0x07, 0x1f, 0x39, 0x4b, 0xbc, 0x4e, + 0xd8, 0x69, 0x98, 0x37, 0xbb, 0x5c, 0x1c, 0xe4, 0x2b, 0xf8, 0x03, 0x60, 0x19, 0xfe, 0xad, 0x3f, + 0xff, 0xe9, 0x4f, 0x0c, 0x1a, 0x79, 0xf0, 0x85, 0x7b, 0x13, 0xa2, 0x42, 0xda, 0x46, 0xf8, 0x3e, + 0xd4, 0xaf, 0xa3, 0x78, 0x5a, 0x43, 0x25, 0x61, 0x4f, 0xb6, 0xbf, 0xc9, 0x2a, 0xf9, 0xd7, 0xd7, + 0xd5, 0x75, 0x6c, 0x7f, 0x65, 0x32, 0xc9, 0x55, 0xf5, 0x93, 0x00, 0xb7, 0xef, 0x98, 0xda, 0xcb, + 0x4e, 0x42, 0xd7, 0x41, 0x61, 0xde, 0xdd, 0xe0, 0x9b, 0x95, 0xea, 0x19, 0x77, 0xcc, 0x73, 0x9a, + 0x12, 0x83, 0x7c, 0xe9, 0x4f, 0x82, 0xbe, 0xaf, 0x6f, 0x97, 0x46, 0xdc, 0xb4, 0x4e, 0x7b, 0xcb, + 0xd7, 0x13, 0xe8, 0xe9, 0xc2, 0x0e, 0x37, 0x9a, 0x27, 0xda, 0xfd, 0x98, 0xd3, 0xff, 0x32, 0x2c, + 0x58, 0x47, 0x8d, 0x50, 0xc8, 0xfb, 0xba, 0xf8, 0x0f, 0x0f, 0xc6, 0xc1, 0x0c, 0x46, 0x94, 0x20, + 0xe4, 0x4b, 0xc7, 0x70, 0x05, 0x74, 0x26, 0x46, 0xeb, 0x1b, 0x25, 0x90, 0x8e, 0x1b, 0xee, 0xc4, + 0xec, 0x18, 0xa1, 0x1a, 0x0d, 0xcb, 0x53, 0x05, 0x1a, 0xee, 0xbe, 0xef, 0x24, 0xd4, 0x19, 0xbe, + 0xb9, 0x9d, 0x43, 0x89, 0x7c, 0x44, 0x64, 0x70, 0x24, 0x39, 0x8d, 0x8e, 0x76, 0xb8, 0x89, 0x8e, + 0x50, 0x20, 0xf4, 0xd0, 0x3e, 0xa4, 0xc4, 0x10, 0x7d, 0xd0, 0xd1, 0x31, 0x0e, 0x72, 0x42, 0x33, + 0x3b, 0x63, 0xcf, 0x1f, 0xc9, 0xb1, 0xe4, 0xb2, 0xd3, 0xf3, 0xcc, 0xdc, 0xe4, 0xcd, 0x07, 0xd2, + 0xec, 0xa2, 0x43, 0x12, 0x38, 0x9c, 0x95, 0x11, 0x2c, 0xae, 0x98, 0x8e, 0xb3, 0x63, 0xf5, 0xf5, + 0x78, 0x95, 0x10, 0xc3, 0x7a, 0x61, 0xdb, 0x79, 0x58, 0xcd, 0x11, 0x95, 0xd4, 0xc6, 0xc4, 0x2a, + 0xa1, 0x64, 0x81, 0x0e, 0xb9, 0xf6, 0xdb, 0xe2, 0xea, 0xc9, 0x2f, 0x6b, 0x3d, 0x78, 0x08, 0x45, + 0xae, 0x5c, 0x24, 0x59, 0x3b, 0x96, 0xa4, 0x83, 0x42, 0xf5, 0x5b, 0x4b, 0xae, 0xfd, 0x0d, 0xe4, + 0xab, 0x1d, 0x06, 0x54, 0xde, 0xf9, 0xe2, 0x02, 0xb1, 0xdd, 0x48, 0xac, 0xae, 0x6f, 0x1e, 0xda, + 0x29, 0x09, 0xec, 0x84, 0xbf, 0x90, 0x70, 0x1a, 0xc3, 0x60, 0x5a, 0xef, 0x71, 0x5e, 0x01, 0x9c, + 0x40, 0x4b, 0x86, 0x82, 0xcd, 0x43, 0xad, 0x45, 0x92, 0xe4, 0x90, 0x8d, 0x8a, 0x84, 0xd2, 0x66, + 0x53, 0x3b, 0x82, 0xf0, 0xbf, 0x4e, 0xef, 0x37, 0x69, 0x02, 0x15, 0xa3, 0x38, 0x20, 0x62, 0xa8, + 0xd0, 0x01, 0x66, 0x6c, 0xa4, 0x37, 0xd6, 0xfa, 0x12, 0x9e, 0x05, 0xe4, 0xcc, 0xd8, 0xf1, 0xe5, + 0x57, 0xd3, 0x60, 0xbe, 0x70, 0xe6, 0x67, 0x0d, 0xa5, 0x2b, 0xc9, 0xea, 0x59, 0xc2, 0x41, 0xcd, + 0xfc, 0xa8, 0xc5, 0xb5, 0x73, 0xc8, 0x56, 0xe2, 0xfa, 0xc0, 0x59, 0x9f, 0xce, 0x7d, 0xf5, 0x6c, + 0x1e, 0xd8, 0xac, 0x48, 0x59, 0xa2, 0x70, 0x31, 0x35, 0xe0, 0xd8, 0x4b, 0xf2, 0x6b, 0x19, 0x1c, + 0x73, 0x70, 0x04, 0xaf, 0xe0, 0x59, 0x9e, 0xf3, 0x10, 0x8a, 0xf7, 0x38, 0x9d, 0x4e, 0x56, 0x53, + 0xc0, 0x78, 0xf7, 0xb0, 0x30, 0x95, 0x4f, 0x5a, 0x78, 0x93, 0xe1, 0x2f, 0x6f, 0xa9, 0x94, 0x8b, + 0x43, 0x3b, 0x9f, 0x22, 0x97, 0x11, 0xe3, 0xd5, 0x9c, 0x65, 0x3d, 0x65, 0x67, 0x01, 0x71, 0x65, + 0x2d, 0xa4, 0xa0, 0xe3, 0xae, 0x6c, 0x2d, 0xf6, 0x45, 0xce, 0x8b, 0xe3, 0xe8, 0xaa, 0xe4, 0xc6, + 0x9a, 0x7d, 0xd2, 0x59, 0x38, 0x74, 0x03, 0xc6, 0xf9, 0x68, 0x11, 0x6c, 0xc1, 0x0b, 0x97, 0x6a, + 0xaf, 0x71, 0xc4, 0x45, 0x1a, 0x0d, 0xa0, 0x82, 0xc1, 0x36, 0x0a, 0x38, 0xd8, 0x74, 0xb6, 0xf4, + 0x10, 0xb6, 0x1c, 0xcb, 0x87, 0x51, 0x00, 0x1e, 0x7d, 0xa7, 0x11, 0x52, 0xfb, 0x9b, 0x53, 0xa8, + 0xf5, 0xb7, 0xd5, 0x6e, 0xb9, 0x59, 0x8f, 0x1a, 0xa4, 0xe1, 0xc1, 0x4f, 0xbf, 0xec, 0x9a, 0x6b, + 0xad, 0x9d, 0xc5, 0x88, 0x97, 0x11, 0x87, 0x95, 0x94, 0x88, 0xd7, 0xf6, 0x30, 0xb0, 0xa9, 0xfb, + 0xc3, 0x68, 0xd8, 0x0c, 0x3f, 0x7e, 0x2e, 0xc4, 0x3b, 0x5b, 0x00, 0x07, 0xca, 0x28, 0x62, 0x1e, + 0x3b, 0xfe, 0xb0, 0x39, 0x60, 0x27, 0x93, 0x8e, 0xe5, 0x1e, 0x9b, 0xb7, 0x57, 0xe1, 0xcb, 0xba, + 0xd0, 0x08, 0x97, 0xd1, 0xae, 0xa4, 0x8c, 0xcc, 0x83, 0xcd, 0x22, 0x6b, 0x31, 0xcd, 0x67, 0xce, + 0xa5, 0xa4, 0x05, 0xc1, 0x61, 0xfa, 0x29, 0x9f, 0xa5, 0x6f, 0x1e, 0xae, 0xcb, 0x3d, 0x48, 0x6a, + 0x09, 0xa1, 0xa7, 0x94, 0x2e, 0x0b, 0xee, 0x44, 0x4f, 0x19, 0x73, 0xdd, 0x42, 0x9e, 0x4a, 0xb3, + 0x07, 0x70, 0x4e, 0x01, 0x8c, 0x0e, 0xbf, 0x88, 0x79, 0xe0, 0x67, 0xaf, 0x62, 0x84, 0x45, 0x8c, + 0x8a, 0x8a, 0xd1, 0x80, 0xde, 0x93, 0xe5, 0x50, 0xc1, 0x03, 0xf1, 0x53, 0x5a, 0xf1, 0x24, 0x14, + 0x34, 0x06, 0xb8, 0x0d, 0x91, 0xf4, 0x1c, 0x6d, 0xd1, 0x22, 0x3a, 0xa3, 0x06, 0xb6, 0x1c, 0xb7, + 0x33, 0x8a, 0xeb, 0x9b, 0x76, 0x2a, 0x75, 0xcc, 0x3c, 0x7b, 0xa6, 0x1f, 0xb4, 0x7b, 0xc1, 0x13, + 0x6e, 0x3e, 0xd8, 0xda, 0x2a, 0x38, 0x21, 0xff, 0x6e, 0x78, 0xe6, 0x32, 0xc1, 0xf0, 0x1a, 0x25, + 0x82, 0x22, 0xe2, 0x09, 0x99, 0x1f, 0x82, 0x8f, 0x4f, 0x9f, 0xb6, 0x8b, 0xa8, 0xb7, 0x3d, 0x76, + 0xf3, 0x6e, 0xd9, 0xf4, 0x9c, 0x97, 0xa8, 0xfe, 0x2e, 0x5f, 0x97, 0x21, 0x56, 0x3b, 0xb1, 0x65, + 0x2d, 0xe6, 0xe5, 0x56, 0xa6, 0xb1, 0xc9, 0x02, 0x61, 0xf8, 0xb9, 0xb0, 0xf5, 0x2f, 0xac, 0x5d, + 0x42, 0xbf, 0x78, 0x5d, 0x3c, 0x9b, 0x4c, 0xf2, 0xfc, 0xf9, 0xf7, 0x6b, 0x4e, 0x9f, 0x5b, 0x59, + 0x0d, 0x2e, 0x88, 0x1a, 0x55, 0xed, 0x1d, 0x4b, 0x66, 0xbc, 0xdf, 0xde, 0x1a, 0x47, 0x3f, 0x15, + 0x9a, 0x23, 0xe8, 0x2f, 0xf0, 0x72, 0x39, 0xec, 0xf2, 0x76, 0xbd, 0x4c, 0x78, 0x40, 0x8d, 0xf2, + 0xf7, 0x8a, 0xd0, 0xae, 0x22, 0x9d, 0x59, 0x37, 0xbb, 0xd1, 0x33, 0xce, 0xc3, 0x32, 0x67, 0x72, + 0xde, 0xa9, 0x49, 0x1a, 0x6e, 0x46, 0x31, 0x9f, 0x3f, 0xe1, 0x15, 0xd3, 0x57, 0xcf, 0x2a, 0x43, + 0x3a, 0xf9, 0x2b, 0x92, 0x51, 0x53, 0x58, 0xb7, 0xe1, 0xf0, 0x4c, 0xdb, 0x26, 0x83, 0x75, 0x8d, + 0x2c, 0x57, 0xb3, 0x56, 0x82, 0x30, 0xdd, 0xc5, 0xb8, 0x26, 0xed, 0x67, 0x64, 0x39, 0x99, 0x7f, + 0x71, 0x70, 0xc0, 0x0f, 0x76, 0x17, 0x72, 0x47, 0x54, 0xe3, 0xc3, 0x59, 0x6d, 0x38, 0xf9, 0x3a, + 0xcf, 0x36, 0x4f, 0x12, 0x50, 0xa5, 0xe5, 0x64, 0x89, 0x44, 0x70, 0x57, 0x38, 0xf1, 0xad, 0x98, + 0xab, 0xdb, 0x8d, 0xdf, 0xaa, 0xfc, 0xfc, 0x76, 0xd5, 0x67, 0x51, 0x5a, 0x2e, 0xef, 0x76, 0x19, + 0xf5, 0xba, 0x44, 0x78, 0x0f, 0xb2, 0xf5, 0x2e, 0xf7, 0x63, 0xb3, 0xf9, 0x8f, 0x91, 0x62, 0xc4, + 0xb1, 0xad, 0x16, 0x85, 0x4f, 0x9d, 0x8e, 0x83, 0x2b, 0xb4, 0xeb, 0xb9, 0x80, 0x18, 0x5b, 0xc6, + 0x34, 0xab, 0xae, 0xd2, 0xe5, 0x0d, 0x08, 0xbe, 0x57, 0x57, 0x43, 0x5b, 0x34, 0xa7, 0x55, 0x78, + 0x8f, 0x7d, 0x5d, 0xb4, 0x36, 0x57, 0xcc, 0xff, 0xbd, 0xac, 0x9e, 0x8b, 0x6c, 0xa6, 0x4a, 0xc3, + 0x78, 0x88, 0x82, 0x60, 0x49, 0x80, 0xe2, 0x9e, 0x78, 0xa0, 0x9d, 0x13, 0x0f, 0xf8, 0x7e, 0xb8, + 0x95, 0xf2, 0x81, 0xbe, 0xa7, 0x0d, 0x0b, 0x27, 0xb1, 0x95, 0x99, 0xc5, 0xd5, 0xfb, 0xe1, 0x1e, + 0xbb, 0xc2, 0x47, 0x5b, 0x4e, 0x17, 0xa0, 0xe6, 0x8a, 0x99, 0x52, 0x58, 0xb6, 0xde, 0x76, 0x43, + 0xed, 0x39, 0x31, 0xcc, 0x76, 0x5f, 0x04, 0xb6, 0x8b, 0x41, 0x38, 0x21, 0x42, 0x8c, 0xa6, 0xbe, + 0x30, 0x87, 0x8c, 0x03, 0xd0, 0xf2, 0x2c, 0x33, 0x08, 0xab, 0xcd, 0x1c, 0x60, 0xb9, 0x41, 0x1d, + 0xa1, 0x97, 0x15, 0xad, 0x90, 0x4a, 0x44, 0x46, 0x92, 0xb6, 0x71, 0x31, 0x89, 0xc5, 0x71, 0x4a, + 0x62, 0x83, 0x94, 0xac, 0xe8, 0x30, 0x02, 0x9d, 0x8a, 0xfd, 0x35, 0xe1, 0x4a, 0xae, 0x53, 0x08, + 0x53, 0xce, 0x96, 0xc5, 0x67, 0x5a, 0x18, 0x32, 0x05, 0xeb, 0xfc, 0x3d, 0xcb, 0xee, 0x9e, 0x45, + 0xd7, 0xca, 0x42, 0x34, 0x4f, 0x52, 0x62, 0xce, 0x65, 0xa4, 0x1f, 0xe4, 0x3c, 0x19, 0xbf, 0x56, + 0xb9, 0x70, 0xde, 0xd5, 0x97, 0x4a, 0x5f, 0xc6, 0x49, 0xb2, 0x78, 0xd8, 0x2f, 0xd4, 0xb4, 0xd6, + 0x8b, 0xb3, 0xa8, 0x6a, 0xe9, 0x44, 0xcc, 0xd9, 0x92, 0xd4, 0xa0, 0xcb, 0x10, 0x2b, 0x4d, 0xd9, + 0x77, 0x9f, 0xe0, 0x98, 0x09, 0x2e, 0x6f, 0x2d, 0x83, 0xcc, 0x2f, 0x52, 0xb2, 0xa9, 0x7f, 0x81, + 0xe6, 0x33, 0x93, 0xfe, 0xdb, 0x28, 0xf3, 0x4f, 0xa1, 0x5a, 0x99, 0x2f, 0x32, 0x31, 0x87, 0xcc, + 0xd8, 0xfd, 0xe2, 0xd9, 0xe9, 0xab, 0x6f, 0xde, 0x1d, 0x1f, 0xbd, 0x82, 0xc1, 0x1b, 0x39, 0xf3, + 0x39, 0x7d, 0xa6, 0xbe, 0x12, 0x5e, 0x7d, 0x37, 0xe7, 0xac, 0x2d, 0x8e, 0x0b, 0x83, 0x7a, 0xd7, + 0x79, 0x01, 0x07, 0x1a, 0xf1, 0xb6, 0x43, 0x8c, 0x01, 0xf5, 0x01, 0x57, 0x60, 0xea, 0xf8, 0xd4, + 0xa4, 0xa9, 0xde, 0x44, 0x9c, 0x0f, 0xfc, 0xc2, 0x57, 0xed, 0xc6, 0xf6, 0xde, 0x9e, 0x44, 0x7a, + 0x8b, 0x84, 0x96, 0x38, 0x1c, 0xdd, 0x2f, 0x47, 0x4c, 0xdd, 0x0f, 0xce, 0x04, 0xee, 0x75, 0x21, + 0xa1, 0x84, 0x28, 0x94, 0x01, 0x78, 0x30, 0x99, 0x3b, 0xfd, 0xd8, 0x7a, 0xaf, 0xcd, 0x90, 0x7c, + 0x49, 0xb3, 0x93, 0x8c, 0xbd, 0x78, 0xa6, 0x3f, 0x8c, 0x93, 0x4b, 0xbe, 0xe8, 0x38, 0xeb, 0xed, + 0x5b, 0xdc, 0xa9, 0xad, 0x8e, 0xfd, 0xe1, 0x5c, 0xdf, 0xe9, 0x2c, 0xfd, 0xdd, 0x79, 0xc9, 0x8e, + 0x34, 0xdb, 0x2f, 0x15, 0x84, 0xdc, 0x28, 0xf6, 0x26, 0x50, 0x13, 0xf8, 0x40, 0x82, 0x6f, 0xe1, + 0x26, 0x0e, 0xa6, 0x6b, 0x34, 0x15, 0xcc, 0xa7, 0xd4, 0xd5, 0x38, 0xf0, 0x70, 0x44, 0x10, 0x8d, + 0x46, 0x7e, 0x4c, 0x33, 0x11, 0xfa, 0x24, 0x31, 0x63, 0xdf, 0x1c, 0x9a, 0x61, 0x96, 0xc6, 0x11, + 0xc6, 0x3b, 0xb8, 0x3b, 0x19, 0x7f, 0xce, 0x68, 0xb3, 0xd2, 0xbf, 0x66, 0x1d, 0xfe, 0x75, 0x46, + 0xdd, 0x98, 0x05, 0x17, 0xbe, 0x3c, 0x90, 0x74, 0xed, 0xe5, 0xbf, 0xd0, 0x9e, 0x3c, 0x89, 0xc5, + 0xd9, 0xfe, 0x5d, 0xfe, 0x76, 0x86, 0xb3, 0xf5, 0xc2, 0x80, 0x5f, 0xc0, 0x20, 0xa2, 0xfe, 0xa4, + 0x68, 0x46, 0x62, 0x9d, 0x18, 0x24, 0x9f, 0x24, 0x7c, 0x9a, 0xc5, 0x11, 0x8e, 0x6d, 0x6c, 0x27, + 0xb0, 0x6e, 0x66, 0xa1, 0xa7, 0xb7, 0xae, 0x12, 0x85, 0x40, 0xb1, 0x0d, 0x18, 0x1b, 0x70, 0xa2, + 0xfd, 0x4a, 0xe4, 0xc8, 0x43, 0x21, 0xe8, 0x26, 0x06, 0x04, 0xa0, 0xb3, 0x30, 0x64, 0xcb, 0x2a, + 0x8f, 0xc9, 0x33, 0x76, 0x6e, 0xbe, 0x87, 0x5a, 0xe0, 0xe3, 0xc2, 0xde, 0xf3, 0xfe, 0x99, 0x39, + 0xd5, 0x70, 0xf2, 0x43, 0x94, 0xc2, 0x83, 0x20, 0x2c, 0xde, 0xbe, 0x41, 0xd5, 0x1b, 0x1a, 0x58, + 0x30, 0x38, 0xe3, 0xdb, 0xec, 0x87, 0xb3, 0xb3, 0xc1, 0x64, 0x9e, 0xc8, 0x9d, 0xe9, 0x51, 0x7f, + 0x50, 0x1c, 0xfb, 0x4b, 0x29, 0xaa, 0xf8, 0x56, 0x73, 0x33, 0xea, 0xbf, 0x20, 0x69, 0x81, 0x06, + 0x22, 0x74, 0xe7, 0xaa, 0x19, 0x91, 0x23, 0xae, 0xf8, 0x61, 0x6b, 0x24, 0xf1, 0x24, 0x3f, 0x4c, + 0x98, 0x9a, 0x5c, 0xf5, 0xed, 0xcb, 0x63, 0x5a, 0x11, 0xa1, 0x4f, 0x48, 0x60, 0x4b, 0x61, 0x69, + 0x84, 0x57, 0x7c, 0xa1, 0x7a, 0xc1, 0xb2, 0x5e, 0x78, 0xc6, 0x61, 0x98, 0x7e, 0x31, 0x49, 0xa7, + 0xfa, 0x57, 0x88, 0x3a, 0xb3, 0xd1, 0x40, 0xfe, 0x95, 0xb1, 0x8d, 0x19, 0x10, 0xfd, 0x2b, 0x8f, + 0xc9, 0x78, 0x86, 0x1f, 0x85, 0xd1, 0xbc, 0x86, 0x47, 0xab, 0xe5, 0x26, 0x68, 0x06, 0xc4, 0xef, + 0x89, 0xe8, 0xd9, 0xa0, 0x35, 0xc8, 0xa6, 0xd9, 0x65, 0xfb, 0x65, 0xe3, 0xf5, 0xc9, 0x0b, 0x17, + 0x61, 0xaf, 0x6c, 0x20, 0xed, 0x4f, 0x60, 0x5a, 0x1d, 0xd8, 0x30, 0x8a, 0x6b, 0x2d, 0x41, 0xa7, + 0xe8, 0xdf, 0x33, 0x44, 0x8e, 0xe2, 0x62, 0x65, 0x79, 0xe3, 0x95, 0x5e, 0xd1, 0x38, 0x7f, 0x12, + 0x84, 0x0b, 0x01, 0x27, 0x29, 0xfc, 0x22, 0xcf, 0x26, 0xb3, 0x11, 0xe6, 0xc4, 0x8b, 0x2f, 0xce, + 0x74, 0x7f, 0x64, 0x7e, 0x83, 0xb8, 0x38, 0x92, 0x6f, 0xbc, 0xe9, 0xd4, 0x23, 0x9a, 0x7c, 0xfd, + 0xfd, 0xa9, 0x19, 0xc4, 0x29, 0x70, 0xcc, 0x38, 0xe3, 0x85, 0x38, 0x89, 0xa2, 0x8b, 0xf9, 0x4c, + 0x12, 0x39, 0xe8, 0xd8, 0x39, 0xbe, 0x53, 0xa0, 0xd4, 0x5f, 0xd0, 0xce, 0x39, 0x80, 0x51, 0x3b, + 0x37, 0xf3, 0xcb, 0xec, 0xb7, 0x37, 0xf4, 0x66, 0x70, 0x9c, 0xd1, 0x2f, 0x0a, 0x8d, 0x9f, 0xb2, + 0x44, 0x98, 0x2d, 0x82, 0xe7, 0x41, 0xe8, 0xc5, 0x37, 0x6a, 0xe4, 0x7b, 0x9c, 0x64, 0x53, 0x6e, + 0xe8, 0xf5, 0x93, 0xae, 0xa2, 0xd5, 0x7c, 0x93, 0xe0, 0x6a, 0x2d, 0xbe, 0xbf, 0xd3, 0x85, 0xc7, + 0x1d, 0xd5, 0xe4, 0x05, 0x31, 0x82, 0x0b, 0x35, 0xae, 0x4e, 0x23, 0x7a, 0x09, 0x85, 0x41, 0xd0, + 0x77, 0xef, 0xa6, 0x15, 0xca, 0x9d, 0xec, 0x85, 0x3e, 0x32, 0x15, 0x9f, 0xa5, 0xd1, 0x19, 0x00, + 0x32, 0xe9, 0x13, 0x1c, 0xfa, 0x3b, 0x9a, 0x85, 0x7c, 0x67, 0xf5, 0x99, 0xbe, 0x46, 0x9d, 0xea, + 0x9f, 0xe9, 0xfa, 0x0e, 0x98, 0x10, 0x50, 0x17, 0x05, 0xc5, 0xbe, 0x3f, 0x7b, 0xa5, 0x5e, 0x18, + 0xe6, 0x22, 0xdd, 0x7f, 0x86, 0x39, 0xc6, 0xe1, 0x77, 0x82, 0xde, 0x93, 0x24, 0x83, 0xd4, 0xd5, + 0xf9, 0xe9, 0x6c, 0xa9, 0x2f, 0x9e, 0x7f, 0xe6, 0x5f, 0x9e, 0x81, 0xc2, 0x81, 0x24, 0xdf, 0x34, + 0x4d, 0xbf, 0xe0, 0x54, 0xa5, 0x7f, 0x8e, 0xa0, 0x8e, 0xf1, 0x82, 0xca, 0x1f, 0x84, 0x2a, 0xe9, + 0xf9, 0x2a, 0x08, 0xcf, 0xae, 0xce, 0x53, 0x36, 0xa3, 0x6b, 0x18, 0x6c, 0x4b, 0x3f, 0x43, 0x1f, + 0xe4, 0x05, 0x7e, 0x9d, 0x4d, 0x82, 0x69, 0x90, 0x66, 0xa0, 0x39, 0x08, 0xd5, 0x80, 0x14, 0x82, + 0xe0, 0x9f, 0xa0, 0xfa, 0xe2, 0x00, 0xff, 0xf2, 0xbc, 0x6a, 0x84, 0x08, 0x4f, 0x4d, 0xfd, 0x46, + 0xdf, 0x9b, 0xf0, 0x3e, 0xb2, 0x76, 0x98, 0x57, 0xfd, 0x33, 0x24, 0xbd, 0xd3, 0xbd, 0xa6, 0xa7, + 0x41, 0x7a, 0x26, 0x37, 0xe0, 0xe8, 0xe7, 0x29, 0x8e, 0x80, 0xcf, 0x26, 0x89, 0x7e, 0xb4, 0xba, + 0x98, 0x5f, 0x28, 0xff, 0x5c, 0xe2, 0x33, 0x13, 0x9d, 0x1f, 0x85, 0x0f, 0x8a, 0xfb, 0xec, 0xf6, + 0x1d, 0xc4, 0x1c, 0x0a, 0x7b, 0x11, 0x46, 0x7d, 0xce, 0x46, 0x50, 0x1b, 0x5c, 0xee, 0xc3, 0xbd, + 0x86, 0xb3, 0x44, 0xf1, 0x59, 0x02, 0x5f, 0xed, 0xc2, 0x29, 0x90, 0x74, 0x7c, 0x2c, 0x31, 0x48, + 0x92, 0x74, 0x12, 0x3f, 0xcb, 0xa6, 0xa4, 0xd3, 0x45, 0x31, 0x81, 0x53, 0xf3, 0x37, 0x09, 0xec, + 0x9e, 0x58, 0x04, 0xec, 0x2b, 0xc1, 0xde, 0xd5, 0x28, 0xf6, 0x42, 0x17, 0xe1, 0x3e, 0xd0, 0xd2, + 0xe3, 0xb3, 0x15, 0x3f, 0xd4, 0x67, 0x1c, 0x28, 0xc1, 0x2c, 0x2c, 0x91, 0x40, 0xdd, 0x93, 0xe0, + 0x7c, 0xea, 0xe1, 0x12, 0x87, 0x2c, 0x98, 0xd8, 0xe4, 0x9a, 0x22, 0x9a, 0xa6, 0x25, 0x67, 0x1c, + 0xde, 0xb3, 0xb0, 0xdd, 0x3c, 0x67, 0x4a, 0x71, 0x87, 0xef, 0xfb, 0x93, 0xe8, 0x8a, 0x4f, 0x3d, + 0x4a, 0x39, 0xad, 0x8f, 0xbe, 0x3b, 0x61, 0x50, 0xb5, 0x4c, 0x4d, 0x74, 0x35, 0x70, 0x96, 0xd6, + 0x72, 0x51, 0xfe, 0x9c, 0x13, 0xc8, 0xe4, 0x5f, 0x44, 0xf6, 0x38, 0x67, 0x1b, 0x76, 0xd1, 0x8c, + 0x75, 0x6e, 0xac, 0xd9, 0xd5, 0x22, 0x38, 0x52, 0x5b, 0xdf, 0x2b, 0xb8, 0x15, 0xf9, 0x6b, 0x0b, + 0x3e, 0x75, 0xa4, 0x36, 0x92, 0xb0, 0xd5, 0x58, 0x96, 0x91, 0xc4, 0x58, 0x80, 0x03, 0xce, 0xf6, + 0x64, 0x7a, 0xc1, 0x12, 0xf2, 0xc8, 0x4e, 0x8d, 0xa9, 0x8d, 0xf4, 0x20, 0x2e, 0x2e, 0x17, 0x66, + 0x02, 0x6d, 0xe1, 0x26, 0x40, 0x2d, 0x25, 0xb3, 0x20, 0x83, 0xab, 0xfb, 0xd8, 0x85, 0x00, 0x37, + 0xa6, 0x20, 0x1b, 0x86, 0x7e, 0x24, 0xe1, 0x4c, 0x64, 0x1c, 0x57, 0xa1, 0xfa, 0x34, 0x20, 0x99, + 0xef, 0xef, 0xff, 0xf2, 0x7f, 0xf0, 0x6f, 0xef, 0xba, 0xbe, 0xa1, 0xd6, 0xfc, 0xd7, 0x05, 0xa4, + 0x72, 0xad, 0x5e, 0x1e, 0x7b, 0xfa, 0x2c, 0x4f, 0xd2, 0xc5, 0xe9, 0xbd, 0x38, 0x13, 0x57, 0x76, + 0xfd, 0x92, 0x3e, 0xe1, 0x8a, 0xe7, 0x61, 0xa2, 0x13, 0xe6, 0x4c, 0x70, 0xd0, 0xc5, 0x49, 0xa4, + 0x41, 0x7e, 0x4c, 0x9b, 0x5e, 0xde, 0x09, 0x39, 0x90, 0x93, 0x53, 0x5a, 0xbd, 0x0a, 0x50, 0xa5, + 0xa9, 0xfe, 0xa2, 0xaf, 0x7d, 0x62, 0x20, 0x41, 0x98, 0xba, 0xc8, 0x1e, 0x05, 0x07, 0x39, 0x14, + 0xd9, 0xc4, 0x8d, 0x51, 0x88, 0x70, 0xa7, 0x2f, 0xe7, 0x9b, 0x1b, 0x96, 0xc3, 0x6e, 0x74, 0x91, + 0x48, 0x6a, 0x28, 0x4f, 0xf5, 0xe3, 0x88, 0xc8, 0x93, 0x57, 0x90, 0x15, 0xb2, 0xaa, 0x8f, 0x05, + 0x02, 0x7d, 0xf9, 0xe1, 0x90, 0x04, 0x9a, 0x40, 0xc2, 0xff, 0xec, 0x5b, 0x51, 0x78, 0x6d, 0x60, + 0x29, 0x64, 0x5d, 0xd3, 0xc7, 0x7a, 0xc8, 0x99, 0x21, 0xc5, 0x36, 0x2a, 0x30, 0x57, 0x84, 0x87, + 0xbd, 0xd1, 0x91, 0xa4, 0xbb, 0xab, 0xe0, 0x71, 0xb1, 0x2a, 0x68, 0x0b, 0x77, 0xff, 0xd1, 0xa6, + 0xb7, 0xaa, 0xd3, 0x7f, 0x76, 0x96, 0x74, 0xe1, 0x29, 0x1c, 0x04, 0xdb, 0xed, 0xe7, 0xed, 0xe2, + 0x39, 0x83, 0xc9, 0x99, 0x5f, 0xb6, 0x69, 0xcb, 0x51, 0x21, 0x88, 0x36, 0x0b, 0x9f, 0x76, 0xb6, + 0x98, 0xe8, 0xb6, 0x80, 0x37, 0xd8, 0x39, 0x33, 0x83, 0x5a, 0xf1, 0x7c, 0x3d, 0xb3, 0xdd, 0x69, + 0xbb, 0x9d, 0x93, 0x5f, 0xaa, 0x29, 0x84, 0xbc, 0x85, 0x31, 0x64, 0x06, 0x72, 0x65, 0x4c, 0x9a, + 0xe5, 0x74, 0x16, 0x9c, 0xe2, 0x7c, 0xc5, 0xb9, 0x1c, 0x96, 0xdc, 0x27, 0xe5, 0xf0, 0xf9, 0x5b, + 0x9e, 0xc4, 0xa7, 0xd8, 0x41, 0x47, 0x8e, 0x77, 0xcc, 0xca, 0xe3, 0xb3, 0x9d, 0x02, 0x5e, 0xc0, + 0x9b, 0x37, 0xb9, 0x84, 0x5e, 0xc3, 0xa2, 0xd2, 0x1b, 0x0d, 0x29, 0x31, 0x36, 0xff, 0x1c, 0x60, + 0x09, 0xab, 0xe8, 0xf3, 0xd2, 0x74, 0x40, 0x56, 0xb5, 0xc5, 0x91, 0x4a, 0x5e, 0x20, 0x9c, 0xb4, + 0x10, 0x1b, 0xd9, 0x72, 0x96, 0x98, 0x22, 0xed, 0x38, 0x6b, 0xc2, 0x5f, 0xe1, 0x7a, 0x36, 0xf8, + 0xe8, 0xb2, 0xd7, 0xab, 0x64, 0xac, 0xa1, 0xcd, 0x99, 0x96, 0x4f, 0x31, 0x0f, 0x9f, 0x95, 0xf5, + 0xca, 0x64, 0x6a, 0x08, 0xc2, 0x20, 0xad, 0xd5, 0xb3, 0x04, 0x6e, 0xec, 0x26, 0x46, 0xbb, 0x00, + 0xda, 0x7d, 0x1f, 0x47, 0x7d, 0x88, 0x82, 0xb9, 0x86, 0xce, 0x7e, 0x4c, 0x1c, 0x86, 0x6e, 0x92, + 0x7b, 0x0d, 0x22, 0xf6, 0x11, 0x84, 0x78, 0xaa, 0x8e, 0x4e, 0xde, 0x93, 0xd8, 0x83, 0x30, 0x28, + 0xf8, 0x41, 0xf2, 0xad, 0x6d, 0x33, 0x28, 0x6e, 0xb0, 0x10, 0x02, 0x5e, 0xa3, 0xa1, 0xf6, 0xb7, + 0xd5, 0xb9, 0x9f, 0xca, 0x59, 0xfd, 0x64, 0xc2, 0x29, 0x44, 0xe5, 0x48, 0x1e, 0x1f, 0x67, 0x24, + 0x79, 0x4c, 0x6e, 0x24, 0x42, 0x62, 0x00, 0xe1, 0xfa, 0x6a, 0xec, 0x4b, 0x66, 0x2e, 0x7a, 0x13, + 0x7b, 0x57, 0xd4, 0x0e, 0xed, 0x61, 0xc5, 0xcd, 0x84, 0x35, 0xcc, 0xa3, 0xef, 0x5e, 0x64, 0xe9, + 0x13, 0x6b, 0x31, 0x31, 0x14, 0x9d, 0xf7, 0x48, 0x9b, 0x7c, 0x7e, 0x06, 0x66, 0x56, 0xfa, 0x55, + 0x7b, 0x7d, 0xbe, 0xd3, 0xdc, 0x9c, 0xbe, 0xea, 0x7a, 0xd3, 0xd9, 0xf3, 0xd5, 0xe1, 0xb6, 0x34, + 0x75, 0xe2, 0xb4, 0x86, 0xda, 0x52, 0x95, 0xe6, 0xe1, 0x5b, 0x74, 0xfd, 0xdd, 0xdb, 0xd7, 0x7f, + 0xc5, 0xe8, 0x3c, 0xa8, 0x04, 0x01, 0xfb, 0x5e, 0xb3, 0x12, 0xd3, 0x54, 0xcf, 0x42, 0x93, 0x23, + 0x91, 0x70, 0x39, 0x0f, 0x81, 0x76, 0xde, 0x98, 0xed, 0xc9, 0xd9, 0xd0, 0x4b, 0x57, 0xb6, 0x7a, + 0x35, 0x9d, 0x23, 0xd1, 0x90, 0xef, 0x5d, 0x72, 0xa4, 0xfe, 0x38, 0x53, 0x7f, 0xb3, 0xd4, 0xa9, + 0x84, 0x3c, 0x2f, 0xdb, 0xa9, 0x75, 0xe6, 0x48, 0x76, 0x85, 0xe8, 0xeb, 0x9c, 0x1a, 0x5e, 0x82, + 0xc3, 0xc9, 0x80, 0xd9, 0x69, 0xb9, 0x28, 0x44, 0x79, 0x9d, 0x01, 0x64, 0x1e, 0x8f, 0x48, 0x66, + 0xd0, 0x8c, 0x94, 0xb6, 0x59, 0x46, 0x5d, 0x5d, 0x09, 0x0a, 0xcd, 0x65, 0xc5, 0x84, 0x91, 0x2f, + 0xbe, 0xd0, 0x68, 0xe6, 0x3b, 0xa7, 0xf8, 0x57, 0x93, 0xa8, 0x23, 0x4b, 0xa2, 0x61, 0x50, 0xb1, + 0xe0, 0x6d, 0x88, 0x2e, 0x40, 0x6a, 0x64, 0xe3, 0xf1, 0xcc, 0xcf, 0xc5, 0x0b, 0x08, 0x14, 0x7b, + 0xed, 0x0e, 0xee, 0xf8, 0x43, 0xf2, 0xbf, 0x80, 0x4b, 0x0a, 0x9e, 0xac, 0xee, 0xf0, 0x8c, 0xd4, + 0xf5, 0xcc, 0xe4, 0x97, 0x27, 0x57, 0x77, 0xe7, 0x4c, 0x37, 0x69, 0xf7, 0x4a, 0x5f, 0x64, 0x48, + 0x04, 0x49, 0xed, 0x83, 0x4a, 0xc3, 0x94, 0x93, 0x01, 0xf2, 0xf0, 0x8f, 0xbe, 0xe3, 0x9b, 0x04, + 0xed, 0x74, 0x70, 0x5e, 0x9a, 0x93, 0xb0, 0xab, 0x43, 0x64, 0x38, 0x57, 0x01, 0x57, 0x67, 0x11, + 0x8a, 0xe9, 0x5c, 0xe0, 0x60, 0xd7, 0x13, 0x07, 0x15, 0x8d, 0x7e, 0x4e, 0x4b, 0x82, 0xf8, 0x3f, + 0xbd, 0x9d, 0x72, 0x2b, 0x58, 0x25, 0x72, 0xfb, 0x92, 0x82, 0xa7, 0x15, 0x56, 0x18, 0xe6, 0x8f, + 0x05, 0x4f, 0xad, 0x37, 0x53, 0x2b, 0x58, 0x97, 0xa0, 0x00, 0x0e, 0x91, 0x44, 0xbd, 0x2b, 0x2a, + 0x2c, 0xb5, 0x8d, 0x38, 0xa8, 0x24, 0xbb, 0x37, 0x09, 0x7a, 0x73, 0x12, 0x63, 0xab, 0x2e, 0x37, + 0x34, 0xa2, 0xd6, 0x0b, 0x92, 0x74, 0xce, 0x23, 0x4e, 0x04, 0xf8, 0x09, 0xbe, 0x1d, 0x83, 0xac, + 0x76, 0xb6, 0x3c, 0xee, 0xe1, 0x56, 0x81, 0xfb, 0xe5, 0x33, 0xff, 0x08, 0x5c, 0xa8, 0xb6, 0xbd, + 0x9f, 0x31, 0x35, 0x6d, 0xbf, 0xd5, 0xee, 0x0a, 0xe2, 0x92, 0xec, 0xf3, 0xc1, 0xa4, 0x49, 0xa3, + 0xf7, 0x09, 0xee, 0x12, 0x7c, 0x5d, 0x52, 0xac, 0xef, 0xf8, 0xd3, 0x8e, 0xef, 0xaa, 0xe0, 0x11, + 0x61, 0xd9, 0xbe, 0xa5, 0x35, 0x53, 0x27, 0xbb, 0x6d, 0x29, 0xae, 0xba, 0x6d, 0x29, 0xcf, 0xa7, + 0x83, 0xad, 0x94, 0xa6, 0x4d, 0xc7, 0xb0, 0x2e, 0x84, 0xa6, 0x32, 0xcc, 0x82, 0x7f, 0xb8, 0xb6, + 0x94, 0x59, 0x57, 0x0d, 0xb6, 0x70, 0x73, 0xa5, 0x2c, 0x05, 0x58, 0xa3, 0x79, 0x1e, 0x99, 0xab, + 0x11, 0xdb, 0x30, 0x0e, 0x44, 0xa0, 0x42, 0x5e, 0x06, 0x92, 0xac, 0x23, 0x81, 0xe9, 0x42, 0x42, + 0x53, 0xa3, 0x19, 0xbc, 0xa9, 0xa8, 0xaf, 0x70, 0x31, 0x35, 0xdb, 0x2e, 0xba, 0x13, 0x78, 0xe7, + 0x21, 0xb1, 0xe2, 0x60, 0xc0, 0x44, 0x4a, 0x6f, 0x62, 0x0e, 0xca, 0x49, 0xc6, 0x68, 0x09, 0x81, + 0x00, 0xbe, 0xce, 0xb0, 0x21, 0x81, 0x66, 0xd4, 0xbd, 0x4c, 0x5c, 0xca, 0xa7, 0xb3, 0xe4, 0xf2, + 0x5e, 0x30, 0xc8, 0x29, 0x2b, 0xcc, 0x56, 0xdf, 0x15, 0x4a, 0xc3, 0xcd, 0x76, 0x34, 0x73, 0x65, + 0x1e, 0x2d, 0x0f, 0x1c, 0xf6, 0xc9, 0x26, 0x81, 0x71, 0xa4, 0xba, 0x2b, 0xe6, 0xbe, 0xf9, 0xdc, + 0x82, 0x7f, 0xb7, 0xb1, 0x9c, 0x96, 0xb2, 0x7b, 0x85, 0x8a, 0x12, 0x3e, 0x1f, 0xea, 0x9f, 0x69, + 0x65, 0x40, 0x23, 0x74, 0xb9, 0x3a, 0x51, 0x28, 0x5d, 0xd9, 0x7a, 0xae, 0x65, 0xd0, 0x2c, 0x02, + 0x4d, 0x05, 0xe5, 0xa5, 0x70, 0x70, 0xf0, 0xbb, 0x69, 0x0f, 0x58, 0x08, 0xbc, 0xe9, 0x7f, 0xab, + 0x9d, 0x53, 0x9c, 0x72, 0xb6, 0x58, 0x8e, 0xe4, 0x20, 0x10, 0x12, 0xaf, 0x51, 0xf6, 0x77, 0xa8, + 0x3a, 0x3f, 0xf9, 0x68, 0x3b, 0x25, 0x14, 0x9d, 0x24, 0x94, 0xd5, 0x58, 0x76, 0xb4, 0x5c, 0xb8, + 0xe0, 0xa4, 0xbb, 0x3d, 0xbb, 0x56, 0xed, 0x45, 0x2f, 0x08, 0x5b, 0x62, 0xd4, 0x15, 0xb0, 0x32, + 0x90, 0x0c, 0x2a, 0x1c, 0x16, 0xae, 0x46, 0x6f, 0x9c, 0x4f, 0x90, 0xd2, 0xa6, 0x1f, 0xc5, 0x34, + 0x33, 0x8d, 0x8a, 0xab, 0xd3, 0x7b, 0x55, 0xd7, 0xa9, 0xaf, 0x3b, 0x2e, 0xce, 0xc4, 0xcd, 0xd9, + 0x82, 0x6c, 0xb9, 0x30, 0xac, 0x92, 0x0a, 0xb6, 0x61, 0xdf, 0xf9, 0xbe, 0x62, 0x58, 0xab, 0x24, + 0x5e, 0xa3, 0xa9, 0x65, 0xdd, 0x18, 0xd9, 0x5e, 0x20, 0x59, 0x0b, 0x95, 0xb7, 0x0e, 0x14, 0x31, + 0x5e, 0x72, 0x04, 0x58, 0xf0, 0xd3, 0x28, 0x96, 0xfe, 0xe4, 0xee, 0xae, 0xc0, 0xd6, 0x9d, 0x75, + 0x3e, 0xf3, 0xef, 0x26, 0x86, 0x83, 0xa2, 0xd7, 0x09, 0xe2, 0x28, 0x83, 0xdf, 0x39, 0xa2, 0xef, + 0x27, 0x7a, 0x57, 0x5c, 0xd9, 0x74, 0x7f, 0xe9, 0x1b, 0xb8, 0x7f, 0xa0, 0x04, 0x5e, 0x15, 0x48, + 0x6d, 0xb9, 0xb8, 0xda, 0x09, 0x6d, 0x84, 0x2b, 0x3c, 0xcc, 0xaf, 0x96, 0x43, 0xc6, 0x6b, 0x76, + 0x8c, 0x9c, 0xf1, 0x0a, 0x7d, 0xa0, 0x1f, 0xa9, 0x0d, 0x08, 0x1b, 0x13, 0xf7, 0x86, 0xf6, 0x38, + 0x0d, 0x0e, 0xda, 0xa4, 0x93, 0xc7, 0xba, 0xe0, 0xc6, 0x25, 0xcb, 0xbd, 0x96, 0x0b, 0x63, 0x7b, + 0x11, 0x90, 0x0b, 0xc1, 0x48, 0x0f, 0x09, 0xa2, 0x5b, 0x7e, 0xd6, 0xc7, 0xee, 0xdb, 0x2b, 0x4e, + 0xf7, 0x90, 0xa5, 0xaf, 0x14, 0x80, 0xa7, 0x0f, 0x9f, 0x84, 0x98, 0x40, 0xc2, 0x5b, 0x52, 0x4e, + 0x17, 0x5b, 0x71, 0xd8, 0xcd, 0xfb, 0xfb, 0x89, 0x5f, 0x71, 0x7f, 0x67, 0x55, 0x88, 0xec, 0x3d, + 0xe2, 0x61, 0x75, 0x7c, 0x90, 0xbe, 0x6c, 0x71, 0x79, 0xc8, 0xa4, 0x84, 0x19, 0xe9, 0x00, 0xe5, + 0xea, 0x50, 0xd8, 0xf8, 0x5e, 0x51, 0xd1, 0xf7, 0x8d, 0xfe, 0x8a, 0x2e, 0x9e, 0xc6, 0x76, 0x10, + 0x74, 0x37, 0xb6, 0x63, 0xc1, 0xd4, 0xaa, 0x60, 0xb0, 0x87, 0x44, 0x83, 0xdd, 0x3b, 0x1c, 0xac, + 0x22, 0x1e, 0xec, 0xca, 0xbb, 0xe9, 0xfb, 0xde, 0xf4, 0x0c, 0x79, 0x33, 0xce, 0xa4, 0x97, 0x26, + 0xbc, 0xab, 0x1c, 0xdf, 0xb5, 0x3e, 0xc0, 0xab, 0x90, 0x12, 0x41, 0x66, 0xc3, 0x0e, 0xed, 0xaa, + 0x8c, 0x80, 0x5e, 0x11, 0xdc, 0xb5, 0x74, 0xc2, 0x8f, 0x20, 0xa7, 0x2f, 0x9f, 0x67, 0x51, 0xaf, + 0xab, 0x43, 0x9d, 0x11, 0x97, 0xce, 0x09, 0x7b, 0xe9, 0x5f, 0xd2, 0x22, 0xe8, 0x5f, 0x98, 0xd1, + 0x93, 0xe3, 0x87, 0x84, 0x3e, 0x1b, 0x6a, 0xb0, 0x62, 0x98, 0x6b, 0xb7, 0xe6, 0xce, 0xd2, 0xbb, + 0xfa, 0x92, 0x00, 0x68, 0x5b, 0xd7, 0x7c, 0x68, 0xdd, 0x4b, 0x24, 0x26, 0x41, 0x46, 0xe9, 0x87, + 0x55, 0xe3, 0xa1, 0x2d, 0xaf, 0xb4, 0x18, 0x73, 0xbd, 0x10, 0xe7, 0xff, 0x89, 0x31, 0xfe, 0xf7, + 0x8b, 0xef, 0xbf, 0xcb, 0xdb, 0xa5, 0xf9, 0xa8, 0x08, 0xcd, 0x86, 0xfd, 0x81, 0x93, 0x46, 0xea, + 0x66, 0xb4, 0xd8, 0x95, 0x5f, 0x20, 0xc9, 0x45, 0xed, 0xb4, 0xe2, 0x07, 0xf6, 0x97, 0xf5, 0x77, + 0xa3, 0x52, 0x03, 0x85, 0x40, 0xe1, 0xe2, 0x35, 0x24, 0xf6, 0xf5, 0xa3, 0x05, 0x5b, 0x32, 0x3b, + 0xb3, 0x5c, 0x58, 0xe9, 0x86, 0x17, 0x0a, 0x21, 0x9d, 0x0d, 0xbb, 0xc4, 0xa2, 0xf0, 0x87, 0xf6, + 0x47, 0x16, 0x64, 0xf8, 0x41, 0x07, 0x57, 0x76, 0x8c, 0xcc, 0x82, 0x64, 0xc5, 0x79, 0x9a, 0xe2, + 0xda, 0x07, 0xaf, 0xf1, 0xcb, 0xc7, 0x7a, 0xeb, 0xdc, 0xad, 0x9d, 0xb9, 0x03, 0x9a, 0xb0, 0x01, + 0xed, 0xec, 0xdf, 0xd3, 0xf6, 0x17, 0xbf, 0xf0, 0x12, 0xbf, 0x56, 0x2f, 0xe7, 0x65, 0xe0, 0x66, + 0x90, 0x94, 0x8e, 0x18, 0x72, 0xa1, 0xf3, 0xfc, 0xa5, 0x38, 0x80, 0xbb, 0x32, 0xd6, 0x41, 0xff, + 0x05, 0xac, 0xaf, 0x0e, 0x82, 0xcf, 0x89, 0xb0, 0x20, 0xba, 0x5c, 0x3e, 0xe9, 0xd3, 0x26, 0xce, + 0xb0, 0x24, 0xea, 0x7d, 0x36, 0x3b, 0xd3, 0x45, 0xb1, 0xa1, 0xf7, 0x0f, 0xf3, 0x18, 0x65, 0xad, + 0xd4, 0x69, 0x21, 0x3d, 0xaf, 0x62, 0x94, 0x3d, 0x6c, 0x0c, 0x4e, 0xef, 0x7e, 0xbd, 0xd1, 0x75, + 0xca, 0xbd, 0x29, 0x75, 0x46, 0x97, 0x2a, 0x77, 0xa4, 0xd5, 0x12, 0x8b, 0x91, 0xe8, 0xf7, 0xa4, + 0x32, 0xc1, 0x06, 0x12, 0x41, 0x45, 0x65, 0xcb, 0x02, 0x9b, 0x33, 0x68, 0xd7, 0x4d, 0xae, 0x10, + 0x23, 0xb9, 0xd7, 0xee, 0xb4, 0x76, 0xdb, 0xbb, 0xe5, 0xd4, 0x9f, 0xae, 0x9d, 0xea, 0x3e, 0xb7, + 0x5e, 0xc0, 0x64, 0x24, 0x51, 0x33, 0xac, 0x89, 0xb1, 0xb1, 0x87, 0xd3, 0x85, 0x70, 0xb6, 0x7e, + 0x0f, 0x06, 0x98, 0xa9, 0x87, 0x7d, 0x55, 0xee, 0x36, 0xe6, 0xa3, 0x9f, 0x1c, 0x12, 0x7d, 0xd5, + 0xb1, 0x8d, 0xc8, 0xa8, 0x8a, 0xab, 0x15, 0x38, 0xaf, 0xfe, 0xe2, 0xa5, 0xa4, 0x44, 0x67, 0x40, + 0xb2, 0x24, 0x8a, 0xcd, 0xf2, 0x9c, 0x78, 0xfd, 0x5e, 0x0e, 0x4b, 0x6c, 0x86, 0x12, 0x07, 0x29, + 0x43, 0x44, 0x88, 0x24, 0xa9, 0xa9, 0xd6, 0xbd, 0x27, 0x99, 0x2d, 0x06, 0x4d, 0xc9, 0x31, 0x94, + 0xb6, 0xc8, 0x04, 0x56, 0x2a, 0x7f, 0x31, 0x0d, 0xe2, 0xfa, 0x92, 0x0a, 0xdb, 0x5f, 0x7d, 0xb9, + 0xbd, 0xd3, 0xb1, 0x40, 0x60, 0x36, 0x32, 0x33, 0x91, 0x5c, 0xde, 0x40, 0xe0, 0xcc, 0xcc, 0xb3, + 0x98, 0xc3, 0xa6, 0xfc, 0xa2, 0x9d, 0xec, 0x9c, 0x04, 0xc0, 0x04, 0x46, 0x3b, 0x4e, 0xae, 0x6f, + 0x8f, 0x2d, 0xb3, 0x9c, 0xc9, 0x95, 0x8e, 0xd9, 0x25, 0x24, 0xb8, 0x7a, 0x84, 0x15, 0xf9, 0x66, + 0xae, 0x8e, 0x15, 0xe8, 0x0e, 0xf2, 0x16, 0x1f, 0xf9, 0xd9, 0xf9, 0x94, 0x09, 0xe4, 0xa9, 0x3e, + 0xf9, 0x03, 0xc2, 0xaf, 0xa2, 0xf8, 0x22, 0x51, 0x35, 0x6d, 0x11, 0x23, 0x4d, 0x3f, 0x66, 0x4f, + 0x35, 0x39, 0x93, 0xa9, 0xbb, 0x7c, 0x11, 0x8c, 0x3e, 0x24, 0x61, 0x16, 0x19, 0xe0, 0x3c, 0xcf, + 0xb3, 0xa1, 0x49, 0xba, 0x0b, 0x85, 0xeb, 0x0f, 0x7d, 0xa4, 0xae, 0x26, 0xa9, 0x19, 0x6d, 0x66, + 0x47, 0x83, 0xda, 0x76, 0x26, 0x34, 0x06, 0x12, 0x93, 0xeb, 0x9a, 0x8c, 0x29, 0xc2, 0xb5, 0x61, + 0x69, 0x4f, 0x42, 0xfe, 0xe6, 0x0d, 0xd2, 0xb9, 0xc7, 0x01, 0xaf, 0xfa, 0x28, 0x52, 0x9c, 0x6b, + 0x13, 0x63, 0xfd, 0x9a, 0x04, 0x56, 0x0a, 0xde, 0x9c, 0x01, 0x06, 0xec, 0x9b, 0xf7, 0x81, 0xef, + 0x97, 0x87, 0xd5, 0x55, 0x52, 0x01, 0xb9, 0xd6, 0x73, 0x34, 0x73, 0x3e, 0x56, 0x24, 0x98, 0xee, + 0xaf, 0x90, 0x77, 0x83, 0x61, 0x31, 0x49, 0x36, 0x21, 0x9a, 0xf6, 0xf5, 0xfe, 0x42, 0xf6, 0x43, + 0x7a, 0xc5, 0xa7, 0x1d, 0x58, 0x9f, 0xd9, 0x1d, 0xdc, 0xc6, 0x30, 0xca, 0xae, 0xa1, 0x00, 0x29, + 0xc6, 0x41, 0xce, 0x05, 0xc6, 0x98, 0x32, 0x0b, 0xdc, 0xce, 0xe3, 0x7b, 0xb7, 0x8c, 0x95, 0xc9, + 0x26, 0xae, 0xed, 0x50, 0xfa, 0x81, 0xcd, 0x50, 0xc5, 0x47, 0xa4, 0x53, 0x28, 0xeb, 0xf2, 0x33, + 0x16, 0x84, 0xca, 0x85, 0x68, 0xaf, 0x09, 0x87, 0xb5, 0xd9, 0xc1, 0x21, 0x32, 0x36, 0x0c, 0x89, + 0x68, 0xec, 0x02, 0x26, 0x81, 0xf8, 0x19, 0x7d, 0x62, 0x73, 0x55, 0xb9, 0xb6, 0x0e, 0x28, 0xd7, + 0x9d, 0x43, 0x0b, 0xd4, 0x0f, 0xfa, 0xc3, 0x97, 0x02, 0x26, 0x85, 0x07, 0xe3, 0xc1, 0x58, 0x8e, + 0x19, 0x60, 0xbb, 0xc4, 0x07, 0xa7, 0xd1, 0x71, 0x16, 0x62, 0x03, 0xa6, 0xaf, 0xcd, 0x95, 0x83, + 0xb7, 0xf8, 0xae, 0x4f, 0xd9, 0x6b, 0xe3, 0xe0, 0x7c, 0x4c, 0xb4, 0x56, 0x77, 0xee, 0x7a, 0x15, + 0x14, 0xc0, 0x99, 0x66, 0xb3, 0x56, 0x2b, 0x66, 0x1a, 0x27, 0x60, 0x3a, 0x03, 0xc0, 0x54, 0xa2, + 0x36, 0x0b, 0xb3, 0x3b, 0x9d, 0xc8, 0xc5, 0x28, 0x17, 0xc5, 0xb7, 0xd2, 0x15, 0xd9, 0x2b, 0xa7, + 0xac, 0x36, 0x02, 0x1f, 0xb5, 0x0b, 0x71, 0x87, 0x9b, 0x36, 0xaf, 0x82, 0x21, 0xce, 0x72, 0xae, + 0xf1, 0x7b, 0xcc, 0x87, 0xf8, 0x5b, 0xce, 0x3f, 0xe0, 0x61, 0xea, 0x5d, 0x9f, 0x8d, 0x66, 0x49, + 0xbd, 0xca, 0x7f, 0x5f, 0xee, 0x3a, 0x2c, 0x5c, 0xa4, 0xc8, 0xf0, 0xad, 0xbb, 0x11, 0x2b, 0xae, + 0x4f, 0x3c, 0x30, 0xbd, 0x29, 0x6b, 0xdc, 0x1b, 0x2b, 0xb2, 0x03, 0x2d, 0xf2, 0x33, 0x2d, 0x8b, + 0xe8, 0x5b, 0xc9, 0x34, 0x19, 0x3d, 0xb5, 0xa4, 0x10, 0xbd, 0x74, 0xe5, 0xb6, 0x46, 0x03, 0xa7, + 0x94, 0x67, 0x27, 0xcf, 0xcc, 0x84, 0x9b, 0xb7, 0x63, 0x52, 0x8d, 0x6a, 0x85, 0x12, 0x76, 0x56, + 0xa0, 0xc5, 0x62, 0x26, 0x81, 0xa2, 0xab, 0x3a, 0x15, 0xb9, 0x83, 0x36, 0x56, 0x87, 0x24, 0x56, + 0xa4, 0xf7, 0x2d, 0xd9, 0x18, 0x57, 0xf8, 0x91, 0x9b, 0xe4, 0xb1, 0xf4, 0xff, 0x22, 0x45, 0xd3, + 0x0b, 0xd2, 0xe8, 0x39, 0xca, 0xfe, 0x10, 0x3f, 0xa1, 0xb4, 0xf3, 0x0f, 0x38, 0xe5, 0x1f, 0x6e, + 0xfc, 0xff, 0x0f, 0xfe, 0x17, 0x02, 0xb3, 0x48, 0x01, 0x00, }; /* When present, this file replaces the built-in dashboard at runtime, so the diff --git a/tests/test_cv610_validation.c b/tests/test_cv610_validation.c index 839888c2..72309e35 100644 --- a/tests/test_cv610_validation.c +++ b/tests/test_cv610_validation.c @@ -1,4 +1,5 @@ #include "cv610_modes.h" +#include "cv610_encoder_config.h" #include "venc_api.h" #include "venc_config.h" @@ -97,12 +98,163 @@ static int test_mode_table(void) return failures; } +/* Every row asserts the index contract too: out_index must address the very + * entry that was returned, because /api/v1/modes publishes that index and the + * ground's mode catalog addresses modes by it. */ +static int select_ok(const char *name, int forced, uint32_t fps, + uint32_t want_fps) +{ + const Cv610SensorMode *table = cv610_mode_table(NULL); + int idx = 999; + const Cv610SensorMode *m = cv610_mode_select(forced, fps, &idx); + + return expect(name, m != NULL && m->fps == want_fps && + idx >= 0 && m == &table[idx]); +} + +/* Derived rather than hardcoded so the tests below keep meaning what they say + * if the table is ever reordered or extended. */ +static int fastest_mode_index(void) +{ + const Cv610SensorMode *table = cv610_mode_table(NULL); + size_t count = 0; + size_t i; + int best = 0; + + cv610_mode_table(&count); + for (i = 1; i < count; i++) + if (table[i].fps > table[best].fps) + best = (int)i; + return best; +} + +static int select_rejects(const char *name, int forced, uint32_t fps) +{ + int idx = 999; + const Cv610SensorMode *m = cv610_mode_select(forced, fps, &idx); + + return expect(name, m == NULL && idx == -1); +} + +/* sensor.mode and video0.fps resolve to one mode the way SigmaStar's + * sensor_select() resolves them: a forced index wins and must exist, else the + * rate is a target rather than a command. One row diverges deliberately — + * see cv610_mode_select(). */ +static int test_mode_select(void) +{ + const Cv610SensorMode *table = cv610_mode_table(NULL); + size_t count = 0; + int failures = 0; + + cv610_mode_table(&count); + + /* A forced index beats the requested rate outright. */ + failures += select_ok("select_forced_beats_fps", 1, 100, table[1].fps); + failures += select_ok("select_forced_last", (int)count - 1, 30, + table[count - 1].fps); + /* Past the table it is an error, not a fallback to something plausible. */ + failures += select_rejects("select_forced_out_of_range", (int)count, 100); + + /* Any negative index means auto, as forced_pad/forced_mode do on + * SigmaStar — only >= 0 is a command. */ + failures += select_ok("select_negative_is_auto", -5, 60, 60); + + failures += select_ok("select_auto_exact", -1, 90, 90); + /* Between modes rounds UP: never deliver fewer frames than asked while a + * mode that can keep up exists. */ + failures += select_ok("select_auto_rounds_up", -1, 45, 60); + failures += select_ok("select_auto_just_below_top", -1, 99, 100); + failures += select_ok("select_auto_below_all", -1, 1, 30); + /* Above every mode clamps to the FASTEST. A literal port of SigmaStar's + * sensor_mode_cost tie-break would answer 30 here, which is the wart this + * table exists to pin down. */ + failures += select_ok("select_auto_clamps_to_fastest", -1, 120, 100); + failures += select_ok("select_auto_clamps_far_above", -1, 100000, 100); + /* No target at all: reject rather than invent a rate. */ + failures += select_rejects("select_auto_zero_fps", -1, 0); + + return failures; +} + +static int test_encoder_config(void) +{ + VencConfig cfg; + Cv610EncoderConfig enc; + int failures = 0; + + venc_config_defaults(&cfg); + cfg.video0.slice_count = 1; + failures += expect("enc_off_derives", + cv610_encoder_config_derive(&cfg, 1080, 100, &enc) == 0); + failures += expect("enc_off_features_disabled", + !enc.intra.enabled && !enc.ref.enabled && !enc.slice.enabled); + failures += expect("enc_off_slice_defaults", + enc.slice.total_lcu_rows == 34 && enc.slice.split_size == 1 && + enc.slice.expected_count == 1); + + (void)venc_config_apply_resilience_preset("racing", &cfg.video0); + failures += expect("enc_racing_derives", + cv610_encoder_config_derive(&cfg, 1080, 100, &enc) == 0); + failures += expect("enc_racing_gdr", + enc.intra.enabled && enc.intra.mode == 0 && + enc.intra.refresh_num == 3 && enc.intra.request_i_qp == 36 && + enc.intra.derived.total_rows == 34); + failures += expect("enc_racing_no_refpred", !enc.ref.enabled); + + (void)venc_config_apply_resilience_preset("rally", &cfg.video0); + failures += expect("enc_rally_derives", + cv610_encoder_config_derive(&cfg, 1080, 60, &enc) == 0); + failures += expect("enc_rally_refpred", + enc.ref.enabled && enc.ref.base == 1 && enc.ref.enhance == 1 && + enc.ref.pred == 1); + + (void)venc_config_apply_resilience_preset("ltr:4", &cfg.video0); + failures += expect("enc_ltr_derives", + cv610_encoder_config_derive(&cfg, 1080, 60, &enc) == 0); + failures += expect("enc_ltr_refpred_without_gdr", + !enc.intra.enabled && enc.ref.enabled && enc.ref.base == 1 && + enc.ref.enhance == 4 && enc.ref.pred == 0); + + cfg.video0.slice_count = 17; + failures += expect("enc_slice_17_derives", + cv610_encoder_config_derive(&cfg, 1080, 100, &enc) == 0); + failures += expect("enc_slice_17_geometry", + enc.slice.enabled && enc.slice.split_mode == 1 && + enc.slice.split_size == 2 && enc.slice.expected_count == 17); + cfg.video0.slice_count = 12; + (void)cv610_encoder_config_derive(&cfg, 1080, 100, &enc); + failures += expect("enc_slice_12_geometry", + enc.slice.split_size == 3 && enc.slice.expected_count == 12); + cfg.video0.slice_count = 32; + (void)cv610_encoder_config_derive(&cfg, 1080, 100, &enc); + failures += expect("enc_slice_saturates_at_rows", + enc.slice.split_size == 2 && enc.slice.expected_count == 17); + cfg.video0.slice_count = 9; + (void)cv610_encoder_config_derive(&cfg, 720, 100, &enc); + failures += expect("enc_slice_720_quantizes", + enc.slice.total_lcu_rows == 23 && enc.slice.split_size == 3 && + enc.slice.expected_count == 8); + + cfg.video0.slice_count = 0; + failures += expect("enc_reject_slice_zero", + cv610_encoder_config_derive(&cfg, 1080, 100, &enc) != 0); + cfg.video0.slice_count = VENC_SLICE_COUNT_MAX + 1; + failures += expect("enc_reject_slice_over_max", + cv610_encoder_config_derive(&cfg, 1080, 100, &enc) != 0); + + return failures; +} + int main(void) { VencConfig cfg; + size_t mode_count = 0; int failures = 0; failures += test_mode_table(); + failures += test_mode_select(); + failures += test_encoder_config(); + cv610_mode_table(&mode_count); venc_config_defaults(&cfg); failures += expect_valid("cv610_defaults", &cfg, 1); @@ -117,13 +269,27 @@ int main(void) failures += expect("cv610_default_is_1280x720", cfg.video0.width == 1280 && cfg.video0.height == 720); failures += expect("cv610_default_is_100fps", cfg.video0.fps == 100); - failures += expect("cv610_default_is_8000kbps", cfg.video0.bitrate == 8000); + /* The shipped bitrate is a BOOT SEED, not an operating point: waybeam-link + * is the single rate controller and actuates within seconds of the link + * coming up. What the seed has to survive is the worst rung — landing at + * the MCS0 no-feedback floor while offering 8 Mbps floods the air, and on + * this fleet an over-offered craft has already been measured demoting a + * SECOND craft's link on the same channel. So this pins low on purpose; + * it asserted 8000 until that was understood. */ + failures += expect("cv610_default_bitrate_survives_mcs0", + cfg.video0.bitrate == 2600); /* And that it names a real sensor mode rather than only passing the * generic range checks. */ failures += expect("cv610_default_names_a_mode", cv610_mode_for_fps(cfg.video0.fps) != NULL); + /* A rate above every mode is no longer a config error — it selects the + * fastest mode. (This asserted rejection until the selector landed; the + * substitution is what replaced it, not the removal of a check.) */ cfg.video0.fps = 120; - failures += expect_valid("cv610_reject_fps", &cfg, 0); + failures += expect_valid("cv610_accept_fps_above_table", &cfg, 1); + /* But a config that names no rate at all still is. */ + cfg.video0.fps = 0; + failures += expect_valid("cv610_reject_fps_zero", &cfg, 0); cfg.video0.fps = 60; cfg.video0.width = 1280; cfg.video0.height = 720; @@ -131,13 +297,37 @@ int main(void) cfg.video0.width = 1936; cfg.video0.height = 1080; failures += expect_valid("cv610_reject_upscale", &cfg, 0); - /* A size the sensor can produce, at a rate it cannot. */ + /* A size the sensor can produce, at a rate between two modes: accepted + * now, and the 60 fps mode is what runs. Geometry is then checked + * against THAT mode, not against the requested rate. */ cfg.video0.width = 1920; cfg.video0.height = 1080; cfg.video0.fps = 45; - failures += expect_valid("cv610_reject_size_ok_fps_bad", &cfg, 0); - /* Half-set geometry must not widen into the default mode. */ + failures += expect_valid("cv610_accept_size_ok_fps_between", &cfg, 1); + /* sensor.index: one pad, so 0 and auto are the only answers. */ cfg.video0.fps = 60; + cfg.sensor.index = 0; + failures += expect_valid("cv610_accept_sensor_pad_zero", &cfg, 1); + cfg.sensor.index = 1; + failures += expect_valid("cv610_reject_sensor_pad", &cfg, 0); + cfg.sensor.index = -1; + /* sensor.mode: an index into the advertised table, or auto. */ + cfg.sensor.mode = 0; + failures += expect_valid("cv610_accept_sensor_mode", &cfg, 1); + cfg.sensor.mode = (int)mode_count; + failures += expect_valid("cv610_reject_sensor_mode_past_end", &cfg, 0); + /* A forced mode drives the GOP limit, because it drives the encoder's + * frame rate. gop_size 700 s passes at 60 fps (42000 frames) and fails + * at the forced 100 fps mode (70000) — video0.fps alone cannot tell + * these apart, which is the bug this check exists to catch. */ + cfg.sensor.mode = -1; + cfg.video0.gop_size = 700.0; + failures += expect_valid("cv610_gop_ok_at_requested_rate", &cfg, 1); + cfg.sensor.mode = fastest_mode_index(); + failures += expect_valid("cv610_gop_uses_forced_mode_rate", &cfg, 0); + cfg.sensor.mode = -1; + cfg.video0.gop_size = 3.0; + /* Half-set geometry must not widen into the default mode. */ cfg.video0.height = 0; failures += expect_valid("cv610_reject_half_set_size", &cfg, 0); /* Control: video0.size=auto is still accepted. */ @@ -152,6 +342,13 @@ int main(void) strcpy(cfg.video0.rc_mode, "vbr"); failures += expect_valid("cv610_reject_vbr", &cfg, 0); strcpy(cfg.video0.rc_mode, "cbr"); + strcpy(cfg.video0.resilience, "racing"); + (void)venc_config_apply_resilience_preset("racing", &cfg.video0); + cfg.video0.slice_count = 17; + failures += expect_valid("cv610_accept_resilience_and_slices", &cfg, 1); + strcpy(cfg.video0.resilience, "off"); + (void)venc_config_apply_resilience_preset("off", &cfg.video0); + cfg.video0.slice_count = 1; strcpy(cfg.video0.framing, "stab"); failures += expect_valid("cv610_reject_framing", &cfg, 0); strcpy(cfg.video0.framing, "off"); diff --git a/tests/test_h26x_util.c b/tests/test_h26x_util.c index e18f8c99..d5e33276 100644 --- a/tests/test_h26x_util.c +++ b/tests/test_h26x_util.c @@ -77,6 +77,29 @@ int test_h26x_util(void) consecutive_codes, sizeof(consecutive_codes), &cursor, &nal, &nal_len) == 0); } + { + uint8_t access_unit[] = { + 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0xaa, /* VPS */ + 0x00, 0x00, 0x01, 0x02, 0x01, 0xbb, /* TRAIL_R */ + 0x00, 0x00, 0x01, 0x00, 0x01, 0xcc, /* TRAIL_N */ + 0x00, 0x00, 0x01, 0x03, 0x01, 0xdd, /* layer-id msb set */ + 0x00, 0x00, 0x01, 0x02, 0x09, 0xee /* layer-id low bit set */ + }; + + CHECK("h26x_patch_trail_count", + h26x_util_hevc_patch_trail_r_to_n(access_unit, + sizeof(access_unit)) == 1); + CHECK("h26x_patch_trail_header", access_unit[10] == 0x00); + CHECK("h26x_patch_trail_keeps_vps", access_unit[4] == 0x40); + CHECK("h26x_patch_trail_keeps_existing_n", access_unit[16] == 0x00); + CHECK("h26x_patch_trail_keeps_layered", access_unit[22] == 0x03); + CHECK("h26x_patch_trail_keeps_low_layer_id", access_unit[28] == 0x02); + CHECK("h26x_patch_trail_idempotent", + h26x_util_hevc_patch_trail_r_to_n(access_unit, + sizeof(access_unit)) == 0); + CHECK("h26x_patch_trail_null", + h26x_util_hevc_patch_trail_r_to_n(NULL, 0) == 0); + } return failures; } diff --git a/tests/test_maruko_config.c b/tests/test_maruko_config.c index 04161011..2365c471 100644 --- a/tests/test_maruko_config.c +++ b/tests/test_maruko_config.c @@ -23,6 +23,7 @@ int test_maruko_config(void) CHECK("maruko defaults codec", cfg.rc_codec == PT_H265); CHECK("maruko defaults rc mode", cfg.rc_mode == 3); CHECK("maruko defaults stream mode", cfg.stream_mode == MARUKO_STREAM_RTP); + CHECK("maruko defaults slice count", cfg.slice_count == 1); CHECK("maruko defaults forced pad", cfg.forced_sensor_pad == (MI_SNR_PAD_ID_e)-1); CHECK("maruko defaults forced mode", cfg.forced_sensor_mode == -1); CHECK("maruko defaults 3dnr", cfg.vpe_level_3dnr == 1); @@ -36,6 +37,7 @@ int test_maruko_config(void) vcfg.video0.fps = 90; vcfg.video0.bitrate = 6000; vcfg.video0.gop_size = 1.5; + vcfg.video0.slice_count = 6; vcfg.video0.zoom_pct = 0.5; vcfg.video0.zoom_x = 0.25; vcfg.video0.zoom_y = 0.75; @@ -57,6 +59,7 @@ int test_maruko_config(void) CHECK("maruko config bitrate", cfg.venc_max_rate == 6000); CHECK("maruko config gop", cfg.venc_gop_size == 135); CHECK("maruko config gop seconds", cfg.venc_gop_seconds == 1.5); + CHECK("maruko config slice count", cfg.slice_count == 6); CHECK("maruko config zoom pct", cfg.zoom_pct == 0.5); CHECK("maruko config zoom x", cfg.zoom_x == 0.25); CHECK("maruko config zoom y", cfg.zoom_y == 0.75); diff --git a/tests/test_maruko_video.c b/tests/test_maruko_video.c new file mode 100644 index 00000000..00a1e029 --- /dev/null +++ b/tests/test_maruko_video.c @@ -0,0 +1,88 @@ +#include "maruko_video.h" +#include "test_helpers.h" + +#include + +static int g_recovery_calls; + +static int recovery_stub(void *ctx) +{ + (void)ctx; + g_recovery_calls++; + return 1; +} + +int test_maruko_video(void) +{ + MarukoOutput output; + i6c_venc_pack pack; + i6c_venc_strm stream; + uint8_t data[16] = { 0 }; + int failures = 0; + unsigned int info_cap; + + memset(&output, 0, sizeof(output)); + memset(&pack, 0, sizeof(pack)); + memset(&stream, 0, sizeof(stream)); + info_cap = (unsigned int)(sizeof(pack.packetInfo) / + sizeof(pack.packetInfo[0])); + + CHECK("maruko packetInfo null stream rejected", + !maruko_video_stream_packet_info_complete(NULL)); + CHECK("maruko packetInfo empty stream rejected", + !maruko_video_stream_packet_info_complete(&stream)); + + stream.count = 1; + stream.packet = &pack; + CHECK("maruko packetInfo null data rejected", + !maruko_video_stream_packet_info_complete(&stream)); + + pack.data = data; + pack.length = sizeof(data); + pack.offset = 0; + CHECK("maruko packetInfo fallback accepted", + maruko_video_stream_packet_info_complete(&stream)); + pack.offset = pack.length; + CHECK("maruko packetInfo empty fallback rejected", + !maruko_video_stream_packet_info_complete(&stream)); + + pack.offset = 0; + pack.packNum = 1; + pack.packetInfo[0].offset = 0; + pack.packetInfo[0].length = 0; + CHECK("maruko packetInfo zero descriptor rejected", + !maruko_video_stream_packet_info_complete(&stream)); + pack.packetInfo[0].offset = pack.length; + pack.packetInfo[0].length = 1; + CHECK("maruko packetInfo offset rejected", + !maruko_video_stream_packet_info_complete(&stream)); + pack.packetInfo[0].offset = 8; + pack.packetInfo[0].length = 9; + CHECK("maruko packetInfo overrun rejected", + !maruko_video_stream_packet_info_complete(&stream)); + pack.packetInfo[0].offset = 4; + pack.packetInfo[0].length = 8; + CHECK("maruko packetInfo descriptor accepted", + maruko_video_stream_packet_info_complete(&stream)); + pack.packNum = info_cap + 1; + CHECK("maruko packetInfo table overflow rejected", + !maruko_video_stream_packet_info_complete(&stream)); + + output.request_idr = recovery_stub; + g_recovery_calls = 0; + CHECK("maruko invalid AU rejected", + maruko_video_reject_incomplete_access_unit(&stream, &output) == 1); + CHECK("maruko invalid AU requests recovery", g_recovery_calls == 1); + CHECK("maruko invalid AU recovery paced", + maruko_video_reject_incomplete_access_unit(&stream, &output) == 1 && + g_recovery_calls == 1); + + output.drop_idr_last_us = 0; + output.svct_active = 1; + stream.h265Info.refType = MARUKO_REFTYPE_ENHANCE_P_NOTFORREF; + CHECK("maruko droppable invalid AU skips recovery", + maruko_video_reject_incomplete_access_unit(&stream, &output) == 1 && + g_recovery_calls == 1); + + return failures; +} diff --git a/tests/test_runner.c b/tests/test_runner.c index cff95783..6ccaaba8 100644 --- a/tests/test_runner.c +++ b/tests/test_runner.c @@ -15,6 +15,7 @@ extern int test_file_util(void); extern int test_h26x_util(void); extern int test_h26x_param_sets(void); extern int test_maruko_config(void); +extern int test_maruko_video(void); extern int test_pipeline_common(void); extern int test_codec_config(void); extern int test_sdk_quiet(void); @@ -81,6 +82,9 @@ int main(void) printf("\n--- test_maruko_config ---\n"); failures += test_maruko_config(); + printf("\n--- test_maruko_video ---\n"); + failures += test_maruko_video(); + printf("\n--- test_pipeline_common ---\n"); failures += test_pipeline_common(); diff --git a/tests/test_star6e_output.c b/tests/test_star6e_output.c index e81ffa89..fafb327a 100644 --- a/tests/test_star6e_output.c +++ b/tests/test_star6e_output.c @@ -436,7 +436,9 @@ static int test_star6e_output_send_frame_rtp_dispatch(void) { Star6eOutputSetup setup; Star6eOutput output; + MI_VENC_Pack_t pack = {0}; MI_VENC_Stream_t stream = {0}; + uint8_t data[4] = { 0 }; size_t expected = 1234; size_t actual; int failures = 0; @@ -444,6 +446,10 @@ static int test_star6e_output_send_frame_rtp_dispatch(void) g_test_star6e_rtp_send_called = 0; g_test_star6e_rtp_send_valid = 0; + pack.data = data; + pack.length = sizeof(data); + stream.count = 1; + stream.packet = &pack; ret = star6e_output_prepare(&setup, "udp://127.0.0.1:5600", "rtp", 0); CHECK("star6e output send frame rtp prepare", ret == 0); ret = star6e_output_init(&output, &setup); @@ -1595,6 +1601,185 @@ static int test_star6e_output_always_sends_under_pressure(void) return failures; } +/* ── frame-ring recovery-IDR paths ─────────────────────────────────────── */ + +static int g_test_ring_idr_calls; +static int g_test_ring_idr_honored; + +static int test_ring_request_idr_stub(void *ctx) +{ + (void)ctx; + g_test_ring_idr_calls++; + return g_test_ring_idr_honored; +} + +static void test_ring_fill_p_frame(MI_VENC_Pack_t *pack, + MI_VENC_Stream_t *stream, uint8_t *data, size_t len) +{ + memset(pack, 0, sizeof(*pack)); + pack->data = data; + pack->length = (MI_U32)len; + pack->packNum = 1; + pack->packetInfo[0].offset = 0; + pack->packetInfo[0].length = (MI_U32)len; + pack->packetInfo[0].packType.h265Nalu = 1; /* TRAIL_R: breaks chain */ + memset(stream, 0, sizeof(*stream)); + stream->count = 1; + stream->packet = pack; +} + +/* Ring-full drop: the 1 s holdoff paces HONORED requests, and a request the + * shared 100 ms limiter swallowed rolls the anchor back so the next drop + * retries instead of leaving the chain unhealed. */ +static int test_star6e_output_frame_ring_idr_holdoff(void) +{ + Star6eOutputSetup setup; + Star6eOutput output; + MI_VENC_Pack_t pack; + MI_VENC_Stream_t stream; + uint8_t data[8] = { 0, 0, 0, 1, 0x02, 0x01, 0xAA, 0xBB }; + int failures = 0; + int i; + + CHECK("ring idr prepare", star6e_output_prepare(&setup, + "frame-shm://test_idr_holdoff", "compact", 0) == 0); + CHECK("ring idr init", star6e_output_init(&output, &setup) == 0); + output.request_idr = test_ring_request_idr_stub; + output.idr_ctx = NULL; + test_ring_fill_p_frame(&pack, &stream, data, sizeof(data)); + + for (i = 0; i < 8; ++i) { /* fill all 8 slots */ + CHECK("ring idr fill slot", + star6e_output_send_frame(&output, &stream, 0, + NULL, NULL) > 0); + } + g_test_ring_idr_calls = 0; + g_test_ring_idr_honored = 1; + CHECK("ring idr 9th drops", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) == 0); + CHECK("ring idr fired once", g_test_ring_idr_calls == 1); + CHECK("ring idr next drop paced", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) == 0); + CHECK("ring idr holdoff quiet", g_test_ring_idr_calls == 1); + + /* Swallowed request: anchor must roll back so the next drop retries. */ + output.drop_idr_last_us = 0; + g_test_ring_idr_honored = 0; + CHECK("ring idr swallowed drop", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) == 0); + CHECK("ring idr swallowed called", g_test_ring_idr_calls == 2); + CHECK("ring idr retry drop", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) == 0); + CHECK("ring idr retried immediately", g_test_ring_idr_calls == 3); + g_test_ring_idr_honored = 1; + CHECK("ring idr honored drop", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) == 0); + CHECK("ring idr honored called", g_test_ring_idr_calls == 4); + CHECK("ring idr paced again", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) == 0); + CHECK("ring idr paced count", g_test_ring_idr_calls == 4); + + star6e_output_teardown(&output); + return failures; +} + +/* A pack reporting more NALs than packetInfo holds must abort the frame — + * never ship it truncated — request recovery, and leave the ring usable. */ +static int test_star6e_output_frame_ring_truncation_abort(void) +{ + Star6eOutputSetup setup; + Star6eOutput output; + MI_VENC_Pack_t pack; + MI_VENC_Stream_t stream; + uint8_t data[64] = { 0 }; + size_t sent; + int failures = 0; + unsigned int k; + + CHECK("ring trunc prepare", star6e_output_prepare(&setup, + "frame-shm://test_trunc_abort", "compact", 0) == 0); + CHECK("ring trunc init", star6e_output_init(&output, &setup) == 0); + output.request_idr = test_ring_request_idr_stub; + output.idr_ctx = NULL; + g_test_ring_idr_calls = 0; + g_test_ring_idr_honored = 1; + + memset(&pack, 0, sizeof(pack)); + pack.data = data; + pack.length = sizeof(data); + pack.packNum = 9; /* one more than the 8-entry packetInfo table */ + for (k = 0; k < 8; ++k) { + pack.packetInfo[k].offset = k * 4; + pack.packetInfo[k].length = 4; + pack.packetInfo[k].packType.h265Nalu = 1; + } + memset(&stream, 0, sizeof(stream)); + stream.count = 1; + stream.packet = &pack; + + sent = star6e_output_send_frame(&output, &stream, 0, NULL, NULL); + CHECK("ring trunc aborted", sent == 0); + CHECK("ring trunc recovery requested", g_test_ring_idr_calls == 1); + CHECK("ring trunc warned once", output.trunc_warned == 1); + CHECK("ring trunc nothing committed", + output.frame_ring->stats.writes == 0); + + /* The abort must leave the ring writable. */ + test_ring_fill_p_frame(&pack, &stream, data, 8); + CHECK("ring trunc ring still usable", + star6e_output_send_frame(&output, &stream, 0, NULL, NULL) > 0); + + star6e_output_teardown(&output); + return failures; +} + +static int test_star6e_output_packet_info_validation(void) +{ + MI_VENC_Pack_t pack; + MI_VENC_Stream_t stream; + uint8_t data[16] = { 0 }; + int failures = 0; + + memset(&pack, 0, sizeof(pack)); + memset(&stream, 0, sizeof(stream)); + CHECK("star packetInfo null stream rejected", + !star6e_output_stream_packet_info_complete(NULL)); + CHECK("star packetInfo empty stream rejected", + !star6e_output_stream_packet_info_complete(&stream)); + + stream.count = 1; + stream.packet = &pack; + CHECK("star packetInfo null data rejected", + !star6e_output_stream_packet_info_complete(&stream)); + pack.data = data; + pack.length = sizeof(data); + CHECK("star packetInfo fallback accepted", + star6e_output_stream_packet_info_complete(&stream)); + pack.offset = pack.length; + CHECK("star packetInfo empty fallback rejected", + !star6e_output_stream_packet_info_complete(&stream)); + + pack.offset = 0; + pack.packNum = 1; + pack.packetInfo[0].length = 0; + CHECK("star packetInfo zero descriptor rejected", + !star6e_output_stream_packet_info_complete(&stream)); + pack.packetInfo[0].offset = pack.length; + pack.packetInfo[0].length = 1; + CHECK("star packetInfo offset rejected", + !star6e_output_stream_packet_info_complete(&stream)); + pack.packetInfo[0].offset = 8; + pack.packetInfo[0].length = 9; + CHECK("star packetInfo overrun rejected", + !star6e_output_stream_packet_info_complete(&stream)); + pack.packetInfo[0].offset = 4; + pack.packetInfo[0].length = 8; + CHECK("star packetInfo descriptor accepted", + star6e_output_stream_packet_info_complete(&stream)); + + return failures; +} + int test_star6e_output(void) { int failures = 0; @@ -1631,5 +1816,8 @@ int test_star6e_output(void) failures += test_star6e_output_unix_flush_is_bounded(); failures += test_star6e_output_unix_stall_mode_resumes_without_drops(); failures += test_star6e_output_always_sends_under_pressure(); + failures += test_star6e_output_frame_ring_idr_holdoff(); + failures += test_star6e_output_frame_ring_truncation_abort(); + failures += test_star6e_output_packet_info_validation(); return failures; } diff --git a/tests/test_venc_api.c b/tests/test_venc_api.c index 5c0dec01..c382310a 100644 --- a/tests/test_venc_api.c +++ b/tests/test_venc_api.c @@ -476,12 +476,21 @@ static int test_field_support_by_backend(void) CHECK("max qp unsupported maruko", venc_api_field_supported_for_backend("maruko", "video0.max_qp") == 0); + CHECK("slice count supported maruko", + venc_api_field_supported_for_backend("maruko", + "video0.sliceCount") == 1); CHECK("bitrate supported cv610", venc_api_field_supported_for_backend("cv610", "video0.bitrate") == 1); CHECK("gop alias supported cv610", venc_api_field_supported_for_backend("cv610", "video0.gopSize") == 1); + CHECK("resilience supported cv610", + venc_api_field_supported_for_backend("cv610", + "video0.resilience") == 1); + CHECK("slice count supported cv610", + venc_api_field_supported_for_backend("cv610", + "video0.sliceCount") == 1); CHECK("opus config API unsupported cv610", venc_api_field_supported_for_backend("cv610", "audio.codec") == 0); @@ -1730,6 +1739,93 @@ static int test_capabilities_emits_ui(void) * behind it. isp.awb_fps paces a loop only Star6E has; on Maruko the entry * must still be present (schema is shared) but marked unsupported, with the * tooltip explaining why. */ +/* Minimal stand-in: the routes test only cares that the pointer is non-NULL, + * not what it returns. */ +static char *api_test_stub_query_iq(void) +{ + return strdup("{\"ok\":true,\"data\":{}}"); +} + +static int api_test_stub_apply_iq(const char *param, const char *value) +{ + (void)param; (void)value; + return 0; +} + +/* /api/v1/capabilities advertises which optional routes the running backend + * actually services, so the dashboard can decide whether to draw the Image + * Quality tab without paying for a whole ISP sweep on /api/v1/iq. The value + * has to track the callback pointer, not the backend name -- the two existing + * capabilities tests both zero the callbacks struct, so neither could ever + * observe routes.iq true. */ +static int test_capabilities_routes_track_callbacks(void) +{ + int failures = 0; + VencConfig cfg; + VencApplyCallbacks cb; + int status = 0, fd; + char response[65536]; + const char *request = + "GET /api/v1/capabilities HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n"; + size_t sent, req_len = strlen(request); + int pass; + + /* Three arms: neither callback, query_iq_info alone, then both. Only + * the pointers change, so a difference in the response can only come + * from them. The middle arm is the one that matters: routes.iq claims + * BOTH /api/v1/iq and /api/v1/iq/set are serviced, and with only + * query_iq_info registered the advertised /iq/set answers 501. */ + for (pass = 0; pass < 3; pass++) { + venc_config_defaults(&cfg); + memset(&cb, 0, sizeof(cb)); + if (pass >= 1) + cb.query_iq_info = api_test_stub_query_iq; + if (pass == 2) + cb.apply_iq_param = api_test_stub_apply_iq; + + if (venc_api_register(&cfg, "star6e", &cb, NULL) != 0) { + CHECK("routes register", 0); + return failures; + } + if (ensure_api_test_server() != 0) { + CHECK("routes server", 0); + return failures; + } + fd = connect_api_test_socket(); + CHECK("routes connect", fd >= 0); + if (fd < 0) + return failures; + for (sent = 0; sent < req_len; ) { + ssize_t n = write(fd, request + sent, req_len - sent); + if (n < 0 && errno == EINTR) + continue; + if (n <= 0) { + close(fd); + CHECK("routes write", 0); + return failures; + } + sent += (size_t)n; + } + shutdown(fd, SHUT_WR); + CHECK("routes read", + read_http_response(fd, &status, response, sizeof(response)) == 0); + close(fd); + CHECK("routes status", status == 200); + CHECK("routes block present", strstr(response, "\"routes\"") != NULL); + if (pass == 0) { + CHECK("routes.iq false without either callback", + strstr(response, "\"iq\":false") != NULL); + } else if (pass == 1) { + CHECK("routes.iq false with query_iq_info alone", + strstr(response, "\"iq\":false") != NULL); + } else { + CHECK("routes.iq true with both callbacks", + strstr(response, "\"iq\":true") != NULL); + } + } + return failures; +} + static int test_capabilities_awb_fps_backend_gate(void) { int failures = 0; @@ -1929,6 +2025,7 @@ int test_venc_api(void) failures += test_set_rejects_malformed_percent_escape(); failures += test_capabilities_emits_ui(); failures += test_capabilities_awb_fps_backend_gate(); + failures += test_capabilities_routes_track_callbacks(); failures += test_snapshot_routes(); stop_api_test_server(); return failures; diff --git a/tests/test_venc_config.c b/tests/test_venc_config.c index 5fe9a802..49c5add2 100644 --- a/tests/test_venc_config.c +++ b/tests/test_venc_config.c @@ -81,6 +81,7 @@ static int test_defaults(void) CHECK("defaults_audio_port", cfg.outgoing.audio_port == 5601); CHECK("defaults_scene_threshold_off", cfg.video0.scene_threshold == 0); CHECK("defaults_scene_holdoff", cfg.video0.scene_holdoff == 2); + CHECK("defaults_slice_count_off", cfg.video0.slice_count == 1); CHECK("defaults_ref_base_off", cfg.video0.ref_base == 0); CHECK("defaults_ref_enhance", cfg.video0.ref_enhance == 0); @@ -349,6 +350,59 @@ static int test_load_full_json(void) return failures; } +static int test_slice_count(void) +{ + int failures = 0; + const char *json = + "{ \"video0\": { \"sliceCount\": 4 } }"; + char *path = write_temp_json(json); + VencConfig cfg; + + CHECK("slice_tmpfile", path != NULL); + if (!path) return failures; + venc_config_defaults(&cfg); + CHECK("slice_load", venc_config_load(path, &cfg) == 0); + CHECK("slice_count_4", cfg.video0.slice_count == 4); + unlink(path); free(path); + + /* out-of-range values clamp to VENC_SLICE_COUNT_MAX */ + path = write_temp_json("{ \"video0\": { \"sliceCount\": 99 } }"); + CHECK("slice_tmpfile2", path != NULL); + if (!path) return failures; + CHECK("slice_load2", venc_config_load(path, &cfg) == 0); + CHECK("slice_count_clamped", + cfg.video0.slice_count == VENC_SLICE_COUNT_MAX); + unlink(path); free(path); + + /* 17 must survive the clamp: it is one slice per CTU-64 row at 1080p, + * the finest the encoder can deliver, and the old ceiling of 8 made it + * — and 9 — unreachable, capping the fleet at 6 delivered slices. */ + path = write_temp_json("{ \"video0\": { \"sliceCount\": 17 } }"); + CHECK("slice_tmpfile5", path != NULL); + if (!path) return failures; + CHECK("slice_load5", venc_config_load(path, &cfg) == 0); + CHECK("slice_count_17_survives", cfg.video0.slice_count == 17); + unlink(path); free(path); + + path = write_temp_json("{ \"video0\": { \"sliceCount\": 0 } }"); + CHECK("slice_tmpfile3", path != NULL); + if (!path) return failures; + CHECK("slice_load3", venc_config_load(path, &cfg) == 0); + CHECK("slice_count_floor", cfg.video0.slice_count == 1); + unlink(path); free(path); + + /* A negative value must floor to 1, not wrap through the unsigned + * store to the 8-slice maximum. */ + path = write_temp_json("{ \"video0\": { \"sliceCount\": -1 } }"); + CHECK("slice_tmpfile4", path != NULL); + if (!path) return failures; + CHECK("slice_load4", venc_config_load(path, &cfg) == 0); + CHECK("slice_count_negative_floors", cfg.video0.slice_count == 1); + unlink(path); free(path); + + return failures; +} + static int test_load_partial_json(void) { int failures = 0; @@ -1271,6 +1325,7 @@ int test_venc_config(void) failures += test_defaults(); failures += test_load_full_json(); failures += test_load_partial_json(); + failures += test_slice_count(); failures += test_load_missing_file(); failures += test_load_bad_json(); failures += test_load_qp_bounds_validation(); diff --git a/tests/test_venc_frame_ring.c b/tests/test_venc_frame_ring.c index d0b63522..bf18b83b 100644 --- a/tests/test_venc_frame_ring.c +++ b/tests/test_venc_frame_ring.c @@ -978,6 +978,36 @@ static int test_fr_drop_breaks_chain(void) } } + /* The recovery-IDR holdoff: a consumer-less ring drops EVERY frame, + * and unpaced requests degraded the stream to an IDR every ~7 frames + * with GDR suppressed (measured on star6e, 2026-08-20). One request + * per second heals a live consumer's transient drop; a storm of + * drops within the window coalesces to that one. */ + { + uint64_t last = 0; + + CHECK("fr_idr_first_drop_fires", + venc_frame_drop_idr_due(&last, 5000000) == 1); + CHECK("fr_idr_within_holdoff_quiet", + venc_frame_drop_idr_due(&last, 5000001) == 0); + CHECK("fr_idr_just_under_holdoff_quiet", + venc_frame_drop_idr_due(&last, + 5000000 + VENC_FRAME_DROP_IDR_HOLDOFF_US - + 1) == 0); + CHECK("fr_idr_at_holdoff_fires", + venc_frame_drop_idr_due(&last, + 5000000 + VENC_FRAME_DROP_IDR_HOLDOFF_US) + == 1); + /* A quiet probe must not advance the window. */ + CHECK("fr_idr_quiet_probe_keeps_anchor", + venc_frame_drop_idr_due(&last, + 6000000 + VENC_FRAME_DROP_IDR_HOLDOFF_US - + 1) == 0 && + venc_frame_drop_idr_due(&last, + 6000000 + VENC_FRAME_DROP_IDR_HOLDOFF_US) + == 1); + } + return failures; } diff --git a/tools/cv610_i2c_dump.c b/tools/cv610_i2c_dump.c new file mode 100644 index 00000000..76ee4a8a --- /dev/null +++ b/tools/cv610_i2c_dump.c @@ -0,0 +1,150 @@ +/* + * cv610_i2c_dump — read IMX662 registers over /dev/i2c on the CV610 bench. + * + * The sensor plugin's imx662_read_register() is a stub (the ISP only ever + * writes), so there is no way to confirm from the daemon that an init + * sequence actually landed. This does the 16-bit-address read the sensor + * needs, from a second process, while the pipeline is running. + * + * Derived from the i2c_dump.c bench tool in diegok3/firmware + * (feat/imx662-driver, utils/i2c_dump.c). + * + * DEV-ONLY. Not installed into any image; push it to /tmp and delete it. + * + * Build: + * toolchain/toolchain.hisilicon-hi3516cv6xx/bin/arm-openipc-linux-musleabi-gcc \ + * -O2 -s -Wall -Wextra -std=c99 -o out/cv610_i2c_dump tools/cv610_i2c_dump.c + * + * Run: + * scp -O out/cv610_i2c_dump root@192.168.2.181:/tmp/ + * ssh root@192.168.2.181 /tmp/cv610_i2c_dump # the default range set + * ssh root@192.168.2.181 /tmp/cv610_i2c_dump 0x3014 0x3015 0x302c:0x302d + * + * Output is one register per line, "0xADDR 0xVV" or "0xADDR ERR", so a diff + * of two dumps is the whole comparison. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Linux I2C_SLAVE_FORCE; the sensor plugin binds the same address, so the + * non-FORCE ioctl would be refused as busy. */ +#define I2C_SLAVE_FORCE 0x0706 + +#define DEFAULT_DEV "/dev/i2c-0" +#define DEFAULT_ADDR 0x1a /* IMX662_I2C_ADDR 0x34 >> 1 */ + +/* The ranges that matter for the power-on init block: mode/timing page, + * gain + reserved page, AD timing, and the reserved tail that Sony's + * sequence ends at (0x4549). */ +static const unsigned short g_default_ranges[][2] = { + { 0x3000, 0x30ff }, + { 0x3400, 0x34ff }, + { 0x3a50, 0x3a52 }, + { 0x3b00, 0x3c50 }, + { 0x3e00, 0x3eff }, + { 0x4490, 0x44e0 }, + { 0x4530, 0x4550 }, +}; + +static int g_fd = -1; + +static int reg_read(unsigned short reg, unsigned char *val) +{ + unsigned char buf[2] = { (unsigned char)(reg >> 8), (unsigned char)(reg & 0xff) }; + + if (write(g_fd, buf, sizeof(buf)) != (ssize_t)sizeof(buf)) + return -1; + if (read(g_fd, val, 1) != 1) + return -1; + return 0; +} + +static void dump_range(unsigned short start, unsigned short end) +{ + unsigned int reg; /* wider than u16 so end == 0xffff terminates */ + + for (reg = start; reg <= end; reg++) { + unsigned char val; + + if (reg_read((unsigned short)reg, &val) == 0) + printf("0x%04X 0x%02X\n", reg, val); + else + printf("0x%04X ERR\n", reg); + } +} + +/* "0x3014" or "0x3000:0x30ff" */ +static int parse_range(const char *arg, unsigned short *start, unsigned short *end) +{ + char *sep; + long a, b; + + a = strtol(arg, &sep, 0); + if (sep == arg || a < 0 || a > 0xffff) + return -1; + + if (*sep == '\0') { + b = a; + } else if (*sep == ':') { + const char *tail = sep + 1; + b = strtol(tail, &sep, 0); + if (sep == tail || *sep != '\0' || b < a || b > 0xffff) + return -1; + } else { + return -1; + } + + *start = (unsigned short)a; + *end = (unsigned short)b; + return 0; +} + +int main(int argc, char *argv[]) +{ + const char *dev = getenv("I2C_DEV"); + const char *addr_env = getenv("I2C_ADDR"); + long addr = DEFAULT_ADDR; + int i; + + if (dev == NULL) + dev = DEFAULT_DEV; + if (addr_env != NULL) + addr = strtol(addr_env, NULL, 0); + + g_fd = open(dev, O_RDWR); + if (g_fd < 0) { + fprintf(stderr, "open %s: %s\n", dev, strerror(errno)); + return 1; + } + if (ioctl(g_fd, I2C_SLAVE_FORCE, addr) < 0) { + fprintf(stderr, "I2C_SLAVE_FORCE 0x%02lx: %s\n", addr, strerror(errno)); + close(g_fd); + return 1; + } + + if (argc > 1) { + for (i = 1; i < argc; i++) { + unsigned short start, end; + + if (parse_range(argv[i], &start, &end) != 0) { + fprintf(stderr, "bad range '%s' (want 0xNNNN or 0xNNNN:0xNNNN)\n", + argv[i]); + close(g_fd); + return 2; + } + dump_range(start, end); + } + } else { + for (i = 0; i < (int)(sizeof(g_default_ranges) / sizeof(g_default_ranges[0])); i++) + dump_range(g_default_ranges[i][0], g_default_ranges[i][1]); + } + + close(g_fd); + return 0; +} diff --git a/tools/frame_shm_consumer_test.c b/tools/frame_shm_consumer_test.c index 3a224f1c..9534edf3 100644 --- a/tools/frame_shm_consumer_test.c +++ b/tools/frame_shm_consumer_test.c @@ -3,14 +3,19 @@ * 8-byte VencFrameMeta header, and reports frame rate, IDR cadence, frame * sizes, pts monotonicity, and Annex-B start-code integrity. * - * Usage: frame_shm_consumer_test [ring_name] [duration_s] + * Usage: frame_shm_consumer_test [ring_name] [duration_s] [dump.h265] + * [expected_slices] * ring_name default "venc_frames" * duration_s default 5 (0 = run until SIGINT) + * dump.h265 optional raw Annex-B output for decoder validation + * (use a FIFO to host storage on small embedded /tmp filesystems) + * expected_slices optional exact VCL count required in every frame * * Cross-compile for Star6E (Infinity6E): * toolchain/toolchain.sigmastar-infinity6e/bin/arm-openipc-linux-gnueabihf-gcc \ * -Os -Iinclude -D_GNU_SOURCE \ - * tools/frame_shm_consumer_test.c src/venc_frame_ring.c -lpthread \ + * tools/frame_shm_consumer_test.c src/venc_frame_ring.c src/h26x_util.c \ + * -lpthread \ * -o frame_shm_consumer * * Reports frame rate, IDR cadence, frame sizes, pts monotonicity, and @@ -25,6 +30,7 @@ #include #include +#include "h26x_util.h" #include "venc_frame_ring.h" static volatile int running = 1; @@ -34,6 +40,9 @@ int main(int argc, char **argv) { const char *name = (argc > 1) ? argv[1] : "venc_frames"; int duration = (argc > 2) ? atoi(argv[2]) : 5; + const char *dump_path = (argc > 3) ? argv[3] : NULL; + int expected_slices = (argc > 4) ? atoi(argv[4]) : 0; + FILE *dump = NULL; signal(SIGINT, sighandler); signal(SIGTERM, sighandler); @@ -43,6 +52,14 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to attach to frame ring '%s'\n", name); return 1; } + if (dump_path) { + dump = fopen(dump_path, "wb"); + if (!dump) { + perror("Failed to open H.265 dump"); + venc_frame_ring_destroy(r); + return 1; + } + } printf("Attached to frame ring '%s': %u slots x %u KB (epoch=%u, V%u, magic=0x%08X)\n", name, r->hdr->slot_count, r->hdr->slot_data_size / 1024, @@ -50,16 +67,25 @@ int main(int argc, char **argv) uint32_t buf_size = r->slot_data_size; uint8_t *buf = malloc(buf_size); - if (!buf) { fprintf(stderr, "OOM\n"); venc_frame_ring_destroy(r); return 1; } + if (!buf) { + fprintf(stderr, "OOM\n"); + if (dump) + fclose(dump); + venc_frame_ring_destroy(r); + return 1; + } uint32_t out_len = 0; unsigned long total_frames = 0, total_idr = 0, total_gdr = 0, total_enhance = 0, total_bytes = 0; uint32_t max_frame = 0, min_frame = 0xFFFFFFFF; unsigned long bad_meta = 0, bad_startcode = 0, pts_regress = 0; + unsigned long total_vcl = 0, vcl_frames = 0; + uint32_t min_vcl = UINT32_MAX, max_vcl = 0; uint32_t first_pts = 0, last_pts = 0; uint8_t last_gdr_len = 0; int have_first = 0; + int dump_started = 0; struct timespec ts_start, ts_now, ts_report; clock_gettime(CLOCK_MONOTONIC, &ts_start); @@ -80,6 +106,10 @@ int main(int argc, char **argv) int is_idr = (m.flags & VENC_FRAME_FLAG_IDR) != 0; int is_gdr = (m.flags & VENC_FRAME_FLAG_GDR) != 0; int is_enhance = (m.flags & VENC_FRAME_FLAG_ENHANCE) != 0; + size_t cursor = 0; + const uint8_t *nal; + size_t nal_len; + uint32_t vcl_count = 0; total_frames++; interval_frames++; @@ -102,6 +132,18 @@ int main(int argc, char **argv) !((fd[0] == 0 && fd[1] == 0 && fd[2] == 1) || (fd[0] == 0 && fd[1] == 0 && fd[2] == 0 && fd[3] == 1))) bad_startcode++; + while (h26x_util_annexb_next(fd, frame_len, &cursor, + &nal, &nal_len)) { + if (nal_len > 0 && h26x_util_hevc_nalu_type(nal, + nal_len) <= 31) + vcl_count++; + } + if (vcl_count > 0) { + total_vcl += vcl_count; + vcl_frames++; + if (vcl_count < min_vcl) min_vcl = vcl_count; + if (vcl_count > max_vcl) max_vcl = vcl_count; + } /* pts monotonicity (allow 32-bit wrap tolerance) */ if (have_first) { @@ -112,6 +154,16 @@ int main(int argc, char **argv) have_first = 1; } last_pts = m.pts; + /* Start raw dumps on an IDR so parameter sets and the reference + * chain are self-contained for offline decoder validation. */ + if (dump && is_idr) + dump_started = 1; + if (dump && dump_started && + fwrite(fd, 1, frame_len, dump) != frame_len) { + perror("Failed to write H.265 dump"); + running = 0; + bad_meta++; + } } clock_gettime(CLOCK_MONOTONIC, &ts_now); @@ -153,6 +205,11 @@ int main(int argc, char **argv) printf("Frame size: avg %lu min %u max %u bytes\n", total_frames ? total_bytes / total_frames : 0, total_frames ? min_frame : 0, max_frame); + printf("VCL slices: avg %.2f min %u max %u (%lu frames)\n", + vcl_frames ? (double)total_vcl / vcl_frames : 0.0, + vcl_frames ? min_vcl : 0, max_vcl, vcl_frames); + if (expected_slices > 0) + printf("VCL expected: %d per frame\n", expected_slices); printf("pts: first=%u last=%u span=%u\n", first_pts, last_pts, last_pts - first_pts); printf("Integrity: bad_meta=%lu bad_startcode=%lu pts_regress=%lu\n", @@ -162,8 +219,21 @@ int main(int argc, char **argv) __ATOMIC_ACQUIRE), (unsigned long)__atomic_load_n(&r->hdr->read_idx, __ATOMIC_ACQUIRE)); - - int ok = (total_frames > 0 && total_idr > 0 && + if (dump_path) + printf("H.265 dump: %s\n", dump_path); + + int dump_ok = 1; + if (dump) { + if (fclose(dump) != 0) { + perror("Failed to finalize H.265 dump"); + dump_ok = 0; + } + dump = NULL; + } + int vcl_ok = (vcl_frames == total_frames && vcl_frames > 0 && + min_vcl == max_vcl && + (expected_slices <= 0 || min_vcl == (uint32_t)expected_slices)); + int ok = (total_frames > 0 && total_idr > 0 && dump_ok && vcl_ok && bad_meta == 0 && bad_startcode == 0 && pts_regress == 0); printf("VERDICT: %s\n", ok ? "PASS" : "FAIL"); diff --git a/web/dashboard.html b/web/dashboard.html index 5bc18583..160effdd 100644 --- a/web/dashboard.html +++ b/web/dashboard.html @@ -236,6 +236,7 @@ .iq-result pre{font-size:.75rem;color:var(--text);line-height:1.5;white-space:pre-wrap} +.iq-note{color:var(--text-dim);font-size:.8rem} .iq-set-form{display:flex;gap:.5rem;align-items:center;margin-bottom:1.5rem;flex-wrap:wrap} .iq-set-form input{max-width:180px} @@ -339,6 +340,9 @@
API Reference
+
Image Quality
Recordings
@@ -491,7 +495,7 @@

Dual-Stream

- The IQ system provides direct access to SigmaStar ISP image processing parameters via runtime dlopen of libmi_isp.so. Parameters are organized by category and can be queried and modified live without restarting the pipeline. Changes take effect on the next frame. + Direct access to the ISP's image-processing parameters. Values are read back from the ISP rather than cached, and changes take effect on the next frame without restarting the pipeline.
@@ -506,7 +510,7 @@

Set Param

Parameter Categories

-

Click a parameter to select it for editing above.

+

Click a parameter to select it for editing above. * also selects op_type = manual; ° also selects op_type = auto.

@@ -514,7 +518,7 @@

Quer
- +
@@ -791,6 +795,11 @@

Quer document.getElementById('tab-'+id).classList.add('active'); + /* The IQ payload is a live ISP read, so fetch it on entry rather than at + page load, and refresh it each time so prefills cannot go stale. */ + if(id === 'iq') renderIQCategories().catch(e => + toast('IQ load failed: ' + e.message, false)); + if(window._recPoll){ clearInterval(window._recPoll); window._recPoll = null; } if(id === 'recordings'){ refreshRecordings(); @@ -1528,6 +1537,10 @@

${sec.title}

\u25BC
${sec.title}

\u25BC
${sec.title}\u25BC
inp.value).join(','); } try{ - const r = await api('/api/v1/iq/set?'+paramName+'.'+fd.n+'='+val); + const r = await api('/api/v1/iq/set?'+encodeURIComponent(paramName+'.'+fd.n)+'='+encodeURIComponent(val)); if(r.ok){ ok++; inputs.forEach(inp=>{inp.dataset.orig=inp.value;inp.classList.remove('changed');}); @@ -1651,9 +1664,80 @@

${sec.title}

\u25BC
{ + const param = g.name+'.'+f.name; + const range = f.count > 1 ? (f.count+' values, '+f.min+'–'+f.max) + : (f.min+'–'+f.max); + /* A value is only read while the block runs the half it lives in, so a + write selects that half. Without the hint, a set that "does nothing" + looks like a broken knob. */ + const hint = f.domain === 'manual' ? ' — also selects op_type = manual' + : f.domain === 'auto' ? ' — also selects op_type = auto' + : ''; + const mark = f.domain === 'manual' ? '*' : f.domain === 'auto' ? '\u00B0' : ''; + return ''+ + f.name+mark+' '; + }).join(''); + sec.innerHTML = '
'+ + '

'+g.name+'

'+g.fields.length+' fields'+ + '
'+ + '
'+chips+'
'; + container.appendChild(sec); + } +} + +/* Tab visibility comes from /api/v1/capabilities, which init() already fetches. + Probing /api/v1/iq for this instead cost a full ISP sweep on every page load + -- 62 getter calls on star6e -- purely to decide whether to draw a tab. */ +function applyIQCapability(routes){ + const iqTab = document.getElementById('tab-btn-iq'); + const impBtn = document.getElementById('iq-import-btn'); + /* Hide ONLY on a positive false. An absent or unreadable capabilities + response must leave both controls visible -- a backend that cannot be + asked is not a backend that lacks the surface. */ + if(iqTab) iqTab.hidden = !!(routes && routes.iq === false); + /* /api/v1/iq/import is compiled per backend and 501s where it is absent. */ + if(impBtn) impBtn.hidden = !!(routes && routes.iq_import === false); +} + +/* Loaded on entry to the IQ tab rather than at page load, and re-loaded on + every entry so a chip cannot prefill a value the ISP stopped holding -- a + pipeline reinit reseeds the whole ISP from the sensor plugin. */ +async function renderIQCategories(){ const container = document.getElementById('iq-categories'); + container.innerHTML = '
Loading\u2026
'; + + let data = null, err = null; + try{ + const r = await api('/api/v1/iq'); + if(r && r.ok && r.data) data = r.data; + else err = (r && r.error && r.error.message) || 'backend returned no data'; + }catch(e){ err = e.message; } + + if(!data){ + /* Report it in the tab. Hiding the tab here would strand the operator with + no diagnostic and no retry short of reloading the page. */ + container.textContent = 'Image Quality unavailable: ' + err + + ' \u2014 re-open this tab to retry.'; + return; + } + container.innerHTML = ''; + + if(Array.isArray(data._schema)){ + renderIQSchema(container, data._schema); + return; + } + for(const cat of IQ_CATEGORIES){ const sec = document.createElement('div'); sec.className = 'iq-cat-section collapsed'; @@ -1689,7 +1773,7 @@

${sec.title}

\u25BC
${sec.title}\u25BC
({ok:false})), - api('/api/v1/capabilities'), + api('/api/v1/capabilities').catch(()=>({ok:false})), - api('/api/v1/version'), + api('/api/v1/version').catch(()=>({ok:false})), api('/api/v1/modes').catch(()=>({ok:false})) @@ -1782,10 +1866,11 @@

${sec.title}

\u25BC
${sec.title}\u25BC