diff --git a/go/sqltypes/bind_variables.go b/go/sqltypes/bind_variables.go index 9d60c1c8e1a..de424904592 100644 --- a/go/sqltypes/bind_variables.go +++ b/go/sqltypes/bind_variables.go @@ -65,6 +65,16 @@ func BuildBindVariables(in map[string]interface{}) (map[string]*querypb.BindVari return out, nil } +// HexNumBindVariable converts bytes representing a hex number to a bind var. +func HexNumBindVariable(v []byte) *querypb.BindVariable { + return ValueBindVariable(NewHexNum(v)) +} + +// HexValBindVariable converts bytes representing a hex encoded string to a bind var. +func HexValBindVariable(v []byte) *querypb.BindVariable { + return ValueBindVariable(NewHexVal(v)) +} + // Int8BindVariable converts an int8 to a bind var. func Int8BindVariable(v int8) *querypb.BindVariable { return ValueBindVariable(NewInt8(v)) diff --git a/go/sqltypes/result.go b/go/sqltypes/result.go index 7f5e45d0c8f..297915ed1e6 100644 --- a/go/sqltypes/result.go +++ b/go/sqltypes/result.go @@ -17,6 +17,8 @@ limitations under the License. package sqltypes import ( + "crypto/sha256" + "fmt" "reflect" "github.com/golang/protobuf/proto" @@ -175,6 +177,61 @@ func ResultsEqual(r1, r2 []Result) bool { return true } +// ResultsEqualUnordered compares two unordered arrays of Result. +func ResultsEqualUnordered(r1, r2 []Result) bool { + if len(r1) != len(r2) { + return false + } + + // allRows is a hash map that contains a row hashed as a key and + // the number of occurrence as the value. we use this map to ensure + // equality between the two result sets. when analyzing r1, we + // increment each key's value by one for each row's occurrence, and + // then we decrement it by one each time we see the same key in r2. + // if one of the key's value is not equal to zero, then r1 and r2 do + // not match. + allRows := map[string]int{} + countRows := 0 + for _, r := range r1 { + saveRowsAnalysis(r, allRows, &countRows, true) + } + for _, r := range r2 { + saveRowsAnalysis(r, allRows, &countRows, false) + } + if countRows != 0 { + return false + } + for _, i := range allRows { + if i != 0 { + return false + } + } + return true +} + +func saveRowsAnalysis(r Result, allRows map[string]int, totalRows *int, increment bool) { + for _, row := range r.Rows { + newHash := hashCodeForRow(row) + if increment { + allRows[newHash]++ + } else { + allRows[newHash]-- + } + } + if increment { + *totalRows += int(r.RowsAffected) + } else { + *totalRows -= int(r.RowsAffected) + } +} + +func hashCodeForRow(val []Value) string { + h := sha256.New() + h.Write([]byte(fmt.Sprintf("%v", val))) + + return fmt.Sprintf("%x", h.Sum(nil)) +} + // MakeRowTrusted converts a *querypb.Row to []Value based on the types // in fields. It does not sanity check the values against the type. // Every place this function is called, a comment is needed that explains diff --git a/go/sqltypes/type.go b/go/sqltypes/type.go index 45edc7b62b5..39afa48a5c1 100644 --- a/go/sqltypes/type.go +++ b/go/sqltypes/type.go @@ -140,6 +140,8 @@ const ( Geometry = querypb.Type_GEOMETRY TypeJSON = querypb.Type_JSON Expression = querypb.Type_EXPRESSION + HexNum = querypb.Type_HEXNUM + HexVal = querypb.Type_HEXVAL ) // bit-shift the mysql flags by two byte so we diff --git a/go/sqltypes/type_test.go b/go/sqltypes/type_test.go index efaeb726121..c21e330a6f3 100644 --- a/go/sqltypes/type_test.go +++ b/go/sqltypes/type_test.go @@ -119,6 +119,12 @@ func TestTypeValues(t *testing.T) { }, { defined: Expression, expected: 31, + }, { + defined: HexNum, + expected: 32 | flagIsText, + }, { + defined: HexVal, + expected: 33 | flagIsText, }} for _, tcase := range testcases { if int(tcase.defined) != tcase.expected { @@ -162,6 +168,8 @@ func TestCategory(t *testing.T) { Geometry, TypeJSON, Expression, + HexNum, + HexVal, } for _, typ := range alltypes { matched := false @@ -192,7 +200,7 @@ func TestCategory(t *testing.T) { } matched = true } - if typ == Null || typ == Decimal || typ == Expression || typ == Bit { + if typ == Null || typ == Decimal || typ == Expression || typ == Bit || typ == HexNum || typ == HexVal { if matched { t.Errorf("%v matched more than one category", typ) } diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go index 8b8bf84ad5c..d79fb0e43cf 100644 --- a/go/sqltypes/value.go +++ b/go/sqltypes/value.go @@ -19,16 +19,21 @@ package sqltypes import ( "encoding/base64" + "encoding/hex" "encoding/json" "errors" "fmt" + "regexp" "strconv" "strings" "vitess.io/vitess/go/bytes2" "vitess.io/vitess/go/hack" + "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -79,7 +84,7 @@ func NewValue(typ querypb.Type, val []byte) (v Value, err error) { return NULL, err } return MakeTrusted(typ, val), nil - case IsQuoted(typ) || typ == Bit || typ == Null: + case IsQuoted(typ) || typ == Bit || typ == HexNum || typ == HexVal || typ == Null: return MakeTrusted(typ, val), nil } // All other types are unsafe or invalid. @@ -102,6 +107,16 @@ func MakeTrusted(typ querypb.Type, val []byte) Value { return Value{typ: typ, val: val} } +// NewHexNum builds an Hex Value. +func NewHexNum(v []byte) Value { + return MakeTrusted(HexNum, v) +} + +// NewHexVal builds a HexVal Value. +func NewHexVal(v []byte) Value { + return MakeTrusted(HexVal, v) +} + // NewInt64 builds an Int64 Value. func NewInt64(v int64) Value { return MakeTrusted(Int64, strconv.AppendInt(nil, v, 10)) @@ -200,6 +215,20 @@ func (v Value) ToBytes() []byte { if v.typ == Expression { return nil } + if v.typ == HexVal { + dv, err := v.decodeHexVal() + if err != nil { + log.Errorf("Unexpected error seen when returning MySQL representation of SQL Hex value: %v", err) + } + return dv + } + if v.typ == HexNum { + dv, err := v.decodeHexNum() + if err != nil { + log.Errorf("Unexpected error seen when returning MySQL representation of SQL Hex number: %v", err) + } + return dv + } return v.val } @@ -385,6 +414,38 @@ func (v *Value) UnmarshalJSON(b []byte) error { return err } +// decodeHexVal decodes the SQL hex value of the form x'A1' into a byte +// array matching what MySQL would return when querying the column where +// an INSERT was performed with x'A1' having been specified as a value +func (v *Value) decodeHexVal() ([]byte, error) { + match, err := regexp.Match("^x'.*'$", v.val) + if !match || err != nil { + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid hex value: %v", v.val) + } + hexBytes := v.val[2 : len(v.val)-1] + decodedHexBytes, err := hex.DecodeString(string(hexBytes)) + if err != nil { + return nil, err + } + return decodedHexBytes, nil +} + +// decodeHexNum decodes the SQL hex value of the form 0xA1 into a byte +// array matching what MySQL would return when querying the column where +// an INSERT was performed with 0xA1 having been specified as a value +func (v *Value) decodeHexNum() ([]byte, error) { + match, err := regexp.Match("^0x.*$", v.val) + if !match || err != nil { + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid hex number: %v", v.val) + } + hexBytes := v.val[2:] + decodedHexBytes, err := hex.DecodeString(string(hexBytes)) + if err != nil { + return nil, err + } + return decodedHexBytes, nil +} + func encodeBytesSQL(val []byte, b BinWriter) { buf := &bytes2.Buffer{} buf.WriteByte('\'') diff --git a/go/test/endtoend/vtgate/queries/normalize/main_test.go b/go/test/endtoend/vtgate/queries/normalize/main_test.go new file mode 100644 index 00000000000..7d7e6cd8011 --- /dev/null +++ b/go/test/endtoend/vtgate/queries/normalize/main_test.go @@ -0,0 +1,92 @@ +/* +Copyright 2021 The Vitess Authors. + +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 normalize + +import ( + "flag" + "os" + "testing" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/test/endtoend/cluster" +) + +var ( + clusterInstance *cluster.LocalProcessCluster + vtParams mysql.ConnParams + KeyspaceName = "ks_normalize" + Cell = "test_normalize" + SchemaSQL = ` +create table t1( + id bigint unsigned not null, + charcol char(10), + vcharcol varchar(50), + bincol binary(50), + varbincol varbinary(50), + floatcol float, + deccol decimal(5,2), + bitcol bit, + datecol date, + enumcol enum('small', 'medium', 'large'), + setcol set('a', 'b', 'c'), + jsoncol json, + geocol geometry, + primary key(id) +) Engine=InnoDB; +` +) + +func TestMain(m *testing.M) { + defer cluster.PanicHandler(nil) + flag.Parse() + + exitCode := func() int { + clusterInstance = cluster.NewCluster(Cell, "localhost") + defer clusterInstance.Teardown() + + // Start topo server + err := clusterInstance.StartTopo() + if err != nil { + return 1 + } + + // Start keyspace + keyspace := &cluster.Keyspace{ + Name: KeyspaceName, + SchemaSQL: SchemaSQL, + } + clusterInstance.VtGateExtraArgs = []string{} + clusterInstance.VtTabletExtraArgs = []string{} + err = clusterInstance.StartKeyspace(*keyspace, []string{"-"}, 1, false) + if err != nil { + return 1 + } + + // Start vtgate + err = clusterInstance.StartVtgate() + if err != nil { + return 1 + } + + vtParams = mysql.ConnParams{ + Host: clusterInstance.Hostname, + Port: clusterInstance.VtgateMySQLPort, + } + return m.Run() + }() + os.Exit(exitCode) +} diff --git a/go/test/endtoend/vtgate/queries/normalize/normalize_test.go b/go/test/endtoend/vtgate/queries/normalize/normalize_test.go new file mode 100644 index 00000000000..bf56beb1e63 --- /dev/null +++ b/go/test/endtoend/vtgate/queries/normalize/normalize_test.go @@ -0,0 +1,82 @@ +/* +Copyright 2021 The Vitess Authors. + +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 normalize + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/test/endtoend/vtgate/utils" +) + +func TestNormalizeAllFields(t *testing.T) { + conn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer conn.Close() + + insertQuery := string(`insert into t1 values (1, "chars", "variable chars", x'73757265', 0x676F, 0.33, 9.99, 1, "1976-06-08", "small", "b", "{\"key\":\"value\"}", point(1,5))`) + normalizedInsertQuery := string(`insert into t1 values (:vtg1, :vtg2, :vtg3, :vtg4, :vtg5, :vtg6, :vtg7, :vtg8, :vtg9, :vtg10, :vtg11, :vtg12, point(:vtg13, :vtg14))`) + selectQuery := "select * from t1" + utils.Exec(t, conn, insertQuery) + qr := utils.Exec(t, conn, selectQuery) + assert.Equal(t, 1, len(qr.Rows), "wrong number of table rows, expected 1 but had %d. Results: %v", len(qr.Rows), qr.Rows) + + // Now need to figure out the best way to check the normalized query in the planner cache... + results, err := getPlanCache(fmt.Sprintf("%s:%d", clusterInstance.Hostname, clusterInstance.VtgateProcess.Port)) + require.Nil(t, err) + found := false + for _, record := range results { + key := record["Key"].(string) + if key == normalizedInsertQuery { + found = true + break + } + } + assert.True(t, found, "correctly normalized record not found in planner cache") +} + +func getPlanCache(vtgateHostPort string) ([]map[string]interface{}, error) { + var results []map[string]interface{} + client := http.Client{ + Timeout: 10 * time.Second, + } + resp, err := client.Get(fmt.Sprintf("http://%s/debug/query_plans", vtgateHostPort)) + if err != nil { + return results, err + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return results, err + } + + err = json.Unmarshal(body, &results) + if err != nil { + return results, err + } + + return results, nil +} diff --git a/go/test/endtoend/vtgate/utils/utils.go b/go/test/endtoend/vtgate/utils/utils.go new file mode 100644 index 00000000000..7f6a8dc0c25 --- /dev/null +++ b/go/test/endtoend/vtgate/utils/utils.go @@ -0,0 +1,97 @@ +/* +Copyright 2021 The Vitess Authors. + +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 utils + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/utils" +) + +func AssertMatches(t *testing.T, conn *mysql.Conn, query, expected string) { + t.Helper() + qr := Exec(t, conn, query) + got := fmt.Sprintf("%v", qr.Rows) + diff := cmp.Diff(expected, got) + if diff != "" { + t.Errorf("Query: %s (-want +got):\n%s", query, diff) + } +} + +func AssertContainsError(t *testing.T, conn *mysql.Conn, query, expected string) { + t.Helper() + _, err := ExecAllowError(t, conn, query) + require.Error(t, err) + require.Contains(t, err.Error(), expected) +} + +func AssertMatchesNoOrder(t *testing.T, conn *mysql.Conn, query, expected string) { + t.Helper() + qr := Exec(t, conn, query) + actual := fmt.Sprintf("%v", qr.Rows) + assert.Equal(t, utils.SortString(expected), utils.SortString(actual), "for query: [%s] expected \n%s \nbut actual \n%s", query, expected, actual) +} + +func AssertIsEmpty(t *testing.T, conn *mysql.Conn, query string) { + t.Helper() + qr := Exec(t, conn, query) + assert.Empty(t, qr.Rows, "for query: "+query) +} + +func AssertFoundRowsValue(t *testing.T, conn *mysql.Conn, query, workload string, count int) { + Exec(t, conn, query) + qr := Exec(t, conn, "select found_rows()") + got := fmt.Sprintf("%v", qr.Rows) + want := fmt.Sprintf(`[[UINT64(%d)]]`, count) + assert.Equalf(t, want, got, "Workload: %s\nQuery:%s\n", workload, query) +} + +func AssertSingleRowIsReturned(t *testing.T, conn *mysql.Conn, predicate string, expectedKs string) { + t.Run(predicate, func(t *testing.T) { + qr, err := conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE "+predicate, 1000, true) + require.NoError(t, err) + assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back") + assert.Equal(t, expectedKs, qr.Rows[0][0].ToString()) + }) +} + +func AssertResultIsEmpty(t *testing.T, conn *mysql.Conn, pre string) { + t.Run(pre, func(t *testing.T) { + qr, err := conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE "+pre, 1000, true) + require.NoError(t, err) + assert.Empty(t, qr.Rows) + }) +} + +func Exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { + t.Helper() + qr, err := conn.ExecuteFetch(query, 1000, true) + require.NoError(t, err, "for query: "+query) + return qr +} + +func ExecAllowError(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { + t.Helper() + return conn.ExecuteFetch(query, 1000, true) +} diff --git a/go/vt/proto/query/query.pb.go b/go/vt/proto/query/query.pb.go index bec6552eb8c..f4418fdb98d 100644 --- a/go/vt/proto/query/query.pb.go +++ b/go/vt/proto/query/query.pb.go @@ -250,6 +250,12 @@ const ( // This type is for internal use only. // Properties: 31, None. Type_EXPRESSION Type = 31 + // HEXNUM specifies a HEXNUM type (unquoted varbinary). + // Properties: 32, IsText. + Type_HEXNUM Type = 4128 + // HEXVAL specifies a HEXVAL type (unquoted varbinary). + // Properties: 33, IsText. + Type_HEXVAL Type = 4129 ) var Type_name = map[int32]string{ @@ -285,6 +291,8 @@ var Type_name = map[int32]string{ 2077: "GEOMETRY", 2078: "JSON", 31: "EXPRESSION", + 4128: "HEXNUM", + 4129: "HEXVAL", } var Type_value = map[string]int32{ @@ -320,6 +328,8 @@ var Type_value = map[string]int32{ "GEOMETRY": 2077, "JSON": 2078, "EXPRESSION": 31, + "HEXNUM": 4128, + "HEXVAL": 4129, } func (x Type) String() string { @@ -4875,214 +4885,215 @@ func init() { func init() { proto.RegisterFile("query.proto", fileDescriptor_5c6ac9b241082464) } var fileDescriptor_5c6ac9b241082464 = []byte{ - // 3303 bytes of a gzipped FileDescriptorProto + // 3321 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0x4d, 0x90, 0x1b, 0x49, 0x56, 0xee, 0x2a, 0xfd, 0xb4, 0xf4, 0xd4, 0x52, 0x67, 0x67, 0x77, 0xdb, 0x9a, 0xf6, 0x8c, 0xa7, 0xb7, 0x76, 0x67, 0xd7, 0x18, 0x68, 0x7b, 0xda, 0x5e, 0x63, 0x66, 0x17, 0x98, 0x6a, 0x75, 0xb5, - 0x47, 0xb6, 0x54, 0x92, 0x53, 0x25, 0x7b, 0x3d, 0x41, 0x44, 0x45, 0x59, 0x4a, 0xab, 0x2b, 0xba, - 0x54, 0xa5, 0xae, 0xaa, 0x6e, 0x8f, 0x6e, 0x86, 0x65, 0x59, 0xfe, 0x59, 0xfe, 0x77, 0xd9, 0x60, - 0x83, 0x08, 0x0e, 0x04, 0x17, 0x22, 0xb8, 0x71, 0xe6, 0x30, 0x41, 0x70, 0x20, 0xe0, 0x08, 0x1c, - 0x58, 0x86, 0x20, 0xe0, 0xb4, 0x41, 0x70, 0xe0, 0xc0, 0x81, 0x20, 0xf2, 0xa7, 0x4a, 0x52, 0xb7, - 0xc6, 0xee, 0xf5, 0x32, 0xb1, 0x61, 0x8f, 0x6f, 0xf9, 0x7e, 0xf2, 0xe7, 0x7d, 0xf9, 0xf2, 0xbd, - 0x57, 0xa9, 0x14, 0x94, 0x0e, 0x8f, 0x68, 0x38, 0xde, 0x1a, 0x85, 0x41, 0x1c, 0xe0, 0x1c, 0x27, - 0x36, 0x2a, 0x71, 0x30, 0x0a, 0xfa, 0x4e, 0xec, 0x08, 0xf6, 0x46, 0xe9, 0x38, 0x0e, 0x47, 0x3d, - 0x41, 0x68, 0x5f, 0x53, 0x20, 0x6f, 0x39, 0xe1, 0x80, 0xc6, 0x78, 0x03, 0x0a, 0x07, 0x74, 0x1c, - 0x8d, 0x9c, 0x1e, 0xad, 0x2a, 0x9b, 0xca, 0xa5, 0x22, 0x49, 0x69, 0xbc, 0x06, 0xb9, 0x68, 0xdf, - 0x09, 0xfb, 0x55, 0x95, 0x0b, 0x04, 0x81, 0xbf, 0x08, 0xa5, 0xd8, 0x79, 0xe8, 0xd1, 0xd8, 0x8e, - 0xc7, 0x23, 0x5a, 0xcd, 0x6c, 0x2a, 0x97, 0x2a, 0xdb, 0x6b, 0x5b, 0xe9, 0x7c, 0x16, 0x17, 0x5a, - 0xe3, 0x11, 0x25, 0x10, 0xa7, 0x6d, 0x8c, 0x21, 0xdb, 0xa3, 0x9e, 0x57, 0xcd, 0xf2, 0xb1, 0x78, - 0x5b, 0xdb, 0x85, 0xca, 0x3d, 0xeb, 0x96, 0x13, 0xd3, 0x9a, 0xe3, 0x79, 0x34, 0xac, 0xef, 0xb2, - 0xe5, 0x1c, 0x45, 0x34, 0xf4, 0x9d, 0x61, 0xba, 0x9c, 0x84, 0xc6, 0xe7, 0x20, 0x3f, 0x08, 0x83, - 0xa3, 0x51, 0x54, 0x55, 0x37, 0x33, 0x97, 0x8a, 0x44, 0x52, 0xda, 0xcf, 0x02, 0x18, 0xc7, 0xd4, - 0x8f, 0xad, 0xe0, 0x80, 0xfa, 0xf8, 0x75, 0x28, 0xc6, 0xee, 0x90, 0x46, 0xb1, 0x33, 0x1c, 0xf1, - 0x21, 0x32, 0x64, 0xc2, 0xf8, 0x18, 0x93, 0x36, 0xa0, 0x30, 0x0a, 0x22, 0x37, 0x76, 0x03, 0x9f, - 0xdb, 0x53, 0x24, 0x29, 0xad, 0xfd, 0x34, 0xe4, 0xee, 0x39, 0xde, 0x11, 0xc5, 0x6f, 0x42, 0x96, - 0x1b, 0xac, 0x70, 0x83, 0x4b, 0x5b, 0x02, 0x74, 0x6e, 0x27, 0x17, 0xb0, 0xb1, 0x8f, 0x99, 0x26, - 0x1f, 0x7b, 0x89, 0x08, 0x42, 0x3b, 0x80, 0xa5, 0x1d, 0xd7, 0xef, 0xdf, 0x73, 0x42, 0x97, 0x81, - 0xf1, 0x9c, 0xc3, 0xe0, 0xcf, 0x41, 0x9e, 0x37, 0xa2, 0x6a, 0x66, 0x33, 0x73, 0xa9, 0xb4, 0xbd, - 0x24, 0x3b, 0xf2, 0xb5, 0x11, 0x29, 0xd3, 0xfe, 0x4a, 0x01, 0xd8, 0x09, 0x8e, 0xfc, 0xfe, 0x5d, - 0x26, 0xc4, 0x08, 0x32, 0xd1, 0xa1, 0x27, 0x81, 0x64, 0x4d, 0x7c, 0x07, 0x2a, 0x0f, 0x5d, 0xbf, - 0x6f, 0x1f, 0xcb, 0xe5, 0x08, 0x2c, 0x4b, 0xdb, 0x9f, 0x93, 0xc3, 0x4d, 0x3a, 0x6f, 0x4d, 0xaf, - 0x3a, 0x32, 0xfc, 0x38, 0x1c, 0x93, 0xf2, 0xc3, 0x69, 0xde, 0x46, 0x17, 0xf0, 0x69, 0x25, 0x36, - 0xe9, 0x01, 0x1d, 0x27, 0x93, 0x1e, 0xd0, 0x31, 0xfe, 0x91, 0x69, 0x8b, 0x4a, 0xdb, 0xab, 0xc9, - 0x5c, 0x53, 0x7d, 0xa5, 0x99, 0xef, 0xa8, 0x37, 0x15, 0xed, 0x2f, 0x16, 0xa1, 0x62, 0x7c, 0x40, - 0x7b, 0x47, 0x31, 0x6d, 0x8d, 0xd8, 0x1e, 0x44, 0xb8, 0x09, 0xcb, 0xae, 0xdf, 0xf3, 0x8e, 0xfa, - 0xb4, 0x6f, 0x3f, 0x72, 0xa9, 0xd7, 0x8f, 0xb8, 0x1f, 0x55, 0xd2, 0x75, 0xcf, 0xea, 0x6f, 0xd5, - 0xa5, 0xf2, 0x1e, 0xd7, 0x25, 0x15, 0x77, 0x86, 0xc6, 0x97, 0x61, 0xa5, 0xe7, 0xb9, 0xd4, 0x8f, - 0xed, 0x47, 0xcc, 0x5e, 0x3b, 0x0c, 0x1e, 0x47, 0xd5, 0xdc, 0xa6, 0x72, 0xa9, 0x40, 0x96, 0x85, - 0x60, 0x8f, 0xf1, 0x49, 0xf0, 0x38, 0xc2, 0xef, 0x40, 0xe1, 0x71, 0x10, 0x1e, 0x78, 0x81, 0xd3, - 0xaf, 0xe6, 0xf9, 0x9c, 0x17, 0xe7, 0xcf, 0x79, 0x5f, 0x6a, 0x91, 0x54, 0x1f, 0x5f, 0x02, 0x14, - 0x1d, 0x7a, 0x76, 0x44, 0x3d, 0xda, 0x8b, 0x6d, 0xcf, 0x1d, 0xba, 0x71, 0xb5, 0xc0, 0x5d, 0xb2, - 0x12, 0x1d, 0x7a, 0x1d, 0xce, 0x6e, 0x30, 0x2e, 0xb6, 0x61, 0x3d, 0x0e, 0x1d, 0x3f, 0x72, 0x7a, - 0x6c, 0x30, 0xdb, 0x8d, 0x02, 0xcf, 0xe1, 0xee, 0x58, 0xe4, 0x53, 0x5e, 0x9e, 0x3f, 0xa5, 0x35, - 0xe9, 0x52, 0x4f, 0x7a, 0x90, 0xb5, 0x78, 0x0e, 0x17, 0xbf, 0x0d, 0xeb, 0xd1, 0x81, 0x3b, 0xb2, - 0xf9, 0x38, 0xf6, 0xc8, 0x73, 0x7c, 0xbb, 0xe7, 0xf4, 0xf6, 0x69, 0x15, 0xb8, 0xd9, 0x98, 0x09, - 0xf9, 0xbe, 0xb7, 0x3d, 0xc7, 0xaf, 0x31, 0x09, 0x03, 0x9d, 0xe9, 0xf9, 0x34, 0xb4, 0x8f, 0x69, - 0x18, 0xb1, 0xd5, 0x94, 0x9e, 0x06, 0x7a, 0x5b, 0x28, 0xdf, 0x13, 0xba, 0xa4, 0x32, 0x9a, 0xa1, - 0xf1, 0x17, 0xe1, 0xfc, 0xbe, 0x13, 0xd9, 0xbd, 0x90, 0x3a, 0x31, 0xed, 0xdb, 0x31, 0x1d, 0x8e, - 0xec, 0x58, 0xf8, 0xe0, 0x12, 0x5f, 0xc3, 0xda, 0xbe, 0x13, 0xd5, 0x84, 0xd4, 0xa2, 0xc3, 0x11, - 0x8f, 0x23, 0x91, 0xf6, 0x25, 0xa8, 0xcc, 0xee, 0x26, 0x5e, 0x81, 0xb2, 0xf5, 0xa0, 0x6d, 0xd8, - 0xba, 0xb9, 0x6b, 0x9b, 0x7a, 0xd3, 0x40, 0x0b, 0xb8, 0x0c, 0x45, 0xce, 0x6a, 0x99, 0x8d, 0x07, - 0x48, 0xc1, 0x8b, 0x90, 0xd1, 0x1b, 0x0d, 0xa4, 0x6a, 0x37, 0xa1, 0x90, 0x6c, 0x0b, 0x5e, 0x86, - 0x52, 0xd7, 0xec, 0xb4, 0x8d, 0x5a, 0x7d, 0xaf, 0x6e, 0xec, 0xa2, 0x05, 0x5c, 0x80, 0x6c, 0xab, - 0x61, 0xb5, 0x91, 0x22, 0x5a, 0x7a, 0x1b, 0xa9, 0xac, 0xe7, 0xee, 0x8e, 0x8e, 0x32, 0xda, 0x9f, - 0x2a, 0xb0, 0x36, 0x0f, 0x5e, 0x5c, 0x82, 0xc5, 0x5d, 0x63, 0x4f, 0xef, 0x36, 0x2c, 0xb4, 0x80, - 0x57, 0x61, 0x99, 0x18, 0x6d, 0x43, 0xb7, 0xf4, 0x9d, 0x86, 0x61, 0x13, 0x43, 0xdf, 0x45, 0x0a, - 0xc6, 0x50, 0x61, 0x2d, 0xbb, 0xd6, 0x6a, 0x36, 0xeb, 0x96, 0x65, 0xec, 0x22, 0x15, 0xaf, 0x01, - 0xe2, 0xbc, 0xae, 0x39, 0xe1, 0x66, 0x30, 0x82, 0xa5, 0x8e, 0x41, 0xea, 0x7a, 0xa3, 0xfe, 0x3e, - 0x1b, 0x00, 0x65, 0xf1, 0x67, 0xe0, 0x8d, 0x5a, 0xcb, 0xec, 0xd4, 0x3b, 0x96, 0x61, 0x5a, 0x76, - 0xc7, 0xd4, 0xdb, 0x9d, 0xf7, 0x5a, 0x16, 0x1f, 0x59, 0x18, 0x97, 0xc3, 0x15, 0x00, 0xbd, 0x6b, - 0xb5, 0xc4, 0x38, 0x28, 0xaf, 0x1d, 0x42, 0x65, 0x16, 0x79, 0xb6, 0x2a, 0xb9, 0x44, 0xbb, 0xdd, - 0xd0, 0x4d, 0xd3, 0x20, 0x68, 0x01, 0xe7, 0x41, 0xbd, 0x77, 0x4d, 0xd8, 0x7a, 0x8b, 0xfa, 0xd7, - 0x91, 0xca, 0x06, 0x62, 0xad, 0x5b, 0x21, 0xa5, 0xfd, 0x31, 0xca, 0xb0, 0x75, 0x33, 0xba, 0x41, - 0x1f, 0xc5, 0xdb, 0xc4, 0x1d, 0xec, 0xc7, 0x28, 0xcb, 0xd6, 0xcd, 0x78, 0xf7, 0xdd, 0x78, 0x7f, - 0xcf, 0xf1, 0xbc, 0x87, 0x4e, 0xef, 0x00, 0xe5, 0x6e, 0x67, 0x0b, 0x0a, 0x52, 0x6f, 0x67, 0x0b, - 0x2a, 0xca, 0xdc, 0xce, 0x16, 0x32, 0x28, 0xab, 0xfd, 0xa5, 0x0a, 0x39, 0xbe, 0x3d, 0x2c, 0xce, - 0x4f, 0x45, 0x6f, 0xde, 0x4e, 0x63, 0x9e, 0xfa, 0x94, 0x98, 0xc7, 0x5d, 0x41, 0x46, 0x5f, 0x41, - 0xe0, 0x0b, 0x50, 0x0c, 0xc2, 0x81, 0x70, 0x12, 0x99, 0x37, 0x0a, 0x41, 0x38, 0xe0, 0x8e, 0xc1, - 0x62, 0x36, 0x4b, 0x37, 0x0f, 0x9d, 0x88, 0xf2, 0xa3, 0x5b, 0x24, 0x29, 0x8d, 0x5f, 0x03, 0xa6, - 0x67, 0xf3, 0x75, 0xe4, 0xb9, 0x6c, 0x31, 0x08, 0x07, 0x26, 0x5b, 0xca, 0x67, 0xa1, 0xdc, 0x0b, - 0xbc, 0xa3, 0xa1, 0x6f, 0x7b, 0xd4, 0x1f, 0xc4, 0xfb, 0xd5, 0xc5, 0x4d, 0xe5, 0x52, 0x99, 0x2c, - 0x09, 0x66, 0x83, 0xf3, 0x70, 0x15, 0x16, 0x7b, 0xfb, 0x4e, 0x18, 0x51, 0x71, 0x5c, 0xcb, 0x24, - 0x21, 0xf9, 0xac, 0xb4, 0xe7, 0x0e, 0x1d, 0x2f, 0xe2, 0x47, 0xb3, 0x4c, 0x52, 0x9a, 0x19, 0xf1, - 0xc8, 0x73, 0x06, 0x11, 0x3f, 0x52, 0x65, 0x22, 0x08, 0xfc, 0x26, 0x94, 0xe4, 0x84, 0x1c, 0x82, - 0x12, 0x5f, 0x0e, 0x08, 0x16, 0x43, 0x40, 0xfb, 0x09, 0xc8, 0x90, 0xe0, 0x31, 0x9b, 0x53, 0xac, - 0x28, 0xaa, 0x2a, 0x9b, 0x99, 0x4b, 0x98, 0x24, 0x24, 0xcb, 0x7b, 0x32, 0xf4, 0x8b, 0x8c, 0x90, - 0x04, 0xfb, 0x6f, 0x2b, 0x50, 0xe2, 0x47, 0x96, 0xd0, 0xe8, 0xc8, 0x8b, 0x59, 0x8a, 0x90, 0xb1, - 0x51, 0x99, 0x49, 0x11, 0x7c, 0x5f, 0x88, 0x94, 0x31, 0x00, 0x58, 0xb8, 0xb3, 0x9d, 0x47, 0x8f, - 0x68, 0x2f, 0xa6, 0x22, 0x13, 0x66, 0xc9, 0x12, 0x63, 0xea, 0x92, 0xc7, 0x90, 0x77, 0xfd, 0x88, - 0x86, 0xb1, 0xed, 0xf6, 0xf9, 0x9e, 0x64, 0x49, 0x41, 0x30, 0xea, 0x7d, 0x7c, 0x11, 0xb2, 0x3c, - 0x60, 0x66, 0xf9, 0x2c, 0x20, 0x67, 0x21, 0xc1, 0x63, 0xc2, 0xf9, 0xb7, 0xb3, 0x85, 0x1c, 0xca, - 0x6b, 0x5f, 0x86, 0x25, 0xbe, 0xb8, 0xfb, 0x4e, 0xe8, 0xbb, 0xfe, 0x80, 0xe7, 0xff, 0xa0, 0x2f, - 0xfc, 0xa2, 0x4c, 0x78, 0x9b, 0xd9, 0x3c, 0xa4, 0x51, 0xe4, 0x0c, 0xa8, 0xcc, 0xc7, 0x09, 0xa9, - 0xfd, 0x71, 0x06, 0x4a, 0x9d, 0x38, 0xa4, 0xce, 0x90, 0xa7, 0x76, 0xfc, 0x65, 0x80, 0x28, 0x76, - 0x62, 0x3a, 0xa4, 0x7e, 0x9c, 0xd8, 0xf7, 0xba, 0x9c, 0x79, 0x4a, 0x6f, 0xab, 0x93, 0x28, 0x91, - 0x29, 0x7d, 0xbc, 0x0d, 0x25, 0xca, 0xc4, 0x76, 0xcc, 0x4a, 0x04, 0x99, 0x86, 0x56, 0x92, 0x28, - 0x96, 0xd6, 0x0e, 0x04, 0x68, 0xda, 0xde, 0xf8, 0x8e, 0x0a, 0xc5, 0x74, 0x34, 0xac, 0x43, 0xa1, - 0xe7, 0xc4, 0x74, 0x10, 0x84, 0x63, 0x99, 0xb9, 0xdf, 0x7a, 0xda, 0xec, 0x5b, 0x35, 0xa9, 0x4c, - 0xd2, 0x6e, 0xf8, 0x0d, 0x10, 0xe5, 0x90, 0x70, 0x4b, 0x61, 0x6f, 0x91, 0x73, 0xb8, 0x63, 0xbe, - 0x03, 0x78, 0x14, 0xba, 0x43, 0x27, 0x1c, 0xdb, 0x07, 0x74, 0x9c, 0x64, 0xb9, 0xcc, 0x9c, 0x9d, - 0x44, 0x52, 0xef, 0x0e, 0x1d, 0xcb, 0x88, 0x78, 0x73, 0xb6, 0xaf, 0xf4, 0x96, 0xd3, 0xfb, 0x33, - 0xd5, 0x93, 0xd7, 0x0d, 0x51, 0x52, 0x21, 0xe4, 0xb8, 0x63, 0xb1, 0xa6, 0xf6, 0x05, 0x28, 0x24, - 0x8b, 0xc7, 0x45, 0xc8, 0x19, 0x61, 0x18, 0x84, 0x68, 0x81, 0x07, 0xc6, 0x66, 0x43, 0xc4, 0xd6, - 0xdd, 0x5d, 0x16, 0x5b, 0xff, 0x45, 0x4d, 0xd3, 0x34, 0xa1, 0x87, 0x47, 0x34, 0x8a, 0xf1, 0xcf, - 0xc0, 0x2a, 0xe5, 0x2e, 0xe4, 0x1e, 0x53, 0xbb, 0xc7, 0x6b, 0x3a, 0xe6, 0x40, 0x0a, 0xc7, 0x7b, - 0x79, 0x4b, 0x94, 0xa0, 0x49, 0xad, 0x47, 0x56, 0x52, 0x5d, 0xc9, 0xea, 0x63, 0x03, 0x56, 0xdd, - 0xe1, 0x90, 0xf6, 0x5d, 0x27, 0x9e, 0x1e, 0x40, 0x6c, 0xd8, 0x7a, 0x52, 0xf2, 0xcc, 0x94, 0x8c, - 0x64, 0x25, 0xed, 0x91, 0x0e, 0xf3, 0x16, 0xe4, 0x63, 0x5e, 0xde, 0x72, 0xdf, 0x2d, 0x6d, 0x97, - 0x93, 0x88, 0xc3, 0x99, 0x44, 0x0a, 0xf1, 0x17, 0x40, 0x14, 0xcb, 0x3c, 0xb6, 0x4c, 0x1c, 0x62, - 0x52, 0x03, 0x11, 0x21, 0xc7, 0x6f, 0x41, 0x65, 0x26, 0x3b, 0xf7, 0x39, 0x60, 0x19, 0x52, 0x9e, - 0x4e, 0xb5, 0x7d, 0x7c, 0x05, 0x16, 0x03, 0x91, 0x0b, 0x79, 0xd4, 0x99, 0xac, 0x78, 0x36, 0x51, - 0x92, 0x44, 0x8b, 0xc5, 0x86, 0x90, 0x46, 0x34, 0x3c, 0xa6, 0x7d, 0x36, 0xe8, 0x22, 0x1f, 0x14, - 0x12, 0x56, 0xbd, 0xaf, 0xfd, 0x14, 0x2c, 0xa7, 0x10, 0x47, 0xa3, 0xc0, 0x8f, 0x28, 0xbe, 0x0c, - 0xf9, 0x90, 0x9f, 0x77, 0x09, 0x2b, 0x96, 0x73, 0x4c, 0x45, 0x02, 0x22, 0x35, 0xb4, 0x3e, 0x2c, - 0x0b, 0x0e, 0x8b, 0xdf, 0x7c, 0x27, 0xf1, 0x5b, 0x90, 0xa3, 0xac, 0x71, 0x62, 0x53, 0x48, 0xbb, - 0xc6, 0xe5, 0x44, 0x48, 0xa7, 0x66, 0x51, 0x9f, 0x39, 0xcb, 0x7f, 0xaa, 0xb0, 0x2a, 0x57, 0xb9, - 0xe3, 0xc4, 0xbd, 0xfd, 0x17, 0xd4, 0x1b, 0x7e, 0x14, 0x16, 0x19, 0xdf, 0x4d, 0x4f, 0xce, 0x1c, - 0x7f, 0x48, 0x34, 0x98, 0x47, 0x38, 0x91, 0x3d, 0xb5, 0xfd, 0xb2, 0x7c, 0x2c, 0x3b, 0xd1, 0x54, - 0xd5, 0x30, 0xc7, 0x71, 0xf2, 0xcf, 0x70, 0x9c, 0xc5, 0xb3, 0x38, 0x8e, 0xb6, 0x0b, 0x6b, 0xb3, - 0x88, 0x4b, 0xe7, 0xf8, 0x31, 0x58, 0x14, 0x9b, 0x92, 0xc4, 0xc8, 0x79, 0xfb, 0x96, 0xa8, 0x68, - 0x1f, 0xaa, 0xb0, 0x26, 0xc3, 0xd7, 0xa7, 0xe3, 0x1c, 0x4f, 0xe1, 0x9c, 0x3b, 0xd3, 0x01, 0x3d, - 0xdb, 0xfe, 0x69, 0x35, 0x58, 0x3f, 0x81, 0xe3, 0x73, 0x1c, 0xd6, 0xef, 0x29, 0xb0, 0xb4, 0x43, - 0x07, 0xae, 0xff, 0x82, 0xee, 0xc2, 0x14, 0xb8, 0xd9, 0x33, 0x39, 0xf1, 0x08, 0xca, 0xd2, 0x5e, - 0x89, 0xd6, 0x69, 0xb4, 0x95, 0x79, 0xa7, 0xe5, 0x26, 0x2c, 0xc9, 0x0b, 0x08, 0xc7, 0x73, 0x9d, - 0x28, 0xb5, 0xe7, 0xc4, 0x0d, 0x84, 0xce, 0x84, 0x44, 0xde, 0x55, 0x70, 0x42, 0xfb, 0x37, 0x05, - 0xca, 0xb5, 0x60, 0x38, 0x74, 0xe3, 0x17, 0x14, 0xe3, 0xd3, 0x08, 0x65, 0xe7, 0xf9, 0xe3, 0xdb, - 0x50, 0x49, 0xcc, 0x94, 0xd0, 0x9e, 0xc8, 0x34, 0xca, 0xa9, 0x4c, 0xf3, 0xef, 0x0a, 0x2c, 0x93, - 0x40, 0x54, 0xf8, 0x2f, 0x37, 0x38, 0xd7, 0x00, 0x4d, 0x0c, 0x3d, 0x2b, 0x3c, 0xff, 0xa3, 0x40, - 0xa5, 0x1d, 0xd2, 0x91, 0x13, 0xd2, 0x97, 0x1a, 0x1d, 0x56, 0xa6, 0xf7, 0x63, 0x59, 0xe0, 0x14, - 0x09, 0x6f, 0x6b, 0x2b, 0xb0, 0x9c, 0xda, 0x2e, 0x00, 0xd3, 0xfe, 0x51, 0x81, 0x75, 0xe1, 0x62, - 0x52, 0xd2, 0x7f, 0x41, 0x61, 0x49, 0xec, 0xcd, 0x4e, 0xd9, 0x5b, 0x85, 0x73, 0x27, 0x6d, 0x93, - 0x66, 0x7f, 0x55, 0x85, 0xf3, 0x89, 0xf3, 0xbc, 0xe0, 0x86, 0xff, 0x00, 0xfe, 0xb0, 0x01, 0xd5, - 0xd3, 0x20, 0x48, 0x84, 0xbe, 0xa1, 0x42, 0x55, 0x5c, 0xe2, 0x4c, 0xd5, 0x41, 0x2f, 0x8f, 0x6f, - 0xe0, 0xb7, 0x61, 0x69, 0xe4, 0x84, 0xb1, 0xdb, 0x73, 0x47, 0x0e, 0xfb, 0x14, 0xcd, 0xf1, 0x32, - 0xeb, 0xc4, 0x00, 0x33, 0x2a, 0xda, 0x05, 0x78, 0x6d, 0x0e, 0x22, 0x12, 0xaf, 0xff, 0x55, 0x00, - 0x77, 0x62, 0x27, 0x8c, 0x3f, 0x05, 0x79, 0x69, 0xae, 0x33, 0xad, 0xc3, 0xea, 0x8c, 0xfd, 0xd3, - 0xb8, 0xd0, 0xf8, 0x53, 0x91, 0x92, 0x3e, 0x16, 0x97, 0x69, 0xfb, 0x25, 0x2e, 0xff, 0xac, 0xc0, - 0x46, 0x2d, 0x10, 0x17, 0xa2, 0x2f, 0xe5, 0x09, 0xd3, 0xde, 0x80, 0x0b, 0x73, 0x0d, 0x94, 0x00, - 0xfc, 0x93, 0x02, 0xe7, 0x08, 0x75, 0xfa, 0x2f, 0xa7, 0xf1, 0x77, 0xe1, 0xfc, 0x29, 0xe3, 0x64, - 0x8d, 0x72, 0x03, 0x0a, 0x43, 0x1a, 0x3b, 0xac, 0xc2, 0x95, 0x26, 0x6d, 0x24, 0xe3, 0x4e, 0xb4, - 0x9b, 0x52, 0x83, 0xa4, 0xba, 0xda, 0x77, 0x55, 0x58, 0xe5, 0x75, 0xf6, 0xab, 0x8f, 0xbc, 0x33, - 0xdd, 0xc2, 0xe4, 0x4f, 0x16, 0x7f, 0x4c, 0x61, 0x14, 0x52, 0x3b, 0xb9, 0x1d, 0x58, 0xe4, 0xbf, - 0x3e, 0xc2, 0x28, 0xa4, 0x77, 0x05, 0x47, 0xfb, 0x1b, 0x05, 0xd6, 0x66, 0x21, 0x4e, 0xbf, 0x68, - 0xfe, 0xbf, 0x6f, 0x5b, 0xe6, 0x84, 0x94, 0xcc, 0x59, 0x3e, 0x92, 0xb2, 0x67, 0xfe, 0x48, 0xfa, - 0x5b, 0x15, 0xaa, 0xd3, 0xc6, 0xbc, 0xba, 0xd3, 0x99, 0xbd, 0xd3, 0xf9, 0x7e, 0x6f, 0xf9, 0xb4, - 0xbf, 0x57, 0xe0, 0xb5, 0x39, 0x80, 0x7e, 0x7f, 0x2e, 0x32, 0x75, 0xb3, 0xa3, 0x3e, 0xf3, 0x66, - 0xe7, 0x93, 0x77, 0x92, 0x7f, 0x50, 0x60, 0xad, 0x29, 0xee, 0xea, 0xc5, 0xcd, 0xc7, 0x8b, 0x1b, - 0x83, 0xf9, 0x75, 0x7c, 0x76, 0xf2, 0x6b, 0x95, 0x56, 0x83, 0xf5, 0x13, 0xa6, 0x3d, 0xc7, 0x6d, - 0xce, 0x7f, 0x2b, 0xb0, 0x22, 0x47, 0xd1, 0x5f, 0xd8, 0xf2, 0x65, 0x0e, 0x3a, 0xf8, 0x22, 0x64, - 0xdc, 0x7e, 0x52, 0xf7, 0xce, 0xbe, 0x42, 0x60, 0x02, 0xed, 0x5d, 0xc0, 0xd3, 0x76, 0x3f, 0x07, - 0x74, 0xff, 0xa1, 0xc2, 0x3a, 0x11, 0xd1, 0xf7, 0xd5, 0xef, 0x0b, 0x3f, 0xe8, 0xef, 0x0b, 0x4f, - 0x4f, 0x5c, 0x1f, 0xf2, 0x62, 0x6a, 0x16, 0xea, 0x4f, 0x2e, 0x75, 0x9d, 0x48, 0xb4, 0x99, 0x53, - 0x89, 0xf6, 0xf9, 0xe3, 0xd1, 0x87, 0x2a, 0x6c, 0x48, 0x43, 0x5e, 0xd5, 0x3a, 0x67, 0xf7, 0x88, - 0xfc, 0x29, 0x8f, 0xf8, 0x2f, 0x05, 0x2e, 0xcc, 0x05, 0xf2, 0x87, 0x5e, 0xd1, 0x9c, 0xf0, 0x9e, - 0xec, 0x33, 0xbd, 0x27, 0x77, 0x66, 0xef, 0xf9, 0xba, 0x0a, 0x15, 0x42, 0x3d, 0xea, 0x44, 0x2f, - 0xf9, 0xed, 0xde, 0x09, 0x0c, 0x73, 0xa7, 0xee, 0x39, 0x57, 0x60, 0x39, 0x05, 0x42, 0x7e, 0x70, - 0xf1, 0x0f, 0x74, 0x96, 0x07, 0xdf, 0xa3, 0x8e, 0x17, 0x27, 0x95, 0xa0, 0xf6, 0x27, 0x2a, 0x94, - 0x09, 0xe3, 0xb8, 0x43, 0xda, 0x89, 0x9d, 0x38, 0xc2, 0x9f, 0x81, 0xa5, 0x7d, 0xae, 0x62, 0x4f, - 0x3c, 0xa4, 0x48, 0x4a, 0x82, 0x27, 0x7e, 0x7d, 0xdc, 0x86, 0xf5, 0x88, 0xf6, 0x02, 0xbf, 0x1f, - 0xd9, 0x0f, 0xe9, 0xbe, 0xeb, 0xf7, 0xed, 0xa1, 0x13, 0xc5, 0x34, 0xe4, 0xb0, 0x94, 0xc9, 0xaa, - 0x14, 0xee, 0x70, 0x59, 0x93, 0x8b, 0xf0, 0x55, 0x58, 0x7b, 0xe8, 0xfa, 0x5e, 0x30, 0xb0, 0x47, - 0x9e, 0x33, 0xa6, 0x61, 0x64, 0xf7, 0x82, 0x23, 0x5f, 0xe0, 0x91, 0x23, 0x58, 0xc8, 0xda, 0x42, - 0x54, 0x63, 0x12, 0xfc, 0x3e, 0x5c, 0x9e, 0x3b, 0x8b, 0xfd, 0xc8, 0xf5, 0x62, 0x1a, 0xd2, 0xbe, - 0x1d, 0xd2, 0x91, 0xe7, 0xf6, 0xc4, 0x0b, 0x2b, 0x01, 0xd4, 0xe7, 0xe7, 0x4c, 0xbd, 0x27, 0xd5, - 0xc9, 0x44, 0x1b, 0x5f, 0x80, 0x62, 0x6f, 0x74, 0x64, 0x1f, 0xf1, 0x47, 0x0b, 0x0c, 0x3f, 0x85, - 0x14, 0x7a, 0xa3, 0xa3, 0x2e, 0xa3, 0x31, 0x82, 0xcc, 0xe1, 0x48, 0x04, 0x67, 0x85, 0xb0, 0xa6, - 0xf6, 0x3d, 0x05, 0x2a, 0xfa, 0x60, 0x10, 0xd2, 0x81, 0x13, 0x4b, 0x98, 0xae, 0xc2, 0x9a, 0x80, - 0x64, 0x6c, 0x4b, 0x77, 0x15, 0xf6, 0x28, 0xc2, 0x1e, 0x29, 0x13, 0xbe, 0x2a, 0xec, 0xb9, 0x0e, - 0xe7, 0x8e, 0xfc, 0xb9, 0x7d, 0x54, 0xde, 0x67, 0x2d, 0x95, 0x4e, 0xf7, 0xfa, 0x49, 0x78, 0x6d, - 0x3e, 0x0a, 0x43, 0x57, 0xbc, 0x72, 0x2c, 0x93, 0x73, 0x73, 0x8c, 0x6e, 0xba, 0xfe, 0x53, 0xba, - 0x3a, 0x1f, 0x70, 0xbc, 0x3e, 0xa6, 0xab, 0xf3, 0x81, 0xf6, 0x67, 0xe9, 0x6f, 0x8a, 0x89, 0xbb, - 0xa4, 0x81, 0x23, 0x71, 0x64, 0xe5, 0x69, 0x8e, 0x5c, 0x85, 0x45, 0xe6, 0x8c, 0xae, 0x3f, 0xe0, - 0xc6, 0x15, 0x48, 0x42, 0xe2, 0x0e, 0x7c, 0x5e, 0xda, 0x4e, 0x3f, 0x88, 0x69, 0xe8, 0x3b, 0x9e, - 0x37, 0xb6, 0xc5, 0xf5, 0xa3, 0xcf, 0x1f, 0x94, 0xa5, 0xaf, 0x3e, 0x45, 0xf8, 0xf8, 0xac, 0xd0, - 0x36, 0x52, 0x65, 0x92, 0xea, 0x5a, 0xe9, 0x7b, 0xd0, 0x2f, 0x41, 0x25, 0x94, 0x4e, 0x6c, 0x47, - 0x6c, 0x7b, 0x64, 0xc8, 0x5d, 0x4b, 0x5e, 0x4d, 0x4c, 0x7b, 0x38, 0x29, 0x87, 0x33, 0x0e, 0xff, - 0xdc, 0x01, 0xe7, 0x76, 0xb6, 0x90, 0x47, 0x8b, 0xda, 0x9f, 0x2b, 0xb0, 0x3a, 0xe7, 0xdb, 0x3d, - 0xbd, 0x18, 0x50, 0xa6, 0xee, 0x1d, 0x7f, 0x1c, 0x72, 0xfc, 0x41, 0x8b, 0x7c, 0x43, 0x75, 0xfe, - 0xf4, 0xa7, 0x3f, 0x7f, 0x7c, 0x42, 0x84, 0x16, 0x3b, 0x8b, 0xdc, 0x26, 0xf9, 0xda, 0x4e, 0x42, - 0x52, 0x62, 0x3c, 0xf9, 0xc4, 0xee, 0xd4, 0x4d, 0x66, 0xf6, 0x99, 0x37, 0x99, 0x97, 0x7f, 0x3b, - 0x03, 0xc5, 0xe6, 0xb8, 0x73, 0xe8, 0xed, 0x79, 0xce, 0x80, 0xbf, 0x0e, 0x69, 0xb6, 0xad, 0x07, - 0x68, 0x01, 0xaf, 0x40, 0xd9, 0x6c, 0x59, 0xb6, 0xd9, 0x6d, 0x34, 0xec, 0xbd, 0x86, 0x7e, 0x0b, - 0x29, 0x18, 0xc1, 0x52, 0x9b, 0xd4, 0xed, 0x3b, 0xc6, 0x03, 0xc1, 0x51, 0xf1, 0x2a, 0x2c, 0x77, - 0xcd, 0xfa, 0xdd, 0xae, 0x31, 0x61, 0x66, 0xf1, 0x3a, 0xac, 0x34, 0xbb, 0x0d, 0xab, 0xde, 0x6e, - 0x4c, 0xb1, 0x0b, 0xb8, 0x0c, 0xc5, 0x9d, 0x46, 0x6b, 0x47, 0x90, 0x88, 0x8d, 0xdf, 0x35, 0x3b, - 0xf5, 0x5b, 0xa6, 0xb1, 0x2b, 0x58, 0x9b, 0x8c, 0xf5, 0xbe, 0x41, 0x5a, 0x7b, 0xf5, 0x64, 0xca, - 0x77, 0x31, 0x82, 0xd2, 0x4e, 0xdd, 0xd4, 0x89, 0x1c, 0xe5, 0x89, 0x82, 0x2b, 0x50, 0x34, 0xcc, - 0x6e, 0x53, 0xd2, 0x2a, 0xae, 0xc2, 0xaa, 0xde, 0xb5, 0x5a, 0x76, 0xdd, 0xac, 0x11, 0xa3, 0x69, - 0x98, 0x96, 0x94, 0x64, 0xf1, 0x2a, 0x54, 0xac, 0x7a, 0xd3, 0xe8, 0x58, 0x7a, 0xb3, 0x2d, 0x99, - 0x6c, 0x15, 0x85, 0x8e, 0x91, 0xe8, 0x20, 0xbc, 0x01, 0xeb, 0x66, 0xcb, 0x4e, 0x9e, 0xd6, 0xdd, - 0xd3, 0x1b, 0x5d, 0x43, 0xca, 0x36, 0xf1, 0x79, 0xc0, 0x2d, 0xd3, 0xee, 0xb6, 0x77, 0x75, 0xcb, - 0xb0, 0xcd, 0xd6, 0x7d, 0x29, 0x78, 0x17, 0x57, 0xa0, 0x30, 0x59, 0xc1, 0x13, 0x86, 0x42, 0xb9, - 0xad, 0x13, 0x6b, 0x62, 0xec, 0x93, 0x27, 0x0c, 0x2c, 0xb8, 0x45, 0x5a, 0xdd, 0xf6, 0x44, 0x6d, - 0x05, 0x4a, 0x12, 0x2c, 0xc9, 0xca, 0x32, 0xd6, 0x4e, 0xdd, 0xac, 0xa5, 0xeb, 0x7b, 0x52, 0xd8, - 0x50, 0x91, 0x72, 0xf9, 0x00, 0xb2, 0x7c, 0x3b, 0x0a, 0x90, 0x35, 0x5b, 0xa6, 0x81, 0x16, 0xf0, - 0x32, 0x40, 0xbd, 0x53, 0x37, 0x2d, 0xe3, 0x16, 0xd1, 0x1b, 0xcc, 0x6c, 0xce, 0x48, 0x00, 0x64, - 0xd6, 0x2e, 0xc1, 0x62, 0xbd, 0xb3, 0xd7, 0x68, 0xe9, 0x96, 0x34, 0xb3, 0xde, 0xb9, 0xdb, 0x6d, - 0x59, 0x4c, 0x88, 0x70, 0x09, 0xf2, 0xf5, 0x8e, 0x65, 0x7c, 0xc5, 0x62, 0x76, 0x71, 0x99, 0x40, - 0x15, 0x3d, 0x79, 0xf7, 0xf2, 0xb7, 0x32, 0x90, 0xe5, 0xcf, 0xb9, 0xcb, 0x50, 0xe4, 0xbb, 0x6d, - 0x3d, 0x68, 0xb3, 0x29, 0x8b, 0x90, 0xad, 0x9b, 0xd6, 0x4d, 0xf4, 0x73, 0x2a, 0x06, 0xc8, 0x75, - 0x79, 0xfb, 0xe7, 0xf3, 0xac, 0x5d, 0x37, 0xad, 0xb7, 0x6f, 0xa0, 0xaf, 0xaa, 0x6c, 0xd8, 0xae, - 0x20, 0x7e, 0x21, 0x11, 0x6c, 0x5f, 0x47, 0x5f, 0x4b, 0x05, 0xdb, 0xd7, 0xd1, 0x2f, 0x26, 0x82, - 0x6b, 0xdb, 0xe8, 0xeb, 0xa9, 0xe0, 0xda, 0x36, 0xfa, 0xa5, 0x44, 0x70, 0xe3, 0x3a, 0xfa, 0xe5, - 0x54, 0x70, 0xe3, 0x3a, 0xfa, 0x95, 0x3c, 0xb3, 0x85, 0x5b, 0x72, 0x6d, 0x1b, 0xfd, 0x6a, 0x21, - 0xa5, 0x6e, 0x5c, 0x47, 0xbf, 0x56, 0x60, 0xfb, 0x9f, 0xee, 0x2a, 0xfa, 0x75, 0xc4, 0x96, 0xc9, - 0x36, 0x08, 0xfd, 0x06, 0x6f, 0x32, 0x11, 0xfa, 0x4d, 0xc4, 0x6c, 0x64, 0x5c, 0x4e, 0x7e, 0x83, - 0x4b, 0x1e, 0x18, 0x3a, 0x41, 0xbf, 0x95, 0x17, 0x8f, 0x3d, 0x6b, 0xf5, 0xa6, 0xde, 0x40, 0x98, - 0xf7, 0x60, 0xa8, 0xfc, 0xce, 0x55, 0xd6, 0x64, 0xee, 0x89, 0x7e, 0xb7, 0xcd, 0x26, 0xbc, 0xa7, - 0x93, 0xda, 0x7b, 0x3a, 0x41, 0xbf, 0x77, 0x95, 0x4d, 0x78, 0x4f, 0x27, 0x12, 0xaf, 0xdf, 0x6f, - 0x33, 0x45, 0x2e, 0xfa, 0x83, 0xab, 0x6c, 0xd1, 0x92, 0xff, 0xcd, 0x36, 0x2e, 0x40, 0x66, 0xa7, - 0x6e, 0xa1, 0x6f, 0xf1, 0xd9, 0x98, 0x8b, 0xa2, 0x3f, 0x44, 0x8c, 0xd9, 0x31, 0x2c, 0xf4, 0x6d, - 0xc6, 0xcc, 0x59, 0xdd, 0x76, 0xc3, 0x40, 0xaf, 0xb3, 0xc5, 0xdd, 0x32, 0x5a, 0x4d, 0xc3, 0x22, - 0x0f, 0xd0, 0x1f, 0x71, 0xf5, 0xdb, 0x9d, 0x96, 0x89, 0xbe, 0x83, 0x70, 0x05, 0xc0, 0xf8, 0x4a, - 0x9b, 0x18, 0x9d, 0x4e, 0xbd, 0x65, 0xa2, 0x37, 0x2f, 0xef, 0x01, 0x3a, 0x19, 0x0e, 0x98, 0x01, - 0x5d, 0xf3, 0x8e, 0xd9, 0xba, 0x6f, 0xa2, 0x05, 0x46, 0xb4, 0x89, 0xd1, 0xd6, 0x89, 0x81, 0x14, - 0x0c, 0x90, 0x97, 0x4f, 0x48, 0x55, 0xbc, 0x04, 0x05, 0xd2, 0x6a, 0x34, 0x76, 0xf4, 0xda, 0x1d, - 0x94, 0xd9, 0x31, 0xfe, 0xfa, 0xa3, 0x8b, 0xca, 0xdf, 0x7d, 0x74, 0x51, 0xf9, 0xee, 0x47, 0x17, - 0x95, 0x6f, 0xfe, 0xeb, 0xc5, 0x05, 0x58, 0x76, 0x83, 0xad, 0x63, 0x37, 0xa6, 0x51, 0x24, 0xfe, - 0x40, 0xf0, 0xbe, 0x26, 0x29, 0x37, 0xb8, 0x22, 0x5a, 0x57, 0x06, 0xc1, 0x95, 0xe3, 0xf8, 0x0a, - 0x97, 0x5e, 0xe1, 0x11, 0xe4, 0x61, 0x9e, 0x13, 0xd7, 0xfe, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xc4, - 0x64, 0x72, 0x89, 0x9e, 0x30, 0x00, 0x00, + 0x47, 0xb6, 0x54, 0x92, 0x53, 0xa5, 0xf6, 0x78, 0x82, 0x88, 0x8a, 0xb2, 0x94, 0x56, 0x57, 0x74, + 0xa9, 0x4a, 0xae, 0xaa, 0x6e, 0x8f, 0x6e, 0x86, 0x65, 0x59, 0xfe, 0x59, 0xfe, 0x17, 0x36, 0xd8, + 0x58, 0x82, 0x03, 0xc1, 0x85, 0x08, 0x82, 0x0b, 0x67, 0x0e, 0x13, 0x04, 0x07, 0x02, 0x8e, 0xc0, + 0x81, 0x65, 0x08, 0x02, 0x4e, 0x1b, 0x04, 0x07, 0x0e, 0x1c, 0x08, 0x22, 0x7f, 0xaa, 0x24, 0x75, + 0x6b, 0xec, 0x5e, 0x2f, 0x13, 0x1b, 0xf6, 0xcc, 0x2d, 0xdf, 0x4f, 0xfe, 0xbc, 0x2f, 0x5f, 0xbe, + 0xf7, 0x2a, 0x95, 0x82, 0xd2, 0xa3, 0x23, 0x1a, 0x8e, 0xb7, 0x46, 0x61, 0x10, 0x07, 0x38, 0xc7, + 0x89, 0x8d, 0x4a, 0x1c, 0x8c, 0x82, 0xbe, 0x13, 0x3b, 0x82, 0xbd, 0x51, 0x3a, 0x8e, 0xc3, 0x51, + 0x4f, 0x10, 0xda, 0x57, 0x15, 0xc8, 0x5b, 0x4e, 0x38, 0xa0, 0x31, 0xde, 0x80, 0xc2, 0x21, 0x1d, + 0x47, 0x23, 0xa7, 0x47, 0xab, 0xca, 0xa6, 0x72, 0xa9, 0x48, 0x52, 0x1a, 0xaf, 0x41, 0x2e, 0x3a, + 0x70, 0xc2, 0x7e, 0x55, 0xe5, 0x02, 0x41, 0xe0, 0x2f, 0x42, 0x29, 0x76, 0x1e, 0x78, 0x34, 0xb6, + 0xe3, 0xf1, 0x88, 0x56, 0x33, 0x9b, 0xca, 0xa5, 0xca, 0xf6, 0xda, 0x56, 0x3a, 0x9f, 0xc5, 0x85, + 0xd6, 0x78, 0x44, 0x09, 0xc4, 0x69, 0x1b, 0x63, 0xc8, 0xf6, 0xa8, 0xe7, 0x55, 0xb3, 0x7c, 0x2c, + 0xde, 0xd6, 0x76, 0xa1, 0xb2, 0x6f, 0xdd, 0x72, 0x62, 0x5a, 0x73, 0x3c, 0x8f, 0x86, 0xf5, 0x5d, + 0xb6, 0x9c, 0xa3, 0x88, 0x86, 0xbe, 0x33, 0x4c, 0x97, 0x93, 0xd0, 0xf8, 0x1c, 0xe4, 0x07, 0x61, + 0x70, 0x34, 0x8a, 0xaa, 0xea, 0x66, 0xe6, 0x52, 0x91, 0x48, 0x4a, 0xfb, 0x69, 0x00, 0xe3, 0x98, + 0xfa, 0xb1, 0x15, 0x1c, 0x52, 0x1f, 0xbf, 0x0a, 0xc5, 0xd8, 0x1d, 0xd2, 0x28, 0x76, 0x86, 0x23, + 0x3e, 0x44, 0x86, 0x4c, 0x18, 0x1f, 0x61, 0xd2, 0x06, 0x14, 0x46, 0x41, 0xe4, 0xc6, 0x6e, 0xe0, + 0x73, 0x7b, 0x8a, 0x24, 0xa5, 0xb5, 0x9f, 0x84, 0xdc, 0xbe, 0xe3, 0x1d, 0x51, 0xfc, 0x3a, 0x64, + 0xb9, 0xc1, 0x0a, 0x37, 0xb8, 0xb4, 0x25, 0x40, 0xe7, 0x76, 0x72, 0x01, 0x1b, 0xfb, 0x98, 0x69, + 0xf2, 0xb1, 0x97, 0x88, 0x20, 0xb4, 0x43, 0x58, 0xda, 0x71, 0xfd, 0xfe, 0xbe, 0x13, 0xba, 0x0c, + 0x8c, 0xe7, 0x1c, 0x06, 0x7f, 0x0e, 0xf2, 0xbc, 0x11, 0x55, 0x33, 0x9b, 0x99, 0x4b, 0xa5, 0xed, + 0x25, 0xd9, 0x91, 0xaf, 0x8d, 0x48, 0x99, 0xf6, 0x57, 0x0a, 0xc0, 0x4e, 0x70, 0xe4, 0xf7, 0xef, + 0x32, 0x21, 0x46, 0x90, 0x89, 0x1e, 0x79, 0x12, 0x48, 0xd6, 0xc4, 0x77, 0xa0, 0xf2, 0xc0, 0xf5, + 0xfb, 0xf6, 0xb1, 0x5c, 0x8e, 0xc0, 0xb2, 0xb4, 0xfd, 0x39, 0x39, 0xdc, 0xa4, 0xf3, 0xd6, 0xf4, + 0xaa, 0x23, 0xc3, 0x8f, 0xc3, 0x31, 0x29, 0x3f, 0x98, 0xe6, 0x6d, 0x74, 0x01, 0x9f, 0x56, 0x62, + 0x93, 0x1e, 0xd2, 0x71, 0x32, 0xe9, 0x21, 0x1d, 0xe3, 0x1f, 0x9a, 0xb6, 0xa8, 0xb4, 0xbd, 0x9a, + 0xcc, 0x35, 0xd5, 0x57, 0x9a, 0xf9, 0x96, 0x7a, 0x53, 0xd1, 0xfe, 0x7c, 0x11, 0x2a, 0xc6, 0xfb, + 0xb4, 0x77, 0x14, 0xd3, 0xd6, 0x88, 0xed, 0x41, 0x84, 0x9b, 0xb0, 0xec, 0xfa, 0x3d, 0xef, 0xa8, + 0x4f, 0xfb, 0xf6, 0x43, 0x97, 0x7a, 0xfd, 0x88, 0xfb, 0x51, 0x25, 0x5d, 0xf7, 0xac, 0xfe, 0x56, + 0x5d, 0x2a, 0xef, 0x71, 0x5d, 0x52, 0x71, 0x67, 0x68, 0x7c, 0x19, 0x56, 0x7a, 0x9e, 0x4b, 0xfd, + 0xd8, 0x7e, 0xc8, 0xec, 0xb5, 0xc3, 0xe0, 0x71, 0x54, 0xcd, 0x6d, 0x2a, 0x97, 0x0a, 0x64, 0x59, + 0x08, 0xf6, 0x18, 0x9f, 0x04, 0x8f, 0x23, 0xfc, 0x16, 0x14, 0x1e, 0x07, 0xe1, 0xa1, 0x17, 0x38, + 0xfd, 0x6a, 0x9e, 0xcf, 0x79, 0x71, 0xfe, 0x9c, 0xf7, 0xa4, 0x16, 0x49, 0xf5, 0xf1, 0x25, 0x40, + 0xd1, 0x23, 0xcf, 0x8e, 0xa8, 0x47, 0x7b, 0xb1, 0xed, 0xb9, 0x43, 0x37, 0xae, 0x16, 0xb8, 0x4b, + 0x56, 0xa2, 0x47, 0x5e, 0x87, 0xb3, 0x1b, 0x8c, 0x8b, 0x6d, 0x58, 0x8f, 0x43, 0xc7, 0x8f, 0x9c, + 0x1e, 0x1b, 0xcc, 0x76, 0xa3, 0xc0, 0x73, 0xb8, 0x3b, 0x16, 0xf9, 0x94, 0x97, 0xe7, 0x4f, 0x69, + 0x4d, 0xba, 0xd4, 0x93, 0x1e, 0x64, 0x2d, 0x9e, 0xc3, 0xc5, 0x6f, 0xc2, 0x7a, 0x74, 0xe8, 0x8e, + 0x6c, 0x3e, 0x8e, 0x3d, 0xf2, 0x1c, 0xdf, 0xee, 0x39, 0xbd, 0x03, 0x5a, 0x05, 0x6e, 0x36, 0x66, + 0x42, 0xbe, 0xef, 0x6d, 0xcf, 0xf1, 0x6b, 0x4c, 0xc2, 0x40, 0x67, 0x7a, 0x3e, 0x0d, 0xed, 0x63, + 0x1a, 0x46, 0x6c, 0x35, 0xa5, 0xa7, 0x81, 0xde, 0x16, 0xca, 0xfb, 0x42, 0x97, 0x54, 0x46, 0x33, + 0x34, 0xfe, 0x22, 0x9c, 0x3f, 0x70, 0x22, 0xbb, 0x17, 0x52, 0x27, 0xa6, 0x7d, 0x3b, 0xa6, 0xc3, + 0x91, 0x1d, 0x0b, 0x1f, 0x5c, 0xe2, 0x6b, 0x58, 0x3b, 0x70, 0xa2, 0x9a, 0x90, 0x5a, 0x74, 0x38, + 0xe2, 0x71, 0x24, 0xd2, 0xbe, 0x04, 0x95, 0xd9, 0xdd, 0xc4, 0x2b, 0x50, 0xb6, 0xee, 0xb7, 0x0d, + 0x5b, 0x37, 0x77, 0x6d, 0x53, 0x6f, 0x1a, 0x68, 0x01, 0x97, 0xa1, 0xc8, 0x59, 0x2d, 0xb3, 0x71, + 0x1f, 0x29, 0x78, 0x11, 0x32, 0x7a, 0xa3, 0x81, 0x54, 0xed, 0x26, 0x14, 0x92, 0x6d, 0xc1, 0xcb, + 0x50, 0xea, 0x9a, 0x9d, 0xb6, 0x51, 0xab, 0xef, 0xd5, 0x8d, 0x5d, 0xb4, 0x80, 0x0b, 0x90, 0x6d, + 0x35, 0xac, 0x36, 0x52, 0x44, 0x4b, 0x6f, 0x23, 0x95, 0xf5, 0xdc, 0xdd, 0xd1, 0x51, 0x46, 0xfb, + 0x13, 0x05, 0xd6, 0xe6, 0xc1, 0x8b, 0x4b, 0xb0, 0xb8, 0x6b, 0xec, 0xe9, 0xdd, 0x86, 0x85, 0x16, + 0xf0, 0x2a, 0x2c, 0x13, 0xa3, 0x6d, 0xe8, 0x96, 0xbe, 0xd3, 0x30, 0x6c, 0x62, 0xe8, 0xbb, 0x48, + 0xc1, 0x18, 0x2a, 0xac, 0x65, 0xd7, 0x5a, 0xcd, 0x66, 0xdd, 0xb2, 0x8c, 0x5d, 0xa4, 0xe2, 0x35, + 0x40, 0x9c, 0xd7, 0x35, 0x27, 0xdc, 0x0c, 0x46, 0xb0, 0xd4, 0x31, 0x48, 0x5d, 0x6f, 0xd4, 0xdf, + 0x63, 0x03, 0xa0, 0x2c, 0xfe, 0x0c, 0xbc, 0x56, 0x6b, 0x99, 0x9d, 0x7a, 0xc7, 0x32, 0x4c, 0xcb, + 0xee, 0x98, 0x7a, 0xbb, 0xf3, 0x4e, 0xcb, 0xe2, 0x23, 0x0b, 0xe3, 0x72, 0xb8, 0x02, 0xa0, 0x77, + 0xad, 0x96, 0x18, 0x07, 0xe5, 0xb5, 0x47, 0x50, 0x99, 0x45, 0x9e, 0xad, 0x4a, 0x2e, 0xd1, 0x6e, + 0x37, 0x74, 0xd3, 0x34, 0x08, 0x5a, 0xc0, 0x79, 0x50, 0xf7, 0xaf, 0x09, 0x5b, 0x6f, 0x51, 0xff, + 0x3a, 0x52, 0xd9, 0x40, 0xac, 0x75, 0x2b, 0xa4, 0xb4, 0x3f, 0x46, 0x19, 0xb6, 0x6e, 0x46, 0x37, + 0xe8, 0xc3, 0x78, 0x9b, 0xb8, 0x83, 0x83, 0x18, 0x65, 0xd9, 0xba, 0x19, 0xef, 0x9e, 0x1b, 0x1f, + 0xec, 0x39, 0x9e, 0xf7, 0xc0, 0xe9, 0x1d, 0xa2, 0xdc, 0xed, 0x6c, 0x41, 0x41, 0xea, 0xed, 0x6c, + 0x41, 0x45, 0x99, 0xdb, 0xd9, 0x42, 0x06, 0x65, 0xb5, 0xbf, 0x54, 0x21, 0xc7, 0xb7, 0x87, 0xc5, + 0xf9, 0xa9, 0xe8, 0xcd, 0xdb, 0x69, 0xcc, 0x53, 0x9f, 0x12, 0xf3, 0xb8, 0x2b, 0xc8, 0xe8, 0x2b, + 0x08, 0x7c, 0x01, 0x8a, 0x41, 0x38, 0x10, 0x4e, 0x22, 0xf3, 0x46, 0x21, 0x08, 0x07, 0xdc, 0x31, + 0x58, 0xcc, 0x66, 0xe9, 0xe6, 0x81, 0x13, 0x51, 0x7e, 0x74, 0x8b, 0x24, 0xa5, 0xf1, 0x2b, 0xc0, + 0xf4, 0x6c, 0xbe, 0x8e, 0x3c, 0x97, 0x2d, 0x06, 0xe1, 0xc0, 0x64, 0x4b, 0xf9, 0x2c, 0x94, 0x7b, + 0x81, 0x77, 0x34, 0xf4, 0x6d, 0x8f, 0xfa, 0x83, 0xf8, 0xa0, 0xba, 0xb8, 0xa9, 0x5c, 0x2a, 0x93, + 0x25, 0xc1, 0x6c, 0x70, 0x1e, 0xae, 0xc2, 0x62, 0xef, 0xc0, 0x09, 0x23, 0x2a, 0x8e, 0x6b, 0x99, + 0x24, 0x24, 0x9f, 0x95, 0xf6, 0xdc, 0xa1, 0xe3, 0x45, 0xfc, 0x68, 0x96, 0x49, 0x4a, 0x33, 0x23, + 0x1e, 0x7a, 0xce, 0x20, 0xe2, 0x47, 0xaa, 0x4c, 0x04, 0x81, 0x5f, 0x87, 0x92, 0x9c, 0x90, 0x43, + 0x50, 0xe2, 0xcb, 0x01, 0xc1, 0x62, 0x08, 0x68, 0x3f, 0x06, 0x19, 0x12, 0x3c, 0x66, 0x73, 0x8a, + 0x15, 0x45, 0x55, 0x65, 0x33, 0x73, 0x09, 0x93, 0x84, 0x64, 0x79, 0x4f, 0x86, 0x7e, 0x91, 0x11, + 0x92, 0x60, 0xff, 0x4d, 0x05, 0x4a, 0xfc, 0xc8, 0x12, 0x1a, 0x1d, 0x79, 0x31, 0x4b, 0x11, 0x32, + 0x36, 0x2a, 0x33, 0x29, 0x82, 0xef, 0x0b, 0x91, 0x32, 0x06, 0x00, 0x0b, 0x77, 0xb6, 0xf3, 0xf0, + 0x21, 0xed, 0xc5, 0x54, 0x64, 0xc2, 0x2c, 0x59, 0x62, 0x4c, 0x5d, 0xf2, 0x18, 0xf2, 0xae, 0x1f, + 0xd1, 0x30, 0xb6, 0xdd, 0x3e, 0xdf, 0x93, 0x2c, 0x29, 0x08, 0x46, 0xbd, 0x8f, 0x2f, 0x42, 0x96, + 0x07, 0xcc, 0x2c, 0x9f, 0x05, 0xe4, 0x2c, 0x24, 0x78, 0x4c, 0x38, 0xff, 0x76, 0xb6, 0x90, 0x43, + 0x79, 0xed, 0xcb, 0xb0, 0xc4, 0x17, 0x77, 0xcf, 0x09, 0x7d, 0xd7, 0x1f, 0xf0, 0xfc, 0x1f, 0xf4, + 0x85, 0x5f, 0x94, 0x09, 0x6f, 0x33, 0x9b, 0x87, 0x34, 0x8a, 0x9c, 0x01, 0x95, 0xf9, 0x38, 0x21, + 0xb5, 0x6f, 0x67, 0xa0, 0xd4, 0x89, 0x43, 0xea, 0x0c, 0x79, 0x6a, 0xc7, 0x5f, 0x06, 0x88, 0x62, + 0x27, 0xa6, 0x43, 0xea, 0xc7, 0x89, 0x7d, 0xaf, 0xca, 0x99, 0xa7, 0xf4, 0xb6, 0x3a, 0x89, 0x12, + 0x99, 0xd2, 0xc7, 0xdb, 0x50, 0xa2, 0x4c, 0x6c, 0xc7, 0xac, 0x44, 0x90, 0x69, 0x68, 0x25, 0x89, + 0x62, 0x69, 0xed, 0x40, 0x80, 0xa6, 0xed, 0x8d, 0x6f, 0xa9, 0x50, 0x4c, 0x47, 0xc3, 0x3a, 0x14, + 0x7a, 0x4e, 0x4c, 0x07, 0x41, 0x38, 0x96, 0x99, 0xfb, 0x8d, 0xa7, 0xcd, 0xbe, 0x55, 0x93, 0xca, + 0x24, 0xed, 0x86, 0x5f, 0x03, 0x51, 0x0e, 0x09, 0xb7, 0x14, 0xf6, 0x16, 0x39, 0x87, 0x3b, 0xe6, + 0x5b, 0x80, 0x47, 0xa1, 0x3b, 0x74, 0xc2, 0xb1, 0x7d, 0x48, 0xc7, 0x49, 0x96, 0xcb, 0xcc, 0xd9, + 0x49, 0x24, 0xf5, 0xee, 0xd0, 0xb1, 0x8c, 0x88, 0x37, 0x67, 0xfb, 0x4a, 0x6f, 0x39, 0xbd, 0x3f, + 0x53, 0x3d, 0x79, 0xdd, 0x10, 0x25, 0x15, 0x42, 0x8e, 0x3b, 0x16, 0x6b, 0x6a, 0x5f, 0x80, 0x42, + 0xb2, 0x78, 0x5c, 0x84, 0x9c, 0x11, 0x86, 0x41, 0x88, 0x16, 0x78, 0x60, 0x6c, 0x36, 0x44, 0x6c, + 0xdd, 0xdd, 0x65, 0xb1, 0xf5, 0x5f, 0xd4, 0x34, 0x4d, 0x13, 0xfa, 0xe8, 0x88, 0x46, 0x31, 0xfe, + 0x29, 0x58, 0xa5, 0xdc, 0x85, 0xdc, 0x63, 0x6a, 0xf7, 0x78, 0x4d, 0xc7, 0x1c, 0x48, 0xe1, 0x78, + 0x2f, 0x6f, 0x89, 0x12, 0x34, 0xa9, 0xf5, 0xc8, 0x4a, 0xaa, 0x2b, 0x59, 0x7d, 0x6c, 0xc0, 0xaa, + 0x3b, 0x1c, 0xd2, 0xbe, 0xeb, 0xc4, 0xd3, 0x03, 0x88, 0x0d, 0x5b, 0x4f, 0x4a, 0x9e, 0x99, 0x92, + 0x91, 0xac, 0xa4, 0x3d, 0xd2, 0x61, 0xde, 0x80, 0x7c, 0xcc, 0xcb, 0x5b, 0xee, 0xbb, 0xa5, 0xed, + 0x72, 0x12, 0x71, 0x38, 0x93, 0x48, 0x21, 0xfe, 0x02, 0x88, 0x62, 0x99, 0xc7, 0x96, 0x89, 0x43, + 0x4c, 0x6a, 0x20, 0x22, 0xe4, 0xf8, 0x0d, 0xa8, 0xcc, 0x64, 0xe7, 0x3e, 0x07, 0x2c, 0x43, 0xca, + 0xd3, 0xa9, 0xb6, 0x8f, 0xaf, 0xc0, 0x62, 0x20, 0x72, 0x21, 0x8f, 0x3a, 0x93, 0x15, 0xcf, 0x26, + 0x4a, 0x92, 0x68, 0xb1, 0xd8, 0x10, 0xd2, 0x88, 0x86, 0xc7, 0xb4, 0xcf, 0x06, 0x5d, 0xe4, 0x83, + 0x42, 0xc2, 0xaa, 0xf7, 0xb5, 0x9f, 0x80, 0xe5, 0x14, 0xe2, 0x68, 0x14, 0xf8, 0x11, 0xc5, 0x97, + 0x21, 0x1f, 0xf2, 0xf3, 0x2e, 0x61, 0xc5, 0x72, 0x8e, 0xa9, 0x48, 0x40, 0xa4, 0x86, 0xd6, 0x87, + 0x65, 0xc1, 0x61, 0xf1, 0x9b, 0xef, 0x24, 0x7e, 0x03, 0x72, 0x94, 0x35, 0x4e, 0x6c, 0x0a, 0x69, + 0xd7, 0xb8, 0x9c, 0x08, 0xe9, 0xd4, 0x2c, 0xea, 0x33, 0x67, 0xf9, 0x4f, 0x15, 0x56, 0xe5, 0x2a, + 0x77, 0x9c, 0xb8, 0x77, 0xf0, 0x82, 0x7a, 0xc3, 0x0f, 0xc3, 0x22, 0xe3, 0xbb, 0xe9, 0xc9, 0x99, + 0xe3, 0x0f, 0x89, 0x06, 0xf3, 0x08, 0x27, 0xb2, 0xa7, 0xb6, 0x5f, 0x96, 0x8f, 0x65, 0x27, 0x9a, + 0xaa, 0x1a, 0xe6, 0x38, 0x4e, 0xfe, 0x19, 0x8e, 0xb3, 0x78, 0x16, 0xc7, 0xd1, 0x76, 0x61, 0x6d, + 0x16, 0x71, 0xe9, 0x1c, 0x3f, 0x02, 0x8b, 0x62, 0x53, 0x92, 0x18, 0x39, 0x6f, 0xdf, 0x12, 0x15, + 0xed, 0x03, 0x15, 0xd6, 0x64, 0xf8, 0xfa, 0x64, 0x9c, 0xe3, 0x29, 0x9c, 0x73, 0x67, 0x3a, 0xa0, + 0x67, 0xdb, 0x3f, 0xad, 0x06, 0xeb, 0x27, 0x70, 0x7c, 0x8e, 0xc3, 0xfa, 0x5d, 0x05, 0x96, 0x76, + 0xe8, 0xc0, 0xf5, 0x5f, 0xd0, 0x5d, 0x98, 0x02, 0x37, 0x7b, 0x26, 0x27, 0x1e, 0x41, 0x59, 0xda, + 0x2b, 0xd1, 0x3a, 0x8d, 0xb6, 0x32, 0xef, 0xb4, 0xdc, 0x84, 0x25, 0x79, 0x01, 0xe1, 0x78, 0xae, + 0x13, 0xa5, 0xf6, 0x9c, 0xb8, 0x81, 0xd0, 0x99, 0x90, 0xc8, 0xbb, 0x0a, 0x4e, 0x68, 0xff, 0xa6, + 0x40, 0xb9, 0x16, 0x0c, 0x87, 0x6e, 0xfc, 0x82, 0x62, 0x7c, 0x1a, 0xa1, 0xec, 0x3c, 0x7f, 0x7c, + 0x13, 0x2a, 0x89, 0x99, 0x12, 0xda, 0x13, 0x99, 0x46, 0x39, 0x95, 0x69, 0xfe, 0x5d, 0x81, 0x65, + 0x12, 0x88, 0x0a, 0xff, 0xe5, 0x06, 0xe7, 0x1a, 0xa0, 0x89, 0xa1, 0x67, 0x85, 0xe7, 0x7f, 0x14, + 0xa8, 0xb4, 0x43, 0x3a, 0x72, 0x42, 0xfa, 0x52, 0xa3, 0xc3, 0xca, 0xf4, 0x7e, 0x2c, 0x0b, 0x9c, + 0x22, 0xe1, 0x6d, 0x6d, 0x05, 0x96, 0x53, 0xdb, 0x05, 0x60, 0xda, 0x3f, 0x2a, 0xb0, 0x2e, 0x5c, + 0x4c, 0x4a, 0xfa, 0x2f, 0x28, 0x2c, 0x89, 0xbd, 0xd9, 0x29, 0x7b, 0xab, 0x70, 0xee, 0xa4, 0x6d, + 0xd2, 0xec, 0xaf, 0xa8, 0x70, 0x3e, 0x71, 0x9e, 0x17, 0xdc, 0xf0, 0xef, 0xc3, 0x1f, 0x36, 0xa0, + 0x7a, 0x1a, 0x04, 0x89, 0xd0, 0xd7, 0x55, 0xa8, 0x8a, 0x4b, 0x9c, 0xa9, 0x3a, 0xe8, 0xe5, 0xf1, + 0x0d, 0xfc, 0x26, 0x2c, 0x8d, 0x9c, 0x30, 0x76, 0x7b, 0xee, 0xc8, 0x61, 0x9f, 0xa2, 0x39, 0x5e, + 0x66, 0x9d, 0x18, 0x60, 0x46, 0x45, 0xbb, 0x00, 0xaf, 0xcc, 0x41, 0x44, 0xe2, 0xf5, 0xbf, 0x0a, + 0xe0, 0x4e, 0xec, 0x84, 0xf1, 0x27, 0x20, 0x2f, 0xcd, 0x75, 0xa6, 0x75, 0x58, 0x9d, 0xb1, 0x7f, + 0x1a, 0x17, 0x1a, 0x7f, 0x22, 0x52, 0xd2, 0x47, 0xe2, 0x32, 0x6d, 0xbf, 0xc4, 0xe5, 0x9f, 0x15, + 0xd8, 0xa8, 0x05, 0xe2, 0x42, 0xf4, 0xa5, 0x3c, 0x61, 0xda, 0x6b, 0x70, 0x61, 0xae, 0x81, 0x12, + 0x80, 0x7f, 0x52, 0xe0, 0x1c, 0xa1, 0x4e, 0xff, 0xe5, 0x34, 0xfe, 0x2e, 0x9c, 0x3f, 0x65, 0x9c, + 0xac, 0x51, 0x6e, 0x40, 0x61, 0x48, 0x63, 0x87, 0x55, 0xb8, 0xd2, 0xa4, 0x8d, 0x64, 0xdc, 0x89, + 0x76, 0x53, 0x6a, 0x90, 0x54, 0x57, 0xfb, 0x8e, 0x0a, 0xab, 0xbc, 0xce, 0xfe, 0xf4, 0x23, 0xef, + 0x4c, 0xb7, 0x30, 0xf9, 0x93, 0xc5, 0x1f, 0x53, 0x18, 0x85, 0xd4, 0x4e, 0x6e, 0x07, 0x16, 0xf9, + 0xaf, 0x8f, 0x30, 0x0a, 0xe9, 0x5d, 0xc1, 0xd1, 0xfe, 0x46, 0x81, 0xb5, 0x59, 0x88, 0xd3, 0x2f, + 0x9a, 0xff, 0xef, 0xdb, 0x96, 0x39, 0x21, 0x25, 0x73, 0x96, 0x8f, 0xa4, 0xec, 0x99, 0x3f, 0x92, + 0xfe, 0x56, 0x85, 0xea, 0xb4, 0x31, 0x9f, 0xde, 0xe9, 0xcc, 0xde, 0xe9, 0x7c, 0xaf, 0xb7, 0x7c, + 0xda, 0xdf, 0x2b, 0xf0, 0xca, 0x1c, 0x40, 0xbf, 0x37, 0x17, 0x99, 0xba, 0xd9, 0x51, 0x9f, 0x79, + 0xb3, 0xf3, 0xf1, 0x3b, 0xc9, 0x3f, 0x28, 0xb0, 0xd6, 0x14, 0x77, 0xf5, 0xe2, 0xe6, 0xe3, 0xc5, + 0x8d, 0xc1, 0xfc, 0x3a, 0x3e, 0x3b, 0xf9, 0xb5, 0x4a, 0xab, 0xc1, 0xfa, 0x09, 0xd3, 0x9e, 0xe3, + 0x36, 0xe7, 0xbf, 0x15, 0x58, 0x91, 0xa3, 0xe8, 0x2f, 0x6c, 0xf9, 0x32, 0x07, 0x1d, 0x7c, 0x11, + 0x32, 0x6e, 0x3f, 0xa9, 0x7b, 0x67, 0x5f, 0x21, 0x30, 0x81, 0xf6, 0x36, 0xe0, 0x69, 0xbb, 0x9f, + 0x03, 0xba, 0xff, 0x50, 0x61, 0x9d, 0x88, 0xe8, 0xfb, 0xe9, 0xef, 0x0b, 0xdf, 0xef, 0xef, 0x0b, + 0x4f, 0x4f, 0x5c, 0x1f, 0xf0, 0x62, 0x6a, 0x16, 0xea, 0x8f, 0x2f, 0x75, 0x9d, 0x48, 0xb4, 0x99, + 0x53, 0x89, 0xf6, 0xf9, 0xe3, 0xd1, 0x07, 0x2a, 0x6c, 0x48, 0x43, 0x3e, 0xad, 0x75, 0xce, 0xee, + 0x11, 0xf9, 0x53, 0x1e, 0xf1, 0x5f, 0x0a, 0x5c, 0x98, 0x0b, 0xe4, 0x0f, 0xbc, 0xa2, 0x39, 0xe1, + 0x3d, 0xd9, 0x67, 0x7a, 0x4f, 0xee, 0xcc, 0xde, 0xf3, 0x35, 0x15, 0x2a, 0x84, 0x7a, 0xd4, 0x89, + 0x5e, 0xf2, 0xdb, 0xbd, 0x13, 0x18, 0xe6, 0x4e, 0xdd, 0x73, 0xae, 0xc0, 0x72, 0x0a, 0x84, 0xfc, + 0xe0, 0xe2, 0x1f, 0xe8, 0x2c, 0x0f, 0xbe, 0x43, 0x1d, 0x2f, 0x4e, 0x2a, 0x41, 0xed, 0x8f, 0x55, + 0x28, 0x13, 0xc6, 0x71, 0x87, 0xb4, 0x13, 0x3b, 0x71, 0x84, 0x3f, 0x03, 0x4b, 0x07, 0x5c, 0xc5, + 0x9e, 0x78, 0x48, 0x91, 0x94, 0x04, 0x4f, 0xfc, 0xfa, 0xb8, 0x0d, 0xeb, 0x11, 0xed, 0x05, 0x7e, + 0x3f, 0xb2, 0x1f, 0xd0, 0x03, 0xd7, 0xef, 0xdb, 0x43, 0x27, 0x8a, 0x69, 0xc8, 0x61, 0x29, 0x93, + 0x55, 0x29, 0xdc, 0xe1, 0xb2, 0x26, 0x17, 0xe1, 0xab, 0xb0, 0xf6, 0xc0, 0xf5, 0xbd, 0x60, 0x60, + 0x8f, 0x3c, 0x67, 0x4c, 0xc3, 0xc8, 0xee, 0x05, 0x47, 0xbe, 0xc0, 0x23, 0x47, 0xb0, 0x90, 0xb5, + 0x85, 0xa8, 0xc6, 0x24, 0xf8, 0x3d, 0xb8, 0x3c, 0x77, 0x16, 0xfb, 0xa1, 0xeb, 0xc5, 0x34, 0xa4, + 0x7d, 0x3b, 0xa4, 0x23, 0xcf, 0xed, 0x89, 0x17, 0x56, 0x02, 0xa8, 0xcf, 0xcf, 0x99, 0x7a, 0x4f, + 0xaa, 0x93, 0x89, 0x36, 0xbe, 0x00, 0xc5, 0xde, 0xe8, 0xc8, 0x3e, 0xe2, 0x8f, 0x16, 0x18, 0x7e, + 0x0a, 0x29, 0xf4, 0x46, 0x47, 0x5d, 0x46, 0x63, 0x04, 0x99, 0x47, 0x23, 0x11, 0x9c, 0x15, 0xc2, + 0x9a, 0xda, 0x77, 0x15, 0xa8, 0xe8, 0x83, 0x41, 0x48, 0x07, 0x4e, 0x2c, 0x61, 0xba, 0x0a, 0x6b, + 0x02, 0x92, 0xb1, 0x2d, 0xdd, 0x55, 0xd8, 0xa3, 0x08, 0x7b, 0xa4, 0x4c, 0xf8, 0xaa, 0xb0, 0xe7, + 0x3a, 0x9c, 0x3b, 0xf2, 0xe7, 0xf6, 0x51, 0x79, 0x9f, 0xb5, 0x54, 0x3a, 0xdd, 0xeb, 0xc7, 0xe1, + 0x95, 0xf9, 0x28, 0x0c, 0x5d, 0xf1, 0xca, 0xb1, 0x4c, 0xce, 0xcd, 0x31, 0xba, 0xe9, 0xfa, 0x4f, + 0xe9, 0xea, 0xbc, 0xcf, 0xf1, 0xfa, 0x88, 0xae, 0xce, 0xfb, 0xda, 0x9f, 0xa6, 0xbf, 0x29, 0x26, + 0xee, 0x92, 0x06, 0x8e, 0xc4, 0x91, 0x95, 0xa7, 0x39, 0x72, 0x15, 0x16, 0x99, 0x33, 0xba, 0xfe, + 0x80, 0x1b, 0x57, 0x20, 0x09, 0x89, 0x3b, 0xf0, 0x79, 0x69, 0x3b, 0x7d, 0x3f, 0xa6, 0xa1, 0xef, + 0x78, 0xde, 0xd8, 0x16, 0xd7, 0x8f, 0x3e, 0x7f, 0x50, 0x96, 0xbe, 0xfa, 0x14, 0xe1, 0xe3, 0xb3, + 0x42, 0xdb, 0x48, 0x95, 0x49, 0xaa, 0x6b, 0xa5, 0xef, 0x41, 0xbf, 0x04, 0x95, 0x50, 0x3a, 0xb1, + 0x1d, 0xb1, 0xed, 0x91, 0x21, 0x77, 0x2d, 0x79, 0x35, 0x31, 0xed, 0xe1, 0xa4, 0x1c, 0xce, 0x38, + 0xfc, 0x73, 0x07, 0x9c, 0xdb, 0xd9, 0x42, 0x1e, 0x2d, 0x6a, 0x7f, 0xa6, 0xc0, 0xea, 0x9c, 0x6f, + 0xf7, 0xf4, 0x62, 0x40, 0x99, 0xba, 0x77, 0xfc, 0x51, 0xc8, 0xf1, 0x07, 0x2d, 0xf2, 0x0d, 0xd5, + 0xf9, 0xd3, 0x9f, 0xfe, 0xfc, 0xf1, 0x09, 0x11, 0x5a, 0xec, 0x2c, 0x72, 0x9b, 0xe4, 0x6b, 0x3b, + 0x09, 0x49, 0x89, 0xf1, 0xe4, 0x13, 0xbb, 0x53, 0x37, 0x99, 0xd9, 0x67, 0xde, 0x64, 0x5e, 0xfe, + 0xcd, 0x0c, 0x14, 0x9b, 0xe3, 0xce, 0x23, 0x6f, 0xcf, 0x73, 0x06, 0xfc, 0x75, 0x48, 0xb3, 0x6d, + 0xdd, 0x47, 0x0b, 0x78, 0x05, 0xca, 0x66, 0xcb, 0xb2, 0xcd, 0x6e, 0xa3, 0x61, 0xef, 0x35, 0xf4, + 0x5b, 0x48, 0xc1, 0x08, 0x96, 0xda, 0xa4, 0x6e, 0xdf, 0x31, 0xee, 0x0b, 0x8e, 0x8a, 0x57, 0x61, + 0xb9, 0x6b, 0xd6, 0xef, 0x76, 0x8d, 0x09, 0x33, 0x8b, 0xd7, 0x61, 0xa5, 0xd9, 0x6d, 0x58, 0xf5, + 0x76, 0x63, 0x8a, 0x5d, 0xc0, 0x65, 0x28, 0xee, 0x34, 0x5a, 0x3b, 0x82, 0x44, 0x6c, 0xfc, 0xae, + 0xd9, 0xa9, 0xdf, 0x32, 0x8d, 0x5d, 0xc1, 0xda, 0x64, 0xac, 0xf7, 0x0c, 0xd2, 0xda, 0xab, 0x27, + 0x53, 0xbe, 0x8d, 0x11, 0x94, 0x76, 0xea, 0xa6, 0x4e, 0xe4, 0x28, 0x4f, 0x14, 0x5c, 0x81, 0xa2, + 0x61, 0x76, 0x9b, 0x92, 0x56, 0x71, 0x15, 0x56, 0xf5, 0xae, 0xd5, 0xb2, 0xeb, 0x66, 0x8d, 0x18, + 0x4d, 0xc3, 0xb4, 0xa4, 0x24, 0x8b, 0x57, 0xa1, 0x62, 0xd5, 0x9b, 0x46, 0xc7, 0xd2, 0x9b, 0x6d, + 0xc9, 0x64, 0xab, 0x28, 0x74, 0x8c, 0x44, 0x07, 0xe1, 0x0d, 0x58, 0x37, 0x5b, 0x76, 0xf2, 0xb4, + 0x6e, 0x5f, 0x6f, 0x74, 0x0d, 0x29, 0xdb, 0xc4, 0xe7, 0x01, 0xb7, 0x4c, 0xbb, 0xdb, 0xde, 0xd5, + 0x2d, 0xc3, 0x36, 0x5b, 0xf7, 0xa4, 0xe0, 0x6d, 0x5c, 0x81, 0xc2, 0x64, 0x05, 0x4f, 0x18, 0x0a, + 0xe5, 0xb6, 0x4e, 0xac, 0x89, 0xb1, 0x4f, 0x9e, 0x30, 0xb0, 0xe0, 0x16, 0x69, 0x75, 0xdb, 0x13, + 0xb5, 0x15, 0x28, 0x49, 0xb0, 0x24, 0x2b, 0xcb, 0x58, 0x3b, 0x75, 0xb3, 0x96, 0xae, 0xef, 0x49, + 0x61, 0x43, 0x45, 0xca, 0xe5, 0x43, 0xc8, 0xf2, 0xed, 0x28, 0x40, 0xd6, 0x6c, 0x99, 0x06, 0x5a, + 0xc0, 0xcb, 0x00, 0xf5, 0x4e, 0xdd, 0xb4, 0x8c, 0x5b, 0x44, 0x6f, 0x30, 0xb3, 0x39, 0x23, 0x01, + 0x90, 0x59, 0xbb, 0x04, 0x8b, 0xf5, 0xce, 0x5e, 0xa3, 0xa5, 0x5b, 0xd2, 0xcc, 0x7a, 0xe7, 0x6e, + 0xb7, 0x65, 0x31, 0x21, 0xc2, 0x25, 0xc8, 0xd7, 0x3b, 0x96, 0xf1, 0xae, 0xc5, 0xec, 0xe2, 0x32, + 0x81, 0x2a, 0x7a, 0xf2, 0xf6, 0xe5, 0xbf, 0xc8, 0x40, 0x96, 0x3f, 0xe7, 0x2e, 0x43, 0x91, 0xef, + 0xb6, 0x75, 0xbf, 0xcd, 0xa6, 0x2c, 0x42, 0xb6, 0x6e, 0x5a, 0x37, 0xd1, 0xcf, 0xa8, 0x18, 0x20, + 0xd7, 0xe5, 0xed, 0x9f, 0xcd, 0xb3, 0x76, 0xdd, 0xb4, 0xde, 0xbc, 0x81, 0xbe, 0xa2, 0xb2, 0x61, + 0xbb, 0x82, 0xf8, 0xb9, 0x44, 0xb0, 0x7d, 0x1d, 0x7d, 0x35, 0x15, 0x6c, 0x5f, 0x47, 0x3f, 0x9f, + 0x08, 0xae, 0x6d, 0xa3, 0xaf, 0xa5, 0x82, 0x6b, 0xdb, 0xe8, 0x17, 0x12, 0xc1, 0x8d, 0xeb, 0xe8, + 0x17, 0x53, 0xc1, 0x8d, 0xeb, 0xe8, 0x97, 0xf2, 0xcc, 0x16, 0x6e, 0xc9, 0xb5, 0x6d, 0xf4, 0xcb, + 0x85, 0x94, 0xba, 0x71, 0x1d, 0xfd, 0x4a, 0x81, 0xed, 0x7f, 0xba, 0xab, 0xe8, 0x57, 0x11, 0x5b, + 0x26, 0xdb, 0x20, 0xf4, 0x6b, 0xbc, 0xc9, 0x44, 0xe8, 0xd7, 0x11, 0xb3, 0x91, 0x71, 0x39, 0xf9, + 0x75, 0x2e, 0xb9, 0x6f, 0xe8, 0x04, 0xfd, 0x46, 0x5e, 0x3c, 0xf6, 0xac, 0xd5, 0x9b, 0x7a, 0x03, + 0x61, 0xde, 0x83, 0xa1, 0xf2, 0x5b, 0x57, 0x59, 0x93, 0xb9, 0x27, 0xfa, 0xed, 0x36, 0x9b, 0x70, + 0x5f, 0x27, 0xb5, 0x77, 0x74, 0x82, 0x7e, 0xe7, 0x2a, 0x9b, 0x70, 0x5f, 0x27, 0x12, 0xaf, 0xdf, + 0x6d, 0x33, 0x45, 0x2e, 0xfa, 0xbd, 0xab, 0x6c, 0xd1, 0x92, 0xff, 0x8d, 0x36, 0x2e, 0x40, 0x66, + 0xa7, 0x6e, 0xa1, 0xdf, 0xe7, 0xb3, 0x31, 0x17, 0x45, 0x7f, 0x80, 0x18, 0xb3, 0x63, 0x58, 0xe8, + 0x9b, 0x8c, 0x99, 0xb3, 0xba, 0xed, 0x86, 0x81, 0x5e, 0x65, 0x8b, 0xbb, 0x65, 0xb4, 0x9a, 0x86, + 0x45, 0xee, 0xa3, 0x3f, 0xe4, 0xea, 0xb7, 0x3b, 0x2d, 0x13, 0x7d, 0x0b, 0xe1, 0x0a, 0x80, 0xf1, + 0x6e, 0x9b, 0x18, 0x9d, 0x4e, 0xbd, 0x65, 0xa2, 0xd7, 0xd9, 0x04, 0xef, 0x18, 0xef, 0xb2, 0xb1, + 0xbe, 0xbd, 0x29, 0x89, 0x7d, 0xbd, 0x81, 0xfe, 0x68, 0xf3, 0xf2, 0x1e, 0xa0, 0x93, 0x81, 0x82, + 0x99, 0xd6, 0x35, 0xef, 0x98, 0xad, 0x7b, 0x26, 0x5a, 0x60, 0x44, 0x9b, 0x18, 0x6d, 0x9d, 0x18, + 0x48, 0xc1, 0x00, 0x79, 0xf9, 0xb8, 0x54, 0xc5, 0x4b, 0x50, 0x20, 0xad, 0x46, 0x63, 0x47, 0xaf, + 0xdd, 0x41, 0x99, 0x1d, 0xe3, 0xaf, 0x3f, 0xbc, 0xa8, 0xfc, 0xdd, 0x87, 0x17, 0x95, 0xef, 0x7c, + 0x78, 0x51, 0xf9, 0xc6, 0xbf, 0x5e, 0x5c, 0x80, 0x65, 0x37, 0xd8, 0x3a, 0x76, 0x63, 0x1a, 0x45, + 0xe2, 0xaf, 0x05, 0xef, 0x69, 0x92, 0x72, 0x83, 0x2b, 0xa2, 0x75, 0x65, 0x10, 0x5c, 0x39, 0x8e, + 0xaf, 0x70, 0xe9, 0x15, 0x1e, 0x5b, 0x1e, 0xe4, 0x39, 0x71, 0xed, 0xff, 0x02, 0x00, 0x00, 0xff, + 0xff, 0x6e, 0x8f, 0xd1, 0x9e, 0xb8, 0x30, 0x00, 0x00, } func (m *Target) Marshal() (dAtA []byte, err error) { diff --git a/go/vt/sqlparser/ast_funcs.go b/go/vt/sqlparser/ast_funcs.go index 5ad474ba693..75b70df459b 100644 --- a/go/vt/sqlparser/ast_funcs.go +++ b/go/vt/sqlparser/ast_funcs.go @@ -17,8 +17,10 @@ limitations under the License. package sqlparser import ( + "bytes" "encoding/hex" "encoding/json" + "regexp" "strings" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -469,6 +471,32 @@ func (node *Literal) HexDecode() ([]byte, error) { return hex.DecodeString(node.Val) } +// encodeHexValToMySQLQueryFormat encodes the hexval back into the query format +// for passing on to MySQL as a bind var +func (node *Literal) encodeHexValToMySQLQueryFormat() ([]byte, error) { + nb := node.Bytes() + if node.Type != HexVal { + return nb, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Literal value is not a HexVal") + } + + // Let's make this idempotent in case it's called more than once + match, err := regexp.Match("^x'.*'$", nb) + if err != nil { + return nb, err + } + if match { + return nb, nil + } + + var bb bytes.Buffer + bb.WriteByte('x') + bb.WriteByte('\'') + bb.WriteString(string(nb)) + bb.WriteByte('\'') + nb = bb.Bytes() + return nb, nil +} + // Equal returns true if the column names match. func (node *ColName) Equal(c *ColName) bool { // Failsafe: ColName should not be empty. diff --git a/go/vt/sqlparser/normalizer.go b/go/vt/sqlparser/normalizer.go index e4626a57b6d..5691d97ceda 100644 --- a/go/vt/sqlparser/normalizer.go +++ b/go/vt/sqlparser/normalizer.go @@ -202,6 +202,17 @@ func (nz *normalizer) sqlToBindvar(node SQLNode) *querypb.BindVariable { v, err = sqltypes.NewValue(sqltypes.Int64, node.Bytes()) case FloatVal: v, err = sqltypes.NewValue(sqltypes.Float64, node.Bytes()) + case HexNum: + v, err = sqltypes.NewValue(sqltypes.HexNum, node.Bytes()) + case HexVal: + // We parse the `x'7b7d'` string literal into a hex encoded string of `7b7d` in the parser + // We need to re-encode it back to the original MySQL query format before passing it on as a bindvar value to MySQL + var vbytes []byte + vbytes, err = node.encodeHexValToMySQLQueryFormat() + if err != nil { + return nil + } + v, err = sqltypes.NewValue(sqltypes.HexVal, vbytes) default: return nil } diff --git a/go/vt/sqlparser/normalizer_test.go b/go/vt/sqlparser/normalizer_test.go index 09bee85773f..6aa47529b05 100644 --- a/go/vt/sqlparser/normalizer_test.go +++ b/go/vt/sqlparser/normalizer_test.go @@ -127,15 +127,33 @@ func TestNormalize(t *testing.T) { "bv2": sqltypes.TestBindVariable([]interface{}{1, 4, 5}), }, }, { - // Hex value does not convert + // Hex number values should work for selects in: "select * from t where v1 = 0x1234", - outstmt: "select * from t where v1 = 0x1234", - outbv: map[string]*querypb.BindVariable{}, + outstmt: "select * from t where v1 = :bv1", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexNumBindVariable([]byte("0x1234")), + }, }, { - // Hex value does not convert for DMLs - in: "update a set v1 = 0x1234", - outstmt: "update a set v1 = 0x1234", - outbv: map[string]*querypb.BindVariable{}, + // Hex encoded string values should work for selects + in: "select * from t where v1 = x'7b7d'", + outstmt: "select * from t where v1 = :bv1", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexValBindVariable([]byte("x'7b7d'")), + }, + }, { + // Ensure that hex notation bind vars work with collation based conversions + in: "select convert(x'7b7d' using utf8mb4) from dual", + outstmt: "select convert(:bv1 using utf8mb4) from dual", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexValBindVariable([]byte("x'7b7d'")), + }, + }, { + // Hex number values should work for DMLs + in: "update a set v1 = 0x12", + outstmt: "update a set v1 = :bv1", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexNumBindVariable([]byte("0x12")), + }, }, { // Bin value does not convert in: "select * from t where v1 = b'11'", diff --git a/go/vt/vtgate/vindexes/binary_test.go b/go/vt/vtgate/vindexes/binary_test.go index 167a05e8ef2..0399c1687bc 100644 --- a/go/vt/vtgate/vindexes/binary_test.go +++ b/go/vt/vtgate/vindexes/binary_test.go @@ -18,6 +18,8 @@ package vindexes import ( "bytes" + "encoding/hex" + "fmt" "reflect" "testing" @@ -69,13 +71,17 @@ func TestBinaryMap(t *testing.T) { } func TestBinaryVerify(t *testing.T) { - ids := []sqltypes.Value{sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("2")} - ksids := [][]byte{[]byte("1"), []byte("1")} + hexValStr := "8a1e" + hexValStrSQL := fmt.Sprintf("x'%s'", hexValStr) + hexNumStrSQL := fmt.Sprintf("0x%s", hexValStr) + hexBytes, _ := hex.DecodeString(hexValStr) + ids := []sqltypes.Value{sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("2"), sqltypes.NewHexVal([]byte(hexValStrSQL)), sqltypes.NewHexNum([]byte(hexNumStrSQL))} + ksids := [][]byte{[]byte("1"), []byte("1"), hexBytes, hexBytes} got, err := binOnlyVindex.Verify(nil, ids, ksids) if err != nil { t.Fatal(err) } - want := []bool{true, false} + want := []bool{true, false, true, true} if !reflect.DeepEqual(got, want) { t.Errorf("binary.Verify: %v, want %v", got, want) } diff --git a/go/vt/vtgate/vindexes/binarymd5_test.go b/go/vt/vtgate/vindexes/binarymd5_test.go index 5dfd3ae770f..58fb485abe3 100644 --- a/go/vt/vtgate/vindexes/binarymd5_test.go +++ b/go/vt/vtgate/vindexes/binarymd5_test.go @@ -17,6 +17,7 @@ limitations under the License. package vindexes import ( + "encoding/hex" "fmt" "reflect" "testing" @@ -72,13 +73,17 @@ func TestBinaryMD5Map(t *testing.T) { } func TestBinaryMD5Verify(t *testing.T) { - ids := []sqltypes.Value{sqltypes.NewVarBinary("Test"), sqltypes.NewVarBinary("TEst")} - ksids := [][]byte{[]byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za["), []byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za[")} + hexValStr := "21cf" + hexValStrSQL := fmt.Sprintf("x'%s'", hexValStr) + hexNumStrSQL := fmt.Sprintf("0x%s", hexValStr) + hexBytes, _ := hex.DecodeString(hexValStr) + ids := []sqltypes.Value{sqltypes.NewVarBinary("Test"), sqltypes.NewVarBinary("TEst"), sqltypes.NewHexVal([]byte(hexValStrSQL)), sqltypes.NewHexNum([]byte(hexNumStrSQL))} + ksids := [][]byte{[]byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za["), []byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za["), vMD5Hash(hexBytes), vMD5Hash(hexBytes)} got, err := binVindex.Verify(nil, ids, ksids) if err != nil { t.Fatal(err) } - want := []bool{true, false} + want := []bool{true, false, true, true} if !reflect.DeepEqual(got, want) { t.Errorf("binaryMD5.Verify: %v, want %v", got, want) } diff --git a/go/vt/vtgate/vindexes/xxhash_test.go b/go/vt/vtgate/vindexes/xxhash_test.go index 1586f9a4d89..7ccfdc5da6d 100644 --- a/go/vt/vtgate/vindexes/xxhash_test.go +++ b/go/vt/vtgate/vindexes/xxhash_test.go @@ -18,6 +18,7 @@ package vindexes import ( "bytes" + "encoding/hex" "fmt" "reflect" "testing" @@ -94,13 +95,17 @@ func TestXXHashMap(t *testing.T) { } func TestXXHashVerify(t *testing.T) { - ids := []sqltypes.Value{sqltypes.NewUint64(1), sqltypes.NewUint64(2)} - ksids := [][]byte{{0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}, {0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}} + hexValStr := "9efa" + hexValStrSQL := fmt.Sprintf("x'%s'", hexValStr) + hexNumStrSQL := fmt.Sprintf("0x%s", hexValStr) + hexBytes, _ := hex.DecodeString(hexValStr) + ids := []sqltypes.Value{sqltypes.NewUint64(1), sqltypes.NewUint64(2), sqltypes.NewHexVal([]byte(hexValStrSQL)), sqltypes.NewHexNum([]byte(hexNumStrSQL))} + ksids := [][]byte{{0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}, {0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}, vXXHash(hexBytes), vXXHash(hexBytes)} got, err := xxHash.Verify(nil, ids, ksids) if err != nil { t.Fatal(err) } - want := []bool{true, false} + want := []bool{true, false, true, true} if !reflect.DeepEqual(got, want) { t.Errorf("xxHash.Verify: %v, want %v", got, want) } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java index d9d5294e89e..85127a2bf1d 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java @@ -294,7 +294,7 @@ public void testPrecisionAdjustFactor() throws SQLException { conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); for (Query.Type type : Query.Type.values()) { - if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION) { + if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION || type == Query.Type.HEXVAL || type == Query.Type.HEXNUM) { continue; } diff --git a/misc/git/hooks/golangci-lint b/misc/git/hooks/golangci-lint index bf80fe4f4cd..7a0ae6cc651 100755 --- a/misc/git/hooks/golangci-lint +++ b/misc/git/hooks/golangci-lint @@ -20,7 +20,7 @@ gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '^go/.*\.go$' | grep -v '^go/vt/proto/' | grep -v 'go/vt/sqlparser/sql.go') # xargs -n1 because dirname on MacOS does not support multiple arguments. -gopackages=$(echo $gofiles | xargs -n1 dirname | sort -u) +gopackages=$(echo $gofiles | xargs -n1 dirname | sort -u -) GOLANGCI_LINT=$(command -v golangci-lint >/dev/null 2>&1) if [ $? -eq 1 ]; then diff --git a/misc/git/hooks/govet b/misc/git/hooks/govet index 72951834cbd..02d0a2debd7 100755 --- a/misc/git/hooks/govet +++ b/misc/git/hooks/govet @@ -36,7 +36,7 @@ errors= # If any checks are found to be useless, they can be disabled here. # See the output of "go doc cmd/vet" for a list of flags. -vetflags="" +vetflags="-unsafeptr=false" # Run on one package at a time for gopackage in $gopackages diff --git a/proto/query.proto b/proto/query.proto index 4b9b2345f72..c38b0614157 100644 --- a/proto/query.proto +++ b/proto/query.proto @@ -206,6 +206,12 @@ enum Type { // This type is for internal use only. // Properties: 31, None. EXPRESSION = 31; + // HEXNUM specifies a HEXNUM type (unquoted varbinary). + // Properties: 32, IsText. + HEXNUM = 4128; + // HEXVAL specifies a HEXVAL type (unquoted varbinary). + // Properties: 33, IsText. + HEXVAL = 4129; } // Value represents a typed value. diff --git a/test/config.json b/test/config.json index 6dd53b80770..e30cdb30db5 100644 --- a/test/config.json +++ b/test/config.json @@ -517,6 +517,15 @@ "RetryMax": 0, "Tags": [] }, + "vtgate_queries_normalize": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/queries/normalize"], + "Command": [], + "Manual": false, + "Shard": "vtgate_queries", + "RetryMax": 2, + "Tags": [] + }, "vtgate_buffer": { "File": "unused.go", "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/buffer"],