From 3fccc56e3e3900987d3d7d54cfa6cf8195b6c754 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 15 Apr 2026 10:37:28 +0200 Subject: [PATCH 1/2] Remove rf1_after from query frontend and query paths Query all blocks regardless of replication factor for non-metrics paths (search, tags, trace-by-ID). Metrics queries continue to filter RF1-only. The rf1_after config field is kept but deprecated for YAML backward compatibility. Proto fields are marked deprecated for wire compatibility. Fixes #6960 --- CHANGELOG.md | 1 + cmd/tempo-vulture/main.go | 7 - cmd/tempo/app/config.go | 7 + docs/sources/tempo/configuration/manifest.md | 1 - example/docker-compose/debug/tempo.yaml | 1 - example/docker-compose/distributed/tempo.yaml | 1 - example/docker-compose/multitenant/tempo.yaml | 1 - .../docker-compose/single-binary/tempo.yaml | 1 - integration/util/config-base.yaml | 3 - modules/frontend/config.go | 7 +- modules/frontend/frontend.go | 6 +- modules/frontend/search_handlers_test.go | 28 +- modules/frontend/search_sharder.go | 12 +- modules/frontend/search_sharder_test.go | 32 -- modules/frontend/tag_sharder.go | 13 +- modules/frontend/tag_sharder_test.go | 2 - modules/frontend/traceid_handlers.go | 4 +- modules/frontend/traceid_sharder.go | 9 - modules/frontend/util.go | 12 +- modules/querier/http.go | 8 +- modules/querier/querier.go | 1 - pkg/api/http.go | 42 +- pkg/api/http_test.go | 6 +- pkg/api/search_tags.go | 17 - pkg/tempopb/tempo.pb.go | 375 +++++++++--------- pkg/tempopb/tempo.proto | 12 +- tempodb/encoding/common/interfaces.go | 1 - tempodb/tempodb.go | 17 +- tempodb/tempodb_test.go | 4 +- 29 files changed, 247 insertions(+), 384 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 540ad6c7cfb..9ec3f1b1ae5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * [CHANGE] Deprecate metrics-generator no-local-blocks [#6707](https://github.com/grafana/tempo/pull/6707) (@javiermolinar) * [CHANGE] Own local block and partition ring helpers [#6808](https://github.com/grafana/tempo/pull/6808) (@javiermolinar) * [CHANGE] Track invalid trace and span id discards [#6799](https://github.com/grafana/tempo/pull/6799) (@javiermolinar) +* [CHANGE] Deprecate `query_frontend.rf1_after` and query all blocks regardless of replication factor for non-metrics paths. Simplifies 2.x to 3.0 migration. [#6969](https://github.com/grafana/tempo/pull/6969) (@mapno) * [FEATURE] Add automemlimit support for automatic GOMEMLIMIT configuration. Enable with `memory.automemlimit_enabled: true`. [#6313](https://github.com/grafana/tempo/pull/6313) (@oleg-kozlyuk) * [FEATURE] Support comparison operators in TraceQL Metrics queries [#6474](https://github.com/grafana/tempo/pull/6474) (@ruslan-mikhailov) * [FEATURE] Add new include_any filter policy for spanmetrics filter [#6392](https://github.com/grafana/tempo/pull/6392) (@javiermolinar) diff --git a/cmd/tempo-vulture/main.go b/cmd/tempo-vulture/main.go index 93e0e3896e1..720e9327d0b 100644 --- a/cmd/tempo-vulture/main.go +++ b/cmd/tempo-vulture/main.go @@ -16,7 +16,6 @@ import ( "time" "github.com/go-test/deep" - "github.com/grafana/tempo/pkg/api" zaplogfmt "github.com/jsternberg/zap-logfmt" "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/zap" @@ -45,7 +44,6 @@ var ( tempoRecentTracesCutoffDuration time.Duration tempoPushTLS bool - rf1After time.Time tempoQueryLiveStores bool logger *zap.Logger @@ -134,7 +132,6 @@ func init() { flag.IntVar(&validationCycles, "validation-cycles", 3, "Number of write/read cycles to perform in validation mode") flag.DurationVar(&validationTimeout, "validation-timeout", 5*time.Minute, "Maximum time to run validation mode before timing out") - flag.Var(newTimeVar(&rf1After), "rhythm-rf1-after", "Timestamp (RFC3339) after which only blocks with RF==1 are included in search and ID lookups") flag.BoolVar(&tempoQueryLiveStores, "tempo-query-livestore", false, "When to query live stores") } @@ -174,10 +171,6 @@ func main() { panic(err) } - if !rf1After.IsZero() { - httpClient.SetQueryParam(api.URLParamRF1After, rf1After.Format(time.RFC3339)) - } - tickerWrite, tickerRead, tickerSearch, tickerMetrics, err := initTickers( vultureConfig.tempoWriteBackoffDuration, vultureConfig.tempoReadBackoffDuration, diff --git a/cmd/tempo/app/config.go b/cmd/tempo/app/config.go index 85baa2f65e5..f7ed021038c 100644 --- a/cmd/tempo/app/config.go +++ b/cmd/tempo/app/config.go @@ -239,6 +239,13 @@ func (c *Config) CheckConfig() []ConfigWarning { warnings = append(warnings, warnPartitionAssigmentCollision) } + if !c.Frontend.RF1After.IsZero() { + warnings = append(warnings, ConfigWarning{ + Message: "query_frontend.rf1_after is deprecated and will be removed in a future release.", + Explain: "Non-metric query paths now query all blocks regardless of replication factor. This setting is ignored.", + }) + } + return warnings } diff --git a/docs/sources/tempo/configuration/manifest.md b/docs/sources/tempo/configuration/manifest.md index 315f1951d9a..82ae418603b 100644 --- a/docs/sources/tempo/configuration/manifest.md +++ b/docs/sources/tempo/configuration/manifest.md @@ -356,7 +356,6 @@ query_frontend: mcp_server: enabled: false max_query_expression_size_bytes: 131072 - rf1_after: 0001-01-01T00:00:00Z metrics_generator: ring: kvstore: diff --git a/example/docker-compose/debug/tempo.yaml b/example/docker-compose/debug/tempo.yaml index db829c4019e..f1bc703c478 100644 --- a/example/docker-compose/debug/tempo.yaml +++ b/example/docker-compose/debug/tempo.yaml @@ -45,7 +45,6 @@ metrics_generator: send_exemplars: true query_frontend: - rf1_after: "1999-01-01T00:00:00Z" mcp_server: enabled: true diff --git a/example/docker-compose/distributed/tempo.yaml b/example/docker-compose/distributed/tempo.yaml index 67fc339b75d..13862e6a4cc 100644 --- a/example/docker-compose/distributed/tempo.yaml +++ b/example/docker-compose/distributed/tempo.yaml @@ -57,7 +57,6 @@ metrics_generator: send_exemplars: true query_frontend: - rf1_after: "1999-01-01T00:00:00Z" mcp_server: enabled: true diff --git a/example/docker-compose/multitenant/tempo.yaml b/example/docker-compose/multitenant/tempo.yaml index 94e0eff03b1..2a49f800efb 100644 --- a/example/docker-compose/multitenant/tempo.yaml +++ b/example/docker-compose/multitenant/tempo.yaml @@ -39,7 +39,6 @@ querier: metrics_generator: query_frontend: - rf1_after: "1999-01-01T00:00:00Z" mcp_server: enabled: true diff --git a/example/docker-compose/single-binary/tempo.yaml b/example/docker-compose/single-binary/tempo.yaml index de880c466b5..52f03c9787b 100644 --- a/example/docker-compose/single-binary/tempo.yaml +++ b/example/docker-compose/single-binary/tempo.yaml @@ -47,7 +47,6 @@ metrics_generator: send_exemplars: true query_frontend: - rf1_after: "1999-01-01T00:00:00Z" mcp_server: enabled: true diff --git a/integration/util/config-base.yaml b/integration/util/config-base.yaml index d3a5a06b2bc..d9705fbc69f 100644 --- a/integration/util/config-base.yaml +++ b/integration/util/config-base.yaml @@ -21,9 +21,6 @@ overrides: metrics_generator: processors: [service-graphs, span-metrics] -query_frontend: - rf1_after: "2025-01-01T00:00:00Z" - distributor: receivers: otlp: diff --git a/modules/frontend/config.go b/modules/frontend/config.go index 4ab10b15553..332a62a6c2e 100644 --- a/modules/frontend/config.go +++ b/modules/frontend/config.go @@ -41,7 +41,8 @@ type Config struct { AllowedHeaders []string `yaml:"allowed_headers,omitempty"` // RF1After specifies the time after which RF1 logic is applied. - RF1After time.Time `yaml:"rf1_after" category:"advanced"` + // Deprecated: it's ignored + RF1After time.Time `yaml:"rf1_after,omitempty" category:"advanced"` // QueryEndCutoff prevents querying incomplete recent data. QueryEndCutoff time.Duration `yaml:"query_end_cutoff,omitempty"` @@ -63,10 +64,6 @@ type TraceByIDConfig struct { ConcurrentShards int `yaml:"concurrent_shards,omitempty"` SLO SLOConfig `yaml:",inline"` ExternalEnabled bool `yaml:"external_enabled,omitempty"` - - // RF1After specifies the time after which RF1 logic is applied, injected by the configuration - // or determined at runtime based on search request parameters. - RF1After time.Time `yaml:"-"` } type MetricsConfig struct { diff --git a/modules/frontend/frontend.go b/modules/frontend/frontend.go index b1087f5db06..e19493dce5c 100644 --- a/modules/frontend/frontend.go +++ b/modules/frontend/frontend.go @@ -128,10 +128,6 @@ func New(cfg Config, next pipeline.RoundTripper, o overrides.Interface, reader t NativeHistogramMinResetDuration: 1 * time.Hour, }, []string{"op"}) - // Propagate RF1After to search and traceByID sharders - cfg.Search.Sharder.RF1After = cfg.RF1After - cfg.TraceByID.RF1After = cfg.RF1After - adjustEndWareSeconds := pipeline.NewAdjustStartEndWare(cfg.Search.Sharder.QueryBackendAfter, cfg.QueryEndCutoff, false) adjustEndWareNanos := pipeline.NewAdjustStartEndWare(cfg.Metrics.Sharder.QueryBackendAfter, cfg.QueryEndCutoff, true) // metrics queries work in nanoseconds retryWare := pipeline.NewRetryWare(cfg.MaxRetries, cfg.Weights.RetryWithWeights, registerer) @@ -380,7 +376,7 @@ func blockMetasForSearch(allBlocks []*backend.BlockMeta, start, end time.Time, f // block start is before or equal to search end AND block end is after or equal to search start if !m.StartTime.After(end) && // block start <= search end !m.EndTime.Before(start) && // block end >= search start - filterFn(m) { // This check skips generator blocks (RF=1) + filterFn(m) { blocks = append(blocks, m) } } diff --git a/modules/frontend/search_handlers_test.go b/modules/frontend/search_handlers_test.go index 27b7875a2a5..ac615986489 100644 --- a/modules/frontend/search_handlers_test.go +++ b/modules/frontend/search_handlers_test.go @@ -165,7 +165,7 @@ func runnerRequests(t *testing.T, f *QueryFrontend) { expectedErr error }{ { - name: "access 2 blocks x 2 jobs = 4", + name: "access 4 blocks x 2 jobs = 8", request: &tempopb.SearchRequest{ Query: "{resource.service.name = `test`}", Start: 1, @@ -180,12 +180,12 @@ func runnerRequests(t *testing.T, f *QueryFrontend) { StartTimeUnixNano: math.MaxUint64, }}, Metrics: &tempopb.SearchMetrics{ - InspectedTraces: 4, - InspectedBytes: 4, - TotalBlocks: 2, - TotalJobs: 4, - TotalBlockBytes: 4 * defaultTargetBytesPerRequest, - CompletedJobs: 4, + InspectedTraces: 8, + InspectedBytes: 8, + TotalBlocks: 4, + TotalJobs: 8, + TotalBlockBytes: 8 * defaultTargetBytesPerRequest, + CompletedJobs: 8, }, }, }, @@ -202,7 +202,7 @@ func runnerRequests(t *testing.T, f *QueryFrontend) { expectedErr: status.Error(codes.InvalidArgument, "invalid TraceQL query: parse error at line 1, col 1: syntax error: unexpected IDENTIFIER"), }, { - name: "multitenant - 4 jobs x 2 tenants = 8", + name: "multitenant - 8 jobs x 2 tenants = 16", tenant: "tenant-1|tenant-2", request: &tempopb.SearchRequest{ Query: "{resource.service.name = `test`}", @@ -218,12 +218,12 @@ func runnerRequests(t *testing.T, f *QueryFrontend) { StartTimeUnixNano: math.MaxUint64, }}, Metrics: &tempopb.SearchMetrics{ - InspectedTraces: 8, - InspectedBytes: 8, - TotalBlocks: 4, - TotalJobs: 8, - TotalBlockBytes: 8 * defaultTargetBytesPerRequest, - CompletedJobs: 8, + InspectedTraces: 16, + InspectedBytes: 16, + TotalBlocks: 8, + TotalJobs: 16, + TotalBlockBytes: 16 * defaultTargetBytesPerRequest, + CompletedJobs: 16, }, }, }, diff --git a/modules/frontend/search_sharder.go b/modules/frontend/search_sharder.go index 6ba40706c65..9a15d687e7f 100644 --- a/modules/frontend/search_sharder.go +++ b/modules/frontend/search_sharder.go @@ -40,10 +40,6 @@ type SearchSharderConfig struct { MostRecentShards int `yaml:"most_recent_shards,omitempty"` DefaultSpansPerSpanSet uint32 `yaml:"default_spans_per_span_set,omitempty"` MaxSpansPerSpanSet uint32 `yaml:"max_spans_per_span_set,omitempty"` - - // RF1After specifies the time after which RF1 logic is applied, injected by the configuration - // or determined at runtime based on search request parameters. - RF1After time.Time `yaml:"-"` } type asyncSearchSharder struct { @@ -154,13 +150,7 @@ func (s *asyncSearchSharder) backendRequests(ctx context.Context, tenantID strin startT := time.Unix(int64(start), 0) endT := time.Unix(int64(end), 0) - // Use RF1After from the request if it's not zero, otherwise use the config value - rf1After := searchReq.RF1After - if rf1After.IsZero() { - rf1After = s.cfg.RF1After - } - - blocks := blockMetasForSearch(s.reader.BlockMetas(tenantID), startT, endT, rf1FilterFn(rf1After)) + blocks := blockMetasForSearch(s.reader.BlockMetas(tenantID), startT, endT, acceptAllBlocks) // calculate metrics to return to the caller resp.TotalBlocks = len(blocks) diff --git a/modules/frontend/search_sharder_test.go b/modules/frontend/search_sharder_test.go index 1fd8c10f5d2..f4b9e5c8b30 100644 --- a/modules/frontend/search_sharder_test.go +++ b/modules/frontend/search_sharder_test.go @@ -1156,38 +1156,6 @@ func TestBackendShards(t *testing.T) { } } -func TestRF1After(t *testing.T) { - // Define a set of block metadata with different replication factors and time ranges - blockMetas := []*backend.BlockMeta{ - {StartTime: time.Unix(100, 0), EndTime: time.Unix(200, 0), ReplicationFactor: backend.DefaultReplicationFactor}, - {StartTime: time.Unix(100, 0), EndTime: time.Unix(200, 0), ReplicationFactor: backend.MetricsGeneratorReplicationFactor}, - {StartTime: time.Unix(200, 0), EndTime: time.Unix(300, 0), ReplicationFactor: backend.DefaultReplicationFactor}, - {StartTime: time.Unix(200, 0), EndTime: time.Unix(300, 0), ReplicationFactor: backend.MetricsGeneratorReplicationFactor}, - } - - // Create a request for processing, including a query string that specifies `rf1After` as a filter - r := httptest.NewRequest("GET", "/?q={}&rf1After=1970-01-01T00:01:30Z&bar&limit=50&start=50&end=300", nil) - searchReq, err := api.ParseSearchRequest(r) - require.NoError(t, err) - - ctx, cancelCause := context.WithCancelCause(context.Background()) - pipelineRequest := pipeline.NewHTTPRequest(r) - - // Initialize the search sharder with mock metadata for testing - s := &asyncSearchSharder{ - cfg: SearchSharderConfig{ - MostRecentShards: defaultMostRecentShards, - }, - } - s.reader = &mockReader{metas: blockMetas} - - // Execute backend requests and validate the result - searchJobResponse := &combiner.SearchJobResponse{} - s.backendRequests(ctx, "test", pipelineRequest, searchReq, searchJobResponse, make(chan pipeline.Request), cancelCause) - - require.Equal(t, 2, searchJobResponse.TotalBlocks) // Verify the expected number of blocks after filtering -} - func TestSearchSharderReturnsConsistentShards(t *testing.T) { now := time.Now() diff --git a/modules/frontend/tag_sharder.go b/modules/frontend/tag_sharder.go index 504210850bd..f5c5f22faa2 100644 --- a/modules/frontend/tag_sharder.go +++ b/modules/frontend/tag_sharder.go @@ -41,8 +41,6 @@ func (r *tagsSearchRequest) keyPrefix() string { return cacheKeyPrefixSearchTag } -func (r *tagsSearchRequest) rf1After() time.Time { return r.request.RF1After } - func (r *tagsSearchRequest) newWithRange(start, end uint32) tagSearchReq { newReq := r.request newReq.Start = start @@ -96,8 +94,6 @@ func (r *tagValueSearchRequest) keyPrefix() string { return cacheKeyPrefixSearchTagValues } -func (r *tagValueSearchRequest) rf1After() time.Time { return r.request.RF1After } - func (r *tagValueSearchRequest) newWithRange(start, end uint32) tagSearchReq { newReq := r.request newReq.Start = start @@ -170,8 +166,6 @@ type tagSearchReq interface { // should only be based on the content the request is searching for hash() uint64 keyPrefix() string - - rf1After() time.Time } type searchTagSharder struct { @@ -273,15 +267,10 @@ func (s searchTagSharder) backendRequests(ctx context.Context, tenantID string, return 0 } - rf1After := searchReq.rf1After() - if rf1After.IsZero() { - rf1After = s.cfg.RF1After - } - // get block metadata of blocks in start, end duration startT := time.Unix(int64(start), 0) endT := time.Unix(int64(end), 0) - blocks := blockMetasForSearch(s.reader.BlockMetas(tenantID), startT, endT, rf1FilterFn(rf1After)) + blocks := blockMetasForSearch(s.reader.BlockMetas(tenantID), startT, endT, acceptAllBlocks) targetBytesPerRequest := s.cfg.TargetBytesPerRequest // the callback function is nil, so we will use it just for counting the total number of jobs diff --git a/modules/frontend/tag_sharder_test.go b/modules/frontend/tag_sharder_test.go index e846294001c..76a17033c33 100644 --- a/modules/frontend/tag_sharder_test.go +++ b/modules/frontend/tag_sharder_test.go @@ -54,8 +54,6 @@ func (r *fakeReq) keyPrefix() string { return "" } -func (r *fakeReq) rf1After() time.Time { return time.Time{} } - func (r *fakeReq) buildSearchTagRequest(subR *http.Request) (*http.Request, error) { newReq := subR.Clone(subR.Context()) q := subR.URL.Query() diff --git a/modules/frontend/traceid_handlers.go b/modules/frontend/traceid_handlers.go index d93dc311b66..72964d02060 100644 --- a/modules/frontend/traceid_handlers.go +++ b/modules/frontend/traceid_handlers.go @@ -31,7 +31,7 @@ func newTraceIDHandler(cfg Config, next pipeline.AsyncRoundTripper[combiner.Pipe } // validate start and end parameter - _, _, _, _, _, _, reqErr := api.ValidateAndSanitizeRequest(req) + _, _, _, _, _, reqErr := api.ValidateAndSanitizeRequest(req) if reqErr != nil { return httpInvalidRequest(reqErr), nil } @@ -101,7 +101,7 @@ func newTraceIDV2Handler(cfg Config, next pipeline.AsyncRoundTripper[combiner.Pi } // validate start and end parameter - _, _, _, _, _, _, reqErr := api.ValidateAndSanitizeRequest(req) + _, _, _, _, _, reqErr := api.ValidateAndSanitizeRequest(req) if reqErr != nil { return httpInvalidRequest(reqErr), nil } diff --git a/modules/frontend/traceid_sharder.go b/modules/frontend/traceid_sharder.go index fcfd0043094..d0600e8439d 100644 --- a/modules/frontend/traceid_sharder.go +++ b/modules/frontend/traceid_sharder.go @@ -3,7 +3,6 @@ package frontend import ( "encoding/hex" "net/http" - "time" "github.com/go-kit/log" //nolint:all //deprecated "github.com/grafana/tempo/modules/frontend/combiner" @@ -100,13 +99,6 @@ func (s *asyncTraceSharder) buildShardedRequests(parent pipeline.Request) ([]pip } reqs = append(reqs, req) - var rf1After string - if val := parent.HTTPRequest().URL.Query().Get(api.URLParamRF1After); val != "" { - rf1After = val - } else if !s.cfg.RF1After.IsZero() { - rf1After = s.cfg.RF1After.Format(time.RFC3339) - } - // Job 1: external job (if enabled) if s.cfg.ExternalEnabled { req, err = cloneRequestforQueriers(parent, userID, func(r *http.Request) (*http.Request, error) { @@ -130,7 +122,6 @@ func (s *asyncTraceSharder) buildShardedRequests(parent pipeline.Request) ([]pip params[querier.BlockStartKey] = hex.EncodeToString(s.blockBoundaries[i-1]) params[querier.BlockEndKey] = hex.EncodeToString(s.blockBoundaries[i]) params[querier.QueryModeKey] = querier.QueryModeBlocks - params[api.URLParamRF1After] = rf1After return api.BuildQueryRequest(r, params), nil }) diff --git a/modules/frontend/util.go b/modules/frontend/util.go index d782e49f352..f25e1e877b1 100644 --- a/modules/frontend/util.go +++ b/modules/frontend/util.go @@ -4,7 +4,6 @@ import ( "io" "net/http" "strings" - "time" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -26,13 +25,4 @@ func extractTenant(req *http.Request, logger log.Logger) (string, *http.Response return tenant, nil } -func rf1FilterFn(rf1After time.Time) func(m *backend.BlockMeta) bool { - return func(m *backend.BlockMeta) bool { - if rf1After.IsZero() { - return m.ReplicationFactor == backend.DefaultReplicationFactor - } - - return (m.ReplicationFactor == backend.DefaultReplicationFactor && m.StartTime.Before(rf1After)) || - (m.ReplicationFactor == backend.MetricsGeneratorReplicationFactor && m.StartTime.After(rf1After)) - } -} +func acceptAllBlocks(_ *backend.BlockMeta) bool { return true } diff --git a/modules/querier/http.go b/modules/querier/http.go index 33930386352..9a593e8949a 100644 --- a/modules/querier/http.go +++ b/modules/querier/http.go @@ -47,7 +47,7 @@ func (q *Querier) TraceByIDHandler(w http.ResponseWriter, r *http.Request) { } // validate request - blockStart, blockEnd, queryMode, timeStart, timeEnd, rf1After, err := api.ValidateAndSanitizeRequest(r) + blockStart, blockEnd, queryMode, timeStart, timeEnd, err := api.ValidateAndSanitizeRequest(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -59,7 +59,6 @@ func (q *Querier) TraceByIDHandler(w http.ResponseWriter, r *http.Request) { attribute.String("timeStart", fmt.Sprint(timeStart)), attribute.String("timeEnd", fmt.Sprint(timeEnd)), attribute.String("apiVersion", "v1"), - attribute.String("rf1After", rf1After.Format(time.RFC3339)), )) resp, err := q.FindTraceByID(ctx, &tempopb.TraceByIDRequest{ @@ -67,7 +66,6 @@ func (q *Querier) TraceByIDHandler(w http.ResponseWriter, r *http.Request) { BlockStart: blockStart, BlockEnd: blockEnd, QueryMode: queryMode, - RF1After: rf1After, }, timeStart, timeEnd) if err != nil { handleError(w, err) @@ -98,7 +96,7 @@ func (q *Querier) TraceByIDHandlerV2(w http.ResponseWriter, r *http.Request) { } // validate request - blockStart, blockEnd, queryMode, timeStart, timeEnd, rf1After, err := api.ValidateAndSanitizeRequest(r) + blockStart, blockEnd, queryMode, timeStart, timeEnd, err := api.ValidateAndSanitizeRequest(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -110,7 +108,6 @@ func (q *Querier) TraceByIDHandlerV2(w http.ResponseWriter, r *http.Request) { attribute.String("timeStart", fmt.Sprint(timeStart)), attribute.String("timeEnd", fmt.Sprint(timeEnd)), attribute.String("apiVersion", "v2"), - attribute.String("rf1After", rf1After.Format(time.RFC3339)), )) resp, err := q.FindTraceByID(ctx, &tempopb.TraceByIDRequest{ @@ -119,7 +116,6 @@ func (q *Querier) TraceByIDHandlerV2(w http.ResponseWriter, r *http.Request) { BlockEnd: blockEnd, QueryMode: queryMode, AllowPartialTrace: true, - RF1After: rf1After, }, timeStart, timeEnd) if err != nil { handleError(w, err) diff --git a/modules/querier/querier.go b/modules/querier/querier.go index 0e9aab6c109..a0c4a8f9cf9 100644 --- a/modules/querier/querier.go +++ b/modules/querier/querier.go @@ -242,7 +242,6 @@ func (q *Querier) FindTraceByID(ctx context.Context, req *tempopb.TraceByIDReque )) opts := common.DefaultSearchOptionsWithMaxBytes(maxBytes) - opts.RF1After = req.RF1After partialTraces, blockErrs, err := q.store.Find(ctx, userID, req.TraceID, req.BlockStart, req.BlockEnd, timeStart, timeEnd, opts) if err != nil { diff --git a/pkg/api/http.go b/pkg/api/http.go index dd1ea976cbe..bdfaca49e19 100644 --- a/pkg/api/http.go +++ b/pkg/api/http.go @@ -38,7 +38,6 @@ const ( urlParamStep = "step" urlParamSince = "since" urlParamExemplars = "exemplars" - URLParamRF1After = "rf1After" urlMaxSeries = "maxSeries" urlInstant = "instant" @@ -267,14 +266,6 @@ func ParseSearchRequestWithDefault(r *http.Request, defaultSpansPerSpanSet uint3 req.SpansPerSpanSet = uint32(spansPerSpanSet) } - if s, ok := extractQueryParam(vals, URLParamRF1After); ok { - t, err := time.Parse(time.RFC3339, s) - if err != nil { - return nil, fmt.Errorf("invalid rf1After: %w", err) - } - req.RF1After = t - } - // start and end == 0 is fine if req.End == 0 && req.Start == 0 { return req, nil @@ -708,10 +699,6 @@ func BuildSearchRequest(req *http.Request, searchReq *tempopb.SearchRequest) (*h qb.addParam(urlParamTags, builder.String()) } - if !searchReq.RF1After.IsZero() { - qb.addParam(URLParamRF1After, searchReq.RF1After.Format(time.RFC3339)) - } - req.URL.RawQuery = qb.query() return req, nil @@ -765,8 +752,8 @@ func extractDateRangeParams(vals url.Values) (start, end, since string) { } // ValidateAndSanitizeRequest validates params for trace by id api -// return values are (blockStart, blockEnd, queryMode, start, end, rf1After, error) -func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, int64, time.Time, error) { +// return values are (blockStart, blockEnd, queryMode, start, end, error) +func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, int64, error) { vals := r.URL.Query() q, _ := extractQueryParam(vals, QueryModeKey) @@ -777,7 +764,6 @@ func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, var endTime int64 var blockStart string var blockEnd string - var rf1After time.Time switch { case len(q) == 0 || q == QueryModeAll: @@ -789,18 +775,18 @@ func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, case q == QueryModeExternal: queryMode = QueryModeExternal default: - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("invalid value for mode %s", q) + return "", "", "", 0, 0, fmt.Errorf("invalid value for mode %s", q) } // no need to validate/sanitize other parameters if queryMode == QueryModeIngesters if queryMode == QueryModeIngesters { - return "", "", queryMode, 0, 0, time.Time{}, nil + return "", "", queryMode, 0, 0, nil } if start, ok := extractQueryParam(vals, BlockStartKey); ok { _, err := uuid.Parse(start) if err != nil { - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("invalid value for blockstart: %w", err) + return "", "", "", 0, 0, fmt.Errorf("invalid value for blockstart: %w", err) } blockStart = start } else { @@ -810,7 +796,7 @@ func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, if end, ok := extractQueryParam(vals, BlockEndKey); ok { _, err := uuid.Parse(end) if err != nil { - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("invalid value for blockEnd: %w", err) + return "", "", "", 0, 0, fmt.Errorf("invalid value for blockEnd: %w", err) } blockEnd = end } else { @@ -821,7 +807,7 @@ func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, var err error startTime, err = strconv.ParseInt(s, 10, 64) if err != nil { - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("invalid start: %w", err) + return "", "", "", 0, 0, fmt.Errorf("invalid start: %w", err) } } else { startTime = 0 @@ -831,25 +817,17 @@ func ValidateAndSanitizeRequest(r *http.Request) (string, string, string, int64, var err error endTime, err = strconv.ParseInt(s, 10, 64) if err != nil { - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("invalid end: %w", err) + return "", "", "", 0, 0, fmt.Errorf("invalid end: %w", err) } } else { endTime = 0 } if startTime != 0 && endTime != 0 && endTime <= startTime { - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("http parameter start must be before end. received start=%d end=%d", startTime, endTime) - } - - if rf1AfterStr, ok := extractQueryParam(vals, URLParamRF1After); ok { - var err error - rf1After, err = time.Parse(time.RFC3339, rf1AfterStr) - if err != nil { - return "", "", "", 0, 0, time.Time{}, fmt.Errorf("invalid rf1After: %w", err) - } + return "", "", "", 0, 0, fmt.Errorf("http parameter start must be before end. received start=%d end=%d", startTime, endTime) } - return blockStart, blockEnd, queryMode, startTime, endTime, rf1After, nil + return blockStart, blockEnd, queryMode, startTime, endTime, nil } func ReadBodyToBuffer(resp *http.Response) (*bytes.Buffer, error) { diff --git a/pkg/api/http_test.go b/pkg/api/http_test.go index bba9374ac34..9eb05fde4f7 100644 --- a/pkg/api/http_test.go +++ b/pkg/api/http_test.go @@ -520,7 +520,6 @@ func TestBuildSearchBlockRequest(t *testing.T) { } func TestValidateAndSanitizeRequest(t *testing.T) { - rf1After := time.Date(1970, 1, 1, 1, 16, 40, 0, time.UTC) tests := []struct { httpReq *http.Request queryMode string @@ -528,7 +527,6 @@ func TestValidateAndSanitizeRequest(t *testing.T) { endTime int64 blockStart string blockEnd string - rf1After time.Time expectedError string }{ { @@ -570,7 +568,6 @@ func TestValidateAndSanitizeRequest(t *testing.T) { endTime: 0, blockStart: "12345678000000001235000001240000", blockEnd: "ffffffffffffffffffffffffffffffff", - rf1After: rf1After, }, { httpReq: httptest.NewRequest("GET", "/api/traces/1234?mode=blocks&blockStart=12345678000000001235000001240000&blockEnd=ffffffffffffffffffffffffffffffff&start=1&end=1", nil), @@ -592,7 +589,7 @@ func TestValidateAndSanitizeRequest(t *testing.T) { } for _, tc := range tests { - blockStart, blockEnd, queryMode, startTime, endTime, rf1After, err := ValidateAndSanitizeRequest(tc.httpReq) + blockStart, blockEnd, queryMode, startTime, endTime, err := ValidateAndSanitizeRequest(tc.httpReq) if len(tc.expectedError) != 0 { assert.EqualError(t, err, tc.expectedError) continue @@ -603,7 +600,6 @@ func TestValidateAndSanitizeRequest(t *testing.T) { assert.Equal(t, tc.blockEnd, blockEnd) assert.Equal(t, tc.startTime, startTime) assert.Equal(t, tc.endTime, endTime) - assert.Equal(t, tc.rf1After, rf1After) } } diff --git a/pkg/api/search_tags.go b/pkg/api/search_tags.go index eccbb8a9b22..247123c94ed 100644 --- a/pkg/api/search_tags.go +++ b/pkg/api/search_tags.go @@ -7,7 +7,6 @@ import ( "net/http" "net/url" "strconv" - "time" "github.com/google/uuid" "github.com/gorilla/mux" @@ -381,14 +380,6 @@ func parseSearchTagValuesRequest(r *http.Request, enforceTraceQL bool) (*tempopb req.End = uint32(end) } - if s, ok := extractQueryParam(vals, URLParamRF1After); ok { - t, err := time.Parse(time.RFC3339, s) - if err != nil { - return nil, fmt.Errorf("invalid rf1After: %w", err) - } - req.RF1After = t - } - return req, nil } @@ -423,14 +414,6 @@ func ParseSearchTagsRequest(r *http.Request) (*tempopb.SearchTagsRequest, error) req.End = uint32(end) } - if s, ok := extractQueryParam(vals, URLParamRF1After); ok { - t, err := time.Parse(time.RFC3339, s) - if err != nil { - return nil, fmt.Errorf("invalid rf1After: %w", err) - } - req.RF1After = t - } - return req, nil } diff --git a/pkg/tempopb/tempo.pb.go b/pkg/tempopb/tempo.pb.go index 2e638760cd8..effb11d9d42 100644 --- a/pkg/tempopb/tempo.pb.go +++ b/pkg/tempopb/tempo.pb.go @@ -173,13 +173,12 @@ func (DedicatedColumn_Option) EnumDescriptor() ([]byte, []int) { // Read type TraceByIDRequest struct { - TraceID []byte `protobuf:"bytes,1,opt,name=traceID,proto3" json:"traceID,omitempty"` - BlockStart string `protobuf:"bytes,2,opt,name=blockStart,proto3" json:"blockStart,omitempty"` - BlockEnd string `protobuf:"bytes,3,opt,name=blockEnd,proto3" json:"blockEnd,omitempty"` - QueryMode string `protobuf:"bytes,5,opt,name=queryMode,proto3" json:"queryMode,omitempty"` - AllowPartialTrace bool `protobuf:"varint,6,opt,name=allowPartialTrace,proto3" json:"allowPartialTrace,omitempty"` - // Rhythm fields - RF1After time.Time `protobuf:"bytes,7,opt,name=RF1After,proto3,stdtime" json:"RF1After"` + TraceID []byte `protobuf:"bytes,1,opt,name=traceID,proto3" json:"traceID,omitempty"` + BlockStart string `protobuf:"bytes,2,opt,name=blockStart,proto3" json:"blockStart,omitempty"` + BlockEnd string `protobuf:"bytes,3,opt,name=blockEnd,proto3" json:"blockEnd,omitempty"` + QueryMode string `protobuf:"bytes,5,opt,name=queryMode,proto3" json:"queryMode,omitempty"` + AllowPartialTrace bool `protobuf:"varint,6,opt,name=allowPartialTrace,proto3" json:"allowPartialTrace,omitempty"` + RF1After time.Time `protobuf:"bytes,7,opt,name=RF1After,proto3,stdtime" json:"RF1After"` // Deprecated: Do not use. } func (m *TraceByIDRequest) Reset() { *m = TraceByIDRequest{} } @@ -250,6 +249,7 @@ func (m *TraceByIDRequest) GetAllowPartialTrace() bool { return false } +// Deprecated: Do not use. func (m *TraceByIDRequest) GetRF1After() time.Time { if m != nil { return m.RF1After @@ -379,10 +379,9 @@ type SearchRequest struct { Start uint32 `protobuf:"varint,5,opt,name=start,proto3" json:"start,omitempty"` End uint32 `protobuf:"varint,6,opt,name=end,proto3" json:"end,omitempty"` // TraceQL query - Query string `protobuf:"bytes,8,opt,name=Query,proto3" json:"Query,omitempty"` - SpansPerSpanSet uint32 `protobuf:"varint,9,opt,name=SpansPerSpanSet,proto3" json:"SpansPerSpanSet,omitempty"` - // Rhythm fields - RF1After time.Time `protobuf:"bytes,10,opt,name=RF1After,proto3,stdtime" json:"RF1After"` + Query string `protobuf:"bytes,8,opt,name=Query,proto3" json:"Query,omitempty"` + SpansPerSpanSet uint32 `protobuf:"varint,9,opt,name=SpansPerSpanSet,proto3" json:"SpansPerSpanSet,omitempty"` + RF1After time.Time `protobuf:"bytes,10,opt,name=RF1After,proto3,stdtime" json:"RF1After"` // Deprecated: Do not use. } func (m *SearchRequest) Reset() { *m = SearchRequest{} } @@ -474,6 +473,7 @@ func (m *SearchRequest) GetSpansPerSpanSet() uint32 { return 0 } +// Deprecated: Do not use. func (m *SearchRequest) GetRF1After() time.Time { if m != nil { return m.RF1After @@ -1103,14 +1103,13 @@ func (m *SearchMetrics) GetInspectedSpans() uint64 { } type SearchTagsRequest struct { - Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"` - Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` - Start uint32 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` - End uint32 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` - MaxTagsPerScope uint32 `protobuf:"varint,5,opt,name=maxTagsPerScope,proto3" json:"maxTagsPerScope,omitempty"` - StaleValuesThreshold uint32 `protobuf:"varint,6,opt,name=staleValuesThreshold,proto3" json:"staleValuesThreshold,omitempty"` - // Rhythm fields - RF1After time.Time `protobuf:"bytes,7,opt,name=RF1After,proto3,stdtime" json:"RF1After"` + Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"` + Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` + Start uint32 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` + End uint32 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + MaxTagsPerScope uint32 `protobuf:"varint,5,opt,name=maxTagsPerScope,proto3" json:"maxTagsPerScope,omitempty"` + StaleValuesThreshold uint32 `protobuf:"varint,6,opt,name=staleValuesThreshold,proto3" json:"staleValuesThreshold,omitempty"` + RF1After time.Time `protobuf:"bytes,7,opt,name=RF1After,proto3,stdtime" json:"RF1After"` // Deprecated: Do not use. } func (m *SearchTagsRequest) Reset() { *m = SearchTagsRequest{} } @@ -1188,6 +1187,7 @@ func (m *SearchTagsRequest) GetStaleValuesThreshold() uint32 { return 0 } +// Deprecated: Do not use. func (m *SearchTagsRequest) GetRF1After() time.Time { if m != nil { return m.RF1After @@ -1606,14 +1606,13 @@ func (m *SearchTagsV2Scope) GetTags() []string { } type SearchTagValuesRequest struct { - TagName string `protobuf:"bytes,1,opt,name=tagName,proto3" json:"tagName,omitempty"` - Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` - Start uint32 `protobuf:"varint,4,opt,name=start,proto3" json:"start,omitempty"` - End uint32 `protobuf:"varint,5,opt,name=end,proto3" json:"end,omitempty"` - MaxTagValues uint32 `protobuf:"varint,6,opt,name=maxTagValues,proto3" json:"maxTagValues,omitempty"` - StaleValueThreshold uint32 `protobuf:"varint,7,opt,name=staleValueThreshold,proto3" json:"staleValueThreshold,omitempty"` - // Rhythm fields - RF1After time.Time `protobuf:"bytes,8,opt,name=RF1After,proto3,stdtime" json:"RF1After"` + TagName string `protobuf:"bytes,1,opt,name=tagName,proto3" json:"tagName,omitempty"` + Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` + Start uint32 `protobuf:"varint,4,opt,name=start,proto3" json:"start,omitempty"` + End uint32 `protobuf:"varint,5,opt,name=end,proto3" json:"end,omitempty"` + MaxTagValues uint32 `protobuf:"varint,6,opt,name=maxTagValues,proto3" json:"maxTagValues,omitempty"` + StaleValueThreshold uint32 `protobuf:"varint,7,opt,name=staleValueThreshold,proto3" json:"staleValueThreshold,omitempty"` + RF1After time.Time `protobuf:"bytes,8,opt,name=RF1After,proto3,stdtime" json:"RF1After"` // Deprecated: Do not use. } func (m *SearchTagValuesRequest) Reset() { *m = SearchTagValuesRequest{} } @@ -1691,6 +1690,7 @@ func (m *SearchTagValuesRequest) GetStaleValueThreshold() uint32 { return 0 } +// Deprecated: Do not use. func (m *SearchTagValuesRequest) GetRF1After() time.Time { if m != nil { return m.RF1After @@ -2895,167 +2895,168 @@ func init() { func init() { proto.RegisterFile("tempo.proto", fileDescriptor_b334b194b16825ec) } var fileDescriptor_b334b194b16825ec = []byte{ - // 2560 bytes of a gzipped FileDescriptorProto + // 2561 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x59, 0xdd, 0x6f, 0x23, 0x57, - 0x15, 0xcf, 0xf8, 0xdb, 0xc7, 0x76, 0x32, 0xb9, 0xc9, 0xa6, 0x5e, 0x67, 0x37, 0x09, 0xc3, 0x0a, - 0xa2, 0x6d, 0xeb, 0x24, 0xee, 0x22, 0xba, 0xbb, 0xa2, 0x60, 0x6f, 0xdc, 0x6d, 0xba, 0x89, 0x13, - 0xae, 0xbd, 0xa1, 0xa0, 0x4a, 0xd1, 0xc4, 0xbe, 0xeb, 0x1d, 0xc5, 0x9e, 0x71, 0x67, 0xc6, 0x21, - 0xe1, 0xa1, 0x42, 0x42, 0x40, 0x91, 0x78, 0xd8, 0x47, 0xf8, 0x0b, 0xf8, 0x17, 0x90, 0x10, 0x2f, - 0xf0, 0x52, 0xc4, 0x4b, 0x25, 0x5e, 0x10, 0x42, 0x05, 0xed, 0xbe, 0xf1, 0x07, 0xf0, 0x8c, 0xee, - 0xd7, 0x7c, 0x79, 0x9c, 0xfd, 0x68, 0x2a, 0xf1, 0xd0, 0x27, 0xcf, 0x3d, 0xf7, 0x77, 0xcf, 0x9c, - 0x7b, 0xce, 0xb9, 0xe7, 0xfc, 0xee, 0x18, 0x0a, 0x2e, 0x19, 0x8e, 0xac, 0xea, 0xc8, 0xb6, 0x5c, - 0x0b, 0x65, 0xd9, 0x60, 0x74, 0x5c, 0x59, 0xea, 0x5a, 0xc3, 0xa1, 0x65, 0x6e, 0x9c, 0x6e, 0x6d, - 0xf0, 0x27, 0x0e, 0xa8, 0xbc, 0xd9, 0x37, 0xdc, 0xc7, 0xe3, 0xe3, 0x6a, 0xd7, 0x1a, 0x6e, 0xf4, - 0xad, 0xbe, 0xb5, 0xc1, 0xc4, 0xc7, 0xe3, 0x47, 0x6c, 0xc4, 0x06, 0xec, 0x49, 0xc0, 0x17, 0x5d, - 0x5b, 0xef, 0x12, 0xaa, 0x85, 0x3d, 0x08, 0xe9, 0x6a, 0xdf, 0xb2, 0xfa, 0x03, 0xe2, 0xaf, 0x75, - 0x8d, 0x21, 0x71, 0x5c, 0x7d, 0x38, 0xe2, 0x00, 0xed, 0xbf, 0x0a, 0xa8, 0x1d, 0xba, 0xa0, 0x71, - 0xbe, 0xb3, 0x8d, 0xc9, 0x47, 0x63, 0xe2, 0xb8, 0xa8, 0x0c, 0x59, 0xa6, 0x64, 0x67, 0xbb, 0xac, - 0xac, 0x29, 0xeb, 0x45, 0x2c, 0x87, 0x68, 0x05, 0xe0, 0x78, 0x60, 0x75, 0x4f, 0xda, 0xae, 0x6e, - 0xbb, 0xe5, 0xc4, 0x9a, 0xb2, 0x9e, 0xc7, 0x01, 0x09, 0xaa, 0x40, 0x8e, 0x8d, 0x9a, 0x66, 0xaf, - 0x9c, 0x64, 0xb3, 0xde, 0x18, 0x5d, 0x83, 0xfc, 0x47, 0x63, 0x62, 0x9f, 0xef, 0x59, 0x3d, 0x52, - 0x4e, 0xb3, 0x49, 0x5f, 0x80, 0xde, 0x80, 0x79, 0x7d, 0x30, 0xb0, 0x7e, 0x7c, 0xa0, 0xdb, 0xae, - 0xa1, 0x0f, 0x98, 0x4d, 0xe5, 0xcc, 0x9a, 0xb2, 0x9e, 0xc3, 0x93, 0x13, 0xe8, 0x7b, 0x90, 0xc3, - 0xef, 0x6e, 0xd5, 0x1f, 0xb9, 0xc4, 0x2e, 0x67, 0xd7, 0x94, 0xf5, 0x42, 0xad, 0x52, 0xe5, 0x5b, - 0xad, 0xca, 0xad, 0x56, 0x3b, 0x72, 0xab, 0x8d, 0xdc, 0xa7, 0x9f, 0xaf, 0xce, 0x3c, 0xf9, 0xd7, - 0xaa, 0x82, 0xbd, 0x55, 0xda, 0xef, 0x15, 0x98, 0x0f, 0x6c, 0xdc, 0x19, 0x59, 0xa6, 0x43, 0xd0, - 0x0d, 0x48, 0xb3, 0xad, 0xb2, 0x7d, 0x17, 0x6a, 0xb3, 0x55, 0x11, 0xa5, 0x2a, 0x83, 0x62, 0x3e, - 0x89, 0xde, 0x82, 0xec, 0x90, 0xb8, 0xb6, 0xd1, 0x75, 0x98, 0x0b, 0x0a, 0xb5, 0xab, 0x61, 0x1c, - 0x55, 0xb9, 0xc7, 0x01, 0x58, 0x22, 0x51, 0x15, 0x32, 0x8e, 0xab, 0xbb, 0x63, 0x87, 0x39, 0x66, - 0xb6, 0xb6, 0xe4, 0xad, 0x11, 0x3b, 0x6b, 0xb3, 0x59, 0x2c, 0x50, 0x34, 0x08, 0x43, 0xe2, 0x38, - 0x7a, 0x9f, 0x94, 0x53, 0xcc, 0x59, 0x72, 0xa8, 0xdd, 0x09, 0x84, 0x4c, 0xbc, 0x06, 0x7d, 0x03, - 0x66, 0x0d, 0xd3, 0x19, 0x91, 0xae, 0x4b, 0x7a, 0x8d, 0x73, 0x97, 0x38, 0x6c, 0x07, 0x29, 0x1c, - 0x91, 0x6a, 0x4f, 0x92, 0x50, 0x6a, 0x13, 0xdd, 0xee, 0x3e, 0x96, 0xc1, 0xbe, 0x03, 0xa9, 0x8e, - 0xde, 0xa7, 0xf8, 0xe4, 0x7a, 0xa1, 0xb6, 0xe6, 0x59, 0x15, 0x42, 0x55, 0x29, 0xa4, 0x69, 0xba, - 0xf6, 0x79, 0x23, 0x45, 0x9d, 0x89, 0xd9, 0x1a, 0x74, 0x03, 0x4a, 0x7b, 0x86, 0xb9, 0x3d, 0xb6, - 0x75, 0xd7, 0xb0, 0xcc, 0x3d, 0xee, 0x8e, 0x12, 0x0e, 0x0b, 0x19, 0x4a, 0x3f, 0x0b, 0xa0, 0x92, - 0x02, 0x15, 0x14, 0xa2, 0x45, 0x48, 0xef, 0x1a, 0x43, 0xc3, 0x65, 0xbb, 0x2d, 0x61, 0x3e, 0xa0, - 0x52, 0x87, 0xe5, 0x5a, 0x9a, 0x4b, 0xd9, 0x00, 0xa9, 0x90, 0x24, 0x66, 0x8f, 0xa5, 0x47, 0x09, - 0xd3, 0x47, 0x8a, 0xfb, 0x3e, 0xcd, 0xa5, 0x72, 0x8e, 0xf9, 0x8a, 0x0f, 0xd0, 0x3a, 0xcc, 0xb5, - 0x47, 0xba, 0xe9, 0x1c, 0x10, 0x9b, 0xfe, 0xb6, 0x89, 0x5b, 0xce, 0xb3, 0x35, 0x51, 0x71, 0x28, - 0xa1, 0xe0, 0x55, 0x12, 0xaa, 0xf2, 0x6d, 0xc8, 0x7b, 0x4e, 0xa2, 0x06, 0x9e, 0x90, 0x73, 0x16, - 0x83, 0x3c, 0xa6, 0x8f, 0xd4, 0xc0, 0x53, 0x7d, 0x30, 0x26, 0xe2, 0xd0, 0xf0, 0xc1, 0x9d, 0xc4, - 0xdb, 0x8a, 0xf6, 0x8b, 0x24, 0x20, 0xee, 0xec, 0x06, 0x3d, 0x2a, 0x32, 0x2e, 0xb7, 0x20, 0xef, - 0xc8, 0x10, 0x88, 0x74, 0x5c, 0x8a, 0x0f, 0x0e, 0xf6, 0x81, 0x34, 0x6b, 0xd8, 0x81, 0xdb, 0xd9, - 0x16, 0x2f, 0x92, 0x43, 0x7a, 0xfc, 0x98, 0xf3, 0x0e, 0x68, 0x46, 0xf1, 0x08, 0xf8, 0x02, 0x1a, - 0xa3, 0x91, 0xde, 0x27, 0x4e, 0xc7, 0xe2, 0xaa, 0x45, 0x14, 0xc2, 0x42, 0x8a, 0x32, 0xcc, 0x1e, - 0x39, 0xa3, 0x4b, 0xda, 0xc6, 0x4f, 0x88, 0x88, 0x40, 0x58, 0x88, 0x34, 0x28, 0xba, 0x96, 0xab, - 0x0f, 0x30, 0xe9, 0x5a, 0x76, 0xcf, 0x61, 0x07, 0xb4, 0x84, 0x43, 0x32, 0x6a, 0xe7, 0x29, 0xb1, - 0x1d, 0xc3, 0x32, 0x59, 0x44, 0xf2, 0x58, 0x0e, 0x11, 0x82, 0x94, 0x43, 0x55, 0x03, 0xcb, 0x5f, - 0xf6, 0x4c, 0xcb, 0xce, 0x23, 0xcb, 0x72, 0x89, 0xcd, 0x5e, 0x5a, 0x60, 0xfa, 0x02, 0x12, 0xb4, - 0x0d, 0x6a, 0x8f, 0xf4, 0x8c, 0xae, 0xee, 0x92, 0xde, 0x3d, 0x6b, 0x30, 0x1e, 0x9a, 0x4e, 0xb9, - 0xc8, 0xf2, 0xb9, 0xec, 0xb9, 0x6c, 0x3b, 0x0c, 0xc0, 0x13, 0x2b, 0xb4, 0x3f, 0x24, 0x60, 0x2e, - 0x82, 0x42, 0xb7, 0x20, 0xed, 0x74, 0xad, 0x11, 0x11, 0x87, 0x76, 0x65, 0x9a, 0xba, 0x6a, 0x9b, - 0xa2, 0x30, 0x07, 0xd3, 0x3d, 0x98, 0xfa, 0x50, 0xc6, 0x9a, 0x3d, 0xa3, 0x2d, 0x48, 0xb9, 0xe7, - 0x23, 0x5e, 0x59, 0x66, 0x6b, 0xd7, 0xa7, 0x2a, 0xea, 0x9c, 0x8f, 0x08, 0x66, 0x50, 0x74, 0x1b, - 0xb2, 0xd6, 0x88, 0x1e, 0x0f, 0x87, 0x85, 0x63, 0xb6, 0xb6, 0x3a, 0x75, 0xd5, 0x3e, 0xc3, 0x61, - 0x89, 0xd7, 0x6e, 0x42, 0x9a, 0x59, 0x84, 0x72, 0x90, 0x6a, 0x1f, 0xd4, 0x5b, 0xea, 0x0c, 0x2a, - 0x42, 0x0e, 0x37, 0xdb, 0xfb, 0x0f, 0xf1, 0xbd, 0xa6, 0xaa, 0xa0, 0x3c, 0xa4, 0x9b, 0x87, 0xcd, - 0x56, 0x47, 0x4d, 0x68, 0xcb, 0x90, 0xa2, 0x2f, 0x45, 0x00, 0x99, 0x76, 0x07, 0xef, 0xb4, 0xee, - 0xab, 0x33, 0x28, 0x0b, 0xc9, 0x9d, 0x56, 0x47, 0x55, 0xb4, 0x6f, 0x42, 0x86, 0xeb, 0xa6, 0x9a, - 0x5a, 0xfb, 0xad, 0xa6, 0x3a, 0x43, 0xd7, 0xd6, 0x31, 0xae, 0xff, 0x50, 0x55, 0xa8, 0xb0, 0xb1, - 0xbb, 0xdf, 0x50, 0x13, 0xda, 0x19, 0xcc, 0xca, 0xac, 0x14, 0xc5, 0xf4, 0x16, 0x64, 0x58, 0xbd, - 0x94, 0xb5, 0xe5, 0x5a, 0xb8, 0x4a, 0x72, 0xf4, 0x1e, 0x71, 0xf5, 0x9e, 0xee, 0xea, 0x58, 0x60, - 0xd1, 0x66, 0xb4, 0xb8, 0x46, 0xb3, 0x3e, 0x5a, 0x59, 0xb5, 0xbf, 0x25, 0x61, 0x21, 0x46, 0x63, - 0xb4, 0x8d, 0xe5, 0xfd, 0x36, 0xb6, 0x0e, 0x73, 0xb6, 0x65, 0xb9, 0x6d, 0x62, 0x9f, 0x1a, 0x5d, - 0xd2, 0xf2, 0x43, 0x15, 0x15, 0xd3, 0x8c, 0xa7, 0x22, 0xa6, 0x9e, 0xe1, 0x78, 0x57, 0x0b, 0x0b, - 0x69, 0xf3, 0x62, 0x47, 0x89, 0x56, 0x88, 0x87, 0xa6, 0x71, 0xd6, 0xd2, 0x4d, 0x8b, 0x85, 0x2c, - 0x85, 0x27, 0x27, 0x68, 0x36, 0xf7, 0xfc, 0x62, 0xc8, 0x0b, 0x5b, 0x40, 0x82, 0x6e, 0x42, 0xd6, - 0x11, 0xd5, 0x2a, 0xc3, 0x3c, 0xa0, 0xfa, 0x1e, 0xe0, 0x72, 0x2c, 0x01, 0xe8, 0x0d, 0xc8, 0x89, - 0x47, 0x7a, 0xce, 0x92, 0xb1, 0x60, 0x0f, 0x81, 0x30, 0x14, 0x1d, 0xbe, 0x39, 0xda, 0x6c, 0x9c, - 0x72, 0x8e, 0xad, 0xa8, 0x5e, 0x14, 0x97, 0x6a, 0x3b, 0xb0, 0x80, 0x15, 0x37, 0x1c, 0xd2, 0x51, - 0x39, 0x84, 0xf9, 0x09, 0x48, 0x4c, 0xfd, 0x7b, 0x3d, 0x58, 0xff, 0x0a, 0xb5, 0x2b, 0x81, 0xa0, - 0xfa, 0x8b, 0x83, 0x65, 0x71, 0x17, 0x8a, 0xc1, 0x29, 0x56, 0xbf, 0x46, 0xba, 0x79, 0xcf, 0x1a, - 0x9b, 0x2e, 0x53, 0x4c, 0xeb, 0x97, 0x14, 0x50, 0x9f, 0x12, 0xdb, 0xb6, 0x6c, 0x3e, 0xcd, 0xdb, - 0x50, 0x40, 0xa2, 0xfd, 0x5c, 0x81, 0xac, 0xac, 0xf5, 0x5f, 0x87, 0x34, 0x5d, 0x28, 0xd3, 0xb2, - 0x14, 0x72, 0x18, 0xe6, 0x73, 0xac, 0xfd, 0xea, 0x6e, 0xf7, 0x31, 0xe9, 0x09, 0x6d, 0x72, 0x88, - 0xee, 0x02, 0xe8, 0xae, 0x6b, 0x1b, 0xc7, 0x63, 0xda, 0x66, 0x93, 0x4c, 0xc7, 0xb2, 0xa7, 0x43, - 0x70, 0xb8, 0xd3, 0xad, 0xea, 0x03, 0x72, 0x7e, 0x48, 0x77, 0x83, 0x03, 0x70, 0xed, 0xcf, 0x0a, - 0xa4, 0xe8, 0x6b, 0xd0, 0x12, 0x64, 0xe8, 0x8b, 0xbc, 0xdc, 0x14, 0xa3, 0xd8, 0xd2, 0x11, 0x9b, - 0x5e, 0xc9, 0x69, 0xe9, 0x75, 0x03, 0x4a, 0x32, 0x99, 0xe8, 0xd8, 0x11, 0x89, 0x18, 0x16, 0x46, - 0x76, 0x91, 0x7e, 0xb9, 0x5d, 0xfc, 0x36, 0x21, 0x59, 0x84, 0xe4, 0x1f, 0xeb, 0x30, 0xe7, 0x31, - 0x8d, 0x8e, 0x3c, 0xf4, 0xac, 0xd3, 0x46, 0xc4, 0x31, 0x4c, 0x25, 0x11, 0xc7, 0x54, 0xd0, 0x1a, - 0x14, 0x58, 0xc7, 0x60, 0x4d, 0x51, 0x72, 0x86, 0xa0, 0x88, 0x6e, 0xb4, 0x6b, 0x0d, 0x47, 0x03, - 0xe2, 0x92, 0xde, 0xfb, 0xd6, 0xb1, 0x23, 0x7b, 0x56, 0x48, 0x48, 0xf3, 0x86, 0x2d, 0x62, 0x08, - 0x7e, 0xd8, 0x7c, 0x01, 0xb5, 0xdb, 0x57, 0xc9, 0xcd, 0xc9, 0x30, 0x73, 0xa2, 0xe2, 0x90, 0xdd, - 0x8c, 0x3d, 0xb0, 0xbe, 0x16, 0xb4, 0x9b, 0x49, 0xb5, 0x5f, 0x26, 0xe8, 0x81, 0xa0, 0xbe, 0xa1, - 0x74, 0x40, 0x76, 0xf3, 0x45, 0xd9, 0x47, 0x78, 0xb4, 0x45, 0x9f, 0x58, 0x84, 0x34, 0x63, 0xc0, - 0x92, 0x14, 0xb0, 0x81, 0xcf, 0x79, 0x92, 0x31, 0x9c, 0x27, 0xe5, 0x73, 0x9e, 0x75, 0x98, 0x1b, - 0xea, 0x67, 0xf4, 0x2d, 0x94, 0xc8, 0x30, 0xed, 0x7c, 0x7f, 0x51, 0x31, 0xaa, 0xc1, 0xa2, 0xe3, - 0xea, 0x03, 0xc2, 0x22, 0xe9, 0x74, 0x1e, 0xdb, 0xc4, 0x79, 0x6c, 0x0d, 0x24, 0x81, 0x8a, 0x9d, - 0xbb, 0x04, 0x8a, 0xfd, 0x9f, 0x24, 0x2c, 0xf9, 0x9e, 0x08, 0x91, 0x9b, 0xb7, 0x27, 0xc9, 0x4d, - 0x25, 0x52, 0xe6, 0x03, 0xde, 0xfb, 0x8a, 0xe0, 0x5c, 0x0a, 0xc1, 0x89, 0x4b, 0x98, 0x52, 0x7c, - 0xc2, 0x6c, 0xc2, 0x82, 0x9f, 0x14, 0x7e, 0xbe, 0xcc, 0x32, 0x74, 0xdc, 0x94, 0xf6, 0x9b, 0x24, - 0x2c, 0x7b, 0x81, 0xe3, 0xb9, 0x14, 0x8a, 0xf8, 0x77, 0x26, 0x23, 0xbe, 0x3a, 0x19, 0x71, 0xbe, - 0xf0, 0xab, 0xb0, 0x5f, 0x2a, 0xaf, 0xed, 0xc9, 0xfb, 0x05, 0x3f, 0x52, 0x82, 0x9d, 0x55, 0x20, - 0xe7, 0xea, 0x7d, 0x4a, 0x5f, 0x78, 0x23, 0xcc, 0x63, 0x6f, 0x8c, 0x6a, 0x51, 0x0e, 0xe6, 0xbf, - 0x4e, 0xf2, 0x82, 0x09, 0x16, 0xf6, 0x31, 0x2c, 0xfa, 0x6f, 0x39, 0xac, 0x79, 0xef, 0xa9, 0x41, - 0x86, 0x15, 0x3b, 0xd9, 0x6e, 0xe3, 0xce, 0xf9, 0x61, 0x8d, 0xd3, 0x67, 0x81, 0x7c, 0xa5, 0xf7, - 0xdf, 0x0d, 0x96, 0x5d, 0xa1, 0xd0, 0xeb, 0xa6, 0x4a, 0xa0, 0x9b, 0x22, 0x48, 0xb9, 0xf4, 0xc2, - 0x9b, 0x60, 0x9b, 0x66, 0xcf, 0xda, 0x27, 0x89, 0x40, 0xa9, 0x0a, 0x25, 0x21, 0x63, 0x91, 0xdc, - 0x2f, 0x1e, 0x8b, 0xe4, 0xc3, 0xe7, 0x55, 0xef, 0x54, 0x4c, 0xf5, 0x4e, 0xfb, 0xd5, 0x5b, 0x83, - 0x22, 0x3f, 0x75, 0xfc, 0x75, 0x22, 0xe5, 0x42, 0xb2, 0x69, 0xc7, 0x30, 0x3b, 0xf5, 0x18, 0x86, - 0xaa, 0x76, 0xee, 0x95, 0xaa, 0xf6, 0x09, 0xbc, 0x36, 0xe1, 0x09, 0x11, 0x4a, 0xda, 0x4a, 0x3d, - 0x7b, 0x79, 0xce, 0xf8, 0x82, 0x57, 0x0a, 0xda, 0x2d, 0xc8, 0xc9, 0xd7, 0xb0, 0xb8, 0x9c, 0x7b, - 0x1d, 0x92, 0xdf, 0x80, 0x62, 0x6f, 0xcd, 0xda, 0x4f, 0x15, 0xb8, 0x1a, 0xb1, 0x31, 0x90, 0x70, - 0x1b, 0x51, 0x2b, 0x0b, 0xb5, 0x79, 0x9f, 0xe1, 0x8a, 0x99, 0x2f, 0x6a, 0xf8, 0x5f, 0x14, 0x98, - 0x8b, 0x4c, 0xbe, 0xe8, 0x37, 0x98, 0x30, 0x23, 0x49, 0x44, 0x19, 0xc9, 0x04, 0xab, 0x49, 0xc6, - 0xb1, 0x9a, 0x08, 0x3b, 0x4a, 0x4d, 0xb2, 0xa3, 0x18, 0x66, 0x93, 0x8e, 0x65, 0x36, 0x5a, 0x0b, - 0xd2, 0xfc, 0xab, 0x5a, 0x13, 0x4a, 0x36, 0x71, 0xac, 0xb1, 0xdd, 0x25, 0xed, 0x00, 0x41, 0xf6, - 0xeb, 0x34, 0xff, 0xb4, 0x78, 0xba, 0x55, 0xc5, 0x41, 0x18, 0x0e, 0xaf, 0xd2, 0x5a, 0x50, 0x3c, - 0x18, 0x3b, 0xfe, 0x3d, 0xf0, 0x1d, 0x28, 0x31, 0x26, 0xee, 0x34, 0xce, 0x3b, 0xe2, 0xe3, 0x5a, - 0x72, 0x7d, 0x36, 0xe0, 0x65, 0x8a, 0x6e, 0x52, 0x04, 0x26, 0xba, 0x63, 0x99, 0x38, 0x0c, 0xd7, - 0x7e, 0xa5, 0x80, 0x4a, 0x21, 0xcc, 0x5a, 0x79, 0x2c, 0xdf, 0xf4, 0x2e, 0x97, 0xf4, 0x1c, 0x17, - 0x1b, 0x57, 0x68, 0x2a, 0xff, 0xe3, 0xf3, 0xd5, 0xd2, 0x81, 0x4d, 0xf4, 0xc1, 0xc0, 0xea, 0x72, - 0xb4, 0xbc, 0x55, 0xaa, 0x90, 0x34, 0x7a, 0x9c, 0xad, 0x17, 0x31, 0x7d, 0x44, 0xb7, 0xe0, 0x8a, - 0x73, 0x62, 0x8c, 0x44, 0xf0, 0xee, 0x13, 0x93, 0x70, 0x7a, 0xcc, 0xbc, 0x94, 0xc3, 0xf1, 0x93, - 0xda, 0xcf, 0x84, 0x2d, 0x7c, 0xe3, 0xc2, 0x96, 0xdb, 0x90, 0x3d, 0x66, 0x97, 0x83, 0x17, 0xf6, - 0x98, 0xc4, 0x4f, 0xb7, 0x22, 0x71, 0x91, 0x15, 0x37, 0x00, 0xc4, 0x17, 0x40, 0x9a, 0x4f, 0x4b, - 0xa1, 0x7b, 0x76, 0x51, 0xee, 0x59, 0x7b, 0x07, 0xf2, 0xbb, 0x86, 0x79, 0xd2, 0x1e, 0x18, 0x5d, - 0x82, 0xb6, 0x20, 0x3d, 0x30, 0xcc, 0x13, 0x69, 0xe1, 0xf2, 0xa4, 0x85, 0xd4, 0xb2, 0x2a, 0x5d, - 0x80, 0x39, 0x52, 0x6b, 0xc3, 0x02, 0xfb, 0x8c, 0xb6, 0x63, 0x3a, 0xae, 0x6e, 0xba, 0x01, 0x2a, - 0xcb, 0xcb, 0x9e, 0x12, 0x5b, 0xf6, 0x38, 0x9b, 0x0f, 0x97, 0x3d, 0x7e, 0x57, 0xa1, 0x8f, 0xda, - 0x9f, 0x14, 0x58, 0x0c, 0x6b, 0x15, 0x59, 0x52, 0x85, 0x8c, 0x43, 0x6c, 0xc3, 0xf3, 0xa1, 0x7f, - 0xed, 0x17, 0xc8, 0x36, 0x9b, 0xc5, 0x02, 0xf5, 0xf2, 0xdf, 0x09, 0x2e, 0xf1, 0x0b, 0xac, 0x03, - 0xa5, 0x90, 0x51, 0xe8, 0x36, 0x64, 0x06, 0xfa, 0x31, 0x19, 0x4c, 0xba, 0x77, 0xf2, 0x26, 0x25, - 0xbe, 0xa0, 0x8a, 0x05, 0xe1, 0x12, 0xa7, 0x88, 0x12, 0xf7, 0x7e, 0x2a, 0x97, 0x54, 0x53, 0xb8, - 0x30, 0xb2, 0xad, 0xe1, 0x11, 0x07, 0x6a, 0xff, 0x4c, 0xc2, 0x3c, 0xf3, 0x1c, 0xd6, 0xcd, 0x3e, - 0xb9, 0x94, 0x68, 0x30, 0x52, 0xe2, 0x92, 0x91, 0xb8, 0x22, 0xb2, 0xe7, 0xf0, 0x77, 0xfa, 0x6c, - 0xf4, 0x3b, 0x7d, 0x80, 0x88, 0xe5, 0x2e, 0x20, 0x62, 0xf9, 0xe7, 0x12, 0x31, 0x88, 0x23, 0x62, - 0x01, 0xfa, 0x54, 0x88, 0xa7, 0x4f, 0xa5, 0xa9, 0xf4, 0x69, 0xf6, 0x85, 0xe8, 0xd3, 0xdc, 0x4b, - 0xb3, 0xe6, 0x6b, 0x90, 0x27, 0x67, 0x64, 0x38, 0x1a, 0xe8, 0xb6, 0x53, 0x56, 0xf9, 0xbe, 0x3c, - 0x01, 0x9d, 0x1d, 0xea, 0x67, 0x3c, 0x0d, 0xca, 0xf3, 0x7c, 0xd6, 0x13, 0xa0, 0xeb, 0x90, 0x35, - 0x78, 0xa2, 0x94, 0x11, 0x3d, 0xd0, 0xef, 0xcd, 0x60, 0x29, 0xf8, 0x44, 0x51, 0x1a, 0x00, 0xb9, - 0x23, 0x31, 0xd4, 0xfe, 0xa8, 0x00, 0x0a, 0x86, 0x57, 0x1c, 0x8b, 0xd7, 0x23, 0xc7, 0x62, 0xc1, - 0x6f, 0x65, 0xc6, 0x90, 0xfc, 0x1f, 0x9d, 0x89, 0x8f, 0x21, 0xd7, 0x14, 0x5e, 0xb9, 0xf4, 0xe3, - 0x80, 0xbe, 0x06, 0x45, 0xef, 0x9f, 0xab, 0xa3, 0x21, 0x37, 0x36, 0x89, 0x0b, 0x9e, 0x6c, 0xcf, - 0xd1, 0xea, 0x90, 0x69, 0xeb, 0xb4, 0x45, 0x4e, 0x80, 0x13, 0x13, 0x60, 0xff, 0x2d, 0x4a, 0xe0, - 0x2d, 0xb4, 0x36, 0x81, 0xef, 0xd5, 0x2f, 0xb2, 0x8b, 0x0d, 0xc8, 0x3a, 0xcc, 0x18, 0xde, 0x9e, - 0x0a, 0xb5, 0x39, 0x3f, 0x10, 0x4c, 0x2e, 0xf0, 0x12, 0x85, 0xbe, 0x15, 0x4c, 0xb2, 0x54, 0x84, - 0xb4, 0x48, 0xbf, 0x8a, 0x45, 0x3e, 0x32, 0xa6, 0x4c, 0xdc, 0xfc, 0x10, 0xe6, 0x22, 0xfd, 0x14, - 0x15, 0x21, 0xd7, 0xda, 0x3f, 0x6a, 0x62, 0xbc, 0x8f, 0xd5, 0x19, 0xb4, 0x00, 0x73, 0x7b, 0xf5, - 0x0f, 0x8e, 0x76, 0x77, 0x0e, 0x9b, 0x47, 0x1d, 0x5c, 0xbf, 0xd7, 0x6c, 0xab, 0x0a, 0x15, 0xb2, - 0xe7, 0xa3, 0xce, 0xfe, 0xfe, 0xd1, 0x6e, 0x1d, 0xdf, 0x6f, 0xaa, 0x09, 0x34, 0x0f, 0xa5, 0x87, - 0xad, 0x07, 0xad, 0xfd, 0x1f, 0xb4, 0xc4, 0xe2, 0xe4, 0xcd, 0x9b, 0x50, 0x0a, 0x25, 0x06, 0xd5, - 0x7d, 0x6f, 0x7f, 0xef, 0x60, 0xb7, 0xd9, 0x69, 0xaa, 0x33, 0xa8, 0x00, 0xd9, 0x83, 0x3a, 0xee, - 0xec, 0xd4, 0x77, 0x55, 0xa5, 0xf6, 0x6b, 0x05, 0x32, 0xd4, 0x14, 0x62, 0xa3, 0xef, 0x42, 0xde, - 0xeb, 0xe0, 0xe8, 0x6a, 0xa8, 0xf1, 0x07, 0xbb, 0x7a, 0xe5, 0x4a, 0x68, 0x4a, 0x1e, 0x02, 0x6d, - 0x06, 0xd5, 0xa1, 0xe0, 0x81, 0x0f, 0x6b, 0xaf, 0xa2, 0xa2, 0xf6, 0xbb, 0x14, 0x64, 0xe9, 0x01, - 0x33, 0x88, 0x8d, 0xde, 0x83, 0xd2, 0xbb, 0x86, 0xd9, 0xf3, 0xfe, 0x46, 0x43, 0x31, 0xff, 0xe0, - 0x49, 0x85, 0x95, 0xb8, 0xa9, 0x80, 0x61, 0x45, 0xf9, 0xd9, 0xbb, 0x4b, 0x4c, 0x17, 0x4d, 0xf9, - 0x8f, 0xa6, 0xf2, 0xda, 0x84, 0xdc, 0x53, 0xd1, 0x84, 0x42, 0xe0, 0xff, 0x1f, 0xb4, 0x1c, 0x41, - 0x06, 0xaf, 0xd1, 0x17, 0xa9, 0xb9, 0x0f, 0xe0, 0x5f, 0x80, 0xd0, 0x05, 0x9f, 0x53, 0x2a, 0xcb, - 0xb1, 0x73, 0x9e, 0xa2, 0x07, 0x72, 0x4b, 0xfc, 0x26, 0x75, 0xa1, 0xaa, 0xeb, 0xb1, 0xb7, 0xb9, - 0x80, 0xb2, 0x43, 0x98, 0x8b, 0x50, 0x75, 0xf4, 0xbc, 0x7b, 0x7f, 0x65, 0x6d, 0x3a, 0xc0, 0xd3, - 0xfb, 0xa3, 0xc0, 0x75, 0x4f, 0x5e, 0x01, 0x9e, 0xaf, 0x59, 0x9b, 0x06, 0x08, 0xda, 0x5c, 0xfb, - 0x6b, 0x0a, 0xd4, 0xb6, 0x6b, 0x13, 0x7d, 0x68, 0x98, 0x7d, 0x99, 0x32, 0x77, 0x21, 0x23, 0x9a, - 0xd4, 0xcb, 0x86, 0x78, 0x53, 0x41, 0x3b, 0x97, 0x14, 0x9b, 0x4d, 0x05, 0xed, 0x5d, 0x62, 0x74, - 0x36, 0x15, 0xf4, 0xc1, 0x97, 0x13, 0x9f, 0x4d, 0x05, 0x7d, 0xf8, 0xe5, 0x45, 0x68, 0x53, 0x41, - 0x07, 0x30, 0x2f, 0x9a, 0x99, 0xdf, 0x34, 0x03, 0xbe, 0x98, 0x20, 0x4a, 0x01, 0xc7, 0x4e, 0x76, - 0x59, 0xa6, 0xf1, 0x10, 0x16, 0x82, 0x1a, 0x05, 0xc1, 0x43, 0xd7, 0xc2, 0xeb, 0xc2, 0x64, 0x38, - 0xe0, 0xe1, 0x38, 0x52, 0x4b, 0xf5, 0xd6, 0x30, 0x64, 0xe5, 0x0d, 0xf1, 0x3e, 0xc0, 0xa5, 0x58, - 0xdb, 0x28, 0x7f, 0xfa, 0x74, 0x45, 0xf9, 0xec, 0xe9, 0x8a, 0xf2, 0xef, 0xa7, 0x2b, 0xca, 0x93, - 0x67, 0x2b, 0x33, 0x9f, 0x3d, 0x5b, 0x99, 0xf9, 0xfb, 0xb3, 0x95, 0x99, 0xe3, 0x0c, 0xbb, 0xe6, - 0xbf, 0xf5, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x46, 0xce, 0x3f, 0x5d, 0x6d, 0x22, 0x00, 0x00, + 0x15, 0xcf, 0xf8, 0xdb, 0xc7, 0x76, 0x3c, 0xb9, 0xc9, 0xa6, 0xae, 0xb3, 0x4d, 0xc2, 0xb0, 0x82, + 0x68, 0xdb, 0x3a, 0x89, 0xbb, 0x88, 0x76, 0x57, 0x14, 0xd9, 0x1b, 0x77, 0x9b, 0x6e, 0xe2, 0x84, + 0x6b, 0x6f, 0x28, 0xa8, 0x52, 0x34, 0xb1, 0xef, 0x7a, 0x47, 0xb1, 0x67, 0xdc, 0x99, 0x71, 0x48, + 0x78, 0xa8, 0x90, 0x10, 0x88, 0x22, 0x1e, 0x2a, 0x9e, 0xe0, 0x2f, 0xe0, 0x5f, 0x40, 0x42, 0xbc, + 0xc0, 0x4b, 0x11, 0x2f, 0x95, 0x78, 0x41, 0x08, 0x15, 0xb4, 0xfb, 0xc6, 0x5f, 0xc0, 0x23, 0xba, + 0x5f, 0xf3, 0xe5, 0x71, 0xf6, 0xa3, 0xa9, 0xc4, 0x43, 0x9f, 0x3c, 0xf7, 0xdc, 0xdf, 0x3d, 0x73, + 0xee, 0x39, 0xe7, 0x9e, 0xf3, 0xbb, 0x63, 0x28, 0xb8, 0x64, 0x34, 0xb6, 0x6a, 0x63, 0xdb, 0x72, + 0x2d, 0x94, 0x65, 0x83, 0xf1, 0x49, 0x75, 0xb9, 0x67, 0x8d, 0x46, 0x96, 0xb9, 0x79, 0xb6, 0xbd, + 0xc9, 0x9f, 0x38, 0xa0, 0xfa, 0xfa, 0xc0, 0x70, 0x1f, 0x4d, 0x4e, 0x6a, 0x3d, 0x6b, 0xb4, 0x39, + 0xb0, 0x06, 0xd6, 0x26, 0x13, 0x9f, 0x4c, 0x1e, 0xb2, 0x11, 0x1b, 0xb0, 0x27, 0x01, 0x5f, 0x72, + 0x6d, 0xbd, 0x47, 0xa8, 0x16, 0xf6, 0x20, 0xa4, 0x6b, 0x03, 0xcb, 0x1a, 0x0c, 0x89, 0xbf, 0xd6, + 0x35, 0x46, 0xc4, 0x71, 0xf5, 0xd1, 0x98, 0x03, 0xb4, 0xff, 0x2a, 0xa0, 0x76, 0xe9, 0x82, 0xe6, + 0xc5, 0xee, 0x0e, 0x26, 0x1f, 0x4e, 0x88, 0xe3, 0xa2, 0x0a, 0x64, 0x99, 0x92, 0xdd, 0x9d, 0x8a, + 0xb2, 0xae, 0x6c, 0x14, 0xb1, 0x1c, 0xa2, 0x55, 0x80, 0x93, 0xa1, 0xd5, 0x3b, 0xed, 0xb8, 0xba, + 0xed, 0x56, 0x12, 0xeb, 0xca, 0x46, 0x1e, 0x07, 0x24, 0xa8, 0x0a, 0x39, 0x36, 0x6a, 0x99, 0xfd, + 0x4a, 0x92, 0xcd, 0x7a, 0x63, 0x74, 0x1d, 0xf2, 0x1f, 0x4e, 0x88, 0x7d, 0xb1, 0x6f, 0xf5, 0x49, + 0x25, 0xcd, 0x26, 0x7d, 0x01, 0x7a, 0x0d, 0x16, 0xf4, 0xe1, 0xd0, 0xfa, 0xd1, 0xa1, 0x6e, 0xbb, + 0x86, 0x3e, 0x64, 0x36, 0x55, 0x32, 0xeb, 0xca, 0x46, 0x0e, 0x4f, 0x4f, 0xa0, 0x26, 0xe4, 0xf0, + 0x3b, 0xdb, 0x8d, 0x87, 0x2e, 0xb1, 0x2b, 0xd9, 0x75, 0x65, 0xa3, 0x50, 0xaf, 0xd6, 0xf8, 0x56, + 0x6b, 0x72, 0xab, 0xb5, 0xae, 0xdc, 0x6a, 0x13, 0x3e, 0xfd, 0x7c, 0x6d, 0xee, 0x93, 0x7f, 0xad, + 0x29, 0x15, 0x05, 0x7b, 0xeb, 0xb4, 0xdf, 0x2b, 0xb0, 0x10, 0xd8, 0xba, 0x33, 0xb6, 0x4c, 0x87, + 0xa0, 0x1b, 0x90, 0x66, 0x9b, 0x65, 0x3b, 0x2f, 0xd4, 0xe7, 0x6b, 0x22, 0x4e, 0x35, 0x06, 0xc5, + 0x7c, 0x12, 0xbd, 0x01, 0xd9, 0x11, 0x71, 0x6d, 0xa3, 0xe7, 0x30, 0x27, 0x14, 0xea, 0x2f, 0x87, + 0x71, 0x54, 0xe5, 0x3e, 0x07, 0x60, 0x89, 0x44, 0x35, 0xc8, 0x38, 0xae, 0xee, 0x4e, 0x1c, 0xe6, + 0x9a, 0xf9, 0xfa, 0xb2, 0xb7, 0x46, 0xec, 0xad, 0xc3, 0x66, 0xb1, 0x40, 0xd1, 0x30, 0x8c, 0x88, + 0xe3, 0xe8, 0x03, 0x52, 0x49, 0x31, 0x77, 0xc9, 0xa1, 0x76, 0x3b, 0x10, 0x34, 0xf1, 0x1a, 0xf4, + 0x0d, 0x98, 0x37, 0x4c, 0x67, 0x4c, 0x7a, 0x2e, 0xe9, 0x37, 0x2f, 0x5c, 0xe2, 0xb0, 0x1d, 0xa4, + 0x70, 0x44, 0xaa, 0xfd, 0x3a, 0x09, 0xa5, 0x0e, 0xd1, 0xed, 0xde, 0x23, 0x19, 0xee, 0xdb, 0x90, + 0xea, 0xea, 0x03, 0x8a, 0x4f, 0x6e, 0x14, 0xea, 0xeb, 0x9e, 0x55, 0x21, 0x54, 0x8d, 0x42, 0x5a, + 0xa6, 0x6b, 0x5f, 0x34, 0x53, 0xd4, 0x9d, 0x98, 0xad, 0x41, 0x37, 0xa0, 0xb4, 0x6f, 0x98, 0x3b, + 0x13, 0x5b, 0x77, 0x0d, 0xcb, 0xdc, 0xe7, 0xee, 0x28, 0xe1, 0xb0, 0x90, 0xa1, 0xf4, 0xf3, 0x00, + 0x2a, 0x29, 0x50, 0x41, 0x21, 0x5a, 0x82, 0xf4, 0x9e, 0x31, 0x32, 0x5c, 0xb6, 0xdb, 0x12, 0xe6, + 0x03, 0x2a, 0x75, 0x58, 0xb6, 0xa5, 0xb9, 0x94, 0x0d, 0x90, 0x0a, 0x49, 0x62, 0xf6, 0x59, 0x82, + 0x94, 0x30, 0x7d, 0xa4, 0xb8, 0xef, 0xd1, 0x6c, 0xaa, 0xe4, 0x98, 0xaf, 0xf8, 0x00, 0x6d, 0x40, + 0xb9, 0x33, 0xd6, 0x4d, 0xe7, 0x90, 0xd8, 0xf4, 0xb7, 0x43, 0xdc, 0x4a, 0x9e, 0xad, 0x89, 0x8a, + 0x43, 0x29, 0x05, 0x2f, 0x96, 0x52, 0xd5, 0x6f, 0x43, 0xde, 0x73, 0x13, 0x35, 0xf1, 0x94, 0x5c, + 0xb0, 0x28, 0xe4, 0x31, 0x7d, 0xa4, 0x26, 0x9e, 0xe9, 0xc3, 0x09, 0x11, 0x07, 0x87, 0x0f, 0x6e, + 0x27, 0xde, 0x54, 0xb4, 0x9f, 0x27, 0x01, 0x71, 0x77, 0x37, 0xe9, 0x71, 0x91, 0x91, 0xb9, 0x05, + 0x79, 0x47, 0x06, 0x41, 0x24, 0xe4, 0x72, 0x7c, 0x78, 0xb0, 0x0f, 0xa4, 0x79, 0xc3, 0x0e, 0xdd, + 0xee, 0x8e, 0x78, 0x91, 0x1c, 0xd2, 0x23, 0xc8, 0xdc, 0x77, 0x48, 0x73, 0x8a, 0xc7, 0xc0, 0x17, + 0xd0, 0x28, 0x8d, 0xf5, 0x01, 0x71, 0xba, 0x16, 0x57, 0x2d, 0xe2, 0x10, 0x16, 0x52, 0x94, 0x61, + 0xf6, 0xc9, 0x39, 0x5d, 0xd2, 0x31, 0x7e, 0x4c, 0x44, 0x0c, 0xc2, 0x42, 0xa4, 0x41, 0xd1, 0xb5, + 0x5c, 0x7d, 0x88, 0x49, 0xcf, 0xb2, 0xfb, 0x0e, 0x3b, 0xa4, 0x25, 0x1c, 0x92, 0x51, 0x3b, 0xcf, + 0x88, 0xed, 0x18, 0x96, 0xc9, 0x62, 0x92, 0xc7, 0x72, 0x88, 0x10, 0xa4, 0x1c, 0xaa, 0x1a, 0x58, + 0x06, 0xb3, 0x67, 0x5a, 0x7a, 0x1e, 0x5a, 0x96, 0x4b, 0x6c, 0xf6, 0xd2, 0x02, 0xd3, 0x17, 0x90, + 0xa0, 0x1d, 0x50, 0xfb, 0xa4, 0x6f, 0xf4, 0x74, 0x97, 0xf4, 0xef, 0x5a, 0xc3, 0xc9, 0xc8, 0x74, + 0x2a, 0x45, 0x96, 0xd1, 0x15, 0xcf, 0x65, 0x3b, 0x61, 0x00, 0x9e, 0x5a, 0xa1, 0xfd, 0x21, 0x01, + 0xe5, 0x08, 0x0a, 0xdd, 0x82, 0xb4, 0xd3, 0xb3, 0xc6, 0x44, 0x1c, 0xdb, 0xd5, 0x59, 0xea, 0x6a, + 0x1d, 0x8a, 0xc2, 0x1c, 0x4c, 0xf7, 0x60, 0xea, 0x23, 0x19, 0x6b, 0xf6, 0x8c, 0xb6, 0x21, 0xe5, + 0x5e, 0x8c, 0x79, 0x6d, 0x99, 0xaf, 0xbf, 0x32, 0x53, 0x51, 0xf7, 0x62, 0x4c, 0x30, 0x83, 0xa2, + 0xb7, 0x20, 0x6b, 0x8d, 0xe9, 0x01, 0x71, 0x58, 0x38, 0xe6, 0xeb, 0x6b, 0x33, 0x57, 0x1d, 0x30, + 0x1c, 0x96, 0x78, 0xed, 0x26, 0xa4, 0x99, 0x45, 0x28, 0x07, 0xa9, 0xce, 0x61, 0xa3, 0xad, 0xce, + 0xa1, 0x22, 0xe4, 0x70, 0xab, 0x73, 0xf0, 0x00, 0xdf, 0x6d, 0xa9, 0x0a, 0xca, 0x43, 0xba, 0x75, + 0xd4, 0x6a, 0x77, 0xd5, 0x84, 0xb6, 0x02, 0x29, 0xfa, 0x52, 0x04, 0x90, 0xe9, 0x74, 0xf1, 0x6e, + 0xfb, 0x9e, 0x3a, 0x87, 0xb2, 0x90, 0xdc, 0x6d, 0x77, 0x55, 0x45, 0xfb, 0x26, 0x64, 0xb8, 0x6e, + 0xaa, 0xa9, 0x7d, 0xd0, 0x6e, 0xa9, 0x73, 0x74, 0x6d, 0x03, 0xe3, 0xc6, 0x0f, 0x54, 0x85, 0x0a, + 0x9b, 0x7b, 0x07, 0x4d, 0x35, 0xa1, 0x9d, 0xc3, 0xbc, 0xcc, 0x4a, 0x51, 0x4e, 0x6f, 0x41, 0x86, + 0x55, 0x4c, 0x59, 0x5d, 0xae, 0x87, 0xeb, 0x24, 0x47, 0xef, 0x13, 0x57, 0xef, 0xeb, 0xae, 0x8e, + 0x05, 0x16, 0x6d, 0x45, 0xcb, 0x6b, 0x34, 0xeb, 0xa3, 0xb5, 0x55, 0xfb, 0x5b, 0x12, 0x16, 0x63, + 0x34, 0x46, 0x5b, 0x59, 0xde, 0x6f, 0x65, 0x1b, 0x50, 0xb6, 0x2d, 0xcb, 0xed, 0x10, 0xfb, 0xcc, + 0xe8, 0x91, 0xb6, 0x1f, 0xaa, 0xa8, 0x98, 0x66, 0x3c, 0x15, 0x31, 0xf5, 0x0c, 0xc7, 0x3b, 0x5b, + 0x58, 0x48, 0x1b, 0x18, 0x3b, 0x4a, 0xb4, 0x46, 0x3c, 0x30, 0x8d, 0xf3, 0xb6, 0x6e, 0x5a, 0x2c, + 0x64, 0x29, 0x3c, 0x3d, 0x41, 0xb3, 0xb9, 0xef, 0x97, 0x43, 0x5e, 0xda, 0x02, 0x12, 0x74, 0x13, + 0xb2, 0x8e, 0xa8, 0x57, 0x19, 0xe6, 0x01, 0xd5, 0xf7, 0x00, 0x97, 0x63, 0x09, 0x40, 0xaf, 0x41, + 0x4e, 0x3c, 0xd2, 0x73, 0x96, 0x8c, 0x05, 0x7b, 0x08, 0x84, 0xa1, 0xe8, 0xf0, 0xcd, 0xd1, 0x76, + 0xe3, 0x54, 0x72, 0x6c, 0x45, 0xed, 0xb2, 0xb8, 0xd4, 0x3a, 0x81, 0x05, 0xac, 0xb8, 0xe1, 0x90, + 0x8e, 0xea, 0x11, 0x2c, 0x4c, 0x41, 0x62, 0xea, 0xdf, 0xab, 0xc1, 0xfa, 0x57, 0xa8, 0x5f, 0x0b, + 0x04, 0xd5, 0x5f, 0x1c, 0x2c, 0x8b, 0x7b, 0x50, 0x0c, 0x4e, 0xb1, 0xfa, 0x35, 0xd6, 0xcd, 0xbb, + 0xd6, 0xc4, 0x74, 0x99, 0x62, 0x5a, 0xbf, 0xa4, 0x80, 0xfa, 0x94, 0xd8, 0xb6, 0x65, 0xf3, 0x69, + 0xde, 0x88, 0x02, 0x12, 0xed, 0x67, 0x0a, 0x64, 0x65, 0xb5, 0xff, 0x3a, 0xa4, 0xe9, 0x42, 0x99, + 0x96, 0xa5, 0x90, 0xc3, 0x30, 0x9f, 0x63, 0x0d, 0x58, 0x77, 0x7b, 0x8f, 0x48, 0x5f, 0x68, 0x93, + 0x43, 0x74, 0x07, 0x40, 0x77, 0x5d, 0xdb, 0x38, 0x99, 0xd0, 0x46, 0x9b, 0x64, 0x3a, 0x56, 0x3c, + 0x1d, 0x82, 0xc7, 0x9d, 0x6d, 0xd7, 0xee, 0x93, 0x8b, 0x23, 0xba, 0x1b, 0x1c, 0x80, 0x6b, 0x7f, + 0x56, 0x20, 0x45, 0x5f, 0x83, 0x96, 0x21, 0x43, 0x5f, 0xe4, 0xe5, 0xa6, 0x18, 0xc5, 0x96, 0x8e, + 0xd8, 0xf4, 0x4a, 0xce, 0x4a, 0xaf, 0x1b, 0x50, 0x92, 0xc9, 0x44, 0xc7, 0x8e, 0x48, 0xc4, 0xb0, + 0x30, 0xb2, 0x8b, 0xf4, 0xf3, 0xed, 0xe2, 0xb7, 0x09, 0xc9, 0x23, 0x24, 0x03, 0xd9, 0x80, 0xb2, + 0xc7, 0x35, 0xba, 0xf2, 0xd0, 0xb3, 0x5e, 0x1b, 0x11, 0xc7, 0x70, 0x95, 0x44, 0x1c, 0x57, 0x41, + 0xeb, 0x50, 0x60, 0x1d, 0x83, 0x35, 0x45, 0xc9, 0x1a, 0x82, 0x22, 0xba, 0xd1, 0x9e, 0x35, 0x1a, + 0x0f, 0x89, 0x4b, 0xfa, 0xef, 0x59, 0x27, 0x8e, 0xec, 0x59, 0x21, 0x21, 0xcd, 0x1b, 0xb6, 0x88, + 0x21, 0xf8, 0x61, 0xf3, 0x05, 0xd4, 0x6e, 0x5f, 0x25, 0x37, 0x27, 0xc3, 0xcc, 0x89, 0x8a, 0x43, + 0x76, 0x33, 0xfe, 0xc0, 0xfa, 0x5a, 0xd0, 0x6e, 0x26, 0xd5, 0x3e, 0x4e, 0xd0, 0x03, 0x41, 0x7d, + 0x43, 0xe9, 0x80, 0xec, 0xe6, 0x4b, 0xb2, 0x8f, 0xf0, 0x68, 0x8b, 0x3e, 0xb1, 0x04, 0x69, 0xc6, + 0x82, 0x25, 0x29, 0x60, 0x03, 0x9f, 0xf5, 0x24, 0x63, 0x58, 0x4f, 0xca, 0x67, 0x3d, 0x1b, 0x50, + 0x1e, 0xe9, 0xe7, 0xf4, 0x2d, 0x94, 0xca, 0x30, 0xed, 0x7c, 0x7f, 0x51, 0x31, 0xaa, 0xc3, 0x92, + 0xe3, 0xea, 0x43, 0xc2, 0x22, 0xe9, 0x74, 0x1f, 0xd9, 0xc4, 0x79, 0x64, 0x0d, 0x25, 0x85, 0x8a, + 0x9d, 0xbb, 0x12, 0x9a, 0xfd, 0x9f, 0x24, 0x2c, 0xfb, 0xbe, 0x08, 0xd1, 0x9b, 0x37, 0xa7, 0xe9, + 0x4d, 0x35, 0x52, 0xe8, 0x03, 0xfe, 0xfb, 0x8a, 0xe2, 0x5c, 0x09, 0xc5, 0x89, 0x4b, 0x99, 0x52, + 0x7c, 0xca, 0x6c, 0xc1, 0xa2, 0x9f, 0x16, 0x7e, 0xc6, 0xcc, 0x33, 0x74, 0xdc, 0x94, 0xf6, 0x9b, + 0x24, 0xac, 0x78, 0x81, 0xe3, 0xd9, 0x14, 0x8a, 0xf8, 0x77, 0xa6, 0x23, 0xbe, 0x36, 0x1d, 0x71, + 0xbe, 0xf0, 0xab, 0xb0, 0x5f, 0x29, 0xb3, 0xed, 0xcb, 0x1b, 0x06, 0x3f, 0x52, 0x82, 0x9f, 0x55, + 0x21, 0xe7, 0xea, 0x03, 0x4a, 0x60, 0x78, 0x2b, 0xcc, 0x63, 0x6f, 0x8c, 0xea, 0x51, 0x16, 0xe6, + 0xbf, 0x4e, 0x32, 0x83, 0x29, 0x1e, 0xf6, 0x11, 0x2c, 0xf9, 0x6f, 0x39, 0xaa, 0x7b, 0xef, 0xa9, + 0x43, 0x86, 0x95, 0x3b, 0xd9, 0x70, 0xe3, 0xce, 0xf9, 0x51, 0x9d, 0x13, 0x68, 0x81, 0x7c, 0xa1, + 0xf7, 0xdf, 0x09, 0x16, 0x5e, 0xa1, 0xd0, 0xeb, 0xa7, 0x4a, 0xa0, 0x9f, 0x22, 0x48, 0xb9, 0xf4, + 0xd2, 0x9b, 0x60, 0x9b, 0x66, 0xcf, 0xda, 0x2f, 0x13, 0x81, 0x52, 0x15, 0x4a, 0x42, 0xc6, 0x23, + 0xb9, 0x5f, 0x3c, 0x1e, 0xc9, 0x87, 0x4f, 0xab, 0xdf, 0xa9, 0x98, 0xfa, 0x9d, 0xf6, 0xeb, 0xb7, + 0x06, 0x45, 0x7e, 0xea, 0xf8, 0xeb, 0x44, 0xca, 0x85, 0x64, 0xb3, 0x8e, 0x61, 0x76, 0xe6, 0x31, + 0x0c, 0xd5, 0xed, 0xdc, 0x0b, 0xd6, 0xed, 0x53, 0x78, 0x69, 0xca, 0x17, 0x22, 0x98, 0xb4, 0x9d, + 0x7a, 0x16, 0xf3, 0xac, 0xf1, 0x05, 0x2f, 0x14, 0xb6, 0x5b, 0x90, 0x93, 0xaf, 0x61, 0x91, 0xb9, + 0xf0, 0xba, 0x24, 0xbf, 0x05, 0xc5, 0xde, 0x9c, 0xb5, 0x9f, 0x28, 0xf0, 0x72, 0xc4, 0xc6, 0x40, + 0xca, 0x6d, 0x46, 0xad, 0x2c, 0xd4, 0x17, 0x7c, 0x96, 0x2b, 0x66, 0xbe, 0xa8, 0xe1, 0x7f, 0x51, + 0xa0, 0x1c, 0x99, 0x7c, 0xd6, 0x2f, 0x31, 0x61, 0x56, 0x92, 0x88, 0xb2, 0x92, 0x29, 0x66, 0x93, + 0x8c, 0x63, 0x36, 0x11, 0x86, 0x94, 0x9a, 0x66, 0x48, 0x31, 0xec, 0x26, 0x1d, 0xcb, 0x6e, 0xb4, + 0x36, 0xa4, 0xf9, 0xd7, 0xb5, 0x16, 0x94, 0x6c, 0xe2, 0x58, 0x13, 0xbb, 0x47, 0x3a, 0x01, 0x92, + 0xec, 0x57, 0x6a, 0xfe, 0x89, 0xf1, 0x6c, 0xbb, 0x86, 0x83, 0x30, 0x1c, 0x5e, 0xa5, 0xb5, 0xa1, + 0x78, 0x38, 0x71, 0xfc, 0xbb, 0xe0, 0xdb, 0x50, 0x62, 0x6c, 0xdc, 0x69, 0x5e, 0x74, 0xc5, 0x27, + 0xb6, 0xe4, 0xc6, 0x7c, 0xc0, 0xcb, 0x14, 0xdd, 0xa2, 0x08, 0x4c, 0x74, 0xc7, 0x32, 0x71, 0x18, + 0xae, 0x7d, 0xac, 0x80, 0x4a, 0x21, 0xcc, 0x5a, 0x79, 0x30, 0x5f, 0xf7, 0x2e, 0x98, 0xf4, 0x24, + 0x17, 0x9b, 0xd7, 0x68, 0x32, 0xff, 0xe3, 0xf3, 0xb5, 0xd2, 0xa1, 0x4d, 0xf4, 0xe1, 0xd0, 0xea, + 0x71, 0xb4, 0xbc, 0x59, 0xaa, 0x90, 0x34, 0xfa, 0x9c, 0xb1, 0x17, 0x31, 0x7d, 0x44, 0xb7, 0xe0, + 0x9a, 0x73, 0x6a, 0x8c, 0x45, 0xf0, 0xee, 0x11, 0x93, 0x70, 0x8a, 0xcc, 0xbc, 0x94, 0xc3, 0xf1, + 0x93, 0xda, 0x4f, 0x85, 0x2d, 0x7c, 0xe3, 0xc2, 0x96, 0xb7, 0x20, 0x7b, 0xc2, 0x2e, 0x08, 0xcf, + 0xec, 0x31, 0x89, 0x9f, 0x6d, 0x45, 0xe2, 0x32, 0x2b, 0x6e, 0x00, 0x88, 0xef, 0x80, 0x34, 0x9f, + 0x96, 0x43, 0x77, 0xed, 0xa2, 0xdc, 0xb3, 0xf6, 0x36, 0xe4, 0xf7, 0x0c, 0xf3, 0xb4, 0x33, 0x34, + 0x7a, 0x04, 0x6d, 0x43, 0x7a, 0x68, 0x98, 0xa7, 0xd2, 0xc2, 0x95, 0x69, 0x0b, 0xa9, 0x65, 0x35, + 0xba, 0x00, 0x73, 0xa4, 0xd6, 0x81, 0x45, 0xf6, 0x31, 0x6d, 0xd7, 0x74, 0x5c, 0xdd, 0x74, 0x03, + 0x74, 0x96, 0x17, 0x3e, 0x25, 0xb6, 0xf0, 0x71, 0x46, 0x1f, 0x2e, 0x7c, 0xfc, 0xbe, 0x42, 0x1f, + 0xb5, 0x3f, 0x29, 0xb0, 0x14, 0xd6, 0x2a, 0xb2, 0xa4, 0x06, 0x19, 0x87, 0xd8, 0x86, 0xe7, 0x43, + 0xff, 0xea, 0x2f, 0x90, 0x1d, 0x36, 0x8b, 0x05, 0xea, 0xf9, 0xbf, 0x15, 0x5c, 0xe1, 0x77, 0x58, + 0x07, 0x4a, 0x21, 0xa3, 0xd0, 0x5b, 0x90, 0x19, 0xea, 0x27, 0x64, 0x38, 0xed, 0xde, 0xe9, 0xdb, + 0x94, 0xf8, 0x8e, 0x2a, 0x16, 0x84, 0x4b, 0x9c, 0x22, 0x4a, 0xdc, 0x7b, 0xa9, 0x5c, 0x52, 0x4d, + 0xe1, 0xc2, 0xd8, 0xb6, 0x46, 0xc7, 0x1c, 0xa8, 0xfd, 0x33, 0x09, 0x0b, 0xcc, 0x73, 0x58, 0x37, + 0x07, 0xe4, 0x4a, 0xa2, 0xc1, 0x68, 0x89, 0x4b, 0xc6, 0xe2, 0x9a, 0xc8, 0x9e, 0xc3, 0xdf, 0xeb, + 0xb3, 0xd1, 0xef, 0xf5, 0x01, 0x2a, 0x96, 0xbb, 0x84, 0x8a, 0xe5, 0x9f, 0x4a, 0xc5, 0x20, 0x8e, + 0x8a, 0x05, 0x08, 0x54, 0x21, 0x9e, 0x40, 0x95, 0x66, 0x12, 0xa8, 0xf9, 0x67, 0x22, 0x50, 0xe5, + 0xe7, 0xe6, 0xcd, 0xd7, 0x21, 0x4f, 0xce, 0xc9, 0x68, 0x3c, 0xd4, 0x6d, 0xa7, 0xa2, 0xf2, 0x7d, + 0x79, 0x02, 0x3a, 0x3b, 0xd2, 0xcf, 0x79, 0x1a, 0x54, 0x16, 0xf8, 0xac, 0x27, 0x40, 0xaf, 0x40, + 0xd6, 0xe0, 0x89, 0x52, 0x41, 0xf4, 0x40, 0xbf, 0x3b, 0x87, 0xa5, 0xe0, 0x17, 0x8a, 0xd2, 0x04, + 0xc8, 0x1d, 0x8b, 0xa1, 0xf6, 0x47, 0x05, 0x50, 0x30, 0xbc, 0xe2, 0x58, 0xbc, 0x1a, 0x39, 0x16, + 0x8b, 0x7e, 0x2b, 0x33, 0x46, 0xe4, 0xff, 0xe8, 0x4c, 0x7c, 0x04, 0xb9, 0x96, 0xf0, 0xca, 0x95, + 0x1f, 0x07, 0xf4, 0x35, 0x28, 0x7a, 0xff, 0x60, 0x1d, 0x8f, 0xb8, 0xb1, 0x49, 0x5c, 0xf0, 0x64, + 0xfb, 0x8e, 0xd6, 0x80, 0x4c, 0x47, 0xa7, 0x2d, 0x72, 0x0a, 0x9c, 0x98, 0x02, 0xfb, 0x6f, 0x51, + 0x02, 0x6f, 0xa1, 0xb5, 0x09, 0x7c, 0xaf, 0x7e, 0x91, 0x5d, 0x6c, 0x42, 0xd6, 0x61, 0xc6, 0xf0, + 0xf6, 0x54, 0xa8, 0x97, 0xfd, 0x40, 0x30, 0xb9, 0xc0, 0x4b, 0x14, 0xfa, 0x56, 0x30, 0xc9, 0x52, + 0x11, 0xd2, 0x22, 0xfd, 0x2a, 0x16, 0xf9, 0xc8, 0x98, 0x32, 0x71, 0xf3, 0x03, 0x28, 0x47, 0xfa, + 0x29, 0x2a, 0x42, 0xae, 0x7d, 0x70, 0xdc, 0xc2, 0xf8, 0x00, 0xab, 0x73, 0x68, 0x11, 0xca, 0xfb, + 0x8d, 0xf7, 0x8f, 0xf7, 0x76, 0x8f, 0x5a, 0xc7, 0x5d, 0xdc, 0xb8, 0xdb, 0xea, 0xa8, 0x0a, 0x15, + 0xb2, 0xe7, 0xe3, 0xee, 0xc1, 0xc1, 0xf1, 0x5e, 0x03, 0xdf, 0x6b, 0xa9, 0x09, 0xb4, 0x00, 0xa5, + 0x07, 0xed, 0xfb, 0xed, 0x83, 0xef, 0xb7, 0xc5, 0xe2, 0xe4, 0xcd, 0x9b, 0x50, 0x0a, 0x25, 0x06, + 0xd5, 0x7d, 0xf7, 0x60, 0xff, 0x70, 0xaf, 0xd5, 0x6d, 0xa9, 0x73, 0xa8, 0x00, 0xd9, 0xc3, 0x06, + 0xee, 0xee, 0x36, 0xf6, 0x54, 0xa5, 0xfe, 0x2b, 0x05, 0x32, 0xd4, 0x14, 0x62, 0xa3, 0xef, 0x42, + 0xde, 0xeb, 0xe0, 0xe8, 0xe5, 0x50, 0xe3, 0x0f, 0x76, 0xf5, 0xea, 0xb5, 0xd0, 0x94, 0x3c, 0x04, + 0xda, 0x1c, 0x6a, 0x40, 0xc1, 0x03, 0x1f, 0xd5, 0x5f, 0x44, 0x45, 0xfd, 0x77, 0x29, 0xc8, 0xd2, + 0x03, 0x66, 0x10, 0x1b, 0xbd, 0x0b, 0xa5, 0x77, 0x0c, 0xb3, 0xef, 0xfd, 0x99, 0x86, 0x62, 0xfe, + 0xc7, 0x93, 0x0a, 0xab, 0x71, 0x53, 0x01, 0xc3, 0x8a, 0xf2, 0xd3, 0x77, 0x8f, 0x98, 0x2e, 0x9a, + 0xf1, 0x3f, 0x4d, 0xf5, 0xa5, 0x29, 0xb9, 0xa7, 0xa2, 0x05, 0x85, 0xc0, 0x7f, 0x40, 0x68, 0x25, + 0x82, 0x0c, 0x5e, 0xa4, 0x2f, 0x53, 0x73, 0x0f, 0xc0, 0xbf, 0x02, 0xa1, 0x4b, 0x3e, 0xa8, 0x54, + 0x57, 0x62, 0xe7, 0x3c, 0x45, 0xf7, 0xe5, 0x96, 0xf8, 0x5d, 0xea, 0x52, 0x55, 0xaf, 0xc4, 0xde, + 0xe7, 0x02, 0xca, 0x8e, 0xa0, 0x1c, 0xa1, 0xea, 0xe8, 0x69, 0x37, 0xff, 0xea, 0xfa, 0x6c, 0x80, + 0xa7, 0xf7, 0x87, 0x81, 0x0b, 0x9f, 0xbc, 0x02, 0x3c, 0x5d, 0xb3, 0x36, 0x0b, 0x10, 0xb4, 0xb9, + 0xfe, 0xd7, 0x14, 0xa8, 0x1d, 0xd7, 0x26, 0xfa, 0xc8, 0x30, 0x07, 0x32, 0x65, 0xee, 0x40, 0x46, + 0x34, 0xa9, 0xe7, 0x0d, 0xf1, 0x96, 0x82, 0x76, 0xaf, 0x28, 0x36, 0x5b, 0x0a, 0xda, 0xbf, 0xc2, + 0xe8, 0x6c, 0x29, 0xe8, 0xfd, 0x2f, 0x27, 0x3e, 0x5b, 0x0a, 0xfa, 0xe0, 0xcb, 0x8b, 0xd0, 0x96, + 0x82, 0x0e, 0x61, 0x41, 0x34, 0x33, 0xbf, 0x69, 0x06, 0x7c, 0x31, 0x45, 0x94, 0x02, 0x8e, 0x9d, + 0xee, 0xb2, 0x4c, 0xe3, 0x11, 0x2c, 0x06, 0x35, 0x0a, 0x82, 0x87, 0xae, 0x87, 0xd7, 0x85, 0xc9, + 0x70, 0xc0, 0xc3, 0x71, 0xa4, 0x96, 0xea, 0xad, 0x63, 0xc8, 0xca, 0x1b, 0xe2, 0x3d, 0x80, 0x2b, + 0xb1, 0xb6, 0x59, 0xf9, 0xf4, 0xf1, 0xaa, 0xf2, 0xd9, 0xe3, 0x55, 0xe5, 0xdf, 0x8f, 0x57, 0x95, + 0x4f, 0x9e, 0xac, 0xce, 0x7d, 0xf6, 0x64, 0x75, 0xee, 0xef, 0x4f, 0x56, 0xe7, 0x4e, 0x32, 0xec, + 0xa2, 0xff, 0xc6, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x03, 0x03, 0xde, 0x75, 0x22, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/pkg/tempopb/tempo.proto b/pkg/tempopb/tempo.proto index f9a41288a12..c944f1fd696 100644 --- a/pkg/tempopb/tempo.proto +++ b/pkg/tempopb/tempo.proto @@ -45,8 +45,9 @@ message TraceByIDRequest { string blockEnd = 3; string queryMode = 5; bool allowPartialTrace = 6; - // Rhythm fields + google.protobuf.Timestamp RF1After = 7 [ + deprecated = true, (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; @@ -75,8 +76,9 @@ message SearchRequest { // TraceQL query string Query = 8; uint32 SpansPerSpanSet = 9; - // Rhythm fields + google.protobuf.Timestamp RF1After = 10 [ + deprecated = true, (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; @@ -173,8 +175,9 @@ message SearchTagsRequest { uint32 end = 4; uint32 maxTagsPerScope = 5; uint32 staleValuesThreshold = 6; - // Rhythm fields + google.protobuf.Timestamp RF1After = 7 [ + deprecated = true, (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; @@ -237,8 +240,9 @@ message SearchTagValuesRequest { uint32 end = 5; uint32 maxTagValues = 6; uint32 staleValueThreshold = 7; // Limit of stale values - // Rhythm fields + google.protobuf.Timestamp RF1After = 8 [ + deprecated = true, (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; diff --git a/tempodb/encoding/common/interfaces.go b/tempodb/encoding/common/interfaces.go index 7824ee9847e..781624e5a72 100644 --- a/tempodb/encoding/common/interfaces.go +++ b/tempodb/encoding/common/interfaces.go @@ -43,7 +43,6 @@ type SearchOptions struct { PrefetchTraceCount int // How many traces to prefetch async. ReadBufferCount int ReadBufferSize int - RF1After time.Time // Only blocks with RF1 are selected after this timestamp. RF3 is selected otherwise. } // DefaultSearchOptions is used in a lot of places such as local ingester searches. It is important diff --git a/tempodb/tempodb.go b/tempodb/tempodb.go index ff87e8829a1..185ac501882 100644 --- a/tempodb/tempodb.go +++ b/tempodb/tempodb.go @@ -360,13 +360,13 @@ func (rw *readerWriter) Find(ctx context.Context, tenantID string, id common.ID, compactedBlocksSearched := 0 for _, b := range blocklist { - if includeBlock(b, id, blockStartBytes, blockEndBytes, timeStart, timeEnd, opts.RF1After) { + if includeBlock(b, id, blockStartBytes, blockEndBytes, timeStart, timeEnd) { copiedBlocklist = append(copiedBlocklist, b) blocksSearched++ } } for _, c := range compactedBlocklist { - if includeCompactedBlock(c, id, blockStartBytes, blockEndBytes, rw.cfg.BlocklistPoll, timeStart, timeEnd, opts.RF1After) { + if includeCompactedBlock(c, id, blockStartBytes, blockEndBytes, rw.cfg.BlocklistPoll, timeStart, timeEnd) { copiedBlocklist = append(copiedBlocklist, &c.BlockMeta) compactedBlocksSearched++ } @@ -819,7 +819,7 @@ func (rw *readerWriter) pollBlocklist(ctx context.Context) { } // includeBlock indicates whether a given block should be included in a backend search -func includeBlock(b *backend.BlockMeta, _ common.ID, blockStart, blockEnd []byte, timeStart, timeEnd int64, rf1After time.Time) bool { +func includeBlock(b *backend.BlockMeta, _ common.ID, blockStart, blockEnd []byte, timeStart, timeEnd int64) bool { // todo: restore this functionality once it works. min/max ids are currently not recorded // https://github.com/grafana/tempo/issues/1903 // correctly in a block @@ -840,21 +840,16 @@ func includeBlock(b *backend.BlockMeta, _ common.ID, blockStart, blockEnd []byte return false } - if rf1After.IsZero() { - return b.ReplicationFactor == backend.DefaultReplicationFactor - } - - return (b.StartTime.Before(rf1After) && b.ReplicationFactor == backend.DefaultReplicationFactor) || - (b.StartTime.After(rf1After) && b.ReplicationFactor == backend.MetricsGeneratorReplicationFactor) + return true } // if block is compacted within lookback period, and is within shard ranges, include it in search -func includeCompactedBlock(c *backend.CompactedBlockMeta, id common.ID, blockStart, blockEnd []byte, poll time.Duration, timeStart, timeEnd int64, rf1After time.Time) bool { +func includeCompactedBlock(c *backend.CompactedBlockMeta, id common.ID, blockStart, blockEnd []byte, poll time.Duration, timeStart, timeEnd int64) bool { lookback := time.Now().Add(-(2 * poll)) if c.CompactedTime.Before(lookback) { return false } - return includeBlock(&c.BlockMeta, id, blockStart, blockEnd, timeStart, timeEnd, rf1After) + return includeBlock(&c.BlockMeta, id, blockStart, blockEnd, timeStart, timeEnd) } // createLegacyCache uses the config to return a cache and a list of roles. diff --git a/tempodb/tempodb_test.go b/tempodb/tempodb_test.go index 5511881ed25..5197b1c2327 100644 --- a/tempodb/tempodb_test.go +++ b/tempodb/tempodb_test.go @@ -412,7 +412,7 @@ func TestIncludeBlock(t *testing.T) { e, err := tc.blockEnd.MarshalBinary() require.NoError(t, err) - assert.Equal(t, tc.expected, includeBlock(tc.meta, tc.searchID, s, e, tc.start, tc.end, time.Time{})) + assert.Equal(t, tc.expected, includeBlock(tc.meta, tc.searchID, s, e, tc.start, tc.end)) }) } } @@ -483,7 +483,7 @@ func TestIncludeCompactedBlock(t *testing.T) { e, err := tc.blockEnd.MarshalBinary() require.NoError(t, err) - assert.Equal(t, tc.expected, includeCompactedBlock(tc.meta, tc.searchID, s, e, blocklistPoll, tc.start, tc.end, time.Time{})) + assert.Equal(t, tc.expected, includeCompactedBlock(tc.meta, tc.searchID, s, e, blocklistPoll, tc.start, tc.end)) }) } } From 138cfe0efb582dbb7aa09280940dbe4c1059f98d Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 15 Apr 2026 14:42:55 +0200 Subject: [PATCH 2/2] fmt --- modules/frontend/config.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/frontend/config.go b/modules/frontend/config.go index 332a62a6c2e..4b8e2ac4b5c 100644 --- a/modules/frontend/config.go +++ b/modules/frontend/config.go @@ -41,8 +41,7 @@ type Config struct { AllowedHeaders []string `yaml:"allowed_headers,omitempty"` // RF1After specifies the time after which RF1 logic is applied. - // Deprecated: it's ignored - RF1After time.Time `yaml:"rf1_after,omitempty" category:"advanced"` + RF1After time.Time `yaml:"rf1_after,omitempty" category:"advanced"` // Deprecated: it's ignored // QueryEndCutoff prevents querying incomplete recent data. QueryEndCutoff time.Duration `yaml:"query_end_cutoff,omitempty"`