diff --git a/docs/generated/sql/functions.md b/docs/generated/sql/functions.md index 6001ea647ce8..58c77fd1e8ca 100644 --- a/docs/generated/sql/functions.md +++ b/docs/generated/sql/functions.md @@ -1022,6 +1022,8 @@ SELECT * FROM crdb_internal.check_consistency(true, ‘\x02’, ‘\x04’)

crdb_internal.force_retry(val: interval) → int

This function is used only by CockroachDB’s developers for testing purposes.

+crdb_internal.is_admin() → bool

Retrieves the current user’s admin status.

+
crdb_internal.json_num_index_entries(val: jsonb) → int

This function is used only by CockroachDB’s developers for testing purposes.

crdb_internal.lease_holder(key: bytes) → int

This function is used to fetch the leaseholder corresponding to a request key

diff --git a/pkg/ccl/logictestccl/testdata/logic_test/role b/pkg/ccl/logictestccl/testdata/logic_test/role index cd4fee6cec5f..b7de17f4e21c 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/role +++ b/pkg/ccl/logictestccl/testdata/logic_test/role @@ -219,6 +219,12 @@ user root statement ok GRANT admin TO testuser +# Verify that is_admin reports the right value. +query B +SELECT crdb_internal.is_admin() +---- +true + # Dropping users/roles deletes all their memberships. query TTB colnames SELECT * FROM system.role_members @@ -735,3 +741,5 @@ REVOKE public FROM testuser statement error user or role public does not exist REVOKE admin FROM public + + diff --git a/pkg/server/admin.go b/pkg/server/admin.go index 39110e40172b..3b20789f7c0a 100644 --- a/pkg/server/admin.go +++ b/pkg/server/admin.go @@ -46,8 +46,8 @@ import ( "github.com/cockroachdb/cockroach/pkg/util/mon" "github.com/cockroachdb/cockroach/pkg/util/protoutil" "github.com/cockroachdb/cockroach/pkg/util/uuid" + "github.com/cockroachdb/errors" gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/pkg/errors" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -116,15 +116,6 @@ func (s *adminServer) RegisterGateway( return serverpb.RegisterAdminHandler(ctx, mux, conn) } -// getUserProto will return the authenticated user. For now, this is just a stub until we -// figure out our authentication mechanism. -// -// TODO(cdo): Make this work when we have an authentication scheme for the -// API. -func (s *adminServer) getUser(_ protoutil.Message) string { - return security.RootUser -} - // serverError logs the provided error and returns an error that should be returned by // the RPC endpoint method. func (s *adminServer) serverError(err error) error { @@ -189,8 +180,14 @@ func (s *adminServer) Databases( ctx context.Context, req *serverpb.DatabasesRequest, ) (*serverpb.DatabasesResponse, error) { ctx = s.server.AnnotateCtx(ctx) + + sessionUser, err := userFromContext(ctx) + if err != nil { + return nil, err + } + rows, _ /* cols */, err := s.server.internalExecutor.QueryWithUser( - ctx, "admi-show-db", nil /* txn */, s.getUser(req), "SHOW DATABASES", + ctx, "admin-show-dbs", nil /* txn */, sessionUser, "SHOW DATABASES", ) if err != nil { return nil, s.serverError(err) @@ -215,7 +212,10 @@ func (s *adminServer) DatabaseDetails( ctx context.Context, req *serverpb.DatabaseDetailsRequest, ) (*serverpb.DatabaseDetailsResponse, error) { ctx = s.server.AnnotateCtx(ctx) - userName := s.getUser(req) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } escDBName := tree.NameStringP(&req.Database) // Placeholders don't work with SHOW statements, so we need to manually @@ -330,7 +330,10 @@ func (s *adminServer) TableDetails( ctx context.Context, req *serverpb.TableDetailsRequest, ) (*serverpb.TableDetailsResponse, error) { ctx = s.server.AnnotateCtx(ctx) - userName := s.getUser(req) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } escDBName := tree.NameStringP(&req.Database) // TODO(cdo): Use real placeholders for the table and database names when we've extended our SQL @@ -581,9 +584,16 @@ func generateTableSpan(tableID sqlbase.ID) roachpb.Span { func (s *adminServer) TableStats( ctx context.Context, req *serverpb.TableStatsRequest, ) (*serverpb.TableStatsResponse, error) { + // TODO(someone): perform authorization based on the requesting user's + // SELECT privilege over the requested table. + userName, err := s.requireAdminUser(ctx) + if err != nil { + return nil, err + } + // Get table span. path, err := s.queryDescriptorIDPath( - ctx, s.getUser(req), []string{req.Database, req.Table}, + ctx, userName, []string{req.Database, req.Table}, ) if err != nil { return nil, s.serverError(err) @@ -599,6 +609,10 @@ func (s *adminServer) TableStats( func (s *adminServer) NonTableStats( ctx context.Context, req *serverpb.NonTableStatsRequest, ) (*serverpb.NonTableStatsResponse, error) { + if _, err := s.requireAdminUser(ctx); err != nil { + return nil, err + } + timeSeriesStats, err := s.statsForSpan(ctx, roachpb.Span{ Key: keys.TimeseriesPrefix, EndKey: keys.TimeseriesPrefix.PrefixEnd(), @@ -779,9 +793,13 @@ func (s *adminServer) Users( ctx context.Context, req *serverpb.UsersRequest, ) (*serverpb.UsersResponse, error) { ctx = s.server.AnnotateCtx(ctx) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } query := `SELECT username FROM system.users WHERE "isRole" = false` rows, _ /* cols */, err := s.server.internalExecutor.QueryWithUser( - ctx, "admin-users", nil /* txn */, s.getUser(req), query, + ctx, "admin-users", nil /* txn */, userName, query, ) if err != nil { return nil, s.serverError(err) @@ -804,6 +822,16 @@ func (s *adminServer) Events( ) (*serverpb.EventsResponse, error) { ctx = s.server.AnnotateCtx(ctx) + userName, isAdmin, err := s.getUserAndRole(ctx) + if err != nil { + return nil, err + } + redactEvents := false + if isAdmin { + // We obey the redacted bit only if the user is admin. + redactEvents = !req.UnredactedEvents + } + limit := req.Limit if limit == 0 { limit = defaultAPIEventLimit @@ -828,7 +856,7 @@ func (s *adminServer) Events( return nil, s.serverErrors(q.Errors()) } rows, cols, err := s.server.internalExecutor.QueryWithUser( - ctx, "admin-events", nil /* txn */, s.getUser(req), q.String(), q.QueryArguments()...) + ctx, "admin-events", nil /* txn */, userName, q.String(), q.QueryArguments()...) if err != nil { return nil, s.serverError(err) } @@ -856,10 +884,9 @@ func (s *adminServer) Events( return nil, err } if event.EventType == string(sql.EventLogSetClusterSetting) { - - // TODO: `if s.getUser(req) != security.RootUser` when we have auth. - - event.Info = redactSettingsChange(event.Info) + if redactEvents { + event.Info = redactSettingsChange(event.Info) + } } if err := scanner.ScanIndex(row, 5, &event.UniqueID); err != nil { return nil, err @@ -890,6 +917,12 @@ func (s *adminServer) RangeLog( ) (*serverpb.RangeLogResponse, error) { ctx = s.server.AnnotateCtx(ctx) + // Range keys, even when pretty-printed, contain PII. + userName, err := s.requireAdminUser(ctx) + if err != nil { + return nil, err + } + limit := req.Limit if limit == 0 { limit = defaultAPIEventLimit @@ -914,7 +947,7 @@ func (s *adminServer) RangeLog( } rows, cols, err := s.server.internalExecutor.QueryWithUser( ctx, "admin-range-log", - nil /* txn */, s.getUser(req), q.String(), q.QueryArguments()..., + nil /* txn */, userName, q.String(), q.QueryArguments()..., ) if err != nil { return nil, s.serverError(err) @@ -1062,6 +1095,11 @@ func (s *adminServer) SetUIData( ) (*serverpb.SetUIDataResponse, error) { ctx = s.server.AnnotateCtx(ctx) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } + if len(req.KeyValues) == 0 { return nil, status.Errorf(codes.InvalidArgument, "KeyValues cannot be empty") } @@ -1071,7 +1109,7 @@ func (s *adminServer) SetUIData( // avoid long-running transactions and possible deadlocks. query := `UPSERT INTO system.ui (key, value, "lastUpdated") VALUES ($1, $2, now())` rowsAffected, err := s.server.internalExecutor.ExecWithUser( - ctx, "admin-set-ui-data", nil /* txn */, s.getUser(req), query, key, val) + ctx, "admin-set-ui-data", nil /* txn */, userName, query, key, val) if err != nil { return nil, s.serverError(err) } @@ -1093,11 +1131,17 @@ func (s *adminServer) GetUIData( ctx context.Context, req *serverpb.GetUIDataRequest, ) (*serverpb.GetUIDataResponse, error) { ctx = s.server.AnnotateCtx(ctx) + + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } + if len(req.Keys) == 0 { return nil, status.Errorf(codes.InvalidArgument, "keys cannot be empty") } - resp, err := s.getUIData(ctx, s.getUser(req), req.Keys) + resp, err := s.getUIData(ctx, userName, req.Keys) if err != nil { return nil, s.serverError(err) } @@ -1186,6 +1230,11 @@ func (s *adminServer) Jobs( ) (*serverpb.JobsResponse, error) { ctx = s.server.AnnotateCtx(ctx) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } + q := makeSQLQuery() q.Append(` SELECT job_id, job_type, description, statement, user_name, descriptor_ids, status, @@ -1208,7 +1257,7 @@ func (s *adminServer) Jobs( q.Append(" LIMIT $", tree.DInt(req.Limit)) } rows, cols, err := s.server.internalExecutor.QueryWithUser( - ctx, "admin-jobs", nil /* txn */, s.getUser(req), q.String(), q.QueryArguments()..., + ctx, "admin-jobs", nil /* txn */, userName, q.String(), q.QueryArguments()..., ) if err != nil { return nil, s.serverError(err) @@ -1268,10 +1317,15 @@ func (s *adminServer) Locations( ) (*serverpb.LocationsResponse, error) { ctx = s.server.AnnotateCtx(ctx) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } + q := makeSQLQuery() q.Append(`SELECT "localityKey", "localityValue", latitude, longitude FROM system.locations`) rows, cols, err := s.server.internalExecutor.QueryWithUser( - ctx, "admin-locations", nil /* txn */, s.getUser(req), q.String(), + ctx, "admin-locations", nil /* txn */, userName, q.String(), ) if err != nil { return nil, s.serverError(err) @@ -1306,6 +1360,11 @@ func (s *adminServer) QueryPlan( ) (*serverpb.QueryPlanResponse, error) { ctx = s.server.AnnotateCtx(ctx) + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } + // As long as there's only one query provided it's safe to construct the // explain query. stmts, err := parser.Parse(req.Query) @@ -1320,7 +1379,7 @@ func (s *adminServer) QueryPlan( "SELECT json FROM [EXPLAIN (DISTSQL) %s]", strings.Trim(req.Query, ";")) rows, _ /* cols */, err := s.server.internalExecutor.QueryWithUser( - ctx, "admin-query-plan", nil /* txn */, s.getUser(req), explain, + ctx, "admin-query-plan", nil /* txn */, userName, explain, ) if err != nil { return nil, s.serverError(err) @@ -1502,18 +1561,26 @@ func (s *adminServer) Decommission( func (s *adminServer) DataDistribution( ctx context.Context, req *serverpb.DataDistributionRequest, ) (*serverpb.DataDistributionResponse, error) { + if _, err := s.requireAdminUser(ctx); err != nil { + return nil, err + } + resp := &serverpb.DataDistributionResponse{ DatabaseInfo: make(map[string]serverpb.DataDistributionResponse_DatabaseInfo), ZoneConfigs: make(map[string]serverpb.DataDistributionResponse_ZoneConfig), } + userName, err := userFromContext(ctx) + if err != nil { + return nil, err + } + // Get ids and names for databases and tables. // Set up this structure in the response. // This relies on crdb_internal.tables returning data even for newly added tables // and deleted tables (as opposed to e.g. information_schema) because we are interested // in the data for all ranges, not just ranges for visible tables. - userName := s.getUser(req) tablesQuery := `SELECT name, table_id, database_name, drop_time FROM "".crdb_internal.tables WHERE schema_name = 'public'` rows1, _ /* cols */, err := s.server.internalExecutor.QueryWithUser( ctx, "admin-replica-matrix", nil /* txn */, userName, tablesQuery, @@ -1661,6 +1728,10 @@ func (s *adminServer) DataDistribution( func (s *adminServer) EnqueueRange( ctx context.Context, req *serverpb.EnqueueRangeRequest, ) (*serverpb.EnqueueRangeResponse, error) { + if _, err := s.requireAdminUser(ctx); err != nil { + return nil, err + } + if !debug.GatewayRemoteAllowed(ctx, s.server.ClusterSettings()) { return nil, remoteDebuggingErr } @@ -2134,3 +2205,48 @@ func (s *adminServer) dialNode( } return serverpb.NewAdminClient(conn), nil } + +func (s *adminServer) requireAdminUser(ctx context.Context) (userName string, err error) { + userName, isAdmin, err := s.getUserAndRole(ctx) + if err != nil { + return "", err + } + if !isAdmin { + return "", errInsufficientPrivilege + } + return userName, nil +} + +func (s *adminServer) getUserAndRole( + ctx context.Context, +) (userName string, isAdmin bool, err error) { + userName, err = userFromContext(ctx) + if err != nil { + return "", false, err + } + isAdmin, err = s.hasAdminRole(ctx, userName) + return userName, isAdmin, err +} + +func (s *adminServer) hasAdminRole(ctx context.Context, sessionUser string) (bool, error) { + if sessionUser == security.RootUser { + // Shortcut. + return true, nil + } + rows, cols, err := s.server.internalExecutor.QueryWithUser( + ctx, "check-is-admin", + nil /* txn */, sessionUser, "SELECT crdb_internal.is_admin()") + if err != nil { + return false, err + } + if len(rows) != 1 || len(cols) != 1 { + return false, errors.AssertionFailedf("hasAdminRole: expected 1 row, got %d", len(rows)) + } + dbDatum, ok := tree.AsDBool(rows[0][0]) + if !ok { + return false, errors.AssertionFailedf("hasAdminRole: expected bool, got %T", rows[0][0]) + } + return bool(dbDatum), nil +} + +var errInsufficientPrivilege = errors.New("this operation requires admin privilege") diff --git a/pkg/server/admin_cluster_test.go b/pkg/server/admin_cluster_test.go index 82042109421e..5c78e7a84f61 100644 --- a/pkg/server/admin_cluster_test.go +++ b/pkg/server/admin_cluster_test.go @@ -45,7 +45,7 @@ func TestAdminAPITableStats(t *testing.T) { // Create clients (SQL, HTTP) connected to server 0. db := tc.ServerConn(0) - client, err := server0.GetAuthenticatedHTTPClient() + client, err := server0.GetAdminAuthenticatedHTTPClient() if err != nil { t.Fatal(err) } diff --git a/pkg/server/admin_test.go b/pkg/server/admin_test.go index 76db6981b767..6e688b39ee91 100644 --- a/pkg/server/admin_test.go +++ b/pkg/server/admin_test.go @@ -71,7 +71,7 @@ func postAdminJSONProto( // getText fetches the HTTP response body as text in the form of a // byte slice from the specified URL. func getText(ts serverutils.TestServerInterface, url string) ([]byte, error) { - httpClient, err := ts.GetAuthenticatedHTTPClient() + httpClient, err := ts.GetAdminAuthenticatedHTTPClient() if err != nil { return nil, err } @@ -747,6 +747,7 @@ VALUES ('adminUser', 'abc'), ('bob', 'xyz')` expResult := serverpb.UsersResponse{ Users: []serverpb.UsersResponse_User{ {Username: "adminUser"}, + {Username: "authentic_user"}, {Username: "bob"}, {Username: "root"}, }, @@ -783,22 +784,26 @@ func TestAdminAPIEvents(t *testing.T) { const allEvents = "" type testcase struct { - eventType sql.EventLogType - hasLimit bool - limit int - expCount int + eventType sql.EventLogType + hasLimit bool + limit int + unredacted bool + expCount int } testcases := []testcase{ - {sql.EventLogNodeJoin, false, 0, 1}, - {sql.EventLogNodeRestart, false, 0, 0}, - {sql.EventLogDropDatabase, false, 0, 0}, - {sql.EventLogCreateDatabase, false, 0, 3}, - {sql.EventLogDropTable, false, 0, 2}, - {sql.EventLogCreateTable, false, 0, 3}, - {sql.EventLogSetClusterSetting, false, 0, 4}, - {sql.EventLogCreateTable, true, 0, 3}, - {sql.EventLogCreateTable, true, -1, 3}, - {sql.EventLogCreateTable, true, 2, 2}, + {sql.EventLogNodeJoin, false, 0, false, 1}, + {sql.EventLogNodeRestart, false, 0, false, 0}, + {sql.EventLogDropDatabase, false, 0, false, 0}, + {sql.EventLogCreateDatabase, false, 0, false, 3}, + {sql.EventLogDropTable, false, 0, false, 2}, + {sql.EventLogCreateTable, false, 0, false, 3}, + {sql.EventLogSetClusterSetting, false, 0, false, 4}, + // We use limit=true with no limit here because otherwise the + // expCount will mess up the expected total count below. + {sql.EventLogSetClusterSetting, true, 0, true, 4}, + {sql.EventLogCreateTable, true, 0, false, 3}, + {sql.EventLogCreateTable, true, -1, false, 3}, + {sql.EventLogCreateTable, true, 2, false, 2}, } minTotalEvents := 0 for _, tc := range testcases { @@ -806,7 +811,7 @@ func TestAdminAPIEvents(t *testing.T) { minTotalEvents += tc.expCount } } - testcases = append(testcases, testcase{allEvents, false, 0, minTotalEvents}) + testcases = append(testcases, testcase{allEvents, false, 0, false, minTotalEvents}) for i, tc := range testcases { url := "events" @@ -815,6 +820,9 @@ func TestAdminAPIEvents(t *testing.T) { if tc.hasLimit { url += fmt.Sprintf("&limit=%d", tc.limit) } + if tc.unredacted { + url += fmt.Sprintf("&unredacted_events=true") + } } t.Run(url, func(t *testing.T) { @@ -862,8 +870,16 @@ func TestAdminAPIEvents(t *testing.T) { if len(e.Info) == 0 { t.Errorf("%d: missing/empty Info", i) } - if isSettingChange && strings.Contains(e.Info, "somestring") { - t.Errorf("%d: un-redacted 'somestring' in Info", i) + if isSettingChange && strings.Contains(e.Info, "cluster.organization") { + if tc.unredacted { + if !strings.Contains(e.Info, "somestring") { + t.Errorf("%d: require 'somestring' in Info", i) + } + } else { + if strings.Contains(e.Info, "somestring") { + t.Errorf("%d: un-redacted 'somestring' in Info", i) + } + } } if len(e.UniqueID) == 0 { t.Errorf("%d: missing/empty UniqueID", i) diff --git a/pkg/server/authentication_test.go b/pkg/server/authentication_test.go index b50c404d078f..1b4c1ce482fb 100644 --- a/pkg/server/authentication_test.go +++ b/pkg/server/authentication_test.go @@ -504,7 +504,7 @@ func TestLogout(t *testing.T) { ts := s.(*TestServer) // Log in. - authHTTPClient, cookie, err := ts.getAuthenticatedHTTPClientAndCookie() + authHTTPClient, cookie, err := ts.getAuthenticatedHTTPClientAndCookie(authenticatedUserName, true) if err != nil { t.Fatal("error opening HTTP client", err) } @@ -589,7 +589,7 @@ func TestAuthenticationMux(t *testing.T) { if err != nil { t.Fatal(err) } - authClient, err := tsrv.GetAuthenticatedHTTPClient() + authClient, err := tsrv.GetAdminAuthenticatedHTTPClient() if err != nil { t.Fatal(err) } diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index d931f78754b7..0291eb94da23 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -256,7 +256,7 @@ func TestAcceptEncoding(t *testing.T) { defer leaktest.AfterTest(t)() s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop(context.TODO()) - client, err := s.GetAuthenticatedHTTPClient() + client, err := s.GetAdminAuthenticatedHTTPClient() if err != nil { t.Fatal(err) } @@ -940,7 +940,7 @@ Binary built without web UI. defer s.Stopper().Stop(context.TODO()) tsrv := s.(*TestServer) - loggedInClient, err := tsrv.GetAuthenticatedHTTPClient() + loggedInClient, err := tsrv.GetAdminAuthenticatedHTTPClient() if err != nil { t.Fatal(err) } diff --git a/pkg/server/serverpb/admin.pb.go b/pkg/server/serverpb/admin.pb.go index 2737e8f76209..b8c3f78f4de9 100644 --- a/pkg/server/serverpb/admin.pb.go +++ b/pkg/server/serverpb/admin.pb.go @@ -73,7 +73,7 @@ func (x ZoneConfigurationLevel) String() string { return proto.EnumName(ZoneConfigurationLevel_name, int32(x)) } func (ZoneConfigurationLevel) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{0} } type DrainMode int32 @@ -100,7 +100,7 @@ func (x DrainMode) String() string { return proto.EnumName(DrainMode_name, int32(x)) } func (DrainMode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{1} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{1} } // DatabasesRequest requests a list of databases. @@ -111,7 +111,7 @@ func (m *DatabasesRequest) Reset() { *m = DatabasesRequest{} } func (m *DatabasesRequest) String() string { return proto.CompactTextString(m) } func (*DatabasesRequest) ProtoMessage() {} func (*DatabasesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{0} } func (m *DatabasesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -145,7 +145,7 @@ func (m *DatabasesResponse) Reset() { *m = DatabasesResponse{} } func (m *DatabasesResponse) String() string { return proto.CompactTextString(m) } func (*DatabasesResponse) ProtoMessage() {} func (*DatabasesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{1} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{1} } func (m *DatabasesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -181,7 +181,7 @@ func (m *DatabaseDetailsRequest) Reset() { *m = DatabaseDetailsRequest{} func (m *DatabaseDetailsRequest) String() string { return proto.CompactTextString(m) } func (*DatabaseDetailsRequest) ProtoMessage() {} func (*DatabaseDetailsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{2} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{2} } func (m *DatabaseDetailsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -228,7 +228,7 @@ func (m *DatabaseDetailsResponse) Reset() { *m = DatabaseDetailsResponse func (m *DatabaseDetailsResponse) String() string { return proto.CompactTextString(m) } func (*DatabaseDetailsResponse) ProtoMessage() {} func (*DatabaseDetailsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{3} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{3} } func (m *DatabaseDetailsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -264,7 +264,7 @@ func (m *DatabaseDetailsResponse_Grant) Reset() { *m = DatabaseDetailsRe func (m *DatabaseDetailsResponse_Grant) String() string { return proto.CompactTextString(m) } func (*DatabaseDetailsResponse_Grant) ProtoMessage() {} func (*DatabaseDetailsResponse_Grant) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{3, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{3, 0} } func (m *DatabaseDetailsResponse_Grant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -301,7 +301,7 @@ func (m *TableDetailsRequest) Reset() { *m = TableDetailsRequest{} } func (m *TableDetailsRequest) String() string { return proto.CompactTextString(m) } func (*TableDetailsRequest) ProtoMessage() {} func (*TableDetailsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{4} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{4} } func (m *TableDetailsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -358,7 +358,7 @@ func (m *TableDetailsResponse) Reset() { *m = TableDetailsResponse{} } func (m *TableDetailsResponse) String() string { return proto.CompactTextString(m) } func (*TableDetailsResponse) ProtoMessage() {} func (*TableDetailsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{5} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{5} } func (m *TableDetailsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -395,7 +395,7 @@ func (m *TableDetailsResponse_Grant) Reset() { *m = TableDetailsResponse func (m *TableDetailsResponse_Grant) String() string { return proto.CompactTextString(m) } func (*TableDetailsResponse_Grant) ProtoMessage() {} func (*TableDetailsResponse_Grant) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{5, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{5, 0} } func (m *TableDetailsResponse_Grant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -439,7 +439,7 @@ func (m *TableDetailsResponse_Column) Reset() { *m = TableDetailsRespons func (m *TableDetailsResponse_Column) String() string { return proto.CompactTextString(m) } func (*TableDetailsResponse_Column) ProtoMessage() {} func (*TableDetailsResponse_Column) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{5, 1} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{5, 1} } func (m *TableDetailsResponse_Column) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -485,7 +485,7 @@ func (m *TableDetailsResponse_Index) Reset() { *m = TableDetailsResponse func (m *TableDetailsResponse_Index) String() string { return proto.CompactTextString(m) } func (*TableDetailsResponse_Index) ProtoMessage() {} func (*TableDetailsResponse_Index) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{5, 2} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{5, 2} } func (m *TableDetailsResponse_Index) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -523,7 +523,7 @@ func (m *TableStatsRequest) Reset() { *m = TableStatsRequest{} } func (m *TableStatsRequest) String() string { return proto.CompactTextString(m) } func (*TableStatsRequest) ProtoMessage() {} func (*TableStatsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{6} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{6} } func (m *TableStatsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -577,7 +577,7 @@ func (m *TableStatsResponse) Reset() { *m = TableStatsResponse{} } func (m *TableStatsResponse) String() string { return proto.CompactTextString(m) } func (*TableStatsResponse) ProtoMessage() {} func (*TableStatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{7} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{7} } func (m *TableStatsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -615,7 +615,7 @@ func (m *TableStatsResponse_MissingNode) Reset() { *m = TableStatsRespon func (m *TableStatsResponse_MissingNode) String() string { return proto.CompactTextString(m) } func (*TableStatsResponse_MissingNode) ProtoMessage() {} func (*TableStatsResponse_MissingNode) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{7, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{7, 0} } func (m *TableStatsResponse_MissingNode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -649,7 +649,7 @@ func (m *NonTableStatsRequest) Reset() { *m = NonTableStatsRequest{} } func (m *NonTableStatsRequest) String() string { return proto.CompactTextString(m) } func (*NonTableStatsRequest) ProtoMessage() {} func (*NonTableStatsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{8} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{8} } func (m *NonTableStatsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -688,7 +688,7 @@ func (m *NonTableStatsResponse) Reset() { *m = NonTableStatsResponse{} } func (m *NonTableStatsResponse) String() string { return proto.CompactTextString(m) } func (*NonTableStatsResponse) ProtoMessage() {} func (*NonTableStatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{9} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{9} } func (m *NonTableStatsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -721,7 +721,7 @@ func (m *UsersRequest) Reset() { *m = UsersRequest{} } func (m *UsersRequest) String() string { return proto.CompactTextString(m) } func (*UsersRequest) ProtoMessage() {} func (*UsersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{10} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{10} } func (m *UsersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -756,7 +756,7 @@ func (m *UsersResponse) Reset() { *m = UsersResponse{} } func (m *UsersResponse) String() string { return proto.CompactTextString(m) } func (*UsersResponse) ProtoMessage() {} func (*UsersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{11} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{11} } func (m *UsersResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -790,7 +790,7 @@ func (m *UsersResponse_User) Reset() { *m = UsersResponse_User{} } func (m *UsersResponse_User) String() string { return proto.CompactTextString(m) } func (*UsersResponse_User) ProtoMessage() {} func (*UsersResponse_User) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{11, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{11, 0} } func (m *UsersResponse_User) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -825,13 +825,19 @@ type EventsRequest struct { // returned. When set to > 0, at most only that number of results are // returned. When set to < 0, an unlimited number of results are returned. Limit int32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + // unredacted_events indicates that the values in the events should + // not be redacted. The default is to redact, so that older versions + // of `cockroach zip` do not see un-redacted values by default. + // For good security, this field is only obeyed by the server after + // checking that the client of the RPC is an admin user. + UnredactedEvents bool `protobuf:"varint,4,opt,name=unredacted_events,json=unredactedEvents,proto3" json:"unredacted_events,omitempty"` } func (m *EventsRequest) Reset() { *m = EventsRequest{} } func (m *EventsRequest) String() string { return proto.CompactTextString(m) } func (*EventsRequest) ProtoMessage() {} func (*EventsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{12} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{12} } func (m *EventsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -866,7 +872,7 @@ func (m *EventsResponse) Reset() { *m = EventsResponse{} } func (m *EventsResponse) String() string { return proto.CompactTextString(m) } func (*EventsResponse) ProtoMessage() {} func (*EventsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{13} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{13} } func (m *EventsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -911,7 +917,7 @@ func (m *EventsResponse_Event) Reset() { *m = EventsResponse_Event{} } func (m *EventsResponse_Event) String() string { return proto.CompactTextString(m) } func (*EventsResponse_Event) ProtoMessage() {} func (*EventsResponse_Event) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{13, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{13, 0} } func (m *EventsResponse_Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -947,7 +953,7 @@ func (m *SetUIDataRequest) Reset() { *m = SetUIDataRequest{} } func (m *SetUIDataRequest) String() string { return proto.CompactTextString(m) } func (*SetUIDataRequest) ProtoMessage() {} func (*SetUIDataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{14} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{14} } func (m *SetUIDataRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -980,7 +986,7 @@ func (m *SetUIDataResponse) Reset() { *m = SetUIDataResponse{} } func (m *SetUIDataResponse) String() string { return proto.CompactTextString(m) } func (*SetUIDataResponse) ProtoMessage() {} func (*SetUIDataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{15} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{15} } func (m *SetUIDataResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1015,7 +1021,7 @@ func (m *GetUIDataRequest) Reset() { *m = GetUIDataRequest{} } func (m *GetUIDataRequest) String() string { return proto.CompactTextString(m) } func (*GetUIDataRequest) ProtoMessage() {} func (*GetUIDataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{16} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{16} } func (m *GetUIDataRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1052,7 +1058,7 @@ func (m *GetUIDataResponse) Reset() { *m = GetUIDataResponse{} } func (m *GetUIDataResponse) String() string { return proto.CompactTextString(m) } func (*GetUIDataResponse) ProtoMessage() {} func (*GetUIDataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{17} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{17} } func (m *GetUIDataResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1088,7 +1094,7 @@ func (m *GetUIDataResponse_Value) Reset() { *m = GetUIDataResponse_Value func (m *GetUIDataResponse_Value) String() string { return proto.CompactTextString(m) } func (*GetUIDataResponse_Value) ProtoMessage() {} func (*GetUIDataResponse_Value) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{17, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{17, 0} } func (m *GetUIDataResponse_Value) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1121,7 +1127,7 @@ func (m *ClusterRequest) Reset() { *m = ClusterRequest{} } func (m *ClusterRequest) String() string { return proto.CompactTextString(m) } func (*ClusterRequest) ProtoMessage() {} func (*ClusterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{18} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{18} } func (m *ClusterRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1160,7 +1166,7 @@ func (m *ClusterResponse) Reset() { *m = ClusterResponse{} } func (m *ClusterResponse) String() string { return proto.CompactTextString(m) } func (*ClusterResponse) ProtoMessage() {} func (*ClusterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{19} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{19} } func (m *ClusterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1204,7 +1210,7 @@ func (m *DrainRequest) Reset() { *m = DrainRequest{} } func (m *DrainRequest) String() string { return proto.CompactTextString(m) } func (*DrainRequest) ProtoMessage() {} func (*DrainRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{20} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{20} } func (m *DrainRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1239,7 +1245,7 @@ func (m *DrainResponse) Reset() { *m = DrainResponse{} } func (m *DrainResponse) String() string { return proto.CompactTextString(m) } func (*DrainResponse) ProtoMessage() {} func (*DrainResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{21} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{21} } func (m *DrainResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1274,7 +1280,7 @@ func (m *DecommissionStatusRequest) Reset() { *m = DecommissionStatusReq func (m *DecommissionStatusRequest) String() string { return proto.CompactTextString(m) } func (*DecommissionStatusRequest) ProtoMessage() {} func (*DecommissionStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{22} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{22} } func (m *DecommissionStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1312,7 +1318,7 @@ func (m *DecommissionRequest) Reset() { *m = DecommissionRequest{} } func (m *DecommissionRequest) String() string { return proto.CompactTextString(m) } func (*DecommissionRequest) ProtoMessage() {} func (*DecommissionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{23} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{23} } func (m *DecommissionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1347,7 +1353,7 @@ func (m *DecommissionStatusResponse) Reset() { *m = DecommissionStatusRe func (m *DecommissionStatusResponse) String() string { return proto.CompactTextString(m) } func (*DecommissionStatusResponse) ProtoMessage() {} func (*DecommissionStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{24} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{24} } func (m *DecommissionStatusResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1385,7 +1391,7 @@ func (m *DecommissionStatusResponse_Status) Reset() { *m = DecommissionS func (m *DecommissionStatusResponse_Status) String() string { return proto.CompactTextString(m) } func (*DecommissionStatusResponse_Status) ProtoMessage() {} func (*DecommissionStatusResponse_Status) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{24, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{24, 0} } func (m *DecommissionStatusResponse_Status) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1421,7 +1427,7 @@ func (m *SettingsRequest) Reset() { *m = SettingsRequest{} } func (m *SettingsRequest) String() string { return proto.CompactTextString(m) } func (*SettingsRequest) ProtoMessage() {} func (*SettingsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{25} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{25} } func (m *SettingsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1455,7 +1461,7 @@ func (m *SettingsResponse) Reset() { *m = SettingsResponse{} } func (m *SettingsResponse) String() string { return proto.CompactTextString(m) } func (*SettingsResponse) ProtoMessage() {} func (*SettingsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{26} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{26} } func (m *SettingsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1490,7 +1496,7 @@ func (m *SettingsResponse_Value) Reset() { *m = SettingsResponse_Value{} func (m *SettingsResponse_Value) String() string { return proto.CompactTextString(m) } func (*SettingsResponse_Value) ProtoMessage() {} func (*SettingsResponse_Value) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{26, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{26, 0} } func (m *SettingsResponse_Value) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1523,7 +1529,7 @@ func (m *HealthRequest) Reset() { *m = HealthRequest{} } func (m *HealthRequest) String() string { return proto.CompactTextString(m) } func (*HealthRequest) ProtoMessage() {} func (*HealthRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{27} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{27} } func (m *HealthRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1558,7 +1564,7 @@ func (m *HealthResponse) Reset() { *m = HealthResponse{} } func (m *HealthResponse) String() string { return proto.CompactTextString(m) } func (*HealthResponse) ProtoMessage() {} func (*HealthResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{28} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{28} } func (m *HealthResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1591,7 +1597,7 @@ func (m *LivenessRequest) Reset() { *m = LivenessRequest{} } func (m *LivenessRequest) String() string { return proto.CompactTextString(m) } func (*LivenessRequest) ProtoMessage() {} func (*LivenessRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{29} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{29} } func (m *LivenessRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1626,7 +1632,7 @@ func (m *LivenessResponse) Reset() { *m = LivenessResponse{} } func (m *LivenessResponse) String() string { return proto.CompactTextString(m) } func (*LivenessResponse) ProtoMessage() {} func (*LivenessResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{30} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{30} } func (m *LivenessResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1662,7 +1668,7 @@ func (m *JobsRequest) Reset() { *m = JobsRequest{} } func (m *JobsRequest) String() string { return proto.CompactTextString(m) } func (*JobsRequest) ProtoMessage() {} func (*JobsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{31} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{31} } func (m *JobsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1696,7 +1702,7 @@ func (m *JobsResponse) Reset() { *m = JobsResponse{} } func (m *JobsResponse) String() string { return proto.CompactTextString(m) } func (*JobsResponse) ProtoMessage() {} func (*JobsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{32} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{32} } func (m *JobsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1749,7 +1755,7 @@ func (m *JobsResponse_Job) Reset() { *m = JobsResponse_Job{} } func (m *JobsResponse_Job) String() string { return proto.CompactTextString(m) } func (*JobsResponse_Job) ProtoMessage() {} func (*JobsResponse_Job) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{32, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{32, 0} } func (m *JobsResponse_Job) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1782,7 +1788,7 @@ func (m *LocationsRequest) Reset() { *m = LocationsRequest{} } func (m *LocationsRequest) String() string { return proto.CompactTextString(m) } func (*LocationsRequest) ProtoMessage() {} func (*LocationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{33} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{33} } func (m *LocationsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1816,7 +1822,7 @@ func (m *LocationsResponse) Reset() { *m = LocationsResponse{} } func (m *LocationsResponse) String() string { return proto.CompactTextString(m) } func (*LocationsResponse) ProtoMessage() {} func (*LocationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{34} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{34} } func (m *LocationsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1852,7 +1858,7 @@ func (m *LocationsResponse_Location) Reset() { *m = LocationsResponse_Lo func (m *LocationsResponse_Location) String() string { return proto.CompactTextString(m) } func (*LocationsResponse_Location) ProtoMessage() {} func (*LocationsResponse_Location) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{34, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{34, 0} } func (m *LocationsResponse_Location) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1894,7 +1900,7 @@ func (m *RangeLogRequest) Reset() { *m = RangeLogRequest{} } func (m *RangeLogRequest) String() string { return proto.CompactTextString(m) } func (*RangeLogRequest) ProtoMessage() {} func (*RangeLogRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{35} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{35} } func (m *RangeLogRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1928,7 +1934,7 @@ func (m *RangeLogResponse) Reset() { *m = RangeLogResponse{} } func (m *RangeLogResponse) String() string { return proto.CompactTextString(m) } func (*RangeLogResponse) ProtoMessage() {} func (*RangeLogResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{36} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{36} } func (m *RangeLogResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1968,7 +1974,7 @@ func (m *RangeLogResponse_PrettyInfo) Reset() { *m = RangeLogResponse_Pr func (m *RangeLogResponse_PrettyInfo) String() string { return proto.CompactTextString(m) } func (*RangeLogResponse_PrettyInfo) ProtoMessage() {} func (*RangeLogResponse_PrettyInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{36, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{36, 0} } func (m *RangeLogResponse_PrettyInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2002,7 +2008,7 @@ func (m *RangeLogResponse_Event) Reset() { *m = RangeLogResponse_Event{} func (m *RangeLogResponse_Event) String() string { return proto.CompactTextString(m) } func (*RangeLogResponse_Event) ProtoMessage() {} func (*RangeLogResponse_Event) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{36, 1} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{36, 1} } func (m *RangeLogResponse_Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2037,7 +2043,7 @@ func (m *QueryPlanRequest) Reset() { *m = QueryPlanRequest{} } func (m *QueryPlanRequest) String() string { return proto.CompactTextString(m) } func (*QueryPlanRequest) ProtoMessage() {} func (*QueryPlanRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{37} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{37} } func (m *QueryPlanRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2072,7 +2078,7 @@ func (m *QueryPlanResponse) Reset() { *m = QueryPlanResponse{} } func (m *QueryPlanResponse) String() string { return proto.CompactTextString(m) } func (*QueryPlanResponse) ProtoMessage() {} func (*QueryPlanResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{38} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{38} } func (m *QueryPlanResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2104,7 +2110,7 @@ func (m *DataDistributionRequest) Reset() { *m = DataDistributionRequest func (m *DataDistributionRequest) String() string { return proto.CompactTextString(m) } func (*DataDistributionRequest) ProtoMessage() {} func (*DataDistributionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{39} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{39} } func (m *DataDistributionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2140,7 +2146,7 @@ func (m *DataDistributionResponse) Reset() { *m = DataDistributionRespon func (m *DataDistributionResponse) String() string { return proto.CompactTextString(m) } func (*DataDistributionResponse) ProtoMessage() {} func (*DataDistributionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{40} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{40} } func (m *DataDistributionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2178,7 +2184,7 @@ func (m *DataDistributionResponse_ZoneConfig) Reset() { *m = DataDistrib func (m *DataDistributionResponse_ZoneConfig) String() string { return proto.CompactTextString(m) } func (*DataDistributionResponse_ZoneConfig) ProtoMessage() {} func (*DataDistributionResponse_ZoneConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{40, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{40, 0} } func (m *DataDistributionResponse_ZoneConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2219,7 @@ func (m *DataDistributionResponse_TableInfo) Reset() { *m = DataDistribu func (m *DataDistributionResponse_TableInfo) String() string { return proto.CompactTextString(m) } func (*DataDistributionResponse_TableInfo) ProtoMessage() {} func (*DataDistributionResponse_TableInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{40, 1} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{40, 1} } func (m *DataDistributionResponse_TableInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2247,7 +2253,7 @@ func (m *DataDistributionResponse_DatabaseInfo) Reset() { *m = DataDistr func (m *DataDistributionResponse_DatabaseInfo) String() string { return proto.CompactTextString(m) } func (*DataDistributionResponse_DatabaseInfo) ProtoMessage() {} func (*DataDistributionResponse_DatabaseInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{40, 2} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{40, 2} } func (m *DataDistributionResponse_DatabaseInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2280,7 +2286,7 @@ func (m *MetricMetadataRequest) Reset() { *m = MetricMetadataRequest{} } func (m *MetricMetadataRequest) String() string { return proto.CompactTextString(m) } func (*MetricMetadataRequest) ProtoMessage() {} func (*MetricMetadataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{41} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{41} } func (m *MetricMetadataRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2314,7 +2320,7 @@ func (m *MetricMetadataResponse) Reset() { *m = MetricMetadataResponse{} func (m *MetricMetadataResponse) String() string { return proto.CompactTextString(m) } func (*MetricMetadataResponse) ProtoMessage() {} func (*MetricMetadataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{42} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{42} } func (m *MetricMetadataResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2357,7 +2363,7 @@ func (m *EnqueueRangeRequest) Reset() { *m = EnqueueRangeRequest{} } func (m *EnqueueRangeRequest) String() string { return proto.CompactTextString(m) } func (*EnqueueRangeRequest) ProtoMessage() {} func (*EnqueueRangeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{43} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{43} } func (m *EnqueueRangeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2390,7 +2396,7 @@ func (m *EnqueueRangeResponse) Reset() { *m = EnqueueRangeResponse{} } func (m *EnqueueRangeResponse) String() string { return proto.CompactTextString(m) } func (*EnqueueRangeResponse) ProtoMessage() {} func (*EnqueueRangeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{44} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{44} } func (m *EnqueueRangeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2427,7 +2433,7 @@ func (m *EnqueueRangeResponse_Details) Reset() { *m = EnqueueRangeRespon func (m *EnqueueRangeResponse_Details) String() string { return proto.CompactTextString(m) } func (*EnqueueRangeResponse_Details) ProtoMessage() {} func (*EnqueueRangeResponse_Details) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{44, 0} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{44, 0} } func (m *EnqueueRangeResponse_Details) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2460,7 +2466,7 @@ func (m *ChartCatalogRequest) Reset() { *m = ChartCatalogRequest{} } func (m *ChartCatalogRequest) String() string { return proto.CompactTextString(m) } func (*ChartCatalogRequest) ProtoMessage() {} func (*ChartCatalogRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{45} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{45} } func (m *ChartCatalogRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2494,7 +2500,7 @@ func (m *ChartCatalogResponse) Reset() { *m = ChartCatalogResponse{} } func (m *ChartCatalogResponse) String() string { return proto.CompactTextString(m) } func (*ChartCatalogResponse) ProtoMessage() {} func (*ChartCatalogResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_admin_19a5a4e012fc0559, []int{46} + return fileDescriptor_admin_ad0cc1fe2eb840c9, []int{46} } func (m *ChartCatalogResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2672,10 +2678,16 @@ type AdminClient interface { QueryPlan(ctx context.Context, in *QueryPlanRequest, opts ...grpc.CallOption) (*QueryPlanResponse, error) // Drain puts the node into the specified drain mode(s) and optionally // instructs the process to terminate. + // We do not expose this via HTTP unless we have a way to authenticate + // + authorize streaming RPC connections. See #42567. Drain(ctx context.Context, in *DrainRequest, opts ...grpc.CallOption) (Admin_DrainClient, error) // Decommission puts the node(s) into the specified decommissioning state. + // If this ever becomes exposed via HTTP, ensure that it performs + // authorization. See #42567. Decommission(ctx context.Context, in *DecommissionRequest, opts ...grpc.CallOption) (*DecommissionStatusResponse, error) // DecommissionStatus retrieves the decommissioning status of the specified nodes. + // If this ever becomes exposed via HTTP, ensure that it performs + // authorization. See #42567. DecommissionStatus(ctx context.Context, in *DecommissionStatusRequest, opts ...grpc.CallOption) (*DecommissionStatusResponse, error) // URL: /_admin/v1/rangelog // URL: /_admin/v1/rangelog?limit=100 @@ -3011,10 +3023,16 @@ type AdminServer interface { QueryPlan(context.Context, *QueryPlanRequest) (*QueryPlanResponse, error) // Drain puts the node into the specified drain mode(s) and optionally // instructs the process to terminate. + // We do not expose this via HTTP unless we have a way to authenticate + // + authorize streaming RPC connections. See #42567. Drain(*DrainRequest, Admin_DrainServer) error // Decommission puts the node(s) into the specified decommissioning state. + // If this ever becomes exposed via HTTP, ensure that it performs + // authorization. See #42567. Decommission(context.Context, *DecommissionRequest) (*DecommissionStatusResponse, error) // DecommissionStatus retrieves the decommissioning status of the specified nodes. + // If this ever becomes exposed via HTTP, ensure that it performs + // authorization. See #42567. DecommissionStatus(context.Context, *DecommissionStatusRequest) (*DecommissionStatusResponse, error) // URL: /_admin/v1/rangelog // URL: /_admin/v1/rangelog?limit=100 @@ -4324,6 +4342,16 @@ func (m *EventsRequest) MarshalTo(dAtA []byte) (int, error) { i++ i = encodeVarintAdmin(dAtA, i, uint64(m.Limit)) } + if m.UnredactedEvents { + dAtA[i] = 0x20 + i++ + if m.UnredactedEvents { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } return i, nil } @@ -6483,6 +6511,9 @@ func (m *EventsRequest) Size() (n int) { if m.Limit != 0 { n += 1 + sovAdmin(uint64(m.Limit)) } + if m.UnredactedEvents { + n += 2 + } return n } @@ -9599,6 +9630,26 @@ func (m *EventsRequest) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnredactedEvents", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAdmin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.UnredactedEvents = bool(v != 0) default: iNdEx = preIndex skippy, err := skipAdmin(dAtA[iNdEx:]) @@ -15540,260 +15591,261 @@ var ( ErrIntOverflowAdmin = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("server/serverpb/admin.proto", fileDescriptor_admin_19a5a4e012fc0559) } +func init() { proto.RegisterFile("server/serverpb/admin.proto", fileDescriptor_admin_ad0cc1fe2eb840c9) } -var fileDescriptor_admin_19a5a4e012fc0559 = []byte{ - // 4019 bytes of a gzipped FileDescriptorProto +var fileDescriptor_admin_ad0cc1fe2eb840c9 = []byte{ + // 4033 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3a, 0x4d, 0x73, 0x1b, 0xc9, - 0x75, 0x1a, 0x80, 0xf8, 0x7a, 0x04, 0x48, 0xb0, 0x45, 0x51, 0x10, 0x24, 0x13, 0xdc, 0x91, 0xd7, + 0x75, 0x1c, 0x80, 0xf8, 0x7a, 0x04, 0x48, 0xb0, 0x45, 0x51, 0x10, 0x24, 0x13, 0xdc, 0x91, 0xd7, 0x4b, 0x6b, 0xd7, 0xc0, 0x8a, 0xd2, 0xee, 0x3a, 0x5a, 0x6d, 0x1c, 0x82, 0x64, 0x71, 0xa1, 0xa5, - 0xb4, 0xab, 0x01, 0xa5, 0x2d, 0xcb, 0xd9, 0x4c, 0x06, 0x98, 0x26, 0x38, 0xe6, 0x60, 0x06, 0x9c, - 0x19, 0x50, 0xe2, 0x6e, 0xec, 0x8a, 0x9d, 0x54, 0x2a, 0xa7, 0xd4, 0x56, 0xec, 0x9b, 0xab, 0x52, - 0xe5, 0x54, 0x2a, 0xa9, 0x24, 0xa7, 0xdc, 0x92, 0x1c, 0x72, 0xde, 0xca, 0xc1, 0x76, 0x55, 0x2e, + 0xb4, 0xab, 0x21, 0xa5, 0x2d, 0xcb, 0x59, 0x4f, 0x06, 0x98, 0x26, 0x38, 0xe6, 0x60, 0x06, 0x9c, + 0x19, 0x50, 0xe2, 0x6e, 0xec, 0x8a, 0xed, 0x94, 0x2b, 0xa7, 0xd4, 0x56, 0xec, 0x9b, 0xab, 0x52, + 0x95, 0x54, 0x2a, 0xa9, 0x24, 0xa7, 0xdc, 0x92, 0x1c, 0x72, 0xde, 0xca, 0xc1, 0x76, 0x55, 0x2e, 0xce, 0x21, 0x74, 0xc2, 0xcd, 0x21, 0x95, 0x1f, 0x90, 0x43, 0x0e, 0x49, 0xaa, 0xbf, 0x66, 0x1a, - 0xe0, 0xec, 0x08, 0xa0, 0xec, 0x1c, 0x48, 0x4c, 0xbf, 0xd7, 0xfd, 0xfa, 0xf5, 0xeb, 0xd7, 0xaf, - 0xdf, 0x47, 0xc3, 0x55, 0x1f, 0x7b, 0x47, 0xd8, 0x6b, 0xb0, 0x9f, 0x41, 0xa7, 0x61, 0x98, 0x7d, - 0xcb, 0xa9, 0x0f, 0x3c, 0x37, 0x70, 0xd1, 0x95, 0xae, 0xdb, 0x3d, 0xf0, 0x5c, 0xa3, 0xbb, 0x5f, - 0x67, 0xf8, 0xba, 0xe8, 0x56, 0x5d, 0xe8, 0xba, 0xce, 0x9e, 0xd5, 0x6b, 0x7c, 0xec, 0x3a, 0x98, - 0xf5, 0xae, 0x2e, 0x7d, 0xdb, 0xed, 0xf8, 0x0d, 0xf2, 0x6f, 0xd0, 0xa1, 0x3f, 0x1c, 0x7e, 0x6d, - 0x7c, 0x0a, 0x3f, 0x30, 0x82, 0xa1, 0xc0, 0xaa, 0x7e, 0xe0, 0x7a, 0x46, 0x0f, 0x37, 0xb0, 0xd3, - 0xb3, 0x1c, 0xf1, 0x33, 0xe8, 0x34, 0xfa, 0x47, 0xdd, 0x2e, 0xef, 0xb3, 0x22, 0xfa, 0xf0, 0xdf, - 0x41, 0xa7, 0x61, 0x5b, 0x47, 0xd8, 0xc1, 0xbe, 0xa0, 0x72, 0x35, 0xa6, 0x87, 0xdb, 0xe3, 0xc8, - 0xe5, 0xc0, 0x6f, 0x74, 0x8d, 0xc0, 0xb0, 0xdd, 0x5e, 0xa3, 0xbb, 0x6f, 0x78, 0x81, 0xce, 0x5b, - 0x1c, 0x5f, 0x19, 0x06, 0x96, 0xdd, 0xe8, 0xe3, 0xc0, 0xb3, 0xba, 0xfc, 0x87, 0x63, 0x16, 0x7b, - 0x6e, 0xcf, 0xa5, 0x9f, 0x0d, 0xf2, 0x25, 0x16, 0xd4, 0x73, 0xdd, 0x9e, 0x8d, 0x1b, 0xc6, 0xc0, - 0x6a, 0x18, 0x8e, 0xe3, 0x06, 0x46, 0x60, 0xb9, 0x8e, 0x60, 0xa5, 0xc6, 0xb1, 0xb4, 0xd5, 0x19, - 0xee, 0x35, 0x02, 0xab, 0x8f, 0xfd, 0xc0, 0xe8, 0x0f, 0x58, 0x07, 0x15, 0x41, 0x79, 0xd3, 0x08, - 0x8c, 0x8e, 0xe1, 0x63, 0x5f, 0xc3, 0x87, 0x43, 0xec, 0x07, 0xea, 0x4d, 0x58, 0x90, 0x60, 0xfe, - 0xc0, 0x75, 0x7c, 0x8c, 0xae, 0x41, 0xc1, 0x14, 0xc0, 0x8a, 0xb2, 0x92, 0x5e, 0x2d, 0x68, 0x11, - 0x40, 0xbd, 0x0d, 0x4b, 0x62, 0xc8, 0x26, 0x0e, 0x0c, 0xcb, 0x16, 0xc4, 0x50, 0x15, 0xf2, 0xa2, - 0x5b, 0x45, 0x59, 0x51, 0x56, 0x0b, 0x5a, 0xd8, 0x56, 0xff, 0x2a, 0x0d, 0x97, 0xcf, 0x0c, 0xe3, - 0xf3, 0x3d, 0x86, 0x6c, 0xcf, 0x33, 0x9c, 0x80, 0x4d, 0x36, 0xbb, 0xf6, 0xf5, 0xfa, 0x17, 0xee, - 0x7f, 0xfd, 0x0b, 0x68, 0xd4, 0xb7, 0x09, 0x81, 0xe6, 0xcc, 0x67, 0x27, 0xb5, 0x0b, 0x1a, 0xa7, - 0x86, 0x6a, 0x30, 0x1b, 0x18, 0x1d, 0x1b, 0xeb, 0x8e, 0xd1, 0xc7, 0x7e, 0x25, 0x45, 0x57, 0x02, - 0x14, 0xf4, 0x80, 0x40, 0xd0, 0x1b, 0x50, 0x32, 0xb1, 0xdf, 0xf5, 0xac, 0x41, 0xe0, 0x7a, 0xba, - 0x65, 0x56, 0xd2, 0x2b, 0xca, 0x6a, 0xba, 0x59, 0x3e, 0x3d, 0xa9, 0x15, 0x37, 0x43, 0x44, 0x6b, - 0x53, 0x2b, 0x46, 0xdd, 0x5a, 0x26, 0xda, 0x80, 0x59, 0xa2, 0x7e, 0x3a, 0x53, 0xc5, 0xca, 0xcc, - 0x8a, 0xb2, 0x3a, 0xbb, 0x76, 0x4d, 0x62, 0x9a, 0x21, 0xea, 0x4f, 0x5c, 0x07, 0x6f, 0xd0, 0x4f, - 0xce, 0x18, 0x7c, 0x1c, 0x42, 0xd0, 0x47, 0xb0, 0x20, 0x11, 0xd1, 0x6d, 0x7c, 0x84, 0xed, 0x4a, - 0x66, 0x45, 0x59, 0x9d, 0x5b, 0xbb, 0x99, 0xb0, 0xfe, 0x88, 0xe6, 0xd0, 0xa3, 0xdb, 0xbf, 0x43, - 0x06, 0x6a, 0xf3, 0x11, 0x65, 0x0a, 0xa8, 0xbe, 0x0d, 0x19, 0x2a, 0x12, 0x84, 0x60, 0x66, 0xe8, - 0x63, 0x8f, 0x6f, 0x08, 0xfd, 0x46, 0xcb, 0x00, 0x03, 0xcf, 0x3a, 0xb2, 0x6c, 0xdc, 0x8b, 0xe4, - 0x12, 0x41, 0xd4, 0x6d, 0xb8, 0xb8, 0x4b, 0xa4, 0x34, 0xf9, 0xfe, 0xa2, 0x45, 0xc8, 0x50, 0xc1, - 0x56, 0x52, 0x14, 0xc1, 0x1a, 0xea, 0xff, 0xe4, 0x60, 0x71, 0x94, 0x12, 0xdf, 0xf2, 0xf6, 0xd8, - 0x96, 0xbf, 0x91, 0xb0, 0xe4, 0x38, 0x02, 0xb1, 0xfb, 0xfd, 0x18, 0x72, 0x5d, 0xd7, 0x1e, 0xf6, - 0x1d, 0xb6, 0xa6, 0xd9, 0xb5, 0x37, 0xa7, 0xa5, 0xba, 0x41, 0x87, 0x73, 0xb2, 0x82, 0x18, 0x7a, - 0x04, 0x39, 0xcb, 0x31, 0xf1, 0x33, 0xec, 0x57, 0xd2, 0xe7, 0xe3, 0xb6, 0x45, 0x86, 0x0b, 0xb2, - 0x9c, 0x16, 0x51, 0x4f, 0xcf, 0x70, 0x7a, 0x44, 0x05, 0x86, 0x4e, 0x40, 0xd5, 0x28, 0xad, 0x01, - 0x05, 0x6d, 0x10, 0x08, 0xba, 0x0d, 0x4b, 0x5d, 0x0f, 0x1b, 0x01, 0xd6, 0x99, 0x1a, 0x13, 0xfb, - 0x85, 0xfb, 0xd8, 0x09, 0xa8, 0x9e, 0x14, 0xb4, 0x45, 0x86, 0xa5, 0x33, 0xb6, 0x05, 0x6e, 0x5c, - 0x3b, 0xb3, 0xbf, 0x3c, 0xed, 0xcc, 0xfd, 0xb2, 0xb4, 0xf3, 0xec, 0xc1, 0xcb, 0x4f, 0x72, 0xf0, - 0x5e, 0x48, 0xa9, 0xab, 0xff, 0xa0, 0x40, 0x96, 0xed, 0x2f, 0x19, 0x4e, 0x4c, 0x82, 0x18, 0x4e, - 0xbe, 0x09, 0x2c, 0x38, 0x1e, 0x08, 0xfd, 0xa5, 0xdf, 0x44, 0xe1, 0x9d, 0xa1, 0x6d, 0x53, 0xbd, - 0x26, 0xa6, 0x21, 0xaf, 0x85, 0x6d, 0x74, 0x9d, 0x2c, 0x61, 0xcf, 0x18, 0xda, 0x81, 0x7e, 0x64, - 0xd8, 0x43, 0x4c, 0xf7, 0xaf, 0x40, 0x18, 0xa6, 0xc0, 0xc7, 0x04, 0x86, 0x6e, 0xc1, 0xa5, 0x1e, - 0x76, 0x30, 0x93, 0x85, 0x8e, 0x9f, 0x0d, 0x3c, 0xec, 0xfb, 0x96, 0xeb, 0x88, 0x0d, 0x8c, 0x90, - 0x5b, 0x21, 0x0e, 0x2d, 0x41, 0x76, 0xdf, 0x32, 0x4d, 0xec, 0xd0, 0xbd, 0xcb, 0x6b, 0xbc, 0x55, - 0xfd, 0x1b, 0x05, 0x32, 0x54, 0x91, 0x62, 0xf9, 0x5f, 0x82, 0xec, 0xd0, 0xb1, 0x0e, 0x87, 0x6c, - 0x05, 0x79, 0x8d, 0xb7, 0x50, 0x19, 0xd2, 0x3e, 0x3e, 0x64, 0x96, 0x4d, 0x23, 0x9f, 0xa4, 0x27, - 0xd3, 0x6c, 0xce, 0x32, 0x6f, 0x51, 0xb3, 0x6f, 0x79, 0xb8, 0x1b, 0x44, 0x0c, 0x46, 0x00, 0x54, - 0x81, 0x1c, 0xb9, 0xe3, 0x2c, 0xa7, 0xc7, 0xd9, 0x12, 0x4d, 0x22, 0x25, 0xab, 0x3f, 0xb0, 0xad, - 0xae, 0x15, 0x50, 0x15, 0xc9, 0x6b, 0x61, 0x5b, 0xdd, 0x82, 0x85, 0x50, 0x3d, 0x5f, 0xc0, 0x8e, - 0xfc, 0x6d, 0x1a, 0x90, 0x4c, 0x87, 0x5b, 0x91, 0xb1, 0x13, 0xa4, 0x9c, 0x39, 0x41, 0xd7, 0xa1, - 0xe4, 0x61, 0xc2, 0x8a, 0xc1, 0xbb, 0xa4, 0x68, 0x97, 0x22, 0x07, 0xb2, 0x4e, 0x5f, 0x02, 0x70, - 0x5c, 0x53, 0x10, 0x61, 0x82, 0x2a, 0x10, 0x08, 0x43, 0xbf, 0x0b, 0x19, 0x72, 0xf0, 0x7c, 0x6e, - 0xe7, 0x5f, 0x93, 0xd5, 0x9f, 0x5d, 0xfa, 0x75, 0xe6, 0x3b, 0xd4, 0x85, 0x0b, 0x51, 0xbf, 0xff, - 0x78, 0x63, 0x83, 0x72, 0xca, 0x4f, 0x16, 0x23, 0x80, 0x4c, 0x28, 0xf5, 0x2d, 0xdf, 0xb7, 0x9c, - 0x9e, 0x4e, 0xc8, 0xfb, 0x95, 0x0c, 0xb5, 0x26, 0xbf, 0xf6, 0x3c, 0x6b, 0x32, 0xb2, 0xe8, 0xfa, - 0x7d, 0x46, 0xe2, 0x81, 0x6b, 0x62, 0x4e, 0xbe, 0xd8, 0x8f, 0x40, 0x3e, 0xb1, 0x1a, 0xc6, 0x60, - 0xe0, 0xb9, 0xcf, 0xac, 0x3e, 0x31, 0x1d, 0xa6, 0xe5, 0x1f, 0xe8, 0x9d, 0xe3, 0x00, 0xfb, 0x74, - 0xdf, 0x66, 0xb4, 0x45, 0x09, 0xbb, 0x69, 0xf9, 0x07, 0x4d, 0x82, 0xab, 0x7e, 0x08, 0xb3, 0x12, - 0x61, 0x74, 0x1d, 0x72, 0x54, 0x26, 0x96, 0xc9, 0x76, 0xa8, 0x09, 0xa7, 0x27, 0xb5, 0x2c, 0x41, - 0xb5, 0x36, 0xb5, 0x2c, 0x41, 0xb5, 0x4c, 0x22, 0x5d, 0xec, 0x79, 0xae, 0xa7, 0xf7, 0xb1, 0xef, - 0x1b, 0x3d, 0xb1, 0x67, 0x45, 0x0a, 0xbc, 0xcf, 0x60, 0xea, 0x12, 0x2c, 0x3e, 0x70, 0x9d, 0x33, - 0x4a, 0xa0, 0xfe, 0x54, 0x81, 0x4b, 0x63, 0x08, 0xbe, 0xab, 0xdf, 0x84, 0x05, 0xe2, 0xba, 0xe8, - 0x3e, 0xf6, 0x2c, 0xec, 0xeb, 0x4c, 0xf8, 0x0a, 0x15, 0xfe, 0xd7, 0xa6, 0x12, 0x95, 0x36, 0x4f, - 0xe8, 0xb4, 0x29, 0x19, 0x8a, 0x40, 0xdf, 0x02, 0x64, 0x39, 0x01, 0xf6, 0x1c, 0xc3, 0xd6, 0x87, - 0x3e, 0xe6, 0xb4, 0x53, 0xe7, 0xa1, 0x5d, 0x16, 0x84, 0x1e, 0xf9, 0x0c, 0xa3, 0xce, 0x41, 0xf1, - 0x91, 0x8f, 0xbd, 0x70, 0x85, 0xdf, 0x85, 0x12, 0x6f, 0xf3, 0x85, 0xb5, 0x20, 0x43, 0x2c, 0x95, - 0xb8, 0xf3, 0x92, 0x26, 0x1c, 0x19, 0x48, 0x5b, 0x42, 0x95, 0x28, 0x85, 0xaa, 0x0a, 0x33, 0x04, - 0x48, 0x8e, 0x12, 0x01, 0x48, 0xd6, 0x20, 0x6c, 0xab, 0x8f, 0xa1, 0xb4, 0x75, 0x84, 0x9d, 0xe8, - 0xdc, 0x09, 0x13, 0xa7, 0x48, 0x26, 0xee, 0x2a, 0x14, 0x02, 0xc3, 0xeb, 0xe1, 0x80, 0x6c, 0x35, - 0x3b, 0x1d, 0x79, 0x06, 0x68, 0x99, 0xe4, 0x30, 0xda, 0x56, 0xdf, 0x62, 0x87, 0x22, 0xa3, 0xb1, - 0x86, 0xfa, 0x9f, 0x29, 0x98, 0x13, 0x84, 0xf9, 0xca, 0xee, 0x43, 0x16, 0x53, 0x08, 0x5f, 0x5a, - 0x23, 0x61, 0x69, 0xa3, 0x43, 0x59, 0x53, 0x5c, 0xe4, 0x8c, 0x48, 0xf5, 0x0f, 0x53, 0x90, 0xa1, - 0x70, 0xd4, 0x84, 0x42, 0xe8, 0xc6, 0x72, 0x1d, 0xa8, 0xd6, 0x99, 0xa3, 0x5b, 0x17, 0x8e, 0x6e, - 0x7d, 0x57, 0xf4, 0x68, 0xe6, 0x09, 0x99, 0x4f, 0x7f, 0x51, 0x53, 0xb4, 0x68, 0x18, 0x39, 0xdf, - 0x94, 0xae, 0x2e, 0xd9, 0xf7, 0x02, 0x85, 0xec, 0x12, 0x09, 0x7c, 0x55, 0x96, 0x00, 0x73, 0x00, - 0x8b, 0xa7, 0x27, 0xb5, 0xfc, 0x2e, 0x93, 0xc2, 0xa6, 0x24, 0x8f, 0x35, 0x20, 0x96, 0xc3, 0xf5, - 0x02, 0x72, 0x84, 0x2d, 0x93, 0x5d, 0xd9, 0xcd, 0xf9, 0xd3, 0x93, 0xda, 0xac, 0x26, 0xe0, 0xad, - 0x4d, 0x6d, 0x36, 0xec, 0xd4, 0x32, 0x89, 0xd0, 0x2d, 0x67, 0xcf, 0xe5, 0x06, 0x95, 0x7e, 0x93, - 0x29, 0x99, 0x75, 0x26, 0x44, 0xc8, 0xa9, 0x2c, 0xb2, 0x29, 0x1f, 0x51, 0x20, 0x99, 0x92, 0xa1, - 0x5b, 0xa6, 0xfa, 0xd7, 0x0a, 0x94, 0xdb, 0x38, 0x78, 0xd4, 0x22, 0x8e, 0xaf, 0xd8, 0xc8, 0x6f, - 0x02, 0x1c, 0xe0, 0x63, 0x76, 0xef, 0x08, 0x91, 0xdf, 0x49, 0x10, 0xf9, 0x38, 0x81, 0xfa, 0x7b, - 0xf8, 0x98, 0x5e, 0x50, 0xfe, 0x96, 0x13, 0x78, 0xc7, 0x5a, 0xe1, 0x40, 0xb4, 0xab, 0x77, 0x61, - 0x6e, 0x14, 0x49, 0x2e, 0x90, 0x03, 0x7c, 0xcc, 0x95, 0x86, 0x7c, 0x12, 0xb5, 0x60, 0x57, 0x1e, - 0x91, 0x65, 0x51, 0x63, 0x8d, 0x3b, 0xa9, 0xaf, 0x2b, 0xea, 0x45, 0x58, 0x90, 0xe6, 0x62, 0x3b, - 0xac, 0x7e, 0x05, 0xca, 0xdb, 0xe3, 0x2b, 0x40, 0x30, 0x73, 0x80, 0x8f, 0x45, 0x74, 0x41, 0xbf, - 0xd5, 0x9f, 0xa6, 0x60, 0x61, 0x7b, 0x7c, 0x34, 0xfa, 0xed, 0x98, 0xb5, 0xbe, 0x9d, 0xb0, 0xd6, - 0x33, 0x14, 0xc6, 0x16, 0xcb, 0x55, 0x4d, 0x5a, 0xf2, 0x1e, 0x64, 0xd8, 0x6d, 0x1d, 0xae, 0x4b, - 0x91, 0xd6, 0x85, 0xb6, 0xa1, 0x68, 0x1b, 0x7e, 0xa0, 0x0f, 0x07, 0xa6, 0x11, 0x60, 0x93, 0x5b, - 0x8b, 0xc9, 0xb4, 0x70, 0x96, 0x8c, 0x7c, 0xc4, 0x06, 0x56, 0x07, 0x13, 0x88, 0xf6, 0x5d, 0x59, - 0xb4, 0xb3, 0x6b, 0x6b, 0x53, 0x2d, 0x94, 0x92, 0x96, 0xb7, 0xa3, 0x0c, 0x73, 0x1b, 0xf6, 0xd0, - 0x0f, 0xb0, 0x27, 0x6c, 0xd2, 0x8f, 0x14, 0x98, 0x0f, 0x41, 0x5c, 0xc2, 0xaf, 0x01, 0x74, 0x19, - 0x28, 0x32, 0xf7, 0xa5, 0xd3, 0x93, 0x5a, 0x81, 0x77, 0x6c, 0x6d, 0x6a, 0x05, 0xde, 0xa1, 0x65, - 0xa2, 0x57, 0x61, 0x21, 0x3a, 0x03, 0xd8, 0x21, 0x86, 0xd1, 0xe4, 0x2e, 0x47, 0x39, 0x44, 0x6c, - 0x31, 0x38, 0xfa, 0x1a, 0x20, 0x4c, 0xcc, 0xe4, 0xc0, 0xb3, 0x7c, 0x1c, 0xf6, 0x66, 0xae, 0xd4, - 0x42, 0x84, 0xe1, 0xdd, 0xd5, 0x1d, 0x28, 0x6e, 0x7a, 0x86, 0xe5, 0x08, 0x2d, 0x99, 0x83, 0x94, - 0xeb, 0xd0, 0x3d, 0xcf, 0x68, 0x29, 0xd7, 0x21, 0xf2, 0x72, 0xf7, 0xf6, 0xa8, 0x6f, 0x97, 0xd1, - 0xc8, 0x27, 0xb1, 0x7f, 0xfe, 0xfe, 0x30, 0x30, 0xdd, 0xa7, 0x8e, 0xf0, 0xd0, 0x44, 0x5b, 0xad, - 0x41, 0x89, 0x53, 0xe3, 0x0b, 0x1d, 0x23, 0xa7, 0x7e, 0x0c, 0x57, 0x36, 0x71, 0xd7, 0xed, 0xd3, - 0xeb, 0xd3, 0x75, 0xda, 0x34, 0x3d, 0x20, 0xe6, 0xfe, 0x08, 0xf2, 0xfc, 0x06, 0x64, 0x5a, 0x97, - 0x69, 0x36, 0x4f, 0x4f, 0x6a, 0x39, 0x76, 0x05, 0xfa, 0xff, 0x7d, 0x52, 0xbb, 0xd5, 0xb3, 0x82, - 0xfd, 0x61, 0xa7, 0xde, 0x75, 0xfb, 0x8d, 0x70, 0x97, 0xcc, 0x4e, 0xf4, 0xdd, 0x18, 0x1c, 0xf4, - 0x1a, 0xf4, 0x6b, 0xd0, 0xa9, 0xf3, 0xab, 0x33, 0xc7, 0xae, 0x4e, 0x5f, 0xfd, 0x13, 0x05, 0x2e, - 0xca, 0x93, 0xff, 0xff, 0x4c, 0x8b, 0x56, 0x61, 0xde, 0x94, 0x66, 0x25, 0xde, 0x1c, 0xdb, 0xbb, - 0x71, 0xb0, 0xfa, 0x79, 0x0a, 0xaa, 0x71, 0xd2, 0xe1, 0xb2, 0x7c, 0x02, 0x59, 0x96, 0x4e, 0xe1, - 0xa1, 0xd6, 0xdd, 0xa4, 0x98, 0xfd, 0x0b, 0xc9, 0xd4, 0x59, 0x53, 0x98, 0x7f, 0x46, 0xb1, 0xfa, - 0x1f, 0x0a, 0x64, 0x19, 0x02, 0x3d, 0x19, 0xf5, 0x43, 0x32, 0xcd, 0xf5, 0xc8, 0x0f, 0x39, 0xaf, - 0x30, 0x84, 0xfb, 0x72, 0x19, 0x72, 0x96, 0xaf, 0xdb, 0xd6, 0x51, 0xe8, 0x32, 0x5b, 0xfe, 0x8e, - 0x75, 0x84, 0xcf, 0x7a, 0x8d, 0xe9, 0x18, 0xaf, 0x31, 0x46, 0x92, 0x33, 0xb1, 0x92, 0xa4, 0xee, - 0x2e, 0xd1, 0x43, 0xd2, 0x25, 0xc3, 0x74, 0x54, 0xb4, 0xd5, 0x97, 0x61, 0xbe, 0x8d, 0x03, 0x72, - 0x64, 0xfc, 0x24, 0xd3, 0xf8, 0x77, 0x29, 0x7a, 0x0b, 0xf0, 0x7e, 0x7c, 0x0b, 0xf4, 0xe9, 0x6f, - 0x81, 0x11, 0x02, 0xcf, 0x35, 0x8c, 0xed, 0x58, 0xc3, 0x58, 0x10, 0x86, 0x31, 0x2e, 0x62, 0x5a, - 0x81, 0x59, 0x11, 0xb1, 0x91, 0x28, 0x22, 0x4d, 0x51, 0x32, 0xa8, 0xea, 0x4e, 0x60, 0x05, 0xb7, - 0x47, 0xad, 0xe0, 0xcd, 0x69, 0x16, 0x75, 0xc6, 0x08, 0xce, 0x43, 0xe9, 0x5d, 0x6c, 0xd8, 0xc1, - 0xbe, 0xb0, 0x81, 0x65, 0x98, 0x13, 0x00, 0x7e, 0x43, 0x2d, 0xc0, 0xfc, 0x0e, 0xcf, 0xeb, 0x89, - 0x4e, 0x3f, 0x49, 0x41, 0x39, 0x82, 0x71, 0x89, 0xaf, 0x03, 0x88, 0xfc, 0x5f, 0x28, 0xf1, 0xab, - 0x31, 0xf1, 0x80, 0x18, 0x28, 0x02, 0xeb, 0x68, 0x10, 0xfa, 0x63, 0x05, 0xf2, 0x4c, 0xcd, 0xb1, - 0x38, 0x3a, 0x49, 0xfe, 0xff, 0x38, 0x0b, 0xfc, 0xc0, 0x88, 0x2d, 0x7b, 0x9b, 0xd0, 0xff, 0xfe, - 0x2f, 0xce, 0x77, 0x0e, 0x42, 0x3e, 0xaa, 0x1d, 0x28, 0x8d, 0xd0, 0x95, 0xb7, 0x24, 0xc3, 0xb6, - 0xe4, 0x6d, 0x79, 0x4b, 0xe6, 0xd6, 0x5e, 0x8e, 0x59, 0x35, 0x21, 0x2b, 0xf8, 0xe5, 0xc7, 0x5c, - 0xda, 0x86, 0x01, 0xcc, 0xde, 0x73, 0x3b, 0xa1, 0x96, 0x87, 0xae, 0xa5, 0x22, 0xb9, 0x96, 0x24, - 0x34, 0x0d, 0xad, 0x0a, 0x0d, 0x4d, 0x59, 0x0b, 0xdd, 0xe2, 0xaa, 0x96, 0xa6, 0x93, 0xd7, 0xe4, - 0xc9, 0x0f, 0xed, 0x3a, 0xcd, 0xf9, 0xb2, 0xfc, 0x6f, 0x9d, 0xb8, 0x74, 0x4c, 0x17, 0xd5, 0x9f, - 0x64, 0xa1, 0xc8, 0xa6, 0xe4, 0xdb, 0xb7, 0x05, 0x33, 0xa4, 0x17, 0xdf, 0xb8, 0x57, 0x13, 0xc4, - 0x2e, 0x0f, 0x23, 0x0d, 0xbe, 0x91, 0x74, 0x78, 0xf5, 0xbf, 0x32, 0x90, 0xbe, 0xe7, 0x76, 0xd0, - 0x12, 0xa4, 0xb8, 0x59, 0x4a, 0x37, 0xb3, 0xa7, 0x27, 0xb5, 0x54, 0x6b, 0x53, 0x4b, 0x59, 0xe6, - 0xf9, 0xce, 0xc5, 0x88, 0x27, 0x3f, 0x33, 0xea, 0xc9, 0x23, 0x17, 0xe6, 0x46, 0xd2, 0x25, 0x2c, - 0x72, 0x2c, 0x35, 0xdf, 0x3d, 0x3d, 0xa9, 0x95, 0xe4, 0x7c, 0xc9, 0xe4, 0x17, 0x84, 0x7f, 0x68, - 0x93, 0x3f, 0x12, 0x73, 0xd7, 0x5b, 0x9b, 0x5a, 0x49, 0xce, 0xb3, 0xf8, 0xd2, 0x3e, 0x64, 0x47, - 0xf6, 0xe1, 0x0e, 0xe4, 0x58, 0xce, 0xc9, 0xa4, 0x91, 0x7e, 0xb2, 0x1b, 0x34, 0x43, 0x5d, 0x20, - 0x31, 0x80, 0x8c, 0xf5, 0x03, 0xc3, 0x23, 0x63, 0xf3, 0x93, 0x8e, 0xe5, 0x03, 0xd0, 0x5d, 0xc8, - 0xef, 0x59, 0x8e, 0xe5, 0xef, 0x63, 0xb3, 0x52, 0x98, 0x70, 0x70, 0x38, 0x82, 0x8c, 0xee, 0xbb, - 0xa6, 0xb5, 0x67, 0x61, 0xb3, 0x02, 0x93, 0x8e, 0x16, 0x23, 0x88, 0x0f, 0xb3, 0xe7, 0x19, 0x34, - 0x09, 0xa2, 0x77, 0xdd, 0xfe, 0xc0, 0xc6, 0x64, 0x09, 0xb3, 0x2b, 0xca, 0x6a, 0x4a, 0x5b, 0x10, - 0x98, 0x0d, 0x81, 0x20, 0x8a, 0x4d, 0xe3, 0xdf, 0x4a, 0x91, 0xd9, 0x4a, 0xda, 0x40, 0x0f, 0xe1, - 0xe2, 0xbe, 0xd5, 0xdb, 0x7f, 0x6a, 0x10, 0x2f, 0x2b, 0x8a, 0x68, 0x4a, 0x13, 0x72, 0x83, 0xc2, - 0xc1, 0x21, 0x86, 0x38, 0x62, 0x11, 0x49, 0x13, 0x77, 0xad, 0xbe, 0x61, 0x57, 0xe6, 0xe8, 0xa4, - 0xe5, 0x10, 0xb1, 0xc9, 0xe0, 0xe8, 0x65, 0x98, 0xf3, 0x86, 0x0e, 0xb9, 0x72, 0x74, 0xbe, 0xb1, - 0xf3, 0xb4, 0x67, 0x89, 0x43, 0xf9, 0x75, 0x7b, 0x0d, 0x0a, 0x51, 0x92, 0xb1, 0xcc, 0x22, 0xa5, - 0x10, 0xa0, 0x22, 0x28, 0xef, 0xb8, 0x5d, 0x56, 0x74, 0x10, 0x76, 0xf2, 0x7f, 0x15, 0x58, 0x90, - 0x80, 0x61, 0x08, 0x5f, 0xb0, 0x05, 0x70, 0x82, 0x0c, 0xef, 0x19, 0x02, 0x21, 0x44, 0x5c, 0x4a, - 0x21, 0xb5, 0xea, 0x1f, 0x29, 0x90, 0x17, 0x58, 0xf4, 0x12, 0x14, 0x09, 0xc6, 0xb6, 0x82, 0x63, - 0x3d, 0xba, 0x43, 0x66, 0x05, 0xec, 0x3d, 0x7c, 0x4c, 0x56, 0x1e, 0x76, 0x89, 0x2c, 0x58, 0x41, - 0x2b, 0x09, 0x28, 0xbb, 0xe2, 0xaa, 0x90, 0xb7, 0x8d, 0xc0, 0x0a, 0x86, 0x26, 0xb3, 0x32, 0x8a, - 0x16, 0xb6, 0x89, 0x54, 0x6c, 0xd7, 0xe9, 0x31, 0xe4, 0x0c, 0x45, 0x46, 0x00, 0xb5, 0x09, 0xf3, - 0x9a, 0xe1, 0xf4, 0xf0, 0x8e, 0xdb, 0x13, 0xc6, 0xed, 0x0a, 0xe4, 0x59, 0x5e, 0x4a, 0xd8, 0x07, - 0x2d, 0x47, 0xdb, 0x72, 0x48, 0x9d, 0x92, 0x43, 0xea, 0x7f, 0x49, 0x43, 0x39, 0x22, 0xc2, 0x85, - 0xf8, 0x7e, 0x18, 0x54, 0xb3, 0x7b, 0x22, 0xe9, 0x1a, 0x1c, 0x1f, 0x1c, 0x1b, 0x56, 0xff, 0xa3, - 0x02, 0xf0, 0x81, 0x87, 0x83, 0xe0, 0xb8, 0x45, 0xa2, 0xd0, 0x97, 0xa0, 0xc8, 0x63, 0x1a, 0x9d, - 0x9c, 0x7e, 0x21, 0x3c, 0x0e, 0x23, 0x66, 0x85, 0x2c, 0xc4, 0xc1, 0x4f, 0x19, 0x9a, 0x89, 0x2d, - 0xe7, 0xe0, 0xa7, 0x14, 0x75, 0x1d, 0x4a, 0x86, 0x69, 0x62, 0x53, 0xe7, 0x5e, 0x11, 0xb7, 0x69, - 0x45, 0x0a, 0xd4, 0x18, 0x0c, 0xbd, 0x02, 0xf3, 0x1e, 0xee, 0xbb, 0x47, 0x52, 0x37, 0x66, 0xdb, - 0xe6, 0x38, 0x58, 0x74, 0x5c, 0x82, 0xac, 0x87, 0x0d, 0x3f, 0x4c, 0x3c, 0xf2, 0x16, 0xaa, 0x40, - 0xce, 0x64, 0xb9, 0x74, 0x6e, 0x89, 0x44, 0xb3, 0xfa, 0x67, 0x8a, 0xc8, 0x11, 0xdc, 0x85, 0x0c, - 0x5d, 0x20, 0xcf, 0x0f, 0xac, 0xc4, 0x5c, 0x4d, 0x42, 0x3c, 0xb2, 0x54, 0xd8, 0x20, 0xf4, 0x11, - 0xcc, 0x0e, 0xa8, 0x4c, 0x74, 0x1a, 0xa6, 0x33, 0x8f, 0xe3, 0xcd, 0x69, 0x44, 0x1d, 0x89, 0x54, - 0xdc, 0xf7, 0x83, 0x10, 0x72, 0x6f, 0x26, 0xaf, 0x94, 0x53, 0xea, 0x2a, 0x94, 0x1f, 0x0e, 0xb1, - 0x77, 0xfc, 0x81, 0x6d, 0x38, 0xd2, 0x0d, 0x78, 0x48, 0x60, 0xc2, 0xa9, 0xa2, 0x0d, 0x75, 0x00, - 0x0b, 0x52, 0x4f, 0xae, 0x09, 0xdf, 0x82, 0xab, 0xa6, 0xe5, 0x07, 0xfe, 0xa1, 0xad, 0x0f, 0xf6, - 0x8f, 0x7d, 0xab, 0x6b, 0xd8, 0x3a, 0xed, 0xae, 0x0f, 0x6c, 0xc3, 0xe1, 0x21, 0xdb, 0xb5, 0xd3, - 0x93, 0x5a, 0x65, 0xd3, 0xf2, 0x83, 0xf6, 0xc3, 0x9d, 0x0f, 0x78, 0xaf, 0x88, 0x54, 0x85, 0x13, - 0x38, 0x83, 0x51, 0xaf, 0xb0, 0xc2, 0x1c, 0x19, 0xe9, 0x59, 0x9d, 0x61, 0x10, 0x05, 0x23, 0xea, - 0x5f, 0x02, 0x54, 0xce, 0xe2, 0x38, 0x53, 0x03, 0x28, 0x89, 0xac, 0x2d, 0x13, 0x1d, 0x3b, 0xe7, - 0x5b, 0xcf, 0x29, 0xde, 0xc5, 0xd1, 0x0a, 0xab, 0x7a, 0x44, 0x64, 0xb2, 0x33, 0x5a, 0x34, 0x25, - 0x04, 0xea, 0x43, 0x51, 0x2a, 0x4a, 0x88, 0x62, 0xcc, 0xe6, 0x79, 0x26, 0x8c, 0x0a, 0x15, 0x23, - 0xce, 0xef, 0x6c, 0x54, 0xa8, 0xf0, 0xab, 0x3f, 0x54, 0x00, 0xa2, 0x7e, 0x44, 0x45, 0x59, 0x22, - 0x88, 0x6f, 0x18, 0x6f, 0xa1, 0x3b, 0x90, 0xe5, 0xa5, 0x96, 0xd4, 0xc4, 0xa5, 0x16, 0x3e, 0x82, - 0x86, 0xde, 0xac, 0xc2, 0xe2, 0x1f, 0xda, 0xec, 0x68, 0xf0, 0xd0, 0x9b, 0x42, 0xdb, 0x0f, 0x77, - 0xb4, 0x02, 0xeb, 0xd0, 0x3e, 0xb4, 0xef, 0xcd, 0xe4, 0xd3, 0xe5, 0x99, 0xea, 0x1f, 0xa4, 0xa1, - 0x40, 0xf3, 0x91, 0x54, 0x26, 0x9f, 0x29, 0x50, 0x19, 0x09, 0x56, 0xf4, 0xce, 0xb1, 0x1e, 0x85, - 0x4c, 0x44, 0x40, 0x1f, 0x9e, 0x47, 0x40, 0xe1, 0x0c, 0x75, 0x4d, 0x8a, 0x7a, 0x9a, 0xc7, 0xd4, - 0x77, 0x34, 0x99, 0xcc, 0xde, 0x3a, 0xaf, 0xe7, 0xb9, 0xe8, 0xc5, 0xd0, 0x44, 0x5f, 0x86, 0x39, - 0xb9, 0xe6, 0x14, 0xe6, 0x23, 0x8b, 0xd1, 0xa6, 0xb4, 0x4c, 0xf4, 0x0d, 0x00, 0xd3, 0x73, 0x07, - 0x03, 0x6c, 0xea, 0x06, 0x8b, 0xcc, 0x26, 0xb9, 0x40, 0x0b, 0x7c, 0xcc, 0x7a, 0x50, 0xdd, 0x86, - 0x2b, 0x5f, 0xb8, 0xa4, 0x18, 0xc7, 0x77, 0x24, 0xd9, 0x95, 0x96, 0x3c, 0xda, 0xea, 0xf7, 0x52, - 0x50, 0x94, 0x15, 0x17, 0x05, 0xc0, 0x8a, 0xcb, 0xf2, 0x71, 0x78, 0xff, 0x45, 0x8f, 0x43, 0xb4, - 0x13, 0x23, 0x51, 0x5a, 0x20, 0xa0, 0xd5, 0x4f, 0x60, 0x6e, 0xb4, 0x4b, 0x4c, 0x40, 0xd5, 0x1e, - 0x0d, 0xa8, 0xde, 0x79, 0x21, 0x8d, 0x18, 0x91, 0x81, 0x12, 0x3d, 0x20, 0x48, 0x62, 0xe0, 0xf1, - 0x28, 0x03, 0xbf, 0xf1, 0xa2, 0x52, 0x91, 0x79, 0xf8, 0x2e, 0x94, 0xc7, 0x8f, 0x73, 0x0c, 0x07, - 0xbb, 0xa3, 0x1c, 0xfc, 0xfa, 0x8b, 0x59, 0x0d, 0x69, 0xfe, 0x7b, 0x33, 0xf9, 0x54, 0x39, 0xad, - 0x5e, 0x86, 0x4b, 0xf7, 0xe9, 0x13, 0x8e, 0xfb, 0x38, 0x30, 0xcc, 0x28, 0xd5, 0xa9, 0xfe, 0xb3, - 0x02, 0x4b, 0xe3, 0x18, 0x6e, 0x42, 0x0d, 0xc8, 0xf7, 0x39, 0x8c, 0xab, 0xcb, 0x37, 0x12, 0xd8, - 0x8a, 0x27, 0x52, 0x17, 0x00, 0x59, 0x3d, 0x42, 0xb2, 0xd5, 0xdf, 0x84, 0xd2, 0x48, 0x87, 0x18, - 0xc9, 0xbc, 0x31, 0x2a, 0x19, 0x39, 0xba, 0x1a, 0x06, 0x96, 0x5d, 0xe7, 0x2f, 0x53, 0xc2, 0x89, - 0xa5, 0xa0, 0xee, 0x07, 0x29, 0xb8, 0xb8, 0xe5, 0x1c, 0x0e, 0xf1, 0x10, 0xd3, 0x6b, 0x51, 0xdc, - 0x6d, 0xbf, 0xca, 0xb4, 0x0d, 0xbb, 0x37, 0x43, 0x3f, 0x8e, 0x35, 0xd0, 0x6f, 0x49, 0x2e, 0x17, - 0xad, 0x56, 0x34, 0x37, 0x4e, 0x4f, 0x6a, 0x39, 0xca, 0x15, 0x9d, 0xf3, 0xf6, 0x54, 0x73, 0xf2, - 0x71, 0x91, 0xdf, 0x76, 0x03, 0x16, 0xfc, 0x03, 0x6b, 0xa0, 0xfb, 0xfb, 0xee, 0xd0, 0x36, 0x75, - 0xc6, 0x01, 0x4f, 0xf8, 0x10, 0x44, 0x9b, 0xc2, 0x1f, 0x12, 0xb0, 0xfa, 0xe7, 0x29, 0x58, 0x1c, - 0x95, 0x0a, 0xdf, 0xef, 0x87, 0x91, 0x37, 0xc3, 0xb6, 0xfb, 0xad, 0xa4, 0x3a, 0x49, 0x0c, 0x85, - 0xba, 0x78, 0x58, 0x10, 0xba, 0x41, 0x7f, 0xaf, 0x40, 0x8e, 0x03, 0x7f, 0xa5, 0x52, 0x7f, 0x67, - 0xcc, 0x19, 0x7d, 0x39, 0xa9, 0x5a, 0xe6, 0x19, 0x5d, 0x4c, 0x5d, 0x2d, 0xe1, 0x7a, 0x46, 0x51, - 0x51, 0x5a, 0x8a, 0x8a, 0xd4, 0x4b, 0x70, 0x71, 0x63, 0xdf, 0xf0, 0x82, 0x0d, 0xf6, 0x2c, 0x4a, - 0x9c, 0x98, 0x27, 0xb0, 0x38, 0x0a, 0xe6, 0xe2, 0x6b, 0x42, 0x8e, 0x3f, 0xa0, 0xe2, 0xe2, 0x53, - 0x25, 0x26, 0x02, 0xbf, 0x2e, 0x5e, 0x57, 0xd1, 0xc1, 0x6d, 0x56, 0xb7, 0x0e, 0xdf, 0x72, 0x30, - 0xdc, 0x8d, 0xf7, 0x60, 0x29, 0xfe, 0x91, 0x02, 0x9a, 0x85, 0xdc, 0xa3, 0x07, 0xef, 0x3d, 0x78, - 0xff, 0xc3, 0x07, 0xe5, 0x0b, 0xa4, 0xb1, 0xb1, 0xf3, 0xa8, 0xbd, 0xbb, 0xa5, 0x95, 0x15, 0x54, - 0x84, 0xfc, 0xe6, 0xfa, 0xee, 0x7a, 0x73, 0xbd, 0xbd, 0x55, 0x4e, 0xa1, 0x02, 0x64, 0x76, 0xd7, - 0x9b, 0x3b, 0x5b, 0xe5, 0xf4, 0x8d, 0xeb, 0x50, 0xa0, 0x19, 0xe6, 0xfb, 0xae, 0x89, 0x11, 0x40, - 0x76, 0x63, 0xa7, 0xb5, 0xf5, 0x60, 0xb7, 0x7c, 0x81, 0x7c, 0xef, 0x6c, 0xad, 0xb7, 0xb7, 0xda, - 0x65, 0x65, 0xed, 0xc7, 0x55, 0xc8, 0xac, 0x9b, 0x7d, 0xcb, 0x41, 0x01, 0x64, 0x68, 0x5d, 0x0f, - 0xbd, 0xf2, 0xfc, 0xca, 0x1f, 0x95, 0x44, 0x75, 0x75, 0xd2, 0x12, 0xa1, 0x5a, 0xf9, 0xfe, 0x3f, - 0xfd, 0xfb, 0x0f, 0x52, 0x08, 0x95, 0x1b, 0x3a, 0x7d, 0x49, 0xd7, 0x38, 0xba, 0xd9, 0xa0, 0xa5, - 0x42, 0xf4, 0xfb, 0x0a, 0x14, 0xc2, 0x37, 0x5e, 0xe8, 0xd5, 0x09, 0xde, 0x56, 0x85, 0xd3, 0xbf, - 0x36, 0x59, 0x67, 0xce, 0xc2, 0x35, 0xca, 0xc2, 0x12, 0x5a, 0x94, 0x58, 0x08, 0x9f, 0x8d, 0xa1, - 0x1f, 0x2b, 0x30, 0x3f, 0xf6, 0x78, 0x0b, 0xdd, 0x9c, 0xe6, 0xa1, 0x17, 0x63, 0x69, 0x6d, 0xfa, - 0xb7, 0x61, 0xea, 0x2b, 0x94, 0xb1, 0x97, 0x50, 0x2d, 0x8e, 0xb1, 0xc6, 0x27, 0xe2, 0xf3, 0x3b, - 0xe8, 0x2f, 0x14, 0x28, 0xca, 0xef, 0x77, 0x50, 0x7d, 0xe2, 0x87, 0x3e, 0x8c, 0xbb, 0xc6, 0x94, - 0x0f, 0x83, 0xd4, 0x37, 0x29, 0x6b, 0xaf, 0xa3, 0xfa, 0x73, 0x58, 0x6b, 0xd0, 0xfb, 0xde, 0x6f, - 0x7c, 0x42, 0x7f, 0x29, 0xa7, 0x10, 0x15, 0xa5, 0xd1, 0x6b, 0x13, 0xd6, 0xae, 0x19, 0x97, 0xd3, - 0x55, 0xba, 0xd5, 0xbb, 0x94, 0xc7, 0x37, 0xd1, 0xed, 0xe9, 0x78, 0x6c, 0xb0, 0x47, 0x0f, 0x3f, - 0x54, 0xa0, 0x34, 0x52, 0xe7, 0x47, 0x49, 0x42, 0x8a, 0x7b, 0x2a, 0x50, 0x7d, 0x7d, 0xf2, 0x01, - 0x9c, 0xe5, 0x15, 0xca, 0x72, 0x15, 0x55, 0x24, 0x96, 0x1d, 0xd7, 0x61, 0x0c, 0x52, 0x26, 0x9e, - 0x41, 0x96, 0x15, 0xa2, 0xd1, 0xea, 0x04, 0xb5, 0x6a, 0xc6, 0xc7, 0x57, 0x27, 0xae, 0x6a, 0xab, - 0x57, 0x28, 0x03, 0x17, 0xd1, 0x82, 0xc4, 0x00, 0x37, 0x85, 0xe4, 0x3c, 0x86, 0x45, 0xd2, 0xc4, - 0xf3, 0x38, 0x5e, 0xb6, 0x4d, 0x3c, 0x8f, 0x67, 0xeb, 0xae, 0xfc, 0x3c, 0xaa, 0x32, 0x0f, 0x43, - 0x8b, 0x6c, 0xd7, 0x1d, 0xe5, 0x06, 0xfa, 0x9e, 0x02, 0x85, 0xed, 0x89, 0xd8, 0xd8, 0x9e, 0x86, - 0x8d, 0x33, 0x55, 0xc9, 0x58, 0x51, 0x30, 0x36, 0xd0, 0xef, 0x40, 0x8e, 0xd7, 0x18, 0x51, 0x92, - 0x6c, 0x47, 0x6b, 0x98, 0xd5, 0x1b, 0x93, 0x74, 0xe5, 0x93, 0x57, 0xe9, 0xe4, 0x8b, 0x08, 0x49, - 0x93, 0xf3, 0x5a, 0x26, 0xfa, 0x5d, 0x05, 0xf2, 0xa2, 0x7c, 0x80, 0x6e, 0x4c, 0x54, 0x63, 0x60, - 0x0c, 0xbc, 0x3a, 0x45, 0x3d, 0x42, 0xbd, 0x4a, 0x39, 0xb8, 0x84, 0x2e, 0x4a, 0x1c, 0xf8, 0x62, - 0xd6, 0x67, 0x90, 0x65, 0xa5, 0x88, 0x44, 0x2d, 0x1c, 0x29, 0x5f, 0x24, 0x6a, 0xe1, 0x58, 0x5d, - 0x23, 0x4e, 0xf4, 0xfb, 0x6c, 0x3e, 0xb2, 0x78, 0x91, 0xac, 0x4f, 0x5c, 0xfc, 0x58, 0x61, 0x24, - 0x71, 0xf1, 0xe3, 0xd5, 0x8a, 0xd8, 0xc5, 0x8b, 0x62, 0x08, 0x1a, 0xc0, 0xcc, 0x3d, 0xb7, 0xe3, - 0xa3, 0xaf, 0x3c, 0x37, 0x11, 0xcf, 0x66, 0x7e, 0x65, 0xc2, 0x84, 0xbd, 0x7a, 0x99, 0xce, 0xba, - 0x80, 0xe6, 0xa5, 0x59, 0xbf, 0x4d, 0x66, 0x22, 0x47, 0x2f, 0xcc, 0x35, 0x26, 0xea, 0xfc, 0x78, - 0x9e, 0x33, 0x51, 0xe7, 0xcf, 0xa4, 0x2f, 0x63, 0xaf, 0xc2, 0x30, 0x85, 0x49, 0xd9, 0x08, 0xf3, - 0x2f, 0x89, 0x6c, 0x8c, 0x27, 0x8d, 0x12, 0xd9, 0x38, 0x93, 0x37, 0x8a, 0x65, 0x83, 0xe6, 0x8d, - 0x06, 0x64, 0xe2, 0x63, 0xc8, 0x50, 0xef, 0x25, 0xd1, 0x1d, 0x91, 0xeb, 0xf1, 0x89, 0xee, 0xc8, - 0x48, 0xa9, 0x5d, 0x6c, 0xbc, 0x2a, 0xbb, 0x23, 0xb4, 0xe8, 0x79, 0x47, 0xb9, 0xf1, 0xba, 0x82, - 0x9e, 0x42, 0x51, 0x2e, 0x0a, 0x27, 0xde, 0xb3, 0x31, 0x55, 0xf2, 0xea, 0x1b, 0xe7, 0xaa, 0x36, - 0xab, 0x17, 0xd0, 0xef, 0x29, 0x80, 0xce, 0x76, 0x40, 0xb7, 0xa7, 0xa4, 0xf7, 0x82, 0x5c, 0xfc, - 0xa9, 0x02, 0x79, 0x91, 0x46, 0x4c, 0x3c, 0x7c, 0x63, 0x89, 0xe5, 0xc4, 0xc3, 0x37, 0x9e, 0x97, - 0x54, 0xdf, 0xa1, 0x7b, 0xf0, 0xd6, 0xc8, 0xe1, 0xa3, 0xe1, 0x8c, 0xed, 0xf6, 0x9e, 0xac, 0xa0, - 0xe5, 0x18, 0x70, 0xe3, 0x13, 0x11, 0x44, 0x7d, 0x87, 0x38, 0x6c, 0xe5, 0xf1, 0x48, 0x18, 0xad, - 0x4d, 0x15, 0x36, 0x33, 0xa6, 0x6f, 0x9d, 0x23, 0xd4, 0x56, 0xbf, 0x4c, 0x99, 0x5f, 0x46, 0xd7, - 0xc6, 0x9c, 0x0e, 0xdd, 0x94, 0xd9, 0xf9, 0x91, 0x02, 0x0b, 0xeb, 0xb6, 0x3d, 0x1a, 0x19, 0xa3, - 0xd7, 0xa7, 0x08, 0xa2, 0x19, 0x8b, 0x37, 0xa7, 0x0e, 0xbb, 0xd5, 0x97, 0x28, 0x83, 0x57, 0xd1, - 0x15, 0x89, 0x41, 0x16, 0x29, 0x8b, 0xd8, 0x1b, 0x7d, 0xaa, 0x40, 0x51, 0x0e, 0x64, 0x12, 0xd5, - 0x3c, 0x26, 0x10, 0x4a, 0x74, 0x27, 0xe3, 0x22, 0x24, 0xb5, 0x46, 0x99, 0xba, 0x82, 0x2e, 0xcb, - 0xd7, 0x1d, 0xe9, 0xc8, 0xc3, 0x1f, 0xe2, 0x8d, 0x15, 0xe5, 0xc0, 0x32, 0x91, 0xa5, 0x98, 0xc8, - 0x3e, 0x91, 0xa5, 0xb8, 0x88, 0x55, 0xbd, 0x4e, 0x59, 0xfa, 0x92, 0x2a, 0xbb, 0x62, 0x98, 0x75, - 0xd4, 0xa9, 0xb2, 0xdd, 0x51, 0x6e, 0x34, 0x6f, 0x7c, 0xf6, 0x6f, 0xcb, 0x17, 0x3e, 0x3b, 0x5d, - 0x56, 0x7e, 0x76, 0xba, 0xac, 0xfc, 0xfc, 0x74, 0x59, 0xf9, 0xd7, 0xd3, 0x65, 0xe5, 0xd3, 0xcf, - 0x97, 0x2f, 0xfc, 0xec, 0xf3, 0xe5, 0x0b, 0x3f, 0xff, 0x7c, 0xf9, 0xc2, 0x93, 0xbc, 0x98, 0xa5, - 0x93, 0xa5, 0x49, 0xbe, 0x5b, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x3c, 0x60, 0xd7, 0x42, - 0x34, 0x00, 0x00, + 0xe0, 0x68, 0x04, 0x50, 0xde, 0x1c, 0x48, 0x4c, 0xbf, 0xd7, 0xfd, 0xfa, 0xf5, 0xeb, 0xd7, 0xaf, + 0xdf, 0x47, 0xc3, 0x15, 0x1f, 0x7b, 0x47, 0xd8, 0x6b, 0xb0, 0x9f, 0x7e, 0xbb, 0x61, 0x98, 0x3d, + 0xcb, 0xa9, 0xf7, 0x3d, 0x37, 0x70, 0xd1, 0xe5, 0x8e, 0xdb, 0x39, 0xf0, 0x5c, 0xa3, 0xb3, 0x5f, + 0x67, 0xf8, 0xba, 0xe8, 0x56, 0x9d, 0xef, 0xb8, 0xce, 0x9e, 0xd5, 0x6d, 0x7c, 0xec, 0x3a, 0x98, + 0xf5, 0xae, 0x2e, 0x7e, 0xc7, 0x6d, 0xfb, 0x0d, 0xf2, 0xaf, 0xdf, 0xa6, 0x3f, 0x1c, 0x7e, 0x75, + 0x74, 0x0a, 0x3f, 0x30, 0x82, 0x81, 0xc0, 0xaa, 0x7e, 0xe0, 0x7a, 0x46, 0x17, 0x37, 0xb0, 0xd3, + 0xb5, 0x1c, 0xf1, 0xd3, 0x6f, 0x37, 0x7a, 0x47, 0x9d, 0x0e, 0xef, 0xb3, 0x2c, 0xfa, 0xf0, 0xdf, + 0x7e, 0xbb, 0x61, 0x5b, 0x47, 0xd8, 0xc1, 0xbe, 0xa0, 0x72, 0x25, 0xa6, 0x87, 0xdb, 0xe5, 0xc8, + 0xa5, 0xc0, 0x6f, 0x74, 0x8c, 0xc0, 0xb0, 0xdd, 0x6e, 0xa3, 0xb3, 0x6f, 0x78, 0x81, 0xce, 0x5b, + 0x1c, 0x5f, 0x19, 0x04, 0x96, 0xdd, 0xe8, 0xe1, 0xc0, 0xb3, 0x3a, 0xfc, 0x87, 0x63, 0x16, 0xba, + 0x6e, 0xd7, 0xa5, 0x9f, 0x0d, 0xf2, 0x25, 0x16, 0xd4, 0x75, 0xdd, 0xae, 0x8d, 0x1b, 0x46, 0xdf, + 0x6a, 0x18, 0x8e, 0xe3, 0x06, 0x46, 0x60, 0xb9, 0x8e, 0x60, 0xa5, 0xc6, 0xb1, 0xb4, 0xd5, 0x1e, + 0xec, 0x35, 0x02, 0xab, 0x87, 0xfd, 0xc0, 0xe8, 0xf5, 0x59, 0x07, 0x15, 0x41, 0x79, 0xc3, 0x08, + 0x8c, 0xb6, 0xe1, 0x63, 0x5f, 0xc3, 0x87, 0x03, 0xec, 0x07, 0xea, 0x0d, 0x98, 0x97, 0x60, 0x7e, + 0xdf, 0x75, 0x7c, 0x8c, 0xae, 0x42, 0xc1, 0x14, 0xc0, 0x8a, 0xb2, 0x9c, 0x5e, 0x29, 0x68, 0x11, + 0x40, 0xbd, 0x05, 0x8b, 0x62, 0xc8, 0x06, 0x0e, 0x0c, 0xcb, 0x16, 0xc4, 0x50, 0x15, 0xf2, 0xa2, + 0x5b, 0x45, 0x59, 0x56, 0x56, 0x0a, 0x5a, 0xd8, 0x56, 0xff, 0x2a, 0x0d, 0x97, 0xce, 0x0c, 0xe3, + 0xf3, 0x3d, 0x82, 0x6c, 0xd7, 0x33, 0x9c, 0x80, 0x4d, 0x36, 0xb3, 0xfa, 0xf5, 0xfa, 0x33, 0xf7, + 0xbf, 0xfe, 0x0c, 0x1a, 0xf5, 0x2d, 0x42, 0xa0, 0x39, 0xfd, 0xd9, 0x49, 0x6d, 0x4a, 0xe3, 0xd4, + 0x50, 0x0d, 0x66, 0x02, 0xa3, 0x6d, 0x63, 0xdd, 0x31, 0x7a, 0xd8, 0xaf, 0xa4, 0xe8, 0x4a, 0x80, + 0x82, 0xee, 0x13, 0x08, 0x7a, 0x03, 0x4a, 0x26, 0xf6, 0x3b, 0x9e, 0xd5, 0x0f, 0x5c, 0x4f, 0xb7, + 0xcc, 0x4a, 0x7a, 0x59, 0x59, 0x49, 0x37, 0xcb, 0xa7, 0x27, 0xb5, 0xe2, 0x46, 0x88, 0x68, 0x6d, + 0x68, 0xc5, 0xa8, 0x5b, 0xcb, 0x44, 0xeb, 0x30, 0x43, 0xd4, 0x4f, 0x67, 0xaa, 0x58, 0x99, 0x5e, + 0x56, 0x56, 0x66, 0x56, 0xaf, 0x4a, 0x4c, 0x33, 0x44, 0xfd, 0xb1, 0xeb, 0xe0, 0x75, 0xfa, 0xc9, + 0x19, 0x83, 0x8f, 0x43, 0x08, 0xfa, 0x08, 0xe6, 0x25, 0x22, 0xba, 0x8d, 0x8f, 0xb0, 0x5d, 0xc9, + 0x2c, 0x2b, 0x2b, 0xb3, 0xab, 0x37, 0x12, 0xd6, 0x1f, 0xd1, 0x1c, 0x78, 0x74, 0xfb, 0xb7, 0xc9, + 0x40, 0x6d, 0x2e, 0xa2, 0x4c, 0x01, 0xd5, 0xb7, 0x21, 0x43, 0x45, 0x82, 0x10, 0x4c, 0x0f, 0x7c, + 0xec, 0xf1, 0x0d, 0xa1, 0xdf, 0x68, 0x09, 0xa0, 0xef, 0x59, 0x47, 0x96, 0x8d, 0xbb, 0x91, 0x5c, + 0x22, 0x88, 0xba, 0x05, 0x17, 0x76, 0x89, 0x94, 0xc6, 0xdf, 0x5f, 0xb4, 0x00, 0x19, 0x2a, 0xd8, + 0x4a, 0x8a, 0x22, 0x58, 0x43, 0xfd, 0x9f, 0x1c, 0x2c, 0x0c, 0x53, 0xe2, 0x5b, 0xbe, 0x33, 0xb2, + 0xe5, 0x6f, 0x24, 0x2c, 0x39, 0x8e, 0x40, 0xec, 0x7e, 0x3f, 0x82, 0x5c, 0xc7, 0xb5, 0x07, 0x3d, + 0x87, 0xad, 0x69, 0x66, 0xf5, 0xcd, 0x49, 0xa9, 0xae, 0xd3, 0xe1, 0x9c, 0xac, 0x20, 0x86, 0x1e, + 0x42, 0xce, 0x72, 0x4c, 0xfc, 0x14, 0xfb, 0x95, 0xf4, 0xf9, 0xb8, 0x6d, 0x91, 0xe1, 0x82, 0x2c, + 0xa7, 0x45, 0xd4, 0xd3, 0x33, 0x9c, 0x2e, 0x51, 0x81, 0x81, 0x13, 0x50, 0x35, 0x4a, 0x6b, 0x40, + 0x41, 0xeb, 0x04, 0x82, 0x6e, 0xc1, 0x62, 0xc7, 0xc3, 0x46, 0x80, 0x75, 0xa6, 0xc6, 0xc4, 0x7e, + 0xe1, 0x1e, 0x76, 0x02, 0xaa, 0x27, 0x05, 0x6d, 0x81, 0x61, 0xe9, 0x8c, 0x3b, 0x02, 0x37, 0xaa, + 0x9d, 0xd9, 0x5f, 0x9f, 0x76, 0xe6, 0x7e, 0x5d, 0xda, 0x79, 0xf6, 0xe0, 0xe5, 0xc7, 0x39, 0x78, + 0x2f, 0xa4, 0xd4, 0xd5, 0x7f, 0x50, 0x20, 0xcb, 0xf6, 0x97, 0x0c, 0x27, 0x26, 0x41, 0x0c, 0x27, + 0xdf, 0x04, 0x16, 0x1c, 0xf7, 0x85, 0xfe, 0xd2, 0x6f, 0xa2, 0xf0, 0xce, 0xc0, 0xb6, 0xa9, 0x5e, + 0x13, 0xd3, 0x90, 0xd7, 0xc2, 0x36, 0xba, 0x46, 0x96, 0xb0, 0x67, 0x0c, 0xec, 0x40, 0x3f, 0x32, + 0xec, 0x01, 0xa6, 0xfb, 0x57, 0x20, 0x0c, 0x53, 0xe0, 0x23, 0x02, 0x43, 0x37, 0xe1, 0x62, 0x17, + 0x3b, 0x98, 0xc9, 0x42, 0xc7, 0x4f, 0xfb, 0x1e, 0xf6, 0x7d, 0xcb, 0x75, 0xc4, 0x06, 0x46, 0xc8, + 0xcd, 0x10, 0x87, 0x16, 0x21, 0xbb, 0x6f, 0x99, 0x26, 0x76, 0xe8, 0xde, 0xe5, 0x35, 0xde, 0xaa, + 0xfe, 0x8d, 0x02, 0x19, 0xaa, 0x48, 0xb1, 0xfc, 0x2f, 0x42, 0x76, 0xe0, 0x58, 0x87, 0x03, 0xb6, + 0x82, 0xbc, 0xc6, 0x5b, 0xa8, 0x0c, 0x69, 0x1f, 0x1f, 0x32, 0xcb, 0xa6, 0x91, 0x4f, 0xd2, 0x93, + 0x69, 0x36, 0x67, 0x99, 0xb7, 0xa8, 0xd9, 0xb7, 0x3c, 0xdc, 0x09, 0x22, 0x06, 0x23, 0x00, 0xaa, + 0x40, 0x8e, 0xdc, 0x71, 0x96, 0xd3, 0xe5, 0x6c, 0x89, 0x26, 0x91, 0x92, 0xd5, 0xeb, 0xdb, 0x56, + 0xc7, 0x0a, 0xa8, 0x8a, 0xe4, 0xb5, 0xb0, 0xad, 0x6e, 0xc2, 0x7c, 0xa8, 0x9e, 0x2f, 0x60, 0x47, + 0xfe, 0x36, 0x0d, 0x48, 0xa6, 0xc3, 0xad, 0xc8, 0xc8, 0x09, 0x52, 0xce, 0x9c, 0xa0, 0x6b, 0x50, + 0xf2, 0x30, 0x61, 0xc5, 0xe0, 0x5d, 0x52, 0xb4, 0x4b, 0x91, 0x03, 0x59, 0xa7, 0x2f, 0x01, 0x38, + 0xae, 0x29, 0x88, 0x30, 0x41, 0x15, 0x08, 0x84, 0xa1, 0xdf, 0x85, 0x0c, 0x39, 0x78, 0x3e, 0xb7, + 0xf3, 0xaf, 0xc9, 0xea, 0xcf, 0x2e, 0xfd, 0x3a, 0xf3, 0x1d, 0xea, 0xc2, 0x85, 0xa8, 0xdf, 0x7b, + 0xb4, 0xbe, 0x4e, 0x39, 0xe5, 0x27, 0x8b, 0x11, 0x40, 0x26, 0x94, 0x7a, 0x96, 0xef, 0x5b, 0x4e, + 0x57, 0x27, 0xe4, 0xfd, 0x4a, 0x86, 0x5a, 0x93, 0xdf, 0x78, 0x9e, 0x35, 0x19, 0x5a, 0x74, 0xfd, + 0x1e, 0x23, 0x71, 0xdf, 0x35, 0x31, 0x27, 0x5f, 0xec, 0x45, 0x20, 0x9f, 0x58, 0x0d, 0xa3, 0xdf, + 0xf7, 0xdc, 0xa7, 0x56, 0x8f, 0x98, 0x0e, 0xd3, 0xf2, 0x0f, 0xf4, 0xf6, 0x71, 0x80, 0x7d, 0xba, + 0x6f, 0xd3, 0xda, 0x82, 0x84, 0xdd, 0xb0, 0xfc, 0x83, 0x26, 0xc1, 0x55, 0x3f, 0x84, 0x19, 0x89, + 0x30, 0xba, 0x06, 0x39, 0x2a, 0x13, 0xcb, 0x64, 0x3b, 0xd4, 0x84, 0xd3, 0x93, 0x5a, 0x96, 0xa0, + 0x5a, 0x1b, 0x5a, 0x96, 0xa0, 0x5a, 0x26, 0x91, 0x2e, 0xf6, 0x3c, 0xd7, 0xd3, 0x7b, 0xd8, 0xf7, + 0x8d, 0xae, 0xd8, 0xb3, 0x22, 0x05, 0xde, 0x63, 0x30, 0x75, 0x11, 0x16, 0xee, 0xbb, 0xce, 0x19, + 0x25, 0x50, 0x7f, 0xae, 0xc0, 0xc5, 0x11, 0x04, 0xdf, 0xd5, 0x6f, 0xc2, 0x3c, 0x71, 0x5d, 0x74, + 0x1f, 0x7b, 0x16, 0xf6, 0x75, 0x26, 0x7c, 0x85, 0x0a, 0xff, 0x6b, 0x13, 0x89, 0x4a, 0x9b, 0x23, + 0x74, 0x76, 0x28, 0x19, 0x8a, 0x40, 0xdf, 0x02, 0x64, 0x39, 0x01, 0xf6, 0x1c, 0xc3, 0xd6, 0x07, + 0x3e, 0xe6, 0xb4, 0x53, 0xe7, 0xa1, 0x5d, 0x16, 0x84, 0x1e, 0xfa, 0x0c, 0xa3, 0xce, 0x42, 0xf1, + 0xa1, 0x8f, 0xbd, 0x70, 0x85, 0xdf, 0x83, 0x12, 0x6f, 0xf3, 0x85, 0xb5, 0x20, 0x43, 0x2c, 0x95, + 0xb8, 0xf3, 0x92, 0x26, 0x1c, 0x1a, 0x48, 0x5b, 0x42, 0x95, 0x28, 0x85, 0xaa, 0x0a, 0xd3, 0x04, + 0x48, 0x8e, 0x12, 0x01, 0x48, 0xd6, 0x20, 0x6c, 0xab, 0x3f, 0x54, 0xa0, 0xb4, 0x79, 0x84, 0x9d, + 0xe8, 0xe0, 0x09, 0x1b, 0xa7, 0x48, 0x36, 0xee, 0x0a, 0x14, 0x02, 0xc3, 0xeb, 0xe2, 0x80, 0xec, + 0x35, 0x3b, 0x1e, 0x79, 0x06, 0x68, 0x99, 0xe4, 0x34, 0xda, 0x56, 0xcf, 0x62, 0xa7, 0x22, 0xa3, + 0xb1, 0x06, 0x7a, 0x15, 0xe6, 0x07, 0x8e, 0x87, 0x4d, 0xa3, 0x13, 0x60, 0x53, 0xc7, 0x74, 0x0a, + 0x7a, 0x3a, 0xf2, 0x5a, 0x39, 0x42, 0xb0, 0xa9, 0xd5, 0xff, 0x4c, 0xc1, 0xac, 0xe0, 0x82, 0xcb, + 0xe1, 0x1e, 0x64, 0xf9, 0x20, 0x26, 0x88, 0x46, 0x82, 0x20, 0x86, 0x87, 0xb2, 0xa6, 0xb8, 0xf6, + 0x19, 0x91, 0xea, 0x1f, 0xa4, 0x20, 0x43, 0xe1, 0xa8, 0x09, 0x85, 0xd0, 0xe9, 0xe5, 0x1a, 0x53, + 0xad, 0x33, 0xb7, 0xb8, 0x2e, 0xdc, 0xe2, 0xfa, 0xae, 0xe8, 0xd1, 0xcc, 0x13, 0x32, 0x9f, 0xfe, + 0xaa, 0xa6, 0x68, 0xd1, 0x30, 0x62, 0x0d, 0x28, 0x5d, 0x5d, 0xba, 0x0d, 0x0a, 0x14, 0xb2, 0x4b, + 0xc4, 0xf5, 0x55, 0x59, 0x5c, 0xcc, 0x5d, 0x2c, 0x9e, 0x9e, 0xd4, 0xf2, 0xbb, 0x4c, 0x64, 0x1b, + 0x92, 0xf0, 0x56, 0x81, 0xd8, 0x19, 0xd7, 0x0b, 0xc8, 0x81, 0xb7, 0x4c, 0x76, 0xc1, 0x37, 0xe7, + 0x4e, 0x4f, 0x6a, 0x33, 0x9a, 0x80, 0xb7, 0x36, 0xb4, 0x99, 0xb0, 0x53, 0xcb, 0x24, 0x3b, 0x64, + 0x39, 0x7b, 0x2e, 0x37, 0xbf, 0xf4, 0x9b, 0x4c, 0xc9, 0x6c, 0x39, 0x21, 0x42, 0xce, 0x70, 0x91, + 0x4d, 0xf9, 0x90, 0x02, 0xc9, 0x94, 0x0c, 0xdd, 0x32, 0xd5, 0xbf, 0x56, 0xa0, 0xbc, 0x83, 0x83, + 0x87, 0x2d, 0xe2, 0x26, 0x8b, 0x5d, 0xff, 0x26, 0xc0, 0x01, 0x3e, 0x66, 0xb7, 0x94, 0x10, 0xf9, + 0xed, 0x04, 0x91, 0x8f, 0x12, 0xa8, 0xbf, 0x87, 0x8f, 0xe9, 0x75, 0xe6, 0x6f, 0x3a, 0x81, 0x77, + 0xac, 0x15, 0x0e, 0x44, 0xbb, 0x7a, 0x07, 0x66, 0x87, 0x91, 0xe4, 0xba, 0x39, 0xc0, 0xc7, 0x5c, + 0xc3, 0xc8, 0x27, 0xd1, 0x21, 0x76, 0x41, 0x12, 0x59, 0x16, 0x35, 0xd6, 0xb8, 0x9d, 0xfa, 0xba, + 0xa2, 0x5e, 0x80, 0x79, 0x69, 0x2e, 0xb6, 0xc3, 0xea, 0x57, 0xa0, 0xbc, 0x35, 0xba, 0x02, 0x04, + 0xd3, 0x07, 0xf8, 0x58, 0xc4, 0x22, 0xf4, 0x5b, 0xfd, 0x79, 0x0a, 0xe6, 0xb7, 0x46, 0x47, 0xa3, + 0xdf, 0x89, 0x59, 0xeb, 0xdb, 0x09, 0x6b, 0x3d, 0x43, 0x61, 0x64, 0xb1, 0x5c, 0xd5, 0xa4, 0x25, + 0xef, 0x41, 0x86, 0xdd, 0xed, 0xe1, 0xba, 0x14, 0x69, 0x5d, 0x68, 0x0b, 0x8a, 0xb6, 0xe1, 0x07, + 0xfa, 0xa0, 0x6f, 0x1a, 0x01, 0x36, 0xb9, 0x6d, 0x19, 0x4f, 0x0b, 0x67, 0xc8, 0xc8, 0x87, 0x6c, + 0x60, 0xb5, 0x3f, 0x86, 0x68, 0xdf, 0x95, 0x45, 0x3b, 0xb3, 0xba, 0x3a, 0xd1, 0x42, 0x29, 0x69, + 0x79, 0x3b, 0xca, 0x30, 0xbb, 0x6e, 0x0f, 0xfc, 0x00, 0x7b, 0xc2, 0x82, 0xfd, 0x54, 0x81, 0xb9, + 0x10, 0xc4, 0x25, 0xfc, 0x1a, 0x40, 0x87, 0x81, 0xa2, 0xcb, 0xa1, 0x74, 0x7a, 0x52, 0x2b, 0xf0, + 0x8e, 0xad, 0x0d, 0xad, 0xc0, 0x3b, 0xb4, 0x4c, 0x62, 0x2a, 0xa2, 0x33, 0x80, 0x1d, 0x62, 0x46, + 0x4d, 0xee, 0xa0, 0x94, 0x43, 0xc4, 0x26, 0x83, 0xa3, 0xaf, 0x01, 0xc2, 0xc4, 0xa8, 0xf6, 0x3d, + 0xcb, 0xc7, 0x61, 0x6f, 0xe6, 0x78, 0xcd, 0x47, 0x18, 0xde, 0x5d, 0xdd, 0x86, 0xe2, 0x86, 0x67, + 0x58, 0x8e, 0xd0, 0x92, 0x59, 0x48, 0xb9, 0x0e, 0xdd, 0xf3, 0x8c, 0x96, 0x72, 0x1d, 0x22, 0x2f, + 0x77, 0x6f, 0x8f, 0x7a, 0x82, 0x19, 0x8d, 0x7c, 0x12, 0x6b, 0xe9, 0xef, 0x0f, 0x02, 0xd3, 0x7d, + 0xe2, 0x08, 0x7f, 0x4e, 0xb4, 0xd5, 0x1a, 0x94, 0x38, 0x35, 0xbe, 0xd0, 0x11, 0x72, 0xea, 0xc7, + 0x70, 0x79, 0x03, 0x77, 0xdc, 0x1e, 0xbd, 0x6c, 0x5d, 0x67, 0x87, 0x26, 0x13, 0xc4, 0xdc, 0x1f, + 0x41, 0x9e, 0xdf, 0x97, 0x4c, 0xeb, 0x32, 0xcd, 0xe6, 0xe9, 0x49, 0x2d, 0xc7, 0x2e, 0x4c, 0xff, + 0xbf, 0x4f, 0x6a, 0x37, 0xbb, 0x56, 0xb0, 0x3f, 0x68, 0xd7, 0x3b, 0x6e, 0xaf, 0x11, 0xee, 0x92, + 0xd9, 0x8e, 0xbe, 0x1b, 0xfd, 0x83, 0x6e, 0x83, 0x7e, 0xf5, 0xdb, 0x75, 0x7e, 0xd1, 0xe6, 0xd8, + 0x45, 0xeb, 0xab, 0x7f, 0xac, 0xc0, 0x05, 0x79, 0xf2, 0xff, 0x9f, 0x69, 0xd1, 0x0a, 0xcc, 0x99, + 0xd2, 0xac, 0xc4, 0xf7, 0x63, 0x7b, 0x37, 0x0a, 0x56, 0x3f, 0x4f, 0x41, 0x35, 0x4e, 0x3a, 0x5c, + 0x96, 0x8f, 0x21, 0xcb, 0x92, 0x2f, 0x3c, 0x30, 0xbb, 0x93, 0x14, 0xe1, 0x3f, 0x93, 0x4c, 0x9d, + 0x35, 0x85, 0xf9, 0x67, 0x14, 0xab, 0xff, 0xa1, 0x40, 0x96, 0x21, 0xd0, 0xe3, 0x61, 0xaf, 0x25, + 0xd3, 0x5c, 0x8b, 0xbc, 0x96, 0xf3, 0x0a, 0x43, 0x38, 0x3b, 0x97, 0x20, 0x67, 0xf9, 0xba, 0x6d, + 0x1d, 0x85, 0x0e, 0xb6, 0xe5, 0x6f, 0x5b, 0x47, 0xf8, 0xac, 0x8f, 0x99, 0x8e, 0xf1, 0x31, 0x63, + 0x24, 0x39, 0x1d, 0x2b, 0x49, 0xea, 0x1c, 0x13, 0x3d, 0x24, 0x5d, 0x32, 0x4c, 0x47, 0x45, 0x5b, + 0x7d, 0x19, 0xe6, 0x76, 0x70, 0x40, 0x8e, 0x8c, 0x9f, 0x64, 0x1a, 0xff, 0x2e, 0x45, 0x6f, 0x01, + 0xde, 0x8f, 0x6f, 0x81, 0x3e, 0xf9, 0x2d, 0x30, 0x44, 0xe0, 0xb9, 0x86, 0x71, 0x27, 0xd6, 0x30, + 0x16, 0x84, 0x61, 0x8c, 0x8b, 0xaf, 0x96, 0x61, 0x46, 0xc4, 0x77, 0x24, 0xe6, 0x48, 0x53, 0x94, + 0x0c, 0xaa, 0xba, 0x63, 0x58, 0xc1, 0xad, 0x61, 0x2b, 0x78, 0x63, 0x92, 0x45, 0x9d, 0x31, 0x82, + 0x73, 0x50, 0x7a, 0x17, 0x1b, 0x76, 0xb0, 0x2f, 0x6c, 0x60, 0x19, 0x66, 0x05, 0x80, 0xdf, 0x50, + 0xf3, 0x30, 0xb7, 0xcd, 0xb3, 0x80, 0xa2, 0xd3, 0xcf, 0x52, 0x50, 0x8e, 0x60, 0x5c, 0xe2, 0x6b, + 0x00, 0x22, 0x5b, 0x18, 0x4a, 0xfc, 0x4a, 0x4c, 0xf4, 0x20, 0x06, 0x8a, 0x30, 0x3c, 0x1a, 0x84, + 0xfe, 0x48, 0x81, 0x3c, 0x53, 0x73, 0x2c, 0x8e, 0x4e, 0x52, 0xb4, 0x30, 0xca, 0x02, 0x3f, 0x30, + 0x62, 0xcb, 0xde, 0x26, 0xf4, 0x7f, 0xf0, 0xab, 0xf3, 0x9d, 0x83, 0x90, 0x8f, 0x6a, 0x1b, 0x4a, + 0x43, 0x74, 0xe5, 0x2d, 0xc9, 0xb0, 0x2d, 0x79, 0x5b, 0xde, 0x92, 0xd9, 0xd5, 0x97, 0x63, 0x56, + 0x4d, 0xc8, 0x0a, 0x7e, 0xf9, 0x31, 0x97, 0xb6, 0xa1, 0x0f, 0x33, 0x77, 0xdd, 0x76, 0xa8, 0xe5, + 0xa1, 0x1f, 0xaa, 0xc8, 0x7e, 0xe8, 0xa2, 0x64, 0x55, 0x68, 0x20, 0xcb, 0x5a, 0xe8, 0x26, 0x57, + 0xb5, 0x34, 0x9d, 0xbc, 0x26, 0x4f, 0x7e, 0x68, 0xd7, 0x69, 0x86, 0x98, 0x65, 0x8b, 0xeb, 0xc4, + 0xa5, 0x63, 0xba, 0xa8, 0xfe, 0x2c, 0x0b, 0x45, 0x36, 0x25, 0xdf, 0xbe, 0x4d, 0x98, 0x26, 0xbd, + 0xf8, 0xc6, 0xbd, 0x9a, 0x20, 0x76, 0x79, 0x18, 0x69, 0xf0, 0x8d, 0xa4, 0xc3, 0xab, 0xff, 0x95, + 0x81, 0xf4, 0x5d, 0xb7, 0x8d, 0x16, 0x21, 0xc5, 0xcd, 0x52, 0xba, 0x99, 0x3d, 0x3d, 0xa9, 0xa5, + 0x5a, 0x1b, 0x5a, 0xca, 0x32, 0xcf, 0x77, 0x2e, 0x86, 0xfc, 0xfe, 0xe9, 0x61, 0xbf, 0x1f, 0xb9, + 0x30, 0x3b, 0x94, 0x5c, 0x61, 0x71, 0x66, 0xa9, 0xf9, 0xee, 0xe9, 0x49, 0xad, 0x24, 0x67, 0x57, + 0xc6, 0xbf, 0x20, 0xfc, 0x43, 0x9b, 0xfc, 0x91, 0x08, 0xbd, 0xde, 0xda, 0xd0, 0x4a, 0x72, 0x56, + 0xc6, 0x97, 0xf6, 0x21, 0x3b, 0xb4, 0x0f, 0xb7, 0x21, 0xc7, 0x32, 0x54, 0x26, 0xcd, 0x0b, 0x24, + 0xbb, 0x41, 0xd3, 0xd4, 0x05, 0x12, 0x03, 0xc8, 0x58, 0x3f, 0x30, 0x3c, 0x32, 0x36, 0x3f, 0xee, + 0x58, 0x3e, 0x00, 0xdd, 0x81, 0xfc, 0x9e, 0xe5, 0x58, 0xfe, 0x3e, 0x36, 0x2b, 0x85, 0x31, 0x07, + 0x87, 0x23, 0xc8, 0xe8, 0x9e, 0x6b, 0x5a, 0x7b, 0x16, 0x36, 0x2b, 0x30, 0xee, 0x68, 0x31, 0x82, + 0xf8, 0x30, 0x7b, 0x9e, 0x41, 0x53, 0x26, 0x7a, 0xc7, 0xed, 0xf5, 0x6d, 0x4c, 0x96, 0x30, 0xb3, + 0xac, 0xac, 0xa4, 0xb4, 0x79, 0x81, 0x59, 0x17, 0x08, 0xa2, 0xd8, 0x34, 0x5a, 0xae, 0x14, 0x99, + 0xad, 0xa4, 0x0d, 0xf4, 0x00, 0x2e, 0xec, 0x5b, 0xdd, 0xfd, 0x27, 0x06, 0xf1, 0xb2, 0xa2, 0x88, + 0xa6, 0x34, 0x26, 0x37, 0x28, 0x1c, 0x1c, 0x62, 0x88, 0x23, 0x16, 0x91, 0x34, 0x71, 0xc7, 0xea, + 0x19, 0x76, 0x65, 0x96, 0x4e, 0x5a, 0x0e, 0x11, 0x1b, 0x0c, 0x8e, 0x5e, 0x86, 0x59, 0x6f, 0xe0, + 0x90, 0x2b, 0x47, 0xe7, 0x1b, 0x3b, 0x47, 0x7b, 0x96, 0x38, 0x94, 0x5f, 0xb7, 0x57, 0xa1, 0x10, + 0xa5, 0x24, 0xcb, 0x2c, 0x52, 0x0a, 0x01, 0x2a, 0x82, 0xf2, 0xb6, 0xdb, 0x61, 0x25, 0x0a, 0x61, + 0x27, 0xff, 0x57, 0x81, 0x79, 0x09, 0x18, 0x06, 0xfc, 0x05, 0x5b, 0x00, 0xc7, 0xc8, 0x07, 0x9f, + 0x21, 0x10, 0x42, 0xc4, 0xa5, 0x14, 0x52, 0xab, 0xfe, 0xa1, 0x02, 0x79, 0x81, 0x45, 0x2f, 0x41, + 0x91, 0x60, 0x6c, 0x2b, 0x38, 0xd6, 0xa3, 0x3b, 0x64, 0x46, 0xc0, 0xde, 0xc3, 0xc7, 0x64, 0xe5, + 0x61, 0x97, 0xc8, 0x82, 0x15, 0xb4, 0x92, 0x80, 0xb2, 0x2b, 0xae, 0x0a, 0x79, 0xdb, 0x08, 0xac, + 0x60, 0x60, 0x32, 0x2b, 0xa3, 0x68, 0x61, 0x9b, 0x48, 0xc5, 0x76, 0x9d, 0x2e, 0x43, 0x4e, 0x53, + 0x64, 0x04, 0x50, 0x9b, 0x30, 0xa7, 0x19, 0x4e, 0x17, 0x6f, 0xbb, 0x5d, 0x61, 0xdc, 0x2e, 0x43, + 0x9e, 0x65, 0xb1, 0x84, 0x7d, 0xd0, 0x72, 0xb4, 0x2d, 0xc7, 0xdf, 0x29, 0xc9, 0xee, 0xa9, 0xff, + 0x92, 0x86, 0x72, 0x44, 0x84, 0x0b, 0xf1, 0xfd, 0x30, 0xa8, 0x66, 0xf7, 0x44, 0xd2, 0x35, 0x38, + 0x3a, 0x38, 0x36, 0xac, 0xfe, 0x47, 0x05, 0xe0, 0x03, 0x0f, 0x07, 0xc1, 0x71, 0x8b, 0x44, 0xa1, + 0x2f, 0x41, 0x91, 0xc7, 0x34, 0x3a, 0x39, 0xfd, 0x42, 0x78, 0x1c, 0x46, 0xcc, 0x0a, 0x59, 0x88, + 0x83, 0x9f, 0x30, 0x34, 0x13, 0x5b, 0xce, 0xc1, 0x4f, 0x28, 0xea, 0x1a, 0x94, 0x0c, 0xd3, 0xc4, + 0xa6, 0xce, 0xbd, 0x22, 0x6e, 0xd3, 0x8a, 0x14, 0xa8, 0x31, 0x18, 0x7a, 0x05, 0xe6, 0x3c, 0xdc, + 0x73, 0x8f, 0xa4, 0x6e, 0xcc, 0xb6, 0xcd, 0x72, 0xb0, 0xe8, 0xb8, 0x08, 0x59, 0x0f, 0x1b, 0x7e, + 0x98, 0xa6, 0xe4, 0x2d, 0x54, 0x81, 0x9c, 0xc9, 0x32, 0xef, 0xdc, 0x12, 0x89, 0x66, 0xf5, 0xcf, + 0x14, 0x91, 0x23, 0xb8, 0x03, 0x19, 0xba, 0x40, 0x9e, 0x1f, 0x58, 0x8e, 0xb9, 0x9a, 0x84, 0x78, + 0x64, 0xa9, 0xb0, 0x41, 0xe8, 0x23, 0x98, 0xe9, 0x53, 0x99, 0xe8, 0x34, 0x4c, 0x67, 0x1e, 0xc7, + 0x9b, 0x93, 0x88, 0x3a, 0x12, 0xa9, 0xb8, 0xef, 0xfb, 0x21, 0xe4, 0xee, 0x74, 0x5e, 0x29, 0xa7, + 0xd4, 0x15, 0x28, 0x3f, 0x18, 0x60, 0xef, 0xf8, 0x03, 0xdb, 0x70, 0xa4, 0x1b, 0xf0, 0x90, 0xc0, + 0x84, 0x53, 0x45, 0x1b, 0x6a, 0x1f, 0xe6, 0xa5, 0x9e, 0x5c, 0x13, 0xbe, 0x05, 0x57, 0x4c, 0xcb, + 0x0f, 0xfc, 0x43, 0x5b, 0xef, 0xef, 0x1f, 0xfb, 0x56, 0xc7, 0xb0, 0x75, 0xda, 0x5d, 0xef, 0xdb, + 0x86, 0xc3, 0x43, 0xb6, 0xab, 0xa7, 0x27, 0xb5, 0xca, 0x86, 0xe5, 0x07, 0x3b, 0x0f, 0xb6, 0x3f, + 0xe0, 0xbd, 0x22, 0x52, 0x15, 0x4e, 0xe0, 0x0c, 0x46, 0xbd, 0xcc, 0xca, 0x78, 0x64, 0xa4, 0x67, + 0xb5, 0x07, 0x41, 0x14, 0x8c, 0xa8, 0x7f, 0x09, 0x50, 0x39, 0x8b, 0xe3, 0x4c, 0xf5, 0xa1, 0x24, + 0x72, 0xbc, 0x4c, 0x74, 0xec, 0x9c, 0x6f, 0x3e, 0xa7, 0xd4, 0x17, 0x47, 0x2b, 0xac, 0x01, 0x12, + 0x91, 0xc9, 0xce, 0x68, 0xd1, 0x94, 0x10, 0xa8, 0x07, 0x45, 0xa9, 0x84, 0x21, 0x4a, 0x37, 0x1b, + 0xe7, 0x99, 0x30, 0x2a, 0x6b, 0x0c, 0x39, 0xbf, 0x33, 0x51, 0x59, 0xc3, 0xaf, 0xfe, 0x44, 0x01, + 0x88, 0xfa, 0x11, 0x15, 0x65, 0x89, 0x20, 0xbe, 0x61, 0xbc, 0x85, 0x6e, 0x43, 0x96, 0x17, 0x66, + 0x52, 0x63, 0x17, 0x66, 0xf8, 0x08, 0x1a, 0x7a, 0xb3, 0x7a, 0x8c, 0x7f, 0x68, 0xb3, 0xa3, 0xc1, + 0x43, 0x6f, 0x0a, 0xdd, 0x79, 0xb0, 0xad, 0x15, 0x58, 0x87, 0x9d, 0x43, 0xfb, 0xee, 0x74, 0x3e, + 0x5d, 0x9e, 0xae, 0xfe, 0x28, 0x0d, 0x05, 0x9a, 0xbd, 0xa4, 0x32, 0xf9, 0x4c, 0x81, 0xca, 0x50, + 0xb0, 0xa2, 0xb7, 0x8f, 0xf5, 0x28, 0x64, 0x22, 0x02, 0xfa, 0xf0, 0x3c, 0x02, 0x0a, 0x67, 0xa8, + 0x6b, 0x52, 0xd4, 0xd3, 0x3c, 0xa6, 0xbe, 0xa3, 0xc9, 0x64, 0xf6, 0xd6, 0x79, 0x3d, 0xcf, 0x05, + 0x2f, 0x86, 0x26, 0xfa, 0x32, 0xcc, 0xca, 0x15, 0xaa, 0x30, 0x79, 0x59, 0x8c, 0x36, 0xa5, 0x65, + 0xa2, 0x6f, 0x00, 0x98, 0x9e, 0xdb, 0xef, 0x63, 0x53, 0x37, 0x58, 0x64, 0x36, 0xce, 0x05, 0x5a, + 0xe0, 0x63, 0xd6, 0x82, 0xea, 0x16, 0x5c, 0x7e, 0xe6, 0x92, 0x62, 0x1c, 0xdf, 0xa1, 0x64, 0x57, + 0x5a, 0xf2, 0x68, 0xab, 0xdf, 0x4f, 0x41, 0x51, 0x56, 0x5c, 0x14, 0x00, 0x2b, 0x45, 0xcb, 0xc7, + 0xe1, 0xfd, 0x17, 0x3d, 0x0e, 0xd1, 0x4e, 0x0c, 0x45, 0x69, 0x81, 0x80, 0x56, 0x3f, 0x81, 0xd9, + 0xe1, 0x2e, 0x31, 0x01, 0xd5, 0xce, 0x70, 0x40, 0xf5, 0xce, 0x0b, 0x69, 0xc4, 0x90, 0x0c, 0x94, + 0xe8, 0xb9, 0x41, 0x12, 0x03, 0x8f, 0x86, 0x19, 0xf8, 0xad, 0x17, 0x95, 0x8a, 0xcc, 0xc3, 0xf7, + 0xa0, 0x3c, 0x7a, 0x9c, 0x63, 0x38, 0xd8, 0x1d, 0xe6, 0xe0, 0x37, 0x5f, 0xcc, 0x6a, 0x48, 0xf3, + 0xdf, 0x9d, 0xce, 0xa7, 0xca, 0x69, 0xf5, 0x12, 0x5c, 0xbc, 0x47, 0x1f, 0x7c, 0xdc, 0xc3, 0x81, + 0x61, 0x46, 0xa9, 0x4e, 0xf5, 0x9f, 0x15, 0x58, 0x1c, 0xc5, 0x70, 0x13, 0x6a, 0x40, 0xbe, 0xc7, + 0x61, 0x5c, 0x5d, 0xbe, 0x91, 0xc0, 0x56, 0x3c, 0x91, 0xba, 0x00, 0xc8, 0xea, 0x11, 0x92, 0xad, + 0xfe, 0x36, 0x94, 0x86, 0x3a, 0xc4, 0x48, 0xe6, 0x8d, 0x61, 0xc9, 0xc8, 0xd1, 0xd5, 0x20, 0xb0, + 0xec, 0x3a, 0x7f, 0xc7, 0x12, 0x4e, 0x2c, 0x05, 0x75, 0x3f, 0x4e, 0xc1, 0x85, 0x4d, 0xe7, 0x70, + 0x80, 0x07, 0x98, 0x5e, 0x8b, 0xe2, 0x6e, 0xfb, 0x22, 0xd3, 0x36, 0xec, 0xde, 0x0c, 0xfd, 0x38, + 0xd6, 0x40, 0xdf, 0x96, 0x5c, 0x2e, 0x5a, 0xda, 0x68, 0xae, 0x9f, 0x9e, 0xd4, 0x72, 0x94, 0x2b, + 0x3a, 0xe7, 0xad, 0x89, 0xe6, 0xe4, 0xe3, 0x22, 0xbf, 0xed, 0x3a, 0xcc, 0xfb, 0x07, 0x56, 0x5f, + 0xf7, 0xf7, 0xdd, 0x81, 0x6d, 0xea, 0x8c, 0x03, 0x9e, 0xf0, 0x21, 0x88, 0x1d, 0x0a, 0x7f, 0x40, + 0xc0, 0xea, 0x9f, 0xa7, 0x60, 0x61, 0x58, 0x2a, 0x7c, 0xbf, 0x1f, 0x44, 0xde, 0x0c, 0xdb, 0xee, + 0xb7, 0x92, 0xea, 0x24, 0x31, 0x14, 0xea, 0xe2, 0x19, 0x42, 0xe8, 0x06, 0xfd, 0xbd, 0x02, 0x39, + 0x0e, 0xfc, 0x42, 0xa5, 0xfe, 0xce, 0x88, 0x33, 0xfa, 0x72, 0x52, 0x6d, 0xcd, 0x33, 0x3a, 0x98, + 0xba, 0x5a, 0xc2, 0xf5, 0x8c, 0xa2, 0xa2, 0xb4, 0x14, 0x15, 0xa9, 0x17, 0xe1, 0xc2, 0xfa, 0xbe, + 0xe1, 0x05, 0xeb, 0xec, 0x11, 0x95, 0x38, 0x31, 0x8f, 0x61, 0x61, 0x18, 0xcc, 0xc5, 0xd7, 0x84, + 0x1c, 0x7f, 0x6e, 0xc5, 0xc5, 0xa7, 0x4a, 0x4c, 0x04, 0x7e, 0x5d, 0xbc, 0xc5, 0xa2, 0x83, 0x77, + 0x58, 0x95, 0x3b, 0x7c, 0xf9, 0xc1, 0x70, 0xd7, 0xdf, 0x83, 0xc5, 0xf8, 0x27, 0x0d, 0x68, 0x06, + 0x72, 0x0f, 0xef, 0xbf, 0x77, 0xff, 0xfd, 0x0f, 0xef, 0x97, 0xa7, 0x48, 0x63, 0x7d, 0xfb, 0xe1, + 0xce, 0xee, 0xa6, 0x56, 0x56, 0x50, 0x11, 0xf2, 0x1b, 0x6b, 0xbb, 0x6b, 0xcd, 0xb5, 0x9d, 0xcd, + 0x72, 0x0a, 0x15, 0x20, 0xb3, 0xbb, 0xd6, 0xdc, 0xde, 0x2c, 0xa7, 0xaf, 0x5f, 0x83, 0x02, 0xcd, + 0x30, 0xdf, 0x73, 0x4d, 0x8c, 0x00, 0xb2, 0xeb, 0xdb, 0xad, 0xcd, 0xfb, 0xbb, 0xe5, 0x29, 0xf2, + 0xbd, 0xbd, 0xb9, 0xb6, 0xb3, 0xb9, 0x53, 0x56, 0x56, 0x7f, 0x54, 0x85, 0xcc, 0x9a, 0xd9, 0xb3, + 0x1c, 0x14, 0x40, 0x86, 0x56, 0x01, 0xd1, 0x2b, 0xcf, 0xaf, 0x13, 0x52, 0x49, 0x54, 0x57, 0xc6, + 0x2d, 0x28, 0xaa, 0x95, 0x1f, 0xfc, 0xd3, 0xbf, 0xff, 0x38, 0x85, 0x50, 0xb9, 0xa1, 0xd3, 0x77, + 0x77, 0x8d, 0xa3, 0x1b, 0x0d, 0x5a, 0x58, 0x44, 0xbf, 0xaf, 0x40, 0x21, 0x7c, 0x11, 0x86, 0x5e, + 0x1d, 0xe3, 0x25, 0x56, 0x38, 0xfd, 0x6b, 0xe3, 0x75, 0xe6, 0x2c, 0x5c, 0xa5, 0x2c, 0x2c, 0xa2, + 0x05, 0x89, 0x85, 0xf0, 0x91, 0x19, 0xfa, 0x13, 0x05, 0xe6, 0x46, 0x9e, 0x7a, 0xa1, 0x1b, 0x93, + 0x3c, 0x0b, 0x63, 0x2c, 0xad, 0x4e, 0xfe, 0x92, 0x4c, 0x7d, 0x85, 0x32, 0xf6, 0x12, 0xaa, 0xc5, + 0x31, 0xd6, 0xf8, 0x44, 0x7c, 0x7e, 0x17, 0xfd, 0x85, 0x02, 0x45, 0xf9, 0xb5, 0x0f, 0xaa, 0x8f, + 0xfd, 0x2c, 0x88, 0x71, 0xd7, 0x98, 0xf0, 0x19, 0x91, 0xfa, 0x26, 0x65, 0xed, 0x75, 0x54, 0x7f, + 0x0e, 0x6b, 0x0d, 0x7a, 0xdf, 0xfb, 0x8d, 0x4f, 0xe8, 0x2f, 0xe5, 0x14, 0xa2, 0x12, 0x36, 0x7a, + 0x6d, 0xcc, 0x4a, 0x37, 0xe3, 0x72, 0xb2, 0xba, 0xb8, 0x7a, 0x87, 0xf2, 0xf8, 0x26, 0xba, 0x35, + 0x19, 0x8f, 0x0d, 0xf6, 0x44, 0xe2, 0x27, 0x0a, 0x94, 0x86, 0x5e, 0x05, 0xa0, 0x24, 0x21, 0xc5, + 0x3d, 0x2c, 0xa8, 0xbe, 0x3e, 0xfe, 0x00, 0xce, 0xf2, 0x32, 0x65, 0xb9, 0x8a, 0x2a, 0x12, 0xcb, + 0x8e, 0xeb, 0x30, 0x06, 0x29, 0x13, 0x4f, 0x21, 0xcb, 0x0a, 0xd1, 0x68, 0x65, 0x8c, 0x5a, 0x35, + 0xe3, 0xe3, 0xab, 0x63, 0x57, 0xb5, 0xd5, 0xcb, 0x94, 0x81, 0x0b, 0x68, 0x5e, 0x62, 0x80, 0x9b, + 0x42, 0x72, 0x1e, 0xc3, 0x22, 0x69, 0xe2, 0x79, 0x1c, 0x2d, 0xdb, 0x26, 0x9e, 0xc7, 0xb3, 0x75, + 0x57, 0x7e, 0x1e, 0x55, 0x99, 0x87, 0x81, 0x45, 0xb6, 0xeb, 0xb6, 0x72, 0x1d, 0x7d, 0x5f, 0x81, + 0xc2, 0xd6, 0x58, 0x6c, 0x6c, 0x4d, 0xc2, 0xc6, 0x99, 0xaa, 0x64, 0xac, 0x28, 0x18, 0x1b, 0xe8, + 0x77, 0x21, 0xc7, 0x6b, 0x8c, 0x28, 0x49, 0xb6, 0xc3, 0x35, 0xcc, 0xea, 0xf5, 0x71, 0xba, 0xf2, + 0xc9, 0xab, 0x74, 0xf2, 0x05, 0x84, 0xa4, 0xc9, 0x79, 0x2d, 0x13, 0xfd, 0x9e, 0x02, 0x79, 0x51, + 0x3e, 0x40, 0xd7, 0xc7, 0xaa, 0x31, 0x30, 0x06, 0x5e, 0x9d, 0xa0, 0x1e, 0xa1, 0x5e, 0xa1, 0x1c, + 0x5c, 0x44, 0x17, 0x24, 0x0e, 0x7c, 0x31, 0xeb, 0x53, 0xc8, 0xb2, 0x52, 0x44, 0xa2, 0x16, 0x0e, + 0x95, 0x2f, 0x12, 0xb5, 0x70, 0xa4, 0xae, 0x11, 0x27, 0xfa, 0x7d, 0x36, 0x1f, 0x59, 0xbc, 0x48, + 0xd6, 0x27, 0x2e, 0x7e, 0xa4, 0x30, 0x92, 0xb8, 0xf8, 0xd1, 0x6a, 0x45, 0xec, 0xe2, 0x45, 0x31, + 0x04, 0xf5, 0x61, 0xfa, 0xae, 0xdb, 0xf6, 0xd1, 0x57, 0x9e, 0x9b, 0x88, 0x67, 0x33, 0xbf, 0x32, + 0x66, 0xc2, 0x5e, 0xbd, 0x44, 0x67, 0x9d, 0x47, 0x73, 0xd2, 0xac, 0xdf, 0x21, 0x33, 0x91, 0xa3, + 0x17, 0xe6, 0x1a, 0x13, 0x75, 0x7e, 0x34, 0xcf, 0x99, 0xa8, 0xf3, 0x67, 0xd2, 0x97, 0xb1, 0x57, + 0x61, 0x98, 0xc2, 0xa4, 0x6c, 0x84, 0xf9, 0x97, 0x44, 0x36, 0x46, 0x93, 0x46, 0x89, 0x6c, 0x9c, + 0xc9, 0x1b, 0xc5, 0xb2, 0x41, 0xf3, 0x46, 0x7d, 0x32, 0xf1, 0xb7, 0x21, 0x43, 0xbd, 0x97, 0x44, + 0x77, 0x44, 0xae, 0xc7, 0x27, 0xba, 0x23, 0x43, 0xa5, 0x76, 0x75, 0xea, 0x75, 0x05, 0x3d, 0x81, + 0xa2, 0x5c, 0xf9, 0x4d, 0xbc, 0x4c, 0x63, 0x4a, 0xe1, 0xd5, 0x37, 0xce, 0x55, 0x52, 0x56, 0xa7, + 0xd0, 0x0f, 0x15, 0x40, 0x67, 0x3b, 0xa0, 0x5b, 0x13, 0xd2, 0x7b, 0x41, 0x2e, 0xfe, 0x54, 0x81, + 0xbc, 0xc8, 0x15, 0x26, 0x9e, 0xb0, 0x91, 0xec, 0x71, 0xe2, 0x09, 0x1b, 0x4d, 0x3e, 0xaa, 0xef, + 0xd0, 0x2d, 0x7e, 0x6b, 0xe8, 0x84, 0xd1, 0x98, 0xc5, 0x76, 0xbb, 0x8f, 0x97, 0xd1, 0x52, 0x0c, + 0xb8, 0xf1, 0x89, 0x88, 0x94, 0xbe, 0x4b, 0xbc, 0xb2, 0xf2, 0x68, 0xb8, 0x8b, 0x56, 0x27, 0x8a, + 0x8d, 0x19, 0xd3, 0x37, 0xcf, 0x11, 0x4f, 0xab, 0x5f, 0xa6, 0xcc, 0x2f, 0xa1, 0xab, 0x23, 0x9e, + 0x85, 0x6e, 0xca, 0xec, 0xfc, 0x54, 0x81, 0xf9, 0x35, 0xdb, 0x1e, 0x0e, 0x7f, 0xd1, 0xeb, 0x13, + 0x44, 0xca, 0x8c, 0xc5, 0x1b, 0x13, 0xc7, 0xd6, 0xea, 0x4b, 0x94, 0xc1, 0x2b, 0xe8, 0xb2, 0xc4, + 0x20, 0x0b, 0x87, 0x45, 0x80, 0x8d, 0x3e, 0x55, 0xa0, 0x28, 0x47, 0x2b, 0x89, 0x6a, 0x1e, 0x13, + 0xed, 0x24, 0xfa, 0x8c, 0x71, 0x61, 0x90, 0x5a, 0xa3, 0x4c, 0x5d, 0x46, 0x97, 0xe4, 0x3b, 0x8d, + 0x74, 0xe4, 0x31, 0x0e, 0x71, 0xb9, 0x8a, 0x72, 0xf4, 0x98, 0xc8, 0x52, 0x4c, 0xf8, 0x9e, 0xc8, + 0x52, 0x5c, 0x58, 0xaa, 0x5e, 0xa3, 0x2c, 0x7d, 0x49, 0x95, 0xfd, 0x2d, 0xcc, 0x3a, 0xea, 0x54, + 0xd9, 0x6e, 0x2b, 0xd7, 0x9b, 0xd7, 0x3f, 0xfb, 0xb7, 0xa5, 0xa9, 0xcf, 0x4e, 0x97, 0x94, 0x5f, + 0x9c, 0x2e, 0x29, 0xbf, 0x3c, 0x5d, 0x52, 0xfe, 0xf5, 0x74, 0x49, 0xf9, 0xf4, 0xf3, 0xa5, 0xa9, + 0x5f, 0x7c, 0xbe, 0x34, 0xf5, 0xcb, 0xcf, 0x97, 0xa6, 0x1e, 0xe7, 0xc5, 0x2c, 0xed, 0x2c, 0xcd, + 0xe4, 0xdd, 0xfc, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x43, 0x76, 0xe0, 0x83, 0x55, 0x34, 0x00, + 0x00, } diff --git a/pkg/server/serverpb/admin.pb.gw.go b/pkg/server/serverpb/admin.pb.gw.go index ee826e71c0e9..65873a4e2862 100644 --- a/pkg/server/serverpb/admin.pb.gw.go +++ b/pkg/server/serverpb/admin.pb.gw.go @@ -293,27 +293,6 @@ func request_Admin_QueryPlan_0(ctx context.Context, marshaler runtime.Marshaler, } -func request_Admin_Drain_0(ctx context.Context, marshaler runtime.Marshaler, client AdminClient, req *http.Request, pathParams map[string]string) (Admin_DrainClient, runtime.ServerMetadata, error) { - var protoReq DrainRequest - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - stream, err := client.Drain(ctx, &protoReq) - if err != nil { - return nil, metadata, err - } - header, err := stream.Header() - if err != nil { - return nil, metadata, err - } - metadata.HeaderMD = header - return stream, metadata, nil - -} - var ( filter_Admin_RangeLog_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -908,35 +887,6 @@ func RegisterAdminHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("POST", pattern_Admin_Drain_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Admin_Drain_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Admin_Drain_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Admin_RangeLog_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1147,8 +1097,6 @@ var ( pattern_Admin_QueryPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"_admin", "v1", "queryplan"}, "")) - pattern_Admin_Drain_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"_admin", "v1", "drain"}, "")) - pattern_Admin_RangeLog_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"_admin", "v1", "rangelog"}, "")) pattern_Admin_RangeLog_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"_admin", "v1", "rangelog", "range_id"}, "")) @@ -1195,8 +1143,6 @@ var ( forward_Admin_QueryPlan_0 = runtime.ForwardResponseMessage - forward_Admin_Drain_0 = runtime.ForwardResponseStream - forward_Admin_RangeLog_0 = runtime.ForwardResponseMessage forward_Admin_RangeLog_1 = runtime.ForwardResponseMessage diff --git a/pkg/server/serverpb/admin.proto b/pkg/server/serverpb/admin.proto index ac28896a89d8..3672d5a8bb23 100644 --- a/pkg/server/serverpb/admin.proto +++ b/pkg/server/serverpb/admin.proto @@ -253,6 +253,12 @@ message EventsRequest { // returned. When set to > 0, at most only that number of results are // returned. When set to < 0, an unlimited number of results are returned. int32 limit = 3; + // unredacted_events indicates that the values in the events should + // not be redacted. The default is to redact, so that older versions + // of `cockroach zip` do not see un-redacted values by default. + // For good security, this field is only obeyed by the server after + // checking that the client of the RPC is an admin user. + bool unredacted_events = 4; } // EventsResponse contains a set of event log entries. This is always limited @@ -761,18 +767,20 @@ service Admin { // Drain puts the node into the specified drain mode(s) and optionally // instructs the process to terminate. + // We do not expose this via HTTP unless we have a way to authenticate + // + authorize streaming RPC connections. See #42567. rpc Drain(DrainRequest) returns (stream DrainResponse) { - option (google.api.http) = { - post: "/_admin/v1/drain" - body: "*" - }; } // Decommission puts the node(s) into the specified decommissioning state. + // If this ever becomes exposed via HTTP, ensure that it performs + // authorization. See #42567. rpc Decommission(DecommissionRequest) returns (DecommissionStatusResponse) { } // DecommissionStatus retrieves the decommissioning status of the specified nodes. + // If this ever becomes exposed via HTTP, ensure that it performs + // authorization. See #42567. rpc DecommissionStatus(DecommissionStatusRequest) returns (DecommissionStatusResponse) { } diff --git a/pkg/server/status.go b/pkg/server/status.go index 9a86a5021ab6..1a2333048ca3 100644 --- a/pkg/server/status.go +++ b/pkg/server/status.go @@ -225,6 +225,9 @@ func (s *statusServer) dialNode( func (s *statusServer) Gossip( ctx context.Context, req *serverpb.GossipRequest, ) (*gossip.InfoStatus, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } if !debug.GatewayRemoteAllowed(ctx, s.st) { return nil, remoteDebuggingErr } @@ -250,6 +253,10 @@ func (s *statusServer) Gossip( func (s *statusServer) EngineStats( ctx context.Context, req *serverpb.EngineStatsRequest, ) (*serverpb.EngineStatsResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -291,6 +298,10 @@ func (s *statusServer) EngineStats( func (s *statusServer) Allocator( ctx context.Context, req *serverpb.AllocatorRequest, ) (*serverpb.AllocatorResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + // TODO(a-robinson): It'd be nice to allow this endpoint and just avoid // logging range start/end keys in the simulated allocator runs. if !debug.GatewayRemoteAllowed(ctx, s.st) { @@ -400,6 +411,10 @@ func recordedSpansToTraceEvents(spans []tracing.RecordedSpan) []*serverpb.TraceE func (s *statusServer) AllocatorRange( ctx context.Context, req *serverpb.AllocatorRangeRequest, ) (*serverpb.AllocatorRangeResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + // TODO(a-robinson): It'd be nice to allow this endpoint and just avoid // logging range start/end keys in the simulated allocator runs. if !debug.GatewayRemoteAllowed(ctx, s.st) { @@ -489,6 +504,10 @@ func (s *statusServer) AllocatorRange( func (s *statusServer) Certificates( ctx context.Context, req *serverpb.CertificatesRequest, ) (*serverpb.CertificatesResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -604,6 +623,10 @@ func extractCertFields(contents []byte, details *serverpb.CertificateDetails) er func (s *statusServer) Details( ctx context.Context, req *serverpb.DetailsRequest, ) (*serverpb.DetailsResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -658,6 +681,10 @@ func (s *statusServer) Details( func (s *statusServer) GetFiles( ctx context.Context, req *serverpb.GetFilesRequest, ) (*serverpb.GetFilesResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + if !debug.GatewayRemoteAllowed(ctx, s.st) { return nil, remoteDebuggingErr } @@ -726,6 +753,10 @@ func checkFilePattern(pattern string) error { func (s *statusServer) LogFilesList( ctx context.Context, req *serverpb.LogFilesListRequest, ) (*serverpb.LogFilesListResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -751,6 +782,10 @@ func (s *statusServer) LogFilesList( func (s *statusServer) LogFile( ctx context.Context, req *serverpb.LogFileRequest, ) (*serverpb.LogEntriesResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + if !debug.GatewayRemoteAllowed(ctx, s.st) { return nil, remoteDebuggingErr } @@ -826,6 +861,9 @@ func parseInt64WithDefault(s string, defaultValue int64) (int64, error) { func (s *statusServer) Logs( ctx context.Context, req *serverpb.LogsRequest, ) (*serverpb.LogEntriesResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } if !debug.GatewayRemoteAllowed(ctx, s.st) { return nil, remoteDebuggingErr } @@ -892,6 +930,10 @@ func (s *statusServer) Logs( func (s *statusServer) Stacks( ctx context.Context, req *serverpb.StacksRequest, ) (*serverpb.JSONResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -928,6 +970,10 @@ func (s *statusServer) Stacks( func (s *statusServer) Profile( ctx context.Context, req *serverpb.ProfileRequest, ) (*serverpb.JSONResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + nodeID, local, err := s.parseNodeID(req.NodeId) if err != nil { return nil, grpcstatus.Errorf(codes.InvalidArgument, err.Error()) @@ -1074,6 +1120,10 @@ func (s *statusServer) Metrics( func (s *statusServer) RaftDebug( ctx context.Context, req *serverpb.RaftDebugRequest, ) (*serverpb.RaftDebugResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodes, err := s.Nodes(ctx, nil) @@ -1174,6 +1224,10 @@ func (s *statusServer) handleVars(w http.ResponseWriter, r *http.Request) { func (s *statusServer) Ranges( ctx context.Context, req *serverpb.RangesRequest, ) (*serverpb.RangesResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -1332,6 +1386,10 @@ func (s *statusServer) Ranges( func (s *statusServer) HotRanges( ctx context.Context, req *serverpb.HotRangesRequest, ) (*serverpb.HotRangesResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) @@ -1418,6 +1476,10 @@ func (s *statusServer) localHotRanges(ctx context.Context) serverpb.HotRangesRes func (s *statusServer) Range( ctx context.Context, req *serverpb.RangeRequest, ) (*serverpb.RangeResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) @@ -1475,13 +1537,12 @@ func (s *statusServer) ListLocalSessions( return nil, remoteDebuggingErr } - sessionUser, err := userFromContext(ctx) + sessionUser, isAdmin, err := s.admin.getUserAndRole(ctx) if err != nil { return nil, err } - ok := s.hasAdminRole(ctx, sessionUser) - if !ok { + if !isAdmin { // For non-superusers, requests with an empty username is // implicitly a request for the client's own sessions. if req.Username == "" { @@ -1598,11 +1659,11 @@ func (s *statusServer) iterateNodes( func (s *statusServer) ListSessions( ctx context.Context, req *serverpb.ListSessionsRequest, ) (*serverpb.ListSessionsResponse, error) { - ctx = propagateGatewayMetadata(ctx) if !debug.GatewayRemoteAllowed(ctx, s.st) { return nil, remoteDebuggingErr } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) response := &serverpb.ListSessionsResponse{ @@ -1639,6 +1700,16 @@ func (s *statusServer) ListSessions( func (s *statusServer) CancelSession( ctx context.Context, req *serverpb.CancelSessionRequest, ) (*serverpb.CancelSessionResponse, error) { + sessionUser, isAdmin, err := s.admin.getUserAndRole(ctx) + if err != nil { + return nil, err + } + + if !isAdmin && sessionUser != req.Username { + // A user can only cancel their own sessions. + return nil, errInsufficientPrivilege + } + ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -1670,6 +1741,16 @@ func (s *statusServer) CancelSession( func (s *statusServer) CancelQuery( ctx context.Context, req *serverpb.CancelQueryRequest, ) (*serverpb.CancelQueryResponse, error) { + sessionUser, isAdmin, err := s.admin.getUserAndRole(ctx) + if err != nil { + return nil, err + } + + if !isAdmin && sessionUser != req.Username { + // A user can only cancel their own queries. + return nil, errInsufficientPrivilege + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -1702,6 +1783,10 @@ func (s *statusServer) CancelQuery( func (s *statusServer) SpanStats( ctx context.Context, req *serverpb.SpanStatsRequest, ) (*serverpb.SpanStatsResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeID) @@ -1761,6 +1846,10 @@ func (s *statusServer) Diagnostics( func (s *statusServer) Stores( ctx context.Context, req *serverpb.StoresRequest, ) (*serverpb.StoresResponse, error) { + if _, err := s.admin.requireAdminUser(ctx); err != nil { + return nil, err + } + ctx = propagateGatewayMetadata(ctx) ctx = s.AnnotateCtx(ctx) nodeID, local, err := s.parseNodeID(req.NodeId) @@ -1861,27 +1950,6 @@ func userFromContext(ctx context.Context) (string, error) { return usernames[0], nil } -type superUserChecker interface { - RequireAdminRole(ctx context.Context, action string) error -} - -func (s *statusServer) hasAdminRole(ctx context.Context, username string) bool { - if username == security.RootUser { - return true - } - planner, cleanup := sql.NewInternalPlanner( - "check-superuser", - client.NewTxn(ctx, s.db, s.gossip.NodeID.Get(), client.RootTxn), - username, - &sql.MemoryMetrics{}, - s.admin.server.execCfg) - defer cleanup() - if err := planner.(superUserChecker).RequireAdminRole(ctx, "access status server endpoint"); err != nil { - return false - } - return true -} - type systemInfoOnce struct { once sync.Once info serverpb.SystemInfo diff --git a/pkg/server/status_test.go b/pkg/server/status_test.go index 4c50972716af..7190cbbfd890 100644 --- a/pkg/server/status_test.go +++ b/pkg/server/status_test.go @@ -63,6 +63,12 @@ func getStatusJSONProto( return serverutils.GetJSONProto(ts, statusPrefix+path, response) } +func getStatusJSONProtoWithAdminOption( + ts serverutils.TestServerInterface, path string, response protoutil.Message, isAdmin bool, +) error { + return serverutils.GetJSONProtoWithAdminOption(ts, statusPrefix+path, response, isAdmin) +} + // TestStatusLocalStacks verifies that goroutine stack traces are available // via the /_status/stacks/local endpoint. func TestStatusLocalStacks(t *testing.T) { @@ -991,7 +997,7 @@ func TestSpanStatsResponse(t *testing.T) { ts := startServer(t) defer ts.Stopper().Stop(context.TODO()) - httpClient, err := ts.GetAuthenticatedHTTPClient() + httpClient, err := ts.GetAdminAuthenticatedHTTPClient() if err != nil { t.Fatal(err) } @@ -1430,33 +1436,50 @@ func TestListSessionsSecurity(t *testing.T) { ts := s.(*TestServer) defer ts.Stopper().Stop(context.TODO()) - // HTTP requests respect the authenticated username from the HTTP session. - testCases := []struct { - endpoint string - expectedErr string - }{ - {"local_sessions", ""}, - {"sessions", ""}, - {fmt.Sprintf("local_sessions?username=%s", authenticatedUserName), ""}, - {fmt.Sprintf("sessions?username=%s", authenticatedUserName), ""}, - {"local_sessions?username=root", "does not have permission to view sessions from user"}, - {"sessions?username=root", "does not have permission to view sessions from user"}, - } - for _, tc := range testCases { - var response serverpb.ListSessionsResponse - err := getStatusJSONProto(ts, tc.endpoint, &response) - if tc.expectedErr == "" { - if err != nil || len(response.Errors) > 0 { - t.Errorf("unexpected failure listing sessions from %s; error: %v; response errors: %v", - tc.endpoint, err, response.Errors) + ctx := context.TODO() + + for _, requestWithAdmin := range []bool{true, false} { + t.Run(fmt.Sprintf("admin=%v", requestWithAdmin), func(t *testing.T) { + myUser := authenticatedUserNameNoAdmin + expectedErrOnListingRootSessions := "does not have permission to view sessions from user" + if requestWithAdmin { + myUser = authenticatedUserName + expectedErrOnListingRootSessions = "" } - } else { - if !testutils.IsError(err, tc.expectedErr) && - !strings.Contains(response.Errors[0].Message, tc.expectedErr) { - t.Errorf("did not get expected error %q when listing sessions from %s: %v", - tc.expectedErr, tc.endpoint, err) + + // HTTP requests respect the authenticated username from the HTTP session. + testCases := []struct { + endpoint string + expectedErr string + }{ + {"local_sessions", ""}, + {"sessions", ""}, + {fmt.Sprintf("local_sessions?username=%s", myUser), ""}, + {fmt.Sprintf("sessions?username=%s", myUser), ""}, + {"local_sessions?username=root", expectedErrOnListingRootSessions}, + {"sessions?username=root", expectedErrOnListingRootSessions}, } - } + for _, tc := range testCases { + var response serverpb.ListSessionsResponse + err := getStatusJSONProtoWithAdminOption(ts, tc.endpoint, &response, requestWithAdmin) + if tc.expectedErr == "" { + if err != nil || len(response.Errors) > 0 { + t.Errorf("unexpected failure listing sessions from %s; error: %v; response errors: %v", + tc.endpoint, err, response.Errors) + } + } else { + respErr := "" + if len(response.Errors) > 0 { + respErr = response.Errors[0].Message + } + if !testutils.IsError(err, tc.expectedErr) && + !strings.Contains(respErr, tc.expectedErr) { + t.Errorf("did not get expected error %q when listing sessions from %s: %v", + tc.expectedErr, tc.endpoint, err) + } + } + } + }) } // gRPC requests behave as root and thus are always allowed. @@ -1469,7 +1492,7 @@ func TestListSessionsSecurity(t *testing.T) { t.Fatal(err) } client := serverpb.NewStatusClient(conn) - ctx := context.Background() + for _, user := range []string{"", authenticatedUserName, "root"} { request := &serverpb.ListSessionsRequest{Username: user} if resp, err := client.ListLocalSessions(ctx, request); err != nil || len(resp.Errors) > 0 { diff --git a/pkg/server/testserver.go b/pkg/server/testserver.go index bbea7f72a4a3..f0d79228e505 100644 --- a/pkg/server/testserver.go +++ b/pkg/server/testserver.go @@ -252,7 +252,7 @@ type TestServer struct { *Server // authClient is an http.Client that has been authenticated to access the // Admin UI. - authClient struct { + authClient [2]struct { httpClient http.Client cookie *serverpb.SessionCookie once sync.Once @@ -475,24 +475,41 @@ func (ts *TestServer) GetHTTPClient() (http.Client, error) { } const authenticatedUserName = "authentic_user" +const authenticatedUserNameNoAdmin = "authentic_user_noadmin" + +// GetAdminAuthenticatedHTTPClient implements the TestServerInterface. +func (ts *TestServer) GetAdminAuthenticatedHTTPClient() (http.Client, error) { + httpClient, _, err := ts.getAuthenticatedHTTPClientAndCookie(authenticatedUserName, true) + return httpClient, err +} // GetAuthenticatedHTTPClient implements the TestServerInterface. -func (ts *TestServer) GetAuthenticatedHTTPClient() (http.Client, error) { - httpClient, _, err := ts.getAuthenticatedHTTPClientAndCookie() +func (ts *TestServer) GetAuthenticatedHTTPClient(isAdmin bool) (http.Client, error) { + authUser := authenticatedUserName + if !isAdmin { + authUser = authenticatedUserNameNoAdmin + } + httpClient, _, err := ts.getAuthenticatedHTTPClientAndCookie(authUser, isAdmin) return httpClient, err } -func (ts *TestServer) getAuthenticatedHTTPClientAndCookie() ( - http.Client, - *serverpb.SessionCookie, - error, -) { - ts.authClient.once.Do(func() { - // Create an authentication session for an arbitrary user. We do not - // currently have an authorization mechanism, so a specific user is not - // necessary. - ts.authClient.err = func() error { - id, secret, err := ts.authentication.newAuthSession(context.TODO(), authenticatedUserName) +func (ts *TestServer) getAuthenticatedHTTPClientAndCookie( + authUser string, isAdmin bool, +) (http.Client, *serverpb.SessionCookie, error) { + authIdx := 0 + if isAdmin { + authIdx = 1 + } + authClient := &ts.authClient[authIdx] + authClient.once.Do(func() { + // Create an authentication session for an arbitrary admin user. + authClient.err = func() error { + // The user needs to exist as the admin endpoints will check its role. + if err := ts.createAuthUser(authUser, isAdmin); err != nil { + return err + } + + id, secret, err := ts.authentication.newAuthSession(context.TODO(), authUser) if err != nil { return err } @@ -515,17 +532,36 @@ func (ts *TestServer) getAuthenticatedHTTPClientAndCookie() ( } cookieJar.SetCookies(url, []*http.Cookie{cookie}) // Create an httpClient and attach the cookie jar to the client. - ts.authClient.httpClient, err = ts.Cfg.GetHTTPClient() + authClient.httpClient, err = ts.Cfg.GetHTTPClient() if err != nil { return err } - ts.authClient.httpClient.Jar = cookieJar - ts.authClient.cookie = rawCookie + authClient.httpClient.Jar = cookieJar + authClient.cookie = rawCookie return nil }() }) - return ts.authClient.httpClient, ts.authClient.cookie, ts.authClient.err + return authClient.httpClient, authClient.cookie, authClient.err +} + +func (ts *TestServer) createAuthUser(userName string, isAdmin bool) error { + if _, err := ts.Server.internalExecutor.Exec(context.TODO(), + "create-auth-user", nil, "CREATE USER $1", userName, + ); err != nil { + return err + } + if isAdmin { + // We can't use the GRANT statement here because we don't want + // to rely on CCL code. + if _, err := ts.Server.internalExecutor.Exec(context.TODO(), + "grant-admin", nil, + "INSERT INTO system.role_members (role, member, \"isAdmin\") VALUES ('admin', $1, true)", userName, + ); err != nil { + return err + } + } + return nil } // MustGetSQLCounter implements TestServerInterface. diff --git a/pkg/sql/internal_test.go b/pkg/sql/internal_test.go index 30fa817b4314..fd30a5f33807 100644 --- a/pkg/sql/internal_test.go +++ b/pkg/sql/internal_test.go @@ -99,6 +99,46 @@ func TestInternalExecutor(t *testing.T) { } } +func TestQueryIsAdminWithNoTxn(t *testing.T) { + defer leaktest.AfterTest(t)() + + ctx := context.TODO() + params, _ := tests.CreateTestServerParams() + s, db, _ := serverutils.StartServer(t, params) + defer s.Stopper().Stop(ctx) + + if _, err := db.Exec("create user testuser"); err != nil { + t.Fatal(err) + } + + ie := s.InternalExecutor().(*sql.InternalExecutor) + + testData := []struct { + user string + expAdmin bool + }{ + {security.NodeUser, true}, + {security.RootUser, true}, + {"testuser", false}, + } + + for _, tc := range testData { + t.Run(tc.user, func(t *testing.T) { + rows, cols, err := ie.QueryWithUser(ctx, "test", nil /* txn */, tc.user, "SELECT crdb_internal.is_admin()") + if err != nil { + t.Fatal(err) + } + if len(rows) != 1 || len(cols) != 1 { + t.Fatalf("unexpected result shape %d, %d", len(rows), len(cols)) + } + isAdmin := bool(*rows[0][0].(*tree.DBool)) + if isAdmin != tc.expAdmin { + t.Fatalf("expected %q admin %v, got %v", tc.user, tc.expAdmin, isAdmin) + } + }) + } +} + func TestSessionBoundInternalExecutor(t *testing.T) { defer leaktest.AfterTest(t)() diff --git a/pkg/sql/logictest/testdata/logic_test/crdb_internal b/pkg/sql/logictest/testdata/logic_test/crdb_internal index b4fd9c951ea1..5846c09af731 100644 --- a/pkg/sql/logictest/testdata/logic_test/crdb_internal +++ b/pkg/sql/logictest/testdata/logic_test/crdb_internal @@ -589,3 +589,21 @@ SELECT ) FROM table41834; + + +subtest builtin_is_admin + +user root + +query B +SELECT crdb_internal.is_admin() +---- +true + +user testuser + +query B +SELECT crdb_internal.is_admin() +---- +false + diff --git a/pkg/sql/sem/builtins/builtins.go b/pkg/sql/sem/builtins/builtins.go index c311221aa503..ae385c7c6d79 100644 --- a/pkg/sql/sem/builtins/builtins.go +++ b/pkg/sql/sem/builtins/builtins.go @@ -3297,6 +3297,31 @@ may increase either contention or retry errors, or both.`, }, ), + // Returns true iff the current user has admin role. + // Note: it would be a privacy leak to extend this to check arbitrary usernames. + "crdb_internal.is_admin": makeBuiltin( + tree.FunctionProperties{ + Category: categorySystemInfo, + DistsqlBlacklist: true, + }, + tree.Overload{ + Types: tree.ArgTypes{}, + ReturnType: tree.FixedReturnType(types.Bool), + Fn: func(evalCtx *tree.EvalContext, _ tree.Datums) (tree.Datum, error) { + if evalCtx.SessionAccessor == nil { + return nil, errors.AssertionFailedf("session accessor not set") + } + ctx := evalCtx.Ctx() + isAdmin, err := evalCtx.SessionAccessor.HasAdminRole(ctx) + if err != nil { + return nil, err + } + return tree.MakeDBool(tree.DBool(isAdmin)), nil + }, + Info: "Retrieves the current user's admin status.", + }, + ), + "crdb_internal.round_decimal_values": makeBuiltin( tree.FunctionProperties{ Category: categorySystemInfo, diff --git a/pkg/sql/sem/tree/eval.go b/pkg/sql/sem/tree/eval.go index 0129883784e1..bf8632e9a070 100644 --- a/pkg/sql/sem/tree/eval.go +++ b/pkg/sql/sem/tree/eval.go @@ -2555,6 +2555,9 @@ type EvalSessionAccessor interface { // GetSessionVar retrieves the current value of a session variable. GetSessionVar(ctx context.Context, settingName string, missingOk bool) (bool, string, error) + + // HasAdminRole returns true iff the current session user has the admin role. + HasAdminRole(ctx context.Context) (bool, error) } // SessionBoundInternalExecutor is a subset of sqlutil.InternalExecutor used by diff --git a/pkg/sql/sqlbase/evalctx.go b/pkg/sql/sqlbase/evalctx.go index 6ac61297e5dc..b93fab37cb9f 100644 --- a/pkg/sql/sqlbase/evalctx.go +++ b/pkg/sql/sqlbase/evalctx.go @@ -127,3 +127,8 @@ func (ep *DummySessionAccessor) GetSessionVar( func (ep *DummySessionAccessor) SetSessionVar(_ context.Context, _, _ string) error { return errEvalSessionVar } + +// HasAdminRole is part of the tree.EvalSessionAccessor interface. +func (ep *DummySessionAccessor) HasAdminRole(_ context.Context) (bool, error) { + return false, errEvalSessionVar +} diff --git a/pkg/testutils/serverutils/test_server_shim.go b/pkg/testutils/serverutils/test_server_shim.go index 1f8fb6f84d23..e4ef45aecf2b 100644 --- a/pkg/testutils/serverutils/test_server_shim.go +++ b/pkg/testutils/serverutils/test_server_shim.go @@ -115,9 +115,13 @@ type TestServerInterface interface { // GetHTTPClient returns an http client configured with the client TLS // config required by the TestServer's configuration. GetHTTPClient() (http.Client, error) + // GetAdminAuthenticatedHTTPClient returns an http client which has been + // authenticated to access Admin API methods (via a cookie). + // The user has admin privileges. + GetAdminAuthenticatedHTTPClient() (http.Client, error) // GetAuthenticatedHTTPClient returns an http client which has been // authenticated to access Admin API methods (via a cookie). - GetAuthenticatedHTTPClient() (http.Client, error) + GetAuthenticatedHTTPClient(isAdmin bool) (http.Client, error) // MustGetSQLCounter returns the value of a counter metric from the server's // SQL Executor. Runs in O(# of metrics) time, which is fine for test code. @@ -220,7 +224,15 @@ func StartServerRaw(args base.TestServerArgs) (TestServerInterface, error) { // GetJSONProto uses the supplied client to GET the URL specified by the parameters // and unmarshals the result into response. func GetJSONProto(ts TestServerInterface, path string, response protoutil.Message) error { - httpClient, err := ts.GetAuthenticatedHTTPClient() + return GetJSONProtoWithAdminOption(ts, path, response, true) +} + +// GetJSONProtoWithAdminOption is like GetJSONProto but the caller can customize +// whether the request is performed with admin privilege +func GetJSONProtoWithAdminOption( + ts TestServerInterface, path string, response protoutil.Message, isAdmin bool, +) error { + httpClient, err := ts.GetAuthenticatedHTTPClient(isAdmin) if err != nil { return err } @@ -230,7 +242,7 @@ func GetJSONProto(ts TestServerInterface, path string, response protoutil.Messag // PostJSONProto uses the supplied client to POST request to the URL specified by // the parameters and unmarshals the result into response. func PostJSONProto(ts TestServerInterface, path string, request, response protoutil.Message) error { - httpClient, err := ts.GetAuthenticatedHTTPClient() + httpClient, err := ts.GetAdminAuthenticatedHTTPClient() if err != nil { return err } diff --git a/pkg/ui/src/util/api.spec.ts b/pkg/ui/src/util/api.spec.ts index b905af0c9cf3..c046e2f4921c 100644 --- a/pkg/ui/src/util/api.spec.ts +++ b/pkg/ui/src/util/api.spec.ts @@ -359,7 +359,7 @@ describe("rest api", function() { method: "GET", response: (url: string, requestObj: RequestInit) => { const params = url.split("?")[1].split("&"); - assert.lengthOf(params, 2); + assert.lengthOf(params, 3); _.each(params, (param) => { let [k, v] = param.split("="); k = decodeURIComponent(k); @@ -373,6 +373,9 @@ describe("rest api", function() { assert.equal(req.type, v); break; + case "unredacted_events": + break; + default: throw new Error(`Unknown property ${k}`); } diff --git a/pkg/ui/src/util/api.ts b/pkg/ui/src/util/api.ts index 0a331ec18b99..07502d24d81b 100644 --- a/pkg/ui/src/util/api.ts +++ b/pkg/ui/src/util/api.ts @@ -221,7 +221,7 @@ export function setUIData(req: SetUIDataRequestMessage, timeout?: moment.Duratio // getEvents gets event data export function getEvents(req: EventsRequestMessage, timeout?: moment.Duration): Promise { const queryString = propsToQueryString(_.pick(req, ["type", "target_id"])); - return timeoutFetch(serverpb.EventsResponse, `${API_PREFIX}/events?${queryString}`, null, timeout); + return timeoutFetch(serverpb.EventsResponse, `${API_PREFIX}/events?unredacted_events=true&${queryString}`, null, timeout); } export function getLocations(_req: LocationsRequestMessage, timeout?: moment.Duration): Promise {