From 6cb746623b1298a40f0d2a10f1b6031fc6a2420f Mon Sep 17 00:00:00 2001 From: Luis <72552948+luis261@users.noreply.github.com> Date: Thu, 29 Apr 2021 21:05:37 +0200 Subject: [PATCH 1/6] fix typo (#7496) --- paper/dgraph.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/dgraph.tex b/paper/dgraph.tex index 5e12d7e8a2c..1c3ce0969ad 100644 --- a/paper/dgraph.tex +++ b/paper/dgraph.tex @@ -847,7 +847,7 @@ \section{Replication} \section{High Availability and Scalability} Dgraph's architecture revolves around Raft groups for update log serialization -and replication. In the CAP throrem, this follows CP, i.e. in a network +and replication. In the CAP theorem, this follows CP, i.e. in a network partition, Dgraph would choose consistency over availability. However, the concepts of CAP theorem should not be confused with high availability, which is determined by how many instances can be lost without the service getting From 0b332543566bfba64721e06edd81eca578eb5d83 Mon Sep 17 00:00:00 2001 From: minhaj-shakeel Date: Fri, 30 Apr 2021 10:23:14 +0530 Subject: [PATCH 2/6] feat(DQL): @groupby on scalar fields and count duplicate (#7746) --- query/groupby.go | 62 +++++++++++++++++++++++++++++++++--------- query/query0_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 12 deletions(-) diff --git a/query/groupby.go b/query/groupby.go index aadd836072f..80094d39fd3 100644 --- a/query/groupby.go +++ b/query/groupby.go @@ -290,11 +290,14 @@ func (sg *SubGraph) fillGroupedVars(doneVars map[string]varValue, path []*SubGra var pathNode *SubGraph var dedupMap dedup - + // uidPredicate is true when atleast one argument to + // the groupby is uid predicate. + uidPredicate := false for _, child := range sg.Children { if !child.Params.IgnoreResult { continue } + uidPredicate = uidPredicate || !child.DestMap.IsEmpty() attr := child.Params.Alias if attr == "" { @@ -312,6 +315,23 @@ func (sg *SubGraph) fillGroupedVars(doneVars map[string]varValue, path []*SubGra pathNode = child } else { // It's a value node. + + // Currently vars are supported only at the root. + // for eg, The following query will result into error:- + // v as var(func: uid(1,31)) { + // name + // friend @groupby(age) { + // a as count(uid) + // } + // } + // since `a` is a global variable which stores (uid, val) pair for + // all the srcUids (1 & 31 in this case), we can't store distinct + // vals for same uid locally. This will eventually lead to incorrect + // results. + if sg.SrcFunc == nil { + return errors.Errorf("Vars can be assigned only at root when grouped by Value") + } + for i, v := range child.valueMatrix { srcUid := child.SrcUIDs.Uids[i] if len(v.Values) == 0 { @@ -352,17 +372,35 @@ func (sg *SubGraph) fillGroupedVars(doneVars map[string]varValue, path []*SubGra if len(grp.keys) == 0 { continue } - if len(grp.keys) > 1 { - return errors.Errorf("Expected one UID for var in groupby but got: %d", len(grp.keys)) - } - uidVal := grp.keys[0].key.Value - uid, ok := uidVal.(uint64) - if !ok { - return errors.Errorf("Vars can be assigned only when grouped by UID attribute") - } - // grp.aggregates could be empty if schema conversion failed during aggregation - if len(grp.aggregates) > 0 { - tempMap[uid] = grp.aggregates[len(grp.aggregates)-1].key + + if len(grp.keys) == 1 && grp.keys[0].key.Tid == types.UidID { + uidVal := grp.keys[0].key.Value + uid, _ := uidVal.(uint64) + // grp.aggregates could be empty if schema conversion failed during aggregation + if len(grp.aggregates) > 0 { + tempMap[uid] = grp.aggregates[len(grp.aggregates)-1].key + } + } else { + // if there are more than one predicates or a single scalar + // predicate in the @groupby then the variable stores the mapping of + // uid -> count of duplicates. for eg if there are two predicates(u & v) and + // the grouped uids for (u1, v1) pair are (uid1, uid2, uid3) then the variable + // stores (uid1, 3), (uid2, 3) & (uid2, 2) map. + // For the query given below:- + // var(func: type(Student)) @groupby(school, age) { + // c as count(uid) + // } + // if the grouped result is:- + // (s1, age1) -> "0x1", "0x2", "0x3" + // (s2, age2) -> "0x4" + // (s3, ag3) -> "0x5","0x6" + // then `c` will store the mapping:- + // {"0x1" -> 3, "0x2" -> 3, "0x3" -> 3, "0x4" -> 1, "0x5" -> 2, "0x6"-> 2} + for _, uid := range grp.uids { + if len(grp.aggregates) > 0 { + tempMap[uid] = grp.aggregates[len(grp.aggregates)-1].key + } + } } } doneVars[chVar] = varValue{ diff --git a/query/query0_test.go b/query/query0_test.go index 1a131644941..7c31e121a5d 100644 --- a/query/query0_test.go +++ b/query/query0_test.go @@ -1471,6 +1471,70 @@ func TestGroupByRootAlias(t *testing.T) { require.JSONEq(t, `{"data":{"me":[{"@groupby":[{"age":17,"Count":1},{"age":19,"Count":1},{"age":38,"Count":1},{"age":15,"Count":2}]}]}}`, js) } +func TestGroupByCountValVar(t *testing.T) { + query := ` + { + var(func: uid(1, 23, 24, 25, 31)) @groupby(age) { + c as count(uid) + } + me(func: uid(c)) { + uid + val: val(c) + } + } + ` + js := processQueryNoErr(t, query) + require.JSONEq(t, `{"data":{"me":[{"uid": "0x1","val":1},{"uid": "0x17","val": 2},{"uid": "0x18","val": 2},{"uid": "0x19","val": 1},{"uid": "0x1f","val": 1}]}}`, js) +} + +func TestGroupByCountValVarFilter(t *testing.T) { + query := ` + { + var(func: uid(1, 23, 24, 25, 31)) @groupby(age) { + c as count(uid) + } + me(func: uid(c)) @filter(ge(val(c),2)) { + name + val: val(c) + } + } + ` + js := processQueryNoErr(t, query) + require.JSONEq(t, `{"data":{"me": [{"name": "Rick Grimes","val": 2},{"name": "Glenn Rhee","val": 2}]}}`, js) +} + +func TestGroupByMultiCountValVar(t *testing.T) { + query := ` + { + var(func: uid(1, 23, 24, 25, 31)) @groupby(name,age) { + c as count(uid) + } + me(func: uid(c)) { + name + val: val(c) + } + } + ` + js := processQueryNoErr(t, query) + require.JSONEq(t, `{"data": {"me": [{"name": "Michonne","val": 1},{"name": "Rick Grimes","val": 1},{"name": "Glenn Rhee","val": 1},{"name": "Daryl Dixon","val": 1},{"name": "Andrea","val": 1}]}}`, js) +} + +func TestGroupByCountUidValVar(t *testing.T) { + query := ` + { + var(func: uid(1, 23, 24)) @groupby(school, age) { + c as count(uid) + } + me(func: uid(c)) { + name + val: val(c) + } + } + ` + js := processQueryNoErr(t, query) + require.JSONEq(t, `{"data": {"me": [{"name": "Michonne","val": 1},{"name": "Rick Grimes","val": 1},{"name": "Glenn Rhee","val": 1}]}}`, js) +} + func TestGroupByRootAlias2(t *testing.T) { query := ` { From 8925049ff80fa7aabaff8dbc64885d8568ddb6be Mon Sep 17 00:00:00 2001 From: Ahsan Barkati Date: Fri, 30 Apr 2021 11:59:06 +0530 Subject: [PATCH 3/6] feat(cdc): Add support for SCRAM SASL mechanism (#7765) We used to support only the PLAIN mechanism for SASL in CDC-Kafka. This commit adds support for SCRAM-SHA-256 and SCRAM-SHA-512. --- dgraph/cmd/alpha/run.go | 2 ++ go.mod | 1 + go.sum | 2 ++ worker/server_state.go | 2 +- worker/sink_handler.go | 48 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 1 deletion(-) diff --git a/dgraph/cmd/alpha/run.go b/dgraph/cmd/alpha/run.go index c8178fcb0f8..ebf77b5be23 100644 --- a/dgraph/cmd/alpha/run.go +++ b/dgraph/cmd/alpha/run.go @@ -233,6 +233,8 @@ they form a Raft group and provide synchronous replication. "The SASL username for Kafka."). Flag("sasl-password", "The SASL password for Kafka."). + Flag("sasl-mechanism", + "The SASL mechanism for Kafka (PLAIN, SCRAM-SHA-256 or SCRAM-SHA-512)"). Flag("ca-cert", "The path to CA cert file for TLS encryption."). Flag("client-cert", diff --git a/go.mod b/go.mod index db7ca1a9e20..a79320127a3 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/tinylib/msgp v1.1.5 // indirect github.com/twpayne/go-geom v1.0.5 + github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c go.etcd.io/etcd v0.0.0-20190228193606-a943ad0ee4c9 go.opencensus.io v0.22.5 go.uber.org/zap v1.16.0 diff --git a/go.sum b/go.sum index aced7c60f59..f2d2902c5b7 100644 --- a/go.sum +++ b/go.sum @@ -605,7 +605,9 @@ github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUd github.com/vektah/gqlparser/v2 v2.1.0/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms= github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= diff --git a/worker/server_state.go b/worker/server_state.go index 28a855359dc..56a7164b882 100644 --- a/worker/server_state.go +++ b/worker/server_state.go @@ -44,7 +44,7 @@ const ( `snapshot-after-duration=30m; pending-proposals=256; idx=; group=;` SecurityDefaults = `token=; whitelist=;` CDCDefaults = `file=; kafka=; sasl_user=; sasl_password=; ca_cert=; client_cert=; ` + - `client_key=;` + `client_key=; sasl-mechanism=PLAIN;` LimitDefaults = `mutations=allow; query-edge=1000000; normalize-node=10000; ` + `mutations-nquad=1000000; disallow-drop=false; query-timeout=0ms; txn-abort-after=5m;` + `max-pending-queries=10000; max-retries=-1;` diff --git a/worker/sink_handler.go b/worker/sink_handler.go index 93f37e55ce9..35d1943b435 100644 --- a/worker/sink_handler.go +++ b/worker/sink_handler.go @@ -17,6 +17,8 @@ package worker import ( + "crypto/sha256" + "crypto/sha512" "crypto/tls" "crypto/x509" "encoding/binary" @@ -27,6 +29,7 @@ import ( "strings" "github.com/pkg/errors" + "github.com/xdg/scram" "github.com/Shopify/sarama" @@ -116,6 +119,27 @@ func newKafkaSink(config *z.SuperFlag) (Sink, error) { saramaConf.Net.SASL.User = config.GetString("sasl-user") saramaConf.Net.SASL.Password = config.GetString("sasl-password") } + mechanism := config.GetString("sasl-mechanism") + if mechanism != "" { + switch mechanism { + case sarama.SASLTypeSCRAMSHA256: + saramaConf.Net.SASL.Mechanism = sarama.SASLTypeSCRAMSHA256 + saramaConf.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient { + return &scramClient{HashGeneratorFcn: sha256.New} + } + case sarama.SASLTypeSCRAMSHA512: + saramaConf.Net.SASL.Mechanism = sarama.SASLTypeSCRAMSHA512 + saramaConf.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient { + return &scramClient{HashGeneratorFcn: sha512.New} + } + case sarama.SASLTypePlaintext: + saramaConf.Net.SASL.Mechanism = sarama.SASLTypePlaintext + default: + return nil, errors.Errorf("Invalid SASL mechanism. Valid mechanisms are: %s, %s and %s", + sarama.SASLTypePlaintext, sarama.SASLTypeSCRAMSHA256, sarama.SASLTypeSCRAMSHA512) + } + } + brokers := strings.Split(config.GetString("kafka"), ",") client, err := sarama.NewClient(brokers, saramaConf) if err != nil { @@ -197,3 +221,27 @@ func newFileSink(path *z.SuperFlag) (Sink, error) { fileWriter: w, }, nil } + +type scramClient struct { + *scram.Client + *scram.ClientConversation + scram.HashGeneratorFcn +} + +func (sc *scramClient) Begin(userName, password, authzID string) (err error) { + sc.Client, err = sc.HashGeneratorFcn.NewClient(userName, password, authzID) + if err != nil { + return err + } + sc.ClientConversation = sc.Client.NewConversation() + return nil +} + +func (sc *scramClient) Step(challenge string) (response string, err error) { + response, err = sc.ClientConversation.Step(challenge) + return +} + +func (sc *scramClient) Done() bool { + return sc.ClientConversation.Done() +} From 07bfbf85e9407149d1c0bc7293af0ba0eb5343be Mon Sep 17 00:00:00 2001 From: vmrajas Date: Fri, 30 Apr 2021 12:40:40 +0530 Subject: [PATCH 4/6] Fix(GraphQL): Make mutation rewriting tests more robust (#7768) * Make mutation rewriting tests more robust * Fix lint --- graphql/resolve/auth_add_test.yaml | 8 ++++---- graphql/resolve/auth_test.go | 6 +++++- graphql/resolve/auth_update_test.yaml | 2 +- graphql/resolve/mutation.go | 2 +- graphql/resolve/mutation_rewriter.go | 6 +++++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/graphql/resolve/auth_add_test.yaml b/graphql/resolve/auth_add_test.yaml index 77008cfbf74..0c116e93e9f 100644 --- a/graphql/resolve/auth_add_test.yaml +++ b/graphql/resolve/auth_add_test.yaml @@ -169,7 +169,7 @@ } queryjson: | { - "Project_1": [ { "uid": "0x123" } ] + "Project_1": [ { "uid": "0x123", "dgraph.type": ["Project"] } ] } uids: | { @@ -464,8 +464,8 @@ } queryjson: | { - "Project_1": [ { "uid": "0x123" } ], - "Ticket_2": [ { "uid": "0x789" } ] + "Project_1": [ { "uid": "0x123", "dgraph.type": ["Project"] } ], + "Ticket_2": [ { "uid": "0x789", "dgraph.type": ["Ticket"] } ] } dgquerysec: |- query { @@ -627,7 +627,7 @@ } queryjson: | { - "Ticket_1": [ { "uid": "0x789" } ] + "Ticket_1": [ { "uid": "0x789", "dgraph.type": ["Ticket"] } ] } dgquerysec: |- query { diff --git a/graphql/resolve/auth_test.go b/graphql/resolve/auth_test.go index 8817c31d0e0..5d48a724bf1 100644 --- a/graphql/resolve/auth_test.go +++ b/graphql/resolve/auth_test.go @@ -783,13 +783,17 @@ func checkAddUpdateCase( resolver := NewDgraphResolver(rewriter(), ex) // -- Act -- - resolved, _ := resolver.Resolve(ctx, mut) + resolved, success := resolver.Resolve(ctx, mut) // -- Assert -- // most cases are built into the authExecutor if tcase.Error != nil { + require.False(t, success, "Mutation should have failed as it throws an error") require.NotNil(t, resolved.Err) require.Equal(t, tcase.Error.Error(), resolved.Err.Error()) + } else { + require.True(t, success, "Mutation should have not failed as it did not"+ + " throw an error") } } diff --git a/graphql/resolve/auth_update_test.yaml b/graphql/resolve/auth_update_test.yaml index 7601e0ef9a9..385d9a886ac 100644 --- a/graphql/resolve/auth_update_test.yaml +++ b/graphql/resolve/auth_update_test.yaml @@ -184,7 +184,7 @@ } queryjson: | { - "Ticket_1": [ { "uid": "0x789" } ] + "Ticket_1": [ { "uid": "0x789", "dgraph.type": ["Ticket"] } ] } dgquerysec: |- query { diff --git a/graphql/resolve/mutation.go b/graphql/resolve/mutation.go index 2f7b3637e78..b99fe7f0259 100644 --- a/graphql/resolve/mutation.go +++ b/graphql/resolve/mutation.go @@ -489,7 +489,7 @@ func (mr *dgraphResolver) rewriteAndExecute( dgQuery, err = mr.mutationRewriter.FromMutationResult(ctx, mutation, mutResp.GetUids(), result) queryErrs = schema.AppendGQLErrs(queryErrs, schema.GQLWrapf(err, "couldn't rewrite query for mutation %s", mutation.Name())) - if dgQuery == nil && err != nil { + if err != nil { return emptyResult(queryErrs), resolverFailed } diff --git a/graphql/resolve/mutation_rewriter.go b/graphql/resolve/mutation_rewriter.go index 7375b391ff9..2a33a892627 100644 --- a/graphql/resolve/mutation_rewriter.go +++ b/graphql/resolve/mutation_rewriter.go @@ -773,7 +773,11 @@ func (arw *AddRewriter) FromMutationResult( } authRw.hasAuthRules = hasAuthRules(mutation.QueryField(), authRw) - return rewriteAsQueryByIds(mutation.QueryField(), uids, authRw), errs + if errs != nil { + return nil, errs + } + // No errors are thrown while rewriting queries by Ids. + return rewriteAsQueryByIds(mutation.QueryField(), uids, authRw), nil } // FromMutationResult rewrites the query part of a GraphQL update mutation into a Dgraph query. From cfdf7a5f9567b45b8af7136665ea52e28e96feb3 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Mon, 3 May 2021 15:02:04 +0530 Subject: [PATCH 5/6] feat(Dgraph): Add task queue implementation (#7716) --- dgraph/cmd/alpha/admin.go | 42 -- dgraph/cmd/alpha/admin_backup.go | 66 -- dgraph/cmd/alpha/run.go | 1 + go.mod | 2 +- go.sum | 4 +- graphql/admin/admin.go | 48 +- graphql/admin/backup.go | 21 +- graphql/admin/endpoints_ee.go | 1 + graphql/admin/export.go | 24 +- graphql/admin/task.go | 70 ++ protos/pb.proto | 8 +- protos/pb/pb.pb.go | 682 +++++++++++--------- systest/backup/encryption/backup_test.go | 12 +- systest/backup/filesystem/backup_test.go | 11 +- systest/backup/minio-large/backup_test.go | 39 +- systest/backup/minio/backup_test.go | 12 +- systest/backup/multi-tenancy/backup_test.go | 17 +- systest/export/export_test.go | 84 +-- systest/mutations_test.go | 4 +- testutil/backup.go | 2 +- testutil/utils.go | 61 +- worker/backup_ee.go | 13 +- worker/backup_oss.go | 2 +- worker/export.go | 4 +- worker/queue.go | 357 ++++++++++ worker/worker_test.go | 30 +- 26 files changed, 1038 insertions(+), 579 deletions(-) delete mode 100644 dgraph/cmd/alpha/admin_backup.go create mode 100644 graphql/admin/task.go create mode 100644 worker/queue.go diff --git a/dgraph/cmd/alpha/admin.go b/dgraph/cmd/alpha/admin.go index 32f498853d4..62e1f248377 100644 --- a/dgraph/cmd/alpha/admin.go +++ b/dgraph/cmd/alpha/admin.go @@ -83,8 +83,6 @@ func getAdminMux() *http.ServeMux { http.MethodPut: true, http.MethodPost: true, }, adminAuthHandler(http.HandlerFunc(drainingHandler)))) - adminMux.Handle("/admin/export", allowedMethodsHandler(allowedMethods{http.MethodGet: true}, - adminAuthHandler(http.HandlerFunc(exportHandler)))) adminMux.Handle("/admin/config/cache_mb", allowedMethodsHandler(allowedMethods{ http.MethodGet: true, http.MethodPut: true, @@ -160,46 +158,6 @@ func shutDownHandler(w http.ResponseWriter, r *http.Request) { x.Check2(w.Write([]byte(`{"code": "Success", "message": "Server is shutting down"}`))) } -func exportHandler(w http.ResponseWriter, r *http.Request) { - if err := r.ParseForm(); err != nil { - x.SetHttpStatus(w, http.StatusBadRequest, "Parse of export request failed.") - return - } - - format := worker.DefaultExportFormat - if vals, ok := r.Form["format"]; ok { - if len(vals) > 1 { - x.SetHttpStatus(w, http.StatusBadRequest, - "Only one export format may be specified.") - return - } - format = worker.NormalizeExportFormat(vals[0]) - if format == "" { - x.SetHttpStatus(w, http.StatusBadRequest, "Invalid export format.") - return - } - } - - gqlReq := &schema.Request{ - Query: ` - mutation export($format: String) { - export(input: {format: $format}) { - response { - code - } - } - }`, - Variables: map[string]interface{}{}, - } - - if resp := resolveWithAdminServer(gqlReq, r, adminServer); len(resp.Errors) != 0 { - x.SetStatus(w, resp.Errors[0].Message, "Export failed.") - return - } - w.Header().Set("Content-Type", "application/json") - x.Check2(w.Write([]byte(`{"code": "Success", "message": "Export completed."}`))) -} - func memoryLimitHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: diff --git a/dgraph/cmd/alpha/admin_backup.go b/dgraph/cmd/alpha/admin_backup.go deleted file mode 100644 index cfcae22c82e..00000000000 --- a/dgraph/cmd/alpha/admin_backup.go +++ /dev/null @@ -1,66 +0,0 @@ -// +build !oss - -/* - * Copyright 2018 Dgraph Labs, Inc. and Contributors - * - * 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 alpha - -import ( - "net/http" - - "github.com/dgraph-io/dgraph/graphql/schema" - - "github.com/dgraph-io/dgraph/x" - "github.com/golang/glog" -) - -func init() { - http.Handle("/admin/backup", allowedMethodsHandler(allowedMethods{http.MethodPost: true}, - adminAuthHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - backupHandler(w, r) - })))) -} - -// backupHandler handles backup requests coming from the HTTP endpoint. -func backupHandler(w http.ResponseWriter, r *http.Request) { - gqlReq := &schema.Request{ - Query: ` - mutation backup($input: BackupInput!) { - backup(input: $input) { - response { - code - } - } - }`, - Variables: map[string]interface{}{"input": map[string]interface{}{ - "destination": r.FormValue("destination"), - "accessKey": r.FormValue("access_key"), - "secretKey": r.FormValue("secret_key"), - "sessionToken": r.FormValue("session_token"), - "anonymous": r.FormValue("anonymous") == "true", - "forceFull": r.FormValue("force_full") == "true", - }}, - } - glog.Infof("gqlReq %+v, r %+v adminServer %+v", gqlReq, r, adminServer) - resp := resolveWithAdminServer(gqlReq, r, adminServer) - if resp.Errors != nil { - x.SetStatus(w, resp.Errors.Error(), "Backup failed.") - return - } - - w.Header().Set("Content-Type", "application/json") - x.Check2(w.Write([]byte(`{"code": "Success", "message": "Backup completed."}`))) -} diff --git a/dgraph/cmd/alpha/run.go b/dgraph/cmd/alpha/run.go index ebf77b5be23..5d20682f99d 100644 --- a/dgraph/cmd/alpha/run.go +++ b/dgraph/cmd/alpha/run.go @@ -736,6 +736,7 @@ func run() { glog.Infof("worker.Config: %+v", worker.Config) worker.InitServerState() + worker.InitTasks() if Alpha.Conf.GetBool("expose_trace") { // TODO: Remove this once we get rid of event logs. diff --git a/go.mod b/go.mod index a79320127a3..9f8a5217b53 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/dgraph-io/gqlgen v0.13.2 github.com/dgraph-io/gqlparser/v2 v2.2.0 github.com/dgraph-io/graphql-transport-ws v0.0.0-20210223074046-e5b8b80bb4ed - github.com/dgraph-io/ristretto v0.0.4-0.20210428103110-8405ab9b246f + github.com/dgraph-io/ristretto v0.0.4-0.20210430144708-642987276d6a github.com/dgraph-io/roaring v0.5.6-0.20210227175938-766b897233a5 github.com/dgraph-io/simdjson-go v0.3.0 github.com/dgrijalva/jwt-go v3.2.0+incompatible diff --git a/go.sum b/go.sum index f2d2902c5b7..31a40a898a8 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/dgraph-io/gqlparser/v2 v2.2.0/go.mod h1:MYS4jppjyx8b9tuUtjV7jU1UFZK6P github.com/dgraph-io/graphql-transport-ws v0.0.0-20210223074046-e5b8b80bb4ed h1:pgGMBoTtFhR+xkyzINaToLYRurHn+6pxMYffIGmmEPc= github.com/dgraph-io/graphql-transport-ws v0.0.0-20210223074046-e5b8b80bb4ed/go.mod h1:7z3c/5w0sMYYZF5bHsrh8IH4fKwG5O5Y70cPH1ZLLRQ= github.com/dgraph-io/ristretto v0.0.4-0.20210309073149-3836124cdc5a/go.mod h1:MIonLggsKgZLUSt414ExgwNtlOL5MuEoAJP514mwGe8= -github.com/dgraph-io/ristretto v0.0.4-0.20210428103110-8405ab9b246f h1:vupa/2tdIvqUTP0Md7MMvdKwCQjF48m+T6LZRVc+3cg= -github.com/dgraph-io/ristretto v0.0.4-0.20210428103110-8405ab9b246f/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgraph-io/ristretto v0.0.4-0.20210430144708-642987276d6a h1:www55JYSP8aYgBPNWJLeMS/HJMba6emZyBF65/a4XRI= +github.com/dgraph-io/ristretto v0.0.4-0.20210430144708-642987276d6a/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgraph-io/roaring v0.5.6-0.20210227175938-766b897233a5 h1:9t3OKcvsQlxU9Cu0U55tgvNtaRYVGDr6rUb95P8cSbg= github.com/dgraph-io/roaring v0.5.6-0.20210227175938-766b897233a5/go.mod h1:I8kxPBtSQW3OdQFWonumQdCx2DTmq2WjdnTjGXz3uTM= github.com/dgraph-io/simdjson-go v0.3.0 h1:h71LO7vR4LHMPUhuoGN8bqGm1VNfGOlAG8BI6iDUKw0= diff --git a/graphql/admin/admin.go b/graphql/admin/admin.go index 33ef7068491..203c6c5a914 100644 --- a/graphql/admin/admin.go +++ b/graphql/admin/admin.go @@ -55,9 +55,9 @@ const ( """ The UInt64 scalar type represents an unsigned 64‐bit numeric non‐fractional value. UInt64 can represent values in range [0,(2^64 - 1)]. - """ + """ scalar UInt64 - + """ The DateTime scalar type represents date and time as a string in RFC3339 format. For example: "1985-04-12T23:20:50.52Z" represents 20 minutes and 50.52 seconds after the 23rd hour of April 12th, 1985 in UTC. @@ -243,14 +243,19 @@ const ( anonymous: Boolean } + input TaskInput { + id: String! + } + type Response { code: String message: String } type ExportPayload { - response: Response exportedFiles: [String] + response: Response + taskId: String } type DrainingPayload { @@ -261,6 +266,26 @@ const ( response: Response } + type TaskPayload { + kind: TaskKind + status: TaskStatus + lastUpdated: DateTime + } + + enum TaskStatus { + Queued + Running + Failed + Success + Unknown + } + + enum TaskKind { + Backup + Export + Unknown + } + input ConfigInput { """ Estimated memory the caches can take. Actual usage by the process would be @@ -367,6 +392,7 @@ const ( health: [NodeState] state: MembershipState config: Config + task(input: TaskInput!): TaskPayload ` + adminQueries + ` } @@ -718,7 +744,6 @@ func newAdminResolver( } func newAdminResolverFactory() resolve.ResolverFactory { - adminMutationResolvers := map[string]resolve.MutationResolverFunc{ "addNamespace": resolveAddNamespace, "backup": resolveBackup, @@ -751,18 +776,21 @@ func newAdminResolverFactory() resolve.ResolverFactory { WithQueryResolver("listBackups", func(q schema.Query) resolve.QueryResolver { return resolve.QueryResolverFunc(resolveListBackups) }). - WithMutationResolver("updateGQLSchema", func(m schema.Mutation) resolve.MutationResolver { - return resolve.MutationResolverFunc( - func(ctx context.Context, m schema.Mutation) (*resolve.Resolved, bool) { - return &resolve.Resolved{Err: errors.Errorf(errMsgServerNotReady), Field: m}, - false - }) + WithQueryResolver("task", func(q schema.Query) resolve.QueryResolver { + return resolve.QueryResolverFunc(resolveTask) }). WithQueryResolver("getGQLSchema", func(q schema.Query) resolve.QueryResolver { return resolve.QueryResolverFunc( func(ctx context.Context, query schema.Query) *resolve.Resolved { return &resolve.Resolved{Err: errors.Errorf(errMsgServerNotReady), Field: q} }) + }). + WithMutationResolver("updateGQLSchema", func(m schema.Mutation) resolve.MutationResolver { + return resolve.MutationResolverFunc( + func(ctx context.Context, m schema.Mutation) (*resolve.Resolved, bool) { + return &resolve.Resolved{Err: errors.Errorf(errMsgServerNotReady), Field: m}, + false + }) }) for gqlMut, resolver := range adminMutationResolvers { // gotta force go to evaluate the right function at each loop iteration diff --git a/graphql/admin/backup.go b/graphql/admin/backup.go index a5d51f7f4ad..0405d07ebc1 100644 --- a/graphql/admin/backup.go +++ b/graphql/admin/backup.go @@ -19,6 +19,7 @@ package admin import ( "context" "encoding/json" + "fmt" "github.com/dgraph-io/dgraph/graphql/resolve" "github.com/dgraph-io/dgraph/graphql/schema" @@ -34,27 +35,39 @@ type backupInput struct { func resolveBackup(ctx context.Context, m schema.Mutation) (*resolve.Resolved, bool) { glog.Info("Got backup request") + if !worker.EnterpriseEnabled() { + err := fmt.Errorf("you must enable enterprise features first. " + + "Supply the appropriate license file to Dgraph Zero using the HTTP endpoint.") + return resolve.EmptyResult(m, err), false + } input, err := getBackupInput(m) if err != nil { return resolve.EmptyResult(m, err), false } + if input.Destination == "" { + err := fmt.Errorf("you must specify a 'destination' value") + return resolve.EmptyResult(m, err), false + } - err = worker.ProcessBackupRequest(context.Background(), &pb.BackupRequest{ + req := &pb.BackupRequest{ Destination: input.Destination, AccessKey: input.AccessKey, SecretKey: input.SecretKey, SessionToken: input.SessionToken, Anonymous: input.Anonymous, - }, input.ForceFull) - + } + taskId, err := worker.Tasks.Enqueue(req) if err != nil { return resolve.EmptyResult(m, err), false } + msg := fmt.Sprintf("Backup queued with ID %s", taskId) + data := response("Success", msg) + data["taskId"] = taskId return resolve.DataResult( m, - map[string]interface{}{m.Name(): response("Success", "Backup completed.")}, + map[string]interface{}{m.Name(): data}, nil, ), true } diff --git a/graphql/admin/endpoints_ee.go b/graphql/admin/endpoints_ee.go index 819caa93da4..9618461d192 100644 --- a/graphql/admin/endpoints_ee.go +++ b/graphql/admin/endpoints_ee.go @@ -48,6 +48,7 @@ const adminTypes = ` type BackupPayload { response: Response + taskId: String } input RestoreInput { diff --git a/graphql/admin/export.go b/graphql/admin/export.go index f778c18d6a4..45658dfccda 100644 --- a/graphql/admin/export.go +++ b/graphql/admin/export.go @@ -19,6 +19,7 @@ package admin import ( "context" "encoding/json" + "fmt" "math" "github.com/dgraph-io/dgraph/graphql/resolve" @@ -39,7 +40,6 @@ type exportInput struct { } func resolveExport(ctx context.Context, m schema.Mutation) (*resolve.Resolved, bool) { - glog.Info("Got export request through GraphQL admin API") input, err := getExportInput(m) @@ -83,7 +83,7 @@ func resolveExport(ctx context.Context, m schema.Mutation) (*resolve.Resolved, b return resolve.EmptyResult(m, err), false } - files, err := worker.ExportOverNetwork(ctx, &pb.ExportRequest{ + req := &pb.ExportRequest{ Format: format, Namespace: exportNs, Destination: input.Destination, @@ -91,30 +91,22 @@ func resolveExport(ctx context.Context, m schema.Mutation) (*resolve.Resolved, b SecretKey: input.SecretKey, SessionToken: input.SessionToken, Anonymous: input.Anonymous, - }) + } + taskId, err := worker.Tasks.Enqueue(req) if err != nil { return resolve.EmptyResult(m, err), false } - responseData := response("Success", "Export completed.") - responseData["exportedFiles"] = toInterfaceSlice(files) - + msg := fmt.Sprintf("Export queued with ID %s", taskId) + data := response("Success", msg) + data["taskId"] = taskId return resolve.DataResult( m, - map[string]interface{}{m.Name(): responseData}, + map[string]interface{}{m.Name(): data}, nil, ), true } -// toInterfaceSlice converts []string to []interface{} -func toInterfaceSlice(in []string) []interface{} { - out := make([]interface{}, 0, len(in)) - for _, s := range in { - out = append(out, s) - } - return out -} - func getExportInput(m schema.Mutation) (*exportInput, error) { inputArg := m.ArgValue(schema.InputArgName) inputByts, err := json.Marshal(inputArg) diff --git a/graphql/admin/task.go b/graphql/admin/task.go new file mode 100644 index 00000000000..e377f3fa082 --- /dev/null +++ b/graphql/admin/task.go @@ -0,0 +1,70 @@ +/* + * Copyright 2021 Dgraph Labs, Inc. and Contributors + * + * 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 admin + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/dgraph-io/dgraph/graphql/resolve" + "github.com/dgraph-io/dgraph/graphql/schema" + "github.com/dgraph-io/dgraph/worker" +) + +type taskInput struct { + Id string +} + +func resolveTask(ctx context.Context, q schema.Query) *resolve.Resolved { + input, err := getTaskInput(q) + if err != nil { + return resolve.EmptyResult(q, err) + } + if input.Id == "" { + return resolve.EmptyResult(q, fmt.Errorf("task ID is missing")) + } + + meta, err := worker.Tasks.Get(input.Id) + if err != nil { + return resolve.EmptyResult(q, err) + } + return resolve.DataResult( + q, + map[string]interface{}{q.Name(): map[string]interface{}{ + "kind": meta.Kind().String(), + "status": meta.Status().String(), + "lastUpdated": meta.Timestamp().Format(time.RFC3339), + }}, + nil, + ) +} + +func getTaskInput(q schema.Query) (*taskInput, error) { + inputArg := q.ArgValue(schema.InputArgName) + inputBytes, err := json.Marshal(inputArg) + if err != nil { + return nil, schema.GQLWrapf(err, "couldn't get input argument") + } + + var input taskInput + if err := json.Unmarshal(inputBytes, &input); err != nil { + return nil, schema.GQLWrapf(err, "couldn't get input argument") + } + return &input, nil +} diff --git a/protos/pb.proto b/protos/pb.proto index 28d8cafb81b..9f8a27b2920 100644 --- a/protos/pb.proto +++ b/protos/pb.proto @@ -620,9 +620,13 @@ message Status { string msg = 2; } +// Backups record all data from since_ts to read_ts. +// With incremental backups, the read_ts of the first backup becomes +// the since_ts of the second backup. +// Incremental backups can be disabled using the force_full field. message BackupRequest { uint64 read_ts = 1; - uint64 since_ts = 2; + uint64 since_ts = 2; uint32 group_id = 3; string unix_ts = 4; string destination = 5; @@ -637,6 +641,8 @@ message BackupRequest { // The predicates to backup. All other predicates present in the group (e.g // stale data from a predicate move) will be ignored. repeated string predicates = 10; + + bool force_full = 11; } message BackupResponse { diff --git a/protos/pb/pb.pb.go b/protos/pb/pb.pb.go index b0cc02c368a..467e0275e50 100644 --- a/protos/pb/pb.pb.go +++ b/protos/pb/pb.pb.go @@ -4480,6 +4480,10 @@ func (m *Status) GetMsg() string { return "" } +// Backups record all data from since_ts to read_ts. +// With incremental backups, the read_ts of the first backup becomes +// the since_ts of the second backup. +// Incremental backups can be disabled using the force_full field. type BackupRequest struct { ReadTs uint64 `protobuf:"varint,1,opt,name=read_ts,json=readTs,proto3" json:"read_ts,omitempty"` SinceTs uint64 `protobuf:"varint,2,opt,name=since_ts,json=sinceTs,proto3" json:"since_ts,omitempty"` @@ -4495,6 +4499,7 @@ type BackupRequest struct { // The predicates to backup. All other predicates present in the group (e.g // stale data from a predicate move) will be ignored. Predicates []string `protobuf:"bytes,10,rep,name=predicates,proto3" json:"predicates,omitempty"` + ForceFull bool `protobuf:"varint,11,opt,name=force_full,json=forceFull,proto3" json:"force_full,omitempty"` } func (m *BackupRequest) Reset() { *m = BackupRequest{} } @@ -4600,6 +4605,13 @@ func (m *BackupRequest) GetPredicates() []string { return nil } +func (m *BackupRequest) GetForceFull() bool { + if m != nil { + return m.ForceFull + } + return false +} + type BackupResponse struct { DropOperations []*DropOperation `protobuf:"bytes,1,rep,name=drop_operations,json=dropOperations,proto3" json:"drop_operations,omitempty"` } @@ -5361,334 +5373,335 @@ func init() { func init() { proto.RegisterFile("pb.proto", fileDescriptor_f80abaa17e25ccc8) } var fileDescriptor_f80abaa17e25ccc8 = []byte{ - // 5229 bytes of a gzipped FileDescriptorProto + // 5244 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x7b, 0x4b, 0x6c, 0x1c, 0xd9, - 0x75, 0x28, 0xab, 0xfa, 0x57, 0x75, 0xfa, 0xc3, 0xe6, 0x95, 0x2c, 0xb7, 0x5b, 0x33, 0x92, 0xa6, - 0x64, 0xcd, 0x70, 0xa4, 0x11, 0xa5, 0xa1, 0x6c, 0x3c, 0xcf, 0x18, 0x0f, 0x08, 0x3f, 0x4d, 0x0d, - 0x47, 0x64, 0x53, 0xae, 0x6e, 0xc9, 0x1f, 0x20, 0x69, 0x14, 0xab, 0x2e, 0xc9, 0x32, 0xab, 0xab, - 0xca, 0x55, 0xd5, 0x34, 0xe9, 0x9d, 0x11, 0xc0, 0x46, 0x76, 0x5e, 0x66, 0x95, 0x45, 0x16, 0xd9, - 0x64, 0x11, 0x64, 0x91, 0x0f, 0x02, 0x64, 0x17, 0x04, 0x41, 0x36, 0xf1, 0x32, 0x40, 0x92, 0x41, - 0x30, 0x0e, 0xb2, 0x98, 0x5d, 0x90, 0x6d, 0x16, 0xc1, 0x3d, 0xe7, 0xd6, 0xaf, 0xd9, 0x94, 0x34, - 0x13, 0x64, 0x91, 0x55, 0xdf, 0x73, 0xce, 0xfd, 0x9e, 0x7b, 0xee, 0xf9, 0x56, 0x83, 0x16, 0x1e, - 0xae, 0x85, 0x51, 0x90, 0x04, 0x4c, 0x0d, 0x0f, 0xfb, 0xba, 0x15, 0xba, 0x04, 0xf6, 0xef, 0x1f, - 0xbb, 0xc9, 0xc9, 0xec, 0x70, 0xcd, 0x0e, 0xa6, 0x8f, 0x9c, 0xe3, 0xc8, 0x0a, 0x4f, 0x1e, 0xba, - 0xc1, 0xa3, 0x43, 0xcb, 0x39, 0xe6, 0xd1, 0xa3, 0xb3, 0x27, 0x8f, 0xc2, 0xc3, 0x47, 0xe9, 0xd0, - 0xfe, 0xc3, 0x42, 0xdf, 0xe3, 0xe0, 0x38, 0x78, 0x84, 0xe8, 0xc3, 0xd9, 0x11, 0x42, 0x08, 0x60, - 0x8b, 0xba, 0x1b, 0x03, 0xa8, 0xee, 0xb9, 0x71, 0xc2, 0x18, 0x54, 0x67, 0xae, 0x13, 0xf7, 0x94, - 0x3b, 0x95, 0xd5, 0xba, 0x89, 0x6d, 0xf6, 0x3e, 0xac, 0x1c, 0xba, 0xc9, 0xd4, 0x0a, 0x27, 0x4e, - 0x30, 0xf1, 0x83, 0x64, 0x32, 0x8b, 0x79, 0x4f, 0xbd, 0xa3, 0xac, 0xb6, 0xcc, 0x0e, 0x11, 0xb6, - 0x83, 0x61, 0x90, 0xbc, 0x88, 0xb9, 0xb1, 0x0f, 0xfa, 0xd8, 0x8a, 0x4f, 0x5f, 0x5a, 0xde, 0x8c, - 0xb3, 0x2e, 0x54, 0xce, 0x2c, 0xaf, 0xa7, 0x60, 0x4f, 0xd1, 0x64, 0x6b, 0xa0, 0x9d, 0x59, 0xde, - 0x24, 0xb9, 0x08, 0x69, 0x82, 0xce, 0xfa, 0xb5, 0xb5, 0xf0, 0x70, 0xed, 0x79, 0x10, 0x27, 0xae, - 0x7f, 0xbc, 0xf6, 0xd2, 0xf2, 0xc6, 0x17, 0x21, 0x37, 0x1b, 0x67, 0xd4, 0x30, 0x0e, 0xa0, 0x39, - 0x8a, 0xec, 0x9d, 0x99, 0x6f, 0x27, 0x6e, 0xe0, 0x8b, 0xcd, 0xf9, 0xd6, 0x94, 0xe3, 0x8c, 0xba, - 0x89, 0x6d, 0x81, 0xb3, 0xa2, 0xe3, 0xb8, 0x57, 0xb9, 0x53, 0x11, 0x38, 0xd1, 0x66, 0x3d, 0x68, - 0xb8, 0xf1, 0x56, 0x30, 0xf3, 0x93, 0x5e, 0xf5, 0x8e, 0xb2, 0xaa, 0x99, 0x29, 0x68, 0xfc, 0x45, - 0x05, 0x6a, 0xdf, 0x9b, 0xf1, 0xe8, 0x02, 0xc7, 0x25, 0x49, 0x94, 0xce, 0x25, 0xda, 0xec, 0x3a, - 0xd4, 0x3c, 0xcb, 0x3f, 0x8e, 0x7b, 0x2a, 0x4e, 0x46, 0x00, 0xbb, 0x09, 0xba, 0x75, 0x94, 0xf0, - 0x68, 0x32, 0x73, 0x9d, 0x5e, 0xe5, 0x8e, 0xb2, 0x5a, 0x37, 0x35, 0x44, 0xbc, 0x70, 0x1d, 0xf6, - 0x0d, 0xd0, 0x9c, 0x60, 0x62, 0x17, 0xd7, 0x72, 0x02, 0x5c, 0x8b, 0xdd, 0x05, 0x6d, 0xe6, 0x3a, - 0x13, 0xcf, 0x8d, 0x93, 0x5e, 0xed, 0x8e, 0xb2, 0xda, 0x5c, 0xd7, 0xc4, 0x61, 0x05, 0x9b, 0xcd, - 0xc6, 0xcc, 0x75, 0x90, 0xdf, 0xf7, 0x41, 0x8b, 0x23, 0x7b, 0x72, 0x34, 0xf3, 0xed, 0x5e, 0x1d, - 0x3b, 0x2d, 0x8b, 0x4e, 0x85, 0x53, 0x9b, 0x8d, 0x98, 0x00, 0x71, 0xac, 0x88, 0x9f, 0xf1, 0x28, - 0xe6, 0xbd, 0x06, 0x2d, 0x25, 0x41, 0xf6, 0x18, 0x9a, 0x47, 0x96, 0xcd, 0x93, 0x49, 0x68, 0x45, - 0xd6, 0xb4, 0xa7, 0xe5, 0x13, 0xed, 0x08, 0xf4, 0x73, 0x81, 0x8d, 0x4d, 0x38, 0xca, 0x00, 0xf6, - 0x04, 0xda, 0x08, 0xc5, 0x93, 0x23, 0xd7, 0x4b, 0x78, 0xd4, 0xd3, 0x71, 0x4c, 0x07, 0xc7, 0x20, - 0x66, 0x1c, 0x71, 0x6e, 0xb6, 0xa8, 0x13, 0x61, 0xd8, 0xdb, 0x00, 0xfc, 0x3c, 0xb4, 0x7c, 0x67, - 0x62, 0x79, 0x5e, 0x0f, 0x70, 0x0f, 0x3a, 0x61, 0x36, 0x3c, 0x8f, 0x7d, 0x5d, 0xec, 0xcf, 0x72, - 0x26, 0x49, 0xdc, 0x6b, 0xdf, 0x51, 0x56, 0xab, 0x66, 0x5d, 0x80, 0xe3, 0x58, 0xf0, 0xd5, 0xb6, - 0xec, 0x13, 0xde, 0xeb, 0xdc, 0x51, 0x56, 0x6b, 0x26, 0x01, 0x02, 0x7b, 0xe4, 0x46, 0x71, 0xd2, - 0x5b, 0x26, 0x2c, 0x02, 0xec, 0x06, 0xd4, 0x83, 0xa3, 0xa3, 0x98, 0x27, 0xbd, 0x2e, 0xa2, 0x25, - 0x64, 0xac, 0x83, 0x8e, 0x52, 0x85, 0x5c, 0xbb, 0x07, 0xf5, 0x33, 0x01, 0x90, 0x9c, 0x36, 0xd7, - 0xdb, 0x62, 0xdb, 0x99, 0xe0, 0x99, 0x92, 0x68, 0xdc, 0x02, 0x6d, 0xcf, 0xf2, 0x8f, 0x53, 0xc1, - 0x16, 0xd7, 0x89, 0x03, 0x74, 0x13, 0xdb, 0xc6, 0xef, 0xab, 0x50, 0x37, 0x79, 0x3c, 0xf3, 0x12, - 0xf6, 0x1e, 0x80, 0xb8, 0xac, 0xa9, 0x95, 0x44, 0xee, 0xb9, 0x9c, 0x35, 0xbf, 0x2e, 0x7d, 0xe6, - 0x3a, 0xfb, 0x48, 0x62, 0x8f, 0xa1, 0x85, 0xb3, 0xa7, 0x5d, 0xd5, 0x7c, 0x03, 0xd9, 0xfe, 0xcc, - 0x26, 0x76, 0x91, 0x23, 0x6e, 0x40, 0x1d, 0xe5, 0x83, 0x64, 0xb4, 0x6d, 0x4a, 0x88, 0xdd, 0x83, - 0x8e, 0xeb, 0x27, 0xe2, 0xfe, 0xec, 0x64, 0xe2, 0xf0, 0x38, 0x15, 0xa0, 0x76, 0x86, 0xdd, 0xe6, - 0x71, 0xc2, 0x3e, 0x04, 0xba, 0x84, 0x74, 0xc1, 0x1a, 0x2e, 0xd8, 0xc9, 0x2e, 0x37, 0xa6, 0x15, - 0xb1, 0x8f, 0x5c, 0xf1, 0x21, 0x34, 0xc5, 0xf9, 0xd2, 0x11, 0x75, 0x1c, 0xd1, 0xc2, 0xd3, 0x48, - 0x76, 0x98, 0x20, 0x3a, 0xc8, 0xee, 0x82, 0x35, 0x42, 0x48, 0x49, 0xa8, 0xb0, 0x6d, 0x0c, 0xa0, - 0x76, 0x10, 0x39, 0x3c, 0x5a, 0xf8, 0x4e, 0x18, 0x54, 0x1d, 0x1e, 0xdb, 0xf8, 0x84, 0x35, 0x13, - 0xdb, 0xf9, 0xdb, 0xa9, 0x14, 0xde, 0x8e, 0xf1, 0x07, 0x0a, 0x34, 0x47, 0x41, 0x94, 0xec, 0xf3, - 0x38, 0xb6, 0x8e, 0x39, 0xbb, 0x0d, 0xb5, 0x40, 0x4c, 0x2b, 0x39, 0xac, 0x8b, 0x3d, 0xe1, 0x3a, - 0x26, 0xe1, 0xe7, 0xee, 0x41, 0xbd, 0xfa, 0x1e, 0x84, 0x4c, 0xe1, 0xab, 0xab, 0x48, 0x99, 0xc2, - 0x37, 0x97, 0x4b, 0x4f, 0xb5, 0x28, 0x3d, 0x57, 0x8a, 0xa6, 0xf1, 0x6d, 0x00, 0xb1, 0xbf, 0x2f, - 0x29, 0x05, 0xc6, 0x2f, 0x15, 0x68, 0x9a, 0xd6, 0x51, 0xb2, 0x15, 0xf8, 0x09, 0x3f, 0x4f, 0x58, - 0x07, 0x54, 0xd7, 0x41, 0x1e, 0xd5, 0x4d, 0xd5, 0x75, 0xc4, 0xee, 0x8e, 0xa3, 0x60, 0x16, 0x22, - 0x8b, 0xda, 0x26, 0x01, 0xc8, 0x4b, 0xc7, 0x89, 0x70, 0xcb, 0x82, 0x97, 0x8e, 0x13, 0xb1, 0xdb, - 0xd0, 0x8c, 0x7d, 0x2b, 0x8c, 0x4f, 0x82, 0x44, 0xec, 0xae, 0x8a, 0xbb, 0x83, 0x14, 0x35, 0x8e, - 0xc5, 0xa3, 0x73, 0xe3, 0x89, 0xc7, 0xad, 0xc8, 0xe7, 0x11, 0x2a, 0x12, 0xcd, 0xd4, 0xdd, 0x78, - 0x8f, 0x10, 0xc6, 0x2f, 0x2b, 0x50, 0xdf, 0xe7, 0xd3, 0x43, 0x1e, 0x5d, 0xda, 0xc4, 0x63, 0xd0, - 0x70, 0xdd, 0x89, 0xeb, 0xd0, 0x3e, 0x36, 0xbf, 0xf6, 0xc5, 0x67, 0xb7, 0x57, 0x10, 0xb7, 0xeb, - 0x7c, 0x10, 0x4c, 0xdd, 0x84, 0x4f, 0xc3, 0xe4, 0xc2, 0x6c, 0x48, 0xd4, 0xc2, 0x0d, 0xde, 0x80, - 0xba, 0xc7, 0x2d, 0x71, 0x67, 0x24, 0x9e, 0x12, 0x62, 0x0f, 0xa1, 0x61, 0x4d, 0x27, 0x0e, 0xb7, - 0x1c, 0xda, 0xd4, 0xe6, 0xf5, 0x2f, 0x3e, 0xbb, 0xdd, 0xb5, 0xa6, 0xdb, 0xdc, 0x2a, 0xce, 0x5d, - 0x27, 0x0c, 0xfb, 0x48, 0xc8, 0x64, 0x9c, 0x4c, 0x66, 0xa1, 0x63, 0x25, 0x1c, 0x75, 0x5d, 0x75, - 0xb3, 0xf7, 0xc5, 0x67, 0xb7, 0xaf, 0x0b, 0xf4, 0x0b, 0xc4, 0x16, 0x86, 0x41, 0x8e, 0x15, 0x7a, - 0x2f, 0x3d, 0xbe, 0xd4, 0x7b, 0x12, 0x64, 0xbb, 0xb0, 0x62, 0x7b, 0xb3, 0x58, 0x28, 0x67, 0xd7, - 0x3f, 0x0a, 0x26, 0x81, 0xef, 0x5d, 0xe0, 0x05, 0x6b, 0x9b, 0x6f, 0x7f, 0xf1, 0xd9, 0xed, 0x6f, - 0x48, 0xe2, 0xae, 0x7f, 0x14, 0x1c, 0xf8, 0xde, 0x45, 0x61, 0xfe, 0xe5, 0x39, 0x12, 0xfb, 0x2d, - 0xe8, 0x1c, 0x05, 0x91, 0xcd, 0x27, 0x19, 0xcb, 0x3a, 0x38, 0x4f, 0xff, 0x8b, 0xcf, 0x6e, 0xdf, - 0x40, 0xca, 0xd3, 0x4b, 0x7c, 0x6b, 0x15, 0xf1, 0xc6, 0xbf, 0xa8, 0x50, 0xc3, 0x36, 0x7b, 0x0c, - 0x8d, 0x29, 0x5e, 0x49, 0xaa, 0x9f, 0x6e, 0x08, 0x19, 0x42, 0xda, 0x1a, 0xdd, 0x55, 0x3c, 0xf0, - 0x93, 0xe8, 0xc2, 0x4c, 0xbb, 0x89, 0x11, 0x89, 0x75, 0xe8, 0xf1, 0x24, 0x96, 0x32, 0x5f, 0x18, - 0x31, 0x26, 0x82, 0x1c, 0x21, 0xbb, 0xcd, 0xcb, 0x4d, 0xe5, 0x92, 0xdc, 0xf4, 0x41, 0xb3, 0x4f, - 0xb8, 0x7d, 0x1a, 0xcf, 0xa6, 0x52, 0xaa, 0x32, 0x98, 0xdd, 0x85, 0x36, 0xb6, 0xc3, 0xc0, 0xf5, - 0x71, 0x78, 0x0d, 0x3b, 0xb4, 0x72, 0xe4, 0x38, 0xee, 0xef, 0x40, 0xab, 0xb8, 0x59, 0x61, 0xce, - 0x4f, 0xf9, 0x05, 0xca, 0x57, 0xd5, 0x14, 0x4d, 0x76, 0x07, 0x6a, 0xa8, 0xe8, 0x50, 0xba, 0x9a, - 0xeb, 0x20, 0xf6, 0x4c, 0x43, 0x4c, 0x22, 0x7c, 0xac, 0x7e, 0x47, 0x11, 0xf3, 0x14, 0x8f, 0x50, - 0x9c, 0x47, 0xbf, 0x7a, 0x1e, 0x1a, 0x52, 0x98, 0xc7, 0x08, 0xa0, 0xb1, 0xe7, 0xda, 0xdc, 0x8f, - 0xd1, 0xe8, 0xcf, 0x62, 0x9e, 0x29, 0x25, 0xd1, 0x16, 0xe7, 0x9d, 0x5a, 0xe7, 0xc3, 0xc0, 0xe1, - 0x31, 0xce, 0x53, 0x35, 0x33, 0x58, 0xd0, 0xf8, 0x79, 0xe8, 0x46, 0x17, 0x63, 0xe2, 0x54, 0xc5, - 0xcc, 0x60, 0x21, 0x5d, 0xdc, 0x17, 0x8b, 0x39, 0xa9, 0x01, 0x97, 0xa0, 0xf1, 0x8b, 0x2a, 0xb4, - 0x7e, 0xc4, 0xa3, 0xe0, 0x79, 0x14, 0x84, 0x41, 0x6c, 0x79, 0x6c, 0xa3, 0xcc, 0x73, 0xba, 0xdb, - 0x3b, 0x62, 0xb7, 0xc5, 0x6e, 0x6b, 0xa3, 0xec, 0x12, 0xe8, 0xce, 0x8a, 0xb7, 0x62, 0x40, 0x9d, - 0xee, 0x7c, 0x01, 0xcf, 0x24, 0x45, 0xf4, 0xa1, 0x5b, 0xc6, 0xbd, 0x96, 0xf9, 0x21, 0x29, 0xe2, - 0x55, 0x4e, 0xad, 0xf3, 0x17, 0xbb, 0xdb, 0xf2, 0x6e, 0x25, 0x24, 0xb9, 0x30, 0x3e, 0xf7, 0xc7, - 0xe9, 0xa5, 0x66, 0xb0, 0x38, 0xa9, 0xe0, 0x48, 0xbc, 0xbb, 0xdd, 0x6b, 0x21, 0x29, 0x05, 0xd9, - 0x5b, 0xa0, 0x4f, 0xad, 0x73, 0xa1, 0xd0, 0x76, 0x1d, 0x7a, 0x9a, 0x66, 0x8e, 0x60, 0xef, 0x40, - 0x25, 0x39, 0xf7, 0xf1, 0xed, 0x09, 0xaf, 0x42, 0xf8, 0xa3, 0xe3, 0x73, 0x5f, 0xaa, 0x3e, 0x53, - 0xd0, 0xc4, 0x9d, 0xda, 0xae, 0x83, 0x4e, 0x84, 0x6e, 0x8a, 0x26, 0xbb, 0x07, 0x0d, 0x8f, 0x6e, - 0x0b, 0x1d, 0x85, 0xe6, 0x7a, 0x93, 0xf4, 0x28, 0xa2, 0xcc, 0x94, 0xc6, 0x3e, 0x00, 0x2d, 0xe5, - 0x4e, 0xaf, 0x89, 0xfd, 0xba, 0x29, 0x3f, 0x53, 0x36, 0x9a, 0x59, 0x0f, 0xf6, 0x18, 0x74, 0x87, - 0x7b, 0x3c, 0xe1, 0x13, 0x9f, 0x14, 0x79, 0x93, 0x1c, 0xc8, 0x6d, 0x44, 0x0e, 0x63, 0x93, 0xff, - 0x64, 0xc6, 0xe3, 0xc4, 0xd4, 0x1c, 0x89, 0xe8, 0xff, 0x7f, 0x58, 0x9e, 0xbb, 0x8e, 0xa2, 0xfc, - 0xb5, 0x49, 0xfe, 0xae, 0x17, 0xe5, 0xaf, 0x5a, 0x90, 0xb9, 0x4f, 0xab, 0x9a, 0xd6, 0xd5, 0x8d, - 0xff, 0xa8, 0xc0, 0xb2, 0x7c, 0x0a, 0x27, 0x6e, 0x38, 0x4a, 0xa4, 0x52, 0x42, 0x93, 0x23, 0xa5, - 0xb0, 0x6a, 0xa6, 0x20, 0xfb, 0x7f, 0x50, 0x47, 0x1d, 0x92, 0x3e, 0xe5, 0xdb, 0xf9, 0x15, 0x67, - 0xc3, 0xe9, 0x69, 0x4b, 0xf9, 0x90, 0xdd, 0xd9, 0xb7, 0xa0, 0xf6, 0x33, 0x1e, 0x05, 0x64, 0x42, - 0x9b, 0xeb, 0xb7, 0x16, 0x8d, 0x13, 0x8c, 0x91, 0xc3, 0xa8, 0xf3, 0xff, 0x54, 0x12, 0xe0, 0xcb, - 0x48, 0xc2, 0x37, 0x85, 0x19, 0x9d, 0x06, 0x67, 0xdc, 0xe9, 0x35, 0x70, 0x8f, 0x45, 0xf1, 0x4d, - 0x49, 0xa9, 0x30, 0x68, 0x0b, 0x85, 0x41, 0xbf, 0x5a, 0x18, 0xfa, 0xdb, 0xd0, 0x2c, 0xf0, 0x65, - 0xc1, 0x45, 0xdd, 0x2e, 0x2b, 0x0a, 0x3d, 0x53, 0x92, 0x45, 0x7d, 0xb3, 0x0d, 0x90, 0x73, 0xe9, - 0xab, 0x6a, 0x2d, 0xe3, 0xe7, 0x0a, 0x2c, 0x6f, 0x05, 0xbe, 0xcf, 0xd1, 0x09, 0xa7, 0x3b, 0xcf, + 0x75, 0x28, 0xab, 0xfa, 0x57, 0x75, 0xfa, 0xc3, 0xe6, 0x95, 0x2c, 0xb7, 0xa9, 0x19, 0x49, 0x53, + 0xb2, 0x66, 0x38, 0xd2, 0x88, 0xd2, 0x50, 0x36, 0x9e, 0x67, 0x8c, 0x07, 0x84, 0x9f, 0xa6, 0x86, + 0x23, 0xb2, 0x29, 0x57, 0xb7, 0xe4, 0x0f, 0x90, 0x34, 0x8a, 0x55, 0x97, 0x64, 0x99, 0xd5, 0x55, + 0xe5, 0xaa, 0x6a, 0x9a, 0xf4, 0xce, 0x08, 0x60, 0x23, 0x3b, 0x2f, 0xb3, 0xca, 0x22, 0x8b, 0x6c, + 0xb2, 0x08, 0xb2, 0xc8, 0x67, 0x93, 0x5d, 0x10, 0x04, 0xd9, 0xc4, 0xcb, 0x04, 0x49, 0x06, 0xc1, + 0x38, 0xc8, 0x62, 0x76, 0x41, 0xb6, 0x59, 0x04, 0xf7, 0x9c, 0x5b, 0xbf, 0xee, 0xa6, 0xa4, 0x99, + 0x20, 0x8b, 0xac, 0xfa, 0x9e, 0x73, 0xee, 0xf7, 0xdc, 0x73, 0xcf, 0xb7, 0x1a, 0xb4, 0xf0, 0x68, + 0x3d, 0x8c, 0x82, 0x24, 0x60, 0x6a, 0x78, 0xb4, 0xaa, 0x5b, 0xa1, 0x4b, 0xe0, 0xea, 0xfd, 0x13, + 0x37, 0x39, 0x9d, 0x1e, 0xad, 0xdb, 0xc1, 0xe4, 0x91, 0x73, 0x12, 0x59, 0xe1, 0xe9, 0x43, 0x37, + 0x78, 0x74, 0x64, 0x39, 0x27, 0x3c, 0x7a, 0x74, 0xfe, 0xe4, 0x51, 0x78, 0xf4, 0x28, 0x1d, 0xba, + 0xfa, 0xb0, 0xd0, 0xf7, 0x24, 0x38, 0x09, 0x1e, 0x21, 0xfa, 0x68, 0x7a, 0x8c, 0x10, 0x02, 0xd8, + 0xa2, 0xee, 0x46, 0x1f, 0xaa, 0xfb, 0x6e, 0x9c, 0x30, 0x06, 0xd5, 0xa9, 0xeb, 0xc4, 0x3d, 0xe5, + 0x4e, 0x65, 0xad, 0x6e, 0x62, 0x9b, 0xbd, 0x0f, 0x2b, 0x47, 0x6e, 0x32, 0xb1, 0xc2, 0xb1, 0x13, + 0x8c, 0xfd, 0x20, 0x19, 0x4f, 0x63, 0xde, 0x53, 0xef, 0x28, 0x6b, 0x2d, 0xb3, 0x43, 0x84, 0x9d, + 0x60, 0x10, 0x24, 0x2f, 0x62, 0x6e, 0x1c, 0x80, 0x3e, 0xb2, 0xe2, 0xb3, 0x97, 0x96, 0x37, 0xe5, + 0xac, 0x0b, 0x95, 0x73, 0xcb, 0xeb, 0x29, 0xd8, 0x53, 0x34, 0xd9, 0x3a, 0x68, 0xe7, 0x96, 0x37, + 0x4e, 0x2e, 0x43, 0x9a, 0xa0, 0xb3, 0x71, 0x6d, 0x3d, 0x3c, 0x5a, 0x7f, 0x1e, 0xc4, 0x89, 0xeb, + 0x9f, 0xac, 0xbf, 0xb4, 0xbc, 0xd1, 0x65, 0xc8, 0xcd, 0xc6, 0x39, 0x35, 0x8c, 0x43, 0x68, 0x0e, + 0x23, 0x7b, 0x77, 0xea, 0xdb, 0x89, 0x1b, 0xf8, 0x62, 0x73, 0xbe, 0x35, 0xe1, 0x38, 0xa3, 0x6e, + 0x62, 0x5b, 0xe0, 0xac, 0xe8, 0x24, 0xee, 0x55, 0xee, 0x54, 0x04, 0x4e, 0xb4, 0x59, 0x0f, 0x1a, + 0x6e, 0xbc, 0x1d, 0x4c, 0xfd, 0xa4, 0x57, 0xbd, 0xa3, 0xac, 0x69, 0x66, 0x0a, 0x1a, 0x7f, 0x51, + 0x81, 0xda, 0xf7, 0xa6, 0x3c, 0xba, 0xc4, 0x71, 0x49, 0x12, 0xa5, 0x73, 0x89, 0x36, 0xbb, 0x0e, + 0x35, 0xcf, 0xf2, 0x4f, 0xe2, 0x9e, 0x8a, 0x93, 0x11, 0xc0, 0x6e, 0x82, 0x6e, 0x1d, 0x27, 0x3c, + 0x1a, 0x4f, 0x5d, 0xa7, 0x57, 0xb9, 0xa3, 0xac, 0xd5, 0x4d, 0x0d, 0x11, 0x2f, 0x5c, 0x87, 0x7d, + 0x03, 0x34, 0x27, 0x18, 0xdb, 0xc5, 0xb5, 0x9c, 0x00, 0xd7, 0x62, 0x77, 0x41, 0x9b, 0xba, 0xce, + 0xd8, 0x73, 0xe3, 0xa4, 0x57, 0xbb, 0xa3, 0xac, 0x35, 0x37, 0x34, 0x71, 0x58, 0xc1, 0x66, 0xb3, + 0x31, 0x75, 0x1d, 0xe4, 0xf7, 0x7d, 0xd0, 0xe2, 0xc8, 0x1e, 0x1f, 0x4f, 0x7d, 0xbb, 0x57, 0xc7, + 0x4e, 0xcb, 0xa2, 0x53, 0xe1, 0xd4, 0x66, 0x23, 0x26, 0x40, 0x1c, 0x2b, 0xe2, 0xe7, 0x3c, 0x8a, + 0x79, 0xaf, 0x41, 0x4b, 0x49, 0x90, 0x3d, 0x86, 0xe6, 0xb1, 0x65, 0xf3, 0x64, 0x1c, 0x5a, 0x91, + 0x35, 0xe9, 0x69, 0xf9, 0x44, 0xbb, 0x02, 0xfd, 0x5c, 0x60, 0x63, 0x13, 0x8e, 0x33, 0x80, 0x3d, + 0x81, 0x36, 0x42, 0xf1, 0xf8, 0xd8, 0xf5, 0x12, 0x1e, 0xf5, 0x74, 0x1c, 0xd3, 0xc1, 0x31, 0x88, + 0x19, 0x45, 0x9c, 0x9b, 0x2d, 0xea, 0x44, 0x18, 0xf6, 0x36, 0x00, 0xbf, 0x08, 0x2d, 0xdf, 0x19, + 0x5b, 0x9e, 0xd7, 0x03, 0xdc, 0x83, 0x4e, 0x98, 0x4d, 0xcf, 0x63, 0x5f, 0x17, 0xfb, 0xb3, 0x9c, + 0x71, 0x12, 0xf7, 0xda, 0x77, 0x94, 0xb5, 0xaa, 0x59, 0x17, 0xe0, 0x28, 0x16, 0x7c, 0xb5, 0x2d, + 0xfb, 0x94, 0xf7, 0x3a, 0x77, 0x94, 0xb5, 0x9a, 0x49, 0x80, 0xc0, 0x1e, 0xbb, 0x51, 0x9c, 0xf4, + 0x96, 0x09, 0x8b, 0x00, 0xbb, 0x01, 0xf5, 0xe0, 0xf8, 0x38, 0xe6, 0x49, 0xaf, 0x8b, 0x68, 0x09, + 0x19, 0x1b, 0xa0, 0xa3, 0x54, 0x21, 0xd7, 0xee, 0x41, 0xfd, 0x5c, 0x00, 0x24, 0xa7, 0xcd, 0x8d, + 0xb6, 0xd8, 0x76, 0x26, 0x78, 0xa6, 0x24, 0x1a, 0xb7, 0x40, 0xdb, 0xb7, 0xfc, 0x93, 0x54, 0xb0, + 0xc5, 0x75, 0xe2, 0x00, 0xdd, 0xc4, 0xb6, 0xf1, 0xfb, 0x2a, 0xd4, 0x4d, 0x1e, 0x4f, 0xbd, 0x84, + 0xbd, 0x07, 0x20, 0x2e, 0x6b, 0x62, 0x25, 0x91, 0x7b, 0x21, 0x67, 0xcd, 0xaf, 0x4b, 0x9f, 0xba, + 0xce, 0x01, 0x92, 0xd8, 0x63, 0x68, 0xe1, 0xec, 0x69, 0x57, 0x35, 0xdf, 0x40, 0xb6, 0x3f, 0xb3, + 0x89, 0x5d, 0xe4, 0x88, 0x1b, 0x50, 0x47, 0xf9, 0x20, 0x19, 0x6d, 0x9b, 0x12, 0x62, 0xf7, 0xa0, + 0xe3, 0xfa, 0x89, 0xb8, 0x3f, 0x3b, 0x19, 0x3b, 0x3c, 0x4e, 0x05, 0xa8, 0x9d, 0x61, 0x77, 0x78, + 0x9c, 0xb0, 0x0f, 0x81, 0x2e, 0x21, 0x5d, 0xb0, 0x86, 0x0b, 0x76, 0xb2, 0xcb, 0x8d, 0x69, 0x45, + 0xec, 0x23, 0x57, 0x7c, 0x08, 0x4d, 0x71, 0xbe, 0x74, 0x44, 0x1d, 0x47, 0xb4, 0xf0, 0x34, 0x92, + 0x1d, 0x26, 0x88, 0x0e, 0xb2, 0xbb, 0x60, 0x8d, 0x10, 0x52, 0x12, 0x2a, 0x6c, 0x1b, 0x7d, 0xa8, + 0x1d, 0x46, 0x0e, 0x8f, 0x16, 0xbe, 0x13, 0x06, 0x55, 0x87, 0xc7, 0x36, 0x3e, 0x61, 0xcd, 0xc4, + 0x76, 0xfe, 0x76, 0x2a, 0x85, 0xb7, 0x63, 0xfc, 0x81, 0x02, 0xcd, 0x61, 0x10, 0x25, 0x07, 0x3c, + 0x8e, 0xad, 0x13, 0xce, 0x6e, 0x43, 0x2d, 0x10, 0xd3, 0x4a, 0x0e, 0xeb, 0x62, 0x4f, 0xb8, 0x8e, + 0x49, 0xf8, 0x99, 0x7b, 0x50, 0xaf, 0xbe, 0x07, 0x21, 0x53, 0xf8, 0xea, 0x2a, 0x52, 0xa6, 0xf0, + 0xcd, 0xe5, 0xd2, 0x53, 0x2d, 0x4a, 0xcf, 0x95, 0xa2, 0x69, 0x7c, 0x1b, 0x40, 0xec, 0xef, 0x4b, + 0x4a, 0x81, 0xf1, 0x4b, 0x05, 0x9a, 0xa6, 0x75, 0x9c, 0x6c, 0x07, 0x7e, 0xc2, 0x2f, 0x12, 0xd6, + 0x01, 0xd5, 0x75, 0x90, 0x47, 0x75, 0x53, 0x75, 0x1d, 0xb1, 0xbb, 0x93, 0x28, 0x98, 0x86, 0xc8, + 0xa2, 0xb6, 0x49, 0x00, 0xf2, 0xd2, 0x71, 0x22, 0xdc, 0xb2, 0xe0, 0xa5, 0xe3, 0x44, 0xec, 0x36, + 0x34, 0x63, 0xdf, 0x0a, 0xe3, 0xd3, 0x20, 0x11, 0xbb, 0xab, 0xe2, 0xee, 0x20, 0x45, 0x8d, 0x62, + 0xf1, 0xe8, 0xdc, 0x78, 0xec, 0x71, 0x2b, 0xf2, 0x79, 0x84, 0x8a, 0x44, 0x33, 0x75, 0x37, 0xde, + 0x27, 0x84, 0xf1, 0xcb, 0x0a, 0xd4, 0x0f, 0xf8, 0xe4, 0x88, 0x47, 0x73, 0x9b, 0x78, 0x0c, 0x1a, + 0xae, 0x3b, 0x76, 0x1d, 0xda, 0xc7, 0xd6, 0xd7, 0xbe, 0xf8, 0xec, 0xf6, 0x0a, 0xe2, 0xf6, 0x9c, + 0x0f, 0x82, 0x89, 0x9b, 0xf0, 0x49, 0x98, 0x5c, 0x9a, 0x0d, 0x89, 0x5a, 0xb8, 0xc1, 0x1b, 0x50, + 0xf7, 0xb8, 0x25, 0xee, 0x8c, 0xc4, 0x53, 0x42, 0xec, 0x21, 0x34, 0xac, 0xc9, 0xd8, 0xe1, 0x96, + 0x43, 0x9b, 0xda, 0xba, 0xfe, 0xc5, 0x67, 0xb7, 0xbb, 0xd6, 0x64, 0x87, 0x5b, 0xc5, 0xb9, 0xeb, + 0x84, 0x61, 0x1f, 0x09, 0x99, 0x8c, 0x93, 0xf1, 0x34, 0x74, 0xac, 0x84, 0xa3, 0xae, 0xab, 0x6e, + 0xf5, 0xbe, 0xf8, 0xec, 0xf6, 0x75, 0x81, 0x7e, 0x81, 0xd8, 0xc2, 0x30, 0xc8, 0xb1, 0x42, 0xef, + 0xa5, 0xc7, 0x97, 0x7a, 0x4f, 0x82, 0x6c, 0x0f, 0x56, 0x6c, 0x6f, 0x1a, 0x0b, 0xe5, 0xec, 0xfa, + 0xc7, 0xc1, 0x38, 0xf0, 0xbd, 0x4b, 0xbc, 0x60, 0x6d, 0xeb, 0xed, 0x2f, 0x3e, 0xbb, 0xfd, 0x0d, + 0x49, 0xdc, 0xf3, 0x8f, 0x83, 0x43, 0xdf, 0xbb, 0x2c, 0xcc, 0xbf, 0x3c, 0x43, 0x62, 0xbf, 0x05, + 0x9d, 0xe3, 0x20, 0xb2, 0xf9, 0x38, 0x63, 0x59, 0x07, 0xe7, 0x59, 0xfd, 0xe2, 0xb3, 0xdb, 0x37, + 0x90, 0xf2, 0x74, 0x8e, 0x6f, 0xad, 0x22, 0xde, 0xf8, 0x17, 0x15, 0x6a, 0xd8, 0x66, 0x8f, 0xa1, + 0x31, 0xc1, 0x2b, 0x49, 0xf5, 0xd3, 0x0d, 0x21, 0x43, 0x48, 0x5b, 0xa7, 0xbb, 0x8a, 0xfb, 0x7e, + 0x12, 0x5d, 0x9a, 0x69, 0x37, 0x31, 0x22, 0xb1, 0x8e, 0x3c, 0x9e, 0xc4, 0x52, 0xe6, 0x0b, 0x23, + 0x46, 0x44, 0x90, 0x23, 0x64, 0xb7, 0x59, 0xb9, 0xa9, 0xcc, 0xc9, 0xcd, 0x2a, 0x68, 0xf6, 0x29, + 0xb7, 0xcf, 0xe2, 0xe9, 0x44, 0x4a, 0x55, 0x06, 0xb3, 0xbb, 0xd0, 0xc6, 0x76, 0x18, 0xb8, 0x3e, + 0x0e, 0xaf, 0x61, 0x87, 0x56, 0x8e, 0x1c, 0xc5, 0xab, 0xbb, 0xd0, 0x2a, 0x6e, 0x56, 0x98, 0xf3, + 0x33, 0x7e, 0x89, 0xf2, 0x55, 0x35, 0x45, 0x93, 0xdd, 0x81, 0x1a, 0x2a, 0x3a, 0x94, 0xae, 0xe6, + 0x06, 0x88, 0x3d, 0xd3, 0x10, 0x93, 0x08, 0x1f, 0xab, 0xdf, 0x51, 0xc4, 0x3c, 0xc5, 0x23, 0x14, + 0xe7, 0xd1, 0xaf, 0x9e, 0x87, 0x86, 0x14, 0xe6, 0x31, 0x02, 0x68, 0xec, 0xbb, 0x36, 0xf7, 0x63, + 0x34, 0xfa, 0xd3, 0x98, 0x67, 0x4a, 0x49, 0xb4, 0xc5, 0x79, 0x27, 0xd6, 0xc5, 0x20, 0x70, 0x78, + 0x8c, 0xf3, 0x54, 0xcd, 0x0c, 0x16, 0x34, 0x7e, 0x11, 0xba, 0xd1, 0xe5, 0x88, 0x38, 0x55, 0x31, + 0x33, 0x58, 0x48, 0x17, 0xf7, 0xc5, 0x62, 0x4e, 0x6a, 0xc0, 0x25, 0x68, 0xfc, 0xa2, 0x0a, 0xad, + 0x1f, 0xf1, 0x28, 0x78, 0x1e, 0x05, 0x61, 0x10, 0x5b, 0x1e, 0xdb, 0x2c, 0xf3, 0x9c, 0xee, 0xf6, + 0x8e, 0xd8, 0x6d, 0xb1, 0xdb, 0xfa, 0x30, 0xbb, 0x04, 0xba, 0xb3, 0xe2, 0xad, 0x18, 0x50, 0xa7, + 0x3b, 0x5f, 0xc0, 0x33, 0x49, 0x11, 0x7d, 0xe8, 0x96, 0x71, 0xaf, 0x65, 0x7e, 0x48, 0x8a, 0x78, + 0x95, 0x13, 0xeb, 0xe2, 0xc5, 0xde, 0x8e, 0xbc, 0x5b, 0x09, 0x49, 0x2e, 0x8c, 0x2e, 0xfc, 0x51, + 0x7a, 0xa9, 0x19, 0x2c, 0x4e, 0x2a, 0x38, 0x12, 0xef, 0xed, 0xf4, 0x5a, 0x48, 0x4a, 0x41, 0xf6, + 0x16, 0xe8, 0x13, 0xeb, 0x42, 0x28, 0xb4, 0x3d, 0x87, 0x9e, 0xa6, 0x99, 0x23, 0xd8, 0x3b, 0x50, + 0x49, 0x2e, 0x7c, 0x7c, 0x7b, 0xc2, 0xab, 0x10, 0xfe, 0xe8, 0xe8, 0xc2, 0x97, 0xaa, 0xcf, 0x14, + 0x34, 0x71, 0xa7, 0xb6, 0xeb, 0xa0, 0x13, 0xa1, 0x9b, 0xa2, 0xc9, 0xee, 0x41, 0xc3, 0xa3, 0xdb, + 0x42, 0x47, 0xa1, 0xb9, 0xd1, 0x24, 0x3d, 0x8a, 0x28, 0x33, 0xa5, 0xb1, 0x0f, 0x40, 0x4b, 0xb9, + 0xd3, 0x6b, 0x62, 0xbf, 0x6e, 0xca, 0xcf, 0x94, 0x8d, 0x66, 0xd6, 0x83, 0x3d, 0x06, 0xdd, 0xe1, + 0x1e, 0x4f, 0xf8, 0xd8, 0x27, 0x45, 0xde, 0x24, 0x07, 0x72, 0x07, 0x91, 0x83, 0xd8, 0xe4, 0x3f, + 0x99, 0xf2, 0x38, 0x31, 0x35, 0x47, 0x22, 0x56, 0xff, 0x3f, 0x2c, 0xcf, 0x5c, 0x47, 0x51, 0xfe, + 0xda, 0x24, 0x7f, 0xd7, 0x8b, 0xf2, 0x57, 0x2d, 0xc8, 0xdc, 0xa7, 0x55, 0x4d, 0xeb, 0xea, 0xc6, + 0x7f, 0x54, 0x60, 0x59, 0x3e, 0x85, 0x53, 0x37, 0x1c, 0x26, 0x52, 0x29, 0xa1, 0xc9, 0x91, 0x52, + 0x58, 0x35, 0x53, 0x90, 0xfd, 0x3f, 0xa8, 0xa3, 0x0e, 0x49, 0x9f, 0xf2, 0xed, 0xfc, 0x8a, 0xb3, + 0xe1, 0xf4, 0xb4, 0xa5, 0x7c, 0xc8, 0xee, 0xec, 0x5b, 0x50, 0xfb, 0x19, 0x8f, 0x02, 0x32, 0xa1, + 0xcd, 0x8d, 0x5b, 0x8b, 0xc6, 0x09, 0xc6, 0xc8, 0x61, 0xd4, 0xf9, 0x7f, 0x2a, 0x09, 0xf0, 0x65, + 0x24, 0xe1, 0x9b, 0xc2, 0x8c, 0x4e, 0x82, 0x73, 0xee, 0xf4, 0x1a, 0xb8, 0xc7, 0xa2, 0xf8, 0xa6, + 0xa4, 0x54, 0x18, 0xb4, 0x85, 0xc2, 0xa0, 0x5f, 0x2d, 0x0c, 0xab, 0x3b, 0xd0, 0x2c, 0xf0, 0x65, + 0xc1, 0x45, 0xdd, 0x2e, 0x2b, 0x0a, 0x3d, 0x53, 0x92, 0x45, 0x7d, 0xb3, 0x03, 0x90, 0x73, 0xe9, + 0xab, 0x6a, 0x2d, 0xe3, 0xe7, 0x0a, 0x2c, 0x6f, 0x07, 0xbe, 0xcf, 0xd1, 0x09, 0xa7, 0x3b, 0xcf, 0x1f, 0xaf, 0x72, 0xe5, 0xe3, 0x7d, 0x1f, 0x6a, 0xb1, 0xe8, 0x2c, 0x67, 0xbf, 0xb6, 0xe0, 0x12, - 0x4d, 0xea, 0x21, 0x54, 0xf8, 0xd4, 0x3a, 0x9f, 0x84, 0xdc, 0x77, 0x5c, 0xff, 0x38, 0x55, 0xe1, - 0x53, 0xeb, 0xfc, 0x39, 0x61, 0x8c, 0xbf, 0x54, 0x01, 0x3e, 0xe1, 0x96, 0x97, 0x9c, 0x08, 0x33, + 0x4d, 0xea, 0x21, 0x54, 0xf8, 0xc4, 0xba, 0x18, 0x87, 0xdc, 0x77, 0x5c, 0xff, 0x24, 0x55, 0xe1, + 0x13, 0xeb, 0xe2, 0x39, 0x61, 0x8c, 0xbf, 0x54, 0x01, 0x3e, 0xe1, 0x96, 0x97, 0x9c, 0x0a, 0x33, 0x25, 0x6e, 0xd4, 0xf5, 0xe3, 0xc4, 0xf2, 0xed, 0x34, 0x04, 0xca, 0x60, 0x71, 0xa3, 0xc2, 0x5a, - 0xf3, 0x98, 0x94, 0x9f, 0x6e, 0xa6, 0xa0, 0x90, 0x0f, 0xb1, 0xdc, 0x2c, 0x96, 0x56, 0x5d, 0x42, + 0xf3, 0x98, 0x94, 0x9f, 0x6e, 0xa6, 0xa0, 0x90, 0x0f, 0xb1, 0xdc, 0x34, 0x96, 0x56, 0x5d, 0x42, 0xb9, 0x8b, 0x52, 0x45, 0xb4, 0x74, 0x51, 0x7a, 0xd0, 0x10, 0x21, 0x85, 0x1b, 0xf8, 0x28, 0x34, - 0xba, 0x99, 0x82, 0x62, 0x9e, 0x59, 0x98, 0xb8, 0x53, 0xb2, 0xdd, 0x15, 0x53, 0x42, 0x62, 0x57, - 0xc2, 0x56, 0x0f, 0xec, 0x93, 0x00, 0x55, 0x44, 0xc5, 0xcc, 0x60, 0x31, 0x5b, 0xe0, 0x1f, 0x07, - 0xe2, 0x74, 0x1a, 0xba, 0x85, 0x29, 0x48, 0x67, 0x71, 0xf8, 0xb9, 0x20, 0xe9, 0x48, 0xca, 0x60, - 0xc1, 0x17, 0xce, 0x27, 0x47, 0xdc, 0x4a, 0x66, 0x11, 0x8f, 0x7b, 0x80, 0x64, 0xe0, 0x7c, 0x47, - 0x62, 0xd8, 0x3b, 0xd0, 0x12, 0x8c, 0xb3, 0xe2, 0xd8, 0x3d, 0xf6, 0xb9, 0x83, 0x8a, 0xa3, 0x6a, - 0x0a, 0x66, 0x6e, 0x48, 0x94, 0xf1, 0xd7, 0x2a, 0xd4, 0x49, 0x65, 0x96, 0xdc, 0x20, 0xe5, 0x8d, + 0xba, 0x99, 0x82, 0x62, 0x9e, 0x69, 0x98, 0xb8, 0x13, 0xb2, 0xdd, 0x15, 0x53, 0x42, 0x62, 0x57, + 0xc2, 0x56, 0xf7, 0xed, 0xd3, 0x00, 0x55, 0x44, 0xc5, 0xcc, 0x60, 0x31, 0x5b, 0xe0, 0x9f, 0x04, + 0xe2, 0x74, 0x1a, 0xba, 0x85, 0x29, 0x48, 0x67, 0x71, 0xf8, 0x85, 0x20, 0xe9, 0x48, 0xca, 0x60, + 0xc1, 0x17, 0xce, 0xc7, 0xc7, 0xdc, 0x4a, 0xa6, 0x11, 0x8f, 0x7b, 0x80, 0x64, 0xe0, 0x7c, 0x57, + 0x62, 0xd8, 0x3b, 0xd0, 0x12, 0x8c, 0xb3, 0xe2, 0xd8, 0x3d, 0xf1, 0xb9, 0x83, 0x8a, 0xa3, 0x6a, + 0x0a, 0x66, 0x6e, 0x4a, 0x94, 0xf1, 0x57, 0x2a, 0xd4, 0x49, 0x65, 0x96, 0xdc, 0x20, 0xe5, 0x8d, 0xdc, 0xa0, 0xb7, 0x40, 0x0f, 0x23, 0xee, 0xb8, 0x76, 0x7a, 0x8f, 0xba, 0x99, 0x23, 0x30, 0x6e, - 0x11, 0x76, 0x1f, 0xf9, 0xa9, 0x99, 0x04, 0x30, 0x03, 0xda, 0x81, 0x3f, 0x71, 0xdc, 0xf8, 0x74, - 0x72, 0x78, 0x91, 0xf0, 0x58, 0xf2, 0xa2, 0x19, 0xf8, 0xdb, 0x6e, 0x7c, 0xba, 0x29, 0x50, 0x82, + 0x11, 0x76, 0x1f, 0xf9, 0xa9, 0x99, 0x04, 0x30, 0x03, 0xda, 0x81, 0x3f, 0x76, 0xdc, 0xf8, 0x6c, + 0x7c, 0x74, 0x99, 0xf0, 0x58, 0xf2, 0xa2, 0x19, 0xf8, 0x3b, 0x6e, 0x7c, 0xb6, 0x25, 0x50, 0x82, 0x85, 0xf4, 0x46, 0xf0, 0x6d, 0x68, 0xa6, 0x84, 0xd8, 0x13, 0xd0, 0xd1, 0x3b, 0x45, 0xf7, 0x45, - 0x47, 0xb7, 0xe3, 0xc6, 0x17, 0x9f, 0xdd, 0x66, 0x02, 0x39, 0xe7, 0xb7, 0x68, 0x29, 0x4e, 0xf8, - 0x5f, 0x62, 0xb0, 0x30, 0x44, 0xf8, 0x86, 0xc9, 0xff, 0x12, 0xa8, 0x71, 0x5c, 0xf4, 0xbf, 0x08, - 0xc3, 0x1e, 0x02, 0x9b, 0xf9, 0x76, 0x30, 0x0d, 0x85, 0x50, 0x70, 0x47, 0x6e, 0xb2, 0x89, 0x9b, - 0x5c, 0x29, 0x52, 0x70, 0xab, 0xc6, 0x3f, 0xab, 0xd0, 0xda, 0x76, 0x23, 0x6e, 0x27, 0xdc, 0x19, - 0x38, 0xc7, 0x5c, 0xec, 0x9d, 0xfb, 0x89, 0x9b, 0x5c, 0x48, 0x07, 0x53, 0x42, 0x59, 0x7c, 0xa0, - 0x96, 0xe3, 0x68, 0x7a, 0x61, 0x15, 0x0c, 0xfd, 0x09, 0x60, 0xeb, 0x00, 0x14, 0x39, 0x61, 0xf8, + 0x47, 0xb7, 0xe3, 0xc6, 0x17, 0x9f, 0xdd, 0x66, 0x02, 0x39, 0xe3, 0xb7, 0x68, 0x29, 0x4e, 0xf8, + 0x5f, 0x62, 0xb0, 0x30, 0x44, 0xf8, 0x86, 0xc9, 0xff, 0x12, 0xa8, 0x51, 0x5c, 0xf4, 0xbf, 0x08, + 0xc3, 0x1e, 0x02, 0x9b, 0xfa, 0x76, 0x30, 0x09, 0x85, 0x50, 0x70, 0x47, 0x6e, 0xb2, 0x89, 0x9b, + 0x5c, 0x29, 0x52, 0x70, 0xab, 0xc6, 0x3f, 0xab, 0xd0, 0xda, 0x71, 0x23, 0x6e, 0x27, 0xdc, 0xe9, + 0x3b, 0x27, 0x5c, 0xec, 0x9d, 0xfb, 0x89, 0x9b, 0x5c, 0x4a, 0x07, 0x53, 0x42, 0x59, 0x7c, 0xa0, + 0x96, 0xe3, 0x68, 0x7a, 0x61, 0x15, 0x0c, 0xfd, 0x09, 0x60, 0x1b, 0x00, 0x14, 0x39, 0x61, 0xf8, 0x5f, 0xbd, 0x3a, 0xfc, 0xd7, 0xb1, 0x9b, 0x68, 0x8a, 0xf0, 0x9a, 0xc6, 0xb8, 0xe4, 0x65, 0xd6, - 0x31, 0x37, 0x30, 0xe3, 0xe4, 0xab, 0x62, 0x40, 0xd7, 0xa0, 0x85, 0x45, 0x9b, 0xdd, 0x05, 0x35, - 0x08, 0x91, 0xb9, 0x72, 0xea, 0xe2, 0x11, 0xd6, 0x0e, 0x42, 0x53, 0x0d, 0x42, 0xf1, 0x8a, 0x29, + 0x31, 0x37, 0x30, 0xe5, 0xe4, 0xab, 0x62, 0x40, 0xd7, 0xa0, 0x85, 0x45, 0x9b, 0xdd, 0x05, 0x35, + 0x08, 0x91, 0xb9, 0x72, 0xea, 0xe2, 0x11, 0xd6, 0x0f, 0x43, 0x53, 0x0d, 0x42, 0xf1, 0x8a, 0x29, 0xaa, 0x45, 0xc1, 0x13, 0xaf, 0x58, 0x58, 0x34, 0x8c, 0xa5, 0x4c, 0x49, 0x61, 0x06, 0xb4, 0x2c, 0xcf, 0x0b, 0x7e, 0xca, 0x9d, 0xe7, 0x11, 0x77, 0x52, 0x19, 0x2c, 0xe1, 0x84, 0x94, 0xf8, 0xd6, - 0x94, 0xc7, 0xa1, 0x65, 0x73, 0x29, 0x82, 0x39, 0xc2, 0xb8, 0x01, 0xea, 0x41, 0xc8, 0x1a, 0x50, - 0x19, 0x0d, 0xc6, 0xdd, 0x25, 0xd1, 0xd8, 0x1e, 0xec, 0x75, 0x85, 0x45, 0xa9, 0x77, 0x1b, 0xc6, - 0xe7, 0x2a, 0xe8, 0xfb, 0xb3, 0xc4, 0x12, 0xba, 0x25, 0x16, 0xa7, 0x2c, 0x4b, 0x68, 0x2e, 0x8a, - 0xdf, 0x00, 0x2d, 0x4e, 0xac, 0x08, 0xfd, 0x0d, 0xb2, 0x4e, 0x0d, 0x84, 0xc7, 0x31, 0x7b, 0x17, - 0x6a, 0xdc, 0x39, 0xe6, 0xa9, 0xb9, 0xe8, 0xce, 0x9f, 0xd7, 0x24, 0x32, 0x5b, 0x85, 0x7a, 0x6c, - 0x9f, 0xf0, 0xa9, 0xd5, 0xab, 0xe6, 0x1d, 0x47, 0x88, 0x21, 0x07, 0xdb, 0x94, 0x74, 0xf6, 0x4d, + 0x84, 0xc7, 0xa1, 0x65, 0x73, 0x29, 0x82, 0x39, 0xc2, 0xb8, 0x01, 0xea, 0x61, 0xc8, 0x1a, 0x50, + 0x19, 0xf6, 0x47, 0xdd, 0x25, 0xd1, 0xd8, 0xe9, 0xef, 0x77, 0x85, 0x45, 0xa9, 0x77, 0x1b, 0xc6, + 0xe7, 0x2a, 0xe8, 0x07, 0xd3, 0xc4, 0x12, 0xba, 0x25, 0x16, 0xa7, 0x2c, 0x4b, 0x68, 0x2e, 0x8a, + 0xdf, 0x00, 0x2d, 0x4e, 0xac, 0x08, 0xfd, 0x0d, 0xb2, 0x4e, 0x0d, 0x84, 0x47, 0x31, 0x7b, 0x17, + 0x6a, 0xdc, 0x39, 0xe1, 0xa9, 0xb9, 0xe8, 0xce, 0x9e, 0xd7, 0x24, 0x32, 0x5b, 0x83, 0x7a, 0x6c, + 0x9f, 0xf2, 0x89, 0xd5, 0xab, 0xe6, 0x1d, 0x87, 0x88, 0x21, 0x07, 0xdb, 0x94, 0x74, 0xf6, 0x4d, 0xa8, 0x89, 0xbb, 0x89, 0x65, 0xc4, 0x88, 0x31, 0xa6, 0xb8, 0x06, 0xd9, 0x8d, 0x88, 0x42, 0xf0, - 0x9c, 0x28, 0x08, 0x27, 0x41, 0x88, 0xbc, 0xef, 0xac, 0x5f, 0x47, 0x1d, 0x97, 0x9e, 0x66, 0x6d, - 0x3b, 0x0a, 0xc2, 0x83, 0xd0, 0xac, 0x3b, 0xf8, 0x2b, 0xe2, 0x17, 0xec, 0x4e, 0x12, 0x41, 0x46, - 0x41, 0x17, 0x18, 0x4a, 0x12, 0xad, 0x82, 0x36, 0xe5, 0x89, 0xe5, 0x58, 0x89, 0x25, 0x6d, 0x43, - 0x8b, 0x54, 0x26, 0xe1, 0xcc, 0x8c, 0x6a, 0x3c, 0x82, 0x3a, 0x4d, 0xcd, 0x34, 0xa8, 0x0e, 0x0f, - 0x86, 0x03, 0x62, 0xeb, 0xc6, 0xde, 0x5e, 0x57, 0x11, 0xa8, 0xed, 0x8d, 0xf1, 0x46, 0x57, 0x15, - 0xad, 0xf1, 0x0f, 0x9f, 0x0f, 0xba, 0x15, 0xe3, 0xef, 0x15, 0xd0, 0xd2, 0x79, 0xd8, 0xc7, 0x00, - 0xe2, 0x09, 0x4f, 0x4e, 0x5c, 0x3f, 0x73, 0xdd, 0x6e, 0x16, 0x57, 0x5a, 0x13, 0xb7, 0xfa, 0x89, - 0xa0, 0x92, 0x79, 0xc5, 0x17, 0x8f, 0x70, 0x7f, 0x04, 0x9d, 0x32, 0x71, 0x81, 0x0f, 0xfb, 0xa0, - 0x68, 0x55, 0x3a, 0xeb, 0x5f, 0x2b, 0x4d, 0x2d, 0x46, 0xa2, 0x68, 0x17, 0x0c, 0xcc, 0x43, 0xd0, - 0x52, 0x34, 0x6b, 0x42, 0x63, 0x7b, 0xb0, 0xb3, 0xf1, 0x62, 0x4f, 0x88, 0x0a, 0x40, 0x7d, 0xb4, - 0x3b, 0x7c, 0xba, 0x37, 0xa0, 0x63, 0xed, 0xed, 0x8e, 0xc6, 0x5d, 0xd5, 0xf8, 0x73, 0x05, 0xb4, - 0xd4, 0x93, 0x61, 0xef, 0x0b, 0xe7, 0x03, 0xdd, 0x2f, 0x69, 0x89, 0x30, 0xd7, 0x53, 0x08, 0x48, - 0xcd, 0x94, 0x2e, 0xde, 0x22, 0x2a, 0xd6, 0xd4, 0xb7, 0x41, 0xa0, 0x18, 0x0f, 0x57, 0x4a, 0xa9, - 0x1a, 0x11, 0xda, 0x07, 0x3e, 0x97, 0xae, 0x30, 0xb6, 0x51, 0x06, 0x5d, 0xdf, 0xe6, 0x79, 0xa0, - 0xd0, 0x40, 0x78, 0x7c, 0x59, 0x13, 0xd7, 0x2f, 0x6b, 0xe2, 0x84, 0x9c, 0xe8, 0x6c, 0xef, 0xd9, - 0x86, 0x94, 0xe2, 0x86, 0x2e, 0x45, 0x24, 0xea, 0xe5, 0x88, 0x24, 0xb7, 0xad, 0xb5, 0xd7, 0xd9, - 0x56, 0xe3, 0x4f, 0xab, 0xd0, 0x31, 0x79, 0x9c, 0x04, 0x11, 0x97, 0x4e, 0xe1, 0xab, 0x5e, 0xd9, - 0xdb, 0x00, 0x11, 0x75, 0xce, 0x97, 0xd6, 0x25, 0x86, 0x42, 0x29, 0x2f, 0xb0, 0x51, 0xbc, 0xa5, - 0x11, 0xcd, 0x60, 0x76, 0x13, 0xf4, 0x43, 0xcb, 0x3e, 0xa5, 0x69, 0xc9, 0x94, 0x6a, 0x84, 0xa0, - 0x79, 0x2d, 0xdb, 0xe6, 0x71, 0x3c, 0x11, 0xd2, 0x42, 0x06, 0x55, 0x27, 0xcc, 0x33, 0x7e, 0x21, - 0xc8, 0x31, 0xb7, 0x23, 0x9e, 0x20, 0xb9, 0x4e, 0x64, 0xc2, 0x08, 0xf2, 0x5d, 0x68, 0xc7, 0x3c, - 0x16, 0xc6, 0x77, 0x92, 0x04, 0xa7, 0xdc, 0x97, 0xaa, 0xae, 0x25, 0x91, 0x63, 0x81, 0x13, 0x5a, - 0xc8, 0xf2, 0x03, 0xff, 0x62, 0x1a, 0xcc, 0x62, 0x69, 0x56, 0x72, 0x04, 0x5b, 0x83, 0x6b, 0xdc, - 0xb7, 0xa3, 0x8b, 0x50, 0xec, 0x55, 0xac, 0x32, 0x39, 0x72, 0x3d, 0x2e, 0xfd, 0xf4, 0x95, 0x9c, - 0xf4, 0x8c, 0x5f, 0xec, 0xb8, 0x1e, 0x17, 0x3b, 0x3a, 0xb3, 0x66, 0x5e, 0x32, 0xc1, 0x34, 0x00, - 0xd0, 0x8e, 0x10, 0xb3, 0xe1, 0x38, 0x11, 0xbb, 0x0f, 0x2b, 0x44, 0x8e, 0x02, 0x8f, 0xbb, 0x0e, - 0x4d, 0xd6, 0xc4, 0x5e, 0xcb, 0x48, 0x30, 0x11, 0x8f, 0x53, 0xad, 0xc1, 0x35, 0xea, 0x4b, 0x07, - 0x4a, 0x7b, 0xb7, 0x68, 0x69, 0x24, 0x8d, 0x24, 0xa5, 0xbc, 0x74, 0x68, 0x25, 0x27, 0xe8, 0xdc, - 0xa7, 0x4b, 0x3f, 0xb7, 0x92, 0x13, 0xe1, 0x14, 0x10, 0xf9, 0xc8, 0xe5, 0x1e, 0x05, 0xe7, 0xba, - 0x49, 0x23, 0x76, 0x04, 0x46, 0x88, 0xa2, 0xec, 0x10, 0x44, 0x53, 0x8b, 0xb2, 0x8a, 0xba, 0x49, - 0x83, 0x76, 0x10, 0x25, 0x96, 0x90, 0x77, 0xe5, 0xcf, 0xa6, 0x98, 0x5f, 0xac, 0x9a, 0xf2, 0xf6, - 0x86, 0xb3, 0xa9, 0xf1, 0x5f, 0x15, 0xd0, 0xb2, 0x58, 0xef, 0x01, 0xe8, 0xd3, 0x54, 0xa5, 0x49, - 0x5f, 0xae, 0x5d, 0xd2, 0x73, 0x66, 0x4e, 0x67, 0x6f, 0x83, 0x7a, 0x7a, 0x26, 0xd5, 0x6b, 0x7b, - 0x8d, 0x12, 0xf2, 0xe1, 0xe1, 0x93, 0xb5, 0x67, 0x2f, 0x4d, 0xf5, 0xf4, 0xec, 0x4b, 0xc8, 0x2d, - 0x7b, 0x0f, 0x96, 0x6d, 0x8f, 0x5b, 0xfe, 0x24, 0x77, 0x40, 0x48, 0x2e, 0x3a, 0x88, 0x7e, 0x9e, - 0x79, 0x21, 0xf7, 0xa0, 0xe6, 0x70, 0x2f, 0xb1, 0x8a, 0xc9, 0xde, 0x83, 0xc8, 0xb2, 0x3d, 0xbe, - 0x2d, 0xd0, 0x26, 0x51, 0x85, 0x7a, 0xcd, 0xe2, 0xab, 0x82, 0x7a, 0x5d, 0x10, 0x5b, 0x65, 0xef, - 0x12, 0x8a, 0xef, 0xf2, 0x01, 0xac, 0xf0, 0xf3, 0x10, 0x6d, 0xca, 0x24, 0x4b, 0x27, 0x90, 0xb1, - 0xeb, 0xa6, 0x84, 0xad, 0x34, 0xad, 0xf0, 0x81, 0xd0, 0x2a, 0xf8, 0x68, 0xf0, 0x9a, 0x9b, 0xeb, - 0x0c, 0xd5, 0x52, 0xe9, 0x19, 0x9a, 0x69, 0x17, 0xf6, 0x3e, 0xe8, 0xb6, 0x63, 0x4f, 0x88, 0x33, - 0xed, 0x7c, 0x6f, 0x5b, 0xdb, 0x5b, 0xc4, 0x12, 0xcd, 0x76, 0x6c, 0x72, 0xbc, 0x4b, 0x71, 0x5f, - 0xe7, 0x0d, 0xe2, 0xbe, 0x54, 0x41, 0x2f, 0xe7, 0x6e, 0x7f, 0xd1, 0x92, 0x76, 0x4b, 0x96, 0xf4, - 0xd3, 0xaa, 0xd6, 0xe8, 0x6a, 0xc6, 0x5d, 0xd0, 0xd2, 0xa5, 0x85, 0x7e, 0x8c, 0xb9, 0x2f, 0xa3, - 0x7c, 0xd4, 0x8f, 0x02, 0x1c, 0xc7, 0x86, 0x0d, 0x95, 0x67, 0x2f, 0x47, 0xa8, 0x26, 0x85, 0xc5, - 0xaa, 0xa1, 0x83, 0x83, 0xed, 0x4c, 0x75, 0xaa, 0x05, 0xd5, 0x79, 0x8b, 0xac, 0x0e, 0x5e, 0x59, - 0x9a, 0x1a, 0x2d, 0x60, 0x04, 0xd3, 0xc9, 0xe2, 0x56, 0x29, 0x6b, 0x8a, 0x80, 0xf1, 0xef, 0x15, - 0x68, 0x48, 0xa7, 0x48, 0x1c, 0x64, 0x96, 0x65, 0xf5, 0x44, 0xb3, 0x1c, 0xad, 0x66, 0xde, 0x55, - 0xb1, 0xb4, 0x52, 0x79, 0x7d, 0x69, 0x85, 0x7d, 0x0c, 0xad, 0x90, 0x68, 0x45, 0x7f, 0xec, 0xeb, - 0xc5, 0x31, 0xf2, 0x17, 0xc7, 0x35, 0xc3, 0x1c, 0x10, 0xac, 0xc4, 0xfc, 0x72, 0x62, 0x1d, 0x4b, - 0x0e, 0x34, 0x04, 0x3c, 0xb6, 0x8e, 0xdf, 0xc8, 0xb9, 0xea, 0xa0, 0x97, 0xd6, 0x42, 0x15, 0x2c, - 0x1c, 0xb2, 0xe2, 0xcd, 0xb4, 0xcb, 0x3e, 0xce, 0x4d, 0xd0, 0xed, 0x60, 0x3a, 0x75, 0x91, 0xd6, - 0x91, 0x59, 0x2c, 0x44, 0x8c, 0x63, 0xe3, 0x17, 0x0a, 0x34, 0xe4, 0xb9, 0x2e, 0x59, 0xd0, 0xcd, - 0xdd, 0xe1, 0x86, 0xf9, 0xc3, 0xae, 0x22, 0x3c, 0x84, 0xdd, 0xe1, 0xb8, 0xab, 0x32, 0x1d, 0x6a, - 0x3b, 0x7b, 0x07, 0x1b, 0xe3, 0x6e, 0x45, 0x58, 0xd5, 0xcd, 0x83, 0x83, 0xbd, 0x6e, 0x95, 0xb5, - 0x40, 0xdb, 0xde, 0x18, 0x0f, 0xc6, 0xbb, 0xfb, 0x83, 0x6e, 0x4d, 0xf4, 0x7d, 0x3a, 0x38, 0xe8, - 0xd6, 0x45, 0xe3, 0xc5, 0xee, 0x76, 0xb7, 0x21, 0xe8, 0xcf, 0x37, 0x46, 0xa3, 0xef, 0x1f, 0x98, - 0xdb, 0x5d, 0x0d, 0x2d, 0xf3, 0xd8, 0xdc, 0x1d, 0x3e, 0xed, 0xea, 0xa2, 0x7d, 0xb0, 0xf9, 0xe9, - 0x60, 0x6b, 0xdc, 0x05, 0xe3, 0x43, 0x68, 0x16, 0x78, 0x25, 0x46, 0x9b, 0x83, 0x9d, 0xee, 0x92, - 0x58, 0xf2, 0xe5, 0xc6, 0xde, 0x0b, 0x61, 0xc8, 0x3b, 0x00, 0xd8, 0x9c, 0xec, 0x6d, 0x0c, 0x9f, - 0x76, 0x55, 0xe9, 0x06, 0xfe, 0x9e, 0x92, 0x8d, 0xc4, 0x22, 0xc5, 0x7b, 0xa0, 0x49, 0x3e, 0xa7, - 0xc9, 0x83, 0x66, 0xe1, 0x42, 0xcc, 0x8c, 0x58, 0xe6, 0x4b, 0xa5, 0xcc, 0x17, 0x8c, 0xf8, 0x42, - 0xcf, 0x4d, 0x48, 0xaa, 0x84, 0xec, 0x22, 0x24, 0xf0, 0x54, 0xae, 0x93, 0x97, 0x26, 0xa1, 0x4f, - 0xab, 0x9a, 0xd2, 0x55, 0x8d, 0x6f, 0x01, 0xe4, 0xc5, 0xa2, 0x05, 0x0e, 0xce, 0x75, 0xa8, 0x59, - 0x9e, 0x6b, 0xa5, 0xf1, 0x25, 0x01, 0xc6, 0x10, 0x9a, 0x85, 0x12, 0x93, 0xb8, 0x4a, 0xcb, 0xf3, - 0x84, 0xa1, 0xa1, 0x87, 0xa3, 0x99, 0x0d, 0xcb, 0xf3, 0x9e, 0xf1, 0x8b, 0x58, 0x38, 0x97, 0x54, - 0x9d, 0x52, 0xe7, 0x0a, 0x18, 0x38, 0xd4, 0x24, 0xa2, 0xf1, 0x01, 0xd4, 0x77, 0x52, 0x17, 0x3c, - 0x95, 0x24, 0xe5, 0x2a, 0x49, 0x32, 0x3e, 0x92, 0x7b, 0xc6, 0x1a, 0x08, 0x7b, 0x20, 0xab, 0x60, - 0x31, 0xd5, 0xdc, 0x94, 0x3c, 0x43, 0x41, 0x9d, 0x64, 0x01, 0x0c, 0x3b, 0x1b, 0xdb, 0xa0, 0xbd, - 0xb2, 0xae, 0x28, 0x19, 0xa0, 0xe6, 0x0c, 0x58, 0x50, 0x69, 0x34, 0x7e, 0x0c, 0x90, 0x57, 0xcb, - 0xa4, 0x60, 0xd3, 0x2c, 0x42, 0xb0, 0xef, 0x83, 0x66, 0x9f, 0xb8, 0x9e, 0x13, 0x71, 0xbf, 0x74, - 0xea, 0xbc, 0xbe, 0x96, 0xd1, 0xd9, 0x1d, 0xa8, 0x62, 0x11, 0xb0, 0x92, 0x2b, 0xc2, 0xac, 0x02, - 0x88, 0x14, 0xe3, 0x1c, 0xda, 0xe4, 0xb5, 0xbf, 0x81, 0x43, 0x53, 0xd6, 0x3b, 0xea, 0x25, 0xbd, - 0x73, 0x03, 0xea, 0x68, 0x47, 0xd3, 0xd3, 0x48, 0xe8, 0x0a, 0x7d, 0xf4, 0xbb, 0x2a, 0x00, 0x2d, - 0x3d, 0x0c, 0x1c, 0x5e, 0x0e, 0x8f, 0x95, 0xf9, 0xf0, 0x98, 0x41, 0x35, 0xab, 0xef, 0xea, 0x26, - 0xb6, 0x73, 0xdb, 0x22, 0x43, 0x66, 0xb2, 0x2d, 0x6f, 0x81, 0x8e, 0x7e, 0x8d, 0xfb, 0x33, 0x2c, - 0x2e, 0x88, 0x05, 0x73, 0x44, 0xb1, 0xda, 0x59, 0x2b, 0x57, 0x3b, 0xb3, 0xd2, 0x4f, 0x9d, 0x66, - 0xa3, 0xd2, 0xcf, 0x82, 0x2a, 0x16, 0xe5, 0x2c, 0x62, 0x1e, 0x25, 0x69, 0xc0, 0x4d, 0x50, 0x16, - 0x3b, 0xea, 0xb2, 0xaf, 0x45, 0x59, 0x07, 0x3f, 0x98, 0xd8, 0x81, 0x7f, 0xe4, 0xb9, 0x76, 0x22, - 0xab, 0x9b, 0xe0, 0x07, 0x5b, 0x12, 0x63, 0x7c, 0x0c, 0xad, 0x94, 0xff, 0x58, 0x2c, 0xba, 0x9f, - 0xc5, 0x55, 0x4a, 0x7e, 0xb7, 0x39, 0x9b, 0x36, 0xd5, 0x9e, 0x92, 0x46, 0x56, 0xc6, 0x7f, 0x56, - 0xd2, 0xc1, 0xb2, 0xa6, 0xf1, 0x6a, 0x1e, 0x96, 0x43, 0x65, 0xf5, 0x8d, 0x42, 0xe5, 0xef, 0x80, - 0xee, 0x60, 0xf4, 0xe7, 0x9e, 0xa5, 0x16, 0xa0, 0x3f, 0x1f, 0xe9, 0xc9, 0xf8, 0xd0, 0x3d, 0xe3, - 0x66, 0xde, 0xf9, 0x35, 0xf7, 0x90, 0x71, 0xbb, 0xb6, 0x88, 0xdb, 0xf5, 0xaf, 0xc8, 0xed, 0x77, - 0xa0, 0xe5, 0x07, 0xfe, 0xc4, 0x9f, 0x79, 0x9e, 0x75, 0xe8, 0x71, 0xc9, 0xee, 0xa6, 0x1f, 0xf8, - 0x43, 0x89, 0x12, 0xce, 0x66, 0xb1, 0x0b, 0x3d, 0xea, 0x26, 0xf6, 0x5b, 0x2e, 0xf4, 0xc3, 0xa7, - 0xbf, 0x0a, 0xdd, 0xe0, 0xf0, 0xc7, 0xdc, 0x4e, 0x90, 0x63, 0x13, 0x7c, 0xcd, 0xe4, 0x69, 0x76, - 0x08, 0x2f, 0x58, 0x34, 0x14, 0xef, 0x7a, 0xee, 0x9a, 0xdb, 0x97, 0xae, 0xf9, 0x23, 0xd0, 0x33, - 0x2e, 0x15, 0x22, 0x4d, 0x1d, 0x6a, 0xbb, 0xc3, 0xed, 0xc1, 0x0f, 0xba, 0x8a, 0xb0, 0x35, 0xe6, - 0xe0, 0xe5, 0xc0, 0x1c, 0x0d, 0xba, 0xaa, 0xb0, 0x03, 0xdb, 0x83, 0xbd, 0xc1, 0x78, 0xd0, 0xad, - 0x90, 0x1f, 0x81, 0xa5, 0x05, 0xcf, 0xb5, 0xdd, 0xc4, 0x18, 0x01, 0xe4, 0xe1, 0xb3, 0xd0, 0xd9, - 0xf9, 0xe6, 0x64, 0xfe, 0x2e, 0x49, 0xb7, 0xb5, 0x9a, 0x3d, 0x48, 0xf5, 0xaa, 0x20, 0x9d, 0xe8, - 0xc6, 0x3a, 0xe8, 0xfb, 0x56, 0xf8, 0x09, 0x15, 0xe1, 0xee, 0x41, 0x27, 0xb4, 0xa2, 0xc4, 0x4d, - 0xdd, 0x7b, 0x52, 0x96, 0x2d, 0xb3, 0x9d, 0x61, 0x85, 0xee, 0x35, 0xfe, 0x41, 0x81, 0xeb, 0xfb, - 0xc1, 0x19, 0xcf, 0xdc, 0xc7, 0xe7, 0xd6, 0x85, 0x17, 0x58, 0xce, 0x6b, 0xc4, 0x50, 0xc4, 0x27, - 0xc1, 0x0c, 0x8b, 0x62, 0x69, 0x09, 0xd1, 0xd4, 0x09, 0xf3, 0x54, 0x7e, 0xfb, 0xc0, 0xe3, 0x04, - 0x89, 0x15, 0xd2, 0x3f, 0x02, 0x16, 0xa4, 0x42, 0x7c, 0x59, 0x2d, 0xc5, 0x97, 0x0b, 0xfd, 0xc9, - 0xda, 0x15, 0xfe, 0x64, 0x31, 0xf0, 0xac, 0x97, 0x02, 0x4f, 0x63, 0x0b, 0xf4, 0xf1, 0x39, 0xa6, - 0x65, 0x67, 0x71, 0xc9, 0x81, 0x50, 0x5e, 0xe1, 0x40, 0xa8, 0x73, 0x0e, 0xc4, 0xbf, 0x29, 0xd0, - 0x2c, 0xf8, 0xcc, 0xec, 0x1d, 0xa8, 0x26, 0xe7, 0x7e, 0xf9, 0xa3, 0x82, 0x74, 0x11, 0x13, 0x49, - 0x97, 0x02, 0x5e, 0xf5, 0x52, 0xc0, 0xcb, 0xf6, 0x60, 0x99, 0xd4, 0x72, 0x7a, 0xbe, 0x34, 0x43, - 0x73, 0x77, 0xce, 0x47, 0xa7, 0xd4, 0x75, 0x7a, 0x5a, 0x99, 0x76, 0xe8, 0x1c, 0x97, 0x90, 0xfd, - 0x0d, 0xb8, 0xb6, 0xa0, 0xdb, 0x97, 0x29, 0x62, 0x18, 0xb7, 0xa1, 0x3d, 0x3e, 0xf7, 0xc7, 0xee, - 0x94, 0xc7, 0x89, 0x35, 0x0d, 0xd1, 0x01, 0x93, 0x66, 0xb5, 0x6a, 0xaa, 0x49, 0x6c, 0xbc, 0x0b, - 0xad, 0xe7, 0x9c, 0x47, 0x26, 0x8f, 0xc3, 0xc0, 0x8f, 0x79, 0x21, 0x65, 0x4c, 0x36, 0x5c, 0x42, - 0xc6, 0xef, 0x80, 0x6e, 0x5a, 0x47, 0xc9, 0xa6, 0x95, 0xd8, 0x27, 0x5f, 0x26, 0x07, 0xf1, 0x2e, - 0x34, 0x42, 0x12, 0x38, 0x19, 0x49, 0xb5, 0xd0, 0x96, 0x4b, 0x21, 0x34, 0x53, 0xa2, 0xf1, 0xdb, - 0x70, 0x6d, 0x34, 0x3b, 0x8c, 0xed, 0xc8, 0xc5, 0xa0, 0x34, 0xb5, 0x73, 0x7d, 0xd0, 0xc2, 0x88, - 0x1f, 0xb9, 0xe7, 0x3c, 0x15, 0xef, 0x0c, 0x66, 0xf7, 0xa1, 0x31, 0x15, 0xdb, 0xe1, 0xf9, 0xc3, - 0xc9, 0xc3, 0xaf, 0x7d, 0x41, 0x31, 0xd3, 0x0e, 0xc6, 0x77, 0xe1, 0x7a, 0x79, 0x7a, 0x79, 0xdc, - 0xbb, 0x50, 0x39, 0x3d, 0x8b, 0xe5, 0x29, 0x56, 0x4a, 0xe1, 0x1b, 0xd6, 0xfd, 0x05, 0xd5, 0xf8, - 0x23, 0x05, 0x2a, 0xc3, 0xd9, 0xb4, 0xf8, 0x51, 0x53, 0x95, 0x3e, 0x6a, 0xba, 0x59, 0xcc, 0xde, - 0x92, 0xf3, 0x9f, 0x67, 0x69, 0xdf, 0x02, 0xfd, 0x28, 0x88, 0x7e, 0x6a, 0x45, 0x0e, 0x77, 0xa4, - 0xf5, 0xcb, 0x11, 0xec, 0x9e, 0xb4, 0x95, 0xe4, 0x7c, 0xaf, 0x08, 0x06, 0x0e, 0x67, 0xd3, 0x35, - 0x8f, 0x5b, 0x31, 0x2a, 0x75, 0x32, 0x9f, 0xc6, 0x03, 0xd0, 0x33, 0x94, 0x50, 0x44, 0xc3, 0xd1, - 0x64, 0x77, 0x9b, 0xb2, 0x5f, 0xc2, 0x4d, 0x55, 0x84, 0x12, 0x1a, 0xff, 0x60, 0x38, 0x19, 0x8f, - 0xba, 0xaa, 0xf1, 0x23, 0x68, 0xa6, 0xa2, 0xb8, 0xeb, 0x60, 0xa9, 0x07, 0xdf, 0xc2, 0xae, 0x53, - 0x7a, 0x1a, 0xbb, 0x18, 0x47, 0x70, 0xdf, 0xd9, 0x4d, 0x65, 0x98, 0x80, 0xf2, 0x69, 0x64, 0xdd, - 0x28, 0x3d, 0x8d, 0x31, 0x80, 0x15, 0x13, 0x53, 0xd6, 0xc2, 0xc0, 0xa5, 0xd7, 0x73, 0x03, 0xea, - 0x7e, 0xe0, 0xf0, 0x6c, 0x01, 0x09, 0x89, 0x95, 0xa5, 0x3b, 0x22, 0x55, 0x47, 0x0a, 0x1a, 0x1c, - 0x56, 0x84, 0x36, 0x92, 0x25, 0x4d, 0x39, 0x4d, 0x29, 0x9d, 0xaa, 0xcc, 0xa5, 0x53, 0xc5, 0x22, - 0xb2, 0x26, 0x4a, 0x7e, 0x45, 0x5a, 0x07, 0xed, 0x83, 0xe6, 0xc4, 0x09, 0xbe, 0x10, 0xa9, 0x83, - 0x32, 0xd8, 0x78, 0x04, 0xd7, 0x36, 0xc2, 0xd0, 0xbb, 0x48, 0xeb, 0x4c, 0x72, 0xa1, 0x5e, 0x5e, - 0x8c, 0x52, 0x64, 0xf0, 0x42, 0xa0, 0xb1, 0x03, 0xad, 0x34, 0x30, 0xde, 0xe7, 0x89, 0x85, 0xca, - 0xc3, 0x73, 0x4b, 0x71, 0xa0, 0x46, 0x88, 0x71, 0x39, 0x69, 0x3b, 0x77, 0xbe, 0x35, 0xa8, 0x4b, - 0xcd, 0xc4, 0xa0, 0x6a, 0x07, 0x0e, 0x2d, 0x54, 0x33, 0xb1, 0x2d, 0x24, 0x68, 0x1a, 0x1f, 0xa7, - 0x9e, 0xe5, 0x34, 0x3e, 0x36, 0xfe, 0x4a, 0x85, 0xf6, 0x26, 0xa6, 0x21, 0xd2, 0x3d, 0x16, 0xf4, - 0xa7, 0x52, 0xd2, 0x9f, 0x45, 0x95, 0xa8, 0x96, 0x73, 0x71, 0xc5, 0x0d, 0x55, 0xca, 0xee, 0xe0, - 0xd7, 0xa1, 0x31, 0xf3, 0xdd, 0xf3, 0x54, 0x1d, 0xeb, 0x66, 0x5d, 0x80, 0xe3, 0x98, 0xdd, 0x81, - 0xa6, 0x50, 0xd9, 0xae, 0x4f, 0xc9, 0x2d, 0xca, 0x50, 0x15, 0x51, 0x73, 0x29, 0xac, 0xfa, 0xab, - 0x53, 0x58, 0x8d, 0xd7, 0xa6, 0xb0, 0xb4, 0xd7, 0xa5, 0xb0, 0xf4, 0xf9, 0x14, 0x56, 0xd9, 0x95, - 0x85, 0x79, 0x57, 0xd6, 0xd8, 0x83, 0x4e, 0xca, 0x3b, 0xf9, 0x9e, 0x3f, 0x86, 0x65, 0x99, 0xa0, - 0xe6, 0x91, 0x4c, 0xe0, 0x90, 0x46, 0xc7, 0x07, 0x46, 0x39, 0x64, 0x49, 0x31, 0x3b, 0x4e, 0x11, - 0x8c, 0x8d, 0x5f, 0x29, 0xd0, 0x2e, 0xf5, 0x60, 0x1f, 0xe6, 0xe9, 0x6e, 0x05, 0x9f, 0x69, 0xef, - 0xd2, 0x2c, 0xaf, 0x4e, 0x79, 0xab, 0x73, 0x29, 0x6f, 0xe3, 0x61, 0x96, 0xc8, 0x96, 0xe9, 0xeb, - 0xa5, 0x2c, 0x7d, 0x8d, 0x19, 0xdf, 0x8d, 0xf1, 0xd8, 0xec, 0xaa, 0xac, 0x0e, 0xea, 0x70, 0xd4, - 0xad, 0x18, 0x7f, 0xa6, 0x42, 0x7b, 0x70, 0x1e, 0xe2, 0x57, 0x4a, 0xaf, 0x75, 0xfc, 0x0b, 0x82, - 0xa3, 0x96, 0x04, 0xa7, 0x20, 0x02, 0x15, 0x59, 0xbf, 0x23, 0x11, 0x10, 0xa1, 0x00, 0x65, 0xcc, - 0xa4, 0x68, 0x10, 0xf4, 0x7f, 0x41, 0x34, 0x4a, 0x2a, 0x03, 0xe6, 0x2b, 0x30, 0x7b, 0xd0, 0x49, - 0xd9, 0x26, 0x05, 0xe3, 0x8d, 0x5e, 0x23, 0x7d, 0x97, 0xe8, 0x65, 0xe9, 0x1a, 0x02, 0x8c, 0x3f, - 0x56, 0x41, 0x27, 0x39, 0x13, 0x9b, 0x7f, 0x5f, 0x2a, 0x6e, 0x25, 0x4f, 0xf6, 0x67, 0xc4, 0xb5, - 0x67, 0xfc, 0x22, 0x57, 0xde, 0x0b, 0x0b, 0x64, 0x32, 0xa9, 0x43, 0x81, 0x3b, 0x26, 0x75, 0x6e, - 0x82, 0x4e, 0x2e, 0xcc, 0x4c, 0xa6, 0x91, 0xab, 0x26, 0xf9, 0x34, 0x2f, 0x5c, 0x2c, 0x75, 0x25, - 0x3c, 0x9a, 0xca, 0x3b, 0xc0, 0x76, 0x39, 0x08, 0x6a, 0xa7, 0x6e, 0x79, 0x89, 0x23, 0x8d, 0x79, - 0x8e, 0x9c, 0x40, 0x43, 0xee, 0x4d, 0xf8, 0xb0, 0x2f, 0x86, 0xcf, 0x86, 0x07, 0xdf, 0x1f, 0x96, - 0xa4, 0x2f, 0xf3, 0x72, 0xd5, 0xa2, 0x97, 0x5b, 0x11, 0xf8, 0xad, 0x83, 0x17, 0xc3, 0x71, 0xb7, - 0xca, 0xda, 0xa0, 0x63, 0x73, 0x62, 0x0e, 0x5e, 0x76, 0x6b, 0x98, 0x13, 0xd9, 0xfa, 0x64, 0xb0, - 0xbf, 0xd1, 0xad, 0x67, 0xa5, 0x97, 0x86, 0xf1, 0x87, 0x0a, 0xac, 0x10, 0x43, 0x8a, 0xe9, 0x8d, - 0xe2, 0xc7, 0xc5, 0x55, 0xf9, 0x71, 0xf1, 0xff, 0x6e, 0xca, 0xe3, 0x26, 0xe8, 0x33, 0x37, 0x2d, - 0x76, 0x52, 0xd6, 0x43, 0x9b, 0xb9, 0xb2, 0xc6, 0xf9, 0xb7, 0x0a, 0xf4, 0xc9, 0xb9, 0x7e, 0x1a, - 0x59, 0xe1, 0xc9, 0xf7, 0xf6, 0x2e, 0x85, 0xd7, 0x57, 0x79, 0x95, 0xf7, 0xa0, 0x83, 0x9f, 0x5f, - 0xff, 0xc4, 0x9b, 0xc8, 0x10, 0x90, 0x6e, 0xb7, 0x2d, 0xb1, 0x34, 0x11, 0x7b, 0x02, 0x2d, 0xfa, - 0x4c, 0x1b, 0xb3, 0xb9, 0xa5, 0x42, 0x5d, 0xc9, 0xb5, 0x6f, 0x52, 0x2f, 0x2a, 0x2b, 0x7e, 0x98, - 0x0d, 0xca, 0x23, 0xf1, 0xcb, 0xb5, 0x38, 0x39, 0x64, 0x8c, 0xf1, 0xf9, 0x23, 0xb8, 0xb9, 0xf0, - 0x1c, 0x52, 0xec, 0x0b, 0x29, 0x44, 0x92, 0x36, 0xe3, 0x9f, 0x14, 0xd0, 0x36, 0x67, 0xde, 0x29, - 0x5a, 0xb9, 0xb7, 0x01, 0xb8, 0x73, 0xcc, 0xe5, 0x47, 0xcc, 0x0a, 0x2a, 0x07, 0x5d, 0x60, 0xe8, - 0x33, 0xe6, 0x8f, 0x01, 0xe8, 0x8c, 0x93, 0xa9, 0x15, 0xca, 0x2b, 0xc2, 0xc2, 0x59, 0x3a, 0x81, - 0x3c, 0xcb, 0xbe, 0x15, 0xca, 0xc2, 0x59, 0x9c, 0xc2, 0x79, 0x41, 0xb1, 0xf2, 0x8a, 0x82, 0x62, - 0x7f, 0x08, 0x9d, 0xf2, 0x14, 0x0b, 0xb2, 0x4f, 0xef, 0x96, 0x3f, 0xda, 0xb8, 0xcc, 0xc3, 0x82, - 0xbf, 0xfb, 0x29, 0x2c, 0xcf, 0x25, 0x86, 0x5f, 0xa5, 0x31, 0x4b, 0x4f, 0x46, 0x9d, 0x7b, 0x32, - 0xeb, 0x7f, 0xa3, 0x40, 0x55, 0xf8, 0xb4, 0xec, 0x21, 0xe8, 0x9f, 0x70, 0x2b, 0x4a, 0x0e, 0xb9, - 0x95, 0xb0, 0x92, 0xff, 0xda, 0xc7, 0x63, 0xe5, 0xdf, 0x69, 0x18, 0x4b, 0x8f, 0x15, 0xb6, 0x46, - 0xdf, 0x87, 0xa6, 0xdf, 0xbd, 0xb6, 0x53, 0xdf, 0x18, 0x7d, 0xe7, 0x7e, 0x69, 0xbc, 0xb1, 0xb4, - 0x8a, 0xfd, 0x3f, 0x0d, 0x5c, 0x7f, 0x8b, 0xbe, 0x4a, 0x64, 0xf3, 0xbe, 0xf4, 0xfc, 0x08, 0xf6, - 0x10, 0xea, 0xbb, 0xb1, 0x70, 0xda, 0x2f, 0x77, 0x45, 0xde, 0x14, 0xfd, 0x79, 0x63, 0x69, 0xfd, - 0xe7, 0x35, 0xa8, 0xfe, 0x88, 0x47, 0x01, 0xfb, 0x00, 0x1a, 0xf2, 0xab, 0x16, 0x56, 0xf8, 0x7a, - 0xa5, 0x8f, 0xc9, 0x85, 0xb9, 0xcf, 0x5d, 0x70, 0x95, 0x2e, 0xb1, 0x37, 0xaf, 0x56, 0xb0, 0xfc, - 0xa3, 0x9b, 0x4b, 0x9b, 0xfa, 0x08, 0xba, 0xa3, 0x24, 0xe2, 0xd6, 0xb4, 0xd0, 0xbd, 0xcc, 0xaa, - 0x45, 0xa5, 0x0f, 0xe4, 0xd7, 0x03, 0xa8, 0x53, 0x64, 0x34, 0x37, 0x60, 0xbe, 0xae, 0x81, 0x9d, - 0xdf, 0x83, 0xe6, 0xe8, 0x24, 0x98, 0x79, 0xce, 0x88, 0x47, 0x67, 0x9c, 0x15, 0xbe, 0x8f, 0xeb, - 0x17, 0xda, 0xc6, 0x12, 0x7b, 0x0f, 0x74, 0xf2, 0x85, 0x85, 0x27, 0xdc, 0x90, 0xee, 0x35, 0xcd, - 0x59, 0xf0, 0x91, 0x8d, 0x25, 0xb6, 0x0a, 0x50, 0x88, 0x8f, 0x5e, 0xd5, 0xf3, 0x09, 0xb4, 0xb7, - 0x50, 0xeb, 0x1c, 0x44, 0x1b, 0x87, 0x41, 0x94, 0xb0, 0xf9, 0x0f, 0xe2, 0xfa, 0xf3, 0x08, 0x63, - 0x89, 0x3d, 0x06, 0x6d, 0x1c, 0x5d, 0x50, 0xff, 0x15, 0x19, 0x56, 0xe6, 0xeb, 0x2d, 0x38, 0x24, - 0xfb, 0x56, 0x26, 0xc3, 0x99, 0x0b, 0xbc, 0xa8, 0xe2, 0x41, 0xe7, 0x25, 0x67, 0xd3, 0x58, 0x62, - 0x1f, 0x02, 0xe4, 0xfe, 0x39, 0xfb, 0x1a, 0x55, 0x5f, 0xe6, 0xfc, 0xf5, 0xcb, 0x43, 0x72, 0x5f, - 0x9c, 0x86, 0x5c, 0xf2, 0xcd, 0xe7, 0x86, 0x7c, 0x1b, 0x5a, 0x45, 0xbf, 0x9a, 0x61, 0xd1, 0x60, - 0x81, 0xa7, 0x5d, 0x1e, 0xb6, 0xfe, 0x27, 0x35, 0xa8, 0x7f, 0x3f, 0x88, 0x4e, 0x79, 0xc4, 0xee, - 0x43, 0x1d, 0xeb, 0x68, 0xf2, 0x61, 0x64, 0x35, 0xb5, 0x45, 0xbc, 0xfb, 0x26, 0xe8, 0x78, 0xcd, - 0x63, 0x2b, 0x3e, 0x25, 0xe1, 0xc3, 0x3f, 0x70, 0xd0, 0xe4, 0x94, 0x8a, 0x43, 0x49, 0xed, 0x90, - 0xe8, 0x65, 0x75, 0xe6, 0x52, 0x9d, 0xab, 0x8f, 0x57, 0xfa, 0xec, 0xe5, 0x48, 0x3c, 0xb6, 0xc7, - 0x8a, 0xb0, 0xdf, 0x23, 0xba, 0x3c, 0xd1, 0x29, 0xff, 0x40, 0x9d, 0xde, 0x72, 0xfe, 0x45, 0xb8, - 0xb1, 0xc4, 0x1e, 0x41, 0x5d, 0xaa, 0xf3, 0x95, 0x5c, 0xe9, 0xa4, 0x27, 0xec, 0x16, 0x51, 0x72, - 0xc0, 0x87, 0x50, 0x27, 0xd3, 0x47, 0x03, 0x4a, 0x8e, 0x7d, 0x9f, 0x15, 0x51, 0xe9, 0xf3, 0x64, - 0x0f, 0xa0, 0x21, 0xab, 0x64, 0x6c, 0x41, 0xc9, 0xec, 0xd2, 0x8d, 0xd5, 0xc9, 0xaf, 0xa1, 0xf9, - 0x4b, 0xae, 0x21, 0xcd, 0x5f, 0x76, 0x7b, 0xe8, 0x1d, 0x9b, 0xdc, 0xe6, 0x6e, 0x21, 0x03, 0xc4, - 0x52, 0x8e, 0x2c, 0x50, 0x46, 0x1f, 0x41, 0xbb, 0x94, 0x2d, 0x62, 0xbd, 0x54, 0x2c, 0xe6, 0x13, - 0x48, 0x97, 0x54, 0xc0, 0x77, 0x41, 0x97, 0x31, 0xf6, 0xa1, 0x14, 0x8c, 0x05, 0x11, 0x7d, 0xff, - 0x72, 0x90, 0x8d, 0xef, 0xfa, 0x07, 0x70, 0x6d, 0x81, 0x1d, 0x63, 0xf8, 0x21, 0xe4, 0xd5, 0x86, - 0xba, 0x7f, 0xfb, 0x4a, 0x7a, 0xc6, 0x80, 0xaf, 0xf4, 0x9c, 0x36, 0x7b, 0x7f, 0xf7, 0xf9, 0x2d, - 0xe5, 0xd7, 0x9f, 0xdf, 0x52, 0xfe, 0xf5, 0xf3, 0x5b, 0xca, 0xaf, 0x7e, 0x73, 0x6b, 0xe9, 0xd7, - 0xbf, 0xb9, 0xb5, 0xf4, 0x8f, 0xbf, 0xb9, 0xb5, 0x74, 0x58, 0xc7, 0x7f, 0x4d, 0x3d, 0xf9, 0xef, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x02, 0xb4, 0xc0, 0xf4, 0xab, 0x35, 0x00, 0x00, + 0x9c, 0x28, 0x08, 0xc7, 0x41, 0x88, 0xbc, 0xef, 0x6c, 0x5c, 0x47, 0x1d, 0x97, 0x9e, 0x66, 0x7d, + 0x27, 0x0a, 0xc2, 0xc3, 0xd0, 0xac, 0x3b, 0xf8, 0x2b, 0xe2, 0x17, 0xec, 0x4e, 0x12, 0x41, 0x46, + 0x41, 0x17, 0x18, 0x4a, 0x12, 0xad, 0x81, 0x36, 0xe1, 0x89, 0xe5, 0x58, 0x89, 0x25, 0x6d, 0x43, + 0x8b, 0x54, 0x26, 0xe1, 0xcc, 0x8c, 0x6a, 0x3c, 0x82, 0x3a, 0x4d, 0xcd, 0x34, 0xa8, 0x0e, 0x0e, + 0x07, 0x7d, 0x62, 0xeb, 0xe6, 0xfe, 0x7e, 0x57, 0x11, 0xa8, 0x9d, 0xcd, 0xd1, 0x66, 0x57, 0x15, + 0xad, 0xd1, 0x0f, 0x9f, 0xf7, 0xbb, 0x15, 0xe3, 0xef, 0x14, 0xd0, 0xd2, 0x79, 0xd8, 0xc7, 0x00, + 0xe2, 0x09, 0x8f, 0x4f, 0x5d, 0x3f, 0x73, 0xdd, 0x6e, 0x16, 0x57, 0x5a, 0x17, 0xb7, 0xfa, 0x89, + 0xa0, 0x92, 0x79, 0xc5, 0x17, 0x8f, 0xf0, 0xea, 0x10, 0x3a, 0x65, 0xe2, 0x02, 0x1f, 0xf6, 0x41, + 0xd1, 0xaa, 0x74, 0x36, 0xbe, 0x56, 0x9a, 0x5a, 0x8c, 0x44, 0xd1, 0x2e, 0x18, 0x98, 0x87, 0xa0, + 0xa5, 0x68, 0xd6, 0x84, 0xc6, 0x4e, 0x7f, 0x77, 0xf3, 0xc5, 0xbe, 0x10, 0x15, 0x80, 0xfa, 0x70, + 0x6f, 0xf0, 0x74, 0xbf, 0x4f, 0xc7, 0xda, 0xdf, 0x1b, 0x8e, 0xba, 0xaa, 0xf1, 0xe7, 0x0a, 0x68, + 0xa9, 0x27, 0xc3, 0xde, 0x17, 0xce, 0x07, 0xba, 0x5f, 0xd2, 0x12, 0x61, 0xae, 0xa7, 0x10, 0x90, + 0x9a, 0x29, 0x5d, 0xbc, 0x45, 0x54, 0xac, 0xa9, 0x6f, 0x83, 0x40, 0x31, 0x1e, 0xae, 0x94, 0x52, + 0x35, 0x22, 0xb4, 0x0f, 0x7c, 0x2e, 0x5d, 0x61, 0x6c, 0xa3, 0x0c, 0xba, 0xbe, 0xcd, 0xf3, 0x40, + 0xa1, 0x81, 0xf0, 0x68, 0x5e, 0x13, 0xd7, 0xe7, 0x35, 0x71, 0x42, 0x4e, 0x74, 0xb6, 0xf7, 0x6c, + 0x43, 0x4a, 0x71, 0x43, 0x73, 0x11, 0x89, 0x3a, 0x1f, 0x91, 0xe4, 0xb6, 0xb5, 0xf6, 0x3a, 0xdb, + 0x6a, 0xfc, 0x69, 0x15, 0x3a, 0x26, 0x8f, 0x93, 0x20, 0xe2, 0xd2, 0x29, 0x7c, 0xd5, 0x2b, 0x7b, + 0x1b, 0x20, 0xa2, 0xce, 0xf9, 0xd2, 0xba, 0xc4, 0x50, 0x28, 0xe5, 0x05, 0x36, 0x8a, 0xb7, 0x34, + 0xa2, 0x19, 0xcc, 0x6e, 0x82, 0x7e, 0x64, 0xd9, 0x67, 0x34, 0x2d, 0x99, 0x52, 0x8d, 0x10, 0x34, + 0xaf, 0x65, 0xdb, 0x3c, 0x8e, 0xc7, 0x42, 0x5a, 0xc8, 0xa0, 0xea, 0x84, 0x79, 0xc6, 0x2f, 0x05, + 0x39, 0xe6, 0x76, 0xc4, 0x13, 0x24, 0xd7, 0x89, 0x4c, 0x18, 0x41, 0xbe, 0x0b, 0xed, 0x98, 0xc7, + 0xc2, 0xf8, 0x8e, 0x93, 0xe0, 0x8c, 0xfb, 0x52, 0xd5, 0xb5, 0x24, 0x72, 0x24, 0x70, 0x42, 0x0b, + 0x59, 0x7e, 0xe0, 0x5f, 0x4e, 0x82, 0x69, 0x2c, 0xcd, 0x4a, 0x8e, 0x60, 0xeb, 0x70, 0x8d, 0xfb, + 0x76, 0x74, 0x19, 0x8a, 0xbd, 0x8a, 0x55, 0xc6, 0xc7, 0xae, 0xc7, 0xa5, 0x9f, 0xbe, 0x92, 0x93, + 0x9e, 0xf1, 0xcb, 0x5d, 0xd7, 0xe3, 0x62, 0x47, 0xe7, 0xd6, 0xd4, 0x4b, 0xc6, 0x98, 0x06, 0x00, + 0xda, 0x11, 0x62, 0x36, 0x1d, 0x27, 0x62, 0xf7, 0x61, 0x85, 0xc8, 0x51, 0xe0, 0x71, 0xd7, 0xa1, + 0xc9, 0x9a, 0xd8, 0x6b, 0x19, 0x09, 0x26, 0xe2, 0x71, 0xaa, 0x75, 0xb8, 0x46, 0x7d, 0xe9, 0x40, + 0x69, 0xef, 0x16, 0x2d, 0x8d, 0xa4, 0xa1, 0xa4, 0x94, 0x97, 0x0e, 0xad, 0xe4, 0x14, 0x9d, 0xfb, + 0x74, 0xe9, 0xe7, 0x56, 0x72, 0x2a, 0x9c, 0x02, 0x22, 0x1f, 0xbb, 0xdc, 0xa3, 0xe0, 0x5c, 0x37, + 0x69, 0xc4, 0xae, 0xc0, 0x08, 0x51, 0x94, 0x1d, 0x82, 0x68, 0x62, 0x51, 0x56, 0x51, 0x37, 0x69, + 0xd0, 0x2e, 0xa2, 0xc4, 0x12, 0xf2, 0xae, 0xfc, 0xe9, 0x04, 0xf3, 0x8b, 0x55, 0x53, 0xde, 0xde, + 0x60, 0x3a, 0x31, 0xfe, 0xab, 0x02, 0x5a, 0x16, 0xeb, 0x3d, 0x00, 0x7d, 0x92, 0xaa, 0x34, 0xe9, + 0xcb, 0xb5, 0x4b, 0x7a, 0xce, 0xcc, 0xe9, 0xec, 0x6d, 0x50, 0xcf, 0xce, 0xa5, 0x7a, 0x6d, 0xaf, + 0x53, 0x42, 0x3e, 0x3c, 0x7a, 0xb2, 0xfe, 0xec, 0xa5, 0xa9, 0x9e, 0x9d, 0x7f, 0x09, 0xb9, 0x65, + 0xef, 0xc1, 0xb2, 0xed, 0x71, 0xcb, 0x1f, 0xe7, 0x0e, 0x08, 0xc9, 0x45, 0x07, 0xd1, 0xcf, 0x33, + 0x2f, 0xe4, 0x1e, 0xd4, 0x1c, 0xee, 0x25, 0x56, 0x31, 0xd9, 0x7b, 0x18, 0x59, 0xb6, 0xc7, 0x77, + 0x04, 0xda, 0x24, 0xaa, 0x50, 0xaf, 0x59, 0x7c, 0x55, 0x50, 0xaf, 0x0b, 0x62, 0xab, 0xec, 0x5d, + 0x42, 0xf1, 0x5d, 0x3e, 0x80, 0x15, 0x7e, 0x11, 0xa2, 0x4d, 0x19, 0x67, 0xe9, 0x04, 0x32, 0x76, + 0xdd, 0x94, 0xb0, 0x9d, 0xa6, 0x15, 0x3e, 0x10, 0x5a, 0x05, 0x1f, 0x0d, 0x5e, 0x73, 0x73, 0x83, + 0xa1, 0x5a, 0x2a, 0x3d, 0x43, 0x33, 0xed, 0xc2, 0xde, 0x07, 0xdd, 0x76, 0xec, 0x31, 0x71, 0xa6, + 0x9d, 0xef, 0x6d, 0x7b, 0x67, 0x9b, 0x58, 0xa2, 0xd9, 0x8e, 0x4d, 0x8e, 0x77, 0x29, 0xee, 0xeb, + 0xbc, 0x41, 0xdc, 0x97, 0x2a, 0xe8, 0xe5, 0xdc, 0xed, 0x2f, 0x5a, 0xd2, 0x6e, 0xc9, 0x92, 0x7e, + 0x5a, 0xd5, 0x1a, 0x5d, 0xcd, 0xb8, 0x0b, 0x5a, 0xba, 0xb4, 0xd0, 0x8f, 0x31, 0xf7, 0x65, 0x94, + 0x8f, 0xfa, 0x51, 0x80, 0xa3, 0xd8, 0xb0, 0xa1, 0xf2, 0xec, 0xe5, 0x10, 0xd5, 0xa4, 0xb0, 0x58, + 0x35, 0x74, 0x70, 0xb0, 0x9d, 0xa9, 0x4e, 0xb5, 0xa0, 0x3a, 0x6f, 0x91, 0xd5, 0xc1, 0x2b, 0x4b, + 0x53, 0xa3, 0x05, 0x8c, 0x60, 0x3a, 0x59, 0xdc, 0x2a, 0x65, 0x4d, 0x11, 0x30, 0xfe, 0xbd, 0x02, + 0x0d, 0xe9, 0x14, 0x89, 0x83, 0x4c, 0xb3, 0xac, 0x9e, 0x68, 0x96, 0xa3, 0xd5, 0xcc, 0xbb, 0x2a, + 0x96, 0x56, 0x2a, 0xaf, 0x2f, 0xad, 0xb0, 0x8f, 0xa1, 0x15, 0x12, 0xad, 0xe8, 0x8f, 0x7d, 0xbd, + 0x38, 0x46, 0xfe, 0xe2, 0xb8, 0x66, 0x98, 0x03, 0x82, 0x95, 0x98, 0x5f, 0x4e, 0xac, 0x13, 0xc9, + 0x81, 0x86, 0x80, 0x47, 0xd6, 0xc9, 0x1b, 0x39, 0x57, 0x1d, 0xf4, 0xd2, 0x5a, 0xa8, 0x82, 0x85, + 0x43, 0x56, 0xbc, 0x99, 0x76, 0xd9, 0xc7, 0xb9, 0x09, 0xba, 0x1d, 0x4c, 0x26, 0x2e, 0xd2, 0x3a, + 0x32, 0x8b, 0x85, 0x88, 0x51, 0x6c, 0xfc, 0x42, 0x81, 0x86, 0x3c, 0xd7, 0x9c, 0x05, 0xdd, 0xda, + 0x1b, 0x6c, 0x9a, 0x3f, 0xec, 0x2a, 0xc2, 0x43, 0xd8, 0x1b, 0x8c, 0xba, 0x2a, 0xd3, 0xa1, 0xb6, + 0xbb, 0x7f, 0xb8, 0x39, 0xea, 0x56, 0x84, 0x55, 0xdd, 0x3a, 0x3c, 0xdc, 0xef, 0x56, 0x59, 0x0b, + 0xb4, 0x9d, 0xcd, 0x51, 0x7f, 0xb4, 0x77, 0xd0, 0xef, 0xd6, 0x44, 0xdf, 0xa7, 0xfd, 0xc3, 0x6e, + 0x5d, 0x34, 0x5e, 0xec, 0xed, 0x74, 0x1b, 0x82, 0xfe, 0x7c, 0x73, 0x38, 0xfc, 0xfe, 0xa1, 0xb9, + 0xd3, 0xd5, 0xd0, 0x32, 0x8f, 0xcc, 0xbd, 0xc1, 0xd3, 0xae, 0x2e, 0xda, 0x87, 0x5b, 0x9f, 0xf6, + 0xb7, 0x47, 0x5d, 0x30, 0x3e, 0x84, 0x66, 0x81, 0x57, 0x62, 0xb4, 0xd9, 0xdf, 0xed, 0x2e, 0x89, + 0x25, 0x5f, 0x6e, 0xee, 0xbf, 0x10, 0x86, 0xbc, 0x03, 0x80, 0xcd, 0xf1, 0xfe, 0xe6, 0xe0, 0x69, + 0x57, 0x95, 0x6e, 0xe0, 0xef, 0x29, 0xd9, 0x48, 0x2c, 0x52, 0xbc, 0x07, 0x9a, 0xe4, 0x73, 0x9a, + 0x3c, 0x68, 0x16, 0x2e, 0xc4, 0xcc, 0x88, 0x65, 0xbe, 0x54, 0xca, 0x7c, 0xc1, 0x88, 0x2f, 0xf4, + 0xdc, 0x84, 0xa4, 0x4a, 0xc8, 0x2e, 0x42, 0x02, 0x4f, 0xe5, 0x3a, 0x79, 0x69, 0x12, 0xfa, 0xb4, + 0xaa, 0x29, 0x5d, 0xd5, 0xf8, 0x16, 0x40, 0x5e, 0x2c, 0x5a, 0xe0, 0xe0, 0x5c, 0x87, 0x9a, 0xe5, + 0xb9, 0x56, 0x1a, 0x5f, 0x12, 0x60, 0x0c, 0xa0, 0x59, 0x28, 0x31, 0x89, 0xab, 0xb4, 0x3c, 0x4f, + 0x18, 0x1a, 0x7a, 0x38, 0x9a, 0xd9, 0xb0, 0x3c, 0xef, 0x19, 0xbf, 0x8c, 0x85, 0x73, 0x49, 0xd5, + 0x29, 0x75, 0xa6, 0x80, 0x81, 0x43, 0x4d, 0x22, 0x1a, 0x1f, 0x40, 0x7d, 0x37, 0x75, 0xc1, 0x53, + 0x49, 0x52, 0xae, 0x92, 0x24, 0xe3, 0x23, 0xb9, 0x67, 0xac, 0x81, 0xb0, 0x07, 0xb2, 0x0a, 0x16, + 0x53, 0xcd, 0x4d, 0xc9, 0x33, 0x14, 0xd4, 0x49, 0x16, 0xc0, 0xb0, 0xb3, 0xb1, 0x03, 0xda, 0x2b, + 0xeb, 0x8a, 0x92, 0x01, 0x6a, 0xce, 0x80, 0x05, 0x95, 0x46, 0xe3, 0xc7, 0x00, 0x79, 0xb5, 0x4c, + 0x0a, 0x36, 0xcd, 0x22, 0x04, 0xfb, 0x3e, 0x68, 0xf6, 0xa9, 0xeb, 0x39, 0x11, 0xf7, 0x4b, 0xa7, + 0xce, 0xeb, 0x6b, 0x19, 0x9d, 0xdd, 0x81, 0x2a, 0x16, 0x01, 0x2b, 0xb9, 0x22, 0xcc, 0x2a, 0x80, + 0x48, 0x31, 0x2e, 0xa0, 0x4d, 0x5e, 0xfb, 0x1b, 0x38, 0x34, 0x65, 0xbd, 0xa3, 0xce, 0xe9, 0x9d, + 0x1b, 0x50, 0x47, 0x3b, 0x9a, 0x9e, 0x46, 0x42, 0x57, 0xe8, 0xa3, 0xdf, 0x55, 0x01, 0x68, 0xe9, + 0x41, 0xe0, 0xf0, 0x72, 0x78, 0xac, 0xcc, 0x86, 0xc7, 0x0c, 0xaa, 0x59, 0x7d, 0x57, 0x37, 0xb1, + 0x9d, 0xdb, 0x16, 0x19, 0x32, 0x93, 0x6d, 0x79, 0x0b, 0x74, 0xf4, 0x6b, 0xdc, 0x9f, 0x61, 0x71, + 0x41, 0x2c, 0x98, 0x23, 0x8a, 0xd5, 0xce, 0x5a, 0xb9, 0xda, 0x99, 0x95, 0x7e, 0xea, 0x34, 0x1b, + 0x95, 0x7e, 0x16, 0x54, 0xb1, 0x28, 0x67, 0x11, 0xf3, 0x28, 0x49, 0x03, 0x6e, 0x82, 0xb2, 0xd8, + 0x51, 0x97, 0x7d, 0x2d, 0xca, 0x3a, 0xf8, 0xc1, 0xd8, 0x0e, 0xfc, 0x63, 0xcf, 0xb5, 0x13, 0x59, + 0xdd, 0x04, 0x3f, 0xd8, 0x96, 0x18, 0xe3, 0x63, 0x68, 0xa5, 0xfc, 0xc7, 0x62, 0xd1, 0xfd, 0x2c, + 0xae, 0x52, 0xf2, 0xbb, 0xcd, 0xd9, 0xb4, 0xa5, 0xf6, 0x94, 0x34, 0xb2, 0x32, 0xfe, 0xb3, 0x92, + 0x0e, 0x96, 0x35, 0x8d, 0x57, 0xf3, 0xb0, 0x1c, 0x2a, 0xab, 0x6f, 0x14, 0x2a, 0x7f, 0x07, 0x74, + 0x07, 0xa3, 0x3f, 0xf7, 0x3c, 0xb5, 0x00, 0xab, 0xb3, 0x91, 0x9e, 0x8c, 0x0f, 0xdd, 0x73, 0x6e, + 0xe6, 0x9d, 0x5f, 0x73, 0x0f, 0x19, 0xb7, 0x6b, 0x8b, 0xb8, 0x5d, 0xff, 0x8a, 0xdc, 0x7e, 0x07, + 0x5a, 0x7e, 0xe0, 0x8f, 0xfd, 0xa9, 0xe7, 0x59, 0x47, 0x1e, 0x97, 0xec, 0x6e, 0xfa, 0x81, 0x3f, + 0x90, 0x28, 0xe1, 0x6c, 0x16, 0xbb, 0xd0, 0xa3, 0x6e, 0x62, 0xbf, 0xe5, 0x42, 0x3f, 0x7c, 0xfa, + 0x6b, 0xd0, 0x0d, 0x8e, 0x7e, 0xcc, 0xed, 0x04, 0x39, 0x36, 0xc6, 0xd7, 0x4c, 0x9e, 0x66, 0x87, + 0xf0, 0x82, 0x45, 0x03, 0xf1, 0xae, 0x67, 0xae, 0xb9, 0x3d, 0x77, 0xcd, 0x1f, 0x81, 0x9e, 0x71, + 0xa9, 0x10, 0x69, 0xea, 0x50, 0xdb, 0x1b, 0xec, 0xf4, 0x7f, 0xd0, 0x55, 0x84, 0xad, 0x31, 0xfb, + 0x2f, 0xfb, 0xe6, 0xb0, 0xdf, 0x55, 0x85, 0x1d, 0xd8, 0xe9, 0xef, 0xf7, 0x47, 0xfd, 0x6e, 0x85, + 0xfc, 0x08, 0x2c, 0x2d, 0x78, 0xae, 0xed, 0x26, 0xc6, 0x10, 0x20, 0x0f, 0x9f, 0x85, 0xce, 0xce, + 0x37, 0x27, 0xf3, 0x77, 0x49, 0xba, 0xad, 0xb5, 0xec, 0x41, 0xaa, 0x57, 0x05, 0xe9, 0x44, 0x37, + 0x36, 0x40, 0x3f, 0xb0, 0xc2, 0x4f, 0xa8, 0x08, 0x77, 0x0f, 0x3a, 0xa1, 0x15, 0x25, 0x6e, 0xea, + 0xde, 0x93, 0xb2, 0x6c, 0x99, 0xed, 0x0c, 0x2b, 0x74, 0xaf, 0xf1, 0xf7, 0x0a, 0x5c, 0x3f, 0x08, + 0xce, 0x79, 0xe6, 0x3e, 0x3e, 0xb7, 0x2e, 0xbd, 0xc0, 0x72, 0x5e, 0x23, 0x86, 0x22, 0x3e, 0x09, + 0xa6, 0x58, 0x14, 0x4b, 0x4b, 0x88, 0xa6, 0x4e, 0x98, 0xa7, 0xf2, 0xdb, 0x07, 0x1e, 0x27, 0x48, + 0xac, 0x90, 0xfe, 0x11, 0xb0, 0x20, 0x15, 0xe2, 0xcb, 0x6a, 0x29, 0xbe, 0x5c, 0xe8, 0x4f, 0xd6, + 0xae, 0xf0, 0x27, 0x8b, 0x81, 0x67, 0xbd, 0x14, 0x78, 0x1a, 0xdb, 0xa0, 0x8f, 0x2e, 0x30, 0x2d, + 0x3b, 0x8d, 0x4b, 0x0e, 0x84, 0xf2, 0x0a, 0x07, 0x42, 0x9d, 0x71, 0x20, 0xfe, 0x4d, 0x81, 0x66, + 0xc1, 0x67, 0x66, 0xef, 0x40, 0x35, 0xb9, 0xf0, 0xcb, 0x1f, 0x15, 0xa4, 0x8b, 0x98, 0x48, 0x9a, + 0x0b, 0x78, 0xd5, 0xb9, 0x80, 0x97, 0xed, 0xc3, 0x32, 0xa9, 0xe5, 0xf4, 0x7c, 0x69, 0x86, 0xe6, + 0xee, 0x8c, 0x8f, 0x4e, 0xa9, 0xeb, 0xf4, 0xb4, 0x32, 0xed, 0xd0, 0x39, 0x29, 0x21, 0x57, 0x37, + 0xe1, 0xda, 0x82, 0x6e, 0x5f, 0xa6, 0x88, 0x61, 0xdc, 0x86, 0xf6, 0xe8, 0xc2, 0x1f, 0xb9, 0x13, + 0x1e, 0x27, 0xd6, 0x24, 0x44, 0x07, 0x4c, 0x9a, 0xd5, 0xaa, 0xa9, 0x26, 0xb1, 0xf1, 0x2e, 0xb4, + 0x9e, 0x73, 0x1e, 0x99, 0x3c, 0x0e, 0x03, 0x3f, 0xe6, 0x85, 0x94, 0x31, 0xd9, 0x70, 0x09, 0x19, + 0xbf, 0x03, 0xba, 0x69, 0x1d, 0x27, 0x5b, 0x56, 0x62, 0x9f, 0x7e, 0x99, 0x1c, 0xc4, 0xbb, 0xd0, + 0x08, 0x49, 0xe0, 0x64, 0x24, 0xd5, 0x42, 0x5b, 0x2e, 0x85, 0xd0, 0x4c, 0x89, 0xc6, 0x6f, 0xc3, + 0xb5, 0xe1, 0xf4, 0x28, 0xb6, 0x23, 0x17, 0x83, 0xd2, 0xd4, 0xce, 0xad, 0x82, 0x16, 0x46, 0xfc, + 0xd8, 0xbd, 0xe0, 0xa9, 0x78, 0x67, 0x30, 0xbb, 0x0f, 0x8d, 0x89, 0xd8, 0x0e, 0xcf, 0x1f, 0x4e, + 0x1e, 0x7e, 0x1d, 0x08, 0x8a, 0x99, 0x76, 0x30, 0xbe, 0x0b, 0xd7, 0xcb, 0xd3, 0xcb, 0xe3, 0xde, + 0x85, 0xca, 0xd9, 0x79, 0x2c, 0x4f, 0xb1, 0x52, 0x0a, 0xdf, 0xb0, 0xee, 0x2f, 0xa8, 0xc6, 0x1f, + 0x29, 0x50, 0x19, 0x4c, 0x27, 0xc5, 0x8f, 0x9a, 0xaa, 0xf4, 0x51, 0xd3, 0xcd, 0x62, 0xf6, 0x96, + 0x9c, 0xff, 0x3c, 0x4b, 0xfb, 0x16, 0xe8, 0xc7, 0x41, 0xf4, 0x53, 0x2b, 0x72, 0xb8, 0x23, 0xad, + 0x5f, 0x8e, 0x60, 0xf7, 0xa4, 0xad, 0x24, 0xe7, 0x7b, 0x45, 0x30, 0x70, 0x30, 0x9d, 0xac, 0x7b, + 0xdc, 0x8a, 0x51, 0xa9, 0x93, 0xf9, 0x34, 0x1e, 0x80, 0x9e, 0xa1, 0x84, 0x22, 0x1a, 0x0c, 0xc7, + 0x7b, 0x3b, 0x94, 0xfd, 0x12, 0x6e, 0xaa, 0x22, 0x94, 0xd0, 0xe8, 0x07, 0x83, 0xf1, 0x68, 0xd8, + 0x55, 0x8d, 0x1f, 0x41, 0x33, 0x15, 0xc5, 0x3d, 0x07, 0x4b, 0x3d, 0xf8, 0x16, 0xf6, 0x9c, 0xd2, + 0xd3, 0xd8, 0xc3, 0x38, 0x82, 0xfb, 0xce, 0x5e, 0x2a, 0xc3, 0x04, 0x94, 0x4f, 0x23, 0xeb, 0x46, + 0xe9, 0x69, 0x8c, 0x3e, 0xac, 0x98, 0x98, 0xb2, 0x16, 0x06, 0x2e, 0xbd, 0x9e, 0x1b, 0x50, 0xf7, + 0x03, 0x87, 0x67, 0x0b, 0x48, 0x48, 0xac, 0x2c, 0xdd, 0x11, 0xa9, 0x3a, 0x52, 0xd0, 0xe0, 0xb0, + 0x22, 0xb4, 0x91, 0x2c, 0x69, 0xca, 0x69, 0x4a, 0xe9, 0x54, 0x65, 0x26, 0x9d, 0x2a, 0x16, 0x91, + 0x35, 0x51, 0xf2, 0x2b, 0xd2, 0x3a, 0xe8, 0x2a, 0x68, 0x4e, 0x9c, 0xe0, 0x0b, 0x91, 0x3a, 0x28, + 0x83, 0x8d, 0x47, 0x70, 0x6d, 0x33, 0x0c, 0xbd, 0xcb, 0xb4, 0xce, 0x24, 0x17, 0xea, 0xe5, 0xc5, + 0x28, 0x45, 0x06, 0x2f, 0x04, 0x1a, 0xbb, 0xd0, 0x4a, 0x03, 0xe3, 0x03, 0x9e, 0x58, 0xa8, 0x3c, + 0x3c, 0xb7, 0x14, 0x07, 0x6a, 0x84, 0x18, 0x95, 0x93, 0xb6, 0x33, 0xe7, 0x5b, 0x87, 0xba, 0xd4, + 0x4c, 0x0c, 0xaa, 0x76, 0xe0, 0xd0, 0x42, 0x35, 0x13, 0xdb, 0x42, 0x82, 0x26, 0xf1, 0x49, 0xea, + 0x59, 0x4e, 0xe2, 0x13, 0xe3, 0x1f, 0x55, 0x68, 0x6f, 0x61, 0x1a, 0x22, 0xdd, 0x63, 0x41, 0x7f, + 0x2a, 0x25, 0xfd, 0x59, 0x54, 0x89, 0x6a, 0x39, 0x17, 0x57, 0xdc, 0x50, 0xa5, 0xec, 0x0e, 0x7e, + 0x1d, 0x1a, 0x53, 0xdf, 0xbd, 0x48, 0xd5, 0xb1, 0x6e, 0xd6, 0x05, 0x38, 0x8a, 0xd9, 0x1d, 0x68, + 0x0a, 0x95, 0xed, 0xfa, 0x94, 0xdc, 0xa2, 0x0c, 0x55, 0x11, 0x35, 0x93, 0xc2, 0xaa, 0xbf, 0x3a, + 0x85, 0xd5, 0x78, 0x6d, 0x0a, 0x4b, 0x7b, 0x5d, 0x0a, 0x4b, 0x9f, 0x4d, 0x61, 0x95, 0x5d, 0x59, + 0x98, 0x73, 0x65, 0xdf, 0x06, 0xa0, 0x0f, 0x37, 0x8e, 0xa7, 0x9e, 0x27, 0xfd, 0x03, 0x1d, 0x31, + 0xbb, 0x53, 0xcf, 0x33, 0xf6, 0xa1, 0x93, 0xb2, 0x56, 0x3e, 0xf7, 0x8f, 0x61, 0x59, 0xe6, 0xaf, + 0x79, 0x24, 0xf3, 0x3b, 0xa4, 0xf0, 0xf1, 0xfd, 0x51, 0x8a, 0x59, 0x52, 0xcc, 0x8e, 0x53, 0x04, + 0x63, 0xe3, 0x57, 0x0a, 0xb4, 0x4b, 0x3d, 0xd8, 0x87, 0x79, 0x36, 0x5c, 0xc1, 0x57, 0xdc, 0x9b, + 0x9b, 0xe5, 0xd5, 0x19, 0x71, 0x75, 0x26, 0x23, 0x6e, 0x3c, 0xcc, 0xf2, 0xdc, 0x32, 0xbb, 0xbd, + 0x94, 0x65, 0xb7, 0x31, 0x21, 0xbc, 0x39, 0x1a, 0x99, 0x5d, 0x95, 0xd5, 0x41, 0x1d, 0x0c, 0xbb, + 0x15, 0xe3, 0xcf, 0x54, 0x68, 0xf7, 0x2f, 0x42, 0xfc, 0x88, 0xe9, 0xb5, 0x71, 0x41, 0x41, 0xae, + 0xd4, 0x92, 0x5c, 0x15, 0x24, 0xa4, 0x22, 0xcb, 0x7b, 0x24, 0x21, 0x22, 0x52, 0xa0, 0x84, 0x9a, + 0x94, 0x1c, 0x82, 0xfe, 0x2f, 0x48, 0x4e, 0x49, 0xa3, 0xc0, 0x6c, 0x81, 0x66, 0x1f, 0x3a, 0x29, + 0xdb, 0xa4, 0x60, 0xbc, 0xd1, 0x63, 0xa5, 0xcf, 0x16, 0xbd, 0x2c, 0x9b, 0x43, 0x80, 0xf1, 0xc7, + 0x2a, 0xe8, 0x24, 0x67, 0x62, 0xf3, 0xef, 0x4b, 0xbd, 0xae, 0xe4, 0xb5, 0x80, 0x8c, 0xb8, 0xfe, + 0x8c, 0x5f, 0xe6, 0xba, 0x7d, 0x61, 0xfd, 0x4c, 0xe6, 0x7c, 0x28, 0xae, 0xc7, 0x9c, 0xcf, 0x4d, + 0xd0, 0xc9, 0xc3, 0x99, 0xca, 0x2c, 0x73, 0xd5, 0x24, 0x97, 0xe7, 0x85, 0x8b, 0x95, 0xb0, 0x84, + 0x47, 0x13, 0x79, 0x07, 0xd8, 0x2e, 0xc7, 0x48, 0xed, 0xd4, 0x6b, 0x2f, 0x71, 0xa4, 0x31, 0xcb, + 0x91, 0x53, 0x68, 0xc8, 0xbd, 0x09, 0x17, 0xf7, 0xc5, 0xe0, 0xd9, 0xe0, 0xf0, 0xfb, 0x83, 0x92, + 0xf4, 0x65, 0x4e, 0xb0, 0x5a, 0x74, 0x82, 0x2b, 0x02, 0xbf, 0x7d, 0xf8, 0x62, 0x30, 0xea, 0x56, + 0x59, 0x1b, 0x74, 0x6c, 0x8e, 0xcd, 0xfe, 0xcb, 0x6e, 0x0d, 0x53, 0x26, 0xdb, 0x9f, 0xf4, 0x0f, + 0x36, 0xbb, 0xf5, 0xac, 0x32, 0xd3, 0x30, 0xfe, 0x50, 0x81, 0x15, 0x62, 0x48, 0x31, 0xfb, 0x51, + 0xfc, 0xf6, 0xb8, 0x2a, 0xbf, 0x3d, 0xfe, 0xdf, 0xcd, 0x88, 0xdc, 0x04, 0x7d, 0xea, 0xa6, 0xb5, + 0x50, 0x4a, 0x8a, 0x68, 0x53, 0x57, 0x96, 0x40, 0xff, 0x46, 0x81, 0x55, 0xf2, 0xbd, 0x9f, 0x46, + 0x56, 0x78, 0xfa, 0xbd, 0xfd, 0xb9, 0xe8, 0xfb, 0x2a, 0xa7, 0xf3, 0x1e, 0x74, 0xf0, 0xeb, 0xec, + 0x9f, 0x78, 0x63, 0x19, 0x21, 0xd2, 0xed, 0xb6, 0x25, 0x96, 0x26, 0x62, 0x4f, 0xa0, 0x45, 0x5f, + 0x71, 0x63, 0xb2, 0xb7, 0x54, 0xc7, 0x2b, 0x79, 0xfe, 0x4d, 0xea, 0x45, 0x55, 0xc7, 0x0f, 0xb3, + 0x41, 0x79, 0xa0, 0x3e, 0x5f, 0xaa, 0x93, 0x43, 0x46, 0x18, 0xbe, 0x3f, 0x82, 0x9b, 0x0b, 0xcf, + 0x21, 0xc5, 0xbe, 0x90, 0x61, 0x24, 0x69, 0x33, 0xfe, 0x49, 0x01, 0x6d, 0x6b, 0xea, 0x9d, 0xa1, + 0x11, 0x7c, 0x1b, 0x80, 0x3b, 0x27, 0x5c, 0x7e, 0xe3, 0xac, 0xa0, 0x72, 0xd0, 0x05, 0x86, 0xbe, + 0x72, 0xfe, 0x18, 0x80, 0xce, 0x38, 0x9e, 0x58, 0xa1, 0xbc, 0x22, 0xac, 0xab, 0xa5, 0x13, 0xc8, + 0xb3, 0x1c, 0x58, 0xa1, 0xac, 0xab, 0xc5, 0x29, 0x9c, 0xd7, 0x1b, 0x2b, 0xaf, 0xa8, 0x37, 0xae, + 0x0e, 0xa0, 0x53, 0x9e, 0x62, 0x41, 0x72, 0xea, 0xdd, 0xf2, 0x37, 0x1d, 0xf3, 0x3c, 0x2c, 0xb8, + 0xc3, 0x9f, 0xc2, 0xf2, 0x4c, 0xde, 0xf8, 0x55, 0x1a, 0xb3, 0xf4, 0x64, 0xd4, 0x99, 0x27, 0xb3, + 0xf1, 0xd7, 0x0a, 0x54, 0x85, 0xcb, 0xcb, 0x1e, 0x82, 0xfe, 0x09, 0xb7, 0xa2, 0xe4, 0x88, 0x5b, + 0x09, 0x2b, 0xb9, 0xb7, 0xab, 0x78, 0xac, 0xfc, 0x33, 0x0e, 0x63, 0xe9, 0xb1, 0xc2, 0xd6, 0xe9, + 0xf3, 0xd1, 0xf4, 0xb3, 0xd8, 0x76, 0xea, 0x3a, 0xa3, 0x6b, 0xbd, 0x5a, 0x1a, 0x6f, 0x2c, 0xad, + 0x61, 0xff, 0x4f, 0x03, 0xd7, 0xdf, 0xa6, 0x8f, 0x16, 0xd9, 0xac, 0xab, 0x3d, 0x3b, 0x82, 0x3d, + 0x84, 0xfa, 0x5e, 0x2c, 0x7c, 0xfa, 0xf9, 0xae, 0xc8, 0x9b, 0xa2, 0xbb, 0x6f, 0x2c, 0x6d, 0xfc, + 0xbc, 0x06, 0xd5, 0x1f, 0xf1, 0x28, 0x60, 0x1f, 0x40, 0x43, 0x7e, 0xf4, 0xc2, 0x0a, 0x1f, 0xb7, + 0xac, 0x62, 0xee, 0x61, 0xe6, 0x6b, 0x18, 0x5c, 0xa5, 0x4b, 0xec, 0xcd, 0x8b, 0x19, 0x2c, 0xff, + 0x26, 0x67, 0x6e, 0x53, 0x1f, 0x41, 0x77, 0x98, 0x44, 0xdc, 0x9a, 0x14, 0xba, 0x97, 0x59, 0xb5, + 0xa8, 0x32, 0x82, 0xfc, 0x7a, 0x00, 0x75, 0x0a, 0x9c, 0x66, 0x06, 0xcc, 0x96, 0x3d, 0xb0, 0xf3, + 0x7b, 0xd0, 0x1c, 0x9e, 0x06, 0x53, 0xcf, 0x19, 0xf2, 0xe8, 0x9c, 0xb3, 0xc2, 0xe7, 0x73, 0xab, + 0x85, 0xb6, 0xb1, 0xc4, 0xde, 0x03, 0x9d, 0x5c, 0x65, 0xe1, 0x28, 0x37, 0xa4, 0xf7, 0x4d, 0x73, + 0x16, 0x5c, 0x68, 0x63, 0x89, 0xad, 0x01, 0x14, 0xc2, 0xa7, 0x57, 0xf5, 0x7c, 0x02, 0xed, 0x6d, + 0xd4, 0x3a, 0x87, 0xd1, 0xe6, 0x51, 0x10, 0x25, 0x6c, 0xf6, 0x7b, 0xb9, 0xd5, 0x59, 0x84, 0xb1, + 0xc4, 0x1e, 0x83, 0x36, 0x8a, 0x2e, 0xa9, 0xff, 0x8a, 0x8c, 0x3a, 0xf3, 0xf5, 0x16, 0x1c, 0x92, + 0x7d, 0x2b, 0x93, 0xe1, 0xcc, 0x43, 0x5e, 0x54, 0x10, 0xa1, 0xf3, 0x92, 0x2f, 0x6a, 0x2c, 0xb1, + 0x0f, 0x01, 0x72, 0xf7, 0x9d, 0x7d, 0x8d, 0x8a, 0x33, 0x33, 0xee, 0xfc, 0xfc, 0x90, 0xdc, 0x55, + 0xa7, 0x21, 0x73, 0xae, 0xfb, 0xcc, 0x90, 0x6f, 0x43, 0xab, 0xe8, 0x76, 0x33, 0xac, 0x29, 0x2c, + 0x70, 0xc4, 0xcb, 0xc3, 0x36, 0xfe, 0xa4, 0x06, 0xf5, 0xef, 0x07, 0xd1, 0x19, 0x8f, 0xd8, 0x7d, + 0xa8, 0x63, 0x99, 0x4d, 0x3e, 0x8c, 0xac, 0xe4, 0xb6, 0x88, 0x77, 0xdf, 0x04, 0x1d, 0xaf, 0x79, + 0x64, 0xc5, 0x67, 0x24, 0x7c, 0xf8, 0xff, 0x0e, 0x9a, 0x9c, 0x32, 0x75, 0x28, 0xa9, 0x1d, 0x12, + 0xbd, 0xac, 0x0c, 0x5d, 0x2a, 0x83, 0xad, 0xe2, 0x95, 0x3e, 0x7b, 0x39, 0x14, 0x8f, 0xed, 0xb1, + 0x22, 0xec, 0xf7, 0x90, 0x2e, 0x4f, 0x74, 0xca, 0xbf, 0x5f, 0xa7, 0xb7, 0x9c, 0x7f, 0x30, 0x6e, + 0x2c, 0xb1, 0x47, 0x50, 0x97, 0xea, 0x7c, 0x25, 0x57, 0x3a, 0xe9, 0x09, 0xbb, 0x45, 0x94, 0x1c, + 0xf0, 0x21, 0xd4, 0xc9, 0xf4, 0xd1, 0x80, 0x92, 0xdf, 0xbf, 0xca, 0x8a, 0xa8, 0xf4, 0x79, 0xb2, + 0x07, 0xd0, 0x90, 0x45, 0x34, 0xb6, 0xa0, 0xa2, 0x36, 0x77, 0x63, 0x75, 0xf2, 0x6b, 0x68, 0xfe, + 0x92, 0x6b, 0x48, 0xf3, 0x97, 0xdd, 0x1e, 0x7a, 0xc7, 0x26, 0xb7, 0xb9, 0x5b, 0x48, 0x10, 0xb1, + 0x94, 0x23, 0x0b, 0x94, 0xd1, 0x47, 0xd0, 0x2e, 0x25, 0x93, 0x58, 0x2f, 0x15, 0x8b, 0xd9, 0xfc, + 0xd2, 0x9c, 0x0a, 0xf8, 0x2e, 0xe8, 0x32, 0x04, 0x3f, 0x92, 0x82, 0xb1, 0x20, 0xe0, 0x5f, 0x9d, + 0x8f, 0xc1, 0xf1, 0x5d, 0xff, 0x00, 0xae, 0x2d, 0xb0, 0x63, 0x0c, 0xbf, 0x93, 0xbc, 0xda, 0x50, + 0xaf, 0xde, 0xbe, 0x92, 0x9e, 0x31, 0xe0, 0x2b, 0x3d, 0xa7, 0xad, 0xde, 0xdf, 0x7e, 0x7e, 0x4b, + 0xf9, 0xf5, 0xe7, 0xb7, 0x94, 0x7f, 0xfd, 0xfc, 0x96, 0xf2, 0xab, 0xdf, 0xdc, 0x5a, 0xfa, 0xf5, + 0x6f, 0x6e, 0x2d, 0xfd, 0xc3, 0x6f, 0x6e, 0x2d, 0x1d, 0xd5, 0xf1, 0x4f, 0x55, 0x4f, 0xfe, 0x3b, + 0x00, 0x00, 0xff, 0xff, 0xba, 0xab, 0xf7, 0xd2, 0xca, 0x35, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -10657,6 +10670,16 @@ func (m *BackupRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ForceFull { + i-- + if m.ForceFull { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } if len(m.Predicates) > 0 { for iNdEx := len(m.Predicates) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Predicates[iNdEx]) @@ -12885,6 +12908,9 @@ func (m *BackupRequest) Size() (n int) { n += 1 + l + sovPb(uint64(l)) } } + if m.ForceFull { + n += 2 + } return n } @@ -23767,6 +23793,26 @@ func (m *BackupRequest) Unmarshal(dAtA []byte) error { } m.Predicates = append(m.Predicates, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ForceFull", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPb + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ForceFull = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPb(dAtA[iNdEx:]) diff --git a/systest/backup/encryption/backup_test.go b/systest/backup/encryption/backup_test.go index 9117d8f2205..19c9653d781 100644 --- a/systest/backup/encryption/backup_test.go +++ b/systest/backup/encryption/backup_test.go @@ -264,8 +264,8 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles, backup(input: {destination: $dst, forceFull: $ff}) { response { code - message } + taskId } }` @@ -282,9 +282,13 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles, client := testutil.GetHttpsClient(t) resp, err := client.Post(adminUrl, "application/json", bytes.NewBuffer(b)) require.NoError(t, err) - buf, err := ioutil.ReadAll(resp.Body) - require.NoError(t, err) - require.Contains(t, string(buf), "Backup completed.") + defer resp.Body.Close() + + var data interface{} + require.NoError(t, json.NewDecoder(resp.Body).Decode(&data)) + require.Equal(t, "Success", testutil.JsonGet(data, "data", "backup", "response", "code").(string)) + taskId := testutil.JsonGet(data, "data", "backup", "taskId").(string) + testutil.WaitForTask(t, taskId, true) // Verify that the right amount of files and directories were created. copyToLocalFs(t) diff --git a/systest/backup/filesystem/backup_test.go b/systest/backup/filesystem/backup_test.go index b673f9ea71a..57db08c7d67 100644 --- a/systest/backup/filesystem/backup_test.go +++ b/systest/backup/filesystem/backup_test.go @@ -372,8 +372,8 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles, backup(input: {destination: $dst, forceFull: $ff}) { response { code - message } + taskId } }` @@ -392,9 +392,12 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles, resp, err := client.Post(adminUrl, "application/json", bytes.NewBuffer(b)) require.NoError(t, err) defer resp.Body.Close() - buf, err := ioutil.ReadAll(resp.Body) - require.NoError(t, err) - require.Contains(t, string(buf), "Backup completed.") + + var data interface{} + require.NoError(t, json.NewDecoder(resp.Body).Decode(&data)) + require.Equal(t, "Success", testutil.JsonGet(data, "data", "backup", "response", "code").(string)) + taskId := testutil.JsonGet(data, "data", "backup", "taskId").(string) + testutil.WaitForTask(t, taskId, true) // Verify that the right amount of files and directories were created. common.CopyToLocalFs(t) diff --git a/systest/backup/minio-large/backup_test.go b/systest/backup/minio-large/backup_test.go index 02d13f3d1b6..137daf91c79 100644 --- a/systest/backup/minio-large/backup_test.go +++ b/systest/backup/minio-large/backup_test.go @@ -16,11 +16,11 @@ package main import ( + "bytes" "context" + "encoding/json" "fmt" - "io/ioutil" "math" - "net/url" "os" "strings" "testing" @@ -144,17 +144,36 @@ func addTriples(t *testing.T, dg *dgo.Dgraph, numTriples int) { } func runBackup(t *testing.T) { - // Using the old /admin/backup endpoint to ensure it works. Change back to using - // the GraphQL endpoint at /admin once this endpoint is deprecated. + backupRequest := `mutation backup($dst: String!, $ff: Boolean!) { + backup(input: {destination: $dst, forceFull: $ff}) { + response { + code + } + taskId + } + }` + + adminUrl := "https://" + testutil.SockAddrHttp + "/admin" + params := testutil.GraphQLParams{ + Query: backupRequest, + Variables: map[string]interface{}{ + "dst": backupDestination, + "ff": false, + }, + } + b, err := json.Marshal(params) + require.NoError(t, err) + client := testutil.GetHttpsClient(t) - resp, err := client.PostForm("https://"+testutil.SockAddrHttp+"/admin/backup", url.Values{ - "destination": []string{backupDestination}, - }) + resp, err := client.Post(adminUrl, "application/json", bytes.NewBuffer(b)) require.NoError(t, err) defer resp.Body.Close() - buf, err := ioutil.ReadAll(resp.Body) - require.NoError(t, err) - require.Contains(t, string(buf), "Backup completed.") + + var data interface{} + require.NoError(t, json.NewDecoder(resp.Body).Decode(&data)) + require.Equal(t, "Success", testutil.JsonGet(data, "data", "backup", "response", "code").(string)) + taskId := testutil.JsonGet(data, "data", "backup", "taskId").(string) + testutil.WaitForTask(t, taskId, true) // Verify that the right amount of files and directories were created. copyToLocalFs(t) diff --git a/systest/backup/minio/backup_test.go b/systest/backup/minio/backup_test.go index cb7ff3da223..b759dae2ce0 100644 --- a/systest/backup/minio/backup_test.go +++ b/systest/backup/minio/backup_test.go @@ -284,8 +284,8 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles, backup(input: {destination: $dst, forceFull: $ff}) { response { code - message } + taskId } }` @@ -303,9 +303,13 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles, client := testutil.GetHttpsClient(t) resp, err := client.Post(adminUrl, "application/json", bytes.NewBuffer(b)) require.NoError(t, err) - buf, err := ioutil.ReadAll(resp.Body) - require.NoError(t, err) - require.Contains(t, string(buf), "Backup completed.") + defer resp.Body.Close() + + var data interface{} + require.NoError(t, json.NewDecoder(resp.Body).Decode(&data)) + require.Equal(t, "Success", testutil.JsonGet(data, "data", "backup", "response", "code").(string)) + taskId := testutil.JsonGet(data, "data", "backup", "taskId").(string) + testutil.WaitForTask(t, taskId, true) // Verify that the right amount of files and directories were created. copyToLocalFs(t) diff --git a/systest/backup/multi-tenancy/backup_test.go b/systest/backup/multi-tenancy/backup_test.go index 712336a1f34..5ba453ba572 100644 --- a/systest/backup/multi-tenancy/backup_test.go +++ b/systest/backup/multi-tenancy/backup_test.go @@ -138,8 +138,8 @@ func runBackupInternal(t *testing.T, token *testutil.HttpToken, forceFull bool, backup(input: {destination: $dst, forceFull: $ff}) { response { code - message } + taskId } }` @@ -150,16 +150,13 @@ func runBackupInternal(t *testing.T, token *testutil.HttpToken, forceFull bool, "ff": forceFull, }, } + resp := testutil.MakeRequest(t, token, params) - var result struct { - Backup struct { - Response struct { - Message, Code string - } - } - } - require.NoError(t, json.Unmarshal(resp.Data, &result)) - require.Contains(t, result.Backup.Response.Message, "Backup completed.") + var data interface{} + require.NoError(t, json.Unmarshal(resp.Data, &data)) + require.Equal(t, "Success", testutil.JsonGet(data, "backup", "response", "code").(string)) + taskId := testutil.JsonGet(data, "backup", "taskId").(string) + testutil.WaitForTask(t, taskId, false) // Verify that the right amount of files and directories were created. common.CopyToLocalFs(t) diff --git a/systest/export/export_test.go b/systest/export/export_test.go index 15f9d7bc6fd..306fdd0d57f 100644 --- a/systest/export/export_test.go +++ b/systest/export/export_test.go @@ -24,6 +24,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "testing" "github.com/dgraph-io/dgo/v210" @@ -52,20 +53,17 @@ func TestExportSchemaToMinio(t *testing.T) { mc.MakeBucket(bucketName, "") setupDgraph(t, moviesData, movieSchema) - result := requestExport(t, minioDest, "rdf") - - require.Equal(t, "Success", getFromJSON(result, "data", "export", "response", "code").(string)) - require.Equal(t, "Export completed.", - getFromJSON(result, "data", "export", "response", "message").(string)) - - var files []string - for _, f := range getFromJSON(result, "data", "export", "exportedFiles").([]interface{}) { - files = append(files, f.(string)) + requestExport(t, minioDest, "rdf") + + schemaFile := "" + doneCh := make(chan struct{}) + defer close(doneCh) + for obj := range mc.ListObjectsV2(bucketName, "dgraph.", true, doneCh) { + if strings.Contains(obj.Key, ".schema.gz") { + schemaFile = obj.Key + } } - require.Equal(t, 3, len(files)) - - schemaFile := files[1] - require.Contains(t, schemaFile, ".schema.gz") + require.NotEmpty(t, schemaFile) object, err := mc.GetObject(bucketName, schemaFile, minio.GetObjectOptions{}) require.NoError(t, err) @@ -113,16 +111,7 @@ func TestExportAndLoadJson(t *testing.T) { setupDgraph(t, moviesData, movieSchema) // Run export - result := requestExport(t, "/data/export-data", "json") - require.Equal(t, "Success", getFromJSON(result, "data", "export", "response", "code").(string)) - require.Equal(t, "Export completed.", - getFromJSON(result, "data", "export", "response", "message").(string)) - - var files []string - for _, f := range getFromJSON(result, "data", "export", "exportedFiles").([]interface{}) { - files = append(files, f.(string)) - } - require.Equal(t, 3, len(files)) + requestExport(t, "/data/export-data", "json") copyToLocalFs(t) q := `{ q(func:has(movie)) { count(uid) } }` @@ -140,8 +129,11 @@ func TestExportAndLoadJson(t *testing.T) { require.JSONEq(t, `{"data": {"q": [{"count":0}]}}`, res) // Live load the exported data - base := filepath.Dir(files[0]) - dir := filepath.Join(copyExportDir, base) + files, err := ioutil.ReadDir(copyExportDir) + require.NoError(t, err) + require.Len(t, files, 1) + exportName := files[0].Name() + dir := filepath.Join(copyExportDir, exportName) loadData(t, dir, "json") res = runQuery(t, q) @@ -175,16 +167,7 @@ func TestExportAndLoadJsonFacets(t *testing.T) { setupDgraph(t, facetsData, facetsSchema) // Run export - result := requestExport(t, "/data/export-data", "json") - require.Equal(t, "Success", getFromJSON(result, "data", "export", "response", "code").(string)) - require.Equal(t, "Export completed.", - getFromJSON(result, "data", "export", "response", "message").(string)) - - var files []string - for _, f := range getFromJSON(result, "data", "export", "exportedFiles").([]interface{}) { - files = append(files, f.(string)) - } - require.Equal(t, 3, len(files)) + requestExport(t, "/data/export-data", "json") copyToLocalFs(t) checkRes := func() { @@ -225,8 +208,11 @@ func TestExportAndLoadJsonFacets(t *testing.T) { require.JSONEq(t, `{"data": {"q": []}}`, res) // Live load the exported data and verify that exported data is loaded correctly. - base := filepath.Dir(files[0]) - dir := filepath.Join(copyExportDir, base) + files, err := ioutil.ReadDir(copyExportDir) + require.NoError(t, err) + require.Len(t, files, 1) + exportName := files[0].Name() + dir := filepath.Join(copyExportDir, exportName) loadData(t, dir, "json") // verify that the state after loading the exported data as same. @@ -299,14 +285,13 @@ func setupDgraph(t *testing.T, nquads, schema string) { require.NoError(t, err) } -func requestExport(t *testing.T, dest string, format string) map[string]interface{} { +func requestExport(t *testing.T, dest string, format string) { exportRequest := `mutation export($dst: String!, $f: String!) { export(input: {destination: $dst, format: $f}) { response { code - message } - exportedFiles + taskId } }` @@ -323,19 +308,10 @@ func requestExport(t *testing.T, dest string, format string) map[string]interfac resp, err := http.Post(adminUrl, "application/json", bytes.NewBuffer(b)) require.NoError(t, err) - buf, err := ioutil.ReadAll(resp.Body) - require.NoError(t, err) - - var result map[string]interface{} - require.NoError(t, json.Unmarshal(buf, &result)) - return result -} - -func getFromJSON(j map[string]interface{}, path ...string) interface{} { - var res interface{} = j - for _, p := range path { - res = res.(map[string]interface{})[p] - } - return res + var data interface{} + require.NoError(t, json.NewDecoder(resp.Body).Decode(&data)) + require.Equal(t, "Success", testutil.JsonGet(data, "data", "export", "response", "code").(string)) + taskId := testutil.JsonGet(data, "data", "export", "taskId").(string) + testutil.WaitForTask(t, taskId, false) } diff --git a/systest/mutations_test.go b/systest/mutations_test.go index 496e3096bb7..129e70f8083 100644 --- a/systest/mutations_test.go +++ b/systest/mutations_test.go @@ -1738,7 +1738,7 @@ func CountIndexConcurrentSetDelUIDList(t *testing.T, c *dgo.Dgraph) { CommitNow: true, } - mu.SetNquads = []byte(fmt.Sprintf("<0x1> <0x%x> .", id)) + mu.SetNquads = []byte(fmt.Sprintf("<0x1> <%#x> .", id)) _, err := dg.NewTxn().Mutate(context.Background(), mu) if err != nil && err != dgo.ErrAborted { require.Fail(t, "unable to inserted uid with err: %s", err) @@ -1789,7 +1789,7 @@ func CountIndexConcurrentSetDelUIDList(t *testing.T, c *dgo.Dgraph) { CommitNow: true, } - mu.DelNquads = []byte(fmt.Sprintf("<0x1> <0x%x> .", id)) + mu.DelNquads = []byte(fmt.Sprintf("<0x1> <%#x> .", id)) _, err := dg.NewTxn().Mutate(context.Background(), mu) if err != nil && err != dgo.ErrAborted { require.Fail(t, "unable to delete uid with err: %s", err) diff --git a/testutil/backup.go b/testutil/backup.go index 0e192257283..a98b348c878 100644 --- a/testutil/backup.go +++ b/testutil/backup.go @@ -93,7 +93,7 @@ func WaitForRestore(t *testing.T, dg *dgo.Dgraph) { }}`) if err == nil { - numSuccess += 1 + numSuccess++ } else { require.Contains(t, err.Error(), "the server is in draining mode") numSuccess = 0 diff --git a/testutil/utils.go b/testutil/utils.go index b88aae972f4..e36bb174e5a 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -16,7 +16,17 @@ package testutil -import "github.com/dgraph-io/dgraph/x" +import ( + "bytes" + "encoding/json" + "log" + "net/http" + "testing" + "time" + + "github.com/dgraph-io/dgraph/x" + "github.com/stretchr/testify/require" +) func GalaxySchemaKey(attr string) []byte { attr = x.GalaxyAttr(attr) @@ -47,3 +57,52 @@ func GalaxyCountKey(attr string, count uint32, reverse bool) []byte { attr = x.GalaxyAttr(attr) return x.CountKey(attr, count, reverse) } + +func WaitForTask(t *testing.T, taskId string, useHttps bool) { + const query = `query task($id: String!) { + task(input: {id: $id}) { + status + } + }` + params := GraphQLParams{ + Query: query, + Variables: map[string]interface{}{"id": taskId}, + } + request, err := json.Marshal(params) + require.NoError(t, err) + + for { + var adminUrl string + var client http.Client + if useHttps { + adminUrl = "https://" + SockAddrHttp + "/admin" + client = GetHttpsClient(t) + } else { + adminUrl = "http://" + SockAddrHttp + "/admin" + client = *http.DefaultClient + } + response, err := client.Post(adminUrl, "application/json", bytes.NewBuffer(request)) + require.NoError(t, err) + defer response.Body.Close() + + var data interface{} + require.NoError(t, json.NewDecoder(response.Body).Decode(&data)) + status := JsonGet(data, "data", "task", "status").(string) + switch status { + case "Success": + log.Printf("export complete") + return + case "Failed", "Unknown": + t.Errorf("task failed with status: %s", status) + } + + time.Sleep(4 * time.Second) + } +} + +func JsonGet(j interface{}, components ...string) interface{} { + for _, component := range components { + j = j.(map[string]interface{})[component] + } + return j +} diff --git a/worker/backup_ee.go b/worker/backup_ee.go index 71de253e113..bcdc8cf5a51 100644 --- a/worker/backup_ee.go +++ b/worker/backup_ee.go @@ -109,16 +109,7 @@ type BackupRes struct { err error } -func ProcessBackupRequest(ctx context.Context, req *pb.BackupRequest, forceFull bool) error { - if !EnterpriseEnabled() { - return errors.New("you must enable enterprise features first. " + - "Supply the appropriate license file to Dgraph Zero using the HTTP endpoint.") - } - - if req.Destination == "" { - return errors.Errorf("you must specify a 'destination' value") - } - +func ProcessBackupRequest(ctx context.Context, req *pb.BackupRequest) error { if err := x.HealthCheck(); err != nil { glog.Errorf("Backup canceled, not ready to accept requests: %s", err) return err @@ -162,7 +153,7 @@ func ProcessBackupRequest(ctx context.Context, req *pb.BackupRequest, forceFull } req.SinceTs = latestManifest.Since - if forceFull { + if req.ForceFull { req.SinceTs = 0 } else { if x.WorkerConfig.EncryptionKey != nil { diff --git a/worker/backup_oss.go b/worker/backup_oss.go index c7d4b09d740..1472b902809 100644 --- a/worker/backup_oss.go +++ b/worker/backup_oss.go @@ -34,7 +34,7 @@ func (w *grpcWorker) Backup( return nil, x.ErrNotSupported } -func ProcessBackupRequest(ctx context.Context, req *pb.BackupRequest, forceFull bool) error { +func ProcessBackupRequest(ctx context.Context, req *pb.BackupRequest) error { glog.Warningf("Backup failed: %v", x.ErrNotSupported) return x.ErrNotSupported } diff --git a/worker/export.go b/worker/export.go index e02da6cdd5b..21265738a99 100644 --- a/worker/export.go +++ b/worker/export.go @@ -168,7 +168,7 @@ func (e *exporter) toJSON() (*bpb.KVList, error) { } continuing := false - mapStart := fmt.Sprintf(" {\"uid\":"+uidFmtStrJson+`,"namespace":"0x%x"`, e.uid, e.namespace) + mapStart := fmt.Sprintf(" {\"uid\":"+uidFmtStrJson+`,"namespace":"%#x"`, e.uid, e.namespace) err := e.pl.IterateAll(e.readTs, 0, func(p *pb.Posting) error { if continuing { fmt.Fprint(bp, ",\n") @@ -334,7 +334,7 @@ func toSchema(attr string, update *pb.SchemaUpdate) *bpb.KV { func toType(attr string, update pb.TypeUpdate) *bpb.KV { var buf bytes.Buffer ns, attr := x.ParseNamespaceAttr(attr) - x.Check2(buf.WriteString(fmt.Sprintf("[0x%x] type <%s> {\n", ns, attr))) + x.Check2(buf.WriteString(fmt.Sprintf("[%#x] type <%s> {\n", ns, attr))) for _, field := range update.Fields { x.Check2(buf.WriteString(fieldToString(field))) } diff --git a/worker/queue.go b/worker/queue.go new file mode 100644 index 00000000000..1f0b28e3a28 --- /dev/null +++ b/worker/queue.go @@ -0,0 +1,357 @@ +/* + * Copyright 2021 Dgraph Labs, Inc. and Contributors + * + * 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 worker + +import ( + "context" + "fmt" + "math" + "math/rand" + "path/filepath" + "reflect" + "strconv" + "sync" + "time" + + "github.com/dgraph-io/dgraph/protos/pb" + "github.com/dgraph-io/dgraph/raftwal" + "github.com/dgraph-io/dgraph/x" + "github.com/dgraph-io/ristretto/z" + "github.com/golang/glog" + "github.com/pkg/errors" +) + +var ( + // Tasks is a global persistent task queue. + // Do not use this before calling InitTasks. + Tasks tasks +) + +// InitTasks initializes the global Tasks variable. +func InitTasks() { + path := filepath.Join(x.WorkerConfig.TmpDir, "tasks.buf") + log, err := z.NewTreePersistent(path) + x.Check(err) + + // #nosec G404: weak RNG + Tasks = tasks{ + queue: make(chan taskRequest, 16), + log: log, + logMu: new(sync.Mutex), + raftId: State.WALstore.Uint(raftwal.RaftId), + rng: rand.New(rand.NewSource(time.Now().UnixNano())), + } + + // Mark all pending tasks as failed. + Tasks.logMu.Lock() + Tasks.log.IterateKV(func(id, val uint64) uint64 { + meta := TaskMeta(val) + if status := meta.Status(); status == TaskStatusQueued || status == TaskStatusRunning { + return uint64(newTaskMeta(meta.Kind(), TaskStatusFailed)) + } + return 0 + }) + Tasks.logMu.Unlock() + + // Start the task runner. + go Tasks.worker() +} + +// tasks is a persistent task queue. +type tasks struct { + // queue stores the full Protobuf request. + queue chan taskRequest + // log stores the timestamp, TaskKind, and TaskStatus. + log *z.Tree + logMu *sync.Mutex + + raftId uint64 + rng *rand.Rand +} + +// Get retrieves metadata for a given task ID. +// It returns 0 if the task was not found. +func (t tasks) Get(id string) (TaskMeta, error) { + idUint64, err := strconv.ParseUint(id, 0, 64) + if err != nil { + return 0, errors.Wrapf(err, "task ID is invalid: %s", id) + } + if idUint64 == 0 || idUint64 == math.MaxUint64 { + return 0, fmt.Errorf("task ID is invalid: %d", idUint64) + } + t.logMu.Lock() + defer t.logMu.Unlock() + meta := TaskMeta(t.log.Get(idUint64)) + if meta == 0 { + return 0, fmt.Errorf("task does not exist or has expired") + } + return meta, nil +} + +// cleanup deletes all expired tasks. +func (t tasks) cleanup() { + const taskTtl = 7 * 24 * time.Hour // 1 week + minTs := time.Now().UTC().Add(-taskTtl).Unix() + minMeta := uint64(minTs) << 32 + + t.logMu.Lock() + defer t.logMu.Unlock() + t.log.DeleteBelow(minMeta) +} + +// worker loops forever, running queued tasks one at a time. Any returned errors are logged. +func (t tasks) worker() { + shouldCleanup := time.NewTicker(time.Hour) + defer shouldCleanup.Stop() + for { + // If the server is shutting down, return immediately. Else, fetch a task from the queue. + var task taskRequest + select { + case <-x.ServerCloser.HasBeenClosed(): + t.log.Close() + return + case <-shouldCleanup.C: + t.cleanup() + case task = <-t.queue: + if err := t.run(task); err != nil { + glog.Errorf("task %#x: failed: %s", task.id, err) + } else { + glog.Infof("task %#x: completed successfully", task.id) + } + } + } +} + +func (t tasks) run(task taskRequest) error { + // Fetch the task from the log. If the task isn't found, this means it has expired (older than + // taskTtl). + t.logMu.Lock() + meta := TaskMeta(t.log.Get(task.id)) + t.logMu.Unlock() + if meta == 0 { + return fmt.Errorf("is expired, skipping") + } + + // Only proceed if the task is still queued. It's possible that the task got canceled before we + // were able to run it. + if status := meta.Status(); status != TaskStatusQueued { + return fmt.Errorf("status is set to %s, skipping", status) + } + + // Change the task status to Running. + t.logMu.Lock() + t.log.Set(task.id, newTaskMeta(meta.Kind(), TaskStatusRunning).uint64()) + t.logMu.Unlock() + + // Run the task. + var status TaskStatus + err := task.run() + if err != nil { + status = TaskStatusFailed + } else { + status = TaskStatusSuccess + } + + // Change the task status to Success / Failed. + t.logMu.Lock() + t.log.Set(task.id, newTaskMeta(meta.Kind(), status).uint64()) + t.logMu.Unlock() + + // Return the error from the task. + return err +} + +// Enqueue adds a new task to the queue, waits for 3 seconds, and returns any errors that +// may have happened in that span of time. The request must be of type: +// - *pb.BackupRequest +// - *pb.ExportRequest +func (t tasks) Enqueue(req interface{}) (string, error) { + id, err := t.enqueue(req) + if err != nil { + return "", err + } + taskId := fmt.Sprintf("%#x", id) + + // Wait for upto 3 seconds to check for errors. + for i := 0; i < 3; i++ { + time.Sleep(time.Second) + + t.logMu.Lock() + meta := TaskMeta(t.log.Get(id)) + t.logMu.Unlock() + + // Early return + switch meta.Status() { + case TaskStatusFailed: + return "", fmt.Errorf("an error occurred, please check logs for details") + case TaskStatusSuccess: + return taskId, nil + } + } + + return taskId, nil +} + +// enqueue adds a new task to the queue. This must be of type: +// - *pb.BackupRequest +// - *pb.ExportRequest +func (t tasks) enqueue(req interface{}) (uint64, error) { + var kind TaskKind + switch req.(type) { + case *pb.BackupRequest: + kind = TaskKindBackup + case *pb.ExportRequest: + kind = TaskKindExport + default: + err := fmt.Errorf("invalid TaskKind: %d", kind) + panic(err) + } + + t.logMu.Lock() + defer t.logMu.Unlock() + + task := taskRequest{ + id: t.newId(), + req: req, + } + select { + // t.logMu must be acquired before pushing to t.queue, otherwise the worker might start the + // task, and won't be able to find it in t.log. + case t.queue <- task: + t.log.Set(task.id, newTaskMeta(kind, TaskStatusQueued).uint64()) + return task.id, nil + default: + return 0, fmt.Errorf("too many pending tasks, please try again later") + } +} + +// newId generates a random unique task ID. logMu must be acquired before calling this function. +// +// The format of this is: +// 32 bits: raft ID +// 32 bits: random number +func (t tasks) newId() uint64 { + for { + id := t.raftId<<32 | uint64(t.rng.Int()) + // z.Tree cannot store 0 or math.MaxUint64. Check that id is unique. + if id != 0 && id != math.MaxUint64 && t.log.Get(id) == 0 { + return id + } + } +} + +type taskRequest struct { + id uint64 + req interface{} // *pb.BackupRequest, *pb.ExportRequest +} + +// run starts a task and blocks till it completes. +func (t taskRequest) run() error { + switch req := t.req.(type) { + case *pb.BackupRequest: + if err := ProcessBackupRequest(context.Background(), req); err != nil { + return err + } + case *pb.ExportRequest: + files, err := ExportOverNetwork(context.Background(), req) + if err != nil { + return err + } + glog.Infof("task %#x: exported files: %v", t.id, files) + default: + glog.Errorf( + "task %#x: received request of unknown type (%T)", t.id, reflect.TypeOf(t.req)) + } + return nil +} + +// TaskMeta stores a timestamp, a TaskKind and a Status. +// +// The format of this is: +// 32 bits: UNIX timestamp (overflows on 2106-02-07) +// 16 bits: TaskKind +// 16 bits: TaskStatus +type TaskMeta uint64 + +func newTaskMeta(kind TaskKind, status TaskStatus) TaskMeta { + now := time.Now().UTC().Unix() + return TaskMeta(now)<<32 | TaskMeta(kind)<<16 | TaskMeta(status) +} + +// Timestamp returns the timestamp of the last status change of the task. +func (t TaskMeta) Timestamp() time.Time { + return time.Unix(int64(t>>32), 0) +} + +// Kind returns the type of the task. +func (t TaskMeta) Kind() TaskKind { + return TaskKind((t >> 16) & math.MaxUint16) +} + +// Status returns the current status of the task. +func (t TaskMeta) Status() TaskStatus { + return TaskStatus(t & math.MaxUint16) +} + +// uint64 represents the TaskMeta as a uint64. +func (t TaskMeta) uint64() uint64 { + return uint64(t) +} + +const ( + // Reserve the zero value for errors. + TaskKindBackup TaskKind = iota + 1 + TaskKindExport +) + +type TaskKind uint64 + +func (k TaskKind) String() string { + switch k { + case TaskKindBackup: + return "Backup" + case TaskKindExport: + return "Export" + default: + return "Unknown" + } +} + +const ( + // Reserve the zero value for errors. + TaskStatusQueued TaskStatus = iota + 1 + TaskStatusRunning + TaskStatusFailed + TaskStatusSuccess +) + +type TaskStatus uint64 + +func (status TaskStatus) String() string { + switch status { + case TaskStatusQueued: + return "Queued" + case TaskStatusRunning: + return "Running" + case TaskStatusFailed: + return "Failed" + case TaskStatusSuccess: + return "Success" + default: + return "Unknown" + } +} diff --git a/worker/worker_test.go b/worker/worker_test.go index 0c63758af49..1de0a1e7d7c 100644 --- a/worker/worker_test.go +++ b/worker/worker_test.go @@ -141,13 +141,13 @@ func populateGraph(t *testing.T) { func populateClusterGraph(t *testing.T, dg *dgo.Dgraph) { data1 := [][]int{{10, 23}, {11, 23}, {12, 23}, {12, 25}, {12, 26}, {10, 31}, {12, 31}} for _, pair := range data1 { - rdf := fmt.Sprintf(`<0x%x> <0x%x> .`, pair[0], pair[1]) + rdf := fmt.Sprintf(`<%#x> <%#x> .`, pair[0], pair[1]) setClusterEdge(t, dg, rdf) } data2 := map[int]string{12: "photon", 10: "photon"} for key, val := range data2 { - rdf := fmt.Sprintf(`<0x%x> %q .`, key, val) + rdf := fmt.Sprintf(`<%#x> %q .`, key, val) setClusterEdge(t, dg, rdf) } } @@ -211,7 +211,7 @@ func runQuery(dg *dgo.Dgraph, attr string, uids []uint64, srcFunc []string) (*ap if uids != nil { var uidv []string for _, uid := range uids { - uidv = append(uidv, fmt.Sprintf("0x%x", uid)) + uidv = append(uidv, fmt.Sprintf("%#x", uid)) } query = fmt.Sprintf(` { @@ -258,8 +258,8 @@ func TestProcessTaskIndexMLayer(t *testing.T) { // Now try changing 12's friend value from "photon" to "notphotonExtra" to // "notphoton". - setClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "notphotonExtra")) - setClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "notphoton")) + setClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "notphotonExtra")) + setClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "notphoton")) // Issue a similar query. resp, err = runQuery(dg, "friend", nil, @@ -275,12 +275,12 @@ func TestProcessTaskIndexMLayer(t *testing.T) { ) // Try redundant deletes. - delClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 10, "photon")) - delClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 10, "photon")) + delClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 10, "photon")) + delClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 10, "photon")) // Delete followed by set. - delClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "notphoton")) - setClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "ignored")) + delClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "notphoton")) + setClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "ignored")) // Issue a similar query. resp, err = runQuery(dg, "friend", nil, @@ -324,8 +324,8 @@ func TestProcessTaskIndex(t *testing.T) { // Now try changing 12's friend value from "photon" to "notphotonExtra" to // "notphoton". - setClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "notphotonExtra")) - setClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "notphoton")) + setClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "notphotonExtra")) + setClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "notphoton")) // Issue a similar query. resp, err = runQuery(dg, "friend", nil, @@ -341,12 +341,12 @@ func TestProcessTaskIndex(t *testing.T) { ) // Try redundant deletes. - delClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 10, "photon")) - delClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 10, "photon")) + delClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 10, "photon")) + delClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 10, "photon")) // Delete followed by set. - delClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "notphoton")) - setClusterEdge(t, dg, fmt.Sprintf("<0x%x> %q .", 12, "ignored")) + delClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "notphoton")) + setClusterEdge(t, dg, fmt.Sprintf("<%#x> %q .", 12, "ignored")) // Issue a similar query. resp, err = runQuery(dg, "friend", nil, From 6b188f254202f9c38b16c4769b672dd0e9d596ac Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Mon, 3 May 2021 22:30:47 +0530 Subject: [PATCH 6/6] Format protos using clang-format (#7773) --- protos/pb.proto | 891 +++++++++++++++++++++++---------------------- protos/pb/pb.pb.go | 105 +++--- 2 files changed, 515 insertions(+), 481 deletions(-) diff --git a/protos/pb.proto b/protos/pb.proto index 9f8a27b2920..b9e72e4ed7a 100644 --- a/protos/pb.proto +++ b/protos/pb.proto @@ -14,7 +14,6 @@ * limitations under the License. */ - // Style guide for Protocol Buffer 3. // Use CamelCase (with an initial capital) for message names – for example, // SongServerRequest. Use underscore_separated_names for field names – for @@ -36,653 +35,671 @@ import "github.com/gogo/protobuf/gogoproto/gogo.proto"; /* option (gogoproto.goproto_getters_all) = true; */ message List { - repeated fixed64 uids = 1; - bytes bitmap_do_not_use = 2; + repeated fixed64 uids = 1; + bytes bitmap_do_not_use = 2; } message TaskValue { - bytes val = 1; - Posting.ValType val_type = 2; + bytes val = 1; + Posting.ValType val_type = 2; } message SrcFunction { - string name = 1; - repeated string args = 3; - bool isCount = 4; + string name = 1; + repeated string args = 3; + bool isCount = 4; } message Query { - string attr = 1; - repeated string langs = 2; // language list for attribute - fixed64 after_uid = 3; // Only return UIDs greater than this. - bool do_count = 4; // Are we just getting lengths? + string attr = 1; + repeated string langs = 2; // language list for attribute + fixed64 after_uid = 3; // Only return UIDs greater than this. + bool do_count = 4; // Are we just getting lengths? - // Exactly one of uids and terms is populated. - List uid_list = 5; + // Exactly one of uids and terms is populated. + List uid_list = 5; - // Function to generate or filter UIDs. - SrcFunction src_func = 6; + // Function to generate or filter UIDs. + SrcFunction src_func = 6; - bool reverse = 7; // Whether this is a reverse edge. + // Whether this is a reverse edge. + bool reverse = 7; - FacetParams facet_param = 8; // which facets to fetch - FilterTree facets_filter = 9; // filtering on facets : has Op (and/or/not) tree + // Which facets to fetch. + FacetParams facet_param = 8; + // Filtering on facets: has Op (and/or/not) tree. + FilterTree facets_filter = 9; - bool expand_all = 10; // expand all language variants. + // Expand all language variants. + bool expand_all = 10; - uint64 read_ts = 13; - int32 cache = 14; - int32 first = 15; // used to limit the number of result. Typically, the count is value of first - // field. Now, It's been used only for has query. - int32 offset = 16; // offset helps in fetching lesser results for the has query when there is - // no filter and order. + uint64 read_ts = 13; + int32 cache = 14; + // Used to limit the number of result. Typically, the count is value of first + // field. Now, It's been used only for has query. + int32 first = 15; + // Offset helps in fetching lesser results for the has query when there is no + // filter and order. + int32 offset = 16; } message ValueList { - repeated TaskValue values = 1; + repeated TaskValue values = 1; } message LangList { - repeated string lang = 1; + repeated string lang = 1; } message Result { - repeated List uid_matrix = 1; - repeated ValueList value_matrix = 2; - repeated uint32 counts = 3; - bool intersect_dest = 4; - repeated FacetsList facet_matrix = 5; - repeated LangList lang_matrix = 6; - bool list = 7; + repeated List uid_matrix = 1; + repeated ValueList value_matrix = 2; + repeated uint32 counts = 3; + bool intersect_dest = 4; + repeated FacetsList facet_matrix = 5; + repeated LangList lang_matrix = 6; + bool list = 7; } message Order { - string attr = 1; - bool desc = 2; - repeated string langs = 3; + string attr = 1; + bool desc = 2; + repeated string langs = 3; } message SortMessage { - repeated Order order = 1; - repeated List uid_matrix = 2; - int32 count = 3; // Return this many elements. - int32 offset = 4; // Skip this many elements. + repeated Order order = 1; + repeated List uid_matrix = 2; + int32 count = 3; // Return this many elements. + int32 offset = 4; // Skip this many elements. - uint64 read_ts = 13; + uint64 read_ts = 13; } message SortResult { - repeated List uid_matrix = 1; + repeated List uid_matrix = 1; } message RaftContext { - fixed64 id = 1; - uint32 group = 2; - string addr = 3; - uint64 snapshot_ts = 4; - bool is_learner = 5; + fixed64 id = 1; + uint32 group = 2; + string addr = 3; + uint64 snapshot_ts = 4; + bool is_learner = 5; } // Member stores information about RAFT group member for a single RAFT node. -// Note that each server can be serving multiple RAFT groups. Each group would have -// one RAFT node per server serving that group. +// Note that each server can be serving multiple RAFT groups. Each group would +// have one RAFT node per server serving that group. message Member { - fixed64 id = 1; - uint32 group_id = 2 [(gogoproto.jsontag) = "groupId,omitempty"]; - string addr = 3; - bool leader = 4; - bool am_dead = 5 [(gogoproto.jsontag) = "amDead,omitempty"]; - uint64 last_update = 6 [(gogoproto.jsontag) = "lastUpdate,omitempty"]; - bool learner = 7; + fixed64 id = 1; + uint32 group_id = 2 [(gogoproto.jsontag) = "groupId,omitempty"]; + string addr = 3; + bool leader = 4; + bool am_dead = 5 [(gogoproto.jsontag) = "amDead,omitempty"]; + uint64 last_update = 6 [(gogoproto.jsontag) = "lastUpdate,omitempty"]; + bool learner = 7; - bool cluster_info_only = 13 [(gogoproto.jsontag) = "clusterInfoOnly,omitempty"]; - bool force_group_id = 14 [(gogoproto.jsontag) = "forceGroupId,omitempty"]; + bool cluster_info_only = 13 + [(gogoproto.jsontag) = "clusterInfoOnly,omitempty"]; + bool force_group_id = 14 [(gogoproto.jsontag) = "forceGroupId,omitempty"]; } message Group { - map members = 1; // Raft ID is the key. - map tablets = 2; // Predicate + others are key. - uint64 snapshot_ts = 3; // Stores Snapshot transaction ts. - uint64 checksum = 4; // Stores a checksum. - uint64 checkpoint_ts = 5; // Stores checkpoint ts as seen by leader. + map members = 1; // Raft ID is the key. + map tablets = 2; // Predicate + others are key. + uint64 snapshot_ts = 3; // Stores Snapshot transaction ts. + uint64 checksum = 4; // Stores a checksum. + uint64 checkpoint_ts = 5; // Stores checkpoint ts as seen by leader. } message License { - string user = 1; - uint64 maxNodes = 2; - int64 expiryTs = 3; - bool enabled = 4; + string user = 1; + uint64 maxNodes = 2; + int64 expiryTs = 3; + bool enabled = 4; } message ZeroProposal { - reserved 8; // Was used for string key. - map snapshot_ts = 1; // Group ID -> Snapshot Ts. - Member member = 2; - Tablet tablet = 3; - uint64 maxUID = 4; - uint64 maxTxnTs = 5; - uint64 maxNsID = 12; - uint64 maxRaftId = 6; - api.TxnContext txn = 7; - string cid = 9; // Used as unique identifier for the cluster. - License license = 10; - ZeroSnapshot snapshot = 11; // Used to make Zeros take a snapshot. - // 12 has already been used. - DeleteNsRequest delete_ns = 13; // Used to delete namespace. -} - -// MembershipState is used to pack together the current membership state of all the nodes -// in the caller server; and the membership updates recorded by the callee server since -// the provided lastUpdate. + reserved 8; // Was used for string key. + map snapshot_ts = 1; // Group ID -> Snapshot Ts. + Member member = 2; + Tablet tablet = 3; + uint64 maxUID = 4; + uint64 maxTxnTs = 5; + uint64 maxNsID = 12; + uint64 maxRaftId = 6; + api.TxnContext txn = 7; + string cid = 9; // Used as unique identifier for the cluster. + License license = 10; + ZeroSnapshot snapshot = 11; // Used to make Zeros take a snapshot. + // 12 has already been used. + DeleteNsRequest delete_ns = 13; // Used to delete namespace. +} + +// MembershipState is used to pack together the current membership state of all +// the nodes in the caller server; and the membership updates recorded by the +// callee server since the provided lastUpdate. message MembershipState { - uint64 counter = 1; // used to find latest membershipState in case of race. - map groups = 2; - map zeros = 3; - uint64 maxUID = 4; - uint64 maxTxnTs = 5; - uint64 maxNsID = 10; - uint64 maxRaftId = 6; - repeated Member removed = 7; - string cid = 8; // Used to uniquely identify the Dgraph cluster. - License license = 9; - // 10 has already been used. + uint64 counter = 1; // Used to find latest membershipState in case of race. + map groups = 2; + map zeros = 3; + uint64 maxUID = 4; + uint64 maxTxnTs = 5; + uint64 maxNsID = 10; + uint64 maxRaftId = 6; + repeated Member removed = 7; + string cid = 8; // Used to uniquely identify the Dgraph cluster. + License license = 9; + // 10 has already been used. } message ConnectionState { - Member member = 1; - MembershipState state = 2; - uint64 max_pending = 3; // Used to determine the timstamp for reading after bulk load + Member member = 1; + MembershipState state = 2; + // Used to determine the timstamp for reading after bulk load. + uint64 max_pending = 3; } message HealthInfo { - string instance = 1; - string address = 2; - string status = 3; - string group = 4; // string so group = 0 can be printed in JSON. - string version = 5; - int64 uptime = 6; - int64 lastEcho = 7; - repeated string ongoing = 8; - repeated string indexing = 9; - repeated string ee_features = 10; - uint64 max_assigned = 11; + string instance = 1; + string address = 2; + string status = 3; + string group = 4; // string so group = 0 can be printed in JSON. + string version = 5; + int64 uptime = 6; + int64 lastEcho = 7; + repeated string ongoing = 8; + repeated string indexing = 9; + repeated string ee_features = 10; + uint64 max_assigned = 11; } message Tablet { - uint32 group_id = 1 [(gogoproto.jsontag) = "groupId,omitempty"]; // Served by which group. - string predicate = 2; - bool force = 3; // Used while moving predicate. - int64 on_disk_bytes = 7; - bool remove = 8; - bool read_only = 9 [(gogoproto.jsontag) = "readOnly,omitempty"]; // If true, do not ask zero to serve any tablets. - uint64 move_ts = 10 [(gogoproto.jsontag) = "moveTs,omitempty"]; - int64 uncompressed_bytes = 11; // Estimated uncompressed size of tablet in bytes + // Served by which group. + uint32 group_id = 1 [(gogoproto.jsontag) = "groupId,omitempty"]; + string predicate = 2; + bool force = 3; // Used while moving predicate. + int64 on_disk_bytes = 7; + bool remove = 8; + // If true, do not ask zero to serve any tablets. + bool read_only = 9 [(gogoproto.jsontag) = "readOnly,omitempty"]; + uint64 move_ts = 10 [(gogoproto.jsontag) = "moveTs,omitempty"]; + // Estimated uncompressed size of tablet in bytes + int64 uncompressed_bytes = 11; } message DirectedEdge { - reserved 6; // This was used for label. - fixed64 entity = 1; // Subject or source node / UID. - string attr = 2; // Attribute or predicate. Labels the edge. - bytes value = 3; // Edge points to a value. - Posting.ValType value_type = 4; // The type of the value - fixed64 value_id = 5; // Object or destination node / UID. - string lang = 7; - enum Op { - SET = 0; - DEL = 1; - } - Op op = 8; - repeated api.Facet facets = 9; - repeated string allowedPreds = 10; - uint64 namespace = 11; + reserved 6; // This was used for label. + fixed64 entity = 1; // Subject or source node / UID. + string attr = 2; // Attribute or predicate. Labels the edge. + bytes value = 3; // Edge points to a value. + Posting.ValType value_type = 4; // The type of the value + fixed64 value_id = 5; // Object or destination node / UID. + string lang = 7; + enum Op { + SET = 0; + DEL = 1; + } + Op op = 8; + repeated api.Facet facets = 9; + repeated string allowedPreds = 10; + uint64 namespace = 11; } message Mutations { - uint32 group_id = 1; - uint64 start_ts = 2; - repeated DirectedEdge edges = 3; - repeated SchemaUpdate schema = 4; - repeated TypeUpdate types = 6; - enum DropOp { - NONE = 0; - ALL = 1; - DATA = 2; - TYPE = 3; - } - DropOp drop_op = 7; - string drop_value = 8; - - Metadata metadata = 9; + uint32 group_id = 1; + uint64 start_ts = 2; + repeated DirectedEdge edges = 3; + repeated SchemaUpdate schema = 4; + repeated TypeUpdate types = 6; + enum DropOp { + NONE = 0; + ALL = 1; + DATA = 2; + TYPE = 3; + } + DropOp drop_op = 7; + string drop_value = 8; + + Metadata metadata = 9; } message Metadata { // HintType represents a hint that will be passed along the mutation and used // to add the predicate to the schema if it's not already there. enum HintType { - // DEFAULT means no hint is provided and Dgraph will follow the default behavior. + // DEFAULT means no hint is provided and Dgraph will follow the default + // behavior. DEFAULT = 0; - // SINGLE signals that the predicate should be created as a single type (e.g string, uid). + // SINGLE signals that the predicate should be created as a single type (e.g + // string, uid). SINGLE = 1; - // LIST signals that the predicate should be created as a list (e.g [string], [uid]). + // LIST signals that the predicate should be created as a list (e.g + // [string], [uid]). LIST = 2; } // Map of predicates to their hints. - map pred_hints = 1; + map pred_hints = 1; } message Snapshot { - RaftContext context = 1; - uint64 index = 2; - uint64 read_ts = 3; - // done is used to indicate that snapshot stream was a success. - bool done = 4; - // since_ts stores the ts of the last snapshot to support diff snap updates. - uint64 since_ts = 5; - // max_assigned stores the ts as seen as of snapshot read_ts. - uint64 max_assigned = 6; + RaftContext context = 1; + uint64 index = 2; + uint64 read_ts = 3; + // done is used to indicate that snapshot stream was a success. + bool done = 4; + // since_ts stores the ts of the last snapshot to support diff snap updates. + uint64 since_ts = 5; + // max_assigned stores the ts as seen as of snapshot read_ts. + uint64 max_assigned = 6; } message ZeroSnapshot { - uint64 index = 1; - uint64 checkpoint_ts = 2; - MembershipState state = 5; + uint64 index = 1; + uint64 checkpoint_ts = 2; + MembershipState state = 5; } message RestoreRequest { - uint32 group_id = 1; - uint64 restore_ts = 2; - string location = 3; - string backup_id = 4; - - // Credentials when using a minio or S3 bucket as the backup location. - string access_key = 5; - string secret_key = 6; - string session_token = 7; - bool anonymous = 8; - - // Info needed to process encrypted backups. - string encryption_key_file = 9; - // Vault options - string vault_addr = 10; - string vault_roleid_file = 11; - string vault_secretid_file = 12; - string vault_path = 13; - string vault_field = 14; - string vault_format = 15; - - uint64 backup_num = 16; + uint32 group_id = 1; + uint64 restore_ts = 2; + string location = 3; + string backup_id = 4; + + // Credentials when using a minio or S3 bucket as the backup location. + string access_key = 5; + string secret_key = 6; + string session_token = 7; + bool anonymous = 8; + + // Info needed to process encrypted backups. + string encryption_key_file = 9; + // Vault options + string vault_addr = 10; + string vault_roleid_file = 11; + string vault_secretid_file = 12; + string vault_path = 13; + string vault_field = 14; + string vault_format = 15; + + uint64 backup_num = 16; } message Proposal { - reserved 7; // Was used for string key. - Mutations mutations = 2; - repeated badgerpb3.KV kv = 4; - MembershipState state = 5; - string clean_predicate = 6; // Delete the predicate which was moved to other group. - OracleDelta delta = 8; - Snapshot snapshot = 9; // Used to tell the group when to take snapshot. - uint64 index = 10; // Used to store Raft index, in raft.Ready. - uint64 expected_checksum = 11; // Block an operation until membership reaches this checksum. - RestoreRequest restore = 12; - CDCState cdc_state = 13; - DeleteNsRequest delete_ns = 14; // Used to delete namespace. - uint64 key = 15; - uint64 start_ts = 16; + reserved 7; // Was used for string key. + Mutations mutations = 2; + repeated badgerpb3.KV kv = 4; + MembershipState state = 5; + // Delete the predicate which was moved to other group. + string clean_predicate = 6; + OracleDelta delta = 8; + Snapshot snapshot = 9; // Used to tell the group when to take snapshot. + uint64 index = 10; // Used to store Raft index, in raft.Ready. + // Block an operation until membership reaches this checksum. + uint64 expected_checksum = 11; + RestoreRequest restore = 12; + CDCState cdc_state = 13; + DeleteNsRequest delete_ns = 14; // Used to delete namespace. + uint64 key = 15; + uint64 start_ts = 16; } message CDCState { - uint64 sent_ts = 1; + uint64 sent_ts = 1; } message KVS { - bytes data = 5; - - // done used to indicate if the stream of KVS is over. - bool done = 2; - // predicates is the list of predicates known by the leader at the time of the snapshot. - repeated string predicates = 3; - // types is the list of types known by the leader at the time of the snapshot. - repeated string types = 4; + bytes data = 5; + + // Done used to indicate if the stream of KVS is over. + bool done = 2; + // Predicates is the list of predicates known by the leader at the time of the + // snapshot. + repeated string predicates = 3; + // Types is the list of types known by the leader at the time of the snapshot. + repeated string types = 4; } // Posting messages. message Posting { - reserved 6; // This was used for label. - fixed64 uid = 1; - bytes value = 2; - enum ValType { - DEFAULT = 0; - BINARY = 1; - INT = 2; // We treat it as int64. - FLOAT = 3; - BOOL = 4; - DATETIME = 5; - GEO = 6; - UID = 7; - PASSWORD = 8; - STRING = 9; + reserved 6; // This was used for label. + fixed64 uid = 1; + bytes value = 2; + enum ValType { + DEFAULT = 0; + BINARY = 1; + INT = 2; // We treat it as int64. + FLOAT = 3; + BOOL = 4; + DATETIME = 5; + GEO = 6; + UID = 7; + PASSWORD = 8; + STRING = 9; OBJECT = 10; - } - ValType val_type = 3; - enum PostingType { - REF=0; // UID - VALUE=1; // simple, plain value - VALUE_LANG=2; // value with specified language - } - PostingType posting_type = 4; - bytes lang_tag = 5; // Only set for VALUE_LANG - repeated api.Facet facets = 9; - - // TODO: op is only used temporarily. See if we can remove it from here. - uint32 op = 12; - uint64 start_ts = 13; // Meant to use only inmemory - uint64 commit_ts = 14; // Meant to use only inmemory + } + ValType val_type = 3; + enum PostingType { + REF = 0; // UID + VALUE = 1; // simple, plain value + VALUE_LANG = 2; // value with specified language + } + PostingType posting_type = 4; + bytes lang_tag = 5; // Only set for VALUE_LANG + repeated api.Facet facets = 9; + + // TODO: op is only used temporarily. See if we can remove it from here. + uint32 op = 12; + uint64 start_ts = 13; // Meant to use only inmemory + uint64 commit_ts = 14; // Meant to use only inmemory } message PostingList { - reserved 1; // It was used for UidPack. - repeated Posting postings = 2; - uint64 commit_ts = 3; // More inclination towards smaller values. + reserved 1; // It was used for UidPack. + repeated Posting postings = 2; + uint64 commit_ts = 3; // More inclination towards smaller values. repeated uint64 splits = 4; - bytes bitmap = 5; // Roaring Bitmap encoded uint64s. + bytes bitmap = 5; // Roaring Bitmap encoded uint64s. } message FacetParam { - string key = 1; - string alias = 2; + string key = 1; + string alias = 2; } message FacetParams { - bool all_keys = 1; // keys should be in sorted order. - repeated FacetParam param = 2; + bool all_keys = 1; // Keys should be in sorted order. + repeated FacetParam param = 2; } message Facets { - repeated api.Facet facets = 1; + repeated api.Facet facets = 1; } message FacetsList { - repeated Facets facets_list = 1; + repeated Facets facets_list = 1; } message Function { - string name = 1; // Name of the function : eq, le - string key = 2; // Facet key over which to run the function. - repeated string args = 3; // Arguments of the function. + string name = 1; // Name of the function : eq, le + string key = 2; // Facet key over which to run the function. + repeated string args = 3; // Arguments of the function. } // Op and Children are internal nodes and Func on leaves. message FilterTree { - string op = 1; - repeated FilterTree children = 2; - Function func = 3; + string op = 1; + repeated FilterTree children = 2; + Function func = 3; } // Schema messages. message SchemaRequest { - uint32 group_id = 1; - repeated string predicates = 2; - // fields can be on of type, index, reverse or tokenizer - repeated string fields = 3; + uint32 group_id = 1; + repeated string predicates = 2; + // Fields can be on of type, index, reverse or tokenizer. + repeated string fields = 3; repeated string types = 4; } message SchemaNode { - string predicate = 1; - string type = 2; - bool index = 3; - repeated string tokenizer = 4; - bool reverse = 5; - bool count = 6; - bool list = 7; - bool upsert = 8; - bool lang = 9; - bool no_conflict = 10; + string predicate = 1; + string type = 2; + bool index = 3; + repeated string tokenizer = 4; + bool reverse = 5; + bool count = 6; + bool list = 7; + bool upsert = 8; + bool lang = 9; + bool no_conflict = 10; } message SchemaResult { - repeated SchemaNode schema = 1 [deprecated=true]; + repeated SchemaNode schema = 1 [deprecated = true]; } message SchemaUpdate { - string predicate = 1; - Posting.ValType value_type = 2; - enum Directive { - NONE = 0; - INDEX = 1; - REVERSE = 2; - DELETE = 3; - } - Directive directive = 3; - repeated string tokenizer = 4; - bool count = 5; - bool list = 6; - bool upsert = 8; - bool lang = 9; - - // Fields required for type system. - bool non_nullable = 10; - bool non_nullable_list = 11; - - // If value_type is OBJECT, then this represents an object type with a - // custom name. This field stores said name. - string object_type_name = 12; - - bool no_conflict = 13; - - // Deleted field: - reserved 7; - reserved "explicit"; + string predicate = 1; + Posting.ValType value_type = 2; + enum Directive { + NONE = 0; + INDEX = 1; + REVERSE = 2; + DELETE = 3; + } + Directive directive = 3; + repeated string tokenizer = 4; + bool count = 5; + bool list = 6; + bool upsert = 8; + bool lang = 9; + + // Fields required for type system. + bool non_nullable = 10; + bool non_nullable_list = 11; + + // If value_type is OBJECT, then this represents an object type with a custom + // name. This field stores said name. + string object_type_name = 12; + + bool no_conflict = 13; + + // Deleted field: + reserved 7; + reserved "explicit"; } message TypeUpdate { - string type_name = 1; - repeated SchemaUpdate fields = 2; + string type_name = 1; + repeated SchemaUpdate fields = 2; } message MapHeader { - repeated bytes partition_keys = 1; + repeated bytes partition_keys = 1; } message MovePredicatePayload { - string predicate = 1; - uint32 source_gid = 2; - uint32 dest_gid = 3; - uint64 read_ts = 4; - uint64 expected_checksum = 5; - uint64 since_ts = 6; + string predicate = 1; + uint32 source_gid = 2; + uint32 dest_gid = 3; + uint64 read_ts = 4; + uint64 expected_checksum = 5; + uint64 since_ts = 6; } message TxnStatus { - uint64 start_ts = 1; - uint64 commit_ts = 2; + uint64 start_ts = 1; + uint64 commit_ts = 2; } message OracleDelta { - repeated TxnStatus txns = 1; - uint64 max_assigned = 2; - map group_checksums = 3; - // implement tmax. + repeated TxnStatus txns = 1; + uint64 max_assigned = 2; + map group_checksums = 3; + // implement tmax. } message TxnTimestamps { - repeated uint64 ts = 1; + repeated uint64 ts = 1; } message PeerResponse { - bool status = 1; + bool status = 1; } message RaftBatch { - RaftContext context = 1; - api.Payload payload = 2; + RaftContext context = 1; + api.Payload payload = 2; } service Raft { - rpc Heartbeat (api.Payload) returns (stream HealthInfo) {} - rpc RaftMessage (stream RaftBatch) returns (api.Payload) {} - rpc JoinCluster (RaftContext) returns (api.Payload) {} - rpc IsPeer (RaftContext) returns (PeerResponse) {} + rpc Heartbeat(api.Payload) returns (stream HealthInfo) {} + rpc RaftMessage(stream RaftBatch) returns (api.Payload) {} + rpc JoinCluster(RaftContext) returns (api.Payload) {} + rpc IsPeer(RaftContext) returns (PeerResponse) {} } service Zero { - // These 3 endpoints are for handling membership. - rpc Connect (Member) returns (ConnectionState) {} - rpc UpdateMembership (Group) returns (api.Payload) {} - rpc StreamMembership (api.Payload) returns (stream MembershipState) {} - - rpc Oracle (api.Payload) returns (stream OracleDelta) {} - rpc ShouldServe (Tablet) returns (Tablet) {} - rpc AssignIds (Num) returns (AssignedIds) {} - rpc Timestamps (Num) returns (AssignedIds) {} - rpc CommitOrAbort (api.TxnContext) returns (api.TxnContext) {} - rpc TryAbort (TxnTimestamps) returns (OracleDelta) {} - rpc DeleteNamespace(DeleteNsRequest) returns (Status) {} - rpc RemoveNode (RemoveNodeRequest) returns (Status) {} - rpc MoveTablet (MoveTabletRequest) returns (Status) {} - rpc ApplyLicense (ApplyLicenseRequest) returns (Status) {} + // These 3 endpoints are for handling membership. + rpc Connect(Member) returns (ConnectionState) {} + rpc UpdateMembership(Group) returns (api.Payload) {} + rpc StreamMembership(api.Payload) returns (stream MembershipState) {} + + rpc Oracle(api.Payload) returns (stream OracleDelta) {} + rpc ShouldServe(Tablet) returns (Tablet) {} + rpc AssignIds(Num) returns (AssignedIds) {} + rpc Timestamps(Num) returns (AssignedIds) {} + rpc CommitOrAbort(api.TxnContext) returns (api.TxnContext) {} + rpc TryAbort(TxnTimestamps) returns (OracleDelta) {} + rpc DeleteNamespace(DeleteNsRequest) returns (Status) {} + rpc RemoveNode(RemoveNodeRequest) returns (Status) {} + rpc MoveTablet(MoveTabletRequest) returns (Status) {} + rpc ApplyLicense(ApplyLicenseRequest) returns (Status) {} } service Worker { - // Data serving RPCs. - rpc Mutate (Mutations) returns (api.TxnContext) {} - rpc ServeTask (Query) returns (Result) {} - rpc StreamSnapshot (stream Snapshot) returns (stream KVS) {} - rpc Sort (SortMessage) returns (SortResult) {} - rpc Schema (SchemaRequest) returns (SchemaResult) {} - rpc Backup (BackupRequest) returns (BackupResponse) {} - rpc Restore (RestoreRequest) returns (Status) {} - rpc Export (ExportRequest) returns (ExportResponse) {} - rpc ReceivePredicate(stream KVS) returns (api.Payload) {} - rpc MovePredicate(MovePredicatePayload) returns (api.Payload) {} - rpc Subscribe(SubscriptionRequest) returns (stream badgerpb3.KVList) {} - rpc UpdateGraphQLSchema(UpdateGraphQLSchemaRequest) returns (UpdateGraphQLSchemaResponse) {} - rpc DeleteNamespace (DeleteNsRequest) returns (Status) {} + // Data serving RPCs. + rpc Mutate(Mutations) returns (api.TxnContext) {} + rpc ServeTask(Query) returns (Result) {} + rpc StreamSnapshot(stream Snapshot) returns (stream KVS) {} + rpc Sort(SortMessage) returns (SortResult) {} + rpc Schema(SchemaRequest) returns (SchemaResult) {} + rpc Backup(BackupRequest) returns (BackupResponse) {} + rpc Restore(RestoreRequest) returns (Status) {} + rpc Export(ExportRequest) returns (ExportResponse) {} + rpc ReceivePredicate(stream KVS) returns (api.Payload) {} + rpc MovePredicate(MovePredicatePayload) returns (api.Payload) {} + rpc Subscribe(SubscriptionRequest) returns (stream badgerpb3.KVList) {} + rpc UpdateGraphQLSchema(UpdateGraphQLSchemaRequest) + returns (UpdateGraphQLSchemaResponse) {} + rpc DeleteNamespace(DeleteNsRequest) returns (Status) {} } message SubscriptionRequest { - repeated bytes prefixes = 1; - repeated badgerpb3.Match matches = 2; + repeated bytes prefixes = 1; + repeated badgerpb3.Match matches = 2; } message SubscriptionResponse { - badgerpb3.KVList kvs = 1; + badgerpb3.KVList kvs = 1; } message Num { - uint64 val = 1; - bool read_only = 2; - bool forwarded = 3; // True if this request was forwarded by a peer. - enum leaseType { - NS_ID = 0; - UID = 1; - TXN_TS = 2; - } - leaseType type = 4; + uint64 val = 1; + bool read_only = 2; + bool forwarded = 3; // True if this request was forwarded by a peer. + enum leaseType { + NS_ID = 0; + UID = 1; + TXN_TS = 2; + } + leaseType type = 4; } message AssignedIds { - uint64 startId = 1; - uint64 endId = 2; + uint64 startId = 1; + uint64 endId = 2; - // The following is used for read only transactions. - uint64 read_only = 5; + // The following is used for read only transactions. + uint64 read_only = 5; } message RemoveNodeRequest { - uint64 nodeId = 1; - uint32 groupId = 2; + uint64 nodeId = 1; + uint32 groupId = 2; } message MoveTabletRequest { - uint64 namespace = 1; - string tablet = 2; - uint32 dstGroup = 3; + uint64 namespace = 1; + string tablet = 2; + uint32 dstGroup = 3; } message ApplyLicenseRequest { - bytes license = 1; + bytes license = 1; } message SnapshotMeta { - uint64 client_ts = 1; - uint32 group_id = 2; + uint64 client_ts = 1; + uint32 group_id = 2; } // Status describes a general status response. // code: 0 = success, 0 != failure. message Status { - int32 code = 1; - string msg = 2; + int32 code = 1; + string msg = 2; } -// Backups record all data from since_ts to read_ts. -// With incremental backups, the read_ts of the first backup becomes -// the since_ts of the second backup. +// Backups record all data from since_ts to read_ts. With incremental backups, +// the read_ts of the first backup becomes the since_ts of the second backup. // Incremental backups can be disabled using the force_full field. message BackupRequest { - uint64 read_ts = 1; - uint64 since_ts = 2; - uint32 group_id = 3; - string unix_ts = 4; - string destination = 5; - string access_key = 6; - string secret_key = 7; - string session_token = 8; + uint64 read_ts = 1; + uint64 since_ts = 2; + uint32 group_id = 3; + string unix_ts = 4; + string destination = 5; + string access_key = 6; + string secret_key = 7; + string session_token = 8; - // True if no credentials should be used to access the S3 or minio bucket. - // For example, when using a bucket with a public policy. - bool anonymous = 9; + // True if no credentials should be used to access the S3 or minio bucket. + // For example, when using a bucket with a public policy. + bool anonymous = 9; - // The predicates to backup. All other predicates present in the group (e.g - // stale data from a predicate move) will be ignored. - repeated string predicates = 10; + // The predicates to backup. All other predicates present in the group (e.g + // stale data from a predicate move) will be ignored. + repeated string predicates = 10; - bool force_full = 11; + bool force_full = 11; } message BackupResponse { - repeated DropOperation drop_operations = 1; + repeated DropOperation drop_operations = 1; } message DropOperation { - enum DropOp { - ALL = 0; - DATA = 1; - ATTR = 2; - NS = 3; - } - DropOp drop_op = 1; - // When drop_op is ATTR, drop_value will be the name of the ATTR; empty otherwise. - string drop_value = 2; + enum DropOp { + ALL = 0; + DATA = 1; + ATTR = 2; + NS = 3; + } + DropOp drop_op = 1; + // When drop_op is ATTR, drop_value will be the name of the ATTR; empty + // otherwise. + string drop_value = 2; } message ExportRequest { - uint32 group_id = 1; // Group id to back up. - uint64 read_ts = 2; - int64 unix_ts = 3; - string format = 4; + uint32 group_id = 1; // Group id to back up. + uint64 read_ts = 2; + int64 unix_ts = 3; + string format = 4; - string destination = 5; + string destination = 5; - // These credentials are used to access the S3 or minio bucket. - string access_key = 6; - string secret_key = 7; - string session_token = 8; - bool anonymous = 9; + // These credentials are used to access the S3 or minio bucket. + string access_key = 6; + string secret_key = 7; + string session_token = 8; + bool anonymous = 9; - uint64 namespace = 10; + uint64 namespace = 10; } message ExportResponse { - // 0 indicates a success, and a non-zero code indicates failure - int32 code = 1; - string msg = 2; - repeated string files = 3; + // 0 indicates a success, and a non-zero code indicates failure + int32 code = 1; + string msg = 2; + repeated string files = 3; } // A key stored in the format used for writing backups. @@ -704,39 +721,39 @@ message BackupKey { uint64 start_uid = 4; string term = 5; uint32 count = 6; - uint64 namespace = 7; + uint64 namespace = 7; } // A posting list stored in the format used for writing backups. message BackupPostingList { - repeated uint64 uids = 1; - repeated Posting postings = 2; - uint64 commit_ts = 3; + repeated uint64 uids = 1; + repeated Posting postings = 2; + uint64 commit_ts = 3; repeated uint64 splits = 4; - bytes uid_bytes = 5; + bytes uid_bytes = 5; } message UpdateGraphQLSchemaRequest { - uint64 start_ts = 1; - string graphql_schema = 2; - repeated SchemaUpdate dgraph_preds = 3; - repeated TypeUpdate dgraph_types = 4; + uint64 start_ts = 1; + string graphql_schema = 2; + repeated SchemaUpdate dgraph_preds = 3; + repeated TypeUpdate dgraph_types = 4; } message UpdateGraphQLSchemaResponse { - uint64 uid = 1; + uint64 uid = 1; } // BulkMeta stores metadata from the map phase of the bulk loader. message BulkMeta { - int64 edge_count = 1; - map schema_map = 2; - repeated TypeUpdate types = 3; + int64 edge_count = 1; + map schema_map = 2; + repeated TypeUpdate types = 3; } message DeleteNsRequest { - uint32 group_id = 1; - uint64 namespace = 2; + uint32 group_id = 1; + uint64 namespace = 2; } -// vim: noexpandtab sw=2 ts=2 +// vim: expandtab sw=2 ts=2 diff --git a/protos/pb/pb.pb.go b/protos/pb/pb.pb.go index 467e0275e50..eb1d1ac08d8 100644 --- a/protos/pb/pb.pb.go +++ b/protos/pb/pb.pb.go @@ -91,11 +91,14 @@ func (Mutations_DropOp) EnumDescriptor() ([]byte, []int) { type Metadata_HintType int32 const ( - // DEFAULT means no hint is provided and Dgraph will follow the default behavior. + // DEFAULT means no hint is provided and Dgraph will follow the default + // behavior. Metadata_DEFAULT Metadata_HintType = 0 - // SINGLE signals that the predicate should be created as a single type (e.g string, uid). + // SINGLE signals that the predicate should be created as a single type (e.g + // string, uid). Metadata_SINGLE Metadata_HintType = 1 - // LIST signals that the predicate should be created as a list (e.g [string], [uid]). + // LIST signals that the predicate should be created as a list (e.g + // [string], [uid]). Metadata_LIST Metadata_HintType = 2 ) @@ -504,15 +507,22 @@ type Query struct { // Exactly one of uids and terms is populated. UidList *List `protobuf:"bytes,5,opt,name=uid_list,json=uidList,proto3" json:"uid_list,omitempty"` // Function to generate or filter UIDs. - SrcFunc *SrcFunction `protobuf:"bytes,6,opt,name=src_func,json=srcFunc,proto3" json:"src_func,omitempty"` - Reverse bool `protobuf:"varint,7,opt,name=reverse,proto3" json:"reverse,omitempty"` - FacetParam *FacetParams `protobuf:"bytes,8,opt,name=facet_param,json=facetParam,proto3" json:"facet_param,omitempty"` - FacetsFilter *FilterTree `protobuf:"bytes,9,opt,name=facets_filter,json=facetsFilter,proto3" json:"facets_filter,omitempty"` - ExpandAll bool `protobuf:"varint,10,opt,name=expand_all,json=expandAll,proto3" json:"expand_all,omitempty"` - ReadTs uint64 `protobuf:"varint,13,opt,name=read_ts,json=readTs,proto3" json:"read_ts,omitempty"` - Cache int32 `protobuf:"varint,14,opt,name=cache,proto3" json:"cache,omitempty"` - First int32 `protobuf:"varint,15,opt,name=first,proto3" json:"first,omitempty"` + SrcFunc *SrcFunction `protobuf:"bytes,6,opt,name=src_func,json=srcFunc,proto3" json:"src_func,omitempty"` + // Whether this is a reverse edge. + Reverse bool `protobuf:"varint,7,opt,name=reverse,proto3" json:"reverse,omitempty"` + // Which facets to fetch. + FacetParam *FacetParams `protobuf:"bytes,8,opt,name=facet_param,json=facetParam,proto3" json:"facet_param,omitempty"` + // Filtering on facets: has Op (and/or/not) tree. + FacetsFilter *FilterTree `protobuf:"bytes,9,opt,name=facets_filter,json=facetsFilter,proto3" json:"facets_filter,omitempty"` + // Expand all language variants. + ExpandAll bool `protobuf:"varint,10,opt,name=expand_all,json=expandAll,proto3" json:"expand_all,omitempty"` + ReadTs uint64 `protobuf:"varint,13,opt,name=read_ts,json=readTs,proto3" json:"read_ts,omitempty"` + Cache int32 `protobuf:"varint,14,opt,name=cache,proto3" json:"cache,omitempty"` + // Used to limit the number of result. Typically, the count is value of first // field. Now, It's been used only for has query. + First int32 `protobuf:"varint,15,opt,name=first,proto3" json:"first,omitempty"` + // Offset helps in fetching lesser results for the has query when there is no + // filter and order. Offset int32 `protobuf:"varint,16,opt,name=offset,proto3" json:"offset,omitempty"` } @@ -1084,8 +1094,8 @@ func (m *RaftContext) GetIsLearner() bool { } // Member stores information about RAFT group member for a single RAFT node. -// Note that each server can be serving multiple RAFT groups. Each group would have -// one RAFT node per server serving that group. +// Note that each server can be serving multiple RAFT groups. Each group would +// have one RAFT node per server serving that group. type Member struct { Id uint64 `protobuf:"fixed64,1,opt,name=id,proto3" json:"id,omitempty"` GroupId uint32 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"groupId,omitempty"` @@ -1471,9 +1481,9 @@ func (m *ZeroProposal) GetDeleteNs() *DeleteNsRequest { return nil } -// MembershipState is used to pack together the current membership state of all the nodes -// in the caller server; and the membership updates recorded by the callee server since -// the provided lastUpdate. +// MembershipState is used to pack together the current membership state of all +// the nodes in the caller server; and the membership updates recorded by the +// callee server since the provided lastUpdate. type MembershipState struct { Counter uint64 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"` Groups map[uint32]*Group `protobuf:"bytes,2,rep,name=groups,proto3" json:"groups,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -1591,9 +1601,10 @@ func (m *MembershipState) GetLicense() *License { } type ConnectionState struct { - Member *Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` - State *MembershipState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` - MaxPending uint64 `protobuf:"varint,3,opt,name=max_pending,json=maxPending,proto3" json:"max_pending,omitempty"` + Member *Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` + State *MembershipState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + // Used to determine the timstamp for reading after bulk load. + MaxPending uint64 `protobuf:"varint,3,opt,name=max_pending,json=maxPending,proto3" json:"max_pending,omitempty"` } func (m *ConnectionState) Reset() { *m = ConnectionState{} } @@ -1775,14 +1786,17 @@ func (m *HealthInfo) GetMaxAssigned() uint64 { } type Tablet struct { - GroupId uint32 `protobuf:"varint,1,opt,name=group_id,json=groupId,proto3" json:"groupId,omitempty"` - Predicate string `protobuf:"bytes,2,opt,name=predicate,proto3" json:"predicate,omitempty"` - Force bool `protobuf:"varint,3,opt,name=force,proto3" json:"force,omitempty"` - OnDiskBytes int64 `protobuf:"varint,7,opt,name=on_disk_bytes,json=onDiskBytes,proto3" json:"on_disk_bytes,omitempty"` - Remove bool `protobuf:"varint,8,opt,name=remove,proto3" json:"remove,omitempty"` - ReadOnly bool `protobuf:"varint,9,opt,name=read_only,json=readOnly,proto3" json:"readOnly,omitempty"` - MoveTs uint64 `protobuf:"varint,10,opt,name=move_ts,json=moveTs,proto3" json:"moveTs,omitempty"` - UncompressedBytes int64 `protobuf:"varint,11,opt,name=uncompressed_bytes,json=uncompressedBytes,proto3" json:"uncompressed_bytes,omitempty"` + // Served by which group. + GroupId uint32 `protobuf:"varint,1,opt,name=group_id,json=groupId,proto3" json:"groupId,omitempty"` + Predicate string `protobuf:"bytes,2,opt,name=predicate,proto3" json:"predicate,omitempty"` + Force bool `protobuf:"varint,3,opt,name=force,proto3" json:"force,omitempty"` + OnDiskBytes int64 `protobuf:"varint,7,opt,name=on_disk_bytes,json=onDiskBytes,proto3" json:"on_disk_bytes,omitempty"` + Remove bool `protobuf:"varint,8,opt,name=remove,proto3" json:"remove,omitempty"` + // If true, do not ask zero to serve any tablets. + ReadOnly bool `protobuf:"varint,9,opt,name=read_only,json=readOnly,proto3" json:"readOnly,omitempty"` + MoveTs uint64 `protobuf:"varint,10,opt,name=move_ts,json=moveTs,proto3" json:"moveTs,omitempty"` + // Estimated uncompressed size of tablet in bytes + UncompressedBytes int64 `protobuf:"varint,11,opt,name=uncompressed_bytes,json=uncompressedBytes,proto3" json:"uncompressed_bytes,omitempty"` } func (m *Tablet) Reset() { *m = Tablet{} } @@ -2450,13 +2464,15 @@ func (m *RestoreRequest) GetBackupNum() uint64 { } type Proposal struct { - Mutations *Mutations `protobuf:"bytes,2,opt,name=mutations,proto3" json:"mutations,omitempty"` - Kv []*pb.KV `protobuf:"bytes,4,rep,name=kv,proto3" json:"kv,omitempty"` - State *MembershipState `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` - CleanPredicate string `protobuf:"bytes,6,opt,name=clean_predicate,json=cleanPredicate,proto3" json:"clean_predicate,omitempty"` - Delta *OracleDelta `protobuf:"bytes,8,opt,name=delta,proto3" json:"delta,omitempty"` - Snapshot *Snapshot `protobuf:"bytes,9,opt,name=snapshot,proto3" json:"snapshot,omitempty"` - Index uint64 `protobuf:"varint,10,opt,name=index,proto3" json:"index,omitempty"` + Mutations *Mutations `protobuf:"bytes,2,opt,name=mutations,proto3" json:"mutations,omitempty"` + Kv []*pb.KV `protobuf:"bytes,4,rep,name=kv,proto3" json:"kv,omitempty"` + State *MembershipState `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` + // Delete the predicate which was moved to other group. + CleanPredicate string `protobuf:"bytes,6,opt,name=clean_predicate,json=cleanPredicate,proto3" json:"clean_predicate,omitempty"` + Delta *OracleDelta `protobuf:"bytes,8,opt,name=delta,proto3" json:"delta,omitempty"` + Snapshot *Snapshot `protobuf:"bytes,9,opt,name=snapshot,proto3" json:"snapshot,omitempty"` + Index uint64 `protobuf:"varint,10,opt,name=index,proto3" json:"index,omitempty"` + // Block an operation until membership reaches this checksum. ExpectedChecksum uint64 `protobuf:"varint,11,opt,name=expected_checksum,json=expectedChecksum,proto3" json:"expected_checksum,omitempty"` Restore *RestoreRequest `protobuf:"bytes,12,opt,name=restore,proto3" json:"restore,omitempty"` CdcState *CDCState `protobuf:"bytes,13,opt,name=cdc_state,json=cdcState,proto3" json:"cdc_state,omitempty"` @@ -2635,11 +2651,12 @@ func (m *CDCState) GetSentTs() uint64 { type KVS struct { Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` - // done used to indicate if the stream of KVS is over. + // Done used to indicate if the stream of KVS is over. Done bool `protobuf:"varint,2,opt,name=done,proto3" json:"done,omitempty"` - // predicates is the list of predicates known by the leader at the time of the snapshot. + // Predicates is the list of predicates known by the leader at the time of the + // snapshot. Predicates []string `protobuf:"bytes,3,rep,name=predicates,proto3" json:"predicates,omitempty"` - // types is the list of types known by the leader at the time of the snapshot. + // Types is the list of types known by the leader at the time of the snapshot. Types []string `protobuf:"bytes,4,rep,name=types,proto3" json:"types,omitempty"` } @@ -3199,7 +3216,7 @@ func (m *FilterTree) GetFunc() *Function { type SchemaRequest struct { GroupId uint32 `protobuf:"varint,1,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` Predicates []string `protobuf:"bytes,2,rep,name=predicates,proto3" json:"predicates,omitempty"` - // fields can be on of type, index, reverse or tokenizer + // Fields can be on of type, index, reverse or tokenizer. Fields []string `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"` Types []string `protobuf:"bytes,4,rep,name=types,proto3" json:"types,omitempty"` } @@ -3438,8 +3455,8 @@ type SchemaUpdate struct { // Fields required for type system. NonNullable bool `protobuf:"varint,10,opt,name=non_nullable,json=nonNullable,proto3" json:"non_nullable,omitempty"` NonNullableList bool `protobuf:"varint,11,opt,name=non_nullable_list,json=nonNullableList,proto3" json:"non_nullable_list,omitempty"` - // If value_type is OBJECT, then this represents an object type with a - // custom name. This field stores said name. + // If value_type is OBJECT, then this represents an object type with a custom + // name. This field stores said name. ObjectTypeName string `protobuf:"bytes,12,opt,name=object_type_name,json=objectTypeName,proto3" json:"object_type_name,omitempty"` NoConflict bool `protobuf:"varint,13,opt,name=no_conflict,json=noConflict,proto3" json:"no_conflict,omitempty"` } @@ -4480,9 +4497,8 @@ func (m *Status) GetMsg() string { return "" } -// Backups record all data from since_ts to read_ts. -// With incremental backups, the read_ts of the first backup becomes -// the since_ts of the second backup. +// Backups record all data from since_ts to read_ts. With incremental backups, +// the read_ts of the first backup becomes the since_ts of the second backup. // Incremental backups can be disabled using the force_full field. type BackupRequest struct { ReadTs uint64 `protobuf:"varint,1,opt,name=read_ts,json=readTs,proto3" json:"read_ts,omitempty"` @@ -4658,7 +4674,8 @@ func (m *BackupResponse) GetDropOperations() []*DropOperation { type DropOperation struct { DropOp DropOperation_DropOp `protobuf:"varint,1,opt,name=drop_op,json=dropOp,proto3,enum=pb.DropOperation_DropOp" json:"drop_op,omitempty"` - // When drop_op is ATTR, drop_value will be the name of the ATTR; empty otherwise. + // When drop_op is ATTR, drop_value will be the name of the ATTR; empty + // otherwise. DropValue string `protobuf:"bytes,2,opt,name=drop_value,json=dropValue,proto3" json:"drop_value,omitempty"` }