diff --git a/pkg/common/hashmap/inthashmap.go b/pkg/common/hashmap/inthashmap.go index ff0c13e0e11a0..bbb62300f563c 100644 --- a/pkg/common/hashmap/inthashmap.go +++ b/pkg/common/hashmap/inthashmap.go @@ -370,3 +370,7 @@ func (m *IntHashMap) UnmarshalFrom(r io.Reader, allocator malloc.Allocator) (int return n, nil } + +func (m *IntHashMap) AllGroupHash() []uint64 { + return m.hashMap.AllGroupHash() +} diff --git a/pkg/common/hashmap/strhashmap.go b/pkg/common/hashmap/strhashmap.go index cc5e70f715af9..4f644cd61d6a1 100644 --- a/pkg/common/hashmap/strhashmap.go +++ b/pkg/common/hashmap/strhashmap.go @@ -461,3 +461,7 @@ func (m *StrHashMap) UnmarshalFrom(r io.Reader, allocator malloc.Allocator) (int return n, nil } + +func (m *StrHashMap) AllGroupHash() []uint64 { + return m.hashMap.AllGroupHash() +} diff --git a/pkg/common/hashmap/types.go b/pkg/common/hashmap/types.go index 246c44acdc7e7..962d4dc56d8c5 100644 --- a/pkg/common/hashmap/types.go +++ b/pkg/common/hashmap/types.go @@ -57,6 +57,8 @@ type HashMap interface { WriteTo(w io.Writer) (int64, error) // UnmarshalFrom deserializes a byte slice from a reader. UnmarshalFrom(r io.Reader, allocator malloc.Allocator) (int64, error) + // Get all (group, hashCode) pairs + AllGroupHash() []uint64 } // Iterator allows users to do insert or find operations on hash tables in bulk. diff --git a/pkg/container/batch/batch.go b/pkg/container/batch/batch.go index 819ef15116138..a790ec0931c5a 100644 --- a/pkg/container/batch/batch.go +++ b/pkg/container/batch/batch.go @@ -18,13 +18,13 @@ import ( "bytes" "context" "fmt" + "io" "github.com/matrixorigin/matrixone/pkg/common/bitmap" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" ) func New(attrs []string) *Batch { @@ -107,63 +107,16 @@ func (bat *Batch) Slice(from, to int) *Batch { } func (bat *Batch) MarshalBinary() ([]byte, error) { - // -------------------------------------------------------------------- - // | len | Zs... | len | Vecs... | len | Attrs... | len | AggInfos... | - // -------------------------------------------------------------------- var w bytes.Buffer + return bat.MarshalBinaryWithBuffer(&w, false) +} - // row count. - rl := int64(bat.rowCount) - w.Write(types.EncodeInt64(&rl)) - - // Vecs - l := int32(len(bat.Vecs)) - w.Write(types.EncodeInt32(&l)) - for i := 0; i < int(l); i++ { - data, err := bat.Vecs[i].MarshalBinary() - if err != nil { - return nil, err - } - size := int32(len(data)) - w.Write(types.EncodeInt32(&size)) - w.Write(data) - } - - // Attrs - l = int32(len(bat.Attrs)) - w.Write(types.EncodeInt32(&l)) - for i := 0; i < int(l); i++ { - size := int32(len(bat.Attrs[i])) - w.Write(types.EncodeInt32(&size)) - w.WriteString(bat.Attrs[i]) - } - - // AggInfos - aggInfos := make([][]byte, len(bat.Aggs)) - for i, exec := range bat.Aggs { - data, err := aggexec.MarshalAggFuncExec(exec) - if err != nil { - return nil, err - } - aggInfos[i] = data - } - - l = int32(len(aggInfos)) - w.Write(types.EncodeInt32(&l)) - for i := 0; i < int(l); i++ { - size := int32(len(aggInfos[i])) - w.Write(types.EncodeInt32(&size)) - w.Write(aggInfos[i]) +func (bat *Batch) MarshalBinaryWithBuffer(w *bytes.Buffer, reset bool) ([]byte, error) { + // reset the buffer if caller wants to. + if reset { + w.Reset() } - w.Write(types.EncodeInt32(&bat.Recursive)) - w.Write(types.EncodeInt32(&bat.ShuffleIDX)) - - return w.Bytes(), nil -} - -func (bat *Batch) MarshalBinaryWithBuffer(w *bytes.Buffer) ([]byte, error) { - w.Reset() // row count. rl := int64(bat.rowCount) w.Write(types.EncodeInt64(&rl)) @@ -196,23 +149,9 @@ func (bat *Batch) MarshalBinaryWithBuffer(w *bytes.Buffer) ([]byte, error) { } } - // AggInfos - aggInfos := make([][]byte, len(bat.Aggs)) - for i, exec := range bat.Aggs { - data, err := aggexec.MarshalAggFuncExec(exec) - if err != nil { - return nil, err - } - aggInfos[i] = data - } - - l = int32(len(aggInfos)) - w.Write(types.EncodeInt32(&l)) - for i := 0; i < int(l); i++ { - size := int32(len(aggInfos[i])) - w.Write(types.EncodeInt32(&size)) - w.Write(aggInfos[i]) - } + // ExtraBuf1 and ExtraBuf2 + types.WriteSizeBytes(bat.ExtraBuf1, w) + types.WriteSizeBytes(bat.ExtraBuf2, w) w.Write(types.EncodeInt32(&bat.Recursive)) w.Write(types.EncodeInt32(&bat.ShuffleIDX)) @@ -270,33 +209,92 @@ func (bat *Batch) UnmarshalBinaryWithAnyMp(data []byte, mp *mpool.MPool) (err er data = data[size:] } + // ExtraBuf1 l = types.DecodeInt32(data[:4]) - aggs := make([][]byte, l) + data = data[4:] + bat.ExtraBuf1 = nil + bat.ExtraBuf1 = append(bat.ExtraBuf1, data[:l]...) + data = data[l:] + // ExtraBuf2 + l = types.DecodeInt32(data[:4]) data = data[4:] - for i := 0; i < int(l); i++ { - size := types.DecodeInt32(data[:4]) - data = data[4:] - aggs[i] = data[:size] - data = data[size:] - } + bat.ExtraBuf2 = nil + bat.ExtraBuf2 = append(bat.ExtraBuf2, data[:l]...) + data = data[l:] bat.Recursive = types.DecodeInt32(data[:4]) data = data[4:] bat.ShuffleIDX = types.DecodeInt32(data[:4]) + return nil +} - if len(aggs) > 0 { - bat.Aggs = make([]aggexec.AggFuncExec, len(aggs)) - var aggMemoryManager aggexec.AggMemoryManager = nil - if mp != nil { - aggMemoryManager = aggexec.NewSimpleAggMemoryManager(mp) +func (bat *Batch) UnmarshalFromReader(r io.Reader, mp *mpool.MPool) (err error) { + i64, err := types.ReadInt64(r) + if err != nil { + return err + } + bat.rowCount = int(i64) + + l, err := types.ReadInt32AsInt(r) + if err != nil { + return err + } + if l != len(bat.Vecs) { + if len(bat.Vecs) > 0 { + bat.Clean(mp) } - for i, info := range aggs { - if bat.Aggs[i], err = aggexec.UnmarshalAggFuncExec(aggMemoryManager, info); err != nil { - return err + bat.Vecs = make([]*vector.Vector, l) + for i := range bat.Vecs { + if bat.offHeap { + bat.Vecs[i] = vector.NewOffHeapVec() + } else { + bat.Vecs[i] = vector.NewVecFromReuse() } } } + vecs := bat.Vecs + + for i := 0; i < l; i++ { + _, bs, err := types.ReadSizeBytes(r, nil, false) + if err != nil { + return err + } + if err := vecs[i].UnmarshalWithReader(bytes.NewReader(bs), mp); err != nil { + return err + } + } + + l, err = types.ReadInt32AsInt(r) + if err != nil { + return err + } + if l != len(bat.Attrs) { + bat.Attrs = make([]string, l) + } + + for i := 0; i < int(l); i++ { + _, bs, err := types.ReadSizeBytes(r, nil, false) + if err != nil { + return err + } + bat.Attrs[i] = string(bs) + } + + // ExtraBuf1 + if _, bat.ExtraBuf1, err = types.ReadSizeBytes(r, nil, false); err != nil { + return err + } + if _, bat.ExtraBuf2, err = types.ReadSizeBytes(r, nil, false); err != nil { + return err + } + + if bat.Recursive, err = types.ReadInt32(r); err != nil { + return err + } + if bat.ShuffleIDX, err = types.ReadInt32(r); err != nil { + return err + } return nil } @@ -460,14 +458,11 @@ func (bat *Batch) Clean(m *mpool.MPool) { vec.Free(m) } } - for _, agg := range bat.Aggs { - if agg != nil { - agg.Free() - } - } - bat.Aggs = nil + bat.Vecs = nil bat.Attrs = nil + bat.ExtraBuf1 = nil + bat.ExtraBuf2 = nil bat.SetRowCount(0) } @@ -662,7 +657,7 @@ func (bat *Batch) ReplaceVector(oldVec *vector.Vector, newVec *vector.Vector, st } func (bat *Batch) IsEmpty() bool { - return bat.rowCount == 0 && len(bat.Aggs) == 0 + return bat.rowCount == 0 } func (bat *Batch) IsDone() bool { diff --git a/pkg/container/batch/batch_test.go b/pkg/container/batch/batch_test.go index e1f9273293367..378f6064ff848 100644 --- a/pkg/container/batch/batch_test.go +++ b/pkg/container/batch/batch_test.go @@ -16,9 +16,10 @@ package batch import ( "bytes" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" "testing" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -53,6 +54,10 @@ func TestBatchMarshalAndUnmarshal(t *testing.T) { rbat := new(Batch) err = rbat.UnmarshalBinary(data) require.NoError(t, err) + + require.Equal(t, tc.bat.ExtraBuf1, rbat.ExtraBuf1) + require.Equal(t, tc.bat.ExtraBuf2, rbat.ExtraBuf2) + for i, vec := range rbat.Vecs { require.Equal(t, vector.MustFixedColWithTypeCheck[int8](tc.bat.Vecs[i]), vector.MustFixedColWithTypeCheck[int8](vec)) } @@ -60,7 +65,7 @@ func TestBatchMarshalAndUnmarshal(t *testing.T) { var buf bytes.Buffer for _, tc := range tcs { - data, err := tc.bat.MarshalBinaryWithBuffer(&buf) + data, err := tc.bat.MarshalBinaryWithBuffer(&buf, true) require.NoError(t, err) rbat := new(Batch) @@ -69,6 +74,14 @@ func TestBatchMarshalAndUnmarshal(t *testing.T) { for i, vec := range rbat.Vecs { require.Equal(t, vector.MustFixedColWithTypeCheck[int8](tc.bat.Vecs[i]), vector.MustFixedColWithTypeCheck[int8](vec)) } + + reader := bytes.NewReader(data) + rbat = new(Batch) + err = rbat.UnmarshalFromReader(reader, nil) + require.NoError(t, err) + for i, vec := range rbat.Vecs { + require.Equal(t, vector.MustFixedColWithTypeCheck[int8](tc.bat.Vecs[i]), vector.MustFixedColWithTypeCheck[int8](vec)) + } } } @@ -140,9 +153,10 @@ func newBatch(ts []types.Type, rows int) *Batch { } } + bat.ExtraBuf1 = []byte("extra buf 1") + bat.ExtraBuf2 = []byte("extra buf 2") + aggexec.RegisterGroupConcatAgg(0, ",") - agg0, _ := aggexec.MakeAgg(aggexec.NewSimpleAggMemoryManager(mp), 0, false, []types.Type{types.T_varchar.ToType()}...) - bat.Aggs = []aggexec.AggFuncExec{agg0} bat.Attrs = []string{"1"} return bat } diff --git a/pkg/container/batch/types.go b/pkg/container/batch/types.go index 9d4701e9f7e14..b6d18ff382b91 100644 --- a/pkg/container/batch/types.go +++ b/pkg/container/batch/types.go @@ -16,7 +16,6 @@ package batch import ( "github.com/matrixorigin/matrixone/pkg/container/vector" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" ) // special batch that will never been free. @@ -52,10 +51,10 @@ type Batch struct { // Vecs col data Vecs []*vector.Vector - Aggs []aggexec.AggFuncExec + ExtraBuf1 []byte + ExtraBuf2 []byte // row count of batch, to instead of old len(Zs). rowCount int - - offHeap bool + offHeap bool } diff --git a/pkg/container/hashtable/int64_hash_map.go b/pkg/container/hashtable/int64_hash_map.go index 6afd69f93e01e..abced8e6ca446 100644 --- a/pkg/container/hashtable/int64_hash_map.go +++ b/pkg/container/hashtable/int64_hash_map.go @@ -419,3 +419,15 @@ func (ht *Int64HashMap) UnmarshalFrom(r io.Reader, allocator malloc.Allocator) ( return } + +func (ht *Int64HashMap) AllGroupHash() []uint64 { + ret := make([]uint64, ht.elemCnt) + for i := range ht.cells { + for _, c := range ht.cells[i] { + if c.Mapped != 0 { + ret[c.Mapped-1] = c.Key + } + } + } + return ret +} diff --git a/pkg/container/hashtable/string_hash_map.go b/pkg/container/hashtable/string_hash_map.go index 2e97c7e92e0a6..fc9bf0c305940 100644 --- a/pkg/container/hashtable/string_hash_map.go +++ b/pkg/container/hashtable/string_hash_map.go @@ -61,11 +61,16 @@ func init() { } func (ht *StringHashMap) Free() { - for i, de := range ht.rawDataDeallocators { + for _, de := range ht.rawDataDeallocators { if de != nil { de.Deallocate(malloc.NoHints) } - ht.rawData[i], ht.cells[i] = nil, nil + } + for i := range ht.rawData { + ht.rawData[i] = nil + } + for i := range ht.cells { + ht.cells[i] = nil } ht.rawData, ht.cells = nil, nil } @@ -426,3 +431,15 @@ func (ht *StringHashMap) UnmarshalFrom(r io.Reader, allocator malloc.Allocator) return } + +func (ht *StringHashMap) AllGroupHash() []uint64 { + ret := make([]uint64, ht.elemCnt) + for i := range ht.cells { + for _, c := range ht.cells[i] { + if c.Mapped != 0 { + ret[c.Mapped-1] = c.HashState[0] + } + } + } + return ret +} diff --git a/pkg/container/pSpool/buffer.go b/pkg/container/pSpool/buffer.go index 1074d8370d6f5..8fed0b513a36d 100644 --- a/pkg/container/pSpool/buffer.go +++ b/pkg/container/pSpool/buffer.go @@ -15,10 +15,11 @@ package pSpool import ( + "sync" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/batch" "github.com/matrixorigin/matrixone/pkg/container/vector" - "sync" ) type spoolBuffer struct { @@ -77,12 +78,8 @@ func (b *spoolBuffer) putCacheID(mp *mpool.MPool, id uint32, bat *batch.Batch) { bat.Vecs = bat.Vecs[:0] bat.Attrs = bat.Attrs[:0] bat.SetRowCount(0) - - // we won't reuse the aggregation's memories now. - for i := range bat.Aggs { - bat.Aggs[i].Free() - } - bat.Aggs = nil + bat.ExtraBuf1 = nil + bat.ExtraBuf2 = nil // put id into free list. b.Lock() diff --git a/pkg/container/pSpool/copy.go b/pkg/container/pSpool/copy.go index 1095c2428bb29..5c6cb4cca20d8 100644 --- a/pkg/container/pSpool/copy.go +++ b/pkg/container/pSpool/copy.go @@ -15,10 +15,11 @@ package pSpool import ( + "math" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/batch" "github.com/matrixorigin/matrixone/pkg/container/vector" - "math" ) // cachedBatch is just like the cachedVectorPool in the original code, @@ -131,8 +132,10 @@ func (cb *cachedBatch) GetCopiedBatch( } } - dst.Aggs = src.Aggs - src.Aggs = nil + dst.ExtraBuf1 = src.ExtraBuf1 + src.ExtraBuf1 = nil + dst.ExtraBuf2 = src.ExtraBuf2 + src.ExtraBuf2 = nil // set row count. dst.SetRowCount(src.RowCount()) diff --git a/pkg/container/types/encoding.go b/pkg/container/types/encoding.go index ed1b01855f4f9..7b8ec9fc367e4 100644 --- a/pkg/container/types/encoding.go +++ b/pkg/container/types/encoding.go @@ -25,6 +25,7 @@ import ( "unsafe" "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/util" "github.com/matrixorigin/matrixone/pkg/container/bytejson" ) @@ -664,3 +665,119 @@ func Uint32ToInt32(ux uint32) int32 { } return x } + +func WriteSizeBytes(bs []byte, w io.Writer) error { + sz := int32(len(bs)) + if _, err := w.Write(EncodeInt32(&sz)); err != nil { + return err + } + if sz > 0 { + if _, err := w.Write(bs); err != nil { + return err + } + } + return nil +} + +func ReadInt64(r io.Reader) (int64, error) { + buf := make([]byte, 8) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return DecodeInt64(buf), nil +} + +func ReadUint64(r io.Reader) (uint64, error) { + buf := make([]byte, 8) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return DecodeUint64(buf), nil +} + +func WriteInt64(w io.Writer, v int64) error { + w.Write(EncodeInt64(&v)) + return nil +} + +func WriteUint64(w io.Writer, v uint64) error { + w.Write(EncodeUint64(&v)) + return nil +} + +func ReadBool(r io.Reader) (bool, error) { + buf := make([]byte, 1) + if _, err := io.ReadFull(r, buf); err != nil { + return false, err + } + return DecodeBool(buf), nil +} + +func ReadInt32(r io.Reader) (int32, error) { + buf := make([]byte, 4) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return DecodeInt32(buf), nil +} + +func WriteInt32(w io.Writer, v int32) error { + w.Write(EncodeInt32(&v)) + return nil +} + +func ReadInt32AsInt(r io.Reader) (int, error) { + buf := make([]byte, 4) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return int(DecodeInt32(buf)), nil +} + +func ReadByte(r io.Reader) (byte, error) { + buf := make([]byte, 1) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return buf[0], nil +} + +func ReadByteAsInt(r io.Reader) (int, error) { + buf := make([]byte, 1) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, err + } + return int(buf[0]), nil +} + +func ReadType(r io.Reader) (Type, error) { + buf := make([]byte, TSize) + if _, err := io.ReadFull(r, buf); err != nil { + return Type{}, err + } + return DecodeType(buf), nil +} + +func ReadSizeBytes(r io.Reader, mp *mpool.MPool, offHeap bool) (int32, []byte, error) { + sz, err := ReadInt32(r) + if err != nil { + return 0, nil, err + } + if sz > 0 { + var bs []byte + if mp != nil { + bs, err = mp.Alloc(int(sz), offHeap) + if err != nil { + return 0, nil, err + } + } else { + bs = make([]byte, sz) + } + + if _, err := io.ReadFull(r, bs); err != nil { + return 0, nil, err + } + return sz, bs, nil + } + return sz, nil, nil +} diff --git a/pkg/container/vector/vector.go b/pkg/container/vector/vector.go index 848fcaa5c0fa9..f6d50bbe26e5e 100644 --- a/pkg/container/vector/vector.go +++ b/pkg/container/vector/vector.go @@ -17,6 +17,7 @@ package vector import ( "bytes" "fmt" + "io" "slices" "sort" "time" @@ -821,6 +822,61 @@ func (v *Vector) UnmarshalBinaryWithCopy(data []byte, mp *mpool.MPool) error { return nil } +func (v *Vector) UnmarshalWithReader(r io.Reader, mp *mpool.MPool) error { + var err error + + if v.class, err = types.ReadByteAsInt(r); err != nil { + return err + } + + if v.typ, err = types.ReadType(r); err != nil { + return err + } + + if v.length, err = types.ReadInt32AsInt(r); err != nil { + return err + } + + // read data + dataLen, dataBuf, err := types.ReadSizeBytes(r, mp, v.offHeap) + if err != nil { + return err + } + if dataLen > 0 { + v.data = dataBuf + v.setupFromData() + } + + // read area + areaLen, areaBuf, err := types.ReadSizeBytes(r, mp, v.offHeap) + if err != nil { + return err + } + if areaLen > 0 { + v.area = areaBuf + } + + // read nsp, do not use mpool. nspBuf is different because + // it is not managed by vector. In the following, it will + // be unmarshalled into v.nsp + nspLen, nspBuf, err := types.ReadSizeBytes(r, nil, false) + if err != nil { + return err + } + if nspLen > 0 { + v.nsp.Read(nspBuf) + } else { + v.nsp.Reset() + } + + v.sorted, err = types.ReadBool(r) + if err != nil { + return err + } + + return nil +} + func (v *Vector) ToConst() { v.class = CONSTANT } diff --git a/pkg/fileservice/local_etl_fs.go b/pkg/fileservice/local_etl_fs.go index c6afd6951b55a..456541450f50b 100644 --- a/pkg/fileservice/local_etl_fs.go +++ b/pkg/fileservice/local_etl_fs.go @@ -790,3 +790,74 @@ func (l *LocalETLFSMutator) Close() error { return nil } + +// open for read and write, raw os.File API. +func (l *LocalETLFS) EnsureDir(ctx context.Context, filePath string) error { + return l.ensureDir(l.toNativeFilePath(filePath)) +} + +func (l *LocalETLFS) OpenFile(ctx context.Context, filePath string) (*os.File, error) { + err := ctx.Err() + if err != nil { + return nil, err + } + + path, err := ParsePathAtService(filePath, l.name) + if err != nil { + return nil, err + } + nativePath := l.toNativeFilePath(path.File) + return os.OpenFile(nativePath, os.O_RDWR, 0644) +} + +// create or truncate. +func (l *LocalETLFS) CreateFile(ctx context.Context, filePath string) (*os.File, error) { + err := ctx.Err() + if err != nil { + return nil, err + } + + path, err := ParsePathAtService(filePath, l.name) + if err != nil { + return nil, err + } + nativePath := l.toNativeFilePath(path.File) + return os.Create(nativePath) +} + +// remove file +func (l *LocalETLFS) RemoveFile(ctx context.Context, filePath string) error { + err := ctx.Err() + if err != nil { + return err + } + + path, err := ParsePathAtService(filePath, l.name) + if err != nil { + return err + } + nativePath := l.toNativeFilePath(path.File) + return os.Remove(nativePath) +} + +// open/create then immediately remove. the opend file is good for read/write. +func (l *LocalETLFS) CreateAndRemoveFile(ctx context.Context, filePath string) (*os.File, error) { + err := ctx.Err() + if err != nil { + return nil, err + } + + path, err := ParsePathAtService(filePath, l.name) + if err != nil { + return nil, err + } + nativePath := l.toNativeFilePath(path.File) + f, err := os.Create(nativePath) + if err != nil { + return nil, err + } + + // do not check error for this one + os.Remove(nativePath) + return f, nil +} diff --git a/pkg/fileservice/local_fs.go b/pkg/fileservice/local_fs.go index a746ba4344ab3..39615474f0b51 100644 --- a/pkg/fileservice/local_fs.go +++ b/pkg/fileservice/local_fs.go @@ -1221,7 +1221,11 @@ func entryIsDir(path string, name string, entry fs.FileInfo) (bool, error) { return false, nil } -// open for read and write +// open for read and write, raw os.File API. +func (l *LocalFS) EnsureDir(ctx context.Context, filePath string) error { + return l.ensureDir(l.toNativeFilePath(filePath)) +} + func (l *LocalFS) OpenFile(ctx context.Context, filePath string) (*os.File, error) { err := ctx.Err() if err != nil { diff --git a/pkg/fileservice/mutable_file_service.go b/pkg/fileservice/mutable_file_service.go index 5e7c1a90823b0..45e0d0849e3b0 100644 --- a/pkg/fileservice/mutable_file_service.go +++ b/pkg/fileservice/mutable_file_service.go @@ -14,7 +14,10 @@ package fileservice -import "context" +import ( + "context" + "os" +) // MutableFileService is an extension interface to FileService that allow mutation type MutableFileService interface { @@ -22,6 +25,13 @@ type MutableFileService interface { // NewMutator creates a new mutator NewMutator(ctx context.Context, filePath string) (Mutator, error) + + // Raw os.File API + EnsureDir(ctx context.Context, filePath string) error + OpenFile(ctx context.Context, filePath string) (*os.File, error) + CreateFile(ctx context.Context, filePath string) (*os.File, error) + RemoveFile(ctx context.Context, filePath string) error + CreateAndRemoveFile(ctx context.Context, filePath string) (*os.File, error) } type Mutator interface { diff --git a/pkg/fileservice/sub_path.go b/pkg/fileservice/sub_path.go index 1d4360d786eaa..30b159f2a2cc7 100644 --- a/pkg/fileservice/sub_path.go +++ b/pkg/fileservice/sub_path.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "iter" + "os" "path" "strings" ) @@ -145,6 +146,18 @@ func (s *subPathFS) Cost() *CostAttr { var _ MutableFileService = new(subPathFS) +func (s *subPathFS) EnsureDir(ctx context.Context, filePath string) error { + p, err := s.toUpstreamPath(filePath) + if err != nil { + return err + } + fs, ok := s.upstream.(MutableFileService) + if !ok { + panic(fmt.Sprintf("%T does not implement MutableFileService", s.upstream)) + } + return fs.EnsureDir(ctx, p) +} + func (s *subPathFS) NewMutator(ctx context.Context, filePath string) (Mutator, error) { p, err := s.toUpstreamPath(filePath) if err != nil { @@ -156,3 +169,59 @@ func (s *subPathFS) NewMutator(ctx context.Context, filePath string) (Mutator, e } return fs.NewMutator(ctx, p) } + +func (s *subPathFS) OpenFile(ctx context.Context, filePath string) (*os.File, error) { + p, err := s.toUpstreamPath(filePath) + if err != nil { + return nil, err + } + + fs, ok := s.upstream.(MutableFileService) + if !ok { + panic(fmt.Sprintf("%T does not implement MutableFileService", s.upstream)) + } + + return fs.OpenFile(ctx, p) +} + +func (s *subPathFS) CreateFile(ctx context.Context, filePath string) (*os.File, error) { + p, err := s.toUpstreamPath(filePath) + if err != nil { + return nil, err + } + + fs, ok := s.upstream.(MutableFileService) + if !ok { + panic(fmt.Sprintf("%T does not implement MutableFileService", s.upstream)) + } + + return fs.CreateFile(ctx, p) +} + +func (s *subPathFS) RemoveFile(ctx context.Context, filePath string) error { + p, err := s.toUpstreamPath(filePath) + if err != nil { + return err + } + + fs, ok := s.upstream.(MutableFileService) + if !ok { + panic(fmt.Sprintf("%T does not implement MutableFileService", s.upstream)) + } + + return fs.RemoveFile(ctx, p) +} + +func (s *subPathFS) CreateAndRemoveFile(ctx context.Context, filePath string) (*os.File, error) { + p, err := s.toUpstreamPath(filePath) + if err != nil { + return nil, err + } + + fs, ok := s.upstream.(MutableFileService) + if !ok { + panic(fmt.Sprintf("%T does not implement MutableFileService", s.upstream)) + } + + return fs.CreateAndRemoveFile(ctx, p) +} diff --git a/pkg/frontend/variables.go b/pkg/frontend/variables.go index 06004f49e1d08..07cf3a4ac52a7 100644 --- a/pkg/frontend/variables.go +++ b/pkg/frontend/variables.go @@ -3818,6 +3818,14 @@ var gSysVarsDefs = map[string]SystemVariable{ Type: InitSystemVariableIntType("agg_spill_mem", 0, common.TiB, false), Default: int64(common.GiB), }, + "max_dop": { + Name: "max_dop", + Scope: ScopeBoth, + Dynamic: true, + SetVarHintApplies: false, + Type: InitSystemVariableIntType("max_dop", 0, math.MaxInt32, false), + Default: int64(0), + }, } func updateTimeZone(ctx context.Context, sess *Session, sv *SystemVariables, name string, val interface{}) error { diff --git a/pkg/pb/plan/plan.pb.go b/pkg/pb/plan/plan.pb.go index ee4279fcb7320..bd3843f9020f1 100644 --- a/pkg/pb/plan/plan.pb.go +++ b/pkg/pb/plan/plan.pb.go @@ -2694,6 +2694,7 @@ func (m *Function) GetArgs() []*Expr { type Expr struct { Typ Type `protobuf:"bytes,1,opt,name=typ,proto3" json:"typ"` // Types that are valid to be assigned to Expr: + // // *Expr_Lit // *Expr_P // *Expr_V @@ -4602,6 +4603,7 @@ func (m *TableDef) GetFeatureFlag() uint64 { // XXX: Deprecated and to be removed soon. type TableDef_DefType struct { // Types that are valid to be assigned to Def: + // // *TableDef_DefType_Properties Def isTableDef_DefType_Def `protobuf_oneof:"def"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -4871,18 +4873,18 @@ func (m *HashMapStats) GetRanges() []float64 { } type Stats struct { - //for scan, number of blocks to read from S3 + // for scan, number of blocks to read from S3 BlockNum int32 `protobuf:"varint,1,opt,name=block_num,json=blockNum,proto3" json:"block_num,omitempty"` - //for scan, cost of reading from S3, basically the read lines - //for other nodes, it means the estimated cost of current node + // for scan, cost of reading from S3, basically the read lines + // for other nodes, it means the estimated cost of current node Cost float64 `protobuf:"fixed64,2,opt,name=cost,proto3" json:"cost,omitempty"` - //number of output lines + // number of output lines Outcnt float64 `protobuf:"fixed64,3,opt,name=outcnt,proto3" json:"outcnt,omitempty"` // average size of one row Rowsize float64 `protobuf:"fixed64,4,opt,name=rowsize,proto3" json:"rowsize,omitempty"` - //for scan, this means total count of all table, before filtering + // for scan, this means total count of all table, before filtering TableCnt float64 `protobuf:"fixed64,5,opt,name=table_cnt,json=tableCnt,proto3" json:"table_cnt,omitempty"` - //for scan, selectivity means outcnt divide total count + // for scan, selectivity means outcnt divide total count Selectivity float64 `protobuf:"fixed64,6,opt,name=selectivity,proto3" json:"selectivity,omitempty"` ForceOneCN bool `protobuf:"varint,7,opt,name=forceOneCN,proto3" json:"forceOneCN,omitempty"` Dop int32 `protobuf:"varint,8,opt,name=dop,proto3" json:"dop,omitempty"` @@ -6381,7 +6383,7 @@ type Node struct { OnUpdateExprs []*Expr `protobuf:"bytes,55,rep,name=onUpdateExprs,proto3" json:"onUpdateExprs,omitempty"` Fuzzymessage *OriginTableMessageForFuzzy `protobuf:"bytes,56,opt,name=fuzzymessage,proto3" json:"fuzzymessage,omitempty"` IfInsertFromUnique bool `protobuf:"varint,57,opt,name=ifInsertFromUnique,proto3" json:"ifInsertFromUnique,omitempty"` - //for message + // for message SendMsgList []MsgHeader `protobuf:"bytes,58,rep,name=send_msg_list,json=sendMsgList,proto3" json:"send_msg_list"` RecvMsgList []MsgHeader `protobuf:"bytes,59,rep,name=recv_msg_list,json=recvMsgList,proto3" json:"recv_msg_list"` DedupJoinCtx *DedupJoinCtx `protobuf:"bytes,60,opt,name=dedup_join_ctx,json=dedupJoinCtx,proto3" json:"dedup_join_ctx,omitempty"` @@ -8084,9 +8086,11 @@ type Query struct { LoadTag bool `protobuf:"varint,6,opt,name=loadTag,proto3" json:"loadTag,omitempty"` // load write S3 LoadWriteS3 bool `protobuf:"varint,7,opt,name=loadWriteS3,proto3" json:"loadWriteS3,omitempty"` - //detectSqls are sqls detect fk self refer constraint - DetectSqls []string `protobuf:"bytes,8,rep,name=detectSqls,proto3" json:"detectSqls,omitempty"` - BackgroundQueries []*Query `protobuf:"bytes,9,rep,name=background_queries,json=backgroundQueries,proto3" json:"background_queries,omitempty"` + // detectSqls are sqls detect fk self refer constraint + DetectSqls []string `protobuf:"bytes,8,rep,name=detectSqls,proto3" json:"detectSqls,omitempty"` + BackgroundQueries []*Query `protobuf:"bytes,9,rep,name=background_queries,json=backgroundQueries,proto3" json:"background_queries,omitempty"` + // run time config that can change query behaviors + MaxDop int64 `protobuf:"varint,10,opt,name=maxDop,proto3" json:"maxDop,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -8188,10 +8192,18 @@ func (m *Query) GetBackgroundQueries() []*Query { return nil } +func (m *Query) GetMaxDop() int64 { + if m != nil { + return m.MaxDop + } + return 0 +} + type TransationControl struct { - //TransationControl type + // TransationControl type TclType TransationControl_TclType `protobuf:"varint,1,opt,name=tcl_type,json=tclType,proto3,enum=plan.TransationControl_TclType" json:"tcl_type,omitempty"` // Types that are valid to be assigned to Action: + // // *TransationControl_Begin // *TransationControl_Commit // *TransationControl_Rollback @@ -8441,6 +8453,7 @@ func (m *TransationRollback) GetCompletionType() TransationCompletionType { type Plan struct { // Types that are valid to be assigned to Plan: + // // *Plan_Query // *Plan_Tcl // *Plan_Ddl @@ -8617,9 +8630,10 @@ func (m *Column) GetColumn() []*Expr { } type DataControl struct { - //DataDefinition type + // DataDefinition type DclType DataControl_DclType `protobuf:"varint,1,opt,name=dcl_type,json=dclType,proto3,enum=plan.DataControl_DclType" json:"dcl_type,omitempty"` // Types that are valid to be assigned to Control: + // // *DataControl_SetVariables // *DataControl_Prepare // *DataControl_Execute @@ -8753,13 +8767,14 @@ func (*DataControl) XXX_OneofWrappers() []interface{} { } type DataDefinition struct { - //DataDefinition type + // DataDefinition type DdlType DataDefinition_DdlType `protobuf:"varint,1,opt,name=ddl_type,json=ddlType,proto3,enum=plan.DataDefinition_DdlType" json:"ddl_type,omitempty"` - //other show statement we will rewrite to a select statement - //then we will get a Query - //eg: 'show databases' will rewrite to 'select md.datname as `Database` from mo_database md' + // other show statement we will rewrite to a select statement + // then we will get a Query + // eg: 'show databases' will rewrite to 'select md.datname as `Database` from mo_database md' Query *Query `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` // Types that are valid to be assigned to Definition: + // // *DataDefinition_CreateDatabase // *DataDefinition_AlterDatabase // *DataDefinition_DropDatabase @@ -10648,7 +10663,7 @@ type AlterTable struct { CreateTmpTableSql string `protobuf:"bytes,7,opt,name=create_tmp_table_sql,json=createTmpTableSql,proto3" json:"create_tmp_table_sql,omitempty"` InsertTmpDataSql string `protobuf:"bytes,8,opt,name=insert_tmp_data_sql,json=insertTmpDataSql,proto3" json:"insert_tmp_data_sql,omitempty"` ChangeTblColIdMap map[uint64]*ColDef `protobuf:"bytes,9,rep,name=change_tbl_colId_map,json=changeTblColIdMap,proto3" json:"change_tbl_colId_map,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - //detect fk self refer constraint + // detect fk self refer constraint DetectSqls []string `protobuf:"bytes,10,rep,name=detectSqls,proto3" json:"detectSqls,omitempty"` // alter table may insert fk records related to this table // into mo_foreign_keys @@ -10802,6 +10817,7 @@ func (m *AlterTable) GetAlterPartition() *AlterPartitionOption { type AlterTable_Action struct { // Types that are valid to be assigned to Action: + // // *AlterTable_Action_Drop // *AlterTable_Action_AddFk // *AlterTable_Action_AddIndex @@ -11031,7 +11047,7 @@ type DropTable struct { // drop table may delete fk records related to this table // into mo_foreign_keys UpdateFkSqls []string `protobuf:"bytes,11,rep,name=updateFkSqls,proto3" json:"updateFkSqls,omitempty"` - //fk child table id that refers to me + // fk child table id that refers to me FkChildTblsReferToMe []uint64 `protobuf:"varint,12,rep,packed,name=fkChildTblsReferToMe,proto3" json:"fkChildTblsReferToMe,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -13264,480 +13280,480 @@ func init() { func init() { proto.RegisterFile("plan.proto", fileDescriptor_2d655ab2f7683c23) } var fileDescriptor_2d655ab2f7683c23 = []byte{ - // 12678 bytes of a gzipped FileDescriptorProto + // 12690 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0xbd, 0x5d, 0x6c, 0x1b, 0x59, 0x96, 0x18, 0x2c, 0x8a, 0xff, 0x87, 0x14, 0x55, 0xba, 0x96, 0x6d, 0xfa, 0xa7, 0x6d, 0xb9, 0xec, 0x76, 0x7b, 0xdc, 0xdd, 0x76, 0xb7, 0xdd, 0x3f, 0xee, 0xd9, 0x99, 0x9d, 0xa6, 0x48, 0xca, 0x62, 0x9b, 0x22, 0x35, 0x45, 0xca, 0xee, 0x9e, 0xfd, 0x16, 0x85, 0x22, 0xab, 0x28, 0x55, 0xab, 0x58, 0xc5, 0xae, 0x2a, 0x5a, 0x52, 0x03, 0x8b, 0x6f, 0xf0, 0x7d, 0xc0, 0xfe, 0x24, 0x8f, 0xc1, 0x6e, - 0xf2, 0x90, 0x05, 0x26, 0x0b, 0x2c, 0x12, 0x04, 0x09, 0x90, 0x04, 0x1b, 0x6c, 0xf2, 0x9c, 0x87, - 0x6c, 0x12, 0x64, 0x11, 0x20, 0x40, 0x82, 0x24, 0xc0, 0x26, 0x98, 0x20, 0x8f, 0x41, 0x12, 0x24, - 0x4f, 0x79, 0x49, 0x70, 0xce, 0xbd, 0x55, 0xbc, 0x45, 0x52, 0x76, 0x77, 0xcf, 0x2c, 0x90, 0xbc, - 0x48, 0x75, 0xcf, 0xcf, 0xfd, 0xbf, 0xe7, 0x9e, 0x73, 0xee, 0xb9, 0x97, 0x00, 0x13, 0xc7, 0x70, - 0x1f, 0x4c, 0x7c, 0x2f, 0xf4, 0x58, 0x06, 0xbf, 0xaf, 0xbe, 0x7b, 0x68, 0x87, 0x47, 0xd3, 0xc1, - 0x83, 0xa1, 0x37, 0x7e, 0x78, 0xe8, 0x1d, 0x7a, 0x0f, 0x09, 0x39, 0x98, 0x8e, 0x28, 0x45, 0x09, - 0xfa, 0xe2, 0x4c, 0x57, 0xc1, 0xf1, 0x86, 0xc7, 0xe2, 0x7b, 0x3d, 0xb4, 0xc7, 0x56, 0x10, 0x1a, - 0xe3, 0x09, 0x07, 0xa8, 0x7f, 0x9c, 0x82, 0x4c, 0xff, 0x6c, 0x62, 0xb1, 0x0a, 0xac, 0xda, 0x66, - 0x35, 0xb5, 0x95, 0xba, 0x97, 0xd5, 0x56, 0x6d, 0x93, 0x6d, 0x41, 0xc9, 0xf5, 0xc2, 0xce, 0xd4, - 0x71, 0x8c, 0x81, 0x63, 0x55, 0x57, 0xb7, 0x52, 0xf7, 0x0a, 0x9a, 0x0c, 0x62, 0xd7, 0xa0, 0x68, - 0x4c, 0x43, 0x4f, 0xb7, 0xdd, 0xa1, 0x5f, 0x4d, 0x13, 0xbe, 0x80, 0x80, 0x96, 0x3b, 0xf4, 0xd9, - 0x26, 0x64, 0x4f, 0x6c, 0x33, 0x3c, 0xaa, 0x66, 0x28, 0x47, 0x9e, 0x40, 0x68, 0x30, 0x34, 0x1c, - 0xab, 0x9a, 0xe5, 0x50, 0x4a, 0x20, 0x34, 0xa4, 0x42, 0x72, 0x5b, 0xa9, 0x7b, 0x45, 0x8d, 0x27, - 0xd8, 0x0d, 0x00, 0xcb, 0x9d, 0x8e, 0x5f, 0x1a, 0xce, 0xd4, 0x0a, 0xaa, 0x79, 0x42, 0x49, 0x10, - 0xf5, 0x47, 0x50, 0x1c, 0x07, 0x87, 0xbb, 0x96, 0x61, 0x5a, 0x3e, 0xbb, 0x0c, 0xf9, 0x71, 0x70, - 0xa8, 0x87, 0xc6, 0xa1, 0x68, 0x42, 0x6e, 0x1c, 0x1c, 0xf6, 0x8d, 0x43, 0x76, 0x05, 0x0a, 0x84, - 0x38, 0x9b, 0xf0, 0x36, 0x64, 0x35, 0x24, 0xc4, 0x16, 0xab, 0xbf, 0x93, 0x83, 0x7c, 0xdb, 0x0e, - 0x2d, 0xdf, 0x70, 0xd8, 0x25, 0xc8, 0xd9, 0x81, 0x3b, 0x75, 0x1c, 0x62, 0x2f, 0x68, 0x22, 0xc5, - 0x2e, 0x41, 0xd6, 0x7e, 0xf2, 0xd2, 0x70, 0x38, 0xef, 0xee, 0x8a, 0xc6, 0x93, 0xac, 0x0a, 0x39, - 0xfb, 0xfd, 0x8f, 0x10, 0x91, 0x16, 0x08, 0x91, 0x26, 0xcc, 0xe3, 0x47, 0x88, 0xc9, 0xc4, 0x18, - 0x4a, 0x13, 0xe6, 0xa3, 0x0f, 0x10, 0x83, 0xad, 0x4f, 0x13, 0x86, 0xd2, 0x58, 0xca, 0x94, 0x4a, - 0xc1, 0x0e, 0x58, 0xc3, 0x52, 0xa6, 0x51, 0x29, 0x53, 0x5e, 0x4a, 0x5e, 0x20, 0x44, 0x9a, 0x30, - 0xbc, 0x94, 0x42, 0x8c, 0x89, 0x4b, 0x99, 0xf2, 0x52, 0x8a, 0x5b, 0xa9, 0x7b, 0x19, 0xc2, 0xf0, - 0x52, 0x36, 0x21, 0x63, 0x22, 0x1c, 0xb6, 0x52, 0xf7, 0x52, 0xbb, 0x2b, 0x1a, 0xa5, 0x10, 0x1a, - 0x20, 0xb4, 0x84, 0x1d, 0x8c, 0xd0, 0x40, 0x40, 0x07, 0x08, 0x2d, 0x63, 0x6f, 0x20, 0x74, 0x20, - 0xa0, 0x23, 0x84, 0xae, 0x6d, 0xa5, 0xee, 0xad, 0x22, 0x14, 0x53, 0xec, 0x2a, 0xe4, 0x4d, 0x23, - 0xb4, 0x10, 0x51, 0x11, 0x4d, 0x8e, 0x00, 0x88, 0xc3, 0x19, 0x87, 0xb8, 0x75, 0xd1, 0xe8, 0x08, - 0xc0, 0x54, 0x28, 0x21, 0x59, 0x84, 0x57, 0x04, 0x5e, 0x06, 0xb2, 0x0f, 0xa1, 0x6c, 0x5a, 0x43, - 0x7b, 0x6c, 0x38, 0xbc, 0x4d, 0x1b, 0x5b, 0xa9, 0x7b, 0xa5, 0x47, 0xeb, 0x0f, 0x68, 0x4d, 0xc4, - 0x98, 0xdd, 0x15, 0x2d, 0x41, 0xc6, 0x9e, 0xc0, 0x9a, 0x48, 0xbf, 0xff, 0x88, 0x3a, 0x96, 0x11, - 0x9f, 0x92, 0xe0, 0x7b, 0xff, 0xd1, 0x93, 0xdd, 0x15, 0x2d, 0x49, 0xc8, 0xee, 0x40, 0x39, 0x5e, - 0x22, 0xc8, 0x78, 0x41, 0xd4, 0x2a, 0x01, 0xc5, 0x66, 0x7d, 0x19, 0x78, 0x2e, 0x12, 0x6c, 0x8a, - 0x7e, 0x8b, 0x00, 0x6c, 0x0b, 0xc0, 0xb4, 0x46, 0xc6, 0xd4, 0x09, 0x11, 0x7d, 0x51, 0x74, 0xa0, - 0x04, 0x63, 0x37, 0xa0, 0x38, 0x9d, 0x60, 0x2b, 0x9f, 0x1b, 0x4e, 0xf5, 0x92, 0x20, 0x98, 0x81, - 0x30, 0x77, 0x9c, 0xe7, 0x88, 0xbd, 0x2c, 0x46, 0x37, 0x02, 0xe0, 0xf0, 0xbe, 0xb4, 0x86, 0x88, - 0xaa, 0x8a, 0x82, 0x45, 0x1a, 0x57, 0x91, 0x1d, 0x6c, 0xdb, 0x6e, 0xf5, 0x0a, 0xcd, 0x60, 0x9e, - 0x60, 0xd7, 0x21, 0x1d, 0xf8, 0xc3, 0xea, 0x55, 0x6a, 0x3f, 0xf0, 0xf6, 0x37, 0x4f, 0x27, 0xbe, - 0x86, 0xe0, 0xed, 0x3c, 0x64, 0x69, 0x35, 0xa9, 0xd7, 0xa1, 0xb0, 0x6f, 0xf8, 0xc6, 0x58, 0xb3, - 0x46, 0x4c, 0x81, 0xf4, 0xc4, 0x0b, 0xc4, 0x3a, 0xc2, 0x4f, 0xb5, 0x0d, 0xb9, 0xe7, 0x86, 0x8f, - 0x38, 0x06, 0x19, 0xd7, 0x18, 0x5b, 0x84, 0x2c, 0x6a, 0xf4, 0x8d, 0x6b, 0x27, 0x38, 0x0b, 0x42, - 0x6b, 0x2c, 0x84, 0x84, 0x48, 0x21, 0xfc, 0xd0, 0xf1, 0x06, 0x62, 0x8d, 0x14, 0x34, 0x91, 0x52, - 0xff, 0xbf, 0x14, 0xe4, 0xea, 0x9e, 0x83, 0xd9, 0x5d, 0x86, 0xbc, 0x6f, 0x39, 0xfa, 0xac, 0xb8, - 0x9c, 0x6f, 0x39, 0xfb, 0x5e, 0x80, 0x88, 0xa1, 0xc7, 0x11, 0x7c, 0xd5, 0xe6, 0x86, 0x1e, 0x21, - 0xa2, 0x0a, 0xa4, 0xa5, 0x0a, 0x5c, 0x81, 0x42, 0x38, 0x70, 0x74, 0x82, 0x67, 0x08, 0x9e, 0x0f, - 0x07, 0x4e, 0x07, 0x51, 0x97, 0x21, 0x6f, 0x0e, 0x38, 0x26, 0x4b, 0x98, 0x9c, 0x39, 0x40, 0x84, - 0xfa, 0x09, 0x14, 0x35, 0xe3, 0x44, 0x54, 0xe3, 0x22, 0xe4, 0x30, 0x03, 0x21, 0xff, 0x32, 0x5a, - 0x36, 0x1c, 0x38, 0x2d, 0x13, 0xc1, 0x58, 0x09, 0xdb, 0xa4, 0x3a, 0x64, 0xb4, 0xec, 0xd0, 0x73, - 0x5a, 0xa6, 0xda, 0x07, 0xa8, 0x7b, 0xbe, 0xff, 0x9d, 0x9b, 0xb0, 0x09, 0x59, 0xd3, 0x9a, 0x84, - 0x47, 0x5c, 0x74, 0x68, 0x3c, 0xa1, 0xde, 0x87, 0x02, 0x8e, 0x4b, 0xdb, 0x0e, 0x42, 0x76, 0x03, - 0x32, 0x8e, 0x1d, 0x84, 0xd5, 0xd4, 0x56, 0x7a, 0x6e, 0xd4, 0x08, 0xae, 0x6e, 0x41, 0x61, 0xcf, - 0x38, 0x7d, 0x8e, 0x23, 0x87, 0xb9, 0xd1, 0x10, 0x8a, 0x21, 0x11, 0xe3, 0x59, 0x06, 0xe8, 0x1b, - 0xfe, 0xa1, 0x15, 0x92, 0xa4, 0xfb, 0xef, 0x29, 0x28, 0xf5, 0xa6, 0x83, 0xaf, 0xa6, 0x96, 0x7f, - 0x86, 0x75, 0xbe, 0x07, 0xe9, 0xf0, 0x6c, 0x42, 0x1c, 0x95, 0x47, 0x97, 0x78, 0xf6, 0x12, 0xfe, - 0x01, 0x32, 0x69, 0x48, 0x82, 0x8d, 0x70, 0x3d, 0xd3, 0x8a, 0xfa, 0x20, 0xab, 0xe5, 0x30, 0xd9, - 0x32, 0x71, 0xbb, 0xf0, 0x26, 0x62, 0x14, 0x56, 0xbd, 0x09, 0xdb, 0x82, 0xec, 0xf0, 0xc8, 0x76, - 0x4c, 0x1a, 0x80, 0x64, 0x9d, 0x39, 0x02, 0x47, 0xc9, 0xf7, 0x4e, 0xf4, 0xc0, 0xfe, 0x3a, 0x12, - 0xff, 0x79, 0xdf, 0x3b, 0xe9, 0xd9, 0x5f, 0x5b, 0x6a, 0x5f, 0xec, 0x41, 0x00, 0xb9, 0x5e, 0xbd, - 0xd6, 0xae, 0x69, 0xca, 0x0a, 0x7e, 0x37, 0x3f, 0x6f, 0xf5, 0xfa, 0x3d, 0x25, 0xc5, 0x2a, 0x00, - 0x9d, 0x6e, 0x5f, 0x17, 0xe9, 0x55, 0x96, 0x83, 0xd5, 0x56, 0x47, 0x49, 0x23, 0x0d, 0xc2, 0x5b, - 0x1d, 0x25, 0xc3, 0xf2, 0x90, 0xae, 0x75, 0xbe, 0x50, 0xb2, 0xf4, 0xd1, 0x6e, 0x2b, 0x39, 0xf5, - 0x4f, 0x57, 0xa1, 0xd8, 0x1d, 0x7c, 0x69, 0x0d, 0x43, 0x6c, 0x33, 0xce, 0x52, 0xcb, 0x7f, 0x69, - 0xf9, 0xd4, 0xec, 0xb4, 0x26, 0x52, 0xd8, 0x10, 0x73, 0x40, 0x8d, 0x4b, 0x6b, 0xab, 0xe6, 0x80, - 0xe8, 0x86, 0x47, 0xd6, 0xd8, 0xa0, 0xc6, 0x21, 0x1d, 0xa5, 0x70, 0x55, 0x78, 0x83, 0x2f, 0xa9, - 0x79, 0x69, 0x0d, 0x3f, 0xd9, 0x4d, 0x28, 0xf1, 0x3c, 0xe4, 0xf9, 0x05, 0x1c, 0x34, 0x3f, 0xf9, - 0x72, 0xf2, 0xe4, 0x23, 0x4e, 0xca, 0x95, 0x23, 0xc5, 0xde, 0xc6, 0x41, 0x1d, 0x31, 0xa3, 0xbd, - 0xc1, 0x97, 0x1c, 0x5b, 0xe0, 0x33, 0xda, 0x1b, 0x7c, 0x49, 0xa8, 0xb7, 0x61, 0x23, 0x98, 0x0e, - 0x82, 0xa1, 0x6f, 0x4f, 0x42, 0xdb, 0x73, 0x39, 0x4d, 0x91, 0x68, 0x14, 0x19, 0x41, 0xc4, 0xf7, - 0xa0, 0x30, 0x99, 0x0e, 0x74, 0xdb, 0x1d, 0x79, 0x24, 0xf6, 0x4b, 0x8f, 0xd6, 0xf8, 0xc0, 0xec, - 0x4f, 0x07, 0x2d, 0x77, 0xe4, 0x69, 0xf9, 0x09, 0xff, 0x60, 0x2a, 0xac, 0xb9, 0x5e, 0xa8, 0xa3, - 0xaa, 0xa0, 0x8f, 0xad, 0xd0, 0xa0, 0xfd, 0x80, 0x6f, 0xf8, 0x6d, 0x6f, 0x78, 0xbc, 0x67, 0x85, - 0x86, 0x7a, 0x17, 0xf2, 0x82, 0x0f, 0xf7, 0xfe, 0xd0, 0x72, 0x0d, 0x37, 0xd4, 0x63, 0xa5, 0xa1, - 0xc0, 0x01, 0x2d, 0x53, 0xfd, 0xa3, 0x14, 0x28, 0x3d, 0xa9, 0x2a, 0xc8, 0xbc, 0x54, 0x72, 0xbc, - 0x01, 0x60, 0x0c, 0x87, 0xde, 0x94, 0x67, 0xc3, 0x27, 0x58, 0x51, 0x40, 0x5a, 0xa6, 0xdc, 0x7f, - 0xe9, 0x44, 0xff, 0xdd, 0x82, 0x72, 0xc4, 0x27, 0x2d, 0xfa, 0x92, 0x80, 0x45, 0x3d, 0x18, 0x4c, - 0x13, 0x2b, 0x3f, 0x1f, 0x4c, 0x39, 0xf7, 0x25, 0xc8, 0x91, 0x86, 0x11, 0x44, 0xa3, 0xc2, 0x53, - 0xea, 0xbf, 0x4e, 0xc1, 0x5a, 0xcb, 0x35, 0xad, 0xd3, 0xde, 0xd0, 0x70, 0xa3, 0x4e, 0xb1, 0x03, - 0xdd, 0x46, 0x98, 0x1e, 0x0c, 0x0d, 0x57, 0x28, 0x07, 0x25, 0x3b, 0x88, 0xe9, 0xb0, 0x0d, 0x9c, - 0x80, 0x8a, 0x5a, 0xa5, 0x1c, 0x8b, 0x04, 0xa1, 0xc2, 0xee, 0xc2, 0xfa, 0xc0, 0x72, 0x3c, 0xf7, - 0x50, 0x0f, 0x3d, 0x9d, 0x6b, 0x39, 0xbc, 0x2d, 0x6b, 0x1c, 0xdc, 0xf7, 0xfa, 0xa4, 0xed, 0x6c, - 0x42, 0x76, 0x62, 0xf8, 0x61, 0x50, 0xcd, 0x6c, 0xa5, 0x71, 0x19, 0x53, 0x02, 0xbb, 0xd9, 0x0e, - 0xf4, 0xa9, 0x6b, 0x7f, 0x35, 0xe5, 0xcd, 0x28, 0x68, 0x05, 0x3b, 0x38, 0xa0, 0x34, 0xbb, 0x07, - 0x0a, 0x2f, 0x99, 0xb2, 0x95, 0xe7, 0x59, 0x85, 0xe0, 0x94, 0x31, 0x09, 0xbb, 0xbf, 0xb0, 0x0a, - 0x85, 0x9d, 0xa9, 0x3b, 0xc4, 0xc1, 0x60, 0xb7, 0x21, 0x33, 0x9a, 0xba, 0x43, 0x6a, 0x4b, 0xbc, - 0x95, 0xc6, 0xeb, 0x44, 0x23, 0x24, 0x4a, 0x20, 0xc3, 0x3f, 0x44, 0xc9, 0xb5, 0x20, 0x81, 0x10, - 0xae, 0xfe, 0x83, 0x14, 0xcf, 0x71, 0xc7, 0x31, 0x0e, 0x59, 0x01, 0x32, 0x9d, 0x6e, 0xa7, 0xa9, - 0xac, 0xb0, 0x32, 0x14, 0x5a, 0x9d, 0x7e, 0x53, 0xeb, 0xd4, 0xda, 0x4a, 0x8a, 0x96, 0x73, 0xbf, - 0xb6, 0xdd, 0x6e, 0x2a, 0xab, 0x88, 0x79, 0xde, 0x6d, 0xd7, 0xfa, 0xad, 0x76, 0x53, 0xc9, 0x70, - 0x8c, 0xd6, 0xaa, 0xf7, 0x95, 0x02, 0x53, 0xa0, 0xbc, 0xaf, 0x75, 0x1b, 0x07, 0xf5, 0xa6, 0xde, - 0x39, 0x68, 0xb7, 0x15, 0x85, 0x5d, 0x80, 0xf5, 0x18, 0xd2, 0xe5, 0xc0, 0x2d, 0x64, 0x79, 0x5e, - 0xd3, 0x6a, 0xda, 0x53, 0xe5, 0x53, 0x56, 0x80, 0x74, 0xed, 0xe9, 0x53, 0xe5, 0xa7, 0x28, 0x19, - 0x8a, 0x2f, 0x5a, 0x1d, 0xfd, 0x79, 0xad, 0x7d, 0xd0, 0x54, 0x7e, 0xba, 0x1a, 0xa5, 0xbb, 0x5a, - 0xa3, 0xa9, 0x29, 0x3f, 0xcd, 0xb0, 0x0d, 0x28, 0xff, 0xa4, 0xdb, 0x69, 0xee, 0xd5, 0xf6, 0xf7, - 0xa9, 0x22, 0x3f, 0x2d, 0xa8, 0xff, 0x39, 0x03, 0x19, 0x6c, 0x09, 0x53, 0x67, 0x52, 0x30, 0x6e, - 0x22, 0x8a, 0xa1, 0xed, 0xcc, 0x9f, 0xfc, 0xd9, 0xcd, 0x15, 0x2e, 0xff, 0x6e, 0x41, 0xda, 0xb1, - 0x43, 0x1a, 0xd6, 0x78, 0xed, 0x08, 0x9d, 0x71, 0x77, 0x45, 0x43, 0x1c, 0xbb, 0x01, 0x29, 0x2e, - 0x08, 0x4b, 0x8f, 0x2a, 0x62, 0x71, 0x89, 0x9d, 0x74, 0x77, 0x45, 0x4b, 0x4d, 0xd8, 0x75, 0x48, - 0xbd, 0x14, 0x52, 0xb1, 0xcc, 0xf1, 0x7c, 0x2f, 0x45, 0xec, 0x4b, 0xb6, 0x05, 0xe9, 0xa1, 0xc7, - 0x35, 0xc2, 0x18, 0xcf, 0x77, 0x16, 0xcc, 0x7f, 0xe8, 0x39, 0xec, 0x36, 0xa4, 0x7d, 0xe3, 0x84, - 0x46, 0x36, 0x1e, 0xae, 0x78, 0xeb, 0x42, 0x22, 0xdf, 0x38, 0xc1, 0x4a, 0x8c, 0x48, 0x8e, 0xc4, - 0x95, 0x88, 0xc6, 0x1b, 0x8b, 0x19, 0xb1, 0x2d, 0x48, 0x9d, 0x90, 0x24, 0x89, 0x95, 0xa0, 0x17, - 0xb6, 0x6b, 0x7a, 0x27, 0xbd, 0x89, 0x35, 0x44, 0x8a, 0x13, 0xf6, 0x26, 0xa4, 0x83, 0xe9, 0x80, - 0x24, 0x49, 0xe9, 0xd1, 0xc6, 0xc2, 0x9e, 0x80, 0x05, 0x05, 0xd3, 0x01, 0xbb, 0x0b, 0x99, 0xa1, - 0xe7, 0xfb, 0x42, 0x9a, 0x28, 0x51, 0x85, 0xa3, 0xed, 0x10, 0x95, 0x42, 0xc4, 0x63, 0x81, 0x21, - 0xc9, 0x90, 0x98, 0x68, 0xb6, 0x1f, 0x61, 0x81, 0x21, 0xbb, 0x23, 0x36, 0xb9, 0xb2, 0x5c, 0xeb, - 0x68, 0x0b, 0xc4, 0x7c, 0x10, 0x8b, 0x83, 0x34, 0x36, 0x4e, 0x49, 0xe3, 0x8c, 0x89, 0xa2, 0xbd, - 0x0f, 0xeb, 0x34, 0x36, 0x4e, 0xd9, 0x1d, 0x48, 0xbf, 0xb4, 0x86, 0xa4, 0x7c, 0xc6, 0xa5, 0x89, - 0x41, 0x7a, 0x4e, 0xcd, 0x43, 0x34, 0xcd, 0x7b, 0xcf, 0x31, 0x49, 0x0f, 0x8d, 0xc7, 0x72, 0xc7, - 0x73, 0xcc, 0xe7, 0x34, 0x96, 0x84, 0xc4, 0x2d, 0xdf, 0x98, 0x9e, 0xa2, 0x34, 0x52, 0xf8, 0xe6, - 0x6c, 0x4c, 0x4f, 0x5b, 0x26, 0x0a, 0x7f, 0xd7, 0x7c, 0x49, 0xda, 0x67, 0x4a, 0xc3, 0x4f, 0x34, - 0x8f, 0x02, 0xcb, 0xb1, 0x86, 0xa1, 0xfd, 0xd2, 0x0e, 0xcf, 0x48, 0xbf, 0x4c, 0x69, 0x32, 0x68, - 0x3b, 0x07, 0x19, 0xeb, 0x74, 0xe2, 0xab, 0xbb, 0x90, 0x17, 0xa5, 0x2c, 0xd8, 0x58, 0x57, 0xa0, - 0x60, 0x07, 0xfa, 0xd0, 0x73, 0x83, 0x50, 0xe8, 0x4e, 0x79, 0x3b, 0xa8, 0x63, 0x12, 0xc5, 0xa5, - 0x69, 0x84, 0x7c, 0x13, 0x2a, 0x6b, 0xf4, 0xad, 0x3e, 0x02, 0x98, 0x35, 0x0b, 0xeb, 0xe4, 0x58, - 0x6e, 0xa4, 0xa6, 0x39, 0x96, 0x1b, 0xf3, 0xac, 0x4a, 0x3c, 0x57, 0xa0, 0x18, 0x6b, 0xc6, 0xac, - 0x0c, 0x29, 0x43, 0x6c, 0x7f, 0x29, 0x43, 0xbd, 0x87, 0x8a, 0x6a, 0xa4, 0xfb, 0x26, 0x71, 0x98, - 0x8a, 0x36, 0xc5, 0xd4, 0x40, 0xfd, 0x01, 0x94, 0x35, 0x2b, 0x98, 0x3a, 0x61, 0xdd, 0x73, 0x1a, - 0xd6, 0x88, 0xbd, 0x03, 0x10, 0xa7, 0x03, 0xa1, 0xa5, 0xcc, 0xe6, 0x6e, 0xc3, 0x1a, 0x69, 0x12, - 0x5e, 0xfd, 0x1b, 0x19, 0xd2, 0xf7, 0x1a, 0x5c, 0xd1, 0x12, 0x1a, 0x55, 0x4a, 0xd2, 0xa8, 0xe2, - 0xbd, 0x61, 0x35, 0xa9, 0x55, 0x1e, 0xd9, 0xa6, 0x69, 0xb9, 0x91, 0xf6, 0xc8, 0x53, 0x38, 0xd8, - 0x86, 0x73, 0x48, 0x0b, 0xaa, 0xf2, 0x88, 0x45, 0x85, 0x8e, 0x27, 0xbe, 0x15, 0x04, 0x5c, 0x6f, - 0x31, 0x9c, 0xc3, 0x68, 0x6d, 0x67, 0x5f, 0xb5, 0xb6, 0xaf, 0x40, 0x01, 0xb7, 0x3c, 0xb2, 0xfa, - 0x72, 0xbc, 0xf7, 0x85, 0x79, 0xcb, 0xde, 0x82, 0xbc, 0xd0, 0xd7, 0xc5, 0xa2, 0x12, 0xd3, 0xa5, - 0xc1, 0x81, 0x5a, 0x84, 0x65, 0x55, 0x54, 0xf2, 0xc6, 0x63, 0xcb, 0x0d, 0xa3, 0x7d, 0x5a, 0x24, - 0xd9, 0xdb, 0x50, 0xf4, 0x5c, 0x9d, 0x2b, 0xf5, 0x62, 0x55, 0x89, 0xe9, 0xdb, 0x75, 0x0f, 0x08, - 0xaa, 0x15, 0x3c, 0xf1, 0x85, 0x55, 0x71, 0xbc, 0x13, 0x7d, 0x68, 0xf8, 0x26, 0xad, 0xac, 0x82, - 0x96, 0x77, 0xbc, 0x93, 0xba, 0xe1, 0x9b, 0x5c, 0x6f, 0xf9, 0xca, 0x9d, 0x8e, 0x69, 0x35, 0xad, - 0x69, 0x22, 0xc5, 0xae, 0x43, 0x71, 0xe8, 0x4c, 0x83, 0xd0, 0xf2, 0xb7, 0xcf, 0xb8, 0x99, 0xa6, - 0xcd, 0x00, 0x58, 0xaf, 0x89, 0x6f, 0x8f, 0x0d, 0xff, 0x8c, 0x96, 0x4e, 0x41, 0x8b, 0x92, 0xb4, - 0xd1, 0x1c, 0xdb, 0xe6, 0x29, 0xb7, 0xd5, 0x34, 0x9e, 0x40, 0xfa, 0x23, 0xb2, 0xa4, 0x03, 0x5a, - 0x1f, 0x05, 0x2d, 0x4a, 0xd2, 0x38, 0xd0, 0x27, 0xad, 0x88, 0xa2, 0x26, 0x52, 0x09, 0xa5, 0x7b, - 0xe3, 0x5c, 0xa5, 0x9b, 0xcd, 0xeb, 0x3d, 0x9e, 0x6f, 0x1f, 0xda, 0x42, 0x6b, 0xb9, 0xc0, 0xf5, - 0x1e, 0x0e, 0xa2, 0x8d, 0xea, 0x2b, 0xc8, 0x8b, 0x2e, 0xc6, 0x1d, 0x08, 0x97, 0x4f, 0x52, 0x3c, - 0xf3, 0x1d, 0x08, 0xe1, 0xec, 0x36, 0xac, 0x89, 0xbc, 0x82, 0xd0, 0xb7, 0xdd, 0x43, 0x31, 0x79, - 0xca, 0x1c, 0xd8, 0x23, 0x18, 0x2a, 0x0a, 0x38, 0xbc, 0xba, 0x31, 0xb0, 0x1d, 0x5c, 0xa6, 0x69, - 0xa1, 0xd4, 0x4c, 0x1d, 0xa7, 0xc6, 0x41, 0x6a, 0x17, 0x0a, 0xd1, 0x80, 0xfc, 0x52, 0xca, 0x54, - 0x7f, 0x33, 0x05, 0x25, 0x52, 0x0f, 0xba, 0xa4, 0xfc, 0xb0, 0x77, 0x80, 0x0d, 0x7d, 0xcb, 0x08, - 0x2d, 0xdd, 0x3a, 0x0d, 0x7d, 0x43, 0x28, 0x01, 0x5c, 0x93, 0x50, 0x38, 0xa6, 0x89, 0x08, 0xae, - 0x07, 0xdc, 0x84, 0xd2, 0xc4, 0xf0, 0x83, 0x48, 0xa9, 0xe4, 0x05, 0x00, 0x07, 0x09, 0x95, 0x4e, - 0x71, 0x0f, 0x7d, 0x63, 0xac, 0x87, 0xde, 0xb1, 0xe5, 0x72, 0x75, 0x9a, 0x1b, 0x12, 0x15, 0x82, - 0xf7, 0x11, 0x4c, 0x5a, 0xf5, 0xbf, 0x4d, 0xc1, 0xda, 0x3e, 0x1f, 0xf5, 0x67, 0xd6, 0x59, 0x83, - 0x5b, 0x6f, 0xc3, 0x68, 0xc5, 0x66, 0x34, 0xfa, 0x66, 0x37, 0xa0, 0x34, 0x39, 0xb6, 0xce, 0xf4, - 0x84, 0xa5, 0x53, 0x44, 0x50, 0x9d, 0xd6, 0xe6, 0xf7, 0x20, 0xe7, 0x51, 0x43, 0xc4, 0x1e, 0x27, - 0xb6, 0x06, 0xa9, 0x85, 0x9a, 0x20, 0x40, 0x75, 0x29, 0xce, 0x4a, 0xd6, 0xcb, 0x44, 0x66, 0x54, - 0xfd, 0x4d, 0xc8, 0x22, 0x2a, 0xa8, 0x66, 0xb9, 0x9e, 0x43, 0x09, 0xf6, 0x1e, 0xac, 0x0d, 0xbd, - 0xf1, 0x44, 0x8f, 0xd8, 0xc5, 0x6e, 0x97, 0x94, 0x29, 0x25, 0x24, 0xd9, 0xe7, 0x79, 0xa9, 0xbf, - 0x97, 0x86, 0x02, 0xd5, 0x41, 0x88, 0x15, 0xdb, 0x3c, 0x8d, 0xc4, 0x4a, 0x51, 0xcb, 0xda, 0x26, - 0x4a, 0xed, 0xd7, 0xa8, 0x66, 0xb1, 0xca, 0x95, 0x96, 0x55, 0xae, 0x4b, 0x90, 0x13, 0xfa, 0x56, - 0x86, 0xcb, 0x9d, 0xe9, 0xf9, 0xda, 0x56, 0x76, 0x99, 0xb6, 0x85, 0x43, 0xc8, 0x69, 0xac, 0x53, - 0xdc, 0xdf, 0xb8, 0x68, 0x01, 0x02, 0x35, 0x11, 0x22, 0x0b, 0x8d, 0x7c, 0x52, 0x68, 0x54, 0x21, - 0xff, 0xd2, 0x0e, 0x6c, 0x9c, 0x20, 0x05, 0xbe, 0x0c, 0x45, 0x52, 0x1a, 0x86, 0xe2, 0xeb, 0x86, - 0x21, 0x6e, 0xb6, 0xe1, 0x1c, 0x72, 0xb5, 0x3f, 0x6a, 0x76, 0xcd, 0x39, 0xf4, 0xd8, 0xfb, 0x70, - 0x71, 0x86, 0x16, 0xad, 0x21, 0xf7, 0x18, 0x79, 0x80, 0x34, 0x16, 0x53, 0x52, 0x8b, 0xc8, 0x2e, - 0xbb, 0x0f, 0x1b, 0x12, 0xcb, 0x04, 0xd5, 0x9b, 0x80, 0x64, 0x4e, 0x51, 0x5b, 0x8f, 0xc9, 0x49, - 0xeb, 0x09, 0xd4, 0x7f, 0xb2, 0x0a, 0x6b, 0x3b, 0x9e, 0x6f, 0xd9, 0x87, 0xee, 0x6c, 0xd6, 0x2d, - 0x68, 0xfe, 0xd1, 0x4c, 0x5c, 0x95, 0x66, 0xe2, 0x4d, 0x28, 0x8d, 0x38, 0xa3, 0x1e, 0x0e, 0xb8, - 0xd3, 0x20, 0xa3, 0x81, 0x00, 0xf5, 0x07, 0x0e, 0xae, 0xe6, 0x88, 0x80, 0x98, 0x33, 0xc4, 0x1c, - 0x31, 0xe1, 0x5e, 0xc3, 0xbe, 0x4f, 0x52, 0xd7, 0xb4, 0x1c, 0x2b, 0xe4, 0xc3, 0x53, 0x79, 0xf4, - 0x46, 0xb4, 0xd3, 0x4b, 0x75, 0x7a, 0xa0, 0x59, 0xa3, 0x1a, 0xa9, 0x47, 0x28, 0x84, 0x1b, 0x44, - 0x2e, 0x78, 0x85, 0xc4, 0xce, 0x7d, 0x43, 0x5e, 0x2e, 0x39, 0xd4, 0x3e, 0x14, 0x63, 0x30, 0xea, - 0xba, 0x5a, 0x53, 0xe8, 0xb7, 0x2b, 0xac, 0x04, 0xf9, 0x7a, 0xad, 0x57, 0xaf, 0x35, 0x9a, 0x4a, - 0x0a, 0x51, 0xbd, 0x66, 0x9f, 0xeb, 0xb4, 0xab, 0x6c, 0x1d, 0x4a, 0x98, 0x6a, 0x34, 0x77, 0x6a, - 0x07, 0xed, 0xbe, 0x92, 0x66, 0x6b, 0x50, 0xec, 0x74, 0xf5, 0x5a, 0xbd, 0xdf, 0xea, 0x76, 0x94, - 0x8c, 0xfa, 0x29, 0x14, 0xea, 0x47, 0xd6, 0xf0, 0xf8, 0xbc, 0x5e, 0x24, 0xa3, 0xdb, 0x1a, 0x1e, - 0x0b, 0xfd, 0x74, 0xce, 0xe8, 0xb6, 0x86, 0xc7, 0x6a, 0x13, 0x8a, 0xfb, 0x86, 0x1f, 0xda, 0x54, - 0xaf, 0x27, 0xb0, 0x16, 0x27, 0x1a, 0xd6, 0x28, 0xda, 0xb9, 0x59, 0xac, 0xb5, 0xc6, 0x28, 0x2d, - 0x49, 0xa8, 0xbe, 0x03, 0x65, 0x19, 0xc0, 0xae, 0x43, 0xda, 0xb4, 0x46, 0x4b, 0xe4, 0x24, 0x82, - 0xd5, 0xe7, 0x50, 0xae, 0x47, 0x3b, 0xd1, 0x79, 0x55, 0x7f, 0x04, 0x15, 0x5a, 0xf1, 0xc3, 0x41, - 0xb4, 0xe4, 0x57, 0x97, 0x2c, 0xf9, 0x32, 0xd2, 0xd4, 0x07, 0x62, 0xcd, 0x7f, 0x08, 0xa5, 0x7d, - 0xdf, 0x9b, 0x58, 0x7e, 0x48, 0xd9, 0x2a, 0x90, 0x3e, 0xb6, 0xce, 0x44, 0xae, 0xf8, 0x39, 0xf3, - 0x85, 0xac, 0xca, 0xbe, 0x90, 0x47, 0x50, 0x88, 0xd8, 0xbe, 0x31, 0xcf, 0x8f, 0x50, 0x74, 0x12, - 0x8f, 0x6d, 0x05, 0x58, 0xd8, 0x03, 0x80, 0x49, 0x0c, 0x10, 0x1d, 0x17, 0xa9, 0xfb, 0x22, 0x73, - 0x4d, 0xa2, 0x50, 0xdf, 0x80, 0xfc, 0x73, 0xdb, 0x3a, 0x11, 0xcd, 0x7f, 0x69, 0x5b, 0x27, 0x51, - 0xf3, 0xf1, 0x5b, 0xfd, 0x8b, 0x45, 0x28, 0xd0, 0xfa, 0x6a, 0x9c, 0xef, 0x7e, 0xfa, 0x36, 0x5a, - 0xd1, 0x96, 0x58, 0x4f, 0x99, 0x25, 0xba, 0x18, 0x5f, 0x5d, 0x6f, 0x00, 0x48, 0x6b, 0x9d, 0x4b, - 0xae, 0x62, 0x18, 0x2f, 0x71, 0x54, 0x27, 0x68, 0x2f, 0x0a, 0xbe, 0x72, 0x84, 0x15, 0x39, 0x03, - 0xb0, 0x07, 0x7c, 0xb3, 0x27, 0xbb, 0x91, 0x2b, 0x44, 0x17, 0x22, 0xa5, 0x7e, 0xe0, 0x58, 0x91, - 0xa9, 0x41, 0x1a, 0x00, 0x26, 0x48, 0x8e, 0x59, 0x7e, 0x80, 0xe2, 0x8a, 0xfc, 0xd3, 0x5a, 0x94, - 0x64, 0x6f, 0x41, 0x06, 0x85, 0xbc, 0x30, 0x0d, 0x2e, 0x44, 0x3d, 0x28, 0xed, 0x52, 0x1a, 0x11, - 0xb0, 0x7b, 0x90, 0x27, 0xd1, 0x62, 0xa1, 0xa4, 0x91, 0x7a, 0x3b, 0x12, 0xfa, 0x5a, 0x84, 0x66, - 0xdf, 0x83, 0xec, 0xe8, 0xd8, 0x3a, 0x0b, 0xaa, 0x6b, 0x44, 0x77, 0x61, 0xc9, 0x9a, 0xd5, 0x38, - 0x05, 0xbb, 0x03, 0x15, 0xdf, 0x1a, 0xe9, 0xe4, 0x90, 0x42, 0x21, 0x13, 0x54, 0x2b, 0x24, 0x43, - 0xca, 0xbe, 0x35, 0xaa, 0x23, 0xb0, 0x3f, 0x70, 0x02, 0x76, 0x17, 0x72, 0xb4, 0x7a, 0x50, 0x17, - 0x92, 0x4a, 0x8e, 0x96, 0xa2, 0x26, 0xb0, 0xec, 0x7d, 0x00, 0xa1, 0x71, 0xe9, 0x83, 0x33, 0x72, - 0xe4, 0xc6, 0x8b, 0x49, 0x9e, 0xff, 0xb2, 0x5e, 0xf6, 0x16, 0x64, 0x71, 0x92, 0x04, 0xd5, 0xcb, - 0x94, 0xf3, 0x46, 0x72, 0x06, 0x51, 0x4d, 0x09, 0xcf, 0xee, 0x41, 0x01, 0x27, 0x8a, 0x8e, 0xc3, - 0x51, 0x95, 0x55, 0x50, 0x31, 0xab, 0x70, 0x67, 0xb0, 0x4e, 0x7a, 0x5f, 0x39, 0xec, 0x3e, 0x64, - 0x4c, 0x5c, 0xcc, 0x57, 0x28, 0xc7, 0x4b, 0xd2, 0xb8, 0xa0, 0xb0, 0x6a, 0x58, 0x23, 0xd2, 0x8a, - 0x89, 0x86, 0xed, 0x42, 0x05, 0xa7, 0xd1, 0x23, 0xda, 0xec, 0xb1, 0xfb, 0xaa, 0x57, 0x89, 0xeb, - 0xd6, 0x1c, 0x57, 0x47, 0x10, 0x51, 0x67, 0x37, 0xdd, 0xd0, 0x3f, 0xd3, 0xd6, 0x5c, 0x19, 0xc6, - 0xae, 0xa2, 0xe9, 0xd2, 0xf6, 0x86, 0xc7, 0x96, 0x59, 0xbd, 0x16, 0x39, 0x26, 0x78, 0x9a, 0x7d, - 0x02, 0x6b, 0x34, 0xb1, 0x30, 0x89, 0x85, 0x57, 0xaf, 0x93, 0x30, 0x95, 0xa7, 0x4c, 0x84, 0xd2, - 0x92, 0x94, 0x28, 0xe2, 0xed, 0x40, 0x0f, 0xad, 0xf1, 0xc4, 0xf3, 0x51, 0x79, 0x7d, 0x23, 0x72, - 0xb8, 0xf4, 0x23, 0x10, 0x6e, 0xc4, 0xf1, 0xb1, 0x93, 0xee, 0x8d, 0x46, 0x81, 0x15, 0x56, 0x6f, - 0xd0, 0xba, 0xa9, 0x44, 0xa7, 0x4f, 0x5d, 0x82, 0xd2, 0x46, 0x18, 0xe8, 0xe6, 0x99, 0x6b, 0x8c, - 0xed, 0x61, 0xf5, 0x26, 0xd7, 0x91, 0xed, 0xa0, 0xc1, 0x01, 0xb2, 0x9a, 0xba, 0x95, 0x50, 0x53, - 0x2f, 0x40, 0xd6, 0x1c, 0xe0, 0x72, 0xbc, 0x45, 0xd9, 0x66, 0xcc, 0x41, 0xcb, 0x64, 0xef, 0x42, - 0x71, 0x12, 0x89, 0xc0, 0xaa, 0x2a, 0x1b, 0xe3, 0xb1, 0x64, 0xd4, 0x66, 0x14, 0x68, 0x1f, 0xee, - 0x58, 0x46, 0x38, 0xf5, 0xad, 0x1d, 0xc7, 0x38, 0xac, 0xde, 0xa6, 0x9c, 0x64, 0xd0, 0xd5, 0xa7, - 0xa4, 0xeb, 0x52, 0xab, 0x3f, 0x9c, 0x13, 0x2e, 0x89, 0xa5, 0x21, 0x49, 0xa1, 0xdd, 0x15, 0x59, - 0xc6, 0x6c, 0x67, 0x49, 0x0a, 0x5f, 0xfd, 0x14, 0xd8, 0xe2, 0x78, 0xbd, 0x4e, 0xd2, 0x65, 0x85, - 0xa4, 0xfb, 0xfe, 0xea, 0x93, 0x94, 0xfa, 0x1c, 0xd6, 0x12, 0x0b, 0x79, 0xa9, 0xc4, 0xe6, 0xea, - 0x92, 0x31, 0x16, 0xe6, 0x25, 0x4f, 0x08, 0x0f, 0x55, 0x60, 0xbb, 0x87, 0xc2, 0xb3, 0x45, 0x13, - 0xa1, 0x47, 0x69, 0xf5, 0x4f, 0xd3, 0x50, 0xde, 0x35, 0x82, 0xa3, 0x3d, 0x63, 0xd2, 0x0b, 0x8d, - 0x30, 0xc0, 0xe1, 0x3d, 0x32, 0x82, 0xa3, 0xb1, 0x31, 0xe1, 0x8a, 0x6b, 0x8a, 0x9b, 0xcd, 0x02, - 0x86, 0x5a, 0x2b, 0x4e, 0x2c, 0x4c, 0x76, 0xdd, 0xfd, 0x67, 0xc2, 0x26, 0x8e, 0xd3, 0x28, 0x56, - 0x82, 0xa3, 0xe9, 0x68, 0x14, 0x17, 0x15, 0x25, 0xd9, 0x1d, 0x58, 0x13, 0x9f, 0xa4, 0xb5, 0x9e, - 0x8a, 0x63, 0xc7, 0x24, 0x90, 0x3d, 0x86, 0x92, 0x00, 0xf4, 0x23, 0x21, 0x58, 0x89, 0x7d, 0x1d, - 0x33, 0x84, 0x26, 0x53, 0xb1, 0x1f, 0xc3, 0x45, 0x29, 0xb9, 0xe3, 0xf9, 0x7b, 0x53, 0x27, 0xb4, - 0xeb, 0x1d, 0xa1, 0x22, 0x5c, 0x5b, 0x60, 0x9f, 0x91, 0x68, 0xcb, 0x39, 0x93, 0xb5, 0xdd, 0xb3, - 0x5d, 0x92, 0xa9, 0x69, 0x2d, 0x09, 0x9c, 0xa3, 0x32, 0x4e, 0x49, 0x94, 0x26, 0xa9, 0x8c, 0x53, - 0x5c, 0x6c, 0x02, 0xb0, 0x67, 0x85, 0x47, 0x9e, 0x49, 0xfa, 0x61, 0xbc, 0xd8, 0x7a, 0x32, 0x4a, - 0x4b, 0x52, 0x62, 0x77, 0xa2, 0x25, 0x34, 0x74, 0x43, 0xd2, 0x12, 0xd3, 0x5a, 0x94, 0xc4, 0x6d, - 0xc6, 0x37, 0xdc, 0x43, 0x2b, 0xa8, 0x96, 0xb6, 0xd2, 0xf7, 0x52, 0x9a, 0x48, 0xa9, 0x7f, 0xb8, - 0x0a, 0x59, 0x3e, 0x92, 0xd7, 0xa0, 0x38, 0x20, 0x67, 0x31, 0x5a, 0xa6, 0xc2, 0x01, 0x4c, 0x80, - 0xce, 0x74, 0xcc, 0xb5, 0x3b, 0xe1, 0xd3, 0x48, 0x69, 0xf4, 0x8d, 0x59, 0x7a, 0xd3, 0x10, 0xcb, - 0x4a, 0x13, 0x54, 0xa4, 0xb0, 0x12, 0xbe, 0x77, 0x42, 0xb3, 0x21, 0x43, 0x88, 0x28, 0x49, 0x3e, - 0x66, 0xda, 0xb1, 0x90, 0x29, 0x4b, 0xb8, 0x02, 0x01, 0xea, 0x6e, 0x38, 0xef, 0x7f, 0xc9, 0x2d, - 0xf8, 0x5f, 0xd8, 0x0d, 0x40, 0xdd, 0x71, 0x68, 0x75, 0x5d, 0xab, 0xde, 0xa1, 0x1e, 0x2e, 0x68, - 0x12, 0x04, 0x17, 0x88, 0xe9, 0x4d, 0xa8, 0x53, 0xb3, 0x1a, 0x7e, 0xb2, 0x8f, 0xe2, 0xd9, 0x49, - 0x6d, 0x14, 0x9a, 0xb6, 0x90, 0xe8, 0xf2, 0x3c, 0xd6, 0x12, 0x74, 0x98, 0x13, 0x8a, 0x69, 0xae, - 0x69, 0xe3, 0xa7, 0xda, 0x04, 0xd0, 0xbc, 0x93, 0xc0, 0x0a, 0xc9, 0xd1, 0x78, 0x99, 0x9a, 0x98, - 0x38, 0x22, 0xf2, 0x4e, 0xf6, 0xbd, 0x20, 0xb6, 0x37, 0x57, 0x97, 0xdb, 0x9b, 0xea, 0x43, 0xc8, - 0xe3, 0x1e, 0x6e, 0x84, 0x06, 0xbb, 0x23, 0x7c, 0x3b, 0x5c, 0xf3, 0x10, 0x4e, 0xae, 0x59, 0x19, - 0xc2, 0xdb, 0xd3, 0x8e, 0xca, 0x25, 0x9e, 0x5b, 0x92, 0xb9, 0x17, 0xef, 0x1f, 0x22, 0x43, 0xa1, - 0x15, 0x5c, 0x83, 0x22, 0x56, 0x8d, 0xfc, 0xe6, 0x42, 0x2e, 0x14, 0x7c, 0xef, 0xa4, 0x8e, 0x69, - 0xf5, 0xdf, 0xa5, 0xa0, 0xd4, 0xf5, 0x4d, 0xdc, 0xb8, 0x7a, 0x13, 0x6b, 0xf8, 0x5a, 0xf3, 0x18, - 0x75, 0x08, 0xcf, 0x71, 0x0c, 0x12, 0x91, 0xc2, 0xdc, 0x8a, 0x01, 0xec, 0x7d, 0xc8, 0x8c, 0x50, - 0x14, 0xa6, 0x65, 0xcd, 0x5a, 0xca, 0x3e, 0xfa, 0x46, 0xe1, 0xa8, 0x11, 0xa9, 0xfa, 0x6b, 0x71, - 0xf9, 0xe4, 0x67, 0x96, 0xbd, 0xcb, 0x2b, 0x74, 0xce, 0xd3, 0xab, 0x2b, 0x29, 0x56, 0x80, 0x4c, - 0xa3, 0xd9, 0xab, 0x73, 0x7d, 0x1a, 0x35, 0xeb, 0x9e, 0xbe, 0xd3, 0xd2, 0x7a, 0x7d, 0x25, 0x43, - 0x07, 0x47, 0x04, 0x68, 0xd7, 0x7a, 0x7d, 0xa5, 0xc0, 0x00, 0x72, 0x07, 0x9d, 0xd6, 0x8f, 0x0f, - 0x9a, 0x8a, 0xa2, 0xfe, 0xcb, 0x14, 0xc0, 0xcc, 0x09, 0xca, 0xde, 0x86, 0xd2, 0x09, 0xa5, 0x74, - 0xc9, 0x3b, 0x2e, 0xb7, 0x11, 0x38, 0x9a, 0xf4, 0x9b, 0x77, 0xa1, 0x1c, 0x8b, 0x7a, 0xdc, 0xfb, - 0x17, 0xdd, 0xe4, 0xa5, 0x18, 0xbf, 0x7d, 0xc6, 0xde, 0x81, 0x82, 0x87, 0xed, 0x40, 0xd2, 0xb4, - 0xbc, 0xf1, 0x4b, 0xcd, 0xd7, 0xf2, 0x1e, 0x4f, 0xa0, 0x8e, 0x30, 0xf2, 0x23, 0xf3, 0x39, 0x26, - 0xdd, 0x41, 0x50, 0xdd, 0x31, 0xa6, 0x81, 0xa5, 0x71, 0x7c, 0x2c, 0xa5, 0xb3, 0x33, 0x29, 0xad, - 0xfe, 0x04, 0x2a, 0x3d, 0x63, 0x3c, 0xe1, 0xb2, 0x9c, 0x1a, 0xc6, 0x20, 0x83, 0x73, 0x42, 0x4c, - 0x3d, 0xfa, 0xc6, 0x45, 0xb7, 0x6f, 0xf9, 0x43, 0xcb, 0x8d, 0xd6, 0x68, 0x94, 0x44, 0xf1, 0x7b, - 0x80, 0xd2, 0x5c, 0xf3, 0x4e, 0x22, 0x71, 0x1e, 0xa5, 0xd5, 0xbf, 0x95, 0x82, 0x92, 0x54, 0x0d, - 0xf6, 0x10, 0x32, 0xa4, 0x4c, 0xa6, 0x64, 0x41, 0x28, 0x11, 0xf0, 0x6f, 0xae, 0x7e, 0x20, 0x21, - 0xbb, 0x0b, 0xd9, 0x20, 0x34, 0xfc, 0xc8, 0x9f, 0xae, 0x48, 0x1c, 0xdb, 0xde, 0xd4, 0x35, 0x35, - 0x8e, 0x66, 0x2a, 0xa4, 0x2d, 0xd7, 0x14, 0x0e, 0x87, 0x45, 0x2a, 0x44, 0xaa, 0x5b, 0x50, 0x8c, - 0xb3, 0xc7, 0x29, 0xa0, 0x75, 0x5f, 0xf4, 0x94, 0x15, 0x56, 0x84, 0xac, 0x56, 0xeb, 0x3c, 0x6d, - 0x2a, 0x29, 0xf5, 0x8f, 0x52, 0x00, 0x33, 0x2e, 0xf6, 0x20, 0x51, 0xdb, 0xab, 0xf3, 0xb9, 0x3e, - 0xa0, 0xbf, 0x52, 0x65, 0xaf, 0x43, 0x71, 0xea, 0x12, 0xd0, 0x32, 0xc5, 0x4e, 0x34, 0x03, 0xa0, - 0x05, 0x14, 0x45, 0x7f, 0xcc, 0x59, 0x40, 0x2f, 0x0d, 0x47, 0xfd, 0x3e, 0x14, 0xe3, 0xec, 0xd0, - 0xa8, 0xdb, 0xe9, 0xb6, 0xdb, 0xdd, 0x17, 0xad, 0xce, 0x53, 0x65, 0x05, 0x93, 0xfb, 0x5a, 0xb3, - 0xde, 0x6c, 0x60, 0x32, 0x85, 0x73, 0xb6, 0x7e, 0xa0, 0x69, 0xcd, 0x4e, 0x5f, 0xd7, 0xba, 0x2f, - 0x94, 0x55, 0xf5, 0xff, 0xcf, 0xc0, 0x46, 0xd7, 0x6d, 0x4c, 0x27, 0x8e, 0x3d, 0x34, 0x42, 0xeb, - 0x99, 0x75, 0x56, 0x0f, 0x4f, 0x71, 0xf7, 0x35, 0xc2, 0xd0, 0xe7, 0x8b, 0xb9, 0xa8, 0xf1, 0x04, - 0x77, 0x4a, 0x04, 0x96, 0x1f, 0x92, 0xcf, 0x45, 0x5e, 0xc5, 0x15, 0x0e, 0xaf, 0x7b, 0x0e, 0xad, - 0x65, 0xf6, 0x43, 0xb8, 0xc8, 0x1d, 0x19, 0x9c, 0x12, 0x15, 0x58, 0x9d, 0x16, 0x73, 0x7a, 0x61, - 0xea, 0x32, 0x4e, 0x88, 0xac, 0x48, 0x46, 0x22, 0xec, 0x26, 0x94, 0x66, 0xec, 0xd1, 0x21, 0x15, - 0xc4, 0x84, 0x54, 0x13, 0x34, 0xbc, 0xa3, 0x5a, 0xeb, 0xb6, 0x79, 0x4a, 0x2e, 0x9e, 0xac, 0x56, - 0xf1, 0x66, 0x8d, 0xc1, 0x4d, 0xf8, 0x73, 0xd8, 0x48, 0x50, 0x52, 0x2d, 0x72, 0x54, 0x8b, 0x77, - 0x22, 0x07, 0xe9, 0x5c, 0xeb, 0x65, 0x08, 0x56, 0x87, 0x6b, 0xa4, 0xeb, 0x5e, 0x12, 0x2a, 0x74, - 0x11, 0xfb, 0xd0, 0xf5, 0x7c, 0x4b, 0x08, 0xfc, 0x82, 0x1d, 0xb4, 0x28, 0x3d, 0xb3, 0x7f, 0xa4, - 0x43, 0x55, 0xbe, 0xbf, 0x44, 0xe7, 0x85, 0x1c, 0x6d, 0xf3, 0x1d, 0x34, 0xa3, 0xe5, 0x29, 0xdd, - 0x32, 0xd9, 0x6d, 0xa1, 0xce, 0xea, 0x91, 0x49, 0x03, 0x64, 0xd2, 0x94, 0x09, 0xf8, 0x9c, 0xc3, - 0xae, 0x76, 0x60, 0x73, 0x59, 0x25, 0x97, 0xa8, 0x61, 0x5b, 0xb2, 0x1a, 0x36, 0x67, 0xb4, 0xcf, - 0x54, 0xb2, 0xbf, 0x93, 0x82, 0x72, 0xc3, 0x32, 0xa7, 0x93, 0xcf, 0x3c, 0xdb, 0xc5, 0x09, 0xf0, - 0x01, 0x94, 0x3d, 0xc7, 0xa4, 0xd1, 0x93, 0x62, 0x03, 0x12, 0x27, 0x46, 0xc2, 0xb9, 0x0d, 0x9e, - 0x63, 0xd6, 0x3d, 0x87, 0x22, 0x09, 0xde, 0x85, 0x0b, 0xdc, 0xa1, 0x21, 0xfc, 0x7b, 0xa7, 0x9c, - 0x79, 0x95, 0x46, 0x46, 0xe1, 0x28, 0xae, 0x1c, 0x11, 0xf9, 0xaf, 0xc0, 0xa6, 0x44, 0x8e, 0x23, - 0xc3, 0xe9, 0x17, 0x27, 0xc9, 0x46, 0xcc, 0x1b, 0x1d, 0xd9, 0xa8, 0xbf, 0xb5, 0x0a, 0x45, 0xee, - 0x0e, 0xc1, 0xfa, 0xde, 0x83, 0xbc, 0x37, 0xf8, 0x52, 0xf7, 0x63, 0x37, 0xc1, 0xc2, 0x49, 0x63, - 0xce, 0x1b, 0x7c, 0xa9, 0x59, 0x23, 0xf6, 0x76, 0xb4, 0xcf, 0x9b, 0xd6, 0x48, 0x74, 0x4a, 0x25, - 0x69, 0x8f, 0x88, 0x7d, 0x1f, 0x6d, 0xe5, 0xc7, 0x50, 0x9a, 0xcd, 0xf8, 0xa0, 0x9a, 0x3f, 0xbf, - 0x17, 0xe2, 0x05, 0x10, 0x20, 0x13, 0x77, 0x09, 0x71, 0xa6, 0xc2, 0xf9, 0x4c, 0x9c, 0x8c, 0x98, - 0x3e, 0x81, 0xca, 0x4c, 0xc6, 0x13, 0x5f, 0xf1, 0x5c, 0xbe, 0xb5, 0x98, 0x92, 0x4e, 0x3c, 0xfe, - 0x6e, 0x0a, 0x8a, 0x2d, 0x5e, 0x7c, 0x78, 0xca, 0x6e, 0x41, 0xfa, 0x15, 0xbd, 0x80, 0x38, 0x76, - 0x1f, 0x36, 0x0c, 0xd3, 0xd4, 0x8d, 0xd1, 0xc8, 0x1a, 0x86, 0x96, 0xa9, 0xa3, 0x0a, 0x24, 0x64, - 0xce, 0xba, 0x61, 0x9a, 0x35, 0x01, 0x27, 0xd9, 0x8d, 0x6b, 0x3e, 0xd0, 0x23, 0xc3, 0x73, 0x76, - 0xa4, 0x5c, 0xd0, 0x2a, 0x76, 0x20, 0xec, 0x4e, 0xee, 0x4b, 0x4e, 0x74, 0x6c, 0xe6, 0xd5, 0x1d, - 0xab, 0xfe, 0xee, 0x2a, 0x80, 0x66, 0x4d, 0x1c, 0x63, 0x68, 0xfd, 0x5f, 0x53, 0x69, 0x14, 0x4b, - 0xf1, 0xc0, 0xba, 0x66, 0x14, 0x82, 0x11, 0x0d, 0xa2, 0x6b, 0xb2, 0x4f, 0xe1, 0x0d, 0xdf, 0x3a, - 0xf1, 0xed, 0xd0, 0xd2, 0x47, 0xbe, 0x37, 0xd6, 0x13, 0x92, 0x07, 0x17, 0x66, 0x91, 0x2a, 0x71, - 0x45, 0x10, 0xed, 0xf8, 0xde, 0x38, 0x29, 0x7d, 0xd4, 0x7f, 0x0c, 0x50, 0xaa, 0xb9, 0x86, 0x73, - 0xf6, 0xb5, 0x45, 0x31, 0x01, 0xe4, 0x5d, 0x9d, 0x4c, 0x43, 0xde, 0x5c, 0x7e, 0x60, 0x56, 0x24, - 0x08, 0x35, 0xf4, 0x26, 0x94, 0xbc, 0x69, 0x18, 0xe3, 0xf9, 0x11, 0x1a, 0x70, 0x10, 0x11, 0xc4, - 0xfc, 0xb1, 0xe7, 0x3e, 0xe2, 0x27, 0xf3, 0x67, 0xc6, 0x1f, 0xab, 0xc4, 0x31, 0x3f, 0x11, 0xa0, - 0x34, 0xb2, 0xc7, 0xd4, 0xe0, 0x60, 0x3a, 0xb6, 0x78, 0xa3, 0xd3, 0x3c, 0x3e, 0xad, 0x2e, 0x60, - 0x98, 0xcb, 0xd8, 0x1a, 0x7b, 0xfe, 0x19, 0xcf, 0x25, 0xc7, 0x73, 0xe1, 0x20, 0xca, 0xe5, 0x1d, - 0x60, 0x27, 0x86, 0x1d, 0xea, 0xc9, 0xac, 0xb8, 0x19, 0xa2, 0x20, 0xa6, 0x2f, 0x67, 0x77, 0x09, - 0x72, 0xa6, 0x1d, 0x1c, 0xb7, 0xba, 0xc2, 0x04, 0x11, 0x29, 0x6c, 0x4b, 0x30, 0x34, 0x50, 0x03, - 0x0a, 0x2d, 0xae, 0x2e, 0xa7, 0xb5, 0x22, 0x42, 0xb6, 0x11, 0x80, 0x3b, 0xa8, 0x6b, 0x85, 0x27, - 0x9e, 0x8f, 0x9c, 0xdc, 0xc2, 0x98, 0x01, 0x50, 0xd3, 0x40, 0x52, 0x2c, 0x88, 0xbc, 0x41, 0x69, - 0x2d, 0x4e, 0xa3, 0xee, 0xce, 0x97, 0x2f, 0x61, 0xcb, 0xbc, 0xfa, 0x33, 0x08, 0xbb, 0x03, 0x15, - 0xaa, 0x3e, 0x59, 0x20, 0xd8, 0x06, 0x3a, 0xe5, 0x4a, 0x6b, 0x65, 0x84, 0x92, 0x33, 0x01, 0xa9, - 0x3e, 0x81, 0x2b, 0x89, 0xf6, 0xe9, 0x86, 0xef, 0x1b, 0x67, 0xfa, 0xd8, 0xf8, 0xd2, 0xf3, 0xc9, - 0xf1, 0x93, 0xd6, 0x2e, 0xc9, 0xdd, 0x56, 0x43, 0xf4, 0x1e, 0x62, 0xcf, 0x65, 0xb5, 0x5d, 0xcf, - 0x27, 0xaf, 0xd0, 0x52, 0x56, 0xc4, 0x92, 0x0b, 0x83, 0x06, 0x98, 0xcc, 0xa1, 0x80, 0xc7, 0x35, - 0x6a, 0x25, 0x82, 0x6d, 0x13, 0x08, 0x0d, 0x82, 0xe0, 0x31, 0x97, 0xac, 0x1b, 0x22, 0xc8, 0xe8, - 0x31, 0xc9, 0x5f, 0x8e, 0x38, 0xb2, 0x0c, 0x93, 0x4e, 0xce, 0x08, 0xb1, 0x6b, 0x19, 0x74, 0x2e, - 0x1d, 0x3c, 0xd6, 0x27, 0xd3, 0x90, 0x07, 0x24, 0x6a, 0xd9, 0xe0, 0xf1, 0xfe, 0x34, 0x14, 0xe0, - 0x43, 0x2b, 0xa4, 0x30, 0x44, 0x02, 0x3f, 0xb5, 0x42, 0xdc, 0x08, 0x83, 0xc7, 0x91, 0x17, 0xfc, - 0xa2, 0xe8, 0xdb, 0xc7, 0xc2, 0xcd, 0xad, 0xc2, 0x5a, 0x8c, 0xd4, 0xc7, 0x53, 0x1e, 0x81, 0x98, - 0xd6, 0x4a, 0x11, 0xc1, 0xde, 0xd4, 0xc1, 0x81, 0x1d, 0x1a, 0xc3, 0x23, 0x4b, 0xf7, 0xb1, 0x2a, - 0x97, 0xf9, 0xd0, 0x11, 0x44, 0xc3, 0xda, 0x5c, 0x03, 0x9e, 0xd0, 0x8f, 0xec, 0x90, 0xbc, 0x53, - 0x69, 0xad, 0x40, 0x80, 0x5d, 0x3b, 0x44, 0xb1, 0xc0, 0x91, 0x62, 0x06, 0x52, 0x16, 0x57, 0x88, - 0x68, 0x9d, 0x10, 0x7b, 0x04, 0xa7, 0x8c, 0xee, 0x81, 0x92, 0xa0, 0xc5, 0xfc, 0xae, 0x12, 0x69, - 0x45, 0x22, 0xc5, 0x5c, 0xef, 0x02, 0x67, 0xd6, 0x71, 0xea, 0xf1, 0x3c, 0xaf, 0x71, 0x73, 0x98, - 0xc0, 0x0d, 0x3b, 0x38, 0xa6, 0x1c, 0xef, 0x40, 0x45, 0xa2, 0xc3, 0xfc, 0xae, 0xf3, 0x99, 0x11, - 0x93, 0x25, 0xea, 0xe8, 0x5b, 0x63, 0x2f, 0x14, 0xcd, 0x7c, 0x43, 0xaa, 0xa3, 0x46, 0xf0, 0x64, - 0x1d, 0x05, 0x2d, 0xe6, 0x79, 0x43, 0xaa, 0x23, 0x27, 0xc5, 0x5c, 0x6f, 0x41, 0x19, 0xa5, 0x48, - 0x68, 0xb9, 0x7c, 0xf1, 0xdf, 0xe4, 0x1d, 0x2b, 0x60, 0xb4, 0xfa, 0x6f, 0x41, 0x99, 0xf7, 0xbc, - 0x10, 0x97, 0x5b, 0x9c, 0x44, 0xc0, 0x22, 0x01, 0x21, 0x7a, 0x63, 0x6c, 0xbb, 0xe4, 0x82, 0x4a, - 0x6b, 0x45, 0x0e, 0xd9, 0xb3, 0x5d, 0x19, 0x6d, 0x9c, 0x92, 0x23, 0x6a, 0x86, 0x36, 0x4e, 0x69, - 0x49, 0x4e, 0x6c, 0xc7, 0xe1, 0x0b, 0xff, 0xb6, 0x58, 0x92, 0x08, 0xe9, 0x09, 0x9b, 0x9a, 0xa3, - 0x31, 0xef, 0x3b, 0x62, 0x66, 0x20, 0x00, 0xb3, 0x9e, 0x21, 0x8d, 0xd3, 0xea, 0x9b, 0x32, 0xd2, - 0x38, 0x15, 0x82, 0x09, 0x2b, 0x4d, 0xbc, 0x77, 0x63, 0xc1, 0x84, 0x20, 0xe4, 0x96, 0x09, 0x8c, - 0xd3, 0xea, 0x5b, 0x49, 0x02, 0xe3, 0x54, 0xfd, 0x69, 0x0a, 0xae, 0x76, 0xe9, 0xa4, 0x94, 0x24, - 0xf9, 0x9e, 0x15, 0x04, 0xc6, 0xa1, 0xb5, 0xe3, 0xf9, 0x3b, 0xd3, 0xaf, 0xbf, 0x3e, 0x63, 0xf7, - 0x60, 0x7d, 0xdf, 0xf0, 0x2d, 0x37, 0x8c, 0x4f, 0xd2, 0x84, 0xd6, 0x34, 0x0f, 0x66, 0x4f, 0x40, - 0xe1, 0xa0, 0x83, 0x58, 0xff, 0x14, 0x16, 0x58, 0xd2, 0xf1, 0xbd, 0x40, 0xa5, 0xfe, 0xcf, 0x5b, - 0x90, 0xe9, 0x78, 0xa6, 0xc5, 0xde, 0x83, 0x22, 0xc5, 0x35, 0x4a, 0x16, 0x81, 0xf0, 0x98, 0x20, - 0x9a, 0xfe, 0x90, 0x29, 0x50, 0x70, 0xc5, 0xd7, 0xf9, 0x91, 0x90, 0xb7, 0xc8, 0xa8, 0xa1, 0x63, - 0x44, 0xdc, 0xac, 0x4a, 0xc2, 0xf1, 0x42, 0x7e, 0x02, 0x8e, 0x41, 0x51, 0x47, 0x2e, 0x67, 0xdf, - 0x72, 0x49, 0x75, 0xce, 0x6a, 0x71, 0x9a, 0x4c, 0x49, 0xdf, 0xc3, 0x8d, 0x95, 0x0b, 0x84, 0xec, - 0x12, 0x53, 0x92, 0xe3, 0x49, 0x42, 0xbc, 0x07, 0xc5, 0x2f, 0x3d, 0xdb, 0xe5, 0x15, 0xcf, 0x2d, - 0x54, 0x1c, 0xb5, 0x45, 0x5e, 0xf1, 0x2f, 0xc5, 0x17, 0xbb, 0x0d, 0x79, 0xcf, 0xe5, 0x79, 0xe7, - 0x17, 0xf2, 0xce, 0x79, 0x6e, 0x9b, 0x87, 0xd9, 0xac, 0xd9, 0x81, 0xee, 0xdb, 0x87, 0x47, 0xa1, - 0x8e, 0x9c, 0xe2, 0xf8, 0xb1, 0x64, 0x07, 0x1a, 0xc2, 0x30, 0x5b, 0xb4, 0x90, 0x47, 0xb6, 0x83, - 0xfb, 0x37, 0x65, 0x56, 0x5c, 0xc8, 0x0c, 0x38, 0x9a, 0x32, 0x7c, 0x13, 0x0a, 0x87, 0xbe, 0x37, - 0x9d, 0xa0, 0xc9, 0x0b, 0x0b, 0x94, 0x79, 0xc2, 0x6d, 0x9f, 0xe1, 0x6e, 0x46, 0x9f, 0xb6, 0x7b, - 0xa8, 0x93, 0x77, 0xa0, 0xb4, 0x95, 0xbe, 0x57, 0xd0, 0xca, 0x11, 0x90, 0xec, 0xfe, 0x37, 0xa1, - 0x60, 0x1c, 0x1e, 0xea, 0x22, 0x5a, 0x68, 0x21, 0x2f, 0xe3, 0xf0, 0x90, 0x8a, 0x7c, 0x00, 0x6b, - 0x27, 0xb6, 0xab, 0x07, 0x13, 0x6b, 0xc8, 0x69, 0xd7, 0x16, 0xbb, 0xf2, 0xc4, 0x76, 0xd1, 0x28, - 0x26, 0x7a, 0xd9, 0x2a, 0xaf, 0xbc, 0xd6, 0x2a, 0xdf, 0x82, 0xac, 0x63, 0x8f, 0xed, 0x50, 0xc4, - 0x0f, 0x25, 0xd4, 0x76, 0x42, 0x30, 0x15, 0x72, 0xc2, 0x1d, 0xad, 0x2c, 0x90, 0x08, 0x4c, 0x52, - 0xbb, 0xd9, 0x78, 0x8d, 0x76, 0x23, 0xa9, 0xd0, 0xec, 0xd5, 0x2a, 0xf4, 0x87, 0xa4, 0xab, 0x5a, - 0x6e, 0xa8, 0x47, 0x0c, 0x17, 0x96, 0x33, 0x94, 0x39, 0x59, 0x97, 0xb3, 0xbd, 0x0f, 0x25, 0x9f, - 0xdc, 0x45, 0x3a, 0xf9, 0x96, 0x36, 0x65, 0x7b, 0x7b, 0xe6, 0x47, 0xd2, 0xc0, 0x9f, 0xf9, 0x94, - 0x6a, 0xb0, 0x3e, 0x8b, 0x87, 0xe4, 0x81, 0xa5, 0x17, 0x65, 0x7f, 0x75, 0x22, 0x80, 0x32, 0xd2, - 0x8e, 0xed, 0x44, 0x54, 0xe5, 0x6d, 0x58, 0xe3, 0x91, 0x10, 0xfc, 0xbc, 0x3a, 0xa0, 0x0d, 0xa8, - 0xa8, 0x95, 0x09, 0xc8, 0xcf, 0xb2, 0x03, 0xf6, 0x00, 0x20, 0xd2, 0xec, 0xc2, 0x53, 0xda, 0x81, - 0xe2, 0xd6, 0xf0, 0x6d, 0xaa, 0x1e, 0x9e, 0x6a, 0x45, 0x33, 0xfa, 0x44, 0xc1, 0x3a, 0xb0, 0x5d, - 0x13, 0xe7, 0x51, 0x68, 0x1c, 0x06, 0xd5, 0x2a, 0x2d, 0xb3, 0x92, 0x80, 0xf5, 0x8d, 0xc3, 0x00, - 0x2d, 0x28, 0x83, 0x2b, 0x72, 0xbc, 0xde, 0x57, 0x64, 0xf7, 0x8a, 0xa4, 0xe2, 0x69, 0x25, 0x43, - 0xd2, 0xf7, 0x3e, 0x06, 0x16, 0x1d, 0x7d, 0x49, 0x06, 0xd1, 0xd5, 0x85, 0xa9, 0xb5, 0x2e, 0xce, - 0xbe, 0xe2, 0x20, 0xee, 0x9b, 0x50, 0x0a, 0xbc, 0xa9, 0x3f, 0xb4, 0xf4, 0x20, 0xb4, 0x26, 0xd5, - 0x6b, 0x54, 0x21, 0xe0, 0xa0, 0x5e, 0x68, 0x4d, 0xd8, 0xc7, 0xb0, 0x96, 0x54, 0x88, 0xaf, 0x2f, - 0x39, 0x41, 0xa2, 0x69, 0xa1, 0x95, 0x87, 0xb2, 0x8a, 0x7c, 0x9b, 0xc7, 0xea, 0xd2, 0xee, 0x43, - 0x8c, 0xfc, 0x94, 0xa4, 0xec, 0x7a, 0x61, 0x3d, 0x82, 0x61, 0x07, 0x46, 0x86, 0x52, 0x78, 0x4a, - 0x1b, 0x56, 0xdc, 0x81, 0xb1, 0x69, 0x82, 0x8a, 0x67, 0x64, 0xa5, 0xe0, 0x5c, 0xe0, 0xea, 0x3f, - 0x31, 0xdc, 0x4c, 0xcc, 0x85, 0xd8, 0x2e, 0xd0, 0xc0, 0x9f, 0xd9, 0x08, 0x1f, 0x43, 0x85, 0xfb, - 0x80, 0xe3, 0x65, 0xb4, 0x75, 0xde, 0x32, 0x2a, 0x13, 0xa1, 0x80, 0xa0, 0x24, 0xe1, 0x8c, 0x7c, - 0x45, 0xdd, 0x5a, 0xf4, 0xb5, 0x11, 0xba, 0x4d, 0xcb, 0xea, 0x09, 0x54, 0x26, 0x3e, 0x0e, 0x59, - 0xdc, 0x18, 0x55, 0xee, 0xa7, 0x7d, 0xdf, 0x9a, 0xb5, 0xa7, 0x3c, 0x91, 0x52, 0xec, 0x47, 0xb0, - 0x21, 0x71, 0x4e, 0x8f, 0x89, 0xf9, 0x36, 0x31, 0x6f, 0xce, 0x31, 0x1f, 0x1c, 0x23, 0x7b, 0x65, - 0x92, 0x48, 0xb3, 0xda, 0x9c, 0x53, 0x03, 0x0d, 0x86, 0x3b, 0xc4, 0x7f, 0xf9, 0x1c, 0x4f, 0x45, - 0xc2, 0xdb, 0xf1, 0x8c, 0x1f, 0xba, 0xb4, 0x82, 0xa6, 0x6b, 0xd2, 0x7e, 0x5a, 0xd0, 0x78, 0x82, - 0x3d, 0x86, 0x32, 0x57, 0x5d, 0x29, 0x26, 0x32, 0xa8, 0xde, 0x95, 0xbd, 0xba, 0xa4, 0xbf, 0x12, - 0x42, 0x2b, 0x39, 0xf1, 0x77, 0xc0, 0x3e, 0x82, 0x0d, 0xde, 0x6b, 0xb2, 0x14, 0x7e, 0x6b, 0x71, - 0x22, 0x12, 0xd1, 0xce, 0x4c, 0x14, 0x6b, 0x70, 0xc5, 0x9f, 0xba, 0xa4, 0xce, 0x0a, 0xce, 0x89, - 0xef, 0x0d, 0x2c, 0xce, 0x7f, 0x8f, 0xf8, 0x45, 0x73, 0x34, 0x4e, 0xc6, 0x79, 0x69, 0xdc, 0x2e, - 0xf9, 0x32, 0x68, 0x1f, 0xf9, 0xce, 0xc9, 0x73, 0x30, 0xb5, 0x1d, 0x93, 0xe7, 0xf9, 0xbd, 0x6f, - 0x93, 0xe7, 0x36, 0xf2, 0x51, 0x9e, 0x0c, 0x32, 0xd3, 0xa9, 0x6d, 0x56, 0xef, 0xf3, 0xf0, 0x45, - 0xfc, 0x66, 0x6f, 0x42, 0xc5, 0xb7, 0x86, 0x53, 0x3f, 0xb0, 0x5f, 0x5a, 0x7a, 0x60, 0xbb, 0xc7, - 0xd5, 0xb7, 0xa9, 0x1f, 0xd7, 0x62, 0x68, 0xcf, 0x76, 0x8f, 0x71, 0xf2, 0x5a, 0xa7, 0xa1, 0xe5, - 0xbb, 0x3c, 0x4c, 0xfb, 0x1d, 0x79, 0xf2, 0x36, 0x09, 0x81, 0xd2, 0x47, 0x03, 0x2b, 0xfe, 0x9e, - 0x9b, 0x1c, 0x01, 0x9f, 0x1c, 0x0f, 0xbe, 0xd1, 0xe4, 0xe8, 0xd1, 0xe4, 0xb8, 0x0b, 0x05, 0xdb, - 0x0d, 0x2d, 0xff, 0xa5, 0xe1, 0x54, 0x1f, 0x2e, 0xcc, 0xe0, 0x18, 0xc7, 0xee, 0x40, 0x3e, 0x70, - 0x6c, 0x94, 0x42, 0xd5, 0xf7, 0x16, 0xc8, 0x22, 0x14, 0xbb, 0x07, 0xc5, 0xf8, 0x86, 0x51, 0xf5, - 0xfd, 0x05, 0xba, 0x19, 0x92, 0xdd, 0x80, 0xcc, 0x09, 0x4e, 0xa8, 0x47, 0x8b, 0x5e, 0x78, 0x84, - 0xa3, 0x86, 0x30, 0x42, 0x25, 0x8e, 0x34, 0x84, 0xc7, 0x0b, 0x1a, 0xc2, 0x8e, 0xed, 0x38, 0x5c, - 0x43, 0x18, 0x89, 0x2f, 0xdc, 0x5f, 0x89, 0x03, 0x5b, 0xf2, 0xc1, 0xe2, 0xfe, 0x8a, 0xb8, 0xe7, - 0x74, 0x17, 0xab, 0x14, 0x90, 0x6b, 0x99, 0x7b, 0xc8, 0x3f, 0x94, 0xfb, 0x2a, 0xe9, 0x73, 0xd6, - 0x20, 0x88, 0xd3, 0xa8, 0x91, 0x0a, 0xc7, 0xba, 0x6d, 0x9e, 0x56, 0x3f, 0xe2, 0x41, 0xfe, 0x1c, - 0xd2, 0x32, 0x4f, 0xd9, 0x7b, 0xb0, 0x16, 0x45, 0xd1, 0x60, 0x71, 0x41, 0xf5, 0xe3, 0x85, 0x1a, - 0x24, 0x09, 0x58, 0x03, 0xca, 0x23, 0xd4, 0x18, 0xc7, 0x5c, 0x81, 0xac, 0x3e, 0xa1, 0x8a, 0x6c, - 0x45, 0x42, 0xe7, 0x3c, 0x05, 0x53, 0x4b, 0x70, 0xb1, 0x07, 0xc0, 0xec, 0x11, 0x1f, 0x4f, 0xb4, - 0xfa, 0xb9, 0x92, 0x58, 0xfd, 0x84, 0x66, 0xd7, 0x12, 0x0c, 0x9d, 0xb3, 0x59, 0xae, 0xa9, 0x8f, - 0x03, 0xa1, 0x89, 0x7c, 0x9f, 0xea, 0x29, 0x44, 0x6a, 0x7c, 0x13, 0x51, 0x6c, 0x79, 0x25, 0xa4, - 0xdd, 0x0b, 0xb8, 0x62, 0xf2, 0x09, 0xe0, 0x74, 0x7d, 0x39, 0x63, 0xfd, 0x95, 0x57, 0xb2, 0x22, - 0x6d, 0xc4, 0xfa, 0x04, 0x2a, 0xa6, 0x65, 0x4e, 0x27, 0xa4, 0x94, 0xd1, 0x14, 0xfd, 0x81, 0x2c, - 0xfc, 0x64, 0x0f, 0xa1, 0x56, 0x36, 0x65, 0x7f, 0xe1, 0xc7, 0xb0, 0x1e, 0xb9, 0xf2, 0x42, 0xe1, - 0xf5, 0xfb, 0xa1, 0x5c, 0x6c, 0xec, 0xa9, 0xd3, 0xd6, 0xa6, 0xd1, 0x27, 0x15, 0xf9, 0x18, 0xd6, - 0x68, 0x6f, 0x0f, 0x5c, 0x63, 0x12, 0x1c, 0x79, 0x61, 0xf5, 0x57, 0x65, 0x35, 0xa5, 0x27, 0xa0, - 0x5a, 0x19, 0x89, 0xa2, 0x14, 0x6e, 0x49, 0xb3, 0x75, 0x3a, 0x0c, 0xad, 0xea, 0x8f, 0xf8, 0x96, - 0x14, 0x03, 0xeb, 0xa1, 0xc5, 0x1e, 0x03, 0x18, 0x93, 0x89, 0x73, 0xc6, 0xa7, 0xe6, 0xa7, 0x34, - 0x35, 0x37, 0xa5, 0xa9, 0x59, 0x43, 0x24, 0xcd, 0xcd, 0xa2, 0x11, 0x7d, 0xb2, 0x47, 0x50, 0x9e, - 0x78, 0x41, 0xa8, 0x9b, 0x63, 0x87, 0xda, 0x5f, 0x93, 0xd7, 0xf6, 0xbe, 0x17, 0x84, 0x8d, 0xb1, - 0x43, 0x1b, 0xd3, 0x24, 0xfe, 0x66, 0x6d, 0xb8, 0x90, 0x90, 0xdb, 0x06, 0x9d, 0x6a, 0x57, 0xb7, - 0xa9, 0xc4, 0xeb, 0x52, 0x89, 0x92, 0xfc, 0x16, 0x21, 0x5d, 0x1b, 0xde, 0x3c, 0x08, 0x4d, 0x4a, - 0x3e, 0x06, 0x71, 0x5c, 0x63, 0x9d, 0x2b, 0x2c, 0x04, 0x8d, 0x02, 0x1b, 0x9f, 0xc0, 0xfa, 0x8c, - 0x0a, 0x1b, 0x18, 0x54, 0x1b, 0xf2, 0x4c, 0x96, 0xa2, 0x8f, 0xd7, 0x22, 0x46, 0x84, 0x05, 0xd4, - 0x77, 0x9e, 0xe3, 0x4c, 0x27, 0x42, 0x94, 0x56, 0x9b, 0xa2, 0xef, 0x08, 0xc8, 0xa5, 0xa4, 0x64, - 0x9b, 0x59, 0xe3, 0xea, 0x8e, 0x6c, 0x9b, 0x59, 0x63, 0xf5, 0x9f, 0x65, 0xa1, 0x10, 0x99, 0x2c, - 0xac, 0x04, 0xf9, 0x83, 0xce, 0xb3, 0x4e, 0xf7, 0x45, 0x87, 0xdf, 0xa2, 0xaa, 0xf5, 0x7a, 0x4d, - 0xad, 0xaf, 0x98, 0xac, 0x02, 0x40, 0xf7, 0x24, 0xf4, 0x5e, 0xbd, 0xd6, 0xe1, 0xb7, 0xaa, 0xe8, - 0x76, 0x06, 0x4f, 0xaf, 0xb2, 0x0d, 0x58, 0xdb, 0x39, 0xe8, 0x50, 0xec, 0x19, 0x07, 0xa5, 0x11, - 0xd4, 0xfc, 0x9c, 0x9f, 0xb8, 0x71, 0x50, 0x06, 0x41, 0x7b, 0xb5, 0x7e, 0x53, 0x6b, 0x45, 0xa0, - 0x2c, 0x85, 0xb1, 0x75, 0x0f, 0xb4, 0xba, 0xc8, 0x29, 0xc7, 0x2e, 0xc2, 0x46, 0xcc, 0x16, 0x65, - 0xa9, 0xe4, 0xb1, 0x66, 0xfb, 0x5a, 0xf7, 0xb3, 0x66, 0xbd, 0xaf, 0x00, 0x1d, 0xdf, 0x3d, 0x7d, - 0xaa, 0x94, 0x58, 0x19, 0x0a, 0x8d, 0x56, 0xaf, 0xdf, 0xea, 0xd4, 0xfb, 0x4a, 0x19, 0x2b, 0xbc, - 0xd3, 0x6a, 0xf7, 0x9b, 0x9a, 0xb2, 0xc6, 0x0a, 0x90, 0xf9, 0xac, 0xdb, 0xea, 0x28, 0x15, 0xba, - 0x2f, 0x52, 0xdb, 0xdb, 0x6f, 0x37, 0x95, 0x75, 0x84, 0xf6, 0xba, 0x5a, 0x5f, 0x51, 0x10, 0xfa, - 0xa2, 0xd5, 0x69, 0x74, 0x5f, 0x28, 0x1b, 0xac, 0x08, 0xd9, 0x83, 0x0e, 0x16, 0xc3, 0xd8, 0x1a, - 0x14, 0xe9, 0x53, 0xaf, 0xb5, 0xdb, 0xca, 0x05, 0xe9, 0xcc, 0x6f, 0x13, 0x51, 0x74, 0x82, 0xd8, - 0xc3, 0x3a, 0x5c, 0xc4, 0xb6, 0xc4, 0x49, 0xa2, 0xbe, 0x84, 0xf9, 0xec, 0xb5, 0x3a, 0x07, 0x3d, - 0xe5, 0x32, 0x12, 0xd3, 0x27, 0x61, 0xaa, 0x98, 0x4f, 0xab, 0x43, 0x5d, 0x79, 0x03, 0xbf, 0x1b, - 0xcd, 0x76, 0xb3, 0xdf, 0x54, 0x6e, 0x62, 0xab, 0xb4, 0xe6, 0x7e, 0xbb, 0x56, 0x6f, 0x2a, 0x5b, - 0x98, 0x68, 0x77, 0xeb, 0xcf, 0xf4, 0xee, 0xbe, 0x72, 0x8b, 0x6d, 0x82, 0xd2, 0xed, 0xe8, 0x8d, - 0x83, 0xfd, 0x76, 0xab, 0x5e, 0xeb, 0x37, 0xf5, 0x67, 0xcd, 0x2f, 0x14, 0x15, 0xbb, 0x7d, 0x5f, - 0x6b, 0xea, 0x22, 0xaf, 0xdb, 0x4c, 0x81, 0xf2, 0xce, 0xc1, 0x4f, 0x7e, 0xf2, 0x85, 0x2e, 0xda, - 0xfd, 0x26, 0x56, 0x6b, 0x46, 0xa1, 0x1f, 0x3c, 0x53, 0xee, 0xce, 0x81, 0x7a, 0xcf, 0x94, 0xb7, - 0xb0, 0xdf, 0xa2, 0x81, 0x50, 0xee, 0x21, 0x81, 0xd6, 0xac, 0x1f, 0x68, 0xbd, 0xd6, 0xf3, 0xa6, - 0x5e, 0xef, 0x37, 0x95, 0xef, 0x51, 0x47, 0xb5, 0x3a, 0xcf, 0x94, 0xfb, 0xd8, 0x12, 0xfc, 0xe2, - 0xc3, 0xf3, 0x36, 0x63, 0x50, 0x99, 0xd1, 0x12, 0xec, 0x1d, 0x24, 0xd9, 0xd6, 0xba, 0xb5, 0x46, - 0xbd, 0xd6, 0xeb, 0x2b, 0xef, 0x62, 0x37, 0xf4, 0xf6, 0xdb, 0xad, 0xbe, 0xf2, 0x00, 0xdb, 0xfa, - 0xb4, 0xd6, 0xdf, 0x6d, 0x6a, 0xca, 0x43, 0x1c, 0xe9, 0x7e, 0x6b, 0xaf, 0xa9, 0x8b, 0x6e, 0x7f, - 0x84, 0x65, 0xec, 0xb4, 0xda, 0x6d, 0xe5, 0x31, 0x1d, 0x6b, 0xd5, 0xb4, 0x7e, 0x8b, 0xc6, 0xfa, - 0x03, 0xcc, 0xa0, 0xb6, 0xbf, 0xdf, 0xfe, 0x42, 0xf9, 0x10, 0x1b, 0xb8, 0x77, 0xd0, 0xee, 0xb7, - 0xf4, 0x83, 0xfd, 0x46, 0xad, 0xdf, 0x54, 0x3e, 0xa2, 0x89, 0xd0, 0xed, 0xf5, 0x1b, 0x7b, 0x6d, - 0xe5, 0x63, 0xca, 0x93, 0xa6, 0x61, 0xbd, 0xdd, 0xed, 0x34, 0x95, 0x27, 0xea, 0x6f, 0x40, 0x21, - 0x32, 0x63, 0x31, 0x9b, 0x56, 0xa7, 0xd3, 0xd4, 0x94, 0x15, 0x2c, 0xaa, 0xdd, 0xdc, 0xe9, 0x2b, - 0x29, 0x3a, 0xe3, 0x6b, 0x3d, 0xdd, 0xed, 0x2b, 0xab, 0xf8, 0xd9, 0x3d, 0xc0, 0x5e, 0x4b, 0x53, - 0x73, 0x9b, 0x7b, 0x2d, 0x25, 0x83, 0x5f, 0xb5, 0x4e, 0xbf, 0xa5, 0x64, 0x69, 0xde, 0xb4, 0x3a, - 0x4f, 0xdb, 0x4d, 0x25, 0x87, 0xd0, 0xbd, 0x9a, 0xf6, 0x4c, 0xc9, 0xf3, 0x4c, 0x1b, 0xcd, 0xcf, - 0x95, 0x02, 0xcb, 0xc1, 0x6a, 0xfb, 0x91, 0x52, 0x44, 0x50, 0xa3, 0xd9, 0x38, 0xd8, 0x57, 0x40, - 0xbd, 0x07, 0xf9, 0xda, 0xe1, 0xe1, 0x9e, 0x67, 0xd2, 0xb1, 0xe2, 0xce, 0x41, 0xbb, 0xcd, 0xd7, - 0xd1, 0x76, 0xb7, 0xdf, 0xef, 0xee, 0x29, 0x29, 0x9c, 0xb9, 0xfd, 0xee, 0xbe, 0xb2, 0xaa, 0xb6, - 0xa0, 0x10, 0xed, 0xa6, 0xd2, 0x1d, 0xa8, 0x02, 0x64, 0xf6, 0xb5, 0xe6, 0x73, 0x7e, 0x30, 0xdd, - 0x69, 0x7e, 0x8e, 0xd5, 0xc4, 0x2f, 0xcc, 0x28, 0x8d, 0x05, 0xf1, 0xcb, 0x4a, 0x74, 0x09, 0xaa, - 0xdd, 0xea, 0x34, 0x6b, 0x9a, 0x92, 0x55, 0x3f, 0x4c, 0x9c, 0xf9, 0x09, 0xc1, 0x83, 0xc5, 0xd7, - 0x5a, 0xa2, 0xf8, 0xd6, 0xd3, 0x4e, 0x57, 0x6b, 0xf2, 0x5b, 0x55, 0xa2, 0x23, 0x57, 0xd5, 0xb7, - 0xa1, 0x18, 0x0b, 0x4d, 0x9c, 0x58, 0x75, 0xad, 0xdb, 0xeb, 0xf1, 0x7e, 0x5f, 0xc1, 0x34, 0xf5, - 0x0d, 0x4f, 0xa7, 0xd4, 0x1e, 0x6c, 0x44, 0xf2, 0x9a, 0x02, 0xce, 0xc9, 0xbc, 0xd9, 0x84, 0x6c, - 0xdb, 0x7a, 0x69, 0x39, 0x51, 0xe4, 0x34, 0x25, 0x10, 0xda, 0x1d, 0x7c, 0xd9, 0x8a, 0x2f, 0xbe, - 0x52, 0x02, 0x15, 0xb4, 0x8e, 0x74, 0xf7, 0x96, 0x22, 0xf6, 0x7f, 0x37, 0x05, 0x85, 0x78, 0x17, - 0xb8, 0x03, 0xab, 0xfd, 0x9e, 0x38, 0x33, 0xd8, 0x7c, 0x30, 0x7b, 0x6a, 0xa0, 0x1f, 0x7d, 0x69, - 0xab, 0xfd, 0x1e, 0x7b, 0x07, 0x72, 0xfc, 0xaa, 0xa0, 0x38, 0xec, 0xd9, 0x4c, 0xee, 0x2c, 0x7d, - 0xc2, 0x69, 0x82, 0x86, 0x7d, 0x08, 0xc5, 0xb8, 0xb6, 0xc2, 0xc5, 0x72, 0x39, 0xc9, 0x10, 0xa3, - 0xb5, 0x19, 0xa5, 0xda, 0x86, 0x4a, 0x32, 0x43, 0x76, 0x03, 0x80, 0x67, 0x29, 0xb9, 0x96, 0x24, - 0x08, 0xbb, 0x0a, 0xd1, 0x0d, 0xc6, 0x06, 0x55, 0x6c, 0x2d, 0xbe, 0xd1, 0xd8, 0x50, 0xff, 0x6a, - 0x1a, 0x60, 0xa6, 0x47, 0x62, 0x47, 0xc4, 0x8e, 0xa3, 0xac, 0x38, 0x2e, 0xbe, 0x06, 0x45, 0xc7, - 0x33, 0x4c, 0xf9, 0xa5, 0x81, 0x02, 0x02, 0x68, 0x68, 0xe4, 0xdb, 0x3c, 0x45, 0x1e, 0xab, 0xc1, - 0x2e, 0x41, 0x6e, 0xe4, 0xf9, 0x63, 0x23, 0x14, 0x61, 0xf2, 0x22, 0x85, 0xdb, 0x01, 0x3f, 0xc2, - 0x44, 0x6d, 0xda, 0xa5, 0x48, 0x79, 0x1c, 0x83, 0xb2, 0x00, 0xb6, 0x11, 0x86, 0xc6, 0xa5, 0xe5, - 0x0e, 0x1d, 0x2f, 0xb0, 0x4c, 0xb4, 0xbb, 0x72, 0xa4, 0x32, 0x43, 0x04, 0xda, 0x3e, 0xe3, 0xad, - 0xf5, 0xc7, 0xb6, 0x6b, 0x84, 0xc2, 0xb1, 0x4f, 0xad, 0x8d, 0x20, 0x58, 0xdd, 0x2f, 0x03, 0x4f, - 0xf8, 0x91, 0xf8, 0x69, 0x68, 0x01, 0x01, 0x54, 0xdd, 0x37, 0x00, 0xac, 0x60, 0x68, 0x4c, 0x78, - 0xe6, 0x45, 0xca, 0xbc, 0x28, 0x20, 0xdb, 0x67, 0xac, 0x0d, 0x95, 0xfe, 0x00, 0xb7, 0x2f, 0xaf, - 0x61, 0x84, 0x46, 0xdd, 0x73, 0x84, 0x87, 0xe7, 0xce, 0xbc, 0xc2, 0xfd, 0x20, 0x49, 0xc6, 0x8f, - 0x6d, 0xe7, 0x78, 0xaf, 0xd6, 0xe0, 0xc2, 0x12, 0xb2, 0x6f, 0x15, 0xbf, 0xe6, 0x44, 0xa3, 0x53, - 0x0b, 0x43, 0xba, 0x99, 0x12, 0xef, 0xd4, 0xa9, 0x28, 0xbe, 0x9e, 0x6f, 0xd2, 0xd7, 0x28, 0x42, - 0x45, 0x84, 0x3e, 0x8a, 0x41, 0x8a, 0x43, 0x1a, 0xef, 0xc2, 0x3a, 0x22, 0x47, 0xb6, 0xe5, 0x98, - 0x82, 0x84, 0x5f, 0xac, 0x58, 0x1b, 0x7a, 0xce, 0x0e, 0x42, 0x89, 0x4e, 0xfd, 0xcb, 0x59, 0x80, - 0x99, 0x8d, 0x96, 0x38, 0x39, 0x4e, 0x25, 0x4f, 0x8e, 0x1f, 0xc1, 0x25, 0x71, 0xed, 0x26, 0x3e, - 0x7e, 0xb5, 0x5d, 0x7d, 0x60, 0x44, 0x87, 0xf4, 0x4c, 0x60, 0xf9, 0x09, 0x6c, 0xcb, 0xdd, 0x36, - 0x50, 0xe3, 0x5b, 0x97, 0x79, 0xc2, 0xb3, 0x49, 0x32, 0xc8, 0x40, 0xd6, 0x23, 0x66, 0xec, 0xfd, - 0xb3, 0x09, 0x7b, 0x0f, 0x2e, 0xfa, 0xd6, 0xc8, 0xb7, 0x82, 0x23, 0x3d, 0x0c, 0xe4, 0xc2, 0x78, - 0x2c, 0xdc, 0x86, 0x40, 0xf6, 0x83, 0xb8, 0xac, 0xf7, 0xe0, 0xa2, 0xb0, 0xde, 0xe6, 0xaa, 0xc7, - 0xef, 0x67, 0x6f, 0x70, 0xa4, 0x5c, 0xbb, 0x37, 0x00, 0x84, 0xe1, 0x1a, 0xbd, 0xd7, 0x51, 0xd0, - 0x8a, 0xdc, 0x48, 0x15, 0xb7, 0x58, 0xc9, 0xfa, 0x14, 0xc7, 0x6a, 0x3c, 0xc1, 0x54, 0xc8, 0xa0, - 0x38, 0xa5, 0x23, 0xa0, 0xca, 0xa3, 0xca, 0x03, 0x7a, 0x8f, 0x84, 0x6e, 0x15, 0x7b, 0xa6, 0xa5, - 0x11, 0x8e, 0xbd, 0x0b, 0x17, 0xe4, 0x66, 0x47, 0x57, 0xea, 0x4b, 0x54, 0x11, 0x65, 0xd6, 0x50, - 0x8d, 0x5f, 0xae, 0x7f, 0x1b, 0x98, 0x54, 0xf3, 0x88, 0xba, 0x4c, 0xd4, 0xeb, 0x71, 0xb5, 0x05, - 0xf1, 0x5b, 0x40, 0x55, 0xe4, 0x1e, 0xf7, 0xb5, 0x45, 0x53, 0x0d, 0x91, 0xe4, 0x7a, 0x7f, 0x0f, - 0x2e, 0xce, 0x5a, 0xa7, 0x1b, 0xa1, 0x1e, 0x1e, 0x59, 0xba, 0xe5, 0x9a, 0x74, 0x57, 0xaa, 0xa0, - 0x6d, 0xc4, 0x0d, 0xad, 0x85, 0xfd, 0x23, 0x0b, 0x8d, 0x2d, 0xc9, 0x45, 0xb7, 0xfe, 0x6a, 0x17, - 0xdd, 0x47, 0x50, 0x4d, 0x1c, 0x27, 0xcb, 0xdd, 0xcd, 0xef, 0x1a, 0x6e, 0xca, 0x87, 0xc8, 0x71, - 0x8f, 0xdf, 0x87, 0x8d, 0x23, 0x23, 0xd0, 0x13, 0xbc, 0xe4, 0x39, 0x2c, 0x68, 0xeb, 0x47, 0x46, - 0xb0, 0x2f, 0xf1, 0xa8, 0xbf, 0x9f, 0x82, 0x4a, 0xd2, 0x6a, 0xe5, 0x77, 0x4d, 0x9c, 0xe9, 0xd8, - 0xe5, 0x91, 0x23, 0x59, 0x2d, 0x4a, 0xe2, 0x5a, 0x98, 0x1c, 0xeb, 0x3c, 0x15, 0xad, 0x85, 0xc9, - 0x71, 0x9d, 0xd2, 0xec, 0x7b, 0x90, 0x9f, 0x1c, 0x73, 0xe1, 0x70, 0xde, 0xec, 0xcb, 0x4d, 0x78, - 0xc8, 0xee, 0xf7, 0x20, 0x3f, 0x15, 0xa4, 0x99, 0xf3, 0x48, 0xa7, 0x44, 0xaa, 0xfe, 0xf3, 0x55, + 0xf2, 0x90, 0x05, 0x26, 0x0b, 0x2c, 0x12, 0x04, 0x09, 0x90, 0x04, 0x0b, 0x6c, 0xf2, 0x9c, 0x87, + 0x6c, 0x12, 0xec, 0x22, 0x40, 0x80, 0x04, 0x49, 0x80, 0x4d, 0x30, 0x41, 0x1e, 0x83, 0x24, 0x48, + 0x9e, 0xf2, 0x92, 0xe0, 0x9c, 0x7b, 0xab, 0x78, 0x8b, 0xa4, 0xec, 0xee, 0x9e, 0x59, 0x20, 0x79, + 0x91, 0xea, 0x9e, 0x9f, 0xfb, 0x7f, 0xcf, 0x3d, 0xe7, 0xdc, 0x73, 0x2f, 0x01, 0x26, 0x8e, 0xe1, + 0x3e, 0x98, 0xf8, 0x5e, 0xe8, 0xb1, 0x0c, 0x7e, 0x5f, 0x7d, 0xf7, 0xd0, 0x0e, 0x8f, 0xa6, 0x83, + 0x07, 0x43, 0x6f, 0xfc, 0xf0, 0xd0, 0x3b, 0xf4, 0x1e, 0x12, 0x72, 0x30, 0x1d, 0x51, 0x8a, 0x12, + 0xf4, 0xc5, 0x99, 0xae, 0x82, 0xe3, 0x0d, 0x8f, 0xc5, 0xf7, 0x7a, 0x68, 0x8f, 0xad, 0x20, 0x34, + 0xc6, 0x13, 0x0e, 0x50, 0xff, 0x38, 0x05, 0x99, 0xfe, 0xd9, 0xc4, 0x62, 0x15, 0x58, 0xb5, 0xcd, + 0x6a, 0x6a, 0x2b, 0x75, 0x2f, 0xab, 0xad, 0xda, 0x26, 0xdb, 0x82, 0x92, 0xeb, 0x85, 0x9d, 0xa9, + 0xe3, 0x18, 0x03, 0xc7, 0xaa, 0xae, 0x6e, 0xa5, 0xee, 0x15, 0x34, 0x19, 0xc4, 0xae, 0x41, 0xd1, + 0x98, 0x86, 0x9e, 0x6e, 0xbb, 0x43, 0xbf, 0x9a, 0x26, 0x7c, 0x01, 0x01, 0x2d, 0x77, 0xe8, 0xb3, + 0x4d, 0xc8, 0x9e, 0xd8, 0x66, 0x78, 0x54, 0xcd, 0x50, 0x8e, 0x3c, 0x81, 0xd0, 0x60, 0x68, 0x38, + 0x56, 0x35, 0xcb, 0xa1, 0x94, 0x40, 0x68, 0x48, 0x85, 0xe4, 0xb6, 0x52, 0xf7, 0x8a, 0x1a, 0x4f, + 0xb0, 0x1b, 0x00, 0x96, 0x3b, 0x1d, 0xbf, 0x34, 0x9c, 0xa9, 0x15, 0x54, 0xf3, 0x84, 0x92, 0x20, + 0xea, 0x8f, 0xa0, 0x38, 0x0e, 0x0e, 0x77, 0x2d, 0xc3, 0xb4, 0x7c, 0x76, 0x19, 0xf2, 0xe3, 0xe0, + 0x50, 0x0f, 0x8d, 0x43, 0xd1, 0x84, 0xdc, 0x38, 0x38, 0xec, 0x1b, 0x87, 0xec, 0x0a, 0x14, 0x08, + 0x71, 0x36, 0xe1, 0x6d, 0xc8, 0x6a, 0x48, 0x88, 0x2d, 0x56, 0x7f, 0x27, 0x07, 0xf9, 0xb6, 0x1d, + 0x5a, 0xbe, 0xe1, 0xb0, 0x4b, 0x90, 0xb3, 0x03, 0x77, 0xea, 0x38, 0xc4, 0x5e, 0xd0, 0x44, 0x8a, + 0x5d, 0x82, 0xac, 0xfd, 0xe4, 0xa5, 0xe1, 0x70, 0xde, 0xdd, 0x15, 0x8d, 0x27, 0x59, 0x15, 0x72, + 0xf6, 0xfb, 0x1f, 0x21, 0x22, 0x2d, 0x10, 0x22, 0x4d, 0x98, 0xc7, 0x8f, 0x10, 0x93, 0x89, 0x31, + 0x94, 0x26, 0xcc, 0x47, 0x1f, 0x20, 0x06, 0x5b, 0x9f, 0x26, 0x0c, 0xa5, 0xb1, 0x94, 0x29, 0x95, + 0x82, 0x1d, 0xb0, 0x86, 0xa5, 0x4c, 0xa3, 0x52, 0xa6, 0xbc, 0x94, 0xbc, 0x40, 0x88, 0x34, 0x61, + 0x78, 0x29, 0x85, 0x18, 0x13, 0x97, 0x32, 0xe5, 0xa5, 0x14, 0xb7, 0x52, 0xf7, 0x32, 0x84, 0xe1, + 0xa5, 0x6c, 0x42, 0xc6, 0x44, 0x38, 0x6c, 0xa5, 0xee, 0xa5, 0x76, 0x57, 0x34, 0x4a, 0x21, 0x34, + 0x40, 0x68, 0x09, 0x3b, 0x18, 0xa1, 0x81, 0x80, 0x0e, 0x10, 0x5a, 0xc6, 0xde, 0x40, 0xe8, 0x40, + 0x40, 0x47, 0x08, 0x5d, 0xdb, 0x4a, 0xdd, 0x5b, 0x45, 0x28, 0xa6, 0xd8, 0x55, 0xc8, 0x9b, 0x46, + 0x68, 0x21, 0xa2, 0x22, 0x9a, 0x1c, 0x01, 0x10, 0x87, 0x33, 0x0e, 0x71, 0xeb, 0xa2, 0xd1, 0x11, + 0x80, 0xa9, 0x50, 0x42, 0xb2, 0x08, 0xaf, 0x08, 0xbc, 0x0c, 0x64, 0x1f, 0x42, 0xd9, 0xb4, 0x86, + 0xf6, 0xd8, 0x70, 0x78, 0x9b, 0x36, 0xb6, 0x52, 0xf7, 0x4a, 0x8f, 0xd6, 0x1f, 0xd0, 0x9a, 0x88, + 0x31, 0xbb, 0x2b, 0x5a, 0x82, 0x8c, 0x3d, 0x81, 0x35, 0x91, 0x7e, 0xff, 0x11, 0x75, 0x2c, 0x23, + 0x3e, 0x25, 0xc1, 0xf7, 0xfe, 0xa3, 0x27, 0xbb, 0x2b, 0x5a, 0x92, 0x90, 0xdd, 0x81, 0x72, 0xbc, + 0x44, 0x90, 0xf1, 0x82, 0xa8, 0x55, 0x02, 0x8a, 0xcd, 0xfa, 0x32, 0xf0, 0x5c, 0x24, 0xd8, 0x14, + 0xfd, 0x16, 0x01, 0xd8, 0x16, 0x80, 0x69, 0x8d, 0x8c, 0xa9, 0x13, 0x22, 0xfa, 0xa2, 0xe8, 0x40, + 0x09, 0xc6, 0x6e, 0x40, 0x71, 0x3a, 0xc1, 0x56, 0x3e, 0x37, 0x9c, 0xea, 0x25, 0x41, 0x30, 0x03, + 0x61, 0xee, 0x38, 0xcf, 0x11, 0x7b, 0x59, 0x8c, 0x6e, 0x04, 0xc0, 0xe1, 0x7d, 0x69, 0x0d, 0x11, + 0x55, 0x15, 0x05, 0x8b, 0x34, 0xae, 0x22, 0x3b, 0xd8, 0xb6, 0xdd, 0xea, 0x15, 0x9a, 0xc1, 0x3c, + 0xc1, 0xae, 0x43, 0x3a, 0xf0, 0x87, 0xd5, 0xab, 0xd4, 0x7e, 0xe0, 0xed, 0x6f, 0x9e, 0x4e, 0x7c, + 0x0d, 0xc1, 0xdb, 0x79, 0xc8, 0xd2, 0x6a, 0x52, 0xaf, 0x43, 0x61, 0xdf, 0xf0, 0x8d, 0xb1, 0x66, + 0x8d, 0x98, 0x02, 0xe9, 0x89, 0x17, 0x88, 0x75, 0x84, 0x9f, 0x6a, 0x1b, 0x72, 0xcf, 0x0d, 0x1f, + 0x71, 0x0c, 0x32, 0xae, 0x31, 0xb6, 0x08, 0x59, 0xd4, 0xe8, 0x1b, 0xd7, 0x4e, 0x70, 0x16, 0x84, + 0xd6, 0x58, 0x08, 0x09, 0x91, 0x42, 0xf8, 0xa1, 0xe3, 0x0d, 0xc4, 0x1a, 0x29, 0x68, 0x22, 0xa5, + 0xfe, 0x7f, 0x29, 0xc8, 0xd5, 0x3d, 0x07, 0xb3, 0xbb, 0x0c, 0x79, 0xdf, 0x72, 0xf4, 0x59, 0x71, + 0x39, 0xdf, 0x72, 0xf6, 0xbd, 0x00, 0x11, 0x43, 0x8f, 0x23, 0xf8, 0xaa, 0xcd, 0x0d, 0x3d, 0x42, + 0x44, 0x15, 0x48, 0x4b, 0x15, 0xb8, 0x02, 0x85, 0x70, 0xe0, 0xe8, 0x04, 0xcf, 0x10, 0x3c, 0x1f, + 0x0e, 0x9c, 0x0e, 0xa2, 0x2e, 0x43, 0xde, 0x1c, 0x70, 0x4c, 0x96, 0x30, 0x39, 0x73, 0x80, 0x08, + 0xf5, 0x13, 0x28, 0x6a, 0xc6, 0x89, 0xa8, 0xc6, 0x45, 0xc8, 0x61, 0x06, 0x42, 0xfe, 0x65, 0xb4, + 0x6c, 0x38, 0x70, 0x5a, 0x26, 0x82, 0xb1, 0x12, 0xb6, 0x49, 0x75, 0xc8, 0x68, 0xd9, 0xa1, 0xe7, + 0xb4, 0x4c, 0xb5, 0x0f, 0x50, 0xf7, 0x7c, 0xff, 0x3b, 0x37, 0x61, 0x13, 0xb2, 0xa6, 0x35, 0x09, + 0x8f, 0xb8, 0xe8, 0xd0, 0x78, 0x42, 0xbd, 0x0f, 0x05, 0x1c, 0x97, 0xb6, 0x1d, 0x84, 0xec, 0x06, + 0x64, 0x1c, 0x3b, 0x08, 0xab, 0xa9, 0xad, 0xf4, 0xdc, 0xa8, 0x11, 0x5c, 0xdd, 0x82, 0xc2, 0x9e, + 0x71, 0xfa, 0x1c, 0x47, 0x0e, 0x73, 0xa3, 0x21, 0x14, 0x43, 0x22, 0xc6, 0xb3, 0x0c, 0xd0, 0x37, + 0xfc, 0x43, 0x2b, 0x24, 0x49, 0xf7, 0xdf, 0x53, 0x50, 0xea, 0x4d, 0x07, 0x5f, 0x4d, 0x2d, 0xff, + 0x0c, 0xeb, 0x7c, 0x0f, 0xd2, 0xe1, 0xd9, 0x84, 0x38, 0x2a, 0x8f, 0x2e, 0xf1, 0xec, 0x25, 0xfc, + 0x03, 0x64, 0xd2, 0x90, 0x04, 0x1b, 0xe1, 0x7a, 0xa6, 0x15, 0xf5, 0x41, 0x56, 0xcb, 0x61, 0xb2, + 0x65, 0xe2, 0x76, 0xe1, 0x4d, 0xc4, 0x28, 0xac, 0x7a, 0x13, 0xb6, 0x05, 0xd9, 0xe1, 0x91, 0xed, + 0x98, 0x34, 0x00, 0xc9, 0x3a, 0x73, 0x04, 0x8e, 0x92, 0xef, 0x9d, 0xe8, 0x81, 0xfd, 0x75, 0x24, + 0xfe, 0xf3, 0xbe, 0x77, 0xd2, 0xb3, 0xbf, 0xb6, 0xd4, 0xbe, 0xd8, 0x83, 0x00, 0x72, 0xbd, 0x7a, + 0xad, 0x5d, 0xd3, 0x94, 0x15, 0xfc, 0x6e, 0x7e, 0xde, 0xea, 0xf5, 0x7b, 0x4a, 0x8a, 0x55, 0x00, + 0x3a, 0xdd, 0xbe, 0x2e, 0xd2, 0xab, 0x2c, 0x07, 0xab, 0xad, 0x8e, 0x92, 0x46, 0x1a, 0x84, 0xb7, + 0x3a, 0x4a, 0x86, 0xe5, 0x21, 0x5d, 0xeb, 0x7c, 0xa1, 0x64, 0xe9, 0xa3, 0xdd, 0x56, 0x72, 0xea, + 0x9f, 0xad, 0x42, 0xb1, 0x3b, 0xf8, 0xd2, 0x1a, 0x86, 0xd8, 0x66, 0x9c, 0xa5, 0x96, 0xff, 0xd2, + 0xf2, 0xa9, 0xd9, 0x69, 0x4d, 0xa4, 0xb0, 0x21, 0xe6, 0x80, 0x1a, 0x97, 0xd6, 0x56, 0xcd, 0x01, + 0xd1, 0x0d, 0x8f, 0xac, 0xb1, 0x41, 0x8d, 0x43, 0x3a, 0x4a, 0xe1, 0xaa, 0xf0, 0x06, 0x5f, 0x52, + 0xf3, 0xd2, 0x1a, 0x7e, 0xb2, 0x9b, 0x50, 0xe2, 0x79, 0xc8, 0xf3, 0x0b, 0x38, 0x68, 0x7e, 0xf2, + 0xe5, 0xe4, 0xc9, 0x47, 0x9c, 0x94, 0x2b, 0x47, 0x8a, 0xbd, 0x8d, 0x83, 0x3a, 0x62, 0x46, 0x7b, + 0x83, 0x2f, 0x39, 0xb6, 0xc0, 0x67, 0xb4, 0x37, 0xf8, 0x92, 0x50, 0x6f, 0xc3, 0x46, 0x30, 0x1d, + 0x04, 0x43, 0xdf, 0x9e, 0x84, 0xb6, 0xe7, 0x72, 0x9a, 0x22, 0xd1, 0x28, 0x32, 0x82, 0x88, 0xef, + 0x41, 0x61, 0x32, 0x1d, 0xe8, 0xb6, 0x3b, 0xf2, 0x48, 0xec, 0x97, 0x1e, 0xad, 0xf1, 0x81, 0xd9, + 0x9f, 0x0e, 0x5a, 0xee, 0xc8, 0xd3, 0xf2, 0x13, 0xfe, 0xc1, 0x54, 0x58, 0x73, 0xbd, 0x50, 0x47, + 0x55, 0x41, 0x1f, 0x5b, 0xa1, 0x41, 0xfb, 0x01, 0xdf, 0xf0, 0xdb, 0xde, 0xf0, 0x78, 0xcf, 0x0a, + 0x0d, 0xf5, 0x2e, 0xe4, 0x05, 0x1f, 0xee, 0xfd, 0xa1, 0xe5, 0x1a, 0x6e, 0xa8, 0xc7, 0x4a, 0x43, + 0x81, 0x03, 0x5a, 0xa6, 0xfa, 0x47, 0x29, 0x50, 0x7a, 0x52, 0x55, 0x90, 0x79, 0xa9, 0xe4, 0x78, + 0x03, 0xc0, 0x18, 0x0e, 0xbd, 0x29, 0xcf, 0x86, 0x4f, 0xb0, 0xa2, 0x80, 0xb4, 0x4c, 0xb9, 0xff, + 0xd2, 0x89, 0xfe, 0xbb, 0x05, 0xe5, 0x88, 0x4f, 0x5a, 0xf4, 0x25, 0x01, 0x8b, 0x7a, 0x30, 0x98, + 0x26, 0x56, 0x7e, 0x3e, 0x98, 0x72, 0xee, 0x4b, 0x90, 0x23, 0x0d, 0x23, 0x88, 0x46, 0x85, 0xa7, + 0xd4, 0x7f, 0x9d, 0x82, 0xb5, 0x96, 0x6b, 0x5a, 0xa7, 0xbd, 0xa1, 0xe1, 0x46, 0x9d, 0x62, 0x07, + 0xba, 0x8d, 0x30, 0x3d, 0x18, 0x1a, 0xae, 0x50, 0x0e, 0x4a, 0x76, 0x10, 0xd3, 0x61, 0x1b, 0x38, + 0x01, 0x15, 0xb5, 0x4a, 0x39, 0x16, 0x09, 0x42, 0x85, 0xdd, 0x85, 0xf5, 0x81, 0xe5, 0x78, 0xee, + 0xa1, 0x1e, 0x7a, 0x3a, 0xd7, 0x72, 0x78, 0x5b, 0xd6, 0x38, 0xb8, 0xef, 0xf5, 0x49, 0xdb, 0xd9, + 0x84, 0xec, 0xc4, 0xf0, 0xc3, 0xa0, 0x9a, 0xd9, 0x4a, 0xe3, 0x32, 0xa6, 0x04, 0x76, 0xb3, 0x1d, + 0xe8, 0x53, 0xd7, 0xfe, 0x6a, 0xca, 0x9b, 0x51, 0xd0, 0x0a, 0x76, 0x70, 0x40, 0x69, 0x76, 0x0f, + 0x14, 0x5e, 0x32, 0x65, 0x2b, 0xcf, 0xb3, 0x0a, 0xc1, 0x29, 0x63, 0x12, 0x76, 0x7f, 0x69, 0x15, + 0x0a, 0x3b, 0x53, 0x77, 0x88, 0x83, 0xc1, 0x6e, 0x43, 0x66, 0x34, 0x75, 0x87, 0xd4, 0x96, 0x78, + 0x2b, 0x8d, 0xd7, 0x89, 0x46, 0x48, 0x94, 0x40, 0x86, 0x7f, 0x88, 0x92, 0x6b, 0x41, 0x02, 0x21, + 0x5c, 0xfd, 0x87, 0x29, 0x9e, 0xe3, 0x8e, 0x63, 0x1c, 0xb2, 0x02, 0x64, 0x3a, 0xdd, 0x4e, 0x53, + 0x59, 0x61, 0x65, 0x28, 0xb4, 0x3a, 0xfd, 0xa6, 0xd6, 0xa9, 0xb5, 0x95, 0x14, 0x2d, 0xe7, 0x7e, + 0x6d, 0xbb, 0xdd, 0x54, 0x56, 0x11, 0xf3, 0xbc, 0xdb, 0xae, 0xf5, 0x5b, 0xed, 0xa6, 0x92, 0xe1, + 0x18, 0xad, 0x55, 0xef, 0x2b, 0x05, 0xa6, 0x40, 0x79, 0x5f, 0xeb, 0x36, 0x0e, 0xea, 0x4d, 0xbd, + 0x73, 0xd0, 0x6e, 0x2b, 0x0a, 0xbb, 0x00, 0xeb, 0x31, 0xa4, 0xcb, 0x81, 0x5b, 0xc8, 0xf2, 0xbc, + 0xa6, 0xd5, 0xb4, 0xa7, 0xca, 0xa7, 0xac, 0x00, 0xe9, 0xda, 0xd3, 0xa7, 0xca, 0x4f, 0x51, 0x32, + 0x14, 0x5f, 0xb4, 0x3a, 0xfa, 0xf3, 0x5a, 0xfb, 0xa0, 0xa9, 0xfc, 0x74, 0x35, 0x4a, 0x77, 0xb5, + 0x46, 0x53, 0x53, 0x7e, 0x9a, 0x61, 0x1b, 0x50, 0xfe, 0x49, 0xb7, 0xd3, 0xdc, 0xab, 0xed, 0xef, + 0x53, 0x45, 0x7e, 0x5a, 0x50, 0xff, 0x73, 0x06, 0x32, 0xd8, 0x12, 0xa6, 0xce, 0xa4, 0x60, 0xdc, + 0x44, 0x14, 0x43, 0xdb, 0x99, 0x3f, 0xf9, 0xf3, 0x9b, 0x2b, 0x5c, 0xfe, 0xdd, 0x82, 0xb4, 0x63, + 0x87, 0x34, 0xac, 0xf1, 0xda, 0x11, 0x3a, 0xe3, 0xee, 0x8a, 0x86, 0x38, 0x76, 0x03, 0x52, 0x5c, + 0x10, 0x96, 0x1e, 0x55, 0xc4, 0xe2, 0x12, 0x3b, 0xe9, 0xee, 0x8a, 0x96, 0x9a, 0xb0, 0xeb, 0x90, + 0x7a, 0x29, 0xa4, 0x62, 0x99, 0xe3, 0xf9, 0x5e, 0x8a, 0xd8, 0x97, 0x6c, 0x0b, 0xd2, 0x43, 0x8f, + 0x6b, 0x84, 0x31, 0x9e, 0xef, 0x2c, 0x98, 0xff, 0xd0, 0x73, 0xd8, 0x6d, 0x48, 0xfb, 0xc6, 0x09, + 0x8d, 0x6c, 0x3c, 0x5c, 0xf1, 0xd6, 0x85, 0x44, 0xbe, 0x71, 0x82, 0x95, 0x18, 0x91, 0x1c, 0x89, + 0x2b, 0x11, 0x8d, 0x37, 0x16, 0x33, 0x62, 0x5b, 0x90, 0x3a, 0x21, 0x49, 0x12, 0x2b, 0x41, 0x2f, + 0x6c, 0xd7, 0xf4, 0x4e, 0x7a, 0x13, 0x6b, 0x88, 0x14, 0x27, 0xec, 0x4d, 0x48, 0x07, 0xd3, 0x01, + 0x49, 0x92, 0xd2, 0xa3, 0x8d, 0x85, 0x3d, 0x01, 0x0b, 0x0a, 0xa6, 0x03, 0x76, 0x17, 0x32, 0x43, + 0xcf, 0xf7, 0x85, 0x34, 0x51, 0xa2, 0x0a, 0x47, 0xdb, 0x21, 0x2a, 0x85, 0x88, 0xc7, 0x02, 0x43, + 0x92, 0x21, 0x31, 0xd1, 0x6c, 0x3f, 0xc2, 0x02, 0x43, 0x76, 0x47, 0x6c, 0x72, 0x65, 0xb9, 0xd6, + 0xd1, 0x16, 0x88, 0xf9, 0x20, 0x16, 0x07, 0x69, 0x6c, 0x9c, 0x92, 0xc6, 0x19, 0x13, 0x45, 0x7b, + 0x1f, 0xd6, 0x69, 0x6c, 0x9c, 0xb2, 0x3b, 0x90, 0x7e, 0x69, 0x0d, 0x49, 0xf9, 0x8c, 0x4b, 0x13, + 0x83, 0xf4, 0x9c, 0x9a, 0x87, 0x68, 0x9a, 0xf7, 0x9e, 0x63, 0x92, 0x1e, 0x1a, 0x8f, 0xe5, 0x8e, + 0xe7, 0x98, 0xcf, 0x69, 0x2c, 0x09, 0x89, 0x5b, 0xbe, 0x31, 0x3d, 0x45, 0x69, 0xa4, 0xf0, 0xcd, + 0xd9, 0x98, 0x9e, 0xb6, 0x4c, 0x14, 0xfe, 0xae, 0xf9, 0x92, 0xb4, 0xcf, 0x94, 0x86, 0x9f, 0x68, + 0x1e, 0x05, 0x96, 0x63, 0x0d, 0x43, 0xfb, 0xa5, 0x1d, 0x9e, 0x91, 0x7e, 0x99, 0xd2, 0x64, 0xd0, + 0x76, 0x0e, 0x32, 0xd6, 0xe9, 0xc4, 0x57, 0x77, 0x21, 0x2f, 0x4a, 0x59, 0xb0, 0xb1, 0xae, 0x40, + 0xc1, 0x0e, 0xf4, 0xa1, 0xe7, 0x06, 0xa1, 0xd0, 0x9d, 0xf2, 0x76, 0x50, 0xc7, 0x24, 0x8a, 0x4b, + 0xd3, 0x08, 0xf9, 0x26, 0x54, 0xd6, 0xe8, 0x5b, 0x7d, 0x04, 0x30, 0x6b, 0x16, 0xd6, 0xc9, 0xb1, + 0xdc, 0x48, 0x4d, 0x73, 0x2c, 0x37, 0xe6, 0x59, 0x95, 0x78, 0xae, 0x40, 0x31, 0xd6, 0x8c, 0x59, + 0x19, 0x52, 0x86, 0xd8, 0xfe, 0x52, 0x86, 0x7a, 0x0f, 0x15, 0xd5, 0x48, 0xf7, 0x4d, 0xe2, 0x30, + 0x15, 0x6d, 0x8a, 0xa9, 0x81, 0xfa, 0x03, 0x28, 0x6b, 0x56, 0x30, 0x75, 0xc2, 0xba, 0xe7, 0x34, + 0xac, 0x11, 0x7b, 0x07, 0x20, 0x4e, 0x07, 0x42, 0x4b, 0x99, 0xcd, 0xdd, 0x86, 0x35, 0xd2, 0x24, + 0xbc, 0xfa, 0xb7, 0x32, 0xa4, 0xef, 0x35, 0xb8, 0xa2, 0x25, 0x34, 0xaa, 0x94, 0xa4, 0x51, 0xc5, + 0x7b, 0xc3, 0x6a, 0x52, 0xab, 0x3c, 0xb2, 0x4d, 0xd3, 0x72, 0x23, 0xed, 0x91, 0xa7, 0x70, 0xb0, + 0x0d, 0xe7, 0x90, 0x16, 0x54, 0xe5, 0x11, 0x8b, 0x0a, 0x1d, 0x4f, 0x7c, 0x2b, 0x08, 0xb8, 0xde, + 0x62, 0x38, 0x87, 0xd1, 0xda, 0xce, 0xbe, 0x6a, 0x6d, 0x5f, 0x81, 0x02, 0x6e, 0x79, 0x64, 0xf5, + 0xe5, 0x78, 0xef, 0x0b, 0xf3, 0x96, 0xbd, 0x05, 0x79, 0xa1, 0xaf, 0x8b, 0x45, 0x25, 0xa6, 0x4b, + 0x83, 0x03, 0xb5, 0x08, 0xcb, 0xaa, 0xa8, 0xe4, 0x8d, 0xc7, 0x96, 0x1b, 0x46, 0xfb, 0xb4, 0x48, + 0xb2, 0xb7, 0xa1, 0xe8, 0xb9, 0x3a, 0x57, 0xea, 0xc5, 0xaa, 0x12, 0xd3, 0xb7, 0xeb, 0x1e, 0x10, + 0x54, 0x2b, 0x78, 0xe2, 0x0b, 0xab, 0xe2, 0x78, 0x27, 0xfa, 0xd0, 0xf0, 0x4d, 0x5a, 0x59, 0x05, + 0x2d, 0xef, 0x78, 0x27, 0x75, 0xc3, 0x37, 0xb9, 0xde, 0xf2, 0x95, 0x3b, 0x1d, 0xd3, 0x6a, 0x5a, + 0xd3, 0x44, 0x8a, 0x5d, 0x87, 0xe2, 0xd0, 0x99, 0x06, 0xa1, 0xe5, 0x6f, 0x9f, 0x71, 0x33, 0x4d, + 0x9b, 0x01, 0xb0, 0x5e, 0x13, 0xdf, 0x1e, 0x1b, 0xfe, 0x19, 0x2d, 0x9d, 0x82, 0x16, 0x25, 0x69, + 0xa3, 0x39, 0xb6, 0xcd, 0x53, 0x6e, 0xab, 0x69, 0x3c, 0x81, 0xf4, 0x47, 0x64, 0x49, 0x07, 0xb4, + 0x3e, 0x0a, 0x5a, 0x94, 0xa4, 0x71, 0xa0, 0x4f, 0x5a, 0x11, 0x45, 0x4d, 0xa4, 0x12, 0x4a, 0xf7, + 0xc6, 0xb9, 0x4a, 0x37, 0x9b, 0xd7, 0x7b, 0x3c, 0xdf, 0x3e, 0xb4, 0x85, 0xd6, 0x72, 0x81, 0xeb, + 0x3d, 0x1c, 0x44, 0x1b, 0xd5, 0x57, 0x90, 0x17, 0x5d, 0x8c, 0x3b, 0x10, 0x2e, 0x9f, 0xa4, 0x78, + 0xe6, 0x3b, 0x10, 0xc2, 0xd9, 0x6d, 0x58, 0x13, 0x79, 0x05, 0xa1, 0x6f, 0xbb, 0x87, 0x62, 0xf2, + 0x94, 0x39, 0xb0, 0x47, 0x30, 0x54, 0x14, 0x70, 0x78, 0x75, 0x63, 0x60, 0x3b, 0xb8, 0x4c, 0xd3, + 0x42, 0xa9, 0x99, 0x3a, 0x4e, 0x8d, 0x83, 0xd4, 0x2e, 0x14, 0xa2, 0x01, 0xf9, 0xa5, 0x94, 0xa9, + 0xfe, 0x66, 0x0a, 0x4a, 0xa4, 0x1e, 0x74, 0x49, 0xf9, 0x61, 0xef, 0x00, 0x1b, 0xfa, 0x96, 0x11, + 0x5a, 0xba, 0x75, 0x1a, 0xfa, 0x86, 0x50, 0x02, 0xb8, 0x26, 0xa1, 0x70, 0x4c, 0x13, 0x11, 0x5c, + 0x0f, 0xb8, 0x09, 0xa5, 0x89, 0xe1, 0x07, 0x91, 0x52, 0xc9, 0x0b, 0x00, 0x0e, 0x12, 0x2a, 0x9d, + 0xe2, 0x1e, 0xfa, 0xc6, 0x58, 0x0f, 0xbd, 0x63, 0xcb, 0xe5, 0xea, 0x34, 0x37, 0x24, 0x2a, 0x04, + 0xef, 0x23, 0x98, 0xb4, 0xea, 0x7f, 0x9b, 0x82, 0xb5, 0x7d, 0x3e, 0xea, 0xcf, 0xac, 0xb3, 0x06, + 0xb7, 0xde, 0x86, 0xd1, 0x8a, 0xcd, 0x68, 0xf4, 0xcd, 0x6e, 0x40, 0x69, 0x72, 0x6c, 0x9d, 0xe9, + 0x09, 0x4b, 0xa7, 0x88, 0xa0, 0x3a, 0xad, 0xcd, 0xef, 0x41, 0xce, 0xa3, 0x86, 0x88, 0x3d, 0x4e, + 0x6c, 0x0d, 0x52, 0x0b, 0x35, 0x41, 0x80, 0xea, 0x52, 0x9c, 0x95, 0xac, 0x97, 0x89, 0xcc, 0xa8, + 0xfa, 0x9b, 0x90, 0x45, 0x54, 0x50, 0xcd, 0x72, 0x3d, 0x87, 0x12, 0xec, 0x3d, 0x58, 0x1b, 0x7a, + 0xe3, 0x89, 0x1e, 0xb1, 0x8b, 0xdd, 0x2e, 0x29, 0x53, 0x4a, 0x48, 0xb2, 0xcf, 0xf3, 0x52, 0x7f, + 0x2f, 0x0d, 0x05, 0xaa, 0x83, 0x10, 0x2b, 0xb6, 0x79, 0x1a, 0x89, 0x95, 0xa2, 0x96, 0xb5, 0x4d, + 0x94, 0xda, 0xaf, 0x51, 0xcd, 0x62, 0x95, 0x2b, 0x2d, 0xab, 0x5c, 0x97, 0x20, 0x27, 0xf4, 0xad, + 0x0c, 0x97, 0x3b, 0xd3, 0xf3, 0xb5, 0xad, 0xec, 0x32, 0x6d, 0x0b, 0x87, 0x90, 0xd3, 0x58, 0xa7, + 0xb8, 0xbf, 0x71, 0xd1, 0x02, 0x04, 0x6a, 0x22, 0x44, 0x16, 0x1a, 0xf9, 0xa4, 0xd0, 0xa8, 0x42, + 0xfe, 0xa5, 0x1d, 0xd8, 0x38, 0x41, 0x0a, 0x7c, 0x19, 0x8a, 0xa4, 0x34, 0x0c, 0xc5, 0xd7, 0x0d, + 0x43, 0xdc, 0x6c, 0xc3, 0x39, 0xe4, 0x6a, 0x7f, 0xd4, 0xec, 0x9a, 0x73, 0xe8, 0xb1, 0xf7, 0xe1, + 0xe2, 0x0c, 0x2d, 0x5a, 0x43, 0xee, 0x31, 0xf2, 0x00, 0x69, 0x2c, 0xa6, 0xa4, 0x16, 0x91, 0x5d, + 0x76, 0x1f, 0x36, 0x24, 0x96, 0x09, 0xaa, 0x37, 0x01, 0xc9, 0x9c, 0xa2, 0xb6, 0x1e, 0x93, 0x93, + 0xd6, 0x13, 0xa8, 0xff, 0x74, 0x15, 0xd6, 0x76, 0x3c, 0xdf, 0xb2, 0x0f, 0xdd, 0xd9, 0xac, 0x5b, + 0xd0, 0xfc, 0xa3, 0x99, 0xb8, 0x2a, 0xcd, 0xc4, 0x9b, 0x50, 0x1a, 0x71, 0x46, 0x3d, 0x1c, 0x70, + 0xa7, 0x41, 0x46, 0x03, 0x01, 0xea, 0x0f, 0x1c, 0x5c, 0xcd, 0x11, 0x01, 0x31, 0x67, 0x88, 0x39, + 0x62, 0xc2, 0xbd, 0x86, 0x7d, 0x9f, 0xa4, 0xae, 0x69, 0x39, 0x56, 0xc8, 0x87, 0xa7, 0xf2, 0xe8, + 0x8d, 0x68, 0xa7, 0x97, 0xea, 0xf4, 0x40, 0xb3, 0x46, 0x35, 0x52, 0x8f, 0x50, 0x08, 0x37, 0x88, + 0x5c, 0xf0, 0x0a, 0x89, 0x9d, 0xfb, 0x86, 0xbc, 0x5c, 0x72, 0xa8, 0x7d, 0x28, 0xc6, 0x60, 0xd4, + 0x75, 0xb5, 0xa6, 0xd0, 0x6f, 0x57, 0x58, 0x09, 0xf2, 0xf5, 0x5a, 0xaf, 0x5e, 0x6b, 0x34, 0x95, + 0x14, 0xa2, 0x7a, 0xcd, 0x3e, 0xd7, 0x69, 0x57, 0xd9, 0x3a, 0x94, 0x30, 0xd5, 0x68, 0xee, 0xd4, + 0x0e, 0xda, 0x7d, 0x25, 0xcd, 0xd6, 0xa0, 0xd8, 0xe9, 0xea, 0xb5, 0x7a, 0xbf, 0xd5, 0xed, 0x28, + 0x19, 0xf5, 0x53, 0x28, 0xd4, 0x8f, 0xac, 0xe1, 0xf1, 0x79, 0xbd, 0x48, 0x46, 0xb7, 0x35, 0x3c, + 0x16, 0xfa, 0xe9, 0x9c, 0xd1, 0x6d, 0x0d, 0x8f, 0xd5, 0x26, 0x14, 0xf7, 0x0d, 0x3f, 0xb4, 0xa9, + 0x5e, 0x4f, 0x60, 0x2d, 0x4e, 0x34, 0xac, 0x51, 0xb4, 0x73, 0xb3, 0x58, 0x6b, 0x8d, 0x51, 0x5a, + 0x92, 0x50, 0x7d, 0x07, 0xca, 0x32, 0x80, 0x5d, 0x87, 0xb4, 0x69, 0x8d, 0x96, 0xc8, 0x49, 0x04, + 0xab, 0xcf, 0xa1, 0x5c, 0x8f, 0x76, 0xa2, 0xf3, 0xaa, 0xfe, 0x08, 0x2a, 0xb4, 0xe2, 0x87, 0x83, + 0x68, 0xc9, 0xaf, 0x2e, 0x59, 0xf2, 0x65, 0xa4, 0xa9, 0x0f, 0xc4, 0x9a, 0xff, 0x10, 0x4a, 0xfb, + 0xbe, 0x37, 0xb1, 0xfc, 0x90, 0xb2, 0x55, 0x20, 0x7d, 0x6c, 0x9d, 0x89, 0x5c, 0xf1, 0x73, 0xe6, + 0x0b, 0x59, 0x95, 0x7d, 0x21, 0x8f, 0xa0, 0x10, 0xb1, 0x7d, 0x63, 0x9e, 0x1f, 0xa1, 0xe8, 0x24, + 0x1e, 0xdb, 0x0a, 0xb0, 0xb0, 0x07, 0x00, 0x93, 0x18, 0x20, 0x3a, 0x2e, 0x52, 0xf7, 0x45, 0xe6, + 0x9a, 0x44, 0xa1, 0xbe, 0x01, 0xf9, 0xe7, 0xb6, 0x75, 0x22, 0x9a, 0xff, 0xd2, 0xb6, 0x4e, 0xa2, + 0xe6, 0xe3, 0xb7, 0xfa, 0x97, 0x8b, 0x50, 0xa0, 0xf5, 0xd5, 0x38, 0xdf, 0xfd, 0xf4, 0x6d, 0xb4, + 0xa2, 0x2d, 0xb1, 0x9e, 0x32, 0x4b, 0x74, 0x31, 0xbe, 0xba, 0xde, 0x00, 0x90, 0xd6, 0x3a, 0x97, + 0x5c, 0xc5, 0x30, 0x5e, 0xe2, 0xa8, 0x4e, 0xd0, 0x5e, 0x14, 0x7c, 0xe5, 0x08, 0x2b, 0x72, 0x06, + 0x60, 0x0f, 0xf8, 0x66, 0x4f, 0x76, 0x23, 0x57, 0x88, 0x2e, 0x44, 0x4a, 0xfd, 0xc0, 0xb1, 0x22, + 0x53, 0x83, 0x34, 0x00, 0x4c, 0x90, 0x1c, 0xb3, 0xfc, 0x00, 0xc5, 0x15, 0xf9, 0xa7, 0xb5, 0x28, + 0xc9, 0xde, 0x82, 0x0c, 0x0a, 0x79, 0x61, 0x1a, 0x5c, 0x88, 0x7a, 0x50, 0xda, 0xa5, 0x34, 0x22, + 0x60, 0xf7, 0x20, 0x4f, 0xa2, 0xc5, 0x42, 0x49, 0x23, 0xf5, 0x76, 0x24, 0xf4, 0xb5, 0x08, 0xcd, + 0xbe, 0x07, 0xd9, 0xd1, 0xb1, 0x75, 0x16, 0x54, 0xd7, 0x88, 0xee, 0xc2, 0x92, 0x35, 0xab, 0x71, + 0x0a, 0x76, 0x07, 0x2a, 0xbe, 0x35, 0xd2, 0xc9, 0x21, 0x85, 0x42, 0x26, 0xa8, 0x56, 0x48, 0x86, + 0x94, 0x7d, 0x6b, 0x54, 0x47, 0x60, 0x7f, 0xe0, 0x04, 0xec, 0x2e, 0xe4, 0x68, 0xf5, 0xa0, 0x2e, + 0x24, 0x95, 0x1c, 0x2d, 0x45, 0x4d, 0x60, 0xd9, 0xfb, 0x00, 0x42, 0xe3, 0xd2, 0x07, 0x67, 0xe4, + 0xc8, 0x8d, 0x17, 0x93, 0x3c, 0xff, 0x65, 0xbd, 0xec, 0x2d, 0xc8, 0xe2, 0x24, 0x09, 0xaa, 0x97, + 0x29, 0xe7, 0x8d, 0xe4, 0x0c, 0xa2, 0x9a, 0x12, 0x9e, 0xdd, 0x83, 0x02, 0x4e, 0x14, 0x1d, 0x87, + 0xa3, 0x2a, 0xab, 0xa0, 0x62, 0x56, 0xe1, 0xce, 0x60, 0x9d, 0xf4, 0xbe, 0x72, 0xd8, 0x7d, 0xc8, + 0x98, 0xb8, 0x98, 0xaf, 0x50, 0x8e, 0x97, 0xa4, 0x71, 0x41, 0x61, 0xd5, 0xb0, 0x46, 0xa4, 0x15, + 0x13, 0x0d, 0xdb, 0x85, 0x0a, 0x4e, 0xa3, 0x47, 0xb4, 0xd9, 0x63, 0xf7, 0x55, 0xaf, 0x12, 0xd7, + 0xad, 0x39, 0xae, 0x8e, 0x20, 0xa2, 0xce, 0x6e, 0xba, 0xa1, 0x7f, 0xa6, 0xad, 0xb9, 0x32, 0x8c, + 0x5d, 0x45, 0xd3, 0xa5, 0xed, 0x0d, 0x8f, 0x2d, 0xb3, 0x7a, 0x2d, 0x72, 0x4c, 0xf0, 0x34, 0xfb, + 0x04, 0xd6, 0x68, 0x62, 0x61, 0x12, 0x0b, 0xaf, 0x5e, 0x27, 0x61, 0x2a, 0x4f, 0x99, 0x08, 0xa5, + 0x25, 0x29, 0x51, 0xc4, 0xdb, 0x81, 0x1e, 0x5a, 0xe3, 0x89, 0xe7, 0xa3, 0xf2, 0xfa, 0x46, 0xe4, + 0x70, 0xe9, 0x47, 0x20, 0xdc, 0x88, 0xe3, 0x63, 0x27, 0xdd, 0x1b, 0x8d, 0x02, 0x2b, 0xac, 0xde, + 0xa0, 0x75, 0x53, 0x89, 0x4e, 0x9f, 0xba, 0x04, 0xa5, 0x8d, 0x30, 0xd0, 0xcd, 0x33, 0xd7, 0x18, + 0xdb, 0xc3, 0xea, 0x4d, 0xae, 0x23, 0xdb, 0x41, 0x83, 0x03, 0x64, 0x35, 0x75, 0x2b, 0xa1, 0xa6, + 0x5e, 0x80, 0xac, 0x39, 0xc0, 0xe5, 0x78, 0x8b, 0xb2, 0xcd, 0x98, 0x83, 0x96, 0xc9, 0xde, 0x85, + 0xe2, 0x24, 0x12, 0x81, 0x55, 0x55, 0x36, 0xc6, 0x63, 0xc9, 0xa8, 0xcd, 0x28, 0xd0, 0x3e, 0xdc, + 0xb1, 0x8c, 0x70, 0xea, 0x5b, 0x3b, 0x8e, 0x71, 0x58, 0xbd, 0x4d, 0x39, 0xc9, 0xa0, 0xab, 0x4f, + 0x49, 0xd7, 0xa5, 0x56, 0x7f, 0x38, 0x27, 0x5c, 0x12, 0x4b, 0x43, 0x92, 0x42, 0xbb, 0x2b, 0xb2, + 0x8c, 0xd9, 0xce, 0x92, 0x14, 0xbe, 0xfa, 0x29, 0xb0, 0xc5, 0xf1, 0x7a, 0x9d, 0xa4, 0xcb, 0x0a, + 0x49, 0xf7, 0xfd, 0xd5, 0x27, 0x29, 0xf5, 0x39, 0xac, 0x25, 0x16, 0xf2, 0x52, 0x89, 0xcd, 0xd5, + 0x25, 0x63, 0x2c, 0xcc, 0x4b, 0x9e, 0x10, 0x1e, 0xaa, 0xc0, 0x76, 0x0f, 0x85, 0x67, 0x8b, 0x26, + 0x42, 0x8f, 0xd2, 0xea, 0x9f, 0xa5, 0xa1, 0xbc, 0x6b, 0x04, 0x47, 0x7b, 0xc6, 0xa4, 0x17, 0x1a, + 0x61, 0x80, 0xc3, 0x7b, 0x64, 0x04, 0x47, 0x63, 0x63, 0xc2, 0x15, 0xd7, 0x14, 0x37, 0x9b, 0x05, + 0x0c, 0xb5, 0x56, 0x9c, 0x58, 0x98, 0xec, 0xba, 0xfb, 0xcf, 0x84, 0x4d, 0x1c, 0xa7, 0x51, 0xac, + 0x04, 0x47, 0xd3, 0xd1, 0x28, 0x2e, 0x2a, 0x4a, 0xb2, 0x3b, 0xb0, 0x26, 0x3e, 0x49, 0x6b, 0x3d, + 0x15, 0xc7, 0x8e, 0x49, 0x20, 0x7b, 0x0c, 0x25, 0x01, 0xe8, 0x47, 0x42, 0xb0, 0x12, 0xfb, 0x3a, + 0x66, 0x08, 0x4d, 0xa6, 0x62, 0x3f, 0x86, 0x8b, 0x52, 0x72, 0xc7, 0xf3, 0xf7, 0xa6, 0x4e, 0x68, + 0xd7, 0x3b, 0x42, 0x45, 0xb8, 0xb6, 0xc0, 0x3e, 0x23, 0xd1, 0x96, 0x73, 0x26, 0x6b, 0xbb, 0x67, + 0xbb, 0x24, 0x53, 0xd3, 0x5a, 0x12, 0x38, 0x47, 0x65, 0x9c, 0x92, 0x28, 0x4d, 0x52, 0x19, 0xa7, + 0xb8, 0xd8, 0x04, 0x60, 0xcf, 0x0a, 0x8f, 0x3c, 0x93, 0xf4, 0xc3, 0x78, 0xb1, 0xf5, 0x64, 0x94, + 0x96, 0xa4, 0xc4, 0xee, 0x44, 0x4b, 0x68, 0xe8, 0x86, 0xa4, 0x25, 0xa6, 0xb5, 0x28, 0x89, 0xdb, + 0x8c, 0x6f, 0xb8, 0x87, 0x56, 0x50, 0x2d, 0x6d, 0xa5, 0xef, 0xa5, 0x34, 0x91, 0x52, 0xff, 0x70, + 0x15, 0xb2, 0x7c, 0x24, 0xaf, 0x41, 0x71, 0x40, 0xce, 0x62, 0xb4, 0x4c, 0x85, 0x03, 0x98, 0x00, + 0x9d, 0xe9, 0x98, 0x6b, 0x77, 0xc2, 0xa7, 0x91, 0xd2, 0xe8, 0x1b, 0xb3, 0xf4, 0xa6, 0x21, 0x96, + 0x95, 0x26, 0xa8, 0x48, 0x61, 0x25, 0x7c, 0xef, 0x84, 0x66, 0x43, 0x86, 0x10, 0x51, 0x92, 0x7c, + 0xcc, 0xb4, 0x63, 0x21, 0x53, 0x96, 0x70, 0x05, 0x02, 0xd4, 0xdd, 0x70, 0xde, 0xff, 0x92, 0x5b, + 0xf0, 0xbf, 0xb0, 0x1b, 0x80, 0xba, 0xe3, 0xd0, 0xea, 0xba, 0x56, 0xbd, 0x43, 0x3d, 0x5c, 0xd0, + 0x24, 0x08, 0x2e, 0x10, 0xd3, 0x9b, 0x50, 0xa7, 0x66, 0x35, 0xfc, 0x64, 0x1f, 0xc5, 0xb3, 0x93, + 0xda, 0x28, 0x34, 0x6d, 0x21, 0xd1, 0xe5, 0x79, 0xac, 0x25, 0xe8, 0x30, 0x27, 0x14, 0xd3, 0x5c, + 0xd3, 0xc6, 0x4f, 0xb5, 0x09, 0xa0, 0x79, 0x27, 0x81, 0x15, 0x92, 0xa3, 0xf1, 0x32, 0x35, 0x31, + 0x71, 0x44, 0xe4, 0x9d, 0xec, 0x7b, 0x41, 0x6c, 0x6f, 0xae, 0x2e, 0xb7, 0x37, 0xd5, 0x87, 0x90, + 0xc7, 0x3d, 0xdc, 0x08, 0x0d, 0x76, 0x47, 0xf8, 0x76, 0xb8, 0xe6, 0x21, 0x9c, 0x5c, 0xb3, 0x32, + 0x84, 0xb7, 0xa7, 0x1d, 0x95, 0x4b, 0x3c, 0xb7, 0x24, 0x73, 0x2f, 0xde, 0x3f, 0x44, 0x86, 0x42, + 0x2b, 0xb8, 0x06, 0x45, 0xac, 0x1a, 0xf9, 0xcd, 0x85, 0x5c, 0x28, 0xf8, 0xde, 0x49, 0x1d, 0xd3, + 0xea, 0xbf, 0x4b, 0x41, 0xa9, 0xeb, 0x9b, 0xb8, 0x71, 0xf5, 0x26, 0xd6, 0xf0, 0xb5, 0xe6, 0x31, + 0xea, 0x10, 0x9e, 0xe3, 0x18, 0x24, 0x22, 0x85, 0xb9, 0x15, 0x03, 0xd8, 0xfb, 0x90, 0x19, 0xa1, + 0x28, 0x4c, 0xcb, 0x9a, 0xb5, 0x94, 0x7d, 0xf4, 0x8d, 0xc2, 0x51, 0x23, 0x52, 0xf5, 0xd7, 0xe2, + 0xf2, 0xc9, 0xcf, 0x2c, 0x7b, 0x97, 0x57, 0xe8, 0x9c, 0xa7, 0x57, 0x57, 0x52, 0xac, 0x00, 0x99, + 0x46, 0xb3, 0x57, 0xe7, 0xfa, 0x34, 0x6a, 0xd6, 0x3d, 0x7d, 0xa7, 0xa5, 0xf5, 0xfa, 0x4a, 0x86, + 0x0e, 0x8e, 0x08, 0xd0, 0xae, 0xf5, 0xfa, 0x4a, 0x81, 0x01, 0xe4, 0x0e, 0x3a, 0xad, 0x1f, 0x1f, + 0x34, 0x15, 0x45, 0xfd, 0x97, 0x29, 0x80, 0x99, 0x13, 0x94, 0xbd, 0x0d, 0xa5, 0x13, 0x4a, 0xe9, + 0x92, 0x77, 0x5c, 0x6e, 0x23, 0x70, 0x34, 0xe9, 0x37, 0xef, 0x42, 0x39, 0x16, 0xf5, 0xb8, 0xf7, + 0x2f, 0xba, 0xc9, 0x4b, 0x31, 0x7e, 0xfb, 0x8c, 0xbd, 0x03, 0x05, 0x0f, 0xdb, 0x81, 0xa4, 0x69, + 0x79, 0xe3, 0x97, 0x9a, 0xaf, 0xe5, 0x3d, 0x9e, 0x40, 0x1d, 0x61, 0xe4, 0x47, 0xe6, 0x73, 0x4c, + 0xba, 0x83, 0xa0, 0xba, 0x63, 0x4c, 0x03, 0x4b, 0xe3, 0xf8, 0x58, 0x4a, 0x67, 0x67, 0x52, 0x5a, + 0xfd, 0x09, 0x54, 0x7a, 0xc6, 0x78, 0xc2, 0x65, 0x39, 0x35, 0x8c, 0x41, 0x06, 0xe7, 0x84, 0x98, + 0x7a, 0xf4, 0x8d, 0x8b, 0x6e, 0xdf, 0xf2, 0x87, 0x96, 0x1b, 0xad, 0xd1, 0x28, 0x89, 0xe2, 0xf7, + 0x00, 0xa5, 0xb9, 0xe6, 0x9d, 0x44, 0xe2, 0x3c, 0x4a, 0xab, 0x7f, 0x27, 0x05, 0x25, 0xa9, 0x1a, + 0xec, 0x21, 0x64, 0x48, 0x99, 0x4c, 0xc9, 0x82, 0x50, 0x22, 0xe0, 0xdf, 0x5c, 0xfd, 0x40, 0x42, + 0x76, 0x17, 0xb2, 0x41, 0x68, 0xf8, 0x91, 0x3f, 0x5d, 0x91, 0x38, 0xb6, 0xbd, 0xa9, 0x6b, 0x6a, + 0x1c, 0xcd, 0x54, 0x48, 0x5b, 0xae, 0x29, 0x1c, 0x0e, 0x8b, 0x54, 0x88, 0x54, 0xb7, 0xa0, 0x18, + 0x67, 0x8f, 0x53, 0x40, 0xeb, 0xbe, 0xe8, 0x29, 0x2b, 0xac, 0x08, 0x59, 0xad, 0xd6, 0x79, 0xda, + 0x54, 0x52, 0xea, 0x1f, 0xa5, 0x00, 0x66, 0x5c, 0xec, 0x41, 0xa2, 0xb6, 0x57, 0xe7, 0x73, 0x7d, + 0x40, 0x7f, 0xa5, 0xca, 0x5e, 0x87, 0xe2, 0xd4, 0x25, 0xa0, 0x65, 0x8a, 0x9d, 0x68, 0x06, 0x40, + 0x0b, 0x28, 0x8a, 0xfe, 0x98, 0xb3, 0x80, 0x5e, 0x1a, 0x8e, 0xfa, 0x7d, 0x28, 0xc6, 0xd9, 0xa1, + 0x51, 0xb7, 0xd3, 0x6d, 0xb7, 0xbb, 0x2f, 0x5a, 0x9d, 0xa7, 0xca, 0x0a, 0x26, 0xf7, 0xb5, 0x66, + 0xbd, 0xd9, 0xc0, 0x64, 0x0a, 0xe7, 0x6c, 0xfd, 0x40, 0xd3, 0x9a, 0x9d, 0xbe, 0xae, 0x75, 0x5f, + 0x28, 0xab, 0xea, 0xff, 0x9f, 0x81, 0x8d, 0xae, 0xdb, 0x98, 0x4e, 0x1c, 0x7b, 0x68, 0x84, 0xd6, + 0x33, 0xeb, 0xac, 0x1e, 0x9e, 0xe2, 0xee, 0x6b, 0x84, 0xa1, 0xcf, 0x17, 0x73, 0x51, 0xe3, 0x09, + 0xee, 0x94, 0x08, 0x2c, 0x3f, 0x24, 0x9f, 0x8b, 0xbc, 0x8a, 0x2b, 0x1c, 0x5e, 0xf7, 0x1c, 0x5a, + 0xcb, 0xec, 0x87, 0x70, 0x91, 0x3b, 0x32, 0x38, 0x25, 0x2a, 0xb0, 0x3a, 0x2d, 0xe6, 0xf4, 0xc2, + 0xd4, 0x65, 0x9c, 0x10, 0x59, 0x91, 0x8c, 0x44, 0xd8, 0x4d, 0x28, 0xcd, 0xd8, 0xa3, 0x43, 0x2a, + 0x88, 0x09, 0xa9, 0x26, 0x68, 0x78, 0x47, 0xb5, 0xd6, 0x6d, 0xf3, 0x94, 0x5c, 0x3c, 0x59, 0xad, + 0xe2, 0xcd, 0x1a, 0x83, 0x9b, 0xf0, 0xe7, 0xb0, 0x91, 0xa0, 0xa4, 0x5a, 0xe4, 0xa8, 0x16, 0xef, + 0x44, 0x0e, 0xd2, 0xb9, 0xd6, 0xcb, 0x10, 0xac, 0x0e, 0xd7, 0x48, 0xd7, 0xbd, 0x24, 0x54, 0xe8, + 0x22, 0xf6, 0xa1, 0xeb, 0xf9, 0x96, 0x10, 0xf8, 0x05, 0x3b, 0x68, 0x51, 0x7a, 0x66, 0xff, 0x48, + 0x87, 0xaa, 0x7c, 0x7f, 0x89, 0xce, 0x0b, 0x39, 0xda, 0xe6, 0x3b, 0x68, 0x46, 0xcb, 0x53, 0xba, + 0x65, 0xb2, 0xdb, 0x42, 0x9d, 0xd5, 0x23, 0x93, 0x06, 0xc8, 0xa4, 0x29, 0x13, 0xf0, 0x39, 0x87, + 0x5d, 0xed, 0xc0, 0xe6, 0xb2, 0x4a, 0x2e, 0x51, 0xc3, 0xb6, 0x64, 0x35, 0x6c, 0xce, 0x68, 0x9f, + 0xa9, 0x64, 0x7f, 0x2f, 0x05, 0xe5, 0x86, 0x65, 0x4e, 0x27, 0x9f, 0x79, 0xb6, 0x8b, 0x13, 0xe0, + 0x03, 0x28, 0x7b, 0x8e, 0x49, 0xa3, 0x27, 0xc5, 0x06, 0x24, 0x4e, 0x8c, 0x84, 0x73, 0x1b, 0x3c, + 0xc7, 0xac, 0x7b, 0x0e, 0x45, 0x12, 0xbc, 0x0b, 0x17, 0xb8, 0x43, 0x43, 0xf8, 0xf7, 0x4e, 0x39, + 0xf3, 0x2a, 0x8d, 0x8c, 0xc2, 0x51, 0x5c, 0x39, 0x22, 0xf2, 0x5f, 0x81, 0x4d, 0x89, 0x1c, 0x47, + 0x86, 0xd3, 0x2f, 0x4e, 0x92, 0x8d, 0x98, 0x37, 0x3a, 0xb2, 0x51, 0x7f, 0x6b, 0x15, 0x8a, 0xdc, + 0x1d, 0x82, 0xf5, 0xbd, 0x07, 0x79, 0x6f, 0xf0, 0xa5, 0xee, 0xc7, 0x6e, 0x82, 0x85, 0x93, 0xc6, + 0x9c, 0x37, 0xf8, 0x52, 0xb3, 0x46, 0xec, 0xed, 0x68, 0x9f, 0x37, 0xad, 0x91, 0xe8, 0x94, 0x4a, + 0xd2, 0x1e, 0x11, 0xfb, 0x3e, 0xda, 0xca, 0x8f, 0xa1, 0x34, 0x9b, 0xf1, 0x41, 0x35, 0x7f, 0x7e, + 0x2f, 0xc4, 0x0b, 0x20, 0x40, 0x26, 0xee, 0x12, 0xe2, 0x4c, 0x85, 0xf3, 0x99, 0x38, 0x19, 0x31, + 0x7d, 0x02, 0x95, 0x99, 0x8c, 0x27, 0xbe, 0xe2, 0xb9, 0x7c, 0x6b, 0x31, 0x25, 0x9d, 0x78, 0xfc, + 0xfd, 0x14, 0x14, 0x5b, 0xbc, 0xf8, 0xf0, 0x94, 0xdd, 0x82, 0xf4, 0x2b, 0x7a, 0x01, 0x71, 0xec, + 0x3e, 0x6c, 0x18, 0xa6, 0xa9, 0x1b, 0xa3, 0x91, 0x35, 0x0c, 0x2d, 0x53, 0x47, 0x15, 0x48, 0xc8, + 0x9c, 0x75, 0xc3, 0x34, 0x6b, 0x02, 0x4e, 0xb2, 0x1b, 0xd7, 0x7c, 0xa0, 0x47, 0x86, 0xe7, 0xec, + 0x48, 0xb9, 0xa0, 0x55, 0xec, 0x40, 0xd8, 0x9d, 0xdc, 0x97, 0x9c, 0xe8, 0xd8, 0xcc, 0xab, 0x3b, + 0x56, 0xfd, 0xdd, 0x55, 0x00, 0xcd, 0x9a, 0x38, 0xc6, 0xd0, 0xfa, 0xbf, 0xa6, 0xd2, 0x28, 0x96, + 0xe2, 0x81, 0x75, 0xcd, 0x28, 0x04, 0x23, 0x1a, 0x44, 0xd7, 0x64, 0x9f, 0xc2, 0x1b, 0xbe, 0x75, + 0xe2, 0xdb, 0xa1, 0xa5, 0x8f, 0x7c, 0x6f, 0xac, 0x27, 0x24, 0x0f, 0x2e, 0xcc, 0x22, 0x55, 0xe2, + 0x8a, 0x20, 0xda, 0xf1, 0xbd, 0x71, 0x52, 0xfa, 0xa8, 0xff, 0x04, 0xa0, 0x54, 0x73, 0x0d, 0xe7, + 0xec, 0x6b, 0x8b, 0x62, 0x02, 0xc8, 0xbb, 0x3a, 0x99, 0x86, 0xbc, 0xb9, 0xfc, 0xc0, 0xac, 0x48, + 0x10, 0x6a, 0xe8, 0x4d, 0x28, 0x79, 0xd3, 0x30, 0xc6, 0xf3, 0x23, 0x34, 0xe0, 0x20, 0x22, 0x88, + 0xf9, 0x63, 0xcf, 0x7d, 0xc4, 0x4f, 0xe6, 0xcf, 0x8c, 0x3f, 0x56, 0x89, 0x63, 0x7e, 0x22, 0x40, + 0x69, 0x64, 0x8f, 0xa9, 0xc1, 0xc1, 0x74, 0x6c, 0xf1, 0x46, 0xa7, 0x79, 0x7c, 0x5a, 0x5d, 0xc0, + 0x30, 0x97, 0xb1, 0x35, 0xf6, 0xfc, 0x33, 0x9e, 0x4b, 0x8e, 0xe7, 0xc2, 0x41, 0x94, 0xcb, 0x3b, + 0xc0, 0x4e, 0x0c, 0x3b, 0xd4, 0x93, 0x59, 0x71, 0x33, 0x44, 0x41, 0x4c, 0x5f, 0xce, 0xee, 0x12, + 0xe4, 0x4c, 0x3b, 0x38, 0x6e, 0x75, 0x85, 0x09, 0x22, 0x52, 0xd8, 0x96, 0x60, 0x68, 0xa0, 0x06, + 0x14, 0x5a, 0x5c, 0x5d, 0x4e, 0x6b, 0x45, 0x84, 0x6c, 0x23, 0x00, 0x77, 0x50, 0xd7, 0x0a, 0x4f, + 0x3c, 0x1f, 0x39, 0xb9, 0x85, 0x31, 0x03, 0xa0, 0xa6, 0x81, 0xa4, 0x58, 0x10, 0x79, 0x83, 0xd2, + 0x5a, 0x9c, 0x46, 0xdd, 0x9d, 0x2f, 0x5f, 0xc2, 0x96, 0x79, 0xf5, 0x67, 0x10, 0x76, 0x07, 0x2a, + 0x54, 0x7d, 0xb2, 0x40, 0xb0, 0x0d, 0x74, 0xca, 0x95, 0xd6, 0xca, 0x08, 0x25, 0x67, 0x02, 0x52, + 0x7d, 0x02, 0x57, 0x12, 0xed, 0xd3, 0x0d, 0xdf, 0x37, 0xce, 0xf4, 0xb1, 0xf1, 0xa5, 0xe7, 0x93, + 0xe3, 0x27, 0xad, 0x5d, 0x92, 0xbb, 0xad, 0x86, 0xe8, 0x3d, 0xc4, 0x9e, 0xcb, 0x6a, 0xbb, 0x9e, + 0x4f, 0x5e, 0xa1, 0xa5, 0xac, 0x88, 0x25, 0x17, 0x06, 0x0d, 0x30, 0x99, 0x43, 0x01, 0x8f, 0x6b, + 0xd4, 0x4a, 0x04, 0xdb, 0x26, 0x10, 0x1a, 0x04, 0xc1, 0x63, 0x2e, 0x59, 0x37, 0x44, 0x90, 0xd1, + 0x63, 0x92, 0xbf, 0x1c, 0x71, 0x64, 0x19, 0x26, 0x9d, 0x9c, 0x11, 0x62, 0xd7, 0x32, 0xe8, 0x5c, + 0x3a, 0x78, 0xac, 0x4f, 0xa6, 0x21, 0x0f, 0x48, 0xd4, 0xb2, 0xc1, 0xe3, 0xfd, 0x69, 0x28, 0xc0, + 0x87, 0x56, 0x48, 0x61, 0x88, 0x04, 0x7e, 0x6a, 0x85, 0xb8, 0x11, 0x06, 0x8f, 0x23, 0x2f, 0xf8, + 0x45, 0xd1, 0xb7, 0x8f, 0x85, 0x9b, 0x5b, 0x85, 0xb5, 0x18, 0xa9, 0x8f, 0xa7, 0x3c, 0x02, 0x31, + 0xad, 0x95, 0x22, 0x82, 0xbd, 0xa9, 0x83, 0x03, 0x3b, 0x34, 0x86, 0x47, 0x96, 0xee, 0x63, 0x55, + 0x2e, 0xf3, 0xa1, 0x23, 0x88, 0x86, 0xb5, 0xb9, 0x06, 0x3c, 0xa1, 0x1f, 0xd9, 0x21, 0x79, 0xa7, + 0xd2, 0x5a, 0x81, 0x00, 0xbb, 0x76, 0x88, 0x62, 0x81, 0x23, 0xc5, 0x0c, 0xa4, 0x2c, 0xae, 0x10, + 0xd1, 0x3a, 0x21, 0xf6, 0x08, 0x4e, 0x19, 0xdd, 0x03, 0x25, 0x41, 0x8b, 0xf9, 0x5d, 0x25, 0xd2, + 0x8a, 0x44, 0x8a, 0xb9, 0xde, 0x05, 0xce, 0xac, 0xe3, 0xd4, 0xe3, 0x79, 0x5e, 0xe3, 0xe6, 0x30, + 0x81, 0x1b, 0x76, 0x70, 0x4c, 0x39, 0xde, 0x81, 0x8a, 0x44, 0x87, 0xf9, 0x5d, 0xe7, 0x33, 0x23, + 0x26, 0x4b, 0xd4, 0xd1, 0xb7, 0xc6, 0x5e, 0x28, 0x9a, 0xf9, 0x86, 0x54, 0x47, 0x8d, 0xe0, 0xc9, + 0x3a, 0x0a, 0x5a, 0xcc, 0xf3, 0x86, 0x54, 0x47, 0x4e, 0x8a, 0xb9, 0xde, 0x82, 0x32, 0x4a, 0x91, + 0xd0, 0x72, 0xf9, 0xe2, 0xbf, 0xc9, 0x3b, 0x56, 0xc0, 0x68, 0xf5, 0xdf, 0x82, 0x32, 0xef, 0x79, + 0x21, 0x2e, 0xb7, 0x38, 0x89, 0x80, 0x45, 0x02, 0x42, 0xf4, 0xc6, 0xd8, 0x76, 0xc9, 0x05, 0x95, + 0xd6, 0x8a, 0x1c, 0xb2, 0x67, 0xbb, 0x32, 0xda, 0x38, 0x25, 0x47, 0xd4, 0x0c, 0x6d, 0x9c, 0xd2, + 0x92, 0x9c, 0xd8, 0x8e, 0xc3, 0x17, 0xfe, 0x6d, 0xb1, 0x24, 0x11, 0xd2, 0x13, 0x36, 0x35, 0x47, + 0x63, 0xde, 0x77, 0xc4, 0xcc, 0x40, 0x00, 0x66, 0x3d, 0x43, 0x1a, 0xa7, 0xd5, 0x37, 0x65, 0xa4, + 0x71, 0x2a, 0x04, 0x13, 0x56, 0x9a, 0x78, 0xef, 0xc6, 0x82, 0x09, 0x41, 0xc8, 0x2d, 0x13, 0x18, + 0xa7, 0xd5, 0xb7, 0x92, 0x04, 0xc6, 0xa9, 0xfa, 0xd3, 0x14, 0x5c, 0xed, 0xd2, 0x49, 0x29, 0x49, + 0xf2, 0x3d, 0x2b, 0x08, 0x8c, 0x43, 0x6b, 0xc7, 0xf3, 0x77, 0xa6, 0x5f, 0x7f, 0x7d, 0xc6, 0xee, + 0xc1, 0xfa, 0xbe, 0xe1, 0x5b, 0x6e, 0x18, 0x9f, 0xa4, 0x09, 0xad, 0x69, 0x1e, 0xcc, 0x9e, 0x80, + 0xc2, 0x41, 0x07, 0xb1, 0xfe, 0x29, 0x2c, 0xb0, 0xa4, 0xe3, 0x7b, 0x81, 0x4a, 0xfd, 0x9f, 0xb7, + 0x20, 0xd3, 0xf1, 0x4c, 0x8b, 0xbd, 0x07, 0x45, 0x8a, 0x6b, 0x94, 0x2c, 0x02, 0xe1, 0x31, 0x41, + 0x34, 0xfd, 0x21, 0x53, 0xa0, 0xe0, 0x8a, 0xaf, 0xf3, 0x23, 0x21, 0x6f, 0x91, 0x51, 0x43, 0xc7, + 0x88, 0xb8, 0x59, 0x95, 0x84, 0xe3, 0x85, 0xfc, 0x04, 0x1c, 0x83, 0xa2, 0x8e, 0x5c, 0xce, 0xbe, + 0xe5, 0x92, 0xea, 0x9c, 0xd5, 0xe2, 0x34, 0x99, 0x92, 0xbe, 0x87, 0x1b, 0x2b, 0x17, 0x08, 0xd9, + 0x25, 0xa6, 0x24, 0xc7, 0x93, 0x84, 0x78, 0x0f, 0x8a, 0x5f, 0x7a, 0xb6, 0xcb, 0x2b, 0x9e, 0x5b, + 0xa8, 0x38, 0x6a, 0x8b, 0xbc, 0xe2, 0x5f, 0x8a, 0x2f, 0x76, 0x1b, 0xf2, 0x9e, 0xcb, 0xf3, 0xce, + 0x2f, 0xe4, 0x9d, 0xf3, 0xdc, 0x36, 0x0f, 0xb3, 0x59, 0xb3, 0x03, 0xdd, 0xb7, 0x0f, 0x8f, 0x42, + 0x1d, 0x39, 0xc5, 0xf1, 0x63, 0xc9, 0x0e, 0x34, 0x84, 0x61, 0xb6, 0x68, 0x21, 0x8f, 0x6c, 0x07, + 0xf7, 0x6f, 0xca, 0xac, 0xb8, 0x90, 0x19, 0x70, 0x34, 0x65, 0xf8, 0x26, 0x14, 0x0e, 0x7d, 0x6f, + 0x3a, 0x41, 0x93, 0x17, 0x16, 0x28, 0xf3, 0x84, 0xdb, 0x3e, 0xc3, 0xdd, 0x8c, 0x3e, 0x6d, 0xf7, + 0x50, 0x27, 0xef, 0x40, 0x69, 0x2b, 0x7d, 0xaf, 0xa0, 0x95, 0x23, 0x20, 0xd9, 0xfd, 0x6f, 0x42, + 0xc1, 0x38, 0x3c, 0xd4, 0x45, 0xb4, 0xd0, 0x42, 0x5e, 0xc6, 0xe1, 0x21, 0x15, 0xf9, 0x00, 0xd6, + 0x4e, 0x6c, 0x57, 0x0f, 0x26, 0xd6, 0x90, 0xd3, 0xae, 0x2d, 0x76, 0xe5, 0x89, 0xed, 0xa2, 0x51, + 0x4c, 0xf4, 0xb2, 0x55, 0x5e, 0x79, 0xad, 0x55, 0xbe, 0x05, 0x59, 0xc7, 0x1e, 0xdb, 0xa1, 0x88, + 0x1f, 0x4a, 0xa8, 0xed, 0x84, 0x60, 0x2a, 0xe4, 0x84, 0x3b, 0x5a, 0x59, 0x20, 0x11, 0x98, 0xa4, + 0x76, 0xb3, 0xf1, 0x1a, 0xed, 0x46, 0x52, 0xa1, 0xd9, 0xab, 0x55, 0xe8, 0x0f, 0x49, 0x57, 0xb5, + 0xdc, 0x50, 0x8f, 0x18, 0x2e, 0x2c, 0x67, 0x28, 0x73, 0xb2, 0x2e, 0x67, 0x7b, 0x1f, 0x4a, 0x3e, + 0xb9, 0x8b, 0x74, 0xf2, 0x2d, 0x6d, 0xca, 0xf6, 0xf6, 0xcc, 0x8f, 0xa4, 0x81, 0x3f, 0xf3, 0x29, + 0xd5, 0x60, 0x7d, 0x16, 0x0f, 0xc9, 0x03, 0x4b, 0x2f, 0xca, 0xfe, 0xea, 0x44, 0x00, 0x65, 0xa4, + 0x1d, 0xdb, 0x89, 0xa8, 0xca, 0xdb, 0xb0, 0xc6, 0x23, 0x21, 0xf8, 0x79, 0x75, 0x40, 0x1b, 0x50, + 0x51, 0x2b, 0x13, 0x90, 0x9f, 0x65, 0x07, 0xec, 0x01, 0x40, 0xa4, 0xd9, 0x85, 0xa7, 0xb4, 0x03, + 0xc5, 0xad, 0xe1, 0xdb, 0x54, 0x3d, 0x3c, 0xd5, 0x8a, 0x66, 0xf4, 0x89, 0x82, 0x75, 0x60, 0xbb, + 0x26, 0xce, 0xa3, 0xd0, 0x38, 0x0c, 0xaa, 0x55, 0x5a, 0x66, 0x25, 0x01, 0xeb, 0x1b, 0x87, 0x01, + 0x5a, 0x50, 0x06, 0x57, 0xe4, 0x78, 0xbd, 0xaf, 0xc8, 0xee, 0x15, 0x49, 0xc5, 0xd3, 0x4a, 0x86, + 0xa4, 0xef, 0x7d, 0x0c, 0x2c, 0x3a, 0xfa, 0x92, 0x0c, 0xa2, 0xab, 0x0b, 0x53, 0x6b, 0x5d, 0x9c, + 0x7d, 0xc5, 0x41, 0xdc, 0x37, 0xa1, 0x14, 0x78, 0x53, 0x7f, 0x68, 0xe9, 0x41, 0x68, 0x4d, 0xaa, + 0xd7, 0xa8, 0x42, 0xc0, 0x41, 0xbd, 0xd0, 0x9a, 0xb0, 0x8f, 0x61, 0x2d, 0xa9, 0x10, 0x5f, 0x5f, + 0x72, 0x82, 0x44, 0xd3, 0x42, 0x2b, 0x0f, 0x65, 0x15, 0xf9, 0x36, 0x8f, 0xd5, 0xa5, 0xdd, 0x87, + 0x18, 0xf9, 0x29, 0x49, 0xd9, 0xf5, 0xc2, 0x7a, 0x04, 0xc3, 0x0e, 0x8c, 0x0c, 0xa5, 0xf0, 0x94, + 0x36, 0xac, 0xb8, 0x03, 0x63, 0xd3, 0x04, 0x15, 0xcf, 0xc8, 0x4a, 0xc1, 0xb9, 0xc0, 0xd5, 0x7f, + 0x62, 0xb8, 0x99, 0x98, 0x0b, 0xb1, 0x5d, 0xa0, 0x81, 0x3f, 0xb3, 0x11, 0x3e, 0x86, 0x0a, 0xf7, + 0x01, 0xc7, 0xcb, 0x68, 0xeb, 0xbc, 0x65, 0x54, 0x26, 0x42, 0x01, 0x41, 0x49, 0xc2, 0x19, 0xf9, + 0x8a, 0xba, 0xb5, 0xe8, 0x6b, 0x23, 0x74, 0x9b, 0x96, 0xd5, 0x13, 0xa8, 0x4c, 0x7c, 0x1c, 0xb2, + 0xb8, 0x31, 0xaa, 0xdc, 0x4f, 0xfb, 0xbe, 0x35, 0x6b, 0x4f, 0x79, 0x22, 0xa5, 0xd8, 0x8f, 0x60, + 0x43, 0xe2, 0x9c, 0x1e, 0x13, 0xf3, 0x6d, 0x62, 0xde, 0x9c, 0x63, 0x3e, 0x38, 0x46, 0xf6, 0xca, + 0x24, 0x91, 0x66, 0xb5, 0x39, 0xa7, 0x06, 0x1a, 0x0c, 0x77, 0x88, 0xff, 0xf2, 0x39, 0x9e, 0x8a, + 0x84, 0xb7, 0xe3, 0x19, 0x3f, 0x74, 0x69, 0x05, 0x4d, 0xd7, 0xa4, 0xfd, 0xb4, 0xa0, 0xf1, 0x04, + 0x7b, 0x0c, 0x65, 0xae, 0xba, 0x52, 0x4c, 0x64, 0x50, 0xbd, 0x2b, 0x7b, 0x75, 0x49, 0x7f, 0x25, + 0x84, 0x56, 0x72, 0xe2, 0xef, 0x80, 0x7d, 0x04, 0x1b, 0xbc, 0xd7, 0x64, 0x29, 0xfc, 0xd6, 0xe2, + 0x44, 0x24, 0xa2, 0x9d, 0x99, 0x28, 0xd6, 0xe0, 0x8a, 0x3f, 0x75, 0x49, 0x9d, 0x15, 0x9c, 0x13, + 0xdf, 0x1b, 0x58, 0x9c, 0xff, 0x1e, 0xf1, 0x8b, 0xe6, 0x68, 0x9c, 0x8c, 0xf3, 0xd2, 0xb8, 0x5d, + 0xf2, 0x65, 0xd0, 0x3e, 0xf2, 0x9d, 0x93, 0xe7, 0x60, 0x6a, 0x3b, 0x26, 0xcf, 0xf3, 0x7b, 0xdf, + 0x26, 0xcf, 0x6d, 0xe4, 0xa3, 0x3c, 0x19, 0x64, 0xa6, 0x53, 0xdb, 0xac, 0xde, 0xe7, 0xe1, 0x8b, + 0xf8, 0xcd, 0xde, 0x84, 0x8a, 0x6f, 0x0d, 0xa7, 0x7e, 0x60, 0xbf, 0xb4, 0xf4, 0xc0, 0x76, 0x8f, + 0xab, 0x6f, 0x53, 0x3f, 0xae, 0xc5, 0xd0, 0x9e, 0xed, 0x1e, 0xe3, 0xe4, 0xb5, 0x4e, 0x43, 0xcb, + 0x77, 0x79, 0x98, 0xf6, 0x3b, 0xf2, 0xe4, 0x6d, 0x12, 0x02, 0xa5, 0x8f, 0x06, 0x56, 0xfc, 0x3d, + 0x37, 0x39, 0x02, 0x3e, 0x39, 0x1e, 0x7c, 0xa3, 0xc9, 0xd1, 0xa3, 0xc9, 0x71, 0x17, 0x0a, 0xb6, + 0x1b, 0x5a, 0xfe, 0x4b, 0xc3, 0xa9, 0x3e, 0x5c, 0x98, 0xc1, 0x31, 0x8e, 0xdd, 0x81, 0x7c, 0xe0, + 0xd8, 0x28, 0x85, 0xaa, 0xef, 0x2d, 0x90, 0x45, 0x28, 0x76, 0x0f, 0x8a, 0xf1, 0x0d, 0xa3, 0xea, + 0xfb, 0x0b, 0x74, 0x33, 0x24, 0xbb, 0x01, 0x99, 0x13, 0x9c, 0x50, 0x8f, 0x16, 0xbd, 0xf0, 0x08, + 0x47, 0x0d, 0x61, 0x84, 0x4a, 0x1c, 0x69, 0x08, 0x8f, 0x17, 0x34, 0x84, 0x1d, 0xdb, 0x71, 0xb8, + 0x86, 0x30, 0x12, 0x5f, 0xb8, 0xbf, 0x12, 0x07, 0xb6, 0xe4, 0x83, 0xc5, 0xfd, 0x15, 0x71, 0xcf, + 0xe9, 0x2e, 0x56, 0x29, 0x20, 0xd7, 0x32, 0xf7, 0x90, 0x7f, 0x28, 0xf7, 0x55, 0xd2, 0xe7, 0xac, + 0x41, 0x10, 0xa7, 0x51, 0x23, 0x15, 0x8e, 0x75, 0xdb, 0x3c, 0xad, 0x7e, 0xc4, 0x83, 0xfc, 0x39, + 0xa4, 0x65, 0x9e, 0xb2, 0xf7, 0x60, 0x2d, 0x8a, 0xa2, 0xc1, 0xe2, 0x82, 0xea, 0xc7, 0x0b, 0x35, + 0x48, 0x12, 0xb0, 0x06, 0x94, 0x47, 0xa8, 0x31, 0x8e, 0xb9, 0x02, 0x59, 0x7d, 0x42, 0x15, 0xd9, + 0x8a, 0x84, 0xce, 0x79, 0x0a, 0xa6, 0x96, 0xe0, 0x62, 0x0f, 0x80, 0xd9, 0x23, 0x3e, 0x9e, 0x68, + 0xf5, 0x73, 0x25, 0xb1, 0xfa, 0x09, 0xcd, 0xae, 0x25, 0x18, 0x3a, 0x67, 0xb3, 0x5c, 0x53, 0x1f, + 0x07, 0x42, 0x13, 0xf9, 0x3e, 0xd5, 0x53, 0x88, 0xd4, 0xf8, 0x26, 0xa2, 0xd8, 0xf2, 0x4a, 0x48, + 0xbb, 0x17, 0x70, 0xc5, 0xe4, 0x13, 0xc0, 0xe9, 0xfa, 0x72, 0xc6, 0xfa, 0x2b, 0xaf, 0x64, 0x45, + 0xda, 0x88, 0xf5, 0x09, 0x54, 0x4c, 0xcb, 0x9c, 0x4e, 0x48, 0x29, 0xa3, 0x29, 0xfa, 0x03, 0x59, + 0xf8, 0xc9, 0x1e, 0x42, 0xad, 0x6c, 0xca, 0xfe, 0xc2, 0x8f, 0x61, 0x3d, 0x72, 0xe5, 0x85, 0xc2, + 0xeb, 0xf7, 0x43, 0xb9, 0xd8, 0xd8, 0x53, 0xa7, 0xad, 0x4d, 0xa3, 0x4f, 0x2a, 0xf2, 0x31, 0xac, + 0xd1, 0xde, 0x1e, 0xb8, 0xc6, 0x24, 0x38, 0xf2, 0xc2, 0xea, 0xaf, 0xca, 0x6a, 0x4a, 0x4f, 0x40, + 0xb5, 0x32, 0x12, 0x45, 0x29, 0xdc, 0x92, 0x66, 0xeb, 0x74, 0x18, 0x5a, 0xd5, 0x1f, 0xf1, 0x2d, + 0x29, 0x06, 0xd6, 0x43, 0x8b, 0x3d, 0x06, 0x30, 0x26, 0x13, 0xe7, 0x8c, 0x4f, 0xcd, 0x4f, 0x69, + 0x6a, 0x6e, 0x4a, 0x53, 0xb3, 0x86, 0x48, 0x9a, 0x9b, 0x45, 0x23, 0xfa, 0x64, 0x8f, 0xa0, 0x3c, + 0xf1, 0x82, 0x50, 0x37, 0xc7, 0x0e, 0xb5, 0xbf, 0x26, 0xaf, 0xed, 0x7d, 0x2f, 0x08, 0x1b, 0x63, + 0x87, 0x36, 0xa6, 0x49, 0xfc, 0xcd, 0xda, 0x70, 0x21, 0x21, 0xb7, 0x0d, 0x3a, 0xd5, 0xae, 0x6e, + 0x53, 0x89, 0xd7, 0xa5, 0x12, 0x25, 0xf9, 0x2d, 0x42, 0xba, 0x36, 0xbc, 0x79, 0x10, 0x9a, 0x94, + 0x7c, 0x0c, 0xe2, 0xb8, 0xc6, 0x3a, 0x57, 0x58, 0x08, 0x1a, 0x05, 0x36, 0x3e, 0x81, 0xf5, 0x19, + 0x15, 0x36, 0x30, 0xa8, 0x36, 0xe4, 0x99, 0x2c, 0x45, 0x1f, 0xaf, 0x45, 0x8c, 0x08, 0x0b, 0xa8, + 0xef, 0x3c, 0xc7, 0x99, 0x4e, 0x84, 0x28, 0xad, 0x36, 0x45, 0xdf, 0x11, 0x90, 0x4b, 0x49, 0xc9, + 0x36, 0xb3, 0xc6, 0xd5, 0x1d, 0xd9, 0x36, 0xb3, 0xc6, 0xea, 0x3f, 0xcf, 0x42, 0x21, 0x32, 0x59, + 0x58, 0x09, 0xf2, 0x07, 0x9d, 0x67, 0x9d, 0xee, 0x8b, 0x0e, 0xbf, 0x45, 0x55, 0xeb, 0xf5, 0x9a, + 0x5a, 0x5f, 0x31, 0x59, 0x05, 0x80, 0xee, 0x49, 0xe8, 0xbd, 0x7a, 0xad, 0xc3, 0x6f, 0x55, 0xd1, + 0xed, 0x0c, 0x9e, 0x5e, 0x65, 0x1b, 0xb0, 0xb6, 0x73, 0xd0, 0xa1, 0xd8, 0x33, 0x0e, 0x4a, 0x23, + 0xa8, 0xf9, 0x39, 0x3f, 0x71, 0xe3, 0xa0, 0x0c, 0x82, 0xf6, 0x6a, 0xfd, 0xa6, 0xd6, 0x8a, 0x40, + 0x59, 0x0a, 0x63, 0xeb, 0x1e, 0x68, 0x75, 0x91, 0x53, 0x8e, 0x5d, 0x84, 0x8d, 0x98, 0x2d, 0xca, + 0x52, 0xc9, 0x63, 0xcd, 0xf6, 0xb5, 0xee, 0x67, 0xcd, 0x7a, 0x5f, 0x01, 0x3a, 0xbe, 0x7b, 0xfa, + 0x54, 0x29, 0xb1, 0x32, 0x14, 0x1a, 0xad, 0x5e, 0xbf, 0xd5, 0xa9, 0xf7, 0x95, 0x32, 0x56, 0x78, + 0xa7, 0xd5, 0xee, 0x37, 0x35, 0x65, 0x8d, 0x15, 0x20, 0xf3, 0x59, 0xb7, 0xd5, 0x51, 0x2a, 0x74, + 0x5f, 0xa4, 0xb6, 0xb7, 0xdf, 0x6e, 0x2a, 0xeb, 0x08, 0xed, 0x75, 0xb5, 0xbe, 0xa2, 0x20, 0xf4, + 0x45, 0xab, 0xd3, 0xe8, 0xbe, 0x50, 0x36, 0x58, 0x11, 0xb2, 0x07, 0x1d, 0x2c, 0x86, 0xb1, 0x35, + 0x28, 0xd2, 0xa7, 0x5e, 0x6b, 0xb7, 0x95, 0x0b, 0xd2, 0x99, 0xdf, 0x26, 0xa2, 0xe8, 0x04, 0xb1, + 0x87, 0x75, 0xb8, 0x88, 0x6d, 0x89, 0x93, 0x44, 0x7d, 0x09, 0xf3, 0xd9, 0x6b, 0x75, 0x0e, 0x7a, + 0xca, 0x65, 0x24, 0xa6, 0x4f, 0xc2, 0x54, 0x31, 0x9f, 0x56, 0x87, 0xba, 0xf2, 0x06, 0x7e, 0x37, + 0x9a, 0xed, 0x66, 0xbf, 0xa9, 0xdc, 0xc4, 0x56, 0x69, 0xcd, 0xfd, 0x76, 0xad, 0xde, 0x54, 0xb6, + 0x30, 0xd1, 0xee, 0xd6, 0x9f, 0xe9, 0xdd, 0x7d, 0xe5, 0x16, 0xdb, 0x04, 0xa5, 0xdb, 0xd1, 0x1b, + 0x07, 0xfb, 0xed, 0x56, 0xbd, 0xd6, 0x6f, 0xea, 0xcf, 0x9a, 0x5f, 0x28, 0x2a, 0x76, 0xfb, 0xbe, + 0xd6, 0xd4, 0x45, 0x5e, 0xb7, 0x99, 0x02, 0xe5, 0x9d, 0x83, 0x9f, 0xfc, 0xe4, 0x0b, 0x5d, 0xb4, + 0xfb, 0x4d, 0xac, 0xd6, 0x8c, 0x42, 0x3f, 0x78, 0xa6, 0xdc, 0x9d, 0x03, 0xf5, 0x9e, 0x29, 0x6f, + 0x61, 0xbf, 0x45, 0x03, 0xa1, 0xdc, 0x43, 0x02, 0xad, 0x59, 0x3f, 0xd0, 0x7a, 0xad, 0xe7, 0x4d, + 0xbd, 0xde, 0x6f, 0x2a, 0xdf, 0xa3, 0x8e, 0x6a, 0x75, 0x9e, 0x29, 0xf7, 0xb1, 0x25, 0xf8, 0xc5, + 0x87, 0xe7, 0x6d, 0xc6, 0xa0, 0x32, 0xa3, 0x25, 0xd8, 0x3b, 0x48, 0xb2, 0xad, 0x75, 0x6b, 0x8d, + 0x7a, 0xad, 0xd7, 0x57, 0xde, 0xc5, 0x6e, 0xe8, 0xed, 0xb7, 0x5b, 0x7d, 0xe5, 0x01, 0xb6, 0xf5, + 0x69, 0xad, 0xbf, 0xdb, 0xd4, 0x94, 0x87, 0x38, 0xd2, 0xfd, 0xd6, 0x5e, 0x53, 0x17, 0xdd, 0xfe, + 0x08, 0xcb, 0xd8, 0x69, 0xb5, 0xdb, 0xca, 0x63, 0x3a, 0xd6, 0xaa, 0x69, 0xfd, 0x16, 0x8d, 0xf5, + 0x07, 0x98, 0x41, 0x6d, 0x7f, 0xbf, 0xfd, 0x85, 0xf2, 0x21, 0x36, 0x70, 0xef, 0xa0, 0xdd, 0x6f, + 0xe9, 0x07, 0xfb, 0x8d, 0x5a, 0xbf, 0xa9, 0x7c, 0x44, 0x13, 0xa1, 0xdb, 0xeb, 0x37, 0xf6, 0xda, + 0xca, 0xc7, 0x94, 0x27, 0x4d, 0xc3, 0x7a, 0xbb, 0xdb, 0x69, 0x2a, 0x4f, 0xd4, 0xdf, 0x80, 0x42, + 0x64, 0xc6, 0x62, 0x36, 0xad, 0x4e, 0xa7, 0xa9, 0x29, 0x2b, 0x58, 0x54, 0xbb, 0xb9, 0xd3, 0x57, + 0x52, 0x74, 0xc6, 0xd7, 0x7a, 0xba, 0xdb, 0x57, 0x56, 0xf1, 0xb3, 0x7b, 0x80, 0xbd, 0x96, 0xa6, + 0xe6, 0x36, 0xf7, 0x5a, 0x4a, 0x06, 0xbf, 0x6a, 0x9d, 0x7e, 0x4b, 0xc9, 0xd2, 0xbc, 0x69, 0x75, + 0x9e, 0xb6, 0x9b, 0x4a, 0x0e, 0xa1, 0x7b, 0x35, 0xed, 0x99, 0x92, 0xe7, 0x99, 0x36, 0x9a, 0x9f, + 0x2b, 0x05, 0x96, 0x83, 0xd5, 0xf6, 0x23, 0xa5, 0x88, 0xa0, 0x46, 0xb3, 0x71, 0xb0, 0xaf, 0x80, + 0x7a, 0x0f, 0xf2, 0xb5, 0xc3, 0xc3, 0x3d, 0xcf, 0xa4, 0x63, 0xc5, 0x9d, 0x83, 0x76, 0x9b, 0xaf, + 0xa3, 0xed, 0x6e, 0xbf, 0xdf, 0xdd, 0x53, 0x52, 0x38, 0x73, 0xfb, 0xdd, 0x7d, 0x65, 0x55, 0x6d, + 0x41, 0x21, 0xda, 0x4d, 0xa5, 0x3b, 0x50, 0x05, 0xc8, 0xec, 0x6b, 0xcd, 0xe7, 0xfc, 0x60, 0xba, + 0xd3, 0xfc, 0x1c, 0xab, 0x89, 0x5f, 0x98, 0x51, 0x1a, 0x0b, 0xe2, 0x97, 0x95, 0xe8, 0x12, 0x54, + 0xbb, 0xd5, 0x69, 0xd6, 0x34, 0x25, 0xab, 0x7e, 0x98, 0x38, 0xf3, 0x13, 0x82, 0x07, 0x8b, 0xaf, + 0xb5, 0x44, 0xf1, 0xad, 0xa7, 0x9d, 0xae, 0xd6, 0xe4, 0xb7, 0xaa, 0x44, 0x47, 0xae, 0xaa, 0x6f, + 0x43, 0x31, 0x16, 0x9a, 0x38, 0xb1, 0xea, 0x5a, 0xb7, 0xd7, 0xe3, 0xfd, 0xbe, 0x82, 0x69, 0xea, + 0x1b, 0x9e, 0x4e, 0xa9, 0x3d, 0xd8, 0x88, 0xe4, 0x35, 0x05, 0x9c, 0x93, 0x79, 0xb3, 0x09, 0xd9, + 0xb6, 0xf5, 0xd2, 0x72, 0xa2, 0xc8, 0x69, 0x4a, 0x20, 0xb4, 0x3b, 0xf8, 0xb2, 0x15, 0x5f, 0x7c, + 0xa5, 0x04, 0x2a, 0x68, 0x1d, 0xe9, 0xee, 0x2d, 0x45, 0xec, 0xff, 0x6e, 0x0a, 0x0a, 0xf1, 0x2e, + 0x70, 0x07, 0x56, 0xfb, 0x3d, 0x71, 0x66, 0xb0, 0xf9, 0x60, 0xf6, 0xd4, 0x40, 0x3f, 0xfa, 0xd2, + 0x56, 0xfb, 0x3d, 0xf6, 0x0e, 0xe4, 0xf8, 0x55, 0x41, 0x71, 0xd8, 0xb3, 0x99, 0xdc, 0x59, 0xfa, + 0x84, 0xd3, 0x04, 0x0d, 0xfb, 0x10, 0x8a, 0x71, 0x6d, 0x85, 0x8b, 0xe5, 0x72, 0x92, 0x21, 0x46, + 0x6b, 0x33, 0x4a, 0xb5, 0x0d, 0x95, 0x64, 0x86, 0xec, 0x06, 0x00, 0xcf, 0x52, 0x72, 0x2d, 0x49, + 0x10, 0x76, 0x15, 0xa2, 0x1b, 0x8c, 0x0d, 0xaa, 0xd8, 0x5a, 0x7c, 0xa3, 0xb1, 0xa1, 0xfe, 0xf5, + 0x34, 0xc0, 0x4c, 0x8f, 0xc4, 0x8e, 0x88, 0x1d, 0x47, 0x59, 0x71, 0x5c, 0x7c, 0x0d, 0x8a, 0x8e, + 0x67, 0x98, 0xf2, 0x4b, 0x03, 0x05, 0x04, 0xd0, 0xd0, 0xc8, 0xb7, 0x79, 0x8a, 0x3c, 0x56, 0x83, + 0x5d, 0x82, 0xdc, 0xc8, 0xf3, 0xc7, 0x46, 0x28, 0xc2, 0xe4, 0x45, 0x0a, 0xb7, 0x03, 0x7e, 0x84, + 0x89, 0xda, 0xb4, 0x4b, 0x91, 0xf2, 0x38, 0x06, 0x65, 0x01, 0x6c, 0x23, 0x0c, 0x8d, 0x4b, 0xcb, + 0x1d, 0x3a, 0x5e, 0x60, 0x99, 0x68, 0x77, 0xe5, 0x48, 0x65, 0x86, 0x08, 0xb4, 0x7d, 0xc6, 0x5b, + 0xeb, 0x8f, 0x6d, 0xd7, 0x08, 0x85, 0x63, 0x9f, 0x5a, 0x1b, 0x41, 0xb0, 0xba, 0x5f, 0x06, 0x9e, + 0xf0, 0x23, 0xf1, 0xd3, 0xd0, 0x02, 0x02, 0xa8, 0xba, 0x6f, 0x00, 0x58, 0xc1, 0xd0, 0x98, 0xf0, + 0xcc, 0x8b, 0x94, 0x79, 0x51, 0x40, 0xb6, 0xcf, 0x58, 0x1b, 0x2a, 0xfd, 0x01, 0x6e, 0x5f, 0x5e, + 0xc3, 0x08, 0x8d, 0xba, 0xe7, 0x08, 0x0f, 0xcf, 0x9d, 0x79, 0x85, 0xfb, 0x41, 0x92, 0x8c, 0x1f, + 0xdb, 0xce, 0xf1, 0x5e, 0xad, 0xc1, 0x85, 0x25, 0x64, 0xdf, 0x2a, 0x7e, 0xcd, 0x89, 0x46, 0xa7, + 0x16, 0x86, 0x74, 0x33, 0x25, 0xde, 0xa9, 0x53, 0x51, 0x7c, 0x3d, 0xdf, 0xa4, 0xaf, 0x51, 0x84, + 0x8a, 0x08, 0x7d, 0x14, 0x83, 0x14, 0x87, 0x34, 0xde, 0x85, 0x75, 0x44, 0x8e, 0x6c, 0xcb, 0x31, + 0x05, 0x09, 0xbf, 0x58, 0xb1, 0x36, 0xf4, 0x9c, 0x1d, 0x84, 0x12, 0x9d, 0xfa, 0x57, 0xb3, 0x00, + 0x33, 0x1b, 0x2d, 0x71, 0x72, 0x9c, 0x4a, 0x9e, 0x1c, 0x3f, 0x82, 0x4b, 0xe2, 0xda, 0x4d, 0x7c, + 0xfc, 0x6a, 0xbb, 0xfa, 0xc0, 0x88, 0x0e, 0xe9, 0x99, 0xc0, 0xf2, 0x13, 0xd8, 0x96, 0xbb, 0x6d, + 0xa0, 0xc6, 0xb7, 0x2e, 0xf3, 0x84, 0x67, 0x93, 0x64, 0x90, 0x81, 0xac, 0x47, 0xcc, 0xd8, 0xfb, + 0x67, 0x13, 0xf6, 0x1e, 0x5c, 0xf4, 0xad, 0x91, 0x6f, 0x05, 0x47, 0x7a, 0x18, 0xc8, 0x85, 0xf1, + 0x58, 0xb8, 0x0d, 0x81, 0xec, 0x07, 0x71, 0x59, 0xef, 0xc1, 0x45, 0x61, 0xbd, 0xcd, 0x55, 0x8f, + 0xdf, 0xcf, 0xde, 0xe0, 0x48, 0xb9, 0x76, 0x6f, 0x00, 0x08, 0xc3, 0x35, 0x7a, 0xaf, 0xa3, 0xa0, + 0x15, 0xb9, 0x91, 0x2a, 0x6e, 0xb1, 0x92, 0xf5, 0x29, 0x8e, 0xd5, 0x78, 0x82, 0xa9, 0x90, 0x41, + 0x71, 0x4a, 0x47, 0x40, 0x95, 0x47, 0x95, 0x07, 0xf4, 0x1e, 0x09, 0xdd, 0x2a, 0xf6, 0x4c, 0x4b, + 0x23, 0x1c, 0x7b, 0x17, 0x2e, 0xc8, 0xcd, 0x8e, 0xae, 0xd4, 0x97, 0xa8, 0x22, 0xca, 0xac, 0xa1, + 0x1a, 0xbf, 0x5c, 0xff, 0x36, 0x30, 0xa9, 0xe6, 0x11, 0x75, 0x99, 0xa8, 0xd7, 0xe3, 0x6a, 0x0b, + 0xe2, 0xb7, 0x80, 0xaa, 0xc8, 0x3d, 0xee, 0x6b, 0x8b, 0xa6, 0x1a, 0x22, 0xc9, 0xf5, 0xfe, 0x1e, + 0x5c, 0x9c, 0xb5, 0x4e, 0x37, 0x42, 0x3d, 0x3c, 0xb2, 0x74, 0xcb, 0x35, 0xe9, 0xae, 0x54, 0x41, + 0xdb, 0x88, 0x1b, 0x5a, 0x0b, 0xfb, 0x47, 0x16, 0x1a, 0x5b, 0x92, 0x8b, 0x6e, 0xfd, 0xd5, 0x2e, + 0xba, 0x8f, 0xa0, 0x9a, 0x38, 0x4e, 0x96, 0xbb, 0x9b, 0xdf, 0x35, 0xdc, 0x94, 0x0f, 0x91, 0xe3, + 0x1e, 0xbf, 0x0f, 0x1b, 0x47, 0x46, 0xa0, 0x27, 0x78, 0xc9, 0x73, 0x58, 0xd0, 0xd6, 0x8f, 0x8c, + 0x60, 0x5f, 0xe2, 0x51, 0x7f, 0x3f, 0x05, 0x95, 0xa4, 0xd5, 0xca, 0xef, 0x9a, 0x38, 0xd3, 0xb1, + 0xcb, 0x23, 0x47, 0xb2, 0x5a, 0x94, 0xc4, 0xb5, 0x30, 0x39, 0xd6, 0x79, 0x2a, 0x5a, 0x0b, 0x93, + 0xe3, 0x3a, 0xa5, 0xd9, 0xf7, 0x20, 0x3f, 0x39, 0xe6, 0xc2, 0xe1, 0xbc, 0xd9, 0x97, 0x9b, 0xf0, + 0x90, 0xdd, 0xef, 0x41, 0x7e, 0x2a, 0x48, 0x33, 0xe7, 0x91, 0x4e, 0x89, 0x54, 0xfd, 0xd3, 0x55, 0x28, 0xcb, 0xfe, 0x9a, 0x6f, 0x72, 0xca, 0xfc, 0xad, 0xa2, 0x03, 0xb6, 0x28, 0x82, 0x4f, 0xa7, 0xf8, 0x60, 0xec, 0x27, 0x7e, 0xc4, 0x0c, 0x47, 0x46, 0x50, 0x9b, 0x86, 0x5e, 0xdd, 0xe3, 0x27, 0x5b, 0x9e, 0x13, 0xc5, 0x0d, 0xf3, 0x95, 0x81, 0x32, 0x41, 0x84, 0x0c, 0xbf, 0x27, 0xae, 0x25, @@ -13758,7 +13774,7 @@ var fileDescriptor_2d655ab2f7683c23 = []byte{ 0x5e, 0x8e, 0x74, 0x1c, 0x49, 0xd9, 0x32, 0x5b, 0xe6, 0xe9, 0xf2, 0x50, 0x89, 0xcc, 0x37, 0x0f, 0x95, 0xc8, 0x2e, 0x0d, 0x95, 0xb8, 0x3b, 0xdb, 0x2a, 0x70, 0xba, 0x62, 0xc1, 0x45, 0xbe, 0x61, 0x4d, 0xe2, 0x0b, 0x15, 0x58, 0xfa, 0xf7, 0xa1, 0x12, 0xb5, 0x4e, 0xe4, 0x07, 0x89, 0x3b, 0x1c, - 0x02, 0xc7, 0x5d, 0xcd, 0x6b, 0xa1, 0x9c, 0x4c, 0x2e, 0xbf, 0xd2, 0x6b, 0x62, 0x48, 0xfe, 0x5a, + 0x02, 0xc7, 0x5d, 0xcd, 0x6b, 0xa1, 0x9c, 0x4c, 0x2e, 0xbf, 0xd2, 0x6b, 0x62, 0x48, 0xfe, 0x46, 0x0a, 0x98, 0x30, 0xc9, 0x77, 0xa6, 0x8e, 0xd3, 0xb7, 0x4e, 0x69, 0x95, 0xdf, 0x87, 0x0d, 0xe1, 0x09, 0x97, 0x22, 0xb0, 0xc4, 0xd9, 0x1e, 0x47, 0xcc, 0xce, 0xf6, 0x96, 0x5d, 0xb3, 0x5b, 0x5d, 0x7a, 0xcd, 0x6e, 0xf9, 0xf5, 0xbd, 0x9b, 0x50, 0x92, 0x2f, 0xa9, 0x71, 0xd5, 0x0a, 0x8c, 0xd9, @@ -13768,296 +13784,297 @@ var fileDescriptor_2d655ab2f7683c23 = []byte{ 0x76, 0xc0, 0xe5, 0x2b, 0xfb, 0x04, 0xae, 0xc4, 0x9c, 0xfa, 0x89, 0x1d, 0x1e, 0x79, 0xd3, 0x50, 0xb8, 0x18, 0x02, 0x21, 0x71, 0x2e, 0x45, 0x39, 0xbd, 0xe0, 0x68, 0x2e, 0x45, 0x02, 0x54, 0xba, 0x47, 0x53, 0xc7, 0xd1, 0x43, 0xeb, 0x34, 0x14, 0xcf, 0x06, 0x54, 0x13, 0x1e, 0x17, 0x69, 0x78, - 0xb5, 0xc2, 0x48, 0x24, 0xd4, 0xbf, 0x9f, 0x86, 0xec, 0x8f, 0xa7, 0x96, 0x7f, 0xc6, 0x3e, 0x82, - 0x62, 0x10, 0x8e, 0x43, 0xf9, 0x7c, 0xf5, 0x0a, 0xcf, 0x80, 0xf0, 0x74, 0x3c, 0x6a, 0x8d, 0x2d, - 0x37, 0xe4, 0xae, 0x48, 0xa4, 0xa5, 0xcd, 0x64, 0x13, 0xb2, 0x41, 0x68, 0x4d, 0x02, 0x11, 0xa1, - 0xc6, 0x13, 0x6c, 0x0b, 0xb2, 0xae, 0x67, 0x5a, 0x41, 0x32, 0x0e, 0xad, 0x83, 0xda, 0x03, 0x47, - 0x30, 0x15, 0x72, 0xf1, 0x88, 0x2f, 0x9c, 0x71, 0x72, 0x0c, 0xdd, 0x2c, 0xb0, 0x0c, 0xd3, 0x76, - 0x0f, 0xa3, 0xdb, 0xa7, 0x71, 0x1a, 0xb7, 0x49, 0x52, 0xd6, 0x8d, 0xc3, 0xe8, 0x2a, 0xb8, 0x48, - 0xb2, 0x2d, 0x28, 0xe1, 0xe7, 0x0b, 0xdf, 0x0e, 0xad, 0xde, 0xe3, 0x48, 0x52, 0x4b, 0x20, 0x54, - 0xb5, 0x4d, 0x2b, 0xb4, 0x86, 0x61, 0xef, 0x2b, 0x11, 0x5c, 0x46, 0x31, 0x48, 0x11, 0x84, 0x7d, - 0x1f, 0xd8, 0xc0, 0x18, 0x1e, 0x1f, 0xfa, 0xde, 0xd4, 0x35, 0xf5, 0xaf, 0xa6, 0x96, 0x6f, 0x5b, - 0x51, 0x30, 0x59, 0x49, 0xea, 0x14, 0x6d, 0x63, 0x46, 0xf6, 0x63, 0x4e, 0xa5, 0x9a, 0xb0, 0x96, - 0xe8, 0xaa, 0x05, 0xef, 0x4e, 0xaf, 0xd9, 0x6e, 0xd6, 0xfb, 0xdc, 0x2c, 0x14, 0x2e, 0x85, 0x55, - 0xd9, 0x25, 0x91, 0x96, 0x7c, 0x15, 0x19, 0xc9, 0x76, 0xcc, 0x92, 0xa7, 0xa3, 0xa9, 0x3d, 0x6d, - 0x2a, 0x39, 0xf5, 0x0f, 0x56, 0x61, 0xa3, 0xef, 0x1b, 0x6e, 0x60, 0x70, 0x4d, 0xc2, 0x0d, 0x7d, - 0xcf, 0x61, 0xdf, 0x87, 0x42, 0x38, 0x74, 0xe4, 0x21, 0xbc, 0x19, 0x09, 0x8c, 0x39, 0xd2, 0x07, - 0xfd, 0x21, 0xf7, 0x29, 0xe7, 0x43, 0xfe, 0xc1, 0xde, 0x85, 0xec, 0xc0, 0x3a, 0xb4, 0x5d, 0x21, - 0x33, 0x2f, 0xce, 0x33, 0x6e, 0x23, 0x72, 0x77, 0x45, 0xe3, 0x54, 0xec, 0x3d, 0xc8, 0x0d, 0xbd, - 0x71, 0xb4, 0xf1, 0xcc, 0x6e, 0x31, 0x49, 0x05, 0x21, 0x76, 0x77, 0x45, 0x13, 0x74, 0xec, 0x23, - 0x28, 0xf8, 0x9e, 0xe3, 0x60, 0x8f, 0x89, 0x2d, 0xa9, 0x3a, 0xcf, 0xa3, 0x09, 0xfc, 0xee, 0x8a, - 0x16, 0xd3, 0xaa, 0x0f, 0x20, 0x2f, 0x2a, 0x8b, 0x1d, 0xb0, 0xdd, 0x7c, 0xda, 0x12, 0x1d, 0x59, - 0xef, 0xee, 0xed, 0xb5, 0xfa, 0xfc, 0x8a, 0xa6, 0xd6, 0x6d, 0xb7, 0xb7, 0x6b, 0xf5, 0x67, 0xca, - 0xea, 0x76, 0x01, 0x72, 0xdc, 0x7b, 0xa8, 0xfe, 0x66, 0x0a, 0xd6, 0xe7, 0x1a, 0xc0, 0x9e, 0x40, - 0x66, 0x8c, 0x9a, 0x2d, 0xef, 0x9e, 0x3b, 0x4b, 0x5b, 0x29, 0xa5, 0xb9, 0xbe, 0x8b, 0x1c, 0xea, - 0x27, 0x50, 0x49, 0xc2, 0x25, 0x0f, 0xc2, 0x1a, 0x14, 0xb5, 0x66, 0xad, 0xa1, 0x77, 0x3b, 0x68, - 0xb7, 0xa3, 0x1d, 0x4f, 0xc9, 0x17, 0x5a, 0x8b, 0x8c, 0xfe, 0x5f, 0x03, 0x65, 0xbe, 0x63, 0xd8, - 0x53, 0xb4, 0x5d, 0xc6, 0x13, 0xc7, 0x22, 0x15, 0x51, 0x1a, 0xb2, 0x1b, 0x4b, 0x7a, 0x52, 0x90, - 0xd1, 0x88, 0x55, 0x86, 0x89, 0xb4, 0xfa, 0xeb, 0xc0, 0x16, 0x7b, 0xf0, 0x97, 0x97, 0xfd, 0xff, - 0x48, 0x41, 0x66, 0xdf, 0x31, 0x5c, 0x76, 0x1b, 0xb2, 0xf4, 0xb4, 0x88, 0x90, 0xbc, 0xf2, 0x3a, - 0xc0, 0x69, 0x41, 0x38, 0xf6, 0x36, 0xa4, 0xc3, 0x61, 0x74, 0x33, 0xf4, 0xf2, 0x39, 0x93, 0x6f, - 0x77, 0x45, 0x43, 0x2a, 0x76, 0x0f, 0xd2, 0xa6, 0x19, 0x45, 0x64, 0x0b, 0x9f, 0x02, 0x5a, 0x94, - 0x0d, 0x6b, 0x64, 0xbb, 0xb6, 0x78, 0x0a, 0x05, 0x49, 0xd8, 0x9b, 0x90, 0x36, 0x87, 0x4e, 0x32, - 0xbc, 0x9e, 0xdb, 0x9e, 0x71, 0x86, 0xe6, 0xd0, 0x41, 0x0d, 0x2c, 0xf4, 0xcf, 0x74, 0x7f, 0xea, - 0x52, 0x88, 0x59, 0x20, 0xac, 0xa2, 0x12, 0xea, 0x1f, 0x53, 0x8a, 0x53, 0x0b, 0xc4, 0x15, 0xb3, - 0x89, 0x6f, 0x4d, 0x0c, 0x3f, 0xb6, 0x87, 0xec, 0x60, 0x9f, 0x03, 0xb6, 0x73, 0x40, 0x2f, 0x36, - 0xaa, 0xef, 0xd0, 0xbb, 0x17, 0xa8, 0x58, 0xab, 0xd1, 0xd7, 0x92, 0xc7, 0xbd, 0x04, 0x46, 0xfd, - 0xb3, 0x34, 0x94, 0xa4, 0xfa, 0xb0, 0x0f, 0xa0, 0x60, 0x26, 0x17, 0xe2, 0x95, 0x85, 0x4a, 0x3f, - 0x68, 0x44, 0x4b, 0xd0, 0x14, 0xd3, 0x9b, 0x0e, 0x2c, 0x42, 0xfd, 0xa5, 0xe1, 0xdb, 0xfc, 0xb5, - 0xa3, 0x55, 0xf9, 0xe4, 0xa0, 0x67, 0x85, 0xcf, 0x23, 0xcc, 0xee, 0x8a, 0x56, 0x0e, 0xa4, 0x34, - 0x69, 0xff, 0xa2, 0x49, 0xe9, 0xc4, 0xab, 0x51, 0x1c, 0xb8, 0xbb, 0xa2, 0x45, 0x78, 0x24, 0xb5, - 0x4e, 0xad, 0xe1, 0x34, 0x8c, 0xb4, 0xff, 0xb5, 0xa8, 0x41, 0x04, 0xa4, 0xa7, 0xeb, 0xf8, 0x27, - 0x7b, 0x84, 0x72, 0xd2, 0x70, 0x1c, 0x8f, 0xd4, 0xac, 0xac, 0xec, 0xc7, 0x6f, 0xc4, 0x70, 0xfe, - 0x54, 0x5e, 0x94, 0x62, 0x77, 0x21, 0xeb, 0x85, 0x47, 0x56, 0xa4, 0x53, 0x47, 0x2f, 0x68, 0x20, - 0xa8, 0x51, 0x6f, 0xe3, 0x4c, 0x21, 0xb4, 0xfa, 0xb3, 0x14, 0xe4, 0x45, 0x0f, 0xb0, 0x0d, 0x58, - 0xeb, 0x35, 0xfb, 0xfa, 0xf3, 0x9a, 0xd6, 0xaa, 0x6d, 0xb7, 0x9b, 0xe2, 0x56, 0xc0, 0x53, 0xad, - 0xd6, 0x11, 0x72, 0x52, 0x6b, 0x3e, 0xef, 0x3e, 0x6b, 0x72, 0xb7, 0x5c, 0xa3, 0xd9, 0xf9, 0x42, - 0x49, 0x73, 0xd7, 0x74, 0x73, 0xbf, 0xa6, 0xa1, 0x94, 0x2c, 0x41, 0xbe, 0xf9, 0x79, 0xb3, 0x7e, - 0x40, 0x62, 0xb2, 0x02, 0xd0, 0x68, 0xd6, 0xda, 0xed, 0x6e, 0x1d, 0xc5, 0x66, 0x8e, 0x31, 0xa8, - 0xd4, 0xb5, 0x66, 0xad, 0xdf, 0xd4, 0x6b, 0xf5, 0x7a, 0xf7, 0xa0, 0xd3, 0x57, 0xf2, 0x58, 0x62, - 0xad, 0xdd, 0x6f, 0x6a, 0x31, 0x88, 0x5e, 0x35, 0x6a, 0x68, 0xdd, 0xfd, 0x18, 0x52, 0xdc, 0x2e, - 0xa2, 0x25, 0x46, 0x63, 0xa5, 0xfe, 0xc3, 0x0d, 0xa8, 0x24, 0xa7, 0x26, 0xfb, 0x18, 0x0a, 0xa6, - 0x99, 0x18, 0xe3, 0xeb, 0xcb, 0xa6, 0xf0, 0x83, 0x86, 0x19, 0x0d, 0x33, 0xff, 0x60, 0xb7, 0xa2, - 0x85, 0xb4, 0xba, 0xb0, 0x90, 0xa2, 0x65, 0xf4, 0x23, 0x58, 0x17, 0x2f, 0x50, 0x98, 0x46, 0x68, - 0x0c, 0x8c, 0xc0, 0x4a, 0xae, 0x92, 0x3a, 0x21, 0x1b, 0x02, 0xb7, 0xbb, 0xa2, 0x55, 0x86, 0x09, - 0x08, 0xfb, 0x01, 0x54, 0x0c, 0x32, 0xb6, 0x63, 0xfe, 0x8c, 0xac, 0x40, 0xd6, 0x10, 0x27, 0xb1, - 0xaf, 0x19, 0x32, 0x00, 0x27, 0xa2, 0xe9, 0x7b, 0x93, 0x19, 0x73, 0x36, 0x71, 0x84, 0xe5, 0x7b, - 0x13, 0x89, 0xb7, 0x6c, 0x4a, 0x69, 0xf6, 0x11, 0x94, 0x45, 0xcd, 0x67, 0x0e, 0x87, 0x78, 0xc9, - 0xf2, 0x6a, 0x93, 0x42, 0xb8, 0xbb, 0xa2, 0x95, 0x86, 0xb3, 0x24, 0x7b, 0x8c, 0x5a, 0xe0, 0x4c, - 0x7d, 0xce, 0xcb, 0x73, 0x8d, 0x6a, 0x1b, 0x71, 0x81, 0x11, 0xa7, 0xd8, 0x7b, 0x00, 0x54, 0x4f, - 0xce, 0x53, 0x48, 0x84, 0x9c, 0xf8, 0xde, 0x24, 0x62, 0x29, 0x9a, 0x51, 0x42, 0xaa, 0x1e, 0x77, - 0x17, 0x15, 0x17, 0xab, 0x47, 0x2e, 0xa3, 0x59, 0xf5, 0xb8, 0xa7, 0x29, 0xae, 0x1e, 0x67, 0x83, - 0x85, 0xea, 0x45, 0x5c, 0xbc, 0x7a, 0x9c, 0x29, 0xaa, 0x1e, 0xe7, 0x29, 0xcd, 0x57, 0x2f, 0x62, - 0xa1, 0xea, 0x71, 0x8e, 0x1f, 0x2c, 0xe8, 0xfd, 0xe5, 0x73, 0xf5, 0x7e, 0x1c, 0xb6, 0xa4, 0xe6, - 0xff, 0x03, 0xa8, 0x04, 0x47, 0xde, 0x89, 0x24, 0x40, 0xd6, 0x64, 0xee, 0xde, 0x91, 0x77, 0x22, - 0x4b, 0x90, 0xb5, 0x40, 0x06, 0x60, 0x6d, 0x79, 0x13, 0xe9, 0xea, 0x7b, 0x45, 0xae, 0x2d, 0xb5, - 0xf0, 0xb9, 0x6d, 0x9d, 0x60, 0x6d, 0x8d, 0x28, 0x81, 0x9d, 0x32, 0x73, 0xbe, 0x04, 0xc2, 0x9d, - 0x92, 0x08, 0x89, 0x10, 0x25, 0x41, 0xec, 0x86, 0x09, 0x70, 0x6e, 0x4d, 0x5d, 0x99, 0x4d, 0x91, - 0xe7, 0xd6, 0x81, 0x9b, 0x60, 0x2c, 0x73, 0x52, 0xc1, 0x3a, 0x5b, 0x15, 0x81, 0xf5, 0xd5, 0xd4, - 0x72, 0x87, 0x96, 0x08, 0xc8, 0x4a, 0xac, 0x8a, 0x9e, 0xc0, 0xcd, 0x56, 0x45, 0x04, 0x89, 0xe7, - 0x75, 0xcc, 0xce, 0xe6, 0xe7, 0xb5, 0xc4, 0x4c, 0xf3, 0x3a, 0x66, 0x8d, 0x17, 0x54, 0xcc, 0x7b, - 0x61, 0x61, 0x41, 0x49, 0xcc, 0x7c, 0x41, 0xc5, 0xdc, 0x8f, 0x41, 0xcc, 0x26, 0xde, 0xb9, 0x89, - 0xb0, 0x2d, 0x5e, 0x6b, 0xd1, 0xbb, 0x30, 0x8c, 0x53, 0x38, 0x57, 0x7d, 0x0b, 0xed, 0x0c, 0x31, - 0x15, 0x2e, 0xca, 0x73, 0x55, 0x23, 0x4c, 0xbc, 0x94, 0xfc, 0x59, 0x52, 0x2a, 0x6c, 0x62, 0x87, - 0x7e, 0xd5, 0x5c, 0x2c, 0x6c, 0xdf, 0x0e, 0xfd, 0x59, 0x61, 0x98, 0x62, 0xef, 0x02, 0x4d, 0x43, - 0xce, 0x62, 0xc9, 0xa2, 0x1b, 0xbb, 0x45, 0x30, 0x14, 0x4c, 0xf1, 0x8d, 0x93, 0x45, 0x94, 0x31, - 0x34, 0x87, 0xd5, 0x91, 0x3c, 0x59, 0x78, 0x11, 0xf5, 0x46, 0x1d, 0x27, 0x0b, 0x27, 0xaa, 0x9b, - 0x43, 0x76, 0x1f, 0x88, 0x9b, 0xe8, 0x0f, 0x13, 0x2f, 0x34, 0xf9, 0xde, 0x84, 0x53, 0xe7, 0x91, - 0x00, 0x69, 0xb1, 0x05, 0x8e, 0xe7, 0x46, 0x0d, 0x3f, 0x4a, 0xb4, 0x00, 0x11, 0xb1, 0x30, 0x18, - 0xc6, 0x29, 0xf5, 0xb7, 0x73, 0x90, 0x17, 0xb2, 0x96, 0x5d, 0x80, 0x75, 0x21, 0xf2, 0x1b, 0xb5, - 0x7e, 0x6d, 0xbb, 0xd6, 0x43, 0x25, 0x8d, 0x41, 0x85, 0xcb, 0xfc, 0x18, 0x96, 0xc2, 0x7d, 0x80, - 0x84, 0x7e, 0x0c, 0x5a, 0xc5, 0x7d, 0x40, 0xf0, 0xf2, 0x97, 0xf0, 0xd2, 0x6c, 0x1d, 0x4a, 0x9c, - 0x91, 0x03, 0xe8, 0x92, 0x22, 0x71, 0xf1, 0x74, 0x56, 0x62, 0xe1, 0xa7, 0x54, 0xb9, 0x19, 0x0b, - 0x07, 0xe4, 0x63, 0x96, 0xe8, 0x18, 0x8b, 0x41, 0xa5, 0xaf, 0x1d, 0x74, 0xea, 0xb3, 0x72, 0x8a, - 0x74, 0xb1, 0x8c, 0x67, 0xf3, 0xbc, 0xd5, 0x7c, 0xa1, 0x00, 0x32, 0xf1, 0x5c, 0x28, 0x5d, 0x42, - 0x35, 0x93, 0x32, 0xa1, 0x64, 0x99, 0x5d, 0x86, 0x0b, 0xbd, 0xdd, 0xee, 0x0b, 0x9d, 0x33, 0xc5, - 0x4d, 0x58, 0x63, 0x9b, 0xa0, 0x48, 0x08, 0x9e, 0x7d, 0x05, 0x8b, 0x24, 0x68, 0x44, 0xd8, 0x53, - 0xd6, 0xe9, 0x20, 0x18, 0x61, 0x7d, 0xbe, 0xef, 0x2a, 0xd8, 0x14, 0xce, 0xda, 0x6d, 0x1f, 0xec, - 0x75, 0x7a, 0xca, 0x06, 0x56, 0x82, 0x20, 0xbc, 0xe6, 0x2c, 0xce, 0x66, 0xb6, 0x5b, 0x5f, 0xa0, - 0x0d, 0x1c, 0x61, 0x2f, 0x6a, 0x5a, 0xa7, 0xd5, 0x79, 0xda, 0x53, 0x36, 0xe3, 0x9c, 0x9b, 0x9a, - 0xd6, 0xd5, 0x7a, 0xca, 0xc5, 0x18, 0xd0, 0xeb, 0xd7, 0xfa, 0x07, 0x3d, 0xe5, 0x52, 0x5c, 0xcb, - 0x7d, 0xad, 0x5b, 0x6f, 0xf6, 0x7a, 0xed, 0x56, 0xaf, 0xaf, 0x5c, 0x66, 0x17, 0x61, 0x63, 0x56, - 0xa3, 0x88, 0xb8, 0x2a, 0x55, 0x54, 0x7b, 0xda, 0xec, 0x2b, 0x57, 0xe2, 0x6a, 0xd4, 0xbb, 0xed, - 0x76, 0x8d, 0x8e, 0x30, 0xaf, 0x22, 0x11, 0x9d, 0xe5, 0x8a, 0xd6, 0x5c, 0xc3, 0x7a, 0x1d, 0x74, - 0x64, 0xd0, 0x75, 0x69, 0x6a, 0xf4, 0x9a, 0x3f, 0x3e, 0x68, 0x76, 0xea, 0x4d, 0xe5, 0x8d, 0xd9, - 0xd4, 0x88, 0x61, 0x37, 0xe2, 0xa9, 0x11, 0x83, 0x6e, 0xc6, 0x65, 0x46, 0xa0, 0x9e, 0xb2, 0x85, - 0xf9, 0x89, 0x7a, 0x74, 0x3a, 0xcd, 0x7a, 0x1f, 0xdb, 0x7a, 0x2b, 0xee, 0xc5, 0x83, 0xfd, 0xa7, - 0x5a, 0xad, 0xd1, 0x54, 0x54, 0x84, 0x68, 0xcd, 0x4e, 0x6d, 0x2f, 0x1a, 0xed, 0xdb, 0xd2, 0x68, - 0xef, 0xb7, 0xfa, 0x9a, 0x72, 0x27, 0x1e, 0x5d, 0x4a, 0xbe, 0xc9, 0xae, 0xc1, 0x65, 0x79, 0x1e, - 0xea, 0x2f, 0x5a, 0xfd, 0x5d, 0x71, 0xe2, 0x7a, 0x97, 0x9f, 0x1c, 0x12, 0xb2, 0xde, 0xa8, 0xf3, - 0xa3, 0x65, 0xe2, 0xc5, 0xd4, 0xbd, 0xed, 0x32, 0x3d, 0x68, 0x2c, 0x14, 0x10, 0xf5, 0x33, 0x60, - 0xf2, 0xdb, 0x9e, 0xe2, 0x91, 0x2b, 0x06, 0x99, 0x91, 0xef, 0x8d, 0xa3, 0x07, 0x03, 0xf0, 0x1b, - 0x2d, 0xe7, 0xc9, 0x74, 0x40, 0x27, 0x9a, 0xb3, 0x0b, 0xc1, 0x32, 0x48, 0xfd, 0xdb, 0x29, 0xa8, - 0x24, 0x95, 0x0f, 0x72, 0x7b, 0x8e, 0x74, 0xd7, 0x0b, 0xf9, 0xeb, 0x49, 0x41, 0xfc, 0xe4, 0xe6, - 0xa8, 0xe3, 0x85, 0xf4, 0x7c, 0x12, 0x19, 0xf2, 0xb1, 0x2e, 0xc1, 0x73, 0x8d, 0xd3, 0xac, 0x05, - 0x17, 0x12, 0xcf, 0xa3, 0x26, 0xde, 0xae, 0xaa, 0xc6, 0xcf, 0x1a, 0xce, 0xd5, 0x5f, 0x63, 0xc1, - 0x62, 0x9b, 0xc4, 0xb5, 0xee, 0xcc, 0xec, 0x5a, 0xf7, 0x2e, 0xac, 0x25, 0x74, 0x1d, 0xf2, 0xbf, - 0x8c, 0x92, 0x35, 0x2d, 0xd8, 0xa3, 0xd7, 0x57, 0x53, 0xfd, 0x9b, 0x29, 0x28, 0xcb, 0x9a, 0xcf, - 0x77, 0xce, 0x89, 0xae, 0x40, 0x89, 0x6f, 0xdd, 0x36, 0xa3, 0x57, 0x93, 0x22, 0x50, 0x8b, 0x1e, - 0x72, 0xe7, 0x1e, 0xe4, 0x9d, 0xe3, 0x5e, 0xdc, 0x1c, 0x19, 0xc4, 0x6e, 0x00, 0xd0, 0x85, 0xd0, - 0x9d, 0x67, 0x48, 0x20, 0x2e, 0x51, 0xcd, 0x20, 0xea, 0x4d, 0x28, 0xee, 0x1c, 0x47, 0x71, 0x2e, - 0xf2, 0x1b, 0x62, 0x45, 0x7e, 0x8b, 0x5c, 0xfd, 0xe3, 0x14, 0x54, 0x66, 0xef, 0xad, 0xd0, 0xb9, - 0x32, 0x7f, 0x56, 0x97, 0x4f, 0x87, 0x55, 0x73, 0x30, 0x7b, 0xe3, 0x7d, 0x55, 0x7e, 0xe3, 0xfd, - 0xb6, 0xc8, 0x2c, 0x2d, 0x8b, 0xfc, 0xb8, 0x2c, 0x71, 0x47, 0xfd, 0x31, 0x94, 0xf1, 0xbf, 0x66, - 0x8d, 0x2c, 0xdf, 0xb7, 0xa2, 0x17, 0x86, 0x17, 0x88, 0x13, 0x44, 0x64, 0xe3, 0x59, 0x23, 0xa1, - 0x6a, 0x2e, 0x7d, 0x12, 0x86, 0x9e, 0x2a, 0xfa, 0xaf, 0x69, 0x28, 0x49, 0x7a, 0xe4, 0x37, 0x9a, - 0x7e, 0xd7, 0xa1, 0x38, 0x7b, 0xa0, 0x44, 0x5c, 0x0c, 0x8e, 0x01, 0x89, 0xb1, 0x4a, 0xcf, 0x8d, - 0x55, 0x15, 0xf2, 0x22, 0x7c, 0x56, 0x38, 0x7f, 0xa3, 0x64, 0xd2, 0xcd, 0x9a, 0x7d, 0xcd, 0x29, - 0xc7, 0xfb, 0x50, 0x96, 0x7c, 0xa4, 0x81, 0xb8, 0x3c, 0x3b, 0x4f, 0x5f, 0x9a, 0xf9, 0x4b, 0x03, - 0x76, 0x11, 0x72, 0xa3, 0x63, 0xdd, 0x1c, 0xf0, 0x1b, 0x93, 0x45, 0x2d, 0x3b, 0x3a, 0x6e, 0x0c, - 0xe8, 0x0c, 0x68, 0x14, 0xab, 0x4e, 0xdc, 0x73, 0x55, 0x18, 0x45, 0x0a, 0xd2, 0x3d, 0xc8, 0x8f, - 0x8e, 0xe5, 0x9b, 0x8f, 0x0b, 0x5d, 0x9e, 0x1b, 0x1d, 0xd3, 0x55, 0xc9, 0x87, 0xb0, 0x29, 0xf6, - 0x6f, 0x23, 0xd0, 0xf9, 0x1b, 0x0c, 0xf4, 0x70, 0x0d, 0x7f, 0x51, 0x6c, 0x83, 0xe3, 0x6a, 0x41, - 0x8f, 0x30, 0x38, 0xe3, 0x54, 0x28, 0x4b, 0x13, 0x90, 0xbf, 0xf0, 0x53, 0xd4, 0x12, 0x30, 0xf6, - 0x04, 0xca, 0xa3, 0x63, 0x3e, 0xa0, 0x7d, 0x6f, 0xcf, 0x12, 0xd1, 0xfc, 0x9b, 0xf3, 0x43, 0x49, - 0x07, 0xff, 0x09, 0x4a, 0x76, 0x09, 0x72, 0x9a, 0x71, 0xd2, 0xfb, 0x71, 0x9b, 0x94, 0xc8, 0xa2, - 0x26, 0x52, 0x9f, 0x65, 0x0a, 0x15, 0x65, 0x5d, 0xfd, 0x47, 0x29, 0xa8, 0xcc, 0x6c, 0x00, 0x5c, - 0x84, 0xec, 0xbe, 0xfc, 0x1e, 0x76, 0x75, 0xde, 0x4c, 0x40, 0x92, 0x07, 0xfd, 0xb3, 0x09, 0x7f, - 0x35, 0x72, 0xd9, 0xab, 0x4c, 0xcb, 0x9c, 0xd6, 0xe9, 0xa5, 0x2f, 0xf1, 0x3e, 0x85, 0x74, 0xff, - 0x6c, 0xc2, 0xfd, 0x4d, 0xb8, 0x25, 0x72, 0xdb, 0x94, 0x6f, 0x86, 0x14, 0x59, 0xf2, 0xac, 0xf9, - 0x05, 0x7f, 0xc8, 0x60, 0x5f, 0x6b, 0xed, 0xd5, 0xb4, 0x2f, 0x28, 0x68, 0x88, 0x94, 0x86, 0x9d, - 0xae, 0xd6, 0x6c, 0x3d, 0xed, 0x10, 0x20, 0x43, 0xde, 0xa8, 0x59, 0x15, 0x6b, 0xa6, 0xb9, 0x73, - 0x2c, 0x3f, 0x68, 0x93, 0x4a, 0x3c, 0x68, 0x93, 0xbc, 0xfb, 0xbc, 0x3a, 0x7f, 0xf7, 0x99, 0xc5, - 0xab, 0x30, 0x5e, 0xd2, 0xec, 0x2d, 0xc8, 0x8c, 0x8e, 0xad, 0xb3, 0xa4, 0xa1, 0x97, 0x5c, 0x40, - 0x44, 0xa0, 0xfe, 0x3c, 0x05, 0x2c, 0x51, 0x11, 0x6e, 0x7b, 0x7c, 0xd7, 0xba, 0x7c, 0x0c, 0x55, - 0xf1, 0xc4, 0x22, 0xa7, 0x92, 0xbc, 0xe4, 0xa2, 0x4b, 0x2f, 0x7a, 0xb3, 0x10, 0xcf, 0xd9, 0xc3, - 0x51, 0xec, 0x21, 0xf0, 0x37, 0xee, 0x28, 0x4e, 0x24, 0x73, 0x8e, 0x9d, 0xa8, 0xcd, 0x68, 0x66, - 0x8f, 0xda, 0xc9, 0x8f, 0xf5, 0x71, 0x07, 0xfb, 0xfa, 0x6c, 0xd4, 0x68, 0xcd, 0xab, 0xbf, 0x97, - 0x82, 0x0b, 0xc9, 0x09, 0xf1, 0x8b, 0xb5, 0x32, 0xf9, 0x32, 0x61, 0x7a, 0xfe, 0x65, 0xc2, 0x65, - 0xf3, 0x29, 0xb3, 0x74, 0x3e, 0xfd, 0x56, 0x0a, 0x36, 0xa5, 0xde, 0x9f, 0x59, 0x8b, 0x7f, 0x4e, - 0x35, 0x93, 0x1e, 0x28, 0xcc, 0x24, 0x1e, 0x28, 0x54, 0xff, 0x20, 0x05, 0x97, 0xe6, 0x6a, 0xa2, - 0x59, 0x7f, 0xae, 0x75, 0x49, 0x3e, 0x64, 0x48, 0x4e, 0x7e, 0x1e, 0xe7, 0xca, 0x2f, 0xcd, 0xb2, - 0xe4, 0xcb, 0x84, 0x74, 0x45, 0xfd, 0x03, 0xd8, 0x98, 0xd5, 0xb1, 0x2e, 0x1e, 0x5d, 0xbc, 0x09, - 0x25, 0xd7, 0x3a, 0xd1, 0xa3, 0x27, 0x19, 0x45, 0x64, 0x90, 0x6b, 0x9d, 0x08, 0x02, 0x75, 0x47, - 0x16, 0x18, 0xf1, 0xfb, 0xec, 0x8e, 0x99, 0x08, 0x31, 0xf1, 0x1c, 0x33, 0x42, 0x61, 0x6e, 0x52, - 0x8b, 0xf2, 0xae, 0x75, 0x42, 0x83, 0x75, 0x22, 0xf2, 0xa9, 0x99, 0xa6, 0x38, 0x66, 0x5f, 0xf6, - 0xce, 0xd2, 0x15, 0x28, 0x4c, 0xfc, 0x44, 0x97, 0xe4, 0x27, 0x3e, 0x2f, 0xf6, 0x8e, 0x88, 0x3b, - 0x3a, 0xef, 0x48, 0x9e, 0x47, 0x22, 0x89, 0xdf, 0x6f, 0xc8, 0xcc, 0x7e, 0xbf, 0xe1, 0x43, 0x21, - 0x2b, 0xc8, 0x38, 0xe2, 0x25, 0x2b, 0x90, 0xb6, 0xcd, 0x53, 0x2a, 0x78, 0x4d, 0xc3, 0x4f, 0x52, - 0x77, 0xac, 0xaf, 0x44, 0xe8, 0x13, 0x7e, 0xaa, 0xdb, 0x50, 0xd2, 0x12, 0x96, 0x60, 0x59, 0x72, - 0xaa, 0x04, 0xc9, 0xa7, 0x68, 0x66, 0x1d, 0xa4, 0x95, 0x66, 0x3e, 0x95, 0x40, 0x0d, 0x84, 0x74, - 0x78, 0x6e, 0xf8, 0xc3, 0x23, 0xc3, 0x6f, 0x5b, 0xee, 0x61, 0x78, 0x84, 0x5d, 0xce, 0x7d, 0x9d, - 0x72, 0x17, 0x02, 0x07, 0x45, 0x43, 0x8f, 0xbd, 0xe8, 0x10, 0x79, 0xf4, 0x32, 0xbc, 0x6b, 0x9d, - 0x08, 0xfe, 0x37, 0x00, 0xb0, 0xff, 0x05, 0x9a, 0x9f, 0xb0, 0x15, 0x3d, 0xc7, 0xe4, 0x68, 0x75, - 0x43, 0xb4, 0x57, 0xdc, 0x5b, 0x69, 0x58, 0x23, 0xd5, 0x11, 0x23, 0xcf, 0x1b, 0x24, 0x3a, 0xe1, - 0x3b, 0x0d, 0x23, 0xbb, 0x05, 0xe5, 0xc8, 0x6c, 0xa7, 0xd7, 0x8f, 0x78, 0xf1, 0xa5, 0x08, 0xd6, - 0x99, 0x8e, 0xd5, 0xdf, 0x4f, 0x43, 0xb9, 0xc6, 0x83, 0x50, 0x26, 0x67, 0xdd, 0x49, 0xc8, 0x7e, - 0x1d, 0x2e, 0x06, 0xc7, 0xf6, 0x44, 0x3c, 0xe5, 0x4e, 0xb1, 0x1f, 0x14, 0x04, 0x2c, 0x3a, 0xf1, - 0xbe, 0xd4, 0x89, 0x82, 0xe5, 0x41, 0xef, 0xd8, 0x9e, 0xf0, 0xd8, 0xf3, 0x96, 0x79, 0x4a, 0x81, - 0xde, 0xfc, 0xe8, 0x9b, 0x05, 0x0b, 0x08, 0xba, 0xd3, 0x8b, 0xd9, 0x4f, 0x8e, 0x45, 0xb6, 0xe2, - 0x84, 0x1f, 0x81, 0xfb, 0xc7, 0x9c, 0xe6, 0x3e, 0x6c, 0xf0, 0xeb, 0x26, 0x8b, 0xbb, 0xd4, 0x3a, - 0x47, 0xcc, 0xe6, 0x77, 0x0f, 0x36, 0x28, 0x3f, 0xf1, 0xc4, 0x9e, 0x3e, 0xf4, 0x26, 0x67, 0xe2, - 0x64, 0xed, 0xad, 0x73, 0xaa, 0xda, 0xe2, 0xa4, 0x08, 0x12, 0xcf, 0x73, 0x04, 0x49, 0xe8, 0xd5, - 0x26, 0x5c, 0x3e, 0xa7, 0x4d, 0xaf, 0x3b, 0xbd, 0x2f, 0x48, 0xa7, 0xf7, 0x57, 0xb7, 0x61, 0x73, - 0x59, 0x79, 0xdf, 0x26, 0x0f, 0xf5, 0x3f, 0x95, 0x01, 0x66, 0x33, 0x36, 0xa1, 0xb3, 0xa5, 0xe6, - 0x74, 0xb6, 0x6f, 0x15, 0x7f, 0xf2, 0x01, 0x54, 0xb0, 0xab, 0xf4, 0x19, 0x47, 0x7a, 0x29, 0x47, - 0x19, 0xa9, 0xfa, 0xb3, 0x7b, 0x7e, 0x8b, 0x27, 0xfe, 0x99, 0xa5, 0x27, 0xfe, 0xef, 0x43, 0x9e, - 0x9f, 0x46, 0x05, 0xe2, 0x9e, 0xe8, 0xe5, 0xf9, 0xd5, 0xf7, 0x40, 0xc4, 0xb1, 0x47, 0x74, 0xac, - 0x09, 0x15, 0x94, 0x8f, 0xbe, 0x1d, 0x1e, 0x8d, 0xe5, 0x5b, 0xa3, 0x37, 0x16, 0x39, 0x23, 0x32, - 0xfe, 0x30, 0x9f, 0x21, 0x27, 0x25, 0x15, 0x2f, 0x1c, 0x0b, 0x17, 0x29, 0xa9, 0x78, 0x79, 0x59, - 0xc5, 0xeb, 0x8f, 0xb9, 0x63, 0x14, 0x55, 0xbc, 0x77, 0xe1, 0x82, 0xb8, 0x5b, 0x83, 0x0c, 0xd8, - 0x9d, 0x44, 0xcf, 0x43, 0x0d, 0xc5, 0xab, 0x35, 0xfd, 0x31, 0x19, 0x40, 0x48, 0xfe, 0x39, 0x6c, - 0x0e, 0x8f, 0x0c, 0xf7, 0xd0, 0xd2, 0xc3, 0x81, 0xa3, 0xd3, 0xb3, 0xe0, 0xfa, 0xd8, 0x98, 0x08, - 0xcd, 0xf3, 0xad, 0x85, 0xca, 0xd6, 0x89, 0xb8, 0x3f, 0x70, 0x28, 0x56, 0x2a, 0x8e, 0x0b, 0xd9, - 0x18, 0xce, 0xc3, 0xe7, 0x8e, 0x67, 0x61, 0xe1, 0x78, 0x76, 0x5e, 0x17, 0x2d, 0x2d, 0xd1, 0x45, - 0x67, 0x1a, 0x65, 0x59, 0xd6, 0x28, 0xd9, 0x3b, 0x90, 0x17, 0x17, 0x16, 0x85, 0x73, 0x94, 0x2d, - 0xae, 0x0e, 0x2d, 0x22, 0xc1, 0x92, 0xa2, 0x60, 0x01, 0xba, 0xb3, 0x5c, 0xe1, 0x25, 0xc9, 0x30, - 0xb6, 0x2d, 0x3c, 0x83, 0x71, 0x5c, 0x97, 0x70, 0x84, 0x5e, 0x95, 0x32, 0x8e, 0x71, 0xc2, 0x78, - 0x9d, 0xe3, 0xb8, 0xfa, 0xdf, 0xb2, 0x90, 0x13, 0x21, 0xc4, 0xf7, 0x21, 0x63, 0xfa, 0xde, 0x24, - 0x8e, 0xc9, 0x5d, 0xa2, 0xda, 0xd2, 0x2f, 0x41, 0xa1, 0x16, 0xfc, 0x00, 0x72, 0x86, 0x69, 0xea, - 0xa3, 0xe3, 0xe4, 0xa1, 0xed, 0x9c, 0x96, 0xb9, 0xbb, 0xa2, 0x65, 0x0d, 0x52, 0x37, 0x3f, 0x86, - 0x22, 0xd2, 0xcf, 0x22, 0x25, 0x4b, 0x8b, 0xba, 0x73, 0xa4, 0x0f, 0xee, 0xae, 0x68, 0x05, 0x23, - 0xd2, 0x0d, 0x7f, 0x98, 0x74, 0x7f, 0x67, 0x16, 0x1a, 0x38, 0xa7, 0xcc, 0xcc, 0x39, 0xc2, 0x7f, - 0x15, 0xb8, 0x3f, 0x34, 0xde, 0xb1, 0xb3, 0xf2, 0xf9, 0xe0, 0xc2, 0xfe, 0xbe, 0xbb, 0xa2, 0xf1, - 0x7d, 0x2b, 0xda, 0xef, 0x3f, 0x8c, 0x5c, 0xd3, 0xf1, 0x2f, 0x66, 0x2c, 0xe9, 0x19, 0x14, 0x83, - 0xb1, 0x7f, 0x9a, 0x64, 0x22, 0xb2, 0x99, 0x66, 0x14, 0x30, 0x97, 0x5f, 0x60, 0x8b, 0x77, 0x75, - 0x62, 0x8b, 0xb7, 0xf8, 0x27, 0x50, 0xe2, 0x9e, 0x4a, 0xce, 0x57, 0x58, 0xe8, 0xda, 0xd9, 0xa6, - 0x4c, 0x67, 0x5f, 0xb3, 0x2d, 0xba, 0x1e, 0xb5, 0xd3, 0xb7, 0xe4, 0xe3, 0x85, 0xeb, 0x4b, 0x3b, - 0x4a, 0x8b, 0x4f, 0x1a, 0x78, 0x63, 0x35, 0xce, 0xc3, 0xda, 0xb0, 0x29, 0xfc, 0xf0, 0x7c, 0x03, - 0x8e, 0xf6, 0x4c, 0x58, 0x18, 0xaf, 0xc4, 0x0e, 0xbd, 0xbb, 0xa2, 0x31, 0x63, 0x71, 0xdf, 0xae, - 0xc3, 0x46, 0x54, 0x25, 0x7e, 0x55, 0x74, 0x16, 0x15, 0x24, 0x37, 0x69, 0xb6, 0xef, 0xee, 0xae, - 0x68, 0xeb, 0x46, 0x12, 0xc4, 0x5a, 0x70, 0x21, 0xca, 0x84, 0xfc, 0xd1, 0xa2, 0x67, 0xca, 0x0b, - 0xa3, 0x28, 0xef, 0xd5, 0xbb, 0x2b, 0xda, 0x86, 0x31, 0x0f, 0x9c, 0x9d, 0xce, 0x5f, 0xd5, 0xe0, - 0xd2, 0x72, 0x91, 0x20, 0xef, 0x0b, 0x19, 0xbe, 0x2f, 0xa8, 0xc9, 0x17, 0x98, 0x92, 0x8f, 0x06, - 0x48, 0xbb, 0xc4, 0xa7, 0xb0, 0x96, 0x90, 0x89, 0xac, 0x04, 0xf9, 0xe8, 0xad, 0x66, 0x8a, 0xf3, - 0xaf, 0x77, 0xf7, 0xbf, 0x50, 0x52, 0x08, 0x6e, 0x75, 0x7a, 0xfd, 0x5a, 0x47, 0xc4, 0x5e, 0xb4, - 0x3a, 0x22, 0xf6, 0x42, 0xfd, 0x2b, 0x69, 0x28, 0xc6, 0x67, 0x47, 0xdf, 0xdd, 0xc7, 0x13, 0x3b, - 0x4f, 0xd2, 0xb2, 0xf3, 0x64, 0xce, 0x80, 0xe1, 0xcf, 0xaa, 0xf3, 0x97, 0xb9, 0xd6, 0x93, 0x66, - 0x42, 0xb0, 0x78, 0xd7, 0x38, 0xfb, 0x0d, 0xef, 0x1a, 0xcb, 0xd1, 0xcd, 0xb9, 0x64, 0x74, 0xf3, - 0xdc, 0x7b, 0xdd, 0x79, 0x7a, 0x49, 0x57, 0x7e, 0xaf, 0x9b, 0x7e, 0x54, 0xef, 0xb9, 0x6d, 0x9d, - 0x88, 0x70, 0x60, 0x91, 0x4a, 0x6e, 0xa9, 0xf0, 0x9a, 0x2d, 0xf5, 0x9b, 0x88, 0xe7, 0x47, 0xb0, - 0x39, 0x3a, 0x8e, 0xdf, 0xef, 0x9d, 0xb9, 0x0c, 0xca, 0x54, 0xa5, 0xa5, 0x38, 0xf5, 0x2f, 0xa5, - 0x00, 0x66, 0x87, 0x25, 0xbf, 0xb0, 0xdf, 0x51, 0x72, 0xed, 0xa4, 0x5f, 0xe1, 0xda, 0x79, 0xdd, - 0x2b, 0x4c, 0x5f, 0x41, 0x31, 0x3e, 0x1e, 0xfb, 0xee, 0xf3, 0xe5, 0x5b, 0x15, 0xf9, 0x1b, 0x91, - 0x0f, 0x36, 0x3e, 0x5f, 0xfa, 0x45, 0xfb, 0x22, 0x51, 0x7c, 0xfa, 0x35, 0xc5, 0x9f, 0x72, 0x47, - 0x68, 0x5c, 0xf8, 0x2f, 0x79, 0x91, 0xc8, 0xf3, 0x37, 0x93, 0x98, 0xbf, 0xea, 0x54, 0x78, 0x73, - 0x7f, 0xf1, 0xa2, 0xbf, 0x55, 0x83, 0xff, 0x4b, 0x2a, 0x72, 0x39, 0xc6, 0x2f, 0x29, 0x9f, 0xab, - 0x7c, 0x2e, 0xf7, 0x9a, 0x7e, 0x9b, 0xe2, 0x5e, 0xe9, 0x50, 0xc9, 0xbc, 0xca, 0xa1, 0xf2, 0x16, - 0x64, 0xf9, 0xb6, 0x93, 0x3d, 0xcf, 0x99, 0xc2, 0xf1, 0xaf, 0xfd, 0xbd, 0x03, 0x55, 0x15, 0xca, - 0x36, 0x6f, 0xef, 0x66, 0x94, 0x6f, 0xf4, 0x5b, 0x0d, 0x74, 0xa9, 0xe2, 0xff, 0xe1, 0x82, 0xf2, - 0xbb, 0x76, 0xc9, 0xab, 0x5d, 0x05, 0xea, 0xff, 0x4a, 0xc1, 0x5a, 0xe2, 0xb8, 0xfb, 0x3b, 0x14, - 0xb1, 0x54, 0xdc, 0xa6, 0xff, 0x0f, 0x12, 0xb7, 0x89, 0x48, 0xd1, 0x42, 0x32, 0x52, 0x14, 0xc5, - 0x5d, 0x39, 0x61, 0x4a, 0x2c, 0x33, 0x3a, 0x52, 0x4b, 0x8d, 0x8e, 0x1b, 0xf1, 0xaf, 0xb4, 0xb5, - 0x1a, 0x3c, 0x30, 0x73, 0x4d, 0x93, 0x20, 0xec, 0x13, 0xb8, 0x22, 0x8c, 0x79, 0xde, 0x3f, 0xde, - 0x48, 0x8f, 0x7f, 0xc3, 0x4d, 0x18, 0xc7, 0x97, 0x38, 0x01, 0xff, 0xb5, 0x8a, 0x51, 0x2d, 0xc2, - 0xaa, 0x2d, 0x58, 0x4b, 0xc4, 0x11, 0x48, 0xbf, 0x19, 0x99, 0x92, 0x7f, 0x33, 0x92, 0x6d, 0x41, - 0xf6, 0xe4, 0xc8, 0xf2, 0xad, 0x25, 0x2f, 0xad, 0x72, 0x84, 0xfa, 0x03, 0x28, 0xcb, 0x31, 0x4d, - 0xec, 0x1d, 0xc8, 0xda, 0xa1, 0x35, 0x8e, 0xdc, 0x14, 0x97, 0x16, 0xc3, 0x9e, 0x5a, 0xa1, 0x35, - 0xd6, 0x38, 0x91, 0xfa, 0xb3, 0x14, 0x28, 0xf3, 0x38, 0xe9, 0x87, 0x2d, 0x53, 0xe7, 0xfc, 0xb0, - 0xe5, 0x6a, 0xa2, 0x92, 0xcb, 0x7e, 0x9b, 0x32, 0x7e, 0xed, 0x31, 0x73, 0xce, 0x6b, 0x8f, 0xec, - 0x2e, 0x14, 0x7c, 0x8b, 0x7e, 0x35, 0xd0, 0x5c, 0x72, 0xd9, 0x20, 0xc6, 0xa9, 0xbf, 0x93, 0x82, - 0xbc, 0x08, 0xc0, 0x5a, 0xea, 0x37, 0xfa, 0x1e, 0xe4, 0xf9, 0x2f, 0x08, 0x46, 0x8f, 0x21, 0x2d, - 0x44, 0x33, 0x47, 0x78, 0x76, 0x83, 0x87, 0xa5, 0x25, 0xfd, 0x48, 0xfb, 0x8e, 0xe1, 0x6a, 0x04, - 0x17, 0x3f, 0x42, 0x63, 0x8c, 0xc5, 0x3d, 0x66, 0xfe, 0x64, 0x11, 0x10, 0x88, 0xae, 0x2c, 0xab, - 0x3f, 0x84, 0xbc, 0x08, 0xf0, 0x5a, 0x5a, 0x95, 0xd7, 0xfd, 0x7a, 0xdc, 0x16, 0xc0, 0x2c, 0xe2, - 0x6b, 0x59, 0x0e, 0xea, 0x7d, 0x28, 0x44, 0x41, 0x5e, 0x38, 0xff, 0x66, 0x45, 0x8b, 0x5b, 0x2c, - 0x72, 0x65, 0x1c, 0xf1, 0x7a, 0x79, 0xdb, 0x1b, 0x1e, 0x93, 0x67, 0xf7, 0x21, 0xd0, 0x95, 0x9e, - 0xfe, 0xc2, 0xdb, 0x4e, 0xc9, 0xa7, 0xe7, 0x63, 0x22, 0x76, 0x1f, 0x62, 0x79, 0xf9, 0x3a, 0x13, - 0x5f, 0xad, 0x45, 0x97, 0xbf, 0x68, 0x96, 0x3d, 0x16, 0x1e, 0xcc, 0x36, 0x3d, 0xf5, 0x96, 0x92, - 0x7f, 0x80, 0x20, 0x51, 0x27, 0x4d, 0x22, 0x53, 0x2b, 0x50, 0x96, 0x23, 0x53, 0xd4, 0x1a, 0x6c, - 0xec, 0x59, 0xa1, 0x81, 0xf2, 0x27, 0x7a, 0x24, 0x87, 0xcf, 0x5f, 0xfc, 0x48, 0xce, 0xdf, 0x79, - 0x3a, 0x8d, 0x13, 0xa9, 0x3f, 0xcb, 0x80, 0x32, 0x8f, 0x7b, 0xd5, 0x45, 0xb8, 0x9b, 0x50, 0xf2, - 0x68, 0x5e, 0x24, 0x7e, 0x66, 0x88, 0x83, 0xa4, 0xb0, 0xf3, 0xc4, 0x6f, 0x4d, 0x14, 0xec, 0x60, - 0x97, 0xff, 0xda, 0xc4, 0x65, 0x7e, 0xeb, 0xc9, 0xf1, 0x86, 0x34, 0xad, 0xcb, 0x74, 0xc9, 0xa9, - 0xed, 0x0d, 0xe9, 0x7e, 0x9d, 0xf0, 0x12, 0xf0, 0x70, 0xc9, 0xb2, 0x56, 0x10, 0xae, 0x01, 0x3a, - 0x6c, 0x12, 0xc1, 0xe8, 0x61, 0x20, 0x6e, 0x2c, 0x16, 0x38, 0xa0, 0x1f, 0x44, 0x6f, 0x64, 0x0f, - 0xc5, 0x6f, 0xe2, 0xa4, 0xe9, 0x8d, 0xec, 0xba, 0x4b, 0xd7, 0xeb, 0xe8, 0x27, 0x9c, 0x86, 0xe2, - 0x27, 0xb6, 0xc4, 0x2b, 0xe5, 0x88, 0xba, 0xcd, 0x7f, 0x35, 0xc8, 0xb7, 0x82, 0x80, 0x3f, 0x77, - 0x56, 0x14, 0x4f, 0xbd, 0x09, 0x60, 0xfc, 0xa0, 0xa2, 0xf8, 0xcd, 0x26, 0x24, 0x01, 0xf1, 0x2c, - 0x19, 0xff, 0xc5, 0x26, 0x24, 0xb8, 0x02, 0x85, 0xaf, 0x3d, 0xd7, 0x22, 0x6f, 0x43, 0x89, 0x6a, - 0x95, 0xc7, 0xf4, 0x9e, 0x31, 0x51, 0xff, 0x69, 0x0a, 0x36, 0xe7, 0x7b, 0x95, 0x26, 0x4c, 0x19, - 0x0a, 0xf5, 0x6e, 0x5b, 0xef, 0xd4, 0xf6, 0x9a, 0xca, 0x0a, 0x5b, 0x87, 0x52, 0x77, 0xfb, 0xb3, - 0x66, 0xbd, 0xcf, 0x01, 0x29, 0xba, 0x66, 0xde, 0xd3, 0x77, 0x5b, 0x8d, 0x46, 0xb3, 0xc3, 0x4d, - 0x82, 0xee, 0xf6, 0x67, 0x7a, 0xbb, 0x5b, 0xe7, 0x3f, 0xf1, 0x12, 0x1d, 0xc4, 0xf7, 0x94, 0x0c, - 0x1d, 0xd3, 0x53, 0x74, 0x36, 0x26, 0xb3, 0x3c, 0xf8, 0xf8, 0x45, 0x4f, 0xaf, 0x77, 0xfa, 0x4a, - 0x0e, 0x53, 0x9d, 0x83, 0x76, 0x9b, 0x52, 0x14, 0x65, 0x58, 0xef, 0xee, 0xed, 0x6b, 0xcd, 0x5e, - 0x4f, 0xef, 0xb5, 0x7e, 0xd2, 0x54, 0x0a, 0x54, 0xb2, 0xd6, 0x7a, 0xda, 0xea, 0x70, 0x40, 0x91, - 0xe5, 0x21, 0xbd, 0xd7, 0xea, 0xf0, 0xeb, 0xf5, 0x7b, 0xb5, 0xcf, 0x95, 0x12, 0x7e, 0xf4, 0x0e, - 0xf6, 0x94, 0xb2, 0xfa, 0xef, 0xd3, 0x91, 0xc2, 0x4b, 0x31, 0x37, 0xdf, 0x44, 0xc9, 0x5b, 0x76, - 0xd6, 0xb5, 0x09, 0x59, 0x87, 0x2e, 0x0c, 0x8b, 0x5f, 0xaf, 0xa5, 0xc4, 0x37, 0xf9, 0x45, 0xce, - 0xdb, 0xb0, 0x16, 0x1f, 0x54, 0x4b, 0xcf, 0x56, 0x97, 0x23, 0xe0, 0x92, 0x13, 0x81, 0xdc, 0x92, - 0x13, 0x81, 0x89, 0x1d, 0xa2, 0x31, 0x8b, 0x22, 0x95, 0x4f, 0x94, 0x22, 0x42, 0xf8, 0x6f, 0xe1, - 0x5e, 0x03, 0x4a, 0xe8, 0x53, 0xd7, 0x8e, 0x7e, 0x8f, 0xad, 0x80, 0x80, 0x03, 0xd7, 0x0e, 0xe7, - 0x0f, 0xca, 0x8b, 0x0b, 0x07, 0xe5, 0xf2, 0xde, 0x0b, 0xc9, 0xbd, 0x37, 0xf9, 0x43, 0xa5, 0xfc, - 0x87, 0xd8, 0xa4, 0x1f, 0x2a, 0x7d, 0x07, 0xd8, 0x70, 0xea, 0xd3, 0xfb, 0x5b, 0x12, 0x59, 0x99, - 0xc8, 0x14, 0x81, 0x89, 0x37, 0x3d, 0xf6, 0x16, 0xac, 0xcf, 0x51, 0x93, 0xf3, 0xa8, 0xa8, 0x55, - 0x92, 0xa4, 0xec, 0x01, 0x5c, 0x10, 0x53, 0x37, 0xd1, 0xb7, 0xe2, 0x32, 0x22, 0x47, 0xd5, 0x66, - 0x3d, 0xac, 0xfe, 0x0a, 0x14, 0xa2, 0xf0, 0xaa, 0x57, 0xeb, 0xb2, 0x4b, 0xc6, 0x55, 0xfd, 0x7b, - 0xab, 0x50, 0x8c, 0x83, 0xad, 0xbe, 0xd1, 0xec, 0xa0, 0xf7, 0xf9, 0x83, 0x63, 0x59, 0x82, 0x14, - 0x10, 0x10, 0x8d, 0x94, 0xb8, 0xf3, 0x33, 0xf5, 0xed, 0x48, 0x21, 0xe3, 0x90, 0x03, 0xdf, 0xa6, - 0xe7, 0x2c, 0x6c, 0x57, 0xba, 0x36, 0x58, 0xd4, 0x0a, 0x08, 0xa0, 0xd5, 0x75, 0x05, 0xe8, 0x9b, - 0x38, 0xa3, 0xdf, 0x6e, 0xb5, 0xdd, 0x63, 0xe4, 0x3b, 0xe7, 0xb7, 0x5b, 0xe9, 0xd7, 0x05, 0x78, - 0xa4, 0x07, 0x3f, 0xdf, 0x8e, 0x7e, 0x0b, 0xeb, 0x1a, 0x14, 0xa7, 0xf1, 0x8f, 0xa9, 0x89, 0x19, - 0x31, 0x8d, 0x7e, 0x4a, 0x2d, 0x39, 0xaa, 0xc5, 0xf9, 0x51, 0x9d, 0x9f, 0xd3, 0xb0, 0x30, 0xa7, - 0xd5, 0x10, 0xf2, 0x22, 0xe0, 0xec, 0xd5, 0x1d, 0xfe, 0xca, 0xae, 0x52, 0x20, 0x6d, 0x38, 0xd1, - 0x5d, 0x45, 0xfc, 0x9c, 0xab, 0x58, 0x66, 0xae, 0x62, 0xea, 0x5f, 0x5f, 0x05, 0x98, 0x05, 0xae, - 0xb1, 0x77, 0xe7, 0x82, 0x64, 0x53, 0x0b, 0xbb, 0xfa, 0x5c, 0x6c, 0xec, 0xdc, 0xfb, 0x2e, 0xab, - 0xdf, 0xe0, 0x7d, 0x97, 0x47, 0xb0, 0x16, 0xf8, 0xc3, 0xd7, 0xfa, 0xb5, 0x4b, 0x81, 0x3f, 0x8c, - 0xdd, 0xda, 0x0f, 0x01, 0x93, 0xf4, 0x22, 0xdd, 0xcc, 0x0e, 0x5d, 0x50, 0x4a, 0x8a, 0x81, 0x3f, - 0xec, 0x0e, 0xbe, 0x6c, 0xf0, 0x8b, 0x56, 0x66, 0x10, 0xea, 0xcb, 0xa4, 0xc4, 0xba, 0x19, 0x84, - 0x0d, 0x59, 0x50, 0xdc, 0x81, 0x0a, 0xd2, 0x2e, 0x08, 0x8b, 0xb2, 0x19, 0xcc, 0xce, 0x31, 0xd4, - 0xdf, 0x8e, 0x8e, 0x47, 0xe7, 0x5c, 0xa6, 0xec, 0x23, 0x61, 0x67, 0x4b, 0x3a, 0x42, 0x75, 0x99, - 0x87, 0x95, 0xbf, 0x46, 0x13, 0x93, 0x2e, 0xfe, 0x84, 0xd6, 0xea, 0x37, 0xfc, 0x09, 0xad, 0xfb, - 0xb7, 0xa0, 0x2c, 0xff, 0x4c, 0x25, 0x5d, 0xf7, 0xf0, 0x5c, 0x8b, 0xff, 0x90, 0x41, 0xfb, 0xeb, - 0x0f, 0x94, 0xd4, 0x7d, 0x15, 0x4a, 0xd2, 0xcf, 0x88, 0x20, 0xc5, 0xae, 0x11, 0x1c, 0x89, 0x47, - 0xed, 0x0d, 0xf7, 0xd0, 0x52, 0x52, 0xf7, 0xef, 0xa2, 0xc6, 0x2c, 0xff, 0x88, 0x07, 0x40, 0xae, - 0xe3, 0xf9, 0x63, 0xc3, 0x11, 0x74, 0xd6, 0x34, 0x40, 0xba, 0x87, 0x70, 0x71, 0xe9, 0x4f, 0x92, - 0xd0, 0x9d, 0x21, 0x7b, 0x3c, 0x71, 0x2c, 0x7e, 0xed, 0x65, 0xf7, 0x6c, 0xe0, 0xdb, 0xa6, 0x92, - 0xba, 0xff, 0x24, 0xba, 0x43, 0x1f, 0x95, 0xdd, 0xee, 0xd6, 0x1a, 0x7c, 0x73, 0x8b, 0xdf, 0x72, - 0xe9, 0x6f, 0xf3, 0x07, 0xeb, 0xb5, 0x66, 0xef, 0xa0, 0xdd, 0x17, 0xef, 0xc6, 0xdc, 0xff, 0x14, - 0xaa, 0xe7, 0xdd, 0xff, 0xc0, 0x1a, 0xd5, 0x77, 0x6b, 0x74, 0xc7, 0x06, 0x37, 0xb3, 0xae, 0xce, - 0x53, 0x29, 0x7e, 0x45, 0xa9, 0xdd, 0xa4, 0x20, 0xc9, 0xfb, 0x3f, 0x4d, 0x49, 0x2a, 0x5c, 0x14, - 0xc3, 0x1f, 0x03, 0x44, 0x37, 0xc9, 0x20, 0xcd, 0x32, 0x4c, 0x25, 0xc5, 0x2e, 0x01, 0x4b, 0x80, - 0xda, 0xde, 0xd0, 0x70, 0x94, 0x55, 0x0a, 0x87, 0x8c, 0xe0, 0x74, 0x4b, 0x4b, 0x49, 0xb3, 0x37, - 0xe0, 0x4a, 0x0c, 0x6b, 0x7b, 0x27, 0xfb, 0xbe, 0xed, 0xf9, 0x76, 0x78, 0xc6, 0xd1, 0x99, 0xfb, - 0xff, 0xaf, 0x38, 0xa7, 0x4c, 0x8c, 0x3c, 0x16, 0x50, 0x33, 0xcd, 0x19, 0x8c, 0x84, 0x8d, 0xb2, - 0xc2, 0x2e, 0xc3, 0x05, 0x92, 0xb4, 0x73, 0x88, 0x14, 0xbb, 0x06, 0x97, 0x23, 0x3b, 0x73, 0x1e, - 0xb9, 0x8a, 0x48, 0xcd, 0xa2, 0x50, 0xba, 0x05, 0x64, 0x7a, 0xfb, 0x47, 0x7f, 0xf2, 0xf3, 0x1b, - 0xa9, 0x7f, 0xf1, 0xf3, 0x1b, 0xa9, 0xff, 0xf0, 0xf3, 0x1b, 0x2b, 0x3f, 0xfb, 0x8f, 0x37, 0x52, - 0x3f, 0x79, 0xf7, 0xd0, 0x0e, 0x8f, 0xa6, 0x83, 0x07, 0x43, 0x6f, 0xfc, 0x70, 0x6c, 0x84, 0xbe, - 0x7d, 0xca, 0x45, 0x7e, 0x94, 0x70, 0xad, 0x87, 0x93, 0xe3, 0xc3, 0x87, 0x93, 0xc1, 0x43, 0x9c, - 0x7c, 0x83, 0xdc, 0xc4, 0xf7, 0x42, 0xef, 0xf1, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xb8, 0x5b, - 0x0d, 0x43, 0x30, 0x84, 0x00, 0x00, + 0xb5, 0xc2, 0x48, 0x24, 0xd4, 0x3f, 0x4d, 0x43, 0xf6, 0xc7, 0x53, 0xcb, 0x3f, 0x63, 0x1f, 0x41, + 0x31, 0x08, 0xc7, 0xa1, 0x7c, 0xbe, 0x7a, 0x85, 0x67, 0x40, 0x78, 0x3a, 0x1e, 0xb5, 0xc6, 0x96, + 0x1b, 0x72, 0x57, 0x24, 0xd2, 0xd2, 0x66, 0xb2, 0x09, 0xd9, 0x20, 0xb4, 0x26, 0x81, 0x88, 0x50, + 0xe3, 0x09, 0xb6, 0x05, 0x59, 0xd7, 0x33, 0xad, 0x20, 0x19, 0x87, 0xd6, 0x41, 0xed, 0x81, 0x23, + 0x98, 0x0a, 0xb9, 0x78, 0xc4, 0x17, 0xce, 0x38, 0x39, 0x86, 0x6e, 0x16, 0x58, 0x86, 0x69, 0xbb, + 0x87, 0xd1, 0xed, 0xd3, 0x38, 0x8d, 0xdb, 0x24, 0x29, 0xeb, 0xc6, 0x61, 0x74, 0x15, 0x5c, 0x24, + 0xd9, 0x16, 0x94, 0xf0, 0xf3, 0x85, 0x6f, 0x87, 0x56, 0xef, 0x71, 0x24, 0xa9, 0x25, 0x10, 0xaa, + 0xda, 0xa6, 0x15, 0x5a, 0xc3, 0xb0, 0xf7, 0x95, 0x08, 0x2e, 0xa3, 0x18, 0xa4, 0x08, 0xc2, 0xbe, + 0x0f, 0x6c, 0x60, 0x0c, 0x8f, 0x0f, 0x7d, 0x6f, 0xea, 0x9a, 0xfa, 0x57, 0x53, 0xcb, 0xb7, 0xad, + 0x28, 0x98, 0xac, 0x24, 0x75, 0x8a, 0xb6, 0x31, 0x23, 0xfb, 0x31, 0xa7, 0x42, 0x23, 0x61, 0x6c, + 0x9c, 0x36, 0xbc, 0x89, 0x88, 0x9f, 0x11, 0x29, 0xd5, 0x84, 0xb5, 0x44, 0x17, 0x2e, 0x78, 0x7d, + 0x7a, 0xcd, 0x76, 0xb3, 0xde, 0xe7, 0xe6, 0xa2, 0x70, 0x35, 0xac, 0xca, 0xae, 0x8a, 0xb4, 0xe4, + 0xc3, 0xc8, 0x48, 0x36, 0x65, 0x96, 0x3c, 0x20, 0x4d, 0xed, 0x69, 0x53, 0xc9, 0xa9, 0x7f, 0xb0, + 0x0a, 0x1b, 0x7d, 0xdf, 0x70, 0x03, 0x83, 0x6b, 0x18, 0x6e, 0xe8, 0x7b, 0x0e, 0xfb, 0x3e, 0x14, + 0xc2, 0xa1, 0x23, 0x0f, 0xed, 0xcd, 0x48, 0x90, 0xcc, 0x91, 0x3e, 0xe8, 0x0f, 0xb9, 0xaf, 0x39, + 0x1f, 0xf2, 0x0f, 0xf6, 0x2e, 0x64, 0x07, 0xd6, 0xa1, 0xed, 0x0a, 0x59, 0x7a, 0x71, 0x9e, 0x71, + 0x1b, 0x91, 0xbb, 0x2b, 0x1a, 0xa7, 0x62, 0xef, 0x41, 0x6e, 0xe8, 0x8d, 0xa3, 0x0d, 0x69, 0x76, + 0xbb, 0x49, 0x2a, 0x08, 0xb1, 0xbb, 0x2b, 0x9a, 0xa0, 0x63, 0x1f, 0x41, 0xc1, 0xf7, 0x1c, 0x07, + 0x7b, 0x52, 0x6c, 0x55, 0xd5, 0x79, 0x1e, 0x4d, 0xe0, 0x77, 0x57, 0xb4, 0x98, 0x56, 0x7d, 0x00, + 0x79, 0x51, 0x59, 0xec, 0x80, 0xed, 0xe6, 0xd3, 0x96, 0xe8, 0xc8, 0x7a, 0x77, 0x6f, 0xaf, 0xd5, + 0xe7, 0x57, 0x37, 0xb5, 0x6e, 0xbb, 0xbd, 0x5d, 0xab, 0x3f, 0x53, 0x56, 0xb7, 0x0b, 0x90, 0xe3, + 0x5e, 0x45, 0xf5, 0x37, 0x53, 0xb0, 0x3e, 0xd7, 0x00, 0xf6, 0x04, 0x32, 0x63, 0xd4, 0x78, 0x79, + 0xf7, 0xdc, 0x59, 0xda, 0x4a, 0x29, 0xcd, 0xf5, 0x60, 0xe4, 0x50, 0x3f, 0x81, 0x4a, 0x12, 0x2e, + 0x79, 0x16, 0xd6, 0xa0, 0xa8, 0x35, 0x6b, 0x0d, 0xbd, 0xdb, 0x41, 0x7b, 0x1e, 0xed, 0x7b, 0x4a, + 0xbe, 0xd0, 0x5a, 0xe4, 0x0c, 0xf8, 0x35, 0x50, 0xe6, 0x3b, 0x86, 0x3d, 0x45, 0x9b, 0x66, 0x3c, + 0x71, 0x2c, 0x52, 0x1d, 0xa5, 0x21, 0xbb, 0xb1, 0xa4, 0x27, 0x05, 0x19, 0x8d, 0x58, 0x65, 0x98, + 0x48, 0xab, 0xbf, 0x0e, 0x6c, 0xb1, 0x07, 0x7f, 0x79, 0xd9, 0xff, 0x8f, 0x14, 0x64, 0xf6, 0x1d, + 0xc3, 0x65, 0xb7, 0x21, 0x4b, 0x4f, 0x8e, 0x08, 0x89, 0x2c, 0xaf, 0x0f, 0x9c, 0x16, 0x84, 0x63, + 0x6f, 0x43, 0x3a, 0x1c, 0x46, 0x37, 0x46, 0x2f, 0x9f, 0x33, 0xf9, 0x76, 0x57, 0x34, 0xa4, 0x62, + 0xf7, 0x20, 0x6d, 0x9a, 0x51, 0xa4, 0xb6, 0xf0, 0x35, 0xa0, 0xa5, 0xd9, 0xb0, 0x46, 0xb6, 0x6b, + 0x8b, 0x27, 0x52, 0x90, 0x84, 0xbd, 0x09, 0x69, 0x73, 0xe8, 0x24, 0xc3, 0xee, 0xb9, 0x4d, 0x1a, + 0x67, 0x68, 0x0e, 0x1d, 0xd4, 0xcc, 0x42, 0xff, 0x4c, 0xf7, 0xa7, 0x2e, 0x85, 0x9e, 0x05, 0xc2, + 0x5a, 0x2a, 0xa1, 0x5e, 0x32, 0xa5, 0xf8, 0xb5, 0x40, 0x5c, 0x3d, 0x9b, 0xf8, 0xd6, 0xc4, 0xf0, + 0x63, 0x3b, 0xc9, 0x0e, 0xf6, 0x39, 0x60, 0x3b, 0x07, 0xf4, 0x92, 0xa3, 0xfa, 0x0e, 0xbd, 0x87, + 0x81, 0x0a, 0xb7, 0x1a, 0x7d, 0x2d, 0x79, 0xf4, 0x4b, 0x60, 0xd4, 0x3f, 0x4f, 0x43, 0x49, 0xaa, + 0x0f, 0xfb, 0x00, 0x0a, 0x66, 0x72, 0x21, 0x5e, 0x59, 0xa8, 0xf4, 0x83, 0x46, 0xb4, 0x04, 0x4d, + 0x31, 0xbd, 0xe9, 0x20, 0x23, 0xd4, 0x5f, 0x1a, 0xbe, 0xcd, 0x5f, 0x41, 0x5a, 0x95, 0x4f, 0x14, + 0x7a, 0x56, 0xf8, 0x3c, 0xc2, 0xec, 0xae, 0x68, 0xe5, 0x40, 0x4a, 0x93, 0x55, 0x20, 0x9a, 0x94, + 0x4e, 0xbc, 0x26, 0xc5, 0x81, 0xbb, 0x2b, 0x5a, 0x84, 0x47, 0x52, 0xeb, 0xd4, 0x1a, 0x4e, 0xc3, + 0xc8, 0x2a, 0x58, 0x8b, 0x1a, 0x44, 0x40, 0x7a, 0xd2, 0x8e, 0x7f, 0xb2, 0x47, 0x28, 0x3f, 0x0d, + 0xc7, 0xf1, 0x48, 0xfd, 0xca, 0xca, 0xfe, 0xfd, 0x46, 0x0c, 0xe7, 0x4f, 0xe8, 0x45, 0x29, 0x76, + 0x17, 0xb2, 0x5e, 0x78, 0x64, 0x45, 0xba, 0x76, 0xf4, 0xb2, 0x06, 0x82, 0x1a, 0xf5, 0x36, 0xce, + 0x14, 0x42, 0xab, 0x3f, 0x4b, 0x41, 0x5e, 0xf4, 0x00, 0xdb, 0x80, 0xb5, 0x5e, 0xb3, 0xaf, 0x3f, + 0xaf, 0x69, 0xad, 0xda, 0x76, 0xbb, 0x29, 0x6e, 0x0b, 0x3c, 0xd5, 0x6a, 0x1d, 0x21, 0x27, 0xb5, + 0xe6, 0xf3, 0xee, 0xb3, 0x26, 0x77, 0xd7, 0x35, 0x9a, 0x9d, 0x2f, 0x94, 0x34, 0x77, 0x59, 0x37, + 0xf7, 0x6b, 0x1a, 0x4a, 0xc9, 0x12, 0xe4, 0x9b, 0x9f, 0x37, 0xeb, 0x07, 0x24, 0x26, 0x2b, 0x00, + 0x8d, 0x66, 0xad, 0xdd, 0xee, 0xd6, 0x51, 0x6c, 0xe6, 0x18, 0x83, 0x4a, 0x5d, 0x6b, 0xd6, 0xfa, + 0x4d, 0xbd, 0x56, 0xaf, 0x77, 0x0f, 0x3a, 0x7d, 0x25, 0x8f, 0x25, 0xd6, 0xda, 0xfd, 0xa6, 0x16, + 0x83, 0xe8, 0xb5, 0xa3, 0x86, 0xd6, 0xdd, 0x8f, 0x21, 0xc5, 0xed, 0x22, 0x5a, 0x68, 0x34, 0x56, + 0xea, 0x3f, 0xda, 0x80, 0x4a, 0x72, 0x6a, 0xb2, 0x8f, 0xa1, 0x60, 0x9a, 0x89, 0x31, 0xbe, 0xbe, + 0x6c, 0x0a, 0x3f, 0x68, 0x98, 0xd1, 0x30, 0xf3, 0x0f, 0x76, 0x2b, 0x5a, 0x48, 0xab, 0x0b, 0x0b, + 0x29, 0x5a, 0x46, 0x3f, 0x82, 0x75, 0xf1, 0x32, 0x85, 0x69, 0x84, 0xc6, 0xc0, 0x08, 0xac, 0xe4, + 0x2a, 0xa9, 0x13, 0xb2, 0x21, 0x70, 0xbb, 0x2b, 0x5a, 0x65, 0x98, 0x80, 0xb0, 0x1f, 0x40, 0xc5, + 0x20, 0x23, 0x3c, 0xe6, 0xcf, 0xc8, 0x8a, 0x65, 0x0d, 0x71, 0x12, 0xfb, 0x9a, 0x21, 0x03, 0x70, + 0x22, 0x9a, 0xbe, 0x37, 0x99, 0x31, 0x67, 0x13, 0x47, 0x5b, 0xbe, 0x37, 0x91, 0x78, 0xcb, 0xa6, + 0x94, 0x66, 0x1f, 0x41, 0x59, 0xd4, 0x7c, 0xe6, 0x88, 0x88, 0x97, 0x2c, 0xaf, 0x36, 0x29, 0x8a, + 0xbb, 0x2b, 0x5a, 0x69, 0x38, 0x4b, 0xb2, 0xc7, 0xa8, 0x1d, 0xce, 0xd4, 0xea, 0xbc, 0x3c, 0xd7, + 0xa8, 0xb6, 0x11, 0x17, 0x18, 0x71, 0x8a, 0xbd, 0x07, 0x40, 0xf5, 0xe4, 0x3c, 0x85, 0x44, 0x28, + 0x8a, 0xef, 0x4d, 0x22, 0x96, 0xa2, 0x19, 0x25, 0xa4, 0xea, 0x71, 0x37, 0x52, 0x71, 0xb1, 0x7a, + 0xe4, 0x4a, 0x9a, 0x55, 0x8f, 0x7b, 0xa0, 0xe2, 0xea, 0x71, 0x36, 0x58, 0xa8, 0x5e, 0xc4, 0xc5, + 0xab, 0xc7, 0x99, 0xa2, 0xea, 0x71, 0x9e, 0xd2, 0x7c, 0xf5, 0x22, 0x16, 0xaa, 0x1e, 0xe7, 0xf8, + 0xc1, 0x82, 0x3d, 0x50, 0x3e, 0xd7, 0x1e, 0xc0, 0x61, 0x4b, 0x5a, 0x04, 0x3f, 0x80, 0x4a, 0x70, + 0xe4, 0x9d, 0x48, 0x02, 0x64, 0x4d, 0xe6, 0xee, 0x1d, 0x79, 0x27, 0xb2, 0x04, 0x59, 0x0b, 0x64, + 0x00, 0xd6, 0x96, 0x37, 0x91, 0xae, 0xc4, 0x57, 0xe4, 0xda, 0x52, 0x0b, 0x9f, 0xdb, 0xd6, 0x09, + 0xd6, 0xd6, 0x88, 0x12, 0xd8, 0x29, 0x33, 0xa7, 0x4c, 0x20, 0xdc, 0x2c, 0x89, 0x50, 0x09, 0x51, + 0x12, 0xc4, 0xee, 0x99, 0x00, 0xe7, 0xd6, 0xd4, 0x95, 0xd9, 0x14, 0x79, 0x6e, 0x1d, 0xb8, 0x09, + 0xc6, 0x32, 0x27, 0x15, 0xac, 0xb3, 0x55, 0x11, 0x58, 0x5f, 0x4d, 0x2d, 0x77, 0x68, 0x89, 0x40, + 0xad, 0xc4, 0xaa, 0xe8, 0x09, 0xdc, 0x6c, 0x55, 0x44, 0x90, 0x78, 0x5e, 0xc7, 0xec, 0x6c, 0x7e, + 0x5e, 0x4b, 0xcc, 0x34, 0xaf, 0x63, 0xd6, 0x78, 0x41, 0xc5, 0xbc, 0x17, 0x16, 0x16, 0x94, 0xc4, + 0xcc, 0x17, 0x54, 0xcc, 0xfd, 0x18, 0xc4, 0x6c, 0xe2, 0x9d, 0x9b, 0x08, 0xe7, 0xe2, 0xb5, 0x16, + 0xbd, 0x0b, 0xc3, 0x38, 0x85, 0x73, 0xd5, 0xb7, 0xd0, 0xfe, 0x10, 0x53, 0xe1, 0xa2, 0x3c, 0x57, + 0x35, 0xc2, 0xc4, 0x4b, 0xc9, 0x9f, 0x25, 0xa5, 0xc2, 0x26, 0x76, 0xe8, 0x57, 0xcd, 0xc5, 0xc2, + 0xf6, 0xed, 0xd0, 0x9f, 0x15, 0x86, 0x29, 0xf6, 0x2e, 0xd0, 0x34, 0xe4, 0x2c, 0x96, 0x2c, 0xba, + 0xb1, 0x5b, 0x04, 0x43, 0xc1, 0x14, 0xdf, 0x38, 0x59, 0x44, 0x19, 0x43, 0x73, 0x58, 0x1d, 0xc9, + 0x93, 0x85, 0x17, 0x51, 0x6f, 0xd4, 0x71, 0xb2, 0x70, 0xa2, 0xba, 0x39, 0x64, 0xf7, 0x81, 0xb8, + 0x89, 0xfe, 0x30, 0xf1, 0x72, 0x93, 0xef, 0x4d, 0x38, 0x75, 0x1e, 0x09, 0x90, 0x16, 0x5b, 0xe0, + 0x78, 0x6e, 0xd4, 0xf0, 0xa3, 0x44, 0x0b, 0x10, 0x11, 0x0b, 0x83, 0x61, 0x9c, 0x52, 0x7f, 0x3b, + 0x07, 0x79, 0x21, 0x6b, 0xd9, 0x05, 0x58, 0x17, 0x22, 0xbf, 0x51, 0xeb, 0xd7, 0xb6, 0x6b, 0x3d, + 0x54, 0xd2, 0x18, 0x54, 0xb8, 0xcc, 0x8f, 0x61, 0x29, 0xdc, 0x07, 0x48, 0xe8, 0xc7, 0xa0, 0x55, + 0xdc, 0x07, 0x04, 0x2f, 0x7f, 0x21, 0x2f, 0xcd, 0xd6, 0xa1, 0xc4, 0x19, 0x39, 0x80, 0x2e, 0x2f, + 0x12, 0x17, 0x4f, 0x67, 0x25, 0x16, 0x7e, 0x7a, 0x95, 0x9b, 0xb1, 0x70, 0x40, 0x3e, 0x66, 0x89, + 0x8e, 0xb7, 0x18, 0x54, 0xfa, 0xda, 0x41, 0xa7, 0x3e, 0x2b, 0xa7, 0x48, 0x17, 0xce, 0x78, 0x36, + 0xcf, 0x5b, 0xcd, 0x17, 0x0a, 0x20, 0x13, 0xcf, 0x85, 0xd2, 0x25, 0x54, 0x33, 0x29, 0x13, 0x4a, + 0x96, 0xd9, 0x65, 0xb8, 0xd0, 0xdb, 0xed, 0xbe, 0xd0, 0x39, 0x53, 0xdc, 0x84, 0x35, 0xb6, 0x09, + 0x8a, 0x84, 0xe0, 0xd9, 0x57, 0xb0, 0x48, 0x82, 0x46, 0x84, 0x3d, 0x65, 0x9d, 0x0e, 0x88, 0x11, + 0xd6, 0xe7, 0xfb, 0xae, 0x82, 0x4d, 0xe1, 0xac, 0xdd, 0xf6, 0xc1, 0x5e, 0xa7, 0xa7, 0x6c, 0x60, + 0x25, 0x08, 0xc2, 0x6b, 0xce, 0xe2, 0x6c, 0x66, 0xbb, 0xf5, 0x05, 0xda, 0xc0, 0x11, 0xf6, 0xa2, + 0xa6, 0x75, 0x5a, 0x9d, 0xa7, 0x3d, 0x65, 0x33, 0xce, 0xb9, 0xa9, 0x69, 0x5d, 0xad, 0xa7, 0x5c, + 0x8c, 0x01, 0xbd, 0x7e, 0xad, 0x7f, 0xd0, 0x53, 0x2e, 0xc5, 0xb5, 0xdc, 0xd7, 0xba, 0xf5, 0x66, + 0xaf, 0xd7, 0x6e, 0xf5, 0xfa, 0xca, 0x65, 0x76, 0x11, 0x36, 0x66, 0x35, 0x8a, 0x88, 0xab, 0x52, + 0x45, 0xb5, 0xa7, 0xcd, 0xbe, 0x72, 0x25, 0xae, 0x46, 0xbd, 0xdb, 0x6e, 0xd7, 0xe8, 0x68, 0xf3, + 0x2a, 0x12, 0xd1, 0x19, 0xaf, 0x68, 0xcd, 0x35, 0xac, 0xd7, 0x41, 0x47, 0x06, 0x5d, 0x97, 0xa6, + 0x46, 0xaf, 0xf9, 0xe3, 0x83, 0x66, 0xa7, 0xde, 0x54, 0xde, 0x98, 0x4d, 0x8d, 0x18, 0x76, 0x23, + 0x9e, 0x1a, 0x31, 0xe8, 0x66, 0x5c, 0x66, 0x04, 0xea, 0x29, 0x5b, 0x98, 0x9f, 0xa8, 0x47, 0xa7, + 0xd3, 0xac, 0xf7, 0xb1, 0xad, 0xb7, 0xe2, 0x5e, 0x3c, 0xd8, 0x7f, 0xaa, 0xd5, 0x1a, 0x4d, 0x45, + 0x45, 0x88, 0xd6, 0xec, 0xd4, 0xf6, 0xa2, 0xd1, 0xbe, 0x2d, 0x8d, 0xf6, 0x7e, 0xab, 0xaf, 0x29, + 0x77, 0xe2, 0xd1, 0xa5, 0xe4, 0x9b, 0xec, 0x1a, 0x5c, 0x96, 0xe7, 0xa1, 0xfe, 0xa2, 0xd5, 0xdf, + 0x15, 0x27, 0xb1, 0x77, 0xf9, 0x89, 0x22, 0x21, 0xeb, 0x8d, 0x3a, 0x3f, 0x72, 0x26, 0x5e, 0x4c, + 0xdd, 0xdb, 0x2e, 0xd3, 0x43, 0xc7, 0x42, 0x01, 0x51, 0x3f, 0x03, 0x26, 0xbf, 0xf9, 0x29, 0x1e, + 0xbf, 0x62, 0x90, 0x19, 0xf9, 0xde, 0x38, 0x7a, 0x48, 0x00, 0xbf, 0xd1, 0xa2, 0x9e, 0x4c, 0x07, + 0x74, 0xd2, 0x39, 0xbb, 0x28, 0x2c, 0x83, 0xd4, 0xbf, 0x9b, 0x82, 0x4a, 0x52, 0xf9, 0x20, 0x77, + 0xe8, 0x48, 0x77, 0xbd, 0x90, 0xbf, 0xaa, 0x14, 0xc4, 0x4f, 0x71, 0x8e, 0x3a, 0x5e, 0x48, 0xcf, + 0x2a, 0x91, 0x81, 0x1f, 0xeb, 0x12, 0x3c, 0xd7, 0x38, 0xcd, 0x5a, 0x70, 0x21, 0xf1, 0x6c, 0x6a, + 0xe2, 0x4d, 0xab, 0x6a, 0xfc, 0xdc, 0xe1, 0x5c, 0xfd, 0x35, 0x16, 0x2c, 0xb6, 0x49, 0x5c, 0xf7, + 0xce, 0xcc, 0xae, 0x7b, 0xef, 0xc2, 0x5a, 0x42, 0xd7, 0x21, 0xbf, 0xcc, 0x28, 0x59, 0xd3, 0x82, + 0x3d, 0x7a, 0x7d, 0x35, 0xd5, 0xbf, 0x9d, 0x82, 0xb2, 0xac, 0xf9, 0x7c, 0xe7, 0x9c, 0xe8, 0x6a, + 0x94, 0xf8, 0xd6, 0x6d, 0x33, 0x7a, 0x4d, 0x29, 0x02, 0xb5, 0xe8, 0x81, 0x77, 0xee, 0x59, 0xde, + 0x39, 0xee, 0xc5, 0xcd, 0x91, 0x41, 0xec, 0x06, 0x00, 0x5d, 0x14, 0xdd, 0x79, 0x86, 0x04, 0xe2, + 0x72, 0xd5, 0x0c, 0xa2, 0xde, 0x84, 0xe2, 0xce, 0x71, 0x14, 0xff, 0x22, 0xbf, 0x2d, 0x56, 0xe4, + 0xb7, 0xcb, 0xd5, 0x3f, 0x4e, 0x41, 0x65, 0xf6, 0x0e, 0x0b, 0x9d, 0x37, 0xf3, 0xe7, 0x76, 0xf9, + 0x74, 0x58, 0x35, 0x07, 0xb3, 0xb7, 0xdf, 0x57, 0xe5, 0xb7, 0xdf, 0x6f, 0x8b, 0xcc, 0xd2, 0xb2, + 0xc8, 0x8f, 0xcb, 0x12, 0x77, 0xd7, 0x1f, 0x43, 0x19, 0xff, 0x6b, 0xd6, 0xc8, 0xf2, 0x7d, 0x2b, + 0x7a, 0x79, 0x78, 0x81, 0x38, 0x41, 0x44, 0x36, 0x9e, 0x35, 0x12, 0xaa, 0xe6, 0xd2, 0xa7, 0x62, + 0xe8, 0x09, 0xa3, 0xff, 0x9a, 0x86, 0x92, 0xa4, 0x47, 0x7e, 0xa3, 0xe9, 0x77, 0x1d, 0x8a, 0xb3, + 0x87, 0x4b, 0xc4, 0x85, 0xe1, 0x18, 0x90, 0x18, 0xab, 0xf4, 0xdc, 0x58, 0x55, 0x21, 0x2f, 0xc2, + 0x6a, 0x85, 0x53, 0x38, 0x4a, 0x26, 0xdd, 0xaf, 0xd9, 0xd7, 0x9c, 0x7e, 0xbc, 0x0f, 0x65, 0xc9, + 0x77, 0x1a, 0x88, 0x4b, 0xb5, 0xf3, 0xf4, 0xa5, 0x99, 0x1f, 0x35, 0x60, 0x17, 0x21, 0x37, 0x3a, + 0xd6, 0xcd, 0x01, 0xbf, 0x49, 0x59, 0xd4, 0xb2, 0xa3, 0xe3, 0xc6, 0x80, 0xce, 0x86, 0x46, 0xb1, + 0xea, 0xc4, 0x3d, 0x5a, 0x85, 0x51, 0xa4, 0x20, 0xdd, 0x83, 0xfc, 0xe8, 0x58, 0xbe, 0x11, 0xb9, + 0xd0, 0xe5, 0xb9, 0xd1, 0x31, 0x5d, 0xa1, 0x7c, 0x08, 0x9b, 0x62, 0xff, 0x36, 0x02, 0x9d, 0xbf, + 0xcd, 0x40, 0x0f, 0xda, 0xf0, 0x97, 0xc6, 0x36, 0x38, 0xae, 0x16, 0xf4, 0x08, 0x83, 0x33, 0x4e, + 0x85, 0xb2, 0x34, 0x01, 0xf9, 0xcb, 0x3f, 0x45, 0x2d, 0x01, 0x63, 0x4f, 0xa0, 0x3c, 0x3a, 0xe6, + 0x03, 0xda, 0xf7, 0xf6, 0x2c, 0x11, 0xe5, 0xbf, 0x39, 0x3f, 0x94, 0x14, 0x10, 0x90, 0xa0, 0x64, + 0x97, 0x20, 0xa7, 0x19, 0x27, 0xbd, 0x1f, 0xb7, 0x49, 0x89, 0x2c, 0x6a, 0x22, 0xf5, 0x59, 0xa6, + 0x50, 0x51, 0xd6, 0xd5, 0x7f, 0x9c, 0x82, 0xca, 0xcc, 0x06, 0xc0, 0x45, 0xc8, 0xee, 0xcb, 0xef, + 0x64, 0x57, 0xe7, 0xcd, 0x04, 0x24, 0x79, 0xd0, 0x3f, 0x9b, 0xf0, 0xd7, 0x24, 0x97, 0xbd, 0xd6, + 0xb4, 0xcc, 0x99, 0x9d, 0x5e, 0xfa, 0x42, 0xef, 0x53, 0x48, 0xf7, 0xcf, 0x26, 0xdc, 0xdf, 0x84, + 0x5b, 0x22, 0xb7, 0x4d, 0xf9, 0x66, 0x48, 0x11, 0x27, 0xcf, 0x9a, 0x5f, 0xf0, 0x07, 0x0e, 0xf6, + 0xb5, 0xd6, 0x5e, 0x4d, 0xfb, 0x82, 0x82, 0x89, 0x48, 0x69, 0xd8, 0xe9, 0x6a, 0xcd, 0xd6, 0xd3, + 0x0e, 0x01, 0x32, 0xe4, 0x8d, 0x9a, 0x55, 0xb1, 0x66, 0x9a, 0x3b, 0xc7, 0xf2, 0x43, 0x37, 0xa9, + 0xc4, 0x43, 0x37, 0xc9, 0x3b, 0xd1, 0xab, 0xf3, 0x77, 0xa2, 0x59, 0xbc, 0x0a, 0xe3, 0x25, 0xcd, + 0xde, 0x82, 0xcc, 0xe8, 0xd8, 0x3a, 0x4b, 0x1a, 0x7a, 0xc9, 0x05, 0x44, 0x04, 0xea, 0xcf, 0x53, + 0xc0, 0x12, 0x15, 0xe1, 0xb6, 0xc7, 0x77, 0xad, 0xcb, 0xc7, 0x50, 0x15, 0x4f, 0x2f, 0x72, 0x2a, + 0xc9, 0x7b, 0x2e, 0xba, 0xf4, 0xa2, 0x37, 0x0b, 0xfd, 0x9c, 0x3d, 0x28, 0xc5, 0x1e, 0x02, 0x7f, + 0xfb, 0x8e, 0xe2, 0x47, 0x32, 0xe7, 0xd8, 0x89, 0xda, 0x8c, 0x66, 0xf6, 0xd8, 0x9d, 0xfc, 0x88, + 0x1f, 0x77, 0xbc, 0xaf, 0xcf, 0x46, 0x8d, 0xd6, 0xbc, 0xfa, 0x7b, 0x29, 0xb8, 0x90, 0x9c, 0x10, + 0xbf, 0x58, 0x2b, 0x93, 0x2f, 0x16, 0xa6, 0xe7, 0x5f, 0x2c, 0x5c, 0x36, 0x9f, 0x32, 0x4b, 0xe7, + 0xd3, 0x6f, 0xa5, 0x60, 0x53, 0xea, 0xfd, 0x99, 0xb5, 0xf8, 0x17, 0x54, 0x33, 0xe9, 0xe1, 0xc2, + 0x4c, 0xe2, 0xe1, 0x42, 0xf5, 0x0f, 0x52, 0x70, 0x69, 0xae, 0x26, 0x9a, 0xf5, 0x17, 0x5a, 0x97, + 0xe4, 0x03, 0x87, 0xe4, 0xfc, 0xe7, 0xf1, 0xaf, 0xfc, 0x32, 0x2d, 0x4b, 0xbe, 0x58, 0x48, 0x57, + 0xd7, 0x3f, 0x80, 0x8d, 0x59, 0x1d, 0xeb, 0xe2, 0x31, 0xc6, 0x9b, 0x50, 0x72, 0xad, 0x13, 0x3d, + 0x7a, 0xaa, 0x51, 0x44, 0x0c, 0xb9, 0xd6, 0x89, 0x20, 0x50, 0x77, 0x64, 0x81, 0x11, 0xbf, 0xdb, + 0xee, 0x98, 0x89, 0xd0, 0x13, 0xcf, 0x31, 0x23, 0x14, 0xe6, 0x26, 0xb5, 0x28, 0xef, 0x5a, 0x27, + 0x34, 0x58, 0x27, 0x22, 0x9f, 0x9a, 0x69, 0x8a, 0xe3, 0xf7, 0x65, 0xef, 0x2f, 0x5d, 0x81, 0xc2, + 0xc4, 0x4f, 0x74, 0x49, 0x7e, 0xe2, 0xf3, 0x62, 0xef, 0x88, 0x78, 0xa4, 0xf3, 0x8e, 0xea, 0x79, + 0x84, 0x92, 0xf8, 0x5d, 0x87, 0xcc, 0xec, 0x77, 0x1d, 0x3e, 0x14, 0xb2, 0x82, 0x8c, 0x23, 0x5e, + 0xb2, 0x02, 0x69, 0xdb, 0x3c, 0xa5, 0x82, 0xd7, 0x34, 0xfc, 0x24, 0x75, 0xc7, 0xfa, 0x4a, 0x84, + 0x44, 0xe1, 0xa7, 0xba, 0x0d, 0x25, 0x2d, 0x61, 0x09, 0x96, 0x25, 0xa7, 0x4a, 0x90, 0x7c, 0xa2, + 0x66, 0xd6, 0x41, 0x5a, 0x69, 0xe6, 0x53, 0x09, 0xd4, 0x40, 0x48, 0x87, 0xe7, 0x86, 0x3f, 0x3c, + 0x32, 0xfc, 0xb6, 0xe5, 0x1e, 0x86, 0x47, 0xd8, 0xe5, 0xdc, 0xd7, 0x29, 0x77, 0x21, 0x70, 0x50, + 0x34, 0xf4, 0xd8, 0x8b, 0x0e, 0x91, 0x47, 0x2f, 0xc6, 0xbb, 0xd6, 0x89, 0xe0, 0x7f, 0x03, 0x00, + 0xfb, 0x5f, 0xa0, 0xf9, 0xc9, 0x5b, 0xd1, 0x73, 0x4c, 0x8e, 0x56, 0x37, 0x44, 0x7b, 0xc5, 0x7d, + 0x96, 0x86, 0x35, 0x52, 0x1d, 0x31, 0xf2, 0xbc, 0x41, 0xa2, 0x13, 0xbe, 0xd3, 0x30, 0xb2, 0x5b, + 0x50, 0x8e, 0xcc, 0x76, 0x7a, 0x15, 0x89, 0x17, 0x5f, 0x8a, 0x60, 0x9d, 0xe9, 0x58, 0xfd, 0xfd, + 0x34, 0x94, 0x6b, 0x3c, 0x38, 0x65, 0x72, 0xd6, 0x9d, 0x84, 0xec, 0xd7, 0xe1, 0x62, 0x70, 0x6c, + 0x4f, 0xc4, 0x13, 0xef, 0x14, 0x13, 0x42, 0xc1, 0xc1, 0xa2, 0x13, 0xef, 0x4b, 0x9d, 0x28, 0x58, + 0x1e, 0xf4, 0x8e, 0xed, 0x09, 0x8f, 0x49, 0x6f, 0x99, 0xa7, 0x14, 0x00, 0xce, 0x8f, 0xc4, 0x59, + 0xb0, 0x80, 0xa0, 0xbb, 0xbe, 0x98, 0xfd, 0xe4, 0x58, 0x64, 0x2b, 0x4e, 0xfe, 0x11, 0xb8, 0x7f, + 0xcc, 0x69, 0xee, 0xc3, 0x06, 0xbf, 0x86, 0xb2, 0xb8, 0x4b, 0xad, 0x73, 0xc4, 0x6c, 0x7e, 0xf7, + 0x60, 0x83, 0xf2, 0x13, 0x4f, 0xef, 0xe9, 0x43, 0x6f, 0x72, 0x26, 0x4e, 0xdc, 0xde, 0x3a, 0xa7, + 0xaa, 0x2d, 0x4e, 0x8a, 0x20, 0xf1, 0x6c, 0x47, 0x90, 0x84, 0x5e, 0x6d, 0xc2, 0xe5, 0x73, 0xda, + 0xf4, 0xba, 0x53, 0xfd, 0x82, 0x74, 0xaa, 0x7f, 0x75, 0x1b, 0x36, 0x97, 0x95, 0xf7, 0x6d, 0xf2, + 0x50, 0xff, 0x53, 0x19, 0x60, 0x36, 0x63, 0x13, 0x3a, 0x5b, 0x6a, 0x4e, 0x67, 0xfb, 0x56, 0x71, + 0x29, 0x1f, 0x40, 0x05, 0xbb, 0x4a, 0x9f, 0x71, 0xa4, 0x97, 0x72, 0x94, 0x91, 0xaa, 0x3f, 0xbb, + 0xff, 0xb7, 0x18, 0x09, 0x90, 0x59, 0x1a, 0x09, 0xf0, 0x3e, 0xe4, 0xf9, 0x69, 0x54, 0x20, 0xee, + 0x8f, 0x5e, 0x9e, 0x5f, 0x7d, 0x0f, 0x44, 0x7c, 0x7b, 0x44, 0xc7, 0x9a, 0x50, 0x41, 0xf9, 0xe8, + 0xdb, 0xe1, 0xd1, 0x58, 0xbe, 0x4d, 0x7a, 0x63, 0x91, 0x33, 0x22, 0xe3, 0x0f, 0xf6, 0x19, 0x72, + 0x52, 0x52, 0xf1, 0xc2, 0xb1, 0x70, 0x91, 0x92, 0x8a, 0x97, 0x97, 0x55, 0xbc, 0xfe, 0x98, 0x3b, + 0x46, 0x51, 0xc5, 0x7b, 0x17, 0x2e, 0x88, 0x3b, 0x37, 0xc8, 0x80, 0xdd, 0x49, 0xf4, 0x3c, 0x04, + 0x51, 0xbc, 0x66, 0xd3, 0x1f, 0x93, 0x01, 0x84, 0xe4, 0x9f, 0xc3, 0xe6, 0xf0, 0xc8, 0x70, 0x0f, + 0x2d, 0x3d, 0x1c, 0x38, 0x3a, 0x3d, 0x17, 0xae, 0x8f, 0x8d, 0x89, 0xd0, 0x3c, 0xdf, 0x5a, 0xa8, + 0x6c, 0x9d, 0x88, 0xfb, 0x03, 0x87, 0x62, 0xa8, 0xe2, 0x78, 0x91, 0x8d, 0xe1, 0x3c, 0x7c, 0xee, + 0xd8, 0x16, 0x16, 0x8e, 0x6d, 0xe7, 0x75, 0xd1, 0xd2, 0x12, 0x5d, 0x74, 0xa6, 0x51, 0x96, 0x65, + 0x8d, 0x92, 0xbd, 0x03, 0x79, 0x71, 0x91, 0x51, 0x38, 0x47, 0xd9, 0xe2, 0xea, 0xd0, 0x22, 0x12, + 0x2c, 0x29, 0x0a, 0x22, 0xa0, 0xbb, 0xcc, 0x15, 0x5e, 0x92, 0x0c, 0x63, 0xdb, 0xc2, 0x33, 0x18, + 0xc7, 0x7b, 0x09, 0x47, 0xe8, 0x55, 0x29, 0xe3, 0x18, 0x27, 0x8c, 0xd7, 0x39, 0x8e, 0xab, 0xff, + 0x2d, 0x0b, 0x39, 0x11, 0x5a, 0x7c, 0x1f, 0x32, 0xa6, 0xef, 0x4d, 0xe2, 0x58, 0xdd, 0x25, 0xaa, + 0x2d, 0xfd, 0x42, 0x14, 0x6a, 0xc1, 0x0f, 0x20, 0x67, 0x98, 0xa6, 0x3e, 0x3a, 0x4e, 0x1e, 0xda, + 0xce, 0x69, 0x99, 0xbb, 0x2b, 0x5a, 0xd6, 0x20, 0x75, 0xf3, 0x63, 0x28, 0x22, 0xfd, 0x2c, 0x82, + 0xb2, 0xb4, 0xa8, 0x3b, 0x47, 0xfa, 0xe0, 0xee, 0x8a, 0x56, 0x30, 0x22, 0xdd, 0xf0, 0x87, 0x49, + 0xf7, 0x77, 0x66, 0xa1, 0x81, 0x73, 0xca, 0xcc, 0x9c, 0x23, 0xfc, 0x57, 0x81, 0xfb, 0x43, 0xe3, + 0x1d, 0x3b, 0x2b, 0x9f, 0x0f, 0x2e, 0xec, 0xef, 0xbb, 0x2b, 0x1a, 0xdf, 0xb7, 0xa2, 0xfd, 0xfe, + 0xc3, 0xc8, 0x35, 0x1d, 0xff, 0x92, 0xc6, 0x92, 0x9e, 0x41, 0x31, 0x18, 0xfb, 0xa7, 0x49, 0x26, + 0x22, 0x9b, 0x69, 0x46, 0x81, 0x74, 0xf9, 0x05, 0xb6, 0x78, 0x57, 0x27, 0xb6, 0x78, 0x8b, 0x7f, + 0x02, 0x25, 0xee, 0xa9, 0xe4, 0x7c, 0x85, 0x85, 0xae, 0x9d, 0x6d, 0xca, 0x74, 0xf6, 0x35, 0xdb, + 0xa2, 0xeb, 0x51, 0x3b, 0x7d, 0x4b, 0x3e, 0x5e, 0xb8, 0xbe, 0xb4, 0xa3, 0xb4, 0xf8, 0xa4, 0x81, + 0x37, 0x56, 0xe3, 0x3c, 0xac, 0x0d, 0x9b, 0xc2, 0x0f, 0xcf, 0x37, 0xe0, 0x68, 0xcf, 0x84, 0x85, + 0xf1, 0x4a, 0xec, 0xd0, 0xbb, 0x2b, 0x1a, 0x33, 0x16, 0xf7, 0xed, 0x3a, 0x6c, 0x44, 0x55, 0xe2, + 0x57, 0x48, 0x67, 0xd1, 0x42, 0x72, 0x93, 0x66, 0xfb, 0xee, 0xee, 0x8a, 0xb6, 0x6e, 0x24, 0x41, + 0xac, 0x05, 0x17, 0xa2, 0x4c, 0xc8, 0x1f, 0x2d, 0x7a, 0xa6, 0xbc, 0x30, 0x8a, 0xf2, 0x5e, 0xbd, + 0xbb, 0xa2, 0x6d, 0x18, 0xf3, 0xc0, 0xd9, 0xe9, 0xfc, 0x55, 0x0d, 0x2e, 0x2d, 0x17, 0x09, 0xf2, + 0xbe, 0x90, 0xe1, 0xfb, 0x82, 0x9a, 0x7c, 0x99, 0x29, 0xf9, 0x98, 0x80, 0xb4, 0x4b, 0x7c, 0x0a, + 0x6b, 0x09, 0x99, 0xc8, 0x4a, 0x90, 0x8f, 0xde, 0x70, 0xa6, 0xf8, 0xff, 0x7a, 0x77, 0xff, 0x0b, + 0x25, 0x85, 0xe0, 0x56, 0xa7, 0xd7, 0xaf, 0x75, 0x44, 0xec, 0x45, 0xab, 0x23, 0x62, 0x2f, 0xd4, + 0xbf, 0x96, 0x86, 0x62, 0x7c, 0x76, 0xf4, 0xdd, 0x7d, 0x3c, 0xb1, 0xf3, 0x24, 0x2d, 0x3b, 0x4f, + 0xe6, 0x0c, 0x18, 0xfe, 0xdc, 0x3a, 0x7f, 0xb1, 0x6b, 0x3d, 0x69, 0x26, 0x04, 0x8b, 0x77, 0x90, + 0xb3, 0xdf, 0xf0, 0x0e, 0xb2, 0x1c, 0xf5, 0x9c, 0x4b, 0x46, 0x3d, 0xcf, 0xbd, 0xe3, 0x9d, 0xa7, + 0x17, 0x76, 0xe5, 0x77, 0xbc, 0xe9, 0xc7, 0xf6, 0x9e, 0xdb, 0xd6, 0x89, 0x08, 0x13, 0x16, 0xa9, + 0xe4, 0x96, 0x0a, 0xaf, 0xd9, 0x52, 0xbf, 0x89, 0x78, 0x7e, 0x04, 0x9b, 0xa3, 0xe3, 0xf8, 0x5d, + 0xdf, 0x99, 0xcb, 0xa0, 0x4c, 0x55, 0x5a, 0x8a, 0x53, 0xff, 0x4a, 0x0a, 0x60, 0x76, 0x58, 0xf2, + 0x0b, 0xfb, 0x1d, 0x25, 0xd7, 0x4e, 0xfa, 0x15, 0xae, 0x9d, 0xd7, 0xbd, 0xce, 0xf4, 0x15, 0x14, + 0xe3, 0xe3, 0xb1, 0xef, 0x3e, 0x5f, 0xbe, 0x55, 0x91, 0xbf, 0x11, 0xf9, 0x60, 0xe3, 0xf3, 0xa5, + 0x5f, 0xb4, 0x2f, 0x12, 0xc5, 0xa7, 0x5f, 0x53, 0xfc, 0x29, 0x77, 0x84, 0xc6, 0x85, 0xff, 0x92, + 0x17, 0x89, 0x3c, 0x7f, 0x33, 0x89, 0xf9, 0xab, 0x4e, 0x85, 0x37, 0xf7, 0x17, 0x2f, 0xfa, 0x5b, + 0x35, 0xf8, 0xbf, 0xa4, 0x22, 0x97, 0x63, 0xfc, 0xc2, 0xf2, 0xb9, 0xca, 0xe7, 0x72, 0xaf, 0xe9, + 0xb7, 0x29, 0xee, 0x95, 0x0e, 0x95, 0xcc, 0xab, 0x1c, 0x2a, 0x6f, 0x41, 0x96, 0x6f, 0x3b, 0xd9, + 0xf3, 0x9c, 0x29, 0x1c, 0xff, 0xda, 0xdf, 0x41, 0x50, 0x55, 0xa1, 0x6c, 0xf3, 0xf6, 0x6e, 0x46, + 0xf9, 0x46, 0xbf, 0xe1, 0x40, 0x97, 0x2d, 0xfe, 0x1f, 0x2e, 0x28, 0xbf, 0x6b, 0x97, 0xbc, 0xda, + 0x55, 0xa0, 0xfe, 0xaf, 0x14, 0xac, 0x25, 0x8e, 0xbb, 0xbf, 0x43, 0x11, 0x4b, 0xc5, 0x6d, 0xfa, + 0xff, 0x20, 0x71, 0x9b, 0x88, 0x20, 0x2d, 0x24, 0x23, 0x48, 0x51, 0xdc, 0x95, 0x13, 0xa6, 0xc4, + 0x32, 0xa3, 0x23, 0xb5, 0xd4, 0xe8, 0xb8, 0x11, 0xff, 0x7a, 0x5b, 0xab, 0xc1, 0x03, 0x36, 0xd7, + 0x34, 0x09, 0xc2, 0x3e, 0x81, 0x2b, 0xc2, 0x98, 0xe7, 0xfd, 0xe3, 0x8d, 0xf4, 0xf8, 0xb7, 0xdd, + 0x84, 0x71, 0x7c, 0x89, 0x13, 0xf0, 0x5f, 0xb1, 0x18, 0xd5, 0x22, 0xac, 0xda, 0x82, 0xb5, 0x44, + 0x1c, 0x81, 0xf4, 0x5b, 0x92, 0x29, 0xf9, 0xb7, 0x24, 0xd9, 0x16, 0x64, 0x4f, 0x8e, 0x2c, 0xdf, + 0x5a, 0xf2, 0x02, 0x2b, 0x47, 0xa8, 0x3f, 0x80, 0xb2, 0x1c, 0xd3, 0xc4, 0xde, 0x81, 0xac, 0x1d, + 0x5a, 0xe3, 0xc8, 0x4d, 0x71, 0x69, 0x31, 0xec, 0xa9, 0x15, 0x5a, 0x63, 0x8d, 0x13, 0xa9, 0x3f, + 0x4b, 0x81, 0x32, 0x8f, 0x93, 0x7e, 0xf0, 0x32, 0x75, 0xce, 0x0f, 0x5e, 0xae, 0x26, 0x2a, 0xb9, + 0xec, 0x37, 0x2b, 0xe3, 0x57, 0x20, 0x33, 0xe7, 0xbc, 0x02, 0xc9, 0xee, 0x42, 0xc1, 0xb7, 0xe8, + 0xd7, 0x04, 0xcd, 0x25, 0x97, 0x10, 0x62, 0x9c, 0xfa, 0x3b, 0x29, 0xc8, 0x8b, 0x00, 0xac, 0xa5, + 0x7e, 0xa3, 0xef, 0x41, 0x9e, 0xff, 0xb2, 0x60, 0xf4, 0x48, 0xd2, 0x42, 0x94, 0x73, 0x84, 0x67, + 0x37, 0x78, 0x58, 0x5a, 0xd2, 0x8f, 0xb4, 0xef, 0x18, 0xae, 0x46, 0x70, 0xf1, 0xe3, 0x34, 0xc6, + 0x58, 0xdc, 0x6f, 0xe6, 0x4f, 0x19, 0x01, 0x81, 0xe8, 0x2a, 0xb3, 0xfa, 0x43, 0xc8, 0x8b, 0x00, + 0xaf, 0xa5, 0x55, 0x79, 0xdd, 0xaf, 0xca, 0x6d, 0x01, 0xcc, 0x22, 0xbe, 0x96, 0xe5, 0xa0, 0xde, + 0x87, 0x42, 0x14, 0xe4, 0x85, 0xf3, 0x6f, 0x56, 0xb4, 0xb8, 0xdd, 0x22, 0x57, 0xc6, 0x11, 0xaf, + 0x9a, 0xb7, 0xbd, 0xe1, 0x31, 0x79, 0x76, 0x1f, 0x02, 0x5d, 0xf5, 0xe9, 0x2f, 0xbc, 0xf9, 0x94, + 0x7c, 0x92, 0x3e, 0x26, 0x62, 0xf7, 0x21, 0x96, 0x97, 0xaf, 0x33, 0xf1, 0xd5, 0x5a, 0x74, 0x29, + 0x8c, 0x66, 0xd9, 0x63, 0xe1, 0xc1, 0x6c, 0xd3, 0x13, 0x70, 0x29, 0xf9, 0x87, 0x09, 0x12, 0x75, + 0xd2, 0x24, 0x32, 0xb5, 0x02, 0x65, 0x39, 0x32, 0x45, 0xad, 0xc1, 0xc6, 0x9e, 0x15, 0x1a, 0x28, + 0x7f, 0xa2, 0xc7, 0x73, 0xf8, 0xfc, 0xc5, 0x8f, 0xe4, 0xfc, 0x9d, 0xa7, 0xd3, 0x38, 0x91, 0xfa, + 0xb3, 0x0c, 0x28, 0xf3, 0xb8, 0x57, 0x5d, 0x90, 0xbb, 0x09, 0x25, 0x8f, 0xe6, 0x45, 0xe2, 0xe7, + 0x87, 0x38, 0x48, 0x0a, 0x47, 0x4f, 0xfc, 0x06, 0x45, 0xc1, 0x0e, 0x76, 0xf9, 0xaf, 0x50, 0x5c, + 0xe6, 0xb7, 0xa1, 0x1c, 0x6f, 0x48, 0xd3, 0xba, 0x4c, 0x97, 0x9f, 0xda, 0xde, 0x90, 0xee, 0xdd, + 0x09, 0x2f, 0x01, 0x0f, 0x97, 0x2c, 0x6b, 0x05, 0xe1, 0x1a, 0xa0, 0xc3, 0x26, 0x11, 0xa4, 0x1e, + 0x06, 0xe2, 0x26, 0x63, 0x81, 0x03, 0xfa, 0x41, 0xf4, 0x76, 0xf6, 0x50, 0xfc, 0x56, 0x4e, 0x9a, + 0xde, 0xce, 0xae, 0xbb, 0x74, 0xed, 0x8e, 0x7e, 0xda, 0x69, 0x28, 0x7e, 0x7a, 0x4b, 0xbc, 0x5e, + 0x8e, 0xa8, 0xdb, 0xfc, 0xd7, 0x84, 0x7c, 0x2b, 0x08, 0xf8, 0x33, 0x68, 0x45, 0xf1, 0x04, 0x9c, + 0x00, 0xc6, 0x0f, 0x2d, 0x8a, 0xdf, 0x72, 0x42, 0x12, 0x10, 0xcf, 0x95, 0xf1, 0x5f, 0x72, 0x42, + 0x82, 0x2b, 0x50, 0xf8, 0xda, 0x73, 0x2d, 0xf2, 0x36, 0x94, 0xa8, 0x56, 0x79, 0x4c, 0xef, 0x19, + 0x13, 0xf5, 0x9f, 0xa5, 0x60, 0x73, 0xbe, 0x57, 0x69, 0xc2, 0x94, 0xa1, 0x50, 0xef, 0xb6, 0xf5, + 0x4e, 0x6d, 0xaf, 0xa9, 0xac, 0xb0, 0x75, 0x28, 0x75, 0xb7, 0x3f, 0x6b, 0xd6, 0xfb, 0x1c, 0x90, + 0xa2, 0xeb, 0xe7, 0x3d, 0x7d, 0xb7, 0xd5, 0x68, 0x34, 0x3b, 0xdc, 0x24, 0xe8, 0x6e, 0x7f, 0xa6, + 0xb7, 0xbb, 0x75, 0xfe, 0xd3, 0x2f, 0xd1, 0x41, 0x7c, 0x4f, 0xc9, 0xd0, 0x31, 0x3d, 0x45, 0x67, + 0x63, 0x32, 0xcb, 0x83, 0x8f, 0x5f, 0xf4, 0xf4, 0x7a, 0xa7, 0xaf, 0xe4, 0x30, 0xd5, 0x39, 0x68, + 0xb7, 0x29, 0x45, 0x51, 0x86, 0xf5, 0xee, 0xde, 0xbe, 0xd6, 0xec, 0xf5, 0xf4, 0x5e, 0xeb, 0x27, + 0x4d, 0xa5, 0x40, 0x25, 0x6b, 0xad, 0xa7, 0xad, 0x0e, 0x07, 0x14, 0x59, 0x1e, 0xd2, 0x7b, 0xad, + 0x0e, 0xbf, 0x76, 0xbf, 0x57, 0xfb, 0x5c, 0x29, 0xe1, 0x47, 0xef, 0x60, 0x4f, 0x29, 0xab, 0xff, + 0x3e, 0x1d, 0x29, 0xbc, 0x14, 0x73, 0xf3, 0x4d, 0x94, 0xbc, 0x65, 0x67, 0x5d, 0x9b, 0x90, 0x75, + 0xe8, 0x22, 0xb1, 0xf8, 0x55, 0x5b, 0x4a, 0x7c, 0x93, 0x5f, 0xea, 0xbc, 0x0d, 0x6b, 0xf1, 0x41, + 0xb5, 0xf4, 0x9c, 0x75, 0x39, 0x02, 0x2e, 0x39, 0x11, 0xc8, 0x2d, 0x39, 0x11, 0x98, 0xd8, 0x21, + 0x1a, 0xb3, 0x28, 0x52, 0xf9, 0x44, 0x29, 0x22, 0x84, 0xff, 0x46, 0xee, 0x35, 0xa0, 0x84, 0x3e, + 0x75, 0xed, 0xe8, 0x77, 0xda, 0x0a, 0x08, 0x38, 0x70, 0xed, 0x70, 0xfe, 0xa0, 0xbc, 0xb8, 0x70, + 0x50, 0x2e, 0xef, 0xbd, 0x90, 0xdc, 0x7b, 0x93, 0x3f, 0x60, 0xca, 0x7f, 0xa0, 0x4d, 0xfa, 0x01, + 0xd3, 0x77, 0x80, 0x0d, 0xa7, 0x3e, 0xbd, 0xcb, 0x25, 0x91, 0x95, 0x89, 0x4c, 0x11, 0x98, 0x78, + 0xd3, 0x63, 0x6f, 0xc1, 0xfa, 0x1c, 0x35, 0x39, 0x8f, 0x8a, 0x5a, 0x25, 0x49, 0xca, 0x1e, 0xc0, + 0x05, 0x31, 0x75, 0x13, 0x7d, 0x2b, 0x2e, 0x29, 0x72, 0x54, 0x6d, 0xd6, 0xc3, 0xea, 0xaf, 0x40, + 0x21, 0x0a, 0xaf, 0x7a, 0xb5, 0x2e, 0xbb, 0x64, 0x5c, 0xd5, 0x7f, 0xb0, 0x0a, 0xc5, 0x38, 0xd8, + 0xea, 0x1b, 0xcd, 0x0e, 0x7a, 0xb7, 0x3f, 0x38, 0x96, 0x25, 0x48, 0x01, 0x01, 0xd1, 0x48, 0x89, + 0xbb, 0x40, 0x53, 0xdf, 0x8e, 0x14, 0x32, 0x0e, 0x39, 0xf0, 0x6d, 0x7a, 0xe6, 0xc2, 0x76, 0xa5, + 0xeb, 0x84, 0x45, 0xad, 0x80, 0x00, 0x5a, 0x5d, 0x57, 0x80, 0xbe, 0x89, 0x33, 0xfa, 0x4d, 0x57, + 0xdb, 0x3d, 0x46, 0xbe, 0x73, 0x7e, 0xd3, 0x95, 0x7e, 0x75, 0x80, 0x47, 0x7a, 0xf0, 0xf3, 0xed, + 0xe8, 0x37, 0xb2, 0xae, 0x41, 0x71, 0x1a, 0xff, 0xc8, 0x9a, 0x98, 0x11, 0xd3, 0xe8, 0x27, 0xd6, + 0x92, 0xa3, 0x5a, 0x9c, 0x1f, 0xd5, 0xf9, 0x39, 0x0d, 0x0b, 0x73, 0x5a, 0x0d, 0x21, 0x2f, 0x02, + 0xce, 0x5e, 0xdd, 0xe1, 0xaf, 0xec, 0x2a, 0x05, 0xd2, 0x86, 0x13, 0xdd, 0x61, 0xc4, 0xcf, 0xb9, + 0x8a, 0x65, 0xe6, 0x2a, 0xa6, 0xfe, 0xcd, 0x55, 0x80, 0x59, 0xe0, 0x1a, 0x7b, 0x77, 0x2e, 0x48, + 0x36, 0xb5, 0xb0, 0xab, 0xcf, 0xc5, 0xc6, 0xce, 0xbd, 0xfb, 0xb2, 0xfa, 0x0d, 0xde, 0x7d, 0x79, + 0x04, 0x6b, 0x81, 0x3f, 0x7c, 0xad, 0x5f, 0xbb, 0x14, 0xf8, 0xc3, 0xd8, 0xad, 0xfd, 0x10, 0x30, + 0x49, 0x2f, 0xd5, 0xcd, 0xec, 0xd0, 0x05, 0xa5, 0xa4, 0x18, 0xf8, 0xc3, 0xee, 0xe0, 0xcb, 0x06, + 0xbf, 0x80, 0x65, 0x06, 0xa1, 0xbe, 0x4c, 0x4a, 0xac, 0x9b, 0x41, 0xd8, 0x90, 0x05, 0xc5, 0x1d, + 0xa8, 0x20, 0xed, 0x82, 0xb0, 0x28, 0x9b, 0xc1, 0xec, 0x1c, 0x43, 0xfd, 0xed, 0xe8, 0x78, 0x74, + 0xce, 0x65, 0xca, 0x3e, 0x12, 0x76, 0xb6, 0xa4, 0x23, 0x54, 0x97, 0x79, 0x58, 0xf9, 0x2b, 0x35, + 0x31, 0xe9, 0xe2, 0x4f, 0x6b, 0xad, 0x7e, 0xc3, 0x9f, 0xd6, 0xba, 0x7f, 0x0b, 0xca, 0xf2, 0xcf, + 0x57, 0xd2, 0x75, 0x0f, 0xcf, 0xb5, 0xf8, 0x0f, 0x1c, 0xb4, 0xbf, 0xfe, 0x40, 0x49, 0xdd, 0x57, + 0xa1, 0x24, 0xfd, 0xbc, 0x08, 0x52, 0xec, 0x1a, 0xc1, 0x91, 0x78, 0xec, 0xde, 0x70, 0x0f, 0x2d, + 0x25, 0x75, 0xff, 0x2e, 0x6a, 0xcc, 0xf2, 0x8f, 0x7b, 0x00, 0xe4, 0x3a, 0x9e, 0x3f, 0x36, 0x1c, + 0x41, 0x67, 0x4d, 0x03, 0xa4, 0x7b, 0x08, 0x17, 0x97, 0xfe, 0x54, 0x09, 0xdd, 0x19, 0xb2, 0xc7, + 0x13, 0xc7, 0xe2, 0xd7, 0x5e, 0x76, 0xcf, 0x06, 0xbe, 0x6d, 0x2a, 0xa9, 0xfb, 0x4f, 0xa2, 0xbb, + 0xf5, 0x51, 0xd9, 0xed, 0x6e, 0xad, 0xc1, 0x37, 0xb7, 0xf8, 0x8d, 0x97, 0xfe, 0x36, 0x7f, 0xc8, + 0x5e, 0x6b, 0xf6, 0x0e, 0xda, 0x7d, 0xf1, 0x9e, 0xcc, 0xfd, 0x4f, 0xa1, 0x7a, 0xde, 0xfd, 0x0f, + 0xac, 0x51, 0x7d, 0xb7, 0x46, 0x77, 0x6c, 0x70, 0x33, 0xeb, 0xea, 0x3c, 0x95, 0xe2, 0x57, 0x94, + 0xda, 0x4d, 0x0a, 0x92, 0xbc, 0xff, 0xd3, 0x94, 0xa4, 0xc2, 0x45, 0x31, 0xfc, 0x31, 0x40, 0x74, + 0x93, 0x0c, 0xd2, 0x2c, 0xc3, 0x54, 0x52, 0xec, 0x12, 0xb0, 0x04, 0xa8, 0xed, 0x0d, 0x0d, 0x47, + 0x59, 0xa5, 0x70, 0xc8, 0x08, 0x4e, 0xb7, 0xb7, 0x94, 0x34, 0x7b, 0x03, 0xae, 0xc4, 0xb0, 0xb6, + 0x77, 0xb2, 0xef, 0xdb, 0x9e, 0x6f, 0x87, 0x67, 0x1c, 0x9d, 0xb9, 0xff, 0xff, 0x8a, 0x73, 0xca, + 0xc4, 0xc8, 0x63, 0x01, 0x35, 0xd3, 0x9c, 0xc1, 0x48, 0xd8, 0x28, 0x2b, 0xec, 0x32, 0x5c, 0x20, + 0x49, 0x3b, 0x87, 0x48, 0xb1, 0x6b, 0x70, 0x39, 0xb2, 0x33, 0xe7, 0x91, 0xab, 0x88, 0xd4, 0x2c, + 0x0a, 0xa5, 0x5b, 0x40, 0xa6, 0xb7, 0x7f, 0xf4, 0x27, 0x3f, 0xbf, 0x91, 0xfa, 0x17, 0x3f, 0xbf, + 0x91, 0xfa, 0x0f, 0x3f, 0xbf, 0xb1, 0xf2, 0xb3, 0xff, 0x78, 0x23, 0xf5, 0x93, 0x77, 0x0f, 0xed, + 0xf0, 0x68, 0x3a, 0x78, 0x30, 0xf4, 0xc6, 0x0f, 0xc7, 0x46, 0xe8, 0xdb, 0xa7, 0x5c, 0xe4, 0x47, + 0x09, 0xd7, 0x7a, 0x38, 0x39, 0x3e, 0x7c, 0x38, 0x19, 0x3c, 0xc4, 0xc9, 0x37, 0xc8, 0x4d, 0x7c, + 0x2f, 0xf4, 0x1e, 0xff, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xcf, 0x37, 0xa1, 0x48, 0x84, + 0x00, 0x00, } func (m *Type) Marshal() (dAtA []byte, err error) { @@ -20702,6 +20719,11 @@ func (m *Query) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.MaxDop != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.MaxDop)) + i-- + dAtA[i] = 0x50 + } if len(m.BackgroundQueries) > 0 { for iNdEx := len(m.BackgroundQueries) - 1; iNdEx >= 0; iNdEx-- { { @@ -28432,6 +28454,9 @@ func (m *Query) ProtoSize() (n int) { n += 1 + l + sovPlan(uint64(l)) } } + if m.MaxDop != 0 { + n += 1 + sovPlan(uint64(m.MaxDop)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -48015,6 +48040,25 @@ func (m *Query) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxDop", wireType) + } + m.MaxDop = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxDop |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipPlan(dAtA[iNdEx:]) diff --git a/pkg/pb/task/task.pb.go b/pkg/pb/task/task.pb.go index cdad092dbf432..ce35f403e1529 100644 --- a/pkg/pb/task/task.pb.go +++ b/pkg/pb/task/task.pb.go @@ -838,11 +838,11 @@ func (m *Account) GetName() string { } type CreateCdcDetails struct { - //cdc task uuid + // cdc task uuid TaskId string `protobuf:"bytes,1,opt,name=TaskId,proto3" json:"TaskId,omitempty"` - //cdc task name in CreateCdc + // cdc task name in CreateCdc TaskName string `protobuf:"bytes,2,opt,name=TaskName,proto3" json:"TaskName,omitempty"` - //cdc source account + // cdc source account Accounts []*Account `protobuf:"bytes,3,rep,name=Accounts,proto3" json:"Accounts,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1006,6 +1006,7 @@ type Details struct { Username string `protobuf:"bytes,4,opt,name=Username,proto3" json:"Username,omitempty"` Error string `protobuf:"bytes,5,opt,name=Error,proto3" json:"Error,omitempty"` // Types that are valid to be assigned to Details: + // // *Details_Connector // *Details_CreateCdc // *Details_ISCP diff --git a/pkg/sql/colexec/aggexec/aggContext.go b/pkg/sql/colexec/aggexec/aggContext.go index fd8996f6aab9e..09e2145d20f0d 100644 --- a/pkg/sql/colexec/aggexec/aggContext.go +++ b/pkg/sql/colexec/aggexec/aggContext.go @@ -107,6 +107,36 @@ func (a *AggContext) getGroupContextEncodings() [][]byte { return encodings } +func (a *AggContext) getGroupContextEncodingsForFlags(cnt int64, flags [][]uint8) [][]byte { + if !a.hasGroupContext { + return nil + } + encodings := make([][]byte, cnt) + nextX := 0 + nextY := 0 + for i := range flags { + for j := range flags[i] { + if flags[i][j] == 1 { + encodings[nextX] = a.groupContext[nextY].Marshal() + nextX++ + } + nextY++ + } + } + return encodings +} + +func (a *AggContext) getGroupContextEncodingsForChunk(start int, ngroup int) [][]byte { + if !a.hasGroupContext { + return nil + } + encodings := make([][]byte, ngroup) + for i := 0; i < ngroup; i++ { + encodings[i] = a.groupContext[start+i].Marshal() + } + return encodings +} + func (a *AggContext) decodeGroupContexts(encodings [][]byte, resultType types.Type, parameters ...types.Type) { if !a.hasGroupContext { return diff --git a/pkg/sql/colexec/aggexec/aggFrame_test.go b/pkg/sql/colexec/aggexec/aggFrame_test.go index 1519eb5289cd5..2d4ae3448c68f 100644 --- a/pkg/sql/colexec/aggexec/aggFrame_test.go +++ b/pkg/sql/colexec/aggexec/aggFrame_test.go @@ -75,9 +75,10 @@ type avgDemoCtx struct { count int64 } -func (d *avgDemoCtx) Marshal() []byte { return types.EncodeInt64(&d.count) } -func (d *avgDemoCtx) Unmarshal(b []byte) { d.count = types.DecodeInt64(b) } -func (d *avgDemoCtx) Size() int64 { return 8 } // size of count +func (d *avgDemoCtx) Marshal() []byte { return types.EncodeInt64(&d.count) } +func (d *avgDemoCtx) MarshalBinary() ([]byte, error) { return d.Marshal(), nil } +func (d *avgDemoCtx) Unmarshal(b []byte) { d.count = types.DecodeInt64(b) } +func (d *avgDemoCtx) Size() int64 { return 8 } // size of count var _ AggGroupExecContext = &avgDemoCtx{} func fromIdxListToNullList(start, end int, idxList []int) []bool { diff --git a/pkg/sql/colexec/aggexec/aggMethod.go b/pkg/sql/colexec/aggexec/aggMethod.go index b2d1f95b0832d..02d83a90b6860 100644 --- a/pkg/sql/colexec/aggexec/aggMethod.go +++ b/pkg/sql/colexec/aggexec/aggMethod.go @@ -127,6 +127,7 @@ type ( type AggCanMarshal interface { Marshal() []byte + MarshalBinary() ([]byte, error) Unmarshal([]byte) Size() int64 } diff --git a/pkg/sql/colexec/aggexec/approx_count.go b/pkg/sql/colexec/aggexec/approx_count.go index fac4af9343223..5dedf3c3f249e 100644 --- a/pkg/sql/colexec/aggexec/approx_count.go +++ b/pkg/sql/colexec/aggexec/approx_count.go @@ -15,7 +15,11 @@ package aggexec import ( + "bytes" + io "io" + hll "github.com/axiomhq/hyperloglog" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -37,10 +41,13 @@ func (exec *approxCountFixedExec[T]) GetOptResult() SplitResult { func (exec *approxCountFixedExec[T]) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("distinct should have been nil") + } encoded := EncodedAgg{ Info: d, @@ -60,8 +67,31 @@ func (exec *approxCountFixedExec[T]) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *approxCountFixedExec[T]) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer( + cnt, flags, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *approxCountFixedExec[T]) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + return marshalChunkToBuffer( + chunk, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *approxCountFixedExec[T]) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + groups, _, err := unmarshalFromReader[*hll.Sketch](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + exec.groups = groups + return nil +} + func (exec *approxCountFixedExec[T]) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { - err := exec.ret.unmarshalFromBytes(result, empties) + // distinct is nil + err := exec.ret.unmarshalFromBytes(result, empties, nil) if err != nil { return err } @@ -92,10 +122,13 @@ func (exec *approxCountVarExec) GetOptResult() SplitResult { func (exec *approxCountVarExec) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := EncodedAgg{ Info: d, @@ -115,8 +148,29 @@ func (exec *approxCountVarExec) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *approxCountVarExec) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer( + cnt, flags, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *approxCountVarExec) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + return marshalChunkToBuffer(chunk, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *approxCountVarExec) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + groups, _, err := unmarshalFromReader[*hll.Sketch](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + exec.groups = groups + return nil +} + func (exec *approxCountVarExec) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { - err := exec.ret.unmarshalFromBytes(result, empties) + err := exec.ret.unmarshalFromBytes(result, empties, nil) if err != nil { return err } @@ -135,7 +189,7 @@ func (exec *approxCountVarExec) unmarshal(_ *mpool.MPool, result, empties, group func newApproxCountFixedExec[T types.FixedSizeTExceptStrType](mg AggMemoryManager, info singleAggInfo) AggFuncExec { return &approxCountFixedExec[T]{ singleAggInfo: info, - ret: initAggResultWithFixedTypeResult[uint64](mg, info.retType, false, 0), + ret: initAggResultWithFixedTypeResult[uint64](mg, info.retType, false, 0, false), } } @@ -151,7 +205,7 @@ func makeApproxCount(mg AggMemoryManager, id int64, arg types.Type) AggFuncExec if info.argType.IsVarlen() { return &approxCountVarExec{ singleAggInfo: info, - ret: initAggResultWithFixedTypeResult[uint64](mg, info.retType, false, 0), + ret: initAggResultWithFixedTypeResult[uint64](mg, info.retType, false, 0, false), } } diff --git a/pkg/sql/colexec/aggexec/concat.go b/pkg/sql/colexec/aggexec/concat.go index 2fd5c865a40ec..ac81c1f7bcebd 100644 --- a/pkg/sql/colexec/aggexec/concat.go +++ b/pkg/sql/colexec/aggexec/concat.go @@ -15,7 +15,9 @@ package aggexec import ( + "bytes" "fmt" + io "io" "math" "github.com/matrixorigin/matrixone/pkg/common/moerr" @@ -28,7 +30,6 @@ import ( type groupConcatExec struct { multiAggInfo ret aggResultWithBytesType - distinctHash separator []byte } @@ -39,7 +40,7 @@ func (exec *groupConcatExec) GetOptResult() SplitResult { func (exec *groupConcatExec) marshal() ([]byte, error) { d := exec.multiAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } @@ -47,14 +48,12 @@ func (exec *groupConcatExec) marshal() ([]byte, error) { Info: d, Result: r, Empties: em, - Groups: [][]byte{exec.separator}, + // Oh, this is so f**ked. + Groups: [][]byte{exec.separator}, } - if exec.IsDistinct() { - data, err := exec.distinctHash.marshal() - if err != nil { - return nil, err - } - encoded.Groups = append(encoded.Groups, data) + + if dist != nil { + encoded.Groups = append(encoded.Groups, dist...) } return encoded.Marshal() } @@ -63,14 +62,45 @@ func (exec *groupConcatExec) unmarshal(_ *mpool.MPool, result, empties, groups [ if err := exec.SetExtraInformation(groups[0], 0); err != nil { return err } - if exec.IsDistinct() { - if len(groups) > 1 { - if err := exec.distinctHash.unmarshal(groups[1]); err != nil { - return err - } - } + return exec.ret.unmarshalFromBytes(result, empties, groups[1:]) +} + +func (exec *groupConcatExec) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + err := marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, [][]byte{exec.separator}) + if err != nil { + return err } - return exec.ret.unmarshalFromBytes(result, empties) + + if err = types.WriteSizeBytes(exec.separator, buf); err != nil { + return err + } + return nil +} + +func (exec *groupConcatExec) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + err := marshalChunkToBuffer[dummyBinaryMarshaler](chunk, buf, + &exec.ret.optSplitResult, nil, [][]byte{exec.separator}) + if err != nil { + return err + } + + if err = types.WriteSizeBytes(exec.separator, buf); err != nil { + return err + } + return nil +} + +func (exec *groupConcatExec) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, sep, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + // + // exec.ret.setupT() + exec.separator = sep[0] + return nil } func GroupConcatReturnType(args []types.Type) types.Type { @@ -85,12 +115,9 @@ func GroupConcatReturnType(args []types.Type) types.Type { func newGroupConcatExec(mg AggMemoryManager, info multiAggInfo, separator string) AggFuncExec { exec := &groupConcatExec{ multiAggInfo: info, - ret: initAggResultWithBytesTypeResult(mg, info.retType, info.emptyNull, ""), + ret: initAggResultWithBytesTypeResult(mg, info.retType, info.emptyNull, "", info.distinct), separator: []byte(separator), } - if info.distinct { - exec.distinctHash = newDistinctHash() - } return exec } @@ -102,11 +129,6 @@ func isValidGroupConcatUnit(value []byte) error { } func (exec *groupConcatExec) GroupGrow(more int) error { - if exec.IsDistinct() { - if err := exec.distinctHash.grows(more); err != nil { - return err - } - } return exec.ret.grows(more) } @@ -123,14 +145,13 @@ func (exec *groupConcatExec) Fill(groupIndex int, row int, vectors []*vector.Vec } } - if exec.IsDistinct() { - if need, err := exec.distinctHash.fill(groupIndex, vectors, row); err != nil || !need { - return err - } - } - x, y := exec.ret.updateNextAccessIdx(groupIndex) exec.ret.setGroupNotEmpty(x, y) + + if need, err := exec.ret.distinctFill(x, y, vectors, row); err != nil || !need { + return err + } + r := exec.ret.get() if len(r) > 0 { r = append(r, exec.separator...) @@ -175,7 +196,8 @@ func (exec *groupConcatExec) SetExtraInformation(partialResult any, _ int) error func (exec *groupConcatExec) merge(other *groupConcatExec, idx1, idx2 int) error { x1, y1 := exec.ret.updateNextAccessIdx(idx1) x2, y2 := other.ret.updateNextAccessIdx(idx2) - if err := exec.distinctHash.merge(&other.distinctHash); err != nil { + + if err := exec.ret.distinctMerge(x1, &other.ret.optSplitResult, x2); err != nil { return err } empty1, empty2 := exec.ret.isGroupEmpty(x1, y1), other.ret.isGroupEmpty(x2, y2) @@ -216,12 +238,11 @@ func (exec *groupConcatExec) Flush() ([]*vector.Vector, error) { } func (exec *groupConcatExec) Free() { - exec.distinctHash.free() exec.ret.free() } func (exec *groupConcatExec) Size() int64 { - return exec.ret.Size() + exec.distinctHash.Size() + int64(cap(exec.separator)) + return exec.ret.Size() + int64(cap(exec.separator)) } var GroupConcatUnsupportedTypes = []types.T{ diff --git a/pkg/sql/colexec/aggexec/count.go b/pkg/sql/colexec/aggexec/count.go index 53c0badfb737a..63eec80acee24 100644 --- a/pkg/sql/colexec/aggexec/count.go +++ b/pkg/sql/colexec/aggexec/count.go @@ -15,6 +15,10 @@ package aggexec import ( + "bytes" + io "io" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -41,7 +45,7 @@ func (exec *countColumnExec) GetOptResult() SplitResult { func (exec *countColumnExec) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } @@ -49,38 +53,40 @@ func (exec *countColumnExec) marshal() ([]byte, error) { Info: d, Result: r, Empties: em, - Groups: nil, - } - if exec.IsDistinct() { - data, err := exec.distinctHash.marshal() - if err != nil { - return nil, err - } - if len(data) > 0 { - encoded.Groups = [][]byte{data} - } + Groups: dist, } return encoded.Marshal() } -func (exec *countColumnExec) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { - if exec.IsDistinct() { - if len(groups) > 0 { - if err := exec.distinctHash.unmarshal(groups[0]); err != nil { - return err - } - } +func (exec *countColumnExec) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, nil) +} + +func (exec *countColumnExec) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + return marshalChunkToBuffer[dummyBinaryMarshaler]( + chunk, buf, + &exec.ret.optSplitResult, nil, nil) +} + +func (exec *countColumnExec) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, _, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err } - return exec.ret.unmarshalFromBytes(result, empties) + exec.ret.setupT() + return nil +} + +func (exec *countColumnExec) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { + return exec.ret.unmarshalFromBytes(result, empties, groups) } func newCountColumnExecExec(mg AggMemoryManager, info singleAggInfo) AggFuncExec { exec := &countColumnExec{ singleAggInfo: info, - ret: initAggResultWithFixedTypeResult[int64](mg, info.retType, false, 0), - } - if info.distinct { - exec.distinctHash = newDistinctHash() + ret: initAggResultWithFixedTypeResult[int64](mg, info.retType, false, 0, info.distinct), } return exec } @@ -288,10 +294,13 @@ func (exec *countStarExec) GetOptResult() SplitResult { func (exec *countStarExec) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should has been nil") + } encoded := EncodedAgg{ Info: d, Result: r, @@ -301,14 +310,33 @@ func (exec *countStarExec) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *countStarExec) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, nil) +} +func (exec *countStarExec) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + return marshalChunkToBuffer[dummyBinaryMarshaler]( + chunk, buf, + &exec.ret.optSplitResult, nil, nil) +} +func (exec *countStarExec) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, _, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + return nil +} + func (exec *countStarExec) unmarshal(_ *mpool.MPool, result, empties, _ [][]byte) error { - return exec.ret.unmarshalFromBytes(result, empties) + return exec.ret.unmarshalFromBytes(result, empties, nil) } func newCountStarExec(mg AggMemoryManager, info singleAggInfo) AggFuncExec { return &countStarExec{ singleAggInfo: info, - ret: initAggResultWithFixedTypeResult[int64](mg, info.retType, false, 0), + ret: initAggResultWithFixedTypeResult[int64](mg, info.retType, false, 0, false), } } diff --git a/pkg/sql/colexec/aggexec/distinct.go b/pkg/sql/colexec/aggexec/distinct.go index 0f7815906ed94..8bde00c4e5edf 100644 --- a/pkg/sql/colexec/aggexec/distinct.go +++ b/pkg/sql/colexec/aggexec/distinct.go @@ -157,6 +157,7 @@ func (d *distinctHash) free() { m.Free() } } + } func (d *distinctHash) Size() int64 { @@ -202,12 +203,38 @@ func (d *distinctHash) marshal() ([]byte, error) { return buf.Bytes(), nil } +func (d *distinctHash) marshalToBuffers(flags []uint8, buf *bytes.Buffer) error { + var cnt int64 + if flags == nil { + cnt = int64(len(d.maps)) + } else { + for _, f := range flags { + if f != 0 { + cnt += 1 + } + } + } + + types.WriteInt64(buf, cnt) + for i := range d.maps { + if flags != nil && flags[i] != 0 { + if _, err := d.maps[i].WriteTo(buf); err != nil { + return err + } + } + } + return nil +} + func (d *distinctHash) unmarshal(data []byte) error { if len(data) == 0 { return nil } buf := bytes.NewBuffer(data) + return d.unmarshalFromReader(buf) +} +func (d *distinctHash) unmarshalFromReader(buf io.Reader) error { var n uint64 if _, err := buf.Read(types.EncodeUint64(&n)); err != nil { return err diff --git a/pkg/sql/colexec/aggexec/fromBytesRetBytes.go b/pkg/sql/colexec/aggexec/fromBytesRetBytes.go index 7cf43bf871c82..36f57ccee203d 100644 --- a/pkg/sql/colexec/aggexec/fromBytesRetBytes.go +++ b/pkg/sql/colexec/aggexec/fromBytesRetBytes.go @@ -15,7 +15,11 @@ package aggexec import ( + "bytes" "fmt" + io "io" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/vector" ) @@ -102,10 +106,13 @@ func (exec *aggregatorFromBytesToBytes) GetOptResult() SplitResult { func (exec *aggregatorFromBytesToBytes) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := EncodedAgg{ Info: d, Result: r, @@ -117,7 +124,33 @@ func (exec *aggregatorFromBytesToBytes) marshal() ([]byte, error) { func (exec *aggregatorFromBytesToBytes) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { exec.execContext.decodeGroupContexts(groups, exec.singleAggInfo.retType, exec.singleAggInfo.argType) - return exec.ret.unmarshalFromBytes(result, empties) + // this groups is not distict + return exec.ret.unmarshalFromBytes(result, empties, nil) +} + +func (exec *aggregatorFromBytesToBytes) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForFlags(cnt, flags)) +} + +func (exec *aggregatorFromBytesToBytes) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + start := exec.ret.optSplitResult.optInformation.chunkSize * chunk + chunkNGroup := exec.ret.optSplitResult.getNthChunkSize(chunk) + return marshalChunkToBuffer[dummyBinaryMarshaler]( + chunk, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForChunk(start, chunkNGroup)) +} + +func (exec *aggregatorFromBytesToBytes) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, bs, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + // XXX FIXME + // exec.ret.setupT() + exec.execContext.decodeGroupContexts(bs, exec.singleAggInfo.retType, exec.singleAggInfo.argType) + return nil } func (exec *aggregatorFromBytesToBytes) init( @@ -133,7 +166,9 @@ func (exec *aggregatorFromBytesToBytes) init( if resultInitMethod := impl.logic.init; resultInitMethod != nil { v = string(resultInitMethod.(InitBytesResultOfAgg)(info.retType, info.argType)) } - exec.ret = initAggResultWithBytesTypeResult(mg, info.retType, info.emptyNull, v) + + // XXX distinct is always false? + exec.ret = initAggResultWithBytesTypeResult(mg, info.retType, info.emptyNull, v, false) exec.singleAggInfo = info exec.singleAggExecExtraInformation = emptyExtraInfo diff --git a/pkg/sql/colexec/aggexec/fromBytesRetFixed.go b/pkg/sql/colexec/aggexec/fromBytesRetFixed.go index 0b3e1c5bdd936..8e99dc43ef4f1 100644 --- a/pkg/sql/colexec/aggexec/fromBytesRetFixed.go +++ b/pkg/sql/colexec/aggexec/fromBytesRetFixed.go @@ -15,8 +15,11 @@ package aggexec import ( + "bytes" "fmt" + io "io" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -200,10 +203,13 @@ func (exec *aggregatorFromBytesToFixed[to]) GetOptResult() SplitResult { func (exec *aggregatorFromBytesToFixed[to]) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := &EncodedAgg{ Info: d, Result: r, @@ -213,9 +219,34 @@ func (exec *aggregatorFromBytesToFixed[to]) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *aggregatorFromBytesToFixed[to]) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForFlags(cnt, flags)) +} + +func (exec *aggregatorFromBytesToFixed[to]) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + start := exec.ret.optSplitResult.optInformation.chunkSize * chunk + chunkNGroup := exec.ret.optSplitResult.getNthChunkSize(chunk) + return marshalChunkToBuffer[dummyBinaryMarshaler]( + chunk, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForChunk(start, chunkNGroup)) +} + +func (exec *aggregatorFromBytesToFixed[to]) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, bs, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + exec.execContext.decodeGroupContexts(bs, exec.singleAggInfo.retType, exec.singleAggInfo.argType) + return nil +} + func (exec *aggregatorFromBytesToFixed[to]) unmarshal(mp *mpool.MPool, result, empties, groups [][]byte) error { exec.execContext.decodeGroupContexts(groups, exec.singleAggInfo.retType, exec.singleAggInfo.argType) - return exec.ret.unmarshalFromBytes(result, empties) + // groups used as above, distinct is nil. + return exec.ret.unmarshalFromBytes(result, empties, nil) } func (exec *aggregatorFromBytesToFixed[to]) init( @@ -231,7 +262,7 @@ func (exec *aggregatorFromBytesToFixed[to]) init( if resultInitMethod := impl.logic.init; resultInitMethod != nil { v = resultInitMethod.(InitFixedResultOfAgg[to])(info.retType, info.argType) } - exec.ret = initAggResultWithFixedTypeResult[to](mg, info.retType, info.emptyNull, v) + exec.ret = initAggResultWithFixedTypeResult[to](mg, info.retType, info.emptyNull, v, false) exec.singleAggInfo = info exec.singleAggExecExtraInformation = emptyExtraInfo diff --git a/pkg/sql/colexec/aggexec/fromFixedRetBytes.go b/pkg/sql/colexec/aggexec/fromFixedRetBytes.go index fda4318cc8b8b..7955bcf601eca 100644 --- a/pkg/sql/colexec/aggexec/fromFixedRetBytes.go +++ b/pkg/sql/colexec/aggexec/fromFixedRetBytes.go @@ -15,8 +15,11 @@ package aggexec import ( + "bytes" "fmt" + io "io" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -219,10 +222,13 @@ func (exec *aggregatorFromFixedToBytes[from]) GetOptResult() SplitResult { func (exec *aggregatorFromFixedToBytes[from]) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := EncodedAgg{ Info: d, Result: r, @@ -232,9 +238,34 @@ func (exec *aggregatorFromFixedToBytes[from]) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *aggregatorFromFixedToBytes[from]) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForFlags(cnt, flags)) +} + +func (exec *aggregatorFromFixedToBytes[from]) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + start := exec.ret.optSplitResult.optInformation.chunkSize * chunk + chunkNGroup := exec.ret.optSplitResult.getNthChunkSize(chunk) + return marshalChunkToBuffer[dummyBinaryMarshaler]( + chunk, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForChunk(start, chunkNGroup)) +} + +func (exec *aggregatorFromFixedToBytes[from]) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, bs, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + // exec.ret.setupT() + exec.execContext.decodeGroupContexts(bs, exec.singleAggInfo.retType, exec.singleAggInfo.argType) + return nil +} + func (exec *aggregatorFromFixedToBytes[from]) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { exec.execContext.decodeGroupContexts(groups, exec.singleAggInfo.retType, exec.singleAggInfo.argType) - return exec.ret.unmarshalFromBytes(result, empties) + // groups used above, dist is nil + return exec.ret.unmarshalFromBytes(result, empties, nil) } func (exec *aggregatorFromFixedToBytes[from]) init( @@ -242,15 +273,15 @@ func (exec *aggregatorFromFixedToBytes[from]) init( info singleAggInfo, impl aggImplementation) { - if info.IsDistinct() { - exec.distinctHash = newDistinctHash() - } - var v string if resultInitMethod := impl.logic.init; resultInitMethod != nil { v = string(resultInitMethod.(InitBytesResultOfAgg)(info.retType, info.argType)) } - exec.ret = initAggResultWithBytesTypeResult(mg, info.retType, info.emptyNull, v) + + // XXX WTF + // this is fucked, now we do put in a distinct in this init. + // from marshal/unmarshal, the groups is used in its own special logic. + exec.ret = initAggResultWithBytesTypeResult(mg, info.retType, info.emptyNull, v, info.IsDistinct()) exec.singleAggInfo = info exec.singleAggExecExtraInformation = emptyExtraInfo @@ -269,12 +300,6 @@ func (exec *aggregatorFromFixedToBytes[from]) GroupGrow(more int) error { if err := exec.ret.grows(more); err != nil { return err } - // deal with distinct hash. - if exec.IsDistinct() { - if err := exec.distinctHash.grows(more); err != nil { - return err - } - } // deal with execContext. exec.execContext.growsGroupContext(more, exec.singleAggInfo.retType, exec.singleAggInfo.argType) return nil diff --git a/pkg/sql/colexec/aggexec/fromFixedRetFixed.go b/pkg/sql/colexec/aggexec/fromFixedRetFixed.go index 2d3520b16039c..6c41b2631570c 100644 --- a/pkg/sql/colexec/aggexec/fromFixedRetFixed.go +++ b/pkg/sql/colexec/aggexec/fromFixedRetFixed.go @@ -15,8 +15,11 @@ package aggexec import ( + "bytes" "fmt" + io "io" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -273,11 +276,13 @@ func (exec *aggregatorFromFixedToFixed[from, to]) GetOptResult() SplitResult { func (exec *aggregatorFromFixedToFixed[from, to]) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } - + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := &EncodedAgg{ Info: d, Result: r, @@ -287,9 +292,33 @@ func (exec *aggregatorFromFixedToFixed[from, to]) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *aggregatorFromFixedToFixed[from, to]) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer[dummyBinaryMarshaler]( + cnt, flags, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForFlags(cnt, flags)) +} + +func (exec *aggregatorFromFixedToFixed[from, to]) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + start := exec.ret.optSplitResult.optInformation.chunkSize * chunk + chunkNGroup := exec.ret.optSplitResult.getNthChunkSize(chunk) + return marshalChunkToBuffer[dummyBinaryMarshaler]( + chunk, buf, + &exec.ret.optSplitResult, nil, exec.execContext.getGroupContextEncodingsForChunk(start, chunkNGroup)) +} + +func (exec *aggregatorFromFixedToFixed[from, to]) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + _, groups, err := unmarshalFromReader[dummyBinaryUnmarshaler](reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + exec.execContext.decodeGroupContexts(groups, exec.singleAggInfo.retType, exec.singleAggInfo.argType) + return nil +} + func (exec *aggregatorFromFixedToFixed[from, to]) unmarshal(_ *mpool.MPool, result, empties, groups [][]byte) error { exec.execContext.decodeGroupContexts(groups, exec.singleAggInfo.retType, exec.singleAggInfo.argType) - return exec.ret.unmarshalFromBytes(result, empties) + return exec.ret.unmarshalFromBytes(result, empties, nil) } func (exec *aggregatorFromFixedToFixed[from, to]) init( @@ -305,7 +334,10 @@ func (exec *aggregatorFromFixedToFixed[from, to]) init( if resultInitMethod := impl.logic.init; resultInitMethod != nil { v = resultInitMethod.(InitFixedResultOfAgg[to])(info.retType, info.argType) } - exec.ret = initAggResultWithFixedTypeResult[to](mg, info.retType, info.emptyNull, v) + + // XXX + // This is fucked. See marshal/unmarshal for special handling of distinct. + exec.ret = initAggResultWithFixedTypeResult[to](mg, info.retType, info.emptyNull, v, info.IsDistinct()) exec.singleAggInfo = info exec.singleAggExecExtraInformation = emptyExtraInfo diff --git a/pkg/sql/colexec/aggexec/median.go b/pkg/sql/colexec/aggexec/median.go index 96f435d8b9179..87fd41190611a 100644 --- a/pkg/sql/colexec/aggexec/median.go +++ b/pkg/sql/colexec/aggexec/median.go @@ -15,6 +15,9 @@ package aggexec import ( + "bytes" + io "io" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -56,10 +59,13 @@ func (exec *medianColumnExecSelf[T, R]) GetOptResult() SplitResult { func (exec *medianColumnExecSelf[T, R]) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := &EncodedAgg{ Info: d, @@ -78,6 +84,45 @@ func (exec *medianColumnExecSelf[T, R]) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *medianColumnExecSelf[T, R]) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer( + cnt, flags, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *medianColumnExecSelf[T, R]) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + return marshalChunkToBuffer( + chunk, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *medianColumnExecSelf[T, R]) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + err := unmarshalFromReaderNoGroup(reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + + ngrp, err := types.ReadInt64(reader) + if err != nil { + return err + } + if ngrp != 0 { + exec.groups = make([]*Vectors[T], ngrp) + for i := range exec.groups { + exec.groups[i] = NewEmptyVectors[T]() + _, bs, err := types.ReadSizeBytes(reader, nil, false) + if err != nil { + return err + } + if err = exec.groups[i].Unmarshal(bs, exec.singleAggInfo.argType, mp); err != nil { + return err + } + } + } + return nil +} + func (exec *medianColumnExecSelf[T, R]) unmarshal(mp *mpool.MPool, result, empties, groups [][]byte) error { if len(groups) > 0 { exec.groups = make([]*Vectors[T], len(groups)) @@ -89,17 +134,17 @@ func (exec *medianColumnExecSelf[T, R]) unmarshal(mp *mpool.MPool, result, empti } } } - return exec.ret.unmarshalFromBytes(result, empties) + // XXX: unless we do not support median(distinct X), this is a bug. + // group, so distinct is not used. + return exec.ret.unmarshalFromBytes(result, empties, nil) } func newMedianColumnExecSelf[T numeric | types.Decimal64 | types.Decimal128, R float64 | types.Decimal128](mg AggMemoryManager, info singleAggInfo) medianColumnExecSelf[T, R] { var r R + // XXX: this distinct impl. is totall screwed. s := medianColumnExecSelf[T, R]{ singleAggInfo: info, - ret: initAggResultWithFixedTypeResult[R](mg, info.retType, info.emptyNull, r), - } - if info.IsDistinct() { - s.distinctHash = newDistinctHash() + ret: initAggResultWithFixedTypeResult[R](mg, info.retType, info.emptyNull, r, info.IsDistinct()), } return s } diff --git a/pkg/sql/colexec/aggexec/result.go b/pkg/sql/colexec/aggexec/result.go index 08ba97b9e3b36..9c94ed7150995 100644 --- a/pkg/sql/colexec/aggexec/result.go +++ b/pkg/sql/colexec/aggexec/result.go @@ -15,6 +15,9 @@ package aggexec import ( + "bytes" + io "io" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/nulls" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -70,10 +73,10 @@ type SplitResult interface { func initAggResultWithFixedTypeResult[T types.FixedSizeTExceptStrType]( mg AggMemoryManager, resultType types.Type, - needEmptySituationList bool, initialValue T) aggResultWithFixedType[T] { + needEmptySituationList bool, initialValue T, hasDistinct bool) aggResultWithFixedType[T] { res := aggResultWithFixedType[T]{} - res.init(mg, resultType, needEmptySituationList) + res.init(mg, resultType, needEmptySituationList, hasDistinct) res.InitialValue = initialValue res.values = make([][]T, 1) @@ -83,10 +86,10 @@ func initAggResultWithFixedTypeResult[T types.FixedSizeTExceptStrType]( func initAggResultWithBytesTypeResult( mg AggMemoryManager, resultType types.Type, - setEmptyGroupToNull bool, initialValue string) aggResultWithBytesType { + setEmptyGroupToNull bool, initialValue string, hasDistinct bool) aggResultWithBytesType { res := aggResultWithBytesType{} - res.init(mg, resultType, setEmptyGroupToNull) + res.init(mg, resultType, setEmptyGroupToNull, hasDistinct) res.InitialValue = []byte(initialValue) return res @@ -98,6 +101,9 @@ type aggResultWithFixedType[T types.FixedSizeTExceptStrType] struct { // the initial value for a new result row. InitialValue T + // XXX FIXME: + // which genius thought of using this? It MUST be removed. + // Use GetValue and SetValue, to directly access the reuslt list. // for easy get from / set to resultList. values [][]T } @@ -109,8 +115,8 @@ func (r *aggResultWithFixedType[T]) Size() int64 { return size } -func (r *aggResultWithFixedType[T]) unmarshalFromBytes(resultData [][]byte, emptyData [][]byte) error { - if err := r.optSplitResult.unmarshalFromBytes(resultData, emptyData); err != nil { +func (r *aggResultWithFixedType[T]) unmarshalFromBytes(resultData, emptyData, distData [][]byte) error { + if err := r.optSplitResult.unmarshalFromBytes(resultData, emptyData, distData); err != nil { return err } r.values = make([][]T, len(resultData)) @@ -120,6 +126,15 @@ func (r *aggResultWithFixedType[T]) unmarshalFromBytes(resultData [][]byte, empt return nil } +func (r *aggResultWithFixedType[T]) setupT() { + if len(r.optSplitResult.resultList) > 0 { + r.values = make([][]T, len(r.optSplitResult.resultList)) + for i := range r.values { + r.values[i] = vector.MustFixedColNoTypeCheck[T](r.optSplitResult.resultList[i]) + } + } +} + func (r *aggResultWithFixedType[T]) grows(more int) error { x1, y1, x2, y2, err := r.resExtend(more) if err != nil { @@ -229,6 +244,7 @@ type optSplitResult struct { // nsp opt. doesThisNeedEmptyList bool shouldSetNullToEmptyGroup bool + hasDistinct bool // split opt. chunkSize int @@ -241,48 +257,55 @@ type optSplitResult struct { // the list of each group's result and empty situation. resultList []*vector.Vector emptyList []*vector.Vector - nowIdx1 int + + // This nowIdx1 is f**king insane + nowIdx1 int // for easy get from / set to emptyList. bsFromEmptyList [][]bool // for easy get / set result and empty from outer. accessIdx1, accessIdx2 int + + distinct []distinctHash } -func (r *optSplitResult) marshalToBytes() ([][]byte, [][]byte, error) { +// this API is broken. It should not need to return those [][]byte +func (r *optSplitResult) marshalToBytes() ([][]byte, [][]byte, [][]byte, error) { var err error + // WTF? min(r.nowIdx1+1, len...) resultData := make([][]byte, min(r.nowIdx1+1, len(r.resultList))) emptyData := make([][]byte, min(r.nowIdx1+1, len(r.emptyList))) for i := range resultData { if resultData[i], err = r.resultList[i].MarshalBinary(); err != nil { - return nil, nil, err + return nil, nil, nil, err } } for i := range emptyData { if emptyData[i], err = r.emptyList[i].MarshalBinary(); err != nil { - return nil, nil, err + return nil, nil, nil, err } } - return resultData, emptyData, nil + + if len(r.distinct) > 0 { + distinctData := make([][]byte, min(r.nowIdx1+1, len(r.distinct))) + for i := range r.distinct { + if distinctData[i], err = r.distinct[i].marshal(); err != nil { + return nil, nil, nil, err + } + } + return resultData, emptyData, distinctData, nil + } + return resultData, emptyData, nil, nil } -func (r *optSplitResult) unmarshalFromBytes(resultData [][]byte, emptyData [][]byte) (err error) { +func (r *optSplitResult) unmarshalFromBytes(resultData, emptyData, distinctData [][]byte) (err error) { r.free() defer func() { if err != nil { - for i := range r.resultList { - if r.resultList[i] != nil { - r.resultList[i].Free(r.mp) - } - } - for i := range r.emptyList { - if r.emptyList[i] != nil { - r.emptyList[i].Free(r.mp) - } - } + r.free() } }() @@ -303,11 +326,131 @@ func (r *optSplitResult) unmarshalFromBytes(resultData [][]byte, emptyData [][]b } r.bsFromEmptyList[i] = vector.MustFixedColNoTypeCheck[bool](r.emptyList[i]) } + + if len(distinctData) != 0 { + r.distinct = make([]distinctHash, len(distinctData)) + for i := range distinctData { + if err = r.distinct[i].unmarshal(distinctData[i]); err != nil { + return err + } + } + } + return nil +} + +func (r *optSplitResult) marshalToBuffers(flags [][]uint8, buf *bytes.Buffer) error { + rvec := vector.NewVec(r.resultType) + for i := range r.resultList { + rvec.UnionBatch(r.resultList[i], 0, r.resultList[i].Length(), flags[i], r.mp) + } + if err := rvec.MarshalBinaryWithBuffer(buf); err != nil { + return err + } + + var cnt int64 + cnt = int64(len(r.emptyList)) + buf.Write(types.EncodeInt64(&cnt)) + if cnt > 0 { + mvec := vector.NewVec(types.T_bool.ToType()) + for i := range r.emptyList { + mvec.UnionBatch(r.emptyList[i], 0, r.emptyList[i].Length(), flags[i], r.mp) + } + if err := mvec.MarshalBinaryWithBuffer(buf); err != nil { + return err + } + } + + cnt = 0 + if len(r.distinct) == 0 { + buf.Write(types.EncodeInt64(&cnt)) + } else { + cnt = int64(rvec.Length()) + buf.Write(types.EncodeInt64(&cnt)) + for i := range r.distinct { + if err := r.distinct[i].marshalToBuffers(flags[i], buf); err != nil { + return err + } + } + } + + return nil +} + +func (r *optSplitResult) marshalChunkToBuffer(chunk int, buf *bytes.Buffer) error { + if err := r.resultList[chunk].MarshalBinaryWithBuffer(buf); err != nil { + return err + } + + var cnt int64 + cnt = int64(len(r.emptyList)) + buf.Write(types.EncodeInt64(&cnt)) + if cnt > 0 { + if err := r.emptyList[chunk].MarshalBinaryWithBuffer(buf); err != nil { + return err + } + } + + cnt = 0 + if len(r.distinct) == 0 { + buf.Write(types.EncodeInt64(&cnt)) + } else { + cnt = int64(len(r.distinct[chunk].maps)) + buf.Write(types.EncodeInt64(&cnt)) + if err := r.distinct[chunk].marshalToBuffers(nil, buf); err != nil { + return err + } + } + return nil +} + +func (r *optSplitResult) unmarshalFromReader(reader io.Reader) error { + var err error + r.free() + defer func() { + if err != nil { + r.free() + } + }() + + r.resultList = make([]*vector.Vector, 1) + r.nowIdx1 = 0 + + r.resultList[0] = vector.NewOffHeapVecWithType(r.resultType) + if err = r.resultList[0].UnmarshalWithReader(reader, r.mp); err != nil { + return err + } + + cnt, err := types.ReadInt64(reader) + if err != nil { + return err + } + if cnt > 0 { + r.emptyList = make([]*vector.Vector, 1) + r.bsFromEmptyList = make([][]bool, 1) + r.emptyList[0] = vector.NewOffHeapVecWithType(types.T_bool.ToType()) + if err = r.emptyList[0].UnmarshalWithReader(reader, r.mp); err != nil { + return err + } + r.bsFromEmptyList[0] = vector.MustFixedColNoTypeCheck[bool](r.emptyList[0]) + } + + cnt, err = types.ReadInt64(reader) + if err != nil { + return err + } + if cnt > 0 { + r.distinct = make([]distinctHash, cnt) + for i := range r.distinct { + if err = r.distinct[i].unmarshalFromReader(reader); err != nil { + return err + } + } + } return nil } func (r *optSplitResult) init( - mg AggMemoryManager, typ types.Type, needEmptyList bool) { + mg AggMemoryManager, typ types.Type, needEmptyList, hasDistinct bool) { if mg != nil { r.mp = mg.Mp() } @@ -316,12 +459,17 @@ func (r *optSplitResult) init( r.optInformation.doesThisNeedEmptyList = needEmptyList r.optInformation.shouldSetNullToEmptyGroup = needEmptyList r.optInformation.chunkSize = GetChunkSizeFromType(typ) + r.optInformation.hasDistinct = hasDistinct r.resultList = append(r.resultList, vector.NewOffHeapVecWithType(typ)) if needEmptyList { r.emptyList = append(r.emptyList, vector.NewOffHeapVecWithType(types.T_bool.ToType())) r.bsFromEmptyList = append(r.bsFromEmptyList, nil) } + + if hasDistinct { + r.distinct = append(r.distinct, newDistinctHash()) + } r.nowIdx1 = 0 } @@ -329,6 +477,13 @@ func (r *optSplitResult) getChunkSize() int { return r.optInformation.chunkSize } +func (r *optSplitResult) getNthChunkSize(chunk int) int { + if chunk >= len(r.resultList) { + return -1 + } + return r.resultList[chunk].Length() +} + func (r *optSplitResult) modifyChunkSize(n int) { r.optInformation.chunkSize = n } @@ -475,7 +630,14 @@ func (r *optSplitResult) extendMoreToKthGroup(k int, more int) error { return err } if r.optInformation.doesThisNeedEmptyList { - return r.emptyList[k].PreExtend(more, r.mp) + if err := r.emptyList[k].PreExtend(more, r.mp); err != nil { + return err + } + } + if r.optInformation.hasDistinct { + if err := r.distinct[k].grows(more); err != nil { + return err + } } return nil } @@ -492,6 +654,9 @@ func (r *optSplitResult) appendPartK() int { if r.optInformation.doesThisNeedEmptyList { r.emptyList = append(r.emptyList, vector.NewOffHeapVecWithType(types.T_bool.ToType())) } + if r.optInformation.hasDistinct { + r.distinct = append(r.distinct, newDistinctHash()) + } return len(r.resultList) - 1 } @@ -565,6 +730,11 @@ func (r *optSplitResult) free() { r.resultList = nil r.emptyList = nil r.bsFromEmptyList = nil + + for _, d := range r.distinct { + d.free() + } + r.distinct = nil } func (r *optSplitResult) Size() int64 { @@ -585,6 +755,12 @@ func (r *optSplitResult) Size() int64 { size += int64(cap(r.emptyList)) * 8 // 24 is the size of a slice header. size += int64(cap(r.bsFromEmptyList)) * 24 + + if r.optInformation.hasDistinct { + for _, d := range r.distinct { + size += d.Size() + } + } return size } @@ -612,3 +788,23 @@ func setValueFromX1Y1ToX2Y2[T types.FixedSizeTExceptStrType]( src[x2][i] = value } } + +// fill in distict. return true if need to update agg state, false if not distinct. +func (r *optSplitResult) distinctFill(x, y int, vecs []*vector.Vector, row int) (bool, error) { + if !r.optInformation.hasDistinct { + // if has no distinct, always need to update agg + return true, nil + } + + need, err := r.distinct[x].fill(y, vecs, row) + return need, err +} + +func (r *optSplitResult) distinctMerge(x1 int, other *optSplitResult, x2 int) error { + if !r.optInformation.hasDistinct { + // this is fine. + return nil + } + // thank god, the following will bomb out if they collide. + return r.distinct[x1].merge(&other.distinct[x2]) +} diff --git a/pkg/sql/colexec/aggexec/result_test.go b/pkg/sql/colexec/aggexec/result_test.go index 6efa16c67743e..8b7048a532cf0 100644 --- a/pkg/sql/colexec/aggexec/result_test.go +++ b/pkg/sql/colexec/aggexec/result_test.go @@ -15,11 +15,12 @@ package aggexec import ( + "testing" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/stretchr/testify/require" - "testing" ) // there is very important to check the result's extendResultPurely first. @@ -34,7 +35,7 @@ func TestExtendResultPurely(t *testing.T) { mg := SimpleAggMemoryManager{mp: mpool.MustNewZeroNoFixed()} { osr := optSplitResult{} - osr.init(mg, types.T_bool.ToType(), false) + osr.init(mg, types.T_bool.ToType(), false, false) osr.optInformation.chunkSize = blockLimitation // pre extendResultPurely 130 rows. @@ -65,7 +66,7 @@ func TestFlushAll(t *testing.T) { mg := SimpleAggMemoryManager{mp: mpool.MustNewZeroNoFixed()} { osr := optSplitResult{} - osr.init(mg, types.T_bool.ToType(), false) + osr.init(mg, types.T_bool.ToType(), false, false) osr.optInformation.chunkSize = blockLimitation require.NoError(t, osr.preExtend(130)) @@ -81,7 +82,7 @@ func TestFlushAll(t *testing.T) { { osr := optSplitResult{} - osr.init(mg, types.T_bool.ToType(), false) + osr.init(mg, types.T_bool.ToType(), false, false) osr.optInformation.chunkSize = blockLimitation require.NoError(t, osr.extendResultPurely(201)) @@ -125,20 +126,26 @@ func TestResultSerialization(t *testing.T) { r1 := aggResultWithFixedType[int64]{} r1.optSplitResult.optInformation.chunkSize = 2 r1.optSplitResult.optInformation.doesThisNeedEmptyList = true - r1.init(proc, types.T_int64.ToType(), true) + r1.init(proc, types.T_int64.ToType(), true, false) _, _, _, _, err := r1.resExtend(7) require.NoError(t, err) - data1, data2, err := r1.marshalToBytes() + data1, data2, dist, err := r1.marshalToBytes() require.NoError(t, err) + if dist != nil { + t.Fatal("dist should be nil") + } + // XXX The following will fail -- a typed nil is not require.Equal to nil. + // require.Equal(t, nil, dist) + require.Equal(t, 0, len(dist)) r2 := aggResultWithFixedType[int64]{} - r2.init(proc, types.T_int64.ToType(), true) + r2.init(proc, types.T_int64.ToType(), true, false) r2.optSplitResult.optInformation.chunkSize = 2 r2.optSplitResult.optInformation.doesThisNeedEmptyList = true - require.NoError(t, r2.unmarshalFromBytes(data1, data2)) + require.NoError(t, r2.unmarshalFromBytes(data1, data2, nil)) require.Equal(t, len(r1.resultList), len(r2.resultList)) require.Equal(t, len(r1.emptyList), len(r2.emptyList)) @@ -154,20 +161,21 @@ func TestResultSerialization(t *testing.T) { r1 := aggResultWithBytesType{} r1.optSplitResult.optInformation.chunkSize = 2 r1.optSplitResult.optInformation.doesThisNeedEmptyList = true - r1.init(proc, types.T_varchar.ToType(), true) + r1.init(proc, types.T_varchar.ToType(), true, false) _, _, _, _, err := r1.resExtend(15) require.NoError(t, err) - data1, data2, err := r1.marshalToBytes() + data1, data2, dist, err := r1.marshalToBytes() require.NoError(t, err) + require.Equal(t, 0, len(dist)) r2 := aggResultWithBytesType{} - r2.init(proc, types.T_varchar.ToType(), true) + r2.init(proc, types.T_varchar.ToType(), true, false) r2.optSplitResult.optInformation.chunkSize = 2 r2.optSplitResult.optInformation.doesThisNeedEmptyList = true - require.NoError(t, r2.unmarshalFromBytes(data1, data2)) + require.NoError(t, r2.unmarshalFromBytes(data1, data2, nil)) require.Equal(t, len(r1.resultList), len(r2.resultList)) require.Equal(t, len(r1.emptyList), len(r2.emptyList)) @@ -186,7 +194,7 @@ func TestResultSize(t *testing.T) { // Test aggResultWithFixedType { before := proc.Mp().CurrNB() - r := initAggResultWithFixedTypeResult[int64](proc, types.T_int64.ToType(), true, 0) + r := initAggResultWithFixedTypeResult[int64](proc, types.T_int64.ToType(), true, 0, false) r.optInformation.chunkSize = chunkSize initialSize := r.Size() @@ -206,7 +214,7 @@ func TestResultSize(t *testing.T) { // Test aggResultWithBytesType { before := proc.Mp().CurrNB() - r := initAggResultWithBytesTypeResult(proc, types.T_varchar.ToType(), true, "") + r := initAggResultWithBytesTypeResult(proc, types.T_varchar.ToType(), true, "", false) r.optInformation.chunkSize = chunkSize initialSize := r.Size() diff --git a/pkg/sql/colexec/aggexec/types.go b/pkg/sql/colexec/aggexec/types.go index ac1cda5512c30..f56143f4f14e4 100644 --- a/pkg/sql/colexec/aggexec/types.go +++ b/pkg/sql/colexec/aggexec/types.go @@ -15,8 +15,12 @@ package aggexec import ( + "bytes" + "encoding" "fmt" + io "io" + proto "github.com/gogo/protobuf/proto" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -48,20 +52,20 @@ func MakeAggFunctionExpression(id int64, isDistinct bool, args []*plan.Expr, con } } -func (expr AggFuncExecExpression) GetAggID() int64 { - return expr.aggID +func (ag *AggFuncExecExpression) GetAggID() int64 { + return ag.aggID } -func (expr AggFuncExecExpression) IsDistinct() bool { - return expr.isDistinct +func (ag *AggFuncExecExpression) IsDistinct() bool { + return ag.isDistinct } -func (expr AggFuncExecExpression) GetArgExpressions() []*plan.Expr { - return expr.argExpressions +func (ag *AggFuncExecExpression) GetArgExpressions() []*plan.Expr { + return ag.argExpressions } -func (expr AggFuncExecExpression) GetExtraConfig() []byte { - return expr.extraConfig +func (ag *AggFuncExecExpression) GetExtraConfig() []byte { + return ag.extraConfig } // AggFuncExec is an interface to do execution for aggregation. @@ -109,6 +113,11 @@ type AggFuncExec interface { // Flush return the aggregation result. Flush() ([]*vector.Vector, error) + // Serialize intermediate result to bytes. + SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error + SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error + UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error + Size() int64 // Free clean the resource and reuse the aggregation if possible. @@ -302,3 +311,219 @@ func makeWindowExec( } return makeRankDenseRankRowNumber(mg, info), nil } + +type dummyBinaryMarshaler struct { + encoding.BinaryMarshaler +} +type dummyBinaryUnmarshaler struct { + encoding.BinaryUnmarshaler +} + +func (d dummyBinaryMarshaler) MarshalBinary() ([]byte, error) { + return nil, nil +} +func (d dummyBinaryUnmarshaler) UnmarshalBinary(data []byte) error { + return nil +} + +func marshalRetAndGroupsToBuffer[T encoding.BinaryMarshaler]( + cnt int64, flags [][]uint8, buf *bytes.Buffer, + ret *optSplitResult, groups []T, extra [][]byte) error { + types.WriteInt64(buf, cnt) + if cnt == 0 { + return nil + } + if err := ret.marshalToBuffers(flags, buf); err != nil { + return err + } + + if len(groups) == 0 { + types.WriteInt64(buf, 0) + } else { + types.WriteInt64(buf, cnt) + groupIdx := 0 + for i := range flags { + for j := range flags[i] { + if flags[i][j] == 1 { + bs, err := groups[groupIdx].MarshalBinary() + if err != nil { + return err + } + if err = types.WriteSizeBytes(bs, buf); err != nil { + return err + } + } + groupIdx += 1 + } + } + } + + cnt = int64(len(extra)) + types.WriteInt64(buf, cnt) + for i := range extra { + if err := types.WriteSizeBytes(extra[i], buf); err != nil { + return err + } + } + return nil +} + +func marshalChunkToBuffer[T encoding.BinaryMarshaler](chunk int, buf *bytes.Buffer, + ret *optSplitResult, groups []T, extra [][]byte) error { + chunkSz := ret.optInformation.chunkSize + start := chunkSz * chunk + chunkNGroup := ret.getNthChunkSize(chunk) + if chunkSz < 0 { + return moerr.NewInternalErrorNoCtx("invalid chunk number.") + } + + cnt := int64(chunkNGroup) + buf.Write(types.EncodeInt64(&cnt)) + + if err := ret.marshalChunkToBuffer(chunk, buf); err != nil { + return err + } + + if len(groups) == 0 { + types.WriteInt64(buf, 0) + } else { + types.WriteInt64(buf, cnt) + for i := 0; i < chunkNGroup; i++ { + bs, err := groups[start+i].MarshalBinary() + if err != nil { + return err + } + if err = types.WriteSizeBytes(bs, buf); err != nil { + return err + } + } + } + + cnt = int64(len(extra)) + types.WriteInt64(buf, cnt) + for i := range extra { + if err := types.WriteSizeBytes(extra[i], buf); err != nil { + return err + } + } + + return nil +} + +func unmarshalFromReaderNoGroup(reader io.Reader, ret *optSplitResult) error { + var err error + + cnt, err := types.ReadInt64(reader) + if err != nil { + return err + } + ret.optInformation.chunkSize = int(cnt) + if err := ret.unmarshalFromReader(reader); err != nil { + return err + } + return nil +} + +func unmarshalFromReader[T encoding.BinaryUnmarshaler](reader io.Reader, ret *optSplitResult) ([]T, [][]byte, error) { + err := unmarshalFromReaderNoGroup(reader, ret) + if err != nil { + return nil, nil, err + } + + var res []T + var extra [][]byte + // read groups + cnt, err := types.ReadInt64(reader) + if err != nil { + return nil, nil, err + } + if cnt != 0 { + res = make([]T, cnt) + for i := range res { + _, bs, err := types.ReadSizeBytes(reader, nil, false) + if err != nil { + return nil, nil, err + } + if err = res[i].UnmarshalBinary(bs); err != nil { + return nil, nil, err + } + } + } + + cnt, err = types.ReadInt64(reader) + if err != nil { + return nil, nil, err + } + if cnt > 0 { + extra = make([][]byte, cnt) + for i := range extra { + _, bs, err := types.ReadSizeBytes(reader, nil, false) + if err != nil { + return nil, nil, err + } + extra[i] = bs + } + } + + return res, extra, nil +} + +func (ag *AggFuncExecExpression) MarshalToBuffer(buf *bytes.Buffer) error { + buf.Write(types.EncodeInt64(&ag.aggID)) + buf.Write(types.EncodeBool(&ag.isDistinct)) + argLen := int32(len(ag.argExpressions)) + buf.Write(types.EncodeInt32(&argLen)) + for _, expr := range ag.argExpressions { + bs, err := proto.Marshal(expr) + if err != nil { + return err + } + bsLen := int32(len(bs)) + buf.Write(types.EncodeInt32(&bsLen)) + buf.Write(bs) + } + exLen := int32(len(ag.extraConfig)) + buf.Write(types.EncodeInt32(&exLen)) + buf.Write(ag.extraConfig) + return nil +} + +func (ag *AggFuncExecExpression) UnmarshalFromReader(r io.Reader) error { + var err error + if ag.aggID, err = types.ReadInt64(r); err != nil { + return err + } + if ag.isDistinct, err = types.ReadBool(r); err != nil { + return err + } + argLen, err := types.ReadInt32(r) + if err != nil { + return err + } + for i := int32(0); i < argLen; i++ { + _, bs, err := types.ReadSizeBytes(r, nil, false) + if err != nil { + return err + } + expr := &plan.Expr{} + if err := proto.Unmarshal(bs, expr); err != nil { + return err + } + ag.argExpressions = append(ag.argExpressions, expr) + } + exLen, err := types.ReadInt32(r) + if err != nil { + return err + } + + // if exLen is 0, the extra config is nil, we SHOULD NOT create a + // zero length slice, which will cause failure later when people + // check extraConfig != nil + if exLen > 0 { + ag.extraConfig = make([]byte, exLen) + if _, err := io.ReadFull(r, ag.extraConfig); err != nil { + return err + } + } + return nil +} diff --git a/pkg/sql/colexec/aggexec/window.go b/pkg/sql/colexec/aggexec/window.go index 21c856d3bb6d8..46ad4cf1011e7 100644 --- a/pkg/sql/colexec/aggexec/window.go +++ b/pkg/sql/colexec/aggexec/window.go @@ -15,6 +15,9 @@ package aggexec import ( + "bytes" + io "io" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -25,23 +28,30 @@ func SingleWindowReturnType(_ []types.Type) types.Type { return types.T_int64.ToType() } +type i64Slice []int64 + +func (s i64Slice) MarshalBinary() ([]byte, error) { + return types.EncodeSlice[int64](s), nil +} + // special structure for a single column window function. type singleWindowExec struct { singleAggInfo ret aggResultWithFixedType[int64] - groups [][]int64 + // groups [][]int64 + groups []i64Slice } func makeRankDenseRankRowNumber(mg AggMemoryManager, info singleAggInfo) AggFuncExec { return &singleWindowExec{ singleAggInfo: info, - ret: initAggResultWithFixedTypeResult[int64](mg, info.retType, info.emptyNull, 0), + ret: initAggResultWithFixedTypeResult[int64](mg, info.retType, info.emptyNull, 0, false), } } func (exec *singleWindowExec) GroupGrow(more int) error { - exec.groups = append(exec.groups, make([][]int64, more)...) + exec.groups = append(exec.groups, make([]i64Slice, more)...) return exec.ret.grows(more) } @@ -61,10 +71,13 @@ func (exec *singleWindowExec) GetOptResult() SplitResult { func (exec *singleWindowExec) marshal() ([]byte, error) { d := exec.singleAggInfo.getEncoded() - r, em, err := exec.ret.marshalToBytes() + r, em, dist, err := exec.ret.marshalToBytes() if err != nil { return nil, err } + if dist != nil { + return nil, moerr.NewInternalErrorNoCtx("dist should have been nil") + } encoded := EncodedAgg{ Info: d, @@ -81,16 +94,53 @@ func (exec *singleWindowExec) marshal() ([]byte, error) { return encoded.Marshal() } +func (exec *singleWindowExec) SaveIntermediateResult(cnt int64, flags [][]uint8, buf *bytes.Buffer) error { + return marshalRetAndGroupsToBuffer( + cnt, flags, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *singleWindowExec) SaveIntermediateResultOfChunk(chunk int, buf *bytes.Buffer) error { + return marshalChunkToBuffer( + chunk, buf, + &exec.ret.optSplitResult, exec.groups, nil) +} + +func (exec *singleWindowExec) UnmarshalFromReader(reader io.Reader, mp *mpool.MPool) error { + err := unmarshalFromReaderNoGroup(reader, &exec.ret.optSplitResult) + if err != nil { + return err + } + exec.ret.setupT() + + ngrp, err := types.ReadInt64(reader) + if err != nil { + return err + } + if ngrp != 0 { + exec.groups = make([]i64Slice, ngrp) + for i := range exec.groups { + _, bs, err := types.ReadSizeBytes(reader, nil, false) + if err != nil { + return err + } + exec.groups[i] = types.DecodeSlice[int64](bs) + } + } + return nil +} + func (exec *singleWindowExec) unmarshal(mp *mpool.MPool, result, empties, groups [][]byte) error { if len(exec.groups) > 0 { - exec.groups = make([][]int64, len(groups)) + exec.groups = make([]i64Slice, len(groups)) for i := range exec.groups { if len(groups[i]) > 0 { exec.groups[i] = types.DecodeSlice[int64](groups[i]) } } } - return exec.ret.unmarshalFromBytes(result, empties) + // group used by above, + return exec.ret.unmarshalFromBytes(result, empties, nil) } func (exec *singleWindowExec) BulkFill(groupIndex int, vectors []*vector.Vector) error { diff --git a/pkg/sql/colexec/dispatch/sendfunc.go b/pkg/sql/colexec/dispatch/sendfunc.go index 775f77d9a2210..f225bc4402e21 100644 --- a/pkg/sql/colexec/dispatch/sendfunc.go +++ b/pkg/sql/colexec/dispatch/sendfunc.go @@ -73,7 +73,7 @@ func sendToAllRemoteFunc(bat *batch.Batch, ap *Dispatch, proc *process.Process) } { // send to remote regs - encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf) + encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf, true) if errEncode != nil { return false, errEncode } @@ -124,8 +124,7 @@ func sendBatToIndex(ap *Dispatch, proc *process.Process, bat *batch.Batch, shuff if shuffleIndex == batIndex { if bat != nil && !bat.IsEmpty() { receiverID := fmt.Sprintf("%s(ShuffleIdx=%d)", r.Uid.String(), shuffleIndex) - - encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf) + encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf, true) if errEncode != nil { err = errEncode break @@ -181,8 +180,7 @@ func sendBatToMultiMatchedReg(ap *Dispatch, proc *process.Process, bat *batch.Ba if shuffleIndex%localRegsCnt == batIndex%localRegsCnt { if bat != nil && !bat.IsEmpty() { receiverID := fmt.Sprintf("%s(ShuffleIdx=%d)", r.Uid.String(), shuffleIndex) - - encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf) + encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf, true) if errEncode != nil { return errEncode } @@ -294,7 +292,7 @@ func sendToAnyRemoteFunc(bat *batch.Batch, ap *Dispatch, proc *process.Process) default: } - encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf) + encodeData, errEncode := bat.MarshalBinaryWithBuffer(&ap.ctr.marshalBuf, true) if errEncode != nil { return false, errEncode } diff --git a/pkg/sql/colexec/evalExpression.go b/pkg/sql/colexec/evalExpression.go index a8cdaab45d6c0..88bf6552385ad 100644 --- a/pkg/sql/colexec/evalExpression.go +++ b/pkg/sql/colexec/evalExpression.go @@ -1526,3 +1526,43 @@ func isConst(expr *plan.Expr) bool { return true } } + +type ExprEvalVector struct { + Executor []ExpressionExecutor + Vec []*vector.Vector + Typ []types.Type +} + +func MakeEvalVector(proc *process.Process, expressions []*plan.Expr) (ev ExprEvalVector, err error) { + if len(expressions) == 0 { + return + } + + ev.Executor, err = NewExpressionExecutorsFromPlanExpressions(proc, expressions) + if err != nil { + return + } + ev.Vec = make([]*vector.Vector, len(ev.Executor)) + ev.Typ = make([]types.Type, len(ev.Executor)) + for i, expr := range expressions { + ev.Typ[i] = types.New(types.T(expr.Typ.Id), expr.Typ.Width, expr.Typ.Scale) + } + return +} + +func (ev *ExprEvalVector) Free() { + for i := range ev.Executor { + if ev.Executor[i] != nil { + ev.Executor[i].Free() + } + } + ev.Executor = nil +} + +func (ev *ExprEvalVector) ResetForNextQuery() { + for i := range ev.Executor { + if ev.Executor[i] != nil { + ev.Executor[i].ResetForNextQuery() + } + } +} diff --git a/pkg/sql/colexec/group/exec.go b/pkg/sql/colexec/group/exec.go deleted file mode 100644 index c866dc67f8625..0000000000000 --- a/pkg/sql/colexec/group/exec.go +++ /dev/null @@ -1,503 +0,0 @@ -// Copyright 2024 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 group - -import ( - "bytes" - "fmt" - - "github.com/matrixorigin/matrixone/pkg/common/hashmap" - "github.com/matrixorigin/matrixone/pkg/container/batch" - "github.com/matrixorigin/matrixone/pkg/container/types" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/sql/plan/function" - "github.com/matrixorigin/matrixone/pkg/vm" - "github.com/matrixorigin/matrixone/pkg/vm/process" -) - -var makeAggExec = aggexec.MakeAgg - -// intermediateResultSendActionTrigger is the row number to trigger an action -// to send the intermediate result -// if the result row is not less than this number. -var intermediateResultSendActionTrigger = aggexec.BlockCapacityForStrType - -func (group *Group) String(buf *bytes.Buffer) { - buf.WriteString(thisOperatorName + ": group([") - for i, expr := range group.Exprs { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(fmt.Sprintf("%v", expr)) - } - buf.WriteString("], [") - - for i, ag := range group.Aggs { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(fmt.Sprintf("%v(%v)", function.GetAggFunctionNameByID(ag.GetAggID()), ag.GetArgExpressions())) - } - buf.WriteString("])") -} - -func (group *Group) Prepare(proc *process.Process) (err error) { - group.ctr.state = vm.Build - group.ctr.dataSourceIsEmpty = true - group.prepareAnalyzer() - if err = group.prepareAgg(proc); err != nil { - return err - } - if err = group.prepareGroup(proc); err != nil { - return err - } - return group.PrepareProjection(proc) -} - -func (group *Group) prepareAnalyzer() { - if group.OpAnalyzer != nil { - group.OpAnalyzer.Reset() - return - } - group.OpAnalyzer = process.NewAnalyzer(group.GetIdx(), group.IsFirst, group.IsLast, "group") -} - -func (group *Group) prepareAgg(proc *process.Process) error { - if len(group.ctr.aggregateEvaluate) == len(group.Aggs) { - return nil - } - - group.ctr.freeAggEvaluate() - group.ctr.aggregateEvaluate = make([]ExprEvalVector, 0, len(group.Aggs)) - for _, ag := range group.Aggs { - e, err := MakeEvalVector(proc, ag.GetArgExpressions()) - if err != nil { - return err - } - group.ctr.aggregateEvaluate = append(group.ctr.aggregateEvaluate, e) - } - return nil -} - -func (group *Group) prepareGroup(proc *process.Process) (err error) { - if len(group.ctr.groupByEvaluate.Executor) == len(group.Exprs) { - return nil - } - - group.ctr.freeGroupEvaluate() - // calculate the key width and key nullable. - group.ctr.keyWidth, group.ctr.keyNullable = 0, false - for _, expr := range group.Exprs { - group.ctr.keyNullable = group.ctr.keyNullable || (!expr.Typ.NotNullable) - } - for _, expr := range group.Exprs { - width := GetKeyWidth(types.T(expr.Typ.Id), expr.Typ.Width, group.ctr.keyNullable) - group.ctr.keyWidth += width - } - - if group.ctr.keyWidth == 0 { - group.ctr.mtyp = H0 - } else if group.ctr.keyWidth <= 8 { - group.ctr.mtyp = H8 - } else { - group.ctr.mtyp = HStr - } - for _, flag := range group.GroupingFlag { - if !flag { - group.ctr.mtyp = HStr - break - } - } - group.ctr.groupByEvaluate, err = MakeEvalVector(proc, group.Exprs) - return err -} - -func GetKeyWidth(id types.T, width0 int32, nullable bool) (width int) { - if id.FixedLength() < 0 { - width = 128 - if width0 > 0 { - width = int(width0) - } - - if id == types.T_array_float32 { - width *= 4 - } - if id == types.T_array_float64 { - width *= 8 - } - } else { - width = id.TypeLen() - } - - if nullable { - width++ - } - return width -} - -func (group *Group) Call(proc *process.Process) (vm.CallResult, error) { - if err, isCancel := vm.CancelCheck(proc); isCancel { - return vm.CancelResult, err - } - - var b *batch.Batch - var err error - if group.NeedEval { - b, err = group.callToGetFinalResult(proc) - } else { - b, err = group.callToGetIntermediateResult(proc) - } - if err != nil { - return vm.CancelResult, err - } - - res := vm.NewCallResult() - res.Batch = b - return res, nil -} - -func (group *Group) getInputBatch(proc *process.Process) (*batch.Batch, error) { - r, err := vm.ChildrenCall(group.GetChildren(0), proc, group.OpAnalyzer) - return r.Batch, err -} - -// callToGetFinalResult -// if this operator need to eval the final result for `agg(y) group by x`, -// we are looping to receive all the data to fill the aggregate functions with every group, -// flush the final result as vectors once data was over. -// -// To avoid a single batch being too large, -// we split the result as many part of vector, and send them in order. -func (group *Group) callToGetFinalResult(proc *process.Process) (*batch.Batch, error) { - group.ctr.result1.CleanLastPopped(proc.Mp()) - if group.ctr.state == vm.End { - return nil, nil - } - - for { - if group.ctr.state == vm.Eval { - if group.ctr.result1.IsEmpty() { - group.ctr.state = vm.End - return nil, nil - } - return group.ctr.result1.PopResult(proc.Mp()) - } - - res, err := group.getInputBatch(proc) - if err != nil { - return nil, err - } - if res == nil { - group.ctr.state = vm.Eval - - if group.ctr.isDataSourceEmpty() && len(group.Exprs) == 0 { - if err = group.generateInitialResult1WithoutGroupBy(proc); err != nil { - return nil, err - } - group.ctr.result1.ToPopped[0].SetRowCount(1) - } else { - // update stats - if group.OpAnalyzer != nil && group.ctr.hr.Hash != nil { - group.OpAnalyzer.Alloc(group.ctr.hr.Hash.Size()) - } - // the others are in GroupResultBuffer -- later. - } - continue - } - if res.IsEmpty() { - continue - } - - group.ctr.dataSourceIsEmpty = false - if err = group.consumeBatchToGetFinalResult(proc, res); err != nil { - return nil, err - } - } -} - -func (group *Group) generateInitialResult1WithoutGroupBy(proc *process.Process) error { - aggs, err := group.generateAggExec(proc) - if err != nil { - return err - } - - group.ctr.result1.InitOnlyAgg(aggexec.GetMinAggregatorsChunkSize(nil, aggs), aggs) - for i := range group.ctr.result1.AggList { - if err = group.ctr.result1.AggList[i].GroupGrow(1); err != nil { - return err - } - } - return nil -} - -func (group *Group) consumeBatchToGetFinalResult( - proc *process.Process, bat *batch.Batch) error { - - if err := group.evaluateGroupByAndAgg(proc, bat); err != nil { - return err - } - - switch group.ctr.mtyp { - case H0: - // without group by. - if group.ctr.result1.IsEmpty() { - if err := group.generateInitialResult1WithoutGroupBy(proc); err != nil { - return err - } - } - - group.ctr.result1.ToPopped[0].SetRowCount(1) - for i := range group.ctr.result1.AggList { - if err := group.ctr.result1.AggList[i].BulkFill(0, group.ctr.aggregateEvaluate[i].Vec); err != nil { - return err - } - } - - default: - // with group by. - if group.ctr.result1.IsEmpty() { - err := group.ctr.hr.BuildHashTable(false, group.ctr.mtyp == HStr, group.ctr.keyNullable, group.PreAllocSize) - if err != nil { - return err - } - - aggs, err := group.generateAggExec(proc) - if err != nil { - return err - } - if err = group.ctr.result1.InitWithGroupBy( - proc.Mp(), - aggexec.GetMinAggregatorsChunkSize(group.ctr.groupByEvaluate.Vec, aggs), aggs, group.ctr.groupByEvaluate.Vec, group.PreAllocSize); err != nil { - return err - } - } - - count := bat.RowCount() - more := 0 - aggList := group.ctr.result1.GetAggList() - for i := 0; i < count; i += hashmap.UnitLimit { - n := count - i - if n > hashmap.UnitLimit { - n = hashmap.UnitLimit - } - - originGroupCount := group.ctr.hr.Hash.GroupCount() - vals, _, err := group.ctr.hr.Itr.Insert(i, n, group.ctr.groupByEvaluate.Vec) - if err != nil { - return err - } - insertList, _ := group.ctr.hr.GetBinaryInsertList(vals, originGroupCount) - - more, err = group.ctr.result1.AppendBatch(proc.Mp(), group.ctr.groupByEvaluate.Vec, i, insertList) - if err != nil { - return err - } - - if more > 0 { - for _, agg := range aggList { - if err = agg.GroupGrow(more); err != nil { - return err - } - } - } - - for j := range aggList { - if err = aggList[j].BatchFill(i, vals[:n], group.ctr.aggregateEvaluate[j].Vec); err != nil { - return err - } - } - } - } - - return nil -} - -func (group *Group) generateAggExec(proc *process.Process) ([]aggexec.AggFuncExec, error) { - var err error - execs := make([]aggexec.AggFuncExec, 0, len(group.Aggs)) - defer func() { - if err != nil { - for _, exec := range execs { - exec.Free() - } - } - }() - - for i, ag := range group.Aggs { - exec, err := makeAggExec(proc, ag.GetAggID(), ag.IsDistinct(), group.ctr.aggregateEvaluate[i].Typ...) - if err != nil { - return nil, err - } - execs = append(execs, exec) - - if config := ag.GetExtraConfig(); config != nil { - if err = exec.SetExtraInformation(config, 0); err != nil { - return nil, err - } - } - } - return execs, nil -} - -func preExtendAggExecs(execs []aggexec.AggFuncExec, preAllocated uint64) (err error) { - if allocate := int(preAllocated); allocate > 0 { - for _, exec := range execs { - if err = exec.PreAllocateGroups(allocate); err != nil { - return err - } - } - } - return nil -} - -// callToGetIntermediateResult return the intermediate result of grouped data aggregation, -// sending out intermediate results once the group count exceeds intermediateResultSendActionTrigger. -// -// this function will be only called when there is one MergeGroup operator was behind. -func (group *Group) callToGetIntermediateResult(proc *process.Process) (*batch.Batch, error) { - group.ctr.result2.resetLastPopped() - if group.ctr.state == vm.End { - return nil, nil - } - - r, err := group.initCtxToGetIntermediateResult(proc) - if err != nil { - return nil, err - } - - var input *batch.Batch - for { - if group.ctr.state == vm.End { - return nil, nil - } - - input, err = group.getInputBatch(proc) - if err != nil { - return nil, err - } - if input == nil { - group.ctr.state = vm.End - - if group.ctr.isDataSourceEmpty() && len(group.Exprs) == 0 { - r.SetRowCount(1) - return r, nil - } - if r.RowCount() > 0 { - return r, nil - } - continue - } - if input.IsEmpty() { - continue - } - group.ctr.dataSourceIsEmpty = false - - if next, er := group.consumeBatchToRes(proc, input, r); er != nil { - return nil, er - } else { - if next { - continue - } - return r, nil - } - } -} - -func (group *Group) initCtxToGetIntermediateResult( - proc *process.Process) (*batch.Batch, error) { - - r, err := group.ctr.result2.getResultBatch( - proc, &group.ctr.groupByEvaluate, group.ctr.aggregateEvaluate, group.Aggs) - if err != nil { - return nil, err - } - - if group.ctr.mtyp == H0 { - for i := range r.Aggs { - if err = r.Aggs[i].GroupGrow(1); err != nil { - return nil, err - } - } - } else { - allocated := max(min(group.PreAllocSize, uint64(intermediateResultSendActionTrigger)), 0) - if err = group.ctr.hr.BuildHashTable(true, group.ctr.mtyp == HStr, group.ctr.keyNullable, allocated); err != nil { - return nil, err - } - err = preExtendAggExecs(r.Aggs, allocated) - } - - return r, err -} - -func (group *Group) consumeBatchToRes( - proc *process.Process, bat *batch.Batch, res *batch.Batch) (receiveNext bool, err error) { - - if err = group.evaluateGroupByAndAgg(proc, bat); err != nil { - return false, err - } - - switch group.ctr.mtyp { - case H0: - // without group by. - for i := range res.Aggs { - if err = res.Aggs[i].BulkFill(0, group.ctr.aggregateEvaluate[i].Vec); err != nil { - return false, err - } - } - res.SetRowCount(1) - return false, nil - - default: - // with group by. - count := bat.RowCount() - for i := 0; i < count; i += hashmap.UnitLimit { - n := count - i - if n > hashmap.UnitLimit { - n = hashmap.UnitLimit - } - - originGroupCount := group.ctr.hr.Hash.GroupCount() - vals, _, err1 := group.ctr.hr.Itr.Insert(i, n, group.ctr.groupByEvaluate.Vec) - if err1 != nil { - return false, err1 - } - insertList, more := group.ctr.hr.GetBinaryInsertList(vals, originGroupCount) - - cnt := int(more) - if cnt > 0 { - for j, vec := range res.Vecs { - if err = vec.UnionBatch(group.ctr.groupByEvaluate.Vec[j], int64(i), n, insertList, proc.Mp()); err != nil { - return false, err - } - } - - for _, ag := range res.Aggs { - if err = ag.GroupGrow(cnt); err != nil { - return false, err - } - } - res.AddRowCount(cnt) - } - - for j, ag := range res.Aggs { - if err = ag.BatchFill(i, vals[:n], group.ctr.aggregateEvaluate[j].Vec); err != nil { - return false, err - } - } - } - - return res.RowCount() < intermediateResultSendActionTrigger, nil - } -} diff --git a/pkg/sql/colexec/group/exec2.go b/pkg/sql/colexec/group/exec2.go new file mode 100644 index 0000000000000..a9cc0cf5a0280 --- /dev/null +++ b/pkg/sql/colexec/group/exec2.go @@ -0,0 +1,527 @@ +// Copyright 2024 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 group + +import ( + "bytes" + + "github.com/matrixorigin/matrixone/pkg/common/hashmap" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "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/sql/colexec" + "github.com/matrixorigin/matrixone/pkg/vm" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +const ( + // we use this size as preferred output batch size, which is typical + // in MO. + aggBatchSize = 8192 + + // we use this size as pre-allocated size for hash table. + aggHtPreAllocSize = 1024 + + // spill parameters. + spillNumBuckets = 32 + spillMaskBits = 5 + spillMaxPass = 3 +) + +func (group *Group) Prepare(proc *process.Process) (err error) { + group.ctr.state = vm.Build + + if group.OpAnalyzer != nil { + group.OpAnalyzer.Reset() + } + group.OpAnalyzer = process.NewAnalyzer(group.GetIdx(), group.IsFirst, group.IsLast, "group") + + if err = group.prepareGroupAndAggArg(proc); err != nil { + return err + } + + if err = group.PrepareProjection(proc); err != nil { + return err + } + + if group.NeedEval { + group.ctr.setSpillMem(group.SpillMem, group.Aggs) + } else { + group.ctr.setSpillMem(group.SpillMem/8, group.Aggs) + } + return nil +} + +func (group *Group) prepareGroupAndAggArg(proc *process.Process) (err error) { + if len(group.ctr.groupByEvaluate.Executor) == len(group.Exprs) { + group.ctr.groupByEvaluate.ResetForNextQuery() + } else { + // calculate the key width and key nullable, and hash table type. + group.ctr.keyWidth, group.ctr.keyNullable = 0, false + for _, expr := range group.Exprs { + group.ctr.keyNullable = group.ctr.keyNullable || (!expr.Typ.NotNullable) + width := GetKeyWidth(types.T(expr.Typ.Id), expr.Typ.Width, group.ctr.keyNullable) + group.ctr.keyWidth += int32(width) + } + + if group.ctr.keyWidth == 0 { + group.ctr.mtyp = H0 + } else if group.ctr.keyWidth <= 8 { + group.ctr.mtyp = H8 + } else { + group.ctr.mtyp = HStr + } + + for _, flag := range group.GroupingFlag { + if !flag { + group.ctr.mtyp = HStr + break + } + } + + // create group by evaluate + group.ctr.groupByEvaluate.Free() + group.ctr.groupByEvaluate, err = colexec.MakeEvalVector(proc, group.Exprs) + if err != nil { + return err + } + } + + if group.ctr.mtyp == H0 { + // no group by, only one group, always create the dummy group by batch. + if len(group.ctr.groupByBatches) == 0 { + group.ctr.groupByBatches = append(group.ctr.groupByBatches, + group.ctr.createNewGroupByBatch(proc, group.ctr.groupByEvaluate.Vec, 1)) + group.ctr.groupByBatches[0].SetRowCount(1) + } + } + + needMakeAggArg := true + if len(group.ctr.aggArgEvaluate) == len(group.Aggs) { + needMakeAggArg = false + for i := range group.ctr.aggArgEvaluate { + if len(group.ctr.aggArgEvaluate[i].Vec) != len(group.Aggs[i].GetArgExpressions()) { + needMakeAggArg = true + break + } else { + group.ctr.aggArgEvaluate[i].ResetForNextQuery() + } + } + } + + if needMakeAggArg { + for i := range group.ctr.aggArgEvaluate { + group.ctr.aggArgEvaluate[i].Free() + } + group.ctr.aggArgEvaluate = make([]colexec.ExprEvalVector, 0, len(group.Aggs)) + for _, ag := range group.Aggs { + e, err := colexec.MakeEvalVector(proc, ag.GetArgExpressions()) + if err != nil { + return err + } + group.ctr.aggArgEvaluate = append(group.ctr.aggArgEvaluate, e) + } + } + + // have not generated aggList agg exec yet, lets do it. + if len(group.Aggs) > 0 { + if len(group.ctr.aggList) == len(group.Aggs) { + for _, ag := range group.ctr.aggList { + ag.Free() + if group.ctr.mtyp == H0 { + ag.GroupGrow(1) + } + } + } else { + group.ctr.aggList, err = group.ctr.makeAggList(proc, group.Aggs) + if err != nil { + return err + } + } + } + + return nil +} + +func GetKeyWidth(id types.T, width0 int32, nullable bool) (width int) { + if id.FixedLength() < 0 { + width = 128 + if width0 > 0 { + width = int(width0) + } + + if id == types.T_array_float32 { + width *= 4 + } + if id == types.T_array_float64 { + width *= 8 + } + } else { + width = id.TypeLen() + } + + if nullable { + width++ + } + return width +} + +// main entry of the group operator. +func (group *Group) Call(proc *process.Process) (vm.CallResult, error) { + var err error + + var isCancel bool + if err, isCancel = vm.CancelCheck(proc); isCancel { + return vm.CancelResult, err + } + + group.OpAnalyzer.Start() + defer group.OpAnalyzer.Stop() + + switch group.ctr.state { + case vm.Build: + // receive all data, loop till exhuasted. + for !group.ctr.inputDone { + var r vm.CallResult + r, err = vm.ChildrenCall(group.GetChildren(0), proc, group.OpAnalyzer) + if err != nil { + return vm.CancelResult, err + } + + // all handled, going to eval mode. + // + // XXX: Note that this test, r.Batch == nil is treated as ExecStop. + // I am not sure this is correct, but our code depends on this. + // Esp, some table function will produce ExecNext result with nil + // batch as end of data. Shuffle, on the otherhand may product + // more batches after sending a ExecStop result. + // + // if r.Status == vm.ExecStop || r.Batch == nil { + if r.Batch == nil { + group.ctr.state = vm.Eval + group.ctr.inputDone = true + } + + // empty batch, skip. + if r.Batch == nil || r.Batch.IsEmpty() { + continue + } + + if len(group.ctr.aggList) != len(group.Aggs) { + group.ctr.aggList, err = group.ctr.makeAggList(proc, group.Aggs) + if err != nil { + return vm.CancelResult, err + } + } + + // build one batch. + var needSpill bool + needSpill, err = group.buildOneBatch(proc, r.Batch) + if err != nil { + return vm.CancelResult, err + } + + if needSpill { + // we need to spill the data to disk. + if group.NeedEval { + group.ctr.spillDataToDisk(proc, nil) + // continue the loop, to receive more data. + } else { + // break the loop, output the intermediate result. + break + } + } + } + + // spilling -- spill whatever left in memory, and load first spilled bucket. + if group.ctr.isSpilling() { + if err = group.ctr.spillDataToDisk(proc, nil); err != nil { + return vm.CancelResult, err + } + if _, err = group.ctr.loadSpilledData(proc, group.OpAnalyzer, group.Aggs); err != nil { + return vm.CancelResult, err + } + } + + return group.outputOneBatch(proc) + + case vm.Eval: + return group.outputOneBatch(proc) + + case vm.End: + return vm.CancelResult, nil + } + + err = moerr.NewInternalError(proc.Ctx, "bug: unknown group state") + return vm.CancelResult, err +} + +func (group *Group) buildOneBatch(proc *process.Process, bat *batch.Batch) (bool, error) { + + var err error + // evaluate the group by and agg args, no matter what mtyp, + // we need to do this first. + if err = group.evaluateGroupByAndAggArgs(proc, bat); err != nil { + return false, err + } + + // without group by, there is only one group. + if group.ctr.mtyp == H0 { + // note that in prepare we already called GroupGrow(1) for each agg. + // just fill the result. + for i, ag := range group.ctr.aggList { + if err = ag.BulkFill(0, group.ctr.aggArgEvaluate[i].Vec); err != nil { + return false, err + } + } + return false, nil + } else { + if group.ctr.hr.IsEmpty() { + if err = group.ctr.buildHashTable(proc); err != nil { + return false, err + } + } + + // here is a strange loop. our hash table exposed something called + // hashmap.UnitLimit -- which limits per iteration insert mini batch size. + count := bat.RowCount() + for i := 0; i < count; i += hashmap.UnitLimit { + n := min(count-i, hashmap.UnitLimit) + // we will put rows of mini batch,starting from [i: i+n) into the hash table. + originGroupCount := group.ctr.hr.Hash.GroupCount() + + // insert the mini batch into the hash table. + vals, _, err := group.ctr.hr.Itr.Insert(i, n, group.ctr.groupByEvaluate.Vec) + if err != nil { + return false, err + } + // find out which rows are really inserted, which are grouped with existing. + insertList, _ := group.ctr.hr.GetBinaryInsertList(vals, originGroupCount) + + // append the mini batch to the group by batches, return the number of added + // groups. + more, err := group.ctr.appendGroupByBatch(proc, group.ctr.groupByEvaluate.Vec, i, insertList) + if err != nil { + return false, err + } + + // if more groups were added, grow the aggregators. + if more > 0 { + for _, agg := range group.ctr.aggList { + if err = agg.GroupGrow(more); err != nil { + return false, err + } + } + } + + // do the aggregation + for j, ag := range group.ctr.aggList { + err = ag.BatchFill(i, vals[:n], group.ctr.aggArgEvaluate[j].Vec) + if err != nil { + return false, err + } + } + } // end of mini batch for loop + + // check size + return group.ctr.needSpill(group.OpAnalyzer), nil + } +} + +func (ctr *container) buildHashTable(proc *process.Process) error { + // build hash table + if err := ctr.hr.BuildHashTable(false, + ctr.mtyp == HStr, + ctr.keyNullable, + aggHtPreAllocSize); err != nil { + return err + } + + // pre-allocate groups for each agg. + for _, ag := range ctr.aggList { + if err := ag.PreAllocateGroups(aggHtPreAllocSize); err != nil { + return err + } + } + return nil +} + +func (ctr *container) createNewGroupByBatch(proc *process.Process, vs []*vector.Vector, size int) *batch.Batch { + // initialize the groupByTypes. this is again very bad design. + // types should be resolved at plan time. + if len(ctr.groupByTypes) == 0 { + for _, vec := range vs { + ctr.groupByTypes = append(ctr.groupByTypes, *vec.GetType()) + } + } + + b := batch.NewOffHeapWithSize(len(ctr.groupByTypes)) + for i, typ := range ctr.groupByTypes { + b.Vecs[i] = vector.NewOffHeapVecWithType(typ) + } + b.PreExtend(proc.Mp(), size) + b.SetRowCount(0) + return b +} + +func (ctr *container) appendGroupByBatch( + proc *process.Process, + vs []*vector.Vector, + offset int, + insertList []uint8) (int, error) { + + // first find the target batch. + if len(ctr.groupByBatches) == 0 || + ctr.groupByBatches[len(ctr.groupByBatches)-1].RowCount() >= aggBatchSize { + ctr.groupByBatches = append(ctr.groupByBatches, ctr.createNewGroupByBatch(proc, vs, aggBatchSize)) + } + currBatch := ctr.groupByBatches[len(ctr.groupByBatches)-1] + spaceLeft := aggBatchSize - currBatch.RowCount() + + toIncrease, kth := countNonZeroAndFindKth(insertList, spaceLeft) + if toIncrease == 0 { + // there is nothing in the insertList + return 0, nil + } + + thisTime := insertList + addedRows := toIncrease + if toIncrease > spaceLeft { + thisTime = insertList[:kth+1] + addedRows = spaceLeft + } + + // there is enough space in the current batch to insert thisTime. + for i, vec := range currBatch.Vecs { + err := vec.UnionBatch(vs[i], int64(offset), len(thisTime), thisTime, proc.Mp()) + if err != nil { + return 0, err + } + } + currBatch.AddRowCount(addedRows) + + if toIncrease > spaceLeft { + // there is not enough space in the current batch to insert thisTime. + // so we need to append the rest of the insertList to the next batch. + _, err := ctr.appendGroupByBatch(proc, vs, offset+kth+1, insertList[kth+1:]) + if err != nil { + return 0, err + } + } + return toIncrease, nil +} + +func (group *Group) outputOneBatch(proc *process.Process) (vm.CallResult, error) { + if group.NeedEval { + return group.ctr.outputOneBatchFinal(proc, group.OpAnalyzer, group.Aggs) + } else { + // no need to eval, we are in streaming mode. spill never happen + // here. + res, hasMore, err := group.getNextIntermediateResult(proc) + if err != nil { + return vm.CancelResult, err + } + if !hasMore { + if group.ctr.inputDone { + group.ctr.state = vm.End + } else { + // switch back to build to receive more data. + // reset will set state to vm.Build, which will let us + // process more by Call child. + group.ctr.reset(proc) + } + } + return res, nil + } +} + +func (group *Group) getNextIntermediateResult(proc *process.Process) (vm.CallResult, bool, error) { + // the groupby batches are now in groupbybatches, partial agg result is in agglist. + // now, we need to stream the partial results in the group by batch as aggs. + if group.ctr.currBatchIdx >= len(group.ctr.groupByBatches) { + // done. + return vm.CancelResult, false, nil + } + curr := group.ctr.currBatchIdx + group.ctr.currBatchIdx += 1 + hasMore := group.ctr.currBatchIdx < len(group.ctr.groupByBatches) + + batch := group.ctr.groupByBatches[curr] + + // XXX: serialize aggs to ExtraBuf1, only need to do this for the first + // batch. This really should be set at plan time. + if curr == 0 { + var buf1 bytes.Buffer + buf1.Write(types.EncodeInt32(&group.ctr.mtyp)) + nAggs := int32(len(group.Aggs)) + buf1.Write(types.EncodeInt32(&nAggs)) + if nAggs > 0 { + for _, agExpr := range group.Aggs { + agExpr.MarshalToBuffer(&buf1) + } + } + batch.ExtraBuf1 = buf1.Bytes() + } + + // XXX: Serialize chunk of aggList entries to batch. + // This is also a pretty bad design, we would really like to + // dump group state to a vector and put the vector into the batch. + // But well, + var buf2 bytes.Buffer + nAggs := int32(len(group.ctr.aggList)) + buf2.Write(types.EncodeInt32(&nAggs)) + for _, ag := range group.ctr.aggList { + ag.SaveIntermediateResultOfChunk(curr, &buf2) + } + batch.ExtraBuf2 = buf2.Bytes() + + res := vm.NewCallResult() + res.Batch = batch + return res, hasMore, nil +} + +// given buckets, and a specific bucket, compute the flags for vector union. +func computeChunkFlags(bucketIdx []uint64, bucket uint64, chunkSize int) (int64, [][]uint8) { + // compute the number of chunks, and last chunk size + nChunks := (len(bucketIdx) + chunkSize - 1) / chunkSize + lastChunkSize := len(bucketIdx) - (chunkSize * (nChunks - 1)) + + cnt := int64(0) + flags := make([][]uint8, nChunks) + for i := range flags { + if i+1 == nChunks { + flags[i] = make([]uint8, lastChunkSize) + } else { + flags[i] = make([]uint8, chunkSize) + } + } + + nextX := 0 + nextY := 0 + + for _, idx := range bucketIdx { + if idx == bucket { + flags[nextX][nextY] = 1 + cnt += 1 + } + nextY += 1 + if nextY == chunkSize { + nextX += 1 + nextY = 0 + } + } + return cnt, flags +} diff --git a/pkg/sql/colexec/group/exec_test.go b/pkg/sql/colexec/group/exec_test.go deleted file mode 100644 index 5e53f82e8aef2..0000000000000 --- a/pkg/sql/colexec/group/exec_test.go +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright 2024 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 group - -import ( - "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/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/value_scan" - "github.com/matrixorigin/matrixone/pkg/testutil" - "github.com/matrixorigin/matrixone/pkg/vm" - "github.com/stretchr/testify/require" - "testing" -) - -// hackAggExecToTest 是一个不带任何逻辑的AggExec,主要用于单测中检查各种接口的调用次数。 -type hackAggExecToTest struct { - toFlush int - - aggexec.AggFuncExec - preAllocated int - groupNumber int - doFillRow int - doBulkFillRow int - doBatchFillRow int - doFlushTime int - isFree bool -} - -func (h *hackAggExecToTest) GetOptResult() aggexec.SplitResult { - return nil -} - -func (h *hackAggExecToTest) GroupGrow(more int) error { - h.groupNumber += more - return nil -} - -func (h *hackAggExecToTest) PreAllocateGroups(more int) error { - h.preAllocated += more - return nil -} - -func (h *hackAggExecToTest) Fill(groupIndex int, row int, vectors []*vector.Vector) error { - h.doFillRow++ - return nil -} - -func (h *hackAggExecToTest) BulkFill(groupIndex int, vectors []*vector.Vector) error { - h.doBulkFillRow++ - return nil -} - -func (h *hackAggExecToTest) BatchFill(offset int, groups []uint64, vectors []*vector.Vector) error { - h.doBatchFillRow++ - return nil -} - -var hackVecResult = vector.NewVec(types.T_int64.ToType()) - -func (h *hackAggExecToTest) Flush() ([]*vector.Vector, error) { - h.doFlushTime++ - - ret := make([]*vector.Vector, h.toFlush) - for i := 0; i < h.toFlush; i++ { - ret[i] = hackVecResult - } - return ret, nil -} - -func (h *hackAggExecToTest) Free() { - h.isFree = true -} - -func hackMakeAggToTest(cnt int) (*hackAggExecToTest, func()) { - originalMakeAggExec := makeAggExec - exec := &hackAggExecToTest{ - toFlush: cnt, - } - makeAggExec = func(_ aggexec.AggMemoryManager, _ int64, _ bool, _ ...types.Type) (aggexec.AggFuncExec, error) { - return exec, nil - } - return exec, func() { makeAggExec = originalMakeAggExec } -} - -// Group算子的单元测试需要验证以下内容: -// -// 情况一:Group算子输出最终结果。 -// -// 1. 计算单纯的聚合结果,要求结果为1行且结果正确。 -// 2. 计算分组聚合结果,要求组数正确,结果正确。 -// -// 以上结果都仅输出一次,下一次调用将输出nil结果。 -// -// 情况二:Group算子输出中间结果。 -// -// 1,计算单纯的聚合结果,要求每个聚合只有1个ResultGroup,且没有输出任何group by列。 -// 2. 计算分组聚合结果,要求每个聚合的组数正确,且对应的Agg中间结果正确。 -// -// 单测 以 -// ` select agg(y) from t group by x; ` 为例。 -// 且 t 表数据如下: -// col1 col2 -// 1 1 -// 1 2 -// 2 3 -// 2 4 -// 3 5 -// -// 所有情况都验证以下三种情况的输入: -// 1. batch list : 1, Empty, 2, nil. -// 2. batch list : empty, nil. -// 3. batch list : nil. - -func TestGroup_GetFinalEvaluation_NoneGroupBy(t *testing.T) { - proc := testutil.NewProcess(t) - - // datasource. - { - before := proc.Mp().CurrNB() - - exec, restore := hackMakeAggToTest(1) - defer restore() - datas := []*batch.Batch{ - getGroupTestBatch(proc.Mp(), [][2]int64{ - {1, 1}, - {1, 2}, - {2, 3}, - }), - batch.EmptyBatch, - getGroupTestBatch(proc.Mp(), [][2]int64{ - {2, 4}, - {3, 5}, - }), - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = true - g.Exprs = nil - g.GroupingFlag = nil - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(0)}, nil), - } - - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - var final *batch.Batch - outCnt := 0 - for { - r, err := g.Call(proc) - require.NoError(t, err) - if r.Batch == nil { - break - } - - outCnt++ - final = r.Batch - require.Equal(t, 1, outCnt) - - // result check. - require.NotNil(t, final) - if final != nil { - require.Equal(t, 0, len(final.Aggs)) - require.Equal(t, 1, len(final.Vecs)) - require.Equal(t, hackVecResult, final.Vecs[0]) - } - require.Equal(t, 1, exec.groupNumber) - require.Equal(t, 2, exec.doBulkFillRow) - require.Equal(t, 1, exec.doFlushTime) - } - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - require.Equal(t, true, exec.isFree) - require.Equal(t, before, proc.Mp().CurrNB()) - } - - // datasource is empty. - { - before := proc.Mp().CurrNB() - - exec, restore := hackMakeAggToTest(1) - defer restore() - datas := []*batch.Batch{ - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = true - g.Exprs, g.GroupingFlag = nil, nil - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(0)}, nil), - } - - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - // get the initial result. - r, err := g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 1, b.RowCount()) - require.Equal(t, 1, len(b.Vecs)) - require.Equal(t, hackVecResult, b.Vecs[0]) - require.Equal(t, 0, len(b.Aggs)) - require.Equal(t, 1, exec.doFlushTime) - require.Equal(t, 1, exec.groupNumber) - } - - // next call get the nil - r, err = g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - require.Equal(t, true, exec.isFree) - require.Equal(t, before, proc.Mp().CurrNB()) - } -} - -func TestGroup_GetFinalEvaluation_WithGroupBy(t *testing.T) { - proc := testutil.NewProcess(t) - - // datasource. - { - before := proc.Mp().CurrNB() - - exec, restore := hackMakeAggToTest(1) - defer restore() - datas := []*batch.Batch{ - getGroupTestBatch(proc.Mp(), [][2]int64{ - {1, 1}, - {1, 2}, - {2, 3}, - }), - batch.EmptyBatch, - getGroupTestBatch(proc.Mp(), [][2]int64{ - {2, 4}, - {3, 5}, - }), - nil, - } - - // select x, agg(y) group by x; - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = true - g.GroupingFlag = nil - g.PreAllocSize = 20 - g.Exprs = []*plan.Expr{newColumnExpression(0)} - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(1)}, nil), - } - - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - var final *batch.Batch - outCnt := 0 - for { - r, err := g.Call(proc) - require.NoError(t, err) - if r.Batch == nil { - break - } - - outCnt++ - final = r.Batch - require.Equal(t, 1, outCnt) - - // result check. - require.Equal(t, 20, exec.preAllocated) - require.Equal(t, 3, exec.groupNumber) // 1, 2, 3 - require.Equal(t, 2, exec.doBatchFillRow) - require.Equal(t, 1, exec.doFlushTime) - - require.NotNil(t, final) - if final != nil { - require.Equal(t, 0, len(final.Aggs)) - require.Equal(t, 2, len(final.Vecs)) - require.Equal(t, hackVecResult, final.Vecs[1]) - - gvs := vector.MustFixedColNoTypeCheck[int64](final.Vecs[0]) - require.Equal(t, 3, len(gvs)) - require.Equal(t, int64(1), gvs[0]) - require.Equal(t, int64(2), gvs[1]) - require.Equal(t, int64(3), gvs[2]) - } - } - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - - require.Equal(t, true, exec.isFree) - require.Equal(t, before, proc.Mp().CurrNB()) - } - - // datasource is empty. - { - before := proc.Mp().CurrNB() - exec, restore := hackMakeAggToTest(1) - defer restore() - datas := []*batch.Batch{ - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = true - g.Exprs = []*plan.Expr{newColumnExpression(0)} - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(1)}, nil), - } - - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - r, err := g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - exec.Free() - g.Free(proc, false, nil) - src.Free(proc, false, nil) - require.Equal(t, true, exec.isFree) - require.Equal(t, before, proc.Mp().CurrNB()) - } -} - -func TestGroup_GetIntermediateResult_NoneGroupBy(t *testing.T) { - proc := testutil.NewProcess(t) - intermediateResultSendActionTrigger = 0 - - // datasource. - { - before := proc.Mp().CurrNB() - - exec, restore := hackMakeAggToTest(1) - defer restore() - datas := []*batch.Batch{ - getGroupTestBatch(proc.Mp(), [][2]int64{ - {1, 1}, - {1, 2}, - {2, 3}, - }), - batch.EmptyBatch, - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = false - g.Exprs, g.GroupingFlag = nil, nil - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(0)}, nil), - } - - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - // return intermediate result for datas[0]. - r, err := g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 1, b.RowCount()) - require.Equal(t, 1, len(b.Aggs)) - require.Equal(t, exec, b.Aggs[0]) - require.Equal(t, 0, len(b.Vecs)) - } - - // return nothing for EmptyBatch and return nil. - exec2, restore := hackMakeAggToTest(1) - defer restore() - r, err = g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - exec2.Free() - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - require.Equal(t, true, exec.isFree) - require.Equal(t, true, exec2.isFree) - - require.Equal(t, before, proc.Mp().CurrNB()) - } - - // datasource is empty. - { - before := proc.Mp().CurrNB() - - exec, restore := hackMakeAggToTest(1) - defer restore() - datas := []*batch.Batch{ - batch.EmptyBatch, - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = false - g.Exprs, g.GroupingFlag = nil, nil - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(0)}, nil), - } - - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - // if data source is empty, - // return intermediate result for agg (count is 0, and others are null). - r, err := g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 1, len(b.Aggs)) - require.Equal(t, exec, b.Aggs[0]) - require.Equal(t, 1, exec.groupNumber) - require.Equal(t, 0, exec.doBulkFillRow) - require.Equal(t, 0, exec.doFlushTime) - } - - // next call will get nil. - r, err = g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - require.Equal(t, true, exec.isFree) - - require.Equal(t, before, proc.Mp().CurrNB()) - } -} - -func TestGroup_GetIntermediateResult_WithGroupBy(t *testing.T) { - proc := testutil.NewProcess(t) - intermediateResultSendActionTrigger = 0 - - // datasource. - { - before := proc.Mp().CurrNB() - datas := []*batch.Batch{ - getGroupTestBatch(proc.Mp(), [][2]int64{ - {1, 1}, - {1, 2}, - {2, 3}, - }), - getGroupTestBatch(proc.Mp(), [][2]int64{ - {1, 1}, - {1, 2}, - {2, 3}, - }), - batch.EmptyBatch, - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = false - g.Exprs = []*plan.Expr{newColumnExpression(0)} - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(1)}, nil), - } - - exec, restore := hackMakeAggToTest(1) - defer restore() - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - // get from datas[0] - r, err := g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 1, len(b.Aggs)) - require.Equal(t, exec, b.Aggs[0]) - require.Equal(t, 1, len(b.Vecs)) - require.Equal(t, 2, exec.groupNumber) - require.Equal(t, 1, exec.doBatchFillRow) - require.Equal(t, 0, exec.doFlushTime) - } - - // get from datas[1] - exec2, restore := hackMakeAggToTest(1) - defer restore() - r, err = g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 1, len(b.Aggs)) - require.Equal(t, exec2, b.Aggs[0]) - require.Equal(t, 1, len(b.Vecs)) - require.Equal(t, 2, exec.groupNumber) - require.Equal(t, 1, exec.doBatchFillRow) - require.Equal(t, 0, exec.doFlushTime) - } - - // get from Empty and nil. - r, err = g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - require.Equal(t, true, exec.isFree) - require.Equal(t, true, exec2.isFree) - - require.Equal(t, before, proc.Mp().CurrNB()) - } - - // datasource is empty. - { - before := proc.Mp().CurrNB() - datas := []*batch.Batch{ - batch.EmptyBatch, - nil, - } - g, src := getGroupOperatorWithInputs(datas) - g.NeedEval = false - g.Exprs = []*plan.Expr{newColumnExpression(0)} - g.Aggs = []aggexec.AggFuncExecExpression{ - aggexec.MakeAggFunctionExpression(0, false, []*plan.Expr{newColumnExpression(1)}, nil), - } - - exec, restore := hackMakeAggToTest(1) - defer restore() - require.NoError(t, src.Prepare(proc)) - require.NoError(t, g.Prepare(proc)) - - // get nil if datasource is just empty. - r, err := g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - { - require.Equal(t, 0, exec.doFlushTime) - require.Equal(t, 0, exec.groupNumber) - require.Equal(t, 0, exec.doBatchFillRow) - } - - g.Free(proc, false, nil) - src.Free(proc, false, nil) - exec.Free() - require.Equal(t, true, exec.isFree) - - require.Equal(t, before, proc.Mp().CurrNB()) - } -} - -func getGroupTestBatch(mp *mpool.MPool, values [][2]int64) *batch.Batch { - typ := types.T_int64.ToType() - - first := make([]int64, len(values)) - second := make([]int64, len(values)) - for i := range first { - first[i] = values[i][0] - second[i] = values[i][1] - } - - v1 := testutil.NewInt64Vector(len(values), typ, mp, false, first) - v2 := testutil.NewInt64Vector(len(values), typ, mp, false, second) - - res := batch.NewWithSize(2) - res.Vecs[0], res.Vecs[1] = v1, v2 - res.SetRowCount(len(values)) - return res -} - -func getGroupOperatorWithInputs(dataList []*batch.Batch) (*Group, *value_scan.ValueScan) { - vscan := value_scan.NewArgument() - vscan.Batchs = dataList - - res := &Group{ - OperatorBase: vm.OperatorBase{}, - } - res.AppendChild(vscan) - - return res, vscan -} - -func newColumnExpression(pos int32) *plan.Expr { - return &plan.Expr{ - Typ: plan.Type{Id: int32(types.T_int64)}, - Expr: &plan.Expr_Col{ - Col: &plan.ColRef{ - RelPos: 0, - ColPos: pos, - }, - }, - } -} diff --git a/pkg/sql/colexec/group/execctx.go b/pkg/sql/colexec/group/execctx.go deleted file mode 100644 index 22fc688d8392d..0000000000000 --- a/pkg/sql/colexec/group/execctx.go +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2024 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 group - -import ( - "github.com/matrixorigin/matrixone/pkg/common/hashmap" - "github.com/matrixorigin/matrixone/pkg/common/mpool" - "github.com/matrixorigin/matrixone/pkg/container/batch" - "github.com/matrixorigin/matrixone/pkg/container/vector" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/vm/process" -) - -type ResHashRelated struct { - Hash hashmap.HashMap - Itr hashmap.Iterator - inserted []uint8 -} - -func (hr *ResHashRelated) IsEmpty() bool { - return hr.Hash == nil || hr.Itr == nil -} - -func (hr *ResHashRelated) BuildHashTable( - rebuild bool, - isStrHash bool, keyNullable bool, preAllocated uint64) error { - - if rebuild { - if hr.Hash != nil { - hr.Hash.Free() - hr.Hash = nil - } - } - - if hr.Hash != nil { - return nil - } - - if isStrHash { - h, err := hashmap.NewStrHashMap(keyNullable) - if err != nil { - return err - } - hr.Hash = h - - if hr.Itr == nil { - hr.Itr = h.NewIterator() - } else { - hashmap.IteratorChangeOwner(hr.Itr, hr.Hash) - } - if preAllocated > 0 { - if err = h.PreAlloc(preAllocated); err != nil { - return err - } - } - return nil - } - - h, err := hashmap.NewIntHashMap(keyNullable) - if err != nil { - return err - } - hr.Hash = h - - if hr.Itr == nil { - hr.Itr = h.NewIterator() - } else { - hashmap.IteratorChangeOwner(hr.Itr, hr.Hash) - } - if preAllocated > 0 { - if err = h.PreAlloc(preAllocated); err != nil { - return err - } - } - return nil -} - -func (hr *ResHashRelated) GetBinaryInsertList(vals []uint64, before uint64) (insertList []uint8, insertCount uint64) { - if cap(hr.inserted) < len(vals) { - hr.inserted = make([]uint8, len(vals)) - } else { - hr.inserted = hr.inserted[:len(vals)] - } - - insertCount = hr.Hash.GroupCount() - before - - last := before - for k, val := range vals { - if val > last { - hr.inserted[k] = 1 - last++ - } else { - hr.inserted[k] = 0 - } - } - return hr.inserted, insertCount -} - -func (hr *ResHashRelated) Free0() { - if hr.Hash != nil { - hr.Hash.Free() - hr.Hash = nil - } -} - -type GroupResultBuffer struct { - ChunkSize int - Popped *batch.Batch - ToPopped []*batch.Batch - AggList []aggexec.AggFuncExec -} - -func (buf *GroupResultBuffer) IsEmpty() bool { - return cap(buf.ToPopped) == 0 -} - -func (buf *GroupResultBuffer) InitOnlyAgg(chunkSize int, aggList []aggexec.AggFuncExec) { - aggexec.SyncAggregatorsToChunkSize(aggList, chunkSize) - - buf.ChunkSize = chunkSize - buf.AggList = aggList - buf.ToPopped = make([]*batch.Batch, 0, 1) - buf.ToPopped = append(buf.ToPopped, batch.NewOffHeapEmpty()) -} - -func (buf *GroupResultBuffer) InitWithGroupBy( - mp *mpool.MPool, - chunkSize int, aggList []aggexec.AggFuncExec, groupByVec []*vector.Vector, preAllocated uint64) error { - aggexec.SyncAggregatorsToChunkSize(aggList, chunkSize) - - buf.ChunkSize = chunkSize - buf.AggList = aggList - - if preAllocated > 0 { - fullNum, moreRow := preAllocated/uint64(buf.ChunkSize), preAllocated%uint64(buf.ChunkSize) - for i := uint64(0); i < fullNum; i++ { - vec := getInitialBatchWithSameTypeVecs(groupByVec) - if err := vec.PreExtend(mp, buf.ChunkSize); err != nil { - vec.Clean(mp) - return err - } - buf.ToPopped = append(buf.ToPopped, vec) - } - if moreRow > 0 { - vec := getInitialBatchWithSameTypeVecs(groupByVec) - if err := vec.PreExtend(mp, int(moreRow)); err != nil { - vec.Clean(mp) - return err - } - buf.ToPopped = append(buf.ToPopped, vec) - } - } else { - buf.ToPopped = append(buf.ToPopped, getInitialBatchWithSameTypeVecs(groupByVec)) - } - - buf.ToPopped = buf.ToPopped[:1] - return preExtendAggExecs(buf.AggList, preAllocated) -} - -func (buf *GroupResultBuffer) InitWithBatch(chunkSize int, aggList []aggexec.AggFuncExec, vecExampleBatch *batch.Batch) { - aggexec.SyncAggregatorsToChunkSize(aggList, chunkSize) - - buf.ChunkSize = chunkSize - buf.AggList = aggList - buf.ToPopped = make([]*batch.Batch, 0, 1) - buf.ToPopped = append(buf.ToPopped, getInitialBatchWithSameTypeVecs(vecExampleBatch.Vecs)) -} - -func (buf *GroupResultBuffer) AppendBatch( - mp *mpool.MPool, - vs []*vector.Vector, - offset int, insertList []uint8) (rowIncrease int, err error) { - - spaceNonBatchExpand := buf.ChunkSize - buf.ToPopped[len(buf.ToPopped)-1].RowCount() - toIncrease, k := countNonZeroAndFindKth(insertList, spaceNonBatchExpand) - - if toIncrease == 0 { - return toIncrease, nil - } - - if spaceNonBatchExpand > toIncrease { - if err = buf.unionToSpecificBatch(mp, len(buf.ToPopped)-1, vs, int64(offset), insertList, toIncrease); err != nil { - return toIncrease, err - } - return toIncrease, nil - } - - if err = buf.unionToSpecificBatch(mp, len(buf.ToPopped)-1, vs, int64(offset), insertList[:k+1], spaceNonBatchExpand); err != nil { - return toIncrease, err - } - - if cap(buf.ToPopped) > len(buf.ToPopped) { - buf.ToPopped = buf.ToPopped[:len(buf.ToPopped)+1] - } else { - buf.ToPopped = append(buf.ToPopped, nil) - } - if buf.ToPopped[len(buf.ToPopped)-1] == nil { - buf.ToPopped[len(buf.ToPopped)-1] = getInitialBatchWithSameTypeVecs(vs) - if len(buf.ToPopped) > 4 { - if err = buf.ToPopped[len(buf.ToPopped)-1].PreExtend(mp, buf.ChunkSize); err != nil { - return toIncrease, err - } - } - } - _, err = buf.AppendBatch(mp, vs, offset+k+1, insertList[k+1:]) - - return toIncrease, err -} - -func (buf *GroupResultBuffer) GetAggList() []aggexec.AggFuncExec { - return buf.AggList -} - -func (buf *GroupResultBuffer) unionToSpecificBatch( - mp *mpool.MPool, - idx int, vs []*vector.Vector, offset int64, insertList []uint8, rowIncrease int) error { - for i, vec := range buf.ToPopped[idx].Vecs { - if err := vec.UnionBatch(vs[i], offset, len(insertList), insertList, mp); err != nil { - return err - } - } - buf.ToPopped[idx].AddRowCount(rowIncrease) - return nil -} - -func (buf *GroupResultBuffer) DealPartialResult(partials []any) error { - for i, agg := range buf.AggList { - if len(partials) > i && partials[i] != nil { - if err := agg.SetExtraInformation(partials[i], 0); err != nil { - return err - } - } - } - return nil -} - -func (buf *GroupResultBuffer) PopResult(m *mpool.MPool) (*batch.Batch, error) { - buf.CleanLastPopped(m) - - if len(buf.ToPopped) == 0 { - return nil, nil - } - - if buf.AggList != nil { - for i := range buf.AggList { - vec, err := buf.AggList[i].Flush() - if err != nil { - return nil, err - } - - for j := range vec { - buf.ToPopped[j].Vecs = append(buf.ToPopped[j].Vecs, vec[j]) - } - } - - for i := range buf.AggList { - buf.AggList[i].Free() - } - buf.AggList = nil - } - - buf.Popped = buf.ToPopped[0] - buf.ToPopped = buf.ToPopped[1:] - return buf.Popped, nil -} - -func (buf *GroupResultBuffer) CleanLastPopped(m *mpool.MPool) { - if buf.Popped != nil { - buf.Popped.Clean(m) - buf.Popped = nil - } -} - -func (buf *GroupResultBuffer) Free0(m *mpool.MPool) { - buf.ToPopped = buf.ToPopped[:cap(buf.ToPopped)] - for i := range buf.ToPopped { - if buf.ToPopped[i] != nil { - buf.ToPopped[i].Clean(m) - } - } - for i := range buf.AggList { - if buf.AggList[i] != nil { - buf.AggList[i].Free() - } - } - if buf.Popped != nil { - buf.Popped.Clean(m) - } - - buf.ToPopped, buf.Popped, buf.AggList = nil, nil, nil -} - -type GroupResultNoneBlock struct { - res *batch.Batch -} - -func (r *GroupResultNoneBlock) resetLastPopped() { - if r.res == nil { - return - } - for _, ag := range r.res.Aggs { - if ag != nil { - ag.Free() - } - } - for i := range r.res.Vecs { - r.res.Vecs[i].CleanOnlyData() - } -} - -func (r *GroupResultNoneBlock) getResultBatch( - proc *process.Process, - gEval *ExprEvalVector, - aEval []ExprEvalVector, aExpressions []aggexec.AggFuncExecExpression) (*batch.Batch, error) { - var err error - - // prepare an OK result. - if r.res == nil { - r.res = batch.NewOffHeapWithSize(len(gEval.Typ)) - for i := range r.res.Vecs { - r.res.Vecs[i] = vector.NewOffHeapVecWithType(gEval.Typ[i]) - } - r.res.Aggs = make([]aggexec.AggFuncExec, len(aExpressions)) - } else { - if cap(r.res.Aggs) >= len(aExpressions) { - r.res.Aggs = r.res.Aggs[:len(aExpressions)] - for i := range r.res.Aggs { - r.res.Aggs[i] = nil - } - } else { - r.res.Aggs = make([]aggexec.AggFuncExec, len(aExpressions)) - } - - for i := range r.res.Vecs { - r.res.Vecs[i].ResetWithSameType() - } - r.res.SetRowCount(0) - } - - // set agg. - for i := range r.res.Aggs { - r.res.Aggs[i], err = makeAggExec( - proc, aExpressions[i].GetAggID(), aExpressions[i].IsDistinct(), aEval[i].Typ...) - if err != nil { - return nil, err - } - - if config := aExpressions[i].GetExtraConfig(); config != nil { - if err = r.res.Aggs[i].SetExtraInformation(config, 0); err != nil { - return nil, err - } - } - } - return r.res, nil -} - -func (r *GroupResultNoneBlock) Free0(m *mpool.MPool) { - if r.res != nil { - r.res.Clean(m) - r.res = nil - } -} - -func getInitialBatchWithSameTypeVecs(src []*vector.Vector) *batch.Batch { - b := batch.NewOffHeapWithSize(len(src)) - for i := range b.Vecs { - b.Vecs[i] = vector.NewOffHeapVecWithType(*src[i].GetType()) - } - b.SetRowCount(0) - return b -} - -func countNonZeroAndFindKth(values []uint8, k int) (count int, kth int) { - count = 0 - kth = -1 - if len(values) < k { - for _, v := range values { - if v == 0 { - continue - } - count++ - } - return count, kth - } - - for i, v := range values { - if v == 0 { - continue - } - - count++ - if count == k { - kth = i - break - } - } - - if kth != -1 { - for i := kth + 1; i < len(values); i++ { - if values[i] == 0 { - continue - } - count++ - } - } - return count, kth -} diff --git a/pkg/sql/colexec/group/execctx_test.go b/pkg/sql/colexec/group/execctx_test.go deleted file mode 100644 index beae54fc26893..0000000000000 --- a/pkg/sql/colexec/group/execctx_test.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2024 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 group - -import ( - "github.com/matrixorigin/matrixone/pkg/common/mpool" - "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/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/testutil" - "github.com/stretchr/testify/require" - "testing" -) - -func TestInitGroupResultBuffer(t *testing.T) { - mp := mpool.MustNewZeroNoFixed() - - { - // pre-extend test. - buf := GroupResultBuffer{} - vec := []*vector.Vector{vector.NewVec(types.T_int64.ToType())} - - require.NoError(t, buf.InitWithGroupBy(mp, 256, nil, vec, 3*256+128)) - - require.Equal(t, 3+1, cap(buf.ToPopped)) - - ol := len(buf.ToPopped) - buf.ToPopped = buf.ToPopped[:cap(buf.ToPopped)] - require.Equal(t, 256, buf.ToPopped[0].Vecs[0].Capacity()) - require.Equal(t, 256, buf.ToPopped[1].Vecs[0].Capacity()) - require.Equal(t, 256, buf.ToPopped[2].Vecs[0].Capacity()) - require.Equal(t, 128, buf.ToPopped[3].Vecs[0].Capacity()) - buf.ToPopped = buf.ToPopped[:ol] - - buf.Free0(mp) - } - - require.Equal(t, int64(0), mp.CurrNB()) -} - -func newExpression(pos int32) *plan.Expr { - return &plan.Expr{ - Typ: plan.Type{}, - Expr: &plan.Expr_Col{ - Col: &plan.ColRef{ - ColPos: pos, - }, - }, - } -} - -func TestGetResultBatch(t *testing.T) { - proc := testutil.NewProcessWithMPool(t, "", mpool.MustNewZero()) - invalidAggExpr := aggexec.MakeAggFunctionExpression( - -9999, - false, - []*plan.Expr{newExpression(1)}, - nil, - ) - aEval := []ExprEvalVector{ - { - Typ: []types.Type{types.T_int32.ToType()}, - }, - } - gEval := &ExprEvalVector{ - Typ: []types.Type{types.T_int32.ToType()}, - } - r := &GroupResultNoneBlock{ - res: nil, - } - _, err := r.getResultBatch( - proc, - gEval, - aEval, - []aggexec.AggFuncExecExpression{invalidAggExpr}, - ) - single := aggexec.SingleAggValuesString() - special := aggexec.SpecialAggValuesString() - t.Log(single) - t.Log(special) - t.Log(err) - require.Error(t, err) -} diff --git a/pkg/sql/colexec/group/helper.go b/pkg/sql/colexec/group/helper.go new file mode 100644 index 0000000000000..e6c4eb0dc898f --- /dev/null +++ b/pkg/sql/colexec/group/helper.go @@ -0,0 +1,574 @@ +// Copyright 2024 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 group + +import ( + "bytes" + "fmt" + "io" + + "github.com/google/uuid" + "github.com/matrixorigin/matrixone/pkg/common" + "github.com/matrixorigin/matrixone/pkg/common/hashmap" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/logutil" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" + "github.com/matrixorigin/matrixone/pkg/util/list" + "github.com/matrixorigin/matrixone/pkg/vm" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +type ResHashRelated struct { + Hash hashmap.HashMap + Itr hashmap.Iterator + inserted []uint8 +} + +func (hr *ResHashRelated) IsEmpty() bool { + return hr.Hash == nil || hr.Itr == nil +} + +func (hr *ResHashRelated) BuildHashTable( + rebuild bool, + isStrHash bool, keyNullable bool, preAllocated uint64) error { + + if rebuild { + if hr.Hash != nil { + hr.Hash.Free() + hr.Hash = nil + } + } + + if hr.Hash != nil { + return nil + } + + if isStrHash { + h, err := hashmap.NewStrHashMap(keyNullable) + if err != nil { + return err + } + hr.Hash = h + + if hr.Itr == nil { + hr.Itr = h.NewIterator() + } else { + hashmap.IteratorChangeOwner(hr.Itr, hr.Hash) + } + if preAllocated > 0 { + if err = h.PreAlloc(preAllocated); err != nil { + return err + } + } + return nil + } + + h, err := hashmap.NewIntHashMap(keyNullable) + if err != nil { + return err + } + hr.Hash = h + + if hr.Itr == nil { + hr.Itr = h.NewIterator() + } else { + hashmap.IteratorChangeOwner(hr.Itr, hr.Hash) + } + if preAllocated > 0 { + if err = h.PreAlloc(preAllocated); err != nil { + return err + } + } + return nil +} + +func (hr *ResHashRelated) GetBinaryInsertList(vals []uint64, before uint64) (insertList []uint8, insertCount uint64) { + if cap(hr.inserted) < len(vals) { + hr.inserted = make([]uint8, len(vals)) + } else { + hr.inserted = hr.inserted[:len(vals)] + } + + insertCount = hr.Hash.GroupCount() - before + + last := before + for k, val := range vals { + if val > last { + hr.inserted[k] = 1 + last++ + } else { + hr.inserted[k] = 0 + } + } + return hr.inserted, insertCount +} + +func (hr *ResHashRelated) Free0() { + if hr.Hash != nil { + hr.Hash.Free() + hr.Hash = nil + } +} + +// countNonZeroAndFindKth is a helper function to count the number of non-zero values +// and find index of values, that is the kth non-zero, -1 if there are less than k +// non-zero values. +func countNonZeroAndFindKth(values []uint8, k int) (count int, kth int) { + count = 0 + kth = -1 + if len(values) < k { + for _, v := range values { + if v == 0 { + continue + } + count++ + } + return count, kth + } + + for i, v := range values { + if v == 0 { + continue + } + + count++ + if count == k { + kth = i + break + } + } + + if kth != -1 { + for i := kth + 1; i < len(values); i++ { + if values[i] == 0 { + continue + } + count++ + } + } + return count, kth +} + +func (ctr *container) spillDataToDisk(proc *process.Process, parentBkt *spillBucket) error { + var parentLv int + if parentBkt != nil { + parentLv = parentBkt.lv + } + myLv := parentLv + 1 + + // if current spill bucket is not created, create a new one. + if ctr.currentSpillBkt == nil { + // check parent level, if it is too deep, return error. + // we only allow to spill up to spillMaxPass passes. + // each pass we take spillMaskBits bits from the hashCode, and use them as the index + // to select the spill bucket. Default params, 32^3 = 32768 spill buckets -- if this + // is still not enough, probably we cannot do much anyway, just fail the query. + if parentLv >= spillMaxPass { + return moerr.NewInternalError(proc.Ctx, "spill level too deep") + } + + var parentName string + if parentBkt != nil { + parentName = parentBkt.name + } else { + uuid, _ := uuid.NewV7() + parentName = fmt.Sprintf("spill_%s", uuid.String()) + } + + spillfs, err := proc.GetSpillFileService() + if err != nil { + return err + } + logutil.Infof("spilling data to disk, level %d, parent file %s", myLv, parentName) + // now create the current spill bucket. + ctr.currentSpillBkt = make([]*spillBucket, spillNumBuckets) + for i := range ctr.currentSpillBkt { + ctr.currentSpillBkt[i] = &spillBucket{ + lv: myLv, + name: fmt.Sprintf("%s_%d", parentName, i), + } + + // it is OK to fail here, as all the opened files are tracked by + // current spill bucket, and we will close them all when we clean + // up the operator. + if ctr.currentSpillBkt[i].file, err = spillfs.CreateAndRemoveFile( + proc.Ctx, ctr.currentSpillBkt[i].name); err != nil { + return err + } + } + } + + // nothing to spill, + if ctr.hr.IsEmpty() { + return nil + } + + // compute spill bucket. + hashCodes := ctr.hr.Hash.AllGroupHash() + for i, hashCode := range hashCodes { + hashCodes[i] = (hashCode >> (64 - spillMaskBits*uint64(myLv))) & (spillNumBuckets - 1) + } + + // tmp batch and buffer to write. it is OK to pass in a nil vec, as + // ctr.groupByTypes is already initialized. + gbBatch := ctr.createNewGroupByBatch(proc, nil, aggBatchSize) + defer gbBatch.Clean(proc.Mp()) + buf := bytes.NewBuffer(make([]byte, 0, common.MiB)) + + for i := 0; i < spillNumBuckets; i++ { + buf.Reset() + + cnt, flags := computeChunkFlags(hashCodes, uint64(i), aggBatchSize) + buf.Write(types.EncodeInt64(&cnt)) + if cnt == 0 { + continue + } + + // extend the group by batch to the new size, set row count to 0, then we union + // group by batches to the parent batch. + gbBatch.CleanOnlyData() + gbBatch.PreExtend(proc.Mp(), int(cnt)) + + for nthBatch, gb := range ctr.groupByBatches { + for j := range gb.Vecs { + err := gbBatch.Vecs[j].UnionBatch( + gb.Vecs[j], 0, len(flags[nthBatch]), flags[nthBatch], proc.Mp()) + if err != nil { + return err + } + } + } + // Oh, this API. + gbBatch.SetRowCount(int(cnt)) + // write batch to buf + gbBatch.MarshalBinaryWithBuffer(buf, false) + + // write marker + var magic uint64 = 0x12345678DEADBEEF + buf.Write(types.EncodeInt64(&cnt)) + buf.Write(types.EncodeUint64(&magic)) + + // save aggs to buf + nAggs := int32(len(ctr.aggList)) + buf.Write(types.EncodeInt32(&nAggs)) + for _, ag := range ctr.aggList { + ag.SaveIntermediateResult(cnt, flags, buf) + } + + magic = 0xdeadbeef12345678 + buf.Write(types.EncodeInt64(&cnt)) + buf.Write(types.EncodeUint64(&magic)) + + ctr.currentSpillBkt[i].cnt += cnt + ctr.currentSpillBkt[i].file.Write(buf.Bytes()) + } + + // reset ctr for next spill + ctr.resetForSpill(proc) + return nil +} + +// load spilled data from the spill bucket queue. +func (ctr *container) loadSpilledData(proc *process.Process, opAnalyzer process.Analyzer, aggExprs []aggexec.AggFuncExecExpression) (bool, error) { + // first, if there is current spill bucket, transfer it to the spill bucket queue. + if ctr.currentSpillBkt != nil { + if ctr.spillBkts == nil { + ctr.spillBkts = list.New[*spillBucket]() + } + for _, bkt := range ctr.currentSpillBkt { + ctr.spillBkts.PushBack(bkt) + } + ctr.currentSpillBkt = nil + } + + // then, if there is no spill bucket in the queue, done. + if ctr.spillBkts == nil || ctr.spillBkts.Len() == 0 { + // done + return false, nil + } + + // popped bkt must be defer freed. + bkt := ctr.spillBkts.PopBack().Value + defer bkt.free(proc) + + // reposition to the start of the file. + bkt.file.Seek(0, io.SeekStart) + + // we reset ctr state, and create a new group by batch. + ctr.resetForSpill(proc) + gbBatch := ctr.createNewGroupByBatch(proc, nil, aggBatchSize) + totalCnt := int64(0) + + for { + // load next batch from the spill bucket. + cnt, err := types.ReadInt64(bkt.file) + if err != nil { + if err == io.EOF { + break + } else { + return false, err + } + } + if cnt == 0 { + continue + } + totalCnt += cnt + + if len(ctr.aggList) != len(aggExprs) { + ctr.aggList, err = ctr.makeAggList(proc, aggExprs) + if err != nil { + return false, err + } + } + if len(ctr.spillAggList) != len(aggExprs) { + ctr.spillAggList, err = ctr.makeAggList(proc, aggExprs) + if err != nil { + return false, err + } + } + + // load group by batch from the spill bucket. + gbBatch.CleanOnlyData() + gbBatch.PreExtend(proc.Mp(), int(cnt)) + gbBatch.UnmarshalFromReader(bkt.file, proc.Mp()) + + checkMagic, err := types.ReadUint64(bkt.file) + if err != nil { + return false, err + } + if checkMagic != uint64(cnt) { + return false, moerr.NewInternalError(proc.Ctx, "spill groupby cnt mismatch") + } + + checkMagic, err = types.ReadUint64(bkt.file) + if err != nil { + return false, err + } + if checkMagic != 0x12345678DEADBEEF { + return false, moerr.NewInternalError(proc.Ctx, "spill groupby magic number mismatch") + } + + nAggs, err := types.ReadInt32(bkt.file) + if err != nil { + return false, err + } + if nAggs != int32(len(ctr.spillAggList)) { + return false, moerr.NewInternalError(proc.Ctx, "spill agg cnt mismatch") + } + + // load aggs from the spill bucket. + for _, ag := range ctr.spillAggList { + ag.UnmarshalFromReader(bkt.file, proc.Mp()) + } + + checkMagic, err = types.ReadUint64(bkt.file) + if err != nil { + return false, err + } + if checkMagic != uint64(cnt) { + return false, moerr.NewInternalError(proc.Ctx, "spill agg cnt mismatch") + } + + checkMagic, err = types.ReadUint64(bkt.file) + if err != nil { + return false, err + } + if checkMagic != 0xDEADBEEF12345678 { + return false, moerr.NewInternalError(proc.Ctx, "spill agg magic number mismatch") + } + + if ctr.hr.IsEmpty() { + if err = ctr.buildHashTable(proc); err != nil { + return false, err + } + } + + // insert group by batch into the hash table. + rowCount := gbBatch.RowCount() + for i := 0; i < rowCount; i += hashmap.UnitLimit { + n := min(rowCount-i, hashmap.UnitLimit) + originGroupCount := ctr.hr.Hash.GroupCount() + vals, _, err := ctr.hr.Itr.Insert(i, n, gbBatch.Vecs) + if err != nil { + return false, err + } + insertList, _ := ctr.hr.GetBinaryInsertList(vals, originGroupCount) + more, err := ctr.appendGroupByBatch(proc, gbBatch.Vecs, i, insertList) + if err != nil { + return false, err + } + + if len(ctr.aggList) == 0 { + continue + } + if more > 0 { + for j := range ctr.aggList { + if err := ctr.aggList[j].GroupGrow(more); err != nil { + return false, err + } + } + } + + for j, ag := range ctr.aggList { + if err := ag.BatchMerge(ctr.spillAggList[j], i, vals[:len(insertList)]); err != nil { + return false, err + } + } + } + + if ctr.needSpill(opAnalyzer) { + if err := ctr.spillDataToDisk(proc, bkt); err != nil { + return false, err + } + + } + } + + // respilling happened, so we finish the last batch and recursive down + if ctr.isSpilling() { + if err := ctr.spillDataToDisk(proc, bkt); err != nil { + return false, err + } + return ctr.loadSpilledData(proc, opAnalyzer, aggExprs) + } + + return true, nil +} + +func (ctr *container) getNextFinalResult(proc *process.Process) (vm.CallResult, error) { + // the groupby batches are now in groupbybatches, partial agg result is in agglist. + // now we need to flush the final result of agg to output batches. + if ctr.currBatchIdx >= len(ctr.groupByBatches) || + (ctr.currBatchIdx == len(ctr.groupByBatches)-1 && + ctr.groupByBatches[ctr.currBatchIdx].RowCount() == 0) { + // exhauseed all batches, or, last group by batch has no data, + // done. + return vm.CancelResult, nil + } + + curr := ctr.currBatchIdx + ctr.currBatchIdx += 1 + + if curr == 0 { + // flush aggs final result to vectors, all aggs follow groupby columns. + for _, ag := range ctr.aggList { + vecs, err := ag.Flush() + if err != nil { + return vm.CancelResult, err + } + for j := range vecs { + ctr.groupByBatches[j].Vecs = append( + ctr.groupByBatches[j].Vecs, vecs[j]) + } + } + } + + // get the groupby batch + batch := ctr.groupByBatches[curr] + res := vm.NewCallResult() + res.Batch = batch + return res, nil +} + +func (ctr *container) outputOneBatchFinal(proc *process.Process, opAnalyzer process.Analyzer, aggExprs []aggexec.AggFuncExecExpression) (vm.CallResult, error) { + // read next result batch + res, err := ctr.getNextFinalResult(proc) + if err != nil { + return vm.CancelResult, err + } + + // or should we check res.Status == vm.ExecStop + if res.Batch != nil { + return res, nil + } + + loaded, err := ctr.loadSpilledData(proc, opAnalyzer, aggExprs) + if err != nil { + return vm.CancelResult, err + } + if loaded { + return ctr.outputOneBatchFinal(proc, opAnalyzer, aggExprs) + } + return res, nil +} + +func (ctr *container) memUsed() int64 { + var memUsed int64 + + // group by + for _, b := range ctr.groupByBatches { + memUsed += int64(b.Size()) + } + // times 2, so that roughly we have the hashtable size. + memUsed *= 2 + + // aggs + for _, ag := range ctr.aggList { + memUsed += ag.Size() + } + return memUsed +} + +func (ctr *container) needSpill(opAnalyzer process.Analyzer) bool { + + memUsed := ctr.memUsed() + opAnalyzer.SetMemUsed(memUsed) + + // spill less than 10K, used only for debug. + // in this case, we spill when there are more than + // this many groups + var needSpill bool + if ctr.spillMem < 10000 { + needSpill = ctr.hr.Hash.GroupCount() >= uint64(ctr.spillMem) + } else { + needSpill = memUsed > ctr.spillMem + } + + if needSpill { + opAnalyzer.Spill(memUsed) + } + return needSpill +} + +func (ctr *container) makeAggList(proc *process.Process, aggExprs []aggexec.AggFuncExecExpression) ([]aggexec.AggFuncExec, error) { + var err error + aggList := make([]aggexec.AggFuncExec, len(aggExprs)) + for i, agExpr := range aggExprs { + typs := make([]types.Type, len(agExpr.GetArgExpressions())) + for j, arg := range agExpr.GetArgExpressions() { + typs[j] = types.New(types.T(arg.Typ.Id), arg.Typ.Width, arg.Typ.Scale) + } + aggList[i], err = aggexec.MakeAgg(proc, agExpr.GetAggID(), agExpr.IsDistinct(), typs...) + if err != nil { + return nil, err + } + if config := agExpr.GetExtraConfig(); config != nil { + if err := aggList[i].SetExtraInformation(config, 0); err != nil { + return nil, err + } + } + if ctr.mtyp == H0 { + if err := aggList[i].GroupGrow(1); err != nil { + return nil, err + } + } + } + + if ctr.mtyp != H0 { + aggexec.SyncAggregatorsToChunkSize(aggList, aggBatchSize) + } + return aggList, nil +} diff --git a/pkg/sql/colexec/group/mergeGroup.go b/pkg/sql/colexec/group/mergeGroup.go new file mode 100644 index 0000000000000..0b01c72ade2a5 --- /dev/null +++ b/pkg/sql/colexec/group/mergeGroup.go @@ -0,0 +1,229 @@ +// Copyright 2025 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 group + +import ( + "bytes" + + "github.com/matrixorigin/matrixone/pkg/common/hashmap" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/container/batch" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" + "github.com/matrixorigin/matrixone/pkg/vm" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +func (mergeGroup *MergeGroup) Prepare(proc *process.Process) error { + mergeGroup.ctr.state = vm.Build + if mergeGroup.OpAnalyzer != nil { + mergeGroup.OpAnalyzer.Reset() + } + mergeGroup.OpAnalyzer = process.NewAnalyzer(mergeGroup.GetIdx(), mergeGroup.IsFirst, mergeGroup.IsLast, "merge_group") + + if err := mergeGroup.PrepareProjection(proc); err != nil { + return err + } + mergeGroup.ctr.setSpillMem(mergeGroup.SpillMem, mergeGroup.Aggs) + return nil +} + +func (mergeGroup *MergeGroup) Call(proc *process.Process) (vm.CallResult, error) { + if err, isCancel := vm.CancelCheck(proc); isCancel { + return vm.CancelResult, err + } + + mergeGroup.OpAnalyzer.Start() + defer mergeGroup.OpAnalyzer.Stop() + + switch mergeGroup.ctr.state { + case vm.Build: + // receive data and merge. + for !mergeGroup.ctr.inputDone { + r, err := vm.ChildrenCall(mergeGroup.GetChildren(0), proc, mergeGroup.OpAnalyzer) + if err != nil { + return vm.CancelResult, err + } + + // all handled, going to eval mode. + // + // XXX: Note that this test, r.Batch == nil is treated as ExecStop. + // if r.Status == vm.ExecStop || r.Batch == nil { + if r.Batch == nil { + mergeGroup.ctr.state = vm.Eval + mergeGroup.ctr.inputDone = true + } + + // empty batch, skip. + if r.Batch == nil || r.Batch.IsEmpty() { + continue + } + + needSpill, err := mergeGroup.buildOneBatch(proc, r.Batch) + if err != nil { + return vm.CancelResult, err + } + + if needSpill { + mergeGroup.ctr.spillDataToDisk(proc, nil) + } + } + + // has partial results, merge them. + if mergeGroup.PartialResults != nil { + for i, ag := range mergeGroup.ctr.aggList { + if len(mergeGroup.PartialResults) > i && mergeGroup.PartialResults[i] != nil { + if err := ag.SetExtraInformation(mergeGroup.PartialResults[i], 0); err != nil { + return vm.CancelResult, err + } + } + } + } + + if mergeGroup.ctr.isSpilling() { + if err := mergeGroup.ctr.spillDataToDisk(proc, nil); err != nil { + return vm.CancelResult, err + } + if _, err := mergeGroup.ctr.loadSpilledData(proc, mergeGroup.OpAnalyzer, mergeGroup.Aggs); err != nil { + return vm.CancelResult, err + } + } + + // output the final result. + return mergeGroup.ctr.outputOneBatchFinal(proc, mergeGroup.OpAnalyzer, mergeGroup.Aggs) + + case vm.Eval: + return mergeGroup.ctr.outputOneBatchFinal(proc, mergeGroup.OpAnalyzer, mergeGroup.Aggs) + case vm.End: + return vm.CancelResult, nil + } + return vm.CancelResult, moerr.NewInternalError(proc.Ctx, "bug: unknown merge group state") +} + +func (mergeGroup *MergeGroup) buildOneBatch(proc *process.Process, bat *batch.Batch) (bool, error) { + var err error + + // lower send me a batch with extra buf1, + // which contains the aggregation expressions. + if len(bat.ExtraBuf1) != 0 { + // but mergeGroup has not build Aggs yet, so we need to build it. + // This info really should be set during query planning and prepare. + // We screwed up, so deal with it. + reader := bytes.NewReader(bat.ExtraBuf1) + if mergeGroup.ctr.mtyp, err = types.ReadInt32(reader); err != nil { + return false, err + } + + if mergeGroup.ctr.mtyp == H0 { + if len(mergeGroup.ctr.groupByBatches) == 0 { + gb := mergeGroup.ctr.createNewGroupByBatch(proc, bat.Vecs, 1) + gb.SetRowCount(1) + mergeGroup.ctr.groupByBatches = append(mergeGroup.ctr.groupByBatches, gb) + } + } + + nAggs, err := types.ReadInt32(reader) + if err != nil { + return false, err + } + if nAggs > 0 && len(mergeGroup.Aggs) == 0 { + for i := int32(0); i < nAggs; i++ { + agExpr := aggexec.AggFuncExecExpression{} + if err := agExpr.UnmarshalFromReader(reader); err != nil { + return false, err + } + mergeGroup.Aggs = append(mergeGroup.Aggs, agExpr) + } + mergeGroup.ctr.setSpillMem(mergeGroup.SpillMem, mergeGroup.Aggs) + + if mergeGroup.ctr.aggList, err = mergeGroup.ctr.makeAggList(proc, mergeGroup.Aggs); err != nil { + return false, err + } + if mergeGroup.ctr.spillAggList, err = mergeGroup.ctr.makeAggList(proc, mergeGroup.Aggs); err != nil { + return false, err + } + } + } + + // deserialize extra buf2. + if len(bat.ExtraBuf2) != 0 { + var nAggs int32 + r := bytes.NewReader(bat.ExtraBuf2) + nAggs, err := types.ReadInt32(r) + if err != nil { + return false, err + } + if int(nAggs) != len(mergeGroup.ctr.spillAggList) { + return false, moerr.NewInternalError(proc.Ctx, "nAggs != len(mergeGroup.ctr.spillAggList)") + } + + for i := int32(0); i < nAggs; i++ { + ag := mergeGroup.ctr.spillAggList[i] + if err := ag.UnmarshalFromReader(r, proc.Mp()); err != nil { + return false, err + } + } + } + + // merge intermedia results with only Aggregation. + if len(bat.Vecs) == 0 { + // no group by columns, group grow 1 for each agg. + for i := range mergeGroup.ctr.aggList { + if err := mergeGroup.ctr.aggList[i].Merge(mergeGroup.ctr.spillAggList[i], 0, 0); err != nil { + return false, err + } + } + } else { + if mergeGroup.ctr.hr.IsEmpty() { + if err := mergeGroup.ctr.buildHashTable(proc); err != nil { + return false, err + } + } + + rowCount := bat.RowCount() + for i := 0; i < rowCount; i += hashmap.UnitLimit { + n := min(rowCount-i, hashmap.UnitLimit) + + originGroupCount := mergeGroup.ctr.hr.Hash.GroupCount() + vals, _, err := mergeGroup.ctr.hr.Itr.Insert(i, n, bat.Vecs) + if err != nil { + return false, err + } + insertList, _ := mergeGroup.ctr.hr.GetBinaryInsertList(vals, originGroupCount) + more, err := mergeGroup.ctr.appendGroupByBatch(proc, bat.Vecs, i, insertList) + if err != nil { + return false, err + } + + if len(mergeGroup.ctr.aggList) == 0 { + continue + } + if more > 0 { + for j := range mergeGroup.ctr.aggList { + if err := mergeGroup.ctr.aggList[j].GroupGrow(more); err != nil { + return false, err + } + } + } + for j, ag := range mergeGroup.ctr.aggList { + if err := ag.BatchMerge(mergeGroup.ctr.spillAggList[j], i, vals[:len(insertList)]); err != nil { + return false, err + } + } + } + } + + return mergeGroup.ctr.needSpill(mergeGroup.OpAnalyzer), nil +} diff --git a/pkg/sql/colexec/group/types.go b/pkg/sql/colexec/group/types.go deleted file mode 100644 index e34d9aff38333..0000000000000 --- a/pkg/sql/colexec/group/types.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright 2024 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 group - -import ( - "github.com/matrixorigin/matrixone/pkg/common/mpool" - "github.com/matrixorigin/matrixone/pkg/common/reuse" - "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/sql/colexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/vm" - "github.com/matrixorigin/matrixone/pkg/vm/process" -) - -const ( - H0 = iota - H8 - HStr -) - -const ( - thisOperatorName = "group" -) - -type ExprEvalVector struct { - Executor []colexec.ExpressionExecutor - Vec []*vector.Vector - Typ []types.Type -} - -func MakeEvalVector(proc *process.Process, expressions []*plan.Expr) (ev ExprEvalVector, err error) { - if len(expressions) == 0 { - return - } - - ev.Executor, err = colexec.NewExpressionExecutorsFromPlanExpressions(proc, expressions) - if err != nil { - return - } - ev.Vec = make([]*vector.Vector, len(ev.Executor)) - ev.Typ = make([]types.Type, len(ev.Executor)) - for i, expr := range expressions { - ev.Typ[i] = types.New(types.T(expr.Typ.Id), expr.Typ.Width, expr.Typ.Scale) - } - return -} - -func (ev *ExprEvalVector) Free() { - for i := range ev.Executor { - if ev.Executor[i] != nil { - ev.Executor[i].Free() - } - } -} - -func (ev *ExprEvalVector) ResetForNextQuery() { - for i := range ev.Executor { - if ev.Executor[i] != nil { - ev.Executor[i].ResetForNextQuery() - } - } -} - -var _ vm.Operator = &Group{} - -// Group -// the group operator using new implement. -type Group struct { - vm.OperatorBase - colexec.Projection - - ctr container - NeedEval bool - PreAllocSize uint64 - SpillMem int64 - - // group-by column. - Exprs []*plan.Expr - GroupingFlag []bool - // agg info and agg column. - Aggs []aggexec.AggFuncExecExpression -} - -func (group *Group) evaluateGroupByAndAgg(proc *process.Process, bat *batch.Batch) (err error) { - input := []*batch.Batch{bat} - - // group. - for i := range group.ctr.groupByEvaluate.Vec { - if group.ctr.groupByEvaluate.Vec[i], err = group.ctr.groupByEvaluate.Executor[i].Eval(proc, input, nil); err != nil { - return err - } - } - - // agg. - for i := range group.ctr.aggregateEvaluate { - for j := range group.ctr.aggregateEvaluate[i].Vec { - if group.ctr.aggregateEvaluate[i].Vec[j], err = group.ctr.aggregateEvaluate[i].Executor[j].Eval(proc, input, nil); err != nil { - return err - } - } - } - - // grouping flag. - for i, flag := range group.GroupingFlag { - if !flag { - group.ctr.groupByEvaluate.Vec[i] = vector.NewRollupConst(group.ctr.groupByEvaluate.Typ[i], group.ctr.groupByEvaluate.Vec[i].Length(), proc.Mp()) - } - } - - return nil -} - -func (group *Group) AnyDistinctAgg() bool { - for _, agg := range group.Aggs { - if agg.IsDistinct() { - return true - } - } - return false -} - -func (group *Group) ExecProjection(proc *process.Process, input *batch.Batch) (*batch.Batch, error) { - if group.ProjectList == nil { - return input, nil - } - return group.EvalProjection(input, proc) -} - -// container -// running context. -type container struct { - state vm.CtrState - dataSourceIsEmpty bool - - // hash. - hr ResHashRelated - mtyp int - keyWidth int - keyNullable bool - - // x, y of `group by x, y`. - // m, n of `select agg1(m, n), agg2(m, n)`. - groupByEvaluate ExprEvalVector - aggregateEvaluate []ExprEvalVector - - // result if NeedEval is true. - result1 GroupResultBuffer - // result if NeedEval is false. - result2 GroupResultNoneBlock -} - -func (ctr *container) isDataSourceEmpty() bool { - return ctr.dataSourceIsEmpty -} - -func (group *Group) Free(proc *process.Process, _ bool, _ error) { - group.freeCannotReuse(proc.Mp()) - - group.ctr.freeGroupEvaluate() - group.ctr.freeAggEvaluate() - group.FreeProjection(proc) -} - -func (group *Group) Reset(proc *process.Process, pipelineFailed bool, err error) { - group.freeCannotReuse(proc.Mp()) - - group.ctr.groupByEvaluate.ResetForNextQuery() - for i := range group.ctr.aggregateEvaluate { - group.ctr.aggregateEvaluate[i].ResetForNextQuery() - } - group.ResetProjection(proc) -} - -func (group *Group) freeCannotReuse(mp *mpool.MPool) { - group.ctr.hr.Free0() - group.ctr.result1.Free0(mp) - group.ctr.result2.Free0(mp) -} - -func (ctr *container) freeAggEvaluate() { - for i := range ctr.aggregateEvaluate { - ctr.aggregateEvaluate[i].Free() - } - ctr.aggregateEvaluate = nil -} - -func (ctr *container) freeGroupEvaluate() { - ctr.groupByEvaluate.Free() - ctr.groupByEvaluate = ExprEvalVector{} -} - -func (group *Group) OpType() vm.OpType { - return vm.Group -} - -func (group Group) TypeName() string { - return thisOperatorName -} - -func (group *Group) GetOperatorBase() *vm.OperatorBase { - return &group.OperatorBase -} - -func init() { - reuse.CreatePool( - func() *Group { - return &Group{} - }, - func(a *Group) { - *a = Group{} - }, - reuse.DefaultOptions[Group](). - WithEnableChecker(), - ) -} - -func NewArgument() *Group { - return reuse.Alloc[Group](nil) -} - -func (group *Group) Release() { - if group != nil { - reuse.Free(group, nil) - } -} diff --git a/pkg/sql/colexec/group/types2.go b/pkg/sql/colexec/group/types2.go new file mode 100644 index 0000000000000..d9f26448fcf05 --- /dev/null +++ b/pkg/sql/colexec/group/types2.go @@ -0,0 +1,402 @@ +// Copyright 2024 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 group + +import ( + "bytes" + "fmt" + "os" + + "github.com/matrixorigin/matrixone/pkg/common" + "github.com/matrixorigin/matrixone/pkg/common/reuse" + "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/sql/colexec" + "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/util/list" + "github.com/matrixorigin/matrixone/pkg/vm" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +const ( + H0 = iota + H8 + HStr +) + +const ( + thisOperatorName = "group" +) + +var _ vm.Operator = &Group{} + +// Group +// the group operator using new implement. +type Group struct { + vm.OperatorBase + colexec.Projection + + ctr container + NeedEval bool + SpillMem int64 + + // group-by column. + Exprs []*plan.Expr + GroupingFlag []bool + + Aggs []aggexec.AggFuncExecExpression +} + +type spillBucket struct { + lv int // spill level + name string // spill bucket name + cnt int64 // number of rows in this spill bucket + file *os.File // spill file +} + +func (bkt *spillBucket) free(proc *process.Process) { + if bkt != nil && bkt.file != nil { + bkt.file.Close() + bkt.file = nil + } +} + +// container running context. +type container struct { + state vm.CtrState + inputDone bool + currBatchIdx int + + // hash. + hr ResHashRelated + mtyp int32 + keyWidth int32 + keyNullable bool + + // x, y of `group by x, y`. + groupByEvaluate colexec.ExprEvalVector + // m, n of `select agg1(m, n), agg2(m, n)`. + aggArgEvaluate []colexec.ExprEvalVector + + // group by columns + groupByTypes []types.Type + groupByBatches []*batch.Batch + + // aggs, which holds the intermediate state of agg functions. + aggList []aggexec.AggFuncExec + + // spill, agglist to load spilled data. + spillMem int64 + spillAggList []aggexec.AggFuncExec + spillBkts list.Deque[*spillBucket] + currentSpillBkt []*spillBucket +} + +func (ctr *container) isSpilling() bool { + return len(ctr.currentSpillBkt) > 0 +} + +func (ctr *container) setSpillMem(m int64, aggs []aggexec.AggFuncExecExpression) { + // BUG #22725 + // We simply cannot spill distinct agg at this moment. + for _, ag := range aggs { + if ag.IsDistinct() { + // Set to TiB, effectively disabling spill for distinct agg. + // If we cannot fix this before TB mem is commonly available + // it will be very sad. + ctr.spillMem = common.TiB + return + } + } + if m == 0 { + ctr.spillMem = common.GiB + } else { + ctr.spillMem = m + } +} + +func (ctr *container) freeAggList(proc *process.Process) { + for i := range ctr.aggList { + if ctr.aggList[i] != nil { + ctr.aggList[i].Free() + ctr.aggList[i] = nil + } + } + ctr.aggList = nil + + for i := range ctr.spillAggList { + if ctr.spillAggList[i] != nil { + ctr.spillAggList[i].Free() + ctr.spillAggList[i] = nil + } + } + ctr.spillAggList = nil +} + +func (ctr *container) freeSpillBkts(proc *process.Process) { + // free all spill buckets. + if ctr.spillBkts != nil { + ctr.spillBkts.Iter(0, func(bkt *spillBucket) bool { + bkt.free(proc) + return true + }) + ctr.spillBkts.Clear() + } + + for _, bkt := range ctr.currentSpillBkt { + bkt.free(proc) + } + ctr.currentSpillBkt = nil +} + +func (ctr *container) freeGroupByBatches(proc *process.Process) { + for i := range ctr.groupByBatches { + if ctr.groupByBatches[i] != nil { + ctr.groupByBatches[i].Clean(proc.Mp()) + ctr.groupByBatches[i] = nil + } + } + ctr.groupByBatches = nil + ctr.currBatchIdx = 0 +} + +func (ctr *container) free(proc *process.Process) { + // free container stuff, WTH is the Free0? + ctr.inputDone = false + ctr.hr.Free0() + + ctr.groupByEvaluate.Free() + + for i := range ctr.aggArgEvaluate { + ctr.aggArgEvaluate[i].Free() + } + ctr.aggArgEvaluate = nil + + ctr.freeGroupByBatches(proc) + ctr.freeAggList(proc) + ctr.freeSpillBkts(proc) +} + +func (ctr *container) reset(proc *process.Process) { + ctr.state = vm.Build + ctr.inputDone = false + ctr.resetForSpill(proc) + ctr.freeSpillBkts(proc) +} + +func (ctr *container) resetForSpill(proc *process.Process) { + // Reset also frees the hash related stuff. + ctr.hr.Free0() + + ctr.groupByEvaluate.ResetForNextQuery() + + for i := range ctr.aggArgEvaluate { + ctr.aggArgEvaluate[i].ResetForNextQuery() + } + // free group by batches, agg list and spill buckets, do not reuse for now. + ctr.freeGroupByBatches(proc) + ctr.currBatchIdx = 0 + + ctr.freeAggList(proc) +} + +func (group *Group) evaluateGroupByAndAggArgs(proc *process.Process, bat *batch.Batch) (err error) { + input := []*batch.Batch{bat} + + // group. + for i := range group.ctr.groupByEvaluate.Vec { + if group.ctr.groupByEvaluate.Vec[i], err = + group.ctr.groupByEvaluate.Executor[i].Eval(proc, input, nil); err != nil { + return err + } + } + + // agg args. + for i := range group.ctr.aggArgEvaluate { + for j := range group.ctr.aggArgEvaluate[i].Vec { + if group.ctr.aggArgEvaluate[i].Vec[j], err = + group.ctr.aggArgEvaluate[i].Executor[j].Eval(proc, input, nil); err != nil { + return err + } + } + } + + // grouping flag + for i, flag := range group.GroupingFlag { + if !flag { + group.ctr.groupByEvaluate.Vec[i] = vector.NewRollupConst( + group.ctr.groupByEvaluate.Typ[i], + group.ctr.groupByEvaluate.Vec[i].Length(), + proc.Mp()) + } + } + + return nil +} + +func (group *Group) AnyDistinctAgg() bool { + for _, agg := range group.Aggs { + if agg.IsDistinct() { + return true + } + } + return false +} + +func (group *Group) ExecProjection(proc *process.Process, input *batch.Batch) (*batch.Batch, error) { + if group.ProjectList == nil { + return input, nil + } + return group.EvalProjection(input, proc) +} + +func (group *Group) Free(proc *process.Process, _ bool, _ error) { + group.ctr.free(proc) + // free projection stuff, + group.FreeProjection(proc) +} + +func (group *Group) Reset(proc *process.Process, pipelineFailed bool, err error) { + group.ctr.reset(proc) + group.ResetProjection(proc) +} + +func (group *Group) OpType() vm.OpType { + return vm.Group +} + +func (group Group) TypeName() string { + return thisOperatorName +} + +func (group *Group) GetOperatorBase() *vm.OperatorBase { + return &group.OperatorBase +} + +func NewArgument() *Group { + return reuse.Alloc[Group](nil) +} + +func (group *Group) Release() { + if group != nil { + reuse.Free(group, nil) + } +} + +func (group *Group) String(buf *bytes.Buffer) { + buf.WriteString(thisOperatorName + ": group([") + for i, expr := range group.Exprs { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(fmt.Sprintf("%v", expr)) + } + buf.WriteString("], [") + + for i, ag := range group.Aggs { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(fmt.Sprintf("%v(%v)", function.GetAggFunctionNameByID(ag.GetAggID()), ag.GetArgExpressions())) + } + buf.WriteString("])") +} + +const ( + mergeGroupOperatorName = "merge_group" +) + +type MergeGroup struct { + vm.OperatorBase + colexec.Projection + + ctr container + SpillMem int64 + + Aggs []aggexec.AggFuncExecExpression + + PartialResults []any + PartialResultTypes []types.T +} + +func (mergeGroup *MergeGroup) ExecProjection(proc *process.Process, input *batch.Batch) (*batch.Batch, error) { + if mergeGroup.ProjectList == nil { + return input, nil + } + return mergeGroup.EvalProjection(input, proc) +} + +func (mergeGroup *MergeGroup) Reset(proc *process.Process, _ bool, _ error) { + mergeGroup.ctr.reset(proc) + mergeGroup.ResetProjection(proc) +} + +func (mergeGroup *MergeGroup) Free(proc *process.Process, _ bool, _ error) { + mergeGroup.ctr.free(proc) + mergeGroup.FreeProjection(proc) +} + +func (mergeGroup *MergeGroup) GetOperatorBase() *vm.OperatorBase { + return &mergeGroup.OperatorBase +} + +func (mergeGroup *MergeGroup) OpType() vm.OpType { + return vm.MergeGroup +} + +func (mergeGroup MergeGroup) TypeName() string { + return mergeGroupOperatorName +} + +func (mergeGroup *MergeGroup) String(buf *bytes.Buffer) { + buf.WriteString(mergeGroupOperatorName) +} + +func NewArgumentMergeGroup() *MergeGroup { + return reuse.Alloc[MergeGroup](nil) +} + +func (mergeGroup *MergeGroup) Release() { + if mergeGroup != nil { + reuse.Free(mergeGroup, nil) + } +} + +func init() { + reuse.CreatePool( + func() *Group { + return &Group{} + }, + func(a *Group) { + *a = Group{} + }, + reuse.DefaultOptions[Group](). + WithEnableChecker(), + ) + + reuse.CreatePool( + func() *MergeGroup { + return &MergeGroup{} + }, + func(a *MergeGroup) { + *a = MergeGroup{} + }, + reuse.DefaultOptions[MergeGroup](). + WithEnableChecker(), + ) +} diff --git a/pkg/sql/colexec/mergegroup/exec.go b/pkg/sql/colexec/mergegroup/exec.go deleted file mode 100644 index cd91238966e3a..0000000000000 --- a/pkg/sql/colexec/mergegroup/exec.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2024 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 mergegroup - -import ( - "bytes" - "math" - - "github.com/matrixorigin/matrixone/pkg/common/hashmap" - "github.com/matrixorigin/matrixone/pkg/container/batch" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/group" - "github.com/matrixorigin/matrixone/pkg/vm" - "github.com/matrixorigin/matrixone/pkg/vm/process" -) - -var makeInitialAggListFromList = aggexec.MakeInitialAggListFromList - -func (mergeGroup *MergeGroup) String(buf *bytes.Buffer) { - buf.WriteString(thisOperatorName) -} - -func (mergeGroup *MergeGroup) Prepare(proc *process.Process) error { - mergeGroup.ctr.state = vm.Build - mergeGroup.prepareAnalyzer() - return mergeGroup.prepareProjection(proc) -} - -func (mergeGroup *MergeGroup) prepareAnalyzer() { - if mergeGroup.OpAnalyzer != nil { - mergeGroup.OpAnalyzer.Reset() - return - } - mergeGroup.OpAnalyzer = process.NewAnalyzer(mergeGroup.GetIdx(), mergeGroup.IsFirst, mergeGroup.IsLast, "merge_group") -} - -func (mergeGroup *MergeGroup) prepareProjection(proc *process.Process) error { - if mergeGroup.ProjectList != nil { - err := mergeGroup.PrepareProjection(proc) - if err != nil { - return err - } - } - return nil -} - -func (mergeGroup *MergeGroup) Call(proc *process.Process) (vm.CallResult, error) { - if err, isCancel := vm.CancelCheck(proc); isCancel { - return vm.CancelResult, err - } - mergeGroup.OpAnalyzer.Start() - defer mergeGroup.OpAnalyzer.Stop() - - for { - switch mergeGroup.ctr.state { - case vm.Build: - // receive data and merge. - for { - b, err := mergeGroup.getInputBatch(proc) - if err != nil { - return vm.CancelResult, err - } - if b == nil { - break - } - if b.IsEmpty() { - continue - } - - if err = mergeGroup.consumeBatch(proc, b); err != nil { - return vm.CancelResult, err - } - } - if err := mergeGroup.ctr.result.DealPartialResult(mergeGroup.PartialResults); err != nil { - return vm.CancelResult, err - } - mergeGroup.ctr.state = vm.Eval - - case vm.Eval: - // output result. - mergeGroup.ctr.result.CleanLastPopped(proc.Mp()) - - if mergeGroup.ctr.result.IsEmpty() { - mergeGroup.ctr.state = vm.End - continue - } - - b, err := mergeGroup.ctr.result.PopResult(proc.Mp()) - if err != nil { - return vm.CancelResult, err - } - result := vm.NewCallResult() - result.Batch = b - mergeGroup.OpAnalyzer.Output(b) - return result, nil - - default: - // END status. - result := vm.NewCallResult() - result.Batch, result.Status = nil, vm.ExecStop - return result, nil - } - } -} - -func (mergeGroup *MergeGroup) getInputBatch(proc *process.Process) (*batch.Batch, error) { - r, err := vm.ChildrenCall(mergeGroup.GetChildren(0), proc, mergeGroup.OpAnalyzer) - return r.Batch, err -} - -func (mergeGroup *MergeGroup) consumeBatch(proc *process.Process, b *batch.Batch) error { - // merge intermedia results with only Aggregation. - if len(b.Vecs) == 0 { - - if mergeGroup.ctr.result.IsEmpty() { - aggList, err := makeInitialAggListFromList(proc, b.Aggs) - if err != nil { - return err - } - mergeGroup.ctr.result.InitOnlyAgg(math.MaxInt32, aggList) - mergeGroup.ctr.result.ToPopped[0].SetRowCount(1) - for i := range mergeGroup.ctr.result.AggList { - if err := mergeGroup.ctr.result.AggList[i].GroupGrow(1); err != nil { - return err - } - } - } - - for i, input := range b.Aggs { - if err := mergeGroup.ctr.result.AggList[i].Merge(input, 0, 0); err != nil { - return err - } - } - return nil - } - - // merge intermedia results with group-by columns. - if mergeGroup.ctr.hr.IsEmpty() { - // calculate key width and build the hash map. - keyWidth, keyNullable := 0, false - for _, vec := range b.Vecs { - keyNullable = keyNullable || (!vec.GetType().GetNotNull()) - } - for _, vec := range b.Vecs { - typ := vec.GetType() - keyWidth += group.GetKeyWidth(typ.Oid, typ.Width, keyNullable) - } - - if err := mergeGroup.ctr.hr.BuildHashTable(false, keyWidth > 8, keyNullable, 0); err != nil { - return err - } - } - - if mergeGroup.ctr.result.IsEmpty() { - aggList, err := makeInitialAggListFromList(proc, b.Aggs) - if err != nil { - return err - } - mergeGroup.ctr.result.InitWithBatch(aggexec.GetMinAggregatorsChunkSize(b.Vecs, b.Aggs), aggList, b) - } - - for i, count := 0, b.RowCount(); i < count; i += hashmap.UnitLimit { - n := count - i - if n > hashmap.UnitLimit { - n = hashmap.UnitLimit - } - - origin := mergeGroup.ctr.hr.Hash.GroupCount() - vals, _, err := mergeGroup.ctr.hr.Itr.Insert(i, n, b.Vecs) - if err != nil { - return err - } - insertList, _ := mergeGroup.ctr.hr.GetBinaryInsertList(vals, origin) - - more, err := mergeGroup.ctr.result.AppendBatch(proc.Mp(), b.Vecs, i, insertList) - if err != nil { - return err - } - - if len(b.Aggs) == 0 { - continue - } - if err = mergeGroup.updateAggPart(b, i, len(insertList), more, vals); err != nil { - return err - } - } - - return nil -} - -func (mergeGroup *MergeGroup) updateAggPart( - b *batch.Batch, - offset int, length int, newGroupCount int, - groupList []uint64) error { - var err error - - for i := range mergeGroup.ctr.result.AggList { - if err = mergeGroup.ctr.result.AggList[i].GroupGrow(newGroupCount); err != nil { - return err - } - } - - for i := range mergeGroup.ctr.result.AggList { - if err = mergeGroup.ctr.result.AggList[i].BatchMerge(b.Aggs[i], offset, groupList[:length]); err != nil { - return err - } - } - return nil -} diff --git a/pkg/sql/colexec/mergegroup/exec_test.go b/pkg/sql/colexec/mergegroup/exec_test.go deleted file mode 100644 index 4e542641d0312..0000000000000 --- a/pkg/sql/colexec/mergegroup/exec_test.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2024 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 mergegroup - -import ( - "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/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/value_scan" - "github.com/matrixorigin/matrixone/pkg/testutil" - "github.com/matrixorigin/matrixone/pkg/vm" - "github.com/stretchr/testify/require" - "testing" -) - -// hackAggExecToTestMerge 是一个不带具体逻辑的AggExec. -// 主要用于测试在该算子中,每个接口被调用的次数,以及传入的值。 -type hackAggExecToTestMerge struct { - toFlush int - dst *hackAggExecToTestMerge - - aggexec.AggFuncExec - groupNumber int - doFlushTime int - doMergeTime int - doBatchMerge int - isFree bool -} - -func (h *hackAggExecToTestMerge) GetOptResult() aggexec.SplitResult { - return nil -} - -func (h *hackAggExecToTestMerge) GroupGrow(more int) error { - h.groupNumber += more - return nil -} - -func (h *hackAggExecToTestMerge) Merge(next aggexec.AggFuncExec, groupIdx1, groupIdx2 int) error { - h.doMergeTime++ - return nil -} - -func (h *hackAggExecToTestMerge) BatchMerge(next aggexec.AggFuncExec, offset int, groups []uint64) error { - h.doBatchMerge++ - return nil -} - -func (h *hackAggExecToTestMerge) Flush() ([]*vector.Vector, error) { - h.doFlushTime++ - - ret := make([]*vector.Vector, h.toFlush) - for i := 0; i < h.toFlush; i++ { - ret[i] = hackVecResult - } - return ret, nil -} - -func (h *hackAggExecToTestMerge) Free() { - h.isFree = true -} - -var hackVecResult = vector.NewVec(types.T_int64.ToType()) - -func hackMakeAggExecToTestMerge(r int) *hackAggExecToTestMerge { - makeInitialAggListFromList = func(mg aggexec.AggMemoryManager, list []aggexec.AggFuncExec) ([]aggexec.AggFuncExec, error) { - res := make([]aggexec.AggFuncExec, len(list)) - for i := range res { - res[i] = &hackAggExecToTestMerge{ - toFlush: r, - isFree: false, - } - list[i].(*hackAggExecToTestMerge).dst = res[i].(*hackAggExecToTestMerge) - } - return res, nil - } - - return &hackAggExecToTestMerge{ - toFlush: r, - isFree: false, - } -} - -func TestMergeGroup_WithoutGroupBy(t *testing.T) { - proc := testutil.NewProcess(t) - - { - before := proc.Mp().CurrNB() - - exec1, exec2 := hackMakeAggExecToTestMerge(1), hackMakeAggExecToTestMerge(1) - require.NoError(t, exec1.GroupGrow(1)) - require.NoError(t, exec2.GroupGrow(1)) - - datas := []*batch.Batch{ - getTestBatch(proc.Mp(), nil, exec1), - getTestBatch(proc.Mp(), nil, exec2), - nil, - } - g, src := getGroupOperatorWithInputs(datas) - - require.NoError(t, g.Prepare(proc)) - require.NoError(t, src.Prepare(proc)) - - r, err := g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 1, len(b.Vecs)) - require.Equal(t, hackVecResult, b.Vecs[0]) - require.Equal(t, 1, exec1.dst.groupNumber) - require.Equal(t, 2, exec1.dst.doMergeTime) - require.Equal(t, 1, exec1.dst.doFlushTime) - } - - r, err = g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - src.Free(proc, false, nil) - g.Free(proc, false, nil) - require.Equal(t, before, proc.Mp().CurrNB()) - } -} - -func TestMergeGroup_WithGroupBy(t *testing.T) { - proc := testutil.NewProcess(t) - - { - before := proc.Mp().CurrNB() - - exec1, exec2 := hackMakeAggExecToTestMerge(1), hackMakeAggExecToTestMerge(1) - exec3 := hackMakeAggExecToTestMerge(1) - datas := []*batch.Batch{ - getTestBatch(proc.Mp(), []int64{1, 2, 3}, exec1), - getTestBatch(proc.Mp(), []int64{2, 3, 1}, exec2), - getTestBatch(proc.Mp(), []int64{1, 4, 2}, exec3), - nil, - } - require.NoError(t, exec1.GroupGrow(3)) - require.NoError(t, exec2.GroupGrow(3)) - require.NoError(t, exec3.GroupGrow(3)) - - g, src := getGroupOperatorWithInputs(datas) - - require.NoError(t, g.Prepare(proc)) - require.NoError(t, src.Prepare(proc)) - - r, err := g.Call(proc) - require.NoError(t, err) - require.NotNil(t, r.Batch) - if b := r.Batch; b != nil { - require.Equal(t, 2, len(b.Vecs)) - require.Equal(t, hackVecResult, b.Vecs[1]) - - vs := vector.MustFixedColNoTypeCheck[int64](b.Vecs[0]) - require.Equal(t, 4, len(vs)) - require.Equal(t, int64(1), vs[0]) - require.Equal(t, int64(2), vs[1]) - require.Equal(t, int64(3), vs[2]) - require.Equal(t, int64(4), vs[3]) - require.Equal(t, 4, exec1.dst.groupNumber) // 1, 2, 3, 4 - require.Equal(t, 3, exec1.dst.doBatchMerge) - require.Equal(t, 1, exec1.dst.doFlushTime) - } - - r, err = g.Call(proc) - require.NoError(t, err) - require.Nil(t, r.Batch) - - src.Free(proc, false, nil) - g.Free(proc, false, nil) - require.Equal(t, before, proc.Mp().CurrNB()) - } -} - -func getGroupOperatorWithInputs(dataList []*batch.Batch) (*MergeGroup, *value_scan.ValueScan) { - vscan := value_scan.NewArgument() - vscan.Batchs = dataList - - res := &MergeGroup{ - OperatorBase: vm.OperatorBase{}, - } - res.AppendChild(vscan) - - return res, vscan -} - -func getTestBatch(mp *mpool.MPool, values []int64, agg aggexec.AggFuncExec) *batch.Batch { - typ := types.T_int64.ToType() - - var res *batch.Batch - if len(values) > 0 { - res = batch.NewWithSize(1) - - v1 := testutil.NewInt64Vector(len(values), typ, mp, false, values) - res.Vecs[0] = v1 - res.SetRowCount(len(values)) - } else { - res = batch.NewWithSize(0) - res.SetRowCount(1) - } - - res.Aggs = []aggexec.AggFuncExec{agg} - return res -} diff --git a/pkg/sql/colexec/mergegroup/types.go b/pkg/sql/colexec/mergegroup/types.go deleted file mode 100644 index 68490a86f5f8e..0000000000000 --- a/pkg/sql/colexec/mergegroup/types.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2024 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 mergegroup - -import ( - "github.com/matrixorigin/matrixone/pkg/common/reuse" - "github.com/matrixorigin/matrixone/pkg/container/batch" - "github.com/matrixorigin/matrixone/pkg/container/types" - "github.com/matrixorigin/matrixone/pkg/sql/colexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/group" - "github.com/matrixorigin/matrixone/pkg/vm" - "github.com/matrixorigin/matrixone/pkg/vm/process" -) - -const ( - thisOperatorName = "merge_group" -) - -type MergeGroup struct { - vm.OperatorBase - colexec.Projection - - ctr container - - PartialResults []any - PartialResultTypes []types.T -} - -func (mergeGroup *MergeGroup) ExecProjection(proc *process.Process, input *batch.Batch) (*batch.Batch, error) { - if mergeGroup.ProjectList == nil { - return input, nil - } - return mergeGroup.EvalProjection(input, proc) -} - -type container struct { - state vm.CtrState - - // hash. - hr group.ResHashRelated - // res. - result group.GroupResultBuffer -} - -func (mergeGroup *MergeGroup) Reset(proc *process.Process, _ bool, _ error) { - mergeGroup.Free(proc, false, nil) - mergeGroup.ResetProjection(proc) -} - -func (mergeGroup *MergeGroup) Free(proc *process.Process, _ bool, _ error) { - mergeGroup.ctr.result.Free0(proc.Mp()) - mergeGroup.ctr.hr.Free0() - mergeGroup.FreeProjection(proc) -} - -func (mergeGroup *MergeGroup) GetOperatorBase() *vm.OperatorBase { - return &mergeGroup.OperatorBase -} - -func (mergeGroup *MergeGroup) OpType() vm.OpType { - return vm.MergeGroup -} - -func (mergeGroup MergeGroup) TypeName() string { - return thisOperatorName -} - -func init() { - reuse.CreatePool[MergeGroup]( - func() *MergeGroup { - return &MergeGroup{} - }, - func(a *MergeGroup) { - *a = MergeGroup{} - }, - reuse.DefaultOptions[MergeGroup](). - WithEnableChecker(), - ) -} - -func NewArgument() *MergeGroup { - return reuse.Alloc[MergeGroup](nil) -} - -func (mergeGroup *MergeGroup) Release() { - if mergeGroup != nil { - reuse.Free[MergeGroup](mergeGroup, nil) - } -} diff --git a/pkg/sql/colexec/multi_update/s3writer_delegate.go b/pkg/sql/colexec/multi_update/s3writer_delegate.go index 1aeecd6468b0f..15feac45a1ec3 100644 --- a/pkg/sql/colexec/multi_update/s3writer_delegate.go +++ b/pkg/sql/colexec/multi_update/s3writer_delegate.go @@ -785,7 +785,7 @@ func (writer *s3WriterDelegate) addBatchToOutput( } var val []byte - val, err = bat.MarshalBinaryWithBuffer(&writer.buf) + val, err = bat.MarshalBinaryWithBuffer(&writer.buf, true) if err != nil { return } diff --git a/pkg/sql/colexec/top/top.go b/pkg/sql/colexec/top/top.go index a70cb206db224..4ca2321f1b548 100644 --- a/pkg/sql/colexec/top/top.go +++ b/pkg/sql/colexec/top/top.go @@ -19,6 +19,7 @@ import ( "container/heap" "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/compare" "github.com/matrixorigin/matrixone/pkg/container/batch" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -131,7 +132,9 @@ func (top *Top) Call(proc *process.Process) (vm.CallResult, error) { top.ctr.buildBat.Recursive = bat.Recursive top.ctr.buildBat.ShuffleIDX = bat.ShuffleIDX top.ctr.buildBat.Attrs = bat.Attrs - top.ctr.buildBat.Aggs = bat.Aggs + if len(bat.ExtraBuf1) > 0 || len(bat.ExtraBuf2) > 0 { + return result, moerr.NewInternalError(proc.Ctx, "top build should not have extra buffers") + } copy(top.ctr.buildBat.Vecs, bat.Vecs) top.ctr.buildBat.SetRowCount(bat.RowCount()) diff --git a/pkg/sql/colexec/window/types.go b/pkg/sql/colexec/window/types.go index ffdc5fca79f88..e8e0916998101 100644 --- a/pkg/sql/colexec/window/types.go +++ b/pkg/sql/colexec/window/types.go @@ -21,8 +21,8 @@ import ( "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/sql/colexec" "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/group" "github.com/matrixorigin/matrixone/pkg/vm" "github.com/matrixorigin/matrixone/pkg/vm/process" ) @@ -39,16 +39,17 @@ const ( type container struct { status int - bat *batch.Batch + bat *batch.Batch + batAggs []aggexec.AggFuncExec desc []bool nullsLast []bool - orderVecs []group.ExprEvalVector + orderVecs []colexec.ExprEvalVector sels []int64 ps []int64 // index of partition by os []int64 // Sorted partitions - aggVecs []group.ExprEvalVector + aggVecs []colexec.ExprEvalVector vec *vector.Vector rBat *batch.Batch @@ -152,12 +153,12 @@ func (ctr *container) freeBatch(mp *mpool.MPool) { func (ctr *container) freeAggFun() { if ctr.bat != nil { - for _, a := range ctr.bat.Aggs { + for _, a := range ctr.batAggs { if a != nil { a.Free() } } - ctr.bat.Aggs = nil + ctr.batAggs = nil } } diff --git a/pkg/sql/colexec/window/window.go b/pkg/sql/colexec/window/window.go index de9576cd857a7..22224c1fa8cc7 100644 --- a/pkg/sql/colexec/window/window.go +++ b/pkg/sql/colexec/window/window.go @@ -18,8 +18,8 @@ import ( "bytes" "time" + "github.com/matrixorigin/matrixone/pkg/sql/colexec" "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/group" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/container/batch" @@ -54,10 +54,10 @@ func (window *Window) Prepare(proc *process.Process) (err error) { ctr := &window.ctr if len(ctr.aggVecs) == 0 { - ctr.aggVecs = make([]group.ExprEvalVector, len(window.Aggs)) + ctr.aggVecs = make([]colexec.ExprEvalVector, len(window.Aggs)) for i, ag := range window.Aggs { expressions := ag.GetArgExpressions() - if ctr.aggVecs[i], err = group.MakeEvalVector(proc, expressions); err != nil { + if ctr.aggVecs[i], err = colexec.MakeEvalVector(proc, expressions); err != nil { return err } } @@ -121,18 +121,18 @@ func (window *Window) Call(proc *process.Process) (vm.CallResult, error) { return result, err } - ctr.bat.Aggs = make([]aggexec.AggFuncExec, len(window.Aggs)) + ctr.batAggs = make([]aggexec.AggFuncExec, len(window.Aggs)) for i, ag := range window.Aggs { - ctr.bat.Aggs[i], err = aggexec.MakeAgg(proc, ag.GetAggID(), ag.IsDistinct(), window.Types[i]) + ctr.batAggs[i], err = aggexec.MakeAgg(proc, ag.GetAggID(), ag.IsDistinct(), window.Types[i]) if err != nil { return result, err } if config := ag.GetExtraConfig(); config != nil { - if err = ctr.bat.Aggs[i].SetExtraInformation(config, 0); err != nil { + if err = ctr.batAggs[i].SetExtraInformation(config, 0); err != nil { return result, err } } - if err = ctr.bat.Aggs[i].GroupGrow(ctr.bat.RowCount()); err != nil { + if err = ctr.batAggs[i].GroupGrow(ctr.bat.RowCount()); err != nil { return result, err } } @@ -141,9 +141,9 @@ func (window *Window) Call(proc *process.Process) (vm.CallResult, error) { // sort and partitions if window.Fs = makeOrderBy(w); window.Fs != nil { if len(ctr.orderVecs) == 0 { - ctr.orderVecs = make([]group.ExprEvalVector, len(window.Fs)) + ctr.orderVecs = make([]colexec.ExprEvalVector, len(window.Fs)) for j := range ctr.orderVecs { - ctr.orderVecs[j], err = group.MakeEvalVector(proc, []*plan.Expr{window.Fs[j].Expr}) + ctr.orderVecs[j], err = colexec.MakeEvalVector(proc, []*plan.Expr{window.Fs[j].Expr}) if err != nil { return result, err } @@ -235,8 +235,7 @@ func (ctr *container) processFunc(idx int, ap *Window, proc *process.Process, an for ; o < len(ctr.os); o++ { if ctr.os[o] <= ctr.ps[p] { - - if err = ctr.bat.Aggs[idx].Fill(p-1, o, []*vector.Vector{vec}); err != nil { + if err = ctr.batAggs[idx].Fill(p-1, o, []*vector.Vector{vec}); err != nil { return err } @@ -281,7 +280,7 @@ func (ctr *container) processFunc(idx int, ap *Window, proc *process.Process, an } for k := left; k < right; k++ { - if err = ctr.bat.Aggs[idx].Fill(j, k, ctr.aggVecs[idx].Vec); err != nil { + if err = ctr.batAggs[idx].Fill(j, k, ctr.aggVecs[idx].Vec); err != nil { return err } } @@ -293,7 +292,7 @@ func (ctr *container) processFunc(idx int, ap *Window, proc *process.Process, an if ctr.vec != nil { ctr.vec.Free(proc.Mp()) } - vecs, err := ctr.bat.Aggs[idx].Flush() + vecs, err := ctr.batAggs[idx].Flush() if err != nil { return err } diff --git a/pkg/sql/compile/compile.go b/pkg/sql/compile/compile.go index 6ea0598a0c605..4559a681c00ea 100644 --- a/pkg/sql/compile/compile.go +++ b/pkg/sql/compile/compile.go @@ -60,7 +60,6 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergeblock" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergecte" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergedelete" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergegroup" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergerecursive" "github.com/matrixorigin/matrixone/pkg/sql/colexec/minus" "github.com/matrixorigin/matrixone/pkg/sql/colexec/multi_update" @@ -872,7 +871,12 @@ func (c *Compile) compileQuery(qry *plan.Query) ([]*Scope, error) { return nil, cantCompileForPrepareErr } - plan2.CalcQueryDOP(c.pn, int32(c.ncpu), len(c.cnList), c.execType) + ncpu := int32(c.ncpu) + if qry.MaxDop > 0 { + ncpu = min(ncpu, int32(qry.MaxDop)) + } + + plan2.CalcQueryDOP(c.pn, ncpu, len(c.cnList), c.execType) c.initAnalyzeModule(qry) // deal with sink scan first. @@ -2234,7 +2238,7 @@ func (c *Compile) compileProjection(n *plan.Node, ss []*Scope) []*Scope { } else { c.setProjection(n, ss[i]) } - case *mergegroup.MergeGroup: + case *group.MergeGroup: if op.ProjectList == nil { op.ProjectList = n.ProjectList } else { @@ -3205,7 +3209,7 @@ func (c *Compile) compileTPGroup(n *plan.Node, ss []*Scope, ns []*plan.Node) []* op := constructGroup(c.proc.Ctx, n, ns[n.Children[0]], false, 0, c.proc) op.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) ss[0].setRootOperator(op) - arg := constructMergeGroup() + arg := constructMergeGroup(n) arg.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) ss[0].setRootOperator(arg) } else { @@ -3240,7 +3244,7 @@ func (c *Compile) compileMergeGroup(n *plan.Node, ss []*Scope, ns []*plan.Node, rs := c.newMergeScope([]*Scope{mergeToGroup}) currentFirstFlag = c.anal.isFirst - arg := constructMergeGroup() + arg := constructMergeGroup(n) arg.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) rs.setRootOperator(arg) c.anal.isFirst = false @@ -3259,7 +3263,7 @@ func (c *Compile) compileMergeGroup(n *plan.Node, ss []*Scope, ns []*plan.Node, rs := c.newMergeScope(ss) currentFirstFlag = c.anal.isFirst - arg := constructMergeGroup() + arg := constructMergeGroup(n) arg.SetAnalyzeControl(c.anal.curNodeIdx, currentFirstFlag) rs.setRootOperator(arg) c.anal.isFirst = false diff --git a/pkg/sql/compile/operator.go b/pkg/sql/compile/operator.go index 103baeafa06e7..389609c1213e0 100644 --- a/pkg/sql/compile/operator.go +++ b/pkg/sql/compile/operator.go @@ -57,7 +57,6 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/merge" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergeblock" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergecte" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergegroup" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergeorder" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergerecursive" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergetop" @@ -170,7 +169,6 @@ func dupOperator(sourceOp vm.Operator, index int, maxParallel int) vm.Operator { case vm.Group: t := sourceOp.(*group.Group) op := group.NewArgument() - op.PreAllocSize = t.PreAllocSize op.NeedEval = t.NeedEval op.SpillMem = t.SpillMem op.GroupingFlag = t.GroupingFlag @@ -1547,22 +1545,12 @@ func constructGroup(_ context.Context, n, cn *plan.Node, needEval bool, shuffleD typs[i] = types.New(types.T(e.Typ.Id), e.Typ.Width, e.Typ.Scale) } - var preAllocSize uint64 = 0 - if n.Stats != nil && n.Stats.HashmapStats != nil && n.Stats.HashmapStats.Shuffle { - if cn.NodeType == plan.Node_TABLE_SCAN && len(cn.FilterList) == 0 { - // if group on scan without filter, stats for hashmap is accurate to do preAlloc - // tune it up a little bit in case it is not so average after shuffle - preAllocSize = uint64(n.Stats.HashmapStats.HashmapSize / float64(shuffleDop) * 1.05) - } - } - arg := group.NewArgument() arg.Aggs = aggregationExpressions arg.NeedEval = needEval arg.SpillMem = n.SpillMem arg.GroupingFlag = n.GroupingFlag arg.Exprs = n.GroupBy - arg.PreAllocSize = preAllocSize return arg } @@ -1745,8 +1733,15 @@ func constructDispatch(idx int, target []*Scope, source *Scope, node *plan.Node, return arg } -func constructMergeGroup() *mergegroup.MergeGroup { - arg := mergegroup.NewArgument() +func constructMergeGroup(n *plan.Node) *group.MergeGroup { + arg := group.NewArgumentMergeGroup() + // here the n is a Group node, merge group is "generated" by the + // group node and then merge them + // + // XXX: merge group groupby and agg should also be set here. + // but right now we use batch.ExtraBuf1. This is just wrong. + // should be here. + arg.SpillMem = n.SpillMem return arg } diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 7d8a2dce6bd9d..edeab76b8aa1c 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -49,7 +49,6 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/lockop" "github.com/matrixorigin/matrixone/pkg/sql/colexec/loopjoin" "github.com/matrixorigin/matrixone/pkg/sql/colexec/merge" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergegroup" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergeorder" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergerecursive" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergetop" @@ -527,7 +526,6 @@ func convertToPipelineInstruction(op vm.Operator, proc *process.Process, ctx *sc } case *group.Group: in.Agg = &pipeline.Group{ - PreAllocSize: t.PreAllocSize, NeedEval: t.NeedEval, SpillMem: t.SpillMem, GroupingFlag: t.GroupingFlag, @@ -695,8 +693,10 @@ func convertToPipelineInstruction(op vm.Operator, proc *process.Process, ctx *sc EndIdx: t.EndIDX, } case *mergerecursive.MergeRecursive: - case *mergegroup.MergeGroup: - in.Agg = &pipeline.Group{} + case *group.MergeGroup: + in.Agg = &pipeline.Group{ + SpillMem: t.SpillMem, + } in.ProjectList = t.ProjectList EncodeMergeGroup(t, in.Agg) case *mergetop.MergeTop: @@ -1061,7 +1061,6 @@ func convertToVmOperator(opr *pipeline.Instruction, ctx *scopeContext, eng engin case vm.Group: t := opr.GetAgg() arg := group.NewArgument() - arg.PreAllocSize = t.PreAllocSize arg.NeedEval = t.NeedEval arg.SpillMem = t.SpillMem arg.GroupingFlag = t.GroupingFlag @@ -1233,10 +1232,14 @@ func convertToVmOperator(opr *pipeline.Instruction, ctx *scopeContext, eng engin case vm.MergeRecursive: op = mergerecursive.NewArgument() case vm.MergeGroup: - arg := mergegroup.NewArgument() + arg := group.NewArgumentMergeGroup() + // here the opr is a MergeGroup node, merge group is "generated" by the + // group node and then merge them + t := opr.GetAgg() + arg.SpillMem = t.SpillMem arg.ProjectList = opr.ProjectList op = arg - DecodeMergeGroup(op.(*mergegroup.MergeGroup), opr.Agg) + DecodeMergeGroup(op.(*group.MergeGroup), opr.Agg) case vm.MergeTop: op = mergetop.NewArgument(). WithLimit(opr.Limit). @@ -1557,7 +1560,7 @@ func (ctx *scopeContext) findRegister(reg *process.WaitRegister) (int32, *scopeC return -1, nil } -func EncodeMergeGroup(merge *mergegroup.MergeGroup, pipe *pipeline.Group) { +func EncodeMergeGroup(merge *group.MergeGroup, pipe *pipeline.Group) { if merge.PartialResults == nil { return } @@ -1662,7 +1665,7 @@ func EncodeMergeGroup(merge *mergegroup.MergeGroup, pipe *pipeline.Group) { } } -func DecodeMergeGroup(merge *mergegroup.MergeGroup, pipe *pipeline.Group) { +func DecodeMergeGroup(merge *group.MergeGroup, pipe *pipeline.Group) { if pipe.PartialResults == nil { return } diff --git a/pkg/sql/compile/remoterun_test.go b/pkg/sql/compile/remoterun_test.go index f0fa1f21cc1d3..05b9134bb669f 100644 --- a/pkg/sql/compile/remoterun_test.go +++ b/pkg/sql/compile/remoterun_test.go @@ -57,7 +57,6 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/colexec/lockop" "github.com/matrixorigin/matrixone/pkg/sql/colexec/loopjoin" "github.com/matrixorigin/matrixone/pkg/sql/colexec/merge" - "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergegroup" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergeorder" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergerecursive" "github.com/matrixorigin/matrixone/pkg/sql/colexec/mergetop" @@ -224,7 +223,7 @@ func Test_convertToPipelineInstruction(t *testing.T) { &intersectall.IntersectAll{}, &merge.Merge{}, &mergerecursive.MergeRecursive{}, - &mergegroup.MergeGroup{}, + &group.MergeGroup{}, &mergetop.MergeTop{}, &mergeorder.MergeOrder{}, &table_function.TableFunction{}, @@ -349,28 +348,12 @@ func Test_convertToProcessSessionInfo(t *testing.T) { func Test_decodeBatch(t *testing.T) { mp := &mpool.MPool{} - vp := process.NewTopProcess( - context.TODO(), - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil) aggexec.RegisterGroupConcatAgg(0, ",") - agg0, err := aggexec.MakeAgg( - vp, 0, false, []types.Type{types.T_varchar.ToType()}...) - require.Nil(t, err) bat := &batch.Batch{ Recursive: 0, ShuffleIDX: 0, Attrs: []string{"1"}, Vecs: []*vector.Vector{vector.NewVec(types.T_int64.ToType())}, - Aggs: []aggexec.AggFuncExec{agg0}, } bat.SetRowCount(1) data, err := types.Encode(bat) diff --git a/pkg/sql/compile/scope.go b/pkg/sql/compile/scope.go index 0d20e83c4d999..5498cdb12a9aa 100644 --- a/pkg/sql/compile/scope.go +++ b/pkg/sql/compile/scope.go @@ -38,7 +38,6 @@ import ( "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/mergegroup" "github.com/matrixorigin/matrixone/pkg/sql/colexec/output" "github.com/matrixorigin/matrixone/pkg/sql/colexec/table_scan" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" @@ -1001,11 +1000,11 @@ func (s *Scope) aggOptimize(c *Compile, rel engine.Relation, ctx context.Context } // find scan->group->mergegroup -func findMergeGroup(op vm.Operator) *mergegroup.MergeGroup { +func findMergeGroup(op vm.Operator) *group.MergeGroup { if op == nil { return nil } - if mergeGroup, ok := op.(*mergegroup.MergeGroup); ok { + if mergeGroup, ok := op.(*group.MergeGroup); ok { child := op.GetOperatorBase().GetChildren(0) if _, ok = child.(*group.Group); ok { child = child.GetOperatorBase().GetChildren(0) diff --git a/pkg/sql/plan/explain/explain_node.go b/pkg/sql/plan/explain/explain_node.go index 988e82a89ce33..59468e9fdf380 100644 --- a/pkg/sql/plan/explain/explain_node.go +++ b/pkg/sql/plan/explain/explain_node.go @@ -1149,6 +1149,13 @@ func (a AnalyzeInfoDescribeImpl) GetDescription(ctx context.Context, options *Ex common.ConvertBytesToHumanReadable(a.AnalyzeInfo.MemoryMin), common.ConvertBytesToHumanReadable(a.AnalyzeInfo.MemoryMax)) + if a.AnalyzeInfo.SpillSize > 0 { + fmt.Fprintf(buf, " SpillSize=%s (min=%s, max=%s)", + common.ConvertBytesToHumanReadable(a.AnalyzeInfo.SpillSize), + common.ConvertBytesToHumanReadable(a.AnalyzeInfo.SpillMin), + common.ConvertBytesToHumanReadable(a.AnalyzeInfo.SpillMax)) + } + return nil } diff --git a/pkg/sql/plan/function/agg/avg.go b/pkg/sql/plan/function/agg/avg.go index 6c9b5c57301ec..910b137054bfa 100644 --- a/pkg/sql/plan/function/agg/avg.go +++ b/pkg/sql/plan/function/agg/avg.go @@ -121,8 +121,9 @@ func AvgReturnType(typs []types.Type) types.Type { type aggAvgContext int64 -func (a *aggAvgContext) Marshal() []byte { return types.EncodeInt64((*int64)(a)) } -func (a *aggAvgContext) Unmarshal(bs []byte) { *a = aggAvgContext(types.DecodeInt64(bs)) } +func (a *aggAvgContext) Marshal() []byte { return types.EncodeInt64((*int64)(a)) } +func (a *aggAvgContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } +func (a *aggAvgContext) Unmarshal(bs []byte) { *a = aggAvgContext(types.DecodeInt64(bs)) } func generateAggAvgContext(_ types.Type, _ ...types.Type) aggexec.AggGroupExecContext { c := aggAvgContext(0) return &c @@ -177,7 +178,8 @@ func aggAvgFlush( type aggAvgDecimalCommonCtx int32 -func (a *aggAvgDecimalCommonCtx) Marshal() []byte { return types.EncodeInt32((*int32)(a)) } +func (a *aggAvgDecimalCommonCtx) Marshal() []byte { return types.EncodeInt32((*int32)(a)) } +func (a *aggAvgDecimalCommonCtx) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *aggAvgDecimalCommonCtx) Unmarshal(bs []byte) { *a = aggAvgDecimalCommonCtx(types.DecodeInt32(bs)) } diff --git a/pkg/sql/plan/function/agg/avg_tw_cache.go b/pkg/sql/plan/function/agg/avg_tw_cache.go index 35fa27f8b1af3..4a6fc9e88969e 100644 --- a/pkg/sql/plan/function/agg/avg_tw_cache.go +++ b/pkg/sql/plan/function/agg/avg_tw_cache.go @@ -127,6 +127,7 @@ func (a *AvgTwCacheContext) Marshal() []byte { copy(res[8:], c) return res } +func (a *AvgTwCacheContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *AvgTwCacheContext) Unmarshal(bs []byte) { a.Sum = types.DecodeFloat64(bs[0:]) a.Count = types.DecodeInt64(bs[8:]) @@ -200,6 +201,8 @@ func (a *AvgTwCacheDecimalContext) Marshal() []byte { return res } +func (a *AvgTwCacheDecimalContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } + func (a *AvgTwCacheDecimalContext) Unmarshal(bs []byte) { d1 := types.DecodeUint64(bs[0:]) d2 := types.DecodeUint64(bs[8:]) diff --git a/pkg/sql/plan/function/agg/avg_tw_result.go b/pkg/sql/plan/function/agg/avg_tw_result.go index cce57a2b7d3b8..00129f1b7dd8a 100644 --- a/pkg/sql/plan/function/agg/avg_tw_result.go +++ b/pkg/sql/plan/function/agg/avg_tw_result.go @@ -61,6 +61,7 @@ func (a *AvgTwResultContext) Marshal() []byte { copy(res[8:], c) return res } +func (a *AvgTwResultContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *AvgTwResultContext) Unmarshal(bs []byte) { a.Sum = types.DecodeFloat64(bs[0:]) a.Count = types.DecodeInt64(bs[8:]) @@ -133,7 +134,7 @@ func (a *AvgTwResultDecimalContext) Marshal() []byte { copy(res[24:], s) return res } - +func (a *AvgTwResultDecimalContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *AvgTwResultDecimalContext) Unmarshal(bs []byte) { d1 := types.DecodeUint64(bs[0:]) d2 := types.DecodeUint64(bs[8:]) diff --git a/pkg/sql/plan/function/agg/bitmap.go b/pkg/sql/plan/function/agg/bitmap.go index d8597c2b6666f..6e7b8aa591e06 100644 --- a/pkg/sql/plan/function/agg/bitmap.go +++ b/pkg/sql/plan/function/agg/bitmap.go @@ -58,6 +58,7 @@ func (a *aggBitmapGroupContext) Marshal() []byte { b, _ := a.bmp.ToBytes() return b } +func (a *aggBitmapGroupContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *aggBitmapGroupContext) Unmarshal(bs []byte) { a.bmp = roaring.New() _ = a.bmp.UnmarshalBinary(bs) diff --git a/pkg/sql/plan/function/agg/sum.go b/pkg/sql/plan/function/agg/sum.go index aa34cb045c6c7..29e2519106701 100644 --- a/pkg/sql/plan/function/agg/sum.go +++ b/pkg/sql/plan/function/agg/sum.go @@ -151,8 +151,9 @@ func (a *aggSumDecimal) Size() int64 { return 4 // int32 } -func (a *aggSumDecimal) Marshal() []byte { return types.EncodeInt32(&a.argScale) } -func (a *aggSumDecimal) Unmarshal(bs []byte) { a.argScale = types.DecodeInt32(bs) } +func (a *aggSumDecimal) Marshal() []byte { return types.EncodeInt32(&a.argScale) } +func (a *aggSumDecimal) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } +func (a *aggSumDecimal) Unmarshal(bs []byte) { a.argScale = types.DecodeInt32(bs) } func aggSumOfDecimalInitCommonContext( resultType types.Type, parameters ...types.Type, ) aggexec.AggCommonExecContext { diff --git a/pkg/sql/plan/function/agg/var_pop.go b/pkg/sql/plan/function/agg/var_pop.go index f30070450ddf0..6fe1ec0c77921 100644 --- a/pkg/sql/plan/function/agg/var_pop.go +++ b/pkg/sql/plan/function/agg/var_pop.go @@ -15,10 +15,11 @@ package agg import ( + "math" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec" - "math" ) func RegisterVarPop2(id int64) { @@ -131,6 +132,7 @@ func (a *aggVarPopGroupContext) Marshal() []byte { bs = append(bs, types.EncodeInt64(&a.count)...) return bs } +func (a *aggVarPopGroupContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *aggVarPopGroupContext) Unmarshal(bs []byte) { a.sum = types.DecodeFloat64(bs[:8]) a.count = types.DecodeInt64(bs[8:]) @@ -218,6 +220,7 @@ func (a *aggVarPopOfDecimalGroupContext) Marshal() []byte { bs = append(bs, types.EncodeDecimal128(&a.sum)...) return bs } +func (a *aggVarPopOfDecimalGroupContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *aggVarPopOfDecimalGroupContext) Unmarshal(bs []byte) { a.count = types.DecodeInt64(bs[:8]) a.overflow = types.DecodeBool(bs[8:9]) @@ -245,6 +248,7 @@ func (a *aggVarPopOfDecimalCommonContext) Marshal() []byte { bs = append(bs, types.EncodeInt32(&a.resultScale)...) return bs } +func (a *aggVarPopOfDecimalCommonContext) MarshalBinary() ([]byte, error) { return a.Marshal(), nil } func (a *aggVarPopOfDecimalCommonContext) Unmarshal(bs []byte) { a.argScale = types.DecodeInt32(bs[:4]) a.resultScale = types.DecodeInt32(bs[4:]) diff --git a/pkg/sql/plan/query_builder.go b/pkg/sql/plan/query_builder.go index 2b2a60908d8b5..0388feecab490 100644 --- a/pkg/sql/plan/query_builder.go +++ b/pkg/sql/plan/query_builder.go @@ -76,9 +76,18 @@ func NewQueryBuilder(queryType plan.Query_StatementType, ctx CompilerContext, is } } + var maxDop int64 + maxDopInt, err := ctx.ResolveVariable("max_dop", true, false) + if err == nil { + if maxDopVal, ok := maxDopInt.(int64); ok { + maxDop = maxDopVal + } + } + return &QueryBuilder{ qry: &Query{ StmtType: queryType, + MaxDop: int64(maxDop), }, compCtx: ctx, ctxByNode: []*BindContext{}, diff --git a/pkg/sql/plan/shuffle.go b/pkg/sql/plan/shuffle.go index 93dd94d34b880..226431ca82404 100644 --- a/pkg/sql/plan/shuffle.go +++ b/pkg/sql/plan/shuffle.go @@ -678,10 +678,20 @@ func determineShuffleForGroupBy(node *plan.Node, builder *QueryBuilder) { } func getShuffleDop(ncpu int, lencn int, hashmapSize float64) (dop int) { + // XXX + // why do we ever need to do this to ncpu? What is the reason to ever + // return a value that is more than ncpu? + // + // Shouldn't just be this? + // // // // // // // // maxret := ncpu + // + // See #19054, #20302 + // I don't think either make any sense. if ncpu <= 4 { ncpu = 4 } maxret := ncpu * 4 + // these magic number comes from hashmap resize factor. see hashtable/common.go, in maxElemCnt function ret1 := int(hashmapSize/float64(lencn)/12800000) + 1 if ret1 >= maxret { diff --git a/pkg/sql/plan/stats.go b/pkg/sql/plan/stats.go index deaffbba72de3..0b5d7e5e6f31a 100644 --- a/pkg/sql/plan/stats.go +++ b/pkg/sql/plan/stats.go @@ -1854,7 +1854,7 @@ func CalcNodeDOP(p *plan.Plan, rootID int32, ncpu int32, lencn int) { func CalcQueryDOP(p *plan.Plan, ncpu int32, lencn int, typ ExecType) { qry := p.GetQuery() - if typ == ExecTypeTP { + if typ == ExecTypeTP || ncpu == 1 { for i := range qry.Nodes { qry.Nodes[i].Stats.Dop = 1 } diff --git a/pkg/sql/util/index_util.go b/pkg/sql/util/index_util.go index 0e880e4531630..038fca5aaa87b 100644 --- a/pkg/sql/util/index_util.go +++ b/pkg/sql/util/index_util.go @@ -989,8 +989,10 @@ func XXHashVectors(vs []*vector.Vector, // extend the hashCode slice if necessary rowCount := vs[0].Length() - if rowCount > cap(hashCode) { + if rowCount > len(hashCode) { hashCode = make([]uint64, rowCount) + } else { + hashCode = hashCode[:rowCount] } // extend the packers slice if necessary diff --git a/pkg/vm/process/operator_analyzer.go b/pkg/vm/process/operator_analyzer.go index 14077cd745187..a97d17d859c26 100644 --- a/pkg/vm/process/operator_analyzer.go +++ b/pkg/vm/process/operator_analyzer.go @@ -39,6 +39,8 @@ type Analyzer interface { Stop() ChildrenCallStop(time time.Time) Alloc(int64) + SetMemUsed(int64) + Spill(int64) Input(batch *batch.Batch) Output(*batch.Batch) WaitStop(time.Time) @@ -154,6 +156,13 @@ func (opAlyzr *operatorAnalyzer) Alloc(size int64) { opAlyzr.opStats.MemorySize += size } +func (opAlyzr *operatorAnalyzer) SetMemUsed(size int64) { + if opAlyzr.opStats == nil { + panic("operatorAnalyzer.SetMemUsed: operatorAnalyzer.opStats is nil") + } + opAlyzr.opStats.MemorySize = max(opAlyzr.opStats.MemorySize, size) +} + func (opAlyzr *operatorAnalyzer) Spill(size int64) { if opAlyzr.opStats == nil { panic("operatorAnalyzer.AddSpillSize: operatorAnalyzer.opStats is nil") diff --git a/pkg/vm/process/process.go b/pkg/vm/process/process.go index e6aff493172a5..7b9ea289e3468 100644 --- a/pkg/vm/process/process.go +++ b/pkg/vm/process/process.go @@ -24,6 +24,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/taskservice" "github.com/matrixorigin/matrixone/pkg/common/log" + "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/nulls" @@ -271,5 +272,15 @@ func (proc *Process) GetSpillFileService() (fileservice.MutableFileService, erro if err != nil { return nil, err } - return fileservice.SubPath(local, defines.SpillFileServiceName).(fileservice.MutableFileService), nil + + if err := local.EnsureDir(proc.Ctx, defines.SpillFileServiceName); err != nil { + return nil, err + } + + subPathFS := fileservice.SubPath(local, defines.SpillFileServiceName) + mutablefs, ok := subPathFS.(fileservice.MutableFileService) + if !ok { + return nil, moerr.NewInternalErrorNoCtx("subPathFS is not a MutableFileService") + } + return mutablefs, nil } diff --git a/pkg/vm/process/types.go b/pkg/vm/process/types.go index b0e54853ce9cd..2b5c85cd06a24 100644 --- a/pkg/vm/process/types.go +++ b/pkg/vm/process/types.go @@ -16,12 +16,14 @@ package process import ( "context" - "github.com/matrixorigin/matrixone/pkg/taskservice" "io" "sync" "sync/atomic" "time" + "github.com/matrixorigin/matrixone/pkg/logutil" + "github.com/matrixorigin/matrixone/pkg/taskservice" + "github.com/confluentinc/confluent-kafka-go/v2/kafka" "github.com/google/uuid" "github.com/hayageek/threadsafe" @@ -481,3 +483,9 @@ func (si *SessionInfo) GetDatabase() string { func (si *SessionInfo) GetVersion() string { return si.Version } + +func (proc *Process) DebugBreakDump(cond bool) { + if proc.Base.SessionInfo.User == "dump" && cond { + logutil.GetGlobalLogger().Info("debug break dump") + } +} diff --git a/proto/plan.proto b/proto/plan.proto index 17233480a8815..9ba8776209b9d 100644 --- a/proto/plan.proto +++ b/proto/plan.proto @@ -1063,6 +1063,9 @@ message Query { repeated string detectSqls= 8; repeated Query background_queries = 9; + + // run time config that can change query behaviors + int64 maxDop = 10; } message TransationControl { diff --git a/test/distributed/cases/qexec/group.result b/test/distributed/cases/qexec/group.result new file mode 100644 index 0000000000000..69bf0c084467a --- /dev/null +++ b/test/distributed/cases/qexec/group.result @@ -0,0 +1,96 @@ +drop database if exists qetest; +create database qetest; +use qetest; +create table t (a int, b int, c varchar(100), d decimal(10, 2), f real); +insert into t select +result, result % 1000, +case when result % 10 = 0 then null else 'foobar' || result || 'zoo' end, +case when result % 10 = 0 then null else result end, +case when result % 10 = 0 then null else result end +from generate_series(1, 1000000) gt; +select count(*) from t; +count(*) +1000000 +insert into t select * from t; +select count(*) from t; +count(*) +2000000 +select count(*), count(a), count(b), count(c), +avg(a), avg(b), avg(d), avg(f), +max(a), max(b), max(c), max(d), max(f) +from t; +count(*) count(a) count(b) count(c) avg(a) avg(b) avg(d) avg(f) max(a) max(b) max(c) max(d) max(f) +2000000 2000000 2000000 1800000 500000.5 499.5 500000.00000000 500000.0 1000000 999 foobar9zoo 999999.00 999999.0 +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(d) as d, sum(f) as f from t group by a +) tmp; +count(a) sum(d) sum(f) +1000000 900000000000.00 9.0E11 +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(d) as d, sum(f) as f from t group by a +having a % 100 > 95 +) tmp; +count(a) sum(d) sum(f) +40000 40003800000.00 4.00038E10 +select count(*) from (select a, b, c from t group by a, b, c) tmpt; +count(*) +1000000 +select sum(a), max(c), avg(d), avg(f) from (select a, c, avg(d) as d, avg(f) as f from t group by a, c) tmpt; +sum(a) max(c) avg(d) avg(f) +500000500000 foobar9zoo 500000.000000000000 500000.0 +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(distinct d) d, sum(distinct f) f from t where a < 10000 group by a +) tmpt; +count(a) sum(d) sum(f) +9999 45000000.00 4.5E7 +select 'set max_dop to 1 ... '; +set max_dop to 1 ... +set max_dop to 1 ... +set @@max_dop = 1; +select 'set agg_spill_mem to 50MB ... '; +set agg_spill_mem to 50MB ... +set agg_spill_mem to 50MB ... +set @@agg_spill_mem = 60000000; +select count(*) from (select a, b, c from t group by a, b, c) tmptt; +count(*) +1000000 +select sum(a), max(c), avg(d), avg(f) from (select a, c, avg(d) as d, avg(f) as f from t group by a, c) tmptt; +sum(a) max(c) avg(d) avg(f) +500000500000 foobar9zoo 500000.000000000000 500000.0 +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(distinct d) d, sum(distinct f) f from t where a < 10000 group by a +) tmptt; +count(a) sum(d) sum(f) +9999 45000000.00 4.5E7 +explain analyze select a, b, c from t group by a, b, c; +ap query plan on one cn(24 core) +Project + Analyze: timeConsumed=0ms waitTime=0ms inputRows=1000000 outputRows=1000000 (min=1000000, max=1000000) InputSize=30.52 MiB OutputSize=30.52 MiB MemorySize=256.00 KiB (min=256.00 KiB, max=256.00 KiB) + -> Aggregate + Analyze: timeConsumed=1430ms waitTime=0ms inputRows=0 outputRows=1000000 (min=1000000, max=1000000) InputSize=0 bytes OutputSize=30.52 MiB MemorySize=57.50 MiB (min=57.50 MiB, max=57.50 MiB) SpillSize=115.00 MiB (min=115.00 MiB, max=115.00 MiB) + Group Key: t.a, t.b, t.c shuffle: range(t.a) + -> Table Scan on qetest.t + Analyze: timeConsumed=9ms waitTime=0ms inputBlocks=246 inputRows=2000000 outputRows=2000000 (min=2000000, max=2000000) InputSize=61.04 MiB OutputSize=61.04 MiB MemorySize=512.00 KiB (min=512.00 KiB, max=512.00 KiB) +explain analyze select a, c, avg(d) d, avg(f) f from t group by a, c; +ap query plan on one cn(24 core) +Project + Analyze: timeConsumed=0ms waitTime=0ms inputRows=1000000 outputRows=1000000 (min=1000000, max=1000000) InputSize=49.59 MiB OutputSize=49.59 MiB MemorySize=416.00 KiB (min=416.00 KiB, max=416.00 KiB) + -> Aggregate + Analyze: timeConsumed=7013ms waitTime=0ms inputRows=0 outputRows=1000000 (min=1000000, max=1000000) InputSize=0 bytes OutputSize=49.59 MiB MemorySize=60.76 MiB (min=60.76 MiB, max=60.76 MiB) SpillSize=242.90 MiB (min=242.90 MiB, max=242.90 MiB) + Group Key: t.a, t.c shuffle: range(t.a) + Aggregate Functions: avg(t.d), avg(t.f) + -> Table Scan on qetest.t + Analyze: timeConsumed=20ms waitTime=0ms inputBlocks=246 inputRows=2000000 outputRows=2000000 (min=2000000, max=2000000) InputSize=83.92 MiB OutputSize=83.92 MiB MemorySize=704.00 KiB (min=704.00 KiB, max=704.00 KiB) +explain analyze select count(*), a, sum(distinct d) d, sum(distinct f) f from t where a < 10000 group by a; +tp query plan +Project + Analyze: timeConsumed=0ms waitTime=0ms inputRows=9999 outputRows=9999 (min=9999, max=9999) InputSize=351.53 KiB OutputSize=351.53 KiB MemorySize=288.00 KiB (min=288.00 KiB, max=288.00 KiB) + -> Aggregate + Analyze: timeConsumed=442ms waitTime=0ms inputRows=19998 outputRows=9999 (min=9999, max=9999) InputSize=390.59 KiB OutputSize=351.53 KiB MemorySize=2.57 GiB (min=2.57 GiB, max=2.57 GiB) + Group Key: t.a + Aggregate Functions: starcount(1), sum(t.d), sum(t.f) + -> Table Scan on qetest.t + Analyze: timeConsumed=0ms waitTime=0ms inputBlocks=4 inputRows=32768 outputRows=19998 (min=19998, max=19998) InputSize=640.00 KiB OutputSize=390.59 KiB MemorySize=318.74 KiB (min=126.74 KiB, max=160.00 KiB) + Filter Cond: (t.a < 10000) + Block Filter Cond: (t.a < 10000) +drop database qetest; diff --git a/test/distributed/cases/qexec/group.sql b/test/distributed/cases/qexec/group.sql new file mode 100644 index 0000000000000..70e9beefada98 --- /dev/null +++ b/test/distributed/cases/qexec/group.sql @@ -0,0 +1,66 @@ +drop database if exists qetest; +create database qetest; +use qetest; + +create table t (a int, b int, c varchar(100), d decimal(10, 2), f real); + +insert into t select + result, result % 1000, + case when result % 10 = 0 then null else 'foobar' || result || 'zoo' end, + case when result % 10 = 0 then null else result end, + case when result % 10 = 0 then null else result end + from generate_series(1, 1000000) gt; + +select count(*) from t; + +insert into t select * from t; + +select count(*) from t; + +-- run a bunch of group bys +select count(*), count(a), count(b), count(c), +avg(a), avg(b), avg(d), avg(f), +max(a), max(b), max(c), max(d), max(f) +from t; + +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(d) as d, sum(f) as f from t group by a +) tmp; + +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(d) as d, sum(f) as f from t group by a +having a % 100 > 95 +) tmp; + +-- a few group by queries +select count(*) from (select a, b, c from t group by a, b, c) tmpt; +select sum(a), max(c), avg(d), avg(f) from (select a, c, avg(d) as d, avg(f) as f from t group by a, c) tmpt; + +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(distinct d) d, sum(distinct f) f from t where a < 10000 group by a +) tmpt; + +-- force dop to 1, so it is easier to trigger spill +select 'set max_dop to 1 ... '; +set @@max_dop = 1; +-- this will set agg_spill_mem to min allowed (1MB) +select 'set agg_spill_mem to 50MB ... '; +set @@agg_spill_mem = 60000000; +-- rerun queries + +select count(*) from (select a, b, c from t group by a, b, c) tmptt; +select sum(a), max(c), avg(d), avg(f) from (select a, c, avg(d) as d, avg(f) as f from t group by a, c) tmptt; + +select count(a), sum(d), sum(f) from ( +select count(*), a, sum(distinct d) d, sum(distinct f) f from t where a < 10000 group by a +) tmptt; + +-- A much better way is to run explain analyze, but these all depends on issue 22721 + +-- @bvt:issue#22721 +explain analyze select a, b, c from t group by a, b, c; +explain analyze select a, c, avg(d) d, avg(f) f from t group by a, c; +explain analyze select count(*), a, sum(distinct d) d, sum(distinct f) f from t where a < 10000 group by a; +-- @bvt:issue + +drop database qetest;