From ff19f952b49bd4ec8940ab25a9370da27fd2a2ee Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 02:15:04 +0800 Subject: [PATCH 1/7] fix(top): bound distributed large Top-N merge Replace the blocking global MergeOrder materialization for large distributed Top-N plans with a version-gated hierarchical ordered-stream merge. Preserve the existing path for small candidate sets and rolling upgrades, and add topology, lifecycle, codec, cancellation, and comparator coverage. Fixes #28285 --- docs/design/bounded_distributed_topn.md | 384 ++++++ pkg/defines/const.go | 3 +- pkg/pb/pipeline/pipeline.pb.go | 1143 +++++++++-------- pkg/sql/colexec/mergetop/stream.go | 461 +++++++ pkg/sql/colexec/mergetop/top.go | 6 + pkg/sql/colexec/mergetop/top_test.go | 216 ++++ pkg/sql/colexec/mergetop/types.go | 22 +- pkg/sql/colexec/top/types.go | 14 +- .../allocation_account_lifecycle_test.go | 44 + pkg/sql/compile/compile.go | 127 +- pkg/sql/compile/merge_top_fallback_test.go | 145 ++- pkg/sql/compile/operator.go | 2 + pkg/sql/compile/remoterun.go | 7 +- pkg/sql/compile/remoterunClient.go | 6 + pkg/sql/compile/remoterun_test.go | 19 + pkg/sql/compile/scope.go | 93 +- pkg/sql/compile/scope_test.go | 51 + pkg/sql/compile/types.go | 4 + pkg/vm/process/pipeline_edge.go | 6 + pkg/vm/process/pipeline_edge_test.go | 9 + proto/pipeline.proto | 3 + 21 files changed, 2181 insertions(+), 584 deletions(-) create mode 100644 docs/design/bounded_distributed_topn.md create mode 100644 pkg/sql/colexec/mergetop/stream.go diff --git a/docs/design/bounded_distributed_topn.md b/docs/design/bounded_distributed_topn.md new file mode 100644 index 0000000000000..b0c2c31b410b1 --- /dev/null +++ b/docs/design/bounded_distributed_topn.md @@ -0,0 +1,384 @@ +# Bounded distributed ORDER BY / LIMIT + +Status: implemented and validated on 2026-09-07; ready for review. +Owner: issue #28285; regression constraint: #27968 must remain executable. +Source baseline: `6e5f82f568b1ec3e013e8d4ab9031b2360300b84`. +Implementation branch: `xp/fix-28285-bounded-merge-top`. + +## Problem and review decision + +Reject the earlier proposal to unconditionally restore resident MergeTop. +It addresses the #28285 plan regression but leaves large valid outputs limited +by one allocation and mistakes a bound on row count for a bound on physical +capacity. Keep the vector ownership/error-classification fixes from #27999. + +The required result is efficient completion within available memory and spill +resources, including both the large-LIMIT narrow-row case and wide payloads. +A controlled error is appropriate when actual resources or the supported +single-record representation are exhausted. It is not an acceptable substitute +for executing an otherwise feasible query solely because all output rows were +put in one vector. + +Observed facts: + +- #28285 identifies `17c161a3`, immediately after `0db2d5e`, as the regression. + It replaces global MergeTop with blocking MergeOrder followed by Limit for + large/runtime multi-scope LIMITs. +- MergeOrder receives every candidate batch before emitting its first result. + MergeTop also consumes all input, but discards losing candidates while doing so. +- MergeTop retains all selected payload in one batch, then shuffles and returns + that batch. Allocation peaks include input clones and replacement capacity. +- In `Vector.Copy`, replacing a non-inline variable-length value appends area + bytes. Dead payload remains until reclamation; N live rows do not imply only + N rows' payload capacity. This also matters for variable-length local Top keys. +- #27968 requests up to 2,499,999 VECF32(1024) payloads: approximately 9.54 GiB + for that column if the limit is filled. The issue reports the actual vector + grow crossing 2 GiB. That ceiling can reject a feasible query even on a + machine with sufficient total RAM; actual post-delete row count must be + recorded in reproduction, not inferred from LIMIT. +- Local Top spill logic is unchanged between the two historical commits. + It writes incoming full-row batches and reconstructs selected rows in chunks. +- A WaitRegister can have multiple senders. `newParallelScope` duplicates the + operator tree; ordinary Merge and per-CN scope grouping can interleave batches. + An individually sorted batch is not evidence of a sorted receiver stream. + +Existing 55 evidence is diagnostic, not acceptance of this new proposal: +10M/500K took 10.92s versus 13.64s; old 50M/2.5M INSERT took 290.7s. +The new 50M timeout occurred while executing EXPLAIN PHYPLAN, which runs its +inner query. It is not a matched INSERT timing. Finding no directory entries +does not prove zero spill: open temporary files can already be unlinked. + +## Algebra and contracts + +Let S be input rows, P actual producers (not merely CNs), and K the demanded +ordered prefix. For LIMIT L OFFSET O, K = O + L only when checked addition and +the SQL semantics permit it. Otherwise retain the existing correct full-order +path. LIMIT 0 and runtime parameters retain their established public semantics. + +For the same ordering relation and bag semantics: + +`TopK(union inputs) = TopK(union TopK(each input))`. + +Rows excluded from a prefix have K rows ahead of them in that subset. They +cannot be necessary to produce a valid global prefix. Equal keys preserve +multiplicity; arbitrary tie selection is allowed only where SQL leaves it +unspecified. Tests use unique tie-breakers when exact row identity matters. + +After each producer has an ordered stream, its head is a bound on its unseen +tail. The minimum of all active heads is the next output. No output is safe +while an active stream has neither a head nor EOF. A slow stream must be waited +for or failed/cancelled, never treated as empty. + +This supports these invariants: + +1. Ordinary Top-K returns exactly min(K, S) rows in the existing SQL order. +2. Global merging does not retain K payload rows or consume all P*K candidates + before it can return output. +3. Memory is bounded in physical bytes, including transport and allocation + overlap. Large result cardinality alone never requires one large allocation. +4. Spill remains an executable path when the resident selection state does not + fit. Memory, disk, FD, metadata, and merge depth have separate bounds. +5. Success, rejection, error, cancellation, and reuse have one cleanup owner. +6. Early stop applies only to the exclusively owned pure read subtree. Shared + producers, found-rows consumers, and required effects retain their semantics. + +## Selected architecture + +```text +scan / filter / join / aggregate output + -> local Top-K builder, resident or external + -> ordered stream per actual worker + -> bounded ordered fan-in within CN, when necessary + -> ordered CN stream + -> bounded ordered fan-in at coordinator + -> OFFSET / LIMIT semantics -> SELECT or transactional INSERT consumer +``` + +The new capability is an ordered gather at a scope boundary. Keep it distinct +from MergeOrder, whose input contract is a collection of sorted runs rather +than one sorted stream per receiver. It does not add a global spill store. +PostgreSQL's Gather Merge provides an architectural precedent for preserving +worker order; MatrixOne must additionally close its own parallel expansion, +transport, accounting, and cleanup contracts. See the +[PostgreSQL documentation](https://www.postgresql.org/docs/17/how-parallel-query-works.html). + +Implementation v1 uses the following deliberately narrow activation contract: + +- protocol version 53 and the serialized `Top.top_ordered_output` bit prove + that every participating CN understands the boundary; +- the planner activates it only when every ORDER BY key is already a materialized + input column. Non-column expressions retain the compatible MergeTop or + MergeOrder plan until hidden-key materialization is implemented, so a + volatile expression is never silently reevaluated as a new ordering key; +- every runtime DOP worker gets its own one-sender edge, a CN-local gather + reduces those streams to one ordered CN stream, and the coordinator repeats + the same bounded merge; +- a static plan uses the hierarchy only when the estimated candidate set + `min(input rows, K * runtime fanout) * row size` exceeds 512 MiB. This is four + MergeOrder spill windows: below it, the existing vectorized path avoids the + extra hierarchy. Runtime parameters use the full estimated input as their + candidate upper bound; missing/invalid estimates choose the bounded path; +- output is bounded by both 8,192 rows and 64 MiB (except that one individually + valid row must be allowed to make progress). Fixed and variable-width winner + runs are copied in bounded chunks using actual varlen payload sizes; +- cleanup shares one 30-second deadline across every receiver. The first + implementation drains already-produced local Top output rather than + introducing a new receiver-stop terminal state; producer early-stop remains + disabled until error arbitration can prove that it cannot hide a substantive + producer failure. This preserves correctness while still removing the + blocking global MergeOrder materialization that caused #28285. + +### A. Preserve order across the physical topology + +- Introduce an explicit ordered-input scope/operator contract with ordering + expressions, optional prefix demand, and one logical sorted stream per edge. + Ordering keys are materialized before the boundary and carried with the row; + derived/volatile keys are not independently reevaluated by successive merges. +- After runtime DOP expansion, each Top producer has a distinct local edge to + an ordered gather. Do not let cloned connectors share an ordered receiver. + Keep parallel scans; do not force the entire scan to DOP=1. +- Per-CN regrouping must use ordered fan-in on this path. Preserve the existing + sibling dependency ownership that makes remote trees independently runnable. + CN count and receiver count are not substitutes for this proof. +- Plain Merge, shuffle, and arbitrary projection invalidate an ordering proof + unless explicitly shown to preserve the same keys. Validate the final graph + after cloning/grouping and after remote decode, before any row is published. +- Empty and failed-to-start producers complete their own edge. Do not invent + EOF to get around missing registration or a scheduling failure. + +### B. Stream the ordered prefix with bounded buffers + +- Maintain one borrowed current batch and one cursor per input; the heap holds + stream indexes, not copies of result rows. Refill only an exhausted input. +- Append winners into a bounded output batch. Release consumed input batches + after their referenced rows have been copied. No final K-row Shuffle exists. +- Use row and byte limits for chunks. Reduce a chunk before publication on + pressure; a single large row must satisfy the existing record/allocation + limit and be admitted explicitly. A row cap alone is insufficient. +- Credits bound prefetch by both count and bytes. Include decode buffers, + sender spool buffers, borrowed batches, output, and heap capacity in the + query/CN account. Reuse existing batch-flow and allocation primitives. +- Bound per-node fan-in using a tree where needed. Also bound the sum of all + active tree nodes on a CN: a tree alone does not bound total memory. +- Provide capacity for a minimal head window and output progress before + admitting the stage. If necessary choose lower DOP before producer startup; + never wait for memory that can only be released by a blocked downstream. +- Check for errors/cancellation between bounded work units. After K rows, + publish prefix completion and stop further requests. Already admitted + prefetch is finite and included in the accounting and cost model. + +### C. Complete the local Top resource contract + +The global change removes the reported P*K materialization. Local Top must +also have a bounded response for wide keys and repeated candidate replacement. + +- Keep a resident heap fast path for fitting selection state. SQL row counts + and estimated widths can guide policy, but exact allocation admission owns + safety. Compact dead variable-length bytes at a bounded threshold, with + admitted replacement capacity, or transition to external selection. +- Reserve a bounded spill/output working window before growing resident state + to its limit. Reclamation must not depend on a large new allocation after + the resident state has consumed the entire account. +- At a committed input boundary, externalize the current surviving candidates + and process the remaining input as byte-bounded sorted runs. The Top-K + identity permits discarding earlier losers. A failed multi-column mutation + cannot be used as that boundary: preflight/checkpoint unpublished changes, + and preserve the input cursor until the mutation or transition commits. +- Publish a run only after its write succeeds. Release its source state only + after publication. On partial write or failed recovery, abort the query and + clean all owned resources; never replay a partly applied row as new input. +- Use bounded fan-in external merging, truncating each completed merged run + to K. Keep merge-pass depth and resident run metadata bounded; use the + existing run management/codec where possible, with explicit common ownership + for primitives shared by Top and MergeOrder. Do not copy an entire spill engine. +- Disk admission covers live input runs plus the new output run until commit. + FD admission covers active readers and writer, not total run count. Exhausted + disk, FDs, depth, or the minimal working set returns the appropriate error. +- Output an ordered stream in chunks from either local mode. This permits + wide payloads and wide keys without a single K-row payload/key vector. + +Local external selection can still write substantial input data and require +multiple passes. This proposal does not promise O(K) total spill or avoid the +full scan of an unordered source. Further payload read-locality optimization +requires separate measured evidence and is not a claimed benefit here. + +## Ownership, errors, and generations + +| State/owner | Transition or wait | Required terminal behavior | +|---|---|---| +| Ordered stage / scope | prepare -> register/admit -> prime all heads | Failed admission/start closes created edges and propagates the real error | +| Gather input cursor | borrow -> compare/copy -> release -> refill | One receiver owns the borrow; no next receive invalidates another stream's batch | +| Output batch / gather | build -> publish to consumer | Never publish partially built rows after an allocation or comparison error | +| Local builder | resident -> externalizing -> external -> ordered output | Run publication is the state switch; old ownership remains valid until then | +| Prefix completion / scope | emit K -> stop owned producers -> quiesce | Internal stop is success; query cancel and substantive errors remain errors | +| Shared input / consumer | early stop of one reader | Release that reader only; do not cancel other consumers | +| Transport / scope | full credit queue or missing head | Independent cancellation/stop wakes both sender and receiver | +| Prepared attempt | terminate -> quiesce -> Reset -> new admission | No previous cursor, EOF, limit, credit, error, or callback enters the next generation | + +Reuse End/Error/Abort, StopSending, and current scope error arbitration. +Call returns execution status; Reset performs terminal signaling. Do not send +terminals from Call. V1 cleanup drains the finite remaining local Top output +because the current protocol cannot distinguish an intentional prefix stop from +a producer failure without risking error masking. Concurrent teardown shares a +bounded deadline rather than paying one full timeout per edge. A later protocol +may stop producers early only after preserving any earlier substantive error. + +INSERT commits only after successful statement completion and producer +quiescence. An error after partial consumption must roll back the statement. +SELECT may have streamed rows before a later error, following its existing +protocol; never label that execution successful. + +The minimal wait graph is producer -> credit -> receiver -> missing head from +another producer. Stage startup must make every required producer runnable. +No consumer may monopolize the execution slots needed to start the producer +it waits on. Inject submission failure and a constrained worker pool to prove it. + +## Compatibility and rollout + +This is R3 design work: it changes distributed scope topology, ownership, +runtime expansion, and a material execution hot path. It requires its own +design review before implementation approval. + +Encode ordered-gather capability and configuration explicitly in the pipeline +representation. Both cloning and remote encode/decode preserve it. Version 53 +is the rollout gate. A node that cannot honor the ordering contract must +never silently decode it as ordinary Merge or MergeTop. + +New plans activate only when all participating nodes support the capability; +otherwise use the existing compatible plan before execution. Mixed-version +fallback may retain today's performance and must be visible in EXPLAIN. +Never change algorithms after result publication to accommodate an old peer. +Topology/capability changes invalidate a cached prepared physical plan. + +Retain existing row comparator, NULL/NaN/type rules, prepared provenance, and +spill codec. No table/catalog or persistent storage migration is proposed. +Spill is attempt-local and not resumable after restart. Rollback uses the +compatible planner path for new attempts after active generations quiesce. + +Diagnostics expose bounded per-operator counters: consumed/emitted rows, +stream count, physical peak bytes, spill read/write bytes, merge passes, and +prefix-stop reason. Do not add per-row logging, source-row labels, or a second +estimated memory ledger. All resources remain charged to the owning tenant. + +## Cost model and alternatives + +Let F be fan-in, b the admitted input-window bytes, q the admitted queued bytes +per edge, and o the output-window bytes. One gather uses approximately +F*(b+q)+o plus O(F) cursor/heap state; allocation accounts enforce the actual +sum across the CN. None of these buffers grows with K. + +For a flat merge, selection CPU is O(P + K log P); a balanced merge tree can +perform O(K log P) comparisons plus bounded prefetch/initialization work per +level. Its buffers and copies at every level must be measured. Flat input +consumption is K plus per-stream lookahead and finite prefetch, capped by +available rows. This is not an exact K-row network or disk-read claim. + +The static activation estimate is deliberately about the pre-global-merge +candidate set, not the final K rows. The existing path remains preferable for +small inputs even when K itself is large relative to S. On 55, 1M input / +500K limit with approximately 146-byte rows ran in 1.15--1.28s through the +compatible path versus 2.82--2.94s when hierarchy was forced. At the issue-like +5% ratio, 10M input / 500K limit ran in 3.56--3.62s with bounded hierarchy +versus 21.19--21.49s on main. These measurements motivated, but do not replace, +the byte estimate and its conservative unknown-statistics fallback. + +The issue-shaped 100M input / 5M limit INSERT completed in 111.57s on the +fixed build and produced exactly 5,000,000 distinct keys from 0 through +4,999,999. The same data and service configuration on main `6e5f82f568` +remained incomplete at 300s; canceling the client rolled the target table back +to zero rows. Thus the matched one-CN comparison establishes at least a 2.69x +speedup without extrapolating the 300s lower bound. + +For 50M input and K=2.5M with 64-byte payload, global resident MergeTop needs +at least about 160 MB for that payload alone, before descriptors, keys, input +copies, dead area, and shuffle overlap. Streaming gather retains only windows. +For #27968, 4 KiB vector payloads remain bounded batches across the same path. +End-to-end improvement depends on how much time remains in local selection, +storage reads, and INSERT. No speedup multiplier is promised before measurement. + +| Alternative | Decision | +|---|---| +| Restore resident MergeTop for every K | Reject as complete fix: single-allocation ceiling and variable-length replacement history remain | +| Raise threshold / trust row-width statistics | Reject as safety design: physical capacity and stale/unknown statistics differ | +| Global spill Top on unordered candidates | Possible compatible algorithm, but existing implementation writes all candidates and can repeat local payload I/O | +| Give existing MergeOrder a terminal LIMIT only | Insufficient: still receives/materializes every candidate before first output | +| Ordered gather plus bounded local selection | Selected: uses order already established by producers, bounds global state, supports external local execution | + +## Validation and delivery sequence + +Implementation acceptance completed on 55 (`10.222.1.55`) with the same +service configuration and data for fixed/main comparisons: + +- 1M input / K=500K stayed on the compatible path and completed in 1.286s, + matching the main-path envelope; forcing the hierarchy here was rejected + after it measured 2.82--2.94s. +- 10M input / K=500K completed in 3.56--3.62s versus 21.19--21.49s on main. +- 100M input / K=5M completed in 111.57s with exactly 5M distinct keys; main + did not complete within 300s and cancellation left the INSERT target empty. +- ASC/DESC, NULL and duplicate keys, LIMIT 0 and LIMIT beyond cardinality, + runtime parameters, expression fallback, cancellation, and a following + healthy query were exercised. Removing the final global merge was also + rejected by a black-box counterexample: parallel INSERT applied LIMIT per + worker instead of globally. +- Focused package, topology, codec, allocation-generation, and race tests pass; + static analysis reports zero issues. The five failures in the full compile + package are identical Parquet fanout failures on the clean base commit. + +1. Prove typed topology and a deterministic minimal gather, including shared + receiver and runtime-DOP counterexamples, before large benchmarks. +2. Implement ordered fan-in, byte-bounded output, and teardown as one closure. + Include encode/decode/version/clone tests and public multi-CN execution. +3. Close local variable-length reclamation and resident-to-external transition + with the common spill primitives. This is part of the full resource claim, + not optional if those counterexamples fail. Split commits by owner closure. +4. Run the combined implementation on 55 and review the complete change map. + Functional partial delivery cannot be described as full #28285/#27968 closure. + +| Counterexample/axis | Independent oracle | +|---|---| +| Interleaved sorted batches from two workers on one edge | Final topology rejects/repairs it before output; exact reference ordering | +| One slow/empty/failed producer; bounded scheduling slots | No premature output or fabricated EOF; injected release/error terminates | +| K=0/1, 16383/16384/16385, K>=S, parameter K, OFFSET overflow | Exact result and cardinality; reuse behaves like a fresh query | +| ASC/DESC, compound keys, NULLs, duplicates, NaN, expressions | Existing comparator semantics; full sort/reference with unique ties where required | +| N fixed, replacement count grows, increasing/decreasing payload lengths | Accounted physical peak remains within byte budget; same correct survivors | +| VECF32(1024) payload; large variable-length sort keys | Success with enough total resources despite a reduced per-allocation cap | +| Pressure before/after candidate mutation and run publication | No lost/duplicate row; exact cleanup; external result equals resident reference | +| Disk/FD failure, partial/truncated spill, allocation rejection | Correct error class; zero terminal ownership; healthy following query | +| Full queue/held ACK, cancel, disconnect, stop racing real error | All owners quiesce; actual error is not masked; no producer drains unused output | +| Shared producers, SQL_CALC_FOUND_ROWS, DML consumer | Required work/count preserved; statement rollback after downstream failure | +| Old/new peers, prepared reuse after topology/capability change | Correct fallback/recompile; no silent ordered-to-unordered decode | +| Result identity and cleanup through SQL | COUNT and exact ordered/reference comparison; duplicate multiplicity; same-instance rerun | + +Use injected small limits for UT/BVT boundaries, not huge fixtures. Preserve +existing useful tests and add only distinct proof. Run focused/package/race +evidence for changed owners and consumers, then SQL tests on 55 only. + +Performance uses direct target SQL, without an unmeasured executing EXPLAIN in +front of it. Compare historical good, verified current main, and fixed build +under identical topology, DOP, rows, schema, data distribution, cache policy, +and resource limits. Use an ordered/interleaved repeated schedule to detect +noise rather than claiming stability from one run. Record build hashes and +data fingerprints. Compare 1M, 10M, 50M, and 100M with 1/2/3 CN where the +dimension adds evidence; vary narrow/wide rows and K/S, including high selectivity. + +Acceptance requires both original scenarios to succeed and the narrow-row +50M/100M performance to recover to the historical-good envelope in matched +runs. Report the observed variance; any material regression (initial alert +threshold 5%, subject to baseline variance) requires investigation. Small K +and single-CN controls must also remain within the measured baseline envelope. +Gather input rows must follow prefix-plus-prefetch, and gather spill must be +zero. Local spill, total CPU, RSS, allocation peaks, I/O, and cleanup are +reported separately. If gains are below expectation, attribute the remaining +time before extending the design. + +A finite suite cannot prove that no counterexample exists. Acceptance means +the stated invariants, reachable transitions, and mapped failure dimensions +have evidence; untested dimensions and known limits remain explicit. + +## References + +- https://github.com/matrixorigin/matrixone/issues/28285 +- https://github.com/matrixorigin/matrixone/issues/27968 +- https://github.com/matrixorigin/matrixone/pull/27999 +- [Memory accounting implementation](query_memory_control_and_attribution_impl.md) +- [PostgreSQL 17 Gather Merge](https://www.postgresql.org/docs/17/how-parallel-query-works.html) diff --git a/pkg/defines/const.go b/pkg/defines/const.go index dd2c26e7427b6..35eba8903e9ce 100644 --- a/pkg/defines/const.go +++ b/pkg/defines/const.go @@ -88,7 +88,8 @@ const ( MORPCVersion50 int64 = 50 // ordered ODKU evaluation and logical affected-row metadata MORPCVersion51 int64 = 51 // per-action ODKU validation and statement-local target arbitration MORPCVersion52 int64 = 52 // MySQL binary JSON subtype tags - MORPCLatestVersion = MORPCVersion52 + MORPCVersion53 int64 = 53 // ordered-stream distributed Top-N merge + MORPCLatestVersion = MORPCVersion53 ) // DefaultLockWaitTimeoutSeconds is shared by the frontend default and by diff --git a/pkg/pb/pipeline/pipeline.pb.go b/pkg/pb/pipeline/pipeline.pb.go index 7790807d94029..8ba733b3c65d2 100644 --- a/pkg/pb/pipeline/pipeline.pb.go +++ b/pkg/pb/pipeline/pipeline.pb.go @@ -4841,11 +4841,14 @@ type Instruction struct { // PROJECTION only: vector-level expansion metadata for planner-generated // ROLLUP/CUBE grouping sets. Older CNs ignore these fields, so planning is // gated by MORPCVersion49 until every participant understands them. - ProjectionGroupingFlags []bool `protobuf:"varint,60,rep,packed,name=projection_grouping_flags,json=projectionGroupingFlags,proto3" json:"projection_grouping_flags,omitempty"` - ProjectionGroupingSetCount int32 `protobuf:"varint,61,opt,name=projection_grouping_set_count,json=projectionGroupingSetCount,proto3" json:"projection_grouping_set_count,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ProjectionGroupingFlags []bool `protobuf:"varint,60,rep,packed,name=projection_grouping_flags,json=projectionGroupingFlags,proto3" json:"projection_grouping_flags,omitempty"` + ProjectionGroupingSetCount int32 `protobuf:"varint,61,opt,name=projection_grouping_set_count,json=projectionGroupingSetCount,proto3" json:"projection_grouping_set_count,omitempty"` + // TOP only: every runtime worker must be consolidated into one stream that + // remains ordered across batch boundaries before leaving its CN. + TopOrderedOutput bool `protobuf:"varint,62,opt,name=top_ordered_output,json=topOrderedOutput,proto3" json:"top_ordered_output,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Instruction) Reset() { *m = Instruction{} } @@ -5251,6 +5254,13 @@ func (m *Instruction) GetProjectionGroupingSetCount() int32 { return 0 } +func (m *Instruction) GetTopOrderedOutput() bool { + if m != nil { + return m.TopOrderedOutput + } + return false +} + type AnalysisList struct { List []*plan.AnalyzeInfo `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -6617,551 +6627,553 @@ func init() { func init() { proto.RegisterFile("pipeline.proto", fileDescriptor_7ac67a7adf3df9c7) } var fileDescriptor_7ac67a7adf3df9c7 = []byte{ - // 8700 bytes of a gzipped FileDescriptorProto + // 8726 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7c, 0x4b, 0x6c, 0x1d, 0x47, 0xb6, 0x98, 0x2f, 0xc9, 0xfb, 0x3b, 0xf7, 0xcb, 0x22, 0x45, 0x5d, 0x7d, 0x6c, 0xd1, 0xd7, 0x96, - 0x4c, 0xcb, 0x36, 0x25, 0xd3, 0xf6, 0xf8, 0x33, 0xe3, 0xf1, 0xa3, 0x28, 0xc9, 0xe6, 0x58, 0x94, - 0x38, 0x4d, 0xea, 0x19, 0x30, 0x90, 0x34, 0x9a, 0xdd, 0x75, 0x2f, 0xdb, 0xec, 0xdb, 0xdd, 0xea, - 0xea, 0x96, 0x48, 0xad, 0x92, 0x65, 0x82, 0xec, 0xf3, 0x90, 0xd5, 0x04, 0xc9, 0x22, 0x41, 0x96, - 0xc1, 0x64, 0x99, 0xf5, 0x43, 0x90, 0xc5, 0xac, 0xb2, 0x0c, 0x82, 0x99, 0x65, 0x80, 0x24, 0x08, - 0x90, 0x20, 0x48, 0xf0, 0x80, 0xe0, 0x9c, 0x53, 0xd5, 0xdd, 0xf7, 0xf2, 0x4a, 0xb2, 0x9d, 0xe0, - 0x6d, 0xde, 0xdb, 0x75, 0x9f, 0x73, 0xaa, 0xba, 0xba, 0xea, 0x7c, 0xeb, 0x9c, 0x2a, 0xe8, 0xc6, - 0x7e, 0x2c, 0x03, 0x3f, 0x94, 0x9b, 0x71, 0x12, 0xa5, 0x91, 0x68, 0x98, 0xf7, 0xcb, 0x1f, 0x8c, - 0xfd, 0xf4, 0x38, 0x3b, 0xda, 0x74, 0xa3, 0xc9, 0xad, 0x71, 0x34, 0x8e, 0x6e, 0x11, 0xc1, 0x51, - 0x36, 0xa2, 0x37, 0x7a, 0xa1, 0x27, 0x6e, 0x78, 0x19, 0x82, 0xc8, 0x3d, 0x31, 0xcf, 0x71, 0xe0, - 0x84, 0xfa, 0xb9, 0x97, 0xfa, 0x13, 0xa9, 0x52, 0x67, 0x12, 0x6b, 0x40, 0x33, 0x3d, 0xd5, 0xb8, - 0xe1, 0xef, 0x6a, 0x50, 0xdf, 0x93, 0x4a, 0x39, 0x63, 0x29, 0x86, 0xb0, 0xa8, 0x7c, 0x6f, 0x50, - 0x59, 0xaf, 0x6c, 0x74, 0xb7, 0xfa, 0x9b, 0xf9, 0xb0, 0x0e, 0x52, 0x27, 0xcd, 0x94, 0x85, 0x48, - 0xa4, 0x71, 0x27, 0xde, 0x60, 0x61, 0x96, 0x66, 0x4f, 0xa6, 0xc7, 0x91, 0x67, 0x21, 0x52, 0xf4, - 0x61, 0x51, 0x26, 0xc9, 0x60, 0x71, 0xbd, 0xb2, 0xd1, 0xb6, 0xf0, 0x51, 0x08, 0x58, 0xf2, 0x9c, - 0xd4, 0x19, 0x2c, 0x11, 0x88, 0x9e, 0xc5, 0xdb, 0xd0, 0x8d, 0x93, 0xc8, 0xb5, 0xfd, 0x70, 0x14, - 0xd9, 0x84, 0xad, 0x12, 0xb6, 0x8d, 0xd0, 0xdd, 0x70, 0x14, 0xdd, 0x45, 0xaa, 0x01, 0xd4, 0x9d, - 0xd0, 0x09, 0xce, 0x94, 0x1c, 0xd4, 0x08, 0x6d, 0x5e, 0x45, 0x17, 0x16, 0x7c, 0x6f, 0x50, 0x5f, - 0xaf, 0x6c, 0x2c, 0x59, 0x0b, 0xbe, 0x87, 0xdf, 0xc8, 0x32, 0xdf, 0x1b, 0x34, 0xf8, 0x1b, 0xf8, - 0x2c, 0x86, 0xd0, 0x0e, 0xa5, 0xf4, 0x1e, 0x46, 0xa9, 0x25, 0xe3, 0xe0, 0x6c, 0xd0, 0x5c, 0xaf, - 0x6c, 0x34, 0xac, 0x29, 0x98, 0xb8, 0x0c, 0x0d, 0x4f, 0x1e, 0x65, 0xe3, 0x3d, 0x35, 0x1e, 0xc0, - 0x7a, 0x65, 0xa3, 0x69, 0xe5, 0xef, 0xe2, 0x10, 0x2e, 0x26, 0xf2, 0x49, 0x26, 0x55, 0x2a, 0x3d, - 0x3b, 0x95, 0x4e, 0xe2, 0x45, 0xcf, 0x42, 0x7b, 0x12, 0x79, 0x72, 0xd0, 0xa2, 0x19, 0xb8, 0x5a, - 0x9e, 0xa5, 0x44, 0x3a, 0x93, 0x43, 0x4d, 0xb4, 0x17, 0x79, 0xd2, 0xba, 0x90, 0x37, 0x2e, 0x83, - 0x85, 0x05, 0x6b, 0x8e, 0xeb, 0xca, 0xf8, 0x7c, 0xa7, 0xed, 0x1f, 0xd1, 0xe9, 0xaa, 0x69, 0x3b, - 0xd5, 0xe7, 0x57, 0x70, 0xb5, 0x18, 0xe9, 0x91, 0x93, 0xba, 0xc7, 0xb6, 0x9b, 0x48, 0xcf, 0x4f, - 0x6d, 0x37, 0xca, 0xc2, 0x74, 0xd0, 0x59, 0xaf, 0x6c, 0x74, 0xac, 0x4b, 0x39, 0xcd, 0x1d, 0x24, - 0xd9, 0x21, 0x8a, 0x1d, 0x24, 0x78, 0x49, 0x07, 0x47, 0x67, 0xa9, 0x54, 0x83, 0x2e, 0x4d, 0xf4, - 0xdc, 0x0e, 0xee, 0x20, 0x81, 0xf8, 0x12, 0xae, 0xe4, 0x7f, 0x35, 0x67, 0x00, 0x3d, 0x1a, 0xc0, - 0xc0, 0x90, 0x9c, 0xfb, 0xfe, 0x0b, 0x9b, 0xf3, 0xe7, 0xfb, 0xf4, 0xf9, 0x79, 0xcd, 0xf9, 0xeb, - 0xd7, 0xa1, 0xcb, 0xad, 0x14, 0x0e, 0x30, 0x74, 0xe5, 0x60, 0x99, 0x5a, 0x74, 0x08, 0x7a, 0xa0, - 0x81, 0xe2, 0x7d, 0x10, 0x4c, 0xe6, 0xb8, 0x27, 0x05, 0xa9, 0x20, 0xd2, 0x3e, 0x61, 0xb6, 0xdd, - 0x13, 0x43, 0xfd, 0xc5, 0xd2, 0x5f, 0xfc, 0xee, 0xda, 0x6b, 0xc3, 0xc7, 0xd0, 0xdc, 0x89, 0xc2, - 0x50, 0xba, 0x69, 0x94, 0x88, 0x6b, 0xd0, 0x32, 0x8b, 0x63, 0x6b, 0x59, 0xa9, 0x5a, 0x60, 0x40, - 0xbb, 0x9e, 0x78, 0x07, 0x7a, 0xae, 0xa1, 0xb6, 0xfd, 0xd0, 0x93, 0xa7, 0x24, 0x2c, 0x55, 0xab, - 0x9b, 0x83, 0x77, 0x11, 0x3a, 0xfc, 0x2f, 0x8b, 0x50, 0x3f, 0x38, 0xce, 0x46, 0xa3, 0x40, 0x8a, - 0xb7, 0xa1, 0xa3, 0x1f, 0x77, 0xa2, 0x60, 0xd7, 0x3b, 0xd5, 0xfd, 0x4e, 0x03, 0xc5, 0x3a, 0xb4, - 0x34, 0xe0, 0xf0, 0x2c, 0x96, 0xba, 0xdb, 0x32, 0x68, 0xba, 0x9f, 0x3d, 0x3f, 0x24, 0x19, 0x5c, - 0xb4, 0xa6, 0x81, 0x33, 0x54, 0xce, 0x29, 0x89, 0xe5, 0x34, 0x95, 0x43, 0x5f, 0xdb, 0x0e, 0xfc, - 0xa7, 0xd2, 0x92, 0xe3, 0x9d, 0x30, 0x25, 0xe1, 0xac, 0x5a, 0x65, 0x90, 0xd8, 0x82, 0x0b, 0x8a, - 0x9b, 0xd8, 0x89, 0x13, 0x8e, 0xa5, 0xb2, 0x33, 0x3f, 0x4c, 0x7f, 0xf1, 0xf1, 0xa0, 0xb6, 0xbe, - 0xb8, 0xb1, 0x64, 0xad, 0x68, 0xa4, 0x45, 0xb8, 0xc7, 0x84, 0x12, 0xb7, 0x61, 0x75, 0xa6, 0x0d, - 0x37, 0xa9, 0xaf, 0x2f, 0x6e, 0x2c, 0x5a, 0x62, 0xaa, 0xc9, 0x2e, 0xb5, 0xb8, 0x07, 0xcb, 0x49, - 0x16, 0xa2, 0x0a, 0xbb, 0xef, 0x07, 0xa9, 0x4c, 0x0e, 0x62, 0xe9, 0x92, 0x90, 0xb7, 0xb6, 0x2e, - 0x6e, 0x92, 0x96, 0xb3, 0x66, 0xd1, 0xd6, 0xf9, 0x16, 0xe2, 0xfd, 0x7c, 0xf2, 0xee, 0x9d, 0xc6, - 0x09, 0x69, 0x82, 0xd6, 0x16, 0x70, 0x07, 0x08, 0xb1, 0xca, 0x68, 0x71, 0x13, 0x96, 0xbd, 0xc4, - 0xf1, 0x43, 0xdb, 0x09, 0x02, 0xfb, 0x28, 0x73, 0x4f, 0x64, 0xaa, 0x48, 0x3b, 0x34, 0xac, 0x1e, - 0x21, 0xb6, 0x83, 0xe0, 0x0e, 0x83, 0xc5, 0x0d, 0xe8, 0xa9, 0x34, 0xf1, 0xc3, 0xb1, 0x7d, 0xec, - 0xa8, 0x63, 0xfb, 0x44, 0x9e, 0x91, 0x72, 0x68, 0x58, 0x1d, 0x06, 0x7f, 0xe3, 0xa8, 0xe3, 0x6f, - 0xe5, 0xd9, 0xf0, 0x7f, 0x2d, 0x40, 0xe3, 0xae, 0xaf, 0x62, 0xe4, 0x32, 0x71, 0x11, 0xea, 0xa3, - 0x2c, 0x74, 0x0b, 0x1e, 0xaa, 0xe1, 0xeb, 0xae, 0x27, 0x7e, 0x05, 0xbd, 0x20, 0x72, 0x9d, 0xc0, - 0xce, 0xd9, 0x65, 0xb0, 0xb0, 0xbe, 0xb8, 0xd1, 0xda, 0x5a, 0x29, 0xb4, 0x42, 0xce, 0x8e, 0x56, - 0x97, 0x68, 0x0b, 0xf6, 0xfc, 0x12, 0xfa, 0x89, 0x9c, 0x44, 0xa9, 0x2c, 0x35, 0x5f, 0xa4, 0xe6, - 0xa2, 0x68, 0xfe, 0x5d, 0xe2, 0xc4, 0x0f, 0x51, 0x95, 0xf4, 0x98, 0xb6, 0x68, 0xfe, 0x61, 0x69, - 0x45, 0xe5, 0xd8, 0xf6, 0xbd, 0x53, 0x9b, 0x3e, 0x30, 0x58, 0x5a, 0x5f, 0xdc, 0xa8, 0x16, 0xcb, - 0x23, 0xc7, 0xbb, 0xde, 0xe9, 0x03, 0xc4, 0x88, 0x8f, 0x60, 0x6d, 0xb6, 0x09, 0xf7, 0x3a, 0xa8, - 0x52, 0x9b, 0x95, 0xa9, 0x36, 0x16, 0xa1, 0xc4, 0x9b, 0xd0, 0x36, 0x8d, 0x52, 0x64, 0xe5, 0x1a, - 0x33, 0x97, 0x2a, 0xb1, 0xf2, 0x45, 0xa8, 0xfb, 0xca, 0x56, 0x7e, 0x78, 0x42, 0x3a, 0xbe, 0x61, - 0xd5, 0x7c, 0x75, 0xe0, 0x87, 0x27, 0xe2, 0x12, 0x34, 0x12, 0xe9, 0x32, 0xa6, 0x41, 0x98, 0x7a, - 0x22, 0x5d, 0x42, 0x5d, 0x04, 0x7c, 0xb4, 0xdd, 0x54, 0x6a, 0x4d, 0x5f, 0x4b, 0xa4, 0xbb, 0x93, - 0xca, 0xa1, 0x82, 0xea, 0x9e, 0x4c, 0xc6, 0x12, 0x95, 0x3d, 0x36, 0x3c, 0x70, 0x9d, 0x90, 0xe6, - 0xbd, 0x61, 0xe5, 0xef, 0x68, 0x6a, 0x62, 0x27, 0x49, 0x7d, 0x27, 0x20, 0xd1, 0x6a, 0x58, 0xe6, - 0x55, 0x5c, 0x81, 0xa6, 0x4a, 0x9d, 0x24, 0xc5, 0xbf, 0x23, 0x91, 0xaa, 0x5a, 0x0d, 0x02, 0xa0, - 0x54, 0x5e, 0x84, 0xba, 0x0c, 0x3d, 0x42, 0x2d, 0xf1, 0x4a, 0xca, 0xd0, 0xdb, 0xf5, 0x4e, 0x87, - 0xff, 0xba, 0x02, 0x9d, 0xbd, 0x2c, 0x48, 0xfd, 0xed, 0x64, 0x9c, 0xc9, 0x49, 0x98, 0xa2, 0x89, - 0xba, 0xeb, 0xab, 0x54, 0x7f, 0x99, 0x9e, 0xc5, 0x06, 0x34, 0xbf, 0x4e, 0xa2, 0x2c, 0x26, 0xae, - 0xe4, 0x95, 0x2e, 0x73, 0x65, 0x81, 0x44, 0x0e, 0x7e, 0x94, 0x78, 0x32, 0xb9, 0x73, 0x46, 0xb4, - 0x8b, 0xe7, 0x68, 0xcb, 0x68, 0x71, 0x15, 0x9a, 0x07, 0x32, 0x76, 0x12, 0x07, 0x59, 0x60, 0x89, - 0xec, 0x5a, 0x01, 0xc0, 0x7f, 0x25, 0xe2, 0x5d, 0x4f, 0x0b, 0xb6, 0x79, 0x1d, 0xfe, 0xb3, 0x0a, - 0x34, 0xb7, 0xc7, 0xe3, 0x44, 0x8e, 0x9d, 0x94, 0x8c, 0x6c, 0x14, 0xd3, 0x78, 0x17, 0xad, 0x85, - 0x28, 0x26, 0x43, 0x8e, 0x7f, 0xc0, 0x13, 0x44, 0xcf, 0xe2, 0x0d, 0x58, 0x92, 0xf3, 0x07, 0x44, - 0x70, 0xb1, 0x06, 0x35, 0x37, 0x0a, 0x47, 0xfe, 0x58, 0x9b, 0x7f, 0xfd, 0x26, 0xbe, 0x80, 0x16, - 0x3f, 0x31, 0x0f, 0x54, 0xc9, 0xf6, 0x5d, 0xe2, 0xe6, 0xf9, 0x08, 0x76, 0x88, 0x02, 0x39, 0xc2, - 0x02, 0x37, 0x7f, 0x1e, 0xfe, 0x69, 0x09, 0xaa, 0x34, 0x33, 0xb8, 0x36, 0x68, 0xce, 0x6d, 0xf9, - 0xd4, 0x09, 0xcc, 0x92, 0x22, 0xe0, 0xde, 0x53, 0x27, 0x10, 0xeb, 0x50, 0xc5, 0x21, 0xa8, 0x39, - 0x13, 0xcb, 0x08, 0x71, 0x03, 0xaa, 0xf8, 0x75, 0x35, 0x3d, 0x7a, 0xfc, 0xc6, 0x9d, 0xa5, 0xbf, - 0xfc, 0x8f, 0xd7, 0x5e, 0xb3, 0x18, 0x2d, 0xde, 0x81, 0x25, 0x67, 0x3c, 0x56, 0x24, 0x08, 0x53, - 0xb2, 0x98, 0x8f, 0xd4, 0x22, 0x02, 0xf1, 0x09, 0x34, 0x79, 0xd1, 0x91, 0xba, 0x4a, 0xd4, 0x17, - 0x4b, 0x6e, 0x52, 0x99, 0x1f, 0xac, 0x82, 0x12, 0x97, 0xcb, 0x57, 0x5a, 0x03, 0x91, 0x38, 0x34, - 0xac, 0x02, 0x80, 0x7e, 0x4c, 0x9c, 0xc8, 0xed, 0x20, 0x88, 0xdc, 0x03, 0xff, 0xb9, 0xd4, 0x5e, - 0xcf, 0x14, 0x4c, 0xdc, 0x80, 0xee, 0x3e, 0xf3, 0xab, 0x25, 0x55, 0x16, 0xa4, 0x4a, 0x7b, 0x42, - 0x33, 0x50, 0xb1, 0x09, 0x62, 0x0a, 0x72, 0x48, 0xbf, 0xdf, 0x5c, 0x5f, 0xdc, 0xe8, 0x58, 0x73, - 0x30, 0xe2, 0x2d, 0xe8, 0x8c, 0x71, 0xa6, 0x51, 0xc1, 0x8d, 0x02, 0x07, 0x9d, 0xa4, 0x45, 0x74, - 0xa2, 0x0c, 0xf0, 0x7e, 0xe0, 0x8c, 0x49, 0x42, 0x62, 0x3f, 0x08, 0xec, 0x89, 0x9c, 0x90, 0xf6, - 0x5b, 0xb4, 0x1a, 0x04, 0xd8, 0x93, 0x13, 0xf1, 0x2e, 0x2c, 0x13, 0xb1, 0x7d, 0x74, 0x56, 0xa8, - 0xc8, 0x36, 0x69, 0x87, 0x2e, 0x21, 0xee, 0x9c, 0x69, 0x1d, 0x29, 0xde, 0x85, 0xbe, 0x77, 0x16, - 0x3a, 0x13, 0xdf, 0xb5, 0x4d, 0xff, 0xe4, 0xba, 0xa0, 0xda, 0x65, 0xf8, 0xd7, 0x1a, 0x8c, 0x8a, - 0x47, 0x4e, 0xe2, 0xf4, 0x2c, 0x27, 0xb4, 0x95, 0x44, 0x09, 0x45, 0x57, 0x05, 0x6d, 0xc9, 0x0a, - 0x61, 0x0d, 0xf9, 0x81, 0x4c, 0x77, 0x3d, 0x85, 0xf6, 0xff, 0x7c, 0x23, 0xf2, 0x4d, 0x1a, 0x56, - 0x7f, 0xb6, 0xc1, 0xf0, 0x5f, 0x2d, 0x41, 0x6d, 0x37, 0x54, 0x32, 0x49, 0x51, 0x71, 0x38, 0xa3, - 0x91, 0x74, 0x53, 0xc9, 0x0a, 0x7b, 0xc9, 0xca, 0xdf, 0x71, 0xed, 0x0e, 0xa3, 0xef, 0x12, 0x3f, - 0x95, 0x07, 0x1f, 0x69, 0xc9, 0x28, 0x00, 0x68, 0x4a, 0x1c, 0xcf, 0xb3, 0x0d, 0xb5, 0x9d, 0x44, - 0xcf, 0x14, 0x29, 0x91, 0x86, 0xd5, 0x73, 0x3c, 0x6f, 0x5b, 0xc3, 0xad, 0xe8, 0x99, 0x12, 0x6f, - 0xc2, 0x62, 0x22, 0x47, 0x24, 0x27, 0xad, 0xad, 0x1e, 0xf3, 0xe2, 0xa3, 0xa3, 0x1f, 0xa4, 0x9b, - 0x5a, 0x72, 0x64, 0x21, 0x4e, 0xac, 0x42, 0xd5, 0x49, 0xd3, 0x84, 0x79, 0xab, 0x69, 0xf1, 0x8b, - 0xd8, 0x84, 0x15, 0x52, 0x56, 0xa9, 0x1f, 0x85, 0x76, 0xea, 0x1c, 0x05, 0x92, 0x66, 0x82, 0x0d, - 0xf1, 0x72, 0x8e, 0x3a, 0x44, 0x0c, 0xce, 0xc3, 0x16, 0x5c, 0x98, 0xa5, 0x0f, 0x9d, 0x89, 0x54, - 0x64, 0x87, 0x9b, 0xd6, 0xca, 0x74, 0x8b, 0x87, 0x88, 0x42, 0x46, 0x28, 0xda, 0xa0, 0xba, 0x6b, - 0x90, 0xe6, 0x68, 0xe7, 0x40, 0xd4, 0x86, 0x17, 0xa0, 0xe6, 0x2b, 0x5b, 0x86, 0x9e, 0xd6, 0xc0, - 0x55, 0x5f, 0xdd, 0x0b, 0x3d, 0xf1, 0x1e, 0x34, 0xf9, 0x2b, 0x9e, 0x1c, 0x91, 0x1d, 0x6d, 0x6d, - 0x75, 0xb5, 0xa8, 0x21, 0xf8, 0xae, 0x1c, 0x59, 0x8d, 0x54, 0x3f, 0xa1, 0x8f, 0x95, 0x46, 0xb6, - 0x3c, 0x4d, 0x65, 0x12, 0x3a, 0x81, 0x36, 0xa6, 0x90, 0x46, 0xf7, 0x34, 0x44, 0x7c, 0x02, 0x17, - 0x0d, 0xd6, 0x56, 0xe9, 0x24, 0xb5, 0xb3, 0xd0, 0x3f, 0xb5, 0x43, 0x27, 0x8c, 0xc8, 0x83, 0x5e, - 0xb4, 0x56, 0x0d, 0xfa, 0x20, 0x9d, 0xa4, 0x8f, 0x43, 0xff, 0xf4, 0xa1, 0x13, 0x46, 0x62, 0x03, - 0xfa, 0x79, 0xb3, 0xf4, 0x39, 0xfd, 0x30, 0x31, 0x57, 0xd3, 0xea, 0x1a, 0xf8, 0xe1, 0x73, 0xfc, - 0x57, 0xe2, 0xad, 0x12, 0x65, 0x34, 0x1a, 0x21, 0x6f, 0x29, 0xe9, 0x92, 0x1b, 0x5c, 0xb5, 0x56, - 0x0a, 0xfa, 0x47, 0x84, 0x3b, 0x90, 0xee, 0xf0, 0xf7, 0x15, 0x68, 0x91, 0x40, 0x3f, 0x8e, 0x3d, - 0xd4, 0x9d, 0x6f, 0x41, 0x67, 0x7a, 0xd1, 0x99, 0x6f, 0xda, 0x4e, 0x79, 0xc5, 0xd7, 0xa0, 0xb6, - 0xed, 0xe2, 0xe4, 0x11, 0xe3, 0x74, 0x2c, 0xfd, 0x26, 0x3e, 0x85, 0x5e, 0x46, 0xdd, 0xd8, 0x6e, - 0x7a, 0x6a, 0x07, 0xa8, 0x73, 0x59, 0x43, 0x69, 0xae, 0xe0, 0x6f, 0xec, 0xa4, 0xa7, 0x56, 0x27, - 0x33, 0x8f, 0x0f, 0x50, 0x1b, 0xdf, 0x86, 0xd5, 0x44, 0x22, 0xc7, 0xd8, 0xcf, 0x65, 0x12, 0xd9, - 0xa9, 0x9c, 0xc4, 0x51, 0x42, 0x16, 0x1c, 0x67, 0x51, 0x30, 0xee, 0x7b, 0x99, 0x44, 0x87, 0x1a, - 0x33, 0x7c, 0x1d, 0xaa, 0xdb, 0x49, 0xe2, 0x9c, 0x11, 0x6b, 0xe1, 0xc3, 0xa0, 0x42, 0xb2, 0xc9, - 0x2f, 0x43, 0x17, 0x16, 0xf7, 0x9c, 0x58, 0x5c, 0x87, 0x85, 0x49, 0x4c, 0x98, 0xd6, 0xd6, 0x85, - 0x92, 0x42, 0x73, 0xe2, 0xcd, 0xbd, 0xf8, 0x5e, 0x98, 0x26, 0x67, 0xd6, 0xc2, 0x24, 0xbe, 0xfc, - 0x09, 0xd4, 0xf5, 0x2b, 0x86, 0x81, 0x28, 0xe8, 0x15, 0x9a, 0x61, 0x7c, 0xc4, 0x0f, 0x3c, 0x75, - 0x82, 0xcc, 0xb8, 0xae, 0xfc, 0xf2, 0xc5, 0xc2, 0x67, 0x95, 0xe1, 0xff, 0x58, 0x82, 0xc6, 0x5d, - 0x19, 0x48, 0xfa, 0xf7, 0x21, 0xb4, 0xcb, 0x52, 0x61, 0xe6, 0x6d, 0x4a, 0x52, 0x86, 0xd0, 0x66, - 0x5f, 0x82, 0x5a, 0x49, 0x2d, 0x76, 0x53, 0x30, 0x34, 0x72, 0xbb, 0xec, 0xa4, 0x91, 0xbc, 0x75, - 0x2c, 0xf3, 0x8a, 0x98, 0x87, 0x1a, 0xb3, 0xc4, 0x18, 0xfd, 0x2a, 0xae, 0x02, 0x24, 0xd1, 0x33, - 0xdb, 0x67, 0x83, 0xce, 0xb6, 0xb1, 0x91, 0x44, 0xcf, 0x76, 0xd1, 0xa4, 0xff, 0xb5, 0x88, 0xd9, - 0xa7, 0x30, 0x28, 0x89, 0x19, 0x86, 0x0a, 0xb6, 0x1f, 0x72, 0x48, 0xa4, 0x25, 0xae, 0xe8, 0x93, - 0x22, 0x89, 0xdd, 0x90, 0xa2, 0x21, 0xa3, 0x3c, 0x9a, 0x2f, 0x51, 0x1e, 0x73, 0x75, 0x11, 0xcc, - 0xd7, 0x45, 0x77, 0x00, 0x0e, 0xe4, 0x78, 0x22, 0xc3, 0x74, 0xcf, 0x89, 0x07, 0x2d, 0x5a, 0xf8, - 0x61, 0xb1, 0xf0, 0x66, 0xb5, 0x36, 0x0b, 0x22, 0xe6, 0x82, 0x52, 0x2b, 0xf4, 0xf3, 0x5c, 0x27, - 0xb4, 0xd3, 0x24, 0x0b, 0x5d, 0x27, 0xe5, 0xf8, 0xb6, 0x61, 0xb5, 0x5c, 0x27, 0x3c, 0xd4, 0xa0, - 0x92, 0xc2, 0xe8, 0x94, 0x15, 0xc6, 0x0d, 0xe8, 0xc5, 0x89, 0x3f, 0x71, 0x92, 0x33, 0xb4, 0x16, - 0xb4, 0x18, 0x2c, 0x7a, 0x1d, 0x0d, 0xfe, 0x56, 0x9e, 0xed, 0x7a, 0xa7, 0x97, 0xbf, 0x84, 0xde, - 0xcc, 0x00, 0x7e, 0x12, 0xdf, 0xfd, 0xa3, 0x2a, 0x34, 0xf7, 0x13, 0xa9, 0x95, 0xfc, 0x35, 0x68, - 0x29, 0xf7, 0x58, 0x4e, 0x1c, 0xd6, 0x0d, 0xdc, 0x03, 0x30, 0x88, 0xf4, 0xc2, 0x94, 0x1a, 0x5b, - 0x78, 0x85, 0x1a, 0xeb, 0xc3, 0x22, 0xfb, 0x8b, 0x28, 0x4c, 0xf8, 0x58, 0xe8, 0xee, 0xa5, 0xb2, - 0xee, 0x5e, 0x87, 0xf6, 0xb1, 0xa3, 0x6c, 0x27, 0x4b, 0x23, 0xdb, 0x8d, 0x02, 0x62, 0xba, 0x86, - 0x05, 0xc7, 0x8e, 0xda, 0xce, 0xd2, 0x68, 0x27, 0x0a, 0xc4, 0xeb, 0x00, 0x6e, 0x14, 0x68, 0x35, - 0xa4, 0x9d, 0xe5, 0xa6, 0x1b, 0x05, 0xac, 0x7b, 0x90, 0x2b, 0xa5, 0x4a, 0xfd, 0x89, 0xa3, 0x97, - 0x54, 0x47, 0xdc, 0x75, 0x52, 0x85, 0xcb, 0x39, 0xca, 0x8a, 0x9e, 0x71, 0xa8, 0x7d, 0x1b, 0xba, - 0x6e, 0x34, 0x89, 0xed, 0x18, 0x67, 0x96, 0x5c, 0xb7, 0xc6, 0xb9, 0x68, 0xa8, 0x8d, 0x14, 0xfb, - 0x27, 0x92, 0x9d, 0xc9, 0x2d, 0xe8, 0xb9, 0x41, 0xa6, 0x52, 0x99, 0xa0, 0x0d, 0x97, 0xf3, 0x03, - 0xa8, 0x8e, 0x26, 0xd1, 0x0e, 0xe8, 0x10, 0x3a, 0xbe, 0xb2, 0xa3, 0xc0, 0xb3, 0x59, 0x41, 0x69, - 0x3e, 0x6b, 0xf9, 0xea, 0x51, 0xe0, 0x69, 0x15, 0xc9, 0x34, 0xa1, 0x7c, 0x66, 0x68, 0x5a, 0x86, - 0xe6, 0xa1, 0x7c, 0xa6, 0x69, 0x5e, 0xa4, 0xd0, 0xda, 0x2f, 0x52, 0x68, 0x38, 0x1f, 0x38, 0xa1, - 0xa9, 0x93, 0x8c, 0x49, 0x6b, 0x07, 0x1c, 0x07, 0x31, 0x7f, 0x2d, 0x1f, 0x3b, 0xea, 0x90, 0x30, - 0x07, 0x1a, 0x81, 0x51, 0x8f, 0xa6, 0xc5, 0xc9, 0x0b, 0xb3, 0xc9, 0x91, 0x4c, 0x68, 0x25, 0x98, - 0xe3, 0x04, 0x23, 0xad, 0xe8, 0xd9, 0x43, 0x42, 0xe1, 0x8a, 0xdc, 0x84, 0x65, 0xdd, 0xc4, 0x71, - 0x53, 0xff, 0xa9, 0x24, 0xf2, 0x1e, 0x91, 0xf7, 0x18, 0xb1, 0x4d, 0x70, 0xa4, 0x7d, 0x37, 0xa7, - 0xd5, 0x9a, 0x05, 0x69, 0xfb, 0xbc, 0x27, 0x90, 0x77, 0xbd, 0xeb, 0xed, 0x44, 0xc1, 0xf0, 0x3f, - 0x2c, 0x40, 0x7d, 0x3f, 0x52, 0xe9, 0xdd, 0x49, 0x60, 0xc4, 0xb9, 0xf2, 0x53, 0xc5, 0x79, 0x61, - 0xbe, 0x38, 0xcf, 0x11, 0xa8, 0xc5, 0x39, 0x02, 0x85, 0x46, 0xb2, 0x4c, 0x47, 0x82, 0xc0, 0xe1, - 0x43, 0xb7, 0x20, 0x24, 0x61, 0xb8, 0x82, 0x2e, 0xab, 0xed, 0xb1, 0xfe, 0x65, 0xa6, 0x6d, 0xf8, - 0x4a, 0xeb, 0x5e, 0x46, 0xfa, 0x24, 0x57, 0xda, 0x9f, 0x6d, 0xf8, 0x4a, 0xcb, 0xd9, 0xe7, 0x70, - 0x29, 0x6f, 0x69, 0x3f, 0xf3, 0xd3, 0xe3, 0x28, 0x4b, 0xed, 0x11, 0xc5, 0xea, 0x4a, 0x47, 0x7b, - 0x6b, 0xa6, 0xa7, 0xef, 0x18, 0xcd, 0x91, 0x3c, 0xb9, 0xd7, 0xa3, 0x2c, 0x08, 0xec, 0x54, 0x9e, - 0xa6, 0x9a, 0x6d, 0x07, 0x3c, 0x37, 0x7a, 0xde, 0xee, 0x67, 0x41, 0x70, 0x28, 0x4f, 0x53, 0x34, - 0x8d, 0x8d, 0x91, 0x7e, 0x19, 0xfe, 0xe3, 0x25, 0x80, 0x07, 0x91, 0x7b, 0xc2, 0x2b, 0x8f, 0x31, - 0xa4, 0xd1, 0xde, 0xda, 0xba, 0xd4, 0x53, 0xd6, 0xd9, 0x62, 0x0b, 0xd6, 0xcc, 0xff, 0xa3, 0xcc, - 0x61, 0x3c, 0xcb, 0xea, 0x57, 0x2b, 0x0f, 0xa1, 0xb1, 0xbc, 0x27, 0x43, 0xba, 0x57, 0x7c, 0x56, - 0xcc, 0x2d, 0xb6, 0x49, 0xcf, 0x62, 0x9a, 0xdb, 0x79, 0xe1, 0x44, 0xa7, 0x68, 0x7e, 0x78, 0x16, - 0x8b, 0xdb, 0x70, 0x21, 0x91, 0xa3, 0x44, 0xaa, 0x63, 0x3b, 0x55, 0xe5, 0x8f, 0x71, 0x28, 0xb9, - 0xac, 0x91, 0x87, 0x2a, 0xff, 0xd6, 0x6d, 0xb8, 0xc0, 0x33, 0x35, 0x3b, 0x3c, 0xb6, 0x55, 0xcb, - 0x8c, 0x2c, 0x8f, 0xee, 0x75, 0xa0, 0x8d, 0x61, 0xb6, 0x3f, 0x26, 0xb6, 0x08, 0x68, 0x32, 0x8e, - 0x02, 0x89, 0xde, 0xeb, 0xce, 0xb1, 0x13, 0x8e, 0x51, 0x67, 0xe9, 0xc9, 0x2f, 0x00, 0x62, 0x08, - 0x4b, 0x7b, 0x91, 0x27, 0x69, 0xaa, 0xbb, 0x5b, 0xdd, 0x4d, 0xda, 0x62, 0xc6, 0x99, 0xa4, 0xbd, - 0x48, 0xc2, 0x89, 0x77, 0x80, 0xba, 0x63, 0xf6, 0x3b, 0xaf, 0x17, 0x1a, 0x88, 0x24, 0x1e, 0xbc, - 0x0d, 0x17, 0x8a, 0x91, 0xd8, 0x4e, 0x6a, 0xa7, 0xc7, 0x92, 0x54, 0x3f, 0xab, 0x86, 0xe5, 0x7c, - 0x50, 0xdb, 0xe9, 0xe1, 0xb1, 0x44, 0x33, 0xb0, 0x01, 0xf5, 0xe8, 0xe8, 0x07, 0x1b, 0x05, 0xa1, - 0x35, 0x5f, 0x10, 0x6a, 0xd1, 0xd1, 0x0f, 0x96, 0x1c, 0x89, 0x5f, 0x94, 0xcd, 0xe6, 0xcc, 0xd4, - 0xb4, 0x69, 0x6a, 0x56, 0x73, 0x7c, 0x69, 0x76, 0x86, 0x9f, 0x41, 0x0d, 0x7f, 0xe7, 0x51, 0x2c, - 0x36, 0xa1, 0xce, 0xe2, 0xa8, 0xb4, 0x9b, 0xb3, 0x5a, 0x58, 0xbb, 0x82, 0x77, 0x2c, 0x43, 0x34, - 0xb4, 0xa0, 0x97, 0x9b, 0x8e, 0xc7, 0xa1, 0xff, 0x24, 0x93, 0xe2, 0x2b, 0x58, 0x8e, 0x13, 0xa9, - 0xd9, 0xde, 0xce, 0x4e, 0xd0, 0x79, 0xd3, 0x12, 0xbc, 0xaa, 0xb9, 0x34, 0x6f, 0x71, 0x82, 0x1c, - 0xda, 0x8d, 0xa7, 0xde, 0x87, 0xdf, 0xc3, 0xc5, 0x9c, 0xe2, 0x40, 0xba, 0x51, 0xe8, 0x39, 0xc9, - 0x19, 0x59, 0xf9, 0x99, 0xbe, 0xd5, 0x4f, 0xe9, 0xfb, 0x80, 0xfa, 0xfe, 0x6f, 0x15, 0x68, 0xdd, - 0xcf, 0x9e, 0x3f, 0x3f, 0x63, 0x59, 0x12, 0x6d, 0xa8, 0x3c, 0xa4, 0x0e, 0x16, 0xac, 0xca, 0x43, - 0x74, 0x44, 0xf7, 0x4f, 0x50, 0xae, 0x89, 0xcf, 0x9b, 0x96, 0x7e, 0xc3, 0x00, 0x79, 0xff, 0xe4, - 0xf0, 0x25, 0x1c, 0xcd, 0x68, 0x0c, 0x90, 0xee, 0x64, 0x7e, 0x80, 0x6e, 0x92, 0x66, 0xde, 0xfc, - 0x1d, 0x43, 0xce, 0xdd, 0x11, 0x0f, 0xe5, 0x7e, 0x12, 0x4d, 0x78, 0xb2, 0xb4, 0xca, 0x98, 0x83, - 0x11, 0x5f, 0xc3, 0x8a, 0xde, 0xc0, 0xd3, 0x5a, 0xc1, 0x56, 0xb1, 0x74, 0x89, 0x75, 0x7f, 0xd2, - 0xa6, 0xdf, 0xf0, 0xef, 0xd7, 0xa0, 0x81, 0xa1, 0xe5, 0x6f, 0x22, 0x3f, 0x14, 0xb7, 0xa1, 0xf9, - 0x43, 0xe4, 0x87, 0xbc, 0xdb, 0xc0, 0x49, 0x8e, 0x15, 0xee, 0xeb, 0x61, 0xe4, 0xc9, 0x4d, 0xa4, - 0xa1, 0x7d, 0x86, 0xc6, 0x0f, 0xfa, 0x49, 0x9b, 0xa7, 0xc4, 0x1f, 0x1f, 0xa7, 0x36, 0x02, 0xb5, - 0x6e, 0x6d, 0xf9, 0xca, 0x42, 0x18, 0xf5, 0x7a, 0x15, 0x80, 0x62, 0xda, 0x28, 0xb4, 0xe3, 0x13, - 0x1d, 0xd7, 0x35, 0x10, 0xf2, 0x28, 0xdc, 0x3f, 0x41, 0xd9, 0xf3, 0x95, 0xad, 0xf7, 0xb5, 0xb4, - 0x0f, 0x5e, 0x8a, 0xeb, 0xdf, 0x86, 0x2e, 0xfa, 0x47, 0xea, 0xc4, 0x8f, 0xed, 0x38, 0x89, 0x8e, - 0xcc, 0xa4, 0xa0, 0xd7, 0x74, 0x70, 0xe2, 0xc7, 0xfb, 0x08, 0x23, 0xb7, 0x44, 0xef, 0x96, 0xa1, - 0xda, 0x66, 0xfb, 0x0f, 0x1a, 0x84, 0xf3, 0x4b, 0x5b, 0x62, 0x01, 0x47, 0x09, 0x75, 0x72, 0x37, - 0xea, 0x89, 0x0c, 0x28, 0x1c, 0xb8, 0x04, 0x0d, 0x14, 0x06, 0x42, 0x35, 0x18, 0xe5, 0x46, 0x8c, - 0x7a, 0x17, 0x20, 0x90, 0xa3, 0xd4, 0x46, 0x2e, 0xe3, 0x0d, 0x80, 0x99, 0xad, 0x27, 0xc4, 0xee, - 0x20, 0x52, 0xbc, 0x07, 0x2d, 0x9e, 0x05, 0xa6, 0x85, 0x73, 0xb4, 0x40, 0x68, 0x26, 0xbe, 0x09, - 0xad, 0x30, 0x0a, 0x6d, 0xf9, 0x84, 0xa8, 0xb5, 0xdc, 0x4e, 0x75, 0x1c, 0x46, 0xe1, 0xbd, 0x27, - 0x48, 0x2c, 0x6e, 0xe9, 0x31, 0xf0, 0x1e, 0x4c, 0xfb, 0x05, 0x7b, 0x30, 0x34, 0x12, 0xde, 0x8d, - 0xf8, 0xd0, 0x8c, 0x84, 0x5b, 0x74, 0x5e, 0xd0, 0x82, 0xc7, 0xc3, 0x4d, 0xd6, 0xa1, 0x4d, 0xeb, - 0x3e, 0x71, 0x62, 0x3b, 0x75, 0xc6, 0xda, 0xaa, 0x03, 0xc2, 0xf6, 0x9c, 0xf8, 0xd0, 0x19, 0x0b, - 0x0b, 0x2e, 0xcd, 0xf0, 0xdb, 0x11, 0xb2, 0x2e, 0xcf, 0x5a, 0xcf, 0xec, 0xe1, 0xcc, 0xe7, 0xba, - 0xb5, 0x29, 0xae, 0x23, 0x96, 0xa7, 0xd9, 0xfd, 0x1c, 0x2e, 0xc9, 0x09, 0x65, 0x3f, 0x26, 0x71, - 0x22, 0x95, 0x9a, 0x72, 0xcd, 0xfa, 0x6c, 0xe3, 0x90, 0x60, 0x27, 0xc7, 0xe7, 0xfe, 0xd9, 0xdb, - 0xd0, 0x75, 0x54, 0x34, 0xb2, 0xcd, 0x94, 0x07, 0x94, 0xcb, 0xa8, 0x5a, 0x6d, 0x84, 0x5a, 0x3c, - 0xd1, 0x01, 0x1a, 0x74, 0xa2, 0xd2, 0x43, 0x95, 0xa3, 0x94, 0xf2, 0x18, 0x0d, 0xab, 0x83, 0x60, - 0x1e, 0x88, 0x1c, 0xa5, 0xc3, 0x7f, 0xbe, 0x00, 0x8d, 0x07, 0x51, 0x14, 0xff, 0x4c, 0x19, 0x28, - 0xf3, 0xd6, 0xc2, 0x8b, 0x79, 0x6b, 0x71, 0x9a, 0xb7, 0x66, 0x78, 0x60, 0xe9, 0xc7, 0xf3, 0x40, - 0xf5, 0x27, 0xf3, 0x40, 0xed, 0x67, 0xf0, 0x40, 0x7d, 0x96, 0x07, 0x86, 0xb7, 0xa1, 0x7a, 0x20, - 0xd3, 0x47, 0x31, 0x5a, 0x33, 0xe3, 0x17, 0x1b, 0x43, 0x30, 0x65, 0xcd, 0xb4, 0x4f, 0xac, 0x86, - 0x7f, 0xd5, 0x82, 0xe6, 0x5d, 0xe9, 0x65, 0x3c, 0xb3, 0xe5, 0x79, 0xaa, 0xbc, 0x78, 0x9e, 0x16, - 0xa6, 0xe7, 0x09, 0x4d, 0xa7, 0x91, 0xc1, 0x39, 0x1b, 0xa8, 0x0d, 0x23, 0x82, 0x28, 0xac, 0x85, - 0x04, 0xea, 0x5d, 0xc8, 0xa9, 0xf9, 0xcc, 0x05, 0xf0, 0xe5, 0xdc, 0x5c, 0xfd, 0x79, 0xdc, 0x3c, - 0xad, 0xc7, 0xce, 0xed, 0x4f, 0xbe, 0x72, 0x7a, 0x67, 0x75, 0x58, 0xe3, 0x9c, 0x0e, 0x7b, 0x00, - 0x2b, 0x51, 0x68, 0x7b, 0x59, 0x1c, 0xf8, 0x18, 0x17, 0x92, 0x5f, 0x1d, 0x85, 0xe4, 0x4e, 0x50, - 0x46, 0x34, 0xe7, 0xd1, 0x47, 0xe1, 0x5d, 0x43, 0xc4, 0x7b, 0x25, 0xd6, 0x72, 0x34, 0x0b, 0x42, - 0x11, 0xf2, 0x70, 0x69, 0xc8, 0x13, 0x20, 0x1f, 0x96, 0x53, 0xbb, 0x6d, 0x82, 0xee, 0x44, 0x01, - 0xd9, 0xb6, 0xcf, 0xa0, 0x57, 0x50, 0x31, 0x33, 0xb5, 0x5e, 0xc0, 0x4c, 0x1d, 0xd3, 0x90, 0xf9, - 0xe9, 0xaf, 0x43, 0x6f, 0x7d, 0x00, 0x2b, 0x66, 0x0b, 0x48, 0xbb, 0x33, 0xb4, 0x82, 0x5d, 0xe2, - 0xa0, 0xbe, 0xde, 0xf5, 0x21, 0x4f, 0x86, 0x96, 0xe8, 0x97, 0xb0, 0x5a, 0x22, 0x47, 0xf6, 0x2d, - 0xeb, 0xaf, 0x32, 0xaf, 0x2c, 0xe7, 0x6d, 0xf1, 0xf5, 0x01, 0xef, 0xe1, 0xb7, 0x3c, 0x19, 0x98, - 0x0f, 0xe9, 0xe8, 0xa4, 0xe9, 0xc9, 0x40, 0xa7, 0x1e, 0xf7, 0xe0, 0x6d, 0x8c, 0xe4, 0x10, 0xef, - 0x3a, 0x71, 0x9a, 0x25, 0xd2, 0x8e, 0x03, 0xc7, 0x95, 0xc7, 0x51, 0xe0, 0xc9, 0xa4, 0x18, 0xdc, - 0x32, 0x0d, 0xee, 0x5a, 0x14, 0x60, 0x38, 0xb3, 0xc3, 0x94, 0xfb, 0x05, 0xa1, 0x19, 0xeb, 0x36, - 0xbc, 0x71, 0xae, 0x3b, 0x34, 0x75, 0x45, 0x47, 0x82, 0x3a, 0xba, 0x34, 0xdd, 0x11, 0x92, 0x98, - 0x2e, 0x3e, 0x84, 0x0b, 0xbc, 0x76, 0xcc, 0xdc, 0x27, 0x52, 0xc6, 0x76, 0xe0, 0xa8, 0x74, 0xb0, - 0xc2, 0x6e, 0x05, 0x21, 0x89, 0x81, 0xbf, 0x95, 0x32, 0x7e, 0xe0, 0xf0, 0x57, 0xb9, 0x89, 0x8e, - 0x3c, 0xa8, 0xcd, 0xd4, 0xdc, 0xae, 0xf2, 0x57, 0x89, 0x8a, 0xc3, 0x0f, 0x6c, 0x5c, 0x9a, 0xe4, - 0x5f, 0xc1, 0x95, 0xa9, 0x2e, 0x26, 0x4e, 0x72, 0x52, 0xb8, 0xe2, 0x83, 0x0b, 0x34, 0x6f, 0x17, - 0x4b, 0xed, 0xf7, 0x88, 0x40, 0xcf, 0xe2, 0x47, 0xb0, 0x86, 0x81, 0x69, 0xe4, 0x9d, 0x64, 0x33, - 0x41, 0xdb, 0x1a, 0x0d, 0x1a, 0xc3, 0xd6, 0x47, 0xde, 0x49, 0x36, 0x15, 0xb8, 0x7d, 0x0a, 0x83, - 0x29, 0x5a, 0x3b, 0xa1, 0xcd, 0x79, 0x3b, 0x8e, 0xd4, 0xe0, 0x22, 0xef, 0x07, 0x95, 0x77, 0x14, - 0x79, 0xeb, 0x7e, 0x3f, 0x52, 0xe2, 0x3e, 0xac, 0xc7, 0xc7, 0x67, 0xca, 0xa7, 0x64, 0x22, 0x39, - 0xf4, 0xe7, 0x3b, 0x18, 0x50, 0x07, 0x57, 0x0d, 0x1d, 0xfb, 0xfd, 0x33, 0xfd, 0x7c, 0x06, 0x97, - 0x0c, 0x63, 0x1d, 0x4b, 0xf7, 0x64, 0x7a, 0xc6, 0x2e, 0xd1, 0x8c, 0x5d, 0xd0, 0x1c, 0x85, 0xf8, - 0xd2, 0x6c, 0x6d, 0x40, 0x9f, 0xec, 0x9d, 0x3d, 0x8a, 0xb2, 0x50, 0xff, 0xe9, 0x65, 0xfa, 0xd3, - 0x2e, 0xc1, 0xef, 0x23, 0x98, 0x7e, 0x72, 0x03, 0xfa, 0x64, 0x2d, 0x59, 0xea, 0x99, 0xf2, 0x0a, - 0x53, 0x22, 0x5c, 0x0b, 0x3a, 0x52, 0x7e, 0x02, 0x17, 0x35, 0xd1, 0xc8, 0x0f, 0x9d, 0xa0, 0xfc, - 0x33, 0x57, 0xd9, 0xcd, 0x67, 0xf4, 0x7d, 0xc4, 0x16, 0x3f, 0xf1, 0x5b, 0x10, 0xa3, 0x28, 0x91, - 0xfe, 0x38, 0xa4, 0xb0, 0x96, 0xfe, 0x44, 0x0d, 0x5e, 0x27, 0xd9, 0x78, 0xbd, 0xf0, 0xf3, 0x1f, - 0xdd, 0xfd, 0xf6, 0xf1, 0x7d, 0xa6, 0xfb, 0x56, 0x9e, 0xd1, 0xff, 0x68, 0xc9, 0xec, 0x8f, 0xa6, - 0xc1, 0x6a, 0xf8, 0x4f, 0x6a, 0xd0, 0x25, 0x6b, 0xfc, 0xb7, 0x46, 0xe0, 0x6f, 0x8d, 0xc0, 0xdf, - 0x04, 0x23, 0x70, 0x13, 0x96, 0xfd, 0x30, 0xce, 0x52, 0x94, 0x20, 0x65, 0x67, 0x1c, 0xc5, 0x2d, - 0xf3, 0x76, 0x13, 0x21, 0xbe, 0x95, 0x67, 0x8a, 0x43, 0xb8, 0xe1, 0xdf, 0xab, 0x40, 0x7d, 0x3f, - 0x89, 0xbc, 0xcc, 0x4d, 0x7f, 0xa6, 0x54, 0x4c, 0x73, 0xdb, 0xe2, 0xab, 0xb8, 0x6d, 0xe9, 0x9c, - 0x47, 0xf7, 0x2f, 0x2b, 0xd0, 0xd4, 0x43, 0x78, 0xb0, 0xf5, 0x33, 0x07, 0x51, 0xe4, 0xb6, 0x2b, - 0x73, 0x73, 0xdb, 0xaf, 0x1c, 0x05, 0x32, 0xe1, 0x53, 0x2e, 0x06, 0x8a, 0xe2, 0x22, 0xd1, 0xdd, - 0xb4, 0xda, 0x0c, 0x7d, 0x14, 0x53, 0x3e, 0xfb, 0x19, 0x34, 0x29, 0xca, 0x27, 0x2d, 0xb2, 0x06, - 0x35, 0xd6, 0x6a, 0x7a, 0xa0, 0xfa, 0xed, 0xe5, 0x32, 0xbd, 0xf0, 0xb3, 0x64, 0x7a, 0xf8, 0xef, - 0x16, 0xa1, 0x43, 0x5b, 0x2e, 0xf7, 0xb3, 0x90, 0xa5, 0x26, 0xdf, 0xa4, 0xae, 0x4c, 0x6f, 0x52, - 0x2f, 0x25, 0x32, 0x35, 0x89, 0xf4, 0x36, 0x7f, 0x66, 0x27, 0x0a, 0xee, 0xca, 0x91, 0x45, 0x18, - 0x9c, 0x2a, 0x27, 0x19, 0xab, 0x79, 0x65, 0x00, 0x08, 0xc7, 0xbf, 0x8a, 0x9d, 0xc4, 0x99, 0x28, - 0x53, 0x06, 0xc0, 0x6f, 0x42, 0xc0, 0x12, 0xc9, 0x26, 0x4f, 0x0b, 0x3d, 0xeb, 0xdd, 0x43, 0xe5, - 0x87, 0xe3, 0x5c, 0xd1, 0x34, 0xa8, 0xfc, 0x63, 0x1c, 0x48, 0x71, 0x17, 0x04, 0xa7, 0x45, 0x12, - 0xe9, 0xa0, 0xf3, 0x41, 0xfd, 0x90, 0xb6, 0x69, 0x6d, 0xad, 0xf1, 0x67, 0x69, 0x2e, 0x2d, 0x42, - 0xef, 0x23, 0xd6, 0xea, 0xfb, 0x33, 0x90, 0x39, 0x93, 0xc9, 0x1e, 0x48, 0x1e, 0x29, 0xff, 0xe8, - 0xc9, 0x24, 0xb7, 0x84, 0xb8, 0xe5, 0x2b, 0x58, 0x19, 0x65, 0x41, 0x90, 0xca, 0xd3, 0xd4, 0x56, - 0x51, 0x96, 0xb8, 0xd2, 0x7e, 0x49, 0x46, 0x66, 0xd9, 0xd0, 0x1e, 0x10, 0xa9, 0x25, 0x47, 0xe2, - 0x4b, 0x10, 0x79, 0x07, 0xe6, 0x1f, 0x4d, 0xbe, 0xf4, 0x5c, 0xfb, 0xbe, 0x21, 0xd5, 0x7f, 0x3b, - 0x1a, 0x6e, 0xc3, 0x05, 0x93, 0x23, 0x45, 0xd5, 0xb6, 0x85, 0x72, 0x4b, 0x7b, 0x47, 0x66, 0x8e, - 0x2b, 0xa5, 0x39, 0x5e, 0x85, 0x6a, 0xb9, 0x3c, 0x8d, 0x5f, 0x86, 0xd7, 0xa1, 0x35, 0xf2, 0x03, - 0xa9, 0x73, 0x0d, 0xb8, 0x68, 0x3a, 0xeb, 0x50, 0xa1, 0xa4, 0xba, 0x7e, 0x1b, 0xfe, 0xbe, 0x02, - 0x17, 0x63, 0x27, 0x79, 0x92, 0xe9, 0x5d, 0x6d, 0xce, 0xef, 0xab, 0x63, 0x27, 0xf1, 0x50, 0x70, - 0xa9, 0x0b, 0xee, 0x9d, 0xab, 0x9b, 0x9a, 0x08, 0xe1, 0xb1, 0xdc, 0x80, 0x5e, 0xa9, 0x45, 0xea, - 0x24, 0x66, 0x67, 0xb5, 0x93, 0x44, 0xcf, 0x28, 0xfb, 0x7e, 0x80, 0x40, 0x31, 0x84, 0x4e, 0x41, - 0x27, 0xc9, 0x32, 0x52, 0x91, 0x90, 0xa1, 0xba, 0x17, 0x7a, 0x28, 0xb9, 0x61, 0x36, 0x61, 0x77, - 0x81, 0x8b, 0xd8, 0xea, 0x61, 0x36, 0x21, 0x3f, 0x61, 0x15, 0xaa, 0x5c, 0x39, 0x58, 0x25, 0x38, - 0xbf, 0x0c, 0xff, 0x50, 0x85, 0x95, 0x5d, 0x57, 0x1e, 0xc9, 0x64, 0x7c, 0xd7, 0x49, 0x9d, 0xfb, - 0x7e, 0x20, 0x0f, 0x1d, 0x75, 0x82, 0x0c, 0x47, 0x63, 0x8e, 0x9d, 0xf4, 0x58, 0xcf, 0x52, 0x03, - 0x01, 0xfb, 0x4e, 0x7a, 0x8c, 0x66, 0x8b, 0x90, 0xa3, 0x28, 0x99, 0xe8, 0x7d, 0xe0, 0xa6, 0x45, - 0xff, 0x78, 0x9f, 0x20, 0x79, 0x6b, 0xe5, 0x3f, 0x97, 0xba, 0xe4, 0x8e, 0x5a, 0x53, 0x5d, 0xc6, - 0x9b, 0xd0, 0x4e, 0xa4, 0x1b, 0x25, 0x9e, 0x8e, 0xfd, 0x79, 0x9c, 0x2d, 0x86, 0x71, 0xc0, 0x7f, - 0x13, 0x8a, 0xdc, 0x21, 0x6d, 0x75, 0xd9, 0xbe, 0xa9, 0xcb, 0xe9, 0xe5, 0x08, 0xe4, 0xbc, 0x5d, - 0x4f, 0xfc, 0x1d, 0xe8, 0x17, 0xb4, 0x94, 0xc8, 0x32, 0x11, 0xf0, 0x56, 0xe1, 0xc6, 0xcc, 0xf9, - 0xc5, 0xcd, 0x7d, 0xd3, 0xea, 0xcf, 0xa9, 0x11, 0x27, 0xeb, 0x8a, 0xee, 0x19, 0x2a, 0xde, 0x82, - 0x8e, 0x8a, 0x03, 0x3f, 0xd5, 0x0c, 0xa0, 0x74, 0x61, 0x5e, 0x9b, 0x80, 0x9c, 0x6f, 0x52, 0xf3, - 0x96, 0xb0, 0xf1, 0xa3, 0x96, 0xb0, 0x79, 0x7e, 0x09, 0xdf, 0x85, 0xbe, 0x9b, 0x48, 0x4f, 0x86, - 0xa9, 0xef, 0x04, 0xb6, 0x72, 0xa3, 0xd8, 0x98, 0xe9, 0x5e, 0x01, 0x3f, 0x40, 0xb0, 0xf8, 0x05, - 0x5c, 0x74, 0xa3, 0x30, 0x95, 0x61, 0x9a, 0x97, 0x6e, 0xea, 0x6c, 0x8d, 0x2e, 0x39, 0xb9, 0xa0, - 0xd1, 0xa6, 0x80, 0x93, 0xf3, 0x35, 0xe2, 0x36, 0xac, 0xf2, 0xf2, 0xcc, 0x34, 0xe2, 0x5a, 0x01, - 0x41, 0x2b, 0x35, 0xdd, 0x42, 0x67, 0x90, 0x12, 0xa9, 0x7c, 0x2f, 0x73, 0x02, 0xad, 0x21, 0x4a, - 0x19, 0x24, 0x4b, 0x63, 0xf4, 0x56, 0x2a, 0xe5, 0xa8, 0xa6, 0x68, 0xa9, 0xd0, 0x85, 0xb6, 0x9a, - 0x9a, 0x96, 0x48, 0xa6, 0xa8, 0xbf, 0x71, 0xd4, 0xf1, 0xe5, 0x3b, 0xb0, 0x3a, 0x6f, 0x41, 0x5e, - 0x95, 0xbc, 0x6c, 0x96, 0x92, 0x97, 0xba, 0x3c, 0xf5, 0xbf, 0x2f, 0xc0, 0x05, 0xb3, 0xde, 0x14, - 0x72, 0xe4, 0x4c, 0x7d, 0x8d, 0xec, 0x39, 0x86, 0x29, 0xf9, 0x76, 0x4f, 0xd3, 0x02, 0x06, 0xd1, - 0xde, 0xce, 0x06, 0xf4, 0x35, 0x41, 0xc1, 0xfc, 0xfc, 0x95, 0xae, 0x97, 0x77, 0x45, 0x22, 0x40, - 0x3f, 0x38, 0x92, 0x09, 0xce, 0x91, 0x47, 0xd5, 0xda, 0xd4, 0x84, 0x98, 0x9d, 0x7e, 0xd0, 0xe0, - 0x0c, 0xcb, 0x51, 0xa5, 0xcd, 0x93, 0xcc, 0x09, 0xfc, 0xf4, 0xcc, 0x1e, 0xf9, 0x32, 0xf0, 0x28, - 0x53, 0xce, 0x75, 0x84, 0x7d, 0x83, 0xb9, 0x8f, 0x88, 0x5d, 0x4f, 0x95, 0x46, 0xa2, 0x13, 0xb0, - 0xb9, 0x00, 0xe8, 0x91, 0x1c, 0x10, 0x78, 0xd7, 0x9b, 0x2f, 0x2b, 0xb5, 0xf9, 0xb2, 0xf2, 0x0e, - 0xf4, 0x66, 0xd7, 0x9c, 0x93, 0xa2, 0x5d, 0x35, 0xbd, 0xde, 0xf3, 0x98, 0xb0, 0x31, 0x97, 0x09, - 0xf5, 0xa4, 0xff, 0xcf, 0x05, 0x58, 0xd5, 0x93, 0xbe, 0x13, 0x05, 0xd9, 0x04, 0xad, 0x3d, 0x55, - 0x25, 0xad, 0x43, 0x7b, 0x12, 0xb1, 0x0b, 0x55, 0x52, 0x7f, 0x30, 0x89, 0x72, 0x5d, 0xbc, 0x01, - 0x7d, 0x9f, 0x5b, 0xe6, 0xf3, 0x62, 0x2a, 0x84, 0x35, 0x5c, 0xcf, 0x0a, 0x72, 0xa1, 0x0a, 0x9d, - 0x58, 0x1d, 0x47, 0xa9, 0x26, 0x25, 0x25, 0xce, 0x73, 0xbe, 0x6c, 0x50, 0x44, 0x4d, 0x9e, 0xec, - 0xfb, 0x20, 0xdc, 0x2c, 0x49, 0x50, 0x3e, 0x4a, 0xe4, 0x9c, 0xbc, 0xeb, 0x6b, 0x4c, 0x41, 0xfd, - 0x16, 0xd4, 0x27, 0x51, 0xe1, 0x91, 0x4c, 0x39, 0xa2, 0x56, 0x6d, 0x12, 0x11, 0x87, 0x5c, 0x46, - 0xaf, 0xe9, 0x49, 0xe6, 0x27, 0xd2, 0x33, 0x76, 0xd8, 0xbc, 0x6b, 0x23, 0x7d, 0xec, 0x7b, 0x9e, - 0x0c, 0x75, 0xe2, 0xa8, 0xe1, 0xab, 0x6f, 0xe8, 0x9d, 0x0a, 0x68, 0xe5, 0xc8, 0xc1, 0xd0, 0x2c, - 0xcc, 0x02, 0x92, 0x8a, 0x40, 0x97, 0x6b, 0xf6, 0x34, 0xe2, 0x61, 0x16, 0xa0, 0x44, 0x04, 0x7a, - 0x49, 0xc9, 0x96, 0x20, 0x0b, 0xda, 0xc7, 0x7e, 0x98, 0x92, 0xaa, 0x68, 0xd2, 0x92, 0x22, 0x02, - 0x99, 0xf0, 0x1b, 0x3f, 0x4c, 0x87, 0xff, 0x62, 0x01, 0xd6, 0xf4, 0xc4, 0x1f, 0xe8, 0x09, 0xd0, - 0xf6, 0x99, 0xa2, 0x0b, 0x33, 0x5d, 0x3a, 0xaf, 0xb7, 0x68, 0x81, 0x01, 0xed, 0xd2, 0x80, 0x0b, - 0xee, 0x5a, 0xd0, 0x65, 0x9c, 0x86, 0xaf, 0xde, 0x07, 0x71, 0x8e, 0xaf, 0x94, 0xde, 0xd6, 0xec, - 0xcf, 0x30, 0x96, 0x12, 0x1f, 0xc3, 0xda, 0x44, 0xa6, 0x0e, 0x09, 0x42, 0x10, 0xb9, 0x0e, 0xb5, - 0x22, 0x91, 0xe7, 0xe9, 0x5e, 0x35, 0xd8, 0x07, 0x1a, 0x89, 0x42, 0x8f, 0xdf, 0x98, 0x38, 0xa1, - 0x3f, 0x92, 0x2a, 0x25, 0x3f, 0x83, 0x5b, 0xb0, 0xe3, 0xd3, 0x37, 0x18, 0xf4, 0x24, 0x88, 0x9a, - 0x3c, 0xd6, 0x11, 0x2f, 0x62, 0x8d, 0x68, 0xea, 0x89, 0x1c, 0xe9, 0xb5, 0xeb, 0xe0, 0x5a, 0x85, - 0x7e, 0x38, 0xe6, 0x83, 0x03, 0x75, 0xf6, 0x29, 0x0d, 0x70, 0x2f, 0xf2, 0xe4, 0xf0, 0x2f, 0x96, - 0x72, 0x1e, 0xdd, 0xd7, 0xf0, 0x83, 0xd4, 0x49, 0xa9, 0x56, 0x3e, 0x1f, 0x3c, 0xdb, 0x48, 0x9e, - 0xab, 0x8e, 0x81, 0x72, 0x49, 0xfd, 0x26, 0xac, 0x4c, 0x8f, 0x96, 0x69, 0x17, 0xb8, 0xac, 0xa0, - 0x3c, 0xdc, 0xbc, 0x04, 0x3f, 0xa7, 0x67, 0x52, 0x5d, 0x7d, 0x6e, 0xa0, 0x4c, 0xf6, 0x41, 0x31, - 0x09, 0x4a, 0x27, 0xe7, 0xa5, 0xa7, 0xad, 0x62, 0xde, 0xab, 0x3a, 0xd0, 0x08, 0x14, 0xcd, 0x82, - 0x3c, 0x4e, 0xb2, 0x50, 0x7a, 0xda, 0xa4, 0xf7, 0x72, 0xf8, 0x3e, 0x81, 0x71, 0xc0, 0xb9, 0x66, - 0x2a, 0x75, 0x5d, 0xe3, 0xae, 0x3d, 0xad, 0x99, 0x8a, 0xae, 0x91, 0x47, 0x0b, 0x7a, 0xdd, 0x37, - 0x2b, 0x88, 0x5e, 0x4e, 0xad, 0xfb, 0xfe, 0x14, 0x06, 0x39, 0x2d, 0xff, 0x5d, 0xf1, 0x81, 0x06, - 0x1b, 0x1f, 0xd3, 0x84, 0x7e, 0x33, 0xff, 0xc8, 0x47, 0xb0, 0x36, 0xdb, 0x50, 0x7f, 0xa9, 0x49, - 0xcd, 0x56, 0xa6, 0x9a, 0x15, 0x7f, 0x92, 0xaf, 0xaf, 0xeb, 0xb8, 0xc7, 0xd2, 0x3e, 0xf6, 0x75, - 0x01, 0xfa, 0xa2, 0xb5, 0x6c, 0x50, 0x3b, 0x88, 0xf9, 0xc6, 0x4f, 0xd5, 0x1c, 0xfa, 0x89, 0xaf, - 0x94, 0xb6, 0x8a, 0xd3, 0xf4, 0x7b, 0xbe, 0x52, 0xc3, 0xff, 0xda, 0x82, 0xb6, 0xf1, 0x14, 0xa9, - 0xf6, 0xf9, 0xfd, 0xb2, 0xd3, 0xdf, 0xda, 0xea, 0x1b, 0xef, 0x1d, 0x49, 0xb6, 0xd3, 0x34, 0x31, - 0xb9, 0x3e, 0x0e, 0x06, 0xa6, 0xfc, 0x9d, 0x05, 0x72, 0x10, 0x0a, 0x7f, 0x67, 0x1b, 0x96, 0x4b, - 0x1e, 0xa4, 0x9d, 0x46, 0xa9, 0x13, 0xe8, 0xa0, 0xa0, 0x54, 0x37, 0x56, 0x22, 0xb1, 0x7a, 0xf8, - 0xc2, 0xbe, 0xc5, 0x21, 0x52, 0x63, 0xb0, 0xe1, 0x46, 0x81, 0x29, 0xb6, 0x9d, 0x09, 0x36, 0x10, - 0x43, 0x15, 0x31, 0x89, 0xc4, 0x38, 0x57, 0x3d, 0x09, 0xb4, 0x04, 0x35, 0x19, 0x72, 0xf0, 0x24, - 0xc8, 0x07, 0x48, 0xce, 0x7c, 0x8d, 0xe2, 0x18, 0x1a, 0x20, 0x79, 0xe9, 0x1f, 0x40, 0x2b, 0x4a, - 0xfc, 0xb1, 0x4f, 0x69, 0x62, 0x76, 0x70, 0x66, 0x3f, 0x02, 0x4c, 0xb0, 0x83, 0x9f, 0x1a, 0x42, - 0x4d, 0x9b, 0xff, 0xf3, 0x55, 0x32, 0x1a, 0x63, 0x8e, 0x00, 0xb8, 0x29, 0x0e, 0x87, 0x25, 0xb2, - 0x59, 0x1c, 0x01, 0x70, 0xd3, 0x83, 0x27, 0x01, 0x65, 0xca, 0x6f, 0x40, 0xcf, 0x25, 0x73, 0xc1, - 0x02, 0x15, 0xc8, 0x90, 0xd6, 0xb4, 0x6a, 0x75, 0x18, 0x8c, 0xe3, 0x7b, 0x20, 0x43, 0x5d, 0x6a, - 0xe9, 0x04, 0x01, 0x46, 0xac, 0x91, 0xe3, 0xe9, 0xba, 0x98, 0xb6, 0x01, 0x3e, 0x88, 0x1c, 0x4f, - 0x7c, 0x01, 0x97, 0x11, 0x67, 0x73, 0x41, 0x6b, 0x98, 0x4d, 0x64, 0xe2, 0xbb, 0xb6, 0xa3, 0xa8, - 0x4e, 0x46, 0x97, 0xc7, 0xac, 0x21, 0xc5, 0x3d, 0x24, 0x78, 0xc8, 0xf8, 0x6d, 0xf5, 0xbd, 0x4c, - 0x22, 0xf1, 0x3d, 0x65, 0xcb, 0xe7, 0xb9, 0xef, 0x66, 0x5b, 0xe2, 0xcd, 0x62, 0xad, 0x5e, 0x40, - 0x49, 0x75, 0x68, 0x88, 0xb0, 0x8c, 0xd3, 0x47, 0xed, 0xc5, 0xb7, 0x20, 0x8c, 0x81, 0x23, 0xce, - 0x4f, 0x1d, 0x75, 0xc2, 0x45, 0xb9, 0x53, 0x5b, 0x6d, 0x73, 0x7c, 0x54, 0xcb, 0x58, 0x46, 0x04, - 0x22, 0x40, 0x89, 0xdf, 0xc2, 0x6a, 0xde, 0x99, 0xf6, 0x65, 0xa8, 0x3b, 0xde, 0xd0, 0xb8, 0x76, - 0xbe, 0xbb, 0x29, 0x17, 0xc8, 0x32, 0x23, 0x61, 0x30, 0x77, 0xf9, 0x35, 0xf4, 0x4c, 0x97, 0x3c, - 0xeb, 0x6a, 0xd0, 0xa7, 0xde, 0xde, 0x38, 0xd7, 0xdb, 0x94, 0x6d, 0xcf, 0xed, 0x33, 0x43, 0xf1, - 0x47, 0x73, 0x4b, 0x6e, 0xac, 0x0c, 0x6d, 0x87, 0xb4, 0xb6, 0xd6, 0xcf, 0xf5, 0x34, 0x63, 0xac, - 0x2c, 0x33, 0x04, 0x03, 0x17, 0x1f, 0xc2, 0x05, 0xd3, 0x59, 0x44, 0x21, 0x9e, 0xed, 0x47, 0x14, - 0xfd, 0x09, 0x76, 0xb1, 0x34, 0x92, 0xc3, 0xbf, 0xdd, 0x88, 0xa3, 0xc5, 0x2b, 0xa6, 0x09, 0x5b, - 0x61, 0x8a, 0x88, 0xf3, 0x9f, 0x5a, 0x21, 0xdb, 0x35, 0xd0, 0x24, 0x6c, 0x97, 0x31, 0x02, 0x36, - 0xc3, 0xdf, 0x80, 0x3e, 0x55, 0xce, 0xe3, 0xb2, 0x46, 0x89, 0xe7, 0x87, 0x4e, 0x30, 0x58, 0xe5, - 0x3d, 0x57, 0x84, 0x5b, 0xd1, 0xb3, 0x47, 0x0c, 0x15, 0x87, 0xb0, 0x66, 0x3e, 0x94, 0xab, 0x19, - 0x85, 0xa6, 0x84, 0x36, 0xbc, 0xe7, 0x4d, 0xdc, 0x94, 0xc1, 0xb1, 0xcc, 0x12, 0x4e, 0x9b, 0xa1, - 0xbb, 0x70, 0x6d, 0x66, 0x69, 0x27, 0xce, 0xa9, 0x3d, 0x91, 0x93, 0x28, 0x39, 0xd3, 0x06, 0x64, - 0x8d, 0x14, 0xd8, 0x95, 0xa9, 0x45, 0xdc, 0x73, 0x4e, 0xf7, 0x88, 0x86, 0xcd, 0xc9, 0x57, 0x70, - 0x75, 0xa6, 0x17, 0x2e, 0x44, 0x97, 0xa1, 0x73, 0x14, 0x48, 0x8f, 0xb6, 0xc8, 0x1b, 0xd6, 0xa5, - 0xa9, 0x2e, 0x0e, 0x90, 0xe2, 0x1e, 0x13, 0x88, 0x2f, 0x81, 0x94, 0xbd, 0xa2, 0x93, 0x76, 0xb6, - 0x72, 0x9d, 0x90, 0x76, 0xc5, 0xf3, 0xaa, 0x0a, 0xe4, 0x45, 0x3e, 0x86, 0x87, 0x9a, 0xd2, 0xea, - 0x16, 0xc4, 0xa4, 0x39, 0x3f, 0x86, 0xb6, 0xd9, 0x58, 0xa6, 0xb6, 0x97, 0xa8, 0xed, 0x32, 0xb7, - 0xd5, 0x5b, 0xc9, 0xd4, 0xb0, 0x35, 0x2a, 0x5e, 0xc4, 0x26, 0xc0, 0x89, 0x33, 0x3a, 0x71, 0xb8, - 0xcd, 0xe5, 0x72, 0x80, 0xff, 0x2d, 0xc2, 0xa9, 0x45, 0xf3, 0xc4, 0x3c, 0x8a, 0xcf, 0xe1, 0x92, - 0x91, 0xc2, 0x67, 0xc7, 0x51, 0xa0, 0x1d, 0xf6, 0x91, 0x13, 0x46, 0x59, 0xaa, 0x37, 0xca, 0xd7, - 0x34, 0xc1, 0x77, 0x88, 0x47, 0x01, 0xb8, 0x4f, 0x58, 0xed, 0xb0, 0x1e, 0x41, 0x93, 0xb6, 0x79, - 0xa8, 0xb7, 0xfc, 0xd0, 0x43, 0xe5, 0xe5, 0x87, 0x1e, 0x3e, 0x80, 0xb6, 0x8e, 0x66, 0x5e, 0x74, - 0x8a, 0xa2, 0xc5, 0x78, 0x4e, 0x88, 0xbe, 0x0f, 0x4d, 0x0a, 0x65, 0xe8, 0x1b, 0xd7, 0xa0, 0xc5, - 0x27, 0xed, 0x8e, 0x82, 0xc8, 0x3d, 0x31, 0xc1, 0x07, 0x81, 0xee, 0x20, 0x64, 0x08, 0xd0, 0x78, - 0x1c, 0xfa, 0x51, 0xb8, 0x1d, 0x04, 0xc3, 0x3f, 0xd5, 0xa0, 0x89, 0x3e, 0x0f, 0xed, 0x4b, 0x61, - 0xd8, 0x48, 0x8c, 0x49, 0x75, 0x15, 0x13, 0x27, 0xd6, 0xc7, 0x3a, 0x5a, 0x08, 0x44, 0xaa, 0x3d, - 0x27, 0x9e, 0x29, 0xbb, 0x58, 0x98, 0x29, 0xbb, 0x78, 0x93, 0xcf, 0x7d, 0x72, 0xd5, 0xac, 0x34, - 0xe5, 0xf6, 0xd4, 0xc1, 0x1d, 0x06, 0xa1, 0x2f, 0x46, 0x24, 0x4e, 0x40, 0xfe, 0x1b, 0x46, 0x87, - 0x81, 0xd2, 0x15, 0x1a, 0x24, 0x17, 0xdb, 0x1a, 0x71, 0x20, 0xd9, 0xde, 0x94, 0x36, 0x23, 0xab, - 0xb3, 0x9b, 0x91, 0x37, 0x01, 0xdc, 0x28, 0xf4, 0xc8, 0x45, 0x9c, 0x49, 0x48, 0x73, 0x79, 0x44, - 0x81, 0xfd, 0x11, 0xdb, 0xe4, 0xef, 0x40, 0x3f, 0xa7, 0x40, 0x0f, 0xd0, 0x0d, 0xf3, 0xf8, 0x5a, - 0x53, 0x59, 0x72, 0xb4, 0x13, 0xa6, 0xb3, 0xfb, 0xe9, 0xcd, 0x73, 0xfb, 0xe9, 0x2f, 0x28, 0xa4, - 0x81, 0x9f, 0x7c, 0x7a, 0xee, 0x12, 0x34, 0xa8, 0x62, 0xcf, 0xcb, 0x62, 0x6d, 0x8b, 0xea, 0xbe, - 0xa2, 0xbc, 0xc7, 0x8b, 0xf6, 0xec, 0xdb, 0xff, 0xbf, 0xf6, 0xec, 0x3b, 0x3f, 0x6e, 0xcf, 0xbe, - 0xfb, 0xe3, 0xf6, 0xec, 0x67, 0xf6, 0xb8, 0x7b, 0xb3, 0x7b, 0xdc, 0x2f, 0x4c, 0x2b, 0xf6, 0x5f, - 0x98, 0x56, 0x7c, 0x45, 0x4e, 0x70, 0xf9, 0xe5, 0x39, 0xc1, 0x57, 0x27, 0x25, 0xc5, 0xab, 0x92, - 0x92, 0x37, 0xa0, 0x97, 0x26, 0x8e, 0x7b, 0xc2, 0x91, 0xd6, 0x89, 0x3c, 0x53, 0x3a, 0x09, 0xda, - 0x21, 0x30, 0xc6, 0x59, 0xdf, 0xca, 0x33, 0x35, 0x7c, 0x0c, 0x40, 0x21, 0x28, 0xfd, 0xda, 0x8b, - 0x78, 0xa3, 0xf2, 0x93, 0x8b, 0xac, 0xfe, 0xaa, 0x02, 0x70, 0xe0, 0x4c, 0x62, 0xde, 0x43, 0x16, - 0x7f, 0x06, 0x2d, 0x45, 0x6f, 0xe5, 0x22, 0x93, 0x92, 0xa1, 0x2e, 0x48, 0xf5, 0x23, 0x1f, 0xee, - 0x52, 0xf9, 0x33, 0xb1, 0x35, 0xf7, 0x90, 0x17, 0xb4, 0x56, 0x0d, 0x01, 0xed, 0xed, 0x5d, 0x87, - 0xae, 0x26, 0x88, 0x65, 0xe2, 0xca, 0x90, 0xeb, 0xfb, 0x2b, 0x56, 0x87, 0xa1, 0xfb, 0x0c, 0x14, - 0x1f, 0xe6, 0x64, 0xc6, 0x24, 0x9e, 0x4f, 0x99, 0xe9, 0x26, 0xda, 0x26, 0x0e, 0xb7, 0xcc, 0xaf, - 0xd0, 0x40, 0x1a, 0xb0, 0x84, 0xdf, 0xeb, 0xbf, 0x26, 0x5a, 0x50, 0xd7, 0xbd, 0xf6, 0x2b, 0xa2, - 0x03, 0x4d, 0x3a, 0x4d, 0x48, 0xb8, 0x85, 0xe1, 0xff, 0x5e, 0x81, 0xd6, 0x6e, 0xa8, 0xd2, 0x24, - 0x63, 0x16, 0x2e, 0xce, 0xcc, 0x55, 0xe9, 0xcc, 0x9c, 0xae, 0x03, 0xe7, 0xdf, 0xa0, 0x3a, 0xf0, - 0x0f, 0xa0, 0xae, 0x8f, 0x67, 0xea, 0xc4, 0xc2, 0xdc, 0xb3, 0x9d, 0x86, 0x46, 0x6c, 0x42, 0xc3, - 0xd3, 0xe7, 0x46, 0x75, 0x25, 0x4d, 0xe9, 0x30, 0xa7, 0x39, 0x51, 0x6a, 0xe5, 0x34, 0xe2, 0x4d, - 0x58, 0x74, 0xc6, 0x63, 0x1d, 0xd5, 0xf7, 0x0a, 0x52, 0x72, 0xd2, 0x2c, 0xc4, 0x89, 0x5b, 0xd0, - 0x24, 0xf5, 0x49, 0x55, 0x6d, 0xb5, 0xd9, 0x3e, 0x4d, 0xc9, 0x1c, 0x6b, 0x54, 0xca, 0x49, 0xdc, - 0x82, 0x66, 0x10, 0x45, 0x31, 0x37, 0xa8, 0xcf, 0x36, 0x30, 0xf5, 0x45, 0x56, 0x23, 0x30, 0x95, - 0x46, 0x37, 0xa0, 0x86, 0xee, 0x7f, 0x14, 0x6b, 0xb7, 0xb9, 0x34, 0x0e, 0xaa, 0xb3, 0xb1, 0xaa, - 0x8a, 0xca, 0x6d, 0xb6, 0x00, 0x98, 0xff, 0xa9, 0xe7, 0xe6, 0xec, 0x74, 0xe4, 0xb9, 0x55, 0x14, - 0x52, 0x93, 0x66, 0xbd, 0x03, 0x7d, 0xce, 0xa3, 0x95, 0x5a, 0x82, 0xa9, 0x05, 0x36, 0x2d, 0xa7, - 0x53, 0xb3, 0x56, 0x37, 0x99, 0x4e, 0xd5, 0xbe, 0x07, 0xf5, 0x98, 0x93, 0x43, 0xa4, 0x61, 0xc8, - 0x64, 0x9b, 0xa6, 0x3a, 0x6b, 0x64, 0x19, 0x0a, 0xf1, 0x6b, 0xe8, 0x72, 0xcd, 0xea, 0x48, 0x67, - 0x49, 0x68, 0x67, 0x6f, 0xea, 0x64, 0xdf, 0x54, 0x12, 0xc5, 0xea, 0xa4, 0x53, 0x39, 0x95, 0x5f, - 0x42, 0xa7, 0x38, 0xb0, 0x84, 0x16, 0xbf, 0x67, 0xb2, 0x15, 0xa6, 0x79, 0x39, 0x1a, 0xb3, 0xda, - 0xb2, 0x1c, 0x9b, 0x6d, 0x40, 0x4d, 0xd7, 0x51, 0xf7, 0xa9, 0x55, 0xe9, 0xd6, 0x05, 0xae, 0x9c, - 0xb4, 0x34, 0x1e, 0xe7, 0xb2, 0x28, 0x11, 0x25, 0xc7, 0x71, 0x6a, 0x2e, 0xf3, 0xfa, 0x50, 0xab, - 0x99, 0x97, 0x86, 0x8a, 0x7b, 0xd3, 0x25, 0xab, 0x9c, 0xd4, 0x5b, 0xa1, 0xa6, 0x97, 0xe6, 0x34, - 0xe5, 0xf4, 0x9e, 0xd5, 0x8b, 0x67, 0x2a, 0x5f, 0xdf, 0x87, 0x46, 0x94, 0x78, 0x74, 0x3e, 0x80, - 0xaa, 0x28, 0x72, 0x17, 0x48, 0x9f, 0x49, 0x25, 0xe5, 0x51, 0x8f, 0xf8, 0x05, 0x1d, 0x8b, 0x38, - 0x89, 0xc8, 0xcb, 0x25, 0x15, 0x77, 0xe1, 0xbc, 0x63, 0xa1, 0xf1, 0xa4, 0xe0, 0xde, 0x86, 0xba, - 0xa9, 0x0e, 0x5f, 0x3b, 0x47, 0x69, 0x50, 0xe2, 0x23, 0xe8, 0x4d, 0x2b, 0x34, 0x35, 0xb8, 0x78, - 0x8e, 0xba, 0x3b, 0xa5, 0xbf, 0xd0, 0x1a, 0x57, 0x03, 0x7f, 0xe2, 0xa7, 0xda, 0xe7, 0x9b, 0x3a, - 0x21, 0x4a, 0x08, 0x8c, 0xff, 0x74, 0x0a, 0xe4, 0xd2, 0xf9, 0xf8, 0x4f, 0xa7, 0x49, 0x06, 0x50, - 0xf7, 0xd5, 0x7d, 0x3f, 0x51, 0xa9, 0xae, 0x6f, 0x30, 0xaf, 0x62, 0x0d, 0x6a, 0xbe, 0x42, 0x33, - 0xa1, 0xbd, 0x34, 0xfd, 0x26, 0x6e, 0x42, 0x4d, 0x57, 0xce, 0xaf, 0x9f, 0x93, 0x68, 0x7d, 0xb2, - 0xc6, 0xd2, 0x14, 0xe2, 0x5d, 0xa8, 0x53, 0xd9, 0x74, 0x14, 0x0f, 0xde, 0x9c, 0xe5, 0x00, 0xae, - 0x5d, 0xb6, 0x6a, 0x01, 0xd7, 0x30, 0xbf, 0x07, 0x75, 0xe3, 0xa4, 0x0c, 0x67, 0xb9, 0x5a, 0x3b, - 0x2b, 0x96, 0xa1, 0x10, 0xd7, 0xa1, 0x3a, 0x41, 0x3d, 0x36, 0x78, 0x6b, 0x56, 0x42, 0x59, 0xbd, - 0x31, 0x56, 0xfc, 0x5d, 0xb8, 0x5c, 0x2e, 0x3c, 0x36, 0x55, 0xc9, 0x7a, 0x83, 0xf3, 0x3a, 0xb5, - 0x7d, 0x73, 0x0e, 0xab, 0x4c, 0xd7, 0x2f, 0x5b, 0x17, 0xe3, 0x17, 0x14, 0x36, 0x7f, 0x92, 0xab, - 0x7b, 0x94, 0xae, 0xc1, 0x0d, 0xe3, 0x7c, 0x9f, 0x37, 0x18, 0xc6, 0x08, 0x90, 0x9d, 0xf9, 0x0c, - 0xda, 0xa3, 0xec, 0xf9, 0xf3, 0x33, 0xb3, 0x39, 0xff, 0x0e, 0xb5, 0x2b, 0x6d, 0x31, 0x94, 0x6a, - 0x9d, 0xad, 0xd6, 0xa8, 0x54, 0xf8, 0x7c, 0x11, 0xea, 0x6e, 0x68, 0x3b, 0x9e, 0x97, 0x0c, 0x36, - 0xb8, 0xd6, 0xd9, 0x0d, 0xb7, 0x3d, 0x8f, 0x2e, 0x77, 0x88, 0x62, 0x49, 0x27, 0xa4, 0x6d, 0xdf, - 0x1b, 0xbc, 0xcb, 0x86, 0xc7, 0x80, 0x76, 0x3d, 0xba, 0xfd, 0xc1, 0xc4, 0xe5, 0xbe, 0x37, 0xb8, - 0xa9, 0x6f, 0x7f, 0xd0, 0xa0, 0x5d, 0x0f, 0x1d, 0x4f, 0x0c, 0x62, 0x0c, 0x64, 0xf0, 0x1e, 0x27, - 0x3c, 0x26, 0xce, 0xe9, 0xbe, 0x06, 0xa1, 0x90, 0x72, 0x6a, 0x8f, 0xd4, 0xd6, 0xfb, 0xb3, 0x42, - 0x9a, 0xa7, 0x81, 0xad, 0xa6, 0x9f, 0x67, 0x84, 0x49, 0xb0, 0x49, 0x15, 0xd9, 0xc1, 0xd6, 0xe0, - 0x83, 0xf3, 0x82, 0xad, 0xb3, 0xdc, 0x28, 0xd8, 0x26, 0xe1, 0xbd, 0x05, 0xc0, 0x3a, 0x8b, 0x14, - 0xce, 0xe6, 0x6c, 0x9b, 0x3c, 0x1a, 0xb0, 0xf8, 0x48, 0x13, 0xa9, 0x9a, 0x2d, 0x00, 0x4a, 0x2f, - 0x70, 0x9b, 0x5b, 0xb3, 0x6d, 0x72, 0xef, 0xde, 0x6a, 0x3e, 0xcd, 0x1d, 0xfd, 0x5b, 0xd0, 0xcc, - 0xd0, 0x8f, 0x47, 0x4f, 0x7a, 0x70, 0x7b, 0x96, 0x99, 0x8d, 0x8b, 0x6f, 0x35, 0x32, 0xfd, 0x84, - 0x1f, 0x21, 0xdb, 0x43, 0x6e, 0xc8, 0xe0, 0xc3, 0xd9, 0x8f, 0xe4, 0x71, 0x80, 0x45, 0x26, 0x8a, - 0x43, 0x82, 0x4f, 0xa0, 0xc5, 0x93, 0xc6, 0x8d, 0xb6, 0x66, 0x79, 0xa4, 0xf0, 0x6b, 0x2c, 0x9e, - 0x5d, 0x6e, 0x76, 0x1d, 0xaa, 0x4e, 0x1c, 0x07, 0x67, 0x83, 0x8f, 0x66, 0x39, 0x7c, 0x1b, 0xc1, - 0x16, 0x63, 0x91, 0x95, 0x26, 0x59, 0x90, 0xfa, 0xe6, 0x14, 0xd2, 0xc7, 0xb3, 0xac, 0x54, 0x3a, - 0xd6, 0x69, 0xb5, 0x26, 0xa5, 0x33, 0x9e, 0xef, 0x43, 0x23, 0x8e, 0x54, 0x6a, 0x7b, 0x93, 0x60, - 0xf0, 0xc9, 0x39, 0x33, 0xc2, 0x27, 0x52, 0xac, 0x7a, 0xac, 0x8f, 0xf4, 0x4c, 0x9d, 0x92, 0xfe, - 0xc5, 0xcc, 0x29, 0xe9, 0x2d, 0x68, 0x4f, 0xa2, 0x70, 0x1c, 0x79, 0x47, 0x3c, 0xfb, 0x9f, 0x96, - 0x83, 0xc2, 0x3d, 0xc4, 0x70, 0x18, 0xa9, 0x89, 0xb4, 0x69, 0xe8, 0x6b, 0xdf, 0xcd, 0x57, 0xb6, - 0xa3, 0x48, 0xed, 0x7f, 0xc6, 0x21, 0x3c, 0xc3, 0x77, 0xd5, 0x36, 0x41, 0xa7, 0xb7, 0xb7, 0x8f, - 0xce, 0x74, 0x2e, 0xf2, 0x73, 0x62, 0xcf, 0x62, 0x7b, 0xfb, 0xce, 0x19, 0x27, 0x24, 0xbf, 0x80, - 0xcb, 0xa5, 0x73, 0x8b, 0x51, 0x6c, 0x87, 0x36, 0xaa, 0x80, 0x44, 0x7a, 0x99, 0x2b, 0x07, 0x5f, - 0xe4, 0xf1, 0xa6, 0x3e, 0xbc, 0x18, 0xc5, 0x0f, 0xf7, 0x13, 0x69, 0x11, 0x56, 0x3c, 0x2c, 0x9f, - 0x91, 0x74, 0x82, 0x71, 0x94, 0xf8, 0xe9, 0xf1, 0x64, 0xf0, 0x4b, 0xf2, 0x03, 0x5f, 0x2f, 0xc5, - 0x03, 0x79, 0xfe, 0x6b, 0xdb, 0x10, 0x59, 0xc5, 0x18, 0x73, 0x98, 0xf8, 0x02, 0x2e, 0x69, 0x5b, - 0x80, 0x1d, 0x4e, 0x1d, 0x45, 0x57, 0x83, 0x5f, 0xd1, 0x59, 0xf4, 0x8b, 0x05, 0xc1, 0xd7, 0xa5, - 0x53, 0xe9, 0x4a, 0x6c, 0xc3, 0xeb, 0xf3, 0xda, 0xa2, 0x63, 0xc2, 0x13, 0xf0, 0x25, 0x4d, 0xc0, - 0xe5, 0xf3, 0xed, 0x0f, 0x24, 0xdf, 0x4b, 0xc3, 0xe1, 0xf3, 0x6f, 0x96, 0x1a, 0xcb, 0x7d, 0xf1, - 0x9b, 0xa5, 0xc6, 0xdb, 0xfd, 0xeb, 0x56, 0xab, 0xb4, 0x55, 0x30, 0xfc, 0x04, 0xda, 0xdb, 0x74, - 0x21, 0x91, 0xaf, 0xc8, 0x54, 0x5d, 0x87, 0xa5, 0xbc, 0xc4, 0x24, 0xb7, 0x81, 0x44, 0xf1, 0x5c, - 0xee, 0x86, 0xa3, 0xc8, 0x22, 0xf4, 0xf0, 0xdf, 0x2c, 0x41, 0x8d, 0xd3, 0xfe, 0xaf, 0x3e, 0x74, - 0xf8, 0xba, 0x11, 0xe4, 0xb0, 0x38, 0x9d, 0xc1, 0x32, 0x4b, 0xe8, 0xd9, 0x2a, 0xec, 0x66, 0x51, - 0xbd, 0xb2, 0x0a, 0x55, 0x8e, 0xbe, 0x39, 0x29, 0xc1, 0x2f, 0xa4, 0xc4, 0x32, 0x75, 0x4c, 0xb7, - 0x0e, 0xe9, 0x34, 0xdb, 0x92, 0x05, 0x06, 0xb4, 0xeb, 0xd1, 0xee, 0xa3, 0x21, 0x20, 0x2d, 0x59, - 0xd3, 0xd9, 0x05, 0x0d, 0x24, 0x5d, 0x69, 0x2a, 0x63, 0xea, 0x2f, 0xa8, 0x8c, 0x79, 0x03, 0x96, - 0x42, 0x73, 0x70, 0x28, 0xc7, 0xd3, 0xad, 0x23, 0x04, 0x17, 0x37, 0x21, 0x3f, 0x29, 0xa9, 0xbd, - 0xbe, 0x17, 0x9f, 0xa4, 0xdc, 0x82, 0x66, 0x7e, 0x85, 0x95, 0x76, 0xf4, 0x56, 0x37, 0x8b, 0x4b, - 0xad, 0x0e, 0xcd, 0x93, 0x55, 0x90, 0xbd, 0xbc, 0xbe, 0xa3, 0xf5, 0xf3, 0xea, 0x3b, 0x38, 0x0a, - 0x76, 0xa3, 0x50, 0xa5, 0x7a, 0x7f, 0xb5, 0xee, 0xab, 0x1d, 0x7c, 0x15, 0x9f, 0x43, 0x27, 0x91, - 0xee, 0x53, 0x7b, 0xa2, 0xc6, 0xfc, 0x89, 0x4e, 0xf9, 0xb4, 0xf6, 0x44, 0x8d, 0xbf, 0xa1, 0xda, - 0x13, 0x1d, 0x94, 0xb6, 0x90, 0x76, 0x4f, 0x8d, 0xa9, 0xd7, 0xf7, 0x60, 0x79, 0x22, 0x27, 0x47, - 0x32, 0x51, 0xc7, 0x7e, 0x6c, 0xac, 0x59, 0x97, 0x6a, 0x64, 0xfa, 0x05, 0x82, 0xc7, 0x32, 0xfc, - 0x87, 0x15, 0x68, 0xe0, 0x2c, 0x22, 0x2f, 0x09, 0x01, 0x4b, 0x13, 0x37, 0xce, 0x74, 0xac, 0x41, - 0xcf, 0xfa, 0x5a, 0x2c, 0xe6, 0x12, 0x7d, 0x2d, 0x16, 0xad, 0x21, 0x67, 0x0d, 0xe9, 0x99, 0x6f, - 0x3a, 0x39, 0xa3, 0x8d, 0x65, 0xe6, 0x0c, 0xf3, 0x2a, 0x2e, 0x40, 0xcd, 0x0d, 0x69, 0xc3, 0x81, - 0xb3, 0xaf, 0x55, 0x37, 0xdc, 0x09, 0x53, 0x0d, 0x2e, 0x0e, 0x9f, 0x54, 0xdd, 0x70, 0xd7, 0x3b, - 0x1d, 0xfe, 0xfb, 0x0a, 0x2c, 0xef, 0x27, 0x91, 0x2b, 0x95, 0x7a, 0x80, 0xbe, 0x12, 0x65, 0xba, - 0xf0, 0x8b, 0x94, 0x18, 0xe0, 0xa4, 0x12, 0x3d, 0x23, 0x0f, 0xf3, 0x6e, 0x50, 0x1e, 0xd1, 0x2d, - 0x5a, 0x4d, 0x82, 0x50, 0x40, 0x97, 0xa3, 0x4b, 0x15, 0x14, 0x8c, 0xa6, 0x94, 0xc2, 0x75, 0xe8, - 0x16, 0x2a, 0xa5, 0x54, 0xec, 0x51, 0xdc, 0x47, 0x40, 0xbd, 0x5c, 0x83, 0x96, 0x2e, 0x09, 0xa2, - 0x6e, 0x38, 0x4b, 0x04, 0x0c, 0x3a, 0xd0, 0xa3, 0x60, 0xfd, 0x4b, 0x78, 0xce, 0x0b, 0xb1, 0x46, - 0x46, 0xf4, 0xf0, 0x0f, 0x15, 0xe8, 0xef, 0x27, 0x32, 0x76, 0x12, 0x49, 0x35, 0x42, 0x34, 0xc7, - 0x6b, 0x50, 0x0b, 0x64, 0x38, 0xd6, 0x65, 0x21, 0x8b, 0x96, 0x7e, 0xcb, 0xaf, 0x34, 0x5b, 0x28, - 0x5d, 0x69, 0x86, 0x73, 0x9d, 0x48, 0x47, 0xdf, 0x7c, 0x46, 0xcf, 0x28, 0x83, 0x18, 0x96, 0x73, - 0xec, 0xd9, 0xb0, 0xf8, 0x45, 0x9f, 0x7a, 0x3e, 0xf2, 0x43, 0xaa, 0xc5, 0xa4, 0x53, 0xcf, 0x77, - 0x7c, 0xd2, 0xe7, 0x0c, 0x46, 0xff, 0x8a, 0x6f, 0x0f, 0xa2, 0xdd, 0xa4, 0x86, 0xd5, 0x25, 0x02, - 0x27, 0x39, 0x3b, 0x20, 0x28, 0x85, 0xc0, 0x7c, 0xe9, 0x10, 0x17, 0x1a, 0x71, 0x1e, 0xa3, 0x63, - 0xee, 0x1c, 0x62, 0xdd, 0xa2, 0x86, 0xff, 0xb4, 0x0e, 0x2d, 0xbd, 0x42, 0xf4, 0x37, 0xcc, 0x1d, - 0x95, 0x9c, 0x3b, 0xfa, 0xb0, 0xa8, 0x9e, 0x04, 0x9a, 0x5d, 0xf0, 0x51, 0x7c, 0x04, 0x8b, 0x81, - 0x3f, 0xd1, 0x71, 0xe9, 0x95, 0x29, 0x1f, 0x63, 0x7a, 0x9d, 0x35, 0x2b, 0x23, 0x35, 0x1a, 0x36, - 0xba, 0x82, 0x01, 0x85, 0x46, 0xaf, 0x0d, 0xda, 0xfb, 0x53, 0x94, 0x4c, 0x9c, 0x75, 0xc7, 0xe5, - 0x3a, 0x60, 0xad, 0x6e, 0x3a, 0x56, 0x53, 0x43, 0x76, 0x3d, 0xf1, 0x31, 0x34, 0xf2, 0xdd, 0x73, - 0x13, 0x89, 0xa6, 0xa7, 0xe1, 0xe6, 0xce, 0xc3, 0xc3, 0xd3, 0xd0, 0x6c, 0x8f, 0xeb, 0x8f, 0xe5, - 0x94, 0xe2, 0xd7, 0xd0, 0x56, 0x52, 0x29, 0x3e, 0x23, 0x3f, 0x8a, 0xb4, 0x1a, 0xba, 0x50, 0x0e, - 0x32, 0x09, 0x8b, 0x7f, 0x6d, 0x84, 0x4e, 0x15, 0x20, 0xf1, 0x0d, 0x74, 0x4d, 0xfb, 0x20, 0x1a, - 0x8f, 0xf3, 0xec, 0xce, 0x95, 0x73, 0x3d, 0x3c, 0x20, 0x74, 0xa9, 0x9f, 0x8e, 0x2a, 0x23, 0xc4, - 0xd7, 0xd0, 0x8d, 0x99, 0x69, 0x6c, 0x5d, 0xdf, 0xc6, 0xea, 0xec, 0xf2, 0x94, 0x4b, 0x3c, 0xc5, - 0x54, 0xc5, 0x59, 0xd0, 0x02, 0xae, 0xce, 0xdf, 0x17, 0xc1, 0xe9, 0xbe, 0xe9, 0xfb, 0x22, 0x24, - 0xac, 0xe9, 0x0b, 0x9e, 0x46, 0x89, 0x43, 0xe7, 0xde, 0xd9, 0x92, 0x99, 0xa2, 0xd5, 0x5b, 0xe7, - 0x56, 0x0c, 0x3f, 0xb8, 0xc9, 0xf7, 0x22, 0xdc, 0xd7, 0x4d, 0xc8, 0xb2, 0xe9, 0x0a, 0xa0, 0xd5, - 0x64, 0x0e, 0x4a, 0x6c, 0xc2, 0x8a, 0xfe, 0x8c, 0x3c, 0x95, 0x6e, 0xa6, 0xaf, 0xfc, 0x20, 0xa5, - 0xd7, 0xb6, 0x96, 0x19, 0x75, 0xcf, 0x60, 0x76, 0x3d, 0xf1, 0x19, 0x0c, 0x54, 0xea, 0xa4, 0x92, - 0x06, 0x64, 0xf4, 0xae, 0x3f, 0x0e, 0xa3, 0x44, 0xea, 0xaa, 0x99, 0xb5, 0x1c, 0xaf, 0xf5, 0xed, - 0x2e, 0x61, 0xc5, 0xaf, 0xa1, 0x8f, 0x2a, 0x32, 0xcf, 0xa0, 0xd8, 0xa9, 0xd2, 0xc1, 0xf5, 0x7c, - 0x15, 0xdf, 0x45, 0x6a, 0xc3, 0x16, 0x87, 0x94, 0x89, 0xa7, 0xf6, 0x63, 0x19, 0xa2, 0x9b, 0x4e, - 0x1a, 0x42, 0x66, 0x4a, 0x7a, 0xfa, 0x56, 0x97, 0x55, 0xc4, 0x7e, 0x9d, 0x23, 0x2d, 0xc2, 0xa1, - 0x63, 0x60, 0xc4, 0x47, 0x6f, 0xa0, 0x92, 0x4b, 0x5a, 0xb8, 0x2b, 0x7d, 0x62, 0xd3, 0xcb, 0x5a, - 0x9a, 0x98, 0x06, 0x3d, 0xd3, 0xdc, 0x2f, 0xb9, 0xfc, 0x35, 0x5c, 0x7a, 0xe1, 0xac, 0xbe, 0xaa, - 0x8c, 0xa7, 0x53, 0xbe, 0x83, 0xe0, 0xff, 0x2c, 0x42, 0xab, 0xc4, 0xad, 0x74, 0x91, 0xa1, 0x92, - 0x89, 0x29, 0xd6, 0xc3, 0x67, 0x84, 0x1d, 0x47, 0xca, 0xd4, 0x9e, 0xd1, 0x33, 0xc2, 0x92, 0x28, - 0xaf, 0xc1, 0xa1, 0x67, 0xe4, 0x21, 0xbd, 0x6b, 0xa4, 0x57, 0x6c, 0x89, 0xef, 0xce, 0x28, 0x80, - 0xbb, 0x1e, 0xdd, 0x78, 0xe8, 0xa4, 0xce, 0x91, 0xa3, 0x4c, 0xd5, 0x65, 0xfe, 0x8e, 0xa6, 0xe1, - 0xa9, 0x4c, 0x70, 0x2c, 0xa6, 0xe6, 0x40, 0xbf, 0xa2, 0x8c, 0xd3, 0xaa, 0x3e, 0x8f, 0x42, 0xae, - 0x37, 0x68, 0x5b, 0x0d, 0x04, 0x7c, 0x1f, 0x85, 0xd4, 0x4c, 0x4b, 0xb4, 0xae, 0x9b, 0x31, 0xaf, - 0x68, 0x33, 0x9f, 0x64, 0x12, 0xc3, 0x45, 0x8f, 0xce, 0x18, 0x36, 0xad, 0x3a, 0xbd, 0x73, 0x29, - 0x0f, 0xc5, 0xb5, 0xcf, 0x1c, 0x3f, 0x25, 0xd5, 0x11, 0x65, 0xa9, 0x66, 0xfa, 0x1e, 0x22, 0xbe, - 0x73, 0xfc, 0xf4, 0x90, 0xc1, 0xe2, 0x43, 0x7d, 0x74, 0xb8, 0x4c, 0x4b, 0x77, 0xf7, 0xf0, 0x6e, - 0xb4, 0x98, 0xa1, 0x3f, 0x90, 0x74, 0x3d, 0xdd, 0xc4, 0x49, 0x13, 0xff, 0x34, 0x0a, 0xd1, 0x77, - 0xa2, 0x63, 0xfa, 0xf9, 0x2d, 0x8b, 0x0d, 0x6b, 0x25, 0x47, 0x3e, 0x24, 0x1c, 0x25, 0x68, 0x1f, - 0xc3, 0x86, 0x3c, 0x8d, 0x03, 0xdf, 0xf5, 0x67, 0xae, 0x1b, 0xb0, 0x5d, 0x47, 0xa5, 0x76, 0x22, - 0xd3, 0x2c, 0x09, 0x15, 0x6d, 0xb4, 0x6a, 0xbe, 0x7e, 0xcb, 0xd0, 0x97, 0xaf, 0x20, 0xd8, 0x71, - 0x54, 0x6a, 0x31, 0xed, 0xc3, 0x2c, 0x08, 0x70, 0x12, 0xf2, 0xc4, 0x30, 0xd7, 0x84, 0xd5, 0x15, - 0xa7, 0x84, 0x87, 0xff, 0xb9, 0x02, 0xcb, 0xe7, 0x34, 0x0d, 0x86, 0xa8, 0xa8, 0x65, 0x4c, 0x1d, - 0x4b, 0xdb, 0xaa, 0xe1, 0xeb, 0xae, 0x47, 0x88, 0x74, 0x92, 0x9a, 0x0a, 0x16, 0x44, 0xa4, 0x13, - 0x54, 0xa3, 0x17, 0xa0, 0x96, 0x9e, 0xd2, 0x92, 0xb3, 0xf5, 0xa9, 0xa6, 0xa7, 0xb8, 0xd6, 0xdb, - 0xd0, 0x0c, 0xa2, 0xb1, 0x1d, 0xc8, 0xa7, 0x92, 0xef, 0x80, 0xe9, 0x6e, 0xbd, 0xfd, 0x12, 0x15, - 0xb7, 0xf9, 0x20, 0x1a, 0x3f, 0x40, 0x5a, 0xab, 0x11, 0xe8, 0xa7, 0xe1, 0x6f, 0xa0, 0x61, 0xa0, - 0xa2, 0x09, 0xd5, 0xbb, 0xf2, 0x28, 0x1b, 0xf7, 0x5f, 0x13, 0x0d, 0x58, 0xc2, 0x16, 0xfd, 0x0a, - 0x3e, 0x7d, 0xe7, 0x24, 0x61, 0x7f, 0x01, 0xd1, 0xf7, 0x92, 0x24, 0x4a, 0xfa, 0x8b, 0xf8, 0xb8, - 0xef, 0x84, 0xbe, 0xdb, 0x5f, 0xc2, 0xc7, 0xfb, 0x4e, 0xea, 0x04, 0xfd, 0xea, 0xf0, 0xf7, 0x55, - 0x68, 0xec, 0xeb, 0xaf, 0x8b, 0xbb, 0xd0, 0xc9, 0xef, 0x52, 0x9c, 0xbf, 0x57, 0xbc, 0x3f, 0xfb, - 0x40, 0x7b, 0xc5, 0xed, 0xb8, 0xf4, 0x36, 0x7b, 0x23, 0xe3, 0xc2, 0xb9, 0x1b, 0x19, 0xaf, 0xc2, - 0xe2, 0x93, 0xe4, 0x6c, 0xba, 0x84, 0x7b, 0x3f, 0x70, 0x42, 0x0b, 0xc1, 0xe2, 0x43, 0x68, 0x51, - 0x96, 0x9a, 0xcd, 0xa8, 0xde, 0x5f, 0x2d, 0x5f, 0x7e, 0xca, 0xc5, 0xb9, 0x80, 0x44, 0xda, 0x63, - 0xdf, 0x84, 0x86, 0x7b, 0xec, 0x07, 0x5e, 0x22, 0x43, 0x7d, 0x94, 0x42, 0x9c, 0x1f, 0xb2, 0x95, - 0xd3, 0x88, 0x3f, 0x83, 0xbe, 0x5f, 0xec, 0x0f, 0x17, 0x45, 0x09, 0x53, 0xf6, 0xaa, 0xb4, 0x83, - 0x6c, 0xf5, 0x4a, 0xe4, 0xe4, 0x22, 0x16, 0x97, 0xa4, 0xd4, 0xcb, 0x97, 0xa4, 0xf0, 0x1d, 0x79, - 0xe4, 0xc7, 0x35, 0xf2, 0xdd, 0x25, 0x74, 0xe3, 0x6e, 0x68, 0xe7, 0xbb, 0x39, 0x1b, 0x8e, 0x1b, - 0xd7, 0x51, 0x3b, 0xe1, 0x6f, 0x43, 0x17, 0x9d, 0x7a, 0x9b, 0x63, 0x01, 0xb4, 0xa3, 0xa0, 0xef, - 0x74, 0xca, 0xd4, 0xf1, 0x5d, 0x8c, 0x06, 0x90, 0x19, 0xaf, 0x43, 0xd7, 0xfc, 0x8b, 0x0e, 0x9b, - 0x5a, 0xba, 0x68, 0x41, 0x43, 0x39, 0x68, 0xdc, 0x84, 0x15, 0xf7, 0xd8, 0x09, 0x43, 0x19, 0xd8, - 0x47, 0xd9, 0x68, 0x64, 0xdc, 0x30, 0xbe, 0xe8, 0x6b, 0x59, 0xa3, 0xee, 0x10, 0x86, 0xbc, 0xb1, - 0x21, 0x74, 0x42, 0x3f, 0x30, 0x97, 0x7d, 0x86, 0xec, 0x32, 0x57, 0xad, 0x56, 0xe8, 0x07, 0x7c, - 0xbd, 0x27, 0xdd, 0x4a, 0xda, 0xcf, 0x32, 0xdf, 0x53, 0x76, 0x1a, 0x99, 0xeb, 0x05, 0x75, 0xa6, - 0xa7, 0xb4, 0x77, 0xfa, 0x38, 0xf3, 0xbd, 0xc3, 0x48, 0x5f, 0x30, 0xd8, 0x21, 0x7a, 0xf3, 0x3a, - 0xfc, 0x0a, 0xda, 0x65, 0xde, 0x41, 0x5e, 0xa4, 0xcd, 0xad, 0xfe, 0x6b, 0x02, 0xa0, 0xf6, 0x30, - 0x4a, 0x26, 0x4e, 0xd0, 0xaf, 0xe0, 0x33, 0x2b, 0xf3, 0xfe, 0x82, 0x68, 0x43, 0xc3, 0x6c, 0xd6, - 0xf4, 0x17, 0x75, 0xfa, 0xf4, 0x97, 0xd0, 0x30, 0xb7, 0x26, 0xd2, 0x8d, 0x73, 0x91, 0x27, 0x39, - 0x34, 0xd2, 0xb5, 0xc2, 0x08, 0xa0, 0xb0, 0xc8, 0xdc, 0x42, 0xbb, 0x50, 0xdc, 0x42, 0x3b, 0xfc, - 0x2d, 0xb4, 0xcb, 0x43, 0x34, 0x09, 0x81, 0x4a, 0x91, 0x10, 0x98, 0xd3, 0x8a, 0x6a, 0x58, 0x92, - 0x68, 0x62, 0x97, 0xbc, 0xf7, 0x06, 0x02, 0xf0, 0x33, 0xc3, 0x7f, 0xb0, 0x00, 0x55, 0xda, 0xc2, - 0x20, 0xef, 0x0a, 0x1f, 0x0a, 0x09, 0xaa, 0x5a, 0x4d, 0x82, 0xfc, 0x3f, 0x1c, 0xdf, 0xcd, 0x13, - 0xc4, 0x4b, 0x2f, 0x4f, 0x10, 0x6f, 0xc3, 0xf2, 0xd3, 0xd2, 0x4d, 0xa7, 0xbc, 0x71, 0x51, 0x35, - 0xae, 0x18, 0xb6, 0xf9, 0xf3, 0xe2, 0xc6, 0x53, 0xda, 0xbe, 0xe8, 0x3d, 0x9d, 0x06, 0x88, 0x37, - 0x41, 0x9f, 0x84, 0xb0, 0xb9, 0x00, 0x89, 0xab, 0x75, 0x5a, 0x0c, 0xdb, 0xa6, 0x72, 0x23, 0x0c, - 0x80, 0x4f, 0x43, 0x73, 0xfd, 0x0d, 0x17, 0x68, 0x35, 0xd3, 0xd3, 0x90, 0x4b, 0x86, 0x86, 0x13, - 0x58, 0x99, 0x73, 0x6c, 0x4b, 0xac, 0x43, 0x7b, 0x2a, 0x8d, 0xc6, 0x67, 0x29, 0xc0, 0x2d, 0xf2, - 0x66, 0x1f, 0xc3, 0x9a, 0x0c, 0xfc, 0xb1, 0x7f, 0xe4, 0x53, 0x95, 0x6a, 0xe9, 0x24, 0x19, 0x2b, - 0x91, 0xd5, 0x12, 0x36, 0x3f, 0x49, 0x76, 0xf3, 0xdf, 0x56, 0xa0, 0xc6, 0xb7, 0x1d, 0x8b, 0x65, - 0xe8, 0x3c, 0x0e, 0x4f, 0xc2, 0xe8, 0x59, 0xc8, 0x80, 0xfe, 0x6b, 0x62, 0x05, 0x7a, 0x86, 0xdf, - 0xf4, 0xb5, 0xca, 0xfd, 0x8a, 0xe8, 0x43, 0x9b, 0x38, 0xda, 0x40, 0x16, 0xc4, 0x55, 0x18, 0x68, - 0xa7, 0xf0, 0x2e, 0x1a, 0xa0, 0x28, 0xf5, 0x47, 0x67, 0x06, 0xbb, 0x28, 0x7a, 0xd0, 0x3a, 0x48, - 0xa3, 0xf8, 0x40, 0x86, 0x9e, 0x1f, 0x8e, 0xfb, 0x4b, 0x62, 0x00, 0xab, 0xa6, 0x57, 0x2e, 0x45, - 0xb8, 0xef, 0x87, 0xbe, 0x3a, 0xee, 0x57, 0xc5, 0x15, 0xb8, 0x38, 0x0f, 0xb3, 0xed, 0x9e, 0xf4, - 0x6b, 0x62, 0x15, 0xfa, 0x06, 0x79, 0x47, 0xdf, 0x6d, 0xdb, 0xaf, 0xdf, 0xfc, 0x18, 0xc4, 0xf9, - 0x6b, 0x85, 0xf1, 0x9b, 0x0f, 0xe4, 0xd8, 0x71, 0xcf, 0x76, 0x82, 0x48, 0xa1, 0x78, 0x74, 0xa0, - 0x59, 0xf4, 0x55, 0xb9, 0x79, 0x1f, 0x6a, 0x7c, 0x0f, 0x74, 0xe9, 0xaf, 0x19, 0xd0, 0x7f, 0x0d, - 0x1b, 0xa3, 0xf1, 0xf5, 0xc3, 0xf1, 0x43, 0x79, 0x9a, 0xb2, 0x49, 0x78, 0xe0, 0xa8, 0xb4, 0xbf, - 0x20, 0xba, 0x00, 0xfa, 0xc7, 0xee, 0x85, 0x5e, 0x7f, 0xf1, 0xce, 0xce, 0x5f, 0xfe, 0xf1, 0x8d, - 0xca, 0x1f, 0xfe, 0xf8, 0x46, 0xe5, 0x3f, 0xfd, 0xf1, 0x8d, 0xd7, 0x7e, 0xf7, 0xa7, 0x37, 0x2a, - 0xdf, 0x7f, 0x58, 0xba, 0xe5, 0x5a, 0xdb, 0x64, 0xaa, 0xbe, 0xba, 0x95, 0x1b, 0xe8, 0x5b, 0xf1, - 0xc9, 0xf8, 0x56, 0x7c, 0x74, 0xcb, 0x48, 0xfc, 0x51, 0x8d, 0x2e, 0xaf, 0xfe, 0xe8, 0xff, 0x06, - 0x00, 0x00, 0xff, 0xff, 0x9c, 0xdd, 0x3b, 0xba, 0x3b, 0x5b, 0x00, 0x00, + 0x4c, 0xcb, 0x32, 0x25, 0xd3, 0xf6, 0x8c, 0xc7, 0x33, 0x1e, 0x3f, 0x8a, 0x92, 0x6c, 0x8e, 0x45, + 0x89, 0xd3, 0xa4, 0x9e, 0x01, 0x03, 0x49, 0xa3, 0xd9, 0x5d, 0xf7, 0xb2, 0xcd, 0xbe, 0xdd, 0xad, + 0xae, 0x6e, 0x89, 0xd4, 0x2a, 0x59, 0x26, 0xc8, 0x3e, 0x0f, 0x59, 0x4d, 0x90, 0x2c, 0x5e, 0x90, + 0x65, 0x30, 0x59, 0x66, 0xfd, 0x10, 0x64, 0x31, 0xab, 0x2c, 0x83, 0x60, 0x66, 0x19, 0x20, 0x09, + 0x02, 0x24, 0x08, 0x10, 0x3c, 0x20, 0x38, 0xe7, 0x54, 0x75, 0xf7, 0xbd, 0xbc, 0x92, 0x6c, 0x27, + 0x78, 0x9b, 0xf7, 0x76, 0xdd, 0xe7, 0x9c, 0xaa, 0xae, 0xae, 0x3a, 0xdf, 0x3a, 0xa7, 0x0a, 0xba, + 0xb1, 0x1f, 0xcb, 0xc0, 0x0f, 0xe5, 0x66, 0x9c, 0x44, 0x69, 0x24, 0x1a, 0xe6, 0xfd, 0xf2, 0x87, + 0x63, 0x3f, 0x3d, 0xce, 0x8e, 0x36, 0xdd, 0x68, 0x72, 0x7b, 0x1c, 0x8d, 0xa3, 0xdb, 0x44, 0x70, + 0x94, 0x8d, 0xe8, 0x8d, 0x5e, 0xe8, 0x89, 0x1b, 0x5e, 0x86, 0x20, 0x72, 0x4f, 0xcc, 0x73, 0x1c, + 0x38, 0xa1, 0x7e, 0xee, 0xa5, 0xfe, 0x44, 0xaa, 0xd4, 0x99, 0xc4, 0x1a, 0xd0, 0x4c, 0x4f, 0x35, + 0x6e, 0xf8, 0xbb, 0x1a, 0xd4, 0xf7, 0xa4, 0x52, 0xce, 0x58, 0x8a, 0x21, 0x2c, 0x2a, 0xdf, 0x1b, + 0x54, 0xd6, 0x2b, 0x1b, 0xdd, 0xad, 0xfe, 0x66, 0x3e, 0xac, 0x83, 0xd4, 0x49, 0x33, 0x65, 0x21, + 0x12, 0x69, 0xdc, 0x89, 0x37, 0x58, 0x98, 0xa5, 0xd9, 0x93, 0xe9, 0x71, 0xe4, 0x59, 0x88, 0x14, + 0x7d, 0x58, 0x94, 0x49, 0x32, 0x58, 0x5c, 0xaf, 0x6c, 0xb4, 0x2d, 0x7c, 0x14, 0x02, 0x96, 0x3c, + 0x27, 0x75, 0x06, 0x4b, 0x04, 0xa2, 0x67, 0xf1, 0x2e, 0x74, 0xe3, 0x24, 0x72, 0x6d, 0x3f, 0x1c, + 0x45, 0x36, 0x61, 0xab, 0x84, 0x6d, 0x23, 0x74, 0x37, 0x1c, 0x45, 0xf7, 0x90, 0x6a, 0x00, 0x75, + 0x27, 0x74, 0x82, 0x33, 0x25, 0x07, 0x35, 0x42, 0x9b, 0x57, 0xd1, 0x85, 0x05, 0xdf, 0x1b, 0xd4, + 0xd7, 0x2b, 0x1b, 0x4b, 0xd6, 0x82, 0xef, 0xe1, 0x37, 0xb2, 0xcc, 0xf7, 0x06, 0x0d, 0xfe, 0x06, + 0x3e, 0x8b, 0x21, 0xb4, 0x43, 0x29, 0xbd, 0x47, 0x51, 0x6a, 0xc9, 0x38, 0x38, 0x1b, 0x34, 0xd7, + 0x2b, 0x1b, 0x0d, 0x6b, 0x0a, 0x26, 0x2e, 0x43, 0xc3, 0x93, 0x47, 0xd9, 0x78, 0x4f, 0x8d, 0x07, + 0xb0, 0x5e, 0xd9, 0x68, 0x5a, 0xf9, 0xbb, 0x38, 0x84, 0x8b, 0x89, 0x7c, 0x9a, 0x49, 0x95, 0x4a, + 0xcf, 0x4e, 0xa5, 0x93, 0x78, 0xd1, 0xf3, 0xd0, 0x9e, 0x44, 0x9e, 0x1c, 0xb4, 0x68, 0x06, 0xae, + 0x96, 0x67, 0x29, 0x91, 0xce, 0xe4, 0x50, 0x13, 0xed, 0x45, 0x9e, 0xb4, 0x2e, 0xe4, 0x8d, 0xcb, + 0x60, 0x61, 0xc1, 0x9a, 0xe3, 0xba, 0x32, 0x3e, 0xdf, 0x69, 0xfb, 0x07, 0x74, 0xba, 0x6a, 0xda, + 0x4e, 0xf5, 0xf9, 0x25, 0x5c, 0x2d, 0x46, 0x7a, 0xe4, 0xa4, 0xee, 0xb1, 0xed, 0x26, 0xd2, 0xf3, + 0x53, 0xdb, 0x8d, 0xb2, 0x30, 0x1d, 0x74, 0xd6, 0x2b, 0x1b, 0x1d, 0xeb, 0x52, 0x4e, 0x73, 0x17, + 0x49, 0x76, 0x88, 0x62, 0x07, 0x09, 0x5e, 0xd1, 0xc1, 0xd1, 0x59, 0x2a, 0xd5, 0xa0, 0x4b, 0x13, + 0x3d, 0xb7, 0x83, 0xbb, 0x48, 0x20, 0xbe, 0x80, 0x2b, 0xf9, 0x5f, 0xcd, 0x19, 0x40, 0x8f, 0x06, + 0x30, 0x30, 0x24, 0xe7, 0xbe, 0xff, 0xd2, 0xe6, 0xfc, 0xf9, 0x3e, 0x7d, 0x7e, 0x5e, 0x73, 0xfe, + 0xfa, 0x75, 0xe8, 0x72, 0x2b, 0x85, 0x03, 0x0c, 0x5d, 0x39, 0x58, 0xa6, 0x16, 0x1d, 0x82, 0x1e, + 0x68, 0xa0, 0xb8, 0x05, 0x82, 0xc9, 0x1c, 0xf7, 0xa4, 0x20, 0x15, 0x44, 0xda, 0x27, 0xcc, 0xb6, + 0x7b, 0x62, 0xa8, 0x3f, 0x5f, 0xfa, 0x8b, 0xdf, 0x5d, 0x7b, 0x63, 0xf8, 0x04, 0x9a, 0x3b, 0x51, + 0x18, 0x4a, 0x37, 0x8d, 0x12, 0x71, 0x0d, 0x5a, 0x66, 0x71, 0x6c, 0x2d, 0x2b, 0x55, 0x0b, 0x0c, + 0x68, 0xd7, 0x13, 0xef, 0x41, 0xcf, 0x35, 0xd4, 0xb6, 0x1f, 0x7a, 0xf2, 0x94, 0x84, 0xa5, 0x6a, + 0x75, 0x73, 0xf0, 0x2e, 0x42, 0x87, 0xff, 0x75, 0x11, 0xea, 0x07, 0xc7, 0xd9, 0x68, 0x14, 0x48, + 0xf1, 0x2e, 0x74, 0xf4, 0xe3, 0x4e, 0x14, 0xec, 0x7a, 0xa7, 0xba, 0xdf, 0x69, 0xa0, 0x58, 0x87, + 0x96, 0x06, 0x1c, 0x9e, 0xc5, 0x52, 0x77, 0x5b, 0x06, 0x4d, 0xf7, 0xb3, 0xe7, 0x87, 0x24, 0x83, + 0x8b, 0xd6, 0x34, 0x70, 0x86, 0xca, 0x39, 0x25, 0xb1, 0x9c, 0xa6, 0x72, 0xe8, 0x6b, 0xdb, 0x81, + 0xff, 0x4c, 0x5a, 0x72, 0xbc, 0x13, 0xa6, 0x24, 0x9c, 0x55, 0xab, 0x0c, 0x12, 0x5b, 0x70, 0x41, + 0x71, 0x13, 0x3b, 0x71, 0xc2, 0xb1, 0x54, 0x76, 0xe6, 0x87, 0xe9, 0xcf, 0x3e, 0x19, 0xd4, 0xd6, + 0x17, 0x37, 0x96, 0xac, 0x15, 0x8d, 0xb4, 0x08, 0xf7, 0x84, 0x50, 0xe2, 0x0e, 0xac, 0xce, 0xb4, + 0xe1, 0x26, 0xf5, 0xf5, 0xc5, 0x8d, 0x45, 0x4b, 0x4c, 0x35, 0xd9, 0xa5, 0x16, 0xf7, 0x61, 0x39, + 0xc9, 0x42, 0x54, 0x61, 0x0f, 0xfc, 0x20, 0x95, 0xc9, 0x41, 0x2c, 0x5d, 0x12, 0xf2, 0xd6, 0xd6, + 0xc5, 0x4d, 0xd2, 0x72, 0xd6, 0x2c, 0xda, 0x3a, 0xdf, 0x42, 0xdc, 0xca, 0x27, 0xef, 0xfe, 0x69, + 0x9c, 0x90, 0x26, 0x68, 0x6d, 0x01, 0x77, 0x80, 0x10, 0xab, 0x8c, 0x16, 0x37, 0x61, 0xd9, 0x4b, + 0x1c, 0x3f, 0xb4, 0x9d, 0x20, 0xb0, 0x8f, 0x32, 0xf7, 0x44, 0xa6, 0x8a, 0xb4, 0x43, 0xc3, 0xea, + 0x11, 0x62, 0x3b, 0x08, 0xee, 0x32, 0x58, 0xdc, 0x80, 0x9e, 0x4a, 0x13, 0x3f, 0x1c, 0xdb, 0xc7, + 0x8e, 0x3a, 0xb6, 0x4f, 0xe4, 0x19, 0x29, 0x87, 0x86, 0xd5, 0x61, 0xf0, 0xd7, 0x8e, 0x3a, 0xfe, + 0x46, 0x9e, 0x0d, 0xff, 0xf7, 0x02, 0x34, 0xee, 0xf9, 0x2a, 0x46, 0x2e, 0x13, 0x17, 0xa1, 0x3e, + 0xca, 0x42, 0xb7, 0xe0, 0xa1, 0x1a, 0xbe, 0xee, 0x7a, 0xe2, 0x57, 0xd0, 0x0b, 0x22, 0xd7, 0x09, + 0xec, 0x9c, 0x5d, 0x06, 0x0b, 0xeb, 0x8b, 0x1b, 0xad, 0xad, 0x95, 0x42, 0x2b, 0xe4, 0xec, 0x68, + 0x75, 0x89, 0xb6, 0x60, 0xcf, 0x2f, 0xa0, 0x9f, 0xc8, 0x49, 0x94, 0xca, 0x52, 0xf3, 0x45, 0x6a, + 0x2e, 0x8a, 0xe6, 0xdf, 0x26, 0x4e, 0xfc, 0x08, 0x55, 0x49, 0x8f, 0x69, 0x8b, 0xe6, 0x1f, 0x95, + 0x56, 0x54, 0x8e, 0x6d, 0xdf, 0x3b, 0xb5, 0xe9, 0x03, 0x83, 0xa5, 0xf5, 0xc5, 0x8d, 0x6a, 0xb1, + 0x3c, 0x72, 0xbc, 0xeb, 0x9d, 0x3e, 0x44, 0x8c, 0xf8, 0x18, 0xd6, 0x66, 0x9b, 0x70, 0xaf, 0x83, + 0x2a, 0xb5, 0x59, 0x99, 0x6a, 0x63, 0x11, 0x4a, 0xbc, 0x0d, 0x6d, 0xd3, 0x28, 0x45, 0x56, 0xae, + 0x31, 0x73, 0xa9, 0x12, 0x2b, 0x5f, 0x84, 0xba, 0xaf, 0x6c, 0xe5, 0x87, 0x27, 0xa4, 0xe3, 0x1b, + 0x56, 0xcd, 0x57, 0x07, 0x7e, 0x78, 0x22, 0x2e, 0x41, 0x23, 0x91, 0x2e, 0x63, 0x1a, 0x84, 0xa9, + 0x27, 0xd2, 0x25, 0xd4, 0x45, 0xc0, 0x47, 0xdb, 0x4d, 0xa5, 0xd6, 0xf4, 0xb5, 0x44, 0xba, 0x3b, + 0xa9, 0x1c, 0x2a, 0xa8, 0xee, 0xc9, 0x64, 0x2c, 0x51, 0xd9, 0x63, 0xc3, 0x03, 0xd7, 0x09, 0x69, + 0xde, 0x1b, 0x56, 0xfe, 0x8e, 0xa6, 0x26, 0x76, 0x92, 0xd4, 0x77, 0x02, 0x12, 0xad, 0x86, 0x65, + 0x5e, 0xc5, 0x15, 0x68, 0xaa, 0xd4, 0x49, 0x52, 0xfc, 0x3b, 0x12, 0xa9, 0xaa, 0xd5, 0x20, 0x00, + 0x4a, 0xe5, 0x45, 0xa8, 0xcb, 0xd0, 0x23, 0xd4, 0x12, 0xaf, 0xa4, 0x0c, 0xbd, 0x5d, 0xef, 0x74, + 0xf8, 0x6f, 0x2a, 0xd0, 0xd9, 0xcb, 0x82, 0xd4, 0xdf, 0x4e, 0xc6, 0x99, 0x9c, 0x84, 0x29, 0x9a, + 0xa8, 0x7b, 0xbe, 0x4a, 0xf5, 0x97, 0xe9, 0x59, 0x6c, 0x40, 0xf3, 0xab, 0x24, 0xca, 0x62, 0xe2, + 0x4a, 0x5e, 0xe9, 0x32, 0x57, 0x16, 0x48, 0xe4, 0xe0, 0xc7, 0x89, 0x27, 0x93, 0xbb, 0x67, 0x44, + 0xbb, 0x78, 0x8e, 0xb6, 0x8c, 0x16, 0x57, 0xa1, 0x79, 0x20, 0x63, 0x27, 0x71, 0x90, 0x05, 0x96, + 0xc8, 0xae, 0x15, 0x00, 0xfc, 0x57, 0x22, 0xde, 0xf5, 0xb4, 0x60, 0x9b, 0xd7, 0xe1, 0xbf, 0xa8, + 0x40, 0x73, 0x7b, 0x3c, 0x4e, 0xe4, 0xd8, 0x49, 0xc9, 0xc8, 0x46, 0x31, 0x8d, 0x77, 0xd1, 0x5a, + 0x88, 0x62, 0x32, 0xe4, 0xf8, 0x07, 0x3c, 0x41, 0xf4, 0x2c, 0xde, 0x82, 0x25, 0x39, 0x7f, 0x40, + 0x04, 0x17, 0x6b, 0x50, 0x73, 0xa3, 0x70, 0xe4, 0x8f, 0xb5, 0xf9, 0xd7, 0x6f, 0xe2, 0x73, 0x68, + 0xf1, 0x13, 0xf3, 0x40, 0x95, 0x6c, 0xdf, 0x25, 0x6e, 0x9e, 0x8f, 0x60, 0x87, 0x28, 0x90, 0x23, + 0x2c, 0x70, 0xf3, 0xe7, 0xe1, 0x9f, 0x96, 0xa0, 0x4a, 0x33, 0x83, 0x6b, 0x83, 0xe6, 0xdc, 0x96, + 0xcf, 0x9c, 0xc0, 0x2c, 0x29, 0x02, 0xee, 0x3f, 0x73, 0x02, 0xb1, 0x0e, 0x55, 0x1c, 0x82, 0x9a, + 0x33, 0xb1, 0x8c, 0x10, 0x37, 0xa0, 0x8a, 0x5f, 0x57, 0xd3, 0xa3, 0xc7, 0x6f, 0xdc, 0x5d, 0xfa, + 0xab, 0xff, 0x74, 0xed, 0x0d, 0x8b, 0xd1, 0xe2, 0x3d, 0x58, 0x72, 0xc6, 0x63, 0x45, 0x82, 0x30, + 0x25, 0x8b, 0xf9, 0x48, 0x2d, 0x22, 0x10, 0x9f, 0x42, 0x93, 0x17, 0x1d, 0xa9, 0xab, 0x44, 0x7d, + 0xb1, 0xe4, 0x26, 0x95, 0xf9, 0xc1, 0x2a, 0x28, 0x71, 0xb9, 0x7c, 0xa5, 0x35, 0x10, 0x89, 0x43, + 0xc3, 0x2a, 0x00, 0xe8, 0xc7, 0xc4, 0x89, 0xdc, 0x0e, 0x82, 0xc8, 0x3d, 0xf0, 0x5f, 0x48, 0xed, + 0xf5, 0x4c, 0xc1, 0xc4, 0x0d, 0xe8, 0xee, 0x33, 0xbf, 0x5a, 0x52, 0x65, 0x41, 0xaa, 0xb4, 0x27, + 0x34, 0x03, 0x15, 0x9b, 0x20, 0xa6, 0x20, 0x87, 0xf4, 0xfb, 0xcd, 0xf5, 0xc5, 0x8d, 0x8e, 0x35, + 0x07, 0x23, 0xde, 0x81, 0xce, 0x18, 0x67, 0x1a, 0x15, 0xdc, 0x28, 0x70, 0xd0, 0x49, 0x5a, 0x44, + 0x27, 0xca, 0x00, 0x1f, 0x04, 0xce, 0x98, 0x24, 0x24, 0xf6, 0x83, 0xc0, 0x9e, 0xc8, 0x09, 0x69, + 0xbf, 0x45, 0xab, 0x41, 0x80, 0x3d, 0x39, 0x11, 0xef, 0xc3, 0x32, 0x11, 0xdb, 0x47, 0x67, 0x85, + 0x8a, 0x6c, 0x93, 0x76, 0xe8, 0x12, 0xe2, 0xee, 0x99, 0xd6, 0x91, 0xe2, 0x7d, 0xe8, 0x7b, 0x67, + 0xa1, 0x33, 0xf1, 0x5d, 0xdb, 0xf4, 0x4f, 0xae, 0x0b, 0xaa, 0x5d, 0x86, 0x7f, 0xa5, 0xc1, 0xa8, + 0x78, 0xe4, 0x24, 0x4e, 0xcf, 0x72, 0x42, 0x5b, 0x49, 0x94, 0x50, 0x74, 0x55, 0xd0, 0x96, 0xac, + 0x10, 0xd6, 0x90, 0x1f, 0xc8, 0x74, 0xd7, 0x53, 0x68, 0xff, 0xcf, 0x37, 0x22, 0xdf, 0xa4, 0x61, + 0xf5, 0x67, 0x1b, 0x0c, 0xff, 0xf5, 0x12, 0xd4, 0x76, 0x43, 0x25, 0x93, 0x14, 0x15, 0x87, 0x33, + 0x1a, 0x49, 0x37, 0x95, 0xac, 0xb0, 0x97, 0xac, 0xfc, 0x1d, 0xd7, 0xee, 0x30, 0xfa, 0x36, 0xf1, + 0x53, 0x79, 0xf0, 0xb1, 0x96, 0x8c, 0x02, 0x80, 0xa6, 0xc4, 0xf1, 0x3c, 0xdb, 0x50, 0xdb, 0x49, + 0xf4, 0x5c, 0x91, 0x12, 0x69, 0x58, 0x3d, 0xc7, 0xf3, 0xb6, 0x35, 0xdc, 0x8a, 0x9e, 0x2b, 0xf1, + 0x36, 0x2c, 0x26, 0x72, 0x44, 0x72, 0xd2, 0xda, 0xea, 0x31, 0x2f, 0x3e, 0x3e, 0xfa, 0x5e, 0xba, + 0xa9, 0x25, 0x47, 0x16, 0xe2, 0xc4, 0x2a, 0x54, 0x9d, 0x34, 0x4d, 0x98, 0xb7, 0x9a, 0x16, 0xbf, + 0x88, 0x4d, 0x58, 0x21, 0x65, 0x95, 0xfa, 0x51, 0x68, 0xa7, 0xce, 0x51, 0x20, 0x69, 0x26, 0xd8, + 0x10, 0x2f, 0xe7, 0xa8, 0x43, 0xc4, 0xe0, 0x3c, 0x6c, 0xc1, 0x85, 0x59, 0xfa, 0xd0, 0x99, 0x48, + 0x45, 0x76, 0xb8, 0x69, 0xad, 0x4c, 0xb7, 0x78, 0x84, 0x28, 0x64, 0x84, 0xa2, 0x0d, 0xaa, 0xbb, + 0x06, 0x69, 0x8e, 0x76, 0x0e, 0x44, 0x6d, 0x78, 0x01, 0x6a, 0xbe, 0xb2, 0x65, 0xe8, 0x69, 0x0d, + 0x5c, 0xf5, 0xd5, 0xfd, 0xd0, 0x13, 0x1f, 0x40, 0x93, 0xbf, 0xe2, 0xc9, 0x11, 0xd9, 0xd1, 0xd6, + 0x56, 0x57, 0x8b, 0x1a, 0x82, 0xef, 0xc9, 0x91, 0xd5, 0x48, 0xf5, 0x13, 0xfa, 0x58, 0x69, 0x64, + 0xcb, 0xd3, 0x54, 0x26, 0xa1, 0x13, 0x68, 0x63, 0x0a, 0x69, 0x74, 0x5f, 0x43, 0xc4, 0xa7, 0x70, + 0xd1, 0x60, 0x6d, 0x95, 0x4e, 0x52, 0x3b, 0x0b, 0xfd, 0x53, 0x3b, 0x74, 0xc2, 0x88, 0x3c, 0xe8, + 0x45, 0x6b, 0xd5, 0xa0, 0x0f, 0xd2, 0x49, 0xfa, 0x24, 0xf4, 0x4f, 0x1f, 0x39, 0x61, 0x24, 0x36, + 0xa0, 0x9f, 0x37, 0x4b, 0x5f, 0xd0, 0x0f, 0x13, 0x73, 0x35, 0xad, 0xae, 0x81, 0x1f, 0xbe, 0xc0, + 0x7f, 0x25, 0xde, 0x2a, 0x51, 0x46, 0xa3, 0x11, 0xf2, 0x96, 0x92, 0x2e, 0xb9, 0xc1, 0x55, 0x6b, + 0xa5, 0xa0, 0x7f, 0x4c, 0xb8, 0x03, 0xe9, 0x0e, 0x7f, 0x5f, 0x81, 0x16, 0x09, 0xf4, 0x93, 0xd8, + 0x43, 0xdd, 0xf9, 0x0e, 0x74, 0xa6, 0x17, 0x9d, 0xf9, 0xa6, 0xed, 0x94, 0x57, 0x7c, 0x0d, 0x6a, + 0xdb, 0x2e, 0x4e, 0x1e, 0x31, 0x4e, 0xc7, 0xd2, 0x6f, 0xe2, 0xe7, 0xd0, 0xcb, 0xa8, 0x1b, 0xdb, + 0x4d, 0x4f, 0xed, 0x00, 0x75, 0x2e, 0x6b, 0x28, 0xcd, 0x15, 0xfc, 0x8d, 0x9d, 0xf4, 0xd4, 0xea, + 0x64, 0xe6, 0xf1, 0x21, 0x6a, 0xe3, 0x3b, 0xb0, 0x9a, 0x48, 0xe4, 0x18, 0xfb, 0x85, 0x4c, 0x22, + 0x3b, 0x95, 0x93, 0x38, 0x4a, 0xc8, 0x82, 0xe3, 0x2c, 0x0a, 0xc6, 0x7d, 0x27, 0x93, 0xe8, 0x50, + 0x63, 0x86, 0x6f, 0x42, 0x75, 0x3b, 0x49, 0x9c, 0x33, 0x62, 0x2d, 0x7c, 0x18, 0x54, 0x48, 0x36, + 0xf9, 0x65, 0xe8, 0xc2, 0xe2, 0x9e, 0x13, 0x8b, 0xeb, 0xb0, 0x30, 0x89, 0x09, 0xd3, 0xda, 0xba, + 0x50, 0x52, 0x68, 0x4e, 0xbc, 0xb9, 0x17, 0xdf, 0x0f, 0xd3, 0xe4, 0xcc, 0x5a, 0x98, 0xc4, 0x97, + 0x3f, 0x85, 0xba, 0x7e, 0xc5, 0x30, 0x10, 0x05, 0xbd, 0x42, 0x33, 0x8c, 0x8f, 0xf8, 0x81, 0x67, + 0x4e, 0x90, 0x19, 0xd7, 0x95, 0x5f, 0x3e, 0x5f, 0xf8, 0xac, 0x32, 0xfc, 0x9f, 0x4b, 0xd0, 0xb8, + 0x27, 0x03, 0x49, 0xff, 0x3e, 0x84, 0x76, 0x59, 0x2a, 0xcc, 0xbc, 0x4d, 0x49, 0xca, 0x10, 0xda, + 0xec, 0x4b, 0x50, 0x2b, 0xa9, 0xc5, 0x6e, 0x0a, 0x86, 0x46, 0x6e, 0x97, 0x9d, 0x34, 0x92, 0xb7, + 0x8e, 0x65, 0x5e, 0x11, 0xf3, 0x48, 0x63, 0x96, 0x18, 0xa3, 0x5f, 0xc5, 0x55, 0x80, 0x24, 0x7a, + 0x6e, 0xfb, 0x6c, 0xd0, 0xd9, 0x36, 0x36, 0x92, 0xe8, 0xf9, 0x2e, 0x9a, 0xf4, 0xbf, 0x11, 0x31, + 0xfb, 0x39, 0x0c, 0x4a, 0x62, 0x86, 0xa1, 0x82, 0xed, 0x87, 0x1c, 0x12, 0x69, 0x89, 0x2b, 0xfa, + 0xa4, 0x48, 0x62, 0x37, 0xa4, 0x68, 0xc8, 0x28, 0x8f, 0xe6, 0x2b, 0x94, 0xc7, 0x5c, 0x5d, 0x04, + 0xf3, 0x75, 0xd1, 0x5d, 0x80, 0x03, 0x39, 0x9e, 0xc8, 0x30, 0xdd, 0x73, 0xe2, 0x41, 0x8b, 0x16, + 0x7e, 0x58, 0x2c, 0xbc, 0x59, 0xad, 0xcd, 0x82, 0x88, 0xb9, 0xa0, 0xd4, 0x0a, 0xfd, 0x3c, 0xd7, + 0x09, 0xed, 0x34, 0xc9, 0x42, 0xd7, 0x49, 0x39, 0xbe, 0x6d, 0x58, 0x2d, 0xd7, 0x09, 0x0f, 0x35, + 0xa8, 0xa4, 0x30, 0x3a, 0x65, 0x85, 0x71, 0x03, 0x7a, 0x71, 0xe2, 0x4f, 0x9c, 0xe4, 0x0c, 0xad, + 0x05, 0x2d, 0x06, 0x8b, 0x5e, 0x47, 0x83, 0xbf, 0x91, 0x67, 0xbb, 0xde, 0xe9, 0xe5, 0x2f, 0xa0, + 0x37, 0x33, 0x80, 0x1f, 0xc5, 0x77, 0xff, 0xa4, 0x0a, 0xcd, 0xfd, 0x44, 0x6a, 0x25, 0x7f, 0x0d, + 0x5a, 0xca, 0x3d, 0x96, 0x13, 0x87, 0x75, 0x03, 0xf7, 0x00, 0x0c, 0x22, 0xbd, 0x30, 0xa5, 0xc6, + 0x16, 0x5e, 0xa3, 0xc6, 0xfa, 0xb0, 0xc8, 0xfe, 0x22, 0x0a, 0x13, 0x3e, 0x16, 0xba, 0x7b, 0xa9, + 0xac, 0xbb, 0xd7, 0xa1, 0x7d, 0xec, 0x28, 0xdb, 0xc9, 0xd2, 0xc8, 0x76, 0xa3, 0x80, 0x98, 0xae, + 0x61, 0xc1, 0xb1, 0xa3, 0xb6, 0xb3, 0x34, 0xda, 0x89, 0x02, 0xf1, 0x26, 0x80, 0x1b, 0x05, 0x5a, + 0x0d, 0x69, 0x67, 0xb9, 0xe9, 0x46, 0x01, 0xeb, 0x1e, 0xe4, 0x4a, 0xa9, 0x52, 0x7f, 0xe2, 0xe8, + 0x25, 0xd5, 0x11, 0x77, 0x9d, 0x54, 0xe1, 0x72, 0x8e, 0xb2, 0xa2, 0xe7, 0x1c, 0x6a, 0xdf, 0x81, + 0xae, 0x1b, 0x4d, 0x62, 0x3b, 0xc6, 0x99, 0x25, 0xd7, 0xad, 0x71, 0x2e, 0x1a, 0x6a, 0x23, 0xc5, + 0xfe, 0x89, 0x64, 0x67, 0x72, 0x0b, 0x7a, 0x6e, 0x90, 0xa9, 0x54, 0x26, 0x68, 0xc3, 0xe5, 0xfc, + 0x00, 0xaa, 0xa3, 0x49, 0xb4, 0x03, 0x3a, 0x84, 0x8e, 0xaf, 0xec, 0x28, 0xf0, 0x6c, 0x56, 0x50, + 0x9a, 0xcf, 0x5a, 0xbe, 0x7a, 0x1c, 0x78, 0x5a, 0x45, 0x32, 0x4d, 0x28, 0x9f, 0x1b, 0x9a, 0x96, + 0xa1, 0x79, 0x24, 0x9f, 0x6b, 0x9a, 0x97, 0x29, 0xb4, 0xf6, 0xcb, 0x14, 0x1a, 0xce, 0x07, 0x4e, + 0x68, 0xea, 0x24, 0x63, 0xd2, 0xda, 0x01, 0xc7, 0x41, 0xcc, 0x5f, 0xcb, 0xc7, 0x8e, 0x3a, 0x24, + 0xcc, 0x81, 0x46, 0x60, 0xd4, 0xa3, 0x69, 0x71, 0xf2, 0xc2, 0x6c, 0x72, 0x24, 0x13, 0x5a, 0x09, + 0xe6, 0x38, 0xc1, 0x48, 0x2b, 0x7a, 0xfe, 0x88, 0x50, 0xb8, 0x22, 0x37, 0x61, 0x59, 0x37, 0x71, + 0xdc, 0xd4, 0x7f, 0x26, 0x89, 0xbc, 0x47, 0xe4, 0x3d, 0x46, 0x6c, 0x13, 0x1c, 0x69, 0xdf, 0xcf, + 0x69, 0xb5, 0x66, 0x41, 0xda, 0x3e, 0xef, 0x09, 0xe4, 0x5d, 0xef, 0x7a, 0x3b, 0x51, 0x30, 0xfc, + 0x8f, 0x0b, 0x50, 0xdf, 0x8f, 0x54, 0x7a, 0x6f, 0x12, 0x18, 0x71, 0xae, 0xfc, 0x58, 0x71, 0x5e, + 0x98, 0x2f, 0xce, 0x73, 0x04, 0x6a, 0x71, 0x8e, 0x40, 0xa1, 0x91, 0x2c, 0xd3, 0x91, 0x20, 0x70, + 0xf8, 0xd0, 0x2d, 0x08, 0x49, 0x18, 0xae, 0xa0, 0xcb, 0x6a, 0x7b, 0xac, 0x7f, 0x99, 0x69, 0x1b, + 0xbe, 0xd2, 0xba, 0x97, 0x91, 0x3e, 0xc9, 0x95, 0xf6, 0x67, 0x1b, 0xbe, 0xd2, 0x72, 0xf6, 0x0b, + 0xb8, 0x94, 0xb7, 0xb4, 0x9f, 0xfb, 0xe9, 0x71, 0x94, 0xa5, 0xf6, 0x88, 0x62, 0x75, 0xa5, 0xa3, + 0xbd, 0x35, 0xd3, 0xd3, 0xb7, 0x8c, 0xe6, 0x48, 0x9e, 0xdc, 0xeb, 0x51, 0x16, 0x04, 0x76, 0x2a, + 0x4f, 0x53, 0xcd, 0xb6, 0x03, 0x9e, 0x1b, 0x3d, 0x6f, 0x0f, 0xb2, 0x20, 0x38, 0x94, 0xa7, 0x29, + 0x9a, 0xc6, 0xc6, 0x48, 0xbf, 0x0c, 0xff, 0xe9, 0x12, 0xc0, 0xc3, 0xc8, 0x3d, 0xe1, 0x95, 0xc7, + 0x18, 0xd2, 0x68, 0x6f, 0x6d, 0x5d, 0xea, 0x29, 0xeb, 0x6c, 0xb1, 0x05, 0x6b, 0xe6, 0xff, 0x51, + 0xe6, 0x30, 0x9e, 0x65, 0xf5, 0xab, 0x95, 0x87, 0xd0, 0x58, 0xde, 0x93, 0x21, 0xdd, 0x2b, 0x3e, + 0x2b, 0xe6, 0x16, 0xdb, 0xa4, 0x67, 0x31, 0xcd, 0xed, 0xbc, 0x70, 0xa2, 0x53, 0x34, 0x3f, 0x3c, + 0x8b, 0xc5, 0x1d, 0xb8, 0x90, 0xc8, 0x51, 0x22, 0xd5, 0xb1, 0x9d, 0xaa, 0xf2, 0xc7, 0x38, 0x94, + 0x5c, 0xd6, 0xc8, 0x43, 0x95, 0x7f, 0xeb, 0x0e, 0x5c, 0xe0, 0x99, 0x9a, 0x1d, 0x1e, 0xdb, 0xaa, + 0x65, 0x46, 0x96, 0x47, 0xf7, 0x26, 0xd0, 0xc6, 0x30, 0xdb, 0x1f, 0x13, 0x5b, 0x04, 0x34, 0x19, + 0x47, 0x81, 0x44, 0xef, 0x75, 0xe7, 0xd8, 0x09, 0xc7, 0xa8, 0xb3, 0xf4, 0xe4, 0x17, 0x00, 0x31, + 0x84, 0xa5, 0xbd, 0xc8, 0x93, 0x34, 0xd5, 0xdd, 0xad, 0xee, 0x26, 0x6d, 0x31, 0xe3, 0x4c, 0xd2, + 0x5e, 0x24, 0xe1, 0xc4, 0x7b, 0x40, 0xdd, 0x31, 0xfb, 0x9d, 0xd7, 0x0b, 0x0d, 0x44, 0x12, 0x0f, + 0xde, 0x81, 0x0b, 0xc5, 0x48, 0x6c, 0x27, 0xb5, 0xd3, 0x63, 0x49, 0xaa, 0x9f, 0x55, 0xc3, 0x72, + 0x3e, 0xa8, 0xed, 0xf4, 0xf0, 0x58, 0xa2, 0x19, 0xd8, 0x80, 0x7a, 0x74, 0xf4, 0xbd, 0x8d, 0x82, + 0xd0, 0x9a, 0x2f, 0x08, 0xb5, 0xe8, 0xe8, 0x7b, 0x4b, 0x8e, 0xc4, 0xcf, 0xca, 0x66, 0x73, 0x66, + 0x6a, 0xda, 0x34, 0x35, 0xab, 0x39, 0xbe, 0x34, 0x3b, 0xc3, 0xcf, 0xa0, 0x86, 0xbf, 0xf3, 0x38, + 0x16, 0x9b, 0x50, 0x67, 0x71, 0x54, 0xda, 0xcd, 0x59, 0x2d, 0xac, 0x5d, 0xc1, 0x3b, 0x96, 0x21, + 0x1a, 0x5a, 0xd0, 0xcb, 0x4d, 0xc7, 0x93, 0xd0, 0x7f, 0x9a, 0x49, 0xf1, 0x25, 0x2c, 0xc7, 0x89, + 0xd4, 0x6c, 0x6f, 0x67, 0x27, 0xe8, 0xbc, 0x69, 0x09, 0x5e, 0xd5, 0x5c, 0x9a, 0xb7, 0x38, 0x41, + 0x0e, 0xed, 0xc6, 0x53, 0xef, 0xc3, 0xef, 0xe0, 0x62, 0x4e, 0x71, 0x20, 0xdd, 0x28, 0xf4, 0x9c, + 0xe4, 0x8c, 0xac, 0xfc, 0x4c, 0xdf, 0xea, 0xc7, 0xf4, 0x7d, 0x40, 0x7d, 0xff, 0xf7, 0x0a, 0xb4, + 0x1e, 0x64, 0x2f, 0x5e, 0x9c, 0xb1, 0x2c, 0x89, 0x36, 0x54, 0x1e, 0x51, 0x07, 0x0b, 0x56, 0xe5, + 0x11, 0x3a, 0xa2, 0xfb, 0x27, 0x28, 0xd7, 0xc4, 0xe7, 0x4d, 0x4b, 0xbf, 0x61, 0x80, 0xbc, 0x7f, + 0x72, 0xf8, 0x0a, 0x8e, 0x66, 0x34, 0x06, 0x48, 0x77, 0x33, 0x3f, 0x40, 0x37, 0x49, 0x33, 0x6f, + 0xfe, 0x8e, 0x21, 0xe7, 0xee, 0x88, 0x87, 0xf2, 0x20, 0x89, 0x26, 0x3c, 0x59, 0x5a, 0x65, 0xcc, + 0xc1, 0x88, 0xaf, 0x60, 0x45, 0x6f, 0xe0, 0x69, 0xad, 0x60, 0xab, 0x58, 0xba, 0xc4, 0xba, 0x3f, + 0x6a, 0xd3, 0x6f, 0xf8, 0x0f, 0x6b, 0xd0, 0xc0, 0xd0, 0xf2, 0x37, 0x91, 0x1f, 0x8a, 0x3b, 0xd0, + 0xfc, 0x3e, 0xf2, 0x43, 0xde, 0x6d, 0xe0, 0x24, 0xc7, 0x0a, 0xf7, 0xf5, 0x28, 0xf2, 0xe4, 0x26, + 0xd2, 0xd0, 0x3e, 0x43, 0xe3, 0x7b, 0xfd, 0xa4, 0xcd, 0x53, 0xe2, 0x8f, 0x8f, 0x53, 0x1b, 0x81, + 0x5a, 0xb7, 0xb6, 0x7c, 0x65, 0x21, 0x8c, 0x7a, 0xbd, 0x0a, 0x40, 0x31, 0x6d, 0x14, 0xda, 0xf1, + 0x89, 0x8e, 0xeb, 0x1a, 0x08, 0x79, 0x1c, 0xee, 0x9f, 0xa0, 0xec, 0xf9, 0xca, 0xd6, 0xfb, 0x5a, + 0xda, 0x07, 0x2f, 0xc5, 0xf5, 0xef, 0x42, 0x17, 0xfd, 0x23, 0x75, 0xe2, 0xc7, 0x76, 0x9c, 0x44, + 0x47, 0x66, 0x52, 0xd0, 0x6b, 0x3a, 0x38, 0xf1, 0xe3, 0x7d, 0x84, 0x91, 0x5b, 0xa2, 0x77, 0xcb, + 0x50, 0x6d, 0xb3, 0xfd, 0x07, 0x0d, 0xc2, 0xf9, 0xa5, 0x2d, 0xb1, 0x80, 0xa3, 0x84, 0x3a, 0xb9, + 0x1b, 0xf5, 0x44, 0x06, 0x14, 0x0e, 0x5c, 0x82, 0x06, 0x0a, 0x03, 0xa1, 0x1a, 0x8c, 0x72, 0x23, + 0x46, 0xbd, 0x0f, 0x10, 0xc8, 0x51, 0x6a, 0x23, 0x97, 0xf1, 0x06, 0xc0, 0xcc, 0xd6, 0x13, 0x62, + 0x77, 0x10, 0x29, 0x3e, 0x80, 0x16, 0xcf, 0x02, 0xd3, 0xc2, 0x39, 0x5a, 0x20, 0x34, 0x13, 0xdf, + 0x84, 0x56, 0x18, 0x85, 0xb6, 0x7c, 0x4a, 0xd4, 0x5a, 0x6e, 0xa7, 0x3a, 0x0e, 0xa3, 0xf0, 0xfe, + 0x53, 0x24, 0x16, 0xb7, 0xf5, 0x18, 0x78, 0x0f, 0xa6, 0xfd, 0x92, 0x3d, 0x18, 0x1a, 0x09, 0xef, + 0x46, 0x7c, 0x64, 0x46, 0xc2, 0x2d, 0x3a, 0x2f, 0x69, 0xc1, 0xe3, 0xe1, 0x26, 0xeb, 0xd0, 0xa6, + 0x75, 0x9f, 0x38, 0xb1, 0x9d, 0x3a, 0x63, 0x6d, 0xd5, 0x01, 0x61, 0x7b, 0x4e, 0x7c, 0xe8, 0x8c, + 0x85, 0x05, 0x97, 0x66, 0xf8, 0xed, 0x08, 0x59, 0x97, 0x67, 0xad, 0x67, 0xf6, 0x70, 0xe6, 0x73, + 0xdd, 0xda, 0x14, 0xd7, 0x11, 0xcb, 0xd3, 0xec, 0xfe, 0x02, 0x2e, 0xc9, 0x09, 0x65, 0x3f, 0x26, + 0x71, 0x22, 0x95, 0x9a, 0x72, 0xcd, 0xfa, 0x6c, 0xe3, 0x90, 0x60, 0x27, 0xc7, 0xe7, 0xfe, 0xd9, + 0xbb, 0xd0, 0x75, 0x54, 0x34, 0xb2, 0xcd, 0x94, 0x07, 0x94, 0xcb, 0xa8, 0x5a, 0x6d, 0x84, 0x5a, + 0x3c, 0xd1, 0x01, 0x1a, 0x74, 0xa2, 0xd2, 0x43, 0x95, 0xa3, 0x94, 0xf2, 0x18, 0x0d, 0xab, 0x83, + 0x60, 0x1e, 0x88, 0x1c, 0xa5, 0xc3, 0x7f, 0xb9, 0x00, 0x8d, 0x87, 0x51, 0x14, 0xff, 0x44, 0x19, + 0x28, 0xf3, 0xd6, 0xc2, 0xcb, 0x79, 0x6b, 0x71, 0x9a, 0xb7, 0x66, 0x78, 0x60, 0xe9, 0x87, 0xf3, + 0x40, 0xf5, 0x47, 0xf3, 0x40, 0xed, 0x27, 0xf0, 0x40, 0x7d, 0x96, 0x07, 0x86, 0x77, 0xa0, 0x7a, + 0x20, 0xd3, 0xc7, 0x31, 0x5a, 0x33, 0xe3, 0x17, 0x1b, 0x43, 0x30, 0x65, 0xcd, 0xb4, 0x4f, 0xac, + 0x86, 0x7f, 0xdd, 0x82, 0xe6, 0x3d, 0xe9, 0x65, 0x3c, 0xb3, 0xe5, 0x79, 0xaa, 0xbc, 0x7c, 0x9e, + 0x16, 0xa6, 0xe7, 0x09, 0x4d, 0xa7, 0x91, 0xc1, 0x39, 0x1b, 0xa8, 0x0d, 0x23, 0x82, 0x28, 0xac, + 0x85, 0x04, 0xea, 0x5d, 0xc8, 0xa9, 0xf9, 0xcc, 0x05, 0xf0, 0xd5, 0xdc, 0x5c, 0xfd, 0x69, 0xdc, + 0x3c, 0xad, 0xc7, 0xce, 0xed, 0x4f, 0xbe, 0x76, 0x7a, 0x67, 0x75, 0x58, 0xe3, 0x9c, 0x0e, 0x7b, + 0x08, 0x2b, 0x51, 0x68, 0x7b, 0x59, 0x1c, 0xf8, 0x18, 0x17, 0x92, 0x5f, 0x1d, 0x85, 0xe4, 0x4e, + 0x50, 0x46, 0x34, 0xe7, 0xd1, 0xc7, 0xe1, 0x3d, 0x43, 0xc4, 0x7b, 0x25, 0xd6, 0x72, 0x34, 0x0b, + 0x42, 0x11, 0xf2, 0x70, 0x69, 0xc8, 0x13, 0x20, 0x1f, 0x96, 0x53, 0xbb, 0x6d, 0x82, 0xee, 0x44, + 0x01, 0xd9, 0xb6, 0xcf, 0xa0, 0x57, 0x50, 0x31, 0x33, 0xb5, 0x5e, 0xc2, 0x4c, 0x1d, 0xd3, 0x90, + 0xf9, 0xe9, 0x6f, 0x42, 0x6f, 0x7d, 0x08, 0x2b, 0x66, 0x0b, 0x48, 0xbb, 0x33, 0xb4, 0x82, 0x5d, + 0xe2, 0xa0, 0xbe, 0xde, 0xf5, 0x21, 0x4f, 0x86, 0x96, 0xe8, 0x97, 0xb0, 0x5a, 0x22, 0x47, 0xf6, + 0x2d, 0xeb, 0xaf, 0x32, 0xaf, 0x2c, 0xe7, 0x6d, 0xf1, 0xf5, 0x21, 0xef, 0xe1, 0xb7, 0x3c, 0x19, + 0x98, 0x0f, 0xe9, 0xe8, 0xa4, 0xe9, 0xc9, 0x40, 0xa7, 0x1e, 0xf7, 0xe0, 0x5d, 0x8c, 0xe4, 0x10, + 0xef, 0x3a, 0x71, 0x9a, 0x25, 0xd2, 0x8e, 0x03, 0xc7, 0x95, 0xc7, 0x51, 0xe0, 0xc9, 0xa4, 0x18, + 0xdc, 0x32, 0x0d, 0xee, 0x5a, 0x14, 0x60, 0x38, 0xb3, 0xc3, 0x94, 0xfb, 0x05, 0xa1, 0x19, 0xeb, + 0x36, 0xbc, 0x75, 0xae, 0x3b, 0x34, 0x75, 0x45, 0x47, 0x82, 0x3a, 0xba, 0x34, 0xdd, 0x11, 0x92, + 0x98, 0x2e, 0x3e, 0x82, 0x0b, 0xbc, 0x76, 0xcc, 0xdc, 0x27, 0x52, 0xc6, 0x76, 0xe0, 0xa8, 0x74, + 0xb0, 0xc2, 0x6e, 0x05, 0x21, 0x89, 0x81, 0xbf, 0x91, 0x32, 0x7e, 0xe8, 0xf0, 0x57, 0xb9, 0x89, + 0x8e, 0x3c, 0xa8, 0xcd, 0xd4, 0xdc, 0xae, 0xf2, 0x57, 0x89, 0x8a, 0xc3, 0x0f, 0x6c, 0x5c, 0x9a, + 0xe4, 0x5f, 0xc1, 0x95, 0xa9, 0x2e, 0x26, 0x4e, 0x72, 0x52, 0xb8, 0xe2, 0x83, 0x0b, 0x34, 0x6f, + 0x17, 0x4b, 0xed, 0xf7, 0x88, 0x40, 0xcf, 0xe2, 0xc7, 0xb0, 0x86, 0x81, 0x69, 0xe4, 0x9d, 0x64, + 0x33, 0x41, 0xdb, 0x1a, 0x0d, 0x1a, 0xc3, 0xd6, 0xc7, 0xde, 0x49, 0x36, 0x15, 0xb8, 0xfd, 0x1c, + 0x06, 0x53, 0xb4, 0x76, 0x42, 0x9b, 0xf3, 0x76, 0x1c, 0xa9, 0xc1, 0x45, 0xde, 0x0f, 0x2a, 0xef, + 0x28, 0xf2, 0xd6, 0xfd, 0x7e, 0xa4, 0xc4, 0x03, 0x58, 0x8f, 0x8f, 0xcf, 0x94, 0x4f, 0xc9, 0x44, + 0x72, 0xe8, 0xcf, 0x77, 0x30, 0xa0, 0x0e, 0xae, 0x1a, 0x3a, 0xf6, 0xfb, 0x67, 0xfa, 0xf9, 0x0c, + 0x2e, 0x19, 0xc6, 0x3a, 0x96, 0xee, 0xc9, 0xf4, 0x8c, 0x5d, 0xa2, 0x19, 0xbb, 0xa0, 0x39, 0x0a, + 0xf1, 0xa5, 0xd9, 0xda, 0x80, 0x3e, 0xd9, 0x3b, 0x7b, 0x14, 0x65, 0xa1, 0xfe, 0xd3, 0xcb, 0xf4, + 0xa7, 0x5d, 0x82, 0x3f, 0x40, 0x30, 0xfd, 0xe4, 0x06, 0xf4, 0xc9, 0x5a, 0xb2, 0xd4, 0x33, 0xe5, + 0x15, 0xa6, 0x44, 0xb8, 0x16, 0x74, 0xa4, 0xfc, 0x14, 0x2e, 0x6a, 0xa2, 0x91, 0x1f, 0x3a, 0x41, + 0xf9, 0x67, 0xae, 0xb2, 0x9b, 0xcf, 0xe8, 0x07, 0x88, 0x2d, 0x7e, 0xe2, 0xb7, 0x20, 0x46, 0x51, + 0x22, 0xfd, 0x71, 0x48, 0x61, 0x2d, 0xfd, 0x89, 0x1a, 0xbc, 0x49, 0xb2, 0xf1, 0x66, 0xe1, 0xe7, + 0x3f, 0xbe, 0xf7, 0xcd, 0x93, 0x07, 0x4c, 0xf7, 0x8d, 0x3c, 0xa3, 0xff, 0xd1, 0x92, 0xd9, 0x1f, + 0x4d, 0x83, 0xd5, 0xf0, 0x9f, 0xd5, 0xa0, 0x4b, 0xd6, 0xf8, 0xef, 0x8c, 0xc0, 0xdf, 0x19, 0x81, + 0xbf, 0x0d, 0x46, 0xe0, 0x26, 0x2c, 0xfb, 0x61, 0x9c, 0xa5, 0x28, 0x41, 0xca, 0xce, 0x38, 0x8a, + 0x5b, 0xe6, 0xed, 0x26, 0x42, 0x7c, 0x23, 0xcf, 0x14, 0x87, 0x70, 0xc3, 0x7f, 0x50, 0x81, 0xfa, + 0x7e, 0x12, 0x79, 0x99, 0x9b, 0xfe, 0x44, 0xa9, 0x98, 0xe6, 0xb6, 0xc5, 0xd7, 0x71, 0xdb, 0xd2, + 0x39, 0x8f, 0xee, 0x5f, 0x55, 0xa0, 0xa9, 0x87, 0xf0, 0x70, 0xeb, 0x27, 0x0e, 0xa2, 0xc8, 0x6d, + 0x57, 0xe6, 0xe6, 0xb6, 0x5f, 0x3b, 0x0a, 0x64, 0xc2, 0x67, 0x5c, 0x0c, 0x14, 0xc5, 0x45, 0xa2, + 0xbb, 0x69, 0xb5, 0x19, 0xfa, 0x38, 0xa6, 0x7c, 0xf6, 0x73, 0x68, 0x52, 0x94, 0x4f, 0x5a, 0x64, + 0x0d, 0x6a, 0xac, 0xd5, 0xf4, 0x40, 0xf5, 0xdb, 0xab, 0x65, 0x7a, 0xe1, 0x27, 0xc9, 0xf4, 0xf0, + 0xdf, 0x2f, 0x42, 0x87, 0xb6, 0x5c, 0x1e, 0x64, 0x21, 0x4b, 0x4d, 0xbe, 0x49, 0x5d, 0x99, 0xde, + 0xa4, 0x5e, 0x4a, 0x64, 0x6a, 0x12, 0xe9, 0x6d, 0xfe, 0xcc, 0x4e, 0x14, 0xdc, 0x93, 0x23, 0x8b, + 0x30, 0x38, 0x55, 0x4e, 0x32, 0x56, 0xf3, 0xca, 0x00, 0x10, 0x8e, 0x7f, 0x15, 0x3b, 0x89, 0x33, + 0x51, 0xa6, 0x0c, 0x80, 0xdf, 0x84, 0x80, 0x25, 0x92, 0x4d, 0x9e, 0x16, 0x7a, 0xd6, 0xbb, 0x87, + 0xca, 0x0f, 0xc7, 0xb9, 0xa2, 0x69, 0x50, 0xf9, 0xc7, 0x38, 0x90, 0xe2, 0x1e, 0x08, 0x4e, 0x8b, + 0x24, 0xd2, 0x41, 0xe7, 0x83, 0xfa, 0x21, 0x6d, 0xd3, 0xda, 0x5a, 0xe3, 0xcf, 0xd2, 0x5c, 0x5a, + 0x84, 0xde, 0x47, 0xac, 0xd5, 0xf7, 0x67, 0x20, 0x73, 0x26, 0x93, 0x3d, 0x90, 0x3c, 0x52, 0xfe, + 0xc1, 0x93, 0x49, 0x6e, 0x09, 0x71, 0xcb, 0x97, 0xb0, 0x32, 0xca, 0x82, 0x20, 0x95, 0xa7, 0xa9, + 0xad, 0xa2, 0x2c, 0x71, 0xa5, 0xfd, 0x8a, 0x8c, 0xcc, 0xb2, 0xa1, 0x3d, 0x20, 0x52, 0x4b, 0x8e, + 0xc4, 0x17, 0x20, 0xf2, 0x0e, 0xcc, 0x3f, 0x9a, 0x7c, 0xe9, 0xb9, 0xf6, 0x7d, 0x43, 0xaa, 0xff, + 0x76, 0x34, 0xdc, 0x86, 0x0b, 0x26, 0x47, 0x8a, 0xaa, 0x6d, 0x0b, 0xe5, 0x96, 0xf6, 0x8e, 0xcc, + 0x1c, 0x57, 0x4a, 0x73, 0xbc, 0x0a, 0xd5, 0x72, 0x79, 0x1a, 0xbf, 0x0c, 0xaf, 0x43, 0x6b, 0xe4, + 0x07, 0x52, 0xe7, 0x1a, 0x70, 0xd1, 0x74, 0xd6, 0xa1, 0x42, 0x49, 0x75, 0xfd, 0x36, 0xfc, 0x7d, + 0x05, 0x2e, 0xc6, 0x4e, 0xf2, 0x34, 0xd3, 0xbb, 0xda, 0x9c, 0xdf, 0x57, 0xc7, 0x4e, 0xe2, 0xa1, + 0xe0, 0x52, 0x17, 0xdc, 0x3b, 0x57, 0x37, 0x35, 0x11, 0xc2, 0x63, 0xb9, 0x01, 0xbd, 0x52, 0x8b, + 0xd4, 0x49, 0xcc, 0xce, 0x6a, 0x27, 0x89, 0x9e, 0x53, 0xf6, 0xfd, 0x00, 0x81, 0x62, 0x08, 0x9d, + 0x82, 0x4e, 0x92, 0x65, 0xa4, 0x22, 0x21, 0x43, 0x75, 0x3f, 0xf4, 0x50, 0x72, 0xc3, 0x6c, 0xc2, + 0xee, 0x02, 0x17, 0xb1, 0xd5, 0xc3, 0x6c, 0x42, 0x7e, 0xc2, 0x2a, 0x54, 0xb9, 0x72, 0xb0, 0x4a, + 0x70, 0x7e, 0x19, 0xfe, 0xa1, 0x0a, 0x2b, 0xbb, 0xae, 0x3c, 0x92, 0xc9, 0xf8, 0x9e, 0x93, 0x3a, + 0x0f, 0xfc, 0x40, 0x1e, 0x3a, 0xea, 0x04, 0x19, 0x8e, 0xc6, 0x1c, 0x3b, 0xe9, 0xb1, 0x9e, 0xa5, + 0x06, 0x02, 0xf6, 0x9d, 0xf4, 0x18, 0xcd, 0x16, 0x21, 0x47, 0x51, 0x32, 0xd1, 0xfb, 0xc0, 0x4d, + 0x8b, 0xfe, 0xf1, 0x01, 0x41, 0xf2, 0xd6, 0xca, 0x7f, 0x21, 0x75, 0xc9, 0x1d, 0xb5, 0xa6, 0xba, + 0x8c, 0xb7, 0xa1, 0x9d, 0x48, 0x37, 0x4a, 0x3c, 0x1d, 0xfb, 0xf3, 0x38, 0x5b, 0x0c, 0xe3, 0x80, + 0xff, 0x26, 0x14, 0xb9, 0x43, 0xda, 0xea, 0xb2, 0x7d, 0x53, 0x97, 0xd3, 0xcb, 0x11, 0xc8, 0x79, + 0xbb, 0x9e, 0xf8, 0x7b, 0xd0, 0x2f, 0x68, 0x29, 0x91, 0x65, 0x22, 0xe0, 0xad, 0xc2, 0x8d, 0x99, + 0xf3, 0x8b, 0x9b, 0xfb, 0xa6, 0xd5, 0x9f, 0x53, 0x23, 0x4e, 0xd6, 0x15, 0xdd, 0x33, 0x54, 0xbc, + 0x03, 0x1d, 0x15, 0x07, 0x7e, 0xaa, 0x19, 0x40, 0xe9, 0xc2, 0xbc, 0x36, 0x01, 0x39, 0xdf, 0xa4, + 0xe6, 0x2d, 0x61, 0xe3, 0x07, 0x2d, 0x61, 0xf3, 0xfc, 0x12, 0xbe, 0x0f, 0x7d, 0x37, 0x91, 0x9e, + 0x0c, 0x53, 0xdf, 0x09, 0x6c, 0xe5, 0x46, 0xb1, 0x31, 0xd3, 0xbd, 0x02, 0x7e, 0x80, 0x60, 0xf1, + 0x33, 0xb8, 0xe8, 0x46, 0x61, 0x2a, 0xc3, 0x34, 0x2f, 0xdd, 0xd4, 0xd9, 0x1a, 0x5d, 0x72, 0x72, + 0x41, 0xa3, 0x4d, 0x01, 0x27, 0xe7, 0x6b, 0xc4, 0x1d, 0x58, 0xe5, 0xe5, 0x99, 0x69, 0xc4, 0xb5, + 0x02, 0x82, 0x56, 0x6a, 0xba, 0x85, 0xce, 0x20, 0x25, 0x52, 0xf9, 0x5e, 0xe6, 0x04, 0x5a, 0x43, + 0x94, 0x32, 0x48, 0x96, 0xc6, 0xe8, 0xad, 0x54, 0xca, 0x51, 0x4d, 0xd1, 0x52, 0xa1, 0x0b, 0x6d, + 0x35, 0x35, 0x2d, 0x91, 0x4c, 0x51, 0x7f, 0xed, 0xa8, 0xe3, 0xcb, 0x77, 0x61, 0x75, 0xde, 0x82, + 0xbc, 0x2e, 0x79, 0xd9, 0x2c, 0x25, 0x2f, 0x75, 0x79, 0xea, 0xff, 0x58, 0x80, 0x0b, 0x66, 0xbd, + 0x29, 0xe4, 0xc8, 0x99, 0xfa, 0x1a, 0xd9, 0x73, 0x0c, 0x53, 0xf2, 0xed, 0x9e, 0xa6, 0x05, 0x0c, + 0xa2, 0xbd, 0x9d, 0x0d, 0xe8, 0x6b, 0x82, 0x82, 0xf9, 0xf9, 0x2b, 0x5d, 0x2f, 0xef, 0x8a, 0x44, + 0x80, 0x7e, 0x70, 0x24, 0x13, 0x9c, 0x23, 0x8f, 0xaa, 0xb5, 0xa9, 0x09, 0x31, 0x3b, 0xfd, 0xa0, + 0xc1, 0x19, 0x96, 0xa3, 0x4a, 0x9b, 0xa7, 0x99, 0x13, 0xf8, 0xe9, 0x99, 0x3d, 0xf2, 0x65, 0xe0, + 0x51, 0xa6, 0x9c, 0xeb, 0x08, 0xfb, 0x06, 0xf3, 0x00, 0x11, 0xbb, 0x9e, 0x2a, 0x8d, 0x44, 0x27, + 0x60, 0x73, 0x01, 0xd0, 0x23, 0x39, 0x20, 0xf0, 0xae, 0x37, 0x5f, 0x56, 0x6a, 0xf3, 0x65, 0xe5, + 0x3d, 0xe8, 0xcd, 0xae, 0x39, 0x27, 0x45, 0xbb, 0x6a, 0x7a, 0xbd, 0xe7, 0x31, 0x61, 0x63, 0x2e, + 0x13, 0xea, 0x49, 0xff, 0x5f, 0x0b, 0xb0, 0xaa, 0x27, 0x7d, 0x27, 0x0a, 0xb2, 0x09, 0x5a, 0x7b, + 0xaa, 0x4a, 0x5a, 0x87, 0xf6, 0x24, 0x62, 0x17, 0xaa, 0xa4, 0xfe, 0x60, 0x12, 0xe5, 0xba, 0x78, + 0x03, 0xfa, 0x3e, 0xb7, 0xcc, 0xe7, 0xc5, 0x54, 0x08, 0x6b, 0xb8, 0x9e, 0x15, 0xe4, 0x42, 0x15, + 0x3a, 0xb1, 0x3a, 0x8e, 0x52, 0x4d, 0x4a, 0x4a, 0x9c, 0xe7, 0x7c, 0xd9, 0xa0, 0x88, 0x9a, 0x3c, + 0xd9, 0x5b, 0x20, 0xdc, 0x2c, 0x49, 0x50, 0x3e, 0x4a, 0xe4, 0x9c, 0xbc, 0xeb, 0x6b, 0x4c, 0x41, + 0xfd, 0x0e, 0xd4, 0x27, 0x51, 0xe1, 0x91, 0x4c, 0x39, 0xa2, 0x56, 0x6d, 0x12, 0x11, 0x87, 0x5c, + 0x46, 0xaf, 0xe9, 0x69, 0xe6, 0x27, 0xd2, 0x33, 0x76, 0xd8, 0xbc, 0x6b, 0x23, 0x7d, 0xec, 0x7b, + 0x9e, 0x0c, 0x75, 0xe2, 0xa8, 0xe1, 0xab, 0xaf, 0xe9, 0x9d, 0x0a, 0x68, 0xe5, 0xc8, 0xc1, 0xd0, + 0x2c, 0xcc, 0x02, 0x92, 0x8a, 0x40, 0x97, 0x6b, 0xf6, 0x34, 0xe2, 0x51, 0x16, 0xa0, 0x44, 0x04, + 0x7a, 0x49, 0xc9, 0x96, 0x20, 0x0b, 0xda, 0xc7, 0x7e, 0x98, 0x92, 0xaa, 0x68, 0xd2, 0x92, 0x22, + 0x02, 0x99, 0xf0, 0x6b, 0x3f, 0x4c, 0x87, 0x7f, 0xb9, 0x00, 0x6b, 0x7a, 0xe2, 0x0f, 0xf4, 0x04, + 0x68, 0xfb, 0x4c, 0xd1, 0x85, 0x99, 0x2e, 0x9d, 0xd7, 0x5b, 0xb4, 0xc0, 0x80, 0x76, 0x69, 0xc0, + 0x05, 0x77, 0x2d, 0xe8, 0x32, 0x4e, 0xc3, 0x57, 0xb7, 0x40, 0x9c, 0xe3, 0x2b, 0xa5, 0xb7, 0x35, + 0xfb, 0x33, 0x8c, 0xa5, 0xc4, 0x27, 0xb0, 0x36, 0x91, 0xa9, 0x43, 0x82, 0x10, 0x44, 0xae, 0x43, + 0xad, 0x48, 0xe4, 0x79, 0xba, 0x57, 0x0d, 0xf6, 0xa1, 0x46, 0xa2, 0xd0, 0xe3, 0x37, 0x26, 0x4e, + 0xe8, 0x8f, 0xa4, 0x4a, 0xc9, 0xcf, 0xe0, 0x16, 0xec, 0xf8, 0xf4, 0x0d, 0x06, 0x3d, 0x09, 0xa2, + 0x26, 0x8f, 0x75, 0xc4, 0x8b, 0x58, 0x23, 0x9a, 0x7a, 0x22, 0x47, 0x7a, 0xed, 0x3a, 0xb8, 0x56, + 0xa1, 0x1f, 0x8e, 0xf9, 0xe0, 0x40, 0x9d, 0x7d, 0x4a, 0x03, 0xdc, 0x8b, 0x3c, 0x39, 0xfc, 0x8b, + 0xa5, 0x9c, 0x47, 0xf7, 0x35, 0xfc, 0x20, 0x75, 0x52, 0xaa, 0x95, 0xcf, 0x07, 0xcf, 0x36, 0x92, + 0xe7, 0xaa, 0x63, 0xa0, 0x5c, 0x52, 0xbf, 0x09, 0x2b, 0xd3, 0xa3, 0x65, 0xda, 0x05, 0x2e, 0x2b, + 0x28, 0x0f, 0x37, 0x2f, 0xc1, 0xcf, 0xe9, 0x99, 0x54, 0x57, 0x9f, 0x1b, 0x28, 0x93, 0x7d, 0x58, + 0x4c, 0x82, 0xd2, 0xc9, 0x79, 0xe9, 0x69, 0xab, 0x98, 0xf7, 0xaa, 0x0e, 0x34, 0x02, 0x45, 0xb3, + 0x20, 0x8f, 0x93, 0x2c, 0x94, 0x9e, 0x36, 0xe9, 0xbd, 0x1c, 0xbe, 0x4f, 0x60, 0x1c, 0x70, 0xae, + 0x99, 0x4a, 0x5d, 0xd7, 0xb8, 0x6b, 0x4f, 0x6b, 0xa6, 0xa2, 0x6b, 0xe4, 0xd1, 0x82, 0x5e, 0xf7, + 0xcd, 0x0a, 0xa2, 0x97, 0x53, 0xeb, 0xbe, 0x7f, 0x0e, 0x83, 0x9c, 0x96, 0xff, 0xae, 0xf8, 0x40, + 0x83, 0x8d, 0x8f, 0x69, 0x42, 0xbf, 0x99, 0x7f, 0xe4, 0x63, 0x58, 0x9b, 0x6d, 0xa8, 0xbf, 0xd4, + 0xa4, 0x66, 0x2b, 0x53, 0xcd, 0x8a, 0x3f, 0xc9, 0xd7, 0xd7, 0x75, 0xdc, 0x63, 0x69, 0x1f, 0xfb, + 0xba, 0x00, 0x7d, 0xd1, 0x5a, 0x36, 0xa8, 0x1d, 0xc4, 0x7c, 0xed, 0xa7, 0x6a, 0x0e, 0xfd, 0xc4, + 0x57, 0x4a, 0x5b, 0xc5, 0x69, 0xfa, 0x3d, 0x5f, 0xa9, 0xe1, 0x7f, 0x6b, 0x41, 0xdb, 0x78, 0x8a, + 0x54, 0xfb, 0x7c, 0xab, 0xec, 0xf4, 0xb7, 0xb6, 0xfa, 0xc6, 0x7b, 0x47, 0x92, 0xed, 0x34, 0x4d, + 0x4c, 0xae, 0x8f, 0x83, 0x81, 0x29, 0x7f, 0x67, 0x81, 0x1c, 0x84, 0xc2, 0xdf, 0xd9, 0x86, 0xe5, + 0x92, 0x07, 0x69, 0xa7, 0x51, 0xea, 0x04, 0x3a, 0x28, 0x28, 0xd5, 0x8d, 0x95, 0x48, 0xac, 0x1e, + 0xbe, 0xb0, 0x6f, 0x71, 0x88, 0xd4, 0x18, 0x6c, 0xb8, 0x51, 0x60, 0x8a, 0x6d, 0x67, 0x82, 0x0d, + 0xc4, 0x50, 0x45, 0x4c, 0x22, 0x31, 0xce, 0x55, 0x4f, 0x03, 0x2d, 0x41, 0x4d, 0x86, 0x1c, 0x3c, + 0x0d, 0xf2, 0x01, 0x92, 0x33, 0x5f, 0xa3, 0x38, 0x86, 0x06, 0x48, 0x5e, 0xfa, 0x87, 0xd0, 0x8a, + 0x12, 0x7f, 0xec, 0x53, 0x9a, 0x98, 0x1d, 0x9c, 0xd9, 0x8f, 0x00, 0x13, 0xec, 0xe0, 0xa7, 0x86, + 0x50, 0xd3, 0xe6, 0xff, 0x7c, 0x95, 0x8c, 0xc6, 0x98, 0x23, 0x00, 0x6e, 0x8a, 0xc3, 0x61, 0x89, + 0x6c, 0x16, 0x47, 0x00, 0xdc, 0xf4, 0xe0, 0x69, 0x40, 0x99, 0xf2, 0x1b, 0xd0, 0x73, 0xc9, 0x5c, + 0xb0, 0x40, 0x05, 0x32, 0xa4, 0x35, 0xad, 0x5a, 0x1d, 0x06, 0xe3, 0xf8, 0x1e, 0xca, 0x50, 0x97, + 0x5a, 0x3a, 0x41, 0x80, 0x11, 0x6b, 0xe4, 0x78, 0xba, 0x2e, 0xa6, 0x6d, 0x80, 0x0f, 0x23, 0xc7, + 0x13, 0x9f, 0xc3, 0x65, 0xc4, 0xd9, 0x5c, 0xd0, 0x1a, 0x66, 0x13, 0x99, 0xf8, 0xae, 0xed, 0x28, + 0xaa, 0x93, 0xd1, 0xe5, 0x31, 0x6b, 0x48, 0x71, 0x1f, 0x09, 0x1e, 0x31, 0x7e, 0x5b, 0x7d, 0x27, + 0x93, 0x48, 0x7c, 0x47, 0xd9, 0xf2, 0x79, 0xee, 0xbb, 0xd9, 0x96, 0x78, 0xbb, 0x58, 0xab, 0x97, + 0x50, 0x52, 0x1d, 0x1a, 0x22, 0x2c, 0xe3, 0xf4, 0x51, 0x7b, 0xf1, 0x0d, 0x08, 0x63, 0xe0, 0x88, + 0xf3, 0x53, 0x47, 0x9d, 0x70, 0x51, 0xee, 0xd4, 0x56, 0xdb, 0x1c, 0x1f, 0xd5, 0x32, 0x96, 0x11, + 0x81, 0x08, 0x50, 0xe2, 0xb7, 0xb0, 0x9a, 0x77, 0xa6, 0x7d, 0x19, 0xea, 0x8e, 0x37, 0x34, 0xae, + 0x9d, 0xef, 0x6e, 0xca, 0x05, 0xb2, 0xcc, 0x48, 0x18, 0xcc, 0x5d, 0x7e, 0x05, 0x3d, 0xd3, 0x25, + 0xcf, 0xba, 0x1a, 0xf4, 0xa9, 0xb7, 0xb7, 0xce, 0xf5, 0x36, 0x65, 0xdb, 0x73, 0xfb, 0xcc, 0x50, + 0xfc, 0xd1, 0xdc, 0x92, 0x1b, 0x2b, 0x43, 0xdb, 0x21, 0xad, 0xad, 0xf5, 0x73, 0x3d, 0xcd, 0x18, + 0x2b, 0xcb, 0x0c, 0xc1, 0xc0, 0xc5, 0x47, 0x70, 0xc1, 0x74, 0x16, 0x51, 0x88, 0x67, 0xfb, 0x11, + 0x45, 0x7f, 0x82, 0x5d, 0x2c, 0x8d, 0xe4, 0xf0, 0x6f, 0x37, 0xe2, 0x68, 0xf1, 0x8a, 0x69, 0xc2, + 0x56, 0x98, 0x22, 0xe2, 0xfc, 0xa7, 0x56, 0xc8, 0x76, 0x0d, 0x34, 0x09, 0xdb, 0x65, 0x8c, 0x80, + 0xcd, 0xf0, 0x37, 0xa0, 0x4f, 0x95, 0xf3, 0xb8, 0xac, 0x51, 0xe2, 0xf9, 0xa1, 0x13, 0x0c, 0x56, + 0x79, 0xcf, 0x15, 0xe1, 0x56, 0xf4, 0xfc, 0x31, 0x43, 0xc5, 0x21, 0xac, 0x99, 0x0f, 0xe5, 0x6a, + 0x46, 0xa1, 0x29, 0xa1, 0x0d, 0xef, 0x79, 0x13, 0x37, 0x65, 0x70, 0x2c, 0xb3, 0x84, 0xd3, 0x66, + 0xe8, 0x1e, 0x5c, 0x9b, 0x59, 0xda, 0x89, 0x73, 0x6a, 0x4f, 0xe4, 0x24, 0x4a, 0xce, 0xb4, 0x01, + 0x59, 0x23, 0x05, 0x76, 0x65, 0x6a, 0x11, 0xf7, 0x9c, 0xd3, 0x3d, 0xa2, 0x61, 0x73, 0xf2, 0x25, + 0x5c, 0x9d, 0xe9, 0x85, 0x0b, 0xd1, 0x65, 0xe8, 0x1c, 0x05, 0xd2, 0xa3, 0x2d, 0xf2, 0x86, 0x75, + 0x69, 0xaa, 0x8b, 0x03, 0xa4, 0xb8, 0xcf, 0x04, 0xe2, 0x0b, 0x20, 0x65, 0xaf, 0xe8, 0xa4, 0x9d, + 0xad, 0x5c, 0x27, 0xa4, 0x5d, 0xf1, 0xbc, 0xaa, 0x02, 0x79, 0x91, 0x8f, 0xe1, 0xa1, 0xa6, 0xb4, + 0xba, 0x05, 0x31, 0x69, 0xce, 0x4f, 0xa0, 0x6d, 0x36, 0x96, 0xa9, 0xed, 0x25, 0x6a, 0xbb, 0xcc, + 0x6d, 0xf5, 0x56, 0x32, 0x35, 0x6c, 0x8d, 0x8a, 0x17, 0xb1, 0x09, 0x70, 0xe2, 0x8c, 0x4e, 0x1c, + 0x6e, 0x73, 0xb9, 0x1c, 0xe0, 0x7f, 0x83, 0x70, 0x6a, 0xd1, 0x3c, 0x31, 0x8f, 0xe2, 0x17, 0x70, + 0xc9, 0x48, 0xe1, 0xf3, 0xe3, 0x28, 0xd0, 0x0e, 0xfb, 0xc8, 0x09, 0xa3, 0x2c, 0xd5, 0x1b, 0xe5, + 0x6b, 0x9a, 0xe0, 0x5b, 0xc4, 0xa3, 0x00, 0x3c, 0x20, 0xac, 0x76, 0x58, 0x8f, 0xa0, 0x49, 0xdb, + 0x3c, 0xd4, 0x5b, 0x7e, 0xe8, 0xa1, 0xf2, 0xea, 0x43, 0x0f, 0x1f, 0x42, 0x5b, 0x47, 0x33, 0x2f, + 0x3b, 0x45, 0xd1, 0x62, 0x3c, 0x27, 0x44, 0x6f, 0x41, 0x93, 0x42, 0x19, 0xfa, 0xc6, 0x35, 0x68, + 0xf1, 0x49, 0xbb, 0xa3, 0x20, 0x72, 0x4f, 0x4c, 0xf0, 0x41, 0xa0, 0xbb, 0x08, 0x19, 0x02, 0x34, + 0x9e, 0x84, 0x7e, 0x14, 0x6e, 0x07, 0xc1, 0xf0, 0x4f, 0x35, 0x68, 0xa2, 0xcf, 0x43, 0xfb, 0x52, + 0x18, 0x36, 0x12, 0x63, 0x52, 0x5d, 0xc5, 0xc4, 0x89, 0xf5, 0xb1, 0x8e, 0x16, 0x02, 0x91, 0x6a, + 0xcf, 0x89, 0x67, 0xca, 0x2e, 0x16, 0x66, 0xca, 0x2e, 0xde, 0xe6, 0x73, 0x9f, 0x5c, 0x35, 0x2b, + 0x4d, 0xb9, 0x3d, 0x75, 0x70, 0x97, 0x41, 0xe8, 0x8b, 0x11, 0x89, 0x13, 0x90, 0xff, 0x86, 0xd1, + 0x61, 0xa0, 0x74, 0x85, 0x06, 0xc9, 0xc5, 0xb6, 0x46, 0x1c, 0x48, 0xb6, 0x37, 0xa5, 0xcd, 0xc8, + 0xea, 0xec, 0x66, 0xe4, 0x4d, 0x00, 0x37, 0x0a, 0x3d, 0x72, 0x11, 0x67, 0x12, 0xd2, 0x5c, 0x1e, + 0x51, 0x60, 0x7f, 0xc0, 0x36, 0xf9, 0x7b, 0xd0, 0xcf, 0x29, 0xd0, 0x03, 0x74, 0xc3, 0x3c, 0xbe, + 0xd6, 0x54, 0x96, 0x1c, 0xed, 0x84, 0xe9, 0xec, 0x7e, 0x7a, 0xf3, 0xdc, 0x7e, 0xfa, 0x4b, 0x0a, + 0x69, 0xe0, 0x47, 0x9f, 0x9e, 0xbb, 0x04, 0x0d, 0xaa, 0xd8, 0xf3, 0xb2, 0x58, 0xdb, 0xa2, 0xba, + 0xaf, 0x28, 0xef, 0xf1, 0xb2, 0x3d, 0xfb, 0xf6, 0xff, 0xaf, 0x3d, 0xfb, 0xce, 0x0f, 0xdb, 0xb3, + 0xef, 0xfe, 0xb0, 0x3d, 0xfb, 0x99, 0x3d, 0xee, 0xde, 0xec, 0x1e, 0xf7, 0x4b, 0xd3, 0x8a, 0xfd, + 0x97, 0xa6, 0x15, 0x5f, 0x93, 0x13, 0x5c, 0x7e, 0x75, 0x4e, 0xf0, 0xf5, 0x49, 0x49, 0xf1, 0xba, + 0xa4, 0xe4, 0x0d, 0xe8, 0xa5, 0x89, 0xe3, 0x9e, 0x70, 0xa4, 0x75, 0x22, 0xcf, 0x94, 0x4e, 0x82, + 0x76, 0x08, 0x8c, 0x71, 0xd6, 0x37, 0xf2, 0x4c, 0x0d, 0x9f, 0x00, 0x50, 0x08, 0x4a, 0xbf, 0xf6, + 0x32, 0xde, 0xa8, 0xfc, 0xe8, 0x22, 0xab, 0xbf, 0xae, 0x00, 0x1c, 0x38, 0x93, 0x98, 0xf7, 0x90, + 0xc5, 0x9f, 0x41, 0x4b, 0xd1, 0x5b, 0xb9, 0xc8, 0xa4, 0x64, 0xa8, 0x0b, 0x52, 0xfd, 0xc8, 0x87, + 0xbb, 0x54, 0xfe, 0x4c, 0x6c, 0xcd, 0x3d, 0xe4, 0x05, 0xad, 0x55, 0x43, 0x40, 0x7b, 0x7b, 0xd7, + 0xa1, 0xab, 0x09, 0x62, 0x99, 0xb8, 0x32, 0xe4, 0xfa, 0xfe, 0x8a, 0xd5, 0x61, 0xe8, 0x3e, 0x03, + 0xc5, 0x47, 0x39, 0x99, 0x31, 0x89, 0xe7, 0x53, 0x66, 0xba, 0x89, 0xb6, 0x89, 0xc3, 0x2d, 0xf3, + 0x2b, 0x34, 0x90, 0x06, 0x2c, 0xe1, 0xf7, 0xfa, 0x6f, 0x88, 0x16, 0xd4, 0x75, 0xaf, 0xfd, 0x8a, + 0xe8, 0x40, 0x93, 0x4e, 0x13, 0x12, 0x6e, 0x61, 0xf8, 0x97, 0xab, 0xd0, 0xda, 0x0d, 0x55, 0x9a, + 0x64, 0xcc, 0xc2, 0xc5, 0x99, 0xb9, 0x2a, 0x9d, 0x99, 0xd3, 0x75, 0xe0, 0xfc, 0x1b, 0x54, 0x07, + 0xfe, 0x21, 0xd4, 0xf5, 0xf1, 0x4c, 0x9d, 0x58, 0x98, 0x7b, 0xb6, 0xd3, 0xd0, 0x88, 0x4d, 0x68, + 0x78, 0xfa, 0xdc, 0xa8, 0xae, 0xa4, 0x29, 0x1d, 0xe6, 0x34, 0x27, 0x4a, 0xad, 0x9c, 0x46, 0xbc, + 0x0d, 0x8b, 0xce, 0x78, 0xac, 0xa3, 0xfa, 0x5e, 0x41, 0x4a, 0x4e, 0x9a, 0x85, 0x38, 0x71, 0x1b, + 0x9a, 0xa4, 0x3e, 0xa9, 0xaa, 0xad, 0x36, 0xdb, 0xa7, 0x29, 0x99, 0x63, 0x8d, 0x4a, 0x39, 0x89, + 0xdb, 0xd0, 0x0c, 0xa2, 0x28, 0xe6, 0x06, 0xf5, 0xd9, 0x06, 0xa6, 0xbe, 0xc8, 0x6a, 0x04, 0xa6, + 0xd2, 0xe8, 0x06, 0xd4, 0xd0, 0xfd, 0x8f, 0x62, 0xed, 0x36, 0x97, 0xc6, 0x41, 0x75, 0x36, 0x56, + 0x55, 0x51, 0xb9, 0xcd, 0x16, 0x00, 0xf3, 0x3f, 0xf5, 0xdc, 0x9c, 0x9d, 0x8e, 0x3c, 0xb7, 0x8a, + 0x42, 0x6a, 0xd2, 0xac, 0x77, 0xa1, 0xcf, 0x79, 0xb4, 0x52, 0x4b, 0x30, 0xb5, 0xc0, 0xa6, 0xe5, + 0x74, 0x6a, 0xd6, 0xea, 0x26, 0xd3, 0xa9, 0xda, 0x0f, 0xa0, 0x1e, 0x73, 0x72, 0x88, 0x34, 0x0c, + 0x99, 0x6c, 0xd3, 0x54, 0x67, 0x8d, 0x2c, 0x43, 0x21, 0x7e, 0x0d, 0x5d, 0xae, 0x59, 0x1d, 0xe9, + 0x2c, 0x09, 0xed, 0xec, 0x4d, 0x9d, 0xec, 0x9b, 0x4a, 0xa2, 0x58, 0x9d, 0x74, 0x2a, 0xa7, 0xf2, + 0x4b, 0xe8, 0x14, 0x07, 0x96, 0xd0, 0xe2, 0xf7, 0x4c, 0xb6, 0xc2, 0x34, 0x2f, 0x47, 0x63, 0x56, + 0x5b, 0x96, 0x63, 0xb3, 0x0d, 0xa8, 0xe9, 0x3a, 0xea, 0x3e, 0xb5, 0x2a, 0xdd, 0xba, 0xc0, 0x95, + 0x93, 0x96, 0xc6, 0xe3, 0x5c, 0x16, 0x25, 0xa2, 0xe4, 0x38, 0x4e, 0xcd, 0x65, 0x5e, 0x1f, 0x6a, + 0x35, 0xf3, 0xd2, 0x50, 0x71, 0x7f, 0xba, 0x64, 0x95, 0x93, 0x7a, 0x2b, 0xd4, 0xf4, 0xd2, 0x9c, + 0xa6, 0x9c, 0xde, 0xb3, 0x7a, 0xf1, 0x4c, 0xe5, 0xeb, 0x2d, 0x68, 0x44, 0x89, 0x47, 0xe7, 0x03, + 0xa8, 0x8a, 0x22, 0x77, 0x81, 0xf4, 0x99, 0x54, 0x52, 0x1e, 0xf5, 0x88, 0x5f, 0xd0, 0xb1, 0x88, + 0x93, 0x88, 0xbc, 0x5c, 0x52, 0x71, 0x17, 0xce, 0x3b, 0x16, 0x1a, 0x4f, 0x0a, 0xee, 0x5d, 0xa8, + 0x9b, 0xea, 0xf0, 0xb5, 0x73, 0x94, 0x06, 0x25, 0x3e, 0x86, 0xde, 0xb4, 0x42, 0x53, 0x83, 0x8b, + 0xe7, 0xa8, 0xbb, 0x53, 0xfa, 0x0b, 0xad, 0x71, 0x35, 0xf0, 0x27, 0x7e, 0xaa, 0x7d, 0xbe, 0xa9, + 0x13, 0xa2, 0x84, 0xc0, 0xf8, 0x4f, 0xa7, 0x40, 0x2e, 0x9d, 0x8f, 0xff, 0x74, 0x9a, 0x64, 0x00, + 0x75, 0x5f, 0x3d, 0xf0, 0x13, 0x95, 0xea, 0xfa, 0x06, 0xf3, 0x2a, 0xd6, 0xa0, 0xe6, 0x2b, 0x34, + 0x13, 0xda, 0x4b, 0xd3, 0x6f, 0xe2, 0x26, 0xd4, 0x74, 0xe5, 0xfc, 0xfa, 0x39, 0x89, 0xd6, 0x27, + 0x6b, 0x2c, 0x4d, 0x21, 0xde, 0x87, 0x3a, 0x95, 0x4d, 0x47, 0xf1, 0xe0, 0xed, 0x59, 0x0e, 0xe0, + 0xda, 0x65, 0xab, 0x16, 0x70, 0x0d, 0xf3, 0x07, 0x50, 0x37, 0x4e, 0xca, 0x70, 0x96, 0xab, 0xb5, + 0xb3, 0x62, 0x19, 0x0a, 0x71, 0x1d, 0xaa, 0x13, 0xd4, 0x63, 0x83, 0x77, 0x66, 0x25, 0x94, 0xd5, + 0x1b, 0x63, 0xc5, 0xdf, 0x87, 0xcb, 0xe5, 0xc2, 0x63, 0x53, 0x95, 0xac, 0x37, 0x38, 0xaf, 0x53, + 0xdb, 0xb7, 0xe7, 0xb0, 0xca, 0x74, 0xfd, 0xb2, 0x75, 0x31, 0x7e, 0x49, 0x61, 0xf3, 0xa7, 0xb9, + 0xba, 0x47, 0xe9, 0x1a, 0xdc, 0x30, 0xce, 0xf7, 0x79, 0x83, 0x61, 0x8c, 0x00, 0xd9, 0x99, 0xcf, + 0xa0, 0x3d, 0xca, 0x5e, 0xbc, 0x38, 0x33, 0x9b, 0xf3, 0xef, 0x51, 0xbb, 0xd2, 0x16, 0x43, 0xa9, + 0xd6, 0xd9, 0x6a, 0x8d, 0x4a, 0x85, 0xcf, 0x17, 0xa1, 0xee, 0x86, 0xb6, 0xe3, 0x79, 0xc9, 0x60, + 0x83, 0x6b, 0x9d, 0xdd, 0x70, 0xdb, 0xf3, 0xe8, 0x72, 0x87, 0x28, 0x96, 0x74, 0x42, 0xda, 0xf6, + 0xbd, 0xc1, 0xfb, 0x6c, 0x78, 0x0c, 0x68, 0xd7, 0xa3, 0xdb, 0x1f, 0x4c, 0x5c, 0xee, 0x7b, 0x83, + 0x9b, 0xfa, 0xf6, 0x07, 0x0d, 0xda, 0xf5, 0xd0, 0xf1, 0xc4, 0x20, 0xc6, 0x40, 0x06, 0x1f, 0x70, + 0xc2, 0x63, 0xe2, 0x9c, 0xee, 0x6b, 0x10, 0x0a, 0x29, 0xa7, 0xf6, 0x48, 0x6d, 0xdd, 0x9a, 0x15, + 0xd2, 0x3c, 0x0d, 0x6c, 0x35, 0xfd, 0x3c, 0x23, 0x4c, 0x82, 0x4d, 0xaa, 0xc8, 0x0e, 0xb6, 0x06, + 0x1f, 0x9e, 0x17, 0x6c, 0x9d, 0xe5, 0x46, 0xc1, 0x36, 0x09, 0xef, 0x2d, 0x00, 0xd6, 0x59, 0xa4, + 0x70, 0x36, 0x67, 0xdb, 0xe4, 0xd1, 0x80, 0xc5, 0x47, 0x9a, 0x48, 0xd5, 0x6c, 0x01, 0x50, 0x7a, + 0x81, 0xdb, 0xdc, 0x9e, 0x6d, 0x93, 0x7b, 0xf7, 0x56, 0xf3, 0x59, 0xee, 0xe8, 0xdf, 0x86, 0x66, + 0x86, 0x7e, 0x3c, 0x7a, 0xd2, 0x83, 0x3b, 0xb3, 0xcc, 0x6c, 0x5c, 0x7c, 0xab, 0x91, 0xe9, 0x27, + 0xfc, 0x08, 0xd9, 0x1e, 0x72, 0x43, 0x06, 0x1f, 0xcd, 0x7e, 0x24, 0x8f, 0x03, 0x2c, 0x32, 0x51, + 0x1c, 0x12, 0x7c, 0x0a, 0x2d, 0x9e, 0x34, 0x6e, 0xb4, 0x35, 0xcb, 0x23, 0x85, 0x5f, 0x63, 0xf1, + 0xec, 0x72, 0xb3, 0xeb, 0x50, 0x75, 0xe2, 0x38, 0x38, 0x1b, 0x7c, 0x3c, 0xcb, 0xe1, 0xdb, 0x08, + 0xb6, 0x18, 0x8b, 0xac, 0x34, 0xc9, 0x82, 0xd4, 0x37, 0xa7, 0x90, 0x3e, 0x99, 0x65, 0xa5, 0xd2, + 0xb1, 0x4e, 0xab, 0x35, 0x29, 0x9d, 0xf1, 0xbc, 0x05, 0x8d, 0x38, 0x52, 0xa9, 0xed, 0x4d, 0x82, + 0xc1, 0xa7, 0xe7, 0xcc, 0x08, 0x9f, 0x48, 0xb1, 0xea, 0xb1, 0x3e, 0xd2, 0x33, 0x75, 0x4a, 0xfa, + 0x67, 0x33, 0xa7, 0xa4, 0xb7, 0xa0, 0x3d, 0x89, 0xc2, 0x71, 0xe4, 0x1d, 0xf1, 0xec, 0xff, 0xbc, + 0x1c, 0x14, 0xee, 0x21, 0x86, 0xc3, 0x48, 0x4d, 0xa4, 0x4d, 0x43, 0x5f, 0xfb, 0x6e, 0xbe, 0xb2, + 0x1d, 0x45, 0x6a, 0xff, 0x33, 0x0e, 0xe1, 0x19, 0xbe, 0xab, 0xb6, 0x09, 0x3a, 0xbd, 0xbd, 0x7d, + 0x74, 0xa6, 0x73, 0x91, 0xbf, 0x20, 0xf6, 0x2c, 0xb6, 0xb7, 0xef, 0x9e, 0x71, 0x42, 0xf2, 0x73, + 0xb8, 0x5c, 0x3a, 0xb7, 0x18, 0xc5, 0x76, 0x68, 0xa3, 0x0a, 0x48, 0xa4, 0x97, 0xb9, 0x72, 0xf0, + 0x79, 0x1e, 0x6f, 0xea, 0xc3, 0x8b, 0x51, 0xfc, 0x68, 0x3f, 0x91, 0x16, 0x61, 0xc5, 0xa3, 0xf2, + 0x19, 0x49, 0x27, 0x18, 0x47, 0x89, 0x9f, 0x1e, 0x4f, 0x06, 0xbf, 0x24, 0x3f, 0xf0, 0xcd, 0x52, + 0x3c, 0x90, 0xe7, 0xbf, 0xb6, 0x0d, 0x91, 0x55, 0x8c, 0x31, 0x87, 0x89, 0xcf, 0xe1, 0x92, 0xb6, + 0x05, 0xd8, 0xe1, 0xd4, 0x51, 0x74, 0x35, 0xf8, 0x15, 0x9d, 0x45, 0xbf, 0x58, 0x10, 0x7c, 0x55, + 0x3a, 0x95, 0xae, 0xc4, 0x36, 0xbc, 0x39, 0xaf, 0x2d, 0x3a, 0x26, 0x3c, 0x01, 0x5f, 0xd0, 0x04, + 0x5c, 0x3e, 0xdf, 0xfe, 0x40, 0xea, 0x7b, 0x69, 0x6e, 0x81, 0xc0, 0x09, 0x20, 0xcb, 0x25, 0x3d, + 0x3b, 0xca, 0xd2, 0x38, 0x4b, 0x07, 0xbf, 0xe6, 0x38, 0x31, 0x8d, 0xe2, 0xc7, 0x8c, 0x78, 0x4c, + 0x70, 0x0e, 0xb6, 0x7f, 0xb3, 0xd4, 0x58, 0xee, 0x8b, 0xdf, 0x2c, 0x35, 0xde, 0xed, 0x5f, 0xb7, + 0x5a, 0xa5, 0x8d, 0x85, 0xe1, 0xa7, 0xd0, 0xde, 0xa6, 0xeb, 0x8b, 0x7c, 0x45, 0x86, 0xed, 0x3a, + 0x2c, 0xe5, 0x05, 0x29, 0xb9, 0xc5, 0x24, 0x8a, 0x17, 0x72, 0x37, 0x1c, 0x45, 0x16, 0xa1, 0x87, + 0xff, 0x76, 0x09, 0x6a, 0x5c, 0x24, 0xf0, 0xfa, 0x23, 0x8a, 0x6f, 0x1a, 0xb1, 0x0f, 0x8b, 0xb3, + 0x1c, 0x2c, 0xe1, 0x84, 0x9e, 0xad, 0xd9, 0x6e, 0x16, 0xb5, 0x2e, 0xab, 0x50, 0xe5, 0x58, 0x9d, + 0x53, 0x18, 0xfc, 0x42, 0x2a, 0x2f, 0x53, 0xc7, 0x74, 0x47, 0x91, 0x4e, 0xca, 0x2d, 0x59, 0x60, + 0x40, 0xbb, 0x1e, 0xed, 0x55, 0x1a, 0x02, 0xd2, 0xa9, 0x35, 0x9d, 0x8b, 0xd0, 0x40, 0xd2, 0xac, + 0xa6, 0x8e, 0xa6, 0xfe, 0x92, 0x3a, 0x9a, 0xb7, 0x60, 0x29, 0x34, 0xc7, 0x8c, 0x72, 0x3c, 0xdd, + 0x51, 0x42, 0x70, 0x71, 0x13, 0xf2, 0x73, 0x95, 0xda, 0x47, 0x7c, 0xf9, 0xb9, 0xcb, 0x2d, 0x68, + 0xe6, 0x17, 0x5e, 0x69, 0xb7, 0x70, 0x75, 0xb3, 0xb8, 0x02, 0xeb, 0xd0, 0x3c, 0x59, 0x05, 0xd9, + 0xab, 0xab, 0x41, 0x5a, 0x3f, 0xad, 0x1a, 0x84, 0x63, 0x66, 0x37, 0x0a, 0x55, 0xaa, 0x77, 0x63, + 0xeb, 0xbe, 0xda, 0xc1, 0x57, 0xf1, 0x0b, 0xe8, 0x24, 0xd2, 0x7d, 0x66, 0x4f, 0xd4, 0x98, 0x3f, + 0xd1, 0x29, 0x9f, 0xed, 0x9e, 0xa8, 0xf1, 0xd7, 0x54, 0xa9, 0xa2, 0x43, 0xd8, 0x16, 0xd2, 0xee, + 0xa9, 0x31, 0xf5, 0xfa, 0x01, 0x2c, 0x4f, 0xe4, 0xe4, 0x48, 0x26, 0xea, 0xd8, 0x8f, 0x8d, 0xed, + 0xeb, 0x52, 0x45, 0x4d, 0xbf, 0x40, 0xf0, 0x58, 0x86, 0xff, 0xb8, 0x02, 0x0d, 0x9c, 0x45, 0xe4, + 0x25, 0x21, 0x60, 0x69, 0xe2, 0xc6, 0x99, 0x8e, 0x4c, 0xe8, 0x59, 0x5f, 0xa2, 0xc5, 0x5c, 0xa2, + 0x2f, 0xd1, 0xa2, 0x35, 0xe4, 0x1c, 0x23, 0x3d, 0xf3, 0xbd, 0x28, 0x67, 0xb4, 0x0d, 0xcd, 0x9c, + 0x61, 0x5e, 0xc5, 0x05, 0xa8, 0xb9, 0x21, 0x6d, 0x4f, 0x70, 0xae, 0xb6, 0xea, 0x86, 0x3b, 0x61, + 0xaa, 0xc1, 0xc5, 0x51, 0x95, 0xaa, 0x1b, 0xee, 0x7a, 0xa7, 0xc3, 0xff, 0x50, 0x81, 0xe5, 0xfd, + 0x24, 0x72, 0xa5, 0x52, 0x0f, 0xd1, 0xb3, 0xa2, 0xbc, 0x18, 0x7e, 0x91, 0xd2, 0x08, 0x9c, 0x82, + 0xa2, 0x67, 0xe4, 0x61, 0xde, 0x3b, 0xca, 0xe3, 0xbf, 0x45, 0xab, 0x49, 0x10, 0x0a, 0xff, 0x72, + 0x74, 0xa9, 0xde, 0x82, 0xd1, 0x94, 0x80, 0xb8, 0x0e, 0xdd, 0x42, 0x01, 0x95, 0x4a, 0x43, 0x8a, + 0xdb, 0x0b, 0xa8, 0x97, 0x6b, 0xd0, 0xd2, 0x05, 0x44, 0xd4, 0x0d, 0xe7, 0x94, 0x80, 0x41, 0x07, + 0x7a, 0x14, 0xac, 0xad, 0x09, 0xcf, 0x59, 0x24, 0xd6, 0xdf, 0x88, 0x1e, 0xfe, 0xa1, 0x02, 0xfd, + 0xfd, 0x44, 0xc6, 0x4e, 0x22, 0xa9, 0xa2, 0x88, 0xe6, 0x78, 0x0d, 0x6a, 0x81, 0x0c, 0xc7, 0xba, + 0x88, 0x64, 0xd1, 0xd2, 0x6f, 0xf9, 0x05, 0x68, 0x0b, 0xa5, 0x0b, 0xd0, 0x70, 0xae, 0x13, 0xe9, + 0xe8, 0x7b, 0xd2, 0xe8, 0x19, 0x65, 0x10, 0x83, 0x78, 0x8e, 0x54, 0x1b, 0x16, 0xbf, 0xe8, 0x33, + 0xd2, 0x47, 0x7e, 0x48, 0x95, 0x9b, 0x74, 0x46, 0xfa, 0xae, 0x4f, 0xda, 0x9f, 0xc1, 0xe8, 0x8d, + 0xf1, 0x5d, 0x43, 0xb4, 0xf7, 0xd4, 0xb0, 0xba, 0x44, 0xe0, 0x24, 0x67, 0x07, 0x04, 0xa5, 0x80, + 0x99, 0xaf, 0x28, 0xe2, 0xb2, 0x24, 0xce, 0x7a, 0x74, 0xcc, 0x0d, 0x45, 0xac, 0x5b, 0xd4, 0xf0, + 0x9f, 0xd7, 0xa1, 0xa5, 0x57, 0x88, 0xfe, 0x86, 0xb9, 0xa3, 0x92, 0x73, 0x47, 0x1f, 0x16, 0xd5, + 0xd3, 0x40, 0xb3, 0x0b, 0x3e, 0x8a, 0x8f, 0x61, 0x31, 0xf0, 0x27, 0x3a, 0x8a, 0xbd, 0x32, 0xe5, + 0x91, 0x4c, 0xaf, 0xb3, 0x66, 0x65, 0xa4, 0x46, 0x33, 0x48, 0x17, 0x36, 0xa0, 0xd0, 0xe8, 0xb5, + 0x41, 0xef, 0xe0, 0x14, 0x25, 0x13, 0x67, 0xdd, 0x71, 0xb9, 0x6a, 0x58, 0xab, 0x9b, 0x8e, 0xd5, + 0xd4, 0x90, 0x5d, 0x4f, 0x7c, 0x02, 0x8d, 0x7c, 0xaf, 0xdd, 0xc4, 0xad, 0xe9, 0x69, 0xb8, 0xb9, + 0xf3, 0xe8, 0xf0, 0x34, 0x34, 0x9b, 0xe9, 0xfa, 0x63, 0x39, 0xa5, 0xf8, 0x35, 0xb4, 0x95, 0x54, + 0x8a, 0x4f, 0xd4, 0x8f, 0x22, 0xad, 0x86, 0x2e, 0x94, 0x43, 0x52, 0xc2, 0xe2, 0x5f, 0x1b, 0xa1, + 0x53, 0x05, 0x48, 0x7c, 0x0d, 0x5d, 0xd3, 0x3e, 0x88, 0xc6, 0xe3, 0x3c, 0x17, 0x74, 0xe5, 0x5c, + 0x0f, 0x0f, 0x09, 0x5d, 0xea, 0xa7, 0xa3, 0xca, 0x08, 0xf1, 0x15, 0x74, 0x63, 0x66, 0x1a, 0x5b, + 0x57, 0xc3, 0xb1, 0x3a, 0xbb, 0x3c, 0xe5, 0x40, 0x4f, 0x31, 0x55, 0x71, 0x72, 0xb4, 0x80, 0xab, + 0xf3, 0xb7, 0x4b, 0x70, 0x72, 0x70, 0xfa, 0x76, 0x09, 0x09, 0x6b, 0xfa, 0x3a, 0xa8, 0x51, 0xe2, + 0xd0, 0x29, 0x79, 0xb6, 0x7b, 0xa6, 0xc4, 0xf5, 0xf6, 0xb9, 0x15, 0xc3, 0x0f, 0x6e, 0xf2, 0x2d, + 0x0a, 0x0f, 0x74, 0x13, 0xb2, 0x83, 0xba, 0x5e, 0x68, 0x35, 0x99, 0x83, 0x12, 0x9b, 0xb0, 0xa2, + 0x3f, 0x23, 0x4f, 0xa5, 0x9b, 0xe9, 0x0b, 0x42, 0x48, 0xe9, 0xb5, 0xad, 0x65, 0x46, 0xdd, 0x37, + 0x98, 0x5d, 0x4f, 0x7c, 0x06, 0x03, 0x95, 0x3a, 0xa9, 0xa4, 0x01, 0x19, 0xbd, 0xeb, 0x8f, 0xc3, + 0x28, 0x91, 0xba, 0xc6, 0x66, 0x2d, 0xc7, 0x6b, 0x7d, 0xbb, 0x4b, 0x58, 0xf1, 0x6b, 0xe8, 0xa3, + 0x8a, 0xcc, 0xf3, 0x2d, 0x76, 0xaa, 0x74, 0x28, 0x3e, 0x5f, 0xc5, 0x77, 0x91, 0xda, 0xb0, 0xc5, + 0x21, 0xe5, 0xed, 0xa9, 0xfd, 0x58, 0x86, 0xe8, 0xd4, 0x93, 0x86, 0x90, 0x99, 0x92, 0x9e, 0xbe, + 0x03, 0x66, 0x15, 0xb1, 0x5f, 0xe5, 0x48, 0x8b, 0x70, 0xe8, 0x46, 0x18, 0xf1, 0xd1, 0xdb, 0xad, + 0xe4, 0xc0, 0x16, 0xce, 0x4d, 0x9f, 0xd8, 0xf4, 0xb2, 0x96, 0x26, 0xa6, 0x41, 0x3f, 0x36, 0xf7, + 0x62, 0x2e, 0x7f, 0x05, 0x97, 0x5e, 0x3a, 0xab, 0xaf, 0x2b, 0xfa, 0xe9, 0x94, 0x6f, 0x2c, 0xf8, + 0x3f, 0x8b, 0xd0, 0x2a, 0x71, 0x2b, 0x5d, 0x7b, 0xa8, 0x64, 0x62, 0x4a, 0xfb, 0xf0, 0x19, 0x61, + 0xc7, 0x91, 0x32, 0x95, 0x6a, 0xf4, 0x8c, 0xb0, 0x24, 0xca, 0x2b, 0x76, 0xe8, 0x19, 0x79, 0x48, + 0xef, 0x31, 0xe9, 0x15, 0x5b, 0xe2, 0x9b, 0x36, 0x0a, 0xe0, 0xae, 0x47, 0xf7, 0x23, 0x3a, 0xa9, + 0x73, 0xe4, 0x28, 0x53, 0xa3, 0x99, 0xbf, 0xa3, 0x69, 0x78, 0x26, 0x13, 0x1c, 0x8b, 0xa9, 0x50, + 0xd0, 0xaf, 0x28, 0xe3, 0xb4, 0xaa, 0x2f, 0xa2, 0x90, 0xab, 0x13, 0xda, 0x56, 0x03, 0x01, 0xdf, + 0x45, 0x21, 0x35, 0xd3, 0x12, 0xad, 0xab, 0x6c, 0xcc, 0x2b, 0xda, 0xcc, 0xa7, 0x99, 0xc4, 0xe0, + 0xd2, 0xa3, 0x13, 0x89, 0x4d, 0xab, 0x4e, 0xef, 0x5c, 0xf8, 0x43, 0x51, 0xf0, 0x73, 0xc7, 0x4f, + 0x49, 0x75, 0x44, 0x59, 0xaa, 0x99, 0xbe, 0x87, 0x88, 0x6f, 0x1d, 0x3f, 0x3d, 0x64, 0xb0, 0xf8, + 0x48, 0x1f, 0x34, 0x2e, 0xd3, 0xd2, 0x4d, 0x3f, 0xbc, 0x77, 0x2d, 0x66, 0xe8, 0x0f, 0x24, 0x5d, + 0x66, 0x37, 0x71, 0xd2, 0xc4, 0x3f, 0x8d, 0x42, 0xf4, 0x9d, 0xe8, 0x50, 0x7f, 0x7e, 0x27, 0x63, + 0xc3, 0x5a, 0xc9, 0x91, 0x8f, 0x08, 0x47, 0xe9, 0xdc, 0x27, 0xb0, 0x21, 0x4f, 0xe3, 0xc0, 0x77, + 0xfd, 0x99, 0xcb, 0x09, 0x6c, 0xd7, 0x51, 0xa9, 0x9d, 0xc8, 0x34, 0x4b, 0x42, 0x45, 0xdb, 0xb2, + 0x9a, 0xaf, 0xdf, 0x31, 0xf4, 0xe5, 0x0b, 0x0b, 0x76, 0x1c, 0x95, 0x5a, 0x4c, 0xfb, 0x28, 0x0b, + 0x02, 0x9c, 0x84, 0x3c, 0x8d, 0xcc, 0x15, 0x64, 0x75, 0xc5, 0x09, 0xe4, 0xe1, 0x7f, 0xa9, 0xc0, + 0xf2, 0x39, 0x4d, 0x83, 0x01, 0x2d, 0x6a, 0x19, 0x53, 0xf5, 0xd2, 0xb6, 0x6a, 0xf8, 0xba, 0xeb, + 0x11, 0x22, 0x9d, 0xa4, 0xa6, 0xde, 0x05, 0x11, 0xe9, 0x04, 0xd5, 0xe8, 0x05, 0xa8, 0xa5, 0xa7, + 0xb4, 0xe4, 0x6c, 0x7d, 0xaa, 0xe9, 0x29, 0xae, 0xf5, 0x36, 0x34, 0x83, 0x68, 0x6c, 0x07, 0xf2, + 0x99, 0xe4, 0x1b, 0x63, 0xba, 0x5b, 0xef, 0xbe, 0x42, 0xc5, 0x6d, 0x3e, 0x8c, 0xc6, 0x0f, 0x91, + 0xd6, 0x6a, 0x04, 0xfa, 0x69, 0xf8, 0x1b, 0x68, 0x18, 0xa8, 0x68, 0x42, 0xf5, 0x9e, 0x3c, 0xca, + 0xc6, 0xfd, 0x37, 0x44, 0x03, 0x96, 0xb0, 0x45, 0xbf, 0x82, 0x4f, 0xdf, 0x3a, 0x49, 0xd8, 0x5f, + 0x40, 0xf4, 0xfd, 0x24, 0x89, 0x92, 0xfe, 0x22, 0x3e, 0xee, 0x3b, 0xa1, 0xef, 0xf6, 0x97, 0xf0, + 0xf1, 0x81, 0x93, 0x3a, 0x41, 0xbf, 0x3a, 0xfc, 0x7d, 0x15, 0x1a, 0xfb, 0xfa, 0xeb, 0xe2, 0x1e, + 0x74, 0xf2, 0x9b, 0x17, 0xe7, 0xef, 0x2c, 0xef, 0xcf, 0x3e, 0xd0, 0xce, 0x72, 0x3b, 0x2e, 0xbd, + 0xcd, 0xde, 0xdf, 0xb8, 0x70, 0xee, 0xfe, 0xc6, 0xab, 0xb0, 0xf8, 0x34, 0x39, 0x9b, 0x2e, 0xf8, + 0xde, 0x0f, 0x9c, 0xd0, 0x42, 0xb0, 0xf8, 0x08, 0x5a, 0x94, 0xd3, 0x66, 0x33, 0xaa, 0x77, 0x63, + 0xcb, 0x57, 0xa5, 0x72, 0x29, 0x2f, 0x20, 0x91, 0xf6, 0xd8, 0x37, 0xa1, 0xe1, 0x1e, 0xfb, 0x81, + 0x97, 0xc8, 0x50, 0x1f, 0xbc, 0x10, 0xe7, 0x87, 0x6c, 0xe5, 0x34, 0xe2, 0xcf, 0xa0, 0xef, 0x17, + 0xbb, 0xc9, 0x45, 0x09, 0xc3, 0x94, 0xbd, 0x2a, 0xed, 0x37, 0x5b, 0xbd, 0x12, 0x39, 0xb9, 0x88, + 0xc5, 0x95, 0x2a, 0xf5, 0xf2, 0x95, 0x2a, 0x7c, 0xa3, 0x1e, 0xf9, 0x71, 0x8d, 0x7c, 0x2f, 0x0a, + 0xdd, 0xb8, 0x1b, 0xda, 0xf9, 0x6e, 0xce, 0x06, 0xef, 0xc6, 0x75, 0xd4, 0x4e, 0xf8, 0xbb, 0xd0, + 0x45, 0xa7, 0xde, 0xe6, 0x58, 0x00, 0xed, 0x28, 0xe8, 0x1b, 0xa0, 0x32, 0x75, 0x7c, 0x0f, 0xa3, + 0x01, 0x64, 0xc6, 0xeb, 0xd0, 0x35, 0xff, 0xa2, 0x83, 0xac, 0x96, 0x2e, 0x71, 0xd0, 0x50, 0x8e, + 0xab, 0x36, 0x61, 0xc5, 0x3d, 0x76, 0xc2, 0x50, 0x06, 0xf6, 0x51, 0x36, 0x1a, 0x19, 0x37, 0x8c, + 0xaf, 0x05, 0x5b, 0xd6, 0xa8, 0xbb, 0x84, 0x21, 0x6f, 0x6c, 0x08, 0x9d, 0xd0, 0x0f, 0xcc, 0xd5, + 0xa0, 0x21, 0xbb, 0xcc, 0x55, 0xab, 0x15, 0xfa, 0x01, 0x5f, 0x06, 0x4a, 0x77, 0x98, 0xf6, 0xb3, + 0xcc, 0xf7, 0x94, 0x9d, 0x46, 0xe6, 0x32, 0x42, 0x9d, 0x17, 0x2a, 0xed, 0xb4, 0x3e, 0xc9, 0x7c, + 0xef, 0x30, 0xd2, 0xd7, 0x11, 0x76, 0x88, 0xde, 0xbc, 0x0e, 0xbf, 0x84, 0x76, 0x99, 0x77, 0x90, + 0x17, 0x69, 0x2b, 0xac, 0xff, 0x86, 0x00, 0xa8, 0x3d, 0x8a, 0x92, 0x89, 0x13, 0xf4, 0x2b, 0xf8, + 0xcc, 0xca, 0xbc, 0xbf, 0x20, 0xda, 0xd0, 0x30, 0x5b, 0x3b, 0xfd, 0x45, 0x9d, 0x6c, 0xfd, 0x25, + 0x34, 0xcc, 0x1d, 0x8b, 0x74, 0x3f, 0x5d, 0xe4, 0x49, 0x0e, 0x8d, 0x74, 0x65, 0x31, 0x02, 0x28, + 0x2c, 0x32, 0x77, 0xd6, 0x2e, 0x14, 0x77, 0xd6, 0x0e, 0x7f, 0x0b, 0xed, 0xf2, 0x10, 0x4d, 0xfa, + 0xa0, 0x52, 0xa4, 0x0f, 0xe6, 0xb4, 0xa2, 0x8a, 0x97, 0x24, 0x9a, 0xd8, 0x25, 0xef, 0xbd, 0x81, + 0x00, 0xfc, 0xcc, 0xf0, 0x1f, 0x2d, 0x40, 0x95, 0x36, 0x3c, 0xc8, 0xbb, 0xc2, 0x87, 0x42, 0x82, + 0xaa, 0x56, 0x93, 0x20, 0xff, 0x0f, 0x87, 0x7d, 0xf3, 0x74, 0xf2, 0xd2, 0xab, 0xd3, 0xc9, 0xdb, + 0xb0, 0xfc, 0xac, 0x74, 0x2f, 0x2a, 0x6f, 0x73, 0x54, 0x8d, 0x2b, 0x86, 0x6d, 0xfe, 0xbc, 0xb8, + 0x1f, 0x95, 0x36, 0x3b, 0x7a, 0xcf, 0xa6, 0x01, 0xe2, 0x6d, 0xd0, 0xe7, 0x26, 0x6c, 0x2e, 0x57, + 0xe2, 0xda, 0x9e, 0x16, 0xc3, 0xb6, 0xa9, 0x38, 0x09, 0x03, 0xe0, 0xd3, 0xd0, 0x5c, 0x96, 0xc3, + 0xe5, 0x5c, 0xcd, 0xf4, 0x34, 0xe4, 0x02, 0xa3, 0xe1, 0x04, 0x56, 0xe6, 0x1c, 0xf2, 0x12, 0xeb, + 0xd0, 0x9e, 0x4a, 0xba, 0xf1, 0xc9, 0x0b, 0x70, 0x8b, 0x2c, 0xdb, 0x27, 0xb0, 0x26, 0x03, 0x7f, + 0xec, 0x1f, 0xf9, 0x54, 0xd3, 0x5a, 0x3a, 0x77, 0xc6, 0x4a, 0x64, 0xb5, 0x84, 0xcd, 0xcf, 0x9d, + 0xdd, 0xfc, 0x77, 0x15, 0xa8, 0xf1, 0xdd, 0xc8, 0x62, 0x19, 0x3a, 0x4f, 0xc2, 0x93, 0x30, 0x7a, + 0x1e, 0x32, 0xa0, 0xff, 0x86, 0x58, 0x81, 0x9e, 0xe1, 0x37, 0x7d, 0x09, 0x73, 0xbf, 0x22, 0xfa, + 0xd0, 0x26, 0x8e, 0x36, 0x90, 0x05, 0x71, 0x15, 0x06, 0xda, 0x29, 0xbc, 0x87, 0x06, 0x28, 0x4a, + 0xfd, 0xd1, 0x99, 0xc1, 0x2e, 0x8a, 0x1e, 0xb4, 0x0e, 0xd2, 0x28, 0x3e, 0x90, 0xa1, 0xe7, 0x87, + 0xe3, 0xfe, 0x92, 0x18, 0xc0, 0xaa, 0xe9, 0x95, 0x0b, 0x17, 0x1e, 0xf8, 0xa1, 0xaf, 0x8e, 0xfb, + 0x55, 0x71, 0x05, 0x2e, 0xce, 0xc3, 0x6c, 0xbb, 0x27, 0xfd, 0x9a, 0x58, 0x85, 0xbe, 0x41, 0xde, + 0xd5, 0x37, 0xe1, 0xf6, 0xeb, 0x37, 0x3f, 0x01, 0x71, 0xfe, 0x12, 0x62, 0xfc, 0xe6, 0x43, 0x39, + 0x76, 0xdc, 0xb3, 0x9d, 0x20, 0x52, 0x28, 0x1e, 0x1d, 0x68, 0x16, 0x7d, 0x55, 0x6e, 0x3e, 0x80, + 0x1a, 0xdf, 0x1a, 0x5d, 0xfa, 0x6b, 0x06, 0xf4, 0xdf, 0xc0, 0xc6, 0x68, 0x7c, 0xfd, 0x70, 0xfc, + 0x48, 0x9e, 0xa6, 0x6c, 0x12, 0x1e, 0x3a, 0x2a, 0xed, 0x2f, 0x88, 0x2e, 0x80, 0xfe, 0xb1, 0xfb, + 0xa1, 0xd7, 0x5f, 0xbc, 0xbb, 0xf3, 0x57, 0x7f, 0x7c, 0xab, 0xf2, 0x87, 0x3f, 0xbe, 0x55, 0xf9, + 0xcf, 0x7f, 0x7c, 0xeb, 0x8d, 0xdf, 0xfd, 0xe9, 0xad, 0xca, 0x77, 0x1f, 0x95, 0xee, 0xc4, 0xd6, + 0x36, 0x99, 0x6a, 0xb5, 0x6e, 0xe7, 0x06, 0xfa, 0x76, 0x7c, 0x32, 0xbe, 0x1d, 0x1f, 0xdd, 0x36, + 0x12, 0x7f, 0x54, 0xa3, 0xab, 0xae, 0x3f, 0xfe, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x95, + 0xf9, 0x59, 0x69, 0x5b, 0x00, 0x00, } func (m *Message) Marshal() (dAtA []byte, err error) { @@ -11900,6 +11912,18 @@ func (m *Instruction) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.TopOrderedOutput { + i-- + if m.TopOrderedOutput { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x3 + i-- + dAtA[i] = 0xf0 + } if m.ProjectionGroupingSetCount != 0 { i = encodeVarintPipeline(dAtA, i, uint64(m.ProjectionGroupingSetCount)) i-- @@ -15970,6 +15994,9 @@ func (m *Instruction) ProtoSize() (n int) { if m.ProjectionGroupingSetCount != 0 { n += 2 + sovPipeline(uint64(m.ProjectionGroupingSetCount)) } + if m.TopOrderedOutput { + n += 3 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -31591,6 +31618,26 @@ func (m *Instruction) Unmarshal(dAtA []byte) error { break } } + case 62: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TopOrderedOutput", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPipeline + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.TopOrderedOutput = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPipeline(dAtA[iNdEx:]) diff --git a/pkg/sql/colexec/mergetop/stream.go b/pkg/sql/colexec/mergetop/stream.go new file mode 100644 index 0000000000000..14e1c6bce56f2 --- /dev/null +++ b/pkg/sql/colexec/mergetop/stream.go @@ -0,0 +1,461 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mergetop + +import ( + "container/heap" + "time" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/compare" + "github.com/matrixorigin/matrixone/pkg/container/batch" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + plan2 "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/sql/colexec" + "github.com/matrixorigin/matrixone/pkg/vm" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +const ( + mergeTopStreamBatchRows = 8192 + mergeTopStreamBatchBytes = 64 * mpool.MB +) + +type orderedStream struct { + receiver *process.PipelineSignalReceiver + bat *batch.Batch + orderCols []*vector.Vector + ownedCols []bool + row int64 + ended bool +} + +type streamContainer struct { + limit uint64 + emitted uint64 + limitExecutor colexec.ExpressionExecutor + executors []colexec.ExpressionExecutor + compares []compare.Compare + streams []orderedStream + heap streamHeap + output *batch.Batch + primed bool + done bool +} + +type streamHeap struct { + ctr *streamContainer + items []int +} + +func (h *streamHeap) Len() int { return len(h.items) } +func (h *streamHeap) Less(i, j int) bool { + left, right := h.items[i], h.items[j] + r := h.ctr.compareRows(left, right) + if r == 0 { + return left < right + } + return r < 0 +} +func (h *streamHeap) Swap(i, j int) { h.items[i], h.items[j] = h.items[j], h.items[i] } +func (h *streamHeap) Push(x any) { h.items = append(h.items, x.(int)) } +func (h *streamHeap) Pop() any { + n := len(h.items) - 1 + x := h.items[n] + h.items = h.items[:n] + return x +} + +func (mergeTop *MergeTop) prepareStream(proc *process.Process) (err error) { + ctr := mergeTop.ctr.stream + if ctr == nil { + ctr = &streamContainer{} + mergeTop.ctr.stream = ctr + } + ctr.emitted = 0 + ctr.primed = false + ctr.done = false + ctr.heap = streamHeap{ctr: ctr} + + if ctr.limitExecutor == nil { + ctr.limitExecutor, err = colexec.NewExpressionExecutorWithAllocation( + proc, mergeTop.Limit, mergeTop.ctr.expressionAllocation) + if err != nil { + return err + } + } + vec, err := ctr.limitExecutor.Eval( + proc, []*batch.Batch{batch.EmptyForConstFoldBatch}, nil) + if err != nil { + return err + } + ctr.limit = vector.MustFixedColWithTypeCheck[uint64](vec)[0] + + if len(ctr.executors) != len(mergeTop.Fs) { + for _, executor := range ctr.executors { + if executor != nil { + executor.Free() + } + } + ctr.executors = make([]colexec.ExpressionExecutor, len(mergeTop.Fs)) + } + for i := range mergeTop.Fs { + if ctr.executors[i] == nil { + ctr.executors[i], err = colexec.NewExpressionExecutorWithAllocation( + proc, mergeTop.Fs[i].Expr, mergeTop.ctr.expressionAllocation) + if err != nil { + return err + } + } + } + ctr.compares = make([]compare.Compare, len(mergeTop.Fs)) + for i, spec := range mergeTop.Fs { + desc := spec.Flag&plan2.OrderBySpec_DESC != 0 + nullsLast := desc + if spec.Flag&plan2.OrderBySpec_NULLS_FIRST != 0 { + nullsLast = false + } else if spec.Flag&plan2.OrderBySpec_NULLS_LAST != 0 { + nullsLast = true + } + t := spec.Expr.Typ + typ := types.NewWithCharset(types.T(t.Id), t.Width, t.Scale, uint8(t.Charset)) + ctr.compares[i] = compare.NewOrder(typ, desc, nullsLast) + } + + ctr.streams = make([]orderedStream, len(proc.Reg.MergeReceivers)) + for i, reg := range proc.Reg.MergeReceivers { + ctr.streams[i].receiver = process.InitPipelineSignalReceiver( + proc.Ctx, []*process.WaitRegister{reg}) + } + return nil +} + +func (mergeTop *MergeTop) callStream( + proc *process.Process, + analyzer process.Analyzer, +) (vm.CallResult, error) { + ctr := mergeTop.ctr.stream + if ctr == nil { + return vm.CancelResult, nil + } + if ctr.output != nil { + ctr.output.Clean(proc.Mp()) + ctr.output = nil + } + if ctr.done || ctr.limit == 0 { + ctr.done = true + return vm.CancelResult, nil + } + if !ctr.primed { + for i := range ctr.streams { + if err := ctr.loadNextBatch(proc, analyzer, i); err != nil { + return vm.CancelResult, err + } + if !ctr.streams[i].ended { + ctr.heap.items = append(ctr.heap.items, i) + } + } + heap.Init(&ctr.heap) + ctr.primed = true + } + if ctr.heap.Len() == 0 { + ctr.done = true + return vm.CancelResult, nil + } + + first := ctr.streams[ctr.heap.items[0]].bat + var err error + ctr.output, err = proc.NewBatchFromSrcWithAllocation( + first, 0, mergeTop.ctr.retainedAllocation) + if err != nil { + return vm.CancelResult, err + } + + remaining := ctr.limit - ctr.emitted + maxRows := uint64(mergeTopStreamBatchRows) + if remaining < maxRows { + maxRows = remaining + } + rows := 0 + for uint64(rows) < maxRows && ctr.heap.Len() > 0 { + winner := ctr.heap.items[0] + stream := &ctr.streams[winner] + if rows > 0 && ctr.output.Size()+stream.rowBytes() > mergeTopStreamBatchBytes { + break + } + chunk := ctr.winnerChunk(winner, int(maxRows)-rows) + for col := range ctr.output.Vecs { + if err = ctr.output.Vecs[col].UnionBatch( + stream.bat.Vecs[col], stream.row, chunk, nil, proc.Mp()); err != nil { + return vm.CancelResult, err + } + } + rows += chunk + ctr.emitted += uint64(chunk) + stream.row += int64(chunk) + if stream.row >= int64(stream.bat.RowCount()) { + if err = ctr.loadNextBatch(proc, analyzer, winner); err != nil { + return vm.CancelResult, err + } + if stream.ended { + heap.Pop(&ctr.heap) + } else { + heap.Fix(&ctr.heap, 0) + } + } else { + heap.Fix(&ctr.heap, 0) + } + if ctr.output.Size() >= mergeTopStreamBatchBytes { + break + } + } + ctr.output.SetRowCount(rows) + if ctr.emitted >= ctr.limit || ctr.heap.Len() == 0 { + ctr.done = true + } + result := vm.NewCallResult() + result.Batch = ctr.output + if !ctr.done { + result.Status = vm.ExecHasMore + } + return result, nil +} + +func (stream *orderedStream) rowBytes() int { + return stream.rowBytesAt(stream.row) +} + +func (stream *orderedStream) rowBytesAt(row int64) int { + bytes := 0 + for _, vec := range stream.bat.Vecs { + typ := vec.GetType() + bytes += typ.TypeSize() + if typ.IsVarlen() { + bytes += len(vec.GetBytesAt(int(row))) + } + } + return bytes +} + +// winnerChunk batches contiguous winner rows while preserving both the k-way +// merge boundary and the 64 MiB output budget. Varlen rows use their actual +// payload lengths rather than an average-size estimate. +func (ctr *streamContainer) winnerChunk(winner, maxRows int) int { + stream := &ctr.streams[winner] + remaining := stream.bat.RowCount() - int(stream.row) + if remaining < maxRows { + maxRows = remaining + } + if maxRows <= 1 { + return 1 + } + rowBytes := 0 + fixedWidth := true + for _, vec := range stream.bat.Vecs { + typ := vec.GetType() + if typ.IsVarlen() { + fixedWidth = false + break + } + rowBytes += typ.TypeSize() + } + if maxRows > 256 { + maxRows = 256 + } + if fixedWidth { + if rowBytes <= 0 { + return 1 + } + budgetRows := (mergeTopStreamBatchBytes - ctr.output.Size()) / rowBytes + if budgetRows < 1 { + return 1 + } + if maxRows > budgetRows { + maxRows = budgetRows + } + } else { + budget := mergeTopStreamBatchBytes - ctr.output.Size() + used := 0 + budgetRows := 0 + for budgetRows < maxRows { + next := stream.rowBytesAt(stream.row + int64(budgetRows)) + if budgetRows > 0 && used+next > budget { + break + } + used += next + budgetRows++ + } + if budgetRows < 1 { + return 1 + } + maxRows = budgetRows + } + if ctr.heap.Len() == 1 { + return maxRows + } + + second := ctr.heap.items[1] + if ctr.heap.Len() > 2 && ctr.compareRows(ctr.heap.items[2], second) < 0 { + second = ctr.heap.items[2] + } + start := stream.row + chunk := 1 + for chunk < maxRows { + stream.row = start + int64(chunk) + if ctr.compareRows(winner, second) > 0 { + break + } + chunk++ + } + stream.row = start + return chunk +} + +func (ctr *streamContainer) loadNextBatch( + proc *process.Process, + analyzer process.Analyzer, + idx int, +) error { + stream := &ctr.streams[idx] + ctr.freeOrderCols(proc, stream) + for { + bat, err := stream.receiver.GetNextBatch(analyzer) + if err != nil { + return err + } + if bat == nil { + if cancelErr, canceled := vm.CancelCheck(proc); canceled { + return cancelErr + } + stream.bat = nil + stream.ended = true + return nil + } + if bat.IsEmpty() { + continue + } + stream.bat = bat + stream.row = 0 + stream.ended = false + stream.orderCols = make([]*vector.Vector, len(ctr.executors)) + stream.ownedCols = make([]bool, len(ctr.executors)) + for i, executor := range ctr.executors { + if executor.IsColumnExpr() { + col := executor.(*colexec.ColumnExpressionExecutor).GetColIndex() + if col < 0 || col >= len(bat.Vecs) { + return moerr.NewInternalErrorf(proc.Ctx, + "merge top ordered stream column %d out of range [0,%d)", + col, len(bat.Vecs)) + } + stream.orderCols[i] = bat.Vecs[col] + continue + } + vec, evalErr := executor.EvalWithoutResultReusing( + proc, []*batch.Batch{bat}, nil) + if evalErr != nil { + ctr.freeOrderCols(proc, stream) + return evalErr + } + stream.orderCols[i] = vec + stream.ownedCols[i] = true + } + return nil + } +} + +func (ctr *streamContainer) compareRows(left, right int) int { + l, r := &ctr.streams[left], &ctr.streams[right] + for i, cmp := range ctr.compares { + cmp.Set(0, l.orderCols[i]) + cmp.Set(1, r.orderCols[i]) + if result := cmp.Compare(0, 1, l.row, r.row); result != 0 { + return result + } + } + return 0 +} + +func (ctr *streamContainer) freeOrderCols(proc *process.Process, stream *orderedStream) { + for i, col := range stream.orderCols { + if i < len(stream.ownedCols) && stream.ownedCols[i] && col != nil { + col.Free(proc.Mp()) + } + } + stream.orderCols = nil + stream.ownedCols = nil +} + +func (ctr *container) resetStream( + proc *process.Process, + pipelineFailed bool, + err error, +) { + if ctr.stream == nil { + return + } + s := ctr.stream + cleanupDeadline := time.Now().Add(process.PipelineCleanupWaitTimeout) + if s.output != nil { + s.output.Clean(proc.Mp()) + s.output = nil + } + for i := range s.streams { + s.freeOrderCols(proc, &s.streams[i]) + remaining := time.Until(cleanupDeadline) + if remaining <= 0 { + remaining = time.Nanosecond + } + if receiver := s.streams[i].receiver; receiver != nil && + !receiver.WaitingEndWithTimeout(remaining) { + state := receiver.State() + process.WarnPipelineCleanupf( + proc, + "merge_top_stream_cleanup_wait_end_timeout", + "merge top stream cleanup timed out: timeout=%s stream=%d alive=%d nil_batch_count=%v channel_len=%v channel_cap=%v pipeline_failed=%t err=%v", + process.PipelineCleanupWaitTimeout, + i, + state.Alive, + state.NilBatches, + state.ChannelLen, + state.ChannelCap, + pipelineFailed, + err) + } + } + s.streams = nil + s.heap.items = nil + s.primed = false + s.done = false + s.emitted = 0 + for i, executor := range s.executors { + if executor != nil { + executor.Free() + s.executors[i] = nil + } + } + s.executors = nil + if s.limitExecutor != nil { + s.limitExecutor.Free() + s.limitExecutor = nil + } + s.compares = nil + ctr.stream = nil +} + +func (ctr *container) freeStream(proc *process.Process) { + ctr.resetStream(proc, false, nil) +} diff --git a/pkg/sql/colexec/mergetop/top.go b/pkg/sql/colexec/mergetop/top.go index 91737b76a405f..b7009409f8d6d 100644 --- a/pkg/sql/colexec/mergetop/top.go +++ b/pkg/sql/colexec/mergetop/top.go @@ -58,6 +58,9 @@ func (mergeTop *MergeTop) Prepare(proc *process.Process) (err error) { } else { mergeTop.OpAnalyzer.Reset() } + if mergeTop.OrderedStreams { + return mergeTop.prepareStream(proc) + } // limit executor if mergeTop.ctr.limitExecutor == nil { @@ -116,6 +119,9 @@ func (mergeTop *MergeTop) Call(proc *process.Process) ( err = mergeTopTerminalCapacityError(proc.Ctx, err) }() analyzer := mergeTop.OpAnalyzer + if mergeTop.OrderedStreams { + return mergeTop.callStream(proc, analyzer) + } result = vm.NewCallResult() if mergeTop.ctr.limit == 0 { diff --git a/pkg/sql/colexec/mergetop/top_test.go b/pkg/sql/colexec/mergetop/top_test.go index 671e8a028c70c..9e914fff5e6a4 100644 --- a/pkg/sql/colexec/mergetop/top_test.go +++ b/pkg/sql/colexec/mergetop/top_test.go @@ -148,6 +148,216 @@ func TestMergeTopMaxUint64LimitReturnsAllRows(t *testing.T) { require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) } +func TestMergeTopOrderedStreamsMergesWithoutRetainingLimitRows(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + proc.Reg.MergeReceivers = []*process.WaitRegister{ + process.NewPipelineEdge(4, 1), + process.NewPipelineEdge(4, 1), + } + + for i, values := range [][]int64{{1, 3, 5}, {2, 4, 6}} { + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + for _, value := range values { + require.NoError(t, vector.AppendFixed(bat.Vecs[0], value, false, proc.Mp())) + } + bat.SetRowCount(len(values)) + require.True(t, proc.Reg.MergeReceivers[i].SendDataDirect(proc.Ctx, bat, proc.Mp())) + require.True(t, proc.Reg.MergeReceivers[i].SendEnd()) + } + + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(4)). + WithFs([]*plan.OrderBySpec{{Expr: newExpression(0)}}). + WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + result, err := arg.Call(proc) + require.NoError(t, err) + require.Equal(t, []int64{1, 2, 3, 4}, + vector.MustFixedColWithTypeCheck[int64](result.Batch.Vecs[0])) + require.Less(t, result.Batch.Size(), mergeTopStreamBatchBytes) + + arg.Reset(proc, false, nil) + arg.Free(proc, false, nil) + arg.Release() + proc.Free() + require.Equal(t, int64(0), proc.Mp().CurrNB()) +} + +func TestMergeTopOrderedStreamsAcrossBatchBoundariesDescending(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + proc.Reg.MergeReceivers = []*process.WaitRegister{ + process.NewPipelineEdge(4, 1), + process.NewPipelineEdge(4, 1), + process.NewPipelineEdge(1, 1), + } + sendInt64Stream(t, proc, proc.Reg.MergeReceivers[0], []int64{9, 7}, []int64{5, 1}) + sendInt64Stream(t, proc, proc.Reg.MergeReceivers[1], []int64{10, 8, 6}, []int64{4, 2}) + require.True(t, proc.Reg.MergeReceivers[2].SendEnd()) + + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(7)). + WithFs([]*plan.OrderBySpec{{Expr: newExpression(0), Flag: plan.OrderBySpec_DESC}}). + WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + result, err := arg.Call(proc) + require.NoError(t, err) + require.Equal(t, []int64{10, 9, 8, 7, 6, 5, 4}, + vector.MustFixedColWithTypeCheck[int64](result.Batch.Vecs[0])) + + arg.Reset(proc, false, nil) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + +func TestMergeTopOrderedStreamsChunksOutputRows(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + reg := process.NewPipelineEdge(2, 1) + proc.Reg.MergeReceivers = []*process.WaitRegister{reg} + values := make([]int64, mergeTopStreamBatchRows+17) + for i := range values { + values[i] = int64(i) + } + sendInt64Stream(t, proc, reg, values) + + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(uint64(len(values)))). + WithFs([]*plan.OrderBySpec{{Expr: newExpression(0)}}). + WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + first, err := arg.Call(proc) + require.NoError(t, err) + require.Equal(t, mergeTopStreamBatchRows, first.Batch.RowCount()) + second, err := arg.Call(proc) + require.NoError(t, err) + require.Equal(t, 17, second.Batch.RowCount()) + require.Equal(t, int64(mergeTopStreamBatchRows), + vector.MustFixedColWithTypeCheck[int64](second.Batch.Vecs[0])[0]) + + arg.Reset(proc, false, nil) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + +func TestMergeTopOrderedStreamsVarlenNullsFirst(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + proc.Reg.MergeReceivers = []*process.WaitRegister{ + process.NewPipelineEdge(2, 1), + process.NewPipelineEdge(2, 1), + } + sendStringStream(t, proc, proc.Reg.MergeReceivers[0], + []string{"", "a", "c"}, []bool{true, false, false}) + sendStringStream(t, proc, proc.Reg.MergeReceivers[1], + []string{"", "b", "d"}, []bool{true, false, false}) + + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(6)). + WithFs([]*plan.OrderBySpec{{ + Expr: newStringExpression(0), + Flag: plan.OrderBySpec_NULLS_FIRST, + }}). + WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + result, err := arg.Call(proc) + require.NoError(t, err) + require.Equal(t, 6, result.Batch.RowCount()) + require.True(t, result.Batch.Vecs[0].IsNull(0)) + require.True(t, result.Batch.Vecs[0].IsNull(1)) + for row, expected := range []string{"a", "b", "c", "d"} { + require.Equal(t, expected, + string(result.Batch.Vecs[0].GetBytesAt(row+2))) + } + + arg.Reset(proc, false, nil) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + +func TestMergeTopOrderedStreamsPropagatesTerminalError(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + proc.Reg.MergeReceivers = []*process.WaitRegister{ + process.NewPipelineEdge(1, 1), + process.NewPipelineEdge(1, 1), + } + require.True(t, proc.Reg.MergeReceivers[0].SendError(context.Canceled)) + require.True(t, proc.Reg.MergeReceivers[1].SendEnd()) + + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(1)). + WithFs([]*plan.OrderBySpec{{Expr: newExpression(0)}}). + WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + _, err := arg.Call(proc) + require.ErrorIs(t, err, context.Canceled) + + arg.Reset(proc, true, err) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + +func TestMergeTopOrderedStreamsRejectsInvalidOrderColumn(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + reg := process.NewPipelineEdge(2, 1) + proc.Reg.MergeReceivers = []*process.WaitRegister{reg} + sendInt64Stream(t, proc, reg, []int64{1}) + + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(1)). + WithFs([]*plan.OrderBySpec{{Expr: newExpression(1)}}). + WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + _, err := arg.Call(proc) + require.ErrorContains(t, err, "column 1 out of range") + + arg.Reset(proc, true, err) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + +func sendInt64Stream( + t *testing.T, + proc *process.Process, + reg *process.WaitRegister, + batches ...[]int64, +) { + t.Helper() + for _, values := range batches { + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + for _, value := range values { + require.NoError(t, vector.AppendFixed(bat.Vecs[0], value, false, proc.Mp())) + } + bat.SetRowCount(len(values)) + require.True(t, reg.SendDataDirect(proc.Ctx, bat, proc.Mp())) + } + require.True(t, reg.SendEnd()) +} + +func sendStringStream( + t *testing.T, + proc *process.Process, + reg *process.WaitRegister, + values []string, + nulls []bool, +) { + t.Helper() + require.Len(t, nulls, len(values)) + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_varchar.ToType()) + for i, value := range values { + require.NoError(t, + vector.AppendBytes(bat.Vecs[0], []byte(value), nulls[i], proc.Mp())) + } + bat.SetRowCount(len(values)) + require.True(t, reg.SendDataDirect(proc.Ctx, bat, proc.Mp())) + require.True(t, reg.SendEnd()) +} + func TestMergeTopEmitsFinalBatchOnce(t *testing.T) { tc := newTestCase(t, []bool{false}, []types.Type{types.T_int64.ToType()}, 1, []*plan.OrderBySpec{{Expr: newExpression(0)}}) @@ -390,6 +600,12 @@ func newExpression(pos int32) *plan.Expr { } } +func newStringExpression(pos int32) *plan.Expr { + expr := newExpression(pos) + expr.Typ.Id = int32(types.T_varchar) + return expr +} + // create a new block based on the type information, ds[i] == true: in descending order func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { return testutil.NewBatch(ts, false, int(rows), proc.Mp()) diff --git a/pkg/sql/colexec/mergetop/types.go b/pkg/sql/colexec/mergetop/types.go index e4e855b6b25e0..bd22ff5bba263 100644 --- a/pkg/sql/colexec/mergetop/types.go +++ b/pkg/sql/colexec/mergetop/types.go @@ -59,12 +59,17 @@ type container struct { retainedAllocation *vector.AllocationAccountSelection expressionAllocation *vector.AllocationAccountSelection appendScratch *mpool.AccountedBuffer + + // stream is non-nil when MergeTop is the leaf of an ordered merge scope. + // The legacy child mode is retained for decoded plans produced by older CNs. + stream *streamContainer } type MergeTop struct { - Limit *plan.Expr // Limit store the number of mergeTop-operator - ctr container // ctr stores the attributes needn't do Serialization work - Fs []*plan.OrderBySpec // Fs store the order information + Limit *plan.Expr // Limit store the number of mergeTop-operator + ctr container // ctr stores the attributes needn't do Serialization work + Fs []*plan.OrderBySpec // Fs store the order information + OrderedStreams bool // consume one sorted stream per merge receiver vm.OperatorBase } @@ -104,6 +109,11 @@ func (mergeTop *MergeTop) WithFs(fs []*plan.OrderBySpec) *MergeTop { return mergeTop } +func (mergeTop *MergeTop) WithOrderedStreams() *MergeTop { + mergeTop.OrderedStreams = true + return mergeTop +} + func (mergeTop *MergeTop) Release() { if mergeTop != nil { reuse.Free(mergeTop, nil) @@ -111,10 +121,12 @@ func (mergeTop *MergeTop) Release() { } func (mergeTop *MergeTop) Reset(proc *process.Process, pipelineFailed bool, err error) { + mergeTop.ctr.resetStream(proc, pipelineFailed, err) mergeTop.ctr.reset(proc) } func (mergeTop *MergeTop) Free(proc *process.Process, pipelineFailed bool, err error) { + mergeTop.ctr.freeStream(proc) mergeTop.ctr.free(proc) } @@ -150,7 +162,7 @@ func (ctr *container) setAllocationAccount(account *mpool.AllocationAccount) err } return mpool.ErrAllocationAccountMismatch } - if ctr.bat != nil || ctr.limitExecutor != nil || ctr.appendScratch != nil || + if ctr.bat != nil || ctr.limitExecutor != nil || ctr.appendScratch != nil || ctr.stream != nil || len(ctr.executorsForOrderList) != 0 || cap(ctr.sels) != 0 { return mpool.ErrAllocationAccountInvariant } @@ -189,7 +201,7 @@ func (ctr *container) clearAllocationAccount(account *mpool.AllocationAccount) e if ctr.allocationAccount != account { return mpool.ErrAllocationAccountMismatch } - if ctr.bat != nil || ctr.limitExecutor != nil || ctr.appendScratch != nil || + if ctr.bat != nil || ctr.limitExecutor != nil || ctr.appendScratch != nil || ctr.stream != nil || len(ctr.executorsForOrderList) != 0 || cap(ctr.sels) != 0 { return mpool.ErrAllocationAccountInvariant } diff --git a/pkg/sql/colexec/top/types.go b/pkg/sql/colexec/top/types.go index 1496b72230b3c..0e7324a2fb964 100644 --- a/pkg/sql/colexec/top/types.go +++ b/pkg/sql/colexec/top/types.go @@ -96,10 +96,11 @@ type container struct { } type Top struct { - Limit *plan.Expr - TopValueTag int32 - ctr container - Fs []*plan.OrderBySpec + Limit *plan.Expr + TopValueTag int32 + OrderedOutput bool + ctr container + Fs []*plan.OrderBySpec vm.OperatorBase } @@ -139,6 +140,11 @@ func (top *Top) WithFs(fs []*plan.OrderBySpec) *Top { return top } +func (top *Top) WithOrderedOutput() *Top { + top.OrderedOutput = true + return top +} + func (top *Top) Release() { if top != nil { reuse.Free(top, nil) diff --git a/pkg/sql/compile/allocation_account_lifecycle_test.go b/pkg/sql/compile/allocation_account_lifecycle_test.go index 480306f8fed9f..9782bcbcc9894 100644 --- a/pkg/sql/compile/allocation_account_lifecycle_test.go +++ b/pkg/sql/compile/allocation_account_lifecycle_test.go @@ -41,6 +41,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/product" "github.com/matrixorigin/matrixone/pkg/sql/colexec/top" "github.com/matrixorigin/matrixone/pkg/sql/internal/materialized" + plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/testutil" "github.com/matrixorigin/matrixone/pkg/vm" "github.com/matrixorigin/matrixone/pkg/vm/engine" @@ -644,6 +645,49 @@ func TestParallelRuntimeClonesJoinAllocationAttempt(t *testing.T) { template.Release() } +func TestOrderedTopRuntimeGatherJoinsAllocationAttempt(t *testing.T) { + registry, err := mpool.NewAllocationAccountRegistry(1, 32) + require.NoError(t, err) + c := newTestAllocationLifecycleCompile(t, registry, + func(mpool.AllocationAccountTerminalSnapshot) {}) + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(100) + orderBy := []*plan.OrderBySpec{{Expr: &plan.Expr{ + Expr: &plan.Expr_Col{Col: &plan.ColRef{ColPos: 0}}, + Typ: plan.Type{Id: int32(types.T_int64)}, + }}} + template := top.NewArgument().WithLimit(limitExpr).WithFs(orderBy).WithOrderedOutput() + source := &Scope{ + RootOp: template, + Proc: c.proc, + NodeInfo: engine.Node{ + Mcpu: 2, + }, + } + c.scopes = []*Scope{source} + _, err = c.beginAllocationAccountAttempt() + require.NoError(t, err) + + parallel, workers := newParallelScope(source) + require.Len(t, workers, 2) + require.NoError(t, c.attachRuntimeAllocationOwners([]*Scope{parallel})) + gather := parallel.RootOp.(*mergetop.MergeTop) + require.NoError(t, gather.Prepare(parallel.Proc)) + for _, worker := range workers { + workerTop := worker.RootOp.(*connector.Connector). + GetOperatorBase().GetChildren(0).(*top.Top) + require.NoError(t, workerTop.Prepare(worker.Proc)) + workerTop.Free(worker.Proc, false, nil) + } + for _, reg := range parallel.Proc.Reg.MergeReceivers { + require.True(t, reg.SendEnd()) + } + gather.Free(parallel.Proc, false, nil) + require.NoError(t, c.finishAllocationAccountAttempt()) + + parallel.release() + template.Release() +} + func TestStatementAllocationAttemptOwnerTeardownFailureExportsFailure(t *testing.T) { registry, err := mpool.NewAllocationAccountRegistry(1, 1) require.NoError(t, err) diff --git a/pkg/sql/compile/compile.go b/pkg/sql/compile/compile.go index 51fd6be86abc5..41c1bd70b2409 100644 --- a/pkg/sql/compile/compile.go +++ b/pkg/sql/compile/compile.go @@ -6391,6 +6391,12 @@ func (c *Compile) compileSort(node *plan.Node, ss []*Scope) []*Scope { const mergeTopResidentPlanThreshold uint64 = 8192 * 2 +// Streaming has an extra k-way merge at each CN boundary. Keep the existing +// MergeOrder path while its estimated candidates fit in a few spill windows; +// beyond that point bounded hierarchical merging avoids materializing and +// repeatedly spilling a much larger P*K candidate set. +const distributedTopNStreamingThresholdBytes = 4 * 128 * mpool.MB + // canUseResidentMergeTop limits the resident-only global MergeTop to small, // statically bounded plans. Large or runtime limits use the existing spill-capable // Top and MergeOrder operators instead. @@ -6406,11 +6412,62 @@ func canUseResidentMergeTop(topN *plan.Expr) bool { return ok && value.U64Val <= mergeTopResidentPlanThreshold } +func shouldUseDistributedOrderedTop( + node *plan.Node, + topN *plan.Expr, + ss []*Scope, +) bool { + if topN == nil { + return false + } + if canUseResidentMergeTop(topN) { + return false + } + if node == nil || node.Stats == nil || + node.Stats.Cost <= 0 || node.Stats.Rowsize <= 0 || + math.IsNaN(node.Stats.Cost) || math.IsInf(node.Stats.Cost, 0) || + math.IsNaN(node.Stats.Rowsize) || math.IsInf(node.Stats.Rowsize, 0) { + // Missing or invalid estimates must choose the bounded path. + return true + } + fanout := 0 + for _, scope := range ss { + if scope == nil { + continue + } + fanout += max(1, scope.NodeInfo.Mcpu) + } + if fanout == 0 { + return true + } + candidateRows := node.Stats.Cost + if literal, ok := topN.Expr.(*plan.Expr_Lit); ok && literal.Lit != nil { + if value, ok := literal.Lit.Value.(*plan.Literal_U64Val); ok { + if value.U64Val == 0 { + return false + } + candidateRows = math.Min( + candidateRows, + float64(value.U64Val)*float64(fanout), + ) + } + } + candidateBytes := candidateRows * node.Stats.Rowsize + return math.IsInf(candidateBytes, 0) || + candidateBytes > float64(distributedTopNStreamingThresholdBytes) +} + func (c *Compile) compileTop(node *plan.Node, topN *plan.Expr, ss []*Scope) []*Scope { + useOrderedStreams := supportsDistributedOrderedTop(c.proc.GetService()) && + hasMaterializedTopOrderColumns(node.OrderBy) && + shouldUseDistributedOrderedTop(node, topN, ss) // use topN TO make scope. if c.IsSingleScope(ss) { currentFirstFlag := c.anal.isFirst op := constructTop(node, topN) + if useOrderedStreams { + op.WithOrderedOutput() + } op.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) ss[0].setRootOperator(op) c.anal.isFirst = false @@ -6421,13 +6478,24 @@ func (c *Compile) compileTop(node *plan.Node, topN *plan.Expr, ss []*Scope) []*S for i := range ss { //c.anal.isFirst = currentFirstFlag op := constructTop(node, topN) + if useOrderedStreams { + op.WithOrderedOutput() + } op.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) ss[i].setRootOperator(op) } c.anal.isFirst = false + if useOrderedStreams { + rs := c.newMergeTopScope(node, topN, ss) + c.anal.isFirst = false + return []*Scope{rs} + } + + // During a rolling upgrade an older CN can still interleave its DOP + // workers. Keep the collection-based path until every participant supports + // the ordered-stream boundary. ss = c.mergeShuffleScopesIfNeeded(ss, false) rs := c.newMergeScope(ss) - currentFirstFlag = c.anal.isFirst if canUseResidentMergeTop(topN) { arg := constructMergeTop(node, topN) @@ -6436,12 +6504,10 @@ func (c *Compile) compileTop(node *plan.Node, topN *plan.Expr, ss []*Scope) []*S c.anal.isFirst = false return []*Scope{rs} } - mergeOrder := constructMergeOrder(node) mergeOrder.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) rs.setRootOperator(mergeOrder) c.anal.isFirst = false - globalLimit := constructLimit(&plan.Node{Limit: topN}) globalLimit.SetAnalyzeControl(c.anal.curNodeIdx, c.anal.isFirst) rs.setRootOperator(globalLimit) @@ -6449,6 +6515,21 @@ func (c *Compile) compileTop(node *plan.Node, topN *plan.Expr, ss []*Scope) []*S return []*Scope{rs} } +func hasMaterializedTopOrderColumns(orderBy []*plan.OrderBySpec) bool { + if len(orderBy) == 0 { + return false + } + for _, spec := range orderBy { + if spec == nil || spec.Expr == nil { + return false + } + if _, ok := spec.Expr.Expr.(*plan.Expr_Col); !ok { + return false + } + } + return true +} + func (c *Compile) compileOrder(node *plan.Node, ss []*Scope) []*Scope { if c.IsSingleScope(ss) { currentFirstFlag := c.anal.isFirst @@ -7191,6 +7272,19 @@ func supportsRemoteGroupingSetExpansion(service string) bool { return ok && protocolVersion >= defines.MORPCVersion49 } +func supportsDistributedOrderedTop(service string) bool { + rt := moruntime.ServiceRuntime(service) + if rt == nil { + return false + } + version, ok := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + if !ok { + return false + } + protocolVersion, ok := version.(int64) + return ok && protocolVersion >= defines.MORPCVersion53 +} + func (c *Compile) canCompileShuffleGroup(node *plan.Node) bool { return node.Stats.HashmapStats != nil && node.Stats.HashmapStats.Shuffle && @@ -7974,6 +8068,33 @@ func (c *Compile) newMergeScope(ss []*Scope) *Scope { return rs } +// newMergeTopScope connects one ordered stream from every input scope to a +// leaf MergeTop. Runtime DOP is consolidated inside each input CN before its +// connector writes this edge, so every receiver has exactly one producer. +func (c *Compile) newMergeTopScope(node *plan.Node, topN *plan.Expr, ss []*Scope) *Scope { + rs := c.newEmptyMergeScope() + rs.PreScopes = ss + rs.Proc = c.proc.NewNoContextChildProc(len(ss)) + if len(ss) > 0 { + rs.Proc.Base.LoadTag = ss[0].Proc.Base.LoadTag + } + + arg := constructMergeTop(node, topN).WithOrderedStreams() + c.hasMergeOp = true + arg.SetAnalyzeControl(c.anal.curNodeIdx, c.anal.isFirst) + rs.setRootOperator(arg) + + for i := range ss { + reg := rs.Proc.Reg.MergeReceivers[i] + reg.ResetForReuse(1, 1) + reg.OrderedStream = true + connArg := connector.NewArgument().WithReg(reg) + connArg.SetAnalyzeControl(c.anal.curNodeIdx, false) + ss[i].setRootOperator(connArg) + } + return rs +} + // newScopeListOnSingleWorkerStage builds a single-worker stage. If query // placement already collapsed to one worker, inherit that worker; otherwise // keep the legacy current-CN coordinator for multi-CN stages. diff --git a/pkg/sql/compile/merge_top_fallback_test.go b/pkg/sql/compile/merge_top_fallback_test.go index edb6e7062387f..fda19d1fcdb73 100644 --- a/pkg/sql/compile/merge_top_fallback_test.go +++ b/pkg/sql/compile/merge_top_fallback_test.go @@ -17,6 +17,9 @@ package compile import ( "testing" + "github.com/google/uuid" + "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/colexec" "github.com/matrixorigin/matrixone/pkg/sql/colexec/connector" @@ -26,6 +29,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/top" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/vm/engine" + "github.com/matrixorigin/matrixone/pkg/vm/process" "github.com/stretchr/testify/require" ) @@ -59,22 +63,23 @@ func TestCanUseResidentMergeTop(t *testing.T) { func TestCompileTopRoutesMultiScopeLimits(t *testing.T) { tests := []struct { - name string - limit *plan.Expr - wantMergeTop bool + name string + limit *plan.Expr + ordered bool }{ { - name: "resident threshold", - limit: plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold), - wantMergeTop: true, + name: "resident threshold", + limit: plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold), }, { - name: "large literal", - limit: plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold + 1), + name: "large literal", + limit: plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold + 1), + ordered: true, }, { - name: "dynamic", - limit: &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}}, + name: "dynamic", + limit: &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}}, + ordered: true, }, } @@ -90,19 +95,25 @@ func TestCompileTopRoutesMultiScopeLimits(t *testing.T) { require.True(t, ok) localTop, ok := connectorOp.GetOperatorBase().GetChildren(0).(*top.Top) require.True(t, ok) + require.Equal(t, test.ordered, localTop.OrderedOutput) require.Same(t, test.limit, localTop.Limit) } - if test.wantMergeTop { - globalTop, ok := result[0].RootOp.(*mergetop.MergeTop) - require.True(t, ok) - require.Same(t, test.limit, globalTop.Limit) + globalTop, ok := result[0].RootOp.(*mergetop.MergeTop) + require.True(t, ok) + require.Equal(t, test.ordered, globalTop.OrderedStreams) + if test.ordered { + require.Zero(t, globalTop.GetOperatorBase().NumChildren()) } else { - globalLimit, ok := result[0].RootOp.(*limit.Limit) - require.True(t, ok) - require.Same(t, test.limit, globalLimit.LimitExpr) - _, ok = globalLimit.GetOperatorBase().GetChildren(0).(*mergeorder.MergeOrder) - require.True(t, ok) + require.Equal(t, 1, globalTop.GetOperatorBase().NumChildren()) + } + require.Same(t, test.limit, globalTop.Limit) + for _, reg := range result[0].Proc.Reg.MergeReceivers { + require.Equal(t, test.ordered, reg.OrderedStream) + if test.ordered { + require.Equal(t, 1, reg.NilBatchCnt) + require.Equal(t, 1, cap(reg.Ch2)) + } } result[0].FreeOperator(c) @@ -112,6 +123,44 @@ func TestCompileTopRoutesMultiScopeLimits(t *testing.T) { } } +func TestShouldUseDistributedOrderedTopUsesCandidateBytes(t *testing.T) { + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(500_000) + scopes := []*Scope{{NodeInfo: engine.Node{Mcpu: 16}}} + tests := []struct { + name string + cost float64 + rowSize float64 + expected bool + }{ + {name: "one spill window shape", cost: 1_000_000, rowSize: 146}, + {name: "many spill windows shape", cost: 10_000_000, rowSize: 146, expected: true}, + {name: "missing cardinality is bounded", rowSize: 146, expected: true}, + {name: "missing row size is bounded", cost: 10_000_000, expected: true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + node := &plan.Node{Stats: &plan.Stats{Cost: test.cost, Rowsize: test.rowSize}} + require.Equal(t, test.expected, + shouldUseDistributedOrderedTop(node, limitExpr, scopes)) + }) + } + require.True(t, shouldUseDistributedOrderedTop( + &plan.Node{}, + &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}}, + scopes)) + dynamicLimit := &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}} + require.False(t, shouldUseDistributedOrderedTop( + &plan.Node{Stats: &plan.Stats{Cost: 1_000_000, Rowsize: 146}}, + dynamicLimit, + scopes)) + require.True(t, shouldUseDistributedOrderedTop( + &plan.Node{Stats: &plan.Stats{Cost: 10_000_000, Rowsize: 146}}, + dynamicLimit, + scopes)) + require.False(t, shouldUseDistributedOrderedTop( + &plan.Node{}, plan2.MakePlan2Uint64ConstExprWithType(0), scopes)) +} + func TestCompileTopKeepsSingleScopeLargeLimitLocal(t *testing.T) { c := newMergeTopFallbackTestCompile(t) limitExpr := plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold + 1) @@ -123,6 +172,7 @@ func TestCompileTopKeepsSingleScopeLargeLimitLocal(t *testing.T) { require.Same(t, scope, result[0]) localTop, ok := result[0].RootOp.(*top.Top) require.True(t, ok) + require.True(t, localTop.OrderedOutput) require.Same(t, limitExpr, localTop.Limit) result[0].FreeOperator(c) @@ -130,6 +180,63 @@ func TestCompileTopKeepsSingleScopeLargeLimitLocal(t *testing.T) { c.proc.Free() } +func TestCompileTopFallsBackDuringRollingUpgrade(t *testing.T) { + c := newMergeTopFallbackTestCompile(t) + rt := runtime.ServiceRuntime(c.proc.GetService()) + previous, hadPrevious := rt.GetGlobalVariables(runtime.MOProtocolVersion) + rt.SetGlobalVariables(runtime.MOProtocolVersion, defines.MORPCVersion52) + t.Cleanup(func() { + if hadPrevious { + rt.SetGlobalVariables(runtime.MOProtocolVersion, previous) + } else { + rt.CompareAndDeleteGlobalVariables(runtime.MOProtocolVersion, defines.MORPCVersion52) + } + }) + + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold + 1) + node := newMergeTopFallbackTestNode(limitExpr) + result := c.compileTop(node, limitExpr, newMergeTopFallbackTestScopes(c, 2)) + require.Len(t, result, 1) + globalLimit, ok := result[0].RootOp.(*limit.Limit) + require.True(t, ok) + _, ok = globalLimit.GetOperatorBase().GetChildren(0).(*mergeorder.MergeOrder) + require.True(t, ok) + orderedReg := process.NewPipelineEdge(1, 1) + orderedReg.OrderedStream = true + orderedOutput := connector.NewArgument().WithReg(orderedReg) + _, _, _, _, err := prepareRemoteRunSendingData( + "select 1 order by 1 limit 1", + &Scope{RootOp: orderedOutput, Proc: c.proc}, + c.proc, + nil, + uuid.Nil, + ) + require.Error(t, err) + orderedOutput.Release() + + result[0].FreeOperator(c) + result[0].release() + c.proc.Free() +} + +func TestCompileTopFallsBackWhenOrderKeyIsNotMaterialized(t *testing.T) { + c := newMergeTopFallbackTestCompile(t) + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold + 1) + node := newMergeTopFallbackTestNode(limitExpr) + node.OrderBy[0].Expr = plan2.MakePlan2Int64ConstExprWithType(7) + + result := c.compileTop(node, limitExpr, newMergeTopFallbackTestScopes(c, 2)) + require.Len(t, result, 1) + globalLimit, ok := result[0].RootOp.(*limit.Limit) + require.True(t, ok) + _, ok = globalLimit.GetOperatorBase().GetChildren(0).(*mergeorder.MergeOrder) + require.True(t, ok) + + result[0].FreeOperator(c) + result[0].release() + c.proc.Free() +} + func newMergeTopFallbackTestCompile(t *testing.T) *Compile { c := NewMockCompile(t) c.anal = &AnalyzeModule{curNodeIdx: 1, isFirst: true} diff --git a/pkg/sql/compile/operator.go b/pkg/sql/compile/operator.go index f77cabec42f03..b78aadd5d6425 100644 --- a/pkg/sql/compile/operator.go +++ b/pkg/sql/compile/operator.go @@ -331,6 +331,7 @@ func dupOperatorWithContext(sourceOp vm.Operator, index int, maxParallel int, du t := sourceOp.(*top.Top) op := top.NewArgument() op.Limit = t.Limit + op.OrderedOutput = t.OrderedOutput if t.TopValueTag > 0 { op.TopValueTag = t.TopValueTag + int32(index)<<16 } @@ -362,6 +363,7 @@ func dupOperatorWithContext(sourceOp vm.Operator, index int, maxParallel int, du op := mergetop.NewArgument() op.Limit = t.Limit op.Fs = t.Fs + op.OrderedStreams = t.OrderedStreams op.SetInfo(&info) return op case vm.MergeOrder: diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 9005412771862..ebe7cd540cd25 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -800,6 +800,7 @@ func convertToPipelineInstruction(op vm.Operator, proc *process.Process, ctx *sc case *top.Top: in.Limit = t.Limit in.OrderBy = t.Fs + in.TopOrderedOutput = t.OrderedOutput case *intersect.Intersect: in.SetOp = &pipeline.SetOp{KeyExprs: t.KeyExprs} case *minus.Minus: @@ -1418,9 +1419,13 @@ func convertToVmOperator(opr *pipeline.Instruction, ctx *scopeContext, eng engin arg.IsAssert = opr.FilterIsAssert op = arg case vm.Top: - op = top.NewArgument(). + topArg := top.NewArgument(). WithLimit(opr.Limit). WithFs(opr.OrderBy) + if opr.TopOrderedOutput { + topArg.WithOrderedOutput() + } + op = topArg // should change next day? case vm.Intersect: arg := intersect.NewArgument() diff --git a/pkg/sql/compile/remoterunClient.go b/pkg/sql/compile/remoterunClient.go index 12a232b16a7d4..38371bec672c1 100644 --- a/pkg/sql/compile/remoterunClient.go +++ b/pkg/sql/compile/remoterunClient.go @@ -232,6 +232,12 @@ func prepareRemoteRunSendingData( remoteFragmentCounts map[string]uint32, remoteExecutionID uuid.UUID, ) (scopeData []byte, withoutOutput bool, processData []byte, folded bool, err error) { + if output, ok := s.RootOp.(*connector.Connector); ok && + output.Reg != nil && output.Reg.OrderedStream && + !supportsDistributedOrderedTop(proc.GetService()) { + return nil, false, nil, false, moerr.NewNotSupportedNoCtx( + "distributed ordered Top-N requires MORPC protocol version 53") + } encodedScope, withoutOutput := getScopeForRemoteRunEncoding(s) encodedScope = copyBlockFiltersForRemoteRun(encodedScope) encodedScope, folded, err = foldVarExprsInRemoteRunScope(encodedScope, proc) diff --git a/pkg/sql/compile/remoterun_test.go b/pkg/sql/compile/remoterun_test.go index 30b1068e7a489..8fbc65ac690c9 100644 --- a/pkg/sql/compile/remoterun_test.go +++ b/pkg/sql/compile/remoterun_test.go @@ -531,6 +531,25 @@ func TestRemoteRunOperatorCodecRoundTrip(t *testing.T) { require.True(t, ownsAllocation) }) + t.Run("TopOrderedOutput", func(t *testing.T) { + original := top.NewArgument(). + WithLimit(plan.MakePlan2Uint64ConstExprWithType(17)). + WithFs([]*planpb.OrderBySpec{{ + Expr: &planpb.Expr{ + Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}, + Typ: planpb.Type{Id: int32(types.T_int64)}, + }, + }}). + WithOrderedOutput() + restored := roundTrip(t, original) + defer restored.Release() + restoredTop, ok := restored.(*top.Top) + require.True(t, ok) + require.True(t, restoredTop.OrderedOutput) + require.Equal(t, original.Limit, restoredTop.Limit) + require.Equal(t, original.Fs, restoredTop.Fs) + }) + t.Run("GroupMetadata", func(t *testing.T) { original := group.NewArgument() original.GroupByHashKey = []int32{0, 2} diff --git a/pkg/sql/compile/scope.go b/pkg/sql/compile/scope.go index c7e6bc49697e3..374bd7635ad9d 100644 --- a/pkg/sql/compile/scope.go +++ b/pkg/sql/compile/scope.go @@ -40,11 +40,14 @@ import ( "github.com/matrixorigin/matrixone/pkg/perfcounter" "github.com/matrixorigin/matrixone/pkg/sql/colexec" "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/connector" "github.com/matrixorigin/matrixone/pkg/sql/colexec/dispatch" "github.com/matrixorigin/matrixone/pkg/sql/colexec/filter" "github.com/matrixorigin/matrixone/pkg/sql/colexec/group" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergetop" "github.com/matrixorigin/matrixone/pkg/sql/colexec/output" "github.com/matrixorigin/matrixone/pkg/sql/colexec/table_scan" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/top" "github.com/matrixorigin/matrixone/pkg/sql/colexec/vectorscan" "github.com/matrixorigin/matrixone/pkg/sql/colexec/window" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" @@ -492,7 +495,7 @@ func (s *Scope) MergeRun(c *Compile) (err error) { defer s.ScopeAnalyzer.Stop() // specific case. - if c.IsTpQuery() && !c.hasMergeOp { + if c.IsTpQuery() && !c.hasMergeOp && !s.ConcurrentPreScopes { for i := len(s.PreScopes) - 1; i >= 0; i-- { err := s.PreScopes[i].MergeRun(c) if err != nil { @@ -959,7 +962,7 @@ func buildLoadParallelRun(s *Scope, c *Compile) (*Scope, error) { return nil, err } } - if err := c.attachRuntimeAllocationOwners(ss); err != nil { + if err := c.attachRuntimeAllocationOwners([]*Scope{ms}); err != nil { s.discardParallelGeneration(ms) return nil, err } @@ -1014,7 +1017,7 @@ func buildScanParallelRun(s *Scope, c *Compile) (*Scope, error) { RecvMsgList: recvMsgList, } } - if err := c.attachRuntimeAllocationOwners(ss); err != nil { + if err := c.attachRuntimeAllocationOwners([]*Scope{ms}); err != nil { s.discardParallelGeneration(ms) return nil, err } @@ -1255,6 +1258,9 @@ func newParallelScope(s *Scope) (*Scope, []*Scope) { panic("pipeline end with dispatch should have been merged in multi CN!") } } + if ordered, workers, ok := newOrderedTopParallelScope(s); ok { + return ordered, workers + } // fake scope is used to merge parallel scopes, and do nothing itself rs := newScope(Normal) @@ -1284,6 +1290,87 @@ func newParallelScope(s *Scope) (*Scope, []*Scope) { return rs, parallelScopes } +// newOrderedTopParallelScope preserves the stream boundary required by a +// distributed MergeTop. Each DOP worker first produces an ordered local Top-K +// stream on its own edge; a single leaf MergeTop consolidates those streams +// before anything is returned to another CN or to the coordinator. +func newOrderedTopParallelScope(s *Scope) (*Scope, []*Scope, bool) { + var ( + sourceRoot vm.Operator + externalReg *process.WaitRegister + externalOp *connector.Connector + topOp *top.Top + ) + switch root := s.RootOp.(type) { + case *top.Top: + sourceRoot = root + topOp = root + case *connector.Connector: + if root.Reg == nil || root.Reg.NilBatchCnt != 1 || !root.Reg.OrderedStream { + return nil, nil, false + } + if root.GetOperatorBase().NumChildren() != 1 { + return nil, nil, false + } + child, ok := root.GetOperatorBase().GetChildren(0).(*top.Top) + if !ok { + return nil, nil, false + } + sourceRoot = child + topOp = child + externalReg = root.Reg + externalOp = root + default: + return nil, nil, false + } + if !topOp.OrderedOutput || !hasMaterializedTopOrderColumns(topOp.Fs) { + return nil, nil, false + } + + workerCount := s.NodeInfo.Mcpu + gather := newScope(Merge) + gather.ConcurrentPreScopes = true + gather.NodeInfo = s.NodeInfo + gather.NodeInfo.Mcpu = 1 + gather.Proc = s.Proc.NewContextChildProc(workerCount) + gather.TxnOffset = s.TxnOffset + + workers := make([]*Scope, workerCount) + dupCtx := newOperatorDupContext() + for i := 0; i < workerCount; i++ { + reg := gather.Proc.Reg.MergeReceivers[i] + reg.ResetForReuse(1, 1) + reg.OrderedStream = true + worker := newScope(Normal) + worker.NodeInfo = s.NodeInfo + worker.NodeInfo.Mcpu = 1 + worker.Proc = gather.Proc.NewContextChildProc(0) + worker.TxnOffset = s.TxnOffset + workerRoot := dupOperatorRecursivelyWithContext( + sourceRoot, i, workerCount, dupCtx) + conn := connector.NewArgument().WithReg(reg) + conn.SetAnalyzeControl(topOp.GetIdx(), false) + conn.AppendChild(workerRoot) + worker.setRootOperator(conn) + workers[i] = worker + } + + gatherTop := mergetop.NewArgument().WithLimit(topOp.Limit).WithFs(topOp.Fs).WithOrderedStreams() + gatherTop.SetAnalyzeControl(topOp.GetIdx(), false) + if externalReg == nil { + gather.setRootOperator(gatherTop) + } else { + out := connector.NewArgument().WithReg(externalReg) + out.SetAnalyzeControl(externalOp.GetIdx(), false) + out.AppendChild(gatherTop) + gather.setRootOperator(out) + } + gather.PreScopes = workers + s.PreScopes = append(s.PreScopes, gather) + s.parallelGenerations = append(s.parallelGenerations, gather) + return gather, workers, true +} + func (s *Scope) doSetRootOperator(op vm.Operator) { if s.RootOp != nil { op.AppendChild(s.RootOp) diff --git a/pkg/sql/compile/scope_test.go b/pkg/sql/compile/scope_test.go index b18fb1357d1b2..140a376dc9f04 100644 --- a/pkg/sql/compile/scope_test.go +++ b/pkg/sql/compile/scope_test.go @@ -776,6 +776,57 @@ func TestNewParallelScope(t *testing.T) { } } +func TestNewParallelScopeConsolidatesOrderedTopStreams(t *testing.T) { + c := NewMockCompile(t) + external := process.NewPipelineEdge(1, 1) + external.OrderedStream = true + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(100000) + orderBy := []*plan.OrderBySpec{{ + Expr: &plan.Expr{ + Expr: &plan.Expr_Col{Col: &plan.ColRef{ColPos: 0}}, + Typ: plan.Type{Id: int32(types.T_int64)}, + }, + }} + localTop := top.NewArgument().WithLimit(limitExpr).WithFs(orderBy).WithOrderedOutput() + localTop.AppendChild(table_scan.NewArgument()) + out := connector.NewArgument().WithReg(external) + out.AppendChild(localTop) + s := &Scope{ + Magic: Normal, + NodeInfo: engine.Node{Mcpu: 4}, + Proc: c.proc, + RootOp: out, + } + + ordered, workers := newParallelScope(s) + require.Equal(t, Merge, ordered.Magic) + require.True(t, ordered.ConcurrentPreScopes) + require.Equal(t, 1, ordered.NodeInfo.Mcpu) + require.Len(t, workers, 4) + require.Len(t, ordered.PreScopes, 4) + require.Len(t, ordered.Proc.Reg.MergeReceivers, 4) + + orderedOut, ok := ordered.RootOp.(*connector.Connector) + require.True(t, ok) + require.Same(t, external, orderedOut.Reg) + globalTop, ok := orderedOut.GetOperatorBase().GetChildren(0).(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, globalTop.OrderedStreams) + require.Same(t, limitExpr, globalTop.Limit) + for i, worker := range workers { + workerOut, ok := worker.RootOp.(*connector.Connector) + require.True(t, ok) + require.Same(t, ordered.Proc.Reg.MergeReceivers[i], workerOut.Reg) + require.Equal(t, 1, workerOut.Reg.NilBatchCnt) + require.True(t, workerOut.Reg.OrderedStream) + _, ok = workerOut.GetOperatorBase().GetChildren(0).(*top.Top) + require.True(t, ok) + } + + s.release() + c.proc.Free() +} + func TestParallelScopeGenerationsReleasedAtCompileResetBoundary(t *testing.T) { testCompile := NewMockCompile(t) testCompile.isPrepare = true diff --git a/pkg/sql/compile/types.go b/pkg/sql/compile/types.go index 6f6171acbf81b..03830328d848f 100644 --- a/pkg/sql/compile/types.go +++ b/pkg/sql/compile/types.go @@ -199,6 +199,10 @@ type Scope struct { // branch receiver is exhausted, so an outer LIMIT can leave later branches // completely unstarted. LazyPreScopes bool + // ConcurrentPreScopes forces producer/consumer concurrency for runtime + // scope trees whose bounded receiver channels would deadlock under the TP + // query's sequential fast path. + ConcurrentPreScopes bool // parallelGenerations are execution-created scope trees retained only so // post-run physical-plan analysis can observe their real DOP and stats. // Compile.Reset releases the previous execution's trees before the template diff --git a/pkg/vm/process/pipeline_edge.go b/pkg/vm/process/pipeline_edge.go index b59d1f29e134a..fed3167e30141 100644 --- a/pkg/vm/process/pipeline_edge.go +++ b/pkg/vm/process/pipeline_edge.go @@ -43,6 +43,11 @@ type PipelineEdge struct { // channel must receive before it is considered done. 0 defaults to 1. NilBatchCnt int + // OrderedStream marks an edge whose single producer must preserve total + // ordering across batch boundaries. It is compile/runtime topology metadata, + // not a data signal property. + OrderedStream bool + // --- terminal state --- done chan struct{} abrt chan struct{} @@ -104,6 +109,7 @@ func (e *PipelineEdge) ResetForReuse(channelBufferSize int, nilBatchCnt int) { done: e.Ch2 = make(chan PipelineSignal, channelBufferSize) e.NilBatchCnt = nilBatchCnt + e.OrderedStream = false e.resetTerminalStateLocked() } diff --git a/pkg/vm/process/pipeline_edge_test.go b/pkg/vm/process/pipeline_edge_test.go index 0233b0cbc4cf9..e70bde8ad38c0 100644 --- a/pkg/vm/process/pipeline_edge_test.go +++ b/pkg/vm/process/pipeline_edge_test.go @@ -145,6 +145,15 @@ func TestWaitPipelineSignalCapacityWaitsUntilChannelDrains(t *testing.T) { } } +func TestPipelineEdgeResetClearsOrderedStreamContract(t *testing.T) { + edge := NewPipelineEdge(1, 1) + edge.OrderedStream = true + edge.ResetForReuse(2, 2) + if edge.OrderedStream { + t.Fatal("ResetForReuse retained a stale ordered-stream contract") + } +} + func TestWaitPipelineSignalCapacityReturnsOnContextCancel(t *testing.T) { edge := NewPipelineEdge(1, 1) edge.Ch2 <- NewPipelineSignalToDirectly(nil, nil, nil) diff --git a/proto/pipeline.proto b/proto/pipeline.proto index 03f252095ba3f..4b0665be92173 100644 --- a/proto/pipeline.proto +++ b/proto/pipeline.proto @@ -644,6 +644,9 @@ message Instruction { // gated by MORPCVersion49 until every participant understands them. repeated bool projection_grouping_flags = 60; int32 projection_grouping_set_count = 61; + // TOP only: every runtime worker must be consolidated into one stream that + // remains ordered across batch boundaries before leaving its CN. + bool top_ordered_output = 62; } message AnalysisList { From f735bbc92ae8bc65b4d5188050a952cd8a7f3c33 Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 02:53:51 +0800 Subject: [PATCH 2/7] fix: preserve ordered top across remote CN groups --- docs/design/bounded_distributed_topn.md | 4 +- pkg/pb/pipeline/pipeline.pb.go | 1279 +++++++++-------- pkg/sql/compile/compile.go | 81 +- pkg/sql/compile/merge_scope_placement_test.go | 87 ++ pkg/sql/compile/merge_top_fallback_test.go | 15 + pkg/sql/compile/remoterun.go | 61 +- pkg/sql/compile/remoterun_test.go | 145 ++ proto/pipeline.proto | 6 + 8 files changed, 1103 insertions(+), 575 deletions(-) diff --git a/docs/design/bounded_distributed_topn.md b/docs/design/bounded_distributed_topn.md index b0c2c31b410b1..31beda25e505a 100644 --- a/docs/design/bounded_distributed_topn.md +++ b/docs/design/bounded_distributed_topn.md @@ -104,8 +104,8 @@ transport, accounting, and cleanup contracts. See the Implementation v1 uses the following deliberately narrow activation contract: -- protocol version 53 and the serialized `Top.top_ordered_output` bit prove - that every participating CN understands the boundary; +- protocol version 53 plus serialized Top output, MergeTop input, and receiver + edge bits prove that every participating CN understands the boundary; - the planner activates it only when every ORDER BY key is already a materialized input column. Non-column expressions retain the compatible MergeTop or MergeOrder plan until hidden-key materialization is implemented, so a diff --git a/pkg/pb/pipeline/pipeline.pb.go b/pkg/pb/pipeline/pipeline.pb.go index 8ba733b3c65d2..769befbaed6b2 100644 --- a/pkg/pb/pipeline/pipeline.pb.go +++ b/pkg/pb/pipeline/pipeline.pb.go @@ -4845,10 +4845,13 @@ type Instruction struct { ProjectionGroupingSetCount int32 `protobuf:"varint,61,opt,name=projection_grouping_set_count,json=projectionGroupingSetCount,proto3" json:"projection_grouping_set_count,omitempty"` // TOP only: every runtime worker must be consolidated into one stream that // remains ordered across batch boundaries before leaving its CN. - TopOrderedOutput bool `protobuf:"varint,62,opt,name=top_ordered_output,json=topOrderedOutput,proto3" json:"top_ordered_output,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + TopOrderedOutput bool `protobuf:"varint,62,opt,name=top_ordered_output,json=topOrderedOutput,proto3" json:"top_ordered_output,omitempty"` + // MERGE_TOP only: consume one independently ordered stream from every + // receiver. This is serialized for per-CN ordered gathers sent by RemoteRun. + MergeTopOrderedStreams bool `protobuf:"varint,63,opt,name=merge_top_ordered_streams,json=mergeTopOrderedStreams,proto3" json:"merge_top_ordered_streams,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Instruction) Reset() { *m = Instruction{} } @@ -5261,6 +5264,13 @@ func (m *Instruction) GetTopOrderedOutput() bool { return false } +func (m *Instruction) GetMergeTopOrderedStreams() bool { + if m != nil { + return m.MergeTopOrderedStreams + } + return false +} + type AnalysisList struct { List []*plan.AnalyzeInfo `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -6136,23 +6146,26 @@ func (m *SessionLoggerInfo) GetLogLevel() SessionLoggerInfo_LogLevel { } type Pipeline struct { - PipelineType Pipeline_PipelineType `protobuf:"varint,1,opt,name=pipeline_type,json=pipelineType,proto3,enum=pipeline.Pipeline_PipelineType" json:"pipeline_type,omitempty"` - PipelineId int32 `protobuf:"varint,2,opt,name=pipeline_id,json=pipelineId,proto3" json:"pipeline_id,omitempty"` - Qry *plan.Plan `protobuf:"bytes,3,opt,name=qry,proto3" json:"qry,omitempty"` - DataSource *Source `protobuf:"bytes,4,opt,name=data_source,json=dataSource,proto3" json:"data_source,omitempty"` - Children []*Pipeline `protobuf:"bytes,5,rep,name=children,proto3" json:"children,omitempty"` - InstructionList []*Instruction `protobuf:"bytes,6,rep,name=instruction_list,json=instructionList,proto3" json:"instruction_list,omitempty"` - IsEnd bool `protobuf:"varint,7,opt,name=is_end,json=isEnd,proto3" json:"is_end,omitempty"` - IsLoad bool `protobuf:"varint,8,opt,name=is_load,json=isLoad,proto3" json:"is_load,omitempty"` - Node *NodeInfo `protobuf:"bytes,9,opt,name=node,proto3" json:"node,omitempty"` - PushDownInfo int32 `protobuf:"varint,10,opt,name=push_down_info,json=pushDownInfo,proto3" json:"push_down_info,omitempty"` - ChildrenCount int32 `protobuf:"varint,11,opt,name=children_count,json=childrenCount,proto3" json:"children_count,omitempty"` - ChannelBufferSize []int32 `protobuf:"varint,12,rep,packed,name=channel_buffer_size,json=channelBufferSize,proto3" json:"channel_buffer_size,omitempty"` - NilBatchCnt []int32 `protobuf:"varint,13,rep,packed,name=nil_batch_cnt,json=nilBatchCnt,proto3" json:"nil_batch_cnt,omitempty"` - UuidsToRegIdx []*UuidToRegIdx `protobuf:"bytes,14,rep,name=uuids_to_reg_idx,json=uuidsToRegIdx,proto3" json:"uuids_to_reg_idx,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + PipelineType Pipeline_PipelineType `protobuf:"varint,1,opt,name=pipeline_type,json=pipelineType,proto3,enum=pipeline.Pipeline_PipelineType" json:"pipeline_type,omitempty"` + PipelineId int32 `protobuf:"varint,2,opt,name=pipeline_id,json=pipelineId,proto3" json:"pipeline_id,omitempty"` + Qry *plan.Plan `protobuf:"bytes,3,opt,name=qry,proto3" json:"qry,omitempty"` + DataSource *Source `protobuf:"bytes,4,opt,name=data_source,json=dataSource,proto3" json:"data_source,omitempty"` + Children []*Pipeline `protobuf:"bytes,5,rep,name=children,proto3" json:"children,omitempty"` + InstructionList []*Instruction `protobuf:"bytes,6,rep,name=instruction_list,json=instructionList,proto3" json:"instruction_list,omitempty"` + IsEnd bool `protobuf:"varint,7,opt,name=is_end,json=isEnd,proto3" json:"is_end,omitempty"` + IsLoad bool `protobuf:"varint,8,opt,name=is_load,json=isLoad,proto3" json:"is_load,omitempty"` + Node *NodeInfo `protobuf:"bytes,9,opt,name=node,proto3" json:"node,omitempty"` + PushDownInfo int32 `protobuf:"varint,10,opt,name=push_down_info,json=pushDownInfo,proto3" json:"push_down_info,omitempty"` + ChildrenCount int32 `protobuf:"varint,11,opt,name=children_count,json=childrenCount,proto3" json:"children_count,omitempty"` + ChannelBufferSize []int32 `protobuf:"varint,12,rep,packed,name=channel_buffer_size,json=channelBufferSize,proto3" json:"channel_buffer_size,omitempty"` + NilBatchCnt []int32 `protobuf:"varint,13,rep,packed,name=nil_batch_cnt,json=nilBatchCnt,proto3" json:"nil_batch_cnt,omitempty"` + UuidsToRegIdx []*UuidToRegIdx `protobuf:"bytes,14,rep,name=uuids_to_reg_idx,json=uuidsToRegIdx,proto3" json:"uuids_to_reg_idx,omitempty"` + // Per receiver, preserve the single-producer ordered-stream contract across + // RemoteRun. Empty means the legacy unordered default. + OrderedStream []bool `protobuf:"varint,15,rep,packed,name=ordered_stream,json=orderedStream,proto3" json:"ordered_stream,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Pipeline) Reset() { *m = Pipeline{} } @@ -6285,6 +6298,13 @@ func (m *Pipeline) GetUuidsToRegIdx() []*UuidToRegIdx { return nil } +func (m *Pipeline) GetOrderedStream() []bool { + if m != nil { + return m.OrderedStream + } + return nil +} + type WrapNode struct { NodeAddr string `protobuf:"bytes,1,opt,name=node_addr,json=nodeAddr,proto3" json:"node_addr,omitempty"` Uuid []byte `protobuf:"bytes,2,opt,name=uuid,proto3" json:"uuid,omitempty"` @@ -6627,553 +6647,555 @@ func init() { func init() { proto.RegisterFile("pipeline.proto", fileDescriptor_7ac67a7adf3df9c7) } var fileDescriptor_7ac67a7adf3df9c7 = []byte{ - // 8726 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7c, 0x4b, 0x6c, 0x1d, 0x47, - 0xb6, 0x98, 0x2f, 0xc9, 0xfb, 0x3b, 0xf7, 0xcb, 0x22, 0x45, 0x5d, 0x7d, 0x6c, 0xd1, 0xd7, 0x96, - 0x4c, 0xcb, 0x32, 0x25, 0xd3, 0xf6, 0x8c, 0xc7, 0x33, 0x1e, 0x3f, 0x8a, 0x92, 0x6c, 0x8e, 0x45, - 0x89, 0xd3, 0xa4, 0x9e, 0x01, 0x03, 0x49, 0xa3, 0xd9, 0x5d, 0xf7, 0xb2, 0xcd, 0xbe, 0xdd, 0xad, - 0xae, 0x6e, 0x89, 0xd4, 0x2a, 0x59, 0x26, 0xc8, 0x3e, 0x0f, 0x59, 0x4d, 0x90, 0x2c, 0x5e, 0x90, - 0x65, 0x30, 0x59, 0x66, 0xfd, 0x10, 0x64, 0x31, 0xab, 0x2c, 0x83, 0x60, 0x66, 0x19, 0x20, 0x09, - 0x02, 0x24, 0x08, 0x10, 0x3c, 0x20, 0x38, 0xe7, 0x54, 0x75, 0xf7, 0xbd, 0xbc, 0x92, 0x6c, 0x27, - 0x78, 0x9b, 0xf7, 0x76, 0xdd, 0xe7, 0x9c, 0xaa, 0xae, 0xae, 0x3a, 0xdf, 0x3a, 0xa7, 0x0a, 0xba, - 0xb1, 0x1f, 0xcb, 0xc0, 0x0f, 0xe5, 0x66, 0x9c, 0x44, 0x69, 0x24, 0x1a, 0xe6, 0xfd, 0xf2, 0x87, - 0x63, 0x3f, 0x3d, 0xce, 0x8e, 0x36, 0xdd, 0x68, 0x72, 0x7b, 0x1c, 0x8d, 0xa3, 0xdb, 0x44, 0x70, - 0x94, 0x8d, 0xe8, 0x8d, 0x5e, 0xe8, 0x89, 0x1b, 0x5e, 0x86, 0x20, 0x72, 0x4f, 0xcc, 0x73, 0x1c, - 0x38, 0xa1, 0x7e, 0xee, 0xa5, 0xfe, 0x44, 0xaa, 0xd4, 0x99, 0xc4, 0x1a, 0xd0, 0x4c, 0x4f, 0x35, - 0x6e, 0xf8, 0xbb, 0x1a, 0xd4, 0xf7, 0xa4, 0x52, 0xce, 0x58, 0x8a, 0x21, 0x2c, 0x2a, 0xdf, 0x1b, - 0x54, 0xd6, 0x2b, 0x1b, 0xdd, 0xad, 0xfe, 0x66, 0x3e, 0xac, 0x83, 0xd4, 0x49, 0x33, 0x65, 0x21, - 0x12, 0x69, 0xdc, 0x89, 0x37, 0x58, 0x98, 0xa5, 0xd9, 0x93, 0xe9, 0x71, 0xe4, 0x59, 0x88, 0x14, - 0x7d, 0x58, 0x94, 0x49, 0x32, 0x58, 0x5c, 0xaf, 0x6c, 0xb4, 0x2d, 0x7c, 0x14, 0x02, 0x96, 0x3c, - 0x27, 0x75, 0x06, 0x4b, 0x04, 0xa2, 0x67, 0xf1, 0x2e, 0x74, 0xe3, 0x24, 0x72, 0x6d, 0x3f, 0x1c, - 0x45, 0x36, 0x61, 0xab, 0x84, 0x6d, 0x23, 0x74, 0x37, 0x1c, 0x45, 0xf7, 0x90, 0x6a, 0x00, 0x75, - 0x27, 0x74, 0x82, 0x33, 0x25, 0x07, 0x35, 0x42, 0x9b, 0x57, 0xd1, 0x85, 0x05, 0xdf, 0x1b, 0xd4, - 0xd7, 0x2b, 0x1b, 0x4b, 0xd6, 0x82, 0xef, 0xe1, 0x37, 0xb2, 0xcc, 0xf7, 0x06, 0x0d, 0xfe, 0x06, - 0x3e, 0x8b, 0x21, 0xb4, 0x43, 0x29, 0xbd, 0x47, 0x51, 0x6a, 0xc9, 0x38, 0x38, 0x1b, 0x34, 0xd7, - 0x2b, 0x1b, 0x0d, 0x6b, 0x0a, 0x26, 0x2e, 0x43, 0xc3, 0x93, 0x47, 0xd9, 0x78, 0x4f, 0x8d, 0x07, - 0xb0, 0x5e, 0xd9, 0x68, 0x5a, 0xf9, 0xbb, 0x38, 0x84, 0x8b, 0x89, 0x7c, 0x9a, 0x49, 0x95, 0x4a, - 0xcf, 0x4e, 0xa5, 0x93, 0x78, 0xd1, 0xf3, 0xd0, 0x9e, 0x44, 0x9e, 0x1c, 0xb4, 0x68, 0x06, 0xae, - 0x96, 0x67, 0x29, 0x91, 0xce, 0xe4, 0x50, 0x13, 0xed, 0x45, 0x9e, 0xb4, 0x2e, 0xe4, 0x8d, 0xcb, - 0x60, 0x61, 0xc1, 0x9a, 0xe3, 0xba, 0x32, 0x3e, 0xdf, 0x69, 0xfb, 0x07, 0x74, 0xba, 0x6a, 0xda, - 0x4e, 0xf5, 0xf9, 0x25, 0x5c, 0x2d, 0x46, 0x7a, 0xe4, 0xa4, 0xee, 0xb1, 0xed, 0x26, 0xd2, 0xf3, - 0x53, 0xdb, 0x8d, 0xb2, 0x30, 0x1d, 0x74, 0xd6, 0x2b, 0x1b, 0x1d, 0xeb, 0x52, 0x4e, 0x73, 0x17, - 0x49, 0x76, 0x88, 0x62, 0x07, 0x09, 0x5e, 0xd1, 0xc1, 0xd1, 0x59, 0x2a, 0xd5, 0xa0, 0x4b, 0x13, - 0x3d, 0xb7, 0x83, 0xbb, 0x48, 0x20, 0xbe, 0x80, 0x2b, 0xf9, 0x5f, 0xcd, 0x19, 0x40, 0x8f, 0x06, - 0x30, 0x30, 0x24, 0xe7, 0xbe, 0xff, 0xd2, 0xe6, 0xfc, 0xf9, 0x3e, 0x7d, 0x7e, 0x5e, 0x73, 0xfe, - 0xfa, 0x75, 0xe8, 0x72, 0x2b, 0x85, 0x03, 0x0c, 0x5d, 0x39, 0x58, 0xa6, 0x16, 0x1d, 0x82, 0x1e, - 0x68, 0xa0, 0xb8, 0x05, 0x82, 0xc9, 0x1c, 0xf7, 0xa4, 0x20, 0x15, 0x44, 0xda, 0x27, 0xcc, 0xb6, - 0x7b, 0x62, 0xa8, 0x3f, 0x5f, 0xfa, 0x8b, 0xdf, 0x5d, 0x7b, 0x63, 0xf8, 0x04, 0x9a, 0x3b, 0x51, - 0x18, 0x4a, 0x37, 0x8d, 0x12, 0x71, 0x0d, 0x5a, 0x66, 0x71, 0x6c, 0x2d, 0x2b, 0x55, 0x0b, 0x0c, - 0x68, 0xd7, 0x13, 0xef, 0x41, 0xcf, 0x35, 0xd4, 0xb6, 0x1f, 0x7a, 0xf2, 0x94, 0x84, 0xa5, 0x6a, - 0x75, 0x73, 0xf0, 0x2e, 0x42, 0x87, 0xff, 0x75, 0x11, 0xea, 0x07, 0xc7, 0xd9, 0x68, 0x14, 0x48, - 0xf1, 0x2e, 0x74, 0xf4, 0xe3, 0x4e, 0x14, 0xec, 0x7a, 0xa7, 0xba, 0xdf, 0x69, 0xa0, 0x58, 0x87, - 0x96, 0x06, 0x1c, 0x9e, 0xc5, 0x52, 0x77, 0x5b, 0x06, 0x4d, 0xf7, 0xb3, 0xe7, 0x87, 0x24, 0x83, - 0x8b, 0xd6, 0x34, 0x70, 0x86, 0xca, 0x39, 0x25, 0xb1, 0x9c, 0xa6, 0x72, 0xe8, 0x6b, 0xdb, 0x81, - 0xff, 0x4c, 0x5a, 0x72, 0xbc, 0x13, 0xa6, 0x24, 0x9c, 0x55, 0xab, 0x0c, 0x12, 0x5b, 0x70, 0x41, - 0x71, 0x13, 0x3b, 0x71, 0xc2, 0xb1, 0x54, 0x76, 0xe6, 0x87, 0xe9, 0xcf, 0x3e, 0x19, 0xd4, 0xd6, - 0x17, 0x37, 0x96, 0xac, 0x15, 0x8d, 0xb4, 0x08, 0xf7, 0x84, 0x50, 0xe2, 0x0e, 0xac, 0xce, 0xb4, - 0xe1, 0x26, 0xf5, 0xf5, 0xc5, 0x8d, 0x45, 0x4b, 0x4c, 0x35, 0xd9, 0xa5, 0x16, 0xf7, 0x61, 0x39, - 0xc9, 0x42, 0x54, 0x61, 0x0f, 0xfc, 0x20, 0x95, 0xc9, 0x41, 0x2c, 0x5d, 0x12, 0xf2, 0xd6, 0xd6, - 0xc5, 0x4d, 0xd2, 0x72, 0xd6, 0x2c, 0xda, 0x3a, 0xdf, 0x42, 0xdc, 0xca, 0x27, 0xef, 0xfe, 0x69, - 0x9c, 0x90, 0x26, 0x68, 0x6d, 0x01, 0x77, 0x80, 0x10, 0xab, 0x8c, 0x16, 0x37, 0x61, 0xd9, 0x4b, - 0x1c, 0x3f, 0xb4, 0x9d, 0x20, 0xb0, 0x8f, 0x32, 0xf7, 0x44, 0xa6, 0x8a, 0xb4, 0x43, 0xc3, 0xea, - 0x11, 0x62, 0x3b, 0x08, 0xee, 0x32, 0x58, 0xdc, 0x80, 0x9e, 0x4a, 0x13, 0x3f, 0x1c, 0xdb, 0xc7, - 0x8e, 0x3a, 0xb6, 0x4f, 0xe4, 0x19, 0x29, 0x87, 0x86, 0xd5, 0x61, 0xf0, 0xd7, 0x8e, 0x3a, 0xfe, - 0x46, 0x9e, 0x0d, 0xff, 0xf7, 0x02, 0x34, 0xee, 0xf9, 0x2a, 0x46, 0x2e, 0x13, 0x17, 0xa1, 0x3e, - 0xca, 0x42, 0xb7, 0xe0, 0xa1, 0x1a, 0xbe, 0xee, 0x7a, 0xe2, 0x57, 0xd0, 0x0b, 0x22, 0xd7, 0x09, - 0xec, 0x9c, 0x5d, 0x06, 0x0b, 0xeb, 0x8b, 0x1b, 0xad, 0xad, 0x95, 0x42, 0x2b, 0xe4, 0xec, 0x68, - 0x75, 0x89, 0xb6, 0x60, 0xcf, 0x2f, 0xa0, 0x9f, 0xc8, 0x49, 0x94, 0xca, 0x52, 0xf3, 0x45, 0x6a, - 0x2e, 0x8a, 0xe6, 0xdf, 0x26, 0x4e, 0xfc, 0x08, 0x55, 0x49, 0x8f, 0x69, 0x8b, 0xe6, 0x1f, 0x95, - 0x56, 0x54, 0x8e, 0x6d, 0xdf, 0x3b, 0xb5, 0xe9, 0x03, 0x83, 0xa5, 0xf5, 0xc5, 0x8d, 0x6a, 0xb1, - 0x3c, 0x72, 0xbc, 0xeb, 0x9d, 0x3e, 0x44, 0x8c, 0xf8, 0x18, 0xd6, 0x66, 0x9b, 0x70, 0xaf, 0x83, - 0x2a, 0xb5, 0x59, 0x99, 0x6a, 0x63, 0x11, 0x4a, 0xbc, 0x0d, 0x6d, 0xd3, 0x28, 0x45, 0x56, 0xae, - 0x31, 0x73, 0xa9, 0x12, 0x2b, 0x5f, 0x84, 0xba, 0xaf, 0x6c, 0xe5, 0x87, 0x27, 0xa4, 0xe3, 0x1b, - 0x56, 0xcd, 0x57, 0x07, 0x7e, 0x78, 0x22, 0x2e, 0x41, 0x23, 0x91, 0x2e, 0x63, 0x1a, 0x84, 0xa9, - 0x27, 0xd2, 0x25, 0xd4, 0x45, 0xc0, 0x47, 0xdb, 0x4d, 0xa5, 0xd6, 0xf4, 0xb5, 0x44, 0xba, 0x3b, - 0xa9, 0x1c, 0x2a, 0xa8, 0xee, 0xc9, 0x64, 0x2c, 0x51, 0xd9, 0x63, 0xc3, 0x03, 0xd7, 0x09, 0x69, - 0xde, 0x1b, 0x56, 0xfe, 0x8e, 0xa6, 0x26, 0x76, 0x92, 0xd4, 0x77, 0x02, 0x12, 0xad, 0x86, 0x65, - 0x5e, 0xc5, 0x15, 0x68, 0xaa, 0xd4, 0x49, 0x52, 0xfc, 0x3b, 0x12, 0xa9, 0xaa, 0xd5, 0x20, 0x00, - 0x4a, 0xe5, 0x45, 0xa8, 0xcb, 0xd0, 0x23, 0xd4, 0x12, 0xaf, 0xa4, 0x0c, 0xbd, 0x5d, 0xef, 0x74, - 0xf8, 0x6f, 0x2a, 0xd0, 0xd9, 0xcb, 0x82, 0xd4, 0xdf, 0x4e, 0xc6, 0x99, 0x9c, 0x84, 0x29, 0x9a, - 0xa8, 0x7b, 0xbe, 0x4a, 0xf5, 0x97, 0xe9, 0x59, 0x6c, 0x40, 0xf3, 0xab, 0x24, 0xca, 0x62, 0xe2, - 0x4a, 0x5e, 0xe9, 0x32, 0x57, 0x16, 0x48, 0xe4, 0xe0, 0xc7, 0x89, 0x27, 0x93, 0xbb, 0x67, 0x44, - 0xbb, 0x78, 0x8e, 0xb6, 0x8c, 0x16, 0x57, 0xa1, 0x79, 0x20, 0x63, 0x27, 0x71, 0x90, 0x05, 0x96, - 0xc8, 0xae, 0x15, 0x00, 0xfc, 0x57, 0x22, 0xde, 0xf5, 0xb4, 0x60, 0x9b, 0xd7, 0xe1, 0xbf, 0xa8, - 0x40, 0x73, 0x7b, 0x3c, 0x4e, 0xe4, 0xd8, 0x49, 0xc9, 0xc8, 0x46, 0x31, 0x8d, 0x77, 0xd1, 0x5a, - 0x88, 0x62, 0x32, 0xe4, 0xf8, 0x07, 0x3c, 0x41, 0xf4, 0x2c, 0xde, 0x82, 0x25, 0x39, 0x7f, 0x40, - 0x04, 0x17, 0x6b, 0x50, 0x73, 0xa3, 0x70, 0xe4, 0x8f, 0xb5, 0xf9, 0xd7, 0x6f, 0xe2, 0x73, 0x68, - 0xf1, 0x13, 0xf3, 0x40, 0x95, 0x6c, 0xdf, 0x25, 0x6e, 0x9e, 0x8f, 0x60, 0x87, 0x28, 0x90, 0x23, - 0x2c, 0x70, 0xf3, 0xe7, 0xe1, 0x9f, 0x96, 0xa0, 0x4a, 0x33, 0x83, 0x6b, 0x83, 0xe6, 0xdc, 0x96, - 0xcf, 0x9c, 0xc0, 0x2c, 0x29, 0x02, 0xee, 0x3f, 0x73, 0x02, 0xb1, 0x0e, 0x55, 0x1c, 0x82, 0x9a, - 0x33, 0xb1, 0x8c, 0x10, 0x37, 0xa0, 0x8a, 0x5f, 0x57, 0xd3, 0xa3, 0xc7, 0x6f, 0xdc, 0x5d, 0xfa, - 0xab, 0xff, 0x74, 0xed, 0x0d, 0x8b, 0xd1, 0xe2, 0x3d, 0x58, 0x72, 0xc6, 0x63, 0x45, 0x82, 0x30, - 0x25, 0x8b, 0xf9, 0x48, 0x2d, 0x22, 0x10, 0x9f, 0x42, 0x93, 0x17, 0x1d, 0xa9, 0xab, 0x44, 0x7d, - 0xb1, 0xe4, 0x26, 0x95, 0xf9, 0xc1, 0x2a, 0x28, 0x71, 0xb9, 0x7c, 0xa5, 0x35, 0x10, 0x89, 0x43, - 0xc3, 0x2a, 0x00, 0xe8, 0xc7, 0xc4, 0x89, 0xdc, 0x0e, 0x82, 0xc8, 0x3d, 0xf0, 0x5f, 0x48, 0xed, - 0xf5, 0x4c, 0xc1, 0xc4, 0x0d, 0xe8, 0xee, 0x33, 0xbf, 0x5a, 0x52, 0x65, 0x41, 0xaa, 0xb4, 0x27, - 0x34, 0x03, 0x15, 0x9b, 0x20, 0xa6, 0x20, 0x87, 0xf4, 0xfb, 0xcd, 0xf5, 0xc5, 0x8d, 0x8e, 0x35, - 0x07, 0x23, 0xde, 0x81, 0xce, 0x18, 0x67, 0x1a, 0x15, 0xdc, 0x28, 0x70, 0xd0, 0x49, 0x5a, 0x44, - 0x27, 0xca, 0x00, 0x1f, 0x04, 0xce, 0x98, 0x24, 0x24, 0xf6, 0x83, 0xc0, 0x9e, 0xc8, 0x09, 0x69, - 0xbf, 0x45, 0xab, 0x41, 0x80, 0x3d, 0x39, 0x11, 0xef, 0xc3, 0x32, 0x11, 0xdb, 0x47, 0x67, 0x85, - 0x8a, 0x6c, 0x93, 0x76, 0xe8, 0x12, 0xe2, 0xee, 0x99, 0xd6, 0x91, 0xe2, 0x7d, 0xe8, 0x7b, 0x67, - 0xa1, 0x33, 0xf1, 0x5d, 0xdb, 0xf4, 0x4f, 0xae, 0x0b, 0xaa, 0x5d, 0x86, 0x7f, 0xa5, 0xc1, 0xa8, - 0x78, 0xe4, 0x24, 0x4e, 0xcf, 0x72, 0x42, 0x5b, 0x49, 0x94, 0x50, 0x74, 0x55, 0xd0, 0x96, 0xac, - 0x10, 0xd6, 0x90, 0x1f, 0xc8, 0x74, 0xd7, 0x53, 0x68, 0xff, 0xcf, 0x37, 0x22, 0xdf, 0xa4, 0x61, - 0xf5, 0x67, 0x1b, 0x0c, 0xff, 0xf5, 0x12, 0xd4, 0x76, 0x43, 0x25, 0x93, 0x14, 0x15, 0x87, 0x33, - 0x1a, 0x49, 0x37, 0x95, 0xac, 0xb0, 0x97, 0xac, 0xfc, 0x1d, 0xd7, 0xee, 0x30, 0xfa, 0x36, 0xf1, - 0x53, 0x79, 0xf0, 0xb1, 0x96, 0x8c, 0x02, 0x80, 0xa6, 0xc4, 0xf1, 0x3c, 0xdb, 0x50, 0xdb, 0x49, - 0xf4, 0x5c, 0x91, 0x12, 0x69, 0x58, 0x3d, 0xc7, 0xf3, 0xb6, 0x35, 0xdc, 0x8a, 0x9e, 0x2b, 0xf1, - 0x36, 0x2c, 0x26, 0x72, 0x44, 0x72, 0xd2, 0xda, 0xea, 0x31, 0x2f, 0x3e, 0x3e, 0xfa, 0x5e, 0xba, - 0xa9, 0x25, 0x47, 0x16, 0xe2, 0xc4, 0x2a, 0x54, 0x9d, 0x34, 0x4d, 0x98, 0xb7, 0x9a, 0x16, 0xbf, - 0x88, 0x4d, 0x58, 0x21, 0x65, 0x95, 0xfa, 0x51, 0x68, 0xa7, 0xce, 0x51, 0x20, 0x69, 0x26, 0xd8, - 0x10, 0x2f, 0xe7, 0xa8, 0x43, 0xc4, 0xe0, 0x3c, 0x6c, 0xc1, 0x85, 0x59, 0xfa, 0xd0, 0x99, 0x48, - 0x45, 0x76, 0xb8, 0x69, 0xad, 0x4c, 0xb7, 0x78, 0x84, 0x28, 0x64, 0x84, 0xa2, 0x0d, 0xaa, 0xbb, - 0x06, 0x69, 0x8e, 0x76, 0x0e, 0x44, 0x6d, 0x78, 0x01, 0x6a, 0xbe, 0xb2, 0x65, 0xe8, 0x69, 0x0d, - 0x5c, 0xf5, 0xd5, 0xfd, 0xd0, 0x13, 0x1f, 0x40, 0x93, 0xbf, 0xe2, 0xc9, 0x11, 0xd9, 0xd1, 0xd6, - 0x56, 0x57, 0x8b, 0x1a, 0x82, 0xef, 0xc9, 0x91, 0xd5, 0x48, 0xf5, 0x13, 0xfa, 0x58, 0x69, 0x64, - 0xcb, 0xd3, 0x54, 0x26, 0xa1, 0x13, 0x68, 0x63, 0x0a, 0x69, 0x74, 0x5f, 0x43, 0xc4, 0xa7, 0x70, - 0xd1, 0x60, 0x6d, 0x95, 0x4e, 0x52, 0x3b, 0x0b, 0xfd, 0x53, 0x3b, 0x74, 0xc2, 0x88, 0x3c, 0xe8, - 0x45, 0x6b, 0xd5, 0xa0, 0x0f, 0xd2, 0x49, 0xfa, 0x24, 0xf4, 0x4f, 0x1f, 0x39, 0x61, 0x24, 0x36, - 0xa0, 0x9f, 0x37, 0x4b, 0x5f, 0xd0, 0x0f, 0x13, 0x73, 0x35, 0xad, 0xae, 0x81, 0x1f, 0xbe, 0xc0, - 0x7f, 0x25, 0xde, 0x2a, 0x51, 0x46, 0xa3, 0x11, 0xf2, 0x96, 0x92, 0x2e, 0xb9, 0xc1, 0x55, 0x6b, - 0xa5, 0xa0, 0x7f, 0x4c, 0xb8, 0x03, 0xe9, 0x0e, 0x7f, 0x5f, 0x81, 0x16, 0x09, 0xf4, 0x93, 0xd8, - 0x43, 0xdd, 0xf9, 0x0e, 0x74, 0xa6, 0x17, 0x9d, 0xf9, 0xa6, 0xed, 0x94, 0x57, 0x7c, 0x0d, 0x6a, - 0xdb, 0x2e, 0x4e, 0x1e, 0x31, 0x4e, 0xc7, 0xd2, 0x6f, 0xe2, 0xe7, 0xd0, 0xcb, 0xa8, 0x1b, 0xdb, - 0x4d, 0x4f, 0xed, 0x00, 0x75, 0x2e, 0x6b, 0x28, 0xcd, 0x15, 0xfc, 0x8d, 0x9d, 0xf4, 0xd4, 0xea, - 0x64, 0xe6, 0xf1, 0x21, 0x6a, 0xe3, 0x3b, 0xb0, 0x9a, 0x48, 0xe4, 0x18, 0xfb, 0x85, 0x4c, 0x22, - 0x3b, 0x95, 0x93, 0x38, 0x4a, 0xc8, 0x82, 0xe3, 0x2c, 0x0a, 0xc6, 0x7d, 0x27, 0x93, 0xe8, 0x50, - 0x63, 0x86, 0x6f, 0x42, 0x75, 0x3b, 0x49, 0x9c, 0x33, 0x62, 0x2d, 0x7c, 0x18, 0x54, 0x48, 0x36, - 0xf9, 0x65, 0xe8, 0xc2, 0xe2, 0x9e, 0x13, 0x8b, 0xeb, 0xb0, 0x30, 0x89, 0x09, 0xd3, 0xda, 0xba, - 0x50, 0x52, 0x68, 0x4e, 0xbc, 0xb9, 0x17, 0xdf, 0x0f, 0xd3, 0xe4, 0xcc, 0x5a, 0x98, 0xc4, 0x97, - 0x3f, 0x85, 0xba, 0x7e, 0xc5, 0x30, 0x10, 0x05, 0xbd, 0x42, 0x33, 0x8c, 0x8f, 0xf8, 0x81, 0x67, - 0x4e, 0x90, 0x19, 0xd7, 0x95, 0x5f, 0x3e, 0x5f, 0xf8, 0xac, 0x32, 0xfc, 0x9f, 0x4b, 0xd0, 0xb8, - 0x27, 0x03, 0x49, 0xff, 0x3e, 0x84, 0x76, 0x59, 0x2a, 0xcc, 0xbc, 0x4d, 0x49, 0xca, 0x10, 0xda, - 0xec, 0x4b, 0x50, 0x2b, 0xa9, 0xc5, 0x6e, 0x0a, 0x86, 0x46, 0x6e, 0x97, 0x9d, 0x34, 0x92, 0xb7, - 0x8e, 0x65, 0x5e, 0x11, 0xf3, 0x48, 0x63, 0x96, 0x18, 0xa3, 0x5f, 0xc5, 0x55, 0x80, 0x24, 0x7a, - 0x6e, 0xfb, 0x6c, 0xd0, 0xd9, 0x36, 0x36, 0x92, 0xe8, 0xf9, 0x2e, 0x9a, 0xf4, 0xbf, 0x11, 0x31, - 0xfb, 0x39, 0x0c, 0x4a, 0x62, 0x86, 0xa1, 0x82, 0xed, 0x87, 0x1c, 0x12, 0x69, 0x89, 0x2b, 0xfa, - 0xa4, 0x48, 0x62, 0x37, 0xa4, 0x68, 0xc8, 0x28, 0x8f, 0xe6, 0x2b, 0x94, 0xc7, 0x5c, 0x5d, 0x04, - 0xf3, 0x75, 0xd1, 0x5d, 0x80, 0x03, 0x39, 0x9e, 0xc8, 0x30, 0xdd, 0x73, 0xe2, 0x41, 0x8b, 0x16, - 0x7e, 0x58, 0x2c, 0xbc, 0x59, 0xad, 0xcd, 0x82, 0x88, 0xb9, 0xa0, 0xd4, 0x0a, 0xfd, 0x3c, 0xd7, - 0x09, 0xed, 0x34, 0xc9, 0x42, 0xd7, 0x49, 0x39, 0xbe, 0x6d, 0x58, 0x2d, 0xd7, 0x09, 0x0f, 0x35, - 0xa8, 0xa4, 0x30, 0x3a, 0x65, 0x85, 0x71, 0x03, 0x7a, 0x71, 0xe2, 0x4f, 0x9c, 0xe4, 0x0c, 0xad, - 0x05, 0x2d, 0x06, 0x8b, 0x5e, 0x47, 0x83, 0xbf, 0x91, 0x67, 0xbb, 0xde, 0xe9, 0xe5, 0x2f, 0xa0, - 0x37, 0x33, 0x80, 0x1f, 0xc5, 0x77, 0xff, 0xa4, 0x0a, 0xcd, 0xfd, 0x44, 0x6a, 0x25, 0x7f, 0x0d, - 0x5a, 0xca, 0x3d, 0x96, 0x13, 0x87, 0x75, 0x03, 0xf7, 0x00, 0x0c, 0x22, 0xbd, 0x30, 0xa5, 0xc6, - 0x16, 0x5e, 0xa3, 0xc6, 0xfa, 0xb0, 0xc8, 0xfe, 0x22, 0x0a, 0x13, 0x3e, 0x16, 0xba, 0x7b, 0xa9, - 0xac, 0xbb, 0xd7, 0xa1, 0x7d, 0xec, 0x28, 0xdb, 0xc9, 0xd2, 0xc8, 0x76, 0xa3, 0x80, 0x98, 0xae, - 0x61, 0xc1, 0xb1, 0xa3, 0xb6, 0xb3, 0x34, 0xda, 0x89, 0x02, 0xf1, 0x26, 0x80, 0x1b, 0x05, 0x5a, - 0x0d, 0x69, 0x67, 0xb9, 0xe9, 0x46, 0x01, 0xeb, 0x1e, 0xe4, 0x4a, 0xa9, 0x52, 0x7f, 0xe2, 0xe8, - 0x25, 0xd5, 0x11, 0x77, 0x9d, 0x54, 0xe1, 0x72, 0x8e, 0xb2, 0xa2, 0xe7, 0x1c, 0x6a, 0xdf, 0x81, - 0xae, 0x1b, 0x4d, 0x62, 0x3b, 0xc6, 0x99, 0x25, 0xd7, 0xad, 0x71, 0x2e, 0x1a, 0x6a, 0x23, 0xc5, - 0xfe, 0x89, 0x64, 0x67, 0x72, 0x0b, 0x7a, 0x6e, 0x90, 0xa9, 0x54, 0x26, 0x68, 0xc3, 0xe5, 0xfc, - 0x00, 0xaa, 0xa3, 0x49, 0xb4, 0x03, 0x3a, 0x84, 0x8e, 0xaf, 0xec, 0x28, 0xf0, 0x6c, 0x56, 0x50, - 0x9a, 0xcf, 0x5a, 0xbe, 0x7a, 0x1c, 0x78, 0x5a, 0x45, 0x32, 0x4d, 0x28, 0x9f, 0x1b, 0x9a, 0x96, - 0xa1, 0x79, 0x24, 0x9f, 0x6b, 0x9a, 0x97, 0x29, 0xb4, 0xf6, 0xcb, 0x14, 0x1a, 0xce, 0x07, 0x4e, - 0x68, 0xea, 0x24, 0x63, 0xd2, 0xda, 0x01, 0xc7, 0x41, 0xcc, 0x5f, 0xcb, 0xc7, 0x8e, 0x3a, 0x24, - 0xcc, 0x81, 0x46, 0x60, 0xd4, 0xa3, 0x69, 0x71, 0xf2, 0xc2, 0x6c, 0x72, 0x24, 0x13, 0x5a, 0x09, - 0xe6, 0x38, 0xc1, 0x48, 0x2b, 0x7a, 0xfe, 0x88, 0x50, 0xb8, 0x22, 0x37, 0x61, 0x59, 0x37, 0x71, - 0xdc, 0xd4, 0x7f, 0x26, 0x89, 0xbc, 0x47, 0xe4, 0x3d, 0x46, 0x6c, 0x13, 0x1c, 0x69, 0xdf, 0xcf, - 0x69, 0xb5, 0x66, 0x41, 0xda, 0x3e, 0xef, 0x09, 0xe4, 0x5d, 0xef, 0x7a, 0x3b, 0x51, 0x30, 0xfc, - 0x8f, 0x0b, 0x50, 0xdf, 0x8f, 0x54, 0x7a, 0x6f, 0x12, 0x18, 0x71, 0xae, 0xfc, 0x58, 0x71, 0x5e, - 0x98, 0x2f, 0xce, 0x73, 0x04, 0x6a, 0x71, 0x8e, 0x40, 0xa1, 0x91, 0x2c, 0xd3, 0x91, 0x20, 0x70, - 0xf8, 0xd0, 0x2d, 0x08, 0x49, 0x18, 0xae, 0xa0, 0xcb, 0x6a, 0x7b, 0xac, 0x7f, 0x99, 0x69, 0x1b, - 0xbe, 0xd2, 0xba, 0x97, 0x91, 0x3e, 0xc9, 0x95, 0xf6, 0x67, 0x1b, 0xbe, 0xd2, 0x72, 0xf6, 0x0b, - 0xb8, 0x94, 0xb7, 0xb4, 0x9f, 0xfb, 0xe9, 0x71, 0x94, 0xa5, 0xf6, 0x88, 0x62, 0x75, 0xa5, 0xa3, - 0xbd, 0x35, 0xd3, 0xd3, 0xb7, 0x8c, 0xe6, 0x48, 0x9e, 0xdc, 0xeb, 0x51, 0x16, 0x04, 0x76, 0x2a, - 0x4f, 0x53, 0xcd, 0xb6, 0x03, 0x9e, 0x1b, 0x3d, 0x6f, 0x0f, 0xb2, 0x20, 0x38, 0x94, 0xa7, 0x29, - 0x9a, 0xc6, 0xc6, 0x48, 0xbf, 0x0c, 0xff, 0xe9, 0x12, 0xc0, 0xc3, 0xc8, 0x3d, 0xe1, 0x95, 0xc7, - 0x18, 0xd2, 0x68, 0x6f, 0x6d, 0x5d, 0xea, 0x29, 0xeb, 0x6c, 0xb1, 0x05, 0x6b, 0xe6, 0xff, 0x51, - 0xe6, 0x30, 0x9e, 0x65, 0xf5, 0xab, 0x95, 0x87, 0xd0, 0x58, 0xde, 0x93, 0x21, 0xdd, 0x2b, 0x3e, - 0x2b, 0xe6, 0x16, 0xdb, 0xa4, 0x67, 0x31, 0xcd, 0xed, 0xbc, 0x70, 0xa2, 0x53, 0x34, 0x3f, 0x3c, - 0x8b, 0xc5, 0x1d, 0xb8, 0x90, 0xc8, 0x51, 0x22, 0xd5, 0xb1, 0x9d, 0xaa, 0xf2, 0xc7, 0x38, 0x94, - 0x5c, 0xd6, 0xc8, 0x43, 0x95, 0x7f, 0xeb, 0x0e, 0x5c, 0xe0, 0x99, 0x9a, 0x1d, 0x1e, 0xdb, 0xaa, - 0x65, 0x46, 0x96, 0x47, 0xf7, 0x26, 0xd0, 0xc6, 0x30, 0xdb, 0x1f, 0x13, 0x5b, 0x04, 0x34, 0x19, - 0x47, 0x81, 0x44, 0xef, 0x75, 0xe7, 0xd8, 0x09, 0xc7, 0xa8, 0xb3, 0xf4, 0xe4, 0x17, 0x00, 0x31, - 0x84, 0xa5, 0xbd, 0xc8, 0x93, 0x34, 0xd5, 0xdd, 0xad, 0xee, 0x26, 0x6d, 0x31, 0xe3, 0x4c, 0xd2, - 0x5e, 0x24, 0xe1, 0xc4, 0x7b, 0x40, 0xdd, 0x31, 0xfb, 0x9d, 0xd7, 0x0b, 0x0d, 0x44, 0x12, 0x0f, - 0xde, 0x81, 0x0b, 0xc5, 0x48, 0x6c, 0x27, 0xb5, 0xd3, 0x63, 0x49, 0xaa, 0x9f, 0x55, 0xc3, 0x72, - 0x3e, 0xa8, 0xed, 0xf4, 0xf0, 0x58, 0xa2, 0x19, 0xd8, 0x80, 0x7a, 0x74, 0xf4, 0xbd, 0x8d, 0x82, - 0xd0, 0x9a, 0x2f, 0x08, 0xb5, 0xe8, 0xe8, 0x7b, 0x4b, 0x8e, 0xc4, 0xcf, 0xca, 0x66, 0x73, 0x66, - 0x6a, 0xda, 0x34, 0x35, 0xab, 0x39, 0xbe, 0x34, 0x3b, 0xc3, 0xcf, 0xa0, 0x86, 0xbf, 0xf3, 0x38, - 0x16, 0x9b, 0x50, 0x67, 0x71, 0x54, 0xda, 0xcd, 0x59, 0x2d, 0xac, 0x5d, 0xc1, 0x3b, 0x96, 0x21, - 0x1a, 0x5a, 0xd0, 0xcb, 0x4d, 0xc7, 0x93, 0xd0, 0x7f, 0x9a, 0x49, 0xf1, 0x25, 0x2c, 0xc7, 0x89, - 0xd4, 0x6c, 0x6f, 0x67, 0x27, 0xe8, 0xbc, 0x69, 0x09, 0x5e, 0xd5, 0x5c, 0x9a, 0xb7, 0x38, 0x41, - 0x0e, 0xed, 0xc6, 0x53, 0xef, 0xc3, 0xef, 0xe0, 0x62, 0x4e, 0x71, 0x20, 0xdd, 0x28, 0xf4, 0x9c, - 0xe4, 0x8c, 0xac, 0xfc, 0x4c, 0xdf, 0xea, 0xc7, 0xf4, 0x7d, 0x40, 0x7d, 0xff, 0xf7, 0x0a, 0xb4, - 0x1e, 0x64, 0x2f, 0x5e, 0x9c, 0xb1, 0x2c, 0x89, 0x36, 0x54, 0x1e, 0x51, 0x07, 0x0b, 0x56, 0xe5, - 0x11, 0x3a, 0xa2, 0xfb, 0x27, 0x28, 0xd7, 0xc4, 0xe7, 0x4d, 0x4b, 0xbf, 0x61, 0x80, 0xbc, 0x7f, - 0x72, 0xf8, 0x0a, 0x8e, 0x66, 0x34, 0x06, 0x48, 0x77, 0x33, 0x3f, 0x40, 0x37, 0x49, 0x33, 0x6f, - 0xfe, 0x8e, 0x21, 0xe7, 0xee, 0x88, 0x87, 0xf2, 0x20, 0x89, 0x26, 0x3c, 0x59, 0x5a, 0x65, 0xcc, - 0xc1, 0x88, 0xaf, 0x60, 0x45, 0x6f, 0xe0, 0x69, 0xad, 0x60, 0xab, 0x58, 0xba, 0xc4, 0xba, 0x3f, - 0x6a, 0xd3, 0x6f, 0xf8, 0x0f, 0x6b, 0xd0, 0xc0, 0xd0, 0xf2, 0x37, 0x91, 0x1f, 0x8a, 0x3b, 0xd0, - 0xfc, 0x3e, 0xf2, 0x43, 0xde, 0x6d, 0xe0, 0x24, 0xc7, 0x0a, 0xf7, 0xf5, 0x28, 0xf2, 0xe4, 0x26, - 0xd2, 0xd0, 0x3e, 0x43, 0xe3, 0x7b, 0xfd, 0xa4, 0xcd, 0x53, 0xe2, 0x8f, 0x8f, 0x53, 0x1b, 0x81, - 0x5a, 0xb7, 0xb6, 0x7c, 0x65, 0x21, 0x8c, 0x7a, 0xbd, 0x0a, 0x40, 0x31, 0x6d, 0x14, 0xda, 0xf1, - 0x89, 0x8e, 0xeb, 0x1a, 0x08, 0x79, 0x1c, 0xee, 0x9f, 0xa0, 0xec, 0xf9, 0xca, 0xd6, 0xfb, 0x5a, - 0xda, 0x07, 0x2f, 0xc5, 0xf5, 0xef, 0x42, 0x17, 0xfd, 0x23, 0x75, 0xe2, 0xc7, 0x76, 0x9c, 0x44, - 0x47, 0x66, 0x52, 0xd0, 0x6b, 0x3a, 0x38, 0xf1, 0xe3, 0x7d, 0x84, 0x91, 0x5b, 0xa2, 0x77, 0xcb, - 0x50, 0x6d, 0xb3, 0xfd, 0x07, 0x0d, 0xc2, 0xf9, 0xa5, 0x2d, 0xb1, 0x80, 0xa3, 0x84, 0x3a, 0xb9, - 0x1b, 0xf5, 0x44, 0x06, 0x14, 0x0e, 0x5c, 0x82, 0x06, 0x0a, 0x03, 0xa1, 0x1a, 0x8c, 0x72, 0x23, - 0x46, 0xbd, 0x0f, 0x10, 0xc8, 0x51, 0x6a, 0x23, 0x97, 0xf1, 0x06, 0xc0, 0xcc, 0xd6, 0x13, 0x62, - 0x77, 0x10, 0x29, 0x3e, 0x80, 0x16, 0xcf, 0x02, 0xd3, 0xc2, 0x39, 0x5a, 0x20, 0x34, 0x13, 0xdf, - 0x84, 0x56, 0x18, 0x85, 0xb6, 0x7c, 0x4a, 0xd4, 0x5a, 0x6e, 0xa7, 0x3a, 0x0e, 0xa3, 0xf0, 0xfe, - 0x53, 0x24, 0x16, 0xb7, 0xf5, 0x18, 0x78, 0x0f, 0xa6, 0xfd, 0x92, 0x3d, 0x18, 0x1a, 0x09, 0xef, - 0x46, 0x7c, 0x64, 0x46, 0xc2, 0x2d, 0x3a, 0x2f, 0x69, 0xc1, 0xe3, 0xe1, 0x26, 0xeb, 0xd0, 0xa6, - 0x75, 0x9f, 0x38, 0xb1, 0x9d, 0x3a, 0x63, 0x6d, 0xd5, 0x01, 0x61, 0x7b, 0x4e, 0x7c, 0xe8, 0x8c, - 0x85, 0x05, 0x97, 0x66, 0xf8, 0xed, 0x08, 0x59, 0x97, 0x67, 0xad, 0x67, 0xf6, 0x70, 0xe6, 0x73, - 0xdd, 0xda, 0x14, 0xd7, 0x11, 0xcb, 0xd3, 0xec, 0xfe, 0x02, 0x2e, 0xc9, 0x09, 0x65, 0x3f, 0x26, - 0x71, 0x22, 0x95, 0x9a, 0x72, 0xcd, 0xfa, 0x6c, 0xe3, 0x90, 0x60, 0x27, 0xc7, 0xe7, 0xfe, 0xd9, - 0xbb, 0xd0, 0x75, 0x54, 0x34, 0xb2, 0xcd, 0x94, 0x07, 0x94, 0xcb, 0xa8, 0x5a, 0x6d, 0x84, 0x5a, - 0x3c, 0xd1, 0x01, 0x1a, 0x74, 0xa2, 0xd2, 0x43, 0x95, 0xa3, 0x94, 0xf2, 0x18, 0x0d, 0xab, 0x83, - 0x60, 0x1e, 0x88, 0x1c, 0xa5, 0xc3, 0x7f, 0xb9, 0x00, 0x8d, 0x87, 0x51, 0x14, 0xff, 0x44, 0x19, - 0x28, 0xf3, 0xd6, 0xc2, 0xcb, 0x79, 0x6b, 0x71, 0x9a, 0xb7, 0x66, 0x78, 0x60, 0xe9, 0x87, 0xf3, - 0x40, 0xf5, 0x47, 0xf3, 0x40, 0xed, 0x27, 0xf0, 0x40, 0x7d, 0x96, 0x07, 0x86, 0x77, 0xa0, 0x7a, - 0x20, 0xd3, 0xc7, 0x31, 0x5a, 0x33, 0xe3, 0x17, 0x1b, 0x43, 0x30, 0x65, 0xcd, 0xb4, 0x4f, 0xac, - 0x86, 0x7f, 0xdd, 0x82, 0xe6, 0x3d, 0xe9, 0x65, 0x3c, 0xb3, 0xe5, 0x79, 0xaa, 0xbc, 0x7c, 0x9e, - 0x16, 0xa6, 0xe7, 0x09, 0x4d, 0xa7, 0x91, 0xc1, 0x39, 0x1b, 0xa8, 0x0d, 0x23, 0x82, 0x28, 0xac, - 0x85, 0x04, 0xea, 0x5d, 0xc8, 0xa9, 0xf9, 0xcc, 0x05, 0xf0, 0xd5, 0xdc, 0x5c, 0xfd, 0x69, 0xdc, - 0x3c, 0xad, 0xc7, 0xce, 0xed, 0x4f, 0xbe, 0x76, 0x7a, 0x67, 0x75, 0x58, 0xe3, 0x9c, 0x0e, 0x7b, - 0x08, 0x2b, 0x51, 0x68, 0x7b, 0x59, 0x1c, 0xf8, 0x18, 0x17, 0x92, 0x5f, 0x1d, 0x85, 0xe4, 0x4e, - 0x50, 0x46, 0x34, 0xe7, 0xd1, 0xc7, 0xe1, 0x3d, 0x43, 0xc4, 0x7b, 0x25, 0xd6, 0x72, 0x34, 0x0b, - 0x42, 0x11, 0xf2, 0x70, 0x69, 0xc8, 0x13, 0x20, 0x1f, 0x96, 0x53, 0xbb, 0x6d, 0x82, 0xee, 0x44, - 0x01, 0xd9, 0xb6, 0xcf, 0xa0, 0x57, 0x50, 0x31, 0x33, 0xb5, 0x5e, 0xc2, 0x4c, 0x1d, 0xd3, 0x90, - 0xf9, 0xe9, 0x6f, 0x42, 0x6f, 0x7d, 0x08, 0x2b, 0x66, 0x0b, 0x48, 0xbb, 0x33, 0xb4, 0x82, 0x5d, - 0xe2, 0xa0, 0xbe, 0xde, 0xf5, 0x21, 0x4f, 0x86, 0x96, 0xe8, 0x97, 0xb0, 0x5a, 0x22, 0x47, 0xf6, - 0x2d, 0xeb, 0xaf, 0x32, 0xaf, 0x2c, 0xe7, 0x6d, 0xf1, 0xf5, 0x21, 0xef, 0xe1, 0xb7, 0x3c, 0x19, - 0x98, 0x0f, 0xe9, 0xe8, 0xa4, 0xe9, 0xc9, 0x40, 0xa7, 0x1e, 0xf7, 0xe0, 0x5d, 0x8c, 0xe4, 0x10, - 0xef, 0x3a, 0x71, 0x9a, 0x25, 0xd2, 0x8e, 0x03, 0xc7, 0x95, 0xc7, 0x51, 0xe0, 0xc9, 0xa4, 0x18, - 0xdc, 0x32, 0x0d, 0xee, 0x5a, 0x14, 0x60, 0x38, 0xb3, 0xc3, 0x94, 0xfb, 0x05, 0xa1, 0x19, 0xeb, - 0x36, 0xbc, 0x75, 0xae, 0x3b, 0x34, 0x75, 0x45, 0x47, 0x82, 0x3a, 0xba, 0x34, 0xdd, 0x11, 0x92, - 0x98, 0x2e, 0x3e, 0x82, 0x0b, 0xbc, 0x76, 0xcc, 0xdc, 0x27, 0x52, 0xc6, 0x76, 0xe0, 0xa8, 0x74, - 0xb0, 0xc2, 0x6e, 0x05, 0x21, 0x89, 0x81, 0xbf, 0x91, 0x32, 0x7e, 0xe8, 0xf0, 0x57, 0xb9, 0x89, - 0x8e, 0x3c, 0xa8, 0xcd, 0xd4, 0xdc, 0xae, 0xf2, 0x57, 0x89, 0x8a, 0xc3, 0x0f, 0x6c, 0x5c, 0x9a, - 0xe4, 0x5f, 0xc1, 0x95, 0xa9, 0x2e, 0x26, 0x4e, 0x72, 0x52, 0xb8, 0xe2, 0x83, 0x0b, 0x34, 0x6f, - 0x17, 0x4b, 0xed, 0xf7, 0x88, 0x40, 0xcf, 0xe2, 0xc7, 0xb0, 0x86, 0x81, 0x69, 0xe4, 0x9d, 0x64, - 0x33, 0x41, 0xdb, 0x1a, 0x0d, 0x1a, 0xc3, 0xd6, 0xc7, 0xde, 0x49, 0x36, 0x15, 0xb8, 0xfd, 0x1c, - 0x06, 0x53, 0xb4, 0x76, 0x42, 0x9b, 0xf3, 0x76, 0x1c, 0xa9, 0xc1, 0x45, 0xde, 0x0f, 0x2a, 0xef, - 0x28, 0xf2, 0xd6, 0xfd, 0x7e, 0xa4, 0xc4, 0x03, 0x58, 0x8f, 0x8f, 0xcf, 0x94, 0x4f, 0xc9, 0x44, - 0x72, 0xe8, 0xcf, 0x77, 0x30, 0xa0, 0x0e, 0xae, 0x1a, 0x3a, 0xf6, 0xfb, 0x67, 0xfa, 0xf9, 0x0c, - 0x2e, 0x19, 0xc6, 0x3a, 0x96, 0xee, 0xc9, 0xf4, 0x8c, 0x5d, 0xa2, 0x19, 0xbb, 0xa0, 0x39, 0x0a, - 0xf1, 0xa5, 0xd9, 0xda, 0x80, 0x3e, 0xd9, 0x3b, 0x7b, 0x14, 0x65, 0xa1, 0xfe, 0xd3, 0xcb, 0xf4, - 0xa7, 0x5d, 0x82, 0x3f, 0x40, 0x30, 0xfd, 0xe4, 0x06, 0xf4, 0xc9, 0x5a, 0xb2, 0xd4, 0x33, 0xe5, - 0x15, 0xa6, 0x44, 0xb8, 0x16, 0x74, 0xa4, 0xfc, 0x14, 0x2e, 0x6a, 0xa2, 0x91, 0x1f, 0x3a, 0x41, - 0xf9, 0x67, 0xae, 0xb2, 0x9b, 0xcf, 0xe8, 0x07, 0x88, 0x2d, 0x7e, 0xe2, 0xb7, 0x20, 0x46, 0x51, - 0x22, 0xfd, 0x71, 0x48, 0x61, 0x2d, 0xfd, 0x89, 0x1a, 0xbc, 0x49, 0xb2, 0xf1, 0x66, 0xe1, 0xe7, - 0x3f, 0xbe, 0xf7, 0xcd, 0x93, 0x07, 0x4c, 0xf7, 0x8d, 0x3c, 0xa3, 0xff, 0xd1, 0x92, 0xd9, 0x1f, - 0x4d, 0x83, 0xd5, 0xf0, 0x9f, 0xd5, 0xa0, 0x4b, 0xd6, 0xf8, 0xef, 0x8c, 0xc0, 0xdf, 0x19, 0x81, - 0xbf, 0x0d, 0x46, 0xe0, 0x26, 0x2c, 0xfb, 0x61, 0x9c, 0xa5, 0x28, 0x41, 0xca, 0xce, 0x38, 0x8a, - 0x5b, 0xe6, 0xed, 0x26, 0x42, 0x7c, 0x23, 0xcf, 0x14, 0x87, 0x70, 0xc3, 0x7f, 0x50, 0x81, 0xfa, - 0x7e, 0x12, 0x79, 0x99, 0x9b, 0xfe, 0x44, 0xa9, 0x98, 0xe6, 0xb6, 0xc5, 0xd7, 0x71, 0xdb, 0xd2, - 0x39, 0x8f, 0xee, 0x5f, 0x55, 0xa0, 0xa9, 0x87, 0xf0, 0x70, 0xeb, 0x27, 0x0e, 0xa2, 0xc8, 0x6d, - 0x57, 0xe6, 0xe6, 0xb6, 0x5f, 0x3b, 0x0a, 0x64, 0xc2, 0x67, 0x5c, 0x0c, 0x14, 0xc5, 0x45, 0xa2, - 0xbb, 0x69, 0xb5, 0x19, 0xfa, 0x38, 0xa6, 0x7c, 0xf6, 0x73, 0x68, 0x52, 0x94, 0x4f, 0x5a, 0x64, - 0x0d, 0x6a, 0xac, 0xd5, 0xf4, 0x40, 0xf5, 0xdb, 0xab, 0x65, 0x7a, 0xe1, 0x27, 0xc9, 0xf4, 0xf0, - 0xdf, 0x2f, 0x42, 0x87, 0xb6, 0x5c, 0x1e, 0x64, 0x21, 0x4b, 0x4d, 0xbe, 0x49, 0x5d, 0x99, 0xde, - 0xa4, 0x5e, 0x4a, 0x64, 0x6a, 0x12, 0xe9, 0x6d, 0xfe, 0xcc, 0x4e, 0x14, 0xdc, 0x93, 0x23, 0x8b, - 0x30, 0x38, 0x55, 0x4e, 0x32, 0x56, 0xf3, 0xca, 0x00, 0x10, 0x8e, 0x7f, 0x15, 0x3b, 0x89, 0x33, - 0x51, 0xa6, 0x0c, 0x80, 0xdf, 0x84, 0x80, 0x25, 0x92, 0x4d, 0x9e, 0x16, 0x7a, 0xd6, 0xbb, 0x87, - 0xca, 0x0f, 0xc7, 0xb9, 0xa2, 0x69, 0x50, 0xf9, 0xc7, 0x38, 0x90, 0xe2, 0x1e, 0x08, 0x4e, 0x8b, - 0x24, 0xd2, 0x41, 0xe7, 0x83, 0xfa, 0x21, 0x6d, 0xd3, 0xda, 0x5a, 0xe3, 0xcf, 0xd2, 0x5c, 0x5a, - 0x84, 0xde, 0x47, 0xac, 0xd5, 0xf7, 0x67, 0x20, 0x73, 0x26, 0x93, 0x3d, 0x90, 0x3c, 0x52, 0xfe, - 0xc1, 0x93, 0x49, 0x6e, 0x09, 0x71, 0xcb, 0x97, 0xb0, 0x32, 0xca, 0x82, 0x20, 0x95, 0xa7, 0xa9, - 0xad, 0xa2, 0x2c, 0x71, 0xa5, 0xfd, 0x8a, 0x8c, 0xcc, 0xb2, 0xa1, 0x3d, 0x20, 0x52, 0x4b, 0x8e, - 0xc4, 0x17, 0x20, 0xf2, 0x0e, 0xcc, 0x3f, 0x9a, 0x7c, 0xe9, 0xb9, 0xf6, 0x7d, 0x43, 0xaa, 0xff, - 0x76, 0x34, 0xdc, 0x86, 0x0b, 0x26, 0x47, 0x8a, 0xaa, 0x6d, 0x0b, 0xe5, 0x96, 0xf6, 0x8e, 0xcc, - 0x1c, 0x57, 0x4a, 0x73, 0xbc, 0x0a, 0xd5, 0x72, 0x79, 0x1a, 0xbf, 0x0c, 0xaf, 0x43, 0x6b, 0xe4, - 0x07, 0x52, 0xe7, 0x1a, 0x70, 0xd1, 0x74, 0xd6, 0xa1, 0x42, 0x49, 0x75, 0xfd, 0x36, 0xfc, 0x7d, - 0x05, 0x2e, 0xc6, 0x4e, 0xf2, 0x34, 0xd3, 0xbb, 0xda, 0x9c, 0xdf, 0x57, 0xc7, 0x4e, 0xe2, 0xa1, - 0xe0, 0x52, 0x17, 0xdc, 0x3b, 0x57, 0x37, 0x35, 0x11, 0xc2, 0x63, 0xb9, 0x01, 0xbd, 0x52, 0x8b, - 0xd4, 0x49, 0xcc, 0xce, 0x6a, 0x27, 0x89, 0x9e, 0x53, 0xf6, 0xfd, 0x00, 0x81, 0x62, 0x08, 0x9d, - 0x82, 0x4e, 0x92, 0x65, 0xa4, 0x22, 0x21, 0x43, 0x75, 0x3f, 0xf4, 0x50, 0x72, 0xc3, 0x6c, 0xc2, - 0xee, 0x02, 0x17, 0xb1, 0xd5, 0xc3, 0x6c, 0x42, 0x7e, 0xc2, 0x2a, 0x54, 0xb9, 0x72, 0xb0, 0x4a, - 0x70, 0x7e, 0x19, 0xfe, 0xa1, 0x0a, 0x2b, 0xbb, 0xae, 0x3c, 0x92, 0xc9, 0xf8, 0x9e, 0x93, 0x3a, - 0x0f, 0xfc, 0x40, 0x1e, 0x3a, 0xea, 0x04, 0x19, 0x8e, 0xc6, 0x1c, 0x3b, 0xe9, 0xb1, 0x9e, 0xa5, - 0x06, 0x02, 0xf6, 0x9d, 0xf4, 0x18, 0xcd, 0x16, 0x21, 0x47, 0x51, 0x32, 0xd1, 0xfb, 0xc0, 0x4d, - 0x8b, 0xfe, 0xf1, 0x01, 0x41, 0xf2, 0xd6, 0xca, 0x7f, 0x21, 0x75, 0xc9, 0x1d, 0xb5, 0xa6, 0xba, - 0x8c, 0xb7, 0xa1, 0x9d, 0x48, 0x37, 0x4a, 0x3c, 0x1d, 0xfb, 0xf3, 0x38, 0x5b, 0x0c, 0xe3, 0x80, - 0xff, 0x26, 0x14, 0xb9, 0x43, 0xda, 0xea, 0xb2, 0x7d, 0x53, 0x97, 0xd3, 0xcb, 0x11, 0xc8, 0x79, - 0xbb, 0x9e, 0xf8, 0x7b, 0xd0, 0x2f, 0x68, 0x29, 0x91, 0x65, 0x22, 0xe0, 0xad, 0xc2, 0x8d, 0x99, - 0xf3, 0x8b, 0x9b, 0xfb, 0xa6, 0xd5, 0x9f, 0x53, 0x23, 0x4e, 0xd6, 0x15, 0xdd, 0x33, 0x54, 0xbc, - 0x03, 0x1d, 0x15, 0x07, 0x7e, 0xaa, 0x19, 0x40, 0xe9, 0xc2, 0xbc, 0x36, 0x01, 0x39, 0xdf, 0xa4, - 0xe6, 0x2d, 0x61, 0xe3, 0x07, 0x2d, 0x61, 0xf3, 0xfc, 0x12, 0xbe, 0x0f, 0x7d, 0x37, 0x91, 0x9e, - 0x0c, 0x53, 0xdf, 0x09, 0x6c, 0xe5, 0x46, 0xb1, 0x31, 0xd3, 0xbd, 0x02, 0x7e, 0x80, 0x60, 0xf1, - 0x33, 0xb8, 0xe8, 0x46, 0x61, 0x2a, 0xc3, 0x34, 0x2f, 0xdd, 0xd4, 0xd9, 0x1a, 0x5d, 0x72, 0x72, - 0x41, 0xa3, 0x4d, 0x01, 0x27, 0xe7, 0x6b, 0xc4, 0x1d, 0x58, 0xe5, 0xe5, 0x99, 0x69, 0xc4, 0xb5, - 0x02, 0x82, 0x56, 0x6a, 0xba, 0x85, 0xce, 0x20, 0x25, 0x52, 0xf9, 0x5e, 0xe6, 0x04, 0x5a, 0x43, - 0x94, 0x32, 0x48, 0x96, 0xc6, 0xe8, 0xad, 0x54, 0xca, 0x51, 0x4d, 0xd1, 0x52, 0xa1, 0x0b, 0x6d, - 0x35, 0x35, 0x2d, 0x91, 0x4c, 0x51, 0x7f, 0xed, 0xa8, 0xe3, 0xcb, 0x77, 0x61, 0x75, 0xde, 0x82, - 0xbc, 0x2e, 0x79, 0xd9, 0x2c, 0x25, 0x2f, 0x75, 0x79, 0xea, 0xff, 0x58, 0x80, 0x0b, 0x66, 0xbd, - 0x29, 0xe4, 0xc8, 0x99, 0xfa, 0x1a, 0xd9, 0x73, 0x0c, 0x53, 0xf2, 0xed, 0x9e, 0xa6, 0x05, 0x0c, - 0xa2, 0xbd, 0x9d, 0x0d, 0xe8, 0x6b, 0x82, 0x82, 0xf9, 0xf9, 0x2b, 0x5d, 0x2f, 0xef, 0x8a, 0x44, - 0x80, 0x7e, 0x70, 0x24, 0x13, 0x9c, 0x23, 0x8f, 0xaa, 0xb5, 0xa9, 0x09, 0x31, 0x3b, 0xfd, 0xa0, - 0xc1, 0x19, 0x96, 0xa3, 0x4a, 0x9b, 0xa7, 0x99, 0x13, 0xf8, 0xe9, 0x99, 0x3d, 0xf2, 0x65, 0xe0, - 0x51, 0xa6, 0x9c, 0xeb, 0x08, 0xfb, 0x06, 0xf3, 0x00, 0x11, 0xbb, 0x9e, 0x2a, 0x8d, 0x44, 0x27, - 0x60, 0x73, 0x01, 0xd0, 0x23, 0x39, 0x20, 0xf0, 0xae, 0x37, 0x5f, 0x56, 0x6a, 0xf3, 0x65, 0xe5, - 0x3d, 0xe8, 0xcd, 0xae, 0x39, 0x27, 0x45, 0xbb, 0x6a, 0x7a, 0xbd, 0xe7, 0x31, 0x61, 0x63, 0x2e, - 0x13, 0xea, 0x49, 0xff, 0x5f, 0x0b, 0xb0, 0xaa, 0x27, 0x7d, 0x27, 0x0a, 0xb2, 0x09, 0x5a, 0x7b, - 0xaa, 0x4a, 0x5a, 0x87, 0xf6, 0x24, 0x62, 0x17, 0xaa, 0xa4, 0xfe, 0x60, 0x12, 0xe5, 0xba, 0x78, - 0x03, 0xfa, 0x3e, 0xb7, 0xcc, 0xe7, 0xc5, 0x54, 0x08, 0x6b, 0xb8, 0x9e, 0x15, 0xe4, 0x42, 0x15, - 0x3a, 0xb1, 0x3a, 0x8e, 0x52, 0x4d, 0x4a, 0x4a, 0x9c, 0xe7, 0x7c, 0xd9, 0xa0, 0x88, 0x9a, 0x3c, - 0xd9, 0x5b, 0x20, 0xdc, 0x2c, 0x49, 0x50, 0x3e, 0x4a, 0xe4, 0x9c, 0xbc, 0xeb, 0x6b, 0x4c, 0x41, - 0xfd, 0x0e, 0xd4, 0x27, 0x51, 0xe1, 0x91, 0x4c, 0x39, 0xa2, 0x56, 0x6d, 0x12, 0x11, 0x87, 0x5c, - 0x46, 0xaf, 0xe9, 0x69, 0xe6, 0x27, 0xd2, 0x33, 0x76, 0xd8, 0xbc, 0x6b, 0x23, 0x7d, 0xec, 0x7b, - 0x9e, 0x0c, 0x75, 0xe2, 0xa8, 0xe1, 0xab, 0xaf, 0xe9, 0x9d, 0x0a, 0x68, 0xe5, 0xc8, 0xc1, 0xd0, - 0x2c, 0xcc, 0x02, 0x92, 0x8a, 0x40, 0x97, 0x6b, 0xf6, 0x34, 0xe2, 0x51, 0x16, 0xa0, 0x44, 0x04, - 0x7a, 0x49, 0xc9, 0x96, 0x20, 0x0b, 0xda, 0xc7, 0x7e, 0x98, 0x92, 0xaa, 0x68, 0xd2, 0x92, 0x22, - 0x02, 0x99, 0xf0, 0x6b, 0x3f, 0x4c, 0x87, 0x7f, 0xb9, 0x00, 0x6b, 0x7a, 0xe2, 0x0f, 0xf4, 0x04, - 0x68, 0xfb, 0x4c, 0xd1, 0x85, 0x99, 0x2e, 0x9d, 0xd7, 0x5b, 0xb4, 0xc0, 0x80, 0x76, 0x69, 0xc0, - 0x05, 0x77, 0x2d, 0xe8, 0x32, 0x4e, 0xc3, 0x57, 0xb7, 0x40, 0x9c, 0xe3, 0x2b, 0xa5, 0xb7, 0x35, - 0xfb, 0x33, 0x8c, 0xa5, 0xc4, 0x27, 0xb0, 0x36, 0x91, 0xa9, 0x43, 0x82, 0x10, 0x44, 0xae, 0x43, - 0xad, 0x48, 0xe4, 0x79, 0xba, 0x57, 0x0d, 0xf6, 0xa1, 0x46, 0xa2, 0xd0, 0xe3, 0x37, 0x26, 0x4e, - 0xe8, 0x8f, 0xa4, 0x4a, 0xc9, 0xcf, 0xe0, 0x16, 0xec, 0xf8, 0xf4, 0x0d, 0x06, 0x3d, 0x09, 0xa2, - 0x26, 0x8f, 0x75, 0xc4, 0x8b, 0x58, 0x23, 0x9a, 0x7a, 0x22, 0x47, 0x7a, 0xed, 0x3a, 0xb8, 0x56, - 0xa1, 0x1f, 0x8e, 0xf9, 0xe0, 0x40, 0x9d, 0x7d, 0x4a, 0x03, 0xdc, 0x8b, 0x3c, 0x39, 0xfc, 0x8b, - 0xa5, 0x9c, 0x47, 0xf7, 0x35, 0xfc, 0x20, 0x75, 0x52, 0xaa, 0x95, 0xcf, 0x07, 0xcf, 0x36, 0x92, - 0xe7, 0xaa, 0x63, 0xa0, 0x5c, 0x52, 0xbf, 0x09, 0x2b, 0xd3, 0xa3, 0x65, 0xda, 0x05, 0x2e, 0x2b, - 0x28, 0x0f, 0x37, 0x2f, 0xc1, 0xcf, 0xe9, 0x99, 0x54, 0x57, 0x9f, 0x1b, 0x28, 0x93, 0x7d, 0x58, - 0x4c, 0x82, 0xd2, 0xc9, 0x79, 0xe9, 0x69, 0xab, 0x98, 0xf7, 0xaa, 0x0e, 0x34, 0x02, 0x45, 0xb3, - 0x20, 0x8f, 0x93, 0x2c, 0x94, 0x9e, 0x36, 0xe9, 0xbd, 0x1c, 0xbe, 0x4f, 0x60, 0x1c, 0x70, 0xae, - 0x99, 0x4a, 0x5d, 0xd7, 0xb8, 0x6b, 0x4f, 0x6b, 0xa6, 0xa2, 0x6b, 0xe4, 0xd1, 0x82, 0x5e, 0xf7, - 0xcd, 0x0a, 0xa2, 0x97, 0x53, 0xeb, 0xbe, 0x7f, 0x0e, 0x83, 0x9c, 0x96, 0xff, 0xae, 0xf8, 0x40, - 0x83, 0x8d, 0x8f, 0x69, 0x42, 0xbf, 0x99, 0x7f, 0xe4, 0x63, 0x58, 0x9b, 0x6d, 0xa8, 0xbf, 0xd4, - 0xa4, 0x66, 0x2b, 0x53, 0xcd, 0x8a, 0x3f, 0xc9, 0xd7, 0xd7, 0x75, 0xdc, 0x63, 0x69, 0x1f, 0xfb, - 0xba, 0x00, 0x7d, 0xd1, 0x5a, 0x36, 0xa8, 0x1d, 0xc4, 0x7c, 0xed, 0xa7, 0x6a, 0x0e, 0xfd, 0xc4, - 0x57, 0x4a, 0x5b, 0xc5, 0x69, 0xfa, 0x3d, 0x5f, 0xa9, 0xe1, 0x7f, 0x6b, 0x41, 0xdb, 0x78, 0x8a, - 0x54, 0xfb, 0x7c, 0xab, 0xec, 0xf4, 0xb7, 0xb6, 0xfa, 0xc6, 0x7b, 0x47, 0x92, 0xed, 0x34, 0x4d, - 0x4c, 0xae, 0x8f, 0x83, 0x81, 0x29, 0x7f, 0x67, 0x81, 0x1c, 0x84, 0xc2, 0xdf, 0xd9, 0x86, 0xe5, - 0x92, 0x07, 0x69, 0xa7, 0x51, 0xea, 0x04, 0x3a, 0x28, 0x28, 0xd5, 0x8d, 0x95, 0x48, 0xac, 0x1e, - 0xbe, 0xb0, 0x6f, 0x71, 0x88, 0xd4, 0x18, 0x6c, 0xb8, 0x51, 0x60, 0x8a, 0x6d, 0x67, 0x82, 0x0d, - 0xc4, 0x50, 0x45, 0x4c, 0x22, 0x31, 0xce, 0x55, 0x4f, 0x03, 0x2d, 0x41, 0x4d, 0x86, 0x1c, 0x3c, - 0x0d, 0xf2, 0x01, 0x92, 0x33, 0x5f, 0xa3, 0x38, 0x86, 0x06, 0x48, 0x5e, 0xfa, 0x87, 0xd0, 0x8a, - 0x12, 0x7f, 0xec, 0x53, 0x9a, 0x98, 0x1d, 0x9c, 0xd9, 0x8f, 0x00, 0x13, 0xec, 0xe0, 0xa7, 0x86, - 0x50, 0xd3, 0xe6, 0xff, 0x7c, 0x95, 0x8c, 0xc6, 0x98, 0x23, 0x00, 0x6e, 0x8a, 0xc3, 0x61, 0x89, - 0x6c, 0x16, 0x47, 0x00, 0xdc, 0xf4, 0xe0, 0x69, 0x40, 0x99, 0xf2, 0x1b, 0xd0, 0x73, 0xc9, 0x5c, - 0xb0, 0x40, 0x05, 0x32, 0xa4, 0x35, 0xad, 0x5a, 0x1d, 0x06, 0xe3, 0xf8, 0x1e, 0xca, 0x50, 0x97, - 0x5a, 0x3a, 0x41, 0x80, 0x11, 0x6b, 0xe4, 0x78, 0xba, 0x2e, 0xa6, 0x6d, 0x80, 0x0f, 0x23, 0xc7, - 0x13, 0x9f, 0xc3, 0x65, 0xc4, 0xd9, 0x5c, 0xd0, 0x1a, 0x66, 0x13, 0x99, 0xf8, 0xae, 0xed, 0x28, - 0xaa, 0x93, 0xd1, 0xe5, 0x31, 0x6b, 0x48, 0x71, 0x1f, 0x09, 0x1e, 0x31, 0x7e, 0x5b, 0x7d, 0x27, - 0x93, 0x48, 0x7c, 0x47, 0xd9, 0xf2, 0x79, 0xee, 0xbb, 0xd9, 0x96, 0x78, 0xbb, 0x58, 0xab, 0x97, - 0x50, 0x52, 0x1d, 0x1a, 0x22, 0x2c, 0xe3, 0xf4, 0x51, 0x7b, 0xf1, 0x0d, 0x08, 0x63, 0xe0, 0x88, - 0xf3, 0x53, 0x47, 0x9d, 0x70, 0x51, 0xee, 0xd4, 0x56, 0xdb, 0x1c, 0x1f, 0xd5, 0x32, 0x96, 0x11, - 0x81, 0x08, 0x50, 0xe2, 0xb7, 0xb0, 0x9a, 0x77, 0xa6, 0x7d, 0x19, 0xea, 0x8e, 0x37, 0x34, 0xae, - 0x9d, 0xef, 0x6e, 0xca, 0x05, 0xb2, 0xcc, 0x48, 0x18, 0xcc, 0x5d, 0x7e, 0x05, 0x3d, 0xd3, 0x25, - 0xcf, 0xba, 0x1a, 0xf4, 0xa9, 0xb7, 0xb7, 0xce, 0xf5, 0x36, 0x65, 0xdb, 0x73, 0xfb, 0xcc, 0x50, - 0xfc, 0xd1, 0xdc, 0x92, 0x1b, 0x2b, 0x43, 0xdb, 0x21, 0xad, 0xad, 0xf5, 0x73, 0x3d, 0xcd, 0x18, - 0x2b, 0xcb, 0x0c, 0xc1, 0xc0, 0xc5, 0x47, 0x70, 0xc1, 0x74, 0x16, 0x51, 0x88, 0x67, 0xfb, 0x11, - 0x45, 0x7f, 0x82, 0x5d, 0x2c, 0x8d, 0xe4, 0xf0, 0x6f, 0x37, 0xe2, 0x68, 0xf1, 0x8a, 0x69, 0xc2, - 0x56, 0x98, 0x22, 0xe2, 0xfc, 0xa7, 0x56, 0xc8, 0x76, 0x0d, 0x34, 0x09, 0xdb, 0x65, 0x8c, 0x80, - 0xcd, 0xf0, 0x37, 0xa0, 0x4f, 0x95, 0xf3, 0xb8, 0xac, 0x51, 0xe2, 0xf9, 0xa1, 0x13, 0x0c, 0x56, - 0x79, 0xcf, 0x15, 0xe1, 0x56, 0xf4, 0xfc, 0x31, 0x43, 0xc5, 0x21, 0xac, 0x99, 0x0f, 0xe5, 0x6a, - 0x46, 0xa1, 0x29, 0xa1, 0x0d, 0xef, 0x79, 0x13, 0x37, 0x65, 0x70, 0x2c, 0xb3, 0x84, 0xd3, 0x66, - 0xe8, 0x1e, 0x5c, 0x9b, 0x59, 0xda, 0x89, 0x73, 0x6a, 0x4f, 0xe4, 0x24, 0x4a, 0xce, 0xb4, 0x01, - 0x59, 0x23, 0x05, 0x76, 0x65, 0x6a, 0x11, 0xf7, 0x9c, 0xd3, 0x3d, 0xa2, 0x61, 0x73, 0xf2, 0x25, - 0x5c, 0x9d, 0xe9, 0x85, 0x0b, 0xd1, 0x65, 0xe8, 0x1c, 0x05, 0xd2, 0xa3, 0x2d, 0xf2, 0x86, 0x75, - 0x69, 0xaa, 0x8b, 0x03, 0xa4, 0xb8, 0xcf, 0x04, 0xe2, 0x0b, 0x20, 0x65, 0xaf, 0xe8, 0xa4, 0x9d, - 0xad, 0x5c, 0x27, 0xa4, 0x5d, 0xf1, 0xbc, 0xaa, 0x02, 0x79, 0x91, 0x8f, 0xe1, 0xa1, 0xa6, 0xb4, - 0xba, 0x05, 0x31, 0x69, 0xce, 0x4f, 0xa0, 0x6d, 0x36, 0x96, 0xa9, 0xed, 0x25, 0x6a, 0xbb, 0xcc, - 0x6d, 0xf5, 0x56, 0x32, 0x35, 0x6c, 0x8d, 0x8a, 0x17, 0xb1, 0x09, 0x70, 0xe2, 0x8c, 0x4e, 0x1c, - 0x6e, 0x73, 0xb9, 0x1c, 0xe0, 0x7f, 0x83, 0x70, 0x6a, 0xd1, 0x3c, 0x31, 0x8f, 0xe2, 0x17, 0x70, - 0xc9, 0x48, 0xe1, 0xf3, 0xe3, 0x28, 0xd0, 0x0e, 0xfb, 0xc8, 0x09, 0xa3, 0x2c, 0xd5, 0x1b, 0xe5, - 0x6b, 0x9a, 0xe0, 0x5b, 0xc4, 0xa3, 0x00, 0x3c, 0x20, 0xac, 0x76, 0x58, 0x8f, 0xa0, 0x49, 0xdb, - 0x3c, 0xd4, 0x5b, 0x7e, 0xe8, 0xa1, 0xf2, 0xea, 0x43, 0x0f, 0x1f, 0x42, 0x5b, 0x47, 0x33, 0x2f, - 0x3b, 0x45, 0xd1, 0x62, 0x3c, 0x27, 0x44, 0x6f, 0x41, 0x93, 0x42, 0x19, 0xfa, 0xc6, 0x35, 0x68, - 0xf1, 0x49, 0xbb, 0xa3, 0x20, 0x72, 0x4f, 0x4c, 0xf0, 0x41, 0xa0, 0xbb, 0x08, 0x19, 0x02, 0x34, - 0x9e, 0x84, 0x7e, 0x14, 0x6e, 0x07, 0xc1, 0xf0, 0x4f, 0x35, 0x68, 0xa2, 0xcf, 0x43, 0xfb, 0x52, - 0x18, 0x36, 0x12, 0x63, 0x52, 0x5d, 0xc5, 0xc4, 0x89, 0xf5, 0xb1, 0x8e, 0x16, 0x02, 0x91, 0x6a, - 0xcf, 0x89, 0x67, 0xca, 0x2e, 0x16, 0x66, 0xca, 0x2e, 0xde, 0xe6, 0x73, 0x9f, 0x5c, 0x35, 0x2b, - 0x4d, 0xb9, 0x3d, 0x75, 0x70, 0x97, 0x41, 0xe8, 0x8b, 0x11, 0x89, 0x13, 0x90, 0xff, 0x86, 0xd1, - 0x61, 0xa0, 0x74, 0x85, 0x06, 0xc9, 0xc5, 0xb6, 0x46, 0x1c, 0x48, 0xb6, 0x37, 0xa5, 0xcd, 0xc8, - 0xea, 0xec, 0x66, 0xe4, 0x4d, 0x00, 0x37, 0x0a, 0x3d, 0x72, 0x11, 0x67, 0x12, 0xd2, 0x5c, 0x1e, - 0x51, 0x60, 0x7f, 0xc0, 0x36, 0xf9, 0x7b, 0xd0, 0xcf, 0x29, 0xd0, 0x03, 0x74, 0xc3, 0x3c, 0xbe, - 0xd6, 0x54, 0x96, 0x1c, 0xed, 0x84, 0xe9, 0xec, 0x7e, 0x7a, 0xf3, 0xdc, 0x7e, 0xfa, 0x4b, 0x0a, - 0x69, 0xe0, 0x47, 0x9f, 0x9e, 0xbb, 0x04, 0x0d, 0xaa, 0xd8, 0xf3, 0xb2, 0x58, 0xdb, 0xa2, 0xba, - 0xaf, 0x28, 0xef, 0xf1, 0xb2, 0x3d, 0xfb, 0xf6, 0xff, 0xaf, 0x3d, 0xfb, 0xce, 0x0f, 0xdb, 0xb3, - 0xef, 0xfe, 0xb0, 0x3d, 0xfb, 0x99, 0x3d, 0xee, 0xde, 0xec, 0x1e, 0xf7, 0x4b, 0xd3, 0x8a, 0xfd, - 0x97, 0xa6, 0x15, 0x5f, 0x93, 0x13, 0x5c, 0x7e, 0x75, 0x4e, 0xf0, 0xf5, 0x49, 0x49, 0xf1, 0xba, - 0xa4, 0xe4, 0x0d, 0xe8, 0xa5, 0x89, 0xe3, 0x9e, 0x70, 0xa4, 0x75, 0x22, 0xcf, 0x94, 0x4e, 0x82, - 0x76, 0x08, 0x8c, 0x71, 0xd6, 0x37, 0xf2, 0x4c, 0x0d, 0x9f, 0x00, 0x50, 0x08, 0x4a, 0xbf, 0xf6, - 0x32, 0xde, 0xa8, 0xfc, 0xe8, 0x22, 0xab, 0xbf, 0xae, 0x00, 0x1c, 0x38, 0x93, 0x98, 0xf7, 0x90, - 0xc5, 0x9f, 0x41, 0x4b, 0xd1, 0x5b, 0xb9, 0xc8, 0xa4, 0x64, 0xa8, 0x0b, 0x52, 0xfd, 0xc8, 0x87, - 0xbb, 0x54, 0xfe, 0x4c, 0x6c, 0xcd, 0x3d, 0xe4, 0x05, 0xad, 0x55, 0x43, 0x40, 0x7b, 0x7b, 0xd7, - 0xa1, 0xab, 0x09, 0x62, 0x99, 0xb8, 0x32, 0xe4, 0xfa, 0xfe, 0x8a, 0xd5, 0x61, 0xe8, 0x3e, 0x03, - 0xc5, 0x47, 0x39, 0x99, 0x31, 0x89, 0xe7, 0x53, 0x66, 0xba, 0x89, 0xb6, 0x89, 0xc3, 0x2d, 0xf3, - 0x2b, 0x34, 0x90, 0x06, 0x2c, 0xe1, 0xf7, 0xfa, 0x6f, 0x88, 0x16, 0xd4, 0x75, 0xaf, 0xfd, 0x8a, - 0xe8, 0x40, 0x93, 0x4e, 0x13, 0x12, 0x6e, 0x61, 0xf8, 0x97, 0xab, 0xd0, 0xda, 0x0d, 0x55, 0x9a, - 0x64, 0xcc, 0xc2, 0xc5, 0x99, 0xb9, 0x2a, 0x9d, 0x99, 0xd3, 0x75, 0xe0, 0xfc, 0x1b, 0x54, 0x07, - 0xfe, 0x21, 0xd4, 0xf5, 0xf1, 0x4c, 0x9d, 0x58, 0x98, 0x7b, 0xb6, 0xd3, 0xd0, 0x88, 0x4d, 0x68, - 0x78, 0xfa, 0xdc, 0xa8, 0xae, 0xa4, 0x29, 0x1d, 0xe6, 0x34, 0x27, 0x4a, 0xad, 0x9c, 0x46, 0xbc, - 0x0d, 0x8b, 0xce, 0x78, 0xac, 0xa3, 0xfa, 0x5e, 0x41, 0x4a, 0x4e, 0x9a, 0x85, 0x38, 0x71, 0x1b, - 0x9a, 0xa4, 0x3e, 0xa9, 0xaa, 0xad, 0x36, 0xdb, 0xa7, 0x29, 0x99, 0x63, 0x8d, 0x4a, 0x39, 0x89, - 0xdb, 0xd0, 0x0c, 0xa2, 0x28, 0xe6, 0x06, 0xf5, 0xd9, 0x06, 0xa6, 0xbe, 0xc8, 0x6a, 0x04, 0xa6, - 0xd2, 0xe8, 0x06, 0xd4, 0xd0, 0xfd, 0x8f, 0x62, 0xed, 0x36, 0x97, 0xc6, 0x41, 0x75, 0x36, 0x56, - 0x55, 0x51, 0xb9, 0xcd, 0x16, 0x00, 0xf3, 0x3f, 0xf5, 0xdc, 0x9c, 0x9d, 0x8e, 0x3c, 0xb7, 0x8a, - 0x42, 0x6a, 0xd2, 0xac, 0x77, 0xa1, 0xcf, 0x79, 0xb4, 0x52, 0x4b, 0x30, 0xb5, 0xc0, 0xa6, 0xe5, - 0x74, 0x6a, 0xd6, 0xea, 0x26, 0xd3, 0xa9, 0xda, 0x0f, 0xa0, 0x1e, 0x73, 0x72, 0x88, 0x34, 0x0c, - 0x99, 0x6c, 0xd3, 0x54, 0x67, 0x8d, 0x2c, 0x43, 0x21, 0x7e, 0x0d, 0x5d, 0xae, 0x59, 0x1d, 0xe9, - 0x2c, 0x09, 0xed, 0xec, 0x4d, 0x9d, 0xec, 0x9b, 0x4a, 0xa2, 0x58, 0x9d, 0x74, 0x2a, 0xa7, 0xf2, - 0x4b, 0xe8, 0x14, 0x07, 0x96, 0xd0, 0xe2, 0xf7, 0x4c, 0xb6, 0xc2, 0x34, 0x2f, 0x47, 0x63, 0x56, - 0x5b, 0x96, 0x63, 0xb3, 0x0d, 0xa8, 0xe9, 0x3a, 0xea, 0x3e, 0xb5, 0x2a, 0xdd, 0xba, 0xc0, 0x95, - 0x93, 0x96, 0xc6, 0xe3, 0x5c, 0x16, 0x25, 0xa2, 0xe4, 0x38, 0x4e, 0xcd, 0x65, 0x5e, 0x1f, 0x6a, - 0x35, 0xf3, 0xd2, 0x50, 0x71, 0x7f, 0xba, 0x64, 0x95, 0x93, 0x7a, 0x2b, 0xd4, 0xf4, 0xd2, 0x9c, - 0xa6, 0x9c, 0xde, 0xb3, 0x7a, 0xf1, 0x4c, 0xe5, 0xeb, 0x2d, 0x68, 0x44, 0x89, 0x47, 0xe7, 0x03, - 0xa8, 0x8a, 0x22, 0x77, 0x81, 0xf4, 0x99, 0x54, 0x52, 0x1e, 0xf5, 0x88, 0x5f, 0xd0, 0xb1, 0x88, - 0x93, 0x88, 0xbc, 0x5c, 0x52, 0x71, 0x17, 0xce, 0x3b, 0x16, 0x1a, 0x4f, 0x0a, 0xee, 0x5d, 0xa8, - 0x9b, 0xea, 0xf0, 0xb5, 0x73, 0x94, 0x06, 0x25, 0x3e, 0x86, 0xde, 0xb4, 0x42, 0x53, 0x83, 0x8b, - 0xe7, 0xa8, 0xbb, 0x53, 0xfa, 0x0b, 0xad, 0x71, 0x35, 0xf0, 0x27, 0x7e, 0xaa, 0x7d, 0xbe, 0xa9, - 0x13, 0xa2, 0x84, 0xc0, 0xf8, 0x4f, 0xa7, 0x40, 0x2e, 0x9d, 0x8f, 0xff, 0x74, 0x9a, 0x64, 0x00, - 0x75, 0x5f, 0x3d, 0xf0, 0x13, 0x95, 0xea, 0xfa, 0x06, 0xf3, 0x2a, 0xd6, 0xa0, 0xe6, 0x2b, 0x34, - 0x13, 0xda, 0x4b, 0xd3, 0x6f, 0xe2, 0x26, 0xd4, 0x74, 0xe5, 0xfc, 0xfa, 0x39, 0x89, 0xd6, 0x27, - 0x6b, 0x2c, 0x4d, 0x21, 0xde, 0x87, 0x3a, 0x95, 0x4d, 0x47, 0xf1, 0xe0, 0xed, 0x59, 0x0e, 0xe0, - 0xda, 0x65, 0xab, 0x16, 0x70, 0x0d, 0xf3, 0x07, 0x50, 0x37, 0x4e, 0xca, 0x70, 0x96, 0xab, 0xb5, - 0xb3, 0x62, 0x19, 0x0a, 0x71, 0x1d, 0xaa, 0x13, 0xd4, 0x63, 0x83, 0x77, 0x66, 0x25, 0x94, 0xd5, - 0x1b, 0x63, 0xc5, 0xdf, 0x87, 0xcb, 0xe5, 0xc2, 0x63, 0x53, 0x95, 0xac, 0x37, 0x38, 0xaf, 0x53, - 0xdb, 0xb7, 0xe7, 0xb0, 0xca, 0x74, 0xfd, 0xb2, 0x75, 0x31, 0x7e, 0x49, 0x61, 0xf3, 0xa7, 0xb9, - 0xba, 0x47, 0xe9, 0x1a, 0xdc, 0x30, 0xce, 0xf7, 0x79, 0x83, 0x61, 0x8c, 0x00, 0xd9, 0x99, 0xcf, - 0xa0, 0x3d, 0xca, 0x5e, 0xbc, 0x38, 0x33, 0x9b, 0xf3, 0xef, 0x51, 0xbb, 0xd2, 0x16, 0x43, 0xa9, - 0xd6, 0xd9, 0x6a, 0x8d, 0x4a, 0x85, 0xcf, 0x17, 0xa1, 0xee, 0x86, 0xb6, 0xe3, 0x79, 0xc9, 0x60, - 0x83, 0x6b, 0x9d, 0xdd, 0x70, 0xdb, 0xf3, 0xe8, 0x72, 0x87, 0x28, 0x96, 0x74, 0x42, 0xda, 0xf6, - 0xbd, 0xc1, 0xfb, 0x6c, 0x78, 0x0c, 0x68, 0xd7, 0xa3, 0xdb, 0x1f, 0x4c, 0x5c, 0xee, 0x7b, 0x83, - 0x9b, 0xfa, 0xf6, 0x07, 0x0d, 0xda, 0xf5, 0xd0, 0xf1, 0xc4, 0x20, 0xc6, 0x40, 0x06, 0x1f, 0x70, - 0xc2, 0x63, 0xe2, 0x9c, 0xee, 0x6b, 0x10, 0x0a, 0x29, 0xa7, 0xf6, 0x48, 0x6d, 0xdd, 0x9a, 0x15, - 0xd2, 0x3c, 0x0d, 0x6c, 0x35, 0xfd, 0x3c, 0x23, 0x4c, 0x82, 0x4d, 0xaa, 0xc8, 0x0e, 0xb6, 0x06, - 0x1f, 0x9e, 0x17, 0x6c, 0x9d, 0xe5, 0x46, 0xc1, 0x36, 0x09, 0xef, 0x2d, 0x00, 0xd6, 0x59, 0xa4, - 0x70, 0x36, 0x67, 0xdb, 0xe4, 0xd1, 0x80, 0xc5, 0x47, 0x9a, 0x48, 0xd5, 0x6c, 0x01, 0x50, 0x7a, - 0x81, 0xdb, 0xdc, 0x9e, 0x6d, 0x93, 0x7b, 0xf7, 0x56, 0xf3, 0x59, 0xee, 0xe8, 0xdf, 0x86, 0x66, - 0x86, 0x7e, 0x3c, 0x7a, 0xd2, 0x83, 0x3b, 0xb3, 0xcc, 0x6c, 0x5c, 0x7c, 0xab, 0x91, 0xe9, 0x27, - 0xfc, 0x08, 0xd9, 0x1e, 0x72, 0x43, 0x06, 0x1f, 0xcd, 0x7e, 0x24, 0x8f, 0x03, 0x2c, 0x32, 0x51, - 0x1c, 0x12, 0x7c, 0x0a, 0x2d, 0x9e, 0x34, 0x6e, 0xb4, 0x35, 0xcb, 0x23, 0x85, 0x5f, 0x63, 0xf1, - 0xec, 0x72, 0xb3, 0xeb, 0x50, 0x75, 0xe2, 0x38, 0x38, 0x1b, 0x7c, 0x3c, 0xcb, 0xe1, 0xdb, 0x08, - 0xb6, 0x18, 0x8b, 0xac, 0x34, 0xc9, 0x82, 0xd4, 0x37, 0xa7, 0x90, 0x3e, 0x99, 0x65, 0xa5, 0xd2, - 0xb1, 0x4e, 0xab, 0x35, 0x29, 0x9d, 0xf1, 0xbc, 0x05, 0x8d, 0x38, 0x52, 0xa9, 0xed, 0x4d, 0x82, - 0xc1, 0xa7, 0xe7, 0xcc, 0x08, 0x9f, 0x48, 0xb1, 0xea, 0xb1, 0x3e, 0xd2, 0x33, 0x75, 0x4a, 0xfa, - 0x67, 0x33, 0xa7, 0xa4, 0xb7, 0xa0, 0x3d, 0x89, 0xc2, 0x71, 0xe4, 0x1d, 0xf1, 0xec, 0xff, 0xbc, - 0x1c, 0x14, 0xee, 0x21, 0x86, 0xc3, 0x48, 0x4d, 0xa4, 0x4d, 0x43, 0x5f, 0xfb, 0x6e, 0xbe, 0xb2, - 0x1d, 0x45, 0x6a, 0xff, 0x33, 0x0e, 0xe1, 0x19, 0xbe, 0xab, 0xb6, 0x09, 0x3a, 0xbd, 0xbd, 0x7d, - 0x74, 0xa6, 0x73, 0x91, 0xbf, 0x20, 0xf6, 0x2c, 0xb6, 0xb7, 0xef, 0x9e, 0x71, 0x42, 0xf2, 0x73, - 0xb8, 0x5c, 0x3a, 0xb7, 0x18, 0xc5, 0x76, 0x68, 0xa3, 0x0a, 0x48, 0xa4, 0x97, 0xb9, 0x72, 0xf0, - 0x79, 0x1e, 0x6f, 0xea, 0xc3, 0x8b, 0x51, 0xfc, 0x68, 0x3f, 0x91, 0x16, 0x61, 0xc5, 0xa3, 0xf2, - 0x19, 0x49, 0x27, 0x18, 0x47, 0x89, 0x9f, 0x1e, 0x4f, 0x06, 0xbf, 0x24, 0x3f, 0xf0, 0xcd, 0x52, - 0x3c, 0x90, 0xe7, 0xbf, 0xb6, 0x0d, 0x91, 0x55, 0x8c, 0x31, 0x87, 0x89, 0xcf, 0xe1, 0x92, 0xb6, - 0x05, 0xd8, 0xe1, 0xd4, 0x51, 0x74, 0x35, 0xf8, 0x15, 0x9d, 0x45, 0xbf, 0x58, 0x10, 0x7c, 0x55, - 0x3a, 0x95, 0xae, 0xc4, 0x36, 0xbc, 0x39, 0xaf, 0x2d, 0x3a, 0x26, 0x3c, 0x01, 0x5f, 0xd0, 0x04, - 0x5c, 0x3e, 0xdf, 0xfe, 0x40, 0xea, 0x7b, 0x69, 0x6e, 0x81, 0xc0, 0x09, 0x20, 0xcb, 0x25, 0x3d, - 0x3b, 0xca, 0xd2, 0x38, 0x4b, 0x07, 0xbf, 0xe6, 0x38, 0x31, 0x8d, 0xe2, 0xc7, 0x8c, 0x78, 0x4c, - 0x70, 0x0e, 0xb6, 0x7f, 0xb3, 0xd4, 0x58, 0xee, 0x8b, 0xdf, 0x2c, 0x35, 0xde, 0xed, 0x5f, 0xb7, - 0x5a, 0xa5, 0x8d, 0x85, 0xe1, 0xa7, 0xd0, 0xde, 0xa6, 0xeb, 0x8b, 0x7c, 0x45, 0x86, 0xed, 0x3a, - 0x2c, 0xe5, 0x05, 0x29, 0xb9, 0xc5, 0x24, 0x8a, 0x17, 0x72, 0x37, 0x1c, 0x45, 0x16, 0xa1, 0x87, - 0xff, 0x76, 0x09, 0x6a, 0x5c, 0x24, 0xf0, 0xfa, 0x23, 0x8a, 0x6f, 0x1a, 0xb1, 0x0f, 0x8b, 0xb3, - 0x1c, 0x2c, 0xe1, 0x84, 0x9e, 0xad, 0xd9, 0x6e, 0x16, 0xb5, 0x2e, 0xab, 0x50, 0xe5, 0x58, 0x9d, - 0x53, 0x18, 0xfc, 0x42, 0x2a, 0x2f, 0x53, 0xc7, 0x74, 0x47, 0x91, 0x4e, 0xca, 0x2d, 0x59, 0x60, - 0x40, 0xbb, 0x1e, 0xed, 0x55, 0x1a, 0x02, 0xd2, 0xa9, 0x35, 0x9d, 0x8b, 0xd0, 0x40, 0xd2, 0xac, - 0xa6, 0x8e, 0xa6, 0xfe, 0x92, 0x3a, 0x9a, 0xb7, 0x60, 0x29, 0x34, 0xc7, 0x8c, 0x72, 0x3c, 0xdd, - 0x51, 0x42, 0x70, 0x71, 0x13, 0xf2, 0x73, 0x95, 0xda, 0x47, 0x7c, 0xf9, 0xb9, 0xcb, 0x2d, 0x68, - 0xe6, 0x17, 0x5e, 0x69, 0xb7, 0x70, 0x75, 0xb3, 0xb8, 0x02, 0xeb, 0xd0, 0x3c, 0x59, 0x05, 0xd9, - 0xab, 0xab, 0x41, 0x5a, 0x3f, 0xad, 0x1a, 0x84, 0x63, 0x66, 0x37, 0x0a, 0x55, 0xaa, 0x77, 0x63, - 0xeb, 0xbe, 0xda, 0xc1, 0x57, 0xf1, 0x0b, 0xe8, 0x24, 0xd2, 0x7d, 0x66, 0x4f, 0xd4, 0x98, 0x3f, - 0xd1, 0x29, 0x9f, 0xed, 0x9e, 0xa8, 0xf1, 0xd7, 0x54, 0xa9, 0xa2, 0x43, 0xd8, 0x16, 0xd2, 0xee, - 0xa9, 0x31, 0xf5, 0xfa, 0x01, 0x2c, 0x4f, 0xe4, 0xe4, 0x48, 0x26, 0xea, 0xd8, 0x8f, 0x8d, 0xed, - 0xeb, 0x52, 0x45, 0x4d, 0xbf, 0x40, 0xf0, 0x58, 0x86, 0xff, 0xb8, 0x02, 0x0d, 0x9c, 0x45, 0xe4, - 0x25, 0x21, 0x60, 0x69, 0xe2, 0xc6, 0x99, 0x8e, 0x4c, 0xe8, 0x59, 0x5f, 0xa2, 0xc5, 0x5c, 0xa2, - 0x2f, 0xd1, 0xa2, 0x35, 0xe4, 0x1c, 0x23, 0x3d, 0xf3, 0xbd, 0x28, 0x67, 0xb4, 0x0d, 0xcd, 0x9c, - 0x61, 0x5e, 0xc5, 0x05, 0xa8, 0xb9, 0x21, 0x6d, 0x4f, 0x70, 0xae, 0xb6, 0xea, 0x86, 0x3b, 0x61, - 0xaa, 0xc1, 0xc5, 0x51, 0x95, 0xaa, 0x1b, 0xee, 0x7a, 0xa7, 0xc3, 0xff, 0x50, 0x81, 0xe5, 0xfd, - 0x24, 0x72, 0xa5, 0x52, 0x0f, 0xd1, 0xb3, 0xa2, 0xbc, 0x18, 0x7e, 0x91, 0xd2, 0x08, 0x9c, 0x82, - 0xa2, 0x67, 0xe4, 0x61, 0xde, 0x3b, 0xca, 0xe3, 0xbf, 0x45, 0xab, 0x49, 0x10, 0x0a, 0xff, 0x72, - 0x74, 0xa9, 0xde, 0x82, 0xd1, 0x94, 0x80, 0xb8, 0x0e, 0xdd, 0x42, 0x01, 0x95, 0x4a, 0x43, 0x8a, - 0xdb, 0x0b, 0xa8, 0x97, 0x6b, 0xd0, 0xd2, 0x05, 0x44, 0xd4, 0x0d, 0xe7, 0x94, 0x80, 0x41, 0x07, - 0x7a, 0x14, 0xac, 0xad, 0x09, 0xcf, 0x59, 0x24, 0xd6, 0xdf, 0x88, 0x1e, 0xfe, 0xa1, 0x02, 0xfd, - 0xfd, 0x44, 0xc6, 0x4e, 0x22, 0xa9, 0xa2, 0x88, 0xe6, 0x78, 0x0d, 0x6a, 0x81, 0x0c, 0xc7, 0xba, - 0x88, 0x64, 0xd1, 0xd2, 0x6f, 0xf9, 0x05, 0x68, 0x0b, 0xa5, 0x0b, 0xd0, 0x70, 0xae, 0x13, 0xe9, - 0xe8, 0x7b, 0xd2, 0xe8, 0x19, 0x65, 0x10, 0x83, 0x78, 0x8e, 0x54, 0x1b, 0x16, 0xbf, 0xe8, 0x33, - 0xd2, 0x47, 0x7e, 0x48, 0x95, 0x9b, 0x74, 0x46, 0xfa, 0xae, 0x4f, 0xda, 0x9f, 0xc1, 0xe8, 0x8d, - 0xf1, 0x5d, 0x43, 0xb4, 0xf7, 0xd4, 0xb0, 0xba, 0x44, 0xe0, 0x24, 0x67, 0x07, 0x04, 0xa5, 0x80, - 0x99, 0xaf, 0x28, 0xe2, 0xb2, 0x24, 0xce, 0x7a, 0x74, 0xcc, 0x0d, 0x45, 0xac, 0x5b, 0xd4, 0xf0, - 0x9f, 0xd7, 0xa1, 0xa5, 0x57, 0x88, 0xfe, 0x86, 0xb9, 0xa3, 0x92, 0x73, 0x47, 0x1f, 0x16, 0xd5, - 0xd3, 0x40, 0xb3, 0x0b, 0x3e, 0x8a, 0x8f, 0x61, 0x31, 0xf0, 0x27, 0x3a, 0x8a, 0xbd, 0x32, 0xe5, - 0x91, 0x4c, 0xaf, 0xb3, 0x66, 0x65, 0xa4, 0x46, 0x33, 0x48, 0x17, 0x36, 0xa0, 0xd0, 0xe8, 0xb5, - 0x41, 0xef, 0xe0, 0x14, 0x25, 0x13, 0x67, 0xdd, 0x71, 0xb9, 0x6a, 0x58, 0xab, 0x9b, 0x8e, 0xd5, - 0xd4, 0x90, 0x5d, 0x4f, 0x7c, 0x02, 0x8d, 0x7c, 0xaf, 0xdd, 0xc4, 0xad, 0xe9, 0x69, 0xb8, 0xb9, - 0xf3, 0xe8, 0xf0, 0x34, 0x34, 0x9b, 0xe9, 0xfa, 0x63, 0x39, 0xa5, 0xf8, 0x35, 0xb4, 0x95, 0x54, - 0x8a, 0x4f, 0xd4, 0x8f, 0x22, 0xad, 0x86, 0x2e, 0x94, 0x43, 0x52, 0xc2, 0xe2, 0x5f, 0x1b, 0xa1, - 0x53, 0x05, 0x48, 0x7c, 0x0d, 0x5d, 0xd3, 0x3e, 0x88, 0xc6, 0xe3, 0x3c, 0x17, 0x74, 0xe5, 0x5c, - 0x0f, 0x0f, 0x09, 0x5d, 0xea, 0xa7, 0xa3, 0xca, 0x08, 0xf1, 0x15, 0x74, 0x63, 0x66, 0x1a, 0x5b, - 0x57, 0xc3, 0xb1, 0x3a, 0xbb, 0x3c, 0xe5, 0x40, 0x4f, 0x31, 0x55, 0x71, 0x72, 0xb4, 0x80, 0xab, - 0xf3, 0xb7, 0x4b, 0x70, 0x72, 0x70, 0xfa, 0x76, 0x09, 0x09, 0x6b, 0xfa, 0x3a, 0xa8, 0x51, 0xe2, - 0xd0, 0x29, 0x79, 0xb6, 0x7b, 0xa6, 0xc4, 0xf5, 0xf6, 0xb9, 0x15, 0xc3, 0x0f, 0x6e, 0xf2, 0x2d, - 0x0a, 0x0f, 0x74, 0x13, 0xb2, 0x83, 0xba, 0x5e, 0x68, 0x35, 0x99, 0x83, 0x12, 0x9b, 0xb0, 0xa2, - 0x3f, 0x23, 0x4f, 0xa5, 0x9b, 0xe9, 0x0b, 0x42, 0x48, 0xe9, 0xb5, 0xad, 0x65, 0x46, 0xdd, 0x37, - 0x98, 0x5d, 0x4f, 0x7c, 0x06, 0x03, 0x95, 0x3a, 0xa9, 0xa4, 0x01, 0x19, 0xbd, 0xeb, 0x8f, 0xc3, - 0x28, 0x91, 0xba, 0xc6, 0x66, 0x2d, 0xc7, 0x6b, 0x7d, 0xbb, 0x4b, 0x58, 0xf1, 0x6b, 0xe8, 0xa3, - 0x8a, 0xcc, 0xf3, 0x2d, 0x76, 0xaa, 0x74, 0x28, 0x3e, 0x5f, 0xc5, 0x77, 0x91, 0xda, 0xb0, 0xc5, - 0x21, 0xe5, 0xed, 0xa9, 0xfd, 0x58, 0x86, 0xe8, 0xd4, 0x93, 0x86, 0x90, 0x99, 0x92, 0x9e, 0xbe, - 0x03, 0x66, 0x15, 0xb1, 0x5f, 0xe5, 0x48, 0x8b, 0x70, 0xe8, 0x46, 0x18, 0xf1, 0xd1, 0xdb, 0xad, - 0xe4, 0xc0, 0x16, 0xce, 0x4d, 0x9f, 0xd8, 0xf4, 0xb2, 0x96, 0x26, 0xa6, 0x41, 0x3f, 0x36, 0xf7, - 0x62, 0x2e, 0x7f, 0x05, 0x97, 0x5e, 0x3a, 0xab, 0xaf, 0x2b, 0xfa, 0xe9, 0x94, 0x6f, 0x2c, 0xf8, - 0x3f, 0x8b, 0xd0, 0x2a, 0x71, 0x2b, 0x5d, 0x7b, 0xa8, 0x64, 0x62, 0x4a, 0xfb, 0xf0, 0x19, 0x61, - 0xc7, 0x91, 0x32, 0x95, 0x6a, 0xf4, 0x8c, 0xb0, 0x24, 0xca, 0x2b, 0x76, 0xe8, 0x19, 0x79, 0x48, - 0xef, 0x31, 0xe9, 0x15, 0x5b, 0xe2, 0x9b, 0x36, 0x0a, 0xe0, 0xae, 0x47, 0xf7, 0x23, 0x3a, 0xa9, - 0x73, 0xe4, 0x28, 0x53, 0xa3, 0x99, 0xbf, 0xa3, 0x69, 0x78, 0x26, 0x13, 0x1c, 0x8b, 0xa9, 0x50, - 0xd0, 0xaf, 0x28, 0xe3, 0xb4, 0xaa, 0x2f, 0xa2, 0x90, 0xab, 0x13, 0xda, 0x56, 0x03, 0x01, 0xdf, - 0x45, 0x21, 0x35, 0xd3, 0x12, 0xad, 0xab, 0x6c, 0xcc, 0x2b, 0xda, 0xcc, 0xa7, 0x99, 0xc4, 0xe0, - 0xd2, 0xa3, 0x13, 0x89, 0x4d, 0xab, 0x4e, 0xef, 0x5c, 0xf8, 0x43, 0x51, 0xf0, 0x73, 0xc7, 0x4f, - 0x49, 0x75, 0x44, 0x59, 0xaa, 0x99, 0xbe, 0x87, 0x88, 0x6f, 0x1d, 0x3f, 0x3d, 0x64, 0xb0, 0xf8, - 0x48, 0x1f, 0x34, 0x2e, 0xd3, 0xd2, 0x4d, 0x3f, 0xbc, 0x77, 0x2d, 0x66, 0xe8, 0x0f, 0x24, 0x5d, - 0x66, 0x37, 0x71, 0xd2, 0xc4, 0x3f, 0x8d, 0x42, 0xf4, 0x9d, 0xe8, 0x50, 0x7f, 0x7e, 0x27, 0x63, - 0xc3, 0x5a, 0xc9, 0x91, 0x8f, 0x08, 0x47, 0xe9, 0xdc, 0x27, 0xb0, 0x21, 0x4f, 0xe3, 0xc0, 0x77, - 0xfd, 0x99, 0xcb, 0x09, 0x6c, 0xd7, 0x51, 0xa9, 0x9d, 0xc8, 0x34, 0x4b, 0x42, 0x45, 0xdb, 0xb2, - 0x9a, 0xaf, 0xdf, 0x31, 0xf4, 0xe5, 0x0b, 0x0b, 0x76, 0x1c, 0x95, 0x5a, 0x4c, 0xfb, 0x28, 0x0b, - 0x02, 0x9c, 0x84, 0x3c, 0x8d, 0xcc, 0x15, 0x64, 0x75, 0xc5, 0x09, 0xe4, 0xe1, 0x7f, 0xa9, 0xc0, - 0xf2, 0x39, 0x4d, 0x83, 0x01, 0x2d, 0x6a, 0x19, 0x53, 0xf5, 0xd2, 0xb6, 0x6a, 0xf8, 0xba, 0xeb, - 0x11, 0x22, 0x9d, 0xa4, 0xa6, 0xde, 0x05, 0x11, 0xe9, 0x04, 0xd5, 0xe8, 0x05, 0xa8, 0xa5, 0xa7, - 0xb4, 0xe4, 0x6c, 0x7d, 0xaa, 0xe9, 0x29, 0xae, 0xf5, 0x36, 0x34, 0x83, 0x68, 0x6c, 0x07, 0xf2, - 0x99, 0xe4, 0x1b, 0x63, 0xba, 0x5b, 0xef, 0xbe, 0x42, 0xc5, 0x6d, 0x3e, 0x8c, 0xc6, 0x0f, 0x91, - 0xd6, 0x6a, 0x04, 0xfa, 0x69, 0xf8, 0x1b, 0x68, 0x18, 0xa8, 0x68, 0x42, 0xf5, 0x9e, 0x3c, 0xca, - 0xc6, 0xfd, 0x37, 0x44, 0x03, 0x96, 0xb0, 0x45, 0xbf, 0x82, 0x4f, 0xdf, 0x3a, 0x49, 0xd8, 0x5f, - 0x40, 0xf4, 0xfd, 0x24, 0x89, 0x92, 0xfe, 0x22, 0x3e, 0xee, 0x3b, 0xa1, 0xef, 0xf6, 0x97, 0xf0, - 0xf1, 0x81, 0x93, 0x3a, 0x41, 0xbf, 0x3a, 0xfc, 0x7d, 0x15, 0x1a, 0xfb, 0xfa, 0xeb, 0xe2, 0x1e, - 0x74, 0xf2, 0x9b, 0x17, 0xe7, 0xef, 0x2c, 0xef, 0xcf, 0x3e, 0xd0, 0xce, 0x72, 0x3b, 0x2e, 0xbd, - 0xcd, 0xde, 0xdf, 0xb8, 0x70, 0xee, 0xfe, 0xc6, 0xab, 0xb0, 0xf8, 0x34, 0x39, 0x9b, 0x2e, 0xf8, - 0xde, 0x0f, 0x9c, 0xd0, 0x42, 0xb0, 0xf8, 0x08, 0x5a, 0x94, 0xd3, 0x66, 0x33, 0xaa, 0x77, 0x63, - 0xcb, 0x57, 0xa5, 0x72, 0x29, 0x2f, 0x20, 0x91, 0xf6, 0xd8, 0x37, 0xa1, 0xe1, 0x1e, 0xfb, 0x81, - 0x97, 0xc8, 0x50, 0x1f, 0xbc, 0x10, 0xe7, 0x87, 0x6c, 0xe5, 0x34, 0xe2, 0xcf, 0xa0, 0xef, 0x17, - 0xbb, 0xc9, 0x45, 0x09, 0xc3, 0x94, 0xbd, 0x2a, 0xed, 0x37, 0x5b, 0xbd, 0x12, 0x39, 0xb9, 0x88, - 0xc5, 0x95, 0x2a, 0xf5, 0xf2, 0x95, 0x2a, 0x7c, 0xa3, 0x1e, 0xf9, 0x71, 0x8d, 0x7c, 0x2f, 0x0a, - 0xdd, 0xb8, 0x1b, 0xda, 0xf9, 0x6e, 0xce, 0x06, 0xef, 0xc6, 0x75, 0xd4, 0x4e, 0xf8, 0xbb, 0xd0, - 0x45, 0xa7, 0xde, 0xe6, 0x58, 0x00, 0xed, 0x28, 0xe8, 0x1b, 0xa0, 0x32, 0x75, 0x7c, 0x0f, 0xa3, - 0x01, 0x64, 0xc6, 0xeb, 0xd0, 0x35, 0xff, 0xa2, 0x83, 0xac, 0x96, 0x2e, 0x71, 0xd0, 0x50, 0x8e, - 0xab, 0x36, 0x61, 0xc5, 0x3d, 0x76, 0xc2, 0x50, 0x06, 0xf6, 0x51, 0x36, 0x1a, 0x19, 0x37, 0x8c, - 0xaf, 0x05, 0x5b, 0xd6, 0xa8, 0xbb, 0x84, 0x21, 0x6f, 0x6c, 0x08, 0x9d, 0xd0, 0x0f, 0xcc, 0xd5, - 0xa0, 0x21, 0xbb, 0xcc, 0x55, 0xab, 0x15, 0xfa, 0x01, 0x5f, 0x06, 0x4a, 0x77, 0x98, 0xf6, 0xb3, - 0xcc, 0xf7, 0x94, 0x9d, 0x46, 0xe6, 0x32, 0x42, 0x9d, 0x17, 0x2a, 0xed, 0xb4, 0x3e, 0xc9, 0x7c, - 0xef, 0x30, 0xd2, 0xd7, 0x11, 0x76, 0x88, 0xde, 0xbc, 0x0e, 0xbf, 0x84, 0x76, 0x99, 0x77, 0x90, - 0x17, 0x69, 0x2b, 0xac, 0xff, 0x86, 0x00, 0xa8, 0x3d, 0x8a, 0x92, 0x89, 0x13, 0xf4, 0x2b, 0xf8, - 0xcc, 0xca, 0xbc, 0xbf, 0x20, 0xda, 0xd0, 0x30, 0x5b, 0x3b, 0xfd, 0x45, 0x9d, 0x6c, 0xfd, 0x25, - 0x34, 0xcc, 0x1d, 0x8b, 0x74, 0x3f, 0x5d, 0xe4, 0x49, 0x0e, 0x8d, 0x74, 0x65, 0x31, 0x02, 0x28, - 0x2c, 0x32, 0x77, 0xd6, 0x2e, 0x14, 0x77, 0xd6, 0x0e, 0x7f, 0x0b, 0xed, 0xf2, 0x10, 0x4d, 0xfa, - 0xa0, 0x52, 0xa4, 0x0f, 0xe6, 0xb4, 0xa2, 0x8a, 0x97, 0x24, 0x9a, 0xd8, 0x25, 0xef, 0xbd, 0x81, - 0x00, 0xfc, 0xcc, 0xf0, 0x1f, 0x2d, 0x40, 0x95, 0x36, 0x3c, 0xc8, 0xbb, 0xc2, 0x87, 0x42, 0x82, - 0xaa, 0x56, 0x93, 0x20, 0xff, 0x0f, 0x87, 0x7d, 0xf3, 0x74, 0xf2, 0xd2, 0xab, 0xd3, 0xc9, 0xdb, - 0xb0, 0xfc, 0xac, 0x74, 0x2f, 0x2a, 0x6f, 0x73, 0x54, 0x8d, 0x2b, 0x86, 0x6d, 0xfe, 0xbc, 0xb8, - 0x1f, 0x95, 0x36, 0x3b, 0x7a, 0xcf, 0xa6, 0x01, 0xe2, 0x6d, 0xd0, 0xe7, 0x26, 0x6c, 0x2e, 0x57, - 0xe2, 0xda, 0x9e, 0x16, 0xc3, 0xb6, 0xa9, 0x38, 0x09, 0x03, 0xe0, 0xd3, 0xd0, 0x5c, 0x96, 0xc3, - 0xe5, 0x5c, 0xcd, 0xf4, 0x34, 0xe4, 0x02, 0xa3, 0xe1, 0x04, 0x56, 0xe6, 0x1c, 0xf2, 0x12, 0xeb, - 0xd0, 0x9e, 0x4a, 0xba, 0xf1, 0xc9, 0x0b, 0x70, 0x8b, 0x2c, 0xdb, 0x27, 0xb0, 0x26, 0x03, 0x7f, - 0xec, 0x1f, 0xf9, 0x54, 0xd3, 0x5a, 0x3a, 0x77, 0xc6, 0x4a, 0x64, 0xb5, 0x84, 0xcd, 0xcf, 0x9d, - 0xdd, 0xfc, 0x77, 0x15, 0xa8, 0xf1, 0xdd, 0xc8, 0x62, 0x19, 0x3a, 0x4f, 0xc2, 0x93, 0x30, 0x7a, - 0x1e, 0x32, 0xa0, 0xff, 0x86, 0x58, 0x81, 0x9e, 0xe1, 0x37, 0x7d, 0x09, 0x73, 0xbf, 0x22, 0xfa, - 0xd0, 0x26, 0x8e, 0x36, 0x90, 0x05, 0x71, 0x15, 0x06, 0xda, 0x29, 0xbc, 0x87, 0x06, 0x28, 0x4a, - 0xfd, 0xd1, 0x99, 0xc1, 0x2e, 0x8a, 0x1e, 0xb4, 0x0e, 0xd2, 0x28, 0x3e, 0x90, 0xa1, 0xe7, 0x87, - 0xe3, 0xfe, 0x92, 0x18, 0xc0, 0xaa, 0xe9, 0x95, 0x0b, 0x17, 0x1e, 0xf8, 0xa1, 0xaf, 0x8e, 0xfb, - 0x55, 0x71, 0x05, 0x2e, 0xce, 0xc3, 0x6c, 0xbb, 0x27, 0xfd, 0x9a, 0x58, 0x85, 0xbe, 0x41, 0xde, - 0xd5, 0x37, 0xe1, 0xf6, 0xeb, 0x37, 0x3f, 0x01, 0x71, 0xfe, 0x12, 0x62, 0xfc, 0xe6, 0x43, 0x39, - 0x76, 0xdc, 0xb3, 0x9d, 0x20, 0x52, 0x28, 0x1e, 0x1d, 0x68, 0x16, 0x7d, 0x55, 0x6e, 0x3e, 0x80, - 0x1a, 0xdf, 0x1a, 0x5d, 0xfa, 0x6b, 0x06, 0xf4, 0xdf, 0xc0, 0xc6, 0x68, 0x7c, 0xfd, 0x70, 0xfc, - 0x48, 0x9e, 0xa6, 0x6c, 0x12, 0x1e, 0x3a, 0x2a, 0xed, 0x2f, 0x88, 0x2e, 0x80, 0xfe, 0xb1, 0xfb, - 0xa1, 0xd7, 0x5f, 0xbc, 0xbb, 0xf3, 0x57, 0x7f, 0x7c, 0xab, 0xf2, 0x87, 0x3f, 0xbe, 0x55, 0xf9, - 0xcf, 0x7f, 0x7c, 0xeb, 0x8d, 0xdf, 0xfd, 0xe9, 0xad, 0xca, 0x77, 0x1f, 0x95, 0xee, 0xc4, 0xd6, - 0x36, 0x99, 0x6a, 0xb5, 0x6e, 0xe7, 0x06, 0xfa, 0x76, 0x7c, 0x32, 0xbe, 0x1d, 0x1f, 0xdd, 0x36, - 0x12, 0x7f, 0x54, 0xa3, 0xab, 0xae, 0x3f, 0xfe, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x95, - 0xf9, 0x59, 0x69, 0x5b, 0x00, 0x00, + // 8763 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbc, 0x4d, 0x6c, 0x1d, 0x47, + 0xb6, 0x18, 0xec, 0x4b, 0xf2, 0xfe, 0x9d, 0xfb, 0xcb, 0x22, 0x45, 0x5d, 0xfd, 0xd8, 0xa2, 0xaf, + 0x2d, 0x99, 0x96, 0x65, 0x4a, 0xa6, 0xed, 0x19, 0xdb, 0x33, 0x1e, 0x3f, 0x8a, 0x92, 0x6c, 0x8e, + 0x45, 0x89, 0xd3, 0xa4, 0x9e, 0x01, 0x03, 0xdf, 0xd7, 0x68, 0x76, 0xd7, 0xbd, 0x6c, 0xb3, 0x6f, + 0x77, 0xab, 0xab, 0x5b, 0x22, 0xb5, 0x4a, 0x96, 0x09, 0xb2, 0xcf, 0x43, 0x56, 0x13, 0x24, 0x8b, + 0x04, 0x59, 0x06, 0x2f, 0xcb, 0xac, 0x1f, 0x82, 0x2c, 0x66, 0x95, 0x55, 0x10, 0x04, 0x33, 0xcb, + 0x00, 0x49, 0x10, 0x20, 0x41, 0x80, 0xe0, 0x01, 0xc1, 0x39, 0xa7, 0xaa, 0xbb, 0xef, 0xe5, 0x95, + 0x64, 0x3b, 0xc1, 0xdb, 0xe4, 0xed, 0xba, 0xcf, 0x39, 0x55, 0x5d, 0x5d, 0x75, 0x7e, 0xeb, 0x9c, + 0x2a, 0xe8, 0xc6, 0x7e, 0x2c, 0x03, 0x3f, 0x94, 0x9b, 0x71, 0x12, 0xa5, 0x91, 0x68, 0x98, 0xf7, + 0xcb, 0x1f, 0x8e, 0xfd, 0xf4, 0x38, 0x3b, 0xda, 0x74, 0xa3, 0xc9, 0xed, 0x71, 0x34, 0x8e, 0x6e, + 0x13, 0xc1, 0x51, 0x36, 0xa2, 0x37, 0x7a, 0xa1, 0x27, 0x6e, 0x78, 0x19, 0x82, 0xc8, 0x3d, 0x31, + 0xcf, 0x71, 0xe0, 0x84, 0xfa, 0xb9, 0x97, 0xfa, 0x13, 0xa9, 0x52, 0x67, 0x12, 0x6b, 0x40, 0x33, + 0x3d, 0xd5, 0xb8, 0xe1, 0xef, 0x6b, 0x50, 0xdf, 0x93, 0x4a, 0x39, 0x63, 0x29, 0x86, 0xb0, 0xa8, + 0x7c, 0x6f, 0x50, 0x59, 0xaf, 0x6c, 0x74, 0xb7, 0xfa, 0x9b, 0xf9, 0xb0, 0x0e, 0x52, 0x27, 0xcd, + 0x94, 0x85, 0x48, 0xa4, 0x71, 0x27, 0xde, 0x60, 0x61, 0x96, 0x66, 0x4f, 0xa6, 0xc7, 0x91, 0x67, + 0x21, 0x52, 0xf4, 0x61, 0x51, 0x26, 0xc9, 0x60, 0x71, 0xbd, 0xb2, 0xd1, 0xb6, 0xf0, 0x51, 0x08, + 0x58, 0xf2, 0x9c, 0xd4, 0x19, 0x2c, 0x11, 0x88, 0x9e, 0xc5, 0xbb, 0xd0, 0x8d, 0x93, 0xc8, 0xb5, + 0xfd, 0x70, 0x14, 0xd9, 0x84, 0xad, 0x12, 0xb6, 0x8d, 0xd0, 0xdd, 0x70, 0x14, 0xdd, 0x43, 0xaa, + 0x01, 0xd4, 0x9d, 0xd0, 0x09, 0xce, 0x94, 0x1c, 0xd4, 0x08, 0x6d, 0x5e, 0x45, 0x17, 0x16, 0x7c, + 0x6f, 0x50, 0x5f, 0xaf, 0x6c, 0x2c, 0x59, 0x0b, 0xbe, 0x87, 0xdf, 0xc8, 0x32, 0xdf, 0x1b, 0x34, + 0xf8, 0x1b, 0xf8, 0x2c, 0x86, 0xd0, 0x0e, 0xa5, 0xf4, 0x1e, 0x45, 0xa9, 0x25, 0xe3, 0xe0, 0x6c, + 0xd0, 0x5c, 0xaf, 0x6c, 0x34, 0xac, 0x29, 0x98, 0xb8, 0x0c, 0x0d, 0x4f, 0x1e, 0x65, 0xe3, 0x3d, + 0x35, 0x1e, 0xc0, 0x7a, 0x65, 0xa3, 0x69, 0xe5, 0xef, 0xe2, 0x10, 0x2e, 0x26, 0xf2, 0x69, 0x26, + 0x55, 0x2a, 0x3d, 0x3b, 0x95, 0x4e, 0xe2, 0x45, 0xcf, 0x43, 0x7b, 0x12, 0x79, 0x72, 0xd0, 0xa2, + 0x19, 0xb8, 0x5a, 0x9e, 0xa5, 0x44, 0x3a, 0x93, 0x43, 0x4d, 0xb4, 0x17, 0x79, 0xd2, 0xba, 0x90, + 0x37, 0x2e, 0x83, 0x85, 0x05, 0x6b, 0x8e, 0xeb, 0xca, 0xf8, 0x7c, 0xa7, 0xed, 0x1f, 0xd1, 0xe9, + 0xaa, 0x69, 0x3b, 0xd5, 0xe7, 0x57, 0x70, 0xb5, 0x18, 0xe9, 0x91, 0x93, 0xba, 0xc7, 0xb6, 0x9b, + 0x48, 0xcf, 0x4f, 0x6d, 0x37, 0xca, 0xc2, 0x74, 0xd0, 0x59, 0xaf, 0x6c, 0x74, 0xac, 0x4b, 0x39, + 0xcd, 0x5d, 0x24, 0xd9, 0x21, 0x8a, 0x1d, 0x24, 0x78, 0x45, 0x07, 0x47, 0x67, 0xa9, 0x54, 0x83, + 0x2e, 0x4d, 0xf4, 0xdc, 0x0e, 0xee, 0x22, 0x81, 0xf8, 0x12, 0xae, 0xe4, 0x7f, 0x35, 0x67, 0x00, + 0x3d, 0x1a, 0xc0, 0xc0, 0x90, 0x9c, 0xfb, 0xfe, 0x4b, 0x9b, 0xf3, 0xe7, 0xfb, 0xf4, 0xf9, 0x79, + 0xcd, 0xf9, 0xeb, 0xd7, 0xa1, 0xcb, 0xad, 0x14, 0x0e, 0x30, 0x74, 0xe5, 0x60, 0x99, 0x5a, 0x74, + 0x08, 0x7a, 0xa0, 0x81, 0xe2, 0x16, 0x08, 0x26, 0x73, 0xdc, 0x93, 0x82, 0x54, 0x10, 0x69, 0x9f, + 0x30, 0xdb, 0xee, 0x89, 0xa1, 0xfe, 0x62, 0xe9, 0x2f, 0x7e, 0x7f, 0xed, 0x8d, 0xe1, 0x13, 0x68, + 0xee, 0x44, 0x61, 0x28, 0xdd, 0x34, 0x4a, 0xc4, 0x35, 0x68, 0x99, 0xc5, 0xb1, 0xb5, 0xac, 0x54, + 0x2d, 0x30, 0xa0, 0x5d, 0x4f, 0xbc, 0x07, 0x3d, 0xd7, 0x50, 0xdb, 0x7e, 0xe8, 0xc9, 0x53, 0x12, + 0x96, 0xaa, 0xd5, 0xcd, 0xc1, 0xbb, 0x08, 0x1d, 0xfe, 0xe7, 0x45, 0xa8, 0x1f, 0x1c, 0x67, 0xa3, + 0x51, 0x20, 0xc5, 0xbb, 0xd0, 0xd1, 0x8f, 0x3b, 0x51, 0xb0, 0xeb, 0x9d, 0xea, 0x7e, 0xa7, 0x81, + 0x62, 0x1d, 0x5a, 0x1a, 0x70, 0x78, 0x16, 0x4b, 0xdd, 0x6d, 0x19, 0x34, 0xdd, 0xcf, 0x9e, 0x1f, + 0x92, 0x0c, 0x2e, 0x5a, 0xd3, 0xc0, 0x19, 0x2a, 0xe7, 0x94, 0xc4, 0x72, 0x9a, 0xca, 0xa1, 0xaf, + 0x6d, 0x07, 0xfe, 0x33, 0x69, 0xc9, 0xf1, 0x4e, 0x98, 0x92, 0x70, 0x56, 0xad, 0x32, 0x48, 0x6c, + 0xc1, 0x05, 0xc5, 0x4d, 0xec, 0xc4, 0x09, 0xc7, 0x52, 0xd9, 0x99, 0x1f, 0xa6, 0xbf, 0xf8, 0x64, + 0x50, 0x5b, 0x5f, 0xdc, 0x58, 0xb2, 0x56, 0x34, 0xd2, 0x22, 0xdc, 0x13, 0x42, 0x89, 0x3b, 0xb0, + 0x3a, 0xd3, 0x86, 0x9b, 0xd4, 0xd7, 0x17, 0x37, 0x16, 0x2d, 0x31, 0xd5, 0x64, 0x97, 0x5a, 0xdc, + 0x87, 0xe5, 0x24, 0x0b, 0x51, 0x85, 0x3d, 0xf0, 0x83, 0x54, 0x26, 0x07, 0xb1, 0x74, 0x49, 0xc8, + 0x5b, 0x5b, 0x17, 0x37, 0x49, 0xcb, 0x59, 0xb3, 0x68, 0xeb, 0x7c, 0x0b, 0x71, 0x2b, 0x9f, 0xbc, + 0xfb, 0xa7, 0x71, 0x42, 0x9a, 0xa0, 0xb5, 0x05, 0xdc, 0x01, 0x42, 0xac, 0x32, 0x5a, 0xdc, 0x84, + 0x65, 0x2f, 0x71, 0xfc, 0xd0, 0x76, 0x82, 0xc0, 0x3e, 0xca, 0xdc, 0x13, 0x99, 0x2a, 0xd2, 0x0e, + 0x0d, 0xab, 0x47, 0x88, 0xed, 0x20, 0xb8, 0xcb, 0x60, 0x71, 0x03, 0x7a, 0x2a, 0x4d, 0xfc, 0x70, + 0x6c, 0x1f, 0x3b, 0xea, 0xd8, 0x3e, 0x91, 0x67, 0xa4, 0x1c, 0x1a, 0x56, 0x87, 0xc1, 0xdf, 0x38, + 0xea, 0xf8, 0x5b, 0x79, 0x36, 0xfc, 0x9f, 0x0b, 0xd0, 0xb8, 0xe7, 0xab, 0x18, 0xb9, 0x4c, 0x5c, + 0x84, 0xfa, 0x28, 0x0b, 0xdd, 0x82, 0x87, 0x6a, 0xf8, 0xba, 0xeb, 0x89, 0x5f, 0x43, 0x2f, 0x88, + 0x5c, 0x27, 0xb0, 0x73, 0x76, 0x19, 0x2c, 0xac, 0x2f, 0x6e, 0xb4, 0xb6, 0x56, 0x0a, 0xad, 0x90, + 0xb3, 0xa3, 0xd5, 0x25, 0xda, 0x82, 0x3d, 0xbf, 0x84, 0x7e, 0x22, 0x27, 0x51, 0x2a, 0x4b, 0xcd, + 0x17, 0xa9, 0xb9, 0x28, 0x9a, 0x7f, 0x97, 0x38, 0xf1, 0x23, 0x54, 0x25, 0x3d, 0xa6, 0x2d, 0x9a, + 0x7f, 0x54, 0x5a, 0x51, 0x39, 0xb6, 0x7d, 0xef, 0xd4, 0xa6, 0x0f, 0x0c, 0x96, 0xd6, 0x17, 0x37, + 0xaa, 0xc5, 0xf2, 0xc8, 0xf1, 0xae, 0x77, 0xfa, 0x10, 0x31, 0xe2, 0x63, 0x58, 0x9b, 0x6d, 0xc2, + 0xbd, 0x0e, 0xaa, 0xd4, 0x66, 0x65, 0xaa, 0x8d, 0x45, 0x28, 0xf1, 0x36, 0xb4, 0x4d, 0xa3, 0x14, + 0x59, 0xb9, 0xc6, 0xcc, 0xa5, 0x4a, 0xac, 0x7c, 0x11, 0xea, 0xbe, 0xb2, 0x95, 0x1f, 0x9e, 0x90, + 0x8e, 0x6f, 0x58, 0x35, 0x5f, 0x1d, 0xf8, 0xe1, 0x89, 0xb8, 0x04, 0x8d, 0x44, 0xba, 0x8c, 0x69, + 0x10, 0xa6, 0x9e, 0x48, 0x97, 0x50, 0x17, 0x01, 0x1f, 0x6d, 0x37, 0x95, 0x5a, 0xd3, 0xd7, 0x12, + 0xe9, 0xee, 0xa4, 0x72, 0xa8, 0xa0, 0xba, 0x27, 0x93, 0xb1, 0x44, 0x65, 0x8f, 0x0d, 0x0f, 0x5c, + 0x27, 0xa4, 0x79, 0x6f, 0x58, 0xf9, 0x3b, 0x9a, 0x9a, 0xd8, 0x49, 0x52, 0xdf, 0x09, 0x48, 0xb4, + 0x1a, 0x96, 0x79, 0x15, 0x57, 0xa0, 0xa9, 0x52, 0x27, 0x49, 0xf1, 0xef, 0x48, 0xa4, 0xaa, 0x56, + 0x83, 0x00, 0x28, 0x95, 0x17, 0xa1, 0x2e, 0x43, 0x8f, 0x50, 0x4b, 0xbc, 0x92, 0x32, 0xf4, 0x76, + 0xbd, 0xd3, 0xe1, 0xbf, 0xac, 0x40, 0x67, 0x2f, 0x0b, 0x52, 0x7f, 0x3b, 0x19, 0x67, 0x72, 0x12, + 0xa6, 0x68, 0xa2, 0xee, 0xf9, 0x2a, 0xd5, 0x5f, 0xa6, 0x67, 0xb1, 0x01, 0xcd, 0xaf, 0x93, 0x28, + 0x8b, 0x89, 0x2b, 0x79, 0xa5, 0xcb, 0x5c, 0x59, 0x20, 0x91, 0x83, 0x1f, 0x27, 0x9e, 0x4c, 0xee, + 0x9e, 0x11, 0xed, 0xe2, 0x39, 0xda, 0x32, 0x5a, 0x5c, 0x85, 0xe6, 0x81, 0x8c, 0x9d, 0xc4, 0x41, + 0x16, 0x58, 0x22, 0xbb, 0x56, 0x00, 0xf0, 0x5f, 0x89, 0x78, 0xd7, 0xd3, 0x82, 0x6d, 0x5e, 0x87, + 0xff, 0xa4, 0x02, 0xcd, 0xed, 0xf1, 0x38, 0x91, 0x63, 0x27, 0x25, 0x23, 0x1b, 0xc5, 0x34, 0xde, + 0x45, 0x6b, 0x21, 0x8a, 0xc9, 0x90, 0xe3, 0x1f, 0xf0, 0x04, 0xd1, 0xb3, 0x78, 0x0b, 0x96, 0xe4, + 0xfc, 0x01, 0x11, 0x5c, 0xac, 0x41, 0xcd, 0x8d, 0xc2, 0x91, 0x3f, 0xd6, 0xe6, 0x5f, 0xbf, 0x89, + 0x2f, 0xa0, 0xc5, 0x4f, 0xcc, 0x03, 0x55, 0xb2, 0x7d, 0x97, 0xb8, 0x79, 0x3e, 0x82, 0x1d, 0xa2, + 0x40, 0x8e, 0xb0, 0xc0, 0xcd, 0x9f, 0x87, 0x7f, 0x5a, 0x82, 0x2a, 0xcd, 0x0c, 0xae, 0x0d, 0x9a, + 0x73, 0x5b, 0x3e, 0x73, 0x02, 0xb3, 0xa4, 0x08, 0xb8, 0xff, 0xcc, 0x09, 0xc4, 0x3a, 0x54, 0x71, + 0x08, 0x6a, 0xce, 0xc4, 0x32, 0x42, 0xdc, 0x80, 0x2a, 0x7e, 0x5d, 0x4d, 0x8f, 0x1e, 0xbf, 0x71, + 0x77, 0xe9, 0xaf, 0xfe, 0xc3, 0xb5, 0x37, 0x2c, 0x46, 0x8b, 0xf7, 0x60, 0xc9, 0x19, 0x8f, 0x15, + 0x09, 0xc2, 0x94, 0x2c, 0xe6, 0x23, 0xb5, 0x88, 0x40, 0x7c, 0x0a, 0x4d, 0x5e, 0x74, 0xa4, 0xae, + 0x12, 0xf5, 0xc5, 0x92, 0x9b, 0x54, 0xe6, 0x07, 0xab, 0xa0, 0xc4, 0xe5, 0xf2, 0x95, 0xd6, 0x40, + 0x24, 0x0e, 0x0d, 0xab, 0x00, 0xa0, 0x1f, 0x13, 0x27, 0x72, 0x3b, 0x08, 0x22, 0xf7, 0xc0, 0x7f, + 0x21, 0xb5, 0xd7, 0x33, 0x05, 0x13, 0x37, 0xa0, 0xbb, 0xcf, 0xfc, 0x6a, 0x49, 0x95, 0x05, 0xa9, + 0xd2, 0x9e, 0xd0, 0x0c, 0x54, 0x6c, 0x82, 0x98, 0x82, 0x1c, 0xd2, 0xef, 0x37, 0xd7, 0x17, 0x37, + 0x3a, 0xd6, 0x1c, 0x8c, 0x78, 0x07, 0x3a, 0x63, 0x9c, 0x69, 0x54, 0x70, 0xa3, 0xc0, 0x41, 0x27, + 0x69, 0x11, 0x9d, 0x28, 0x03, 0x7c, 0x10, 0x38, 0x63, 0x92, 0x90, 0xd8, 0x0f, 0x02, 0x7b, 0x22, + 0x27, 0xa4, 0xfd, 0x16, 0xad, 0x06, 0x01, 0xf6, 0xe4, 0x44, 0xbc, 0x0f, 0xcb, 0x44, 0x6c, 0x1f, + 0x9d, 0x15, 0x2a, 0xb2, 0x4d, 0xda, 0xa1, 0x4b, 0x88, 0xbb, 0x67, 0x5a, 0x47, 0x8a, 0xf7, 0xa1, + 0xef, 0x9d, 0x85, 0xce, 0xc4, 0x77, 0x6d, 0xd3, 0x3f, 0xb9, 0x2e, 0xa8, 0x76, 0x19, 0xfe, 0xb5, + 0x06, 0xa3, 0xe2, 0x91, 0x93, 0x38, 0x3d, 0xcb, 0x09, 0x6d, 0x25, 0x51, 0x42, 0xd1, 0x55, 0x41, + 0x5b, 0xb2, 0x42, 0x58, 0x43, 0x7e, 0x20, 0xd3, 0x5d, 0x4f, 0xa1, 0xfd, 0x3f, 0xdf, 0x88, 0x7c, + 0x93, 0x86, 0xd5, 0x9f, 0x6d, 0x30, 0xfc, 0x17, 0x4b, 0x50, 0xdb, 0x0d, 0x95, 0x4c, 0x52, 0x54, + 0x1c, 0xce, 0x68, 0x24, 0xdd, 0x54, 0xb2, 0xc2, 0x5e, 0xb2, 0xf2, 0x77, 0x5c, 0xbb, 0xc3, 0xe8, + 0xbb, 0xc4, 0x4f, 0xe5, 0xc1, 0xc7, 0x5a, 0x32, 0x0a, 0x00, 0x9a, 0x12, 0xc7, 0xf3, 0x6c, 0x43, + 0x6d, 0x27, 0xd1, 0x73, 0x45, 0x4a, 0xa4, 0x61, 0xf5, 0x1c, 0xcf, 0xdb, 0xd6, 0x70, 0x2b, 0x7a, + 0xae, 0xc4, 0xdb, 0xb0, 0x98, 0xc8, 0x11, 0xc9, 0x49, 0x6b, 0xab, 0xc7, 0xbc, 0xf8, 0xf8, 0xe8, + 0x07, 0xe9, 0xa6, 0x96, 0x1c, 0x59, 0x88, 0x13, 0xab, 0x50, 0x75, 0xd2, 0x34, 0x61, 0xde, 0x6a, + 0x5a, 0xfc, 0x22, 0x36, 0x61, 0x85, 0x94, 0x55, 0xea, 0x47, 0xa1, 0x9d, 0x3a, 0x47, 0x81, 0xa4, + 0x99, 0x60, 0x43, 0xbc, 0x9c, 0xa3, 0x0e, 0x11, 0x83, 0xf3, 0xb0, 0x05, 0x17, 0x66, 0xe9, 0x43, + 0x67, 0x22, 0x15, 0xd9, 0xe1, 0xa6, 0xb5, 0x32, 0xdd, 0xe2, 0x11, 0xa2, 0x90, 0x11, 0x8a, 0x36, + 0xa8, 0xee, 0x1a, 0xa4, 0x39, 0xda, 0x39, 0x10, 0xb5, 0xe1, 0x05, 0xa8, 0xf9, 0xca, 0x96, 0xa1, + 0xa7, 0x35, 0x70, 0xd5, 0x57, 0xf7, 0x43, 0x4f, 0x7c, 0x00, 0x4d, 0xfe, 0x8a, 0x27, 0x47, 0x64, + 0x47, 0x5b, 0x5b, 0x5d, 0x2d, 0x6a, 0x08, 0xbe, 0x27, 0x47, 0x56, 0x23, 0xd5, 0x4f, 0xe8, 0x63, + 0xa5, 0x91, 0x2d, 0x4f, 0x53, 0x99, 0x84, 0x4e, 0xa0, 0x8d, 0x29, 0xa4, 0xd1, 0x7d, 0x0d, 0x11, + 0x9f, 0xc2, 0x45, 0x83, 0xb5, 0x55, 0x3a, 0x49, 0xed, 0x2c, 0xf4, 0x4f, 0xed, 0xd0, 0x09, 0x23, + 0xf2, 0xa0, 0x17, 0xad, 0x55, 0x83, 0x3e, 0x48, 0x27, 0xe9, 0x93, 0xd0, 0x3f, 0x7d, 0xe4, 0x84, + 0x91, 0xd8, 0x80, 0x7e, 0xde, 0x2c, 0x7d, 0x41, 0x3f, 0x4c, 0xcc, 0xd5, 0xb4, 0xba, 0x06, 0x7e, + 0xf8, 0x02, 0xff, 0x95, 0x78, 0xab, 0x44, 0x19, 0x8d, 0x46, 0xc8, 0x5b, 0x4a, 0xba, 0xe4, 0x06, + 0x57, 0xad, 0x95, 0x82, 0xfe, 0x31, 0xe1, 0x0e, 0xa4, 0x3b, 0xfc, 0xcb, 0x0a, 0xb4, 0x48, 0xa0, + 0x9f, 0xc4, 0x1e, 0xea, 0xce, 0x77, 0xa0, 0x33, 0xbd, 0xe8, 0xcc, 0x37, 0x6d, 0xa7, 0xbc, 0xe2, + 0x6b, 0x50, 0xdb, 0x76, 0x71, 0xf2, 0x88, 0x71, 0x3a, 0x96, 0x7e, 0x13, 0xbf, 0x84, 0x5e, 0x46, + 0xdd, 0xd8, 0x6e, 0x7a, 0x6a, 0x07, 0xa8, 0x73, 0x59, 0x43, 0x69, 0xae, 0xe0, 0x6f, 0xec, 0xa4, + 0xa7, 0x56, 0x27, 0x33, 0x8f, 0x0f, 0x51, 0x1b, 0xdf, 0x81, 0xd5, 0x44, 0x22, 0xc7, 0xd8, 0x2f, + 0x64, 0x12, 0xd9, 0xa9, 0x9c, 0xc4, 0x51, 0x42, 0x16, 0x1c, 0x67, 0x51, 0x30, 0xee, 0x7b, 0x99, + 0x44, 0x87, 0x1a, 0x33, 0x7c, 0x13, 0xaa, 0xdb, 0x49, 0xe2, 0x9c, 0x11, 0x6b, 0xe1, 0xc3, 0xa0, + 0x42, 0xb2, 0xc9, 0x2f, 0x43, 0x17, 0x16, 0xf7, 0x9c, 0x58, 0x5c, 0x87, 0x85, 0x49, 0x4c, 0x98, + 0xd6, 0xd6, 0x85, 0x92, 0x42, 0x73, 0xe2, 0xcd, 0xbd, 0xf8, 0x7e, 0x98, 0x26, 0x67, 0xd6, 0xc2, + 0x24, 0xbe, 0xfc, 0x29, 0xd4, 0xf5, 0x2b, 0x86, 0x81, 0x28, 0xe8, 0x15, 0x9a, 0x61, 0x7c, 0xc4, + 0x0f, 0x3c, 0x73, 0x82, 0xcc, 0xb8, 0xae, 0xfc, 0xf2, 0xc5, 0xc2, 0x67, 0x95, 0xe1, 0x7f, 0x5f, + 0x82, 0xc6, 0x3d, 0x19, 0x48, 0xfa, 0xf7, 0x21, 0xb4, 0xcb, 0x52, 0x61, 0xe6, 0x6d, 0x4a, 0x52, + 0x86, 0xd0, 0x66, 0x5f, 0x82, 0x5a, 0x49, 0x2d, 0x76, 0x53, 0x30, 0x34, 0x72, 0xbb, 0xec, 0xa4, + 0x91, 0xbc, 0x75, 0x2c, 0xf3, 0x8a, 0x98, 0x47, 0x1a, 0xb3, 0xc4, 0x18, 0xfd, 0x2a, 0xae, 0x02, + 0x24, 0xd1, 0x73, 0xdb, 0x67, 0x83, 0xce, 0xb6, 0xb1, 0x91, 0x44, 0xcf, 0x77, 0xd1, 0xa4, 0xff, + 0x8d, 0x88, 0xd9, 0x2f, 0x61, 0x50, 0x12, 0x33, 0x0c, 0x15, 0x6c, 0x3f, 0xe4, 0x90, 0x48, 0x4b, + 0x5c, 0xd1, 0x27, 0x45, 0x12, 0xbb, 0x21, 0x45, 0x43, 0x46, 0x79, 0x34, 0x5f, 0xa1, 0x3c, 0xe6, + 0xea, 0x22, 0x98, 0xaf, 0x8b, 0xee, 0x02, 0x1c, 0xc8, 0xf1, 0x44, 0x86, 0xe9, 0x9e, 0x13, 0x0f, + 0x5a, 0xb4, 0xf0, 0xc3, 0x62, 0xe1, 0xcd, 0x6a, 0x6d, 0x16, 0x44, 0xcc, 0x05, 0xa5, 0x56, 0xe8, + 0xe7, 0xb9, 0x4e, 0x68, 0xa7, 0x49, 0x16, 0xba, 0x4e, 0xca, 0xf1, 0x6d, 0xc3, 0x6a, 0xb9, 0x4e, + 0x78, 0xa8, 0x41, 0x25, 0x85, 0xd1, 0x29, 0x2b, 0x8c, 0x1b, 0xd0, 0x8b, 0x13, 0x7f, 0xe2, 0x24, + 0x67, 0x68, 0x2d, 0x68, 0x31, 0x58, 0xf4, 0x3a, 0x1a, 0xfc, 0xad, 0x3c, 0xdb, 0xf5, 0x4e, 0x2f, + 0x7f, 0x09, 0xbd, 0x99, 0x01, 0xfc, 0x24, 0xbe, 0xfb, 0x07, 0x55, 0x68, 0xee, 0x27, 0x52, 0x2b, + 0xf9, 0x6b, 0xd0, 0x52, 0xee, 0xb1, 0x9c, 0x38, 0xac, 0x1b, 0xb8, 0x07, 0x60, 0x10, 0xe9, 0x85, + 0x29, 0x35, 0xb6, 0xf0, 0x1a, 0x35, 0xd6, 0x87, 0x45, 0xf6, 0x17, 0x51, 0x98, 0xf0, 0xb1, 0xd0, + 0xdd, 0x4b, 0x65, 0xdd, 0xbd, 0x0e, 0xed, 0x63, 0x47, 0xd9, 0x4e, 0x96, 0x46, 0xb6, 0x1b, 0x05, + 0xc4, 0x74, 0x0d, 0x0b, 0x8e, 0x1d, 0xb5, 0x9d, 0xa5, 0xd1, 0x4e, 0x14, 0x88, 0x37, 0x01, 0xdc, + 0x28, 0xd0, 0x6a, 0x48, 0x3b, 0xcb, 0x4d, 0x37, 0x0a, 0x58, 0xf7, 0x20, 0x57, 0x4a, 0x95, 0xfa, + 0x13, 0x47, 0x2f, 0xa9, 0x8e, 0xb8, 0xeb, 0xa4, 0x0a, 0x97, 0x73, 0x94, 0x15, 0x3d, 0xe7, 0x50, + 0xfb, 0x0e, 0x74, 0xdd, 0x68, 0x12, 0xdb, 0x31, 0xce, 0x2c, 0xb9, 0x6e, 0x8d, 0x73, 0xd1, 0x50, + 0x1b, 0x29, 0xf6, 0x4f, 0x24, 0x3b, 0x93, 0x5b, 0xd0, 0x73, 0x83, 0x4c, 0xa5, 0x32, 0x41, 0x1b, + 0x2e, 0xe7, 0x07, 0x50, 0x1d, 0x4d, 0xa2, 0x1d, 0xd0, 0x21, 0x74, 0x7c, 0x65, 0x47, 0x81, 0x67, + 0xb3, 0x82, 0xd2, 0x7c, 0xd6, 0xf2, 0xd5, 0xe3, 0xc0, 0xd3, 0x2a, 0x92, 0x69, 0x42, 0xf9, 0xdc, + 0xd0, 0xb4, 0x0c, 0xcd, 0x23, 0xf9, 0x5c, 0xd3, 0xbc, 0x4c, 0xa1, 0xb5, 0x5f, 0xa6, 0xd0, 0x70, + 0x3e, 0x70, 0x42, 0x53, 0x27, 0x19, 0x93, 0xd6, 0x0e, 0x38, 0x0e, 0x62, 0xfe, 0x5a, 0x3e, 0x76, + 0xd4, 0x21, 0x61, 0x0e, 0x34, 0x02, 0xa3, 0x1e, 0x4d, 0x8b, 0x93, 0x17, 0x66, 0x93, 0x23, 0x99, + 0xd0, 0x4a, 0x30, 0xc7, 0x09, 0x46, 0x5a, 0xd1, 0xf3, 0x47, 0x84, 0xc2, 0x15, 0xb9, 0x09, 0xcb, + 0xba, 0x89, 0xe3, 0xa6, 0xfe, 0x33, 0x49, 0xe4, 0x3d, 0x22, 0xef, 0x31, 0x62, 0x9b, 0xe0, 0x48, + 0xfb, 0x7e, 0x4e, 0xab, 0x35, 0x0b, 0xd2, 0xf6, 0x79, 0x4f, 0x20, 0xef, 0x7a, 0xd7, 0xdb, 0x89, + 0x82, 0xe1, 0xbf, 0x5b, 0x80, 0xfa, 0x7e, 0xa4, 0xd2, 0x7b, 0x93, 0xc0, 0x88, 0x73, 0xe5, 0xa7, + 0x8a, 0xf3, 0xc2, 0x7c, 0x71, 0x9e, 0x23, 0x50, 0x8b, 0x73, 0x04, 0x0a, 0x8d, 0x64, 0x99, 0x8e, + 0x04, 0x81, 0xc3, 0x87, 0x6e, 0x41, 0x48, 0xc2, 0x70, 0x05, 0x5d, 0x56, 0xdb, 0x63, 0xfd, 0xcb, + 0x4c, 0xdb, 0xf0, 0x95, 0xd6, 0xbd, 0x8c, 0xf4, 0x49, 0xae, 0xb4, 0x3f, 0xdb, 0xf0, 0x95, 0x96, + 0xb3, 0xcf, 0xe1, 0x52, 0xde, 0xd2, 0x7e, 0xee, 0xa7, 0xc7, 0x51, 0x96, 0xda, 0x23, 0x8a, 0xd5, + 0x95, 0x8e, 0xf6, 0xd6, 0x4c, 0x4f, 0xdf, 0x31, 0x9a, 0x23, 0x79, 0x72, 0xaf, 0x47, 0x59, 0x10, + 0xd8, 0xa9, 0x3c, 0x4d, 0x35, 0xdb, 0x0e, 0x78, 0x6e, 0xf4, 0xbc, 0x3d, 0xc8, 0x82, 0xe0, 0x50, + 0x9e, 0xa6, 0x68, 0x1a, 0x1b, 0x23, 0xfd, 0x32, 0xfc, 0x87, 0x4b, 0x00, 0x0f, 0x23, 0xf7, 0x84, + 0x57, 0x1e, 0x63, 0x48, 0xa3, 0xbd, 0xb5, 0x75, 0xa9, 0xa7, 0xac, 0xb3, 0xc5, 0x16, 0xac, 0x99, + 0xff, 0x47, 0x99, 0xc3, 0x78, 0x96, 0xd5, 0xaf, 0x56, 0x1e, 0x42, 0x63, 0x79, 0x4f, 0x86, 0x74, + 0xaf, 0xf8, 0xac, 0x98, 0x5b, 0x6c, 0x93, 0x9e, 0xc5, 0x34, 0xb7, 0xf3, 0xc2, 0x89, 0x4e, 0xd1, + 0xfc, 0xf0, 0x2c, 0x16, 0x77, 0xe0, 0x42, 0x22, 0x47, 0x89, 0x54, 0xc7, 0x76, 0xaa, 0xca, 0x1f, + 0xe3, 0x50, 0x72, 0x59, 0x23, 0x0f, 0x55, 0xfe, 0xad, 0x3b, 0x70, 0x81, 0x67, 0x6a, 0x76, 0x78, + 0x6c, 0xab, 0x96, 0x19, 0x59, 0x1e, 0xdd, 0x9b, 0x40, 0x1b, 0xc3, 0x6c, 0x7f, 0x4c, 0x6c, 0x11, + 0xd0, 0x64, 0x1c, 0x05, 0x12, 0xbd, 0xd7, 0x9d, 0x63, 0x27, 0x1c, 0xa3, 0xce, 0xd2, 0x93, 0x5f, + 0x00, 0xc4, 0x10, 0x96, 0xf6, 0x22, 0x4f, 0xd2, 0x54, 0x77, 0xb7, 0xba, 0x9b, 0xb4, 0xc5, 0x8c, + 0x33, 0x49, 0x7b, 0x91, 0x84, 0x13, 0xef, 0x01, 0x75, 0xc7, 0xec, 0x77, 0x5e, 0x2f, 0x34, 0x10, + 0x49, 0x3c, 0x78, 0x07, 0x2e, 0x14, 0x23, 0xb1, 0x9d, 0xd4, 0x4e, 0x8f, 0x25, 0xa9, 0x7e, 0x56, + 0x0d, 0xcb, 0xf9, 0xa0, 0xb6, 0xd3, 0xc3, 0x63, 0x89, 0x66, 0x60, 0x03, 0xea, 0xd1, 0xd1, 0x0f, + 0x36, 0x0a, 0x42, 0x6b, 0xbe, 0x20, 0xd4, 0xa2, 0xa3, 0x1f, 0x2c, 0x39, 0x12, 0xbf, 0x28, 0x9b, + 0xcd, 0x99, 0xa9, 0x69, 0xd3, 0xd4, 0xac, 0xe6, 0xf8, 0xd2, 0xec, 0x0c, 0x3f, 0x83, 0x1a, 0xfe, + 0xce, 0xe3, 0x58, 0x6c, 0x42, 0x9d, 0xc5, 0x51, 0x69, 0x37, 0x67, 0xb5, 0xb0, 0x76, 0x05, 0xef, + 0x58, 0x86, 0x68, 0x68, 0x41, 0x2f, 0x37, 0x1d, 0x4f, 0x42, 0xff, 0x69, 0x26, 0xc5, 0x57, 0xb0, + 0x1c, 0x27, 0x52, 0xb3, 0xbd, 0x9d, 0x9d, 0xa0, 0xf3, 0xa6, 0x25, 0x78, 0x55, 0x73, 0x69, 0xde, + 0xe2, 0x04, 0x39, 0xb4, 0x1b, 0x4f, 0xbd, 0x0f, 0xbf, 0x87, 0x8b, 0x39, 0xc5, 0x81, 0x74, 0xa3, + 0xd0, 0x73, 0x92, 0x33, 0xb2, 0xf2, 0x33, 0x7d, 0xab, 0x9f, 0xd2, 0xf7, 0x01, 0xf5, 0xfd, 0x5f, + 0x2b, 0xd0, 0x7a, 0x90, 0xbd, 0x78, 0x71, 0xc6, 0xb2, 0x24, 0xda, 0x50, 0x79, 0x44, 0x1d, 0x2c, + 0x58, 0x95, 0x47, 0xe8, 0x88, 0xee, 0x9f, 0xa0, 0x5c, 0x13, 0x9f, 0x37, 0x2d, 0xfd, 0x86, 0x01, + 0xf2, 0xfe, 0xc9, 0xe1, 0x2b, 0x38, 0x9a, 0xd1, 0x18, 0x20, 0xdd, 0xcd, 0xfc, 0x00, 0xdd, 0x24, + 0xcd, 0xbc, 0xf9, 0x3b, 0x86, 0x9c, 0xbb, 0x23, 0x1e, 0xca, 0x83, 0x24, 0x9a, 0xf0, 0x64, 0x69, + 0x95, 0x31, 0x07, 0x23, 0xbe, 0x86, 0x15, 0xbd, 0x81, 0xa7, 0xb5, 0x82, 0xad, 0x62, 0xe9, 0x12, + 0xeb, 0xfe, 0xa4, 0x4d, 0xbf, 0xe1, 0xdf, 0xad, 0x41, 0x03, 0x43, 0xcb, 0xdf, 0x46, 0x7e, 0x28, + 0xee, 0x40, 0xf3, 0x87, 0xc8, 0x0f, 0x79, 0xb7, 0x81, 0x93, 0x1c, 0x2b, 0xdc, 0xd7, 0xa3, 0xc8, + 0x93, 0x9b, 0x48, 0x43, 0xfb, 0x0c, 0x8d, 0x1f, 0xf4, 0x93, 0x36, 0x4f, 0x89, 0x3f, 0x3e, 0x4e, + 0x6d, 0x04, 0x6a, 0xdd, 0xda, 0xf2, 0x95, 0x85, 0x30, 0xea, 0xf5, 0x2a, 0x00, 0xc5, 0xb4, 0x51, + 0x68, 0xc7, 0x27, 0x3a, 0xae, 0x6b, 0x20, 0xe4, 0x71, 0xb8, 0x7f, 0x82, 0xb2, 0xe7, 0x2b, 0x5b, + 0xef, 0x6b, 0x69, 0x1f, 0xbc, 0x14, 0xd7, 0xbf, 0x0b, 0x5d, 0xf4, 0x8f, 0xd4, 0x89, 0x1f, 0xdb, + 0x71, 0x12, 0x1d, 0x99, 0x49, 0x41, 0xaf, 0xe9, 0xe0, 0xc4, 0x8f, 0xf7, 0x11, 0x46, 0x6e, 0x89, + 0xde, 0x2d, 0x43, 0xb5, 0xcd, 0xf6, 0x1f, 0x34, 0x08, 0xe7, 0x97, 0xb6, 0xc4, 0x02, 0x8e, 0x12, + 0xea, 0xe4, 0x6e, 0xd4, 0x13, 0x19, 0x50, 0x38, 0x70, 0x09, 0x1a, 0x28, 0x0c, 0x84, 0x6a, 0x30, + 0xca, 0x8d, 0x18, 0xf5, 0x3e, 0x40, 0x20, 0x47, 0xa9, 0x8d, 0x5c, 0xc6, 0x1b, 0x00, 0x33, 0x5b, + 0x4f, 0x88, 0xdd, 0x41, 0xa4, 0xf8, 0x00, 0x5a, 0x3c, 0x0b, 0x4c, 0x0b, 0xe7, 0x68, 0x81, 0xd0, + 0x4c, 0x7c, 0x13, 0x5a, 0x61, 0x14, 0xda, 0xf2, 0x29, 0x51, 0x6b, 0xb9, 0x9d, 0xea, 0x38, 0x8c, + 0xc2, 0xfb, 0x4f, 0x91, 0x58, 0xdc, 0xd6, 0x63, 0xe0, 0x3d, 0x98, 0xf6, 0x4b, 0xf6, 0x60, 0x68, + 0x24, 0xbc, 0x1b, 0xf1, 0x91, 0x19, 0x09, 0xb7, 0xe8, 0xbc, 0xa4, 0x05, 0x8f, 0x87, 0x9b, 0xac, + 0x43, 0x9b, 0xd6, 0x7d, 0xe2, 0xc4, 0x76, 0xea, 0x8c, 0xb5, 0x55, 0x07, 0x84, 0xed, 0x39, 0xf1, + 0xa1, 0x33, 0x16, 0x16, 0x5c, 0x9a, 0xe1, 0xb7, 0x23, 0x64, 0x5d, 0x9e, 0xb5, 0x9e, 0xd9, 0xc3, + 0x99, 0xcf, 0x75, 0x6b, 0x53, 0x5c, 0x47, 0x2c, 0x4f, 0xb3, 0xfb, 0x39, 0x5c, 0x92, 0x13, 0xca, + 0x7e, 0x4c, 0xe2, 0x44, 0x2a, 0x35, 0xe5, 0x9a, 0xf5, 0xd9, 0xc6, 0x21, 0xc1, 0x4e, 0x8e, 0xcf, + 0xfd, 0xb3, 0x77, 0xa1, 0xeb, 0xa8, 0x68, 0x64, 0x9b, 0x29, 0x0f, 0x28, 0x97, 0x51, 0xb5, 0xda, + 0x08, 0xb5, 0x78, 0xa2, 0x03, 0x34, 0xe8, 0x44, 0xa5, 0x87, 0x2a, 0x47, 0x29, 0xe5, 0x31, 0x1a, + 0x56, 0x07, 0xc1, 0x3c, 0x10, 0x39, 0x4a, 0x87, 0xff, 0x74, 0x01, 0x1a, 0x0f, 0xa3, 0x28, 0xfe, + 0x99, 0x32, 0x50, 0xe6, 0xad, 0x85, 0x97, 0xf3, 0xd6, 0xe2, 0x34, 0x6f, 0xcd, 0xf0, 0xc0, 0xd2, + 0x8f, 0xe7, 0x81, 0xea, 0x4f, 0xe6, 0x81, 0xda, 0xcf, 0xe0, 0x81, 0xfa, 0x2c, 0x0f, 0x0c, 0xef, + 0x40, 0xf5, 0x40, 0xa6, 0x8f, 0x63, 0xb4, 0x66, 0xc6, 0x2f, 0x36, 0x86, 0x60, 0xca, 0x9a, 0x69, + 0x9f, 0x58, 0x0d, 0xff, 0xba, 0x05, 0xcd, 0x7b, 0xd2, 0xcb, 0x78, 0x66, 0xcb, 0xf3, 0x54, 0x79, + 0xf9, 0x3c, 0x2d, 0x4c, 0xcf, 0x13, 0x9a, 0x4e, 0x23, 0x83, 0x73, 0x36, 0x50, 0x1b, 0x46, 0x04, + 0x51, 0x58, 0x0b, 0x09, 0xd4, 0xbb, 0x90, 0x53, 0xf3, 0x99, 0x0b, 0xe0, 0xab, 0xb9, 0xb9, 0xfa, + 0xf3, 0xb8, 0x79, 0x5a, 0x8f, 0x9d, 0xdb, 0x9f, 0x7c, 0xed, 0xf4, 0xce, 0xea, 0xb0, 0xc6, 0x39, + 0x1d, 0xf6, 0x10, 0x56, 0xa2, 0xd0, 0xf6, 0xb2, 0x38, 0xf0, 0x31, 0x2e, 0x24, 0xbf, 0x3a, 0x0a, + 0xc9, 0x9d, 0xa0, 0x8c, 0x68, 0xce, 0xa3, 0x8f, 0xc3, 0x7b, 0x86, 0x88, 0xf7, 0x4a, 0xac, 0xe5, + 0x68, 0x16, 0x84, 0x22, 0xe4, 0xe1, 0xd2, 0x90, 0x27, 0x40, 0x3e, 0x2c, 0xa7, 0x76, 0xdb, 0x04, + 0xdd, 0x89, 0x02, 0xb2, 0x6d, 0x9f, 0x41, 0xaf, 0xa0, 0x62, 0x66, 0x6a, 0xbd, 0x84, 0x99, 0x3a, + 0xa6, 0x21, 0xf3, 0xd3, 0xdf, 0x84, 0xde, 0xfa, 0x10, 0x56, 0xcc, 0x16, 0x90, 0x76, 0x67, 0x68, + 0x05, 0xbb, 0xc4, 0x41, 0x7d, 0xbd, 0xeb, 0x43, 0x9e, 0x0c, 0x2d, 0xd1, 0xaf, 0x60, 0xb5, 0x44, + 0x8e, 0xec, 0x5b, 0xd6, 0x5f, 0x65, 0x5e, 0x59, 0xce, 0xdb, 0xe2, 0xeb, 0x43, 0xde, 0xc3, 0x6f, + 0x79, 0x32, 0x30, 0x1f, 0xd2, 0xd1, 0x49, 0xd3, 0x93, 0x81, 0x4e, 0x3d, 0xee, 0xc1, 0xbb, 0x18, + 0xc9, 0x21, 0xde, 0x75, 0xe2, 0x34, 0x4b, 0xa4, 0x1d, 0x07, 0x8e, 0x2b, 0x8f, 0xa3, 0xc0, 0x93, + 0x49, 0x31, 0xb8, 0x65, 0x1a, 0xdc, 0xb5, 0x28, 0xc0, 0x70, 0x66, 0x87, 0x29, 0xf7, 0x0b, 0x42, + 0x33, 0xd6, 0x6d, 0x78, 0xeb, 0x5c, 0x77, 0x68, 0xea, 0x8a, 0x8e, 0x04, 0x75, 0x74, 0x69, 0xba, + 0x23, 0x24, 0x31, 0x5d, 0x7c, 0x04, 0x17, 0x78, 0xed, 0x98, 0xb9, 0x4f, 0xa4, 0x8c, 0xed, 0xc0, + 0x51, 0xe9, 0x60, 0x85, 0xdd, 0x0a, 0x42, 0x12, 0x03, 0x7f, 0x2b, 0x65, 0xfc, 0xd0, 0xe1, 0xaf, + 0x72, 0x13, 0x1d, 0x79, 0x50, 0x9b, 0xa9, 0xb9, 0x5d, 0xe5, 0xaf, 0x12, 0x15, 0x87, 0x1f, 0xd8, + 0xb8, 0x34, 0xc9, 0xbf, 0x86, 0x2b, 0x53, 0x5d, 0x4c, 0x9c, 0xe4, 0xa4, 0x70, 0xc5, 0x07, 0x17, + 0x68, 0xde, 0x2e, 0x96, 0xda, 0xef, 0x11, 0x81, 0x9e, 0xc5, 0x8f, 0x61, 0x0d, 0x03, 0xd3, 0xc8, + 0x3b, 0xc9, 0x66, 0x82, 0xb6, 0x35, 0x1a, 0x34, 0x86, 0xad, 0x8f, 0xbd, 0x93, 0x6c, 0x2a, 0x70, + 0xfb, 0x25, 0x0c, 0xa6, 0x68, 0xed, 0x84, 0x36, 0xe7, 0xed, 0x38, 0x52, 0x83, 0x8b, 0xbc, 0x1f, + 0x54, 0xde, 0x51, 0xe4, 0xad, 0xfb, 0xfd, 0x48, 0x89, 0x07, 0xb0, 0x1e, 0x1f, 0x9f, 0x29, 0x9f, + 0x92, 0x89, 0xe4, 0xd0, 0x9f, 0xef, 0x60, 0x40, 0x1d, 0x5c, 0x35, 0x74, 0xec, 0xf7, 0xcf, 0xf4, + 0xf3, 0x19, 0x5c, 0x32, 0x8c, 0x75, 0x2c, 0xdd, 0x93, 0xe9, 0x19, 0xbb, 0x44, 0x33, 0x76, 0x41, + 0x73, 0x14, 0xe2, 0x4b, 0xb3, 0xb5, 0x01, 0x7d, 0xb2, 0x77, 0xf6, 0x28, 0xca, 0x42, 0xfd, 0xa7, + 0x97, 0xe9, 0x4f, 0xbb, 0x04, 0x7f, 0x80, 0x60, 0xfa, 0xc9, 0x0d, 0xe8, 0x93, 0xb5, 0x64, 0xa9, + 0x67, 0xca, 0x2b, 0x4c, 0x89, 0x70, 0x2d, 0xe8, 0x48, 0xf9, 0x29, 0x5c, 0xd4, 0x44, 0x23, 0x3f, + 0x74, 0x82, 0xf2, 0xcf, 0x5c, 0x65, 0x37, 0x9f, 0xd1, 0x0f, 0x10, 0x5b, 0xfc, 0xc4, 0xef, 0x40, + 0x8c, 0xa2, 0x44, 0xfa, 0xe3, 0x90, 0xc2, 0x5a, 0xfa, 0x13, 0x35, 0x78, 0x93, 0x64, 0xe3, 0xcd, + 0xc2, 0xcf, 0x7f, 0x7c, 0xef, 0xdb, 0x27, 0x0f, 0x98, 0xee, 0x5b, 0x79, 0x46, 0xff, 0xa3, 0x25, + 0xb3, 0x3f, 0x9a, 0x06, 0xab, 0xe1, 0x3f, 0xaa, 0x41, 0x97, 0xac, 0xf1, 0xdf, 0x1a, 0x81, 0xbf, + 0x35, 0x02, 0xff, 0x2f, 0x18, 0x81, 0x9b, 0xb0, 0xec, 0x87, 0x71, 0x96, 0xa2, 0x04, 0x29, 0x3b, + 0xe3, 0x28, 0x6e, 0x99, 0xb7, 0x9b, 0x08, 0xf1, 0xad, 0x3c, 0x53, 0x1c, 0xc2, 0x0d, 0xff, 0x4e, + 0x05, 0xea, 0xfb, 0x49, 0xe4, 0x65, 0x6e, 0xfa, 0x33, 0xa5, 0x62, 0x9a, 0xdb, 0x16, 0x5f, 0xc7, + 0x6d, 0x4b, 0xe7, 0x3c, 0xba, 0x7f, 0x5e, 0x81, 0xa6, 0x1e, 0xc2, 0xc3, 0xad, 0x9f, 0x39, 0x88, + 0x22, 0xb7, 0x5d, 0x99, 0x9b, 0xdb, 0x7e, 0xed, 0x28, 0x90, 0x09, 0x9f, 0x71, 0x31, 0x50, 0x14, + 0x17, 0x89, 0xee, 0xa6, 0xd5, 0x66, 0xe8, 0xe3, 0x98, 0xf2, 0xd9, 0xcf, 0xa1, 0x49, 0x51, 0x3e, + 0x69, 0x91, 0x35, 0xa8, 0xb1, 0x56, 0xd3, 0x03, 0xd5, 0x6f, 0xaf, 0x96, 0xe9, 0x85, 0x9f, 0x25, + 0xd3, 0xc3, 0x7f, 0xb3, 0x08, 0x1d, 0xda, 0x72, 0x79, 0x90, 0x85, 0x2c, 0x35, 0xf9, 0x26, 0x75, + 0x65, 0x7a, 0x93, 0x7a, 0x29, 0x91, 0xa9, 0x49, 0xa4, 0xb7, 0xf9, 0x33, 0x3b, 0x51, 0x70, 0x4f, + 0x8e, 0x2c, 0xc2, 0xe0, 0x54, 0x39, 0xc9, 0x58, 0xcd, 0x2b, 0x03, 0x40, 0x38, 0xfe, 0x55, 0xec, + 0x24, 0xce, 0x44, 0x99, 0x32, 0x00, 0x7e, 0x13, 0x02, 0x96, 0x48, 0x36, 0x79, 0x5a, 0xe8, 0x59, + 0xef, 0x1e, 0x2a, 0x3f, 0x1c, 0xe7, 0x8a, 0xa6, 0x41, 0xe5, 0x1f, 0xe3, 0x40, 0x8a, 0x7b, 0x20, + 0x38, 0x2d, 0x92, 0x48, 0x07, 0x9d, 0x0f, 0xea, 0x87, 0xb4, 0x4d, 0x6b, 0x6b, 0x8d, 0x3f, 0x4b, + 0x73, 0x69, 0x11, 0x7a, 0x1f, 0xb1, 0x56, 0xdf, 0x9f, 0x81, 0xcc, 0x99, 0x4c, 0xf6, 0x40, 0xf2, + 0x48, 0xf9, 0x47, 0x4f, 0x26, 0xb9, 0x25, 0xc4, 0x2d, 0x5f, 0xc1, 0xca, 0x28, 0x0b, 0x82, 0x54, + 0x9e, 0xa6, 0xb6, 0x8a, 0xb2, 0xc4, 0x95, 0xf6, 0x2b, 0x32, 0x32, 0xcb, 0x86, 0xf6, 0x80, 0x48, + 0x2d, 0x39, 0x12, 0x5f, 0x82, 0xc8, 0x3b, 0x30, 0xff, 0x68, 0xf2, 0xa5, 0xe7, 0xda, 0xf7, 0x0d, + 0xa9, 0xfe, 0xdb, 0xd1, 0x70, 0x1b, 0x2e, 0x98, 0x1c, 0x29, 0xaa, 0xb6, 0x2d, 0x94, 0x5b, 0xda, + 0x3b, 0x32, 0x73, 0x5c, 0x29, 0xcd, 0xf1, 0x2a, 0x54, 0xcb, 0xe5, 0x69, 0xfc, 0x32, 0xbc, 0x0e, + 0xad, 0x91, 0x1f, 0x48, 0x9d, 0x6b, 0xc0, 0x45, 0xd3, 0x59, 0x87, 0x0a, 0x25, 0xd5, 0xf5, 0xdb, + 0xf0, 0x2f, 0x2b, 0x70, 0x31, 0x76, 0x92, 0xa7, 0x99, 0xde, 0xd5, 0xe6, 0xfc, 0xbe, 0x3a, 0x76, + 0x12, 0x0f, 0x05, 0x97, 0xba, 0xe0, 0xde, 0xb9, 0xba, 0xa9, 0x89, 0x10, 0x1e, 0xcb, 0x0d, 0xe8, + 0x95, 0x5a, 0xa4, 0x4e, 0x62, 0x76, 0x56, 0x3b, 0x49, 0xf4, 0x9c, 0xb2, 0xef, 0x07, 0x08, 0x14, + 0x43, 0xe8, 0x14, 0x74, 0x92, 0x2c, 0x23, 0x15, 0x09, 0x19, 0xaa, 0xfb, 0xa1, 0x87, 0x92, 0x1b, + 0x66, 0x13, 0x76, 0x17, 0xb8, 0x88, 0xad, 0x1e, 0x66, 0x13, 0xf2, 0x13, 0x56, 0xa1, 0xca, 0x95, + 0x83, 0x55, 0x82, 0xf3, 0xcb, 0xf0, 0x0f, 0x55, 0x58, 0xd9, 0x75, 0xe5, 0x91, 0x4c, 0xc6, 0xf7, + 0x9c, 0xd4, 0x79, 0xe0, 0x07, 0xf2, 0xd0, 0x51, 0x27, 0xc8, 0x70, 0x34, 0xe6, 0xd8, 0x49, 0x8f, + 0xf5, 0x2c, 0x35, 0x10, 0xb0, 0xef, 0xa4, 0xc7, 0x68, 0xb6, 0x08, 0x39, 0x8a, 0x92, 0x89, 0xde, + 0x07, 0x6e, 0x5a, 0xf4, 0x8f, 0x0f, 0x08, 0x92, 0xb7, 0x56, 0xfe, 0x0b, 0xa9, 0x4b, 0xee, 0xa8, + 0x35, 0xd5, 0x65, 0xbc, 0x0d, 0xed, 0x44, 0xba, 0x51, 0xe2, 0xe9, 0xd8, 0x9f, 0xc7, 0xd9, 0x62, + 0x18, 0x07, 0xfc, 0x37, 0xa1, 0xc8, 0x1d, 0xd2, 0x56, 0x97, 0xed, 0x9b, 0xba, 0x9c, 0x5e, 0x8e, + 0x40, 0xce, 0xdb, 0xf5, 0xc4, 0xff, 0x07, 0xfd, 0x82, 0x96, 0x12, 0x59, 0x26, 0x02, 0xde, 0x2a, + 0xdc, 0x98, 0x39, 0xbf, 0xb8, 0xb9, 0x6f, 0x5a, 0xfd, 0x39, 0x35, 0xe2, 0x64, 0x5d, 0xd1, 0x3d, + 0x43, 0xc5, 0x3b, 0xd0, 0x51, 0x71, 0xe0, 0xa7, 0x9a, 0x01, 0x94, 0x2e, 0xcc, 0x6b, 0x13, 0x90, + 0xf3, 0x4d, 0x6a, 0xde, 0x12, 0x36, 0x7e, 0xd4, 0x12, 0x36, 0xcf, 0x2f, 0xe1, 0xfb, 0xd0, 0x77, + 0x13, 0xe9, 0xc9, 0x30, 0xf5, 0x9d, 0xc0, 0x56, 0x6e, 0x14, 0x1b, 0x33, 0xdd, 0x2b, 0xe0, 0x07, + 0x08, 0x16, 0xbf, 0x80, 0x8b, 0x6e, 0x14, 0xa6, 0x32, 0x4c, 0xf3, 0xd2, 0x4d, 0x9d, 0xad, 0xd1, + 0x25, 0x27, 0x17, 0x34, 0xda, 0x14, 0x70, 0x72, 0xbe, 0x46, 0xdc, 0x81, 0x55, 0x5e, 0x9e, 0x99, + 0x46, 0x5c, 0x2b, 0x20, 0x68, 0xa5, 0xa6, 0x5b, 0xe8, 0x0c, 0x52, 0x22, 0x95, 0xef, 0x65, 0x4e, + 0xa0, 0x35, 0x44, 0x29, 0x83, 0x64, 0x69, 0x8c, 0xde, 0x4a, 0xa5, 0x1c, 0xd5, 0x14, 0x2d, 0x15, + 0xba, 0xd0, 0x56, 0x53, 0xd3, 0x12, 0xc9, 0x14, 0xf5, 0x37, 0x8e, 0x3a, 0xbe, 0x7c, 0x17, 0x56, + 0xe7, 0x2d, 0xc8, 0xeb, 0x92, 0x97, 0xcd, 0x52, 0xf2, 0x52, 0x97, 0xa7, 0xfe, 0xb7, 0x05, 0xb8, + 0x60, 0xd6, 0x9b, 0x42, 0x8e, 0x9c, 0xa9, 0xaf, 0x91, 0x3d, 0xc7, 0x30, 0x25, 0xdf, 0xee, 0x69, + 0x5a, 0xc0, 0x20, 0xda, 0xdb, 0xd9, 0x80, 0xbe, 0x26, 0x28, 0x98, 0x9f, 0xbf, 0xd2, 0xf5, 0xf2, + 0xae, 0x48, 0x04, 0xe8, 0x07, 0x47, 0x32, 0xc1, 0x39, 0xf2, 0xa8, 0x5a, 0x9b, 0x9a, 0x10, 0xb3, + 0xd3, 0x0f, 0x1a, 0x9c, 0x61, 0x39, 0xaa, 0xb4, 0x79, 0x9a, 0x39, 0x81, 0x9f, 0x9e, 0xd9, 0x23, + 0x5f, 0x06, 0x1e, 0x65, 0xca, 0xb9, 0x8e, 0xb0, 0x6f, 0x30, 0x0f, 0x10, 0xb1, 0xeb, 0xa9, 0xd2, + 0x48, 0x74, 0x02, 0x36, 0x17, 0x00, 0x3d, 0x92, 0x03, 0x02, 0xef, 0x7a, 0xf3, 0x65, 0xa5, 0x36, + 0x5f, 0x56, 0xde, 0x83, 0xde, 0xec, 0x9a, 0x73, 0x52, 0xb4, 0xab, 0xa6, 0xd7, 0x7b, 0x1e, 0x13, + 0x36, 0xe6, 0x32, 0xa1, 0x9e, 0xf4, 0xff, 0xb1, 0x00, 0xab, 0x7a, 0xd2, 0x77, 0xa2, 0x20, 0x9b, + 0xa0, 0xb5, 0xa7, 0xaa, 0xa4, 0x75, 0x68, 0x4f, 0x22, 0x76, 0xa1, 0x4a, 0xea, 0x0f, 0x26, 0x51, + 0xae, 0x8b, 0x37, 0xa0, 0xef, 0x73, 0xcb, 0x7c, 0x5e, 0x4c, 0x85, 0xb0, 0x86, 0xeb, 0x59, 0x41, + 0x2e, 0x54, 0xa1, 0x13, 0xab, 0xe3, 0x28, 0xd5, 0xa4, 0xa4, 0xc4, 0x79, 0xce, 0x97, 0x0d, 0x8a, + 0xa8, 0xc9, 0x93, 0xbd, 0x05, 0xc2, 0xcd, 0x92, 0x04, 0xe5, 0xa3, 0x44, 0xce, 0xc9, 0xbb, 0xbe, + 0xc6, 0x14, 0xd4, 0xef, 0x40, 0x7d, 0x12, 0x15, 0x1e, 0xc9, 0x94, 0x23, 0x6a, 0xd5, 0x26, 0x11, + 0x71, 0xc8, 0x65, 0xf4, 0x9a, 0x9e, 0x66, 0x7e, 0x22, 0x3d, 0x63, 0x87, 0xcd, 0xbb, 0x36, 0xd2, + 0xc7, 0xbe, 0xe7, 0xc9, 0x50, 0x27, 0x8e, 0x1a, 0xbe, 0xfa, 0x86, 0xde, 0xa9, 0x80, 0x56, 0x8e, + 0x1c, 0x0c, 0xcd, 0xc2, 0x2c, 0x20, 0xa9, 0x08, 0x74, 0xb9, 0x66, 0x4f, 0x23, 0x1e, 0x65, 0x01, + 0x4a, 0x44, 0xa0, 0x97, 0x94, 0x6c, 0x09, 0xb2, 0xa0, 0x7d, 0xec, 0x87, 0x29, 0xa9, 0x8a, 0x26, + 0x2d, 0x29, 0x22, 0x90, 0x09, 0xbf, 0xf1, 0xc3, 0x74, 0xf8, 0xcf, 0x16, 0x60, 0x4d, 0x4f, 0xfc, + 0x81, 0x9e, 0x00, 0x6d, 0x9f, 0x29, 0xba, 0x30, 0xd3, 0xa5, 0xf3, 0x7a, 0x8b, 0x16, 0x18, 0xd0, + 0x2e, 0x0d, 0xb8, 0xe0, 0xae, 0x05, 0x5d, 0xc6, 0x69, 0xf8, 0xea, 0x16, 0x88, 0x73, 0x7c, 0xa5, + 0xf4, 0xb6, 0x66, 0x7f, 0x86, 0xb1, 0x94, 0xf8, 0x04, 0xd6, 0x26, 0x32, 0x75, 0x48, 0x10, 0x82, + 0xc8, 0x75, 0xa8, 0x15, 0x89, 0x3c, 0x4f, 0xf7, 0xaa, 0xc1, 0x3e, 0xd4, 0x48, 0x14, 0x7a, 0xfc, + 0xc6, 0xc4, 0x09, 0xfd, 0x91, 0x54, 0x29, 0xf9, 0x19, 0xdc, 0x82, 0x1d, 0x9f, 0xbe, 0xc1, 0xa0, + 0x27, 0x41, 0xd4, 0xe4, 0xb1, 0x8e, 0x78, 0x11, 0x6b, 0x44, 0x53, 0x4f, 0xe4, 0x48, 0xaf, 0x5d, + 0x07, 0xd7, 0x2a, 0xf4, 0xc3, 0x31, 0x1f, 0x1c, 0xa8, 0xb3, 0x4f, 0x69, 0x80, 0x7b, 0x91, 0x27, + 0x87, 0x7f, 0xb1, 0x94, 0xf3, 0xe8, 0xbe, 0x86, 0x1f, 0xa4, 0x4e, 0x4a, 0xb5, 0xf2, 0xf9, 0xe0, + 0xd9, 0x46, 0xf2, 0x5c, 0x75, 0x0c, 0x94, 0x4b, 0xea, 0x37, 0x61, 0x65, 0x7a, 0xb4, 0x4c, 0xbb, + 0xc0, 0x65, 0x05, 0xe5, 0xe1, 0xe6, 0x25, 0xf8, 0x39, 0x3d, 0x93, 0xea, 0xea, 0x73, 0x03, 0x65, + 0xb2, 0x0f, 0x8b, 0x49, 0x50, 0x3a, 0x39, 0x2f, 0x3d, 0x6d, 0x15, 0xf3, 0x5e, 0xd5, 0x81, 0x46, + 0xa0, 0x68, 0x16, 0xe4, 0x71, 0x92, 0x85, 0xd2, 0xd3, 0x26, 0xbd, 0x97, 0xc3, 0xf7, 0x09, 0x8c, + 0x03, 0xce, 0x35, 0x53, 0xa9, 0xeb, 0x1a, 0x77, 0xed, 0x69, 0xcd, 0x54, 0x74, 0x8d, 0x3c, 0x5a, + 0xd0, 0xeb, 0xbe, 0x59, 0x41, 0xf4, 0x72, 0x6a, 0xdd, 0xf7, 0x2f, 0x61, 0x90, 0xd3, 0xf2, 0xdf, + 0x15, 0x1f, 0x68, 0xb0, 0xf1, 0x31, 0x4d, 0xe8, 0x37, 0xf3, 0x8f, 0x7c, 0x0c, 0x6b, 0xb3, 0x0d, + 0xf5, 0x97, 0x9a, 0xd4, 0x6c, 0x65, 0xaa, 0x59, 0xf1, 0x27, 0xf9, 0xfa, 0xba, 0x8e, 0x7b, 0x2c, + 0xed, 0x63, 0x5f, 0x17, 0xa0, 0x2f, 0x5a, 0xcb, 0x06, 0xb5, 0x83, 0x98, 0x6f, 0xfc, 0x54, 0xcd, + 0xa1, 0x9f, 0xf8, 0x4a, 0x69, 0xab, 0x38, 0x4d, 0xbf, 0xe7, 0x2b, 0x35, 0xfc, 0x2f, 0x2d, 0x68, + 0x1b, 0x4f, 0x91, 0x6a, 0x9f, 0x6f, 0x95, 0x9d, 0xfe, 0xd6, 0x56, 0xdf, 0x78, 0xef, 0x48, 0xb2, + 0x9d, 0xa6, 0x89, 0xc9, 0xf5, 0x71, 0x30, 0x30, 0xe5, 0xef, 0x2c, 0x90, 0x83, 0x50, 0xf8, 0x3b, + 0xdb, 0xb0, 0x5c, 0xf2, 0x20, 0xed, 0x34, 0x4a, 0x9d, 0x40, 0x07, 0x05, 0xa5, 0xba, 0xb1, 0x12, + 0x89, 0xd5, 0xc3, 0x17, 0xf6, 0x2d, 0x0e, 0x91, 0x1a, 0x83, 0x0d, 0x37, 0x0a, 0x4c, 0xb1, 0xed, + 0x4c, 0xb0, 0x81, 0x18, 0xaa, 0x88, 0x49, 0x24, 0xc6, 0xb9, 0xea, 0x69, 0xa0, 0x25, 0xa8, 0xc9, + 0x90, 0x83, 0xa7, 0x41, 0x3e, 0x40, 0x72, 0xe6, 0x6b, 0x14, 0xc7, 0xd0, 0x00, 0xc9, 0x4b, 0xff, + 0x10, 0x5a, 0x51, 0xe2, 0x8f, 0x7d, 0x4a, 0x13, 0xb3, 0x83, 0x33, 0xfb, 0x11, 0x60, 0x82, 0x1d, + 0xfc, 0xd4, 0x10, 0x6a, 0xda, 0xfc, 0x9f, 0xaf, 0x92, 0xd1, 0x18, 0x73, 0x04, 0xc0, 0x4d, 0x71, + 0x38, 0x2c, 0x91, 0xcd, 0xe2, 0x08, 0x80, 0x9b, 0x1e, 0x3c, 0x0d, 0x28, 0x53, 0x7e, 0x03, 0x7a, + 0x2e, 0x99, 0x0b, 0x16, 0xa8, 0x40, 0x86, 0xb4, 0xa6, 0x55, 0xab, 0xc3, 0x60, 0x1c, 0xdf, 0x43, + 0x19, 0xea, 0x52, 0x4b, 0x27, 0x08, 0x30, 0x62, 0x8d, 0x1c, 0x4f, 0xd7, 0xc5, 0xb4, 0x0d, 0xf0, + 0x61, 0xe4, 0x78, 0xe2, 0x0b, 0xb8, 0x8c, 0x38, 0x9b, 0x0b, 0x5a, 0xc3, 0x6c, 0x22, 0x13, 0xdf, + 0xb5, 0x1d, 0x45, 0x75, 0x32, 0xba, 0x3c, 0x66, 0x0d, 0x29, 0xee, 0x23, 0xc1, 0x23, 0xc6, 0x6f, + 0xab, 0xef, 0x65, 0x12, 0x89, 0xef, 0x29, 0x5b, 0x3e, 0xcf, 0x7d, 0x37, 0xdb, 0x12, 0x6f, 0x17, + 0x6b, 0xf5, 0x12, 0x4a, 0xaa, 0x43, 0x43, 0x84, 0x65, 0x9c, 0x3e, 0x6a, 0x2f, 0xbe, 0x05, 0x61, + 0x0c, 0x1c, 0x71, 0x7e, 0xea, 0xa8, 0x13, 0x2e, 0xca, 0x9d, 0xda, 0x6a, 0x9b, 0xe3, 0xa3, 0x5a, + 0xc6, 0x32, 0x22, 0x10, 0x01, 0x4a, 0xfc, 0x0e, 0x56, 0xf3, 0xce, 0xb4, 0x2f, 0x43, 0xdd, 0xf1, + 0x86, 0xc6, 0xb5, 0xf3, 0xdd, 0x4d, 0xb9, 0x40, 0x96, 0x19, 0x09, 0x83, 0xb9, 0xcb, 0xaf, 0xa1, + 0x67, 0xba, 0xe4, 0x59, 0x57, 0x83, 0x3e, 0xf5, 0xf6, 0xd6, 0xb9, 0xde, 0xa6, 0x6c, 0x7b, 0x6e, + 0x9f, 0x19, 0x8a, 0x3f, 0x9a, 0x5b, 0x72, 0x63, 0x65, 0x68, 0x3b, 0xa4, 0xb5, 0xb5, 0x7e, 0xae, + 0xa7, 0x19, 0x63, 0x65, 0x99, 0x21, 0x18, 0xb8, 0xf8, 0x08, 0x2e, 0x98, 0xce, 0x22, 0x0a, 0xf1, + 0x6c, 0x3f, 0xa2, 0xe8, 0x4f, 0xb0, 0x8b, 0xa5, 0x91, 0x1c, 0xfe, 0xed, 0x46, 0x1c, 0x2d, 0x5e, + 0x31, 0x4d, 0xd8, 0x0a, 0x53, 0x44, 0x9c, 0xff, 0xd4, 0x0a, 0xd9, 0xae, 0x81, 0x26, 0x61, 0xbb, + 0x8c, 0x11, 0xb0, 0x19, 0xfe, 0x06, 0xf4, 0xa9, 0x72, 0x1e, 0x97, 0x35, 0x4a, 0x3c, 0x3f, 0x74, + 0x82, 0xc1, 0x2a, 0xef, 0xb9, 0x22, 0xdc, 0x8a, 0x9e, 0x3f, 0x66, 0xa8, 0x38, 0x84, 0x35, 0xf3, + 0xa1, 0x5c, 0xcd, 0x28, 0x34, 0x25, 0xb4, 0xe1, 0x3d, 0x6f, 0xe2, 0xa6, 0x0c, 0x8e, 0x65, 0x96, + 0x70, 0xda, 0x0c, 0xdd, 0x83, 0x6b, 0x33, 0x4b, 0x3b, 0x71, 0x4e, 0xed, 0x89, 0x9c, 0x44, 0xc9, + 0x99, 0x36, 0x20, 0x6b, 0xa4, 0xc0, 0xae, 0x4c, 0x2d, 0xe2, 0x9e, 0x73, 0xba, 0x47, 0x34, 0x6c, + 0x4e, 0xbe, 0x82, 0xab, 0x33, 0xbd, 0x70, 0x21, 0xba, 0x0c, 0x9d, 0xa3, 0x40, 0x7a, 0xb4, 0x45, + 0xde, 0xb0, 0x2e, 0x4d, 0x75, 0x71, 0x80, 0x14, 0xf7, 0x99, 0x40, 0x7c, 0x09, 0xa4, 0xec, 0x15, + 0x9d, 0xb4, 0xb3, 0x95, 0xeb, 0x84, 0xb4, 0x2b, 0x9e, 0x57, 0x55, 0x20, 0x2f, 0xf2, 0x31, 0x3c, + 0xd4, 0x94, 0x56, 0xb7, 0x20, 0x26, 0xcd, 0xf9, 0x09, 0xb4, 0xcd, 0xc6, 0x32, 0xb5, 0xbd, 0x44, + 0x6d, 0x97, 0xb9, 0xad, 0xde, 0x4a, 0xa6, 0x86, 0xad, 0x51, 0xf1, 0x22, 0x36, 0x01, 0x4e, 0x9c, + 0xd1, 0x89, 0xc3, 0x6d, 0x2e, 0x97, 0x03, 0xfc, 0x6f, 0x11, 0x4e, 0x2d, 0x9a, 0x27, 0xe6, 0x51, + 0x7c, 0x0e, 0x97, 0x8c, 0x14, 0x3e, 0x3f, 0x8e, 0x02, 0xed, 0xb0, 0x8f, 0x9c, 0x30, 0xca, 0x52, + 0xbd, 0x51, 0xbe, 0xa6, 0x09, 0xbe, 0x43, 0x3c, 0x0a, 0xc0, 0x03, 0xc2, 0x6a, 0x87, 0xf5, 0x08, + 0x9a, 0xb4, 0xcd, 0x43, 0xbd, 0xe5, 0x87, 0x1e, 0x2a, 0xaf, 0x3e, 0xf4, 0xf0, 0x21, 0xb4, 0x75, + 0x34, 0xf3, 0xb2, 0x53, 0x14, 0x2d, 0xc6, 0x73, 0x42, 0xf4, 0x16, 0x34, 0x29, 0x94, 0xa1, 0x6f, + 0x5c, 0x83, 0x16, 0x9f, 0xb4, 0x3b, 0x0a, 0x22, 0xf7, 0xc4, 0x04, 0x1f, 0x04, 0xba, 0x8b, 0x90, + 0x21, 0x40, 0xe3, 0x49, 0xe8, 0x47, 0xe1, 0x76, 0x10, 0x0c, 0xff, 0x54, 0x83, 0x26, 0xfa, 0x3c, + 0xb4, 0x2f, 0x85, 0x61, 0x23, 0x31, 0x26, 0xd5, 0x55, 0x4c, 0x9c, 0x58, 0x1f, 0xeb, 0x68, 0x21, + 0x10, 0xa9, 0xf6, 0x9c, 0x78, 0xa6, 0xec, 0x62, 0x61, 0xa6, 0xec, 0xe2, 0x6d, 0x3e, 0xf7, 0xc9, + 0x55, 0xb3, 0xd2, 0x94, 0xdb, 0x53, 0x07, 0x77, 0x19, 0x84, 0xbe, 0x18, 0x91, 0x38, 0x01, 0xf9, + 0x6f, 0x18, 0x1d, 0x06, 0x4a, 0x57, 0x68, 0x90, 0x5c, 0x6c, 0x6b, 0xc4, 0x81, 0x64, 0x7b, 0x53, + 0xda, 0x8c, 0xac, 0xce, 0x6e, 0x46, 0xde, 0x04, 0x70, 0xa3, 0xd0, 0x23, 0x17, 0x71, 0x26, 0x21, + 0xcd, 0xe5, 0x11, 0x05, 0xf6, 0x47, 0x6c, 0x93, 0xbf, 0x07, 0xfd, 0x9c, 0x02, 0x3d, 0x40, 0x37, + 0xcc, 0xe3, 0x6b, 0x4d, 0x65, 0xc9, 0xd1, 0x4e, 0x98, 0xce, 0xee, 0xa7, 0x37, 0xcf, 0xed, 0xa7, + 0xbf, 0xa4, 0x90, 0x06, 0x7e, 0xf2, 0xe9, 0xb9, 0x4b, 0xd0, 0xa0, 0x8a, 0x3d, 0x2f, 0x8b, 0xb5, + 0x2d, 0xaa, 0xfb, 0x8a, 0xf2, 0x1e, 0x2f, 0xdb, 0xb3, 0x6f, 0xff, 0xdf, 0xda, 0xb3, 0xef, 0xfc, + 0xb8, 0x3d, 0xfb, 0xee, 0x8f, 0xdb, 0xb3, 0x9f, 0xd9, 0xe3, 0xee, 0xcd, 0xee, 0x71, 0xbf, 0x34, + 0xad, 0xd8, 0x7f, 0x69, 0x5a, 0xf1, 0x35, 0x39, 0xc1, 0xe5, 0x57, 0xe7, 0x04, 0x5f, 0x9f, 0x94, + 0x14, 0xaf, 0x4b, 0x4a, 0xde, 0x80, 0x5e, 0x9a, 0x38, 0xee, 0x09, 0x47, 0x5a, 0x27, 0xf2, 0x4c, + 0xe9, 0x24, 0x68, 0x87, 0xc0, 0x18, 0x67, 0x7d, 0x2b, 0xcf, 0xd4, 0xf0, 0x09, 0x00, 0x85, 0xa0, + 0xf4, 0x6b, 0x2f, 0xe3, 0x8d, 0xca, 0x4f, 0x2e, 0xb2, 0xfa, 0xeb, 0x0a, 0xc0, 0x81, 0x33, 0x89, + 0x79, 0x0f, 0x59, 0xfc, 0x19, 0xb4, 0x14, 0xbd, 0x95, 0x8b, 0x4c, 0x4a, 0x86, 0xba, 0x20, 0xd5, + 0x8f, 0x7c, 0xb8, 0x4b, 0xe5, 0xcf, 0xc4, 0xd6, 0xdc, 0x43, 0x5e, 0xd0, 0x5a, 0x35, 0x04, 0xb4, + 0xb7, 0x77, 0x1d, 0xba, 0x9a, 0x20, 0x96, 0x89, 0x2b, 0x43, 0xae, 0xef, 0xaf, 0x58, 0x1d, 0x86, + 0xee, 0x33, 0x50, 0x7c, 0x94, 0x93, 0x19, 0x93, 0x78, 0x3e, 0x65, 0xa6, 0x9b, 0x68, 0x9b, 0x38, + 0xdc, 0x32, 0xbf, 0x42, 0x03, 0x69, 0xc0, 0x12, 0x7e, 0xaf, 0xff, 0x86, 0x68, 0x41, 0x5d, 0xf7, + 0xda, 0xaf, 0x88, 0x0e, 0x34, 0xe9, 0x34, 0x21, 0xe1, 0x16, 0x86, 0x7f, 0x5a, 0x85, 0xd6, 0x6e, + 0xa8, 0xd2, 0x24, 0x63, 0x16, 0x2e, 0xce, 0xcc, 0x55, 0xe9, 0xcc, 0x9c, 0xae, 0x03, 0xe7, 0xdf, + 0xa0, 0x3a, 0xf0, 0x0f, 0xa1, 0xae, 0x8f, 0x67, 0xea, 0xc4, 0xc2, 0xdc, 0xb3, 0x9d, 0x86, 0x46, + 0x6c, 0x42, 0xc3, 0xd3, 0xe7, 0x46, 0x75, 0x25, 0x4d, 0xe9, 0x30, 0xa7, 0x39, 0x51, 0x6a, 0xe5, + 0x34, 0xe2, 0x6d, 0x58, 0x74, 0xc6, 0x63, 0x1d, 0xd5, 0xf7, 0x0a, 0x52, 0x72, 0xd2, 0x2c, 0xc4, + 0x89, 0xdb, 0xd0, 0x24, 0xf5, 0x49, 0x55, 0x6d, 0xb5, 0xd9, 0x3e, 0x4d, 0xc9, 0x1c, 0x6b, 0x54, + 0xca, 0x49, 0xdc, 0x86, 0x66, 0x10, 0x45, 0x31, 0x37, 0xa8, 0xcf, 0x36, 0x30, 0xf5, 0x45, 0x56, + 0x23, 0x30, 0x95, 0x46, 0x37, 0xa0, 0x86, 0xee, 0x7f, 0x14, 0x6b, 0xb7, 0xb9, 0x34, 0x0e, 0xaa, + 0xb3, 0xb1, 0xaa, 0x8a, 0xca, 0x6d, 0xb6, 0x00, 0x98, 0xff, 0xa9, 0xe7, 0xe6, 0xec, 0x74, 0xe4, + 0xb9, 0x55, 0x14, 0x52, 0x93, 0x66, 0xbd, 0x0b, 0x7d, 0xce, 0xa3, 0x95, 0x5a, 0x82, 0xa9, 0x05, + 0x36, 0x2d, 0xa7, 0x53, 0xb3, 0x56, 0x37, 0x99, 0x4e, 0xd5, 0x7e, 0x00, 0xf5, 0x98, 0x93, 0x43, + 0xa4, 0x61, 0xc8, 0x64, 0x9b, 0xa6, 0x3a, 0x6b, 0x64, 0x19, 0x0a, 0xf1, 0x1b, 0xe8, 0x72, 0xcd, + 0xea, 0x48, 0x67, 0x49, 0x68, 0x67, 0x6f, 0xea, 0x64, 0xdf, 0x54, 0x12, 0xc5, 0xea, 0xa4, 0x53, + 0x39, 0x95, 0x5f, 0x41, 0xa7, 0x38, 0xb0, 0x84, 0x16, 0xbf, 0x67, 0xb2, 0x15, 0xa6, 0x79, 0x39, + 0x1a, 0xb3, 0xda, 0xb2, 0x1c, 0x9b, 0x6d, 0x40, 0x4d, 0xd7, 0x51, 0xf7, 0xa9, 0x55, 0xe9, 0xd6, + 0x05, 0xae, 0x9c, 0xb4, 0x34, 0x1e, 0xe7, 0xb2, 0x28, 0x11, 0x25, 0xc7, 0x71, 0x6a, 0x2e, 0xf3, + 0xfa, 0x50, 0xab, 0x99, 0x97, 0x86, 0x8a, 0xfb, 0xd3, 0x25, 0xab, 0x9c, 0xd4, 0x5b, 0xa1, 0xa6, + 0x97, 0xe6, 0x34, 0xe5, 0xf4, 0x9e, 0xd5, 0x8b, 0x67, 0x2a, 0x5f, 0x6f, 0x41, 0x23, 0x4a, 0x3c, + 0x3a, 0x1f, 0x40, 0x55, 0x14, 0xb9, 0x0b, 0xa4, 0xcf, 0xa4, 0x92, 0xf2, 0xa8, 0x47, 0xfc, 0x82, + 0x8e, 0x45, 0x9c, 0x44, 0xe4, 0xe5, 0x92, 0x8a, 0xbb, 0x70, 0xde, 0xb1, 0xd0, 0x78, 0x52, 0x70, + 0xef, 0x42, 0xdd, 0x54, 0x87, 0xaf, 0x9d, 0xa3, 0x34, 0x28, 0xf1, 0x31, 0xf4, 0xa6, 0x15, 0x9a, + 0x1a, 0x5c, 0x3c, 0x47, 0xdd, 0x9d, 0xd2, 0x5f, 0x68, 0x8d, 0xab, 0x81, 0x3f, 0xf1, 0x53, 0xed, + 0xf3, 0x4d, 0x9d, 0x10, 0x25, 0x04, 0xc6, 0x7f, 0x3a, 0x05, 0x72, 0xe9, 0x7c, 0xfc, 0xa7, 0xd3, + 0x24, 0x03, 0xa8, 0xfb, 0xea, 0x81, 0x9f, 0xa8, 0x54, 0xd7, 0x37, 0x98, 0x57, 0xb1, 0x06, 0x35, + 0x5f, 0xa1, 0x99, 0xd0, 0x5e, 0x9a, 0x7e, 0x13, 0x37, 0xa1, 0xa6, 0x2b, 0xe7, 0xd7, 0xcf, 0x49, + 0xb4, 0x3e, 0x59, 0x63, 0x69, 0x0a, 0xf1, 0x3e, 0xd4, 0xa9, 0x6c, 0x3a, 0x8a, 0x07, 0x6f, 0xcf, + 0x72, 0x00, 0xd7, 0x2e, 0x5b, 0xb5, 0x80, 0x6b, 0x98, 0x3f, 0x80, 0xba, 0x71, 0x52, 0x86, 0xb3, + 0x5c, 0xad, 0x9d, 0x15, 0xcb, 0x50, 0x88, 0xeb, 0x50, 0x9d, 0xa0, 0x1e, 0x1b, 0xbc, 0x33, 0x2b, + 0xa1, 0xac, 0xde, 0x18, 0x2b, 0xfe, 0x7f, 0xb8, 0x5c, 0x2e, 0x3c, 0x36, 0x55, 0xc9, 0x7a, 0x83, + 0xf3, 0x3a, 0xb5, 0x7d, 0x7b, 0x0e, 0xab, 0x4c, 0xd7, 0x2f, 0x5b, 0x17, 0xe3, 0x97, 0x14, 0x36, + 0x7f, 0x9a, 0xab, 0x7b, 0x94, 0xae, 0xc1, 0x0d, 0xe3, 0x7c, 0x9f, 0x37, 0x18, 0xc6, 0x08, 0x90, + 0x9d, 0xf9, 0x0c, 0xda, 0xa3, 0xec, 0xc5, 0x8b, 0x33, 0xb3, 0x39, 0xff, 0x1e, 0xb5, 0x2b, 0x6d, + 0x31, 0x94, 0x6a, 0x9d, 0xad, 0xd6, 0xa8, 0x54, 0xf8, 0x7c, 0x11, 0xea, 0x6e, 0x68, 0x3b, 0x9e, + 0x97, 0x0c, 0x36, 0xb8, 0xd6, 0xd9, 0x0d, 0xb7, 0x3d, 0x8f, 0x2e, 0x77, 0x88, 0x62, 0x49, 0x27, + 0xa4, 0x6d, 0xdf, 0x1b, 0xbc, 0xcf, 0x86, 0xc7, 0x80, 0x76, 0x3d, 0xba, 0xfd, 0xc1, 0xc4, 0xe5, + 0xbe, 0x37, 0xb8, 0xa9, 0x6f, 0x7f, 0xd0, 0xa0, 0x5d, 0x0f, 0x1d, 0x4f, 0x0c, 0x62, 0x0c, 0x64, + 0xf0, 0x01, 0x27, 0x3c, 0x26, 0xce, 0xe9, 0xbe, 0x06, 0xa1, 0x90, 0x72, 0x6a, 0x8f, 0xd4, 0xd6, + 0xad, 0x59, 0x21, 0xcd, 0xd3, 0xc0, 0x56, 0xd3, 0xcf, 0x33, 0xc2, 0x24, 0xd8, 0xa4, 0x8a, 0xec, + 0x60, 0x6b, 0xf0, 0xe1, 0x79, 0xc1, 0xd6, 0x59, 0x6e, 0x14, 0x6c, 0x93, 0xf0, 0xde, 0x02, 0x60, + 0x9d, 0x45, 0x0a, 0x67, 0x73, 0xb6, 0x4d, 0x1e, 0x0d, 0x58, 0x7c, 0xa4, 0x89, 0x54, 0xcd, 0x16, + 0x00, 0xa5, 0x17, 0xb8, 0xcd, 0xed, 0xd9, 0x36, 0xb9, 0x77, 0x6f, 0x35, 0x9f, 0xe5, 0x8e, 0xfe, + 0x6d, 0x68, 0x66, 0xe8, 0xc7, 0xa3, 0x27, 0x3d, 0xb8, 0x33, 0xcb, 0xcc, 0xc6, 0xc5, 0xb7, 0x1a, + 0x99, 0x7e, 0xc2, 0x8f, 0x90, 0xed, 0x21, 0x37, 0x64, 0xf0, 0xd1, 0xec, 0x47, 0xf2, 0x38, 0xc0, + 0x22, 0x13, 0xc5, 0x21, 0xc1, 0xa7, 0xd0, 0xe2, 0x49, 0xe3, 0x46, 0x5b, 0xb3, 0x3c, 0x52, 0xf8, + 0x35, 0x16, 0xcf, 0x2e, 0x37, 0xbb, 0x0e, 0x55, 0x27, 0x8e, 0x83, 0xb3, 0xc1, 0xc7, 0xb3, 0x1c, + 0xbe, 0x8d, 0x60, 0x8b, 0xb1, 0xc8, 0x4a, 0x93, 0x2c, 0x48, 0x7d, 0x73, 0x0a, 0xe9, 0x93, 0x59, + 0x56, 0x2a, 0x1d, 0xeb, 0xb4, 0x5a, 0x93, 0xd2, 0x19, 0xcf, 0x5b, 0xd0, 0x88, 0x23, 0x95, 0xda, + 0xde, 0x24, 0x18, 0x7c, 0x7a, 0xce, 0x8c, 0xf0, 0x89, 0x14, 0xab, 0x1e, 0xeb, 0x23, 0x3d, 0x53, + 0xa7, 0xa4, 0x7f, 0x31, 0x73, 0x4a, 0x7a, 0x0b, 0xda, 0x93, 0x28, 0x1c, 0x47, 0xde, 0x11, 0xcf, + 0xfe, 0x2f, 0xcb, 0x41, 0xe1, 0x1e, 0x62, 0x38, 0x8c, 0xd4, 0x44, 0xda, 0x34, 0xf4, 0xb5, 0xef, + 0xe6, 0x2b, 0xdb, 0x51, 0xa4, 0xf6, 0x3f, 0xe3, 0x10, 0x9e, 0xe1, 0xbb, 0x6a, 0x9b, 0xa0, 0xd3, + 0xdb, 0xdb, 0x47, 0x67, 0x3a, 0x17, 0xf9, 0x39, 0xb1, 0x67, 0xb1, 0xbd, 0x7d, 0xf7, 0x8c, 0x13, + 0x92, 0x5f, 0xc0, 0xe5, 0xd2, 0xb9, 0xc5, 0x28, 0xb6, 0x43, 0x1b, 0x55, 0x40, 0x22, 0xbd, 0xcc, + 0x95, 0x83, 0x2f, 0xf2, 0x78, 0x53, 0x1f, 0x5e, 0x8c, 0xe2, 0x47, 0xfb, 0x89, 0xb4, 0x08, 0x2b, + 0x1e, 0x95, 0xcf, 0x48, 0x3a, 0xc1, 0x38, 0x4a, 0xfc, 0xf4, 0x78, 0x32, 0xf8, 0x15, 0xf9, 0x81, + 0x6f, 0x96, 0xe2, 0x81, 0x3c, 0xff, 0xb5, 0x6d, 0x88, 0xac, 0x62, 0x8c, 0x39, 0x4c, 0x7c, 0x01, + 0x97, 0xb4, 0x2d, 0xc0, 0x0e, 0xa7, 0x8e, 0xa2, 0xab, 0xc1, 0xaf, 0xe9, 0x2c, 0xfa, 0xc5, 0x82, + 0xe0, 0xeb, 0xd2, 0xa9, 0x74, 0x25, 0xb6, 0xe1, 0xcd, 0x79, 0x6d, 0xd1, 0x31, 0xe1, 0x09, 0xf8, + 0x92, 0x26, 0xe0, 0xf2, 0xf9, 0xf6, 0x07, 0x52, 0xdf, 0x4b, 0x73, 0x0b, 0x04, 0x4e, 0x00, 0x59, + 0x2e, 0xe9, 0xd9, 0x51, 0x96, 0xc6, 0x59, 0x3a, 0xf8, 0x0d, 0xc7, 0x89, 0x69, 0x14, 0x3f, 0x66, + 0xc4, 0x63, 0x82, 0x63, 0x9c, 0x4e, 0x4a, 0xd3, 0x2e, 0xb7, 0xe1, 0xdd, 0x02, 0x35, 0xf8, 0x8a, + 0xe7, 0x8d, 0x08, 0x0e, 0xf3, 0x96, 0xbc, 0xb7, 0xa0, 0x38, 0x4e, 0xff, 0xed, 0x52, 0x63, 0xb9, + 0x2f, 0x7e, 0xbb, 0xd4, 0x78, 0xb7, 0x7f, 0xdd, 0x6a, 0x95, 0xf6, 0x24, 0x86, 0x9f, 0x42, 0x7b, + 0x9b, 0x6e, 0x3e, 0xf2, 0x15, 0xd9, 0xc4, 0xeb, 0xb0, 0x94, 0xd7, 0xb2, 0xe4, 0xc6, 0x96, 0x28, + 0x5e, 0xc8, 0xdd, 0x70, 0x14, 0x59, 0x84, 0x1e, 0xfe, 0xab, 0x25, 0xa8, 0x71, 0x7d, 0xc1, 0xeb, + 0x4f, 0x37, 0xbe, 0x69, 0x34, 0x46, 0x58, 0x1c, 0x03, 0x61, 0xe5, 0x40, 0xe8, 0xd9, 0x72, 0xef, + 0x66, 0x51, 0x26, 0xb3, 0x0a, 0x55, 0x0e, 0xf3, 0x39, 0xfb, 0xc1, 0x2f, 0xa4, 0x2d, 0x33, 0x75, + 0x4c, 0xd7, 0x1b, 0xe9, 0x7c, 0xde, 0x92, 0x05, 0x06, 0xb4, 0xeb, 0xd1, 0x36, 0xa7, 0x21, 0x20, + 0x75, 0x5c, 0xd3, 0x69, 0x0c, 0x0d, 0x24, 0xa5, 0x6c, 0x4a, 0x70, 0xea, 0x2f, 0x29, 0xc1, 0x79, + 0x0b, 0x96, 0x42, 0x73, 0x42, 0x29, 0xc7, 0xd3, 0xf5, 0x26, 0x04, 0x17, 0x37, 0x21, 0x3f, 0x92, + 0xa9, 0xdd, 0xcb, 0x97, 0x1f, 0xd9, 0xdc, 0x82, 0x66, 0x7e, 0x57, 0x96, 0xf6, 0x28, 0x57, 0x37, + 0x8b, 0xdb, 0xb3, 0x0e, 0xcd, 0x93, 0x55, 0x90, 0xbd, 0xba, 0x90, 0xa4, 0xf5, 0xf3, 0x0a, 0x49, + 0x38, 0xdc, 0x76, 0xa3, 0x50, 0xa5, 0x7a, 0x23, 0xb7, 0xee, 0xab, 0x1d, 0x7c, 0x15, 0x9f, 0x43, + 0x27, 0x91, 0xee, 0x33, 0x7b, 0xa2, 0xc6, 0xfc, 0x89, 0x4e, 0xf9, 0x58, 0xf8, 0x44, 0x8d, 0xbf, + 0xa1, 0x22, 0x17, 0x1d, 0xfd, 0xb6, 0x90, 0x76, 0x4f, 0x8d, 0xa9, 0xd7, 0x0f, 0x60, 0x79, 0x22, + 0x27, 0x47, 0x32, 0x51, 0xc7, 0x7e, 0x6c, 0xcc, 0x66, 0x97, 0x8a, 0x71, 0xfa, 0x05, 0x82, 0xc7, + 0x32, 0xfc, 0xfb, 0x15, 0x68, 0xe0, 0x2c, 0x22, 0x2f, 0x09, 0x01, 0x4b, 0x13, 0x37, 0xce, 0x74, + 0x50, 0x43, 0xcf, 0xfa, 0xfe, 0x2d, 0xe6, 0x12, 0x7d, 0xff, 0x16, 0xad, 0x21, 0xa7, 0x27, 0xe9, + 0x99, 0xaf, 0x54, 0x39, 0xa3, 0x1d, 0x6c, 0xe6, 0x0c, 0xf3, 0x2a, 0x2e, 0x40, 0xcd, 0x0d, 0x69, + 0x67, 0x83, 0xd3, 0xbc, 0x55, 0x37, 0xdc, 0x09, 0x53, 0x0d, 0x2e, 0x4e, 0xb9, 0x54, 0xdd, 0x70, + 0xd7, 0x3b, 0x1d, 0xfe, 0xdb, 0x0a, 0x2c, 0xef, 0x27, 0x91, 0x2b, 0x95, 0x7a, 0x88, 0x4e, 0x19, + 0xa5, 0xd4, 0xf0, 0x8b, 0x94, 0x81, 0xe0, 0xec, 0x15, 0x3d, 0x23, 0x0f, 0xf3, 0xb6, 0x53, 0x1e, + 0x3a, 0x2e, 0x5a, 0x4d, 0x82, 0x50, 0xe4, 0x98, 0xa3, 0x4b, 0xa5, 0x1a, 0x8c, 0xa6, 0xdc, 0xc5, + 0x75, 0xe8, 0x16, 0xba, 0xab, 0x54, 0x55, 0x52, 0x5c, 0x7c, 0x40, 0xbd, 0x5c, 0x83, 0x96, 0xae, + 0x3d, 0xa2, 0x6e, 0x38, 0x1d, 0x05, 0x0c, 0x3a, 0xd0, 0xa3, 0x60, 0x45, 0x4f, 0x78, 0x4e, 0x40, + 0xb1, 0xea, 0x47, 0xf4, 0xf0, 0x0f, 0x15, 0xe8, 0xef, 0x27, 0x32, 0x76, 0x12, 0x49, 0xc5, 0x48, + 0x34, 0xc7, 0x6b, 0x50, 0x0b, 0x64, 0x38, 0xd6, 0xf5, 0x27, 0x8b, 0x96, 0x7e, 0xcb, 0xef, 0x4e, + 0x5b, 0x28, 0xdd, 0x9d, 0x86, 0x73, 0x9d, 0x48, 0x47, 0x5f, 0xb1, 0x46, 0xcf, 0x28, 0x83, 0x18, + 0xff, 0x73, 0x90, 0xdb, 0xb0, 0xf8, 0x45, 0x1f, 0xaf, 0x3e, 0xf2, 0x43, 0x2a, 0xfa, 0xa4, 0xe3, + 0xd5, 0x77, 0x7d, 0x32, 0x1c, 0x0c, 0x46, 0x47, 0x8e, 0xaf, 0x29, 0xa2, 0x6d, 0xab, 0x86, 0xd5, + 0x25, 0x02, 0x27, 0x39, 0x3b, 0x20, 0x28, 0xc5, 0xda, 0x7c, 0xbb, 0x11, 0x57, 0x34, 0x71, 0xc2, + 0xa4, 0x63, 0x2e, 0x37, 0x62, 0xdd, 0xa2, 0x86, 0xff, 0xb8, 0x0e, 0x2d, 0xbd, 0x42, 0xf4, 0x37, + 0xcc, 0x1d, 0x95, 0x9c, 0x3b, 0xfa, 0xb0, 0xa8, 0x9e, 0x06, 0x9a, 0x5d, 0xf0, 0x51, 0x7c, 0x0c, + 0x8b, 0x81, 0x3f, 0xd1, 0x01, 0xf0, 0x95, 0x29, 0x67, 0x66, 0x7a, 0x9d, 0x35, 0x2b, 0x23, 0x35, + 0x5a, 0x50, 0xba, 0xeb, 0x01, 0x85, 0x46, 0xaf, 0x0d, 0x3a, 0x16, 0xa7, 0x28, 0x99, 0x38, 0xeb, + 0x8e, 0xcb, 0x05, 0xc7, 0x5a, 0xdd, 0x74, 0xac, 0xa6, 0x86, 0xec, 0x7a, 0xe2, 0x13, 0x68, 0xe4, + 0xdb, 0xf4, 0x26, 0xe4, 0x4d, 0x4f, 0xc3, 0xcd, 0x9d, 0x47, 0x87, 0xa7, 0xa1, 0xd9, 0x87, 0xd7, + 0x1f, 0xcb, 0x29, 0xc5, 0x6f, 0xa0, 0xad, 0xa4, 0x52, 0x7c, 0x18, 0x7f, 0x14, 0x69, 0x35, 0x74, + 0xa1, 0x1c, 0xcd, 0x12, 0x16, 0xff, 0xda, 0x08, 0x9d, 0x2a, 0x40, 0xe2, 0x1b, 0xe8, 0x9a, 0xf6, + 0x41, 0x34, 0x1e, 0xe7, 0x69, 0xa4, 0x2b, 0xe7, 0x7a, 0x78, 0x48, 0xe8, 0x52, 0x3f, 0x1d, 0x55, + 0x46, 0x88, 0xaf, 0xa1, 0x1b, 0x33, 0xd3, 0xd8, 0xba, 0x90, 0x8e, 0xd5, 0xd9, 0xe5, 0x29, 0xdf, + 0x7b, 0x8a, 0xa9, 0x8a, 0x43, 0xa7, 0x05, 0x5c, 0x9d, 0xbf, 0x98, 0x82, 0xf3, 0x8a, 0xd3, 0x17, + 0x53, 0x48, 0x58, 0xd3, 0x37, 0x49, 0x8d, 0x12, 0x87, 0x0e, 0xd8, 0xb3, 0xc9, 0x34, 0xd5, 0xb1, + 0xb7, 0xcf, 0xad, 0x18, 0x7e, 0x70, 0x93, 0x2f, 0x60, 0x78, 0xa0, 0x9b, 0x90, 0x09, 0xd5, 0xa5, + 0x46, 0xab, 0xc9, 0x1c, 0x94, 0xd8, 0x84, 0x15, 0xfd, 0x19, 0x79, 0x2a, 0xdd, 0x4c, 0xdf, 0x2d, + 0x42, 0x4a, 0xaf, 0x6d, 0x2d, 0x33, 0xea, 0xbe, 0xc1, 0xec, 0x7a, 0xe2, 0x33, 0x18, 0xa8, 0xd4, + 0x49, 0x25, 0x0d, 0xc8, 0xe8, 0x5d, 0x7f, 0x1c, 0x46, 0x89, 0xd4, 0xe5, 0x39, 0x6b, 0x39, 0x5e, + 0xeb, 0xdb, 0x5d, 0xc2, 0x8a, 0xdf, 0x40, 0x1f, 0x55, 0x64, 0x9e, 0xaa, 0xb1, 0x53, 0xa5, 0xa3, + 0xf8, 0xf9, 0x2a, 0xbe, 0x8b, 0xd4, 0x86, 0x2d, 0x0e, 0x29, 0xe5, 0x4f, 0xed, 0xc7, 0x32, 0xc4, + 0x78, 0x80, 0x34, 0x84, 0xcc, 0x94, 0xf4, 0xf4, 0xf5, 0x31, 0xab, 0x88, 0xfd, 0x3a, 0x47, 0x5a, + 0x84, 0x43, 0x0f, 0xc4, 0x88, 0x8f, 0xde, 0xa9, 0x25, 0xdf, 0xb7, 0xf0, 0x8b, 0xfa, 0xc4, 0xa6, + 0x97, 0xb5, 0x34, 0x31, 0x0d, 0xba, 0xc0, 0xb9, 0x03, 0x74, 0xf9, 0x6b, 0xb8, 0xf4, 0xd2, 0x59, + 0x7d, 0x5d, 0xbd, 0x50, 0xa7, 0x7c, 0xd9, 0xc1, 0xff, 0x5a, 0x84, 0x56, 0x89, 0x5b, 0xe9, 0xc6, + 0x44, 0x25, 0x13, 0x53, 0x15, 0x88, 0xcf, 0x08, 0x3b, 0x8e, 0x94, 0x29, 0x72, 0xa3, 0x67, 0x84, + 0x25, 0x51, 0x5e, 0xec, 0x43, 0xcf, 0xc8, 0x43, 0x7a, 0x7b, 0x4a, 0xaf, 0xd8, 0x12, 0x5f, 0xd2, + 0x51, 0x00, 0x77, 0x3d, 0xba, 0x5a, 0xd1, 0x49, 0x9d, 0x23, 0x47, 0x99, 0xf2, 0xce, 0xfc, 0x1d, + 0x4d, 0xc3, 0x33, 0x99, 0xe0, 0x58, 0x4c, 0x71, 0x83, 0x7e, 0x45, 0x19, 0xa7, 0x55, 0x7d, 0x11, + 0x85, 0x5c, 0xd8, 0xd0, 0xb6, 0x1a, 0x08, 0xf8, 0x3e, 0x0a, 0xa9, 0x99, 0x96, 0x68, 0x5d, 0xa0, + 0x63, 0x5e, 0xd1, 0x66, 0x3e, 0xcd, 0x24, 0xc6, 0xa5, 0x1e, 0x1d, 0x66, 0x6c, 0x5a, 0x75, 0x7a, + 0xe7, 0x9a, 0x21, 0x0a, 0xa0, 0x9f, 0x3b, 0x7e, 0x4a, 0xaa, 0x23, 0xca, 0x52, 0xcd, 0xf4, 0x3d, + 0x44, 0x7c, 0xe7, 0xf8, 0xe9, 0x21, 0x83, 0xc5, 0x47, 0xfa, 0x8c, 0x72, 0x99, 0x96, 0x2e, 0x09, + 0xe2, 0x6d, 0x6f, 0x31, 0x43, 0x7f, 0x20, 0xe9, 0x1e, 0xbc, 0x89, 0x93, 0x26, 0xfe, 0x69, 0x14, + 0xa2, 0xef, 0x44, 0xf7, 0x01, 0xe4, 0xd7, 0x39, 0x36, 0xac, 0x95, 0x1c, 0xf9, 0x88, 0x70, 0x94, + 0x09, 0x7e, 0x02, 0x1b, 0xf2, 0x34, 0x0e, 0x7c, 0xd7, 0x9f, 0xb9, 0xd7, 0xc0, 0x76, 0x1d, 0x95, + 0xda, 0x89, 0x4c, 0xb3, 0x24, 0x54, 0xb4, 0xa3, 0xab, 0xf9, 0xfa, 0x1d, 0x43, 0x5f, 0xbe, 0xeb, + 0x60, 0xc7, 0x51, 0xa9, 0xc5, 0xb4, 0x8f, 0xb2, 0x20, 0xc0, 0x49, 0xc8, 0x33, 0xd0, 0x5c, 0x7c, + 0x56, 0x57, 0x9c, 0x7b, 0x1e, 0xfe, 0xa7, 0x0a, 0x2c, 0x9f, 0xd3, 0x34, 0x18, 0x0b, 0xa3, 0x96, + 0x31, 0x05, 0x33, 0x6d, 0xab, 0x86, 0xaf, 0xbb, 0x1e, 0x21, 0xd2, 0x49, 0x6a, 0x4a, 0x65, 0x10, + 0x91, 0x4e, 0x50, 0x8d, 0x5e, 0x80, 0x5a, 0x7a, 0x4a, 0x4b, 0xce, 0xd6, 0xa7, 0x9a, 0x9e, 0xe2, + 0x5a, 0x6f, 0x43, 0x33, 0x88, 0xc6, 0x76, 0x20, 0x9f, 0x49, 0xbe, 0x6c, 0xa6, 0xbb, 0xf5, 0xee, + 0x2b, 0x54, 0xdc, 0xe6, 0xc3, 0x68, 0xfc, 0x10, 0x69, 0xad, 0x46, 0xa0, 0x9f, 0x86, 0xbf, 0x85, + 0x86, 0x81, 0x8a, 0x26, 0x54, 0xef, 0xc9, 0xa3, 0x6c, 0xdc, 0x7f, 0x43, 0x34, 0x60, 0x09, 0x5b, + 0xf4, 0x2b, 0xf8, 0xf4, 0x9d, 0x93, 0x84, 0xfd, 0x05, 0x44, 0xdf, 0x4f, 0x92, 0x28, 0xe9, 0x2f, + 0xe2, 0xe3, 0xbe, 0x13, 0xfa, 0x6e, 0x7f, 0x09, 0x1f, 0x1f, 0x38, 0xa9, 0x13, 0xf4, 0xab, 0xc3, + 0x7f, 0x5f, 0x85, 0xc6, 0xbe, 0xfe, 0xba, 0xb8, 0x07, 0x9d, 0xfc, 0xd2, 0xc6, 0xf9, 0x9b, 0xd2, + 0xfb, 0xb3, 0x0f, 0xb4, 0x29, 0xdd, 0x8e, 0x4b, 0x6f, 0xb3, 0x57, 0x3f, 0x2e, 0x9c, 0xbb, 0xfa, + 0xf1, 0x2a, 0x2c, 0x3e, 0x4d, 0xce, 0xa6, 0x6b, 0xc5, 0xf7, 0x03, 0x27, 0xb4, 0x10, 0x2c, 0x3e, + 0x82, 0x16, 0xa5, 0xc3, 0xd9, 0x8c, 0xea, 0x8d, 0xdc, 0xf2, 0x2d, 0xab, 0x5c, 0x05, 0x0c, 0x48, + 0xa4, 0x3d, 0xf6, 0x4d, 0x68, 0xb8, 0xc7, 0x7e, 0xe0, 0x25, 0x32, 0xd4, 0x67, 0x36, 0xc4, 0xf9, + 0x21, 0x5b, 0x39, 0x8d, 0xf8, 0x33, 0xe8, 0xfb, 0xc5, 0x46, 0x74, 0x51, 0xfd, 0x30, 0x65, 0xaf, + 0x4a, 0x5b, 0xd5, 0x56, 0xaf, 0x44, 0x4e, 0x2e, 0x62, 0x71, 0x1b, 0x4b, 0xbd, 0x7c, 0x1b, 0x0b, + 0x5f, 0xc6, 0x47, 0x7e, 0x5c, 0x23, 0xdf, 0xc6, 0x42, 0x37, 0xee, 0x86, 0x76, 0xbe, 0x9b, 0xb3, + 0x71, 0xbf, 0x71, 0x1d, 0xb5, 0x13, 0xfe, 0x2e, 0x74, 0xd1, 0xa9, 0xb7, 0x39, 0x16, 0x40, 0x3b, + 0x0a, 0xfa, 0xf2, 0xa8, 0x4c, 0x1d, 0xdf, 0xc3, 0x68, 0x00, 0x99, 0xf1, 0x3a, 0x74, 0xcd, 0xbf, + 0xe8, 0xf8, 0xac, 0xa5, 0xab, 0x23, 0x34, 0x94, 0x43, 0xb2, 0x4d, 0x58, 0x71, 0x8f, 0x9d, 0x30, + 0x94, 0x81, 0x7d, 0x94, 0x8d, 0x46, 0xc6, 0x0d, 0xe3, 0x1b, 0xc5, 0x96, 0x35, 0xea, 0x2e, 0x61, + 0xc8, 0x1b, 0x1b, 0x42, 0x27, 0xf4, 0x03, 0x73, 0xab, 0x68, 0xc8, 0x2e, 0x73, 0xd5, 0x6a, 0x85, + 0x7e, 0xc0, 0xf7, 0x88, 0xd2, 0xf5, 0xa7, 0xfd, 0x2c, 0xf3, 0x3d, 0x65, 0xa7, 0x91, 0xb9, 0xc7, + 0x50, 0xa7, 0x94, 0x4a, 0x9b, 0xb4, 0x4f, 0x32, 0xdf, 0x3b, 0x8c, 0xf4, 0x4d, 0x86, 0x1d, 0xa2, + 0x37, 0xaf, 0x38, 0xf6, 0xe9, 0x78, 0x8f, 0x4a, 0x14, 0x1a, 0x56, 0x27, 0x2a, 0x87, 0x79, 0xc3, + 0xaf, 0xa0, 0x5d, 0x66, 0x31, 0x64, 0x59, 0xda, 0x6c, 0xeb, 0xbf, 0x21, 0x00, 0x6a, 0x8f, 0xa2, + 0x64, 0xe2, 0x04, 0xfd, 0x0a, 0x3e, 0xb3, 0xce, 0xef, 0x2f, 0x88, 0x36, 0x34, 0xcc, 0xe6, 0x51, + 0x7f, 0x51, 0xa7, 0x73, 0x7f, 0x05, 0x0d, 0x73, 0x8b, 0x23, 0xdd, 0x80, 0x17, 0x79, 0x92, 0x23, + 0x28, 0x5d, 0xbb, 0x8c, 0x00, 0x8a, 0x9e, 0xcc, 0xad, 0xb8, 0x0b, 0xc5, 0xad, 0xb8, 0xc3, 0xdf, + 0x41, 0xbb, 0xfc, 0x27, 0x26, 0x41, 0x51, 0x29, 0x12, 0x14, 0x73, 0x5a, 0x51, 0x4d, 0x4d, 0x12, + 0x4d, 0xec, 0x92, 0x93, 0xdf, 0x40, 0x00, 0x7e, 0x66, 0xf8, 0xf7, 0x16, 0xa0, 0x4a, 0x5b, 0x2a, + 0xe4, 0x84, 0xe1, 0x43, 0x21, 0x68, 0x55, 0xab, 0x49, 0x90, 0xff, 0x83, 0xe3, 0xc4, 0x79, 0xc2, + 0x7a, 0xe9, 0xd5, 0x09, 0xeb, 0x6d, 0x58, 0x7e, 0x56, 0xba, 0x79, 0x95, 0x37, 0x52, 0xaa, 0xc6, + 0x63, 0xc3, 0x36, 0x7f, 0x5e, 0xdc, 0xc0, 0x4a, 0xdb, 0x29, 0xbd, 0x67, 0xd3, 0x00, 0xf1, 0x36, + 0xe8, 0x93, 0x19, 0x36, 0x17, 0x44, 0x71, 0xf5, 0x50, 0x8b, 0x61, 0xdb, 0x54, 0xfe, 0x84, 0x71, + 0xf2, 0x69, 0x68, 0xae, 0xe3, 0xe1, 0x82, 0xb1, 0x66, 0x7a, 0x1a, 0x72, 0x09, 0xd3, 0x70, 0x02, + 0x2b, 0x73, 0x8e, 0x91, 0x89, 0x75, 0x68, 0x4f, 0xa5, 0xf5, 0xf8, 0x6c, 0x07, 0xb8, 0x45, 0x1e, + 0xef, 0x13, 0x58, 0x93, 0x81, 0x3f, 0xf6, 0x8f, 0x7c, 0xaa, 0x9a, 0x2d, 0x9d, 0x6c, 0x63, 0x5d, + 0xb3, 0x5a, 0xc2, 0xe6, 0x27, 0xdb, 0x6e, 0xfe, 0xeb, 0x0a, 0xd4, 0xf8, 0xf6, 0x65, 0xb1, 0x0c, + 0x9d, 0x27, 0xe1, 0x49, 0x18, 0x3d, 0x0f, 0x19, 0xd0, 0x7f, 0x43, 0xac, 0x40, 0xcf, 0xf0, 0x9b, + 0xbe, 0xe6, 0xb9, 0x5f, 0x11, 0x7d, 0x68, 0x13, 0xe3, 0x1b, 0xc8, 0x82, 0xb8, 0x0a, 0x03, 0xed, + 0x3b, 0xde, 0x43, 0x3b, 0x15, 0xa5, 0xfe, 0xe8, 0xcc, 0x60, 0x17, 0x45, 0x0f, 0x5a, 0x07, 0x69, + 0x14, 0x1f, 0xc8, 0xd0, 0xf3, 0xc3, 0x71, 0x7f, 0x49, 0x0c, 0x60, 0xd5, 0xf4, 0xca, 0x7c, 0xfd, + 0xc0, 0x0f, 0x7d, 0x75, 0xdc, 0xaf, 0x8a, 0x2b, 0x70, 0x71, 0x1e, 0x66, 0xdb, 0x3d, 0xe9, 0xd7, + 0xc4, 0x2a, 0xf4, 0x0d, 0xf2, 0xae, 0xbe, 0x6b, 0xb7, 0x5f, 0xbf, 0xf9, 0x09, 0x88, 0xf3, 0xd7, + 0x1c, 0xe3, 0x37, 0x1f, 0xca, 0xb1, 0xe3, 0x9e, 0xed, 0x04, 0x91, 0x42, 0xf1, 0xe8, 0x40, 0xb3, + 0xe8, 0xab, 0x72, 0xf3, 0x01, 0xd4, 0xf8, 0x5e, 0xea, 0xd2, 0x5f, 0x33, 0xa0, 0xff, 0x06, 0x36, + 0x46, 0x1b, 0xed, 0x87, 0xe3, 0x47, 0xf2, 0x34, 0x65, 0xcb, 0xf1, 0xd0, 0x51, 0x69, 0x7f, 0x41, + 0x74, 0x01, 0xf4, 0x8f, 0xdd, 0x0f, 0xbd, 0xfe, 0xe2, 0xdd, 0x9d, 0xbf, 0xfa, 0xe3, 0x5b, 0x95, + 0x3f, 0xfc, 0xf1, 0xad, 0xca, 0x7f, 0xfc, 0xe3, 0x5b, 0x6f, 0xfc, 0xfe, 0x4f, 0x6f, 0x55, 0xbe, + 0xff, 0xa8, 0x74, 0xeb, 0xb6, 0x36, 0xdd, 0x54, 0x0d, 0x76, 0x3b, 0xb7, 0xe3, 0xb7, 0xe3, 0x93, + 0xf1, 0xed, 0xf8, 0xe8, 0xb6, 0x51, 0x0c, 0x47, 0x35, 0xba, 0x4c, 0xfb, 0xe3, 0xff, 0x1d, 0x00, + 0x00, 0xff, 0xff, 0xb4, 0xc1, 0xbc, 0x3b, 0xcb, 0x5b, 0x00, 0x00, } func (m *Message) Marshal() (dAtA []byte, err error) { @@ -11912,6 +11934,18 @@ func (m *Instruction) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.MergeTopOrderedStreams { + i-- + if m.MergeTopOrderedStreams { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x3 + i-- + dAtA[i] = 0xf8 + } if m.TopOrderedOutput { i-- if m.TopOrderedOutput { @@ -13380,6 +13414,19 @@ func (m *Pipeline) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.OrderedStream) > 0 { + for iNdEx := len(m.OrderedStream) - 1; iNdEx >= 0; iNdEx-- { + i-- + if m.OrderedStream[iNdEx] { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + } + i = encodeVarintPipeline(dAtA, i, uint64(len(m.OrderedStream))) + i-- + dAtA[i] = 0x7a + } if len(m.UuidsToRegIdx) > 0 { for iNdEx := len(m.UuidsToRegIdx) - 1; iNdEx >= 0; iNdEx-- { { @@ -15997,6 +16044,9 @@ func (m *Instruction) ProtoSize() (n int) { if m.TopOrderedOutput { n += 3 } + if m.MergeTopOrderedStreams { + n += 3 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -16419,6 +16469,9 @@ func (m *Pipeline) ProtoSize() (n int) { n += 1 + l + sovPipeline(uint64(l)) } } + if len(m.OrderedStream) > 0 { + n += 1 + sovPipeline(uint64(len(m.OrderedStream))) + len(m.OrderedStream)*1 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -31638,6 +31691,26 @@ func (m *Instruction) Unmarshal(dAtA []byte) error { } } m.TopOrderedOutput = bool(v != 0) + case 63: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MergeTopOrderedStreams", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPipeline + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MergeTopOrderedStreams = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPipeline(dAtA[iNdEx:]) @@ -34731,6 +34804,76 @@ func (m *Pipeline) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 15: + if wireType == 0 { + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPipeline + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.OrderedStream = append(m.OrderedStream, bool(v != 0)) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPipeline + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthPipeline + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthPipeline + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + elementCount = packedLen + if elementCount != 0 && len(m.OrderedStream) == 0 { + m.OrderedStream = make([]bool, 0, elementCount) + } + for iNdEx < postIndex { + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPipeline + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.OrderedStream = append(m.OrderedStream, bool(v != 0)) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field OrderedStream", wireType) + } default: iNdEx = preIndex skippy, err := skipPipeline(dAtA[iNdEx:]) diff --git a/pkg/sql/compile/compile.go b/pkg/sql/compile/compile.go index 41c1bd70b2409..cd4f7176b66ba 100644 --- a/pkg/sql/compile/compile.go +++ b/pkg/sql/compile/compile.go @@ -8073,6 +8073,7 @@ func (c *Compile) newMergeScope(ss []*Scope) *Scope { // connector writes this edge, so every receiver has exactly one producer. func (c *Compile) newMergeTopScope(node *plan.Node, topN *plan.Expr, ss []*Scope) *Scope { rs := c.newEmptyMergeScope() + ss = c.groupOrderedTopRemoteRunDependenciesByCNIfNeeded(node, topN, ss, rs.NodeInfo) rs.PreScopes = ss rs.Proc = c.proc.NewNoContextChildProc(len(ss)) if len(ss) > 0 { @@ -8095,6 +8096,41 @@ func (c *Compile) newMergeTopScope(node *plan.Node, topN *plan.Expr, ss []*Scope return rs } +// newMergeTopScopeByCN keeps all same-CN receiver dependencies in one remote +// execution tree while preserving one ordered stream per child. A plain Merge +// cannot be used here because interleaving sorted child batches would invalidate +// the stream contract consumed by the coordinator MergeTop. +func (c *Compile) newMergeTopScopeByCN( + node *plan.Node, + topN *plan.Expr, + ss []*Scope, + nodeinfo engine.Node, +) *Scope { + rs := newScope(Remote) + rs.NodeInfo = scopeNodeWithMcpu(nodeinfo, 1) + rs.PreScopes = ss + rs.Proc = c.proc.NewNoContextChildProc(len(ss)) + if len(ss) > 0 { + rs.Proc.Base.LoadTag = ss[0].Proc.Base.LoadTag + } + + arg := constructMergeTop(node, topN).WithOrderedStreams() + c.hasMergeOp = true + arg.SetAnalyzeControl(c.anal.curNodeIdx, false) + rs.setRootOperator(arg) + + for i := range ss { + reg := rs.Proc.Reg.MergeReceivers[i] + reg.ResetForReuse(1, 1) + reg.OrderedStream = true + connArg := connector.NewArgument().WithReg(reg) + connArg.SetAnalyzeControl(c.anal.curNodeIdx, false) + ss[i].setRootOperator(connArg) + ss[i].IsEnd = true + } + return rs +} + // newScopeListOnSingleWorkerStage builds a single-worker stage. If query // placement already collapsed to one worker, inherit that worker; otherwise // keep the legacy current-CN coordinator for multi-CN stages. @@ -8324,18 +8360,55 @@ func (c *Compile) groupRemoteRunDependenciesByCNIfNeeded( ss []*Scope, mergeNode engine.Node, ) []*Scope { - stageNodes := shuffleBucketStageNodes(ss) - if len(ss) <= len(stageNodes) { + stageNodes, needed := remoteRunDependenciesNeedGroupingByCN(ss, mergeNode) + if !needed { return ss } + return c.mergeScopesByStageNodes(ss, stageNodes) +} +func remoteRunDependenciesNeedGroupingByCN( + ss []*Scope, + mergeNode engine.Node, +) (engine.Nodes, bool) { + stageNodes := shuffleBucketStageNodes(ss) + if len(ss) <= len(stageNodes) { + return stageNodes, false + } for _, scope := range ss { if !sameExecutionNode(scope.NodeInfo, mergeNode) && findPipelineExternalLocalReceiver(scope) != nil { - return c.mergeScopesByStageNodes(ss, stageNodes) + return stageNodes, true } } - return ss + return stageNodes, false +} + +func (c *Compile) groupOrderedTopRemoteRunDependenciesByCNIfNeeded( + node *plan.Node, + topN *plan.Expr, + ss []*Scope, + mergeNode engine.Node, +) []*Scope { + stageNodes, needed := remoteRunDependenciesNeedGroupingByCN(ss, mergeNode) + if !needed { + return ss + } + + rs := make([]*Scope, 0, len(stageNodes)) + for i := range stageNodes { + cn := stageNodes[i] + currentSS := make([]*Scope, 0, cn.Mcpu) + for j := range ss { + if sameExecutionNode(ss[j].NodeInfo, cn) { + currentSS = append(currentSS, ss[j]) + } + } + if len(currentSS) > 0 { + rs = append(rs, c.newMergeTopScopeByCN(node, topN, currentSS, cn)) + } + } + return rs } // shuffleBucketsNeedPerCNGrouping reports whether a dispatch in one top-level diff --git a/pkg/sql/compile/merge_scope_placement_test.go b/pkg/sql/compile/merge_scope_placement_test.go index 718ab0a557b84..11954a2b7fdcb 100644 --- a/pkg/sql/compile/merge_scope_placement_test.go +++ b/pkg/sql/compile/merge_scope_placement_test.go @@ -24,6 +24,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/connector" "github.com/matrixorigin/matrixone/pkg/sql/colexec/dispatch" "github.com/matrixorigin/matrixone/pkg/sql/colexec/merge" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergetop" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/vm" @@ -114,6 +115,92 @@ func TestNewMergeScopePreservesIndependentRemoteInputs(t *testing.T) { "independent remote pipelines should not pay for an extra per-CN merge") } +func TestNewMergeTopScopeGroupsRemoteCrossTreeDependenciesByCN(t *testing.T) { + nodes := engine.Nodes{ + {Id: "cn-local", Addr: "cn-local:6001", Mcpu: 2}, + {Id: "cn-remote", Addr: "cn-remote:6001", Mcpu: 2}, + } + + for _, operator := range []vm.OpType{vm.Dispatch, vm.Connector} { + t.Run(operator.String(), func(t *testing.T) { + c := newCompileForShuffleJoinTest(t, nodes) + enableDistributedOrderedTopForTest(t, c.proc) + owner := newRemoteMergeInputForTest(c, nodes[1], 1) + producer := newRemoteMergeInputForTest(c, nodes[1], 0) + dependency := &Scope{ + Magic: Remote, + NodeInfo: scopeNodeWithMcpu(nodes[1], 1), + Proc: c.proc.NewNoContextChildProc(0), + } + switch operator { + case vm.Dispatch: + op := dispatch.NewArgument() + op.LocalRegs = []*process.WaitRegister{owner.Proc.Reg.MergeReceivers[0]} + dependency.setRootOperator(op) + case vm.Connector: + dependency.setRootOperator(connector.NewArgument().WithReg(owner.Proc.Reg.MergeReceivers[0])) + } + producer.PreScopes = append(producer.PreScopes, dependency) + + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(20_000) + node := &plan.Node{ + Limit: limitExpr, + OrderBy: []*plan.OrderBySpec{{Expr: &plan.Expr{ + Expr: &plan.Expr_Col{Col: &plan.ColRef{ColPos: 0}}, + Typ: plan.Type{Id: int32(types.T_int64)}, + }}}, + } + result := c.compileTop(node, limitExpr, []*Scope{producer, owner}) + require.Len(t, result, 1) + require.Len(t, result[0].PreScopes, 1) + + cnGroup := result[0].PreScopes[0] + require.Len(t, cnGroup.PreScopes, 2) + cnGroup.Proc.Base.TxnOperator = fakeTxnOperator{} + require.True(t, checkPipelineStandaloneExecutableAtRemote(cnGroup)) + out, ok := cnGroup.RootOp.(*connector.Connector) + require.True(t, ok) + require.True(t, out.Reg.OrderedStream) + cnTop, ok := out.GetOperatorBase().GetChildren(0).(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, cnTop.OrderedStreams) + require.Len(t, cnGroup.Proc.Reg.MergeReceivers, 2) + for _, reg := range cnGroup.Proc.Reg.MergeReceivers { + require.True(t, reg.OrderedStream) + require.Equal(t, 1, reg.NilBatchCnt) + require.Equal(t, 1, cap(reg.Ch2)) + } + }) + } +} + +func TestNewMergeTopScopePreservesIndependentRemoteInputs(t *testing.T) { + nodes := engine.Nodes{ + {Id: "cn-local", Addr: "cn-local:6001", Mcpu: 2}, + {Id: "cn-remote", Addr: "cn-remote:6001", Mcpu: 2}, + } + c := newCompileForShuffleJoinTest(t, nodes) + enableDistributedOrderedTopForTest(t, c.proc) + inputs := []*Scope{ + newRemoteMergeInputForTest(c, nodes[1], 0), + newRemoteMergeInputForTest(c, nodes[1], 0), + } + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(20_000) + node := &plan.Node{ + Limit: limitExpr, + OrderBy: []*plan.OrderBySpec{{Expr: &plan.Expr{ + Expr: &plan.Expr_Col{Col: &plan.ColRef{ColPos: 0}}, + Typ: plan.Type{Id: int32(types.T_int64)}, + }}}, + } + + result := c.compileTop(node, limitExpr, inputs) + + require.Len(t, result, 1) + require.Len(t, result[0].PreScopes, 2, + "independent ordered remote pipelines should not pay for an extra per-CN gather") +} + func TestCompileWindowKeepsDistributedShuffleJoinTreesStandalone(t *testing.T) { const dop = int32(2) nodes := engine.Nodes{ diff --git a/pkg/sql/compile/merge_top_fallback_test.go b/pkg/sql/compile/merge_top_fallback_test.go index fda19d1fcdb73..6e6d78697f46a 100644 --- a/pkg/sql/compile/merge_top_fallback_test.go +++ b/pkg/sql/compile/merge_top_fallback_test.go @@ -239,12 +239,27 @@ func TestCompileTopFallsBackWhenOrderKeyIsNotMaterialized(t *testing.T) { func newMergeTopFallbackTestCompile(t *testing.T) *Compile { c := NewMockCompile(t) + enableDistributedOrderedTopForTest(t, c.proc) c.anal = &AnalyzeModule{curNodeIdx: 1, isFirst: true} c.execType = plan2.ExecTypeAP_ONECN c.isPrepare = true return c } +func enableDistributedOrderedTopForTest(t *testing.T, proc *process.Process) { + t.Helper() + rt := runtime.ServiceRuntime(proc.GetService()) + previous, hadPrevious := rt.GetGlobalVariables(runtime.MOProtocolVersion) + rt.SetGlobalVariables(runtime.MOProtocolVersion, defines.MORPCLatestVersion) + t.Cleanup(func() { + if hadPrevious { + rt.SetGlobalVariables(runtime.MOProtocolVersion, previous) + } else { + rt.CompareAndDeleteGlobalVariables(runtime.MOProtocolVersion, defines.MORPCLatestVersion) + } + }) +} + func newMergeTopFallbackTestNode(limitExpr *plan.Expr) *plan.Node { return &plan.Node{ Limit: limitExpr, diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index ebe7cd540cd25..1f7023de89d5f 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -120,6 +120,9 @@ func encodeRemoteScope(s *Scope, proc *process.Process) ([]byte, error) { if err = validateRemoteGroupingSetPipelineProtocol(proc, p); err != nil { return nil, err } + if err = validateRemoteDistributedOrderedTopPipelineProtocol(proc, p); err != nil { + return nil, err + } if err = validateRemoteODKUAffectedRowsPipelineProtocol(proc, p); err != nil { return nil, err } @@ -217,6 +220,9 @@ func decodeScope(data []byte, proc *process.Process, isRemote bool, eng engine.E if err = validateRemoteGroupingSetPipelineProtocol(proc, p); err != nil { return nil, err } + if err = validateRemoteDistributedOrderedTopPipelineProtocol(proc, p); err != nil { + return nil, err + } } else if err = plan.ValidateStringLiteralFormsInOwner(p); err != nil { return nil, err } @@ -337,8 +343,17 @@ func generatePipeline(s *Scope, ctx *scopeContext, ctxId int32) (*pipeline.Pipel for i := range s.Proc.Reg.MergeReceivers { p.ChannelBufferSize = append(p.ChannelBufferSize, int32(cap(s.Proc.Reg.MergeReceivers[i].Ch2))) p.NilBatchCnt = append(p.NilBatchCnt, int32(s.Proc.Reg.MergeReceivers[i].NilBatchCnt)) + if s.Proc.Reg.MergeReceivers[i].OrderedStream { + if p.OrderedStream == nil { + p.OrderedStream = make([]bool, len(s.Proc.Reg.MergeReceivers)) + } + p.OrderedStream[i] = true + } ctx.regs[s.Proc.Reg.MergeReceivers[i]] = int32(i) } + for len(p.OrderedStream) > 0 && !p.OrderedStream[len(p.OrderedStream)-1] { + p.OrderedStream = p.OrderedStream[:len(p.OrderedStream)-1] + } } // DataSource if s.DataSource != nil { // if select 1, DataSource is nil @@ -506,6 +521,11 @@ func generateScope(proc *process.Process, p *pipeline.Pipeline, ctx *scopeContex s.NodeInfo.Data = relData } s.Proc = proc.NewNoContextChildProcWithChannel(int(p.ChildrenCount), p.ChannelBufferSize, p.NilBatchCnt) + for i := range s.Proc.Reg.MergeReceivers { + if i < len(p.OrderedStream) { + s.Proc.Reg.MergeReceivers[i].OrderedStream = p.OrderedStream[i] + } + } ctx.scope = s { for i := range s.Proc.Reg.MergeReceivers { @@ -833,6 +853,7 @@ func convertToPipelineInstruction(op vm.Operator, proc *process.Process, ctx *sc case *mergetop.MergeTop: in.Limit = t.Limit in.OrderBy = t.Fs + in.MergeTopOrderedStreams = t.OrderedStreams case *mergeorder.MergeOrder: in.OrderBy = t.OrderBySpecs in.SpillMem = t.SpillThreshold @@ -1475,9 +1496,13 @@ func convertToVmOperator(opr *pipeline.Instruction, ctx *scopeContext, eng engin op = arg DecodeMergeGroup(op.(*group.MergeGroup), opr.Agg) case vm.MergeTop: - op = mergetop.NewArgument(). + arg := mergetop.NewArgument(). WithLimit(opr.Limit). WithFs(opr.OrderBy) + if opr.MergeTopOrderedStreams { + arg.WithOrderedStreams() + } + op = arg case vm.MergeOrder: arg := mergeorder.NewArgument() arg.OrderBySpecs = opr.OrderBy @@ -1990,6 +2015,40 @@ func validateRemoteMongoUserQueryPipelineProtocol( return nil } +func validateRemoteDistributedOrderedTopPipelineProtocol( + proc *process.Process, + p *pipeline.Pipeline, +) error { + if p == nil { + return nil + } + usesOrderedTop := false + for _, ordered := range p.OrderedStream { + if ordered { + usesOrderedTop = true + break + } + } + if !usesOrderedTop { + for _, instruction := range p.InstructionList { + if instruction.TopOrderedOutput || instruction.MergeTopOrderedStreams { + usesOrderedTop = true + break + } + } + } + if usesOrderedTop && (proc == nil || !supportsDistributedOrderedTop(proc.GetService())) { + return moerr.NewNotSupportedNoCtx( + "distributed ordered Top-N requires MORPC protocol version 53") + } + for _, child := range p.Children { + if err := validateRemoteDistributedOrderedTopPipelineProtocol(proc, child); err != nil { + return err + } + } + return nil +} + func validateRemoteRightDedupInputKeysUniquePipelineProtocol( proc *process.Process, p *pipeline.Pipeline, diff --git a/pkg/sql/compile/remoterun_test.go b/pkg/sql/compile/remoterun_test.go index 8fbc65ac690c9..80f1cdeaea1bb 100644 --- a/pkg/sql/compile/remoterun_test.go +++ b/pkg/sql/compile/remoterun_test.go @@ -550,6 +550,25 @@ func TestRemoteRunOperatorCodecRoundTrip(t *testing.T) { require.Equal(t, original.Fs, restoredTop.Fs) }) + t.Run("MergeTopOrderedStreams", func(t *testing.T) { + original := mergetop.NewArgument(). + WithLimit(plan.MakePlan2Uint64ConstExprWithType(17)). + WithFs([]*planpb.OrderBySpec{{ + Expr: &planpb.Expr{ + Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}, + Typ: planpb.Type{Id: int32(types.T_int64)}, + }, + }}). + WithOrderedStreams() + restored := roundTrip(t, original) + defer restored.Release() + restoredMergeTop, ok := restored.(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, restoredMergeTop.OrderedStreams) + require.Equal(t, original.Limit, restoredMergeTop.Limit) + require.Equal(t, original.Fs, restoredMergeTop.Fs) + }) + t.Run("GroupMetadata", func(t *testing.T) { original := group.NewArgument() original.GroupByHashKey = []int32{0, 2} @@ -637,6 +656,132 @@ func TestRemoteRunOperatorCodecRoundTrip(t *testing.T) { }) } +func TestRemoteRunOrderedPipelineEdgeRoundTrip(t *testing.T) { + proc := testutil.NewProcess(t) + rt := moruntime.ServiceRuntime(proc.GetService()) + oldVersion, hadVersion := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCLatestVersion) + t.Cleanup(func() { + if hadVersion { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, oldVersion) + } else { + rt.CompareAndDeleteGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCLatestVersion) + } + }) + scope := &Scope{ + Magic: Remote, + Proc: proc.NewNoContextChildProc(2), + RootOp: mergetop.NewArgument().WithOrderedStreams(), + } + scope.Proc.Reg.MergeReceivers[0].ResetForReuse(1, 1) + scope.Proc.Reg.MergeReceivers[0].OrderedStream = true + scope.Proc.Reg.MergeReceivers[1].ResetForReuse(3, 2) + + data, err := encodeRemoteScope(scope, proc) + require.NoError(t, err) + wire := new(pipeline.Pipeline) + require.NoError(t, wire.Unmarshal(data)) + require.Equal(t, []bool{true}, wire.OrderedStream, + "trailing unordered receivers should retain the legacy zero-value wire representation") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion52) + _, err = encodeRemoteScope(scope, proc) + require.ErrorContains(t, err, "requires MORPC protocol version 53") + _, err = decodeScope(data, proc, true, nil) + require.ErrorContains(t, err, "requires MORPC protocol version 53") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCLatestVersion) + restored, err := decodeScope(data, proc, true, nil) + require.NoError(t, err) + t.Cleanup(func() { + restored.release() + scope.release() + proc.Free() + }) + + require.Len(t, restored.Proc.Reg.MergeReceivers, 2) + require.True(t, restored.Proc.Reg.MergeReceivers[0].OrderedStream) + require.False(t, restored.Proc.Reg.MergeReceivers[1].OrderedStream) + require.Equal(t, 1, cap(restored.Proc.Reg.MergeReceivers[0].Ch2)) + require.Equal(t, 1, restored.Proc.Reg.MergeReceivers[0].NilBatchCnt) + require.Equal(t, 3, cap(restored.Proc.Reg.MergeReceivers[1].Ch2)) + require.Equal(t, 2, restored.Proc.Reg.MergeReceivers[1].NilBatchCnt) + restoredTop, ok := restored.RootOp.(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, restoredTop.OrderedStreams) +} + +func TestRemoteRunOrderedMergeTopHierarchyRoundTrip(t *testing.T) { + nodes := engine.Nodes{ + {Id: "cn-local", Addr: "cn-local:6001", Mcpu: 2}, + {Id: "cn-remote", Addr: "cn-remote:6001", Mcpu: 2}, + } + c := newCompileForShuffleJoinTest(t, nodes) + rt := moruntime.ServiceRuntime(c.proc.GetService()) + oldVersion, hadVersion := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCLatestVersion) + t.Cleanup(func() { + if hadVersion { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, oldVersion) + } else { + rt.CompareAndDeleteGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCLatestVersion) + } + }) + + limitExpr := plan.MakePlan2Uint64ConstExprWithType(20_000) + orderBy := []*planpb.OrderBySpec{{Expr: &planpb.Expr{ + Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}, + Typ: planpb.Type{Id: int32(types.T_int64)}, + }}} + node := &planpb.Node{Limit: limitExpr, OrderBy: orderBy} + inputs := []*Scope{ + newRemoteMergeInputForTest(c, nodes[1], 0), + newRemoteMergeInputForTest(c, nodes[1], 0), + } + inputs[0].NodeInfo.Mcpu = 2 + for _, input := range inputs { + input.setRootOperator(top.NewArgument(). + WithLimit(limitExpr). + WithFs(orderBy). + WithOrderedOutput()) + } + group := c.newMergeTopScopeByCN(node, limitExpr, inputs, nodes[1]) + + data, err := encodeRemoteScope(group, c.proc) + require.NoError(t, err) + restored, err := decodeScope(data, c.proc, true, nil) + require.NoError(t, err) + t.Cleanup(func() { + restored.release() + group.release() + c.proc.Free() + }) + + require.Len(t, restored.PreScopes, 2) + require.Len(t, restored.Proc.Reg.MergeReceivers, 2) + restoredTop, ok := restored.RootOp.(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, restoredTop.OrderedStreams) + for i, input := range restored.PreScopes { + out, ok := input.RootOp.(*connector.Connector) + require.True(t, ok) + require.Same(t, restored.Proc.Reg.MergeReceivers[i], out.Reg) + require.True(t, out.Reg.OrderedStream) + localTop, ok := out.GetOperatorBase().GetChildren(0).(*top.Top) + require.True(t, ok) + require.True(t, localTop.OrderedOutput) + } + + restored.PreScopes[0].Proc.Ctx = context.Background() + ordered, workers := newParallelScope(restored.PreScopes[0]) + require.Equal(t, Merge, ordered.Magic) + require.True(t, ordered.ConcurrentPreScopes) + require.Len(t, workers, 2) + orderedOut, ok := ordered.RootOp.(*connector.Connector) + require.True(t, ok) + gatherTop, ok := orderedOut.GetOperatorBase().GetChildren(0).(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, gatherTop.OrderedStreams) +} + func TestTargetAwareUpdateRemoteProtocolValidation(t *testing.T) { ctx := &scopeContext{id: 1, root: &scopeContext{}, parent: &scopeContext{}} proc := testutil.NewProcess(t) diff --git a/proto/pipeline.proto b/proto/pipeline.proto index 4b0665be92173..5d7088f4eae44 100644 --- a/proto/pipeline.proto +++ b/proto/pipeline.proto @@ -647,6 +647,9 @@ message Instruction { // TOP only: every runtime worker must be consolidated into one stream that // remains ordered across batch boundaries before leaving its CN. bool top_ordered_output = 62; + // MERGE_TOP only: consume one independently ordered stream from every + // receiver. This is serialized for per-CN ordered gathers sent by RemoteRun. + bool merge_top_ordered_streams = 63; } message AnalysisList { @@ -793,6 +796,9 @@ message Pipeline { repeated int32 nil_batch_cnt = 13; repeated UuidToRegIdx uuids_to_reg_idx = 14; + // Per receiver, preserve the single-producer ordered-stream contract across + // RemoteRun. Empty means the legacy unordered default. + repeated bool ordered_stream = 15; } message WrapNode { From 76670d12eb71fe010c426908a5b82ab47a65b6eb Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 03:19:02 +0800 Subject: [PATCH 3/7] fix(top): bound spill output by payload bytes --- docs/design/bounded_distributed_topn.md | 49 ++++++---- .../colexec/top/allocation_account_test.go | 7 +- pkg/sql/colexec/top/top.go | 89 +++++++++++++++++-- pkg/sql/colexec/top/top_test.go | 73 ++++++++++++++- pkg/sql/colexec/top/types.go | 10 ++- 5 files changed, 193 insertions(+), 35 deletions(-) diff --git a/docs/design/bounded_distributed_topn.md b/docs/design/bounded_distributed_topn.md index 31beda25e505a..8420e2746be3b 100644 --- a/docs/design/bounded_distributed_topn.md +++ b/docs/design/bounded_distributed_topn.md @@ -74,10 +74,12 @@ This supports these invariants: 1. Ordinary Top-K returns exactly min(K, S) rows in the existing SQL order. 2. Global merging does not retain K payload rows or consume all P*K candidates before it can return output. -3. Memory is bounded in physical bytes, including transport and allocation - overlap. Large result cardinality alone never requires one large allocation. -4. Spill remains an executable path when the resident selection state does not - fit. Memory, disk, FD, metadata, and merge depth have separate bounds. +3. Transport, reconstructed payload, and ordered-gather output are bounded in + physical bytes, including allocation overlap. Large result cardinality alone + never requires one large payload allocation. +4. Local Top spills source payload, but v1 still retains O(K) row references + and ordering keys per producer. Those allocations remain query-accounted; + a fully external key-selection state is a separate follow-up boundary. 5. Success, rejection, error, cancellation, and reuse have one cleanup owner. 6. Early stop applies only to the exclusively owned pure read subtree. Shared producers, found-rows consumers, and required effects retain their semantics. @@ -167,10 +169,21 @@ Implementation v1 uses the following deliberately narrow activation contract: publish prefix completion and stop further requests. Already admitted prefetch is finite and included in the accounting and cost model. -### C. Complete the local Top resource contract +### C. Local Top resource boundary -The global change removes the reported P*K materialization. Local Top must -also have a bounded response for wide keys and repeated candidate replacement. +The global change removes the reported P*K payload materialization. This PR +also makes spill reconstruction row-and-byte bounded: each selected row records +its actual output width while the source batch is available, and evaluation +uses that metadata to reconstruct at most 8,192 rows / 64 MiB per batch. A +single individually valid row may exceed the normal batch target to guarantee +progress. This closes the single-vector failure for a narrow ordering key with +wide projected payload, including the #27968 shape. + +The remaining local selection state is not independent of K. Spill mode keeps +O(K) row references and materialized ordering keys per producer. All of that +state is allocation-accounted and fails with a controlled resource error, but +v1 does not claim that an arbitrarily wide ordering key succeeds merely because +disk is available. A future fully external key-selection implementation must: - Keep a resident heap fast path for fitting selection state. SQL row counts and estimated widths can guide policy, but exact allocation admission owns @@ -194,13 +207,12 @@ also have a bounded response for wide keys and repeated candidate replacement. - Disk admission covers live input runs plus the new output run until commit. FD admission covers active readers and writer, not total run count. Exhausted disk, FDs, depth, or the minimal working set returns the appropriate error. -- Output an ordered stream in chunks from either local mode. This permits - wide payloads and wide keys without a single K-row payload/key vector. +- Output an ordered stream in chunks without a single K-row payload vector. -Local external selection can still write substantial input data and require -multiple passes. This proposal does not promise O(K) total spill or avoid the -full scan of an unordered source. Further payload read-locality optimization -requires separate measured evidence and is not a claimed benefit here. +The current source-payload spill can still write substantial input data and +requires a full scan of an unordered source. A future external key selector can +require multiple merge passes; neither O(K) total spill nor payload read-locality +improvements are claimed here. ## Ownership, errors, and generations @@ -302,7 +314,7 @@ storage reads, and INSERT. No speedup multiplier is promised before measurement. | Raise threshold / trust row-width statistics | Reject as safety design: physical capacity and stale/unknown statistics differ | | Global spill Top on unordered candidates | Possible compatible algorithm, but existing implementation writes all candidates and can repeat local payload I/O | | Give existing MergeOrder a terminal LIMIT only | Insufficient: still receives/materializes every candidate before first output | -| Ordered gather plus bounded local selection | Selected: uses order already established by producers, bounds global state, supports external local execution | +| Ordered gather plus byte-bounded payload reconstruction | Selected: uses order already established by producers, bounds global state and output batches while retaining accounted O(K) local keys | ## Validation and delivery sequence @@ -328,9 +340,9 @@ service configuration and data for fixed/main comparisons: receiver and runtime-DOP counterexamples, before large benchmarks. 2. Implement ordered fan-in, byte-bounded output, and teardown as one closure. Include encode/decode/version/clone tests and public multi-CN execution. -3. Close local variable-length reclamation and resident-to-external transition - with the common spill primitives. This is part of the full resource claim, - not optional if those counterexamples fail. Split commits by owner closure. +3. Follow up with variable-length key reclamation and a resident-to-external + key-selection transition if workloads require K-independent local key state; + do not attribute that unimplemented guarantee to this PR. 4. Run the combined implementation on 55 and review the complete change map. Functional partial delivery cannot be described as full #28285/#27968 closure. @@ -341,7 +353,8 @@ service configuration and data for fixed/main comparisons: | K=0/1, 16383/16384/16385, K>=S, parameter K, OFFSET overflow | Exact result and cardinality; reuse behaves like a fresh query | | ASC/DESC, compound keys, NULLs, duplicates, NaN, expressions | Existing comparator semantics; full sort/reference with unique ties where required | | N fixed, replacement count grows, increasing/decreasing payload lengths | Accounted physical peak remains within byte budget; same correct survivors | -| VECF32(1024) payload; large variable-length sort keys | Success with enough total resources despite a reduced per-allocation cap | +| VECF32(1024) payload with narrow key | Byte-bounded multi-batch output succeeds despite a reduced per-allocation cap | +| Large variable-length sort keys | Accounted success or controlled resource error; external key selection is outside v1 | | Pressure before/after candidate mutation and run publication | No lost/duplicate row; exact cleanup; external result equals resident reference | | Disk/FD failure, partial/truncated spill, allocation rejection | Correct error class; zero terminal ownership; healthy following query | | Full queue/held ACK, cancel, disconnect, stop racing real error | All owners quiesce; actual error is not masked; no producer drains unused output | diff --git a/pkg/sql/colexec/top/allocation_account_test.go b/pkg/sql/colexec/top/allocation_account_test.go index 9d68af24f7e60..ae5fe45a4dd09 100644 --- a/pkg/sql/colexec/top/allocation_account_test.go +++ b/pkg/sql/colexec/top/allocation_account_test.go @@ -439,9 +439,10 @@ func TestAccountedTopCorruptSpillFailsClosed(t *testing.T) { require.NoError(t, err) op.ctr.sels[0] = 0 op.ctr.rowRefs[0] = rowRef{ - offset: record.offset, - size: record.size - 1, - rowIdx: 0, + offset: record.offset, + size: record.size - 1, + rowIdx: 0, + outputBytes: uint64(types.T_int64.ToType().TypeSize()), } op.ctr.spillOrdered = true var result vm.CallResult diff --git a/pkg/sql/colexec/top/top.go b/pkg/sql/colexec/top/top.go index feba897340a75..ef8572f4246ef 100644 --- a/pkg/sql/colexec/top/top.go +++ b/pkg/sql/colexec/top/top.go @@ -590,12 +590,17 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr } } for i := range processCount { + outputBytes, err := spillOutputRowBytes(bat, ctr.n, i) + if err != nil { + return err + } position := baseSel + i ctr.sels[position] = int64(position) ctr.rowRefs[position] = rowRef{ - offset: record.offset, - size: record.size, - rowIdx: int64(i), + offset: record.offset, + size: record.size, + rowIdx: int64(i), + outputBytes: outputBytes, } } ctr.bat.AddRowCount(processCount) @@ -616,15 +621,20 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr for i, j := processCount, rowCount; i < j; i++ { rowIdx := int64(i) if ctr.compare(1, 0, rowIdx, ctr.sels[0]) < 0 { + outputBytes, err := spillOutputRowBytes(bat, ctr.n, i) + if err != nil { + return err + } for idx := range ctr.cmps { if err := ctr.cmps[idx].Copy(1, 0, rowIdx, ctr.sels[0], proc); err != nil { return err } } ctr.rowRefs[ctr.sels[0]] = rowRef{ - offset: record.offset, - size: record.size, - rowIdx: int64(i), + offset: record.offset, + size: record.size, + rowIdx: int64(i), + outputBytes: outputBytes, } heap.Fix(ctr, 0) } @@ -632,6 +642,29 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr return nil } +func spillOutputRowBytes(bat *batch.Batch, columnCount, row int) (uint64, error) { + if bat == nil || columnCount < 0 || columnCount > len(bat.Vecs) || + row < 0 || row >= bat.RowCount() { + return 0, moerr.NewInternalErrorNoCtx("invalid top spill output row") + } + var total uint64 + for col := 0; col < columnCount; col++ { + vec := bat.Vecs[col] + if vec == nil || vec.GetType() == nil { + return 0, moerr.NewInternalErrorNoCtx("invalid top spill output vector") + } + rowBytes := uint64(vec.GetType().TypeSize()) + if vec.GetType().IsVarlen() && !vec.IsNull(uint64(row)) { + rowBytes += uint64(len(vec.GetBytesAt(row))) + } + if rowBytes > math.MaxUint64-total { + return 0, moerr.NewInvalidInputNoCtx("top spill output row size overflows") + } + total += rowBytes + } + return total, nil +} + func rowsToFill(limit uint64, currentRows int, batchRows int) int { if uint64(currentRows) >= limit { return 0 @@ -675,7 +708,44 @@ func (ctr *container) evalInMemory(limit uint64, n int, proc *process.Process, r return nil } -const evalSpillChunkSize = 8192 +const ( + evalSpillChunkSize = 8192 + evalSpillChunkBytes = 64 * mpool.MB +) + +func (ctr *container) nextSpillOutputChunkEnd(start int) (int, error) { + if start < 0 || start >= len(ctr.sels) { + return start, moerr.NewInternalErrorNoCtx("invalid top spill output cursor") + } + byteLimit := uint64(evalSpillChunkBytes) + if ctr.evalSpillOutputBytes != 0 { + byteLimit = ctr.evalSpillOutputBytes + } + endLimit := min(start+evalSpillChunkSize, len(ctr.sels)) + end := start + var outputBytes uint64 + for end < endLimit { + selection := ctr.sels[end] + if selection < 0 || selection >= int64(len(ctr.rowRefs)) { + return start, moerr.NewInternalErrorNoCtx("invalid top spill row reference") + } + rowBytes := ctr.rowRefs[selection].outputBytes + if rowBytes > math.MaxUint64-outputBytes { + return start, moerr.NewInvalidInputNoCtx("top spill output batch size overflows") + } + // One individually valid row must make progress even when it is larger + // than the normal batch budget. Subsequent rows wait for the next call. + if end > start && outputBytes+rowBytes > byteLimit { + break + } + outputBytes += rowBytes + end++ + if outputBytes >= byteLimit { + break + } + } + return end, nil +} func (ctr *container) evalSpill(limit uint64, n int, proc *process.Process, result *vm.CallResult) (bool, error) { if err, canceled := vm.CancelCheck(proc); canceled { @@ -726,7 +796,10 @@ func (ctr *container) evalSpill(limit uint64, n int, proc *process.Process, resu } chunkStart := ctr.evalCursor - chunkEnd := min(chunkStart+evalSpillChunkSize, len(ctr.sels)) + chunkEnd, err := ctr.nextSpillOutputChunkEnd(chunkStart) + if err != nil { + return false, err + } chunkSize := chunkEnd - chunkStart type batchRow struct { diff --git a/pkg/sql/colexec/top/top_test.go b/pkg/sql/colexec/top/top_test.go index da8a87ea2898a..9c4e2c57de89a 100644 --- a/pkg/sql/colexec/top/top_test.go +++ b/pkg/sql/colexec/top/top_test.go @@ -305,6 +305,72 @@ func TestTopSpill(t *testing.T) { } } +func TestTopSpillOutputUsesRowAndByteBounds(t *testing.T) { + const ( + payloadBytes = 200 + batchRows = 128 + outputBytes = 8 * 1024 + ) + limit := int(topSpillThreshold + 1) + inputRows := limit + 257 + tc := newTestCase( + t, + mpool.MustNewZero(), + []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, + int64(limit), + []*plan.OrderBySpec{{Expr: newExpression(0)}}, + ) + require.NoError(t, tc.arg.Prepare(tc.proc)) + require.True(t, tc.arg.ctr.spilling) + tc.arg.ctr.evalSpillOutputBytes = outputBytes + + input := make([]*batch.Batch, 0, (inputRows+batchRows-1)/batchRows+1) + for highest := inputRows; highest > 0; { + rows := min(batchRows, highest) + bat := batch.NewWithSize(2) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + bat.Vecs[1] = vector.NewVec(types.T_varchar.ToType()) + for i := range rows { + key := int64(highest - i) + require.NoError(t, vector.AppendFixed(bat.Vecs[0], key, false, tc.proc.Mp())) + payload := bytes.Repeat([]byte{byte('a' + key%26)}, payloadBytes+int(key%7)) + require.NoError(t, vector.AppendBytes(bat.Vecs[1], payload, false, tc.proc.Mp())) + } + bat.SetRowCount(rows) + input = append(input, bat) + highest -= rows + } + input = append(input, batch.EmptyBatch) + resetChildren(tc.arg, input) + + got := make([]int64, 0, limit) + outputBatches := 0 + for { + result, err := vm.Exec(tc.arg, tc.proc) + require.NoError(t, err) + if result.Batch == nil || result.Status == vm.ExecStop { + break + } + outputBatches++ + require.LessOrEqual(t, uint64(result.Batch.Size()), uint64(outputBytes)) + keys := vector.MustFixedColWithTypeCheck[int64](result.Batch.Vecs[0]) + got = append(got, keys...) + for row := range result.Batch.RowCount() { + require.GreaterOrEqual(t, len(result.Batch.Vecs[1].GetBytesAt(row)), payloadBytes) + } + } + require.Greater(t, outputBatches, 1) + require.Len(t, got, limit) + for i, key := range got { + require.Equal(t, int64(i+1), key) + } + + tc.arg.Free(tc.proc, false, nil) + tc.arg.GetChildren(0).Free(tc.proc, false, nil) + tc.proc.Free() + require.Zero(t, tc.proc.Mp().CurrNB()) +} + func TestTopSpillPrepareParamMetadata(t *testing.T) { mp := mpool.MustNewZero() proc := testutil.NewProcessWithMPool(t, "", mp) @@ -523,9 +589,10 @@ func TestTopSpillEvalCancellationCheckpoints(t *testing.T) { require.NoError(t, err) arg.ctr.sels = []int64{0} arg.ctr.rowRefs = []rowRef{{ - offset: record.offset, - size: record.size, - rowIdx: 0, + offset: record.offset, + size: record.size, + rowIdx: 0, + outputBytes: uint64(types.T_int64.ToType().TypeSize()), }} arg.ctr.spillOrdered = true src.Clean(proc.Mp()) diff --git a/pkg/sql/colexec/top/types.go b/pkg/sql/colexec/top/types.go index 0e7324a2fb964..d64beb7987798 100644 --- a/pkg/sql/colexec/top/types.go +++ b/pkg/sql/colexec/top/types.go @@ -42,9 +42,10 @@ var _ interface { const topSpillThreshold uint64 = 8192 * 2 type rowRef struct { - offset int64 - size int64 - rowIdx int64 + offset int64 + size int64 + rowIdx int64 + outputBytes uint64 } type spillRecordRef struct { @@ -93,6 +94,9 @@ type container struct { spillOrdered bool // sels backing contains the final ascending order evalCursor int // next row index to output in sels spillOutBat *batch.Batch // current chunk output batch, freed on next call + // evalSpillOutputBytes overrides the production byte ceiling in focused + // tests. Zero selects evalSpillChunkBytes. + evalSpillOutputBytes uint64 } type Top struct { From f54060825639a67fc5bea349757472d08933573e Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 08:18:11 +0800 Subject: [PATCH 4/7] fix(top): enforce payload bounds independently of estimates --- docs/design/bounded_distributed_topn.md | 94 +++++++++++++-- pkg/sql/colexec/mergetop/stream.go | 24 +++- pkg/sql/colexec/mergetop/top_test.go | 111 ++++++++++++++++++ .../colexec/top/allocation_account_test.go | 42 +++++-- pkg/sql/colexec/top/top.go | 36 +++++- pkg/sql/colexec/top/top_test.go | 79 ++++++++++++- pkg/sql/compile/compile.go | 98 ++++++++++++---- pkg/sql/compile/merge_top_fallback_test.go | 94 ++++++++++++++- pkg/sql/compile/scope_test.go | 103 ++++++++++------ pkg/tests/dml/dml_test.go | 33 ++++++ .../distributed/cases/dml/select/limit.result | 21 +++- test/distributed/cases/dml/select/limit.sql | 11 +- 12 files changed, 647 insertions(+), 99 deletions(-) diff --git a/docs/design/bounded_distributed_topn.md b/docs/design/bounded_distributed_topn.md index 8420e2746be3b..58bce8cd6e0e2 100644 --- a/docs/design/bounded_distributed_topn.md +++ b/docs/design/bounded_distributed_topn.md @@ -1,6 +1,8 @@ # Bounded distributed ORDER BY / LIMIT -Status: implemented and validated on 2026-09-07; ready for review. +Status: local correctness fixes validated on 2026-09-07; design approval and +rollout performance/compatibility acceptance remain pending. Historical measurements below are not +acceptance evidence for the revised worktree. Owner: issue #28285; regression constraint: #27968 must remain executable. Source baseline: `6e5f82f568b1ec3e013e8d4ab9031b2360300b84`. Implementation branch: `xp/fix-28285-bounded-merge-top`. @@ -74,9 +76,12 @@ This supports these invariants: 1. Ordinary Top-K returns exactly min(K, S) rows in the existing SQL order. 2. Global merging does not retain K payload rows or consume all P*K candidates before it can return output. -3. Transport, reconstructed payload, and ordered-gather output are bounded in - physical bytes, including allocation overlap. Large result cardinality alone - never requires one large payload allocation. +3. Reconstructed payload and ordered-gather output have a 64 MiB logical payload + window and an 8,192-row window, reduced further for a smaller allocator cap. + Vector capacity rounding, sidecars, input windows, and growth overlap are + charged by the existing allocation accounts, not by `Batch.Size()`. The + 64 MiB window is not an exact physical peak/RSS guarantee. Large result + cardinality alone never requires one large payload allocation. 4. Local Top spills source payload, but v1 still retains O(K) row references and ordering keys per producer. Those allocations remain query-accounted; a fully external key-selection state is a separate follow-up boundary. @@ -115,13 +120,26 @@ Implementation v1 uses the following deliberately narrow activation contract: - every runtime DOP worker gets its own one-sender edge, a CN-local gather reduces those streams to one ordered CN stream, and the coordinator repeats the same bounded merge; -- a static plan uses the hierarchy only when the estimated candidate set +- for large static limits, a plan uses the hierarchy when the estimated candidate set `min(input rows, K * runtime fanout) * row size` exceeds 512 MiB. This is four MergeOrder spill windows: below it, the existing vectorized path avoids the extra hierarchy. Runtime parameters use the full estimated input as their - candidate upper bound; missing/invalid estimates choose the bounded path; + candidate upper bound; missing/invalid estimates choose the bounded path. + Small static limits additionally require a type-based resident payload proof: + all projected/order values are fixed width, with K times their widths fitting + a 16 MiB allowance (including conservative bitmap space). Runtime limits and + unbounded/unknown payload types choose the hierarchy independently of estimates. + When the protocol/order-expression gate forbids hierarchy, these unsafe resident + plans use Top plus MergeOrder. Every updated local Top also checks its actual + first input schema before retaining any payload. Varlen payload uses external + storage because replacement history is not bounded by the number of survivors; +- once the hierarchy is selected, every local Top uses external payload storage + and byte-bounded ordered output even when K is at or below 16,384. This keeps + wide rows from being reconstructed into one resident result vector; - output is bounded by both 8,192 rows and 64 MiB (except that one individually - valid row must be allowed to make progress). Fixed and variable-width winner + valid row must be allowed to make progress). The logical window is additionally + capped at one quarter of the allocator's single-allocation ceiling, reserving + slack for vector growth. Fixed and variable-width winner runs are copied in bounded chunks using actual varlen payload sizes; - cleanup shares one 30-second deadline across every receiver. The first implementation drains already-produced local Top output rather than @@ -267,10 +285,21 @@ spill codec. No table/catalog or persistent storage migration is proposed. Spill is attempt-local and not resumable after restart. Rollback uses the compatible planner path for new attempts after active generations quiesce. -Diagnostics expose bounded per-operator counters: consumed/emitted rows, -stream count, physical peak bytes, spill read/write bytes, merge passes, and -prefix-stop reason. Do not add per-row logging, source-row labels, or a second -estimated memory ledger. All resources remain charged to the owning tenant. +Existing analyzer counters expose input/output rows and Top spill rows/bytes; +allocation accounts own actual allocation admission and peak accounting. Cleanup +timeout diagnostics include receiver/channel state. Dedicated stream-count, +spill-read, and prefix-stop metrics are not implemented in this revision; neither +external key merge passes nor producer early-stop is implemented. Do not infer +these metrics from `Batch.Size()`, or add a second estimated memory ledger. +All resources remain charged to the owning tenant. + +The type-based guard intentionally retains the small fixed-width fast path. +Small varlen Top-N now incurs local payload spill even when the actual values are +short. A runtime resident-to-external migration can recover that optimization in +a follow-up only after publication, comparator reuse, and partial-failure +ownership are proved. Updating a cluster cannot retrofit this runtime guard onto +old CN binaries: mixed-version fallback preserves protocol compatibility, while +the full payload safety guarantee requires all executors to carry this fix. ## Cost model and alternatives @@ -318,8 +347,9 @@ storage reads, and INSERT. No speedup multiplier is promised before measurement. ## Validation and delivery sequence -Implementation acceptance completed on 55 (`10.222.1.55`) with the same -service configuration and data for fixed/main comparisons: +Historical author measurements on 55 (`10.222.1.55`) used the same service +configuration and data for fixed/main comparisons. They predate the type-based +payload admission change and are not performance acceptance for that change: - 1M input / K=500K stayed on the compatible path and completed in 1.286s, matching the main-path envelope; forcing the hierarchy here was rejected @@ -336,6 +366,44 @@ service configuration and data for fixed/main comparisons: static analysis reports zero issues. The five failures in the full compile package are identical Parquet fanout failures on the clean base commit. +### Revised-worktree validation (2026-09-07) + +Base: `f14eb824df4c74fb341ebecd46d2da3358503a95`; rebased PR commit: +`76670d12eb71fe010c426908a5b82ab47a65b6eb`, plus the local fixes. Unlike the +historical run above, the current complete compile package passes. + +- Complete Top, MergeTop and compile packages pass in normal mode. Top and + MergeTop also pass under the race detector. Changed packages and the DML + consumer pass `go vet`; the final service builds successfully. +- A 1 MiB allocator ceiling test executes K=8192 with varlen payload and no + ordered-output hint. Independent exact survivor/order and multi-batch checks + pass. MergeTop tests exercise interleaved varlen winners and an indivisible + row exceeding the injected logical output window. +- Fixed-width allocation rejection exposed an 8192-byte selection leak: failed + slice growth returned nil over the live owner. The Top wrapper now preserves + the original slice on failure. The regression asserts error classification + and zero account/pool ownership after cleanup. Small-K runtime spill disk + rejection also asserts the disk resource error and zero disk/FD/memory usage. +- The existing forced multi-CN DML fixture now includes five-row varlen Top-N, + a real remote physical plan, exact global OFFSET results and prepared reuse. + The entire fixture passed twice in one process on 55 (20.60s including cluster + startup, then 3.38s; the added subtest took 0.09s and 0.01s). Test executable + SHA256: `0abd0ab7a055a5d81334d3ec2ae40701066949877d7c83581d30ade36a01db0f`. +- LIMIT BVT extends its existing data with small-K varlen and prepared queries; + it adds no rows. Normal comparison passed 34/34 statements twice on the same + two-CN instance, and the test table count was zero after teardown. + Final service SHA256: + `455a8209b59ec9619860fb4e7c31b3139ff76e49048615b50e2a132121e7deb7`. +- Test startup incident: restarting the launch fixture with its existing data + failed CN admission before any SQL. Original data and logs were retained; + a clean test-owned data directory reached SQL and ISCP readiness. This is not + evidence of restart acceptance or a Top-N execution failure. + +The revised small-varlen spill cost and original large-scale performance matrix +have not been remeasured. Final design approval, mixed-version execution and +restart acceptance remain separate rollout requirements; no approval is implied +by this local validation record. + 1. Prove typed topology and a deterministic minimal gather, including shared receiver and runtime-DOP counterexamples, before large benchmarks. 2. Implement ordered fan-in, byte-bounded output, and teardown as one closure. diff --git a/pkg/sql/colexec/mergetop/stream.go b/pkg/sql/colexec/mergetop/stream.go index 14e1c6bce56f2..b44ef80f7302c 100644 --- a/pkg/sql/colexec/mergetop/stream.go +++ b/pkg/sql/colexec/mergetop/stream.go @@ -55,6 +55,18 @@ type streamContainer struct { output *batch.Batch primed bool done bool + // A per-instance seam for byte-boundary tests; zero uses the normal window. + outputByteLimit int +} + +func (ctr *streamContainer) outputBytesLimit() int { + limit := mergeTopStreamBatchBytes + if ctr.outputByteLimit > 0 { + limit = min(limit, ctr.outputByteLimit) + } + // Payload chunks must remain feasible with a reduced allocator ceiling. + // Reserve slack for vector growth, headers and simultaneous old/new buffers. + return min(limit, int(mpool.MaxAllocationSize()/4)) } type streamHeap struct { @@ -138,8 +150,8 @@ func (mergeTop *MergeTop) prepareStream(proc *process.Process) (err error) { ctr.streams = make([]orderedStream, len(proc.Reg.MergeReceivers)) for i, reg := range proc.Reg.MergeReceivers { - ctr.streams[i].receiver = process.InitPipelineSignalReceiver( - proc.Ctx, []*process.WaitRegister{reg}) + ctr.streams[i].receiver = process.InitPipelineSignalReceiverFromProcess( + proc, []*process.WaitRegister{reg}) } return nil } @@ -194,7 +206,7 @@ func (mergeTop *MergeTop) callStream( for uint64(rows) < maxRows && ctr.heap.Len() > 0 { winner := ctr.heap.items[0] stream := &ctr.streams[winner] - if rows > 0 && ctr.output.Size()+stream.rowBytes() > mergeTopStreamBatchBytes { + if rows > 0 && ctr.output.Size()+stream.rowBytes() > ctr.outputBytesLimit() { break } chunk := ctr.winnerChunk(winner, int(maxRows)-rows) @@ -219,7 +231,7 @@ func (mergeTop *MergeTop) callStream( } else { heap.Fix(&ctr.heap, 0) } - if ctr.output.Size() >= mergeTopStreamBatchBytes { + if ctr.output.Size() >= ctr.outputBytesLimit() { break } } @@ -280,7 +292,7 @@ func (ctr *streamContainer) winnerChunk(winner, maxRows int) int { if rowBytes <= 0 { return 1 } - budgetRows := (mergeTopStreamBatchBytes - ctr.output.Size()) / rowBytes + budgetRows := (ctr.outputBytesLimit() - ctr.output.Size()) / rowBytes if budgetRows < 1 { return 1 } @@ -288,7 +300,7 @@ func (ctr *streamContainer) winnerChunk(winner, maxRows int) int { maxRows = budgetRows } } else { - budget := mergeTopStreamBatchBytes - ctr.output.Size() + budget := ctr.outputBytesLimit() - ctr.output.Size() used := 0 budgetRows := 0 for budgetRows < maxRows { diff --git a/pkg/sql/colexec/mergetop/top_test.go b/pkg/sql/colexec/mergetop/top_test.go index 9e914fff5e6a4..a7ba97c55cfc8 100644 --- a/pkg/sql/colexec/mergetop/top_test.go +++ b/pkg/sql/colexec/mergetop/top_test.go @@ -17,11 +17,14 @@ package mergetop import ( "bytes" "context" + "fmt" "math" "testing" + "time" "github.com/stretchr/testify/require" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/batch" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -276,6 +279,54 @@ func TestMergeTopOrderedStreamsVarlenNullsFirst(t *testing.T) { require.Zero(t, proc.Mp().CurrNB()) } +func TestMergeTopOrderedStreamsVarlenByteBoundary(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + proc.Reg.MergeReceivers = []*process.WaitRegister{ + process.NewPipelineEdge(2, 1), process.NewPipelineEdge(2, 1), + } + const byteLimit = 1024 + expected := make([]string, 20) + for i := range expected { + expected[i] = fmt.Sprintf("%04d%s", i, bytes.Repeat([]byte("x"), 130+i)) + } + // An indivisible valid row may exceed the normal output window. + expected[19] += string(bytes.Repeat([]byte("y"), 2*byteLimit)) + for parity := range 2 { + var values []string + for i := parity; i < len(expected); i += 2 { + values = append(values, expected[i]) + } + sendStringStream(t, proc, proc.Reg.MergeReceivers[parity], values, make([]bool, len(values))) + } + arg := NewArgument().WithLimit(plan2.MakePlan2Uint64ConstExprWithType(uint64(len(expected)))). + WithFs([]*plan.OrderBySpec{{Expr: newStringExpression(0)}}).WithOrderedStreams() + require.NoError(t, arg.Prepare(proc)) + arg.ctr.stream.outputByteLimit = byteLimit + var got []string + batches := 0 + for { + result, err := arg.Call(proc) + require.NoError(t, err) + if result.Batch == nil { + break + } + batches++ + if result.Batch.Size() > byteLimit { + require.Equal(t, 1, result.Batch.RowCount()) + } + for row := range result.Batch.RowCount() { + got = append(got, string(result.Batch.Vecs[0].GetBytesAt(row))) + } + } + require.Greater(t, batches, 2) + require.Equal(t, expected, got) + arg.Reset(proc, false, nil) + arg.Free(proc, false, nil) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + func TestMergeTopOrderedStreamsPropagatesTerminalError(t *testing.T) { proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) proc.Reg.MergeReceivers = []*process.WaitRegister{ @@ -299,6 +350,66 @@ func TestMergeTopOrderedStreamsPropagatesTerminalError(t *testing.T) { require.Zero(t, proc.Mp().CurrNB()) } +func TestMergeTopOrderedStreamsPreservesQueryTerminalOverLateEdgeFailure(t *testing.T) { + tests := []struct { + name string + buildContext func(*process.Process) (context.Context, func()) + wantErr error + }{ + { + name: "query cancellation", + buildContext: func(proc *process.Process) (context.Context, func()) { + queryCtx := proc.Base.GetContextBase().BuildQueryCtx(proc.GetTopContext()) + _, cancel := process.GetQueryCtxFromProc(proc) + return queryCtx, cancel + }, + wantErr: context.Canceled, + }, + { + name: "query deadline", + buildContext: func(proc *process.Process) (context.Context, func()) { + parentCtx, cancel := context.WithDeadline( + proc.GetTopContext(), time.Now().Add(-time.Second)) + return proc.Base.GetContextBase().BuildQueryCtx(parentCtx), cancel + }, + wantErr: context.DeadlineExceeded, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + queryCtx, cancelQuery := test.buildContext(proc) + proc.BuildPipelineContext(queryCtx) + edge := process.NewPipelineEdge(1, 1) + proc.Reg.MergeReceivers = []*process.WaitRegister{edge} + arg := NewArgument(). + WithLimit(plan2.MakePlan2Uint64ConstExprWithType(1)). + WithFs([]*plan.OrderBySpec{{Expr: newExpression(0)}}). + WithOrderedStreams() + var callErr error + t.Cleanup(func() { + arg.Reset(proc, callErr != nil, callErr) + arg.Release() + proc.Cancel(nil) + cancelQuery() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) + }) + + require.NoError(t, arg.Prepare(proc)) + edge.Ch2 <- process.NewPipelineSignalToDirectly(batch.EmptyBatch, nil, nil) + cancelQuery() + lateErr := moerr.NewDuplicateEntryNoCtx("ordered-top", "primary") + require.False(t, edge.SendError(lateErr)) + + _, callErr = arg.Call(proc) + require.ErrorIs(t, callErr, test.wantErr) + require.NotErrorIs(t, callErr, lateErr) + }) + } +} + func TestMergeTopOrderedStreamsRejectsInvalidOrderColumn(t *testing.T) { proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) reg := process.NewPipelineEdge(2, 1) diff --git a/pkg/sql/colexec/top/allocation_account_test.go b/pkg/sql/colexec/top/allocation_account_test.go index ae5fe45a4dd09..0139645a08661 100644 --- a/pkg/sql/colexec/top/allocation_account_test.go +++ b/pkg/sql/colexec/top/allocation_account_test.go @@ -15,7 +15,6 @@ package top import ( - "bytes" "context" "testing" @@ -317,17 +316,11 @@ func TestAccountedTopPrepareExactCapacityBoundary(t *testing.T) { func TestAccountedTopRuntimeCapacityRejectionCleans(t *testing.T) { proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) - op := newAccountedTop(3) + // Fixed-width input retains the resident allocation-rejection contract; + // varlen payload now takes the spill-resource admission path. + op := newAccountedTop(8192) state := installTopTestAllocation(t, op, proc, 64<<10) - src := batch.NewWithSize(1) - src.Vecs[0] = vector.NewVec(types.T_text.ToType()) - require.NoError(t, vector.AppendBytes( - src.Vecs[0], - bytes.Repeat([]byte("x"), 1<<20), - false, - proc.Mp(), - )) - src.SetRowCount(1) + src := newInt64TopBatch(t, proc, make([]int64, 8192)) child := colexec.NewMockOperator().WithBatchs([]*batch.Batch{src}) op.AppendChild(child) require.NoError(t, op.Prepare(proc)) @@ -342,6 +335,33 @@ func TestAccountedTopRuntimeCapacityRejectionCleans(t *testing.T) { require.Zero(t, proc.Mp().CurrNB()) } +func TestAccountedTopSmallVarlenSpillRejectionCleans(t *testing.T) { + proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) + op := newAccountedTop(3) + state := installTopTestAllocation(t, op, proc, 64<<20) + // Exhaust the explicit spill budget before the first actual-schema guard + // enables spilling. Prepare itself remains on the small-limit path. + blocker, err := state.generation.ReserveSpillDisk(state.generation.SpillDiskCap()) + require.NoError(t, err) + t.Cleanup(func() { blocker.Release() }) + child := colexec.NewMockOperator().WithBatchs([]*batch.Batch{ + newNullableVarcharTopBatch(t, proc, 1, make([]byte, 1<<20), false), + }) + op.AppendChild(child) + require.NoError(t, op.Prepare(proc)) + require.False(t, op.ctr.spilling) + _, err = vm.Exec(op, proc) + var resourceErr *process.ExecutionResourceError + require.ErrorAs(t, err, &resourceErr) + require.Equal(t, process.ExecutionResourceComponentSpillDisk, resourceErr.Component) + child.Free(proc, true, err) + op.Free(proc, true, err) + blocker.Release() + finalizeTopTestAllocation(t, op, state) + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) +} + func TestAccountedTopSpillResourceAdmissionCleans(t *testing.T) { tests := []struct { name string diff --git a/pkg/sql/colexec/top/top.go b/pkg/sql/colexec/top/top.go index ef8572f4246ef..135126c0c73a1 100644 --- a/pkg/sql/colexec/top/top.go +++ b/pkg/sql/colexec/top/top.go @@ -66,19 +66,25 @@ func growTopSlice[T any]( site mpool.AllocationSite, ) ([]T, error) { if length < len(values) || proc == nil { - return nil, mpool.ErrAllocationAccountInvalid + return values, mpool.ErrAllocationAccountInvalid } if length <= cap(values) { return values[:length], nil } if allocation != nil { - return spillutil.GrowAccountedSlice( + grown, err := spillutil.GrowAccountedSlice( values, length, proc.Mp(), allocation, site, ) + if err != nil { + // Callers assign the returned slice back to its owning field. Failed + // growth leaves the old allocation live and owned until Reset/Free. + return values, err + } + return grown, nil } values = slices.Grow(values, length-len(values)) return values[:length], nil @@ -151,7 +157,10 @@ func (top *Top) Prepare(proc *process.Process) (err error) { top.ctr.topValueZM = objectio.NewZM(types.T(typ.Id), typ.Scale) } - if top.ctr.limit > topSpillThreshold { + // Ordered output is consumed as a byte-bounded stream. Use the external + // path even for a small row limit so wide payloads never have to be + // reconstructed as one resident result batch. + if top.OrderedOutput || top.ctr.limit > topSpillThreshold { top.ctr.spilling = true } @@ -262,6 +271,23 @@ func (ctr *container) build(ap *Top, bat *batch.Batch, proc *process.Process, an } if len(ctr.cmps) == 0 { + // The actual input schema is authoritative, including compatible plans + // and runtime limits. Varlen replacement history is not bounded by K. + // Decide before retaining any payload so no migration/replay is needed. + if !ctr.spilling { + remaining := uint64(evalSpillChunkBytes / 4) + if ctr.limit > 0 { + remaining /= ctr.limit + } + for _, vec := range bat.Vecs { + size := vec.GetType().TypeSize() + if size <= 0 || !vec.GetType().Oid.IsFixedLen() || uint64(size)+1 > remaining { + ctr.spilling = true + break + } + remaining -= uint64(size) + 1 + } + } mp := make(map[int]int) for i, pos := range ctr.poses { mp[int(pos)] = i @@ -721,6 +747,10 @@ func (ctr *container) nextSpillOutputChunkEnd(start int) (int, error) { if ctr.evalSpillOutputBytes != 0 { byteLimit = ctr.evalSpillOutputBytes } + // Leave growth/overlap slack under the actual allocator ceiling as well as + // the ordinary logical output window. A single oversized row still gets the + // existing resource/representation error instead of splitting a SQL row. + byteLimit = min(byteLimit, uint64(mpool.MaxAllocationSize()/4)) endLimit := min(start+evalSpillChunkSize, len(ctr.sels)) end := start var outputBytes uint64 diff --git a/pkg/sql/colexec/top/top_test.go b/pkg/sql/colexec/top/top_test.go index 9c4e2c57de89a..cef15f2182783 100644 --- a/pkg/sql/colexec/top/top_test.go +++ b/pkg/sql/colexec/top/top_test.go @@ -113,6 +113,54 @@ func TestPrepare(t *testing.T) { } } +func TestTopPrepareSpillBoundary(t *testing.T) { + tests := []struct { + name string + limit int64 + orderedOutput bool + wantSpill bool + }{ + { + name: "resident threshold remains resident", + limit: int64(topSpillThreshold), + }, + { + name: "ordered threshold uses bounded output", + limit: int64(topSpillThreshold), + orderedOutput: true, + wantSpill: true, + }, + { + name: "above threshold spills", + limit: int64(topSpillThreshold + 1), + wantSpill: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tc := newTestCase( + t, + mpool.MustNewZero(), + []types.Type{types.T_int64.ToType()}, + test.limit, + []*plan.OrderBySpec{{Expr: newExpression(0)}}, + ) + if test.orderedOutput { + tc.arg.WithOrderedOutput() + } + t.Cleanup(func() { + tc.arg.Free(tc.proc, false, nil) + tc.proc.Free() + require.Zero(t, tc.proc.Mp().CurrNB()) + }) + + require.NoError(t, tc.arg.Prepare(tc.proc)) + require.Equal(t, test.wantSpill, tc.arg.ctr.spilling) + }) + } +} + func TestTop(t *testing.T) { for _, tc := range genTestCases(t) { err := tc.arg.Prepare(tc.proc) @@ -306,12 +354,33 @@ func TestTopSpill(t *testing.T) { } func TestTopSpillOutputUsesRowAndByteBounds(t *testing.T) { + testTopSpillOutputUsesRowAndByteBounds(t, int(topSpillThreshold+1), false) +} + +func TestTopOrderedOutputUsesSpillRowAndByteBounds(t *testing.T) { + testTopSpillOutputUsesRowAndByteBounds(t, 37, true) +} + +func TestTopCompatibleVarlenOutputUsesSpillRowAndByteBounds(t *testing.T) { + testTopSpillOutputUsesRowAndByteBounds(t, 37, false) +} + +func TestTopSmallLimitPayloadExceedsAllocationCeiling(t *testing.T) { + previous := mpool.CapLimit + mpool.CapLimit = 1 << 20 + t.Cleanup(func() { mpool.CapLimit = previous }) + // Each input and output batch fits, but the 8192 winning payloads do not + // fit in one vector. This must succeed without an OrderedOutput plan hint. + testTopSpillOutputUsesRowAndByteBounds(t, 8192, false) +} + +func testTopSpillOutputUsesRowAndByteBounds(t *testing.T, limit int, orderedOutput bool) { + t.Helper() const ( payloadBytes = 200 batchRows = 128 outputBytes = 8 * 1024 ) - limit := int(topSpillThreshold + 1) inputRows := limit + 257 tc := newTestCase( t, @@ -320,8 +389,11 @@ func TestTopSpillOutputUsesRowAndByteBounds(t *testing.T) { int64(limit), []*plan.OrderBySpec{{Expr: newExpression(0)}}, ) + if orderedOutput { + tc.arg.WithOrderedOutput() + } require.NoError(t, tc.arg.Prepare(tc.proc)) - require.True(t, tc.arg.ctr.spilling) + require.Equal(t, orderedOutput || uint64(limit) > topSpillThreshold, tc.arg.ctr.spilling) tc.arg.ctr.evalSpillOutputBytes = outputBytes input := make([]*batch.Batch, 0, (inputRows+batchRows-1)/batchRows+1) @@ -353,6 +425,9 @@ func TestTopSpillOutputUsesRowAndByteBounds(t *testing.T) { } outputBatches++ require.LessOrEqual(t, uint64(result.Batch.Size()), uint64(outputBytes)) + for _, vec := range result.Batch.Vecs { + require.Less(t, int64(vec.Allocated()), mpool.MaxAllocationSize()) + } keys := vector.MustFixedColWithTypeCheck[int64](result.Batch.Vecs[0]) got = append(got, keys...) for row := range result.Batch.RowCount() { diff --git a/pkg/sql/compile/compile.go b/pkg/sql/compile/compile.go index cd4f7176b66ba..fc4935b2bef88 100644 --- a/pkg/sql/compile/compile.go +++ b/pkg/sql/compile/compile.go @@ -6365,8 +6365,10 @@ func (c *Compile) compileSort(node *plan.Node, ss []*Scope) []*Scope { if topN < limit || topN < offset { overflow = true } - if !overflow && topN <= mergeTopResidentPlanThreshold { - // if n is small, convert `order by col limit m offset n` to `top m+n offset n` + if !overflow { + // Convert `ORDER BY ... LIMIT m OFFSET n` to `Top(m+n)` plus + // the final offset. compileTop owns the resident-versus-bounded + // physical decision for the checked candidate prefix. return c.compileOffset(node, c.compileTop(node, plan2.MakePlan2Uint64ConstExprWithType(topN), ss)) } } @@ -6397,19 +6399,72 @@ const mergeTopResidentPlanThreshold uint64 = 8192 * 2 // repeatedly spilling a much larger P*K candidate set. const distributedTopNStreamingThresholdBytes = 4 * 128 * mpool.MB -// canUseResidentMergeTop limits the resident-only global MergeTop to small, -// statically bounded plans. Large or runtime limits use the existing spill-capable -// Top and MergeOrder operators instead. +// canUseResidentMergeTop limits the collection-based global MergeTop fallback +// to small, statically bounded plans. When ordered streams are unavailable, +// larger or runtime limits retain the spill-capable Top and MergeOrder path. func canUseResidentMergeTop(topN *plan.Expr) bool { - if topN == nil { + value, ok := staticTopNValue(topN) + return ok && value <= mergeTopResidentPlanThreshold +} + +// residentTopPayloadFits proves a bound from types, never from statistics. +// Varlen replacement can append dead area even with a fixed survivor count. +// Leave room for headers, input copies and growth/shuffle overlap. +func residentTopPayloadFits(node *plan.Node, topN *plan.Expr) bool { + rows, ok := staticTopNValue(topN) + if !ok || node == nil || len(node.ProjectList) == 0 { + return false + } + // These nodes run compileSort before their projection (and TIME_WINDOW + // before aggregation). Their ProjectList does not describe Top's input. + if node.NodeType == plan.Node_SORT || node.NodeType == plan.Node_TIME_WINDOW { return false } + if rows == 0 { + return true + } + remaining := uint64(64*mpool.MB/4) / rows + check := func(expr *plan.Expr) bool { + if expr == nil { + return false + } + typ := types.T(expr.Typ.Id) + if typ.TypeLen() <= 0 || !typ.IsFixedLen() { + return false + } + bytes := uint64(typ.TypeLen()) + 1 // null bitmap, conservatively per row + if bytes > remaining { + return false + } + remaining -= bytes + return true + } + for _, expr := range node.ProjectList { + if !check(expr) { + return false + } + } + for _, spec := range node.OrderBy { + if spec == nil || !check(spec.Expr) { + return false + } + } + return true +} + +func staticTopNValue(topN *plan.Expr) (uint64, bool) { + if topN == nil { + return 0, false + } literal, ok := topN.Expr.(*plan.Expr_Lit) if !ok || literal.Lit == nil { - return false + return 0, false } value, ok := literal.Lit.Value.(*plan.Literal_U64Val) - return ok && value.U64Val <= mergeTopResidentPlanThreshold + if !ok { + return 0, false + } + return value.U64Val, true } func shouldUseDistributedOrderedTop( @@ -6420,9 +6475,17 @@ func shouldUseDistributedOrderedTop( if topN == nil { return false } - if canUseResidentMergeTop(topN) { + staticLimit, hasStaticLimit := staticTopNValue(topN) + if hasStaticLimit && staticLimit == 0 { return false } + // Large static limits already use spill-capable Top + MergeOrder below + // the performance threshold. Small/runtime limits may otherwise retain + // payload, so lack of a type-based bound must select ordered streams. + if (!hasStaticLimit || staticLimit <= mergeTopResidentPlanThreshold) && + !residentTopPayloadFits(node, topN) { + return true + } if node == nil || node.Stats == nil || node.Stats.Cost <= 0 || node.Stats.Rowsize <= 0 || math.IsNaN(node.Stats.Cost) || math.IsInf(node.Stats.Cost, 0) || @@ -6441,16 +6504,11 @@ func shouldUseDistributedOrderedTop( return true } candidateRows := node.Stats.Cost - if literal, ok := topN.Expr.(*plan.Expr_Lit); ok && literal.Lit != nil { - if value, ok := literal.Lit.Value.(*plan.Literal_U64Val); ok { - if value.U64Val == 0 { - return false - } - candidateRows = math.Min( - candidateRows, - float64(value.U64Val)*float64(fanout), - ) - } + if hasStaticLimit { + candidateRows = math.Min( + candidateRows, + float64(staticLimit)*float64(fanout), + ) } candidateBytes := candidateRows * node.Stats.Rowsize return math.IsInf(candidateBytes, 0) || @@ -6497,7 +6555,7 @@ func (c *Compile) compileTop(node *plan.Node, topN *plan.Expr, ss []*Scope) []*S ss = c.mergeShuffleScopesIfNeeded(ss, false) rs := c.newMergeScope(ss) currentFirstFlag = c.anal.isFirst - if canUseResidentMergeTop(topN) { + if canUseResidentMergeTop(topN) && residentTopPayloadFits(node, topN) { arg := constructMergeTop(node, topN) arg.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) rs.setRootOperator(arg) diff --git a/pkg/sql/compile/merge_top_fallback_test.go b/pkg/sql/compile/merge_top_fallback_test.go index 6e6d78697f46a..bce08bcc489c1 100644 --- a/pkg/sql/compile/merge_top_fallback_test.go +++ b/pkg/sql/compile/merge_top_fallback_test.go @@ -19,6 +19,7 @@ import ( "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/colexec" @@ -65,11 +66,22 @@ func TestCompileTopRoutesMultiScopeLimits(t *testing.T) { tests := []struct { name string limit *plan.Expr + stats *plan.Stats ordered bool }{ { name: "resident threshold", limit: plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold), + stats: &plan.Stats{Cost: 1_000, Rowsize: 100}, + }, + { + name: "resident row threshold with wide candidates", + limit: plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold), + stats: &plan.Stats{ + Cost: float64(mergeTopResidentPlanThreshold * 2), + Rowsize: float64(distributedTopNStreamingThresholdBytes)/(float64(mergeTopResidentPlanThreshold)*2) + 1, + }, + ordered: true, }, { name: "large literal", @@ -87,6 +99,7 @@ func TestCompileTopRoutesMultiScopeLimits(t *testing.T) { t.Run(test.name, func(t *testing.T) { c := newMergeTopFallbackTestCompile(t) node := newMergeTopFallbackTestNode(test.limit) + node.Stats = test.stats result := c.compileTop(node, test.limit, newMergeTopFallbackTestScopes(c, 2)) require.Len(t, result, 1) require.Len(t, result[0].PreScopes, 2) @@ -149,7 +162,7 @@ func TestShouldUseDistributedOrderedTopUsesCandidateBytes(t *testing.T) { &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}}, scopes)) dynamicLimit := &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}} - require.False(t, shouldUseDistributedOrderedTop( + require.True(t, shouldUseDistributedOrderedTop( &plan.Node{Stats: &plan.Stats{Cost: 1_000_000, Rowsize: 146}}, dynamicLimit, scopes)) @@ -159,6 +172,23 @@ func TestShouldUseDistributedOrderedTopUsesCandidateBytes(t *testing.T) { scopes)) require.False(t, shouldUseDistributedOrderedTop( &plan.Node{}, plan2.MakePlan2Uint64ConstExprWithType(0), scopes)) + + residentLimit := plan2.MakePlan2Uint64ConstExprWithType(mergeTopResidentPlanThreshold) + residentCandidates := float64(mergeTopResidentPlanThreshold * 16) + exactThresholdRowSize := float64(distributedTopNStreamingThresholdBytes) / residentCandidates + residentNode := newMergeTopFallbackTestNode(residentLimit) + residentNode.Stats = &plan.Stats{Cost: residentCandidates, Rowsize: exactThresholdRowSize} + require.False(t, shouldUseDistributedOrderedTop( + residentNode, + residentLimit, + scopes)) + residentNode.Stats.Rowsize++ + require.True(t, shouldUseDistributedOrderedTop( + residentNode, + residentLimit, + scopes)) + require.True(t, shouldUseDistributedOrderedTop( + &plan.Node{}, residentLimit, scopes)) } func TestCompileTopKeepsSingleScopeLargeLimitLocal(t *testing.T) { @@ -180,6 +210,59 @@ func TestCompileTopKeepsSingleScopeLargeLimitLocal(t *testing.T) { c.proc.Free() } +func TestCompileTopStaleStatisticsCannotAdmitVarlenPayload(t *testing.T) { + for _, k := range []uint64{16383, 16384, 16385} { + for _, version := range []int64{defines.MORPCVersion52, defines.MORPCLatestVersion} { + c := newMergeTopFallbackTestCompile(t) + runtime.ServiceRuntime(c.proc.GetService()).SetGlobalVariables(runtime.MOProtocolVersion, version) + node := newMergeTopFallbackTestNode(plan2.MakePlan2Uint64ConstExprWithType(k)) + node.Stats = &plan.Stats{Cost: 1, Rowsize: 1} + node.ProjectList = append(node.ProjectList, &plan.Expr{Typ: plan.Type{Id: int32(types.T_varchar)}}) + result := c.compileTop(node, node.Limit, newMergeTopFallbackTestScopes(c, 2)) + if version >= defines.MORPCVersion53 && k <= mergeTopResidentPlanThreshold { + gather, ok := result[0].RootOp.(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, gather.OrderedStreams) + } else { + globalLimit, ok := result[0].RootOp.(*limit.Limit) + require.True(t, ok) + _, ok = globalLimit.GetChildren(0).(*mergeorder.MergeOrder) + require.True(t, ok) + } + result[0].FreeOperator(c) + result[0].release() + c.proc.Free() + } + } +} + +func TestResidentTopPayloadProofUsesPhysicalInputSchema(t *testing.T) { + limitExpr := plan2.MakePlan2Uint64ConstExprWithType(16384) + node := newMergeTopFallbackTestNode(limitExpr) + require.True(t, residentTopPayloadFits(node, limitExpr)) + for _, kind := range []plan.Node_NodeType{plan.Node_SORT, plan.Node_TIME_WINDOW} { + node.NodeType = kind + // These projections run after Top; a narrow final projection says + // nothing about the width of retained child payload. + require.False(t, residentTopPayloadFits(node, limitExpr)) + } + node.NodeType = plan.Node_PROJECT + node.ProjectList = nil + require.False(t, residentTopPayloadFits(node, limitExpr)) + node.ProjectList = []*plan.Expr{{Typ: plan.Type{Id: int32(types.T_any)}}} + require.False(t, residentTopPayloadFits(node, limitExpr)) + node.ProjectList = []*plan.Expr{{Typ: plan.Type{Id: int32(types.T_tuple)}}} + require.False(t, residentTopPayloadFits(node, limitExpr)) + node.ProjectList = []*plan.Expr{{Typ: plan.Type{Id: int32(types.T_int64)}}} + require.False(t, residentTopPayloadFits(node, plan2.MakePlan2Uint64ConstExprWithType(^uint64(0)))) + // Widen the fixed-width payload beyond the resident allowance without + // allocating rows or relying on optimizer estimates. + for range 128 { + node.ProjectList = append(node.ProjectList, node.ProjectList[0]) + } + require.False(t, residentTopPayloadFits(node, limitExpr)) +} + func TestCompileTopFallsBackDuringRollingUpgrade(t *testing.T) { c := newMergeTopFallbackTestCompile(t) rt := runtime.ServiceRuntime(c.proc.GetService()) @@ -261,10 +344,15 @@ func enableDistributedOrderedTopForTest(t *testing.T, proc *process.Process) { } func newMergeTopFallbackTestNode(limitExpr *plan.Expr) *plan.Node { + key := &plan.Expr{ + Typ: plan.Type{Id: int32(types.T_int64)}, + Expr: &plan.Expr_Col{Col: &plan.ColRef{ColPos: 0}}, + } return &plan.Node{ - Limit: limitExpr, + Limit: limitExpr, + ProjectList: []*plan.Expr{key}, OrderBy: []*plan.OrderBySpec{{ - Expr: &plan.Expr{Expr: &plan.Expr_Col{Col: &plan.ColRef{ColPos: 0}}}, + Expr: key, }}, } } diff --git a/pkg/sql/compile/scope_test.go b/pkg/sql/compile/scope_test.go index 140a376dc9f04..cb69c5a03a0bd 100644 --- a/pkg/sql/compile/scope_test.go +++ b/pkg/sql/compile/scope_test.go @@ -391,48 +391,73 @@ func TestScopeSerialization(t *testing.T) { func TestCompileOrderByLimitOffsetUsesTopCandidateBudget(t *testing.T) { catalog.SetupDefines("") - scope := generateScopeCases(t, []string{ - "select n_regionkey from nation order by n_regionkey limit 2 + 3 offset 0 + 2", - })[0] - - var topLimits []uint64 - var offsets []uint64 - var opTypes []vm.OpType - var visitOperator func(vm.Operator) - visitOperator = func(operator vm.Operator) { - if operator == nil { - return - } - base := operator.GetOperatorBase() - for i := 0; i < base.NumChildren(); i++ { - visitOperator(base.GetChildren(i)) - } - opTypes = append(opTypes, operator.OpType()) - switch op := operator.(type) { - case *top.Top: - topLimits = append(topLimits, op.Limit.GetLit().GetU64Val()) - case *mergetop.MergeTop: - topLimits = append(topLimits, op.Limit.GetLit().GetU64Val()) - case *offset.Offset: - offsets = append(offsets, op.OffsetExpr.GetLit().GetU64Val()) - } - } - var visitScope func(*Scope) - visitScope = func(current *Scope) { - visitOperator(current.RootOp) - for _, preScope := range current.PreScopes { - visitScope(preScope) - } + tests := []struct { + name string + sql string + candidateLimit uint64 + offset uint64 + expectResidentGather bool + }{ + { + name: "resident candidate prefix", + sql: "select n_regionkey from nation order by n_regionkey limit 2 + 3 offset 0 + 2", + candidateLimit: 7, + offset: 2, + expectResidentGather: true, + }, + { + name: "candidate prefix above resident threshold", + sql: "select n_regionkey from nation order by n_regionkey limit 8193 offset 8192", + candidateLimit: mergeTopResidentPlanThreshold + 1, + offset: 8192, + }, } - visitScope(scope) - require.NotEmpty(t, topLimits) - for _, candidateLimit := range topLimits { - require.Equal(t, uint64(7), candidateLimit) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + scope := generateScopeCases(t, []string{test.sql})[0] + var topLimits []uint64 + var offsets []uint64 + var opTypes []vm.OpType + var visitOperator func(vm.Operator) + visitOperator = func(operator vm.Operator) { + if operator == nil { + return + } + base := operator.GetOperatorBase() + for i := 0; i < base.NumChildren(); i++ { + visitOperator(base.GetChildren(i)) + } + opTypes = append(opTypes, operator.OpType()) + switch op := operator.(type) { + case *top.Top: + topLimits = append(topLimits, op.Limit.GetLit().GetU64Val()) + case *mergetop.MergeTop: + topLimits = append(topLimits, op.Limit.GetLit().GetU64Val()) + case *offset.Offset: + offsets = append(offsets, op.OffsetExpr.GetLit().GetU64Val()) + } + } + var visitScope func(*Scope) + visitScope = func(current *Scope) { + visitOperator(current.RootOp) + for _, preScope := range current.PreScopes { + visitScope(preScope) + } + } + visitScope(scope) + + require.NotEmpty(t, topLimits) + for _, candidateLimit := range topLimits { + require.Equal(t, test.candidateLimit, candidateLimit) + } + require.Contains(t, offsets, test.offset) + require.NotContains(t, opTypes, vm.Order) + if test.expectResidentGather { + require.NotContains(t, opTypes, vm.MergeOrder) + } + }) } - require.Contains(t, offsets, uint64(2)) - require.NotContains(t, opTypes, vm.Order) - require.NotContains(t, opTypes, vm.MergeOrder) } func checkScopeRoot(t *testing.T, s *Scope) { diff --git a/pkg/tests/dml/dml_test.go b/pkg/tests/dml/dml_test.go index e422819d35c1f..b8e8db4d4967d 100644 --- a/pkg/tests/dml/dml_test.go +++ b/pkg/tests/dml/dml_test.go @@ -81,6 +81,39 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { defer plan.SetForceScanOnMultiCN(false) plan.SetForceScanOnMultiCN(true) + t.Run("bounded top preserves remote order and prepared reuse", func(t *testing.T) { + execSQLDB(t, ctx, db, "use `"+deleteDB+"`") + query := "select a,b from " + deleteTable + " order by a desc limit 2" + physical, planErr := testutils.QueryTextResult(ctx, db, "explain phyplan "+query) + require.NoError(t, planErr) + require.Contains(t, strings.ToUpper(physical.ColumnName), "PHYPLAN ON MULTICN(") + require.Contains(t, physical.Text, "Magic: Remote") + require.Contains(t, strings.ToLower(physical.Text), "merge top") + readRows := func(rows *sql.Rows, queryErr error, want [][2]string) { + t.Helper() + require.NoError(t, queryErr) + defer rows.Close() + var got [][2]string + for rows.Next() { + var row [2]string + require.NoError(t, rows.Scan(&row[0], &row[1])) + got = append(got, row) + } + require.NoError(t, rows.Err()) + require.Equal(t, want, got) + } + rows, queryErr := db.QueryContext(ctx, query+" offset 1") + readRows(rows, queryErr, [][2]string{{"7", "7"}, {"3", "3"}}) + stmt, prepareErr := db.PrepareContext(ctx, + "select a,b from "+deleteTable+" order by a desc limit ?") + require.NoError(t, prepareErr) + defer stmt.Close() + for range 2 { + rows, queryErr = stmt.QueryContext(ctx, 2) + readRows(rows, queryErr, [][2]string{{"8", "8"}, {"7", "7"}}) + } + }) + t.Run("delete and select retain exact rows", func(t *testing.T) { execSQLDB(t, ctx, db, "use `"+deleteDB+"`") planResult, planErr := testutils.QueryTextResult(ctx, db, diff --git a/test/distributed/cases/dml/select/limit.result b/test/distributed/cases/dml/select/limit.result index ff39ad27265b1..7822639fa58da 100644 --- a/test/distributed/cases/dml/select/limit.result +++ b/test/distributed/cases/dml/select/limit.result @@ -65,4 +65,23 @@ drop table if exists t1; create table t1 (a int primary key, b varchar); insert into t1 select result, repeat("abcdefg",500) from generate_series (1, 30000)g; select a, left(b,3) from t1 order by a desc limit 32000, 2; -a left(b, 3) \ No newline at end of file +a left(b, 3) +select a, left(b,3) from t1 order by a desc limit 2, 3; +a left(b, 3) +29998 abc +29997 abc +29996 abc +prepare bounded_top from 'select a, left(b,3) from t1 order by a desc limit ?'; +set @bounded_k = 3; +execute bounded_top using @bounded_k; +a left(b, 3) +30000 abc +29999 abc +29998 abc +execute bounded_top using @bounded_k; +a left(b, 3) +30000 abc +29999 abc +29998 abc +deallocate prepare bounded_top; +drop table t1; diff --git a/test/distributed/cases/dml/select/limit.sql b/test/distributed/cases/dml/select/limit.sql index dd78c04e03526..17a2539aa28a0 100644 --- a/test/distributed/cases/dml/select/limit.sql +++ b/test/distributed/cases/dml/select/limit.sql @@ -24,4 +24,13 @@ select * from t1 order by a limit 700000, 2; drop table if exists t1; create table t1 (a int primary key, b varchar); insert into t1 select result, repeat("abcdefg",500) from generate_series (1, 30000)g; -select a, left(b,3) from t1 order by a desc limit 32000, 2; \ No newline at end of file +select a, left(b,3) from t1 order by a desc limit 32000, 2; +-- Small K with varlen payload must select bounded output independently of +-- estimated cardinality/width. Exact order and prepared reuse are public oracles. +select a, left(b,3) from t1 order by a desc limit 2, 3; +prepare bounded_top from 'select a, left(b,3) from t1 order by a desc limit ?'; +set @bounded_k = 3; +execute bounded_top using @bounded_k; +execute bounded_top using @bounded_k; +deallocate prepare bounded_top; +drop table t1; From c8dfd01ebd64edc537b49fc89a8e29f65a176514 Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 09:40:15 +0800 Subject: [PATCH 5/7] fix top-n admission regressions and remote ordered write-back --- docs/design/bounded_distributed_topn.md | 172 ++++++++++++-- .../colexec/top/allocation_account_test.go | 4 +- pkg/sql/colexec/top/resident_test.go | 197 ++++++++++++++++ pkg/sql/colexec/top/top.go | 218 ++++++++++++++++-- pkg/sql/colexec/top/top_test.go | 2 + pkg/sql/colexec/top/types.go | 19 +- pkg/sql/compile/compile.go | 12 +- pkg/sql/compile/compile_test.go | 2 +- pkg/sql/compile/merge_top_fallback_test.go | 80 ++++++- pkg/sql/compile/remoterun.go | 9 + pkg/sql/compile/remoterun_test.go | 53 +++++ pkg/sql/compile/scope_test.go | 7 + pkg/tests/dml/dml_test.go | 44 +++- .../distributed/cases/dml/select/limit.result | 3 + test/distributed/cases/dml/select/limit.sql | 2 + 15 files changed, 767 insertions(+), 57 deletions(-) create mode 100644 pkg/sql/colexec/top/resident_test.go diff --git a/docs/design/bounded_distributed_topn.md b/docs/design/bounded_distributed_topn.md index 58bce8cd6e0e2..a1368fd078245 100644 --- a/docs/design/bounded_distributed_topn.md +++ b/docs/design/bounded_distributed_topn.md @@ -1,10 +1,10 @@ # Bounded distributed ORDER BY / LIMIT -Status: local correctness fixes validated on 2026-09-07; design approval and -rollout performance/compatibility acceptance remain pending. Historical measurements below are not -acceptance evidence for the revised worktree. +Status: review 5127191041 corrections validated locally; new-head CI pending (2026-09-07). Historical +measurements below are not acceptance evidence for the revised worktree. Owner: issue #28285; regression constraint: #27968 must remain executable. -Source baseline: `6e5f82f568b1ec3e013e8d4ab9031b2360300b84`. +Current base: `e60b3eb3bdfd8ad5f1b5ae3eb8745037371f44d8`. +Reviewed head: `7764c28ecdf038b4c7ea0edf26870c52de52103c`. Implementation branch: `xp/fix-28285-bounded-merge-top`. ## Problem and review decision @@ -52,6 +52,37 @@ does not prove zero spill: open temporary files can already be unlinked. ## Algebra and contracts +### Review 5127191041: correction contract + +The two reproduced regressions are ordinary corrections to admission policy, +not a new distributed protocol. Retain the ordered gather for #28285 (no +OFFSET, K=5M), but restore the existing 16,384 candidate-prefix rewrite bound +for OFFSET. An external payload file does not externalize Top's O(K) keys, +references, or their growth overlap, including across parallel workers. + +For small local Top, a varlen type alone is not grounds for disk I/O. Admit +winning rows into a byte-limited resident batch; compare losers before copying. +Before a winner can exceed the resident logical window, compact dead replacement +history if live rows plus that candidate fit in half the window. Otherwise +write only the current survivors, construct their key/reference state, and +publish the resident-to-spill transition before consuming the pending row. +Failed copy/write/allocation aborts the attempt: no partial-row retry and no +output publication. All temporary/old/new capacity remains allocation-accounted. +The window is at most 16 MiB and one eighth of the single-allocation ceiling; +it is an admission policy, not a second physical-memory ledger or RSS claim. +The existing account remains authoritative and may reject a minimal work set. + +Spill-mode Top delays serializing an input batch until its first winner. A +fully rejected batch has zero payload writes; it still must be scanned for +ordering keys. Ordered distributed producers retain their bounded-output +contract. A genuinely single-worker scope needs no ordered-edge hint. + +Validation: exact OFFSET result and cleanup under the review's 160 MiB budget; +small-varlen zero-spill control; replacement compaction and mid-batch migration; +wide rows, disk/allocation rejection, cancel/reset; matched small-Top benchmark +and final-head issue-shaped 100M/K=5M execution. Historical timings are not reused +as final performance acceptance. + Let S be input rows, P actual producers (not merely CNs), and K the demanded ordered prefix. For LIMIT L OFFSET O, K = O + L only when checked addition and the SQL semantics permit it. Otherwise retain the existing correct full-order @@ -131,8 +162,10 @@ Implementation v1 uses the following deliberately narrow activation contract: unbounded/unknown payload types choose the hierarchy independently of estimates. When the protocol/order-expression gate forbids hierarchy, these unsafe resident plans use Top plus MergeOrder. Every updated local Top also checks its actual - first input schema before retaining any payload. Varlen payload uses external - storage because replacement history is not bounded by the number of survivors; + first input schema before retaining payload. Non-ordered small Top uses actual + winner-byte admission with compaction/migration as specified above; a varlen + type alone does not require disk. Single-worker scopes do not request an + ordered-edge contract they do not consume; - once the hierarchy is selected, every local Top uses external payload storage and byte-bounded ordered output even when K is at or below 16,384. This keeps wide rows from being reconstructed into one resident result vector; @@ -227,7 +260,8 @@ disk is available. A future fully external key-selection implementation must: disk, FDs, depth, or the minimal working set returns the appropriate error. - Output an ordered stream in chunks without a single K-row payload vector. -The current source-payload spill can still write substantial input data and +The current source-payload spill writes a batch only after its first candidate +is admitted; fully rejected batches are not written. It can still write substantial input data and requires a full scan of an unordered source. A future external key selector can require multiple merge passes; neither O(K) total spill nor payload read-locality improvements are claimed here. @@ -293,11 +327,11 @@ external key merge passes nor producer early-stop is implemented. Do not infer these metrics from `Batch.Size()`, or add a second estimated memory ledger. All resources remain charged to the owning tenant. -The type-based guard intentionally retains the small fixed-width fast path. -Small varlen Top-N now incurs local payload spill even when the actual values are -short. A runtime resident-to-external migration can recover that optimization in -a follow-up only after publication, comparator reuse, and partial-failure -ownership are proved. Updating a cluster cannot retrofit this runtime guard onto +The type-based guard retains the small fixed-width fast path. The runtime +resident path additionally retains fitting small varlen results, compacting dead +payload or migrating survivors on actual pressure. Ordered distributed producers +still use spill output; lazy writing bounds their rejected-input I/O, not all +candidate I/O. Updating a cluster cannot retrofit this runtime guard onto old CN binaries: mixed-version fallback preserves protocol compatibility, while the full payload safety guarantee requires all executors to carry this fix. @@ -399,10 +433,9 @@ historical run above, the current complete compile package passes. a clean test-owned data directory reached SQL and ISCP readiness. This is not evidence of restart acceptance or a Top-N execution failure. -The revised small-varlen spill cost and original large-scale performance matrix -have not been remeasured. Final design approval, mixed-version execution and -restart acceptance remain separate rollout requirements; no approval is implied -by this local validation record. +The following historical worktree record predates review 5127191041. Consult +the correction evidence below for current measurements. Mixed-version execution +and restart acceptance are not implied by unit tests or historical measurements. 1. Prove typed topology and a deterministic minimal gather, including shared receiver and runtime-DOP counterexamples, before large benchmarks. @@ -456,6 +489,113 @@ A finite suite cannot prove that no counterexample exists. Acceptance means the stated invariants, reachable transitions, and mapped failure dimensions have evidence; untested dimensions and known limits remain explicit. +## Review correction evidence (2026-09-07) + +These checks apply to the corrections on reviewed head `7764c28e`, not the +historical implementation measurements below/elsewhere in this document. + +Complete change-map closure against `e60b3eb3`: + +| Owner / consumer group | Contract and evidence | +| --- | --- | +| Top state, accounting and tests | Actual winner admission; old/new migration ownership; bounded output; OFFSET and small-varlen reproducers; normal/race/failure/reuse tests | +| MergeTop stream, legacy path and tests | One head per ordered producer; exact bag prefix; byte/row output windows; terminal errors and cleanup; full package/race tests | +| Compile routing, scope placement/expansion, duplication, lifecycle tests | Compatible external fallback; preserve worker/CN ordering and allocation owner attachments; scope tests and final SQL topology/result checks | +| Remote encode/decode, write-back and client cleanup | Preserve ordered flags through the entire decoded execution envelope, including the newly added local edge; decoded DOP regression repeated 100 times under race; multi-CN SQL | +| Protocol constants/generated codec and process edges | Explicit version 53 capability; legacy zero values remain unordered; receiver end counts/reuse/backpressure; protocol and edge tests | +| DML and LIMIT BVT | Exact ordered values and payloads, prepared reuse, delete/cast behavior, external large OFFSET; isolated SQL fixtures | + +Q1: resident, compacted and spilled batches have explicit owners. Migration +publishes only after successful copying; failure cleanup retains the old owner +and releases temporary keys, references and spill resources. Q2: ordered edges +have one real producer after DOP gathering; concurrent stage startup, existing +cancellation and terminal draining remain necessary, with no new wait primitive. +Q3: resident replacement history is bounded by admission/compaction, rejected +spill batches do not write payload, and large OFFSET avoids O(K) Top metadata. +Physical capacity is still charged; v1's accounted large-K key/reference state +is not claimed to be fully external. Human approval of the distributed design +and mixed-version deployment acceptance are not inferred from these tests. + +- Review OFFSET reproducer: 4,194,304 bigint rows, LIMIT 1 OFFSET 4,194,303, + 160 MiB shared account; correct final value 4,194,303 and peak accounted + bytes 103,374,880. Memory, spill-disk and spill-FD charges return to zero. + The normal UT uses the minimum 16,385-row routing boundary; the 4M fixture + is an explicit benchmark, not a permanently expensive unit test. +- Matched small-varlen Top benchmark: 128 batches of 8,192 ascending bigint + keys with 64-byte varchar payload, LIMIT 1. Five samples per build, median + main 7.682 ms versus fixed 7.738 ms; both write zero spill bytes. This + replaces the review head's full-input payload writes without unaccounted + retention or raising memory limits. +- Top, MergeTop and compile package tests pass. Resident compaction, + partial/full-heap migration, cancellation/short-write cleanup and reuse + have focused tests; full Top/MergeTop race checks pass. +- CI run 34069583657 on `7764c28e`: SCA found two `rowserrcheck` failures in + the DML fixture. Explicit per-query `rows.Err()` checks fix them without + suppressions. Matching golangci-lint 2.6.2 checks pass locally. +- That run's coverage failure is an actual `TestExecuteIteration1` timeout, + not insufficient coverage. Its internal snapshot lookup uses LIMIT 1 with + varlen payload and failed with `service LOCAL not found`; the snapshot + polling helper hid that error and kept retrying. Byte-bounded local + admission removes the unnecessary spill dependency. The unchanged test + passes in 3.862 seconds, five repetitions in 19.031 seconds, and with + `-short -tags matrixone_test -covermode=set -coverpkg=./pkg/...` in 3.942 + seconds. The full engine/test package also passes with that cross-package + instrumentation in 130.732 seconds. The downstream Coverage merge job failed only because its UT + producer failed. Remote CI for the eventual new commit remains required. + +### Remote write-back correction found during large-scale acceptance + +The three-CN 100M-row/5M-limit acceptance run exposed wrong result identity, +despite completing in about 150 seconds. The decoded remote Top was wrapped +by `appendWriteBackOperator` in an ordinary merge edge. That edge discarded +the ordered producer contract before runtime DOP expansion, allowing worker +batches to interleave on the wire. The coordinator cannot repair this while +performing a streaming merge. + +The correction must preserve the ordered, single-producer edge when wrapping +an ordered Top. Runtime DOP expansion then creates the existing local ordered +gather before the write-back merge forwards its single stream. No new protocol +or ordering algorithm is needed. Acceptance requires a decoded-scope regression +including write-back and DOP expansion, and a fresh exact-result SQL rerun; +the timings of the incorrect runs are not performance acceptance evidence. + +After preserving the write-back edge, final production binary SHA-256 +`c593f182705aef2aa3d0609c600870584068bae4f0d6f5b5a02a5e069185cfe8` +passes the issue-shaped 100M/K=5M INSERT twice: **156.078 s and 145.954 s**. +Both outputs have count/distinct count 5,000,000, min/max 0/4,999,999, +sum 12,499,997,500,000 and payload byte count 640,000,000. Main at `e60b3eb3` +(binary `8fde3aa5c4c57b568b10926140f80d3f78fac5658069d6e4e633a756542c5386`) +did not complete in the 300-second observation window; its specific query +was canceled at about 324 seconds and returned after 328.25 seconds. The +target remained empty after cancellation. This is a censored baseline, not +a measured completion time or a reproduction of the historical 900s timeout. + +Both builds used the same retained data, configuration and host 55 NVMe: +three CN services plus TN/logservice in one launch process, GOMAXPROCS=8, +8-worker scan scopes, bigint key and 128-byte varchar payload. This is not +the original three-host TKE deployment or a historical-good build comparison. +Run order was main then fixed then fixed; no cache-drop operation was used. +The source fingerprint is 100,000,000 rows, keys 0..99,999,999, sum +4,999,999,950,000,000. Final service process RSS high-water was 9,473,892 KiB; +this includes all co-located services and is not query-accounted memory. +Whole-query CPU/I/O counters and a full 1/2/3-CN scale matrix were not collected. + +On the same final instance, fixed-width LIMIT 10 returns exact 0..9 twice +(0.504/0.420 s). The extended forced multi-CN DML test also passes twice in +one process, including a 100K-row/1K-limit exact key/payload regression. +Test-harness startup encountered an existing shared `/tmp` lock and was +rerun with a task-owned TMPDIR; that failed launch is not a test pass. + +The final LIMIT BVT passes twice (35/35 statements each) against the same +final three-CN instance. Both teardown checks find zero `t1` tables and retain +the 100M performance source. Tester startup initially deleted the generated +performance fixture: its configuration loader ignores the supplied Java +property and reads `run.yml` from the working directory. The fixture was +recreated, the actual working-directory configuration now protects it, and +both final protected runs verify it survives. Generated expected results were +not used. The measured INSERT logs predate this reconstruction and are retained +separately; reconstructing test data is not counted as another performance run. + ## References - https://github.com/matrixorigin/matrixone/issues/28285 diff --git a/pkg/sql/colexec/top/allocation_account_test.go b/pkg/sql/colexec/top/allocation_account_test.go index 0139645a08661..473bcf18993c7 100644 --- a/pkg/sql/colexec/top/allocation_account_test.go +++ b/pkg/sql/colexec/top/allocation_account_test.go @@ -339,8 +339,8 @@ func TestAccountedTopSmallVarlenSpillRejectionCleans(t *testing.T) { proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) op := newAccountedTop(3) state := installTopTestAllocation(t, op, proc, 64<<20) - // Exhaust the explicit spill budget before the first actual-schema guard - // enables spilling. Prepare itself remains on the small-limit path. + // Exhaust disk before actual winner pressure triggers resident migration. + op.ctr.residentByteLimit = 512 << 10 blocker, err := state.generation.ReserveSpillDisk(state.generation.SpillDiskCap()) require.NoError(t, err) t.Cleanup(func() { blocker.Release() }) diff --git a/pkg/sql/colexec/top/resident_test.go b/pkg/sql/colexec/top/resident_test.go new file mode 100644 index 0000000000000..deca688539cb7 --- /dev/null +++ b/pkg/sql/colexec/top/resident_test.go @@ -0,0 +1,197 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package top + +import ( + "bytes" + "context" + "io" + "testing" + + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/batch" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/vm" + "github.com/stretchr/testify/require" +) + +func TestTopResidentMigrationFailureKeepsOwner(t *testing.T) { + for _, failure := range []string{"cancel", "short write"} { + t.Run(failure, func(t *testing.T) { + tc := newTestCase(t, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, 1, []*plan.OrderBySpec{{Expr: newExpression(0)}}) + state := installTopTestAllocation(t, tc.arg, tc.proc, 4<<20) + require.NoError(t, tc.arg.Prepare(tc.proc)) + first := newNullableVarcharTopBatch(t, tc.proc, 1, bytes.Repeat([]byte("x"), 64), false) + tc.arg.ctr.n = 2 + require.NoError(t, tc.arg.ctr.build(tc.arg, first, tc.proc, tc.arg.OpAnalyzer)) + owner := tc.arg.ctr.bat + if failure == "cancel" { + ctx, cancel := context.WithCancel(tc.proc.Ctx) + tc.proc.Ctx = ctx + cancel() + } else { + tc.arg.ctr.spillWriter = shortTopSpillWriter{} + } + err := tc.arg.ctr.startResidentSpill(tc.proc, tc.arg.OpAnalyzer) + if failure == "cancel" { + require.ErrorIs(t, err, context.Canceled) + } else { + require.ErrorIs(t, err, io.ErrShortWrite) + } + require.Same(t, owner, tc.arg.ctr.bat) + require.False(t, tc.arg.ctr.spilling) + first.Clean(tc.proc.Mp()) + tc.arg.Free(tc.proc, true, err) + finalizeTopTestAllocation(t, tc.arg, state) + tc.proc.Free() + require.Zero(t, tc.proc.Mp().CurrNB()) + }) + } +} + +func TestTopRejectedBatchesDoNotSpill(t *testing.T) { + for _, ordered := range []bool{false, true} { + t.Run(map[bool]string{false: "resident", true: "ordered spill"}[ordered], func(t *testing.T) { + tc := newTestCase(t, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, 1, []*plan.OrderBySpec{{Expr: newExpression(0)}}) + tc.arg.OrderedOutput = ordered + state := installTopTestAllocation(t, tc.arg, tc.proc, 4<<20) + require.NoError(t, tc.arg.Prepare(tc.proc)) + first := newNullableVarcharTopBatch(t, tc.proc, 1, bytes.Repeat([]byte("x"), 64), false) + tc.arg.ctr.n = 2 + require.NoError(t, tc.arg.ctr.build(tc.arg, first, tc.proc, tc.arg.OpAnalyzer)) + written := tc.arg.ctr.spillOffset + for i := 0; i < 3; i++ { + loser := newNullableVarcharTopBatch(t, tc.proc, 2, bytes.Repeat([]byte("y"), 64), false) + require.NoError(t, tc.arg.ctr.build(tc.arg, loser, tc.proc, tc.arg.OpAnalyzer)) + loser.Clean(tc.proc.Mp()) + require.Equal(t, written, tc.arg.ctr.spillOffset) + } + if !ordered { + require.Zero(t, written) + require.Zero(t, state.generation.SpillFDUsed()) + } + first.Clean(tc.proc.Mp()) + tc.arg.Free(tc.proc, false, nil) + finalizeTopTestAllocation(t, tc.arg, state) + tc.proc.Free() + require.Zero(t, tc.proc.Mp().CurrNB()) + }) + } +} + +func TestTopResidentWinnerAdmission(t *testing.T) { + for _, scenario := range []struct { + name string + limit int64 + wideAt int + }{ + {name: "replacement history compacts", limit: 3, wideAt: -1}, + {name: "migrate full heap mid batch", limit: 3, wideAt: 8}, + {name: "migrate partial heap mid batch", limit: 16, wideAt: 3}, + } { + t.Run(scenario.name, func(t *testing.T) { + tc := newTestCase(t, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, scenario.limit, []*plan.OrderBySpec{{Expr: newExpression(0)}}) + state := installTopTestAllocation(t, tc.arg, tc.proc, 4<<20) + tc.arg.ctr.residentByteLimit = 4096 + for attempt := 0; attempt < 2; attempt++ { + bat := batch.NewWithSize(2) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + bat.Vecs[1] = vector.NewVec(types.T_varchar.ToType()) + for row := 0; row < 128; row++ { + key := int64(128 - row) + size := 64 + if row == scenario.wideAt { + size = 4096 + } + require.NoError(t, vector.AppendFixed(bat.Vecs[0], key, false, tc.proc.Mp())) + require.NoError(t, vector.AppendBytes(bat.Vecs[1], bytes.Repeat([]byte{byte(key)}, size), false, tc.proc.Mp())) + } + bat.SetRowCount(128) + resetChildren(tc.arg, []*batch.Batch{bat}) + require.NoError(t, tc.arg.Prepare(tc.proc)) + var keys []int64 + for { + result, err := vm.Exec(tc.arg, tc.proc) + require.NoError(t, err) + if result.Batch == nil { + break + } + for row := 0; row < result.Batch.RowCount(); row++ { + key := vector.GetFixedAtWithTypeCheck[int64](result.Batch.Vecs[0], row) + keys = append(keys, key) + require.Equal(t, bytes.Repeat([]byte{byte(key)}, 64), result.Batch.Vecs[1].GetBytesAt(row)) + } + } + require.Len(t, keys, int(scenario.limit)) + for i, key := range keys { + require.Equal(t, int64(i+1), key) + } + if scenario.wideAt < 0 { + require.Zero(t, tc.arg.ctr.spillOffset) + require.LessOrEqual(t, tc.arg.ctr.residentBytes, uint64(4096)) + } else { + require.Positive(t, tc.arg.ctr.spillOffset) + } + tc.arg.GetChildren(0).Free(tc.proc, false, nil) + tc.arg.Reset(tc.proc, false, nil) + require.Zero(t, state.account.Snapshot().Used) + require.Zero(t, state.generation.SpillDiskUsed()) + require.Zero(t, state.generation.SpillFDUsed()) + } + tc.arg.Free(tc.proc, false, nil) + finalizeTopTestAllocation(t, tc.arg, state) + tc.proc.Free() + require.Zero(t, tc.proc.Mp().CurrNB()) + }) + } +} + +// Same workload as review 5127191041. Input setup/cleanup is not timed. +// Keep this a benchmark, not a million-row ordinary unit test. +func BenchmarkReviewSmallVarlenTop(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + tc := newTestCase(b, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, 1, []*plan.OrderBySpec{{Expr: newExpression(0)}}) + bats := make([]*batch.Batch, 128) + payload := bytes.Repeat([]byte("x"), 64) + for k := range bats { + bat := batch.NewWithSize(2) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + bat.Vecs[1] = vector.NewVec(types.T_varchar.ToType()) + for j := 0; j < 8192; j++ { + require.NoError(b, vector.AppendFixed(bat.Vecs[0], int64(k*8192+j), false, tc.proc.Mp())) + require.NoError(b, vector.AppendBytes(bat.Vecs[1], payload, false, tc.proc.Mp())) + } + bat.SetRowCount(8192) + bats[k] = bat + } + resetChildren(tc.arg, bats) + b.StartTimer() + require.NoError(b, tc.arg.Prepare(tc.proc)) + result, err := vm.Exec(tc.arg, tc.proc) + require.NoError(b, err) + require.NotNil(b, result.Batch) + require.Equal(b, 1, result.Batch.RowCount()) + require.Equal(b, int64(0), vector.GetFixedAtWithTypeCheck[int64](result.Batch.Vecs[0], 0)) + b.StopTimer() + b.ReportMetric(float64(tc.arg.ctr.spillOffset), "spill-bytes/op") + tc.arg.Free(tc.proc, false, nil) + tc.arg.GetChildren(0).Free(tc.proc, false, nil) + tc.proc.Free() + require.Zero(b, tc.proc.Mp().CurrNB()) + } +} diff --git a/pkg/sql/colexec/top/top.go b/pkg/sql/colexec/top/top.go index 135126c0c73a1..4fd0b9bfefaac 100644 --- a/pkg/sql/colexec/top/top.go +++ b/pkg/sql/colexec/top/top.go @@ -271,9 +271,8 @@ func (ctr *container) build(ap *Top, bat *batch.Batch, proc *process.Process, an } if len(ctr.cmps) == 0 { - // The actual input schema is authoritative, including compatible plans - // and runtime limits. Varlen replacement history is not bounded by K. - // Decide before retaining any payload so no migration/replay is needed. + // Types can prove the fixed-width fast path. Everything else uses + // actual winner-byte admission, not unconditional full-input spilling. if !ctr.spilling { remaining := uint64(evalSpillChunkBytes / 4) if ctr.limit > 0 { @@ -282,7 +281,7 @@ func (ctr *container) build(ap *Top, bat *batch.Batch, proc *process.Process, an for _, vec := range bat.Vecs { size := vec.GetType().TypeSize() if size <= 0 || !vec.GetType().Oid.IsFixedLen() || uint64(size)+1 > remaining { - ctr.spilling = true + ctr.boundedResident = true break } remaining -= uint64(size) + 1 @@ -368,9 +367,187 @@ func (ctr *container) build(ap *Top, bat *batch.Batch, proc *process.Process, an if ctr.spilling { return ctr.processBatchSpill(ap.ctr.limit, bat, proc, analyzer) } + if ctr.boundedResident { + return ctr.processBatchResident(bat, proc, analyzer) + } return ctr.processBatch(ap.ctr.limit, bat, proc) } +func (ctr *container) residentWindow() uint64 { + window := uint64(evalSpillChunkBytes / 4) + if ctr.residentByteLimit != 0 { + window = min(window, ctr.residentByteLimit) + } + return min(window, uint64(mpool.MaxAllocationSize()/8)) +} + +// compactResident preserves row positions (and hence the heap). Admit the new +// allocation while the old one is still owned, and publish only after all +// columns have copied successfully. UnionBatch copies live varlen values only. +func (ctr *container) compactResident(proc *process.Process) error { + next := batch.NewOffHeapWithSize(len(ctr.bat.Vecs)) + defer func() { + if next != nil { + next.Clean(proc.Mp()) + } + }() + for i, vec := range ctr.bat.Vecs { + next.Vecs[i] = vector.NewOffHeapVecWithType(*vec.GetType()) + } + if ctr.retainedAllocation != nil { + if err := next.SetAllocationAccount(ctr.retainedAllocation); err != nil { + return err + } + } + for i := range next.Vecs { + if err := next.Vecs[i].UnionBatch(ctr.bat.Vecs[i], 0, ctr.bat.RowCount(), nil, proc.Mp()); err != nil { + return err + } + } + next.SetRowCount(ctr.bat.RowCount()) + ctr.bat.Clean(proc.Mp()) + ctr.bat, next = next, nil + for i, cmp := range ctr.cmps { + cmp.Set(0, ctr.bat.Vecs[i]) + } + return nil +} + +// startResidentSpill transfers only surviving rows. The pending input row has +// not been mutated or consumed, so the caller resumes it exactly once. On any +// failure the query aborts and Reset/Free still owns all published resources. +func (ctr *container) startResidentSpill(proc *process.Process, analyzer process.Analyzer) error { + keys := batch.NewOffHeapWithSize(len(ctr.poses)) + defer func() { + if keys != nil { + keys.Clean(proc.Mp()) + } + }() + for i, pos := range ctr.poses { + keys.Vecs[i] = vector.NewOffHeapVecWithType(*ctr.bat.Vecs[pos].GetType()) + } + if ctr.retainedAllocation != nil { + if err := keys.SetAllocationAccount(ctr.retainedAllocation); err != nil { + return err + } + } + rows := ctr.bat.RowCount() + if rows > 0 { + record, err := ctr.spillBatch(ctr.bat, proc, analyzer) + if err != nil { + return err + } + ctr.rowRefs, err = growTopSlice(ctr.rowRefs, rows, proc, ctr.spillAllocation, topsites.TopRowReferences) + if err != nil { + return err + } + for i, pos := range ctr.poses { + if err := keys.Vecs[i].UnionBatch(ctr.bat.Vecs[pos], 0, rows, nil, proc.Mp()); err != nil { + return err + } + } + for i := range rows { + width, err := spillOutputRowBytes(ctr.bat, ctr.n, i) + if err != nil { + return err + } + ctr.rowRefs[i] = rowRef{offset: record.offset, size: record.size, rowIdx: int64(i), outputBytes: width} + } + } + keys.SetRowCount(rows) + cmps := make([]compare.Compare, len(ctr.poses)) + for i, pos := range ctr.poses { + cmps[i] = ctr.cmps[pos] + cmps[i].Set(0, keys.Vecs[i]) + } + ctr.bat.Clean(proc.Mp()) + ctr.bat, keys = keys, nil + ctr.cmps = cmps + ctr.spilling = true + ctr.residentBytes = 0 + return nil +} + +func (ctr *container) processBatchResident(bat *batch.Batch, proc *process.Process, analyzer process.Analyzer) error { + for i, cmp := range ctr.cmps { + cmp.Set(1, bat.Vecs[i]) + } + window := ctr.residentWindow() + full := uint64(len(ctr.sels)) == ctr.limit + for row := 0; row < bat.RowCount(); row++ { + if full { + // Reject contiguous losers with only the comparison hot path. Keep + // cancellation outside that loop but bound each scan segment. + if err, canceled := vm.CancelCheck(proc); canceled { + return err + } + end := min(row+evalSpillChunkSize, bat.RowCount()) + for row < end && ctr.compare(1, 0, int64(row), ctr.sels[0]) >= 0 { + row++ + } + if row == end { + row-- // the outer loop advances to the next unchecked row + continue + } + } + if err, canceled := vm.CancelCheck(proc); canceled { + return err + } + width, err := spillOutputRowBytes(bat, len(bat.Vecs), row) + if err != nil { + return err + } + if width > window || ctr.residentBytes > window-width { + var live uint64 + for i := 0; i < ctr.bat.RowCount(); i++ { + n, err := spillOutputRowBytes(ctr.bat, len(ctr.bat.Vecs), i) + if err != nil { + return err + } + live += n + } + if width <= window/2 && live <= window/2-width { + if err := ctr.compactResident(proc); err != nil { + return err + } + ctr.residentBytes = live + } else { + if err := ctr.startResidentSpill(proc, analyzer); err != nil { + return err + } + return ctr.processBatchSpillFrom(ctr.limit, bat, row, proc, analyzer) + } + } + if !full { + position := len(ctr.sels) + ctr.sels, err = growTopSlice(ctr.sels, position+1, proc, ctr.spillAllocation, topsites.TopSelections) + if err != nil { + return err + } + for i, vec := range ctr.bat.Vecs { + if err := vec.UnionOne(bat.Vecs[i], int64(row), proc.Mp()); err != nil { + return err + } + } + ctr.sels[position] = int64(position) + ctr.bat.AddRowCount(1) + if uint64(len(ctr.sels)) == ctr.limit { + ctr.sort() + full = true + } + } else { + for _, cmp := range ctr.cmps { + if err := cmp.Copy(1, 0, int64(row), ctr.sels[0], proc); err != nil { + return err + } + } + heap.Fix(ctr, 0) + } + ctr.residentBytes += width + } + return nil +} + func (ctr *container) processBatch(limit uint64, bat *batch.Batch, proc *process.Process) error { rowCount := bat.RowCount() processCount := rowsToFill(limit, len(ctr.sels), rowCount) @@ -570,15 +747,22 @@ func (ctr *container) spillBatch( } func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *process.Process, analyzer process.Analyzer) error { - record, err := ctr.spillBatch(bat, proc, analyzer) - if err != nil { - return err - } + return ctr.processBatchSpillFrom(limit, bat, 0, proc, analyzer) +} + +func (ctr *container) processBatchSpillFrom(limit uint64, bat *batch.Batch, start int, proc *process.Process, analyzer process.Analyzer) error { + // A complete loser batch must not create a spill file or consume disk. + var record spillRecordRef + var err error rowCount := bat.RowCount() - processCount := rowsToFill(limit, len(ctr.sels), rowCount) + processCount := rowsToFill(limit, len(ctr.sels), rowCount-start) if processCount > 0 { + record, err = ctr.spillBatch(bat, proc, analyzer) + if err != nil { + return err + } if processCount > math.MaxInt-len(ctr.sels) { return moerr.NewInvalidInputNoCtx("top selection count exceeds platform limit") } @@ -607,7 +791,7 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr for idx, pos := range ctr.poses { if err := ctr.bat.Vecs[idx].UnionBatch( bat.Vecs[pos], - 0, + int64(start), processCount, nil, proc.Mp(), @@ -616,7 +800,7 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr } } for i := range processCount { - outputBytes, err := spillOutputRowBytes(bat, ctr.n, i) + outputBytes, err := spillOutputRowBytes(bat, ctr.n, start+i) if err != nil { return err } @@ -625,7 +809,7 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr ctr.rowRefs[position] = rowRef{ offset: record.offset, size: record.size, - rowIdx: int64(i), + rowIdx: int64(start + i), outputBytes: outputBytes, } } @@ -636,7 +820,7 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr } } - if processCount == rowCount { + if start+processCount == rowCount { return nil } @@ -644,9 +828,15 @@ func (ctr *container) processBatchSpill(limit uint64, bat *batch.Batch, proc *pr for idx, pos := range ctr.poses { ctr.cmps[idx].Set(1, bat.Vecs[pos]) } - for i, j := processCount, rowCount; i < j; i++ { + for i, j := start+processCount, rowCount; i < j; i++ { rowIdx := int64(i) if ctr.compare(1, 0, rowIdx, ctr.sels[0]) < 0 { + if record.size == 0 { + record, err = ctr.spillBatch(bat, proc, analyzer) + if err != nil { + return err + } + } outputBytes, err := spillOutputRowBytes(bat, ctr.n, i) if err != nil { return err diff --git a/pkg/sql/colexec/top/top_test.go b/pkg/sql/colexec/top/top_test.go index cef15f2182783..adc079c7b1f95 100644 --- a/pkg/sql/colexec/top/top_test.go +++ b/pkg/sql/colexec/top/top_test.go @@ -395,6 +395,8 @@ func testTopSpillOutputUsesRowAndByteBounds(t *testing.T, limit int, orderedOutp require.NoError(t, tc.arg.Prepare(tc.proc)) require.Equal(t, orderedOutput || uint64(limit) > topSpillThreshold, tc.arg.ctr.spilling) tc.arg.ctr.evalSpillOutputBytes = outputBytes + // Force actual resident pressure independently of output reconstruction. + tc.arg.ctr.residentByteLimit = outputBytes / 2 input := make([]*batch.Batch, 0, (inputRows+batchRows-1)/batchRows+1) for highest := inputRows; highest > 0; { diff --git a/pkg/sql/colexec/top/types.go b/pkg/sql/colexec/top/types.go index d64beb7987798..801c1853e205b 100644 --- a/pkg/sql/colexec/top/types.go +++ b/pkg/sql/colexec/top/types.go @@ -82,13 +82,16 @@ type container struct { spillAllocation *spillutil.SpillAllocationAccount budget *process.ExecutionResourceGeneration - spilling bool - spillFile *os.File - spillWriter spillWriteFlusher - spillOffset int64 - spillFDToken *process.ExecutionSpillFDReservation - spillDiskToken *process.ExecutionSpillDiskReservation - rowRefs []rowRef + spilling bool + boundedResident bool // actual schema needs byte admission and reclamation + residentBytes uint64 // logical bytes including dead replacement history + residentByteLimit uint64 // zero uses the production window; instance test seam + spillFile *os.File + spillWriter spillWriteFlusher + spillOffset int64 + spillFDToken *process.ExecutionSpillFDReservation + spillDiskToken *process.ExecutionSpillDiskReservation + rowRefs []rowRef // streaming eval state for spill mode spillOrdered bool // sels backing contains the final ascending order @@ -357,6 +360,8 @@ func (ctr *container) cleanupSpill(proc *process.Process) { ctr.sels = nil ctr.rowRefs = nil ctr.spilling = false + ctr.boundedResident = false + ctr.residentBytes = 0 ctr.spillOffset = 0 ctr.spillOrdered = false ctr.evalCursor = 0 diff --git a/pkg/sql/compile/compile.go b/pkg/sql/compile/compile.go index fc4935b2bef88..f6a4e5a1de8c7 100644 --- a/pkg/sql/compile/compile.go +++ b/pkg/sql/compile/compile.go @@ -6365,10 +6365,9 @@ func (c *Compile) compileSort(node *plan.Node, ss []*Scope) []*Scope { if topN < limit || topN < offset { overflow = true } - if !overflow { - // Convert `ORDER BY ... LIMIT m OFFSET n` to `Top(m+n)` plus - // the final offset. compileTop owns the resident-versus-bounded - // physical decision for the checked candidate prefix. + if !overflow && topN <= mergeTopResidentPlanThreshold { + // Spilling Top still retains K keys/references per worker. Keep + // external Order for large prefixes, even with a tiny final LIMIT. return c.compileOffset(node, c.compileTop(node, plan2.MakePlan2Uint64ConstExprWithType(topN), ss)) } } @@ -6523,9 +6522,8 @@ func (c *Compile) compileTop(node *plan.Node, topN *plan.Expr, ss []*Scope) []*S if c.IsSingleScope(ss) { currentFirstFlag := c.anal.isFirst op := constructTop(node, topN) - if useOrderedStreams { - op.WithOrderedOutput() - } + // No ordered receiver consumes this single-worker result. Top owns + // actual payload admission and can retain fitting small results. op.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) ss[0].setRootOperator(op) c.anal.isFirst = false diff --git a/pkg/sql/compile/compile_test.go b/pkg/sql/compile/compile_test.go index 37f2d8c30e2b6..485f6bf8b1083 100644 --- a/pkg/sql/compile/compile_test.go +++ b/pkg/sql/compile/compile_test.go @@ -881,7 +881,7 @@ func (w *Ws) PPString() string { return "" } -func NewMockCompile(t *testing.T) *Compile { +func NewMockCompile(t testing.TB) *Compile { return &Compile{ proc: testutil.NewProcess(t), ncpu: system.GoMaxProcs(), diff --git a/pkg/sql/compile/merge_top_fallback_test.go b/pkg/sql/compile/merge_top_fallback_test.go index bce08bcc489c1..2487f243081e6 100644 --- a/pkg/sql/compile/merge_top_fallback_test.go +++ b/pkg/sql/compile/merge_top_fallback_test.go @@ -18,8 +18,11 @@ import ( "testing" "github.com/google/uuid" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/container/batch" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/colexec" @@ -29,11 +32,82 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergetop" "github.com/matrixorigin/matrixone/pkg/sql/colexec/top" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" + "github.com/matrixorigin/matrixone/pkg/vm" "github.com/matrixorigin/matrixone/pkg/vm/engine" "github.com/matrixorigin/matrixone/pkg/vm/process" "github.com/stretchr/testify/require" ) +func TestCompileLargeOffsetUsesExternalOrder(t *testing.T) { + runLargeOffsetMemory(t, int(mergeTopResidentPlanThreshold)+1) +} + +// Scale-sensitive memory acceptance from review 5127191041 belongs outside +// the ordinary UT fixture. The UT above pins the minimum routing boundary. +func BenchmarkReviewLargeOffsetMemory(b *testing.B) { + for i := 0; i < b.N; i++ { + runLargeOffsetMemory(b, 4*1024*1024) + } +} + +func runLargeOffsetMemory(t testing.TB, n int) { + c := newMergeTopFallbackTestCompile(t) + c.proc.Base.Lim.Size = 160 << 20 + generation, err := c.proc.GetExecutionResourceBudget() + require.NoError(t, err) + registry, err := mpool.NewAllocationAccountRegistry(1, 1<<14) + require.NoError(t, err) + account, err := registry.OpenWithController(160<<20, generation) + require.NoError(t, err) + var bats []*batch.Batch + for start := 0; start < n; start += 8192 { + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + values := make([]int64, min(8192, n-start)) + for j := range values { + values[j] = int64(start + j) + } + require.NoError(t, vector.AppendFixedList(bat.Vecs[0], values, nil, c.proc.Mp())) + bat.SetRowCount(len(values)) + bats = append(bats, bat) + } + s := newMergeTopFallbackTestScope(c) + s.Proc = c.proc + s.RootOp = colexec.NewMockOperator().WithBatchs(bats) + node := newMergeTopFallbackTestNode(plan2.MakePlan2Uint64ConstExprWithType(1)) + node.Offset = plan2.MakePlan2Uint64ConstExprWithType(uint64(n - 1)) + node.NodeType = plan.Node_SORT + scopes := c.compileSort(node, []*Scope{s}) + require.Len(t, scopes, 1) + op := scopes[0].RootOp + var owners []executionAllocationAccountOwner + defer func() { + require.NoError(t, vm.HandleAllOp(op, func(_ vm.Operator, o vm.Operator) error { o.Free(c.proc, false, nil); return nil })) + for _, owner := range owners { + require.NoError(t, owner.ClearAllocationAccount(account)) + } + require.Zero(t, account.Snapshot().Used) + require.Zero(t, generation.SpillDiskUsed()) + require.Zero(t, generation.SpillFDUsed()) + c.proc.Free() + require.Zero(t, c.proc.Mp().CurrNB()) + }() + require.NoError(t, vm.HandleAllOp(op, func(_ vm.Operator, o vm.Operator) error { + require.NotEqual(t, vm.Top, o.OpType()) + if owner, ok := o.(executionAllocationAccountOwner); ok { + require.NoError(t, owner.SetAllocationAccount(account)) + owners = append(owners, owner) + } + return o.Prepare(c.proc) + })) + result, err := vm.Exec(op, c.proc) + t.Logf("rows=%d peak accounted bytes=%d", n, account.Snapshot().Peak) + require.NoError(t, err) + require.NotNil(t, result.Batch) + require.Equal(t, 1, result.Batch.RowCount()) + require.Equal(t, int64(n-1), vector.GetFixedAtWithTypeCheck[int64](result.Batch.Vecs[0], 0)) +} + func TestCanUseResidentMergeTop(t *testing.T) { dynamicLimit := &plan.Expr{Expr: &plan.Expr_P{P: &plan.ParamRef{Pos: 0}}} tests := []struct { @@ -202,7 +276,7 @@ func TestCompileTopKeepsSingleScopeLargeLimitLocal(t *testing.T) { require.Same(t, scope, result[0]) localTop, ok := result[0].RootOp.(*top.Top) require.True(t, ok) - require.True(t, localTop.OrderedOutput) + require.False(t, localTop.OrderedOutput, "single-worker results have no ordered receiver edge") require.Same(t, limitExpr, localTop.Limit) result[0].FreeOperator(c) @@ -320,7 +394,7 @@ func TestCompileTopFallsBackWhenOrderKeyIsNotMaterialized(t *testing.T) { c.proc.Free() } -func newMergeTopFallbackTestCompile(t *testing.T) *Compile { +func newMergeTopFallbackTestCompile(t testing.TB) *Compile { c := NewMockCompile(t) enableDistributedOrderedTopForTest(t, c.proc) c.anal = &AnalyzeModule{curNodeIdx: 1, isFirst: true} @@ -329,7 +403,7 @@ func newMergeTopFallbackTestCompile(t *testing.T) *Compile { return c } -func enableDistributedOrderedTopForTest(t *testing.T, proc *process.Process) { +func enableDistributedOrderedTopForTest(t testing.TB, proc *process.Process) { t.Helper() rt := runtime.ServiceRuntime(proc.GetService()) previous, hadPrevious := rt.GetGlobalVariables(runtime.MOProtocolVersion) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 1f7023de89d5f..5e30cc142f392 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -263,7 +263,16 @@ func encodeProcessInfo( } func appendWriteBackOperator(c *Compile, s *Scope) *Scope { + orderedTop, isTop := s.RootOp.(*top.Top) rs := c.newMergeScope([]*Scope{s}) + if isTop && orderedTop.OrderedOutput { + // The wire promises one ordered stream, not interleaved DOP batches. + // Preserve that promise on the new local edge so runtime expansion + // inserts the ordered worker gather before this write-back merge. + reg := rs.Proc.Reg.MergeReceivers[0] + reg.ResetForReuse(1, 1) + reg.OrderedStream = true + } op := output.NewArgument(). WithFunc(c.fill) op.SetIdx(-1) diff --git a/pkg/sql/compile/remoterun_test.go b/pkg/sql/compile/remoterun_test.go index 80f1cdeaea1bb..df5bf4c982a3d 100644 --- a/pkg/sql/compile/remoterun_test.go +++ b/pkg/sql/compile/remoterun_test.go @@ -83,6 +83,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/runtimefilter" "github.com/matrixorigin/matrixone/pkg/sql/colexec/shuffle" "github.com/matrixorigin/matrixone/pkg/sql/colexec/table_function" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/table_scan" "github.com/matrixorigin/matrixone/pkg/sql/colexec/top" "github.com/matrixorigin/matrixone/pkg/sql/colexec/value_scan" sqlmongodb "github.com/matrixorigin/matrixone/pkg/sql/mongodb" @@ -201,6 +202,58 @@ func Test_refactorScope(t *testing.T) { require.Equal(t, vm.GetLeafOpParent(nil, rs.RootOp).GetOperatorBase().Idx, -1) } +func TestRemoteOrderedTopWriteBackPreservesDOPBoundary(t *testing.T) { + for _, ordered := range []bool{false, true} { + t.Run(fmt.Sprintf("ordered=%t", ordered), func(t *testing.T) { + c := newMergeTopFallbackTestCompile(t) + defer c.proc.Free() + limitExpr := plan.MakePlan2Uint64ConstExprWithType(20_000) + orderBy := []*planpb.OrderBySpec{{Expr: &planpb.Expr{ + Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}, + Typ: planpb.Type{Id: int32(types.T_int64)}, + }}} + localTop := top.NewArgument().WithLimit(limitExpr).WithFs(orderBy) + localTop.OrderedOutput = ordered + localTop.AppendChild(table_scan.NewArgument()) + source := &Scope{ + Magic: Remote, NodeInfo: engine.Node{Mcpu: 4}, + Proc: c.proc.NewNoContextChildProc(0), RootOp: localTop, + } + defer source.release() + data, err := encodeRemoteScope(source, c.proc) + require.NoError(t, err) + decoded, err := decodeScope(data, c.proc, true, nil) + require.NoError(t, err) + writeBack := appendWriteBackOperator(c, decoded) + defer writeBack.release() + decoded.Proc.BuildPipelineContext(c.proc.Ctx) + defer decoded.Proc.Cancel(nil) + reg := writeBack.Proc.Reg.MergeReceivers[0] + require.Equal(t, ordered, reg.OrderedStream) + gather, workers := newParallelScope(decoded) + require.Len(t, workers, 4) + if ordered { + require.Equal(t, 1, reg.NilBatchCnt) + require.Equal(t, Merge, gather.Magic) + out, ok := gather.RootOp.(*connector.Connector) + require.True(t, ok) + require.Same(t, reg, out.Reg) + merged, ok := out.GetChildren(0).(*mergetop.MergeTop) + require.True(t, ok) + require.True(t, merged.OrderedStreams) + for i, worker := range workers { + workerOut := worker.RootOp.(*connector.Connector) + require.NotSame(t, reg, workerOut.Reg) + require.Same(t, gather.Proc.Reg.MergeReceivers[i], workerOut.Reg) + require.True(t, workerOut.Reg.OrderedStream) + } + } else { + require.Equal(t, Normal, gather.Magic) + } + }) + } +} + func Test_convertPipelineUuid(t *testing.T) { id, _ := uuid.NewV7() p := &pipeline.Pipeline{ diff --git a/pkg/sql/compile/scope_test.go b/pkg/sql/compile/scope_test.go index cb69c5a03a0bd..3bbdad95cbefd 100644 --- a/pkg/sql/compile/scope_test.go +++ b/pkg/sql/compile/scope_test.go @@ -447,6 +447,13 @@ func TestCompileOrderByLimitOffsetUsesTopCandidateBudget(t *testing.T) { } visitScope(scope) + if !test.expectResidentGather { + require.Empty(t, topLimits) + require.Contains(t, opTypes, vm.Order) + require.Contains(t, opTypes, vm.MergeOrder) + require.Contains(t, offsets, test.offset) + return + } require.NotEmpty(t, topLimits) for _, candidateLimit := range topLimits { require.Equal(t, test.candidateLimit, candidateLimit) diff --git a/pkg/tests/dml/dml_test.go b/pkg/tests/dml/dml_test.go index b8e8db4d4967d..b469f42b47323 100644 --- a/pkg/tests/dml/dml_test.go +++ b/pkg/tests/dml/dml_test.go @@ -74,6 +74,8 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { execSQLDB(t, ctx, db, "create table forced_src (v int)") execSQLDB(t, ctx, db, "insert into forced_src values (31),(31),(31),(31)") execSQLDB(t, ctx, db, "create table forced_dst (b bit(4))") + execSQLDB(t, ctx, db, "create table forced_top_src (id bigint, k bigint, payload varchar(64))") + execSQLDB(t, ctx, db, "insert into forced_top_src select result, 99999-result, repeat('x',64) from generate_series(0,99999) g") // Force only the operations under test. Applying this process-wide test // hook to fixture DDL would exercise an unrelated execution path and can @@ -81,6 +83,29 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { defer plan.SetForceScanOnMultiCN(false) plan.SetForceScanOnMultiCN(true) + t.Run("remote top gathers workers before write back", func(t *testing.T) { + execSQLDB(t, ctx, db, "use `"+castDB+"`") + // Varlen payload selects the ordered hierarchy; enough source rows + // exercise DOP expansion, unlike the five-row control below. + rows, queryErr := db.QueryContext(ctx, + "select id,k,payload from forced_top_src order by k limit 1000") + require.NoError(t, queryErr) + defer rows.Close() + count := 0 + for rows.Next() { + var id, key int64 + var payload string + require.NoError(t, rows.Scan(&id, &key, &payload)) + require.Equal(t, int64(count), key) + require.Equal(t, int64(99999-count), id) + require.Equal(t, strings.Repeat("x", 64), payload) + count++ + } + require.NoError(t, rows.Err()) + require.NoError(t, rows.Close()) + require.Equal(t, 1000, count) + }) + t.Run("bounded top preserves remote order and prepared reuse", func(t *testing.T) { execSQLDB(t, ctx, db, "use `"+deleteDB+"`") query := "select a,b from " + deleteTable + " order by a desc limit 2" @@ -89,28 +114,33 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { require.Contains(t, strings.ToUpper(physical.ColumnName), "PHYPLAN ON MULTICN(") require.Contains(t, physical.Text, "Magic: Remote") require.Contains(t, strings.ToLower(physical.Text), "merge top") - readRows := func(rows *sql.Rows, queryErr error, want [][2]string) { + readRows := func(rows *sql.Rows) [][2]string { t.Helper() - require.NoError(t, queryErr) - defer rows.Close() var got [][2]string for rows.Next() { var row [2]string require.NoError(t, rows.Scan(&row[0], &row[1])) got = append(got, row) } - require.NoError(t, rows.Err()) - require.Equal(t, want, got) + return got } rows, queryErr := db.QueryContext(ctx, query+" offset 1") - readRows(rows, queryErr, [][2]string{{"7", "7"}, {"3", "3"}}) + require.NoError(t, queryErr) + defer rows.Close() + require.Equal(t, [][2]string{{"7", "7"}, {"3", "3"}}, readRows(rows)) + require.NoError(t, rows.Err()) + require.NoError(t, rows.Close()) stmt, prepareErr := db.PrepareContext(ctx, "select a,b from "+deleteTable+" order by a desc limit ?") require.NoError(t, prepareErr) defer stmt.Close() for range 2 { rows, queryErr = stmt.QueryContext(ctx, 2) - readRows(rows, queryErr, [][2]string{{"8", "8"}, {"7", "7"}}) + require.NoError(t, queryErr) + defer rows.Close() + require.Equal(t, [][2]string{{"8", "8"}, {"7", "7"}}, readRows(rows)) + require.NoError(t, rows.Err()) + require.NoError(t, rows.Close()) } }) diff --git a/test/distributed/cases/dml/select/limit.result b/test/distributed/cases/dml/select/limit.result index 7822639fa58da..5b97a7a02ce6b 100644 --- a/test/distributed/cases/dml/select/limit.result +++ b/test/distributed/cases/dml/select/limit.result @@ -66,6 +66,9 @@ create table t1 (a int primary key, b varchar); insert into t1 select result, repeat("abcdefg",500) from generate_series (1, 30000)g; select a, left(b,3) from t1 order by a desc limit 32000, 2; a left(b, 3) +select a, left(b,3) from t1 order by a desc limit 29999, 1; +a left(b, 3) +1 abc select a, left(b,3) from t1 order by a desc limit 2, 3; a left(b, 3) 29998 abc diff --git a/test/distributed/cases/dml/select/limit.sql b/test/distributed/cases/dml/select/limit.sql index 17a2539aa28a0..59ca2778e5427 100644 --- a/test/distributed/cases/dml/select/limit.sql +++ b/test/distributed/cases/dml/select/limit.sql @@ -25,6 +25,8 @@ drop table if exists t1; create table t1 (a int primary key, b varchar); insert into t1 select result, repeat("abcdefg",500) from generate_series (1, 30000)g; select a, left(b,3) from t1 order by a desc limit 32000, 2; +-- A large OFFSET retains the external-sort path and returns the exact tail. +select a, left(b,3) from t1 order by a desc limit 29999, 1; -- Small K with varlen payload must select bounded output independently of -- estimated cardinality/width. Exact order and prepared reuse are public oracles. select a, left(b,3) from t1 order by a desc limit 2, 3; From b65946fd08133ad82eb46eab98dc5189643c39c8 Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 10:21:20 +0800 Subject: [PATCH 6/7] fix(top): decouple ordered output from spill admission --- pkg/sql/colexec/mergetop/top_test.go | 57 ++++++++---- .../colexec/top/allocation_account_test.go | 10 +++ pkg/sql/colexec/top/resident_test.go | 89 ++++++++++++++++++- pkg/sql/colexec/top/top.go | 8 +- pkg/sql/colexec/top/top_test.go | 11 ++- pkg/tests/dml/dml_test.go | 36 ++++++-- 6 files changed, 181 insertions(+), 30 deletions(-) diff --git a/pkg/sql/colexec/mergetop/top_test.go b/pkg/sql/colexec/mergetop/top_test.go index a7ba97c55cfc8..e4138bfc658ad 100644 --- a/pkg/sql/colexec/mergetop/top_test.go +++ b/pkg/sql/colexec/mergetop/top_test.go @@ -31,6 +31,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/colexec" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/top" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/testutil" "github.com/matrixorigin/matrixone/pkg/vm" @@ -158,33 +159,55 @@ func TestMergeTopOrderedStreamsMergesWithoutRetainingLimitRows(t *testing.T) { process.NewPipelineEdge(4, 1), } - for i, values := range [][]int64{{1, 3, 5}, {2, 4, 6}} { - bat := batch.NewWithSize(1) - bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) - for _, value := range values { - require.NoError(t, vector.AppendFixed(bat.Vecs[0], value, false, proc.Mp())) - } - bat.SetRowCount(len(values)) - require.True(t, proc.Reg.MergeReceivers[i].SendDataDirect(proc.Ctx, bat, proc.Mp())) - require.True(t, proc.Reg.MergeReceivers[i].SendEnd()) - } - arg := NewArgument(). WithLimit(plan2.MakePlan2Uint64ConstExprWithType(4)). WithFs([]*plan.OrderBySpec{{Expr: newExpression(0)}}). WithOrderedStreams() require.NoError(t, arg.Prepare(proc)) + t.Cleanup(func() { + if t.Failed() { + for _, reg := range proc.Reg.MergeReceivers { + reg.Abort(context.Canceled) + } + } + arg.Reset(proc, t.Failed(), nil) + arg.Free(proc, t.Failed(), nil) + arg.Release() + proc.Free() + require.Zero(t, proc.Mp().CurrNB()) + }) + + // Exercise the actual producer/consumer boundary, including resident Top + // output: an ordered edge must not depend on the producer's storage mode. + for i, values := range [][]int64{{5, 1, 3}, {6, 2, 4}} { + func() { + bat := batch.NewWithSize(1) + child := colexec.NewMockOperator().WithBatchs([]*batch.Batch{bat}) + defer child.Free(proc, false, nil) + bat.Vecs[0] = vector.NewVec(types.T_int64.ToType()) + for _, value := range values { + require.NoError(t, vector.AppendFixed(bat.Vecs[0], value, false, proc.Mp())) + } + bat.SetRowCount(len(values)) + producer := top.NewArgument().WithLimit(plan2.MakePlan2Uint64ConstExprWithType(3)). + WithFs(arg.Fs).WithOrderedOutput() + producer.AppendChild(child) + defer producer.Release() + defer producer.Free(proc, false, nil) + require.NoError(t, producer.Prepare(proc)) + result, err := producer.Call(proc) + require.NoError(t, err) + copied, err := result.Batch.Dup(proc.Mp()) + require.NoError(t, err) + require.True(t, proc.Reg.MergeReceivers[i].SendDataDirect(proc.Ctx, copied, proc.Mp())) + require.True(t, proc.Reg.MergeReceivers[i].SendEnd()) + }() + } result, err := arg.Call(proc) require.NoError(t, err) require.Equal(t, []int64{1, 2, 3, 4}, vector.MustFixedColWithTypeCheck[int64](result.Batch.Vecs[0])) require.Less(t, result.Batch.Size(), mergeTopStreamBatchBytes) - - arg.Reset(proc, false, nil) - arg.Free(proc, false, nil) - arg.Release() - proc.Free() - require.Equal(t, int64(0), proc.Mp().CurrNB()) } func TestMergeTopOrderedStreamsAcrossBatchBoundariesDescending(t *testing.T) { diff --git a/pkg/sql/colexec/top/allocation_account_test.go b/pkg/sql/colexec/top/allocation_account_test.go index 473bcf18993c7..b96388e913b02 100644 --- a/pkg/sql/colexec/top/allocation_account_test.go +++ b/pkg/sql/colexec/top/allocation_account_test.go @@ -336,8 +336,18 @@ func TestAccountedTopRuntimeCapacityRejectionCleans(t *testing.T) { } func TestAccountedTopSmallVarlenSpillRejectionCleans(t *testing.T) { + testAccountedTopSmallVarlenSpillRejectionCleans(t, false) +} + +func TestAccountedTopOrderedSmallVarlenSpillRejectionCleans(t *testing.T) { + testAccountedTopSmallVarlenSpillRejectionCleans(t, true) +} + +func testAccountedTopSmallVarlenSpillRejectionCleans(t *testing.T, ordered bool) { + t.Helper() proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) op := newAccountedTop(3) + op.OrderedOutput = ordered state := installTopTestAllocation(t, op, proc, 64<<20) // Exhaust disk before actual winner pressure triggers resident migration. op.ctr.residentByteLimit = 512 << 10 diff --git a/pkg/sql/colexec/top/resident_test.go b/pkg/sql/colexec/top/resident_test.go index deca688539cb7..a58c64557d176 100644 --- a/pkg/sql/colexec/top/resident_test.go +++ b/pkg/sql/colexec/top/resident_test.go @@ -17,6 +17,7 @@ package top import ( "bytes" "context" + "fmt" "io" "testing" @@ -29,6 +30,69 @@ import ( "github.com/stretchr/testify/require" ) +func TestTopOrderedResidentDoesNotRequireSpillResources(t *testing.T) { + for _, resource := range []string{"disk", "fd"} { + t.Run(resource, func(t *testing.T) { + expr := newExpression(0) + expr.Typ.Id = int32(types.T_varchar) + tc := newTestCase(t, mpool.MustNewZero(), []types.Type{types.T_varchar.ToType()}, 2, + []*plan.OrderBySpec{{Expr: expr}}) + tc.arg.WithOrderedOutput() + // Twelve improving keys cross this window; the two live winners fit. + // Reclamation, not input-sized replacement history, must bound memory. + tc.arg.ctr.residentByteLimit = 1024 + state := installTopTestAllocation(t, tc.arg, tc.proc, 4<<20) + t.Cleanup(func() { + if tc.arg.NumChildren() > 0 { + tc.arg.GetChildren(0).Free(tc.proc, false, nil) + } + tc.arg.Free(tc.proc, false, nil) + finalizeTopTestAllocation(t, tc.arg, state) + tc.proc.Free() + require.Zero(t, tc.proc.Mp().CurrNB()) + }) + if resource == "disk" { + blocker, err := state.generation.ReserveSpillDisk(state.generation.SpillDiskCap()) + require.NoError(t, err) + t.Cleanup(func() { blocker.Release() }) + } else { + blocker, err := state.generation.ReserveSpillFD(state.generation.SpillFDCap()) + require.NoError(t, err) + t.Cleanup(func() { blocker.Release() }) + } + for range 2 { + bat := batch.NewWithSize(1) + bat.Vecs[0] = vector.NewVec(types.T_varchar.ToType()) + resetChildren(tc.arg, []*batch.Batch{bat}) + for key := 12; key > 0; key-- { + value := fmt.Sprintf("%02d%s", key, bytes.Repeat([]byte("x"), 62)) + require.NoError(t, vector.AppendBytes(bat.Vecs[0], []byte(value), false, tc.proc.Mp())) + } + bat.SetRowCount(12) + require.NoError(t, tc.arg.Prepare(tc.proc)) + result, err := vm.Exec(tc.arg, tc.proc) + require.NoError(t, err) + require.NotNil(t, result.Batch) + require.Equal(t, 2, result.Batch.RowCount()) + for row := range 2 { + require.Equal(t, fmt.Sprintf("%02d%s", row+1, bytes.Repeat([]byte("x"), 62)), + string(result.Batch.Vecs[0].GetBytesAt(row))) + } + require.False(t, tc.arg.ctr.spilling) + require.Nil(t, tc.arg.ctr.spillFile) + require.Zero(t, tc.arg.ctr.spillOffset) + require.LessOrEqual(t, tc.arg.ctr.residentBytes, uint64(1024)) + result, err = vm.Exec(tc.arg, tc.proc) + require.NoError(t, err) + require.Nil(t, result.Batch) + tc.arg.GetChildren(0).Free(tc.proc, false, nil) + tc.arg.Reset(tc.proc, false, nil) + require.Zero(t, state.account.Snapshot().Used) + } + }) + } +} + func TestTopResidentMigrationFailureKeepsOwner(t *testing.T) { for _, failure := range []string{"cancel", "short write"} { t.Run(failure, func(t *testing.T) { @@ -65,14 +129,18 @@ func TestTopResidentMigrationFailureKeepsOwner(t *testing.T) { func TestTopRejectedBatchesDoNotSpill(t *testing.T) { for _, ordered := range []bool{false, true} { - t.Run(map[bool]string{false: "resident", true: "ordered spill"}[ordered], func(t *testing.T) { + t.Run(map[bool]string{false: "resident", true: "migrated ordered spill"}[ordered], func(t *testing.T) { tc := newTestCase(t, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, 1, []*plan.OrderBySpec{{Expr: newExpression(0)}}) tc.arg.OrderedOutput = ordered + if ordered { + tc.arg.ctr.residentByteLimit = 32 + } state := installTopTestAllocation(t, tc.arg, tc.proc, 4<<20) require.NoError(t, tc.arg.Prepare(tc.proc)) first := newNullableVarcharTopBatch(t, tc.proc, 1, bytes.Repeat([]byte("x"), 64), false) tc.arg.ctr.n = 2 require.NoError(t, tc.arg.ctr.build(tc.arg, first, tc.proc, tc.arg.OpAnalyzer)) + require.Equal(t, ordered, tc.arg.ctr.spilling) written := tc.arg.ctr.spillOffset for i := 0; i < 3; i++ { loser := newNullableVarcharTopBatch(t, tc.proc, 2, bytes.Repeat([]byte("y"), 64), false) @@ -94,6 +162,15 @@ func TestTopRejectedBatchesDoNotSpill(t *testing.T) { } func TestTopResidentWinnerAdmission(t *testing.T) { + testTopResidentWinnerAdmission(t, false) +} + +func TestTopOrderedResidentWinnerAdmission(t *testing.T) { + testTopResidentWinnerAdmission(t, true) +} + +func testTopResidentWinnerAdmission(t *testing.T, ordered bool) { + t.Helper() for _, scenario := range []struct { name string limit int64 @@ -105,6 +182,7 @@ func TestTopResidentWinnerAdmission(t *testing.T) { } { t.Run(scenario.name, func(t *testing.T) { tc := newTestCase(t, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, scenario.limit, []*plan.OrderBySpec{{Expr: newExpression(0)}}) + tc.arg.OrderedOutput = ordered state := installTopTestAllocation(t, tc.arg, tc.proc, 4<<20) tc.arg.ctr.residentByteLimit = 4096 for attempt := 0; attempt < 2; attempt++ { @@ -163,9 +241,18 @@ func TestTopResidentWinnerAdmission(t *testing.T) { // Same workload as review 5127191041. Input setup/cleanup is not timed. // Keep this a benchmark, not a million-row ordinary unit test. func BenchmarkReviewSmallVarlenTop(b *testing.B) { + benchmarkSmallVarlenTop(b, false) +} + +func BenchmarkOrderedSmallVarlenTop(b *testing.B) { + benchmarkSmallVarlenTop(b, true) +} + +func benchmarkSmallVarlenTop(b *testing.B, ordered bool) { for i := 0; i < b.N; i++ { b.StopTimer() tc := newTestCase(b, mpool.MustNewZero(), []types.Type{types.T_int64.ToType(), types.T_varchar.ToType()}, 1, []*plan.OrderBySpec{{Expr: newExpression(0)}}) + tc.arg.OrderedOutput = ordered bats := make([]*batch.Batch, 128) payload := bytes.Repeat([]byte("x"), 64) for k := range bats { diff --git a/pkg/sql/colexec/top/top.go b/pkg/sql/colexec/top/top.go index 4fd0b9bfefaac..5924938d85a15 100644 --- a/pkg/sql/colexec/top/top.go +++ b/pkg/sql/colexec/top/top.go @@ -157,10 +157,10 @@ func (top *Top) Prepare(proc *process.Process) (err error) { top.ctr.topValueZM = objectio.NewZM(types.T(typ.Id), typ.Scale) } - // Ordered output is consumed as a byte-bounded stream. Use the external - // path even for a small row limit so wide payloads never have to be - // reconstructed as one resident result batch. - if top.OrderedOutput || top.ctr.limit > topSpillThreshold { + // OrderedOutput is a topology contract, not a storage policy. Both eval + // paths produce sorted rows. Small results use type/actual-byte admission + // in build and migrate only under payload pressure; large K still spills. + if top.ctr.limit > topSpillThreshold { top.ctr.spilling = true } diff --git a/pkg/sql/colexec/top/top_test.go b/pkg/sql/colexec/top/top_test.go index adc079c7b1f95..2dc5bac9430e3 100644 --- a/pkg/sql/colexec/top/top_test.go +++ b/pkg/sql/colexec/top/top_test.go @@ -125,16 +125,21 @@ func TestTopPrepareSpillBoundary(t *testing.T) { limit: int64(topSpillThreshold), }, { - name: "ordered threshold uses bounded output", + name: "ordered threshold remains resident", limit: int64(topSpillThreshold), orderedOutput: true, - wantSpill: true, }, { name: "above threshold spills", limit: int64(topSpillThreshold + 1), wantSpill: true, }, + { + name: "ordered above threshold spills", + limit: int64(topSpillThreshold + 1), + orderedOutput: true, + wantSpill: true, + }, } for _, test := range tests { @@ -393,7 +398,7 @@ func testTopSpillOutputUsesRowAndByteBounds(t *testing.T, limit int, orderedOutp tc.arg.WithOrderedOutput() } require.NoError(t, tc.arg.Prepare(tc.proc)) - require.Equal(t, orderedOutput || uint64(limit) > topSpillThreshold, tc.arg.ctr.spilling) + require.Equal(t, uint64(limit) > topSpillThreshold, tc.arg.ctr.spilling) tc.arg.ctr.evalSpillOutputBytes = outputBytes // Force actual resident pressure independently of output reconstruction. tc.arg.ctr.residentByteLimit = outputBytes / 2 diff --git a/pkg/tests/dml/dml_test.go b/pkg/tests/dml/dml_test.go index b469f42b47323..ac1694c9b3fa8 100644 --- a/pkg/tests/dml/dml_test.go +++ b/pkg/tests/dml/dml_test.go @@ -29,8 +29,10 @@ import ( _ "github.com/go-sql-driver/mysql" "github.com/stretchr/testify/require" + "github.com/matrixorigin/matrixone/pkg/clusterservice" "github.com/matrixorigin/matrixone/pkg/embed" "github.com/matrixorigin/matrixone/pkg/objectio" + "github.com/matrixorigin/matrixone/pkg/pb/metadata" "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/tests/testutils" "github.com/matrixorigin/matrixone/pkg/util/executor" @@ -44,6 +46,23 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { cn, err := c.GetCNService(0) require.NoError(t, err) + // Service startup does not imply that the query coordinator's cached + // inventory contains both workers. Establish that precondition before + // asserting the distributed Top topology. + cluster := clusterservice.GetMOCluster(cn.ServiceID()) + refresher, ok := cluster.(clusterservice.AuthoritativeRefresher) + require.True(t, ok) + require.Eventually(t, func() bool { + if refresher.Refresh(ctx) != nil { + return false + } + workers := 0 + cluster.GetCNService(clusterservice.NewSelector(), func(metadata.CNService) bool { + workers++ + return true + }) + return workers == 2 + }, 30*time.Second, 100*time.Millisecond, "both CN workers must be discoverable") internalExec := testutils.GetSQLExecutor(cn) port := cn.GetServiceConfig().CN.Frontend.Port db, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) @@ -85,10 +104,15 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { t.Run("remote top gathers workers before write back", func(t *testing.T) { execSQLDB(t, ctx, db, "use `"+castDB+"`") - // Varlen payload selects the ordered hierarchy; enough source rows - // exercise DOP expansion, unlike the five-row control below. - rows, queryErr := db.QueryContext(ctx, - "select id,k,payload from forced_top_src order by k limit 1000") + // Varlen payload selects the ordered hierarchy. Assert the actual + // gather topology, not just the MULTICN execution-mode header. + query := "select id,k,payload from forced_top_src order by k limit 1000" + physical, planErr := testutils.QueryTextResult(ctx, db, "explain phyplan "+query) + require.NoError(t, planErr) + require.Contains(t, strings.ToUpper(physical.ColumnName), "PHYPLAN ON MULTICN(") + require.Contains(t, physical.Text, "Magic: Remote") + require.Contains(t, strings.ToLower(physical.Text), "merge top") + rows, queryErr := db.QueryContext(ctx, query) require.NoError(t, queryErr) defer rows.Close() count := 0 @@ -113,7 +137,9 @@ func TestForcedMultiCNDeleteAndInsertIgnore(t *testing.T) { require.NoError(t, planErr) require.Contains(t, strings.ToUpper(physical.ColumnName), "PHYPLAN ON MULTICN(") require.Contains(t, physical.Text, "Magic: Remote") - require.Contains(t, strings.ToLower(physical.Text), "merge top") + // A tiny source can collapse to one remote worker. The larger case + // above proves the gather topology; this control proves exact rows + // and prepared reuse without requiring an unnecessary merge. readRows := func(rows *sql.Rows) [][2]string { t.Helper() var got [][2]string From f8d40ae8ed29895a459798a60cafe2c7c3e0bc4a Mon Sep 17 00:00:00 2001 From: XuPeng-SH Date: Mon, 7 Sep 2026 11:52:57 +0800 Subject: [PATCH 7/7] docs(design): align bounded Top-N review record --- docs/design/bounded_distributed_topn.md | 81 +++++++++++++++++++------ 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/docs/design/bounded_distributed_topn.md b/docs/design/bounded_distributed_topn.md index a1368fd078245..7065eb4aa4929 100644 --- a/docs/design/bounded_distributed_topn.md +++ b/docs/design/bounded_distributed_topn.md @@ -1,12 +1,49 @@ # Bounded distributed ORDER BY / LIMIT -Status: review 5127191041 corrections validated locally; new-head CI pending (2026-09-07). Historical -measurements below are not acceptance evidence for the revised worktree. +Status: implementation review completed through `b65946fd08133ad82eb46eab98dc5189643c39c8`; +substantive CI is green; independent design approval is pending (2026-09-07). +Historical measurements below remain labeled separately from final-head evidence. Owner: issue #28285; regression constraint: #27968 must remain executable. Current base: `e60b3eb3bdfd8ad5f1b5ae3eb8745037371f44d8`. -Reviewed head: `7764c28ecdf038b4c7ea0edf26870c52de52103c`. +Implementation reviewed through: `b65946fd08133ad82eb46eab98dc5189643c39c8`. Implementation branch: `xp/fix-28285-bounded-merge-top`. +## Design review record + +| Field | Record | +| --- | --- | +| Change scope | Distributed ordered Top-N hierarchy, local Top admission/spill policy, remote scope encoding/write-back, runtime DOP expansion, and cleanup/accounting contracts | +| Design trigger | Changes a distributed wire protocol and ordering contract, crosses compile/process/operator/remote-execution ownership boundaries, and materially affects a hot path and capacity bounds | +| Design revision | The commit containing this document; an independent reviewer must cite that commit when recording the decision | +| Implementation revision | Code reviewed through `b65946fd08133ad82eb46eab98dc5189643c39c8`; the documentation-only alignment commit does not change runtime behavior | +| Design status | Ready for independent review; approval is not self-asserted and remains a merge gate | +| Blocking design questions from implementation review | None identified; the independent reviewer owns the final PASS or concrete design findings | +| Implementation conformance | Conforms to the selected hierarchy, protocol-v53 fallback, one-producer ordered edges, bounded gather output, resident winner admission, spill migration, and large-OFFSET fallback described below | + +### Decision log + +| Decision | Rationale and accepted boundary | +| --- | --- | +| Add a protocol-v53 ordered-stream edge and hierarchical MergeTop | Eliminates global P*K payload materialization while preserving one sorted stream per actual worker and CN boundary | +| Activate the hierarchy only for materialized order columns and estimated/unknown pressure | Avoids reevaluating volatile expressions and retains the lower-overhead compatible path for small bounded inputs | +| Let small fixed-width and varlen winners remain resident | Avoids mandatory disk I/O for ordinary small Top; actual-byte admission compacts dead history or migrates survivors under pressure | +| Keep large OFFSET on external Order above the 16,384-row prefix bound | Spill-backed Top still retains O(K) keys/references and their growth overlap, so a small final LIMIT does not prove safe Top admission | +| Retain O(K) local keys/references in v1 | They remain allocation-accounted and may return a controlled resource error; fully external key selection is a separate design | +| Drain finite producer output instead of adding prefix-stop in v1 | Preserves substantive producer errors and existing terminal arbitration; early producer stop needs a separate protocol decision | + +### Remaining rollout gates + +- An independent reviewer must approve this design revision and record the + decision on the PR before implementation approval. +- Mixed-version deployment must demonstrate that the negotiated version keeps + old peers on the compatible MergeTop/MergeOrder path and rejects an ordered + payload that a peer cannot understand. This is a deployment gate, not evidence + inferred from codec unit tests. +- The final binary has issue-shaped co-located three-CN evidence. Reproducing the + original three-host TKE topology and comparing a historical-good build remain + production rollout evidence; absence of either does not change the source-level + correctness result already reviewed. + ## Problem and review decision Reject the earlier proposal to unconditionally restore resident MergeTop. @@ -113,9 +150,10 @@ This supports these invariants: charged by the existing allocation accounts, not by `Batch.Size()`. The 64 MiB window is not an exact physical peak/RSS guarantee. Large result cardinality alone never requires one large payload allocation. -4. Local Top spills source payload, but v1 still retains O(K) row references - and ordering keys per producer. Those allocations remain query-accounted; - a fully external key-selection state is a separate follow-up boundary. +4. Local Top retains fitting winners and spills source payload after actual + pressure. Spill mode still retains O(K) row references and ordering keys per + producer. Those allocations remain query-accounted; a fully external + key-selection state is a separate follow-up boundary. 5. Success, rejection, error, cancellation, and reuse have one cleanup owner. 6. Early stop applies only to the exclusively owned pure read subtree. Shared producers, found-rows consumers, and required effects retain their semantics. @@ -166,14 +204,17 @@ Implementation v1 uses the following deliberately narrow activation contract: winner-byte admission with compaction/migration as specified above; a varlen type alone does not require disk. Single-worker scopes do not request an ordered-edge contract they do not consume; -- once the hierarchy is selected, every local Top uses external payload storage - and byte-bounded ordered output even when K is at or below 16,384. This keeps - wide rows from being reconstructed into one resident result vector; -- output is bounded by both 8,192 rows and 64 MiB (except that one individually - valid row must be allowed to make progress). The logical window is additionally - capped at one quarter of the allocator's single-allocation ceiling, reserving - slack for vector growth. Fixed and variable-width winner - runs are copied in bounded chunks using actual varlen payload sizes; +- once the hierarchy is selected, each local Top preserves the ordered-output + contract but chooses storage independently. Fitting small winners remain + resident; dead varlen replacement history is compacted, and survivors migrate + to external payload storage only under actual byte pressure. Large K starts in + spill mode. Both resident and spilled paths emit the same sorted rows; +- spill reconstruction and ordered gather output are bounded by both 8,192 rows + and 64 MiB (except that one individually valid row must make progress). The + logical window is additionally capped by the allocator's single-allocation + ceiling with slack for growth. Fixed and variable-width winner runs are copied + in bounded chunks using actual varlen payload sizes. A fitting resident Top may + return its complete small result in one batch; - cleanup shares one 30-second deadline across every receiver. The first implementation drains already-produced local Top output rather than introducing a new receiver-stop terminal state; producer early-stop remains @@ -330,8 +371,8 @@ All resources remain charged to the owning tenant. The type-based guard retains the small fixed-width fast path. The runtime resident path additionally retains fitting small varlen results, compacting dead payload or migrating survivors on actual pressure. Ordered distributed producers -still use spill output; lazy writing bounds their rejected-input I/O, not all -candidate I/O. Updating a cluster cannot retrofit this runtime guard onto +use the same resident-or-spill admission; once spill mode is active, lazy writing +bounds rejected-input I/O, not all candidate I/O. Updating a cluster cannot retrofit this runtime guard onto old CN binaries: mixed-version fallback preserves protocol compatibility, while the full payload safety guarantee requires all executors to carry this fix. @@ -489,10 +530,10 @@ A finite suite cannot prove that no counterexample exists. Acceptance means the stated invariants, reachable transitions, and mapped failure dimensions have evidence; untested dimensions and known limits remain explicit. -## Review correction evidence (2026-09-07) +## Final implementation review evidence (2026-09-07) -These checks apply to the corrections on reviewed head `7764c28e`, not the -historical implementation measurements below/elsewhere in this document. +These checks cover the implementation through `b65946fd08133ad82eb46eab98dc5189643c39c8`. +Earlier failed or superseded measurements remain identified as historical evidence. Complete change-map closure against `e60b3eb3`: @@ -513,7 +554,7 @@ cancellation and terminal draining remain necessary, with no new wait primitive. Q3: resident replacement history is bounded by admission/compaction, rejected spill batches do not write payload, and large OFFSET avoids O(K) Top metadata. Physical capacity is still charged; v1's accounted large-K key/reference state -is not claimed to be fully external. Human approval of the distributed design +is not claimed to be fully external. Independent approval of this design revision and mixed-version deployment acceptance are not inferred from these tests. - Review OFFSET reproducer: 4,194,304 bigint rows, LIMIT 1 OFFSET 4,194,303,